From 5b615e33a05fbff076402b9b88671163525d2de2 Mon Sep 17 00:00:00 2001 From: worldofpeace Date: Wed, 18 Sep 2019 00:01:22 +0000 Subject: [PATCH 01/73] build: Don't hardcode /bin/echo So that the shell builtin is used instead when available. --- libfprint/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libfprint/meson.build b/libfprint/meson.build index 976c70c8..ce19e95e 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -142,7 +142,7 @@ libfprint_sources += configure_file(input: 'empty_file', output: 'drivers_definitions.h', capture: true, command: [ - '/bin/echo', + 'echo', drivers_struct_list ]) @@ -150,7 +150,7 @@ libfprint_sources += configure_file(input: 'empty_file', output: 'drivers_arrays.h', capture: true, command: [ - '/bin/echo', + 'echo', drivers_primitive_array + '\n\n' + drivers_img_array ]) From 6ba8a15d3a27cff680a7d77e073f548e6ca1a760 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 13 Jun 2019 15:00:25 +0200 Subject: [PATCH 02/73] build: We are now working on version 2 of libfprint Bump the version to 1.90.0, the soname to 2.0.0. Also rename the pkgconfig file to libfprint2.pc. --- meson.build | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index b7f7f315..c3aee14a 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('libfprint', [ 'c', 'cpp' ], - version: '1.0', + version: '1.90.0', license: 'LGPLv2.1+', default_options: [ 'buildtype=debugoptimized', @@ -35,7 +35,7 @@ common_cflags = cc.get_supported_arguments([ # maintaining compatibility with the previous libtool versioning # current = binary - interface # revision = interface -soversion = 0 +soversion = 2 current = 0 revision = 0 libversion = '@0@.@1@.@2@'.format(soversion, current, revision) @@ -142,6 +142,6 @@ pkgconfig.generate( version: meson.project_version(), libraries: libfprint, subdirs: 'libfprint', - filebase: 'libfprint', + filebase: 'libfprint2', install_dir: join_paths(get_option('libdir'), 'pkgconfig'), ) From 5fcd41b96223cb9a05144d5f3ba26d05316d9983 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Fri, 16 Aug 2019 09:33:57 +0200 Subject: [PATCH 03/73] CI: Disable ABI check As the ABI check is not useful for now until the API becomes stable again. Disable it. --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 82846fbd..4ddbd9d9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -34,7 +34,7 @@ build: stage: build <<: *build_one_driver <<: *build - <<: *check_abi +# <<: *check_abi .flatpak_script_template: &flatpak_script script: From 45d7046f99726a9804210e670ad164c6e1e5e7c4 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 12 Jun 2019 21:07:06 +0200 Subject: [PATCH 04/73] lib: Remove all deprecated API --- doc/libfprint-docs.xml | 2 - doc/libfprint-sections.txt | 21 -- libfprint/fp_internal.h | 9 - libfprint/fpi-core.c | 105 ------- libfprint/fpi-data.c | 560 ------------------------------------- libfprint/fprint.h | 32 --- 6 files changed, 729 deletions(-) diff --git a/doc/libfprint-docs.xml b/doc/libfprint-docs.xml index 3ef995b7..52041adf 100644 --- a/doc/libfprint-docs.xml +++ b/doc/libfprint-docs.xml @@ -31,8 +31,6 @@ - - diff --git a/doc/libfprint-sections.txt b/doc/libfprint-sections.txt index 556ea723..cc9b3aec 100644 --- a/doc/libfprint-sections.txt +++ b/doc/libfprint-sections.txt @@ -4,7 +4,6 @@ events Initialisation and events handling LIBFPRINT_DEPRECATED -fp_set_debug fp_init fp_exit fp_pollfd @@ -28,9 +27,6 @@ fp_dscv_dev_get_driver fp_dscv_dev_get_devtype fp_dscv_dev_get_driver_id fp_dscv_dev_supports_print_data -fp_dscv_dev_supports_dscv_print -fp_dscv_dev_for_print_data -fp_dscv_dev_for_dscv_print
@@ -59,7 +55,6 @@ fp_dev_get_devtype fp_dev_supports_print_data fp_dev_supports_imaging fp_dev_supports_identification -fp_dev_supports_dscv_print fp_dev_get_img_width fp_dev_get_img_height @@ -102,27 +97,11 @@ fp_finger fp_print_data fp_print_data_get_data fp_print_data_from_data -fp_print_data_save -fp_print_data_load -fp_print_data_delete -fp_print_data_from_dscv_print fp_print_data_free fp_print_data_get_driver_id fp_print_data_get_devtype
-
-fprint.h -dscv_print -fp_dscv_print -fp_discover_prints -fp_dscv_prints_free -fp_dscv_print_get_driver_id -fp_dscv_print_get_devtype -fp_dscv_print_get_finger -fp_dscv_print_delete -
-
fprint.h img diff --git a/libfprint/fp_internal.h b/libfprint/fp_internal.h index 5c89e184..78610321 100644 --- a/libfprint/fp_internal.h +++ b/libfprint/fp_internal.h @@ -162,14 +162,6 @@ struct fp_dscv_dev { uint32_t devtype; }; -/* fp_dscv_print structure definition */ -struct fp_dscv_print { - uint16_t driver_id; - uint32_t devtype; - enum fp_finger finger; - char *path; -}; - /* fp_minutia structure definition */ struct fp_minutia { int x; @@ -206,7 +198,6 @@ struct fp_driver **fprint_get_drivers (void); enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv); /* Defined in fpi-data.c */ -void fpi_data_exit(void); gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1, enum fp_print_data_type type1, uint16_t driver_id2, uint32_t devtype2, enum fp_print_data_type type2); diff --git a/libfprint/fpi-core.c b/libfprint/fpi-core.c index 6009c82d..ee158bdd 100644 --- a/libfprint/fpi-core.c +++ b/libfprint/fpi-core.c @@ -416,88 +416,6 @@ API_EXPORTED int fp_dscv_dev_supports_print_data(struct fp_dscv_dev *dev, print->type); } -/** - * fp_dscv_dev_supports_dscv_print: - * @dev: the discovered device - * @print: the discovered print for compatibility checking - * - * Determines if a specific #fp_dscv_print discovered print appears to be - * compatible with a discovered device. - * - * Returns: 1 if the print is compatible with the device, 0 otherwise - * - * Deprecated: Do not use. - */ -API_EXPORTED int fp_dscv_dev_supports_dscv_print(struct fp_dscv_dev *dev, - struct fp_dscv_print *print) -{ - g_return_val_if_fail(dev, 0); - g_return_val_if_fail(print, 0); - - return fpi_print_data_compatible(dev->drv->id, dev->devtype, 0, - print->driver_id, print->devtype, 0); -} - -/** - * fp_dscv_dev_for_print_data: - * @devs: a list of discovered devices - * @print: the print under inspection - * - * Searches a list of discovered devices for a device that appears to be - * compatible with a #fp_print_data stored print. - * - * Returns: the first discovered device that appears to support the print, or - * %NULL if no apparently compatible devices could be found - * - * Deprecated: Do not use. - */ -API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_print_data(struct fp_dscv_dev **devs, - struct fp_print_data *print) -{ - struct fp_dscv_dev *ddev; - int i; - - g_return_val_if_fail(devs, NULL); - g_return_val_if_fail(print, NULL); - - for (i = 0; (ddev = devs[i]); i++) - if (fp_dscv_dev_supports_print_data(ddev, print)) - return ddev; - return NULL; -} - -/** - * fp_dscv_dev_for_dscv_print: - * @devs: a list of discovered devices - * @print: the print under inspection - * - * Searches a list of discovered devices for a device that appears to be - * compatible with a #fp_dscv_print discovered print. - * - * Returns: the first discovered device that appears to support the print, or - * %NULL if no apparently compatible devices could be found - * - * Deprecated: Do not use. - */ -API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_dscv_print(struct fp_dscv_dev **devs, - struct fp_dscv_print *print) -{ - struct fp_dscv_dev *ddev; - int i; - - g_return_val_if_fail(devs, NULL); - g_return_val_if_fail(print, NULL); - - for (i = 0; (ddev = devs[i]); i++) { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - if (fp_dscv_dev_supports_dscv_print(ddev, print)) - return ddev; -#pragma GCC diagnostic pop - } - return NULL; -} - /** * fp_dev_get_driver: * @dev: the struct #fp_dev device @@ -564,28 +482,6 @@ API_EXPORTED int fp_dev_supports_print_data(struct fp_dev *dev, data->type); } -/** - * fp_dev_supports_dscv_print: - * @dev: the struct #fp_dev device - * @print: the discovered print - * - * Determines if a #fp_dscv_print discovered print appears to be compatible - * with a certain device. - * - * Returns: 1 if the print is compatible with the device, 0 if not - * - * Deprecated: Do not use. - */ -API_EXPORTED int fp_dev_supports_dscv_print(struct fp_dev *dev, - struct fp_dscv_print *print) -{ - g_return_val_if_fail(dev, 0); - g_return_val_if_fail(print, 0); - - return fpi_print_data_compatible(dev->drv->id, dev->devtype, - 0, print->driver_id, print->devtype, 0); -} - /** * fp_driver_get_name: * @drv: the driver @@ -826,7 +722,6 @@ API_EXPORTED void fp_exit(void) opened_devices = NULL; } - fpi_data_exit(); fpi_poll_exit(); g_slist_free(registered_drivers); registered_drivers = NULL; diff --git a/libfprint/fpi-data.c b/libfprint/fpi-data.c index c19142ac..2a330643 100644 --- a/libfprint/fpi-data.c +++ b/libfprint/fpi-data.c @@ -61,10 +61,6 @@ struct fpi_print_data_item_fp2 { * to convert print data into byte strings, and to reconstruct stored prints * from such data at a later point. You are welcome to store these byte strings * in any fashion that suits you. - * - * The provided API to store data on disk is deprecated and should not be - * used anymore. This API stored the prints in the current user's home - * directory. */ /* @@ -77,51 +73,9 @@ struct fpi_print_data_item_fp2 { * See #fp_print_data for the public API counterpart. */ -static char *base_store = NULL; - -static void storage_setup(void) -{ - const char *homedir; - - homedir = g_getenv("HOME"); - if (!homedir) - homedir = g_get_home_dir(); - if (!homedir) - return; - - base_store = g_build_filename(homedir, ".fprint/prints", NULL); - g_mkdir_with_parents(base_store, DIR_PERMS); - /* FIXME handle failure */ -} - -void fpi_data_exit(void) -{ - g_free(base_store); -} - #define FP_FINGER_IS_VALID(finger) \ ((finger) >= LEFT_THUMB && (finger) <= RIGHT_LITTLE) -/* for debug messages only */ -static const char *finger_num_to_str(enum fp_finger finger) -{ - const char *names[] = { - [LEFT_THUMB] = "left thumb", - [LEFT_INDEX] = "left index", - [LEFT_MIDDLE] = "left middle", - [LEFT_RING] = "left ring", - [LEFT_LITTLE] = "left little", - [RIGHT_THUMB] = "right thumb", - [RIGHT_INDEX] = "right index", - [RIGHT_MIDDLE] = "right middle", - [RIGHT_RING] = "right ring", - [RIGHT_LITTLE] = "right little", - }; - if (!FP_FINGER_IS_VALID(finger)) - return "UNKNOWN"; - return names[finger]; -} - static struct fp_print_data *print_data_new(uint16_t driver_id, uint32_t devtype, enum fp_print_data_type type) { @@ -321,105 +275,6 @@ API_EXPORTED struct fp_print_data *fp_print_data_from_data(unsigned char *buf, return NULL; } -static char *get_path_to_storedir(uint16_t driver_id, uint32_t devtype) -{ - char idstr[5]; - char devtypestr[9]; - - g_snprintf(idstr, sizeof(idstr), "%04x", driver_id); - g_snprintf(devtypestr, sizeof(devtypestr), "%08x", devtype); - - return g_build_filename(base_store, idstr, devtypestr, NULL); -} - -static char *__get_path_to_print(uint16_t driver_id, uint32_t devtype, - enum fp_finger finger) -{ - char *dirpath; - char *path; - char fingername[2]; - - g_snprintf(fingername, 2, "%x", finger); - - dirpath = get_path_to_storedir(driver_id, devtype); - path = g_build_filename(dirpath, fingername, NULL); - g_free(dirpath); - return path; -} - -static char *get_path_to_print(struct fp_dev *dev, enum fp_finger finger) -{ - return __get_path_to_print(dev->drv->id, dev->devtype, finger); -} - -/** - * fp_print_data_save: - * @data: the stored print to save to disk - * @finger: the finger that this print corresponds to - * - * Saves a stored print to disk, assigned to a specific finger. Even though - * you are limited to storing only the 10 human fingers, this is a - * per-device-type limit. For example, you can store the users right index - * finger from a DigitalPersona scanner, and you can also save the right index - * finger from a UPEK scanner. When you later come to load the print, the right - * one will be automatically selected. - * - * This function will unconditionally overwrite a fingerprint previously - * saved for the same finger and device type. The print is saved in a hidden - * directory beneath the current user's home directory. - * - * Returns: 0 on success, non-zero on error. - * - * Deprecated: Data storage should be handled outside of libfprint. - * See stored prints description - * for more information. - */ -API_EXPORTED int fp_print_data_save(struct fp_print_data *data, - enum fp_finger finger) -{ - GError *err = NULL; - char *path; - char *dirpath; - unsigned char *buf; - size_t len; - int r; - - if (!base_store) - storage_setup(); - - fp_dbg("save %s print from driver %04x", finger_num_to_str(finger), - data->driver_id); - len = fp_print_data_get_data(data, &buf); - if (!len) - return -ENOMEM; - - path = __get_path_to_print(data->driver_id, data->devtype, finger); - dirpath = g_path_get_dirname(path); - r = g_mkdir_with_parents(dirpath, DIR_PERMS); - if (r < 0) { - fp_err("couldn't create storage directory"); - free(buf); - g_free(path); - g_free(dirpath); - return r; - } - - fp_dbg("saving to %s", path); - g_file_set_contents(path, buf, len, &err); - free(buf); - g_free(dirpath); - g_free(path); - if (err) { - r = err->code; - fp_err("save failed: %s", err->message); - g_error_free(err); - /* FIXME interpret error codes */ - return r; - } - - return 0; -} - gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1, enum fp_print_data_type type1, uint16_t driver_id2, uint32_t devtype2, enum fp_print_data_type type2) @@ -442,132 +297,6 @@ gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1, return TRUE; } -static int load_from_file(char *path, struct fp_print_data **data) -{ - gsize length; - gchar *contents; - GError *err = NULL; - struct fp_print_data *fdata; - - fp_dbg("from %s", path); - g_file_get_contents(path, &contents, &length, &err); - if (err) { - int r = err->code; - fp_err("%s load failed: %s", path, err->message); - g_error_free(err); - /* FIXME interpret more error codes */ - if (r == G_FILE_ERROR_NOENT) - return -ENOENT; - else - return r; - } - - fdata = fp_print_data_from_data(contents, length); - g_free(contents); - if (!fdata) - return -EIO; - *data = fdata; - return 0; -} - -/** - * fp_print_data_load: - * @dev: the device you are loading the print for - * @finger: the finger of the file you are loading - * @data: output location to put the corresponding stored print. Must be - * freed with fp_print_data_free() after use. - - * Loads a previously stored print from disk. The print must have been saved - * earlier using the fp_print_data_save() function. - * - * A return code of -ENOENT indicates that the fingerprint requested could not - * be found. Other error codes (both positive and negative) are possible for - * obscure error conditions (e.g. corruption). - * - * Returns: 0 on success, non-zero on error - * - * Deprecated: Data storage should be handled outside of libfprint. - * See stored prints description - * for more information. - */ -API_EXPORTED int fp_print_data_load(struct fp_dev *dev, - enum fp_finger finger, struct fp_print_data **data) -{ - gchar *path; - struct fp_print_data *fdata = NULL; - int r; - - if (!base_store) - storage_setup(); - - path = get_path_to_print(dev, finger); - r = load_from_file(path, &fdata); - g_free(path); - if (r) - return r; - - if (!fp_dev_supports_print_data(dev, fdata)) { - fp_err("print data is not compatible!"); - fp_print_data_free(fdata); - return -EINVAL; - } - - *data = fdata; - return 0; -} - -/** - * fp_print_data_delete: - * @dev: the device that the print belongs to - * @finger: the finger of the file you are deleting - - * Removes a stored print from disk previously saved with fp_print_data_save(). - * - * Returns: 0 on success, negative on error - * - * Deprecated: Data storage should be handled outside of libfprint. - * See stored prints description - * for more information. - */ -API_EXPORTED int fp_print_data_delete(struct fp_dev *dev, - enum fp_finger finger) -{ - int r; - gchar *path = get_path_to_print(dev, finger); - - fp_dbg("remove finger %d at %s", finger, path); - r = g_unlink(path); - g_free(path); - if (r < 0) - fp_dbg("unlink failed with error %d", r); - - /* FIXME: cleanup empty directory */ - return r; -} - -/** - * fp_print_data_from_dscv_print: - * @print: the discovered print - * @data: output location to point to the corresponding stored print. Must - * be freed with fp_print_data_free() after use. - - * Attempts to load a stored print based on a #fp_dscv_print - * discovered print record. - * - * A return code of -ENOENT indicates that the file referred to by the - * discovered print could not be found. Other error codes (both positive and - * negative) are possible for obscure error conditions (e.g. corruption). - * - * Returns: 0 on success, non-zero on error. - * - * Deprecated: Do not use. - */ -API_EXPORTED int fp_print_data_from_dscv_print(struct fp_dscv_print *print, - struct fp_print_data **data) -{ - return load_from_file(print->path, data); -} - /** * fp_print_data_free: * @data: the stored print to destroy. If NULL, function simply returns. @@ -609,292 +338,3 @@ API_EXPORTED uint32_t fp_print_data_get_devtype(struct fp_print_data *data) { return data->devtype; } - -/** - * SECTION:dscv_print - * @title: Print discovery (deprecated) - * @short_description: Print discovery functions - * - * The [stored print](libfprint-Stored-prints.html) documentation detailed a simple API - * for storing per-device prints for a single user, namely - * fp_print_data_save(). It also detailed a load function, - * fp_print_data_load(), but usage of this function is limited to scenarios - * where you know which device you would like to use, and you know which - * finger you are looking to verify. - * - * In other cases, it would be more useful to be able to enumerate all - * previously saved prints, potentially even before device discovery. These - * functions are designed to offer this functionality to you. - * - * Discovered prints are stored in a #fp_dscv_print structure, and you - * can use functions documented below to access some information about these - * prints. You can determine if a discovered print appears to be compatible - * with a device using functions such as fp_dscv_dev_supports_dscv_print() and - * fp_dev_supports_dscv_print(). - * - * When you are ready to use the print, you can load it into memory in the form - * of a stored print by using the fp_print_data_from_dscv_print() function. - * - * You may have noticed the use of the word "appears" in the above paragraphs. - * libfprint performs print discovery simply by examining the file and - * directory structure of libfprint's private data store. It does not examine - * the actual prints themselves. Just because a print has been discovered - * and appears to be compatible with a certain device does not necessarily mean - * that it is usable; when you come to load or use it, under unusual - * circumstances it may turn out that the print is corrupt or not for the - * device that it appeared to be. Also, it is possible that the print may have - * been deleted by the time you come to load it. - * - * Note that this portion of the library is deprecated. All that it offers is - * already implementable using publicly available functions, and its usage is - * unnecessarily restrictive in terms of how it stores data. - */ - -static GSList *scan_dev_store_dir(char *devpath, uint16_t driver_id, - uint32_t devtype, GSList *list) -{ - GError *err = NULL; - const gchar *ent; - struct fp_dscv_print *print; - - GDir *dir = g_dir_open(devpath, 0, &err); - if (!dir) { - fp_err("opendir %s failed: %s", devpath, err->message); - g_error_free(err); - return list; - } - - while ((ent = g_dir_read_name(dir))) { - /* ent is an 1 hex character fp_finger code */ - guint64 val; - enum fp_finger finger; - gchar *endptr; - - if (*ent == 0 || strlen(ent) != 1) - continue; - - val = g_ascii_strtoull(ent, &endptr, 16); - if (endptr == ent || !FP_FINGER_IS_VALID(val)) { - fp_dbg("skipping print file %s", ent); - continue; - } - - finger = (enum fp_finger) val; - print = g_malloc(sizeof(*print)); - print->driver_id = driver_id; - print->devtype = devtype; - print->path = g_build_filename(devpath, ent, NULL); - print->finger = finger; - list = g_slist_prepend(list, print); - } - - g_dir_close(dir); - return list; -} - -static GSList *scan_driver_store_dir(char *drvpath, uint16_t driver_id, - GSList *list) -{ - GError *err = NULL; - const gchar *ent; - - GDir *dir = g_dir_open(drvpath, 0, &err); - if (!dir) { - fp_err("opendir %s failed: %s", drvpath, err->message); - g_error_free(err); - return list; - } - - while ((ent = g_dir_read_name(dir))) { - /* ent is an 8 hex character devtype */ - guint64 val; - uint32_t devtype; - gchar *endptr; - gchar *path; - - if (*ent == 0 || strlen(ent) != 8) - continue; - - val = g_ascii_strtoull(ent, &endptr, 16); - if (endptr == ent) { - fp_dbg("skipping devtype %s", ent); - continue; - } - - devtype = (uint32_t) val; - path = g_build_filename(drvpath, ent, NULL); - list = scan_dev_store_dir(path, driver_id, devtype, list); - g_free(path); - } - - g_dir_close(dir); - return list; -} - -/** - * fp_discover_prints: - * - * Scans the users home directory and returns a list of prints that were - * previously saved using fp_print_data_save(). - * - * Returns: a %NULL-terminated list of discovered prints, must be freed with - * fp_dscv_prints_free() after use. - * - * Deprecated: Do not use. - */ -API_EXPORTED struct fp_dscv_print **fp_discover_prints(void) -{ - GDir *dir; - const gchar *ent; - GError *err = NULL; - GSList *tmplist = NULL; - GSList *elem; - GPtrArray *array; - - if (!base_store) - storage_setup(); - - dir = g_dir_open(base_store, 0, &err); - if (!dir) { - fp_err("opendir %s failed: %s", base_store, err->message); - g_error_free(err); - return NULL; - } - - while ((ent = g_dir_read_name(dir))) { - /* ent is a 4 hex digit driver_id */ - gchar *endptr; - gchar *path; - guint64 val; - uint16_t driver_id; - - if (*ent == 0 || strlen(ent) != 4) - continue; - - val = g_ascii_strtoull(ent, &endptr, 16); - if (endptr == ent) { - fp_dbg("skipping drv id %s", ent); - continue; - } - - driver_id = (uint16_t) val; - path = g_build_filename(base_store, ent, NULL); - tmplist = scan_driver_store_dir(path, driver_id, tmplist); - g_free(path); - } - - g_dir_close(dir); - - if (tmplist == NULL) - return NULL; - - array = g_ptr_array_new(); - for (elem = tmplist; elem != NULL; elem = elem->next) - g_ptr_array_add(array, elem->data); - g_ptr_array_add(array, NULL); - - g_slist_free(tmplist); - return (struct fp_dscv_print **) g_ptr_array_free(array, FALSE); -} - -/** - * fp_dscv_prints_free: - * @prints: the list of discovered prints. If NULL, function simply - * returns. - * - * Frees a list of discovered prints. This function also frees the discovered - * prints themselves, so make sure you do not use any discovered prints - * after calling this function. - * - * Deprecated: Do not use. - */ -API_EXPORTED void fp_dscv_prints_free(struct fp_dscv_print **prints) -{ - int i; - struct fp_dscv_print *print; - - if (!prints) - return; - - for (i = 0; (print = prints[i]); i++) { - if (print) - g_free(print->path); - g_free(print); - } - g_free(prints); -} - -/** - * fp_dscv_print_get_driver_id: - * @print: the discovered print - * - * Gets the [driver ID](advanced-topics.html#driver_id) for a discovered print. The driver ID - * indicates which driver the print originally came from. The print is only - * usable with a device controlled by that driver. - * - * Returns: the driver ID of the driver compatible with the print - * - * Deprecated: Do not use. - */ -API_EXPORTED uint16_t fp_dscv_print_get_driver_id(struct fp_dscv_print *print) -{ - return print->driver_id; -} - -/** - * fp_dscv_print_get_devtype: - * @print: the discovered print - * - * Gets the [devtype](advanced-topics.html#device-types) for a discovered print. The devtype - * represents which type of device under the parent driver is compatible - * with the print. - * - * Returns: the devtype of the device range compatible with the print - * - * Deprecated: Do not use. - */ -API_EXPORTED uint32_t fp_dscv_print_get_devtype(struct fp_dscv_print *print) -{ - return print->devtype; -} - -/** - * fp_dscv_print_get_finger: - * @print: discovered print - * - * Gets the finger code for a discovered print. - * - * Returns: a finger code from #fp_finger - * - * Deprecated: Do not use. - */ -API_EXPORTED enum fp_finger fp_dscv_print_get_finger(struct fp_dscv_print *print) -{ - return print->finger; -} - -/** - * fp_dscv_print_delete: - * @print: the discovered print to remove from disk - * - * Removes a discovered print from disk. After successful return of this - * function, functions such as fp_dscv_print_get_finger() will continue to - * operate as before, however calling fp_print_data_from_dscv_print() will - * fail for obvious reasons. - * - * Returns: 0 on success, negative on error - * - * Deprecated: Do not use. - */ -API_EXPORTED int fp_dscv_print_delete(struct fp_dscv_print *print) -{ - int r; - fp_dbg("remove at %s", print->path); - r = g_unlink(print->path); - if (r < 0) - fp_dbg("unlink failed with error %d", r); - - /* FIXME: cleanup empty directory */ - return r; -} - diff --git a/libfprint/fprint.h b/libfprint/fprint.h index 4b68e4aa..c7e81b45 100644 --- a/libfprint/fprint.h +++ b/libfprint/fprint.h @@ -46,14 +46,6 @@ extern "C" { */ struct fp_dscv_dev; -/** - * fp_dscv_print: - * - * #fp_dscv_print is an opaque structure type. You must access it using the - * functions in this section. - */ -struct fp_dscv_print; - /** * fp_dev: * @@ -147,20 +139,6 @@ uint16_t fp_dscv_dev_get_driver_id(struct fp_dscv_dev *dev); uint32_t fp_dscv_dev_get_devtype(struct fp_dscv_dev *dev); int fp_dscv_dev_supports_print_data(struct fp_dscv_dev *dev, struct fp_print_data *print); -int fp_dscv_dev_supports_dscv_print(struct fp_dscv_dev *dev, - struct fp_dscv_print *print) LIBFPRINT_DEPRECATED; -struct fp_dscv_dev *fp_dscv_dev_for_print_data(struct fp_dscv_dev **devs, - struct fp_print_data *print) LIBFPRINT_DEPRECATED; -struct fp_dscv_dev *fp_dscv_dev_for_dscv_print(struct fp_dscv_dev **devs, - struct fp_dscv_print *print) LIBFPRINT_DEPRECATED; - -/* Print discovery */ -struct fp_dscv_print **fp_discover_prints(void) LIBFPRINT_DEPRECATED; -void fp_dscv_prints_free(struct fp_dscv_print **prints) LIBFPRINT_DEPRECATED; -uint16_t fp_dscv_print_get_driver_id(struct fp_dscv_print *print) LIBFPRINT_DEPRECATED; -uint32_t fp_dscv_print_get_devtype(struct fp_dscv_print *print) LIBFPRINT_DEPRECATED; -enum fp_finger fp_dscv_print_get_finger(struct fp_dscv_print *print) LIBFPRINT_DEPRECATED; -int fp_dscv_print_delete(struct fp_dscv_print *print) LIBFPRINT_DEPRECATED; /* Device handling */ struct fp_dev *fp_dev_open(struct fp_dscv_dev *ddev); @@ -169,7 +147,6 @@ struct fp_driver *fp_dev_get_driver(struct fp_dev *dev); int fp_dev_get_nr_enroll_stages(struct fp_dev *dev); uint32_t fp_dev_get_devtype(struct fp_dev *dev); int fp_dev_supports_print_data(struct fp_dev *dev, struct fp_print_data *data); -int fp_dev_supports_dscv_print(struct fp_dev *dev, struct fp_dscv_print *print) LIBFPRINT_DEPRECATED; /** * fp_capture_result: @@ -274,14 +251,6 @@ int fp_identify_finger(struct fp_dev *dev, struct fp_print_data **print_gallery, size_t *match_offset); /* Data handling */ -int fp_print_data_load(struct fp_dev *dev, enum fp_finger finger, - struct fp_print_data **data) LIBFPRINT_DEPRECATED; -int fp_print_data_from_dscv_print(struct fp_dscv_print *print, - struct fp_print_data **data) LIBFPRINT_DEPRECATED; -int fp_print_data_save(struct fp_print_data *data, enum fp_finger finger) - LIBFPRINT_DEPRECATED; -int fp_print_data_delete(struct fp_dev *dev, enum fp_finger finger) - LIBFPRINT_DEPRECATED; void fp_print_data_free(struct fp_print_data *data); size_t fp_print_data_get_data(struct fp_print_data *data, unsigned char **ret); struct fp_print_data *fp_print_data_from_data(unsigned char *buf, @@ -354,7 +323,6 @@ void fp_set_pollfd_notifiers(fp_pollfd_added_cb added_cb, /* Library */ int fp_init(void); void fp_exit(void); -void fp_set_debug(int level) LIBFPRINT_DEPRECATED; /* Asynchronous I/O */ From ec8dd6410e7156fb4c589d38f030f6f0651e50a6 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 13 Jun 2019 15:45:38 +0200 Subject: [PATCH 05/73] build: Make glib a libfprint dependency We are going to use GLib types in the public API now. --- examples/meson.build | 2 +- libfprint/meson.build | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/meson.build b/examples/meson.build index 7596be64..c6ed326c 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -3,7 +3,7 @@ examples = [ 'verify_live', 'enroll', 'verify', 'img_capture' ] foreach example: examples executable(example, [example + '.c', 'storage.c'], - dependencies: [libfprint_dep, glib_dep], + dependencies: [libfprint_dep], include_directories: [ root_inc, ], diff --git a/libfprint/meson.build b/libfprint/meson.build index ce19e95e..e46f2f99 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -168,7 +168,8 @@ libfprint = library('fprint', install: true) libfprint_dep = declare_dependency(link_with: libfprint, - include_directories: root_inc) + include_directories: root_inc, + dependencies: glib_dep) install_headers(['fprint.h'], subdir: 'libfprint') From 01ec1c5777970c5c19e151139b3e5ab3b2dacdf4 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 13 Jun 2019 14:57:56 +0200 Subject: [PATCH 06/73] build: Add dependency to GUsb rather than libusb We will use GUsb rather than libusb directly in the future. This should simplify a lot of the integration work and changes such as supporting hotplugging. It will also require quite a lot of internal changes. --- libfprint/meson.build | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libfprint/meson.build b/libfprint/meson.build index e46f2f99..57264c03 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -154,7 +154,7 @@ libfprint_sources += configure_file(input: 'empty_file', drivers_primitive_array + '\n\n' + drivers_img_array ]) -deps = [ mathlib_dep, glib_dep, libusb_dep, nss_dep, imaging_dep ] +deps = [ mathlib_dep, glib_dep, gusb_dep, nss_dep, imaging_dep ] libfprint = library('fprint', libfprint_sources + drivers_sources + nbis_sources + other_sources, soversion: soversion, diff --git a/meson.build b/meson.build index c3aee14a..0b075c48 100644 --- a/meson.build +++ b/meson.build @@ -42,7 +42,7 @@ libversion = '@0@.@1@.@2@'.format(soversion, current, revision) # Dependencies glib_dep = dependency('glib-2.0', version: '>= 2.50') -libusb_dep = dependency('libusb-1.0', version: '>= 0.9.1') +gusb_dep = dependency('gusb', version: '>= 0.3.0') mathlib_dep = cc.find_library('m', required: false) # Drivers From ce9702571bf34d292a2006fb9a756a4f51038dd3 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 13 Jun 2019 15:24:51 +0200 Subject: [PATCH 07/73] build: Add a "default" driver selection to exclude virtual drivers We will not want to install virtual drivers by default, yet they should be inside the "all" category. So add a new "default" category and also a separate array for the future virtual drivers. --- meson.build | 9 ++++++++- meson_options.txt | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 0b075c48..8c370641 100644 --- a/meson.build +++ b/meson.build @@ -47,13 +47,20 @@ mathlib_dep = cc.find_library('m', required: false) # Drivers drivers = get_option('drivers').split(',') -all_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] +virtual_drivers = [ ] +default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] primitive_drivers = [ 'upekts' ] +all_drivers = default_drivers + virtual_drivers + if drivers == [ 'all' ] drivers = all_drivers endif +if drivers == [ 'default' ] + drivers = default_drivers +endif + if drivers.length() == 0 or drivers[0] == '' error('Cannot build libfprint without drivers, please specify a valid value for the drivers option') endif diff --git a/meson_options.txt b/meson_options.txt index f40ebc31..f21e1e78 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,7 +1,7 @@ option('drivers', - description: 'Drivers to integrate', + description: 'Drivers to integrate, "default" selects the default set, "all" selects all drivers', type: 'string', - value: 'all') + value: 'default') option('udev_rules', description: 'Whether to create a udev rules file', type: 'boolean', From 7fed33fb4983d3958ce8f61e07426e40739a3a91 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 1 Jul 2019 17:28:48 +0200 Subject: [PATCH 08/73] build: Disable all drivers We will re-enable them again when they are ported. --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 8c370641..c6de688c 100644 --- a/meson.build +++ b/meson.build @@ -48,8 +48,8 @@ mathlib_dep = cc.find_library('m', required: false) # Drivers drivers = get_option('drivers').split(',') virtual_drivers = [ ] -default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -primitive_drivers = [ 'upekts' ] +#default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] +default_drivers = [ ] all_drivers = default_drivers + virtual_drivers From 059fc5ef7ded2048969ad4ed241b99c6fe55bbd4 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 3 Jul 2019 23:47:35 +0200 Subject: [PATCH 09/73] examples: Disable existing examples These examples will stop working with the following API changes. Updated examples may be re-enabled again later. --- examples/meson.build | 32 ++++++++++++++++---------------- meson.build | 14 +++++++------- meson_options.txt | 4 ---- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/examples/meson.build b/examples/meson.build index c6ed326c..9c84e6bc 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -10,20 +10,20 @@ foreach example: examples c_args: common_cflags) endforeach -executable('cpp-test', - 'cpp-test.cpp', - dependencies: libfprint_dep, - include_directories: [ - root_inc, - ], - c_args: common_cflags) +# executable('cpp-test', +# 'cpp-test.cpp', +# dependencies: libfprint_dep, +# include_directories: [ +# root_inc, +# ], +# c_args: common_cflags) -if get_option('x11-examples') - executable('img_capture_continuous', - 'img_capture_continuous.c', - dependencies: [ libfprint_dep, xv_dep, x11_dep ], - include_directories: [ - root_inc, - ], - c_args: common_cflags) -endif +# if get_option('x11-examples') +# executable('img_capture_continuous', +# 'img_capture_continuous.c', +# dependencies: [ libfprint_dep, xv_dep, x11_dep ], +# include_directories: [ +# root_inc, +# ], +# c_args: common_cflags) +# endif diff --git a/meson.build b/meson.build index c6de688c..2f043039 100644 --- a/meson.build +++ b/meson.build @@ -112,13 +112,13 @@ if get_option('udev_rules') endif endif -if get_option('x11-examples') - x11_dep = cc.find_library('X11') - xv_dep = dependency('xv', required: false) - if not xv_dep.found() - error('XV is required for X11 examples') - endif -endif +# if get_option('x11-examples') +# x11_dep = cc.find_library('X11') +# xv_dep = dependency('xv', required: false) +# if not xv_dep.found() +# error('XV is required for X11 examples') +# endif +# endif if get_option('gtk-examples') gnome = import('gnome') diff --git a/meson_options.txt b/meson_options.txt index f21e1e78..78f16ef5 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -10,10 +10,6 @@ option('udev_rules_dir', description: 'Installation path for udev rules', type: 'string', value: 'auto') -option('x11-examples', - description: 'Whether to build X11 example applications', - type: 'boolean', - value: true) option('gtk-examples', description: 'Whether to build GTK+ example applications', type: 'boolean', From 95d7c0e80033817679ab33462f65793490aeeb71 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 1 Jul 2019 17:15:49 +0200 Subject: [PATCH 10/73] lib: Add dummy namespace versioning file --- libfprint/libfprint.ver | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 libfprint/libfprint.ver diff --git a/libfprint/libfprint.ver b/libfprint/libfprint.ver new file mode 100644 index 00000000..d99a456a --- /dev/null +++ b/libfprint/libfprint.ver @@ -0,0 +1,6 @@ +LIBFPRINT_2.0.0 { +global: + fp_*; +local: + *; +}; From d67a801f1f7cc210448aef509f535baf89604841 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 13 Jun 2019 15:52:51 +0200 Subject: [PATCH 11/73] examples: Add a few example prints from NIST These prints are from NIST and are not copyrighted. They were sourced via wikipedia. --- examples/prints/README | 1 + examples/prints/arch.jpg | Bin 0 -> 18235 bytes examples/prints/loop-right.jpg | Bin 0 -> 18185 bytes examples/prints/tented_arch.jpg | Bin 0 -> 14590 bytes examples/prints/whorl.jpg | Bin 0 -> 14379 bytes 5 files changed, 1 insertion(+) create mode 100644 examples/prints/README create mode 100644 examples/prints/arch.jpg create mode 100644 examples/prints/loop-right.jpg create mode 100644 examples/prints/tented_arch.jpg create mode 100644 examples/prints/whorl.jpg diff --git a/examples/prints/README b/examples/prints/README new file mode 100644 index 00000000..2d4a06e4 --- /dev/null +++ b/examples/prints/README @@ -0,0 +1 @@ +These are example images from NIST and are in the public domain. diff --git a/examples/prints/arch.jpg b/examples/prints/arch.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b87e285c375ac75e461ffa0ad104bced363acd13 GIT binary patch literal 18235 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 lxOX;eOEEgm`K(F6UKw*B06wAO9e(tf Date: Thu, 13 Jun 2019 15:53:26 +0200 Subject: [PATCH 12/73] examples: Add PNGs for NIST example prints These PNGs were generated using gimp simply by using the greyscale image itself as an alpha mask. The reason to do this is solely for easier consumption together with cairo A8 surfaces. --- examples/prints/README | 2 ++ examples/prints/arch.png | Bin 0 -> 123124 bytes examples/prints/loop-right.png | Bin 0 -> 122398 bytes examples/prints/tented_arch.png | Bin 0 -> 109822 bytes examples/prints/whorl.png | Bin 0 -> 104880 bytes 5 files changed, 2 insertions(+) create mode 100644 examples/prints/arch.png create mode 100644 examples/prints/loop-right.png create mode 100644 examples/prints/tented_arch.png create mode 100644 examples/prints/whorl.png diff --git a/examples/prints/README b/examples/prints/README index 2d4a06e4..977d7066 100644 --- a/examples/prints/README +++ b/examples/prints/README @@ -1 +1,3 @@ These are example images from NIST and are in the public domain. + +The PNG files have been generated by using the greyscale data as a mask. diff --git a/examples/prints/arch.png b/examples/prints/arch.png new file mode 100644 index 0000000000000000000000000000000000000000..f8c9b4de2c514639988cacea58fbcc23ec4920f1 GIT binary patch literal 123124 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%0DEDU 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

GEGbAg6D)mtKs<@x8A%2Kjwb+usD~

Esf`glCaW)#KqIIc23y9)p} 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

m>%g4DQLO# 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 literal 0 HcmV?d00001 diff --git a/examples/prints/whorl.png b/examples/prints/whorl.png new file mode 100644 index 0000000000000000000000000000000000000000..9e7e7c4b721884bc97d0d93f8dd3b89e1fa6282c GIT binary patch literal 104880 zcmV(>K-j;DP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3^gk}b!vUH@|wZwQ$g{ctimGtEH5*IIEd$p?^< znPdV;0Jo}6HWBXI_x2|0TL1HZ?CZb&>%X2*L%d=tHMg8^{)#QO_v1h6{rl_p@8^!^ zpXaar{rTSW*RNmeAK!TSQsCd=_s6{c{QSq))4x7Y;-9bgzkdBHKp9?+zyzu!e zcxV56{&~nh7Ygt1>(8G*U+vEazWm=_=gxK7vS9rqx`{(aY zfu{&9eEd7}PrvI|()mg`Uuploe%D{_@wWwB`#-PWJ^uVe_}6m$F7%Jr%70s@KVN^+ z-@YFHdHeS-PxQQhe&qevH_lc+;m=b3`}*xY>)z}4c3;dF%a#AU)IVPF{1-piSCmL$y2^Dgv{pD*L(As@|>T2)BF1}@WMtUoTjifI1rl^V~QDntC-MtrI2DuDW{TZ zYU#@%$DDG`C5uyE2_=?Paw(;jR=yf)tf}T&YOSq)?QH=VOIORSwAxzxK5qKOk86GW z{Kpsi+e42%_1sIZz4dQkJ|m7a@+hN@Hop1JFoA$;=2>Q)ZGP)nn9_y4(K#xodxR^{>13_nrGc@7nWc*WR;H{#^OjuJPqk{&9&%I7#jqJNCwh z9WU+x2K~BccYR`f-8uK{Zg03kNH0&B+?@HiW9(pD&ztu1&%OKC&i!xq?P7KRZ};u} zPdj(Hb^kwh?sDt?+s^&_zWs+?o8N)ka5hLUWKBWHfcx$A)HP>}-Sz3AbR*5^4G4U= zo{{rTA+TnNpUPkFtWg{Nc}t(6jPDBf2rJ#A#}=M<#8tk+Q_WfS{f)u8RK8JLT%+P@ zG4nR#D`41XtV{LDfnYr@T#Q?Py|VSa?ecxCuqs~!9$M^gyC>_)rjK6vZr+V;oa1Fd zL&~8(EAf(Fy>`K|pSR8uM}Fph<5(qgslp0iSVZ8rw0AuBJ?hi*SiIWHdqpho&5xm> zyN&M`JN7n4*ctE|ZO+Z!zB5MvE9?plNvmO_yk~iO&-EJ5ssSthAOpR!p_tx0rpHFD zaT72Gi-=iNjPD+)Pb?mjtZeLJ$s6YWrHN(7k6=|tp5vLl`HK51F;CXv9vj?+HuTDk zMq4b?>n_j9vVWiq56*7Yc@t?%%52tdlZ9LC&Hc@|*JQ2U&QHC0zRPGl>S7J+9m0oG zMW3S-?!z|UEnmR=3OMTdAaD>`!C�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%0AhldZ1qjc75JCc$4HOr6?BCgc{7Ogr6Z0or?I~v4 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%0A3O_eI@ zBzPaIz_|;{bcj}s5d%MuvJv(QGu{B9zsFHT%RSDiUW86WXJ@=+-d6SpVJCI*2OM|7 zme6MDyTg)L{2%v_pRaO*zS*}Ihy`Lq3Wn|8l~^Lq7i|aj zwy8%FU4IKjlkvss1|Dq|PuvY&R)~nR>F(6wM}_o^@sqiVS5vBPzEB z`L-bc?9d3@-QN%fH>von%yMVdh{jYtW18>4~hu z-F#kZ|BVhH| z$m%VzUEc{dL$Kt$kf@=d>(%J;Dm?$XN{HcRFml~;E9BP5I|HZlX6&-5dD0z)hbIav zc0E|%SXCb(A6;(G72a1oWuZTrfKikvlyWLVoCzvQM*V`s`t@c0h9=b%paOl*{Ws!d zFfklkTRi^O=1ndP*>W|H+DLsvxQe(v*;K<9gE4!uc>6T><`(2$=*==_5A( z#sQz$C{TBy?K*pY-O}0ho7PW!Mr;u5>BXyv8S$5p);Ds;@l}s|(@M>m^k*iTz@O#a z<u!2Z-I|eA6-+~>-|WW|2|x?!yjX+ocMl4UlaQv&o__R7DlhEC!`BY? zes$l&6y40vwkv)gXtG@}M_DF?JU%`_+2@ZQJ9{+a%GBTh0OyJ~!gF-~?e%X4sn^UM z=qPB%v}-1N1U|WWohf)RtH~=Pdtc57j_tT*A!Q+53#3F;A9H#=M^no;n`3mH8cjU68sig6W10sq zj91T~s$I7MeL|@LTaDbKYdEg7l-(Ar6g`o*&G$m|V0Z2!y!_4EXGB9Q_iKIg-kx;l zHkVg;Pp+;)12;VB-KhYG*&?|&T)cn~?hINyA0TozF9jV*rhs7&fkuSqxb`utCq!%c zH(u&ZpOYP&7dYlhk*woCv@Mtl0q+)3pg^aWU|Q=yB|Zel#h;IJU}JmMfwHdAd);Il z3L`uUBQJs3WfCf%%d=E4pdA??>k1NGt3hYKecS(MLx^CVwCjE@R7C(qq0B(59=*Z^ zDMN(7ZvH1&lrEGgRIeBmm}%-D1=q1W7(d#_T!tTj;ep$Y{ts?G0^Jok9%5C8k_E$h z(ptsNug1>Pq)nCI)c&e26*1qJSD$@kW*=Jl0MI`;bpt@MJl+R5Ucii6a?l`ef7GX6 zhzYREe~sXQeReC03vDck#ltF6p@$FdnMT(;Y>IZhHoZ zx4xD0->zYCi=-NFw zZQB6G{(Tva+HN`pxtQ(I291g3lLOifuQ~%uPy+Z3v&~qTmJ{iU-?e_l)-XY!xjwuHva)aucBOELP!tKHd1^aBco%MifxvQ({&josyn;lA3%(&w0mrg{cl-}z{01eSF>d=tAz`8OCIDr9wIr=1se!};HQ!I zZj4ePY*R8SxT> zQ?9g}=(9ZvOe^m&Svj?@{+qxoz}OY7Tyu6Cfp^)88TVtlHBntr`kN`Q&Tmh$vyEW& zHCvAHgB<0hzbdOJ_xrTwf{L(YZJ_A{LwAuP<0BxA+E0(!23;oBTb=(U4g=UxVyOO1 zc;-l@~24dJg;8`6Ur>FMP6rsB%Ii-U5 zs1=mJFdODGy^5;~V^qrK>Um35OTer3GX(apEZp*SQvV1ETbkH=vO092p=0SEFzXXg z<0np;@nXRv2Qjaep`!pQ7<77=Z)LtDikq1ekT@jfjb}J|8sVQ@v<1-TM{9QaUmjMF zHJ;V!gr|>56c8I!be_tLDNy;pc}Dhch1v0fujTu#_JQe1ijW5LD0gqF=&X4CuYnRz2k5hU2F2dq!cy2*(kUL`B_v9M0AWaL?6;poo z5j8j_qPPsv%LxR1lx5U?qX|GiQ6T?hyeEmaOC)&7{CB(yztIAH_yLMP|` zeXe%BUaFF=I5u-TTb}iqq(F_Tj_W-WSClmI(=m)SZR!+go5b!!+Sm^4kSjzdbX}>q z4Z#EIk+ZK=SI8CnGL90e>?7HkjPX(~iQl5*CXHZyyIrG_K(G9G(opz7m@Tj|XxC5U zz>T;J-;7h{NZRe$Tb$g4@Y#$SOPwz`d4GtrsK0NCf5E3obL)9;K@69IcX;~AeG$zA zjX+pS|DcUvcUZEPf`CTEUkzp8m_z;BEYWgost&fIJ`lC8?aiZ9y1BH!lU~` z!nGAzs#Rc96l252siO6)1K^v(-0SYZ5udPDIAsi|jZYX>GiU-gfBkE0wU{s8K@~5! z=kEJJG+afn2T7eH<~*AOaTfIOx>&vq0sMq4T}#FQrDB<(4Ko&HNlPP8D#F_B{wjk= z+zKs6|FA=)hH_Dz?v3Ys2<{0cD`3)wfZXk=sblu0cwlJHg}P>dMy6erZ08TA6-gOK zv4U6vkpm!){fU;LtQi|U5K+e#$(6L&4NC@CMH^_o+g^|_-VNGrG>&^_z24(b@ijgc zGVm?Y(m`zRqBI*a7XbmVYl;_^xuPAn&uR!aQRp9n8!JADg+|nXW^)>dCk_(wLlgkK z;Yhs;3GkLZY)uTmJm0_YY8eTOAM07yldK+h$6sxiPR#T4tmkc^;`}3~&fvb~H>!d$#U{!Jd1Tr%du1HaXP^hYyr|-P!MetK zV=&Hj z7dI~O;Rn%SH&l~hAkA`ZvKkYiv^LvteQ}MQV`FRfPU|2^WxLnQ*NiVvbFE@4=2z24h10HWSK;-2 zq~}%f!$*^9Kp-Y20VgO3kOk)ygjD_v7a3rgI4M+pInf?*-&FR*)=J;GLtWF9(AbWJ zv$?XXjiUoDA$4ilgXJz){B1q~aJkE^oj6c)`=Y?xr_2BrQMudfX3CqLj(8I}j@Yz< zWNj49U9gA3pQ8|?#`~NcEL!*RtU3Lv<74F_#W!_upT0qgceT_wRjEf~7_69R;Ol_S275O$}(a{wG3{)_se>(Sfm1dN5{~_B*}TTiF8ZP*YWVXylQFA73#@FdBWZ^KH@gX4p5kd z1ht;IojJMJ$;!Aad-?ht^iqQjM??P&uNG$CE`20=5XC#WygxE=orE0K7y_+(@Pi)r zQapr2J`MkwO(Pkk=N$c%iE~46@D2*_{Kq}AmlK-*(E(gQ@5en{!~qH<#I1bqopy?& z#VX`Q*`M&@B`azgPnurIsL})Qf!<2j=5A0rBqfX*B)ubUFF~pD>LVz}GJ~84`)iNY zeE%;H;2FavBc?ZL!(!G)q0PhkX^y}whDXOo~^K{efjB3Cr8L{)dKN`;pK&l@rGr|-+9P4xy95HoFo8>!1 z0r>h#R3{auI+SDdsPpzgc(+s1g`LH_IdOp=Viy96AGPZ(Q+_Gvc=_EJfAhOB+$%u6 z*1dC^heUDUj|CwdS=aNr5m0c4mPg#PWnM;p<-v(r-Vv{~MHy3f<0 zd!G`pi+g3Ga*(t8sXb1m0{t0w zCjm{_n2ukcmF80b&y_N|cs*ET09cTP@N`Gq>MGIaXqZWzW?#_}DR~@1jX*2APYCe8 z5CwMT&=T@e#t|7n`S)dzT}BU;BY#%bKR!KH>ezJKMLEdu08gkp*ap@GrA#KSmp zH2+)vWlZqZ4J$S<7PIlHd2$y3DBC_R#VcB22u4=5ONfu|RWbCa0{&I2c@~<$i><3q zx7D;vv5kS_2GO7GuaEbJ_=p78eJ+)(`Q*LDy+ZqB*YF(YLJB~B{NeGmeP!5hKI6>u z;RTBpi!DM>AdvrwjS~mwL1{6PIQGZfUxh_Vs(t_Su+=m18c(?1jhtou#^%calXsT2 zwET0gdE*SUY$wv;OVkWpPBD__}3 z5Y4fbX3?0d$-aA*h{hOe1X}KV(y!cI%w`lZ>&66+ zulBcdjBd5NR`mRmJ0ml#h8yo?b1QEWdV1xZ1FUe_Ho8bq^B&Q-GT!+MCkhC$X-z zKe$aKtQokL@>9&|??lJHQ5BU#zP(C-9By~QueK9Pvkk&a{_J>9yEk5V1uk@T;asBk zWEG~o*Tg6iwy=Uhr-a#XZizHqRN@0mh8KYc?{I-06dYG=*A?mW*Z+72hq9e;cake7 zmyd}K#I?fBlyo>fb)f%o_0atFLZwlLa0T)e>txLA`n`8JBK2^Ys|ftrnUla~c=$x% z=~4>F!Du_{@@#aaL4K=owD{>bOb*c(L!cZO)7l(x&s$!+m^ECMzdO`&B^Z5fxuGd% z?>*vsbmOZH<}(jAxkBKK62F8bV%QeOP%b zYq+>PzhmCObIVwCkhN`Qf8FgTeIOQ@Z3EJ@N~^O@q?$de8(wx#E6;il?y_N;SS{2# zhOBJb{~ToB668sLKr1nN=5FFLR%G4Ob$YSxggB>AP*W#ef=^aQf#jdTHtB&SfdqvNbR zuR4nO9_pDK9XT$fa!xtFL=sPv*GaU4j02V_V!4 zF{sa$VTwb^@kqp%MG(oF>O8p(fEs%MZ5??&olOpni*6Ek-fa`%4rBCDHSBXUY`Yv8 zDj0%q0Gq9%43+Mvly%gI*K!z2So0J;&oSfFaW?wog&Sb$y|`y}6P@$$(-DTkno#t& zzgD0Dt-?X$=-KC=myv%4#@qX6Kje^*Qgb`2wrbkRWmsRk3%51ky(cTpas}-|Z?8_{ zMxGbZMhgRUjnn&;cYT2}bBkZ=mgxa_6F5(qC_n9|jPo$k9^4cU0Pzm8tJ9x#?m1)2 z+4f~5VMs=i>6;K>K2?XA*GXrfi6l_j9zD3CQ~lx3e0hb_pQLOvNsb8bC~H2L&7-eaRLeZuNR5&S?G{`!Gc&?EfCN+XY#_s*kut(!S$ z0Wr!DMc`NTDXLNewa?#MOP5dw(iKfZ%2@%PkM7_#)qh9@d=()>!%tRJ_&@#=hrUox zG3S$tUFI-*UmEB0%U9WmLB_@8)mNd#e2L|P()`Nf!%6Kui>)%A*U_d@ha+n+`DiFd z!0!3x3%v@7Y!ObD zzK#4IfEk!kg_a?2;c96qi6&FEx#{+~SVD!1CHo()hlZXD;P2E|yxIwi&Rmo?UNJ_t zzo{_0^+fdTTLT}VH?mpTS+d5@?pBYD6vAbsUM)huaAst~DdO2>*}{&`pG*j=spJdv z3QXMPx&^L5de2BUK}_WiWb>a+TWtAFgjPz;T{pIgNv91=lz%u{S`9ktS+#(YW_u*a zK?4x+8_F|ytgrVzpv^o0cRl1^$KI8uklJMXaHeb=L|( z4KUs_JM2%d;J9C1HSEXatMyE5;PJ-!lcP_=R(bj0$19Da8U|zXjsU349Hnqh#I1W5 z+Y6=*XM6MW{@dg_^goO#F^m1}jY2DD;ttQu2elqTWE4i6))tXa<_$tX737@H#^w0* zsDd<6LU`rHkE|pQb^X{NV)8|sXAy1)@$P#UMLm!?Rg3!otCrT7c(?BGDrT9E$di@{ zHCgP7wI9dUhPNpo%RgGm-QQxc=raJ2^rH)lho8|PY2@COkAK-cO!i6S&F5$|pvdP) zOdUjJlV~3bRWeo;;e{jKiuzr=QYVA?+uhB}|1XOnEpN#(#Le4%&y!Ti9UV^!k~obB z!4rv5DLvDWx%`EMzH-S&re=)(>B70S0&T?0Bi^B_kY5CwhR>GWi%rbx0rSSM7!d#< zp{r|yf4A1JQJyd28z=(+HL;okFOT0VHklni30N=mu=6%uCvTU%u9{-Z6smqDnrRFN z1pnI6b|u=d#NP+ZDFQjNr(})!bCSS;+=Rq<>)2TPeS7IHlII_5FN&BdUHzoxx&`3XsyV1H?{(+v<@*-PJTwSO=FEC^wSdR~{2Cp3 zO|S5J+ctX+S3)gc4Wk~(vDgv+_jOd+TW(a1Dd36|O}#uY0qFnnMvZh6*E|dlGF&13 zqrHzq8oDH^)tsd=OSW_|=JepxS9^y5&Wco28zWZ?d zjbj%Ja5!J+4Dxn(tzg38p9wrmV7y^bkKem*gPnpA+syM&^h5~UEjoe8)|B5d~lVW zNV2oB#>FLCMnkPKwEQz3eT78Zm#}C2Zy7%W0;FhGeBA@_cwf07C6+E$(OxXd2lC>YG-Pgw+heSAPFp$owhrTJ96p|#D+<-EI?-KIaF}Ol$Tl=n zW#yvpX5l>1C|{G_{FvHGjbfSB^X$ueP}t{TMalbFFCxSsrGP|IL2Yw^^G5GIdP5Ys z1zJ4RK#g3iz?hLWA2cv{Kpj={e)*xxo7o0DdzFEQ7@edpJJzq+*JgBul0zrVJ}5&P zW!ty^sct0rGlU6~k50QAoFk2tdOgkTSj7B;@HfnC={8Uc!=jbVUxlRn-ghncL3cO) z?AJ4_>X6N0^Egb3KDTMsGf~L^ zQ6)VmSKE8)xo2BW-qM%d=yKuSlHsuUUr)k76M7|oNC)NSke3u5eyxo-qNd}9FF&At zaWU$YF8G{H0dJKhnO@Oy7a+V08wF&TRb)L%Q8bf#k2>2+Wl8J&g_N)69CUvYqr+4I z)$bsQmrKIC;c`72+fbIip`e9ZYFj?Bo*wF&mp}k!QNIRq?*9J%NY}`0I#H6^-0|pG z7-gKDAtRDKrS`Aup{JPlr%P6VnpD3#^l7u`Cf1qkO-5P8fr%I^n@u10D?@)$mGXpg zBdJ<>@YlXr1pLMuQ!bbistHFR18{hD{dkLF6*W~vXQZ5KBg4j!?#kkdOJ)gn&uILOV|WByQNzgKJZV= zn&o?{nO(9Q{cR&5-w{=0fDA%Nz`|m9cJ0Lw)&KOq1aU*wwp?tB_q%Un6#~*)v4JW(6 z9{$9*26(~boB8W{Yz?^{y_bn&Q9{{oPvK~r`@!$1Xk1%zD>{&scMVSF6T^M!vq34% zW_+Q;#tzn);ef2Rwje?4X6fs#LmfjzK8vAN4J7py0|H;*N+PQOiL83Z(ju~2 zZqBAO;U3;KR?V7MapbA4!z@eTuyF(*a|?-a{X1@fs>6?~puYO4I>`)~ndjPP>PMav zZ_0C~Ef9!pMZ&WUTcWZV24?D6N|yY+MN}N~#@>Lb72`l10kQU#gPL*am&63EOQlW1 z?8V0L(6MWgOyU?$1T2j5*yj?>znK(m)pD44WJwE5+zVZo4%u)-T`F6@tV(BI?#%IfN=$J4Xah9p2)a>SxDZPQx|@v z(Z4MJ|7bePhbG_u?O&Kf1x6?}QYn!Xq-&HSA)p{JYLs+$7!#0G7+oKjgrrEY`sN@{Ug+Vv#!K{bT0(cc6q)Uez9)Za%qS# zFiOn||Hq|EyGRe9X%`zHF`iCE6kPbczNyvll`i-2=I}HTHusI`{F%7c;j~c_x!!;> z$KC*}Ze3@6^{)ZmF`)=C`@RKhmgHOQC*gDFoMhKb0mim`0(QA`PA2 z@Q&&d?*va297KLB{RCY({hug zB5xKHJHHI~Y0<;BoZ20q{hOmYAC04x3Hi+dEv%@WHeRNt*Pi*>G~2>VPSRY+pWeo9 zIuCH6iF=`8Mag2L1z2J;mMEwHLos-32Sx)IbNcuxi{Yjf3yvMG6gNU@5;9R;iuho>hKwVoRg{8MQ63rD%RprcgtWppL7x$m*+oQYgzl_oyOCTdOC-U~l=c z$h#rz4IqiHZRnCotvRx(?tk@dVyBly>#csaCVwR4MpjHwx{XJZas!KnmcsrzrfA=DBo<2kS!<*D) zf0W_{^8)hmXj+f}4efBW4C?eTDh3hgqtM=BVkvqvFM#<`?8Ex}jtMGS_KiHdc*ftq zST?|MtQJ#$*5n&$-^IN34N>*9COh66@Ky#xTzc=#N#qqSz~D8AzflSckv9)LTW$+K z9;pl`lKAvyf9^%NIevIxB1=KzhP~Gc6XQaQi`+@<*W>|nHnt1DEq)RMrMLWzt=qB# z2t7doX&QR`O=Z^d+C&T*8l>{MrdCWvT5fjs#wS+gr>_Hr3O2jES2p$nrU}HKSph29 zd6@&W@p}75Zsop-x`R_T=T)1$hC-PzKs%zaDHXHXm_rZh<%i&FMNqno98zvZiK0#Z z-Mn=JO6{5}0DaFnC9nUuieov;If&+Vt;HUnH`hZ+NseC_5Nu!9mq)55V16im9s(iK zSj7+nNxx24$pSm{L);$2(l3*rP(FyVXS+J7|px zn!&3HYL~tHO{w}VnSE0g%hN|?0(@b5t>o9|{t*5F0!UKNTK8w|QzupYVF57qjCO@D zW!dl@K`;nqB6i0K;JlOQVWWc;GZln7` z9)@RNd){q-i3YDU+|zD@is9W7KZ( z8RVjGVX9Y4jdw4r_+!Ni1$Pyta~M$6aWLBbj>#mN%b9w&{|X#y<5%gRtsi?I~&+^dnbungY| z^egs;k1YM_)L@LmiJ{@0(#UJ=lapJY z=#HotJT^oQ!6+Ho@U{OK>mkk`KNo-NMc^8x8XZr9V3D#8@hPK7_GRmK`3+u&$jlH2 zi38w!iYx=P0+)AF0R?CeG-;LAy|8Ion~tP}5u0_GC`9E3cezk6d>oYi?1O#I-qPN| zw(PW~=e%+NNrqR0UgMu<=;fO=J$4G^s8u~9T@Uk0C5gB(t&hW#b`m^y;PB^#&>M* zLDI;E1$D<~Z3uYqT9kWN+BLwpNG?>iM%D5j%IKtd`Uk*yI`pdROUSK}y1EoEDgI;P zkTI%R425yr%mYWeU*_(YeNE{f$SlhdnyV>)=>-d3(d^ZSJ$7!rHWF|HnEtmAc7j*B z*jf!gu1B`Dmh^(VnV=jobmKdt3Qb3ZXM7dY)IB8L69KQWH-AnWYTS<4`j5{&hBcBkz39rqm_r?lcp z=cI&ITi>AYOkFl`C@?mzXSs6XYH}AE^o}VaM-CFau;t=qf4F_(Z;V(C?0pQ>?B|E1 zZo{OsAhmulF+X#j(kn#H!ZLS=FQTU*c*bP20o_ZBgv3?cmPsifIwiaNpJYY8@r!&W zO6lOVmC2c$KalJeETSx(=3%k2BWntL)@=_s@;MT37W`2nFJ|D#Q^0tKiuf#A6j=Xs zx!wROP%Nc{m89_+g8I*e5es^V-@i^p6aJ>)}< zPDH}QY7G8eoHiB1bG-oS&Dk5s9S;iz8yD6hM?vt8w5j~MNq-A~L#R}zn<^4RmF}RF zC+ZN4>P#4si6}&>rJ3Kt&J?3u>`;w22<7G4)>cN6@pzV-eN?MNjTKj^{Id63NM@aia)na$r zl{`kLEM1NN&15|P!pH)wId(&Uce{8HrPpOfS#bpqq=Ggh99LESz~`Hrw^ z)pP~U8P2TiiX02<=^5ChEHB6OIw+Cr6D%GWjxWQI zzcQt{Fhpt?lTh4TtBm<`THSp5zNNR{IfAR?m|1r!b;Y>)SkyQ-9^zNAl4DG+LICvP zux4+eWUtc=Dc}T3hgISeI{p9Nqi6#!^t0 zjA24SIzq-@P9y$Drp+^8A(GMc1hLy{;=b?o=KT>2GKxUFR3=x*guYfFmUMWvz_eE} ztx7JIt1RYd9M1++FE7$^YaM5cA;Zr`320i-?)0n(T6h~0w?fT@N}jH`g~WSzRG28( zR4~H)aHHugnhU2|?9*P`s7W|~YO4(Sk@jw7a!rJnl3LV{ z>buBSd4#3Ty_0&afz-(CKZv&Jy6g^z$K}(qt__=f3t54x+eKRYV!953A`i50Nk(Jc zpSA`bY?AdtrOf!(`*HR#&RE{warvf8KUi5+N+fXSE^k<$e3ak3pB*&Df?9(X&#x`o z#X##^u*N!U80q2Mr1gxan6W=$^AOzS?o@DgGQrg%a?Hxh_V_@rKXmr^rsS!Bb=r%K z8$7gE6k1~?b+wD4DrAS7Eju0l}BO1G+Xlk;x~rh0SM zb)+F{sG?@^SNqD&&)KJ= zcVu&}dzxMUH0Ghm)CphEq(XDf~B_!E@!>l7^=UZ{a^Q(h{O|2Iu|8|m85 zkb+lcM$XQ$V^b_@QCGjP)WXxGp%lt&5H5oc!>U*H%}#3BxttQxOfft_8lC;NG~JF) zN1-g|%w1J$5anUZarTL$0h>77lc~LeTDd8sCg>b_ywo+}Iv4y!((Qi|u5S*d`DIL? zT1*Fp2{Tb-2#v4Vo$^Etf7kiK7(OMIsl07xl%A!N2}jL-h!ljcZ~I|+KFU)Bl$qc# zlt3*0)2gbYgk4218xQTR4t{&xDq_|__pPLdtT#m%LKDR+9st#i98HQq^Cmg&r9)AI zq63)2+M?$^=q+i=3M$S^J3w5&laM#rNUOlU2+Dl_I@};io;iftgL}>8U(iS=O)cuJ6aaww`e1r<{T6_6 zSJKui=|A2+Mb4W|+ifehIXjp0uBI_x|H4u(2Kp`->n*{MAybpZDLF?%en;=x-12BvcH&E$V^bcDU{aW-&` zs!5rTDQNG?ZiJo|vgS#|p9i0aB`nua2tFRJ?|GvqkA_ZPi}o-h)hW5&{oOhUX>EJ= zcU>gCjnsyEog;tVC^dU&1uDx%b5}Ux==wb$Q@hzRBy3=Y;hcR}`uJ}u3rd!}Yl7Om zuX2pLqU-~8QiqAWQW|YE=uB7Gxy6$(ZpvGPXVspvaY=eL&(NIYQ0)z$ax&e_f;JVM}e+G95AM>p}-- znQii!uK0&K_hAOpZr?8FcZg>xKT>UPXW)jH`I@hosHPif(cOE1zfoNO-&dAlEIgjm+5|)W*-Ct zgY*5=PH^h%q~e65NPTm>7z-mOvA*l0UANile zIH2X+0@G3eCMp0x?((2jCQf|U10Zq4DyE2Dd~bEgAgn#&pE)+#*ZqDU%fhpXO7h|9nrC`inN%60z54gL9$pbt=)P{Q4@ z2Qd!e*znQ<;-JXL?Mc_R{tBX9NFhG6vSJ<#OgPSvsq18*W%uMm+`Wlv{;-9!c(!Ap zivS=8Nt|{SNl?CwK+qOsWaf+!@TN^sHFP9MA!&w(45;5a5^slx9qAz~=A;7WzkLbR zU5nf-bxHW!{Tx+Pl$5+SlFWMa%2LVWzTY@0elGwAlX8kD=?ZFL9%Nj3!H$0KQMc$O z%?9Ejj_-?U(>lylPlZzv&Au;j%b8jA->=T!Z1}6nf+C09<o|A$b~WKK&~ps1JL$tTjsBbX}>qJO7$x%nA-lTN>KzhfUL=N2IPCL zWr{y%RB^h4V-hTQiH-d1+4I3RXzG>0Ke0jsXb((j$wKtzP&5Ts z!PB601na?K<(UjkGcj_$(n5bQ^V7-(If+ZA$j!1jOd5d=BkNhCM2|+lhq(0b!v)=M z4DVk*iL2A-o$OVd50R3{m&5uSM%AEItIa}lX5ADelT#l!Ea`~ThgzCdhXj!k^2W&K z-GkH5^Y>k9#^%qS@8=Bp>@C@4OR0Nv%3FM0HSJM(j;dw3DX<@E7&+|F_P$s!7JFe` zAD2(+-k>bpl*%-7PLj|r;0M)rDxQz1!{l$_Kydf6#ingZEywnlZ~0O+M}60JFodHm ze_)$c?Ci|F;Zo$X-x2heEyp*{D1$_CJ`l4P2Mel5^N2zDrTk${aa~{;@$Kv8ixs}TjdLki@}^GJ zvv1Z-@^je)2UT(h2V_rm$LfzHxgRvCM=6FJWnMnXY`n1M>kPsRXe>pxaYTA-=#bA= zP7Fjfk4NROgS#3OZ!_;KpU2gzBI7vxeY4r-vd-Hbhd<4w-iYo0L?^LpLH9I;Sc$ep3N|^NZE_b3ns}&VuatcgWR>P)kB>xzQR&Ru zjvE^(P}<(FfJWAhPK+`GvGh(7-ke)bgPPJ7$LixYFkUe8Q4E4C!JkzKolB=3 ztNXrE1jevG%;*(hc6k8ayY zlO!sk6ZFqm*~!|q7N6pl&b`ERF~mS9`~%1W2>2edN4PX(Z>$fB2N~nIm=WWANtU;# zRz4w9ss8Sfx^d)S{PM+;XN~q_usdof?>!rlGW8YWs>sykXl2i^nSY5!JR+vkk22?J z(1fN1=r_*0L%7iU*c1$-#$)Z~#Qn)ntToHh*Tj~a&185-NIU@H9#LB79sv9_-(j8I zQlEbk&#GHoN*I!zJNxEXM)CHA_LrDGoAt*SIQX2W}9jv^d^CXU0vj8Gcsv>%8LE;%*`7`nG z)6_8^O;pnQ;v!+5H(~d(q4^dcV`VYYwf5kA*)AkMqOMF3KC4EhRhPU;Ux?bmjpg2v z1j06Sdoo?(DBJT17)hNusRL?5XC_9_w$jNr7?_P^M-%ZzAYT zP@bBl1WD>L)KjK4D~H`}`RN<^_0s-vr)zJ$P;71Ars{SPj9mEaM@c-^1`^Bsya!!8 z)~;gIGuhe2o-pcqo1YW6(~v&KF~4quT=E_uYBg=i4B3uu#C-SjQ*7-U_jebN3m0qM zx`m-6Dz+2+)?oggbpcb1B#p!BgMVAcCy~?Q-ZPH6Z0%rg=@#;jzo6C{4AqE-#!`I# zkbfL<=dh%lke1aqIQ6iZ%0BJX+U)AkIHE!Wpq}0exOo4)LUQHwKHyXq&mB+ftwEpim z?Q0=^r^Uh$Nz?di)*CzXGi?hOU8RS2zRXHRL8o5L#OR&L6so8-!Xo};+$@M^X^^{x z>Ueqlq;?%ORx;piuPe<`gHJe80q-fAc z@BKA^XCQnhV{;-{zmRdclqi~7F(u%Q`tNq!{y3S$J(FSN6y$=-Zy{G5mDhtVxu zIb~trZYj2)FAnE+A}}w*zC6&-*6r7AOY%8AJfzUq}4a z;*L-Okk$5;nyb5$$r;}Xhl40)ca?~>`IR;^ag&It-QEN%a>tc zWQL)D7>it#2$Yo{n_eGzxS7db6IiVfDn#CHesZ~TDIdCBaKh0OYFTcO>eD8hyD1f3rZ#a8+v(*cv_sy!Gb(|q2PF}RKXfd=A!ufvqJ5+=?15PTk;*c zmF00AH&=NDQp-%4QV%Us%JG0(b;2>+t0no*Ud@%Cj;Ie3X-%FN>l=D@DSgG&mmcJ? z+feS1t*^zsph0f3z97;1&caeiacJ&m>$HHBd2 z2a$1(aRR%#7djz-U?6c}@$YA8g5QDAK|5)yOXOm+e>Z_uh}J@W(akvKc*I>Ke4`UA zCm?^85`#4Cq>idi<4y=kmf2X10DmD_pyWd>!c|*5#y+XS9r#`-(DGRng0B-S`j-r!-{ zhnmCI?X#SI9}XoH%l&}gRU$E&#MZH~SVWkyofiCB9t?;w)K0W(tTuW!o}^m0W2)8I ztAN5=2=aX|Y;e6*o<>9=Z*sLmR3ESid<9=lEE>bK_>4(a`k0B#g;Pn)QaBBPxy`dZ z9wfRo(J64nmuf&p0@L5vZC~ZoITYP>8omm=W%R1-`GNQ%K=6%y)*bj+`eLU^nms|~ ze@$aKh^AjsZ8zV}gcH?NPEQ91u$?aFMdZ!gOGfSNzr(!;A}N-07u9Q#0}1UPewm|Rj4}TXY_tiyTanFx7a#-fXP{W;R zkKx0sasa>k{_J#}v|CGYpQz`DfSqgo!)XCtDWa*tI$`06SI=Z)8p+B?J8ElHLvWC9 z@iVJpr@34H>6C%9^Lxqz>T$aWC=lP){HDaV#MT%(m!is8sG2mNqKS-fD~{9<5GWax#p!db<=J)sCv znDldzCgPEl*BzVkw}cXTka8$qB#2))`#5Z1>u-l+LzM+y9CW8ks$S)KZ)%pA6Cau^ zz}z*G%xEen5h;f|Z;;XYWe!fn9;`o1*H@$lI!8$N`OvD~4CjYSXWrU7iptWrFas8$ zXR|xhDpIc%o6jwxyTE1Vh3$FA`IIBdzNp^)^j?y!qRf2Q#2nvxjAiukiV)m1TY;}d zkwFeKayM^zAmMF!OfN^TMS_8qc=#V!kAmINmlt@NBBR=5$rw$v<`)#i`*VpWQK#T_O39de!WT3FNz!#HjwqXMXwildJqJmC1w`{nBekXM0d1{0Gzp(E0L zz6#;8nU4l?xUX?u=slMTINfcXT%p;$Y@8_SogA4~Vyjna30Ufy^>j%m{+qc!1DSN9 za*=o@5|KZ_d95skNluKZ*$Z}-M*fN73-vRnp|Tq?pjkWf^O8MwP&zKk4Qsv}C6G%A zw-qYpdAw2i1(IkJ8EVA0;MjE5&ZLj}q}d&WG4=NOwzYGuq^jAn>L8Oh=Yzv7$?s58 zLq^rr(~*%bZ=ht>^YQVFnPTASDo2=HjTT&uA8z`sO8O2W?SUX_Ry2+7eO0a~BR#5i zaqety>C0B8su2vrL%ktFzF->rK(II{4J5S{b)%3m-2fivYyxvkn8(e~EefbTpz+2H+UG_m; zzS8bSg4Y_0n2+nLCsaTVh^ML;xVIV>`>A#pE0E9$g4V06-cTd1zfJvZ5oelUbHQNf zzQ2@8XoY1c(4>kSG;?3&G)t}T^FEVxz762QPrEPA&MK!DkIPxN=4vNm+Key3{F`JIp*+y6IZ|b zW}+@sCVp(>Rg1E;Y`khybc)8ey;D5`EfRkcQqaICROkMc-w%hPSEBfD&PWppp){0| zXmUq`NjIp-!U0jSDO0JJNHh8WB{r-UXe6IZvccC)YFwzNODm|5v8~0j{Gax0*RMr7 zJAWN=+S&*mf8n>^M;Y(jBkCE_qjW||uk>1xt7QiH2yeT1E#FzNfM4~sgjU_F@ql+Q zwfjw%mWLQgoVBbBawqpfQBHcGefY;f35E#}4NZ2K=3J~`I<<&;w%+9i?bKo^e~`D( zM_E%+ZKLGl+WI;U9v{Z^b!-&>&^dax)c_^Ri`wK}-+Ji-A&Xgu&N5&CfNQ^N-WPv{ ztnHS9kUfLmeP^{XXB@4?vD{N0H74B{ne;*gJwS3IjZpBgwOw96(;B(C~%K!+d^`40lwsfZanORwrBT`tjt|jOk-EZw$ZnWnT zWPLcBNlf{nFYmKn04SF(FHaa+u3Al1; zDm`UPyT=MI|2UKo%RXF$M(uL-v;+QUsiWH)*!vICKVgM6^X@LkKabi3 zy*N%jS5az}wpDzw?B)v8XqzSzyV>;U#C+VOj6eGk2yr<+8me0! z@{LPOyT*mOmcQ@j*n=<==d;kxHB*)0MbobSy$IOs(%5zXAp{%@>bCLM+1YE?nzbsD z(_#DBOq?@q$grR<1G^OsF@I+{Vw~NtEO<(pNH7;Nwgr#}T}@W_QY|gaLq1Ugc%9I! zoMl#c>(4zYcdmUty+y1`%!X)U-&VC>#@(X}KU=uwVdf@I!EF zF+iIR7?qZwSyVxBz5i{BVxplNjyAfb4e1)COdl~q5K^78vYW!>Z#!tc#8*(kSNKUo zR3M}Wbv6_;^P)5o;Zt5q1ni`d_4Mfl}Z)uTOs zylb)@$Bcx`ZNp*uo|dYkRR@vM`zY1wX03ab7uBpPQ7?>ptoQ$kT-Li^x)%WdF2+@4 zTN_SCRwDj5P7zi`(gnMY3ws7ED=hYvqaQk#RJ4XC2o&-S0*?FpfO1pK4ZxYgDxNW@ zDmNm=YL2~b_jJk>-k4ejb&H>L^&E1lyTbVt)+Xe?S@&ttXV_RH#zIhJDTgKVemgji zgNlHkBKn${K8JY6&V~2Y`#yUrv7op>h<_pCakYGBu6x*%k#WxUJk9`+57f!tGIe&w zNMw|XJ)`(fJ5Gm!D=%yfulv7%mRCQ7@bTZplkUUE*xhg{hi*U30a4!;Y+zLQCpVbd z{K}YFZv4L7Nc*sR_Qqu{#zsK&H<--oz}6^LoY5c8XMG4s>NqCIFSXtdwsxpNgh!@ix)A`P-J)>T zAwWsiqk%Fi10{7P?wtYQvuBoGdOkCT`IQl4rsJ5G0!n{F20?=8jAY@rhWna;`QXv{ z1SJ|(Jn`g}enUkq@V`iL=v9Cou9=6fMKunF?H`JqcP;c!&xia=`Lo=$dHMVNyoflv z8lGJ?rsRUv8`M>7BN3a!B~SMmNARRpmdyMHIZ}6*NcncJa3u}2!a{*`&|LXr8l2KG zC7WBk?56-QQXCzVF>MiT*kF7>RU4^ek(6+;E!9Ta@i#?!9sgm86^nR54Kd_X*vqdQ za$5UAuE^WkukN~yQOnFyRYL&KiaNr@`MB$5;K;{XD9cqYZ?)-HB%?d1pm(g|<7-b? zr$j0F(9Y^<45k$SyAgKlixF|i2#0#pIBmfix|hyisy`6AV)g#>rr@M&t?9hEJolZE zjvINRjc4LAm&f7guEC2BYwQACtyP`quqki)#T zLKinjLs1ltk2jtUOJ(k!`2?+KR6ERiI&y9F>;&x7Pp)pd2$@du=%o-YT$4;btiAYH zI(SjnDB>n2?lB|hq1@iK0?-5kx zZuR6-E+197Pc^xU<_L4v_-*0y+|Q%DR=mQu48u+=1n}y`-3Qvve|Zs|-T<{!{=rq? zeW&Tp972cJ)X?F;o}u($If<9v)sW{+HrI^(a!yqy>tNh!E_V1FbhxL za1YgD*D-QF+B#5w)s!|GdSMxMcEM2@<`6Mi-8CZWh0w;x(8RWPKA)MOOiNYd()L9K zRI%#wH4drzWxCp4m-IYi7KPBW^!>rl!Ql7tIMcr3=L$RO)!l&&RyjsN@_}r6?$~Cs zw9sDLLtHQj{on8I|%;fsIAm06;qDwl85HR5b28vKLw>&Mh z_$|!^#HyP4Q{_SEGakKXfNSqm)^c~!5Cu*m3I}>IlHD_VaTR{X^YfN6bEFu@MEA(B zCgr~)e5J6P3w32N`W{j_BJAUlv$&(hH!Y6fPT_rKJ)hqEnbDn&&m8i(jikCq8nhAB zgi{QZW|?<5#=?0JTx$*16MwUb_*}7C7FEc5lp$8xoiTNEFQII*Wq$4r8)`4s%h_Bc zL)4)-#?|vhqTJ}W>O8Ta;*;?cj_T=SM~3$Nk)8xv;U{?C;H}as%?T>=TybYErpUbQ z4VP&&q~LaJTwMe-wswORjxmuwx^j)ot8_RkR;uN7L>TfkmO%ENRdZN=R;1AjV5o@C zJ@qR7M(qFe;rCg(l77C(ucM`J^qx}F_M7X=hw7*1lxjF?L$xTPZfyG<>kXC8_v;S7 zocMp7cr}m}=P$Z0S+f6GkHd@a(&*+qThQB>op?1lYCSL_Lg|e;<-7@`jWCdX>#XAw z!M@zWX9o5-wqqgzbVcR{hykkJEz{=PCs+=>832%CKwxXfjvB!(ugez9*v#oqNwYFw zD>1*L(@#3f@^T(2VBzB4T9^PQFUMJWAT0dwob2-a_u?ay=sI`Nyezpfrv3m!!DV$q z7_5f6WBrP?fIu=vjK)G52hlf(%MrOz{#Dv7BVU;OMEi-mm>3JNb7ja_i$(Ptm|Fyl zS!I+hz1RWWov*ekdp;yqxVs`)wokjl{4Ul~P3vy9Z_ciSj*AW;c5Zx2{hcRNmfY^> zob1BtjHwZ#jW6A!-@3hsR>M zpPn;tN6m0r6juqJU&~*_&WwLFK;`66h$<|H86O`V2L8)pOv&(npTe2n=fc=jYRA*4qDDefzkqIUh6^h>g*RAo1U6`tyR^-rHIXCE&riZZc z+pSSvd_TW(WSYm%TnANPy7mC-+Zs$ME8_7+^ookj_f~=vEEQx#T;WnrExu!o7{`SM@c^m^xi9-q-TF97EY<}cmB7}oeDscxri8P_NBBw+8x1-7mf#W7J)Yh#jo|fP9y?3Nz45K0je3RDs0j8kx529L>ssa9tIP1k5V~gU^3iDJo zWk2!`u1I-c3LQ&Dm*ZjSs@bzg+eKK8Nd2uH0d)ux?~vsw!$JkvfwRp=N=hxx34pQ$ zb$s|~S}@qfmVZ&r1t8qWLw zw@CNwVcn6`M13A-Wwg3l8a8k%0l6#`13kjU z`>Cldanr1HeBrAeUlsz=Z2XQM3o}-}nr1Y*-t92n@3sYSjy9j;t1$9?@h1cE*^-kF zP4@q8R~CH}>JIRRh{15}!U_KVon1THkW1SFgI`|-vgIh|B$pTdb*1VXaq!zc(rUN$Gjc;cK#TXJK^{lBUAUajnb5Kj zBnKki+(TZ;I|&U8d3a)~@|52WtyyhbK&}#!n$sCsA`I1=>d@nG{2zzH%F%aHS3{9h zVpnOq@9MpFyut1GV%8s@Cp#ybgy_BwfH~gVv@6d-esRCbv>^CB;5HB3l%OKBsi}RB zf;gPsZ|_w~J6rmO`n`Tk`S!4Di@r!K#^{%eG;S42;jtIv7aFjd{TNB#AIP+96d7pz zLf8hvr>E}ccc`mx4}k9`|CZUX4V5Z}Pl!YLn~ zcJ$^iIcA=~v>s4W7&yU}`Jp<2Bdg$1EM>=pW5Ii?j3z}WqE`lhXr}8gO)K@ZWg;|s z|GDg4&u@Acb;G{wNmJ2#^|ViDEfl`zu*q}EtWSH_ry+U(pC8CXjeK@3*=D7D$45%% zoE>-=_;7z=s3HTl!IX;=G&c5Cl7| zdw6@dwbyuWYiF8Y#>FDEE_98R7xK&=Ie4`vIj2w=J|Q`>#6}$R@f}wrV`5kS1f$aa zRwzp7Kx@jy_(WP*Z=ytLujFF|j>p3G3Hx2={wNd|(puZZkXZ=Bxky1nD?A=qO*X-B!c$$H;?2qUZBBiQtir{YFvpj*9A_--LSMK0-JY zXR!T@L7kU}yX(JVp%Ybz&4?ROL&}6S+tsAqW7Pj${@p)b2%jpXy=3e2x&Oy%OtDrE z`mWndCi3YkKW*W~k&bD+yLM_@XWy|djpmoK@XI|tyB_YojcI}&-sVwuVLNNi(0>hk zPkI7hgYKDr;XX{kZ{CFOB|p)K5nv%nL^$j{CHx>}M6WvLkh?80kmPYmUbT2t`&bJV z8~Fz6xsLGO%FMgY2^lHSE`RuhTz>M5MdM&(`8Fztmg`x@Ks}A=tLwMsX+d=%^=MA>gu`|96X9i?-xBrkdFfIbZKfrOYHe z$ln}1K3a*Dzx*NR=1wSnsVEn|ur)ysX9lcWTK;P(2O#a$gIhqz6SFLvKWJCgr&tDq zgnm!|W=rRf(1P_4-%t{X5t*zf&vg$xljB{ zRzB5tfsp=E4t16aC_Xn3g^lAN9KR^1tAR_i}~X-aoBx0^h{&hX>WU z6jriwa9iBzr)O&IgznW+y~xCmgZQMrQw&Mt!6TNQ3y5;VL&doZoE$B0X+RfJZfEWZ zSc<(g1byVGgGqMjC>azoMiix5ig!uRRgtdK*t4qpZtt7?s6{Zxj|SJLw*t`b;)a8r z9b%-ZxOY!+jnZ)r=DHUR6@q|~gZ@f3`zF!t{_=)4syT9>>G!5y1FU&Nlv*5JRjnb% z*cEddGddLvw@vFC9U_REBRUVTqPO05B~o&M2}I7In_=V2O>U>#%=-6MC4P$(4|Pm@ zqiE;H26Wh&!K8@uWtK9jE0fWYT^N=!+_ksoL2J5}YL9p0PY7=36!2X?oC1RKo0z@X{M&#bxIJ%0I;aHM)(On&2Z($(tUZ-2z2Cwe=zd3WxzC@A=V zLo9SJ#zXR@YS+@9u)Lnj^Hq-0)S5ZUqa4~I;(ff8)0 z@m`!ZNU3JPApSf1JrOlJ+u5+DqNnY)=rR@Sm0x)!{pSb0UiT5r_lG9Za@BLe_Fn^!%>~OBs~eYUCp7bi$%LX@i*vZ`qbolT^}-2k0Sv;4 zF$Zns<}Q$;|E~oIo;4$|KT)DPU7ueajxDV-O?YMb*EPfm{|}b$=NdGk`f^_XnW{UN z4K0x5khf0$z#L$UJKD_*4SQ&#jbHgE?T1FTUxTMvz5nh%K!;o2@OGz2YuPwrD(rQp z?Ve$FNc+re-IUtMoRM9v@3**U680v-UaF2y1Q3nx<*Wb=d%R#XE9LbLQp$;wLONtbY`tb^il-03L6t;WPd{1DZtE0P!&r;!B zg9eq2eWqLfaGa>TzUAYm@^J%l_3aN(-wE3|=H%uzfi9!H1?aW2_k?3nKOcN1J(LSP ztr9L{){JE?lFzm)wKdtzQG9*XdK&eGFYWhJl#1=>!m!CMZN4^21?2%PS2B1Kh}wIA zx^rM>XsE@j6d1+X9{W-LR=(G~f7jH8jp}5kW!5Fk@P}K%{CW58CBKqMYfh_q=&&0Z zX{pc>em1maadyRU_C{b}TU-BND~~zhKx!{Aw2hP^>flo!s>xIcxt~9^?|E`xO(aak zuDMI1(bm&9Cf!{A(sk~NvYqHv&ejb1n3oDEYKJ%P$!2HM+*O0h8oCBBJrJZDfE20J zcr~?fZ07B3zDbN2kFV2J(5-hPy|k@Hc@RRRg0}o9Bqe)Gx8>C`vWZTJpsk zA)^z-`I3q$VfHlCkWTBH5#P8r)AfaY@eEDxS%t7om!?~E4jHZb=2#NpMPTpyBp1@B zdSK{(i>onG@`VNudKu+g{$)gM=&Btgx%eL2)y%X?_OQUyqwKZ83sG7EjqEAV=DfnG z;7Y?CvPasG1R|#^f-d8X-q{8k%kg3OEzJ{j8Wk%d<2_LnoG)?K(V}V^cc*9VGYUT$ z2$xmRfaa-kGOH#73Sc@X%&Vjw2Fv}3f;?2$u=5ib+16CJmuVw)XFxV72VW$Av2b~Q zF|KOt(kUgLW7&2VY}~eVxxaGKEEjdCJke{({r>M#OmHb~rE8w*URSV;+-0C=b$DB| z?-RsVzR8$wckFyfTA|~PcC9r9_^qu}w%%Sv-PbN~BVWlM$+fDx*ghp69xkpv`Xj^* zy7Ay$+$JqxYgknh2r@AF0cu>r;QaV37zMbkb8D-xy~7|nvuf*|7BfAah1su?q=Gu z_ousn5iR+Lwij>qelfRqs5i{CZP!8g7}t~Qo2XJnymJ29?sF@gyBzU0-!TSY?yvvH zM)To;1s(f?fqNRg)oPfwP;BE2l zkI79D^#|O*#;j-gU1F-p2geNlRj>X2D(BO>O>p?{4bQ#KOPFKXFS^Xyw-syC6;bO+ zA{awIR`0*rpY#f@58k+Nl}-3DcsYF5MN&y1A9V=9Q^^6or}Y-+|Bt5g4rl9s-}up% zMoYykS~1#MRbubGT3hYfGggh-TPrn#wx}TZpkmi5YPZxDsv5JQ_Lhnn^PArvzyEVx zxpGd<^M20#JooG7&kpJ_h&qQXO=rZ9(}RN8`#vTv-IVp}c;I=N@HE8#(xO?|}LnaUw@ol7~} zhC+0lJ!<<-&&6frc3M^tD2!+6oND~c+p9AsK8b_tOLgUENzy32qFeNQX1dl-LMv^0 z8fJXMBFI>t+x{cU&h(FX-=^!%2KHQ}Q|;uduONc2nnnbTx&<5Lf#pvY^HhhyzEaU; z;iFuGxH$jJ29EEx8NKwSUk1rO__h9fqxJ?+e@>num(}KFW_u%xCHUdTXpK2I5#l6~B@{Y4tFGi4T6 zuC{)DdTs>ER<#uCb7O7!Y?vtAtEN=yH=+W1&oYzE@rR-3XhWU`jgb?*>8$Y-a}{x%gUv~*){VL{+j~*r+I(WwbkR}W zb$_9|k5Evp=6^2SuXu(>&7BKcaTL0HXWBZC3h&6X z6H{sp(cOr7a}Uh2a6?N)3u~9ZeL#b6Z`fe&MiMSc!aY#$WVzkQI`o#I@BCe^EIGA! zG5vUsH+-~UQd@`aL%dDvLx9Gwzq7enKagY7G*|9Y+TtESY1p1hn0}PmYFQNH8tHq) zczgEc;ZL^XAh5%=XmP`qmWQ7E1u{~a@rXi(f?$mv1NMp8LoszjW+6R3zmM93Cbqk0 zUh93F@5XOjjb5#6Oh}LDSEmt=8oh-SE!xb(>6XD6?DH3K>`_g)9z#+e96*SDHvFMJ z=<0H*>Fgy~VD#f8%=Yu8-38{td$dD}$lt-?uzxS!f6{BEGSs*#zK^^08v}r)OX=Tb z#;Ud=0i6$TH;+@TP*Iz>rPl7F z#bVIxFV?{~ycV$`#O2C((CuFw0jt6Hp1koVv_!4i3^s4@RG$?r7N9ILY$Wtsc>a_x zc06uNB^*@ZN?>v_f9%R%@YiW~(Xgi+PuN`px*X#ST0U6RcV28AE)k1C&H{xTWdF_F zpLA!Av#()_=4}c0+am{3=TmXGn^kE}_xH09Rj*06p!O2#?@slARslC5Ui_?1N;b@o z7~ucvd~c7`%x<4HdXqh^n=aF-7savf1|0*HpY;@zKgu2Lp5nvCdfMMZtxI-vCN z8nltg(Sy@zxY_N)2N6!}&mdBaMLYsE>kaJ)?)kAxBKB5#mn48y+Rchgfp`uCUs!CM zNniI|bG;u+*Lwjy6Yy-I((JgW#*S%eIY3jM&)K55Zne!D| z`gh!bU&tx9Y_%lv+Rx1T$I>1_5o2bfGv07ouRG~+(p_6Y$9UQosL0bGx4$pj%Z^P| zLEm=C03GHMR078;;a^SE<_!9~6ewNAHDr;EsChNJ!%oudTRXR3RKz zMTQ<7Ze0Z)pDnta?OsUcG=O;7S@EAEKU&WyDtNVxU+ijT30t&@UYI|+i%ed@Tut5; zS$mJFb-m2ynJzZbJ60$5-%!DNohg+DVIut;bsK*;WjoPfa(#OdfSpXEDc)-m&sUuq zG25sT50$+Q15-By!4sgv!iRTM;G8O7WkQ9nvC!Qr2paJvTUaK8_A>W&tMwBMGC>yg z=E8=MJ7HC`Bl`Pt&+_M;dTCb|vmVU`?K7^C(kLUwn@HLLXT)R!!k4Vz_(hPlb%Tp zoT|$+OMu(a6UCtMSViy z`HC5mE*9El8q{+cc?^p7vzOBC1=+u3zOFP8^=yUxoF-Gz3}YU3Rk9@uSF_t$^@=z< zSR&$Ah3YFfI#0?B-KkWHAakM$oi^bjonp5NLnrTtL_ce{r&}0E`kkUbub&1fEzMIy zS&x{$8k19D5F|kh3KvJRIb<$wM3)@v_QW_{;-VDVp;|Pf2OoKto(IgyCOu0hL??x3 z2pCT?Mwoc^DQo!7-EYr9yJer(bG*3x>oFBRYWxq|axj#d1jUj^BEIc^C`x&dP1hfpX}U;3f0+1)sF?H%QjdQ@$P-$)q9 z87VYQZeLy<2v5lcajKmJo8hs41prL#ADO=3bRpXtd|dIv)wV})htmT#^oV~3E4UCv zfW|#N)-4DX|J~P;NUw4xn6Fu8$R$^~Z-nnR50xak-O8+}{@{lr5tk#Z*-I!FTBfcB z{#B0(?qi2KBlZ|q_C7qr1KMT|dl1{d1E^FCLZY$Y}$$IAo zqHRjn>L;f&#*Jf>&fP1QGJ@)jKp}r|hdIF-Z#PReSVZ)i4F^!#5QVGkVOrCwU3ECg zPX_KfT#^#dtIwz(F@QLel3{Zp2sDb&cr^DyMeRRqAnq9Sc45UsFkiv=Caw9<6hTd6 zk7J3zl>S!0ySWy3|TwwFE@IqOgY1 z5!Jty*H~*4#@VWXdQ_d;n|J%XTCaduFA`iv6>*)V-(NYzjQR<;h#r%`dPQ7QpFHQ? z>Ji0;mdE9~4M9xw@Yv6Cp^CO6LUr{d$fZmhKCw2p4dNZO6w%3Y6H!F^AH+Xvjx|U< zEbu@C-YJmU&)Z+=S<$a#Eq@htmfNsAexHmsS0Ji<;&L|pk{#~PRc8muZ}7m8DXr|S25TY>fzk1Q~1;ztKy)V%=VD1?<_dZHyew( z?t+BVydg2vvtkh6F0BQfaJ!2)1;^$F8QWBGjb)jXBN5hZOUy2x6CrS z=BuDfI*&e^B%Wg)fdN7A8(svjq9@v|(Wy}I3ms{Sz`1=9Mfrd^S-4=tFnc-u5Ob99 z+(TGTM1``rQsGNRgNEow3Ygin*5QN>q_E%#%@SzAfm{h052mN(l+zvI(wP#&o^?A~ z($hWF;kNav{QgNMl>HI2Dzk=f;GRVw*|(!G{At~vatMk3KPS7U2354~Q2IKZne$l# z1b84Inp)lQgy2A8NT>wS#SEXX_|WO>w-^okK9RUJl;2yzqv(-u&XD_%y$L^<{0`|K z0B*c_)!N~H2Q;+2B9y~pqFKVVM7b*Wa+h;E1+MPb6|=oz2@FFe2FUeY?J`W#^z~Yn zcF_tc^3Fu}sQtZaT7~92izF~S(!bZ8zpxlZf-KYEdt(P&Bz32YMOTb!DWZRFKa}QU zmz12S{47k#RkTSBghJgTworZ`!`NCs_fI++13KKuK__1_d$VNgh%XeJAX>dTDYI_h zS&7k~XHvqU+q0nr-;Ynwlxe{dN2+TP^XZzPq8}D8>{Qd7KK;^b;|E>utxy!gaBPQ6 zC=KVDGIAI!k@(XAMz!=T@=am5FWaZ`ouLla7e!U1$p)HIr3ef4MmS;GiVf0GE7`gJ;XqsXTqU=)(5T(9yT1_Hv4r9sem4gM&Q> zJNEO0X-RQsz4j{7jQg1pwGp;nIf+SyguG=E)Qr95P`8=fZjW>h>Z!fUk7_>;zv^CU z>WTF&l9WVJ?F8y>42^n6?Xb~|*DoV@~M;Oy$+AAnZX+(~0Cc_Xfv{gL8BWcd5G622GS>?)lD))yWCbOs(gZ#I_L$yF&8VR52N|w z34ZSxj&o+qZ(Y;LODl;Op8$UFaSq7IeuqDUNXNL@?yw(%3>8xM{oNW2HL!i3bJ0>X zM)*^vXeU~s!IICf8mpYtrlgMA5xlwi5B-2e^+-xX;?M1N`sb-54vUpza>(4gsMmbd z{!M2!%`7s5aI*)_({%Lmy~GXJS?x7OO%b}})AnyY)-L$bK<{Ka( z5?56OBberg-JTCAX$cLol4R_vUpX(7MqCiw_v&!hp(F|EcDD&s(}^&bt=EKX@bI?y z%?^nQ3rC^1)m(^-E*G@+?`5dJ8BkcfGb5>;*fhKr{;U7d*GBHFfrr`TWxGk5@HI1d zkS70~pg5i)7R{&0OW&BCd4!<}LwMQW4`f z{#&B==|B&b=kRrcS(GbwLGO?h6rcMkJpd!6u}2&tnuM-axwjTR<{7;vNE%j>9FB)p zt7}|yZ54qaQfdvhr#@MwpE!M$*{3{E*UMn^;|B4NM=O33Mw^=ecl*Jk^fa+i9^waS{&;yUck@ zl(vrtkP?kz8_5(Z+32i6Z&lUrT?6=of8Qm|4@}G&-$L3YL+|I&&oc{sREed8Po#&z zU?n4vyu_k(L;}Y<$4Lg&>U6&(6XpkUN2;(dW1x^L#Aay6q$AaWr^Zu>QGKZ4#m{SC zH6&oC2^31J1RX>Q zs^+hxTNEX2*0k$hisV%*B$yH_ux2eUAvwwJqn-S_AI6vIq6vmHT<(o?<*^_*?dyI^ zCS~~gazei?Po^Hv+KP26Ub~|Eeqn9LmHnKO>)~ncafvr!C@EjkgQ*u*?$zW{(=yH3 z)$IeRD!s2=GF#Oo!V_Ma{e(-|z4vH}(X?KP>M$_dm`2I0NxYbtNGUEC!9d0hryx0? z_Bo#RMiKxHIbG(PbOlm8U!F8@8{YtlrVP}Bqn`s^P+J{(__&yEzrDaGL>_wplijcT zLHYnQ&g4w?d@W)e3t~Td{z};bEGV=#seDVR-Qvn%Cx@;JyF$E68iYABIf1qy0Nm{E zoG{r~b4G$r6$QYB4T{O1CGGTRNw0 z9HhE_eYkoEW`lP_b={cYD@P$=*f9LU4tre10KM?Xp155D zxoxkUSL>YcpEGV<$hxG->dTQ$?L4_YRNBzOQ?=m2^34f;NY0!rZeurOewZIJAf43q zHl7DLOdy$IVTE+V~06c7GrVfH(W*5Nrj z+HLzS)%Yve!B1yDl~$6<_)!?p{SFV(#Rf5pruZ@+SFz>~3DK(Y(Q8oW)~9p+G44}k z=-~q*WU0EN4L)#ukTp%vmIu08GxIVC{vx){FHKm{-;~!vU z<0|i~84Hy-g?BnSkOkcMX8554ks^9&XV35uY;sdaje}kX;4oHGrW@(*F-T8MlU!O@ z*jw^+(?y08X}Z*--t8|gO^KbovV@$byi-znI=%52n7hPAroQugwkRKRQsJ{Ye69=C zuGWj3d1-6f+SF47sbrA_zJ|BCr5tzSIvxn1ir17ot`wU8CKw6WTo_BDQ}tSR%r_v> zwY!O-cU`8Nhj~)VQ1$(8{A6GjpmL2eslIo%<1ek6m6uoU%cJrl2Ljf`HH~})8yJYb z2``K8cb8{Wr3L5ZDTAU}hA{SPf2PWOv(XZ27@wQN zjZbbwIA#faE;Yz)!hDv8 z?2TZ6^X510$8OOR% zTa{EHY44J*1I2ZE996iTbv$XAksfp*qY3_x0v6}8P1-?8GY5^d^Q6uj+3e_f7dDGd zb}Bs#<6J8VxcG9};r;vXpKwOBMuw&MKaMW^ZLbo~T5w@ATlVJk< zi}wNAmY$|YiD};0nyNSmr$?LqFJ4L` zSkd&hm6{xvfFdm?BUr(#FBF<+0Ow2cgL4+5hI}R7hYV=XB&qq!aqBO{F0EB|?U@lcbjqQwdAfS2 z#5Ir@@UCQX!1;3V)k_LB2}J`En(~DsX2Gx`{O!NxR<7aMCuzzlAeZUe{AFShU$peu zJMVIKy-2n8b9zJGca!OdrB2+SEO5G+cGaTT*cv$0Ro|)Z-1J1@j{2AE_UF`HEjj3e z`?Na3MRZ)_sn|5;~Oz6#w?`2DE4mR zni7Z`u!`LDG}Becvv=2k_vw+Id#zOPfRv@4QQOl|GJ_q1s!sgisjC=#<9s=w?UhR@ zdSl}PrwM#;YIIUbReng{^+8=q_RpQ<_+Hc0w7wf@Ydr}Z!~?SdY4|MrZs!hZ?}NJV z9Cd4uQhT(k=X7?ltip*(3Ebxv!c2i+N!@p)Pzu|=H`qOut;F3Nr0eW2DWzY@$>6B7 ziNoxOJ(`}n2GC{>JbRUAqr&hcAn5Cc7I&WGCBD;7VuUhG0bVGL7D?6TNWiO2nOYU#Iz%VF=tv zFzGP@=j`pp?R5KbN*tN0s|mMw@I%X9y(6m&lz+TtSnC7YZSZ%Dk`n24*{1e z!z=EN{o&^h&}Zh}zY8!Ns~WMBG!-4N3zv0q39#N_lf)cdE3MFwQI8lx5?toDa|1q7 zia$?$*PzQ7ItULZCY?~d@9S)dy1lRh8$&>`meyY8&`zsJ86rne=-I_WU^aL&2kNE` z5wtB?Gc7v`wydPg&6Te2JibFeXwyc)5#KdD9op1hJ;;0K6XFdt3%@(5UzE5k_C4yb z)2tQB)><2O(oYm41NRrC(&1q|1B=*d4#X&#>m+hOow&Cv%Q z!Y}!Na*c;pdkoQ$lP`DTK_t8sQmkmVoy`(UJ8|Fk+%rmbYU3_Ar1eUvXW=s+l+tLB z6aJJYVyFEbvV4v={&!7_mOk|G^E3@LJ@~Kzk_F}jLTg+iX`gfvms`6Hbm{GtTRO{V zzzVGoENYrDnd4uYz3=hy89h)TIt2DUV$`{2*E^sX9yMjBVlio)Apr(+sWA`of@0!_ zI+*N{ldVn(Zc`<8B_VUejp%=w!P17iG-vPq?2+ev3uzE| zxiJOFM?a$;XMkJFAN1ZJ^sK>b0U+AM#q%g9wI^>cy!NZwlxz`bXv9S*Cj4wt70YNn z{c#E4T;ggw)iw{z=BeC%RSS^O%l_HlBZi))Viy70#ZqDRqDsIgkbv%DZlLSGmuTk7pIPYQigYam??MeBNElgMR+~!wPd87ued+Ky3pRuxYlxql5 zeX1UYa8ahqH}Y=v`Tt!2r%8Z{ysNx`ZhYWD7Z(@6obsLOeV{x8xU6xSVuLt(tZ1HL zZ8(rt>)#Sunr95tkPnUfHw`njc-gRddYbk5X)_kMK?{sLzdULJpxh4z+x+eTpnB&P z6x!XAy`9In*SZ)hdKs7WkUfl>nytpl?Aym%7&1CXCCK*WRHWWf)Rzkoo zi~qhvg`f7Dr;q4yenD3|hZ9uLrm0UD$Eb{8=!Ah_b+y)9MZx*|UV-ehgBEb4ox?gh z!H;F{TNo#LW1EC?HATvFFQ4lk5&EL)FBdkt&)CWHxkqwbexr(?ebnT09$&_tpP#~7 zZj#t0`@*0k+y$E>NxmL2WGWuNp%k#L=rsX;&aHw6>oHA6Nf8%EHa|~=i^;@;iX)hN zNP^jSf=PpfqwUX|6@zCTo{1MO%uGX)ik1;?YIZ4uW)S6m6Bck@@5i*uL(?o=JAtLc zC%ckbd~XdHRx12C3o)48y{~(DN#SJ_oLN3hmzTE2sXVq1GZzLH!kPiQ3+k>MeC`v; z(C`-Zr(0W+N!mq#dB=;$Ui$H&9`nX~UFxx*jF#MRU%xhNJLKT0Yn=m`TDcJ$+}Lgg z;?>!DdOj3&e$aXxH4x)}NXV3vkXPe+(6tfiO#!(n%Fk2nJ|3220gZ8$nt2aW+YUbe zcMgI}tChbk4OT%Kz}sVZvq@N(!js@OKZ&R2cD)5IWQ-y-BJsljEj22zm!%}2I&Q#m zhVigN#&xCg7zuT$8sjoYX*LHT`w_ReV{|?l>vhaFv^GUGhETtZT~-_iKwNX_!#4YEOJcyLvamO`{^Y z@P6TEtNForUwr$LGBWY$56A0<@64^`QrPU%@7{w6DV`m$!z&iMk8X;pe7cDZTf>QQ z-cV}M(&M)E&WXVyw;>4O?4J*B8-WhZ*=fR5y4IKZEsQN;vx8v-?<)&y>(0FVu%P4a zA;sVe+uUZV(4^$N=nmil$JcTLxRMaEz#N{J~DAwtjU7w^fkKH$-2crv%oB7|#bE zk@9E|osb(Z;Y~BNBvW!_)*s)``H+ubgDX=-iz30Rx$c-Lc1re~K75|nm(8$|%zA-I zegu3!l5|xQS9KgDLSPb-_|7t|UUY)63NLlHr-E$#3+e$m3yX$UBdx)4KS)3PrxW?N zBea5uf-V5Q^^Neyf_sq!lwuHCtDd{`wGErRj}qq}WD;`q*}DmUU=`kWkyIPd%UaYH z=Auai{QQ;~rzNGE%U;{`6$ZROO>)?^6?2lAZSDOW%jy zLpv*(#>QI*Vm7&#+esi%S+CBDJSg=qjz?U`$)LdPJBN`3RZMZbvzMkCN21>N*7QA- z98N2`F*%Ad(N|1P?3bRAkddKO$238b(jg{(bI@dxQTZ2Rx#ko?l^k$!v{u+*4^|>A zcWH&Rzy8UBCutle6>$X=95%r)3K+`J+H9S41kT2=V5aW349e;RL%(PkajU?FB23h3 z$42ZC1NE6tYzL*{IpH9B9kO>8?K>46UWuDhx`uQxE3WNfG38Q<-sC%Pdib1)Zhj1$ za3q?iK2u=(Xba!Sp5xG3c5e-4aeuAev-az6Rk0jvdW8wNql|HqHhw>imwmQlmmk*W zbwyhAz0+4Mcv)#W_=y}i>| zo+N$Y>wqYLn%G%R_~uCfz^~)Ia!Opr@0PcoPhVba&y*A1Cl2h#KkE`!ybsMP_vmM+u@&J_izw*M}6Hiu+MbPVghx{HW_NnoXezR8W@g%b$m!&T z#8MB1sISa+3a_PJX&xY-bZ}kcs@Bcq0^muT4&EZ&yM5jDrs)zxw_8$P!Qw`;u`j9S zEMBJ9XU?P#-TuL359bKo({hq~z)<)`z>D)C;ue64eQJ7F`O(78{yxndlkPv&t;%|Y z==Vom;8hdpxSu+F&e-k7wrh5KjbZ36y`81CdCMI(Aj0Dbe5B_o-Jm}R9c2h|uMqjEG=f8Ie$8VdE0LMoz>};DfZcCP9yF;{H{~^Krb(K!nxMbPbPan`v z+AjMYw(iiYfHE51xx-yY%p^(M1N!s$$kCy3&5{`yKcr(%u-ZtBp8}@(P8#lg)n+bH ztwZw-V~dJfHc8||2cKM?UHu)#34v3->jCK%;bpB$5eh+rJ?)4%$uV0~2>=@xe+y3nR0+>^d6U@ocrX?70)hIUF@v~RpN z3}t8*KvKVLgeZ{;H#H&1K706M@oo|;l zFHETmMlK18cTGA@_7ouyGAZ`e$9dE+5BS63*@CSZqKHtCK9~vnlf^F}Y@a+0IbzFM zckvl#h2kmC4}CxSIguP5YG7?D*)#`HY-mk~+F!E=K#l}Vl=~_3?~p6QLxB0MK^S^2Bfu;ew`iSwiI_7OV)Pd!RPZ=_blcwS%A#M(5sin z!y>rU5(bl~Kc&xf)t|8x0F}0v=hf;)bIM{nZ!jML#H?MyQ(%X-kr zZ?iVne2%(7H*SjwyveAjx9wH)Zpr?Jbam>e>3rJ|Y)}BXOUbo`d@W_lvBe7CE#pKWo;7-x766>a6`cHVdn!S*$8hXq`Nghx z>RI}ij+PX|)$dI_oH@m!;A=|E&cd5x>&zS^aC%XRZ#H7@JBjYaHS{Gg1q>jnv;g=w zHQoB2&E1viogYb~SAW?1BDZO?(G@xF_GmZI+`2syLleg5JQ1WGa>0MnHnJJ+Rk8<9 zXo}O6C;Jv`GxPywk%m#Yc+dr+@Ad0?PKZss=)*asK=)Tp}vt;!_lLpiJ=oIH*zSp}CE-b^t=* zG`yfS{MjQwFNc;(r)bUMACAl(ceCX5=x08{#p=+d?zGUZ{#JCG@9N2ysHvz=a=|(- zL4ZL*7E9ZAG26;0jbN(HPqLyn;`&RjG#mKHz}M6G8b;yLew^(;`r+7AMTUkZKJ*RF zUUgqu$rs%xo+j1C`I6;k-M=l1G#nj(p#a}wV(Q(k?@xI8(Kgw$4X>(jwf+SsdXyfR} z4aESXQMHEX8l+=rk7M%e466Z3_-h@fEmrgh}P>O>AST9)7n^uqVB8Ad#r6pq;P= z3fub9wAP1-)27~)S5beYt+SQ$m&1WY4V?-pT#G{KA^Wq}=ICPi(1kOR$9wlc6%-49 zDG$9izdBu`=WfHmh#PdzKl8x&y5V5Lk+#Q(CIE+?*5t(c{^x(+5fv(nl|0l-=?st?J_R|M`!zpBeH^PiZ)6)NHlVE&D(r|8*p9a9&<`sd@+0) z$58Kl@oUSIa_k)Regir*iG#)KWYP`AkpK5pp##?J`8g8uhq&**s2&h;0u3-NfhPp* zeD>ad?!@QI=Ql{18>&L-hnD3^&j8}LKeUmC^5pvKJENf1A7`2Mf18JMrf-8-aqg#9d9`xiK3cm-?De zTZBmZ1h<;QngPLS&wpM7O36GJa^DdHenh-P%CLo`~X1b|2lU%F7_nnC=~tUC*gJR;VCowCLY{aegev;(sB3P0$E zc*HS~+y?jZ$T%F1Rvic63Fo=)5{+GO$Ja zuzN+UkrtQG>Rg^A^0!CV^JVo!QuTjMFlDF^dj88g5m`Pl`$`;AuW?*H#0uA^+1cG) zoBIUkgS&_s{o@lEcnIjprqRJyt`$0DVdDQj0xm>_g68F;f`YjjqH%s&BP^;Q_((?a z@&4N};ohfD<@2o#cb{+zONkz;dVCqKun7Cl)7Nqs_1YjEl%Eg9sz$x3LG2IE(sX(= zkrI!*Ka!ABsiSyj&I*RO@hQ4&lf#V4L`J|R+Es@1B{LJ+Du<;Sc!E38;Zme0{~f1b zEOVn`=*@4d^%E*2|LLnIA|h<2ik5Bnj$a)ej4EDsN2WQO7zus#cRBNsp(7048b6|6 z;F}0C>zui~6J4R0a7oM`Np(TIuDKhP{XCJ6i_Y`xw-=a+yld{@?5`Sa%(%;T(0(R7 zUqRp657Qy7*aM8=ss-K6yHF}W_;hj=6gPb%CGQ(6c0R67dTcl@a5{VS!vl9sshI6- z&C^Sh#3#PjRq`N8(5#KOnhZ&*OlEv}3QC_^9T??>+W02;G^$${nExyoCf7FzjOeei z!6)$!!QoLdR(8LwRGiWc`K&`<^a9K`*TAP0oqLV*dF&+;6h$dH?o8+QN#Fw2RN=cI zT}Q(g5BC4Yb$AFNx6*&d2i9>6ZzesqaRSNC=I?7UVL#l0RlZt%vuPM(%B;Hl1gNkS zq`c12k6EgjD1FA;~~f$HQ!DeNdh z;NI%y=r%awY8idHyJ6Jg}!oO;2|BLN6@XZY$VUuiaL-rSUX%sZ`5^72hACbOo z_z(O%@OZ^->7@<51PZ}*KthPO_@cPC2ngZgk&>RopG5wX{byR7ly7}}arqNM?OUm9 zsx~7NhpdHrVyHNY*jh=K`_i_yYtCBfut%em?D}yxJpg3vG(Ux4MTqbaYnKD>$L@}K z{ai@Q=$3mK1x(n>wEmvqwRayX&#K&wWE6GfxwkR_|G32sOy}_3ouXZ`_()Rzdt7}J z5WE&a#p#oEmjqz)wYkAAckX?a{LVQo1D+60B(14%c@Zd#OaUkx`T+p)?wpVKpzfFP zVSMCM|Gv9?SVna`$&rs+vyX{K)n4NQ)W#LLx+?721INF1S4L)WVH!K%t{?Dy^_+M) z%zMki_HTNfDXH?mjLan6wb4u_3&)2wjYkV>>ltbH2=r)TE5BAw)h%?{N z-?JE2r`pJ*jq#>F7`GZzxM{=LF1)rMam_B0(ed8}-=o2lFuZLWr!h5_OFdp8Qrpec zj_zD6etY+}AxiRMW0ehU8gfrHh*@T^a{6VvZS~rgo78r1ZF!yCkm^&n3x~)xF~*(` zgMZCGR=4d+ekah4@6}xSgp1tjO8@;8XN(=adTVml=bkrdYPnNYPa2+_Y-UudJ#&^= zTd9!__X%|u8rH}ohoy_^EC)1AOj7BqUURLOrV}1^&amc=Bp6*VkqH zbRw)5^!A^~w`-)37LLU4ycGjb_`6?I(wZB;r#JTT;9fYvJ$H2HH~#ec=mCgxWp49( zR?_z?5iyL*v;(Q}mdmC6$T$S;{$ifQ-AT}56EcybRa>t|VmiUP`>dkXTQNDnPaM%# zs`uZjEyo}E?AJb`iEr+fCv#E+D9CRsTKYY6VyMd&U9gV&6IFNm#mwmAq#vlno)!Kj zTU(sOOET1O&ggfDHdsbV(LbOU{-G3N`pPY!-r*O&VQB|)Eui_w?~Qb{D3D}U=jPSE z69iX&YMwYp_U(t88N;0Haj>E;ywcR-y_uPJdBtBr>6ZekaIJXMWkw{pFLA1|1$Tw`I@yBD6FL9FCV+?drUQKYrIj`NWzjfmXcfNxfk{* z@_73`+^P193#*X|Z|qV%*5wUv>|dHxWa(b`j}wRGN%|!K`r3zzPiDve-^we>nZAYp zNI5EnD4(w0?#;);Dfs-T(fw5tOduRBH04{2BT)tL^!ro!@8blre{ zcc4;5%A>6|5!yw0&$6rZZ!@pa2Szj>n*zChDWpn*p8NZQ^KNgUI;akc{J&D>RNAGU z0O2#o9}7NqbkUJb7gAp|MDrLe0;ca6jHm_a&~gc8k)RB*UIF8kS;Ouhlh>x}Yy@nc zDRW+<>baZor+)8m3cM{(>BqVPYhUl1!boCUv|*9p~p4drvnU_(a8bBtmHA zNVFn06)lThwk|4Ii1c-!AQb0iohTe!@!Jl~kQ>M?1+?i>s_0C5pCxjrm4%UYK+d`_W=$X{@m3zjHbE<>C5?I^kSfK8zZ5aY?@b0Z3Id`N z_ET^{JowQP7w-DMq}k7nD!|~@5||_X16VM7MLoo{Iw$9^KmK6#On;u`NqvXxeNKk^ z037~qTK&P$N@O>3SUC3G&%+_h7lQlJYJ8zXKL~-u(97PGG41Epnt068m1M5N&kKLO z1Q=1Ec>Z!e$>aT&;qs*IK&TAvYJbID!<-4EdU7fx_>oVRT2ubhGH!~offwmSN6)Q3 zjX$(AY3E-9i9Rz=beV}%V6W0G;~)AULP+WyDJRI&n|WIVhW=5MlJ!r=`stu;n9RH# z-@o{WVWp2lddD+lw4Z+lusRC@cVNT-8;*Kcov_t+gy(aIdD=s9BBD&qu; znT45HR1hWp0h%FH>9!pq3YH!9X_A35f7l_(D#2$5ZR)Ob!R!wn!2!D+F?%cVyK$!& zZHx5V7PLocPmt18Ve;$tp2D2^$5)=>KuCrpSbE2r^b+pbzQO_*{&a9;hM~>~9CS$% zYHKt~)afU1{fz~2c^k{#KX5&KYh)s3VNsne3#weZVVCiZla00n`^{vu zm{8pt5kaFj7u{cl*<6t7c=UST#fB(=d7^gl(b=q%fg1B%NBDGsC3+RJU87N~flUwo;%H3XkZ2_CPr0{j0-X6TGs2kC4)uG}fQz4jd zD4gpZ^|r=6rouafk{0vZ_ew$PV-Gk&i%$j4$0)#a?oVS#^}U!m#v~Mpy9Ovx>Ggf{ zGu(u9jgPywj(BxQ&yZccdPj#kz;R8frgdKND$+ehXw@t(@-e^7)cX}N?J-^S zgEwaJUk5x)<1Hd})oPHsVX^?Y(#vfX9sU+HWC5w%9eUfJ^@aZ{v)UMYB_Rb04-vk< zIeTf*@I9*lcg+7L6fuXm#vT2j7#Urhak7dnGapXH*Qt+?Sdclz91h} zH-*}yyO*!2tFv%}G2W)$lr$-K!fifi>8YDx`XS+S^RrqUB#-w&diWW8BHH}Z6h7DO zbIefYSjE1-NIQx;2X{t%3R757oj(eLbVVI{OOB1=H&3CX<~tau9ew&?Vhu|J9jpld4qyO`fgs>j38Qak4vx zL2k4>AfkyB=?A4o42kqKvbVl69mztykbiC?=p>(89}C6FCi5|Zi{ss>j2SA{F{JmD z>W8in0AO)^rlxF6bff}vwq5euLL#Rwl*r+0$)ctkdkfu?P&UW>p2`Ee zGl5u=-wpExp}i&b`NZq*dRIIe1>uh`#&lZQ`|5*+?iOwz8$C`8kNtO~$qn-B-DD=b z__&$>oI#{ojq{dHz^Gq5@)MmsP`d2A&k6v~#c=zI>m&C{VvM@?vJBqa1}7-8usdjh z=ryJmi#<^e(~H{K$+P-VB+CB9<(Jp*v|+Hxr2+5W!0oDmx|Nw}Vkq&$nu}*sYur91 zr`AH$u`O-lyD?REM^Vc;74u=mOT7xANO=@Qu@Vm^?1mfAJMvj*Kh^T?(DF|-6$&H3wzknsLY3X)62lgvCkcTV`&03ZGsMEjl}AWHKKCKmVqZ}n1YXP z#v^%|dOrAg4@1Kk<%iUl(A{T8)3cXKA;Pda-2MD4^FNr~Mttjam60PJ71&nW0BcEp z)RcTL@52II*6l)W1f@E!5XbPKc7|tikg5HfXJKHLrTUeO(n*jdxqXm%8?=bEO_f`{ zYg_7Y$B?@2-w4Ux&Tl~i04$WhloX~5jWo9YM=JJuwc7{Ld~i8fRxWg<7DXxsotuxirMhU3D54nx zw)}lS4?Ig2peU!1$oPeGxj2Ud@p}_!&zTai*Mi1X;4Hwb`$|SPB-?cx! z*x*yQ_-wOf?_MGi8=56~i1F|J;#&IOIcZt@nMBxW_a*0vJCj_dI{o#`PZq&_9!v0n1~+D`SR7dH(Y+m9HW2j)3}{a@OJo*JQH*NaNB0^shYnE?(VsocSQS+`=#87jfg? zCzJYbYRMD*2q*9hYR=5Mc+N-MPRbSym8)RZ3`tKEx@6F%l#R7*LU*Ngi3W1uJ8Ls$LuE%EwCf;^)GGg&&>k1vqLuc_pJd| zIO(H3NuD1ut{RUXLtEp&@3@8r#DYcPn3{{rHp&jy!M7&3IZN2{!E*N}_W;z3j_Vv> z?TiTM+57BMXjyQ}SB$%8N>x_f2a%JYtBYXN4D%bKZt`*)O!NJb2yMQC7s4Y_0GDk$ zzgb)VYNl^eZZM~N{2R<<_daodn-Oy~U)DG;WJB^Es0F*7M$*S@l2W|s4W$E4{O2UL zDk(U=G7sNSYK9s$(I~_&d9A;F$Kt%Ald77TsV;hW(d?N>0f;J-=w4iA*WrM{oE51* zmO0&JQRyl}M9MXe8fluF7N>KiktnoO=`^s49FykXs!{9u`&(@VUF8hw&!!&Ly<3|e z&WVIEqLKd#z!N|0G`IcEs_jS0Q(V8<{J4Fvma$>zhaz8JS2Lp!2EdsMy}4fTEG2~N zYnBIh0Rl(wl%1Tm$|{~YqX(;F001HgFP{LU7~|!Jx}a|%!X$5sWj4d~A{4zmykQrd zo%G-|08Fw>_XwM5I02B?JWtVEOqrBbbh8Mg5fQS^&pS_`yWu>3LU^%8v#lSKugHvbK%GypbcoT!Sst;b4$h=7QL;);mq z^%;Qmm&>=+O|~@MtA82n>BITKY1NOd)d)>}R_3!|8$BZ9KAY>d-=;`q|IG3f)$zh? zaFd(HeQ@=iQ^*DjfM~8NUh1~E0>E@MLnM04vYC8GGp`r#?C4Z**(_gG*RqO%Ny4ev zz83}MOfbnLVX~G@uy!&-4E>fcL|Art=kZF;2h zKt}-D&D34Q#O;0@Uj0n$9@d!vh5tE#D%R*8(s;LAlmSFQQb zo?^U^%VWeuPlQtDtatOP7>r6OD~kp~OxlBYAy9fD$pR1~!XigFCBn*OzR2d6IfK_u z>F#vDzn^-m36%wtgd&_0!YN*2`mOeE{U*4SWK~_2*B3R7ope8*#qt;uj!BLLGF zLfyRj`m`}B#@UiEJ$7fMvdmiYPyZ8PEJN5%-m)xfsEi%}+0-xP8~~c-SBT1adF|A& z9gmm>2NC5?Z@$Gep9hyOy-_WG!nEHp83TSs*lC2bnbX5QI5U_*)}l(Wyq0sP>}ZGR z$34O^3_IOpx_s9@sB`lon|DvaVTM_@xIz#?1d*s;{M9ASpXG>njffo)A>1211jln( zJJoH@5A`jk(=i6!KK))4glDs|({1-0oEcM^ztnxd8_%D<2jKPBRuAWK0Dy}ayi2>o%eLWuVeQVKwKjuB%T+LQNragkS~ zc#$Swgw+UB&IG0qrnKa;&KE3CF?xs~LL|lMc>1Ke;Po)|F?a_6!ofR(36qzX0sz4W z7eh+rx>)nF{e1tM4b-|fHQW%Ma#i)?XOoaP@1hv;}u*y6362TM2= zvSE3O0NBZlmxoSeaKQ!NZJa?EBBxTcS-lw?!O3u_twJ8$*#~3k$McHk3AE&PRkkzW6ItY1o-lzc+ zSy*ipmoZq=?fO$nc~#c3@Gh?*9J&~*S+xvq`$=Ssrw9O-vOt)M7}Ow(Jjp_j^*Wye zP+dXTADszakAxxYG@(^Ugflu@f2PDLNbc*jG)xyfB-LvRd`ayR1As6EeRJe*eg2jPQT_uVXM8p`wn_875{| z+fVJ0@oFY=CYYo=cmU3uYWelQE^m2lTAD?#jw$l$kE7V=y-pDTJLuLMUIv?DwgAA6 z5Va2g5FT8&dHEOpvz@#t*D)OLt;!mNr}O^v>XlWSk0Ee@FaU4=4AW1)?N8JA_LpWF z+r_OKrY=S<^IDdKiSn}8Ny(`gAUZzi@xm*%n(|_X>39Ml#&+kOEGR#13C&6_jZ#Ba zF7En+QF=tUS`@RCRF}`DR`rB6SH;p!{ho4f^=KvtdB!usVwk@LX0|lP^Vmi9C{X(e#hQM%2T0*r_(9;HFNGF~o2_5VE{Y>A2zI z_DeH$hpb$@G~@A6k1<}oChXz6&105R+O^I}+4lrO?}t967zss)P(4z%xGI`z36UPg z^Ldw&%#DI@`%V9x&1diQ+3QOMN@Q_+_ya_UU~gxXAx?y>YLS3_n2BGvaI$-br8zJ*~j+~ zo(^r-_j#UWb)ywyWPTld*&v+P!Rrx|YDxLn4rga%ky1*OsnOXOjoN>}v|Nt+@d!Y< zrZQMw)~_(b43QKeqWOi+MswQ-L-XjpVkH3jga~H(OeD>Cg}FWPedRR5vcXh$c7hNhmQeu_!c-!X;`uWbF{J2C^wDE7oFKe-T)evo zyL1yE#2uBeHUy)r5H)gBjHj z1Lc>-jLA!c66Kf7iL8<(lcFq^a)zm#du<0hdSeFNnQ=H#PMA7pvti%u5H6O}Nwp~z z^I{GW0Jp!m`jX|cvEy_ijLF4IDyZmpQy)BpYS?WqoCg31DJnuS!G!$$uK{oq&GMBU z`e%rW^>ldp-Q)M|!I`YWMC9FBEAO?kI;HAR9lAZwsEEGXq&V&`R)iEGVmT2I>veUMxP- zELdLU%jrNfmecIA`ni}a5J_>|_Zx_^S+T^df9yBj@Zu8vlOm>~p&4ep3Rccc?=?ih zIyIfVwJNKNrKkw^=J282>8A06=%mZN7v^ zor5Jjded*efhc-2TIKWw=5;Yp2S@nqHeV1(qDzpjcuGk!-SM{c8Tj&HL^-1^}Gi{9ui9 z2q6T3R`3*Ke9LLG^yUlKtC0A70?JpiBoZa6Sm z-wgZv-#RO}#e z>Qx^jLMgeJH%ubzv^Ru{+Uw>8%>Zzd=?Tl{0N7D?W+1FuGRd;;`T70WGC?TiDM3gW z7b0s`R;%HBczP}igvdAlXNqbFf$izmV01(b*m>xa? zFdT#Tw%ZdHJVefPN2!>&ya6dE6jPpEI?rw&e7(B*nH@#deO718)KMKUBV3QqA7UgV zuMwtv_v3j>+12aW3o3aPtQ`*T3E%%vb!HG1%P>R4YcqHQ5vGL4pn59I7(B)zfBu#V z00@&+Hq#vd5T$4aGpG)L7{)V`5XRu09xpof*%dE%Iqvr#4v!&}b-TZ)MlnvwD63`Z zZ4BN*r2DCL7DDgz1VD_=GR~!$Vt|keo?*(ftfri0gqy(|J9(R8eG|i__(FtJmLu%+ zWy^;t%UG5#0k{lg$L+A~o`)mPQkvQnV}Qtv!2>`z^9U10IRH~zUl%I?yqQkXo4$VG zrs?1f!T9n1Odd@HR7M5kbLRb&o@wo4M=ToAT06_UgaUFDs zF&sZ_-y>Wu>)U)O8k)WPo7FF9<~0$R&%cXaod7U{?g-Bp5Sihd|4SB_s6kK80)Wu< z8#6g$l^Ra_5T-r`t1)5HX~K1vV)PJRy`$VrdEMN|niuU8!qxiaU&^`HMCkK$2-YcC z$AD>Y?Gs@D*lB95x^Tm%E=H>mu9sOoyW<5S002NZB2)mt3vVE@leYi_ZJ7h-H{TL^vzdsec|0!KJ8&;jG8J27qU> zyd-tW3IJJAnKe|(1_0gOl+A0J1?%;=vjZzI>z|JIF;rLCJhkIVbxg_{fbn#Ag3#Of z-OXF8Ai{*_gv9`1J{wPmr@pl|r6OyZyd+#gWVO|pFwtDy{CqlX-naYiFdTV?DW*4n z;uJ4+i%7l-mWbKg{3@9Kk!G_mgE@ZpD=sPk&YyQb^hfVf^cEtktadg=LPYl6-y4$> zgdqfPwYNrn`Ioo9UVUl$e3>l)P{-xhm+JKVfo8=`|2S+B@%H*xc9b)(X@*&_Dlg;AF>i;3X9vpOY&^{A(zLntpH#3U=TDtN0z-rS^^QVf@wV2Ti_jxdBT!Q(N+ zuzrInCYP}b006L@O3Zi}{kR|Z006N6aNa_QN$|mQ+3peI8P5@pfeMxtOIAP#fM`Uc zj;0rNisM$dDLQ4x3%DV0bj44DAL3satGfD%WrusK5RO6hl;;gZOp4O!Y=*GYvNl7vaoSAYLc}v!@!V8+{Foh88LZREt@-D#E>GUG!u37M4Ug`iSW}Wt7LVVOt9Px z{Wc|8AwmVq5q4@i>HhRot?KJ+#!Jx<0f0WAJ|dhgblY#8_D1!m&HkD3x5%+w6uGRF{xI(kPVe?vO|jhe^uv_6EO?~(e8G)9XlcO6G$L&|7)>=ff)gl&)BgOn}t`@ z6>3u|m0lrTak@j&-5R(NCypC7B@-tPP)f;&07%5PuSY(J(zrd+;Z^DJoY#2w zx8#?ZloBzl#khTYYIf5XDN@8+Dwz}jQsZj!uBJaaZKaui?!$OZ!H<5bxb7JITtS}O z8bc{1=S{I<*DGOdTGN?McWjm++@|YzEm>QnEtxiJ0436}K`aHp?rP_-MF8SBC66?m zqc`m`uhI7KPbnx-QlT!TAh|<(az~{B^12LL{C*ogwFQXxy1olD!0GAue0cf&xV#Uy bhaTV$7|U&laH3=v00000NkvXXu0mjf1R^{h literal 0 HcmV?d00001 From 56543e131182d5edf5caceb665ea427f31a6df71 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 5 Sep 2019 15:58:00 +0200 Subject: [PATCH 13/73] nbis: Add spatch file to use GLib memory management functions Add an spatch/coccinelle file to replace all free/malloc/realloc calls with g_free/g_malloc/g_realloc. It also removes all the error code paths that we do not need to check anymore. --- libfprint/nbis/glib-memory.cocci | 29 +++++++++++++++++++++++++++++ libfprint/nbis/update-from-nbis.sh | 2 ++ 2 files changed, 31 insertions(+) create mode 100644 libfprint/nbis/glib-memory.cocci diff --git a/libfprint/nbis/glib-memory.cocci b/libfprint/nbis/glib-memory.cocci new file mode 100644 index 00000000..c2ac323b --- /dev/null +++ b/libfprint/nbis/glib-memory.cocci @@ -0,0 +1,29 @@ +@ free @ +expression ptr; +@@ +- free(ptr); ++ g_free(ptr); +@ malloc @ +type ptr_type; +expression ptr; +expression size; +@@ +- ptr = (ptr_type) malloc(size); ++ ptr = (ptr_type) g_malloc(size); + ... +( +- if (ptr == (ptr_type) NULL) { ... } +| +) +@ realloc @ +type ptr_type; +expression ptr; +expression size; +@@ +- ptr = (ptr_type) realloc(ptr, size); ++ ptr = (ptr_type) g_realloc(ptr, size); + ... +( +- if (ptr == (ptr_type) NULL) { ... } +| +) diff --git a/libfprint/nbis/update-from-nbis.sh b/libfprint/nbis/update-from-nbis.sh index bd3a59b9..4e243a24 100755 --- a/libfprint/nbis/update-from-nbis.sh +++ b/libfprint/nbis/update-from-nbis.sh @@ -179,3 +179,5 @@ sed -i 's/[ \t]*$//' `find -name "*.[ch]"` # Remove usebsd.h sed -i '/usebsd.h/d' `find -name "*.[ch]"` +# Use GLib memory management +spatch --sp-file glib-memory.cocci --dir . --in-place \ No newline at end of file From 30a449841cb28ab9e0b20bbe601ac4fc51fd33ab Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 27 Jun 2019 19:21:17 +0200 Subject: [PATCH 14/73] nbis: Use GLib memory management functions Apply the previously added spatch/coccinell file to replace all free/malloc/realloc calls with g_free/g_malloc/g_realloc. It also removes all the error code paths that we do not need to check anymore. This means that the returned data must be free'ed using g_free rather than free, making memory management more consistent. --- libfprint/nbis/mindtct/binar.c | 6 +- libfprint/nbis/mindtct/block.c | 6 +- libfprint/nbis/mindtct/chaincod.c | 7 +- libfprint/nbis/mindtct/contour.c | 45 ++------- libfprint/nbis/mindtct/detect.c | 80 +++++++-------- libfprint/nbis/mindtct/dft.c | 16 +-- libfprint/nbis/mindtct/free.c | 26 ++--- libfprint/nbis/mindtct/getmin.c | 22 ++-- libfprint/nbis/mindtct/imgutil.c | 14 +-- libfprint/nbis/mindtct/init.c | 161 ++++-------------------------- libfprint/nbis/mindtct/line.c | 17 +--- libfprint/nbis/mindtct/loop.c | 2 +- libfprint/nbis/mindtct/maps.c | 155 +++++++++++----------------- libfprint/nbis/mindtct/minutia.c | 105 +++++++------------ libfprint/nbis/mindtct/quality.c | 10 +- libfprint/nbis/mindtct/remove.c | 77 +++++++------- libfprint/nbis/mindtct/ridges.c | 69 +++++-------- libfprint/nbis/mindtct/shape.c | 56 ++--------- libfprint/nbis/mindtct/sort.c | 6 +- libfprint/nbis/mindtct/util.c | 21 +--- 20 files changed, 273 insertions(+), 628 deletions(-) diff --git a/libfprint/nbis/mindtct/binar.c b/libfprint/nbis/mindtct/binar.c index fb2be224..57c82a31 100644 --- a/libfprint/nbis/mindtct/binar.c +++ b/libfprint/nbis/mindtct/binar.c @@ -214,11 +214,7 @@ int binarize_image_V2(unsigned char **odata, int *ow, int *oh, bw = pw - (dirbingrids->pad<<1); bh = ph - (dirbingrids->pad<<1); - bdata = (unsigned char *)malloc(bw*bh*sizeof(unsigned char)); - if(bdata == (unsigned char *)NULL){ - fprintf(stderr, "ERROR : binarize_image_V2 : malloc : bdata\n"); - return(-600); - } + bdata = (unsigned char *)g_malloc(bw * bh * sizeof(unsigned char)); bptr = bdata; spptr = pdata + (dirbingrids->pad * pw) + dirbingrids->pad; diff --git a/libfprint/nbis/mindtct/block.c b/libfprint/nbis/mindtct/block.c index f530f94d..ebdf8c3c 100644 --- a/libfprint/nbis/mindtct/block.c +++ b/libfprint/nbis/mindtct/block.c @@ -134,11 +134,7 @@ int block_offsets(int **optr, int *ow, int *oh, lastbh = bh - 1; /* Allocate list of block offsets */ - blkoffs = (int *)malloc(bsize * sizeof(int)); - if(blkoffs == (int *)NULL){ - fprintf(stderr, "ERROR : block_offsets : malloc : blkoffs\n"); - return(-81); - } + blkoffs = (int *)g_malloc(bsize * sizeof(int)); /* Current block index */ bi = 0; diff --git a/libfprint/nbis/mindtct/chaincod.c b/libfprint/nbis/mindtct/chaincod.c index dd5d779c..b5dd9eeb 100644 --- a/libfprint/nbis/mindtct/chaincod.c +++ b/libfprint/nbis/mindtct/chaincod.c @@ -100,12 +100,7 @@ int chain_code_loop(int **ochain, int *onchain, /* number of points in the contour. There will be one chain code */ /* between each point on the contour including a code between the */ /* last to the first point on the contour (completing the loop). */ - chain = (int *)malloc(ncontour * sizeof(int)); - /* If the allocation fails ... */ - if(chain == (int *)NULL){ - fprintf(stderr, "ERROR : chain_code_loop : malloc : chain\n"); - return(-170); - } + chain = (int *)g_malloc(ncontour * sizeof(int)); /* For each neighboring point in the list (with "i" pointing to the */ /* previous neighbor and "j" pointing to the next neighbor... */ diff --git a/libfprint/nbis/mindtct/contour.c b/libfprint/nbis/mindtct/contour.c index 5d802c28..3e9416c3 100644 --- a/libfprint/nbis/mindtct/contour.c +++ b/libfprint/nbis/mindtct/contour.c @@ -110,45 +110,16 @@ int allocate_contour(int **ocontour_x, int **ocontour_y, ASSERT_SIZE_MUL(ncontour, sizeof(int)); /* Allocate contour's x-coord list. */ - contour_x = (int *)malloc(ncontour*sizeof(int)); - /* If allocation error... */ - if(contour_x == (int *)NULL){ - fprintf(stderr, "ERROR : allocate_contour : malloc : contour_x\n"); - return(-180); - } + contour_x = (int *)g_malloc(ncontour * sizeof(int)); /* Allocate contour's y-coord list. */ - contour_y = (int *)malloc(ncontour*sizeof(int)); - /* If allocation error... */ - if(contour_y == (int *)NULL){ - /* Deallocate memory allocated to this point in this routine. */ - free(contour_x); - fprintf(stderr, "ERROR : allocate_contour : malloc : contour_y\n"); - return(-181); - } + contour_y = (int *)g_malloc(ncontour * sizeof(int)); /* Allocate contour's edge x-coord list. */ - contour_ex = (int *)malloc(ncontour*sizeof(int)); - /* If allocation error... */ - if(contour_ex == (int *)NULL){ - /* Deallocate memory allocated to this point in this routine. */ - free(contour_x); - free(contour_y); - fprintf(stderr, "ERROR : allocate_contour : malloc : contour_ex\n"); - return(-182); - } + contour_ex = (int *)g_malloc(ncontour * sizeof(int)); /* Allocate contour's edge y-coord list. */ - contour_ey = (int *)malloc(ncontour*sizeof(int)); - /* If allocation error... */ - if(contour_ey == (int *)NULL){ - /* Deallocate memory allocated to this point in this routine. */ - free(contour_x); - free(contour_y); - free(contour_ex); - fprintf(stderr, "ERROR : allocate_contour : malloc : contour_ey\n"); - return(-183); - } + contour_ey = (int *)g_malloc(ncontour * sizeof(int)); /* Otherwise, allocations successful, so assign output pointers. */ *ocontour_x = contour_x; @@ -181,10 +152,10 @@ int allocate_contour(int **ocontour_x, int **ocontour_y, void free_contour(int *contour_x, int *contour_y, int *contour_ex, int *contour_ey) { - free(contour_x); - free(contour_y); - free(contour_ex); - free(contour_ey); + g_free(contour_x); + g_free(contour_y); + g_free(contour_ex); + g_free(contour_ey); } /************************************************************************* diff --git a/libfprint/nbis/mindtct/detect.c b/libfprint/nbis/mindtct/detect.c index 10ed85c5..703579db 100644 --- a/libfprint/nbis/mindtct/detect.c +++ b/libfprint/nbis/mindtct/detect.c @@ -207,15 +207,7 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, } else{ /* If padding is unnecessary, then copy the input image. */ - pdata = (unsigned char *)malloc(iw*ih); - if(pdata == (unsigned char *)NULL){ - /* Free memory allocated to this point. */ - free_dir2rad(dir2rad); - free_dftwaves(dftwaves); - free_rotgrids(dftgrids); - fprintf(stderr, "ERROR : lfs_detect_minutiae_V2 : malloc : pdata\n"); - return(-580); - } + pdata = (unsigned char *)g_malloc(iw * ih); memcpy(pdata, idata, iw*ih); pw = iw; ph = ih; @@ -244,7 +236,7 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, free_dir2rad(dir2rad); free_dftwaves(dftwaves); free_rotgrids(dftgrids); - free(pdata); + g_free(pdata); return(ret); } /* Deallocate working memories. */ @@ -268,11 +260,11 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, lfsparms->dirbin_grid_w, lfsparms->dirbin_grid_h, RELATIVE2CENTER))){ /* Free memory allocated to this point. */ - free(pdata); - free(direction_map); - free(low_contrast_map); - free(low_flow_map); - free(high_curve_map); + g_free(pdata); + g_free(direction_map); + g_free(low_contrast_map); + g_free(low_flow_map); + g_free(high_curve_map); return(ret); } @@ -281,11 +273,11 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, pdata, pw, ph, direction_map, mw, mh, dirbingrids, lfsparms))){ /* Free memory allocated to this point. */ - free(pdata); - free(direction_map); - free(low_contrast_map); - free(low_flow_map); - free(high_curve_map); + g_free(pdata); + g_free(direction_map); + g_free(low_contrast_map); + g_free(low_flow_map); + g_free(high_curve_map); free_rotgrids(dirbingrids); return(ret); } @@ -297,12 +289,12 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, /* the input image, then ERROR. */ if((iw != bw) || (ih != bh)){ /* Free memory allocated to this point. */ - free(pdata); - free(direction_map); - free(low_contrast_map); - free(low_flow_map); - free(high_curve_map); - free(bdata); + g_free(pdata); + g_free(direction_map); + g_free(low_contrast_map); + g_free(low_flow_map); + g_free(high_curve_map); + g_free(bdata); fprintf(stderr, "ERROR : lfs_detect_minutiae_V2 :"); fprintf(stderr,"binary image has bad dimensions : %d, %d\n", bw, bh); @@ -332,12 +324,12 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, direction_map, low_flow_map, high_curve_map, mw, mh, lfsparms))){ /* Free memory allocated to this point. */ - free(pdata); - free(direction_map); - free(low_contrast_map); - free(low_flow_map); - free(high_curve_map); - free(bdata); + g_free(pdata); + g_free(direction_map); + g_free(low_contrast_map); + g_free(low_flow_map); + g_free(high_curve_map); + g_free(bdata); return(ret); } @@ -349,12 +341,12 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, direction_map, low_flow_map, high_curve_map, mw, mh, lfsparms))){ /* Free memory allocated to this point. */ - free(pdata); - free(direction_map); - free(low_contrast_map); - free(low_flow_map); - free(high_curve_map); - free(bdata); + g_free(pdata); + g_free(direction_map); + g_free(low_contrast_map); + g_free(low_flow_map); + g_free(high_curve_map); + g_free(bdata); free_minutiae(minutiae); return(ret); } @@ -370,11 +362,11 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, if((ret = count_minutiae_ridges(minutiae, bdata, iw, ih, lfsparms))){ /* Free memory allocated to this point. */ - free(pdata); - free(direction_map); - free(low_contrast_map); - free(low_flow_map); - free(high_curve_map); + g_free(pdata); + g_free(direction_map); + g_free(low_contrast_map); + g_free(low_flow_map); + g_free(high_curve_map); free_minutiae(minutiae); return(ret); } @@ -393,7 +385,7 @@ int lfs_detect_minutiae_V2(MINUTIAE **ominutiae, gray2bin(1, 255, 0, bdata, iw, ih); /* Deallocate working memory. */ - free(pdata); + g_free(pdata); /* Assign results to output pointers. */ *odmap = direction_map; diff --git a/libfprint/nbis/mindtct/dft.c b/libfprint/nbis/mindtct/dft.c index be485864..3b49ecf7 100644 --- a/libfprint/nbis/mindtct/dft.c +++ b/libfprint/nbis/mindtct/dft.c @@ -113,11 +113,7 @@ int dft_dir_powers(double **powers, unsigned char *pdata, fprintf(stderr, "ERROR : dft_dir_powers : DFT grids must be square\n"); return(-90); } - rowsums = (int *)malloc(dftgrids->grid_w * sizeof(int)); - if(rowsums == (int *)NULL){ - fprintf(stderr, "ERROR : dft_dir_powers : malloc : rowsums\n"); - return(-91); - } + rowsums = (int *)g_malloc(dftgrids->grid_w * sizeof(int)); memset(rowsums, 0, dftgrids->grid_w * sizeof(int)); /* Foreach direction ... */ @@ -135,7 +131,7 @@ int dft_dir_powers(double **powers, unsigned char *pdata, } /* Deallocate working memory. */ - free(rowsums); + g_free(rowsums); return(0); } @@ -355,11 +351,7 @@ int sort_dft_waves(int *wis, const double *powmaxs, const double *pownorms, double *pownorms2; /* Allocate normalized power^2 array */ - pownorms2 = (double *)malloc(nstats * sizeof(double)); - if(pownorms2 == (double *)NULL){ - fprintf(stderr, "ERROR : sort_dft_waves : malloc : pownorms2\n"); - return(-100); - } + pownorms2 = (double *)g_malloc(nstats * sizeof(double)); for(i = 0; i < nstats; i++){ /* Wis will hold the sorted statistic indices when all is done. */ @@ -372,7 +364,7 @@ int sort_dft_waves(int *wis, const double *powmaxs, const double *pownorms, bubble_sort_double_dec_2(pownorms2, wis, nstats); /* Deallocate the working memory. */ - free(pownorms2); + g_free(pownorms2); return(0); } diff --git a/libfprint/nbis/mindtct/free.c b/libfprint/nbis/mindtct/free.c index adaeeb9a..1acd7e2d 100644 --- a/libfprint/nbis/mindtct/free.c +++ b/libfprint/nbis/mindtct/free.c @@ -72,9 +72,9 @@ of the software. *************************************************************************/ void free_dir2rad(DIR2RAD *dir2rad) { - free(dir2rad->cos); - free(dir2rad->sin); - free(dir2rad); + g_free(dir2rad->cos); + g_free(dir2rad->sin); + g_free(dir2rad); } /************************************************************************* @@ -90,12 +90,12 @@ void free_dftwaves(DFTWAVES *dftwaves) int i; for(i = 0; i < dftwaves->nwaves; i++){ - free(dftwaves->waves[i]->cos); - free(dftwaves->waves[i]->sin); - free(dftwaves->waves[i]); + g_free(dftwaves->waves[i]->cos); + g_free(dftwaves->waves[i]->sin); + g_free(dftwaves->waves[i]); } - free(dftwaves->waves); - free(dftwaves); + g_free(dftwaves->waves); + g_free(dftwaves); } /************************************************************************* @@ -111,9 +111,9 @@ void free_rotgrids(ROTGRIDS *rotgrids) int i; for(i = 0; i < rotgrids->ngrids; i++) - free(rotgrids->grids[i]); - free(rotgrids->grids); - free(rotgrids); + g_free(rotgrids->grids[i]); + g_free(rotgrids->grids); + g_free(rotgrids); } /************************************************************************* @@ -129,8 +129,8 @@ void free_dir_powers(double **powers, const int nwaves) int w; for(w = 0; w < nwaves; w++) - free(powers[w]); + g_free(powers[w]); - free(powers); + g_free(powers); } diff --git a/libfprint/nbis/mindtct/getmin.c b/libfprint/nbis/mindtct/getmin.c index 08a087d8..3597a0a8 100644 --- a/libfprint/nbis/mindtct/getmin.c +++ b/libfprint/nbis/mindtct/getmin.c @@ -134,11 +134,11 @@ int get_minutiae(MINUTIAE **ominutiae, int **oquality_map, direction_map, low_contrast_map, low_flow_map, high_curve_map, map_w, map_h))){ free_minutiae(minutiae); - free(direction_map); - free(low_contrast_map); - free(low_flow_map); - free(high_curve_map); - free(bdata); + g_free(direction_map); + g_free(low_contrast_map); + g_free(low_flow_map); + g_free(high_curve_map); + g_free(bdata); return(ret); } @@ -147,12 +147,12 @@ int get_minutiae(MINUTIAE **ominutiae, int **oquality_map, lfsparms->blocksize, idata, iw, ih, id, ppmm))){ free_minutiae(minutiae); - free(direction_map); - free(low_contrast_map); - free(low_flow_map); - free(high_curve_map); - free(quality_map); - free(bdata); + g_free(direction_map); + g_free(low_contrast_map); + g_free(low_flow_map); + g_free(high_curve_map); + g_free(quality_map); + g_free(bdata); return(ret); } diff --git a/libfprint/nbis/mindtct/imgutil.c b/libfprint/nbis/mindtct/imgutil.c index 50cf7666..63f4ec9a 100644 --- a/libfprint/nbis/mindtct/imgutil.c +++ b/libfprint/nbis/mindtct/imgutil.c @@ -191,11 +191,7 @@ int pad_uchar_image(unsigned char **optr, int *ow, int *oh, psize = pw * ph; /* Allocate padded image */ - pdata = (unsigned char *)malloc(psize * sizeof(unsigned char)); - if(pdata == (unsigned char *)NULL){ - fprintf(stderr, "ERROR : pad_uchar_image : malloc : pdata\n"); - return(-160); - } + pdata = (unsigned char *)g_malloc(psize * sizeof(unsigned char)); /* Initialize values to a constant PAD value */ memset(pdata, pad_value, psize); @@ -355,8 +351,8 @@ int free_path(const int x1, const int y1, const int x2, const int y2, /* If number of transitions seen > than threshold (ex. 2) ... */ if(trans > lfsparms->maxtrans){ /* Deallocate the line segment's coordinate lists. */ - free(x_list); - free(y_list); + g_free(x_list); + g_free(y_list); /* Return free path to be FALSE. */ return(FALSE); } @@ -370,8 +366,8 @@ int free_path(const int x1, const int y1, const int x2, const int y2, /* If we get here we did not exceed the maximum allowable number */ /* of transitions. So, deallocate the line segment's coordinate lists. */ - free(x_list); - free(y_list); + g_free(x_list); + g_free(y_list); /* Return free path to be TRUE. */ return(TRUE); diff --git a/libfprint/nbis/mindtct/init.c b/libfprint/nbis/mindtct/init.c index 90152283..28e182c8 100644 --- a/libfprint/nbis/mindtct/init.c +++ b/libfprint/nbis/mindtct/init.c @@ -91,33 +91,16 @@ int init_dir2rad(DIR2RAD **optr, const int ndirs) double cs, sn; /* Allocate structure */ - dir2rad = (DIR2RAD *)malloc(sizeof(DIR2RAD)); - if(dir2rad == (DIR2RAD *)NULL){ - fprintf(stderr, "ERROR : init_dir2rad : malloc : dir2rad\n"); - return(-10); - } + dir2rad = (DIR2RAD *)g_malloc(sizeof(DIR2RAD)); /* Assign number of directions */ dir2rad->ndirs = ndirs; /* Allocate cosine vector */ - dir2rad->cos = (double *)malloc(ndirs * sizeof(double)); - if(dir2rad->cos == (double *)NULL){ - /* Free memory allocated to this point. */ - free(dir2rad); - fprintf(stderr, "ERROR : init_dir2rad : malloc : dir2rad->cos\n"); - return(-11); - } + dir2rad->cos = (double *)g_malloc(ndirs * sizeof(double)); /* Allocate sine vector */ - dir2rad->sin = (double *)malloc(ndirs * sizeof(double)); - if(dir2rad->sin == (double *)NULL){ - /* Free memory allocated to this point. */ - free(dir2rad->cos); - free(dir2rad); - fprintf(stderr, "ERROR : init_dir2rad : malloc : dir2rad->sin\n"); - return(-12); - } + dir2rad->sin = (double *)g_malloc(ndirs * sizeof(double)); /* Pi_factor sets the period of the trig functions to NDIRS units in x. */ /* For example, if NDIRS==16, then pi_factor = 2(PI/16) = .3926... */ @@ -166,11 +149,7 @@ int init_dftwaves(DFTWAVES **optr, const double *dft_coefs, double *cptr, *sptr; /* Allocate structure */ - dftwaves = (DFTWAVES *)malloc(sizeof(DFTWAVES)); - if(dftwaves == (DFTWAVES *)NULL){ - fprintf(stderr, "ERROR : init_dftwaves : malloc : dftwaves\n"); - return(-20); - } + dftwaves = (DFTWAVES *)g_malloc(sizeof(DFTWAVES)); /* Set number of DFT waves */ dftwaves->nwaves = nwaves; @@ -178,10 +157,10 @@ int init_dftwaves(DFTWAVES **optr, const double *dft_coefs, dftwaves->wavelen = blocksize; /* Allocate list of wave pointers */ - dftwaves->waves = (DFTWAVE **)malloc(nwaves * sizeof(DFTWAVE *)); + dftwaves->waves = (DFTWAVE **)g_malloc(nwaves * sizeof(DFTWAVE *)); if(dftwaves == (DFTWAVES *)NULL){ /* Free memory allocated to this point. */ - free(dftwaves); + g_free(dftwaves); fprintf(stderr, "ERROR : init_dftwaves : malloc : dftwaves->waves\n"); return(-21); } @@ -194,53 +173,11 @@ int init_dftwaves(DFTWAVES **optr, const double *dft_coefs, /* Foreach of 4 DFT frequency coef ... */ for (i = 0; i < nwaves; ++i) { /* Allocate wave structure */ - dftwaves->waves[i] = (DFTWAVE *)malloc(sizeof(DFTWAVE)); - if(dftwaves->waves[i] == (DFTWAVE *)NULL){ - /* Free memory allocated to this point. */ - { int _j; for(_j = 0; _j < i; _j++){ - free(dftwaves->waves[_j]->cos); - free(dftwaves->waves[_j]->sin); - free(dftwaves->waves[_j]); - }} - free(dftwaves->waves); - free(dftwaves); - fprintf(stderr, - "ERROR : init_dftwaves : malloc : dftwaves->waves[i]\n"); - return(-22); - } + dftwaves->waves[i] = (DFTWAVE *)g_malloc(sizeof(DFTWAVE)); /* Allocate cosine vector */ - dftwaves->waves[i]->cos = (double *)malloc(blocksize * sizeof(double)); - if(dftwaves->waves[i]->cos == (double *)NULL){ - /* Free memory allocated to this point. */ - { int _j; for(_j = 0; _j < i; _j++){ - free(dftwaves->waves[_j]->cos); - free(dftwaves->waves[_j]->sin); - free(dftwaves->waves[_j]); - }} - free(dftwaves->waves[i]); - free(dftwaves->waves); - free(dftwaves); - fprintf(stderr, - "ERROR : init_dftwaves : malloc : dftwaves->waves[i]->cos\n"); - return(-23); - } + dftwaves->waves[i]->cos = (double *)g_malloc(blocksize * sizeof(double)); /* Allocate sine vector */ - dftwaves->waves[i]->sin = (double *)malloc(blocksize * sizeof(double)); - if(dftwaves->waves[i]->sin == (double *)NULL){ - /* Free memory allocated to this point. */ - { int _j; for(_j = 0; _j < i; _j++){ - free(dftwaves->waves[_j]->cos); - free(dftwaves->waves[_j]->sin); - free(dftwaves->waves[_j]); - }} - free(dftwaves->waves[i]->cos); - free(dftwaves->waves[i]); - free(dftwaves->waves); - free(dftwaves); - fprintf(stderr, - "ERROR : init_dftwaves : malloc : dftwaves->waves[i]->sin\n"); - return(-24); - } + dftwaves->waves[i]->sin = (double *)g_malloc(blocksize * sizeof(double)); /* Assign pointer nicknames */ cptr = dftwaves->waves[i]->cos; @@ -435,11 +372,7 @@ int init_rotgrids(ROTGRIDS **optr, const int iw, const int ih, const int ipad, double pad; /* Allocate structure */ - rotgrids = (ROTGRIDS *)malloc(sizeof(ROTGRIDS)); - if(rotgrids == (ROTGRIDS *)NULL){ - fprintf(stderr, "ERROR : init_rotgrids : malloc : rotgrids\n"); - return(-30); - } + rotgrids = (ROTGRIDS *)g_malloc(sizeof(ROTGRIDS)); /* Set rotgrid attributes */ rotgrids->ngrids = ndirs; @@ -474,7 +407,7 @@ int init_rotgrids(ROTGRIDS **optr, const int iw, const int ih, const int ipad, fprintf(stderr, "ERROR : init_rotgrids : Illegal relative flag : %d\n", relative2); - free(rotgrids); + g_free(rotgrids); return(-31); } @@ -488,7 +421,7 @@ int init_rotgrids(ROTGRIDS **optr, const int iw, const int ih, const int ipad, if(ipad < grid_pad){ /* If input pad is NOT large enough, then ERROR. */ fprintf(stderr, "ERROR : init_rotgrids : Pad passed is too small\n"); - free(rotgrids); + g_free(rotgrids); return(-32); } /* Otherwise, use the specified input pad in computing grid offsets. */ @@ -506,13 +439,7 @@ int init_rotgrids(ROTGRIDS **optr, const int iw, const int ih, const int ipad, cy = (grid_h-1)/(double)2.0; /* Allocate list of rotgrid pointers */ - rotgrids->grids = (int **)malloc(ndirs * sizeof(int *)); - if(rotgrids->grids == (int **)NULL){ - /* Free memory allocated to this point. */ - free(rotgrids); - fprintf(stderr, "ERROR : init_rotgrids : malloc : rotgrids->grids\n"); - return(-33); - } + rotgrids->grids = (int **)g_malloc(ndirs * sizeof(int *)); /* Pi_offset is the offset in radians from which angles are to begin. */ pi_offset = start_dir_angle; @@ -523,17 +450,7 @@ int init_rotgrids(ROTGRIDS **optr, const int iw, const int ih, const int ipad, dir < ndirs; dir++, theta += pi_incr) { /* Allocate a rotgrid */ - rotgrids->grids[dir] = (int *)malloc(grid_size * sizeof(int)); - if(rotgrids->grids[dir] == (int *)NULL){ - /* Free memory allocated to this point. */ - { int _j; for(_j = 0; _j < dir; _j++){ - free(rotgrids->grids[_j]); - }} - free(rotgrids); - fprintf(stderr, - "ERROR : init_rotgrids : malloc : rotgrids->grids[dir]\n"); - return(-34); - } + rotgrids->grids[dir] = (int *)g_malloc(grid_size * sizeof(int)); /* Set pointer to current grid */ grid = rotgrids->grids[dir]; @@ -635,24 +552,11 @@ int alloc_dir_powers(double ***opowers, const int nwaves, const int ndirs) double **powers; /* Allocate list of double pointers to hold power vectors */ - powers = (double **)malloc(nwaves * sizeof(double*)); - if(powers == (double **)NULL){ - fprintf(stderr, "ERROR : alloc_dir_powers : malloc : powers\n"); - return(-40); - } + powers = (double **)g_malloc(nwaves * sizeof(double *)); /* Foreach DFT wave ... */ for(w = 0; w < nwaves; w++){ /* Allocate power vector for all directions */ - powers[w] = (double *)malloc(ndirs * sizeof(double)); - if(powers[w] == (double *)NULL){ - /* Free memory allocated to this point. */ - { int _j; for(_j = 0; _j < w; _j++){ - free(powers[_j]); - }} - free(powers); - fprintf(stderr, "ERROR : alloc_dir_powers : malloc : powers[w]\n"); - return(-41); - } + powers[w] = (double *)g_malloc(ndirs * sizeof(double)); } *opowers = powers; @@ -697,41 +601,16 @@ int alloc_power_stats(int **owis, double **opowmaxs, int **opowmax_dirs, ASSERT_SIZE_MUL(nstats, sizeof(double)); /* Allocate DFT wave index vector */ - wis = (int *)malloc(nstats * sizeof(int)); - if(wis == (int *)NULL){ - fprintf(stderr, "ERROR : alloc_power_stats : malloc : wis\n"); - return(-50); - } + wis = (int *)g_malloc(nstats * sizeof(int)); /* Allocate max power vector */ - powmaxs = (double *)malloc(nstats * sizeof(double)); - if(powmaxs == (double *)NULL){ - /* Free memory allocated to this point. */ - free(wis); - fprintf(stderr, "ERROR : alloc_power_stats : malloc : powmaxs\n"); - return(-51); - } + powmaxs = (double *)g_malloc(nstats * sizeof(double)); /* Allocate max power direction vector */ - powmax_dirs = (int *)malloc(nstats * sizeof(int)); - if(powmax_dirs == (int *)NULL){ - /* Free memory allocated to this point. */ - free(wis); - free(powmaxs); - fprintf(stderr, "ERROR : alloc_power_stats : malloc : powmax_dirs\n"); - return(-52); - } + powmax_dirs = (int *)g_malloc(nstats * sizeof(int)); /* Allocate normalized power vector */ - pownorms = (double *)malloc(nstats * sizeof(double)); - if(pownorms == (double *)NULL){ - /* Free memory allocated to this point. */ - free(wis); - free(powmaxs); - free(powmax_dirs); - fprintf(stderr, "ERROR : alloc_power_stats : malloc : pownorms\n"); - return(-53); - } + pownorms = (double *)g_malloc(nstats * sizeof(double)); *owis = wis; *opowmaxs = powmaxs; diff --git a/libfprint/nbis/mindtct/line.c b/libfprint/nbis/mindtct/line.c index 07edf18d..d556141d 100644 --- a/libfprint/nbis/mindtct/line.c +++ b/libfprint/nbis/mindtct/line.c @@ -95,17 +95,8 @@ int line_points(int **ox_list, int **oy_list, int *onum, asize = max(abs(x2-x1)+2, abs(y2-y1)+2); /* Allocate x and y-pixel coordinate lists to length 'asize'. */ - x_list = (int *)malloc(asize*sizeof(int)); - if(x_list == (int *)NULL){ - fprintf(stderr, "ERROR : line_points : malloc : x_list\n"); - return(-410); - } - y_list = (int *)malloc(asize*sizeof(int)); - if(y_list == (int *)NULL){ - free(x_list); - fprintf(stderr, "ERROR : line_points : malloc : y_list\n"); - return(-411); - } + x_list = (int *)g_malloc(asize * sizeof(int)); + y_list = (int *)g_malloc(asize * sizeof(int)); /* Compute delta x and y. */ dx = x2 - x1; @@ -190,8 +181,8 @@ int line_points(int **ox_list, int **oy_list, int *onum, if(i >= asize){ fprintf(stderr, "ERROR : line_points : coord list overflow\n"); - free(x_list); - free(y_list); + g_free(x_list); + g_free(y_list); return(-412); } diff --git a/libfprint/nbis/mindtct/loop.c b/libfprint/nbis/mindtct/loop.c index 2142d181..6ab8ea2d 100644 --- a/libfprint/nbis/mindtct/loop.c +++ b/libfprint/nbis/mindtct/loop.c @@ -443,7 +443,7 @@ int is_loop_clockwise(const int *contour_x, const int *contour_y, ret = is_chain_clockwise(chain, nchain, default_ret); /* Free the chain code and return result. */ - free(chain); + g_free(chain); return(ret); } diff --git a/libfprint/nbis/mindtct/maps.c b/libfprint/nbis/mindtct/maps.c index ac3b82da..28e5b5f5 100644 --- a/libfprint/nbis/mindtct/maps.c +++ b/libfprint/nbis/mindtct/maps.c @@ -154,14 +154,14 @@ int gen_image_maps(int **odmap, int **olcmap, int **olfmap, int **ohcmap, &low_flow_map, blkoffs, mw, mh, pdata, pw, ph, dftwaves, dftgrids, lfsparms))){ /* Free memory allocated to this point. */ - free(blkoffs); + g_free(blkoffs); return(ret); } if((ret = morph_TF_map(low_flow_map, mw, mh, lfsparms))){ - free(direction_map); - free(low_contrast_map); - free(low_flow_map); + g_free(direction_map); + g_free(low_contrast_map); + g_free(low_flow_map); return(ret); } @@ -176,9 +176,9 @@ int gen_image_maps(int **odmap, int **olcmap, int **olfmap, int **ohcmap, /* 5. Interpolate INVALID direction blocks with their valid neighbors. */ if((ret = interpolate_direction_map(direction_map, low_contrast_map, mw, mh, lfsparms))){ - free(direction_map); - free(low_contrast_map); - free(low_flow_map); + g_free(direction_map); + g_free(low_contrast_map); + g_free(low_flow_map); return(ret); } @@ -198,14 +198,14 @@ int gen_image_maps(int **odmap, int **olcmap, int **olfmap, int **ohcmap, /* 9. Generate High Curvature Map from interpolated Direction Map. */ if((ret = gen_high_curve_map(&high_curve_map, direction_map, mw, mh, lfsparms))){ - free(direction_map); - free(low_contrast_map); - free(low_flow_map); + g_free(direction_map); + g_free(low_contrast_map); + g_free(low_flow_map); return(ret); } /* Deallocate working memory. */ - free(blkoffs); + g_free(blkoffs); *odmap = direction_map; *olcmap = low_contrast_map; @@ -276,44 +276,26 @@ int gen_initial_maps(int **odmap, int **olcmap, int **olfmap, bsize = mw * mh; /* Allocate Direction Map memory */ - direction_map = (int *)malloc(bsize * sizeof(int)); - if(direction_map == (int *)NULL){ - fprintf(stderr, - "ERROR : gen_initial_maps : malloc : direction_map\n"); - return(-550); - } + direction_map = (int *)g_malloc(bsize * sizeof(int)); /* Initialize the Direction Map to INVALID (-1). */ memset(direction_map, INVALID_DIR, bsize * sizeof(int)); /* Allocate Low Contrast Map memory */ - low_contrast_map = (int *)malloc(bsize * sizeof(int)); - if(low_contrast_map == (int *)NULL){ - free(direction_map); - fprintf(stderr, - "ERROR : gen_initial_maps : malloc : low_contrast_map\n"); - return(-551); - } + low_contrast_map = (int *)g_malloc(bsize * sizeof(int)); /* Initialize the Low Contrast Map to FALSE (0). */ memset(low_contrast_map, 0, bsize * sizeof(int)); /* Allocate Low Ridge Flow Map memory */ - low_flow_map = (int *)malloc(bsize * sizeof(int)); - if(low_flow_map == (int *)NULL){ - free(direction_map); - free(low_contrast_map); - fprintf(stderr, - "ERROR : gen_initial_maps : malloc : low_flow_map\n"); - return(-552); - } + low_flow_map = (int *)g_malloc(bsize * sizeof(int)); /* Initialize the Low Flow Map to FALSE (0). */ memset(low_flow_map, 0, bsize * sizeof(int)); /* Allocate DFT directional power vectors */ if((ret = alloc_dir_powers(&powers, dftwaves->nwaves, dftgrids->ngrids))){ /* Free memory allocated to this point. */ - free(direction_map); - free(low_contrast_map); - free(low_flow_map); + g_free(direction_map); + g_free(low_contrast_map); + g_free(low_flow_map); return(ret); } @@ -324,9 +306,9 @@ int gen_initial_maps(int **odmap, int **olcmap, int **olfmap, if((ret = alloc_power_stats(&wis, &powmaxs, &powmax_dirs, &pownorms, nstats))){ /* Free memory allocated to this point. */ - free(direction_map); - free(low_contrast_map); - free(low_flow_map); + g_free(direction_map); + g_free(low_contrast_map); + g_free(low_flow_map); free_dir_powers(powers, dftwaves->nwaves); return(ret); } @@ -364,14 +346,14 @@ int gen_initial_maps(int **odmap, int **olcmap, int **olfmap, pdata, pw, ph, lfsparms))){ /* If system error ... */ if(ret < 0){ - free(direction_map); - free(low_contrast_map); - free(low_flow_map); + g_free(direction_map); + g_free(low_contrast_map); + g_free(low_flow_map); free_dir_powers(powers, dftwaves->nwaves); - free(wis); - free(powmaxs); - free(powmax_dirs); - free(pownorms); + g_free(wis); + g_free(powmaxs); + g_free(powmax_dirs); + g_free(pownorms); return(ret); } @@ -388,14 +370,14 @@ int gen_initial_maps(int **odmap, int **olcmap, int **olfmap, if((ret = dft_dir_powers(powers, pdata, low_contrast_offset, pw, ph, dftwaves, dftgrids))){ /* Free memory allocated to this point. */ - free(direction_map); - free(low_contrast_map); - free(low_flow_map); + g_free(direction_map); + g_free(low_contrast_map); + g_free(low_flow_map); free_dir_powers(powers, dftwaves->nwaves); - free(wis); - free(powmaxs); - free(powmax_dirs); - free(pownorms); + g_free(wis); + g_free(powmaxs); + g_free(powmax_dirs); + g_free(pownorms); return(ret); } @@ -405,14 +387,14 @@ int gen_initial_maps(int **odmap, int **olcmap, int **olfmap, if((ret = dft_power_stats(wis, powmaxs, powmax_dirs, pownorms, powers, 1, dftwaves->nwaves, dftgrids->ngrids))){ /* Free memory allocated to this point. */ - free(direction_map); - free(low_contrast_map); - free(low_flow_map); + g_free(direction_map); + g_free(low_contrast_map); + g_free(low_flow_map); free_dir_powers(powers, dftwaves->nwaves); - free(wis); - free(powmaxs); - free(powmax_dirs); - free(pownorms); + g_free(wis); + g_free(powmaxs); + g_free(powmax_dirs); + g_free(pownorms); return(ret); } @@ -452,10 +434,10 @@ int gen_initial_maps(int **odmap, int **olcmap, int **olfmap, /* Deallocate working memory */ free_dir_powers(powers, dftwaves->nwaves); - free(wis); - free(powmaxs); - free(powmax_dirs); - free(pownorms); + g_free(wis); + g_free(powmaxs); + g_free(powmax_dirs); + g_free(pownorms); *odmap = direction_map; *olcmap = low_contrast_map; @@ -505,12 +487,7 @@ int interpolate_direction_map(int *direction_map, int *low_contrast_map, /* Allocate output (interpolated) Direction Map. */ ASSERT_SIZE_MUL(mw, mh); ASSERT_SIZE_MUL(mw * mh, sizeof(int)); - omap = (int *)malloc(mw*mh*sizeof(int)); - if(omap == (int *)NULL){ - fprintf(stderr, - "ERROR : interpolate_direction_map : malloc : omap\n"); - return(-520); - } + omap = (int *)g_malloc(mw * mh * sizeof(int)); /* Set pointers to the first block in the maps. */ dptr = direction_map; @@ -650,7 +627,7 @@ int interpolate_direction_map(int *direction_map, int *low_contrast_map, /* Copy the interpolated directions into the input map. */ memcpy(direction_map, omap, mw*mh*sizeof(int)); /* Deallocate the working memory. */ - free(omap); + g_free(omap); /* Return normally. */ return(0); @@ -680,18 +657,9 @@ int morph_TF_map(int *tfmap, const int mw, const int mh, ASSERT_INT_MUL(mw, mh); /* Convert TRUE/FALSE map into a binary byte image. */ - cimage = (unsigned char *)malloc(mw*mh); - if(cimage == (unsigned char *)NULL){ - fprintf(stderr, "ERROR : morph_TF_map : malloc : cimage\n"); - return(-660); - } + cimage = (unsigned char *)g_malloc(mw * mh); - mimage = (unsigned char *)malloc(mw*mh); - if(mimage == (unsigned char *)NULL){ - free(cimage); - fprintf(stderr, "ERROR : morph_TF_map : malloc : mimage\n"); - return(-661); - } + mimage = (unsigned char *)g_malloc(mw * mh); cptr = cimage; mptr = tfmap; @@ -710,8 +678,8 @@ int morph_TF_map(int *tfmap, const int mw, const int mh, *mptr++ = *cptr++; } - free(cimage); - free(mimage); + g_free(cimage); + g_free(mimage); return(0); } @@ -746,20 +714,16 @@ int pixelize_map(int **omap, const int iw, const int ih, ASSERT_SIZE_MUL(iw, ih); ASSERT_SIZE_MUL(iw * ih, sizeof(int)); - pmap = (int *)malloc(iw*ih*sizeof(int)); - if(pmap == (int *)NULL){ - fprintf(stderr, "ERROR : pixelize_map : malloc : pmap\n"); - return(-590); - } + pmap = (int *)g_malloc(iw * ih * sizeof(int)); if((ret = block_offsets(&blkoffs, &bw, &bh, iw, ih, 0, blocksize))){ - free(pmap); + g_free(pmap); return(ret); } if((bw != mw) || (bh != mh)){ - free(blkoffs); - free(pmap); + g_free(blkoffs); + g_free(pmap); fprintf(stderr, "ERROR : pixelize_map : block dimensions do not match\n"); return(-591); @@ -777,7 +741,7 @@ int pixelize_map(int **omap, const int iw, const int ih, } /* Deallocate working memory. */ - free(blkoffs); + g_free(blkoffs); /* Assign pixelized map to output pointer. */ *omap = pmap; @@ -910,12 +874,7 @@ int gen_high_curve_map(int **ohcmap, int *direction_map, /* Allocate High Curvature Map. */ ASSERT_SIZE_MUL(mapsize, sizeof(int)); - high_curve_map = (int *)malloc(mapsize * sizeof(int)); - if(high_curve_map == (int *)NULL){ - fprintf(stderr, - "ERROR: gen_high_curve_map : malloc : high_curve_map\n"); - return(-530); - } + high_curve_map = (int *)g_malloc(mapsize * sizeof(int)); /* Initialize High Curvature Map to FALSE (0). */ memset(high_curve_map, 0, mapsize*sizeof(int)); diff --git a/libfprint/nbis/mindtct/minutia.c b/libfprint/nbis/mindtct/minutia.c index ca0d551c..0b29aa00 100644 --- a/libfprint/nbis/mindtct/minutia.c +++ b/libfprint/nbis/mindtct/minutia.c @@ -118,16 +118,8 @@ int alloc_minutiae(MINUTIAE **ominutiae, const int DEFAULT_BOZORTH_MINUTIAE) { MINUTIAE *minutiae; - minutiae = (MINUTIAE *)malloc(sizeof(MINUTIAE)); - if(minutiae == (MINUTIAE *)NULL){ - fprintf(stderr, "ERROR : alloc_minutiae : malloc : minutiae\n"); - exit(-430); - } - minutiae->list = (MINUTIA **)malloc(DEFAULT_BOZORTH_MINUTIAE * sizeof(MINUTIA *)); - if(minutiae->list == (MINUTIA **)NULL){ - fprintf(stderr, "ERROR : alloc_minutiae : malloc : minutiae->list\n"); - exit(-431); - } + minutiae = (MINUTIAE *)g_malloc(sizeof(MINUTIAE)); + minutiae->list = (MINUTIA **)g_malloc(DEFAULT_BOZORTH_MINUTIAE * sizeof(MINUTIA *)); minutiae->alloc = DEFAULT_BOZORTH_MINUTIAE; minutiae->num = 0; @@ -154,12 +146,8 @@ int alloc_minutiae(MINUTIAE **ominutiae, const int DEFAULT_BOZORTH_MINUTIAE) int realloc_minutiae(MINUTIAE *minutiae, const int incr_minutiae) { minutiae->alloc += incr_minutiae; - minutiae->list = (MINUTIA **)realloc(minutiae->list, - minutiae->alloc * sizeof(MINUTIA *)); - if(minutiae->list == (MINUTIA **)NULL){ - fprintf(stderr, "ERROR : realloc_minutiae : realloc : minutiae->list\n"); - exit(-432); - } + minutiae->list = (MINUTIA **)g_realloc(minutiae->list, + minutiae->alloc * sizeof(MINUTIA *)); return(0); } @@ -227,37 +215,37 @@ int detect_minutiae_V2(MINUTIAE *minutiae, if((ret = pixelize_map(&plow_flow_map, iw, ih, low_flow_map, mw, mh, lfsparms->blocksize))){ - free(pdirection_map); + g_free(pdirection_map); return(ret); } if((ret = pixelize_map(&phigh_curve_map, iw, ih, high_curve_map, mw, mh, lfsparms->blocksize))){ - free(pdirection_map); - free(plow_flow_map); + g_free(pdirection_map); + g_free(plow_flow_map); return(ret); } if((ret = scan4minutiae_horizontally_V2(minutiae, bdata, iw, ih, pdirection_map, plow_flow_map, phigh_curve_map, lfsparms))){ - free(pdirection_map); - free(plow_flow_map); - free(phigh_curve_map); + g_free(pdirection_map); + g_free(plow_flow_map); + g_free(phigh_curve_map); return(ret); } if((ret = scan4minutiae_vertically_V2(minutiae, bdata, iw, ih, pdirection_map, plow_flow_map, phigh_curve_map, lfsparms))){ - free(pdirection_map); - free(plow_flow_map); - free(phigh_curve_map); + g_free(pdirection_map); + g_free(plow_flow_map); + g_free(phigh_curve_map); return(ret); } /* Deallocate working memories. */ - free(pdirection_map); - free(plow_flow_map); - free(phigh_curve_map); + g_free(pdirection_map); + g_free(plow_flow_map); + g_free(phigh_curve_map); /* Return normally. */ return(0); @@ -550,11 +538,7 @@ int sort_minutiae_y_x(MINUTIAE *minutiae, const int iw, const int ih) /* Allocate a list of integers to hold 1-D image pixel offsets */ /* for each of the 2-D minutia coordinate points. */ - ranks = (int *)malloc(minutiae->num * sizeof(int)); - if(ranks == (int *)NULL){ - fprintf(stderr, "ERROR : sort_minutiae_y_x : malloc : ranks\n"); - return(-310); - } + ranks = (int *)g_malloc(minutiae->num * sizeof(int)); /* Compute 1-D image pixel offsets form 2-D minutia coordinate points. */ for(i = 0; i < minutiae->num; i++) @@ -562,31 +546,25 @@ int sort_minutiae_y_x(MINUTIAE *minutiae, const int iw, const int ih) /* Get sorted order of minutiae. */ if((ret = sort_indices_int_inc(&order, ranks, minutiae->num))){ - free(ranks); + g_free(ranks); return(ret); } /* Allocate new MINUTIA list to hold sorted minutiae. */ - newlist = (MINUTIA **)malloc(minutiae->num * sizeof(MINUTIA *)); - if(newlist == (MINUTIA **)NULL){ - free(ranks); - free(order); - fprintf(stderr, "ERROR : sort_minutiae_y_x : malloc : newlist\n"); - return(-311); - } + newlist = (MINUTIA **)g_malloc(minutiae->num * sizeof(MINUTIA *)); /* Put minutia into sorted order in new list. */ for(i = 0; i < minutiae->num; i++) newlist[i] = minutiae->list[order[i]]; /* Deallocate non-sorted list of minutia pointers. */ - free(minutiae->list); + g_free(minutiae->list); /* Assign new sorted list of minutia to minutiae list. */ minutiae->list = newlist; /* Free the working memories supporting the sort. */ - free(order); - free(ranks); + g_free(order); + g_free(ranks); /* Return normally. */ return(0); @@ -615,11 +593,7 @@ int sort_minutiae_x_y(MINUTIAE *minutiae, const int iw, const int ih) /* Allocate a list of integers to hold 1-D image pixel offsets */ /* for each of the 2-D minutia coordinate points. */ - ranks = (int *)malloc(minutiae->num * sizeof(int)); - if(ranks == (int *)NULL){ - fprintf(stderr, "ERROR : sort_minutiae_x_y : malloc : ranks\n"); - return(-440); - } + ranks = (int *)g_malloc(minutiae->num * sizeof(int)); /* Compute 1-D image pixel offsets form 2-D minutia coordinate points. */ for(i = 0; i < minutiae->num; i++) @@ -627,31 +601,25 @@ int sort_minutiae_x_y(MINUTIAE *minutiae, const int iw, const int ih) /* Get sorted order of minutiae. */ if((ret = sort_indices_int_inc(&order, ranks, minutiae->num))){ - free(ranks); + g_free(ranks); return(ret); } /* Allocate new MINUTIA list to hold sorted minutiae. */ - newlist = (MINUTIA **)malloc(minutiae->num * sizeof(MINUTIA *)); - if(newlist == (MINUTIA **)NULL){ - free(ranks); - free(order); - fprintf(stderr, "ERROR : sort_minutiae_x_y : malloc : newlist\n"); - return(-441); - } + newlist = (MINUTIA **)g_malloc(minutiae->num * sizeof(MINUTIA *)); /* Put minutia into sorted order in new list. */ for(i = 0; i < minutiae->num; i++) newlist[i] = minutiae->list[order[i]]; /* Deallocate non-sorted list of minutia pointers. */ - free(minutiae->list); + g_free(minutiae->list); /* Assign new sorted list of minutia to minutiae list. */ minutiae->list = newlist; /* Free the working memories supporting the sort. */ - free(order); - free(ranks); + g_free(order); + g_free(ranks); /* Return normally. */ return(0); @@ -764,12 +732,7 @@ int create_minutia(MINUTIA **ominutia, const int x_loc, const int y_loc, MINUTIA *minutia; /* Allocate a minutia structure. */ - minutia = (MINUTIA *)malloc(sizeof(MINUTIA)); - /* If allocation error... */ - if(minutia == (MINUTIA *)NULL){ - fprintf(stderr, "ERROR : create_minutia : malloc : minutia\n"); - return(-230); - } + minutia = (MINUTIA *)g_malloc(sizeof(MINUTIA)); /* Assign minutia structure attributes. */ minutia->x = x_loc; @@ -807,10 +770,10 @@ void free_minutiae(MINUTIAE *minutiae) for(i = 0; i < minutiae->num; i++) free_minutia(minutiae->list[i]); /* Deallocate list of minutia pointers. */ - free(minutiae->list); + g_free(minutiae->list); /* Deallocate the list structure. */ - free(minutiae); + g_free(minutiae); } /************************************************************************* @@ -825,12 +788,12 @@ void free_minutia(MINUTIA *minutia) { /* Deallocate sublists. */ if(minutia->nbrs != (int *)NULL) - free(minutia->nbrs); + g_free(minutia->nbrs); if(minutia->ridge_counts != (int *)NULL) - free(minutia->ridge_counts); + g_free(minutia->ridge_counts); /* Deallocate the minutia structure. */ - free(minutia); + g_free(minutia); } /************************************************************************* diff --git a/libfprint/nbis/mindtct/quality.c b/libfprint/nbis/mindtct/quality.c index 94e9b63a..399c4776 100644 --- a/libfprint/nbis/mindtct/quality.c +++ b/libfprint/nbis/mindtct/quality.c @@ -118,11 +118,7 @@ int gen_quality_map(int **oqmap, int *direction_map, int *low_contrast_map, ASSERT_SIZE_MUL(map_w, map_h); ASSERT_SIZE_MUL(map_w * map_h, sizeof(int)); - QualMap = (int *)malloc(map_w * map_h * sizeof(int)); - if(QualMap == (int *)NULL){ - fprintf(stderr, "ERROR : gen_quality_map : malloc : QualMap\n"); - return(-2); - } + QualMap = (int *)g_malloc(map_w * map_h * sizeof(int)); /* Foreach row of blocks in maps ... */ for(thisY=0; thisYreliability = reliability; } /* NEW 05-08-2002 */ - free(pquality_map); + g_free(pquality_map); /* Return normally. */ return(0); diff --git a/libfprint/nbis/mindtct/remove.c b/libfprint/nbis/mindtct/remove.c index faa6607e..af5ab7d0 100644 --- a/libfprint/nbis/mindtct/remove.c +++ b/libfprint/nbis/mindtct/remove.c @@ -380,7 +380,7 @@ int remove_hooks(MINUTIAE *minutiae, if((deltadir = closest_dir_dist(minutia1->direction, minutia2->direction, full_ndirs)) == INVALID_DIR){ - free(to_remove); + g_free(to_remove); fprintf(stderr, "ERROR : remove_hooks : INVALID direction\n"); return(-641); @@ -424,7 +424,7 @@ int remove_hooks(MINUTIAE *minutiae, } /* If system error occurred during hook test ... */ else if (ret < 0){ - free(to_remove); + g_free(to_remove); return(ret); } /* Otherwise, no hook found, so skip to next */ @@ -474,14 +474,14 @@ int remove_hooks(MINUTIAE *minutiae, if(to_remove[i]){ /* Remove the minutia from the minutiae list. */ if((ret = remove_minutia(i, minutiae))){ - free(to_remove); + g_free(to_remove); return(ret); } } } /* Deallocate flag list. */ - free(to_remove); + g_free(to_remove); /* Return normally. */ return(0); @@ -641,7 +641,7 @@ int remove_islands_and_lakes(MINUTIAE *minutiae, if((deltadir = closest_dir_dist(minutia1->direction, minutia2->direction, full_ndirs)) == INVALID_DIR){ - free(to_remove); + g_free(to_remove); fprintf(stderr, "ERROR : remove_islands_and_lakes : INVALID direction\n"); return(-611); @@ -673,7 +673,7 @@ int remove_islands_and_lakes(MINUTIAE *minutiae, bdata, iw, ih))){ free_contour(loop_x, loop_y, loop_ex, loop_ey); - free(to_remove); + g_free(to_remove); return(ret); } /* Set to remove first minutia. */ @@ -696,7 +696,7 @@ int remove_islands_and_lakes(MINUTIAE *minutiae, } /* If ERROR while looking for island/lake ... */ else if (ret < 0){ - free(to_remove); + g_free(to_remove); return(ret); } else @@ -741,14 +741,14 @@ int remove_islands_and_lakes(MINUTIAE *minutiae, if(to_remove[i]){ /* Remove the minutia from the minutiae list. */ if((ret = remove_minutia(i, minutiae))){ - free(to_remove); + g_free(to_remove); return(ret); } } } /* Deallocate flag list. */ - free(to_remove); + g_free(to_remove); /* Return normally. */ return(0); @@ -950,8 +950,8 @@ int remove_malformations(MINUTIAE *minutiae, print2log("%d,%d RMMAL3 (%f)\n", minutia->x, minutia->y, ratio); if((ret = remove_minutia(i, minutiae))){ - free(x_list); - free(y_list); + g_free(x_list); + g_free(y_list); /* If system error, return error code. */ return(ret); } @@ -961,8 +961,8 @@ int remove_malformations(MINUTIAE *minutiae, } } - free(x_list); - free(y_list); + g_free(x_list); + g_free(y_list); } } @@ -1447,7 +1447,7 @@ int remove_overlaps(MINUTIAE *minutiae, if((deltadir = closest_dir_dist(minutia1->direction, minutia2->direction, full_ndirs)) == INVALID_DIR){ - free(to_remove); + g_free(to_remove); fprintf(stderr, "ERROR : remove_overlaps : INVALID direction\n"); return(-651); @@ -1546,14 +1546,14 @@ int remove_overlaps(MINUTIAE *minutiae, if(to_remove[i]){ /* Remove the minutia from the minutiae list. */ if((ret = remove_minutia(i, minutiae))){ - free(to_remove); + g_free(to_remove); return(ret); } } } /* Deallocate flag list. */ - free(to_remove); + g_free(to_remove); /* Return normally. */ return(0); @@ -2034,12 +2034,7 @@ int remove_or_adjust_side_minutiae_V2(MINUTIAE *minutiae, /* Allocate working memory for holding rotated y-coord of a */ /* minutia's contour. */ - rot_y = (int *)malloc(((lfsparms->side_half_contour<<1)+1) * sizeof(int)); - if(rot_y == (int *)NULL){ - fprintf(stderr, - "ERROR : remove_or_adjust_side_minutiae_V2 : malloc : rot_y\n"); - return(-630); - } + rot_y = (int *)g_malloc(((lfsparms->side_half_contour << 1) + 1) * sizeof(int)); /* Compute factor for converting integer directions to radians. */ pi_factor = M_PI / (double)lfsparms->num_directions; @@ -2061,7 +2056,7 @@ int remove_or_adjust_side_minutiae_V2(MINUTIAE *minutiae, /* If system error occurred ... */ if(ret < 0){ /* Deallocate working memory. */ - free(rot_y); + g_free(rot_y); /* Return error code. */ return(ret); } @@ -2077,7 +2072,7 @@ int remove_or_adjust_side_minutiae_V2(MINUTIAE *minutiae, /* Remove minutia from list. */ if((ret = remove_minutia(i, minutiae))){ /* Deallocate working memory. */ - free(rot_y); + g_free(rot_y); /* Return error code. */ return(ret); } @@ -2130,7 +2125,7 @@ int remove_or_adjust_side_minutiae_V2(MINUTIAE *minutiae, &minmax_alloc, &minmax_num, rot_y, ncontour))){ /* If system error, then deallocate working memories. */ - free(rot_y); + g_free(rot_y); free_contour(contour_x, contour_y, contour_ex, contour_ey); /* Return error code. */ return(ret); @@ -2156,12 +2151,12 @@ int remove_or_adjust_side_minutiae_V2(MINUTIAE *minutiae, /* Remove minutia from list. */ if((ret = remove_minutia(i, minutiae))){ /* Deallocate working memory. */ - free(rot_y); + g_free(rot_y); free_contour(contour_x, contour_y, contour_ex, contour_ey); if(minmax_alloc > 0){ - free(minmax_val); - free(minmax_type); - free(minmax_i); + g_free(minmax_val); + g_free(minmax_type); + g_free(minmax_i); } /* Return error code. */ return(ret); @@ -2202,12 +2197,12 @@ int remove_or_adjust_side_minutiae_V2(MINUTIAE *minutiae, /* Remove minutia from list. */ if((ret = remove_minutia(i, minutiae))){ /* Deallocate working memory. */ - free(rot_y); + g_free(rot_y); free_contour(contour_x, contour_y, contour_ex, contour_ey); if(minmax_alloc > 0){ - free(minmax_val); - free(minmax_type); - free(minmax_i); + g_free(minmax_val); + g_free(minmax_type); + g_free(minmax_i); } /* Return error code. */ return(ret); @@ -2231,12 +2226,12 @@ int remove_or_adjust_side_minutiae_V2(MINUTIAE *minutiae, /* Remove minutia from list. */ if((ret = remove_minutia(i, minutiae))){ /* If system error, then deallocate working memories. */ - free(rot_y); + g_free(rot_y); free_contour(contour_x, contour_y, contour_ex, contour_ey); if(minmax_alloc > 0){ - free(minmax_val); - free(minmax_type); - free(minmax_i); + g_free(minmax_val); + g_free(minmax_type); + g_free(minmax_i); } /* Return error code. */ return(ret); @@ -2248,15 +2243,15 @@ int remove_or_adjust_side_minutiae_V2(MINUTIAE *minutiae, /* Deallocate contour and min/max buffers. */ free_contour(contour_x, contour_y, contour_ex, contour_ey); if(minmax_alloc > 0){ - free(minmax_val); - free(minmax_type); - free(minmax_i); + g_free(minmax_val); + g_free(minmax_type); + g_free(minmax_i); } } /* End else contour extracted. */ } /* End while not end of minutiae list. */ /* Deallocate working memory. */ - free(rot_y); + g_free(rot_y); /* Return normally. */ return(0); diff --git a/libfprint/nbis/mindtct/ridges.c b/libfprint/nbis/mindtct/ridges.c index 8f69fb24..f0d9cd3c 100644 --- a/libfprint/nbis/mindtct/ridges.c +++ b/libfprint/nbis/mindtct/ridges.c @@ -152,7 +152,7 @@ int count_minutia_ridges(const int first, MINUTIAE *minutiae, if((ret = find_neighbors(&nbr_list, &nnbrs, lfsparms->max_nbrs, first, minutiae))){ if (nbr_list != NULL) - free(nbr_list); + g_free(nbr_list); return(ret); } @@ -167,18 +167,13 @@ int count_minutia_ridges(const int first, MINUTIAE *minutiae, /* Sort neighbors on delta dirs. */ if((ret = sort_neighbors(nbr_list, nnbrs, first, minutiae))){ - free(nbr_list); + g_free(nbr_list); return(ret); } /* Count ridges between first and neighbors. */ /* List of ridge counts, one for each neighbor stored. */ - nbr_nridges = (int *)malloc(nnbrs * sizeof(int)); - if(nbr_nridges == (int *)NULL){ - free(nbr_list); - fprintf(stderr, "ERROR : count_minutia_ridges : malloc : nbr_nridges\n"); - return(-450); - } + nbr_nridges = (int *)g_malloc(nnbrs * sizeof(int)); /* Foreach neighbor found and sorted in list ... */ for(i = 0; i < nnbrs; i++){ @@ -187,8 +182,8 @@ int count_minutia_ridges(const int first, MINUTIAE *minutiae, /* If system error ... */ if(ret < 0){ /* Deallocate working memories. */ - free(nbr_list); - free(nbr_nridges); + g_free(nbr_list); + g_free(nbr_nridges); /* Return error code. */ return(ret); } @@ -235,21 +230,11 @@ int find_neighbors(int **onbr_list, int *onnbrs, const int max_nbrs, double *nbr_sqr_dists, xdist, xdist2; /* Allocate list of neighbor minutiae indices. */ - nbr_list = (int *)malloc(max_nbrs * sizeof(int)); - if(nbr_list == (int *)NULL){ - fprintf(stderr, "ERROR : find_neighbors : malloc : nbr_list\n"); - return(-460); - } + nbr_list = (int *)g_malloc(max_nbrs * sizeof(int)); /* Allocate list of squared euclidean distances between neighbors */ /* and current primary minutia point. */ - nbr_sqr_dists = (double *)malloc(max_nbrs * sizeof(double)); - if(nbr_sqr_dists == (double *)NULL){ - free(nbr_list); - fprintf(stderr, - "ERROR : find_neighbors : malloc : nbr_sqr_dists\n"); - return(-461); - } + nbr_sqr_dists = (double *)g_malloc(max_nbrs * sizeof(double)); /* Initialize number of stored neighbors to 0. */ nnbrs = 0; @@ -280,8 +265,8 @@ int find_neighbors(int **onbr_list, int *onnbrs, const int max_nbrs, /* Append or insert the new neighbor into the neighbor lists. */ if((ret = update_nbr_dists(nbr_list, nbr_sqr_dists, &nnbrs, max_nbrs, first, second, minutiae))){ - free(nbr_sqr_dists); - free(nbr_list); + g_free(nbr_sqr_dists); + g_free(nbr_list); return(ret); } } @@ -297,12 +282,12 @@ int find_neighbors(int **onbr_list, int *onnbrs, const int max_nbrs, } /* Deallocate working memory. */ - free(nbr_sqr_dists); + g_free(nbr_sqr_dists); /* If no neighbors found ... */ if(nnbrs == 0){ /* Deallocate the neighbor list. */ - free(nbr_list); + g_free(nbr_list); *onnbrs = 0; } /* Otherwise, assign neighbors to output pointer. */ @@ -497,11 +482,7 @@ int sort_neighbors(int *nbr_list, const int nnbrs, const int first, /* List of angles of lines joining the current primary to each */ /* of the secondary neighbors. */ - join_thetas = (double *)malloc(nnbrs * sizeof(double)); - if(join_thetas == (double *)NULL){ - fprintf(stderr, "ERROR : sort_neighbors : malloc : join_thetas\n"); - return(-490); - } + join_thetas = (double *)g_malloc(nnbrs * sizeof(double)); for(i = 0; i < nnbrs; i++){ /* Compute angle to line connecting the 2 points. */ @@ -523,7 +504,7 @@ int sort_neighbors(int *nbr_list, const int nnbrs, const int first, bubble_sort_double_inc_2(join_thetas, nbr_list, nnbrs); /* Deallocate the list of angles. */ - free(join_thetas); + g_free(join_thetas); /* Return normally. */ return(0); @@ -576,8 +557,8 @@ int ridge_count(const int first, const int second, MINUTIAE *minutiae, /* It there are no points on the line trajectory, then no ridges */ /* to count (this should not happen, but just in case) ... */ if(num == 0){ - free(xlist); - free(ylist); + g_free(xlist); + g_free(ylist); return(0); } @@ -597,8 +578,8 @@ int ridge_count(const int first, const int second, MINUTIAE *minutiae, /* If opposite pixel not found ... then no ridges to count */ if(!found){ - free(xlist); - free(ylist); + g_free(xlist); + g_free(ylist); return(0); } @@ -613,8 +594,8 @@ int ridge_count(const int first, const int second, MINUTIAE *minutiae, /* If 0-to-1 transition not found ... */ if(!find_transition(&i, 0, 1, xlist, ylist, num, bdata, iw, ih)){ /* Then we are done looking for ridges. */ - free(xlist); - free(ylist); + g_free(xlist); + g_free(ylist); print2log("\n"); @@ -630,8 +611,8 @@ int ridge_count(const int first, const int second, MINUTIAE *minutiae, /* If 1-to-0 transition not found ... */ if(!find_transition(&i, 1, 0, xlist, ylist, num, bdata, iw, ih)){ /* Then we are done looking for ridges. */ - free(xlist); - free(ylist); + g_free(xlist); + g_free(ylist); print2log("\n"); @@ -657,8 +638,8 @@ int ridge_count(const int first, const int second, MINUTIAE *minutiae, /* If system error ... */ if(ret < 0){ - free(xlist); - free(ylist); + g_free(xlist); + g_free(ylist); /* Return the error code. */ return(ret); } @@ -677,8 +658,8 @@ int ridge_count(const int first, const int second, MINUTIAE *minutiae, } /* Deallocate working memories. */ - free(xlist); - free(ylist); + g_free(xlist); + g_free(ylist); print2log("\n"); diff --git a/libfprint/nbis/mindtct/shape.c b/libfprint/nbis/mindtct/shape.c index 5f9e7bcb..28bc66c7 100644 --- a/libfprint/nbis/mindtct/shape.c +++ b/libfprint/nbis/mindtct/shape.c @@ -98,23 +98,11 @@ int alloc_shape(SHAPE **oshape, const int xmin, const int ymin, alloc_pts = xmax - xmin + 1; /* Allocate the shape structure. */ - shape = (SHAPE *)malloc(sizeof(SHAPE)); - /* If there is an allocation error... */ - if(shape == (SHAPE *)NULL){ - fprintf(stderr, "ERROR : alloc_shape : malloc : shape\n"); - return(-250); - } + shape = (SHAPE *)g_malloc(sizeof(SHAPE)); /* Allocate the list of row pointers. We now this number will fit */ /* the shape exactly. */ - shape->rows = (ROW **)malloc(alloc_rows * sizeof(ROW *)); - /* If there is an allocation error... */ - if(shape->rows == (ROW **)NULL){ - /* Deallocate memory alloated by this routine to this point. */ - free(shape); - fprintf(stderr, "ERROR : alloc_shape : malloc : shape->rows\n"); - return(-251); - } + shape->rows = (ROW **)g_malloc(alloc_rows * sizeof(ROW *)); /* Initialize the shape structure's attributes. */ shape->ymin = ymin; @@ -128,36 +116,10 @@ int alloc_shape(SHAPE **oshape, const int xmin, const int ymin, for(i = 0, y = ymin; i < alloc_rows; i++, y++){ /* Allocate a row structure and store it in its respective position */ /* in the shape structure's list of row pointers. */ - shape->rows[i] = (ROW *)malloc(sizeof(ROW)); - /* If there is an allocation error... */ - if(shape->rows[i] == (ROW *)NULL){ - /* Deallocate memory alloated by this routine to this point. */ - for(j = 0; j < i; j++){ - free(shape->rows[j]->xs); - free(shape->rows[j]); - } - free(shape->rows); - free(shape); - fprintf(stderr, "ERROR : alloc_shape : malloc : shape->rows[i]\n"); - return(-252); - } + shape->rows[i] = (ROW *)g_malloc(sizeof(ROW)); /* Allocate the current rows list of x-coords. */ - shape->rows[i]->xs = (int *)malloc(alloc_pts * sizeof(int)); - /* If there is an allocation error... */ - if(shape->rows[i]->xs == (int *)NULL){ - /* Deallocate memory alloated by this routine to this point. */ - for(j = 0; j < i; j++){ - free(shape->rows[j]->xs); - free(shape->rows[j]); - } - free(shape->rows[i]); - free(shape->rows); - free(shape); - fprintf(stderr, - "ERROR : alloc_shape : malloc : shape->rows[i]->xs\n"); - return(-253); - } + shape->rows[i]->xs = (int *)g_malloc(alloc_pts * sizeof(int)); /* Initialize the current row structure's attributes. */ shape->rows[i]->y = y; @@ -188,15 +150,15 @@ void free_shape(SHAPE *shape) /* Foreach allocated row in the shape ... */ for(i = 0; i < shape->alloc; i++){ /* Deallocate the current row's list of x-coords. */ - free(shape->rows[i]->xs); + g_free(shape->rows[i]->xs); /* Deallocate the current row structure. */ - free(shape->rows[i]); + g_free(shape->rows[i]); } /* Deallocate the list of row pointers. */ - free(shape->rows); + g_free(shape->rows); /* Deallocate the shape structure. */ - free(shape); + g_free(shape); } /************************************************************************* @@ -260,7 +222,7 @@ int shape_from_contour(SHAPE **oshape, const int *contour_x, if(row->npts >= row->alloc){ /* This should never happen becuase we have allocated */ /* based on shape bounding limits. */ - free(shape); + g_free(shape); fprintf(stderr, "ERROR : shape_from_contour : row overflow\n"); return(-260); diff --git a/libfprint/nbis/mindtct/sort.c b/libfprint/nbis/mindtct/sort.c index 9080ce0d..5343639f 100644 --- a/libfprint/nbis/mindtct/sort.c +++ b/libfprint/nbis/mindtct/sort.c @@ -89,11 +89,7 @@ int sort_indices_int_inc(int **optr, int *ranks, const int num) int i; /* Allocate list of sequential indices. */ - order = (int *)malloc(num * sizeof(int)); - if(order == (int *)NULL){ - fprintf(stderr, "ERROR : sort_indices_int_inc : malloc : order\n"); - return(-390); - } + order = (int *)g_malloc(num * sizeof(int)); /* Initialize list of sequential indices. */ for(i = 0; i < num; i++) order[i] = i; diff --git a/libfprint/nbis/mindtct/util.c b/libfprint/nbis/mindtct/util.c index 1662e629..5ae11990 100644 --- a/libfprint/nbis/mindtct/util.c +++ b/libfprint/nbis/mindtct/util.c @@ -178,24 +178,9 @@ int minmaxs(int **ominmax_val, int **ominmax_type, int **ominmax_i, /* min or max. */ minmax_alloc = num - 2; /* Allocate the buffers. */ - minmax_val = (int *)malloc(minmax_alloc * sizeof(int)); - if(minmax_val == (int *)NULL){ - fprintf(stderr, "ERROR : minmaxs : malloc : minmax_val\n"); - return(-290); - } - minmax_type = (int *)malloc(minmax_alloc * sizeof(int)); - if(minmax_type == (int *)NULL){ - free(minmax_val); - fprintf(stderr, "ERROR : minmaxs : malloc : minmax_type\n"); - return(-291); - } - minmax_i = (int *)malloc(minmax_alloc * sizeof(int)); - if(minmax_i == (int *)NULL){ - free(minmax_val); - free(minmax_type); - fprintf(stderr, "ERROR : minmaxs : malloc : minmax_i\n"); - return(-292); - } + minmax_val = (int *)g_malloc(minmax_alloc * sizeof(int)); + minmax_type = (int *)g_malloc(minmax_alloc * sizeof(int)); + minmax_i = (int *)g_malloc(minmax_alloc * sizeof(int)); /* Initialize number of min/max to 0. */ minmax_num = 0; From 689aff023253e4ca970c9f76f9e4209188175d3d Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 3 Jul 2019 23:29:05 +0200 Subject: [PATCH 15/73] lib: Major rewrite of the libfprint core and API This is a rewrite of the core based on GObject and Gio. This commit breaks the build in a lot of ways, but basic functionality will start working again with the next commits. --- doc/advanced-topics.xml | 30 +- doc/getting-started.xml | 4 +- doc/libfprint-docs.xml | 44 +- doc/libfprint-sections.txt | 420 +-- doc/libfprint-sections.txt-new-manual | 118 + doc/meson.build | 39 +- libfprint/drivers_api.h | 13 +- libfprint/fp-context.c | 364 +++ libfprint/fp-context.h | 52 + libfprint/fp-device.c | 2574 +++++++++++++++++++ libfprint/fp-device.h | 255 ++ libfprint/fp-image-device.c | 795 ++++++ libfprint/{fpi-data.h => fp-image-device.h} | 23 +- libfprint/fp-image.c | 610 +++++ libfprint/fp-image.h | 59 + libfprint/fp-print.c | 1118 ++++++++ libfprint/fp-print.h | 101 + libfprint/fp_internal.h | 186 +- libfprint/fpi-assembling.c | 687 ++--- libfprint/fpi-assembling.h | 65 +- libfprint/fpi-async.c | 706 ----- libfprint/fpi-async.h | 39 - libfprint/fpi-context.h | 33 + libfprint/fpi-core.c | 730 ------ libfprint/fpi-core.h | 118 - libfprint/fpi-data.c | 340 --- libfprint/fpi-dev-img.c | 660 ----- libfprint/fpi-dev-img.h | 101 - libfprint/fpi-dev.c | 150 -- libfprint/fpi-dev.h | 47 - libfprint/fpi-device.h | 252 ++ libfprint/fpi-image-device.h | 118 + libfprint/fpi-image.h | 83 + libfprint/fpi-img-pixman.c | 75 - libfprint/fpi-img.c | 682 ----- libfprint/fpi-img.h | 85 - libfprint/fpi-poll.c | 485 ---- libfprint/fpi-poll.h | 51 - libfprint/fpi-print.h | 50 + libfprint/fpi-ssm.c | 312 ++- libfprint/fpi-ssm.h | 82 +- libfprint/fpi-sync.c | 690 ----- libfprint/fpi-usb-transfer.c | 522 ++++ libfprint/fpi-usb-transfer.h | 157 ++ libfprint/fpi-usb.c | 236 -- libfprint/fpi-usb.h | 70 - libfprint/fprint-list-supported-devices.c | 49 +- libfprint/fprint-list-udev-rules.c | 80 +- libfprint/fprint.h | 412 +-- libfprint/libfprint.ver | 3 + libfprint/meson.build | 110 +- meson.build | 28 +- meson_options.txt | 4 + 53 files changed, 8358 insertions(+), 6759 deletions(-) create mode 100644 doc/libfprint-sections.txt-new-manual create mode 100644 libfprint/fp-context.c create mode 100644 libfprint/fp-context.h create mode 100644 libfprint/fp-device.c create mode 100644 libfprint/fp-device.h create mode 100644 libfprint/fp-image-device.c rename libfprint/{fpi-data.h => fp-image-device.h} (57%) create mode 100644 libfprint/fp-image.c create mode 100644 libfprint/fp-image.h create mode 100644 libfprint/fp-print.c create mode 100644 libfprint/fp-print.h delete mode 100644 libfprint/fpi-async.c delete mode 100644 libfprint/fpi-async.h create mode 100644 libfprint/fpi-context.h delete mode 100644 libfprint/fpi-core.c delete mode 100644 libfprint/fpi-core.h delete mode 100644 libfprint/fpi-data.c delete mode 100644 libfprint/fpi-dev-img.c delete mode 100644 libfprint/fpi-dev-img.h delete mode 100644 libfprint/fpi-dev.c delete mode 100644 libfprint/fpi-dev.h create mode 100644 libfprint/fpi-device.h create mode 100644 libfprint/fpi-image-device.h create mode 100644 libfprint/fpi-image.h delete mode 100644 libfprint/fpi-img-pixman.c delete mode 100644 libfprint/fpi-img.c delete mode 100644 libfprint/fpi-img.h delete mode 100644 libfprint/fpi-poll.c delete mode 100644 libfprint/fpi-poll.h create mode 100644 libfprint/fpi-print.h delete mode 100644 libfprint/fpi-sync.c create mode 100644 libfprint/fpi-usb-transfer.c create mode 100644 libfprint/fpi-usb-transfer.h delete mode 100644 libfprint/fpi-usb.c delete mode 100644 libfprint/fpi-usb.h diff --git a/doc/advanced-topics.xml b/doc/advanced-topics.xml index 5af6f717..18a12897 100644 --- a/doc/advanced-topics.xml +++ b/doc/advanced-topics.xml @@ -60,21 +60,18 @@ In summary, libfprint represents fingerprints in several internal structures and each representation will offer you a way of determining the - driver ID and devtype of the print in + driver and device ID of the print in question. Prints are only compatible if the driver ID and devtypes match. libfprint does offer you some "is this print compatible?" helper functions, so you don't have to worry about these details too much. - - Driver IDs + + Driver - Each driver is assigned a unique ID by the project maintainer. These - assignments are - - documented in the sources and will never change. + Each driver is assigned a unique string identifier by the project maintainer. @@ -89,22 +86,23 @@ - - Device types + + Device ID - Internally, the driver behind a device assigns a 32-bit - devtype identifier to the device. This cannot be used as a unique - ID for a specific device as many devices under the same range may share - the same devtype. The devtype may even be 0 in all cases. + Internally, the behind a device assigns a string identifier to the device + This cannot be used as a unique ID for a specific device as many devices + under the same range may share the same devtype. The device ID may even + be the same string in all cases. It is guaranteed to have a non-zero length + and be a valid file name. It defaults to "0". - The only reason you may be interested in retrieving the devtype for a + The only reason you may be interested in retrieving the device ID for a device is for the purpose of checking if some print data is compatible - with a device. libfprint uses the devtype as one way of checking that the + with a device. libfprint uses the device ID as one way of checking that the print you are verifying is compatible with the device in question - the - devtypes must be equal. This effectively allows drivers to support more + device ID must be equal. This effectively allows drivers to support more than one type of device where the data from each one is not compatible with the other. Note that libfprint does provide you with helper functions to determine whether a print is compatible with a device, so under most diff --git a/doc/getting-started.xml b/doc/getting-started.xml index 8ed8592b..369e5639 100644 --- a/doc/getting-started.xml +++ b/doc/getting-started.xml @@ -13,12 +13,12 @@ Usually the first thing you want to do is determine which fingerprint - devices are present. This is done through device discovery. + devices are present. This is done using the FpContext object. Once you have found a device you would like to operate, you should open it. - Refer to device operations. This section also details enrollment, + Refer to device operations. This section also details enrollment, image capture, and verification. diff --git a/doc/libfprint-docs.xml b/doc/libfprint-docs.xml index 52041adf..b866aab0 100644 --- a/doc/libfprint-docs.xml +++ b/doc/libfprint-docs.xml @@ -25,39 +25,43 @@ Library API Documentation - - - - - - - + + + + + Writing Drivers - - Logging, and async machinery - - - + + Device methods for drivers + + - - Device and driver structures - - - - + + USB and State Machine helpers + + + Image manipulation - + - + + Print handling + + + + + Listing drivers + + diff --git a/doc/libfprint-sections.txt b/doc/libfprint-sections.txt index cc9b3aec..814ab804 100644 --- a/doc/libfprint-sections.txt +++ b/doc/libfprint-sections.txt @@ -1,125 +1,191 @@ -

-fprint.h -events -Initialisation and events handling -LIBFPRINT_DEPRECATED -fp_init -fp_exit -fp_pollfd -fp_handle_events_timeout -fp_handle_events -fp_get_next_timeout -fp_get_pollfds -fp_pollfd_added_cb -fp_pollfd_removed_cb -fp_set_pollfd_notifiers +drivers_api +
-fprint.h -discovery -Device discovery -fp_dscv_dev -fp_discover_devs -fp_dscv_devs_free -fp_dscv_dev_get_driver -fp_dscv_dev_get_devtype -fp_dscv_dev_get_driver_id -fp_dscv_dev_supports_print_data +fp-context +FpContext +FP_TYPE_CONTEXT +FpContextClass +fp_context_new +fp_context_enumerate +fp_context_get_devices +FpContext
-fprint.h -drv -fp_driver -fp_driver_get_name -fp_driver_get_full_name -fp_driver_get_driver_id -fp_driver_get_scan_type -fp_driver_supports_imaging +fp-device +FP_TYPE_DEVICE +FP_DEVICE_RETRY +FP_DEVICE_ERROR +FpDeviceType +FpScanType +FpDeviceRetry +FpDeviceError +fp_device_retry_quark +fp_device_error_quark +FpEnrollProgress +fp_device_get_driver +fp_device_get_device_id +fp_device_get_name +fp_device_get_scan_type +fp_device_get_nr_enroll_stages +fp_device_has_storage +fp_device_supports_identify +fp_device_supports_capture +fp_device_open +fp_device_close +fp_device_enroll +fp_device_verify +fp_device_identify +fp_device_capture +fp_device_delete_print +fp_device_list_prints +fp_device_open_finish +fp_device_close_finish +fp_device_enroll_finish +fp_device_verify_finish +fp_device_identify_finish +fp_device_capture_finish +fp_device_delete_print_finish +fp_device_list_prints_finish +fp_device_open_sync +fp_device_close_sync +fp_device_enroll_sync +fp_device_verify_sync +fp_device_identify_sync +fp_device_capture_sync +fp_device_delete_print_sync +fp_device_list_prints_sync +FpDevice
-fprint.h -dev -fp_dev -fp_scan_type -fp_capture_result -fp_enroll_result -fp_verify_result - -fp_dev_get_driver -fp_dev_get_nr_enroll_stages -fp_dev_get_devtype -fp_dev_supports_print_data -fp_dev_supports_imaging -fp_dev_supports_identification -fp_dev_get_img_width -fp_dev_get_img_height - -fp_operation_stop_cb -fp_img_operation_cb -fp_dev_open_cb -fp_enroll_stage_cb -fp_identify_cb - -fp_dev_open -fp_async_dev_open - -fp_dev_close -fp_async_dev_close - -fp_enroll_finger -fp_enroll_finger_img -fp_async_enroll_start -fp_async_enroll_stop - -fp_verify_finger -fp_verify_finger_img -fp_async_verify_start -fp_async_verify_stop - -fp_identify_finger -fp_identify_finger_img -fp_async_identify_start -fp_async_identify_stop - -fp_dev_img_capture -fp_async_capture_start -fp_async_capture_stop -
- -
-fprint.h -print_data -fp_finger -fp_print_data -fp_print_data_get_data -fp_print_data_from_data -fp_print_data_free -fp_print_data_get_driver_id -fp_print_data_get_devtype -
- -
-fprint.h -img -fp_img -fp_minutia -fp_img_free -fp_img_get_height -fp_img_get_width -fp_img_get_data -fp_img_save_to_file -fp_img_standardize -fp_img_binarize -fp_img_get_minutiae +fp-image +FP_TYPE_IMAGE +FpMinutia +fp_image_new +fp_image_get_width +fp_image_get_height +fp_image_get_ppmm +fp_image_get_minutiae +fp_image_detect_minutiae +fp_image_detect_minutiae_finish +fp_image_get_data +fp_image_get_binarized fp_minutia_get_coords +FpImage +
+ +
+fp-image-device +FP_TYPE_IMAGE_DEVICE +FpImageDevice +
+ +
+fp-print +FP_TYPE_PRINT +FpFinger +FpPrint +fp_print_new +fp_print_new_from_data +fp_print_to_data +fp_print_get_driver +fp_print_get_device_id +fp_print_get_device_stored +fp_print_get_image +fp_print_get_finger +fp_print_get_username +fp_print_get_description +fp_print_get_enroll_date +fp_print_set_finger +fp_print_set_username +fp_print_set_description +fp_print_set_enroll_date +fp_print_compatible +fp_print_equal +fp_print_serialize +fp_print_deserialize +
+ +
+fpi-assembling +fpi_frame +fpi_frame_asmbl_ctx +fpi_do_movement_estimation +fpi_assemble_frames +fpi_line_asmbl_ctx +fpi_assemble_lines +
+ +
+fpi-context +fpi_get_driver_types +
+ +
+fpi-device +FpDeviceClass +FpTimeoutFunc +FpDeviceAction +FpIdEntry +fpi_device_get_usb_device +fpi_device_get_virtual_env +fpi_device_get_current_action +fpi_device_retry_new +fpi_device_error_new +fpi_device_retry_new_msg +fpi_device_error_new_msg +fpi_device_get_driver_data +fpi_device_get_enroll_data +fpi_device_get_capture_data +fpi_device_get_verify_data +fpi_device_get_identify_data +fpi_device_get_delete_data +fpi_device_get_cancellable +fpi_device_action_is_cancelled +fpi_device_add_timeout +fpi_device_set_nr_enroll_stages +fpi_device_set_scan_type +fpi_device_action_error +fpi_device_probe_complete +fpi_device_open_complete +fpi_device_close_complete +fpi_device_enroll_complete +fpi_device_verify_complete +fpi_device_identify_complete +fpi_device_capture_complete +fpi_device_delete_complete +fpi_device_enroll_progress +
+ +
+fpi-image +FpiImageFlags +FpImage +fpi_std_sq_dev +fpi_mean_sq_diff_norm +fpi_image_resize +
+ +
+fpi-image-device +FpImageDevice +FpImageDeviceState +FpImageDeviceClass +fpi_image_device_session_error +fpi_image_device_open_complete +fpi_image_device_close_complete +fpi_image_device_activate_complete +fpi_image_device_deactivate_complete +fpi_image_device_report_finger_status +fpi_image_device_image_captured +fpi_image_device_retry_scan
-fpi-log.h fpi-log fp_dbg fp_info @@ -130,121 +196,57 @@ BUG
-fpi-ssm.h -fpi-ssm -fpi_ssm -ssm_completed_fn -ssm_handler_fn +fpi-print +FpPrintType +FpiMatchResult +fpi_print_add_print +fpi_print_set_type +fpi_print_set_device_stored +fpi_print_add_from_image +fpi_print_bz3_match +
+
+fpi-ssm +FpiSsmCompletedCallback +FpiSsmHandlerCallback fpi_ssm_new fpi_ssm_free fpi_ssm_start fpi_ssm_start_subsm - fpi_ssm_next_state -fpi_ssm_next_state_timeout_cb fpi_ssm_jump_to_state fpi_ssm_mark_completed fpi_ssm_mark_failed fpi_ssm_get_user_data fpi_ssm_get_error +fpi_ssm_dup_error fpi_ssm_get_cur_state +fpi_ssm_next_state_timeout_cb +fpi_ssm_usb_transfer_cb +FpiSsm
-fpi-poll.h -fpi-poll -fpi_timeout -fpi_timeout_fn -fpi_timeout_add -fpi_timeout_set_name -fpi_timeout_cancel +fpi-usb-transfer +FPI_USB_ENDPOINT_IN +FPI_USB_ENDPOINT_OUT +FpiUsbTransferCallback +FpiTransferType +FpiUsbTransfer +fpi_usb_transfer_new +fpi_usb_transfer_ref +fpi_usb_transfer_unref +fpi_usb_transfer_set_short_error +fpi_usb_transfer_fill_bulk +fpi_usb_transfer_fill_bulk_full +fpi_usb_transfer_fill_control +fpi_usb_transfer_fill_interrupt +fpi_usb_transfer_fill_interrupt_full +fpi_usb_transfer_submit +fpi_usb_transfer_submit_sync + +FPI_TYPE_USB_TRANSFER +fpi_usb_transfer_get_type
-
-fpi-dev.h -fpi-dev -fp_img_dev - -FP_DEV -FP_IMG_DEV -fp_dev_set_instance_data -FP_INSTANCE_DATA - -fpi_dev_get_usb_dev -fpi_dev_get_verify_data -fpi_dev_set_nr_enroll_stages -
- -
-fpi-dev-img.h -fpi-dev-img -fp_imgdev_action -fp_imgdev_state -fp_imgdev_enroll_state - -fpi_imgdev_abort_scan -fpi_imgdev_activate_complete -fpi_imgdev_close_complete -fpi_imgdev_deactivate_complete -fpi_imgdev_get_action -fpi_imgdev_get_action_result -fpi_imgdev_get_action_state -fpi_imgdev_image_captured -fpi_imgdev_open_complete -fpi_imgdev_report_finger_status -fpi_imgdev_session_error -fpi_imgdev_set_action_result -
- -
-fpi-core.h -fpi-core -usb_id -fp_driver_type -
- -
-fpi-core.h -fpi-core-img -FpiImgDriverFlags -fp_img_driver -
- -
-fpi-img.h -fpi-img -FpiImgFlags - -fpi_img_new -fpi_img_new_for_imgdev -fpi_img_realloc -fpi_img_resize - -fpi_std_sq_dev -fpi_mean_sq_diff_norm -
- -
-fpi-assembling.h -fpi-assembling -fpi_frame -fpi_frame_asmbl_ctx -fpi_line_asmbl_ctx - -fpi_do_movement_estimation -fpi_assemble_frames -fpi_assemble_lines -
- -
-fpi-usb.h -fpi-usb -fpi_usb_transfer - -fpi_usb_transfer_cb_fn -fpi_usb_alloc -fpi_usb_fill_bulk_transfer -fpi_usb_submit_transfer -fpi_usb_cancel_transfer -
diff --git a/doc/libfprint-sections.txt-new-manual b/doc/libfprint-sections.txt-new-manual new file mode 100644 index 00000000..857425b9 --- /dev/null +++ b/doc/libfprint-sections.txt-new-manual @@ -0,0 +1,118 @@ + +
+fprint.h +context +Device discovery and hotplugging +FP_TYPE_CONTEXT +FpContext +fp_context_new +fp_context_enumerate +fp_context_get_devices +
+ + +
+fprint.h +device +Device +FP_TYPE_DEVICE +FpDevice +FpDeviceType +FpScanType +FpDeviceRetry +FpDeviceError +FP_DEVICE_ERROR +FP_DEVICE_RETRY +fp_device_get_driver +fp_device_get_device_id +fp_device_get_name +fp_device_get_scan_type + +fp_device_open +fp_device_open_finish +fp_device_open_sync + +fp_device_close +fp_device_close_finish +fp_device_close_sync + +fp_device_enroll +fp_device_enroll_finish +fp_device_enroll_sync + +fp_device_identify +fp_device_identify_finish +fp_device_identify_sync + +fp_device_capture +fp_device_capture_finish +fp_device_capture_sync + +fp_device_verify +fp_device_verify_finish +fp_device_verify_sync + +_fp_device_get_cancellable +
+ + +
+fprint.h +print +Fingerprint handling +FpPrint +fp_print_new +
+ + +
+fprint.h +image +Image handling +FP_TYPE_IMAGE +FpImage +fp_image_new +fp_image_detect_minutiae +fp_image_detect_minutiae_finish +fp_image_device_new +fp_image_get_binarized +fp_image_get_data +fp_image_get_height +fp_image_get_minutiae +fp_image_get_ppmm +fp_image_get_width +
+ + +
+internal-image-device +drivers_api.h +Base class for image devices +FpImageDevice +FpImageDeviceClass +FpImageDeviceState +
+ +
+internal-usb-transfers +drivers_api.h +USB Transfers +FpUsbTransfer +fp_usb_transfer_fill_bulk +fp_usb_transfer_fill_bulk_full +fp_usb_transfer_fill_control +fp_usb_transfer_fill_interrupt +fp_usb_transfer_fill_interrupt_full +fp_usb_transfer_get_type +fp_usb_transfer_new +fp_usb_transfer_ref +fp_usb_transfer_set_short_error +fp_usb_transfer_submit +fp_usb_transfer_submit_sync +fp_usb_transfer_unref +FpUsbTransferCallback +FP_USB_ENDPOINT_IN +FP_USB_ENDPOINT_OUT +
+ + diff --git a/doc/meson.build b/doc/meson.build index 37d515d8..54186677 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -2,41 +2,13 @@ subdir('xml') private_headers = [ 'config.h', - - 'aeslib.h', - 'assembling.h', - 'fp_internal.h', 'nbis-helpers.h', - 'fpi-async.h', - 'fpi-data.h', + 'fprint.h', + 'fp_internal.h', - # Drivers - 'aes1660.h', - 'aes2501.h', - 'aes2550.h', - 'aes2660.h', - 'aes3k.h', - 'aesx660.h', - 'driver_ids.h', - 'elan.h', - 'upek_proto.h', - 'upeksonly.h', - 'upektc.h', - 'upektc_img.h', - 'vfs0050.h', - 'vfs301_proto_fragments.h', - 'vfs301_proto.h', - 'vfs5011_proto.h', - - # NBIS - 'morph.h', - 'sunrast.h', - 'bozorth.h', - 'defs.h', - 'log.h', - 'bz_array.h', - 'lfs.h', - 'mytime.h', + # Subdirectories to ignore + 'drivers', + 'nbis', ] html_images = [ @@ -59,6 +31,7 @@ gnome.gtkdoc('libfprint', content_files: content_files, expand_content_files: expand_content_files, scan_args: [ + #'--rebuild-sections', '--ignore-decorators=API_EXPORTED', '--ignore-headers=' + ' '.join(private_headers), ], diff --git a/libfprint/drivers_api.h b/libfprint/drivers_api.h index 7867e346..bb401cd3 100644 --- a/libfprint/drivers_api.h +++ b/libfprint/drivers_api.h @@ -23,17 +23,12 @@ #include -#include "fprint.h" +#include "fp_internal.h" + #include "fpi-log.h" -#include "fpi-dev.h" -#include "fpi-dev-img.h" -#include "fpi-core.h" +#include "fpi-usb-transfer.h" #include "fpi-ssm.h" -#include "fpi-poll.h" -#include "fpi-dev.h" -#include "fpi-usb.h" -#include "fpi-img.h" #include "fpi-assembling.h" -#include "drivers/driver_ids.h" +#include "fpi-image-device.h" #endif diff --git a/libfprint/fp-context.c b/libfprint/fp-context.c new file mode 100644 index 00000000..74dda51f --- /dev/null +++ b/libfprint/fp-context.c @@ -0,0 +1,364 @@ +/* + * FpContext - A FPrint context + * Copyright (C) 2019 Benjamin Berg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define FP_COMPONENT "context" +#include + +#include "fpi-context.h" +#include "fpi-device.h" +#include + +/** + * SECTION: fp-context + * @title: FpContext + * @short_description: Discover fingerprint devices + * + * The #FpContext allows you to discover fingerprint scanning hardware. This + * is the starting point when integrating libfprint into your software. + * + * The device-added and device-removed signals allow you to handle devices + * that may be hotplugged at runtime. + */ + +typedef struct +{ + GUsbContext *usb_ctx; + GCancellable *cancellable; + + gint pending_devices; + gboolean enumerated; + + GArray *drivers; + GPtrArray *devices; +} FpContextPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (FpContext, fp_context, G_TYPE_OBJECT) + +enum { + DEVICE_ADDED_SIGNAL, + DEVICE_REMOVED_SIGNAL, + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + +static void +async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GError) error = NULL; + FpDevice *device; + FpContext *context; + FpContextPrivate *priv; + + device = (FpDevice *) g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), res, &error); + if (!device) + { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + context = FP_CONTEXT (user_data); + priv = fp_context_get_instance_private (context); + priv->pending_devices--; + g_message ("Ignoring device due to initialization error: %s", error->message); + return; + } + + context = FP_CONTEXT (user_data); + priv = fp_context_get_instance_private (context); + priv->pending_devices--; + g_ptr_array_add (priv->devices, device); + g_signal_emit (context, signals[DEVICE_ADDED_SIGNAL], 0, device); +} + +static void +usb_device_added_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx) +{ + FpContextPrivate *priv = fp_context_get_instance_private (self); + GType found_driver = G_TYPE_NONE; + const FpIdEntry *found_entry = NULL; + gint found_score = 0; + gint i; + guint16 pid, vid; + + pid = g_usb_device_get_pid (device); + vid = g_usb_device_get_vid (device); + + /* Find the best driver to handle this USB device. */ + for (i = 0; i < priv->drivers->len; i++) + { + GType driver = g_array_index (priv->drivers, GType, i); + FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver)); + const FpIdEntry *entry; + + if (cls->type != FP_DEVICE_TYPE_USB) + { + g_type_class_unref (cls); + continue; + } + + for (entry = cls->id_table; entry->pid; entry++) + { + gint driver_score = 50; + + if (entry->pid != pid || entry->vid != vid) + continue; + + if (cls->usb_discover) + driver_score = cls->usb_discover (device); + + /* Is this driver better than the one we had? */ + if (driver_score <= found_score) + continue; + + found_score = driver_score; + found_driver = driver; + found_entry = entry; + } + + g_type_class_unref (cls); + } + + if (found_driver == G_TYPE_NONE) + { + g_debug ("No driver found for USB device %04X:%04X", pid, vid); + return; + } + + priv->pending_devices++; + g_async_initable_new_async (found_driver, + G_PRIORITY_LOW, + priv->cancellable, + async_device_init_done_cb, + self, + "fp-usb-device", device, + "fp-driver-data", found_entry->driver_data, + NULL); +} + +static void +usb_device_removed_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx) +{ + FpContextPrivate *priv = fp_context_get_instance_private (self); + gint i; + + /* Do the lazy way and just look at each device. */ + for (i = 0; i < priv->devices->len; i++) + { + FpDevice *dev = g_ptr_array_index (priv->devices, i); + FpDeviceClass *cls = FP_DEVICE_GET_CLASS (dev); + + if (cls->type != FP_DEVICE_TYPE_USB) + continue; + + if (fpi_device_get_usb_device (dev) == device) + { + g_signal_emit (self, signals[DEVICE_REMOVED_SIGNAL], 0, dev); + g_ptr_array_remove_index_fast (priv->devices, i); + + return; + } + } +} + +static void +fp_context_finalize (GObject *object) +{ + FpContext *self = (FpContext *) object; + FpContextPrivate *priv = fp_context_get_instance_private (self); + + g_clear_pointer (&priv->devices, g_ptr_array_unref); + + g_cancellable_cancel (priv->cancellable); + g_clear_object (&priv->cancellable); + g_clear_pointer (&priv->drivers, g_array_unref); + g_clear_object (&priv->usb_ctx); + + G_OBJECT_CLASS (fp_context_parent_class)->finalize (object); +} + +static void +fp_context_class_init (FpContextClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = fp_context_finalize; + + /** + * FpContext::device-added: + * @context: the #FpContext instance that emitted the signal + * @device: A #FpDevice + * + * This signal is emitted when a fingerprint reader is added. + **/ + signals[DEVICE_ADDED_SIGNAL] = g_signal_new ("device-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (FpContextClass, device_added), + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + FP_TYPE_DEVICE); + + /** + * FpContext::device-removed: + * @context: the #FpContext instance that emitted the signal + * @device: A #FpDevice + * + * This signal is emitted when a fingerprint reader is removed. + **/ + signals[DEVICE_REMOVED_SIGNAL] = g_signal_new ("device-removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (FpContextClass, device_removed), + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + FP_TYPE_DEVICE); +} + +static void +fp_context_init (FpContext *self) +{ + g_autoptr(GError) error = NULL; + FpContextPrivate *priv = fp_context_get_instance_private (self); + + priv->drivers = g_array_new (TRUE, FALSE, sizeof (GType)); + fpi_get_driver_types (priv->drivers); + + priv->devices = g_ptr_array_new_with_free_func (g_object_unref); + + priv->cancellable = g_cancellable_new (); + priv->usb_ctx = g_usb_context_new (&error); + if (!priv->usb_ctx) + { + fp_warn ("Could not initialise USB Subsystem: %s", error->message); + } + else + { + g_usb_context_set_debug (priv->usb_ctx, G_LOG_LEVEL_INFO); + g_signal_connect_object (priv->usb_ctx, + "device-added", + G_CALLBACK (usb_device_added_cb), + self, + G_CONNECT_SWAPPED); + g_signal_connect_object (priv->usb_ctx, + "device-removed", + G_CALLBACK (usb_device_removed_cb), + self, + G_CONNECT_SWAPPED); + } +} + +/** + * fp_context_new: + * + * Create a new #FpContext. + * + * Returns: (transfer full): a newly created #FpContext + */ +FpContext * +fp_context_new (void) +{ + return g_object_new (FP_TYPE_CONTEXT, NULL); +} + +/** + * fp_context_enumerate: + * @context: a #FpContext + * + * Enumerate all devices. You should call this function exactly once + * at startup. Please note that it iterates the mainloop until all + * devices are enumerated. + */ +void +fp_context_enumerate (FpContext *context) +{ + FpContextPrivate *priv = fp_context_get_instance_private (context); + gint i; + + g_return_if_fail (FP_IS_CONTEXT (context)); + + if (priv->enumerated) + return; + + priv->enumerated = TRUE; + + /* USB devices are handled from callbacks */ + g_usb_context_enumerate (priv->usb_ctx); + + /* Handle Virtual devices based on environment variables */ + for (i = 0; i < priv->drivers->len; i++) + { + GType driver = g_array_index (priv->drivers, GType, i); + FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver)); + const FpIdEntry *entry; + + if (cls->type != FP_DEVICE_TYPE_VIRTUAL) + continue; + + for (entry = cls->id_table; entry->pid; entry++) + { + const gchar *val; + + val = g_getenv (entry->virtual_envvar); + if (!val || val[0] == '\0') + continue; + + g_debug ("Found virtual environment device: %s, %s", entry->virtual_envvar, val); + priv->pending_devices++; + g_async_initable_new_async (driver, + G_PRIORITY_LOW, + priv->cancellable, + async_device_init_done_cb, + context, + "fp-environ", val, + "fp-driver-data", entry->driver_data, + NULL); + g_debug ("created"); + } + + g_type_class_unref (cls); + } + + while (priv->pending_devices) + g_main_context_iteration (NULL, TRUE); +} + +/** + * fp_context_get_devices: + * @context: a #FpContext + * + * Get all devices. fp_context_enumerate() will be called as needed. + * + * Returns: (transfer none) (element-type FpDevice): a new #GPtrArray of #GUsbDevice's. + */ +GPtrArray * +fp_context_get_devices (FpContext *context) +{ + FpContextPrivate *priv = fp_context_get_instance_private (context); + + g_return_val_if_fail (FP_IS_CONTEXT (context), NULL); + + fp_context_enumerate (context); + + return priv->devices; +} diff --git a/libfprint/fp-context.h b/libfprint/fp-context.h new file mode 100644 index 00000000..aeaeca07 --- /dev/null +++ b/libfprint/fp-context.h @@ -0,0 +1,52 @@ +/* + * FpContext - A FPrint context + * Copyright (C) 2019 Benjamin Berg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "fp-device.h" + +G_BEGIN_DECLS + +#define FP_TYPE_CONTEXT (fp_context_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FpContext, fp_context, FP, CONTEXT, GObject) + +/** + * FpContextClass: + * @device_added: Called when a new device is added + * @device_removed: Called when a device is removed + * + * Class structure for #FpContext instances. + */ +struct _FpContextClass +{ + GObjectClass parent_class; + + void (*device_added) (FpContext *context, + FpDevice *device); + void (*device_removed) (FpContext *context, + FpDevice *device); +}; + +FpContext *fp_context_new (void); + +void fp_context_enumerate (FpContext *context); + +GPtrArray *fp_context_get_devices (FpContext *context); + +G_END_DECLS diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c new file mode 100644 index 00000000..fe477982 --- /dev/null +++ b/libfprint/fp-device.c @@ -0,0 +1,2574 @@ +/* + * FpDevice - A fingerprint reader device + * Copyright (C) 2019 Benjamin Berg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define FP_COMPONENT "device" +#include "fpi-log.h" + +#include "fpi-device.h" + +/** + * SECTION: fp-device + * @title: FpDevice + * @short_description: Fingerprint device handling + * + * The #FpDevice object allows you to interact with fingerprint readers. + * Befor doing any other operation you need to fp_device_open() the device + * and after you are done you need to fp_device_close() it again. + */ + +/** + * SECTION: fpi-device + * @title: Internal FpDevice + * @short_description: Internal device routines + * + * The methods that are availabe for drivers to manipulate a device. See + * #FpDeviceClass for more information. Also note that most of these are + * not relevant for image based devices, see #FpImageDeviceClass in that + * case. + * + * Also see the public #FpDevice routines. + */ + +typedef struct +{ + FpDeviceType type; + + union + { + GUsbDevice *usb_device; + const gchar *virtual_env; + }; + + gboolean is_open; + + gchar *device_id; + gchar *device_name; + FpScanType scan_type; + + guint64 driver_data; + + gint nr_enroll_stages; + GSList *sources; + + /* We always make sure that only one task is run at a time. */ + FpDeviceAction current_action; + GTask *current_task; + GAsyncReadyCallback current_user_cb; + gulong current_cancellable_id; + GSource *current_idle_cancel_source; + + /* State for tasks */ + gboolean wait_for_finger; +} FpDevicePrivate; + +static void fp_device_async_initable_iface_init (GAsyncInitableIface *iface); + +G_DEFINE_TYPE_EXTENDED (FpDevice, fp_device, G_TYPE_OBJECT, G_TYPE_FLAG_ABSTRACT, + G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, + fp_device_async_initable_iface_init) + G_ADD_PRIVATE (FpDevice)) + +enum { + PROP_0, + PROP_DRIVER, + PROP_DEVICE_ID, + PROP_NAME, + PROP_NR_ENROLL_STAGES, + PROP_SCAN_TYPE, + PROP_FPI_ENVIRON, + PROP_FPI_USB_DEVICE, + PROP_FPI_DRIVER_DATA, + N_PROPS +}; + +static GParamSpec *properties[N_PROPS]; + +typedef struct +{ + FpPrint *print; + + FpEnrollProgress enroll_progress_cb; + gpointer enroll_progress_data; + GDestroyNotify enroll_progress_destroy; +} FpEnrollData; + +static void +enroll_data_free (gpointer free_data) +{ + FpEnrollData *data = free_data; + + if (data->enroll_progress_destroy) + data->enroll_progress_destroy (data->enroll_progress_data); + data->enroll_progress_data = NULL; + g_clear_object (&data->print); + g_free (data); +} + +/** + * fp_device_retry_quark: + * + * Return value: Quark representing a retryable error. + **/ +G_DEFINE_QUARK (fp - device - retry - quark, fp_device_retry) + +/** + * fp_device_error_quark: + * + * Return value: Quark representing a device error. + **/ +G_DEFINE_QUARK (fp - device - error - quark, fp_device_error) + +/** + * fpi_device_retry_new: + * @error: The #FpDeviceRetry error value describing the issue + * + * Create a new retry error code for use with fpi_device_verify_complete() + * and similar calls. + */ +GError * +fpi_device_retry_new (FpDeviceRetry error) +{ + const gchar *msg; + + switch (error) + { + case FP_DEVICE_RETRY_GENERAL: + msg = "Please try again."; + break; + + case FP_DEVICE_RETRY_TOO_SHORT: + msg = "The swipe was too short, please try again."; + break; + + case FP_DEVICE_RETRY_CENTER_FINGER: + msg = "The finger was not centered properly, please try again."; + break; + + case FP_DEVICE_RETRY_REMOVE_FINGER: + msg = "Please try again after removing the finger first."; + break; + + default: + g_warning ("Unsupported error, returning general error instead!"); + error = FP_DEVICE_RETRY_GENERAL; + msg = "Please try again."; + } + + return g_error_new_literal (FP_DEVICE_RETRY, error, msg); +} + +/** + * fpi_device_error_new: + * @error: The #FpDeviceRetry error value describing the issue + * + * Create a new error code for use with fpi_device_verify_complete() and + * similar calls. + */ +GError * +fpi_device_error_new (FpDeviceError error) +{ + const gchar *msg; + + switch (error) + { + case FP_DEVICE_ERROR_GENERAL: + msg = "An unspecified error occured!"; + break; + + case FP_DEVICE_ERROR_NOT_SUPPORTED: + msg = "The operation is not supported on this device!"; + break; + + case FP_DEVICE_ERROR_NOT_OPEN: + msg = "The device needs to be opened first!"; + break; + + case FP_DEVICE_ERROR_ALREADY_OPEN: + msg = "The device has already been opened!"; + break; + + case FP_DEVICE_ERROR_BUSY: + msg = "The device is still busy with another operation, please try again later."; + break; + + case FP_DEVICE_ERROR_PROTO: + msg = "The driver encountered a protocol error with the device."; + break; + + case FP_DEVICE_ERROR_DATA_INVALID: + msg = "Passed (print) data is not valid."; + break; + + case FP_DEVICE_ERROR_DATA_FULL: + msg = "On device storage space is full."; + break; + + case FP_DEVICE_ERROR_DATA_NOT_FOUND: + msg = "Print was not found on the devices storage."; + break; + + default: + g_warning ("Unsupported error, returning general error instead!"); + error = FP_DEVICE_ERROR_GENERAL; + msg = "An unspecified error occured!"; + } + + return g_error_new_literal (FP_DEVICE_ERROR, error, msg); +} + +/** + * fpi_device_retry_new_msg: + * @error: The #FpDeviceRetry error value describing the issue + * @msg: Custom message to use + * + * Create a new retry error code for use with fpi_device_verify_complete() + * and similar calls. + */ +GError * +fpi_device_retry_new_msg (FpDeviceRetry error, const gchar *msg) +{ + return g_error_new_literal (FP_DEVICE_RETRY, error, msg); +} + +/** + * fpi_device_error_new_msg: + * @error: The #FpDeviceRetry error value describing the issue + * @msg: Custom message to use + * + * Create a new error code for use with fpi_device_verify_complete() + * and similar calls. + */ +GError * +fpi_device_error_new_msg (FpDeviceError error, const gchar *msg) +{ + return g_error_new_literal (FP_DEVICE_ERROR, error, msg); +} + +static gboolean +fp_device_cancel_in_idle_cb (gpointer user_data) +{ + FpDevice *self = user_data; + FpDeviceClass *cls = FP_DEVICE_GET_CLASS (self); + FpDevicePrivate *priv = fp_device_get_instance_private (self); + + g_assert (cls->cancel); + g_assert (priv->current_action != FP_DEVICE_ACTION_NONE); + + g_debug ("Idle cancelling on ongoing operation!"); + + priv->current_idle_cancel_source = NULL; + + cls->cancel (self); + + return G_SOURCE_REMOVE; +} + +/* Notify the class that the task was cancelled; this should be connected + * with the GTask as the user_data object for automatic cleanup together + * with the task. */ +static void +fp_device_cancelled_cb (GCancellable *cancellable, FpDevice *self) +{ + FpDeviceClass *cls = FP_DEVICE_GET_CLASS (self); + FpDevicePrivate *priv = fp_device_get_instance_private (self); + + if (cls->cancel) + { + priv->current_idle_cancel_source = g_idle_source_new (); + g_source_set_callback (priv->current_idle_cancel_source, + fp_device_cancel_in_idle_cb, + self, + NULL); + g_source_attach (priv->current_idle_cancel_source, NULL); + g_source_unref (priv->current_idle_cancel_source); + } +} + +static void +fp_device_constructed (GObject *object) +{ + FpDevice *self = (FpDevice *) object; + FpDeviceClass *cls = FP_DEVICE_GET_CLASS (self); + FpDevicePrivate *priv = fp_device_get_instance_private (self); + + priv->type = cls->type; + if (cls->nr_enroll_stages) + priv->nr_enroll_stages = cls->nr_enroll_stages; + priv->scan_type = cls->scan_type; + priv->device_name = g_strdup (cls->full_name); + priv->device_id = g_strdup ("0"); + + G_OBJECT_CLASS (fp_device_parent_class)->constructed (object); +} + +static void +fp_device_finalize (GObject *object) +{ + FpDevice *self = (FpDevice *) object; + FpDevicePrivate *priv = fp_device_get_instance_private (self); + + g_assert (priv->current_action == FP_DEVICE_ACTION_NONE); + g_assert (priv->current_task == NULL); + if (priv->is_open) + g_warning ("User destroyed open device! Not cleaning up properly!"); + + g_slist_free_full (priv->sources, (GDestroyNotify) g_source_destroy); + + g_clear_pointer (&priv->device_id, g_free); + g_clear_pointer (&priv->device_name, g_free); + + G_OBJECT_CLASS (fp_device_parent_class)->finalize (object); +} + +static void +fp_device_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + FpDevice *self = FP_DEVICE (object); + FpDevicePrivate *priv = fp_device_get_instance_private (self); + + switch (prop_id) + { + case PROP_NR_ENROLL_STAGES: + g_value_set_int (value, priv->nr_enroll_stages); + break; + + case PROP_SCAN_TYPE: + g_value_set_enum (value, priv->scan_type); + break; + + case PROP_DRIVER: + g_value_set_static_string (value, FP_DEVICE_GET_CLASS (priv)->id); + break; + + case PROP_DEVICE_ID: + g_value_set_string (value, priv->device_id); + break; + + case PROP_NAME: + g_value_set_string (value, priv->device_name); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +fp_device_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + FpDevice *self = FP_DEVICE (object); + FpDevicePrivate *priv = fp_device_get_instance_private (self); + FpDeviceClass *cls = FP_DEVICE_GET_CLASS (self); + + /* _construct has not run yet, so we cannot use priv->type. */ + switch (prop_id) + { + case PROP_FPI_ENVIRON: + if (cls->type == FP_DEVICE_TYPE_VIRTUAL) + priv->virtual_env = g_value_dup_string (value); + else + g_assert (g_value_get_string (value) == NULL); + break; + + case PROP_FPI_USB_DEVICE: + if (cls->type == FP_DEVICE_TYPE_USB) + priv->usb_device = g_value_dup_object (value); + else + g_assert (g_value_get_object (value) == NULL); + break; + + case PROP_FPI_DRIVER_DATA: + priv->driver_data = g_value_get_uint64 (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +fp_device_async_initable_init_async (GAsyncInitable *initable, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + FpDevice *self = FP_DEVICE (initable); + FpDevicePrivate *priv = fp_device_get_instance_private (self); + + /* It is next to impossible to call async_init at the wrong time. */ + g_assert (!priv->is_open); + g_assert (!priv->current_task); + + task = g_task_new (self, cancellable, callback, user_data); + if (g_task_return_error_if_cancelled (task)) + return; + + if (!FP_DEVICE_GET_CLASS (self)->probe) + { + g_task_return_boolean (task, TRUE); + return; + } + + priv->current_action = FP_DEVICE_ACTION_PROBE; + priv->current_task = g_steal_pointer (&task); + if (cancellable) + { + priv->current_cancellable_id = g_cancellable_connect (cancellable, + G_CALLBACK (fp_device_cancelled_cb), + self, + NULL); + } + + FP_DEVICE_GET_CLASS (self)->probe (self); +} + +static gboolean +fp_device_async_initable_init_finish (GAsyncInitable *initable, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +fp_device_async_initable_iface_init (GAsyncInitableIface *iface) +{ + iface->init_async = fp_device_async_initable_init_async; + iface->init_finish = fp_device_async_initable_init_finish; +} + +static void +fp_device_class_init (FpDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = fp_device_constructed; + object_class->finalize = fp_device_finalize; + object_class->get_property = fp_device_get_property; + object_class->set_property = fp_device_set_property; + + properties[PROP_NR_ENROLL_STAGES] = + g_param_spec_uint ("nr-enroll-stages", + "EnrollStages", + "Number of enroll stages needed on the device", + 0, G_MAXUINT, + 0, + G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); + + properties[PROP_SCAN_TYPE] = + g_param_spec_enum ("scan-type", + "ScanType", + "The scan type of the device", + FP_TYPE_SCAN_TYPE, FP_SCAN_TYPE_SWIPE, + G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); + + properties[PROP_DRIVER] = + g_param_spec_string ("driver", + "Driver", + "String describing the driver", + NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); + + properties[PROP_DEVICE_ID] = + g_param_spec_string ("device-id", + "Device ID", + "String describing the device, often generic but may be a serial number", + "", + G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); + + properties[PROP_NAME] = + g_param_spec_string ("name", + "Device Name", + "Human readable name for the device", + NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); + + properties[PROP_FPI_ENVIRON] = + g_param_spec_string ("fp-environ", + "Virtual Environment", + "Private: The environment variable for the virtual device", + NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); + + properties[PROP_FPI_USB_DEVICE] = + g_param_spec_object ("fp-usb-device", + "USB Device", + "Private: The USB device for the device", + G_USB_TYPE_DEVICE, + G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); + + properties[PROP_FPI_DRIVER_DATA] = + g_param_spec_uint64 ("fp-driver-data", + "Driver Data", + "Private: The driver data from the ID table entry", + 0, + G_MAXUINT64, + 0, + G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +fp_device_init (FpDevice *self) +{ +} + +/** + * fp_device_get_driver: + * @device: A #FpDevice + * + * Returns: (transfer none): The ID of the driver + */ +const gchar * +fp_device_get_driver (FpDevice *device) +{ + g_return_val_if_fail (FP_IS_DEVICE (device), NULL); + + return FP_DEVICE_GET_CLASS (device)->id; +} + +/** + * fp_device_get_device_id: + * @device: A #FpDevice + * + * Returns: (transfer none): The ID of the device + */ +const gchar * +fp_device_get_device_id (FpDevice *device) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_val_if_fail (FP_IS_DEVICE (device), NULL); + + return priv->device_id; +} + +/** + * fp_device_get_name: + * @device: A #FpDevice + * + * Returns: (transfer none): The human readable name of the device + */ +const gchar * +fp_device_get_name (FpDevice *device) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_val_if_fail (FP_IS_DEVICE (device), NULL); + + return priv->device_name; +} + +/** + * fp_device_get_scan_type: + * @device: A #FpDevice + * + * Retrieves the scan type of the device. + * + * Returns: The #FpScanType + */ +FpScanType +fp_device_get_scan_type (FpDevice *device) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_val_if_fail (FP_IS_DEVICE (device), FP_SCAN_TYPE_SWIPE); + + return priv->scan_type; +} + +/** + * fp_device_get_nr_enroll_stages: + * @device: A #FpDevice + * + * Retrieves the number of enroll stages for this device. + * + * Returns: The number of enroll stages + */ +gint +fp_device_get_nr_enroll_stages (FpDevice *device) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_val_if_fail (FP_IS_DEVICE (device), -1); + + return priv->nr_enroll_stages; +} + +/** + * fp_device_supports_identify: + * @device: A #FpDevice + * + * Check whether the device supports identification. + * + * Returns: Whether the device supports identification + */ +gboolean +fp_device_supports_identify (FpDevice *device) +{ + FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device); + + g_return_val_if_fail (FP_IS_DEVICE (device), FALSE); + + return cls->identify != NULL; +} + +/** + * fp_device_supports_capture: + * @device: A #FpDevice + * + * Check whether the device supports capturing images. + * + * Returns: Whether the device supports image capture + */ +gboolean +fp_device_supports_capture (FpDevice *device) +{ + FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device); + + g_return_val_if_fail (FP_IS_DEVICE (device), FALSE); + + return cls->capture != NULL; +} + +/** + * fp_device_has_storage: + * @device: A #FpDevice + * + * Whether the device has on-chip storage. If it has, you can list the + * prints stored on the with fp_device_list_prints() and you should + * always delete prints from the device again using + * fp_device_delete_print(). + */ +gboolean +fp_device_has_storage (FpDevice *device) +{ + FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device); + + g_return_val_if_fail (FP_IS_DEVICE (device), FALSE); + + return cls->list != NULL; +} + +/** + * fp_device_open: + * @device: a #FpDevice + * @cancellable: (nullable): a #GCancellable, or %NULL + * @callback: the function to call on completion + * @user_data: the data to pass to @callback + * + * Start an asynchronous operation to open the device. The callback will + * be called once the operation has finished. Retrieve the result with + * fp_device_open_finish(). + */ +void +fp_device_open (FpDevice *device, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + FpDevicePrivate *priv = fp_device_get_instance_private (device); + GError *error = NULL; + + task = g_task_new (device, cancellable, callback, user_data); + if (g_task_return_error_if_cancelled (task)) + return; + + if (priv->is_open) + { + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_ALREADY_OPEN)); + return; + } + + if (priv->current_task) + { + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_BUSY)); + return; + } + + switch (priv->type) + { + case FP_DEVICE_TYPE_USB: + if (!g_usb_device_open (priv->usb_device, &error)) + { + g_task_return_error (task, error); + return; + } + break; + + case FP_DEVICE_TYPE_VIRTUAL: + break; + + default: + g_assert_not_reached (); + g_task_return_error (task, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + return; + } + + priv->current_action = FP_DEVICE_ACTION_OPEN; + priv->current_task = g_steal_pointer (&task); + if (cancellable) + { + priv->current_cancellable_id = g_cancellable_connect (cancellable, + G_CALLBACK (fp_device_cancelled_cb), + device, + NULL); + } + + FP_DEVICE_GET_CLASS (device)->open (device); +} + +/** + * fp_device_open_finish: + * @device: A #FpDevice + * @result: A #GAsyncResult + * @error: Return location for errors, or %NULL to ignore + * + * Finish an asynchronous operation to open the device. + * See fp_device_open(). + * + * Returns: (type void): %FALSE on error, %TRUE otherwise + */ +gboolean +fp_device_open_finish (FpDevice *device, + GAsyncResult *result, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (result), error); +} + +/** + * fp_device_close: + * @device: a #FpDevice + * @cancellable: (nullable): a #GCancellable, or %NULL + * @callback: the function to call on completion + * @user_data: the data to pass to @callback + * + * Start an asynchronous operation to close the device. The callback will + * be called once the operation has finished. Retrieve the result with + * fp_device_close_finish(). + */ +void +fp_device_close (FpDevice *device, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + task = g_task_new (device, cancellable, callback, user_data); + if (g_task_return_error_if_cancelled (task)) + return; + + if (!priv->is_open) + { + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN)); + return; + } + + if (priv->current_task) + { + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_BUSY)); + return; + } + + priv->current_action = FP_DEVICE_ACTION_CLOSE; + priv->current_task = g_steal_pointer (&task); + if (cancellable) + { + priv->current_cancellable_id = g_cancellable_connect (cancellable, + G_CALLBACK (fp_device_cancelled_cb), + device, + NULL); + } + + FP_DEVICE_GET_CLASS (device)->close (device); +} + +/** + * fp_device_close_finish: + * @device: A #FpDevice + * @result: A #GAsyncResult + * @error: Return location for errors, or %NULL to ignore + * + * Finish an asynchronous operation to close the device. + * See fp_device_close(). + * + * Returns: (type void): %FALSE on error, %TRUE otherwise + */ +gboolean +fp_device_close_finish (FpDevice *device, + GAsyncResult *result, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (result), error); +} + + +/** + * fp_device_enroll: + * @device: a #FpDevice + * @template_print: (transfer floating): a #FpPrint + * @cancellable: (nullable): a #GCancellable, or %NULL + * @progress_cb: (nullable) (scope notified): progress reporting callback + * @progress_data: (closure progress_cb): user data for @progress_cb + * @progress_destroy: (destroy progress_data): Destroy notify for @progress_data + * @callback: (scope async): the function to call on completion + * @user_data: the data to pass to @callback + * + * Start an asynchronous operation to enroll a print. The callback will + * be called once the operation has finished. Retrieve the result with + * fp_device_enroll_finish(). + * + * The @template_print parameter is a #FpPrint with available metadata filled + * in. The driver may make use of this metadata, when e.g. storing the print on + * device memory. It is undefined whether this print is filled in by the driver + * and returned, or whether the driver will return a newly created print after + * enrollment successed. + */ +void +fp_device_enroll (FpDevice *device, + FpPrint *template_print, + GCancellable *cancellable, + FpEnrollProgress progress_cb, + gpointer progress_data, + GDestroyNotify progress_destroy, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + FpDevicePrivate *priv = fp_device_get_instance_private (device); + FpEnrollData *data; + FpPrintType print_type; + + task = g_task_new (device, cancellable, callback, user_data); + if (g_task_return_error_if_cancelled (task)) + return; + + if (!priv->is_open) + { + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN)); + return; + } + + if (priv->current_task) + { + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_BUSY)); + return; + } + + if (!FP_IS_PRINT (template_print)) + { + g_warning ("User did not pass a print template!"); + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); + return; + } + + g_object_get (template_print, "fp-type", &print_type, NULL); + if (print_type != FP_PRINT_UNDEFINED) + { + g_warning ("Passed print template must be newly created and blank!"); + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); + return; + } + + priv->current_action = FP_DEVICE_ACTION_ENROLL; + priv->current_task = g_steal_pointer (&task); + if (cancellable) + { + priv->current_cancellable_id = g_cancellable_connect (cancellable, + G_CALLBACK (fp_device_cancelled_cb), + device, + NULL); + } + + data = g_new0 (FpEnrollData, 1); + data->print = g_object_ref_sink (template_print); + data->enroll_progress_cb = progress_cb; + data->enroll_progress_data = progress_data; + + // Attach the progress data as task data so that it is destroyed + g_task_set_task_data (priv->current_task, data, enroll_data_free); + + FP_DEVICE_GET_CLASS (device)->enroll (device); +} + +/** + * fp_device_enroll_finish: + * @device: A #FpDevice + * @result: A #GAsyncResult + * @error: Return location for errors, or %NULL to ignore + * + * Finish an asynchronous operation to enroll a print. You should check + * for an error of type %FP_DEVICE_RETRY to prompt the user again if there + * was an interaction issue. + * See fp_device_enroll(). + * + * Returns: (transfer full): The enrolled #FpPrint, or %NULL on error + */ +FpPrint * +fp_device_enroll_finish (FpDevice *device, + GAsyncResult *result, + GError **error) +{ + return g_task_propagate_pointer (G_TASK (result), error); +} + +/** + * fp_device_verify: + * @device: a #FpDevice + * @enrolled_print: a #FpPrint to verify + * @cancellable: (nullable): a #GCancellable, or %NULL + * @callback: the function to call on completion + * @user_data: the data to pass to @callback + * + * Start an asynchronous operation to close the device. The callback will + * be called once the operation has finished. Retrieve the result with + * fp_device_verify_finish(). + */ +void +fp_device_verify (FpDevice *device, + FpPrint *enrolled_print, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + task = g_task_new (device, cancellable, callback, user_data); + if (g_task_return_error_if_cancelled (task)) + return; + + if (!priv->is_open) + { + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN)); + return; + } + + if (priv->current_task) + { + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_BUSY)); + return; + } + + priv->current_action = FP_DEVICE_ACTION_VERIFY; + priv->current_task = g_steal_pointer (&task); + if (cancellable) + { + priv->current_cancellable_id = g_cancellable_connect (cancellable, + G_CALLBACK (fp_device_cancelled_cb), + device, + NULL); + } + + g_task_set_task_data (priv->current_task, + g_object_ref (enrolled_print), + g_object_unref); + + FP_DEVICE_GET_CLASS (device)->verify (device); +} + +/** + * fp_device_verify_finish: + * @device: A #FpDevice + * @result: A #GAsyncResult + * @match: (out): Whether the user presented the correct finger + * @print: (out) (transfer full) (nullable): Location to store the scanned print, or %NULL to ignore + * @error: Return location for errors, or %NULL to ignore + * + * Finish an asynchronous operation to verify an enrolled print. You should check + * for an error of type %FP_DEVICE_RETRY to prompt the user again if there + * was an interaction issue. + * + * With @print you can fetch the newly created print and retrieve the image data if available. + * + * See fp_device_verify(). + * + * Returns: (type void): %FALSE on error, %TRUE otherwise + */ +gboolean +fp_device_verify_finish (FpDevice *device, + GAsyncResult *result, + gboolean *match, + FpPrint **print, + GError **error) +{ + gint res; + + res = g_task_propagate_int (G_TASK (result), error); + + if (print) + { + *print = g_object_get_data (G_OBJECT (result), "print"); + if (*print) + g_object_ref (*print); + } + + if (match) + *match = res == FPI_MATCH_SUCCESS; + + return res != FPI_MATCH_ERROR; +} + +/** + * fp_device_identify: + * @device: a #FpDevice + * @prints: (element-type FpPrint) (transfer none): #GPtrArray of #FpPrint + * @cancellable: (nullable): a #GCancellable, or %NULL + * @callback: the function to call on completion + * @user_data: the data to pass to @callback + * + * Start an asynchronous operation to identify prints. The callback will + * be called once the operation has finished. Retrieve the result with + * fp_device_identify_finish(). + */ +void +fp_device_identify (FpDevice *device, + GPtrArray *prints, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + task = g_task_new (device, cancellable, callback, user_data); + if (g_task_return_error_if_cancelled (task)) + return; + + if (!priv->is_open) + { + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN)); + return; + } + + if (priv->current_task) + { + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_BUSY)); + return; + } + + priv->current_action = FP_DEVICE_ACTION_IDENTIFY; + priv->current_task = g_steal_pointer (&task); + if (cancellable) + { + priv->current_cancellable_id = g_cancellable_connect (cancellable, + G_CALLBACK (fp_device_cancelled_cb), + device, + NULL); + } + + g_task_set_task_data (priv->current_task, + g_ptr_array_ref (prints), + (GDestroyNotify) g_ptr_array_unref); + + FP_DEVICE_GET_CLASS (device)->verify (device); +} + +/** + * fp_device_identify_finish: + * @device: A #FpDevice + * @result: A #GAsyncResult + * @match: (out) (transfer full) (nullable): Location for the matched #FpPrint, or %NULL + * @print: (out) (transfer full) (nullable): Location for the new #FpPrint, or %NULL + * @error: Return location for errors, or %NULL to ignore + * + * Finish an asynchronous operation to identify a print. You should check + * for an error of type %FP_DEVICE_RETRY to prompt the user again if there + * was an interaction issue. + * + * Use @match to find the print that matched. With @print you can fetch the + * newly created print and retrieve the image data if available. + * + * See fp_device_identify(). + * + * Returns: (type void): %FALSE on error, %TRUE otherwise + */ +gboolean +fp_device_identify_finish (FpDevice *device, + GAsyncResult *result, + FpPrint **match, + FpPrint **print, + GError **error) +{ + if (print) + { + *print = g_object_get_data (G_OBJECT (result), "print"); + if (*print) + g_object_ref (*print); + } + if (match) + { + *match = g_object_get_data (G_OBJECT (result), "match"); + if (*match) + g_object_ref (*match); + } + + return g_task_propagate_boolean (G_TASK (result), error); +} + +/** + * fp_device_capture: + * @device: a #FpDevice + * @wait_for_finger: Whether to wait for a finger or not + * @cancellable: (nullable): a #GCancellable, or %NULL + * @callback: the function to call on completion + * @user_data: the data to pass to @callback + * + * Start an asynchronous operation to capture an image. The callback will + * be called once the operation has finished. Retrieve the result with + * fp_device_capture_finish(). + */ +void +fp_device_capture (FpDevice *device, + gboolean wait_for_finger, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + task = g_task_new (device, cancellable, callback, user_data); + if (g_task_return_error_if_cancelled (task)) + return; + + if (!priv->is_open) + { + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN)); + return; + } + + if (priv->current_task) + { + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_BUSY)); + return; + } + + priv->current_action = FP_DEVICE_ACTION_CAPTURE; + priv->current_task = g_steal_pointer (&task); + if (cancellable) + { + priv->current_cancellable_id = g_cancellable_connect (cancellable, + G_CALLBACK (fp_device_cancelled_cb), + device, + NULL); + } + + priv->wait_for_finger = wait_for_finger; + + FP_DEVICE_GET_CLASS (device)->capture (device); +} + +/** + * fp_device_capture_finish: + * @device: A #FpDevice + * @result: A #GAsyncResult + * @error: Return location for errors, or %NULL to ignore + * + * Finish an asynchronous operation to capture an image. You should check + * for an error of type %FP_DEVICE_RETRY to prompt the user again if there + * was an interaction issue. + * + * See fp_device_capture(). + * + * Returns: (transfer full): #FpImage or %NULL on error + */ +FpImage * +fp_device_capture_finish (FpDevice *device, + GAsyncResult *result, + GError **error) +{ + return g_task_propagate_pointer (G_TASK (result), error); +} + +/** + * fp_device_delete_print: + * @device: a #FpDevice + * @enrolled_print: a #FpPrint to delete + * @cancellable: (nullable): a #GCancellable, or %NULL + * @callback: the function to call on completion + * @user_data: the data to pass to @callback + * + * Start an asynchronous operation to delete a print from the device. + * The callback will be called once the operation has finished. Retrieve + * the result with fp_device_delete_print_finish(). + * + * This only makes sense on devices that store prints on-chip, but is safe + * to always call. + */ +void +fp_device_delete_print (FpDevice *device, + FpPrint *enrolled_print, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + task = g_task_new (device, cancellable, callback, user_data); + if (g_task_return_error_if_cancelled (task)) + return; + + if (!priv->is_open) + { + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN)); + return; + } + + if (priv->current_task) + { + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_BUSY)); + return; + } + + /* Succeed immediately if delete is not implemented. */ + if (!FP_DEVICE_GET_CLASS (device)->delete) + { + g_task_return_boolean (task, TRUE); + return; + } + + priv->current_action = FP_DEVICE_ACTION_DELETE; + priv->current_task = g_steal_pointer (&task); + if (cancellable) + { + priv->current_cancellable_id = g_cancellable_connect (cancellable, + G_CALLBACK (fp_device_cancelled_cb), + device, + NULL); + } + + g_task_set_task_data (priv->current_task, + g_object_ref (enrolled_print), + g_object_unref); + + FP_DEVICE_GET_CLASS (device)->delete (device); +} + +/** + * fp_device_delete_print_finish: + * @device: A #FpDevice + * @result: A #GAsyncResult + * @error: Return location for errors, or %NULL to ignore + * + * Finish an asynchronous operation to delete an enrolled print. + * + * See fp_device_delete_print(). + * + * Returns: (type void): %FALSE on error, %TRUE otherwise + */ +gboolean +fp_device_delete_print_finish (FpDevice *device, + GAsyncResult *result, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (result), error); +} + +/** + * fp_device_list_prints: + * @device: a #FpDevice + * @cancellable: (nullable): a #GCancellable, or %NULL + * @callback: the function to call on completion + * @user_data: the data to pass to @callback + * + * Start an asynchronous operation to list all prints stored on the device. + * This only makes sense on devices that store prints on-chip. + * + * Retrieve the result with fp_device_list_prints_finish(). + */ +void +fp_device_list_prints (FpDevice *device, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + task = g_task_new (device, cancellable, callback, user_data); + if (g_task_return_error_if_cancelled (task)) + return; + + if (!priv->is_open) + { + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN)); + return; + } + + if (priv->current_task) + { + g_task_return_error (task, + fpi_device_error_new (FP_DEVICE_ERROR_BUSY)); + return; + } + + priv->current_action = FP_DEVICE_ACTION_LIST; + priv->current_task = g_steal_pointer (&task); + if (cancellable) + { + priv->current_cancellable_id = g_cancellable_connect (cancellable, + G_CALLBACK (fp_device_cancelled_cb), + device, + NULL); + } + + FP_DEVICE_GET_CLASS (device)->list (device); +} + +/** + * fp_device_list_prints_finish: + * @device: A #FpDevice + * @result: A #GAsyncResult + * @error: Return location for errors, or %NULL to ignore + * + * Finish an asynchronous operation to list all device stored prints. + * + * See fp_device_list_prints(). + * + * Returns: (element-type FpPrint) (transfer container): Array of prints or %NULL on error + */ +GPtrArray * +fp_device_list_prints_finish (FpDevice *device, + GAsyncResult *result, + GError **error) +{ + return g_task_propagate_pointer (G_TASK (result), error); +} + +typedef struct +{ + GSource source; + FpDevice *device; + FpTimeoutFunc callback; + gpointer user_data; +} FpDeviceTimeoutSource; + +gboolean +device_timeout_cb (gpointer user_data) +{ + FpDeviceTimeoutSource *source = user_data; + + source->callback (source->device, source->user_data); + + return G_SOURCE_REMOVE; +} + +void +timeout_finalize (GSource *source) +{ + FpDeviceTimeoutSource *timeout_source = (FpDeviceTimeoutSource *) source; + FpDevicePrivate *priv; + + priv = fp_device_get_instance_private (timeout_source->device); + priv->sources = g_slist_remove (priv->sources, source); +} + +static gboolean +timeout_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) +{ + FpDeviceTimeoutSource *timeout_source = (FpDeviceTimeoutSource *) source; + + ((FpTimeoutFunc) callback)(timeout_source->device, user_data); + + return G_SOURCE_REMOVE; +} + +static GSourceFuncs timeout_funcs = { + NULL, /* prepare */ + NULL, /* check */ + timeout_dispatch, + timeout_finalize, + NULL, NULL +}; + +/* Private API functions */ + +/** + * fpi_device_set_nr_enroll_stages: + * @device: The #FpDevice + * @enroll_stages: The number of enroll stages + * + * Updates the reported number of enroll stages that the device needs. + * If all supported devices have the same number of stages, then the + * value can simply be set in the class. + */ +void +fpi_device_set_nr_enroll_stages (FpDevice *device, + gint enroll_stages) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_if_fail (FP_IS_DEVICE (device)); + + priv->nr_enroll_stages = enroll_stages; + g_object_notify_by_pspec (G_OBJECT (device), properties[PROP_NR_ENROLL_STAGES]); +} + +/** + * fpi_device_set_scan_type: + * @device: The #FpDevice + * @scan_type: The scan type of the device + * + * Updates the the scan type of the device from the default. + * If all supported devices have the same scan type, then the + * value can simply be set in the class. + */ +void +fpi_device_set_scan_type (FpDevice *device, + FpScanType scan_type) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_if_fail (FP_IS_DEVICE (device)); + + priv->scan_type = scan_type; + g_object_notify_by_pspec (G_OBJECT (device), properties[PROP_SCAN_TYPE]); +} + +/** + * fpi_device_add_timeout: + * @device: The #FpDevice + * @interval: The interval in milliseconds + * @func: The #FpTimeoutFunc to call on timeout + * @user_data: User data to pass to the callback + * + * Register a timeout to run. Drivers should always make sure that timers are + * cancelled when appropriate. + * + * Returns: (transfer none): A newly created and attached #GSource + */ +GSource * +fpi_device_add_timeout (FpDevice *device, + gint interval, + FpTimeoutFunc func, + gpointer user_data) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + FpDeviceTimeoutSource *source; + + source = (FpDeviceTimeoutSource *) g_source_new (&timeout_funcs, + sizeof (FpDeviceTimeoutSource)); + source->device = device; + source->user_data = user_data; + + g_source_attach (&source->source, NULL); + g_source_set_callback (&source->source, (GSourceFunc) func, user_data, NULL); + g_source_set_ready_time (&source->source, + g_source_get_time (&source->source) + interval * (guint64) 1000); + priv->sources = g_slist_prepend (priv->sources, source); + g_source_unref (&source->source); + + return &source->source; +} + +/** + * fpi_device_get_usb_device: + * @device: The #FpDevice + * + * Get the #GUsbDevice for this #FpDevice. Only permissible to call if the + * #FpDevice is of type %FP_DEVICE_TYPE_USB. + * + * Returns: The #GUsbDevice + */ +GUsbDevice * +fpi_device_get_usb_device (FpDevice *device) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_val_if_fail (FP_IS_DEVICE (device), NULL); + g_return_val_if_fail (priv->type == FP_DEVICE_TYPE_USB, NULL); + + return priv->usb_device; +} + +/** + * fpi_device_get_virtual_env: + * @device: The #FpDevice + * + * Get the value of the environment variable that caused the virtual #FpDevice to be + * generated. Only permissible to call if the #FpDevice is of type %FP_DEVICE_TYPE_VIRTUAL. + * + * Returns: The value of the environment variable + */ +const gchar * +fpi_device_get_virtual_env (FpDevice *device) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_val_if_fail (FP_IS_DEVICE (device), NULL); + g_return_val_if_fail (priv->type == FP_DEVICE_TYPE_VIRTUAL, NULL); + + return priv->virtual_env; +} + +/** + * fpi_device_get_current_action: + * @device: The #FpDevice + * + * Get the currently ongoing action or %FP_DEVICE_ACTION_NONE if there + * is no operation at this time. + * + * This is useful for drivers that might share code paths between different + * actions (e.g. verify and identify) and want to find out again later which + * action was started in the beginning. + * + * Returns: The ongoing #FpDeviceAction + */ +FpDeviceAction +fpi_device_get_current_action (FpDevice *device) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_val_if_fail (FP_IS_DEVICE (device), FP_DEVICE_ACTION_NONE); + + return priv->current_action; +} + +/** + * fpi_device_action_is_cancelled: + * @device: The #FpDevice + * + * Checks whether the current action has been cancelled by the user. + * This is equivalent to first getting the cancellable using + * fpi_device_get_cancellable() and then checking whether it has been + * cancelled (if it is non-NULL). + * + * Returns: %TRUE if action should be cancelled + */ +gboolean +fpi_device_action_is_cancelled (FpDevice *device) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + GCancellable *cancellable; + + g_return_val_if_fail (FP_IS_DEVICE (device), TRUE); + g_return_val_if_fail (priv->current_action != FP_DEVICE_ACTION_NONE, TRUE); + + cancellable = g_task_get_cancellable (priv->current_task); + + return cancellable ? g_cancellable_is_cancelled (cancellable) : FALSE; +} + +/** + * fpi_device_get_driver_data: + * @device: The #FpDevice + * + * Returns: The driver data from the #FpIdEntry table entry + */ +guint64 +fpi_device_get_driver_data (FpDevice *device) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_val_if_fail (FP_IS_DEVICE (device), 0); + + return priv->driver_data; +} + +/** + * fpi_device_get_enroll_data: + * @device: The #FpDevice + * @print: (out) (transfer none): The user provided template print + * + * Get data for enrollment. + */ +void +fpi_device_get_enroll_data (FpDevice *device, + FpPrint **print) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + FpEnrollData *data; + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_ENROLL); + + data = g_task_get_task_data (priv->current_task); + g_assert (data); + + if (print) + *print = data->print; +} + +/** + * fpi_device_get_capture_data: + * @device: The #FpDevice + * @wait_for_finger: (out): Whether to wait for finger or not + * + * Get data for capture. + */ +void +fpi_device_get_capture_data (FpDevice *device, + gboolean *wait_for_finger) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_CAPTURE); + + if (wait_for_finger) + *wait_for_finger = priv->wait_for_finger; +} + +/** + * fpi_device_get_verify_data: + * @device: The #FpDevice + * @print: (out) (transfer none): The enrolled print + * + * Get data for verify. + */ +void +fpi_device_get_verify_data (FpDevice *device, + FpPrint **print) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_VERIFY); + + if (print) + *print = g_task_get_task_data (priv->current_task); +} + +/** + * fpi_device_get_identify_data: + * @device: The #FpDevice + * @prints: (out) (transfer none) (element-type FpPrint): The gallery of prints + * + * Get data for identify. + */ +void +fpi_device_get_identify_data (FpDevice *device, + GPtrArray **prints) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_IDENTIFY); + + if (prints) + *prints = g_task_get_task_data (priv->current_task); +} + +/** + * fpi_device_get_delete_data: + * @device: The #FpDevice + * @print: (out) (transfer none): The print to delete + * + * Get data for delete. + */ +void +fpi_device_get_delete_data (FpDevice *device, + FpPrint **print) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_DELETE); + + if (print) + *print = g_task_get_task_data (priv->current_task); +} + +/** + * fpi_device_get_cancellable: + * @device: The #FpDevice + * + * Retrieve the #GCancellable that may cancel the currently ongoing operation. This + * is primarily useful to pass directly to e.g. fpi_usb_transfer_submit() for cancellable + * transfers. + * In many cases the cancel vfunc may be more convenient to react to cancellation in some + * way. + * + * Returns: (transfer none): The #GCancellable for the current action. + */ +GCancellable * +fpi_device_get_cancellable (FpDevice *device) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_val_if_fail (FP_IS_DEVICE (device), NULL); + g_return_val_if_fail (priv->current_action != FP_DEVICE_ACTION_NONE, NULL); + + return g_task_get_cancellable (priv->current_task); +} + +/** + * fpi_device_action_error: + * @device: The #FpDevice + * @error: The #GError to return + * + * Finish an ongoing action with an error. This is the same as calling + * the corresponding complete function such as fpi_device_open_complete() + * with an error set. If possible, use the correct complete function as + * that results in improved error detection. + */ +void +fpi_device_action_error (FpDevice *device, + GError *error) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action != FP_DEVICE_ACTION_NONE); + + if (error != NULL) + { + g_debug ("Device reported generic error during action; action was: %i", priv->current_action); + } + else + { + g_warning ("Device failed to pass an error to generic action error function"); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, "Device reported error but did not provide an error condition"); + } + + + switch (priv->current_action) + { + case FP_DEVICE_ACTION_PROBE: + fpi_device_probe_complete (device, NULL, NULL, error); + break; + + case FP_DEVICE_ACTION_OPEN: + fpi_device_open_complete (device, error); + break; + + case FP_DEVICE_ACTION_CLOSE: + fpi_device_close_complete (device, error); + break; + + case FP_DEVICE_ACTION_ENROLL: + fpi_device_enroll_complete (device, NULL, error); + break; + + case FP_DEVICE_ACTION_VERIFY: + fpi_device_verify_complete (device, FPI_MATCH_ERROR, NULL, error); + break; + + case FP_DEVICE_ACTION_IDENTIFY: + fpi_device_identify_complete (device, NULL, NULL, error); + break; + + case FP_DEVICE_ACTION_CAPTURE: + fpi_device_capture_complete (device, NULL, error); + break; + + case FP_DEVICE_ACTION_DELETE: + fpi_device_delete_complete (device, error); + break; + + case FP_DEVICE_ACTION_LIST: + fpi_device_list_complete (device, NULL, error); + break; + + default: + case FP_DEVICE_ACTION_NONE: + g_return_if_reached (); + break; + } +} + +/** + * fpi_device_probe_complete: + * @device: The #FpDevice + * @device_id: Unique ID for the device or %NULL + * @device_name: Human readable name or %NULL for driver name + * @error: The #GError or %NULL on success + * + * Finish an ongoing probe operation. If error is %NULL success is assumed. + */ +void +fpi_device_probe_complete (FpDevice *device, + const gchar *device_id, + const gchar *device_name, + GError *error) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_PROBE); + + g_debug ("Device reported probe completion"); + + task = g_steal_pointer (&priv->current_task); + g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); + if (priv->current_cancellable_id) + g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); + priv->current_cancellable_id = 0; + priv->current_action = FP_DEVICE_ACTION_NONE; + + if (!error) + { + if (device_id) + { + g_clear_pointer (&priv->device_id, g_free); + priv->device_id = g_strdup (device_id); + g_object_notify_by_pspec (G_OBJECT (device), properties[PROP_DEVICE_ID]); + } + if (device_name) + { + g_clear_pointer (&priv->device_name, g_free); + priv->device_name = g_strdup (device_name); + g_object_notify_by_pspec (G_OBJECT (device), properties[PROP_NAME]); + } + g_task_return_boolean (task, TRUE); + } + else + { + g_task_return_error (task, error); + } +} + +/** + * fpi_device_open_complete: + * @device: The #FpDevice + * @error: The #GError or %NULL on success + * + * Finish an ongoing open operation. If error is %NULL success is assumed. + */ +void +fpi_device_open_complete (FpDevice *device, GError *error) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_OPEN); + + g_debug ("Device reported open completion"); + + task = g_steal_pointer (&priv->current_task); + g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); + if (priv->current_cancellable_id) + g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); + priv->current_cancellable_id = 0; + priv->current_action = FP_DEVICE_ACTION_NONE; + + if (!error) + priv->is_open = TRUE; + + if (!error) + g_task_return_boolean (task, TRUE); + else + g_task_return_error (task, error); +} + +/** + * fpi_device_close_complete: + * @device: The #FpDevice + * @error: The #GError or %NULL on success + * + * Finish an ongoing close operation. If error is %NULL success is assumed. + */ +void +fpi_device_close_complete (FpDevice *device, GError *error) +{ + g_autoptr(GTask) task = NULL; + GError *nested_error = NULL; + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_CLOSE); + + g_debug ("Device reported close completion"); + + task = g_steal_pointer (&priv->current_task); + g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); + if (priv->current_cancellable_id) + g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); + priv->current_cancellable_id = 0; + priv->current_action = FP_DEVICE_ACTION_NONE; + priv->is_open = FALSE; + + switch (priv->type) + { + case FP_DEVICE_TYPE_USB: + if (!g_usb_device_close (priv->usb_device, &nested_error)) + { + if (error == NULL) + error = nested_error; + g_task_return_error (task, error); + return; + } + break; + + case FP_DEVICE_TYPE_VIRTUAL: + break; + + default: + g_assert_not_reached (); + g_task_return_error (task, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + return; + } + + if (!error) + g_task_return_boolean (task, TRUE); + else + g_task_return_error (task, error); +} + +/** + * fpi_device_enroll_complete: + * @device: The #FpDevice + * @print: (nullable) (transfer full): The #FpPrint or %NULL on failure + * @error: The #GError or %NULL on success + * + * Finish an ongoing enroll operation. The #FpPrint can be stored by the + * caller for later verification. + */ +void +fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_ENROLL); + + g_debug ("Device reported enroll completion"); + + task = g_steal_pointer (&priv->current_task); + g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); + if (priv->current_cancellable_id) + g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); + priv->current_cancellable_id = 0; + priv->current_action = FP_DEVICE_ACTION_NONE; + + if (!error) + { + if (FP_IS_PRINT (print)) + { + g_task_return_pointer (task, print, g_object_unref); + } + else + { + g_warning ("Driver did not provide a valid print and failed to provide an error!"); + g_task_return_new_error (task, + FP_DEVICE_ERROR, + FP_DEVICE_ERROR_GENERAL, + "Driver failed to provide print data!"); + } + } + else + { + g_task_return_error (task, error); + if (FP_IS_PRINT (print)) + { + g_warning ("Driver passed an error but also provided a print, returning error!"); + g_object_unref (print); + } + } +} + +/** + * fpi_device_verify_complete: + * @device: The #FpDevice + * @result: The #FpiMatchResult of the operation + * @print: The scanned #FpPrint + * @error: A #GError if result is %FPI_MATCH_ERROR + * + * Finish an ongoing verify operation. The returned print should be + * representing the new scan and not the one passed for verification. + */ +void +fpi_device_verify_complete (FpDevice *device, + FpiMatchResult result, + FpPrint *print, + GError *error) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_VERIFY); + + g_debug ("Device reported verify completion"); + + task = g_steal_pointer (&priv->current_task); + g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); + if (priv->current_cancellable_id) + g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); + priv->current_cancellable_id = 0; + priv->current_action = FP_DEVICE_ACTION_NONE; + + g_object_set_data_full (G_OBJECT (task), + "print", + print, + g_object_unref); + + if (!error) + { + if (result != FPI_MATCH_ERROR) + { + g_task_return_int (task, result); + } + else + { + g_warning ("Driver did not provide an error for a failed verify operation!"); + g_task_return_new_error (task, + FP_DEVICE_ERROR, + FP_DEVICE_ERROR_GENERAL, + "Driver failed to provide an error!"); + } + } + else + { + g_task_return_error (task, error); + if (result != FPI_MATCH_ERROR) + { + g_warning ("Driver passed an error but also provided a match result, returning error!"); + g_object_unref (print); + } + } +} + +/** + * fpi_device_identify_complete: + * @device: The #FpDevice + * @match: The matching #FpPrint from the passed gallery, or %NULL if none matched + * @print: The scanned #FpPrint, may be %NULL + * @error: The #GError or %NULL on success + * + * Finish an ongoing identify operation. The match that was identified is + * returned in @match. The @print parameter returns the newly created scan + * that was used for matching. + */ +void +fpi_device_identify_complete (FpDevice *device, + FpPrint *match, + FpPrint *print, + GError *error) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_IDENTIFY); + + g_debug ("Device reported identify completion"); + + task = g_steal_pointer (&priv->current_task); + g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); + if (priv->current_cancellable_id) + g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); + priv->current_cancellable_id = 0; + priv->current_action = FP_DEVICE_ACTION_NONE; + + g_object_set_data_full (G_OBJECT (task), + "print", + print, + g_object_unref); + g_object_set_data_full (G_OBJECT (task), + "match", + match, + g_object_unref); + if (!error) + { + g_task_return_boolean (task, TRUE); + } + else + { + g_task_return_error (task, error); + if (match) + { + g_warning ("Driver passed an error but also provided a match result, returning error!"); + g_clear_object (&match); + } + } +} + + +/** + * fpi_device_capture_complete: + * @device: The #FpDevice + * @image: The #FpImage, or %NULL on error + * @error: The #GError or %NULL on success + * + * Finish an ongoing capture operation. + */ +void +fpi_device_capture_complete (FpDevice *device, + FpImage *image, + GError *error) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_CAPTURE); + + g_debug ("Device reported capture completion"); + + task = g_steal_pointer (&priv->current_task); + g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); + if (priv->current_cancellable_id) + g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); + priv->current_cancellable_id = 0; + priv->current_action = FP_DEVICE_ACTION_NONE; + + if (!error) + { + if (image) + { + g_task_return_pointer (task, image, g_object_unref); + } + else + { + g_warning ("Driver did not provide an error for a failed capture operation!"); + g_task_return_new_error (task, + FP_DEVICE_ERROR, + FP_DEVICE_ERROR_GENERAL, + "Driver failed to provide an error!"); + } + } + else + { + g_task_return_error (task, error); + if (image) + { + g_warning ("Driver passed an error but also provided an image, returning error!"); + g_clear_object (&image); + } + } +} + +/** + * fpi_device_delete_complete: + * @device: The #FpDevice + * @error: The #GError or %NULL on success + * + * Finish an ongoing delete operation. + */ +void +fpi_device_delete_complete (FpDevice *device, + GError *error) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_autoptr(GTask) task = NULL; + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_DELETE); + + g_debug ("Device reported deletion completion"); + + task = g_steal_pointer (&priv->current_task); + g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); + if (priv->current_cancellable_id) + g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); + priv->current_cancellable_id = 0; + priv->current_action = FP_DEVICE_ACTION_NONE; + + if (!error) + g_task_return_boolean (task, TRUE); + else + g_task_return_error (task, error); +} + +/** + * fpi_device_list_complete: + * @device: The #FpDevice + * @prints: (element-type FpPrint) (transfer container): Possibly empty array of prints or %NULL on error + * @error: The #GError or %NULL on success + * + * Finish an ongoing list operation. + * + * Please note that the @prints array will be free'ed using + * g_ptr_array_unref() and the elements are destroyed automatically. + * As such, you must use g_ptr_array_new_with_free_func() with + * g_object_unref() as free func to create the array. + */ +void +fpi_device_list_complete (FpDevice *device, + GPtrArray *prints, + GError *error) +{ + g_autoptr(GTask) task = NULL; + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_LIST); + + g_debug ("Device reported listing completion"); + + task = g_steal_pointer (&priv->current_task); + g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); + if (priv->current_cancellable_id) + g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); + priv->current_cancellable_id = 0; + priv->current_action = FP_DEVICE_ACTION_NONE; + + if (prints && error) + { + g_warning ("Driver reported back prints and error, ignoring prints"); + g_clear_pointer (&prints, g_ptr_array_unref); + } + else if (!prints && !error) + { + g_warning ("Driver did not pass array but failed to provide an error"); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Driver failed to provide a list of prints"); + } + + if (!error) + g_task_return_pointer (task, prints, (GDestroyNotify) g_ptr_array_unref); + else + g_task_return_error (task, error); +} + +/** + * fpi_device_enroll_progress: + * @device: The #FpDevice + * @completed_stages: The number of stages that are completed at this point + * @print: The #FpPrint for the newly completed stage or %NULL on failure + * @error: The #GError or %NULL on success + * + * Notify about the progress of the enroll operation. This is important for UI interaction. + * The passed error may be used if a scan needs to be retried, use fpi_device_retry_new(). + */ +void +fpi_device_enroll_progress (FpDevice *device, + gint completed_stages, + FpPrint *print, + GError *error) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + FpEnrollData *data; + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_ENROLL); + g_return_if_fail (error == NULL || error->domain == FP_DEVICE_RETRY); + + g_debug ("Device reported enroll progress, reported %i of %i have been completed", completed_stages, priv->nr_enroll_stages); + + if (error && print) + { + g_warning ("Driver passed an error and also provided a print, returning error!"); + g_clear_object (&print); + } + + data = g_task_get_task_data (priv->current_task); + + if (data->enroll_progress_cb) + { + data->enroll_progress_cb (device, + completed_stages, + print, + data->enroll_progress_data, + error); + } + if (error) + g_error_free (error); +} + + +static void +async_result_ready (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GTask **task = user_data; + + *task = g_object_ref (G_TASK (res)); +} + +/** + * fp_device_open_sync: + * @device: a #FpDevice + * @cancellable: (nullable): a #GCancellable, or %NULL + * @error: Return location for errors, or %NULL to ignore + * + * Open the device synchronously. + * + * Returns: (type void): %FALSE on error, %TRUE otherwise + */ +gboolean +fp_device_open_sync (FpDevice *device, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GAsyncResult) task = NULL; + + g_return_val_if_fail (FP_IS_DEVICE (device), FALSE); + + fp_device_open (device, cancellable, async_result_ready, &task); + while (!task) + g_main_context_iteration (NULL, TRUE); + + return fp_device_open_finish (device, task, error); +} + +/** + * fp_device_close_sync: + * @device: a #FpDevice + * @cancellable: (nullable): a #GCancellable, or %NULL + * @error: Return location for errors, or %NULL to ignore + * + * Close the device synchronously. + * + * Returns: (type void): %FALSE on error, %TRUE otherwise + */ +gboolean +fp_device_close_sync (FpDevice *device, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GAsyncResult) task = NULL; + + g_return_val_if_fail (FP_IS_DEVICE (device), FALSE); + + fp_device_close (device, cancellable, async_result_ready, &task); + while (!task) + g_main_context_iteration (NULL, TRUE); + + return fp_device_close_finish (device, task, error); +} + +/** + * fp_device_enroll_sync: + * @device: a #FpDevice + * @template_print: (transfer floating): A #FpPrint to fill in or use + * as a template. + * @cancellable: (nullable): a #GCancellable, or %NULL + * @progress_cb: (nullable) (scope call): progress reporting callback + * @progress_data: user data for @progress_cb + * @error: Return location for errors, or %NULL to ignore + * + * Enroll a new print. See fp_device_enroll(). It is undefined whether + * @template_print is updated or a newly created #FpPrint is returned. + * + * Returns:(transfer full): A #FpPrint on success, %NULL otherwise + */ +FpPrint * +fp_device_enroll_sync (FpDevice *device, + FpPrint *template_print, + GCancellable *cancellable, + FpEnrollProgress progress_cb, + gpointer progress_data, + GError **error) +{ + g_autoptr(GAsyncResult) task = NULL; + + g_return_val_if_fail (FP_IS_DEVICE (device), FALSE); + + fp_device_enroll (device, template_print, cancellable, + progress_cb, progress_data, NULL, + async_result_ready, &task); + while (!task) + g_main_context_iteration (NULL, TRUE); + + return fp_device_enroll_finish (device, task, error); +} + +/** + * fp_device_verify_sync: + * @device: a #FpDevice + * @enrolled_print: a #FpPrint to verify + * @cancellable: (nullable): a #GCancellable, or %NULL + * @match: (out): Whether the user presented the correct finger + * @print: (out) (transfer full) (nullable): Location to store the scanned print, or %NULL to ignore + * @error: Return location for errors, or %NULL to ignore + * + * Verify a given print synchronously. + * + * Returns: (type void): %FALSE on error, %TRUE otherwise + */ +gboolean +fp_device_verify_sync (FpDevice *device, + FpPrint *enrolled_print, + GCancellable *cancellable, + gboolean *match, + FpPrint **print, + GError **error) +{ + g_autoptr(GAsyncResult) task = NULL; + + g_return_val_if_fail (FP_IS_DEVICE (device), FALSE); + + fp_device_verify (device, + enrolled_print, + cancellable, + async_result_ready, &task); + while (!task) + g_main_context_iteration (NULL, TRUE); + + return fp_device_verify_finish (device, task, match, print, error); +} + +/** + * fp_device_identify_sync: + * @device: a #FpDevice + * @prints: (element-type FpPrint) (transfer none): #GPtrArray of #FpPrint + * @cancellable: (nullable): a #GCancellable, or %NULL + * @match: (out) (transfer full) (nullable): Location for the matched #FpPrint, or %NULL + * @print: (out) (transfer full) (nullable): Location for the new #FpPrint, or %NULL + * @error: Return location for errors, or %NULL to ignore + * + * Identify a print synchronously. + * + * Returns: (type void): %FALSE on error, %TRUE otherwise + */ +gboolean +fp_device_identify_sync (FpDevice *device, + GPtrArray *prints, + GCancellable *cancellable, + FpPrint **match, + FpPrint **print, + GError **error) +{ + g_autoptr(GAsyncResult) task = NULL; + + g_return_val_if_fail (FP_IS_DEVICE (device), FALSE); + + fp_device_identify (device, + prints, + cancellable, + async_result_ready, &task); + while (!task) + g_main_context_iteration (NULL, TRUE); + + return fp_device_identify_finish (device, task, match, print, error); +} + + +/** + * fp_device_capture_sync: + * @device: a #FpDevice + * @wait_for_finger: Whether to wait for a finger or not + * @cancellable: (nullable): a #GCancellable, or %NULL + * @error: Return location for errors, or %NULL to ignore + * + * Start an synchronous operation to capture an image. + * + * Returns: (transfer full): A new #FpImage or %NULL on error + */ +FpImage * +fp_device_capture_sync (FpDevice *device, + gboolean wait_for_finger, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GAsyncResult) task = NULL; + + g_return_val_if_fail (FP_IS_DEVICE (device), FALSE); + + fp_device_capture (device, + wait_for_finger, + cancellable, + async_result_ready, &task); + while (!task) + g_main_context_iteration (NULL, TRUE); + + return fp_device_capture_finish (device, task, error); +} + +/** + * fp_device_delete_print_sync: + * @device: a #FpDevice + * @enrolled_print: a #FpPrint to verify + * @cancellable: (nullable): a #GCancellable, or %NULL + * @error: Return location for errors, or %NULL to ignore + * + * Delete a given print from the device. + * + * Returns: %FALSE on error, %TRUE otherwise + */ +gboolean +fp_device_delete_print_sync (FpDevice *device, + FpPrint *enrolled_print, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GAsyncResult) task = NULL; + + g_return_val_if_fail (FP_IS_DEVICE (device), FALSE); + + fp_device_delete_print (device, + enrolled_print, + cancellable, + async_result_ready, &task); + while (!task) + g_main_context_iteration (NULL, TRUE); + + return fp_device_delete_print_finish (device, task, error); +} + +/** + * fp_device_list_prints_sync: + * @device: a #FpDevice + * @cancellable: (nullable): a #GCancellable, or %NULL + * @error: Return location for errors, or %NULL to ignore + * + * List device stored prints synchronously. + * + * Returns: (element-type FpPrint) (transfer container): Array of prints, or %NULL on error + */ +GPtrArray * +fp_device_list_prints_sync (FpDevice *device, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GAsyncResult) task = NULL; + + g_return_val_if_fail (FP_IS_DEVICE (device), FALSE); + + fp_device_list_prints (device, + NULL, + async_result_ready, &task); + while (!task) + g_main_context_iteration (NULL, TRUE); + + return fp_device_list_prints_finish (device, task, error); +} diff --git a/libfprint/fp-device.h b/libfprint/fp-device.h new file mode 100644 index 00000000..821514d7 --- /dev/null +++ b/libfprint/fp-device.h @@ -0,0 +1,255 @@ +/* + * FpDevice - A fingerprint reader device + * Copyright (C) 2019 Benjamin Berg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#pragma once + +#include "fp-image.h" +#include +#include + +G_BEGIN_DECLS + +#define FP_TYPE_DEVICE (fp_device_get_type ()) +#define FP_DEVICE_RETRY (fp_device_retry_quark ()) +#define FP_DEVICE_ERROR (fp_device_error_quark ()) +G_DECLARE_DERIVABLE_TYPE (FpDevice, fp_device, FP, DEVICE, GObject) + +#include "fp-print.h" + +/* NOTE: We keep the class struct private! */ + +/** + * FpDeviceType: + * @FP_DEVICE_TYPE_VIRTUAL: The device is a virtual device + * @FP_DEVICE_TYPE_USB: The device is a USB device + */ +typedef enum { + FP_DEVICE_TYPE_VIRTUAL, + FP_DEVICE_TYPE_USB, +} FpDeviceType; + +/** + * FpScanType: + * @FP_SCAN_TYPE_SWIPE: Sensor requires swiping the finger. + * @FP_SCAN_TYPE_PRESS: Sensor requires placing/pressing down the finger. + */ +typedef enum { + FP_SCAN_TYPE_SWIPE, + FP_SCAN_TYPE_PRESS, +} FpScanType; + +/** + * FpDeviceRetry: + * @FP_DEVICE_RETRY_GENERAL: The scan did not succeed due to poor scan quality + * or other general user scanning problem. + * @FP_DEVICE_RETRY_TOO_SHORT: The scan did not succeed because the finger + * swipe was too short. + * @FP_DEVICE_RETRY_CENTER_FINGER: The scan did not succeed because the finger + * was not centered on the scanner. + * @FP_DEVICE_RETRY_REMOVE_FINGER: The scan did not succeed due to quality or + * pressure problems; the user should remove their finger from the scanner + * before retrying. + * + * Error codes representing scan failures resulting in the user needing to + * retry. + */ +typedef enum { + FP_DEVICE_RETRY_GENERAL, + FP_DEVICE_RETRY_TOO_SHORT, + FP_DEVICE_RETRY_CENTER_FINGER, + FP_DEVICE_RETRY_REMOVE_FINGER, +} FpDeviceRetry; + +/** + * FpDeviceError: + * @FP_DEVICE_ERROR_GENERAL: A general error occured. + * @FP_DEVICE_ERROR_NOT_SUPPORTED: The device does not support the requested + * operation. + * @FP_DEVICE_ERROR_NOT_OPEN: The device needs to be opened to start this + * operation. + * @FP_DEVICE_ERROR_ALREADY_OPEN: The device has already been opened. + * @FP_DEVICE_ERROR_BUSY: The device is busy with another request. + * @FP_DEVICE_ERROR_PROTO: Protocol error + * @FP_DEVICE_ERROR_DATA_INVALID: The passed data is invalid + * @FP_DEVICE_ERROR_DATA_NOT_FOUND: Requested print was not found on device + * @FP_DEVICE_ERROR_DATA_FULL: No space on device available for operation + * + * Error codes for device operations. More specific errors from other domains + * such as #G_IO_ERROR or #G_USB_DEVICE_ERROR may also be reported. + */ +typedef enum { + FP_DEVICE_ERROR_GENERAL, + FP_DEVICE_ERROR_NOT_SUPPORTED, + FP_DEVICE_ERROR_NOT_OPEN, + FP_DEVICE_ERROR_ALREADY_OPEN, + FP_DEVICE_ERROR_BUSY, + FP_DEVICE_ERROR_PROTO, + FP_DEVICE_ERROR_DATA_INVALID, + FP_DEVICE_ERROR_DATA_NOT_FOUND, + FP_DEVICE_ERROR_DATA_FULL, +} FpDeviceError; + +GQuark fp_device_retry_quark (void); +GQuark fp_device_error_quark (void); + +/** + * FpEnrollProgress: + * @device: a #FpDevice + * @completed_stages: Number of completed stages + * @print: (nullable): The last scaned print + * @user_data: (nullable): User provided data + * @error: (nullable) (transfer none): #GError or %NULL + * + * The passed error is guaranteed to be of type %FP_DEVICE_RETRY if set. + */ +typedef void (*FpEnrollProgress) (FpDevice *device, + gint completed_stages, + FpPrint *print, + gpointer user_data, + GError *error); + + +const gchar *fp_device_get_driver (FpDevice *device); +const gchar *fp_device_get_device_id (FpDevice *device); +const gchar *fp_device_get_name (FpDevice *device); +FpScanType fp_device_get_scan_type (FpDevice *device); +gint fp_device_get_nr_enroll_stages (FpDevice *device); + +gboolean fp_device_supports_identify (FpDevice *device); +gboolean fp_device_supports_capture (FpDevice *device); +gboolean fp_device_has_storage (FpDevice *device); + +/* Opening the device */ +void fp_device_open (FpDevice *device, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +void fp_device_close (FpDevice *device, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +void fp_device_enroll (FpDevice *device, + FpPrint *template_print, + GCancellable *cancellable, + FpEnrollProgress progress_cb, + gpointer progress_data, + GDestroyNotify progress_destroy, + GAsyncReadyCallback callback, + gpointer user_data); + +void fp_device_verify (FpDevice *device, + FpPrint *enrolled_print, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +void fp_device_identify (FpDevice *device, + GPtrArray *prints, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +void fp_device_capture (FpDevice *device, + gboolean wait_for_finger, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +void fp_device_delete_print (FpDevice *device, + FpPrint *enrolled_print, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +void fp_device_list_prints (FpDevice *device, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean fp_device_open_finish (FpDevice *device, + GAsyncResult *result, + GError **error); +gboolean fp_device_close_finish (FpDevice *device, + GAsyncResult *result, + GError **error); +FpPrint *fp_device_enroll_finish (FpDevice *device, + GAsyncResult *result, + GError **error); +gboolean fp_device_verify_finish (FpDevice *device, + GAsyncResult *result, + gboolean *match, + FpPrint **print, + GError **error); +gboolean fp_device_identify_finish (FpDevice *device, + GAsyncResult *result, + FpPrint **match, + FpPrint **print, + GError **error); +FpImage * fp_device_capture_finish (FpDevice *device, + GAsyncResult *result, + GError **error); +gboolean fp_device_delete_print_finish (FpDevice *device, + GAsyncResult *result, + GError **error); +GPtrArray * fp_device_list_prints_finish (FpDevice *device, + GAsyncResult *result, + GError **error); + + +gboolean fp_device_open_sync (FpDevice *device, + GCancellable *cancellable, + GError **error); +gboolean fp_device_close_sync (FpDevice *device, + GCancellable *cancellable, + GError **error); +FpPrint * fp_device_enroll_sync (FpDevice *device, + FpPrint *template_print, + GCancellable *cancellable, + FpEnrollProgress progress_cb, + gpointer progress_data, + GError **error); +gboolean fp_device_verify_sync (FpDevice *device, + FpPrint *enrolled_print, + GCancellable *cancellable, + gboolean *match, + FpPrint **print, + GError **error); +gboolean fp_device_identify_sync (FpDevice *device, + GPtrArray *prints, + GCancellable *cancellable, + FpPrint **match, + FpPrint **print, + GError **error); +FpImage * fp_device_capture_sync (FpDevice *device, + gboolean wait_for_finger, + GCancellable *cancellable, + GError **error); +gboolean fp_device_delete_print_sync (FpDevice *device, + FpPrint *enrolled_print, + GCancellable *cancellable, + GError **error); +GPtrArray * fp_device_list_prints_sync (FpDevice *device, + GCancellable *cancellable, + GError **error); + + +G_END_DECLS diff --git a/libfprint/fp-image-device.c b/libfprint/fp-image-device.c new file mode 100644 index 00000000..8524e069 --- /dev/null +++ b/libfprint/fp-image-device.c @@ -0,0 +1,795 @@ +/* + * FpImageDevice - An image based fingerprint reader device + * Copyright (C) 2019 Benjamin Berg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define FP_COMPONENT "image_device" +#include "fpi-log.h" + +#include "fpi-image-device.h" +#include "fpi-print.h" +#include "fpi-image.h" + +#define MIN_ACCEPTABLE_MINUTIAE 10 +#define BOZORTH3_DEFAULT_THRESHOLD 40 +#define IMG_ENROLL_STAGES 5 + +/** + * SECTION: fp-image-device + * @title: FpImageDevice + * @short_description: Image device subclass + * + * This is a helper class for the commonly found image based devices. + */ + +/** + * SECTION: fpi-image-device + * @title: Internal FpImageDevice + * @short_description: Internal image device routines + * + * See #FpImageDeviceClass for more details. Also see the public + * #FpImageDevice routines. + */ + +typedef struct +{ + FpImageDeviceState state; + gboolean active; + + gint enroll_stage; + + guint pending_activation_timeout_id; + gboolean pending_activation_timeout_waiting_finger_off; + + gint bz3_threshold; +} FpImageDevicePrivate; + +G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (FpImageDevice, fp_image_device, FP_TYPE_DEVICE) + + +/*******************************************************/ + +/* TODO: + * - sanitize_image seems a bit odd, in particular the sizing stuff. + **/ + +/* Static helper functions */ + +static void +fp_image_device_change_state (FpImageDevice *self, FpImageDeviceState state) +{ + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self); + + /* Cannot change to inactive using this function. */ + g_assert (state != FP_IMAGE_DEVICE_STATE_INACTIVE); + + /* We might have been waiting for the finger to go OFF to start the + * next operation. */ + if (priv->pending_activation_timeout_id) + { + g_source_remove (priv->pending_activation_timeout_id); + priv->pending_activation_timeout_id = 0; + } + + fp_dbg ("Image device internal state change from %d to %d\n", priv->state, state); + + priv->state = state; + + /* change_state is the only callback which is optional and does not + * have a default implementation. */ + if (cls->change_state) + cls->change_state (self, state); +} + +static void +fp_image_device_activate (FpImageDevice *self) +{ + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self); + + g_assert (!priv->active); + + /* We don't have a neutral ACTIVE state, but we always will + * go into WAIT_FINGER_ON afterwards. */ + priv->state = FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON; + + /* We might have been waiting for deactivation to finish before + * starting the next operation. */ + if (priv->pending_activation_timeout_id) + { + g_source_remove (priv->pending_activation_timeout_id); + priv->pending_activation_timeout_id = 0; + } + + fp_dbg ("Activating image device\n"); + cls->activate (self); +} + +static void +fp_image_device_deactivate (FpDevice *device) +{ + FpImageDevice *self = FP_IMAGE_DEVICE (device); + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (device); + + if (!priv->active) + { + /* XXX: We currently deactivate both from minutiae scan result + * and finger off report. */ + fp_dbg ("Already deactivated, ignoring request."); + return; + } + priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE; + + fp_dbg ("Deactivating image device\n"); + cls->deactivate (self); +} + +static gboolean +pending_activation_timeout (gpointer user_data) +{ + FpImageDevice *self = FP_IMAGE_DEVICE (user_data); + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + + priv->pending_activation_timeout_id = 0; + + if (priv->pending_activation_timeout_waiting_finger_off) + fpi_device_action_error (FP_DEVICE (self), + fpi_device_retry_new_msg (FP_DEVICE_RETRY_REMOVE_FINGER, + "Remove finger before requesting another scan operation")); + else + fpi_device_action_error (FP_DEVICE (self), + fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); + + return G_SOURCE_REMOVE; +} + +/* Callbacks/vfuncs */ +static void +fp_image_device_open (FpDevice *device) +{ + FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (device); + + /* Nothing special about opening an image device, just + * forward the request. */ + cls->img_open (FP_IMAGE_DEVICE (device)); +} + +static void +fp_image_device_close (FpDevice *device) +{ + FpImageDevice *self = FP_IMAGE_DEVICE (device); + FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self); + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + + /* In the close case we may need to wait/force deactivation first. + * Three possible cases: + * 1. We are inactive + * -> immediately close + * 2. We are waiting for finger off + * -> imediately deactivate + * 3. We are deactivating + * -> handled by deactivate_complete */ + + if (!priv->active) + cls->img_close (self); + else if (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE) + fp_image_device_deactivate (device); +} + +static void +fp_image_device_cancel_action (FpDevice *device) +{ + FpImageDevice *self = FP_IMAGE_DEVICE (device); + FpDeviceAction action; + + action = fpi_device_get_current_action (device); + + /* We can only cancel capture operations, in that case, deactivate and return + * an error immediately. */ + if (action == FP_DEVICE_ACTION_ENROLL || + action == FP_DEVICE_ACTION_VERIFY || + action == FP_DEVICE_ACTION_IDENTIFY || + action == FP_DEVICE_ACTION_CAPTURE) + { + fp_image_device_deactivate (FP_DEVICE (self)); + + /* XXX: Some nicer way of doing this would be good. */ + fpi_device_action_error (FP_DEVICE (self), + g_error_new (G_IO_ERROR, + G_IO_ERROR_CANCELLED, + "Device operation was cancelled")); + } +} + +static void +fp_image_device_start_capture_action (FpDevice *device) +{ + FpImageDevice *self = FP_IMAGE_DEVICE (device); + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + FpDeviceAction action; + + /* There is just one action that we cannot support out + * of the box, which is a capture without first waiting + * for a finger to be on the device. + */ + action = fpi_device_get_current_action (device); + if (action == FP_DEVICE_ACTION_CAPTURE) + { + gboolean wait_for_finger; + + fpi_device_get_capture_data (device, &wait_for_finger); + + if (!wait_for_finger) + { + fpi_device_action_error (device, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED)); + return; + } + } + else if (action == FP_DEVICE_ACTION_ENROLL) + { + FpPrint *enroll_print = NULL; + + fpi_device_get_enroll_data (device, &enroll_print); + fpi_print_set_type (enroll_print, FP_PRINT_NBIS); + } + + priv->enroll_stage = 0; + + /* The device might still be deactivating from a previous call. + * In that situation, try to wait for a bit before reporting back an + * error (which will usually say that the user should remove the + * finger). + */ + if (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE || priv->active) + { + g_debug ("Got a new request while the device was still active"); + g_assert (priv->pending_activation_timeout_id == 0); + priv->pending_activation_timeout_id = + g_timeout_add (100, pending_activation_timeout, device); + + if (priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF) + priv->pending_activation_timeout_waiting_finger_off = TRUE; + else + priv->pending_activation_timeout_waiting_finger_off = FALSE; + + return; + } + + /* And activate the device; we rely on fpi_image_device_activate_complete() + * to be called when done (or immediately). */ + fp_image_device_activate (self); +} + + +/*********************************************************/ + +static void +fp_image_device_finalize (GObject *object) +{ + FpImageDevice *self = (FpImageDevice *) object; + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + + g_assert (priv->active == FALSE); + + G_OBJECT_CLASS (fp_image_device_parent_class)->finalize (object); +} + +static void +fp_image_device_default_activate (FpImageDevice *self) +{ + fpi_image_device_activate_complete (self, NULL); +} + +static void +fp_image_device_default_deactivate (FpImageDevice *self) +{ + fpi_image_device_deactivate_complete (self, NULL); +} + +static void +fp_image_device_class_init (FpImageDeviceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FpDeviceClass *fp_device_class = FP_DEVICE_CLASS (klass); + + object_class->finalize = fp_image_device_finalize; + + fp_device_class->open = fp_image_device_open; + fp_device_class->close = fp_image_device_close; + fp_device_class->enroll = fp_image_device_start_capture_action; + fp_device_class->verify = fp_image_device_start_capture_action; + fp_device_class->identify = fp_image_device_start_capture_action; + fp_device_class->capture = fp_image_device_start_capture_action; + + fp_device_class->cancel = fp_image_device_cancel_action; + + /* Default implementations */ + klass->activate = fp_image_device_default_activate; + klass->deactivate = fp_image_device_default_deactivate; +} + +static void +fp_image_device_init (FpImageDevice *self) +{ + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self); + + /* Set default values. */ + fpi_device_set_nr_enroll_stages (FP_DEVICE (self), IMG_ENROLL_STAGES); + + priv->bz3_threshold = BOZORTH3_DEFAULT_THRESHOLD; + if (cls->bz3_threshold > 0) + priv->bz3_threshold = cls->bz3_threshold; + +} + +static void +fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(FpImage) image = FP_IMAGE (source_object); + GError *error = NULL; + FpPrint *print = NULL; + FpDevice *device = FP_DEVICE (user_data); + FpImageDevicePrivate *priv; + FpDeviceAction action; + + /* Note: We rely on the device to not disappear during an operation. */ + + if (!fp_image_detect_minutiae_finish (image, res, &error)) + { + /* Cancel operation . */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + fpi_device_action_error (device, g_steal_pointer (&error)); + fp_image_device_deactivate (device); + return; + } + + /* Replace error with a retry condition. */ + g_warning ("Failed to detect minutiae: %s", error->message); + g_clear_pointer (&error, g_error_free); + + error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_GENERAL, "Minutiae detection failed, please retry"); + } + + priv = fp_image_device_get_instance_private (FP_IMAGE_DEVICE (device)); + action = fpi_device_get_current_action (device); + + if (action == FP_DEVICE_ACTION_CAPTURE) + { + fpi_device_capture_complete (device, g_steal_pointer (&image), error); + fp_image_device_deactivate (device); + return; + } + + if (!error) + { + print = fp_print_new (device); + fpi_print_set_type (print, FP_PRINT_NBIS); + if (!fpi_print_add_from_image (print, image, &error)) + g_clear_object (&print); + } + + if (action == FP_DEVICE_ACTION_ENROLL) + { + FpPrint *enroll_print; + fpi_device_get_enroll_data (device, &enroll_print); + + if (print) + { + fpi_print_add_print (enroll_print, print); + priv->enroll_stage += 1; + } + + fpi_device_enroll_progress (device, priv->enroll_stage, print, error); + + if (priv->enroll_stage == IMG_ENROLL_STAGES) + { + fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL); + fp_image_device_deactivate (device); + } + } + else if (action == FP_DEVICE_ACTION_VERIFY) + { + FpPrint *template; + FpiMatchResult result; + + fpi_device_get_verify_data (device, &template); + if (print) + result = fpi_print_bz3_match (template, print, priv->bz3_threshold, &error); + else + result = FPI_MATCH_ERROR; + + fpi_device_verify_complete (device, result, print, error); + fp_image_device_deactivate (device); + } + else if (action == FP_DEVICE_ACTION_IDENTIFY) + { + gint i; + GPtrArray *templates; + FpPrint *result = NULL; + + fpi_device_get_identify_data (device, &templates); + for (i = 0; !error && i < templates->len; i++) + { + FpPrint *template = g_ptr_array_index (templates, i); + + if (fpi_print_bz3_match (template, print, priv->bz3_threshold, &error) == FPI_MATCH_SUCCESS) + { + result = g_object_ref (template); + break; + } + } + + fpi_device_identify_complete (device, result, print, error); + fp_image_device_deactivate (device); + } + else + { + /* XXX: This can be hit currently due to a race condition in the enroll code! + * In that case we scan a further image even though the minutiae for the previous + * one have not yet been detected. + * We need to keep track on the pending minutiae detection and the fact that + * it will finish eventually (or we may need to retry on error and activate the + * device again). */ + g_assert_not_reached (); + } +} + +/*********************************************************/ +/* Private API */ + +/** + * fpi_image_device_set_bz3_threshold: + * @self: a #FpImageDevice imaging fingerprint device + * @bz3_threshold: BZ3 threshold to use + * + * Dynamically adjust the bz3 threshold. This is only needed for drivers + * that support devices with different properties. It should generally be + * called from the probe callback, but is acceptable to call from the open + * callback. + */ +void +fpi_image_device_set_bz3_threshold (FpImageDevice *self, + gint bz3_threshold) +{ + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + + g_return_if_fail (FP_IS_IMAGE_DEVICE (self)); + g_return_if_fail (bz3_threshold > 0); + + priv->bz3_threshold = bz3_threshold; +} + +/** + * fpi_image_device_report_finger_status: + * @self: a #FpImageDevice imaging fingerprint device + * @present: whether the finger is present on the sensor + * + * Reports from the driver whether the user's finger is on + * the sensor. + */ +void +fpi_image_device_report_finger_status (FpImageDevice *self, + gboolean present) +{ + FpDevice *device = FP_DEVICE (self); + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + FpDeviceAction action; + + action = fpi_device_get_current_action (device); + + if (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE) + { + /* Do we really want to always ignore such reports? We could + * also track the state in case the user had the finger on + * the device at initialisation time and the driver reports + * this early. + */ + g_debug ("Ignoring finger presence report as the device is not active!"); + return; + } + + action = fpi_device_get_current_action (device); + + g_assert (action != FP_DEVICE_ACTION_OPEN); + g_assert (action != FP_DEVICE_ACTION_CLOSE); + + g_debug ("Image device reported finger status: %s", present ? "on" : "off"); + + if (present && priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON) + { + fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_CAPTURE); + } + else if (!present && priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF) + { + /* We need to deactivate or continue to await finger */ + + /* There are three possible situations: + * 1. We are deactivating the device and the action is still in progress + * (minutiae detection). + * 2. We are still deactivating the device after an action completed + * 3. We were waiting for finger removal to start the new action + * Either way, we always end up deactivating except for the enroll case. + * XXX: This is not quite correct though, as we assume we need another finger + * scan even though we might be processing the last one (successfully). + */ + if (action != FP_DEVICE_ACTION_ENROLL) + fp_image_device_deactivate (device); + else + fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON); + } +} + +/** + * fpi_image_device_image_captured: + * @self: a #FpImageDevice imaging fingerprint device + * @image: whether the finger is present on the sensor + * + * Reports an image capture. Only use this function if the image was + * captured successfully. If there was an issue where the user should + * retry, use fpi_image_device_retry_scan() to report the retry condition. + * + * In the event of a fatal error for the operation use + * fpi_image_device_session_error(). This will abort the entire operation + * including e.g. an enroll operation which captures multiple images during + * one session. + */ +void +fpi_image_device_image_captured (FpImageDevice *self, FpImage *image) +{ + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + FpDeviceAction action; + + action = fpi_device_get_current_action (FP_DEVICE (self)); + + g_return_if_fail (image != NULL); + g_return_if_fail (priv->state == FP_IMAGE_DEVICE_STATE_CAPTURE); + g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL || + action == FP_DEVICE_ACTION_VERIFY || + action == FP_DEVICE_ACTION_IDENTIFY || + action == FP_DEVICE_ACTION_CAPTURE); + + fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF); + + g_debug ("Image device captured an image"); + + /* XXX: We also detect minutiae in capture mode, we solely do this + * to normalize the image which will happen as a by-product. */ + fp_image_detect_minutiae (image, + fpi_device_get_cancellable (FP_DEVICE (self)), + fpi_image_device_minutiae_detected, + self); +} + +/** + * fpi_image_device_retry_scan: + * @self: a #FpImageDevice imaging fingerprint device + * @retry: The #FpDeviceRetry error code to report + * + * Reports a scan failure to the user. This may or may not abort the + * current session. It is the equivalent of fpi_image_device_image_captured() + * in the case of a retryable error condition (e.g. short swipe). + */ +void +fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry) +{ + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + FpDeviceAction action; + GError *error; + + action = fpi_device_get_current_action (FP_DEVICE (self)); + + /* We might be waiting for a finger at this point, so just accept + * all but INACTIVE */ + g_return_if_fail (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE); + g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL || + action == FP_DEVICE_ACTION_VERIFY || + action == FP_DEVICE_ACTION_IDENTIFY || + action == FP_DEVICE_ACTION_CAPTURE); + + error = fpi_device_retry_new (retry); + + if (action == FP_DEVICE_ACTION_ENROLL) + { + g_debug ("Reporting retry during enroll"); + fpi_device_enroll_progress (FP_DEVICE (self), priv->enroll_stage, NULL, error); + } + else + { + /* We abort the operation and let the surrounding code retry in the + * non-enroll case (this is identical to a session error). */ + g_debug ("Abort current operation due to retry (non-enroll case)"); + fp_image_device_deactivate (FP_DEVICE (self)); + fpi_device_action_error (FP_DEVICE (self), error); + } +} + +/** + * fpi_image_device_session_error: + * @self: a #FpImageDevice imaging fingerprint device + * @error: The #GError to report + * + * Report an error while interacting with the device. This effectively + * aborts the current ongoing action. + */ +void +fpi_image_device_session_error (FpImageDevice *self, GError *error) +{ + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + + g_return_if_fail (self); + + if (!error) + { + g_warning ("Driver did not provide an error, generating a generic one"); + error = g_error_new (FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL, "Driver reported session error without an error"); + } + + if (!priv->active) + { + FpDeviceAction action = fpi_device_get_current_action (FP_DEVICE (self)); + g_warning ("Driver reported session error, but device is inactive."); + + if (action != FP_DEVICE_ACTION_NONE) + { + g_warning ("Translating to activation failure!"); + fpi_image_device_activate_complete (self, error); + return; + } + } + else if (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE) + { + g_warning ("Driver reported session error; translating to deactivation failure."); + fpi_image_device_deactivate_complete (self, error); + return; + } + + if (error->domain == FP_DEVICE_RETRY) + g_warning ("Driver should report retries using fpi_image_device_retry_scan!"); + + fp_image_device_deactivate (FP_DEVICE (self)); + fpi_device_action_error (FP_DEVICE (self), error); +} + +/** + * fpi_image_device_activate_complete: + * @self: a #FpImageDevice imaging fingerprint device + * @error: A #GError or %NULL on success + * + * Reports completion of device activation. + */ +void +fpi_image_device_activate_complete (FpImageDevice *self, GError *error) +{ + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + FpDeviceAction action; + + action = fpi_device_get_current_action (FP_DEVICE (self)); + + g_return_if_fail (priv->active == FALSE); + g_return_if_fail (action == FP_DEVICE_ACTION_ENROLL || + action == FP_DEVICE_ACTION_VERIFY || + action == FP_DEVICE_ACTION_IDENTIFY || + action == FP_DEVICE_ACTION_CAPTURE); + + if (error) + { + g_debug ("Image device activation failed"); + fpi_device_action_error (FP_DEVICE (self), error); + return; + } + + g_debug ("Image device activation completed"); + + priv->active = TRUE; + + /* We always want to capture at this point, move to AWAIT_FINGER + * state. */ + fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON); +} + +/** + * fpi_image_device_deactivate_complete: + * @self: a #FpImageDevice imaging fingerprint device + * @error: A #GError or %NULL on success + * + * Reports completion of device deactivation. + */ +void +fpi_image_device_deactivate_complete (FpImageDevice *self, GError *error) +{ + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self); + FpDeviceAction action; + + g_return_if_fail (priv->active == TRUE); + g_return_if_fail (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE); + + g_debug ("Image device deactivation completed"); + + priv->active = FALSE; + + /* Deactivation completed. As we deactivate in the background + * there may already be a new task pending. Check whether we + * need to do anything. */ + action = fpi_device_get_current_action (FP_DEVICE (self)); + + /* Special case, if we should be closing, but didn't due to a running + * deactivation, then do so now. */ + if (action == FP_DEVICE_ACTION_CLOSE) + { + cls->img_close (self); + return; + } + + /* We might be waiting to be able to activate again. */ + if (priv->pending_activation_timeout_id) + fp_image_device_activate (self); +} + +/** + * fpi_image_device_open_complete: + * @self: a #FpImageDevice imaging fingerprint device + * @error: A #GError or %NULL on success + * + * Reports completion of open operation. + */ +void +fpi_image_device_open_complete (FpImageDevice *self, GError *error) +{ + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + FpDeviceAction action; + + action = fpi_device_get_current_action (FP_DEVICE (self)); + + g_return_if_fail (priv->active == FALSE); + g_return_if_fail (action == FP_DEVICE_ACTION_OPEN); + + g_debug ("Image device open completed"); + + priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE; + + fpi_device_open_complete (FP_DEVICE (self), error); +} + +/** + * fpi_image_device_close_complete: + * @self: a #FpImageDevice imaging fingerprint device + * @error: A #GError or %NULL on success + * + * Reports completion of close operation. + */ +void +fpi_image_device_close_complete (FpImageDevice *self, GError *error) +{ + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + FpDeviceAction action; + + action = fpi_device_get_current_action (FP_DEVICE (self)); + + g_debug ("Image device close completed"); + + g_return_if_fail (priv->active == FALSE); + g_return_if_fail (action == FP_DEVICE_ACTION_CLOSE); + + priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE; + + fpi_device_close_complete (FP_DEVICE (self), error); +} diff --git a/libfprint/fpi-data.h b/libfprint/fp-image-device.h similarity index 57% rename from libfprint/fpi-data.h rename to libfprint/fp-image-device.h index 37a7911a..1eda8fbc 100644 --- a/libfprint/fpi-data.h +++ b/libfprint/fp-image-device.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2007-2008 Daniel Drake - * Copyright (C) 2018 Bastien Nocera + * FpImageDevice - An image based fingerprint reader device + * Copyright (C) 2019 Benjamin Berg * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,18 +17,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __FPI_DATA_H__ -#define __FPI_DATA_H__ +#pragma once -struct fp_print_data; -struct fp_print_data_item { - size_t length; - unsigned char data[0]; -}; +#include -struct fp_print_data *fpi_print_data_new(struct fp_dev *dev); -struct fp_print_data_item *fpi_print_data_item_new(size_t length); -struct fp_print_data_item *fpi_print_data_get_item(struct fp_print_data *data); -void fpi_print_data_add_item(struct fp_print_data *data, struct fp_print_data_item *item); +G_BEGIN_DECLS -#endif +#define FP_TYPE_IMAGE_DEVICE (fp_image_device_get_type ()) +G_DECLARE_DERIVABLE_TYPE (FpImageDevice, fp_image_device, FP, IMAGE_DEVICE, FpDevice) + +G_END_DECLS diff --git a/libfprint/fp-image.c b/libfprint/fp-image.c new file mode 100644 index 00000000..4b8b3cd1 --- /dev/null +++ b/libfprint/fp-image.c @@ -0,0 +1,610 @@ +/* + * FPrint Image + * Copyright (C) 2007 Daniel Drake + * Copyright (C) 2019 Benjamin Berg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "fpi-image.h" + +#include "nbis/include/lfs.h" + +#if HAVE_PIXMAN +#include +#endif + +/** + * SECTION: fp-image + * @title: FpImage + * @short_description: Internal Image handling routines + * + * Some devices will provide the image data corresponding to a print + * this object allows accessing this data. + */ + +/** + * SECTION: fpi-image + * @title: Internal FpImage + * @short_description: Internal image handling routines + * + * Internal image handling routines. Also see the public FpImage routines. + */ + +G_DEFINE_TYPE (FpImage, fp_image, G_TYPE_OBJECT) + +enum { + PROP_0, + PROP_WIDTH, + PROP_HEIGHT, + N_PROPS +}; + +static GParamSpec *properties[N_PROPS]; + +FpImage * +fp_image_new (gint width, gint height) +{ + return g_object_new (FP_TYPE_IMAGE, + "width", width, + "height", height, + NULL); +} + +static void +fp_image_finalize (GObject *object) +{ + FpImage *self = (FpImage *) object; + + g_clear_pointer (&self->data, g_free); + g_clear_pointer (&self->binarized, g_free); + g_clear_pointer (&self->minutiae, g_ptr_array_unref); + + G_OBJECT_CLASS (fp_image_parent_class)->finalize (object); +} + +static void +fp_image_constructed (GObject *object) +{ + FpImage *self = (FpImage *) object; + + self->data = g_malloc0 (self->width * self->height); +} + +static void +fp_image_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + FpImage *self = FP_IMAGE (object); + + switch (prop_id) + { + case PROP_WIDTH: + g_value_set_uint (value, self->width); + break; + + case PROP_HEIGHT: + g_value_set_uint (value, self->height); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +fp_image_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + FpImage *self = FP_IMAGE (object); + + switch (prop_id) + { + case PROP_WIDTH: + self->width = g_value_get_uint (value); + break; + + case PROP_HEIGHT: + self->height = g_value_get_uint (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +fp_image_class_init (FpImageClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = fp_image_finalize; + object_class->constructed = fp_image_constructed; + object_class->set_property = fp_image_set_property; + object_class->get_property = fp_image_get_property; + + properties[PROP_WIDTH] = + g_param_spec_uint ("width", + "Width", + "The width of the image", + 0, + G_MAXUINT16, + 0, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + properties[PROP_HEIGHT] = + g_param_spec_uint ("height", + "Height", + "The height of the image", + 0, + G_MAXUINT16, + 0, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +fp_image_init (FpImage *self) +{ +} + +typedef struct +{ + GAsyncReadyCallback user_cb; + struct fp_minutiae *minutiae; + gint width, height; + gdouble ppmm; + FpiImageFlags flags; + guchar *image; + guchar *binarized; +} DetectMinutiaeData; + +static void +fp_image_detect_minutiae_free (DetectMinutiaeData *data) +{ + g_clear_pointer (&data->image, g_free); + g_clear_pointer (&data->minutiae, free_minutiae); + g_clear_pointer (&data->binarized, g_free); + g_free (data); +} + +static void +fp_image_detect_minutiae_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GTask *task = G_TASK (res); + FpImage *image; + DetectMinutiaeData *data = g_task_get_task_data (task); + GCancellable *cancellable; + + cancellable = g_task_get_cancellable (task); + if (!cancellable || !g_cancellable_is_cancelled (cancellable)) + { + gint i; + image = FP_IMAGE (source_object); + + image->flags = data->flags; + + g_clear_pointer (&image->data, g_free); + image->data = g_steal_pointer (&data->image); + + g_clear_pointer (&image->binarized, g_free); + image->binarized = g_steal_pointer (&data->binarized); + + g_clear_pointer (&image->minutiae, g_ptr_array_unref); + image->minutiae = g_ptr_array_new_full (data->minutiae->num, + (GDestroyNotify) free_minutia); + + for (i = 0; i < data->minutiae->num; i++) + g_ptr_array_add (image->minutiae, + g_steal_pointer (&data->minutiae->list[i])); + + /* Don't let it delete anything. */ + data->minutiae->num = 0; + } + + if (data->user_cb) + data->user_cb (source_object, res, user_data); +} + +static void +vflip (guint8 *data, gint width, gint height) +{ + int data_len = width * height; + unsigned char rowbuf[width]; + int i; + + for (i = 0; i < height / 2; i++) + { + int offset = i * width; + int swap_offset = data_len - (width * (i + 1)); + + /* copy top row into buffer */ + memcpy (rowbuf, data + offset, width); + + /* copy lower row over upper row */ + memcpy (data + offset, data + swap_offset, width); + + /* copy buffer over lower row */ + memcpy (data + swap_offset, rowbuf, width); + } +} + +static void +hflip (guint8 *data, gint width, gint height) +{ + unsigned char rowbuf[width]; + int i, j; + + for (i = 0; i < height; i++) + { + int offset = i * width; + + memcpy (rowbuf, data + offset, width); + for (j = 0; j < width; j++) + data[offset + j] = rowbuf[width - j - 1]; + } +} + +static void +invert_colors (guint8 *data, gint width, gint height) +{ + int data_len = width * height; + int i; + + for (i = 0; i < data_len; i++) + data[i] = 0xff - data[i]; +} + +static void +fp_image_detect_minutiae_thread_func (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + g_autoptr(GTimer) timer = NULL; + DetectMinutiaeData *data = task_data; + struct fp_minutiae *minutiae = NULL; + g_autofree gint *direction_map = NULL; + g_autofree gint *low_contrast_map = NULL; + g_autofree gint *low_flow_map = NULL; + g_autofree gint *high_curve_map = NULL; + g_autofree gint *quality_map = NULL; + g_autofree guchar *bdata = NULL; + gint map_w, map_h; + gint bw, bh, bd; + gint r; + + /* Normalize the image first */ + if (data->flags & FPI_IMAGE_H_FLIPPED) + hflip (data->image, data->width, data->height); + + if (data->flags & FPI_IMAGE_V_FLIPPED) + vflip (data->image, data->width, data->height); + + if (data->flags & FPI_IMAGE_COLORS_INVERTED) + invert_colors (data->image, data->width, data->height); + + data->flags &= ~(FPI_IMAGE_H_FLIPPED | FPI_IMAGE_V_FLIPPED | FPI_IMAGE_COLORS_INVERTED); + + timer = g_timer_new (); + r = get_minutiae (&minutiae, &quality_map, &direction_map, + &low_contrast_map, &low_flow_map, &high_curve_map, + &map_w, &map_h, &bdata, &bw, &bh, &bd, + data->image, data->width, data->height, 8, + data->ppmm, &g_lfsparms_V2); + g_timer_stop (timer); + fp_dbg ("Minutiae scan completed in %f secs", g_timer_elapsed (timer, NULL)); + + data->binarized = g_steal_pointer (&bdata); + data->minutiae = minutiae; + + if (r) + { + fp_err ("get minutiae failed, code %d", r); + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "Minutiae scan failed with code %d", r); + g_object_unref (task); + return; + } + + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +/** + * fp_image_get_height: + * @self: A #FpImage + * + * Gets the pixel height of an image. + * + * Returns: the height of the image + */ +guint +fp_image_get_height (FpImage *self) +{ + return self->height; +} + +/** + * fp_image_get_width: + * @self: A #FpImage + * + * Gets the pixel width of an image. + * + * Returns: the width of the image + */ +guint +fp_image_get_width (FpImage *self) +{ + return self->width; +} + +/** + * fp_image_get_ppmm: + * @self: A #FpImage + * + * Gets the resolution of the image. Note that this is assumed to + * be fixed to 500 points per inch (~19.685 p/mm) for most drivers. + * + * Returns: the resolution of the image in points per millimeter + */ +gdouble +fp_image_get_ppmm (FpImage *self) +{ + return self->ppmm; +} + +/** + * fp_image_get_data: + * @self: A #FpImage + * @len: (out) (optional): Return location for length or %NULL + * + * Gets the greyscale data for an image. This data must not be modified or + * freed. + * + * Returns: (transfer none) (array length=len): The image data + */ +const guchar * +fp_image_get_data (FpImage *self, gsize *len) +{ + if (len) + *len = self->width * self->height; + + return self->data; +} + +/** + * fp_image_get_binarized: + * @self: A #FpImage + * @len: (out) (optional): Return location for length or %NULL + * + * Gets the binarized data for an image. This data must not be modified or + * freed. You need to first detect the minutiae using + * fp_image_detect_minutiae(). + * + * Returns: (transfer none) (array length=len): The binarized image data + */ +const guchar * +fp_image_get_binarized (FpImage *self, gsize *len) +{ + if (len && self->binarized) + *len = self->width * self->height; + + return self->binarized; +} + +/** + * fp_image_get_minutiae: + * @self: A #FpImage + * + * Gets the minutiae for an image. This data must not be modified or + * freed. You need to first detect the minutiae using + * fp_image_detect_minutiae(). + * + * Returns: (transfer none) (element-type FpMinutia): The detected minutiae + */ +GPtrArray * +fp_image_get_minutiae (FpImage *self) +{ + return self->minutiae; +} + +/** + * fp_image_detect_minutiae: + * @self: A #FpImage + * @cancellable: a #GCancellable, or %NULL + * @callback: the function to call on completion + * @user_data: the data to pass to @callback + * + * Detects the minutiae found in an image. + */ +void +fp_image_detect_minutiae (FpImage *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + DetectMinutiaeData *data = g_new0 (DetectMinutiaeData, 1); + + task = g_task_new (self, cancellable, fp_image_detect_minutiae_cb, user_data); + + data->image = g_malloc (self->width * self->height); + memcpy (data->image, self->data, self->width * self->height); + data->flags = self->flags; + data->width = self->width; + data->height = self->height; + data->ppmm = self->ppmm; + data->user_cb = callback; + + g_task_set_task_data (task, data, (GDestroyNotify) fp_image_detect_minutiae_free); + g_task_run_in_thread (task, fp_image_detect_minutiae_thread_func); +} + +/** + * fp_image_detect_minutiae_finish: + * @self: A #FpImage + * @result: A #GAsyncResult + * @error: Return location for errors, or %NULL to ignore + * + * Finish minutiae detection in an image + * + * Returns: %TRUE on success + */ +gboolean +fp_image_detect_minutiae_finish (FpImage *self, + GAsyncResult *result, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (result), error); +} + + + +/** + * fpi_std_sq_dev: + * @buf: buffer (usually bitmap, one byte per pixel) + * @size: size of @buffer + * + * Calculates the squared standard deviation of the individual + * pixels in the buffer, as per the following formula: + * |[ + * mean = sum (buf[0..size]) / size + * sq_dev = sum ((buf[0.size] - mean) ^ 2) + * ]| + * This function is usually used to determine whether image + * is empty. + * + * Returns: the squared standard deviation for @buffer + */ +gint +fpi_std_sq_dev (const guint8 *buf, + gint size) +{ + guint64 res = 0, mean = 0; + gint i; + + for (i = 0; i < size; i++) + mean += buf[i]; + + mean /= size; + + for (i = 0; i < size; i++) + { + int dev = (int) buf[i] - mean; + res += dev * dev; + } + + return res / size; +} + +/** + * fpi_mean_sq_diff_norm: + * @buf1: buffer (usually bitmap, one byte per pixel) + * @buf2: buffer (usually bitmap, one byte per pixel) + * @size: buffer size of smallest buffer + * + * This function calculates the normalized mean square difference of + * two buffers, usually two lines, as per the following formula: + * |[ + * sq_diff = sum ((buf1[0..size] - buf2[0..size]) ^ 2) / size + * ]| + * + * This functions is usually used to get numerical difference + * between two images. + * + * Returns: the normalized mean squared difference between @buf1 and @buf2 + */ +gint +fpi_mean_sq_diff_norm (const guint8 *buf1, + const guint8 *buf2, + gint size) +{ + int res = 0, i; + + for (i = 0; i < size; i++) + { + int dev = (int) buf1[i] - (int) buf2[i]; + res += dev * dev; + } + + return res / size; +} + +/** + * fp_minutia_get_coords: + * @min: A #FpMinutia + * @x: (out): x position in image + * @y: (out): y position in image + * + * Returns the coordinates of the found minutia. This is only useful for + * debugging purposes and the API is not considered stable for production. + */ +void +fp_minutia_get_coords (FpMinutia *min, gint *x, gint *y) +{ + if (x) + *x = min->x; + if (y) + *y = min->y; +} + +#if HAVE_PIXMAN +FpImage * +fpi_image_resize (FpImage *orig_img, + guint w_factor, + guint h_factor) +{ + int new_width = orig_img->width * w_factor; + int new_height = orig_img->height * h_factor; + pixman_image_t *orig, *resized; + pixman_transform_t transform; + FpImage *newimg; + + orig = pixman_image_create_bits (PIXMAN_a8, orig_img->width, orig_img->height, (uint32_t *) orig_img->data, orig_img->width); + resized = pixman_image_create_bits (PIXMAN_a8, new_width, new_height, NULL, new_width); + + pixman_transform_init_identity (&transform); + pixman_transform_scale (NULL, &transform, pixman_int_to_fixed (w_factor), pixman_int_to_fixed (h_factor)); + pixman_image_set_transform (orig, &transform); + pixman_image_set_filter (orig, PIXMAN_FILTER_BILINEAR, NULL, 0); + pixman_image_composite32 (PIXMAN_OP_SRC, + orig, /* src */ + NULL, /* mask */ + resized, /* dst */ + 0, 0, /* src x y */ + 0, 0, /* mask x y */ + 0, 0, /* dst x y */ + new_width, new_height /* width height */ + ); + + newimg = fp_image_new (new_width, new_height); + newimg->flags = orig_img->flags; + + memcpy (newimg->data, pixman_image_get_data (resized), new_width * new_height); + + pixman_image_unref (orig); + pixman_image_unref (resized); + + return newimg; +} +#endif diff --git a/libfprint/fp-image.h b/libfprint/fp-image.h new file mode 100644 index 00000000..7de9f1a4 --- /dev/null +++ b/libfprint/fp-image.h @@ -0,0 +1,59 @@ +/* + * FPrint Image + * Copyright (C) 2007 Daniel Drake + * Copyright (C) 2019 Benjamin Berg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define FP_TYPE_IMAGE (fp_image_get_type ()) + +typedef struct fp_minutia FpMinutia; + +G_DECLARE_FINAL_TYPE (FpImage, fp_image, FP, IMAGE, GObject) + +FpImage *fp_image_new (gint width, + gint height); + +guint fp_image_get_width (FpImage *self); +guint fp_image_get_height (FpImage *self); +gdouble fp_image_get_ppmm (FpImage *self); + +GPtrArray * fp_image_get_minutiae (FpImage *self); + +void fp_image_detect_minutiae (FpImage *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean fp_image_detect_minutiae_finish (FpImage *self, + GAsyncResult *result, + GError **error); + +const guchar * fp_image_get_data (FpImage *self, + gsize *len); +const guchar * fp_image_get_binarized (FpImage *self, + gsize *len); + +void fp_minutia_get_coords (FpMinutia *min, + gint *x, + gint *y); + +G_END_DECLS diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c new file mode 100644 index 00000000..644370d6 --- /dev/null +++ b/libfprint/fp-print.c @@ -0,0 +1,1118 @@ +/* + * FPrint Print handling + * Copyright (C) 2007 Daniel Drake + * Copyright (C) 2019 Benjamin Berg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "fpi-print.h" +#include "fpi-image.h" +#include "fpi-device.h" + +#include "nbis/include/bozorth.h" +#include "nbis/include/lfs.h" + +/** + * SECTION: fp-print + * @title: FpPrint + * @short_description: Fingerprint handling + * + * Interaction with prints and their storage. + */ + +/** + * SECTION: fpi-print + * @title: Internal FpPrint + * @short_description: Internal fingerprint handling routines + * + * Interaction with prints and their storage. See also the public + * #FpPrint routines. + */ + +struct _FpPrint +{ + GInitiallyUnowned parent_instance; + + FpPrintType type; + + gchar *driver; + gchar *device_id; + gboolean device_stored; + + FpImage *image; + + /* Metadata */ + FpFinger finger; + gchar *username; + gchar *description; + GDate *enroll_date; + + GVariant *data; + GPtrArray *prints; +}; + +G_DEFINE_TYPE (FpPrint, fp_print, G_TYPE_INITIALLY_UNOWNED) + +enum { + PROP_0, + PROP_DRIVER, + PROP_DEVICE_ID, + PROP_DEVICE_STORED, + PROP_IMAGE, + + /* The following is metadata that is stored by default for each print. + * Drivers may make use of these during enrollment (e.g. to additionaly store + * the metadata on the device). */ + PROP_FINGER, + PROP_USERNAME, + PROP_DESCRIPTION, + PROP_ENROLL_DATE, + + /* Private property*/ + PROP_FPI_TYPE, + PROP_FPI_DATA, + N_PROPS +}; + +static GParamSpec *properties[N_PROPS]; + +static void +fp_print_finalize (GObject *object) +{ + FpPrint *self = (FpPrint *) object; + + g_clear_object (&self->image); + g_clear_pointer (&self->device_id, g_free); + g_clear_pointer (&self->driver, g_free); + g_clear_pointer (&self->username, g_free); + g_clear_pointer (&self->description, g_free); + g_clear_pointer (&self->enroll_date, g_date_free); + g_clear_pointer (&self->data, g_variant_unref); + + G_OBJECT_CLASS (fp_print_parent_class)->finalize (object); +} + +static void +fp_print_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + FpPrint *self = FP_PRINT (object); + + switch (prop_id) + { + case PROP_DRIVER: + g_value_set_string (value, self->driver); + break; + + case PROP_DEVICE_ID: + g_value_set_string (value, self->device_id); + break; + + case PROP_DEVICE_STORED: + g_value_set_boolean (value, self->device_stored); + break; + + case PROP_IMAGE: + g_value_set_object (value, self->image); + break; + + case PROP_FINGER: + g_value_set_enum (value, self->finger); + break; + + case PROP_USERNAME: + g_value_set_string (value, self->username); + break; + + case PROP_DESCRIPTION: + g_value_set_string (value, self->description); + break; + + case PROP_ENROLL_DATE: + g_value_set_boxed (value, self->enroll_date); + break; + + case PROP_FPI_TYPE: + g_value_set_enum (value, self->type); + break; + + case PROP_FPI_DATA: + g_value_set_variant (value, self->data); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +fp_print_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + FpPrint *self = FP_PRINT (object); + + switch (prop_id) + { + case PROP_FPI_TYPE: + fpi_print_set_type (self, g_value_get_enum (value)); + break; + + case PROP_DRIVER: + self->driver = g_value_dup_string (value); + break; + + case PROP_DEVICE_ID: + self->device_id = g_value_dup_string (value); + break; + + case PROP_DEVICE_STORED: + self->device_stored = g_value_get_boolean (value); + break; + + case PROP_FINGER: + self->finger = g_value_get_enum (value); + break; + + case PROP_USERNAME: + g_clear_pointer (&self->username, g_free); + self->username = g_value_dup_string (value); + break; + + case PROP_DESCRIPTION: + g_clear_pointer (&self->description, g_free); + self->description = g_value_dup_string (value); + break; + + case PROP_ENROLL_DATE: + g_clear_pointer (&self->enroll_date, g_date_free); + self->enroll_date = g_value_dup_boxed (value); + break; + + case PROP_FPI_DATA: + g_clear_pointer (&self->description, g_variant_unref); + self->data = g_value_dup_variant (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +fp_print_constructed (GObject *obj) +{ + FpPrint *self = FP_PRINT (obj); + + g_assert (self->driver != NULL); + g_assert (self->device_id != NULL); +} + +static void +fp_print_class_init (FpPrintClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = fp_print_constructed; + object_class->finalize = fp_print_finalize; + object_class->get_property = fp_print_get_property; + object_class->set_property = fp_print_set_property; + + properties[PROP_DRIVER] = + g_param_spec_string ("driver", + "Driver", + "The name of the driver that created the print", + NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + properties[PROP_DEVICE_ID] = + g_param_spec_string ("device-id", + "Device ID", + "Unique ID allowing to check if a device is compatible with the print", + NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + properties[PROP_DEVICE_STORED] = + g_param_spec_boolean ("device-stored", + "Device Stored", + "Whether the print is a handle for data that is stored on the device", + FALSE, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + properties[PROP_IMAGE] = + g_param_spec_object ("image", + "Image", + "The image that was used for the print, only valid for newly enrolled prints on image based devices", + FP_TYPE_IMAGE, + G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); + + properties[PROP_FINGER] = + g_param_spec_enum ("finger", + "Finger", + "The enrolled finger", + FP_TYPE_FINGER, + FP_FINGER_UNKNOWN, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + + properties[PROP_USERNAME] = + g_param_spec_string ("username", + "Username", + "The username that the enrolled print belongs to", + NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + + properties[PROP_DESCRIPTION] = + g_param_spec_string ("description", + "Description", + "A user defined description for the print", + NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + + properties[PROP_ENROLL_DATE] = + g_param_spec_boxed ("enroll-date", + "Enroll Date", + "The date of enrollment", + G_TYPE_DATE, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + + properties[PROP_FPI_TYPE] = + g_param_spec_enum ("fp-type", + "Type", + "Private: The type of the print data", + FP_TYPE_PRINT_TYPE, + FP_PRINT_RAW, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + + properties[PROP_FPI_DATA] = + g_param_spec_variant ("fp-data", + "Raw Data", + "The raw data for internal use only", + G_VARIANT_TYPE_ANY, + NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +fp_print_init (FpPrint *self) +{ +} + +/** + * fp_print_new: + * @device: A #FpDevice + * + * Create a new #FpPrint. This is only useful to prepare an enrollment + * of a new print using fp_device_enroll(). For this you should first + * create a new print, fill in the relevant metadata, and then start + * enrollment. + * + * Returns: (transfer floating): A newyl created #FpPrint + */ +FpPrint * +fp_print_new (FpDevice *device) +{ + g_return_val_if_fail (device, NULL); + + return g_object_new (FP_TYPE_PRINT, + "driver", fp_device_get_driver (device), + "device-id", fp_device_get_device_id (device), + NULL); +} + +/** + * fp_print_get_driver: + * @print: A #FpPrint + * + * Returns the driver that the print was created for. + * + * Returns: (transfer none): The driver + */ +const gchar * +fp_print_get_driver (FpPrint *print) +{ + g_return_val_if_fail (FP_IS_PRINT (print), NULL); + + return print->driver; +} + +/** + * fp_print_get_device_id: + * @print: A #FpPrint + * + * Returns the device ID that the print was created for. + * + * Returns: (transfer none): The device ID + */ +const gchar * +fp_print_get_device_id (FpPrint *print) +{ + g_return_val_if_fail (FP_IS_PRINT (print), NULL); + + return print->device_id; +} + +/** + * fp_print_get_device_stored: + * @print: A #FpPrint + * + * Whether the print is actually stored on the device and this is + * just a handle to use that references the device stored data. + * + * Returns: Whether the print is stored on the device + */ +gboolean +fp_print_get_device_stored (FpPrint *print) +{ + g_return_val_if_fail (FP_IS_PRINT (print), FALSE); + + return print->device_stored; +} + +/** + * fp_print_get_image: + * @print: A #FpPrint + * + * Returns the image that the print was created from, or %NULL + * + * Returns: (transfer none) (nullable): The #FpImage + */ +FpImage * +fp_print_get_image (FpPrint *print) +{ + g_return_val_if_fail (FP_IS_PRINT (print), NULL); + + return print->image; +} + +/** + * fp_print_get_finger: + * @print: A #FpPrint + * + * Returns the finger that the print was created for. + * + * Returns: The #FpFinger + */ +FpFinger +fp_print_get_finger (FpPrint *print) +{ + g_return_val_if_fail (FP_IS_PRINT (print), FP_FINGER_UNKNOWN); + + return print->finger; +} + +/** + * fp_print_get_username: + * @print: A #FpPrint + * + * Returns the user defined username for the print. + * + * Returns: (transfer none) (nullable): The username + */ +const gchar * +fp_print_get_username (FpPrint *print) +{ + g_return_val_if_fail (FP_IS_PRINT (print), NULL); + + return print->username; +} + +/** + * fp_print_get_description: + * @print: A #FpPrint + * + * Returns the user defined description for the print. + * + * Returns: (transfer none) (nullable): The description + */ +const gchar * +fp_print_get_description (FpPrint *print) +{ + g_return_val_if_fail (FP_IS_PRINT (print), NULL); + + return print->description; +} + +/** + * fp_print_get_enroll_date: + * @print: A #FpPrint + * + * Returns the user defined enroll date for the print. + * + * Returns: (transfer none) (nullable): The #GDate + */ +const GDate * +fp_print_get_enroll_date (FpPrint *print) +{ + g_return_val_if_fail (FP_IS_PRINT (print), NULL); + + return print->enroll_date; +} + +/** + * fp_print_set_finger: + * @print: A #FpPrint + * @finger: The #FpFinger + * + * Set the finger that the print is for. + */ +void +fp_print_set_finger (FpPrint *print, + FpFinger finger) +{ + g_return_if_fail (FP_IS_PRINT (print)); + + print->finger = finger; + g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_FINGER]); +} + +/** + * fp_print_set_username: + * @print: A #FpPrint + * @username: (transfer none): The new username + * + * Set the username for the print. + */ +void +fp_print_set_username (FpPrint *print, + const gchar *username) +{ + g_return_if_fail (FP_IS_PRINT (print)); + + g_clear_pointer (&print->username, g_free); + print->username = g_strdup (username); + g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_USERNAME]); +} + +/** + * fp_print_set_description: + * @print: A #FpPrint + * @description: (transfer none): The new description + * + * Set the description for the print. + */ +void +fp_print_set_description (FpPrint *print, + const gchar *description) +{ + g_return_if_fail (FP_IS_PRINT (print)); + + g_clear_pointer (&print->description, g_free); + print->description = g_strdup (description); + g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_DESCRIPTION]); +} + +/** + * fp_print_set_enroll_date: + * @print: A #FpPrint + * @enroll_date: (transfer none): The new enroll date + * + * Set the enroll date for the print. + */ +void +fp_print_set_enroll_date (FpPrint *print, + const GDate *enroll_date) +{ + g_return_if_fail (FP_IS_PRINT (print)); + + g_clear_pointer (&print->enroll_date, g_date_free); + if (enroll_date) + { + /* XXX: Should use g_date_copy, but that is new in 2.56. */ + print->enroll_date = g_date_new (); + *print->enroll_date = *enroll_date; + } + g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_ENROLL_DATE]); +} + + + +/** + * fpi_print_add_print: + * @print: A #FpPrint + * @add: Print to append to @print + * + * Appends the single #FP_PRINT_NBIS print from @add to the collection of + * prints in @print. Both print objects need to be of type #FP_PRINT_NBIS + * for this to work. + */ +void +fpi_print_add_print (FpPrint *print, FpPrint *add) +{ + g_return_if_fail (print->type == FP_PRINT_NBIS); + g_return_if_fail (add->type == FP_PRINT_NBIS); + + g_assert (add->prints->len == 1); + g_ptr_array_add (print->prints, g_memdup (add->prints->pdata[0], sizeof (struct xyt_struct))); +} + +/** + * fpi_print_set_type: + * @print: A #FpPrint + * @type: The newly type of the print data + * + * This function can only be called exactly once. Drivers should + * call it after creating a new print, or to initialize the template + * print passed during enrollment. + */ +void +fpi_print_set_type (FpPrint *print, + FpPrintType type) +{ + g_return_if_fail (FP_IS_PRINT (print)); + /* We only allow setting this once! */ + g_return_if_fail (print->type == FP_PRINT_UNDEFINED); + + print->type = type; + if (print->type == FP_PRINT_NBIS) + print->prints = g_ptr_array_new_with_free_func (g_free); + g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_FPI_TYPE]); +} + +/** + * fpi_print_set_device_stored: + * @print: A #FpPrint + * @device_stored: Whether the print is stored on the device or not + * + * Drivers must set this to %TRUE for any print that is really a handle + * for data that is stored on the device itself. + */ +void +fpi_print_set_device_stored (FpPrint *print, + gboolean device_stored) +{ + g_return_if_fail (FP_IS_PRINT (print)); + + print->device_stored = device_stored; + g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_DEVICE_STORED]); +} + +/* XXX: This is the old version, but wouldn't it be smarter to instead + * use the highest quality mintutiae? Possibly just using bz_prune from + * upstream? */ +static void +minutiae_to_xyt (struct fp_minutiae *minutiae, + int bwidth, + int bheight, + struct xyt_struct *xyt) +{ + int i; + struct fp_minutia *minutia; + struct minutiae_struct c[MAX_FILE_MINUTIAE]; + + /* struct xyt_struct uses arrays of MAX_BOZORTH_MINUTIAE (200) */ + int nmin = min (minutiae->num, MAX_BOZORTH_MINUTIAE); + + for (i = 0; i < nmin; i++) + { + minutia = minutiae->list[i]; + + lfs2nist_minutia_XYT (&c[i].col[0], &c[i].col[1], &c[i].col[2], + minutia, bwidth, bheight); + c[i].col[3] = sround (minutia->reliability * 100.0); + + if (c[i].col[2] > 180) + c[i].col[2] -= 360; + } + + qsort ((void *) &c, (size_t) nmin, sizeof (struct minutiae_struct), + sort_x_y); + + for (i = 0; i < nmin; i++) + { + xyt->xcol[i] = c[i].col[0]; + xyt->ycol[i] = c[i].col[1]; + xyt->thetacol[i] = c[i].col[2]; + } + xyt->nrows = nmin; +} + +/** + * fpi_print_add_from_image: + * @print: A #FpPrint + * @image: A #FpImage + * @error: Return location for error + * + * Extracts the minutiae from the given image and adds it to @print of + * type #FP_PRINT_NBIS. + * + * The @image will be kept so that API users can get retrieve it e.g. + * for debugging purposes. + * + * Returns: %TRUE on success + */ +gboolean +fpi_print_add_from_image (FpPrint *print, + FpImage *image, + GError **error) +{ + GPtrArray *minutiae; + struct fp_minutiae _minutiae; + struct xyt_struct *xyt; + + if (print->type != FP_PRINT_NBIS || !image) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "Cannot add print data from image!"); + return FALSE; + } + + minutiae = fp_image_get_minutiae (image); + if (!minutiae || minutiae->len == 0) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "No minutiae found in image or not yet detected!"); + return FALSE; + } + + _minutiae.num = minutiae->len; + _minutiae.list = (struct fp_minutia **) minutiae->pdata; + _minutiae.alloc = minutiae->len; + + xyt = g_new0 (struct xyt_struct, 1); + minutiae_to_xyt (&_minutiae, image->width, image->height, xyt); + g_ptr_array_add (print->prints, xyt); + + g_clear_object (&print->image); + print->image = g_object_ref (image); + g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_IMAGE]); + + return TRUE; +} + +/** + * fpi_print_bz3_match: + * @template: A #FpPrint containing one or more prints + * @print: A newly scanned #FpPrint to test + * @bz3_threshold: The BZ3 match threshold + * @error: Return location for error + * + * Match the newly scanned @print (containing exactly one print) against the + * prints contained in @template which will have been stored during enrollment. + * + * Both @template and @print need to be of type #FP_PRINT_NBIS for this to + * work. + * + * Returns: Whether the prints match, @error will be set if #FPI_MATCH_ERROR is returned + */ +FpiMatchResult +fpi_print_bz3_match (FpPrint *template, FpPrint *print, gint bz3_threshold, GError **error) +{ + struct xyt_struct *pstruct; + gint probe_len; + gint i; + + /* XXX: Use a different error type? */ + if (template->type != FP_PRINT_NBIS || print->type != FP_PRINT_NBIS) + { + *error = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, + "It is only possible to match NBIS type print data"); + return FPI_MATCH_ERROR; + } + + if (print->prints->len != 1) + { + *error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "New print contains more than one print!"); + return FPI_MATCH_ERROR; + } + + pstruct = g_ptr_array_index (print->prints, 0); + probe_len = bozorth_probe_init (pstruct); + + for (i = 0; i < template->prints->len; i++) + { + struct xyt_struct *gstruct; + gint score; + gstruct = g_ptr_array_index (template->prints, i); + score = bozorth_to_gallery (probe_len, pstruct, gstruct); + fp_dbg ("score %d", score); + + if (score >= bz3_threshold) + return FPI_MATCH_SUCCESS; + } + + return FPI_MATCH_FAIL; +} + +/** + * fp_print_compatible: + * @self: A #FpPrint + * @device: A #FpDevice + * + * Tests whether the prints is compatible with the given device. + * + * Returns: %TRUE if the print is compatible with the device + */ +gboolean +fp_print_compatible (FpPrint *self, FpDevice *device) +{ + g_return_val_if_fail (FP_IS_PRINT (self), FALSE); + g_return_val_if_fail (FP_IS_DEVICE (device), FALSE); + + if (g_strcmp0 (self->driver, fp_device_get_driver (device))) + return FALSE; + + if (g_strcmp0 (self->device_id, fp_device_get_device_id (device))) + return FALSE; + + return TRUE; +} + +/** + * fp_print_equal: + * @self: First #FpPrint + * @other: Second #FpPrint + * + * Tests whether the prints can be considered equal. This only compares the + * actual information about the print, not the metadata. + * + * Returns: %TRUE if the prints are equal + */ +gboolean +fp_print_equal (FpPrint *self, FpPrint *other) +{ + g_return_val_if_fail (FP_IS_PRINT (self), FALSE); + g_return_val_if_fail (FP_IS_PRINT (other), FALSE); + g_return_val_if_fail (self->type != FP_PRINT_UNDEFINED, FALSE); + g_return_val_if_fail (other->type != FP_PRINT_UNDEFINED, FALSE); + + if (self->type != other->type) + return FALSE; + + if (g_strcmp0 (self->driver, other->driver)) + return FALSE; + + if (g_strcmp0 (self->device_id, other->device_id)) + return FALSE; + + if (self->type == FP_PRINT_RAW) + { + return g_variant_equal (self->data, other->data); + } + else if (self->type == FP_PRINT_NBIS) + { + gint i; + + if (self->prints->len != other->prints->len) + return FALSE; + + for (i = 0; i < self->prints->len; i++) + { + struct xyt_struct *a = g_ptr_array_index (self->prints, i); + struct xyt_struct *b = g_ptr_array_index (other->prints, i); + + if (memcmp (a, b, sizeof (struct xyt_struct)) != 0) + return FALSE; + } + + return TRUE; + } + else + { + g_assert_not_reached (); + } +} + +#define FP_PRINT_VARIANT_TYPE G_VARIANT_TYPE ("(issbymsmsia{sv}v)") + +G_STATIC_ASSERT (sizeof (((struct xyt_struct *) NULL)->xcol[0]) == 4); + +/** + * fp_print_serialize: + * @print: A #FpPrint + * @data: (array length=length) (transfer full) (out): Return location for data pointer + * @length: (transfer full) (out): Length of @data + * @error: Return location for error + * + * Serialize a print definition for permanent storage. Note that this is + * lossy in the sense that e.g. the image data is discarded. + * + * Returns: (type void): %TRUE on success + */ +gboolean +fp_print_serialize (FpPrint *print, + guchar **data, + gsize *length, + GError **error) +{ + g_autoptr(GVariant) result = NULL; + GVariantBuilder builder = G_VARIANT_BUILDER_INIT (FP_PRINT_VARIANT_TYPE); + gsize len; + + g_assert (data); + g_assert (length); + + g_variant_builder_add (&builder, "i", print->type); + g_variant_builder_add (&builder, "s", print->driver); + g_variant_builder_add (&builder, "s", print->device_id); + g_variant_builder_add (&builder, "b", print->device_stored); + + /* Metadata */ + g_variant_builder_add (&builder, "y", print->finger); + g_variant_builder_add (&builder, "ms", print->username); + g_variant_builder_add (&builder, "ms", print->description); + if (print->enroll_date && g_date_valid (print->enroll_date)) + g_variant_builder_add (&builder, "i", g_date_get_julian (print->enroll_date)); + else + g_variant_builder_add (&builder, "i", G_MININT32); + + /* Unused a{sv} for expansion */ + g_variant_builder_open (&builder, G_VARIANT_TYPE_VARDICT); + g_variant_builder_close (&builder); + + /* Insert NBIS print data for type NBIS, otherwise the GVariant directly */ + if (print->type == FP_PRINT_NBIS) + { + GVariantBuilder nested = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("(a(aiaiai))")); + gint i; + + g_variant_builder_open (&nested, G_VARIANT_TYPE ("a(aiaiai)")); + for (i = 0; i < print->prints->len; i++) + { + struct xyt_struct *xyt = g_ptr_array_index (print->prints, i); + gint j; + gint32 *col = g_new (gint32, xyt->nrows); + + g_variant_builder_open (&nested, G_VARIANT_TYPE ("(aiaiai)")); + + for (j = 0; j < xyt->nrows; j++) + col[j] = GINT32_TO_LE (xyt->xcol[j]); + g_variant_builder_add_value (&nested, + g_variant_new_fixed_array (G_VARIANT_TYPE_INT32, + col, + xyt->nrows, + sizeof (col[0]))); + + for (j = 0; j < xyt->nrows; j++) + col[j] = GINT32_TO_LE (xyt->ycol[j]); + g_variant_builder_add_value (&nested, + g_variant_new_fixed_array (G_VARIANT_TYPE_INT32, + col, + xyt->nrows, + sizeof (col[0]))); + + for (j = 0; j < xyt->nrows; j++) + col[j] = GINT32_TO_LE (xyt->thetacol[j]); + g_variant_builder_add_value (&nested, + g_variant_new_fixed_array (G_VARIANT_TYPE_INT32, + col, + xyt->nrows, + sizeof (col[0]))); + g_variant_builder_close (&nested); + } + + g_variant_builder_close (&nested); + g_variant_builder_add (&builder, "v", g_variant_builder_end (&nested)); + } + else + { + g_variant_builder_add (&builder, "v", g_variant_new_variant (print->data)); + } + + result = g_variant_builder_end (&builder); + + if (G_BYTE_ORDER == G_BIG_ENDIAN) + { + GVariant *tmp; + tmp = g_variant_byteswap (result); + g_variant_unref (result); + result = tmp; + } + + len = g_variant_get_size (result); + /* Add 3 bytes of header */ + len += 3; + + *data = g_malloc (len); + *length = len; + + (*data)[0] = (guchar) 'F'; + (*data)[1] = (guchar) 'P'; + (*data)[2] = (guchar) '3'; + + g_variant_get_data (result); + g_variant_store (result, (*data) + 3); + + return TRUE; +} + +/** + * fp_print_deserialize: + * @data: (array length=length): The binary data + * @length: Length of the data + * @error: Return location for error + * + * Deserialize a print definition from permanent storage. + * + * Returns: (transfer full): A newly created #FpPrint on success + */ +FpPrint * +fp_print_deserialize (const guchar *data, + gsize length, + GError **error) +{ + g_autoptr(FpPrint) result = NULL; + g_autoptr(GVariant) raw_value = NULL; + g_autoptr(GVariant) value = NULL; + guchar *aligned_data = NULL; + GDate *date = NULL; + guint8 finger_int8; + FpFinger finger; + g_autofree gchar *username = NULL; + g_autofree gchar *description = NULL; + gint julian_date; + FpPrintType type; + const gchar *driver; + const gchar *device_id; + gboolean device_stored; + GVariant *print_data; + + g_assert (data); + g_assert (length > 3); + + if (memcmp (data, "FP3", 3) != 0) + goto invalid_format; + + /* NOTE: + * We make sure that we have no variant left over from the parsing at the end + * of this function (meaning we don't need to keep the data around. + */ + + /* To support GLIB < 2.60 we need to make sure that the memory is aligned correctly. + * We also need to copy the backing store for the raw data that we may keep for + * longer. */ + aligned_data = g_malloc (length - 3); + memcpy (aligned_data, data + 3, length - 3); + raw_value = g_variant_new_from_data (FP_PRINT_VARIANT_TYPE, + aligned_data, length - 3, + FALSE, g_free, NULL); + + if (!raw_value) + goto invalid_format; + + if (G_BYTE_ORDER == G_BIG_ENDIAN) + value = g_variant_byteswap (raw_value); + else + value = g_variant_get_normal_form (raw_value); + + g_variant_get (value, + "(issbymsmsi@a{sv}v)", + &type, + &driver, + &device_id, + &device_stored, + &finger_int8, + &username, + &description, + &julian_date, + NULL, + &print_data); + + finger = finger_int8; + + /* Assume data is valid at this point if the values are somewhat sane. */ + if (type == FP_PRINT_NBIS) + { + g_autoptr(GVariant) prints = g_variant_get_child_value (print_data, 0); + gint i; + + result = g_object_new (FP_TYPE_PRINT, + "driver", driver, + "device-id", device_id, + "device-stored", device_stored, + NULL); + fpi_print_set_type (result, FP_PRINT_NBIS); + for (i = 0; i < g_variant_n_children (prints); i++) + { + struct xyt_struct *xyt = g_new0 (struct xyt_struct, 1); + const gint32 *xcol, *ycol, *thetacol; + gsize xlen, ylen, thetalen; + g_autoptr(GVariant) xyt_data = NULL; + GVariant *child; + + xyt_data = g_variant_get_child_value (prints, i); + + child = g_variant_get_child_value (xyt_data, 0); + xcol = g_variant_get_fixed_array (child, &xlen, sizeof (gint32)); + g_variant_unref (child); + + child = g_variant_get_child_value (xyt_data, 1); + ycol = g_variant_get_fixed_array (child, &ylen, sizeof (gint32)); + g_variant_unref (child); + + child = g_variant_get_child_value (xyt_data, 2); + thetacol = g_variant_get_fixed_array (child, &thetalen, sizeof (gint32)); + g_variant_unref (child); + + if (xlen != ylen || xlen != thetalen) + goto invalid_format; + + if (xlen > G_N_ELEMENTS (xyt->xcol)) + goto invalid_format; + + xyt->nrows = xlen; + memcpy (xyt->xcol, xcol, sizeof (xcol[0]) * xlen); + memcpy (xyt->ycol, ycol, sizeof (xcol[0]) * xlen); + memcpy (xyt->thetacol, thetacol, sizeof (xcol[0]) * xlen); + + g_ptr_array_add (result->prints, xyt); + } + } + else if (type == FP_PRINT_RAW) + { + g_autoptr(GVariant) fp_data = g_variant_get_child_value (print_data, 0); + + result = g_object_new (FP_TYPE_PRINT, + "fp-type", type, + "driver", driver, + "device-id", device_id, + "device-stored", device_stored, + "fp-data", fp_data, + NULL); + } + else + { + g_warning ("Invalid print type: 0x%X", type); + goto invalid_format; + } + + date = g_date_new_julian (julian_date); + g_object_set (result, + "finger", finger, + "username", username, + "description", description, + "enroll_date", date, + NULL); + + g_date_free (date); + + return g_steal_pointer (&result); + +invalid_format: + *error = g_error_new_literal (G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "Data could not be parsed"); + return FALSE; +} diff --git a/libfprint/fp-print.h b/libfprint/fp-print.h new file mode 100644 index 00000000..fcb9532e --- /dev/null +++ b/libfprint/fp-print.h @@ -0,0 +1,101 @@ +/* + * FPrint Print handling + * Copyright (C) 2007 Daniel Drake + * Copyright (C) 2019 Benjamin Berg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "fp-image.h" +#include "fp-enums.h" + +G_BEGIN_DECLS + +#define FP_TYPE_PRINT (fp_print_get_type ()) +G_DECLARE_FINAL_TYPE (FpPrint, fp_print, FP, PRINT, GInitiallyUnowned) + +#include "fp-device.h" + +/** + * FpFinger: + * @FP_FINGER_UNKNOWN: The finger is unknown + * @FP_FINGER_LEFT_THUMB: Left thumb + * @FP_FINGER_LEFT_INDEX: Left index finger + * @FP_FINGER_LEFT_MIDDLE: Left middle finger + * @FP_FINGER_LEFT_RING: Left ring finger + * @FP_FINGER_LEFT_LITTLE: Left little finger + * @FP_FINGER_RIGHT_THUMB: Right thumb + * @FP_FINGER_RIGHT_INDEX: Right index finger + * @FP_FINGER_RIGHT_MIDDLE: Right middle finger + * @FP_FINGER_RIGHT_RING: Right ring finger + * @FP_FINGER_RIGHT_LITTLE: Right little finger + */ +typedef enum { + FP_FINGER_UNKNOWN = 0, + FP_FINGER_LEFT_THUMB, + FP_FINGER_LEFT_INDEX, + FP_FINGER_LEFT_MIDDLE, + FP_FINGER_LEFT_RING, + FP_FINGER_LEFT_LITTLE, + FP_FINGER_RIGHT_THUMB, + FP_FINGER_RIGHT_INDEX, + FP_FINGER_RIGHT_MIDDLE, + FP_FINGER_RIGHT_RING, + FP_FINGER_RIGHT_LITTLE, +} FpFinger; + +FpPrint *fp_print_new (FpDevice *device); + +FpPrint *fp_print_new_from_data (guchar *data, + gsize length); +gboolean fp_print_to_data (guchar **data, + gsize length); + +const gchar *fp_print_get_driver (FpPrint *print); +const gchar *fp_print_get_device_id (FpPrint *print); +FpImage *fp_print_get_image (FpPrint *print); + +FpFinger fp_print_get_finger (FpPrint *print); +const gchar *fp_print_get_username (FpPrint *print); +const gchar *fp_print_get_description (FpPrint *print); +const GDate *fp_print_get_enroll_date (FpPrint *print); +gboolean fp_print_get_device_stored (FpPrint *print); + +void fp_print_set_finger (FpPrint *print, + FpFinger finger); +void fp_print_set_username (FpPrint *print, + const gchar *username); +void fp_print_set_description (FpPrint *print, + const gchar *description); +void fp_print_set_enroll_date (FpPrint *print, + const GDate *enroll_date); + +gboolean fp_print_compatible (FpPrint *self, + FpDevice *device); +gboolean fp_print_equal (FpPrint *self, + FpPrint *other); + +gboolean fp_print_serialize (FpPrint *print, + guchar **data, + gsize *length, + GError **error); + +FpPrint *fp_print_deserialize (const guchar *data, + gsize length, + GError **error); + +G_END_DECLS diff --git a/libfprint/fp_internal.h b/libfprint/fp_internal.h index 78610321..0f4df4ae 100644 --- a/libfprint/fp_internal.h +++ b/libfprint/fp_internal.h @@ -20,147 +20,10 @@ #ifndef __FPRINT_INTERNAL_H__ #define __FPRINT_INTERNAL_H__ -#include - -#include -#include -#include -#include - -#include "nbis-helpers.h" -#include "fprint.h" -#include "fpi-dev.h" -#include "fpi-core.h" #include "fpi-log.h" -#include "fpi-dev-img.h" -#include "fpi-data.h" -#include "fpi-img.h" -#include "drivers/driver_ids.h" - -/* Global variables */ -extern libusb_context *fpi_usb_ctx; -extern GSList *opened_devices; - -/* fp_print_data structure definition */ -enum fp_print_data_type { - PRINT_DATA_RAW = 0, /* memset-imposed default */ - PRINT_DATA_NBIS_MINUTIAE -}; - -struct fp_print_data { - uint16_t driver_id; - uint32_t devtype; - enum fp_print_data_type type; - GSList *prints; -}; - -/* fp_dev structure definition */ -enum fp_dev_state { - DEV_STATE_INITIAL = 0, - DEV_STATE_ERROR, - DEV_STATE_INITIALIZING, - DEV_STATE_INITIALIZED, - DEV_STATE_DEINITIALIZING, - DEV_STATE_DEINITIALIZED, - DEV_STATE_ENROLL_STARTING, - DEV_STATE_ENROLLING, - DEV_STATE_ENROLL_STOPPING, - DEV_STATE_VERIFY_STARTING, - DEV_STATE_VERIFYING, - DEV_STATE_VERIFY_DONE, - DEV_STATE_VERIFY_STOPPING, - DEV_STATE_IDENTIFY_STARTING, - DEV_STATE_IDENTIFYING, - DEV_STATE_IDENTIFY_DONE, - DEV_STATE_IDENTIFY_STOPPING, - DEV_STATE_CAPTURE_STARTING, - DEV_STATE_CAPTURING, - DEV_STATE_CAPTURE_DONE, - DEV_STATE_CAPTURE_STOPPING, -}; - -struct fp_dev { - struct fp_driver *drv; - uint32_t devtype; - - /* only valid if drv->type == DRIVER_IMAGING */ - struct fp_img_dev *img_dev; - /* Link to the instance specific struct */ - void *instance_data; - - int nr_enroll_stages; - - /* FIXME: This will eventually have a bus type */ - libusb_device_handle *udev; - - /* read-only to drivers */ - struct fp_print_data *verify_data; - - /* drivers should not mess with any of the below */ - enum fp_dev_state state; - int __enroll_stage; - int unconditional_capture; - - /* async I/O callbacks and data */ - /* FIXME: convert this to generic state operational data mechanism? */ - fp_dev_open_cb open_cb; - void *open_cb_data; - fp_operation_stop_cb close_cb; - void *close_cb_data; - fp_enroll_stage_cb enroll_stage_cb; - void *enroll_stage_cb_data; - fp_operation_stop_cb enroll_stop_cb; - void *enroll_stop_cb_data; - fp_img_operation_cb verify_cb; - void *verify_cb_data; - fp_operation_stop_cb verify_stop_cb; - void *verify_stop_cb_data; - fp_identify_cb identify_cb; - void *identify_cb_data; - fp_operation_stop_cb identify_stop_cb; - void *identify_stop_cb_data; - fp_img_operation_cb capture_cb; - void *capture_cb_data; - fp_operation_stop_cb capture_stop_cb; - void *capture_stop_cb_data; - - /* FIXME: better place to put this? */ - struct fp_print_data **identify_gallery; -}; - -/* fp_img_dev structure definition */ -struct fp_img_dev { - struct fp_dev *parent; - - enum fp_imgdev_action action; - int action_state; - - struct fp_print_data *acquire_data; - struct fp_print_data *enroll_data; - struct fp_img *acquire_img; - int enroll_stage; - int action_result; - - /* FIXME: better place to put this? */ - size_t identify_match_offset; -}; - -/* fp_driver structure definition */ - -/* fp_img_driver structure definition */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) -#define fpi_driver_to_img_driver(drv) \ - container_of((drv), struct fp_img_driver, driver) - -/* fp_dscv_dev structure definition */ -struct fp_dscv_dev { - struct libusb_device *udev; - struct fp_driver *drv; - unsigned long driver_data; - uint32_t devtype; -}; +#include "nbis-helpers.h" +#include "fpi-image.h" +#include "fpi-image-device.h" /* fp_minutia structure definition */ struct fp_minutia { @@ -185,48 +48,5 @@ struct fp_minutiae { struct fp_minutia **list; }; -/* Defined in fpi-dev-img.c */ -void fpi_img_driver_setup(struct fp_img_driver *idriver); -int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev); -int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev); - -/* Exported for use in command-line tools - * Defined in fpi-core.c */ -struct fp_driver **fprint_get_drivers (void); - -/* Defined in fpi-core.c */ -enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv); - -/* Defined in fpi-data.c */ -gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1, - enum fp_print_data_type type1, uint16_t driver_id2, uint32_t devtype2, - enum fp_print_data_type type2); - -/* Defined in fpi-img.c */ -gboolean fpi_img_is_sane(struct fp_img *img); -int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img, - struct fp_print_data **ret); -int fpi_img_compare_print_data(struct fp_print_data *enrolled_print, - struct fp_print_data *new_print); -int fpi_img_compare_print_data_to_gallery(struct fp_print_data *print, - struct fp_print_data **gallery, int match_threshold, size_t *match_offset); - -/* Defined in fpi-poll.c */ -void fpi_timeout_cancel_all_for_dev(struct fp_dev *dev); -void fpi_poll_init(void); -void fpi_poll_exit(void); - -/* Defined in fpi-async.c */ -void fpi_drvcb_capture_started(struct fp_dev *dev, int status); -void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result, - struct fp_img *img); -void fpi_drvcb_capture_stopped(struct fp_dev *dev); - -void fpi_drvcb_identify_started(struct fp_dev *dev, int status); -void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result, - size_t match_offset, struct fp_img *img); -void fpi_drvcb_identify_stopped(struct fp_dev *dev); - -#include "drivers_definitions.h" #endif diff --git a/libfprint/fpi-assembling.c b/libfprint/fpi-assembling.c index 65fad4d7..b6403cb3 100644 --- a/libfprint/fpi-assembling.c +++ b/libfprint/fpi-assembling.c @@ -23,12 +23,8 @@ #include "fp_internal.h" -#include #include -#include -#include - #include "fpi-assembling.h" /** @@ -42,125 +38,141 @@ * data in small stripes. */ -static unsigned int calc_error(struct fpi_frame_asmbl_ctx *ctx, - struct fpi_frame *first_frame, - struct fpi_frame *second_frame, - int dx, - int dy) +static unsigned int +calc_error (struct fpi_frame_asmbl_ctx *ctx, + struct fpi_frame *first_frame, + struct fpi_frame *second_frame, + int dx, + int dy) { - unsigned int width, height; - unsigned int x1, y1, x2, y2, err, i, j; + unsigned int width, height; + unsigned int x1, y1, x2, y2, err, i, j; - width = ctx->frame_width - (dx > 0 ? dx : -dx); - height = ctx->frame_height - dy; + width = ctx->frame_width - (dx > 0 ? dx : -dx); + height = ctx->frame_height - dy; - y1 = 0; - y2 = dy; - i = 0; - err = 0; - do { - x1 = dx < 0 ? 0 : dx; - x2 = dx < 0 ? -dx : 0; - j = 0; + y1 = 0; + y2 = dy; + i = 0; + err = 0; + do + { + x1 = dx < 0 ? 0 : dx; + x2 = dx < 0 ? -dx : 0; + j = 0; - do { - unsigned char v1, v2; + do + { + unsigned char v1, v2; - v1 = ctx->get_pixel(ctx, first_frame, x1, y1); - v2 = ctx->get_pixel(ctx, second_frame, x2, y2); - err += v1 > v2 ? v1 - v2 : v2 - v1; - j++; - x1++; - x2++; + v1 = ctx->get_pixel (ctx, first_frame, x1, y1); + v2 = ctx->get_pixel (ctx, second_frame, x2, y2); + err += v1 > v2 ? v1 - v2 : v2 - v1; + j++; + x1++; + x2++; - } while (j < width); - i++; - y1++; - y2++; - } while (i < height); + } + while (j < width); + i++; + y1++; + y2++; + } + while (i < height); - /* Normalize error */ - err *= (ctx->frame_height * ctx->frame_width); - err /= (height * width); + /* Normalize error */ + err *= (ctx->frame_height * ctx->frame_width); + err /= (height * width); - if (err == 0) - return INT_MAX; + if (err == 0) + return INT_MAX; - return err; + return err; } /* This function is rather CPU-intensive. It's better to use hardware * to detect movement direction when possible. */ -static void find_overlap(struct fpi_frame_asmbl_ctx *ctx, - struct fpi_frame *first_frame, - struct fpi_frame *second_frame, - unsigned int *min_error) +static void +find_overlap (struct fpi_frame_asmbl_ctx *ctx, + struct fpi_frame *first_frame, + struct fpi_frame *second_frame, + unsigned int *min_error) { - int dx, dy; - unsigned int err; - *min_error = 255 * ctx->frame_height * ctx->frame_width; + int dx, dy; + unsigned int err; - /* Seeking in horizontal and vertical dimensions, - * for horizontal dimension we'll check only 8 pixels - * in both directions. For vertical direction diff is - * rarely less than 2, so start with it. - */ - for (dy = 2; dy < ctx->frame_height; dy++) { - for (dx = -8; dx < 8; dx++) { - err = calc_error(ctx, first_frame, second_frame, - dx, dy); - if (err < *min_error) { - *min_error = err; - second_frame->delta_x = -dx; - second_frame->delta_y = dy; - } - } - } + *min_error = 255 * ctx->frame_height * ctx->frame_width; + + /* Seeking in horizontal and vertical dimensions, + * for horizontal dimension we'll check only 8 pixels + * in both directions. For vertical direction diff is + * rarely less than 2, so start with it. + */ + for (dy = 2; dy < ctx->frame_height; dy++) + { + for (dx = -8; dx < 8; dx++) + { + err = calc_error (ctx, first_frame, second_frame, + dx, dy); + if (err < *min_error) + { + *min_error = err; + second_frame->delta_x = -dx; + second_frame->delta_y = dy; + } + } + } } -static unsigned int do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx, - GSList *stripes, size_t num_stripes, - gboolean reverse) +static unsigned int +do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx, + GSList *stripes, size_t num_stripes, + gboolean reverse) { - GSList *list_entry = stripes; - GTimer *timer; - int frame = 1; - struct fpi_frame *prev_stripe = list_entry->data; - unsigned int min_error; - /* Max error is width * height * 255, for AES2501 which has the largest - * sensor its 192*16*255 = 783360. So for 32bit value it's ~5482 frame before - * we might get int overflow. Use 64bit value here to prevent integer overflow - */ - unsigned long long total_error = 0; + GSList *list_entry = stripes; + GTimer *timer; + int frame = 1; + struct fpi_frame *prev_stripe = list_entry->data; + unsigned int min_error; + /* Max error is width * height * 255, for AES2501 which has the largest + * sensor its 192*16*255 = 783360. So for 32bit value it's ~5482 frame before + * we might get int overflow. Use 64bit value here to prevent integer overflow + */ + unsigned long long total_error = 0; - list_entry = g_slist_next(list_entry); + list_entry = g_slist_next (list_entry); - timer = g_timer_new(); - do { - struct fpi_frame *cur_stripe = list_entry->data; + timer = g_timer_new (); + do + { + struct fpi_frame *cur_stripe = list_entry->data; - if (reverse) { - find_overlap(ctx, prev_stripe, cur_stripe, &min_error); - cur_stripe->delta_y = -cur_stripe->delta_y; - cur_stripe->delta_x = -cur_stripe->delta_x; - } - else - find_overlap(ctx, cur_stripe, prev_stripe, &min_error); - total_error += min_error; + if (reverse) + { + find_overlap (ctx, prev_stripe, cur_stripe, &min_error); + cur_stripe->delta_y = -cur_stripe->delta_y; + cur_stripe->delta_x = -cur_stripe->delta_x; + } + else + { + find_overlap (ctx, cur_stripe, prev_stripe, &min_error); + } + total_error += min_error; - frame++; - prev_stripe = cur_stripe; - list_entry = g_slist_next(list_entry); + frame++; + prev_stripe = cur_stripe; + list_entry = g_slist_next (list_entry); - } while (frame < num_stripes); + } + while (frame < num_stripes); - g_timer_stop(timer); - fp_dbg("calc delta completed in %f secs", g_timer_elapsed(timer, NULL)); - g_timer_destroy(timer); + g_timer_stop (timer); + fp_dbg ("calc delta completed in %f secs", g_timer_elapsed (timer, NULL)); + g_timer_destroy (timer); - return total_error / num_stripes; + return total_error / num_stripes; } /** @@ -179,77 +191,88 @@ static unsigned int do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx, * Note that @num_stripes might be shorter than the length of the list, * if some stripes should be skipped. */ -void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx, - GSList *stripes, size_t num_stripes) +void +fpi_do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx, + GSList *stripes, size_t num_stripes) { - int err, rev_err; - err = do_movement_estimation(ctx, stripes, num_stripes, FALSE); - rev_err = do_movement_estimation(ctx, stripes, num_stripes, TRUE); - fp_dbg("errors: %d rev: %d", err, rev_err); - if (err < rev_err) { - do_movement_estimation(ctx, stripes, num_stripes, FALSE); - } + int err, rev_err; + + err = do_movement_estimation (ctx, stripes, num_stripes, FALSE); + rev_err = do_movement_estimation (ctx, stripes, num_stripes, TRUE); + fp_dbg ("errors: %d rev: %d", err, rev_err); + if (err < rev_err) + do_movement_estimation (ctx, stripes, num_stripes, FALSE); } -static inline void aes_blit_stripe(struct fpi_frame_asmbl_ctx *ctx, - struct fp_img *img, - struct fpi_frame *stripe, - int x, int y) +static inline void +aes_blit_stripe (struct fpi_frame_asmbl_ctx *ctx, + FpImage *img, + struct fpi_frame *stripe, + int x, int y) { - unsigned int ix, iy; - unsigned int fx, fy; - unsigned int width, height; + unsigned int ix, iy; + unsigned int fx, fy; + unsigned int width, height; - /* Find intersection */ - if (x < 0) { - width = ctx->frame_width + x; - ix = 0; - fx = -x; - } else { - ix = x; - fx = 0; - width = ctx->frame_width; - } - if ((ix + width) > img->width) - width = img->width - ix; + /* Find intersection */ + if (x < 0) + { + width = ctx->frame_width + x; + ix = 0; + fx = -x; + } + else + { + ix = x; + fx = 0; + width = ctx->frame_width; + } + if ((ix + width) > img->width) + width = img->width - ix; - if (y < 0) { - iy = 0; - fy = -y; - height = ctx->frame_height + y; - } else { - iy = y; - fy = 0; - height = ctx->frame_height; - } + if (y < 0) + { + iy = 0; + fy = -y; + height = ctx->frame_height + y; + } + else + { + iy = y; + fy = 0; + height = ctx->frame_height; + } - if (fx > ctx->frame_width) - return; + if (fx > ctx->frame_width) + return; - if (fy > ctx->frame_height) - return; + if (fy > ctx->frame_height) + return; - if (ix > img->width) - return; + if (ix > img->width) + return; - if (iy > img->height) - return; + if (iy > img->height) + return; - if ((iy + height) > img->height) - height = img->height - iy; + if ((iy + height) > img->height) + height = img->height - iy; - for (; fy < height; fy++, iy++) { - if (x < 0) { - ix = 0; - fx = -x; - } else { - ix = x; - fx = 0; - } - for (; fx < width; fx++, ix++) { - img->data[ix + (iy * img->width)] = ctx->get_pixel(ctx, stripe, fx, fy); - } - } + for (; fy < height; fy++, iy++) + { + if (x < 0) + { + ix = 0; + fx = -x; + } + else + { + ix = x; + fx = 0; + } + for (; fx < width; fx++, ix++) + img->data[ix + (iy * img->width)] = ctx->get_pixel (ctx, stripe, fx, fy); + } } /** @@ -266,130 +289,145 @@ static inline void aes_blit_stripe(struct fpi_frame_asmbl_ctx *ctx, * * Returns: a newly allocated #fp_img. */ -struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx, - GSList *stripes, size_t num_stripes) +FpImage * +fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx, + GSList *stripes, size_t num_stripes) { - GSList *stripe; - struct fp_img *img; - int height = 0; - int i, y, x; - gboolean reverse = FALSE; - struct fpi_frame *fpi_frame; + GSList *stripe; + FpImage *img; + int height = 0; + int i, y, x; + gboolean reverse = FALSE; + struct fpi_frame *fpi_frame; - //FIXME g_return_if_fail - BUG_ON(num_stripes == 0); - BUG_ON(ctx->image_width < ctx->frame_width); + //FIXME g_return_if_fail + BUG_ON (num_stripes == 0); + BUG_ON (ctx->image_width < ctx->frame_width); - /* Calculate height */ - i = 0; - stripe = stripes; + /* Calculate height */ + i = 0; + stripe = stripes; - /* No offset for 1st image */ - fpi_frame = stripe->data; - fpi_frame->delta_x = 0; - fpi_frame->delta_y = 0; - do { - fpi_frame = stripe->data; + /* No offset for 1st image */ + fpi_frame = stripe->data; + fpi_frame->delta_x = 0; + fpi_frame->delta_y = 0; + do + { + fpi_frame = stripe->data; - height += fpi_frame->delta_y; - i++; - stripe = g_slist_next(stripe); - } while (i < num_stripes); + height += fpi_frame->delta_y; + i++; + stripe = g_slist_next (stripe); + } + while (i < num_stripes); - fp_dbg("height is %d", height); + fp_dbg ("height is %d", height); - if (height < 0) { - reverse = TRUE; - height = -height; - } + if (height < 0) + { + reverse = TRUE; + height = -height; + } - /* For last frame */ - height += ctx->frame_height; + /* For last frame */ + height += ctx->frame_height; - /* Create buffer big enough for max image */ - img = fpi_img_new(ctx->image_width * height); - img->flags = FP_IMG_COLORS_INVERTED; - img->flags |= reverse ? 0 : FP_IMG_H_FLIPPED | FP_IMG_V_FLIPPED; - img->width = ctx->image_width; - img->height = height; + /* Create buffer big enough for max image */ + img = fp_image_new (ctx->image_width, height); + img->flags = FPI_IMAGE_COLORS_INVERTED; + img->flags |= reverse ? 0 : FPI_IMAGE_H_FLIPPED | FPI_IMAGE_V_FLIPPED; + img->width = ctx->image_width; + img->height = height; - /* Assemble stripes */ - i = 0; - stripe = stripes; - y = reverse ? (height - ctx->frame_height) : 0; - x = (ctx->image_width - ctx->frame_width) / 2; + /* Assemble stripes */ + i = 0; + stripe = stripes; + y = reverse ? (height - ctx->frame_height) : 0; + x = (ctx->image_width - ctx->frame_width) / 2; - do { - fpi_frame = stripe->data; + do + { + fpi_frame = stripe->data; - if(reverse) { - y += fpi_frame->delta_y; - x += fpi_frame->delta_x; - } + if(reverse) + { + y += fpi_frame->delta_y; + x += fpi_frame->delta_x; + } - aes_blit_stripe(ctx, img, fpi_frame, x, y); + aes_blit_stripe (ctx, img, fpi_frame, x, y); - if(!reverse) { - y += fpi_frame->delta_y; - x += fpi_frame->delta_x; - } + if(!reverse) + { + y += fpi_frame->delta_y; + x += fpi_frame->delta_x; + } - stripe = g_slist_next(stripe); - i++; - } while (i < num_stripes); + stripe = g_slist_next (stripe); + i++; + } + while (i < num_stripes); - return img; + return img; } -static int cmpint(const void *p1, const void *p2, gpointer data) +static int +cmpint (const void *p1, const void *p2, gpointer data) { - int a = *((int *)p1); - int b = *((int *)p2); - if (a < b) - return -1; - else if (a == b) - return 0; - else - return 1; + int a = *((int *) p1); + int b = *((int *) p2); + + if (a < b) + return -1; + else if (a == b) + return 0; + else + return 1; } -static void median_filter(int *data, int size, int filtersize) +static void +median_filter (int *data, int size, int filtersize) { - int i; - int *result = (int *)g_malloc0(size*sizeof(int)); - int *sortbuf = (int *)g_malloc0(filtersize*sizeof(int)); - for (i = 0; i < size; i++) { - int i1 = i - (filtersize-1)/2; - int i2 = i + (filtersize-1)/2; - if (i1 < 0) - i1 = 0; - if (i2 >= size) - i2 = size-1; - memmove(sortbuf, data+i1, (i2-i1+1)*sizeof(int)); - g_qsort_with_data(sortbuf, i2-i1+1, sizeof(int), cmpint, NULL); - result[i] = sortbuf[(i2-i1+1)/2]; - } - memmove(data, result, size*sizeof(int)); - g_free(result); - g_free(sortbuf); + int i; + int *result = (int *) g_malloc0 (size * sizeof (int)); + int *sortbuf = (int *) g_malloc0 (filtersize * sizeof (int)); + + for (i = 0; i < size; i++) + { + int i1 = i - (filtersize - 1) / 2; + int i2 = i + (filtersize - 1) / 2; + if (i1 < 0) + i1 = 0; + if (i2 >= size) + i2 = size - 1; + memmove (sortbuf, data + i1, (i2 - i1 + 1) * sizeof (int)); + g_qsort_with_data (sortbuf, i2 - i1 + 1, sizeof (int), cmpint, NULL); + result[i] = sortbuf[(i2 - i1 + 1) / 2]; + } + memmove (data, result, size * sizeof (int)); + g_free (result); + g_free (sortbuf); } -static void interpolate_lines(struct fpi_line_asmbl_ctx *ctx, - GSList *line1, float y1, GSList *line2, - float y2, unsigned char *output, float yi, int size) +static void +interpolate_lines (struct fpi_line_asmbl_ctx *ctx, + GSList *line1, float y1, GSList *line2, + float y2, unsigned char *output, float yi, int size) { - int i; - unsigned char p1, p2; + int i; + unsigned char p1, p2; - if (!line1 || !line2) - return; + if (!line1 || !line2) + return; - for (i = 0; i < size; i++) { - p1 = ctx->get_pixel(ctx, line1, i); - p2 = ctx->get_pixel(ctx, line2, i); - output[i] = (float)p1 - + (yi - y1)/(y2 - y1)*(p2 - p1); - } + for (i = 0; i < size; i++) + { + p1 = ctx->get_pixel (ctx, line1, i); + p2 = ctx->get_pixel (ctx, line2, i); + output[i] = (float) p1 + + (yi - y1) / (y2 - y1) * (p2 - p1); + } } /** @@ -406,82 +444,89 @@ static void interpolate_lines(struct fpi_line_asmbl_ctx *ctx, * * Returns: a newly allocated #fp_img. */ -struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx, - GSList *lines, size_t num_lines) +FpImage * +fpi_assemble_lines (struct fpi_line_asmbl_ctx *ctx, + GSList *lines, size_t num_lines) { - /* Number of output lines per distance between two scanners */ - int i; - GSList *row1, *row2; - float y = 0.0; - int line_ind = 0; - int *offsets = (int *)g_malloc0((num_lines / 2) * sizeof(int)); - unsigned char *output = g_malloc0(ctx->line_width * ctx->max_height); - struct fp_img *img; + /* Number of output lines per distance between two scanners */ + int i; + GSList *row1, *row2; + float y = 0.0; + int line_ind = 0; + int *offsets = (int *) g_malloc0 ((num_lines / 2) * sizeof (int)); + unsigned char *output = g_malloc0 (ctx->line_width * ctx->max_height); + FpImage *img; - g_return_val_if_fail (lines != NULL, NULL); - g_return_val_if_fail (num_lines >= 2, NULL); + g_return_val_if_fail (lines != NULL, NULL); + g_return_val_if_fail (num_lines >= 2, NULL); - fp_dbg("%"G_GINT64_FORMAT, g_get_real_time()); + fp_dbg ("%"G_GINT64_FORMAT, g_get_real_time ()); - row1 = lines; - for (i = 0; (i < num_lines - 1) && row1; i += 2) { - int bestmatch = i; - int bestdiff = 0; - int j, firstrow, lastrow; + row1 = lines; + for (i = 0; (i < num_lines - 1) && row1; i += 2) + { + int bestmatch = i; + int bestdiff = 0; + int j, firstrow, lastrow; - firstrow = i + 1; - lastrow = MIN(i + ctx->max_search_offset, num_lines - 1); + firstrow = i + 1; + lastrow = MIN (i + ctx->max_search_offset, num_lines - 1); - row2 = g_slist_next(row1); - for (j = firstrow; j <= lastrow; j++) { - int diff = ctx->get_deviation(ctx, - row1, - row2); - if ((j == firstrow) || (diff < bestdiff)) { - bestdiff = diff; - bestmatch = j; - } - row2 = g_slist_next(row2); - } - offsets[i / 2] = bestmatch - i; - fp_dbg("%d", offsets[i / 2]); - row1 = g_slist_next(row1); - if (row1) - row1 = g_slist_next(row1); - } + row2 = g_slist_next (row1); + for (j = firstrow; j <= lastrow; j++) + { + int diff = ctx->get_deviation (ctx, + row1, + row2); + if ((j == firstrow) || (diff < bestdiff)) + { + bestdiff = diff; + bestmatch = j; + } + row2 = g_slist_next (row2); + } + offsets[i / 2] = bestmatch - i; + fp_dbg ("%d", offsets[i / 2]); + row1 = g_slist_next (row1); + if (row1) + row1 = g_slist_next (row1); + } - median_filter(offsets, (num_lines / 2) - 1, ctx->median_filter_size); + median_filter (offsets, (num_lines / 2) - 1, ctx->median_filter_size); - fp_dbg("offsets_filtered: %"G_GINT64_FORMAT, g_get_real_time()); - for (i = 0; i <= (num_lines / 2) - 1; i++) - fp_dbg("%d", offsets[i]); - row1 = lines; - for (i = 0; i < num_lines - 1; i++, row1 = g_slist_next(row1)) { - int offset = offsets[i/2]; - if (offset > 0) { - float ynext = y + (float)ctx->resolution / offset; - while (line_ind < ynext) { - if (line_ind > ctx->max_height - 1) - goto out; - interpolate_lines(ctx, - row1, y, - g_slist_next(row1), - ynext, - output + line_ind * ctx->line_width, - line_ind, - ctx->line_width); - line_ind++; - } - y = ynext; - } - } + fp_dbg ("offsets_filtered: %"G_GINT64_FORMAT, g_get_real_time ()); + for (i = 0; i <= (num_lines / 2) - 1; i++) + fp_dbg ("%d", offsets[i]); + row1 = lines; + for (i = 0; i < num_lines - 1; i++, row1 = g_slist_next (row1)) + { + int offset = offsets[i / 2]; + if (offset > 0) + { + float ynext = y + (float) ctx->resolution / offset; + while (line_ind < ynext) + { + if (line_ind > ctx->max_height - 1) + goto out; + interpolate_lines (ctx, + row1, y, + g_slist_next (row1), + ynext, + output + line_ind * ctx->line_width, + line_ind, + ctx->line_width); + line_ind++; + } + y = ynext; + } + } out: - img = fpi_img_new(ctx->line_width * line_ind); - img->height = line_ind; - img->width = ctx->line_width; - img->flags = FP_IMG_V_FLIPPED; - memmove(img->data, output, ctx->line_width * line_ind); - g_free(offsets); - g_free(output); - return img; + img = fp_image_new (ctx->line_width, line_ind); + img->height = line_ind; + img->width = ctx->line_width; + img->flags = FPI_IMAGE_V_FLIPPED; + memmove (img->data, output, ctx->line_width * line_ind); + g_free (offsets); + g_free (output); + return img; } diff --git a/libfprint/fpi-assembling.h b/libfprint/fpi-assembling.h index d2a66515..ae9adc24 100644 --- a/libfprint/fpi-assembling.h +++ b/libfprint/fpi-assembling.h @@ -32,10 +32,11 @@ * populate delta_x and delta_y if the device supports hardware movement * estimation. */ -struct fpi_frame { - int delta_x; - int delta_y; - unsigned char data[0]; +struct fpi_frame +{ + int delta_x; + int delta_y; + unsigned char data[0]; }; /** @@ -52,21 +53,24 @@ struct fpi_frame { * hardware parameters of scanner. @image_width is usually 25% wider than * @frame_width to take horizontal movement into account. */ -struct fpi_frame_asmbl_ctx { - unsigned int frame_width; - unsigned int frame_height; - unsigned int image_width; - unsigned char (*get_pixel)(struct fpi_frame_asmbl_ctx *ctx, - struct fpi_frame *frame, - unsigned int x, - unsigned int y); +struct fpi_frame_asmbl_ctx +{ + unsigned int frame_width; + unsigned int frame_height; + unsigned int image_width; + unsigned char (*get_pixel)(struct fpi_frame_asmbl_ctx *ctx, + struct fpi_frame *frame, + unsigned int x, + unsigned int y); }; -void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx, - GSList *stripes, size_t num_stripes); +void fpi_do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx, + GSList *stripes, + size_t num_stripes); -struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx, - GSList *stripes, size_t num_stripes); +FpImage *fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx, + GSList *stripes, + size_t num_stripes); /** * fpi_line_asmbl_ctx: @@ -96,20 +100,23 @@ struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx, * returns two lines at a time, this function should be used to estimate the * difference between pairs of lines. */ -struct fpi_line_asmbl_ctx { - unsigned int line_width; - unsigned int max_height; - unsigned int resolution; - unsigned int median_filter_size; - unsigned int max_search_offset; - int (*get_deviation)(struct fpi_line_asmbl_ctx *ctx, - GSList *line1, GSList *line2); - unsigned char (*get_pixel)(struct fpi_line_asmbl_ctx *ctx, - GSList *line, - unsigned int x); +struct fpi_line_asmbl_ctx +{ + unsigned int line_width; + unsigned int max_height; + unsigned int resolution; + unsigned int median_filter_size; + unsigned int max_search_offset; + int (*get_deviation)(struct fpi_line_asmbl_ctx *ctx, + GSList *line1, + GSList *line2); + unsigned char (*get_pixel)(struct fpi_line_asmbl_ctx *ctx, + GSList *line, + unsigned int x); }; -struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx, - GSList *lines, size_t num_lines); +FpImage *fpi_assemble_lines (struct fpi_line_asmbl_ctx *ctx, + GSList *lines, + size_t num_lines); #endif diff --git a/libfprint/fpi-async.c b/libfprint/fpi-async.c deleted file mode 100644 index 6339c9ca..00000000 --- a/libfprint/fpi-async.c +++ /dev/null @@ -1,706 +0,0 @@ -/* - * Asynchronous I/O functionality - * Copyright (C) 2008 Daniel Drake - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#define FP_COMPONENT "async" - -#include "fp_internal.h" -#include "fpi-async.h" - -#include -#include -#include - -/* - * SECTION:fpi-async - * @title: Asynchronous operations reporting - * @short_description: Asynchronous operations reporting functions - * - * Those functions are used by primitive drivers to report back their - * current status. Most drivers, imaging ones, do not need to use them. - */ - -/* Drivers call this when device initialisation has completed */ -void fpi_drvcb_open_complete(struct fp_dev *dev, int status) -{ - fp_dbg("status %d", status); - BUG_ON(dev->state != DEV_STATE_INITIALIZING); - dev->state = (status) ? DEV_STATE_ERROR : DEV_STATE_INITIALIZED; - opened_devices = g_slist_prepend(opened_devices, dev); - if (dev->open_cb) - dev->open_cb(dev, status, dev->open_cb_data); -} - -/** - * fp_async_dev_open: - * @ddev: the struct #fp_dscv_dev discovered device to open - * @callback: the callback to call when the device has been opened - * @user_data: user data to pass to the callback - * - * Opens and initialises a device. This is the function you call in order - * to convert a #fp_dscv_dev discovered device into an actual device handle - * that you can perform operations with. - * - * The error status of the opening will be provided as an argument to the - * #fp_dev_open_cb callback. - * - * Returns: 0 on success, non-zero on error - */ -API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb callback, - void *user_data) -{ - struct fp_driver *drv; - struct fp_dev *dev; - libusb_device_handle *udevh; - int r; - - g_return_val_if_fail(ddev != NULL, -ENODEV); - g_return_val_if_fail (callback != NULL, -EINVAL); - - drv = ddev->drv; - - G_DEBUG_HERE(); - r = libusb_open(ddev->udev, &udevh); - if (r < 0) { - fp_err("usb_open failed, error %d", r); - return r; - } - - dev = g_malloc0(sizeof(*dev)); - dev->drv = drv; - dev->udev = udevh; - dev->__enroll_stage = -1; - dev->state = DEV_STATE_INITIALIZING; - dev->open_cb = callback; - dev->open_cb_data = user_data; - - if (!drv->open) { - fpi_drvcb_open_complete(dev, 0); - return 0; - } - - dev->state = DEV_STATE_INITIALIZING; - r = drv->open(dev, ddev->driver_data); - if (r) { - fp_err("device initialisation failed, driver=%s", drv->name); - libusb_close(udevh); - g_free(dev); - } - - return r; -} - -/* Drivers call this when device deinitialisation has completed */ -void fpi_drvcb_close_complete(struct fp_dev *dev) -{ - G_DEBUG_HERE(); - BUG_ON(dev->state != DEV_STATE_DEINITIALIZING); - dev->state = DEV_STATE_DEINITIALIZED; - fpi_timeout_cancel_all_for_dev(dev); - libusb_close(dev->udev); - if (dev->close_cb) - dev->close_cb(dev, dev->close_cb_data); - g_free(dev); -} - -/** - * fp_async_dev_close: - * @dev: the struct #fp_dev device - * @callback: the callback to call when the device has been closed - * @user_data: user data to pass to the callback - * - * Closes a device. You must call this function when you have finished using - * a fingerprint device. - */ -API_EXPORTED void fp_async_dev_close(struct fp_dev *dev, - fp_operation_stop_cb callback, void *user_data) -{ - struct fp_driver *drv; - - g_return_if_fail (dev != NULL); - - drv = dev->drv; - - g_return_if_fail (drv->close != NULL); - - if (g_slist_index(opened_devices, (gconstpointer) dev) == -1) - fp_err("device %p not in opened list!", dev); - opened_devices = g_slist_remove(opened_devices, (gconstpointer) dev); - - dev->close_cb = callback; - dev->close_cb_data = user_data; - dev->state = DEV_STATE_DEINITIALIZING; - drv->close(dev); -} - -/* Drivers call this when enrollment has started */ -void fpi_drvcb_enroll_started(struct fp_dev *dev, int status) -{ - fp_dbg("status %d", status); - BUG_ON(dev->state != DEV_STATE_ENROLL_STARTING); - if (status) { - if (status > 0) { - status = -status; - fp_dbg("adjusted to %d", status); - } - dev->state = DEV_STATE_ERROR; - if (dev->enroll_stage_cb) - dev->enroll_stage_cb(dev, status, NULL, NULL, - dev->enroll_stage_cb_data); - } else { - dev->state = DEV_STATE_ENROLLING; - } -} - -/** - * fp_async_enroll_start: - * @dev: the struct #fp_dev device - * @callback: the callback to call for each stage of the enrollment - * @user_data: user data to pass to the callback - * - * Starts an enrollment and calls @callback for each enrollment stage. - * See [Enrolling](libfprint-Devices-operations.html#enrolling) - * for an explanation of enroll stages. - * - * Returns: 0 on success, non-zero on error - */ -API_EXPORTED int fp_async_enroll_start(struct fp_dev *dev, - fp_enroll_stage_cb callback, void *user_data) -{ - struct fp_driver *drv; - int r; - - g_return_val_if_fail(dev != NULL, -ENODEV); - g_return_val_if_fail (callback != NULL, -EINVAL); - - drv = dev->drv; - - if (!dev->nr_enroll_stages || !drv->enroll_start) { - fp_err("driver %s has 0 enroll stages or no enroll func", - drv->name); - return -ENOTSUP; - } - - fp_dbg("starting enrollment"); - dev->enroll_stage_cb = callback; - dev->enroll_stage_cb_data = user_data; - - dev->state = DEV_STATE_ENROLL_STARTING; - r = drv->enroll_start(dev); - if (r < 0) { - dev->enroll_stage_cb = NULL; - fp_err("failed to start enrollment"); - dev->state = DEV_STATE_ERROR; - } - - return r; -} - -/* Drivers call this when an enroll stage has completed */ -void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result, - struct fp_print_data *data, struct fp_img *img) -{ - BUG_ON(dev->state != DEV_STATE_ENROLLING); - fp_dbg("result %d", result); - if (!dev->enroll_stage_cb) { - fp_dbg("ignoring enroll result as no callback is subscribed"); - return; - } - if (result == FP_ENROLL_COMPLETE && !data) { - fp_err("BUG: complete but no data?"); - result = FP_ENROLL_FAIL; - } - dev->enroll_stage_cb(dev, result, data, img, dev->enroll_stage_cb_data); -} - -/* Drivers call this when enrollment has stopped */ -void fpi_drvcb_enroll_stopped(struct fp_dev *dev) -{ - G_DEBUG_HERE(); - BUG_ON(dev->state != DEV_STATE_ENROLL_STOPPING); - dev->state = DEV_STATE_INITIALIZED; - if (dev->enroll_stop_cb) - dev->enroll_stop_cb(dev, dev->enroll_stop_cb_data); -} - -/** - * fp_async_enroll_stop: - * @dev: the struct #fp_dev device - * @callback: the callback to call when the enrollment has been cancelled - * @user_data: user data to pass to the callback - * - * Stops an ongoing enrollment started with fp_async_enroll_start(). - * - * Returns: 0 on success, non-zero on error - */ -API_EXPORTED int fp_async_enroll_stop(struct fp_dev *dev, - fp_operation_stop_cb callback, void *user_data) -{ - struct fp_driver *drv; - int r; - - g_return_val_if_fail(dev != NULL, -ENODEV); - - drv = dev->drv; - - G_DEBUG_HERE(); - if (!drv->enroll_start) - return -ENOTSUP; - - dev->enroll_stage_cb = NULL; - dev->enroll_stop_cb = callback; - dev->enroll_stop_cb_data = user_data; - dev->state = DEV_STATE_ENROLL_STOPPING; - - if (!drv->enroll_stop) { - fpi_drvcb_enroll_stopped(dev); - return 0; - } - - r = drv->enroll_stop(dev); - if (r < 0) { - fp_err("failed to stop enrollment"); - dev->enroll_stop_cb = NULL; - } - - return r; -} - -/** - * fp_async_verify_start: - * @dev: the struct #fp_dev device - * @data: the print to verify against. Must have been previously - * enrolled with a device compatible to the device selected to perform the scan - * @callback: the callback to call when the verification has finished - * @user_data: user data to pass to the callback - * - * Starts a verification and calls @callback when the verification has - * finished. See fp_verify_finger_img() for the synchronous API. When the - * @callback has been called, you must call fp_async_verify_stop(). - * - * Returns: 0 on success, non-zero on error - */ -API_EXPORTED int fp_async_verify_start(struct fp_dev *dev, - struct fp_print_data *data, fp_img_operation_cb callback, void *user_data) -{ - struct fp_driver *drv; - int r; - - g_return_val_if_fail(dev != NULL, -ENODEV); - g_return_val_if_fail (callback != NULL, -EINVAL); - - drv = dev->drv; - - G_DEBUG_HERE(); - if (!drv->verify_start) - return -ENOTSUP; - - dev->state = DEV_STATE_VERIFY_STARTING; - dev->verify_cb = callback; - dev->verify_cb_data = user_data; - dev->verify_data = data; - - r = drv->verify_start(dev); - if (r < 0) { - dev->verify_cb = NULL; - dev->state = DEV_STATE_ERROR; - fp_err("failed to start verification, error %d", r); - } - return r; -} - -/* Drivers call this when verification has started */ -void fpi_drvcb_verify_started(struct fp_dev *dev, int status) -{ - G_DEBUG_HERE(); - BUG_ON(dev->state != DEV_STATE_VERIFY_STARTING); - if (status) { - if (status > 0) { - status = -status; - fp_dbg("adjusted to %d", status); - } - dev->state = DEV_STATE_ERROR; - if (dev->verify_cb) - dev->verify_cb(dev, status, NULL, dev->verify_cb_data); - } else { - dev->state = DEV_STATE_VERIFYING; - } -} - -/* Drivers call this to report a verify result (which might mark completion) */ -void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result, - struct fp_img *img) -{ - fp_dbg("result %d", result); - BUG_ON(dev->state != DEV_STATE_VERIFYING); - if (result < 0 || result == FP_VERIFY_NO_MATCH - || result == FP_VERIFY_MATCH) - dev->state = DEV_STATE_VERIFY_DONE; - - if (dev->verify_cb) - dev->verify_cb(dev, result, img, dev->verify_cb_data); - else - fp_dbg("ignoring verify result as no callback is subscribed"); -} - -/* Drivers call this when verification has stopped */ -void fpi_drvcb_verify_stopped(struct fp_dev *dev) -{ - G_DEBUG_HERE(); - BUG_ON(dev->state != DEV_STATE_VERIFY_STOPPING); - dev->state = DEV_STATE_INITIALIZED; - if (dev->verify_stop_cb) - dev->verify_stop_cb(dev, dev->verify_stop_cb_data); -} - -/** - * fp_async_verify_stop: - * @dev: the struct #fp_dev device - * @callback: the callback to call to finish a verification - * @user_data: user data to pass to the callback - * - * Finishes an ongoing verification started with fp_async_verify_start(). - * - * Returns: 0 on success, non-zero on error - */ -API_EXPORTED int fp_async_verify_stop(struct fp_dev *dev, - fp_operation_stop_cb callback, void *user_data) -{ - struct fp_driver *drv; - gboolean iterating = (dev->state == DEV_STATE_VERIFYING); - int r; - - g_return_val_if_fail(dev != NULL, -ENODEV); - - G_DEBUG_HERE(); - - if (dev->state == DEV_STATE_VERIFY_STOPPING) { - fp_dbg ("Already stopping verification, returning -EINPROGRESS"); - return -EINPROGRESS; - } - - if (dev->state == DEV_STATE_INITIALIZED) { - if (callback) - callback(dev, user_data); - return 0; - } - - drv = dev->drv; - - BUG_ON(dev->state != DEV_STATE_ERROR - && dev->state != DEV_STATE_VERIFYING - && dev->state != DEV_STATE_VERIFY_DONE); - - dev->verify_cb = NULL; - dev->verify_stop_cb = callback; - dev->verify_stop_cb_data = user_data; - dev->state = DEV_STATE_VERIFY_STOPPING; - - if (!drv->verify_start) - return -ENOTSUP; - if (!drv->verify_stop) { - dev->state = DEV_STATE_INITIALIZED; - fpi_drvcb_verify_stopped(dev); - return 0; - } - - r = drv->verify_stop(dev, iterating); - if (r < 0) { - fp_err("failed to stop verification"); - dev->verify_stop_cb = NULL; - } - return r; -} - -/** - * fp_async_identify_start: - * @dev: the struct #fp_dev device - * @gallery: NULL-terminated array of pointers to the prints to - * identify against. Each one must have been previously enrolled with a device - * compatible to the device selected to perform the scan - * @callback: the callback to call when the identification has finished - * @user_data: user data to pass to the callback - * - * Performs a new scan and verifies it against a previously enrolled print. - * See also: fp_verify_finger_img() - * - * Returns: 0 on success, non-zero on error - */ -API_EXPORTED int fp_async_identify_start(struct fp_dev *dev, - struct fp_print_data **gallery, fp_identify_cb callback, void *user_data) -{ - struct fp_driver *drv; - int r; - - g_return_val_if_fail(dev != NULL, -ENODEV); - g_return_val_if_fail (callback != NULL, -EINVAL); - - drv = dev->drv; - - G_DEBUG_HERE(); - if (!drv->identify_start) - return -ENOTSUP; - dev->state = DEV_STATE_IDENTIFY_STARTING; - dev->identify_cb = callback; - dev->identify_cb_data = user_data; - dev->identify_gallery = gallery; - - r = drv->identify_start(dev); - if (r < 0) { - fp_err("identify_start failed with error %d", r); - dev->identify_cb = NULL; - dev->state = DEV_STATE_ERROR; - } - return r; -} - -/* Driver-lib: identification has started, expect results soon */ -void fpi_drvcb_identify_started(struct fp_dev *dev, int status) -{ - fp_dbg("status %d", status); - BUG_ON(dev->state != DEV_STATE_IDENTIFY_STARTING); - if (status) { - if (status > 0) { - status = -status; - fp_dbg("adjusted to %d", status); - } - dev->state = DEV_STATE_ERROR; - if (dev->identify_cb) - dev->identify_cb(dev, status, 0, NULL, dev->identify_cb_data); - } else { - dev->state = DEV_STATE_IDENTIFYING; - } -} - -/* Drivers report an identify result (which might mark completion) */ -void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result, - size_t match_offset, struct fp_img *img) -{ - fp_dbg("result %d", result); - BUG_ON(dev->state != DEV_STATE_IDENTIFYING - && dev->state != DEV_STATE_ERROR); - if (result < 0 || result == FP_VERIFY_NO_MATCH - || result == FP_VERIFY_MATCH) - dev->state = DEV_STATE_IDENTIFY_DONE; - - if (dev->identify_cb) - dev->identify_cb(dev, result, match_offset, img, dev->identify_cb_data); - else - fp_dbg("ignoring verify result as no callback is subscribed"); -} - -/** - * fp_async_identify_stop: - * @dev: the struct #fp_dev device - * @callback: the callback to call when the identification has stopped - * @user_data: user data to pass to the callback - * - * Stops an ongoing identification started with fp_async_identify_start(). - * - * Returns: 0 on success, non-zero on error - */ -API_EXPORTED int fp_async_identify_stop(struct fp_dev *dev, - fp_operation_stop_cb callback, void *user_data) -{ - struct fp_driver *drv; - gboolean iterating = (dev->state == DEV_STATE_IDENTIFYING); - int r; - - g_return_val_if_fail(dev != NULL, -ENODEV); - - G_DEBUG_HERE(); - - if (dev->state == DEV_STATE_IDENTIFY_STOPPING) { - fp_dbg ("Already stopping identification, returning -EINPROGRESS"); - return -EINPROGRESS; - } - - if (dev->state == DEV_STATE_INITIALIZED) { - if (callback) - callback(dev, user_data); - return 0; - } - - drv = dev->drv; - - BUG_ON(dev->state != DEV_STATE_IDENTIFYING - && dev->state != DEV_STATE_IDENTIFY_DONE); - - dev->state = DEV_STATE_IDENTIFY_STOPPING; - dev->identify_cb = NULL; - dev->identify_stop_cb = callback; - dev->identify_stop_cb_data = user_data; - - if (!drv->identify_start) - return -ENOTSUP; - if (!drv->identify_stop) { - dev->state = DEV_STATE_INITIALIZED; - fpi_drvcb_identify_stopped(dev); - return 0; - } - - r = drv->identify_stop(dev, iterating); - if (r < 0) { - fp_err("failed to stop identification"); - dev->identify_stop_cb = NULL; - } - - return r; -} - -/* Drivers call this when identification has stopped */ -void fpi_drvcb_identify_stopped(struct fp_dev *dev) -{ - G_DEBUG_HERE(); - BUG_ON(dev->state != DEV_STATE_IDENTIFY_STOPPING); - dev->state = DEV_STATE_INITIALIZED; - if (dev->identify_stop_cb) - dev->identify_stop_cb(dev, dev->identify_stop_cb_data); -} - -/** - * fp_async_capture_start: - * @dev: the struct #fp_dev device - * @unconditional: whether to unconditionally capture an image, or to only capture when a finger is detected - * @callback: the callback to call when the capture has finished - * @user_data: user data to pass to the callback - * - * Start the capture of an #fp_img from a device. When the @callback has been called, - * you must call fp_async_capture_stop(). - * - * Returns: 0 on success, non-zero on error. -ENOTSUP indicates that either the - * @unconditional flag was set but the device does not support this, or that the• - * device does not support imaging - */ -API_EXPORTED int fp_async_capture_start(struct fp_dev *dev, int unconditional, - fp_img_operation_cb callback, void *user_data) -{ - struct fp_driver *drv; - int r; - - g_return_val_if_fail(dev != NULL, -ENODEV); - g_return_val_if_fail (callback != NULL, -EINVAL); - - drv = dev->drv; - - G_DEBUG_HERE(); - if (!drv->capture_start) - return -ENOTSUP; - - dev->state = DEV_STATE_CAPTURE_STARTING; - dev->capture_cb = callback; - dev->capture_cb_data = user_data; - dev->unconditional_capture = unconditional; - - r = drv->capture_start(dev); - if (r < 0) { - dev->capture_cb = NULL; - dev->state = DEV_STATE_ERROR; - fp_err("failed to start capture, error %d", r); - } - return r; -} - -/* Drivers call this when capture has started */ -void fpi_drvcb_capture_started(struct fp_dev *dev, int status) -{ - G_DEBUG_HERE(); - BUG_ON(dev->state != DEV_STATE_CAPTURE_STARTING); - if (status) { - if (status > 0) { - status = -status; - fp_dbg("adjusted to %d", status); - } - dev->state = DEV_STATE_ERROR; - if (dev->capture_cb) - dev->capture_cb(dev, status, NULL, dev->capture_cb_data); - } else { - dev->state = DEV_STATE_CAPTURING; - } -} - -/* Drivers call this to report a capture result (which might mark completion) */ -void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result, - struct fp_img *img) -{ - fp_dbg("result %d", result); - BUG_ON(dev->state != DEV_STATE_CAPTURING); - if (result < 0 || result == FP_CAPTURE_COMPLETE) - dev->state = DEV_STATE_CAPTURE_DONE; - - if (dev->capture_cb) - dev->capture_cb(dev, result, img, dev->capture_cb_data); - else - fp_dbg("ignoring capture result as no callback is subscribed"); -} - -/* Drivers call this when capture has stopped */ -void fpi_drvcb_capture_stopped(struct fp_dev *dev) -{ - G_DEBUG_HERE(); - BUG_ON(dev->state != DEV_STATE_CAPTURE_STOPPING); - dev->state = DEV_STATE_INITIALIZED; - if (dev->capture_stop_cb) - dev->capture_stop_cb(dev, dev->capture_stop_cb_data); -} - -/** - * fp_async_capture_stop: - * @dev: the struct #fp_dev device - * @callback: the callback to call when the capture has been stopped - * @user_data: user data to pass to the callback - * - * Stops an ongoing verification started with fp_async_capture_start(). - * - * Returns: 0 on success, non-zero on error - */ -API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev, - fp_operation_stop_cb callback, void *user_data) -{ - struct fp_driver *drv; - int r; - - g_return_val_if_fail(dev != NULL, -ENODEV); - - drv = dev->drv; - - G_DEBUG_HERE(); - BUG_ON(dev->state != DEV_STATE_ERROR - && dev->state != DEV_STATE_CAPTURING - && dev->state != DEV_STATE_CAPTURE_DONE); - - dev->capture_cb = NULL; - dev->capture_stop_cb = callback; - dev->capture_stop_cb_data = user_data; - dev->state = DEV_STATE_CAPTURE_STOPPING; - - if (!drv->capture_start) - return -ENOTSUP; - if (!drv->capture_stop) { - dev->state = DEV_STATE_INITIALIZED; - fpi_drvcb_capture_stopped(dev); - return 0; - } - - r = drv->capture_stop(dev); - if (r < 0) { - fp_err("failed to stop capture"); - dev->capture_stop_cb = NULL; - } - return r; -} diff --git a/libfprint/fpi-async.h b/libfprint/fpi-async.h deleted file mode 100644 index cf6fa32e..00000000 --- a/libfprint/fpi-async.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2007-2008 Daniel Drake - * Copyright (C) 2018 Bastien Nocera - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __FPI_ASYNC_H__ -#define __FPI_ASYNC_H__ - -#include "fpi-dev.h" -#include "fpi-data.h" - -void fpi_drvcb_open_complete(struct fp_dev *dev, int status); -void fpi_drvcb_close_complete(struct fp_dev *dev); - -void fpi_drvcb_enroll_started(struct fp_dev *dev, int status); -void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result, - struct fp_print_data *data, struct fp_img *img); -void fpi_drvcb_enroll_stopped(struct fp_dev *dev); - -void fpi_drvcb_verify_started(struct fp_dev *dev, int status); -void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result, - struct fp_img *img); -void fpi_drvcb_verify_stopped(struct fp_dev *dev); - -#endif diff --git a/libfprint/fpi-context.h b/libfprint/fpi-context.h new file mode 100644 index 00000000..c5a10750 --- /dev/null +++ b/libfprint/fpi-context.h @@ -0,0 +1,33 @@ +/* + * FpContext - A FPrint context + * Copyright (C) 2019 Benjamin Berg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#pragma once + +#include +#include "fp-context.h" + +/** + * fpi_get_driver_types: + * @drivers: #GArray to be filled with all driver types + * + * This function is purely for private used. It is solely part of the public + * API as it is useful during build time. + * + * Stability: private + */ +void fpi_get_driver_types (GArray *drivers); diff --git a/libfprint/fpi-core.c b/libfprint/fpi-core.c deleted file mode 100644 index ee158bdd..00000000 --- a/libfprint/fpi-core.c +++ /dev/null @@ -1,730 +0,0 @@ -/* - * Core functions for libfprint - * Copyright (C) 2007-2008 Daniel Drake - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include - -#include -#include - -#include "fp_internal.h" - -libusb_context *fpi_usb_ctx = NULL; -GSList *opened_devices = NULL; - -/** - * SECTION:discovery - * @title: Device discovery - * @short_description: Device discovery functions - * - * These functions allow you to scan the system for supported fingerprint - * scanning hardware. This is your starting point when integrating libfprint - * into your software. - * - * When you've identified a discovered device that you would like to control, - * you can open it with fp_dev_open(). Note that discovered devices may no - * longer be available at the time when you want to open them, for example - * the user may have unplugged the device. - */ - -/** - * SECTION:drv - * @title: Driver operations - * @short_description: Driver operation functions - * - * Internally, libfprint is abstracted into various drivers to communicate - * with the different types of supported fingerprint readers. libfprint works - * hard so that you don't have to care about these internal abstractions, - * however there are some situations where you may be interested in a little - * behind-the-scenes driver info. - * - * You can obtain the driver for a device using fp_dev_get_driver(), which - * you can pass to the functions documented on this page. - */ - -/** - * SECTION:dev - * @title: Devices operations - * @short_description: Device operation functions - * - * In order to interact with fingerprint scanners, your software will - * interface primarily with libfprint's representation of devices, detailed - * on this page. - * - * # Enrolling # {#enrolling} - * - * Enrolling is represented within libfprint as a multi-stage process. This - * slightly complicates things for application developers, but is required - * for a smooth process. - * - * Some devices require the user to scan their finger multiple times in - * order to complete the enrollment process. libfprint must return control - * to your application in-between each scan in order for your application to - * instruct the user to swipe their finger again. Each scan is referred to - * as a stage, so a device that requires 3 scans for enrollment corresponds - * to you running 3 enrollment stages using libfprint. - * - * The fp_dev_get_nr_enroll_stages() function can be used to find out how - * many enroll stages are needed. - * - * In order to complete an enroll stage, you call an enroll function such - * as fp_enroll_finger(). The return of this function does not necessarily - * indicate that a stage has completed though, as the user may not have - * produced a good enough scan. Each stage may have to be retried several - * times. - * - * The exact semantics of the enroll functions are described in the - * fp_enroll_finger() documentation. You should pay careful attention to the - * details. - * - * # Imaging # {#imaging} - * - * libfprint provides you with some ways to retrieve images of scanned - * fingers, such as the fp_dev_img_capture() function, or some enroll/verify - * function variants which provide images. You may wish to do something with - * such images in your application. - * - * However, you must be aware that not all hardware supported by libfprint - * operates like this. Most hardware does operate simply by sending - * fingerprint images to the host computer for further processing, but some - * devices do all fingerprint processing in hardware and do not present images - * to the host computer. - * - * You can use fp_dev_supports_imaging() to see if image capture is possible - * on a particular device. Your application must be able to cope with the - * fact that libfprint does support regular operations (e.g. enrolling and - * verification) on some devices which do not provide images. - */ - -/** - * SECTION:fpi-core - * @title: Driver structures - * @short_description: Driver structures - * - * Driver structures need to be defined inside each driver in - * order for the core library to know what function to call, and the capabilities - * of the driver and the devices it supports. - */ - -/** - * SECTION:fpi-core-img - * @title: Image driver structures - * @short_description: Image driver structures - * - * Image driver structures need to be defined inside each image driver in - * order for the core library to know what function to call, and the capabilities - * of the driver and the devices it supports. Its structure is based off the - * #fp_driver struct. - */ - -static GSList *registered_drivers = NULL; - -static void register_driver(struct fp_driver *drv) -{ - if (drv->id == 0) { - fp_err("not registering driver %s: driver ID is 0", drv->name); - return; - } - registered_drivers = g_slist_prepend(registered_drivers, (gpointer) drv); - fp_dbg("registered driver %s", drv->name); -} - -#include "drivers_arrays.h" - -static void register_drivers(void) -{ - unsigned int i; - - for (i = 0; i < G_N_ELEMENTS(primitive_drivers); i++) - register_driver(primitive_drivers[i]); - - for (i = 0; i < G_N_ELEMENTS(img_drivers); i++) { - struct fp_img_driver *imgdriver = img_drivers[i]; - fpi_img_driver_setup(imgdriver); - register_driver(&imgdriver->driver); - } -} - -API_EXPORTED struct fp_driver **fprint_get_drivers (void) -{ - GPtrArray *array; - unsigned int i; - - array = g_ptr_array_new (); - for (i = 0; i < G_N_ELEMENTS(primitive_drivers); i++) - g_ptr_array_add (array, primitive_drivers[i]); - - for (i = 0; i < G_N_ELEMENTS(img_drivers); i++) - g_ptr_array_add (array, &(img_drivers[i]->driver)); - - /* Add a null item terminating the array */ - g_ptr_array_add (array, NULL); - - return (struct fp_driver **) g_ptr_array_free (array, FALSE); -} - -static struct fp_driver *find_supporting_driver(libusb_device *udev, - const struct usb_id **usb_id, uint32_t *devtype) -{ - int ret; - GSList *elem = registered_drivers; - struct libusb_device_descriptor dsc; - - const struct usb_id *best_usb_id; - struct fp_driver *best_drv; - uint32_t best_devtype; - int drv_score = 0; - - ret = libusb_get_device_descriptor(udev, &dsc); - if (ret < 0) { - fp_err("Failed to get device descriptor"); - return NULL; - } - - best_drv = NULL; - best_devtype = 0; - - do { - struct fp_driver *drv = elem->data; - uint32_t type = 0; - const struct usb_id *id; - - for (id = drv->id_table; id->vendor; id++) { - if (dsc.idVendor == id->vendor && dsc.idProduct == id->product) { - if (drv->discover) { - int r = drv->discover(&dsc, &type); - if (r < 0) - fp_err("%s discover failed, code %d", drv->name, r); - if (r <= 0) - continue; - /* Has a discover function, and matched our device */ - drv_score = 100; - } else { - /* Already got a driver as good */ - if (drv_score >= 50) - continue; - drv_score = 50; - } - fp_dbg("driver %s supports USB device %04x:%04x", - drv->name, id->vendor, id->product); - best_usb_id = id; - best_drv = drv; - best_devtype = type; - - /* We found the best possible driver */ - if (drv_score == 100) - break; - } - } - } while ((elem = g_slist_next(elem))); - - if (best_drv != NULL) { - fp_dbg("selected driver %s supports USB device %04x:%04x", - best_drv->name, dsc.idVendor, dsc.idProduct); - *devtype = best_devtype; - *usb_id = best_usb_id; - } - - return best_drv; -} - -static struct fp_dscv_dev *discover_dev(libusb_device *udev) -{ - const struct usb_id *usb_id; - struct fp_driver *drv; - struct fp_dscv_dev *ddev; - uint32_t devtype; - - drv = find_supporting_driver(udev, &usb_id, &devtype); - - if (!drv) - return NULL; - - ddev = g_malloc0(sizeof(*ddev)); - ddev->drv = drv; - ddev->udev = udev; - ddev->driver_data = usb_id->driver_data; - ddev->devtype = devtype; - return ddev; -} - -/** - * fp_discover_devs: - * - * Scans the system and returns a list of discovered devices. This is your - * entry point into finding a fingerprint reader to operate. Note that %NULL - * is only returned on error. When there are no supported readers available, - * an empty list is returned instead. - * - * Returns: a nul-terminated list of discovered devices or %NULL on error. - * Must be freed with fp_dscv_devs_free() after use. - */ -API_EXPORTED struct fp_dscv_dev **fp_discover_devs(void) -{ - GPtrArray *tmparray; - libusb_device *udev; - libusb_device **devs; - int r; - int i = 0; - - g_return_val_if_fail (registered_drivers != NULL, NULL); - - r = libusb_get_device_list(fpi_usb_ctx, &devs); - if (r < 0) { - fp_err("couldn't enumerate USB devices, error %d", r); - return NULL; - } - - tmparray = g_ptr_array_new (); - - /* Check each device against each driver, temporarily storing successfully - * discovered devices in a GPtrArray. */ - while ((udev = devs[i++]) != NULL) { - struct fp_dscv_dev *ddev = discover_dev(udev); - if (!ddev) - continue; - /* discover_dev() doesn't hold a reference to the udev, - * so increase the reference for ddev to hold this ref */ - libusb_ref_device(udev); - g_ptr_array_add (tmparray, (gpointer) ddev); - } - libusb_free_device_list(devs, 1); - - /* Convert our temporary array into a standard NULL-terminated pointer - * array. */ - g_ptr_array_add (tmparray, NULL); - return (struct fp_dscv_dev **) g_ptr_array_free (tmparray, FALSE); -} - -/** - * fp_dscv_devs_free: - * @devs: the list of discovered devices. If %NULL, function simply - * returns. - * - * Free a list of discovered devices. This function destroys the list and all - * discovered devices that it included, so make sure you have opened your - * discovered device before freeing the list. - */ -API_EXPORTED void fp_dscv_devs_free(struct fp_dscv_dev **devs) -{ - int i; - if (!devs) - return; - - for (i = 0; devs[i]; i++) { - libusb_unref_device(devs[i]->udev); - g_free(devs[i]); - } - g_free(devs); -} - -/** - * fp_dscv_dev_get_driver: - * @dev: the discovered device - * - * Gets the #fp_driver for a discovered device. - * - * Returns: the driver backing the device - */ -API_EXPORTED struct fp_driver *fp_dscv_dev_get_driver(struct fp_dscv_dev *dev) -{ - g_return_val_if_fail(dev, NULL); - - return dev->drv; -} - -/** - * fp_dscv_dev_get_driver_id: - * @dev: a discovered fingerprint device - * - * Returns a unique driver identifier for the underlying driver - * for that device. - * - * Returns: the ID for #dev - */ -API_EXPORTED uint16_t fp_dscv_dev_get_driver_id(struct fp_dscv_dev *dev) -{ - g_return_val_if_fail(dev, 0); - - return fp_driver_get_driver_id(fp_dscv_dev_get_driver(dev)); -} - -/** - * fp_dscv_dev_get_devtype: - * @dev: the discovered device - * - * Gets the [devtype](advanced-topics.html#device-types) for a discovered device. - * - * Returns: the devtype of the device - */ -API_EXPORTED uint32_t fp_dscv_dev_get_devtype(struct fp_dscv_dev *dev) -{ - g_return_val_if_fail(dev, 0); - - return dev->devtype; -} - -enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv) -{ - switch (drv->type) { - case DRIVER_PRIMITIVE: - return PRINT_DATA_RAW; - case DRIVER_IMAGING: - return PRINT_DATA_NBIS_MINUTIAE; - default: - fp_err("unrecognised drv type %d", drv->type); - return PRINT_DATA_RAW; - } -} - -/** - * fp_dscv_dev_supports_print_data: - * @dev: the discovered device - * @print: the print for compatibility checking - * - * Determines if a specific #fp_print_data stored print appears to be - * compatible with a discovered device. - * - * Returns: 1 if the print is compatible with the device, 0 otherwise - */ -API_EXPORTED int fp_dscv_dev_supports_print_data(struct fp_dscv_dev *dev, - struct fp_print_data *print) -{ - g_return_val_if_fail(dev, 0); - g_return_val_if_fail(print, 0); - - return fpi_print_data_compatible(dev->drv->id, dev->devtype, - fpi_driver_get_data_type(dev->drv), print->driver_id, print->devtype, - print->type); -} - -/** - * fp_dev_get_driver: - * @dev: the struct #fp_dev device - * - * Get the #fp_driver for a fingerprint device. - * - * Returns: the driver controlling the device - */ -API_EXPORTED struct fp_driver *fp_dev_get_driver(struct fp_dev *dev) -{ - g_return_val_if_fail(dev, NULL); - - return dev->drv; -} - -/** - * fp_dev_get_nr_enroll_stages: - * @dev: the struct #fp_dev device - * - * Gets the number of [enroll stages](intro.html#enrollment) required to enroll a - * fingerprint with the device. - * - * Returns: the number of enroll stages - */ -API_EXPORTED int fp_dev_get_nr_enroll_stages(struct fp_dev *dev) -{ - g_return_val_if_fail(dev, 0); - - return dev->nr_enroll_stages; -} - -/** - * fp_dev_get_devtype: - * @dev: the struct #fp_dev device - * - * Gets the [devtype](advanced-topics.html#device-types) for a device. - * - * Returns: the devtype - */ -API_EXPORTED uint32_t fp_dev_get_devtype(struct fp_dev *dev) -{ - g_return_val_if_fail(dev, 0); - - return dev->devtype; -} - -/** - * fp_dev_supports_print_data: - * @dev: the struct #fp_dev device - * @data: the stored print - * - * Determines if a stored print is compatible with a certain device. - * - * Returns: 1 if the print is compatible with the device, 0 if not - */ -API_EXPORTED int fp_dev_supports_print_data(struct fp_dev *dev, - struct fp_print_data *data) -{ - g_return_val_if_fail(dev, 0); - g_return_val_if_fail(data, 0); - - return fpi_print_data_compatible(dev->drv->id, dev->devtype, - fpi_driver_get_data_type(dev->drv), data->driver_id, data->devtype, - data->type); -} - -/** - * fp_driver_get_name: - * @drv: the driver - * - * Retrieves the name of the driver. For example: "upekts" - * - * Returns: the driver name. Must not be modified or freed. - */ -API_EXPORTED const char *fp_driver_get_name(struct fp_driver *drv) -{ - g_return_val_if_fail(drv, NULL); - - return drv->name; -} - -/** - * fp_driver_get_full_name: - * @drv: the driver - * - * Retrieves a descriptive name of the driver. For example: "UPEK TouchStrip" - * - * Returns: the descriptive name. Must not be modified or freed. - */ -API_EXPORTED const char *fp_driver_get_full_name(struct fp_driver *drv) -{ - g_return_val_if_fail(drv, NULL); - - return drv->full_name; -} - -/** - * fp_driver_get_driver_id: - * @drv: the driver - * - * Retrieves the driver ID code for a driver. - * - * Returns: the driver ID - */ -API_EXPORTED uint16_t fp_driver_get_driver_id(struct fp_driver *drv) -{ - g_return_val_if_fail(drv, 0); - - return drv->id; -} - -/** - * fp_driver_get_scan_type: - * @drv: the driver - * - * Retrieves the scan type for the devices associated with the driver. - * - * Returns: the scan type - */ -API_EXPORTED enum fp_scan_type fp_driver_get_scan_type(struct fp_driver *drv) -{ - g_return_val_if_fail(drv, FP_SCAN_TYPE_PRESS); - - return drv->scan_type; -} - -/** - * fp_driver_supports_imaging: - * @drv: the driver - * - * Determines if a driver has imaging capabilities. If a driver has imaging - * capabilities you are able to perform imaging operations such as retrieving - * scan images using fp_dev_img_capture(). However, not all drivers support - * imaging devices – some do all processing in hardware. This function will - * indicate which class a device in question falls into. - * - * Returns: 1 if the device is an imaging device, 0 if the device does not - * provide images to the host computer - */ -API_EXPORTED int fp_driver_supports_imaging(struct fp_driver *drv) -{ - g_return_val_if_fail(drv, 0); - - return drv->capture_start != NULL; -} - -/** - * fp_dev_supports_imaging: - * @dev: the struct #fp_dev device - * - * Determines if a device has imaging capabilities. If a device has imaging - * capabilities you are able to perform imaging operations such as retrieving - * scan images using fp_dev_img_capture(). However, not all devices are - * imaging devices – some do all processing in hardware. This function will - * indicate which class a device in question falls into. - * - * Returns: 1 if the device is an imaging device, 0 if the device does not - * provide images to the host computer - */ -API_EXPORTED int fp_dev_supports_imaging(struct fp_dev *dev) -{ - g_return_val_if_fail(dev, 0); - - return dev->drv->capture_start != NULL; -} - -/** - * fp_dev_supports_identification: - * @dev: the struct #fp_dev device - * - * Determines if a device is capable of [identification](intro.html#identification) - * through fp_identify_finger() and similar. Not all devices support this - * functionality. - * - * Returns: 1 if the device is capable of identification, 0 otherwise. - */ -API_EXPORTED int fp_dev_supports_identification(struct fp_dev *dev) -{ - g_return_val_if_fail(dev, 0); - - return dev->drv->identify_start != NULL; -} - -/** - * fp_dev_get_img_width: - * @dev: the struct #fp_dev device - * - * Gets the expected width of images that will be captured from the device. - * This function will return -1 for devices that are not - * [imaging devices](libfprint-Devices-operations.html#imaging). If the width of images from this device - * can vary, 0 will be returned. - * - * Returns: the expected image width, or 0 for variable, or -1 for non-imaging - * devices. - */ -API_EXPORTED int fp_dev_get_img_width(struct fp_dev *dev) -{ - g_return_val_if_fail(dev, -1); - - if (!dev->img_dev) { - fp_dbg("get image width for non-imaging device"); - return -1; - } - - return fpi_imgdev_get_img_width(dev->img_dev); -} - -/** - * fp_dev_get_img_height: - * @dev: the struct #fp_dev device - * - * Gets the expected height of images that will be captured from the device. - * This function will return -1 for devices that are not - * [imaging devices](libfprint-Devices-operations.html#imaging). If the height of images from this device - * can vary, 0 will be returned. - * - * Returns: the expected image height, or 0 for variable, or -1 for non-imaging - * devices. - */ -API_EXPORTED int fp_dev_get_img_height(struct fp_dev *dev) -{ - g_return_val_if_fail(dev, -1); - - if (!dev->img_dev) { - fp_dbg("get image height for non-imaging device"); - return -1; - } - - return fpi_imgdev_get_img_height(dev->img_dev); -} - -/** - * fp_set_debug: - * @level: the verbosity level - * - * This call does nothing, see fp_init() for details. - */ -API_EXPORTED void fp_set_debug(int level) -{ - /* Nothing */ -} - -/** - * fp_init: - * - * Initialise libfprint. This function must be called before you attempt to - * use the library in any way. - * - * To enable debug output of libfprint specifically, use GLib's `G_MESSAGES_DEBUG` - * environment variable as explained in [Running and debugging GLib Applications](https://developer.gnome.org/glib/stable/glib-running.html#G_MESSAGES_DEBUG). - * - * The log domains used in libfprint are either `libfprint` or `libfprint-FP_COMPONENT` - * where `FP_COMPONENT` is defined in the source code for each driver, or component - * of the library. Starting with `all` and trimming down is advised. - * - * To enable debugging of libusb, for USB-based fingerprint reader drivers, use - * libusb's `LIBUSB_DEBUG` environment variable as explained in the - * [libusb-1.0 API Reference](http://libusb.sourceforge.net/api-1.0/#msglog). - * - * Example: - * - * ``` - * LIBUSB_DEBUG=4 G_MESSAGES_DEBUG=all my-libfprint-application - * ``` - * - * Returns: 0 on success, non-zero on error. - */ -API_EXPORTED int fp_init(void) -{ - int r; - G_DEBUG_HERE(); - - r = libusb_init(&fpi_usb_ctx); - if (r < 0) - return r; - - register_drivers(); - fpi_poll_init(); - return 0; -} - -/** - * fp_exit: - * - * Deinitialise libfprint. This function should be called during your program - * exit sequence. You must not use any libfprint functions after calling this - * function, unless you call fp_init() again. - */ -API_EXPORTED void fp_exit(void) -{ - G_DEBUG_HERE(); - - if (opened_devices) { - GSList *copy = g_slist_copy(opened_devices); - GSList *elem = copy; - fp_dbg("naughty app left devices open on exit!"); - - do - fp_dev_close((struct fp_dev *) elem->data); - while ((elem = g_slist_next(elem))); - - g_slist_free(copy); - g_slist_free(opened_devices); - opened_devices = NULL; - } - - fpi_poll_exit(); - g_slist_free(registered_drivers); - registered_drivers = NULL; - libusb_exit(fpi_usb_ctx); -} - diff --git a/libfprint/fpi-core.h b/libfprint/fpi-core.h deleted file mode 100644 index d183f885..00000000 --- a/libfprint/fpi-core.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2007-2008 Daniel Drake - * Copyright (C) 2018 Bastien Nocera - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __FPI_CORE_H__ -#define __FPI_CORE_H__ - -#include -#include "fpi-dev-img.h" - -/** - * usb_id: - * @vendor: the USB vendor ID - * @product: the USB product ID - * @driver_data: data to differentiate devices of different - * vendor and product IDs. - * - * The struct #usb_id is used to declare devices supported by a - * particular driver. The @driver_data information is used to - * differentiate different models of devices which only need - * small changes compared to the default driver behaviour to function. - * - * For example, a device might have a different initialisation from - * the stock device, so the driver could do: - * - * |[ - * if (driver_data == MY_DIFFERENT_DEVICE_QUIRK) { - * ... - * } else { - * ... - * } - * ]| - * - * The default value is zero, so the @driver_data needs to be a - * non-zero to be useful. - */ -struct usb_id { - uint16_t vendor; - uint16_t product; - unsigned long driver_data; -}; - -/** - * fp_driver_type: - * @DRIVER_PRIMITIVE: primitive, non-imaging, driver - * @DRIVER_IMAGING: imaging driver - * - * The type of device the driver supports. - */ -enum fp_driver_type { - DRIVER_PRIMITIVE = 0, - DRIVER_IMAGING = 1, -}; - -struct fp_driver { - const uint16_t id; - const char *name; - const char *full_name; - const struct usb_id * const id_table; - enum fp_driver_type type; - enum fp_scan_type scan_type; - - /* Device operations */ - int (*discover)(struct libusb_device_descriptor *dsc, uint32_t *devtype); - int (*open)(struct fp_dev *dev, unsigned long driver_data); - void (*close)(struct fp_dev *dev); - int (*enroll_start)(struct fp_dev *dev); - int (*enroll_stop)(struct fp_dev *dev); - int (*verify_start)(struct fp_dev *dev); - int (*verify_stop)(struct fp_dev *dev, gboolean iterating); - int (*identify_start)(struct fp_dev *dev); - int (*identify_stop)(struct fp_dev *dev, gboolean iterating); - int (*capture_start)(struct fp_dev *dev); - int (*capture_stop)(struct fp_dev *dev); -}; - -/** - * FpiImgDriverFlags: - * @FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE: Whether the driver supports - * unconditional image capture. No driver currently does. - * - * Flags used in the #fp_img_driver to advertise the capabilities of drivers. - */ -typedef enum { - FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE = 1 << 0 -} FpiImgDriverFlags; - -struct fp_img_driver { - struct fp_driver driver; - FpiImgDriverFlags flags; - int img_width; - int img_height; - int bz3_threshold; - - /* Device operations */ - int (*open)(struct fp_img_dev *dev, unsigned long driver_data); - void (*close)(struct fp_img_dev *dev); - int (*activate)(struct fp_img_dev *dev); - int (*change_state)(struct fp_img_dev *dev, enum fp_imgdev_state state); - void (*deactivate)(struct fp_img_dev *dev); -}; - -#endif diff --git a/libfprint/fpi-data.c b/libfprint/fpi-data.c deleted file mode 100644 index 2a330643..00000000 --- a/libfprint/fpi-data.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Fingerprint data handling and storage - * Copyright (C) 2007 Daniel Drake - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "fp_internal.h" - -#define DIR_PERMS 0700 - -struct fpi_print_data_fp2 { - char prefix[3]; - uint16_t driver_id; - uint32_t devtype; - unsigned char data_type; - unsigned char data[0]; -} __attribute__((__packed__)); - -struct fpi_print_data_item_fp2 { - uint32_t length; - unsigned char data[0]; -} __attribute__((__packed__)); - -/** - * SECTION: print_data - * @title: Stored prints - * @short_description: Stored prints functions - * - * Stored prints are represented by a structure named #fp_print_data. - * Stored prints are originally obtained from an enrollment function such as - * fp_enroll_finger(). - * - * This page documents the various operations you can do with a stored print. - * Note that by default, "stored prints" are not actually stored anywhere - * except in RAM. Storage needs to be handled by the API user by using the - * fp_print_data_get_data() and fp_print_data_from_data(). This API allows - * to convert print data into byte strings, and to reconstruct stored prints - * from such data at a later point. You are welcome to store these byte strings - * in any fashion that suits you. - */ - -/* - * SECTION: fpi-data - * @title: Stored prints creation - * @short_description: Stored prints creation functions - * - * Stored print can be loaded and created by certain drivers which do their own - * print matching in hardware. Most drivers will not be using those functions. - * See #fp_print_data for the public API counterpart. - */ - -#define FP_FINGER_IS_VALID(finger) \ - ((finger) >= LEFT_THUMB && (finger) <= RIGHT_LITTLE) - -static struct fp_print_data *print_data_new(uint16_t driver_id, - uint32_t devtype, enum fp_print_data_type type) -{ - struct fp_print_data *data = g_malloc0(sizeof(*data)); - fp_dbg("driver=%02x devtype=%04x", driver_id, devtype); - data->driver_id = driver_id; - data->devtype = devtype; - data->type = type; - return data; -} - -static void fpi_print_data_item_free(struct fp_print_data_item *item) -{ - g_free(item); -} - -struct fp_print_data_item *fpi_print_data_item_new(size_t length) -{ - struct fp_print_data_item *item = g_malloc0(sizeof(*item) + length); - item->length = length; - - return item; -} - -struct fp_print_data *fpi_print_data_new(struct fp_dev *dev) -{ - return print_data_new(dev->drv->id, dev->devtype, - fpi_driver_get_data_type(dev->drv)); -} - -struct fp_print_data_item * -fpi_print_data_get_item(struct fp_print_data *data) -{ - return data->prints->data; -} - -void -fpi_print_data_add_item(struct fp_print_data *data, - struct fp_print_data_item *item) -{ - data->prints = g_slist_prepend(data->prints, item); -} - -/** - * fp_print_data_get_data: - * @data: the stored print - * @ret: output location for the data buffer. Must be freed with free() - * after use. - - * Convert a stored print into a unified representation inside a data buffer. - * You can then store this data buffer in any way that suits you, and load - * it back at some later time using fp_print_data_from_data(). - * - * Returns: the size of the freshly allocated buffer, or 0 on error. - */ -API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data, - unsigned char **ret) -{ - struct fpi_print_data_fp2 *out_data; - struct fpi_print_data_item_fp2 *out_item; - struct fp_print_data_item *item; - size_t buflen = 0; - GSList *list_item; - unsigned char *buf; - - G_DEBUG_HERE(); - - list_item = data->prints; - while (list_item) { - item = list_item->data; - buflen += sizeof(*out_item); - buflen += item->length; - list_item = g_slist_next(list_item); - } - - buflen += sizeof(*out_data); - out_data = g_malloc(buflen); - - *ret = (unsigned char *) out_data; - buf = out_data->data; - out_data->prefix[0] = 'F'; - out_data->prefix[1] = 'P'; - out_data->prefix[2] = '2'; - out_data->driver_id = GUINT16_TO_LE(data->driver_id); - out_data->devtype = GUINT32_TO_LE(data->devtype); - out_data->data_type = data->type; - - list_item = data->prints; - while (list_item) { - item = list_item->data; - out_item = (struct fpi_print_data_item_fp2 *)buf; - out_item->length = GUINT32_TO_LE(item->length); - /* FIXME: fp_print_data_item->data content is not endianness agnostic */ - memcpy(out_item->data, item->data, item->length); - buf += sizeof(*out_item); - buf += item->length; - list_item = g_slist_next(list_item); - } - - return buflen; -} - -static struct fp_print_data *fpi_print_data_from_fp1_data(unsigned char *buf, - size_t buflen) -{ - size_t print_data_len; - struct fp_print_data *data; - struct fp_print_data_item *item; - struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf; - - print_data_len = buflen - sizeof(*raw); - data = print_data_new(GUINT16_FROM_LE(raw->driver_id), - GUINT32_FROM_LE(raw->devtype), raw->data_type); - item = fpi_print_data_item_new(print_data_len); - /* FIXME: fp_print_data->data content is not endianness agnostic */ - memcpy(item->data, raw->data, print_data_len); - data->prints = g_slist_prepend(data->prints, item); - - return data; -} - -static struct fp_print_data *fpi_print_data_from_fp2_data(unsigned char *buf, - size_t buflen) -{ - size_t total_data_len, item_len; - struct fp_print_data *data; - struct fp_print_data_item *item; - struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf; - unsigned char *raw_buf; - struct fpi_print_data_item_fp2 *raw_item; - - total_data_len = buflen - sizeof(*raw); - data = print_data_new(GUINT16_FROM_LE(raw->driver_id), - GUINT32_FROM_LE(raw->devtype), raw->data_type); - raw_buf = raw->data; - while (total_data_len) { - if (total_data_len < sizeof(*raw_item)) - break; - total_data_len -= sizeof(*raw_item); - - raw_item = (struct fpi_print_data_item_fp2 *)raw_buf; - item_len = GUINT32_FROM_LE(raw_item->length); - fp_dbg("item len %d, total_data_len %d", (int) item_len, (int) total_data_len); - if (total_data_len < item_len) { - fp_err("corrupted fingerprint data"); - break; - } - total_data_len -= item_len; - - item = fpi_print_data_item_new(item_len); - /* FIXME: fp_print_data->data content is not endianness agnostic */ - memcpy(item->data, raw_item->data, item_len); - data->prints = g_slist_prepend(data->prints, item); - - raw_buf += sizeof(*raw_item); - raw_buf += item_len; - } - - if (g_slist_length(data->prints) == 0) { - fp_print_data_free(data); - data = NULL; - } - - return data; - -} - -/** - * fp_print_data_from_data: - * @buf: the data buffer - * @buflen: the length of the buffer - - * Load a stored print from a data buffer. The contents of said buffer must - * be the untouched contents of a buffer previously supplied to you by the - * fp_print_data_get_data() function. - * - * Returns: the stored print represented by the data, or %NULL on error. Must - * be freed with fp_print_data_free() after use. - */ -API_EXPORTED struct fp_print_data *fp_print_data_from_data(unsigned char *buf, - size_t buflen) -{ - struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf; - - fp_dbg("buffer size %zd", buflen); - if (buflen < sizeof(*raw)) - return NULL; - - if (strncmp(raw->prefix, "FP1", 3) == 0) { - return fpi_print_data_from_fp1_data(buf, buflen); - } else if (strncmp(raw->prefix, "FP2", 3) == 0) { - return fpi_print_data_from_fp2_data(buf, buflen); - } else { - fp_dbg("bad header prefix"); - } - - return NULL; -} - -gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1, - enum fp_print_data_type type1, uint16_t driver_id2, uint32_t devtype2, - enum fp_print_data_type type2) -{ - if (driver_id1 != driver_id2) { - fp_dbg("driver ID mismatch: %02x vs %02x", driver_id1, driver_id2); - return FALSE; - } - - if (devtype1 != devtype2) { - fp_dbg("devtype mismatch: %04x vs %04x", devtype1, devtype2); - return FALSE; - } - - if (type1 != type2) { - fp_dbg("type mismatch: %d vs %d", type1, type2); - return FALSE; - } - - return TRUE; -} - -/** - * fp_print_data_free: - * @data: the stored print to destroy. If NULL, function simply returns. - * - * Frees a stored print. Must be called when you are finished using the print. - */ -API_EXPORTED void fp_print_data_free(struct fp_print_data *data) -{ - if (data) - g_slist_free_full(data->prints, (GDestroyNotify)fpi_print_data_item_free); - g_free(data); -} - -/** - * fp_print_data_get_driver_id: - * @data: the stored print - - * Gets the [driver ID](advanced-topics.html#driver_id) for a stored print. The driver ID - * indicates which driver the print originally came from. The print is - * only usable with a device controlled by that driver. - * - * Returns: the driver ID of the driver compatible with the print - */ -API_EXPORTED uint16_t fp_print_data_get_driver_id(struct fp_print_data *data) -{ - return data->driver_id; -} - -/** - * fp_print_data_get_devtype: - * @data: the stored print - - * Gets the [devtype](advanced-topics.html#device-types) for a stored print. The devtype represents - * which type of device under the parent driver is compatible with the print. - * - * Returns: the devtype of the device range compatible with the print - */ -API_EXPORTED uint32_t fp_print_data_get_devtype(struct fp_print_data *data) -{ - return data->devtype; -} diff --git a/libfprint/fpi-dev-img.c b/libfprint/fpi-dev-img.c deleted file mode 100644 index b9d27831..00000000 --- a/libfprint/fpi-dev-img.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - * Core imaging device functions for libfprint - * Copyright (C) 2007-2008 Daniel Drake - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include - -#include - -#include "fpi-dev-img.h" -#include "fpi-async.h" -#include "fp_internal.h" - -/** - * SECTION:fpi-dev-img - * @title: Image device operations - * @short_description: Image device operation functions - * - * As drivers work through different operations, they need to report back - * to the core as to their internal state, so errors and successes can be - * reported back to front-ends. - */ - -#define MIN_ACCEPTABLE_MINUTIAE 10 -#define BOZORTH3_DEFAULT_THRESHOLD 40 -#define IMG_ENROLL_STAGES 5 - -/** - * fpi_imgdev_get_action_state: - * @imgdev: a #fp_img_dev imaging fingerprint device - * - * Returns the state of an imaging device while enrolling a fingerprint. - * - * Returns: a enum #fp_imgdev_enroll_state - */ -enum fp_imgdev_enroll_state -fpi_imgdev_get_action_state(struct fp_img_dev *imgdev) -{ - return imgdev->action_state; -} - -/** - * fpi_imgdev_get_action: - * @imgdev: a #fp_img_dev imaging fingerprint device - * - * Returns the current action being performed by an imaging device. - * - * Returns: a enum #fp_imgdev_action - */ -enum fp_imgdev_action -fpi_imgdev_get_action(struct fp_img_dev *imgdev) -{ - return imgdev->action; -} - -/** - * fpi_imgdev_get_action_result: - * @imgdev: a #fp_img_dev imaging fingerprint device - * - * Returns an integer representing the result of an action. Which enum - * the result code is taken from depends on the current action being performed. - * See #fp_capture_result, #fp_enroll_result and #fp_verify_result. - */ -int -fpi_imgdev_get_action_result(struct fp_img_dev *imgdev) -{ - return imgdev->action_result; -} - -/** - * fpi_imgdev_set_action_result: - * @imgdev: a #fp_img_dev imaging fingerprint device - * @action_result: an action result - * - * Drivers should use fpi_imgdev_image_captured() instead. This function - * should not be used, and will be removed soon. - */ -void -fpi_imgdev_set_action_result(struct fp_img_dev *imgdev, - int action_result) -{ - imgdev->action_result = action_result; -} - -static int img_dev_open(struct fp_dev *dev, unsigned long driver_data) -{ - struct fp_img_dev *imgdev = g_malloc0(sizeof(*imgdev)); - struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv); - int r = 0; - - /* Set up back pointers */ - dev->img_dev = imgdev; - imgdev->parent = dev; - - imgdev->enroll_stage = 0; - dev->nr_enroll_stages = IMG_ENROLL_STAGES; - - if (imgdrv->open) { - r = imgdrv->open(imgdev, driver_data); - if (r) - goto err; - } else { - fpi_drvcb_open_complete(dev, 0); - } - - return 0; -err: - g_free(imgdev); - return r; -} - -/** - * fpi_imgdev_open_complete: - * @imgdev: a #fp_img_dev imaging fingerprint device - * @status: an error code - * - * Function to call when the device has been opened, whether - * successfully of not. - */ -void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status) -{ - fpi_drvcb_open_complete(FP_DEV(imgdev), status); -} - -static void img_dev_close(struct fp_dev *dev) -{ - struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv); - - if (imgdrv->close) - imgdrv->close(dev->img_dev); - else - fpi_drvcb_close_complete(dev); -} - -/** - * fpi_imgdev_close_complete: - * @imgdev: a #fp_img_dev imaging fingerprint device - * - * Function to call when the device has been closed. - */ -void fpi_imgdev_close_complete(struct fp_img_dev *imgdev) -{ - fpi_drvcb_close_complete(FP_DEV(imgdev)); - g_free(imgdev); -} - -static int dev_change_state(struct fp_img_dev *imgdev, - enum fp_imgdev_state state) -{ - struct fp_driver *drv = FP_DEV(imgdev)->drv; - struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv); - - if (!imgdrv->change_state) - return 0; - return imgdrv->change_state(imgdev, state); -} - -/* check image properties and resize it if necessary. potentially returns a new - * image after freeing the old one. */ -static int sanitize_image(struct fp_img_dev *imgdev, struct fp_img **_img) -{ - struct fp_driver *drv = FP_DEV(imgdev)->drv; - struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv); - struct fp_img *img = *_img; - - if (imgdrv->img_width > 0) { - img->width = imgdrv->img_width; - } else if (img->width <= 0) { - fp_err("no image width assigned"); - return -EINVAL; - } - - if (imgdrv->img_height > 0) { - img->height = imgdrv->img_height; - } else if (img->height <= 0) { - fp_err("no image height assigned"); - return -EINVAL; - } - - if (!fpi_img_is_sane(img)) { - fp_err("image is not sane!"); - return -EINVAL; - } - - return 0; -} - -/** - * fpi_imgdev_report_finger_status: - * @imgdev: a #fp_img_dev imaging fingerprint device - * @present: whether the finger is present on the sensor - * - * Reports from the driver whether the user's finger is on - * the sensor. - */ -void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev, - gboolean present) -{ - int r = imgdev->action_result; - struct fp_print_data *data = imgdev->acquire_data; - struct fp_img *img = imgdev->acquire_img; - - fp_dbg(present ? "finger on sensor" : "finger removed"); - - if (present && imgdev->action_state == IMG_ACQUIRE_STATE_AWAIT_FINGER_ON) { - dev_change_state(imgdev, IMGDEV_STATE_CAPTURE); - imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_IMAGE; - return; - } else if (present - || imgdev->action_state != IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF) { - fp_dbg("ignoring status report"); - return; - } - - /* clear these before reporting results to avoid complications with - * call cascading in and out of the library */ - imgdev->acquire_img = NULL; - imgdev->acquire_data = NULL; - - /* finger removed, report results */ - switch (imgdev->action) { - case IMG_ACTION_ENROLL: - fp_dbg("reporting enroll result"); - data = imgdev->enroll_data; - if (r == FP_ENROLL_COMPLETE) { - imgdev->enroll_data = NULL; - } - fpi_drvcb_enroll_stage_completed(FP_DEV(imgdev), r, - r == FP_ENROLL_COMPLETE ? data : NULL, - img); - /* the callback can cancel enrollment, so recheck current - * action and the status to see if retry is needed */ - if (imgdev->action == IMG_ACTION_ENROLL && - r > 0 && r != FP_ENROLL_COMPLETE && r != FP_ENROLL_FAIL) { - imgdev->action_result = 0; - imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_ON; - dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_ON); - } - break; - case IMG_ACTION_VERIFY: - fpi_drvcb_report_verify_result(FP_DEV(imgdev), r, img); - imgdev->action_result = 0; - fp_print_data_free(data); - break; - case IMG_ACTION_IDENTIFY: - fpi_drvcb_report_identify_result(FP_DEV(imgdev), r, - imgdev->identify_match_offset, img); - imgdev->action_result = 0; - fp_print_data_free(data); - break; - case IMG_ACTION_CAPTURE: - fpi_drvcb_report_capture_result(FP_DEV(imgdev), r, img); - imgdev->action_result = 0; - break; - default: - fp_err("unhandled action %d", imgdev->action); - break; - } -} - -static void verify_process_img(struct fp_img_dev *imgdev) -{ - struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(FP_DEV(imgdev)->drv); - int match_score = imgdrv->bz3_threshold; - int r; - - if (match_score == 0) - match_score = BOZORTH3_DEFAULT_THRESHOLD; - - r = fpi_img_compare_print_data(FP_DEV(imgdev)->verify_data, - imgdev->acquire_data); - - if (r >= match_score) - r = FP_VERIFY_MATCH; - else if (r >= 0) - r = FP_VERIFY_NO_MATCH; - - imgdev->action_result = r; -} - -static void identify_process_img(struct fp_img_dev *imgdev) -{ - struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(FP_DEV(imgdev)->drv); - int match_score = imgdrv->bz3_threshold; - size_t match_offset; - int r; - - if (match_score == 0) - match_score = BOZORTH3_DEFAULT_THRESHOLD; - - r = fpi_img_compare_print_data_to_gallery(imgdev->acquire_data, - FP_DEV(imgdev)->identify_gallery, match_score, &match_offset); - - imgdev->action_result = r; - imgdev->identify_match_offset = match_offset; -} - -/** - * fpi_imgdev_abort_scan: - * @imgdev: a #fp_img_dev imaging fingerprint device - * @result: the scan result - * - * Aborts a scan after an error, and set the action result. See - * fpi_imgdev_get_action_result() for possible values. - */ -void fpi_imgdev_abort_scan(struct fp_img_dev *imgdev, int result) -{ - imgdev->action_result = result; - imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF; - dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_OFF); -} - -/** - * fpi_imgdev_image_captured: - * @imgdev: a #fp_img_dev imaging fingerprint device - * @img: an #fp_img image - * - * Report to the core that the driver captured this image from the sensor. - */ -void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img) -{ - struct fp_print_data *print = NULL; - int r; - G_DEBUG_HERE(); - - if (imgdev->action_state != IMG_ACQUIRE_STATE_AWAIT_IMAGE) { - fp_dbg("ignoring due to current state %d", imgdev->action_state); - return; - } - - if (imgdev->action_result) { - fp_dbg("not overwriting existing action result"); - return; - } - - r = sanitize_image(imgdev, &img); - if (r < 0) { - imgdev->action_result = r; - fp_img_free(img); - goto next_state; - } - - fp_img_standardize(img); - imgdev->acquire_img = img; - if (imgdev->action != IMG_ACTION_CAPTURE) { - r = fpi_img_to_print_data(imgdev, img, &print); - if (r < 0) { - fp_dbg("image to print data conversion error: %d", r); - imgdev->action_result = FP_ENROLL_RETRY; - goto next_state; - } else if (img->minutiae->num < MIN_ACCEPTABLE_MINUTIAE) { - fp_dbg("not enough minutiae, %d/%d", img->minutiae->num, - MIN_ACCEPTABLE_MINUTIAE); - fp_print_data_free(print); - /* depends on FP_ENROLL_RETRY == FP_VERIFY_RETRY */ - imgdev->action_result = FP_ENROLL_RETRY; - goto next_state; - } - } - - imgdev->acquire_data = print; - switch (imgdev->action) { - case IMG_ACTION_ENROLL: - if (!imgdev->enroll_data) { - imgdev->enroll_data = fpi_print_data_new(FP_DEV(imgdev)); - } - BUG_ON(g_slist_length(print->prints) != 1); - /* Move print data from acquire data into enroll_data */ - imgdev->enroll_data->prints = - g_slist_prepend(imgdev->enroll_data->prints, print->prints->data); - print->prints = g_slist_remove(print->prints, print->prints->data); - - fp_print_data_free(imgdev->acquire_data); - imgdev->acquire_data = NULL; - imgdev->enroll_stage++; - if (imgdev->enroll_stage == FP_DEV(imgdev)->nr_enroll_stages) - imgdev->action_result = FP_ENROLL_COMPLETE; - else - imgdev->action_result = FP_ENROLL_PASS; - break; - case IMG_ACTION_VERIFY: - verify_process_img(imgdev); - break; - case IMG_ACTION_IDENTIFY: - identify_process_img(imgdev); - break; - case IMG_ACTION_CAPTURE: - imgdev->action_result = FP_CAPTURE_COMPLETE; - break; - default: - BUG(); - break; - } - -next_state: - imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF; - dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_OFF); -} - -/** - * fpi_imgdev_session_error: - * @imgdev: a #fp_img_dev imaging fingerprint device - * @error: an error code - * - * Report an error that occurred in the driver. - */ -void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error) -{ - fp_dbg("error %d", error); - BUG_ON(error == 0); - switch (imgdev->action) { - case IMG_ACTION_ENROLL: - fpi_drvcb_enroll_stage_completed(FP_DEV(imgdev), error, NULL, NULL); - break; - case IMG_ACTION_VERIFY: - fpi_drvcb_report_verify_result(FP_DEV(imgdev), error, NULL); - break; - case IMG_ACTION_IDENTIFY: - fpi_drvcb_report_identify_result(FP_DEV(imgdev), error, 0, NULL); - break; - case IMG_ACTION_CAPTURE: - fpi_drvcb_report_capture_result(FP_DEV(imgdev), error, NULL); - break; - default: - fp_err("unhandled action %d", imgdev->action); - break; - } -} - -/** - * fpi_imgdev_activate_complete: - * @imgdev: a #fp_img_dev imaging fingerprint device - * @status: the activation result - * - * Marks an activation as complete, whether successful or not. - * See fpi_imgdev_get_action_result() for possible values. - */ -void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status) -{ - fp_dbg("status %d", status); - - switch (imgdev->action) { - case IMG_ACTION_ENROLL: - fpi_drvcb_enroll_started(FP_DEV(imgdev), status); - break; - case IMG_ACTION_VERIFY: - fpi_drvcb_verify_started(FP_DEV(imgdev), status); - break; - case IMG_ACTION_IDENTIFY: - fpi_drvcb_identify_started(FP_DEV(imgdev), status); - break; - case IMG_ACTION_CAPTURE: - fpi_drvcb_capture_started(FP_DEV(imgdev), status); - break; - default: - fp_err("unhandled action %d", imgdev->action); - return; - } - - if (status == 0) { - imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_ON; - dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_ON); - } -} - -/** - * fpi_imgdev_deactivate_complete: - * @imgdev: a #fp_img_dev imaging fingerprint device - * - * Marks a deactivation as complete. - */ -void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev) -{ - enum fp_imgdev_action action; - - G_DEBUG_HERE(); - - action = imgdev->action; - imgdev->action = IMG_ACTION_NONE; - imgdev->action_state = 0; - - switch (action) { - case IMG_ACTION_ENROLL: - fpi_drvcb_enroll_stopped(FP_DEV(imgdev)); - break; - case IMG_ACTION_VERIFY: - fpi_drvcb_verify_stopped(FP_DEV(imgdev)); - break; - case IMG_ACTION_IDENTIFY: - fpi_drvcb_identify_stopped(FP_DEV(imgdev)); - break; - case IMG_ACTION_CAPTURE: - fpi_drvcb_capture_stopped(FP_DEV(imgdev)); - break; - default: - fp_err("unhandled action %d", imgdev->action); - break; - } -} - -int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev) -{ - struct fp_driver *drv = FP_DEV(imgdev)->drv; - struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv); - int width = imgdrv->img_width; - - if (width == -1) - width = 0; - - return width; -} - -int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev) -{ - struct fp_driver *drv = FP_DEV(imgdev)->drv; - struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv); - int height = imgdrv->img_height; - - if (height == -1) - height = 0; - - return height; -} - -static int dev_activate(struct fp_img_dev *imgdev) -{ - struct fp_driver *drv = FP_DEV(imgdev)->drv; - struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv); - - if (!imgdrv->activate) - return 0; - return imgdrv->activate(imgdev); -} - -static void dev_deactivate(struct fp_img_dev *imgdev) -{ - struct fp_driver *drv = FP_DEV(imgdev)->drv; - struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv); - - if (!imgdrv->deactivate) - return; - return imgdrv->deactivate(imgdev); -} - -static int generic_acquire_start(struct fp_dev *dev, int action) -{ - struct fp_img_dev *imgdev = dev->img_dev; - int r; - fp_dbg("action %d", action); - imgdev->action = action; - imgdev->action_state = IMG_ACQUIRE_STATE_ACTIVATING; - imgdev->enroll_stage = 0; - - r = dev_activate(imgdev); - if (r < 0) - fp_err("activation failed with error %d", r); - - return r; - -} - -static void generic_acquire_stop(struct fp_img_dev *imgdev) -{ - imgdev->action_state = IMG_ACQUIRE_STATE_DEACTIVATING; - dev_deactivate(imgdev); - - fp_print_data_free(imgdev->acquire_data); - fp_print_data_free(imgdev->enroll_data); - fp_img_free(imgdev->acquire_img); - imgdev->acquire_data = NULL; - imgdev->enroll_data = NULL; - imgdev->acquire_img = NULL; - imgdev->action_result = 0; -} - -static int img_dev_enroll_start(struct fp_dev *dev) -{ - return generic_acquire_start(dev, IMG_ACTION_ENROLL); -} - -static int img_dev_verify_start(struct fp_dev *dev) -{ - return generic_acquire_start(dev, IMG_ACTION_VERIFY); -} - -static int img_dev_identify_start(struct fp_dev *dev) -{ - return generic_acquire_start(dev, IMG_ACTION_IDENTIFY); -} - -static int img_dev_capture_start(struct fp_dev *dev) -{ - /* Unconditional capture is not supported yet */ - if (dev->unconditional_capture) - return -ENOTSUP; - return generic_acquire_start(dev, IMG_ACTION_CAPTURE); -} - -static int img_dev_enroll_stop(struct fp_dev *dev) -{ - struct fp_img_dev *imgdev = dev->img_dev; - BUG_ON(imgdev->action != IMG_ACTION_ENROLL); - generic_acquire_stop(imgdev); - return 0; -} - -static int img_dev_verify_stop(struct fp_dev *dev, gboolean iterating) -{ - struct fp_img_dev *imgdev = dev->img_dev; - BUG_ON(imgdev->action != IMG_ACTION_VERIFY); - generic_acquire_stop(imgdev); - return 0; -} - -static int img_dev_identify_stop(struct fp_dev *dev, gboolean iterating) -{ - struct fp_img_dev *imgdev = dev->img_dev; - BUG_ON(imgdev->action != IMG_ACTION_IDENTIFY); - generic_acquire_stop(imgdev); - imgdev->identify_match_offset = 0; - return 0; -} - -static int img_dev_capture_stop(struct fp_dev *dev) -{ - struct fp_img_dev *imgdev = dev->img_dev; - BUG_ON(imgdev->action != IMG_ACTION_CAPTURE); - generic_acquire_stop(imgdev); - return 0; -} - -void fpi_img_driver_setup(struct fp_img_driver *idriver) -{ - idriver->driver.type = DRIVER_IMAGING; - idriver->driver.open = img_dev_open; - idriver->driver.close = img_dev_close; - idriver->driver.enroll_start = img_dev_enroll_start; - idriver->driver.enroll_stop = img_dev_enroll_stop; - idriver->driver.verify_start = img_dev_verify_start; - idriver->driver.verify_stop = img_dev_verify_stop; - idriver->driver.identify_start = img_dev_identify_start; - idriver->driver.identify_stop = img_dev_identify_stop; - idriver->driver.capture_start = img_dev_capture_start; - idriver->driver.capture_stop = img_dev_capture_stop; -} - diff --git a/libfprint/fpi-dev-img.h b/libfprint/fpi-dev-img.h deleted file mode 100644 index 0b0d48bc..00000000 --- a/libfprint/fpi-dev-img.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2007-2008 Daniel Drake - * Copyright (C) 2018 Bastien Nocera - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __FPI_DEV_IMG_H__ -#define __FPI_DEV_IMG_H__ - -#include "fpi-dev.h" -#include "fpi-img.h" - -/** - * fp_imgdev_action: - * @IMG_ACTION_NONE: no action - * @IMG_ACTION_ENROLL: device action is enrolling - * @IMG_ACTION_VERIFY: device action is verifying - * @IMG_ACTION_IDENTIFY: device action is identifying - * @IMG_ACTION_CAPTURE: device action is capturing - * - * The current action being performed by an imaging device. The current - * action can be gathered inside the driver using fpi_imgdev_get_action(). - */ -enum fp_imgdev_action { - IMG_ACTION_NONE = 0, - IMG_ACTION_ENROLL, - IMG_ACTION_VERIFY, - IMG_ACTION_IDENTIFY, - IMG_ACTION_CAPTURE, -}; - -/** - * fp_imgdev_state: - * @IMGDEV_STATE_INACTIVE: inactive - * @IMGDEV_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped - * @IMGDEV_STATE_CAPTURE: capturing an image - * @IMGDEV_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed - * - * The state of an imaging device while doing a capture. The state is - * passed through to the driver using the ::activate() or ::change_state() vfuncs. - */ -enum fp_imgdev_state { - IMGDEV_STATE_INACTIVE, - IMGDEV_STATE_AWAIT_FINGER_ON, - IMGDEV_STATE_CAPTURE, - IMGDEV_STATE_AWAIT_FINGER_OFF, -}; - -/** - * fp_imgdev_enroll_state: - * @IMG_ACQUIRE_STATE_NONE: doing nothing - * @IMG_ACQUIRE_STATE_ACTIVATING: activating the device - * @IMG_ACQUIRE_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped - * @IMG_ACQUIRE_STATE_AWAIT_IMAGE: waiting for the image to be captured - * @IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed - * @IMG_ACQUIRE_STATE_DONE: enrollment has all the images it needs - * @IMG_ACQUIRE_STATE_DEACTIVATING: deactivating the device - * - * The state of an imaging device while enrolling a fingerprint. Given that enrollment - * requires multiple captures, a number of those states will be repeated before - * the state is @IMG_ACQUIRE_STATE_DONE. - */ -enum fp_imgdev_enroll_state { - IMG_ACQUIRE_STATE_NONE = 0, - IMG_ACQUIRE_STATE_ACTIVATING, - IMG_ACQUIRE_STATE_AWAIT_FINGER_ON, - IMG_ACQUIRE_STATE_AWAIT_IMAGE, - IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF, - IMG_ACQUIRE_STATE_DONE, - IMG_ACQUIRE_STATE_DEACTIVATING, -}; - -void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status); -void fpi_imgdev_close_complete(struct fp_img_dev *imgdev); -void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status); -void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev); -void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev, - gboolean present); -void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img); -void fpi_imgdev_abort_scan(struct fp_img_dev *imgdev, int result); -void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error); - -enum fp_imgdev_enroll_state fpi_imgdev_get_action_state(struct fp_img_dev *imgdev); -enum fp_imgdev_action fpi_imgdev_get_action(struct fp_img_dev *imgdev); -int fpi_imgdev_get_action_result(struct fp_img_dev *imgdev); -void fpi_imgdev_set_action_result(struct fp_img_dev *imgdev, int action_result); - -#endif diff --git a/libfprint/fpi-dev.c b/libfprint/fpi-dev.c deleted file mode 100644 index 219a2a1a..00000000 --- a/libfprint/fpi-dev.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * fp_dev types manipulation - * Copyright (C) 2018 Bastien Nocera - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "fp_internal.h" -#include - -/** - * SECTION:fpi-dev - * @title: Device operations - * @short_description: Device operation functions - * - * Those macros and functions will help get access to and from struct #fp_dev, - * and struct #fp_img_dev types, as well as get and set the instance struct - * data, eg. the structure containing the data specific to each driver. - */ - -/** - * FP_DEV: - * @dev: a struct #fp_img_dev - * - * Returns the struct #fp_dev associated with @dev, or %NULL on failure. - * - * Returns: a struct #fp_dev or %NULL - */ -struct fp_dev * -FP_DEV(struct fp_img_dev *dev) -{ - struct fp_img_dev *imgdev; - - g_return_val_if_fail (dev, NULL); - imgdev = (struct fp_img_dev *) dev; - return imgdev->parent; -} - -/** - * FP_IMG_DEV: - * @dev: a struct #fp_dev representing an imaging device. - * - * Returns a struct #fp_img_dev associated with @dev, or %NULL on failure. - * - * Returns: a struct #fp_img_dev or %NULL - */ -struct fp_img_dev * -FP_IMG_DEV(struct fp_dev *dev) -{ - g_return_val_if_fail (dev, NULL); - g_return_val_if_fail (dev->drv, NULL); - g_return_val_if_fail (dev->drv->type == DRIVER_IMAGING, NULL); - return dev->img_dev; -} - -/** - * fp_dev_set_instance_data: - * @dev: a struct #fp_dev - * @instance_data: a pointer to the instance data - * - * Set the instance data for a struct #fp_dev. This is usually a structure - * private to the driver used to keep state and pass it as user_data to - * asynchronous functions. - * - * The core does not do any memory management for this data, so the driver - * itself will have to create and free its own structure when appropriate. - */ -void -fp_dev_set_instance_data (struct fp_dev *dev, - void *instance_data) -{ - g_return_if_fail (dev); - g_return_if_fail (instance_data != NULL); - g_return_if_fail (dev->instance_data == NULL); - - dev->instance_data = instance_data; -} - -/** - * FP_INSTANCE_DATA: - * @dev: a struct #fp_dev - * - * Returns the instance data set using fp_dev_set_instance_data(). - */ -void * -FP_INSTANCE_DATA (struct fp_dev *dev) -{ - g_return_val_if_fail (dev, NULL); - - return dev->instance_data; -} - -/** - * fpi_dev_get_usb_dev: - * @dev: a struct #fp_dev - * - * Returns the #libusb_device_handle associated with @dev or %NULL - * if none are associated. - * - * Returns: a #libusb_device_handle pointer or %NULL - */ -libusb_device_handle * -fpi_dev_get_usb_dev(struct fp_dev *dev) -{ - return dev->udev; -} - -/** - * fpi_dev_set_nr_enroll_stages: - * @dev: a struct #fp_dev - * @nr_enroll_stages: the number of enroll stages - * - * Sets the number of enroll stages that this device uses. This is - * usually only necessary for primitive devices which have a hard-coded - * number of enroll stages baked into their protocol. - */ -void -fpi_dev_set_nr_enroll_stages(struct fp_dev *dev, - int nr_enroll_stages) -{ - dev->nr_enroll_stages = nr_enroll_stages; -} - -/** - * fpi_dev_get_verify_data: - * @dev: a struct #fp_dev - * - * Returns the verify data associated with @dev. - * This is usually only necessary for primitive devices which need to - * have access to the raw verify data as it might have been stored on disk. - * - * Returns: a struct #fp_print_data pointer or %NULL - */ -struct fp_print_data * -fpi_dev_get_verify_data(struct fp_dev *dev) -{ - return dev->verify_data; -} diff --git a/libfprint/fpi-dev.h b/libfprint/fpi-dev.h deleted file mode 100644 index 98433912..00000000 --- a/libfprint/fpi-dev.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2018 Bastien Nocera - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __FPI_DEV_H__ -#define __FPI_DEV_H__ - -#include -#include - -struct fp_dev; - -/** - * fp_img_dev: - * - * #fp_img_dev is an opaque structure type. You must access it using the - * appropriate functions. - */ -struct fp_img_dev; - -struct fp_dev *FP_DEV (struct fp_img_dev *dev); -struct fp_img_dev *FP_IMG_DEV (struct fp_dev *dev); - -void fp_dev_set_instance_data (struct fp_dev *dev, - void *instance_data); -void *FP_INSTANCE_DATA (struct fp_dev *dev); - -libusb_device_handle *fpi_dev_get_usb_dev(struct fp_dev *dev); -void fpi_dev_set_nr_enroll_stages(struct fp_dev *dev, - int nr_enroll_stages); -struct fp_print_data *fpi_dev_get_verify_data(struct fp_dev *dev); - -#endif diff --git a/libfprint/fpi-device.h b/libfprint/fpi-device.h new file mode 100644 index 00000000..a206798e --- /dev/null +++ b/libfprint/fpi-device.h @@ -0,0 +1,252 @@ +/* + * FpDevice - A fingerprint reader device + * Copyright (C) 2019 Benjamin Berg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include +#include "fp-device.h" +#include "fp-image.h" +#include "fpi-print.h" + +/** + * FpIdEntry: + * + * An entry in the table of supported hardware. For USB devices, the product ID + * and vendor ID should be provided. The optional @driver_data field defaults + * to 0 and can be used as a simple flag for device quirks. + */ +typedef struct _FpIdEntry FpIdEntry; + +struct _FpIdEntry +{ + union + { + struct + { + guint pid; + guint vid; + }; + const gchar *virtual_envvar; + }; + guint64 driver_data; +}; + +/** + * FpDeviceClass: + * @id: ID string for the driver. Should be a valid C identifier and should + * match the drivers file name. + * @full_name: Human readable description of the driver + * @type: The type of driver + * @id_table: The table of IDs to bind the driver to + * @nr_enroll_stages: The number of enroll stages supported devices need; use + * fpi_device_set_nr_enroll_stages() from @probe if this is dynamic. + * @scan_type: The scan type of supported devices; use + * fpi_device_set_scan_type() from @probe if this is dynamic. + * @usb_discover: Class method to check whether a USB device is supported by + * the driver. Should return 0 if the device is unsupported and a positive + * score otherwise. The default score is 50 and the driver with the highest + * score will be loaded. + * @probe: Called immediately for all devices. Most drivers will not need to + * implement this. Drivers should setup the device identifier from the probe + * callback which will be used to verify the compatibility of stored + * #FpPrint's. It is permissable to temporarily open the USB device if this + * is required for the operation. If an error is returned, then the device + * will be destroyed again immediately and never reported to the API user. + * @open: Open the device for futher operations. Any of the normal actions are + * guaranteed to only happen when the device is open (this includes delete). + * @close: Close the device again + * @enroll: Start an enroll operation + * @verify: Start a verify operation + * @identify: Start an identify operation + * @capture: Start a capture operation + * @list: List prints stored on the device + * @delete: Delete a print from the device + * @cancel: Called on cancellation, this is a convenience to not need to handle + * the #GCancellable directly by using fpi_device_get_cancellable(). + * + * NOTE: If your driver is image based, then you should subclass #FpImageDevice + * instead. #FpImageDevice based drivers use a different way of interacting + * with libfprint. + * + * These are the main entry points for drivers to implement. Drivers may not + * implement all of these entry points if they do not support the operation + * (or a default implementation is sufficient). + * + * Drivers must eventually call the corresponding function to finish the + * operation. It is also acceptable to call the generic + * fpi_device_action_error() function but doing so is not recommended in most + * usecases. + * + * Drivers must also handle cancellation properly for any long running + * operation (i.e. any operation that requires capturing). It is entirely fine + * to ignore cancellation requests for short operations (e.g. open/close). + * + * This API is solely intended for drivers. It is purely internal and neither + * API nor ABI stable. + */ +struct _FpDeviceClass +{ + /*< private >*/ + GObjectClass parent_class; + + /*< public >*/ + /* Static information about the driver. */ + const gchar *id; + const gchar *full_name; + FpDeviceType type; + const FpIdEntry *id_table; + + /* Defaults for device properties */ + gint nr_enroll_stages; + FpScanType scan_type; + + /* Callbacks */ + gint (*usb_discover) (GUsbDevice *usb_device); + void (*probe) (FpDevice *device); + void (*open) (FpDevice *device); + void (*close) (FpDevice *device); + void (*enroll) (FpDevice *device); + void (*verify) (FpDevice *device); + void (*identify) (FpDevice *device); + void (*capture) (FpDevice *device); + void (*list) (FpDevice *device); + void (*delete) (FpDevice * device); + + void (*cancel) (FpDevice *device); +}; + +/** + * FpTimeoutFunc: + * @device: The #FpDevice passed to fpi_device_add_timeout() + * @user_data: the data passed to fpi_device_add_timeout() + * + * The prototype of the callback function for fpi_device_add_timeout(). + */ +typedef void (*FpTimeoutFunc) (FpDevice *device, + gpointer user_data); + +/** + * FpDeviceAction: + * @FP_DEVICE_ACTION_NONE: No action is active. + * @FP_DEVICE_ACTION_PROBE: Probe device for support and information. + * @FP_DEVICE_ACTION_OPEN: Device is currently being opened. + * @FP_DEVICE_ACTION_CLOSE: Device is currently being closed. + * @FP_DEVICE_ACTION_ENROLL: Device is currently enrolling. + * @FP_DEVICE_ACTION_VERIFY: Device is currently verifying. + * @FP_DEVICE_ACTION_IDENTIFY: Device is currently identifying. + * @FP_DEVICE_ACTION_CAPTURE: Device is currently capturing an image. + * @FP_DEVICE_ACTION_LIST: Device stored prints are being queried. + * @FP_DEVICE_ACTION_DELETE: Device stored print is being deleted. + * + * Current active action of the device. A driver can retrieve the action. + */ +typedef enum { + FP_DEVICE_ACTION_NONE = 0, + FP_DEVICE_ACTION_PROBE, + FP_DEVICE_ACTION_OPEN, + FP_DEVICE_ACTION_CLOSE, + FP_DEVICE_ACTION_ENROLL, + FP_DEVICE_ACTION_VERIFY, + FP_DEVICE_ACTION_IDENTIFY, + FP_DEVICE_ACTION_CAPTURE, + FP_DEVICE_ACTION_LIST, + FP_DEVICE_ACTION_DELETE, +} FpDeviceAction; + +GUsbDevice *fpi_device_get_usb_device (FpDevice *device); +const gchar *fpi_device_get_virtual_env (FpDevice *device); +//const gchar *fpi_device_get_spi_dev (FpDevice *device); + + +FpDeviceAction fpi_device_get_current_action (FpDevice *device); +gboolean fpi_device_action_is_cancelled (FpDevice *device); + +GError * fpi_device_retry_new (FpDeviceRetry error); +GError * fpi_device_error_new (FpDeviceError error); + +GError * fpi_device_retry_new_msg (FpDeviceRetry error, + const gchar *msg); +GError * fpi_device_error_new_msg (FpDeviceError error, + const gchar *msg); + +guint64 fpi_device_get_driver_data (FpDevice *device); + +void fpi_device_get_enroll_data (FpDevice *device, + FpPrint **print); + +void fpi_device_get_capture_data (FpDevice *device, + gboolean *wait_for_finger); +void fpi_device_get_verify_data (FpDevice *device, + FpPrint **print); +void fpi_device_get_identify_data (FpDevice *device, + GPtrArray **prints); +void fpi_device_get_delete_data (FpDevice *device, + FpPrint **print); +GCancellable *fpi_device_get_cancellable (FpDevice *device); + + + +GSource * fpi_device_add_timeout (FpDevice *device, + gint interval, + FpTimeoutFunc func, + gpointer user_data); + +void fpi_device_set_nr_enroll_stages (FpDevice *device, + gint enroll_stages); + +void fpi_device_set_scan_type (FpDevice *device, + FpScanType scan_type); + +void fpi_device_action_error (FpDevice *device, + GError *error); + +void fpi_device_probe_complete (FpDevice *device, + const gchar *device_id, + const gchar *device_name, + GError *error); +void fpi_device_open_complete (FpDevice *device, + GError *error); +void fpi_device_close_complete (FpDevice *device, + GError *error); +void fpi_device_enroll_complete (FpDevice *device, + FpPrint *print, + GError *error); +void fpi_device_verify_complete (FpDevice *device, + FpiMatchResult result, + FpPrint *print, + GError *error); +void fpi_device_identify_complete (FpDevice *device, + FpPrint *match, + FpPrint *print, + GError *error); +void fpi_device_capture_complete (FpDevice *device, + FpImage *image, + GError *error); +void fpi_device_delete_complete (FpDevice *device, + GError *error); +void fpi_device_list_complete (FpDevice *device, + GPtrArray *prints, + GError *error); + +void fpi_device_enroll_progress (FpDevice *device, + gint completed_stages, + FpPrint *print, + GError *error); + +G_END_DECLS diff --git a/libfprint/fpi-image-device.h b/libfprint/fpi-image-device.h new file mode 100644 index 00000000..06d1a647 --- /dev/null +++ b/libfprint/fpi-image-device.h @@ -0,0 +1,118 @@ +/* + * FpImageDevice - An image based fingerprint reader device + * Copyright (C) 2019 Benjamin Berg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "fpi-device.h" +#include "fp-image-device.h" + +/** + * FpImageDeviceState: + * @FP_IMAGE_DEVICE_STATE_INACTIVE: inactive + * @FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped + * @FP_IMAGE_DEVICE_STATE_CAPTURE: capturing an image + * @FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed + * + * The state of an imaging device while doing a capture. The state is + * passed through to the driver using the ::activate() or ::change_state() vfuncs. + * + * The driver needs to call fpi_image_device_report_finger_status() to move + * between the different states. Note that the capture state might be entered + * unconditionally if the device supports raw capturing. + */ +typedef enum { + FP_IMAGE_DEVICE_STATE_INACTIVE, + FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON, + FP_IMAGE_DEVICE_STATE_CAPTURE, + FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF, +} FpImageDeviceState; + +/** + * FpImageDeviceClass: + * @bz3_threshold: Threshold to consider bozorth3 score a match, default: 40 + * @img_width: Width of the image, only provide if constant + * @img_height: Height of the image, only provide if constant + * @img_open: Open the device and do basic initialization + * (use this instead of the #FpDeviceClass open vfunc) + * @img_close: Close the device + * (use this instead of the #FpDeviceClass close vfunc) + * @activate: Start image capture and finger detection + * @deactivate: Stop image capture and finger detection + * @change_state: Notification about the current device state (i.e. waiting for + * finger or image capture). Implementing this is optional, it can e.g. be + * used to flash an LED when waiting for a finger. + * + * These are the main entry points for image based drivers. For all but the + * change_state vfunc, implementations *must* eventually call the corresponding + * function to finish the operation. It is also acceptable to call the generic + * + * + * These are the main entry points for drivers to implement. Drivers may not + * implement all of these entry points if they do not support the operation + * (or a default implementation is sufficient). + * + * Drivers *must* eventually call the corresponding function to finish the + * operation. It is also acceptable to call the generic + * fpi_device_action_error() function but doing so is not recommended in most + * usecases. + * + * Drivers *must* also handle cancellation properly for any long running + * operation (i.e. any operation that requires capturing). It is entirely fine + * to ignore cancellation requests for short operations (e.g. open/close). + * + * This API is solely intended for drivers. It is purely internal and neither + * API nor ABI stable. + */ +struct _FpImageDeviceClass +{ + FpDeviceClass parent_class; + + gint bz3_threshold; + gint img_width; + gint img_height; + + void (*img_open) (FpImageDevice *dev); + void (*img_close) (FpImageDevice *dev); + void (*activate) (FpImageDevice *dev); + void (*change_state) (FpImageDevice *dev, + FpImageDeviceState state); + void (*deactivate) (FpImageDevice *dev); +}; + +void fpi_image_device_set_bz3_threshold (FpImageDevice *self, + gint bz3_threshold); + +void fpi_image_device_session_error (FpImageDevice *self, + GError *error); + +void fpi_image_device_open_complete (FpImageDevice *self, + GError *error); +void fpi_image_device_close_complete (FpImageDevice *self, + GError *error); +void fpi_image_device_activate_complete (FpImageDevice *self, + GError *error); +void fpi_image_device_deactivate_complete (FpImageDevice *self, + GError *error); + +void fpi_image_device_report_finger_status (FpImageDevice *self, + gboolean present); +void fpi_image_device_image_captured (FpImageDevice *self, + FpImage *image); +void fpi_image_device_retry_scan (FpImageDevice *self, + FpDeviceRetry retry); diff --git a/libfprint/fpi-image.h b/libfprint/fpi-image.h new file mode 100644 index 00000000..dd6dbf88 --- /dev/null +++ b/libfprint/fpi-image.h @@ -0,0 +1,83 @@ +/* + * FPrint Image + * Copyright (C) 2007 Daniel Drake + * Copyright (C) 2019 Benjamin Berg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include +#include "fp-image.h" + +/** + * FpiImageFlags: + * @FPI_IMAGE_V_FLIPPED: the image is vertically flipped + * @FPI_IMAGE_H_FLIPPED: the image is horizontally flipped + * @FPI_IMAGE_COLORS_INVERTED: the colours are inverted + * + * Flags used in an #FpImage structure to describe the contained image. + * This is useful for image drivers as they can simply set these flags and + * rely on the image to be normalized by libfprint before further processing. + */ +typedef enum { + FPI_IMAGE_V_FLIPPED = 1 << 0, + FPI_IMAGE_H_FLIPPED = 1 << 1, + FPI_IMAGE_COLORS_INVERTED = 1 << 2, +} FpiImageFlags; + +/** + * FpImage: + * @width: Width of the image + * @height: Height of the image + * @ppmm: Pixels per millimeter + * @flags: #FpiImageFlags for required normalization + * + * Structure holding an image. The public fields are only public for internal + * use by the drivers. + */ +struct _FpImage +{ + /*< private >*/ + GObject parent; + + /*< public >*/ + guint width; + guint height; + + gdouble ppmm; + + FpiImageFlags flags; + + /*< private >*/ + guint8 *data; + guint8 *binarized; + + GPtrArray *minutiae; + guint ref_count; +}; + +gint fpi_std_sq_dev (const guint8 *buf, + gint size); +gint fpi_mean_sq_diff_norm (const guint8 *buf1, + const guint8 *buf2, + gint size); + +#if HAVE_PIXMAN +FpImage *fpi_image_resize (FpImage *orig, + guint w_factor, + guint h_factor); +#endif diff --git a/libfprint/fpi-img-pixman.c b/libfprint/fpi-img-pixman.c deleted file mode 100644 index 1c1bedb9..00000000 --- a/libfprint/fpi-img-pixman.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Imaging utility functions for libfprint - * Copyright (C) 2007-2008 Daniel Drake - * Copyright (C) 2013 Vasily Khoruzhick - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include - -#include "fp_internal.h" - -/** - * fpi_img_resize: - * @img: an #fp_img image - * @w_factor: horizontal factor to resize the image by - * @h_factor: vertical factor to resize the image by - * - * Resizes the #fp_img image by scaling it by @w_factor times horizontally - * and @h_factor times vertically. - * - * Returns: a newly allocated #fp_img, the original @img will not be modified - * and will also need to be freed - */ -struct fp_img *fpi_img_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor) -{ - int new_width = img->width * w_factor; - int new_height = img->height * h_factor; - pixman_image_t *orig, *resized; - pixman_transform_t transform; - struct fp_img *newimg; - - orig = pixman_image_create_bits(PIXMAN_a8, img->width, img->height, (uint32_t *)img->data, img->width); - resized = pixman_image_create_bits(PIXMAN_a8, new_width, new_height, NULL, new_width); - - pixman_transform_init_identity(&transform); - pixman_transform_scale(NULL, &transform, pixman_int_to_fixed(w_factor), pixman_int_to_fixed(h_factor)); - pixman_image_set_transform(orig, &transform); - pixman_image_set_filter(orig, PIXMAN_FILTER_BILINEAR, NULL, 0); - pixman_image_composite32(PIXMAN_OP_SRC, - orig, /* src */ - NULL, /* mask */ - resized, /* dst */ - 0, 0, /* src x y */ - 0, 0, /* mask x y */ - 0, 0, /* dst x y */ - new_width, new_height /* width height */ - ); - - newimg = fpi_img_new(new_width * new_height); - newimg->width = new_width; - newimg->height = new_height; - newimg->flags = img->flags; - - memcpy(newimg->data, pixman_image_get_data(resized), new_width * new_height); - - pixman_image_unref(orig); - pixman_image_unref(resized); - - return newimg; -} - diff --git a/libfprint/fpi-img.c b/libfprint/fpi-img.c deleted file mode 100644 index c7f44c24..00000000 --- a/libfprint/fpi-img.c +++ /dev/null @@ -1,682 +0,0 @@ -/* - * Image management functions for libfprint - * Copyright (C) 2007 Daniel Drake - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include - -#include - -#include "fp_internal.h" -#include "nbis/include/bozorth.h" -#include "nbis/include/lfs.h" - -/** - * SECTION:img - * @title: Image operations - * @short_description: Image operation functions - * - * libfprint offers several ways of retrieving images from imaging devices, - * one example being the fp_dev_img_capture() function. The functions - * documented below allow you to work with such images. - * - * # Image format # {#img_fmt} - * All images are represented as 8-bit greyscale data. - * - * # Image standardization # {#img_std} - * In some contexts, images you are provided through libfprint are raw images - * from the hardware. The orientation of these varies from device-to-device, - * as does the color scheme (black-on-white or white-on-black?). libfprint - * provides the fp_img_standardize() function to convert images into standard - * form, which is defined to be: finger flesh as black on white surroundings, - * natural upright orientation. - */ - -/** - * SECTION:fpi-img - * @title: Driver Image operations - * @short_description: Driver image operation functions - * - * Those are the driver-specific helpers for #fp_img manipulation. See #fp_img's - * documentation for more information about data formats, and their uses in - * front-end applications. - */ - -/** - * fpi_img_new: - * @length: the length of data to allocate - * - * Creates a new #fp_img structure with @length bytes of data allocated - * to hold the image. - * - * Returns: a new #fp_img to free with fp_img_free() - */ -struct fp_img *fpi_img_new(size_t length) -{ - struct fp_img *img = g_malloc0(sizeof(*img) + length); - fp_dbg("length=%zd", length); - img->length = length; - return img; -} - -/** - * fpi_img_new_for_imgdev: - * @imgdev: a #fp_img_dev imaging fingerprint device - * - * Creates a new #fp_img structure, like fpi_img_new(), but uses the - * driver's advertised height and width to calculate the size of the - * length of data to allocate. - * - * Returns: a new #fp_img to free with fp_img_free() - */ -struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *imgdev) -{ - struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(FP_DEV(imgdev)->drv); - int width = imgdrv->img_width; - int height = imgdrv->img_height; - struct fp_img *img = fpi_img_new(width * height); - img->width = width; - img->height = height; - return img; -} - -/** - * fpi_img_is_sane: - * @img: a #fp_img image - * - * Checks whether an #fp_img structure passes some basic checks, such - * as length, width and height being non-zero, and the buffer being - * big enough to hold the image of said size. - * - * Returns: %TRUE if the image is sane, %FALSE otherwise - */ -gboolean fpi_img_is_sane(struct fp_img *img) -{ - guint len; - - /* basic checks */ - if (!img->length || img->width <= 0 || img->height <= 0) - return FALSE; - - /* Are width and height just too big? */ - if (!g_uint_checked_mul(&len, img->width, img->height) || - len > G_MAXINT) - return FALSE; - - /* buffer big enough? */ - if (len > img->length) - return FALSE; - - return TRUE; -} - -/** - * fpi_img_realloc: - * @img: an #fp_img image - * @newsize: the new length of the image - * - * Changes the size of the data part of the #fp_img. - * - * Returns: the modified #fp_img, the same as the first argument to this function - */ -struct fp_img *fpi_img_realloc(struct fp_img *img, size_t newsize) -{ - return g_realloc(img, sizeof(*img) + newsize); -} - -/** - * fp_img_free: - * @img: the image to destroy. If %NULL, function simply returns. - * - * Frees an image. Must be called when you are finished working with an image. - */ -API_EXPORTED void fp_img_free(struct fp_img *img) -{ - if (!img) - return; - - if (img->minutiae) - free_minutiae(img->minutiae); - if (img->binarized) - free(img->binarized); - g_free(img); -} - -/** - * fp_img_get_height: - * @img: an image - * - * Gets the pixel height of an image. - * - * Returns: the height of the image - */ -API_EXPORTED int fp_img_get_height(struct fp_img *img) -{ - return img->height; -} - -/** - * fp_img_get_width: - * @img: an image - * - * Gets the pixel width of an image. - * - * Returns: the width of the image - */ -API_EXPORTED int fp_img_get_width(struct fp_img *img) -{ - return img->width; -} - -/** - * fp_img_get_data: - * @img: an image - * - * Gets the greyscale data for an image. This data must not be modified or - * freed, and must not be used after fp_img_free() has been called. - * - * Returns: a pointer to libfprint's internal data for the image - */ -API_EXPORTED unsigned char *fp_img_get_data(struct fp_img *img) -{ - return img->data; -} - -/** - * fp_img_save_to_file: - * @img: the image to save - * @path: the path to save the image. Existing files will be overwritten. - * - * A quick convenience function to save an image to a file in - * [PGM format](http://netpbm.sourceforge.net/doc/pgm.html). - * - * Returns: 0 on success, non-zero on error. - */ -API_EXPORTED int fp_img_save_to_file(struct fp_img *img, char *path) -{ - FILE *fd = fopen(path, "w"); - size_t write_size = img->width * img->height; - int r; - - if (!fd) { - fp_dbg("could not open '%s' for writing: %d", path, errno); - return -errno; - } - - r = fprintf(fd, "P5 %d %d 255\n", img->width, img->height); - if (r < 0) { - fclose(fd); - fp_err("pgm header write failed, error %d", r); - return r; - } - - r = fwrite(img->data, 1, write_size, fd); - if (r < write_size) { - fclose(fd); - fp_err("short write (%d)", r); - return -EIO; - } - - fclose(fd); - fp_dbg("written to '%s'", path); - return 0; -} - -static void vflip(struct fp_img *img) -{ - int width = img->width; - int data_len = img->width * img->height; - unsigned char rowbuf[width]; - int i; - - for (i = 0; i < img->height / 2; i++) { - int offset = i * width; - int swap_offset = data_len - (width * (i + 1)); - - /* copy top row into buffer */ - memcpy(rowbuf, img->data + offset, width); - - /* copy lower row over upper row */ - memcpy(img->data + offset, img->data + swap_offset, width); - - /* copy buffer over lower row */ - memcpy(img->data + swap_offset, rowbuf, width); - } -} - -static void hflip(struct fp_img *img) -{ - int width = img->width; - unsigned char rowbuf[width]; - int i, j; - - for (i = 0; i < img->height; i++) { - int offset = i * width; - - memcpy(rowbuf, img->data + offset, width); - for (j = 0; j < width; j++) - img->data[offset + j] = rowbuf[width - j - 1]; - } -} - -static void invert_colors(struct fp_img *img) -{ - int data_len = img->width * img->height; - int i; - for (i = 0; i < data_len; i++) - img->data[i] = 0xff - img->data[i]; -} - -/** - * fp_img_standardize: - * @img: the image to standardize - * - * [Standardizes](libfprint-Image-operations.html#img_std) an image by normalizing its orientation, colors, - * etc. It is safe to call this multiple times on an image, libfprint keeps - * track of the work it needs to do to make an image standard and will not - * perform these operations more than once for a given image. - */ -API_EXPORTED void fp_img_standardize(struct fp_img *img) -{ - if (img->flags & FP_IMG_V_FLIPPED) { - vflip(img); - img->flags &= ~FP_IMG_V_FLIPPED; - } - if (img->flags & FP_IMG_H_FLIPPED) { - hflip(img); - img->flags &= ~FP_IMG_H_FLIPPED; - } - if (img->flags & FP_IMG_COLORS_INVERTED) { - invert_colors(img); - img->flags &= ~FP_IMG_COLORS_INVERTED; - } -} - -/* Based on write_minutiae_XYTQ and bz_load */ -static void minutiae_to_xyt(struct fp_minutiae *minutiae, int bwidth, - int bheight, unsigned char *buf) -{ - int i; - struct fp_minutia *minutia; - struct minutiae_struct c[MAX_FILE_MINUTIAE]; - struct xyt_struct *xyt = (struct xyt_struct *) buf; - - /* struct xyt_struct uses arrays of MAX_BOZORTH_MINUTIAE (200) */ - int nmin = min(minutiae->num, MAX_BOZORTH_MINUTIAE); - - for (i = 0; i < nmin; i++){ - minutia = minutiae->list[i]; - - lfs2nist_minutia_XYT(&c[i].col[0], &c[i].col[1], &c[i].col[2], - minutia, bwidth, bheight); - c[i].col[3] = sround(minutia->reliability * 100.0); - - if (c[i].col[2] > 180) - c[i].col[2] -= 360; - } - - qsort((void *) &c, (size_t) nmin, sizeof(struct minutiae_struct), - sort_x_y); - - for (i = 0; i < nmin; i++) { - xyt->xcol[i] = c[i].col[0]; - xyt->ycol[i] = c[i].col[1]; - xyt->thetacol[i] = c[i].col[2]; - } - xyt->nrows = nmin; -} - -#define FP_IMG_STANDARDIZATION_FLAGS (FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED \ - | FP_IMG_COLORS_INVERTED) - -static int fpi_img_detect_minutiae(struct fp_img *img) -{ - struct fp_minutiae *minutiae; - int r; - int *direction_map, *low_contrast_map, *low_flow_map; - int *high_curve_map, *quality_map; - int map_w, map_h; - unsigned char *bdata; - int bw, bh, bd; - GTimer *timer; - - if (img->flags & FP_IMG_STANDARDIZATION_FLAGS) { - fp_err("Cannot detect minutiae for non-standardized images"); - return -EINVAL; - } - - /* 25.4 mm per inch */ - timer = g_timer_new(); - r = get_minutiae(&minutiae, &quality_map, &direction_map, - &low_contrast_map, &low_flow_map, &high_curve_map, - &map_w, &map_h, &bdata, &bw, &bh, &bd, - img->data, img->width, img->height, 8, - DEFAULT_PPI / (double)25.4, &g_lfsparms_V2); - g_timer_stop(timer); - fp_dbg("minutiae scan completed in %f secs", g_timer_elapsed(timer, NULL)); - g_timer_destroy(timer); - if (r) { - fp_err("get minutiae failed, code %d", r); - return r; - } - fp_dbg("detected %d minutiae", minutiae->num); - img->minutiae = minutiae; - img->binarized = bdata; - - free(quality_map); - free(direction_map); - free(low_contrast_map); - free(low_flow_map); - free(high_curve_map); - return minutiae->num; -} - -int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img, - struct fp_print_data **ret) -{ - struct fp_print_data *print; - struct fp_print_data_item *item; - int r; - - if (!img->minutiae) { - r = fpi_img_detect_minutiae(img); - if (r < 0) - return r; - if (!img->minutiae) { - fp_err("no minutiae after successful detection?"); - return -ENOENT; - } - } - - /* FIXME: space is wasted if we don't hit the max minutiae count. would - * be good to make this dynamic. */ - print = fpi_print_data_new(FP_DEV(imgdev)); - item = fpi_print_data_item_new(sizeof(struct xyt_struct)); - print->type = PRINT_DATA_NBIS_MINUTIAE; - minutiae_to_xyt(img->minutiae, img->width, img->height, item->data); - print->prints = g_slist_prepend(print->prints, item); - - /* FIXME: the print buffer at this point is endian-specific, and will - * only work when loaded onto machines with identical endianness. not good! - * data format should be platform-independent. */ - *ret = print; - - return 0; -} - -int fpi_img_compare_print_data(struct fp_print_data *enrolled_print, - struct fp_print_data *new_print) -{ - int score, max_score = 0, probe_len; - struct xyt_struct *pstruct = NULL; - struct xyt_struct *gstruct = NULL; - struct fp_print_data_item *data_item; - GSList *list_item; - - if (enrolled_print->type != PRINT_DATA_NBIS_MINUTIAE || - new_print->type != PRINT_DATA_NBIS_MINUTIAE) { - fp_err("invalid print format"); - return -EINVAL; - } - - if (g_slist_length(new_print->prints) != 1) { - fp_err("new_print contains more than one sample, is it enrolled print?"); - return -EINVAL; - } - - data_item = new_print->prints->data; - pstruct = (struct xyt_struct *)data_item->data; - - probe_len = bozorth_probe_init(pstruct); - list_item = enrolled_print->prints; - do { - data_item = list_item->data; - gstruct = (struct xyt_struct *)data_item->data; - score = bozorth_to_gallery(probe_len, pstruct, gstruct); - fp_dbg("score %d", score); - max_score = max(score, max_score); - list_item = g_slist_next(list_item); - } while (list_item); - - return max_score; -} - -int fpi_img_compare_print_data_to_gallery(struct fp_print_data *print, - struct fp_print_data **gallery, int match_threshold, size_t *match_offset) -{ - struct xyt_struct *pstruct; - struct xyt_struct *gstruct; - struct fp_print_data *gallery_print; - struct fp_print_data_item *data_item; - int probe_len; - size_t i = 0; - int r; - GSList *list_item; - - if (g_slist_length(print->prints) != 1) { - fp_err("new_print contains more than one sample, is it enrolled print?"); - return -EINVAL; - } - - data_item = print->prints->data; - pstruct = (struct xyt_struct *)data_item->data; - - probe_len = bozorth_probe_init(pstruct); - while ((gallery_print = gallery[i++])) { - list_item = gallery_print->prints; - do { - data_item = list_item->data; - gstruct = (struct xyt_struct *)data_item->data; - r = bozorth_to_gallery(probe_len, pstruct, gstruct); - if (r >= match_threshold) { - *match_offset = i - 1; - return FP_VERIFY_MATCH; - } - list_item = g_slist_next(list_item); - } while (list_item); - } - return FP_VERIFY_NO_MATCH; -} - -/** - * fp_img_binarize: - * @img: a standardized image - * - * Get a binarized form of a standardized scanned image. This is where the - * fingerprint image has been "enhanced" and is a set of pure black ridges - * on a pure white background. Internally, image processing happens on top - * of the binarized image. - * - * The image must have been [standardized](libfprint-Image-operations.html#img_std) - * otherwise this function will fail. - * - * It is safe to binarize an image and free the original while continuing - * to use the binarized version. - * - * You cannot binarize an image twice. - * - * Returns: a new image representing the binarized form of the original, or - * %NULL on error. Must be freed with fp_img_free() after use. - */ -API_EXPORTED struct fp_img *fp_img_binarize(struct fp_img *img) -{ - struct fp_img *ret; - int height = img->height; - int width = img->width; - int imgsize = height * width; - - if (img->flags & FP_IMG_BINARIZED_FORM) { - fp_err("image already binarized"); - return NULL; - } - - if (!img->binarized) { - int r = fpi_img_detect_minutiae(img); - if (r < 0) - return NULL; - if (!img->binarized) { - fp_err("no minutiae after successful detection?"); - return NULL; - } - } - - ret = fpi_img_new(imgsize); - ret->flags |= FP_IMG_BINARIZED_FORM; - ret->width = width; - ret->height = height; - memcpy(ret->data, img->binarized, imgsize); - return ret; -} - -/** - * fp_img_get_minutiae: - * @img: a standardized image - * @nr_minutiae: an output location to store minutiae list length - * - * Get a list of minutiae detected in an image. A minutia point is a feature - * detected on a fingerprint, typically where ridges end or split. - * libfprint's image processing code relies upon comparing sets of minutiae, - * so accurate placement of minutia points is critical for good imaging - * performance. - * - * The image must have been [standardized](libfprint-Image-operations.html#img_std) - * otherwise this function will fail. - * - * You cannot pass a binarized image to this function. Instead, pass the - * original image. - * - * Returns a list of pointers to minutiae, where the list is of length - * indicated in the nr_minutiae output parameter. The returned list is only - * valid while the parent image has not been freed, and the minutiae data - * must not be modified or freed. - * - * Returns: a list of minutiae points. Must not be modified or freed. - */ -API_EXPORTED struct fp_minutia **fp_img_get_minutiae(struct fp_img *img, - int *nr_minutiae) -{ - if (img->flags & FP_IMG_BINARIZED_FORM) { - fp_err("image is binarized"); - return NULL; - } - - if (!img->minutiae) { - int r = fpi_img_detect_minutiae(img); - if (r < 0) - return NULL; - if (!img->minutiae) { - fp_err("no minutiae after successful detection?"); - return NULL; - } - } - - *nr_minutiae = img->minutiae->num; - return img->minutiae->list; -} - -/** - * fp_minutia_get_coords: - * @minutia: a struct #fp_minutia - * @coord_x: the return variable for the X coordinate of the minutia - * @coord_y: the return variable for the Y coordinate of the minutia - * - * Sets @coord_x and @coord_y to be the coordinates of the detected minutia, so it - * can be presented in a more verbose user interface. This is usually only - * used for debugging purposes. - * - * Returns: 0 on success, -1 on error. - */ -API_EXPORTED int fp_minutia_get_coords(struct fp_minutia *minutia, int *coord_x, int *coord_y) -{ - g_return_val_if_fail (minutia != NULL, -1); - g_return_val_if_fail (coord_x != NULL, -1); - g_return_val_if_fail (coord_y != NULL, -1); - - *coord_x = minutia->x; - *coord_y = minutia->y; - - return 0; -} - -/** - * fpi_std_sq_dev: - * @buf: buffer (usually bitmap, one byte per pixel) - * @size: size of @buffer - * - * Calculates the squared standard deviation of the individual - * pixels in the buffer, as per the following formula: - * |[ - * mean = sum (buf[0..size]) / size - * sq_dev = sum ((buf[0.size] - mean) ^ 2) - * ]| - * This function is usually used to determine whether image - * is empty. - * - * Returns: the squared standard deviation for @buffer - */ -int fpi_std_sq_dev(const unsigned char *buf, int size) -{ - int res = 0, mean = 0, i; - - if (size > (INT_MAX / 65536)) { - fp_err("%s: we might get an overflow!", __func__); - return -EOVERFLOW; - } - - for (i = 0; i < size; i++) - mean += buf[i]; - - mean /= size; - - for (i = 0; i < size; i++) { - int dev = (int)buf[i] - mean; - res += dev*dev; - } - - return res / size; -} - -/** - * fpi_mean_sq_diff_norm: - * @buf1: buffer (usually bitmap, one byte per pixel) - * @buf2: buffer (usually bitmap, one byte per pixel) - * @size: buffer size of smallest buffer - * - * This function calculates the normalized mean square difference of - * two buffers, usually two lines, as per the following formula: - * |[ - * sq_diff = sum ((buf1[0..size] - buf2[0..size]) ^ 2) / size - * ]| - * - * This functions is usually used to get numerical difference - * between two images. - * - * Returns: the normalized mean squared difference between @buf1 and @buf2 - */ -int fpi_mean_sq_diff_norm(unsigned char *buf1, unsigned char *buf2, int size) -{ - int res = 0, i; - for (i = 0; i < size; i++) { - int dev = (int)buf1[i] - (int)buf2[i]; - res += dev * dev; - } - - return res / size; -} diff --git a/libfprint/fpi-img.h b/libfprint/fpi-img.h deleted file mode 100644 index 4ebc3f39..00000000 --- a/libfprint/fpi-img.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2007-2008 Daniel Drake - * Copyright (C) 2018 Bastien Nocera - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __FPI_IMG_H__ -#define __FPI_IMG_H__ - -#include - -struct fp_minutiae; - -/** - * FpiImgFlags: - * @FP_IMG_V_FLIPPED: the image is vertically flipped - * @FP_IMG_H_FLIPPED: the image is horizontally flipped - * @FP_IMG_COLORS_INVERTED: the colours are inverted - * @FP_IMG_BINARIZED_FORM: binarised image, see fp_img_binarize() - * @FP_IMG_PARTIAL: the image is partial, useful for driver to keep track - * of incomplete captures - * - * Flags used in the #fp_img structure to describe the image contained - * into the structure. Note that a number of functions will refuse to - * handle images which haven't been standardised through fp_img_standardize() - * (meaning the @FP_IMG_V_FLIPPED, @FP_IMG_H_FLIPPED and @FP_IMG_COLORS_INVERTED - * should all be unset when the image needs to be analysed). - */ -typedef enum { - FP_IMG_V_FLIPPED = 1 << 0, - FP_IMG_H_FLIPPED = 1 << 1, - FP_IMG_COLORS_INVERTED = 1 << 2, - FP_IMG_BINARIZED_FORM = 1 << 3, - FP_IMG_PARTIAL = 1 << 4 -} FpiImgFlags; - -/** - * fp_img: - * @width: the width of the image - * @height: the height of the image - * @length: the length of the data associated with the image - * @flags: @FpiImgFlags flags describing the image contained in the structure - * @minutiae: an opaque structure representing the detected minutiae - * @binarized: the binarized image data - * @data: the start of the image data, which will be of @length size. - * - * A structure representing a captured, or processed image. The @flags member - * will show its current state, including whether whether the binarized form - * if present, whether it is complete, and whether it needs particular changes - * before being processed. - */ -struct fp_img { - int width; - int height; - size_t length; - FpiImgFlags flags; - /*< private >*/ - struct fp_minutiae *minutiae; - /*< public >*/ - unsigned char *binarized; - unsigned char data[0]; -}; - -struct fp_img *fpi_img_new(size_t length); -struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *imgdev); -struct fp_img *fpi_img_realloc(struct fp_img *img, size_t newsize); -struct fp_img *fpi_img_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor); - -int fpi_std_sq_dev(const unsigned char *buf, int size); -int fpi_mean_sq_diff_norm(unsigned char *buf1, unsigned char *buf2, int size); - -#endif diff --git a/libfprint/fpi-poll.c b/libfprint/fpi-poll.c deleted file mode 100644 index 3f2c898f..00000000 --- a/libfprint/fpi-poll.c +++ /dev/null @@ -1,485 +0,0 @@ -/* - * Polling/timing management - * Copyright (C) 2008 Daniel Drake - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#define FP_COMPONENT "poll" - -#include "fp_internal.h" -#include "fpi-poll.h" - -#include -#include -#include -#include - -#include -#include - -/** - * SECTION:events - * @title: Initialisation and events handling - * @short_description: Initialisation and events handling functions - * - * These functions are only applicable to users of libfprint's asynchronous - * API. - * - * libfprint does not create internal library threads and hence can only - * execute when your application is calling a libfprint function. However, - * libfprint often has work to be do, such as handling of completed USB - * transfers, and processing of timeouts required in order for the library - * to function. Therefore it is essential that your own application must - * regularly "phone into" libfprint so that libfprint can handle any pending - * events. - * - * The function you must call is fp_handle_events() or a variant of it. This - * function will handle any pending events, and it is from this context that - * all asynchronous event callbacks from the library will occur. You can view - * this function as a kind of iteration function. - * - * If there are no events pending, fp_handle_events() will block for a few - * seconds (and will handle any new events should anything occur in that time). - * If you wish to customise this timeout, you can use - * fp_handle_events_timeout() instead. If you wish to do a non-blocking - * iteration, call fp_handle_events_timeout() with a zero timeout. - * - * How to integrate events handling depends on your main loop implementation. - * The sister fprintd project includes an implementation of main loop handling - * that integrates into GLib's main loop. The - * [libusb documentation](http://libusb.sourceforge.net/api-1.0/group__poll.html#details) - * also includes more details about how to integrate libfprint events into - * your main loop. - */ - -/** - * SECTION:fpi-poll - * @title: Timeouts - * @short_description: Timeout handling helpers - * - * Helper functions to schedule a function call to be made after a timeout. This - * is useful to avoid making blocking calls while waiting for hardware to answer - * for example. - */ - -/* this is a singly-linked list of pending timers, sorted with the timer that - * is expiring soonest at the head. */ -static GSList *active_timers = NULL; - -/* notifiers for added or removed poll fds */ -static fp_pollfd_added_cb fd_added_cb = NULL; -static fp_pollfd_removed_cb fd_removed_cb = NULL; - -struct fpi_timeout { - struct timeval expiry; - fpi_timeout_fn callback; - struct fp_dev *dev; - void *data; - char *name; -}; - -static int timeout_sort_fn(gconstpointer _a, gconstpointer _b) -{ - fpi_timeout *a = (fpi_timeout *) _a; - fpi_timeout *b = (fpi_timeout *) _b; - struct timeval *tv_a = &a->expiry; - struct timeval *tv_b = &b->expiry; - - if (timercmp(tv_a, tv_b, <)) - return -1; - else if (timercmp(tv_a, tv_b, >)) - return 1; - else - return 0; -} - -static void -fpi_timeout_free(fpi_timeout *timeout) -{ - if (timeout == NULL) - return; - - g_free(timeout->name); - g_free(timeout); -} - -/** - * fpi_timeout_set_name: - * @timeout: a #fpi_timeout - * @name: the name to give the timeout - * - * Sets a name for a timeout, allowing that name to be printed - * along with any timeout related debug. - */ -void -fpi_timeout_set_name(fpi_timeout *timeout, - const char *name) -{ - g_return_if_fail (timeout != NULL); - g_return_if_fail (name != NULL); - g_return_if_fail (timeout->name == NULL); - - timeout->name = g_strdup(name); -} - -/** - * fpi_timeout_add: - * @msec: the time before calling the function, in milliseconds (1/1000ths of a second) - * @callback: function to callback - * @dev: a struct #fp_dev - * @data: data to pass to @callback, or %NULL - * - * A timeout is the asynchronous equivalent of sleeping. You create a timeout - * saying that you'd like to have a function invoked at a certain time in - * the future. - * - * Note that you should hold onto the return value of this function to cancel it - * use fpi_timeout_cancel(), otherwise the callback could be called while the driver - * is being torn down. - * - * This function can be considered to never fail. - * - * Returns: an #fpi_timeout structure - */ -fpi_timeout *fpi_timeout_add(unsigned int msec, - fpi_timeout_fn callback, - struct fp_dev *dev, - void *data) -{ - struct timespec ts; - struct timeval add_msec; - fpi_timeout *timeout; - int r; - - g_return_val_if_fail (dev != NULL, NULL); - - fp_dbg("in %dms", msec); - - r = clock_gettime(CLOCK_MONOTONIC, &ts); - if (r < 0) { - fp_err("failed to read monotonic clock, errno=%d", errno); - BUG(); - return NULL; - } - - timeout = g_new0(fpi_timeout, 1); - timeout->callback = callback; - timeout->dev = dev; - timeout->data = data; - TIMESPEC_TO_TIMEVAL(&timeout->expiry, &ts); - - /* calculate timeout expiry by adding delay to current monotonic clock */ - timerclear(&add_msec); - add_msec.tv_sec = msec / 1000; - add_msec.tv_usec = (msec % 1000) * 1000; - timeradd(&timeout->expiry, &add_msec, &timeout->expiry); - - active_timers = g_slist_insert_sorted(active_timers, timeout, - timeout_sort_fn); - - return timeout; -} - -/** - * fpi_timeout_cancel: - * @timeout: an #fpi_timeout structure - * - * Cancels a timeout scheduled with fpi_timeout_add(), and frees the - * @timeout structure. - */ -void fpi_timeout_cancel(fpi_timeout *timeout) -{ - G_DEBUG_HERE(); - active_timers = g_slist_remove(active_timers, timeout); - fpi_timeout_free(timeout); -} - -/* get the expiry time and optionally the timeout structure for the next - * timeout. returns 0 if there are no expired timers, or 1 if the - * timeval/timeout output parameters were populated. if the returned timeval - * is zero then it means the timeout has already expired and should be handled - * ASAP. */ -static int get_next_timeout_expiry(struct timeval *out, - struct fpi_timeout **out_timeout) -{ - struct timespec ts; - struct timeval tv; - struct fpi_timeout *next_timeout; - int r; - - if (active_timers == NULL) - return 0; - - r = clock_gettime(CLOCK_MONOTONIC, &ts); - if (r < 0) { - fp_err("failed to read monotonic clock, errno=%d", errno); - return r; - } - TIMESPEC_TO_TIMEVAL(&tv, &ts); - - next_timeout = active_timers->data; - if (out_timeout) - *out_timeout = next_timeout; - - if (timercmp(&tv, &next_timeout->expiry, >=)) { - if (next_timeout->name) - fp_dbg("first timeout '%s' already expired", next_timeout->name); - else - fp_dbg("first timeout already expired"); - timerclear(out); - } else { - timersub(&next_timeout->expiry, &tv, out); - if (next_timeout->name) - fp_dbg("next timeout '%s' in %ld.%06lds", next_timeout->name, - out->tv_sec, out->tv_usec); - else - fp_dbg("next timeout in %ld.%06lds", out->tv_sec, out->tv_usec); - } - - return 1; -} - -/* handle a timeout that has expired */ -static void handle_timeout(struct fpi_timeout *timeout) -{ - G_DEBUG_HERE(); - timeout->callback(timeout->dev, timeout->data); - active_timers = g_slist_remove(active_timers, timeout); - fpi_timeout_free(timeout); -} - -static int handle_timeouts(void) -{ - struct timeval next_timeout_expiry; - struct fpi_timeout *next_timeout; - int r; - - r = get_next_timeout_expiry(&next_timeout_expiry, &next_timeout); - if (r <= 0) - return r; - - if (!timerisset(&next_timeout_expiry)) - handle_timeout(next_timeout); - - return 0; -} - -/** - * fp_handle_events_timeout: - * @timeout: Maximum timeout for this blocking function - * - * Handle any pending events. If a non-zero timeout is specified, the function - * will potentially block for the specified amount of time, although it may - * return sooner if events have been handled. The function acts as non-blocking - * for a zero timeout. - * - * Returns: 0 on success, non-zero on error. - */ -API_EXPORTED int fp_handle_events_timeout(struct timeval *timeout) -{ - struct timeval next_timeout_expiry; - struct timeval select_timeout; - struct fpi_timeout *next_timeout; - int r; - - r = get_next_timeout_expiry(&next_timeout_expiry, &next_timeout); - if (r < 0) - return r; - - if (r) { - /* timer already expired? */ - if (!timerisset(&next_timeout_expiry)) { - handle_timeout(next_timeout); - return 0; - } - - /* choose the smallest of next URB timeout or user specified timeout */ - if (timercmp(&next_timeout_expiry, timeout, <)) - select_timeout = next_timeout_expiry; - else - select_timeout = *timeout; - } else { - select_timeout = *timeout; - } - - r = libusb_handle_events_timeout(fpi_usb_ctx, &select_timeout); - *timeout = select_timeout; - if (r < 0) - return r; - - return handle_timeouts(); -} - -/** - * fp_handle_events: - * - * Convenience function for calling fp_handle_events_timeout() with a sensible - * default timeout value of two seconds (subject to change if we decide another - * value is more sensible). - * - * Returns: 0 on success, non-zero on error. - */ -API_EXPORTED int fp_handle_events(void) -{ - struct timeval tv; - tv.tv_sec = 2; - tv.tv_usec = 0; - return fp_handle_events_timeout(&tv); -} - -/** - * fp_get_next_timeout: - * @tv: a #timeval structure containing the duration to the next timeout. - * - * A zero filled @tv timeout means events are to be handled immediately - * - * Returns: returns 0 if no timeouts active, or 1 if timeout returned. - */ -API_EXPORTED int fp_get_next_timeout(struct timeval *tv) -{ - struct timeval fprint_timeout = { 0, 0 }; - struct timeval libusb_timeout = { 0, 0 }; - int r_fprint; - int r_libusb; - - r_fprint = get_next_timeout_expiry(&fprint_timeout, NULL); - r_libusb = libusb_get_next_timeout(fpi_usb_ctx, &libusb_timeout); - - /* if we have no pending timeouts and the same is true for libusb, - * indicate that we have no pending timouts */ - if (r_fprint <= 0 && r_libusb <= 0) - return 0; - - /* if fprint have no pending timeouts return libusb timeout */ - else if (r_fprint == 0) - *tv = libusb_timeout; - - /* if libusb have no pending timeouts return fprint timeout */ - else if (r_libusb == 0) - *tv = fprint_timeout; - - /* otherwise return the smaller of the 2 timeouts */ - else if (timercmp(&fprint_timeout, &libusb_timeout, <)) - *tv = fprint_timeout; - else - *tv = libusb_timeout; - return 1; -} - -/** - * fp_get_pollfds: - * @pollfds: output location for a list of pollfds. If non-%NULL, must be - * released with free() when done. - * - * Retrieve a list of file descriptors that should be polled for events - * interesting to libfprint. This function is only for users who wish to - * combine libfprint's file descriptor set with other event sources – more - * simplistic users will be able to call fp_handle_events() or a variant - * directly. - * - * Returns: the number of pollfds in the resultant list, or negative on error. - */ -API_EXPORTED ssize_t fp_get_pollfds(struct fp_pollfd **pollfds) -{ - const struct libusb_pollfd **usbfds; - const struct libusb_pollfd *usbfd; - struct fp_pollfd *ret; - ssize_t cnt = 0; - size_t i = 0; - - g_return_val_if_fail (fpi_usb_ctx != NULL, -EIO); - - usbfds = libusb_get_pollfds(fpi_usb_ctx); - if (!usbfds) { - *pollfds = NULL; - return -EIO; - } - - while ((usbfd = usbfds[i++]) != NULL) - cnt++; - - ret = g_malloc(sizeof(struct fp_pollfd) * cnt); - i = 0; - while ((usbfd = usbfds[i]) != NULL) { - ret[i].fd = usbfd->fd; - ret[i].events = usbfd->events; - i++; - } - - *pollfds = ret; - return cnt; -} - -/** - * fp_set_pollfd_notifiers: - * @added_cb: a #fp_pollfd_added_cb callback or %NULL - * @removed_cb: a #fp_pollfd_removed_cb callback or %NULL - * - * This sets the callback functions to call for every new or removed - * file descriptor used as an event source. - */ -API_EXPORTED void fp_set_pollfd_notifiers(fp_pollfd_added_cb added_cb, - fp_pollfd_removed_cb removed_cb) -{ - fd_added_cb = added_cb; - fd_removed_cb = removed_cb; -} - -static void add_pollfd(int fd, short events, void *user_data) -{ - if (fd_added_cb) - fd_added_cb(fd, events); -} - -static void remove_pollfd(int fd, void *user_data) -{ - if (fd_removed_cb) - fd_removed_cb(fd); -} - -void fpi_poll_init(void) -{ - libusb_set_pollfd_notifiers(fpi_usb_ctx, add_pollfd, remove_pollfd, NULL); -} - -void fpi_poll_exit(void) -{ - g_slist_free_full(active_timers, (GDestroyNotify) fpi_timeout_free); - active_timers = NULL; - fd_added_cb = NULL; - fd_removed_cb = NULL; - libusb_set_pollfd_notifiers(fpi_usb_ctx, NULL, NULL, NULL); -} - -void -fpi_timeout_cancel_all_for_dev(struct fp_dev *dev) -{ - GSList *l; - - g_return_if_fail (dev != NULL); - - l = active_timers; - while (l) { - struct fpi_timeout *timeout = l->data; - GSList *current = l; - - l = l->next; - if (timeout->dev == dev) { - g_free (timeout); - active_timers = g_slist_delete_link (active_timers, current); - } - } -} diff --git a/libfprint/fpi-poll.h b/libfprint/fpi-poll.h deleted file mode 100644 index 2682f277..00000000 --- a/libfprint/fpi-poll.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2008 Daniel Drake - * Copyright (C) 2018 Bastien Nocera - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __FPI_POLL_H__ -#define __FPI_POLL_H__ - -#include "fprint.h" - -/** - * fpi_timeout_fn: - * @dev: the struct #fp_dev passed to fpi_timeout_add() - * @data: the data passed to fpi_timeout_add() - * - * The prototype of the callback function for fpi_timeout_add(). - * Note that after the callback is called, the #fpi_timeout structure will - * be freed. - */ -typedef void (*fpi_timeout_fn)(struct fp_dev *dev, void *data); - -/** - * fpi_timeout: - * - * An opaque structure representing a scheduled function call, created with - * fpi_timeout_add(). - */ -typedef struct fpi_timeout fpi_timeout; -fpi_timeout *fpi_timeout_add(unsigned int msec, - fpi_timeout_fn callback, - struct fp_dev *dev, - void *data); -void fpi_timeout_set_name(fpi_timeout *timeout, - const char *name); -void fpi_timeout_cancel(fpi_timeout *timeout); - -#endif diff --git a/libfprint/fpi-print.h b/libfprint/fpi-print.h new file mode 100644 index 00000000..fe07c260 --- /dev/null +++ b/libfprint/fpi-print.h @@ -0,0 +1,50 @@ +#pragma once + +#include "fpi-enums.h" +#include "fp-device.h" +#include "fp-print.h" + +G_BEGIN_DECLS + +/** + * FpPrintType: + * @FP_PRINT_UNDEFINED: Undefined type, this happens prior to enrollment + * @FP_PRINT_RAW: A raw print where the data is directly compared + * @FP_PRINT_NBIS: NBIS minutiae comparison + */ +typedef enum { + FP_PRINT_UNDEFINED = 0, + FP_PRINT_RAW, + FP_PRINT_NBIS, +} FpPrintType; + +/** + * FpiMatchResult: + * @FPI_MATCH_ERROR: An error occured during matching + * @FPI_MATCH_SUCCESS: The prints matched + * @FPI_MATCH_FAIL: The prints did not match + */ +typedef enum { + FPI_MATCH_ERROR = 0, + FPI_MATCH_SUCCESS, + FPI_MATCH_FAIL, +} FpiMatchResult; + +void fpi_print_add_print (FpPrint *print, + FpPrint *add); + +void fpi_print_set_type (FpPrint *print, + FpPrintType type); +void fpi_print_set_device_stored (FpPrint *print, + gboolean device_stored); + +gboolean fpi_print_add_from_image (FpPrint *print, + FpImage *image, + GError **error); + +FpiMatchResult fpi_print_bz3_match (FpPrint * template, + FpPrint *print, + gint bz3_threshold, + GError **error); + +G_END_DECLS diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c index 64430c16..2fb25650 100644 --- a/libfprint/fpi-ssm.c +++ b/libfprint/fpi-ssm.c @@ -1,6 +1,7 @@ /* * Functions to assist with asynchronous driver <---> library communications * Copyright (C) 2007-2008 Daniel Drake + * Copyright (C) 2019 Benjamin Berg * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,13 +18,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#define FP_COMPONENT "drv" +#define FP_COMPONENT "SSM" -#include "fp_internal.h" +#include "drivers_api.h" #include "fpi-ssm.h" -#include -#include /** * SECTION:fpi-ssm @@ -32,7 +31,7 @@ * * Asynchronous driver design encourages some kind of state machine behind it. * In most cases, the state machine is entirely linear - you only go to the - * next state, you never jump or go backwards. The #fpi_ssm functions help you + * next state, you never jump or go backwards. The #FpiSsm functions help you * implement such a machine. * * e.g. `S1` ↦ `S2` ↦ `S3` ↦ `S4` @@ -72,20 +71,21 @@ * upon success (or fails). * * Your completion callback should examine the return value of - * fpi_ssm_get_error() in order to determine whether the #fpi_ssm completed or + * fpi_ssm_get_error() in ordater to determine whether the #FpiSsm completed or * failed. An error code of zero indicates successful completion. */ -struct fpi_ssm { - struct fp_dev *dev; - fpi_ssm *parentsm; - void *user_data; - int nr_states; - int cur_state; - gboolean completed; - int error; - ssm_completed_fn callback; - ssm_handler_fn handler; +struct _FpiSsm +{ + FpDevice *dev; + FpiSsm *parentsm; + void *user_data; + int nr_states; + int cur_state; + gboolean completed; + GError *error; + FpiSsmCompletedCallback callback; + FpiSsmHandlerCallback handler; }; /** @@ -98,28 +98,30 @@ struct fpi_ssm { * Allocate a new ssm, with @nr_states states. The @handler callback * will be called after each state transition. * - * Returns: a new #fpi_ssm state machine + * Returns: a new #FpiSsm state machine */ -fpi_ssm *fpi_ssm_new(struct fp_dev *dev, - ssm_handler_fn handler, - int nr_states, - void *user_data) +FpiSsm * +fpi_ssm_new (FpDevice *dev, + FpiSsmHandlerCallback handler, + int nr_states, + void *user_data) { - fpi_ssm *machine; - BUG_ON(nr_states < 1); + FpiSsm *machine; - machine = g_malloc0(sizeof(*machine)); - machine->handler = handler; - machine->nr_states = nr_states; - machine->dev = dev; - machine->completed = TRUE; - machine->user_data = user_data; - return machine; + BUG_ON (nr_states < 1); + + machine = g_malloc0 (sizeof (*machine)); + machine->handler = handler; + machine->nr_states = nr_states; + machine->dev = dev; + machine->completed = TRUE; + machine->user_data = user_data; + return machine; } /** * fpi_ssm_get_user_data: - * @machine: an #fpi_ssm state machine + * @machine: an #FpiSsm state machine * * Retrieve the pointer to user data set when fpi_ssm_new() * is called. @@ -127,66 +129,73 @@ fpi_ssm *fpi_ssm_new(struct fp_dev *dev, * Returns: a pointer */ void * -fpi_ssm_get_user_data(fpi_ssm *machine) +fpi_ssm_get_user_data (FpiSsm *machine) { - return machine->user_data; + return machine->user_data; } /** * fpi_ssm_free: - * @machine: an #fpi_ssm state machine + * @machine: an #FpiSsm state machine * * Frees a state machine. This does not call any error or success * callbacks, so you need to do this yourself. */ -void fpi_ssm_free(fpi_ssm *machine) +void +fpi_ssm_free (FpiSsm *machine) { - if (!machine) - return; - g_free(machine); + if (!machine) + return; + + g_clear_pointer (&machine->error, g_error_free); + g_free (machine); } /* Invoke the state handler */ -static void __ssm_call_handler(fpi_ssm *machine) +static void +__ssm_call_handler (FpiSsm *machine) { - fp_dbg("%p entering state %d", machine, machine->cur_state); - machine->handler(machine, machine->dev, machine->user_data); + fp_dbg ("%p entering state %d", machine, machine->cur_state); + machine->handler (machine, machine->dev, machine->user_data); } /** * fpi_ssm_start: - * @ssm: an #fpi_ssm state machine - * @callback: the #ssm_completed_fn callback to call on completion + * @ssm: an #FpiSsm state machine + * @callback: the #FpiSsmCompletedCallback callback to call on completion * * Starts a state machine. You can also use this function to restart * a completed or failed state machine. The @callback will be called * on completion. */ -void fpi_ssm_start(fpi_ssm *ssm, ssm_completed_fn callback) +void +fpi_ssm_start (FpiSsm *ssm, FpiSsmCompletedCallback callback) { - BUG_ON(!ssm->completed); - ssm->callback = callback; - ssm->cur_state = 0; - ssm->completed = FALSE; - ssm->error = 0; - __ssm_call_handler(ssm); + BUG_ON (!ssm->completed); + ssm->callback = callback; + ssm->cur_state = 0; + ssm->completed = FALSE; + ssm->error = NULL; + __ssm_call_handler (ssm); } -static void __subsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void +__subsm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, GError *error) { - fpi_ssm *parent = ssm->parentsm; - BUG_ON(!parent); - if (ssm->error) - fpi_ssm_mark_failed(parent, ssm->error); - else - fpi_ssm_next_state(parent); - fpi_ssm_free(ssm); + FpiSsm *parent = ssm->parentsm; + + BUG_ON (!parent); + if (error) + fpi_ssm_mark_failed (parent, error); + else + fpi_ssm_next_state (parent); + fpi_ssm_free (ssm); } /** * fpi_ssm_start_subsm: - * @parent: an #fpi_ssm state machine - * @child: an #fpi_ssm state machine + * @parent: an #FpiSsm state machine + * @child: an #FpiSsm state machine * * Starts a state machine as a child of another. if the child completes * successfully, the parent will be advanced to the next state. if the @@ -194,124 +203,185 @@ static void __subsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) * * The child will be automatically freed upon completion or failure. */ -void fpi_ssm_start_subsm(fpi_ssm *parent, fpi_ssm *child) +void +fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child) { - child->parentsm = parent; - fpi_ssm_start(child, __subsm_complete); + child->parentsm = parent; + fpi_ssm_start (child, __subsm_complete); } /** * fpi_ssm_mark_completed: - * @machine: an #fpi_ssm state machine + * @machine: an #FpiSsm state machine * * Mark a ssm as completed successfully. The callback set when creating * the state machine with fpi_ssm_new() will be called synchronously. */ -void fpi_ssm_mark_completed(fpi_ssm *machine) +void +fpi_ssm_mark_completed (FpiSsm *machine) { - BUG_ON(machine->completed); - machine->completed = TRUE; - fp_dbg("%p completed with status %d", machine, machine->error); - if (machine->callback) - machine->callback(machine, machine->dev, machine->user_data); + BUG_ON (machine->completed); + machine->completed = TRUE; + if (machine->error) + fp_dbg ("%p completed with error: %s", machine, machine->error->message); + else + fp_dbg ("%p completed successfully", machine); + if (machine->callback) + { + GError *error = machine->error ? g_error_copy (machine->error) : NULL; + + machine->callback (machine, machine->dev, machine->user_data, error); + } } /** * fpi_ssm_mark_failed: - * @machine: an #fpi_ssm state machine - * @error: the error code + * @machine: an #FpiSsm state machine + * @error: a #GError * * Mark a state machine as failed with @error as the error code. */ -void fpi_ssm_mark_failed(fpi_ssm *machine, int error) +void +fpi_ssm_mark_failed (FpiSsm *machine, GError *error) { - fp_dbg("error %d from state %d", error, machine->cur_state); - BUG_ON(error == 0); - machine->error = error; - fpi_ssm_mark_completed(machine); + g_assert (error); + if (machine->error) + { + fp_warn ("SSM already has an error set, ignoring new error %s", error->message); + g_error_free (error); + return; + } + + fp_dbg ("SSM failed in state %d with error: %s", machine->cur_state, error->message); + machine->error = error; + fpi_ssm_mark_completed (machine); } /** * fpi_ssm_next_state: - * @machine: an #fpi_ssm state machine + * @machine: an #FpiSsm state machine * * Iterate to next state of a state machine. If the current state is the * last state, then the state machine will be marked as completed, as * if calling fpi_ssm_mark_completed(). */ -void fpi_ssm_next_state(fpi_ssm *machine) -{ - g_return_if_fail (machine != NULL); - - BUG_ON(machine->completed); - machine->cur_state++; - if (machine->cur_state == machine->nr_states) { - fpi_ssm_mark_completed(machine); - } else { - __ssm_call_handler(machine); - } -} - -/** - * fpi_ssm_next_state_timeout_cb: - * @dev: a struct #fp_dev - * @data: a pointer to an #fpi_ssm state machine - * - * Same as fpi_ssm_next_state(), but to be used as a callback - * for an fpi_timeout_add() callback, when the state change needs - * to happen after a timeout. - * - * Make sure to pass the #fpi_ssm as the `user_data` argument - * for that fpi_timeout_add() call. - */ void -fpi_ssm_next_state_timeout_cb(struct fp_dev *dev, - void *data) +fpi_ssm_next_state (FpiSsm *machine) { - g_return_if_fail (dev != NULL); - g_return_if_fail (data != NULL); + g_return_if_fail (machine != NULL); - fpi_ssm_next_state(data); + BUG_ON (machine->completed); + machine->cur_state++; + if (machine->cur_state == machine->nr_states) + fpi_ssm_mark_completed (machine); + else + __ssm_call_handler (machine); } /** * fpi_ssm_jump_to_state: - * @machine: an #fpi_ssm state machine + * @machine: an #FpiSsm state machine * @state: the state to jump to * * Jump to the @state state, bypassing intermediary states. */ -void fpi_ssm_jump_to_state(fpi_ssm *machine, int state) +void +fpi_ssm_jump_to_state (FpiSsm *machine, int state) { - BUG_ON(machine->completed); - BUG_ON(state >= machine->nr_states); - machine->cur_state = state; - __ssm_call_handler(machine); + BUG_ON (machine->completed); + BUG_ON (state >= machine->nr_states); + machine->cur_state = state; + __ssm_call_handler (machine); } /** * fpi_ssm_get_cur_state: - * @machine: an #fpi_ssm state machine + * @machine: an #FpiSsm state machine * * Returns the value of the current state. Note that states are * 0-indexed, so a value of 0 means “the first state”. * * Returns: the current state. */ -int fpi_ssm_get_cur_state(fpi_ssm *machine) +int +fpi_ssm_get_cur_state (FpiSsm *machine) { - return machine->cur_state; + return machine->cur_state; } /** * fpi_ssm_get_error: - * @machine: an #fpi_ssm state machine + * @machine: an #FpiSsm state machine * * Returns the error code set by fpi_ssm_mark_failed(). * - * Returns: a error code + * Returns: (transfer none): a error code */ -int fpi_ssm_get_error(fpi_ssm *machine) +GError * +fpi_ssm_get_error (FpiSsm *machine) { - return machine->error; + return machine->error; +} + +/** + * fpi_ssm_dup_error: + * @machine: an #FpiSsm state machine + * + * Returns the error code set by fpi_ssm_mark_failed(). + * + * Returns: (transfer full): a error code + */ +GError * +fpi_ssm_dup_error (FpiSsm *machine) +{ + if (machine->error) + return g_error_copy (machine->error); + + return NULL; +} + +/** + * fpi_ssm_next_state_timeout_cb: + * @dev: a struct #fp_dev + * @data: a pointer to an #FpiSsm state machine + * + * Same as fpi_ssm_next_state(), but to be used as a callback + * for an fpi_timeout_add() callback, when the state change needs + * to happen after a timeout. + * + * Make sure to pass the #FpiSsm as the `user_data` argument + * for that fpi_timeout_add() call. + */ +void +fpi_ssm_next_state_timeout_cb (FpDevice *dev, + void *data) +{ + g_return_if_fail (dev != NULL); + g_return_if_fail (data != NULL); + + fpi_ssm_next_state (data); +} + +/** + * fpi_ssm_usb_transfer_cb: + * @transfer: a #FpiUsbTransfer + * @device: a #FpDevice + * @user_data: User data (unused) + * @error: The #GError or %NULL + * + * Can be used in as a #FpiUsbTransfer callback handler to automatically + * advance or fail a statemachine on transfer completion. + * + * Make sure to set the #FpiSsm on the transfer. + */ +void +fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) +{ + g_return_if_fail (transfer->ssm); + + if (error) + fpi_ssm_mark_failed (transfer->ssm, error); + else + fpi_ssm_next_state (transfer->ssm); } diff --git a/libfprint/fpi-ssm.h b/libfprint/fpi-ssm.h index a619d42c..560452cb 100644 --- a/libfprint/fpi-ssm.h +++ b/libfprint/fpi-ssm.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2007-2008 Daniel Drake * Copyright (C) 2018 Bastien Nocera + * Copyright (C) 2019 Benjamin Berg * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,70 +18,79 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __FPI_SSM_H__ -#define __FPI_SSM_H__ +#pragma once -#include -#include -#include -#include -#include -#include +#include "fp-device.h" +#include "fpi-usb-transfer.h" /* async drv <--> lib comms */ /** - * fpi_ssm: + * FpiSsm: * * Sequential state machine that iterates sequentially over * a predefined series of states. Can be terminated by either completion or * failure error conditions. */ -typedef struct fpi_ssm fpi_ssm; +typedef struct _FpiSsm FpiSsm; /** - * ssm_completed_fn: - * @ssm: a #fpi_ssm state machine + * FpiSsmCompletedCallback: + * @ssm: a #FpiSsm state machine * @dev: the #fp_dev fingerprint device * @user_data: the user data passed to fpi_ssm_new() + * @error: The #GError or %NULL on successful completion * * The callback called when a state machine completes successfully, * as set when calling fpi_ssm_start(). */ -typedef void (*ssm_completed_fn)(fpi_ssm *ssm, - struct fp_dev *dev, - void *user_data); +typedef void (*FpiSsmCompletedCallback)(FpiSsm *ssm, + FpDevice *dev, + void *user_data, + GError *error); /** - * ssm_handler_fn: - * @ssm: a #fpi_ssm state machine + * FpiSsmHandlerCallback: + * @ssm: a #FpiSsm state machine * @dev: the #fp_dev fingerprint device * @user_data: the user data passed to fpi_ssm_new() * * The callback called when a state machine transitions from one * state to the next, as set when calling fpi_ssm_new(). */ -typedef void (*ssm_handler_fn)(fpi_ssm *ssm, - struct fp_dev *dev, - void *user_data); +typedef void (*FpiSsmHandlerCallback)(FpiSsm *ssm, + FpDevice *dev, + void *user_data); /* for library and drivers */ -fpi_ssm *fpi_ssm_new(struct fp_dev *dev, - ssm_handler_fn handler, - int nr_states, - void *user_data); -void fpi_ssm_free(fpi_ssm *machine); -void fpi_ssm_start(fpi_ssm *ssm, ssm_completed_fn callback); -void fpi_ssm_start_subsm(fpi_ssm *parent, fpi_ssm *child); +FpiSsm *fpi_ssm_new (FpDevice *dev, + FpiSsmHandlerCallback handler, + int nr_states, + void *user_data); +void fpi_ssm_free (FpiSsm *machine); +void fpi_ssm_start (FpiSsm *ssm, + FpiSsmCompletedCallback callback); +void fpi_ssm_start_subsm (FpiSsm *parent, + FpiSsm *child); /* for drivers */ -void fpi_ssm_next_state(fpi_ssm *machine); -void fpi_ssm_next_state_timeout_cb(struct fp_dev *dev, void *data); -void fpi_ssm_jump_to_state(fpi_ssm *machine, int state); -void fpi_ssm_mark_completed(fpi_ssm *machine); -void fpi_ssm_mark_failed(fpi_ssm *machine, int error); -void *fpi_ssm_get_user_data(fpi_ssm *machine); -int fpi_ssm_get_error(fpi_ssm *machine); -int fpi_ssm_get_cur_state(fpi_ssm *machine); +void fpi_ssm_next_state (FpiSsm *machine); +void fpi_ssm_jump_to_state (FpiSsm *machine, + int state); +void fpi_ssm_mark_completed (FpiSsm *machine); +void fpi_ssm_mark_failed (FpiSsm *machine, + GError *error); +void *fpi_ssm_get_user_data (FpiSsm *machine); +GError * fpi_ssm_get_error (FpiSsm *machine); +GError * fpi_ssm_dup_error (FpiSsm *machine); +int fpi_ssm_get_cur_state (FpiSsm *machine); -#endif +/* Callbacks to be used by the driver instead of implementing their own + * logic. + */ +void fpi_ssm_next_state_timeout_cb (FpDevice *dev, + void *data); +void fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer, + FpDevice *device, + gpointer user_data, + GError *error); diff --git a/libfprint/fpi-sync.c b/libfprint/fpi-sync.c deleted file mode 100644 index c2dd7927..00000000 --- a/libfprint/fpi-sync.c +++ /dev/null @@ -1,690 +0,0 @@ -/* - * Synchronous I/O functionality - * Copyright (C) 2007-2008 Daniel Drake - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#define FP_COMPONENT "sync" - -#include "fp_internal.h" -#include "fpi-dev.h" - -#include -#include - -struct sync_open_data { - struct fp_dev *dev; - int status; -}; - -static void sync_open_cb(struct fp_dev *dev, int status, void *user_data) -{ - struct sync_open_data *odata = user_data; - fp_dbg("status %d", status); - odata->dev = dev; - odata->status = status; -} - -/** - * fp_dev_open: - * @ddev: the struct #fp_dscv_dev discovered device to open - * - * Opens and initialises a device. This is the function you call in order - * to convert a #fp_dscv_dev discovered device into an actual device handle - * that you can perform operations with. - * - * Returns: the opened device handle, or %NULL on error - */ -API_EXPORTED struct fp_dev *fp_dev_open(struct fp_dscv_dev *ddev) -{ - struct fp_dev *dev = NULL; - struct sync_open_data *odata = g_malloc0(sizeof(*odata)); - int r; - - G_DEBUG_HERE(); - r = fp_async_dev_open(ddev, sync_open_cb, odata); - if (r) - goto out; - - while (!odata->dev) - if (fp_handle_events() < 0) - goto out; - - if (odata->status == 0) - dev = odata->dev; - else - fp_dev_close(odata->dev); - -out: - g_free(odata); - return dev; -} - -static void sync_close_cb(struct fp_dev *dev, void *user_data) -{ - G_DEBUG_HERE(); - gboolean *closed = user_data; - *closed = TRUE; -} - -/** - * fp_dev_close: - * @dev: the struct #fp_dev device to close. If %NULL, function simply returns - * - * Closes a device. You must call this function when you have finished using - * a fingerprint device. - */ -API_EXPORTED void fp_dev_close(struct fp_dev *dev) -{ - gboolean closed = FALSE; - - if (!dev) - return; - - G_DEBUG_HERE(); - fp_async_dev_close(dev, sync_close_cb, &closed); - while (!closed) - if (fp_handle_events() < 0) - break; -} - -struct sync_enroll_data { - gboolean populated; - int result; - struct fp_print_data *data; - struct fp_img *img; -}; - -static void sync_enroll_cb(struct fp_dev *dev, int result, - struct fp_print_data *data, struct fp_img *img, void *user_data) -{ - struct sync_enroll_data *edata = user_data; - fp_dbg("result %d", result); - edata->result = result; - edata->data = data; - edata->img = img; - edata->populated = TRUE; -} - -static void enroll_stop_cb(struct fp_dev *dev, void *user_data) -{ - gboolean *stopped = user_data; - G_DEBUG_HERE(); - *stopped = TRUE; -} - -/** - * fp_enroll_finger_img: - * @dev: the struct #fp_dev device - * @print_data: a location to return the resultant enrollment data from - * the final stage. Must be freed with fp_print_data_free() after use - * @img: location to store the scan image. accepts %NULL for no image - * storage. If an image is returned, it must be freed with fp_img_free() after - * use - * - * Performs an enroll stage. See [Enrolling](libfprint-Devices-operations.html#enrolling) - * for an explanation of enroll stages. - * - * If no enrollment is in process, this kicks of the process and runs the - * first stage. If an enrollment is already in progress, calling this - * function runs the next stage, which may well be the last. - * - * A negative error code may be returned from any stage. When this occurs, - * further calls to the enroll function will start a new enrollment process, - * i.e. a negative error code indicates that the enrollment process has been - * aborted. These error codes only ever indicate unexpected internal errors - * or I/O problems. - * - * The RETRY codes from #fp_enroll_result may be returned from any enroll - * stage. These codes indicate that the scan was not successful in that the - * user did not position their finger correctly or similar. When a RETRY code - * is returned, the enrollment stage is not advanced, so the next call - * into this function will retry the current stage again. The current stage may - * need to be retried several times. - * - * The %FP_ENROLL_FAIL code may be returned from any enroll - * stage. This code indicates that even though the scans themselves have been - * acceptable, data processing applied to these scans produces incomprehensible - * results. In other words, the user may have been scanning a different finger - * for each stage or something like that. Like negative error codes, this - * return code indicates that the enrollment process has been aborted. - * - * The %FP_ENROLL_PASS code will only ever be returned for - * non-final stages. This return code indicates that the scan was acceptable - * and the next call into this function will advance onto the next enroll - * stage. - * - * The %FP_ENROLL_COMPLETE code will only ever be returned - * from the final enroll stage. It indicates that enrollment completed - * successfully, and that print_data has been assigned to point to the - * resultant enrollment data. The print_data parameter will not be modified - * during any other enrollment stages, hence it is actually legal to pass NULL - * as this argument for all but the final stage. - * - * If the device is an imaging device, it can also return the image from - * the scan, even when the enroll fails with a RETRY or FAIL code. It is legal - * to call this function even on non-imaging devices, just don't expect them to - * provide images. - * - * Returns: negative code on error, otherwise a code from #fp_enroll_result - */ -API_EXPORTED int fp_enroll_finger_img(struct fp_dev *dev, - struct fp_print_data **print_data, struct fp_img **img) -{ - struct fp_driver *drv = dev->drv; - int stage = dev->__enroll_stage; - gboolean final = FALSE; - gboolean stopped = FALSE; - struct sync_enroll_data *edata = NULL; - int r; - G_DEBUG_HERE(); - - /* FIXME __enroll_stage is ugly, can we replace it by some function that - * says whether we're enrolling or not, and then put __enroll_stage into - * edata? */ - - if (stage == -1) { - edata = g_malloc0(sizeof(struct sync_enroll_data)); - r = fp_async_enroll_start(dev, sync_enroll_cb, edata); - if (r < 0) { - g_free(edata); - return r; - } - - dev->__enroll_stage = ++stage; - } else if (stage >= dev->nr_enroll_stages) { - fp_err("exceeding number of enroll stages for device claimed by " - "driver %s (%d stages)", drv->name, dev->nr_enroll_stages); - dev->__enroll_stage = -1; - r = -EINVAL; - final = TRUE; - goto out; - } - fp_dbg("%s will handle enroll stage %d/%d", drv->name, stage, - dev->nr_enroll_stages - 1); - - /* FIXME this isn't very clean */ - edata = dev->enroll_stage_cb_data; - - while (!edata->populated) { - r = fp_handle_events(); - if (r < 0) { - g_free(edata); - goto err; - } - } - - edata->populated = FALSE; - - if (img) - *img = edata->img; - else - fp_img_free(edata->img); - - r = edata->result; - switch (r) { - case FP_ENROLL_PASS: - fp_dbg("enroll stage passed"); - dev->__enroll_stage = stage + 1; - break; - case FP_ENROLL_COMPLETE: - fp_dbg("enroll complete"); - dev->__enroll_stage = -1; - *print_data = edata->data; - final = TRUE; - break; - case FP_ENROLL_RETRY: - fp_dbg("enroll should retry"); - break; - case FP_ENROLL_RETRY_TOO_SHORT: - fp_dbg("swipe was too short, enroll should retry"); - break; - case FP_ENROLL_RETRY_CENTER_FINGER: - fp_dbg("finger was not centered, enroll should retry"); - break; - case FP_ENROLL_RETRY_REMOVE_FINGER: - fp_dbg("scan failed, remove finger and retry"); - break; - case FP_ENROLL_FAIL: - fp_err("enroll failed"); - dev->__enroll_stage = -1; - final = TRUE; - break; - default: - fp_err("unrecognised return code %d", r); - dev->__enroll_stage = -1; - r = -EINVAL; - final = TRUE; - break; - } - - if (!final) - return r; - -out: - if (final) { - fp_dbg("ending enrollment"); - g_free(edata); - } - -err: - if (fp_async_enroll_stop(dev, enroll_stop_cb, &stopped) == 0) - while (!stopped) - if (fp_handle_events() < 0) - break; - return r; -} - -/** - * fp_enroll_finger: - * @dev: the struct #fp_dev device - * @print_data: a location to return the resultant enrollment data from - * the final stage. Must be freed with fp_print_data_free() after use - * - * Performs an enroll stage. See [Enrolling](libfprint-Devices-operations.html#enrolling) - * for an explanation of enroll stages. This function is just a shortcut to - * calling fp_enroll_finger_img() with a %NULL image parameter. Be sure to read - * the description of fp_enroll_finger_img() in order to understand its behaviour. - * - * Returns: negative code on error, otherwise a code from #fp_enroll_result - */ -API_EXPORTED int fp_enroll_finger(struct fp_dev *dev, - struct fp_print_data **print_data) -{ - return fp_enroll_finger_img(dev, print_data, NULL); -} - -struct sync_verify_data { - gboolean populated; - int result; - struct fp_img *img; -}; - -static void sync_verify_cb(struct fp_dev *dev, int result, struct fp_img *img, - void *user_data) -{ - struct sync_verify_data *vdata = user_data; - vdata->result = result; - vdata->img = img; - vdata->populated = TRUE; -} - -static void verify_stop_cb(struct fp_dev *dev, void *user_data) -{ - gboolean *stopped = user_data; - G_DEBUG_HERE(); - *stopped = TRUE; -} - -/** - * fp_verify_finger_img: - * @dev: the struct #fp_dev device to perform the scan on - * @enrolled_print: the print to verify against. Must have been previously - * enrolled with a device compatible to the device selected to perform the scan - * @img: location to store the scan image. accepts %NULL for no image - * storage. If an image is returned, it must be freed with fp_img_free() after - * use - - * Performs a new scan and verifies it against a previously enrolled print. - * If the device is an imaging device, it can also return the image from - * the scan, even when the verify fails with a RETRY code. It is legal to - * call this function even on non-imaging devices, just don't expect them to - * provide images. - * - * Returns: negative code on error, otherwise a code from #fp_verify_result - */ -API_EXPORTED int fp_verify_finger_img(struct fp_dev *dev, - struct fp_print_data *enrolled_print, struct fp_img **img) -{ - struct sync_verify_data *vdata; - gboolean stopped = FALSE; - int r; - - if (!enrolled_print) { - fp_err("no print given"); - return -EINVAL; - } - - if (!fp_dev_supports_print_data(dev, enrolled_print)) { - fp_err("print is not compatible with device"); - return -EINVAL; - } - - fp_dbg("to be handled by %s", dev->drv->name); - vdata = g_malloc0(sizeof(struct sync_verify_data)); - r = fp_async_verify_start(dev, enrolled_print, sync_verify_cb, vdata); - if (r < 0) { - fp_dbg("verify_start error %d", r); - g_free(vdata); - return r; - } - - while (!vdata->populated) { - r = fp_handle_events(); - if (r < 0) { - g_free(vdata); - goto err; - } - } - - if (img) - *img = vdata->img; - else - fp_img_free(vdata->img); - - r = vdata->result; - g_free(vdata); - switch (r) { - case FP_VERIFY_NO_MATCH: - fp_dbg("result: no match"); - break; - case FP_VERIFY_MATCH: - fp_dbg("result: match"); - break; - case FP_VERIFY_RETRY: - fp_dbg("verify should retry"); - break; - case FP_VERIFY_RETRY_TOO_SHORT: - fp_dbg("swipe was too short, verify should retry"); - break; - case FP_VERIFY_RETRY_CENTER_FINGER: - fp_dbg("finger was not centered, verify should retry"); - break; - case FP_VERIFY_RETRY_REMOVE_FINGER: - fp_dbg("scan failed, remove finger and retry"); - break; - default: - fp_err("unrecognised return code %d", r); - r = -EINVAL; - } - -err: - fp_dbg("ending verification"); - if (fp_async_verify_stop(dev, verify_stop_cb, &stopped) == 0) - while (!stopped) - if (fp_handle_events() < 0) - break; - - return r; -} - -/** - * fp_verify_finger: - * @dev: the struct #fp_dev device to perform the scan on - * @enrolled_print: the print to verify against. Must have been previously - * enrolled with a device compatible to the device selected to perform the scan - * - * Performs a new scan and verify it against a previously enrolled print. This - * function is just a shortcut to calling fp_verify_finger_img() with a NULL - * image output parameter. - * - * See also fp_verify_finger_img(). - * - * Returns: negative code on error, otherwise a code from #fp_verify_result - */ -API_EXPORTED int fp_verify_finger(struct fp_dev *dev, - struct fp_print_data *enrolled_print) -{ - return fp_verify_finger_img(dev, enrolled_print, NULL); -} - -struct sync_identify_data { - gboolean populated; - int result; - size_t match_offset; - struct fp_img *img; -}; - -static void sync_identify_cb(struct fp_dev *dev, int result, - size_t match_offset, struct fp_img *img, void *user_data) -{ - struct sync_identify_data *idata = user_data; - idata->result = result; - idata->match_offset = match_offset; - idata->img = img; - idata->populated = TRUE; -} - -static void identify_stop_cb(struct fp_dev *dev, void *user_data) -{ - gboolean *stopped = user_data; - G_DEBUG_HERE(); - *stopped = TRUE; -} - -/** - * fp_identify_finger_img: - * @dev: the struct #fp_dev device to perform the scan on - * @print_gallery: NULL-terminated array of pointers to the prints to - * identify against. Each one must have been previously enrolled with a device - * compatible to the device selected to perform the scan - * @match_offset: output location to store the array index of the matched - * gallery print (if any was found). Only valid if %FP_VERIFY_MATCH was - * returned - * @img: location to store the scan image. accepts %NULL for no image - * storage. If an image is returned, it must be freed with fp_img_free() after - * use - - * Performs a new scan and attempts to identify the scanned finger against - * a collection of previously enrolled fingerprints. - * If the device is an imaging device, it can also return the image from - * the scan, even when identification fails with a RETRY code. It is legal to - * call this function even on non-imaging devices, just don't expect them to - * provide images. - * - * This function returns codes from #fp_verify_result. The return code - * %FP_VERIFY_MATCH indicates that the scanned fingerprint - * does appear in the print gallery, and the match_offset output parameter - * will indicate the index into the print gallery array of the matched print. - * - * This function will not necessarily examine the whole print gallery, it - * will return as soon as it finds a matching print. - * - * Not all devices support identification. -ENOTSUP will be returned when - * this is the case. - * - * Returns: negative code on error, otherwise a code from #fp_verify_result - */ -API_EXPORTED int fp_identify_finger_img(struct fp_dev *dev, - struct fp_print_data **print_gallery, size_t *match_offset, - struct fp_img **img) -{ - gboolean stopped = FALSE; - struct sync_identify_data *idata - = g_malloc0(sizeof(struct sync_identify_data)); - int r; - - fp_dbg("to be handled by %s", dev->drv->name); - - r = fp_async_identify_start(dev, print_gallery, sync_identify_cb, idata); - if (r < 0) { - fp_err("identify_start error %d", r); - goto err; - } - - while (!idata->populated) { - r = fp_handle_events(); - if (r < 0) - goto err_stop; - } - - if (img) - *img = idata->img; - else - fp_img_free(idata->img); - - r = idata->result; - switch (idata->result) { - case FP_VERIFY_NO_MATCH: - fp_dbg("result: no match"); - break; - case FP_VERIFY_MATCH: - fp_dbg("result: match at offset %zd", idata->match_offset); - *match_offset = idata->match_offset; - break; - case FP_VERIFY_RETRY: - fp_dbg("verify should retry"); - break; - case FP_VERIFY_RETRY_TOO_SHORT: - fp_dbg("swipe was too short, verify should retry"); - break; - case FP_VERIFY_RETRY_CENTER_FINGER: - fp_dbg("finger was not centered, verify should retry"); - break; - case FP_VERIFY_RETRY_REMOVE_FINGER: - fp_dbg("scan failed, remove finger and retry"); - break; - default: - fp_err("unrecognised return code %d", r); - r = -EINVAL; - } - -err_stop: - if (fp_async_identify_stop(dev, identify_stop_cb, &stopped) == 0) - while (!stopped) - if (fp_handle_events() < 0) - break; - -err: - g_free(idata); - return r; -} - -/** - * fp_identify_finger: - * @dev: the struct #fp_dev device to perform the scan on - * @print_gallery: %NULL-terminated array of pointers to the prints to - * identify against. Each one must have been previously enrolled with a device - * compatible to the device selected to perform the scan - * @match_offset: output location to store the array index of the matched - * gallery print (if any was found). Only valid if %FP_VERIFY_MATCH was - * returned - - * Performs a new scan and attempts to identify the scanned finger against a - * collection of previously enrolled fingerprints. This function is just a - * shortcut to calling fp_identify_finger_img() with a %NULL image output - * parameter. - * - * See also fp_identify_finger_img(). - * - * Returns: negative code on error, otherwise a code from #fp_verify_result - */ -API_EXPORTED int fp_identify_finger(struct fp_dev *dev, - struct fp_print_data **print_gallery, size_t *match_offset) -{ - return fp_identify_finger_img(dev, print_gallery, match_offset, NULL); -} - -struct sync_capture_data { - gboolean populated; - int result; - struct fp_img *img; -}; - -static void sync_capture_cb(struct fp_dev *dev, int result, struct fp_img *img, - void *user_data) -{ - struct sync_capture_data *vdata = user_data; - vdata->result = result; - vdata->img = img; - vdata->populated = TRUE; -} - -static void capture_stop_cb(struct fp_dev *dev, void *user_data) -{ - gboolean *stopped = user_data; - G_DEBUG_HERE(); - *stopped = TRUE; -} -/** - * fp_dev_img_capture: - * @dev: the struct #fp_dev device - * @unconditional: whether to unconditionally capture an image, or to only capture when a finger is detected - * @img: a location to return the captured image. Must be freed with - * fp_img_free() after use - * - * Captures a #fp_img from a device. The returned image is the raw - * image provided by the device, you may wish to [standardize](libfprint-Image-operations.html#img_std) it. - * - * If set, the @unconditional flag indicates that the device should - * capture an image unconditionally, regardless of whether a finger is there - * or not. If unset, this function will block until a finger is detected on - * the sensor. - * - * See fp_dev_supports_imaging(). - * - * Returns: 0 on success, non-zero on error. -ENOTSUP indicates that either the - * @unconditional flag was set but the device does not support this, or that the - * device does not support imaging - */ -API_EXPORTED int fp_dev_img_capture(struct fp_dev *dev, int unconditional, - struct fp_img **img) -{ - struct sync_capture_data *vdata; - gboolean stopped = FALSE; - int r; - - if (!dev->drv->capture_start) { - fp_dbg("image capture is not supported on %s device", dev->drv->name); - return -ENOTSUP; - } - - fp_dbg("to be handled by %s", dev->drv->name); - vdata = g_malloc0(sizeof(struct sync_capture_data)); - r = fp_async_capture_start(dev, unconditional, sync_capture_cb, vdata); - if (r < 0) { - fp_dbg("capture_start error %d", r); - g_free(vdata); - return r; - } - - while (!vdata->populated) { - r = fp_handle_events(); - if (r < 0) { - g_free(vdata); - goto err; - } - } - - if (img) - *img = vdata->img; - else - fp_img_free(vdata->img); - - r = vdata->result; - g_free(vdata); - switch (r) { - case FP_CAPTURE_COMPLETE: - fp_dbg("result: complete"); - break; - case FP_CAPTURE_FAIL: - fp_dbg("result: fail"); - break; - default: - fp_err("unrecognised return code %d", r); - r = -EINVAL; - } - -err: - fp_dbg("ending capture"); - if (fp_async_capture_stop(dev, capture_stop_cb, &stopped) == 0) - while (!stopped) - if (fp_handle_events() < 0) - break; - - return r; -} - diff --git a/libfprint/fpi-usb-transfer.c b/libfprint/fpi-usb-transfer.c new file mode 100644 index 00000000..6b296212 --- /dev/null +++ b/libfprint/fpi-usb-transfer.c @@ -0,0 +1,522 @@ +/* + * FPrint USB transfer handling + * Copyright (C) 2019 Benjamin Berg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "fpi-usb-transfer.h" + +/** + * SECTION:fpi-usb-transfer + * @title: USB transfer helpers + * @short_description: Helpers for libgusb to ease transfer handling + * + * #FpiUsbTransfer is a structure to simplify the USB transfer handling. + * The main goal is to ease memory management and provide more parameters + * to callbacks that are useful for libfprint drivers. + * + * Drivers should use this API only rather than accessing the GUsbDevice + * directly in most cases. + */ + + +G_DEFINE_BOXED_TYPE (FpiUsbTransfer, fpi_usb_transfer, fpi_usb_transfer_ref, fpi_usb_transfer_unref) + +static void +log_transfer (FpiUsbTransfer *transfer, gboolean submit, GError *error) +{ + if (g_getenv ("FP_DEBUG_TRANSFER")) + { + if (!submit) + { + g_autofree gchar *error_str = NULL; + if (error) + error_str = g_strdup_printf ("with error (%s)", error->message); + else + error_str = g_strdup ("successfully"); + + g_debug ("Transfer %p completed %s, requested length %zd, actual length %zd, endpoint 0x%x", + transfer, + error_str, + transfer->length, + transfer->actual_length, + transfer->endpoint); + } + else + { + g_debug ("Transfer %p submitted, requested length %zd, endpoint 0x%x", + transfer, + transfer->length, + transfer->endpoint); + } + + if (!submit == !!(transfer->endpoint & FPI_USB_ENDPOINT_IN)) + { + g_autoptr(GString) line = NULL; + gssize dump_len; + + dump_len = (transfer->endpoint & FPI_USB_ENDPOINT_IN) ? transfer->actual_length : transfer->length; + + line = g_string_new (""); + /* Dump the buffer. */ + for (gint i = 0; i < dump_len; i++) + { + g_string_append_printf (line, "%02x ", transfer->buffer[i]); + if ((i + 1) % 16 == 0) + { + g_debug ("%s", line->str); + g_string_set_size (line, 0); + } + } + + if (line->len) + g_debug ("%s", line->str); + } + } +} + +/** + * fpi_usb_transfer_new: + * @device: The #FpDevice the transfer is for + * + * Creates a new #FpiUsbTransfer. + * + * Returns: (transfer full): A newly created #FpiUsbTransfer + */ +FpiUsbTransfer * +fpi_usb_transfer_new (FpDevice * device) +{ + FpiUsbTransfer *self; + + g_assert (device != NULL); + + self = g_slice_new0 (FpiUsbTransfer); + self->ref_count = 1; + + self->device = device; + + return self; +} + +static void +fpi_usb_transfer_free (FpiUsbTransfer *self) +{ + g_assert (self); + g_assert_cmpint (self->ref_count, ==, 0); + + if (self->free_buffer && self->buffer) + self->free_buffer (self->buffer); + self->buffer = NULL; + + g_slice_free (FpiUsbTransfer, self); +} + +/** + * fpi_usb_transfer_ref: + * @self: A #FpiUsbTransfer + * + * Increments the reference count of @self by one. + * + * Returns: (transfer full): @self + */ +FpiUsbTransfer * +fpi_usb_transfer_ref (FpiUsbTransfer *self) +{ + g_return_val_if_fail (self, NULL); + g_return_val_if_fail (self->ref_count, NULL); + + g_atomic_int_inc (&self->ref_count); + + return self; +} + +/** + * fpi_usb_transfer_unref: + * @self: A #FpiUsbTransfer + * + * Decrements the reference count of @self by one, freeing the structure when + * the reference count reaches zero. + */ +void +fpi_usb_transfer_unref (FpiUsbTransfer *self) +{ + g_return_if_fail (self); + g_return_if_fail (self->ref_count); + + if (g_atomic_int_dec_and_test (&self->ref_count)) + fpi_usb_transfer_free (self); +} + +/** + * fpi_usb_transfer_fill_bulk: + * @transfer: The #FpiUsbTransfer + * @endpoint: The endpoint to send the transfer to + * @length: The buffer size to allocate + * + * Prepare a bulk transfer. A buffer will be created for you, use + * fpi_usb_transfer_fill_bulk_full() if you want to send a static buffer + * or receive a pre-defined buffer. + */ +void +fpi_usb_transfer_fill_bulk (FpiUsbTransfer *transfer, + guint8 endpoint, + gsize length) +{ + fpi_usb_transfer_fill_bulk_full (transfer, + endpoint, + g_malloc0 (length), + length, + g_free); +} + +/** + * fpi_usb_transfer_fill_bulk_full: + * @transfer: The #FpiUsbTransfer + * @endpoint: The endpoint to send the transfer to + * @buffer: The data to send. A buffer will be created and managed for you if you pass NULL. + * @length: The size of @buffer + * @free_func: (destroy buffer): Destroy notify for @buffer + * + * Prepare a bulk transfer. + */ +void +fpi_usb_transfer_fill_bulk_full (FpiUsbTransfer *transfer, + guint8 endpoint, + guint8 *buffer, + gsize length, + GDestroyNotify free_func) +{ + g_assert (transfer->type == FP_TRANSFER_NONE); + g_assert (buffer != NULL); + + transfer->type = FP_TRANSFER_BULK; + transfer->endpoint = endpoint; + + transfer->buffer = buffer; + transfer->length = length; + transfer->free_buffer = free_func; +} + +/** + * fpi_usb_transfer_fill_control: + * @transfer: The #FpiUsbTransfer + * @direction: The direction of the control transfer + * @request_type: The request type + * @recipient: The recipient + * @request: The control transfer request + * @value: The control transfer value + * @idx: The control transfer index + * @length: The size of the transfer + * + * Prepare a control transfer. The function will create a new buffer, + * you can initialize the buffer after calling this function. + */ +void +fpi_usb_transfer_fill_control (FpiUsbTransfer *transfer, + GUsbDeviceDirection direction, + GUsbDeviceRequestType request_type, + GUsbDeviceRecipient recipient, + guint8 request, + guint16 value, + guint16 idx, + gsize length) +{ + g_assert (transfer->type == FP_TRANSFER_NONE); + + transfer->type = FP_TRANSFER_CONTROL; + transfer->direction = direction; + transfer->request_type = request_type; + transfer->recipient = recipient; + transfer->request = request; + transfer->value = value; + transfer->idx = idx; + + transfer->length = length; + transfer->buffer = g_malloc0 (length); + transfer->free_buffer = g_free; +} + +/** + * fpi_usb_transfer_fill_interrupt: + * @transfer: The #FpiUsbTransfer + * @endpoint: The endpoint to send the transfer to + * @length: The size of the transfer + * + * Prepare an interrupt transfer. The function will create a new buffer, + * you can initialize the buffer after calling this function. + */ +void +fpi_usb_transfer_fill_interrupt (FpiUsbTransfer *transfer, + guint8 endpoint, + gsize length) +{ + fpi_usb_transfer_fill_interrupt_full (transfer, + endpoint, + g_malloc0 (length), + length, + g_free); +} + +/** + * fpi_usb_transfer_fill_interrupt_full: + * @transfer: The #FpiUsbTransfer + * @endpoint: The endpoint to send the transfer to + * @buffer: The data to send. A buffer will be created and managed for you if you pass NULL. + * @length: The size of @buffer + * @free_func: (destroy buffer): Destroy notify for @buffer + * + * Prepare an interrupt transfer. + */ +void +fpi_usb_transfer_fill_interrupt_full (FpiUsbTransfer *transfer, + guint8 endpoint, + guint8 *buffer, + gsize length, + GDestroyNotify free_func) +{ + g_assert (transfer->type == FP_TRANSFER_NONE); + g_assert (buffer != NULL); + + transfer->type = FP_TRANSFER_INTERRUPT; + transfer->endpoint = endpoint; + + transfer->buffer = buffer; + transfer->length = length; + transfer->free_buffer = free_func; +} + +void +transfer_finish_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + FpiUsbTransfer *transfer = user_data; + FpiUsbTransferCallback callback; + + switch (transfer->type) + { + case FP_TRANSFER_BULK: + transfer->actual_length = + g_usb_device_bulk_transfer_finish (G_USB_DEVICE (source_object), + res, + &error); + break; + + case FP_TRANSFER_CONTROL: + transfer->actual_length = + g_usb_device_control_transfer_finish (G_USB_DEVICE (source_object), + res, + &error); + break; + + case FP_TRANSFER_INTERRUPT: + transfer->actual_length = + g_usb_device_interrupt_transfer_finish (G_USB_DEVICE (source_object), + res, + &error); + break; + + case FP_TRANSFER_NONE: + default: + g_assert_not_reached (); + } + + log_transfer (transfer, FALSE, error); + + /* Check for short error, and set an error if requested */ + if (error == NULL && + transfer->short_is_error && + transfer->actual_length > 0 && + transfer->actual_length != transfer->length) + { + error = g_error_new (G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_IO, + "Unexpected short error of %zd size (expected %zd)", transfer->actual_length, transfer->length); + } + + callback = transfer->callback; + transfer->callback = NULL; + callback (transfer, transfer->device, transfer->user_data, error); + + fpi_usb_transfer_unref (transfer); +} + + +/** + * fpi_usb_transfer_submit: + * @transfer: The transfer to submit, must have been filled. + * @timeout_ms: Timeout for the transfer in ms + * @cancellable: Cancellable to use, e.g. fpi_device_get_cancellable() + * @callback: Callback on completion or error + * @user_data: Data to pass to callback + * + * Submit a USB transfer with a specific timeout and callback functions. + * + * Note that #FpiUsbTransfer is owned by the user. In most cases, you + * should call fpi_usb_transfer_unref() just after calling this function. + * Doing so means that all associated data will be free'ed automatically + * after the callback ran. + */ +void +fpi_usb_transfer_submit (FpiUsbTransfer *transfer, + guint timeout_ms, + GCancellable *cancellable, + FpiUsbTransferCallback callback, + gpointer user_data) +{ + g_return_if_fail (transfer); + g_return_if_fail (callback); + + /* Recycling is allowed, but not two at the same time. */ + g_return_if_fail (transfer->callback == NULL); + + transfer->callback = callback; + transfer->user_data = user_data; + + /* Grab a reference, this means that one can simply unref after submit and + * trust for the data to disappear without explicit management by the callback + * function. */ + fpi_usb_transfer_ref (transfer); + + log_transfer (transfer, TRUE, NULL); + + switch (transfer->type) + { + case FP_TRANSFER_BULK: + g_usb_device_bulk_transfer_async (fpi_device_get_usb_device (transfer->device), + transfer->endpoint, + transfer->buffer, + transfer->length, + timeout_ms, + cancellable, + transfer_finish_cb, + transfer); + break; + + case FP_TRANSFER_CONTROL: + g_usb_device_control_transfer_async (fpi_device_get_usb_device (transfer->device), + transfer->direction, + transfer->request_type, + transfer->recipient, + transfer->request, + transfer->value, + transfer->idx, + transfer->buffer, + transfer->length, + timeout_ms, + cancellable, + transfer_finish_cb, + transfer); + break; + + case FP_TRANSFER_INTERRUPT: + g_usb_device_interrupt_transfer_async (fpi_device_get_usb_device (transfer->device), + transfer->endpoint, + transfer->buffer, + transfer->length, + timeout_ms, + cancellable, + transfer_finish_cb, + transfer); + break; + + case FP_TRANSFER_NONE: + default: + fpi_usb_transfer_unref (transfer); + g_return_if_reached (); + } +} + +/** + * fpi_usb_transfer_submit_sync: + * @transfer: The transfer to submit, must have been filled. + * @timeout_ms: Timeout for the transfer in millisecnods + * @error: Location to store #GError to + * + * Synchronously submit a USB transfer with a specific timeout. + * Only use this function with short timeouts as the application will + * be blocked otherwise. + * + * Note that you still need to fpi_usb_transfer_unref() the + * #FpiUsbTransfer afterwards. + * + * Returns: #TRUE on success, otherwise #FALSE and @error will be set + */ +gboolean +fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer, + guint timeout_ms, + GError **error) +{ + gboolean res; + + g_return_val_if_fail (transfer, FALSE); + + /* Recycling is allowed, but not two at the same time. */ + g_return_val_if_fail (transfer->callback == NULL, FALSE); + + log_transfer (transfer, TRUE, NULL); + + switch (transfer->type) + { + case FP_TRANSFER_BULK: + res = g_usb_device_bulk_transfer (fpi_device_get_usb_device (transfer->device), + transfer->endpoint, + transfer->buffer, + transfer->length, + &transfer->actual_length, + timeout_ms, + NULL, + error); + break; + + case FP_TRANSFER_CONTROL: + res = g_usb_device_control_transfer (fpi_device_get_usb_device (transfer->device), + transfer->direction, + transfer->request_type, + transfer->recipient, + transfer->request, + transfer->value, + transfer->idx, + transfer->buffer, + transfer->length, + &transfer->actual_length, + timeout_ms, + NULL, + error); + break; + + case FP_TRANSFER_INTERRUPT: + res = g_usb_device_interrupt_transfer (fpi_device_get_usb_device (transfer->device), + transfer->endpoint, + transfer->buffer, + transfer->length, + &transfer->actual_length, + timeout_ms, + NULL, + error); + break; + + case FP_TRANSFER_NONE: + default: + g_return_val_if_reached (FALSE); + } + + log_transfer (transfer, FALSE, *error); + + if (!res) + transfer->actual_length = -1; + + return res; +} diff --git a/libfprint/fpi-usb-transfer.h b/libfprint/fpi-usb-transfer.h new file mode 100644 index 00000000..5b8fe9cb --- /dev/null +++ b/libfprint/fpi-usb-transfer.h @@ -0,0 +1,157 @@ +/* + * FPrint USB transfer handling + * Copyright (C) 2019 Benjamin Berg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include +#include "fpi-device.h" + +G_BEGIN_DECLS + +#define FPI_TYPE_USB_TRANSFER (fpi_usb_transfer_get_type ()) + +#define FPI_USB_ENDPOINT_IN 0x80 +#define FPI_USB_ENDPOINT_OUT 0x00 + +typedef struct _FpiUsbTransfer FpiUsbTransfer; + +#include "fpi-ssm.h" + +typedef void (*FpiUsbTransferCallback)(FpiUsbTransfer *transfer, + FpDevice *dev, + gpointer user_data, + GError *error); + +/** + * FpiTransferType: + * @FP_TRANSFER_NONE: Type not set + * @FP_TRANSFER_BULK: Bulk transfer + * @FP_TRANSFER_CONTROL: Control transfer + * @FP_TRANSFER_INTERRUPT: Interrupt transfer + * + * Type of the transfer. + */ +typedef enum { + FP_TRANSFER_NONE = 0, + FP_TRANSFER_BULK, + FP_TRANSFER_CONTROL, + FP_TRANSFER_INTERRUPT, +} FpiTransferType; + +/** + * FpiUsbTransfer: + * @device: The #FpDevice that the transfer belongs to. + * @ssm: Storage slot to associate the transfer with a state machine. + * Used by fpi_ssm_usb_transfer_cb() to modify the given state machine. + * @length: The requested length of the transfer in bytes. + * @actual_length: The actual length of the transfer + * (see also fpi_usb_transfer_set_short_error()) + * @buffer: The transfered data. + * + * Helper for handling USB transfers. + */ +struct _FpiUsbTransfer +{ + /*< public >*/ + FpDevice *device; + + FpiSsm *ssm; + + gssize length; + gssize actual_length; + + guchar *buffer; + + /*< private >*/ + guint ref_count; + + /* USB Transfer information */ + FpiTransferType type; + guint8 endpoint; + + /* Control Transfer options */ + GUsbDeviceDirection direction; + GUsbDeviceRequestType request_type; + GUsbDeviceRecipient recipient; + guint8 request; + guint16 value; + guint16 idx; + + /* Flags */ + gboolean short_is_error; + + /* Callbacks */ + gpointer user_data; + FpiUsbTransferCallback callback; + + /* Data free function */ + GDestroyNotify free_buffer; +}; + +GType fpi_usb_transfer_get_type (void) G_GNUC_CONST; +FpiUsbTransfer *fpi_usb_transfer_new (FpDevice *device); +FpiUsbTransfer *fpi_usb_transfer_ref (FpiUsbTransfer *self); +void fpi_usb_transfer_unref (FpiUsbTransfer *self); + +void fpi_usb_transfer_set_short_error (FpiUsbTransfer *transfer, + gboolean short_is_error); + +void fpi_usb_transfer_fill_bulk (FpiUsbTransfer *transfer, + guint8 endpoint, + gsize length); + +void fpi_usb_transfer_fill_bulk_full (FpiUsbTransfer *transfer, + guint8 endpoint, + guint8 *buffer, + gsize length, + GDestroyNotify free_func); + +void fpi_usb_transfer_fill_control (FpiUsbTransfer *transfer, + GUsbDeviceDirection direction, + GUsbDeviceRequestType request_type, + GUsbDeviceRecipient recipient, + guint8 request, + guint16 value, + guint16 idx, + gsize length); + +void fpi_usb_transfer_fill_interrupt (FpiUsbTransfer *transfer, + guint8 endpoint, + gsize length); + +void fpi_usb_transfer_fill_interrupt_full (FpiUsbTransfer *transfer, + guint8 endpoint, + guint8 *buffer, + gsize length, + GDestroyNotify free_func); + +void fpi_usb_transfer_submit (FpiUsbTransfer *transfer, + guint timeout_ms, + GCancellable *cancellable, + FpiUsbTransferCallback callback, + gpointer user_data); + +gboolean fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer, + guint timeout_ms, + GError **error); + + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiUsbTransfer, fpi_usb_transfer_unref) + +G_END_DECLS diff --git a/libfprint/fpi-usb.c b/libfprint/fpi-usb.c deleted file mode 100644 index b140d7ef..00000000 --- a/libfprint/fpi-usb.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Driver API definitions - * Copyright (C) 2018 Bastien Nocera - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "fpi-usb.h" -#include "drivers_api.h" - -/** - * SECTION:fpi-usb - * @title: Helpers for libusb - * @short_description: libusb-related helpers - * - * A collection of [libusb helpers](http://libusb.sourceforge.net/api-1.0/group__poll.html#details) - * to make driver development easier. Please refer to the libusb API documentation for more - * information about the original API. - */ - -/* Helpers from glib */ -#include -#include -#include -#include -#include - -/* special helpers to avoid gmessage.c dependency */ -static void mem_error (const char *format, ...) G_GNUC_PRINTF (1,2); -#define mem_assert(cond) do { if (G_LIKELY (cond)) ; else mem_error ("assertion failed: %s", #cond); } while (0) - -static void -mem_error (const char *format, - ...) -{ - const char *pname; - va_list args; - /* at least, put out "MEMORY-ERROR", in case we segfault during the rest of the function */ - fputs ("\n***MEMORY-ERROR***: ", stderr); - pname = g_get_prgname(); - g_fprintf (stderr, "%s[%ld]: ", pname ? pname : "", (long)getpid()); - va_start (args, format); - g_vfprintf (stderr, format, args); - va_end (args); - fputs ("\n", stderr); - abort(); - _exit (1); -} - -struct fpi_usb_transfer { - struct libusb_transfer *transfer; - fpi_ssm *ssm; - struct fp_dev *dev; - fpi_usb_transfer_cb_fn callback; - void *user_data; -}; - -/** - * fpi_usb_alloc: - * - * Returns a struct libusb_transfer, similar to calling - * `libusb_alloc_transfer(0)`[[1](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga13cc69ea40c702181c430c950121c000)]. As libfprint uses GLib internally, - * and [memory allocation failures will make applications fail](https://developer.gnome.org/glib/stable/glib-Memory-Allocation.html#glib-Memory-Allocation.description), - * this helper will assert when the libusb call fails. - */ -struct libusb_transfer * -fpi_usb_alloc(void) -{ - struct libusb_transfer *transfer; - - transfer = libusb_alloc_transfer(0); - mem_assert(transfer); - - return transfer; -} - -static fpi_usb_transfer * -fpi_usb_transfer_new(struct fp_dev *dev, - fpi_ssm *ssm, - fpi_usb_transfer_cb_fn callback, - void *user_data) -{ - fpi_usb_transfer *transfer; - - transfer = g_new0(fpi_usb_transfer, 1); - transfer->transfer = fpi_usb_alloc(); - transfer->dev = dev; - transfer->ssm = ssm; - transfer->callback = callback; - transfer->user_data = user_data; - - return transfer; -} - -void -fpi_usb_transfer_free(fpi_usb_transfer *transfer) -{ - if (transfer == NULL) - return; - - g_free(transfer->transfer->buffer); - libusb_free_transfer(transfer->transfer); - g_free(transfer); -} - -static void -fpi_usb_transfer_cb (struct libusb_transfer *transfer) -{ - fpi_usb_transfer *t; - - g_assert(transfer); - g_assert(transfer->user_data); - - t = transfer->user_data; - BUG_ON(transfer->callback == NULL); - (t->callback) (transfer, t->dev, t->ssm, t->user_data); - fpi_usb_transfer_free(t); -} - -/** - * fpi_usb_fill_bulk_transfer: - * @dev: a struct #fp_dev fingerprint device - * @ssm: the current #fpi_ssm state machine - * @endpoint: the USB end point - * @buffer: a buffer allocated with g_malloc() or another GLib function. - * Note that the returned #fpi_usb_transfer will own this buffer, so it - * should not be freed manually. - * @length: the size of @buffer - * @callback: the callback function that will be called once the fpi_usb_submit_transfer() - * call finishes. - * @user_data: a user data pointer to pass to the callback - * @timeout: timeout for the transfer in milliseconds, or 0 for no timeout - * - * This function is similar to calling [`libusb_alloc_transfer(0)`](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga13cc69ea40c702181c430c950121c000)] - * followed by calling [`libusb_fill_bulk_transfer()`](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#gad4ddb1a5c6c7fefc979a44d7300b95d7). - * The #fpi_usb_transfer_cb_fn callback will however provide more arguments - * relevant to libfprint drivers, making it a good replacement for the raw libusb - * calls. - * - * Returns: a #fpi_usb_transfer transfer struct, to be passed to - * fpi_usb_submit_transfer(). - */ -fpi_usb_transfer * -fpi_usb_fill_bulk_transfer (struct fp_dev *dev, - fpi_ssm *ssm, - unsigned char endpoint, - unsigned char *buffer, - int length, - fpi_usb_transfer_cb_fn callback, - void *user_data, - unsigned int timeout) -{ - fpi_usb_transfer *transfer; - - g_return_val_if_fail (dev != NULL, NULL); - g_return_val_if_fail (callback != NULL, NULL); - - transfer = fpi_usb_transfer_new(dev, - ssm, - callback, - user_data); - - libusb_fill_bulk_transfer(transfer->transfer, - fpi_dev_get_usb_dev(dev), - endpoint, - buffer, - length, - fpi_usb_transfer_cb, - transfer, - timeout); - - return transfer; -} - -/** - * fpi_usb_submit_transfer: - * @transfer: a #fpi_usb_transfer struct - * - * Start a transfer to the device with the provided #fpi_usb_transfer. - * On error, the #fpi_usb_transfer struct will be freed, otherwise it will - * be freed once the callback provided to fpi_usb_fill_bulk_transfer() has - * been called. - * - * Returns: 0 on success, or the same errors as [libusb_submit_transfer](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#gabb0932601f2c7dad2fee4b27962848ce) - * on failure. - */ -int -fpi_usb_submit_transfer(fpi_usb_transfer *transfer) -{ - int r; - - g_return_val_if_fail (transfer != NULL, LIBUSB_ERROR_INVALID_PARAM); - - r = libusb_submit_transfer(transfer->transfer); - if (r < 0) - fpi_usb_transfer_free(transfer); - - return r; -} - -/** - * fpi_usb_cancel_transfer: - * @transfer: a #fpi_usb_transfer struct - * - * Cancel a transfer to the device with the provided #fpi_usb_transfer. - * Note that this will not complete the cancellation, as your transfer - * callback will be called with the `LIBUSB_TRANSFER_CANCELLED` status, - * as [libusb_cancel_transfer](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga685eb7731f9a0593f75beb99727bbe54) - * would. - * - * You should not access anything but the given struct #libusb_transfer - * in the callback before checking whether `LIBUSB_TRANSFER_CANCELLED` has - * been called, as that might cause memory access violations. - * - * Returns: 0 on success, or the same errors as [libusb_cancel_transfer](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#ga685eb7731f9a0593f75beb99727bbe54) - * on failure. - */ -int -fpi_usb_cancel_transfer(fpi_usb_transfer *transfer) -{ - g_return_val_if_fail (transfer != NULL, LIBUSB_ERROR_NOT_FOUND); - - return libusb_cancel_transfer(transfer->transfer); -} diff --git a/libfprint/fpi-usb.h b/libfprint/fpi-usb.h deleted file mode 100644 index 822b6124..00000000 --- a/libfprint/fpi-usb.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2018 Bastien Nocera - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __FPI_USB_H__ -#define __FPI_USB_H__ - -#include -#include "fpi-dev.h" -#include "fpi-ssm.h" - -/** - * fpi_usb_transfer: - * - * A structure containing the arguments passed to fpi_usb_fill_bulk_transfer() - * to be used with fpi_usb_submit_transfer(). - */ -typedef struct fpi_usb_transfer fpi_usb_transfer; - -/** - * fpi_usb_transfer_cb_fn: - * @transfer: a struct #libusb_transfer - * @dev: the struct #fp_dev on which the operation was performed - * @ssm: the #fpi_ssm state machine - * @user_data: the user data passed to fpi_usb_fill_bulk_transfer() - * - * This callback will be called in response to a libusb bulk transfer - * triggered via fpi_usb_fill_bulk_transfer() finishing. Note that the - * struct #libusb_transfer does not need to be freed, as it will be - * freed after the callback returns, similarly to - * the [LIBUSB_TRANSFER_FREE_TRANSFER flag](http://libusb.sourceforge.net/api-1.0/group__asyncio.html#gga1fb47dd0f7c209b60a3609ff0c03d56dacf3f064997b283a14097c9f4d6f8ccc1). - * - * Note that the cancelled status of the transfer should be checked - * first thing, as the @dev, @ssm and @user_data pointers might not - * be pointing to valid values anymore. See fpi_usb_cancel_transfer() - * for more information. - */ -typedef void(*fpi_usb_transfer_cb_fn) (struct libusb_transfer *transfer, - struct fp_dev *dev, - fpi_ssm *ssm, - void *user_data); - -struct libusb_transfer *fpi_usb_alloc(void) __attribute__((returns_nonnull)); - -fpi_usb_transfer *fpi_usb_fill_bulk_transfer (struct fp_dev *dev, - fpi_ssm *ssm, - unsigned char endpoint, - unsigned char *buffer, - int length, - fpi_usb_transfer_cb_fn callback, - void *user_data, - unsigned int timeout); -int fpi_usb_submit_transfer (fpi_usb_transfer *transfer); -int fpi_usb_cancel_transfer (fpi_usb_transfer *transfer); - -#endif diff --git a/libfprint/fprint-list-supported-devices.c b/libfprint/fprint-list-supported-devices.c index ed49ee69..23096ea5 100644 --- a/libfprint/fprint-list-supported-devices.c +++ b/libfprint/fprint-list-supported-devices.c @@ -2,6 +2,7 @@ * Copyright (C) 2009 Red Hat * Copyright (C) 2008 Bastien Nocera * Copyright (C) 2008 Timo Hoenig , + * Coypright (C) 2019 Benjamin Berg * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,28 +23,47 @@ #include #include -#include "fp_internal.h" +#include "fpi-context.h" +#include "fpi-device.h" GHashTable *printed = NULL; -static GList *insert_driver (GList *list, - struct fp_driver *driver) +static GList *insert_drivers (GList *list) { - int i; + g_autoptr(GArray) drivers = g_array_new (FALSE, FALSE, sizeof(GType)); + gint i; - for (i = 0; driver->id_table[i].vendor != 0; i++) { - char *key; + fpi_get_driver_types (drivers); - key = g_strdup_printf ("%04x:%04x", driver->id_table[i].vendor, driver->id_table[i].product); + /* Find the best driver to handle this USB device. */ + for (i = 0; i < drivers->len; i++) + { + GType driver = g_array_index (drivers, GType, i); + FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver)); + const FpIdEntry *entry; - if (g_hash_table_lookup (printed, key) != NULL) { + if (cls->type != FP_DEVICE_TYPE_USB) { + g_type_class_unref (cls); + continue; + } + + for (entry = cls->id_table; entry->vid; entry++) + { + char *key; + + key = g_strdup_printf ("%04x:%04x", entry->vid, entry->pid); + + if (g_hash_table_lookup (printed, key) != NULL) { g_free (key); continue; - } + } - g_hash_table_insert (printed, key, GINT_TO_POINTER (1)); + g_hash_table_insert (printed, key, GINT_TO_POINTER (1)); - list = g_list_prepend (list, g_strdup_printf ("%s | %s\n", key, driver->full_name)); + list = g_list_prepend (list, g_strdup_printf ("%s | %s\n", key, cls->full_name)); + } + + g_type_class_unref (cls); } return list; @@ -51,14 +71,10 @@ static GList *insert_driver (GList *list, int main (int argc, char **argv) { - struct fp_driver **driver_list; - guint i; GList *list, *l; setlocale (LC_ALL, ""); - driver_list = fprint_get_drivers (); - printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); g_print ("%% lifprint — Supported Devices\n"); @@ -76,8 +92,7 @@ int main (int argc, char **argv) g_print ("------------ | ------------\n"); list = NULL; - for (i = 0; driver_list[i] != NULL; i++) - list = insert_driver (list, driver_list[i]); + list = insert_drivers (list); list = g_list_sort (list, (GCompareFunc) g_strcmp0); for (l = list; l != NULL; l = l->next) diff --git a/libfprint/fprint-list-udev-rules.c b/libfprint/fprint-list-udev-rules.c index de291f11..76f84867 100644 --- a/libfprint/fprint-list-udev-rules.c +++ b/libfprint/fprint-list-udev-rules.c @@ -2,6 +2,7 @@ * Copyright (C) 2009 Red Hat * Copyright (C) 2008 Bastien Nocera * Copyright (C) 2008 Timo Hoenig , + * Coypright (C) 2019 Benjamin Berg * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,54 +20,55 @@ */ #include -#include -#include "fp_internal.h" +#include "fpi-context.h" +#include "fpi-device.h" -static const struct usb_id whitelist_id_table[] = { +static const FpIdEntry whitelist_id_table[] = { /* Unsupported (for now) Validity Sensors finger print readers */ - { .vendor = 0x138a, .product = 0x0090 }, /* Found on e.g. Lenovo T460s */ - { .vendor = 0x138a, .product = 0x0091 }, - { .vendor = 0x138a, .product = 0x0094 }, - { .vendor = 0x138a, .product = 0x0097 }, /* Found on e.g. Lenovo T470s */ - { 0, 0, 0, }, + { .vid = 0x138a, .pid = 0x0090 }, /* Found on e.g. Lenovo T460s */ + { .vid = 0x138a, .pid = 0x0091 }, + { .vid = 0x138a, .pid = 0x0094 }, + { .vid = 0x138a, .pid = 0x0097 }, /* Found on e.g. Lenovo T470s */ + { .vid = 0 }, }; -static const struct usb_id blacklist_id_table[] = { - { .vendor = 0x0483, .product = 0x2016 }, +static const FpIdEntry blacklist_id_table[] = { + { .vid = 0x0483, .pid = 0x2016 }, /* https://bugs.freedesktop.org/show_bug.cgi?id=66659 */ - { .vendor = 0x045e, .product = 0x00bb }, - { 0, 0, 0 }, + { .vid = 0x045e, .pid = 0x00bb }, + { .vid = 0 }, }; -struct fp_driver whitelist = { +static const FpDeviceClass whitelist = { + .type = FP_DEVICE_TYPE_USB, .id_table = whitelist_id_table, .full_name = "Hardcoded whitelist" }; GHashTable *printed = NULL; -static void print_driver (struct fp_driver *driver) +static void print_driver (const FpDeviceClass *cls) { - int i, j, blacklist, num_printed; + const FpIdEntry *entry; + gint num_printed = 0; - num_printed = 0; + if (cls->type != FP_DEVICE_TYPE_USB) + return; - for (i = 0; driver->id_table[i].vendor != 0; i++) { + for (entry = cls->id_table; entry->vid != 0; entry++) { + const FpIdEntry *bl_entry; char *key; - blacklist = 0; - for (j = 0; blacklist_id_table[j].vendor != 0; j++) { - if (driver->id_table[i].vendor == blacklist_id_table[j].vendor && - driver->id_table[i].product == blacklist_id_table[j].product) { - blacklist = 1; + for (bl_entry = blacklist_id_table; bl_entry->vid != 0; bl_entry++) { + if (entry->vid == bl_entry->vid && entry->pid == bl_entry->pid) { break; } } - if (blacklist) + if (bl_entry->vid != 0) continue; - key = g_strdup_printf ("%04x:%04x", driver->id_table[i].vendor, driver->id_table[i].product); + key = g_strdup_printf ("%04x:%04x", entry->vid, entry->pid); if (g_hash_table_lookup (printed, key) != NULL) { g_free (key); @@ -76,28 +78,42 @@ static void print_driver (struct fp_driver *driver) g_hash_table_insert (printed, key, GINT_TO_POINTER (1)); if (num_printed == 0) - printf ("# %s\n", driver->full_name); + g_print ("# %s\n", cls->full_name); - printf ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ATTRS{dev}==\"*\", TEST==\"power/control\", ATTR{power/control}=\"auto\"\n", driver->id_table[i].vendor, driver->id_table[i].product); - printf ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ENV{LIBFPRINT_DRIVER}=\"%s\"\n", driver->id_table[i].vendor, driver->id_table[i].product, driver->full_name); + g_print ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ATTRS{dev}==\"*\", TEST==\"power/control\", ATTR{power/control}=\"auto\"\n", + entry->vid, entry->pid); + g_print ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ENV{LIBFPRINT_DRIVER}=\"%s\"\n", + entry->vid, entry->pid, cls->full_name); num_printed++; } if (num_printed > 0) - printf ("\n"); + g_print ("\n"); } int main (int argc, char **argv) { - struct fp_driver **list; + g_autoptr(GArray) drivers = g_array_new (FALSE, FALSE, sizeof(GType)); guint i; - list = fprint_get_drivers (); + g_print ("%p\n", drivers); + g_print ("%p\n", fpi_get_driver_types); + fpi_get_driver_types (drivers); printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - for (i = 0; list[i] != NULL; i++) { - print_driver (list[i]); + for (i = 0; i < drivers->len; i++) { + GType driver = g_array_index (drivers, GType, i); + FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver)); + + if (cls->type != FP_DEVICE_TYPE_USB) { + g_type_class_unref (cls); + continue; + } + + print_driver (cls); + + g_type_class_unref (cls); } print_driver (&whitelist); diff --git a/libfprint/fprint.h b/libfprint/fprint.h index c7e81b45..a4729ea9 100644 --- a/libfprint/fprint.h +++ b/libfprint/fprint.h @@ -1,6 +1,6 @@ /* * Main definitions for libfprint - * Copyright (C) 2007 Daniel Drake + * Copyright (C) 2019 Benjamin Berg * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,411 +17,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __FPRINT_H__ -#define __FPRINT_H__ +#pragma once -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include - -/** - * LIBFPRINT_DEPRECATED: - * - * Expands to the GNU C deprecated attribute if the compiler is `gcc`. When - * called with the `-Wdeprecated-declarations` option, `gcc` will generate warnings - * when deprecated interfaces are used. - */ -#define LIBFPRINT_DEPRECATED __attribute__((__deprecated__)) - -/** - * fp_dscv_dev: - * - * #fp_dscv_dev is an opaque structure type. You must access it using the - * functions in this section. - */ -struct fp_dscv_dev; - -/** - * fp_dev: - * - * #fp_dev is an opaque structure type. You must access it using the - * functions in this section. - */ -struct fp_dev; - -/** - * fp_driver: - * - * #fp_driver is an opaque structure type. You must access it using the - * functions in this section. - */ -struct fp_driver; - -/** - * fp_print_data: - * - * #fp_print_data is an opaque structure type. You must access it using the - * functions in this section. - */ -struct fp_print_data; - -/** - * fp_img: - * - * #fp_img is an opaque structure type. You must access it using the - * functions in this section. - */ -struct fp_img; - -/* misc/general stuff */ - -/** - * fp_finger: - * @LEFT_THUMB: Left thumb - * @LEFT_INDEX: Left index finger - * @LEFT_MIDDLE: Left middle finger - * @LEFT_RING: Left ring finger - * @LEFT_LITTLE: Left little finger - * @RIGHT_THUMB: Right thumb - * @RIGHT_INDEX: Right index finger - * @RIGHT_MIDDLE: Right middle finger - * @RIGHT_RING: Right ring finger - * @RIGHT_LITTLE: Right little finger - * - * Numeric codes used to refer to fingers (and thumbs) of a human. These are - * purposely not available as strings, to avoid getting the library tangled up - * in localization efforts. - */ -enum fp_finger { - LEFT_THUMB = 1, - LEFT_INDEX, - LEFT_MIDDLE, - LEFT_RING, - LEFT_LITTLE, - RIGHT_THUMB, - RIGHT_INDEX, - RIGHT_MIDDLE, - RIGHT_RING, - RIGHT_LITTLE, -}; - -/** - * fp_scan_type: - * @FP_SCAN_TYPE_PRESS: the reader has a surface area that covers the whole finger - * @FP_SCAN_TYPE_SWIPE: the reader requires swiping the finger on a smaller area - * - * Numeric codes used to refer to the scan type of the device. Devices require - * either swiping or pressing the finger on the device. This is useful for - * front-ends. - */ -enum fp_scan_type { - FP_SCAN_TYPE_PRESS = 0, - FP_SCAN_TYPE_SWIPE, -}; - -/* Drivers */ -const char *fp_driver_get_name(struct fp_driver *drv); -const char *fp_driver_get_full_name(struct fp_driver *drv); -uint16_t fp_driver_get_driver_id(struct fp_driver *drv); -enum fp_scan_type fp_driver_get_scan_type(struct fp_driver *drv); -int fp_driver_supports_imaging(struct fp_driver *drv); - -/* Device discovery */ -struct fp_dscv_dev **fp_discover_devs(void); -void fp_dscv_devs_free(struct fp_dscv_dev **devs); -struct fp_driver *fp_dscv_dev_get_driver(struct fp_dscv_dev *dev); -uint16_t fp_dscv_dev_get_driver_id(struct fp_dscv_dev *dev); -uint32_t fp_dscv_dev_get_devtype(struct fp_dscv_dev *dev); -int fp_dscv_dev_supports_print_data(struct fp_dscv_dev *dev, - struct fp_print_data *print); - -/* Device handling */ -struct fp_dev *fp_dev_open(struct fp_dscv_dev *ddev); -void fp_dev_close(struct fp_dev *dev); -struct fp_driver *fp_dev_get_driver(struct fp_dev *dev); -int fp_dev_get_nr_enroll_stages(struct fp_dev *dev); -uint32_t fp_dev_get_devtype(struct fp_dev *dev); -int fp_dev_supports_print_data(struct fp_dev *dev, struct fp_print_data *data); - -/** - * fp_capture_result: - * @FP_CAPTURE_COMPLETE: Capture completed successfully, the capture data has been returned to the caller. - * @FP_CAPTURE_FAIL: Capture failed - * - * Whether a capture failed or completed. - */ -enum fp_capture_result { - FP_CAPTURE_COMPLETE = 0, - FP_CAPTURE_FAIL, -}; - -int fp_dev_supports_imaging(struct fp_dev *dev); -int fp_dev_img_capture(struct fp_dev *dev, int unconditional, - struct fp_img **img); -int fp_dev_get_img_width(struct fp_dev *dev); -int fp_dev_get_img_height(struct fp_dev *dev); - -/** - * fp_enroll_result: - * @FP_ENROLL_COMPLETE: Enrollment completed successfully, the enrollment data has been - * returned to the caller. - * @FP_ENROLL_FAIL: Enrollment failed due to incomprehensible data; this may occur when - * the user scans a different finger on each enroll stage. - * @FP_ENROLL_PASS: Enroll stage passed; more stages are need to complete the process. - * @FP_ENROLL_RETRY: The enrollment scan did not succeed due to poor scan quality or - * other general user scanning problem. - * @FP_ENROLL_RETRY_TOO_SHORT: The enrollment scan did not succeed because the finger swipe was - * too short. - * @FP_ENROLL_RETRY_CENTER_FINGER: The enrollment scan did not succeed because the finger was not - * centered on the scanner. - * @FP_ENROLL_RETRY_REMOVE_FINGER: The verification scan did not succeed due to quality or pressure - * problems; the user should remove their finger from the scanner before - * retrying. - * - * - * Enrollment result codes returned from fp_enroll_finger(). - * Result codes with RETRY in the name suggest that the scan failed due to - * user error. Applications will generally want to inform the user of the - * problem and then retry the enrollment stage. For more info on the semantics - * of interpreting these result codes and tracking enrollment process, see - * [Enrolling](libfprint-Devices-operations.html#enrolling) - */ -enum fp_enroll_result { - FP_ENROLL_COMPLETE = 1, - FP_ENROLL_FAIL, - FP_ENROLL_PASS, - FP_ENROLL_RETRY = 100, - FP_ENROLL_RETRY_TOO_SHORT, - FP_ENROLL_RETRY_CENTER_FINGER, - FP_ENROLL_RETRY_REMOVE_FINGER, -}; - -int fp_enroll_finger_img(struct fp_dev *dev, struct fp_print_data **print_data, - struct fp_img **img); -int fp_enroll_finger(struct fp_dev *dev, - struct fp_print_data **print_data); - -/** - * fp_verify_result: - * @FP_VERIFY_NO_MATCH: The scan completed successfully, but the newly scanned fingerprint - * does not match the fingerprint being verified against. - * In the case of identification, this return code indicates that the - * scanned finger could not be found in the print gallery. - * @FP_VERIFY_MATCH: The scan completed successfully and the newly scanned fingerprint does - * match the fingerprint being verified, or in the case of identification, - * the scanned fingerprint was found in the print gallery. - * @FP_VERIFY_RETRY: The scan did not succeed due to poor scan quality or other general - * user scanning problem. - * @FP_VERIFY_RETRY_TOO_SHORT: The scan did not succeed because the finger swipe was too short. - * @FP_VERIFY_RETRY_CENTER_FINGER: The scan did not succeed because the finger was not centered on the - * scanner. - * @FP_VERIFY_RETRY_REMOVE_FINGER: The scan did not succeed due to quality or pressure problems; the user - * should remove their finger from the scanner before retrying. - * - * Verification result codes returned from fp_verify_finger(). Return codes - * are also shared with fp_identify_finger(). - * Result codes with RETRY in the name suggest that the scan failed due to - * user error. Applications will generally want to inform the user of the - * problem and then retry the verify operation. - */ -enum fp_verify_result { - FP_VERIFY_NO_MATCH = 0, - FP_VERIFY_MATCH = 1, - FP_VERIFY_RETRY = FP_ENROLL_RETRY, - FP_VERIFY_RETRY_TOO_SHORT = FP_ENROLL_RETRY_TOO_SHORT, - FP_VERIFY_RETRY_CENTER_FINGER = FP_ENROLL_RETRY_CENTER_FINGER, - FP_VERIFY_RETRY_REMOVE_FINGER = FP_ENROLL_RETRY_REMOVE_FINGER, -}; - -int fp_verify_finger_img(struct fp_dev *dev, - struct fp_print_data *enrolled_print, struct fp_img **img); -int fp_verify_finger(struct fp_dev *dev, - struct fp_print_data *enrolled_print); - -int fp_dev_supports_identification(struct fp_dev *dev); -int fp_identify_finger_img(struct fp_dev *dev, - struct fp_print_data **print_gallery, size_t *match_offset, - struct fp_img **img); -int fp_identify_finger(struct fp_dev *dev, - struct fp_print_data **print_gallery, size_t *match_offset); - -/* Data handling */ -void fp_print_data_free(struct fp_print_data *data); -size_t fp_print_data_get_data(struct fp_print_data *data, unsigned char **ret); -struct fp_print_data *fp_print_data_from_data(unsigned char *buf, - size_t buflen); -uint16_t fp_print_data_get_driver_id(struct fp_print_data *data); -uint32_t fp_print_data_get_devtype(struct fp_print_data *data); - -/* Image handling */ - -/** - * fp_minutia: - * - * #fp_minutia is an opaque structure type. You must access it using the - * functions in this section. - */ -struct fp_minutia; - -int fp_img_get_height(struct fp_img *img); -int fp_img_get_width(struct fp_img *img); -unsigned char *fp_img_get_data(struct fp_img *img); -int fp_img_save_to_file(struct fp_img *img, char *path); -void fp_img_standardize(struct fp_img *img); -struct fp_img *fp_img_binarize(struct fp_img *img); -struct fp_minutia **fp_img_get_minutiae(struct fp_img *img, int *nr_minutiae); -int fp_minutia_get_coords(struct fp_minutia *minutia, int *coord_x, int *coord_y); -void fp_img_free(struct fp_img *img); - -/* Polling and timing */ - -/** - * fp_pollfd: - * @fd: a file descriptor - * @events: Event flags to poll for from `` - * - * A structure representing a file descriptor and the @events to poll - * for, as returned by fp_get_pollfds(). - */ -struct fp_pollfd { - int fd; - short int events; -}; - -int fp_handle_events_timeout(struct timeval *timeout); -int fp_handle_events(void); -ssize_t fp_get_pollfds(struct fp_pollfd **pollfds); -int fp_get_next_timeout(struct timeval *tv); - -/** - * fp_pollfd_added_cb: - * @fd: the new file descriptor - * @events: events to monitor for, see `` for the possible values - * - * Type definition for a function that will be called when a new - * event source is added. The @events argument is a flag as defined in - * `` such as `POLLIN`, or `POLLOUT`. See fp_set_pollfd_notifiers(). - */ -typedef void (*fp_pollfd_added_cb)(int fd, short int events); - -/** - * fp_pollfd_removed_cb: - * @fd: the file descriptor to stop monitoring - * - * Type definition for a function that will be called when an - * event source is removed. See fp_set_pollfd_notifiers(). - */ -typedef void (*fp_pollfd_removed_cb)(int fd); -void fp_set_pollfd_notifiers(fp_pollfd_added_cb added_cb, - fp_pollfd_removed_cb removed_cb); - -/* Library */ -int fp_init(void); -void fp_exit(void); - -/* Asynchronous I/O */ - -/** - * fp_operation_stop_cb: - * @dev: the struct #fp_dev device - * @user_data: user data passed to the callback - * - * Type definition for a function that will be called when fp_async_dev_close(), - * fp_async_verify_stop(), fp_async_identify_stop() or fp_async_capture_stop() - * finishes. - */ -typedef void (*fp_operation_stop_cb)(struct fp_dev *dev, void *user_data); - -/** - * fp_img_operation_cb: - * @dev: the struct #fp_dev device - * @result: an #fp_verify_result for fp_async_verify_start(), or an #fp_capture_result - * for fp_async_capture_start(), or a negative value on error - * @img: the captured #fp_img if capture or verification was successful - * @user_data: user data passed to the callback - * - * Type definition for a function that will be called when fp_async_verify_start() - * or fp_async_capture_start() finished. - */ -typedef void (*fp_img_operation_cb)(struct fp_dev *dev, int result, - struct fp_img *img, void *user_data); - -/** - * fp_dev_open_cb: - * @dev: the struct #fp_dev device - * @status: 0 on success, or a negative value on error - * @user_data: user data passed to the callback - * - * Type definition for a function that will be called when fp_async_dev_open - * finishes. - */ -typedef void (*fp_dev_open_cb)(struct fp_dev *dev, int status, void *user_data); - -int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb callback, - void *user_data); - -void fp_async_dev_close(struct fp_dev *dev, fp_operation_stop_cb callback, - void *user_data); - -/** - * fp_enroll_stage_cb: - * @dev: the struct #fp_dev device - * @result: a #fp_enroll_result on success, or a negative value on failure - * @print: the enrollment data from the final stage - * @img: an #fp_img to free with fp_img_free() - * @user_data: user data passed to the callback - * - * Type definition for a function that will be called when - * fp_async_enroll_start() finishes. See fp_enroll_finger_img() for - * the expected behaviour of your program based on the @result. - */ -typedef void (*fp_enroll_stage_cb)(struct fp_dev *dev, int result, - struct fp_print_data *print, struct fp_img *img, void *user_data); - -int fp_async_enroll_start(struct fp_dev *dev, fp_enroll_stage_cb callback, - void *user_data); - -int fp_async_enroll_stop(struct fp_dev *dev, fp_operation_stop_cb callback, - void *user_data); - -int fp_async_verify_start(struct fp_dev *dev, struct fp_print_data *data, - fp_img_operation_cb callback, void *user_data); - -int fp_async_verify_stop(struct fp_dev *dev, fp_operation_stop_cb callback, - void *user_data); - -/** - * fp_identify_cb: - * @dev: the struct #fp_dev device - * @result: a #fp_verify_result on success, or a negative value on error. - * @match_offset: the array index of the matched gallery print (if any was found). - * Only valid if %FP_VERIFY_MATCH was returned. - * @img: the scan image, it must be freed with fp_img_free() after use. - * @user_data: user data passed to the callback - * - * Type definition for a function that will be called when fp_async_identify_start() - * finishes. - */ -typedef void (*fp_identify_cb)(struct fp_dev *dev, int result, - size_t match_offset, struct fp_img *img, void *user_data); -int fp_async_identify_start(struct fp_dev *dev, struct fp_print_data **gallery, - fp_identify_cb callback, void *user_data); - -int fp_async_identify_stop(struct fp_dev *dev, fp_operation_stop_cb callback, - void *user_data); - -int fp_async_capture_start(struct fp_dev *dev, int unconditional, fp_img_operation_cb callback, void *user_data); - -int fp_async_capture_stop(struct fp_dev *dev, fp_operation_stop_cb callback, void *user_data); - -#ifdef __cplusplus -} -#endif - -#endif +#include "fp-context.h" +#include "fp-device.h" +#include "fp-image.h" diff --git a/libfprint/libfprint.ver b/libfprint/libfprint.ver index d99a456a..7b484f6a 100644 --- a/libfprint/libfprint.ver +++ b/libfprint/libfprint.ver @@ -1,6 +1,9 @@ LIBFPRINT_2.0.0 { global: fp_*; + + /* Needs to be public for the listing commands. */ + fpi_get_driver_types; local: *; }; diff --git a/libfprint/meson.build b/libfprint/meson.build index 57264c03..96cf85ad 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -1,15 +1,27 @@ libfprint_sources = [ - 'fpi-async.c', + 'fp-context.c', + 'fp-device.c', + 'fp-image.c', + 'fp-print.c', + 'fp-image-device.c', 'fpi-assembling.c', - 'fpi-core.c', - 'fpi-data.c', - 'fpi-dev.c', - 'fpi-dev-img.c', - 'fpi-img.c', 'fpi-ssm.c', - 'fpi-sync.c', - 'fpi-poll.c', - 'fpi-usb.c', + 'fpi-usb-transfer.c', +] + +libfprint_public_headers = [ + 'fp-context.h', + 'fp-device.h', + 'fp-image.h', + 'fp-print.h', +] + +libfprint_private_headers = [ + 'fpi-assembling.h', + 'fpi-device.h', + 'fpi-image.h', + 'fpi-image-device.h', + 'fpi-print.h', ] nbis_sources = [ @@ -134,29 +146,32 @@ if aes3k endif other_sources = [] -if imaging_dep.found() - other_sources += [ 'fpi-img-pixman.c' ] -endif -libfprint_sources += configure_file(input: 'empty_file', - output: 'drivers_definitions.h', - capture: true, - command: [ - 'echo', - drivers_struct_list - ]) +fp_enums = gnome.mkenums_simple('fp-enums', + sources: libfprint_public_headers, + install_header : true) +fp_enums_h = fp_enums[1] -libfprint_sources += configure_file(input: 'empty_file', - output: 'drivers_arrays.h', - capture: true, - command: [ - 'echo', - drivers_primitive_array + '\n\n' + drivers_img_array - ]) +fpi_enums = gnome.mkenums_simple('fpi-enums', + sources: libfprint_private_headers, + install_header : true) +fpi_enums_h = fpi_enums[1] -deps = [ mathlib_dep, glib_dep, gusb_dep, nss_dep, imaging_dep ] +drivers_sources += configure_file(input: 'empty_file', + output: 'fp-drivers.c', + capture: true, + command: [ + 'echo', + drivers_type_list + '\n\n' + drivers_type_func + ]) + +mapfile = 'libfprint.ver' +vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile) + +deps = [ mathlib_dep, glib_dep, gusb_dep, nss_dep, imaging_dep, gio_dep ] libfprint = library('fprint', - libfprint_sources + drivers_sources + nbis_sources + other_sources, + libfprint_sources + fp_enums + fpi_enums + + drivers_sources + nbis_sources + other_sources, soversion: soversion, version: libversion, c_args: common_cflags + drivers_cflags, @@ -164,14 +179,17 @@ libfprint = library('fprint', root_inc, include_directories('nbis/include'), ], + link_args : vflag, + link_depends : mapfile, dependencies: deps, install: true) libfprint_dep = declare_dependency(link_with: libfprint, + sources: [ fp_enums_h ], include_directories: root_inc, - dependencies: glib_dep) + dependencies: [glib_dep, gusb_dep, gio_dep]) -install_headers(['fprint.h'], subdir: 'libfprint') +install_headers(['fprint.h'] + libfprint_public_headers, subdir: 'libfprint') udev_rules = executable('fprint-list-udev-rules', 'fprint-list-udev-rules.c', @@ -197,3 +215,35 @@ supported_devices = executable('fprint-list-supported-devices', ], dependencies: [ deps, libfprint_dep ], install: false) + + +if get_option('introspection') + # We do *not* include the private header here + libfprint_girtarget = gnome.generate_gir(libfprint, + sources : fp_enums + [ + libfprint_public_headers, + libfprint_sources, + ], + nsversion : '2.0', + namespace : 'FPrint', + symbol_prefix : 'fp_', + identifier_prefix : 'Fp', + export_packages : 'fprint', + extra_args : [ + '--c-include=fprint.h', + ], + link_with : libfprint, + dependencies : [ + gio_dep, + gusb_dep, + ], + includes : [ + 'Gio-2.0', + 'GObject-2.0', + 'GUsb-1.0', + ], + install : true + ) + libfprint_gir = libfprint_girtarget[0] + libfprint_typelib = libfprint_girtarget[1] +endif diff --git a/meson.build b/meson.build index 2f043039..68010aaa 100644 --- a/meson.build +++ b/meson.build @@ -8,6 +8,8 @@ project('libfprint', [ 'c', 'cpp' ], ], meson_version: '>= 0.45.0') +gnome = import('gnome') + add_project_arguments([ '-D_GNU_SOURCE' ], language: 'c') add_project_arguments([ '-DG_LOG_DOMAIN="libfprint"' ], language: 'c') @@ -19,7 +21,6 @@ host_system = host_machine.system() common_cflags = cc.get_supported_arguments([ '-fgnu89-inline', - '-fvisibility=hidden', '-std=gnu99', '-Wall', '-Wundef', @@ -42,6 +43,7 @@ libversion = '@0@.@1@.@2@'.format(soversion, current, revision) # Dependencies glib_dep = dependency('glib-2.0', version: '>= 2.50') +gio_dep = dependency('gio-unix-2.0', version: '>= 2.44.0') gusb_dep = dependency('gusb', version: '>= 0.3.0') mathlib_dep = cc.find_library('m', required: false) @@ -67,6 +69,7 @@ endif nss_dep = dependency('', required: false) imaging_dep = dependency('', required: false) +libfprint_conf.set10('HAVE_PIXMAN', false) foreach driver: drivers if driver == 'uru4000' nss_dep = dependency('nss', required: false) @@ -79,27 +82,23 @@ foreach driver: drivers if not imaging_dep.found() error('pixman is required for imaging support') endif + + libfprint_conf.set10('HAVE_PIXMAN', true) endif if not all_drivers.contains(driver) error('Invalid driver \'' + driver + '\'') endif endforeach -# Export the drivers' structures to the core code -drivers_struct_list = '' -drivers_img_array = 'static struct fp_img_driver * const img_drivers[] = {\n' -drivers_primitive_array = 'static struct fp_driver * const primitive_drivers[] = {\n' +# Export the drivers' types to the core code +drivers_type_list = '#include \n' +drivers_type_func = 'void fpi_get_driver_types(GArray *drivers)\n{\n\tGType t;\n' foreach driver: drivers - if primitive_drivers.contains(driver) - drivers_struct_list += 'extern struct fp_driver ' + driver + '_driver;\n' - drivers_primitive_array += ' &' + driver + '_driver,\n' - else - drivers_struct_list += 'extern struct fp_img_driver ' + driver + '_driver;\n' - drivers_img_array += ' &' + driver + '_driver,\n' - endif + drivers_type_list += 'extern GType (fpi_device_' + driver + '_get_type) (void);\n' + drivers_type_func += ' t = fpi_device_' + driver + '_get_type(); g_array_append_val (drivers, t);\n' endforeach -drivers_img_array += '};' -drivers_primitive_array += '};' +drivers_type_list += '' +drivers_type_func += '};' root_inc = include_directories('.') @@ -129,7 +128,6 @@ if get_option('gtk-examples') endif endif -libfprint_conf.set('API_EXPORTED', '__attribute__((visibility("default")))') configure_file(output: 'config.h', configuration: libfprint_conf) subdir('libfprint') diff --git a/meson_options.txt b/meson_options.txt index 78f16ef5..746efdc7 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -2,6 +2,10 @@ option('drivers', description: 'Drivers to integrate, "default" selects the default set, "all" selects all drivers', type: 'string', value: 'default') +option('introspection', + description: 'Build GObject Introspection repository', + type: 'boolean', + value: true) option('udev_rules', description: 'Whether to create a udev rules file', type: 'boolean', From 2b6f22b84d6229c9a7a336417690d0f21753abac Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 3 Jul 2019 23:31:18 +0200 Subject: [PATCH 16/73] virtual_image: Add new virtual image driver --- libfprint/drivers/virtual-image.c | 300 ++++++++++++++++++++++++++++++ libfprint/meson.build | 3 + meson.build | 2 +- 3 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 libfprint/drivers/virtual-image.c diff --git a/libfprint/drivers/virtual-image.c b/libfprint/drivers/virtual-image.c new file mode 100644 index 00000000..17ebb14f --- /dev/null +++ b/libfprint/drivers/virtual-image.c @@ -0,0 +1,300 @@ +/* + * Virtual driver for image device debugging + * + * Copyright (C) 2019 Benjamin Berg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * This is a virtual driver to debug the image based drivers. A small + * python script is provided to connect to it via a socket, allowing + * prints to be sent to this device programatically. + * Using this it is possible to test libfprint and fprintd. + */ + +#define FP_COMPONENT "virtual_image" + +#include "fpi-log.h" + +#include "../fpi-image.h" +#include "../fpi-image-device.h" + +#include +#include +#include + +struct _FpDeviceVirtualImage { + FpImageDevice parent; + + GSocketListener *listener; + GSocketConnection *connection; + GCancellable *cancellable; + + gint socket_fd; + gint client_fd; + + FpImage *recv_img; + gint recv_img_hdr[2]; +}; + +G_DECLARE_FINAL_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FPI, DEVICE_VIRTUAL_IMAGE, FpImageDevice) +G_DEFINE_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FP_TYPE_IMAGE_DEVICE) + +static void start_listen (FpDeviceVirtualImage *dev); +static void recv_image (FpDeviceVirtualImage *dev, GInputStream *stream); + +static void +recv_image_img_recv_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GError) error = NULL; + FpDeviceVirtualImage *self; + FpImageDevice *device; + gssize bytes; + + bytes = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error); + + if (bytes <= 0) { + if (bytes < 0) { + g_warning ("Error receiving header for image data: %s", error->message); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + } + + self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); + g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); + self->connection = NULL; + return; + } + + self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); + device = FP_IMAGE_DEVICE (self); + + fpi_image_device_report_finger_status (device, TRUE); + fpi_image_device_image_captured (device, g_steal_pointer (&self->recv_img)); + fpi_image_device_report_finger_status (device, FALSE); + + /* And, listen for more images from the same client. */ + recv_image(self, G_INPUT_STREAM (source_object)); +} + +static void +recv_image_hdr_recv_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(GError) error = NULL; + FpDeviceVirtualImage *self; + gssize bytes; + + bytes = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error); + + if (bytes <= 0) { + if (bytes < 0) { + g_warning ("Error receiving header for image data: %s", error->message); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + } + + self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); + g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); + self->connection = NULL; + return; + } + + self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); + if (self->recv_img_hdr[0] > 5000 || self->recv_img_hdr[1] > 5000) { + g_warning ("Image header suggests an unrealistically large image, disconnecting client."); + g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); + self->connection = NULL; + } + + if (self->recv_img_hdr[0] < 0 || self->recv_img_hdr[1] < 0) { + switch (self->recv_img_hdr[0]) { + case -1: + /* -1 is a retry error, just pass it through */ + fpi_image_device_retry_scan (FP_IMAGE_DEVICE (self), self->recv_img_hdr[1]); + break; + + case -2: + /* -2 is a fatal error, just pass it through*/ + fpi_image_device_session_error (FP_IMAGE_DEVICE (self), + fpi_device_error_new (self->recv_img_hdr[1])); + break; + + default: + /* disconnect client, it didn't play fair */ + g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); + self->connection = NULL; + } + + /* And, listen for more images from the same client. */ + recv_image(self, G_INPUT_STREAM (source_object)); + return; + } + + self->recv_img = fp_image_new (self->recv_img_hdr[0], self->recv_img_hdr[1]); + g_debug ("image data: %p", self->recv_img->data); + g_input_stream_read_async (G_INPUT_STREAM (source_object), + (guint8*)self->recv_img->data, + self->recv_img->width * self->recv_img->height, + G_PRIORITY_DEFAULT, + self->cancellable, + recv_image_img_recv_cb, + self); +} + +static void +recv_image (FpDeviceVirtualImage *dev, GInputStream *stream) +{ + g_input_stream_read_async (stream, + dev->recv_img_hdr, + sizeof(dev->recv_img_hdr), + G_PRIORITY_DEFAULT, + dev->cancellable, + recv_image_hdr_recv_cb, + dev); +} + +static void +new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GError) error = NULL; + GSocketConnection *connection; + GInputStream *stream; + FpDeviceVirtualImage *dev = user_data; + + connection = g_socket_listener_accept_finish (G_SOCKET_LISTENER (source_object), + res, + NULL, + &error); + if (!connection) { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + g_warning ("Error accepting a new connection: %s", error->message); + start_listen(dev); + } + + /* Always further connections (but we disconnect them immediately + * if we already have a connection). */ + start_listen(dev); + if (dev->connection) { + g_io_stream_close (G_IO_STREAM (connection), NULL, NULL); + return; + } + + dev->connection = connection; + stream = g_io_stream_get_input_stream (G_IO_STREAM (connection)); + + recv_image (dev, stream); + + fp_dbg("Got a new connection!"); +} + +static void +start_listen (FpDeviceVirtualImage *dev) +{ + g_socket_listener_accept_async (dev->listener, + dev->cancellable, + new_connection_cb, + dev); +} + +static void +dev_init(FpImageDevice *dev) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GSocketListener) listener = NULL; + FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev); + const char *env; + g_autoptr(GSocketAddress) addr = NULL; + G_DEBUG_HERE(); + + self->client_fd = -1; + + env = fpi_device_get_virtual_env (FP_DEVICE (self)); + + listener = g_socket_listener_new (); + g_socket_listener_set_backlog (listener, 1); + + /* Remove any left over socket. */ + g_unlink (env); + + addr = g_unix_socket_address_new (env); + + if (!g_socket_listener_add_address (listener, + addr, + G_SOCKET_TYPE_STREAM, + G_SOCKET_PROTOCOL_DEFAULT, + NULL, + NULL, + &error)) { + g_warning ("Could not listen on unix socket: %s", error->message); + + fpi_image_device_open_complete (FP_IMAGE_DEVICE (dev), g_steal_pointer (&error)); + + return; + } + + self->listener = g_steal_pointer (&listener); + self->cancellable = g_cancellable_new (); + + start_listen (self); + + fpi_image_device_open_complete (dev, NULL); +} + +static void dev_deinit(FpImageDevice *dev) +{ + FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev); + + G_DEBUG_HERE(); + + g_cancellable_cancel (self->cancellable); + g_clear_object (&self->cancellable); + g_clear_object (&self->listener); + g_clear_object (&self->connection); + + fpi_image_device_close_complete(dev, NULL); +} + +static void +fpi_device_virtual_image_init (FpDeviceVirtualImage *self) +{ +} + +static const FpIdEntry driver_ids[] = { + { .virtual_envvar = "FP_VIRTUAL_IMAGE" }, + { .virtual_envvar = NULL } +}; + +static void +fpi_device_virtual_image_class_init (FpDeviceVirtualImageClass *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); + + dev_class->id = FP_COMPONENT; + dev_class->full_name = "Virtual image device for debugging"; + dev_class->type = FP_DEVICE_TYPE_VIRTUAL; + dev_class->id_table = driver_ids; + + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; +} + diff --git a/libfprint/meson.build b/libfprint/meson.build index 96cf85ad..6e4eb796 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -133,6 +133,9 @@ foreach driver: drivers if driver == 'elan' drivers_sources += [ 'drivers/elan.c' ] endif + if driver == 'virtual_image' + drivers_sources += [ 'drivers/virtual-image.c' ] + endif endforeach if aeslib diff --git a/meson.build b/meson.build index 68010aaa..de73d6d0 100644 --- a/meson.build +++ b/meson.build @@ -49,7 +49,7 @@ mathlib_dep = cc.find_library('m', required: false) # Drivers drivers = get_option('drivers').split(',') -virtual_drivers = [ ] +virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] default_drivers = [ ] From dd40aeaa7987a783eb8634cfe75ef640443cf91f Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 10 Jun 2019 16:56:57 +0200 Subject: [PATCH 17/73] examples: Add sendvirtimg.py script to send a print to virtual_imgdev With this script it is possible to test libfprint/fprintd without any hardware device. The image needs to be provides as a PNG with the alpha channel storing the print data. See the comment in the file on how the script can be used. --- examples/sendvirtimg.py | 111 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100755 examples/sendvirtimg.py diff --git a/examples/sendvirtimg.py b/examples/sendvirtimg.py new file mode 100755 index 00000000..eb5263be --- /dev/null +++ b/examples/sendvirtimg.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 + +# This script can be used together with the virtual_imgdev to simulate an +# image based fingerprint reader. +# +# To use, set the FP_VIRTUAL_IMAGE environment variable for both the +# libfprint using program (e.g. fprintd) and this script. +# +# Usually this would work by adding it into the systemd unit file. The +# best way of doing so is to create +# /etc/systemd/system/fprintd.service.d/fprintd-test.conf +# +# [Service] +# RuntimeDirectory=fprint +# Environment=FP_VIRTUAL_IMAGE=/run/fprint/virtimg_sock +# Environment=G_MESSAGES_DEBUG=all +# ReadWritePaths=$RUNTIME_DIR +# +# After that run: +# +# systemctl daemon-reload +# systemctl restart fprintd.service +# +# You may also need to disable selinux. +# +# Then run this script with e.g. +# FP_VIRTUAL_IMAGE=/run/fprint/virtimg_sock ./sendvirtimg.py prints/whorl.png + + + +import cairo +import sys +import os +import socket +import struct + +if len(sys.argv) != 2: + sys.stderr.write('You need to pass a PNG with an alpha channel!\n') + sys.exit(1) + +# Just copied from the C file, we could also use the introspection data for +# this. Also, most of them do *not* make any sense. +commands = { + 'retry' : struct.pack('ii', -1, 0), + 'retry-too-short' : struct.pack('ii', -1, 1), + 'retry-center-finger' : struct.pack('ii', -1, 2), + 'retry-remove-finger' : struct.pack('ii', -1, 3), + + 'error' : struct.pack('ii', -2, 0), + 'error-not-supported' : struct.pack('ii', -2, 1), + 'error-not-open' : struct.pack('ii', -2, 2), + 'error-already-open' : struct.pack('ii', -2, 3), + 'error-busy' : struct.pack('ii', -2, 4), + 'error-proto' : struct.pack('ii', -2, 5), + 'error-data-invalid' : struct.pack('ii', -2, 6), + 'error-data-not-found' : struct.pack('ii', -2, 7), + 'error-data-full' : struct.pack('ii', -2, 8), +} + + +if sys.argv[1] in commands: + command = commands[sys.argv[1]] +else: + png = cairo.ImageSurface.create_from_png(sys.argv[1]) + + # Cairo wants 4 byte aligned rows, so just add a few pixel if necessary + w = png.get_width() + h = png.get_height() + w = (w + 3) // 4 * 4 + h = (h + 3) // 4 * 4 + img = cairo.ImageSurface(cairo.Format.A8, w, h) + cr = cairo.Context(img) + + cr.set_source_rgba(1, 1, 1, 1) + cr.paint() + + cr.set_source_rgba(0, 0, 0, 0) + cr.set_operator(cairo.OPERATOR_SOURCE) + + cr.set_source_surface(png) + cr.paint() + + mem = img.get_data() + mem = mem.tobytes() + assert len(mem) == img.get_width() * img.get_height() + + command = struct.pack('ii', img.get_width(), img.get_height()) + command += mem + + + +def write_dbg_img(): + dbg_img_rgb = cairo.ImageSurface(cairo.Format.RGB24, img.get_width(), img.get_height()) + dbg_cr = cairo.Context(dbg_img_rgb) + dbg_cr.set_source_rgb(0, 0, 0) + dbg_cr.paint() + dbg_cr.set_source_rgb(1, 1, 1) + dbg_cr.mask_surface(img, 0, 0) + + dbg_img_rgb.write_to_png('/tmp/test.png') + +#write_dbg_img() + +# Send image through socket +sockaddr = os.environ['FP_VIRTUAL_IMAGE'] + +sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) +sock.connect(sockaddr) + +sock.sendall(command) + From 7d6b0c1376dd58286afeae6b8501233ce8789cef Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 13 Jun 2019 17:26:57 +0200 Subject: [PATCH 18/73] demo: Port to new API --- demo/gtk-libfprint-test.c | 152 +++++++++++++---------------- demo/loop.c | 196 -------------------------------------- demo/loop.h | 27 ------ demo/meson.build | 2 +- 4 files changed, 66 insertions(+), 311 deletions(-) delete mode 100644 demo/loop.c delete mode 100644 demo/loop.h diff --git a/demo/gtk-libfprint-test.c b/demo/gtk-libfprint-test.c index d0dd0c1e..5610cdd6 100644 --- a/demo/gtk-libfprint-test.c +++ b/demo/gtk-libfprint-test.c @@ -22,8 +22,6 @@ #include #include -#include "loop.h" - typedef GtkApplication LibfprintDemo; typedef GtkApplicationClass LibfprintDemoClass; @@ -45,10 +43,10 @@ typedef struct { GtkWidget *spinner; GtkWidget *instructions; - struct fp_dscv_dev *ddev; - struct fp_dev *dev; + gboolean opened; + FpDevice *dev; - struct fp_img *img; + FpImage *img; ImageDisplayFlags img_flags; } LibfprintDemoWindow; @@ -67,27 +65,18 @@ typedef enum { static void libfprint_demo_set_mode (LibfprintDemoWindow *win, LibfprintDemoMode mode); -static void -pixbuf_destroy (guchar *pixels, gpointer data) -{ - if (pixels == NULL) - return; - g_free (pixels); -} - static unsigned char * -img_to_rgbdata (struct fp_img *img, +img_to_rgbdata (const guint8 *imgdata, int width, int height) { int size = width * height; - unsigned char *imgdata = fp_img_get_data (img); - unsigned char *rgbdata = g_malloc (size * 3); + guint8 *rgbdata = g_malloc (size * 3); size_t i; size_t rgb_offset = 0; for (i = 0; i < size; i++) { - unsigned char pixel = imgdata[i]; + guint8 pixel = imgdata[i]; rgbdata[rgb_offset++] = pixel; rgbdata[rgb_offset++] = pixel; @@ -101,8 +90,7 @@ static void plot_minutiae (unsigned char *rgbdata, int width, int height, - struct fp_minutia **minlist, - int nr_minutiae) + GPtrArray *minutiae) { int i; #define write_pixel(num) do { \ @@ -111,8 +99,8 @@ plot_minutiae (unsigned char *rgbdata, rgbdata[((num) * 3) + 2] = 0; \ } while(0) - for (i = 0; i < nr_minutiae; i++) { - struct fp_minutia *min = minlist[i]; + for (i = 0; i < minutiae->len; i++) { + struct fp_minutia *min = g_ptr_array_index (minutiae, i); int x, y; size_t pixel_offset; @@ -136,36 +124,37 @@ plot_minutiae (unsigned char *rgbdata, } static GdkPixbuf * -img_to_pixbuf (struct fp_img *img, +img_to_pixbuf (FpImage *img, ImageDisplayFlags flags) { int width; int height; + const guint8 *data; unsigned char *rgbdata; - width = fp_img_get_width (img); - height = fp_img_get_height (img); + width = fp_image_get_width (img); + height = fp_image_get_height (img); - if (flags & IMAGE_DISPLAY_BINARY) { - struct fp_img *binary; - binary = fp_img_binarize (img); - rgbdata = img_to_rgbdata (binary, width, height); - fp_img_free (binary); - } else { - rgbdata = img_to_rgbdata (img, width, height); - } + if (flags & IMAGE_DISPLAY_BINARY) + data = fp_image_get_binarized (img, NULL); + else + data = fp_image_get_data (img, NULL); + + if (!data) + return NULL; + + rgbdata = img_to_rgbdata (data, width, height); if (flags & IMAGE_DISPLAY_MINUTIAE) { - struct fp_minutia **minlist; - int nr_minutiae; + GPtrArray *minutiae; - minlist = fp_img_get_minutiae (img, &nr_minutiae); - plot_minutiae (rgbdata, width, height, minlist, nr_minutiae); + minutiae = fp_image_get_minutiae (img); + plot_minutiae (rgbdata, width, height, minutiae); } return gdk_pixbuf_new_from_data (rgbdata, GDK_COLORSPACE_RGB, FALSE, 8, width, height, - width * 3, pixbuf_destroy, + width * 3, (GdkPixbufDestroyNotify) g_free, NULL); } @@ -201,12 +190,10 @@ libfprint_demo_set_spinner_label (LibfprintDemoWindow *win, static void libfprint_demo_set_capture_label (LibfprintDemoWindow *win) { - struct fp_driver *drv; - enum fp_scan_type scan_type; + FpScanType scan_type; const char *message; - drv = fp_dscv_dev_get_driver (win->ddev); - scan_type = fp_driver_get_scan_type(drv); + scan_type = fp_device_get_scan_type(win->dev); switch (scan_type) { case FP_SCAN_TYPE_PRESS: @@ -223,46 +210,49 @@ libfprint_demo_set_capture_label (LibfprintDemoWindow *win) } static void -dev_capture_start_cb (struct fp_dev *dev, - int result, - struct fp_img *img, +dev_capture_start_cb (FpDevice *dev, + GAsyncResult *res, void *user_data) { + g_autoptr(GError) error = NULL; LibfprintDemoWindow *win = user_data; + FpImage *image = NULL; - if (result < 0) { + image = fp_device_capture_finish (dev, res, &error); + if (!image) { + g_warning ("Error capturing data: %s", error->message); libfprint_demo_set_mode (win, ERROR_MODE); return; } - fp_async_capture_stop (dev, NULL, NULL); - - win->img = img; + g_clear_object (&win->img); + win->img = image; update_image (win); libfprint_demo_set_mode (win, CAPTURE_MODE); } static void -dev_open_cb (struct fp_dev *dev, int status, void *user_data) +dev_start_capture (LibfprintDemoWindow *win) { - LibfprintDemoWindow *win = user_data; - int r; - - if (status < 0) { - libfprint_demo_set_mode (win, ERROR_MODE); - return; - } - libfprint_demo_set_capture_label (win); - win->dev = dev; - r = fp_async_capture_start (win->dev, FALSE, dev_capture_start_cb, user_data); - if (r < 0) { - g_warning ("fp_async_capture_start failed: %d", r); + fp_device_capture (win->dev, TRUE, NULL, (GAsyncReadyCallback) dev_capture_start_cb, win); +} + +static void +dev_open_cb (FpDevice *dev, GAsyncResult *res, void *user_data) +{ + LibfprintDemoWindow *win = user_data; + g_autoptr(GError) error = NULL; + + if (!fp_device_open_finish (dev, res, &error)) { + g_warning ("Failed to open device: %s", error->message); libfprint_demo_set_mode (win, ERROR_MODE); return; } + + dev_start_capture(win); } static void @@ -271,24 +261,19 @@ activate_capture (GSimpleAction *action, gpointer user_data) { LibfprintDemoWindow *win = user_data; - int r; libfprint_demo_set_mode (win, SPINNER_MODE); - g_clear_pointer (&win->img, fp_img_free); + g_clear_pointer (&win->img, g_object_unref); - if (win->dev != NULL) { - dev_open_cb (win->dev, 0, user_data); + if (win->opened) { + dev_start_capture (win); return; } libfprint_demo_set_spinner_label (win, "Opening fingerprint reader"); - r = fp_async_dev_open (win->ddev, dev_open_cb, user_data); - if (r < 0) { - g_warning ("fp_async_dev_open failed: %d", r); - libfprint_demo_set_mode (win, ERROR_MODE); - return; - } + win->opened = TRUE; + fp_device_open (win->dev, NULL, (GAsyncReadyCallback) dev_open_cb, user_data); } static void @@ -397,7 +382,6 @@ static void libfprint_demo_set_mode (LibfprintDemoWindow *win, LibfprintDemoMode mode) { - struct fp_driver *drv; char *title; switch (mode) { @@ -415,8 +399,7 @@ libfprint_demo_set_mode (LibfprintDemoWindow *win, gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "capture-mode"); gtk_widget_set_sensitive (win->capture_button, TRUE); - drv = fp_dscv_dev_get_driver (win->ddev); - title = g_strdup_printf ("%s Test", fp_driver_get_full_name (drv)); + title = g_strdup_printf ("%s Test", fp_device_get_name (win->dev)); gtk_header_bar_set_title (GTK_HEADER_BAR (win->header_bar), title); g_free (title); @@ -456,7 +439,8 @@ libfprint_demo_class_init (LibfprintDemoClass *class) static void libfprint_demo_window_init (LibfprintDemoWindow *window) { - struct fp_dscv_dev **discovered_devs; + FpContext *ctx; + GPtrArray *devices; gtk_widget_init_template (GTK_WIDGET (window)); gtk_window_set_default_size (GTK_WINDOW (window), 700, 500); @@ -465,32 +449,26 @@ libfprint_demo_window_init (LibfprintDemoWindow *window) win_entries, G_N_ELEMENTS (win_entries), window); - if (fp_init () < 0) { - libfprint_demo_set_mode (window, ERROR_MODE); - return; - } + ctx = fp_context_new (); - setup_pollfds (); - - discovered_devs = fp_discover_devs(); - if (!discovered_devs) { + devices = fp_context_get_devices(ctx); + if (!devices) { libfprint_demo_set_mode (window, ERROR_MODE); return; } /* Empty list? */ - if (discovered_devs[0] == NULL) { - fp_dscv_devs_free (discovered_devs); + if (devices->len == 0) { libfprint_demo_set_mode (window, EMPTY_MODE); return; } - if (!fp_driver_supports_imaging(fp_dscv_dev_get_driver(discovered_devs[0]))) { + if (!fp_device_supports_capture(g_ptr_array_index (devices, 0))) { libfprint_demo_set_mode (window, NOIMAGING_MODE); return; } - window->ddev = discovered_devs[0]; + window->dev = g_object_ref (g_ptr_array_index (devices, 0)); libfprint_demo_set_mode (window, CAPTURE_MODE); } diff --git a/demo/loop.c b/demo/loop.c deleted file mode 100644 index 81dd62ef..00000000 --- a/demo/loop.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * fprint D-Bus daemon - * Copyright (C) 2008 Daniel Drake - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" - -#include -#include - -#include -#include - -#include "loop.h" - -struct fdsource { - GSource source; - GSList *pollfds; -}; - -static gboolean source_prepare(GSource *source, gint *timeout) -{ - int r; - struct timeval tv; - - r = fp_get_next_timeout(&tv); - if (r == 0) { - *timeout = -1; - return FALSE; - } - - if (!timerisset(&tv)) - return TRUE; - - *timeout = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); - return FALSE; -} - -static gboolean source_check(GSource *source) -{ - struct fdsource *_fdsource = (struct fdsource *) source; - GSList *l; - struct timeval tv; - int r; - - if (!_fdsource->pollfds) - return FALSE; - - for (l = _fdsource->pollfds; l != NULL; l = l->next) { - GPollFD *pollfd = l->data; - - if (pollfd->revents) - return TRUE; - } - - r = fp_get_next_timeout(&tv); - if (r == 1 && !timerisset(&tv)) - return TRUE; - - return FALSE; -} - -static gboolean source_dispatch(GSource *source, GSourceFunc callback, - gpointer data) -{ - struct timeval zerotimeout = { - .tv_sec = 0, - .tv_usec = 0, - }; - - /* FIXME error handling */ - fp_handle_events_timeout(&zerotimeout); - - /* FIXME whats the return value used for? */ - return TRUE; -} - -static void source_finalize(GSource *source) -{ - struct fdsource *_fdsource = (struct fdsource *) source; - GSList *l; - - if (!_fdsource->pollfds) - return; - - for (l = _fdsource->pollfds; l != NULL; l = l->next) { - GPollFD *pollfd = l->data; - - g_source_remove_poll((GSource *) _fdsource, pollfd); - g_slice_free(GPollFD, pollfd); - _fdsource->pollfds = g_slist_delete_link(_fdsource->pollfds, l); - } - - g_slist_free(_fdsource->pollfds); -} - -static GSourceFuncs sourcefuncs = { - .prepare = source_prepare, - .check = source_check, - .dispatch = source_dispatch, - .finalize = source_finalize, -}; - -static struct fdsource *fdsource = NULL; - -static void pollfd_add(int fd, short events) -{ - GPollFD *pollfd; - - pollfd = g_slice_new(GPollFD); - pollfd->fd = fd; - pollfd->events = 0; - pollfd->revents = 0; - if (events & POLLIN) - pollfd->events |= G_IO_IN; - if (events & POLLOUT) - pollfd->events |= G_IO_OUT; - - fdsource->pollfds = g_slist_prepend(fdsource->pollfds, pollfd); - g_source_add_poll((GSource *) fdsource, pollfd); -} - -static void pollfd_added_cb(int fd, short events) -{ - g_debug("now monitoring fd %d", fd); - pollfd_add(fd, events); -} - -static void pollfd_removed_cb(int fd) -{ - GSList *l; - - g_debug("no longer monitoring fd %d", fd); - - if (!fdsource->pollfds) { - g_debug("cannot remove from list as list is empty?"); - return; - } - - for (l = fdsource->pollfds; l != NULL; l = l->next) { - GPollFD *pollfd = l->data; - - if (pollfd->fd != fd) - continue; - - g_source_remove_poll((GSource *) fdsource, pollfd); - g_slice_free(GPollFD, pollfd); - fdsource->pollfds = g_slist_delete_link(fdsource->pollfds, l); - return; - } - - g_error("couldn't find fd %d in list\n", fd); -} - -int setup_pollfds(void) -{ - ssize_t numfds; - size_t i; - struct fp_pollfd *fpfds; - GSource *gsource; - - gsource = g_source_new(&sourcefuncs, sizeof(struct fdsource)); - fdsource = (struct fdsource *) gsource; - fdsource->pollfds = NULL; - - numfds = fp_get_pollfds(&fpfds); - if (numfds < 0) { - if (fpfds) - free(fpfds); - return (int) numfds; - } else if (numfds > 0) { - for (i = 0; i < numfds; i++) { - struct fp_pollfd *fpfd = &fpfds[i]; - pollfd_add(fpfd->fd, fpfd->events); - } - } - - free(fpfds); - fp_set_pollfd_notifiers(pollfd_added_cb, pollfd_removed_cb); - g_source_attach(gsource, NULL); - return 0; -} diff --git a/demo/loop.h b/demo/loop.h deleted file mode 100644 index 0266bfbd..00000000 --- a/demo/loop.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2008 Daniel Drake - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#ifndef POLL_H - -#define POLL_H - -int setup_pollfds(void); - -#endif - diff --git a/demo/meson.build b/demo/meson.build index 1f0b537d..ceca56d4 100644 --- a/demo/meson.build +++ b/demo/meson.build @@ -7,7 +7,7 @@ bindir = join_paths(prefix, get_option('bindir')) datadir = join_paths(prefix, get_option('datadir')) executable('gtk-libfprint-test', - [ 'gtk-libfprint-test.c', 'loop.c', 'loop.h', gtk_test_resources ], + [ 'gtk-libfprint-test.c', gtk_test_resources ], dependencies: [ libfprint_dep, gtk_dep ], include_directories: [ root_inc, From b46d336d2b26258996c30018bd7ff8ee2fdf96d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 19 Nov 2019 20:18:13 +0100 Subject: [PATCH 19/73] examples: Add back examples using the async APIs Add the examples back by using the new async API, support verification and enroll for devices with own storage. --- examples/cpp-test.cpp | 6 +- examples/enroll.c | 223 ++++++++++++++++++---------------- examples/meson.build | 18 +-- examples/storage.c | 149 +++++++++++++++++------ examples/storage.h | 7 +- examples/verify.c | 276 +++++++++++++++++++++++++++--------------- 6 files changed, 434 insertions(+), 245 deletions(-) diff --git a/examples/cpp-test.cpp b/examples/cpp-test.cpp index 12936132..a0eb2ed7 100644 --- a/examples/cpp-test.cpp +++ b/examples/cpp-test.cpp @@ -6,6 +6,10 @@ int main (int argc, char **argv) { - fp_init (); + FpContext *ctx; + + ctx = fp_context_new (); + g_object_unref (ctx); + return 0; } diff --git a/examples/enroll.c b/examples/enroll.c index 9814f68e..7542f306 100644 --- a/examples/enroll.c +++ b/examples/enroll.c @@ -2,6 +2,7 @@ * Example fingerprint enrollment program * Enrolls your right index finger and saves the print to disk * Copyright (C) 2007 Daniel Drake + * Copyright (C) 2019 Marco Trevisan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,91 +20,128 @@ */ #include -#include -#include - #include #include "storage.h" -struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs) +typedef struct _EnrollData { + GMainLoop *loop; + int ret_value; +} EnrollData; + +static void +enroll_data_free (EnrollData *enroll_data) { - struct fp_dscv_dev *ddev = discovered_devs[0]; - struct fp_driver *drv; - if (!ddev) + g_main_loop_unref (enroll_data->loop); + g_free (enroll_data); +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC (EnrollData, enroll_data_free) + +FpDevice *discover_device (GPtrArray *devices) +{ + FpDevice *dev; + if (!devices->len) return NULL; - - drv = fp_dscv_dev_get_driver(ddev); - printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv)); - return ddev; + + dev = g_ptr_array_index (devices, 0); + printf("Found device claimed by %s driver\n", fp_device_get_driver (dev)); + return dev; } -struct fp_print_data *enroll(struct fp_dev *dev) { - struct fp_print_data *enrolled_print = NULL; - int r; +static void +on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data) { + EnrollData *enroll_data = user_data; + g_autoptr(GError) error = NULL; - printf("You will need to successfully scan your finger %d times to " - "complete the process.\n", fp_dev_get_nr_enroll_stages(dev)); + fp_device_close_finish (dev, res, &error); - do { - struct fp_img *img = NULL; + if (error) + g_warning ("Failed closing device %s\n", error->message); - printf("\nScan your finger now.\n"); + g_main_loop_quit (enroll_data->loop); +} - r = fp_enroll_finger_img(dev, &enrolled_print, &img); - if (img) { - fp_img_save_to_file(img, "enrolled.pgm"); - printf("Wrote scanned image to enrolled.pgm\n"); - fp_img_free(img); +static void +on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data) { + EnrollData *enroll_data = user_data; + g_autoptr(FpPrint) print = NULL; + g_autoptr(GError) error = NULL; + + print = fp_device_enroll_finish (dev, res, &error); + + if (!error) { + enroll_data->ret_value = EXIT_SUCCESS; + + if (!fp_device_has_storage (dev)) { + g_debug("Device has not storage, saving locally"); + int r = print_data_save(print, FP_FINGER_RIGHT_INDEX); + if (r < 0) { + g_warning("Data save failed, code %d", r); + enroll_data->ret_value = EXIT_FAILURE; + } } - if (r < 0) { - printf("Enroll failed with error %d\n", r); - return NULL; - } - - switch (r) { - case FP_ENROLL_COMPLETE: - printf("Enroll complete!\n"); - break; - case FP_ENROLL_FAIL: - printf("Enroll failed, something wen't wrong :(\n"); - return NULL; - case FP_ENROLL_PASS: - printf("Enroll stage passed. Yay!\n"); - break; - case FP_ENROLL_RETRY: - printf("Didn't quite catch that. Please try again.\n"); - break; - case FP_ENROLL_RETRY_TOO_SHORT: - printf("Your swipe was too short, please try again.\n"); - break; - case FP_ENROLL_RETRY_CENTER_FINGER: - printf("Didn't catch that, please center your finger on the " - "sensor and try again.\n"); - break; - case FP_ENROLL_RETRY_REMOVE_FINGER: - printf("Scan failed, please remove your finger and then try " - "again.\n"); - break; - } - } while (r != FP_ENROLL_COMPLETE); - - if (!enrolled_print) { - fprintf(stderr, "Enroll complete but no print?\n"); - return NULL; + } else { + g_warning("Enroll failed with error %s\n", error->message); } - printf("Enrollment completed!\n\n"); - return enrolled_print; + fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, + enroll_data); +} + +static void +on_enroll_progress (FpDevice *device, + gint completed_stages, + FpPrint *print, + gpointer user_data, + GError *error) +{ + if (error) { + g_warning ("Enroll stage %d of %d failed with error %s", + completed_stages, + fp_device_get_nr_enroll_stages (device), + error->message); + return; + } + + if (fp_device_supports_capture (device) && + print_image_save (print, "enrolled.pgm")) { + printf ("Wrote scanned image to enrolled.pgm\n"); + } + + printf ("Enroll stage %d of %d passed. Yay!\n", completed_stages, + fp_device_get_nr_enroll_stages (device)); +} + +static void +on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data) +{ + EnrollData *enroll_data = user_data; + FpPrint *print_template; + g_autoptr(GError) error = NULL; + + if (!fp_device_open_finish (dev, res, &error)) { + g_warning ("Failed to open device: %s", error->message); + g_main_loop_quit (enroll_data->loop); + return; + } + + printf ("Opened device. It's now time to enroll your finger.\n\n"); + printf ("You will need to successfully scan your finger %d times to " + "complete the process.\n\n", fp_device_get_nr_enroll_stages (dev)); + printf ("Scan your finger now.\n"); + + print_template = print_create_template (dev, FP_FINGER_RIGHT_INDEX); + fp_device_enroll (dev, print_template, NULL, on_enroll_progress, NULL, + NULL, (GAsyncReadyCallback) on_enroll_completed, + enroll_data); } int main(void) { - int r = 1; - struct fp_dscv_dev *ddev; - struct fp_dscv_dev **discovered_devs; - struct fp_dev *dev; - struct fp_print_data *data; + g_autoptr (FpContext) ctx = NULL; + g_autoptr (EnrollData) enroll_data = NULL; + GPtrArray *devices; + FpDevice *dev; printf("This program will enroll your right index finger, " "unconditionally overwriting any right-index print that was enrolled " @@ -112,48 +150,29 @@ int main(void) getchar(); setenv ("G_MESSAGES_DEBUG", "all", 0); - setenv ("LIBUSB_DEBUG", "3", 0); - r = fp_init(); - if (r < 0) { - fprintf(stderr, "Failed to initialize libfprint\n"); - exit(1); + ctx = fp_context_new (); + + devices = fp_context_get_devices (ctx); + if (!devices) { + g_warning("Impossible to get devices"); + return EXIT_FAILURE; } - discovered_devs = fp_discover_devs(); - if (!discovered_devs) { - fprintf(stderr, "Could not discover devices\n"); - goto out; - } - - ddev = discover_device(discovered_devs); - if (!ddev) { - fprintf(stderr, "No devices detected.\n"); - goto out; - } - - dev = fp_dev_open(ddev); - fp_dscv_devs_free(discovered_devs); + dev = discover_device (devices); if (!dev) { - fprintf(stderr, "Could not open device.\n"); - goto out; + g_warning("No devices detected."); + return EXIT_FAILURE; } - printf("Opened device. It's now time to enroll your finger.\n\n"); - data = enroll(dev); - if (!data) - goto out_close; + enroll_data = g_new0 (EnrollData, 1); + enroll_data->ret_value = EXIT_FAILURE; + enroll_data->loop = g_main_loop_new (NULL, FALSE); - r = print_data_save(data, RIGHT_INDEX); - if (r < 0) - fprintf(stderr, "Data save failed, code %d\n", r); + fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened, + enroll_data); - fp_print_data_free(data); -out_close: - fp_dev_close(dev); -out: - fp_exit(); - return r; + g_main_loop_run (enroll_data->loop); + + return enroll_data->ret_value; } - - diff --git a/examples/meson.build b/examples/meson.build index 9c84e6bc..90c5257b 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -1,22 +1,22 @@ -examples = [ 'verify_live', 'enroll', 'verify', 'img_capture' ] +examples = [ 'enroll', 'verify', 'manage-prints' ] foreach example: examples executable(example, [example + '.c', 'storage.c'], - dependencies: [libfprint_dep], + dependencies: [libfprint_dep, glib_dep], include_directories: [ root_inc, ], c_args: common_cflags) endforeach -# executable('cpp-test', -# 'cpp-test.cpp', -# dependencies: libfprint_dep, -# include_directories: [ -# root_inc, -# ], -# c_args: common_cflags) +executable('cpp-test', + 'cpp-test.cpp', + dependencies: libfprint_dep, + include_directories: [ + root_inc, + ], + c_args: common_cflags) # if get_option('x11-examples') # executable('img_capture_continuous', diff --git a/examples/storage.c b/examples/storage.c index aa399e0f..d2f4832b 100644 --- a/examples/storage.c +++ b/examples/storage.c @@ -2,6 +2,7 @@ * Trivial storage driver for example programs * * Copyright (C) 2019 Benjamin Berg + * Copyright (C) 2019 Marco Trevisan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,41 +19,41 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#include + +#include #include #include #include -#include - #define STORAGE_FILE "test-storage.variant" static char * -get_print_data_descriptor (struct fp_print_data *data, struct fp_dev *dev, enum fp_finger finger) +get_print_data_descriptor (FpPrint *print, FpDevice *dev, FpFinger finger) { - gint drv_id; - gint devtype; + const char *driver; + const char *dev_id; - if (data) { - drv_id = fp_print_data_get_driver_id (data); - devtype = fp_print_data_get_devtype (data); + if (print) { + driver = fp_print_get_driver (print); + dev_id = fp_print_get_device_id (print); } else { - drv_id = fp_driver_get_driver_id(fp_dev_get_driver (dev)); - devtype = fp_dev_get_devtype (dev); + driver = fp_device_get_driver (dev); + dev_id = fp_device_get_device_id (dev); } - return g_strdup_printf("%x/%08x/%x", - drv_id, - devtype, + return g_strdup_printf("%s/%s/%x", + driver, + dev_id, finger); } -static GVariantDict* +static GVariantDict * load_data(void) { GVariantDict *res; GVariant *var; - gchar *contents = NULL; + g_autofree gchar *contents = NULL; gssize length = 0; if (!g_file_get_contents (STORAGE_FILE, &contents, &length, NULL)) { @@ -88,49 +89,125 @@ save_data(GVariant *data) } int -print_data_save(struct fp_print_data *fp_data, enum fp_finger finger) +print_data_save(FpPrint *print, FpFinger finger) { - gchar *descr = get_print_data_descriptor (fp_data, NULL, finger); - GVariantDict *dict; + g_autofree gchar *descr = get_print_data_descriptor (print, NULL, finger); + g_autoptr (GError) error = NULL; + g_autoptr (GVariantDict) dict = NULL; + g_autofree guchar *data = NULL; GVariant *val; - guchar *data; gsize size; int res; dict = load_data(); - size = fp_print_data_get_data(fp_data, &data); + fp_print_serialize (print, &data, &size, &error); + if (error) { + g_warning ("Error serializing data: %s", error->message); + return -1; + } val = g_variant_new_fixed_array (G_VARIANT_TYPE("y"), data, size, 1); g_variant_dict_insert_value (dict, descr, val); res = save_data(g_variant_dict_end(dict)); - g_variant_dict_unref(dict); return res; } -struct fp_print_data* -print_data_load(struct fp_dev *dev, enum fp_finger finger) +FpPrint * +print_data_load(FpDevice *dev, FpFinger finger) { - gchar *descr = get_print_data_descriptor (NULL, dev, finger); - GVariantDict *dict; - guchar *stored_data; + g_autofree gchar *descr = get_print_data_descriptor (NULL, dev, finger); + g_autoptr (GVariant) val = NULL; + g_autoptr (GVariantDict) dict = NULL; + g_autofree guchar *stored_data = NULL; gsize stored_len; - GVariant *val; - struct fp_print_data *res = NULL; dict = load_data(); val = g_variant_dict_lookup_value (dict, descr, G_VARIANT_TYPE ("ay")); if (val) { - stored_data = (guchar*) g_variant_get_fixed_array (val, &stored_len, 1); - res = fp_print_data_from_data(stored_data, stored_len); + FpPrint *print; + g_autoptr (GError) error = NULL; - g_variant_unref(val); + stored_data = (guchar*) g_variant_get_fixed_array (val, &stored_len, 1); + print = fp_print_deserialize (stored_data, stored_len, &error); + + if (error) + g_warning ("Error deserializing data: %s", error->message); + + return print; } - g_variant_dict_unref(dict); - g_free(descr); - - return res; + return NULL; +} + +FpPrint * +print_create_template (FpDevice *dev, FpFinger finger) +{ + g_autoptr(GDateTime) datetime = NULL; + FpPrint *template = NULL; + GDate *date = NULL; + gint year, month, day; + + template = fp_print_new (dev); + fp_print_set_finger (template, finger); + fp_print_set_username (template, g_get_user_name ()); + datetime = g_date_time_new_now_local (); + g_date_time_get_ymd (datetime, &year, &month, &day); + date = g_date_new_dmy (day, month, year); + fp_print_set_enroll_date (template, date); + g_date_free (date); + + return template; +} + + +static gboolean +save_image_to_pgm (FpImage *img, const char *path) +{ + FILE *fd = fopen (path, "w"); + size_t write_size; + const guchar *data = fp_image_get_data (img, &write_size); + int r; + + if (!fd) { + g_warning("could not open '%s' for writing: %d", path, errno); + return FALSE; + } + + r = fprintf (fd, "P5 %d %d 255\n", + fp_image_get_width (img), fp_image_get_height (img)); + if (r < 0) { + fclose(fd); + g_critical("pgm header write failed, error %d", r); + return FALSE; + } + + r = fwrite (data, 1, write_size, fd); + if (r < write_size) { + fclose(fd); + g_critical("short write (%d)", r); + return FALSE; + } + + fclose (fd); + g_debug ("written to '%s'", path); + + return TRUE; +} + +gboolean print_image_save (FpPrint *print, const char *path) +{ + g_autoptr(FpImage) img = NULL; + + g_return_val_if_fail (FP_IS_PRINT (print), FALSE); + g_return_val_if_fail (path != NULL, FALSE); + + img = fp_print_get_image (print); + + if (img) + return save_image_to_pgm (img, path); + + return FALSE; } diff --git a/examples/storage.h b/examples/storage.h index fc86813e..f4199954 100644 --- a/examples/storage.h +++ b/examples/storage.h @@ -21,7 +21,10 @@ #ifndef __STORAGE_H #define __STORAGE_H -int print_data_save(struct fp_print_data *fp_data, enum fp_finger finger); -struct fp_print_data* print_data_load(struct fp_dev *dev, enum fp_finger finger); + +int print_data_save(FpPrint *print, FpFinger finger); +FpPrint * print_data_load(FpDevice *dev, FpFinger finger); +FpPrint * print_create_template(FpDevice *dev, FpFinger finger); +gboolean print_image_save(FpPrint *print, const char *path); #endif /* __STORAGE_H */ diff --git a/examples/verify.c b/examples/verify.c index 38b925c5..69e3cbd9 100644 --- a/examples/verify.c +++ b/examples/verify.c @@ -2,6 +2,7 @@ * Example fingerprint verification program, which verifies the right index * finger which has been previously enrolled to disk. * Copyright (C) 2007 Daniel Drake + * Copyright (C) 2019 Marco Trevisan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,131 +20,216 @@ */ #include -#include -#include - #include #include "storage.h" -struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs) +typedef struct _VerifyData { + GMainLoop *loop; + int ret_value; +} VerifyData; + +static void +verify_data_free (VerifyData *verify_data) { - struct fp_dscv_dev *ddev = discovered_devs[0]; - struct fp_driver *drv; - if (!ddev) + g_main_loop_unref (verify_data->loop); + g_free (verify_data); +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC (VerifyData, verify_data_free) + +FpDevice *discover_device (GPtrArray *devices) +{ + FpDevice *dev; + if (!devices->len) return NULL; - - drv = fp_dscv_dev_get_driver(ddev); - printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv)); - return ddev; + + dev = g_ptr_array_index (devices, 0); + printf("Found device claimed by %s driver\n", fp_device_get_driver (dev)); + return dev; } -int verify(struct fp_dev *dev, struct fp_print_data *data) +static void +on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data) { + VerifyData *verify_data = user_data; + g_autoptr(GError) error = NULL; + + fp_device_close_finish (dev, res, &error); + + if (error) + g_warning ("Failed closing device %s\n", error->message); + + g_main_loop_quit (verify_data->loop); +} + +static void start_verification (FpDevice *dev, VerifyData *verify_data); + +static void +on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data) { - int r; + VerifyData *verify_data = user_data; + g_autoptr(FpPrint) print = NULL; + g_autoptr(GError) error = NULL; + char buffer[20]; + gboolean match; - do { - struct fp_img *img = NULL; + if (!fp_device_verify_finish (dev, res, &match, &print, &error)) { + g_warning ("Failed to verify print: %s", error->message); + g_main_loop_quit (verify_data->loop); + return; + } - sleep(1); - printf("\nScan your finger now.\n"); - r = fp_verify_finger_img(dev, data, &img); - if (img) { - fp_img_save_to_file(img, "verify.pgm"); - printf("Wrote scanned image to verify.pgm\n"); - fp_img_free(img); + if (match) { + g_print ("MATCH!\n"); + if (fp_device_supports_capture (dev) && + print_image_save (print, "verify.pgm")) { + g_print("Print image saved as verify.pgm"); } - if (r < 0) { - printf("verification failed with error %d :(\n", r); - return r; + + verify_data->ret_value = EXIT_SUCCESS; + } else { + g_print ("NO MATCH!\n"); + verify_data->ret_value = EXIT_FAILURE; + } + + g_print ("Verify again? [Y/n]? "); + if (fgets (buffer, sizeof (buffer), stdin) && + (buffer[0] == 'Y' || buffer[0] == 'y')) { + start_verification (dev, verify_data); + return; + } + + fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, + verify_data); +} + +static void +on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data) +{ + VerifyData *verify_data = user_data; + g_autoptr(GPtrArray) prints = NULL; + g_autoptr(GError) error = NULL; + + prints = fp_device_list_prints_finish (dev, res, &error); + + if (!error) { + FpPrint *verify_print = NULL; + guint i; + + if (!prints->len) + g_warning ("No prints saved on device"); + + for (i = 0; i < prints->len; ++i) { + FpPrint *print = prints->pdata[i]; + + if (fp_print_get_finger (print) == FP_FINGER_RIGHT_INDEX && + g_strcmp0 (fp_print_get_username (print), g_get_user_name ()) == 0) { + if (!verify_print || + (g_date_compare (fp_print_get_enroll_date (print), + fp_print_get_enroll_date (verify_print)) >= 0)) + verify_print = print; + } } - switch (r) { - case FP_VERIFY_NO_MATCH: - printf("NO MATCH!\n"); - return 0; - case FP_VERIFY_MATCH: - printf("MATCH!\n"); - return 0; - case FP_VERIFY_RETRY: - printf("Scan didn't quite work. Please try again.\n"); - break; - case FP_VERIFY_RETRY_TOO_SHORT: - printf("Swipe was too short, please try again.\n"); - break; - case FP_VERIFY_RETRY_CENTER_FINGER: - printf("Please center your finger on the sensor and try again.\n"); - break; - case FP_VERIFY_RETRY_REMOVE_FINGER: - printf("Please remove finger from the sensor and try again.\n"); - break; + + if (!verify_print) { + g_warning ("Did you remember to enroll your right index " + "finger first?"); + g_main_loop_quit (verify_data->loop); + return; } - } while (1); + + g_debug ("Comparing print with %s", + fp_print_get_description (verify_print)); + + g_print ("Print loaded. Time to verify!\n"); + fp_device_verify (dev, verify_print, NULL, + (GAsyncReadyCallback) on_verify_completed, + verify_data); + } else { + g_warning ("Loading prints failed with error %s", error->message); + g_main_loop_quit (verify_data->loop); + } +} + +static void +start_verification (FpDevice *dev, VerifyData *verify_data) +{ + if (fp_device_has_storage (dev)) { + g_print ("Creating finger template, using device storage...\n"); + fp_device_list_prints (dev, NULL, + (GAsyncReadyCallback) on_list_completed, + verify_data); + } else { + g_print ("Loading previously enrolled right index finger data...\n"); + g_autoptr(FpPrint) verify_print; + + verify_print = print_data_load (dev, FP_FINGER_RIGHT_INDEX); + + if (!verify_print) { + g_warning ("Failed to load fingerprint data"); + g_warning ("Did you remember to enroll your right index " + "finger first?"); + g_main_loop_quit (verify_data->loop); + return; + } + + g_print ("Print loaded. Time to verify!\n"); + fp_device_verify (dev, verify_print, NULL, + (GAsyncReadyCallback) on_verify_completed, + verify_data); + } +} + +static void +on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data) +{ + VerifyData *verify_data = user_data; + g_autoptr(GError) error = NULL; + + if (!fp_device_open_finish (dev, res, &error)) { + g_warning ("Failed to open device: %s", error->message); + g_main_loop_quit (verify_data->loop); + return; + } + + g_print ("Opened device. "); + + start_verification (dev, verify_data); } int main(void) { - int r = 1; - struct fp_dscv_dev *ddev; - struct fp_dscv_dev **discovered_devs; - struct fp_dev *dev; - struct fp_print_data *data; + g_autoptr (FpContext) ctx = NULL; + g_autoptr (VerifyData) verify_data = NULL; + GPtrArray *devices; + FpDevice *dev; setenv ("G_MESSAGES_DEBUG", "all", 0); setenv ("LIBUSB_DEBUG", "3", 0); - r = fp_init(); - if (r < 0) { - fprintf(stderr, "Failed to initialize libfprint\n"); - exit(1); + ctx = fp_context_new (); + + devices = fp_context_get_devices (ctx); + if (!devices) { + g_warning("Impossible to get devices"); + return EXIT_FAILURE; } - discovered_devs = fp_discover_devs(); - if (!discovered_devs) { - fprintf(stderr, "Could not discover devices\n"); - goto out; - } - - ddev = discover_device(discovered_devs); - if (!ddev) { - fprintf(stderr, "No devices detected.\n"); - goto out; - } - - dev = fp_dev_open(ddev); - fp_dscv_devs_free(discovered_devs); + dev = discover_device (devices); if (!dev) { - fprintf(stderr, "Could not open device.\n"); - goto out; + g_warning("No devices detected."); + return EXIT_FAILURE; } - printf("Opened device. Loading previously enrolled right index finger " - "data...\n"); + verify_data = g_new0 (VerifyData, 1); + verify_data->ret_value = EXIT_FAILURE; + verify_data->loop = g_main_loop_new (NULL, FALSE); - data = print_data_load(dev, RIGHT_INDEX); - if (!data) { - fprintf(stderr, "Failed to load fingerprint, error %d\n", r); - fprintf(stderr, "Did you remember to enroll your right index finger " - "first?\n"); - goto out_close; - } + fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened, + verify_data); - printf("Print loaded. Time to verify!\n"); - do { - char buffer[20]; + g_main_loop_run (verify_data->loop); - verify(dev, data); - printf("Verify again? [Y/n]? "); - fgets(buffer, sizeof(buffer), stdin); - if (buffer[0] != '\n' && buffer[0] != 'y' && buffer[0] != 'Y') - break; - } while (1); - - fp_print_data_free(data); -out_close: - fp_dev_close(dev); -out: - fp_exit(); - return r; + return verify_data->ret_value; } From 3f0a143037f8e74a633190920fabfe0b4d7a1b20 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 4 Jul 2019 16:38:32 +0200 Subject: [PATCH 20/73] demo: Add UI for retry errors --- demo/gtk-libfprint-test.c | 13 +++++++++-- demo/gtk-libfprint-test.ui | 46 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/demo/gtk-libfprint-test.c b/demo/gtk-libfprint-test.c index 5610cdd6..238dff5e 100644 --- a/demo/gtk-libfprint-test.c +++ b/demo/gtk-libfprint-test.c @@ -59,7 +59,8 @@ typedef enum { NOIMAGING_MODE, CAPTURE_MODE, SPINNER_MODE, - ERROR_MODE + ERROR_MODE, + RETRY_MODE } LibfprintDemoMode; static void libfprint_demo_set_mode (LibfprintDemoWindow *win, @@ -221,7 +222,10 @@ dev_capture_start_cb (FpDevice *dev, image = fp_device_capture_finish (dev, res, &error); if (!image) { g_warning ("Error capturing data: %s", error->message); - libfprint_demo_set_mode (win, ERROR_MODE); + if (error->domain == FP_DEVICE_RETRY) + libfprint_demo_set_mode (win, RETRY_MODE); + else + libfprint_demo_set_mode (win, ERROR_MODE); return; } @@ -415,6 +419,11 @@ libfprint_demo_set_mode (LibfprintDemoWindow *win, gtk_widget_set_sensitive (win->capture_button, FALSE); gtk_spinner_stop (GTK_SPINNER (win->spinner)); break; + case RETRY_MODE: + gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "retry-mode"); + gtk_widget_set_sensitive (win->capture_button, TRUE); + gtk_spinner_stop (GTK_SPINNER (win->spinner)); + break; default: g_assert_not_reached (); } diff --git a/demo/gtk-libfprint-test.ui b/demo/gtk-libfprint-test.ui index 0691620d..c2bd56a6 100644 --- a/demo/gtk-libfprint-test.ui +++ b/demo/gtk-libfprint-test.ui @@ -266,6 +266,52 @@ 2 + + + True + False + center + center + True + True + vertical + 12 + + + True + False + 9 + 192 + dialog-warning-symbolic + + + 1 + 0 + + + + + True + False + 9 + <b><span size="large">Device reported a recoverable error. Please retry!</span></b> + True + + + 1 + 1 + + + + + + retry-mode + retry-mode + 2 + + True From d184a7662c6997139cef0e3e0a74c82af5ecf910 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 4 Jul 2019 17:40:50 +0200 Subject: [PATCH 21/73] demo: Update flatpak manifest Build libgusb and the current v2 development branch. --- demo/org.freedesktop.libfprint.Demo.json | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/demo/org.freedesktop.libfprint.Demo.json b/demo/org.freedesktop.libfprint.Demo.json index cbb4046f..9c5c7b28 100644 --- a/demo/org.freedesktop.libfprint.Demo.json +++ b/demo/org.freedesktop.libfprint.Demo.json @@ -32,18 +32,30 @@ } ], "post-install": [ - "install -Dm644 COPYING /app/share/licenses/libusb/COPYING" + "install -Dm644 COPYING /app/share/licenses/libgusb/COPYING" + ] + }, + { + "name": "libgusb", + "buildsystem": "meson", + "config-opts": [ "-Dtests=false", "-Dvapi=false", "-Ddocs=false", "-Dintrospection=false" ], + "sources": [ + { + "type": "archive", + "url": "https://github.com/hughsie/libgusb/archive/0.3.0.tar.gz", + "sha256": "b36310f8405d5fd68f6caf4a829f7ab4c627b38fd3d02a139d411fce0f3a49f1" + } ] }, { "name": "libfprint", "buildsystem": "meson", - "config-opts": [ "-Dudev_rules=false", "-Dx11-examples=false", "-Dgtk-examples=true" ], + "config-opts": [ "-Dudev_rules=false", "-Dx11-examples=false", "-Dgtk-examples=true", "-Ddrivers=all" ], "sources": [ { "type": "git", "url": "https://gitlab.freedesktop.org/libfprint/libfprint.git", - "branch": "wip/hadess/gtk-example" + "branch": "wip/benzea/v2" } ] } From 0b4f682233e884c50483923b99836ef61eb5bc10 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 8 Jul 2019 23:51:12 +0200 Subject: [PATCH 22/73] demo: Add ability to cancel capture operation --- demo/gtk-libfprint-test.c | 38 +++- demo/gtk-libfprint-test.ui | 404 ++++++++++++++++++++----------------- 2 files changed, 251 insertions(+), 191 deletions(-) diff --git a/demo/gtk-libfprint-test.c b/demo/gtk-libfprint-test.c index 238dff5e..c460e14a 100644 --- a/demo/gtk-libfprint-test.c +++ b/demo/gtk-libfprint-test.c @@ -39,10 +39,13 @@ typedef struct { GtkWidget *header_bar; GtkWidget *mode_stack; GtkWidget *capture_button; + GtkWidget *cancel_button; GtkWidget *capture_image; GtkWidget *spinner; GtkWidget *instructions; + GCancellable *cancellable; + gboolean opened; FpDevice *dev; @@ -219,10 +222,13 @@ dev_capture_start_cb (FpDevice *dev, LibfprintDemoWindow *win = user_data; FpImage *image = NULL; + g_clear_object (&win->cancellable); + image = fp_device_capture_finish (dev, res, &error); if (!image) { g_warning ("Error capturing data: %s", error->message); - if (error->domain == FP_DEVICE_RETRY) + if (error->domain == FP_DEVICE_RETRY || + g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) libfprint_demo_set_mode (win, RETRY_MODE); else libfprint_demo_set_mode (win, ERROR_MODE); @@ -241,7 +247,7 @@ dev_start_capture (LibfprintDemoWindow *win) { libfprint_demo_set_capture_label (win); - fp_device_capture (win->dev, TRUE, NULL, (GAsyncReadyCallback) dev_capture_start_cb, win); + fp_device_capture (win->dev, TRUE, win->cancellable, (GAsyncReadyCallback) dev_capture_start_cb, win); } static void @@ -269,6 +275,9 @@ activate_capture (GSimpleAction *action, libfprint_demo_set_mode (win, SPINNER_MODE); g_clear_pointer (&win->img, g_object_unref); + g_clear_object (&win->cancellable); + win->cancellable = g_cancellable_new (); + if (win->opened) { dev_start_capture (win); return; @@ -277,7 +286,20 @@ activate_capture (GSimpleAction *action, libfprint_demo_set_spinner_label (win, "Opening fingerprint reader"); win->opened = TRUE; - fp_device_open (win->dev, NULL, (GAsyncReadyCallback) dev_open_cb, user_data); + fp_device_open (win->dev, win->cancellable, (GAsyncReadyCallback) dev_open_cb, user_data); +} + +static void +cancel_capture (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + LibfprintDemoWindow *win = user_data; + + g_debug ("cancelling %p", win->cancellable); + + if (win->cancellable) + g_cancellable_cancel (win->cancellable); } static void @@ -368,7 +390,8 @@ static GActionEntry app_entries[] = { static GActionEntry win_entries[] = { { "show-minutiae", activate_show_minutiae, NULL, "false", change_show_minutiae_state }, { "show-binary", activate_show_binary, NULL, "false", change_show_binary_state }, - { "capture", activate_capture, NULL, NULL, NULL } + { "capture", activate_capture, NULL, NULL, NULL }, + { "cancel", cancel_capture, NULL, NULL, NULL } }; static void @@ -392,16 +415,19 @@ libfprint_demo_set_mode (LibfprintDemoWindow *win, case EMPTY_MODE: gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "empty-mode"); gtk_widget_set_sensitive (win->capture_button, FALSE); + gtk_widget_set_sensitive (win->cancel_button, FALSE); gtk_spinner_stop (GTK_SPINNER (win->spinner)); break; case NOIMAGING_MODE: gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "noimaging-mode"); gtk_widget_set_sensitive (win->capture_button, FALSE); + gtk_widget_set_sensitive (win->cancel_button, FALSE); gtk_spinner_stop (GTK_SPINNER (win->spinner)); break; case CAPTURE_MODE: gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "capture-mode"); gtk_widget_set_sensitive (win->capture_button, TRUE); + gtk_widget_set_sensitive (win->cancel_button, FALSE); title = g_strdup_printf ("%s Test", fp_device_get_name (win->dev)); gtk_header_bar_set_title (GTK_HEADER_BAR (win->header_bar), title); @@ -412,16 +438,19 @@ libfprint_demo_set_mode (LibfprintDemoWindow *win, case SPINNER_MODE: gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "spinner-mode"); gtk_widget_set_sensitive (win->capture_button, FALSE); + gtk_widget_set_sensitive (win->cancel_button, TRUE); gtk_spinner_start (GTK_SPINNER (win->spinner)); break; case ERROR_MODE: gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "error-mode"); gtk_widget_set_sensitive (win->capture_button, FALSE); + gtk_widget_set_sensitive (win->cancel_button, FALSE); gtk_spinner_stop (GTK_SPINNER (win->spinner)); break; case RETRY_MODE: gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "retry-mode"); gtk_widget_set_sensitive (win->capture_button, TRUE); + gtk_widget_set_sensitive (win->cancel_button, FALSE); gtk_spinner_stop (GTK_SPINNER (win->spinner)); break; default: @@ -490,6 +519,7 @@ libfprint_demo_window_class_init (LibfprintDemoWindowClass *class) gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, header_bar); gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, mode_stack); gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_button); + gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, cancel_button); gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_image); gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, spinner); gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, instructions); diff --git a/demo/gtk-libfprint-test.ui b/demo/gtk-libfprint-test.ui index c2bd56a6..d83b826d 100644 --- a/demo/gtk-libfprint-test.ui +++ b/demo/gtk-libfprint-test.ui @@ -1,5 +1,5 @@ - + From 6e25a278707d6d0eeb1e97f98b1f0b9c102ff7cb Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 3 Jul 2019 23:39:08 +0200 Subject: [PATCH 23/73] tests: Add basic unit test based on virtual_image device --- meson.build | 5 + tests/meson.build | 17 +++ tests/virtual-image.py | 280 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 302 insertions(+) create mode 100644 tests/meson.build create mode 100755 tests/virtual-image.py diff --git a/meson.build b/meson.build index de73d6d0..ec9221de 100644 --- a/meson.build +++ b/meson.build @@ -140,6 +140,11 @@ if get_option('gtk-examples') subdir('demo') endif +# The tests require introspeciton support to run +if get_option('introspection') + subdir('tests') +endif + pkgconfig = import('pkgconfig') pkgconfig.generate( name: 'libfprint', diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 00000000..26b8e76d --- /dev/null +++ b/tests/meson.build @@ -0,0 +1,17 @@ +envs = environment() +envs.set('G_DEBUG', 'fatal-warnings') +envs.set('G_MESSAGES_DEBUG', 'all') +envs.set('MESON_SOURCE_ROOT', meson.build_root()) +envs.prepend('GI_TYPELIB_PATH', join_paths(meson.build_root(), 'libfprint')) +envs.prepend('LD_LIBRARY_PATH', join_paths(meson.build_root(), 'libfprint')) +envs.set('NO_AT_BRIDGE', '1') + +if 'virtual_image' in drivers + test( + 'virtual-image', + find_program('virtual-image.py'), + args: '--verbose', + env: envs, + ) +endif + diff --git a/tests/virtual-image.py b/tests/virtual-image.py new file mode 100755 index 00000000..a9fe8f5e --- /dev/null +++ b/tests/virtual-image.py @@ -0,0 +1,280 @@ +#!/usr/bin/env python3 + + +import gi +gi.require_version('FPrint', '2.0') +from gi.repository import FPrint, GLib, Gio + +import os +import sys +import unittest +import socket +import struct +import shutil +import glob +import cairo +import tempfile + +class Connection: + + def __init__(self, addr): + self.addr = addr + + def __enter__(self): + self.con = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.con.connect(self.addr) + return self.con + + def __exit__(self, exc_type, exc_val, exc_tb): + self.con.close() + del self.con + +def load_image(img): + png = cairo.ImageSurface.create_from_png(img) + + # Cairo wants 4 byte aligned rows, so just add a few pixel if necessary + w = png.get_width() + h = png.get_height() + w = (w + 3) // 4 * 4 + h = (h + 3) // 4 * 4 + img = cairo.ImageSurface(cairo.Format.A8, w, h) + cr = cairo.Context(img) + + cr.set_source_rgba(1, 1, 1, 1) + cr.paint() + + cr.set_source_rgba(0, 0, 0, 0) + cr.set_operator(cairo.OPERATOR_SOURCE) + + cr.set_source_surface(png) + cr.paint() + + return img + +if hasattr(os.environ, 'MESON_SOURCE_ROOT'): + root = os.environ['MESON_SOURCE_ROOT'] +else: + root = os.path.join(os.path.dirname(__file__), '..') + +imgdir = os.path.join(root, 'examples', 'prints') + +ctx = GLib.main_context_default() + +class VirtualImage(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.tmpdir = tempfile.mkdtemp(prefix='libfprint-') + + cls.sockaddr = os.path.join(cls.tmpdir, 'virtual-image.socket') + os.environ['FP_VIRTUAL_IMAGE'] = cls.sockaddr + + cls.ctx = FPrint.Context() + + cls.dev = None + for dev in cls.ctx.get_devices(): + # We might have a USB device in the test system that needs skipping + if dev.get_driver() == 'virtual_image': + cls.dev = dev + break + + assert cls.dev is not None, "You need to compile with virtual_image for testing" + + cls.prints = {} + for f in glob.glob(os.path.join(imgdir, '*.png')): + n = os.path.basename(f)[:-4] + cls.prints[n] = load_image(f) + + @classmethod + def tearDownClass(cls): + shutil.rmtree(cls.tmpdir) + + def setUp(self): + self.dev.open_sync() + + def tearDown(self): + self.dev.close_sync() + + def report_finger(self, state): + with Connection(self.sockaddr) as con: + con.write(struct.pack('ii', -1, 1 if state else 0)) + + def send_image(self, image): + img = self.prints[image] + with Connection(self.sockaddr) as con: + mem = img.get_data() + mem = mem.tobytes() + assert len(mem) == img.get_width() * img.get_height() + + encoded_img = struct.pack('ii', img.get_width(), img.get_height()) + encoded_img += mem + + con.sendall(encoded_img) + + def test_capture_prevents_close(self): + cancel = Gio.Cancellable() + def cancelled_cb(dev, res, obj): + print("Capture operation finished") + with self.assertRaises(GLib.GError) as cm: + dev.capture_finish(res) + assert cm.exception.matches(Gio.io_error_quark(), Gio.IOErrorEnum.CANCELLED) + print("Capture cancelled as expected") + obj._cancelled = True + + self._cancelled = False + self.dev.capture(True, cancel, cancelled_cb, self) + + with self.assertRaises(GLib.GError) as cm: + self.dev.close_sync() + assert cm.exception.matches(FPrint.device_error_quark(), FPrint.DeviceError.BUSY) + + cancel.cancel() + while not self._cancelled: + ctx.iteration(True) + + def enroll_print(self, image): + self._step = 0 + self._enrolled = None + + def progress_cb(dev, step, fp, user_data): + print('Print was processed, continuing') + self._step = step + + def done_cb(dev, res): + print("Enroll done") + fp = dev.enroll_finish(res) + self._enrolled = fp + + template = FPrint.Print.new(self.dev) + template.props.finger = FPrint.Finger.LEFT_THUMB + template.props.username = "testuser" + template.props.description = "test print" + datetime = GLib.DateTime.new_now_local() + date = GLib.Date() + date.set_dmy(*datetime.get_ymd()[::-1]) + template.props.enroll_date = date + self.dev.enroll(template, None, progress_cb, tuple(), done_cb) + + # Note: Assumes 5 enroll steps for this device! + self.send_image(image) + while self._step < 1: + ctx.iteration(True) + + self.send_image(image) + while self._step < 2: + ctx.iteration(True) + + self.send_image(image) + while self._step < 3: + ctx.iteration(True) + + self.send_image(image) + while self._step < 4: + ctx.iteration(True) + + self.send_image(image) + while self._enrolled is None: + ctx.iteration(True) + + return self._enrolled + + def test_enroll_verify(self): + done = False + + def verify_cb(dev, res): + match, fp = dev.verify_finish(res) + self._verify_match = match + self._verify_fp = fp + + fp_whorl = self.enroll_print('whorl') + + self._verify_match = None + self._verify_fp = None + self.dev.verify(fp_whorl, None, verify_cb) + self.send_image('whorl') + while self._verify_match is None: + ctx.iteration(True) + assert(self._verify_match) + + self._verify_match = None + self._verify_fp = None + self.dev.verify(fp_whorl, None, verify_cb) + self.send_image('tented_arch') + while self._verify_match is None: + ctx.iteration(True) + assert(not self._verify_match) + + def test_identify(self): + done = False + + def verify_cb(dev, res): + r, fp = dev.verify_finish(res) + self._verify_match = r + self._verify_fp = fp + + fp_whorl = self.enroll_print('whorl') + fp_tented_arch = self.enroll_print('tented_arch') + + def identify_cb(dev, res): + print('Identify finished') + self._identify_match, self._identify_fp = self.dev.identify_finish(res) + + self._identify_fp = None + self.dev.identify([fp_whorl, fp_tented_arch], None, identify_cb) + self.send_image('tented_arch') + while self._identify_fp is None: + ctx.iteration(True) + assert(self._identify_match is fp_tented_arch) + + self._identify_fp = None + self.dev.identify([fp_whorl, fp_tented_arch], None, identify_cb) + self.send_image('whorl') + while self._identify_fp is None: + ctx.iteration(True) + assert(self._identify_match is fp_whorl) + + def test_verify_serialized(self): + done = False + + def verify_cb(dev, res): + r, fp = dev.verify_finish(res) + self._verify_match = r + self._verify_fp = fp + + fp_whorl = self.enroll_print('whorl') + + fp_data = fp_whorl.serialize() + fp_whorl_new = FPrint.Print.deserialize(fp_data) + + # The serialized/deserialized prints need to be equal + assert fp_whorl.equal(fp_whorl_new) + + datetime = GLib.DateTime.new_now_local() + date = GLib.Date() + date.set_dmy(*datetime.get_ymd()[::-1]) + + assert fp_whorl_new.props.username == "testuser" + assert fp_whorl_new.props.description == "test print" + assert fp_whorl_new.props.finger == FPrint.Finger.LEFT_THUMB + assert date.compare(fp_whorl_new.props.enroll_date) == 0 + + self._verify_match = None + self._verify_fp = None + self.dev.verify(fp_whorl_new, None, verify_cb) + self.send_image('whorl') + while self._verify_match is None: + ctx.iteration(True) + assert(self._verify_match) + + self._verify_match = None + self._verify_fp = None + self.dev.verify(fp_whorl_new, None, verify_cb) + self.send_image('tented_arch') + while self._verify_match is None: + ctx.iteration(True) + assert(not self._verify_match) + + +# avoid writing to stderr +unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2)) + From 36777896c2259b4163ecf90b2be15efa2e7b521b Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 1 Jul 2019 17:31:57 +0200 Subject: [PATCH 24/73] CI: Update dependencies and run tests --- .gitlab-ci.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4ddbd9d9..cdb5165c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,10 +2,12 @@ image: fedora:rawhide stages: - build - test + - flatpack variables: - DEPENDENCIES: libusb1-devel glib2-devel nss-devel pixman-devel systemd meson gtk-doc + DEPENDENCIES: libgusb-devel glib2-devel nss-devel pixman-devel systemd meson gtk-doc gcc gcc-c++ glibc-devel libX11-devel libXv-devel gtk3-devel flatpak-builder + gobject-introspection-devel python3-cairo python3-gobject BUNDLE: "org.freedesktop.libfprint.Demo.flatpak" LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546" @@ -13,7 +15,7 @@ variables: script: - dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES # Build with a driver that doesn't need imaging, or nss - - meson -Ddrivers=elan . _build + - meson -Ddrivers=$driver . _build - ninja -C _build - rm -rf _build/ @@ -32,10 +34,20 @@ variables: build: stage: build + variables: + driver: virtual_image <<: *build_one_driver <<: *build # <<: *check_abi +test: + stage: test + script: + - dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES + - meson -Ddrivers=virtual_image . _build + - ninja -C _build + - meson test -C _build --verbose --no-stdsplit + .flatpak_script_template: &flatpak_script script: - flatpak-builder --stop-at=${FLATPAK_MODULE} app ${MANIFEST_PATH} @@ -61,7 +73,7 @@ build: flatpak master: image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master - stage: test + stage: flatpack variables: MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json" # From demo/org.freedesktop.libfprint.Demo.json From 4640e3f5b00903d406edf41bc5490bbf661d0518 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 10 Jul 2019 11:59:09 +0200 Subject: [PATCH 25/73] demo: Use 3.32 runtime for flatpak We do not need the master runtime environment and the stable 3.32 one is more readily available to users. --- .gitlab-ci.yml | 2 +- demo/org.freedesktop.libfprint.Demo.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cdb5165c..92b0f3ff 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -72,7 +72,7 @@ test: <<: *flatpak_artifacts flatpak master: - image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master + image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.32 stage: flatpack variables: MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json" diff --git a/demo/org.freedesktop.libfprint.Demo.json b/demo/org.freedesktop.libfprint.Demo.json index 9c5c7b28..7429670e 100644 --- a/demo/org.freedesktop.libfprint.Demo.json +++ b/demo/org.freedesktop.libfprint.Demo.json @@ -1,7 +1,7 @@ { "app-id": "org.freedesktop.libfprint.Demo", "runtime": "org.gnome.Platform", - "runtime-version": "master", + "runtime-version": "3.32", "sdk": "org.gnome.Sdk", "command": "gtk-libfprint-test", "finish-args": [ From 6ec11a2b26edbb82d15d98f63322b66a88a5efa0 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 3 Jul 2019 23:51:58 +0200 Subject: [PATCH 26/73] cocci: Add spatch/coccinelle patches for driver porting This is an impartial set of transformations to help port the drivers to the new interfaces. --- cocci/00-misc-cleanups.cocci | 78 ++++++ cocci/01-endpoint.cocci | 8 + cocci/02-type-renames.cocci | 64 +++++ cocci/03-function-renames.cocci | 80 ++++++ cocci/04-misc-renames.cocci | 29 +++ cocci/05-libusb-1.cocci | 118 +++++++++ cocci/06-libusb-callback-1.cocci | 344 +++++++++++++++++++++++++ cocci/07-libusb-fill.cocci | 163 ++++++++++++ cocci/08-ssm.cocci | 20 ++ cocci/10-driver.cocci | 386 ++++++++++++++++++++++++++++ cocci/99-insert-checking-code.cocci | 38 +++ cocci/all.cocci | 19 ++ cocci/apply-all | 9 + 13 files changed, 1356 insertions(+) create mode 100644 cocci/00-misc-cleanups.cocci create mode 100644 cocci/01-endpoint.cocci create mode 100644 cocci/02-type-renames.cocci create mode 100644 cocci/03-function-renames.cocci create mode 100644 cocci/04-misc-renames.cocci create mode 100644 cocci/05-libusb-1.cocci create mode 100644 cocci/06-libusb-callback-1.cocci create mode 100644 cocci/07-libusb-fill.cocci create mode 100644 cocci/08-ssm.cocci create mode 100644 cocci/10-driver.cocci create mode 100644 cocci/99-insert-checking-code.cocci create mode 100644 cocci/all.cocci create mode 100755 cocci/apply-all diff --git a/cocci/00-misc-cleanups.cocci b/cocci/00-misc-cleanups.cocci new file mode 100644 index 00000000..dfaba641 --- /dev/null +++ b/cocci/00-misc-cleanups.cocci @@ -0,0 +1,78 @@ +// Remove USB device reset, lets hope that we do not need this. +// If we do, maybe do it elsewhere? +@@ +identifier r; +@@ +- r = libusb_reset_device(...); +- if (r != 0) { ... } + +// Functions that have uneccessary returns (i.e. error cannot happen after refactoring) +// NOTE: Make sure that these function are fine to modify in *all* drivers! +@ prior_int_func @ +identifier func =~ "capture_chunk_async|alksdjflkajsfd"; +expression res, res2; +@@ +-int func ++void func + (...) +{ + <... +- return res2; ++ res2; + ...> +- return res; ++ res; +} + +@@ +identifier prior_int_func.func; +identifier res; +@@ +-res = func ++func + (...); +( +-if (res < 0) { ... } +| +-if (res != 0) { ... } +) + +// Remove useless checks of fpi_timeout_add return values +@@ +expression a1, a2, a3, a4; +@@ +-if (fpi_timeout_add(a1, a2, a3, a4) == NULL) { ... } ++fpi_timeout_add(a1, a2, a3, a4); + +@@ +identifier timeout; +expression a1, a2, a3, a4; +@@ +timeout = fpi_timeout_add(a1, a2, a3, a4); +-if (timeout == NULL) { ... } + + +// The VFS5011 driver has some stupid "radiation detected" logic, that should be asserts +@@ +expression expr; +@@ +-if ((expr)) { +- ... +- fp_err("Radiation detected!"); +- ... +-} ++g_assert(!expr); + + +// A number of drivers call both fpi_imgdev_session_error *and* fpi_ssm_mark_failed. +// While this worked fine, it is plain wrong and considerably complicates memory +// management of the errors. +// Remove this duplication +@@ +expression dev; +expression ssm; +expression error; +@@ +- fpi_imgdev_session_error(dev, error); + fpi_ssm_mark_failed(ssm, error); + diff --git a/cocci/01-endpoint.cocci b/cocci/01-endpoint.cocci new file mode 100644 index 00000000..d3507208 --- /dev/null +++ b/cocci/01-endpoint.cocci @@ -0,0 +1,8 @@ +@@ +@@ +- LIBUSB_ENDPOINT_IN ++ FP_USB_ENDPOINT_IN +@@ +@@ +- LIBUSB_ENDPOINT_OUT ++ FP_USB_ENDPOINT_OUT diff --git a/cocci/02-type-renames.cocci b/cocci/02-type-renames.cocci new file mode 100644 index 00000000..e37fc92f --- /dev/null +++ b/cocci/02-type-renames.cocci @@ -0,0 +1,64 @@ +@ fp_img_dev @ +typedef FpImageDevice; +@@ +-struct fp_img_dev ++FpImageDevice + +@ FpImageDevice_cast @ +typedef FpImageDevice; +expression dev; +@@ +-(FpImageDevice*) dev ++FP_IMAGE_DEVICE (dev) + +@ fp_dev @ +typedef FpDevice; +@@ +-struct fp_dev ++FpDevice + +@ FpDevice_cast @ +typedef FpDevice; +expression dev; +@@ +-(FpDevice*) dev ++FP_DEVICE (dev) + +@ FP_DEV_cast @ +expression dev; +@@ +- FP_DEV (dev) ++ FP_DEVICE (dev) + +@ FP_IMG_DEV_cast @ +expression dev; +@@ +- FP_IMG_DEV (dev) ++ FP_IMAGE_DEVICE (dev) + +@ fpi_ssm @ +typedef fpi_ssm; +typedef FpSsm; +@@ +-fpi_ssm ++FpSsm + +@ fp_img @ +typedef FpImage; +@@ +-struct fp_img ++FpImage + +@ libusb_transfer @ +typedef FpUsbTransfer; +@@ +-struct libusb_transfer ++FpUsbTransfer + +@ libusb_device_handle @ +typedef libusb_device_handle; +typedef GUsbDevice; +@@ +-libusb_device_handle ++GUsbDevice + diff --git a/cocci/03-function-renames.cocci b/cocci/03-function-renames.cocci new file mode 100644 index 00000000..cd261529 --- /dev/null +++ b/cocci/03-function-renames.cocci @@ -0,0 +1,80 @@ +@@ +expression w; +expression h; +expression status; +expression dev; +expression a1, a2, a3; +@@ +( +-fpi_img_new(w * h) ++fp_image_new(w, h) +| +-fpi_ssm_new ++fp_ssm_new +| +-fpi_ssm_free ++fp_ssm_free +| +-fpi_ssm_start ++fp_ssm_start +| +-fpi_ssm_start_subsm ++fp_ssm_start_subsm +| +-fpi_ssm_next_state ++fp_ssm_next_state +| +-fpi_ssm_jump_to_state ++fp_ssm_jump_to_state +| +-fpi_ssm_mark_completed ++fp_ssm_mark_completed +| +-fpi_ssm_get_user_data ++fp_ssm_get_user_data +| +-fpi_ssm_get_cur_state ++fp_ssm_get_cur_state +| +-fpi_dev_get_usb_dev ++_fp_device_get_usb_device +| +// HACK: We just insert an error return here! +-fpi_imgdev_close_complete(dev) ++_fp_image_device_close_complete(dev, error) +| +-fpi_imgdev_open_complete(dev, 0) ++_fp_image_device_open_complete(dev, NULL) +| +-fpi_imgdev_activate_complete(dev, 0) ++_fp_image_device_activate_complete(dev, NULL) +| +-fpi_imgdev_deactivate_complete(dev) ++_fp_image_device_deactivate_complete(dev, NULL) +| +-fpi_imgdev_report_finger_status(dev, status) ++_fp_image_device_report_finger_status(dev, status) +| +-fpi_imgdev_image_captured(dev, a1) ++_fp_image_device_image_captured(dev, a1) +| +-fpi_imgdev_abort_scan ++_fp_image_device_retry_scan +| +-fpi_std_sq_dev ++_fp_std_sq_dev +| +-fpi_mean_sq_diff_norm ++_fp_mean_sq_diff_norm +| +-fpi_timeout_add(a1, a2, dev, a3) ++_fp_device_add_timeout(dev, a1, a2, a3) +) + +// Some can be nested +@@ +@@ +( +-fpi_ssm_next_state_timeout_cb ++fp_ssm_next_state_timeout_cb +) diff --git a/cocci/04-misc-renames.cocci b/cocci/04-misc-renames.cocci new file mode 100644 index 00000000..8bf40a6e --- /dev/null +++ b/cocci/04-misc-renames.cocci @@ -0,0 +1,29 @@ +@@ +typedef FpImageDeviceState; +@@ +( +-FP_IMG_COLORS_INVERTED ++FP_IMAGE_COLORS_INVERTED +| +-FP_IMG_H_FLIPPED ++FP_IMAGE_H_FLIPPED +| +-FP_IMG_V_FLIPPED ++FP_IMAGE_V_FLIPPED +| +-FP_VERIFY_RETRY_TOO_SHORT ++FP_DEVICE_RETRY_TOO_SHORT +| +-FP_VERIFY_RETRY_CENTER_FINGER ++FP_DEVICE_RETRY_CENTER_FINGER +| +-FP_VERIFY_RETRY ++FP_DEVICE_RETRY +) + +@@ +@@ +( +-enum fp_imgdev_state ++FpImageDeviceState +) diff --git a/cocci/05-libusb-1.cocci b/cocci/05-libusb-1.cocci new file mode 100644 index 00000000..0b6cc48f --- /dev/null +++ b/cocci/05-libusb-1.cocci @@ -0,0 +1,118 @@ + +@ dev_func @ +identifier dev; +identifier func; +@@ +func(..., FpDevice *dev, ...) +{ + ... +} + +@ imgdev_func @ +identifier dev; +identifier func; +@@ +func(..., FpImageDevice *dev, ...) +{ + ... +} + +@ self_func extends driver @ +identifier self; +identifier func; +@@ +func(..., driver_cls *self, ...) +{ + ... +} + +@ transfer_func_imgdev @ +typedef FpUsbTransfer; +identifier imgdev_func.func; +identifier imgdev_func.dev; +identifier transfer; +@@ +func (...) +{ +<... +( +-transfer = fpi_usb_alloc(); ++transfer = fp_usb_transfer_new(FP_DEVICE (dev)); +| +-FpUsbTransfer *transfer = fpi_usb_alloc(); ++FpUsbTransfer *transfer = fp_usb_transfer_new(FP_DEVICE (dev)); +) +...> +} + + +@ transfer_func_dev @ +typedef FpUsbTransfer; +identifier dev_func.func; +identifier dev_func.dev; +identifier transfer; +@@ +func (...) +{ +<... +( +-transfer = fpi_usb_alloc(); ++transfer = fp_usb_transfer_new(dev); +| +-FpUsbTransfer *transfer = fpi_usb_alloc(); ++FpUsbTransfer *transfer = fp_usb_transfer_new(dev); +) +...> +} + +@ transfer_func_self @ +typedef FpUsbTransfer; +identifier self_func.func; +identifier self_func.self; +expression transfer; +@@ +func (...) +{ +<... +-transfer = fpi_usb_alloc(); ++transfer = fp_usb_transfer_new(FP_DEVICE (self)); +...> +} + +// None of the release interface calls had error handling ... +@ extends driver @ +expression usb_dev; +expression interface; +@@ +dev_close(...) +{ ++ GError *error = NULL; +... +-libusb_release_interface(usb_dev, interface); ++g_usb_device_release_interface(usb_dev, interface, 0, &error); +... +} + +@ extends driver @ +expression usb_dev; +expression interface; +identifier imgdev; +identifier r; +@@ +dev_open (..., FpImageDevice *imgdev, ...) +{ ++ GError *error = NULL; +... +-r = libusb_claim_interface(usb_dev, interface); ++if (!g_usb_device_claim_interface(usb_dev, interface, 0, &error)) { ++ _fp_image_device_open_complete (imgdev, error); ++ return; ++ } +( +-if (r != 0) { ... } +| +-if (r < 0) { ... } +) +... +} + diff --git a/cocci/06-libusb-callback-1.cocci b/cocci/06-libusb-callback-1.cocci new file mode 100644 index 00000000..643163a4 --- /dev/null +++ b/cocci/06-libusb-callback-1.cocci @@ -0,0 +1,344 @@ +@ usb_transfer_cb @ +typedef FpUsbTransfer; +typedef FpSsm; +identifier func; +identifier transfer; +identifier dev; +identifier ssm; +@@ +( +-void func(FpUsbTransfer *transfer) ++void func(FpUsbTransfer *transfer, ++ FpDevice *device, ++ gpointer user_data, ++ GError *error) +{ +... +} +| +// this is weird, one function in uru4000 didn't get the types +// converted by earlier rules. But, this does not seem to work either. +-void func(\(FpUsbTransfer*\|struct libusb_transfer*\) transfer, +- \(FpDevice*\|struct fp_dev*\) dev, +- \(FpSsm*\|fpi_ssm*\) ssm, +- void* user_data) ++void func(FpUsbTransfer *transfer, ++ FpDevice *dev, ++ gpointer user_data, ++ GError *error) +{ ++ FpSsm *ssm = transfer->ssm; +... +} +) + + +@ errors_generic_1 @ +identifier usb_transfer_cb.func; +identifier usb_transfer_cb.transfer; +@@ +func(...) +{ + <... +( +- (transfer->status != LIBUSB_TRANSFER_COMPLETED) ++ error +| +- (transfer->status == LIBUSB_TRANSFER_COMPLETED) ++ !error +| +- (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) ++ g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) +) + ...> +} + + +@ errors_1 @ +identifier usb_transfer_cb.func; +identifier usb_transfer_cb.transfer; +expression ssm; +statement S; +@@ +func(...) +{ + <... + if (error) { +( + ... +- fpi_ssm_mark_failed (ssm, ...) ++ fp_ssm_mark_failed (ssm, error) + ... +| + ... +- fpi_imgdev_session_error (...) ++ _fp_image_device_session_error (FP_IMAGE_DEVICE (device), error) + ... +) + } + ...> +} + +@ errors_1_alt @ +identifier usb_transfer_cb.func; +identifier usb_transfer_cb.transfer; +expression ssm; +statement S; +@@ +func(...) +{ + <... + if (!error) { ... } + else { +( + ... +- fpi_ssm_mark_failed (ssm, ...) ++ fp_ssm_mark_failed (ssm, error) + ... +| + ... +- fpi_imgdev_session_error (...) ++ _fp_image_device_session_error (FP_IMAGE_DEVICE (device), error) + ... +) + } + ...> +} + +@ errors_2 @ +identifier usb_transfer_cb.func; +identifier usb_transfer_cb.transfer; +expression ssm; +@@ +func(...) +{ + <... + if (transfer->length != transfer->actual_length) { ++ _Pragma("GCC warning \"Driver should probably set short_is_error instead!\""); + ... +( +- fpi_ssm_mark_failed (ssm, ...); ++ fp_ssm_mark_failed (ssm, g_error_new (G_USB_DEVICE_ERROR, ++ G_USB_DEVICE_ERROR_IO, ++ "Short USB transfer!")); +| +- fpi_imgdev_session_error (...); ++ _fp_image_device_session_error (FP_IMAGE_DEVICE (device), ++ g_error_new (G_USB_DEVICE_ERROR, ++ G_USB_DEVICE_ERROR_IO, ++ "Short USB transfer!")); +) + ... + } + ...> +} + +@ not_useful_error_prints @ +identifier usb_transfer_cb.func; +@@ +func(...) +{ + <... +- fp_err (...); + ... +( + fp_ssm_mark_failed (...); +| + _fp_image_device_session_error (...); +) + ...> +} + +@ error_or_wrong_length @ +identifier usb_transfer_cb.func; +identifier usb_transfer_cb.transfer; +expression ssm; +@@ +func(...) +{ + <... +- if (error || (transfer->length != transfer->actual_length)) ++ if (error) + { ++ _Pragma("GCC warning \"Driver needs to set short_is_error for this branch to be taken!\""); + <... +( +- fpi_ssm_mark_failed (ssm, ...); ++ fp_ssm_mark_failed (ssm, error); +| +- fpi_imgdev_session_error (...); ++ _fp_image_device_session_error (FP_IMAGE_DEVICE (device), error); +) + ...> + } + ...> +} + +@ error_or_wrong_length_2 @ +identifier usb_transfer_cb.func; +identifier usb_transfer_cb.transfer; +expression ssm; +@@ +func(...) +{ + <... +- if (!error && (transfer->length == transfer->actual_length)) ++ if (!error) + { ... } + else { ++ _Pragma("GCC warning \"Driver needs to set short_is_error for this branch to be taken!\""); + <... +( +- fpi_ssm_mark_failed (ssm, ...); ++ fp_ssm_mark_failed (ssm, error); +| +- fpi_imgdev_session_error (...); ++ _fp_image_device_session_error (FP_IMAGE_DEVICE (device), error); +) + ...> + } + ...> +} + + +@@ +identifier usb_transfer_cb.func; +identifier usb_transfer_cb.transfer; +identifier out; +@@ +func(...) +{ +<... +- goto out; ++ return; +...> +-out: +( +- g_free(transfer->buffer); +| +) +- libusb_free_transfer (transfer); +} + +@@ +identifier usb_transfer_cb.func; +identifier usb_transfer_cb.transfer; +@@ +func(...) +{ + <... +( +- g_free(transfer->buffer); +| +) +- libusb_free_transfer (transfer); + ... + return; + ...> +} + + +@@ +identifier usb_transfer_cb.func; +identifier usb_transfer_cb.transfer; +@@ +func(...) +{ + <... +- transfer->user_data ++ user_data + ...> +} + +@@ +typedef gint; +identifier usb_transfer_cb.func; +identifier usb_transfer_cb.transfer; +@@ +func(...) +{ +<... +( + fp_dbg +| + fp_warn +| + fp_err +) + (..., +- transfer->length ++ (gint) transfer->length + , ...); +...> +} + +@@ +typedef gint; +identifier usb_transfer_cb.func; +identifier usb_transfer_cb.transfer; +@@ +func(...) +{ +<... +( + fp_dbg +| + fp_warn +| + fp_err +) + (..., +- transfer->actual_length ++ (gint) transfer->actual_length + , ...); +...> +} + +@@ +identifier usb_transfer_cb.func; +identifier usb_transfer_cb.transfer; +identifier ssm_var; +gpointer user_data; +@@ +func(...) +{ + ... +( +- FpSsm *ssm_var = (FpSsm*) user_data; +| +- FpSsm *ssm_var = user_data; +) + <... +- ssm_var ++ transfer->ssm + ...> +} + +// A lot of drivers abuse the SSM user_data for the driver +// Convert FpImageDevice usage to simple cast +@@ +identifier usb_transfer_cb.func; +identifier dev; +@@ +func(...) +{ +-FpImageDevice *dev = ...; ++FpImageDevice *dev = FP_IMAGE_DEVICE (device); +... +} + +// A lot of drivers abuse the SSM user_data for the driver +// Remove FpDevice getter and use argument +@@ +identifier usb_transfer_cb.func; +identifier arg; +identifier dev; +@@ +func(..., FpDevice *arg, ...) +{ +-FpDevice *dev = ...; +<... +-dev ++arg +...> +} diff --git a/cocci/07-libusb-fill.cocci b/cocci/07-libusb-fill.cocci new file mode 100644 index 00000000..04fca269 --- /dev/null +++ b/cocci/07-libusb-fill.cocci @@ -0,0 +1,163 @@ +/////////////////////////////////////////////////////////////////////////// +// bulk transfers +@@ +typedef FpUsbTransfer; +expression transfer; +expression usb_dev; +expression endpoint; +expression data; +expression size; +expression cb; +expression user_data; +expression timeout; +identifier ret; +@@ +- libusb_fill_bulk_transfer(transfer, usb_dev, endpoint, data, size, cb, user_data, timeout); ++ fp_usb_transfer_fill_bulk_full(transfer, endpoint, data, size, NULL); ++ fp_usb_transfer_submit(transfer, timeout, NULL, cb, user_data); ++ fp_usb_transfer_unref(transfer); +( +- ret = libusb_submit_transfer(transfer); + ... +( +- if (ret < 0) { ... } +| +- if (ret != 0) { ... } +| +) +| +- if (libusb_submit_transfer(transfer)) { ... } +| +- if (libusb_submit_transfer(transfer) < 0) { ... } +| +- libusb_submit_transfer(transfer); +) + +/////////////////////////////////////////////////////////////////////////// +// bulk transfers +@@ +typedef FpUsbTransfer; +expression transfer; +expression dev; +expression transfer_ssm; +expression endpoint; +expression data; +expression size; +expression cb; +expression user_data; +expression timeout; +expression storage; +identifier ret; +@@ +- transfer = fpi_usb_fill_bulk_transfer(dev, transfer_ssm, endpoint, data, size, cb, user_data, timeout); ++ transfer = fp_usb_transfer_new (dev); ++ transfer->ssm = transfer_ssm; ++ fp_usb_transfer_fill_bulk_full(transfer, endpoint, data, size, NULL); ++ fp_usb_transfer_submit(transfer, timeout, NULL, cb, user_data); ++ fp_usb_transfer_unref(transfer); +( + storage = transfer; +| +) +( +- ret = fpi_usb_submit_transfer(transfer); + ... +( +- if (ret < 0) { ... } +| +- if (ret != 0) { ... } +| +) +| +- if (fpi_usb_submit_transfer(transfer)) { ... } +| +- if (fpi_usb_submit_transfer(transfer) < 0) { ... } +| +- fpi_usb_submit_transfer(transfer); +) + +// The following only happens due to some prior simplifications we did +@@ +typedef FpUsbTransfer; +expression transfer; +expression usb_dev; +expression endpoint; +expression data; +expression size; +expression cb; +expression user_data; +expression timeout; +identifier ret; +@@ +- libusb_fill_bulk_transfer(transfer, usb_dev, endpoint, data, size, cb, user_data, timeout); +- libusb_submit_transfer(transfer); ++ fp_usb_transfer_fill_bulk_full(transfer, endpoint, data, size, NULL); ++ fp_usb_transfer_submit(transfer, timeout, NULL, cb, user_data); ++ fp_usb_transfer_unref(transfer); + + +/////////////////////////////////////////////////////////////////////////// +// control transfers +@@ +typedef FpUsbTransfer; +expression timeout; +expression direction; +expression request_type; +expression recipient; +expression request; +expression value; +expression index; +expression length; +expression callback; +expression user_data; +expression usb_dev; +identifier ret; +@@ +( +- data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE) +| +- data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + ...) +| +- data = g_malloc0(LIBUSB_CONTROL_SETUP_SIZE) +| +- data = g_malloc0(LIBUSB_CONTROL_SETUP_SIZE + ...) +) +- ; ++ _Pragma("GCC warning \"control transfer filling is a mess due to automatic translation\""); ++ fp_usb_transfer_fill_control(transfer, !((request_type) & 0x80), ((request_type) >> 5) & 0x3, (request_type) & 0x1f, request, value, index, length); ++ data = transfer->buffer; ++ fp_usb_transfer_submit(transfer, timeout, NULL, callback, user_data); ++ fp_usb_transfer_unref(transfer); + ... +- libusb_fill_control_setup(data, request_type, request, value, index, length); +- libusb_fill_control_transfer(transfer, usb_dev, data, callback, user_data, timeout); + <... +- LIBUSB_CONTROL_SETUP_SIZE + ...> +- ret = libusb_submit_transfer(transfer); +( +- if (ret < 0) { ... } +| +) + + +/////////////////////////////////////////////////////////////////////////// +// We have a field in the transfer just for a state machine, use that +// We also later modify all similar code on the callback side to use that field +// instead. +@@ +expression transfer; +expression timeout; +expression cb; +@@ ++ transfer->ssm = ssm; +- fp_usb_transfer_submit(transfer, timeout, NULL, cb, ssm); ++ fp_usb_transfer_submit(transfer, timeout, NULL, cb, NULL); +@@ +expression transfer; +expression timeout; +expression cb; +@@ +- fp_usb_transfer_submit(transfer, timeout, NULL, cb, dev); ++ fp_usb_transfer_submit(transfer, timeout, NULL, cb, NULL); + diff --git a/cocci/08-ssm.cocci b/cocci/08-ssm.cocci new file mode 100644 index 00000000..00397797 --- /dev/null +++ b/cocci/08-ssm.cocci @@ -0,0 +1,20 @@ +@ ssm_callbacks @ +identifier ssm; +identifier cb; +@@ +fp_ssm_start(ssm, cb) + +@@ +identifier ssm_callbacks.cb; +identifier ssm; +identifier dev; +identifier user_data; +@@ +void cb(FpSsm *ssm, FpDevice *dev, void* user_data ++ , GError *error + ) +{ ++ _Pragma("GCC warning \"Check that error is returned/free'ed properly!\""); + ... +} + diff --git a/cocci/10-driver.cocci b/cocci/10-driver.cocci new file mode 100644 index 00000000..cac0212d --- /dev/null +++ b/cocci/10-driver.cocci @@ -0,0 +1,386 @@ +@ orig_driver_struct @ +identifier driver_struct; +@@ +struct fp_img_driver driver_struct = { + ..., +}; + +// Grab the type of the main device struct using a rather blind fashion, +// and remove it from the init function. +// This assume that only device init calls fp_dev_set_instance_data, which +// is a fair assumption after all +@ orig_device_struct @ +type device_struct; +expression dev; +identifier dev_init; +identifier data; +@@ +dev_init(...) +{ + // Note: We redefine it to an instance access for now, which will be + // made to work correctly with a later transform/cast. +... + device_struct *data; +... +( +- data = g_malloc0(sizeof(*data)); ++ data = FP_INSTANCE_DATA(dev); +| +- data = (device_struct*) g_malloc0(sizeof(*data)); ++ data = FP_INSTANCE_DATA(dev); +| +- data = g_malloc0(sizeof(device_struct)); ++ data = FP_INSTANCE_DATA(dev); +) +... +- fp_dev_set_instance_data(dev, data); +... +} + +@ driver_ids @ +typedef FpIdEntry; +identifier driver_id_table; +@@ +-const struct usb_id driver_id_table[] = { ++const FpIdEntry driver_id_table[] = { + ... +}; + + +@ @ +identifier driver_ids.driver_id_table; +expression entry_vid; +expression entry_pid; +@@ +const FpIdEntry driver_id_table[] = { + ..., { +- .vendor = entry_vid, .product = entry_pid, ++ .vid = entry_vid, .pid = entry_pid, + }, ... +}; + +@ @ +identifier driver_ids.driver_id_table; +expression entry_vid; +expression entry_pid; +expression entry_data; +@@ +const FpIdEntry driver_id_table[] = { + ..., { +- .vendor = entry_vid, .product = entry_pid, .device_data = entry_data ++ .vid = entry_vid, .pid = entry_pid, .driver_data = entry_data + }, ... +}; + +@ @ +identifier driver_ids.driver_id_table; +expression entry_vid; +expression entry_pid; +expression entry_data; +@@ +const FpIdEntry driver_id_table[] = { + ..., { +- entry_vid, entry_pid, entry_data ++ .vid = entry_vid, .pid = entry_pid, .driver_data = entry_data + }, ... +}; + + + +@ driver_info extends orig_driver_struct @ +expression driver_full_name; +identifier driver_id_table; +identifier dev_open; +identifier dev_close; +identifier dev_scan_type; +@@ +struct fp_img_driver driver_struct = { + .driver = { + .full_name = driver_full_name, + .id_table = driver_id_table, + .scan_type = dev_scan_type, + }, + + .open = dev_open, + .close = dev_close, +}; + +@ script:python driver_gobj @ +driver_struct << orig_driver_struct.driver_struct; + +driver_id; +driver_init; +driver_cls; +_driver_cls; +driver_klass; +driver_class_init; +driver_ns; +driver_cast; +driver_cast_no_prefix; +@@ + +import os + +driver_id = driver_struct.split('_')[:-1] + +driver_cls = "FpDevice" + "".join(d[0].upper() + d[1:] for d in driver_id) +driver_id = '_'.join(driver_id) + +driver_ns = "fp_device_" + driver_id +driver_cast = driver_ns.upper() +driver_cast_no_prefix = driver_ns.upper()[3:] + +coccinelle.driver_id = cocci.make_expr('"%s"' % driver_id) +coccinelle.driver_cls = cocci.make_type(driver_cls) +coccinelle._driver_cls = cocci.make_type('struct _' + driver_cls) +coccinelle.driver_klass = cocci.make_type(driver_cls + 'Class') +coccinelle.driver_ns = cocci.make_ident(driver_ns) +coccinelle.driver_init = cocci.make_ident(driver_ns + '_init') +coccinelle.driver_class_init = cocci.make_ident(driver_ns + '_class_init') +coccinelle.driver_cast = cocci.make_ident(driver_cast) +coccinelle.driver_cast_no_prefix = cocci.make_ident(driver_cast_no_prefix) + +############################################################################# + +@ driver @ +typedef FpDeviceClass; +typedef FpImageDeviceClass; + +type orig_device_struct.device_struct; + +identifier orig_driver_struct.driver_struct; + +expression driver_gobj.driver_id; +identifier driver_gobj.driver_ns; +identifier driver_gobj.driver_init; +identifier driver_gobj.driver_class_init; +identifier driver_gobj.driver_cast; +identifier driver_gobj.driver_cast_no_prefix; +type driver_gobj.driver_cls; +type driver_gobj._driver_cls; +type driver_gobj.driver_klass; + +expression driver_info.driver_full_name; +identifier driver_info.driver_id_table; +identifier driver_info.dev_open; +identifier driver_info.dev_close; +identifier driver_info.dev_scan_type; +@@ +struct fp_img_driver driver_struct = { + ... +}; + ++static void ++driver_init(driver_cls *self) ++{ ++} ++ ++static void ++driver_class_init(driver_klass *klass) ++{ ++ FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); ++ FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); ++ ++ dev_class->id = driver_id; ++ dev_class->full_name = driver_full_name; ++ dev_class->type = FP_DEVICE_TYPE_USB; ++ dev_class->id_table = driver_id_table; ++ dev_class->scan_type = dev_scan_type; ++ ++ img_class->img_open = dev_open; ++ img_class->img_close = dev_close; ++ IMG_CLASS_FUNCS; ++} + +///////////////////////////////////////////////////////////////////////// +@ optional_activate extends driver @ +identifier dev_activate; +@@ +struct fp_img_driver driver_struct = { +- .activate = dev_activate, +}; +@@ +identifier optional_activate.dev_activate; +@@ ++ img_class->activate = dev_activate; + IMG_CLASS_FUNCS; + +///////////////////////////////////////////////////////////////////////// +@ optional_deactivate extends driver @ +identifier dev_deactivate; +@@ +struct fp_img_driver driver_struct = { +- .deactivate = dev_deactivate, +}; +@@ +identifier optional_deactivate.dev_deactivate; +@@ ++ img_class->deactivate = dev_deactivate; + IMG_CLASS_FUNCS; + +///////////////////////////////////////////////////////////////////////// +@ optional_change_state extends driver @ +identifier dev_change_state; +@@ +struct fp_img_driver driver_struct = { +- .change_state = dev_change_state, +}; +@@ +identifier optional_change_state.dev_change_state; +@@ ++ img_class->change_state = dev_change_state; + IMG_CLASS_FUNCS; + +///////////////////////////////////////////////////////////////////////// +@ optional_bz3 extends driver @ +expression dev_bz3_threshold; +@@ +struct fp_img_driver driver_struct = { +- .bz3_threshold = dev_bz3_threshold, +}; +@@ +expression optional_bz3.dev_bz3_threshold; +@@ ++ ++ img_class->bz3_threshold = dev_bz3_threshold; + IMG_CLASS_FUNCS; + +///////////////////////////////////////////////////////////////////////// +@ optional_img_size extends driver @ +expression dev_img_width; +expression dev_img_height; +@@ +struct fp_img_driver driver_struct = { +- .img_width = dev_img_width, +- .img_height = dev_img_height, +}; +@@ +expression optional_img_size.dev_img_width; +expression optional_img_size.dev_img_height; +@@ ++ ++ img_class->img_width = dev_img_width; ++ img_class->img_height = dev_img_height; + IMG_CLASS_FUNCS; + +@ remove_placeholder extends driver @ +@@ +- IMG_CLASS_FUNCS; + +@ remove_orig extends driver @ +@@ +-struct fp_img_driver driver_struct = { +- ... +-}; + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// +@ type_declaration extends driver @ +@@ +-device_struct { ++_driver_cls { ++ FpImageDevice parent; ++ + ... +}; ++#include "TYPE_DECLARATION" + +@ extends driver @ +@@ +-#include "TYPE_DECLARATION" + ++G_DECLARE_FINAL_TYPE (driver_cls, driver_ns, FP, driver_cast_no_prefix, FpImageDevice); ++G_DEFINE_TYPE (driver_cls, driver_ns, FP_TYPE_IMAGE_DEVICE); + + +/////////////// +// Change some function declarations +@ extends driver @ +identifier a_driver_data; +@@ +-int ++void +dev_open(... +- ,unsigned long a_driver_data + ) { ... } + +@ extends driver @ +@@ +-int ++void +dev_activate(...) { ... } + + +///////////////////////////////////////////////////////////////////////// +// Replace all old data with a cast to the new class +///////////////////////////////////////////////////////////////////////// +@ rewrite_dev_struct extends driver @ +identifier func; +identifier data; +identifier dev; +@@ +func(...) +{ + ... +( +- device_struct *data; ++ driver_cls *self; + ... +( +- data = FP_INSTANCE_DATA(FP_DEVICE(dev)); ++ data = driver_cast(dev); +| +- data = FP_INSTANCE_DATA(dev); ++ data = driver_cast(dev); +) +| +- device_struct *data = FP_INSTANCE_DATA(FP_DEVICE(dev)); ++ driver_cls *self = driver_cast(dev); +| +- device_struct *data = FP_INSTANCE_DATA(dev); ++ driver_cls *self = driver_cast(dev); +) + ... +} + +@@ +identifier rewrite_dev_struct.func; +identifier rewrite_dev_struct.data; +@@ +func(...) +{ + <... +- data ++ self + ...> +} + +@ extends driver @ +identifier func; +identifier data; +@@ +func(..., +- device_struct *data, ++ driver_cls *self, +...) +{ + <... +- data ++ self + ...> +} + +// Remove unneccessary self check +@@ +@@ +-if (self != NULL) { + ... +-} + +// Remove g_free(self) +@@ +@@ +-g_free(self); + + + diff --git a/cocci/99-insert-checking-code.cocci b/cocci/99-insert-checking-code.cocci new file mode 100644 index 00000000..b830f202 --- /dev/null +++ b/cocci/99-insert-checking-code.cocci @@ -0,0 +1,38 @@ +// If we have matches on error conditions, the we likely have a memory +// mangement error. +@ forall @ +identifier error; +statement S; +@@ +if (<+... g_error_matches(error, ...) ...+>) { ++ _Pragma ("GCC error \"Inserted possibly wrong g_error_free!\""); ++ if (error) ++ g_error_free (error); + ... +} else S + +@ forall @ +identifier error; +@@ +if (<+... g_error_matches(error, ...) ...+>) { ++ _Pragma ("GCC error \"Inserted possibly wrong g_error_free!\""); ++ if (error) ++ g_error_free (error); + ... +} + +@@ +expression transfer; +identifier r; +statement S; +@@ +( +- r = libusb_cancel_transfer(transfer); +- if (r < 0) S ++ _Pragma("GCC warning \"Removed libusb_cancel_transfer call!\""); ++ g_warning("USB transfer %p should be cancelled but was not due to a lack of code migration!", transfer); +| +- libusb_cancel_transfer(transfer); ++ _Pragma("GCC warning \"Removed libusb_cancel_transfer call!\""); ++ g_warning("USB transfer %p should be cancelled but was not due to a lack of code migration!", transfer); +) diff --git a/cocci/all.cocci b/cocci/all.cocci new file mode 100644 index 00000000..f031f411 --- /dev/null +++ b/cocci/all.cocci @@ -0,0 +1,19 @@ +# First some cleanups; some of these are required for the later stuff to work +00-misc-cleanups.cocci +01-endpoint.cocci +04-misc-renames.cocci +03-function-renames.cocci +02-type-renames.cocci + + +# GObject and "driver" defintion +10-driver.cocci + +# +07-libusb-fill.cocci +05-libusb-1.cocci +06-libusb-callback-1.cocci + +08-ssm.cocci + +99-insert-checking-code.cocci diff --git a/cocci/apply-all b/cocci/apply-all new file mode 100755 index 00000000..f2e7f485 --- /dev/null +++ b/cocci/apply-all @@ -0,0 +1,9 @@ +#!/bin/sh + +pushd $( dirname "$0" ) +all="all.cocci" +real="/tmp/real.cocci" +cat "$all" | grep -P '^(?!#).+' | xargs cat >$real || exit 1 +popd + +spatch --sp-file $real "$@" From dac489b7f646f4c5677efb07fce8f24efa921553 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 3 Jul 2019 23:52:56 +0200 Subject: [PATCH 27/73] scripts: Add an uncrustify script It currently will only uncrustify the new internal libfprint code, not the drivers or other parts. --- scripts/uncrustify.cfg | 139 +++++++++++++++++++++++++++++++++++++++++ scripts/uncrustify.sh | 19 ++++++ 2 files changed, 158 insertions(+) create mode 100644 scripts/uncrustify.cfg create mode 100755 scripts/uncrustify.sh diff --git a/scripts/uncrustify.cfg b/scripts/uncrustify.cfg new file mode 100644 index 00000000..c1fb82ec --- /dev/null +++ b/scripts/uncrustify.cfg @@ -0,0 +1,139 @@ +newlines lf + +input_tab_size 8 +output_tab_size 8 + +string_escape_char 92 +string_escape_char2 0 + +# indenting +indent_columns 2 +indent_with_tabs 0 +indent_align_string True +indent_brace 2 +indent_braces false +indent_braces_no_func True +indent_func_call_param false +indent_func_def_param false +indent_func_proto_param false +indent_switch_case 0 +indent_case_brace 2 +indent_paren_close 1 + +# spacing +sp_arith Add +sp_assign Add +sp_enum_assign Add +sp_bool Add +sp_compare Add +sp_inside_paren Remove +sp_inside_fparens Remove +sp_func_def_paren Force +sp_func_proto_paren Force +sp_paren_paren Remove +sp_balance_nested_parens False +sp_paren_brace Remove +sp_before_square Remove +sp_before_squares Remove +sp_inside_square Remove +sp_before_ptr_star Add +sp_between_ptr_star Remove +sp_after_comma Add +sp_before_comma Remove +sp_after_cast Add +sp_sizeof_paren Add +sp_not Remove +sp_inv Remove +sp_addr Remove +sp_member Remove +sp_deref Remove +sp_sign Remove +sp_incdec Remove +sp_attribute_paren remove +sp_macro Force +sp_func_call_paren Force +sp_func_call_user_paren Remove +set func_call_user _ N_ C_ g_autoptr g_auto +sp_brace_typedef add +sp_cond_colon add +sp_cond_question add +sp_defined_paren remove + +# alignment +align_keep_tabs False +align_with_tabs False +align_on_tabstop False +align_number_right False +align_func_params True +align_var_def_span 0 +align_var_def_amp_style 1 +align_var_def_colon true +align_enum_equ_span 0 +align_var_struct_span 2 +align_var_def_star_style 2 +align_var_def_amp_style 2 +align_typedef_span 2 +align_typedef_func 0 +align_typedef_star_style 2 +align_typedef_amp_style 2 + +# newlines +nl_assign_leave_one_liners True +nl_enum_leave_one_liners False +nl_func_leave_one_liners False +nl_if_leave_one_liners False +nl_end_of_file Add +nl_assign_brace Remove +nl_func_var_def_blk 1 +nl_fcall_brace Add +nl_enum_brace Remove +nl_struct_brace Force +nl_union_brace Force +nl_if_brace Force +nl_brace_else Force +nl_elseif_brace Force +nl_else_brace Add +nl_for_brace Force +nl_while_brace Force +nl_do_brace Force +nl_brace_while Force +nl_switch_brace Force +nl_before_case True +nl_after_case False +nl_func_type_name Force +nl_func_proto_type_name Remove +nl_func_paren Remove +nl_func_decl_start Remove +nl_func_decl_args Force +nl_func_decl_end Remove +nl_fdef_brace Force +nl_after_return False +nl_define_macro False +nl_create_if_one_liner False +nl_create_for_one_liner False +nl_create_while_one_liner False +nl_after_semicolon True +nl_multi_line_cond true + +# mod +# I'd like these to be remove, but that removes brackets in if { if { foo } }, which i dislike +# Not clear what to do about that... +mod_full_brace_for Remove +mod_full_brace_if Remove +mod_full_brace_if_chain True +mod_full_brace_while Remove +mod_full_brace_do Remove +mod_full_brace_nl 3 +mod_paren_on_return Remove + +# line splitting +#code_width = 78 +ls_for_split_full True +ls_func_split_full True + +# positioning +pos_bool Trail +pos_conditional Trail + +# custom keywords +set FOR udev_list_entry_foreach diff --git a/scripts/uncrustify.sh b/scripts/uncrustify.sh new file mode 100755 index 00000000..9a82320f --- /dev/null +++ b/scripts/uncrustify.sh @@ -0,0 +1,19 @@ +#!/bin/bash +SRCROOT=`git rev-parse --show-toplevel` +CFG="$SRCROOT/scripts/uncrustify.cfg" +echo "srcroot: $SRCROOT" + +case "$1" in + -c|--check) + OPTS="--check" + ;; + *) + OPTS="--replace --no-backup" + ;; +esac + +pushd "$SRCROOT" +uncrustify -c "$CFG" $OPTS `git ls-tree --name-only -r HEAD | grep -E '(fp|fpi)-.*\.[ch]$' | grep -v nbis | grep -v fpi-byte | grep -v build/` +RES=$? +popd +exit $RES \ No newline at end of file From f119c273fde98bf57b6b7aa36b770f6544cbfbbe Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 4 Jul 2019 17:36:54 +0200 Subject: [PATCH 28/73] upektc_img: Port upektc_img and back in Note that this port currently conflicts with with the upeksonly driver as the revision check is non-functional right now. --- libfprint/drivers/upektc_img.c | 523 +++++++++++++++++---------------- meson.build | 2 +- 2 files changed, 263 insertions(+), 262 deletions(-) diff --git a/libfprint/drivers/upektc_img.c b/libfprint/drivers/upektc_img.c index 988793dc..33f76848 100644 --- a/libfprint/drivers/upektc_img.c +++ b/libfprint/drivers/upektc_img.c @@ -21,14 +21,13 @@ #include "drivers_api.h" #include "upek_proto.h" -#include "aeslib.h" #include "upektc_img.h" -static void start_capture(struct fp_img_dev *dev); -static void start_deactivation(struct fp_img_dev *dev); +static void start_capture(FpImageDevice *dev); +static void start_deactivation(FpImageDevice *dev); -#define EP_IN (1 | LIBUSB_ENDPOINT_IN) -#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT) +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) #define CTRL_TIMEOUT 4000 #define BULK_TIMEOUT 4000 @@ -40,15 +39,20 @@ static void start_deactivation(struct fp_img_dev *dev); #define MAX_RESPONSE_SIZE 2052 #define SHORT_RESPONSE_SIZE 64 -struct upektc_img_dev { +struct _FpiDeviceUpektcImg { + FpImageDevice parent; + unsigned char cmd[MAX_CMD_SIZE]; unsigned char response[MAX_RESPONSE_SIZE]; - unsigned char image_bits[IMAGE_SIZE * 2]; + unsigned char *image_bits; unsigned char seq; size_t image_size; size_t response_rest; gboolean deactivating; }; +G_DECLARE_FINAL_TYPE(FpiDeviceUpektcImg, fpi_device_upektc_img, FPI, + DEVICE_UPEKTC_IMG, FpImageDevice); +G_DEFINE_TYPE(FpiDeviceUpektcImg, fpi_device_upektc_img, FP_TYPE_IMAGE_DEVICE); /****** HELPERS ******/ @@ -72,58 +76,48 @@ static void upektc_img_cmd_update_crc(unsigned char *cmd_buf, size_t size) } static void -upektc_img_submit_req(fpi_ssm *ssm, - struct fp_img_dev *dev, +upektc_img_submit_req(FpiSsm *ssm, + FpImageDevice *dev, const unsigned char *buf, size_t buf_size, unsigned char seq, - libusb_transfer_cb_fn cb) + FpiUsbTransferCallback cb) { - struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); - struct libusb_transfer *transfer = fpi_usb_alloc(); - int r; + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); + FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); BUG_ON(buf_size > MAX_CMD_SIZE); - transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; + memcpy(self->cmd, buf, buf_size); + upektc_img_cmd_fix_seq(self->cmd, seq); + upektc_img_cmd_update_crc(self->cmd, buf_size); - memcpy(upekdev->cmd, buf, buf_size); - upektc_img_cmd_fix_seq(upekdev->cmd, seq); - upektc_img_cmd_update_crc(upekdev->cmd, buf_size); - - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, upekdev->cmd, buf_size, - cb, ssm, BULK_TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + fpi_usb_transfer_fill_bulk_full(transfer, EP_OUT, self->cmd, buf_size, + NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, cb, NULL); + fpi_usb_transfer_unref(transfer); } static void -upektc_img_read_data(fpi_ssm *ssm, - struct fp_img_dev *dev, +upektc_img_read_data(FpiSsm *ssm, + FpImageDevice *dev, size_t buf_size, size_t buf_offset, - libusb_transfer_cb_fn cb) + FpiUsbTransferCallback cb) { - struct libusb_transfer *transfer = fpi_usb_alloc(); - struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); - int r; + FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); - BUG_ON(buf_size > MAX_RESPONSE_SIZE); + BUG_ON(buf_offset + buf_size > MAX_RESPONSE_SIZE); - transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; - - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, upekdev->response + buf_offset, buf_size, - cb, ssm, BULK_TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + fpi_usb_transfer_fill_bulk_full(transfer, EP_IN, + self->response + buf_offset, buf_size, + NULL); + transfer->ssm = ssm; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, cb, NULL); + fpi_usb_transfer_unref(transfer); } /****** CAPTURE ******/ @@ -139,21 +133,19 @@ enum capture_states { CAPTURE_NUM_STATES, }; -static void capture_reqs_cb(struct libusb_transfer *transfer) +static void capture_reqs_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - - if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || - (transfer->length != transfer->actual_length)) { - fpi_ssm_mark_failed(ssm, -EIO); + if (error) { + fpi_ssm_mark_failed(transfer->ssm, error); return; } - switch (fpi_ssm_get_cur_state(ssm)) { + switch (fpi_ssm_get_cur_state(transfer->ssm)) { case CAPTURE_ACK_00_28_TERM: - fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA_TERM); + fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_READ_DATA_TERM); break; default: - fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA); + fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_READ_DATA); break; } } @@ -176,53 +168,54 @@ static int upektc_img_process_image_frame(unsigned char *image_buf, unsigned cha return len; } -static void capture_read_data_cb(struct libusb_transfer *transfer) +static void capture_read_data_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); - unsigned char *data = upekdev->response; - struct fp_img *img; + FpImageDevice *dev = FP_IMAGE_DEVICE(device); + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); + unsigned char *data = self->response; + FpImage *img; size_t response_size; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fp_dbg("request is not completed, %d", transfer->status); - fpi_ssm_mark_failed(ssm, -EIO); + if (error) { + fp_dbg("request is not completed, %s", error->message); + fpi_ssm_mark_failed(transfer->ssm, error); return; } - if (upekdev->deactivating) { + if (self->deactivating) { fp_dbg("Deactivate requested\n"); - fpi_ssm_mark_completed(ssm); + fpi_ssm_mark_completed(transfer->ssm); return; } - fp_dbg("request completed, len: %.4x", transfer->actual_length); + fp_dbg("request completed, len: %.4x", (gint)transfer->actual_length); if (transfer->actual_length == 0) { - fpi_ssm_jump_to_state(ssm, fpi_ssm_get_cur_state(ssm)); + fpi_ssm_jump_to_state(transfer->ssm, + fpi_ssm_get_cur_state(transfer->ssm)); return; } - if (fpi_ssm_get_cur_state(ssm) == CAPTURE_READ_DATA_TERM) { + if (fpi_ssm_get_cur_state(transfer->ssm) == CAPTURE_READ_DATA_TERM) { fp_dbg("Terminating SSM\n"); - fpi_ssm_mark_completed(ssm); + fpi_ssm_mark_completed(transfer->ssm); return; } - if (!upekdev->response_rest) { + if (!self->response_rest) { response_size = ((data[5] & 0x0f) << 8) + data[6]; response_size += 9; /* 7 bytes for header, 2 for CRC */ if (response_size > transfer->actual_length) { fp_dbg("response_size is %lu, actual_length is %d\n", - response_size, transfer->actual_length); + response_size, (gint)transfer->actual_length); fp_dbg("Waiting for rest of transfer"); - BUG_ON(upekdev->response_rest); - upekdev->response_rest = response_size - transfer->actual_length; - fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA); + BUG_ON(self->response_rest); + self->response_rest = response_size - transfer->actual_length; + fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_READ_DATA); return; } } - upekdev->response_rest = 0; + self->response_rest = 0; switch (data[4]) { case 0x00: @@ -233,88 +226,103 @@ static void capture_read_data_cb(struct libusb_transfer *transfer) switch (data[18]) { case 0x0c: /* no finger */ - fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_00_28); + fpi_ssm_jump_to_state(transfer->ssm, + CAPTURE_ACK_00_28); break; case 0x00: /* finger is present! */ - fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_00_28); + fpi_ssm_jump_to_state(transfer->ssm, + CAPTURE_ACK_00_28); break; case 0x1e: /* short scan */ fp_err("short scan, aborting\n"); - fpi_imgdev_abort_scan(dev, FP_VERIFY_RETRY_TOO_SHORT); - fpi_imgdev_report_finger_status(dev, FALSE); - fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_00_28_TERM); + fpi_image_device_retry_scan(dev, + FP_DEVICE_RETRY_TOO_SHORT); + fpi_image_device_report_finger_status(dev, + FALSE); + fpi_ssm_jump_to_state(transfer->ssm, + CAPTURE_ACK_00_28_TERM); break; case 0x1d: /* too much horisontal movement */ fp_err("too much horisontal movement, aborting\n"); - fpi_imgdev_abort_scan(dev, FP_VERIFY_RETRY_CENTER_FINGER); - fpi_imgdev_report_finger_status(dev, FALSE); - fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_00_28_TERM); + fpi_image_device_retry_scan(dev, + FP_DEVICE_RETRY_CENTER_FINGER); + fpi_image_device_report_finger_status(dev, + FALSE); + fpi_ssm_jump_to_state(transfer->ssm, + CAPTURE_ACK_00_28_TERM); break; default: /* some error happened, cancel scan */ fp_err("something bad happened, stop scan\n"); - fpi_imgdev_abort_scan(dev, FP_VERIFY_RETRY); - fpi_imgdev_report_finger_status(dev, FALSE); - fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_00_28_TERM); + fpi_image_device_retry_scan(dev, + FP_DEVICE_RETRY); + fpi_image_device_report_finger_status(dev, + FALSE); + fpi_ssm_jump_to_state(transfer->ssm, + CAPTURE_ACK_00_28_TERM); break; } break; /* Image frame with additional info */ case 0x2c: - fpi_imgdev_report_finger_status(dev, TRUE); + fpi_image_device_report_finger_status(dev, + TRUE); /* Plain image frame */ case 0x24: - upekdev->image_size += - upektc_img_process_image_frame(upekdev->image_bits + upekdev->image_size, - data); - fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_FRAME); + self->image_size += + upektc_img_process_image_frame(self->image_bits + self->image_size, + data); + fpi_ssm_jump_to_state(transfer->ssm, + CAPTURE_ACK_FRAME); break; /* Last image frame */ case 0x20: - upekdev->image_size += - upektc_img_process_image_frame(upekdev->image_bits + upekdev->image_size, - data); - BUG_ON(upekdev->image_size != IMAGE_SIZE); - fp_dbg("Image size is %lu\n", upekdev->image_size); - img = fpi_img_new(IMAGE_SIZE); - img->flags = FP_IMG_PARTIAL; - memcpy(img->data, upekdev->image_bits, IMAGE_SIZE); - fpi_imgdev_image_captured(dev, img); - fpi_imgdev_report_finger_status(dev, FALSE); - fpi_ssm_mark_completed(ssm); + self->image_size += + upektc_img_process_image_frame(self->image_bits + self->image_size, + data); + BUG_ON(self->image_size != IMAGE_SIZE); + fp_dbg("Image size is %lu\n", + self->image_size); + img = fp_image_new(IMAGE_WIDTH, IMAGE_HEIGHT); + memcpy(img->data, self->image_bits, + IMAGE_SIZE); + fpi_image_device_image_captured(dev, img); + fpi_image_device_report_finger_status(dev, + FALSE); + fpi_ssm_mark_completed(transfer->ssm); break; default: fp_err("Unknown response!\n"); - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); break; } break; case 0x08: - fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_08); + fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_ACK_08); break; default: fp_err("Not handled response!\n"); - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); } } -static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capture_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case CAPTURE_INIT_CAPTURE: upektc_img_submit_req(ssm, dev, upek2020_init_capture, sizeof(upek2020_init_capture), - upekdev->seq, capture_reqs_cb); - upekdev->seq++; + self->seq, capture_reqs_cb); + self->seq++; break; case CAPTURE_READ_DATA: case CAPTURE_READ_DATA_TERM: - if (!upekdev->response_rest) + if (!self->response_rest) upektc_img_read_data(ssm, dev, SHORT_RESPONSE_SIZE, 0, capture_read_data_cb); else upektc_img_read_data(ssm, dev, MAX_RESPONSE_SIZE - SHORT_RESPONSE_SIZE, @@ -323,8 +331,8 @@ static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data case CAPTURE_ACK_00_28: case CAPTURE_ACK_00_28_TERM: upektc_img_submit_req(ssm, dev, upek2020_ack_00_28, sizeof(upek2020_ack_00_28), - upekdev->seq, capture_reqs_cb); - upekdev->seq++; + self->seq, capture_reqs_cb); + self->seq++; break; case CAPTURE_ACK_08: upektc_img_submit_req(ssm, dev, upek2020_ack_08, sizeof(upek2020_ack_08), @@ -332,37 +340,38 @@ static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data break; case CAPTURE_ACK_FRAME: upektc_img_submit_req(ssm, dev, upek2020_ack_frame, sizeof(upek2020_ack_frame), - upekdev->seq, capture_reqs_cb); - upekdev->seq++; + self->seq, capture_reqs_cb); + self->seq++; break; }; } -static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capture_sm_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, GError *error_arg) { - struct fp_img_dev *dev = user_data; - struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev); - int err = fpi_ssm_get_error(ssm); + FpImageDevice *dev = user_data; + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(_dev); + g_autoptr(GError) error = error_arg; - fp_dbg("Capture completed, %d", err); fpi_ssm_free(ssm); - if (upekdev->deactivating) + /* Note: We assume that the error is a cancellation in the deactivation case */ + if (self->deactivating) start_deactivation(dev); - else if (err) - fpi_imgdev_session_error(dev, err); + else if (error) + fpi_image_device_session_error (dev, g_steal_pointer (&error)); else start_capture(dev); } -static void start_capture(struct fp_img_dev *dev) +static void start_capture(FpImageDevice *dev) { - struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_ssm *ssm; + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); + FpiSsm *ssm; - upekdev->image_size = 0; + self->image_size = 0; - ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev); + ssm = fpi_ssm_new(FP_DEVICE(dev), capture_run_state, + CAPTURE_NUM_STATES, dev); fpi_ssm_start(ssm, capture_sm_complete); } @@ -374,40 +383,38 @@ enum deactivate_states { DEACTIVATE_NUM_STATES, }; -static void deactivate_reqs_cb(struct libusb_transfer *transfer) +static void deactivate_reqs_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - - if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && - (transfer->length == transfer->actual_length)) { - fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA); + if (!error) { + fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_READ_DATA); } else { - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, error); } } /* TODO: process response properly */ -static void deactivate_read_data_cb(struct libusb_transfer *transfer) +static void deactivate_read_data_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - - if (transfer->status == LIBUSB_TRANSFER_COMPLETED) { - fpi_ssm_mark_completed(ssm); + if (!error) { + fpi_ssm_mark_completed(transfer->ssm); } else { - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, error); } } -static void deactivate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void deactivate_run_state(FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - struct fp_img_dev *dev = user_data; - struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case DEACTIVATE_DEINIT: upektc_img_submit_req(ssm, dev, upek2020_deinit, sizeof(upek2020_deinit), - upekdev->seq, deactivate_reqs_cb); - upekdev->seq++; + self->seq, deactivate_reqs_cb); + self->seq++; break; case DEACTIVATE_READ_DEINIT_DATA: upektc_img_read_data(ssm, dev, SHORT_RESPONSE_SIZE, 0, deactivate_read_data_cb); @@ -415,32 +422,28 @@ static void deactivate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_d }; } -static void deactivate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void deactivate_sm_complete(FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - struct fp_img_dev *dev = user_data; - struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev); - int err = fpi_ssm_get_error(ssm); + FpImageDevice *dev = user_data; + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(_dev); fp_dbg("Deactivate completed"); fpi_ssm_free(ssm); - if (err) { - fpi_imgdev_session_error(dev, err); - return; - } - - upekdev->deactivating = FALSE; - fpi_imgdev_deactivate_complete(dev); + self->deactivating = FALSE; + fpi_image_device_deactivate_complete(dev, error); } -static void start_deactivation(struct fp_img_dev *dev) +static void start_deactivation(FpImageDevice *dev) { - struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_ssm *ssm; + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); + FpiSsm *ssm; - upekdev->image_size = 0; + self->image_size = 0; - ssm = fpi_ssm_new(FP_DEV(dev), deactivate_run_state, DEACTIVATE_NUM_STATES, dev); + ssm = fpi_ssm_new(FP_DEVICE(dev), deactivate_run_state, + DEACTIVATE_NUM_STATES, dev); fpi_ssm_start(ssm, deactivate_sm_complete); } @@ -460,69 +463,59 @@ enum activate_states { ACTIVATE_NUM_STATES, }; -static void init_reqs_ctrl_cb(struct libusb_transfer *transfer) +static void init_reqs_ctrl_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - - if (transfer->status == LIBUSB_TRANSFER_COMPLETED) { - fpi_ssm_next_state(ssm); + if (!error) { + fpi_ssm_next_state(transfer->ssm); } else { - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, error); } } -static void init_reqs_cb(struct libusb_transfer *transfer) +static void init_reqs_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - - if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && - (transfer->length == transfer->actual_length)) { - fpi_ssm_next_state(ssm); + if (!error) { + fpi_ssm_next_state(transfer->ssm); } else { - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, error); } } /* TODO: process response properly */ -static void init_read_data_cb(struct libusb_transfer *transfer) +static void init_read_data_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - - if (transfer->status == LIBUSB_TRANSFER_COMPLETED) { - fpi_ssm_next_state(ssm); + if (!error) { + fpi_ssm_next_state(transfer->ssm); } else { - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, error); } } -static void activate_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) +static void activate_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct libusb_transfer *transfer; - struct fp_img_dev *idev = user_data; - struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(dev); - int r; + FpiUsbTransfer *transfer; + FpImageDevice *idev = user_data; + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); switch (fpi_ssm_get_cur_state(ssm)) { case ACTIVATE_CONTROL_REQ_1: case ACTIVATE_CONTROL_REQ_2: { - unsigned char *data; + transfer = fpi_usb_transfer_new(dev); - transfer = fpi_usb_alloc(); - transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER | - LIBUSB_TRANSFER_FREE_TRANSFER; - - data = g_malloc0(LIBUSB_CONTROL_SETUP_SIZE + 1); - libusb_fill_control_setup(data, - LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 0x0c, 0x100, 0x0400, 1); - libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(dev), data, - init_reqs_ctrl_cb, ssm, CTRL_TIMEOUT); - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + fpi_usb_transfer_fill_control(transfer, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0x0c, 0x100, 0x0400, 1); + transfer->buffer[0] = '\0'; + transfer->ssm = ssm; + fpi_usb_transfer_submit(transfer, CTRL_TIMEOUT, NULL, + init_reqs_ctrl_cb, NULL); + fpi_usb_transfer_unref(transfer); } break; case ACTIVATE_INIT_1: @@ -539,9 +532,9 @@ static void activate_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data break; case ACTIVATE_INIT_4: upektc_img_submit_req(ssm, idev, upek2020_init_4, sizeof(upek2020_init_4), - upekdev->seq, init_reqs_cb); + self->seq, init_reqs_cb); /* Seq should be updated after 4th init */ - upekdev->seq++; + self->seq++; break; case ACTIVATE_READ_CTRL_RESP_1: case ACTIVATE_READ_CTRL_RESP_2: @@ -554,94 +547,102 @@ static void activate_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data } } -static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_sm_complete(FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - struct fp_img_dev *dev = user_data; - int err = fpi_ssm_get_error(ssm); + FpImageDevice *dev = user_data; fpi_ssm_free(ssm); - fp_dbg("%s status %d", __func__, err); - fpi_imgdev_activate_complete(dev, err); + fpi_image_device_activate_complete(dev, error); - if (!err) + if (!error) start_capture(dev); } -static int dev_activate(struct fp_img_dev *dev) +static void dev_activate(FpImageDevice *dev) { - struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); - upekdev->seq = 0; + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); + FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); + self->seq = 0; fpi_ssm_start(ssm, activate_sm_complete); - return 0; } -static void dev_deactivate(struct fp_img_dev *dev) +static void dev_deactivate(FpImageDevice *dev) { - struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); - upekdev->deactivating = TRUE; + self->deactivating = TRUE; } -static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) +static void dev_init(FpImageDevice *dev) { + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); + GError *error = NULL; /* TODO check that device has endpoints we're using */ - int r; - struct upektc_img_dev *upekdev; - r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - if (r < 0) { - fp_err("could not claim interface 0: %s", libusb_error_name(r)); - return r; + if (!g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error)) { + fpi_image_device_open_complete(dev, error); + return; } - upekdev = g_malloc0(sizeof(struct upektc_img_dev)); - fp_dev_set_instance_data(FP_DEV(dev), upekdev); - fpi_imgdev_open_complete(dev, 0); - return 0; + self->image_bits = g_malloc0 (IMAGE_SIZE * 2); + fpi_image_device_open_complete(dev, NULL); } -static void dev_deinit(struct fp_img_dev *dev) +static void dev_deinit(FpImageDevice *dev) { - struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); - g_free(upekdev); - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - fpi_imgdev_close_complete(dev); + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); + GError *error = NULL; + + g_clear_pointer (&self->image_bits, g_free); + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), + 0, 0, &error); + fpi_image_device_close_complete(dev, error); } -static int discover(struct libusb_device_descriptor *dsc, uint32_t *devtype) +static int +discover(GUsbDevice *usb_device) { - if (dsc->idProduct == 0x2020 && dsc->bcdDevice == 1) - return 1; - if (dsc->idProduct == 0x2016 && dsc->bcdDevice == 2) - return 1; + gint16 pid = g_usb_device_get_pid (usb_device); + gint16 bcd = g_usb_device_get_release (usb_device); + + if (pid == 0x2020 && bcd == 1) + return 100; + if (pid == 0x2016 && bcd == 2) + return 100; return 0; } -static const struct usb_id id_table[] = { - { .vendor = 0x147e, .product = 0x2016 }, - { .vendor = 0x147e, .product = 0x2020 }, - { 0, 0, 0, }, -}; - -struct fp_img_driver upektc_img_driver = { - .driver = { - .id = UPEKTC_IMG_ID, - .name = FP_COMPONENT, - .full_name = "Upek TouchChip Fingerprint Coprocessor", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_SWIPE, - .discover = discover, +static const FpIdEntry id_table [ ] = { + { .vid = 0x147e, .pid = 0x2016, }, - .flags = 0, - .img_height = IMAGE_HEIGHT, - .img_width = IMAGE_WIDTH, - .bz3_threshold = 20, - - .open = dev_init, - .close = dev_deinit, - .activate = dev_activate, - .deactivate = dev_deactivate, + { .vid = 0x147e, .pid = 0x2020, + }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; + +static void fpi_device_upektc_img_init(FpiDeviceUpektcImg *self) { +} +static void fpi_device_upektc_img_class_init(FpiDeviceUpektcImgClass *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); + + dev_class->id = "upektc_img"; + dev_class->full_name = "Upek TouchChip Fingerprint Coprocessor"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + dev_class->usb_discover = discover; + + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; + + img_class->bz3_threshold = 20; + + img_class->img_width = IMAGE_WIDTH; + img_class->img_height = IMAGE_HEIGHT; +} diff --git a/meson.build b/meson.build index ec9221de..1235ba32 100644 --- a/meson.build +++ b/meson.build @@ -51,7 +51,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ ] +default_drivers = [ 'upektc_img' ] all_drivers = default_drivers + virtual_drivers From 0169fe8cf64489a78e2ca720091177bc10939369 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 4 Jul 2019 17:40:06 +0200 Subject: [PATCH 29/73] vfs5011: Port driver and add it back into build There is still a warning where a USB transfer should be cancelled but it not at this point. --- libfprint/drivers/vfs5011.c | 605 ++++++++++++++---------------- libfprint/drivers/vfs5011_proto.h | 8 +- meson.build | 2 +- 3 files changed, 283 insertions(+), 332 deletions(-) diff --git a/libfprint/drivers/vfs5011.c b/libfprint/drivers/vfs5011.c index c7121f9d..cb1147b0 100644 --- a/libfprint/drivers/vfs5011.c +++ b/libfprint/drivers/vfs5011.c @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define FP_COMPONENT "vfs5011" + #include "drivers_api.h" #include "vfs5011_proto.h" @@ -65,166 +67,119 @@ struct usb_action { struct usbexchange_data { int stepcount; - struct fp_img_dev *device; + FpImageDevice *device; struct usb_action *actions; void *receive_buf; int timeout; }; -static void start_scan(struct fp_img_dev *dev); +static void start_scan(FpImageDevice *dev); -static void async_send_cb(struct libusb_transfer *transfer) +static void async_send_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct usbexchange_data *data = fpi_ssm_get_user_data(ssm); + struct usbexchange_data *data = fpi_ssm_get_user_data(transfer->ssm); struct usb_action *action; - if (fpi_ssm_get_cur_state(ssm) >= data->stepcount) { - fp_err("Radiation detected!"); - fpi_imgdev_session_error(data->device, -EINVAL); - fpi_ssm_mark_failed(ssm, -EINVAL); - goto out; - } + g_assert(!(fpi_ssm_get_cur_state(transfer->ssm) >= data->stepcount)); - action = &data->actions[fpi_ssm_get_cur_state(ssm)]; - if (action->type != ACTION_SEND) { - fp_err("Radiation detected!"); - fpi_imgdev_session_error(data->device, -EINVAL); - fpi_ssm_mark_failed(ssm, -EINVAL); - goto out; - } + action = &data->actions[fpi_ssm_get_cur_state(transfer->ssm)]; + g_assert(!(action->type != ACTION_SEND)); - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { + if (error) { /* Transfer not completed, return IO error */ - fp_err("transfer not completed, status = %d", transfer->status); - fpi_imgdev_session_error(data->device, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); - goto out; - } - if (transfer->length != transfer->actual_length) { - /* Data sended mismatch with expected, return protocol error */ - fp_err("length mismatch, got %d, expected %d", - transfer->actual_length, transfer->length); - fpi_imgdev_session_error(data->device, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); - goto out; + fpi_ssm_mark_failed(transfer->ssm, error); + return; } /* success */ - fpi_ssm_next_state(ssm); - -out: - libusb_free_transfer(transfer); + fpi_ssm_next_state(transfer->ssm); } -static void async_recv_cb(struct libusb_transfer *transfer) +static void async_recv_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct usbexchange_data *data = fpi_ssm_get_user_data(ssm); + struct usbexchange_data *data = fpi_ssm_get_user_data(transfer->ssm); struct usb_action *action; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { + if (error) { /* Transfer not completed, return IO error */ - fp_err("transfer not completed, status = %d", transfer->status); - fpi_imgdev_session_error(data->device, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); - goto out; + fpi_ssm_mark_failed(transfer->ssm, error); + return; } - if (fpi_ssm_get_cur_state(ssm) >= data->stepcount) { - fp_err("Radiation detected!"); - fpi_imgdev_session_error(data->device, -EINVAL); - fpi_ssm_mark_failed(ssm, -EINVAL); - goto out; - } + g_assert(!(fpi_ssm_get_cur_state(transfer->ssm) >= data->stepcount)); - action = &data->actions[fpi_ssm_get_cur_state(ssm)]; - if (action->type != ACTION_RECEIVE) { - fp_err("Radiation detected!"); - fpi_imgdev_session_error(data->device, -EINVAL); - fpi_ssm_mark_failed(ssm, -EINVAL); - goto out; - } + action = &data->actions[fpi_ssm_get_cur_state(transfer->ssm)]; + g_assert(!(action->type != ACTION_RECEIVE)); if (action->data != NULL) { if (transfer->actual_length != action->correct_reply_size) { fp_err("Got %d bytes instead of %d", - transfer->actual_length, + (gint)transfer->actual_length, action->correct_reply_size); - fpi_imgdev_session_error(data->device, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); - goto out; + fpi_ssm_mark_failed(transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + return; } if (memcmp(transfer->buffer, action->data, action->correct_reply_size) != 0) { fp_dbg("Wrong reply:"); - fpi_imgdev_session_error(data->device, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); - goto out; + fpi_ssm_mark_failed(transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + return; } } else - fp_dbg("Got %d bytes out of %d", transfer->actual_length, - transfer->length); + fp_dbg("Got %d bytes out of %d", + (gint)transfer->actual_length, + (gint)transfer->length); - fpi_ssm_next_state(ssm); -out: - libusb_free_transfer(transfer); + fpi_ssm_next_state(transfer->ssm); } -static void usbexchange_loop(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void usbexchange_loop(FpiSsm *ssm, FpDevice *_dev, void *user_data) { struct usbexchange_data *data = user_data; - if (fpi_ssm_get_cur_state(ssm) >= data->stepcount) { - fp_err("Bug detected: state %d out of range, only %d steps", - fpi_ssm_get_cur_state(ssm), data->stepcount); - fpi_imgdev_session_error(data->device, -EINVAL); - fpi_ssm_mark_failed(ssm, -EINVAL); - return; - } - struct usb_action *action = &data->actions[fpi_ssm_get_cur_state(ssm)]; - struct libusb_transfer *transfer; - int ret = -EINVAL; + FpiUsbTransfer *transfer; + + g_assert (fpi_ssm_get_cur_state(ssm) < data->stepcount); switch (action->type) { case ACTION_SEND: fp_dbg("Sending %s", action->name); - transfer = fpi_usb_alloc(); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(data->device)), - action->endpoint, action->data, - action->size, async_send_cb, ssm, - data->timeout); - ret = libusb_submit_transfer(transfer); + transfer = fpi_usb_transfer_new(_dev); + fpi_usb_transfer_fill_bulk_full(transfer, action->endpoint, + action->data, action->size, + NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit(transfer, data->timeout, NULL, + async_send_cb, NULL); + fpi_usb_transfer_unref(transfer); break; case ACTION_RECEIVE: fp_dbg("Receiving %d bytes", action->size); - transfer = fpi_usb_alloc(); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(data->device)), - action->endpoint, data->receive_buf, - action->size, async_recv_cb, ssm, - data->timeout); - ret = libusb_submit_transfer(transfer); + transfer = fpi_usb_transfer_new(_dev); + fpi_usb_transfer_fill_bulk_full(transfer, action->endpoint, + data->receive_buf, + action->size, NULL); + transfer->ssm = ssm; + fpi_usb_transfer_submit(transfer, data->timeout, NULL, + async_recv_cb, NULL); + fpi_usb_transfer_unref(transfer); break; default: fp_err("Bug detected: invalid action %d", action->type); - fpi_imgdev_session_error(data->device, -EINVAL); - fpi_ssm_mark_failed(ssm, -EINVAL); + fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); return; } - - if (ret != 0) { - fp_err("USB transfer error: %s", strerror(ret)); - fpi_imgdev_session_error(data->device, ret); - fpi_ssm_mark_failed(ssm, ret); - } } -static void usb_exchange_async(fpi_ssm *ssm, +static void usb_exchange_async(FpiSsm *ssm, struct usbexchange_data *data) { - fpi_ssm *subsm = fpi_ssm_new(FP_DEV(data->device), + FpiSsm *subsm = fpi_ssm_new(FP_DEVICE(data->device), usbexchange_loop, data->stepcount, data); @@ -283,7 +238,9 @@ static struct fpi_line_asmbl_ctx assembling_ctx = { .get_pixel = vfs5011_get_pixel, }; -struct vfs5011_data { +struct _FpDeviceVfs5011 { + FpImageDevice parent; + unsigned char *total_buffer; unsigned char *capture_buffer; unsigned char *row_buffer; @@ -295,9 +252,12 @@ struct vfs5011_data { gboolean loop_running; gboolean deactivating; struct usbexchange_data init_sequence; - struct libusb_transfer *flying_transfer; }; +G_DECLARE_FINAL_TYPE(FpDeviceVfs5011, fpi_device_vfs5011, FPI, DEVICE_VFS5011, + FpImageDevice); +G_DEFINE_TYPE(FpDeviceVfs5011, fpi_device_vfs5011, FP_TYPE_IMAGE_DEVICE); + enum { DEV_ACTIVATE_REQUEST_FPRINT, DEV_ACTIVATE_INIT_COMPLETE, @@ -312,22 +272,22 @@ enum { DEV_OPEN_NUM_STATES }; -static void capture_init(struct vfs5011_data *data, int max_captured, - int max_recorded) +static void capture_init(FpDeviceVfs5011 *self, int max_captured, + int max_recorded) { fp_dbg("capture_init"); - data->lastline = NULL; - data->lines_captured = 0; - data->lines_recorded = 0; - data->empty_lines = 0; - data->lines_total = 0; - data->lines_total_allocated = 0; - data->total_buffer = NULL; - data->max_lines_captured = max_captured; - data->max_lines_recorded = max_recorded; + self->lastline = NULL; + self->lines_captured = 0; + self->lines_recorded = 0; + self->empty_lines = 0; + self->lines_total = 0; + self->lines_total_allocated = 0; + self->total_buffer = NULL; + self->max_lines_captured = max_captured; + self->max_lines_recorded = max_recorded; } -static int process_chunk(struct vfs5011_data *data, int transferred) +static int process_chunk(FpDeviceVfs5011 *self, int transferred) { enum { DEVIATION_THRESHOLD = 15*15, @@ -340,42 +300,42 @@ static int process_chunk(struct vfs5011_data *data, int transferred) int i; for (i = 0; i < lines_captured; i++) { - unsigned char *linebuf = data->capture_buffer + unsigned char *linebuf = self->capture_buffer + i * VFS5011_LINE_SIZE; if (fpi_std_sq_dev(linebuf + 8, VFS5011_IMAGE_WIDTH) < DEVIATION_THRESHOLD) { - if (data->lines_captured == 0) + if (self->lines_captured == 0) continue; else - data->empty_lines++; + self->empty_lines++; } else - data->empty_lines = 0; - if (data->empty_lines >= STOP_CHECK_LINES) { + self->empty_lines = 0; + if (self->empty_lines >= STOP_CHECK_LINES) { fp_dbg("process_chunk: got %d empty lines, finishing", - data->empty_lines); + self->empty_lines); return 1; } - data->lines_captured++; - if (data->lines_captured > data->max_lines_captured) { + self->lines_captured++; + if (self->lines_captured > self->max_lines_captured) { fp_dbg("process_chunk: captured %d lines, finishing", - data->lines_captured); + self->lines_captured); return 1; } - if ((data->lastline == NULL) - || (fpi_mean_sq_diff_norm( - data->lastline + 8, - linebuf + 8, - VFS5011_IMAGE_WIDTH) >= DIFFERENCE_THRESHOLD)) { - data->lastline = g_malloc(VFS5011_LINE_SIZE); - data->rows = g_slist_prepend(data->rows, data->lastline); - memmove(data->lastline, linebuf, VFS5011_LINE_SIZE); - data->lines_recorded++; - if (data->lines_recorded >= data->max_lines_recorded) { + if ((self->lastline == NULL) + || (fpi_mean_sq_diff_norm(self->lastline + 8, + linebuf + 8, + VFS5011_IMAGE_WIDTH) >= DIFFERENCE_THRESHOLD)) { + self->lastline = g_malloc(VFS5011_LINE_SIZE); + self->rows = g_slist_prepend(self->rows, + self->lastline); + memmove(self->lastline, linebuf, VFS5011_LINE_SIZE); + self->lines_recorded++; + if (self->lines_recorded >= self->max_lines_recorded) { fp_dbg("process_chunk: recorded %d lines, finishing", - data->lines_recorded); + self->lines_recorded); return 1; } } @@ -384,80 +344,88 @@ static int process_chunk(struct vfs5011_data *data, int transferred) } static void -submit_image(fpi_ssm *ssm, - struct vfs5011_data *data, - struct fp_img_dev *dev) +submit_image(FpiSsm *ssm, + FpDeviceVfs5011 *self, + FpImageDevice *dev) { - struct fp_img *img; + FpImage *img; - if (data->lines_recorded == 0) { + if (self->lines_recorded == 0) { /* == FP_ENROLL_RETRY_TOO_SHORT */ - fpi_imgdev_session_error(dev, FP_VERIFY_RETRY_TOO_SHORT); + fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT); return; } - g_assert (data->rows != NULL); + g_assert (self->rows != NULL); - data->rows = g_slist_reverse(data->rows); + self->rows = g_slist_reverse(self->rows); - img = fpi_assemble_lines(&assembling_ctx, data->rows, data->lines_recorded); + img = fpi_assemble_lines(&assembling_ctx, self->rows, + self->lines_recorded); - g_slist_free_full(data->rows, g_free); - data->rows = NULL; + g_slist_free_full(self->rows, g_free); + self->rows = NULL; fp_dbg("Image captured, committing"); - fpi_imgdev_image_captured(dev, img); + fpi_image_device_image_captured(dev, img); } -static void chunk_capture_callback(struct libusb_transfer *transfer) +static void chunk_capture_callback(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = (fpi_ssm *)transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs5011_data *data; + FpImageDevice *dev = FP_IMAGE_DEVICE(device); + FpDeviceVfs5011 *self; - data = FP_INSTANCE_DATA(FP_DEV(dev)); + self = FPI_DEVICE_VFS5011(dev); - if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) || - (transfer->status == LIBUSB_TRANSFER_TIMED_OUT)) { + if (!error || + g_error_matches(error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT)) { + if (error) + g_error_free(error); if (transfer->actual_length > 0) - fpi_imgdev_report_finger_status(dev, TRUE); + fpi_image_device_report_finger_status(dev, TRUE); - if (process_chunk(data, transfer->actual_length)) - fpi_ssm_jump_to_state(ssm, DEV_ACTIVATE_DATA_COMPLETE); + if (process_chunk(self, transfer->actual_length)) + fpi_ssm_jump_to_state(transfer->ssm, + DEV_ACTIVATE_DATA_COMPLETE); else - fpi_ssm_jump_to_state(ssm, DEV_ACTIVATE_READ_DATA); + fpi_ssm_jump_to_state(transfer->ssm, + DEV_ACTIVATE_READ_DATA); } else { - if (!data->deactivating) { + if (!self->deactivating) { fp_err("Failed to capture data"); - fpi_ssm_mark_failed(ssm, -1); + fpi_ssm_mark_failed(transfer->ssm, error); } else { - fpi_ssm_mark_completed(ssm); + g_error_free (error); + fpi_ssm_mark_completed(transfer->ssm); } } - libusb_free_transfer(transfer); - data->flying_transfer = NULL; } -static int capture_chunk_async(struct vfs5011_data *data, - libusb_device_handle *handle, int nline, - int timeout, fpi_ssm *ssm) +static void capture_chunk_async(FpDeviceVfs5011 *self, + GUsbDevice *handle, int nline, + int timeout, FpiSsm *ssm) { + FpiUsbTransfer *transfer; fp_dbg("capture_chunk_async: capture %d lines, already have %d", - nline, data->lines_recorded); + nline, self->lines_recorded); enum { DEVIATION_THRESHOLD = 15*15, DIFFERENCE_THRESHOLD = 600, STOP_CHECK_LINES = 50 }; - data->flying_transfer = fpi_usb_alloc(); - libusb_fill_bulk_transfer(data->flying_transfer, handle, VFS5011_IN_ENDPOINT_DATA, - data->capture_buffer, - nline * VFS5011_LINE_SIZE, - chunk_capture_callback, ssm, timeout); - return libusb_submit_transfer(data->flying_transfer); + transfer = fpi_usb_transfer_new(FP_DEVICE(self)); + fpi_usb_transfer_fill_bulk_full(transfer, + VFS5011_IN_ENDPOINT_DATA, + self->capture_buffer, + nline * VFS5011_LINE_SIZE, NULL); + transfer->ssm = ssm; + fpi_usb_transfer_submit(transfer, timeout, fpi_device_get_cancellable (FP_DEVICE (self)), + chunk_capture_callback, NULL); + fpi_usb_transfer_unref(transfer); } /* @@ -648,20 +616,18 @@ struct usb_action vfs5011_initiate_capture[] = { /* ====================== lifprint interface ======================= */ -static void activate_loop(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_loop(FpiSsm *ssm, FpDevice *_dev, void *user_data) { enum {READ_TIMEOUT = 0}; - struct fp_img_dev *dev = user_data; - struct vfs5011_data *data; - int r; - fpi_timeout *timeout; + FpImageDevice *dev = user_data; + FpDeviceVfs5011 *self; - data = FP_INSTANCE_DATA(_dev); + self = FPI_DEVICE_VFS5011(_dev); fp_dbg("main_loop: state %d", fpi_ssm_get_cur_state(ssm)); - if (data->deactivating) { + if (self->deactivating) { fp_dbg("deactivating, marking completed"); fpi_ssm_mark_completed(ssm); return; @@ -669,239 +635,224 @@ static void activate_loop(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) switch (fpi_ssm_get_cur_state(ssm)) { case DEV_ACTIVATE_REQUEST_FPRINT: - data->init_sequence.stepcount = + self->init_sequence.stepcount = G_N_ELEMENTS(vfs5011_initiate_capture); - data->init_sequence.actions = vfs5011_initiate_capture; - data->init_sequence.device = dev; - if (data->init_sequence.receive_buf == NULL) - data->init_sequence.receive_buf = + self->init_sequence.actions = vfs5011_initiate_capture; + self->init_sequence.device = dev; + if (self->init_sequence.receive_buf == NULL) + self->init_sequence.receive_buf = g_malloc0(VFS5011_RECEIVE_BUF_SIZE); - data->init_sequence.timeout = 1000; - usb_exchange_async(ssm, &data->init_sequence); + self->init_sequence.timeout = 1000; + usb_exchange_async(ssm, &self->init_sequence); break; case DEV_ACTIVATE_INIT_COMPLETE: - if (data->init_sequence.receive_buf != NULL) - g_free(data->init_sequence.receive_buf); - data->init_sequence.receive_buf = NULL; - capture_init(data, MAX_CAPTURE_LINES, MAXLINES); - fpi_imgdev_activate_complete(dev, 0); + if (self->init_sequence.receive_buf != NULL) + g_free(self->init_sequence.receive_buf); + self->init_sequence.receive_buf = NULL; + capture_init(self, MAX_CAPTURE_LINES, MAXLINES); + fpi_image_device_activate_complete(dev, NULL); fpi_ssm_next_state(ssm); break; case DEV_ACTIVATE_READ_DATA: - r = capture_chunk_async(data, fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_LINES, - READ_TIMEOUT, ssm); - if (r != 0) { - fp_err("Failed to capture data"); - fpi_imgdev_session_error(dev, r); - fpi_ssm_mark_failed(ssm, r); - } + capture_chunk_async(self, + fpi_device_get_usb_device(FP_DEVICE(dev)), + CAPTURE_LINES, + READ_TIMEOUT, ssm); break; case DEV_ACTIVATE_DATA_COMPLETE: - timeout = fpi_timeout_add(1, fpi_ssm_next_state_timeout_cb, _dev, ssm); + fpi_device_add_timeout(_dev, 1, + fpi_ssm_next_state_timeout_cb, + ssm); - if (timeout == NULL) { - /* Failed to add timeout */ - fp_err("failed to add timeout"); - fpi_imgdev_session_error(dev, -1); - fpi_ssm_mark_failed(ssm, -1); - } break; case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE: - data->init_sequence.stepcount = + self->init_sequence.stepcount = G_N_ELEMENTS(vfs5011_initiate_capture); - data->init_sequence.actions = vfs5011_initiate_capture; - data->init_sequence.device = dev; - if (data->init_sequence.receive_buf == NULL) - data->init_sequence.receive_buf = + self->init_sequence.actions = vfs5011_initiate_capture; + self->init_sequence.device = dev; + if (self->init_sequence.receive_buf == NULL) + self->init_sequence.receive_buf = g_malloc0(VFS5011_RECEIVE_BUF_SIZE); - data->init_sequence.timeout = VFS5011_DEFAULT_WAIT_TIMEOUT; - usb_exchange_async(ssm, &data->init_sequence); + self->init_sequence.timeout = VFS5011_DEFAULT_WAIT_TIMEOUT; + usb_exchange_async(ssm, &self->init_sequence); break; } } -static void activate_loop_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_loop_complete(FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - struct fp_img_dev *dev = user_data; - struct vfs5011_data *data; - int r = fpi_ssm_get_error(ssm); + FpImageDevice *dev = user_data; + FpDeviceVfs5011 *self; - data = FP_INSTANCE_DATA(_dev); + self = FPI_DEVICE_VFS5011(_dev); fp_dbg("finishing"); - if (data->init_sequence.receive_buf != NULL) - g_free(data->init_sequence.receive_buf); - data->init_sequence.receive_buf = NULL; - if (!data->deactivating && !r) { - submit_image(ssm, data, dev); - fpi_imgdev_report_finger_status(dev, FALSE); + if (self->init_sequence.receive_buf != NULL) + g_free(self->init_sequence.receive_buf); + self->init_sequence.receive_buf = NULL; + if (!self->deactivating && !error) { + submit_image(ssm, self, dev); + fpi_image_device_report_finger_status(dev, FALSE); } fpi_ssm_free(ssm); - data->loop_running = FALSE; + self->loop_running = FALSE; - if (data->deactivating) { - fpi_imgdev_deactivate_complete(dev); - } else if (r) { - fpi_imgdev_session_error(dev, r); + if (self->deactivating) { + fpi_image_device_deactivate_complete(dev, error); + } else if (error) { + fpi_image_device_session_error(dev, error); } else { start_scan(dev); } } -static void open_loop(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void open_loop(FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct vfs5011_data *data; + FpImageDevice *dev = user_data; + FpDeviceVfs5011 *self; - data = FP_INSTANCE_DATA(_dev); + self = FPI_DEVICE_VFS5011(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case DEV_OPEN_START: - data->init_sequence.stepcount = + self->init_sequence.stepcount = G_N_ELEMENTS(vfs5011_initialization); - data->init_sequence.actions = vfs5011_initialization; - data->init_sequence.device = dev; - data->init_sequence.receive_buf = + self->init_sequence.actions = vfs5011_initialization; + self->init_sequence.device = dev; + self->init_sequence.receive_buf = g_malloc0(VFS5011_RECEIVE_BUF_SIZE); - data->init_sequence.timeout = VFS5011_DEFAULT_WAIT_TIMEOUT; - usb_exchange_async(ssm, &data->init_sequence); + self->init_sequence.timeout = VFS5011_DEFAULT_WAIT_TIMEOUT; + usb_exchange_async(ssm, &self->init_sequence); break; }; } -static void open_loop_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void open_loop_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - struct fp_img_dev *dev = user_data; - struct vfs5011_data *data; + FpImageDevice *dev = user_data; + FpDeviceVfs5011 *self; - data = FP_INSTANCE_DATA(_dev); - g_free(data->init_sequence.receive_buf); - data->init_sequence.receive_buf = NULL; + self = FPI_DEVICE_VFS5011(_dev); + g_free(self->init_sequence.receive_buf); + self->init_sequence.receive_buf = NULL; - fpi_imgdev_open_complete(dev, 0); + fpi_image_device_open_complete(dev, error); fpi_ssm_free(ssm); } -static int dev_open(struct fp_img_dev *dev, unsigned long driver_data) +static void dev_open(FpImageDevice *dev) { + FpiSsm *ssm; + GError *error = NULL; + FpDeviceVfs5011 *self; - struct vfs5011_data *data; - int r; - - data = (struct vfs5011_data *)g_malloc0(sizeof(*data)); - data->capture_buffer = + self = FPI_DEVICE_VFS5011(dev); + self->capture_buffer = (unsigned char *)g_malloc0(CAPTURE_LINES * VFS5011_LINE_SIZE); - fp_dev_set_instance_data(FP_DEV(dev), data); - r = libusb_reset_device(fpi_dev_get_usb_dev(FP_DEV(dev))); - if (r != 0) { - fp_err("Failed to reset the device"); - return r; + if (!g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error)) { + fpi_image_device_open_complete(dev, error); + return; } - r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - if (r != 0) { - fp_err("Failed to claim interface: %s", libusb_error_name(r)); - return r; - } - - fpi_ssm *ssm; - ssm = fpi_ssm_new(FP_DEV(dev), open_loop, DEV_OPEN_NUM_STATES, dev); + ssm = fpi_ssm_new(FP_DEVICE(dev), open_loop, DEV_OPEN_NUM_STATES, dev); fpi_ssm_start(ssm, open_loop_complete); - - return 0; } -static void dev_close(struct fp_img_dev *dev) +static void dev_close(FpImageDevice *dev) { - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - struct vfs5011_data *data; - data = FP_INSTANCE_DATA(FP_DEV(dev)); - if (data != NULL) { - g_free(data->capture_buffer); - g_slist_free_full(data->rows, g_free); - g_free(data); - } - fpi_imgdev_close_complete(dev); + GError *error = NULL; + FpDeviceVfs5011 *self = FPI_DEVICE_VFS5011(dev);; + + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), + 0, 0, &error); + + g_free(self->capture_buffer); + g_slist_free_full(self->rows, g_free); + + fpi_image_device_close_complete(dev, error); } -static void start_scan(struct fp_img_dev *dev) +static void start_scan(FpImageDevice *dev) { - struct vfs5011_data *data; - fpi_ssm *ssm; + FpDeviceVfs5011 *self; + FpiSsm *ssm; - data = FP_INSTANCE_DATA(FP_DEV(dev)); - data->loop_running = TRUE; + self = FPI_DEVICE_VFS5011(dev); + self->loop_running = TRUE; fp_dbg("creating ssm"); - ssm = fpi_ssm_new(FP_DEV(dev), activate_loop, DEV_ACTIVATE_NUM_STATES, dev); + ssm = fpi_ssm_new(FP_DEVICE(dev), activate_loop, + DEV_ACTIVATE_NUM_STATES, dev); fp_dbg("starting ssm"); fpi_ssm_start(ssm, activate_loop_complete); fp_dbg("ssm done, getting out"); } -static int dev_activate(struct fp_img_dev *dev) +static void dev_activate(FpImageDevice *dev) { - struct vfs5011_data *data; + FpDeviceVfs5011 *self; - data = FP_INSTANCE_DATA(FP_DEV(dev)); + self = FPI_DEVICE_VFS5011(dev); fp_dbg("device initialized"); - data->deactivating = FALSE; + self->deactivating = FALSE; start_scan(dev); - - return 0; } -static void dev_deactivate(struct fp_img_dev *dev) +static void dev_deactivate(FpImageDevice *dev) { - int r; - struct vfs5011_data *data; + FpDeviceVfs5011 *self; - data = FP_INSTANCE_DATA(FP_DEV(dev)); - if (data->loop_running) { - data->deactivating = TRUE; - if (data->flying_transfer) { - r = libusb_cancel_transfer(data->flying_transfer); - if (r < 0) - fp_dbg("cancel failed error %d", r); - } + self = FPI_DEVICE_VFS5011(dev); + if (self->loop_running) { + self->deactivating = TRUE; } else - fpi_imgdev_deactivate_complete(dev); + fpi_image_device_deactivate_complete(dev, NULL); } -static const struct usb_id id_table[] = { - { .vendor = 0x138a, .product = 0x0010 /* Validity device from some Toshiba laptops */ }, - { .vendor = 0x138a, .product = 0x0011 /* vfs5011 */ }, - { .vendor = 0x138a, .product = 0x0015 /* Validity device from Lenovo Preferred Pro USB Fingerprint Keyboard KUF1256 */ }, - { .vendor = 0x138a, .product = 0x0017 /* Validity device from Lenovo T440 laptops */ }, - { .vendor = 0x138a, .product = 0x0018 /* one more Validity device */ }, - { 0, 0, 0, }, -}; - -struct fp_img_driver vfs5011_driver = { - .driver = { - .id = VFS5011_ID, - .name = "vfs5011", - .full_name = "Validity VFS5011", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_SWIPE, +static const FpIdEntry id_table [ ] = { + { /* Validity device from some Toshiba laptops */ .vid = 0x138a, .pid = 0x0010, }, - - .flags = 0, - .img_width = VFS5011_IMAGE_WIDTH, - .img_height = -1, - .bz3_threshold = 20, - - .open = dev_open, - .close = dev_close, - .activate = dev_activate, - .deactivate = dev_deactivate, + { /* vfs5011 */ .vid = 0x138a, .pid = 0x0011, + }, + { /* Validity device from Lenovo Preferred Pro USB Fingerprint Keyboard KUF1256 */ .vid = 0x138a, .pid = 0x0015, + }, + { /* Validity device from Lenovo T440 laptops */ .vid = 0x138a, .pid = 0x0017, + }, + { /* one more Validity device */ .vid = 0x138a, .pid = 0x0018, + }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; +static void fpi_device_vfs5011_init(FpDeviceVfs5011 *self) { +} +static void fpi_device_vfs5011_class_init(FpDeviceVfs5011Class *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); + + dev_class->id = "vfs5011"; + dev_class->full_name = "Validity VFS5011"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + + img_class->img_open = dev_open; + img_class->img_close = dev_close; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; + + img_class->bz3_threshold = 20; + + img_class->img_width = VFS5011_IMAGE_WIDTH; + img_class->img_height = -1; +} + diff --git a/libfprint/drivers/vfs5011_proto.h b/libfprint/drivers/vfs5011_proto.h index 8cd0ea80..972d0173 100644 --- a/libfprint/drivers/vfs5011_proto.h +++ b/libfprint/drivers/vfs5011_proto.h @@ -7,10 +7,10 @@ enum { VFS5011_DEFAULT_WAIT_TIMEOUT = 3000, - VFS5011_OUT_ENDPOINT = 1 | LIBUSB_ENDPOINT_OUT, - VFS5011_IN_ENDPOINT_CTRL = 1 | LIBUSB_ENDPOINT_IN, - VFS5011_IN_ENDPOINT_DATA = 2 | LIBUSB_ENDPOINT_IN, - VFS5011_IN_ENDPOINT_CTRL2 = 3 | LIBUSB_ENDPOINT_IN, + VFS5011_OUT_ENDPOINT = 1 | FPI_USB_ENDPOINT_OUT, + VFS5011_IN_ENDPOINT_CTRL = 1 | FPI_USB_ENDPOINT_IN, + VFS5011_IN_ENDPOINT_DATA = 2 | FPI_USB_ENDPOINT_IN, + VFS5011_IN_ENDPOINT_CTRL2 = 3 | FPI_USB_ENDPOINT_IN, }; enum { diff --git a/meson.build b/meson.build index 1235ba32..df26addc 100644 --- a/meson.build +++ b/meson.build @@ -51,7 +51,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img' ] +default_drivers = [ 'upektc_img', 'vfs5011' ] all_drivers = default_drivers + virtual_drivers From 7ef64b5f5f5eb4713d1194711380415b7973e6b0 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 8 Jul 2019 14:48:56 +0200 Subject: [PATCH 30/73] aes3k: Port aes3500 and aes4000 drivers to new API --- libfprint/drivers/aes3500.c | 88 ++++++------------ libfprint/drivers/aes3k.c | 180 +++++++++++++++++++++++------------- libfprint/drivers/aes3k.h | 33 +++---- libfprint/drivers/aes4000.c | 88 ++++++------------ libfprint/drivers/aeslib.c | 73 ++++++--------- libfprint/drivers/aeslib.h | 9 +- meson.build | 2 +- 7 files changed, 223 insertions(+), 250 deletions(-) diff --git a/libfprint/drivers/aes3500.c b/libfprint/drivers/aes3500.c index c083c4ed..dccccac8 100644 --- a/libfprint/drivers/aes3500.c +++ b/libfprint/drivers/aes3500.c @@ -29,8 +29,6 @@ #define FP_COMPONENT "aes3500" -#include "drivers_api.h" -#include "aeslib.h" #include "aes3k.h" #define DATA_BUFLEN 0x2089 @@ -117,67 +115,39 @@ static struct aes_regwrite init_reqs[] = { { 0x81, 0x00 }, }; -static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) -{ - int r; - struct aes3k_dev *aesdev; - - r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - if (r < 0) { - fp_err("could not claim interface 0: %s", libusb_error_name(r)); - return r; - } - - aesdev = g_malloc0(sizeof(struct aes3k_dev)); - fp_dev_set_instance_data(FP_DEV(dev), aesdev); - - if (!aesdev) - return -ENOMEM; - - aesdev->data_buflen = DATA_BUFLEN; - aesdev->frame_width = FRAME_WIDTH; - aesdev->frame_size = FRAME_SIZE; - aesdev->frame_number = FRAME_NUMBER; - aesdev->enlarge_factor = ENLARGE_FACTOR; - aesdev->init_reqs = init_reqs; - aesdev->init_reqs_len = G_N_ELEMENTS(init_reqs); - fpi_imgdev_open_complete(dev, 0); - - return r; -} - -static void dev_deinit(struct fp_img_dev *dev) -{ - struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); - g_free(aesdev); - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - fpi_imgdev_close_complete(dev); -} +struct _FpiDeviceAes3500 { + FpiDeviceAes3k parent; +}; +G_DECLARE_FINAL_TYPE(FpiDeviceAes3500, fpi_device_aes3500, FPI, + DEVICE_AES3500, FpiDeviceAes3k); +G_DEFINE_TYPE(FpiDeviceAes3500, fpi_device_aes3500, FPI_TYPE_DEVICE_AES3K); -static const struct usb_id id_table[] = { - { .vendor = 0x08ff, .product = 0x5731 }, - { 0, 0, 0, }, +static const FpIdEntry id_table [ ] = { + { .vid = 0x08ff, .pid = 0x5731 }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -struct fp_img_driver aes3500_driver = { - .driver = { - .id = AES3500_ID, - .name = FP_COMPONENT, - .full_name = "AuthenTec AES3500", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_PRESS, - }, - .flags = 0, - .img_height = FRAME_WIDTH * ENLARGE_FACTOR, - .img_width = FRAME_WIDTH * ENLARGE_FACTOR, +static void fpi_device_aes3500_init(FpiDeviceAes3500 *self) { +} - /* temporarily lowered until image quality improves */ - .bz3_threshold = 9, +static void fpi_device_aes3500_class_init(FpiDeviceAes3500Class *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); + FpiDeviceAes3kClass *aes_class = FPI_DEVICE_AES3K_CLASS (klass); - .open = dev_init, - .close = dev_deinit, - .activate = aes3k_dev_activate, - .deactivate = aes3k_dev_deactivate, -}; + dev_class->id = "aes3500"; + dev_class->full_name = "AuthenTec AES3500"; + dev_class->id_table = id_table; + img_class->img_height = FRAME_WIDTH * ENLARGE_FACTOR; + img_class->img_width = FRAME_WIDTH * ENLARGE_FACTOR; + + aes_class->data_buflen = DATA_BUFLEN; + aes_class->frame_width = FRAME_WIDTH; + aes_class->frame_size = FRAME_SIZE; + aes_class->frame_number = FRAME_NUMBER; + aes_class->enlarge_factor = ENLARGE_FACTOR; + aes_class->init_reqs = init_reqs; + aes_class->init_reqs_len = G_N_ELEMENTS(init_reqs); +} diff --git a/libfprint/drivers/aes3k.c b/libfprint/drivers/aes3k.c index ddb94c9b..9c120bd8 100644 --- a/libfprint/drivers/aes3k.c +++ b/libfprint/drivers/aes3k.c @@ -40,11 +40,18 @@ #include "aeslib.h" #include "aes3k.h" -#define CTRL_TIMEOUT 1000 -#define EP_IN (1 | LIBUSB_ENDPOINT_IN) -#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT) +typedef struct { + FpiUsbTransfer *img_trf; + gboolean deactivating; +} FpiDeviceAes3kPrivate; -static void do_capture(struct fp_img_dev *dev); +#define CTRL_TIMEOUT 1000 +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) + +static void do_capture(FpImageDevice *dev); + +G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(FpiDeviceAes3k, fpi_device_aes3k, FP_TYPE_IMAGE_DEVICE); static void aes3k_assemble_image(unsigned char *input, size_t width, size_t height, unsigned char *output) @@ -60,99 +67,142 @@ static void aes3k_assemble_image(unsigned char *input, size_t width, size_t heig } } -static void img_cb(struct libusb_transfer *transfer) +static void img_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - struct fp_img_dev *dev = transfer->user_data; - struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpiDeviceAes3k *self = FPI_DEVICE_AES3K (device); + FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self); + FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self); unsigned char *ptr = transfer->buffer; - struct fp_img *tmp; - struct fp_img *img; + FpImage *tmp; + FpImage *img; int i; - if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { - goto err; - } else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fpi_imgdev_session_error(dev, -EIO); - goto err; - } else if (transfer->length != transfer->actual_length) { - fpi_imgdev_session_error(dev, -EPROTO); - goto err; + priv->img_trf = NULL; + + if (error) { + if (g_error_matches (error, + G_IO_ERROR, + G_IO_ERROR_CANCELLED)) { + /* Deactivation was completed. */ + g_error_free (error); + if (priv->deactivating) + fpi_image_device_deactivate_complete(dev, NULL); + return; + } + + fpi_image_device_session_error (dev, error); } - fpi_imgdev_report_finger_status(dev, TRUE); + fpi_image_device_report_finger_status(dev, TRUE); - tmp = fpi_img_new(aesdev->frame_width * aesdev->frame_width); - tmp->width = aesdev->frame_width; - tmp->height = aesdev->frame_width; - tmp->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED; - for (i = 0; i < aesdev->frame_number; i++) { + tmp = fp_image_new(cls->frame_width, cls->frame_width); + tmp->width = cls->frame_width; + tmp->height = cls->frame_width; + tmp->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED; + for (i = 0; i < cls->frame_number; i++) { fp_dbg("frame header byte %02x", *ptr); ptr++; - aes3k_assemble_image(ptr, aesdev->frame_width, AES3K_FRAME_HEIGHT, tmp->data + (i * aesdev->frame_width * AES3K_FRAME_HEIGHT)); - ptr += aesdev->frame_size; + aes3k_assemble_image(ptr, cls->frame_width, AES3K_FRAME_HEIGHT, tmp->data + (i * cls->frame_width * AES3K_FRAME_HEIGHT)); + ptr += cls->frame_size; } /* FIXME: this is an ugly hack to make the image big enough for NBIS * to process reliably */ - img = fpi_img_resize(tmp, aesdev->enlarge_factor, aesdev->enlarge_factor); - fp_img_free(tmp); - fpi_imgdev_image_captured(dev, img); + img = fpi_image_resize(tmp, cls->enlarge_factor, cls->enlarge_factor); + g_object_unref (tmp); + fpi_image_device_image_captured(dev, img); /* FIXME: rather than assuming finger has gone, we should poll regs until * it really has, then restart the capture */ - fpi_imgdev_report_finger_status(dev, FALSE); + fpi_image_device_report_finger_status(dev, FALSE); do_capture(dev); - -err: - g_free(transfer->buffer); - aesdev->img_trf = NULL; - libusb_free_transfer(transfer); } -static void do_capture(struct fp_img_dev *dev) +static void do_capture(FpImageDevice *dev) { - struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); - unsigned char *data; - int r; + FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev); + FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self); + FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self); - aesdev->img_trf = fpi_usb_alloc(); - data = g_malloc(aesdev->data_buflen); - libusb_fill_bulk_transfer(aesdev->img_trf, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, - aesdev->data_buflen, img_cb, dev, 0); - - r = libusb_submit_transfer(aesdev->img_trf); - if (r < 0) { - g_free(data); - libusb_free_transfer(aesdev->img_trf); - aesdev->img_trf = NULL; - fpi_imgdev_session_error(dev, r); - } + priv->img_trf = fpi_usb_transfer_new (FP_DEVICE (dev)); + fpi_usb_transfer_fill_bulk(priv->img_trf, EP_IN, cls->data_buflen); + priv->img_trf->short_is_error = TRUE; + fpi_usb_transfer_submit(priv->img_trf, 0, + fpi_device_get_cancellable (FP_DEVICE (dev)), + img_cb, NULL); + fpi_usb_transfer_unref(priv->img_trf); } -static void init_reqs_cb(struct fp_img_dev *dev, int result, void *user_data) +static void init_reqs_cb(FpImageDevice *dev, GError *result, void *user_data) { - fpi_imgdev_activate_complete(dev, result); - if (result == 0) + fpi_image_device_activate_complete (dev, result); + if (!result) do_capture(dev); } -int aes3k_dev_activate(struct fp_img_dev *dev) +static void aes3k_dev_activate(FpImageDevice *dev) { - struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); - aes_write_regv(dev, aesdev->init_reqs, aesdev->init_reqs_len, init_reqs_cb, NULL); - return 0; + FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev); + FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self); + FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self); + + priv->deactivating = FALSE; + aes_write_regv(dev, cls->init_reqs, cls->init_reqs_len, init_reqs_cb, NULL); } -void aes3k_dev_deactivate(struct fp_img_dev *dev) +static void aes3k_dev_deactivate(FpImageDevice *dev) { - struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev); + FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self); - /* FIXME: should wait for cancellation to complete before returning - * from deactivation, otherwise app may legally exit before we've - * cleaned up */ - if (aesdev->img_trf) - libusb_cancel_transfer(aesdev->img_trf); - fpi_imgdev_deactivate_complete(dev); + priv->deactivating = TRUE; + if (priv->img_trf) + return; + fpi_image_device_deactivate_complete(dev, NULL); } +static void fpi_device_aes3k_init(FpiDeviceAes3k *self) { +} + +static void aes3k_dev_init(FpImageDevice *dev) +{ + GError *error = NULL; + + if (!g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error)) { + fpi_image_device_open_complete(dev, error); + return; + } + + fpi_image_device_open_complete(dev, NULL); +} + +static void aes3k_dev_deinit(FpImageDevice *dev) +{ + GError *error = NULL; + + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), + 0, 0, &error); + fpi_image_device_close_complete(dev, error); +} + + +static void fpi_device_aes3k_class_init(FpiDeviceAes3kClass *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); + + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->scan_type = FP_SCAN_TYPE_PRESS; + + img_class->img_open = aes3k_dev_init; + img_class->img_close = aes3k_dev_deinit; + img_class->activate = aes3k_dev_activate; + img_class->deactivate = aes3k_dev_deactivate; + + /* Extremely low due to low image quality. */ + img_class->bz3_threshold = 9; + + /* Everything else is set by the subclasses. */ +} diff --git a/libfprint/drivers/aes3k.h b/libfprint/drivers/aes3k.h index a54199d0..ac491b7a 100644 --- a/libfprint/drivers/aes3k.h +++ b/libfprint/drivers/aes3k.h @@ -34,25 +34,26 @@ * */ -#ifndef __AES3K_H -#define __AES3K_H +#pragma once +#include "fpi-image-device.h" +#include "aeslib.h" #define AES3K_FRAME_HEIGHT 16 -struct aes3k_dev { - struct libusb_transfer *img_trf; - size_t frame_width; /* image size = frame_width x frame_width */ - size_t frame_size; /* 4 bits/pixel: frame_width x AES3K_FRAME_HEIGHT / 2 */ - size_t frame_number; /* number of frames */ - size_t enlarge_factor; +G_DECLARE_DERIVABLE_TYPE(FpiDeviceAes3k, fpi_device_aes3k, FPI, + DEVICE_AES3K, FpImageDevice) - size_t data_buflen; /* buffer length of usb bulk transfer */ +#define FPI_TYPE_DEVICE_AES3K (fpi_device_aes3k_get_type ()) + +struct _FpiDeviceAes3kClass { + FpImageDeviceClass parent; + + gsize frame_width; /* image size = frame_width x frame_width */ + gsize frame_size; /* 4 bits/pixel: frame_width x AES3K_FRAME_HEIGHT / 2 */ + gsize frame_number; /* number of frames */ + gsize enlarge_factor; + + gsize data_buflen; /* buffer length of usb bulk transfer */ struct aes_regwrite *init_reqs; /* initial values sent to device */ - size_t init_reqs_len; + gsize init_reqs_len; }; - - -int aes3k_dev_activate(struct fp_img_dev *dev); -void aes3k_dev_deactivate(struct fp_img_dev *dev); - -#endif diff --git a/libfprint/drivers/aes4000.c b/libfprint/drivers/aes4000.c index 6ea79d15..02984891 100644 --- a/libfprint/drivers/aes4000.c +++ b/libfprint/drivers/aes4000.c @@ -26,8 +26,6 @@ #define FP_COMPONENT "aes4000" -#include "drivers_api.h" -#include "aeslib.h" #include "aes3k.h" #define DATA_BUFLEN 0x1259 @@ -114,67 +112,39 @@ static struct aes_regwrite init_reqs[] = { { 0x81, 0x00 }, }; -static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) -{ - int r; - struct aes3k_dev *aesdev; - - r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - if (r < 0) { - fp_err("could not claim interface 0: %s", libusb_error_name(r)); - return r; - } - - aesdev = g_malloc0(sizeof(struct aes3k_dev)); - fp_dev_set_instance_data(FP_DEV(dev), aesdev); - - if (!aesdev) - return -ENOMEM; - - aesdev->data_buflen = DATA_BUFLEN; - aesdev->frame_width = FRAME_WIDTH; - aesdev->frame_size = FRAME_SIZE; - aesdev->frame_number = FRAME_NUMBER; - aesdev->enlarge_factor = ENLARGE_FACTOR; - aesdev->init_reqs = init_reqs; - aesdev->init_reqs_len = G_N_ELEMENTS(init_reqs); - fpi_imgdev_open_complete(dev, 0); - - return r; -} - -static void dev_deinit(struct fp_img_dev *dev) -{ - struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); - g_free(aesdev); - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - fpi_imgdev_close_complete(dev); -} +struct _FpiDeviceAes4000 { + FpiDeviceAes3k parent; +}; +G_DECLARE_FINAL_TYPE(FpiDeviceAes4000, fpi_device_aes4000, FPI, + DEVICE_AES4000, FpiDeviceAes3k); +G_DEFINE_TYPE(FpiDeviceAes4000, fpi_device_aes4000, FPI_TYPE_DEVICE_AES3K); -static const struct usb_id id_table[] = { - { .vendor = 0x08ff, .product = 0x5501 }, - { 0, 0, 0, }, +static const FpIdEntry id_table [ ] = { + { .pid = 0x08ff, .vid = 0x5501 }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -struct fp_img_driver aes4000_driver = { - .driver = { - .id = AES4000_ID, - .name = FP_COMPONENT, - .full_name = "AuthenTec AES4000", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_PRESS, - }, - .flags = 0, - .img_height = FRAME_WIDTH * ENLARGE_FACTOR, - .img_width = FRAME_WIDTH * ENLARGE_FACTOR, +static void fpi_device_aes4000_init(FpiDeviceAes4000 *self) { +} - /* temporarily lowered until image quality improves */ - .bz3_threshold = 9, +static void fpi_device_aes4000_class_init(FpiDeviceAes4000Class *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); + FpiDeviceAes3kClass *aes_class = FPI_DEVICE_AES3K_CLASS (klass); - .open = dev_init, - .close = dev_deinit, - .activate = aes3k_dev_activate, - .deactivate = aes3k_dev_deactivate, -}; + dev_class->id = "aes4000"; + dev_class->full_name = "AuthenTec AES4000"; + dev_class->id_table = id_table; + img_class->img_height = FRAME_WIDTH * ENLARGE_FACTOR; + img_class->img_width = FRAME_WIDTH * ENLARGE_FACTOR; + + aes_class->data_buflen = DATA_BUFLEN; + aes_class->frame_width = FRAME_WIDTH; + aes_class->frame_size = FRAME_SIZE; + aes_class->frame_number = FRAME_NUMBER; + aes_class->enlarge_factor = ENLARGE_FACTOR; + aes_class->init_reqs = init_reqs; + aes_class->init_reqs_len = G_N_ELEMENTS(init_reqs); +} diff --git a/libfprint/drivers/aeslib.c b/libfprint/drivers/aeslib.c index 24e307ce..0e5557ea 100644 --- a/libfprint/drivers/aeslib.c +++ b/libfprint/drivers/aeslib.c @@ -24,20 +24,17 @@ #include #include -#include - -#include "fpi-usb.h" +#include "fpi-usb-transfer.h" #include "fpi-assembling.h" #include "aeslib.h" #define MAX_REGWRITES_PER_REQUEST 16 #define BULK_TIMEOUT 4000 -#define EP_IN (1 | LIBUSB_ENDPOINT_IN) -#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT) +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) struct write_regv_data { - struct fp_img_dev *imgdev; unsigned int num_regs; const struct aes_regwrite *regs; unsigned int offset; @@ -45,73 +42,62 @@ struct write_regv_data { void *user_data; }; -static void continue_write_regv(struct write_regv_data *wdata); +static void continue_write_regv(FpImageDevice *dev, struct write_regv_data *wdata); /* libusb bulk callback for regv write completion transfer. continues the * transaction */ -static void write_regv_trf_complete(struct libusb_transfer *transfer) +static void write_regv_trf_complete(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - struct write_regv_data *wdata = transfer->user_data; + struct write_regv_data *wdata = user_data; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - wdata->callback(wdata->imgdev, -EIO, wdata->user_data); - g_free(wdata); - } else if (transfer->length != transfer->actual_length) { - wdata->callback(wdata->imgdev, -EPROTO, wdata->user_data); + if (error) { + wdata->callback(FP_IMAGE_DEVICE (device), error, wdata->user_data); g_free(wdata); } else { - continue_write_regv(wdata); + continue_write_regv(FP_IMAGE_DEVICE (device), wdata); } - - g_free(transfer->buffer); - libusb_free_transfer(transfer); } /* write from wdata->offset to upper_bound (inclusive) of wdata->regs */ -static int do_write_regv(struct write_regv_data *wdata, int upper_bound) +static void do_write_regv(FpImageDevice *dev, struct write_regv_data *wdata, int upper_bound) { unsigned int offset = wdata->offset; unsigned int num = upper_bound - offset + 1; size_t alloc_size = num * 2; - unsigned char *data = g_malloc(alloc_size); unsigned int i; size_t data_offset = 0; - struct libusb_transfer *transfer = fpi_usb_alloc(); - int r; + FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE (dev)); + + fpi_usb_transfer_fill_bulk (transfer, EP_OUT, alloc_size); for (i = offset; i < offset + num; i++) { const struct aes_regwrite *regwrite = &wdata->regs[i]; - data[data_offset++] = regwrite->reg; - data[data_offset++] = regwrite->value; + transfer->buffer[data_offset++] = regwrite->reg; + transfer->buffer[data_offset++] = regwrite->value; } - libusb_fill_bulk_transfer(transfer, FP_DEV(wdata->imgdev)->udev, EP_OUT, data, - alloc_size, write_regv_trf_complete, wdata, BULK_TIMEOUT); - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - } - - return r; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + write_regv_trf_complete, wdata); + fpi_usb_transfer_unref (transfer); } /* write the next batch of registers to be written, or if there are no more, * indicate completion to the caller */ -static void continue_write_regv(struct write_regv_data *wdata) +static void continue_write_regv(FpImageDevice *dev, struct write_regv_data *wdata) { unsigned int offset = wdata->offset; unsigned int regs_remaining; unsigned int limit; unsigned int upper_bound; int i; - int r; /* skip all zeros and ensure there is still work to do */ while (TRUE) { if (offset >= wdata->num_regs) { fp_dbg("all registers written"); - wdata->callback(wdata->imgdev, 0, wdata->user_data); + wdata->callback(dev, 0, wdata->user_data); g_free(wdata); return; } @@ -133,12 +119,7 @@ static void continue_write_regv(struct write_regv_data *wdata) break; } - r = do_write_regv(wdata, upper_bound); - if (r < 0) { - wdata->callback(wdata->imgdev, r, wdata->user_data); - g_free(wdata); - return; - } + do_write_regv(dev, wdata, upper_bound); wdata->offset = upper_bound + 1; } @@ -146,20 +127,20 @@ static void continue_write_regv(struct write_regv_data *wdata) /* write a load of registers to the device, combining multiple writes in a * single URB up to a limit. insert writes to non-existent register 0 to force * specific groups of writes to be separated by different URBs. */ -void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs, - unsigned int num_regs, aes_write_regv_cb callback, void *user_data) +void aes_write_regv(FpImageDevice *dev, const struct aes_regwrite *regs, + unsigned int num_regs, aes_write_regv_cb callback, + void *user_data) { struct write_regv_data *wdata; fp_dbg("write %d regs", num_regs); wdata = g_malloc(sizeof(*wdata)); - wdata->imgdev = dev; wdata->num_regs = num_regs; wdata->regs = regs; wdata->offset = 0; wdata->callback = callback; wdata->user_data = user_data; - continue_write_regv(wdata); + continue_write_regv(dev, wdata); } unsigned char aes_get_pixel(struct fpi_frame_asmbl_ctx *ctx, diff --git a/libfprint/drivers/aeslib.h b/libfprint/drivers/aeslib.h index 41cbe1ee..2a45e993 100644 --- a/libfprint/drivers/aeslib.h +++ b/libfprint/drivers/aeslib.h @@ -30,11 +30,12 @@ struct aes_regwrite { struct fpi_frame; struct fpi_frame_asmbl_ctx; -typedef void (*aes_write_regv_cb)(struct fp_img_dev *dev, int result, - void *user_data); +typedef void (*aes_write_regv_cb)(FpImageDevice *dev, GError *error, + void *user_data); -void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs, - unsigned int num_regs, aes_write_regv_cb callback, void *user_data); +void aes_write_regv(FpImageDevice *dev, const struct aes_regwrite *regs, + unsigned int num_regs, aes_write_regv_cb callback, + void *user_data); unsigned char aes_get_pixel(struct fpi_frame_asmbl_ctx *ctx, struct fpi_frame *frame, diff --git a/meson.build b/meson.build index df26addc..570d701b 100644 --- a/meson.build +++ b/meson.build @@ -51,7 +51,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img', 'vfs5011' ] +default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000' ] all_drivers = default_drivers + virtual_drivers From 5e05afecf2028e2328d435f7a36a06c58c9f265f Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 8 Jul 2019 15:38:46 +0200 Subject: [PATCH 31/73] aes1610: Port driver to new API --- libfprint/drivers/aes1610.c | 400 +++++++++++++++++------------------- meson.build | 2 +- 2 files changed, 188 insertions(+), 214 deletions(-) diff --git a/libfprint/drivers/aes1610.c b/libfprint/drivers/aes1610.c index df5b5695..0d3ca4a6 100644 --- a/libfprint/drivers/aes1610.c +++ b/libfprint/drivers/aes1610.c @@ -28,8 +28,8 @@ #include "drivers_api.h" #include "aeslib.h" -static void start_capture(struct fp_img_dev *dev); -static void complete_deactivation(struct fp_img_dev *dev); +static void start_capture(FpImageDevice *dev); +static void complete_deactivation(FpImageDevice *dev); static int adjust_gain(unsigned char *buffer, int status); #define FIRST_AES1610_REG 0x1B @@ -39,8 +39,8 @@ static int adjust_gain(unsigned char *buffer, int status); #define GAIN_STATUS_NORMAL 2 /* FIXME these need checking */ -#define EP_IN (1 | LIBUSB_ENDPOINT_IN) -#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT) +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) #define BULK_TIMEOUT 4000 @@ -69,13 +69,18 @@ static int adjust_gain(unsigned char *buffer, int status); /****** GENERAL FUNCTIONS ******/ -struct aes1610_dev { - uint8_t read_regs_retry_count; +struct _FpiDeviceAes1610 { + FpImageDevice parent; + + guint8 read_regs_retry_count; GSList *strips; - size_t strips_len; + gsize strips_len; gboolean deactivating; - uint8_t blanks_count; + guint8 blanks_count; }; +G_DECLARE_FINAL_TYPE(FpiDeviceAes1610, fpi_device_aes1610, FPI, DEVICE_AES1610, + FpImageDevice); +G_DEFINE_TYPE(FpiDeviceAes1610, fpi_device_aes1610, FP_TYPE_IMAGE_DEVICE); static struct fpi_frame_asmbl_ctx assembling_ctx = { .frame_width = FRAME_WIDTH, @@ -84,67 +89,62 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = { .get_pixel = aes_get_pixel, }; -typedef void (*aes1610_read_regs_cb)(struct fp_img_dev *dev, int status, - unsigned char *regs, void *user_data); +typedef void (*aes1610_read_regs_cb)(FpImageDevice *dev, int status, + unsigned char *regs, void *user_data); struct aes1610_read_regs { - struct fp_img_dev *dev; + FpImageDevice *dev; aes1610_read_regs_cb callback; struct aes_regwrite *regwrite; void *user_data; }; /* FIXME: what to do here? */ -static void stub_capture_stop_cb(struct fp_img_dev *dev, int result, void *user_data) +static void stub_capture_stop_cb(FpImageDevice *dev, GError *error, + void *user_data) { - + if (error) { + fp_warn ("Error stopping capture: %s", error->message); + g_error_free (error); + } } /* check that read succeeded but ignore all data */ -static void generic_ignore_data_cb(struct libusb_transfer *transfer) +static void generic_ignore_data_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - fpi_ssm_mark_failed(ssm, -EIO); - else if (transfer->length != transfer->actual_length) - fpi_ssm_mark_failed(ssm, -EPROTO); + if (error) + fpi_ssm_mark_failed(transfer->ssm, error); else - fpi_ssm_next_state(ssm); - - g_free(transfer->buffer); - libusb_free_transfer(transfer); + fpi_ssm_next_state(transfer->ssm); } -static void generic_write_regv_cb(struct fp_img_dev *dev, int result, - void *user_data) +static void generic_write_regv_cb(FpImageDevice *dev, GError *error, + void *user_data) { - fpi_ssm *ssm = user_data; - if (result == 0) + FpiSsm *ssm = user_data; + if (!error) fpi_ssm_next_state(ssm); else - fpi_ssm_mark_failed(ssm, result); + fpi_ssm_mark_failed(ssm, error); } /* read the specified number of bytes from the IN endpoint but throw them * away, then increment the SSM */ -static void generic_read_ignore_data(fpi_ssm *ssm, struct fp_dev *dev, size_t bytes) +static void generic_read_ignore_data(FpiSsm *ssm, FpDevice *dev, + size_t bytes) { - struct libusb_transfer *transfer = fpi_usb_alloc(); + FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); unsigned char *data; - int r; data = g_malloc(bytes); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(dev), EP_IN, data, bytes, - generic_ignore_data_cb, ssm, BULK_TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + fpi_usb_transfer_fill_bulk_full(transfer, EP_IN, data, bytes, NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + generic_ignore_data_cb, NULL); + fpi_usb_transfer_unref(transfer); } /****** FINGER PRESENCE DETECTION ******/ @@ -175,21 +175,19 @@ static const struct aes_regwrite finger_det_reqs[] = { { 0x81, 0x04 } }; -static void start_finger_detection(struct fp_img_dev *dev); +static void start_finger_detection(FpImageDevice *dev); -static void finger_det_data_cb(struct libusb_transfer *transfer) +static void finger_det_data_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - struct fp_img_dev *dev = transfer->user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE(device); unsigned char *data = transfer->buffer; int i; int sum = 0; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fpi_imgdev_session_error(dev, -EIO); - goto out; - } else if (transfer->length != transfer->actual_length) { - fpi_imgdev_session_error(dev, -EPROTO); - goto out; + if (error) { + fpi_image_device_session_error (dev, error); + return; } /* examine histogram to determine finger presence */ @@ -199,48 +197,37 @@ static void finger_det_data_cb(struct libusb_transfer *transfer) /* reset default gain */ adjust_gain(data,GAIN_STATUS_FIRST); /* finger present, start capturing */ - fpi_imgdev_report_finger_status(dev, TRUE); + fpi_image_device_report_finger_status(dev, TRUE); start_capture(dev); } else { /* no finger, poll for a new histogram */ start_finger_detection(dev); } - -out: - g_free(data); - libusb_free_transfer(transfer); } -static void finger_det_reqs_cb(struct fp_img_dev *dev, int result, void *user_data) +static void finger_det_reqs_cb(FpImageDevice *dev, GError *error, + void *user_data) { - struct libusb_transfer *transfer; - unsigned char *data; - int r; + FpiUsbTransfer *transfer; - if (result) { - fpi_imgdev_session_error(dev, result); + if (error) { + fpi_image_device_session_error(dev, error); return; } - transfer = fpi_usb_alloc(); - data = g_malloc(FINGER_DETECTION_LEN); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, FINGER_DETECTION_LEN, - finger_det_data_cb, dev, BULK_TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_imgdev_session_error(dev, r); - } - + transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); + fpi_usb_transfer_fill_bulk (transfer, EP_IN, FINGER_DETECTION_LEN); + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + finger_det_data_cb, NULL); + fpi_usb_transfer_unref(transfer); } -static void start_finger_detection(struct fp_img_dev *dev) +static void start_finger_detection(FpImageDevice *dev) { - struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAes1610 *self = FPI_DEVICE_AES1610(dev); - if (aesdev->deactivating) { + if (self->deactivating) { complete_deactivation(dev); return; } @@ -545,21 +532,18 @@ enum capture_states { CAPTURE_NUM_STATES, }; -static void capture_read_strip_cb(struct libusb_transfer *transfer) +static void capture_read_strip_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { unsigned char *stripdata; - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpiDeviceAes1610 *self = FPI_DEVICE_AES1610(dev); unsigned char *data = transfer->buffer; - int sum, i; + gint sum, i; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fpi_ssm_mark_failed(ssm, -EIO); - goto out; - } else if (transfer->length != transfer->actual_length) { - fpi_ssm_mark_failed(ssm, -EPROTO); - goto out; + if (error) { + fpi_ssm_mark_failed (transfer->ssm, error); + return; } /* FIXME: would preallocating strip buffers be a decent optimization? */ @@ -572,6 +556,7 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer) sum += data[i]; } + fp_dbg("sum=%d", sum); if (sum > 0) { /* FIXME: would preallocating strip buffers be a decent optimization? */ struct fpi_frame *stripe = g_malloc(FRAME_WIDTH * (FRAME_HEIGHT / 2) + sizeof(struct fpi_frame)); @@ -579,66 +564,57 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer) stripe->delta_y = 0; stripdata = stripe->data; memcpy(stripdata, data + 1, FRAME_WIDTH * (FRAME_HEIGHT / 2)); - aesdev->strips = g_slist_prepend(aesdev->strips, stripe); - aesdev->strips_len++; - aesdev->blanks_count = 0; - } + self->strips = g_slist_prepend(self->strips, stripe); + self->strips_len++; + self->blanks_count = 0; + } else { + /* FIXME: 0 might be too low as a threshold */ + /* FIXME: sometimes we get 0 in the middle of a scan, should we wait for + * a few consecutive zeroes? */ - if (sum < 0) { - fpi_ssm_mark_failed(ssm, sum); - goto out; - } - fp_dbg("sum=%d", sum); - - /* FIXME: 0 might be too low as a threshold */ - /* FIXME: sometimes we get 0 in the middle of a scan, should we wait for - * a few consecutive zeroes? */ - - /* If sum is 0 for a reasonable # of frames, finger has been removed */ - if (sum == 0) { - aesdev->blanks_count++; + /* sum cannot be negative, so is 0 */ + self->blanks_count++; fp_dbg("got blank frame"); } + /* use histogram data above for gain calibration (0xbd, 0xbe, 0x29 and 0x2A ) */ adjust_gain(data, GAIN_STATUS_NORMAL); /* stop capturing if MAX_FRAMES is reached */ - if (aesdev->blanks_count > 10 || g_slist_length(aesdev->strips) >= MAX_FRAMES) { - struct fp_img *img; + if (self->blanks_count > 10 || g_slist_length(self->strips) >= MAX_FRAMES) { + FpImage *img; - fp_dbg("sending stop capture.... blanks=%d frames=%d", aesdev->blanks_count, g_slist_length(aesdev->strips)); + fp_dbg("sending stop capture.... blanks=%d frames=%d", + self->blanks_count, g_slist_length(self->strips)); /* send stop capture bits */ aes_write_regv(dev, capture_stop, G_N_ELEMENTS(capture_stop), stub_capture_stop_cb, NULL); - aesdev->strips = g_slist_reverse(aesdev->strips); - fpi_do_movement_estimation(&assembling_ctx, aesdev->strips, aesdev->strips_len); - img = fpi_assemble_frames(&assembling_ctx, aesdev->strips, aesdev->strips_len); - img->flags |= FP_IMG_PARTIAL; - g_slist_free_full(aesdev->strips, g_free); - aesdev->strips = NULL; - aesdev->strips_len = 0; - aesdev->blanks_count = 0; - fpi_imgdev_image_captured(dev, img); - fpi_imgdev_report_finger_status(dev, FALSE); + self->strips = g_slist_reverse(self->strips); + fpi_do_movement_estimation(&assembling_ctx, self->strips, + self->strips_len); + img = fpi_assemble_frames(&assembling_ctx, self->strips, + self->strips_len); + + g_slist_free_full(self->strips, g_free); + self->strips = NULL; + self->strips_len = 0; + self->blanks_count = 0; + fpi_image_device_image_captured(dev, img); + fpi_image_device_report_finger_status(dev, FALSE); /* marking machine complete will re-trigger finger detection loop */ - fpi_ssm_mark_completed(ssm); + fpi_ssm_mark_completed(transfer->ssm); /* Acquisition finished: restore default gain values */ restore_gain(); } else { /* obtain next strip */ - fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP); + fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_REQUEST_STRIP); } - -out: - g_free(data); - libusb_free_transfer(transfer); } -static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capture_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct aes1610_dev *aesdev = FP_INSTANCE_DATA(_dev); - int r; + FpImageDevice *dev = user_data; + FpiDeviceAes1610 *self = FPI_DEVICE_AES1610(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case CAPTURE_WRITE_REQS: @@ -652,56 +628,56 @@ static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data break; case CAPTURE_REQUEST_STRIP: fp_dbg("request strip"); - if (aesdev->deactivating) + if (self->deactivating) fpi_ssm_mark_completed(ssm); else aes_write_regv(dev, strip_scan_reqs, G_N_ELEMENTS(strip_scan_reqs), generic_write_regv_cb, ssm); break; case CAPTURE_READ_STRIP: ; - struct libusb_transfer *transfer = fpi_usb_alloc(); - unsigned char *data; + FpiUsbTransfer *transfer = fpi_usb_transfer_new(_dev); - data = g_malloc(STRIP_CAPTURE_LEN); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, STRIP_CAPTURE_LEN, - capture_read_strip_cb, ssm, BULK_TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + fpi_usb_transfer_fill_bulk (transfer, EP_IN, STRIP_CAPTURE_LEN); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + capture_read_strip_cb, NULL); + fpi_usb_transfer_unref(transfer); break; }; } -static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capture_sm_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - struct fp_img_dev *dev = user_data; - struct aes1610_dev *aesdev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpiDeviceAes1610 *self = FPI_DEVICE_AES1610(_dev); G_DEBUG_HERE(); - if (aesdev->deactivating) + if (self->deactivating) { complete_deactivation(dev); - else if (fpi_ssm_get_error(ssm)) - fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm)); - else + if (error) + g_error_free (error); + } else if (error) { + fpi_image_device_session_error(dev, error); + } else { start_finger_detection(dev); + } fpi_ssm_free(ssm); } -static void start_capture(struct fp_img_dev *dev) +static void start_capture(FpImageDevice *dev) { - struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_ssm *ssm; + FpiDeviceAes1610 *self = FPI_DEVICE_AES1610(dev); + FpiSsm *ssm; - if (aesdev->deactivating) { + if (self->deactivating) { complete_deactivation(dev); return; } - ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev); + ssm = fpi_ssm_new(FP_DEVICE(dev), capture_run_state, + CAPTURE_NUM_STATES, dev); G_DEBUG_HERE(); fpi_ssm_start(ssm, capture_sm_complete); } @@ -723,9 +699,9 @@ enum activate_states { ACTIVATE_NUM_STATES, }; -static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct fp_img_dev *dev = user_data; + FpImageDevice *dev = user_data; /* activation on aes1610 seems much more straightforward compared to aes2501 */ /* verify there's anything missing here */ @@ -738,100 +714,98 @@ static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_dat } /* jump to finger detection */ -static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_sm_complete(FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - struct fp_img_dev *dev = user_data; - fp_dbg("status %d", fpi_ssm_get_error(ssm)); - fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm)); + FpImageDevice *dev = user_data; + fpi_image_device_activate_complete(dev, error); - if (!fpi_ssm_get_error(ssm)) + if (!error) start_finger_detection(dev); fpi_ssm_free(ssm); } -static int dev_activate(struct fp_img_dev *dev) +static void dev_activate(FpImageDevice *dev) { - struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); - aesdev->read_regs_retry_count = 0; + FpiDeviceAes1610 *self = FPI_DEVICE_AES1610(dev); + FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); + self->read_regs_retry_count = 0; fpi_ssm_start(ssm, activate_sm_complete); - return 0; } -static void dev_deactivate(struct fp_img_dev *dev) +static void dev_deactivate(FpImageDevice *dev) { - struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAes1610 *self = FPI_DEVICE_AES1610(dev); /* FIXME: audit cancellation points, probably need more, specifically * in error handling paths? */ - aesdev->deactivating = TRUE; + self->deactivating = TRUE; } -static void complete_deactivation(struct fp_img_dev *dev) +static void complete_deactivation(FpImageDevice *dev) { - struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAes1610 *self = FPI_DEVICE_AES1610(dev); G_DEBUG_HERE(); /* FIXME: if we're in the middle of a scan, we should cancel the scan. * maybe we can do this with a master reset, unconditionally? */ - aesdev->deactivating = FALSE; - g_slist_free(aesdev->strips); - aesdev->strips = NULL; - aesdev->strips_len = 0; - aesdev->blanks_count = 0; - fpi_imgdev_deactivate_complete(dev); + self->deactivating = FALSE; + g_slist_free(self->strips); + self->strips = NULL; + self->strips_len = 0; + self->blanks_count = 0; + fpi_image_device_deactivate_complete(dev, NULL); } -static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) +static void dev_init(FpImageDevice *dev) { + GError *error = NULL; /* FIXME check endpoints */ - int r; - struct aes1610_dev *aesdev; - r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - if (r < 0) { - fp_err("could not claim interface 0: %s", libusb_error_name(r)); - return r; + if (!g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error)) { + fpi_image_device_open_complete(dev, error); + return; } - aesdev = g_malloc0(sizeof(struct aes1610_dev)); - fp_dev_set_instance_data(FP_DEV(dev), aesdev); - fpi_imgdev_open_complete(dev, 0); - return 0; + fpi_image_device_open_complete(dev, NULL); } -static void dev_deinit(struct fp_img_dev *dev) +static void dev_deinit(FpImageDevice *dev) { - struct aes1610_dev *aesdev; - aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); - g_free(aesdev); - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - fpi_imgdev_close_complete(dev); + GError *error = NULL; + + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), + 0, 0, &error); + fpi_image_device_close_complete(dev, error); } -static const struct usb_id id_table[] = { - { .vendor = 0x08ff, .product = 0x1600 }, /* AES1600 */ - { 0, 0, 0, }, +static const FpIdEntry id_table [ ] = { + { .vid = 0x08ff, .pid = 0x1600, + }, /* AES1600 */ + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -struct fp_img_driver aes1610_driver = { - .driver = { - .id = AES1610_ID, - .name = FP_COMPONENT, - .full_name = "AuthenTec AES1610", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_SWIPE, - }, - .flags = 0, - .img_height = -1, - .img_width = IMAGE_WIDTH, +static void fpi_device_aes1610_init(FpiDeviceAes1610 *self) { +} +static void fpi_device_aes1610_class_init(FpiDeviceAes1610Class *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); - .bz3_threshold = 20, + dev_class->id = "aes1610"; + dev_class->full_name = "AuthenTec AES1610"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - .open = dev_init, - .close = dev_deinit, - .activate = dev_activate, - .deactivate = dev_deactivate, -}; + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; + + img_class->bz3_threshold = 20; + + img_class->img_width = IMAGE_WIDTH; + img_class->img_height = -1; +} diff --git a/meson.build b/meson.build index 570d701b..f4597110 100644 --- a/meson.build +++ b/meson.build @@ -51,7 +51,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000' ] +default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610' ] all_drivers = default_drivers + virtual_drivers From 0a47df7bb7c512618d83cde88c4aa7463a774f0b Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 8 Jul 2019 17:54:54 +0200 Subject: [PATCH 32/73] aesx660: Port aes1660 and aes2660 drivers to new API --- libfprint/drivers/aes1660.c | 124 +++---- libfprint/drivers/aes2660.c | 128 +++----- libfprint/drivers/aesx660.c | 621 ++++++++++++++++++++---------------- libfprint/drivers/aesx660.h | 56 ++-- meson.build | 2 +- 5 files changed, 470 insertions(+), 461 deletions(-) diff --git a/libfprint/drivers/aes1660.c b/libfprint/drivers/aes1660.c index f27b9bf9..cde7b482 100644 --- a/libfprint/drivers/aes1660.c +++ b/libfprint/drivers/aes1660.c @@ -27,6 +27,13 @@ #define FRAME_WIDTH 128 #define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2)) +struct _FpiDeviceAes1660 { + FpiDeviceAesX660 parent; +}; +G_DECLARE_FINAL_TYPE(FpiDeviceAes1660, fpi_device_aes1660, FPI, + DEVICE_AES1660, FpiDeviceAesX660); +G_DEFINE_TYPE(FpiDeviceAes1660, fpi_device_aes1660, FPI_TYPE_DEVICE_AES_X660); + static struct fpi_frame_asmbl_ctx assembling_ctx = { .frame_width = FRAME_WIDTH, .frame_height = AESX660_FRAME_HEIGHT, @@ -34,79 +41,50 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = { .get_pixel = aes_get_pixel, }; -static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) -{ - /* TODO check that device has endpoints we're using */ - int r; - struct aesX660_dev *aesdev; - - r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - if (r < 0) { - fp_err("could not claim interface 0: %s", libusb_error_name(r)); - return r; - } - - aesdev = g_malloc0(sizeof(struct aesX660_dev)); - fp_dev_set_instance_data(FP_DEV(dev), aesdev); - aesdev->buffer = g_malloc0(AES1660_FRAME_SIZE + AESX660_HEADER_SIZE); - aesdev->init_seqs[0] = aes1660_init_1; - aesdev->init_seqs_len[0] = G_N_ELEMENTS(aes1660_init_1); - aesdev->init_seqs[1] = aes1660_init_2; - aesdev->init_seqs_len[1] = G_N_ELEMENTS(aes1660_init_2); - aesdev->start_imaging_cmd = (unsigned char *)aes1660_start_imaging_cmd; - aesdev->start_imaging_cmd_len = sizeof(aes1660_start_imaging_cmd); - aesdev->assembling_ctx = &assembling_ctx; - aesdev->extra_img_flags = FP_IMG_PARTIAL; - - fpi_imgdev_open_complete(dev, 0); - return 0; -} - -static void dev_deinit(struct fp_img_dev *dev) -{ - struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); - g_free(aesdev->buffer); - g_free(aesdev); - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - fpi_imgdev_close_complete(dev); -} - -static const struct usb_id id_table[] = { - { .vendor = 0x08ff, .product = 0x1660 }, - { .vendor = 0x08ff, .product = 0x1680 }, - { .vendor = 0x08ff, .product = 0x1681 }, - { .vendor = 0x08ff, .product = 0x1682 }, - { .vendor = 0x08ff, .product = 0x1683 }, - { .vendor = 0x08ff, .product = 0x1684 }, - { .vendor = 0x08ff, .product = 0x1685 }, - { .vendor = 0x08ff, .product = 0x1686 }, - { .vendor = 0x08ff, .product = 0x1687 }, - { .vendor = 0x08ff, .product = 0x1688 }, - { .vendor = 0x08ff, .product = 0x1689 }, - { .vendor = 0x08ff, .product = 0x168a }, - { .vendor = 0x08ff, .product = 0x168b }, - { .vendor = 0x08ff, .product = 0x168c }, - { .vendor = 0x08ff, .product = 0x168d }, - { .vendor = 0x08ff, .product = 0x168e }, - { .vendor = 0x08ff, .product = 0x168f }, - { 0, 0, 0, }, +static const FpIdEntry id_table [ ] = { + { .vid = 0x08ff, .pid = 0x1660, }, + { .vid = 0x08ff, .pid = 0x1680, }, + { .vid = 0x08ff, .pid = 0x1681, }, + { .vid = 0x08ff, .pid = 0x1682, }, + { .vid = 0x08ff, .pid = 0x1683, }, + { .vid = 0x08ff, .pid = 0x1684, }, + { .vid = 0x08ff, .pid = 0x1685, }, + { .vid = 0x08ff, .pid = 0x1686, }, + { .vid = 0x08ff, .pid = 0x1687, }, + { .vid = 0x08ff, .pid = 0x1688, }, + { .vid = 0x08ff, .pid = 0x1689, }, + { .vid = 0x08ff, .pid = 0x168a, }, + { .vid = 0x08ff, .pid = 0x168b, }, + { .vid = 0x08ff, .pid = 0x168c, }, + { .vid = 0x08ff, .pid = 0x168d, }, + { .vid = 0x08ff, .pid = 0x168e, }, + { .vid = 0x08ff, .pid = 0x168f, }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -struct fp_img_driver aes1660_driver = { - .driver = { - .id = AES1660_ID, - .name = FP_COMPONENT, - .full_name = "AuthenTec AES1660", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_SWIPE, - }, - .flags = 0, - .img_height = -1, - .img_width = FRAME_WIDTH + FRAME_WIDTH / 2, - .bz3_threshold = 20, +static void fpi_device_aes1660_init(FpiDeviceAes1660 *self) { +} +static void fpi_device_aes1660_class_init(FpiDeviceAes1660Class *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); + FpiDeviceAesX660Class *aes_class = FPI_DEVICE_AES_X660_CLASS (klass); - .open = dev_init, - .close = dev_deinit, - .activate = aesX660_dev_activate, - .deactivate = aesX660_dev_deactivate, -}; + dev_class->id = "aes1660"; + dev_class->full_name = "AuthenTec AES1660"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + + img_class->bz3_threshold = 20; + + img_class->img_width = FRAME_WIDTH + FRAME_WIDTH / 2; + img_class->img_height = -1; + + aes_class->init_seqs[0] = aes1660_init_1; + aes_class->init_seqs_len[0] = G_N_ELEMENTS(aes1660_init_1); + aes_class->init_seqs[1] = aes1660_init_2; + aes_class->init_seqs_len[1] = G_N_ELEMENTS(aes1660_init_2); + aes_class->start_imaging_cmd = (unsigned char *)aes1660_start_imaging_cmd; + aes_class->start_imaging_cmd_len = sizeof(aes1660_start_imaging_cmd); + aes_class->assembling_ctx = &assembling_ctx; +} diff --git a/libfprint/drivers/aes2660.c b/libfprint/drivers/aes2660.c index de380e7a..3b054644 100644 --- a/libfprint/drivers/aes2660.c +++ b/libfprint/drivers/aes2660.c @@ -27,6 +27,13 @@ #define FRAME_WIDTH 192 #define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2)) +struct _FpiDeviceAes2660 { + FpiDeviceAesX660 parent; +}; +G_DECLARE_FINAL_TYPE(FpiDeviceAes2660, fpi_device_aes2660, FPI, + DEVICE_AES2660, FpiDeviceAesX660); +G_DEFINE_TYPE(FpiDeviceAes2660, fpi_device_aes2660, FPI_TYPE_DEVICE_AES_X660); + static struct fpi_frame_asmbl_ctx assembling_ctx = { .frame_width = FRAME_WIDTH, .frame_height = AESX660_FRAME_HEIGHT, @@ -34,81 +41,52 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = { .get_pixel = aes_get_pixel, }; -static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) -{ - /* TODO check that device has endpoints we're using */ - int r; - struct aesX660_dev *aesdev; - - r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - if (r < 0) { - fp_err("could not claim interface 0: %s", libusb_error_name(r)); - return r; - } - - aesdev = g_malloc0(sizeof(struct aesX660_dev)); - fp_dev_set_instance_data(FP_DEV(dev), aesdev); - aesdev->buffer = g_malloc0(AES2660_FRAME_SIZE + AESX660_HEADER_SIZE); - /* No scaling for AES2660 */ - aesdev->init_seqs[0] = aes2660_init_1; - aesdev->init_seqs_len[0] = G_N_ELEMENTS(aes2660_init_1); - aesdev->init_seqs[1] = aes2660_init_2; - aesdev->init_seqs_len[1] = G_N_ELEMENTS(aes2660_init_2); - aesdev->start_imaging_cmd = (unsigned char *)aes2660_start_imaging_cmd; - aesdev->start_imaging_cmd_len = sizeof(aes2660_start_imaging_cmd); - aesdev->assembling_ctx = &assembling_ctx; - aesdev->extra_img_flags = FP_IMG_PARTIAL; - - fpi_imgdev_open_complete(dev, 0); - return 0; -} - -static void dev_deinit(struct fp_img_dev *dev) -{ - struct aesX660_dev *aesdev; - aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); - g_free(aesdev->buffer); - g_free(aesdev); - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - fpi_imgdev_close_complete(dev); -} - -static const struct usb_id id_table[] = { - { .vendor = 0x08ff, .product = 0x2660 }, - { .vendor = 0x08ff, .product = 0x2680 }, - { .vendor = 0x08ff, .product = 0x2681 }, - { .vendor = 0x08ff, .product = 0x2682 }, - { .vendor = 0x08ff, .product = 0x2683 }, - { .vendor = 0x08ff, .product = 0x2684 }, - { .vendor = 0x08ff, .product = 0x2685 }, - { .vendor = 0x08ff, .product = 0x2686 }, - { .vendor = 0x08ff, .product = 0x2687 }, - { .vendor = 0x08ff, .product = 0x2688 }, - { .vendor = 0x08ff, .product = 0x2689 }, - { .vendor = 0x08ff, .product = 0x268a }, - { .vendor = 0x08ff, .product = 0x268b }, - { .vendor = 0x08ff, .product = 0x268c }, - { .vendor = 0x08ff, .product = 0x268d }, - { .vendor = 0x08ff, .product = 0x268e }, - { .vendor = 0x08ff, .product = 0x268f }, - { .vendor = 0x08ff, .product = 0x2691 }, - { 0, 0, 0, }, +static const FpIdEntry id_table [ ] = { + { .vid = 0x08ff, .pid = 0x2660, }, + { .vid = 0x08ff, .pid = 0x2680, }, + { .vid = 0x08ff, .pid = 0x2681, }, + { .vid = 0x08ff, .pid = 0x2682, }, + { .vid = 0x08ff, .pid = 0x2683, }, + { .vid = 0x08ff, .pid = 0x2684, }, + { .vid = 0x08ff, .pid = 0x2685, }, + { .vid = 0x08ff, .pid = 0x2686, }, + { .vid = 0x08ff, .pid = 0x2687, }, + { .vid = 0x08ff, .pid = 0x2688, }, + { .vid = 0x08ff, .pid = 0x2689, }, + { .vid = 0x08ff, .pid = 0x268a, }, + { .vid = 0x08ff, .pid = 0x268b, }, + { .vid = 0x08ff, .pid = 0x268c, }, + { .vid = 0x08ff, .pid = 0x268d, }, + { .vid = 0x08ff, .pid = 0x268e, }, + { .vid = 0x08ff, .pid = 0x268f, }, + { .vid = 0x08ff, .pid = 0x2691, }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -struct fp_img_driver aes2660_driver = { - .driver = { - .id = AES2660_ID, - .name = FP_COMPONENT, - .full_name = "AuthenTec AES2660", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_SWIPE, - }, - .flags = 0, - .img_height = -1, - .img_width = FRAME_WIDTH + FRAME_WIDTH / 2, +static void fpi_device_aes2660_init(FpiDeviceAes2660 *self) { +} - .open = dev_init, - .close = dev_deinit, - .activate = aesX660_dev_activate, - .deactivate = aesX660_dev_deactivate, -}; +static void fpi_device_aes2660_class_init(FpiDeviceAes2660Class *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); + FpiDeviceAesX660Class *aes_class = FPI_DEVICE_AES_X660_CLASS (klass); + + dev_class->id = "aes2660"; + dev_class->full_name = "AuthenTec AES2660"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + + img_class->bz3_threshold = 20; + + img_class->img_width = FRAME_WIDTH + FRAME_WIDTH / 2; + img_class->img_height = -1; + + aes_class->init_seqs[0] = aes2660_init_1; + aes_class->init_seqs_len[0] = G_N_ELEMENTS(aes2660_init_1); + aes_class->init_seqs[1] = aes2660_init_2; + aes_class->init_seqs_len[1] = G_N_ELEMENTS(aes2660_init_2); + aes_class->start_imaging_cmd = (unsigned char *)aes2660_start_imaging_cmd; + aes_class->start_imaging_cmd_len = sizeof(aes2660_start_imaging_cmd); + aes_class->assembling_ctx = &assembling_ctx; +} diff --git a/libfprint/drivers/aesx660.c b/libfprint/drivers/aesx660.c index 47da51f5..5ea4cae4 100644 --- a/libfprint/drivers/aesx660.c +++ b/libfprint/drivers/aesx660.c @@ -27,11 +27,24 @@ #include "aeslib.h" #include "aesx660.h" -static void start_capture(struct fp_img_dev *dev); -static void complete_deactivation(struct fp_img_dev *dev); +typedef struct { + GByteArray *stripe_packet; + GSList *strips; + size_t strips_len; + gboolean deactivating; + struct aesX660_cmd *init_seq; + size_t init_seq_len; + unsigned int init_cmd_idx; + unsigned int init_seq_idx; +} FpiDeviceAesX660Private; -#define EP_IN (1 | LIBUSB_ENDPOINT_IN) -#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT) +G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(FpiDeviceAesX660, fpi_device_aes_x660, FP_TYPE_IMAGE_DEVICE); + +static void start_capture(FpImageDevice *dev); +static void complete_deactivation(FpImageDevice *dev); + +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) #define BULK_TIMEOUT 4000 #define FRAME_HEIGHT AESX660_FRAME_HEIGHT @@ -41,99 +54,84 @@ static void complete_deactivation(struct fp_img_dev *dev); #define FINGER_DET_DATA_LEN 4 static void -aesX660_send_cmd_timeout(fpi_ssm *ssm, - struct fp_dev *_dev, +aesX660_send_cmd_timeout(FpiSsm *ssm, + FpDevice *_dev, const unsigned char *cmd, size_t cmd_len, - libusb_transfer_cb_fn callback, + FpiUsbTransferCallback callback, int timeout) { - struct fp_img_dev *dev = FP_IMG_DEV(_dev); - struct libusb_transfer *transfer = fpi_usb_alloc(); - int r; + FpiUsbTransfer *transfer = fpi_usb_transfer_new(_dev); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, - (unsigned char *)cmd, cmd_len, - callback, ssm, timeout); - r = libusb_submit_transfer(transfer); - if (r < 0) { - fp_dbg("failed to submit transfer\n"); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, -ENOMEM); - } + fpi_usb_transfer_fill_bulk_full(transfer, EP_OUT, (unsigned char *)cmd, + cmd_len, NULL); + transfer->ssm = ssm; + fpi_usb_transfer_submit(transfer, timeout, NULL, callback, NULL); + fpi_usb_transfer_unref(transfer); } static void -aesX660_send_cmd(fpi_ssm *ssm, - struct fp_dev *dev, +aesX660_send_cmd(FpiSsm *ssm, + FpDevice *dev, const unsigned char *cmd, size_t cmd_len, - libusb_transfer_cb_fn callback) + FpiUsbTransferCallback callback) { return aesX660_send_cmd_timeout(ssm, dev, cmd, cmd_len, callback, BULK_TIMEOUT); } static void -aesX660_read_response(fpi_ssm *ssm, - struct fp_dev *_dev, +aesX660_read_response(FpiSsm *ssm, + FpDevice *_dev, + gboolean short_is_error, + gboolean cancellable, size_t buf_len, - libusb_transfer_cb_fn callback) + FpiUsbTransferCallback callback) { - struct fp_img_dev *dev = FP_IMG_DEV(_dev); - struct libusb_transfer *transfer = fpi_usb_alloc(); + FpiUsbTransfer *transfer = fpi_usb_transfer_new(_dev); unsigned char *data; - int r; + GCancellable *cancel = NULL; + if (cancellable) + cancel = fpi_device_get_cancellable (_dev); data = g_malloc(buf_len); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, - data, buf_len, - callback, ssm, BULK_TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - fp_dbg("Failed to submit rx transfer: %d\n", r); - g_free(data); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + fpi_usb_transfer_fill_bulk_full(transfer, EP_IN, data, buf_len, NULL); + transfer->ssm = ssm; + transfer->short_is_error = short_is_error; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, cancel, callback, NULL); + fpi_usb_transfer_unref(transfer); } -static void aesX660_send_cmd_cb(struct libusb_transfer *transfer) +static void aesX660_send_cmd_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - - if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && - (transfer->length == transfer->actual_length)) { - fpi_ssm_next_state(ssm); + if (!error) { + fpi_ssm_next_state(transfer->ssm); } else { - fp_dbg("tx transfer status: %d, actual_len: %.4x\n", - transfer->status, transfer->actual_length); - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, error); } - libusb_free_transfer(transfer); } -static void aesX660_read_calibrate_data_cb(struct libusb_transfer *transfer) +static void aesX660_read_calibrate_data_cb(FpiUsbTransfer *transfer, + FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; unsigned char *data = transfer->buffer; - if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || - (transfer->length != transfer->actual_length)) { - fpi_ssm_mark_failed(ssm, -EIO); - goto out; + if (error) { + fpi_ssm_mark_failed(transfer->ssm, error); + return; } /* Calibrate response was read correctly? */ if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_CALIBRATE_RESPONSE) { fp_dbg("Bogus calibrate response: %.2x\n", data[0]); - fpi_ssm_mark_failed(ssm, -EPROTO); - goto out; + fpi_ssm_mark_failed(transfer->ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Bogus calibrate response")); + return; } - fpi_ssm_next_state(ssm); -out: - g_free(transfer->buffer); - libusb_free_transfer(transfer); + fpi_ssm_next_state(transfer->ssm); } /****** FINGER PRESENCE DETECTION ******/ @@ -146,81 +144,78 @@ enum finger_det_states { FINGER_DET_NUM_STATES, }; -static void finger_det_read_fd_data_cb(struct libusb_transfer *transfer) +static void finger_det_read_fd_data_cb(FpiUsbTransfer *transfer, + FpDevice *device, gpointer user_data, + GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); unsigned char *data = transfer->buffer; - aesdev->fd_data_transfer = NULL; - - if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { - fp_dbg("Cancelling transfer...\n"); - fpi_ssm_next_state(ssm); - goto out; + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + fpi_ssm_next_state(transfer->ssm); + return; } - if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || - (transfer->length != transfer->actual_length)) { + if (error) { fp_dbg("Failed to read FD data\n"); - fpi_ssm_mark_failed(ssm, -EIO); - goto out; + fpi_ssm_mark_failed(transfer->ssm, error); + return; } if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_FINGER_DET_RESPONSE) { fp_dbg("Bogus FD response: %.2x\n", data[0]); - fpi_ssm_mark_failed(ssm, -EPROTO); - goto out; + fpi_ssm_mark_failed(transfer->ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Bogus FD response")); + return; } - if (data[AESX660_FINGER_PRESENT_OFFSET] == AESX660_FINGER_PRESENT || aesdev->deactivating) { + if (data[AESX660_FINGER_PRESENT_OFFSET] == AESX660_FINGER_PRESENT || priv->deactivating) { /* Finger present or we're deactivating... */ - fpi_ssm_next_state(ssm); + fpi_ssm_next_state(transfer->ssm); } else { fp_dbg("Wait for finger returned %.2x as result\n", data[AESX660_FINGER_PRESENT_OFFSET]); - fpi_ssm_jump_to_state(ssm, FINGER_DET_SEND_FD_CMD); + fpi_ssm_jump_to_state(transfer->ssm, FINGER_DET_SEND_FD_CMD); } -out: - g_free(data); - libusb_free_transfer(transfer); } -static void finger_det_set_idle_cmd_cb(struct libusb_transfer *transfer) +static void finger_det_set_idle_cmd_cb(FpiUsbTransfer *transfer, + FpDevice *device, gpointer user_data, + GError *error) { - fpi_ssm *ssm = transfer->user_data; - - if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && - (transfer->length == transfer->actual_length)) { - fpi_ssm_mark_completed(ssm); + if (!error) { + fpi_ssm_mark_completed(transfer->ssm); } else { - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, error); } - libusb_free_transfer(transfer); } -static void finger_det_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void finger_det_sm_complete(FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - struct fp_img_dev *dev = user_data; - struct aesX660_dev *aesdev = FP_INSTANCE_DATA(_dev); - int err = fpi_ssm_get_error(ssm); + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (_dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); fp_dbg("Finger detection completed"); - fpi_imgdev_report_finger_status(dev, TRUE); + fpi_image_device_report_finger_status(dev, TRUE); fpi_ssm_free(ssm); - if (aesdev->deactivating) + if (priv->deactivating) { complete_deactivation(dev); - else if (err) - fpi_imgdev_session_error(dev, err); - else { - fpi_imgdev_report_finger_status(dev, TRUE); + if (error) + g_error_free (error); + } else if (error) { + fpi_image_device_session_error(dev, error); + } else { + fpi_image_device_report_finger_status(dev, TRUE); start_capture(dev); } } -static void finger_det_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) +static void finger_det_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { switch (fpi_ssm_get_cur_state(ssm)) { case FINGER_DET_SEND_LED_CMD: @@ -232,7 +227,7 @@ static void finger_det_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_da aesX660_send_cmd_cb, 0); break; case FINGER_DET_READ_FD_DATA: - aesX660_read_response(ssm, dev, FINGER_DET_DATA_LEN, finger_det_read_fd_data_cb); + aesX660_read_response(ssm, dev, TRUE, TRUE, FINGER_DET_DATA_LEN, finger_det_read_fd_data_cb); break; case FINGER_DET_SET_IDLE: aesX660_send_cmd(ssm, dev, set_idle_cmd, sizeof(set_idle_cmd), @@ -241,17 +236,19 @@ static void finger_det_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_da } } -static void start_finger_detection(struct fp_img_dev *dev) +static void start_finger_detection(FpImageDevice *dev) { - fpi_ssm *ssm; - struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + FpiSsm *ssm; - if (aesdev->deactivating) { + if (priv->deactivating) { complete_deactivation(dev); return; } - ssm = fpi_ssm_new(FP_DEV(dev), finger_det_run_state, FINGER_DET_NUM_STATES, dev); + ssm = fpi_ssm_new(FP_DEVICE(dev), finger_det_run_state, + FINGER_DET_NUM_STATES, dev); fpi_ssm_start(ssm, finger_det_sm_complete); } @@ -266,13 +263,22 @@ enum capture_states { }; /* Returns number of processed bytes */ -static int process_stripe_data(fpi_ssm *ssm, struct fp_img_dev *dev, unsigned char *data) +static int process_stripe_data(FpiSsm *ssm, FpiDeviceAesX660 *self, + unsigned char *data, gsize length) { + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + FpiDeviceAesX660Class *cls = FPI_DEVICE_AES_X660_GET_CLASS (self); struct fpi_frame *stripe; unsigned char *stripdata; - struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); - stripe = g_malloc(aesdev->assembling_ctx->frame_width * FRAME_HEIGHT / 2 + sizeof(struct fpi_frame)); /* 4 bpp */ + if (length < AESX660_IMAGE_OFFSET + cls->assembling_ctx->frame_width * FRAME_HEIGHT / 2) { + fp_warn ("Received stripe data is too short, got %zi expected %i bytes!", + length, + AESX660_IMAGE_OFFSET + cls->assembling_ctx->frame_width * FRAME_HEIGHT / 2); + return 0; + } + + stripe = g_malloc(cls->assembling_ctx->frame_width * FRAME_HEIGHT / 2 + sizeof(struct fpi_frame)); /* 4 bpp */ stripdata = stripe->data; fp_dbg("Processing frame %.2x %.2x", data[AESX660_IMAGE_OK_OFFSET], @@ -283,10 +289,10 @@ static int process_stripe_data(fpi_ssm *ssm, struct fp_img_dev *dev, unsigned ch fp_dbg("Offset to previous frame: %d %d", stripe->delta_x, stripe->delta_y); if (data[AESX660_IMAGE_OK_OFFSET] == AESX660_IMAGE_OK) { - memcpy(stripdata, data + AESX660_IMAGE_OFFSET, aesdev->assembling_ctx->frame_width * FRAME_HEIGHT / 2); + memcpy(stripdata, data + AESX660_IMAGE_OFFSET, cls->assembling_ctx->frame_width * FRAME_HEIGHT / 2); - aesdev->strips = g_slist_prepend(aesdev->strips, stripe); - aesdev->strips_len++; + priv->strips = g_slist_prepend(priv->strips, stripe); + priv->strips_len++; return (data[AESX660_LAST_FRAME_OFFSET] & AESX660_LAST_FRAME_BIT); } @@ -294,88 +300,101 @@ static int process_stripe_data(fpi_ssm *ssm, struct fp_img_dev *dev, unsigned ch return 0; } -static void capture_set_idle_cmd_cb(struct libusb_transfer *transfer) +static void capture_set_idle_cmd_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + FpiDeviceAesX660Class *cls = FPI_DEVICE_AES_X660_GET_CLASS (self); - if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && - (transfer->length == transfer->actual_length)) { - struct fp_img *img; + if (!error) { + FpImage *img; - aesdev->strips = g_slist_reverse(aesdev->strips); - img = fpi_assemble_frames(aesdev->assembling_ctx, aesdev->strips, aesdev->strips_len); - img->flags |= aesdev->extra_img_flags; - g_slist_foreach(aesdev->strips, (GFunc) g_free, NULL); - g_slist_free(aesdev->strips); - aesdev->strips = NULL; - aesdev->strips_len = 0; - fpi_imgdev_image_captured(dev, img); - fpi_imgdev_report_finger_status(dev, FALSE); - fpi_ssm_mark_completed(ssm); + priv->strips = g_slist_reverse(priv->strips); + img = fpi_assemble_frames(cls->assembling_ctx, priv->strips, priv->strips_len); + g_slist_foreach(priv->strips, (GFunc) g_free, NULL); + g_slist_free(priv->strips); + priv->strips = NULL; + priv->strips_len = 0; + fpi_image_device_image_captured(dev, img); + fpi_image_device_report_finger_status(dev, FALSE); + fpi_ssm_mark_completed(transfer->ssm); } else { - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, error); } - libusb_free_transfer(transfer); } -static void capture_read_stripe_data_cb(struct libusb_transfer *transfer) +static void capture_read_stripe_data_cb(FpiUsbTransfer *transfer, + FpDevice *device, gpointer user_data, + GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); unsigned char *data = transfer->buffer; int finger_missing = 0; - size_t copied, actual_len = transfer->actual_length; + size_t actual_length = transfer->actual_length; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fpi_ssm_mark_failed(ssm, -EIO); - goto out; + if (error) { + g_byte_array_set_size (priv->stripe_packet, 0); + fpi_ssm_mark_failed(transfer->ssm, error); + return; } - fp_dbg("Got %lu bytes of data", actual_len); - do { - copied = MIN(aesdev->buffer_max - aesdev->buffer_size, actual_len); - memcpy(aesdev->buffer + aesdev->buffer_size, - data, - copied); - actual_len -= copied; - data += copied; - aesdev->buffer_size += copied; - fp_dbg("Copied %.4lx bytes into internal buffer", - copied); - if (aesdev->buffer_size == aesdev->buffer_max) { - if (aesdev->buffer_max == AESX660_HEADER_SIZE) { - aesdev->buffer_max = aesdev->buffer[AESX660_RESPONSE_SIZE_LSB_OFFSET] + - (aesdev->buffer[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8) + AESX660_HEADER_SIZE; - fp_dbg("Got frame, type %.2x size %.4lx", - aesdev->buffer[AESX660_RESPONSE_TYPE_OFFSET], - aesdev->buffer_max); - continue; - } else { - finger_missing |= process_stripe_data(ssm, dev, aesdev->buffer); - aesdev->buffer_max = AESX660_HEADER_SIZE; - aesdev->buffer_size = 0; - } - } - } while (actual_len); + fp_dbg("Got %lu bytes of data", actual_length); + while (actual_length) { + gssize payload_length; + gssize still_needed_len; + gssize copy_len; + + still_needed_len = MAX (0, AESX660_HEADER_SIZE - (gssize) priv->stripe_packet->len); + copy_len = MIN (actual_length, still_needed_len); + g_byte_array_append (priv->stripe_packet, data, copy_len); + data += copy_len; + actual_length -= copy_len; + + /* Do we have a full header? */ + if (priv->stripe_packet->len < AESX660_HEADER_SIZE) + break; + + payload_length = priv->stripe_packet->data[AESX660_RESPONSE_SIZE_LSB_OFFSET] + + (priv->stripe_packet->data[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8); + fp_dbg("Got frame, type %.2x payload of size %.4lx", + priv->stripe_packet->data[AESX660_RESPONSE_TYPE_OFFSET], + payload_length); + + still_needed_len = MAX (0, AESX660_HEADER_SIZE + payload_length - (gssize) priv->stripe_packet->len); + copy_len = MIN (actual_length, still_needed_len); + g_byte_array_append (priv->stripe_packet, data, copy_len); + data += copy_len; + actual_length -= copy_len; + + /* Do we have a full packet including the payload? */ + if (priv->stripe_packet->len < payload_length + AESX660_HEADER_SIZE) + break; + + finger_missing |= process_stripe_data(transfer->ssm, + self, + priv->stripe_packet->data, + priv->stripe_packet->len); + + g_byte_array_set_size (priv->stripe_packet, 0); + } fp_dbg("finger %s\n", finger_missing ? "missing" : "present"); if (finger_missing) { - fpi_ssm_next_state(ssm); + fpi_ssm_next_state(transfer->ssm); } else { - fpi_ssm_jump_to_state(ssm, CAPTURE_READ_STRIPE_DATA); + fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_READ_STRIPE_DATA); } -out: - g_free(transfer->buffer); - libusb_free_transfer(transfer); } -static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capture_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct aesX660_dev *aesdev = FP_INSTANCE_DATA(_dev); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (_dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + FpiDeviceAesX660Class *cls = FPI_DEVICE_AES_X660_GET_CLASS (self); switch (fpi_ssm_get_cur_state(ssm)) { case CAPTURE_SEND_LED_CMD: @@ -383,52 +402,56 @@ static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data aesX660_send_cmd_cb); break; case CAPTURE_SEND_CAPTURE_CMD: - aesdev->buffer_size = 0; - aesdev->buffer_max = AESX660_HEADER_SIZE; - aesX660_send_cmd(ssm, _dev, aesdev->start_imaging_cmd, - aesdev->start_imaging_cmd_len, + g_byte_array_set_size (priv->stripe_packet, 0); + aesX660_send_cmd(ssm, _dev, cls->start_imaging_cmd, + cls->start_imaging_cmd_len, aesX660_send_cmd_cb); break; case CAPTURE_READ_STRIPE_DATA: - aesX660_read_response(ssm, _dev, AESX660_BULK_TRANSFER_SIZE, + aesX660_read_response(ssm, _dev, FALSE, FALSE, AESX660_BULK_TRANSFER_SIZE, capture_read_stripe_data_cb); break; case CAPTURE_SET_IDLE: - fp_dbg("Got %lu frames\n", aesdev->strips_len); + fp_dbg("Got %lu frames\n", priv->strips_len); aesX660_send_cmd(ssm, _dev, set_idle_cmd, sizeof(set_idle_cmd), capture_set_idle_cmd_cb); break; } } -static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capture_sm_complete(FpiSsm *ssm, FpDevice *device, void *user_data, + GError *error) { - struct fp_img_dev *dev = user_data; - struct aesX660_dev *aesdev = FP_INSTANCE_DATA(_dev); - int err = fpi_ssm_get_error(ssm); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); fp_dbg("Capture completed"); fpi_ssm_free(ssm); - if (aesdev->deactivating) - complete_deactivation(dev); - else if (err) - fpi_imgdev_session_error(dev, err); - else - start_finger_detection(dev); + if (priv->deactivating) { + complete_deactivation(FP_IMAGE_DEVICE (device)); + if (error) + g_error_free (error); + } else if (error) { + fpi_image_device_session_error (FP_IMAGE_DEVICE (device), error); + } else { + start_finger_detection(FP_IMAGE_DEVICE (device)); + } } -static void start_capture(struct fp_img_dev *dev) +static void start_capture(FpImageDevice *dev) { - struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_ssm *ssm; + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + FpiSsm *ssm; - if (aesdev->deactivating) { + if (priv->deactivating) { complete_deactivation(dev); return; } - ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev); + ssm = fpi_ssm_new(FP_DEVICE(dev), capture_run_state, + CAPTURE_NUM_STATES, dev); G_DEBUG_HERE(); fpi_ssm_start(ssm, capture_sm_complete); } @@ -446,18 +469,18 @@ enum activate_states { ACTIVATE_NUM_STATES, }; -static void activate_read_id_cb(struct libusb_transfer *transfer) +static void activate_read_id_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + FpiDeviceAesX660Class *cls = FPI_DEVICE_AES_X660_GET_CLASS (self); unsigned char *data = transfer->buffer; - if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || - (transfer->length != transfer->actual_length)) { + if (error) { fp_dbg("read_id cmd failed\n"); - fpi_ssm_mark_failed(ssm, -EIO); - goto out; + fpi_ssm_mark_failed(transfer->ssm, error); + return; } /* ID was read correctly */ if (data[0] == 0x07) { @@ -465,83 +488,82 @@ static void activate_read_id_cb(struct libusb_transfer *transfer) data[4], data[3], data[5], data[6], data[7]); } else { fp_dbg("Bogus read ID response: %.2x\n", data[AESX660_RESPONSE_TYPE_OFFSET]); - fpi_ssm_mark_failed(ssm, -EPROTO); - goto out; + fpi_ssm_mark_failed(transfer->ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Bogus read ID response")); + return; } - switch (aesdev->init_seq_idx) { + switch (priv->init_seq_idx) { case 0: - aesdev->init_seq = aesdev->init_seqs[0]; - aesdev->init_seq_len = aesdev->init_seqs_len[0]; - aesdev->init_seq_idx = 1; - aesdev->init_cmd_idx = 0; + priv->init_seq = cls->init_seqs[0]; + priv->init_seq_len = cls->init_seqs_len[0]; + priv->init_seq_idx = 1; + priv->init_cmd_idx = 0; /* Do calibration only after 1st init sequence */ - fpi_ssm_jump_to_state(ssm, ACTIVATE_SEND_INIT_CMD); + fpi_ssm_jump_to_state(transfer->ssm, ACTIVATE_SEND_INIT_CMD); break; case 1: - aesdev->init_seq = aesdev->init_seqs[1]; - aesdev->init_seq_len = aesdev->init_seqs_len[1]; - aesdev->init_seq_idx = 2; - aesdev->init_cmd_idx = 0; - fpi_ssm_next_state(ssm); + priv->init_seq = cls->init_seqs[1]; + priv->init_seq_len = cls->init_seqs_len[1]; + priv->init_seq_idx = 2; + priv->init_cmd_idx = 0; + fpi_ssm_next_state(transfer->ssm); break; default: fp_dbg("Failed to init device! init status: %.2x\n", data[7]); - fpi_ssm_mark_failed(ssm, -EPROTO); + fpi_ssm_mark_failed(transfer->ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Failed to init device")); break; - } - -out: - g_free(transfer->buffer); - libusb_free_transfer(transfer); } -static void activate_read_init_cb(struct libusb_transfer *transfer) +static void activate_read_init_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); unsigned char *data = transfer->buffer; fp_dbg("read_init_cb\n"); - if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || - (transfer->length != transfer->actual_length)) { - fp_dbg("read_init transfer status: %d, actual_len: %d\n", transfer->status, transfer->actual_length); - fpi_ssm_mark_failed(ssm, -EIO); - goto out; + if (error) { + fp_dbg("read_init transfer status: %s, actual_len: %d\n", error->message, + (gint)transfer->actual_length); + fpi_ssm_mark_failed(transfer->ssm, error); + return; } /* ID was read correctly */ if (data[0] != 0x42 || data[3] != 0x01) { fp_dbg("Bogus read init response: %.2x %.2x\n", data[0], data[3]); - fpi_ssm_mark_failed(ssm, -EPROTO); - goto out; + fpi_ssm_mark_failed(transfer->ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Bogus read init response")); + return; } - aesdev->init_cmd_idx++; - if (aesdev->init_cmd_idx == aesdev->init_seq_len) { - if (aesdev->init_seq_idx < 2) - fpi_ssm_jump_to_state(ssm, ACTIVATE_SEND_READ_ID_CMD); + priv->init_cmd_idx++; + if (priv->init_cmd_idx == priv->init_seq_len) { + if (priv->init_seq_idx < 2) + fpi_ssm_jump_to_state(transfer->ssm, + ACTIVATE_SEND_READ_ID_CMD); else - fpi_ssm_mark_completed(ssm); - goto out; + fpi_ssm_mark_completed(transfer->ssm); + return; } - fpi_ssm_jump_to_state(ssm, ACTIVATE_SEND_INIT_CMD); -out: - g_free(transfer->buffer); - libusb_free_transfer(transfer); + fpi_ssm_jump_to_state(transfer->ssm, ACTIVATE_SEND_INIT_CMD); } -static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (_dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); switch (fpi_ssm_get_cur_state(ssm)) { case ACTIVATE_SET_IDLE: - aesdev->init_seq_idx = 0; + priv->init_seq_idx = 0; fp_dbg("Activate: set idle\n"); aesX660_send_cmd(ssm, _dev, set_idle_cmd, sizeof(set_idle_cmd), aesX660_send_cmd_cb); @@ -552,69 +574,112 @@ static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_dat aesX660_send_cmd_cb); break; case ACTIVATE_READ_ID: - aesX660_read_response(ssm, _dev, ID_LEN, activate_read_id_cb); + aesX660_read_response(ssm, _dev, TRUE, FALSE, ID_LEN, activate_read_id_cb); break; case ACTIVATE_SEND_INIT_CMD: fp_dbg("Activate: send init seq #%d cmd #%d\n", - aesdev->init_seq_idx, - aesdev->init_cmd_idx); + priv->init_seq_idx, + priv->init_cmd_idx); aesX660_send_cmd(ssm, _dev, - aesdev->init_seq[aesdev->init_cmd_idx].cmd, - aesdev->init_seq[aesdev->init_cmd_idx].len, + priv->init_seq[priv->init_cmd_idx].cmd, + priv->init_seq[priv->init_cmd_idx].len, aesX660_send_cmd_cb); break; case ACTIVATE_READ_INIT_RESPONSE: fp_dbg("Activate: read init response\n"); - aesX660_read_response(ssm, _dev, INIT_LEN, activate_read_init_cb); + aesX660_read_response(ssm, _dev, TRUE, FALSE, INIT_LEN, activate_read_init_cb); break; case ACTIVATE_SEND_CALIBRATE_CMD: aesX660_send_cmd(ssm, _dev, calibrate_cmd, sizeof(calibrate_cmd), aesX660_send_cmd_cb); break; case ACTIVATE_READ_CALIBRATE_DATA: - aesX660_read_response(ssm, _dev, CALIBRATE_DATA_LEN, aesX660_read_calibrate_data_cb); + aesX660_read_response(ssm, _dev, TRUE, FALSE, CALIBRATE_DATA_LEN, aesX660_read_calibrate_data_cb); break; } } -static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_sm_complete(FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - struct fp_img_dev *dev = user_data; - int err = fpi_ssm_get_error(ssm); - fp_dbg("status %d", err); - fpi_imgdev_activate_complete(dev, err); + fpi_image_device_activate_complete (FP_IMAGE_DEVICE (_dev), error); fpi_ssm_free(ssm); - if (!err) - start_finger_detection(dev); + if (!error) + start_finger_detection(FP_IMAGE_DEVICE (_dev)); } -int aesX660_dev_activate(struct fp_img_dev *dev) +static void aesX660_dev_activate(FpImageDevice *dev) { - fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); + FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); fpi_ssm_start(ssm, activate_sm_complete); - return 0; } -void aesX660_dev_deactivate(struct fp_img_dev *dev) +static void aesX660_dev_deactivate(FpImageDevice *dev) { - struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); - if (aesdev->fd_data_transfer) - libusb_cancel_transfer(aesdev->fd_data_transfer); - - aesdev->deactivating = TRUE; + priv->deactivating = TRUE; } -static void complete_deactivation(struct fp_img_dev *dev) +static void aesX660_dev_init(FpImageDevice *dev) { - struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + GError *error = NULL; + + g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error); + + priv->stripe_packet = g_byte_array_new (); + + fpi_image_device_open_complete(dev, error); +} + +static void aesX660_dev_deinit(FpImageDevice *dev) +{ + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + GError *error = NULL; + + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), + 0, 0, &error); + + g_clear_pointer (&priv->stripe_packet, g_byte_array_unref); + + fpi_image_device_close_complete(dev, error); +} + + +static void complete_deactivation(FpImageDevice *dev) +{ + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + G_DEBUG_HERE(); - aesdev->deactivating = FALSE; - g_slist_free(aesdev->strips); - aesdev->strips = NULL; - aesdev->strips_len = 0; - fpi_imgdev_deactivate_complete(dev); + priv->deactivating = FALSE; + g_slist_free(priv->strips); + priv->strips = NULL; + priv->strips_len = 0; + fpi_image_device_deactivate_complete(dev, NULL); +} + +static void fpi_device_aes_x660_init(FpiDeviceAesX660 *self) { +} + +static void fpi_device_aes_x660_class_init(FpiDeviceAesX660Class *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); + + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + + img_class->img_open = aesX660_dev_init; + img_class->img_close = aesX660_dev_deinit; + img_class->activate = aesX660_dev_activate; + img_class->deactivate = aesX660_dev_deactivate; + + /* Everything else is set by the subclasses. */ } diff --git a/libfprint/drivers/aesx660.h b/libfprint/drivers/aesx660.h index 8d8f3501..4d6faf56 100644 --- a/libfprint/drivers/aesx660.h +++ b/libfprint/drivers/aesx660.h @@ -17,8 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __AESX660_H -#define __AESX660_H +#pragma once #define AESX660_HEADER_SIZE 3 #define AESX660_RESPONSE_TYPE_OFFSET 0x00 @@ -43,37 +42,30 @@ #define AESX660_FRAME_HEIGHT 8 -struct aesX660_dev { - GSList *strips; - size_t strips_len; - gboolean deactivating; - struct aesX660_cmd *init_seq; - size_t init_seq_len; - unsigned int init_cmd_idx; - unsigned int init_seq_idx; - struct libusb_transfer *fd_data_transfer; - unsigned char *buffer; - size_t buffer_size; - size_t buffer_max; +G_DECLARE_DERIVABLE_TYPE(FpiDeviceAesX660, fpi_device_aes_x660, FPI, + DEVICE_AES_X660, FpImageDevice) - /* Device-specific stuff */ - struct aesX660_cmd *init_seqs[2]; - size_t init_seqs_len[2]; - unsigned char *start_imaging_cmd; - size_t start_imaging_cmd_len; - struct fpi_frame_asmbl_ctx *assembling_ctx; - uint16_t extra_img_flags; +#define FPI_TYPE_DEVICE_AES_X660 (fpi_device_aes_x660_get_type ()) + +struct _FpiDeviceAesX660Class { + FpImageDeviceClass parent; + + struct aesX660_cmd *init_seqs[2]; + gsize init_seqs_len[2]; + guint8 *start_imaging_cmd; + gsize start_imaging_cmd_len; + struct fpi_frame_asmbl_ctx *assembling_ctx; }; struct aesX660_cmd { - const unsigned char *cmd; - size_t len; + const guint8 *cmd; + gsize len; }; /* 0x77 cmd seems to control LED, this sequence * makes LED blink */ -static const unsigned char led_blink_cmd[] = { +static const guint8 led_blink_cmd[] = { 0x77, 0x18, 0x00, 0x00, 0x3f, 0x00, 0xff, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xf3, 0x01, 0x00, @@ -83,40 +75,36 @@ static const unsigned char led_blink_cmd[] = { /* This sequence makes LED light solid */ -static const unsigned char led_solid_cmd[] = { +static const guint8 led_solid_cmd[] = { 0x77, 0x18, 0x00, 0x00, 0x3f, 0x00, 0xff, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f }; -static const unsigned char wait_for_finger_cmd[] = { +static const guint8 wait_for_finger_cmd[] = { 0x20, 0x40, 0x04, 0x00, 0x02, 0x1e, 0x00, 0x32 }; /* 0x40 cmd response * -static const unsigned char pkt1371[] = { +static const guint8 pkt1371[] = { 0x40, 0x01, 0x00, 0x01 }; */ -static const unsigned char set_idle_cmd[] = { +static const guint8 set_idle_cmd[] = { 0x0d, /* Reset or "set idle"? */ }; -static const unsigned char read_id_cmd[] = { +static const guint8 read_id_cmd[] = { 0x44, 0x02, 0x00, 0x08, 0x00, /* Max transfer size is 8 */ 0x07, /* Read ID? */ }; -static const unsigned char calibrate_cmd[] = { +static const guint8 calibrate_cmd[] = { 0x44, 0x02, 0x00, 0x04, 0x00, 0x06, }; -int aesX660_dev_activate(struct fp_img_dev *dev); -void aesX660_dev_deactivate(struct fp_img_dev *dev); - -#endif diff --git a/meson.build b/meson.build index f4597110..d382ae87 100644 --- a/meson.build +++ b/meson.build @@ -51,7 +51,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610' ] +default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660' ] all_drivers = default_drivers + virtual_drivers From 441b1238a5866a43b5b4d1230d114048e8617319 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 8 Jul 2019 18:30:42 +0200 Subject: [PATCH 33/73] aes2501: Port aes2501 to new API --- libfprint/drivers/aes2501.c | 472 ++++++++++++++++-------------------- meson.build | 2 +- 2 files changed, 210 insertions(+), 264 deletions(-) diff --git a/libfprint/drivers/aes2501.c b/libfprint/drivers/aes2501.c index 91e02a39..50b34987 100644 --- a/libfprint/drivers/aes2501.c +++ b/libfprint/drivers/aes2501.c @@ -27,12 +27,12 @@ #include "aeslib.h" #include "aes2501.h" -static void start_capture(struct fp_img_dev *dev); -static void complete_deactivation(struct fp_img_dev *dev); +static void start_capture(FpImageDevice *dev); +static void complete_deactivation(FpImageDevice *dev); /* FIXME these need checking */ -#define EP_IN (1 | LIBUSB_ENDPOINT_IN) -#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT) +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) #define BULK_TIMEOUT 4000 @@ -63,13 +63,18 @@ static void complete_deactivation(struct fp_img_dev *dev); /****** GENERAL FUNCTIONS ******/ -struct aes2501_dev { - uint8_t read_regs_retry_count; +struct _FpiDeviceAes2501 { + FpImageDevice parent; + + guint8 read_regs_retry_count; GSList *strips; size_t strips_len; gboolean deactivating; int no_finger_cnt; }; +G_DECLARE_FINAL_TYPE(FpiDeviceAes2501, fpi_device_aes2501, FPI, DEVICE_AES2501, + FpImageDevice); +G_DEFINE_TYPE(FpiDeviceAes2501, fpi_device_aes2501, FP_TYPE_IMAGE_DEVICE); static struct fpi_frame_asmbl_ctx assembling_ctx = { .frame_width = FRAME_WIDTH, @@ -78,73 +83,47 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = { .get_pixel = aes_get_pixel, }; -typedef void (*aes2501_read_regs_cb)(struct fp_img_dev *dev, int status, - unsigned char *regs, void *user_data); +typedef void (*aes2501_read_regs_cb)(FpImageDevice *dev, GError *error, + unsigned char *regs, void *user_data); struct aes2501_read_regs { - struct fp_img_dev *dev; + FpImageDevice *dev; aes2501_read_regs_cb callback; struct aes_regwrite *regwrite; void *user_data; }; -static void read_regs_data_cb(struct libusb_transfer *transfer, - struct fp_dev *dev, - fpi_ssm *ssm, - void *user_data) +static void read_regs_data_cb(FpiUsbTransfer *transfer, FpDevice *dev, + gpointer user_data, GError *error) { struct aes2501_read_regs *rdata = user_data; - unsigned char *retdata = NULL; - int r; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - r = -EIO; - } else if (transfer->length != transfer->actual_length) { - r = -EPROTO; - } else { - r = 0; - retdata = transfer->buffer; - } - - rdata->callback(rdata->dev, r, retdata, rdata->user_data); + rdata->callback(rdata->dev, error, transfer->buffer, rdata->user_data); g_free(rdata); } -static void read_regs_rq_cb(struct fp_img_dev *dev, int result, void *user_data) +static void read_regs_rq_cb(FpImageDevice *dev, GError *error, void *user_data) { struct aes2501_read_regs *rdata = user_data; - fpi_usb_transfer *transfer; - unsigned char *data; - int r; + FpiUsbTransfer *transfer; g_free(rdata->regwrite); - if (result != 0) - goto err; - - data = g_malloc(READ_REGS_LEN); - transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev), - NULL, - EP_IN, - data, - READ_REGS_LEN, - read_regs_data_cb, - rdata, - BULK_TIMEOUT); - - r = fpi_usb_submit_transfer(transfer); - if (r < 0) { - result = -EIO; - goto err; + if (error) { + rdata->callback(dev, error, NULL, rdata->user_data); + g_free (rdata); + return; } - return; -err: - rdata->callback(dev, result, NULL, rdata->user_data); - g_free(rdata); + transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk(transfer, EP_IN, READ_REGS_LEN); + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + read_regs_data_cb, rdata); + fpi_usb_transfer_unref(transfer); } -static void read_regs(struct fp_img_dev *dev, aes2501_read_regs_cb callback, - void *user_data) +static void read_regs(FpImageDevice *dev, aes2501_read_regs_cb callback, + void *user_data) { /* FIXME: regwrite is dynamic because of asynchronity. is this really * required? */ @@ -164,16 +143,16 @@ static void read_regs(struct fp_img_dev *dev, aes2501_read_regs_cb callback, } /* Read the value of a specific register from a register dump */ -static int regval_from_dump(unsigned char *data, uint8_t target) +static int regval_from_dump(unsigned char *data, guint8 target) { if (*data != FIRST_AES2501_REG) { fp_err("not a register dump"); - return -EILSEQ; + return -1; } if (!(FIRST_AES2501_REG <= target && target <= LAST_AES2501_REG)) { fp_err("out of range"); - return -EINVAL; + return -1; } target -= FIRST_AES2501_REG; @@ -181,66 +160,56 @@ static int regval_from_dump(unsigned char *data, uint8_t target) return data[target + 1]; } -static void generic_write_regv_cb(struct fp_img_dev *dev, int result, - void *user_data) +static void generic_write_regv_cb(FpImageDevice *dev, GError *error, + void *user_data) { - fpi_ssm *ssm = user_data; - if (result == 0) + FpiSsm *ssm = user_data; + if (!error) fpi_ssm_next_state(ssm); else - fpi_ssm_mark_failed(ssm, result); + fpi_ssm_mark_failed(ssm, error); } /* check that read succeeded but ignore all data */ -static void generic_ignore_data_cb(struct libusb_transfer *transfer, - struct fp_dev *dev, - fpi_ssm *ssm, - void *user_data) +static void generic_ignore_data_cb(FpiUsbTransfer *transfer, FpDevice *dev, + gpointer user_data, GError *error) { - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - fpi_ssm_mark_failed(ssm, -EIO); - else if (transfer->length != transfer->actual_length) - fpi_ssm_mark_failed(ssm, -EPROTO); + FpiSsm *ssm = transfer->ssm; + if (error) + fpi_ssm_mark_failed(ssm, error); else fpi_ssm_next_state(ssm); } /* read the specified number of bytes from the IN endpoint but throw them * away, then increment the SSM */ -static void generic_read_ignore_data(fpi_ssm *ssm, struct fp_dev *dev, size_t bytes) +static void generic_read_ignore_data(FpiSsm *ssm, FpDevice *dev, + size_t bytes) { - fpi_usb_transfer *transfer; - unsigned char *data; - int r; + FpiUsbTransfer *transfer; - data = g_malloc(bytes); - transfer = fpi_usb_fill_bulk_transfer(dev, - ssm, - EP_IN, - data, - bytes, - generic_ignore_data_cb, - NULL, - BULK_TIMEOUT); - - r = fpi_usb_submit_transfer(transfer); - if (r < 0) - fpi_ssm_mark_failed(ssm, r); + transfer = fpi_usb_transfer_new(dev); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk(transfer, EP_IN, bytes); + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + generic_ignore_data_cb, NULL); + fpi_usb_transfer_unref(transfer); } /****** IMAGE PROCESSING ******/ -static int sum_histogram_values(unsigned char *data, uint8_t threshold) +static int sum_histogram_values(unsigned char *data, guint8 threshold) { int r = 0; int i; - uint16_t *histogram = (uint16_t *)(data + 1); + guint16 *histogram = (guint16 *)(data + 1); if (*data != 0xde) - return -EILSEQ; + return -1; if (threshold > 0x0f) - return -EINVAL; + return -1; /* FIXME endianness */ for (i = threshold; i < 16; i++) @@ -279,23 +248,18 @@ static const struct aes_regwrite finger_det_reqs[] = { { AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE }, }; -static void start_finger_detection(struct fp_img_dev *dev); +static void start_finger_detection(FpImageDevice *dev); -static void finger_det_data_cb(struct libusb_transfer *transfer, - struct fp_dev *_dev, - fpi_ssm *ssm, - void *user_data) +static void finger_det_data_cb(FpiUsbTransfer *transfer, FpDevice *_dev, + gpointer user_data, GError *error) { - struct fp_img_dev *dev = FP_IMG_DEV(_dev); + FpImageDevice *dev = FP_IMAGE_DEVICE(_dev); unsigned char *data = transfer->buffer; int i; int sum = 0; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fpi_imgdev_session_error(dev, -EIO); - return; - } else if (transfer->length != transfer->actual_length) { - fpi_imgdev_session_error(dev, -EPROTO); + if (error) { + fpi_image_device_session_error(dev, error); return; } @@ -304,7 +268,7 @@ static void finger_det_data_cb(struct libusb_transfer *transfer, sum += (data[i] & 0xf) + (data[i] >> 4); if (sum > 20) { /* finger present, start capturing */ - fpi_imgdev_report_finger_status(dev, TRUE); + fpi_image_device_report_finger_status(dev, TRUE); start_capture(dev); } else { /* no finger, poll for a new histogram */ @@ -312,39 +276,30 @@ static void finger_det_data_cb(struct libusb_transfer *transfer, } } -static void finger_det_reqs_cb(struct fp_img_dev *dev, int result, - void *user_data) +static void finger_det_reqs_cb(FpImageDevice *dev, GError *error, + void *user_data) { - fpi_usb_transfer *transfer; - unsigned char *data; - int r; + FpiUsbTransfer *transfer; - if (result) { - fpi_imgdev_session_error(dev, result); + if (error) { + fpi_image_device_session_error (dev, error); return; } - data = g_malloc(FINGER_DETECTION_LEN); - transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev), - NULL, - EP_IN, - data, - FINGER_DETECTION_LEN, - finger_det_data_cb, - NULL, - BULK_TIMEOUT); - - r = fpi_usb_submit_transfer(transfer); - if (r < 0) - fpi_imgdev_session_error(dev, r); + transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk(transfer, EP_IN, FINGER_DETECTION_LEN); + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + finger_det_data_cb, NULL); + fpi_usb_transfer_unref(transfer); } -static void start_finger_detection(struct fp_img_dev *dev) +static void start_finger_detection(FpImageDevice *dev) { - struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(dev); G_DEBUG_HERE(); - if (aesdev->deactivating) { + if (self->deactivating) { complete_deactivation(dev); return; } @@ -428,36 +383,34 @@ enum capture_states { CAPTURE_NUM_STATES, }; -static void capture_read_strip_cb(struct libusb_transfer *transfer, - struct fp_dev *_dev, - fpi_ssm *ssm, - void *user_data) +static void capture_read_strip_cb(FpiUsbTransfer *transfer, FpDevice *_dev, + gpointer user_data, GError *error) { + FpiSsm *ssm = transfer->ssm; unsigned char *stripdata; - struct fp_img_dev *dev = FP_IMG_DEV(_dev); - struct aes2501_dev *aesdev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = FP_IMAGE_DEVICE(_dev); + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(_dev); unsigned char *data = transfer->buffer; int sum; int threshold; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fpi_ssm_mark_failed(ssm, -EIO); - return; - } else if (transfer->length != transfer->actual_length) { - fpi_ssm_mark_failed(ssm, -EPROTO); + if (error) { + fpi_ssm_mark_failed(ssm, error); return; } threshold = regval_from_dump(data + 1 + 192*8 + 1 + 16*2 + 1 + 8, AES2501_REG_DATFMT); if (threshold < 0) { - fpi_ssm_mark_failed(ssm, threshold); + fpi_ssm_mark_failed(ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); return; } sum = sum_histogram_values(data + 1 + 192*8, threshold & 0x0f); if (sum < 0) { - fpi_ssm_mark_failed(ssm, sum); + fpi_ssm_mark_failed(ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); return; } fp_dbg("sum=%d", sum); @@ -477,21 +430,21 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer, * to ensure */ if (sum == 0) { - aesdev->no_finger_cnt++; - if (aesdev->no_finger_cnt == 3) { - struct fp_img *img; + self->no_finger_cnt++; + if (self->no_finger_cnt == 3) { + FpImage *img; - aesdev->strips = g_slist_reverse(aesdev->strips); + self->strips = g_slist_reverse(self->strips); fpi_do_movement_estimation(&assembling_ctx, - aesdev->strips, aesdev->strips_len); + self->strips, self->strips_len); img = fpi_assemble_frames(&assembling_ctx, - aesdev->strips, aesdev->strips_len); - img->flags |= FP_IMG_PARTIAL; - g_slist_free_full(aesdev->strips, g_free); - aesdev->strips = NULL; - aesdev->strips_len = 0; - fpi_imgdev_image_captured(dev, img); - fpi_imgdev_report_finger_status(dev, FALSE); + self->strips, + self->strips_len); + g_slist_free_full(self->strips, g_free); + self->strips = NULL; + self->strips_len = 0; + fpi_image_device_image_captured(dev, img); + fpi_image_device_report_finger_status(dev, FALSE); /* marking machine complete will re-trigger finger detection loop */ fpi_ssm_mark_completed(ssm); } else { @@ -505,19 +458,18 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer, stripe->delta_y = 0; stripdata = stripe->data; memcpy(stripdata, data + 1, 192*8); - aesdev->no_finger_cnt = 0; - aesdev->strips = g_slist_prepend(aesdev->strips, stripe); - aesdev->strips_len++; + self->no_finger_cnt = 0; + self->strips = g_slist_prepend(self->strips, stripe); + self->strips_len++; fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP); } } -static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capture_run_state(FpiSsm *ssm, FpDevice *device, void *user_data) { - struct fp_img_dev *dev = user_data; - struct aes2501_dev *aesdev = FP_INSTANCE_DATA(_dev); - int r; + FpImageDevice *dev = user_data; + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(device); switch (fpi_ssm_get_cur_state(ssm)) { case CAPTURE_WRITE_REQS_1: @@ -525,72 +477,71 @@ static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data generic_write_regv_cb, ssm); break; case CAPTURE_READ_DATA_1: - generic_read_ignore_data(ssm, _dev, READ_REGS_RESP_LEN); + generic_read_ignore_data(ssm, device, READ_REGS_RESP_LEN); break; case CAPTURE_WRITE_REQS_2: aes_write_regv(dev, capture_reqs_2, G_N_ELEMENTS(capture_reqs_2), generic_write_regv_cb, ssm); break; case CAPTURE_READ_DATA_2: - generic_read_ignore_data(ssm, _dev, READ_REGS_RESP_LEN); + generic_read_ignore_data(ssm, device, READ_REGS_RESP_LEN); break; case CAPTURE_REQUEST_STRIP: - if (aesdev->deactivating) + if (self->deactivating) fpi_ssm_mark_completed(ssm); else aes_write_regv(dev, strip_scan_reqs, G_N_ELEMENTS(strip_scan_reqs), generic_write_regv_cb, ssm); break; - case CAPTURE_READ_STRIP: ; - fpi_usb_transfer *transfer; - unsigned char *data; + case CAPTURE_READ_STRIP: { + FpiUsbTransfer *transfer; - data = g_malloc(STRIP_CAPTURE_LEN); - transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev), - ssm, - EP_IN, - data, - STRIP_CAPTURE_LEN, - capture_read_strip_cb, - NULL, - BULK_TIMEOUT); - - r = fpi_usb_submit_transfer(transfer); - if (r < 0) - fpi_ssm_mark_failed(ssm, r); - break; + transfer = fpi_usb_transfer_new(device); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk(transfer, EP_IN, STRIP_CAPTURE_LEN); + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + capture_read_strip_cb, NULL); + fpi_usb_transfer_unref(transfer); + break; + } }; } -static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capture_sm_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - struct fp_img_dev *dev = user_data; - struct aes2501_dev *aesdev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(_dev); G_DEBUG_HERE(); - if (aesdev->deactivating) + + if (self->deactivating) { complete_deactivation(dev); - else if (fpi_ssm_get_error(ssm)) - fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm)); - else + g_clear_pointer (&error, g_error_free); + } else if (error) { + fpi_image_device_session_error(dev, error); + } else { start_finger_detection(dev); + } fpi_ssm_free(ssm); } -static void start_capture(struct fp_img_dev *dev) +static void start_capture(FpImageDevice *dev) { - struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_ssm *ssm; + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(dev); + FpiSsm *ssm; - if (aesdev->deactivating) { + if (self->deactivating) { complete_deactivation(dev); return; } - aesdev->no_finger_cnt = 0; + self->no_finger_cnt = 0; /* Reset gain */ strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE; - ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev); + ssm = fpi_ssm_new(FP_DEVICE(dev), capture_run_state, + CAPTURE_NUM_STATES, dev); G_DEBUG_HERE(); fpi_ssm_start(ssm, capture_sm_complete); } @@ -700,36 +651,36 @@ enum activate_states { ACTIVATE_NUM_STATES, }; -void activate_read_regs_cb(struct fp_img_dev *dev, int status, - unsigned char *regs, void *user_data) +void activate_read_regs_cb(FpImageDevice *dev, GError *error, + unsigned char *regs, void *user_data) { - fpi_ssm *ssm = user_data; - struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiSsm *ssm = user_data; + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(dev); - if (status != 0) { - fpi_ssm_mark_failed(ssm, status); + if (error) { + fpi_ssm_mark_failed(ssm, error); } else { fp_dbg("reg 0xaf = %x", regs[0x5f]); - if (regs[0x5f] != 0x6b || ++aesdev->read_regs_retry_count == 13) + if (regs[0x5f] != 0x6b || ++self->read_regs_retry_count == 13) fpi_ssm_jump_to_state(ssm, WRITE_INIT_4); else fpi_ssm_next_state(ssm); } } -static void activate_init3_cb(struct fp_img_dev *dev, int result, - void *user_data) +static void activate_init3_cb(FpImageDevice *dev, GError *error, + void *user_data) { - fpi_ssm *ssm = user_data; - if (result == 0) + FpiSsm *ssm = user_data; + if (!error) fpi_ssm_jump_to_state(ssm, READ_REGS); else - fpi_ssm_mark_failed(ssm, result); + fpi_ssm_mark_failed(ssm, error); } -static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct fp_img_dev *dev = user_data; + FpImageDevice *dev = user_data; /* This state machine isn't as linear as it may appear. After doing init1 * and init2 register configuration writes, we have to poll a register @@ -781,97 +732,92 @@ static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_dat } } -static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_sm_complete(FpiSsm *ssm, FpDevice *dev, + void *user_data, GError *error) { - struct fp_img_dev *dev = user_data; - fp_dbg("status %d", fpi_ssm_get_error(ssm)); - fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm)); + fpi_image_device_activate_complete(FP_IMAGE_DEVICE (dev), error); - if (!fpi_ssm_get_error(ssm)) - start_finger_detection(dev); + if (!error) + start_finger_detection(FP_IMAGE_DEVICE (dev)); fpi_ssm_free(ssm); } -static int dev_activate(struct fp_img_dev *dev) +static void dev_activate(FpImageDevice *dev) { - struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); - aesdev->read_regs_retry_count = 0; + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(dev); + FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); + self->read_regs_retry_count = 0; fpi_ssm_start(ssm, activate_sm_complete); - return 0; } -static void dev_deactivate(struct fp_img_dev *dev) +static void dev_deactivate(FpImageDevice *dev) { - struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(dev); /* FIXME: audit cancellation points, probably need more, specifically * in error handling paths? */ - aesdev->deactivating = TRUE; + self->deactivating = TRUE; } -static void complete_deactivation(struct fp_img_dev *dev) +static void complete_deactivation(FpImageDevice *dev) { - struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(dev); G_DEBUG_HERE(); /* FIXME: if we're in the middle of a scan, we should cancel the scan. * maybe we can do this with a master reset, unconditionally? */ - aesdev->deactivating = FALSE; - g_slist_free(aesdev->strips); - aesdev->strips = NULL; - aesdev->strips_len = 0; - fpi_imgdev_deactivate_complete(dev); + self->deactivating = FALSE; + g_slist_free(self->strips); + self->strips = NULL; + self->strips_len = 0; + fpi_image_device_deactivate_complete(dev, NULL); } -static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) +static void dev_init(FpImageDevice *dev) { + GError *error = NULL; /* FIXME check endpoints */ - int r; - struct aes2501_dev *aesdev; - r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - if (r < 0) { - fp_err("could not claim interface 0: %s", libusb_error_name(r)); - return r; - } - - aesdev = g_malloc0(sizeof(struct aes2501_dev)); - fp_dev_set_instance_data(FP_DEV(dev), aesdev); - fpi_imgdev_open_complete(dev, 0); - return 0; + g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error); + fpi_image_device_open_complete(dev, error); } -static void dev_deinit(struct fp_img_dev *dev) +static void dev_deinit(FpImageDevice *dev) { - struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); - g_free(aesdev); - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - fpi_imgdev_close_complete(dev); + GError *error = NULL; + + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), + 0, 0, &error); + fpi_image_device_close_complete(dev, error); } -static const struct usb_id id_table[] = { - { .vendor = 0x08ff, .product = 0x2500 }, /* AES2500 */ - { .vendor = 0x08ff, .product = 0x2580 }, /* AES2501 */ - { 0, 0, 0, }, +static const FpIdEntry id_table [ ] = { + { .vid = 0x08ff, .pid = 0x2500, + }, /* AES2500 */ + { .vid = 0x08ff, .pid = 0x2580, + }, /* AES2501 */ + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -struct fp_img_driver aes2501_driver = { - .driver = { - .id = AES2501_ID, - .name = FP_COMPONENT, - .full_name = "AuthenTec AES2501", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_SWIPE, - }, - .flags = 0, - .img_height = -1, - .img_width = IMAGE_WIDTH, +static void fpi_device_aes2501_init(FpiDeviceAes2501 *self) { +} +static void fpi_device_aes2501_class_init(FpiDeviceAes2501Class *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); - .open = dev_init, - .close = dev_deinit, - .activate = dev_activate, - .deactivate = dev_deactivate, -}; + dev_class->id = "aes2501"; + dev_class->full_name = "AuthenTec AES2501"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; + + img_class->img_width = IMAGE_WIDTH; + img_class->img_height = -1; +} diff --git a/meson.build b/meson.build index d382ae87..1427f4f8 100644 --- a/meson.build +++ b/meson.build @@ -51,7 +51,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660' ] +default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501' ] all_drivers = default_drivers + virtual_drivers From 61e49c2659f70fb795dcbcf946bab8c206620e25 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 8 Jul 2019 21:32:22 +0200 Subject: [PATCH 34/73] aes2550: Port aes2550 driver to new API --- libfprint/drivers/aes2550.c | 526 ++++++++++++++++-------------------- meson.build | 2 +- 2 files changed, 241 insertions(+), 287 deletions(-) diff --git a/libfprint/drivers/aes2550.c b/libfprint/drivers/aes2550.c index 72a86132..62797549 100644 --- a/libfprint/drivers/aes2550.c +++ b/libfprint/drivers/aes2550.c @@ -27,11 +27,11 @@ #include "aes2550.h" #include "aeslib.h" -static void start_capture(struct fp_img_dev *dev); -static void complete_deactivation(struct fp_img_dev *dev); +static void start_capture(FpImageDevice *dev); +static void complete_deactivation(FpImageDevice *dev); -#define EP_IN (1 | LIBUSB_ENDPOINT_IN) -#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT) +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) #define BULK_TIMEOUT 4000 /* @@ -51,12 +51,17 @@ static void complete_deactivation(struct fp_img_dev *dev); #define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT) #define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2)) -struct aes2550_dev { +struct _FpiDeviceAes2550 { + FpImageDevice parent; + GSList *strips; size_t strips_len; gboolean deactivating; int heartbeat_cnt; }; +G_DECLARE_FINAL_TYPE(FpiDeviceAes2550, fpi_device_aes2550, FPI, DEVICE_AES2550, + FpImageDevice); +G_DEFINE_TYPE(FpiDeviceAes2550, fpi_device_aes2550, FP_TYPE_IMAGE_DEVICE); static struct fpi_frame_asmbl_ctx assembling_ctx = { .frame_width = FRAME_WIDTH, @@ -78,89 +83,70 @@ static unsigned char finger_det_reqs[] = { AES2550_CMD_RUN_FD, }; -static void start_finger_detection(struct fp_img_dev *dev); +static void start_finger_detection(FpImageDevice *dev); -static void finger_det_data_cb(struct libusb_transfer *transfer) +static void finger_det_data_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - struct fp_img_dev *dev = transfer->user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE(device); unsigned char *data = transfer->buffer; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fp_dbg("data transfer status %d\n", transfer->status); - fpi_imgdev_session_error(dev, -EIO); - goto out; + if (error) { + fpi_image_device_session_error(FP_IMAGE_DEVICE(device), error); + return; } fp_dbg("transfer completed, len: %.4x, data: %.2x %.2x", - transfer->actual_length, (int)data[0], (int)data[1]); + (gint)transfer->actual_length, (int)data[0], (int)data[1]); /* Check if we got 2 bytes, reg address 0x83 and its value */ if ((transfer->actual_length >= 2) && (data[0] == 0x83) && (data[1] & AES2550_REG83_FINGER_PRESENT)) { /* finger present, start capturing */ - fpi_imgdev_report_finger_status(dev, TRUE); + fpi_image_device_report_finger_status(dev, TRUE); start_capture(dev); } else { /* no finger, poll for a new histogram */ start_finger_detection(dev); } -out: - g_free(data); - libusb_free_transfer(transfer); } -static void finger_det_reqs_cb(struct libusb_transfer *t) +static void finger_det_reqs_cb(FpiUsbTransfer *t, FpDevice *device, + gpointer user_data, GError *error) { - struct libusb_transfer *transfer; - unsigned char *data; - int r; - struct fp_img_dev *dev = t->user_data; + FpiUsbTransfer *transfer; + FpImageDevice *dev = user_data; - if (t->status != LIBUSB_TRANSFER_COMPLETED) { - fp_dbg("req transfer status %d\n", t->status); - fpi_imgdev_session_error(dev, -EIO); - goto exit_free_transfer; - } else if (t->length != t->actual_length) { - fp_dbg("expected %d, got %d bytes", t->length, t->actual_length); - fpi_imgdev_session_error(dev, -EPROTO); - goto exit_free_transfer; + if (error) { + fpi_image_device_session_error(dev, error); + return; } - transfer = fpi_usb_alloc(); + transfer = fpi_usb_transfer_new (device); /* 2 bytes of result */ - data = g_malloc(AES2550_EP_IN_BUF_SIZE); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE, - finger_det_data_cb, dev, BULK_TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_imgdev_session_error(dev, r); - } -exit_free_transfer: - libusb_free_transfer(t); + fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE); + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + finger_det_data_cb, NULL); + fpi_usb_transfer_unref(transfer); } -static void start_finger_detection(struct fp_img_dev *dev) +static void start_finger_detection(FpImageDevice *dev) { - int r; - struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); - struct libusb_transfer *transfer; + FpiDeviceAes2550 *self = FPI_DEVICE_AES2550(dev); + FpiUsbTransfer *transfer; G_DEBUG_HERE(); - if (aesdev->deactivating) { + if (self->deactivating) { complete_deactivation(dev); return; } - transfer = fpi_usb_alloc(); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, finger_det_reqs, - sizeof(finger_det_reqs), finger_det_reqs_cb, dev, BULK_TIMEOUT); - r = libusb_submit_transfer(transfer); - if (r < 0) { - libusb_free_transfer(transfer); - fpi_imgdev_session_error(dev, r); - } + transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk_full(transfer, EP_OUT, finger_det_reqs, + sizeof(finger_det_reqs), NULL); + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + finger_det_reqs_cb, NULL); + fpi_usb_transfer_unref(transfer); } /****** CAPTURE ******/ @@ -191,207 +177,201 @@ enum capture_states { }; /* Returns number of processed bytes */ -static int process_strip_data(fpi_ssm *ssm, struct fp_img_dev *dev, unsigned char *data) +static gboolean process_strip_data(FpiSsm *ssm, FpImageDevice *dev, + unsigned char *data) { unsigned char *stripdata; - struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAes2550 *self = FPI_DEVICE_AES2550(dev); struct fpi_frame *stripe; int len; if (data[0] != AES2550_EDATA_MAGIC) { fp_dbg("Bogus magic: %.2x\n", (int)(data[0])); - return -EPROTO; + return FALSE; } len = data[1] * 256 + data[2]; if (len != (AES2550_STRIP_SIZE - 3)) { fp_dbg("Bogus frame len: %.4x\n", len); } - stripe = g_malloc(FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof(struct fpi_frame)); /* 4 bits per pixel */ + stripe = g_malloc0(FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof(struct fpi_frame)); /* 4 bits per pixel */ stripe->delta_x = (int8_t)data[6]; stripe->delta_y = -(int8_t)data[7]; stripdata = stripe->data; memcpy(stripdata, data + 33, FRAME_WIDTH * FRAME_HEIGHT / 2); - aesdev->strips = g_slist_prepend(aesdev->strips, stripe); - aesdev->strips_len++; + self->strips = g_slist_prepend(self->strips, stripe); + self->strips_len++; fp_dbg("deltas: %dx%d", stripe->delta_x, stripe->delta_y); - return 0; + return TRUE; } -static void capture_reqs_cb(struct libusb_transfer *transfer) +static void capture_reqs_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - - if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && - (transfer->length == transfer->actual_length)) { - fpi_ssm_next_state(ssm); + if (!error) { + fpi_ssm_next_state(transfer->ssm); } else { - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, error); } - libusb_free_transfer(transfer); } -static void capture_set_idle_reqs_cb(struct libusb_transfer *transfer) +static void capture_set_idle_reqs_cb(FpiUsbTransfer *transfer, + FpDevice *device, gpointer user_data, + GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpImageDevice *dev = FP_IMAGE_DEVICE(device); + FpiDeviceAes2550 *self = FPI_DEVICE_AES2550(dev); - if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && - (transfer->length == transfer->actual_length) && - aesdev->strips_len) { - struct fp_img *img; + if (!error && self->strips_len) { + FpImage *img; - aesdev->strips = g_slist_reverse(aesdev->strips); + self->strips = g_slist_reverse(self->strips); img = fpi_assemble_frames(&assembling_ctx, - aesdev->strips, aesdev->strips_len); - img->flags |= FP_IMG_PARTIAL; - g_slist_free_full(aesdev->strips, g_free); - aesdev->strips = NULL; - aesdev->strips_len = 0; - fpi_imgdev_image_captured(dev, img); - fpi_imgdev_report_finger_status(dev, FALSE); + self->strips, self->strips_len); + g_slist_free_full(self->strips, g_free); + self->strips = NULL; + self->strips_len = 0; + fpi_image_device_image_captured(dev, img); + fpi_image_device_report_finger_status(dev, FALSE); /* marking machine complete will re-trigger finger detection loop */ - fpi_ssm_mark_completed(ssm); + fpi_ssm_mark_completed(transfer->ssm); } else { - fpi_ssm_mark_failed(ssm, -EIO); + if (error) + fpi_ssm_mark_failed(transfer->ssm, error); + else + fpi_ssm_mark_failed(transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } - libusb_free_transfer(transfer); } -static void capture_read_data_cb(struct libusb_transfer *transfer) +static void capture_read_data_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpImageDevice *dev = FP_IMAGE_DEVICE(device); + FpiDeviceAes2550 *self = FPI_DEVICE_AES2550(dev); unsigned char *data = transfer->buffer; - int r; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fp_dbg("request is not completed, %d", transfer->status); - fpi_ssm_mark_failed(ssm, -EIO); - goto out; + if (error) { + fpi_ssm_mark_failed(transfer->ssm, error); + return; } - fp_dbg("request completed, len: %.4x", transfer->actual_length); + fp_dbg("request completed, len: %.4x", (gint)transfer->actual_length); if (transfer->actual_length >= 2) fp_dbg("data: %.2x %.2x", (int)data[0], (int)data[1]); switch (transfer->actual_length) { case AES2550_STRIP_SIZE: - r = process_strip_data(ssm, dev, data); - if (r < 0) { - fp_dbg("Processing strip data failed: %d", r); - fpi_ssm_mark_failed(ssm, -EPROTO); - goto out; + if (!process_strip_data(transfer->ssm, dev, data)) { + fp_dbg("Processing strip data failed"); + fpi_ssm_mark_failed(transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + return; } - aesdev->heartbeat_cnt = 0; - fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA); + self->heartbeat_cnt = 0; + fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_READ_DATA); break; case AES2550_HEARTBEAT_SIZE: if (data[0] == AES2550_HEARTBEAT_MAGIC) { /* No data for a long time => finger was removed or there's no movement */ - aesdev->heartbeat_cnt++; - if (aesdev->heartbeat_cnt == 3) { + self->heartbeat_cnt++; + if (self->heartbeat_cnt == 3) { /* Got 3 heartbeat message, that's enough to consider that finger was removed, * assemble image and submit it to the library */ fp_dbg("Got 3 heartbeats => finger removed"); - fpi_ssm_next_state(ssm); + fpi_ssm_next_state(transfer->ssm); } else { - fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA); + fpi_ssm_jump_to_state(transfer->ssm, + CAPTURE_READ_DATA); } } break; default: - fp_dbg("Short frame %d, skip", transfer->actual_length); - fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA); + fp_dbg("Short frame %d, skip", + (gint)transfer->actual_length); + fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_READ_DATA); break; } -out: - g_free(transfer->buffer); - libusb_free_transfer(transfer); } -static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capture_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *dev = user_data; - int r; - switch (fpi_ssm_get_cur_state(ssm)) { case CAPTURE_WRITE_REQS: { - struct libusb_transfer *transfer = fpi_usb_alloc(); + FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, capture_reqs, - sizeof(capture_reqs), capture_reqs_cb, ssm, BULK_TIMEOUT); - r = libusb_submit_transfer(transfer); - if (r < 0) { - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, -ENOMEM); - } + fpi_usb_transfer_fill_bulk_full(transfer, EP_OUT, capture_reqs, + sizeof(capture_reqs), NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + capture_reqs_cb, NULL); + fpi_usb_transfer_unref(transfer); } break; case CAPTURE_READ_DATA: { - struct libusb_transfer *transfer = fpi_usb_alloc(); - unsigned char *data; + FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); - data = g_malloc(AES2550_EP_IN_BUF_SIZE); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE, - capture_read_data_cb, ssm, BULK_TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE); + transfer->ssm = ssm; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + capture_read_data_cb, NULL); + fpi_usb_transfer_unref(transfer); } break; case CAPTURE_SET_IDLE: { - struct libusb_transfer *transfer = fpi_usb_alloc(); + FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, capture_set_idle_reqs, - sizeof(capture_set_idle_reqs), capture_set_idle_reqs_cb, ssm, BULK_TIMEOUT); - r = libusb_submit_transfer(transfer); - if (r < 0) { - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, -ENOMEM); - } + fpi_usb_transfer_fill_bulk_full(transfer, EP_OUT, + capture_set_idle_reqs, + sizeof(capture_set_idle_reqs), + NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + capture_set_idle_reqs_cb, NULL); + fpi_usb_transfer_unref(transfer); } break; }; } -static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capture_sm_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - struct fp_img_dev *dev = user_data; - struct aes2550_dev *aesdev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpiDeviceAes2550 *self = FPI_DEVICE_AES2550(_dev); fp_dbg("Capture completed"); - if (aesdev->deactivating) + + if (self->deactivating) { complete_deactivation(dev); - else if (fpi_ssm_get_error(ssm)) - fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm)); - else + g_clear_pointer (&error, g_error_free); + } else if (error) { + fpi_image_device_session_error(dev, error); + } else { start_finger_detection(dev); + } fpi_ssm_free(ssm); } -static void start_capture(struct fp_img_dev *dev) +static void start_capture(FpImageDevice *dev) { - struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_ssm *ssm; + FpiDeviceAes2550 *self = FPI_DEVICE_AES2550(dev); + FpiSsm *ssm; - if (aesdev->deactivating) { + if (self->deactivating) { complete_deactivation(dev); return; } - aesdev->heartbeat_cnt = 0; - ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev); + self->heartbeat_cnt = 0; + ssm = fpi_ssm_new(FP_DEVICE(dev), capture_run_state, + CAPTURE_NUM_STATES, dev); G_DEBUG_HERE(); fpi_ssm_start(ssm, capture_sm_complete); } @@ -420,201 +400,175 @@ enum activate_states { ACTIVATE_NUM_STATES, }; -static void init_reqs_cb(struct libusb_transfer *transfer) +static void init_reqs_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - - if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && - (transfer->length == transfer->actual_length)) { - fpi_ssm_next_state(ssm); + if (!error) { + fpi_ssm_next_state(transfer->ssm); } else { - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, error); } - libusb_free_transfer(transfer); } -static void init_read_data_cb(struct libusb_transfer *transfer) +static void init_read_data_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - - if (transfer->status == LIBUSB_TRANSFER_COMPLETED) { - fpi_ssm_next_state(ssm); + if (!error) { + fpi_ssm_next_state(transfer->ssm); } else { - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, error); } - g_free(transfer->buffer); - libusb_free_transfer(transfer); } /* TODO: use calibration table, datasheet is rather terse on that * need more info for implementation */ -static void calibrate_read_data_cb(struct libusb_transfer *transfer) +static void calibrate_read_data_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - - if (transfer->status == LIBUSB_TRANSFER_COMPLETED) { - fpi_ssm_next_state(ssm); + if (!error) { + fpi_ssm_next_state(transfer->ssm); } else { - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, error); } - g_free(transfer->buffer); - libusb_free_transfer(transfer); } -static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *dev = user_data; - int r; - switch (fpi_ssm_get_cur_state(ssm)) { case WRITE_INIT: { - struct libusb_transfer *transfer = fpi_usb_alloc(); + FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, init_reqs, - sizeof(init_reqs), init_reqs_cb, ssm, BULK_TIMEOUT); - r = libusb_submit_transfer(transfer); - if (r < 0) { - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, -ENOMEM); - } + fpi_usb_transfer_fill_bulk_full(transfer, EP_OUT, init_reqs, + sizeof(init_reqs), NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + init_reqs_cb, NULL); + fpi_usb_transfer_unref(transfer); } break; case READ_DATA: { - struct libusb_transfer *transfer = fpi_usb_alloc(); - unsigned char *data; + FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); - data = g_malloc(AES2550_EP_IN_BUF_SIZE); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE, - init_read_data_cb, ssm, BULK_TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + fpi_usb_transfer_fill_bulk(transfer, EP_IN, AES2550_EP_IN_BUF_SIZE); + transfer->ssm = ssm; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + init_read_data_cb, NULL); + fpi_usb_transfer_unref(transfer); } break; case CALIBRATE: { - struct libusb_transfer *transfer = fpi_usb_alloc(); + FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, calibrate_reqs, - sizeof(calibrate_reqs), init_reqs_cb, ssm, BULK_TIMEOUT); - r = libusb_submit_transfer(transfer); - if (r < 0) { - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, -ENOMEM); - } + fpi_usb_transfer_fill_bulk_full(transfer, EP_OUT, + calibrate_reqs, + sizeof(calibrate_reqs), NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + init_reqs_cb, NULL); + fpi_usb_transfer_unref(transfer); } break; case READ_CALIB_TABLE: { - struct libusb_transfer *transfer = fpi_usb_alloc(); - unsigned char *data; + FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); - data = g_malloc(AES2550_EP_IN_BUF_SIZE); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE, - calibrate_read_data_cb, ssm, BULK_TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + fpi_usb_transfer_fill_bulk(transfer, EP_IN, AES2550_EP_IN_BUF_SIZE); + transfer->ssm = ssm; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + calibrate_read_data_cb, NULL); + fpi_usb_transfer_unref(transfer); } break; } } -static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_sm_complete(FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - struct fp_img_dev *dev = user_data; - fp_dbg("status %d", fpi_ssm_get_error(ssm)); - fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm)); + FpImageDevice *dev = user_data; - if (!fpi_ssm_get_error(ssm)) + fpi_image_device_activate_complete(dev, error); + + if (!error) start_finger_detection(dev); fpi_ssm_free(ssm); } -static int dev_activate(struct fp_img_dev *dev) +static void dev_activate(FpImageDevice *dev) { - fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); + FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); fpi_ssm_start(ssm, activate_sm_complete); - return 0; } -static void dev_deactivate(struct fp_img_dev *dev) +static void dev_deactivate(FpImageDevice *dev) { - struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAes2550 *self = FPI_DEVICE_AES2550(dev); - aesdev->deactivating = TRUE; + self->deactivating = TRUE; } -static void complete_deactivation(struct fp_img_dev *dev) +static void complete_deactivation(FpImageDevice *dev) { - struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceAes2550 *self = FPI_DEVICE_AES2550(dev); G_DEBUG_HERE(); - aesdev->deactivating = FALSE; - g_slist_free(aesdev->strips); - aesdev->strips = NULL; - aesdev->strips_len = 0; - fpi_imgdev_deactivate_complete(dev); + self->deactivating = FALSE; + g_slist_free(self->strips); + self->strips = NULL; + self->strips_len = 0; + fpi_image_device_deactivate_complete(dev, NULL); } -static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) +static void dev_init(FpImageDevice *dev) { + GError *error = NULL; /* TODO check that device has endpoints we're using */ - int r; - struct aes2550_dev *aes2550_dev; - r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - if (r < 0) { - fp_err("could not claim interface 0: %s", libusb_error_name(r)); - return r; - } + g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error); - aes2550_dev = g_malloc0(sizeof(struct aes2550_dev)); - fp_dev_set_instance_data(FP_DEV(dev), aes2550_dev); - fpi_imgdev_open_complete(dev, 0); - return 0; + fpi_image_device_open_complete(dev, error); } -static void dev_deinit(struct fp_img_dev *dev) +static void dev_deinit(FpImageDevice *dev) { - struct aes2550_dev *aesdev; - aesdev = FP_INSTANCE_DATA(FP_DEV(dev)); - g_free(aesdev); - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - fpi_imgdev_close_complete(dev); + GError *error = NULL; + + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), + 0, 0, &error); + fpi_image_device_close_complete(dev, error); } -static const struct usb_id id_table[] = { - { .vendor = 0x08ff, .product = 0x2550 }, /* AES2550 */ - { .vendor = 0x08ff, .product = 0x2810 }, /* AES2810 */ - { 0, 0, 0, }, +static const FpIdEntry id_table [ ] = { + { .vid = 0x08ff, .pid = 0x2550, + }, /* AES2550 */ + { .vid = 0x08ff, .pid = 0x2810, + }, /* AES2810 */ + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -struct fp_img_driver aes2550_driver = { - .driver = { - .id = AES2550_ID, - .name = FP_COMPONENT, - .full_name = "AuthenTec AES2550/AES2810", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_SWIPE, - }, - .flags = 0, - .img_height = -1, - .img_width = FRAME_WIDTH + FRAME_WIDTH / 2, +static void fpi_device_aes2550_init(FpiDeviceAes2550 *self) { +} +static void fpi_device_aes2550_class_init(FpiDeviceAes2550Class *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); - .open = dev_init, - .close = dev_deinit, - .activate = dev_activate, - .deactivate = dev_deactivate, -}; + dev_class->id = "aes2550"; + dev_class->full_name = "AuthenTec AES2550/AES2810"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; + + img_class->img_width = FRAME_WIDTH + FRAME_WIDTH / 2; + img_class->img_height = -1; +} diff --git a/meson.build b/meson.build index 1427f4f8..d67ef2d6 100644 --- a/meson.build +++ b/meson.build @@ -51,7 +51,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501' ] +default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550' ] all_drivers = default_drivers + virtual_drivers From fd64c46c74e983529a23b9efaeb9f5bbeb81f444 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 8 Jul 2019 23:49:23 +0200 Subject: [PATCH 35/73] vfs101: Port vfs101 driver to new API This driver has a rather odd state machine and also used to mess iwth the internal state of the image device. This code has been removed, but is untested unfortunately due to a lack of hardware. Most likely, this driver is not quite functional currently. --- libfprint/drivers/vfs101.c | 820 ++++++++++++++----------------------- meson.build | 2 +- 2 files changed, 313 insertions(+), 509 deletions(-) diff --git a/libfprint/drivers/vfs101.c b/libfprint/drivers/vfs101.c index 60f0a819..690ec2d5 100644 --- a/libfprint/drivers/vfs101.c +++ b/libfprint/drivers/vfs101.c @@ -22,8 +22,8 @@ #include "drivers_api.h" /* Input-Output usb endpoint */ -#define EP_IN(n) (n | LIBUSB_ENDPOINT_IN) -#define EP_OUT(n) (n | LIBUSB_ENDPOINT_OUT) +#define EP_IN(n) (n | FPI_USB_ENDPOINT_IN) +#define EP_OUT(n) (n | FPI_USB_ENDPOINT_OUT) /* Usb bulk timeout */ #define BULK_TIMEOUT 100 @@ -85,19 +85,18 @@ #define VFS_VAL_IMG_EXPOSURE 0x21c0 /* Structure for Validity device */ -struct vfs101_dev -{ +struct _FpDeviceVfs101 { + FpImageDevice parent; + /* Action state */ - int active; + gboolean active; + gboolean deactivate; /* Sequential number */ unsigned int seqnum; - /* Usb transfer */ - struct libusb_transfer *transfer; - /* Buffer for input/output */ - unsigned char buffer[VFS_BUFFER_SIZE]; + unsigned char *buffer; /* Length of data to send or received */ unsigned int length; @@ -108,9 +107,6 @@ struct vfs101_dev /* Loop counter */ int counter; - /* Number of enroll stage */ - int enroll_stage; - /* Image contrast */ int contrast; @@ -126,6 +122,9 @@ struct vfs101_dev /* Image height */ int height; }; +G_DECLARE_FINAL_TYPE(FpDeviceVfs101, fpi_device_vfs101, FPI, DEVICE_VFS101, + FpImageDevice); +G_DEFINE_TYPE(FpDeviceVfs101, fpi_device_vfs101, FP_TYPE_IMAGE_DEVICE); /* Return byte at specified position */ static inline unsigned char byte(int position, int value) @@ -140,7 +139,7 @@ static inline unsigned short get_seqnum(int h, int l) } /* Check sequential number */ -static inline int check_seqnum(struct vfs101_dev *vdev) +static inline int check_seqnum(FpDeviceVfs101 *vdev) { if ((byte(0, vdev->seqnum) == vdev->buffer[0]) && (byte(1, vdev->seqnum) == vdev->buffer[1])) @@ -158,35 +157,6 @@ enum RESULT_COUNT, }; -/* Enroll result codes */ -static int result_codes[2][RESULT_COUNT] = -{ - { - FP_ENROLL_RETRY, - FP_ENROLL_RETRY_TOO_SHORT, - FP_ENROLL_RETRY_REMOVE_FINGER, - }, - { - FP_VERIFY_RETRY, - FP_VERIFY_RETRY_TOO_SHORT, - FP_VERIFY_RETRY_REMOVE_FINGER, - }, -}; - -/* Return result code based on current action */ -static int result_code(struct fp_img_dev *dev, int result) -{ - /* Check result value */ - if (result < 0 || result >= RESULT_COUNT) - return result; - - /* Return result code */ - if (fpi_imgdev_get_action(dev) == IMG_ACTION_ENROLL) - return result_codes[0][result]; - else - return result_codes[1][result]; -}; - /* Dump buffer for debug */ #define dump_buffer(buf) \ fp_dbg("%02x %02x %02x %02x %02x %02x %02x %02x", \ @@ -194,268 +164,209 @@ static int result_code(struct fp_img_dev *dev, int result) ) /* Callback of asynchronous send */ -static void async_send_cb(struct libusb_transfer *transfer) +static void async_send_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); - - /* Cleanup transfer */ - vdev->transfer = NULL; + FpImageDevice *dev = FP_IMAGE_DEVICE(device); + FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); /* Skip error check if ignore_error is set */ - if (!vdev->ignore_error) - { - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - { - /* Transfer not completed, return IO error */ - fp_err("transfer not completed, status = %d", transfer->status); - fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); - goto out; - } - - if (transfer->length != transfer->actual_length) - { - /* Data sended mismatch with expected, return protocol error */ - fp_err("length mismatch, got %d, expected %d", - transfer->actual_length, transfer->length); - fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); - goto out; + if (error) { + if (!self->ignore_error) { + fpi_ssm_mark_failed(transfer->ssm, error); + return; + } else { + g_error_free (error); + fp_dbg ("Ignoring send error: %s", error->message); } } - else - /* Reset ignore_error flag */ - vdev->ignore_error = FALSE; + /* Reset ignore_error flag */ + self->ignore_error = FALSE; /* Dump buffer for debug */ - dump_buffer(vdev->buffer); + dump_buffer(self->buffer); - fpi_ssm_next_state(ssm); - -out: - libusb_free_transfer(transfer); + fpi_ssm_next_state(transfer->ssm); } /* Submit asynchronous send */ static void -async_send(fpi_ssm *ssm, - struct fp_img_dev *dev) +async_send(FpiSsm *ssm, + FpImageDevice *dev) { - struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); - int r; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); + FpiUsbTransfer *transfer; - /* Allocation of transfer */ - vdev->transfer = fpi_usb_alloc(); + transfer = fpi_usb_transfer_new(FP_DEVICE (dev)); /* Put sequential number into the buffer */ - vdev->seqnum++; - vdev->buffer[0] = byte(0, vdev->seqnum); - vdev->buffer[1] = byte(1, vdev->seqnum); + self->seqnum++; + self->buffer[0] = byte(0, self->seqnum); + self->buffer[1] = byte(1, self->seqnum); /* Prepare bulk transfer */ - libusb_fill_bulk_transfer(vdev->transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT(1), vdev->buffer, vdev->length, async_send_cb, ssm, BULK_TIMEOUT); - - /* Submit transfer */ - r = libusb_submit_transfer(vdev->transfer); - if (r != 0) - { - /* Submission of transfer failed, return IO error */ - libusb_free_transfer(vdev->transfer); - fp_err("submit of usb transfer failed"); - fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); - return; - } + fpi_usb_transfer_fill_bulk_full(transfer, EP_OUT(1), + self->buffer, self->length, NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + async_send_cb, NULL); + fpi_usb_transfer_unref(transfer); } /* Callback of asynchronous recv */ -static void async_recv_cb(struct libusb_transfer *transfer) +static void async_recv_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); - - /* Cleanup transfer */ - vdev->transfer = NULL; + FpImageDevice *dev = FP_IMAGE_DEVICE(device); + FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); /* Skip error check if ignore_error is set */ - if (!vdev->ignore_error) + if (!self->ignore_error) { - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) + if (error) { /* Transfer not completed, return IO error */ - fp_err("transfer not completed, status = %d", transfer->status); - fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); - goto out; + fpi_ssm_mark_failed(transfer->ssm, error); + return; } - if (check_seqnum(vdev)) + if (check_seqnum(self)) { /* Sequential number received mismatch, return protocol error */ fp_err("seqnum mismatch, got %04x, expected %04x", - get_seqnum(vdev->buffer[1], vdev->buffer[0]), vdev->seqnum); - fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); - goto out; + get_seqnum(self->buffer[1], self->buffer[0]), + self->seqnum); + fpi_ssm_mark_failed(transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + return; } } - else - /* Reset ignore_error flag */ - vdev->ignore_error = FALSE; + + g_clear_pointer (&error, g_error_free); + + /* Reset ignore_error flag */ + self->ignore_error = FALSE; /* Dump buffer for debug */ - dump_buffer(vdev->buffer); + dump_buffer(self->buffer); /* Set length of received data */ - vdev->length = transfer->actual_length; + self->length = transfer->actual_length; - fpi_ssm_next_state(ssm); - -out: - libusb_free_transfer(transfer); + fpi_ssm_next_state(transfer->ssm); } /* Submit asynchronous recv */ static void -async_recv(fpi_ssm *ssm, - struct fp_img_dev *dev) +async_recv(FpiSsm *ssm, + FpImageDevice *dev) { - struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); - int r; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); + FpiUsbTransfer *transfer; /* Allocation of transfer */ - vdev->transfer = fpi_usb_alloc(); + transfer = fpi_usb_transfer_new(FP_DEVICE (dev)); /* Prepare bulk transfer */ - libusb_fill_bulk_transfer(vdev->transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN(1), vdev->buffer, 0x0f, async_recv_cb, ssm, BULK_TIMEOUT); - - /* Submit transfer */ - r = libusb_submit_transfer(vdev->transfer); - if (r != 0) - { - /* Submission of transfer failed, free transfer and return IO error */ - libusb_free_transfer(vdev->transfer); - fp_err("submit of usb transfer failed"); - fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); - return; - } + fpi_usb_transfer_fill_bulk_full(transfer, EP_IN(1), self->buffer, + 0x0f, NULL); + transfer->ssm = ssm; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + async_recv_cb, NULL); + fpi_usb_transfer_unref(transfer); } -static void async_load(fpi_ssm *ssm, struct fp_img_dev *dev); +static void async_load(FpiSsm *ssm, FpImageDevice *dev); /* Callback of asynchronous load */ -static void async_load_cb(struct libusb_transfer *transfer) +static void async_load_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); - - /* Cleanup transfer */ - vdev->transfer = NULL; + FpImageDevice *dev = FP_IMAGE_DEVICE(device); + FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); /* Skip error check if ignore_error is set */ - if (!vdev->ignore_error) + if (!self->ignore_error) { - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) + if (error) { /* Transfer not completed */ - fp_err("transfer not completed, status = %d, length = %d", transfer->status, vdev->length); - fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); - goto out; + fpi_ssm_mark_failed(transfer->ssm, error); + return; } if (transfer->actual_length % VFS_FRAME_SIZE) { /* Received incomplete frame, return protocol error */ fp_err("received incomplete frame"); - fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); - goto out; + fpi_ssm_mark_failed(transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + return; } } + /* Any error has been ignored. */ + g_clear_pointer (&error, g_error_free); + /* Increase image length */ - vdev->length += transfer->actual_length; + self->length += transfer->actual_length; if (transfer->actual_length == VFS_BLOCK_SIZE) { - if ((VFS_BUFFER_SIZE - vdev->length) < VFS_BLOCK_SIZE) + if ((VFS_BUFFER_SIZE - self->length) < VFS_BLOCK_SIZE) { /* Buffer full, image too large, return no memory error */ fp_err("buffer full, image too large"); - fpi_imgdev_session_error(dev, -ENOMEM); - fpi_ssm_mark_failed(ssm, -ENOMEM); - goto out; + fpi_ssm_mark_failed(transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + return; } else /* Image load not completed, submit another asynchronous load */ - async_load(ssm, dev); + async_load(transfer->ssm, dev); } else { /* Reset ignore_error flag */ - if (vdev->ignore_error) - vdev->ignore_error = FALSE; + self->ignore_error = FALSE; /* Image load completed, go to next state */ - vdev->height = vdev->length / VFS_FRAME_SIZE; - fp_dbg("image loaded, height = %d", vdev->height); - fpi_ssm_next_state(ssm); + self->height = self->length / VFS_FRAME_SIZE; + fp_dbg("image loaded, height = %d", self->height); + fpi_ssm_next_state(transfer->ssm); } - -out: - libusb_free_transfer(transfer); } /* Submit asynchronous load */ static void -async_load(fpi_ssm *ssm, - struct fp_img_dev *dev) +async_load(FpiSsm *ssm, + FpImageDevice *dev) { - struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); + FpiUsbTransfer *transfer; unsigned char *buffer; - int r; /* Allocation of transfer */ - vdev->transfer = fpi_usb_alloc(); + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); /* Append new data into the buffer */ - buffer = vdev->buffer + vdev->length; + buffer = self->buffer + self->length; /* Prepare bulk transfer */ - libusb_fill_bulk_transfer(vdev->transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN(2), buffer, VFS_BLOCK_SIZE, async_load_cb, ssm, BULK_TIMEOUT); - - /* Submit transfer */ - r = libusb_submit_transfer(vdev->transfer); - if (r != 0) - { - /* Submission of transfer failed, return IO error */ - libusb_free_transfer(vdev->transfer); - fp_err("submit of usb transfer failed"); - fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); - return; - } + fpi_usb_transfer_fill_bulk_full(transfer, EP_IN(2), buffer, + VFS_BLOCK_SIZE, NULL); + transfer->ssm = ssm; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + async_load_cb, NULL); + fpi_usb_transfer_unref(transfer); } /* Submit asynchronous sleep */ static void async_sleep(unsigned int msec, - fpi_ssm *ssm, - struct fp_img_dev *dev) + FpiSsm *ssm, + FpImageDevice *dev) { - if (fpi_timeout_add(msec, fpi_ssm_next_state_timeout_cb, FP_DEV(dev), ssm) == NULL) - { - /* Failed to add timeout */ - fp_err("failed to add timeout"); - fpi_imgdev_session_error(dev, -ETIME); - fpi_ssm_mark_failed(ssm, -ETIME); - } + fpi_device_add_timeout(FP_DEVICE(dev), msec, + fpi_ssm_next_state_timeout_cb, ssm); } /* Swap ssm states */ @@ -467,7 +378,7 @@ enum }; /* Exec swap sequential state machine */ -static void m_swap_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_swap_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) { switch (fpi_ssm_get_cur_state(ssm)) { @@ -485,28 +396,29 @@ static void m_swap_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) /* Start swap sequential state machine */ static void -m_swap(fpi_ssm *ssm, - struct fp_img_dev *dev, +m_swap(FpiSsm *ssm, + FpImageDevice *dev, unsigned char *data, size_t length) { - struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_ssm *subsm; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); + FpiSsm *subsm; /* Prepare data for sending */ - memcpy(vdev->buffer, data, length); - memset(vdev->buffer + length, 0, 16 - length); - vdev->length = length; + memcpy(self->buffer, data, length); + memset(self->buffer + length, 0, 16 - length); + self->length = length; /* Start swap ssm */ - subsm = fpi_ssm_new(FP_DEV(dev), m_swap_state, M_SWAP_NUM_STATES, dev); + subsm = fpi_ssm_new(FP_DEVICE(dev), m_swap_state, M_SWAP_NUM_STATES, + dev); fpi_ssm_start_subsm(ssm, subsm); } /* Retrieve fingerprint image */ static void -vfs_get_print(fpi_ssm *ssm, - struct fp_img_dev *dev, +vfs_get_print(FpiSsm *ssm, + FpImageDevice *dev, unsigned int param, int type) { @@ -529,8 +441,8 @@ vfs_get_print(fpi_ssm *ssm, /* Set a parameter value on the device */ static void -vfs_set_param(fpi_ssm *ssm, - struct fp_img_dev *dev, +vfs_set_param(FpiSsm *ssm, + FpImageDevice *dev, unsigned int param, unsigned int value) { @@ -550,8 +462,8 @@ vfs_set_param(fpi_ssm *ssm, /* Abort previous print */ static void -vfs_abort_print(fpi_ssm *ssm, - struct fp_img_dev *dev) +vfs_abort_print(FpiSsm *ssm, + FpImageDevice *dev) { unsigned char data[0x06] = { 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00 }; @@ -563,8 +475,8 @@ vfs_abort_print(fpi_ssm *ssm, /* Poke a value on a region */ static void -vfs_poke(fpi_ssm *ssm, - struct fp_img_dev *dev, +vfs_poke(FpiSsm *ssm, + FpImageDevice *dev, unsigned int addr, unsigned int value, unsigned int size) @@ -590,8 +502,8 @@ vfs_poke(fpi_ssm *ssm, /* Get current finger state */ static void -vfs_get_finger_state(fpi_ssm *ssm, - struct fp_img_dev *dev) +vfs_get_finger_state(FpiSsm *ssm, + FpImageDevice *dev) { unsigned char data[0x06] = { 0x00, 0x00, 0x00, 0x00, 0x16, 0x00 }; @@ -603,46 +515,28 @@ vfs_get_finger_state(fpi_ssm *ssm, /* Load raw image from reader */ static void -vfs_img_load(fpi_ssm *ssm, - struct fp_img_dev *dev) +vfs_img_load(FpiSsm *ssm, + FpImageDevice *dev) { - struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); G_DEBUG_HERE(); /* Reset buffer length */ - vdev->length = 0; + self->length = 0; /* Reset image properties */ - vdev->bottom = 0; - vdev->height = -1; + self->bottom = 0; + self->height = -1; /* Asynchronous load */ async_load(ssm, dev); } -/* Check if action is completed */ -static int action_completed(struct fp_img_dev *dev) -{ - struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); - - if ((fpi_imgdev_get_action(dev) == IMG_ACTION_ENROLL) && - (vdev->enroll_stage < fp_dev_get_nr_enroll_stages(FP_DEV(dev)))) - /* Enroll not completed, return false */ - return FALSE; - - else if (vdev->enroll_stage < 1) - /* Action not completed, return false */ - return FALSE; - - /* Action completed, return true */ - return TRUE; -} - #define offset(x, y) ((x) + ((y) * VFS_FRAME_SIZE)) /* Screen image to remove noise and find bottom line and height of image */ -static void img_screen(struct vfs101_dev *vdev) +static void img_screen(FpDeviceVfs101 *vdev) { int y, x, count, top; long int level; @@ -714,11 +608,11 @@ static void img_screen(struct vfs101_dev *vdev) }; /* Copy image from reader buffer and put it into image data */ -static void img_copy(struct vfs101_dev *vdev, struct fp_img *img) +static void img_copy(FpDeviceVfs101 *self, FpImage *img) { unsigned int line; unsigned char *img_buffer = img->data; - unsigned char *vdev_buffer = vdev->buffer + (vdev->bottom * VFS_FRAME_SIZE) + 6; + unsigned char *vdev_buffer = self->buffer + (self->bottom * VFS_FRAME_SIZE) + 6; for (line = 0; line < img->height; line++) { @@ -735,71 +629,35 @@ static void img_copy(struct vfs101_dev *vdev, struct fp_img *img) /* Extract fingerpint image from raw data */ static void -img_extract(fpi_ssm *ssm, - struct fp_img_dev *dev) +img_extract(FpiSsm *ssm, + FpImageDevice *dev) { - struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); - struct fp_img *img; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); + FpImage *img; /* Screen image to remove noise and find top and bottom line */ - img_screen(vdev); + img_screen(self); /* Check image height */ - if (vdev->height < VFS_IMG_MIN_HEIGHT) + if (self->height < VFS_IMG_MIN_HEIGHT) { /* Image too short */ - vdev->height = 0; + self->height = 0; + fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT); return; } - /* Fingerprint is present, load image from reader */ - fpi_imgdev_report_finger_status(dev, TRUE); - /* Create new image */ - img = fpi_img_new(vdev->height * VFS_IMG_WIDTH); + img = fp_image_new(self->height, VFS_IMG_WIDTH); img->width = VFS_IMG_WIDTH; - img->height = vdev->height; - img->flags = FP_IMG_V_FLIPPED; + img->height = self->height; + img->flags = FPI_IMAGE_V_FLIPPED; /* Copy data into image */ - img_copy(vdev, img); + img_copy(self, img); /* Notify image captured */ - fpi_imgdev_image_captured(dev, img); - - /* FIXME - * What is this for? The action result, and the enroll stages should - * already be handled in fpi_imgdev_image_captured() - */ - - /* Check captured result */ - if (fpi_imgdev_get_action_result(dev) >= 0 && - fpi_imgdev_get_action_result(dev) != FP_ENROLL_RETRY && - fpi_imgdev_get_action_result(dev) != FP_VERIFY_RETRY) - { - /* Image captured, increase enroll stage */ - vdev->enroll_stage++; - - /* Check if action is completed */ - if (!action_completed(dev)) - fpi_imgdev_set_action_result(dev, FP_ENROLL_PASS); - } - else - { - /* Image capture failed */ - if (fpi_imgdev_get_action(dev) == IMG_ACTION_ENROLL) - /* Return retry */ - fpi_imgdev_set_action_result(dev, result_code(dev, RESULT_RETRY)); - else - { - /* Return no match */ - vdev->enroll_stage++; - fpi_imgdev_set_action_result(dev, FP_VERIFY_NO_MATCH); - } - } - - /* Fingerprint is removed from reader */ - fpi_imgdev_report_finger_status(dev, FALSE); + fpi_image_device_image_captured(dev, img); }; /* Finger states */ @@ -811,7 +669,7 @@ enum }; /* Return finger state */ -static inline int vfs_finger_state(struct vfs101_dev *vdev) +static inline int vfs_finger_state(FpDeviceVfs101 *vdev) { /* Check finger state */ switch (vdev->buffer[0x0a]) @@ -837,7 +695,7 @@ static inline int vfs_finger_state(struct vfs101_dev *vdev) }; /* Check contrast of image */ -static void vfs_check_contrast(struct vfs101_dev *vdev) +static void vfs_check_contrast(FpDeviceVfs101 *vdev) { int y; long int count = 0; @@ -898,15 +756,13 @@ enum }; /* Exec loop sequential state machine */ -static void m_loop_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_loop_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct vfs101_dev *vdev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101(_dev); - /* Check action state */ - if (!vdev->active) - { - /* Action not active, mark sequential state machine completed */ + /* Complete if deactivation was requested */ + if (self->deactivate) { fpi_ssm_mark_completed(ssm); return; } @@ -930,51 +786,50 @@ static void m_loop_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) case M_LOOP_0_LOAD_IMAGE: /* Check finger state */ - switch (vfs_finger_state(vdev)) + switch (vfs_finger_state(self)) { case VFS_FINGER_EMPTY: + fpi_image_device_report_finger_status(dev, FALSE); + /* Finger isn't present, loop */ fpi_ssm_jump_to_state(ssm, M_LOOP_0_SLEEP); break; case VFS_FINGER_PRESENT: + fpi_image_device_report_finger_status(dev, TRUE); + /* Load image from reader */ - vdev->ignore_error = TRUE; + self->ignore_error = TRUE; vfs_img_load(ssm, dev); break; default: + fpi_image_device_report_finger_status(dev, FALSE); + /* Unknown state */ - fp_err("unknown device state 0x%02x", vdev->buffer[0x0a]); - fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); + fp_err("unknown device state 0x%02x", + self->buffer[0x0a]); + fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); break; } break; case M_LOOP_0_EXTRACT_IMAGE: - /* Check if image is loaded */ - if (vdev->height > 0) - /* Fingerprint is loaded, extract image from raw data */ - img_extract(ssm, dev); + /* Fingerprint is loaded, extract image from raw data */ + img_extract(ssm, dev); /* Wait handling image */ async_sleep(10, ssm, dev); break; case M_LOOP_0_CHECK_ACTION: - /* Check if action is completed */ - if (action_completed(dev)) - /* Action completed */ - fpi_ssm_mark_completed(ssm); + /* Action not completed */ + if (self->height > 0) + /* Continue loop */ + fpi_ssm_jump_to_state(ssm, M_LOOP_2_ABORT_PRINT); else - /* Action not completed */ - if (vdev->height > 0) - /* Continue loop */ - fpi_ssm_jump_to_state(ssm, M_LOOP_2_ABORT_PRINT); - else - /* Error found */ - fpi_ssm_next_state(ssm); + /* Error found */ + fpi_ssm_next_state(ssm); break; case M_LOOP_1_GET_STATE: @@ -984,51 +839,17 @@ static void m_loop_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) case M_LOOP_1_CHECK_STATE: /* Check finger state */ - if (vfs_finger_state(vdev) == VFS_FINGER_PRESENT) + if (vfs_finger_state(self) == VFS_FINGER_PRESENT) { - if (vdev->counter < 20) - { - if (vdev->counter == 1) - { - /* The user should remove their finger from the scanner */ - fp_warn("finger present after scan, remove it"); - fpi_imgdev_session_error(dev, result_code(dev, RESULT_RETRY_REMOVE)); - } - - /* Wait removing finger */ - vdev->counter++; - async_sleep(250, ssm, dev); - } - else - { - /* reach max loop counter, return protocol error */ - fp_err("finger not removed from the scanner"); - fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); - } + fpi_image_device_report_finger_status(dev, TRUE); + async_sleep(250, ssm, dev); } else { /* Finger not present */ - if (vdev->counter == 0) - { - /* Check image height */ - if (vdev->height == 0) - { - /* Return retry to short */ - fp_warn("image too short, retry"); - fpi_imgdev_session_error(dev, result_code(dev, RESULT_RETRY_SHORT)); - } - else - { - /* Return retry result */ - fp_warn("load image failed, retry"); - fpi_imgdev_session_error(dev, result_code(dev, RESULT_RETRY)); - } - } + fpi_image_device_report_finger_status(dev, FALSE); /* Continue */ - vdev->counter = 0; fpi_ssm_jump_to_state(ssm, M_LOOP_1_SLEEP); } break; @@ -1040,7 +861,7 @@ static void m_loop_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) case M_LOOP_1_LOAD_IMAGE: /* Load image */ - vdev->ignore_error = TRUE; + self->ignore_error = TRUE; vfs_img_load(ssm, dev); break; @@ -1061,7 +882,7 @@ static void m_loop_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) case M_LOOP_2_LOAD_IMAGE: /* Load abort image */ - vdev->ignore_error = TRUE; + self->ignore_error = TRUE; vfs_img_load(ssm, dev); break; @@ -1072,29 +893,28 @@ static void m_loop_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) case M_LOOP_3_LOAD_IMAGE: /* Load abort image */ - vdev->ignore_error = TRUE; + self->ignore_error = TRUE; vfs_img_load(ssm, dev); break; case M_LOOP_3_CHECK_IMAGE: - if (vdev->height == 10) + if (self->height == 10) { /* Image load correctly, jump to step 0 */ - vdev->counter = 0; + self->counter = 0; fpi_ssm_jump_to_state(ssm, M_LOOP_0_GET_PRINT); } - else if (vdev->counter < 10) + else if (self->counter < 10) { /* Wait aborting */ - vdev->counter++; + self->counter++; async_sleep(100, ssm, dev); } else { /* reach max loop counter, return protocol error */ fp_err("waiting abort reach max loop counter"); - fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } break; @@ -1106,9 +926,18 @@ static void m_loop_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) } /* Complete loop sequential state machine */ -static void m_loop_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_loop_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - /* Free sequential state machine */ + FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev); + + /* When the loop completes, we have (successfully) deactivated */ + if (self->active) + fpi_image_device_deactivate_complete (FP_IMAGE_DEVICE (dev), + error); + + self->active = FALSE; + fpi_ssm_free(ssm); } @@ -1162,16 +991,17 @@ enum }; /* Exec init sequential state machine */ -static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_init_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct vfs101_dev *vdev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101(_dev); - /* Check action state */ - if (!vdev->active) - { - /* Action not active, mark sequential state machine completed */ - fpi_ssm_mark_completed(ssm); + /* Mark as cancelled when activation collides with deactivation. */ + if (self->deactivate) { + fpi_ssm_mark_failed (ssm, + g_error_new (G_IO_ERROR, + G_IO_ERROR_CANCELLED, + "Initialisation was cancelled")); return; } @@ -1179,7 +1009,7 @@ static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) { case M_INIT_0_RECV_DIRTY: /* Recv eventually dirty data */ - vdev->ignore_error = TRUE; + self->ignore_error = TRUE; async_recv(ssm, dev); break; @@ -1190,7 +1020,7 @@ static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) case M_INIT_0_LOAD_IMAGE: /* Load abort image */ - vdev->ignore_error = TRUE; + self->ignore_error = TRUE; vfs_img_load(ssm, dev); break; @@ -1201,29 +1031,28 @@ static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) case M_INIT_1_LOAD_IMAGE: /* Load abort image */ - vdev->ignore_error = TRUE; + self->ignore_error = TRUE; vfs_img_load(ssm, dev); break; case M_INIT_1_CHECK_IMAGE: - if (vdev->height == 10) + if (self->height == 10) { /* Image load correctly, jump to step 2 */ - vdev->counter = 0; + self->counter = 0; fpi_ssm_jump_to_state(ssm, M_INIT_2_GET_STATE); } - else if (vdev->counter < 10) + else if (self->counter < 10) { /* Wait aborting */ - vdev->counter++; + self->counter++; async_sleep(100, ssm, dev); } else { /* reach max loop counter, return protocol error */ fp_err("waiting abort reach max loop counter"); - fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } break; @@ -1239,39 +1068,32 @@ static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) case M_INIT_2_CHECK_STATE: /* Check finger state */ - if (vfs_finger_state(vdev) == VFS_FINGER_PRESENT) + if (vfs_finger_state(self) == VFS_FINGER_PRESENT) { - if (vdev->counter < 20) + /* Wait a bit for finger removal; if it doesn't happen, prompt */ + if (self->counter < 2) { - if (vdev->counter == 2) - { - /* The user should remove their finger from the scanner */ - fp_warn("unexpected finger find, remove finger from the scanner"); - fpi_imgdev_session_error(dev, result_code(dev, RESULT_RETRY_REMOVE)); - } - /* Wait removing finger */ - vdev->counter++; + self->counter++; async_sleep(250, ssm, dev); } else { - /* reach max loop counter, return protocol error */ - fp_err("finger not removed from the scanner"); - fpi_imgdev_session_error(dev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); + /* The user should remove their finger from the scanner */ + fp_warn("unexpected finger find, remove finger from the scanner"); + fpi_ssm_mark_failed(ssm, fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER)); } } else { /* Finger not present */ - if (vdev->counter == 0) + if (self->counter == 0) /* Continue */ fpi_ssm_jump_to_state(ssm, M_INIT_3_SET_000E); else { /* Finger removed, jump to abort */ - vdev->counter = 0; + self->counter = 0; fpi_ssm_jump_to_state(ssm, M_INIT_0_ABORT_PRINT); } } @@ -1284,7 +1106,7 @@ static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) case M_INIT_2_LOAD_IMAGE: /* Load unexpected image */ - vdev->ignore_error = TRUE; + self->ignore_error = TRUE; vfs_img_load(ssm, dev); break; @@ -1341,12 +1163,12 @@ static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) case M_INIT_4_SET_EXPOSURE: /* Set exposure level of reader */ vfs_poke(ssm, dev, VFS_REG_IMG_EXPOSURE, 0x4000, 0x02); - vdev->counter = 1; + self->counter = 1; break; case M_INIT_4_SET_CONTRAST: /* Set contrast level of reader */ - vfs_poke(ssm, dev, VFS_REG_IMG_CONTRAST, vdev->contrast, 0x01); + vfs_poke(ssm, dev, VFS_REG_IMG_CONTRAST, self->contrast, 0x01); break; case M_INIT_4_GET_PRINT: @@ -1361,21 +1183,21 @@ static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) case M_INIT_4_CHECK_CONTRAST: /* Check contrast */ - vfs_check_contrast(vdev); + vfs_check_contrast(self); - if (vdev->contrast <= 6 || vdev->counter >= 12) + if (self->contrast <= 6 || self->counter >= 12) { /* End contrast scan, continue */ - vdev->contrast = vdev->best_contrast; - vdev->counter = 0; - fp_dbg("use contrast value = %d", vdev->contrast); + self->contrast = self->best_contrast; + self->counter = 0; + fp_dbg("use contrast value = %d", self->contrast); fpi_ssm_next_state(ssm); } else { /* Continue contrast scan, loop */ - vdev->contrast--; - vdev->counter++; + self->contrast--; + self->counter++; fpi_ssm_jump_to_state(ssm, M_INIT_4_SET_CONTRAST); } break; @@ -1387,12 +1209,12 @@ static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) case M_INIT_5_SET_CONTRAST: /* Set contrast level of reader */ - vfs_poke(ssm, dev, VFS_REG_IMG_CONTRAST, vdev->contrast, 0x01); + vfs_poke(ssm, dev, VFS_REG_IMG_CONTRAST, self->contrast, 0x01); break; case M_INIT_5_SET_INFO_CONTRAST: /* Set info line contrast */ - vfs_set_param(ssm, dev, VFS_PAR_INFO_CONTRAST, vdev->contrast); + vfs_set_param(ssm, dev, VFS_PAR_INFO_CONTRAST, self->contrast); break; case M_INIT_5_SET_INFO_RATE: @@ -1403,19 +1225,20 @@ static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) } /* Complete init sequential state machine */ -static void m_init_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_init_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - struct fp_img_dev *dev = user_data; - struct vfs101_dev *vdev = FP_INSTANCE_DATA(_dev); - fpi_ssm *ssm_loop; + FpImageDevice *dev = user_data; - if (!fpi_ssm_get_error(ssm) && vdev->active) - { - /* Notify activate complete */ - fpi_imgdev_activate_complete(dev, 0); + /* Notify activate complete */ + fpi_image_device_activate_complete(dev, error); + + if (!error) { + FpiSsm *ssm_loop; /* Start loop ssm */ - ssm_loop = fpi_ssm_new(FP_DEV(dev), m_loop_state, M_LOOP_NUM_STATES, dev); + ssm_loop = fpi_ssm_new(FP_DEVICE(dev), m_loop_state, + M_LOOP_NUM_STATES, dev); fpi_ssm_start(ssm_loop, m_loop_complete); } @@ -1424,124 +1247,105 @@ static void m_init_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) } /* Activate device */ -static int dev_activate(struct fp_img_dev *dev) +static void dev_activate(FpImageDevice *dev) { - struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_ssm *ssm; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); + FpiSsm *ssm; /* Check if already active */ - if (vdev->active) - { - fp_err("device already activated"); - fpi_imgdev_session_error(dev, -EBUSY); - return 1; - } + g_assert (!self->active); /* Set active state */ - vdev->active = TRUE; + self->active = TRUE; + self->deactivate = FALSE; /* Set contrast */ - vdev->contrast = 15; - vdev->best_clevel = -1; + self->contrast = 15; + self->best_clevel = -1; - /* Reset loop counter and enroll stage */ - vdev->counter = 0; - vdev->enroll_stage = 0; + /* Reset loop counter */ + self->counter = 0; /* Start init ssm */ - ssm = fpi_ssm_new(FP_DEV(dev), m_init_state, M_INIT_NUM_STATES, dev); + ssm = fpi_ssm_new(FP_DEVICE(dev), m_init_state, M_INIT_NUM_STATES, dev); fpi_ssm_start(ssm, m_init_complete); - - return 0; } /* Deactivate device */ -static void dev_deactivate(struct fp_img_dev *dev) +static void dev_deactivate(FpImageDevice *dev) { - struct vfs101_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); - /* Reset active state */ - vdev->active = FALSE; + /* Device already deactivated, likely due to an error */ + if (!self->active) { + fpi_image_device_deactivate_complete (dev, NULL); + return; + } - /* Handle eventually existing events */ - while (vdev->transfer) - fp_handle_events(); - - /* Notify deactivate complete */ - fpi_imgdev_deactivate_complete(dev); + /* Signal deactivation, deactivation will happen from the SSM + * completion handler. */ + self->deactivate = TRUE; } /* Open device */ -static int dev_open(struct fp_img_dev *dev, unsigned long driver_data) +static void dev_open(FpImageDevice *dev) { - struct vfs101_dev *vdev = NULL; - int r; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); + GError *error = NULL; /* Claim usb interface */ - r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - if (r < 0) - { - /* Interface not claimed, return error */ - fp_err("could not claim interface 0: %s", libusb_error_name(r)); - return r; - } + g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error); /* Initialize private structure */ - vdev = g_malloc0(sizeof(struct vfs101_dev)); - vdev->seqnum = -1; - fp_dev_set_instance_data(FP_DEV(dev), vdev); + self->seqnum = -1; + self->buffer = g_malloc0 (VFS_BUFFER_SIZE); /* Notify open complete */ - fpi_imgdev_open_complete(dev, 0); - - return 0; + fpi_image_device_open_complete(dev, error); } /* Close device */ -static void dev_close(struct fp_img_dev *dev) +static void dev_close(FpImageDevice *dev) { - struct vfs101_dev *vdev; - - /* Release private structure */ - vdev = FP_INSTANCE_DATA(FP_DEV(dev)); - g_free(vdev); + FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); + GError *error = NULL; /* Release usb interface */ - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), + 0, 0, &error); + + g_clear_pointer (&self->buffer, g_free); /* Notify close complete */ - fpi_imgdev_close_complete(dev); + fpi_image_device_close_complete(dev, error); } /* Usb id table of device */ -static const struct usb_id id_table[] = -{ - { .vendor = 0x138a, .product = 0x0001 }, - { 0, 0, 0, }, +static const FpIdEntry id_table [ ] = { + { .vid = 0x138a, .pid = 0x0001, }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -/* Device driver definition */ -struct fp_img_driver vfs101_driver = -{ - /* Driver specification */ - .driver = - { - .id = VFS101_ID, - .name = FP_COMPONENT, - .full_name = "Validity VFS101", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_SWIPE, - }, +static void fpi_device_vfs101_init(FpDeviceVfs101 *self) { +} - /* Image specification */ - .flags = 0, - .img_width = VFS_IMG_WIDTH, - .img_height = -1, - .bz3_threshold = 24, +static void fpi_device_vfs101_class_init(FpDeviceVfs101Class *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); - /* Routine specification */ - .open = dev_open, - .close = dev_close, - .activate = dev_activate, - .deactivate = dev_deactivate, -}; + dev_class->id = "vfs101"; + dev_class->full_name = "Validity VFS101"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + + img_class->img_open = dev_open; + img_class->img_close = dev_close; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; + + img_class->bz3_threshold = 24; + + img_class->img_width = VFS_IMG_WIDTH; + img_class->img_height = -1; +} diff --git a/meson.build b/meson.build index d67ef2d6..f963fc89 100644 --- a/meson.build +++ b/meson.build @@ -51,7 +51,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550' ] +default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101' ] all_drivers = default_drivers + virtual_drivers From 2e3057236403193f501429b6bd1d057482c0ffa7 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 9 Jul 2019 17:35:52 +0200 Subject: [PATCH 36/73] vfs301: Port driver to new API This driver is synchronuous mostly, and the sync API is not well tested. It should work, but there has been some re-shuffling of buffers, etc. --- libfprint/drivers/vfs301.c | 189 +++++----- .../drivers/{vfs301_proto.h => vfs301.h} | 34 +- libfprint/drivers/vfs301_proto.c | 354 ++++++++++-------- meson.build | 2 +- 4 files changed, 295 insertions(+), 284 deletions(-) rename libfprint/drivers/{vfs301_proto.h => vfs301.h} (80%) diff --git a/libfprint/drivers/vfs301.c b/libfprint/drivers/vfs301.c index 94837de0..2339c2ff 100644 --- a/libfprint/drivers/vfs301.c +++ b/libfprint/drivers/vfs301.c @@ -22,32 +22,30 @@ #define FP_COMPONENT "vfs301" #include "drivers_api.h" -#include "vfs301_proto.h" +#include "vfs301.h" + +G_DEFINE_TYPE (FpDeviceVfs301, fpi_device_vfs301, FP_TYPE_IMAGE_DEVICE) /************************** GENERIC STUFF *************************************/ /* Submit asynchronous sleep */ static void async_sleep(unsigned int msec, - fpi_ssm *ssm, - struct fp_img_dev *dev) + FpiSsm *ssm, + FpImageDevice *dev) { /* Add timeout */ - if (fpi_timeout_add(msec, fpi_ssm_next_state_timeout_cb, FP_DEV(dev), ssm) == NULL) { - /* Failed to add timeout */ - fp_err("failed to add timeout"); - fpi_imgdev_session_error(dev, -ETIME); - fpi_ssm_mark_failed(ssm, -ETIME); - } + fpi_device_add_timeout(FP_DEVICE(dev), msec, + fpi_ssm_next_state_timeout_cb, ssm); } static int -submit_image(fpi_ssm *ssm, - struct fp_img_dev *dev) +submit_image(FpiSsm *ssm, + FpImageDevice *dev) { - vfs301_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpDeviceVfs301 *self = FPI_DEVICE_VFS301(dev); int height; - struct fp_img *img; + FpImage *img; #if 0 /* XXX: This is probably handled by libfprint automagically? */ @@ -57,22 +55,23 @@ submit_image(fpi_ssm *ssm, } #endif - img = fpi_img_new(VFS301_FP_OUTPUT_WIDTH * vdev->scanline_count); + img = fp_image_new(VFS301_FP_OUTPUT_WIDTH, self->scanline_count); if (img == NULL) return 0; - vfs301_extract_image(vdev, img->data, &height); + vfs301_extract_image(self, img->data, &height); /* TODO: how to detect flip? should the resulting image be * oriented so that it is equal e.g. to a fingerprint on a paper, * or to the finger when I look at it?) */ - img->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED; + img->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED; + /* The image buffer is larger at this point, but that does not + * matter. */ img->width = VFS301_FP_OUTPUT_WIDTH; img->height = height; - img = fpi_img_realloc(img, img->height * img->width); - fpi_imgdev_image_captured(dev, img); + fpi_image_device_image_captured(dev, img); return 1; } @@ -94,14 +93,14 @@ enum }; /* Exec loop sequential state machine */ -static void m_loop_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_loop_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct fp_img_dev *dev = user_data; - vfs301_dev_t *vdev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpDeviceVfs301 *self = FPI_DEVICE_VFS301(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case M_REQUEST_PRINT: - vfs301_proto_request_fingerprint(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev); + vfs301_proto_request_fingerprint(self); fpi_ssm_next_state(ssm); break; @@ -111,15 +110,15 @@ static void m_loop_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) break; case M_CHECK_PRINT: - if (!vfs301_proto_peek_event(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev)) + if (!vfs301_proto_peek_event(self)) fpi_ssm_jump_to_state(ssm, M_WAIT_PRINT); else fpi_ssm_next_state(ssm); break; case M_READ_PRINT_START: - fpi_imgdev_report_finger_status(dev, TRUE); - vfs301_proto_process_event_start(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev); + fpi_image_device_report_finger_status(dev, TRUE); + vfs301_proto_process_event_start(self); fpi_ssm_next_state(ssm); break; @@ -130,7 +129,7 @@ static void m_loop_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) case M_READ_PRINT_POLL: { - int rv = vfs301_proto_process_event_poll(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev); + int rv = vfs301_proto_process_event_poll(self); g_assert(rv != VFS301_FAILURE); if (rv == VFS301_ONGOING) fpi_ssm_jump_to_state(ssm, M_READ_PRINT_WAIT); @@ -143,46 +142,53 @@ static void m_loop_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) if (submit_image(ssm, dev)) { fpi_ssm_mark_completed(ssm); /* NOTE: finger off is expected only after submitting image... */ - fpi_imgdev_report_finger_status(dev, FALSE); + fpi_image_device_report_finger_status(dev, FALSE); } else { fpi_ssm_jump_to_state(ssm, M_REQUEST_PRINT); } break; + default: + g_assert_not_reached (); } } /* Complete loop sequential state machine */ -static void m_loop_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_loop_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { + if (error) { + g_warning ("State machine completed with an error: %s", error->message); + g_error_free (error); + } /* Free sequential state machine */ fpi_ssm_free(ssm); } /* Exec init sequential state machine */ -static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_init_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct fp_img_dev *dev = user_data; - vfs301_dev_t *vdev = FP_INSTANCE_DATA(_dev); + FpDeviceVfs301 *self = FPI_DEVICE_VFS301(_dev); g_assert(fpi_ssm_get_cur_state(ssm) == 0); - vfs301_proto_init(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev); + vfs301_proto_init(self); fpi_ssm_mark_completed(ssm); } /* Complete init sequential state machine */ -static void m_init_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_init_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - struct fp_img_dev *dev = user_data; - fpi_ssm *ssm_loop; + FpiSsm *ssm_loop; - if (!fpi_ssm_get_error(ssm)) { + fpi_image_device_activate_complete(FP_IMAGE_DEVICE (dev), error); + if (!error) { /* Notify activate complete */ - fpi_imgdev_activate_complete(dev, 0); /* Start loop ssm */ - ssm_loop = fpi_ssm_new(FP_DEV(dev), m_loop_state, M_LOOP_NUM_STATES, dev); + ssm_loop = fpi_ssm_new(dev, m_loop_state, + M_LOOP_NUM_STATES, dev); fpi_ssm_start(ssm_loop, m_loop_complete); } @@ -191,99 +197,82 @@ static void m_init_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) } /* Activate device */ -static int dev_activate(struct fp_img_dev *dev) +static void dev_activate(FpImageDevice *dev) { - fpi_ssm *ssm; + FpiSsm *ssm; /* Start init ssm */ - ssm = fpi_ssm_new(FP_DEV(dev), m_init_state, 1, dev); + ssm = fpi_ssm_new(FP_DEVICE(dev), m_init_state, 1, dev); fpi_ssm_start(ssm, m_init_complete); - - return 0; } /* Deactivate device */ -static void dev_deactivate(struct fp_img_dev *dev) +static void dev_deactivate(FpImageDevice *dev) { - vfs301_dev_t *vdev; + FpDeviceVfs301 *self; - vdev = FP_INSTANCE_DATA(FP_DEV(dev)); - vfs301_proto_deinit(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev); - fpi_imgdev_deactivate_complete(dev); + self = FPI_DEVICE_VFS301(dev); + vfs301_proto_deinit(self); + fpi_image_device_deactivate_complete(dev, NULL); } -static int dev_open(struct fp_img_dev *dev, unsigned long driver_data) +static void dev_open(FpImageDevice *dev) { - vfs301_dev_t *vdev = NULL; - int r; + FpDeviceVfs301 *self = FPI_DEVICE_VFS301(dev); + GError *error = NULL; /* Claim usb interface */ - r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - if (r < 0) { - /* Interface not claimed, return error */ - fp_err("could not claim interface 0: %s", libusb_error_name(r)); - return r; - } + g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error); /* Initialize private structure */ - vdev = g_malloc0(sizeof(vfs301_dev_t)); - fp_dev_set_instance_data(FP_DEV(dev), vdev); - - vdev->scanline_buf = malloc(0); - vdev->scanline_count = 0; + self->scanline_count = 0; /* Notify open complete */ - fpi_imgdev_open_complete(dev, 0); - - return 0; + fpi_image_device_open_complete(dev, error); } -static void dev_close(struct fp_img_dev *dev) +static void dev_close(FpImageDevice *dev) { - vfs301_dev_t *vdev; + FpDeviceVfs301 *self = FPI_DEVICE_VFS301(dev); + GError *error = NULL; /* Release private structure */ - vdev = FP_INSTANCE_DATA(FP_DEV(dev)); - free(vdev->scanline_buf); - g_free(vdev); + g_clear_pointer (&self->scanline_buf, g_free); /* Release usb interface */ - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), + 0, 0, &error); /* Notify close complete */ - fpi_imgdev_close_complete(dev); + fpi_image_device_close_complete(dev, error); } /* Usb id table of device */ -static const struct usb_id id_table[] = -{ - { .vendor = 0x138a, .product = 0x0005 /* vfs301 */ }, - { .vendor = 0x138a, .product = 0x0008 /* vfs300 */ }, - { 0, 0, 0, }, +static const FpIdEntry id_table [ ] = { + { /* vfs301 */ .vid = 0x138a, .pid = 0x0005, }, + { /* vfs300 */ .vid = 0x138a, .pid = 0x0008, }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -/* Device driver definition */ -struct fp_img_driver vfs301_driver = -{ - /* Driver specification */ - .driver = - { - .id = VFS301_ID, - .name = FP_COMPONENT, - .full_name = "Validity VFS301", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_SWIPE, - }, +static void fpi_device_vfs301_init(FpDeviceVfs301 *self) { +} +static void fpi_device_vfs301_class_init(FpDeviceVfs301Class *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); - /* Image specification */ - .flags = 0, - .img_width = VFS301_FP_WIDTH, - .img_height = -1, - .bz3_threshold = 24, + dev_class->id = "vfs301"; + dev_class->full_name = "Validity VFS301"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - /* Routine specification */ - .open = dev_open, - .close = dev_close, - .activate = dev_activate, - .deactivate = dev_deactivate, -}; + img_class->img_open = dev_open; + img_class->img_close = dev_close; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; + + img_class->bz3_threshold = 24; + + img_class->img_width = VFS301_FP_WIDTH; + img_class->img_height = -1; +} diff --git a/libfprint/drivers/vfs301_proto.h b/libfprint/drivers/vfs301.h similarity index 80% rename from libfprint/drivers/vfs301_proto.h rename to libfprint/drivers/vfs301.h index 2ae587a1..dfbbc7e9 100644 --- a/libfprint/drivers/vfs301_proto.h +++ b/libfprint/drivers/vfs301.h @@ -18,7 +18,11 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include + +#pragma once + +#include "fpi-usb-transfer.h" +#include "fpi-image-device.h" enum { VFS301_DEFAULT_WAIT_TIMEOUT = 300, @@ -31,10 +35,8 @@ enum { #define VFS301_FP_RECV_LEN_1 (84032) #define VFS301_FP_RECV_LEN_2 (84096) -typedef struct { - /* buffer for received data */ - unsigned char recv_buf[0x20000]; - int recv_len; +struct _FpDeviceVfs301 { + FpImageDevice parent; /* buffer to hold raw scanlines */ unsigned char *scanline_buf; @@ -46,7 +48,9 @@ typedef struct { VFS301_FAILURE = -1 } recv_progress; int recv_exp_amt; -} vfs301_dev_t; +}; + +G_DECLARE_FINAL_TYPE (FpDeviceVfs301, fpi_device_vfs301, FPI, DEVICE_VFS301, FpImageDevice) enum { /* Width of the scanned data in px */ @@ -120,18 +124,14 @@ typedef struct { unsigned char sum3[3]; } vfs301_line_t; -void vfs301_proto_init(struct libusb_device_handle *devh, vfs301_dev_t *dev); -void vfs301_proto_deinit(struct libusb_device_handle *devh, vfs301_dev_t *dev); +void vfs301_proto_init(FpDeviceVfs301 *dev); +void vfs301_proto_deinit(FpDeviceVfs301 *dev); -void vfs301_proto_request_fingerprint( - struct libusb_device_handle *devh, vfs301_dev_t *dev); +void vfs301_proto_request_fingerprint(FpDeviceVfs301 *dev); /** returns 0 if no event is ready, or 1 if there is one... */ -int vfs301_proto_peek_event( - struct libusb_device_handle *devh, vfs301_dev_t *dev); -void vfs301_proto_process_event_start( - struct libusb_device_handle *devh, vfs301_dev_t *dev); -int vfs301_proto_process_event_poll( - struct libusb_device_handle *devh, vfs301_dev_t *dev); +int vfs301_proto_peek_event(FpDeviceVfs301 *dev); +void vfs301_proto_process_event_start(FpDeviceVfs301 *dev); +int vfs301_proto_process_event_poll(FpDeviceVfs301 *dev); -void vfs301_extract_image(vfs301_dev_t *vfs, unsigned char *output, int *output_height); +void vfs301_extract_image(FpDeviceVfs301 *vfs, unsigned char *output, int *output_height); diff --git a/libfprint/drivers/vfs301_proto.c b/libfprint/drivers/vfs301_proto.c index 7564f56d..17129f15 100644 --- a/libfprint/drivers/vfs301_proto.c +++ b/libfprint/drivers/vfs301_proto.c @@ -34,16 +34,16 @@ #include #include -#include "fpi-usb.h" -#include "vfs301_proto.h" +#include "fpi-usb-transfer.h" +#include "vfs301.h" #include "vfs301_proto_fragments.h" /************************** USB STUFF *****************************************/ #ifdef DEBUG -static void usb_print_packet(int dir, int rv, const unsigned char *data, int length) +static void usb_print_packet(int dir, GError *error, const guint8 *data, int length) { - fprintf(stderr, "%s, rv %d, len %d\n", dir ? "send" : "recv", rv, length); + fprintf(stderr, "%s, error %s, len %d\n", dir ? "send" : "recv", error ? error->message : "-", length); #ifdef PRINT_VERBOSE int i; @@ -61,60 +61,69 @@ static void usb_print_packet(int dir, int rv, const unsigned char *data, int len } #endif -static int usb_recv( - vfs301_dev_t *dev, - struct libusb_device_handle *devh, unsigned char endpoint, int max_bytes) +static void usb_recv(FpDeviceVfs301 *dev, guint8 endpoint, int max_bytes, FpiUsbTransfer **out, GError **error) { - g_assert(max_bytes <= sizeof(dev->recv_buf)); + GError *err = NULL; + g_autoptr(FpiUsbTransfer) transfer = NULL; + + /* XXX: This function swallows any transfer errors, that is obviously + * quite bad (it used to assert on no-error)! */ + + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk (transfer, endpoint, max_bytes); + + fpi_usb_transfer_submit_sync (transfer, VFS301_DEFAULT_WAIT_TIMEOUT, &err); - int r = libusb_bulk_transfer( - devh, endpoint, - dev->recv_buf, max_bytes, - &dev->recv_len, VFS301_DEFAULT_WAIT_TIMEOUT - ); #ifdef DEBUG - usb_print_packet(0, r, dev->recv_buf, dev->recv_len); + usb_print_packet(0, err, transfer->buffer, transfer->actual_length); #endif + if (err) { + if (!error) + g_warning("Unhandled receive error: %s", err->message); + g_propagate_error (error, err); + } - if (r < 0) - return r; - return 0; + if (out) + *out = g_steal_pointer (&transfer); } -static int usb_send( - struct libusb_device_handle *devh, const unsigned char *data, int length) +static void usb_send(FpDeviceVfs301 *dev, const guint8 *data, gssize length, GError **error) { - int transferred = 0; + GError *err = NULL; + g_autoptr(FpiUsbTransfer) transfer = NULL; - int r = libusb_bulk_transfer( - devh, VFS301_SEND_ENDPOINT, - (unsigned char *)data, length, &transferred, VFS301_DEFAULT_WAIT_TIMEOUT - ); + /* XXX: This function swallows any transfer errors, that is obviously + * quite bad (it used to assert on no-error)! */ + + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk_full (transfer, VFS301_SEND_ENDPOINT, (guint8*) data, length, g_free); + + fpi_usb_transfer_submit_sync (transfer, VFS301_DEFAULT_WAIT_TIMEOUT, &err); #ifdef DEBUG - usb_print_packet(1, r, data, length); + usb_print_packet(1, err, data, length); #endif - g_assert(r == 0); - - if (r < 0) - return r; - if (transferred < length) - return r; - - return 0; + if (err) { + g_warning ("Error while sending data, continuing anyway: %s", err->message); + g_propagate_error (error, err); + } } /************************** OUT MESSAGES GENERATION ***************************/ -static void vfs301_proto_generate_0B(int subtype, unsigned char *data, int *len) +static guint8 * vfs301_proto_generate_0B(int subtype, gssize *len) { + guint8 *res = g_malloc0 (39); + guint8 *data = res; + *data = 0x0B; *len = 1; data++; - memset(data, 0, 39); *len += 38; data[20] = subtype; @@ -125,40 +134,50 @@ static void vfs301_proto_generate_0B(int subtype, unsigned char *data, int *len) break; case 0x05: data[34] = 0xAB; - len++; + /* NOTE: There was a len++ here, which could never do anything */ break; default: g_assert_not_reached(); break; } + + return res; } #define HEX_TO_INT(c) \ (((c) >= '0' && (c) <= '9') ? ((c) - '0') : ((c) - 'A' + 10)) -static void translate_str(const char **srcL, unsigned char *data, int *len) +static guint8 * translate_str(const char **srcL, gssize *len) { + guint8 *res = NULL; + guint8 *dst; + const char **src_pos; const char *src; - unsigned char *dataOrig = data; + gssize src_len = 0; - while (*srcL != NULL) { - src = *srcL; - while (*src != '\0') { - g_assert(*src != '\0'); - g_assert(*(src +1) != '\0'); - *data = (unsigned char)((HEX_TO_INT(*src) << 4) | (HEX_TO_INT(*(src + 1)))); + for (src_pos = srcL; *src_pos; src_pos++) { + gint tmp; - data++; - src += 2; - } - - srcL++; + src = *src_pos; + tmp = strlen(src); + g_assert (tmp % 2 == 0); + src_len += tmp; } - *len = data - dataOrig; + *len = src_len / 2; + res = g_malloc0 (*len); + dst = res; + + for (src_pos = srcL; *src_pos; src_pos++) { + for (src = *src_pos; *src; src += 2, dst += 1) { + *dst = (guint8) ((HEX_TO_INT (src[0]) << 4) | (HEX_TO_INT (src[1]))); + } + } + + return res; } -static void vfs301_proto_generate(int type, int subtype, unsigned char *data, int *len) +static guint8 *vfs301_proto_generate(int type, int subtype, gssize *len) { switch (type) { case 0x01: @@ -173,11 +192,15 @@ static void vfs301_proto_generate(int type, int subtype, unsigned char *data, in case 0x17: case 0x19: case 0x1A: - *data = type; - *len = 1; + { + guint8 *data = g_malloc0 (1); + *data = type; + *len = 1; + return data; + } break; case 0x0B: - vfs301_proto_generate_0B(subtype, data, len); + return vfs301_proto_generate_0B(subtype, len); break; case 0x02D0: { @@ -190,49 +213,57 @@ static void vfs301_proto_generate(int type, int subtype, unsigned char *data, in vfs301_02D0_06, vfs301_02D0_07, }; - g_assert((int)subtype <= (int)(sizeof(dataLs) / sizeof(dataLs[0]))); - translate_str(dataLs[subtype - 1], data, len); + g_assert((int)subtype <= G_N_ELEMENTS (dataLs)); + return translate_str(dataLs[subtype - 1], len); } break; case 0x0220: switch (subtype) { case 1: - translate_str(vfs301_0220_01, data, len); + return translate_str(vfs301_0220_01, len); break; case 2: - translate_str(vfs301_0220_02, data, len); + return translate_str(vfs301_0220_02, len); break; case 3: - translate_str(vfs301_0220_03, data, len); + return translate_str(vfs301_0220_03, len); break; case 0xFA00: case 0x2C01: - case 0x5E01: - translate_str(vfs301_next_scan_template, data, len); - unsigned char *field = data + *len - (sizeof(S4_TAIL) - 1) / 2 - 4; + case 0x5E01: { + guint8 *data; + guint8 *field; - g_assert(*field == 0xDE); - g_assert(*(field + 1) == 0xAD); - g_assert(*(field + 2) == 0xDE); - g_assert(*(field + 3) == 0xAD); + data = translate_str(vfs301_next_scan_template, len); + field = data + *len - (sizeof(S4_TAIL) - 1) / 2 - 4; - *field = (unsigned char)((subtype >> 8) & 0xFF); - *(field + 1) = (unsigned char)(subtype & 0xFF); - *(field + 2) = *field; - *(field + 3) = *(field + 1); + g_assert (field >= data && field < data + *len); + g_assert(field[0] == 0xDE); + g_assert(field[1] == 0xAD); + g_assert(field[2] == 0xDE); + g_assert(field[3] == 0xAD); + + field[0] = (guint8)((subtype >> 8) & 0xFF); + field[1] = (guint8)(subtype & 0xFF); + field[2] = field[0]; + field[3] = field[1]; + + return data; break; + } default: - g_assert(0); + g_assert_not_reached(); break; } break; case 0x06: - g_assert_not_reached(); - break; default: - g_assert_not_reached(); break; } + + g_assert_not_reached(); + *len = 0; + return NULL; } /************************** SCAN IMAGE PROCESSING *****************************/ @@ -256,10 +287,10 @@ static int img_is_finished_scan(fp_line_t *lines, int no_lines) } #endif -static int scanline_diff(const unsigned char *scanlines, int prev, int cur) +static int scanline_diff(const guint8 *scanlines, int prev, int cur) { - const unsigned char *line1 = scanlines + prev * VFS301_FP_OUTPUT_WIDTH; - const unsigned char *line2 = scanlines + cur * VFS301_FP_OUTPUT_WIDTH; + const guint8 *line1 = scanlines + prev * VFS301_FP_OUTPUT_WIDTH; + const guint8 *line2 = scanlines + cur * VFS301_FP_OUTPUT_WIDTH; int i; int diff; @@ -285,11 +316,10 @@ static int scanline_diff(const unsigned char *scanlines, int prev, int cur) } /** Transform the input data to a normalized fingerprint scan */ -void vfs301_extract_image( - vfs301_dev_t *vfs, unsigned char *output, int *output_height +void vfs301_extract_image(FpDeviceVfs301 *vfs, guint8 *output, int *output_height ) { - const unsigned char *scanlines = vfs->scanline_buf; + const guint8 *scanlines = vfs->scanline_buf; int last_line; int i; @@ -318,15 +348,13 @@ void vfs301_extract_image( } } -static int img_process_data( - int first_block, vfs301_dev_t *dev, const unsigned char *buf, int len -) +static int img_process_data(int first_block, FpDeviceVfs301 *dev, const guint8 *buf, int len) { vfs301_line_t *lines = (vfs301_line_t*)buf; int no_lines = len / sizeof(vfs301_line_t); int i; /*int no_nonempty;*/ - unsigned char *cur_line; + guint8 *cur_line; int last_img_height; #ifdef SCAN_FINISH_DETECTION int finished_scan; @@ -340,8 +368,7 @@ static int img_process_data( dev->scanline_count += no_lines; } - dev->scanline_buf = realloc(dev->scanline_buf, dev->scanline_count * VFS301_FP_OUTPUT_WIDTH); - g_assert(dev->scanline_buf != NULL); + dev->scanline_buf = g_realloc(dev->scanline_buf, dev->scanline_count * VFS301_FP_OUTPUT_WIDTH); for (cur_line = dev->scanline_buf + last_img_height * VFS301_FP_OUTPUT_WIDTH, i = 0; i < no_lines; @@ -365,27 +392,24 @@ static int img_process_data( /************************** PROTOCOL STUFF ************************************/ -static unsigned char usb_send_buf[0x2000]; - #define USB_RECV(from, len) \ - usb_recv(dev, devh, from, len) + usb_recv(dev, from, len, NULL, NULL) #define USB_SEND(type, subtype) \ { \ - int len; \ - vfs301_proto_generate(type, subtype, usb_send_buf, &len); \ - usb_send(devh, usb_send_buf, len); \ + const guint8 *data; \ + gssize len; \ + data = vfs301_proto_generate(type, subtype, &len); \ + usb_send(dev, data, len, NULL); \ } #define RAW_DATA(x) x, sizeof(x) #define IS_VFS301_FP_SEQ_START(b) ((b[0] == 0x01) && (b[1] == 0xfe)) -static int vfs301_proto_process_data(int first_block, vfs301_dev_t *dev) +static int vfs301_proto_process_data(FpDeviceVfs301 *dev, int first_block, const guint8 *buf, gint len) { int i; - const unsigned char *buf = dev->recv_buf; - int len = dev->recv_len; if (first_block) { g_assert(len >= VFS301_FP_FRAME_SIZE); @@ -400,80 +424,86 @@ static int vfs301_proto_process_data(int first_block, vfs301_dev_t *dev) return img_process_data(first_block, dev, buf, len); } -void vfs301_proto_request_fingerprint( - struct libusb_device_handle *devh, vfs301_dev_t *dev) +void vfs301_proto_request_fingerprint(FpDeviceVfs301 *dev) { USB_SEND(0x0220, 0xFA00); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 000000000000 */ } -int vfs301_proto_peek_event( - struct libusb_device_handle *devh, vfs301_dev_t *dev) +int vfs301_proto_peek_event(FpDeviceVfs301 *dev) { + g_autoptr(GError) error = NULL; + g_autoptr(FpiUsbTransfer) transfer = NULL; + const char no_event[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const char got_event[] = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00}; USB_SEND(0x17, -1); - g_assert(USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 7) == 0); + usb_recv (dev, VFS301_RECEIVE_ENDPOINT_CTRL, 7, &transfer, &error); - if (memcmp(dev->recv_buf, no_event, sizeof(no_event)) == 0) { + /* XXX: This is obviously not a sane error handling! */ + g_assert (!error); + + if (memcmp(transfer->buffer, no_event, sizeof(no_event)) == 0) { return 0; - } else if (memcmp(dev->recv_buf, got_event, sizeof(no_event)) == 0) { + } else if (memcmp(transfer->buffer, got_event, sizeof(no_event)) == 0) { return 1; } else { g_assert_not_reached(); } } -#define VARIABLE_ORDER(a, b) \ +/* XXX: We sometimes need to receive data on from two endpoints at the same + * time. However, as this driver is currently all synchronous (yikes), + * we will run into timeouts randomly and need to then try again. + */ +#define PARALLEL_RECEIVE(e1, l1, e2, l2) \ { \ - int _rv = a;\ - b; \ - if (_rv == -7) \ - a; \ + g_autoptr(GError) error = NULL;\ + usb_recv(dev, e1, l1, NULL, &error); \ + usb_recv(dev, e2, l2, NULL, NULL); \ + if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT)) \ + usb_recv(dev, e1, l1, NULL, NULL); \ } -static void vfs301_proto_process_event_cb(struct libusb_transfer *transfer) +static void vfs301_proto_process_event_cb(FpiUsbTransfer *transfer, + FpDevice *device, + gpointer user_data, GError *error) { - vfs301_dev_t *dev = transfer->user_data; - struct libusb_device_handle *devh = transfer->dev_handle; + FpDeviceVfs301 *dev = user_data; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { + if (error) { + g_warning ("Error receiving data: %s", error->message); + g_error_free (error); dev->recv_progress = VFS301_FAILURE; - goto end; - } else if (transfer->actual_length < dev->recv_exp_amt) { + return; + } else if (transfer->actual_length < transfer->length) { /* TODO: process the data anyway? */ dev->recv_progress = VFS301_ENDED; - goto end; + return; } else { - dev->recv_len = transfer->actual_length; - if (!vfs301_proto_process_data(dev->recv_exp_amt == VFS301_FP_RECV_LEN_1, dev)) { + FpiUsbTransfer *new; + if (!vfs301_proto_process_data(dev, + transfer->length == VFS301_FP_RECV_LEN_1, + transfer->buffer, + transfer->actual_length)) { dev->recv_progress = VFS301_ENDED; - goto end; + return; } - dev->recv_exp_amt = VFS301_FP_RECV_LEN_2; - libusb_fill_bulk_transfer( - transfer, devh, VFS301_RECEIVE_ENDPOINT_DATA, - dev->recv_buf, dev->recv_exp_amt, - vfs301_proto_process_event_cb, dev, VFS301_FP_RECV_TIMEOUT); + new = fpi_usb_transfer_new (device); - if (libusb_submit_transfer(transfer) < 0) { - printf("cb::continue fail\n"); - dev->recv_progress = VFS301_FAILURE; - goto end; - } + fpi_usb_transfer_fill_bulk(new, VFS301_RECEIVE_ENDPOINT_DATA, VFS301_FP_RECV_LEN_2); + fpi_usb_transfer_submit(new, VFS301_FP_RECV_TIMEOUT, NULL, + vfs301_proto_process_event_cb, NULL); + fpi_usb_transfer_unref (new); return; } - -end: - libusb_free_transfer(transfer); } -void vfs301_proto_process_event_start( - struct libusb_device_handle *devh, vfs301_dev_t *dev) +void vfs301_proto_process_event_start(FpDeviceVfs301 *dev) { - struct libusb_transfer *transfer; + FpiUsbTransfer *transfer; /* * Notes: @@ -499,24 +529,16 @@ void vfs301_proto_process_event_start( USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 64); /* now read the fingerprint data, while there are some */ - transfer = fpi_usb_alloc(); + transfer = fpi_usb_transfer_new(FP_DEVICE (dev)); dev->recv_progress = VFS301_ONGOING; - dev->recv_exp_amt = VFS301_FP_RECV_LEN_1; - libusb_fill_bulk_transfer( - transfer, devh, VFS301_RECEIVE_ENDPOINT_DATA, - dev->recv_buf, dev->recv_exp_amt, - vfs301_proto_process_event_cb, dev, VFS301_FP_RECV_TIMEOUT); - - if (libusb_submit_transfer(transfer) < 0) { - libusb_free_transfer(transfer); - dev->recv_progress = VFS301_FAILURE; - return; - } + fpi_usb_transfer_fill_bulk (transfer, VFS301_RECEIVE_ENDPOINT_DATA, VFS301_FP_RECV_LEN_1); + fpi_usb_transfer_submit(transfer, VFS301_FP_RECV_TIMEOUT, NULL, + vfs301_proto_process_event_cb, NULL); + fpi_usb_transfer_unref(transfer); } -int /* vfs301_dev_t::recv_progress */ vfs301_proto_process_event_poll( - struct libusb_device_handle *devh, vfs301_dev_t *dev) +int vfs301_proto_process_event_poll(FpDeviceVfs301 *dev) { if (dev->recv_progress != VFS301_ENDED) return dev->recv_progress; @@ -526,21 +548,21 @@ int /* vfs301_dev_t::recv_progress */ vfs301_proto_process_event_poll( USB_SEND(0x04, -1); /* the following may come in random order, data may not come at all, don't * try for too long... */ - VARIABLE_ORDER( - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2), /* 1204 */ - USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 16384) + PARALLEL_RECEIVE( + VFS301_RECEIVE_ENDPOINT_CTRL, 2, /* 1204 */ + VFS301_RECEIVE_ENDPOINT_DATA, 16384 ); USB_SEND(0x0220, 2); - VARIABLE_ORDER( - USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 5760), /* seems to always come */ - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2) /* 0000 */ + PARALLEL_RECEIVE( + VFS301_RECEIVE_ENDPOINT_DATA, 5760, /* seems to always come */ + VFS301_RECEIVE_ENDPOINT_CTRL, 2 /* 0000 */ ); return dev->recv_progress; } -void vfs301_proto_init(struct libusb_device_handle *devh, vfs301_dev_t *dev) +void vfs301_proto_init(FpDeviceVfs301 *dev) { USB_SEND(0x01, -1); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 38); @@ -551,14 +573,14 @@ void vfs301_proto_init(struct libusb_device_handle *devh, vfs301_dev_t *dev) USB_SEND(0x19, -1); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 64); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 4); /* 6BB4D0BC */ - usb_send(devh, RAW_DATA(vfs301_06_1)); + usb_send(dev, RAW_DATA(vfs301_06_1), NULL); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ USB_SEND(0x01, -1); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 38); USB_SEND(0x1A, -1); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - usb_send(devh, RAW_DATA(vfs301_06_2)); + usb_send(dev, RAW_DATA(vfs301_06_2), NULL); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ USB_SEND(0x0220, 1); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ @@ -567,7 +589,7 @@ void vfs301_proto_init(struct libusb_device_handle *devh, vfs301_dev_t *dev) USB_SEND(0x1A, -1); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - usb_send(devh, RAW_DATA(vfs301_06_3)); + usb_send(dev, RAW_DATA(vfs301_06_3), NULL); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ USB_SEND(0x01, -1); @@ -593,29 +615,29 @@ void vfs301_proto_init(struct libusb_device_handle *devh, vfs301_dev_t *dev) USB_SEND(0x02D0, 7); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 832); - usb_send(devh, RAW_DATA(vfs301_12)); + usb_send(dev, RAW_DATA(vfs301_12), NULL); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ USB_SEND(0x1A, -1); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - usb_send(devh, RAW_DATA(vfs301_06_2)); + usb_send(dev, RAW_DATA(vfs301_06_2), NULL); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ USB_SEND(0x0220, 2); - VARIABLE_ORDER( - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2), /* 0000 */ - USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 5760) + PARALLEL_RECEIVE( + VFS301_RECEIVE_ENDPOINT_CTRL, 2, /* 0000 */ + VFS301_RECEIVE_ENDPOINT_DATA, 5760 ); USB_SEND(0x1A, -1); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - usb_send(devh, RAW_DATA(vfs301_06_1)); + usb_send(dev, RAW_DATA(vfs301_06_1), NULL); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ USB_SEND(0x1A, -1); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - usb_send(devh, RAW_DATA(vfs301_06_4)); + usb_send(dev, RAW_DATA(vfs301_06_4), NULL); USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - usb_send(devh, RAW_DATA(vfs301_24)); /* turns on white */ + usb_send(dev, RAW_DATA(vfs301_24), NULL); /* turns on white */ USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ USB_SEND(0x01, -1); @@ -626,6 +648,6 @@ void vfs301_proto_init(struct libusb_device_handle *devh, vfs301_dev_t *dev) USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 5760); } -void vfs301_proto_deinit(struct libusb_device_handle *devh, vfs301_dev_t *dev) +void vfs301_proto_deinit(FpDeviceVfs301 *dev) { } diff --git a/meson.build b/meson.build index f963fc89..afc6b810 100644 --- a/meson.build +++ b/meson.build @@ -51,7 +51,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101' ] +default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301' ] all_drivers = default_drivers + virtual_drivers From 043b31df70da048f969952d7d995a15652f25c7c Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 9 Jul 2019 20:31:12 +0200 Subject: [PATCH 37/73] vfs0050: Port vfs0050 driver to new API --- libfprint/drivers/vfs0050.c | 616 ++++++++++++++++-------------------- libfprint/drivers/vfs0050.h | 16 +- meson.build | 2 +- 3 files changed, 287 insertions(+), 347 deletions(-) diff --git a/libfprint/drivers/vfs0050.c b/libfprint/drivers/vfs0050.c index b2f8395e..aa47ec44 100644 --- a/libfprint/drivers/vfs0050.c +++ b/libfprint/drivers/vfs0050.c @@ -22,164 +22,136 @@ #include "drivers_api.h" #include "vfs0050.h" +G_DEFINE_TYPE (FpDeviceVfs0050, fpi_device_vfs0050, FP_TYPE_IMAGE_DEVICE) + /* USB functions */ /* Callback for async_write */ -static void async_write_callback(struct libusb_transfer *transfer) +static void async_write_callback(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - - int transferred = transfer->actual_length, error = - transfer->status, len = transfer->length; - - if (error != 0) { - fp_err("USB write transfer: %s", libusb_error_name(error)); - fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); + if (error) { + fp_err("USB write transfer: %s", error->message); + fpi_ssm_mark_failed(transfer->ssm, error); return; } - if (transferred != len) { - fp_err("Written only %d of %d bytes", transferred, len); - fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); - return; - } - - fpi_ssm_next_state(ssm); + fpi_ssm_next_state(transfer->ssm); } /* Send data to EP1, the only out endpoint */ static void -async_write(fpi_ssm *ssm, - struct fp_img_dev *dev, +async_write(FpiSsm *ssm, + FpDevice *dev, void *data, int len) { - struct libusb_device_handle *usb_dev = fpi_dev_get_usb_dev(FP_DEV(dev)); - struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiUsbTransfer *transfer; - vdev->transfer = fpi_usb_alloc(); - vdev->transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; - libusb_fill_bulk_transfer(vdev->transfer, usb_dev, 0x01, data, len, - async_write_callback, ssm, VFS_USB_TIMEOUT); - libusb_submit_transfer(vdev->transfer); + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + fpi_usb_transfer_fill_bulk_full(transfer, 0x01, data, len, NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit(transfer, VFS_USB_TIMEOUT, NULL, + async_write_callback, NULL); + fpi_usb_transfer_unref(transfer); } /* Callback for async_read */ -static void async_read_callback(struct libusb_transfer *transfer) +static void async_read_callback(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - - int transferred = transfer->actual_length, error = - transfer->status, len = transfer->length; int ep = transfer->endpoint; - if (error != 0) { + if (error) { fp_err("USB read transfer on endpoint %d: %s", ep - 0x80, - libusb_error_name(error)); - fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); + error->message); + fpi_ssm_mark_failed(transfer->ssm, error); return; } - if (transferred != len) { - fp_err("Received %d instead of %d bytes", transferred, len); - fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); - return; - } - - fpi_ssm_next_state(ssm); + fpi_ssm_next_state(transfer->ssm); } -/* Receive data from the given ep and compare with expected */ +/* Receive data from the given ep and either discard or fill the given buffer */ static void -async_read(fpi_ssm *ssm, - struct fp_img_dev *dev, +async_read(FpiSsm *ssm, + FpDevice *dev, int ep, void *data, int len) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct libusb_device_handle *usb_dev = fpi_dev_get_usb_dev(FP_DEV(idev)); - struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev)); + FpiUsbTransfer *transfer; + GDestroyNotify free_func = NULL; - ep |= LIBUSB_ENDPOINT_IN; + ep |= FPI_USB_ENDPOINT_IN; - vdev->transfer = fpi_usb_alloc(); - vdev->transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + + if (data == NULL) { + data = g_malloc0 (len); + free_func = g_free; + } /* 0x83 is the only interrupt endpoint */ if (ep == EP3_IN) - libusb_fill_interrupt_transfer(vdev->transfer, usb_dev, ep, data, - len, async_read_callback, ssm, - VFS_USB_TIMEOUT); + fpi_usb_transfer_fill_interrupt_full(transfer, ep, data, len, free_func); else - libusb_fill_bulk_transfer(vdev->transfer, usb_dev, ep, data, len, - async_read_callback, ssm, - VFS_USB_TIMEOUT); - libusb_submit_transfer(vdev->transfer); + fpi_usb_transfer_fill_bulk_full(transfer, ep, data, len, free_func); + + fpi_usb_transfer_submit(transfer, VFS_USB_TIMEOUT, NULL, + async_read_callback, NULL); + fpi_usb_transfer_unref(transfer); } -/* Callback for async_read */ -static void async_abort_callback(struct libusb_transfer *transfer) +/* Callback for async_abort */ +static void async_abort_callback(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - - int transferred = transfer->actual_length, error = transfer->status; int ep = transfer->endpoint; /* In normal case endpoint is empty */ - if (error == LIBUSB_TRANSFER_TIMED_OUT) { - fpi_ssm_next_state(ssm); + if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT)) { + g_free (error); + fpi_ssm_next_state(transfer->ssm); return; } - if (error != 0) { - fp_err("USB write transfer: %s", libusb_error_name(error)); - fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); + if (error) { + fp_err("USB write transfer: %s", error->message); + fpi_ssm_mark_failed(transfer->ssm, error); return; } /* Don't stop process, only print warning */ - if (transferred > 0) - fp_warn("Endpoint %d had extra %d bytes", ep - 0x80, - transferred); + fp_warn("Endpoint %d had extra %zd bytes readable", ep - 0x80, + transfer->actual_length); - fpi_ssm_jump_to_state(ssm, fpi_ssm_get_cur_state(ssm)); + fpi_ssm_jump_to_state(transfer->ssm, + fpi_ssm_get_cur_state(transfer->ssm)); } -/* Receive data from the given ep and compare with expected */ -static void async_abort(fpi_ssm *ssm, int ep) +/* Receive data from the given ep; continues to the next state once no + * more data is available. Otherwise the current state is repeated. */ +static void async_abort(FpDevice *dev, FpiSsm *ssm, int ep) { - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct libusb_device_handle *usb_dev = fpi_dev_get_usb_dev(FP_DEV(idev)); - struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev)); + FpiUsbTransfer *transfer; - int len = VFS_USB_BUFFER_SIZE; - unsigned char *data = g_malloc(VFS_USB_BUFFER_SIZE); + ep |= FPI_USB_ENDPOINT_IN; - ep |= LIBUSB_ENDPOINT_IN; - - vdev->transfer = fpi_usb_alloc(); - vdev->transfer->flags |= - LIBUSB_TRANSFER_FREE_TRANSFER | LIBUSB_TRANSFER_FREE_BUFFER; + transfer = fpi_usb_transfer_new (dev); /* 0x83 is the only interrupt endpoint */ if (ep == EP3_IN) - libusb_fill_interrupt_transfer(vdev->transfer, usb_dev, ep, data, - len, async_abort_callback, ssm, - VFS_USB_ABORT_TIMEOUT); + fpi_usb_transfer_fill_interrupt (transfer, ep, VFS_USB_BUFFER_SIZE); else - libusb_fill_bulk_transfer(vdev->transfer, usb_dev, ep, data, len, - async_abort_callback, ssm, - VFS_USB_ABORT_TIMEOUT); - libusb_submit_transfer(vdev->transfer); + fpi_usb_transfer_fill_bulk (transfer, ep, VFS_USB_BUFFER_SIZE); + + fpi_usb_transfer_submit(transfer, VFS_USB_ABORT_TIMEOUT, NULL, + async_abort_callback, NULL); + fpi_usb_transfer_unref(transfer); } /* Image processing functions */ @@ -233,7 +205,7 @@ static struct fpi_line_asmbl_ctx assembling_ctx = { }; /* Processes image before submitting */ -static struct fp_img *prepare_image(struct vfs_dev_t *vdev) +static FpImage *prepare_image(FpDeviceVfs0050 *vdev) { int height = vdev->bytes / VFS_LINE_SIZE; @@ -258,152 +230,143 @@ static struct fp_img *prepare_image(struct vfs_dev_t *vdev) lines = g_slist_prepend(lines, vdev->lines_buffer + i); /* Perform line assembling */ - struct fp_img *img = fpi_assemble_lines(&assembling_ctx, lines, height); + FpImage *img = fpi_assemble_lines(&assembling_ctx, lines, height); g_slist_free(lines); return img; } /* Processes and submits image after fingerprint received */ -static void submit_image(struct fp_img_dev *idev) +static void submit_image(FpDeviceVfs0050 *self) { - struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev)); + FpImageDevice *idev = FP_IMAGE_DEVICE(self); /* We were not asked to submit image actually */ - if (!vdev->active) + if (!self->active) return; - struct fp_img *img = prepare_image(vdev); + FpImage *img = prepare_image(self); if (!img) - fpi_imgdev_abort_scan(idev, FP_VERIFY_RETRY_TOO_SHORT); + fpi_image_device_retry_scan(idev, FP_DEVICE_RETRY_TOO_SHORT); else - fpi_imgdev_image_captured(idev, img); + fpi_image_device_image_captured(idev, img); /* Finger not on the scanner */ - fpi_imgdev_report_finger_status(idev, 0); + fpi_image_device_report_finger_status(idev, FALSE); } /* Proto functions */ /* SSM loop for clear_ep2 */ static void -clear_ep2_ssm(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +clear_ep2_ssm(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *idev = user_data; - - short result; char command04 = 0x04; switch (fpi_ssm_get_cur_state(ssm)) { case SUBSM1_COMMAND_04: - async_write(ssm, idev, &command04, sizeof(command04)); + async_write(ssm, dev, &command04, sizeof(command04)); break; case SUBSM1_RETURN_CODE: - async_read(ssm, idev, 1, &result, sizeof(result)); + async_read(ssm, dev, 1, NULL, 2); break; case SUBSM1_ABORT_2: - async_abort(ssm, 2); + async_abort(dev, ssm, 2); break; default: fp_err("Unknown SUBSM1 state"); - fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } } /* Send command to clear EP2 */ static void -clear_ep2(fpi_ssm *ssm, - struct fp_img_dev *idev) +clear_ep2(FpDevice *dev, + FpiSsm *ssm) { - fpi_ssm *subsm = - fpi_ssm_new(FP_DEV(idev), clear_ep2_ssm, SUBSM1_STATES, idev); + FpiSsm *subsm = + fpi_ssm_new(dev, clear_ep2_ssm, SUBSM1_STATES, NULL); fpi_ssm_start_subsm(ssm, subsm); } -static void send_control_packet_ssm(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void send_control_packet_ssm(FpiSsm *ssm, FpDevice *dev, + void *user_data) { - struct fp_img_dev *idev = user_data; - struct vfs_dev_t *vdev = FP_INSTANCE_DATA(_dev); - - short result; - unsigned char *commit_result = NULL; + FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050(dev); switch (fpi_ssm_get_cur_state(ssm)) { case SUBSM2_SEND_CONTROL: - async_write(ssm, idev, vdev->control_packet, VFS_CONTROL_PACKET_SIZE); + async_write(ssm, dev, self->control_packet, + VFS_CONTROL_PACKET_SIZE); break; case SUBSM2_RETURN_CODE: - async_read(ssm, idev, 1, &result, sizeof(result)); + async_read(ssm, dev, 1, NULL, 2); break; case SUBSM2_SEND_COMMIT: /* next_receive_* packets could be sent only in pair */ - if (vdev->control_packet == next_receive_1) { - vdev->control_packet = next_receive_2; + if (self->control_packet == next_receive_1) { + self->control_packet = next_receive_2; fpi_ssm_jump_to_state(ssm, SUBSM2_SEND_CONTROL); break; } /* commit_out in Windows differs in each commit, but I send the same each time */ - async_write(ssm, idev, commit_out, sizeof(commit_out)); + async_write(ssm, dev, commit_out, sizeof(commit_out)); break; case SUBSM2_COMMIT_RESPONSE: - commit_result = g_malloc(VFS_COMMIT_RESPONSE_SIZE); - async_read(ssm, idev, 1, commit_result, VFS_COMMIT_RESPONSE_SIZE); + async_read(ssm, dev, 1, NULL, VFS_COMMIT_RESPONSE_SIZE); break; case SUBSM2_READ_EMPTY_INTERRUPT: - /* I don't know how to check result, it could be different */ - g_free(commit_result); - - async_read(ssm, idev, 3, vdev->interrupt, VFS_INTERRUPT_SIZE); + /* I don't know how to check result, it could be different + * NOTE: I guess this comment relates to the above read. */ + async_read(ssm, dev, 3, self->interrupt, VFS_INTERRUPT_SIZE); break; case SUBSM2_ABORT_3: /* Check that interrupt is empty */ if (memcmp - (vdev->interrupt, empty_interrupt, VFS_INTERRUPT_SIZE)) { + (self->interrupt, empty_interrupt, VFS_INTERRUPT_SIZE)) { fp_err("Unknown SUBSM2 state"); - fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); break; } - async_abort(ssm, 3); + async_abort(dev, ssm, 3); break; case SUBSM2_CLEAR_EP2: /* After turn_on Windows doesn't clear EP2 */ - if (vdev->control_packet != turn_on) - clear_ep2(ssm, idev); + if (self->control_packet != turn_on) + clear_ep2(dev, ssm); else fpi_ssm_next_state(ssm); break; default: fp_err("Unknown SUBSM2 state"); - fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } } /* Send device state control packet */ static void -send_control_packet(fpi_ssm *ssm, - struct fp_img_dev *idev) +send_control_packet(FpiSsm *ssm, + FpDevice *dev) { - fpi_ssm *subsm = - fpi_ssm_new(FP_DEV(idev), send_control_packet_ssm, SUBSM2_STATES, idev); + FpiSsm *subsm = + fpi_ssm_new(dev, send_control_packet_ssm, + SUBSM2_STATES, NULL); fpi_ssm_start_subsm(ssm, subsm); } /* Clears all fprint data */ -static void clear_data(struct vfs_dev_t *vdev) +static void clear_data(FpDeviceVfs0050 *vdev) { g_free(vdev->lines_buffer); vdev->lines_buffer = NULL; @@ -411,35 +374,24 @@ static void clear_data(struct vfs_dev_t *vdev) } /* After receiving interrupt from EP3 */ -static void interrupt_callback(struct libusb_transfer *transfer) +static void interrupt_callback(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev)); + FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050(device); + char *interrupt = transfer->buffer; - char *interrupt = vdev->interrupt; - int error = transfer->status, transferred = transfer->actual_length; - - vdev->wait_interrupt = 0; - - /* When we have cancelled transfer, error is ok actually */ - if (!vdev->active && error == LIBUSB_TRANSFER_CANCELLED) - return; - - if (error != 0) { - fp_err("USB read interrupt transfer: %s", - libusb_error_name(error)); - fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); + /* we expect a cancellation error when the device is deactivating + * go into the SSM_CLEAR_EP2 state in that case. */ + if (!self->active && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + g_error_free (error); + fpi_ssm_jump_to_state(transfer->ssm, SSM_CLEAR_EP2); return; } - /* Interrupt size is VFS_INTERRUPT_SIZE bytes in all known cases */ - if (transferred != VFS_INTERRUPT_SIZE) { - fp_err("Unknown interrupt size %d", transferred); - /* Abort ssm */ - fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); + if (error) { + fp_err("USB read interrupt transfer: %s", + error->message); + fpi_ssm_mark_failed(transfer->ssm, error); return; } @@ -448,7 +400,7 @@ static void interrupt_callback(struct libusb_transfer *transfer) memcmp(interrupt, interrupt2, VFS_INTERRUPT_SIZE) == 0 || memcmp(interrupt, interrupt3, VFS_INTERRUPT_SIZE) == 0) { /* Go to the next ssm stage */ - fpi_ssm_next_state(ssm); + fpi_ssm_next_state(transfer->ssm); return; } @@ -457,7 +409,7 @@ static void interrupt_callback(struct libusb_transfer *transfer) fp_warn("Finger is already on the scanner"); /* Go to the next ssm stage */ - fpi_ssm_next_state(ssm); + fpi_ssm_next_state(transfer->ssm); return; } @@ -467,325 +419,311 @@ static void interrupt_callback(struct libusb_transfer *transfer) interrupt[3] & 0xff, interrupt[4] & 0xff); /* Abort ssm */ - fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } -static void receive_callback(struct libusb_transfer *transfer) +static void receive_callback(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev)); + FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050(device); - int transferred = transfer->actual_length, error = transfer->status; + if (error && !g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT)) { + fp_err("USB read transfer: %s", error->message); - if (error != 0 && error != LIBUSB_TRANSFER_TIMED_OUT) { - fp_err("USB read transfer: %s", libusb_error_name(error)); - - fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, error); return; } + if (error) + g_error_free (error); /* Check if fingerprint data is over */ - if (transferred == 0) { - fpi_ssm_next_state(ssm); + if (transfer->actual_length == 0) { + fpi_ssm_next_state(transfer->ssm); } else { - vdev->bytes += transferred; + self->bytes += transfer->actual_length; /* We need more data */ - fpi_ssm_jump_to_state(ssm, fpi_ssm_get_cur_state(ssm)); + fpi_ssm_jump_to_state(transfer->ssm, + fpi_ssm_get_cur_state(transfer->ssm)); } } -/* Stub to keep SSM alive when waiting an interrupt */ -static void -wait_interrupt(struct fp_dev *dev, - void *data) -{ - fpi_ssm *ssm = data; - struct vfs_dev_t *vdev = FP_INSTANCE_DATA(dev); - - /* Keep sleeping while this flag is on */ - if (vdev->wait_interrupt) - fpi_ssm_jump_to_state(ssm, fpi_ssm_get_cur_state(ssm)); -} - /* SSM stub to prepare device to another scan after orange light was on */ static void -another_scan(struct fp_dev *dev, +another_scan(FpDevice *dev, void *data) { - fpi_ssm *ssm = data; + FpiSsm *ssm = data; fpi_ssm_jump_to_state(ssm, SSM_TURN_ON); } /* Main SSM loop */ -static void activate_ssm(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_ssm(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *idev = user_data; - struct libusb_device_handle *usb_dev = fpi_dev_get_usb_dev(FP_DEV(idev)); - struct vfs_dev_t *vdev = FP_INSTANCE_DATA(_dev); + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); + FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050(dev); switch (fpi_ssm_get_cur_state(ssm)) { case SSM_INITIAL_ABORT_1: - async_abort(ssm, 1); + async_abort(dev, ssm, 1); break; case SSM_INITIAL_ABORT_2: - async_abort(ssm, 2); + async_abort(dev, ssm, 2); break; case SSM_INITIAL_ABORT_3: - async_abort(ssm, 3); + async_abort(dev, ssm, 3); break; case SSM_CLEAR_EP2: - clear_ep2(ssm, idev); + clear_ep2(dev, ssm); break; case SSM_TURN_OFF: /* Set control_packet argument */ - vdev->control_packet = turn_off; + self->control_packet = turn_off; - send_control_packet(ssm, idev); + send_control_packet(ssm, dev); break; case SSM_TURN_ON: - if (!vdev->active) { + if (!self->active) { /* The only correct exit */ fpi_ssm_mark_completed(ssm); - if (vdev->need_report) { - fpi_imgdev_deactivate_complete(idev); - vdev->need_report = 0; + if (self->need_report) { + fpi_image_device_deactivate_complete(idev, + NULL); + self->need_report = 0; } break; } /* Set control_packet argument */ - vdev->control_packet = turn_on; + self->control_packet = turn_on; - send_control_packet(ssm, idev); + send_control_packet(ssm, dev); break; - case SSM_ASK_INTERRUPT: + case SSM_ASK_INTERRUPT: { + FpiUsbTransfer *transfer; /* Activated, light must be blinking now */ /* If we first time here, report that activate completed */ - if (vdev->need_report) { - fpi_imgdev_activate_complete(idev, 0); - vdev->need_report = 0; + if (self->need_report) { + fpi_image_device_activate_complete(idev, NULL); + self->need_report = 0; } /* Asynchronously enquire an interrupt */ - vdev->transfer = fpi_usb_alloc(); - vdev->transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; - libusb_fill_interrupt_transfer(vdev->transfer, usb_dev, 0x83, - vdev->interrupt, - VFS_INTERRUPT_SIZE, - interrupt_callback, ssm, 0); - libusb_submit_transfer(vdev->transfer); - - /* This flag could be turned off only in callback function */ - vdev->wait_interrupt = 1; + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_interrupt (transfer, 0x83, VFS_INTERRUPT_SIZE); + fpi_usb_transfer_submit (transfer, + 0, + fpi_device_get_cancellable (dev), + interrupt_callback, NULL); + fpi_usb_transfer_unref (transfer); /* I've put it here to be sure that data is cleared */ - clear_data(vdev); + clear_data(self); fpi_ssm_next_state(ssm); break; - + } case SSM_WAIT_INTERRUPT: - /* Check if user had interrupted the process */ - if (!vdev->active) { - libusb_cancel_transfer(vdev->transfer); - fpi_ssm_jump_to_state(ssm, SSM_CLEAR_EP2); - break; - } - - if (vdev->wait_interrupt) - fpi_timeout_add(VFS_SSM_TIMEOUT, wait_interrupt, _dev, ssm); + /* TODO: This state is unused at this point. When we + * are in this state, then a user cancellation will + * cause deactivation. In that case, the USB transfer + * is cancelled and the device is set to not be active. + * We then go into SSM_CLEAR_EP2 based on the + * cancellation. */ break; - case SSM_RECEIVE_FINGER: - if (vdev->memory == 0) { + case SSM_RECEIVE_FINGER: { + FpiUsbTransfer *transfer; + + if (self->memory == 0) { /* Initialize fingerprint buffer */ - g_free(vdev->lines_buffer); - vdev->memory = VFS_USB_BUFFER_SIZE; - vdev->lines_buffer = g_malloc(vdev->memory); - vdev->bytes = 0; + g_free(self->lines_buffer); + self->memory = VFS_USB_BUFFER_SIZE; + self->lines_buffer = g_malloc(self->memory); + self->bytes = 0; /* Finger is on the scanner */ - fpi_imgdev_report_finger_status(idev, 1); + fpi_image_device_report_finger_status(idev, TRUE); } /* Increase buffer size while it's insufficient */ - while (vdev->bytes + VFS_USB_BUFFER_SIZE > vdev->memory) { - vdev->memory <<= 1; - vdev->lines_buffer = - (struct vfs_line *)g_realloc(vdev->lines_buffer, - vdev->memory); + while (self->bytes + VFS_USB_BUFFER_SIZE > self->memory) { + self->memory <<= 1; + self->lines_buffer = + (struct vfs_line *)g_realloc(self->lines_buffer, + self->memory); } /* Receive chunk of data */ - vdev->transfer = fpi_usb_alloc(); - vdev->transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; - libusb_fill_bulk_transfer(vdev->transfer, usb_dev, 0x82, - (void *)vdev->lines_buffer + - vdev->bytes, VFS_USB_BUFFER_SIZE, - receive_callback, ssm, - VFS_USB_TIMEOUT); - libusb_submit_transfer(vdev->transfer); + transfer = fpi_usb_transfer_new (dev); + fpi_usb_transfer_fill_bulk_full(transfer, 0x82, + (void *)self->lines_buffer + self->bytes, + VFS_USB_BUFFER_SIZE, NULL); + transfer->ssm = ssm; + fpi_usb_transfer_submit(transfer, VFS_USB_TIMEOUT, NULL, + receive_callback, NULL); + fpi_usb_transfer_unref(transfer); break; - + } case SSM_SUBMIT_IMAGE: - submit_image(idev); - clear_data(vdev); + submit_image(self); + clear_data(self); /* Wait for probable vdev->active changing */ - fpi_timeout_add(VFS_SSM_TIMEOUT, fpi_ssm_next_state_timeout_cb, _dev, ssm); + fpi_device_add_timeout(dev, VFS_SSM_TIMEOUT, + fpi_ssm_next_state_timeout_cb, ssm); break; case SSM_NEXT_RECEIVE: - if (!vdev->active) { + if (!self->active) { /* It's the last scan */ fpi_ssm_jump_to_state(ssm, SSM_CLEAR_EP2); break; } /* Set control_packet argument */ - vdev->control_packet = next_receive_1; + self->control_packet = next_receive_1; - send_control_packet(ssm, idev); + send_control_packet(ssm, dev); break; case SSM_WAIT_ANOTHER_SCAN: /* Orange light is on now */ - fpi_timeout_add(VFS_SSM_ORANGE_TIMEOUT, another_scan, _dev, ssm); + fpi_device_add_timeout(dev, VFS_SSM_ORANGE_TIMEOUT, + another_scan, ssm); break; default: fp_err("Unknown state"); - fpi_imgdev_session_error(idev, -EIO); - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } } /* Driver functions */ /* Callback for dev_activate ssm */ -static void dev_activate_callback(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void dev_activate_callback(FpiSsm *ssm, FpDevice *dev, + void *user_data, GError *error) { - struct vfs_dev_t *vdev = FP_INSTANCE_DATA(_dev); + FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050(dev); - vdev->ssm_active = 0; + self->ssm_active = 0; + + if (error) { + g_warning ("Unhandled device activation error: %s", error->message); + g_error_free (error); + } fpi_ssm_free(ssm); } /* Activate device */ -static int dev_activate(struct fp_img_dev *idev) +static void dev_activate(FpImageDevice *idev) { - struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev)); + FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050(idev); /* Initialize flags */ - vdev->active = 1; - vdev->need_report = 1; - vdev->ssm_active = 1; + self->active = 1; + self->need_report = 1; + self->ssm_active = 1; - fpi_ssm *ssm = fpi_ssm_new(FP_DEV(idev), activate_ssm, SSM_STATES, idev); + FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(idev), activate_ssm, SSM_STATES, + idev); fpi_ssm_start(ssm, dev_activate_callback); - return 0; } /* Deactivate device */ -static void dev_deactivate(struct fp_img_dev *idev) +static void dev_deactivate(FpImageDevice *idev) { - struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev)); + FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050(idev); - if (!vdev->ssm_active) { - fpi_imgdev_deactivate_complete(idev); + if (!self->ssm_active) { + fpi_image_device_deactivate_complete(idev, NULL); return; } /* Initialize flags */ - vdev->active = 0; - vdev->need_report = 1; + self->active = 0; + self->need_report = 1; } /* Callback for dev_open ssm */ -static void dev_open_callback(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void dev_open_callback(FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { /* Notify open complete */ - fpi_imgdev_open_complete(user_data, 0); + fpi_image_device_open_complete(FP_IMAGE_DEVICE (dev), error); fpi_ssm_free(ssm); } /* Open device */ -static int dev_open(struct fp_img_dev *idev, unsigned long driver_data) +static void dev_open(FpImageDevice *idev) { - struct vfs_dev_t *vdev; + GError *error = NULL; /* Claim usb interface */ - int error = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(idev)), 0); - if (error < 0) { - /* Interface not claimed, return error */ - fp_err("could not claim interface 0"); - return error; + if (!g_usb_device_claim_interface (fpi_device_get_usb_device(FP_DEVICE(idev)), 0, 0, &error)) { + fpi_image_device_open_complete (idev, error); + return; } - /* Initialize private structure */ - vdev = g_malloc0(sizeof(struct vfs_dev_t)); - fp_dev_set_instance_data(FP_DEV(idev), vdev); - /* Clearing previous device state */ - fpi_ssm *ssm = fpi_ssm_new(FP_DEV(idev), activate_ssm, SSM_STATES, idev); + FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(idev), activate_ssm, SSM_STATES, NULL); fpi_ssm_start(ssm, dev_open_callback); - return 0; } /* Close device */ -static void dev_close(struct fp_img_dev *idev) +static void dev_close(FpImageDevice *idev) { - struct vfs_dev_t *vdev; + GError *error = NULL; + FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050(idev); - /* Release private structure */ - vdev = FP_INSTANCE_DATA(FP_DEV(idev)); - g_free(vdev); + clear_data(self); /* Release usb interface */ - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(idev)), 0); + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(idev)), + 0, 0, &error); /* Notify close complete */ - fpi_imgdev_close_complete(idev); + fpi_image_device_close_complete(idev, error); } /* Usb id table of device */ -static const struct usb_id id_table[] = { - {.vendor = 0x138a,.product = 0x0050}, - {0, 0, 0,}, +static const FpIdEntry id_table [ ] = { + {.vid = 0x138a, .pid = 0x0050, + }, + {.vid = 0, .pid = 0, .driver_data = 0}, }; -/* Device driver definition */ -struct fp_img_driver vfs0050_driver = { - /* Driver specification */ - .driver = { - .id = VFS0050_ID, - .name = FP_COMPONENT, - .full_name = "Validity VFS0050", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_SWIPE, - }, +static void fpi_device_vfs0050_init(FpDeviceVfs0050 *self) { +} +static void fpi_device_vfs0050_class_init(FpDeviceVfs0050Class *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); - /* Image specification */ - .flags = 0, - .img_width = VFS_IMAGE_WIDTH, - .img_height = -1, - .bz3_threshold = 24, + dev_class->id = "vfs0050"; + dev_class->full_name = "Validity VFS0050"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - /* Routine specification */ - .open = dev_open, - .close = dev_close, - .activate = dev_activate, - .deactivate = dev_deactivate, -}; + img_class->img_open = dev_open; + img_class->img_close = dev_close; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; + + img_class->bz3_threshold = 24; + + img_class->img_width = VFS_IMAGE_WIDTH; + img_class->img_height = -1; +} diff --git a/libfprint/drivers/vfs0050.h b/libfprint/drivers/vfs0050.h index 81407ddb..a6b315b3 100644 --- a/libfprint/drivers/vfs0050.h +++ b/libfprint/drivers/vfs0050.h @@ -17,6 +17,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#pragma once + +#include "fpi-image-device.h" + /* Timeout for all send/recv operations, except interrupt waiting and abort */ #define VFS_USB_TIMEOUT 100 /* Timeout for usb abort */ @@ -74,7 +78,9 @@ struct vfs_line { } __attribute__ ((__packed__)); /* The main driver structure */ -struct vfs_dev_t { +struct _FpDeviceVfs0050 { + FpImageDevice parent; + /* One if we were asked to read fingerprint, zero otherwise */ char active; @@ -84,15 +90,9 @@ struct vfs_dev_t { /* For dev_deactivate to check whether ssm still running or not */ char ssm_active; - /* Current async transfer */ - struct libusb_transfer *transfer; - /* Should we call fpi_imgdev_activate_complete or fpi_imgdev_deactivate_complete */ char need_report; - /* Should we wait more for interrupt */ - char wait_interrupt; - /* Received fingerprint raw lines */ struct vfs_line *lines_buffer; @@ -106,6 +106,8 @@ struct vfs_dev_t { unsigned char interrupt[8]; }; +G_DECLARE_FINAL_TYPE (FpDeviceVfs0050, fpi_device_vfs0050, FPI, DEVICE_VFS0050, FpImageDevice) + /* SSM states for clear_ep2 */ enum SUBSM1 { SUBSM1_COMMAND_04, diff --git a/meson.build b/meson.build index afc6b810..33eb68e4 100644 --- a/meson.build +++ b/meson.build @@ -51,7 +51,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301' ] +default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050' ] all_drivers = default_drivers + virtual_drivers From 431ed7210bd5c75a4e6810a73c3526ee366b1f39 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 9 Jul 2019 21:13:44 +0200 Subject: [PATCH 38/73] etes603: Port etes603 driver to new API --- libfprint/drivers/etes603.c | 854 +++++++++++++++++------------------- meson.build | 2 +- 2 files changed, 412 insertions(+), 444 deletions(-) diff --git a/libfprint/drivers/etes603.c b/libfprint/drivers/etes603.c index f82fb05f..a97d40e0 100644 --- a/libfprint/drivers/etes603.c +++ b/libfprint/drivers/etes603.c @@ -148,67 +148,73 @@ /* This structure must be packed because it is a the raw message sent. */ struct egis_msg { - uint8_t magic[5]; /* out: 'EGIS' 0x09 / in: 'SIGE' 0x0A */ - uint8_t cmd; + guint8 magic[5]; /* out: 'EGIS' 0x09 / in: 'SIGE' 0x0A */ + guint8 cmd; union { struct { - uint8_t nb; - uint8_t regs[REG_MAX]; + guint8 nb; + guint8 regs[REG_MAX]; } egis_readreg; struct { - uint8_t regs[REG_MAX]; + guint8 regs[REG_MAX]; } sige_readreg; struct { - uint8_t nb; + guint8 nb; struct { - uint8_t reg; - uint8_t val; + guint8 reg; + guint8 val; } regs[REG_MAX]; } egis_writereg; struct { - uint8_t length_factor; - uint8_t length; - uint8_t use_gvv; - uint8_t gain; - uint8_t vrt; - uint8_t vrb; + guint8 length_factor; + guint8 length; + guint8 use_gvv; + guint8 gain; + guint8 vrt; + guint8 vrb; } egis_readf; struct { - uint8_t len[2]; - uint8_t val[3]; + guint8 len[2]; + guint8 val[3]; } egis_readfp; struct { - uint8_t val[5]; + guint8 val[5]; } sige_misc; - uint8_t padding[0x40-6]; /* Ensure size of 0x40 */ + guint8 padding[0x40-6]; /* Ensure size of 0x40 */ }; } __attribute__((packed)); /* Structure to keep information between asynchronous functions. */ -struct etes603_dev { - uint8_t regs[256]; +struct _FpiDeviceEtes603 { + FpImageDevice parent; + + guint8 regs[256]; struct egis_msg *req; size_t req_len; struct egis_msg *ans; size_t ans_len; - uint8_t *fp; - uint16_t fp_height; + guint8 *fp; + guint16 fp_height; - uint8_t tunedc_min; - uint8_t tunedc_max; + guint8 tunedc_min; + guint8 tunedc_max; /* Device parameters */ - uint8_t gain; - uint8_t dcoffset; - uint8_t vrt; - uint8_t vrb; + guint8 gain; + guint8 dcoffset; + guint8 vrt; + guint8 vrb; + gboolean deactivating; unsigned int is_active; }; +G_DECLARE_FINAL_TYPE(FpiDeviceEtes603, fpi_device_etes603, FPI, DEVICE_ETES603, + FpImageDevice); +G_DEFINE_TYPE(FpiDeviceEtes603, fpi_device_etes603, FP_TYPE_IMAGE_DEVICE); -static void m_start_fingerdetect(struct fp_img_dev *idev); +static void m_start_fingerdetect(FpImageDevice *idev); /* * Prepare the header of the message to be sent to the device. */ @@ -236,10 +242,11 @@ static int msg_header_check(struct egis_msg *msg) /* * Prepare message to ask for a frame. */ -static void msg_get_frame(struct etes603_dev *dev, - uint8_t use_gvv, uint8_t gain, uint8_t vrt, uint8_t vrb) +static void msg_get_frame(FpiDeviceEtes603 *self, + guint8 use_gvv, guint8 gain, guint8 vrt, + guint8 vrb) { - struct egis_msg *msg = dev->req; + struct egis_msg *msg = self->req; msg_header_prepare(msg); msg->cmd = CMD_READ_FRAME; msg->egis_readf.length_factor = 0x01; @@ -251,17 +258,17 @@ static void msg_get_frame(struct etes603_dev *dev, msg->egis_readf.vrt = vrt; msg->egis_readf.vrb = vrb; - dev->req_len = MSG_HDR_SIZE + 6; - dev->ans_len = FRAME_SIZE; + self->req_len = MSG_HDR_SIZE + 6; + self->ans_len = FRAME_SIZE; } /* * Prepare message to ask for a fingerprint frame. */ -static void msg_get_fp(struct etes603_dev *dev, uint8_t len0, uint8_t len1, - uint8_t v2, uint8_t v3, uint8_t v4) +static void msg_get_fp(FpiDeviceEtes603 *self, guint8 len0, guint8 len1, + guint8 v2, guint8 v3, guint8 v4) { - struct egis_msg *msg = dev->req; + struct egis_msg *msg = self->req; msg_header_prepare(msg); msg->cmd = CMD_READ_FE; /* Unknown values and always same on captured frames. @@ -278,17 +285,17 @@ static void msg_get_fp(struct etes603_dev *dev, uint8_t len0, uint8_t len1, msg->egis_readfp.val[1] = v3; msg->egis_readfp.val[2] = v4; - dev->req_len = MSG_HDR_SIZE + 5; - dev->ans_len = FE_SIZE; + self->req_len = MSG_HDR_SIZE + 5; + self->ans_len = FE_SIZE; } /* * Prepare message to read registers from the sensor. * Variadic argument pattern: int reg, ... */ -static void msg_get_regs(struct etes603_dev *dev, int n_args, ... ) +static void msg_get_regs(FpiDeviceEtes603 *self, int n_args, ... ) { - struct egis_msg *msg = dev->req; + struct egis_msg *msg = self->req; va_list ap; int i; @@ -303,14 +310,14 @@ static void msg_get_regs(struct etes603_dev *dev, int n_args, ... ) } va_end(ap); - dev->req_len = MSG_HDR_SIZE + 1 + n_args; - dev->ans_len = MSG_HDR_SIZE + 1 + n_args; + self->req_len = MSG_HDR_SIZE + 1 + n_args; + self->ans_len = MSG_HDR_SIZE + 1 + n_args; } /* * Parse the result of read register command. */ -static int msg_parse_regs(struct etes603_dev *dev) +static int msg_parse_regs(FpiDeviceEtes603 *dev) { size_t i, n_args; struct egis_msg *msg_req = dev->req; @@ -335,9 +342,9 @@ static int msg_parse_regs(struct etes603_dev *dev) * Prepare message to write sensor's registers. * Variadic arguments are: int reg, int val, ... */ -static void msg_set_regs(struct etes603_dev *dev, int n_args, ...) +static void msg_set_regs(FpiDeviceEtes603 *self, int n_args, ...) { - struct egis_msg *msg = dev->req; + struct egis_msg *msg = self->req; va_list ap; int i; @@ -354,11 +361,11 @@ static void msg_set_regs(struct etes603_dev *dev, int n_args, ...) } va_end(ap); - dev->req_len = MSG_HDR_SIZE + 1 + n_args; - dev->ans_len = MSG_HDR_SIZE + 1; + self->req_len = MSG_HDR_SIZE + 1 + n_args; + self->ans_len = MSG_HDR_SIZE + 1; } -static int msg_check_ok(struct etes603_dev *dev) +static int msg_check_ok(FpiDeviceEtes603 *dev) { struct egis_msg *msg = dev->ans; if (msg_header_check(msg)) { @@ -375,7 +382,7 @@ err: /* * Check the model of the sensor. */ -static int check_info(struct etes603_dev *dev) +static int check_info(FpiDeviceEtes603 *dev) { if (dev->regs[0x70] == 0x4A && dev->regs[0x71] == 0x44 && dev->regs[0x72] == 0x49 && dev->regs[0x73] == 0x31) @@ -387,7 +394,7 @@ static int check_info(struct etes603_dev *dev) return -1; } -static void msg_get_cmd20(struct etes603_dev *dev) +static void msg_get_cmd20(FpiDeviceEtes603 *dev) { struct egis_msg *msg = dev->req; msg_header_prepare(msg); @@ -395,7 +402,7 @@ static void msg_get_cmd20(struct etes603_dev *dev) dev->req_len = MSG_HDR_SIZE; } -static int msg_check_cmd20(struct etes603_dev *dev) +static int msg_check_cmd20(FpiDeviceEtes603 *dev) { struct egis_msg *msg = dev->ans; if (msg_header_check(msg)) { @@ -413,7 +420,7 @@ static int msg_check_cmd20(struct etes603_dev *dev) return 0; } -static void msg_get_cmd25(struct etes603_dev *dev) +static void msg_get_cmd25(FpiDeviceEtes603 *dev) { struct egis_msg *msg = dev->req; msg_header_prepare(msg); @@ -421,7 +428,7 @@ static void msg_get_cmd25(struct etes603_dev *dev) dev->req_len = MSG_HDR_SIZE; } -static int msg_check_cmd25(struct etes603_dev *dev) +static int msg_check_cmd25(FpiDeviceEtes603 *dev) { struct egis_msg *msg = dev->ans; if (msg_header_check(msg)) { @@ -442,9 +449,9 @@ err: return -1; } -static void msg_set_mode_control(struct etes603_dev *dev, uint8_t mode) +static void msg_set_mode_control(FpiDeviceEtes603 *self, guint8 mode) { - msg_set_regs(dev, 2, REG_MODE_CONTROL, mode); + msg_set_regs(self, 2, REG_MODE_CONTROL, mode); } @@ -453,7 +460,7 @@ static void msg_set_mode_control(struct etes603_dev *dev, uint8_t mode) /* * Return the brightness of a 4bpp frame */ -static unsigned int process_get_brightness(uint8_t *f, size_t s) +static unsigned int process_get_brightness(guint8 *f, size_t s) { unsigned int i, sum = 0; for (i = 0; i < s; i++) { @@ -466,7 +473,7 @@ static unsigned int process_get_brightness(uint8_t *f, size_t s) /* * Return the histogram of a 4bpp frame */ -static void process_hist(uint8_t *f, size_t s, float stat[5]) +static void process_hist(guint8 *f, size_t s, float stat[5]) { float hist[16]; float black_mean, white_mean; @@ -502,7 +509,7 @@ static void process_hist(uint8_t *f, size_t s, float stat[5]) /* * Return true if the frame is almost empty. */ -static int process_frame_empty(uint8_t *frame, size_t size) +static int process_frame_empty(guint8 *frame, size_t size) { unsigned int sum = process_get_brightness(frame, size); /* Allow an average of 'threshold' luminosity per pixel */ @@ -512,8 +519,8 @@ static int process_frame_empty(uint8_t *frame, size_t size) } /* Transform 4 bits image to 8 bits image */ -static void process_4to8_bpp(uint8_t *input, unsigned int input_size, - uint8_t *output) +static void process_4to8_bpp(guint8 *input, unsigned int input_size, + guint8 *output) { unsigned int i, j = 0; for (i = 0; i < input_size; i++, j += 2) { @@ -526,11 +533,11 @@ static void process_4to8_bpp(uint8_t *input, unsigned int input_size, /* * Remove duplicated lines at the end of a fingerprint. */ -static void process_remove_fp_end(struct etes603_dev *dev) +static void process_removefpi_end(FpiDeviceEtes603 *dev) { unsigned int i; /* 2 last lines with Fly-Estimation are the empty pattern. */ - uint8_t *pattern = dev->fp + (dev->fp_height - 2) * FE_WIDTH / 2; + guint8 *pattern = dev->fp + (dev->fp_height - 2) * FE_WIDTH / 2; for (i = 2; i < dev->fp_height; i+= 2) { if (memcmp(pattern, pattern - (i * FE_WIDTH / 2), FE_WIDTH)) break; @@ -539,7 +546,7 @@ static void process_remove_fp_end(struct etes603_dev *dev) fp_dbg("Removing %d empty lines from image", i - 2); } -static void reset_param(struct etes603_dev *dev) +static void reset_param(FpiDeviceEtes603 *dev) { dev->dcoffset = 0; dev->vrt = 0; @@ -636,121 +643,112 @@ enum { EXIT_NUM_STATES }; -static int async_tx(struct fp_img_dev *idev, unsigned int ep, void *cb, - void *cb_arg) +static void async_tx(FpDevice *dev, unsigned int ep, void *cb, + FpiSsm *ssm) { - struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev)); - struct libusb_transfer *transfer = fpi_usb_alloc(); - unsigned char *buffer; + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); + FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); + unsigned char *buffer = NULL; int length; if (ep == EP_OUT) { - buffer = (unsigned char *)dev->req; - length = dev->req_len; + buffer = (unsigned char *) self->req; + length = self->req_len; } else if (ep == EP_IN) { - buffer = (unsigned char *)dev->ans; - length = dev->ans_len; + buffer = (unsigned char *) self->ans; + length = self->ans_len; } else { - return -EIO; + g_assert_not_reached (); } - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(idev)), ep, buffer, length, - cb, cb_arg, BULK_TIMEOUT); - - if (libusb_submit_transfer(transfer)) { - libusb_free_transfer(transfer); - return -EIO; - } - return 0; + transfer->ssm = ssm; + fpi_usb_transfer_fill_bulk_full(transfer, ep, buffer, length, NULL); + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, cb, NULL); + fpi_usb_transfer_unref(transfer); } -static void async_tx_cb(struct libusb_transfer *transfer) +static void async_tx_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm); - struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev)); + FpImageDevice *idev = FP_IMAGE_DEVICE(device); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(idev); - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fp_warn("transfer is not completed (status=%d)", - transfer->status); - fpi_ssm_mark_failed(ssm, -EIO); - libusb_free_transfer(transfer); + if (error) { + fp_warn("transfer is not completed (result: %s)", + error->message); + fpi_ssm_mark_failed(transfer->ssm, error); } else { unsigned char endpoint = transfer->endpoint; int actual_length = transfer->actual_length; int length = transfer->length; - /* Freeing now transfer since fpi_ssm_* functions are not - * returning directly. */ - libusb_free_transfer(transfer); + if (endpoint == EP_OUT) { if (length != actual_length) fp_warn("length %d != actual_length %d", length, actual_length); + /* Chained with the answer */ - if (async_tx(idev, EP_IN, async_tx_cb, ssm)) - fpi_ssm_mark_failed(ssm, -EIO); + async_tx(device, EP_IN, async_tx_cb, transfer->ssm); } else if (endpoint == EP_IN) { - dev->ans_len = actual_length; - fpi_ssm_next_state(ssm); + self->ans_len = actual_length; + fpi_ssm_next_state(transfer->ssm); } } } -static void m_exit_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_exit_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *idev = user_data; - struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); switch (fpi_ssm_get_cur_state(ssm)) { case EXIT_SET_REGS_REQ: - msg_set_regs(dev, 4, REG_VCO_CONTROL, REG_VCO_IDLE, + msg_set_regs(self, 4, REG_VCO_CONTROL, REG_VCO_IDLE, REG_MODE_CONTROL, REG_MODE_SLEEP); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case EXIT_SET_REGS_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_mark_completed(ssm); break; default: - fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm)); - goto err; + g_assert_not_reached(); break; } return; err: - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } -static void m_exit_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_exit_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - struct fp_img_dev *idev = user_data; + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); - if (fpi_ssm_get_error(ssm)) { + if (error) { fp_err("Error switching the device to idle state"); } else { fp_dbg("The device is now in idle state"); } - fpi_imgdev_deactivate_complete(idev); + fpi_image_device_deactivate_complete(idev, error); fpi_ssm_free(ssm); } -static void m_exit_start(struct fp_img_dev *idev) +static void m_exit_start(FpImageDevice *idev) { - fpi_ssm *ssm = fpi_ssm_new(FP_DEV(idev), m_exit_state, + FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(idev), m_exit_state, EXIT_NUM_STATES, idev); fp_dbg("Switching device to idle mode"); fpi_ssm_start(ssm, m_exit_complete); } -static void m_capture_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_capture_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *idev = user_data; - struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); - if (dev->is_active == FALSE) { + if (self->is_active == FALSE) { fpi_ssm_mark_completed(ssm); return; } @@ -759,88 +757,87 @@ static void m_capture_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) case CAP_FP_INIT_SET_REG10_REQ: /* Reset fingerprint */ fp_dbg("Capturing a fingerprint..."); - memset(dev->fp, 0, FE_SIZE * 2); - dev->fp_height = 0; - msg_set_regs(dev, 2, REG_10, 0x92); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + memset(self->fp, 0, FE_SIZE * 2); + self->fp_height = 0; + msg_set_regs(self, 2, REG_10, 0x92); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case CAP_FP_INIT_SET_REG10_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_next_state(ssm); break; case CAP_FP_INIT_SET_MODE_FP_REQ: - msg_set_mode_control(dev, REG_MODE_FP); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_mode_control(self, REG_MODE_FP); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case CAP_FP_INIT_SET_MODE_FP_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fp_dbg("Capturing a 1st frame..."); fpi_ssm_next_state(ssm); break; case CAP_FP_GET_FP_REQ: - msg_get_fp(dev, 0x01, 0xF4, 0x02, 0x01, 0x64); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_get_fp(self, 0x01, 0xF4, 0x02, 0x01, 0x64); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case CAP_FP_GET_FP_ANS: - memcpy(dev->fp + dev->fp_height * FE_WIDTH / 2, dev->ans, + memcpy(self->fp + self->fp_height * FE_WIDTH / 2, self->ans, FE_SIZE); - dev->fp_height += FE_HEIGHT; - if (dev->fp_height <= FE_HEIGHT) { + self->fp_height += FE_HEIGHT; + if (self->fp_height <= FE_HEIGHT) { /* 2 lines are at least removed each time */ - dev->fp_height -= 2; + self->fp_height -= 2; fp_dbg("Capturing a 2nd frame..."); fpi_ssm_jump_to_state(ssm, CAP_FP_GET_FP_REQ); } else { - struct fp_img *img; + FpImage *img; unsigned int img_size; /* Remove empty parts 2 times for the 2 frames */ - process_remove_fp_end(dev); - process_remove_fp_end(dev); - img_size = dev->fp_height * FE_WIDTH; - img = fpi_img_new(img_size); + process_removefpi_end(self); + process_removefpi_end(self); + img_size = self->fp_height * FE_WIDTH; + img = fp_image_new(FE_WIDTH, self->fp_height); /* Images received are white on black, so invert it. */ /* TODO detect sweep direction */ - img->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED; - img->height = dev->fp_height; - process_4to8_bpp(dev->fp, img_size / 2, img->data); + img->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED; + img->height = self->fp_height; + process_4to8_bpp(self->fp, img_size / 2, img->data); fp_dbg("Sending the raw fingerprint image (%dx%d)", img->width, img->height); - fpi_imgdev_image_captured(idev, img); - fpi_imgdev_report_finger_status(idev, FALSE); + fpi_image_device_image_captured(idev, img); + fpi_image_device_report_finger_status(idev, FALSE); fpi_ssm_mark_completed(ssm); } break; default: - fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm)); - goto err; + g_assert_not_reached(); break; } return; err: - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } -static void m_capture_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_capture_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - struct fp_img_dev *idev = user_data; - struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); - if (fpi_ssm_get_error(ssm)) { - if (fpi_imgdev_get_action_state(idev) != IMG_ACQUIRE_STATE_DEACTIVATING) { + if (error) { + if (self->is_active) { fp_err("Error while capturing fingerprint " - "(fpi_ssm_get_error(ssm)=%d)", fpi_ssm_get_error(ssm)); - fpi_imgdev_session_error(idev, fpi_ssm_get_error(ssm)); + "(%s)", error->message); + fpi_image_device_session_error (idev, error); + } else { + g_error_free (error); } } fpi_ssm_free(ssm); - if (dev->is_active == TRUE) { + if (self->is_active == TRUE) { fp_dbg("Device is still active, restarting finger detection"); m_start_fingerdetect(idev); } else { @@ -848,141 +845,136 @@ static void m_capture_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_dat } } -static void m_finger_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_finger_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *idev = user_data; - struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); - if (dev->is_active == FALSE) { + if (self->is_active == FALSE) { fpi_ssm_mark_completed(ssm); return; } switch (fpi_ssm_get_cur_state(ssm)) { case FGR_FPA_INIT_SET_MODE_SLEEP_REQ: - msg_set_mode_control(dev, REG_MODE_SLEEP); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_mode_control(self, REG_MODE_SLEEP); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case FGR_FPA_INIT_SET_MODE_SLEEP_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_next_state(ssm); break; case FGR_FPA_INIT_SET_DCOFFSET_REQ: - msg_set_regs(dev, 2, REG_DCOFFSET, dev->dcoffset); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_regs(self, 2, REG_DCOFFSET, self->dcoffset); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case FGR_FPA_INIT_SET_DCOFFSET_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_next_state(ssm); break; case FGR_FPA_INIT_SET_GAINVRTVRB_REQ: - msg_set_regs(dev, 6, REG_GAIN, dev->gain, REG_VRT, dev->vrt, - REG_VRB, dev->vrb); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_regs(self, 6, REG_GAIN, self->gain, REG_VRT, + self->vrt, + REG_VRB, self->vrb); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case FGR_FPA_INIT_SET_GAINVRTVRB_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_next_state(ssm); break; case FGR_FPA_INIT_SET_VCO_CONTROL_RT_REQ: - msg_set_regs(dev, 2, REG_VCO_CONTROL, REG_VCO_RT); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_regs(self, 2, REG_VCO_CONTROL, REG_VCO_RT); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case FGR_FPA_INIT_SET_VCO_CONTROL_RT_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_next_state(ssm); break; case FGR_FPA_INIT_SET_REG04_REQ: - msg_set_regs(dev, 2, REG_04, 0x00); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_regs(self, 2, REG_04, 0x00); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case FGR_FPA_INIT_SET_REG04_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_next_state(ssm); break; case FGR_FPA_INIT_SET_MODE_SENSOR_REQ: - msg_set_mode_control(dev, REG_MODE_SENSOR); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_mode_control(self, REG_MODE_SENSOR); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case FGR_FPA_INIT_SET_MODE_SENSOR_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_next_state(ssm); break; case FGR_FPA_GET_FRAME_REQ: - msg_get_frame(dev, 0x00, 0x00, 0x00, 0x00); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_get_frame(self, 0x00, 0x00, 0x00, 0x00); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case FGR_FPA_GET_FRAME_ANS: - if (process_frame_empty((uint8_t *)dev->ans, FRAME_SIZE)) { + if (process_frame_empty((guint8 *) self->ans, FRAME_SIZE)) { fpi_ssm_jump_to_state(ssm, FGR_FPA_GET_FRAME_REQ); } else { - fpi_imgdev_report_finger_status(idev, TRUE); + fpi_image_device_report_finger_status(FP_IMAGE_DEVICE (dev), TRUE); fpi_ssm_mark_completed(ssm); } break; default: - fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm)); - goto err; + g_assert_not_reached(); break; } return; err: - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } -static void m_finger_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_finger_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - struct fp_img_dev *idev = user_data; - struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); - if (!fpi_ssm_get_error(ssm)) { - fpi_ssm *ssm_cap; - ssm_cap = fpi_ssm_new(FP_DEV(idev), m_capture_state, - CAP_NUM_STATES, idev); + if (!error) { + FpiSsm *ssm_cap; + ssm_cap = fpi_ssm_new(dev, m_capture_state, + CAP_NUM_STATES, NULL); fpi_ssm_start(ssm_cap, m_capture_complete); } else { - if (fpi_imgdev_get_action_state(idev) != IMG_ACQUIRE_STATE_DEACTIVATING) { + if (self->is_active) { fp_err("Error while capturing fingerprint " - "(fpi_ssm_get_error(ssm)=%d)", fpi_ssm_get_error(ssm)); - fpi_imgdev_session_error(idev, -4); + "(%s)", error->message); + fpi_image_device_session_error(idev, error); + } else { + g_error_free (error); } - dev->is_active = FALSE; + self->is_active = FALSE; } fpi_ssm_free(ssm); } -static void m_start_fingerdetect(struct fp_img_dev *idev) +static void m_start_fingerdetect(FpImageDevice *idev) { - fpi_ssm *ssmf; - ssmf = fpi_ssm_new(FP_DEV(idev), m_finger_state, FGR_NUM_STATES, idev); + FpiSsm *ssmf; + ssmf = fpi_ssm_new(FP_DEVICE(idev), m_finger_state, FGR_NUM_STATES, + idev); fpi_ssm_start(ssmf, m_finger_complete); } /* * Tune value of VRT and VRB for contrast and brightness. */ -static void m_tunevrb_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_tunevrb_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *idev = user_data; - struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); float hist[5]; - if (dev->is_active == FALSE) { + if (self->is_active == FALSE) { fpi_ssm_mark_completed(ssm); return; } @@ -990,158 +982,145 @@ static void m_tunevrb_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) switch (fpi_ssm_get_cur_state(ssm)) { case TUNEVRB_INIT: fp_dbg("Tuning of VRT/VRB"); - g_assert(dev->dcoffset); + g_assert(self->dcoffset); /* VRT(reg E1)=0x0A and VRB(reg E2)=0x10 are starting values */ - dev->vrt = 0x0A; - dev->vrb = 0x10; + self->vrt = 0x0A; + self->vrb = 0x10; fpi_ssm_next_state(ssm); break; case TUNEVRB_GET_GAIN_REQ: - msg_get_regs(dev, 1, REG_GAIN); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_get_regs(self, 1, REG_GAIN); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case TUNEVRB_GET_GAIN_ANS: - if (msg_parse_regs(dev)) + if (msg_parse_regs(self)) goto err; fpi_ssm_next_state(ssm); break; case TUNEVRB_GET_DCOFFSET_REQ: - msg_get_regs(dev, 1, REG_DCOFFSET); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_get_regs(self, 1, REG_DCOFFSET); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case TUNEVRB_GET_DCOFFSET_ANS: - if (msg_parse_regs(dev)) + if (msg_parse_regs(self)) goto err; fpi_ssm_next_state(ssm); break; case TUNEVRB_SET_DCOFFSET_REQ: /* Reduce DCoffset by 1 to allow tuning */ - msg_set_regs(dev, 2, REG_DCOFFSET, dev->dcoffset - 1); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_regs(self, 2, REG_DCOFFSET, self->dcoffset - 1); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case TUNEVRB_SET_DCOFFSET_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_next_state(ssm); break; case TUNEVRB_FRAME_REQ: - fp_dbg("Testing VRT=0x%02X VRB=0x%02X", dev->vrt, dev->vrb); - msg_get_frame(dev, 0x01, dev->gain, dev->vrt, dev->vrb); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + fp_dbg("Testing VRT=0x%02X VRB=0x%02X", self->vrt, self->vrb); + msg_get_frame(self, 0x01, self->gain, self->vrt, self->vrb); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case TUNEVRB_FRAME_ANS: - process_hist((uint8_t *)dev->ans, FRAME_SIZE, hist); + process_hist((guint8 *) self->ans, FRAME_SIZE, hist); /* Note that this tuning could probably be improved */ if (hist[0] + hist[1] > 0.95) { - if (dev->vrt <= 0 || dev->vrb <= 0) { + if (self->vrt <= 0 || self->vrb <= 0) { fp_dbg("Image is too dark, reducing DCOffset"); - dev->dcoffset--; + self->dcoffset--; fpi_ssm_jump_to_state(ssm, TUNEVRB_INIT); } else { - dev->vrt--; - dev->vrb--; + self->vrt--; + self->vrb--; fpi_ssm_jump_to_state(ssm, TUNEVRB_FRAME_REQ); } break; } if (hist[4] > 0.95) { fp_dbg("Image is too bright, increasing DCOffset"); - dev->dcoffset++; + self->dcoffset++; fpi_ssm_jump_to_state(ssm, TUNEVRB_INIT); break; } if (hist[4] + hist[3] > 0.4) { - if (dev->vrt >= 2 * dev->vrb - 0x0a) { - dev->vrt++; dev->vrb++; + if (self->vrt >= 2 * self->vrb - 0x0a) { + self->vrt++; self->vrb++; } else { - dev->vrt++; + self->vrt++; } /* Check maximum for vrt/vrb */ /* TODO if maximum is reached, leave with an error? */ - if (dev->vrt > VRT_MAX) - dev->vrt = VRT_MAX; - if (dev->vrb > VRB_MAX) - dev->vrb = VRB_MAX; + if (self->vrt > VRT_MAX) + self->vrt = VRT_MAX; + if (self->vrb > VRB_MAX) + self->vrb = VRB_MAX; fpi_ssm_jump_to_state(ssm, TUNEVRB_FRAME_REQ); break; } fpi_ssm_next_state(ssm); break; case TUNEVRB_FINAL_SET_DCOFFSET_REQ: - fp_dbg("-> VRT=0x%02X VRB=0x%02X", dev->vrt, dev->vrb); + fp_dbg("-> VRT=0x%02X VRB=0x%02X", self->vrt, self->vrb); /* Reset the DCOffset */ - msg_set_regs(dev, 2, REG_DCOFFSET, dev->dcoffset); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_regs(self, 2, REG_DCOFFSET, self->dcoffset); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case TUNEVRB_FINAL_SET_DCOFFSET_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_next_state(ssm); break; case TUNEVRB_FINAL_SET_REG2627_REQ: /* In traces, REG_26/REG_27 are set. purpose? values? */ - msg_set_regs(dev, 4, REG_26, 0x11, REG_27, 0x00); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_regs(self, 4, REG_26, 0x11, REG_27, 0x00); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case TUNEVRB_FINAL_SET_REG2627_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_next_state(ssm); break; case TUNEVRB_FINAL_SET_GAINVRTVRB_REQ: /* Set Gain/VRT/VRB values found */ - msg_set_regs(dev, 6, REG_GAIN, dev->gain, REG_VRT, dev->vrt, - REG_VRB, dev->vrb); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_regs(self, 6, REG_GAIN, self->gain, REG_VRT, + self->vrt, + REG_VRB, self->vrb); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case TUNEVRB_FINAL_SET_GAINVRTVRB_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; /* In traces, Gain/VRT/VRB are read again. */ fpi_ssm_next_state(ssm); break; case TUNEVRB_FINAL_SET_MODE_SLEEP_REQ: - msg_set_mode_control(dev, REG_MODE_SLEEP); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_mode_control(self, REG_MODE_SLEEP); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case TUNEVRB_FINAL_SET_MODE_SLEEP_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_mark_completed(ssm); break; default: - fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm)); - goto err; + g_assert_not_reached(); break; } return; err: - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } -static void m_tunevrb_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_tunevrb_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - struct fp_img_dev *idev = user_data; + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); - fpi_imgdev_activate_complete(idev, fpi_ssm_get_error(ssm) != 0); - if (!fpi_ssm_get_error(ssm)) { + fpi_image_device_activate_complete(idev, error); + if (!error) { fp_dbg("Tuning is done. Starting finger detection."); m_start_fingerdetect(idev); - } else { - struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); - fp_err("Error while tuning VRT"); - dev->is_active = FALSE; - reset_param(dev); - fpi_imgdev_session_error(idev, -3); } fpi_ssm_free(ssm); } @@ -1150,12 +1129,11 @@ static void m_tunevrb_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_dat * This function tunes the DCoffset value and adjusts the gain value if * required. */ -static void m_tunedc_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_tunedc_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *idev = user_data; - struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); - if (dev->is_active == FALSE) { + if (self->is_active == FALSE) { fpi_ssm_mark_completed(ssm); return; } @@ -1167,324 +1145,314 @@ static void m_tunedc_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) switch (fpi_ssm_get_cur_state(ssm)) { case TUNEDC_INIT: /* reg_e0 = 0x23 is sensor normal/small gain */ - dev->gain = GAIN_SMALL_INIT; - dev->tunedc_min = DCOFFSET_MIN; - dev->tunedc_max = DCOFFSET_MAX; + self->gain = GAIN_SMALL_INIT; + self->tunedc_min = DCOFFSET_MIN; + self->tunedc_max = DCOFFSET_MAX; fp_dbg("Tuning DCoffset"); fpi_ssm_next_state(ssm); break; case TUNEDC_SET_DCOFFSET_REQ: /* Dichotomic search to find at which value the frame becomes * almost black. */ - dev->dcoffset = (dev->tunedc_max + dev->tunedc_min) / 2; - fp_dbg("Testing DCoffset=0x%02X Gain=0x%02X", dev->dcoffset, - dev->gain); - msg_set_regs(dev, 2, REG_DCOFFSET, dev->dcoffset); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + self->dcoffset = (self->tunedc_max + self->tunedc_min) / 2; + fp_dbg("Testing DCoffset=0x%02X Gain=0x%02X", self->dcoffset, + self->gain); + msg_set_regs(self, 2, REG_DCOFFSET, self->dcoffset); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case TUNEDC_SET_DCOFFSET_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_next_state(ssm); break; case TUNEDC_GET_FRAME_REQ: /* vrt:0x15 vrb:0x10 are constant in all tuning frames. */ - msg_get_frame(dev, 0x01, dev->gain, 0x15, 0x10); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_get_frame(self, 0x01, self->gain, 0x15, 0x10); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case TUNEDC_GET_FRAME_ANS: - if (process_frame_empty((uint8_t *)dev->ans, FRAME_WIDTH)) - dev->tunedc_max = dev->dcoffset; + if (process_frame_empty((guint8 *) self->ans, FRAME_WIDTH)) + self->tunedc_max = self->dcoffset; else - dev->tunedc_min = dev->dcoffset; - if (dev->tunedc_min + 1 < dev->tunedc_max) { + self->tunedc_min = self->dcoffset; + if (self->tunedc_min + 1 < self->tunedc_max) { fpi_ssm_jump_to_state(ssm, TUNEDC_SET_DCOFFSET_REQ); - } else if (dev->tunedc_max < DCOFFSET_MAX) { - dev->dcoffset = dev->tunedc_max + 1; + } else if (self->tunedc_max < DCOFFSET_MAX) { + self->dcoffset = self->tunedc_max + 1; fpi_ssm_next_state(ssm); } else { - dev->gain--; + self->gain--; fpi_ssm_jump_to_state(ssm, TUNEDC_SET_DCOFFSET_REQ); } break; case TUNEDC_FINAL_SET_REG2122_REQ: - fp_dbg("-> DCoffset=0x%02X Gain=0x%02X", dev->dcoffset, - dev->gain); + fp_dbg("-> DCoffset=0x%02X Gain=0x%02X", self->dcoffset, + self->gain); /* ??? how reg21 / reg22 are calculated */ - msg_set_regs(dev, 4, REG_21, 0x23, REG_22, 0x21); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_regs(self, 4, REG_21, 0x23, REG_22, 0x21); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case TUNEDC_FINAL_SET_REG2122_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_next_state(ssm); break; case TUNEDC_FINAL_SET_GAIN_REQ: - msg_set_regs(dev, 2, REG_GAIN, dev->gain); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_regs(self, 2, REG_GAIN, self->gain); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case TUNEDC_FINAL_SET_GAIN_ANS: fpi_ssm_next_state(ssm); break; case TUNEDC_FINAL_SET_DCOFFSET_REQ: - msg_set_regs(dev, 2, REG_DCOFFSET, dev->dcoffset); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_regs(self, 2, REG_DCOFFSET, self->dcoffset); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case TUNEDC_FINAL_SET_DCOFFSET_ANS: /* In captured traffic, read GAIN, VRT, and VRB registers. */ - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_mark_completed(ssm); break; default: - fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm)); - goto err; + g_assert_not_reached(); break; } return; err: - fpi_ssm_mark_failed(ssm, -EIO); - + fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } -static void m_tunedc_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_tunedc_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - struct fp_img_dev *idev = user_data; - if (!fpi_ssm_get_error(ssm)) { - fpi_ssm *ssm_tune; - ssm_tune = fpi_ssm_new(FP_DEV(idev), m_tunevrb_state, + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); + + if (!error) { + FpiSsm *ssm_tune; + ssm_tune = fpi_ssm_new(FP_DEVICE(idev), m_tunevrb_state, TUNEVRB_NUM_STATES, idev); fpi_ssm_start(ssm_tune, m_tunevrb_complete); } else { - struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); fp_err("Error while tuning DCOFFSET"); - dev->is_active = FALSE; - reset_param(dev); - fpi_imgdev_session_error(idev, -2); + reset_param(FPI_DEVICE_ETES603 (dev)); + fpi_image_device_session_error(idev, error); } fpi_ssm_free(ssm); } -static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_init_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *idev = user_data; - struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); - if (dev->is_active == FALSE) { + if (self->is_active == FALSE) { fpi_ssm_mark_completed(ssm); return; } switch (fpi_ssm_get_cur_state(ssm)) { case INIT_CHECK_INFO_REQ: - msg_get_regs(dev, 4, REG_INFO0, REG_INFO1, REG_INFO2, + msg_get_regs(self, 4, REG_INFO0, REG_INFO1, REG_INFO2, REG_INFO3); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case INIT_CHECK_INFO_ANS: - if (msg_parse_regs(dev)) + if (msg_parse_regs(self)) goto err; - if (check_info(dev)) + if (check_info(self)) goto err; fpi_ssm_next_state(ssm); break; case INIT_CMD20_REQ: - msg_get_cmd20(dev); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_get_cmd20(self); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case INIT_CMD20_ANS: - if (msg_check_cmd20(dev)) + if (msg_check_cmd20(self)) goto err; fpi_ssm_next_state(ssm); break; case INIT_CMD25_REQ: - msg_get_cmd25(dev); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_get_cmd25(self); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case INIT_CMD25_ANS: - if (msg_check_cmd25(dev)) + if (msg_check_cmd25(self)) goto err; fpi_ssm_next_state(ssm); break; case INIT_SENSOR_REQ: /* In captured traffic, those are split. */ - msg_set_regs(dev, 18, REG_MODE_CONTROL, REG_MODE_SLEEP, - REG_50, 0x0F, REG_GAIN, 0x04, REG_VRT, 0x08, - REG_VRB, 0x0D, REG_VCO_CONTROL, REG_VCO_RT, - REG_DCOFFSET, 0x36, REG_F0, 0x00, REG_F2, 0x00); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_regs(self, 18, REG_MODE_CONTROL, REG_MODE_SLEEP, + REG_50, 0x0F, REG_GAIN, 0x04, REG_VRT, 0x08, + REG_VRB, 0x0D, REG_VCO_CONTROL, REG_VCO_RT, + REG_DCOFFSET, 0x36, REG_F0, 0x00, REG_F2, 0x00); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case INIT_SENSOR_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_next_state(ssm); break; case INIT_ENC_REQ: /* Initialize encryption registers without encryption. */ /* Set registers from 0x41 to 0x48 (0x8 regs) */ - msg_set_regs(dev, 16, REG_ENC1, 0x12, REG_ENC2, 0x34, - REG_ENC3, 0x56, REG_ENC4, 0x78, REG_ENC5, 0x90, - REG_ENC6, 0xAB, REG_ENC7, 0xCD, REG_ENC8, 0xEF); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_regs(self, 16, REG_ENC1, 0x12, REG_ENC2, 0x34, + REG_ENC3, 0x56, REG_ENC4, 0x78, REG_ENC5, 0x90, + REG_ENC6, 0xAB, REG_ENC7, 0xCD, REG_ENC8, 0xEF); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case INIT_ENC_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_next_state(ssm); break; case INIT_REGS_REQ: /* Set register from 0x20 to 0x37 (0x18 regs) */ - msg_set_regs(dev, 48, - REG_20, 0x00, REG_21, 0x23, REG_22, 0x21, REG_23, 0x20, - REG_24, 0x14, REG_25, 0x6A, REG_26, 0x00, REG_27, 0x00, - REG_28, 0x00, REG_29, 0xC0, REG_2A, 0x50, REG_2B, 0x50, - REG_2C, 0x4D, REG_2D, 0x03, REG_2E, 0x06, REG_2F, 0x06, - REG_30, 0x10, REG_31, 0x02, REG_32, 0x14, REG_33, 0x34, - REG_34, 0x01, REG_35, 0x08, REG_36, 0x03, REG_37, 0x21); - if (async_tx(idev, EP_OUT, async_tx_cb, ssm)) - goto err; + msg_set_regs(self, 48, + REG_20, 0x00, REG_21, 0x23, REG_22, 0x21, REG_23, + 0x20, + REG_24, 0x14, REG_25, 0x6A, REG_26, 0x00, REG_27, + 0x00, + REG_28, 0x00, REG_29, 0xC0, REG_2A, 0x50, REG_2B, + 0x50, + REG_2C, 0x4D, REG_2D, 0x03, REG_2E, 0x06, REG_2F, + 0x06, + REG_30, 0x10, REG_31, 0x02, REG_32, 0x14, REG_33, + 0x34, + REG_34, 0x01, REG_35, 0x08, REG_36, 0x03, REG_37, + 0x21); + async_tx(dev, EP_OUT, async_tx_cb, ssm); break; case INIT_REGS_ANS: - if (msg_check_ok(dev)) + if (msg_check_ok(self)) goto err; fpi_ssm_mark_completed(ssm); break; default: - fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm)); - goto err; + g_assert_not_reached(); break; } return; err: - fpi_ssm_mark_failed(ssm, -EIO); - + fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } -static void m_init_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void m_init_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - struct fp_img_dev *idev = user_data; - if (!fpi_ssm_get_error(ssm)) { - fpi_ssm *ssm_tune; - ssm_tune = fpi_ssm_new(FP_DEV(idev), m_tunedc_state, + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); + if (!error) { + FpiSsm *ssm_tune; + ssm_tune = fpi_ssm_new(FP_DEVICE(idev), m_tunedc_state, TUNEDC_NUM_STATES, idev); fpi_ssm_start(ssm_tune, m_tunedc_complete); } else { - struct etes603_dev *dev = FP_INSTANCE_DATA(_dev); fp_err("Error initializing the device"); - dev->is_active = FALSE; - reset_param(dev); - fpi_imgdev_session_error(idev, -1); + reset_param(FPI_DEVICE_ETES603 (dev)); + fpi_image_device_session_error (idev, error); } fpi_ssm_free(ssm); } -static int dev_activate(struct fp_img_dev *idev) +static void dev_activate(FpImageDevice *idev) { - struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev)); - fpi_ssm *ssm; + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(idev); + FpiSsm *ssm; - g_assert(dev); + g_assert(self); /* Reset info and data */ - dev->is_active = TRUE; + self->is_active = TRUE; - if (dev->dcoffset == 0) { + if (self->dcoffset == 0) { fp_dbg("Tuning device..."); - ssm = fpi_ssm_new(FP_DEV(idev), m_init_state, INIT_NUM_STATES, idev); + ssm = fpi_ssm_new(FP_DEVICE(idev), m_init_state, + INIT_NUM_STATES, idev); fpi_ssm_start(ssm, m_init_complete); } else { fp_dbg("Using previous tuning (DCOFFSET=0x%02X,VRT=0x%02X," - "VRB=0x%02X,GAIN=0x%02X).", dev->dcoffset, dev->vrt, - dev->vrb, dev->gain); - fpi_imgdev_activate_complete(idev, 0); - ssm = fpi_ssm_new(FP_DEV(idev), m_finger_state, FGR_NUM_STATES, idev); + "VRB=0x%02X,GAIN=0x%02X).", self->dcoffset, self->vrt, + self->vrb, self->gain); + fpi_image_device_activate_complete(idev, NULL); + ssm = fpi_ssm_new(FP_DEVICE(idev), m_finger_state, + FGR_NUM_STATES, idev); fpi_ssm_start(ssm, m_finger_complete); } - return 0; } -static void dev_deactivate(struct fp_img_dev *idev) +static void dev_deactivate(FpImageDevice *idev) { - struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev)); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(idev); fp_dbg("deactivating"); + self->deactivating = TRUE; /* this can be called even if still activated. */ - if (dev->is_active == TRUE) { - dev->is_active = FALSE; + if (self->is_active == TRUE) { + self->is_active = FALSE; + } else { + m_exit_start(idev); + } +} + +static void dev_open(FpImageDevice *idev) +{ + GError *error = NULL; + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(idev); + + if (!g_usb_device_claim_interface (fpi_device_get_usb_device(FP_DEVICE(idev)), 0, 0, &error)) { + fpi_image_device_open_complete(idev, error); + return; } - m_exit_start(idev); + self->req = g_malloc(sizeof(struct egis_msg)); + self->ans = g_malloc(FE_SIZE); + self->fp = g_malloc(FE_SIZE * 4); + + fpi_image_device_open_complete(idev, NULL); } -static int dev_open(struct fp_img_dev *idev, unsigned long driver_data) +static void dev_close(FpImageDevice *idev) { - int ret; - struct etes603_dev *dev; + GError *error = NULL; + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(idev); - dev = g_malloc0(sizeof(struct etes603_dev)); - fp_dev_set_instance_data(FP_DEV(idev), dev); + g_free(self->req); + g_free(self->ans); + g_free(self->fp); - dev->req = g_malloc(sizeof(struct egis_msg)); - dev->ans = g_malloc(FE_SIZE); - dev->fp = g_malloc(FE_SIZE * 4); - - ret = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(idev)), 0); - if (ret != LIBUSB_SUCCESS) { - fp_err("libusb_claim_interface failed on interface 0: %s", libusb_error_name(ret)); - return ret; - } - - fpi_imgdev_open_complete(idev, 0); - return 0; + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(idev)), + 0, 0, &error); + fpi_image_device_close_complete(idev, error); } -static void dev_close(struct fp_img_dev *idev) -{ - struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev)); - - g_free(dev->req); - g_free(dev->ans); - g_free(dev->fp); - g_free(dev); - - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(idev)), 0); - fpi_imgdev_close_complete(idev); -} - -static const struct usb_id id_table[] = { +static const FpIdEntry id_table [ ] = { /* EgisTec (aka Lightuning) ES603 */ - { .vendor = 0x1c7a, .product = 0x0603}, - { 0, 0, 0, }, + { .vid = 0x1c7a, .pid = 0x0603, }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -struct fp_img_driver etes603_driver = { - .driver = { - .id = ETES603_ID, - .name = FP_COMPONENT, - .full_name = "EgisTec ES603", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_SWIPE, - }, - .flags = 0, - .img_height = -1, - .img_width = 256, +static void fpi_device_etes603_init(FpiDeviceEtes603 *self) { +} +static void fpi_device_etes603_class_init(FpiDeviceEtes603Class *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); - .open = dev_open, - .close = dev_close, - .activate = dev_activate, - .deactivate = dev_deactivate, -}; + dev_class->id = "etes603"; + dev_class->full_name = "EgisTec ES603"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + + img_class->img_open = dev_open; + img_class->img_close = dev_close; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; + + img_class->img_width = 256; + img_class->img_height = -1; +} diff --git a/meson.build b/meson.build index 33eb68e4..cff9c49c 100644 --- a/meson.build +++ b/meson.build @@ -51,7 +51,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050' ] +default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603' ] all_drivers = default_drivers + virtual_drivers From fbf4b45e76589183bb49fcc51f43b57f1c45ae0d Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 12 Aug 2019 17:00:14 +0200 Subject: [PATCH 39/73] etes603: Chain into exit SM from other SMs when deactivating When the device is deactivated while it is still active then the exit SM needs to be executed from the SM that was active at the time. This is signalled by is_active being set to FALSE while the active SM completes. Call m_exit_start in those cases to ensure proper device deactivation. --- libfprint/drivers/etes603.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/libfprint/drivers/etes603.c b/libfprint/drivers/etes603.c index a97d40e0..b7592a87 100644 --- a/libfprint/drivers/etes603.c +++ b/libfprint/drivers/etes603.c @@ -207,7 +207,6 @@ struct _FpiDeviceEtes603 { guint8 vrt; guint8 vrb; - gboolean deactivating; unsigned int is_active; }; G_DECLARE_FINAL_TYPE(FpiDeviceEtes603, fpi_device_etes603, FPI, DEVICE_ETES603, @@ -737,8 +736,11 @@ static void m_exit_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, static void m_exit_start(FpImageDevice *idev) { + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(idev); FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(idev), m_exit_state, EXIT_NUM_STATES, idev); + + self->is_active = FALSE; fp_dbg("Switching device to idle mode"); fpi_ssm_start(ssm, m_exit_complete); } @@ -842,6 +844,7 @@ static void m_capture_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, m_start_fingerdetect(idev); } else { fp_dbg("And it's over."); + m_exit_start(idev); } } @@ -950,6 +953,7 @@ static void m_finger_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, "(%s)", error->message); fpi_image_device_session_error(idev, error); } else { + m_exit_start(idev); g_error_free (error); } self->is_active = FALSE; @@ -1115,6 +1119,7 @@ err: static void m_tunevrb_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, GError *error) { + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); FpImageDevice *idev = FP_IMAGE_DEVICE (dev); fpi_image_device_activate_complete(idev, error); @@ -1122,6 +1127,10 @@ static void m_tunevrb_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, fp_dbg("Tuning is done. Starting finger detection."); m_start_fingerdetect(idev); } + + if (!self->is_active) + m_exit_start(idev); + fpi_ssm_free(ssm); } @@ -1227,6 +1236,7 @@ err: static void m_tunedc_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, GError *error) { + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); FpImageDevice *idev = FP_IMAGE_DEVICE (dev); if (!error) { @@ -1239,6 +1249,10 @@ static void m_tunedc_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, reset_param(FPI_DEVICE_ETES603 (dev)); fpi_image_device_session_error(idev, error); } + + if (!self->is_active) + m_exit_start(idev); + fpi_ssm_free(ssm); } @@ -1388,7 +1402,6 @@ static void dev_deactivate(FpImageDevice *idev) FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(idev); fp_dbg("deactivating"); - self->deactivating = TRUE; /* this can be called even if still activated. */ if (self->is_active == TRUE) { From 57866c45cd037ce12379f47c3fc9b238a89e81bc Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 9 Jul 2019 21:44:02 +0200 Subject: [PATCH 40/73] vcom5s: Port vcom5s to new API --- libfprint/drivers/vcom5s.c | 306 ++++++++++++++++++------------------- meson.build | 2 +- 2 files changed, 147 insertions(+), 161 deletions(-) diff --git a/libfprint/drivers/vcom5s.c b/libfprint/drivers/vcom5s.c index b0c6c452..c97c4196 100644 --- a/libfprint/drivers/vcom5s.c +++ b/libfprint/drivers/vcom5s.c @@ -28,10 +28,8 @@ * powerdown? does windows do anything special on exit? */ -#define CTRL_IN 0xc0 -#define CTRL_OUT 0x40 #define CTRL_TIMEOUT 1000 -#define EP_IN (1 | LIBUSB_ENDPOINT_IN) +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) #define IMG_WIDTH 300 #define IMG_HEIGHT 288 @@ -40,12 +38,17 @@ #define RQ_SIZE (IMG_WIDTH * ROWS_PER_RQ) #define IMG_SIZE (IMG_WIDTH * IMG_HEIGHT) -struct v5s_dev { +struct _FpDeviceVcom5s { + FpImageDevice parent; + int capture_iteration; - struct fp_img *capture_img; + FpImage *capture_img; gboolean loop_running; gboolean deactivating; }; +G_DECLARE_FINAL_TYPE(FpDeviceVcom5s, fpi_device_vcom5s, FPI, DEVICE_VCOM5S, + FpImageDevice); +G_DEFINE_TYPE(FpDeviceVcom5s, fpi_device_vcom5s, FP_TYPE_IMAGE_DEVICE); enum v5s_regs { /* when using gain 0x29: @@ -72,76 +75,62 @@ enum v5s_cmd { /***** REGISTER I/O *****/ -static void sm_write_reg_cb(struct libusb_transfer *transfer) +static void sm_write_reg_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - fpi_ssm_mark_failed(ssm, -EIO); + if (error) + fpi_ssm_mark_failed(transfer->ssm, error); else - fpi_ssm_next_state(ssm); - - g_free(transfer->buffer); - libusb_free_transfer(transfer); + fpi_ssm_next_state(transfer->ssm); } static void -sm_write_reg(fpi_ssm *ssm, - struct fp_img_dev *dev, +sm_write_reg(FpiSsm *ssm, + FpDevice *dev, unsigned char reg, unsigned char value) { - struct libusb_transfer *transfer = fpi_usb_alloc(); - unsigned char *data; - int r; - + FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); + fp_dbg("set %02x=%02x", reg, value); - data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE); - libusb_fill_control_setup(data, CTRL_OUT, reg, value, 0, 0); - libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, sm_write_reg_cb, - ssm, CTRL_TIMEOUT); - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + fpi_usb_transfer_fill_control(transfer, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + reg, value, 0, 0); + transfer->ssm = ssm; + fpi_usb_transfer_submit(transfer, CTRL_TIMEOUT, NULL, sm_write_reg_cb, + NULL); + fpi_usb_transfer_unref(transfer); } -static void sm_exec_cmd_cb(struct libusb_transfer *transfer) +static void sm_exec_cmd_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - fpi_ssm_mark_failed(ssm, -EIO); + if (error) + fpi_ssm_mark_failed(transfer->ssm, error); else - fpi_ssm_next_state(ssm); - - g_free(transfer->buffer); - libusb_free_transfer(transfer); + fpi_ssm_next_state(transfer->ssm); } static void -sm_exec_cmd(fpi_ssm *ssm, - struct fp_img_dev *dev, +sm_exec_cmd(FpiSsm *ssm, + FpDevice *dev, unsigned char cmd, unsigned char param) { - struct libusb_transfer *transfer = fpi_usb_alloc(); - unsigned char *data; - int r; + FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); fp_dbg("cmd %02x param %02x", cmd, param); - data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE); - libusb_fill_control_setup(data, CTRL_IN, cmd, param, 0, 0); - libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, sm_exec_cmd_cb, - ssm, CTRL_TIMEOUT); - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + fpi_usb_transfer_fill_control(transfer, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + cmd, param, 0, 0); + transfer->ssm = ssm; + fpi_usb_transfer_submit(transfer, CTRL_TIMEOUT, NULL, sm_exec_cmd_cb, + NULL); + fpi_usb_transfer_unref(transfer); } /***** FINGER DETECTION *****/ @@ -159,11 +148,11 @@ sm_exec_cmd(fpi_ssm *ssm, static gboolean finger_is_present(unsigned char *data) { int row; - uint16_t imgavg = 0; + guint16 imgavg = 0; for (row = DETBOX_ROW_START; row < DETBOX_ROW_END; row++) { unsigned char *rowdata = data + (row * IMG_WIDTH); - uint16_t rowavg = 0; + guint16 rowavg = 0; int col; for (col = DETBOX_COL_START; col < DETBOX_COL_END; col++) @@ -181,67 +170,66 @@ static gboolean finger_is_present(unsigned char *data) /***** IMAGE ACQUISITION *****/ -static void capture_iterate(fpi_ssm *ssm, struct fp_img_dev *dev); +static void capture_iterate(FpiSsm *ssm, FpDevice *dev); -static void capture_cb(struct libusb_transfer *transfer) +static void capture_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpImageDevice *imgdev = FP_IMAGE_DEVICE(device); + FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S(device); - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fpi_ssm_mark_failed(ssm, -EIO); - goto out; + if (error) { + fpi_ssm_mark_failed(transfer->ssm, error); + return; } - if (++vdev->capture_iteration == NR_REQS) { - struct fp_img *img = vdev->capture_img; + if (++self->capture_iteration == NR_REQS) { + FpImage *img = self->capture_img; /* must clear this early, otherwise the call chain takes us into * loopsm_complete where we would free it, when in fact we are * supposed to be handing off this image */ - vdev->capture_img = NULL; + self->capture_img = NULL; - fpi_imgdev_report_finger_status(dev, finger_is_present(img->data)); - fpi_imgdev_image_captured(dev, img); - fpi_ssm_next_state(ssm); + fpi_image_device_report_finger_status(imgdev, + finger_is_present(img->data)); + fpi_image_device_image_captured(imgdev, img); + fpi_ssm_next_state(transfer->ssm); } else { - capture_iterate(ssm, dev); + capture_iterate(transfer->ssm, device); } - -out: - libusb_free_transfer(transfer); } static void -capture_iterate(fpi_ssm *ssm, - struct fp_img_dev *dev) +capture_iterate(FpiSsm *ssm, + FpDevice *dev) { - struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); - int iteration = vdev->capture_iteration; - struct libusb_transfer *transfer = fpi_usb_alloc(); - int r; + FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S(dev); + int iteration = self->capture_iteration; + FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, - vdev->capture_img->data + (RQ_SIZE * iteration), RQ_SIZE, - capture_cb, ssm, CTRL_TIMEOUT); - transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK; - r = libusb_submit_transfer(transfer); - if (r < 0) { - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk_full (transfer, + EP_IN, + self->capture_img->data + (RQ_SIZE * iteration), + RQ_SIZE, + NULL); + + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, capture_cb, NULL); + fpi_usb_transfer_unref (transfer); } static void -sm_do_capture(fpi_ssm *ssm, - struct fp_img_dev *dev) +sm_do_capture(FpiSsm *ssm, + FpDevice *dev) { - struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S(dev); + FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (dev); G_DEBUG_HERE(); - vdev->capture_img = fpi_img_new_for_imgdev(dev); - vdev->capture_iteration = 0; + self->capture_img = fp_image_new (cls->img_width, cls->img_height); + self->capture_iteration = 0; capture_iterate(ssm, dev); } @@ -256,10 +244,9 @@ enum loop_states { LOOP_NUM_STATES, }; -static void loop_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void loop_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct v5s_dev *vdev = FP_INSTANCE_DATA(_dev); + FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S(dev); switch (fpi_ssm_get_cur_state(ssm)) { case LOOP_SET_CONTRAST: @@ -269,7 +256,7 @@ static void loop_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) sm_write_reg(ssm, dev, REG_GAIN, 0x29); break; case LOOP_CMD_SCAN: - if (vdev->deactivating) { + if (self->deactivating) { fp_dbg("deactivating, marking completed"); fpi_ssm_mark_completed(ssm); } else @@ -281,95 +268,94 @@ static void loop_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) case LOOP_CAPTURE_DONE: fpi_ssm_jump_to_state(ssm, LOOP_CMD_SCAN); break; + default: + g_assert_not_reached (); } } -static void loopsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void loopsm_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - struct fp_img_dev *dev = user_data; - struct v5s_dev *vdev = FP_INSTANCE_DATA(_dev); - int r = fpi_ssm_get_error(ssm); + FpImageDevice *imgdev = FP_IMAGE_DEVICE (dev); + FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S(dev); fpi_ssm_free(ssm); - fp_img_free(vdev->capture_img); - vdev->capture_img = NULL; - vdev->loop_running = FALSE; + g_object_unref (self->capture_img); + self->capture_img = NULL; + self->loop_running = FALSE; - if (r) - fpi_imgdev_session_error(dev, r); + if (error && !self->deactivating) + fpi_image_device_session_error(imgdev, error); + else if (error) + g_error_free (error); - if (vdev->deactivating) - fpi_imgdev_deactivate_complete(dev); + if (self->deactivating) + fpi_image_device_deactivate_complete(imgdev, NULL); } -static int dev_activate(struct fp_img_dev *dev) +static void dev_activate(FpImageDevice *dev) { - struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), loop_run_state, - LOOP_NUM_STATES, dev); - vdev->deactivating = FALSE; + FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S(dev); + FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(dev), loop_run_state, + LOOP_NUM_STATES, dev); + self->deactivating = FALSE; fpi_ssm_start(ssm, loopsm_complete); - vdev->loop_running = TRUE; - fpi_imgdev_activate_complete(dev, 0); - return 0; + self->loop_running = TRUE; + fpi_image_device_activate_complete(dev, NULL); } -static void dev_deactivate(struct fp_img_dev *dev) +static void dev_deactivate(FpImageDevice *dev) { - struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev)); - if (vdev->loop_running) - vdev->deactivating = TRUE; + FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S(dev); + if (self->loop_running) + self->deactivating = TRUE; else - fpi_imgdev_deactivate_complete(dev); + fpi_image_device_deactivate_complete(dev, NULL); } -static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) +static void dev_init(FpImageDevice *dev) { - int r; - struct v5s_dev *v5s_dev; + GError *error = NULL; - v5s_dev = g_malloc0(sizeof(struct v5s_dev)); - fp_dev_set_instance_data(FP_DEV(dev), v5s_dev); + g_usb_device_claim_interface (fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error); - r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - if (r < 0) - fp_err("could not claim interface 0: %s", libusb_error_name(r)); - - if (r == 0) - fpi_imgdev_open_complete(dev, 0); - - return r; + fpi_image_device_open_complete(dev, error); } -static void dev_deinit(struct fp_img_dev *dev) +static void dev_deinit(FpImageDevice *dev) { - struct v5s_dev *v5s_dev; - v5s_dev = FP_INSTANCE_DATA(FP_DEV(dev)); - g_free(v5s_dev); - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - fpi_imgdev_close_complete(dev); + GError *error = NULL; + + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), + 0, 0, &error); + + fpi_image_device_close_complete(dev, error); } -static const struct usb_id id_table[] = { - { .vendor = 0x061a, .product = 0x0110 }, - { 0, 0, 0, }, +static const FpIdEntry id_table [ ] = { + { .vid = 0x061a, .pid = 0x0110, }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -struct fp_img_driver vcom5s_driver = { - .driver = { - .id = VCOM5S_ID, - .name = FP_COMPONENT, - .full_name = "Veridicom 5thSense", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_PRESS, - }, - .flags = 0, - .img_height = IMG_HEIGHT, - .img_width = IMG_WIDTH, +static void fpi_device_vcom5s_init(FpDeviceVcom5s *self) { +} - .open = dev_init, - .close = dev_deinit, - .activate = dev_activate, - .deactivate = dev_deactivate, -}; +static void fpi_device_vcom5s_class_init(FpDeviceVcom5sClass *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); + + dev_class->id = "vcom5s"; + dev_class->full_name = "Veridicom 5thSense"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_PRESS; + + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; + + img_class->img_width = IMG_WIDTH; + img_class->img_height = IMG_HEIGHT; +} diff --git a/meson.build b/meson.build index cff9c49c..8481073f 100644 --- a/meson.build +++ b/meson.build @@ -51,7 +51,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603' ] +default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603', 'vcom5s' ] all_drivers = default_drivers + virtual_drivers From b8bb08649d5f23245374fd4a8ae01d68266db3ec Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sat, 13 Jul 2019 11:27:07 +0200 Subject: [PATCH 41/73] lib: Add byte data reader/writer helpers These helpers are directly copied from GStreamer and stripped down quite a bit to e.g. always assume the machine does not support unaligned access. --- libfprint/fpi-byte-reader.c | 1259 +++++++++++++++++++++++++++++++++++ libfprint/fpi-byte-reader.h | 680 +++++++++++++++++++ libfprint/fpi-byte-utils.h | 488 ++++++++++++++ libfprint/fpi-byte-writer.c | 614 +++++++++++++++++ libfprint/fpi-byte-writer.h | 413 ++++++++++++ libfprint/meson.build | 5 + 6 files changed, 3459 insertions(+) create mode 100644 libfprint/fpi-byte-reader.c create mode 100644 libfprint/fpi-byte-reader.h create mode 100644 libfprint/fpi-byte-utils.h create mode 100644 libfprint/fpi-byte-writer.c create mode 100644 libfprint/fpi-byte-writer.h diff --git a/libfprint/fpi-byte-reader.c b/libfprint/fpi-byte-reader.c new file mode 100644 index 00000000..aecbe5bc --- /dev/null +++ b/libfprint/fpi-byte-reader.c @@ -0,0 +1,1259 @@ +/* GStreamer byte reader + * + * Copyright (C) 2008 Sebastian Dröge . + * Copyright (C) 2009,2014 Tim-Philipp Müller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define FPI_BYTE_READER_DISABLE_INLINES +#include "fpi-byte-reader.h" + +#include + +/** + * SECTION:fpi-byte-reader + * @title: FpiByteReader + * @short_description: Reads different integer, string and floating point + * types from a memory buffer + * + * #FpiByteReader provides a byte reader that can read different integer and + * floating point types from a memory buffer. It provides functions for reading + * signed/unsigned, little/big endian integers of 8, 16, 24, 32 and 64 bits + * and functions for reading little/big endian floating points numbers of + * 32 and 64 bits. It also provides functions to read NUL-terminated strings + * in various character encodings. + */ + +/** + * fpi_byte_reader_new: (skip) + * @data: (in) (transfer none) (array length=size): data from which the + * #FpiByteReader should read + * @size: Size of @data in bytes + * + * Create a new #FpiByteReader instance, which will read from @data. + * + * Free-function: fpi_byte_reader_free + * + * Returns: (transfer full): a new #FpiByteReader instance + */ +FpiByteReader * +fpi_byte_reader_new (const guint8 * data, guint size) +{ + FpiByteReader *ret = g_slice_new0 (FpiByteReader); + + ret->data = data; + ret->size = size; + + return ret; +} + +/** + * fpi_byte_reader_free: + * @reader: (in) (transfer full): a #FpiByteReader instance + * + * Frees a #FpiByteReader instance, which was previously allocated by + * fpi_byte_reader_new(). + */ +void +fpi_byte_reader_free (FpiByteReader * reader) +{ + g_return_if_fail (reader != NULL); + + g_slice_free (FpiByteReader, reader); +} + +/** + * fpi_byte_reader_init: + * @reader: a #FpiByteReader instance + * @data: (in) (transfer none) (array length=size): data from which + * the #FpiByteReader should read + * @size: Size of @data in bytes + * + * Initializes a #FpiByteReader instance to read from @data. This function + * can be called on already initialized instances. + */ +void +fpi_byte_reader_init (FpiByteReader * reader, const guint8 * data, guint size) +{ + g_return_if_fail (reader != NULL); + + reader->data = data; + reader->size = size; + reader->byte = 0; +} + +/** + * fpi_byte_reader_peek_sub_reader: (skip) + * @reader: an existing and initialized #FpiByteReader instance + * @sub_reader: a #FpiByteReader instance to initialize as sub-reader + * @size: size of @sub_reader in bytes + * + * Initializes a #FpiByteReader sub-reader instance to contain @size bytes of + * data from the current position of @reader. This is useful to read chunked + * formats and make sure that one doesn't read beyond the size of the sub-chunk. + * + * Unlike fpi_byte_reader_get_sub_reader(), this function does not modify the + * current position of @reader. + * + * Returns: FALSE on error or if @reader does not contain @size more bytes from + * the current position, and otherwise TRUE + * + * Since: 1.6 + */ +gboolean +fpi_byte_reader_peek_sub_reader (FpiByteReader * reader, + FpiByteReader * sub_reader, guint size) +{ + return fpi_byte_reader_peek_sub_reader_inline (reader, sub_reader, size); +} + +/** + * fpi_byte_reader_get_sub_reader: (skip) + * @reader: an existing and initialized #FpiByteReader instance + * @sub_reader: a #FpiByteReader instance to initialize as sub-reader + * @size: size of @sub_reader in bytes + * + * Initializes a #FpiByteReader sub-reader instance to contain @size bytes of + * data from the current position of @reader. This is useful to read chunked + * formats and make sure that one doesn't read beyond the size of the sub-chunk. + * + * Unlike fpi_byte_reader_peek_sub_reader(), this function also modifies the + * position of @reader and moves it forward by @size bytes. + * + * Returns: FALSE on error or if @reader does not contain @size more bytes from + * the current position, and otherwise TRUE + * + * Since: 1.6 + */ +gboolean +fpi_byte_reader_get_sub_reader (FpiByteReader * reader, + FpiByteReader * sub_reader, guint size) +{ + return fpi_byte_reader_get_sub_reader_inline (reader, sub_reader, size); +} + +/** + * fpi_byte_reader_set_pos: + * @reader: a #FpiByteReader instance + * @pos: The new position in bytes + * + * Sets the new position of a #FpiByteReader instance to @pos in bytes. + * + * Returns: %TRUE if the position could be set successfully, %FALSE + * otherwise. + */ +gboolean +fpi_byte_reader_set_pos (FpiByteReader * reader, guint pos) +{ + g_return_val_if_fail (reader != NULL, FALSE); + + if (pos > reader->size) + return FALSE; + + reader->byte = pos; + + return TRUE; +} + +/** + * fpi_byte_reader_get_pos: + * @reader: a #FpiByteReader instance + * + * Returns the current position of a #FpiByteReader instance in bytes. + * + * Returns: The current position of @reader in bytes. + */ +guint +fpi_byte_reader_get_pos (const FpiByteReader * reader) +{ + return fpi_byte_reader_get_pos_inline (reader); +} + +/** + * fpi_byte_reader_get_remaining: + * @reader: a #FpiByteReader instance + * + * Returns the remaining number of bytes of a #FpiByteReader instance. + * + * Returns: The remaining number of bytes of @reader instance. + */ +guint +fpi_byte_reader_get_remaining (const FpiByteReader * reader) +{ + return fpi_byte_reader_get_remaining_inline (reader); +} + +/** + * fpi_byte_reader_get_size: + * @reader: a #FpiByteReader instance + * + * Returns the total number of bytes of a #FpiByteReader instance. + * + * Returns: The total number of bytes of @reader instance. + */ +guint +fpi_byte_reader_get_size (const FpiByteReader * reader) +{ + return fpi_byte_reader_get_size_inline (reader); +} + +#define fpi_byte_reader_get_remaining fpi_byte_reader_get_remaining_inline +#define fpi_byte_reader_get_size fpi_byte_reader_get_size_inline + +/** + * fpi_byte_reader_skip: + * @reader: a #FpiByteReader instance + * @nbytes: the number of bytes to skip + * + * Skips @nbytes bytes of the #FpiByteReader instance. + * + * Returns: %TRUE if @nbytes bytes could be skipped, %FALSE otherwise. + */ +gboolean +fpi_byte_reader_skip (FpiByteReader * reader, guint nbytes) +{ + return fpi_byte_reader_skip_inline (reader, nbytes); +} + +/** + * fpi_byte_reader_get_uint8: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint8 to store the result + * + * Read an unsigned 8 bit integer into @val and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int8: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint8 to store the result + * + * Read a signed 8 bit integer into @val and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint8: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint8 to store the result + * + * Read an unsigned 8 bit integer into @val but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int8: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint8 to store the result + * + * Read a signed 8 bit integer into @val but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_uint16_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint16 to store the result + * + * Read an unsigned 16 bit little endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int16_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint16 to store the result + * + * Read a signed 16 bit little endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint16_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint16 to store the result + * + * Read an unsigned 16 bit little endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int16_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint16 to store the result + * + * Read a signed 16 bit little endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_uint16_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint16 to store the result + * + * Read an unsigned 16 bit big endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int16_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint16 to store the result + * + * Read a signed 16 bit big endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint16_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint16 to store the result + * + * Read an unsigned 16 bit big endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int16_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint16 to store the result + * + * Read a signed 16 bit big endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_uint24_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint32 to store the result + * + * Read an unsigned 24 bit little endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int24_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint32 to store the result + * + * Read a signed 24 bit little endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint24_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint32 to store the result + * + * Read an unsigned 24 bit little endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int24_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint32 to store the result + * + * Read a signed 24 bit little endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_uint24_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint32 to store the result + * + * Read an unsigned 24 bit big endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int24_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint32 to store the result + * + * Read a signed 24 bit big endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint24_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint32 to store the result + * + * Read an unsigned 24 bit big endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int24_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint32 to store the result + * + * Read a signed 24 bit big endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + + +/** + * fpi_byte_reader_get_uint32_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint32 to store the result + * + * Read an unsigned 32 bit little endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int32_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint32 to store the result + * + * Read a signed 32 bit little endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint32_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint32 to store the result + * + * Read an unsigned 32 bit little endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int32_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint32 to store the result + * + * Read a signed 32 bit little endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_uint32_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint32 to store the result + * + * Read an unsigned 32 bit big endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int32_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint32 to store the result + * + * Read a signed 32 bit big endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint32_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint32 to store the result + * + * Read an unsigned 32 bit big endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int32_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint32 to store the result + * + * Read a signed 32 bit big endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_uint64_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint64 to store the result + * + * Read an unsigned 64 bit little endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int64_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint64 to store the result + * + * Read a signed 64 bit little endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint64_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint64 to store the result + * + * Read an unsigned 64 bit little endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int64_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint64 to store the result + * + * Read a signed 64 bit little endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_uint64_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint64 to store the result + * + * Read an unsigned 64 bit big endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int64_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint64 to store the result + * + * Read a signed 64 bit big endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint64_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint64 to store the result + * + * Read an unsigned 64 bit big endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int64_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint64 to store the result + * + * Read a signed 64 bit big endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +#define FPI_BYTE_READER_PEEK_GET(bits,type,name) \ +gboolean \ +fpi_byte_reader_get_##name (FpiByteReader * reader, type * val) \ +{ \ + return fpi_byte_reader_get_##name##_inline (reader, val); \ +} \ +\ +gboolean \ +fpi_byte_reader_peek_##name (const FpiByteReader * reader, type * val) \ +{ \ + return fpi_byte_reader_peek_##name##_inline (reader, val); \ +} + +/* *INDENT-OFF* */ + +FPI_BYTE_READER_PEEK_GET(8,guint8,uint8) +FPI_BYTE_READER_PEEK_GET(8,gint8,int8) + +FPI_BYTE_READER_PEEK_GET(16,guint16,uint16_le) +FPI_BYTE_READER_PEEK_GET(16,guint16,uint16_be) +FPI_BYTE_READER_PEEK_GET(16,gint16,int16_le) +FPI_BYTE_READER_PEEK_GET(16,gint16,int16_be) + +FPI_BYTE_READER_PEEK_GET(24,guint32,uint24_le) +FPI_BYTE_READER_PEEK_GET(24,guint32,uint24_be) +FPI_BYTE_READER_PEEK_GET(24,gint32,int24_le) +FPI_BYTE_READER_PEEK_GET(24,gint32,int24_be) + +FPI_BYTE_READER_PEEK_GET(32,guint32,uint32_le) +FPI_BYTE_READER_PEEK_GET(32,guint32,uint32_be) +FPI_BYTE_READER_PEEK_GET(32,gint32,int32_le) +FPI_BYTE_READER_PEEK_GET(32,gint32,int32_be) + +FPI_BYTE_READER_PEEK_GET(64,guint64,uint64_le) +FPI_BYTE_READER_PEEK_GET(64,guint64,uint64_be) +FPI_BYTE_READER_PEEK_GET(64,gint64,int64_le) +FPI_BYTE_READER_PEEK_GET(64,gint64,int64_be) + +/** + * fpi_byte_reader_get_float32_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gfloat to store the result + * + * Read a 32 bit little endian floating point value into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_float32_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gfloat to store the result + * + * Read a 32 bit little endian floating point value into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_float32_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gfloat to store the result + * + * Read a 32 bit big endian floating point value into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_float32_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gfloat to store the result + * + * Read a 32 bit big endian floating point value into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_float64_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gdouble to store the result + * + * Read a 64 bit little endian floating point value into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_float64_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gdouble to store the result + * + * Read a 64 bit little endian floating point value into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_float64_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gdouble to store the result + * + * Read a 64 bit big endian floating point value into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_float64_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gdouble to store the result + * + * Read a 64 bit big endian floating point value into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +FPI_BYTE_READER_PEEK_GET(32,gfloat,float32_le) +FPI_BYTE_READER_PEEK_GET(32,gfloat,float32_be) +FPI_BYTE_READER_PEEK_GET(64,gdouble,float64_le) +FPI_BYTE_READER_PEEK_GET(64,gdouble,float64_be) + +/* *INDENT-ON* */ + +/** + * fpi_byte_reader_get_data: + * @reader: a #FpiByteReader instance + * @size: Size in bytes + * @val: (out) (transfer none) (array length=size): address of a + * #guint8 pointer variable in which to store the result + * + * Returns a constant pointer to the current data + * position if at least @size bytes are left and + * updates the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ +gboolean +fpi_byte_reader_get_data (FpiByteReader * reader, guint size, + const guint8 ** val) +{ + return fpi_byte_reader_get_data_inline (reader, size, val); +} + +/** + * fpi_byte_reader_peek_data: + * @reader: a #FpiByteReader instance + * @size: Size in bytes + * @val: (out) (transfer none) (array length=size): address of a + * #guint8 pointer variable in which to store the result + * + * Returns a constant pointer to the current data + * position if at least @size bytes are left and + * keeps the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ +gboolean +fpi_byte_reader_peek_data (const FpiByteReader * reader, guint size, + const guint8 ** val) +{ + return fpi_byte_reader_peek_data_inline (reader, size, val); +} + +/** + * fpi_byte_reader_dup_data: + * @reader: a #FpiByteReader instance + * @size: Size in bytes + * @val: (out) (transfer full) (array length=size): address of a + * #guint8 pointer variable in which to store the result + * + * Free-function: g_free + * + * Returns a newly-allocated copy of the current data + * position if at least @size bytes are left and + * updates the current position. Free with g_free() when no longer needed. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ +gboolean +fpi_byte_reader_dup_data (FpiByteReader * reader, guint size, guint8 ** val) +{ + return fpi_byte_reader_dup_data_inline (reader, size, val); +} + +/* Special optimized scan for mask 0xffffff00 and pattern 0x00000100 */ +static inline gint +_scan_for_start_code (const guint8 * data, guint size) +{ + guint8 *pdata = (guint8 *) data; + guint8 *pend = (guint8 *) (data + size - 4); + + while (pdata <= pend) { + if (pdata[2] > 1) { + pdata += 3; + } else if (pdata[1]) { + pdata += 2; + } else if (pdata[0] || pdata[2] != 1) { + pdata++; + } else { + return (pdata - data); + } + } + + /* nothing found */ + return -1; +} + +static inline guint +_masked_scan_uint32_peek (const FpiByteReader * reader, + guint32 mask, guint32 pattern, guint offset, guint size, guint32 * value) +{ + const guint8 *data; + guint32 state; + guint i; + + g_return_val_if_fail (size > 0, -1); + g_return_val_if_fail ((guint64) offset + size <= reader->size - reader->byte, + -1); + + /* we can't find the pattern with less than 4 bytes */ + if (G_UNLIKELY (size < 4)) + return -1; + + data = reader->data + reader->byte + offset; + + /* Handle special case found in MPEG and H264 */ + if ((pattern == 0x00000100) && (mask == 0xffffff00)) { + gint ret = _scan_for_start_code (data, size); + + if (ret == -1) + return ret; + + if (value != NULL) + *value = (1 << 8) | data[ret + 3]; + + return ret + offset; + } + + /* set the state to something that does not match */ + state = ~pattern; + + /* now find data */ + for (i = 0; i < size; i++) { + /* throw away one byte and move in the next byte */ + state = ((state << 8) | data[i]); + if (G_UNLIKELY ((state & mask) == pattern)) { + /* we have a match but we need to have skipped at + * least 4 bytes to fill the state. */ + if (G_LIKELY (i >= 3)) { + if (value) + *value = state; + return offset + i - 3; + } + } + } + + /* nothing found */ + return -1; +} + + +/** + * fpi_byte_reader_masked_scan_uint32: + * @reader: a #FpiByteReader + * @mask: mask to apply to data before matching against @pattern + * @pattern: pattern to match (after mask is applied) + * @offset: offset from which to start scanning, relative to the current + * position + * @size: number of bytes to scan from offset + * + * Scan for pattern @pattern with applied mask @mask in the byte reader data, + * starting from offset @offset relative to the current position. + * + * The bytes in @pattern and @mask are interpreted left-to-right, regardless + * of endianness. All four bytes of the pattern must be present in the + * byte reader data for it to match, even if the first or last bytes are masked + * out. + * + * It is an error to call this function without making sure that there is + * enough data (offset+size bytes) in the byte reader. + * + * Returns: offset of the first match, or -1 if no match was found. + * + * Example: + * |[ + * // Assume the reader contains 0x00 0x01 0x02 ... 0xfe 0xff + * + * fpi_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0x00010203, 0, 256); + * // -> returns 0 + * fpi_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0x00010203, 1, 255); + * // -> returns -1 + * fpi_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0x01020304, 1, 255); + * // -> returns 1 + * fpi_byte_reader_masked_scan_uint32 (reader, 0xffff, 0x0001, 0, 256); + * // -> returns -1 + * fpi_byte_reader_masked_scan_uint32 (reader, 0xffff, 0x0203, 0, 256); + * // -> returns 0 + * fpi_byte_reader_masked_scan_uint32 (reader, 0xffff0000, 0x02030000, 0, 256); + * // -> returns 2 + * fpi_byte_reader_masked_scan_uint32 (reader, 0xffff0000, 0x02030000, 0, 4); + * // -> returns -1 + * ]| + */ +guint +fpi_byte_reader_masked_scan_uint32 (const FpiByteReader * reader, guint32 mask, + guint32 pattern, guint offset, guint size) +{ + return _masked_scan_uint32_peek (reader, mask, pattern, offset, size, NULL); +} + +/** + * fpi_byte_reader_masked_scan_uint32_peek: + * @reader: a #FpiByteReader + * @mask: mask to apply to data before matching against @pattern + * @pattern: pattern to match (after mask is applied) + * @offset: offset from which to start scanning, relative to the current + * position + * @size: number of bytes to scan from offset + * @value: (out): pointer to uint32 to return matching data + * + * Scan for pattern @pattern with applied mask @mask in the byte reader data, + * starting from offset @offset relative to the current position. + * + * The bytes in @pattern and @mask are interpreted left-to-right, regardless + * of endianness. All four bytes of the pattern must be present in the + * byte reader data for it to match, even if the first or last bytes are masked + * out. + * + * It is an error to call this function without making sure that there is + * enough data (offset+size bytes) in the byte reader. + * + * Returns: offset of the first match, or -1 if no match was found. + * + * Since: 1.6 + */ +guint +fpi_byte_reader_masked_scan_uint32_peek (const FpiByteReader * reader, + guint32 mask, guint32 pattern, guint offset, guint size, guint32 * value) +{ + return _masked_scan_uint32_peek (reader, mask, pattern, offset, size, value); +} + +#define FPI_BYTE_READER_SCAN_STRING(bits) \ +static guint \ +fpi_byte_reader_scan_string_utf##bits (const FpiByteReader * reader) \ +{ \ + guint len, off, max_len; \ + \ + max_len = (reader->size - reader->byte) / sizeof (guint##bits); \ + \ + /* need at least a single NUL terminator */ \ + if (max_len < 1) \ + return 0; \ + \ + len = 0; \ + off = reader->byte; \ + /* endianness does not matter if we are looking for a NUL terminator */ \ + while (FP_READ_UINT##bits##_LE (&reader->data[off]) != 0) { \ + ++len; \ + off += sizeof (guint##bits); \ + /* have we reached the end without finding a NUL terminator? */ \ + if (len == max_len) \ + return 0; \ + } \ + /* return size in bytes including the NUL terminator (hence the +1) */ \ + return (len + 1) * sizeof (guint##bits); \ +} + +#define FP_READ_UINT8_LE FP_READ_UINT8 +FPI_BYTE_READER_SCAN_STRING (8); +#undef FP_READ_UINT8_LE +FPI_BYTE_READER_SCAN_STRING (16); +FPI_BYTE_READER_SCAN_STRING (32); + +#define FPI_BYTE_READER_SKIP_STRING(bits) \ +gboolean \ +fpi_byte_reader_skip_string_utf##bits (FpiByteReader * reader) \ +{ \ + guint size; /* size in bytes including the terminator */ \ + \ + g_return_val_if_fail (reader != NULL, FALSE); \ + \ + size = fpi_byte_reader_scan_string_utf##bits (reader); \ + reader->byte += size; \ + return (size > 0); \ +} + +/** + * fpi_byte_reader_skip_string: + * @reader: a #FpiByteReader instance + * + * Skips a NUL-terminated string in the #FpiByteReader instance, advancing + * the current position to the byte after the string. This will work for + * any NUL-terminated string with a character width of 8 bits, so ASCII, + * UTF-8, ISO-8859-N etc. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Returns: %TRUE if a string could be skipped, %FALSE otherwise. + */ +/** + * fpi_byte_reader_skip_string_utf8: + * @reader: a #FpiByteReader instance + * + * Skips a NUL-terminated string in the #FpiByteReader instance, advancing + * the current position to the byte after the string. This will work for + * any NUL-terminated string with a character width of 8 bits, so ASCII, + * UTF-8, ISO-8859-N etc. No input checking for valid UTF-8 is done. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Returns: %TRUE if a string could be skipped, %FALSE otherwise. + */ +FPI_BYTE_READER_SKIP_STRING (8); + +/** + * fpi_byte_reader_skip_string_utf16: + * @reader: a #FpiByteReader instance + * + * Skips a NUL-terminated UTF-16 string in the #FpiByteReader instance, + * advancing the current position to the byte after the string. + * + * No input checking for valid UTF-16 is done. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Returns: %TRUE if a string could be skipped, %FALSE otherwise. + */ +FPI_BYTE_READER_SKIP_STRING (16); + +/** + * fpi_byte_reader_skip_string_utf32: + * @reader: a #FpiByteReader instance + * + * Skips a NUL-terminated UTF-32 string in the #FpiByteReader instance, + * advancing the current position to the byte after the string. + * + * No input checking for valid UTF-32 is done. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Returns: %TRUE if a string could be skipped, %FALSE otherwise. + */ +FPI_BYTE_READER_SKIP_STRING (32); + +/** + * fpi_byte_reader_peek_string: + * @reader: a #FpiByteReader instance + * @str: (out) (transfer none) (array zero-terminated=1): address of a + * #gchar pointer variable in which to store the result + * + * Returns a constant pointer to the current data position if there is + * a NUL-terminated string in the data (this could be just a NUL terminator). + * The current position will be maintained. This will work for any + * NUL-terminated string with a character width of 8 bits, so ASCII, + * UTF-8, ISO-8859-N etc. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Returns: %TRUE if a string could be skipped, %FALSE otherwise. + */ +/** + * fpi_byte_reader_peek_string_utf8: + * @reader: a #FpiByteReader instance + * @str: (out) (transfer none) (array zero-terminated=1): address of a + * #gchar pointer variable in which to store the result + * + * Returns a constant pointer to the current data position if there is + * a NUL-terminated string in the data (this could be just a NUL terminator). + * The current position will be maintained. This will work for any + * NUL-terminated string with a character width of 8 bits, so ASCII, + * UTF-8, ISO-8859-N etc. + * + * No input checking for valid UTF-8 is done. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Returns: %TRUE if a string could be skipped, %FALSE otherwise. + */ +gboolean +fpi_byte_reader_peek_string_utf8 (const FpiByteReader * reader, + const gchar ** str) +{ + g_return_val_if_fail (reader != NULL, FALSE); + g_return_val_if_fail (str != NULL, FALSE); + + if (fpi_byte_reader_scan_string_utf8 (reader) > 0) { + *str = (const gchar *) (reader->data + reader->byte); + } else { + *str = NULL; + } + return (*str != NULL); +} + +/** + * fpi_byte_reader_get_string_utf8: + * @reader: a #FpiByteReader instance + * @str: (out) (transfer none) (array zero-terminated=1): address of a + * #gchar pointer variable in which to store the result + * + * Returns a constant pointer to the current data position if there is + * a NUL-terminated string in the data (this could be just a NUL terminator), + * advancing the current position to the byte after the string. This will work + * for any NUL-terminated string with a character width of 8 bits, so ASCII, + * UTF-8, ISO-8859-N etc. + * + * No input checking for valid UTF-8 is done. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Returns: %TRUE if a string could be found, %FALSE otherwise. + */ +gboolean +fpi_byte_reader_get_string_utf8 (FpiByteReader * reader, const gchar ** str) +{ + guint size; /* size in bytes including the terminator */ + + g_return_val_if_fail (reader != NULL, FALSE); + g_return_val_if_fail (str != NULL, FALSE); + + size = fpi_byte_reader_scan_string_utf8 (reader); + if (size == 0) { + *str = NULL; + return FALSE; + } + + *str = (const gchar *) (reader->data + reader->byte); + reader->byte += size; + return TRUE; +} + +#define FPI_BYTE_READER_DUP_STRING(bits,type) \ +gboolean \ +fpi_byte_reader_dup_string_utf##bits (FpiByteReader * reader, type ** str) \ +{ \ + guint size; /* size in bytes including the terminator */ \ + \ + g_return_val_if_fail (reader != NULL, FALSE); \ + g_return_val_if_fail (str != NULL, FALSE); \ + \ + size = fpi_byte_reader_scan_string_utf##bits (reader); \ + if (size == 0) { \ + *str = NULL; \ + return FALSE; \ + } \ + *str = g_memdup (reader->data + reader->byte, size); \ + reader->byte += size; \ + return TRUE; \ +} + +/** + * fpi_byte_reader_dup_string_utf8: + * @reader: a #FpiByteReader instance + * @str: (out) (transfer full) (array zero-terminated=1): address of a + * #gchar pointer variable in which to store the result + * + * Free-function: g_free + * + * FIXME:Reads (copies) a NUL-terminated string in the #FpiByteReader instance, + * advancing the current position to the byte after the string. This will work + * for any NUL-terminated string with a character width of 8 bits, so ASCII, + * UTF-8, ISO-8859-N etc. No input checking for valid UTF-8 is done. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Returns: %TRUE if a string could be read into @str, %FALSE otherwise. The + * string put into @str must be freed with g_free() when no longer needed. + */ +FPI_BYTE_READER_DUP_STRING (8, gchar); + +/** + * fpi_byte_reader_dup_string_utf16: + * @reader: a #FpiByteReader instance + * @str: (out) (transfer full) (array zero-terminated=1): address of a + * #guint16 pointer variable in which to store the result + * + * Free-function: g_free + * + * Returns a newly-allocated copy of the current data position if there is + * a NUL-terminated UTF-16 string in the data (this could be an empty string + * as well), and advances the current position. + * + * No input checking for valid UTF-16 is done. This function is endianness + * agnostic - you should not assume the UTF-16 characters are in host + * endianness. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Note: there is no peek or get variant of this function to ensure correct + * byte alignment of the UTF-16 string. + * + * Returns: %TRUE if a string could be read, %FALSE otherwise. The + * string put into @str must be freed with g_free() when no longer needed. + */ +FPI_BYTE_READER_DUP_STRING (16, guint16); + +/** + * fpi_byte_reader_dup_string_utf32: + * @reader: a #FpiByteReader instance + * @str: (out) (transfer full) (array zero-terminated=1): address of a + * #guint32 pointer variable in which to store the result + * + * Free-function: g_free + * + * Returns a newly-allocated copy of the current data position if there is + * a NUL-terminated UTF-32 string in the data (this could be an empty string + * as well), and advances the current position. + * + * No input checking for valid UTF-32 is done. This function is endianness + * agnostic - you should not assume the UTF-32 characters are in host + * endianness. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Note: there is no peek or get variant of this function to ensure correct + * byte alignment of the UTF-32 string. + * + * Returns: %TRUE if a string could be read, %FALSE otherwise. The + * string put into @str must be freed with g_free() when no longer needed. + */ +FPI_BYTE_READER_DUP_STRING (32, guint32); diff --git a/libfprint/fpi-byte-reader.h b/libfprint/fpi-byte-reader.h new file mode 100644 index 00000000..0a661c6c --- /dev/null +++ b/libfprint/fpi-byte-reader.h @@ -0,0 +1,680 @@ +/* GStreamer byte reader + * + * Copyright (C) 2008 Sebastian Dröge . + * Copyright (C) 2009 Tim-Philipp Müller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __FPI_BYTE_READER_H__ +#define __FPI_BYTE_READER_H__ + +#include +#include "fpi-byte-utils.h" + +G_BEGIN_DECLS + +#define FPI_BYTE_READER(reader) ((FpiByteReader *) (reader)) + +/** + * FpiByteReader: + * @data: (array length=size): Data from which the bit reader will + * read + * @size: Size of @data in bytes + * @byte: Current byte position + * + * A byte reader instance. + */ +typedef struct { + const guint8 *data; + guint size; + + guint byte; /* Byte position */ + + /* < private > */ +} FpiByteReader; + + +FpiByteReader * fpi_byte_reader_new (const guint8 *data, guint size) G_GNUC_MALLOC; + + +void fpi_byte_reader_free (FpiByteReader *reader); + + +void fpi_byte_reader_init (FpiByteReader *reader, const guint8 *data, guint size); + + +gboolean fpi_byte_reader_peek_sub_reader (FpiByteReader * reader, + FpiByteReader * sub_reader, + guint size); + +gboolean fpi_byte_reader_get_sub_reader (FpiByteReader * reader, + FpiByteReader * sub_reader, + guint size); + +gboolean fpi_byte_reader_set_pos (FpiByteReader *reader, guint pos); + + +guint fpi_byte_reader_get_pos (const FpiByteReader *reader); + + +guint fpi_byte_reader_get_remaining (const FpiByteReader *reader); + + +guint fpi_byte_reader_get_size (const FpiByteReader *reader); + + +gboolean fpi_byte_reader_skip (FpiByteReader *reader, guint nbytes); + + +gboolean fpi_byte_reader_get_uint8 (FpiByteReader *reader, guint8 *val); + + +gboolean fpi_byte_reader_get_int8 (FpiByteReader *reader, gint8 *val); + + +gboolean fpi_byte_reader_get_uint16_le (FpiByteReader *reader, guint16 *val); + + +gboolean fpi_byte_reader_get_int16_le (FpiByteReader *reader, gint16 *val); + + +gboolean fpi_byte_reader_get_uint16_be (FpiByteReader *reader, guint16 *val); + + +gboolean fpi_byte_reader_get_int16_be (FpiByteReader *reader, gint16 *val); + + +gboolean fpi_byte_reader_get_uint24_le (FpiByteReader *reader, guint32 *val); + + +gboolean fpi_byte_reader_get_int24_le (FpiByteReader *reader, gint32 *val); + + +gboolean fpi_byte_reader_get_uint24_be (FpiByteReader *reader, guint32 *val); + + +gboolean fpi_byte_reader_get_int24_be (FpiByteReader *reader, gint32 *val); + + +gboolean fpi_byte_reader_get_uint32_le (FpiByteReader *reader, guint32 *val); + + +gboolean fpi_byte_reader_get_int32_le (FpiByteReader *reader, gint32 *val); + + +gboolean fpi_byte_reader_get_uint32_be (FpiByteReader *reader, guint32 *val); + + +gboolean fpi_byte_reader_get_int32_be (FpiByteReader *reader, gint32 *val); + + +gboolean fpi_byte_reader_get_uint64_le (FpiByteReader *reader, guint64 *val); + + +gboolean fpi_byte_reader_get_int64_le (FpiByteReader *reader, gint64 *val); + + +gboolean fpi_byte_reader_get_uint64_be (FpiByteReader *reader, guint64 *val); + + +gboolean fpi_byte_reader_get_int64_be (FpiByteReader *reader, gint64 *val); + + +gboolean fpi_byte_reader_peek_uint8 (const FpiByteReader *reader, guint8 *val); + + +gboolean fpi_byte_reader_peek_int8 (const FpiByteReader *reader, gint8 *val); + + +gboolean fpi_byte_reader_peek_uint16_le (const FpiByteReader *reader, guint16 *val); + + +gboolean fpi_byte_reader_peek_int16_le (const FpiByteReader *reader, gint16 *val); + + +gboolean fpi_byte_reader_peek_uint16_be (const FpiByteReader *reader, guint16 *val); + + +gboolean fpi_byte_reader_peek_int16_be (const FpiByteReader *reader, gint16 *val); + + +gboolean fpi_byte_reader_peek_uint24_le (const FpiByteReader *reader, guint32 *val); + + +gboolean fpi_byte_reader_peek_int24_le (const FpiByteReader *reader, gint32 *val); + + +gboolean fpi_byte_reader_peek_uint24_be (const FpiByteReader *reader, guint32 *val); + + +gboolean fpi_byte_reader_peek_int24_be (const FpiByteReader *reader, gint32 *val); + + +gboolean fpi_byte_reader_peek_uint32_le (const FpiByteReader *reader, guint32 *val); + + +gboolean fpi_byte_reader_peek_int32_le (const FpiByteReader *reader, gint32 *val); + + +gboolean fpi_byte_reader_peek_uint32_be (const FpiByteReader *reader, guint32 *val); + + +gboolean fpi_byte_reader_peek_int32_be (const FpiByteReader *reader, gint32 *val); + + +gboolean fpi_byte_reader_peek_uint64_le (const FpiByteReader *reader, guint64 *val); + + +gboolean fpi_byte_reader_peek_int64_le (const FpiByteReader *reader, gint64 *val); + + +gboolean fpi_byte_reader_peek_uint64_be (const FpiByteReader *reader, guint64 *val); + + +gboolean fpi_byte_reader_peek_int64_be (const FpiByteReader *reader, gint64 *val); + + +gboolean fpi_byte_reader_get_float32_le (FpiByteReader *reader, gfloat *val); + + +gboolean fpi_byte_reader_get_float32_be (FpiByteReader *reader, gfloat *val); + + +gboolean fpi_byte_reader_get_float64_le (FpiByteReader *reader, gdouble *val); + + +gboolean fpi_byte_reader_get_float64_be (FpiByteReader *reader, gdouble *val); + + +gboolean fpi_byte_reader_peek_float32_le (const FpiByteReader *reader, gfloat *val); + + +gboolean fpi_byte_reader_peek_float32_be (const FpiByteReader *reader, gfloat *val); + + +gboolean fpi_byte_reader_peek_float64_le (const FpiByteReader *reader, gdouble *val); + + +gboolean fpi_byte_reader_peek_float64_be (const FpiByteReader *reader, gdouble *val); + + +gboolean fpi_byte_reader_dup_data (FpiByteReader * reader, guint size, guint8 ** val); + + +gboolean fpi_byte_reader_get_data (FpiByteReader * reader, guint size, const guint8 ** val); + + +gboolean fpi_byte_reader_peek_data (const FpiByteReader * reader, guint size, const guint8 ** val); + +#define fpi_byte_reader_dup_string(reader,str) \ + fpi_byte_reader_dup_string_utf8(reader,str) + + +gboolean fpi_byte_reader_dup_string_utf8 (FpiByteReader * reader, gchar ** str); + + +gboolean fpi_byte_reader_dup_string_utf16 (FpiByteReader * reader, guint16 ** str); + + +gboolean fpi_byte_reader_dup_string_utf32 (FpiByteReader * reader, guint32 ** str); + +#define fpi_byte_reader_skip_string(reader) \ + fpi_byte_reader_skip_string_utf8(reader) + + +gboolean fpi_byte_reader_skip_string_utf8 (FpiByteReader * reader); + + +gboolean fpi_byte_reader_skip_string_utf16 (FpiByteReader * reader); + + +gboolean fpi_byte_reader_skip_string_utf32 (FpiByteReader * reader); + +#define fpi_byte_reader_get_string(reader,str) \ + fpi_byte_reader_get_string_utf8(reader,str) + +#define fpi_byte_reader_peek_string(reader,str) \ + fpi_byte_reader_peek_string_utf8(reader,str) + + +gboolean fpi_byte_reader_get_string_utf8 (FpiByteReader * reader, const gchar ** str); + + +gboolean fpi_byte_reader_peek_string_utf8 (const FpiByteReader * reader, const gchar ** str); + + +guint fpi_byte_reader_masked_scan_uint32 (const FpiByteReader * reader, + guint32 mask, + guint32 pattern, + guint offset, + guint size); + +guint fpi_byte_reader_masked_scan_uint32_peek (const FpiByteReader * reader, + guint32 mask, + guint32 pattern, + guint offset, + guint size, + guint32 * value); + +/** + * FPI_BYTE_READER_INIT: + * @data: Data from which the #FpiByteReader should read + * @size: Size of @data in bytes + * + * A #FpiByteReader must be initialized with this macro, before it can be + * used. This macro can used be to initialize a variable, but it cannot + * be assigned to a variable. In that case you have to use + * fpi_byte_reader_init(). + */ +#define FPI_BYTE_READER_INIT(data, size) {data, size, 0} + +/* unchecked variants */ +static inline void +fpi_byte_reader_skip_unchecked (FpiByteReader * reader, guint nbytes) +{ + reader->byte += nbytes; +} + +#define __FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(bits,type,lower,upper,adj) \ +\ +static inline type \ +fpi_byte_reader_peek_##lower##_unchecked (const FpiByteReader * reader) \ +{ \ + type val = (type) FP_READ_##upper (reader->data + reader->byte); \ + adj \ + return val; \ +} \ +\ +static inline type \ +fpi_byte_reader_get_##lower##_unchecked (FpiByteReader * reader) \ +{ \ + type val = fpi_byte_reader_peek_##lower##_unchecked (reader); \ + reader->byte += bits / 8; \ + return val; \ +} + +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(8,guint8,uint8,UINT8,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(8,gint8,int8,UINT8,/* */) + +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(16,guint16,uint16_le,UINT16_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(16,guint16,uint16_be,UINT16_BE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(16,gint16,int16_le,UINT16_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(16,gint16,int16_be,UINT16_BE,/* */) + +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(32,guint32,uint32_le,UINT32_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(32,guint32,uint32_be,UINT32_BE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(32,gint32,int32_le,UINT32_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(32,gint32,int32_be,UINT32_BE,/* */) + +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(24,guint32,uint24_le,UINT24_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(24,guint32,uint24_be,UINT24_BE,/* */) + +/* fix up the sign for 24-bit signed ints stored in 32-bit signed ints */ +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(24,gint32,int24_le,UINT24_LE, + if (val & 0x00800000) val |= 0xff000000;) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(24,gint32,int24_be,UINT24_BE, + if (val & 0x00800000) val |= 0xff000000;) + +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(64,guint64,uint64_le,UINT64_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(64,guint64,uint64_be,UINT64_BE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(64,gint64,int64_le,UINT64_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(64,gint64,int64_be,UINT64_BE,/* */) + +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(32,gfloat,float32_le,FLOAT_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(32,gfloat,float32_be,FLOAT_BE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(64,gdouble,float64_le,DOUBLE_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(64,gdouble,float64_be,DOUBLE_BE,/* */) + +#undef __GET_PEEK_BITS_UNCHECKED + +static inline const guint8 * +fpi_byte_reader_peek_data_unchecked (const FpiByteReader * reader) +{ + return (const guint8 *) (reader->data + reader->byte); +} + +static inline const guint8 * +fpi_byte_reader_get_data_unchecked (FpiByteReader * reader, guint size) +{ + const guint8 *data; + + data = fpi_byte_reader_peek_data_unchecked (reader); + fpi_byte_reader_skip_unchecked (reader, size); + return data; +} + +static inline guint8 * +fpi_byte_reader_dup_data_unchecked (FpiByteReader * reader, guint size) +{ + gconstpointer data = fpi_byte_reader_get_data_unchecked (reader, size); + return (guint8 *) g_memdup (data, size); +} + +/* Unchecked variants that should not be used */ +static inline guint +fpi_byte_reader_get_pos_unchecked (const FpiByteReader * reader) +{ + return reader->byte; +} + +static inline guint +fpi_byte_reader_get_remaining_unchecked (const FpiByteReader * reader) +{ + return reader->size - reader->byte; +} + +static inline guint +fpi_byte_reader_get_size_unchecked (const FpiByteReader * reader) +{ + return reader->size; +} + +/* inlined variants (do not use directly) */ + +static inline guint +fpi_byte_reader_get_remaining_inline (const FpiByteReader * reader) +{ + g_return_val_if_fail (reader != NULL, 0); + + return fpi_byte_reader_get_remaining_unchecked (reader); +} + +static inline guint +fpi_byte_reader_get_size_inline (const FpiByteReader * reader) +{ + g_return_val_if_fail (reader != NULL, 0); + + return fpi_byte_reader_get_size_unchecked (reader); +} + +#define __FPI_BYTE_READER_GET_PEEK_BITS_INLINE(bits,type,name) \ +\ +static inline gboolean \ +fpi_byte_reader_peek_##name##_inline (const FpiByteReader * reader, type * val) \ +{ \ + g_return_val_if_fail (reader != NULL, FALSE); \ + g_return_val_if_fail (val != NULL, FALSE); \ + \ + if (fpi_byte_reader_get_remaining_unchecked (reader) < (bits / 8)) \ + return FALSE; \ +\ + *val = fpi_byte_reader_peek_##name##_unchecked (reader); \ + return TRUE; \ +} \ +\ +static inline gboolean \ +fpi_byte_reader_get_##name##_inline (FpiByteReader * reader, type * val) \ +{ \ + g_return_val_if_fail (reader != NULL, FALSE); \ + g_return_val_if_fail (val != NULL, FALSE); \ + \ + if (fpi_byte_reader_get_remaining_unchecked (reader) < (bits / 8)) \ + return FALSE; \ +\ + *val = fpi_byte_reader_get_##name##_unchecked (reader); \ + return TRUE; \ +} + +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(8,guint8,uint8) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(8,gint8,int8) + +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(16,guint16,uint16_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(16,guint16,uint16_be) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(16,gint16,int16_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(16,gint16,int16_be) + +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(32,guint32,uint32_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(32,guint32,uint32_be) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(32,gint32,int32_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(32,gint32,int32_be) + +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(24,guint32,uint24_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(24,guint32,uint24_be) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(24,gint32,int24_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(24,gint32,int24_be) + +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(64,guint64,uint64_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(64,guint64,uint64_be) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(64,gint64,int64_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(64,gint64,int64_be) + +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(32,gfloat,float32_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(32,gfloat,float32_be) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(64,gdouble,float64_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(64,gdouble,float64_be) + +#undef __FPI_BYTE_READER_GET_PEEK_BITS_INLINE + +#ifndef FPI_BYTE_READER_DISABLE_INLINES + +#define fpi_byte_reader_init(reader,data,size) \ + fpi_byte_reader_init_inline(reader,data,size) + +#define fpi_byte_reader_get_remaining(reader) \ + fpi_byte_reader_get_remaining_inline(reader) + +#define fpi_byte_reader_get_size(reader) \ + fpi_byte_reader_get_size_inline(reader) + +#define fpi_byte_reader_get_pos(reader) \ + fpi_byte_reader_get_pos_inline(reader) + +/* we use defines here so we can add the G_LIKELY() */ +#define fpi_byte_reader_get_uint8(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint8_inline(reader,val)) +#define fpi_byte_reader_get_int8(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int8_inline(reader,val)) +#define fpi_byte_reader_get_uint16_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint16_le_inline(reader,val)) +#define fpi_byte_reader_get_int16_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int16_le_inline(reader,val)) +#define fpi_byte_reader_get_uint16_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint16_be_inline(reader,val)) +#define fpi_byte_reader_get_int16_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int16_be_inline(reader,val)) +#define fpi_byte_reader_get_uint24_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint24_le_inline(reader,val)) +#define fpi_byte_reader_get_int24_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int24_le_inline(reader,val)) +#define fpi_byte_reader_get_uint24_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint24_be_inline(reader,val)) +#define fpi_byte_reader_get_int24_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int24_be_inline(reader,val)) +#define fpi_byte_reader_get_uint32_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint32_le_inline(reader,val)) +#define fpi_byte_reader_get_int32_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int32_le_inline(reader,val)) +#define fpi_byte_reader_get_uint32_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint32_be_inline(reader,val)) +#define fpi_byte_reader_get_int32_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int32_be_inline(reader,val)) +#define fpi_byte_reader_get_uint64_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint64_le_inline(reader,val)) +#define fpi_byte_reader_get_int64_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int64_le_inline(reader,val)) +#define fpi_byte_reader_get_uint64_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint64_be_inline(reader,val)) +#define fpi_byte_reader_get_int64_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int64_be_inline(reader,val)) + +#define fpi_byte_reader_peek_uint8(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint8_inline(reader,val)) +#define fpi_byte_reader_peek_int8(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int8_inline(reader,val)) +#define fpi_byte_reader_peek_uint16_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint16_le_inline(reader,val)) +#define fpi_byte_reader_peek_int16_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int16_le_inline(reader,val)) +#define fpi_byte_reader_peek_uint16_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint16_be_inline(reader,val)) +#define fpi_byte_reader_peek_int16_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int16_be_inline(reader,val)) +#define fpi_byte_reader_peek_uint24_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint24_le_inline(reader,val)) +#define fpi_byte_reader_peek_int24_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int24_le_inline(reader,val)) +#define fpi_byte_reader_peek_uint24_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint24_be_inline(reader,val)) +#define fpi_byte_reader_peek_int24_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int24_be_inline(reader,val)) +#define fpi_byte_reader_peek_uint32_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint32_le_inline(reader,val)) +#define fpi_byte_reader_peek_int32_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int32_le_inline(reader,val)) +#define fpi_byte_reader_peek_uint32_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint32_be_inline(reader,val)) +#define fpi_byte_reader_peek_int32_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int32_be_inline(reader,val)) +#define fpi_byte_reader_peek_uint64_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint64_le_inline(reader,val)) +#define fpi_byte_reader_peek_int64_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int64_le_inline(reader,val)) +#define fpi_byte_reader_peek_uint64_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint64_be_inline(reader,val)) +#define fpi_byte_reader_peek_int64_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int64_be_inline(reader,val)) + +#define fpi_byte_reader_get_float32_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_float32_le_inline(reader,val)) +#define fpi_byte_reader_get_float32_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_float32_be_inline(reader,val)) +#define fpi_byte_reader_get_float64_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_float64_le_inline(reader,val)) +#define fpi_byte_reader_get_float64_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_float64_be_inline(reader,val)) +#define fpi_byte_reader_peek_float32_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_float32_le_inline(reader,val)) +#define fpi_byte_reader_peek_float32_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_float32_be_inline(reader,val)) +#define fpi_byte_reader_peek_float64_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_float64_le_inline(reader,val)) +#define fpi_byte_reader_peek_float64_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_float64_be_inline(reader,val)) + +#endif /* FPI_BYTE_READER_DISABLE_INLINES */ + +static inline void +fpi_byte_reader_init_inline (FpiByteReader * reader, const guint8 * data, guint size) +{ + g_return_if_fail (reader != NULL); + + reader->data = data; + reader->size = size; + reader->byte = 0; +} + +static inline gboolean +fpi_byte_reader_peek_sub_reader_inline (FpiByteReader * reader, + FpiByteReader * sub_reader, guint size) +{ + g_return_val_if_fail (reader != NULL, FALSE); + g_return_val_if_fail (sub_reader != NULL, FALSE); + + if (fpi_byte_reader_get_remaining_unchecked (reader) < size) + return FALSE; + + sub_reader->data = reader->data + reader->byte; + sub_reader->byte = 0; + sub_reader->size = size; + return TRUE; +} + +static inline gboolean +fpi_byte_reader_get_sub_reader_inline (FpiByteReader * reader, + FpiByteReader * sub_reader, guint size) +{ + if (!fpi_byte_reader_peek_sub_reader_inline (reader, sub_reader, size)) + return FALSE; + fpi_byte_reader_skip_unchecked (reader, size); + return TRUE; +} + +static inline gboolean +fpi_byte_reader_dup_data_inline (FpiByteReader * reader, guint size, guint8 ** val) +{ + g_return_val_if_fail (reader != NULL, FALSE); + g_return_val_if_fail (val != NULL, FALSE); + + if (G_UNLIKELY (size > reader->size || fpi_byte_reader_get_remaining_unchecked (reader) < size)) + return FALSE; + + *val = fpi_byte_reader_dup_data_unchecked (reader, size); + return TRUE; +} + +static inline gboolean +fpi_byte_reader_get_data_inline (FpiByteReader * reader, guint size, const guint8 ** val) +{ + g_return_val_if_fail (reader != NULL, FALSE); + g_return_val_if_fail (val != NULL, FALSE); + + if (G_UNLIKELY (size > reader->size || fpi_byte_reader_get_remaining_unchecked (reader) < size)) + return FALSE; + + *val = fpi_byte_reader_get_data_unchecked (reader, size); + return TRUE; +} + +static inline gboolean +fpi_byte_reader_peek_data_inline (const FpiByteReader * reader, guint size, const guint8 ** val) +{ + g_return_val_if_fail (reader != NULL, FALSE); + g_return_val_if_fail (val != NULL, FALSE); + + if (G_UNLIKELY (size > reader->size || fpi_byte_reader_get_remaining_unchecked (reader) < size)) + return FALSE; + + *val = fpi_byte_reader_peek_data_unchecked (reader); + return TRUE; +} + +static inline guint +fpi_byte_reader_get_pos_inline (const FpiByteReader * reader) +{ + g_return_val_if_fail (reader != NULL, 0); + + return fpi_byte_reader_get_pos_unchecked (reader); +} + +static inline gboolean +fpi_byte_reader_skip_inline (FpiByteReader * reader, guint nbytes) +{ + g_return_val_if_fail (reader != NULL, FALSE); + + if (G_UNLIKELY (fpi_byte_reader_get_remaining_unchecked (reader) < nbytes)) + return FALSE; + + reader->byte += nbytes; + return TRUE; +} + +#ifndef FPI_BYTE_READER_DISABLE_INLINES + +#define fpi_byte_reader_dup_data(reader,size,val) \ + G_LIKELY(fpi_byte_reader_dup_data_inline(reader,size,val)) +#define fpi_byte_reader_get_data(reader,size,val) \ + G_LIKELY(fpi_byte_reader_get_data_inline(reader,size,val)) +#define fpi_byte_reader_peek_data(reader,size,val) \ + G_LIKELY(fpi_byte_reader_peek_data_inline(reader,size,val)) +#define fpi_byte_reader_skip(reader,nbytes) \ + G_LIKELY(fpi_byte_reader_skip_inline(reader,nbytes)) + +#endif /* FPI_BYTE_READER_DISABLE_INLINES */ + +G_END_DECLS + +#endif /* __FPI_BYTE_READER_H__ */ diff --git a/libfprint/fpi-byte-utils.h b/libfprint/fpi-byte-utils.h new file mode 100644 index 00000000..8a991212 --- /dev/null +++ b/libfprint/fpi-byte-utils.h @@ -0,0 +1,488 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * 2002 Thomas Vander Stichele + * + * gstutils.h: Header for various utility functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef __FP_UTILS_H__ +#define __FP_UTILS_H__ + +#include + +G_BEGIN_DECLS + +/* Define PUT and GET functions for unaligned memory */ +#define _FP_GET(__data, __idx, __size, __shift) \ + (((guint##__size) (((const guint8 *) (__data))[__idx])) << (__shift)) + +#define _FP_PUT(__data, __idx, __size, __shift, __num) \ + (((guint8 *) (__data))[__idx] = (((guint##__size) (__num)) >> (__shift)) & 0xff) + +#ifndef __GTK_DOC_IGNORE__ + +/** + * FP_READ_UINT64_BE: + * @data: memory location + * + * Read a 64 bit unsigned integer value in big endian format from the memory buffer. + */ + +/** + * FP_READ_UINT64_LE: + * @data: memory location + * + * Read a 64 bit unsigned integer value in little endian format from the memory buffer. + */ +#define _FP_READ_UINT64_BE(data) (_FP_GET (data, 0, 64, 56) | \ + _FP_GET (data, 1, 64, 48) | \ + _FP_GET (data, 2, 64, 40) | \ + _FP_GET (data, 3, 64, 32) | \ + _FP_GET (data, 4, 64, 24) | \ + _FP_GET (data, 5, 64, 16) | \ + _FP_GET (data, 6, 64, 8) | \ + _FP_GET (data, 7, 64, 0)) + +#define _FP_READ_UINT64_LE(data) (_FP_GET (data, 7, 64, 56) | \ + _FP_GET (data, 6, 64, 48) | \ + _FP_GET (data, 5, 64, 40) | \ + _FP_GET (data, 4, 64, 32) | \ + _FP_GET (data, 3, 64, 24) | \ + _FP_GET (data, 2, 64, 16) | \ + _FP_GET (data, 1, 64, 8) | \ + _FP_GET (data, 0, 64, 0)) + +#define FP_READ_UINT64_BE(data) _fpi_slow_read64_be((const guint8 *)(data)) +static inline guint64 _fpi_slow_read64_be (const guint8 * data) { + return _FP_READ_UINT64_BE (data); +} +#define FP_READ_UINT64_LE(data) _fpi_slow_read64_le((const guint8 *)(data)) +static inline guint64 _fpi_slow_read64_le (const guint8 * data) { + return _FP_READ_UINT64_LE (data); +} + +/** + * FP_READ_UINT32_BE: + * @data: memory location + * + * Read a 32 bit unsigned integer value in big endian format from the memory buffer. + */ + +/** + * FP_READ_UINT32_LE: + * @data: memory location + * + * Read a 32 bit unsigned integer value in little endian format from the memory buffer. + */ +#define _FP_READ_UINT32_BE(data) (_FP_GET (data, 0, 32, 24) | \ + _FP_GET (data, 1, 32, 16) | \ + _FP_GET (data, 2, 32, 8) | \ + _FP_GET (data, 3, 32, 0)) + +#define _FP_READ_UINT32_LE(data) (_FP_GET (data, 3, 32, 24) | \ + _FP_GET (data, 2, 32, 16) | \ + _FP_GET (data, 1, 32, 8) | \ + _FP_GET (data, 0, 32, 0)) + +#define FP_READ_UINT32_BE(data) _fpi_slow_read32_be((const guint8 *)(data)) +static inline guint32 _fpi_slow_read32_be (const guint8 * data) { + return _FP_READ_UINT32_BE (data); +} +#define FP_READ_UINT32_LE(data) _fpi_slow_read32_le((const guint8 *)(data)) +static inline guint32 _fpi_slow_read32_le (const guint8 * data) { + return _FP_READ_UINT32_LE (data); +} + +/** + * FP_READ_UINT24_BE: + * @data: memory location + * + * Read a 24 bit unsigned integer value in big endian format from the memory buffer. + */ +#define _FP_READ_UINT24_BE(data) (_FP_GET (data, 0, 32, 16) | \ + _FP_GET (data, 1, 32, 8) | \ + _FP_GET (data, 2, 32, 0)) + +#define FP_READ_UINT24_BE(data) _fpi_slow_read24_be((const guint8 *)(data)) +static inline guint32 _fpi_slow_read24_be (const guint8 * data) { + return _FP_READ_UINT24_BE (data); +} + +/** + * FP_READ_UINT24_LE: + * @data: memory location + * + * Read a 24 bit unsigned integer value in little endian format from the memory buffer. + */ +#define _FP_READ_UINT24_LE(data) (_FP_GET (data, 2, 32, 16) | \ + _FP_GET (data, 1, 32, 8) | \ + _FP_GET (data, 0, 32, 0)) + +#define FP_READ_UINT24_LE(data) _fpi_slow_read24_le((const guint8 *)(data)) +static inline guint32 _fpi_slow_read24_le (const guint8 * data) { + return _FP_READ_UINT24_LE (data); +} + +/** + * FP_READ_UINT16_BE: + * @data: memory location + * + * Read a 16 bit unsigned integer value in big endian format from the memory buffer. + */ +/** + * FP_READ_UINT16_LE: + * @data: memory location + * + * Read a 16 bit unsigned integer value in little endian format from the memory buffer. + */ +#define _FP_READ_UINT16_BE(data) (_FP_GET (data, 0, 16, 8) | \ + _FP_GET (data, 1, 16, 0)) + +#define _FP_READ_UINT16_LE(data) (_FP_GET (data, 1, 16, 8) | \ + _FP_GET (data, 0, 16, 0)) + +#define FP_READ_UINT16_BE(data) _fpi_slow_read16_be((const guint8 *)(data)) +static inline guint16 _fpi_slow_read16_be (const guint8 * data) { + return _FP_READ_UINT16_BE (data); +} +#define FP_READ_UINT16_LE(data) _fpi_slow_read16_le((const guint8 *)(data)) +static inline guint16 _fpi_slow_read16_le (const guint8 * data) { + return _FP_READ_UINT16_LE (data); +} + +/** + * FP_READ_UINT8: + * @data: memory location + * + * Read an 8 bit unsigned integer value from the memory buffer. + */ +#define FP_READ_UINT8(data) (_FP_GET (data, 0, 8, 0)) + +/** + * FP_WRITE_UINT64_BE: + * @data: memory location + * @val: value to store + * + * Store a 64 bit unsigned integer value in big endian format into the memory buffer. + */ +/** + * FP_WRITE_UINT64_LE: + * @data: memory location + * @val: value to store + * + * Store a 64 bit unsigned integer value in little endian format into the memory buffer. + */ +#define FP_WRITE_UINT64_BE(data,val) do { \ + gpointer __put_data = data; \ + guint64 __put_val = val; \ + _FP_PUT (__put_data, 0, 64, 56, __put_val); \ + _FP_PUT (__put_data, 1, 64, 48, __put_val); \ + _FP_PUT (__put_data, 2, 64, 40, __put_val); \ + _FP_PUT (__put_data, 3, 64, 32, __put_val); \ + _FP_PUT (__put_data, 4, 64, 24, __put_val); \ + _FP_PUT (__put_data, 5, 64, 16, __put_val); \ + _FP_PUT (__put_data, 6, 64, 8, __put_val); \ + _FP_PUT (__put_data, 7, 64, 0, __put_val); \ + } while (0) + +#define FP_WRITE_UINT64_LE(data,val) do { \ + gpointer __put_data = data; \ + guint64 __put_val = val; \ + _FP_PUT (__put_data, 0, 64, 0, __put_val); \ + _FP_PUT (__put_data, 1, 64, 8, __put_val); \ + _FP_PUT (__put_data, 2, 64, 16, __put_val); \ + _FP_PUT (__put_data, 3, 64, 24, __put_val); \ + _FP_PUT (__put_data, 4, 64, 32, __put_val); \ + _FP_PUT (__put_data, 5, 64, 40, __put_val); \ + _FP_PUT (__put_data, 6, 64, 48, __put_val); \ + _FP_PUT (__put_data, 7, 64, 56, __put_val); \ + } while (0) + +/** + * FP_WRITE_UINT32_BE: + * @data: memory location + * @val: value to store + * + * Store a 32 bit unsigned integer value in big endian format into the memory buffer. + */ +/** + * FP_WRITE_UINT32_LE: + * @data: memory location + * @val: value to store + * + * Store a 32 bit unsigned integer value in little endian format into the memory buffer. + */ +#define FP_WRITE_UINT32_BE(data,val) do { \ + gpointer __put_data = data; \ + guint32 __put_val = val; \ + _FP_PUT (__put_data, 0, 32, 24, __put_val); \ + _FP_PUT (__put_data, 1, 32, 16, __put_val); \ + _FP_PUT (__put_data, 2, 32, 8, __put_val); \ + _FP_PUT (__put_data, 3, 32, 0, __put_val); \ + } while (0) + +#define FP_WRITE_UINT32_LE(data,val) do { \ + gpointer __put_data = data; \ + guint32 __put_val = val; \ + _FP_PUT (__put_data, 0, 32, 0, __put_val); \ + _FP_PUT (__put_data, 1, 32, 8, __put_val); \ + _FP_PUT (__put_data, 2, 32, 16, __put_val); \ + _FP_PUT (__put_data, 3, 32, 24, __put_val); \ + } while (0) + +/** + * FP_WRITE_UINT24_BE: + * @data: memory location + * @num: value to store + * + * Store a 24 bit unsigned integer value in big endian format into the memory buffer. + */ +#define FP_WRITE_UINT24_BE(data, num) do { \ + gpointer __put_data = data; \ + guint32 __put_val = num; \ + _FP_PUT (__put_data, 0, 32, 16, __put_val); \ + _FP_PUT (__put_data, 1, 32, 8, __put_val); \ + _FP_PUT (__put_data, 2, 32, 0, __put_val); \ + } while (0) + +/** + * FP_WRITE_UINT24_LE: + * @data: memory location + * @num: value to store + * + * Store a 24 bit unsigned integer value in little endian format into the memory buffer. + */ +#define FP_WRITE_UINT24_LE(data, num) do { \ + gpointer __put_data = data; \ + guint32 __put_val = num; \ + _FP_PUT (__put_data, 0, 32, 0, __put_val); \ + _FP_PUT (__put_data, 1, 32, 8, __put_val); \ + _FP_PUT (__put_data, 2, 32, 16, __put_val); \ + } while (0) + +/** + * FP_WRITE_UINT16_BE: + * @data: memory location + * @val: value to store + * + * Store a 16 bit unsigned integer value in big endian format into the memory buffer. + */ +/** + * FP_WRITE_UINT16_LE: + * @data: memory location + * @val: value to store + * + * Store a 16 bit unsigned integer value in little endian format into the memory buffer. + */ +#define FP_WRITE_UINT16_BE(data,val) do { \ + gpointer __put_data = data; \ + guint16 __put_val = val; \ + _FP_PUT (__put_data, 0, 16, 8, __put_val); \ + _FP_PUT (__put_data, 1, 16, 0, __put_val); \ + } while (0) + +#define FP_WRITE_UINT16_LE(data,val) do { \ + gpointer __put_data = data; \ + guint16 __put_val = val; \ + _FP_PUT (__put_data, 0, 16, 0, __put_val); \ + _FP_PUT (__put_data, 1, 16, 8, __put_val); \ + } while (0) + +/** + * FP_WRITE_UINT8: + * @data: memory location + * @num: value to store + * + * Store an 8 bit unsigned integer value into the memory buffer. + */ +#define FP_WRITE_UINT8(data, num) do { \ + _FP_PUT (data, 0, 8, 0, num); \ + } while (0) + +/* Float endianness conversion macros */ + +/** + * FP_READ_FLOAT_LE: + * @data: memory location + * + * Read a 32 bit float value in little endian format from the memory buffer. + * + * Returns: The floating point value read from @data + */ +static inline gfloat +FP_READ_FLOAT_LE(const guint8 *data) +{ + union + { + guint32 i; + gfloat f; + } u; + + u.i = FP_READ_UINT32_LE (data); + return u.f; +} + +/** + * FP_READ_FLOAT_BE: + * @data: memory location + * + * Read a 32 bit float value in big endian format from the memory buffer. + * + * Returns: The floating point value read from @data + */ +static inline gfloat +FP_READ_FLOAT_BE(const guint8 *data) +{ + union + { + guint32 i; + gfloat f; + } u; + + u.i = FP_READ_UINT32_BE (data); + return u.f; +} + +/** + * FP_READ_DOUBLE_LE: + * @data: memory location + * + * Read a 64 bit double value in little endian format from the memory buffer. + * + * Returns: The double-precision floating point value read from @data + */ +static inline gdouble +FP_READ_DOUBLE_LE(const guint8 *data) +{ + union + { + guint64 i; + gdouble d; + } u; + + u.i = FP_READ_UINT64_LE (data); + return u.d; +} + +/** + * FP_READ_DOUBLE_BE: + * @data: memory location + * + * Read a 64 bit double value in big endian format from the memory buffer. + * + * Returns: The double-precision floating point value read from @data + */ +static inline gdouble +FP_READ_DOUBLE_BE(const guint8 *data) +{ + union + { + guint64 i; + gdouble d; + } u; + + u.i = FP_READ_UINT64_BE (data); + return u.d; +} + +/** + * FP_WRITE_FLOAT_LE: + * @data: memory location + * @num: value to store + * + * Store a 32 bit float value in little endian format into the memory buffer. + */ +static inline void +FP_WRITE_FLOAT_LE(guint8 *data, gfloat num) +{ + union + { + guint32 i; + gfloat f; + } u; + + u.f = num; + FP_WRITE_UINT32_LE (data, u.i); +} + +/** + * FP_WRITE_FLOAT_BE: + * @data: memory location + * @num: value to store + * + * Store a 32 bit float value in big endian format into the memory buffer. + */ +static inline void +FP_WRITE_FLOAT_BE(guint8 *data, gfloat num) +{ + union + { + guint32 i; + gfloat f; + } u; + + u.f = num; + FP_WRITE_UINT32_BE (data, u.i); +} + +/** + * FP_WRITE_DOUBLE_LE: + * @data: memory location + * @num: value to store + * + * Store a 64 bit double value in little endian format into the memory buffer. + */ +static inline void +FP_WRITE_DOUBLE_LE(guint8 *data, gdouble num) +{ + union + { + guint64 i; + gdouble d; + } u; + + u.d = num; + FP_WRITE_UINT64_LE (data, u.i); +} + +/** + * FP_WRITE_DOUBLE_BE: + * @data: memory location + * @num: value to store + * + * Store a 64 bit double value in big endian format into the memory buffer. + */ +static inline void +FP_WRITE_DOUBLE_BE(guint8 *data, gdouble num) +{ + union + { + guint64 i; + gdouble d; + } u; + + u.d = num; + FP_WRITE_UINT64_BE (data, u.i); +} + +G_END_DECLS + +#endif /* __GTK_DOC_IGNORE__ */ +#endif /* __FP_UTILS_H__ */ diff --git a/libfprint/fpi-byte-writer.c b/libfprint/fpi-byte-writer.c new file mode 100644 index 00000000..4ee67ff5 --- /dev/null +++ b/libfprint/fpi-byte-writer.c @@ -0,0 +1,614 @@ +/* GStreamer byte writer + * + * Copyright (C) 2009 Sebastian Dröge . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define FPI_BYTE_WRITER_DISABLE_INLINES +#include "fpi-byte-writer.h" + +/** + * SECTION:fpi-byte-writer + * @title: FpiByteWriter + * @short_description: Writes different integer, string and floating point + * types to a memory buffer and allows reading + * + * #FpiByteWriter provides a byte writer and reader that can write/read different + * integer and floating point types to/from a memory buffer. It provides functions + * for writing/reading signed/unsigned, little/big endian integers of 8, 16, 24, + * 32 and 64 bits and functions for reading little/big endian floating points numbers of + * 32 and 64 bits. It also provides functions to write/read NUL-terminated strings + * in various character encodings. + */ + +/** + * fpi_byte_writer_new: (skip) + * + * Creates a new, empty #FpiByteWriter instance + * + * Free-function: fpi_byte_writer_free + * + * Returns: (transfer full): a new, empty #FpiByteWriter instance + */ +FpiByteWriter * +fpi_byte_writer_new (void) +{ + FpiByteWriter *ret = g_slice_new0 (FpiByteWriter); + + ret->owned = TRUE; + return ret; +} + +/** + * fpi_byte_writer_new_with_size: (skip) + * @size: Initial size of data + * @fixed: If %TRUE the data can't be reallocated + * + * Creates a new #FpiByteWriter instance with the given + * initial data size. + * + * Free-function: fpi_byte_writer_free + * + * Returns: (transfer full): a new #FpiByteWriter instance + */ +FpiByteWriter * +fpi_byte_writer_new_with_size (guint size, gboolean fixed) +{ + FpiByteWriter *ret = fpi_byte_writer_new (); + + ret->alloc_size = size; + ret->parent.data = g_malloc (ret->alloc_size); + ret->fixed = fixed; + ret->owned = TRUE; + + return ret; +} + +/** + * fpi_byte_writer_new_with_data: (skip) + * @data: Memory area for writing + * @size: Size of @data in bytes + * @initialized: If %TRUE the complete data can be read from the beginning + * + * Creates a new #FpiByteWriter instance with the given + * memory area. If @initialized is %TRUE it is possible to + * read @size bytes from the #FpiByteWriter from the beginning. + * + * Free-function: fpi_byte_writer_free + * + * Returns: (transfer full): a new #FpiByteWriter instance + */ +FpiByteWriter * +fpi_byte_writer_new_with_data (guint8 * data, guint size, gboolean initialized) +{ + FpiByteWriter *ret = fpi_byte_writer_new (); + + ret->parent.data = data; + ret->parent.size = (initialized) ? size : 0; + ret->alloc_size = size; + ret->fixed = TRUE; + ret->owned = FALSE; + + return ret; +} + +/** + * fpi_byte_writer_init: + * @writer: #FpiByteWriter instance + * + * Initializes @writer to an empty instance + */ +void +fpi_byte_writer_init (FpiByteWriter * writer) +{ + g_return_if_fail (writer != NULL); + + memset (writer, 0, sizeof (FpiByteWriter)); + + writer->owned = TRUE; +} + +/** + * fpi_byte_writer_init_with_size: + * @writer: #FpiByteWriter instance + * @size: Initial size of data + * @fixed: If %TRUE the data can't be reallocated + * + * Initializes @writer with the given initial data size. + */ +void +fpi_byte_writer_init_with_size (FpiByteWriter * writer, guint size, + gboolean fixed) +{ + g_return_if_fail (writer != NULL); + + fpi_byte_writer_init (writer); + + writer->parent.data = g_malloc (size); + writer->alloc_size = size; + writer->fixed = fixed; + writer->owned = TRUE; +} + +/** + * fpi_byte_writer_init_with_data: + * @writer: #FpiByteWriter instance + * @data: (array length=size) (transfer none): Memory area for writing + * @size: Size of @data in bytes + * @initialized: If %TRUE the complete data can be read from the beginning + * + * Initializes @writer with the given + * memory area. If @initialized is %TRUE it is possible to + * read @size bytes from the #FpiByteWriter from the beginning. + */ +void +fpi_byte_writer_init_with_data (FpiByteWriter * writer, guint8 * data, + guint size, gboolean initialized) +{ + g_return_if_fail (writer != NULL); + + fpi_byte_writer_init (writer); + + writer->parent.data = data; + writer->parent.size = (initialized) ? size : 0; + writer->alloc_size = size; + writer->fixed = TRUE; + writer->owned = FALSE; +} + +/** + * fpi_byte_writer_reset: + * @writer: #FpiByteWriter instance + * + * Resets @writer and frees the data if it's + * owned by @writer. + */ +void +fpi_byte_writer_reset (FpiByteWriter * writer) +{ + g_return_if_fail (writer != NULL); + + if (writer->owned) + g_free ((guint8 *) writer->parent.data); + memset (writer, 0, sizeof (FpiByteWriter)); +} + +/** + * fpi_byte_writer_reset_and_get_data: + * @writer: #FpiByteWriter instance + * + * Resets @writer and returns the current data. + * + * Free-function: g_free + * + * Returns: (array) (transfer full): the current data. g_free() after + * usage. + */ +guint8 * +fpi_byte_writer_reset_and_get_data (FpiByteWriter * writer) +{ + guint8 *data; + + g_return_val_if_fail (writer != NULL, NULL); + + data = (guint8 *) writer->parent.data; + if (!writer->owned) + data = g_memdup (data, writer->parent.size); + writer->parent.data = NULL; + fpi_byte_writer_reset (writer); + + return data; +} + +/** + * fpi_byte_writer_free: + * @writer: (in) (transfer full): #FpiByteWriter instance + * + * Frees @writer and all memory allocated by it. + */ +void +fpi_byte_writer_free (FpiByteWriter * writer) +{ + g_return_if_fail (writer != NULL); + + fpi_byte_writer_reset (writer); + g_slice_free (FpiByteWriter, writer); +} + +/** + * fpi_byte_writer_free_and_get_data: + * @writer: (in) (transfer full): #FpiByteWriter instance + * + * Frees @writer and all memory allocated by it except + * the current data, which is returned. + * + * Free-function: g_free + * + * Returns: (transfer full): the current data. g_free() after usage. + */ +guint8 * +fpi_byte_writer_free_and_get_data (FpiByteWriter * writer) +{ + guint8 *data; + + g_return_val_if_fail (writer != NULL, NULL); + + data = fpi_byte_writer_reset_and_get_data (writer); + g_slice_free (FpiByteWriter, writer); + + return data; +} + +/** + * fpi_byte_writer_get_remaining: + * @writer: #FpiByteWriter instance + * + * Returns the remaining size of data that can still be written. If + * -1 is returned the remaining size is only limited by system resources. + * + * Returns: the remaining size of data that can still be written + */ +guint +fpi_byte_writer_get_remaining (const FpiByteWriter * writer) +{ + g_return_val_if_fail (writer != NULL, -1); + + if (!writer->fixed) + return -1; + else + return writer->alloc_size - writer->parent.byte; +} + +/** + * fpi_byte_writer_ensure_free_space: + * @writer: #FpiByteWriter instance + * @size: Number of bytes that should be available + * + * Checks if enough free space from the current write cursor is + * available and reallocates if necessary. + * + * Returns: %TRUE if at least @size bytes are still available + */ +gboolean +fpi_byte_writer_ensure_free_space (FpiByteWriter * writer, guint size) +{ + return fpi_byte_writer_ensure_free_space_inline (writer, size); +} + + +#define CREATE_WRITE_FUNC(bits,type,name,write_func) \ +gboolean \ +fpi_byte_writer_put_##name (FpiByteWriter *writer, type val) \ +{ \ + return fpi_byte_writer_put_##name##_inline (writer, val); \ +} + +CREATE_WRITE_FUNC (8, guint8, uint8, GST_WRITE_UINT8); +CREATE_WRITE_FUNC (8, gint8, int8, GST_WRITE_UINT8); +CREATE_WRITE_FUNC (16, guint16, uint16_le, GST_WRITE_UINT16_LE); +CREATE_WRITE_FUNC (16, guint16, uint16_be, GST_WRITE_UINT16_BE); +CREATE_WRITE_FUNC (16, gint16, int16_le, GST_WRITE_UINT16_LE); +CREATE_WRITE_FUNC (16, gint16, int16_be, GST_WRITE_UINT16_BE); +CREATE_WRITE_FUNC (24, guint32, uint24_le, GST_WRITE_UINT24_LE); +CREATE_WRITE_FUNC (24, guint32, uint24_be, GST_WRITE_UINT24_BE); +CREATE_WRITE_FUNC (24, gint32, int24_le, GST_WRITE_UINT24_LE); +CREATE_WRITE_FUNC (24, gint32, int24_be, GST_WRITE_UINT24_BE); +CREATE_WRITE_FUNC (32, guint32, uint32_le, GST_WRITE_UINT32_LE); +CREATE_WRITE_FUNC (32, guint32, uint32_be, GST_WRITE_UINT32_BE); +CREATE_WRITE_FUNC (32, gint32, int32_le, GST_WRITE_UINT32_LE); +CREATE_WRITE_FUNC (32, gint32, int32_be, GST_WRITE_UINT32_BE); +CREATE_WRITE_FUNC (64, guint64, uint64_le, GST_WRITE_UINT64_LE); +CREATE_WRITE_FUNC (64, guint64, uint64_be, GST_WRITE_UINT64_BE); +CREATE_WRITE_FUNC (64, gint64, int64_le, GST_WRITE_UINT64_LE); +CREATE_WRITE_FUNC (64, gint64, int64_be, GST_WRITE_UINT64_BE); + +CREATE_WRITE_FUNC (32, gfloat, float32_be, GST_WRITE_FLOAT_BE); +CREATE_WRITE_FUNC (32, gfloat, float32_le, GST_WRITE_FLOAT_LE); +CREATE_WRITE_FUNC (64, gdouble, float64_be, GST_WRITE_DOUBLE_BE); +CREATE_WRITE_FUNC (64, gdouble, float64_le, GST_WRITE_DOUBLE_LE); + +gboolean +fpi_byte_writer_put_data (FpiByteWriter * writer, const guint8 * data, + guint size) +{ + return fpi_byte_writer_put_data_inline (writer, data, size); +} + +gboolean +fpi_byte_writer_fill (FpiByteWriter * writer, guint8 value, guint size) +{ + return fpi_byte_writer_fill_inline (writer, value, size); +} + +#define CREATE_WRITE_STRING_FUNC(bits,type) \ +gboolean \ +fpi_byte_writer_put_string_utf##bits (FpiByteWriter *writer, const type * data) \ +{ \ + guint size = 0; \ + \ + g_return_val_if_fail (writer != NULL, FALSE); \ + \ + /* endianness does not matter if we are looking for a NUL terminator */ \ + while (data[size] != 0) { \ + /* have prevent overflow */ \ + if (G_UNLIKELY (size == G_MAXUINT)) \ + return FALSE; \ + ++size; \ + } \ + ++size; \ + \ + if (G_UNLIKELY (!fpi_byte_writer_ensure_free_space_inline(writer, size * (bits / 8)))) \ + return FALSE; \ + \ + fpi_byte_writer_put_data_inline (writer, (const guint8 *) data, size * (bits / 8)); \ + \ + return TRUE; \ +} + +CREATE_WRITE_STRING_FUNC (8, gchar); +CREATE_WRITE_STRING_FUNC (16, guint16); +CREATE_WRITE_STRING_FUNC (32, guint32); +/** + * fpi_byte_writer_put_uint8: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned 8 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_uint16_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned big endian 16 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_uint24_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned big endian 24 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_uint32_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned big endian 32 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_uint64_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned big endian 64 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_uint16_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned little endian 16 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_uint24_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned little endian 24 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_uint32_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned little endian 32 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_uint64_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned little endian 64 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int8: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed 8 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int16_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed big endian 16 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int24_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed big endian 24 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int32_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed big endian 32 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int64_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed big endian 64 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int16_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed little endian 16 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int24_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed little endian 24 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int32_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed little endian 32 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int64_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed little endian 64 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_float32_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a big endian 32 bit float to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_float64_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a big endian 64 bit float to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_float32_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a little endian 32 bit float to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_float64_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a little endian 64 bit float to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_string_utf8: + * @writer: #FpiByteWriter instance + * @data: (transfer none): UTF8 string to write + * + * Writes a NUL-terminated UTF8 string to @writer (including the terminator). + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_string_utf16: + * @writer: #FpiByteWriter instance + * @data: (transfer none) (array zero-terminated=1): UTF16 string to write + * + * Writes a NUL-terminated UTF16 string to @writer (including the terminator). + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_string_utf32: + * @writer: #FpiByteWriter instance + * @data: (transfer none) (array zero-terminated=1): UTF32 string to write + * + * Writes a NUL-terminated UTF32 string to @writer (including the terminator). + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_data: + * @writer: #FpiByteWriter instance + * @data: (transfer none) (array length=size): Data to write + * @size: Size of @data in bytes + * + * Writes @size bytes of @data to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_fill: + * @writer: #FpiByteWriter instance + * @value: Value to be written + * @size: Number of bytes to be written + * + * Writes @size bytes containing @value to @writer. + * + * Returns: %TRUE if the value could be written + */ + diff --git a/libfprint/fpi-byte-writer.h b/libfprint/fpi-byte-writer.h new file mode 100644 index 00000000..b15a9a1e --- /dev/null +++ b/libfprint/fpi-byte-writer.h @@ -0,0 +1,413 @@ +/* GStreamer byte writer + * + * Copyright (C) 2009 Sebastian Dröge . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __FPI_BYTE_WRITER_H__ +#define __FPI_BYTE_WRITER_H__ + +#include "fpi-byte-reader.h" +#include + +G_BEGIN_DECLS + +#define FPI_BYTE_WRITER(writer) ((FpiByteWriter *) (writer)) + +/** + * FpiByteWriter: + * @parent: #FpiByteReader parent + * @alloc_size: Allocation size of the data + * @fixed: If %TRUE no reallocations are allowed + * @owned: If %FALSE no reallocations are allowed and copies of data are returned + * + * A byte writer instance. + */ +typedef struct { + FpiByteReader parent; + + guint alloc_size; + + gboolean fixed; + gboolean owned; + + /* < private > */ +} FpiByteWriter; + + +FpiByteWriter * fpi_byte_writer_new (void) G_GNUC_MALLOC; + + +FpiByteWriter * fpi_byte_writer_new_with_size (guint size, gboolean fixed) G_GNUC_MALLOC; + + +FpiByteWriter * fpi_byte_writer_new_with_data (guint8 *data, guint size, gboolean initialized) G_GNUC_MALLOC; + + +void fpi_byte_writer_init (FpiByteWriter *writer); + + +void fpi_byte_writer_init_with_size (FpiByteWriter *writer, guint size, gboolean fixed); + + +void fpi_byte_writer_init_with_data (FpiByteWriter *writer, guint8 *data, + guint size, gboolean initialized); + +void fpi_byte_writer_free (FpiByteWriter *writer); + + +guint8 * fpi_byte_writer_free_and_get_data (FpiByteWriter *writer); + + +void fpi_byte_writer_reset (FpiByteWriter *writer); + + +guint8 * fpi_byte_writer_reset_and_get_data (FpiByteWriter *writer); + +/** + * fpi_byte_writer_get_pos: + * @writer: #FpiByteWriter instance + * + * Returns: The current position of the read/write cursor + */ +/** + * fpi_byte_writer_set_pos: + * @writer: #FpiByteWriter instance + * @pos: new position + * + * Sets the current read/write cursor of @writer. The new position + * can only be between 0 and the current size. + * + * Returns: %TRUE if the new position could be set + */ +/** + * fpi_byte_writer_get_size: + * @writer: #FpiByteWriter instance + * + * Returns: The current, initialized size of the data + */ +static inline guint +fpi_byte_writer_get_pos (const FpiByteWriter *writer) +{ + return fpi_byte_reader_get_pos ((const FpiByteReader *) writer); +} + +static inline gboolean +fpi_byte_writer_set_pos (FpiByteWriter *writer, guint pos) +{ + return fpi_byte_reader_set_pos (FPI_BYTE_READER (writer), pos); +} + +static inline guint +fpi_byte_writer_get_size (const FpiByteWriter *writer) +{ + return fpi_byte_reader_get_size ((const FpiByteReader *) writer); +} + + +guint fpi_byte_writer_get_remaining (const FpiByteWriter *writer); + + +gboolean fpi_byte_writer_ensure_free_space (FpiByteWriter *writer, guint size); + + +gboolean fpi_byte_writer_put_uint8 (FpiByteWriter *writer, guint8 val); + + +gboolean fpi_byte_writer_put_int8 (FpiByteWriter *writer, gint8 val); + + +gboolean fpi_byte_writer_put_uint16_be (FpiByteWriter *writer, guint16 val); + + +gboolean fpi_byte_writer_put_uint16_le (FpiByteWriter *writer, guint16 val); + + +gboolean fpi_byte_writer_put_int16_be (FpiByteWriter *writer, gint16 val); + + +gboolean fpi_byte_writer_put_int16_le (FpiByteWriter *writer, gint16 val); + + +gboolean fpi_byte_writer_put_uint24_be (FpiByteWriter *writer, guint32 val); + + +gboolean fpi_byte_writer_put_uint24_le (FpiByteWriter *writer, guint32 val); + + +gboolean fpi_byte_writer_put_int24_be (FpiByteWriter *writer, gint32 val); + + +gboolean fpi_byte_writer_put_int24_le (FpiByteWriter *writer, gint32 val); + + +gboolean fpi_byte_writer_put_uint32_be (FpiByteWriter *writer, guint32 val); + + +gboolean fpi_byte_writer_put_uint32_le (FpiByteWriter *writer, guint32 val); + + +gboolean fpi_byte_writer_put_int32_be (FpiByteWriter *writer, gint32 val); + + +gboolean fpi_byte_writer_put_int32_le (FpiByteWriter *writer, gint32 val); + + +gboolean fpi_byte_writer_put_uint64_be (FpiByteWriter *writer, guint64 val); + + +gboolean fpi_byte_writer_put_uint64_le (FpiByteWriter *writer, guint64 val); + + +gboolean fpi_byte_writer_put_int64_be (FpiByteWriter *writer, gint64 val); + + +gboolean fpi_byte_writer_put_int64_le (FpiByteWriter *writer, gint64 val); + + +gboolean fpi_byte_writer_put_float32_be (FpiByteWriter *writer, gfloat val); + + +gboolean fpi_byte_writer_put_float32_le (FpiByteWriter *writer, gfloat val); + + +gboolean fpi_byte_writer_put_float64_be (FpiByteWriter *writer, gdouble val); + + +gboolean fpi_byte_writer_put_float64_le (FpiByteWriter *writer, gdouble val); + + +gboolean fpi_byte_writer_put_data (FpiByteWriter *writer, const guint8 *data, guint size); + + +gboolean fpi_byte_writer_fill (FpiByteWriter *writer, guint8 value, guint size); + + +gboolean fpi_byte_writer_put_string_utf8 (FpiByteWriter *writer, const gchar *data); + + +gboolean fpi_byte_writer_put_string_utf16 (FpiByteWriter *writer, const guint16 *data); + + +gboolean fpi_byte_writer_put_string_utf32 (FpiByteWriter *writer, const guint32 *data); + +/** + * fpi_byte_writer_put_string: + * @writer: #FpiByteWriter instance + * @data: (in) (array zero-terminated=1): Null terminated string + * + * Write a NUL-terminated string to @writer (including the terminator). The + * string is assumed to be in an 8-bit encoding (e.g. ASCII,UTF-8 or + * ISO-8859-1). + * + * Returns: %TRUE if the string could be written + */ +#define fpi_byte_writer_put_string(writer, data) \ + fpi_byte_writer_put_string_utf8(writer, data) + +static inline guint +fpi_byte_writer_next_pow2 (guint n) +{ + guint ret = 16; + + /* We start with 16, smaller allocations make no sense */ + + while (ret < n && ret > 0) + ret <<= 1; + + return ret ? ret : n; +} + +static inline gboolean +fpi_byte_writer_ensure_free_space_inline (FpiByteWriter * writer, guint size) +{ + gpointer data; + + if (G_LIKELY (size <= writer->alloc_size - writer->parent.byte)) + return TRUE; + if (G_UNLIKELY (writer->fixed || !writer->owned)) + return FALSE; + if (G_UNLIKELY (writer->parent.byte > G_MAXUINT - size)) + return FALSE; + + writer->alloc_size = fpi_byte_writer_next_pow2 (writer->parent.byte + size); + data = g_try_realloc ((guint8 *) writer->parent.data, writer->alloc_size); + if (G_UNLIKELY (data == NULL)) + return FALSE; + + writer->parent.data = (guint8 *) data; + + return TRUE; +} + +#define __FPI_BYTE_WRITER_CREATE_WRITE_FUNC(bits,type,name,write_func) \ +static inline void \ +fpi_byte_writer_put_##name##_unchecked (FpiByteWriter *writer, type val) \ +{ \ + guint8 *write_data; \ + \ + write_data = (guint8 *) writer->parent.data + writer->parent.byte; \ + write_func (write_data, val); \ + writer->parent.byte += bits/8; \ + writer->parent.size = MAX (writer->parent.size, writer->parent.byte); \ +} \ +\ +static inline gboolean \ +fpi_byte_writer_put_##name##_inline (FpiByteWriter *writer, type val) \ +{ \ + g_return_val_if_fail (writer != NULL, FALSE); \ + \ + if (G_UNLIKELY (!fpi_byte_writer_ensure_free_space_inline(writer, bits/8))) \ + return FALSE; \ + \ + fpi_byte_writer_put_##name##_unchecked (writer, val); \ + \ + return TRUE; \ +} + +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (8, guint8, uint8, FP_WRITE_UINT8) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (8, gint8, int8, FP_WRITE_UINT8) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (16, guint16, uint16_le, FP_WRITE_UINT16_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (16, guint16, uint16_be, FP_WRITE_UINT16_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (16, gint16, int16_le, FP_WRITE_UINT16_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (16, gint16, int16_be, FP_WRITE_UINT16_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (24, guint32, uint24_le, FP_WRITE_UINT24_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (24, guint32, uint24_be, FP_WRITE_UINT24_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (24, gint32, int24_le, FP_WRITE_UINT24_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (24, gint32, int24_be, FP_WRITE_UINT24_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (32, guint32, uint32_le, FP_WRITE_UINT32_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (32, guint32, uint32_be, FP_WRITE_UINT32_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (32, gint32, int32_le, FP_WRITE_UINT32_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (32, gint32, int32_be, FP_WRITE_UINT32_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (64, guint64, uint64_le, FP_WRITE_UINT64_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (64, guint64, uint64_be, FP_WRITE_UINT64_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (64, gint64, int64_le, FP_WRITE_UINT64_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (64, gint64, int64_be, FP_WRITE_UINT64_BE) + +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (32, gfloat, float32_be, FP_WRITE_FLOAT_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (32, gfloat, float32_le, FP_WRITE_FLOAT_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (64, gdouble, float64_be, FP_WRITE_DOUBLE_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (64, gdouble, float64_le, FP_WRITE_DOUBLE_LE) + +#undef __FPI_BYTE_WRITER_CREATE_WRITE_FUNC + +static inline void +fpi_byte_writer_put_data_unchecked (FpiByteWriter * writer, const guint8 * data, + guint size) +{ + memcpy ((guint8 *) & writer->parent.data[writer->parent.byte], data, size); + writer->parent.byte += size; + writer->parent.size = MAX (writer->parent.size, writer->parent.byte); +} + +static inline gboolean +fpi_byte_writer_put_data_inline (FpiByteWriter * writer, const guint8 * data, + guint size) +{ + g_return_val_if_fail (writer != NULL, FALSE); + + if (G_UNLIKELY (!fpi_byte_writer_ensure_free_space_inline (writer, size))) + return FALSE; + + fpi_byte_writer_put_data_unchecked (writer, data, size); + + return TRUE; +} + +static inline void +fpi_byte_writer_fill_unchecked (FpiByteWriter * writer, guint8 value, guint size) +{ + memset ((guint8 *) & writer->parent.data[writer->parent.byte], value, size); + writer->parent.byte += size; + writer->parent.size = MAX (writer->parent.size, writer->parent.byte); +} + +static inline gboolean +fpi_byte_writer_fill_inline (FpiByteWriter * writer, guint8 value, guint size) +{ + g_return_val_if_fail (writer != NULL, FALSE); + + if (G_UNLIKELY (!fpi_byte_writer_ensure_free_space_inline (writer, size))) + return FALSE; + + fpi_byte_writer_fill_unchecked (writer, value, size); + + return TRUE; +} + +#ifndef FPI_BYTE_WRITER_DISABLE_INLINES + +/* we use defines here so we can add the G_LIKELY() */ + +#define fpi_byte_writer_ensure_free_space(writer, size) \ + G_LIKELY (fpi_byte_writer_ensure_free_space_inline (writer, size)) +#define fpi_byte_writer_put_uint8(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint8_inline (writer, val)) +#define fpi_byte_writer_put_int8(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int8_inline (writer, val)) +#define fpi_byte_writer_put_uint16_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint16_be_inline (writer, val)) +#define fpi_byte_writer_put_uint16_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint16_le_inline (writer, val)) +#define fpi_byte_writer_put_int16_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int16_be_inline (writer, val)) +#define fpi_byte_writer_put_int16_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int16_le_inline (writer, val)) +#define fpi_byte_writer_put_uint24_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint24_be_inline (writer, val)) +#define fpi_byte_writer_put_uint24_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint24_le_inline (writer, val)) +#define fpi_byte_writer_put_int24_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int24_be_inline (writer, val)) +#define fpi_byte_writer_put_int24_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int24_le_inline (writer, val)) +#define fpi_byte_writer_put_uint32_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint32_be_inline (writer, val)) +#define fpi_byte_writer_put_uint32_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint32_le_inline (writer, val)) +#define fpi_byte_writer_put_int32_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int32_be_inline (writer, val)) +#define fpi_byte_writer_put_int32_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int32_le_inline (writer, val)) +#define fpi_byte_writer_put_uint64_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint64_be_inline (writer, val)) +#define fpi_byte_writer_put_uint64_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint64_le_inline (writer, val)) +#define fpi_byte_writer_put_int64_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int64_be_inline (writer, val)) +#define fpi_byte_writer_put_int64_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int64_le_inline (writer, val)) + +#define fpi_byte_writer_put_float32_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_float32_be_inline (writer, val)) +#define fpi_byte_writer_put_float32_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_float32_le_inline (writer, val)) +#define fpi_byte_writer_put_float64_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_float64_be_inline (writer, val)) +#define fpi_byte_writer_put_float64_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_float64_le_inline (writer, val)) + +#define fpi_byte_writer_put_data(writer, data, size) \ + G_LIKELY (fpi_byte_writer_put_data_inline (writer, data, size)) +#define fpi_byte_writer_fill(writer, val, size) \ + G_LIKELY (fpi_byte_writer_fill_inline (writer, val, size)) + +#endif + +G_END_DECLS + +#endif /* __FPI_BYTE_WRITER_H__ */ diff --git a/libfprint/meson.build b/libfprint/meson.build index 6e4eb796..f2a2e4dd 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -7,6 +7,8 @@ libfprint_sources = [ 'fpi-assembling.c', 'fpi-ssm.c', 'fpi-usb-transfer.c', + 'fpi-byte-reader.c', + 'fpi-byte-writer.c', ] libfprint_public_headers = [ @@ -22,6 +24,9 @@ libfprint_private_headers = [ 'fpi-image.h', 'fpi-image-device.h', 'fpi-print.h', + 'fpi-byte-reader.h', + 'fpi-byte-writer.h', + 'fpi-byte-utils.h', ] nbis_sources = [ From ac65cf455e26a898b1d93f0c55ab876dae329f02 Mon Sep 17 00:00:00 2001 From: Vincent Huang Date: Mon, 29 Jul 2019 15:55:27 +0200 Subject: [PATCH 42/73] synaptics: Add synaptics driver Heavily modified by Benjamin Berg to port it to the new libfprint API and adjust the coding style to follow more closely other drivers. --- libfprint/drivers/synaptics/bmkt.h | 236 +++++ libfprint/drivers/synaptics/bmkt_message.c | 411 ++++++++ libfprint/drivers/synaptics/bmkt_message.h | 86 ++ libfprint/drivers/synaptics/bmkt_response.h | 489 +++++++++ libfprint/drivers/synaptics/sensor.h | 80 ++ libfprint/drivers/synaptics/synaptics.c | 1040 +++++++++++++++++++ libfprint/drivers/synaptics/synaptics.h | 130 +++ libfprint/meson.build | 6 + meson.build | 2 +- 9 files changed, 2479 insertions(+), 1 deletion(-) create mode 100644 libfprint/drivers/synaptics/bmkt.h create mode 100644 libfprint/drivers/synaptics/bmkt_message.c create mode 100644 libfprint/drivers/synaptics/bmkt_message.h create mode 100644 libfprint/drivers/synaptics/bmkt_response.h create mode 100644 libfprint/drivers/synaptics/sensor.h create mode 100644 libfprint/drivers/synaptics/synaptics.c create mode 100644 libfprint/drivers/synaptics/synaptics.h diff --git a/libfprint/drivers/synaptics/bmkt.h b/libfprint/drivers/synaptics/bmkt.h new file mode 100644 index 00000000..de7f875e --- /dev/null +++ b/libfprint/drivers/synaptics/bmkt.h @@ -0,0 +1,236 @@ +/* + * Synaptics MiS Fingerprint Sensor Interface + * Copyright (C) 2019 Synaptics Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _BMKT_H_ +#define _BMKT_H_ + +/**< User ID maximum length allowed */ +#define BMKT_MAX_USER_ID_LEN 100 +/**< Software Part Number length */ +#define BMKT_PART_NUM_LEN 10 +/**< Software supplier identification length */ +#define BMKT_SUPPLIER_ID_LEN 2 + +/**< Maximum namber of templates for storing in internal flash of the fingerprint sensor */ +#define BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH 15 + +#include +#include "bmkt_response.h" + +/*! +******************************************************************************* +** Type definition for result +*/ +/** No error; Operation successfully completed. */ +#define BMKT_SUCCESS 0 +/** Fingerprint system not initialized */ +#define BMKT_FP_SYSTEM_NOT_INITIALIZED 101 +/** Fingerprint system busy performing another operation */ +#define BMKT_FP_SYSTEM_BUSY 102 +/** Operation not allowed */ +#define BMKT_OPERATION_DENIED 103 +/** System ran out of memory while performing operation */ +#define BMKT_OUT_OF_MEMORY 104 +/** Corrupt message, CRC check fail or truncated message */ +#define BMKT_CORRUPT_MESSAGE 110 +/** One of the command parameters is outside the range of valid values */ +#define BMKT_INVALID_PARAM 111 +/** Unrecognized message or message with invalid message ID */ +#define BMKT_UNRECOGNIZED_MESSAGE 112 +/** Operation time out */ +#define BMKT_OP_TIME_OUT 113 +/** General error – cause of error cannot be determined */ +#define BMKT_GENERAL_ERROR 114 + +#define BMKT_SET_SECURITY_LEVEL_FAIL 120 +#define BMKT_GET_SECURITY_LEVEL_FAIL 121 + +/** Fingerprint sensor reset while operation was being performed */ +#define BMKT_SENSOR_RESET 201 +/** Fingerprint sensor malfunctioned */ +#define BMKT_SENSOR_MALFUNCTION 202 +/** Fingerprint sensor cannot be accessed despite repeated attempts */ +#define BMKT_SENSOR_TAMPERED 203 +/** +* BMKT_SENSOR_NOT_INIT: +* Fingerprint sensor module not initialized yet – not ready for use +* (different from error code 101 which indicates that the entire system +* has not been initialized) +*/ +#define BMKT_SENSOR_NOT_INIT 204 +/** Number of re-pairing operations exceeded limit or re-pairing has been disabled */ +#define BMKT_OWNERSHIP_RESET_MAX_EXCEEDED 205 +/** +* BMKT_SENSOR_STIMULUS_ERROR: +* There is a finger or debris on the sensor that needs to be removed +* before issuing this command +*/ +#define BMKT_SENSOR_STIMULUS_ERROR 213 +/** +* BMKT_CORRUPT_TEMPLATE_DATA: +* One of the fingerprint templates stored on flash is corrupt. +* This error code is returned in case of failure in finding a fingerprint match +* during identify or verify operations while also detecting that one or more +* fingerprint templates stored on the flash has become corrupted +*/ +#define BMKT_CORRUPT_TEMPLATE_DATA 300 +/** Failed to extract features from fingerprint image acquired by sensor */ +#define BMKT_FEATURE_EXTRACT_FAIL 301 +/** Failed to generate fingerprint template */ +#define BMKT_ENROLL_FAIL 302 +/** Specified finger already enrolled for this user */ +#define BMKT_ENROLLMENT_EXISTS 303 +/** Invalid fingerprint image */ +#define BMKT_INVALID_FP_IMAGE 304 +/** No matching user fingerprint template found in database */ +#define BMKT_FP_NO_MATCH 404 +/** Fingerprint database is full */ +#define BMKT_FP_DATABASE_FULL 501 +/** Fingerprint database is empty */ +#define BMKT_FP_DATABASE_EMPTY 502 +/** Cannot access fingerprint database */ +#define BMKT_FP_DATABASE_ACCESS_FAIL 503 +/** Fingerprint template record does not exist */ +#define BMKT_FP_DATABASE_NO_RECORD_EXISTS 504 +/** Failed to read/write system parameters stored on flash */ +#define BMKT_FP_PARAM_ACCESS_FAIL 505 +/** Fingerprint is a spoof */ +#define BMKT_FP_SPOOF_ALERT 801 +/** Anti-spoof module failure */ +#define BMKT_ANTI_SPOOF_MODULE_FAIL 802 + +#define BMKT_CORRUPT_UPDATE_IMAGE 901 +#define BMKT_SYSTEM_UPDATE_FAIL 902 + +#define BMKT_EVENT_NOT_SET 1000 +#define BMKT_SENSOR_NOT_READY 1001 +#define BMKT_TIMEOUT 1002 +#define BMKT_SENSOR_RESPONSE_PENDING 1003 + + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* bmkt_mode: +* Fingerprint system operational mode values level 1 +*/ +typedef enum bmkt_mode +{ + BMKT_STATE_UNINIT = 0xFF, + BMKT_STATE_IDLE = 0x00, + BMKT_STATE_ENROLL = 0x10, + BMKT_STATE_IDENTIFY = 0x20, + BMKT_STATE_VERIFY = 0x30, + BMKT_STATE_DB_OPS = 0x40, + BMKT_STATE_SYS_TEST = 0x50, + BMKT_STATE_SYS_OPS = 0x60, +} bmkt_mode_t; + +/** +* bmkt_mode_level2: +* Fingerprint system operational mode values level 2 +*/ +typedef enum bmkt_mode_level2 +{ + BMKT_STATE_L2_IDLE = 0x00, + BMKT_STATE_L2_STARTING = 0x11, + BMKT_STATE_L2_WAITING_FOR_FINGER = 0x12, + BMKT_STATE_L2_CAPTURE_IMAGE = 0x13, + BMKT_STATE_L2_CAPTURE_COMPLETE = 0x14, + BMKT_STATE_L2_EXTRACT_FEATURE = 0x15, + BMKT_STATE_L2_CREATE_TEMPLATE = 0x16, + BMKT_STATE_L2_READING_FROM_FLASH = 0x17, + BMKT_STATE_L2_WRITING_TO_FLASH = 0x18, + BMKT_STATE_L2_FINISHING = 0x19, + BMKT_STATE_L2_CANCELING_OP = 0x20, + BMKT_STATE_L2_MATCHING = 0x21, + BMKT_STATE_L2_TRANSMITTING_RESPONSE = 0x22, + BMKT_STATE_L2_READY_POWER_DOWN = 0xF0, +} bmkt_mode_level2_t; + +/** +* bmkt_transport_type: +* Fingerprint system transport types +*/ +typedef enum bmkt_transport_type +{ + BMKT_TRANSPORT_TYPE_USB = 0, +} bmkt_transport_type_t; + +/** +* bmkt_usb_config: +* Structure represcontainingenting USB configuration details +*/ +typedef struct bmkt_usb_config +{ + int product_id; /**< USB device product ID */ +} bmkt_usb_config_t; + +/** +* bmkt_transport_config_t: +* Union containing transport configuration details +*/ +typedef union +{ + bmkt_usb_config_t usb_config; +} bmkt_transport_config_t; + +/** +* bmkt_sensor_desc_t: +* Structure containing fingerprint system description +*/ +typedef struct bmkt_sensor_desc +{ + int product_id; + int flags; +} bmkt_sensor_desc_t; + +/** +* bmkt_finger_state_t: +* Finger state representation values. +*/ +typedef enum +{ + BMKT_FINGER_STATE_UNKNOWN = 0, + BMKT_FINGER_STATE_ON_SENSOR, + BMKT_FINGER_STATE_NOT_ON_SENSOR, +} bmkt_finger_state_t; + +/** +* bmkt_finger_event_t: +* Structure containing finger state +*/ +typedef struct bmkt_finger_event +{ + bmkt_finger_state_t finger_state; +} bmkt_finger_event_t; + +typedef struct bmkt_user_id +{ + uint8_t user_id_len; + uint8_t user_id[BMKT_MAX_USER_ID_LEN]; +} bmkt_user_id_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _BMKT_H_ */ diff --git a/libfprint/drivers/synaptics/bmkt_message.c b/libfprint/drivers/synaptics/bmkt_message.c new file mode 100644 index 00000000..fe0bebe9 --- /dev/null +++ b/libfprint/drivers/synaptics/bmkt_message.c @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "bmkt_response.h" +#include "bmkt_message.h" + +static uint8_t extract8(const uint8_t *buf, int *offset) +{ + uint8_t ret = 0; + int off = 0; + if (offset) + off = *offset; + + ret = *(buf + off); + + if (offset) + *offset += 1; + + return ret; +} + + +static int parse_error_response(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + if (msg_resp->payload_len != 2) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + resp->result = (msg_resp->payload[0] << 8) | msg_resp->payload[1]; + + return BMKT_SUCCESS; +} + +static int parse_init_ok(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + bmkt_init_resp_t *init_resp = &resp->response.init_resp; + + if (msg_resp->payload_len != 1) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + init_resp->finger_presence = extract8(msg_resp->payload, NULL); + + return BMKT_SUCCESS; +} + + +static int parse_fps_mode_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + int offset = 0; + bmkt_fps_mode_resp_t *fps_mode_resp = &resp->response.fps_mode_resp; + + if (msg_resp->payload_len != sizeof(bmkt_fps_mode_resp_t)) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + fps_mode_resp->mode = extract8(msg_resp->payload, &offset); + fps_mode_resp->level2_mode = extract8(msg_resp->payload, &offset); + fps_mode_resp->cmd_id = extract8(msg_resp->payload, &offset); + fps_mode_resp->finger_presence = extract8(msg_resp->payload, &offset); + + return BMKT_SUCCESS; +} + +static int parse_enroll_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp; + + if (msg_resp->payload_len != 1) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + enroll_resp->progress = extract8(msg_resp->payload, NULL); + + return BMKT_SUCCESS; +} + +static int parse_enroll_ok(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp; + + if (msg_resp->payload_len < 1 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 1)) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + enroll_resp->finger_id = msg_resp->payload[0]; + memcpy(enroll_resp->user_id, &msg_resp->payload[1], msg_resp->payload_len - 1); + + return BMKT_SUCCESS; +} + +static int parse_auth_ok(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + bmkt_identify_resp_t *id_resp = &resp->response.id_resp; + + if (msg_resp->payload_len < 3 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 3)) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + id_resp->match_result = (double)msg_resp->payload[0] + 0.01 * (double)msg_resp->payload[1]; + id_resp->finger_id = msg_resp->payload[2]; + memcpy(id_resp->user_id, &msg_resp->payload[3], msg_resp->payload_len - 3); + + return BMKT_SUCCESS; +} + +static int parse_security_level_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + bmkt_set_sec_level_resp_t *sec_level_resp = &resp->response.sec_level_resp; + + if (msg_resp->payload_len != 1) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + sec_level_resp->sec_level = extract8(msg_resp->payload, NULL); + + return BMKT_SUCCESS; +} + +static int parse_del_all_users_progress_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + bmkt_del_all_users_resp_t *del_all_users_resp = &resp->response.del_all_users_resp; + + if (msg_resp->payload_len != 1) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + del_all_users_resp->progress = extract8(msg_resp->payload, NULL); + + return BMKT_SUCCESS; +} + +static int parse_db_cap_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + bmkt_get_db_capacity_resp_t *db_cap_resp = &resp->response.db_cap_resp; + int offset = 0; + + if (msg_resp->payload_len < 2 || msg_resp->payload_len > 4) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + db_cap_resp->total = extract8(msg_resp->payload, &offset); + db_cap_resp->empty = extract8(msg_resp->payload, &offset); + + if (msg_resp->payload_len == 4) + { + db_cap_resp->bad_slots = extract8(msg_resp->payload, &offset); + db_cap_resp->corrupt_templates = extract8(msg_resp->payload, &offset); + } + + return BMKT_SUCCESS; +} + +static int parse_get_enrolled_fingers_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + int offset = 0; + int i = 0; + + if (msg_resp->payload_len < 2) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + /* 2 bytes per finger so calculate the total number of fingers to process*/ + int num_fingers = (msg_resp->payload_len) / 2; + + bmkt_enrolled_fingers_resp_t *get_enrolled_fingers_resp = &resp->response.enrolled_fingers_resp; + + for (i = 0; i < num_fingers; i++) + { + get_enrolled_fingers_resp->fingers[i].finger_id = extract8(msg_resp->payload, &offset); + get_enrolled_fingers_resp->fingers[i].template_status = extract8(msg_resp->payload, &offset); + + } + return BMKT_SUCCESS; +} +static int parse_get_enrolled_users_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + int offset = 0; + int i = 0; + + /* the payload is 2 bytes + template data */ + if (msg_resp->payload_len < 2) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + bmkt_enroll_templates_resp_t *get_enroll_templates_resp = &resp->response.enroll_templates_resp; + + get_enroll_templates_resp->total_query_messages = extract8(msg_resp->payload, &offset); + get_enroll_templates_resp->query_sequence = extract8(msg_resp->payload, &offset); + + int n = 0; + for (n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++) + { + if (offset >= msg_resp->payload_len) + break; + get_enroll_templates_resp->templates[n].user_id_len = extract8(msg_resp->payload, &offset) - 2; + if(get_enroll_templates_resp->templates[n].user_id_len > BMKT_MAX_USER_ID_LEN) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + get_enroll_templates_resp->templates[n].template_status = extract8(msg_resp->payload, &offset); + get_enroll_templates_resp->templates[n].finger_id = extract8(msg_resp->payload, &offset); + for (i = 0; i < get_enroll_templates_resp->templates[n].user_id_len; i++) + { + get_enroll_templates_resp->templates[n].user_id[i] = extract8(msg_resp->payload, &offset); + } + get_enroll_templates_resp->templates[n].user_id[i] = '\0'; + } + + return BMKT_SUCCESS; +} + +static int parse_get_version_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + bmkt_get_version_resp_t *get_version_resp = &resp->response.get_version_resp; + int offset = 0; + + if (msg_resp->payload_len != 15) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + memcpy(get_version_resp->part, msg_resp->payload, BMKT_PART_NUM_LEN); + offset += BMKT_PART_NUM_LEN; + get_version_resp->year = extract8(msg_resp->payload, &offset); + get_version_resp->week = extract8(msg_resp->payload, &offset); + get_version_resp->patch = extract8(msg_resp->payload, &offset); + memcpy(get_version_resp->supplier_id, msg_resp->payload + offset, BMKT_SUPPLIER_ID_LEN); + + return BMKT_SUCCESS; +} + +int bmkt_compose_message(uint8_t *cmd, int *cmd_len, uint8_t msg_id, uint8_t seq_num, + uint8_t payload_size, const uint8_t *payload) +{ + int message_len = BMKT_MESSAGE_HEADER_LEN + payload_size; + + if (*cmd_len < message_len) + { + return BMKT_OUT_OF_MEMORY; + } + + cmd[BMKT_MESSAGE_HEADER_ID_FIELD] = BMKT_MESSAGE_HEADER_ID; + cmd[BMKT_MESSAGE_SEQ_NUM_FIELD] = seq_num; + cmd[BMKT_MESSAGE_ID_FIELD] = msg_id; + cmd[BMKT_MESSAGE_PAYLOAD_LEN_FIELD] = payload_size; + memcpy(&cmd[BMKT_MESSAGE_PAYLOAD_FIELD], payload, payload_size); + + *cmd_len = message_len; + + return BMKT_SUCCESS; +} + +int bmkt_parse_message_header(uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp) +{ + if (resp_buf[BMKT_MESSAGE_HEADER_ID_FIELD] != BMKT_MESSAGE_HEADER_ID) + { + return BMKT_CORRUPT_MESSAGE; + } + + msg_resp->seq_num = resp_buf[BMKT_MESSAGE_SEQ_NUM_FIELD]; + msg_resp->msg_id = resp_buf[BMKT_MESSAGE_ID_FIELD]; + msg_resp->payload_len = resp_buf[BMKT_MESSAGE_PAYLOAD_LEN_FIELD]; + if (msg_resp->payload_len > 0) + { + msg_resp->payload = &resp_buf[BMKT_MESSAGE_PAYLOAD_FIELD]; + } + else + { + msg_resp->payload = NULL; + } + + return BMKT_SUCCESS; +} + +int bmkt_parse_message_payload(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + int ret = BMKT_SUCCESS; + + memset(resp, 0, sizeof(bmkt_response_t)); + + resp->response_id = msg_resp->msg_id; + + switch(msg_resp->msg_id) + { + case BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_FAIL: + case BMKT_RSP_SENSOR_MODULE_TEST_FAIL: + case BMKT_RSP_FPS_INIT_FAIL: + case BMKT_RSP_FPS_MODE_FAIL: + case BMKT_RSP_SET_SECURITY_LEVEL_FAIL: + case BMKT_RSP_GET_SECURITY_LEVEL_FAIL: + case BMKT_RSP_CANCEL_OP_FAIL: + case BMKT_RSP_ENROLL_FAIL: + case BMKT_RSP_ID_FAIL: + case BMKT_RSP_VERIFY_FAIL: + case BMKT_RSP_QUERY_FAIL: + case BMKT_RSP_DEL_USER_FP_FAIL: + case BMKT_RSP_DEL_FULL_DB_FAIL: + case BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL: + case BMKT_RSP_POWER_DOWN_FAIL: + case BMKT_RSP_GET_VERSION_FAIL: + case BMKT_RSP_DISABLE_PAIRING_FAIL: + case BMKT_RSP_QUERY_PAIRING_FAIL: + case BMKT_RSP_SENSOR_STATUS_FAIL: + case BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL: + ret = parse_error_response(msg_resp, resp); + resp->complete = 1; + break; + + case BMKT_RSP_FPS_INIT_OK: + ret = parse_init_ok(msg_resp, resp); + resp->complete = 1; + break; + + case BMKT_RSP_CANCEL_OP_OK: + case BMKT_RSP_DEL_FULL_DB_OK: + case BMKT_RSP_DEL_USER_FP_OK: + /* responses with a payload of 0 + so the response indicates success */ + resp->result = BMKT_SUCCESS; + resp->complete = 1; + break; + + case BMKT_RSP_FPS_MODE_REPORT: + // parse_fps_mode + ret = parse_fps_mode_report(msg_resp, resp); + resp->complete = 1; + break; + + case BMKT_RSP_GET_SECURITY_LEVEL_REPORT: + case BMKT_RSP_SET_SECURITY_LEVEL_REPORT: + /* parse security level result */ + ret = parse_security_level_report(msg_resp, resp); + resp->complete = 1; + break; + + case BMKT_RSP_DELETE_PROGRESS: + ret = parse_del_all_users_progress_report(msg_resp, resp); + break; + + case BMKT_RSP_CAPTURE_COMPLETE: + resp->result = BMKT_SUCCESS; + break; + + case BMKT_RSP_ENROLL_READY: + resp->result = BMKT_SUCCESS; + break; + + case BMKT_RSP_ENROLL_REPORT: + ret = parse_enroll_report(msg_resp, resp); + break; + + case BMKT_RSP_ENROLL_OK: + resp->complete = 1; + ret = parse_enroll_ok(msg_resp, resp); + break; + + case BMKT_RSP_ID_OK: + case BMKT_RSP_VERIFY_OK: + ret = parse_auth_ok(msg_resp, resp); + resp->complete = 1; + break; + case BMKT_RSP_GET_ENROLLED_FINGERS_REPORT: + ret = parse_get_enrolled_fingers_report(msg_resp, resp); + resp->complete = 1; + break; + case BMKT_RSP_DATABASE_CAPACITY_REPORT: + resp->complete = 1; + ret = parse_db_cap_report(msg_resp, resp); + break; + case BMKT_RSP_TEMPLATE_RECORDS_REPORT: + ret = parse_get_enrolled_users_report(msg_resp, resp); + break; + case BMKT_RSP_QUERY_RESPONSE_COMPLETE: + resp->complete = 1; + break; + + case BMKT_RSP_VERSION_INFO: + ret = parse_get_version_report(msg_resp, resp); + resp->complete = 1; + break; + } + + return ret; +} diff --git a/libfprint/drivers/synaptics/bmkt_message.h b/libfprint/drivers/synaptics/bmkt_message.h new file mode 100644 index 00000000..9366771e --- /dev/null +++ b/libfprint/drivers/synaptics/bmkt_message.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef BMKT_MESSAGE_H_ +#define BMKT_MESSAGE_H_ + + +#define BMKT_MESSAGE_HEADER_ID 0xFE +#define BMKT_MESSAGE_HEADER_LEN (4) +#define BMKT_MESSAGE_CRC32_LEN (4) +#define BMKT_MESSAGE_HEADER_ID_FIELD 0 +#define BMKT_MESSAGE_SEQ_NUM_FIELD 1 +#define BMKT_MESSAGE_ID_FIELD 2 +#define BMKT_MESSAGE_PAYLOAD_LEN_FIELD 3 +#define BMKT_MESSAGE_PAYLOAD_FIELD 4 + +// Command messages +#define BMKT_CMD_CONTINUOUS_IMAGE_CAPTURE 0x01 +#define BMKT_CMD_CONTINUOUS_IMAGE_CAPTURE_STOP 0x04 +#define BMKT_CMD_SENSOR_MODULE_TEST 0x06 +#define BMKT_CMD_SENSOR_MODULE_TEST_START 0x08 +#define BMKT_CMD_NEXT_TEST_REPORT_CHUNK 0x0B +#define BMKT_CMD_FPS_INIT 0x11 +#define BMKT_CMD_GET_FPS_MODE 0x21 +#define BMKT_CMD_SET_SECURITY_LEVEL 0x31 +#define BMKT_CMD_GET_SECURITY_LEVEL 0x34 +#define BMKT_CMD_CANCEL_OP 0x41 +#define BMKT_CMD_ENROLL_USER 0x51 +#define BMKT_CMD_ENROLL_PAUSE 0x52 +#define BMKT_CMD_ENROLL_RESUME 0x53 +#define BMKT_CMD_ID_USER 0x61 +#define BMKT_CMD_VERIFY_USER 0x65 +#define BMKT_CMD_GET_TEMPLATE_RECORDS 0x71 +#define BMKT_CMD_GET_NEXT_QUERY_RESPONSE 0x72 +#define BMKT_CMD_GET_ENROLLED_FINGERS 0x73 +#define BMKT_CMD_GET_DATABASE_CAPACITY 0x74 +#define BMKT_CMD_DEL_USER_FP 0x81 +#define BMKT_CMD_DEL_FULL_DB 0x84 +#define BMKT_CMD_REPEAT_LAST_RSP 0x92 +#define BMKT_CMD_POWER_DOWN_NOTIFY 0xA1 +#define BMKT_CMD_GET_VERSION 0xB1 +#define BMKT_CMD_DISABLE_PAIRING 0xC2 +#define BMKT_CMD_QUERY_PAIRING 0xC5 +#define BMKT_CMD_SENSOR_STATUS 0xD1 +#define BMKT_CMD_ID_USER_IN_ORDER 0xE1 +#define BMKT_CMD_ID_NEXT_USER 0xE3 +#define BMKT_CMD_VERIFY_USER_IN_ORDER 0xF1 +#define BMKT_CMD_VERIFY_FINGERS_IN_ORDER 0xF2 +#define BMKT_CMD_GET_FINAL_RESULT 0xE4 + +#define BMKT_EVT_FINGER_REPORT 0x91 + +#define BMKT_EVT_FINGER_STATE_NOT_ON_SENSOR 0x00 +#define BMKT_EVT_FINGER_STATE_ON_SENSOR 0x01 + +typedef struct bmkt_msg_resp +{ + uint8_t msg_id; + uint8_t seq_num; + uint8_t payload_len; + uint8_t *payload; + int result; +} bmkt_msg_resp_t; + +int bmkt_compose_message(uint8_t *cmd, int *cmd_len, uint8_t msg_id, uint8_t seq_num, + uint8_t payload_size, const uint8_t *payload); + +int bmkt_parse_message_header(uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp); +int bmkt_parse_message_payload(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp); +#endif /* BMKT_MESSAGE_H_ */ diff --git a/libfprint/drivers/synaptics/bmkt_response.h b/libfprint/drivers/synaptics/bmkt_response.h new file mode 100644 index 00000000..874bf972 --- /dev/null +++ b/libfprint/drivers/synaptics/bmkt_response.h @@ -0,0 +1,489 @@ +/* + * Synaptics MiS Fingerprint Sensor Response Data Interface + * Copyright (C) 2019 Synaptics Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef _BMKT_RESPONSE_H_ +#define _BMKT_RESPONSE_H_ + +#include "bmkt.h" + +/** List of response message IDs */ +#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_FAIL 0x02 +#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_READY 0x03 +#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_STOPPED 0x05 +#define BMKT_RSP_SENSOR_MODULE_TEST_READY 0x07 +#define BMKT_RSP_SENSOR_MODULE_TEST_FAIL 0x09 +#define BMKT_RSP_SENSOR_MODULE_TEST_REPORT 0x0A +#define BMKT_RSP_NEXT_TEST_REPORT_CHUNK 0x0C + +/*! \addtogroup init +* Response IDs returned by fingerprint initialization operation +* @{ +*/ +/** Failed to initialize fingerprint sensor module */ +#define BMKT_RSP_FPS_INIT_FAIL 0x12 +/** Successfully initialized fingerprint sensor module */ +#define BMKT_RSP_FPS_INIT_OK 0x13 +/*! @} */ + +/*! \addtogroup mode +* Response IDs returned by get fingerprint mode operation +* @{ +*/ +/** Failed to get fingerprint sensor module’s current operational mode */ +#define BMKT_RSP_FPS_MODE_FAIL 0x22 +/** +* BMKT_RSP_FPS_MODE_REPORT: +* Response containing the current operational mode of the fingerprint sensor module +*
Payload data represented in \ref bmkt_fps_mode_resp_t struct +*/ +#define BMKT_RSP_FPS_MODE_REPORT 0x23 +/*! @} */ + +/*! \addtogroup setseclevel +* Response IDs returned by set security level operation +* @{ +*/ +/** Failed to set fingerprint sensor module security level */ +#define BMKT_RSP_SET_SECURITY_LEVEL_FAIL 0x32 +/** +* BMKT_RSP_SET_SECURITY_LEVEL_REPORT: +* Security level of the fingerprint sensor module was set successfully +*
Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct +*/ +#define BMKT_RSP_SET_SECURITY_LEVEL_REPORT 0x33 +/*! @} */ + +/*! \addtogroup getseclevel +* Response IDs returned by get security level operation +* @{ +*/ +/** Failed to get fingerprint sensor module security level */ +#define BMKT_RSP_GET_SECURITY_LEVEL_FAIL 0x35 +/** +* BMKT_RSP_GET_SECURITY_LEVEL_REPORT: +* Returns the current security level of the fingerprint sensor module +*
Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct +*/ +#define BMKT_RSP_GET_SECURITY_LEVEL_REPORT 0x36 +/*! @} */ + +/*! \addtogroup cancelop +* Response IDs returned by cancel_operation operation +* @{ +*/ +/** +* BMKT_RSP_CANCEL_OP_OK: +* Successfully canceled the current operation and returned +* fingerprint sensor module to idle mode +*/ +#define BMKT_RSP_CANCEL_OP_OK 0x42 +/** Failed to cancel the current operation */ +#define BMKT_RSP_CANCEL_OP_FAIL 0x43 +/*! @} */ + +/*! \addtogroup enrollment +* Response IDs returned by enrollment operation +* @{ +*/ +/** +* BMKT_RSP_ENROLL_READY: +* Fingerprint enrollment session has begun and the user can place +* their finger on the sensor +*/ +#define BMKT_RSP_ENROLL_READY 0x54 +/** Progress of the currently on-going fingerprint enrollment session */ +#define BMKT_RSP_ENROLL_REPORT 0x55 +/** Enrollment has been paused */ +#define BMKT_RSP_ENROLL_PAUSED 0x56 +/** Enrollment has been resume */ +#define BMKT_RSP_ENROLL_RESUMED 0x57 +/** The current enrollment session has encountered an error */ +#define BMKT_RSP_ENROLL_FAIL 0x58 +/** +* BMKT_RSP_ENROLL_OK: +* User has been successfully enrolled into the fingerprint sensor module +*
Contains payload data represented in \ref bmkt_enroll_resp_t struct +*/ +#define BMKT_RSP_ENROLL_OK 0x59 + +/** +* BMKT_RSP_CAPTURE_COMPLETE: +* Fingerprint image capture is complete and it is safe for the user +* to lift their finger off the sensor +*/ +#define BMKT_RSP_CAPTURE_COMPLETE 0x60 +/*! @} */ + +/*! \addtogroup identify +* Response IDs returned by identify operation. +* @{ +*/ +/* Fingerprint identification session has begun */ +#define BMKT_RSP_ID_READY 0x62 +/* Identification has failed */ +#define BMKT_RSP_ID_FAIL 0x63 +/** +* BMKT_RSP_ID_OK: +* User has been successfully identified +*
Contains payload data represented in \ref bmkt_auth_resp struct +*/ +#define BMKT_RSP_ID_OK 0x64 +/*! @} */ + +/*! \addtogroup verify +* Response IDs returned by identify operation. +* @{ +*/ +/** Fingerprint verification session has begun */ +#define BMKT_RSP_VERIFY_READY 0x66 +/** Verification has failed */ +#define BMKT_RSP_VERIFY_FAIL 0x67 +/** +* BMKT_RSP_VERIFY_OK: +* User’s identity has been successfully verified +*
Contains payload data represented in \ref bmkt_auth_resp struct +*/ +#define BMKT_RSP_VERIFY_OK 0x68 +/*! @} */ + +/** +* BMKT_RSP_TEMPLATE_RECORDS_REPORT: +* Response ID returned by get enrolled users templates record operation +*
Returns list of template records containing user IDs and corresponding finger IDs +*
Payload data represented in \ref bmkt_enroll_templates_resp_t struct +*/ +#define BMKT_RSP_TEMPLATE_RECORDS_REPORT 0x75 + +/** +* BMKT_RSP_QUERY_RESPONSE_COMPLETE: +* Response ID returned by get next query response operation +*
Complete sequence of messages containing the template records query response has been sent +*/ +#define BMKT_RSP_QUERY_RESPONSE_COMPLETE 0x76 + +/** +* BMKT_RSP_GET_ENROLLED_FINGERS_REPORT: +* Response ID returned by get enrolled fingers operation +*
Returns list of IDs of enrolled fingers for a specific user, +* along with template record status corresponding to each enrolled finger +*
Contains payload data represented in \ref bmkt_enrolled_fingers_resp_t struct +*/ +#define BMKT_RSP_GET_ENROLLED_FINGERS_REPORT 0x77 + +/*! \addtogroup dbcapacity +* Response IDs returned by get database capacity operation +* @{ +*/ +/** +* BMKT_RSP_DATABASE_CAPACITY_REPORT: +* Response specifying total capacity of fingerprint template database and +* how much free capacity is remaining along with how many templates are corrupted and +* how many bad (permanently unusable) storage slots are there. +*
Payload data represented in \ref bmkt_get_db_capacity_resp_t struct +*/ +#define BMKT_RSP_DATABASE_CAPACITY_REPORT 0x78 +/** Failed to execute database query */ +#define BMKT_RSP_QUERY_FAIL 0x79 +/*! @} */ + +/*! \addtogroup deluser +* Response IDs returned by delete fingerprint of specific user operation +* @{ +*/ +/** Failed to delete a user’s fingerprint template from the database */ +#define BMKT_RSP_DEL_USER_FP_FAIL 0x82 +/** +* BMKT_RSP_DEL_USER_FP_OK: +* Fingerprint template successfully deleted from the database. +* Returns the user ID and finger ID deleted. If value of finger ID is set equal to 0, +* then all fingerprint templates for that user have been deleted from the database +*
Payload data represented in \ref bmkt_del_user_resp_t struct +*/ +#define BMKT_RSP_DEL_USER_FP_OK 0x83 +/*! @} */ + +/*! \addtogroup delfulldb +* Response IDs returned by delete entire fingerprint template DB operation +* @{ +*/ +/** Failed to erase entire fingerprint template database */ +#define BMKT_RSP_DEL_FULL_DB_FAIL 0x85 +/** Successfully erased entire fingerprint template database */ +#define BMKT_RSP_DEL_FULL_DB_OK 0x86 +/** +* BMKT_RSP_DELETE_PROGRESS: +* Notify progress made during the on-going deletion of the full template database +*
Payload data represented in \ref bmkt_del_all_users_resp_t struct +*/ +#define BMKT_RSP_DELETE_PROGRESS 0x87 +/*! @} */ + +/** +* BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL: +* Response ID returned by repeate last response operation +*
Failed to retrieve and re-send last response +*/ +#define BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL 0x93 + +/*! \addtogroup pwrdwn +* Response IDs returned by power down notify operation +* @{ +*/ +/** Fingerprint sensor module is ready to be powered down */ +#define BMKT_RSP_POWER_DOWN_READY 0xA2 +/** Failed to go into power down mode */ +#define BMKT_RSP_POWER_DOWN_FAIL 0xA3 +/*! @} */ + +/*! \addtogroup versioninfo +* Response IDs returned by get version operation +* @{ +*/ +/** +* BMKT_RSP_VERSION_INFO: +* System version information of the fingerprint sensor module +*
Payload data represented in \ref bmkt_get_version_resp_t struct +*/ +#define BMKT_RSP_VERSION_INFO 0xB2 +/* Failed to retrieve and send last response */ +#define BMKT_RSP_GET_VERSION_FAIL 0xB3 +/*! @} */ + +/** +* BMKT_RSP_GENERAL_ERROR: +* Not tied to a specific command-response session. +*
Could be caused by corrupt or truncated command message +*/ +#define BMKT_RSP_GENERAL_ERROR 0xC1 +#define BMKT_RSP_DISABLE_PAIRING_FAIL 0xC3 +#define BMKT_RSP_DISABLE_PAIRING_OK 0xC4 +#define BMKT_RSP_QUERY_PAIRING_FAIL 0xC6 +#define BMKT_RSP_SENSOR_PAIRING_REPORT 0xC7 + +/*! \addtogroup versioninfo +* Response IDs returned by get sensor module status operation +* @{ +*/ +/** +* BMKT_RSP_SENSOR_STATUS_REPORT: +* Response returning the current status of the sensor module +*
Payload data represented in bmkt_XXX struct +*/ +#define BMKT_RSP_SENSOR_STATUS_REPORT 0xD2 +/** Failed to retrieve sensor status */ +#define BMKT_RSP_SENSOR_STATUS_FAIL 0xD3 +/*! @} */ + +/** +* BMKT_RSP_SEND_NEXT_USER_ID: +* Response ID returned by identify user in order operation +*
Notify to send the next batch of user IDs in the priority list +*/ +#define BMKT_RSP_SEND_NEXT_USER_ID 0xE2 +/** +* BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL: +* Response IDs returned by retrieve final result operation +*
Failed to retrieve and re-send cached final result +*/ +#define BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL 0xE5 + +/** +* Response payload data structure returned by sensor initialization operation. +*/ +typedef struct bmkt_init_resp +{ + uint8_t finger_presence; /**< Indicates finger existence on the sensor during startup */ +} bmkt_init_resp_t; + +/** +* bmkt_enroll_resp: +* Response payload data structure returned by enrollment operation. +*/ +typedef struct bmkt_enroll_resp +{ + int progress; /**< Shows current progress stutus [0-100] */ + uint8_t finger_id; /**< User's finger id [1-10] */ + uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< User name to be enrolled */ +} bmkt_enroll_resp_t; + +/** +* bmkt_auth_resp: +* Response payload data structure returned by identify and verify operations. +*/ +struct bmkt_auth_resp +{ + double match_result; /**< match result returned by matcher */ + uint8_t finger_id; /**< Matched templates's finger id */ + uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< Matched template's user id */ +}; + +typedef struct bmkt_auth_resp bmkt_verify_resp_t; /**< Returned by verify */ +typedef struct bmkt_auth_resp bmkt_identify_resp_t; /**< Returned by identify */ + +/** +* bmkt_fps_mode_resp: +* Response payload data structure returned by get fingerprint mode operation. +*/ +typedef struct bmkt_fps_mode_resp +{ + uint8_t mode; /**< One of the Level I bmkt_mode_t values */ + uint8_t level2_mode; /**< One of the Level II bmkt_mode_level2_t values */ + uint8_t cmd_id; /**< Message ID of command being executed when bmkt_get_fps_mode was called */ + uint8_t finger_presence; /**< Finger presence status value finger on sensor 1 / finger not on sensor 0 */ +} bmkt_fps_mode_resp_t; + +/** +* bmkt_get_version_resp: +* Response payload data structure returned by get version operation. +*/ +typedef struct bmkt_get_version_resp +{ + uint8_t part[BMKT_PART_NUM_LEN]; /**< Software Part Number */ + uint8_t year; /**< Software Version Year */ + uint8_t week; /**< Software Version Week */ + uint8_t patch; /**< Software Version Patch Level */ + uint8_t supplier_id[BMKT_SUPPLIER_ID_LEN]; /**< Software Supplier Identification */ +} bmkt_get_version_resp_t; + +/** +* bmkt_get_db_capacity_resp: +* Response payload data structure returned by get DB capacity operation. +*/ +typedef struct bmkt_get_db_capacity_resp +{ + uint8_t total; /**< Total Available Capacity: Total number of template records that can be stored */ + uint8_t empty; /**< Free Capacity: Number of template records that can still be stored */ + uint8_t bad_slots; /**< Number of bad template storage slots */ + uint8_t corrupt_templates; /**< Number of corrupt templates */ +} bmkt_get_db_capacity_resp_t; + +/** +* bmkt_sec_level: +* Security level values. +*/ +typedef enum bmkt_sec_level +{ + BMKT_SECURITY_LEVEL_LOW = 0x10, + BMKT_SECURITY_LEVEL_MEDIUM = 0x40, + BMKT_SECURITY_LEVEL_HIGH = 0x60, +} bmkt_sec_level_t; + +/** +* bmkt_set_sec_level_resp: +* Response payload data structure returned by get/set security level operations. +*/ +typedef struct bmkt_set_sec_level_resp +{ + bmkt_sec_level_t sec_level; /**< One of the bmkt_sec_level_t values */ +} bmkt_set_sec_level_resp_t; + +/** +* bmkt_del_all_users_resp: +* Response payload data structure returned by delete all enrolled users operation. +*/ +typedef struct bmkt_del_all_users_resp +{ + int progress; /**< Progress indicator as a percentage */ +} bmkt_del_all_users_resp_t; + +/** +* bmkt_del_user_resp: +* Response payload data structure returned by delete enrolled user operation. +*/ +typedef struct bmkt_del_user_resp +{ + int progress; /**< Progress indicator as a percentage */ +} bmkt_del_user_resp_t; + +/** +* bmkt_enroll_template: +* Structure of enrolled users template record data. +*/ +typedef struct bmkt_enroll_template +{ + uint8_t user_id_len; /**< Length of user_id string */ + uint8_t template_status; /**< Template record status */ + uint8_t finger_id; /**< ID of enrolled finger */ + uint8_t user_id[BMKT_MAX_USER_ID_LEN + 1]; /**< Name of the enrolled user */ +} bmkt_enroll_template_t; + +/** +* bmkt_enroll_templates_resp: +* Response payload data structure returned by get enrolled user list operation. +*/ +typedef struct bmkt_enroll_templates_resp +{ + uint8_t total_query_messages; /**< Total query response messages */ + uint8_t query_sequence; /**< Query response sequence number */ + bmkt_enroll_template_t templates[BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH]; /**< Enrolled user template records list */ +} bmkt_enroll_templates_resp_t; + +/** +* bmkt_enrolled_fingers: +* Structure of template record status corresponding to each enrolled finger. +*/ +typedef struct bmkt_enrolled_fingers +{ + uint8_t finger_id; /**< ID of enrolled finger */ + uint8_t template_status; /**< Template record status of finger_id */ +} bmkt_enrolled_fingers_t; + +/** +* bmkt_enrolled_fingers_resp: +* Response payload data structure returned by get enrolled fingers operation. +*/ +typedef struct bmkt_enrolled_fingers_resp +{ + bmkt_enrolled_fingers_t fingers[10]; /**< List of enroled fingers, max number of supported fingers per user is 10 */ +} bmkt_enrolled_fingers_resp_t; + +/** +* bmkt_response_data_t: +* Union combining all response payload data types. +*/ +typedef union { + bmkt_init_resp_t init_resp; + bmkt_enroll_resp_t enroll_resp; + bmkt_verify_resp_t verify_resp; + bmkt_identify_resp_t id_resp; + bmkt_fps_mode_resp_t fps_mode_resp; + bmkt_get_version_resp_t get_version_resp; + bmkt_get_db_capacity_resp_t db_cap_resp; + bmkt_set_sec_level_resp_t sec_level_resp; + bmkt_del_all_users_resp_t del_all_users_resp; + bmkt_enroll_templates_resp_t enroll_templates_resp; + bmkt_del_user_resp_t del_user_resp; + bmkt_enrolled_fingers_resp_t enrolled_fingers_resp; +} bmkt_response_data_t; + +/** +* bmkt_response: +* Structure to abstract different response structure types in one API +* to be used in bmkt_resp_cb_t callback function. +*/ +typedef struct bmkt_response +{ + int response_id; /**< Response message ID, one of th BMKT_RSP_XXX */ + int result; /**< Operation execution result code */ + int complete; /**< Operation completion status 1: complete / 0: not completed */ + bmkt_response_data_t response; /**< Operation specific response union */ +} bmkt_response_t; + +#endif /* _BMKT_RESPONSE_H_ */ diff --git a/libfprint/drivers/synaptics/sensor.h b/libfprint/drivers/synaptics/sensor.h new file mode 100644 index 00000000..b8ebdfb2 --- /dev/null +++ b/libfprint/drivers/synaptics/sensor.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _SENSOR_H_ +#define _SENSOR_H_ + +#include "usb_transport.h" +#define BMKT_MAX_PENDING_SESSIONS 2 + +typedef enum bmkt_sensor_state +{ + BMKT_SENSOR_STATE_UNINIT = 0, + BMKT_SENSOR_STATE_IDLE, + BMKT_SENSOR_STATE_INIT, + BMKT_SENSOR_STATE_EXIT, +} bmkt_sensor_state_t; + +typedef struct bmkt_sensor_drv bmkt_sensor_drv_t; + +typedef struct bmkt_sensor_version +{ + uint32_t build_time; + uint32_t build_num; + uint8_t version_major; + uint8_t version_minor; + uint8_t target; + uint8_t product; + uint8_t silicon_rev; + uint8_t formal_release; + uint8_t platform; + uint8_t patch; + uint8_t serial_number[6]; + uint16_t security; + uint8_t iface; + uint8_t device_type; +} bmkt_sensor_version_t; + +typedef struct bmkt_sensor +{ + bmkt_usb_transport_t usb_xport; + bmkt_sensor_version_t version; + bmkt_session_ctx_t pending_sessions[BMKT_MAX_PENDING_SESSIONS]; + int empty_session_idx; + int flags; + int seq_num; + bmkt_sensor_state_t sensor_state; + bmkt_event_cb_t finger_event_cb; + void *finger_cb_ctx; + bmkt_general_error_cb_t gen_err_cb; + void *gen_err_cb_ctx; + bmkt_op_state_t op_state; +} bmkt_sensor_t; + +int bmkt_sensor_open(bmkt_sensor_t *sensor, + bmkt_general_error_cb_t err_cb, void *err_cb_ctx); +int bmkt_sensor_close(bmkt_sensor_t *sensor); + +int bmkt_sensor_init_fps(bmkt_sensor_t *sensor); + +int bmkt_sensor_send_message(bmkt_sensor_t *sensor, uint8_t msg_id, uint8_t payload_size, + uint8_t *payload, bmkt_resp_cb_t resp_cb, void *resp_data); +int bmkt_sensor_handle_response(bmkt_sensor_t *sensor, uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp); + +int bmkt_sensor_send_async_read_command(bmkt_sensor_t *sensor); +#endif /* _SENSOR_H_ */ diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c new file mode 100644 index 00000000..ca99f64a --- /dev/null +++ b/libfprint/drivers/synaptics/synaptics.c @@ -0,0 +1,1040 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define FP_COMPONENT "synaptics" + +#include "drivers_api.h" + +#include "fpi-byte-reader.h" + +#include "synaptics.h" +#include "bmkt_message.h" + +G_DEFINE_TYPE(FpiDeviceSynaptics, fpi_device_synaptics, FP_TYPE_DEVICE) + +static const FpIdEntry id_table [ ] = { + { .vid = SYNAPTICS_VENDOR_ID, .pid = 0xBD, }, + + { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ +}; + + +static gboolean rand_string(char *str, size_t size) +{ + const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + srand(time(NULL)); + if (size) { + --size; + for (size_t n = 0; n < size; n++) { + int key = rand() % (int) (sizeof charset - 1); + str[n] = charset[key]; + } + str[size] = '\0'; + } + else + return FALSE; + return TRUE; +} + + + +static void +cmd_recieve_cb (FpiUsbTransfer *transfer, + FpDevice *device, + gpointer user_data, + GError *error) +{ + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); + SynCmdMsgCallback callback = user_data; + int res; + bmkt_msg_resp_t msg_resp; + bmkt_response_t resp; + + if (error) { + /* NOTE: assumes timeout should never happen for receiving. */ + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } + + res = bmkt_parse_message_header(&transfer->buffer[SENSOR_FW_REPLY_HEADER_LEN], + transfer->actual_length - SENSOR_FW_REPLY_HEADER_LEN, + &msg_resp); + if (res != BMKT_SUCCESS) { + g_warning ("Corrupted message received"); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + return; + } + + /* Special case events */ + if (msg_resp.msg_id == BMKT_EVT_FINGER_REPORT) { + if (msg_resp.payload_len != 1) { + g_warning ("Corrupted finger report received"); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + return; + } + + if (msg_resp.payload[0] == 0x01) { + self->finger_on_sensor = TRUE; + } else { + self->finger_on_sensor = FALSE; + if (self->cmd_complete_on_removal) { + fpi_ssm_mark_completed (transfer->ssm); + return; + } + } + + fp_dbg ("Finger is now %s the sensor", self->finger_on_sensor ? "on" : "off"); + + /* XXX: Call callback!?! */ + } + + res = bmkt_parse_message_payload (&msg_resp, &resp); + if (res != BMKT_SUCCESS) { + g_warning ("Could not parse message payload: %i", res); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + return; + } + + /* Special cancellation handling */ + if (resp.response_id == BMKT_RSP_CANCEL_OP_OK || resp.response_id == BMKT_RSP_CANCEL_OP_FAIL) { + if (resp.response_id == BMKT_RSP_CANCEL_OP_OK) { + fp_dbg ("Received cancellation success resonse"); + fpi_ssm_mark_failed (transfer->ssm, + g_error_new_literal (G_IO_ERROR, + G_IO_ERROR_CANCELLED, + "Device reported cancellation of operation")); + } else { + fp_dbg ("Cancellation failed, this should not happen"); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + } + return; + } + + if (msg_resp.seq_num == 0) { + /* XXX: Should we really abort the command on general error? + * The original code did not! */ + if (msg_resp.msg_id == BMKT_RSP_GENERAL_ERROR) { + guint16 err; + + /* XXX: It is weird that this is big endian. */ + err = FP_READ_UINT16_BE(msg_resp.payload); + + fp_warn("Received General Error %d from the sensor", (guint) err); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Received general error from device")); + //fpi_ssm_jump_to_state (transfer->ssm, fpi_ssm_get_cur_state (transfer->ssm)); + return; + } else { + fp_dbg ("Received message with 0 sequence number 0x%02x, ignoring!", + msg_resp.msg_id); + fpi_ssm_next_state (transfer->ssm); + return; + } + } + + /* We should only ever have one command running, and the sequence num needs + * to match. */ + if (msg_resp.seq_num != self->cmd_seq_num) { + fp_warn ("Got unexpected sequence number from device, %d instead of %d", + msg_resp.seq_num, + self->cmd_seq_num); + } + + if (callback) + callback (self, &resp, NULL); + + /* Callback may have queued a follow up command, then we need + * to restart the SSM. If not, we'll finish/wait for interrupt + * depending on resp.complete. */ + if (self->cmd_pending_transfer) + fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_SEND_PENDING); + else if (!resp.complete) + fpi_ssm_next_state (transfer->ssm); /* SYNAPTICS_CMD_WAIT_INTERRUPT */ + else + fpi_ssm_mark_completed (transfer->ssm); +} + +static void +cmd_interrupt_cb (FpiUsbTransfer *transfer, + FpDevice *device, + gpointer user_data, + GError *error) +{ + g_debug ("interrupt transfer done"); + if (error) { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + g_error_free (error); + fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_GET_RESP); + return; + } + + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } + g_clear_pointer (&error, g_error_free); + + if (transfer->buffer[0] & USB_ASYNC_MESSAGE_PENDING || error) + fpi_ssm_next_state (transfer->ssm); + else + fpi_usb_transfer_submit (transfer, 1000, NULL, cmd_interrupt_cb, NULL); +} + +static void +synaptics_cmd_run_state(FpiSsm *ssm, + FpDevice *dev, + void *user_data) +{ + g_autoptr(FpiUsbTransfer) transfer = NULL; + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev); + + switch (fpi_ssm_get_cur_state(ssm)) { + case SYNAPTICS_CMD_SEND_PENDING: + if (self->cmd_pending_transfer) { + self->cmd_pending_transfer->ssm = ssm; + fpi_usb_transfer_submit (self->cmd_pending_transfer, + 1000, + NULL, + fpi_ssm_usb_transfer_cb, + NULL); + g_clear_pointer (&self->cmd_pending_transfer, fpi_usb_transfer_unref); + } else { + fpi_ssm_next_state (ssm); + } + break; + + case SYNAPTICS_CMD_GET_RESP: + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + fpi_usb_transfer_fill_bulk (transfer, USB_EP_REPLY, MAX_TRANSFER_LEN); + fpi_usb_transfer_submit (transfer, + 5000, + NULL, + cmd_recieve_cb, + user_data); + + break; + + case SYNAPTICS_CMD_WAIT_INTERRUPT: + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + fpi_usb_transfer_fill_interrupt (transfer, USB_EP_INTERRUPT, USB_INTERRUPT_DATA_SIZE); + fpi_usb_transfer_submit (transfer, + 0, + self->interrupt_cancellable, + cmd_interrupt_cb, + NULL); + + break; + + case SYNAPTICS_CMD_SEND_ASYNC: + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + fpi_usb_transfer_fill_bulk (transfer, USB_EP_REQUEST, SENSOR_FW_CMD_HEADER_LEN); + transfer->buffer[0] = SENSOR_CMD_ASYNCMSG_READ; + fpi_usb_transfer_submit (transfer, + 1000, + NULL, + fpi_ssm_usb_transfer_cb, + NULL); + + break; + + case SYNAPTICS_CMD_RESTART: + fpi_ssm_jump_to_state (ssm, SYNAPTICS_CMD_SEND_PENDING); + break; + } +} + +static void +cmd_ssm_done (FpiSsm *ssm, + FpDevice *dev, + void *user_data, + GError *error) +{ + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev); + SynCmdMsgCallback callback = user_data; + + self->cmd_ssm = NULL; + + /* Notify about the SSM failure from here instead. */ + if (error) { + callback (self, NULL, error); + } else if (self->cmd_complete_on_removal) { + callback (self, NULL, self->cmd_complete_error); + self->cmd_complete_error = NULL; + } + self->cmd_complete_on_removal = FALSE; + g_clear_pointer (&self->cmd_complete_error, g_error_free); + fpi_ssm_free (ssm); +} + +static void +cmd_forget_cb (FpiUsbTransfer *transfer, + FpDevice *device, + gpointer user_data, + GError *error) +{ + if (error) { + g_warning ("Async command sending failed: %s", error->message); + g_error_free (error); + } else { + g_debug ("Async command sent successfully"); + } +} + +static void +synaptics_sensor_cmd (FpiDeviceSynaptics *self, + gint seq_num, + guint8 msg_id, + const guint8* payload, + gssize payload_len, + SynCmdMsgCallback callback) +{ + g_autoptr(FpiUsbTransfer) transfer = NULL; + guint8 real_seq_num; + gint msg_len; + gint res; + + /* callback may be NULL in two cases: + * - seq_num == -1 + * - a state machine is already running, continued command */ + g_assert (payload || payload_len == 0); + + /* seq_num of 0 means a normal command, -1 means the current commands + * sequence number should not be udpated (i.e. second async command which + * may only be a cancellation currently). */ + if (seq_num <= 0) { + self->last_seq_num = MAX(1, self->last_seq_num + 1); + real_seq_num = self->last_seq_num; + if (seq_num == 0) + self->cmd_seq_num = self->last_seq_num; + } else { + real_seq_num = seq_num; + self->last_seq_num = real_seq_num; + } + g_debug ("sequence number is %d", real_seq_num); + + /* We calculate the exact length here (we could also just create a larger + * buffer instead and check the result of bmkt_compose_message. */ + msg_len = BMKT_MESSAGE_HEADER_LEN + payload_len; + + /* Send out the command */ + transfer = fpi_usb_transfer_new (FP_DEVICE (self)); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk (transfer, + USB_EP_REQUEST, + msg_len + SENSOR_FW_CMD_HEADER_LEN); + + /* MIS sensors send ACE commands encapsulated in FW commands*/ + transfer->buffer[0] = SENSOR_CMD_ACE_COMMAND; + res = bmkt_compose_message (&transfer->buffer[1], + &msg_len, msg_id, + real_seq_num, + payload_len, + payload); + g_assert (res == BMKT_SUCCESS); + g_assert (msg_len + SENSOR_FW_CMD_HEADER_LEN == transfer->length); + + /* Special case for async command sending (should only be used for + * cancellation). */ + if (seq_num == -1) { + g_assert(callback == NULL); + + /* We just send and forget here. */ + fpi_usb_transfer_submit (transfer, 1000, NULL, cmd_forget_cb, NULL); + } else { + /* Command should be send using the state machine. */ + g_assert (self->cmd_pending_transfer == NULL); + + self->cmd_pending_transfer = g_steal_pointer (&transfer); + + if (self->cmd_ssm) { + /* Continued command, we already have an SSM with a callback. + * There is nothing to do in this case, the command will be + * sent automatically. */ + g_assert (callback == NULL); + } else { + /* Start of a new command, create the state machine. */ + g_assert (callback != NULL); + + self->cmd_ssm = fpi_ssm_new (FP_DEVICE (self), + synaptics_cmd_run_state, + SYNAPTICS_CMD_NUM_STATES, + callback); + + fpi_ssm_start (self->cmd_ssm, cmd_ssm_done); + } + } +} + +static gboolean +parse_print_data (GVariant *data, + guint8 *finger, + const guint8 **user_id, + gssize *user_id_len) +{ + g_autoptr(GVariant) user_id_var = NULL; + + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (finger != NULL, FALSE); + g_return_val_if_fail (user_id != NULL, FALSE); + g_return_val_if_fail (user_id_len != NULL, FALSE); + + *user_id = NULL; + *user_id_len = 0; + + if (!g_variant_check_format_string (data, "(y@ay)", FALSE)) + return FALSE; + + g_variant_get(data, + "(y@ay)", + finger, + &user_id_var); + + *user_id = g_variant_get_fixed_array (user_id_var, user_id_len, 1); + + if (*user_id_len == 0 || *user_id_len > BMKT_MAX_USER_ID_LEN) + return FALSE; + + if (*user_id_len <= 0 || *user_id[0] == ' ') + return FALSE; + + return TRUE; +} + +static void +list_msg_cb(FpiDeviceSynaptics *self, + bmkt_response_t *resp, + GError *error) +{ + bmkt_enroll_templates_resp_t *get_enroll_templates_resp; + + if (error) { + g_clear_pointer (&self->list_result, g_ptr_array_free); + fpi_device_list_complete (FP_DEVICE (self), NULL, error); + return; + } + + get_enroll_templates_resp = &resp->response.enroll_templates_resp; + + switch (resp->response_id) + { + case BMKT_RSP_QUERY_FAIL: + if (resp->result == BMKT_FP_DATABASE_EMPTY) { + fp_info("Database is empty"); + + fpi_device_list_complete (FP_DEVICE (self), + g_steal_pointer (&self->list_result), + NULL); + } else { + fp_info("Failed to query enrolled users: %d", resp->result); + g_clear_pointer (&self->list_result, g_ptr_array_free); + fpi_device_list_complete (FP_DEVICE (self), + NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Failed to query enrolled users")); + } + break; + case BMKT_RSP_QUERY_RESPONSE_COMPLETE: + fp_info("Query complete!"); + + fpi_device_list_complete (FP_DEVICE (self), + g_steal_pointer (&self->list_result), + NULL); + + break; + case BMKT_RSP_TEMPLATE_RECORDS_REPORT: + + for (int n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++) + { + GVariant *data = NULL; + GVariant *uid = NULL; + FpPrint *print; + + if (get_enroll_templates_resp->templates[n].user_id_len == 0) + continue; + + fp_info("![query %d of %d] template %d: status=0x%x, userId=%s, fingerId=%d", + get_enroll_templates_resp->query_sequence, + get_enroll_templates_resp->total_query_messages, + n, + get_enroll_templates_resp->templates[n].template_status, + get_enroll_templates_resp->templates[n].user_id, + get_enroll_templates_resp->templates[n].finger_id); + + print = fp_print_new (FP_DEVICE (self)); + uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + get_enroll_templates_resp->templates[n].user_id, + get_enroll_templates_resp->templates[n].user_id_len, + 1); + data = g_variant_new ("(y@ay)", + get_enroll_templates_resp->templates[n].finger_id, + uid); + + fpi_print_set_type (print, FP_PRINT_RAW); + g_object_set (print, "fp-data", data, NULL); + g_object_set (print, "description", get_enroll_templates_resp->templates[n].user_id, NULL); + g_ptr_array_add (self->list_result, g_object_ref_sink (print)); + } + + synaptics_sensor_cmd (self, + self->cmd_seq_num, + BMKT_CMD_GET_NEXT_QUERY_RESPONSE, + NULL, + 0, + NULL); + + break; + } +} + +static void +list(FpDevice *device) +{ + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); + + G_DEBUG_HERE(); + + self->list_result = g_ptr_array_new_with_free_func (g_object_unref); + synaptics_sensor_cmd (self, 0, BMKT_CMD_GET_TEMPLATE_RECORDS, NULL, 0, list_msg_cb); +} + +static void +verify_msg_cb(FpiDeviceSynaptics *self, + bmkt_response_t *resp, + GError *error) +{ + FpDevice *device = FP_DEVICE (self); + bmkt_verify_resp_t *verify_resp; + + if (error) { + fpi_device_verify_complete (device, FPI_MATCH_ERROR, NULL, error); + return; + } + + if (resp == NULL && self->cmd_complete_on_removal) { + fpi_device_verify_complete (device, + GPOINTER_TO_INT (self->cmd_complete_data), + NULL, + error); + return; + } + + verify_resp = &resp->response.verify_resp; + + switch (resp->response_id) + { + case BMKT_RSP_VERIFY_READY: + fp_info("Place Finger on the Sensor!"); + break; + + case BMKT_RSP_CAPTURE_COMPLETE: + fp_info("Fingerprint image capture complete!"); + break; + + case BMKT_RSP_VERIFY_FAIL: + if(resp->result == BMKT_SENSOR_STIMULUS_ERROR) { + fp_dbg ("delaying retry error until after finger removal!"); + self->cmd_complete_on_removal = TRUE; + self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_ERROR); + self->cmd_complete_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); + } else if (resp->result == BMKT_FP_NO_MATCH) { + fp_dbg ("delaying match failure until after finger removal!"); + self->cmd_complete_on_removal = TRUE; + self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_FAIL); + self->cmd_complete_error = NULL; + } else if (BMKT_FP_DATABASE_NO_RECORD_EXISTS) { + fp_info("Print is not in database"); + fpi_device_verify_complete (device, + FPI_MATCH_ERROR, + NULL, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND)); + } else { + fp_warn("Verify has failed: %d", resp->result); + fpi_device_verify_complete (device, FPI_MATCH_FAIL, NULL, NULL); + } + break; + + case BMKT_RSP_VERIFY_OK: + fp_info("Verify was successful! for user: %s finger: %d score: %f", + verify_resp->user_id, verify_resp->finger_id, verify_resp->match_result); + fpi_device_verify_complete (device, FPI_MATCH_SUCCESS, NULL, NULL); + break; + } +} + +static void +verify(FpDevice *device) +{ + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); + FpPrint *print = NULL; + g_autoptr(GVariant) data = NULL; + guint8 finger; + const guint8 *user_id; + gsize user_id_len = 0; + + fpi_device_get_verify_data (device, &print); + + g_object_get (print, "fp-data", &data, NULL); + g_debug ("data is %p", data); + if (!parse_print_data (data, &finger, &user_id, &user_id_len)) { + fpi_device_verify_complete (device, + FPI_MATCH_ERROR, + NULL, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); + return; + } + + G_DEBUG_HERE(); + + synaptics_sensor_cmd (self, 0, BMKT_CMD_VERIFY_USER, user_id, user_id_len, verify_msg_cb); +} + +static void +enroll_msg_cb(FpiDeviceSynaptics *self, + bmkt_response_t *resp, + GError *error) +{ + FpDevice *device = FP_DEVICE (self); + bmkt_enroll_resp_t *enroll_resp; + + if (error) { + fpi_device_enroll_complete (device, NULL, error); + return; + } + + enroll_resp = &resp->response.enroll_resp; + + switch (resp->response_id) + { + case BMKT_RSP_ENROLL_READY: + { + self->enroll_stage = 0; + fp_info("Place Finger on the Sensor!"); + break; + } + case BMKT_RSP_CAPTURE_COMPLETE: + { + fp_info("Fingerprint image capture complete!"); + break; + } + case BMKT_RSP_ENROLL_REPORT: + { + gint done_stages; + fp_info("Enrollment is %d %% ", enroll_resp->progress); + + done_stages = (enroll_resp->progress * ENROLL_SAMPLES + 99) / 100; + if (enroll_resp->progress < 100) + done_stages = MIN(done_stages, ENROLL_SAMPLES - 1); + + /* Emit a retry error if there has been no discernable + * progress. Some firmware revisions report more required + * touches. */ + if (self->enroll_stage == done_stages) + fpi_device_enroll_progress (device, + done_stages, + NULL, + fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); + + while (self->enroll_stage < done_stages) { + self->enroll_stage += 1; + fpi_device_enroll_progress (device, self->enroll_stage, NULL, NULL); + } + break; + } + case BMKT_RSP_ENROLL_PAUSED: + { + fp_info("Enrollment has been paused!"); + break; + } + case BMKT_RSP_ENROLL_RESUMED: + { + fp_info("Enrollment has been resumed!"); + break; + } + case BMKT_RSP_ENROLL_FAIL: + { + fp_info("Enrollment has failed!: %d", resp->result); + if (resp->result == BMKT_FP_DATABASE_FULL) + fpi_device_enroll_complete (device, + NULL, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_FULL)); + else + fpi_device_enroll_complete (device, + NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Enrollment failed")); + break; + } + case BMKT_RSP_ENROLL_OK: + { + FpPrint *print = NULL; + + fp_info("Enrollment was successful!"); + + fpi_device_get_enroll_data (device, &print); + + fpi_device_enroll_complete (device, g_object_ref (print), NULL); + break; + } + } +} + +#define TEMPLATE_ID_SIZE 20 + +static void +enroll(FpDevice *device) +{ + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); + FpPrint *print = NULL; + GVariant *data = NULL; + GVariant *uid = NULL; + guint8 finger; + char user_id[TEMPLATE_ID_SIZE + 1]; + gssize user_id_len; + guint8 payload[TEMPLATE_ID_SIZE + 1 + 2]; + + fpi_device_get_enroll_data (device, &print); + + G_DEBUG_HERE(); + + finger = 1; + rand_string (user_id, TEMPLATE_ID_SIZE); + user_id_len = strlen (user_id); + + uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + user_id, + user_id_len, + 1); + data = g_variant_new ("(y@ay)", + finger, + uid); + + fpi_print_set_type (print, FP_PRINT_RAW); + g_object_set (print, "fp-data", data, NULL); + g_object_set (print, "description", user_id, NULL); + + g_debug("user_id: %s, finger: %d", user_id, finger); + + /* Backup options are not supported for Prometheus */ + payload[0] = 0; + payload[1] = finger; + memcpy (payload + 2, user_id, user_id_len); + + synaptics_sensor_cmd (self, 0, BMKT_CMD_ENROLL_USER, payload, user_id_len + 2, enroll_msg_cb); +} + +static void +delete_msg_cb(FpiDeviceSynaptics *self, + bmkt_response_t *resp, + GError *error) +{ + FpDevice *device = FP_DEVICE (self); + bmkt_del_user_resp_t *del_user_resp; + + if (error) { + fpi_device_delete_complete (device, error); + return; + } + + del_user_resp = &resp->response.del_user_resp; + + switch (resp->response_id) + { + case BMKT_RSP_DELETE_PROGRESS: + fp_info("Deleting Enrolled Users is %d%% complete", + del_user_resp->progress); + break; + case BMKT_RSP_DEL_USER_FP_FAIL: + fp_info("Failed to delete enrolled user: %d", resp->result); + if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS) + fpi_device_delete_complete (device, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND)); + else + fpi_device_delete_complete (device, + fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + break; + case BMKT_RSP_DEL_USER_FP_OK: + fp_info("Successfully deleted enrolled user"); + fpi_device_delete_complete (device, NULL); + break; + } +} + +static void +delete_print(FpDevice *device) +{ + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); + FpPrint *print = NULL; + g_autoptr(GVariant) data = NULL; + guint8 finger; + const guint8 *user_id; + gsize user_id_len = 0; + g_autofree guint8 *payload = NULL; + + fpi_device_get_delete_data (device, &print); + + g_object_get (print, "fp-data", &data, NULL); + g_debug ("data is %p", data); + if (!parse_print_data (data, &finger, &user_id, &user_id_len)) { + fpi_device_delete_complete (device, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); + return; + } + + G_DEBUG_HERE(); + + payload = g_malloc0 (1 + user_id_len); + payload[0] = finger; + memcpy (payload + 1, user_id, user_id_len); + + synaptics_sensor_cmd (self, 0, BMKT_CMD_DEL_USER_FP, payload, user_id_len + 1, delete_msg_cb); +} + +static void +dev_probe(FpDevice *device) +{ + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); + GUsbDevice *usb_dev; + FpiUsbTransfer *transfer; + FpiByteReader reader; + GError *error = NULL; + guint16 status; + const guint8 *data; + gboolean read_ok = TRUE; + g_autofree gchar *serial = NULL; + + G_DEBUG_HERE(); + + /* Claim usb interface */ + usb_dev = fpi_device_get_usb_device(device); + if (!g_usb_device_open (usb_dev, &error)) { + fpi_device_probe_complete (device, NULL, NULL, error); + return; + } + + if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error)) { + fpi_device_probe_complete (device, NULL, NULL, error); + return; + } + + if (!g_usb_device_claim_interface (fpi_device_get_usb_device(device), 0, 0, &error)) + goto err_close; + + /* TODO: Do not do this synchronous. */ + transfer = fpi_usb_transfer_new (device); + fpi_usb_transfer_fill_bulk (transfer, USB_EP_REQUEST, SENSOR_FW_CMD_HEADER_LEN); + transfer->short_is_error = TRUE; + transfer->buffer[0] = SENSOR_CMD_GET_VERSION; + if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error)) + goto err_close; + fpi_usb_transfer_unref (transfer); + + + transfer = fpi_usb_transfer_new (device); + fpi_usb_transfer_fill_bulk (transfer, USB_EP_REPLY, 40); + if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error)) + goto err_close; + + fpi_byte_reader_init (&reader, transfer->buffer, transfer->actual_length); + + if (!fpi_byte_reader_get_uint16_le (&reader, &status)) { + g_warning ("Transfer in response to version query was too short"); + error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); + goto err_close; + } + if (status != 0) { + g_warning ("Device responded with error: %d", status); + error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); + goto err_close; + } + + read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_time); + read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_num); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.version_major); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.version_minor); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.target); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.product); + + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.silicon_rev); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.formal_release); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.platform); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.patch); + if (fpi_byte_reader_get_data (&reader, sizeof(self->mis_version.serial_number), &data)) + memcpy (self->mis_version.serial_number, data, sizeof(self->mis_version.serial_number)); + else + read_ok = FALSE; + read_ok &= fpi_byte_reader_get_uint16_le (&reader, &self->mis_version.security); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.iface); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.device_type); + + if (!read_ok) { + g_warning ("Transfer in response to verison query was too short"); + error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); + goto err_close; + } + + fp_dbg("Build Time: %d", self->mis_version.build_time); + fp_dbg("Build Num: %d", self->mis_version.build_num); + fp_dbg("Version: %d.%d", self->mis_version.version_major, self->mis_version.version_minor); + fp_dbg("Target: %d", self->mis_version.target); + fp_dbg("Product: %d", self->mis_version.product); + + fpi_usb_transfer_unref (transfer); + + /* We need at least firmware version 10.1, and for 10.1 build 2989158 */ + if (self->mis_version.version_major < 10 || + self->mis_version.version_minor < 1 || + (self->mis_version.version_major == 10 && + self->mis_version.version_minor == 1 && + self->mis_version.build_num < 2989158)) + { + fp_warn ("Firmware version %d.%d with build number %d is unsupported", + self->mis_version.version_major, + self->mis_version.version_minor, + self->mis_version.build_num); + + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Unsupported firmware version"); + goto err_close; + } + + /* This is the same as the serial_number from above, hex encoded and somewhat reordered */ + /* Should we add in more, e.g. the chip revision? */ + serial = g_usb_device_get_string_descriptor (usb_dev, + g_usb_device_get_serial_number_index (usb_dev), + &error); + + g_usb_device_close (usb_dev, NULL); + + fpi_device_probe_complete (device, serial, NULL, error); + + return; + +err_close: + g_usb_device_close (usb_dev, NULL); + fpi_device_probe_complete (device, NULL, NULL, error); +} + +static void +fps_init_msg_cb(FpiDeviceSynaptics *self, + bmkt_response_t *resp, + GError *error) +{ + if (error) { + fpi_device_open_complete (FP_DEVICE (self), error); + return; + } + + /* BMKT_OPERATION_DENIED is returned if the sensor is already initialized */ + if (resp->result == BMKT_SUCCESS || resp->result == BMKT_OPERATION_DENIED) { + fpi_device_open_complete (FP_DEVICE (self), NULL); + } else { + g_warning ("Initializing fingerprint sensor failed with %d!", resp->result); + fpi_device_open_complete (FP_DEVICE (self), + fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + } +} + +static void +dev_init (FpDevice *device) +{ + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); + GError *error = NULL; + + G_DEBUG_HERE(); + + self->interrupt_cancellable = g_cancellable_new (); + + if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error)) + goto error; + + /* Claim usb interface */ + if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error)) + goto error; + + synaptics_sensor_cmd (self, 0, BMKT_CMD_FPS_INIT, NULL, 0, fps_init_msg_cb); + + return; + +error: + fpi_device_open_complete (FP_DEVICE (self), error); +} + +static void +dev_exit(FpDevice *device) +{ + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); + GError *error = NULL; + + G_DEBUG_HERE(); + + /* Release usb interface */ + g_usb_device_release_interface(fpi_device_get_usb_device(device), 0, 0, &error); + + g_clear_object (&self->interrupt_cancellable); + + fpi_device_close_complete(device, error); +} + +static void +cancel(FpDevice *dev) +{ + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS(dev); + + /* We just send out a cancel command and hope for the best. */ + synaptics_sensor_cmd (self, -1, BMKT_CMD_CANCEL_OP, NULL, 0, NULL); + + /* Cancel any current interrupt transfer (resulting us to go into + * response reading mode again); then create a new cancellable + * for the next transfers. */ + g_cancellable_cancel (self->interrupt_cancellable); + g_clear_object (&self->interrupt_cancellable); + self->interrupt_cancellable = g_cancellable_new (); +} + +static void +fpi_device_synaptics_init(FpiDeviceSynaptics *self) { +} + +static void +fpi_device_synaptics_class_init(FpiDeviceSynapticsClass *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + + dev_class->id = FP_COMPONENT; + dev_class->full_name = SYNAPTICS_DRIVER_FULLNAME; + + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->scan_type = FP_SCAN_TYPE_PRESS; + dev_class->id_table = id_table; + dev_class->nr_enroll_stages = ENROLL_SAMPLES; + + dev_class->open = dev_init; + dev_class->close = dev_exit; + dev_class->probe = dev_probe; + dev_class->verify = verify; + dev_class->enroll = enroll; + dev_class->delete = delete_print; + dev_class->cancel = cancel; + dev_class->list = list; +} diff --git a/libfprint/drivers/synaptics/synaptics.h b/libfprint/drivers/synaptics/synaptics.h new file mode 100644 index 00000000..a0bc0b8e --- /dev/null +++ b/libfprint/drivers/synaptics/synaptics.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __synaptics_h__ +#define __synaptics_h__ + +#include "fpi-device.h" +#include "fpi-ssm.h" + +#define SYNAPTICS_VENDOR_ID 0x06cb + +G_DECLARE_FINAL_TYPE(FpiDeviceSynaptics, fpi_device_synaptics, FPI, DEVICE_SYNAPTICS, FpDevice) + + +#define MAX_TRANSFER_LEN 263 + 1 /* SPI Header */ + 2 /* VCSFW header */ + +#define USB_EP_REQUEST 0x01 +#define USB_EP_REPLY 0x81 +#define USB_EP_FINGERPRINT 0x82 +#define USB_EP_INTERRUPT 0x83 + +#define USB_ASYNC_MESSAGE_PENDING 0x4 +#define USB_INTERRUPT_DATA_SIZE 7 + +#define SENSOR_CMD_GET_VERSION 1 +#define SENSOR_CMD_ACE_COMMAND 167 +#define SENSOR_CMD_ASYNCMSG_READ 168 + +#define SENSOR_FW_CMD_HEADER_LEN 1 +#define SENSOR_FW_REPLY_HEADER_LEN 2 + + +/* Number of enroll stages */ +#define ENROLL_SAMPLES 8 + + +#define SYNAPTICS_DRIVER_FULLNAME "Synaptics Sensors" +#include "bmkt.h" +#include "bmkt_response.h" + + +typedef struct bmkt_sensor_version +{ + uint32_t build_time; + uint32_t build_num; + uint8_t version_major; + uint8_t version_minor; + uint8_t target; + uint8_t product; + uint8_t silicon_rev; + uint8_t formal_release; + uint8_t platform; + uint8_t patch; + uint8_t serial_number[6]; + uint16_t security; + uint8_t iface; + uint8_t device_type; +} bmkt_sensor_version_t; + + +struct syna_enroll_resp_data +{ + int progress; +}; +typedef enum syna_state +{ + SYNA_STATE_UNINIT = 0, + SYNA_STATE_IDLE , + SYNA_STATE_ENROLL , + SYNA_STATE_IDENTIFY , + SYNA_STATE_IDENTIFY_DELAY_RESULT , + SYNA_STATE_VERIFY , + SYNA_STATE_VERIFY_DELAY_RESULT , + SYNA_STATE_DELETE , +} syna_state_t; + +typedef enum +{ + SYNAPTICS_CMD_SEND_PENDING = 0, + SYNAPTICS_CMD_GET_RESP, + SYNAPTICS_CMD_WAIT_INTERRUPT, + SYNAPTICS_CMD_SEND_ASYNC, + SYNAPTICS_CMD_RESTART, + SYNAPTICS_CMD_NUM_STATES, +} SynapticsCmdState; + + +typedef void (*SynCmdMsgCallback) (FpiDeviceSynaptics *self, bmkt_response_t *resp, GError *error); + +struct _FpiDeviceSynaptics +{ + FpDevice parent; + + guint8 cmd_seq_num; + guint8 last_seq_num; + FpiSsm *cmd_ssm; + FpiUsbTransfer *cmd_pending_transfer; + gboolean cmd_complete_on_removal; + GError *cmd_complete_error; + void *cmd_complete_data; + + bmkt_sensor_version_t mis_version; + + GCancellable *interrupt_cancellable; + + gint enroll_stage; + gboolean finger_on_sensor; + GPtrArray *list_result; + + + struct syna_enroll_resp_data enroll_resp_data; + syna_state_t state; +}; + +#endif //__synaptics_h__ diff --git a/libfprint/meson.build b/libfprint/meson.build index f2a2e4dd..af2fe849 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -141,6 +141,12 @@ foreach driver: drivers if driver == 'virtual_image' drivers_sources += [ 'drivers/virtual-image.c' ] endif + if driver == 'synaptics' + drivers_sources += [ + 'drivers/synaptics/synaptics.c', + 'drivers/synaptics/bmkt_message.c', + ] + endif endforeach if aeslib diff --git a/meson.build b/meson.build index 8481073f..5552e200 100644 --- a/meson.build +++ b/meson.build @@ -51,7 +51,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603', 'vcom5s' ] +default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603', 'vcom5s', 'synaptics'] all_drivers = default_drivers + virtual_drivers From 664d18836e0b2ae99052b29e771be65f0df17a12 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 12 Aug 2019 18:50:07 +0200 Subject: [PATCH 43/73] synaptics: Encode metadata into userid string This allows us to properly extract metadata for prints that are stored on the device. We could for example delete the oldest prints first with this information. --- libfprint/drivers/synaptics/synaptics.c | 101 ++++++++++++++++++------ 1 file changed, 77 insertions(+), 24 deletions(-) diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index ca99f64a..0621b08f 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -34,25 +34,6 @@ static const FpIdEntry id_table [ ] = { }; -static gboolean rand_string(char *str, size_t size) -{ - const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - srand(time(NULL)); - if (size) { - --size; - for (size_t n = 0; n < size; n++) { - int key = rand() % (int) (sizeof charset - 1); - str[n] = charset[key]; - } - str[size] = '\0'; - } - else - return FALSE; - return TRUE; -} - - - static void cmd_recieve_cb (FpiUsbTransfer *transfer, FpDevice *device, @@ -470,6 +451,7 @@ list_msg_cb(FpiDeviceSynaptics *self, GVariant *data = NULL; GVariant *uid = NULL; FpPrint *print; + gchar *userid; if (get_enroll_templates_resp->templates[n].user_id_len == 0) continue; @@ -482,6 +464,8 @@ list_msg_cb(FpiDeviceSynaptics *self, get_enroll_templates_resp->templates[n].user_id, get_enroll_templates_resp->templates[n].finger_id); + userid = get_enroll_templates_resp->templates[n].user_id; + print = fp_print_new (FP_DEVICE (self)); uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, get_enroll_templates_resp->templates[n].user_id, @@ -494,6 +478,41 @@ list_msg_cb(FpiDeviceSynaptics *self, fpi_print_set_type (print, FP_PRINT_RAW); g_object_set (print, "fp-data", data, NULL); g_object_set (print, "description", get_enroll_templates_resp->templates[n].user_id, NULL); + + /* The format has 24 bytes at the start and some dashes in the right places */ + if (g_str_has_prefix (userid, "FP1-") && strlen(userid) >= 24 && + userid[12] == '-' && userid[14] == '-' && userid[23] == '-') { + g_autofree gchar *copy = g_strdup(userid); + gint32 date_ymd; + GDate *date = NULL; + gint32 finger; + gchar *username; + /* Try to parse information from the string. */ + + copy[12] = '\0'; + date_ymd = g_ascii_strtod (copy + 4, NULL); + if (date_ymd > 0) + date = g_date_new_dmy (date_ymd % 100, + (date_ymd / 100) % 100, + date_ymd / 10000); + else + date = g_date_new (); + + fp_print_set_enroll_date (print, date); + g_date_free (date); + + copy[14] = '\0'; + finger = g_ascii_strtoll (copy + 13, NULL, 16); + fp_print_set_finger (print, finger); + + /* We ignore the next chunk, it is just random data. + * Then comes the username; nobody is the default if the metadata + * is unknown */ + username = copy + 24; + if (strlen(username) > 0 && g_strcmp0 (username, "nobody") != 0) + fp_print_set_username (print, username); + } + g_ptr_array_add (self->list_result, g_object_ref_sink (print)); } @@ -709,18 +728,50 @@ enroll(FpDevice *device) FpPrint *print = NULL; GVariant *data = NULL; GVariant *uid = NULL; - guint8 finger; - char user_id[TEMPLATE_ID_SIZE + 1]; + const gchar *username; + guint finger; + g_autofree gchar *user_id; gssize user_id_len; - guint8 payload[TEMPLATE_ID_SIZE + 1 + 2]; + g_autofree guint8 *payload = NULL; + const GDate *date; + gint y, m, d; + gint32 rand_id = 0; fpi_device_get_enroll_data (device, &print); G_DEBUG_HERE(); - finger = 1; - rand_string (user_id, TEMPLATE_ID_SIZE); + date = fp_print_get_enroll_date (print); + if (date && g_date_valid (date)) { + y = date->year; + m = date->month; + d = date->day; + } else { + y = 0; + m = 0; + d = 0; + } + + username = fp_print_get_username (print); + if (!username) + username = "nobody"; + + if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0) + rand_id = 0; + else + rand_id = g_random_int(); + + user_id = g_strdup_printf ("FP1-%04d%02d%02d-%X-%08X-%s", + y, m, d, + fp_print_get_finger (print), + rand_id, + username); + user_id_len = strlen (user_id); + user_id_len = MIN(BMKT_MAX_USER_ID_LEN, user_id_len); + + /* We currently always use finger 1 from the devices piont of view */ + finger = 1; uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, user_id, @@ -736,6 +787,8 @@ enroll(FpDevice *device) g_debug("user_id: %s, finger: %d", user_id, finger); + payload = g_malloc0(user_id_len + 2); + /* Backup options are not supported for Prometheus */ payload[0] = 0; payload[1] = finger; From 5eba6067a3963927f0e69551d3c6480f0a447fb6 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 6 Aug 2019 12:39:38 +0200 Subject: [PATCH 44/73] elan: Port driver to new API This changes the cancellation logic a bit to ensure we always deactivate the device (equivalent to the AWAIT_OFF state in the driver). All commands except for the deactivation command should be cancelled when an operation is stopped, this is to ensure that the LED is turned off at the end of an operation. --- libfprint/drivers/elan.c | 649 +++++++++++++++++++-------------------- libfprint/drivers/elan.h | 133 ++++---- meson.build | 2 +- 3 files changed, 391 insertions(+), 393 deletions(-) diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c index e9dad43e..2c4e3be4 100644 --- a/libfprint/drivers/elan.c +++ b/libfprint/drivers/elan.c @@ -41,14 +41,6 @@ #include "drivers_api.h" #include "elan.h" -#define dbg_buf(buf, len) \ - if (len == 1) \ - fp_dbg("%02x", buf[0]); \ - else if (len == 2) \ - fp_dbg("%04x", buf[0] << 8 | buf[1]); \ - else if (len > 2) \ - fp_dbg("%04x... (%d bytes)", buf[0] << 8 | buf[1], len) - unsigned char elan_get_pixel(struct fpi_frame_asmbl_ctx *ctx, struct fpi_frame *frame, unsigned int x, unsigned int y) @@ -63,7 +55,9 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = { .get_pixel = elan_get_pixel, }; -struct elan_dev { +struct _FpiDeviceElan { + FpImageDevice parent; + /* device config */ unsigned short dev_type; unsigned short fw_ver; @@ -73,12 +67,12 @@ struct elan_dev { /* commands */ const struct elan_cmd *cmd; int cmd_timeout; - fpi_usb_transfer *cur_transfer; /* end commands */ /* state */ - enum fp_imgdev_state dev_state; - enum fp_imgdev_state dev_state_next; + gboolean deactivating; + FpImageDeviceState dev_state; + FpImageDeviceState dev_state_next; unsigned char *last_read; unsigned char calib_atts_left; unsigned char calib_status; @@ -90,18 +84,19 @@ struct elan_dev { GSList *frames; /* end state */ }; +G_DECLARE_FINAL_TYPE(FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN, + FpImageDevice); +G_DEFINE_TYPE(FpiDeviceElan, fpi_device_elan, FP_TYPE_IMAGE_DEVICE); int cmp_short(const void *a, const void *b) { return (int)(*(short *)a - *(short *)b); } -static void elan_dev_reset(struct elan_dev *elandev) +static void elan_dev_reset_state(FpiDeviceElan *elandev) { G_DEBUG_HERE(); - BUG_ON(elandev->cur_transfer); - elandev->cmd = NULL; elandev->cmd_timeout = ELAN_CMD_TIMEOUT; @@ -115,7 +110,7 @@ static void elan_dev_reset(struct elan_dev *elandev) elandev->num_frames = 0; } -static void elan_save_frame(struct elan_dev *elandev, unsigned short *frame) +static void elan_save_frame(FpiDeviceElan *self, unsigned short *frame) { G_DEBUG_HERE(); @@ -133,25 +128,25 @@ static void elan_save_frame(struct elan_dev *elandev, unsigned short *frame) * we also discard stripes of 'frame_margin' from bottom and top because * assembling works bad for tall frames */ - unsigned char frame_width = elandev->frame_width; - unsigned char frame_height = elandev->frame_height; - unsigned char raw_height = elandev->raw_frame_height; - unsigned char frame_margin = (raw_height - elandev->frame_height) / 2; + unsigned char frame_width = self->frame_width; + unsigned char frame_height = self->frame_height; + unsigned char raw_height = self->raw_frame_height; + unsigned char frame_margin = (raw_height - self->frame_height) / 2; int frame_idx, raw_idx; for (int y = 0; y < frame_height; y++) for (int x = 0; x < frame_width; x++) { - if (elandev->dev_type & ELAN_NOT_ROTATED) + if (self->dev_type & ELAN_NOT_ROTATED) raw_idx = x + (y + frame_margin) * frame_width; else raw_idx = frame_margin + y + x * raw_height; frame_idx = x + y * frame_width; frame[frame_idx] = - ((unsigned short *)elandev->last_read)[raw_idx]; + ((unsigned short *) self->last_read)[raw_idx]; } } -static void elan_save_background(struct elan_dev *elandev) +static void elan_save_background(FpiDeviceElan *elandev) { G_DEBUG_HERE(); @@ -197,7 +192,7 @@ static void elan_save_background(struct elan_dev *elandev) * \ * ======== 0 \___> ======== 0 */ -static int elan_save_img_frame(struct elan_dev *elandev) +static int elan_save_img_frame(FpiDeviceElan *elandev) { G_DEBUG_HERE(); @@ -290,157 +285,145 @@ static void elan_process_frame_thirds(unsigned short *raw_frame, *frames = g_slist_prepend(*frames, frame); } -static void elan_submit_image(struct fp_img_dev *dev) +static void elan_submit_image(FpImageDevice *dev) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); int num_frames; GSList *raw_frames; GSList *frames = NULL; - struct fp_img *img; + FpImage *img; G_DEBUG_HERE(); - num_frames = elandev->num_frames - ELAN_SKIP_LAST_FRAMES; - raw_frames = g_slist_nth(elandev->frames, ELAN_SKIP_LAST_FRAMES); + num_frames = self->num_frames - ELAN_SKIP_LAST_FRAMES; + raw_frames = g_slist_nth(self->frames, ELAN_SKIP_LAST_FRAMES); - assembling_ctx.frame_width = elandev->frame_width; - assembling_ctx.frame_height = elandev->frame_height; - assembling_ctx.image_width = elandev->frame_width * 3 / 2; - g_slist_foreach(raw_frames, (GFunc) elandev->process_frame, &frames); + assembling_ctx.frame_width = self->frame_width; + assembling_ctx.frame_height = self->frame_height; + assembling_ctx.image_width = self->frame_width * 3 / 2; + g_slist_foreach(raw_frames, (GFunc) self->process_frame, &frames); fpi_do_movement_estimation(&assembling_ctx, frames, num_frames); img = fpi_assemble_frames(&assembling_ctx, frames, num_frames); - img->flags |= FP_IMG_PARTIAL; - fpi_imgdev_image_captured(dev, img); + fpi_image_device_image_captured(dev, img); } -static void elan_cmd_done(fpi_ssm *ssm) +static void elan_cmd_done(FpiSsm *ssm) { G_DEBUG_HERE(); fpi_ssm_next_state(ssm); } -static void elan_cmd_cb(struct libusb_transfer *transfer, - struct fp_dev *_dev, - fpi_ssm *ssm, - void *user_data) +static void elan_cmd_cb(FpiUsbTransfer *transfer, FpDevice *dev, + gpointer user_data, GError *error) { - struct fp_img_dev *dev; - struct elan_dev *elandev; + FpiSsm *ssm = transfer->ssm; + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); G_DEBUG_HERE(); - if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { - fp_dbg("transfer cancelled"); + if (error) { + /* XXX: In the cancellation case we used to not + * mark the SSM as failed?! */ + fpi_ssm_mark_failed (transfer->ssm, error); return; } - dev = FP_IMG_DEV(_dev); - elandev = FP_INSTANCE_DATA(_dev); - elandev->cur_transfer = NULL; - - switch (transfer->status) { - case LIBUSB_TRANSFER_COMPLETED: - if (transfer->length != transfer->actual_length) { - fp_dbg("transfer length error: expected %d, got %d", - transfer->length, transfer->actual_length); - elan_dev_reset(elandev); - fpi_ssm_mark_failed(ssm, -EPROTO); - } else if (transfer->endpoint & LIBUSB_ENDPOINT_IN) { - /* just finished receiving */ - elandev->last_read = g_memdup(transfer->buffer, transfer->actual_length); - dbg_buf(transfer->buffer, transfer->actual_length); - elan_cmd_done(ssm); - } else { - /* just finished sending */ - G_DEBUG_HERE(); - elan_cmd_read(ssm, dev); - } - break; - case LIBUSB_TRANSFER_TIMED_OUT: - fp_dbg("transfer timed out"); - fpi_ssm_mark_failed(ssm, -ETIMEDOUT); - break; - default: - fp_dbg("transfer failed: %d", transfer->status); - elan_dev_reset(elandev); - fpi_ssm_mark_failed(ssm, -EIO); + /* XXX: We used to reset the device in error cases! */ + if (transfer->endpoint & FPI_USB_ENDPOINT_IN) { + /* just finished receiving */ + self->last_read = g_memdup(transfer->buffer, transfer->actual_length); + elan_cmd_done(ssm); + } else { + /* just finished sending */ + G_DEBUG_HERE(); + elan_cmd_read(ssm, dev); } } -static void elan_cmd_read(fpi_ssm *ssm, struct fp_img_dev *dev) +static void elan_cmd_read(FpiSsm *ssm, FpDevice *dev) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); - int response_len = elandev->cmd->response_len; - unsigned char *buffer; + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); + FpiUsbTransfer *transfer; + GCancellable *cancellable = NULL; + int response_len = self->cmd->response_len; G_DEBUG_HERE(); - if (elandev->cmd->response_len == ELAN_CMD_SKIP_READ) { + if (self->cmd->response_len == ELAN_CMD_SKIP_READ) { fp_dbg("skipping read, not expecting anything"); elan_cmd_done(ssm); return; } - if (elandev->dev_type == ELAN_0C42) { + if (self->dev_type == ELAN_0C42) { /* ELAN_0C42 sends an extra byte in one byte responses */ - if (elandev->cmd->response_len == 1) + if (self->cmd->response_len == 1) response_len = 2; } - if (elandev->cmd->cmd == get_image_cmd.cmd) + if (self->cmd->cmd == get_image_cmd.cmd) /* raw data has 2-byte "pixels" and the frame is vertical */ response_len = - elandev->raw_frame_height * elandev->frame_width * 2; + self->raw_frame_height * self->frame_width * 2; - g_clear_pointer(&elandev->last_read, g_free); - buffer = g_malloc(response_len); + g_clear_pointer(&self->last_read, g_free); - elandev->cur_transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev), - ssm, - elandev->cmd->response_in, - buffer, - response_len, - elan_cmd_cb, - NULL, - elandev->cmd_timeout); - int r = fpi_usb_submit_transfer(elandev->cur_transfer); - if (r < 0) - fpi_ssm_mark_failed(ssm, r); + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + + fpi_usb_transfer_fill_bulk (transfer, + self->cmd->response_in, + response_len); + + if (!self->cmd->never_cancel) + cancellable = fpi_device_get_cancellable (dev); + + fpi_usb_transfer_submit (transfer, self->cmd_timeout, cancellable, elan_cmd_cb, NULL); + fpi_usb_transfer_unref (transfer); } static void -elan_run_cmd(fpi_ssm *ssm, - struct fp_img_dev *dev, +elan_run_cmd(FpiSsm *ssm, + FpDevice *dev, const struct elan_cmd *cmd, int cmd_timeout) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); + FpiUsbTransfer *transfer; + GCancellable *cancellable = NULL; - dbg_buf(cmd->cmd, 2); - - elandev->cmd = cmd; + self->cmd = cmd; if (cmd_timeout != -1) - elandev->cmd_timeout = cmd_timeout; + self->cmd_timeout = cmd_timeout; - if (cmd->devices != ELAN_ALL_DEV && !(cmd->devices & elandev->dev_type)) { + if (cmd->devices != ELAN_ALL_DEV && !(cmd->devices & self->dev_type)) { fp_dbg("skipping command 0x%x 0x%x for this device (for devices 0x%x but device is 0x%x)", - cmd->cmd[0], cmd->cmd[1], cmd->devices, elandev->dev_type); + cmd->cmd[0], cmd->cmd[1], cmd->devices, self->dev_type); elan_cmd_done(ssm); return; } - elandev->cur_transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev), - ssm, - ELAN_EP_CMD_OUT, - g_memdup((char *) cmd->cmd, ELAN_CMD_LEN), - ELAN_CMD_LEN, - elan_cmd_cb, - NULL, - elandev->cmd_timeout); - int r = fpi_usb_submit_transfer(elandev->cur_transfer); - if (r < 0) - fpi_ssm_mark_failed(ssm, r); + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + + fpi_usb_transfer_fill_bulk_full (transfer, + ELAN_EP_CMD_OUT, + (guint8*) cmd->cmd, + ELAN_CMD_LEN, + NULL); + + if (!self->cmd->never_cancel) + cancellable = fpi_device_get_cancellable (dev); + + fpi_usb_transfer_submit (transfer, + self->cmd_timeout, + cancellable, + elan_cmd_cb, + NULL); + fpi_usb_transfer_unref (transfer); } enum stop_capture_states { @@ -448,53 +431,57 @@ enum stop_capture_states { STOP_CAPTURE_NUM_STATES, }; -static void stop_capture_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) +static void stop_capture_run_state(FpiSsm *ssm, FpDevice *dev, + void *user_data) { G_DEBUG_HERE(); switch (fpi_ssm_get_cur_state(ssm)) { case STOP_CAPTURE: - elan_run_cmd(ssm, FP_IMG_DEV(dev), &stop_cmd, ELAN_CMD_TIMEOUT); + elan_run_cmd(ssm, dev, &stop_cmd, + ELAN_CMD_TIMEOUT); break; } } -static void stop_capture_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void stop_capture_complete(FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - struct fp_img_dev *dev = user_data; - struct elan_dev *elandev = FP_INSTANCE_DATA(_dev); - int error = fpi_ssm_get_error(ssm); + FpImageDevice *dev = user_data; + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); fpi_ssm_free(ssm); + /* The device is inactive at this point. */ + self->dev_state = FP_IMAGE_DEVICE_STATE_INACTIVE; + + if (self->deactivating) { + /* Simply complete the pending deactivation. */ + self->deactivating = FALSE; + fpi_image_device_deactivate_complete (dev, error); + return; + } + if (!error) { - fpi_imgdev_report_finger_status(dev, FALSE); - - /* If verify or identify fails because of short swipe, we need to restart - * capture manually. It feels like libfprint or the application should know - * better if they want to retry, but they don't. Unless we've been asked to - * deactivate, try to re-enter the capture loop. Since state change is - * async, there's still a chance to be deactivated by another pending - * event. */ - if (elandev->dev_state_next != IMGDEV_STATE_INACTIVE) - dev_change_state(dev, IMGDEV_STATE_AWAIT_FINGER_ON); - - } else if (error != -ECANCELED) - fpi_imgdev_abort_scan(dev, error); + fpi_image_device_report_finger_status(dev, FALSE); + } else { + /* NOTE: We cannot get a cancellation error here. */ + fpi_image_device_session_error (dev, error); + } } -static void elan_stop_capture(struct fp_img_dev *dev) +static void elan_stop_capture(FpDevice *dev) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); - elan_dev_reset(elandev); + elan_dev_reset_state(self); - fpi_ssm *ssm = - fpi_ssm_new(FP_DEV(dev), stop_capture_run_state, + FpiSsm *ssm = + fpi_ssm_new(dev, stop_capture_run_state, STOP_CAPTURE_NUM_STATES, dev); fpi_ssm_start(ssm, stop_capture_complete); } @@ -507,10 +494,10 @@ enum capture_states { CAPTURE_NUM_STATES, }; -static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capture_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct elan_dev *elandev = FP_INSTANCE_DATA(_dev); + FpImageDevice *idev = FP_IMAGE_DEVICE(dev); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); int r; switch (fpi_ssm_get_cur_state(ssm)) { @@ -521,22 +508,24 @@ static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data elan_run_cmd(ssm, dev, &pre_scan_cmd, -1); break; case CAPTURE_READ_DATA: + self->dev_state = FP_IMAGE_DEVICE_STATE_CAPTURE; + /* 0x55 - finger present * 0xff - device not calibrated (probably) */ - if (elandev->last_read && elandev->last_read[0] == 0x55) { - if (elandev->dev_state == IMGDEV_STATE_AWAIT_FINGER_ON) - fpi_imgdev_report_finger_status(dev, TRUE); + if (self->last_read && self->last_read[0] == 0x55) { + fpi_image_device_report_finger_status(idev, TRUE); elan_run_cmd(ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT); - } else - fpi_ssm_mark_failed(ssm, -EBADMSG); + } else { + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + } break; case CAPTURE_CHECK_ENOUGH_FRAMES: - r = elan_save_img_frame(elandev); + r = elan_save_img_frame(self); if (r < 0) - fpi_ssm_mark_failed(ssm, r); - else if (elandev->num_frames < ELAN_MAX_FRAMES) { + fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + else if (self->num_frames < ELAN_MAX_FRAMES) { /* quickly stop if finger is removed */ - elandev->cmd_timeout = ELAN_FINGER_TIMEOUT; + self->cmd_timeout = ELAN_FINGER_TIMEOUT; fpi_ssm_jump_to_state(ssm, CAPTURE_WAIT_FINGER); } else { fpi_ssm_next_state(ssm); @@ -545,54 +534,51 @@ static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data } } -static void capture_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capture_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - struct fp_img_dev *dev = user_data; - struct elan_dev *elandev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpiDeviceElan *self = FPI_DEVICE_ELAN(_dev); G_DEBUG_HERE(); - if (fpi_ssm_get_error(ssm) == -ECANCELED) { - fpi_ssm_free(ssm); - return; - } + /* XXX: cancellation was specially handled by doing nothing! */ /* either max frames captured or timed out waiting for the next frame */ - if (!fpi_ssm_get_error(ssm) - || (fpi_ssm_get_error(ssm) == -ETIMEDOUT - && fpi_ssm_get_cur_state(ssm) == CAPTURE_WAIT_FINGER)) - if (elandev->num_frames >= ELAN_MIN_FRAMES) + if (!error || + (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) && + fpi_ssm_get_cur_state(ssm) == CAPTURE_WAIT_FINGER)) { + if (self->num_frames >= ELAN_MIN_FRAMES) elan_submit_image(dev); else { fp_dbg("swipe too short: want >= %d frames, got %d", - ELAN_MIN_FRAMES, elandev->num_frames); - fpi_imgdev_abort_scan(dev, FP_VERIFY_RETRY_TOO_SHORT); + ELAN_MIN_FRAMES, self->num_frames); + fpi_image_device_retry_scan(dev, FP_DEVICE_RETRY_TOO_SHORT); } - - /* other error - * It says "...abort_scan" but reporting 1 during verification makes it - * successful! */ - else - fpi_imgdev_abort_scan(dev, fpi_ssm_get_error(ssm)); + g_clear_error (&error); + } else { + fpi_image_device_session_error (dev, error); + } fpi_ssm_free(ssm); } -static void elan_capture(struct fp_img_dev *dev) +static void elan_capture(FpDevice *dev) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); - elan_dev_reset(elandev); - fpi_ssm *ssm = - fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev); + elan_dev_reset_state(self); + FpiSsm *ssm = + fpi_ssm_new(dev, capture_run_state, CAPTURE_NUM_STATES, + dev); fpi_ssm_start(ssm, capture_complete); } /* this function needs to have elandev->background and elandev->last_read to be * the calibration mean */ -static int elan_need_calibration(struct elan_dev *elandev) +static int elan_need_calibration(FpiDeviceElan *elandev) { G_DEBUG_HERE(); @@ -635,7 +621,7 @@ enum calibrate_states { CALIBRATE_NUM_STATES, }; -static gboolean elan_supports_calibration(struct elan_dev *elandev) +static gboolean elan_supports_calibration(FpiDeviceElan *elandev) { if (elandev->dev_type == ELAN_0C42) return TRUE; @@ -643,10 +629,9 @@ static gboolean elan_supports_calibration(struct elan_dev *elandev) return elandev->fw_ver >= ELAN_MIN_CALIBRATION_FW; } -static void calibrate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void calibrate_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct elan_dev *elandev = FP_INSTANCE_DATA(_dev); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); @@ -655,8 +640,8 @@ static void calibrate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_da elan_run_cmd(ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT); break; case CALIBRATE_SAVE_BACKGROUND: - elan_save_background(elandev); - if (!elan_supports_calibration(elandev)) { + elan_save_background(self); + if (!elan_supports_calibration(self)) { fp_dbg("FW does not support calibration"); fpi_ssm_mark_completed(ssm); } else @@ -666,20 +651,22 @@ static void calibrate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_da elan_run_cmd(ssm, dev, &get_calib_mean_cmd, ELAN_CMD_TIMEOUT); break; case CALIBRATE_CHECK_NEEDED: - if (elan_need_calibration(elandev)) { - elandev->calib_status = 0; + if (elan_need_calibration(self)) { + self->calib_status = 0; fpi_ssm_next_state(ssm); } else fpi_ssm_mark_completed(ssm); break; case CALIBRATE_GET_STATUS: - elandev->calib_atts_left -= 1; - if (elandev->calib_atts_left) + self->calib_atts_left -= 1; + if (self->calib_atts_left) elan_run_cmd(ssm, dev, &get_calib_status_cmd, ELAN_CMD_TIMEOUT); else { fp_dbg("calibration failed"); - fpi_ssm_mark_failed(ssm, -1); + fpi_ssm_mark_failed(ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Callibration failed!")); } break; case CALIBRATE_CHECK_STATUS: @@ -689,19 +676,21 @@ static void calibrate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_da * changes to 0x01. It stays that way for some time and then changes back * to 0x03. Because of this we don't just expect 0x03, we want to see 0x01 * first. This is to make sure that a full calibration loop has completed */ - fp_dbg("calibration status: 0x%02x", elandev->last_read[0]); - if (elandev->calib_status == 0x01 - && elandev->last_read[0] == 0x03) { - elandev->calib_status = 0x03; + fp_dbg("calibration status: 0x%02x", self->last_read[0]); + if (self->calib_status == 0x01 + && self->last_read[0] == 0x03) { + self->calib_status = 0x03; fpi_ssm_jump_to_state(ssm, CALIBRATE_GET_BACKGROUND); } else { - fpi_timeout *timeout; + GSource *timeout; - if (elandev->calib_status == 0x00 - && elandev->last_read[0] == 0x01) - elandev->calib_status = 0x01; - timeout = fpi_timeout_add(50, fpi_ssm_next_state_timeout_cb, _dev, ssm); - fpi_timeout_set_name(timeout, "calibrate_run_state"); + if (self->calib_status == 0x00 + && self->last_read[0] == 0x01) + self->calib_status = 0x01; + timeout = fpi_device_add_timeout(dev, 50, + fpi_ssm_next_state_timeout_cb, + ssm); + g_source_set_name(timeout, "calibrate_run_state"); } break; case CALIBRATE_REPEAT_STATUS: @@ -710,29 +699,34 @@ static void calibrate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_da } } -static void calibrate_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void calibrate_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - struct fp_img_dev *dev = user_data; + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); - - if (fpi_ssm_get_error(ssm) != -ECANCELED) + if (error) { + self->dev_state = FP_IMAGE_DEVICE_STATE_INACTIVE; + fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error); + } else { + self->dev_state = FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON; elan_capture(dev); + } fpi_ssm_free(ssm); } -static void elan_calibrate(struct fp_img_dev *dev) +static void elan_calibrate(FpDevice *dev) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); - elan_dev_reset(elandev); - elandev->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS; + elan_dev_reset_state(self); + self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS; - fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), calibrate_run_state, + FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(dev), calibrate_run_state, CALIBRATE_NUM_STATES, dev); fpi_ssm_start(ssm, calibrate_complete); } @@ -746,10 +740,9 @@ enum activate_states { ACTIVATE_NUM_STATES, }; -static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct elan_dev *elandev = FP_INSTANCE_DATA(_dev); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); @@ -758,9 +751,9 @@ static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_dat elan_run_cmd(ssm, dev, &get_fw_ver_cmd, ELAN_CMD_TIMEOUT); break; case ACTIVATE_SET_FW_VER: - elandev->fw_ver = - (elandev->last_read[0] << 8 | elandev->last_read[1]); - fp_dbg("FW ver 0x%04hx", elandev->fw_ver); + self->fw_ver = + (self->last_read[0] << 8 | self->last_read[1]); + fp_dbg("FW ver 0x%04hx", self->fw_ver); fpi_ssm_next_state(ssm); break; case ACTIVATE_GET_SENSOR_DIM: @@ -768,27 +761,27 @@ static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_dat break; case ACTIVATE_SET_SENSOR_DIM: /* see elan_save_frame for details */ - if (elandev->dev_type & ELAN_NOT_ROTATED) { - elandev->frame_width = elandev->last_read[0]; - elandev->frame_height = elandev->raw_frame_height = - elandev->last_read[2]; + if (self->dev_type & ELAN_NOT_ROTATED) { + self->frame_width = self->last_read[0]; + self->frame_height = self->raw_frame_height = + self->last_read[2]; } else { - elandev->frame_width = elandev->last_read[2]; - elandev->frame_height = elandev->raw_frame_height = - elandev->last_read[0]; + self->frame_width = self->last_read[2]; + self->frame_height = self->raw_frame_height = + self->last_read[0]; } /* Work-around sensors returning the sizes as zero-based index * rather than the number of pixels. */ - if ((elandev->frame_width % 2 == 1) && - (elandev->frame_height % 2 == 1)) { - elandev->frame_width++; - elandev->frame_height++; - elandev->raw_frame_height = elandev->frame_height; + if ((self->frame_width % 2 == 1) && + (self->frame_height % 2 == 1)) { + self->frame_width++; + self->frame_height++; + self->raw_frame_height = self->frame_height; } - if (elandev->frame_height > ELAN_MAX_FRAME_HEIGHT) - elandev->frame_height = ELAN_MAX_FRAME_HEIGHT; - fp_dbg("sensor dimensions, WxH: %dx%d", elandev->frame_width, - elandev->raw_frame_height); + if (self->frame_height > ELAN_MAX_FRAME_HEIGHT) + self->frame_height = ELAN_MAX_FRAME_HEIGHT; + fp_dbg("sensor dimensions, WxH: %dx%d", self->frame_width, + self->raw_frame_height); fpi_ssm_next_state(ssm); break; case ACTIVATE_CMD_1: @@ -798,191 +791,195 @@ static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_dat } } -static void activate_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - struct fp_img_dev *dev = user_data; + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); G_DEBUG_HERE(); - if (fpi_ssm_get_error(ssm) != -ECANCELED) { - fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm)); - } + fpi_image_device_activate_complete (idev, error); fpi_ssm_free(ssm); } -static void elan_activate(struct fp_img_dev *dev) +static void elan_activate(FpImageDevice *dev) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); - elan_dev_reset(elandev); + elan_dev_reset_state(self); - fpi_ssm *ssm = - fpi_ssm_new(FP_DEV(dev), activate_run_state, ACTIVATE_NUM_STATES, dev); + FpiSsm *ssm = + fpi_ssm_new(FP_DEVICE(dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); fpi_ssm_start(ssm, activate_complete); } -static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) +static void dev_init(FpImageDevice *dev) { - struct elan_dev *elandev; - int r; + GError *error = NULL; + FpiDeviceElan *self; G_DEBUG_HERE(); - r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - if (r < 0) { - fp_err("could not claim interface 0: %s", libusb_error_name(r)); - return r; + if (!g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error)) { + fpi_image_device_open_complete(dev, error); + return; } - elandev = g_malloc0(sizeof(struct elan_dev)); - fp_dev_set_instance_data(FP_DEV(dev), elandev); + self = FPI_DEVICE_ELAN(dev); /* common params */ - elandev->dev_type = driver_data; - elandev->background = NULL; - elandev->process_frame = elan_process_frame_thirds; + self->dev_type = fpi_device_get_driver_data (FP_DEVICE (dev)); + self->background = NULL; + self->process_frame = elan_process_frame_thirds; - switch (driver_data) { + switch (self->dev_type) { case ELAN_0907: - elandev->process_frame = elan_process_frame_linear; + self->process_frame = elan_process_frame_linear; break; } - fpi_imgdev_open_complete(dev, 0); - return 0; + fpi_image_device_open_complete(dev, NULL); } -static void elan_deactivate(struct fp_img_dev *dev) +static void dev_deinit(FpImageDevice *dev) { - G_DEBUG_HERE(); - - fpi_imgdev_deactivate_complete(dev); -} - -static void dev_deinit(struct fp_img_dev *dev) -{ - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); + GError *error = NULL; + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); - elan_dev_reset(elandev); - g_free(elandev->background); - g_free(elandev); - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - fpi_imgdev_close_complete(dev); + elan_dev_reset_state(self); + g_free(self->background); + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), + 0, 0, &error); + fpi_image_device_close_complete(dev, error); } -static int dev_activate(struct fp_img_dev *dev) +static void dev_activate(FpImageDevice *dev) { G_DEBUG_HERE(); elan_activate(dev); - return 0; } -static void elan_change_state(struct fp_img_dev *dev) +static void elan_change_state(FpImageDevice *idev) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); - enum fp_imgdev_state next_state = elandev->dev_state_next; + FpDevice *dev = FP_DEVICE(idev); + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); + FpImageDeviceState next_state = self->dev_state_next; - if (elandev->dev_state == next_state) { + if (self->dev_state == next_state) { fp_dbg("already in %d", next_state); return; - } else + } else { fp_dbg("changing to %d", next_state); + } switch (next_state) { - case IMGDEV_STATE_INACTIVE: - if (elandev->cur_transfer) - /* deactivation will complete in transfer callback */ - fpi_usb_cancel_transfer(elandev->cur_transfer); - else - elan_deactivate(dev); break; - case IMGDEV_STATE_AWAIT_FINGER_ON: + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: /* activation completed or another enroll stage started */ elan_calibrate(dev); break; - case IMGDEV_STATE_CAPTURE: + case FP_IMAGE_DEVICE_STATE_CAPTURE: /* not used */ break; - case IMGDEV_STATE_AWAIT_FINGER_OFF: - elan_stop_capture(dev); + case FP_IMAGE_DEVICE_STATE_INACTIVE: + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: + if (self->dev_state != FP_IMAGE_DEVICE_STATE_INACTIVE || + self->dev_state != FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF) + elan_stop_capture(dev); } - - elandev->dev_state = next_state; } static void -elan_change_state_async(struct fp_dev *dev, +elan_change_state_async(FpDevice *dev, void *data) { g_message ("state change dev: %p", dev); - elan_change_state(FP_IMG_DEV (dev)); + elan_change_state(FP_IMAGE_DEVICE(dev)); } -static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state) +static void dev_change_state(FpImageDevice *dev, FpImageDeviceState state) { - struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_timeout *timeout; + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); + GSource *timeout; G_DEBUG_HERE(); + /* Inactive and await finger off are equivalent for the elan driver. */ + if (state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF) + state = FP_IMAGE_DEVICE_STATE_INACTIVE; + + if (self->dev_state_next == state) { + fp_dbg ("change to state %d already queued", state); + } + switch (state) { - case IMGDEV_STATE_INACTIVE: - case IMGDEV_STATE_AWAIT_FINGER_ON: - case IMGDEV_STATE_AWAIT_FINGER_OFF: { + case FP_IMAGE_DEVICE_STATE_INACTIVE: + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: { char *name; /* schedule state change instead of calling it directly to allow all actions * related to the previous state to complete */ - elandev->dev_state_next = state; - timeout = fpi_timeout_add(10, elan_change_state_async, FP_DEV(dev), NULL); + self->dev_state_next = state; + timeout = fpi_device_add_timeout(FP_DEVICE(dev), 10, + elan_change_state_async, + NULL); name = g_strdup_printf ("dev_change_state to %d", state); - fpi_timeout_set_name(timeout, name); + g_source_set_name(timeout, name); g_free (name); break; } - case IMGDEV_STATE_CAPTURE: + case FP_IMAGE_DEVICE_STATE_CAPTURE: /* TODO MAYBE: split capture ssm into smaller ssms and use this state */ - elandev->dev_state = state; - elandev->dev_state_next = state; + self->dev_state = state; + self->dev_state_next = state; break; default: - fp_err("unrecognized state %d", state); - fpi_imgdev_session_error(dev, -EINVAL); - return -EINVAL; + g_assert_not_reached(); } - - /* as of time of writing libfprint never checks the return value */ - return 0; } -static void dev_deactivate(struct fp_img_dev *dev) +static void dev_deactivate(FpImageDevice *dev) { + FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); G_DEBUG_HERE(); - dev_change_state(dev, IMGDEV_STATE_INACTIVE); + if (self->dev_state == FP_IMAGE_DEVICE_STATE_INACTIVE) { + /* The device is inactive already, complete the operation immediately. */ + fpi_image_device_deactivate_complete (dev, NULL); + } else { + /* The device is not yet inactive, flag that we are deactivating (and + * need to signal back deactivation) and then ensure we will change + * to the inactive state eventually. */ + self->deactivating = TRUE; + dev_change_state (dev, FP_IMAGE_DEVICE_STATE_INACTIVE); + } } -struct fp_img_driver elan_driver = { - .driver = { - .id = ELAN_ID, - .name = FP_COMPONENT, - .full_name = "ElanTech Fingerprint Sensor", - .id_table = elan_id_table, - .scan_type = FP_SCAN_TYPE_SWIPE, - }, - .flags = 0, +static void fpi_device_elan_init(FpiDeviceElan *self) { +} +static void fpi_device_elan_class_init(FpiDeviceElanClass *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); - .bz3_threshold = 24, + dev_class->id = "elan"; + dev_class->full_name = "ElanTech Fingerprint Sensor"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = elan_id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - .open = dev_init, - .close = dev_deinit, - .activate = dev_activate, - .deactivate = dev_deactivate, - .change_state = dev_change_state, -}; + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; + img_class->change_state = dev_change_state; + + img_class->bz3_threshold = 24; +} diff --git a/libfprint/drivers/elan.h b/libfprint/drivers/elan.h index c5f0f191..059f00ac 100644 --- a/libfprint/drivers/elan.h +++ b/libfprint/drivers/elan.h @@ -21,7 +21,7 @@ #ifndef __ELAN_H #define __ELAN_H -#include +#include #define ELAN_VEND_ID 0x04f3 @@ -59,9 +59,9 @@ #define ELAN_SKIP_LAST_FRAMES 2 #define ELAN_CMD_LEN 0x2 -#define ELAN_EP_CMD_OUT (0x1 | LIBUSB_ENDPOINT_OUT) -#define ELAN_EP_CMD_IN (0x3 | LIBUSB_ENDPOINT_IN) -#define ELAN_EP_IMG_IN (0x2 | LIBUSB_ENDPOINT_IN) +#define ELAN_EP_CMD_OUT (0x1 | FPI_USB_ENDPOINT_OUT) +#define ELAN_EP_CMD_IN (0x3 | FPI_USB_ENDPOINT_IN) +#define ELAN_EP_IMG_IN (0x2 | FPI_USB_ENDPOINT_IN) /* used as response length to tell the driver to skip reading response */ #define ELAN_CMD_SKIP_READ 0 @@ -76,6 +76,7 @@ struct elan_cmd { int response_len; int response_in; unsigned short devices; + gboolean never_cancel; }; static const struct elan_cmd get_sensor_dim_cmd = { @@ -152,73 +153,73 @@ static const struct elan_cmd stop_cmd = { .response_len = ELAN_CMD_SKIP_READ, .response_in = ELAN_EP_CMD_IN, .devices = ELAN_ALL_DEV, + .never_cancel = TRUE, }; -static const struct usb_id elan_id_table[] = { - {.vendor = ELAN_VEND_ID,.product = 0x0903,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0907,.driver_data = ELAN_0907}, - {.vendor = ELAN_VEND_ID,.product = 0x0c01,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c02,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c03,.driver_data = ELAN_0C03}, - {.vendor = ELAN_VEND_ID,.product = 0x0c04,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c05,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c06,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c07,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c08,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c09,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c0a,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c0b,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c0c,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c0d,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c0e,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c0f,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c10,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c11,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c12,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c13,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c14,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c15,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c16,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c17,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c18,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c19,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c1a,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c1b,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c1c,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c1d,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c1e,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c1f,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c20,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c21,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c22,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c23,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c24,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c25,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c26,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c27,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c28,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c29,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c2a,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c2b,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c2c,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c2d,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c2e,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c2f,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c30,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c31,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c32,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c33,.driver_data = ELAN_ALL_DEV}, - {.vendor = ELAN_VEND_ID,.product = 0x0c42,.driver_data = ELAN_0C42}, - {0, 0, 0,}, +static const FpIdEntry elan_id_table [ ] = { + {.vid = ELAN_VEND_ID, .pid = 0x0903, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0907, .driver_data = ELAN_0907}, + {.vid = ELAN_VEND_ID, .pid = 0x0c01, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c02, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c03, .driver_data = ELAN_0C03}, + {.vid = ELAN_VEND_ID, .pid = 0x0c04, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c05, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c06, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c07, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c08, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c09, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0a, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0b, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0c, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0d, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0e, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0f, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c10, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c11, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c12, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c13, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c14, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c15, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c16, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c17, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c18, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c19, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1a, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1b, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1c, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1d, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1e, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1f, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c20, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c21, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c22, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c23, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c24, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c25, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c26, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c27, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c28, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c29, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2a, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2b, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2c, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2d, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2e, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2f, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c30, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c31, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c32, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c33, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42}, + {.vid = 0, .pid = 0, .driver_data = 0}, }; -static void elan_cmd_done(fpi_ssm *ssm); -static void elan_cmd_read(fpi_ssm *ssm, struct fp_img_dev *dev); +static void elan_cmd_done(FpiSsm *ssm); +static void elan_cmd_read(FpiSsm *ssm, FpDevice *dev); -static void elan_calibrate(struct fp_img_dev *dev); -static void elan_capture(struct fp_img_dev *dev); -static void elan_deactivate(struct fp_img_dev *dev); +static void elan_calibrate(FpDevice *dev); +static void elan_capture(FpDevice *dev); -static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state); +static void dev_change_state(FpImageDevice *dev, FpImageDeviceState state); #endif diff --git a/meson.build b/meson.build index 5552e200..899d8068 100644 --- a/meson.build +++ b/meson.build @@ -51,7 +51,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603', 'vcom5s', 'synaptics'] +default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603', 'vcom5s', 'synaptics', 'elan'] all_drivers = default_drivers + virtual_drivers From aec1b7caad7122f3c949d2751b5bff81ea872ded Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 6 Aug 2019 13:13:15 +0200 Subject: [PATCH 45/73] build: Add -Wtype-limits to default cflags --- meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/meson.build b/meson.build index 899d8068..2e7b1e2a 100644 --- a/meson.build +++ b/meson.build @@ -23,6 +23,7 @@ common_cflags = cc.get_supported_arguments([ '-fgnu89-inline', '-std=gnu99', '-Wall', + '-Wtype-limits', '-Wundef', '-Wunused', '-Wstrict-prototypes', From a8d15bccba3cb152f9f82fb0e398e25efcb46226 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 6 Aug 2019 16:49:15 +0200 Subject: [PATCH 46/73] uru4000: Port URU4000 driver to new API --- libfprint/drivers/uru4000.c | 1019 ++++++++++++++++------------------- meson.build | 2 +- 2 files changed, 467 insertions(+), 554 deletions(-) diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c index 79c48c5b..8962b92f 100644 --- a/libfprint/drivers/uru4000.c +++ b/libfprint/drivers/uru4000.c @@ -25,11 +25,11 @@ #include "drivers_api.h" -#define EP_INTR (1 | LIBUSB_ENDPOINT_IN) -#define EP_DATA (2 | LIBUSB_ENDPOINT_IN) +#define EP_INTR (1 | FPI_USB_ENDPOINT_IN) +#define EP_DATA (2 | FPI_USB_ENDPOINT_IN) #define USB_RQ 0x04 -#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN) -#define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT) +#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | FPI_USB_ENDPOINT_IN) +#define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | FPI_USB_ENDPOINT_OUT) #define CTRL_TIMEOUT 5000 #define BULK_TIMEOUT 5000 #define IRQ_LENGTH 64 @@ -109,19 +109,23 @@ static const struct uru4k_dev_profile { }, }; -typedef void (*irq_cb_fn)(struct fp_img_dev *dev, int status, uint16_t type, - void *user_data); -typedef void (*irqs_stopped_cb_fn)(struct fp_img_dev *dev); +typedef void (*irq_cb_fn)(FpImageDevice *dev, + GError *error, + uint16_t type, + void *user_data); +typedef void (*irqs_stopped_cb_fn)(FpImageDevice *dev); + +struct _FpiDeviceUru4000 { + FpImageDevice parent; -struct uru4k_dev { const struct uru4k_dev_profile *profile; uint8_t interface; - enum fp_imgdev_state activate_state; + FpImageDeviceState activate_state; unsigned char last_reg_rd[16]; unsigned char last_hwstat; - fpi_usb_transfer *irq_transfer; - fpi_usb_transfer *img_transfer; + GCancellable *irq_cancellable; + FpiUsbTransfer *img_transfer; void *img_data; int img_data_actual_length; uint16_t img_lines_done, img_block; @@ -136,7 +140,7 @@ struct uru4k_dev { unsigned char powerup_hwstat; int scanpwr_irq_timeouts; - fpi_timeout *scanpwr_irq_timeout; + GSource *scanpwr_irq_timeout; int fwfixer_offset; unsigned char fwfixer_value; @@ -146,6 +150,9 @@ struct uru4k_dev { PK11SymKey *symkey; SECItem *param; }; +G_DECLARE_FINAL_TYPE(FpiDeviceUru4000, fpi_device_uru4000, FPI, DEVICE_URU4000, + FpImageDevice); +G_DEFINE_TYPE(FpiDeviceUru4000, fpi_device_uru4000, FP_TYPE_IMAGE_DEVICE); /* For 2nd generation MS devices */ static const unsigned char crkey[] = { @@ -155,123 +162,47 @@ static const unsigned char crkey[] = { /***** REGISTER I/O *****/ -typedef void (*write_regs_cb_fn)(struct fp_img_dev *dev, int status, - void *user_data); - -struct write_regs_data { - struct fp_img_dev *dev; - write_regs_cb_fn callback; - void *user_data; -}; - -static void write_regs_cb(struct libusb_transfer *transfer) +static void write_regs(FpImageDevice *dev, uint16_t first_reg, + uint16_t num_regs, unsigned char *values, + FpiUsbTransferCallback callback, + void *user_data) { - struct write_regs_data *wrdata = transfer->user_data; - struct libusb_control_setup *setup = - libusb_control_transfer_get_setup(transfer); - int r = 0; - - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - r = -EIO; - else if (transfer->actual_length != setup->wLength) - r = -EPROTO; + FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); - g_free(transfer->buffer); - libusb_free_transfer(transfer); - wrdata->callback(wrdata->dev, r, wrdata->user_data); - g_free(wrdata); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_control(transfer, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_STANDARD, + G_USB_DEVICE_RECIPIENT_DEVICE, + USB_RQ, first_reg, 0, + num_regs); + memcpy(transfer->buffer, values, num_regs); + fpi_usb_transfer_submit(transfer, CTRL_TIMEOUT, NULL, callback, user_data); + fpi_usb_transfer_unref(transfer); } -static int write_regs(struct fp_img_dev *dev, uint16_t first_reg, - uint16_t num_regs, unsigned char *values, write_regs_cb_fn callback, - void *user_data) +static void write_reg(FpImageDevice *dev, uint16_t reg, + unsigned char value, + FpiUsbTransferCallback callback, + void *user_data) { - struct write_regs_data *wrdata; - struct libusb_transfer *transfer = fpi_usb_alloc(); - unsigned char *data; - int r; - - wrdata = g_malloc(sizeof(*wrdata)); - wrdata->dev = dev; - wrdata->callback = callback; - wrdata->user_data = user_data; - - data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + num_regs); - memcpy(data + LIBUSB_CONTROL_SETUP_SIZE, values, num_regs); - libusb_fill_control_setup(data, CTRL_OUT, USB_RQ, first_reg, 0, num_regs); - libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, write_regs_cb, - wrdata, CTRL_TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(wrdata); - g_free(data); - libusb_free_transfer(transfer); - } - return r; + write_regs(dev, reg, 1, &value, callback, user_data); } -static int write_reg(struct fp_img_dev *dev, uint16_t reg, - unsigned char value, write_regs_cb_fn callback, void *user_data) +static void read_regs(FpImageDevice *dev, uint16_t first_reg, + uint16_t num_regs, + FpiUsbTransferCallback callback, + void *user_data) { - return write_regs(dev, reg, 1, &value, callback, user_data); -} + FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); -typedef void (*read_regs_cb_fn)(struct fp_img_dev *dev, int status, - uint16_t num_regs, unsigned char *data, void *user_data); - -struct read_regs_data { - struct fp_img_dev *dev; - read_regs_cb_fn callback; - void *user_data; -}; - -static void read_regs_cb(struct libusb_transfer *transfer) -{ - struct read_regs_data *rrdata = transfer->user_data; - struct libusb_control_setup *setup = - libusb_control_transfer_get_setup(transfer); - unsigned char *data = NULL; - int r = 0; - - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - r = -EIO; - else if (transfer->actual_length != setup->wLength) - r = -EPROTO; - else - data = libusb_control_transfer_get_data(transfer); - - rrdata->callback(rrdata->dev, r, transfer->actual_length, data, rrdata->user_data); - g_free(rrdata); - g_free(transfer->buffer); - libusb_free_transfer(transfer); -} - -static int read_regs(struct fp_img_dev *dev, uint16_t first_reg, - uint16_t num_regs, read_regs_cb_fn callback, void *user_data) -{ - struct read_regs_data *rrdata; - struct libusb_transfer *transfer = fpi_usb_alloc(); - unsigned char *data; - int r; - - rrdata = g_malloc(sizeof(*rrdata)); - rrdata->dev = dev; - rrdata->callback = callback; - rrdata->user_data = user_data; - - data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + num_regs); - libusb_fill_control_setup(data, CTRL_IN, USB_RQ, first_reg, 0, num_regs); - libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, read_regs_cb, - rrdata, CTRL_TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(rrdata); - g_free(data); - libusb_free_transfer(transfer); - } - return r; + fpi_usb_transfer_fill_control(transfer, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_STANDARD, + G_USB_DEVICE_RECIPIENT_DEVICE, + USB_RQ, first_reg, 0, num_regs); + fpi_usb_transfer_submit(transfer, CTRL_TIMEOUT, NULL, callback, user_data); + fpi_usb_transfer_unref(transfer); } /* @@ -299,49 +230,45 @@ static int read_regs(struct fp_img_dev *dev, uint16_t first_reg, * an interrupt to the host. Maybe? */ -static void response_cb(struct fp_img_dev *dev, int status, void *user_data) +static void response_cb(FpiUsbTransfer *transfer, FpDevice *dev, void *user_data, GError *error) { - fpi_ssm *ssm = user_data; - if (status == 0) + /* NOTE: We could use the SSM function instead if we attached the ssm to the transfer! */ + FpiSsm *ssm = user_data; + + if (!error) fpi_ssm_next_state(ssm); else - fpi_ssm_mark_failed(ssm, status); + fpi_ssm_mark_failed(ssm, error); } -static void challenge_cb(struct fp_img_dev *dev, int status, - uint16_t num_regs, unsigned char *data, void *user_data) +static void challenge_cb(FpiUsbTransfer *transfer, FpDevice *dev, void *user_data, GError *error) { - fpi_ssm *ssm = user_data; - struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); - unsigned char *respdata; + FpiSsm *ssm = user_data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); + unsigned char respdata[CR_LENGTH]; PK11Context *ctx; - int r, outlen; + int outlen; - r = status; - if (status != 0) { - fpi_ssm_mark_failed(ssm, status); + if (error) { + fpi_ssm_mark_failed(ssm, error); return; } /* submit response */ /* produce response from challenge */ - respdata = g_malloc(CR_LENGTH); - ctx = PK11_CreateContextBySymKey(urudev->cipher, CKA_ENCRYPT, - urudev->symkey, urudev->param); - if (PK11_CipherOp(ctx, respdata, &outlen, CR_LENGTH, data, CR_LENGTH) != SECSuccess + ctx = PK11_CreateContextBySymKey(self->cipher, CKA_ENCRYPT, + self->symkey, self->param); + if (PK11_CipherOp(ctx, respdata, &outlen, CR_LENGTH, transfer->buffer, CR_LENGTH) != SECSuccess || PK11_Finalize(ctx) != SECSuccess) { fp_err("Failed to encrypt challenge data"); - r = -ECONNABORTED; - g_free(respdata); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "Failed to encrypt challenge data"); } PK11_DestroyContext(ctx, PR_TRUE); - if (r >= 0) { - r = write_regs(dev, REG_RESPONSE, CR_LENGTH, respdata, response_cb, ssm); - g_free(respdata); - } - if (r < 0) - fpi_ssm_mark_failed(ssm, r); + if (!error) + write_regs(FP_IMAGE_DEVICE (dev), REG_RESPONSE, CR_LENGTH, respdata, response_cb, ssm); + else + fpi_ssm_mark_failed(ssm, error); } /* @@ -350,47 +277,45 @@ static void challenge_cb(struct fp_img_dev *dev, int status, * driver. */ static void -sm_do_challenge_response(fpi_ssm *ssm, - struct fp_img_dev *dev) +sm_do_challenge_response(FpiSsm *ssm, + FpImageDevice *dev) { - int r; - G_DEBUG_HERE(); - r = read_regs(dev, REG_CHALLENGE, CR_LENGTH, challenge_cb, ssm); - if (r < 0) - fpi_ssm_mark_failed(ssm, r); + read_regs(dev, REG_CHALLENGE, CR_LENGTH, challenge_cb, ssm); } /***** INTERRUPT HANDLING *****/ -#define IRQ_HANDLER_IS_RUNNING(urudev) ((urudev)->irq_transfer) +#define IRQ_HANDLER_IS_RUNNING(urudev) ((urudev)->irq_cancellable) -static int start_irq_handler(struct fp_img_dev *dev); +static void start_irq_handler(FpImageDevice *dev); -static void irq_handler(struct libusb_transfer *transfer, - struct fp_dev *_dev, - fpi_ssm *ssm, - void *user_data) +static void irq_handler(FpiUsbTransfer *transfer, + FpDevice *dev, + void *user_data, + GError *error) { - struct fp_img_dev *dev = FP_IMG_DEV(_dev); - struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev); + FpImageDevice *imgdev = FP_IMAGE_DEVICE (dev); + FpiDeviceUru4000 *urudev = FPI_DEVICE_URU4000 (dev); unsigned char *data = transfer->buffer; uint16_t type; - int r = 0; - if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { + g_clear_object (&urudev->irq_cancellable); + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { fp_dbg("cancelled"); if (urudev->irqs_stopped_cb) - urudev->irqs_stopped_cb(dev); + urudev->irqs_stopped_cb(imgdev); urudev->irqs_stopped_cb = NULL; - goto out; - } else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - r = -EIO; - goto err; - } else if (transfer->actual_length != transfer->length) { - fp_err("short interrupt read? %d", transfer->actual_length); - r = -EPROTO; - goto err; + return; + } else if (error) { + if (urudev->irq_cb) { + urudev->irq_cb(imgdev, error, 0, urudev->irq_cb_data); + } else { + fp_dbg("ignoring interrupt error: %s", error->message); + g_clear_error (&error); + } + return; } type = GUINT16_FROM_BE(*((uint16_t *) data)); @@ -402,145 +327,136 @@ static void irq_handler(struct libusb_transfer *transfer, fp_warn("oh no! got the interrupt OF DEATH! expect things to go bad"); if (urudev->irq_cb) - urudev->irq_cb(dev, 0, type, urudev->irq_cb_data); + urudev->irq_cb(imgdev, NULL, type, urudev->irq_cb_data); else fp_dbg("ignoring interrupt"); - r = start_irq_handler(dev); - if (r == 0) - return; - -err: - if (urudev->irq_cb) - urudev->irq_cb(dev, r, 0, urudev->irq_cb_data); -out: - urudev->irq_transfer = NULL; + start_irq_handler(imgdev); } -static int start_irq_handler(struct fp_img_dev *dev) +static void start_irq_handler(FpImageDevice *dev) { - struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_usb_transfer *transfer; - unsigned char *data; - int r; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); + FpiUsbTransfer *transfer; - data = g_malloc(IRQ_LENGTH); - transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev), - NULL, - EP_INTR, - data, - IRQ_LENGTH, - irq_handler, - NULL, - 0); - - urudev->irq_transfer = transfer; - r = fpi_usb_submit_transfer(transfer); - if (r < 0) - urudev->irq_transfer = NULL; - return r; + g_assert (self->irq_cancellable == NULL); + self->irq_cancellable = g_cancellable_new (); + transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); + transfer->ssm = NULL; + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk (transfer, + EP_INTR, + IRQ_LENGTH); + fpi_usb_transfer_submit(transfer, 0, self->irq_cancellable, irq_handler, NULL); + fpi_usb_transfer_unref(transfer); } -static void stop_irq_handler(struct fp_img_dev *dev, irqs_stopped_cb_fn cb) +static void stop_irq_handler(FpImageDevice *dev, irqs_stopped_cb_fn cb) { - struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_usb_transfer *transfer = urudev->irq_transfer; - if (transfer) { - fpi_usb_cancel_transfer(transfer); - urudev->irqs_stopped_cb = cb; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); + + if (self->irq_cancellable) { + g_cancellable_cancel (self->irq_cancellable); + self->irqs_stopped_cb = cb; } } /***** STATE CHANGING *****/ -static int execute_state_change(struct fp_img_dev *dev); +static void execute_state_change(FpImageDevice *dev); -static void finger_presence_irq_cb(struct fp_img_dev *dev, int status, - uint16_t type, void *user_data) +static void finger_presence_irq_cb(FpImageDevice *dev, + GError *error, + uint16_t type, + void *user_data) { - if (status) - fpi_imgdev_session_error(dev, status); + if (error) + fpi_image_device_session_error(dev, error); else if (type == IRQDATA_FINGER_ON) - fpi_imgdev_report_finger_status(dev, TRUE); + fpi_image_device_report_finger_status(dev, TRUE); else if (type == IRQDATA_FINGER_OFF) - fpi_imgdev_report_finger_status(dev, FALSE); + fpi_image_device_report_finger_status(dev, FALSE); else fp_warn("ignoring unexpected interrupt %04x", type); } -static void change_state_write_reg_cb(struct fp_img_dev *dev, int status, - void *user_data) +static void change_state_write_reg_cb(FpiUsbTransfer *transfer, + FpDevice *dev, + void *user_data, + GError *error) { - if (status) - fpi_imgdev_session_error(dev, status); + if (error) + fpi_image_device_session_error(FP_IMAGE_DEVICE (dev), error); } -static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state) +static void dev_change_state(FpImageDevice *dev, FpImageDeviceState state) { - struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); switch (state) { - case IMGDEV_STATE_INACTIVE: - case IMGDEV_STATE_AWAIT_FINGER_ON: - case IMGDEV_STATE_AWAIT_FINGER_OFF: - case IMGDEV_STATE_CAPTURE: + case FP_IMAGE_DEVICE_STATE_INACTIVE: + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: + case FP_IMAGE_DEVICE_STATE_CAPTURE: break; default: - fp_err("unrecognised state %d", state); - return -EINVAL; + g_assert_not_reached (); } - urudev->activate_state = state; - if (urudev->img_transfer != NULL) - return 0; + self->activate_state = state; + if (self->img_transfer != NULL) + return; - return execute_state_change(dev); + execute_state_change(dev); } /***** GENERIC STATE MACHINE HELPER FUNCTIONS *****/ -static void sm_write_reg_cb(struct fp_img_dev *dev, int result, void *user_data) +static void sm_write_reg_cb(FpiUsbTransfer *transfer, + FpDevice *dev, + void *user_data, + GError *error) { - fpi_ssm *ssm = user_data; + FpiSsm *ssm = user_data; - if (result) - fpi_ssm_mark_failed(ssm, result); + if (error) + fpi_ssm_mark_failed(ssm, error); else fpi_ssm_next_state(ssm); } static void -sm_write_regs(fpi_ssm *ssm, - struct fp_img_dev *dev, +sm_write_regs(FpiSsm *ssm, + FpImageDevice *dev, uint16_t first_reg, uint16_t num_regs, void *data) { - int r = write_regs(dev, first_reg, num_regs, data, sm_write_reg_cb, ssm); - if (r < 0) - fpi_ssm_mark_failed(ssm, r); + write_regs(dev, first_reg, num_regs, data, sm_write_reg_cb, ssm); } static void -sm_write_reg(fpi_ssm *ssm, - struct fp_img_dev *dev, +sm_write_reg(FpiSsm *ssm, + FpImageDevice *dev, uint16_t reg, unsigned char value) { sm_write_regs(ssm, dev, reg, 1, &value); } -static void sm_read_reg_cb(struct fp_img_dev *dev, int result, - uint16_t num_regs, unsigned char *data, void *user_data) +static void sm_read_reg_cb(FpiUsbTransfer *transfer, + FpDevice *dev, + void *user_data, + GError *error) { - fpi_ssm *ssm = user_data; - struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiSsm *ssm = user_data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); - if (result) { - fpi_ssm_mark_failed(ssm, result); + if (error) { + fpi_ssm_mark_failed(ssm, error); } else { - memcpy(urudev->last_reg_rd, data, num_regs); - fp_dbg("reg value %x", urudev->last_reg_rd[0]); + memcpy(self->last_reg_rd, transfer->buffer, transfer->actual_length); + fp_dbg("reg value %x", self->last_reg_rd[0]); fpi_ssm_next_state(ssm); } } @@ -548,35 +464,28 @@ static void sm_read_reg_cb(struct fp_img_dev *dev, int result, #define member_size(type, member) sizeof(((type *)0)->member) static void -sm_read_regs(fpi_ssm *ssm, - struct fp_img_dev *dev, +sm_read_regs(FpiSsm *ssm, + FpImageDevice *dev, uint16_t reg, uint16_t num_regs) { - int r; - - if (num_regs > member_size(struct uru4k_dev, last_reg_rd)) { - fpi_ssm_mark_failed(ssm, -EIO); - return; - } + g_assert (num_regs <= member_size(FpiDeviceUru4000, last_reg_rd)); fp_dbg("read %d regs at %x", num_regs, reg); - r = read_regs(dev, reg, num_regs, sm_read_reg_cb, ssm); - if (r < 0) - fpi_ssm_mark_failed(ssm, r); + read_regs(dev, reg, num_regs, sm_read_reg_cb, ssm); } static void -sm_read_reg(fpi_ssm *ssm, - struct fp_img_dev *dev, +sm_read_reg(FpiSsm *ssm, + FpImageDevice *dev, uint16_t reg) { sm_read_regs(ssm, dev, reg, 1); } static void -sm_set_hwstat(fpi_ssm *ssm, - struct fp_img_dev *dev, +sm_set_hwstat(FpiSsm *ssm, + FpImageDevice *dev, unsigned char value) { fp_dbg("set %02x", value); @@ -607,22 +516,18 @@ struct uru4k_image { uint8_t data[IMAGE_HEIGHT][IMAGE_WIDTH]; }; -static void image_transfer_cb(struct libusb_transfer *transfer, - struct fp_dev *dev, - fpi_ssm *ssm, - void *user_data) +static void image_transfer_cb(FpiUsbTransfer *transfer, FpDevice *dev, + gpointer user_data, GError *error) { - if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { - fp_dbg("cancelled"); - fpi_ssm_mark_failed(ssm, -ECANCELED); - } else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fp_dbg("error"); - fpi_ssm_mark_failed(ssm, -EIO); - } else { - struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev); + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); + FpiSsm *ssm = transfer->ssm; - urudev->img_data = g_memdup(transfer->buffer, sizeof(struct uru4k_image)); - urudev->img_data_actual_length = transfer->actual_length; + if (error) { + fp_dbg("error"); + fpi_ssm_mark_failed(ssm, error); + } else { + self->img_data = g_memdup(transfer->buffer, sizeof(struct uru4k_image)); + self->img_data_actual_length = transfer->actual_length; fpi_ssm_next_state(ssm); } } @@ -701,12 +606,12 @@ static int calc_dev2(struct uru4k_image *img) return res / IMAGE_WIDTH; } -static void imaging_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void imaging_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev); - struct uru4k_image *img = urudev->img_data; - struct fp_img *fpimg; + FpImageDevice *dev = user_data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(_dev); + struct uru4k_image *img = self->img_data; + FpImage *fpimg; uint32_t key; uint8_t flags, num_lines; int i, r, to, dev2; @@ -714,27 +619,24 @@ static void imaging_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data switch (fpi_ssm_get_cur_state(ssm)) { case IMAGING_CAPTURE: - urudev->img_lines_done = 0; - urudev->img_block = 0; - r = fpi_usb_submit_transfer(urudev->img_transfer); - if (r < 0) { - urudev->img_transfer = NULL; - fpi_ssm_mark_failed(ssm, -EIO); - } + self->img_lines_done = 0; + self->img_block = 0; + fpi_usb_transfer_submit(self->img_transfer, 0, NULL, image_transfer_cb, NULL); + break; case IMAGING_SEND_INDEX: fp_dbg("hw header lines %d", img->num_lines); if (img->num_lines >= IMAGE_HEIGHT || - urudev->img_data_actual_length < img->num_lines * IMAGE_WIDTH + 64) { + self->img_data_actual_length < img->num_lines * IMAGE_WIDTH + 64) { fp_err("bad captured image (%d lines) or size mismatch %d < %d", img->num_lines, - urudev->img_data_actual_length, + self->img_data_actual_length, img->num_lines * IMAGE_WIDTH + 64); fpi_ssm_jump_to_state(ssm, IMAGING_CAPTURE); return; } - if (!urudev->profile->encryption) { + if (!self->profile->encryption) { dev2 = calc_dev2(img); fp_dbg("dev2: %d", dev2); if (dev2 < ENC_THRESHOLD) { @@ -744,43 +646,44 @@ static void imaging_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data fp_info("image seems to be encrypted"); } buf[0] = img->key_number; - buf[1] = urudev->img_enc_seed; - buf[2] = urudev->img_enc_seed >> 8; - buf[3] = urudev->img_enc_seed >> 16; - buf[4] = urudev->img_enc_seed >> 24; + buf[1] = self->img_enc_seed; + buf[2] = self->img_enc_seed >> 8; + buf[3] = self->img_enc_seed >> 16; + buf[4] = self->img_enc_seed >> 24; sm_write_regs(ssm, dev, REG_SCRAMBLE_DATA_INDEX, 5, buf); break; case IMAGING_READ_KEY: sm_read_regs(ssm, dev, REG_SCRAMBLE_DATA_KEY, 4); break; case IMAGING_DECODE: - key = urudev->last_reg_rd[0]; - key |= urudev->last_reg_rd[1] << 8; - key |= urudev->last_reg_rd[2] << 16; - key |= urudev->last_reg_rd[3] << 24; - key ^= urudev->img_enc_seed; + key = self->last_reg_rd[0]; + key |= self->last_reg_rd[1] << 8; + key |= self->last_reg_rd[2] << 16; + key |= self->last_reg_rd[3] << 24; + key ^= self->img_enc_seed; fp_dbg("encryption id %02x -> key %08x", img->key_number, key); - while (urudev->img_block < G_N_ELEMENTS(img->block_info) && - urudev->img_lines_done < img->num_lines) { - flags = img->block_info[urudev->img_block].flags; - num_lines = img->block_info[urudev->img_block].num_lines; + while (self->img_block < G_N_ELEMENTS(img->block_info) && + self->img_lines_done < img->num_lines) { + flags = img->block_info[self->img_block].flags; + num_lines = img->block_info[self->img_block].num_lines; if (num_lines == 0) break; - fp_dbg("%d %02x %d", urudev->img_block, flags, num_lines); + fp_dbg("%d %02x %d", self->img_block, flags, + num_lines); if (flags & BLOCKF_CHANGE_KEY) { fp_dbg("changing encryption keys.\n"); - img->block_info[urudev->img_block].flags &= ~BLOCKF_CHANGE_KEY; + img->block_info[self->img_block].flags &= ~BLOCKF_CHANGE_KEY; img->key_number++; - urudev->img_enc_seed = rand(); + self->img_enc_seed = rand(); fpi_ssm_jump_to_state(ssm, IMAGING_SEND_INDEX); return; } switch (flags & (BLOCKF_NO_KEY_UPDATE | BLOCKF_ENCRYPTED)) { case BLOCKF_ENCRYPTED: fp_dbg("decoding %d lines", num_lines); - key = do_decode(&img->data[urudev->img_lines_done][0], + key = do_decode(&img->data[self->img_lines_done][0], IMAGE_WIDTH*num_lines, key); break; case 0: @@ -790,13 +693,13 @@ static void imaging_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data break; } if ((flags & BLOCKF_NOT_PRESENT) == 0) - urudev->img_lines_done += num_lines; - urudev->img_block++; + self->img_lines_done += num_lines; + self->img_block++; } fpi_ssm_next_state(ssm); break; case IMAGING_REPORT_IMAGE: - fpimg = fpi_img_new_for_imgdev(dev); + fpimg = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT); to = r = 0; for (i = 0; i < G_N_ELEMENTS(img->block_info) && r < img->num_lines; i++) { @@ -811,12 +714,12 @@ static void imaging_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data to += num_lines * IMAGE_WIDTH; } - fpimg->flags = FP_IMG_COLORS_INVERTED; - if (!urudev->profile->encryption) - fpimg->flags |= FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED; - fpi_imgdev_image_captured(dev, fpimg); + fpimg->flags = FPI_IMAGE_COLORS_INVERTED; + if (!self->profile->encryption) + fpimg->flags |= FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED; + fpi_image_device_image_captured(dev, fpimg); - if (urudev->activate_state == IMGDEV_STATE_CAPTURE) + if (self->activate_state == FP_IMAGE_DEVICE_STATE_CAPTURE) fpi_ssm_jump_to_state(ssm, IMAGING_CAPTURE); else fpi_ssm_mark_completed(ssm); @@ -824,29 +727,26 @@ static void imaging_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data } } -static void imaging_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void imaging_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - struct fp_img_dev *dev = user_data; - struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev); - int r = fpi_ssm_get_error(ssm); + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); fpi_ssm_free(ssm); /* Report error before exiting imaging loop - the error handler * can request state change, which needs to be postponed to end of * this function. */ - if (r) - fpi_imgdev_session_error(dev, r); + if (error) + fpi_image_device_session_error(FP_IMAGE_DEVICE (dev), error); /* Freed by callback or cancellation */ - urudev->img_transfer = NULL; + self->img_transfer = NULL; - g_free(urudev->img_data); - urudev->img_data = NULL; - urudev->img_data_actual_length = 0; + g_free(self->img_data); + self->img_data = NULL; + self->img_data_actual_length = 0; - r = execute_state_change(dev); - if (r) - fpi_imgdev_session_error(dev, r); + execute_state_change(FP_IMAGE_DEVICE (dev)); } /***** INITIALIZATION *****/ @@ -876,43 +776,44 @@ enum rebootpwr_states { }; static void -rebootpwr_pause_cb(struct fp_dev *dev, +rebootpwr_pause_cb(FpDevice *dev, void *data) { - fpi_ssm *ssm = data; - struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev); + FpiSsm *ssm = data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); - if (!--urudev->rebootpwr_ctr) { + if (!--self->rebootpwr_ctr) { fp_err("could not reboot device power"); - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR, + "Could not reboot device")); } else { fpi_ssm_jump_to_state(ssm, REBOOTPWR_GET_HWSTAT); } } -static void rebootpwr_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void rebootpwr_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case REBOOTPWR_SET_HWSTAT: - urudev->rebootpwr_ctr = 100; - sm_set_hwstat(ssm, dev, urudev->last_hwstat & 0xf); + self->rebootpwr_ctr = 100; + sm_set_hwstat(ssm, dev, self->last_hwstat & 0xf); break; case REBOOTPWR_GET_HWSTAT: sm_read_reg(ssm, dev, REG_HWSTAT); break; case REBOOTPWR_CHECK_HWSTAT: - urudev->last_hwstat = urudev->last_reg_rd[0]; - if (urudev->last_hwstat & 0x1) + self->last_hwstat = self->last_reg_rd[0]; + if (self->last_hwstat & 0x1) fpi_ssm_mark_completed(ssm); else fpi_ssm_next_state(ssm); break; case REBOOTPWR_PAUSE: - if (fpi_timeout_add(10, rebootpwr_pause_cb, _dev, ssm) == NULL) - fpi_ssm_mark_failed(ssm, -ETIME); + fpi_device_add_timeout(_dev, 10, rebootpwr_pause_cb, ssm); break; } } @@ -954,49 +855,50 @@ enum powerup_states { }; static void -powerup_pause_cb(struct fp_dev *dev, +powerup_pause_cb(FpDevice *dev, void *data) { - fpi_ssm *ssm = data; - struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev); + FpiSsm *ssm = data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); - if (!--urudev->powerup_ctr) { + if (!--self->powerup_ctr) { fp_err("could not power device up"); - fpi_ssm_mark_failed(ssm, -EIO); - } else if (!urudev->profile->auth_cr) { + fpi_ssm_mark_failed(ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "could not power device up")); + } else if (!self->profile->auth_cr) { fpi_ssm_jump_to_state(ssm, POWERUP_SET_HWSTAT); } else { fpi_ssm_next_state(ssm); } } -static void powerup_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void powerup_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case POWERUP_INIT: - urudev->powerup_ctr = 100; - urudev->powerup_hwstat = urudev->last_hwstat & 0xf; + self->powerup_ctr = 100; + self->powerup_hwstat = self->last_hwstat & 0xf; fpi_ssm_next_state(ssm); break; case POWERUP_SET_HWSTAT: - sm_set_hwstat(ssm, dev, urudev->powerup_hwstat); + sm_set_hwstat(ssm, dev, self->powerup_hwstat); break; case POWERUP_GET_HWSTAT: sm_read_reg(ssm, dev, REG_HWSTAT); break; case POWERUP_CHECK_HWSTAT: - urudev->last_hwstat = urudev->last_reg_rd[0]; - if ((urudev->last_reg_rd[0] & 0x80) == 0) + self->last_hwstat = self->last_reg_rd[0]; + if ((self->last_reg_rd[0] & 0x80) == 0) fpi_ssm_mark_completed(ssm); else fpi_ssm_next_state(ssm); break; case POWERUP_PAUSE: - if (fpi_timeout_add(10, powerup_pause_cb, _dev, ssm) == NULL) - fpi_ssm_mark_failed(ssm, -ETIME); + fpi_device_add_timeout(_dev, 10, powerup_pause_cb, ssm); break; case POWERUP_CHALLENGE_RESPONSE: sm_do_challenge_response(ssm, dev); @@ -1038,14 +940,14 @@ enum init_states { INIT_NUM_STATES, }; -static void init_scanpwr_irq_cb(struct fp_img_dev *dev, int status, +static void init_scanpwr_irq_cb(FpImageDevice *dev, GError *error, uint16_t type, void *user_data) { - fpi_ssm *ssm = user_data; - struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiSsm *ssm = user_data; + FpiDeviceUru4000 *urudev = FPI_DEVICE_URU4000 (dev); - if (status) - fpi_ssm_mark_failed(ssm, status); + if (error) + fpi_ssm_mark_failed(ssm, error); else if (type != IRQDATA_SCANPWR_ON) fp_dbg("ignoring interrupt"); else if (fpi_ssm_get_cur_state(ssm) != INIT_AWAIT_SCAN_POWER) { @@ -1058,65 +960,71 @@ static void init_scanpwr_irq_cb(struct fp_img_dev *dev, int status, } static void -init_scanpwr_timeout(struct fp_dev *dev, +init_scanpwr_timeout(FpDevice *dev, void *user_data) { - fpi_ssm *ssm = user_data; - struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev); + FpiSsm *ssm = user_data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); fp_warn("powerup timed out"); - urudev->irq_cb = NULL; - urudev->scanpwr_irq_timeout = NULL; + self->irq_cb = NULL; + self->scanpwr_irq_timeout = NULL; - if (++urudev->scanpwr_irq_timeouts >= 3) { + if (++self->scanpwr_irq_timeouts >= 3) { fp_err("powerup timed out 3 times, giving up"); - fpi_ssm_mark_failed(ssm, -ETIMEDOUT); + fpi_ssm_mark_failed(ssm, + g_error_new_literal (G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_TIMED_OUT, + "Powerup timed out 3 times, giving up")); } else { fpi_ssm_jump_to_state(ssm, INIT_GET_HWSTAT); } } -static void init_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void init_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case INIT_GET_HWSTAT: sm_read_reg(ssm, dev, REG_HWSTAT); break; case INIT_CHECK_HWSTAT_REBOOT: - urudev->last_hwstat = urudev->last_reg_rd[0]; - if ((urudev->last_hwstat & 0x84) == 0x84) + self->last_hwstat = self->last_reg_rd[0]; + if ((self->last_hwstat & 0x84) == 0x84) fpi_ssm_next_state(ssm); else fpi_ssm_jump_to_state(ssm, INIT_CHECK_HWSTAT_POWERDOWN); break; case INIT_REBOOT_POWER: ; - fpi_ssm *rebootsm = fpi_ssm_new(FP_DEV(dev), rebootpwr_run_state, - REBOOTPWR_NUM_STATES, dev); + FpiSsm *rebootsm = fpi_ssm_new(FP_DEVICE(dev), + rebootpwr_run_state, + REBOOTPWR_NUM_STATES, dev); fpi_ssm_start_subsm(ssm, rebootsm); break; case INIT_CHECK_HWSTAT_POWERDOWN: - if ((urudev->last_hwstat & 0x80) == 0) - sm_set_hwstat(ssm, dev, urudev->last_hwstat | 0x80); + if ((self->last_hwstat & 0x80) == 0) + sm_set_hwstat(ssm, dev, self->last_hwstat | 0x80); else fpi_ssm_next_state(ssm); break; - case INIT_POWERUP: ; - if (!IRQ_HANDLER_IS_RUNNING(urudev)) { - fpi_ssm_mark_failed(ssm, -EIO); - break; + case INIT_POWERUP: + if (!IRQ_HANDLER_IS_RUNNING(self)) { + fpi_ssm_mark_failed(ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "IRQ handler should be running but is not")); + return; } - urudev->irq_cb_data = ssm; - urudev->irq_cb = init_scanpwr_irq_cb; + self->irq_cb_data = ssm; + self->irq_cb = init_scanpwr_irq_cb; - fpi_ssm *powerupsm = fpi_ssm_new(FP_DEV(dev), powerup_run_state, - POWERUP_NUM_STATES, dev); + FpiSsm *powerupsm = fpi_ssm_new(FP_DEVICE(dev), + powerup_run_state, + POWERUP_NUM_STATES, dev); fpi_ssm_start_subsm(ssm, powerupsm); break; case INIT_AWAIT_SCAN_POWER: - if (urudev->scanpwr_irq_timeouts < 0) { + if (self->scanpwr_irq_timeouts < 0) { fpi_ssm_next_state(ssm); break; } @@ -1124,21 +1032,18 @@ static void init_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) /* sometimes the 56aa interrupt that we are waiting for never arrives, * so we include this timeout loop to retry the whole process 3 times * if we don't get an irq any time soon. */ - urudev->scanpwr_irq_timeout = fpi_timeout_add(300, - init_scanpwr_timeout, - _dev, ssm); - if (!urudev->scanpwr_irq_timeout) { - fpi_ssm_mark_failed(ssm, -ETIME); - break; - } + self->scanpwr_irq_timeout = fpi_device_add_timeout(_dev, + 300, + init_scanpwr_timeout, + ssm); break; case INIT_DONE: - if (urudev->scanpwr_irq_timeout) { - fpi_timeout_cancel(urudev->scanpwr_irq_timeout); - urudev->scanpwr_irq_timeout = NULL; + if (self->scanpwr_irq_timeout) { + g_source_destroy (self->scanpwr_irq_timeout); + self->scanpwr_irq_timeout = NULL; } - urudev->irq_cb_data = NULL; - urudev->irq_cb = NULL; + self->irq_cb_data = NULL; + self->irq_cb = NULL; fpi_ssm_next_state(ssm); break; case INIT_GET_VERSION: @@ -1148,142 +1053,137 @@ static void init_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) /* Likely hardware revision, and firmware version. * Not sure which is which. */ fp_info("Versions %02x%02x and %02x%02x", - urudev->last_reg_rd[10], urudev->last_reg_rd[11], - urudev->last_reg_rd[4], urudev->last_reg_rd[5]); + self->last_reg_rd[10], self->last_reg_rd[11], + self->last_reg_rd[4], self->last_reg_rd[5]); fpi_ssm_mark_completed(ssm); break; } } -static void activate_initsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_initsm_complete(FpiSsm *ssm, FpDevice *dev, + void *user_data, GError *error) { - struct fp_img_dev *dev = user_data; - int r = fpi_ssm_get_error(ssm); - fpi_ssm_free(ssm); - - fpi_imgdev_activate_complete(dev, r); + fpi_image_device_activate_complete(FP_IMAGE_DEVICE (dev), error); } -static int dev_activate(struct fp_img_dev *dev) +static void dev_activate(FpImageDevice *dev) { - struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_ssm *ssm; - int r; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); + FpiSsm *ssm; - r = start_irq_handler(dev); - if (r < 0) - return r; + start_irq_handler(dev); - urudev->scanpwr_irq_timeouts = 0; - ssm = fpi_ssm_new(FP_DEV(dev), init_run_state, INIT_NUM_STATES, dev); + self->scanpwr_irq_timeouts = 0; + ssm = fpi_ssm_new(FP_DEVICE(dev), init_run_state, INIT_NUM_STATES, NULL); fpi_ssm_start(ssm, activate_initsm_complete); - return 0; } /***** DEINITIALIZATION *****/ -static void deactivate_irqs_stopped(struct fp_img_dev *dev) +static void deactivate_irqs_stopped(FpImageDevice *dev) { - fpi_imgdev_deactivate_complete(dev); + fpi_image_device_deactivate_complete(dev, NULL); } -static void deactivate_write_reg_cb(struct fp_img_dev *dev, int status, - void *user_data) +static void deactivate_write_reg_cb(FpiUsbTransfer *transfer, FpDevice *dev, + gpointer user_data, GError *error) { - stop_irq_handler(dev, deactivate_irqs_stopped); + stop_irq_handler(FP_IMAGE_DEVICE (dev), deactivate_irqs_stopped); } -static void dev_deactivate(struct fp_img_dev *dev) +static void dev_deactivate(FpImageDevice *dev) { - dev_change_state(dev, IMGDEV_STATE_INACTIVE); + dev_change_state(dev, FP_IMAGE_DEVICE_STATE_INACTIVE); } -static int execute_state_change(struct fp_img_dev *dev) +static void execute_state_change(FpImageDevice *dev) { - struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_ssm *ssm; - void *img_data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); + FpiSsm *ssm; - switch (urudev->activate_state) { - case IMGDEV_STATE_INACTIVE: + switch (self->activate_state) { + case FP_IMAGE_DEVICE_STATE_INACTIVE: fp_dbg("deactivating"); - urudev->irq_cb = NULL; - urudev->irq_cb_data = NULL; - return write_reg(dev, REG_MODE, MODE_OFF, - deactivate_write_reg_cb, NULL); + self->irq_cb = NULL; + self->irq_cb_data = NULL; + write_reg(dev, REG_MODE, MODE_OFF, + deactivate_write_reg_cb, NULL); break; - case IMGDEV_STATE_AWAIT_FINGER_ON: + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: fp_dbg("wait finger on"); - if (!IRQ_HANDLER_IS_RUNNING(urudev)) - return -EIO; - urudev->irq_cb = finger_presence_irq_cb; - return write_reg(dev, REG_MODE, MODE_AWAIT_FINGER_ON, - change_state_write_reg_cb, NULL); + if (!IRQ_HANDLER_IS_RUNNING(self)) { + fpi_image_device_session_error (dev, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "IRQ handler should be running but is not")); + return; + } + self->irq_cb = finger_presence_irq_cb; + write_reg(dev, REG_MODE, MODE_AWAIT_FINGER_ON, + change_state_write_reg_cb, NULL); + break; - case IMGDEV_STATE_CAPTURE: + case FP_IMAGE_DEVICE_STATE_CAPTURE: fp_dbg("starting capture"); - urudev->irq_cb = NULL; + self->irq_cb = NULL; - ssm = fpi_ssm_new(FP_DEV(dev), imaging_run_state, IMAGING_NUM_STATES, dev); - img_data = g_malloc(sizeof(struct uru4k_image)); - urudev->img_enc_seed = rand(); - urudev->img_transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev), - ssm, - EP_DATA, - img_data, - sizeof(struct uru4k_image), - image_transfer_cb, - NULL, - 0); + ssm = fpi_ssm_new(FP_DEVICE(dev), imaging_run_state, + IMAGING_NUM_STATES, dev); + self->img_enc_seed = rand(); + self->img_transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + self->img_transfer->ssm = ssm; + self->img_transfer->short_is_error = FALSE; + fpi_usb_transfer_fill_bulk(self->img_transfer, + EP_DATA, + sizeof(struct uru4k_image)); fpi_ssm_start(ssm, imaging_complete); - return write_reg(dev, REG_MODE, MODE_CAPTURE, - change_state_write_reg_cb, NULL); + write_reg(dev, REG_MODE, MODE_CAPTURE, + change_state_write_reg_cb, NULL); + break; - case IMGDEV_STATE_AWAIT_FINGER_OFF: + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: fp_dbg("await finger off"); - if (!IRQ_HANDLER_IS_RUNNING(urudev)) - return -EIO; - urudev->irq_cb = finger_presence_irq_cb; - return write_reg(dev, REG_MODE, MODE_AWAIT_FINGER_OFF, - change_state_write_reg_cb, NULL); + if (!IRQ_HANDLER_IS_RUNNING(self)) { + fpi_image_device_session_error (dev, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "IRQ handler should be running but is not")); + return; + } + self->irq_cb = finger_presence_irq_cb; + write_reg(dev, REG_MODE, MODE_AWAIT_FINGER_OFF, + change_state_write_reg_cb, NULL); + break; } - - return 0; } /***** LIBRARY STUFF *****/ -static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) +static void dev_init(FpImageDevice *dev) { - struct libusb_config_descriptor *config; - const struct libusb_interface *iface = NULL; - const struct libusb_interface_descriptor *iface_desc; - const struct libusb_endpoint_descriptor *ep; - struct uru4k_dev *urudev; + GError *error = NULL; + FpiDeviceUru4000 *self; + g_autoptr(GPtrArray) interfaces = NULL; + GUsbInterface *iface = NULL; + guint64 driver_data; SECStatus rv; SECItem item; int i; - int r; - /* Find fingerprint interface */ - r = libusb_get_config_descriptor(libusb_get_device(fpi_dev_get_usb_dev(FP_DEV(dev))), 0, &config); - if (r < 0) { - fp_err("Failed to get config descriptor"); - return r; + interfaces = g_usb_device_get_interfaces (fpi_device_get_usb_device(FP_DEVICE(dev)), &error); + if (error) { + fpi_image_device_open_complete (dev, error); + return; } - for (i = 0; i < config->bNumInterfaces; i++) { - const struct libusb_interface *cur_iface = &config->interface[i]; - if (cur_iface->num_altsetting < 1) - continue; + /* Find fingerprint interface; TODO: Move this into probe() */ + for (i = 0; i < interfaces->len; i++) { + GUsbInterface *cur_iface = g_ptr_array_index (interfaces, i); - iface_desc = &cur_iface->altsetting[0]; - if (iface_desc->bInterfaceClass == 255 - && iface_desc->bInterfaceSubClass == 255 - && iface_desc->bInterfaceProtocol == 255) { + if (g_usb_interface_get_class (cur_iface) == 255 && + g_usb_interface_get_subclass (cur_iface) == 255 && + g_usb_interface_get_protocol (cur_iface) == 255) { iface = cur_iface; break; } @@ -1291,12 +1191,14 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) if (iface == NULL) { fp_err("could not find interface"); - r = -ENODEV; - goto out; + fpi_image_device_open_complete (dev, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Could not find interface")); + return; } - /* Find/check endpoints */ - + /* TODO: Find/check endpoints; does not seem easily possible with GUsb unfortunately! */ +#if 0 if (iface_desc->bNumEndpoints != 2) { fp_err("found %d endpoints!?", iface_desc->bNumEndpoints); r = -ENODEV; @@ -1320,13 +1222,14 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) r = -ENODEV; goto out; } +#endif /* Device looks like a supported reader */ - r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), iface_desc->bInterfaceNumber); - if (r < 0) { - fp_err("interface claim failed: %s", libusb_error_name(r)); - goto out; + if (!g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), + g_usb_interface_get_number (iface), 0, &error)) { + fpi_image_device_open_complete(dev, error); + return; } /* Disable loading p11-kit's user configuration */ @@ -1336,101 +1239,111 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) rv = NSS_NoDB_Init("."); if (rv != SECSuccess) { fp_err("could not initialise NSS"); - goto out; + fpi_image_device_open_complete (dev, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Could not initialise NSS")); + return; } - urudev = g_malloc0(sizeof(*urudev)); - fp_dev_set_instance_data(FP_DEV(dev), urudev); + self = FPI_DEVICE_URU4000(dev); - urudev->profile = &uru4k_dev_info[driver_data]; - urudev->interface = iface_desc->bInterfaceNumber; + driver_data = fpi_device_get_driver_data (FP_DEVICE (dev)); + self->profile = &uru4k_dev_info[driver_data]; + self->interface = g_usb_interface_get_number (iface); /* Set up encryption */ - urudev->cipher = CKM_AES_ECB; - urudev->slot = PK11_GetBestSlot(urudev->cipher, NULL); - if (urudev->slot == NULL) { + self->cipher = CKM_AES_ECB; + self->slot = PK11_GetBestSlot(self->cipher, NULL); + if (self->slot == NULL) { fp_err("could not get encryption slot"); - goto out; + fpi_image_device_open_complete (dev, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Could not get encryption slot")); + return; } item.type = siBuffer; item.data = (unsigned char*) crkey; item.len = sizeof(crkey); - urudev->symkey = PK11_ImportSymKey(urudev->slot, - urudev->cipher, + self->symkey = PK11_ImportSymKey(self->slot, + self->cipher, PK11_OriginUnwrap, CKA_ENCRYPT, &item, NULL); - if (urudev->symkey == NULL) { + if (self->symkey == NULL) { fp_err("failed to import key into NSS"); - PK11_FreeSlot(urudev->slot); - urudev->slot = NULL; - goto out; + PK11_FreeSlot(self->slot); + self->slot = NULL; + fpi_image_device_open_complete (dev, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Failed to import key into NSS")); + return; } - urudev->param = PK11_ParamFromIV(urudev->cipher, NULL); + self->param = PK11_ParamFromIV(self->cipher, NULL); - fpi_imgdev_open_complete(dev, 0); - -out: - libusb_free_config_descriptor(config); - return r; + fpi_image_device_open_complete(dev, NULL); } -static void dev_deinit(struct fp_img_dev *dev) +static void dev_deinit(FpImageDevice *dev) { - struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev)); - if (urudev->symkey) - PK11_FreeSymKey (urudev->symkey); - if (urudev->param) - SECITEM_FreeItem(urudev->param, PR_TRUE); - if (urudev->slot) - PK11_FreeSlot(urudev->slot); - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), urudev->interface); - g_free(urudev); - fpi_imgdev_close_complete(dev); + GError *error = NULL; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); + if (self->symkey) + PK11_FreeSymKey (self->symkey); + if (self->param) + SECITEM_FreeItem(self->param, PR_TRUE); + if (self->slot) + PK11_FreeSlot(self->slot); + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), + self->interface, 0, &error); + fpi_image_device_close_complete(dev, error); } -static const struct usb_id id_table[] = { +static const FpIdEntry id_table [ ] = { /* ms kbd with fp rdr */ - { .vendor = 0x045e, .product = 0x00bb, .driver_data = MS_KBD }, + { .vid = 0x045e, .pid = 0x00bb, .driver_data = MS_KBD }, /* ms intellimouse with fp rdr */ - { .vendor = 0x045e, .product = 0x00bc, .driver_data = MS_INTELLIMOUSE }, + { .vid = 0x045e, .pid = 0x00bc, .driver_data = MS_INTELLIMOUSE }, /* ms fp rdr (standalone) */ - { .vendor = 0x045e, .product = 0x00bd, .driver_data = MS_STANDALONE }, + { .vid = 0x045e, .pid = 0x00bd, .driver_data = MS_STANDALONE }, /* ms fp rdr (standalone) v2 */ - { .vendor = 0x045e, .product = 0x00ca, .driver_data = MS_STANDALONE_V2 }, + { .vid = 0x045e, .pid = 0x00ca, .driver_data = MS_STANDALONE_V2 }, /* dp uru4000 (standalone) */ - { .vendor = 0x05ba, .product = 0x0007, .driver_data = DP_URU4000 }, + { .vid = 0x05ba, .pid = 0x0007, .driver_data = DP_URU4000 }, /* dp uru4000 (keyboard) */ - { .vendor = 0x05ba, .product = 0x0008, .driver_data = DP_URU4000 }, + { .vid = 0x05ba, .pid = 0x0008, .driver_data = DP_URU4000 }, /* dp uru4000b (standalone) */ - { .vendor = 0x05ba, .product = 0x000a, .driver_data = DP_URU4000B }, + { .vid = 0x05ba, .pid = 0x000a, .driver_data = DP_URU4000B }, /* terminating entry */ - { 0, 0, 0, }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -struct fp_img_driver uru4000_driver = { - .driver = { - .id = URU4000_ID, - .name = FP_COMPONENT, - .full_name = "Digital Persona U.are.U 4000/4000B/4500", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_PRESS, - }, - .flags = FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE, - .img_height = IMAGE_HEIGHT, - .img_width = IMAGE_WIDTH, +static void fpi_device_uru4000_init(FpiDeviceUru4000 *self) { +} - .open = dev_init, - .close = dev_deinit, - .activate = dev_activate, - .deactivate = dev_deactivate, - .change_state = dev_change_state, -}; +static void fpi_device_uru4000_class_init(FpiDeviceUru4000Class *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); + + dev_class->id = "uru4000"; + dev_class->full_name = "Digital Persona U.are.U 4000/4000B/4500"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_PRESS; + + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; + img_class->change_state = dev_change_state; + + img_class->img_width = IMAGE_WIDTH; + img_class->img_height = IMAGE_HEIGHT; +} diff --git a/meson.build b/meson.build index 2e7b1e2a..c504064f 100644 --- a/meson.build +++ b/meson.build @@ -52,7 +52,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603', 'vcom5s', 'synaptics', 'elan'] +default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603', 'vcom5s', 'synaptics', 'elan', 'uru4000'] all_drivers = default_drivers + virtual_drivers From fcfe82a7b81fe567a3dcf2d03c6369632fd915bb Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 7 Aug 2019 13:21:42 +0200 Subject: [PATCH 47/73] upektc: Port upektc driver to new API --- libfprint/drivers/upektc.c | 486 +++++++++++++++++-------------------- meson.build | 2 +- 2 files changed, 225 insertions(+), 263 deletions(-) diff --git a/libfprint/drivers/upektc.c b/libfprint/drivers/upektc.c index 00d9c553..fb4c0f78 100644 --- a/libfprint/drivers/upektc.c +++ b/libfprint/drivers/upektc.c @@ -23,13 +23,15 @@ #include "drivers_api.h" #include "upektc.h" -#define UPEKTC_EP_IN (2 | LIBUSB_ENDPOINT_IN) -#define UPEKTC_EP_OUT (3 | LIBUSB_ENDPOINT_OUT) -#define UPEKET_EP_IN (1 | LIBUSB_ENDPOINT_IN) -#define UPEKET_EP_OUT (2 | LIBUSB_ENDPOINT_OUT) +#define UPEKTC_EP_IN (2 | FPI_USB_ENDPOINT_IN) +#define UPEKTC_EP_OUT (3 | FPI_USB_ENDPOINT_OUT) +#define UPEKET_EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define UPEKET_EP_OUT (2 | FPI_USB_ENDPOINT_OUT) #define BULK_TIMEOUT 4000 -struct upektc_dev { +struct _FpiDeviceUpektc { + FpImageDevice parent; + gboolean deactivating; const struct setup_cmd *setup_commands; size_t setup_commands_len; @@ -38,15 +40,18 @@ struct upektc_dev { int init_idx; int sum_threshold; }; +G_DECLARE_FINAL_TYPE(FpiDeviceUpektc, fpi_device_upektc, FPI, DEVICE_UPEKTC, + FpImageDevice); +G_DEFINE_TYPE(FpiDeviceUpektc, fpi_device_upektc, FP_TYPE_IMAGE_DEVICE); enum upektc_driver_data { UPEKTC_2015, UPEKTC_3001, }; -static void start_capture(struct fp_img_dev *dev); -static void complete_deactivation(struct fp_img_dev *dev); -static void start_finger_detection(struct fp_img_dev *dev); +static void start_capture(FpImageDevice *dev); +static void complete_deactivation(FpImageDevice *dev, GError *error); +static void start_finger_detection(FpImageDevice *dev); /****** INITIALIZATION/DEINITIALIZATION ******/ @@ -57,98 +62,90 @@ enum activate_states { }; static void -upektc_next_init_cmd(fpi_ssm *ssm, - struct fp_img_dev *dev) +upektc_next_init_cmd(FpiSsm *ssm, + FpImageDevice *dev) { - struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); - upekdev->init_idx += 1; - if (upekdev->init_idx == upekdev->setup_commands_len) + self->init_idx += 1; + if (self->init_idx == self->setup_commands_len) fpi_ssm_mark_completed(ssm); else fpi_ssm_jump_to_state(ssm, WRITE_INIT); } -static void write_init_cb(struct libusb_transfer *transfer) +static void write_init_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpImageDevice *dev = FP_IMAGE_DEVICE(device); + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); - if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && - (transfer->length == transfer->actual_length)) { - if (upekdev->setup_commands[upekdev->init_idx].response_len) - fpi_ssm_next_state(ssm); + if (!error) { + if (self->setup_commands[self->init_idx].response_len) + fpi_ssm_next_state(transfer->ssm); else - upektc_next_init_cmd(ssm, dev); + upektc_next_init_cmd(transfer->ssm, dev); } else { - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, error); } - libusb_free_transfer(transfer); } -static void read_init_data_cb(struct libusb_transfer *transfer) +static void read_init_data_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); + FpImageDevice *dev = FP_IMAGE_DEVICE(device); - if (transfer->status == LIBUSB_TRANSFER_COMPLETED) - upektc_next_init_cmd(ssm, dev); + if (!error) + upektc_next_init_cmd(transfer->ssm, dev); else - fpi_ssm_mark_failed(ssm, -EIO); - g_free(transfer->buffer); - libusb_free_transfer(transfer); + fpi_ssm_mark_failed(transfer->ssm, error); } -static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev); - int r; + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); switch (fpi_ssm_get_cur_state(ssm)) { case WRITE_INIT: { - struct libusb_transfer *transfer = fpi_usb_alloc(); + FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out, - (unsigned char*)upekdev->setup_commands[upekdev->init_idx].cmd, - UPEKTC_CMD_LEN, write_init_cb, ssm, BULK_TIMEOUT); - r = libusb_submit_transfer(transfer); - if (r < 0) { - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, -ENOMEM); - } + fpi_usb_transfer_fill_bulk_full(transfer, + self->ep_out, + (unsigned char *) self->setup_commands[self->init_idx].cmd, + UPEKTC_CMD_LEN, + NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + write_init_cb, NULL); + fpi_usb_transfer_unref(transfer); } break; case READ_DATA: { - struct libusb_transfer *transfer = fpi_usb_alloc(); - unsigned char *data; + FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); - data = g_malloc(upekdev->setup_commands[upekdev->init_idx].response_len); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data, - upekdev->setup_commands[upekdev->init_idx].response_len, - read_init_data_cb, ssm, BULK_TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + fpi_usb_transfer_fill_bulk (transfer, + self->ep_in, + self->setup_commands[self->init_idx].response_len); + transfer->ssm = ssm; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + read_init_data_cb, NULL); + fpi_usb_transfer_unref(transfer); } break; } } -static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void activate_sm_complete(FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - struct fp_img_dev *dev = user_data; - fp_dbg("status %d", fpi_ssm_get_error(ssm)); - fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm)); + FpImageDevice *dev = FP_IMAGE_DEVICE(_dev); - if (!fpi_ssm_get_error(ssm)) + fpi_image_device_activate_complete(dev, error); + + if (!error) start_finger_detection(dev); fpi_ssm_free(ssm); } @@ -172,90 +169,69 @@ static int finger_present(unsigned char *img, size_t len, int sum_threshold) return sum < sum_threshold ? 0 : 1; } -static void finger_det_data_cb(struct libusb_transfer *transfer) +static void finger_det_data_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - struct fp_img_dev *dev = transfer->user_data; - struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); - unsigned char *data = transfer->buffer; + FpImageDevice *dev = FP_IMAGE_DEVICE(device); + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fp_dbg("data transfer status %d\n", transfer->status); - fpi_imgdev_session_error(dev, -EIO); - goto out; - } else if (transfer->length != transfer->actual_length) { - fp_dbg("expected %d, got %d bytes", transfer->length, - transfer->actual_length); - fpi_imgdev_session_error(dev, -EPROTO); + if (error) { + fp_dbg("data transfer status %s\n", error->message); + fpi_image_device_session_error(dev, error); + return; } - if (finger_present(data, IMAGE_SIZE, upekdev->sum_threshold)) { + if (finger_present(transfer->buffer, IMAGE_SIZE, self->sum_threshold)) { /* finger present, start capturing */ - fpi_imgdev_report_finger_status(dev, TRUE); + fpi_image_device_report_finger_status(dev, TRUE); start_capture(dev); } else { /* no finger, poll for a new histogram */ start_finger_detection(dev); } - -out: - g_free(data); - libusb_free_transfer(transfer); } -static void finger_det_cmd_cb(struct libusb_transfer *t) +static void finger_det_cmd_cb(FpiUsbTransfer *t, FpDevice *device, + gpointer user_data, GError *error) { - struct libusb_transfer *transfer; - unsigned char *data; - int r; - struct fp_img_dev *dev = t->user_data; - struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiUsbTransfer *transfer; + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); - if (t->status != LIBUSB_TRANSFER_COMPLETED) { - fp_dbg("req transfer status %d\n", t->status); - fpi_imgdev_session_error(dev, -EIO); - goto exit_free_transfer; - } else if (t->length != t->actual_length) { - fp_dbg("expected %d, sent %d bytes", t->length, t->actual_length); - fpi_imgdev_session_error(dev, -EPROTO); - goto exit_free_transfer; - } - - transfer = fpi_usb_alloc(); - data = g_malloc(IMAGE_SIZE); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data, IMAGE_SIZE, - finger_det_data_cb, dev, BULK_TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_imgdev_session_error(dev, r); - } -exit_free_transfer: - libusb_free_transfer(t); -} - -static void start_finger_detection(struct fp_img_dev *dev) -{ - int r; - struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); - struct libusb_transfer *transfer; - G_DEBUG_HERE(); - - if (upekdev->deactivating) { - complete_deactivation(dev); + if (error) { + fp_dbg("req transfer status %s\n", error->message); + fpi_image_device_session_error(dev, error); return; } - transfer = fpi_usb_alloc(); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out, - (unsigned char *)scan_cmd, UPEKTC_CMD_LEN, - finger_det_cmd_cb, dev, BULK_TIMEOUT); - r = libusb_submit_transfer(transfer); - if (r < 0) { - libusb_free_transfer(transfer); - fpi_imgdev_session_error(dev, r); + transfer = fpi_usb_transfer_new (device); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk(transfer, self->ep_in, + IMAGE_SIZE); + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + finger_det_data_cb, NULL); + fpi_usb_transfer_unref(transfer); +} + +static void start_finger_detection(FpImageDevice *dev) +{ + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); + FpiUsbTransfer *transfer; + G_DEBUG_HERE(); + + if (self->deactivating) { + complete_deactivation(dev, NULL); + return; } + + transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk_full(transfer, self->ep_out, + (unsigned char *)scan_cmd, + UPEKTC_CMD_LEN, NULL); + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + finger_det_cmd_cb, NULL); + fpi_usb_transfer_unref(transfer); } /****** CAPTURE ******/ @@ -266,213 +242,199 @@ enum capture_states { CAPTURE_NUM_STATES, }; -static void capture_cmd_cb(struct libusb_transfer *transfer) +static void capture_cmd_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - - if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && - (transfer->length == transfer->actual_length)) { - fpi_ssm_next_state(ssm); + if (!error) { + fpi_ssm_next_state(transfer->ssm); } else { - fpi_ssm_mark_failed(ssm, -EIO); + fpi_ssm_mark_failed(transfer->ssm, error); } - libusb_free_transfer(transfer); } -static void capture_read_data_cb(struct libusb_transfer *transfer) +static void capture_read_data_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - unsigned char *data = transfer->buffer; - struct fp_img *img; + FpImageDevice *dev = FP_IMAGE_DEVICE(device); + FpImage *img; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fp_dbg("request is not completed, %d", transfer->status); - fpi_ssm_mark_failed(ssm, -EIO); - goto out; - } else if (transfer->length != transfer->actual_length) { - fp_dbg("expected %d, sent %d bytes", transfer->length, transfer->actual_length); - fpi_ssm_mark_failed(ssm, -EPROTO); - goto out; + if (error) { + fp_dbg("request is not completed, %s", error->message); + fpi_ssm_mark_failed(transfer->ssm, error); + return; } - img = fpi_img_new(IMAGE_SIZE); - memcpy(img->data, data, IMAGE_SIZE); - fpi_imgdev_image_captured(dev, img); - fpi_imgdev_report_finger_status(dev, FALSE); - fpi_ssm_mark_completed(ssm); -out: - g_free(transfer->buffer); - libusb_free_transfer(transfer); + img = fp_image_new(IMAGE_WIDTH, IMAGE_HEIGHT); + memcpy(img->data, transfer->buffer, IMAGE_SIZE); + fpi_image_device_image_captured(dev, img); + fpi_image_device_report_finger_status(dev, FALSE); + fpi_ssm_mark_completed(transfer->ssm); } -static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capture_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev); - int r; + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case CAPTURE_WRITE_CMD: { - struct libusb_transfer *transfer = fpi_usb_alloc(); + FpiUsbTransfer *transfer = fpi_usb_transfer_new(_dev); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out, - (unsigned char *)scan_cmd, UPEKTC_CMD_LEN, - capture_cmd_cb, ssm, BULK_TIMEOUT); - r = libusb_submit_transfer(transfer); - if (r < 0) { - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, -ENOMEM); - } + fpi_usb_transfer_fill_bulk_full(transfer, self->ep_out, + (unsigned char *)scan_cmd, + UPEKTC_CMD_LEN, NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + capture_cmd_cb, NULL); + fpi_usb_transfer_unref(transfer); } break; case CAPTURE_READ_DATA: { - struct libusb_transfer *transfer = fpi_usb_alloc(); - unsigned char *data; + FpiUsbTransfer *transfer = fpi_usb_transfer_new(_dev); - data = g_malloc(IMAGE_SIZE); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data, IMAGE_SIZE, - capture_read_data_cb, ssm, BULK_TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + fpi_usb_transfer_fill_bulk(transfer, self->ep_in, + IMAGE_SIZE); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, + capture_read_data_cb, NULL); + fpi_usb_transfer_unref(transfer); } break; }; } -static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capture_sm_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - struct fp_img_dev *dev = user_data; - struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(_dev); fp_dbg("Capture completed"); - if (upekdev->deactivating) - complete_deactivation(dev); - else if (fpi_ssm_get_error(ssm)) - fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm)); + if (self->deactivating) + complete_deactivation(dev, error); + else if (error) + fpi_image_device_session_error(dev, error); else start_finger_detection(dev); + fpi_ssm_free(ssm); } -static void start_capture(struct fp_img_dev *dev) +static void start_capture(FpImageDevice *dev) { - struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_ssm *ssm; + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); + FpiSsm *ssm; - if (upekdev->deactivating) { - complete_deactivation(dev); + if (self->deactivating) { + complete_deactivation(dev, NULL); return; } - ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev); + ssm = fpi_ssm_new(FP_DEVICE(dev), capture_run_state, + CAPTURE_NUM_STATES, dev); G_DEBUG_HERE(); fpi_ssm_start(ssm, capture_sm_complete); } -static int dev_activate(struct fp_img_dev *dev) +static void dev_activate(FpImageDevice *dev) { - struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); - upekdev->init_idx = 0; + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); + FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); + self->init_idx = 0; fpi_ssm_start(ssm, activate_sm_complete); - return 0; } -static void dev_deactivate(struct fp_img_dev *dev) +static void dev_deactivate(FpImageDevice *dev) { - struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); - upekdev->deactivating = TRUE; + self->deactivating = TRUE; } -static void complete_deactivation(struct fp_img_dev *dev) +static void complete_deactivation(FpImageDevice *dev, GError *error) { - struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); G_DEBUG_HERE(); - upekdev->deactivating = FALSE; - fpi_imgdev_deactivate_complete(dev); + self->deactivating = FALSE; + fpi_image_device_deactivate_complete(dev, error); } -static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) +static void dev_init(FpImageDevice *dev) { - /* TODO check that device has endpoints we're using */ - int r; - struct upektc_dev *upekdev; + GError *error = NULL; + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); + guint64 driver_data = fpi_device_get_driver_data (FP_DEVICE (dev)); - r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - if (r < 0) { - fp_err("could not claim interface 0: %s", libusb_error_name(r)); - return r; + /* TODO check that device has endpoints we're using */ + + if (!g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error)) { + fpi_image_device_open_complete(dev, error); + return; } - upekdev = g_malloc0(sizeof(struct upektc_dev)); - fp_dev_set_instance_data(FP_DEV(dev), upekdev); switch (driver_data) { case UPEKTC_2015: - upekdev->ep_in = UPEKTC_EP_IN; - upekdev->ep_out = UPEKTC_EP_OUT; - upekdev->setup_commands = upektc_setup_commands; - upekdev->setup_commands_len = G_N_ELEMENTS(upektc_setup_commands); - upekdev->sum_threshold = UPEKTC_SUM_THRESHOLD; + self->ep_in = UPEKTC_EP_IN; + self->ep_out = UPEKTC_EP_OUT; + self->setup_commands = upektc_setup_commands; + self->setup_commands_len = G_N_ELEMENTS(upektc_setup_commands); + self->sum_threshold = UPEKTC_SUM_THRESHOLD; break; case UPEKTC_3001: - upekdev->ep_in = UPEKET_EP_IN; - upekdev->ep_out = UPEKET_EP_OUT; - upekdev->setup_commands = upeket_setup_commands; - upekdev->setup_commands_len = G_N_ELEMENTS(upeket_setup_commands); - upekdev->sum_threshold = UPEKET_SUM_THRESHOLD; + self->ep_in = UPEKET_EP_IN; + self->ep_out = UPEKET_EP_OUT; + self->setup_commands = upeket_setup_commands; + self->setup_commands_len = G_N_ELEMENTS(upeket_setup_commands); + self->sum_threshold = UPEKET_SUM_THRESHOLD; break; default: fp_err("Device variant %lu is not known\n", driver_data); - g_free(upekdev); - fp_dev_set_instance_data(FP_DEV(dev), NULL); - return -ENODEV; - break; + g_assert_not_reached (); + fpi_image_device_open_complete(dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + return; } - fpi_imgdev_open_complete(dev, 0); - return 0; + fpi_image_device_open_complete(dev, NULL); } -static void dev_deinit(struct fp_img_dev *dev) +static void dev_deinit(FpImageDevice *dev) { - void *user_data; - user_data = FP_INSTANCE_DATA(FP_DEV(dev)); - g_free(user_data); - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - fpi_imgdev_close_complete(dev); + GError *error = NULL; + + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), + 0, 0, &error); + fpi_image_device_close_complete(dev, error); } -static const struct usb_id id_table[] = { - { .vendor = 0x0483, .product = 0x2015, .driver_data = UPEKTC_2015 }, - { .vendor = 0x147e, .product = 0x3001, .driver_data = UPEKTC_3001 }, - { 0, 0, 0, }, +static const FpIdEntry id_table [ ] = { + { .vid = 0x0483, .pid = 0x2015, .driver_data = UPEKTC_2015 }, + { .vid = 0x147e, .pid = 0x3001, .driver_data = UPEKTC_3001 }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -struct fp_img_driver upektc_driver = { - .driver = { - .id = UPEKTC_ID, - .name = FP_COMPONENT, - .full_name = "UPEK TouchChip/Eikon Touch 300", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_PRESS, - }, - .flags = 0, - .img_height = IMAGE_HEIGHT, - .img_width = IMAGE_WIDTH, +static void fpi_device_upektc_init(FpiDeviceUpektc *self) { +} +static void fpi_device_upektc_class_init(FpiDeviceUpektcClass *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); - .bz3_threshold = 30, - .open = dev_init, - .close = dev_deinit, - .activate = dev_activate, - .deactivate = dev_deactivate, -}; + dev_class->id = "upektc"; + dev_class->full_name = "UPEK TouchChip/Eikon Touch 300"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_PRESS; + + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; + + img_class->bz3_threshold = 30; + + img_class->img_width = IMAGE_WIDTH; + img_class->img_height = IMAGE_HEIGHT; +} diff --git a/meson.build b/meson.build index c504064f..a7942ae2 100644 --- a/meson.build +++ b/meson.build @@ -52,7 +52,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603', 'vcom5s', 'synaptics', 'elan', 'uru4000'] +default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603', 'vcom5s', 'synaptics', 'elan', 'uru4000', 'upektc'] all_drivers = default_drivers + virtual_drivers From 4a95f795cb91fde33b00c2dc77b50b1a0c7caf8b Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 7 Aug 2019 15:47:47 +0200 Subject: [PATCH 48/73] upeksonly: Port upeksonly driver to the new API --- libfprint/drivers/upeksonly.c | 1047 +++++++++++++++++---------------- libfprint/drivers/upeksonly.h | 4 +- meson.build | 2 +- 3 files changed, 528 insertions(+), 525 deletions(-) diff --git a/libfprint/drivers/upeksonly.c b/libfprint/drivers/upeksonly.c index 69a79e69..a9e0f27d 100644 --- a/libfprint/drivers/upeksonly.c +++ b/libfprint/drivers/upeksonly.c @@ -44,13 +44,6 @@ enum { UPEKSONLY_1001, }; -struct img_transfer_data { - int idx; - struct fp_img_dev *dev; - gboolean flying; - gboolean cancelling; -}; - enum sonly_kill_transfers_action { NOT_KILLING = 0, @@ -73,17 +66,21 @@ enum sonly_fs { FINGER_REMOVED, }; -struct sonly_dev { +struct _FpiDeviceUpeksonly { + FpImageDevice parent; + gboolean capturing; gboolean deactivating; - uint8_t read_reg_result; + guint8 read_reg_result; int dev_model; int img_width; - fpi_ssm *loopsm; - struct libusb_transfer *img_transfer[NUM_BULK_TRANSFERS]; - struct img_transfer_data *img_transfer_data; + FpiSsm *loopsm; + + /* Do we really need multiple concurrent transfers? */ + GCancellable *img_cancellable; + GPtrArray *img_transfers; int num_flying; GSList *rows; @@ -98,12 +95,17 @@ struct sonly_dev { int last_seqnum; enum sonly_kill_transfers_action killing_transfers; - int kill_status_code; + GError *kill_error; union { - fpi_ssm *kill_ssm; - void (*kill_cb)(struct fp_img_dev *dev); + FpiSsm *kill_ssm; + void (*kill_cb)(FpImageDevice *dev); }; + + struct fpi_line_asmbl_ctx assembling_ctx; }; +G_DECLARE_FINAL_TYPE(FpiDeviceUpeksonly, fpi_device_upeksonly, FPI, + DEVICE_UPEKSONLY, FpImageDevice); +G_DEFINE_TYPE(FpiDeviceUpeksonly, fpi_device_upeksonly, FP_TYPE_IMAGE_DEVICE); /* Calculate squared standard deviation of sum of two lines */ @@ -152,136 +154,110 @@ static unsigned char upeksonly_get_pixel(struct fpi_line_asmbl_ctx *ctx, return buf[offset]; } -static struct fpi_line_asmbl_ctx assembling_ctx = { - .max_height = 1024, - .resolution = 8, - .median_filter_size = 25, - .max_search_offset = 30, - .get_deviation = upeksonly_get_deviation2, - .get_pixel = upeksonly_get_pixel, -}; - /***** IMAGE PROCESSING *****/ -static void free_img_transfers(struct sonly_dev *sdev) +static void free_img_transfers(FpiDeviceUpeksonly *sdev) { - int i; - for (i = 0; i < NUM_BULK_TRANSFERS; i++) { - struct libusb_transfer *transfer = sdev->img_transfer[i]; - if (!transfer) - continue; - - g_free(transfer->buffer); - libusb_free_transfer(transfer); - } - g_free(sdev->img_transfer_data); + g_cancellable_cancel (sdev->img_cancellable); + g_clear_object (&sdev->img_cancellable); + g_clear_pointer (&sdev->img_transfers, g_ptr_array_unref); } -static void last_transfer_killed(struct fp_img_dev *dev) +static void last_transfer_killed(FpImageDevice *dev) { - struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); - switch (sdev->killing_transfers) { + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); + switch (self->killing_transfers) { case ABORT_SSM: - fp_dbg("abort ssm error %d", sdev->kill_status_code); - fpi_ssm_mark_failed(sdev->kill_ssm, sdev->kill_status_code); + fp_dbg("abort ssm error %s", self->kill_error->message); + fpi_ssm_mark_failed(self->kill_ssm, g_steal_pointer (&self->kill_error)); return; case ITERATE_SSM: fp_dbg("iterate ssm"); - fpi_ssm_next_state(sdev->kill_ssm); + fpi_ssm_next_state(self->kill_ssm); return; case IMG_SESSION_ERROR: - fp_dbg("session error %d", sdev->kill_status_code); - fpi_imgdev_session_error(dev, sdev->kill_status_code); + fp_dbg("session error %s", self->kill_error->message); + fpi_image_device_session_error(dev, g_steal_pointer (&self->kill_error)); return; default: return; } } -static void cancel_img_transfers(struct fp_img_dev *dev) +static void cancel_img_transfers(FpImageDevice *dev) { - struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); - int i; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); - if (sdev->num_flying == 0) { + g_cancellable_cancel (self->img_cancellable); + + if (self->num_flying == 0) last_transfer_killed(dev); - return; - } - - for (i = 0; i < NUM_BULK_TRANSFERS; i++) { - struct img_transfer_data *idata = &sdev->img_transfer_data[i]; - if (!idata->flying || idata->cancelling) - continue; - fp_dbg("cancelling transfer %d", i); - int r = libusb_cancel_transfer(sdev->img_transfer[i]); - if (r < 0) - fp_dbg("cancel failed error %d", r); - idata->cancelling = TRUE; - } } -static gboolean is_capturing(struct sonly_dev *sdev) +static gboolean is_capturing(FpiDeviceUpeksonly *sdev) { return sdev->num_rows < MAX_ROWS && (sdev->finger_state != FINGER_REMOVED); } -static void handoff_img(struct fp_img_dev *dev) +static void handoff_img(FpImageDevice *dev) { - struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); - struct fp_img *img; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); + FpImage *img; - GSList *elem = sdev->rows; + GSList *elem = self->rows; if (!elem) { fp_err("no rows?"); return; } - sdev->rows = g_slist_reverse(sdev->rows); + self->rows = g_slist_reverse(self->rows); - fp_dbg("%lu rows", sdev->num_rows); - img = fpi_assemble_lines(&assembling_ctx, sdev->rows, sdev->num_rows); + fp_dbg("%lu rows", self->num_rows); + img = fpi_assemble_lines(&self->assembling_ctx, self->rows, self->num_rows); - g_slist_free_full(sdev->rows, g_free); - sdev->rows = NULL; + g_slist_free_full(self->rows, g_free); + self->rows = NULL; - fpi_imgdev_image_captured(dev, img); - fpi_imgdev_report_finger_status(dev, FALSE); + fpi_image_device_image_captured(dev, img); + fpi_image_device_report_finger_status(dev, FALSE); - sdev->killing_transfers = ITERATE_SSM; - sdev->kill_ssm = sdev->loopsm; + self->killing_transfers = ITERATE_SSM; + self->kill_ssm = self->loopsm; cancel_img_transfers(dev); } -static void row_complete(struct fp_img_dev *dev) +static void row_complete(FpImageDevice *dev) { - struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); - sdev->rowbuf_offset = -1; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); + self->rowbuf_offset = -1; - if (sdev->num_rows > 0) { - unsigned char *lastrow = sdev->rows->data; + if (self->num_rows > 0) { + unsigned char *lastrow = self->rows->data; int std_sq_dev, mean_sq_diff; - std_sq_dev = fpi_std_sq_dev(sdev->rowbuf, sdev->img_width); - mean_sq_diff = fpi_mean_sq_diff_norm(lastrow, sdev->rowbuf, sdev->img_width); + std_sq_dev = fpi_std_sq_dev(self->rowbuf, self->img_width); + mean_sq_diff = fpi_mean_sq_diff_norm(lastrow, self->rowbuf, + self->img_width); - switch (sdev->finger_state) { + switch (self->finger_state) { case AWAIT_FINGER: - if (sdev->deactivating) { - sdev->killing_transfers = ITERATE_SSM; - sdev->kill_ssm = sdev->loopsm; + if (self->deactivating) { + self->killing_transfers = ITERATE_SSM; + self->kill_ssm = self->loopsm; cancel_img_transfers(dev); } fp_dbg("std_sq_dev: %d", std_sq_dev); if (std_sq_dev > BLANK_THRESHOLD) { - sdev->num_nonblank++; + self->num_nonblank++; } else { - sdev->num_nonblank = 0; + self->num_nonblank = 0; } - if (sdev->num_nonblank > FINGER_PRESENT_THRESHOLD) { - sdev->finger_state = FINGER_DETECTED; - fpi_imgdev_report_finger_status(dev, TRUE); + if (self->num_nonblank > FINGER_PRESENT_THRESHOLD) { + self->finger_state = FINGER_DETECTED; + fpi_image_device_report_finger_status(dev, + TRUE); } else { return; } @@ -293,9 +269,9 @@ static void row_complete(struct fp_img_dev *dev) } if (std_sq_dev > BLANK_THRESHOLD) { - sdev->num_blank = 0; + self->num_blank = 0; } else { - sdev->num_blank++; + self->num_blank++; /* Don't consider the scan complete unless there's at least * MIN_ROWS recorded or very long blank read occurred. * @@ -303,66 +279,68 @@ static void row_complete(struct fp_img_dev *dev) * actual scan. Happens most commonly if scan is started * from before the first joint resulting in a gap after the initial touch. */ - if (sdev->num_blank > FINGER_REMOVED_THRESHOLD) { - sdev->finger_state = FINGER_REMOVED; - fp_dbg("detected finger removal. Blank rows: %d, Full rows: %lu", sdev->num_blank, sdev->num_rows); + if (self->num_blank > FINGER_REMOVED_THRESHOLD) { + self->finger_state = FINGER_REMOVED; + fp_dbg("detected finger removal. Blank rows: %d, Full rows: %lu", + self->num_blank, self->num_rows); handoff_img(dev); return; } } fp_dbg("mean_sq_diff: %d, std_sq_dev: %d", mean_sq_diff, std_sq_dev); - fp_dbg("num_blank: %d", sdev->num_blank); + fp_dbg("num_blank: %d", self->num_blank); if (mean_sq_diff < DIFF_THRESHOLD) { return; } } - switch (sdev->finger_state) { + switch (self->finger_state) { case AWAIT_FINGER: - if (!sdev->num_rows) { - sdev->rows = g_slist_prepend(sdev->rows, sdev->rowbuf); - sdev->num_rows++; + if (!self->num_rows) { + self->rows = g_slist_prepend(self->rows, self->rowbuf); + self->num_rows++; } else { return; } break; case FINGER_DETECTED: case FINGER_REMOVED: - sdev->rows = g_slist_prepend(sdev->rows, sdev->rowbuf); - sdev->num_rows++; + self->rows = g_slist_prepend(self->rows, self->rowbuf); + self->num_rows++; break; } - sdev->rowbuf = NULL; + self->rowbuf = NULL; - if (sdev->num_rows >= MAX_ROWS) { + if (self->num_rows >= MAX_ROWS) { fp_dbg("row limit met"); handoff_img(dev); } } /* add data to row buffer */ -static void add_to_rowbuf(struct fp_img_dev *dev, unsigned char *data, int size) +static void add_to_rowbuf(FpImageDevice *dev, unsigned char *data, int size) { - struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); - memcpy(sdev->rowbuf + sdev->rowbuf_offset, data, size); - sdev->rowbuf_offset += size; - if (sdev->rowbuf_offset >= sdev->img_width) + memcpy(self->rowbuf + self->rowbuf_offset, data, size); + self->rowbuf_offset += size; + if (self->rowbuf_offset >= self->img_width) row_complete(dev); } -static void start_new_row(struct sonly_dev *sdev, unsigned char *data, int size) +static void start_new_row(FpiDeviceUpeksonly *self, unsigned char *data, + int size) { - if (!sdev->rowbuf) - sdev->rowbuf = g_malloc(sdev->img_width); - memcpy(sdev->rowbuf, data, size); - sdev->rowbuf_offset = size; + if (!self->rowbuf) + self->rowbuf = g_malloc(self->img_width); + memcpy(self->rowbuf, data, size); + self->rowbuf_offset = size; } /* returns number of bytes left to be copied into rowbuf (capped to 62) * or -1 if we aren't capturing anything */ -static int rowbuf_remaining(struct sonly_dev *sdev) +static int rowbuf_remaining(FpiDeviceUpeksonly *sdev) { int r; @@ -375,10 +353,10 @@ static int rowbuf_remaining(struct sonly_dev *sdev) return r; } -static void handle_packet(struct fp_img_dev *dev, unsigned char *data) +static void handle_packet(FpImageDevice *dev, unsigned char *data) { - struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); - uint16_t seqnum = data[0] << 8 | data[1]; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); + guint16 seqnum = data[0] << 8 | data[1]; int abs_base_addr; int for_rowbuf; int next_row_addr; @@ -389,110 +367,128 @@ static void handle_packet(struct fp_img_dev *dev, unsigned char *data) memset (dummy_data, 204, 62); data += 2; /* skip sequence number */ - if (seqnum != sdev->last_seqnum + 1) { - if (seqnum != 0 && sdev->last_seqnum != 16383) { - int missing_data = seqnum - sdev->last_seqnum; + if (seqnum != self->last_seqnum + 1) { + if (seqnum != 0 && self->last_seqnum != 16383) { + int missing_data = seqnum - self->last_seqnum; int i; - fp_warn("lost %d packets of data between %d and %d", missing_data, sdev->last_seqnum, seqnum ); + fp_warn("lost %d packets of data between %d and %d", missing_data, + self->last_seqnum, seqnum ); /* Minimize distortions for readers that lose a lot of packets */ for (i =1; i < missing_data; i++) { - abs_base_addr = (sdev->last_seqnum + 1) * 62; + abs_base_addr = (self->last_seqnum + 1) * 62; /* If possible take the replacement data from last row */ - if (sdev->num_rows > 1) { - int row_left = sdev->img_width - sdev->rowbuf_offset; - unsigned char *last_row = g_slist_nth_data (sdev->rows, 0); + if (self->num_rows > 1) { + int row_left = self->img_width - self->rowbuf_offset; + unsigned char *last_row = g_slist_nth_data (self->rows, + 0); if (row_left >= 62) { - memcpy(dummy_data, last_row + sdev->rowbuf_offset, 62); + memcpy(dummy_data, + last_row + self->rowbuf_offset, + 62); } else { - memcpy(dummy_data, last_row + sdev->rowbuf_offset, row_left); + memcpy(dummy_data, + last_row + self->rowbuf_offset, + row_left); memcpy(dummy_data + row_left, last_row , 62 - row_left); } } - fp_warn("adding dummy input for %d, i=%d", sdev->last_seqnum + i, i); - for_rowbuf = rowbuf_remaining(sdev); + fp_warn("adding dummy input for %d, i=%d", + self->last_seqnum + i, i); + for_rowbuf = rowbuf_remaining(self); if (for_rowbuf != -1) { add_to_rowbuf(dev, dummy_data, for_rowbuf); /* row boundary */ if (for_rowbuf < 62) { - start_new_row(sdev, dummy_data + for_rowbuf, 62 - for_rowbuf); + start_new_row(self, + dummy_data + for_rowbuf, + 62 - for_rowbuf); } - } else if (abs_base_addr % sdev->img_width == 0) { - start_new_row(sdev, dummy_data, 62); + } else if (abs_base_addr % self->img_width == 0) { + start_new_row(self, dummy_data, 62); } else { /* does the data in the packet reside on a row boundary? * if so capture it */ - next_row_addr = ((abs_base_addr / sdev->img_width) + 1) * sdev->img_width; + next_row_addr = ((abs_base_addr / self->img_width) + 1) * self->img_width; diff = next_row_addr - abs_base_addr; if (diff < 62) - start_new_row(sdev, dummy_data + diff, 62 - diff); + start_new_row(self, + dummy_data + diff, + 62 - diff); } - sdev->last_seqnum = sdev->last_seqnum + 1; + self->last_seqnum = self->last_seqnum + 1; } } } - if (seqnum <= sdev->last_seqnum) { + if (seqnum <= self->last_seqnum) { fp_dbg("detected wraparound"); - sdev->wraparounds++; + self->wraparounds++; } - sdev->last_seqnum = seqnum; - seqnum += sdev->wraparounds * 16384; + self->last_seqnum = seqnum; + seqnum += self->wraparounds * 16384; abs_base_addr = seqnum * 62; /* are we already capturing a row? if so append the data to the * row buffer */ - for_rowbuf = rowbuf_remaining(sdev); + for_rowbuf = rowbuf_remaining(self); if (for_rowbuf != -1) { add_to_rowbuf(dev, data, for_rowbuf); /*row boundary*/ if (for_rowbuf < 62) { - start_new_row(sdev, data + for_rowbuf, 62 - for_rowbuf); + start_new_row(self, data + for_rowbuf, + 62 - for_rowbuf); } return; } /* does the packet START on a boundary? if so we want it in full */ - if (abs_base_addr % sdev->img_width == 0) { - start_new_row(sdev, data, 62); + if (abs_base_addr % self->img_width == 0) { + start_new_row(self, data, 62); return; } /* does the data in the packet reside on a row boundary? * if so capture it */ - next_row_addr = ((abs_base_addr / sdev->img_width) + 1) * sdev->img_width; + next_row_addr = ((abs_base_addr / self->img_width) + 1) * self->img_width; diff = next_row_addr - abs_base_addr; if (diff < 62) - start_new_row(sdev, data + diff, 62 - diff); + start_new_row(self, data + diff, 62 - diff); } -static void img_data_cb(struct libusb_transfer *transfer) +static void img_data_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - struct img_transfer_data *idata = transfer->user_data; - struct fp_img_dev *dev = idata->dev; - struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); int i; - idata->flying = FALSE; - idata->cancelling = FALSE; - sdev->num_flying--; + self->num_flying--; - if (sdev->killing_transfers) { - if (sdev->num_flying == 0) + if (self->killing_transfers) { + if (self->num_flying == 0) last_transfer_killed(dev); /* don't care about error or success if we're terminating */ + g_clear_error (&error); return; } - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fp_warn("bad status %d, terminating session", transfer->status); - sdev->killing_transfers = IMG_SESSION_ERROR; - sdev->kill_status_code = transfer->status; + if (error) { + fp_warn("bad status %s, terminating session", error->message); + self->killing_transfers = IMG_SESSION_ERROR; + + /* This cannot really happen, but just in case. */ + if (!self->kill_error) + self->kill_error = error; + else + g_error_free (error); + cancel_img_transfers(dev); + return; } /* there are 64 packets in the transfer buffer @@ -501,75 +497,48 @@ static void img_data_cb(struct libusb_transfer *transfer) * then there are 62 bytes for image data */ for (i = 0; i < 4096; i += 64) { - if (!is_capturing(sdev)) + if (!is_capturing(self)) return; handle_packet(dev, transfer->buffer + i); } - if (is_capturing(sdev)) { - int r = libusb_submit_transfer(transfer); - if (r < 0) { - fp_warn("failed resubmit, error %d", r); - sdev->killing_transfers = IMG_SESSION_ERROR; - sdev->kill_status_code = r; - cancel_img_transfers(dev); - return; - } - sdev->num_flying++; - idata->flying = TRUE; + if (is_capturing(self)) { + fpi_usb_transfer_submit (transfer, + 0, + self->img_cancellable, + img_data_cb, + user_data); + self->num_flying++; } } /***** STATE MACHINE HELPERS *****/ struct write_regs_data { - fpi_ssm *ssm; - struct libusb_transfer *transfer; + FpDevice *dev; + FpiSsm *ssm; + FpiUsbTransfer *transfer; const struct sonly_regwrite *regs; size_t num_regs; size_t regs_written; }; -static void write_regs_finished(struct write_regs_data *wrdata, int result) +static void write_regs_finished(struct write_regs_data *wrdata, GError *error) { - g_free(wrdata->transfer->buffer); - libusb_free_transfer(wrdata->transfer); - if (result == 0) + if (!error) fpi_ssm_next_state(wrdata->ssm); else - fpi_ssm_mark_failed(wrdata->ssm, result); - g_free(wrdata); + fpi_ssm_mark_failed(wrdata->ssm, error); } +static void write_regs_iterate(struct write_regs_data *wrdata); -static void write_regs_iterate(struct write_regs_data *wrdata) +static void write_regs_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - struct libusb_control_setup *setup; - const struct sonly_regwrite *regwrite; - int r; - - if (wrdata->regs_written >= wrdata->num_regs) { - write_regs_finished(wrdata, 0); - return; - } - - regwrite = &wrdata->regs[wrdata->regs_written]; - - fp_dbg("set %02x=%02x", regwrite->reg, regwrite->value); - setup = libusb_control_transfer_get_setup(wrdata->transfer); - setup->wIndex = regwrite->reg; - wrdata->transfer->buffer[LIBUSB_CONTROL_SETUP_SIZE] = regwrite->value; - - r = libusb_submit_transfer(wrdata->transfer); - if (r < 0) - write_regs_finished(wrdata, r); -} - -static void write_regs_cb(struct libusb_transfer *transfer) -{ - struct write_regs_data *wrdata = transfer->user_data; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - write_regs_finished(wrdata, transfer->status); + struct write_regs_data *wrdata = user_data; + if (error) { + write_regs_finished(wrdata, error); return; } @@ -577,122 +546,140 @@ static void write_regs_cb(struct libusb_transfer *transfer) write_regs_iterate(wrdata); } +static void write_regs_iterate(struct write_regs_data *wrdata) +{ + FpiUsbTransfer *transfer; + const struct sonly_regwrite *regwrite; + + if (wrdata->regs_written >= wrdata->num_regs) { + write_regs_finished(wrdata, NULL); + return; + } + + regwrite = &wrdata->regs[wrdata->regs_written]; + fp_dbg("set %02x=%02x", regwrite->reg, regwrite->value); + + transfer = fpi_usb_transfer_new(wrdata->dev); + fpi_usb_transfer_fill_control(transfer, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0x0c, + 0, + regwrite->reg, + 1); + transfer->short_is_error = TRUE; + transfer->ssm = wrdata->ssm; + fpi_usb_transfer_submit(transfer, CTRL_TIMEOUT, NULL, write_regs_cb, NULL); + fpi_usb_transfer_unref(transfer); + + transfer->buffer[0] = regwrite->value; +} + static void -sm_write_regs(fpi_ssm *ssm, - struct fp_dev *dev, +sm_write_regs(FpiSsm *ssm, + FpDevice *dev, const struct sonly_regwrite *regs, size_t num_regs) { struct write_regs_data *wrdata = g_malloc(sizeof(*wrdata)); - unsigned char *data; - - wrdata->transfer = fpi_usb_alloc(); - data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1); - libusb_fill_control_setup(data, 0x40, 0x0c, 0, 0, 1); - libusb_fill_control_transfer(wrdata->transfer, - fpi_dev_get_usb_dev(dev), data, - write_regs_cb, wrdata, CTRL_TIMEOUT); - wrdata->transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK; wrdata->ssm = ssm; wrdata->regs = regs; wrdata->num_regs = num_regs; wrdata->regs_written = 0; + wrdata->dev = dev; + write_regs_iterate(wrdata); } -static void sm_write_reg_cb(struct libusb_transfer *transfer) +static void sm_write_reg_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - g_free(transfer->buffer); - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - fpi_ssm_mark_failed(ssm, -EIO); + if (error) + fpi_ssm_mark_failed(transfer->ssm, error); else - fpi_ssm_next_state(ssm); + fpi_ssm_next_state(transfer->ssm); } static void -sm_write_reg(fpi_ssm *ssm, - struct fp_img_dev *dev, - uint8_t reg, - uint8_t value) +sm_write_reg(FpiSsm *ssm, + FpImageDevice *dev, + guint8 reg, + guint8 value) { - struct libusb_transfer *transfer = fpi_usb_alloc(); - unsigned char *data; - int r; + FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE (dev)); fp_dbg("set %02x=%02x", reg, value); - data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1); - libusb_fill_control_setup(data, 0x40, 0x0c, 0, reg, 1); - libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), - data, sm_write_reg_cb, - ssm, CTRL_TIMEOUT); + fpi_usb_transfer_fill_control(transfer, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0x0c, + 0, + reg, + 1); + transfer->short_is_error = TRUE; + transfer->ssm = ssm; + fpi_usb_transfer_submit(transfer, CTRL_TIMEOUT, NULL, sm_write_reg_cb, NULL); + fpi_usb_transfer_unref(transfer); - data[LIBUSB_CONTROL_SETUP_SIZE] = value; - transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK | - LIBUSB_TRANSFER_FREE_TRANSFER; - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + transfer->buffer[0] = value; } -static void sm_read_reg_cb(struct libusb_transfer *transfer) +static void sm_read_reg_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpImageDevice *dev = FP_IMAGE_DEVICE(device); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fpi_ssm_mark_failed(ssm, -EIO); + if (error) { + fpi_ssm_mark_failed(transfer->ssm, error); } else { - sdev->read_reg_result = libusb_control_transfer_get_data(transfer)[0]; - fp_dbg("read reg result = %02x", sdev->read_reg_result); - fpi_ssm_next_state(ssm); + self->read_reg_result = transfer->buffer[0]; + fp_dbg("read reg result = %02x", self->read_reg_result); + fpi_ssm_next_state(transfer->ssm); } g_free(transfer->buffer); } static void -sm_read_reg(fpi_ssm *ssm, - struct fp_img_dev *dev, - uint8_t reg) +sm_read_reg(FpiSsm *ssm, + FpImageDevice *dev, + guint8 reg) { - struct libusb_transfer *transfer = fpi_usb_alloc(); - unsigned char *data; - int r; + FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); fp_dbg("read reg %02x", reg); - data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 8); - libusb_fill_control_setup(data, 0xc0, 0x0c, 0, reg, 8); - libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), - data, sm_read_reg_cb, - ssm, CTRL_TIMEOUT); - transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK | - LIBUSB_TRANSFER_FREE_TRANSFER; - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + fpi_usb_transfer_fill_control(transfer, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0x0c, + 0, + reg, + 8); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit(transfer, + CTRL_TIMEOUT, + NULL, + sm_read_reg_cb, + NULL); + fpi_usb_transfer_unref(transfer); } -static void sm_await_intr_cb(struct libusb_transfer *transfer) +static void sm_await_intr_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm); - struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpImageDevice *dev = FP_IMAGE_DEVICE(device); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { + if (error) { g_free(transfer->buffer); - fpi_ssm_mark_failed(ssm, transfer->status); + fpi_ssm_mark_failed(transfer->ssm, error); return; } @@ -701,33 +688,30 @@ static void sm_await_intr_cb(struct libusb_transfer *transfer) transfer->buffer[2], transfer->buffer[3]); g_free(transfer->buffer); - sdev->finger_state = FINGER_DETECTED; - fpi_imgdev_report_finger_status(dev, TRUE); - fpi_ssm_next_state(ssm); + self->finger_state = FINGER_DETECTED; + fpi_image_device_report_finger_status(dev, TRUE); + fpi_ssm_next_state(transfer->ssm); } static void -sm_await_intr(fpi_ssm *ssm, - struct fp_img_dev *dev) +sm_await_intr(FpiSsm *ssm, + FpImageDevice *dev) { - struct libusb_transfer *transfer = fpi_usb_alloc(); - unsigned char *data; - int r; + FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); G_DEBUG_HERE(); - data = g_malloc(4); - libusb_fill_interrupt_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), - 0x83, data, 4, - sm_await_intr_cb, ssm, 0); - transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK | - LIBUSB_TRANSFER_FREE_TRANSFER; - r = libusb_submit_transfer(transfer); - if (r < 0) { - libusb_free_transfer(transfer); - g_free(data); - fpi_ssm_mark_failed(ssm, r); - } + fpi_usb_transfer_fill_interrupt (transfer, 0x83, 4); + transfer->short_is_error = TRUE; + transfer->ssm = ssm; + + /* NOTE: This was changed to be cancellable with the version 2 port! */ + fpi_usb_transfer_submit (transfer, + 0, + fpi_device_get_cancellable (FP_DEVICE (dev)), + sm_await_intr_cb, + NULL); + fpi_usb_transfer_unref (transfer); } /***** AWAIT FINGER *****/ @@ -752,10 +736,11 @@ enum awfsm_1000_states { AWFSM_1000_NUM_STATES, }; -static void awfsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void awfsm_2016_run_state(FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - struct fp_img_dev *dev = user_data; - struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case AWFSM_2016_WRITEV_1: @@ -765,7 +750,7 @@ static void awfsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_d sm_read_reg(ssm, dev, 0x01); break; case AWFSM_2016_WRITE_01: - if (sdev->read_reg_result != 0xc6) + if (self->read_reg_result != 0xc6) sm_write_reg(ssm, dev, 0x01, 0x46); else sm_write_reg(ssm, dev, 0x01, 0xc6); @@ -777,7 +762,7 @@ static void awfsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_d sm_read_reg(ssm, dev, 0x13); break; case AWFSM_2016_WRITE_13: - if (sdev->read_reg_result != 0x45) + if (self->read_reg_result != 0x45) sm_write_reg(ssm, dev, 0x13, 0x05); else sm_write_reg(ssm, dev, 0x13, 0x45); @@ -789,9 +774,9 @@ static void awfsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_d sm_read_reg(ssm, dev, 0x07); break; case AWFSM_2016_WRITE_07: - if (sdev->read_reg_result != 0x10 && sdev->read_reg_result != 0x90) - fp_warn("odd reg7 value %x", sdev->read_reg_result); - sm_write_reg(ssm, dev, 0x07, sdev->read_reg_result); + if (self->read_reg_result != 0x10 && self->read_reg_result != 0x90) + fp_warn("odd reg7 value %x", self->read_reg_result); + sm_write_reg(ssm, dev, 0x07, self->read_reg_result); break; case AWFSM_2016_WRITEV_4: sm_write_regs(ssm, _dev, awfsm_2016_writev_4, G_N_ELEMENTS(awfsm_2016_writev_4)); @@ -799,7 +784,8 @@ static void awfsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_d } } -static void awfsm_1000_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void awfsm_1000_run_state(FpiSsm *ssm, FpDevice *_dev, + void *user_data) { switch (fpi_ssm_get_cur_state(ssm)) { case AWFSM_1000_WRITEV_1: @@ -841,52 +827,44 @@ enum capsm_1001_states { }; static void -capsm_fire_bulk(fpi_ssm *ssm, - struct fp_dev *_dev) +capsm_fire_bulk(FpiSsm *ssm, + FpDevice *dev) { - struct fp_img_dev *dev = FP_IMG_DEV(_dev); - struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); int i; - for (i = 0; i < NUM_BULK_TRANSFERS; i++) { - int r = libusb_submit_transfer(sdev->img_transfer[i]); - if (r < 0) { - if (i == 0) { - /* first one failed: easy peasy */ - fpi_ssm_mark_failed(ssm, r); - return; - } - /* cancel all flying transfers, and request that the SSM - * gets aborted when the last transfer has dropped out of - * the sky */ - sdev->killing_transfers = ABORT_SSM; - sdev->kill_ssm = ssm; - sdev->kill_status_code = r; - cancel_img_transfers(dev); - return; - } - sdev->img_transfer_data[i].flying = TRUE; - sdev->num_flying++; + g_assert (self->capturing == FALSE); + + g_clear_object (&self->img_cancellable); + self->img_cancellable = g_cancellable_new (); + for (i = 0; i < self->img_transfers->len; i++) { + fpi_usb_transfer_submit(g_ptr_array_index (self->img_transfers, i), + 0, + self->img_cancellable, + img_data_cb, + NULL); + self->num_flying++; } - sdev->capturing = TRUE; + self->capturing = TRUE; fpi_ssm_next_state(ssm); } -static void capsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capsm_2016_run_state(FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - struct fp_img_dev *dev = user_data; - struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case CAPSM_2016_INIT: - sdev->rowbuf_offset = -1; - sdev->num_rows = 0; - sdev->wraparounds = -1; - sdev->num_blank = 0; - sdev->num_nonblank = 0; - sdev->finger_state = FINGER_DETECTED; - sdev->last_seqnum = 16383; - sdev->killing_transfers = 0; + self->rowbuf_offset = -1; + self->num_rows = 0; + self->wraparounds = -1; + self->num_blank = 0; + self->num_nonblank = 0; + self->finger_state = FINGER_DETECTED; + self->last_seqnum = 16383; + self->killing_transfers = 0; fpi_ssm_next_state(ssm); break; case CAPSM_2016_WRITE_15: @@ -904,20 +882,21 @@ static void capsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_d } } -static void capsm_1000_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capsm_1000_run_state(FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case CAPSM_1000_INIT: - sdev->rowbuf_offset = -1; - sdev->num_rows = 0; - sdev->wraparounds = -1; - sdev->num_blank = 0; - sdev->num_nonblank = 0; - sdev->finger_state = FINGER_DETECTED; - sdev->last_seqnum = 16383; - sdev->killing_transfers = 0; + self->rowbuf_offset = -1; + self->num_rows = 0; + self->wraparounds = -1; + self->num_blank = 0; + self->num_nonblank = 0; + self->finger_state = FINGER_DETECTED; + self->last_seqnum = 16383; + self->killing_transfers = 0; fpi_ssm_next_state(ssm); break; case CAPSM_1000_FIRE_BULK: ; @@ -929,20 +908,21 @@ static void capsm_1000_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_d } } -static void capsm_1001_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void capsm_1001_run_state(FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case CAPSM_1001_INIT: - sdev->rowbuf_offset = -1; - sdev->num_rows = 0; - sdev->wraparounds = -1; - sdev->num_blank = 0; - sdev->num_nonblank = 0; - sdev->finger_state = AWAIT_FINGER; - sdev->last_seqnum = 16383; - sdev->killing_transfers = 0; + self->rowbuf_offset = -1; + self->num_rows = 0; + self->wraparounds = -1; + self->num_blank = 0; + self->num_nonblank = 0; + self->finger_state = AWAIT_FINGER; + self->last_seqnum = 16383; + self->killing_transfers = 0; fpi_ssm_next_state(ssm); break; case CAPSM_1001_FIRE_BULK: ; @@ -983,7 +963,8 @@ enum deinitsm_1001_states { DEINITSM_1001_NUM_STATES, }; -static void deinitsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void deinitsm_2016_run_state(FpiSsm *ssm, FpDevice *_dev, + void *user_data) { switch (fpi_ssm_get_cur_state(ssm)) { case DEINITSM_2016_WRITEV: @@ -992,7 +973,8 @@ static void deinitsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *use } } -static void deinitsm_1000_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void deinitsm_1000_run_state(FpiSsm *ssm, FpDevice *_dev, + void *user_data) { switch (fpi_ssm_get_cur_state(ssm)) { case DEINITSM_1000_WRITEV: @@ -1001,7 +983,8 @@ static void deinitsm_1000_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *use } } -static void deinitsm_1001_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void deinitsm_1001_run_state(FpiSsm *ssm, FpDevice *_dev, + void *user_data) { switch (fpi_ssm_get_cur_state(ssm)) { case DEINITSM_1001_WRITEV: @@ -1037,10 +1020,11 @@ enum initsm_1001_states { INITSM_1001_NUM_STATES, }; -static void initsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void initsm_2016_run_state(FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - struct fp_img_dev *dev = user_data; - struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case INITSM_2016_WRITEV_1: @@ -1050,13 +1034,13 @@ static void initsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_ sm_read_reg(ssm, dev, 0x09); break; case INITSM_2016_WRITE_09: - sm_write_reg(ssm, dev, 0x09, sdev->read_reg_result & ~0x08); + sm_write_reg(ssm, dev, 0x09, self->read_reg_result & ~0x08); break; case INITSM_2016_READ_13: sm_read_reg(ssm, dev, 0x13); break; case INITSM_2016_WRITE_13: - sm_write_reg(ssm, dev, 0x13, sdev->read_reg_result & ~0x10); + sm_write_reg(ssm, dev, 0x13, self->read_reg_result & ~0x10); break; case INITSM_2016_WRITE_04: sm_write_reg(ssm, dev, 0x04, 0x00); @@ -1067,7 +1051,8 @@ static void initsm_2016_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_ } } -static void initsm_1000_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void initsm_1000_run_state(FpiSsm *ssm, FpDevice *_dev, + void *user_data) { switch (fpi_ssm_get_cur_state(ssm)) { case INITSM_1000_WRITEV_1: @@ -1076,7 +1061,8 @@ static void initsm_1000_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_ } } -static void initsm_1001_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void initsm_1001_run_state(FpiSsm *ssm, FpDevice *_dev, + void *user_data) { switch (fpi_ssm_get_cur_state(ssm)) { case INITSM_1001_WRITEV_1: @@ -1109,34 +1095,38 @@ enum loopsm_states { LOOPSM_NUM_STATES, }; -static void loopsm_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void loopsm_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct fp_img_dev *dev = user_data; - struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(_dev); switch (fpi_ssm_get_cur_state(ssm)) { case LOOPSM_RUN_AWFSM: ; - switch (sdev->dev_model) { + switch (self->dev_model) { case UPEKSONLY_1001: - if (sdev->deactivating) { + if (self->deactivating) { fpi_ssm_mark_completed(ssm); } else { fpi_ssm_next_state(ssm); } break; default: - if (sdev->deactivating) { + if (self->deactivating) { fpi_ssm_mark_completed(ssm); } else { - fpi_ssm *awfsm = NULL; - switch (sdev->dev_model) { + FpiSsm *awfsm = NULL; + switch (self->dev_model) { case UPEKSONLY_2016: - awfsm = fpi_ssm_new(FP_DEV(dev), awfsm_2016_run_state, - AWFSM_2016_NUM_STATES, dev); + awfsm = fpi_ssm_new(FP_DEVICE(dev), + awfsm_2016_run_state, + AWFSM_2016_NUM_STATES, + dev); break; case UPEKSONLY_1000: - awfsm = fpi_ssm_new(FP_DEV(dev), awfsm_1000_run_state, - AWFSM_1000_NUM_STATES, dev); + awfsm = fpi_ssm_new(FP_DEVICE(dev), + awfsm_1000_run_state, + AWFSM_1000_NUM_STATES, + dev); break; } fpi_ssm_start_subsm(ssm, awfsm); @@ -1145,7 +1135,7 @@ static void loopsm_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) } break; case LOOPSM_AWAIT_FINGER: - switch (sdev->dev_model) { + switch (self->dev_model) { case UPEKSONLY_1001: fpi_ssm_next_state(ssm); break; @@ -1155,19 +1145,22 @@ static void loopsm_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) } break; case LOOPSM_RUN_CAPSM: ; - fpi_ssm *capsm = NULL; - switch (sdev->dev_model) { + FpiSsm *capsm = NULL; + switch (self->dev_model) { case UPEKSONLY_2016: - capsm = fpi_ssm_new(FP_DEV(dev), capsm_2016_run_state, - CAPSM_2016_NUM_STATES, dev); + capsm = fpi_ssm_new(FP_DEVICE(dev), + capsm_2016_run_state, + CAPSM_2016_NUM_STATES, dev); break; case UPEKSONLY_1000: - capsm = fpi_ssm_new(FP_DEV(dev), capsm_1000_run_state, - CAPSM_1000_NUM_STATES, dev); + capsm = fpi_ssm_new(FP_DEVICE(dev), + capsm_1000_run_state, + CAPSM_1000_NUM_STATES, dev); break; case UPEKSONLY_1001: - capsm = fpi_ssm_new(FP_DEV(dev), capsm_1001_run_state, - CAPSM_1001_NUM_STATES, dev); + capsm = fpi_ssm_new(FP_DEVICE(dev), + capsm_1001_run_state, + CAPSM_1001_NUM_STATES, dev); break; } fpi_ssm_start_subsm(ssm, capsm); @@ -1175,22 +1168,25 @@ static void loopsm_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) case LOOPSM_CAPTURE: break; case LOOPSM_RUN_DEINITSM: ; - fpi_ssm *deinitsm = NULL; - switch (sdev->dev_model) { + FpiSsm *deinitsm = NULL; + switch (self->dev_model) { case UPEKSONLY_2016: - deinitsm = fpi_ssm_new(FP_DEV(dev), deinitsm_2016_run_state, - DEINITSM_2016_NUM_STATES, dev); + deinitsm = fpi_ssm_new(FP_DEVICE(dev), + deinitsm_2016_run_state, + DEINITSM_2016_NUM_STATES, dev); break; case UPEKSONLY_1000: - deinitsm = fpi_ssm_new(FP_DEV(dev), deinitsm_1000_run_state, - DEINITSM_1000_NUM_STATES, dev); + deinitsm = fpi_ssm_new(FP_DEVICE(dev), + deinitsm_1000_run_state, + DEINITSM_1000_NUM_STATES, dev); break; case UPEKSONLY_1001: - deinitsm = fpi_ssm_new(FP_DEV(dev), deinitsm_1001_run_state, - DEINITSM_1001_NUM_STATES, dev); + deinitsm = fpi_ssm_new(FP_DEVICE(dev), + deinitsm_1001_run_state, + DEINITSM_1001_NUM_STATES, dev); break; } - sdev->capturing = FALSE; + self->capturing = FALSE; fpi_ssm_start_subsm(ssm, deinitsm); break; case LOOPSM_FINAL: @@ -1202,206 +1198,213 @@ static void loopsm_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) /***** DRIVER STUFF *****/ -static void deactivate_done(struct fp_img_dev *dev) +static void deactivate_done(FpImageDevice *dev, GError *error) { - struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); G_DEBUG_HERE(); - free_img_transfers(sdev); - g_free(sdev->rowbuf); - sdev->rowbuf = NULL; + free_img_transfers(self); + g_free(self->rowbuf); + self->rowbuf = NULL; - if (sdev->rows) { - g_slist_foreach(sdev->rows, (GFunc) g_free, NULL); - sdev->rows = NULL; - } + g_slist_free_full (self->rows, g_free); + self->rows = NULL; - fpi_imgdev_deactivate_complete(dev); + fpi_image_device_deactivate_complete(dev, error); } -static void dev_deactivate(struct fp_img_dev *dev) +static void dev_deactivate(FpImageDevice *dev) { - struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); - if (!sdev->capturing) { - deactivate_done(dev); + if (!self->capturing) { + deactivate_done(dev, NULL); return; } - sdev->deactivating = TRUE; - sdev->killing_transfers = ITERATE_SSM; - sdev->kill_ssm = sdev->loopsm; + self->deactivating = TRUE; + self->killing_transfers = ITERATE_SSM; + self->kill_ssm = self->loopsm; cancel_img_transfers(dev); } -static void loopsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void loopsm_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, GError *error) { - struct fp_img_dev *dev = user_data; - struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); - int r = fpi_ssm_get_error(ssm); + FpImageDevice *dev = user_data; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(_dev); fpi_ssm_free(ssm); - if (sdev->deactivating) { - deactivate_done(dev); + if (self->deactivating) { + deactivate_done(dev, error); return; } - if (r) { - fpi_imgdev_session_error(dev, r); + if (error) { + fpi_image_device_session_error(dev, error); return; } } -static void initsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data) +static void initsm_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - struct fp_img_dev *dev = user_data; - struct sonly_dev *sdev = FP_INSTANCE_DATA(_dev); - int r = fpi_ssm_get_error(ssm); + FpImageDevice *dev = user_data; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(_dev); fpi_ssm_free(ssm); - fpi_imgdev_activate_complete(dev, r); - if (r != 0) + fpi_image_device_activate_complete(dev, error); + if (error) return; - sdev->loopsm = fpi_ssm_new(FP_DEV(dev), loopsm_run_state, LOOPSM_NUM_STATES, dev); - fpi_ssm_start(sdev->loopsm, loopsm_complete); + self->loopsm = fpi_ssm_new(FP_DEVICE(dev), loopsm_run_state, + LOOPSM_NUM_STATES, dev); + fpi_ssm_start(self->loopsm, loopsm_complete); } -static int dev_activate(struct fp_img_dev *dev) +static void dev_activate(FpImageDevice *dev) { - struct sonly_dev *sdev = FP_INSTANCE_DATA(FP_DEV(dev)); - fpi_ssm *ssm = NULL; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); + FpiSsm *ssm = NULL; int i; - sdev->deactivating = FALSE; - sdev->capturing = FALSE; + self->deactivating = FALSE; + self->capturing = FALSE; - memset(sdev->img_transfer, 0, - NUM_BULK_TRANSFERS * sizeof(struct libusb_transfer *)); - sdev->img_transfer_data = - g_malloc0(sizeof(struct img_transfer_data) * NUM_BULK_TRANSFERS); - sdev->num_flying = 0; - for (i = 0; i < NUM_BULK_TRANSFERS; i++) { - unsigned char *data; - sdev->img_transfer[i] = fpi_usb_alloc(); - sdev->img_transfer_data[i].idx = i; - sdev->img_transfer_data[i].dev = dev; - data = g_malloc(4096); - libusb_fill_bulk_transfer(sdev->img_transfer[i], fpi_dev_get_usb_dev(FP_DEV(dev)), - 0x81, data, - 4096, img_data_cb, &sdev->img_transfer_data[i], 0); + self->img_transfers = g_ptr_array_new_full(NUM_BULK_TRANSFERS, (GDestroyNotify) fpi_usb_transfer_unref); + self->num_flying = 0; + + for (i = 0; i < self->img_transfers->len; i++) { + FpiUsbTransfer *transfer; + + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + fpi_usb_transfer_fill_bulk (transfer, 0x81, 4096); + + g_ptr_array_add (self->img_transfers, transfer); } - switch (sdev->dev_model) { + switch (self->dev_model) { case UPEKSONLY_2016: - ssm = fpi_ssm_new(FP_DEV(dev), initsm_2016_run_state, INITSM_2016_NUM_STATES, dev); + ssm = fpi_ssm_new(FP_DEVICE(dev), initsm_2016_run_state, + INITSM_2016_NUM_STATES, dev); break; case UPEKSONLY_1000: - ssm = fpi_ssm_new(FP_DEV(dev), initsm_1000_run_state, INITSM_1000_NUM_STATES, dev); + ssm = fpi_ssm_new(FP_DEVICE(dev), initsm_1000_run_state, + INITSM_1000_NUM_STATES, dev); break; case UPEKSONLY_1001: - ssm = fpi_ssm_new(FP_DEV(dev), initsm_1001_run_state, INITSM_1001_NUM_STATES, dev); + ssm = fpi_ssm_new(FP_DEVICE(dev), initsm_1001_run_state, + INITSM_1001_NUM_STATES, dev); break; } fpi_ssm_start(ssm, initsm_complete); - return 0; } -static int dev_init(struct fp_img_dev *dev, unsigned long driver_data); +static void dev_init(FpImageDevice *dev); -static void dev_deinit(struct fp_img_dev *dev) +static void dev_deinit(FpImageDevice *dev) { - void *user_data; - user_data = FP_INSTANCE_DATA(FP_DEV(dev)); - g_free(user_data); - libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - fpi_imgdev_close_complete(dev); + GError *error = NULL; + + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), + 0, 0, &error); + fpi_image_device_close_complete(dev, error); } -static int dev_discover(struct libusb_device_descriptor *dsc, uint32_t *devtype) +static gint dev_discover(GUsbDevice *usb_device) { - if (dsc->idProduct == 0x2016) { - if (dsc->bcdDevice == 1) /* Revision 1 is what we're interested in */ + guint16 pid = g_usb_device_get_pid (usb_device); + guint16 bcd = g_usb_device_get_release (usb_device); + + if (pid == 0x2016) { + if (bcd == 1) /* Revision 1 is what we're interested in */ return 1; } - if (dsc->idProduct == 0x1000) { - if (dsc->bcdDevice == 0x0033) /* Looking for revision 0.33 */ + if (pid == 0x1000) { + if (bcd == 0x0033) /* Looking for revision 0.33 */ return 1; } - if (dsc->idProduct == 0x1001) + if (pid == 0x1001) return 1; return 0; } -static const struct usb_id id_table[] = { - { .vendor = 0x147e, .product = 0x2016, .driver_data = UPEKSONLY_2016 }, - { .vendor = 0x147e, .product = 0x1000, .driver_data = UPEKSONLY_1000 }, - { .vendor = 0x147e, .product = 0x1001, .driver_data = UPEKSONLY_1001 }, - { 0, 0, 0, }, +static const FpIdEntry id_table [ ] = { + { .vid = 0x147e, .pid = 0x2016, .driver_data = UPEKSONLY_2016 }, + { .vid = 0x147e, .pid = 0x1000, .driver_data = UPEKSONLY_1000 }, + { .vid = 0x147e, .pid = 0x1001, .driver_data = UPEKSONLY_1001 }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -struct fp_img_driver upeksonly_driver = { - .driver = { - .id = UPEKSONLY_ID, - .name = FP_COMPONENT, - .full_name = "UPEK TouchStrip Sensor-Only", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_SWIPE, - .discover = dev_discover, - }, - .flags = 0, - .img_width = -1, - .img_height = -1, +static void fpi_device_upeksonly_init(FpiDeviceUpeksonly *self) { +} +static void fpi_device_upeksonly_class_init(FpiDeviceUpeksonlyClass *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); - .open = dev_init, - .close = dev_deinit, - .activate = dev_activate, - .deactivate = dev_deactivate, -}; + dev_class->id = "upeksonly"; + dev_class->full_name = "UPEK TouchStrip Sensor-Only"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; -static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) + dev_class->usb_discover = dev_discover; + + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; + + img_class->img_width = -1; + img_class->img_height = -1; +} + +static void dev_init(FpImageDevice *dev) { - int r; - struct sonly_dev *sdev; + GError *error = NULL; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev); - r = libusb_set_configuration(fpi_dev_get_usb_dev(FP_DEV(dev)), 1); - if (r < 0) { + if (!g_usb_device_set_configuration (fpi_device_get_usb_device(FP_DEVICE(dev)), 1, &error)) { fp_err("could not set configuration 1"); - return r; + fpi_image_device_open_complete(dev, error); } - r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0); - if (r < 0) { - fp_err("could not claim interface 0: %s", libusb_error_name(r)); - return r; + if (!g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error)) { + fpi_image_device_open_complete(dev, error); + return; } - sdev = g_malloc0(sizeof(struct sonly_dev)); - fp_dev_set_instance_data(FP_DEV(dev), sdev); - sdev->dev_model = (int)driver_data; - switch (driver_data) { + self->assembling_ctx.max_height = 1024; + self->assembling_ctx.resolution = 8; + self->assembling_ctx.median_filter_size = 25; + self->assembling_ctx.max_search_offset = 30; + self->assembling_ctx.get_deviation = upeksonly_get_deviation2; + self->assembling_ctx.get_pixel = upeksonly_get_pixel; + + self = FPI_DEVICE_UPEKSONLY(dev); + self->dev_model = (int)fpi_device_get_driver_data (FP_DEVICE (dev)); + switch (self->dev_model) { case UPEKSONLY_1000: - sdev->img_width = IMG_WIDTH_1000; - upeksonly_driver.img_width = IMG_WIDTH_1000; - assembling_ctx.line_width = IMG_WIDTH_1000; + self->img_width = IMG_WIDTH_1000; + self->assembling_ctx.line_width = IMG_WIDTH_1000; break; case UPEKSONLY_1001: - sdev->img_width = IMG_WIDTH_1001; - upeksonly_driver.img_width = IMG_WIDTH_1001; - upeksonly_driver.bz3_threshold = 25; - assembling_ctx.line_width = IMG_WIDTH_1001; + self->img_width = IMG_WIDTH_1001; + self->assembling_ctx.line_width = IMG_WIDTH_1001; + + /* The sensor resolution is too low for the normal threshold. */ + fpi_image_device_set_bz3_threshold (dev, 25); break; case UPEKSONLY_2016: - sdev->img_width = IMG_WIDTH_2016; - upeksonly_driver.img_width = IMG_WIDTH_2016; - assembling_ctx.line_width = IMG_WIDTH_2016; + self->img_width = IMG_WIDTH_2016; + self->assembling_ctx.line_width = IMG_WIDTH_2016; break; + default: + g_assert_not_reached (); } - fpi_imgdev_open_complete(dev, 0); - return 0; + fpi_image_device_open_complete(dev, NULL); } diff --git a/libfprint/drivers/upeksonly.h b/libfprint/drivers/upeksonly.h index 4a3f72ba..cd48a320 100644 --- a/libfprint/drivers/upeksonly.h +++ b/libfprint/drivers/upeksonly.h @@ -28,8 +28,8 @@ #define IMG_WIDTH_1001 216 struct sonly_regwrite { - uint8_t reg; - uint8_t value; + guint8 reg; + guint8 value; }; /***** AWAIT FINGER *****/ diff --git a/meson.build b/meson.build index a7942ae2..17f3669b 100644 --- a/meson.build +++ b/meson.build @@ -52,7 +52,7 @@ mathlib_dep = cc.find_library('m', required: false) drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] #default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603', 'vcom5s', 'synaptics', 'elan', 'uru4000', 'upektc'] +default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603', 'vcom5s', 'synaptics', 'elan', 'uru4000', 'upektc', 'upeksonly'] all_drivers = default_drivers + virtual_drivers From e372311afe47baa3309fb8fb9c59a9084808e95a Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 8 Aug 2019 22:52:13 +0200 Subject: [PATCH 49/73] upekts: Port upekts driver to new API --- libfprint/drivers/upekts.c | 1345 +++++++++++++++++------------------- meson.build | 3 +- 2 files changed, 652 insertions(+), 696 deletions(-) diff --git a/libfprint/drivers/upekts.c b/libfprint/drivers/upekts.c index 476ef34c..09160d97 100644 --- a/libfprint/drivers/upekts.c +++ b/libfprint/drivers/upekts.c @@ -28,24 +28,27 @@ #define FP_COMPONENT "upekts" #include "drivers_api.h" -#include "fpi-async.h" #include "upek_proto.h" -#define EP_IN (1 | LIBUSB_ENDPOINT_IN) -#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT) +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) #define TIMEOUT 5000 #define MSG_READ_BUF_SIZE 0x40 #define MAX_DATA_IN_READ_BUF (MSG_READ_BUF_SIZE - 9) -struct upekts_dev { +struct _FpiDeviceUpekts { + FpDevice parent; + gboolean enroll_passed; + gint enroll_stage; gboolean first_verify_iteration; - gboolean stop_verify; - uint8_t seq; /* FIXME: improve/automate seq handling */ + guint8 seq; /* FIXME: improve/automate seq handling */ }; - +G_DECLARE_FINAL_TYPE(FpiDeviceUpekts, fpi_device_upekts, FPI, + DEVICE_UPEKTS, FpDevice); +G_DEFINE_TYPE(FpiDeviceUpekts, fpi_device_upekts, FP_TYPE_DEVICE); /* * MESSAGE FORMAT @@ -87,158 +90,152 @@ struct upekts_dev { #define CMD_SEQ_INCREMENT 0x10 -static struct libusb_transfer *alloc_send_cmd_transfer(struct fp_dev *dev, - unsigned char seq_a, unsigned char seq_b, const unsigned char *data, - uint16_t len, libusb_transfer_cb_fn callback, void *user_data) +static FpiUsbTransfer *alloc_send_cmd_transfer(FpDevice *dev, + unsigned char seq_a, + unsigned char seq_b, + const unsigned char *data, + guint16 len) { - struct libusb_transfer *transfer = fpi_usb_alloc(); - uint16_t crc; + FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); + guint16 crc; const char *ciao = "Ciao"; /* 9 bytes extra for: 4 byte 'Ciao', 1 byte A, 1 byte B | lenHI, * 1 byte lenLO, 2 byte CRC */ size_t urblen = len + 9; - unsigned char *buf; if (!data && len > 0) { fp_err("len>0 but no data?"); return NULL; } - buf = g_malloc(urblen); + fpi_usb_transfer_fill_bulk (transfer, EP_OUT, urblen); /* Write header */ - memcpy(buf, ciao, strlen(ciao)); - len = GUINT16_TO_LE(len); - buf[4] = seq_a; - buf[5] = seq_b | ((len & 0xf00) >> 8); - buf[6] = len & 0x00ff; + memcpy(transfer->buffer, ciao, strlen(ciao)); + transfer->buffer[4] = seq_a; + transfer->buffer[5] = seq_b | ((len & 0xf00) >> 8); + transfer->buffer[6] = len & 0x00ff; /* Copy data */ if (data) - memcpy(buf + 7, data, len); + memcpy(transfer->buffer + 7, data, len); /* Append CRC */ - crc = GUINT16_TO_BE(udf_crc(buf + 4, urblen - 6)); - buf[urblen - 2] = crc >> 8; - buf[urblen - 1] = crc & 0xff; + crc = udf_crc(transfer->buffer + 4, urblen - 6); + transfer->buffer[urblen - 2] = crc & 0xff; + transfer->buffer[urblen - 1] = crc >> 8; - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(dev), EP_OUT, buf, urblen, - callback, user_data, TIMEOUT); return transfer; } -static struct libusb_transfer *alloc_send_cmd28_transfer(struct fp_dev *dev, - unsigned char subcmd, const unsigned char *data, uint16_t innerlen, - libusb_transfer_cb_fn callback, void *user_data) +static FpiUsbTransfer *alloc_send_cmd28_transfer(FpDevice *dev, + unsigned char subcmd, + const unsigned char *data, + guint16 innerlen) { - uint16_t _innerlen = innerlen; + guint16 _innerlen = innerlen; size_t len = innerlen + 6; unsigned char *buf = g_malloc0(len); - struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); - uint8_t seq = upekdev->seq + CMD_SEQ_INCREMENT; - struct libusb_transfer *ret; + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); + guint8 seq = upekdev->seq + CMD_SEQ_INCREMENT; + FpiUsbTransfer *ret; fp_dbg("seq=%02x subcmd=%02x with %d bytes of data", seq, subcmd, innerlen); - _innerlen = GUINT16_TO_LE(innerlen + 3); + _innerlen = innerlen + 3; buf[0] = 0x28; buf[1] = _innerlen & 0x00ff; buf[2] = (_innerlen & 0xff00) >> 8; buf[5] = subcmd; memcpy(buf + 6, data, innerlen); - ret = alloc_send_cmd_transfer(dev, 0, seq, buf, len, callback, user_data); + ret = alloc_send_cmd_transfer(dev, 0, seq, buf, len); upekdev->seq = seq; g_free(buf); return ret; } -static struct libusb_transfer *alloc_send_cmdresponse_transfer( - struct fp_dev *dev, unsigned char seq, const unsigned char *data, - uint8_t len, libusb_transfer_cb_fn callback, void *user_data) +static FpiUsbTransfer *alloc_send_cmdresponse_transfer(FpDevice *dev, + unsigned char seq, + const unsigned char *data, + guint8 len) { fp_dbg("seq=%02x len=%d", seq, len); - return alloc_send_cmd_transfer(dev, seq, 0, data, len, callback, user_data); + return alloc_send_cmd_transfer(dev, seq, 0, data, len); } -enum read_msg_status { - READ_MSG_ERROR, +enum read_msg_type { READ_MSG_CMD, READ_MSG_RESPONSE, }; -typedef void (*read_msg_cb_fn)(struct fp_dev *dev, enum read_msg_status status, - uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, - void *user_data); +typedef void (*read_msg_cb_fn)(FpDevice *dev, enum read_msg_type type, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, GError *error); struct read_msg_data { - struct fp_dev *dev; + gssize buflen; + guint8 *buffer; read_msg_cb_fn callback; void *user_data; }; -static int __read_msg_async(struct read_msg_data *udata); +static void __read_msg_async(FpDevice *dev, struct read_msg_data *udata); -#define READ_MSG_DATA_CB_ERR(udata) (udata)->callback((udata)->dev, \ - READ_MSG_ERROR, 0, 0, NULL, 0, (udata)->user_data) +#define READ_MSG_DATA_CB_ERR(dev, udata, error) (udata)->callback(dev, \ + READ_MSG_CMD, 0, 0, NULL, 0, (udata)->user_data, error) -static void busy_ack_sent_cb(struct libusb_transfer *transfer) +static void busy_ack_sent_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - struct read_msg_data *udata = transfer->user_data; + struct read_msg_data *udata = user_data; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED || - transfer->length != transfer->actual_length) { - READ_MSG_DATA_CB_ERR(udata); + if (error) { + READ_MSG_DATA_CB_ERR(device, udata, error); + g_free(udata->buffer); g_free(udata); } else { - int r = __read_msg_async(udata); - if (r < 0) { - READ_MSG_DATA_CB_ERR(udata); - g_free(udata); - } + __read_msg_async(device, udata); } - libusb_free_transfer(transfer); } -static int busy_ack_retry_read(struct read_msg_data *udata) +static void busy_ack_retry_read(FpDevice *device, struct read_msg_data *udata) { - struct libusb_transfer *transfer; - int r; + FpiUsbTransfer *transfer; - transfer = alloc_send_cmdresponse_transfer(udata->dev, 0x09, NULL, 0, - busy_ack_sent_cb, udata); - if (!transfer) - return -ENOMEM; + transfer = alloc_send_cmdresponse_transfer(device, 0x09, NULL, 0); + transfer->short_is_error = TRUE; - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(transfer->buffer); - libusb_free_transfer(transfer); - } - return r; + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, busy_ack_sent_cb, udata); + fpi_usb_transfer_unref (transfer); } /* Returns 0 if message was handled, 1 if it was a device-busy message, and * negative on error. */ -static int __handle_incoming_msg(struct read_msg_data *udata, - unsigned char *buf) +static void __handle_incoming_msg(FpDevice *device, + struct read_msg_data *udata) { - uint16_t len = GUINT16_FROM_LE(((buf[5] & 0xf) << 8) | buf[6]); - uint16_t computed_crc = udf_crc(buf + 4, len + 3); - uint16_t msg_crc = GUINT16_FROM_LE((buf[len + 8] << 8) | buf[len + 7]); + GError *error = NULL; + guint8 *buf = udata->buffer; + guint16 len = ((buf[5] & 0xf) << 8) | buf[6]; + guint16 computed_crc = udf_crc(buf + 4, len + 3); + guint16 msg_crc = (buf[len + 8] << 8) | buf[len + 7]; unsigned char *retdata = NULL; unsigned char code_a, code_b; if (computed_crc != msg_crc) { fp_err("CRC failed, got %04x expected %04x", msg_crc, computed_crc); - return -1; + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "CRC check on message failed"); + goto err; } code_a = buf[4]; code_b = buf[5] & 0xf0; - len = GUINT16_FROM_LE(((buf[5] & 0xf) << 8) | buf[6]); + len = ((buf[5] & 0xf) << 8) | buf[6]; fp_dbg("A=%02x B=%02x len=%d", code_a, code_b, len); if (code_a && !code_b) { @@ -246,32 +243,35 @@ static int __handle_incoming_msg(struct read_msg_data *udata, fp_dbg("cmd %x from device to driver", code_a); if (code_a == 0x08) { - int r; fp_dbg("device busy, send busy-ack"); - r = busy_ack_retry_read(udata); - return (r < 0) ? r : 1; + busy_ack_retry_read(device, udata); + return; } if (len > 0) { retdata = g_malloc(len); memcpy(retdata, buf + 7, len); } - udata->callback(udata->dev, READ_MSG_CMD, code_a, 0, retdata, len, - udata->user_data); - g_free(retdata); + udata->callback(device, READ_MSG_CMD, code_a, 0, retdata, len, + udata->user_data, NULL); + goto done; } else if (!code_a) { /* device sends response to a previously executed command */ unsigned char *innerbuf = buf + 7; unsigned char _subcmd; - uint16_t innerlen; + guint16 innerlen; if (len < 6) { - fp_err("cmd response too short (%d)", len); - return -1; + fp_warn("cmd response too short (%d)", len); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "CMD response too short"); + goto err; } if (innerbuf[0] != 0x28) { - fp_err("cmd response without 28 byte?"); - return -1; + fp_warn("cmd response without 28 byte?"); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "CMD response without 0x28 byte"); + goto err; } /* not really sure what these 2 bytes are. on most people's hardware, @@ -282,81 +282,82 @@ static int __handle_incoming_msg(struct read_msg_data *udata, fp_dbg("non-zero bytes in cmd response"); innerlen = innerbuf[1] | (innerbuf[2] << 8); - innerlen = GUINT16_FROM_LE(innerlen) - 3; + innerlen = innerlen - 3; _subcmd = innerbuf[5]; fp_dbg("device responds to subcmd %x with %d bytes", _subcmd, innerlen); if (innerlen > 0) { retdata = g_malloc(innerlen); memcpy(retdata, innerbuf + 6, innerlen); } - udata->callback(udata->dev, READ_MSG_RESPONSE, code_b, _subcmd, - retdata, innerlen, udata->user_data); + udata->callback(device, READ_MSG_RESPONSE, code_b, _subcmd, + retdata, innerlen, udata->user_data, NULL); g_free(retdata); + goto done; } else { fp_err("don't know how to handle this message"); - return -1; - } - return 0; -} - -static void read_msg_extend_cb(struct libusb_transfer *transfer) -{ - struct read_msg_data *udata = transfer->user_data; - unsigned char *buf = transfer->buffer - MSG_READ_BUF_SIZE; - int handle_result = 0; - - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fp_err("extended msg read failed, code %d", transfer->status); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Message cannot be processed"); goto err; } - if (transfer->actual_length < transfer->length) { - fp_err("extended msg short read (%d/%d)", transfer->actual_length, - transfer->length); - goto err; - } - - handle_result = __handle_incoming_msg(udata, buf); - if (handle_result < 0) - goto err; - goto out; + g_assert_not_reached(); err: - READ_MSG_DATA_CB_ERR(udata); -out: - if (handle_result != 1) - g_free(udata); - g_free(buf); - libusb_free_transfer(transfer); + READ_MSG_DATA_CB_ERR(device, udata, error); +done: + g_free(udata->buffer); + g_free(udata); } -static void read_msg_cb(struct libusb_transfer *transfer) +static void read_msg_extend_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - struct read_msg_data *udata = transfer->user_data; - unsigned char *data = transfer->buffer; - uint16_t len; - int handle_result = 0; + struct read_msg_data *udata = user_data; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fp_err("async msg read failed, code %d", transfer->status); + if (error) { + fp_err("extended msg read failed: %s", error->message); + READ_MSG_DATA_CB_ERR(device, udata, error); + g_free(udata->buffer); + g_free(udata); + return; + } + + __handle_incoming_msg(device, udata); +} + +static void read_msg_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) +{ + struct read_msg_data *udata = user_data; + guint16 len; + + if (error) { + fp_err("async msg read failed: %s", error->message); goto err; } if (transfer->actual_length < 9) { - fp_err("async msg read too short (%d)", transfer->actual_length); + fp_err("async msg read too short (%d)", + (gint)transfer->actual_length); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Packet from device was too short"); goto err; } - if (strncmp(data, "Ciao", 4) != 0) { + if (strncmp(udata->buffer, "Ciao", 4) != 0) { fp_err("no Ciao for you!!"); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Packet from device had incorrect header"); goto err; } - len = GUINT16_FROM_LE(((data[5] & 0xf) << 8) | data[6]); + len = ((udata->buffer[5] & 0xf) << 8) | udata->buffer[6]; if (transfer->actual_length != MSG_READ_BUF_SIZE && (len + 9) > transfer->actual_length) { /* Check that the length claimed inside the message is in line with * the amount of data that was transferred over USB. */ fp_err("msg didn't include enough data, expected=%d recv=%d", - len + 9, transfer->actual_length); + len + 9, (gint)transfer->actual_length); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Packet from device didn't include data"); goto err; } @@ -365,70 +366,57 @@ static void read_msg_cb(struct libusb_transfer *transfer) * to read the remainder. This is handled below. */ if (len > MAX_DATA_IN_READ_BUF) { int needed = len - MAX_DATA_IN_READ_BUF; - struct libusb_transfer *etransfer = fpi_usb_alloc(); - int r; + FpiUsbTransfer *etransfer = fpi_usb_transfer_new(device); fp_dbg("didn't fit in buffer, need to extend by %d bytes", needed); - data = g_realloc((gpointer) data, MSG_READ_BUF_SIZE + needed); + udata->buffer = g_realloc((gpointer) udata->buffer, len); + udata->buflen = len; - libusb_fill_bulk_transfer(etransfer, fpi_dev_get_usb_dev(udata->dev), EP_IN, - data + MSG_READ_BUF_SIZE, needed, read_msg_extend_cb, udata, - TIMEOUT); - - r = libusb_submit_transfer(etransfer); - if (r < 0) { - fp_err("extended read submission failed"); - /* FIXME memory leak here? */ - goto err; - } - libusb_free_transfer(transfer); + fpi_usb_transfer_fill_bulk_full(etransfer, EP_IN, + udata->buffer + MSG_READ_BUF_SIZE, + needed, NULL); + etransfer->short_is_error = TRUE; + fpi_usb_transfer_submit(etransfer, TIMEOUT, + NULL, + read_msg_extend_cb, udata); + fpi_usb_transfer_unref(etransfer); return; } - handle_result = __handle_incoming_msg(udata, data); - if (handle_result < 0) - goto err; - goto out; + __handle_incoming_msg(device, udata); + return; err: - READ_MSG_DATA_CB_ERR(udata); -out: - libusb_free_transfer(transfer); - if (handle_result != 1) - g_free(udata); - g_free(data); + READ_MSG_DATA_CB_ERR(device, udata, error); + g_free(udata->buffer); + g_free(udata); } -static int __read_msg_async(struct read_msg_data *udata) +static void __read_msg_async(FpDevice *device, struct read_msg_data *udata) { - unsigned char *buf = g_malloc(MSG_READ_BUF_SIZE); - struct libusb_transfer *transfer = fpi_usb_alloc(); - int r; + FpiUsbTransfer *transfer = fpi_usb_transfer_new(device); - libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(udata->dev), EP_IN, buf, - MSG_READ_BUF_SIZE, read_msg_cb, udata, TIMEOUT); - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(buf); - libusb_free_transfer(transfer); + if (udata->buflen != MSG_READ_BUF_SIZE) { + udata->buffer = g_realloc (udata->buffer, MSG_READ_BUF_SIZE); + udata->buflen = MSG_READ_BUF_SIZE; } - return r; + fpi_usb_transfer_fill_bulk_full(transfer, EP_IN, udata->buffer, udata->buflen, NULL); + fpi_usb_transfer_submit(transfer, TIMEOUT, NULL, read_msg_cb, udata); + fpi_usb_transfer_unref(transfer); } -static int read_msg_async(struct fp_dev *dev, read_msg_cb_fn callback, - void *user_data) +static void read_msg_async(FpDevice *dev, + read_msg_cb_fn callback, + void *user_data) { - struct read_msg_data *udata = g_malloc(sizeof(*udata)); - int r; + struct read_msg_data *udata = g_new0(struct read_msg_data, 1); - udata->dev = dev; + udata->buflen = 0; + udata->buffer = NULL; udata->callback = callback; udata->user_data = user_data; - r = __read_msg_async(udata); - if (r) - g_free(udata); - return r; + __read_msg_async(dev, udata); } static const unsigned char init_resp03[] = { @@ -475,222 +463,189 @@ enum initsm_states { }; static void -initsm_read_msg_response_cb(fpi_ssm *ssm, - struct fp_dev *dev, - enum read_msg_status status, - uint8_t seq, - unsigned char expect_subcmd, - unsigned char subcmd) +initsm_read_msg_response_cb(FpiSsm *ssm, + FpDevice *dev, + enum read_msg_type type, + guint8 seq, + unsigned char expect_subcmd, + unsigned char subcmd, + GError *error) { - struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); - if (status != READ_MSG_RESPONSE) { - fp_err("expected response, got %d seq=%x in state %d", status, seq, + if (error) { + fpi_ssm_mark_failed(ssm, error); + } else if (type != READ_MSG_RESPONSE) { + fp_err("expected response, got %d seq=%x in state %d", type, seq, fpi_ssm_get_cur_state(ssm)); - fpi_ssm_mark_failed(ssm, -1); - } else if (subcmd != expect_subcmd) { + fpi_ssm_mark_failed(ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Unexpected message type")); + } else if (seq != upekdev->seq) { fp_warn("expected response to subcmd 0x%02x, got response to %02x in " - "state %d", expect_subcmd, subcmd, fpi_ssm_get_cur_state(ssm)); - fpi_ssm_mark_failed(ssm, -1); + "state %d", expect_subcmd, subcmd, + fpi_ssm_get_cur_state(ssm)); + fpi_ssm_mark_failed(ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Unexpected response subcommand")); } else if (seq != upekdev->seq) { fp_err("expected response to cmd seq=%02x, got response to %02x " - "in state %d", upekdev->seq, seq, fpi_ssm_get_cur_state(ssm)); - fpi_ssm_mark_failed(ssm, -1); + "in state %d", upekdev->seq, seq, + fpi_ssm_get_cur_state(ssm)); + fpi_ssm_mark_failed(ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Unexpected sequence number in response")); } else { - fp_dbg("state %d completed", fpi_ssm_get_cur_state(ssm)); fpi_ssm_next_state(ssm); } } -static void read28_0b_cb(struct fp_dev *dev, enum read_msg_status status, - uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, - void *user_data) +static void read28_0b_cb(FpDevice *dev, enum read_msg_type type, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, GError *error) { - initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq, - 0x0b, subcmd); + initsm_read_msg_response_cb((FpiSsm *) user_data, dev, type, seq, + 0x0b, subcmd, error); } -static void read28_0c_cb(struct fp_dev *dev, enum read_msg_status status, - uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, - void *user_data) +static void read28_0c_cb(FpDevice *dev, enum read_msg_type type, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, GError *error) { - initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq, - 0x0c, subcmd); + initsm_read_msg_response_cb((FpiSsm *) user_data, dev, type, seq, + 0x0c, subcmd, error); } -static void read28_08_cb(struct fp_dev *dev, enum read_msg_status status, - uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, - void *user_data) +static void read28_08_cb(FpDevice *dev, enum read_msg_type type, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, GError *error) { - initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq, - 0x08, subcmd); + initsm_read_msg_response_cb((FpiSsm *) user_data, dev, type, seq, + 0x08, subcmd, error); } -static void read28_07_cb(struct fp_dev *dev, enum read_msg_status status, - uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, - void *user_data) +static void read28_07_cb(FpDevice *dev, enum read_msg_type type, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, GError *error) { - initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq, - 0x07, subcmd); + initsm_read_msg_response_cb((FpiSsm *) user_data, dev, type, seq, + 0x07, subcmd, error); } -static void read28_06_cb(struct fp_dev *dev, enum read_msg_status status, - uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, - void *user_data) +static void read28_06_cb(FpDevice *dev, enum read_msg_type type, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, GError *error) { - initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq, - 0x06, subcmd); + initsm_read_msg_response_cb((FpiSsm *) user_data, dev, type, seq, + 0x06, subcmd, error); } static void -initsm_read_msg_cmd_cb(fpi_ssm *ssm, - struct fp_dev *dev, - enum read_msg_status status, - uint8_t expect_seq, - uint8_t seq) +initsm_read_msg_cmd_cb(FpiSsm *ssm, + FpDevice *dev, + enum read_msg_type type, + guint8 seq, + guint8 expected_seq, + GError *error) { - struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); - if (status == READ_MSG_ERROR) { - fpi_ssm_mark_failed(ssm, -1); + if (error) { + fpi_ssm_mark_failed(ssm, error); return; - } else if (status != READ_MSG_CMD) { - fp_err("expected command, got %d seq=%x in state %d", status, seq, + } else if (type != READ_MSG_CMD) { + fp_err("expected command, got %d seq=%x in state %d", type, seq, fpi_ssm_get_cur_state(ssm)); - fpi_ssm_mark_failed(ssm, -1); + fpi_ssm_mark_failed(ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Expected command but got response")); return; } upekdev->seq = seq; - if (seq != expect_seq) { - fp_err("expected seq=%x, got %x in state %d", expect_seq, seq, + if (seq != expected_seq) { + fp_err("expected seq=%x, got %x in state %d", expected_seq, seq, fpi_ssm_get_cur_state(ssm)); - fpi_ssm_mark_failed(ssm, -1); + fpi_ssm_mark_failed(ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Got unexpected sequence number")); return; } fpi_ssm_next_state(ssm); } -static void read_msg05_cb(struct fp_dev *dev, enum read_msg_status status, - uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, - void *user_data) +static void read_msg05_cb(FpDevice *dev, enum read_msg_type type, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, GError *error) { - initsm_read_msg_cmd_cb((fpi_ssm *) user_data, dev, status, 5, seq); + initsm_read_msg_cmd_cb((FpiSsm *) user_data, dev, type, 5, seq, error); } -static void read_msg03_cb(struct fp_dev *dev, enum read_msg_status status, - uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, - void *user_data) +static void read_msg03_cb(FpDevice *dev, enum read_msg_type type, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, GError *error) { - initsm_read_msg_cmd_cb((fpi_ssm *) user_data, dev, status, 3, seq); -} - -static void ctrl400_cb(struct libusb_transfer *transfer) -{ - fpi_ssm *ssm = transfer->user_data; - /* FIXME check length? */ - if (transfer->status == LIBUSB_TRANSFER_COMPLETED) - fpi_ssm_next_state(ssm); - else - fpi_ssm_mark_failed(ssm, -1); - g_free(transfer->buffer); - libusb_free_transfer(transfer); + initsm_read_msg_cmd_cb((FpiSsm *) user_data, dev, type, 3, seq, error); } static void -initsm_read_msg_handler(fpi_ssm *ssm, - struct fp_dev *dev, +initsm_read_msg_handler(FpiSsm *ssm, + FpDevice *dev, read_msg_cb_fn callback) { - int r = read_msg_async(dev, callback, ssm); - if (r < 0) { - fp_err("async read msg failed in state %d", fpi_ssm_get_cur_state(ssm)); - fpi_ssm_mark_failed(ssm, r); - } -} - -static void initsm_send_msg_cb(struct libusb_transfer *transfer) -{ - fpi_ssm *ssm = transfer->user_data; - if (transfer->status == LIBUSB_TRANSFER_COMPLETED - && transfer->length == transfer->actual_length) { - fp_dbg("state %d completed", fpi_ssm_get_cur_state(ssm)); - fpi_ssm_next_state(ssm); - } else { - fp_err("failed, state=%d rqlength=%d actual_length=%d", fpi_ssm_get_cur_state(ssm), - transfer->length, transfer->actual_length); - fpi_ssm_mark_failed(ssm, -1); - } - libusb_free_transfer(transfer); + read_msg_async(dev, callback, ssm); } static void -initsm_send_msg28_handler(fpi_ssm *ssm, - struct fp_dev *dev, +initsm_send_msg28_handler(FpiSsm *ssm, + FpDevice *dev, unsigned char subcmd, const unsigned char *data, - uint16_t innerlen) + guint16 innerlen) { - struct libusb_transfer *transfer; - int r; + FpiUsbTransfer *transfer; - transfer = alloc_send_cmd28_transfer(dev, subcmd, data, innerlen, - initsm_send_msg_cb, ssm); - if (!transfer) { - fpi_ssm_mark_failed(ssm, -ENOMEM); - return; - } - - r = libusb_submit_transfer(transfer); - if (r < 0) { - fp_err("urb submission failed error %d in state %d", r, fpi_ssm_get_cur_state(ssm)); - g_free(transfer->buffer); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, -EIO); - } + transfer = alloc_send_cmd28_transfer(dev, subcmd, data, innerlen); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); + fpi_usb_transfer_unref (transfer); } -static void initsm_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) +static void initsm_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) { - struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); - struct libusb_transfer *transfer; - int r; + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); + FpiUsbTransfer *transfer; switch (fpi_ssm_get_cur_state(ssm)) { case WRITE_CTRL400: ; - unsigned char *data; - - transfer = fpi_usb_alloc(); - data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1); - libusb_fill_control_setup(data, - LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 0x0c, 0x100, 0x0400, 1); - libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(dev), data, - ctrl400_cb, ssm, TIMEOUT); - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(data); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + transfer = fpi_usb_transfer_new(dev); + fpi_usb_transfer_fill_control(transfer, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0x0c, 0x100, 0x0400, 1); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit(transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); + fpi_usb_transfer_unref(transfer); break; case READ_MSG03: initsm_read_msg_handler(ssm, dev, read_msg03_cb); break; case SEND_RESP03: ; - transfer = alloc_send_cmdresponse_transfer(dev, ++upekdev->seq, - init_resp03, sizeof(init_resp03), initsm_send_msg_cb, ssm); - if (!transfer) { - fpi_ssm_mark_failed(ssm, -ENOMEM); - break; - } - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(transfer->buffer); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + transfer = alloc_send_cmd28_transfer(dev, ++upekdev->seq, init_resp03, sizeof(init_resp03)); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); + fpi_usb_transfer_unref (transfer); break; case READ_MSG05: initsm_read_msg_handler(ssm, dev, read_msg05_cb); @@ -731,10 +686,9 @@ static void initsm_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) } } -static fpi_ssm *initsm_new(struct fp_dev *dev, - void *user_data) +static FpiSsm *initsm_new(FpDevice *dev) { - return fpi_ssm_new(dev, initsm_run_state, INITSM_NUM_STATES, user_data); + return fpi_ssm_new(dev, initsm_run_state, INITSM_NUM_STATES, NULL); } enum deinitsm_states { @@ -743,106 +697,97 @@ enum deinitsm_states { DEINITSM_NUM_STATES, }; -static void send_resp07_cb(struct libusb_transfer *transfer) +static void read_msg01_cb(FpDevice *dev, enum read_msg_type type, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, GError *error) { - fpi_ssm *ssm = transfer->user_data; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - fpi_ssm_mark_failed(ssm, -EIO); - else if (transfer->length != transfer->actual_length) - fpi_ssm_mark_failed(ssm, -EPROTO); - else - fpi_ssm_next_state(ssm); - libusb_free_transfer(transfer); -} + FpiSsm *ssm = user_data; + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); -static void read_msg01_cb(struct fp_dev *dev, enum read_msg_status status, - uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, - void *user_data) -{ - fpi_ssm *ssm = user_data; - struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); - - if (status == READ_MSG_ERROR) { - fpi_ssm_mark_failed(ssm, -1); + if (error) { + fpi_ssm_mark_failed(ssm, error); return; - } else if (status != READ_MSG_CMD) { - fp_err("expected command, got %d seq=%x", status, seq); - fpi_ssm_mark_failed(ssm, -1); + } else if (type != READ_MSG_CMD) { + fp_err("expected command, got %d seq=%x", type, seq); + fpi_ssm_mark_failed(ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Expected command but got response")); return; } upekdev->seq = seq; if (seq != 1) { fp_err("expected seq=1, got %x", seq); - fpi_ssm_mark_failed(ssm, -1); + fpi_ssm_mark_failed(ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Got wrong sequence number")); return; } fpi_ssm_next_state(ssm); } -static void deinitsm_state_handler(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) +static void deinitsm_state_handler(FpiSsm *ssm, FpDevice *dev, + void *user_data) { - int r; - switch (fpi_ssm_get_cur_state(ssm)) { case SEND_RESP07: ; - struct libusb_transfer *transfer; + FpiUsbTransfer *transfer; unsigned char dummy = 0; - transfer = alloc_send_cmdresponse_transfer(dev, 0x07, &dummy, 1, - send_resp07_cb, ssm); - if (!transfer) { - fpi_ssm_mark_failed(ssm, -ENOMEM); - break; - } - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(transfer->buffer); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + transfer = alloc_send_cmdresponse_transfer(dev, 0x07, &dummy, 1); + transfer->short_is_error = TRUE; + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); + fpi_usb_transfer_unref (transfer); break; case READ_MSG01: ; - r = read_msg_async(dev, read_msg01_cb, ssm); - if (r < 0) - fpi_ssm_mark_failed(ssm, r); + read_msg_async(dev, read_msg01_cb, ssm); break; } } -static fpi_ssm *deinitsm_new(struct fp_dev *dev) +static void initsm_done(FpiSsm *ssm, FpDevice *dev, void *user_data, GError *error) { - return fpi_ssm_new(dev, deinitsm_state_handler, DEINITSM_NUM_STATES, NULL); + if (error) + g_usb_device_release_interface (fpi_device_get_usb_device(dev), 0, 0, NULL); + + fpi_device_open_complete (dev, error); } -static int dev_init(struct fp_dev *dev, unsigned long driver_data) +static FpiSsm *deinitsm_new(FpDevice *dev, void *user_data) { - struct upekts_dev *upekdev = NULL; - int r; + return fpi_ssm_new(dev, deinitsm_state_handler, DEINITSM_NUM_STATES, user_data); +} - r = libusb_claim_interface(fpi_dev_get_usb_dev(dev), 0); - if (r < 0) { - fp_err("could not claim interface 0: %s", libusb_error_name(r)); - return r; +static void dev_init(FpDevice *dev) +{ + FpiSsm *ssm; + GError *error = NULL; + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev); + + if (!g_usb_device_claim_interface (fpi_device_get_usb_device(dev), 0, 0, &error)) { + fpi_device_open_complete (dev, error); + return; } - upekdev = g_malloc(sizeof(*upekdev)); upekdev->seq = 0xf0; /* incremented to 0x00 before first cmd */ - fp_dev_set_instance_data(dev, upekdev); - fpi_dev_set_nr_enroll_stages(dev, 3); - fpi_drvcb_open_complete(dev, 0); - return 0; + ssm = fpi_ssm_new(dev, initsm_run_state, INITSM_NUM_STATES, NULL); + fpi_ssm_start (ssm, initsm_done); } -static void dev_exit(struct fp_dev *dev) +static void deinitsm_done(FpiSsm *ssm, FpDevice *dev, void *user_data, GError *error) { - struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); + g_usb_device_release_interface (fpi_device_get_usb_device(dev), 0, 0, NULL); - libusb_release_interface(fpi_dev_get_usb_dev(dev), 0); - g_free(upekdev); - fpi_drvcb_close_complete(dev); + fpi_device_close_complete (dev, error); +} + +static void dev_exit(FpDevice *dev) +{ + FpiSsm *ssm; + + ssm = fpi_ssm_new(dev, deinitsm_state_handler, DEINITSM_NUM_STATES, NULL); + fpi_ssm_start (ssm, deinitsm_done); } static const unsigned char enroll_init[] = { @@ -862,104 +807,110 @@ enum enroll_start_sm_states { ENROLL_START_NUM_STATES, }; -/* Called when the device initialization state machine completes */ -static void enroll_start_sm_cb_initsm(fpi_ssm *initsm, struct fp_dev *_dev, void *user_data) +static void enroll_start_sm_cb_msg28(FpDevice *dev, + enum read_msg_type type, guint8 seq, + unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, + GError *error) { - fpi_ssm *enroll_start_ssm = user_data; - int error = fpi_ssm_get_error(initsm); + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); + FpiSsm *ssm = user_data; - fpi_ssm_free(initsm); - if (error) - fpi_ssm_mark_failed(enroll_start_ssm, error); - else - fpi_ssm_next_state(enroll_start_ssm); -} - -/* called when enroll init URB has completed */ -static void enroll_start_sm_cb_init(struct libusb_transfer *transfer) -{ - fpi_ssm *ssm = transfer->user_data; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - fpi_ssm_mark_failed(ssm, -EIO); - else if (transfer->length != transfer->actual_length) - fpi_ssm_mark_failed(ssm, -EPROTO); - else - fpi_ssm_next_state(ssm); - libusb_free_transfer(transfer); -} - -static void enroll_start_sm_cb_msg28(struct fp_dev *dev, - enum read_msg_status status, uint8_t seq, unsigned char subcmd, - unsigned char *data, size_t data_len, void *user_data) -{ - struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); - fpi_ssm *ssm = user_data; - - if (status != READ_MSG_RESPONSE) { - fp_err("expected response, got %d seq=%x", status, seq); - fpi_ssm_mark_failed(ssm, -1); + if (error) { + fpi_ssm_mark_failed(ssm, error); + } + if (type != READ_MSG_RESPONSE) { + fp_err("expected response, got %d seq=%x", type, seq); + fpi_ssm_mark_failed(ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Unexpected response type")); } else if (subcmd != 0) { fp_warn("expected response to subcmd 0, got response to %02x", subcmd); - fpi_ssm_mark_failed(ssm, -1); + fpi_ssm_mark_failed(ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Got response to wrong subcommand")); } else if (seq != upekdev->seq) { fp_err("expected response to cmd seq=%02x, got response to %02x", upekdev->seq, seq); - fpi_ssm_mark_failed(ssm, -1); + fpi_ssm_mark_failed(ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Got response with wrong sequence number")); } else { fpi_ssm_next_state(ssm); } } -static void enroll_start_sm_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) +static void enroll_start_sm_run_state(FpiSsm *ssm, FpDevice *dev, + void *user_data) { - int r; - switch (fpi_ssm_get_cur_state(ssm)) { case RUN_INITSM: ; - fpi_ssm *initsm = initsm_new(dev, ssm); - fpi_ssm_start(initsm, enroll_start_sm_cb_initsm); + FpiSsm *initsm = initsm_new(dev); + fpi_ssm_start_subsm(ssm, initsm); break; case ENROLL_INIT: ; - struct libusb_transfer *transfer; - transfer = alloc_send_cmd28_transfer(dev, 0x02, enroll_init, - sizeof(enroll_init), enroll_start_sm_cb_init, ssm); - if (!transfer) { - fpi_ssm_mark_failed(ssm, -ENOMEM); - break; - } + FpiUsbTransfer *transfer; + transfer = alloc_send_cmd28_transfer(dev, 0x02, enroll_init, sizeof(enroll_init)); + transfer->short_is_error = TRUE; + transfer->ssm = ssm; - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(transfer->buffer); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, r); - } + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); + fpi_usb_transfer_unref (transfer); break; case READ_ENROLL_MSG28: ; /* FIXME: protocol misunderstanding here. device receives response * to subcmd 0 after submitting subcmd 2? */ /* actually this is probably a poll response? does the above cmd * include a 30 01 poll somewhere? */ - r = read_msg_async(dev, enroll_start_sm_cb_msg28, ssm); - if (r < 0) - fpi_ssm_mark_failed(ssm, r); + read_msg_async(dev, enroll_start_sm_cb_msg28, ssm); break; } } -static void enroll_iterate(struct fp_dev *dev); +typedef struct { + FpPrint *print; + GError *error; +} EnrollStopData; -static void e_handle_resp00(struct fp_dev *dev, unsigned char *data, - size_t data_len) +static void enroll_stop_deinit_cb(FpiSsm *ssm, FpDevice *dev, + void *user_data, GError *error) { - struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); + EnrollStopData *data = user_data; + + /* don't really care about errors */ + if (error) { + fp_warn ("Error deinitializing: %s", error->message); + g_error_free (error); + } + + fpi_device_enroll_complete (dev, data->print, data->error); + g_free (data); + fpi_ssm_free(ssm); +} + +static void do_enroll_stop(FpDevice *dev, FpPrint *print, GError *error) +{ + EnrollStopData *data = g_new0(EnrollStopData, 1); + FpiSsm *ssm = deinitsm_new(dev, data); + + data->print = print; + data->error = error; + + fpi_ssm_start(ssm, enroll_stop_deinit_cb); +} + +static void enroll_iterate(FpDevice *dev); + +static void e_handle_resp00(FpDevice *dev, unsigned char *data, + size_t data_len) +{ + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); unsigned char status; - int result = 0; if (data_len != 14) { fp_err("received 3001 poll response of %lu bytes?", data_len); - fpi_drvcb_enroll_stage_completed(dev, -EPROTO, NULL, NULL); + do_enroll_stop (dev, NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "received 3001 response with wrong length")); return; } @@ -976,48 +927,58 @@ static void e_handle_resp00(struct fp_dev *dev, unsigned char *data, /* if we previously completed a non-last enrollment stage, we'll * get this code to indicate successful stage completion */ if (upekdev->enroll_passed) { - result = FP_ENROLL_PASS; upekdev->enroll_passed = FALSE; + upekdev->enroll_stage += 1; + + fpi_device_enroll_progress (dev, upekdev->enroll_stage, NULL, NULL); } /* otherwise it just means "no news" so we poll again */ break; case 0x1c: /* FIXME what does this one mean? */ case 0x0b: /* FIXME what does this one mean? */ case 0x23: /* FIXME what does this one mean? */ - result = FP_ENROLL_RETRY; + fpi_device_enroll_progress (dev, + upekdev->enroll_stage, + NULL, + fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); break; case 0x0f: /* scan taking too long, remove finger and try again */ - result = FP_ENROLL_RETRY_REMOVE_FINGER; + fpi_device_enroll_progress (dev, + upekdev->enroll_stage, + NULL, + fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER)); break; case 0x1e: /* swipe too short */ - result = FP_ENROLL_RETRY_TOO_SHORT; + fpi_device_enroll_progress (dev, + upekdev->enroll_stage, + NULL, + fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT)); break; case 0x24: /* finger not centered */ - result = FP_ENROLL_RETRY_CENTER_FINGER; + fpi_device_enroll_progress (dev, + upekdev->enroll_stage, + NULL, + fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER)); break; case 0x20: /* finger scanned successfully */ /* need to look at the next poll result to determine if enrollment is * complete or not */ - upekdev->enroll_passed = 1; + upekdev->enroll_passed = TRUE; break; case 0x00: /* enrollment complete */ /* we can now expect the enrollment data on the next poll, so we * have nothing to do here */ break; default: - fp_err("unrecognised scan status code %02x", status); - result = -EPROTO; - break; - } - - if (result) { - fpi_drvcb_enroll_stage_completed(dev, result, NULL, NULL); - if (result > 0) - enroll_iterate(dev); - } else { - enroll_iterate(dev); + do_enroll_stop (dev, + NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Unrecognised scan status code")); + /* Stop iteration. */ + return; } + enroll_iterate(dev); /* FIXME: need to extend protocol research to handle the case when * enrolment fails, e.g. you scan a different finger on each stage */ @@ -1025,38 +986,52 @@ static void e_handle_resp00(struct fp_dev *dev, unsigned char *data, * cmd2 results and enforce it */ } -static void e_handle_resp02(struct fp_dev *dev, unsigned char *data, - size_t data_len) +static void e_handle_resp02(FpDevice *dev, unsigned char *data, + size_t data_len) { - struct fp_print_data *fdata = NULL; - struct fp_print_data_item *item = NULL; - int result = -EPROTO; + FpPrint *print = NULL; + GError *error = NULL; if (data_len < sizeof(scan_comp)) { fp_err("fingerprint data too short (%lu bytes)", data_len); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "fingerprint data too short"); } else if (memcmp(data, scan_comp, sizeof(scan_comp)) != 0) { fp_err("unrecognised data prefix %x %x %x %x %x", data[0], data[1], data[2], data[3], data[4]); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "fingerprint data has wrong prefix"); } else { - fdata = fpi_print_data_new(dev); - item = fpi_print_data_item_new(data_len - sizeof(scan_comp)); - memcpy(item->data, data + sizeof(scan_comp), - data_len - sizeof(scan_comp)); - fpi_print_data_add_item(fdata, item); + GVariant *fp_data; + print = fp_print_new (dev); - result = FP_ENROLL_COMPLETE; + fpi_device_get_enroll_data (dev, &print); + + fp_data = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + data + sizeof(scan_comp), + data_len - sizeof(scan_comp), + 1); + + g_object_set (print, "fp-data", fp_data, NULL); + g_object_ref (print); } - fpi_drvcb_enroll_stage_completed(dev, result, fdata, NULL); + do_enroll_stop (dev, print, error); } -static void enroll_iterate_msg_cb(struct fp_dev *dev, - enum read_msg_status msgstat, uint8_t seq, unsigned char subcmd, - unsigned char *data, size_t data_len, void *user_data) +static void enroll_iterate_msg_cb(FpDevice *dev, + enum read_msg_type msgtype, guint8 seq, + unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, + GError *error) { - if (msgstat != READ_MSG_RESPONSE) { - fp_err("expected response, got %d seq=%x", msgstat, seq); - fpi_drvcb_enroll_stage_completed(dev, -EPROTO, NULL, NULL); + if (error) { + do_enroll_stop (dev, NULL, error); + return; + } else if (msgtype != READ_MSG_RESPONSE) { + fp_err("expected response, got %d seq=%x", msgtype, seq); + do_enroll_stop (dev, NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Expected message response, not command")); return; } if (subcmd == 0) { @@ -1065,93 +1040,92 @@ static void enroll_iterate_msg_cb(struct fp_dev *dev, e_handle_resp02(dev, data, data_len); } else { fp_err("unexpected subcmd %d", subcmd); - fpi_drvcb_enroll_stage_completed(dev, -EPROTO, NULL, NULL); + do_enroll_stop (dev, NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Unexpected subcommand")); } - } -static void enroll_iterate_cmd_cb(struct libusb_transfer *transfer) +static void enroll_iterate_cmd_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - struct fp_dev *dev = transfer->user_data; - - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fpi_drvcb_enroll_stage_completed(dev, -EIO, NULL, NULL); - } else if (transfer->length != transfer->actual_length) { - fpi_drvcb_enroll_stage_completed(dev, -EPROTO, NULL, NULL); + if (error) { + do_enroll_stop(device, NULL, error); } else { - int r = read_msg_async(dev, enroll_iterate_msg_cb, NULL); - if (r < 0) - fpi_drvcb_enroll_stage_completed(dev, r, NULL, NULL); + read_msg_async(device, enroll_iterate_msg_cb, NULL); } - libusb_free_transfer(transfer); } -static void enroll_iterate(struct fp_dev *dev) +static void enroll_iterate(FpDevice *dev) { - int r; - struct libusb_transfer *transfer = alloc_send_cmd28_transfer(dev, 0x00, - poll_data, sizeof(poll_data), enroll_iterate_cmd_cb, dev); + FpiUsbTransfer *transfer; - if (!transfer) { - fpi_drvcb_enroll_stage_completed(dev, -ENOMEM, NULL, NULL); + if (fpi_device_action_is_cancelled (dev)) { + do_enroll_stop(dev, NULL, g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled")); return; } - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(transfer->buffer); - libusb_free_transfer(transfer); - fpi_drvcb_enroll_stage_completed(dev, -EIO, NULL, NULL); - } + transfer = alloc_send_cmd28_transfer(dev, 0x00, + poll_data, sizeof(poll_data)); + transfer->short_is_error = TRUE; + + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, enroll_iterate_cmd_cb, NULL); + fpi_usb_transfer_unref (transfer); } -static void enroll_started(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) +static void enroll_started(FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - fpi_drvcb_enroll_started(dev, fpi_ssm_get_error(ssm)); - - if (!fpi_ssm_get_error(ssm)) + if (error) { + do_enroll_stop (dev, NULL, error); + } else { enroll_iterate(dev); + } fpi_ssm_free(ssm); } -static int enroll_start(struct fp_dev *dev) +static void enroll(FpDevice *dev) { - struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); /* do_init state machine first */ - fpi_ssm *ssm = fpi_ssm_new(dev, enroll_start_sm_run_state, + FpiSsm *ssm = fpi_ssm_new(dev, enroll_start_sm_run_state, ENROLL_START_NUM_STATES, NULL); upekdev->enroll_passed = FALSE; + upekdev->enroll_stage = 0; fpi_ssm_start(ssm, enroll_started); - return 0; } -static void enroll_stop_deinit_cb(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) +typedef struct { + FpiMatchResult res; + GError *error; +} VerifyStopData; + +static void verify_stop_deinit_cb(FpiSsm *ssm, FpDevice *dev, + void *user_data, GError *error) { - /* don't really care about errors */ - fpi_drvcb_enroll_stopped(dev); + VerifyStopData *data = user_data; + + if (error) { + fp_warn ("Error deinitializing: %s", error->message); + g_error_free (error); + } + + fpi_device_verify_complete (dev, data->res, NULL, data->error); + g_free (data); fpi_ssm_free(ssm); } -static int enroll_stop(struct fp_dev *dev) +static void do_verify_stop(FpDevice *dev, FpiMatchResult res, GError *error) { - fpi_ssm *ssm = deinitsm_new(dev); - fpi_ssm_start(ssm, enroll_stop_deinit_cb); - return 0; -} + VerifyStopData *data = g_new0(VerifyStopData, 1); + FpiSsm *ssm = deinitsm_new(dev, data); -static void verify_stop_deinit_cb(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) -{ - /* don't really care about errors */ - fpi_drvcb_verify_stopped(dev); - fpi_ssm_free(ssm); -} + data->res = res; + data->error = error; -static void do_verify_stop(struct fp_dev *dev) -{ - fpi_ssm *ssm = deinitsm_new(dev); fpi_ssm_start(ssm, verify_stop_deinit_cb); } @@ -1167,79 +1141,58 @@ enum { VERIFY_NUM_STATES, }; -/* Called when the device initialization state machine completes */ -static void verify_start_sm_cb_initsm(fpi_ssm *initsm, struct fp_dev *_dev, void *user_data) +static void verify_start_sm_run_state(FpiSsm *ssm, FpDevice *dev, + void *user_data) { - fpi_ssm *verify_start_ssm = user_data; - int err; - - err = fpi_ssm_get_error(initsm); - if (err) - fpi_ssm_mark_failed(verify_start_ssm, err); - else - fpi_ssm_next_state(verify_start_ssm); - fpi_ssm_free(initsm); -} - -static void verify_init_2803_cb(struct libusb_transfer *transfer) -{ - fpi_ssm *ssm = transfer->user_data; - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) - fpi_ssm_mark_failed(ssm, -EIO); - else if (transfer->length != transfer->actual_length) - fpi_ssm_mark_failed(ssm, -EPROTO); - else - fpi_ssm_next_state(ssm); - libusb_free_transfer(transfer); -} - -static void verify_start_sm_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) -{ - int r; + FpPrint *print; + g_autoptr(GVariant) fp_data = NULL; + FpiUsbTransfer *transfer; + gsize data_len; + const guint8 *data; + guint8 *msg; + gsize msg_len; switch (fpi_ssm_get_cur_state(ssm)) { case VERIFY_RUN_INITSM: ; - fpi_ssm *initsm = initsm_new(dev, ssm); - fpi_ssm_start(initsm, verify_start_sm_cb_initsm); + FpiSsm *initsm = initsm_new(dev); + fpi_ssm_start_subsm(ssm, initsm); break; - case VERIFY_INIT: ; - struct fp_print_data *print = fpi_dev_get_verify_data(dev); - struct fp_print_data_item *item = fpi_print_data_get_item(print); - size_t data_len = sizeof(verify_hdr) + item->length; - unsigned char *data = g_malloc(data_len); - struct libusb_transfer *transfer; + case VERIFY_INIT: + fpi_device_get_verify_data (dev, &print); + g_object_get (dev, "fp-data", &fp_data, NULL); - memcpy(data, verify_hdr, sizeof(verify_hdr)); - memcpy(data + sizeof(verify_hdr), item->data, item->length); - transfer = alloc_send_cmd28_transfer(dev, 0x03, data, data_len, - verify_init_2803_cb, ssm); - g_free(data); - if (!transfer) { - fpi_ssm_mark_failed(ssm, -ENOMEM); - break; - } + data = g_variant_get_fixed_array (fp_data, &data_len, 1); + + msg_len = sizeof(verify_hdr) + data_len; + msg = g_malloc (msg_len); + + memcpy(msg, verify_hdr, sizeof(verify_hdr)); + memcpy(msg + sizeof(verify_hdr), data, data_len); + + transfer = alloc_send_cmd28_transfer(dev, 0x03, data, data_len); + + g_free(msg); + + transfer->short_is_error = TRUE; + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); + fpi_usb_transfer_unref (transfer); - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(transfer->buffer); - libusb_free_transfer(transfer); - fpi_ssm_mark_failed(ssm, -EIO); - } break; } } -static void verify_iterate(struct fp_dev *dev); +static void verify_iterate(FpDevice *dev); -static void v_handle_resp00(struct fp_dev *dev, unsigned char *data, - size_t data_len) +static void v_handle_resp00(FpDevice *dev, unsigned char *data, + size_t data_len) { unsigned char status; - int r = 0; + GError *error = NULL; if (data_len != 14) { - fp_err("received 3001 poll response of %lu bytes?", data_len); - r = -EPROTO; + fp_warn("received 3001 poll response of %lu bytes?", data_len); + error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); goto out; } @@ -1260,65 +1213,84 @@ static void v_handle_resp00(struct fp_dev *dev, unsigned char *data, case 0x1c: /* FIXME what does this one mean? */ case 0x0b: /* FIXME what does this one mean? */ case 0x23: /* FIXME what does this one mean? */ - r = FP_VERIFY_RETRY; + error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); break; case 0x0f: /* scan taking too long, remove finger and try again */ - r = FP_VERIFY_RETRY_REMOVE_FINGER; + error = fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER); break; case 0x1e: /* swipe too short */ - r = FP_VERIFY_RETRY_TOO_SHORT; + error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT); break; case 0x24: /* finger not centered */ - r = FP_VERIFY_RETRY_CENTER_FINGER; + error = fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER); break; default: fp_err("unrecognised verify status code %02x", status); - r = -EPROTO; + error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); } out: - if (r) - fpi_drvcb_report_verify_result(dev, r, NULL); - if (r >= 0) + if (error) + do_verify_stop (dev, FPI_MATCH_ERROR, error); + else verify_iterate(dev); } -static void v_handle_resp03(struct fp_dev *dev, unsigned char *data, - size_t data_len) +static void v_handle_resp03(FpDevice *dev, unsigned char *data, + size_t data_len) { - int r; + FpiMatchResult r; + GError *error = NULL; if (data_len < 2) { - fp_err("verify result abnormally short!"); - r = -EPROTO; + fp_warn("verify result abnormally short!"); + r = FPI_MATCH_ERROR; + error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); } else if (data[0] != 0x12) { - fp_err("unexpected verify header byte %02x", data[0]); - r = -EPROTO; + fp_warn("unexpected verify header byte %02x", data[0]); + r = FPI_MATCH_ERROR; + error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); } else if (data[1] == 0x00) { - r = FP_VERIFY_NO_MATCH; + r = FPI_MATCH_FAIL; } else if (data[1] == 0x01) { - r = FP_VERIFY_MATCH; + r = FPI_MATCH_SUCCESS; } else { - fp_err("unrecognised verify result %02x", data[1]); - r = -EPROTO; + fp_warn("unrecognised verify result %02x", data[1]); + r = FPI_MATCH_ERROR; + error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); } - fpi_drvcb_report_verify_result(dev, r, NULL); + do_verify_stop(dev, r, error); } -static void verify_rd2800_cb(struct fp_dev *dev, enum read_msg_status msgstat, - uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len, - void *user_data) +static void verify_rd2800_cb(FpDevice *dev, enum read_msg_type msgtype, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, + GError *error) { - struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); - if (msgstat != READ_MSG_RESPONSE) { - fp_err("expected response, got %d seq=%x", msgstat, seq); - fpi_drvcb_report_verify_result(dev, -EPROTO, NULL); + if (error) { + do_verify_stop (dev, FPI_MATCH_ERROR, error); return; - } else if (seq != upekdev->seq) { - fp_err("expected response to cmd seq=%02x, got response to %02x", - upekdev->seq, seq); - fpi_drvcb_report_verify_result(dev, -EPROTO, NULL); + } + + if (msgtype != READ_MSG_RESPONSE) { + fp_warn("expected response, got %d seq=%x", msgtype, seq); + do_verify_stop (dev, + FPI_MATCH_ERROR, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Expected message response")); + return; + } + + if (seq != upekdev->seq) { + fp_warn("expected response to cmd seq=%02x, got response to %02x", + upekdev->seq, seq); + do_verify_stop (dev, + FPI_MATCH_ERROR, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Response hat wrong command sequence")); return; } @@ -1327,110 +1299,95 @@ static void verify_rd2800_cb(struct fp_dev *dev, enum read_msg_status msgstat, else if (subcmd == 3) v_handle_resp03(dev, data, data_len); else - fpi_drvcb_report_verify_result(dev, -EPROTO, NULL); + do_verify_stop (dev, + FPI_MATCH_ERROR, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Response had wrong subcommand type")); } -static void verify_wr2800_cb(struct libusb_transfer *transfer) +static void verify_wr2800_cb(FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - struct fp_dev *dev = transfer->user_data; - - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fpi_drvcb_report_verify_result(dev, -EIO, NULL); - } else if (transfer->length != transfer->actual_length) { - fpi_drvcb_report_verify_result(dev, -EIO, NULL); + if (error) { + do_verify_stop (device, + FPI_MATCH_ERROR, + error); } else { - int r = read_msg_async(dev, verify_rd2800_cb, NULL); - if (r < 0) - fpi_drvcb_report_verify_result(dev, r, NULL); + read_msg_async(device, verify_rd2800_cb, NULL); } - libusb_free_transfer(transfer); } -static void verify_iterate(struct fp_dev *dev) +static void verify_iterate(FpDevice *dev) { - struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); - if (upekdev->stop_verify) { - do_verify_stop(dev); + if (fpi_device_action_is_cancelled (dev)) { + do_verify_stop(dev, FPI_MATCH_ERROR, g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled")); return; } /* FIXME: this doesn't flow well, should the first cmd be moved from * verify init to here? */ if (upekdev->first_verify_iteration) { - int r = read_msg_async(dev, verify_rd2800_cb, NULL); + read_msg_async(dev, verify_rd2800_cb, NULL); upekdev->first_verify_iteration = FALSE; - if (r < 0) - fpi_drvcb_report_verify_result(dev, r, NULL); } else { - int r; - struct libusb_transfer *transfer = alloc_send_cmd28_transfer(dev, - 0x00, poll_data, sizeof(poll_data), verify_wr2800_cb, dev); + FpiUsbTransfer *transfer = alloc_send_cmd28_transfer(dev, + 0x00, poll_data, sizeof(poll_data)); + transfer->short_is_error = TRUE; - if (!transfer) { - fpi_drvcb_report_verify_result(dev, -ENOMEM, NULL); - return; - } - - r = libusb_submit_transfer(transfer); - if (r < 0) { - g_free(transfer->buffer); - libusb_free_transfer(transfer); - fpi_drvcb_report_verify_result(dev, -EIO, NULL); - } + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, verify_wr2800_cb, NULL); + fpi_usb_transfer_unref (transfer); } } -static void verify_started(fpi_ssm *ssm, struct fp_dev *dev, void *user_data) +static void verify_started(FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); - fpi_drvcb_verify_started(dev, fpi_ssm_get_error(ssm)); - if (!fpi_ssm_get_error(ssm)) { - upekdev->first_verify_iteration = TRUE; - verify_iterate(dev); + if (error) { + do_verify_stop (dev, FPI_MATCH_ERROR, error); + return; } + upekdev->first_verify_iteration = TRUE; + verify_iterate(dev); + fpi_ssm_free(ssm); } -static int verify_start(struct fp_dev *dev) +static void verify(FpDevice *dev) { - struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); - fpi_ssm *ssm = fpi_ssm_new(dev, verify_start_sm_run_state, + FpiSsm *ssm = fpi_ssm_new(dev, verify_start_sm_run_state, VERIFY_NUM_STATES, NULL); - upekdev->stop_verify = FALSE; fpi_ssm_start(ssm, verify_started); - return 0; } -static int verify_stop(struct fp_dev *dev, gboolean iterating) -{ - struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev); +static const FpIdEntry id_table[] = { + { .vid = 0x0483, .pid = 0x2016, }, + { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ +}; - if (!iterating) - do_verify_stop(dev); - else - upekdev->stop_verify = TRUE; - return 0; +static void +fpi_device_upekts_init(FpiDeviceUpekts *self) { } -static const struct usb_id id_table[] = { - { .vendor = 0x0483, .product = 0x2016 }, - { 0, 0, 0, }, /* terminating entry */ -}; +static void +fpi_device_upekts_class_init(FpiDeviceUpektsClass *klass) { + FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); -struct fp_driver upekts_driver = { - .id = UPEKTS_ID, - .name = FP_COMPONENT, - .full_name = "UPEK TouchStrip", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_SWIPE, - .open = dev_init, - .close = dev_exit, - .enroll_start = enroll_start, - .enroll_stop = enroll_stop, - .verify_start = verify_start, - .verify_stop = verify_stop, -}; + dev_class->id = FP_COMPONENT; + dev_class->full_name = "UPEK TouchStrip"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + dev_class->id_table = id_table; + dev_class->nr_enroll_stages = 3; + + dev_class->open = dev_init; + dev_class->close = dev_exit; + dev_class->verify = verify; + dev_class->enroll = enroll; + /* dev_class->cancel = cancel; */ +} diff --git a/meson.build b/meson.build index 17f3669b..a5891c2f 100644 --- a/meson.build +++ b/meson.build @@ -51,8 +51,7 @@ mathlib_dep = cc.find_library('m', required: false) # Drivers drivers = get_option('drivers').split(',') virtual_drivers = [ 'virtual_image' ] -#default_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603', 'vcom5s', 'synaptics', 'elan', 'uru4000', 'upektc', 'upeksonly'] +default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603', 'vcom5s', 'synaptics', 'elan', 'uru4000', 'upektc', 'upeksonly', 'upekts' ] all_drivers = default_drivers + virtual_drivers From 538038867b8057141f8060dac3e9ccd73aed45b2 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 12 Aug 2019 14:34:37 +0200 Subject: [PATCH 50/73] tests: Add umockdev based testing Initially only the vfs5011 driver is tested. Please note that these tests will be unreliable before umockdev 0.13.2. See also https://github.com/martinpitt/umockdev/pull/92 --- .gitlab-ci.yml | 4 +- tests/README-umockdev | 21 +++++++ tests/capture.py | 46 ++++++++++++++++ tests/meson.build | 8 +++ tests/umockdev-test.py | 65 ++++++++++++++++++++++ tests/vfs5011/capture.ioctl | 107 ++++++++++++++++++++++++++++++++++++ tests/vfs5011/capture.png | Bin 0 -> 65243 bytes tests/vfs5011/device | 80 +++++++++++++++++++++++++++ 8 files changed, 329 insertions(+), 2 deletions(-) create mode 100644 tests/README-umockdev create mode 100755 tests/capture.py create mode 100755 tests/umockdev-test.py create mode 100644 tests/vfs5011/capture.ioctl create mode 100644 tests/vfs5011/capture.png create mode 100644 tests/vfs5011/device diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 92b0f3ff..5441ee31 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,7 +7,7 @@ stages: variables: DEPENDENCIES: libgusb-devel glib2-devel nss-devel pixman-devel systemd meson gtk-doc gcc gcc-c++ glibc-devel libX11-devel libXv-devel gtk3-devel flatpak-builder - gobject-introspection-devel python3-cairo python3-gobject + gobject-introspection-devel python3-cairo python3-gobject umockdev BUNDLE: "org.freedesktop.libfprint.Demo.flatpak" LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546" @@ -44,7 +44,7 @@ test: stage: test script: - dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES - - meson -Ddrivers=virtual_image . _build + - meson -Ddrivers=all . _build - ninja -C _build - meson test -C _build --verbose --no-stdsplit diff --git a/tests/README-umockdev b/tests/README-umockdev new file mode 100644 index 00000000..6b44792e --- /dev/null +++ b/tests/README-umockdev @@ -0,0 +1,21 @@ +To create a new umockdev test, you should: + + 1. Decide on what to test, the easiest case is just using the existing + capture test case. + 2. Find the USB device you are testing with lsusb, e.g.: + Bus 001 Device 005: ID 138a:0090 Validity Sensors, Inc. VFS7500 Touch Fingerprint Sensor + This means we need to record USB device /dev/bus/usb/001/005 + 3. Run "umockdev-record /dev/bus/usb/001/005 >device" + This records the information about device, it should be placed into test/DRIVER/device + 4. Run the test, for a capture test this would be: + umockdev-record -i /dev/bus/usb/001/005=capture.ioctl -- ./capture.py capture.png + This will create a capture.ioctl and capture.png file. + 5. Place all files into the driver subdirectory test/DRIVER, + i.e. device, capture.ioctl, capture.png + 6. Add glue to meson.build + 7. Test whether everything works as expected + +Please note, there is no need to use a real finger print in this case. If +you would like to avoid submitting your own fingerprint then please just +use e.g. the side of your finger, arm, or anything else that will produce +an image with the device. \ No newline at end of file diff --git a/tests/capture.py b/tests/capture.py new file mode 100755 index 00000000..2ad9385c --- /dev/null +++ b/tests/capture.py @@ -0,0 +1,46 @@ +#!/usr/bin/python3 + +import gi +gi.require_version('FPrint', '2.0') +from gi.repository import FPrint, GLib +import cairo +import sys + +if len(sys.argv) != 2: + print("Please specify exactly one argument, the output location for the capture image") + sys.exit(1) + +ctx = GLib.main_context_default() + +c = FPrint.Context() +c.enumerate() +devices = c.get_devices() + +d = devices[0] + +d.open_sync() + +img = d.capture_sync(True) + +d.close_sync() + +width = img.get_width() +height = img.get_height() + +c_img = cairo.ImageSurface(cairo.FORMAT_RGB24, width, height) + +c_rowstride = c_img.get_stride() + +buf = img.get_data() +c_buf = c_img.get_data() + +for x in range(width): + for y in range(height): + c_buf[y * c_rowstride + x * 4 + 0] = buf[y * width + x] + c_buf[y * c_rowstride + x * 4 + 1] = buf[y * width + x] + c_buf[y * c_rowstride + x * 4 + 2] = buf[y * width + x] + # Byte 4 is don't care + +c_img.mark_dirty() +c_img.write_to_png(sys.argv[1]) + diff --git a/tests/meson.build b/tests/meson.build index 26b8e76d..e461c6de 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -15,3 +15,11 @@ if 'virtual_image' in drivers ) endif +if 'vfs5011' in drivers + test( + 'vfs5011', + find_program('umockdev-test.py'), + args: join_paths(meson.current_source_dir(), 'vfs5011'), + env: envs, + ) +endif diff --git a/tests/umockdev-test.py b/tests/umockdev-test.py new file mode 100755 index 00000000..7115298e --- /dev/null +++ b/tests/umockdev-test.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 + +import sys +import os +import os.path +import shutil +import tempfile +import subprocess + +if len(sys.argv) != 2: + print("You need to specify exactly one argument, the directory with test data") + +edir = os.path.dirname(sys.argv[0]) +ddir = sys.argv[1] + +tmpdir = tempfile.mkdtemp(prefix='libfprint-umockdev-test-') + +assert os.path.isdir(ddir) +assert os.path.isfile(os.path.join(ddir, "device")) + +def cmp_pngs(png_a, png_b): + print("Comparing PNGs %s and %s" % (png_a, png_b)) + import cairo + img_a = cairo.ImageSurface.create_from_png(png_a) + img_b = cairo.ImageSurface.create_from_png(png_b) + + assert img_a.get_format() == cairo.FORMAT_RGB24 + assert img_b.get_format() == cairo.FORMAT_RGB24 + assert img_a.get_width() == img_b.get_width() + assert img_a.get_height() == img_b.get_height() + assert img_a.get_stride () == img_b.get_stride() + + data_a = img_a.get_data() + data_b = img_b.get_data() + stride = img_a.get_stride() + + for x in range(img_a.get_width()): + for y in range(img_a.get_height()): + assert(data_a[y * stride + x * 4] == data_b[y * stride + x * 4]) + +def capture(): + ioctl = os.path.join(ddir, "capture.ioctl") + device = os.path.join(ddir, "device") + dev = open(ioctl).readline().strip() + assert dev.startswith('@DEV ') + dev = dev[5:] + + subprocess.check_call(['umockdev-run', '-d', device, + '-i', "%s=%s" % (dev, ioctl), + '--', + '%s' % os.path.join(edir, "capture.py"), + '%s' % os.path.join(tmpdir, "capture.png")]) + + assert os.path.isfile(os.path.join(tmpdir, "capture.png")) + if os.path.isfile(os.path.join(ddir, "capture.png")): + # Compare the images, they need to be identical + cmp_pngs(os.path.join(tmpdir, "capture.png"), os.path.join(ddir, "capture.png")) + +try: + if os.path.exists(os.path.join(ddir, "capture.ioctl")): + capture() + +finally: + shutil.rmtree(tmpdir) + diff --git a/tests/vfs5011/capture.ioctl b/tests/vfs5011/capture.ioctl new file mode 100644 index 00000000..c7ae6094 --- /dev/null +++ b/tests/vfs5011/capture.ioctl @@ -0,0 +1,107 @@ +@DEV /dev/bus/usb/002/017 +USBDEVFS_GET_CAPABILITIES 0 7D000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 01 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 38 0 00008C53DE4A4E000000041E0105000100006C3B5712A6C00000000000000100000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 38 0 00008C53DE4A4E000000041E01050001000A6C3B5712A6C00000113000000100000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 38 0 00008C53DE4A4E000000041E0105000100036C3B5712A6C00000123000000100000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 19 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 64 0 000000030400400CD07104A002000000B84704A0152D6935190000000000000058070060B74187D8000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 4 0 B5C457F9 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 39 39 0 0B000000000000000000000000000000000000000004000000000000000000000000009F000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 6 0 0000FFEF3013 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 40 40 0 0B00000000000000000000000000000000000000000500000000000000000000000000AB00000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 7 0 0000FFFFFFFF12 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 578 578 0 069CF19D71C313DF5FE47A1FC717539A1AA1D7B66EBEDF1F9F444222FA2A6AAB2BF05639E37B539A1AA1DBBA62B2E465E5DB68047998DE8F23FBECAD76CAA2EB6138C7AB6E2E78F979138AE59022638D0E9325495AC8A3D87EAE12F62C1CFC484F0E4822FB4BCE7EDB2D91E0C8782EAF2FD4036F1259C62640882E62BA066CC97A8493CF14154487E20997E6CE7E28A92953D7B8D15330156E953EA27ACA9C1D9DEB5F15EF4834CCCB02A6D6A780F23F7E9623AE42F129F5AD5A355736AAAF97E81EA2D3FB4B1D9C1C0684EB9E2CD41894447E4B1291F28B0745DB52BB2E5363E338B8954D9BCF0705DD4CE239AFA951DBAD19C8136E0A2FEA12B92555B664047F146E1208FBBDBD1DC6E284502060A090D2748A18A4D9E969B21E73AB1B7BBB3BE04223F929498909D24C29F12165AC2C97306CB404F43DBD06A0C61ECE7EB333882E439B2B37F070CB91F12BFB8B48CA3997FB21B9CD0E8C7F8DEC36E6EA27A51E402AF222CA07853EC8AE76A6F071F1AB6B046DA9CA062C66A5CAB04B2B62EBD5610DF04626C3449F0C63BBAABD7EF27400662B7A62A10780338D1FF745CB5E24EB84ED274461FF0CA73BE353058404EE234CB5791AF3A066204C942472F37339F897DD6454F26BBAADBC676678BB5E6DFB8AA2743DF5D472C71ABD0E0B2C8C4A0C60B8085EDF5F05335CB57E1DFCFD25BA95C4A7DAEA6AB1311CC4E507C4C59D28CD3CE98949D4FF7F528A9B7FBC8EF5CF0BD949488880717DABEF472BF77B2D793FCFBFFF3F6DF842EC7FE8ED42E61D4D32FA6A0AD7A77CCBA77BCBBF71F348 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 1A + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2354 2354 0 06FE93FF03BA6AA6269D0366BE6E2AE363D8FE9B4393D70383388CE03888589414AFC9A27ACA965EDE652736EA3A4E8202B90F4B9717F71A9E75C38F53D39F7FFB10E6AA76F6729317FC4A26FE762AEA6A893FF32BA3FF9F1FFC4A06DE5638D858BB0D21F971199919FA4C40981078D858BB0DE139B1D99919FA6C7EA272C67DF942F4865ADAD206863D6F08D000D810902BFDB76BBB67A0209B3536EA3AA20C88337D1AC2122AFE7EC58C17307FE0CFB0944E36EE3E5E9616CD9FE13BEB8B5BDB008AF22AFA0EC848F36D12C81808DC5CE70179A1713DF474CF8417CF7FE0205F7BFBD60E1B65A500DC6AE37ECE4BCE6822B8D7AE33509C1446FA1485354878F823A38E567739FA76A591B434E14DA8351E9EB36B6A3AF9D40D9AD902F494541FE65B8C72C9A3EB6932041C4369F93FBE65F6FE039EF4295982022FF76766A603226B2719BACA2AAA7DC108F663A253D0BA3E51AC3870ADDD0686AB73F2A162C32C99DC47EA7ABA3AE1614C94A6C4098545739F43A5DD1A9648F29802A0CE1295748658447527E3630AB7A5BF0B6A9DA671F020E9640F0833E46F0F11A0C0378B5425F22BA6CDA02345F0F99901CB6DB73F82990AFE2C2829A4851560D508CD68049AFA395B9935150AFD514F3F8597E52317BBA756F6B5745F069AA2F1B0FA94BFC73822CF2DEB68B3C709BDC76567FB5DD1716BD7B7A537E57E19161A7BB715D395F92191C746C6AC2F40209B77DCFE845294E7F228C8E53C2FEF12BF2FEF6FB43419C1D0864574982D8C56437590A143F6BA48589961E2F44089049140BB38C34F8399EA9AFB4199234DBC0F46953CC45B04F91D5829944CCA9CE49635E5C42396DF54C1AD64D435237D66C6BDE44D95683789A0365BD8B1A76E9A662341E9931B741D92F1F3B04F5C609D9CBD7ECE2F39F46CDF8D8E2A3C89C04ADF0E8D0EE569A5DC2E4D40C3FD185138CDAE5EE49F88A07B066540926C6B409B1B4121009D288952C7F510A05147361EAEF879F90794F8A1583B6AD9011632E9F0C98009CF89E53D8DDB5ADA30B3DC089FC704D544F10FD46C6E0FFF2F106AFA4CFD76F522FE9E4173DAE670A31F55D46CA163061C8CCD1FB222884B2287E0AA1E7EA813C31306CEBCC8F42255E927BC04468508F3640CC989E52E2CF44FE11A7700A8276ED5B96DCFB950DE0E11DF4AFADC1C9C4BFF53AB1BD90A829B4884D07AFFD573B5F3F56E0C68A84E8802D62C31527713EEF874D80E7091A037821CCF7F39D651F80569BD07C268CD1A946A91FF5FBF3F76A56933C0A82EAD76621DC2FEE45692495D22FDE86E8804CD66FA90335BF132FF82E9F34727256949E9B96634579A9867502B9D7D8F42C20F305084264D74069026CC04B4565F26AB851C7CEE23E0858313DF97533861B78539598A361A389B9DF9379BF14242E2392D5282D0D5B547C109A73C84F2780ADD058B17A765B63E0069237D08977AFD2A933FC777B566EEB764A8664CDF7A24D972EE3A88AEA6D9BA2EEF3421997F5F14D6DC1D8AE62D7F87EC4238FC565515EE58E65B4B895AD27B9183E70D0724A81E7A588092E1294C4DDD37E6563A850986725D8D57744682595D22F1DDF6845077CD5B8FB755D1516F014B01A5396B22082C1430A2C10CAC56E495BD2047015E7A6E1632942E068AD9EDC51D1BC1119DBC2F956BF98DB1130A4D038FC3A5F887395A10E552744837EC6C4199782DEE36E81CD0F80227D5510A9AD53CAA897A9B0ABFA23182EE862098010B50FE922133CDA509F141B31535DC2EC2A81D7012954E4895494981D2F06CDAAB832EBE72E17CCAA672F1A32727E1A7C74C3E7B6525DE68C67868CEFD8259D9F42CAD8043E277C2874CE171B131EA6A479FBEEB2830E2D81D67FE432303CC5C0AD00522C35E75F5D8001121E243D16439D261901F9CC6214E1F86CF0C25A70C9048F8AE2FAF55B1DE8E1CBB138EF4117E43BEF6A773ABDCE53E3F09CAE21B15726A7000504A8187713A1351B4FA04AF33EB5B0D8C0C7693FC41B6FEDF08D02778A32210D35F88E6A9806605729F666D0E1EAA03CCE1380F3BE0B04DADB44C731BA6137302DB031D528634E48E2E5CC9B8902C4741371393BE66CA622537E87F49923FAFC2403E4E07F2483505855EDEF32BDAE1229314A145D9E002FB3FF9BFD30BBBED6CEC95E19D60ABEBBA61B9876938C1BC8C0CD7577AA2AFCD2CF129B7D90D31DAB81D8C12FF79CA383AAAE80CF9635A58149775512008B8EE6FEF05EE8161D200D34B9C365D6EC435AA29322F6319FA828222F9D7B2E84B2D4F0CC7EB0F5E9D18AB0B62C7B37C274931227558BC6F721030B863F89E5B1B77B5280383AE76F7CA09B1696D13DFA7640CAFBEB3661D0A51C0E0A0D638F35BA2C156E578D6A6E968C84B686DC139893BE8701AE689B1DCAC9E750E6A5595E5A56547B7812DD565C5AF3F469B77E958385A19D2C1C33B4B0BCBDA5EEB05CE7880496B73D523734A597C976C52BDC87AFA32B274325E863660E161F8E6753CED8EFF22FA7D5B8088E3E17AB903424A367674AF6C1A568E9CDFBF96F680CC1426650545BE08F4A404F697175C622E74A76767C71C88C79FEFAF6FAF56F0DEA21232D070895CB0753563E262DF5D3963D0979516EB3B6FBDA0C2BF3C2A985156C4B989A1292DE1C2C26EBEFC64F458A010E228A4BF29452D047426EC3B900CD4641EDF5F84325E8636B67BF942F09D45F59555D50E1476AC7C00C04893583096227EAC2E95BBC51FCF03D153E8C2BD67B7FF2CAE15EB934B9BB763E3589EE63EEEBA7AFA2197FB2393F333B368DEB26ADA925BDB60F2974F9FEF1F9D467008D00030F171AAA0CB13C30BC644FF355E86568E43C17AF0944C9CEC22A01B6507DD0D05D151EAD0B369B9B160E2595733EB3B8352D06BD1AF75A5459715AEF09A42921ECD4FF40264BC6C3ABB3B61C8A1C86500CC165CF49DE71C7C35BC42F79BA6157510954E9DF921F49050B567D1588030F11194FE6900FDF9BE6313C84865BD3C7EBB1AE25114DF72E222A279F9D40C8DC90CAD53E0A5AE039353D30888A57DFCBA7FDE2291D44FE272B232E969449C1D599C3DCE7D3873DE4E8E0ED55578A081C80D815266439B4E2FEFCE3E8D50AE1BBA50D5C77ABF3C9101C1419A1A37EF6E22E746B003468D20B070F02BAB865E6F21E455AC1F52A51059BAB33B900CD46432B33379FF96CF4E2B62CB75C3AF6A2A7CFD7D0783EA80907C149E65B2DE8E14CEB4A86BD1A17548CA2088930569639DF1F338C4573AC656D0039368DEAF8737579717CC7A16CE7E1EDE5E85325E82329E4AC873 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2221 2221 0 022001010003000900042004300000000004030009001820043000000000040300090020200430080080000403000900242004300000FF0104030009002C20043001000000040300090040200430AD010000040300090044200430AD010000040300090048200430AD01000004030009004C200430FF03000004030009005020043000005003040300090054200430013E020004030009000021043014000000040300090004210430010000000403000900082104300100000004030009000C2104300100000004030009001021043001000000040300090014210430010000000403000900182104300100000004030009001C210430120000000403000900202104300400000004030009004021043000000000040300090044210430010000000403000900482104301000000004030009004C2104300100000004030009005021043001000000040300090054210430000000000403000900582104300100000004030009005C2104301F0000000403000900602104300F00000004030009008021043000000000040300090084210430010000000403000900882104301000000004030009008C2104300100000004030009009021043001000000040300090094210430000000000403000900982104300100000004030009009C2104301F0000000403000900A02104300F0000000403000900C0210430000000000403000900C4210430010000000403000900C8210430100000000403000900CC210430010000000403000900D0210430010000000403000900D4210430000000000403000900D8210430010000000403000900DC2104301F0000000403000900E02104300F0000000403000900A0200430EFE100000403000900A4200430000000000403000900A8200430FE2100000403000900B0200430000000000403000900C4200430470000000403000900C8200430000000000403000900CC20043020000000040300090004000038000800000403000900080000380012000004030009000C00003801030200040300090010000038010702000403000900140000380C0C8A000402008005FFF98720834884208348842083488420834884208348842083488420834884208348842083488420834884208548042087480420894804208B4804208D4804208F48042091480420934804209548042097480420994804209B4804209D4804209F480420A1480420A3480420A3480400855A0420875A0420895A04208B5A04208D5A04208F5A0420915A0420935A0420955A0420975A0420995A04209B5A04209D5A04209F5A0420A15A0420A35A0420A35A0400856C0420876C0420896C04208B6C04208D6C04208F6C0420916C0420936C0420956C0420976C0420996C04209B6C04209D6C04209F6C0420A16C0420A36C0420A36C040086480420884804208A4804208C4804208E4804209048042092480420F7480420F9480420FB480420FD480420FF4804200149042003490420054904200749042007490400865A0420885A04208A5A04208C5A04208E5A0420905A0420925A0420F75A0420F95A0420FB5A0420FD5A0420FF5A0420015B0420035B0420055B0420075B0420075B0400866C0420886C04208A6C04208C6C04208E6C0420906C0420926C0420F76C0420F96C0420FB6C0420FD6C0420FF6C0420016D0420036D0420056D0420076D0420076D040083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842083688420836884208368842000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A000800100351091003510903000900002004308000000004150008000000000020280000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 256 256 0 01010000040F081063666666656866646764666763666668696867636868676B6868676668666A676C6768646768696B6A68666A696A66676867676668666967686655005165686A696260616162696767646A696969696A6D6B69686B646864686865696A6B6A696766686767666B676C6863676665656667646768656763646A646667686567656666676566656562656763616667676464676668686667686767676767666A66656865686767676667666966686667686968686A6566646665696868676969666568686967646865676666666764666564666668666669646667646665656666666669686466666465696765656769656364686A65636366 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 64 32 0 6668676867676364666368656766666463676664676464676766696466666865 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2770 2770 0 066B066A76CC1CD050EB7510C8185C9515AEA8C810C0B07AFA2196FA2292AE78F843056EB66662D551EAF0E539E9A1199D2680E038E81CCA4AF1BFD800D034D95DB600F22AA2AA7CFC47DDB860B0D0EF6FB4462CF424BB7B042096C51DAD32324D69DFA07AAAB660E05B89F62CFC14C242F92359815131EF6B8036528A3A5A641BF7BDD40CDCBC54D03B0D4C9010709014FF6529F57555B531DA88C51999F939B95AD0BC64EC8CEC6C8F05C91199F919997AC28E56DEBE3EBE5DE3CF179FFF5FDF3C828E56DEBEFE7E9D23CF179FC948C8F6074D0498FB9A37EF553160DA38B131F7B1DD05B5E362E219CEA25F118E6E08C0662AF24E2401AA544301DADB9457B240DEAF873761E06016A24FA71478B13A59780CC55405C68E57EA3D25554146DC0C713F813AAA8F6B950E68ADED90A020FB7B568EAFFC3F9E70C59872C120D45705602E9535CC9F0229A9845CDD8B48DEA7171E49DC945775CC5815FA49B57F7796B2C4083A72B2A029911DCD7D5B9A1AC17B1D205C1C799E454217CCD537FB6734810CEC5FCD05508758A48303F2088BA25CE5BC3E5D45C6F54DE37611D91A78FE1FC173DF7F9F1F4C22DC2D1DEF45E6318E70C250A238EED56B07C2824A89ABBA545D7CEB96A626FD7D5088A9FE3D3FED7F91009550B1314BC6A9F07211DD742DB3CD875D3919914A5E92DEDF894A0BEC598D5E2E6EAEE6311562E7FD363C256CB1F50802429FEF34B49941FD8809BE66E7699D6AE827954ADB9549DF8567C73DAAE478ED90A079E6C2AA576501E76C2E08F4587A5EB9A3F0C62BD2E0C421BC9778204AFEB9DB5FA1B59D4FE42E4E6EC1D5FD0309C3A382786C44B9148444C41F9FB26A1A5A9A16C4F3A279F8A261B050E5FB003A9A7AFA699A946F56B60191CA0B762EF8888828F3773861A1A747B65BEEE27EEEBEDF5BE16B04ECDDB94978E2EC8749D1B9FB50941571D5E4BA79F5645ADE36357555DD067851A82F4C879B56B9DFB5C95781BA6B0FAF8A2CE12DBBDC6A20B40CCEAE2E50501C0693F7F7E7485257A9501471E13A0D5388BAF220409325EB93B76FA8E813A501DFFD861B31413DC8825911341DE698B165DE3E52D3A8BAF60BA8C8A526F14C854FFF57D292D91BEBAA3C15C25F74024E96EE88FA61E7FC92808B52A0C5B82E5F77C7A767552E9927FD478547EF345F227A6011715DA6C006FE6B04C4ECB50F6815ABCB2EE73C86C13C82E23F4F942E48F5E8A8A0653854C71FAF62A104367FE13BAD2FED4A666E1343C11D554DD4DEFB813359951E7C8F41DB4EE663252E67A67D28AE91C31A8A24FE69DEA233008444622A08645B02B6D004BD44C1C35AC96DF0C6615EDE05BFD9E44A2ABC86A11B6DD07E1ED2697FC3A331418AD9F06EDE5C7BCBA74DE82E982CB10D23431D452A031D5FC000805BDBF62E3CFC1849AF1A9770C39265E61C90FF66E88B8B2BF0C48C5A581A5311C957DBB818F8F4656E1468707B3B1B93483E72AA36DC94F0FA0D62089A7072F10F5874AF9F33E28295338FEC4CEC97370CB2DE1B5B0D8C0C961679F07211098D27A6C9831E6262C2192D5680F28F19B06256F2D2F0BD61AABDCB674B390492591B3F3EFACD81379674C148CC59814567D743A3C1F3B97A788B3DB161D1F736B66DD7B18CA6E6AE8BB00E6257ED5FBB3B52FE86FC216371EC6165C2E2854E8FD202096717893999EDFB4BACDE8B8B63C9343A5202E725CE6C25B8C8D2794FEFF6ED3B9B83F1CA5C4EFE54D808B800C4E62A923CF91FDDD7AFD3C92B75C5A544FD25218EA9EFA430A69122AB27B21ADEFC4BDF3F5D6F25E6E417A12DFD4D6BAA2AF14B2D1032723A1F249AF6E6528F4D6FD84C887A0874E2C0D16FE667FF2ED75407E420FC8E4E8ECC4DAD73C16DAF45E7DC620E0490F0C060BBCFBE300CF0923FF8F39D20C78F9D39E2327D9BC9B4231FAA795BA6EE8AE807FEE492C248A06808DB6D89F4A4CC0C14CBF5CCB66F2D0D855E402852F8CF59A385355A82325233F0282F01DAD3E4013DC1AFC7DD70470B874107CA57E455D1525081086AFD80B030EB6B469EEFB87B5ABA0FDFC5F7556BFD6EDED41E855D97F522B00EDD6AA863E5AC1178706ACA9D37A5B19161331FFA588837A97AC250DC7B827832E64439098952E88EB387C70B894F09DD0F6D01E9CB1BAA44972399F3D427D7198D15579C152C96DEF44F2715D9257151AC3E12F478B11A8652E09DAD95445030C0A2C90E0CDC6FD3A1D136DC4039C3877DC6AF8D01FEBADD0D4F6384E671E2AC38AEC2108DA61C72B7F79B59C4EF6F429A0B5D9E9C65D3FE11A240984FA5214E3AF237CA6F2C9856E775B9A3AB4A74102890F0B89BA01E7232806281047DA2ECD46C0C64E69F3308865CC1A065BDBA92494044210AF65DC119A9C9A86BB3C4EA31487C1933CFA1CFC5685FC93411E17B5CECBA3BBB6CD09D73C0DCF0C8112674AFADE6050D3E489F57076FAF875E4AEC6C39FE1984AF2F02DA76CE899B44D3F9228F1F72F00E0E47B2087545C51E9EB36B7614B131EA503EFBBBED6CEC17034FB2E0A756ED351B740C3415579E445075AD36F4D1B14D4A11CAF89A5F2DF445FB219735F77F4CF907DD699B1591C8305923DDBFDFF76D795B8092F0394BDE6FA132A466E8617880E4EE1076663699EF43EF9DB65103930DCBCFAF1EFFAD3DAFDEF64610911107B3D306ADAED355B93B26D53161E5A56597BBE21374D056A6A31DC7770C0E12F1EA8B7873F13DBDB40E6390EC660C5627C631076A006DE086347DC55DF0320FD2680991C0E126C215B8161CAECE15232844E8E08181DDA355EE10C4743F445415639FD606FC1E1CCB7C3B2F1FF5F5F5AF799F6582795BC6ED7617D292FE3CA18A0A07DFAFEF2FEE7CC904942766E162EBFD901AC829298952763860105090B0F2649A2010B050D0891BF6EE7E1E8E867D494118CD8F6AD706A680545C166FEE398408B101B3D35359D8B7AF3F5F5DFFA4D29E46A60AEAB87EC668D2E224F95C2533A3B9284848E83377396B2BC3426246E00BCC8C2CCC4CDCD13FC5F91BB7372E543C33A817864C94C248832363A3A15FED61B10177BD3AED55F81BA8B49C10814B1E0696F6E4401D6B27FFDF22F2D29006F84472D232B29B09E4FC6C0C4C33F8BCB4ED9DDD1D4FF0C06C94248C406890D4B46C6E02C3819622CEAD0C9CE7474EF498823E5F7D9FC5F3539AFA56B6D3E0A94DA63B511991E752DE0EBEC3F373A8127449ADEDABE6C2FCD5ED5535E3193D4DC1E6560081017B86E9807C1F12902E703851AFCC2C86FDEACB106D0FAACD323509D24218783A228449DE6D01C36AB22D52A330798AEFD1439E14A7F70D2D34413D44A5C6E38778C2A74FC505F7B47FE217E6551CCFC42CFC0925385B290977EDCDF0733B5A8951566EB5C76480655CCE139D2E7E84A4DE3D52B8CB8F82013F6A224BA3C0308AF1E6DD067B18BDD8272016CD4D177756D461C01B0E8A6E5FD86D31D3C302991A0CB9704BDF8F654583C5A971C1BB7AFA2197FB23937FB2308BA9D30BDBA666EC37036B3084449715AE1975AD1D01D757EC265C84549C4ACA714F35ED3DD50383382258805030F070AB1D71A91979B939E25438E05030F070AB1D71A91979B939E25438E05030F070AB1D71A91979B939E27C19C111559C1CA7035F87379741C17A7C10C87864A3239882E339E979BE3E85C3A278A8B876F44FF1924898448303B886F923F33FEA68D3537EA6974580B1DA69A7DF6C9DEC6910ED81DB0262C7469D0E60B82D4989A8C073AEC277F2A304C284E83080D657D73D3E57AEA8CD2477B1F79B43F3A524A4CEC0A9404B2ECFF32D1ACC1130E7220361D21716242DFD54ACA35693D38504846E6D04FDF0957C6FA9EF835BEB8B4BCB10A6CA12A2C2028259EE825EEE76A02299 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2855 2855 0 02B000620003000900042004300000000004030009001820043001806400040300090020200430080080000403000900242004300000FF0104030009002C20043001000000040300090040200430FF030000040300090044200430E6030000040300090048200430E703000004030009004C200430E80300000403000900542004300092010004030009000021043000000000040300090004210430010000000403000900082104300100000004030009000C2104300100000004030009001021043001000000040300090014210430010000000403000900182104300100000004030009001C2104301F0000000403000900202104300100000004030009004021043000000000040300090044210430010000000403000900482104300100000004030009004C2104300100000004030009005021043001000000040300090054210430010000000403000900582104300100000004030009005C2104301F0000000403000900602104300100000004030009008021043000000000040300090084210430010000000403000900882104300100000004030009008C2104300100000004030009009021043001000000040300090094210430010000000403000900982104300100000004030009009C2104301F0000000403000900A0210430010000000403000900C0210430000000000403000900C4210430010000000403000900C8210430010000000403000900CC210430010000000403000900D0210430010000000403000900D4210430010000000403000900D8210430010000000403000900DC2104301F0000000403000900E0210430010000000403000900A0200430EFE100000403000900A4200430000000000403000900B0200430000000000403000900C4200430140000000403000900C8200430000000000403000900CC200430200000000403000900502004300002A8020403000900A8200430FE210000040300090004000038000700000403000900080000380015000004030009000C00003801030200040300090010000038010702000403000900140000380C0C05000402008005FF8307205F820720FF8307205F820720FF8307205F820720FF8307205F820720FF8307205F820720FF8B0720608A0720FF93072061920720FF9B0720629A0720FFA3072063A20720FFAB072064AA0720FFB3072065B20720FFBB072066BA0720FFC3072067C20720FFCB072068CA0720FFD3072069D20720FFDB07206ADA0720FFE307206BE20720FFEB07206CEA0720FFF307206DF20720FFFB07206EFA0720FF8507206F840720FF8D0720708C0720FF95072071940720FF9D0720729C0720FFA5072073A40720FFAD072074AC0720FFB5072075B40720FFBD072076BC0720FFC5072077C40720FFCD072078CC0720FFD5072079D40720FFDD07207ADC0720FFE507207BE40720FFED07207CEC0720FFF507207DF40720FFFD07207EFC0720FF8707207F860720FF8F0720808E0720FF97072081960720FF9F0720829E0720FFA7072083A60720FFAF072084AE0720FFB7072085B60720FFBF072086BE0720FFC7072087C60720FFCF072088CE0720FFD7072089D60720FFDF07208ADE0720FFE707208BE60720FFEF07208CEE0720FFF707208DF60720FFFF07208EFE0720FF83A7005F82A700FF8327005F822700FF8327005F822700FF8327005F822700FF8327005F822700FF8327005F822700FF8327005F822700FF8327005F822700FF8327005F822700FF8327005F822700FF8327005F822700FF8327005F822700FF8327005F822700FF8327005F822700FF8327005F822700FF8327005F822700FF8327005F822700FF8327005F822700FF8327005F822700FF8327005F822700FF8327005F822700FF8327205F822720FF8B2720608A2720FF93272061922720FF9B2720629A2720FFA3272063A22720FFAB272064AA2720FFB3272065B22720FFBB272066BA2720FFC3272067C22720FFCB272068CA2720FFD3272069D22720FFDB27206ADA2720FFE327206BE22720FFEB27206CEA2720FFF327206DF22720FFFB27206EFA2720FF8527206F842720FF8D2720708C2720FF95272071942720FF9D2720729C2720FFA5272073A42720FFAD272074AC2720FFB5272075B42720FFBD272076BC2720FFC5272077C42720FFCD272078CC2720FFD5272079D42720FFDD27207ADC2720FFE527207BE42720FFED27207CEC2720FFF527207DF42720FFFD27207EFC2720FF8727207F862720FF8F2720808E2720FF97272081962720FF9F2720829E2720FFA7272083A62720FFAF272084AE2720FFB7272085B62720FFBF272086BE2720FFC7272087C62720FFCF272088CE2720FFD7272089D62720FFDF27208ADE2720FFE727208BE62720FFEF27208CEE2720FFF727208DF62720FFFF27208EFE272000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A0008001003181C1003181C030009000020043080000000040C000100000D007801500100000E00000002000000006E0065006500720069006E0067005C0070007200690076030000000C00003800070000FD00FFFF0C00003802070000FD00FFFF0C00003800080000FD00FFFF0C00003802080000FD00FFFF0C00003800020000FD00FFFF0C00003802020000FD00FFFF0C00003800030000FD00FFFF0C00003802030000FD00FFFF0C00003800040000FD00FFFF0C00003802040000FD00FFFF0C00003800050000FD00FFFF0C00003802050000FD00FFFF0C00003800060000FD00FFFF0C00003802060000FD00FFFF1000003802030000FD00FFFF1000003800040000FD00FFFF1000003802040000FD00FFFF1000003800050000FD00FFFF1000003802050000FD00FFFF1000003800060000FD00FFFF1000003802060000FD00FFFF1000003800070000FD00FFFF1000003802070000FD00FFFF1000003800080000FD00FFFF1000003802080000FD00FFFF1000003800090000FD00FFFF1000003802090000FD00FFFF10000038000A0000FD00FFFF0E00E000000100010001001F010000000000FE01000101010001001F010000000000FE01000101010101001F010000000000FE01000102010101001F010000000000FE01000101010101011F010000000000FE01000102010101011F010000000000FE01000104010101011F010000000000FE01000104010201011F010000000000FE01000108010201011F010000000000FE01000108010401011F010000000000FE01000110010401011F010000000000FE01000110010801011F010000000000FE01000110010801021F010000000000FE01000110011001021F010000000000FE010F000100021000010001110002000E00120001000E150008000000000020280000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 17216 17216 0 01FE01000101C8107F7A7E7A7E797E7A7E7A7E7A7E7A7E7A7F7A7F7A7F7A7E7A7F7A7F7B7F7A7E7A7E7A7E7A7E7A7F7A7E7A7E7A7E7A7E7A7F7A7F7A7E7A7E7A7E7A7E7A7F7A7E7A7E7A7F7A7E7A7F7A7E7A7E7A7F7A7F797E7A7E7A7E7A7F7A7E7A7E7A7F7A7F7A7E7A7F7A7F7A7E7C807980797F79807A807980797F797F79807980797F79807A80797F7980798079807A8079807980797F797F797F797F797F797F797F797F7A807980797F797F7901FE02000101D8207F79807980797F797F797F797F798079807A807980797F7880797F79807980798079807980798079807A80797F7980797F797F797F797F797F797F7980797F787F797F797F797F797F797F797F787F7980797F79807980797F79807A807A7F798079807980797F7B8277827783778377827782778277827782778277827782778377827782778277827782778277827782778277827781768176817681768178827782778277827701FE03000101D830807880788078807980788078817980798079807880788078807880788078807880788178807880788078807880788078807980788078807880788078807880788078807880788078807880788078807881788078807980788078807880798079807880788078807C8475847485758576857584758374847485748475847584748475847584758474837484758575847585758474847484748474837484748477857584758374847401FE04000101D840807980798079807980798079807980798079807980787F788078807980787F797F787F797F787F7980797F78807980797F79807880797F788079807980787F7980787F7880797F79807980798079807980798079807980797F797F7980787F7980797F798078807C8575857485758575847584748474847484748574847484748473847484748474847484748473847484748474857484748473847484748478847584748474847401FE05000101D8507E7B7E7A7E7B7E7A7E7A7E7A7E7A7E7B7E7B7E7A7D7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7D7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7B7E7A7E7A7E7A7E7A7E7A7F7A7E7A7F7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7C8277837683768376837682768275827582758276837682768275827682758376827682768275827682768276827582758276827682768379837682768275827501FE06000101D8607C7C7C7C7C7C7D7C7C7C7C7C7D7D7D7D7C7C7C7C7D7C7C7C7D7C7C7C7C7C7C7C7C7C7C7C7C7C7D7C7C7C7C7B7C7C7C7C7C7C7C7C7C7C7D7C7C7C7D7C7C7C7C7C7C7C7C7C7D7C7D7C7D7D7D7C7D7C7D7C7D7C7C7C7C7C7C7C7D7C7C7C7C7C7D7C7C7C7C7B7C7C7D7C7F787F79807A807A807980797F787F787F787F797F787F797F787F787F79807980797F787F787F787F787F788079807980797F7880797F7B807980797F787F7801FE07000101D8707B7E7B7E7B7E7B7E7B7D7A7D7B7E7B7D7B7D7B7D7B7E7B7D7B7D7B7D7B7D7B7E7B7E7B7D7B7D7B7E7B7D7B7D7B7D7B7D7B7E7B7E7B7E7B7D7B7E7B7E7B7E7B7E7B7E7B7E7B7D7B7E7B7E7B7E7B7E7B7E7B7E7B7E7B7D7B7E7B7D7B7D7A7D7B7E7B7D7B7E7B7D7B7C7C7C7C7D7C7D7C7D7C7C7C7C7C7C7C7C7C7C7C7C7C7C7B7C7B7C7B7C7C7C7C7C7B7C7B7C7B7B7C7C7C7C7C7C7B7C7C7C7C7C7D7C7D7C7C7D7C7C7C7C7C7C7C7C01FE08000101D8807A7F7A7E7A7E7A7E7A7F7A7E7A7E7A7E797E7A7E7A7E7A7E7A7E7A7E7A7E7A7F7A7E7A7F7A7F7A7E7A7E7A7E7A7E797E7A7E7A7F7A7F7A7E7A7F7A7F7A7F7A7F7A7F7A7F7A7F7A7E7A7F7A7E7A7E7A7E7A7F7A7F7A7F7A7F7A7E7A7E7A7E7A7E7A7E7A7F7A7F7A7D797F79807980797F787F797F797F797F797F797F797E797F787F797F797F797F797F787F797E797E797F797F797F7A807A7F79807A7F797E787F797F797F797F01FE09000101D890797F797F797F797F797F7980797F797F797F7980797F797F7980797F7980797F797F797F797F7980797F797F797F797F797F798079807A807980798079807A807980798079807980797F7980797F79807980797F797F79807980797F797F797F797F79807980797D7681768276817681758176817782778176827781768176817682778177827681768276817781778177827782778377827782768277837881758176817782778101FE0A000101D8A0788078807880788078807880788078807880788078817880788078807880788079817880788078807880788078807880788078807980788078807980798079807881788078807980788078807880788078807880788078807880788078807880788078807880787D7584748474837483748474837584758474847483748474837483748474847484748374837484748374837584748475847584758575857582748474837584758401FE0B000101D8B07980798079807980797F7980787F787F79807980798079807980798079807980798079807980798079807980798078807980798078807980788079807980797F797F787F7880788078807880787F787F797F797F788079807980798079807980798079807980797D7484748474837383748475847484758574847484758475847484748475847485758574847485748474847585748575857485758574847582748475847484758501FE0C000101D8C07A7E7B7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7B7E7B7E7A7E7A7E7A7E7B7E7B7E7A7E7B7E7B7E7B7F7A7E7B7E7B7F7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7B7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7E7A7D7683758276827681768276827683778376837683768377837683778376837683778376837683768376837683768376837683768375827680768276827683778301FE0D000101D8D07C7D7C7C7C7D7C7D7C7C7C7C7C7C7C7C7C7D7C7D7C7D7C7D7C7D7C7C7C7D7C7D7C7D7C7D7C7D7C7C7D7D7C7D7C7D7C7D7C7D7C7C7C7C7C7C7C7C7C7C7C7D7C7C7C7D7C7C7C7C7C7C7B7C7B7C7C7C7C7C7C7D7C7C7C7C7C7C7C7D7C7D7C7C7C7C7C7C7C7C7C7C7C7C7980797F797F787E7A7F79807980798079807980797F798079807A8079807980798179807A80797F7A807980798179807980797F787F797E7A7F79807980798001FE0E000101D8E07E7B7E7B7E7B7D7B7D7B7D7B7E7B7D7B7D7B7E7B7E7A7E7B7E7C7E7B7E7B7E7B7E7B7E7B7E7B7E7B7D7B7E7B7E7B7E7B7E7B7E7B7E7B7D7B7D7A7D7B7D7B7D7B7D7B7D7B7D7B7E7A7D7B7D7B7D7B7D7B7E7B7D7B7E7B7E7B7D7B7E7B7E7B7D7B7D7B7E7B7E7B7E7C7C7C7C7B7C7C7D7C7D7C7D7C7C7C7C7C7D7D7D7C7D7D7D7D7D7D7D7D7C7C7D7C7D7D7C7D7D7D7D7D7C7D7D7C7D7C7C7C7C7B7C7C7C7C7C7B7D7C7D7C7C7C7C7C01FE0100010188107D7D7D7C7C7C7C7C7C7C7C7C7B7C7C7C7D7D7D7C7E7E7E7D7D7D7D7D7E7D7D7D7D7D7D7D7D7D7D7D7C7D7D7D7D7D7D7E7E7D7D7D7B7C7C7D7C7C7C7C7B7C7D7C7C7C7D7D7B7A7B7B7B7A7C7B7C7C7C7C7B7B7C7C7C7C7B7A7C7C7D7E7D7D7D7D7C7D7C7C7B7D7C7C77817680768076807882798277827882788378837882788279837A8378827683788479837A8477837883778378827781768377827781767F788279827782788201FE020001019820827683758475827684758375837583768476837682768476847784778578847684778477847783768476847784768577847682758277837582758276837481758274827581758175837582748374827583758274847682758176837683778376827682768275827B81798178817882788179817981798279817A81798279817A837A817A817A8079827A827A8179817A8179807A8179807880777F7780778078817981798179827901FE03000101983089718870887089718871896F897088728A7189708870897088718871897189718971897189718970897188718971897189728871876F8770876F87708870887087708870876F876F8870886F88708870886F8870887088708870887187728970897189708870887A8672877288738873887287738872877187738873887388728772877387728772887388738873897386728672887286718571857186708774887287738872877101FE0400010198408A6D8C6D8C6D8C6D8B6D8B6C8B6E8E6F8C6E8B6D8B6D8B6C8A6C8B6E8C6D8B6D8C6D8B6D8B6E8C6D8B6D8B6D8B6D8C6E8D6E8B6E8C6D8A6C8A6C8B6C8B6C8A6C8B6D896C8A6D8B6D8B6C8C6D8B6D8A6D8C6D8B6D8B6D8B6D8B6D8B6D8C6E8C6D8B6E8C6D8C6D8A7A8B6F8B6F8B6F8C708B6F8C6E8A6E8A6F8C6F8A6F8B6E8A6F8A6E8A6E8B6E8A6E896E8B6F8B6F8C6F8B6F8A6D896D896E8A6E896E896E8A718B6F8C6E8A6E8A6F01FE0500010198508C6E8C6E8B6D8B6D8B6D8B6E8C6D8C6E8C6F8C6D8B6C8B6C8B6C8A6D8B6D8B6C8A6B8C6D8B6D8A6C8A6D8B6D8B6D8C6D8B6D8A6D8B6C8B6D8B6C8A6C8B6D8B6D8A6C8B6C8B6D8C6D8C6E8D6F8D6E8C6E8C6E8B6D8C6E8C6D8A6C8B6D8C6D8B6D8C6E8B6D8B6D8C7A8D6D8E6C8E6D8E6D8D6D8D6C8C6B8B6B8D6D8D6C8D6C8C6B8B6B8E6C8D6C8D6C8C6B8C6B8D6B8D6D8D6C8C6A8C6B8C6B8C6B8A6B8C6B8E6F8D6D8D6C8C6B8B6B01FE06000101986087708870887088718A70887088718A728871896F8870876E886F876F886F886F8870886F8770876E886F886F886F886F8771886E886E88708870876F8870886F886F876F88718A718A718A7289708A7189718872897088708870876F886F886F896F87718870877A8C6E8B6E8C6F8D6F8D6D8B6C8B6C8A6C8B6D8B6D8C6D8A6C8B6B8C6B8A6D8B6C8B6C8A6C8B6C8C6C8A6D8C6C8C6C8C6C8B6C8B6D8B6D8C708D6D8B6C8B6C8A6C01FE070001019870847683758276837583758375847683768376837582748174827482748274837582738374827583758274837482748274847683748373827483748374837584768475837583758477847584758477857685778576847683758375827383758375837583768275837B897288718872897288728770856E856F866F8771877087708770866F8770866F87708670866F85708770876F87708771887088718872887488728770856E856F01FE0800010198807C7C7C7C7B7B7C7C7C7D7D7C7C7D7C7D7B7C7C7C7B7C7B7A7A7B7B7C7C7C7B7B7C7B7B7B7C7B7C7B7B7A7B7B7B7A7B7A7A7B7C7B7C7C7C7B7D7C7D7D7E7D7E7D7C7B7C7B7D7D7D7D7E7D7D7D7D7E7E7C7D7D7C7C7C7C7D7D7C7D7C7C7D7C7A7B7C7B7C7C7C7C7D7D82778277817983788077817680777F75807680768177807680758078817681757F748075817680757F7480768177827782768278807782798077817680777F7501FE090001019890768376837584768375837683758375837583758375837583748274827482768275827581758275827481748174817482758275837583768375837685768477837684768475837684778577847684768475837683768376847682768375827583748276837584767E7881788177817780777F78807780777F757E777E767F7780777F787F777F77807780777F767E777D777F777F7980788079807A8179817980777F78807780777F01FE0A00010198A071897188718870887087718870886F876F887088718970886F886E866F887087708870876F876F88708971886F8670866F877088718971897188718971897188718972887088718A71897189718870887189708870897187718970887088708870887189718A717E71867186718671867085708571867287718570857186718670856F8571867286718672867085708571857287728773877288738772877286708570857186728701FE0B00010198B06C8B6E8B6D8B6D8B6E8B6C8B6D8B6C8A6D8B6D8A6D8C6F8C6D8B6D8A6C8A6D8B6E8B6D8B6E8B6D8B6D8B6C8A6D8B6C8A6D8A6D8C6E8B6F8C6E8C6E8C6D8D6E8B6D8B6E8C6E8C6D8C6E8C6C8B6D8B6D8B6C8A6D8B6D8C6D8C6E8C6C8B6C8A6C8A6C8A6D8B6E8C6E7F6F8A6E8A6D8A6C886D896E896E8B6F8A6D896E8A6D896E8A6E8A6E8A6F896F8A6E8A6E8A6F8A6D896D8A6D896E8A6E8B6F8B6F8B6F8B6E876D896E896E8B6F8A01FE0C00010198C06D8C6C8C6D8C6D8B6D8B6C8B6C8A6B896C8A6D8B6E8C6E8D6D8C6E8B6E8C6D8B6D8C6D8C6D8C6E8C6E8D6E8D6E8D6E8B6D8C6E8B6C8B6D8C6D8C6E8B6E8B6E8D6E8C6D8B6C8C6C8B6D8B6C8A6D896C8C6D8B6D8B6C8A6D8B6E8B6C8C6D8C6D8B6C8C6C8A6D8C6E7F6A8C6A8C6B8B698B6B8C6B8D6D8E6C8D6B8D6C8E6C8D6C8D6C8D6C8D6C8C6C8E6C8E6D8D6C8D6B8D6D8D6C8D6B8D6C8D6D8D6C8E6B8D6C896B8C6B8D6D8E6C8D01FE0D00010198D06F8970877088718871886F8870886F8870877089718A718A718A71887189718971897088708970897089718A718970897088708971897189718970896F897189708970897089708870886F876F876F876E877087708970886F8871897089718970886F887188707F6B8A6B8A6C896C8A6D8B6C8B6D8D6D8C6F8B6C8C6D8D6F8D6F8C6D8C6D8C6C8D6D8D6D8D6E8D6D8D6E8C6D8C6D8C6E8C6C8B6E8C6C8C6D886D8B6C8B6D8D6D8C01FE0E00010198E0758375837682748375847481758275827583768478857784768475837684778476847684778476847784768678867584768375857584758475847583748475827484758275837483748373827481748475827583758275837583768575847684758274827484767E7087708670866F877187728871887289728A71887189738B738871887188728A748A728A718970887189708973887089708771886F887084718772887188728901FE01000101C810728675877386748572867385738572847487738774877587748572867787748675897388748872877487748975877287748774877187738773867486738673867083748672867485718372867183718371857282728673847186758773877585738672857285747E7486728573837283768673857688758675887487758777877588748674877286768774887688748874887687748673867286728472857280768673857688758601FE02000101D8207A7C7C7F7A7E7B7D7B7D7C7D7D7E7C7F7E7E7C7E7E807B7E7B7E7C7F7C7F7A807E807D807C7D7D807D817F817D827C807C7F7B7D7B7E7B7F7C7F7B7E7A7C7C7C7A7D7A7F7B7D797B777B7A7A7A7B7A7C7C7D797D7B7E797E7A7C7F7E777D7B7F7A7E7B7E7A7D7A7C7583748174827484758376857986788677857685768479847783788575867684788578887987788476867887788474857684778373827282758376857986788601FE03000101D8308377837580758376827682768477847685778377837785788577847783768277847785788276827784788479847A847883778277847781758075807580757F768277807681768076827580758175817683768175837783768175847882768176827783768376827B7A7F777D7A7E7B7E7C7F7C7F7B7F7C7F7C817D817F817B7F7C807C807A7F7C7F7C7F7D817E807B817C817C807C7F7A7D787D777D797D7C807C7F7C7F7B7F7C7F01FE04000101D84087718771867186718670867188728A738971867188738672897288728972877188728772887187728872867388738873877287738672877286718470857085718873877288718770867088718671877187718871887187728671867286728771887287718770867A7D7B7E7C7E7B7E7C7E7A7E7C7E7C7D7C7E7C7E7C7F7D7D7C7E7D7F7E7D7C7D7C7D7D7D7C7D7C807E7E7D7F7C7E7C7C7B7C7B7C7B7C7A7B7D7E7A7E7C7E7C7D7C01FE05000101D8508B6C8A6C8A6D8B6D8A6C8B6D8C6E8F6F906E8D6C896B8B6C8D6D8B6D8C6D8C6D8C6D8B6C8B6C8B6C8B6D8B6C8C6D8C6D8B6D8A6C8B6C896C8B6E8A6D8D6E8C6D8C6D8C6C8B6D8B6C8A6C8B6D8D6E8D6E8C6D8B6C8C6D8A6C8C6D8C6C8C6D8B6D8B6C8B6D8B6C8C7A817683768576857683768276837782768477817683768276827782778376827682778277827785778277817682768176827680758176827A837682768377827601FE06000101D8608C6D8C6D8D6C8B6D8C6C8C6D8C6E8D6D8C6D8D6D896B8A6C8C6D8A6B8B6C8B6B8A6C8B6C8A6C8A6B8C6C8B6C8A6C8D6C896B8B6C8D6C8B6C8A6C8C6C8D6D8C6D8C6C8C6D8D6D8D6E8D6E8B6D8C6E8C6D8C6D8B6D8D6E8C6D8B6E8B6B8C6D8C6D8C6D8C6D8B6C8A798972877188738973897287718670857186718671877186718670867186708570877185708671867187718470867086718671867187728876897287718670857101FE07000101D870886D8A6F8870896F8B6F8A6F8B6F8A71896F896E876D866D8A6D886D886D876E876E876D876E896F896E876E866E896F8970896E896E876D876E876E89708A708B708A7089708B708B718D718A70896F8B718B708B6F896E896E876E896E89708970896F886F897A867187728572877488728871867186708571867086708571847087718570857083708470846F877185708470867288738772877288728675887288718671867001FE08000101D8808673857385718574847285728575847385728470877384728472837184708572826F83738470837083708572856F8471847286718572887385738673857286748673887487728573897587768675877386758674867386738673837185728672837286738473877B8473867687748773857285718772837281728472847182738571867185738271857184718571847384738570826F83718574847387758677857285718772837201FE09000101D8907D7A7C7B7F7C7E7C7C7A7F7C7C7B7E7D7C7A7D7A7D7A7B797C7A7D787B7A7C7A7D7A7D797D797D797B797B777A777C797C7B7E797C797D7A7C797D7C7E7B7D7C7E7B7E7B817C7F7D7F7D807D7F7C7F7C7E7D827C7C7B7E7B7D797D7A7C7A7D797D7B7D797E7B7D7C84768375817682758174817483748176847481717F7384747F717F73817581737F727D738073817381748374837484758277847682758478817481748374817601FE0A000101D8A0768276827781768177837681758275827481778276817581758074817480748175817481768176807581748173807581748176807582778276827683778279837882788478837884798478857883768376827683778378827682778079827581768276817582767D7F7A7F7A7E797D7B7C797E7A7C787C787C797B797B797E797C787A777A787E7A7C787C787E797D787A787E797C787C7A7F7A807B7E7B7F7A7C797E7A7C787C7801FE0B000101D8B0708671877287718771877187718770877287728771877086718670877087738670866F85728670867186708570867186718772867085738773877287728873877387718772877188728873887387718670867388728771877287728772877187718772877287727E7C7E7B7D7A7C7B7D7A7D7C7D7B7E7A7C797C7B7C7A7D7B7D7B7B7B7D7D7D7A7B7A7B7A7B7A7B797C797B7B7C7B7C7C7D7C7D7D7E7D7E7B7A7A7D7C7D7B7E7A7C01FE0C000101D8C06D8B6B8B6D8C6D8C6F8C6D8C6C8B6B8A6C8C6E8B6D8C6E8C6B8B6D8C6B8B6D8C6D8B6C8B6C8B6D8C6D8C6F8D6E8C6B8B6D8B6D8B6D8B6D8C6E8C6E8C6B8C6E8C6C8C6E8C6E8C6F8C6C8B6C8B6C8C6E8C6C8B6C8B6B8C6D8C6E8C6C8B6D8B6C8B6C8B6C8C6E8C6D7F768275827682738175827682758276827582758274817683768176817582768277827782758174817681778377827782778377827882767F758276827582768201FE0D000101D8D06C8C6C8B6D8C6D8C6D8A6D8B6C8B6B8B6C8B6D8C6E8C6D8C6D8D6C8C6F8D6F8D6D8C6C8D6E8C6D8D6F8C6D8C6F8D6D8C6D8D6F8C6D8D6C8D6B8B6D8C6F8E6D8C6E8C6B8A6C8B6C8B6B8A6C8B6B8A6C8B6A8B6D8A6B8B6E8D6D8C6E8C6D8C6D8C6D8B6D8B6D8B6D7F708671876F866F8570876F87718871887187728872887288748972887388728773887388738872887488738871877287728672877286728270876F877188718801FE0E000101D8E06F896E896E89708A6F8970886E876E89708A708B718A708A6F8C718A6F8A718A718A6F8A708B718B718B708B718B728A6F8A718B718A6F896E8A6F8A718B708A6D896E896F896D886C866E886C896D886E876F886F886E897089718B718C71896F896E896E896F7E718671856F867186718771887488768971877387728874887587728872877187748874897388748772887588728772867087728672877081718771887488768901FE010001018810778474857684758374847583738475827383758477847885768676847684768577887884798575837887778477847786778677867884758474827484768274827583758176817480708174807281748274827382778375847684768376857885768473837382747E7784768174817782768374837684788578867A847884768378867784778679877B857785788577847785788575847681758478837583757E768374837684788501FE020001019820758574857283738672847282738474867787778674867785738778867686748677867386758675867B87778878867786778676877385728474847484758373817283748375847081718371826E82728472837684768573867486768674867485738573857686737E7383758275837483778377867887778676867A857884748379847786758575857886788679867A867A86778477857682728174817782757F778377867887778601FE030001019830748375837582748373837281768473827684758678877986768575857683778778877585798878837787788777877785788575877684768476837383728276837683748373817381718172817282748175827583768374847583778574827483778577837483737D718771866F86708675897086748975897388738A758C7689758A75877489748875897489768A748972887088758A7487708471856E856F82758970867489758901FE0400010198407881778176817780778278817780768278827882798179827A837A827881798279827882798277827A8379827883798177827782778377827580778178827781768177817781767F758077807680778077807680788177827781788378817882788176807781787D7583748376827482768277847785778677847685768377847684768579867784768577847785758577847684778475847683758272827480768277847785778601FE0500010198507B7E7B7E7B7E7B7D7A7E7B7D7B7E7B7D7B7E7A7E7A7E7B7F7C7E7B7E7C7F7B7E7B7F7B7F7B7F7B7F7B7F7B7F7B7F7C7F7B7F7A7E7A7E7A7F7A7D797E7A7E7A7E797E7A7E7A7E7A7E7A7E7A7D797D7A7D797D7A7D7B7F7B7E7B7E7B7F7B7F7B7E7B7E7B7E7A7E797D7682778176817881778177827782788378837782788378837883778176827882798479837883788378827782768177817682778275817881778177827782788301FE060001019860817682768176837782768377857784778276827581758075827781758176817681768276827682768076817681778277827781768277827682768277827681768276817681778377837782768176827783778276827782768176817682768477817682768276817B7C7C7C7C7C7C7C7C7C7C7C7C7C7D7C7D7C7C7C7D7C7C7C7D7C7D7C7C7C7D7D7D7B7D7C7D7C7D7C7D7C7D7C7D7C7D7C7D7B7D7B7C7C7C7C7E7C7C7C7C7C7D7C7D01FE070001019870857486748473837384748575867585738274837383738373847483738473847381728373827382738272837382718273827483738373837385748574837484758473837584748675867786768675867584748676847484748374837585738373857484738375857B8375827684778577827583768275857782748275827482748074817682758374827480748173827582758074837582758375837685768479827583768275857701FE08000101988083758575837581758375847585778476847582738274827480738174827483738173837480728175837380727E718474817483748375857584768276857681748676837481748476857787788476837783768476857682768374857482748174827383758477877B81748676837586788374807481737F738175827481738073807482727E758173827380717D7281738276817482768175837381748476857C8374807481737F7301FE090001019890847384738673857583758577877485748072847483718173827383738372817280708172837282728071817082728673847386738372827481748574847585758574867688778574887788778875837486748674857584728173817383728574857381738676877B8575867684758376827384758476827480717F737E7282748274817480737E727D728173807380728174827483758175827585768377857B827384758476827401FE0A00010198A081748373847381738175867683778377837684727F73827381748174817483738272827381738172817182717E728172817281738174837687788677857683768576847484748476877787768678837484768475837585768474847383718175847585758476837B8770867186748672847188708671836F8371836F857287708670857085718673836D836E8272877184708470857186728872887289748778847188708671836F01FE0B00010198B0817881778078827881788076807881777F7781778176807781758177807680757F757F758077817780767F757E757F757F768176817781778276817783798377827782767F77827882798379847980788277827882788076807680767E758278817881788178817C8375847683768577827482747F74807583758274807485758072817481748275827381748173827582748374837483758275857582738277827482747F74807501FE0C00010198C07E7A7E7B7E7B7E7A7E7A7E7A7E7B7E7B7D7B7D7B7E7A7D797D797D7A7C797D7A7E7A7C7A7E7A7E7A7D797D797D797E797D7A7E7A7F7B7F7B7E7A7E7A7E7B7E7B7E7A7F7A7E7A7E7B7E7B7F7B7F7B7E7B7E7A7E7B7F7B7E7B7E7A7E797D7A7D7A7E7A7E7B7F7B7E7C8377837781788277817781778177807681768176817681778076807781768075807480748176817782758176807580768177837882778278817781778177807601FE0D00010198D0778276827682768277837682768276827682768278837782768277827782768277827682778277827782788277827782778278827782788276827782788275827882778177827782778276817682778175817782768276817682778276817782778276817782777D7C7C7C7D7C7C7C7D7D7C7C7C7D7C7D7C7C7C7C7D7D7C7D7C7D7C7C7C7D7C7C7B7C7B7D7B7D7B7C7B7C7B7D7B7D7C7D7C7D7C7D7D7D7C7D7A7D7C7C7C7D7C7D7C01FE0E00010198E0748474847484758474857384748372847585758676857586768675857685768575867786768576857686778575867384758576867483738475857684738473847483728475847282738372827283738473837484758475847383758574857685768574857583747E768475837583758275837582778476857683768478847685768375857784768477857985788576847784768375837683748276837583757F758375827784768501FE01000101C8107583768474837484748373817382748076867685758578867585788878867986788673857586778477867A8877847384778576857986798375857582758273827483758373827481738074827381758273827481768474837683788478857983748374837885737D768573817584748376847885778577867784768674857786788577857484758477857786758777837885788577867885748473827484757F768478857785778601FE02000101D82076837684778475837684778376827382778375837585768476857884778478857B8677867A83778475837A8779837684768476847A857683758376827483778376837881778274817382737F7481748175817581758273817382788275847783758577847683777E7784738177837883778375837C837683768479847A847784788477837482778476867B857D8778867B847983778276817683778375817580778375837C83768301FE03000101D8307285708870857186718872897486708772887188718772897389768A758971877389738972877588768C778B7388728872897188728671886F86728772877387728772896E847084718571866D846E8672867287728872866F8672887388748B758671867087727E7184728572836E847588758776887786748774867587758775857688788972877887768A748877867686748876867586708575867585727E758875877688778601FE04000101D840728373857484728576877686758472817486778775847787758776877584758475877887788776857687778678897786768574877486748473837585718171847583748574847182718272847383748474847283758676847584788775857685748575867587727E71866F84718570867388728A748A74897589748A74887388738874877288778A7688738B768A7487748872897388748770857486718571817388728A748A748901FE05000101D8507783768375827582778376827682768277837783768377837783788478847783778377847783768478847884798476837A847683758274827783768276837682778375827581748275827681757F768277827581758176827883788376817582768276837783777D7581748275807582768278857782758376847883768376837A85768376847883788478857785778377837683778276827483758176827680768278857782758301FE06000101D860797F797F797F79807980797F797F797E7A7F798079807980797F79807980797F798079807980798079817A817A81798079807980797F79807980797F787F7980797F7980797F797F787F787F787F797F797F787F797F79807980798079807980797F787F7880797D7881778177807781788179827782798279817781778178827882788277817883798279827882778178827782798278837781788077817880788179827782798201FE07000101D87082768177837682768276827781768277827680758176807681778376817581767F768276827680768276807580768176807681768076837781778277827782768277837781778077837783778277837782778377827782768276807683778276807680768277827B7E797F7A7E7A7E797E7A7F7A7E797E7A7E7A7E7A7D797D797D7A7F7A7D7A7E7A7C7A7D7A7D7A7D7B7E7B7F7A7E7A7F7A7F7A7E7A7E7A7D7B7E7A7F7A7E797E7A01FE08000101D880847584768776827481748376837484778275847481748373837581748074837481728173847281748173827182718072807382758274837682758377847686748474837483768376837685788777837685778576847785768576837481758374867583748276847B84778576867784758375817382737F72817082758374847483748173807383758373827380718273807381738375817386778475847684788375817382737F7201FE09000101D890847685758474817482778678837583748074827581747E7281738074837580737F7480738275837480757E737E7380737E74837582768076837480768477847682768276857684768478867887788477827783788377857686767F7485738075847582758077827B8477837784778577837781757E7480727F738275817480738174807481717F7580758073807480737D727E7283778376847782768376827A837781757E74807201FE0A000101D8A08270867289718572877288738973877486708471846E83708770857083708770836E8670836F8470846F846F866E81708570856F8572867185708470877386728873897388738A7489728A748A738A7589738872827187718671827087718671867187718671837B867387758674867281728372887488708473826F8070816F8070817384708373827283718070817282718573857485748473847284748A79817283728874887001FE0B000101D8B0837384748373847283748576867485748075847483738571837283728374827380718372847384748373817282718072837383728374867383748374837483738373857386778774847586768675867786768576867586758675827385738375857484738473857B847389738873857385738471856F817188728672877085738672837086718570846F836F836F86708370867085728872857385728672887685738471856F817101FE0C000101D8C0837682768377837682758377847783778275807681768174817681768175817480748175827681758174827580758175817581758275807482758176827783768377847783778477837685788477837682778477837683768276817481768176837683758276827B847683768375847681748274827682748274817681737F758274807482758174817580758175827481748273827582778375827583768077817482748276827401FE0D000101D8D0807A8079807A7F797F7980798079807A7F797E7980797F797F797F797F787F787F787F7980797F797F787F7780787F787F797F787F7980788079807980787F79807980787F798079807A807B80797F79807A80797F79807980787F787F797F7980787F798078807C8178827882798278817781778177817780778075807580778076807780768076807781778076817780768077817781778177817782778179817781778177817701FE0E000101D8E07682768277827582778176827682758279817681798378827682788278837A8378827882788278827882778377837682798378827782778176817781768177827781778377817681748076817681778177817781778276817682798275827882778276827882777D7A7F7A7F7B7F7A7F7B7F7A7F7B7F7B7E7A7E7B7E7A7E7A7E7C7F7B7E7B7E7A7E7B7E7B7E7B7E7B7E7B7E7A7E7A7E7B7E7B7F7C7E7B7E7A7D7B7F7A7F7B7F7B7E01FE010001018810748476847684758375847583758376817484738276857784778378847786768577857784798577847483748479867685768376857584778476827683738274857582738274857581758374817382768374847482778374837383758376857884768475847784747E7681748077817781798278827782798278837783778279837A8279827781768177827A837883778279837882778176827A8278817880777F798278827782798201FE020001019820778377857682758274827782788275817683768379857986788377847784788477857A84788377837A8576847986798579847982788376837382778175827681768377837381788273807680727F748175817781798374807583778477837782768377837883777D7582788079827A807680788179807B817A8479837A847B8379837981788376827A8479847E85788278827A837780778279807781778079817680788179807B8101FE030001019830778572837484738374837483738373837785758476857785768579867A86798679857785788575847783788577857784768477847783758376837683728174817484748377837582738073807281768377837581738373827785788578847684738473827583757E75817380788278817A827882788176817783768178847A857984788379827983798478847A8477837782778379837681778377827780757E7A8278827881768101FE0400010198407186718870887589738774867185738672867286728A728976897588738773887589738872887388748A7489768A72897287708772887287728972866F84718977877587728770856E836D846F877486718571866F86708671877488728874887185718673876E7E7284728373847484758575877585788674857988758676887787778676867686758777867488768575867486798876857685778576867480758575877585788601FE050001019850768374807583778375847583758273827784768477837885788576847785788476847784788576857785778477857785798374837684748375837483758375817683758275817381738073817482748176837482768477837482768375847882758376847682757D77827581758075827884778277837783778375847885788477847784778378847B857A867C8678827885778378837881768277807381747F788477827783778301FE0600010198607782778276817681768177817782768178817782768276827983778277837A83798376817782788278827A8479837984778277827982768276817782788277827781758277827581778276817780768176817882778177817681758277837882768277817781777D78817881788078807981778079817A827881788279827982798278817882778179827882788378827981788178817680798079807881777F7981778079817A8201FE070001019870797E7A7F797F7A7F7A7F7A7E7A7F7A7F7A7E7A7E7A7F7A7F7A7F7A807A7F7A807A7F7A7F7A7F7A7F7A7F7A807A807A807A7E7A7F7A7F7A7F797E797F7A7F7A7E797F797F797F797E797E797E797E797E797E797E797E797F7A7F7A807A7F7A7F797F7A7F7A7F7A7C797F787F787F797F79807A807A7F7A8079807A807A7F797F7A807A8079807A807A817A817A80798079807A80797F798079807A7F797F797E79807A807A7F7A8001FE08000101988084758474827585758475837584768275807481748075827583757F738474807380748475837481748173817480738373837581748376817482768377847685768375847581758676877884778477847882758375827583758475837482748175847684768475827B817783788277837682778276807681768276807681767F757F7681758176827680767E767E757F7680768076827781768277817882788279827782768076817601FE090001019890827683758076827884778377847583768277827683737F74817483757F74827580747F75817485777F738073807380757F7281748175817682778177847884778075827682788377847985788578837683788376827782758277837782778176847681757E74837C85778177827882777F76817882787D768074807781767F767F747F737F737E747E7580747C767F757F7580768276817983777E7680767E787F76817882787D7601FE0A00010198A0857686758375867683758475847585758274837282747F7381728074827381748372827381747F7282738173807280738275837582747F7683748676837583768374837484758477887887768477857784758376827583768375807484768275857582758475847B8078837982768177817780767E7681768176807581737E757E757F75827681757D7480758376807680768075817580778376807781778278817780767E76817601FE0B00010198B0877189728871887386728872847389738670887087728770846E816E846F856F846F84718370856F82708770826C826E847083738872857288738473847185738A7387748574897389768A748B758972857388718472867284708572876F8771887289748872897B8675837584748476807283728274837380728273817484738373837184748170807282727E707F7081718372837486758676857683758577807283728274837301FE0C00010198C0837684758275827784768476857886778175817380758173817483758376807381748274827382758273807483748173827584748274817483758376857681768475837685758478847785788578867782748277847683758175837682738074837482758476837B827582758176827881768275807581778276817483768075807482748075827781737F737E7381748175817582758176837681778277847A817682758075817701FE0D00010198D0817781768176817683778278827882788276817580758176817581778177827781768176827681767F7580767F7681757F7581778277807681778377827682768076837782778277837883788378827884798176817780768277827582778076807682778277837B817781788178817981788077807780777F777F7780767F767F777E7780777F767F7680767E767F777F757D7680788279837880788278827A817880778077807701FE0E00010198E07F7A7F7A7F7A7F7A7F7A7F7A7E7A7F7A7F7A7F797E797E7A7E797E797E7A7F797F797F797F7A7F7A7F797F797E797E797E787F797F797F797F7A7F797F797F797F797F7A7F7A7F7A7F7A7F7A7F7A7F7A7F7A7F7A7F797F797F7A7F7A7F797E7A7F7A7F7A7F7A7F7C807A807A7F7A807A7F797F787E787E7980787E797F787E787F7980787F7980797E7880797E78807980787F7980797E787E78807980797F7B7F797F787E787E7901FE01000101C810798177807580768077807982798076807881798279837882798279817A8279827A827882788078827A827A817A82788179817981788079817880777F767F768079817880777F7680768077807880777F748078817881768076807982788179817B8177817780787D7B7E797D7A7E787E7B7E7B7E7C7F7A7E7A7E7B7E7A7E7B7F7B7F7C7E7A7E7A7E7C7E7B7E7B7E7B7E7B7E7B7E7B7E7B7E7A7E7B7E7B7E7B7D7B7E7B7E7C7F7A7E01FE02000101D8207981767F77827882788376807A8176807A8075817C827B83798378857F8378827982778379837A8377817C857B86798277827A837683778177817582787F7480798275807680777F7781787E747E7680767F7B817982768177817A8279837982798177817880757D787F7B7E7A7E787F7A7F7B7F7C807A817A807D827C807B827E837F817F807D807B807F817D7F7B7F797E797F7B7F7B7E7A7F7B7D757C797C7A7F7B7F7C807A8101FE03000101D830778176817982778177817880798075807A8178827881788177837A827B837B837A8277827B83788279827A847C8477827982788178837A8077817780768076817981768075807681777E767F757E788077807780778178817A827A8178827A81788173807980767D7B807B7E7A7F7A7E7B807C817C807A807C807B7F7A807C817C7F797F79807B7F7E817D837D807A817A807C807B7D7B7D797D797E7A7D7A7B7B807C817C807A8001FE04000101D84074827884758478827381738277827581758476857A8476837886798576857684798579867884778479857986798676837584758375837783728478817481748176827785748173807380727E75817782738278837483758273807A857A867484738374827481737D7881767F797D797F7A80787F7C817B807A827C817A817C817C817B807C7F7B807B817B827B8077807C7F7A8077807C80787E787F7B7E787C7A80787F7C817B8001FE05000101D85076827681748075817682768074817581788278827982788379847A847A82788578827883788379837A837784798477847B8578827883768176817781768275817783768276807582767F747E747E758277827780758277807681798377857582788376807583767D7B80787F7780797F7781777E7B817B827C827A7F7B837B827C837B837C837A817C837B837B837C837C8178807C80787E787F787F76807A7E7781777E7B817B8201FE06000101D8607981788078807880777F7680777F77807980798078807A827B82798178817B827A81788078807A817A8179827C837981788179817880788079807A81767F77807981798178807980777E757E777F787F768078807980788077807A81798178817980777F7882787D7A7F7A7E797E7B7E7C807A7E7D807D807C7F7C807B7F7A7E7B7E7A807C7F7A7F7C807B7F7C807B807C807A807A7F797E787D7A7E7A7E7A7C7C807A7E7D807D8001FE07000101D87079807A7F797F797F7B807A7F7980787F7A80787F7980798079807A807A807A807A807A807A8078807A807A807A80797F7A8079807A7F79807A7F7A7F797F797F797E787F797F787E787E787F787F797F787F787F7A7F797E797F7A80797F7A7F7980797F797F797D7B7F7B7E7A7E7A7E7B7E7A7F7C7F7C7E7B7F7B7E7A7F7A7F7B7F7A7F7C7F7B7F7A7F7C7F7C807B7F7C7F7A7E787E7B7F7A7E7A7E7A7D7C7D7B7E7A7F7C7F7C7E01FE08000101D880817780778077827882778077807884797F777F7681777F777E777F777F76807780787F7780777F777E777D77807780777F7880787F7881797F788078827980797F78827883798278837A817983798178807880788178827984787E767F778178827780778177827C7F7A7D7A7E7B7D7A7D7A7E7A7E7A807A7D7A7E7A7E7A7E7A7E7A7D7A7F7A7E7A7E7A7D7A7D7A7F7A7D7A7E7A7C7A7E7A7E7A7C7A7E7B7F7C7D7A7E7A7E7A807A01FE09000101D890827782778379817683798279807981767D777F7580767D75807682767E737F767F787F76807683767F757D747C757D717E75807883788278847983788178827981778076847A82798079827A837A807983787F777E777E7780777F7680757E777F78827982787F7C807A7F7B7F7B7E7A7C797E797E797C777C777C79797A7C777D797D787B777C777B7778757D787A787F797C79807B807D807B7F7C827B817E7C797E797E797C7701FE0A000101D8A0817880778078817880778178827880787F7681767F7782777F7580767F77807780787E7581757C757F7580757D747D757D7781778277837980787F77827A847980777E77827A827A847A837B847A807881787E78807782768078807882777E77807882787E77807C807B807B7D7A81797B777C777D7A7B787F797E797D777B797E797E7A7F7B7E797C7779777C787B777B787F7A7F7A7F7B7F79807A7E7A807E7B777C777D7A7B7801FE0B000101D8B0817483778274817583768376817685767E748474807580738073827681757F737D74827481747E757F748274827582737E7381758075827686788175867885778275807585778879847787798576857782768175837785748475817383758075827583768277827B81777E7A817B807A80797D7880787E777C777D787D777B787D797E767E79807A7D787E787E777E777D777A777C787F798079817A817A807D80797D7880787E7701FE0C000101D8C08175807682768076837684788279837781768074817581767F767F758375827580748073817580747E748073817480747F7581747F7584788377837581788175827783788378847884788479837A8377827580788277817684767F7483798377827682778177837B7F77837A817980797B78807878757D797F767E777D787C767D767D78807980787E757F777E777D797E7880767F757E787F7A7E7A827A807B7B78807878757D7901FE0D000101D8D08178817880787F7881788079807880788178807880787E778078807781767F777F767F787F777F7880787E777D767F7880777E7680788079817880797F7880787F7881798279827A837A8179827A8079817A81798178807881797F788077807880777F787F78807C7D7A7F7B7F7A7E7A7D7A807A7F7A7D797C787F7A7C797E797C797E797E797D7A7E797F787C797D797C797F7B80797E797F7B7E7A7E7A7E7B7D7A807A7F7A7D79010100000101D8E080797F797F797F797F7A807A8079817A7F797F797F797E797E787E787E787F797F797F787F787E787E787E787D777F797F797F7980787E777E798079807A80797E798079807A817A807A8079807A807A8079817A807A7F797E787E787F79807A807980797F797F7C7D7A7E7B7E7B7F7C7D7A7F7A7F7A7E797E7A7E7A7D7A7E7A7D797D797D797C79 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 32 32 0 7C797D7A7D787C797E7B7D7A7F7A7E7B7F7B7E7B7E7A7E7C7D7A7F7A7F7A7E79 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2503 2503 0 02B000000103000900042004300000000004030009001820043001804F00040300090020200430080080000403000900242004300000FF0104030009002C20043001000000040300090040200430FF030000040300090044200430E6030000040300090048200430E703000004030009004C200430E8030000040300090054200430003E010004030009000021043000000000040300090004210430000000000403000900082104300000000004030009000C2104300000000004030009001021043000000000040300090014210430000000000403000900182104300000000004030009001C2104301F0000000403000900202104300100000004030009004021043000000000040300090044210430000000000403000900482104300000000004030009004C2104300000000004030009005021043000000000040300090054210430000000000403000900582104300000000004030009005C2104301F0000000403000900602104300100000004030009008021043000000000040300090084210430000000000403000900882104300000000004030009008C2104300000000004030009009021043000000000040300090094210430000000000403000900982104300000000004030009009C2104301F0000000403000900A0210430010000000403000900C0210430000000000403000900C4210430000000000403000900C8210430000000000403000900CC210430000000000403000900D0210430000000000403000900D4210430000000000403000900D8210430000000000403000900DC2104301F0000000403000900E0210430010000000403000900A0200430EFE100000403000900A4200430004000000403000900B0200430000000000403000900C4200430140000000403000900C8200430000000000403000900CC200430200000000403000900502004300002A8020403000900A8200430FE210000040300090004000038000700000403000900080000380015000004030009000C00003801030200040300090010000038010702000403000900140000380C0C05000402008005FF8307205F820720FF8307205F820720FF8307205F820720FF8307205F820720FF8307205F820720FF8B0720608A0720FF93072061920720FF9B0720629A0720FFA3072063A20720FFAB072064AA0720FFB3072065B20720FFBB072066BA0720FFC3072067C20720FFCB072068CA0720FFD3072069D20720FFDB07206ADA0720FFE307206BE20720FFEB07206CEA0720FFF307206DF20720FFFB07206EFA0720FF8507206F840720FF8D0720708C0720FF95072071940720FF9D0720729C0720FFA5072073A40720FFAD072074AC0720FFB5072075B40720FFBD072076BC0720FFC5072077C40720FFCD072078CC0720FFD5072079D40720FFDD07207ADC0720FFE507207BE40720FFED07207CEC0720FFF507207DF40720FFFD07207EFC0720FF8707207F860720FF8F0720808E0720FF97072081960720FF9F0720829E0720FFA7072083A60720FFAF072084AE0720FFB7072085B60720FFBF072086BE0720FFC7072087C60720FFCF072088CE0720FFD7072089D60720FFDF07208ADE0720FFE707208BE60720FFEF07208CEE0720FFF707208DF60720FFFF07208EFE0720FFFF07208EFE0720FFF707208DF60720FFEF07208CEE0720FFE707208BE60720FFDF07208ADE0720FFD7072089D60720FFCF072088CE0720FFC7072087C60720FFBF072086BE0720FFB7072085B60720FFAF072084AE0720FFA7072083A60720FF9F0720829E0720FF97072081960720FF8F0720808E0720FF8707207F860720FFFD07207EFC0720FFF507207DF40720FFED07207CEC0720FFE507207BE40720FFDD07207ADC0720FFD5072079D40720FFCD072078CC0720FFC5072077C40720FFBD072076BC0720FFB5072075B40720FFAD072074AC0720FFA5072073A40720FF9D0720729C0720FF95072071940720FF8D0720708C0720FF8507206F840720FFFB07206EFA0720FFF307206DF20720FFEB07206CEA0720FFE307206BE20720FFDB07206ADA0720FFD3072069D20720FFCB072068CA0720FFC3072067C20720FFBB072066BA0720FFB3072065B20720FFAB072064AA0720FFA3072063A20720FF9B0720629A0720FF93072061920720FF8B0720608A0720FF8307205F82072000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A0008001003181C1003181C030009000020043080000000040C000100030D002800C82004300000000001000000FF00000000FFFFFF01000000C820043000000000011C02B0010000000E001000000101010100011F08000000000000010F000100011000010001110002000001120001000105000E000C20FD00FFFF000000000208000005000E001020FD00FFFF00000000000500000300090004210430010000000403000900082104300100000004030009000C21043001000000040300090010210430010000000403000900142104300100000004030009001821043001000000040300090044210430010000000403000900482104300100000004030009004C2104300100000004030009005021043001000000040300090054210430010000000403000900582104300100000004150008000000000020280000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 45056 45056 0 01FE01000801C810796866716359717A6E6E72747476696D68696E6C76856B71787C7B7B686B6A808C726D73706B666A71756F6C7B8279736F7574727671836B6B747573716A6F71757976746E6A746B72847C6D7A796C6B6B63636E706E6A7F77717A717A736F746B7779767372715D727C65656D7168807477727371797D7D7E686D73666A767C7380797174676D6F75747D686E727287827A6E7078796A68756F6D6C736B696D7477727371797D7D01FE02000801D820716C64667D6F6F646A6E776D6D786370786C6A786C6B766B737474776F636E78787A7A6D6765676F636D71716A757F78636D737A796E68777164697473726C77726F716E6D60716B6B72717A7B706F6F6C736C6D717670756E6D6B75716E6C6D66796D746D73716A6C6675736E6F786674727379716B706F7A66716E746F747073697277776A6A6E76706C6D7C7C706C6F6562646769737172736E777784756C74727379716B706F01FE03000801D8306E62686869766E706E69696C717074716A6E6D727D6B6E806B786E7573716B64696B6B5A63826F7C7A77756F64705E756E75787E6C6E65616470757474737B7567716A6466736971697D7170796A5D6F7076677169797679667071727B6B756E677171647869716E75757C6776707178746D76645E635D67736663746E757A7368676F6D7371756A6D74686B7C7C7972686C70717160656F77767B7868696A6A746D76645E635D6701FE04000801D840576D5B58667170776E7679796D6E70776C79636D7D6469685A6871707576736D5D72767773777768647D747374715F626F63606D71635E686D70766D6876776E6C6E6E6D666A77686E686A687975717578746C63636B676268696B70707D7175776B7772726D6D647067666F746E7270777973695D5F5E6C676552626C7875637F7A756F6772686F74797B686C606D6E6C6F6E5F6D72837368686B5F71716F6E777973695D5F5E6C01FE05000801D8506F6F715E5C6A6F6F68706A62697258596270737378786A7D7165686767726A646465775C606F6F6970826A6874766B666D6C6B656D646B716F6364737276707F5E64626A73746E726F6879756360697270746D777B6B6165716D747371736F6B6E68726C68666B72646F6B6D6B6876766F746775736C7A6E715B6F72696E71716A58657271626E6F65576F6A5C6F6B7174726F5F54656671746C78766F596B6D6F746775736C7A6E01FE06000801D860726C6B716D6A6F816E6A6C69646866716F706E746D696968686766776A695F6B6B726A6B6B66646761676C6C6D6D676975676F6667696D69696E7978706F7B706C646B686A7072766D757068677266656F726A6861606D686568746463678067686F6F686475726871666E786F6E67666E5C6A615B67707C76686C75625F6768626A675E68737065756171776868726B6767706F7171786C5F636E66656A67756E5C6A615B67707C01FE07000801D870726A6C68605B677367616773636C7666696D6A61646F6A74706C676767797565606C69646C72696B5B586864676E626A73706771666B726A6C6C756F6372726E746B686672655E6B66685A5C606671716662676C656266636A646B656B6D6669725E65736A715F706273766F756C686767665C706E656C7268676B7B7B68636A727272626A6D657064696E6C6B6E6A686A5B63625A677859686A65776965677467665C706E656C7201FE08000801D88070806C5D636D706566626560645F6A656B6968716F6B6F6A6460676E786B6C695C6D715E6871716D64615B5B5F666A746C786F767466616C6D69606D766F5F655F626774706D6571726D73606565646D6A675F666261776663656B6C69616A62646C686662675E6D6A636B6B6C6A736B646A5D675F706F5C66757070666A5F5B6C6B6F6C636364606365726E687278766B636B636A6A5F75696B656866616465646A5D675F706F5C01FE09000801D8906A6A6C626A6B6E7469655964616E6C737265745B646E6C73586460616A6F69686D68636C705F5F5C66616968696E6E6D686C68636A6A5F5C6C676879615F5D6B6F5F6261595E676B62685C6F6E6D68656F7077646C625A6067586B6C6861625F575F6C676D605E636C6C6470716C73736D696F616B676966655F625B57625B756D6A6A65696E6670625C626C686867606A60645C64575B64625B675E6B74625E6D696F616B67696601FE0A000801D8A05960646C6562645B6960626461645F5F6D636E726F6C6D66636A69675D656866656A5E5C665C626A6A6B756D6466615A65636362666C6C6A68576B67615B66656B6E5F5C5C66657775726D6A665E6E6D767767635865616A63505B6D666B616D617565666B7065605E6A65827370686861665A5867616C636D6A675D636A6168625D5F5C5C74766556605C655D5B606D5F6665645A585962657263615F616D6861665A5867616C6301FE0B000801D8B071686C6A6E7482635E545E5B567066636160596973705D5C5A7163625F675D6B666A62675C676E6F655F6463665C5A696464665B5667635967655F695B6265596369665D6F605C63635664636563596A6E5D646A63716B726765626F7372615D59575C6E6865676862605A6168606862646D6267666263665457576873757566676471635F6A5866576466625D585D65707562695B646C636762566361606157646D62676662636601FE0C000801D8C0636065576467615D676766637066696E606159605F575F5F56565E6666657160636B686D5658605F5D635C6B63626765666760616F665D5D5F7564615F5563656361666D687D776D6D5A6E67566360605E6E6A696763616965635B5E5C655D63616D5B6F6A5A6D61686D706C676667646463636F5D5F6360616E5255596B6A61595C6267635F68726460515C685F6A605F5C665A5F685C555A5E5A62666B5E606463636F5D5F636001FE0D000801D8D05F5451636C606757605B59726F686565616D5C5E656B6F5E615C6066646361605D60595C54596261645E625E606B7261665B57605D5F615C5A5E655C5B65677164645B5C5A60595D58545D6D5F655C69595A605E6C736268655C646259595B6665666F6B695D545C5E6A69625E607466646F635B6068605B6355666C6375615C605F6C685757546056555959606663665F735F535B616B625F6F6360626D6770646F635B6068605B01FE0E000801D8E05960676A6D5B585B675A6465626559516165615D686C6D596057655754645B63605E5C6A5E74755A53576367565B585A5A5E6353535B6866626C62685D58575567705F635C57666F6C69656E5E535A5E6363607062595C61646D6C696364666364605C5A4F5E5B59655D5B6172645E52595D59686B7468696A6060695C5F58636270705F4E6156615A555B5D636F5E5C5E69665E575C5B635D666861696E5660595D59686B74686901FE0F000801D8F0655F585D50555A6A766A685E5654514F5D67586C66665F5B67635D61615F5B666461635B606B6D62665A5656595F5E5F62655D5E5F5953545F5D5D585C5F626465576058525558626055565C545B61636264525C636C686C67685E615B6762585E55544B62605C655B606364675E5B5858615F5B5D625F69575D6E685F605B61685C5455695B57545E6C625D5C6F5F685657635B645E585660646165715B605E58615F5B5D625F6901FE10000801D8006162666A565E55615C616963695B5459636160676E5E5C5C5C5753494A6365645C605C58595F656659585A5D59675F5A565B695B585A6B665D5E625A58596B62525B58685A6658685F656B5C665D505066566559545A5E564D4F54625E5A58686465535A616058535B6457565A5967666E5558697169565C6159575764585D5D665A5B63625B5B5358585956684C555D6A786D6458595F61595656666164646E6E5558697169565C01FE11000801D8105D545F67626A665E615E5A5C5960645D5D5B515D686C5653625E56575655525F6C75635C50656166595A676E54544F5F6F54516161574F49525D55585F58676558575B58525B5D5E5F5C685E525866646A625F6757515B525B536563665458565A63646162666E66514D4E606955545E5958645958685A5C5B6A665C5853635C5A5E524948585E6061585762594E5F6E726458575E5E565A605C5C5E5B67585F5958645958685A5C01FE12000801D8205957545B5F66605E5C5754575D5A5B6965616048526A6366585957606851575C565D545C5359605F5C54575360625E5A58495D5167625C5B66665E666459585A635F5E5456746155605F545B635E515D4E4D605966705A5C51575656615D5A555954575F5F62565663545F57656559584A526259515D5658685C535D5755525E62575963646458645A595D5C4553636265665B636467584D4C5B4A535C5360614A526259515D565801FE13000801D830586354595B665F575B5B505956575B615F5D586068615F5D57555C584F505C5B5F5B524A5D556764635A5E5F5A5752535B59645B62544A546261555A4654575F5F61635055545B5D6A6466605B5153515D584F5C626958505F4C58605E5D56556458505E655A535A57544E495B6558585F5A57555757515C5A655B58655D57595A5C5B5A52545C5C5C57545B5B505258535D52695F574B4C4C605B5C5D6366535F5A57555757515C01FE14000801D8405552554C4C555851555E504C53585A59505458574C585C674F5E565D5D584E5459595F5A636B61524E4F5560505F655F516254594E5751544B595E646C59554F594855575E645A5B604E58605B645F605D545C564F525A62655B5A554E5B566052505458625C5253575B585B6363645345565956605C5352555C5A5F6654554F4E60505B5463595A5E55575F535C5E645B655C595A5A605B524B5B5154575A5845565956605C535201FE15000801D8506759515E58554B5962605B5B4E575E5C5B5A5C51594F4C5F534C4D54474C5A5A6364635B535E56555A5552565B5E525957594B5153585A5F575359525D5F54566354564F5D5A515249505A655C57574A5D59605D555751574F52424E57615F624F5A614E5A685A5F62635F5F535358524F5B5F5156615B5658555C5A565C576460604E515553514C51635869515F4D5155584E504B4C56585363535C58564E674F5B5F5156615B5601FE16000801D8605E615E5C595C5C534F585E565E5B5751464E4759465067555C645A53585A50504F5552514C59535254505B61695A52525351575F5958575C605F554F54545A5B5746434F55524A605C6E5B5E60584B50575B4F50525461585B58554F4C40474E575C5D61524F504857625B534A5E515C57504D485A6049575F5E535660605557535650504B4B4C5C535156595660504F5C535D505349565853505152695C504F57504D485A60495701FE17000801D87059555D6268645250514C5D5B56585145604F565A5F61544B575059544F4F505C5E65525248473C5E6259544D55535551434F486854565258575059534A57505258554E4F524F4F50515A595B59534E47505957545455515D6C5A52493D525F5A555E624E5B5F5664544E595E53534C6250525157605D4F52525456524D56575362565B625E4A524D485248465152525754525B5B635F5360584A54505B50574650525157605D4F5201FE18000801D8805E5E5150485C494E585B595D4D49525750494448585F5C50545A54504A4F605B585D5753434C5150484B524C4F506163524B4C4F4E4F4F46504C59565C5D5A504B5D5D53505952544E50494A566152585D5E5150505150514D47514B524C4C5B5556585458575E554F4D524B6052605650514B5452584850405059515956525B4B5360575343484D6055594F5958495A5B5B575C52605F4F4F524A56525A5B5450514B545258485001FE19000801D8905B4946463A48534C45435B4A515D49625D5353514C54575D404A4B5C5562464D576052634E514549495A5355584F5B5549584D4E4E59565E4D525348484D484E5D564F59595A50474B4E4F55484E44555D5A52585A5D5E574F51514E53605A4A5B4E51485D56505050585F5A57554F5A4A5D5D4F4F5347584553514952484A4C494C524D51584E565053594F564B515C555350464D564C4F5B5E565C585955474A5D5D4F4F53475801FE1A000801D8A0444E4954574A584C404B504E53525A5451575C5F5D54525843594F585C58594B4D525645554A4C4B58474A59585B4E46515D474F58504A46514A4A5258504E4653564C4C51554B4B504C4B50575D5A535A4C4A4C4C585B5D41495A4C4F504C50404A434F58585554494E5353454F555C4D544A514B5F504C544F5F604C4F4B4E4F494C4A5A53535956464B47424F4C51555A5B4A494E464D494A555D56555C494D544A514B5F504C01FE1B000801D8B03B3E464F575054554F65504F45434D5366555956525647515A575E5653574F4F4B504E4F544A514B4A4D4C50524F3F504D44524F494A4F504B5F5A5756504A60463D344D545B514F484A48504F495458494A3B5452504950484356584D4F474F5545554D524B4953545562554F585D554D525B505950544F52515A5E4E4A4A564B484B6155564C4A58444D544B4B5E4E55525E4242564C4D44434848545646424D525B505950544F01FE1C000801D8C05B514B4C4E4D4E504C4B51554C4C4757535146554D424A574D505452474D5A565F424D5C504C464949504C4B4C4F484A554E4E564D48474F544C45514E5657564C4F4F49454D4E555348554F4C4D4F4B4B3E434C554D4F52464A41585E5950504646493F415855514C44504A575B495157644747475952554A444D4F4C494A434D535E504C4A4E4D4E484F505345555454574749565342514C58514B5B4C444E576447474759525501FE1D000801D8D058584A493D4B4F5D59544654464E515F47484D47434A4846493F4D4B4947405152434442444E444A5C535F64484F5358554C36454B464B434F5E58565854535742414546504A4C493A4D574C5B514C423D4C4E554D5554534B4B4B484E4F3C484E47404B52594C53494C425150465046493E555A594A464C4F524B42574B514D424A3E504B534C5152454C5847524744454F48534846514C4F4E4654585C4856493E555A594A464C01FE1E000801D8E0404B4E5C5A5951544C4446574A44493C4948534C4F43475C5253564D4E484E513A415C4D4D4944484E505650464A4D3B4141544E53553D3E3B45483B46514D4E594B414B535255504F3B444D5C4A48444C494B4953454848484753524842424F4940514C524E584F584D4853525457423348524C4D42444356544D4B4D4F54494745464E4E4E5B494F555D4D503C4F4E57434B4E3D504A4F4E56464F4242504E3348524C4D42444301FE1F000801D8F0573D4C45464955485044404F4E514A49414D4B4E4C53444F4242454C4156504B4F493C3E49505350434A484B564D4750474C494B4D49525056544B4F4C484A3C3E4C414549453F4448514B47504E504C525254544C584F5A4C3943424541474F4F4C4554553E493E435F595F4D48485359514047483B493F43414648504F403A4151514149504F4C4439475648494E4552474E47474B47525542424B584F494A59514047483B493F01FE20000801D80050463E454750373B545E59564B414B443E4F4C4A44414F464D484A565546464A444E59454B4B49434E4E414B4545455343474358494D4741504438535B53474547424D4F4E46504F403D485254584E3E46524553474E4E493843373A424D48504D4A42465643464E494C443E3C3443576055483E4C4754534F44465049463E41403F362E39444B4C504F4C514F3F49525250523C3C46565D504E4A3C4B4B49466055483E4C47545301FE21000801D8104C514B494644414C43573F50504849524A4645454846454349414B494C4045514D5A5343494E453F4A53484E4B3C4B41454B465855584D4D40404C514A554F44483E434C4943453D3C40564244444C49384943484750514E48454844574B5844453739544B524B39504E4F43443F394841434B3D42424349524B564748443F475556524F5B3F464845444F483E453D4D3C4A544B47424D50464438424B454E4541434B3D4242434901FE22000801D8204C50424B3E39413B494E4E54534C414D463B3F494D415149434D363942493B3C4E5647444553534E4B4A3D4F414D3E4D50474841473B42573F444A4A3E42424443594D4F4F4D494546424545434652443F464C46443F433F484844433D544D3C534F4C504B4B3E444A4A4B4C4B493B4D4B4A454939414050453F33423848494139464B4F584C4C4B45423A374C4E3F404E4B4758524947402D434B4E4A38393C4B4A45493941405001FE23000801D8304A4146433D49444B42374B41484444374C47463E364C434447374447373F4E4B44454C4D4A443E4044454D5444444B4F34434A3D404C4E4843443E48484032394941414340414C4B4342414E4A45474C45434A4546453C423E4A4C43394436353E443F41494641504F4440404944473B4B4B4B4749474947484E56444C46414A3646433F534131343F44463F3739434B50484940364E424747453C444840414E4B4B4B474947494701FE24000801D840564F48463F484150503D4C4A4D4E4A473D3647493F3F3E443E3D33404A443A3F38464F4C454E4C4D44474A3E484243434F4A4C4343534A3E4030414646423C454D4D463D2D3B4143504D3C464B52463D4738403942374046423D3D3A3E474D49453A4C4D4E43494D47434D423F4D49422E3C303A453246473D3B46454840504547464743494E414A4341423F5047484D3B3E4037454A43454B5A5046494144402E3C303A4532464701FE25000801D8503C3A3F333C3F46453D3E3E4D40423F3A474D47474A4E4A4A4B3A4341494342443F3640364B4541473A403E434F4450524E49403B3C443F3B3A3D483D4956504544443C3D3F44453E42343E4B50433950584443322E433D3A3E363E44504E46463D393E4A41424546453F3D4E3D42424A4742484334413E4648433D4749413F464A503849363B493D4237414A3F3A453F3D4951484A49402E323F4C3A4539414C4742484334413E4601FE26000801D8603E4044453D39373A4A3651473F40363E40423C434935322E323A3F42443E45414A5239434047443E3C4C3F3F4E4B413F434C4D453F44474B4247493741474D453C424048455149393F413C424C444946403D3D48364A4E423E38453E363644454E423F354047464B2B3B464131423F4A3D474A4739423B473B4646394B4B404343473C443E3D40343E4547514142442D41404136363540384142564A4E4C4B493D474A4739423B4701FE27000801D8703B3238383C4840403B3E48454F4F47483749363E3D4943353734243F3E434B3F373C374352494449423E46323A494247483C34493544403F3B3D3E463A374843453942424142503F413D31454B3E47443D4A514C4A3F4137323A3E384445434032343F3F3C433C4136344251373E3E3C3B3A4045444449434736364336393A4447444143473C3846313E4A3C444639333E473B4B4041373A433F353A4443423B3B3A40454444494301FE28000801D88040433D463B38393D485649423F454A402D3A35324051402D38333F4A3B3C4A4A3D402E3F3C40404A423E49453F4A46313944423F2F3B3C35394642464434363B2B3C3F363B3F383A3B383A454248433D3F47533F34383C3F3C3F45424643453C3E3D34433B3D434031303536393B3C3B4B363B49412F3E41413C414D4D4C3D3F464241444C40352D3B36413C40403D39333B44484941393D383F4749363B31494B363B49412F3E4101FE29000801D8903B383B2B393539383C423C3E3C3E3E443940364939323F413F3F413D4D484F4A413938424A414237413B3534483E3F533E444338343A393644413D442C2E38403138433F3536333E3C42434E3D463E3F3B393A333D3A3F41483E393A3636373B423639404D50433E414A343E3D31383A3B3A35434441424034403E3D3E424E3E36393F364137323E40363E3E3E3F493B47413831333E3C4147393D3D4645433A3B3A35434441424001FE2A000801D8A03F32303843444A3C3C2D3C353A302B43454234493F37384039423E453B393D323B473A413A40343A36363F3D3C383840423536393B3D37373A2E3B43344435383A43415358554C3C36352B392C373537334039374033403F40443F4741423A40413D414A443C263E4D49373E4544402E2F342F3A394547393540343647453232384842444037323A42413C4045393E202C3231443C3E3A2E2D304149473D333A2F342F3A3945473901FE2B000801D8B0374740393E343E313B3E323E373E3A2E3136343F40423A40363A3E3E4543394338392339393F3E3A3E3C3B4234392D393E313D323945394D413344403A3F3A33313640413A3C393B31413F3E333544343D373135313141453A313B353B423D423C3E443C353C3945393B303640343647333E3A3B43353C36374541393B3733333F453D2D4432393F3A453F3A373E3B3E3B47443F33353F44363E3E3C45393C35333E3A3B43353C3601FE2C000801D8C02D3F3F3933313C3E3B373E413238383442453D373A34403E413C3C362E3930343B353B3C41363F36372F38354B3D41342D32373532303B37403B48343333373A433437373343312E34374446363D3D3A423C3443393E3237383B37373241433F3B2A312F3C383F334E42423A412C40433C413F39393C35363136352C2D453E384B3C382F3F483C2A2D3B2F3B33363A403F433C3239363139363D3331333E46403C413F39393C353601FE2D000801D8D03940352F322B2D29333E484543432B3439322732323C2D303A4A3F393B35393B403A2D36413B3E343C393C2E35402F3538323A2627313D4A3C3E404042453D3A473A383842443D3936323636303B3B30383C41342F2F304042462F322D363138363B3B2A343D39303B37404528243430363D4439353B44383A3F353A362F353A40422D333D393A3837373A493E3C393A36283637343D34412B3B35413B302C38363D4439353B443801FE2E000801D8E028353245373642444F4244393838313A392A3137363937293B392F3842322D2331393C3C3D3439373A3E312A2E2C3F3A373B423F4038372F2C352F3737372F383F37443B37302B332C324131353E333E43402E393A33393C332C323A3D373C3232353B3E333131313D312A3F3C2B3B3030292A3D3F42433A3B2940393529292537342E34333339292E37423E4030383A4245423B362F3029353B444A4538323330292A3D3F42433A01FE2F000801D8F04940362C393734311B37424342352B28402628333E35333A3B353D3B3A383B383B3931393E2F2D2E3A2F3733342E2C2C302B293026362C2E31383D3432383D30322E37343B3E36302D333C3B373A35342C2F3A37403D433D3E3D2B38332B3933383C37353634332E2F393A39393A3E3B383A3A32272F2B2428403B354034263B2F4335353238373C353F4125394334323B4937332525313D393E36382F453833383A3A32272F2B2401FE30000801D8003B342D2B3C3F3B33313C293B3D353434363B323732302533334845392B2A302F2F2938343C3D3A3338383D31303831292C3534353B243C40333334332926323E2F313239322F334B3940293D3A33293131383432374138403A3328353633302E37393C3D2C2E3333332F33322F27293439273A3C3424323B2F323E3E332F292D313534343C3A46433431322C392C2C2E37393F3A3626302F35303A363B36333C39273A3C3424323B01FE31000801D810383A3F2F2A312E2F39382E3035382C2B373721332B2E31352D303C363636393C382E32363E3B2E2F2A2531262D2C33393B393A30323A413A322C1D24293D46332128352E2F2B33383A3239302A2939353E3A3843383427323436302F33362A2A393E303B3D2F2B2B292E3C3E352E3636313E372C2B2B3636343633351D2E2D363143423930292F2C3E423A302537302A3C3737212D2A36382F31302F39332E37313E372C2B2B363601FE32000801D82031342E2D2B442E2E2C433E3B3C322D332F2D21373B33393A24263A333738272F272235363D3636352F2E2F3A2E25283637302E2728323B3E37343A394032352E2A2F29343222271F292E31372F33323831393330372F2D3739341F23332C343935352F2C312C333828273233304842222734373634322D323841312C2C3F3F2F2E22312F2D24353F3B3532382F2E3B362B312F39362D353D27282B393C3031472734373634322D3201FE33000801D8302A3034362C3A32303731252F3336333533372E272D2D352E2E36383823382E272C32332B2B362A283C31232123282B362C322E2D2D34362D2C393535292C31342A2E35303E2D2A2C2E302D2D2730302E373338322E3D362F2A2C373B31422B22262E313131372D303A32433828223645362F32302E2930302C28262E333735313C31323731382B282D322F39363C283E3535302C292B352B2329272F1D342B30362F32302E29303001FE34000801D8402B353832333828292E2E2C2A40383732293220252F362431363B3C2A2D2E272525252B362B352B27373B3A27262F2F3636363C2E3438222E23292528283747423435342829272E373028373726313632352F2633332E3A2726282832363A2F30222A242E281E373B2D31282A2E2D29302F2E3328202E3735362E2432323A373B2A3626302E2E29362F363342392428272B373C31372D332B282F30331D262A2D2F2E3328202E373501FE35000801D850262E31312028312826222C2A36402A312D282D2A2E333D2B26282A301F352C1E2333243431372C2D2C2C25262E272E3B38342C302E25352C2A35362B26252F2F24233833252E273234351E1D2629242E333B34293B24263932323730212C35312C1D2437372C2F2E382F27231D2F2E2D2C3536362720302E302E292B31312932482F242F3E3333292D2F1E282D3D322C2C34303528222F28232E3433302831292C3536362720302E01FE36000801D8602E2E2E332E29262626373E2F2B262F382A332F2829262A2F2E312C291D2628303A342B270F292B252F2D252E30212D272A413735353224251D1C1F1A2C313236363331343C362D2D3437422B1B3825321D1F24291F2B323A36302F2727282C25302C28332D301D2B31373E2A292F2C242F2C2E35302824272E32362E2223282534253630272E2B322B272B313B322C30202C292B2E221F3239372F272E2D2B2B2F2C2E353028242701FE37000801D870291D242C2E2C301B252F301D1E2B2B2E3430232C2C333B392A3335372421232B2925212E312726322A272E2D3032212B252C1D3B2E302D312D2C282428273439322833362C30342C2F251F1F2629262B2D3822231F2F3430342D2426292E2A312A212F1F231E302F2A1C2934302F322B2D2C332A3832391F312E2E2C2623273022262837322C3829253C22211B2529292A242D2E2E1E212D3E2B2C2C2F23281C2D2C332A3832391F01FE38000801D88038373131322D2323312C2927262A2628281B1E232B2627293E2A232F302B2A2D282D29372935232D2E2B2B271412212D3826272D29252B31292831352F2F2C312A2C323017232C3B323B20292C2E2F1B2E2C20232C3D2D3122241C2D28252A33312C1E183329312A2C252B2D232E2C291E231D2622252E2E242E2E2324392C1F1D2B37362D2D303329231D291F2D2C29353229272C1C2E2E2A2624252D292C211E231D2622252E2E01FE39000801D8901C2B272A2C321F151F232B2B2629252F1C262F2B352E3C393D3422221A262622322E38383F372220131D222129292720332519272C313022211F212A26242933222E3D2D2E1D261D202E2D2C2D242625261C2D282B302F28232926292C2C32251F2726261E312A362B3C2C28342F2C2224232E2C262725152D292A31252D25172026172526253334302B2B24232B2B281F21293C302832363530292C27212B2C24232E2C2627251501FE3A000801D8A0212B292B352E262B2C30271726242F2F3032302B28282A23252F213028242D21252F2A2B292C22121D332B2A2831242A2B272E282E29252828142220241F21272C32253528222026211E2034321E2C31251D221F26332A221D372427222124232D2F302A1F212A1D2B2A2A2A2F2320292A271A221C2D2E282B2E252628262527222B272C28222223292D26202515201D2422201C253A28212A36322224232B292A271A221C2D2E2801FE3B000801D8B01F2420212D292D201F1F251F3631321E20212D2B292B1D2216211D27261624272420382A2C26282E1C1F2421272C30252D2E2B2A2C291E1E2022291E1B22262F37342E2522262C25242D2A1F1D2E322A2C29241F1D1F1F2F2E252923182024292623231E21221D1E2425171B2F2C271F202B242D2827282B2D2F353725242A2829271E2622252B17232B2C27212430332520202321202F302B2A2C21382B2D1C202B242D2827282B01FE3C000801D8C01C24242E2A2C291F292D2A2F232C2B1F1625302D16292429282C261716222B23292C22272435382E151D271F221B2126252725262934231F1A1F1812222B252122221A1F1E2D28222824142825302F3E23342E1F291B25191C222B25393025202B2A201C191F1B2F1F25241E1D232725232318201F282125221D221E1825362E2A36272A262623181B13231C241D262B2A1C161E1C222328192629252229241D232318201F28212501FE3D000801D8D01C1C1B2825242222211F1F23271E281D2D1B1E1A2C2C1F1C221426231A2229321A23242D292E292313212B1E292A241F292A28282D262C29231F2E150B141B20231529232F30202826221E28222C15212A1D25232B2627291F29172423262419121D282E302B1C20281D2527262321221F2B26262B361F2417182724241F2830213029272625232522241E1F1B16232133262123271F1C1B232123291A1E1D221F2B26262B361F2401FE3E000801D8E0222324271C1D1D1E2A30272C281E2C2B162A291B1D1D292423262831232E2816192827241D2119212C252524181D29182626292618292628292324240F20272322161C11232C131D1C28222821261F302B1E182525202A252421161E2516211F1E2F2B1F251F2A2B2C27291C202A1A1B292020212B1B1E172529231A29252421212224222328262B291F1E222920212025231D221C1C191E2A172D232937202F292020212B1B1E1701FE3F000801D8F02820211F1E2323272A2E2D31211E1B1C1E27231210252C2B292B22170D171819161C24291A221D212225231F0F14171F162C2A1F21201516182424241D1F1C1F2328242325271E1E20221E21192620222220232D2B201D252319211C141F2225242A2225261A141B1127221D2623251F29281E1413202A2C252D24200E1F1E282B292627273623201F1827302B1B140E181817241D231D211E10211E1F1A1F2329281E1413202A2C01FE40000801D80025282427231A25131E1D1E1B0E1E1F181A1B1F1F23271C26230D10211B1223121D1F1A1D1D221C1B2322221C272927191B272B21202B1E1D23231B1B221D1B181D281F27171E21201D1A242A292D211A23241E1F2C1B182425162023282A2621201F1C1F1F1813111E1B282F2722181C1A1D231C2D23161F2014131919232A1B131D1F1A201B1F1D1A1F1B181B1E26291E221619202D312421201C1F231D22281A1D231C2D23161F01FE41000801D8101015271A1929302C211314171A211C1322291B1E27192424171614180E1E1C1A1F1721222122221F1E181A2A371D1D21231B1C1C0F19282A1E1F1D120E1D171116232A2A201F2C2724281E1E201A22221C23231A2225241B1F1B191A171B232A161E171C2B2719151E231F1A181D2219272112141A1E181F29221D18151C1C21191E26241A1E221D170F2327221E1F1D2419221D1A29201C11211D191E261A23272112141A1E181F01FE42000801D820262218261D1B1F1B22161E201D1D1C11181E1E1A231E151E191A1B1B1522201D1B2828151F27211D1610101F1F191A1D211116282C1D2A1F131C1A1E221C1F201318211A1612131E2E1E21161A21202818131F1B12251F1118241828312019251B211E1F1C161D15212214091E1B1B201E291824182419222529261B121C191F16131D1F21181D1F1013121B181015272523291E161C0F1925292622272317181E2918241824192201FE43000801D830191422162324221D2326221816171C19131C1C20181E20191F281C1A262719232A11120E0C1D271C1A161C232C2B2225191C1706190D1F1B1B2120251918211F12121B2B142C18151D1918180A1822291411171B1B241B191F1D2B1C2B1F12181C1F201816211A18171E2625221712202D2216141C211E1A17141B1F191A1A160B1E222418231D20181916151A241012242C17141D23231D10171D1A1A191E222D2216141C211E1A01FE44000801D84017151D0A1F2D201E20252C1B1714221C292C1B231C0A0F101C191D0D0A122017141C0F1A281C1916141913121D28261A071120151F23242B191C101D201C1B0F1D24101019121B1F2112111B17161E1914120D1B15251F1F16251D211D0E1A24261F26181F1B161F211517221C1812212520201C0D201D22222726161A1B0F141B24241014211F162A31241314130B0718191B181C2630281913151A122323152520201C0D201D2201FE45000801D85015170A1E171A281F1B1C24230F1312121D12161A0F15121A1D212019211B1B2518101B1E19232828200C17191C1415180F1C1B16130E1213251E18182D22202224251A191619192213180A0B1212190F1A17251B0913191A1D190E1A23101C1A121521231C181E1A1511261E1C191A20121A1E251A1715131E2221141314141709191F1E13211B13120A2328170615181F1616171C18192C1A1A140D16110E28121A1E251A17151301FE46000801D860281118211C140B1919191416160C141A1B161C1A111818190D0B170E1620200E091516101D15161F2419190B101A070A1B1216201E181C2421221E0E1A23151515181F1C1813181C201C14171E1C160B0C140D060B1F1418111F1C1F191A1A08171D1E1E1D1C1515181C2C171A1E24161D1F1D0E120E1D091B171E161A17181A1A0E101E140E120E0E0D15130C191020171A17211622141C0916181317191B281D1F1D0E120E1D0901FE47000801D870160B0F191E18090F1F181218170612221F271C1515180D1A1E1111180B0B190C1512131617181B191E1916191A101E191C220B211F131D1E1D17160F10110B101D0B1A1B0E0F1114121B1B1A1A0A03191D19040A1B1D2517201210201623161A191E19130E08241C0A1D1613161B21171A1B1B1A221811050A12251B1A131009121F0A1811220819221B24200E0B0E0A131D221D1C1418231C1B141A150B0C031A1B1B1A2218110501FE48000801D880120C171F1C1711151B1B121D1C1A07141818101A1F1E1E0911151416000C1A13121915251917191A1A12130C1818131A09110F25111712190A110F0B11121918221D10101B14121A170D090B0D101E0D0E130F1E1A15201C1D1D171814190D121A181514151B14101817191B1B1D1F131A0E0C111014131110060D1613151E14131C121113201D10130A1213081913241A1121161A251C14150C0D1C231517251A0E0C111014131101FE49000801D89003060F07071B190607190F190613181D0C0F0E1116171E1B201E181A121414130D0818261E17070B14101A191910141A191F130C08201313100D0E14110A121F100E150F050823171E1F0E13180E1C1319210E0D25251311030E0C1A161114030D191B1E120E17101A102008031A090818130F140D070E0C061417221E16151A0B10161612120D0D20161717151A090C181A161B201E15111A11200D181B131B18130F140D070E0C01FE4A000801D8A00E141D1D0F171E0A0C07161F1F16100B140F0E1818011B1807150F0D161F19190C0E171716192F15130B1C0A0F140C1216081813111A0A180B100C0F1E231E1613140E100D09091409191716091412191B1306181208161F1D17190E17161318191710110716120C060A0B0E140E0B15210C0C1A140F17151C1A2210131D1615100D000109100D161C0C1717121B191814140E02160E0F07180E1319111D0C17210C0C1A140F171501FE4B000801D8B010050C1309070E13180B080E131E0C0E0E0E04131117150C08151D09040E0F1312070F10120E09101208161210140C14181B15200C101711140E04151425221C0F1E100F0E0E120E10190D0D120511151812111616160C140B181919151C0A05140918191B121411090E190C0A0C080C0D09090D0F15180E0B1610000914130E0B0C1C14111011131A1C181F1B1E1916150F111111070B0F0B0F070B0F1A0F0B0D09090D0F15180E01FE4C000801D8C01319180F0B06020F0D09121515121E1D1306090B0D12110C1C191202000D191F160F0E16110A100D101A0A1609000503090903090E150F12110A0B0F13130C0E040C1F160F1314181200040C11140A1117151316060E0C192821131A0B110F090C17130D05090A0E0B18121315150B0F0D0D1500080C25150316110A0B1012161819160C0B1010150D130F0C060A0A17140D100F0F060B0E11130A00050B111D0D0D1500080C251501FE4D000801D8D0010008190E0010060B120F05091409101915130B14000708021817090013091C0F1711191908141A10120A0E0E130F161711130A0F1004101B1E131213141A0C0E000C0E0B000003181212021111031213151A110F1310120E170D10110F0901051913100B130A150B060C0A110912110F0E1C1B140C050505121A14101606080012170B120F10100A1D11120817140F040D13120A150C0808041C0808121B0D0F0E1C1B140C050501FE4E000801D8E00609060B0D070B1518170814160D070803060C0F09010414060000090C10120F0F0A0D080800041510121112130E0E1116121E170514141114130E050918141019090D0F0805101A0D0700100A070E0806071915060D0A17151702101C100B0908150C0E1009070E0C0F0D060708150E15081815060213161709121A0C07000B10040D0A13060A06150A1113100F1716160C0F0C0910120D090B001C03090300150818150602131601FE4F000801D8F00D191E14070B0F0E0808040E0B150E0804100C181704110A0B0F1411000C0B181212170B040201090312050803080F100E0F0802040B0B1618100B100B050708070508121C04000A070B1117080B0F160A171B0F0809080713120B141307050D0F0E0F06111118171B1B04100D0A01020711080B0B1405000E0D131C050914130E1009041008121B040000000613130E040202060D0D1108160E010E1216120C0711080B0B14050001FE50000801D8001B120D12060221120A10180D08120907091100080A1812150C0D100A000F1209111C1708040903010A000402040613100B13070A111D0E0B0A110E04110A040A0908090F1A150B04001A00040B060B0403040F1C0D0E0B070A180B0B000A081108131400000B131B061715050F0706060D19080C1014191C080E0000000002131C11080005030D100A1307000001150B13030D110D191B0705140702110C0C030D19080C1014191C01FE51000801D8100000081611060608060B0005080C0B110909100E080A1818090B0E1C0612050A1021190703000F0E1614000801031207000800100C090B0300030709100A030107080D0A00000607111511080A0F0006110C0D17020708000400020A0E0A141210060B06040C120E000F140B100A0A0404090912050915151E0A040106120317120907030E07080F06030800000C00110D040E160A06110C06090B000B0C0F0C040909120509151501FE52000801D8200A0C14130800000000080A0A1017080802000000181507020F0E14000000020C07050F0F0C07090D000B090D0F000005050A061A17030506040A090A070A00070E12060D150D0D00120B06070C08060B14170F0E03000400070C0E0B1003000600160E08000B05060200030E03090A01050607120A070909030C120B100C07090004110A0F0C080A00130A010A070A030007050A020904080B0C0E1A1C050500050607120A07090901FE53000801D83003040003060A0F0900060002081001050104000F100F020002120E000000000000121500040611121601050001090C0C100200000005030708030C160C060C060B08090C0D0C000B040C0A1510110003100C0D0A0E0C000700130F0A110A060000110506170900050F08080008010D06000C0E0C0906020004051604080608060D060B06090902000000140B0E0B000C0909110902090B101209030507030207000C0E0C0906020001FE54000801D840050A0900110003010400050014131103100000140E080F030400050806100D00050715010D0C080D0304010E1304040000000004000400000606130A060B0A171306081708000C10000E02000A0E080500000000030B000515070204000F0C0B08040502000000000A060A030A040D040607090E0A0E1203040D0A07020C040000080414100F0504020B0A0603030A00050A0007010A06080B030000010807020607090E0A0E120301FE55000801D8500B00070000080911080D0600050A09020402000309030000000F040005000D150000050C050B08010A0C110F0903000805110605000002020004050E1106090600000000050700000000050B020404000D0004100E10020001020F0007010B00080A0909060709000C04000806000A000A0E0F0909050002000300100400000606080900000B000D0F1100000002000105130401000C120004060D0D0A0700050A0E0F090905000201FE56000801D860000B1005020C000D04000403000409020308000000050A0000090A08040B040507110C110F06000C0000000000000001000305040007030700070001000509020E0B040A0D060005070300080000000412130B0D060A000000000600030800040009030C08030007140E000000060B0E071202010002000300070506060B1000080A000000000300090005050000170D0506000A000003051003070000000008071202010002000301FE57000801D87001070C00030308000006010300000300061400000100000500011403070001000A0000020900010000030D0B0002080000090A080F0603120000070000000000070300050200080000030507000E0E04020700000005080900010000070D080A0700000500000000000B00050200070000040300090000000002000505090D03070003010802000000050D0C0303020903080100000100090000000000000109000403000900000001FE58000801D8800B000004110A07000000000000000003000602060000090F020A02000000000709080D000201000B00010002080700000B0803030100000001060003070900000400000000000B0300070B070000000000000805000000010708070D07000000090809000001000004080A0B0700000A0700070C03080C00010000000009090000000000020000000000000A070000060B0009050600000002110C03000000010700070C03080C0001FE59000801D89000070000000000000001060000020008080E02000000000000040007080400000004000D0D07000000000000000000000B0000000000000002000F0600000400030000010509000000010000000207050804000A08040100000000000004070000020009040F0E07050000080001000605000000000000040000000007050001000000040A0400000000000800000102070700030002000C0E03000003000000050000000000000401FE5A000801D8A00A08000000000300020006000700000000010A00000000000000000000000001000409020500000000000000000000000707020000010007000005080904030800010001080000000000050A0E0D00070000000000000F040500000A0A0607030000000000000000000605000007040E0301000000020106080705000600000001000500000000020007080B0000030100000000000001020100000003020007030100000002010601FE5B000801D8B0000000060002000A030000000000080900000000000810090E0000000000000A0A0001000007060000000000000000040000000000000902000000000000000A0F0500000000040000000000000000000000000E15030000000D0E00000300000000000003060A02000000000000000900000001000000000400000B000000000702000002060F05000000000000020007030000000000000000000009040000000000010000000001FE5C000801D8C000000000000100010000000000060200000D02050207000B000000000000000000000000000000020000000000000000000000030000000000000000010100050000000005070401000000000000070000000102000000000000050000000000000002000001000500000000080000000000020500000000000012000A0C0104000000000000000000000000000A060000000000010201060700000000000000000002050000000001FE5D000801D8D00001000000000100000200000000050000000208020000050000000000000000000600000000020000000000000C0000000000010000000F000000000800000000050D000000000410000000000000000000000000000000000000040109000000000000000000000104090003000002000200080900000000000000000000000000000000000000000000020000040000000000000000060600000000000007000200080900000001FE5E000801D8E0000000000001000000000000000000000000000000010B0000000002000000000001000000050201000000000100000000000000000000000000000000020200000000040000020003000000000000000000000400000506000000000000000007000B000000000000040500000000000000000201000900000000000006000001040000000000000000000100000000050E0000000000000000040000000000000000020100090001FE5F000801D8F0000003040000000000000000000000000000000000000800000000000000000000000000000000040000000000010000060000000000030000080400000000000000000000000000000805000000000000000400000600000000000D0000000000000601000202000000000000000000000000000100000000000000000000000000000000000000000000000003000000030000000000000000000000000000000000000100000001FE60000801D80001000000000509000000000000000000000000000000000000000000000000000000000000000000000000080000000000000003000000000000000000000003000000000008000000000000000000000000000000000000000000000300000000000000000000000003000000000000000000000000000000000000000A0000000000020000000005000000000000030000000000000000000A080000000000000000000000000001FE61000801D81000000000000001000000000000000000000800010C02000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000500000001FE62000801D8200000000000000000000000000000000000000003000F000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000404000000000000000001FE63000801D8300000000000000000000000000000000000000001000000000000040905000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000040000000000000A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE64000801D84000000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010005000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE65000801D85000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000001FE66000801D86000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE67000801D87000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE68000801D88000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020001FE69000801D89000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE6A000801D8A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE6B000801D8B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE6C000801D8C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE6D000801D8D000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE6E000801D8E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE6F000801D8F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE70000801D80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE71000801D81000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE72000801D82000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE73000801D83000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE74000801D84000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE75000801D85000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE76000801D86000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE77000801D87000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE78000801D88000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE79000801D89000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE7A000801D8A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE7B000801D8B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE7C000801D8C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE7D000801D8D000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE7E000801D8E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE7F000801D8F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE80000801D80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE81000801D8106D686E7D7975777D736A707376736B7675706F68707372705F766F6D726F7F7E7D786A6C6E6F65676972786C726F75666F758077717C6D7478635D726E717E6A6666747172746B75777377757D79757664736A6871716968736F756B716B6B717A716B6E687F74736E786A7A767374626A76797560716E717372677C7D817C707B736D6C6F6B696C6B77727172707362686C6F72796D767470757C837C76767C6A76797560716E7101FE82000801D820737074706D686C7378687F6F746F726A72717A786D6D7F717A7385786F748084775F676C75777973676D727175736F77777B75707A798976777572686B7274777E7973777D7880666E686B72696C6E79707F746C7376776B6E6F697B7872716C71716A6C73707C7782756A736E7A827A7173716E726D6D7579806C76706E686565797F706F7A75736C746568768072757B7B706768736D7773777973706F75717173716E726D6D7501FE83000801D8307C72786E857E7B6E6F7980727E6879707075776F767A6D74746F6F6C6B71716B7C7377627B717770707B7E816D7573827F7A736979776B716D74757678727477717175766D82847F776D767271776970716E696F6D73727A7D7A787F727C7B716E6B79726F74806C7067727D74917464757B6E6A7B71756F72797F796E73767176746C6F707377766E69636C62686C7A747580897C6F7A786E77806B75777D79757B6E6A7B71756F01FE84000801D8407C776D787E727F7A717376787275777C79827C7D796C6A69787F7E72746D78757E86827676737675687571747672636477706B7D6A7779767F7A757A8B7D756D776F7A777B8689706E736D6D6E7D7872706B747D7D76756F74757F777877847F727E70746A7A796B747E7E746D777276787B7B716E726A7B7979777775848074766F767E75817D7A676E6D768B7963676C6F6A6E767F727274777370746E7C7F787B7B716E726A7B01FE85000801D85083787874838C7B716F737071716C777679838287837874767D73746B79727F897C6B69746C6E7F8378777D77716E77786F7D75777E776E7C7875776E708176856B7880736F6C6872776D72757C72757E817B857D7A7A7271756E7A7E8775706F7779796E6A7B7B856C74846D6D7676776C7471737B79787D7582776D757A847A71728277746D7780728879767C7F777B75768079827267708578847F647076856C7471737B79787D01FE86000801D86074707C747F7C787B8076747378787E807F807678717B7A767070797477717F736F7379848283737C777D757774767D836F7F777273756E6D7F7C737A697D737980807181807B7C767B706D7171717E7D787278827879827F768A847D71726D73717F6B72786D7478727373757979737E86807576787D83867E7D7D6C7073807E7870707071737E7A7F7C6B707D737F7E7A8279767B7E8870706E7A7F7773807186807576787D838601FE87000801D8707372857F717F7D756975747B75767D837F836275827A7778797E6D7C7B74787F85747C78736F787C7E8682727074817C827D887A74766D7975789090777E6F7472827E7B7A667B84717882838571797C7F7A7B6F70717C80706C787F7C747E80817F6974737B7D7A7B76827E7877767470767B7A6C8188827B7C827F7769787E7A9082706B86877772737A6E737D757878788288726E767B7777758678706F7870767B7A6C81888201FE88000801D880878979797D7E74817F817B7F7B7C8277887A777A72656F85706D7D837E7B7C817E7E79747C7A7E7C8586827C7A777578797472827B6D7C7F897E7B807A7574767F7F7484877A7A7D8C84837C86766D807D8582867B6E747B6E746C7D7170747B7C717B7D75788682757B7973847C74836F7B777B857D777C817E887C78837384827A8375756F7C80827678818984747E82788082707A757B82788580827583836F7B777B857D777C01FE89000801D8907975847F707C6F707A7C8C737C70748071777781848B787E78848E89817885767276706876857E787D7E7C857B828482878B718384807D7E8C897F6D776A7A7E747E778A8B89827C837A7C7B867A6F7A7774877E7E7B85817D868079747472747C896C756F7382818A817B7D80837C6D7C797C806E7478807A7E89777A787F798282827B7F8B776F7B7A7B7C7E7C7B7C7D737D7E857C767A85747E7B857F83757C797C806E74788001FE8A000801D8A07B6E777C7F7C7F8588807F7C7B7B7D81858C88748089867A7672757F817F7D747A6B73757A84847E8B838382867F7C747B73818184847C7D8489848A808885827A80867B7168747B797A7E7A8287856F747F7982787F7D826F8381787A73768379897F727F7D6C77768682877C7D81848782817C85847D7D827C7E897F8373747E77807C8B8A7D838782837A776E847D7987847678807E7F878685807F877F808782817C85847D7D01FE8B000801D8B076788073787F818380857984897F7B728178788D7F7F7F6F7A76817E7D768279818384776E79818288717F8D84837C7B848380878D828283938D8C817B78767B8B778788777E7C7B8185767576797E7B737B7C7F837A7F8482727A867F7C7F7D7D737F89967D7F787A8388707E7F7D857979818883817D7488807B7D7E7C7A707C878587767F848780827D8080878283858790917B7C787E7776757D787A78847979818883817D7401FE8C000801D8C0667582757C838982778A807C757C7F827D7B7B818580828879748180827783897A737E93837D7D7C8A78808B7F78808D81828888837C8690838571757B8482858D7E77718C80797573877C85888A878B7E888B7C857E8087877E72787C8283817D7B747E7E797E8A86838B8088808085828E807C72727B867A7F7D7E827F7E7B768082837F7C82858F888180707F776D78766E7A8385807C827B80857D80807C828E807C72727B8601FE8D000801D8D086807C80828A8394888781767D807B87837A7382867B838A87818187848983938D88817E7B817878767D878B8783788E84808289889189887678827F8A887E8B7D848B81808171707B717E7F8176808380838C908C7D8B8B8A7673747C81807E838384887A7E818A7E818076798278827E6F828F8D83837E8C728A86837D7F7D7B857B8A92808D8888807E7E868D867A7F7A818D8D857F7D78777F81808986717E6F828F8D83837E01FE8E000801D8E0747C808788848580808C97897F7977787D7E86857C787D847E737B828285807B8C8287898D8A8C8E7C7F868B7D79817D898281929B838C808285827F7480857F878B8092888A898E88837971807A848B94838A8B83868279807C80807D8B86707E89887C8F7D85797F74808386847E80867383788184868A818B818D8D877E807C7B797C8A877686787F858D92947574769191848C858285908582737C867779867383788184868A01FE8F000801D8F0908C758787848484887E857F7F81848786868880797F877D7F827C88888D867E82838E8B8480898487827F8286928C818A807D93928985807E81857A76727F8A8B80858879737A89867E83828594868382818386867E907C7C929388817D837F8783828C7C868F88839191899583887C82798F86727F82847E83907A8081808C7D86888B7A81837E858284807E757C8A848C758589888F8C817D8A8E8D90858482798F86727F828401FE90000801D80081716D767E7F8F8F7D778285868D817C8E8788917F827C82818B9389838277818E8C857F837C7A838A83828088858D9284827E737F8C87867D80848A85867F7F908886918F9A878B8F8686868B82888C938B8582827E78807C80858A858988848C7E83898C877687877F87908D98978F867C807A868F85747991877F868A8D878A8C858287878488817C74858393887D80878484848588868287868F79888084867C807A868F857401FE91000801D8107A898E8C7E959087818082797C8B8F8B7E81847C85808A8886788187887E83848D858E8D979081848885827D858F86807F8C8C898F908B8F92937E86918F857D84908382798887928B87847F8271847F7F918986878D887E81887E81888890898D8985878591838083827D8786938C8E8A83818B83867E727789868C86969180928D8688747C8B858882858A837B7D8C92887B8B8A8C8B857D7D80777E8C868B8A83818B83867E7201FE92000801D8208D7F888F8789897E85909184888D878887868D869A918E838B908F899495818D84897E7D87878C8F8283757E808B818A8483838A8499928886988B998E83808784868373888B877A8382897B898A8085838986808C8F83898E8B857C9090958587858C898682848387888C767C8488898D8D94969A8B8388847C888890808C7D88898C8C7B8C7B80847C7F928788897C8E9C8E8884888C898B8A808C88888F7F8D8D94969A8B838801FE93000801D83093949B9B8B998E90888785898D8881807E8C838C8C9B84928286897E7C8C8F8F8A847D878A8B927E767C81877C8C928E8E9C9389888B87888B878F84807E878591878C878B8A84868189858B8A8D8180859393858788898A8C86868B7F7D8A8D9E9D8E8983948D8F8F8E8083768D8C8D958A8697828984838D9C9590888D8A9B8C7E818B83858E8E8484858D8E838280818D8C85888F97868C8B87868D7C9190958A86978289848301FE94000801D840838A7F8E8F888C8889968F8391918A858F8A978E9B808683827C8787788B988F858A8C86828B948C8D8E84848996868D928488898487868C90938E8E968F878282898B84878E92877E868B9F94869590838C898D8E9695898B86A097847C828E938D8B948D7C838085898F838687827F8F8F8C8F9C868182827D8C90858B86938E919790967D7D7B8D94978E8279838182888C818A88878E8C97859A959487878F8F8C8F9C86818201FE95000801D85094868584818B8786958B88888D908A8F929591877A888B8D939489968E918B8B8A8C938D8E8C818A8F92868381928C85868C8D897F90869D8A96A18C9087928B849390828796958E8A8D8F8E98848D838C86878B8C8A968D989582898D8996969F8F888C728697807F868F8E7F89908D8A89898B8D92858D928B8390918D827B88918987958D8A7F8A828A978B90917F8C8F8B88898D869786918F96948F8B828A89898B8D92858D01FE96000801D86087848B8D848E9092938F90969091878C8D8689888898918D84807F8B909091958F8386809890808E8B8B8F95888780918592968B8C8495938F97989684828D90838B89928C998A8A8C8888878782839191948F9995998393939295939382877D968E8E867E8C858296908B8A898A908B958C8B978F858D928F8F86878E85918C8C948F8D837F918E939389958A9482848D868D968B8D938B848F9293958C8B8F958C8B978F858D9201FE97000801D8709B9382919B8A8C88949C9694918C9692888F9C96939089898E8D83868F8B8C8D8588838687898C969294828B879893A398858A7A808E898F968A808B8C898F978F8E8F929B9A92A1909496908A8887988F85848C90877E84878C838A8B979BA1A29B988D7A9683898B8C91909C8E8F968F94858D8F939C94A39382858880848EA3929192888F9089838A8D8D888992928F909692918D94878895928C8D8A8C8C8F94858D8F939C9401FE98000801D880848B999A99918A8F92878E8B8A948B908D8A95868E838996948F9F8A8B92928B8891949D958C909D9A9691909D8F969B979A897D8E81859189848F93898B8C8584948A968D8A938D93928A9589818F8F918F908B85948E96879B9A928E95968E878AA48F829A9492918C9995988F8D9391939A8D847E969E949A9E9C888F7D939A92878B8F8591908B8C878A8B8589938B99918C9095979790A295928C93929891939A8D847E969E01FE99000801D890998A929988808B8C969E9E999A919A928C8C9192969E9493918F908E8C81908988989293948E91968D979C8E87918F96909296A18C908F878880908B8A9693908E8D8C8C908C96958B9896A9999994878A898A8E81948D9995938D988D8F9B8C9B9594958B947F797F8984978F908E8A929295909B95999B8F918A8E8492969C91968F8E9E8C8C959499928F979793908F8E979C98909A8E988A8D9196878990929295909B95999B01FE9A000801D8A090938A8C999994949087928A8F919097979C98919A8C92968C968E84978E91989A95A386959598969F9192867E989691979A979889888392989A90908795978F9388859B9A93928B91939699988F9A949A98A4919294989797978B99A096838F91928F9A939586908E86969F918A9595919C978C8A8B9891A19E9D95A08E8C91918B808E8F938C91919796978B9C91969189A29D949699999390969492838A8F919C978C8A8B989101FE9B000801D8B094949E919488959BA38F93979C8F8D92979F8B8F8B9696948C86928F92948A99A19696A09E98988E9F9496848E888C83999B8994959090988A8D94968F859EA18F928F96918A899AA19796919B939794969C9297A08B969B93969291A0979D94899795818A8D909088999D9788999A9382918C9A8B908E938F93989295989F9A9390899892939798899B94A59D9095949198969A979A979089959C948E9FA08882918C9A8B908E9301FE9C000801D8C09B7B8B888292A09494949395A29F969792999A9894929D9DA6949B9DA2979B8AA3908F9A948C8496999B918B838A9E948A8998A99D8D8B9C98989C9A9A9C8B89948E888692979A91979F8C8E9B97979B9A9B9D919390979B999A92968A99959D8F93A38E949585979290939FA0938B8B979695938D909E95949D98AE8C8D92979CA199938F959998959F9B8E928F8E8E929AA395989C919481908D8F9B9B8D8D979695938D909E9501FE9D000801D8D0979D9FA0988C959B8B969594999287A39698878D989C979F9A9D9C8A989A989E98919B99AC9585998F8D9495989F9B959096959A8BA19299A5A0AB9997A6999485948891998F9293949E9591979994959394928C92A09F9E9E9697919C9A90949A8FA39D8E9091999A98919C99909093A1959591999B8F9D8E939C9D9C949C919C9D9098869096959797A399A49C9B959A9C919096999E9A919B9A9F9891988EA1959591999B8F9D01FE9E000801D8E091A28D9690919697A1A79F9B9F8E888B8AA0A29D8C959394998C969F8B938F97959498988A908E9D949EA499969B97A59D9F9A9692988A9FA4969794949B909B9393A1969B9D9195A4A9A1949799918D939496949D9590919A9695A9A39B94A1918B8F92928F95A69D9E97929A959299899A908F90938E909E9E9A968F96989CA392959BA69A9B9EA0A69592A28C979B987D919C90988F94949897A2979C9792899A908F90938E9001FE9F000801D8F08A9DA292909A9CA39AA09CA1A2A4A7A2AA98A28D929D9C959894949A92949C97989592879B9593938B8F9CA1A59E9C95968A94977E9595A19AA1A79F8E989B9A998F959EA9A3A79F9BA0919BA5A9A59F9194869F8896959A9EA7979F9BA3A7969299A8968F97868F9394909FA591989D9B9F91A1979E99979AA18D9E999A96969C8F9CAE989F94999F9BA79695938F958F908EA19FA69195A5A19D988F9C94969B9F91A1979E999701FEA0000801D80095959A94939A989D94928C9D9FA19A9B9F9C9FA0A6A4958C8B9BA39D95A399A89E9E91A2A09E98939A9F9899979B9AA39E909698939990939FA7A8978D9E989B939393989BA69C9E9D9D9A969C96959D8A9C9A958A9B90989C9B9B9A9A9F97A39F9AA8A2A498999093A0979F9E949BA3A9A4969A9A9DA193969091A297A49B989B9B9596929DA29DAD9F989DA7A4A694A3A69A9C9AA3A0A09597918F999B968AA9A4969A9A9DA19301FEA1000801D8109BA093958F9A9EA49B9FA89792A2A1979EA4A79D999F9FA59292979B9FA293A28D92918BA1A6A4949999909FAAA8A09A9EA49C9A9DA0A28F9E979E8A9C98998C9598A7A0A6A89D98A5A19EA09EA09A9CA19FA39797A38F9E9F919B969890A295928C90989C9FA4A7989B989A9EA5A39E8E94959995A4949B8D9AA0979D9A96909CA4A3AD9D9F9D99A29F8B988D98A09C9E9E9F9E909B9FA6A398A0A1A7979B9D8E94959995A4949B01FEA2000801D820A89F9C918D99A7A996A491A6A49F98A99F979B9496A2AA919896A7A7A39B959B99A3A6A1889096A19C9899939CA0949A9DA0A9A89BA3989CA0B39D9A98949A999BAA9D9A9A8F989F9E9C9DA4919C9A9FA49799A8ACA0969D9DA293A9A0968F97979DA4A69E939C97A2A29A9494A09593969E99A1A698A7A0A0A5B69C9796A1959F959D99999F999AA6A697A3A09E9B97969BA49998A99DA2969997A5A4AAB1A7969E99A1A698A7A001FEA3000801D8309B9DA59AA8999EA9A7A29596A5A0A6979398A2A19CA3A29FA694A2A6A69EA49F9E9E9E9E99A1939B9CA5A3A59B96979AA4AAA69A9AA5A2979AABA4999B91A39C9EA0A29F9C969B9A98ABB4A59D9293919FA0A09BA29F9F99A19B97A6A8A1A59BACA395919391A6A4A19BA09B8EA2AB9B9CA89EA2A19DA1A6A5A3AA9B989C8C97999894949B9F9CA0A0A19D9BABAAA7AFA1A5A2A0979AA2ABA493A4A69B9C90A29CA89EA2A19DA1A601FEA4000801D8409E9B9EA39FA0A29F9AA19C9F9A9E989B979EA2AEA8A89C9C99A4A2A69DA1A5A6A59A98998E9EA3A89C9DAAA9B0989BAE9F9AA39F9DA89D9DA1A0A19A9F9B9E989BA1A0A09C98A1AAA29A9997969A9FA1A2A79AABA2A995A29CA69FA7A19CA0A2ADB1999299A79BA19BA29A999F9B97A298A2989D9FA0A399A3A197A0A5A6969CA2AEA3959F9DA9A9ADB4A09A9F909E999BA4A3A3A99A989B93A19D9BA09D989798A2989D9FA0A39901FEA5000801D8509EA7A4A29BA9A1AE9BA5A69C96A79E928D9C9FAFA5979CA9B699A6ADA1A2A49D9D9FA9A5A89F9BA8979EA6A69EB1A49F9F9C8F9697ACB4A09BA2A69F95A8AA9F99A5A4A598989BA49E94A2A49A96A3AEAAA69EA7A19E9A90A2A0A6AAA99EAA9F9FAB9898A3A5A19FA59DA3A69B9B9F9DA9A49A959AA197A2A0A59B979E90979CA5A0A1A799A1A7A6A2A5AAA29799959B94A09FADABAAA4B4AFB19E94999D9E9BA9A49A959AA197A201FEA6000801D860A59BABA59E9BA4A3968A8DA7A09E9FA69DA3A2A1AEA3A698A19BAD9DA29D9CA2999FA3A7A6A4A5A8A29AAAA5A9A6A4A3B9A4AE9D95A69895A09E9D9E9C9FA39FA3A7A1A2A5A7999A9DA2A1ABA3AD9FA29AA79CA4A1A6AAA19AABACA3A6AA9C9F999B8D95A3AFAB9A9EA4B49EA2ABA1ACAAA8A4A2AFA9AAA4A7A0A7969D9C99A291949C97A6AC9E9AA4A69D999F9A939CA39EA9ADA9B2B5A191A5ACB0A2ABA4B1AAA8A4A2AFA9AAA401FEA7000801D870A39CA1A9AEACA29C9C9EA49E949EA1A0A2A2A7A9ACA9A79CACAEA99F97A79EB2A4A0A2AAA9A1A5A6A1A4B4B3ADA598998FA19B97A5A0AEB59D9EA4AA9F9FA0A7A3A1AFADA9A8AAAAA4A9A1A1A1A9AD9FA1B6B5A9AAA89B969C999B9F99A4AE9E9C9E97999CA5A8A7AEA999B2A5A3AEAF9C9FA5A49C949CA3A5A5A4ADA1ABA8A4ACA7A09EA2A1AAB197A8A7A5A5A59FA6A3A4A196949BA29FAE9B9FA98FA2A49A9C9FA5A49C949CA301FEA8000801D880A1A1A495AEAEA4AFACB2A4A39FA4A9AC9FA3A3AEA5A09D98A0A5AFA2A5A6ADAE9BA1A4A0B290A7B4A6A3A6A49597A0A09E939DA4B0ADAAAAA5A3A6AAB2AFABAEABB1A09D999FA0A2A2B3A2A79CA0B1B2A9A0ABA8ABA9A4A199A1AD9E9BA3AAA39AA28F8F9DA19E9DA7AEA2A69A9FB7A8AF9F9497ACA2B5A6A8AAAAB39EA9AEA9AD9BA5979BA7ADB3A89F9CA3A6A3A1A7A09EA2A0A6A9A7A2A9B1AEB4ADB3A1A5AF9F9497ACA2B5A601FEA9000801D890B1AFA79C98A9A0A0A1A1B0AFAFA797A8B2A6A1A5A8ADB5A49BA2A4A1A4AAA9A7AC9CA7A9A2A79EAFA2A9ABA6ADADABABA8B2A9B1A5A9A4A7A4A6A3A9AAAAAFBAA5A29BA9ADB0AE9FA1A6A0A3A49BA6989BA7B1AFABA7ACA6A79AAAA9A7A4A1A0A59BAEADA49A979BA2A494A1AEB2AC9FB6AFA6AAB5B1AB9A9EB9AAA39FA1AFA6B0AFAD9FA09FA89AA6A59FA2A39EA3A79CA5A4A39A9FA3AEBAB6ACB4A9A09BAAB6AFA6AAB5B1AB9A01FEAA000801D8A09FAAA8A4B2AEA9AA9FA6A2A19CA09BA8B79F9FA6ABABA4A1A3A6AEA89EABA79F9FABAFA6B0A6A2B5A3ADB0A7A196A2A1ADA7A5B1A8AEAFA998AFB5AFA1A6AAABADADAAA9AFB1AEA2A3AAA6ADA3999998A8ADAEA3AFA3A8ABA7A7A69BABB1ABB5A0A6A1A0A9A29CA1AFA8A9AA9EA19FA1A9A7B2A0B1A9ACA9B0B6ADA6B4A79C999AB4B2B3B9A4A1A5A4ACA4AEAA9BA2A79FA2A2A8A8A6A8A7AA9AB1B3A1A5AAB2A9A7B2A0B1A9ACA901FEAB000801D8B0ABAEAAB4A7AAA9A7AEB2A6AC9DA0A3ABA4B1A5AAACA6A6B7B6B8AFA1A4ABADA2ABB4A7A3ADB2AEA9A8A7A9ABA6A1A4A5AC9296B9B1ABA0ACAFB3A7B2A99B98A7A0A3AFAF9DA79D9AB4A8A39E99A8AEADA2A2ABA5B0B2B3B1B6B2A9A5ABB5A6ABB1B1AEA99DA5ABABAC9F9FB3A8B0A29DA191999DA7AAAAACA7AEABA69CAAADACAFAC9CAEB1A1AAA8A6B0AAA7A9B0AB95A8A5A39E9EACB2AB9CA99FA5ABA8A9A7A191999DA7AAAAAC01FEAC000801D8C0A9A2A9B3ACA7A9A7AAB0B5A3A3A5A4A8B3BDC4AAABA8ACA6AEAAABA3B3A7A1ABADA2B1A2A5ABACB0ADAEB0B0ACB2AEA1A0A7A1A2AFB3B1ABB0AFA9A1A19CA3B2A4A4A3AFC2A9AEACB8A9B4B8B9AE9FAEA1A49BADA49B919DACA0A6ABAF9FA4B5ACA9ABB1A8A9B5A8B1A6B7A09A9BAAA39CACAFAEB6A8B8AEA2A9ADADACAFB0AEADA5AEA7A8ACA9B4B7ACB4ADA7A7A2B6B4AD9EA6A3A3A3A7ADACB1A4A6A09E9E9CACAFAEB6A8B8AE01FEAD000801D8D0B6C2A9B4A9AFACA1A4A5A5A8B5A99FAA9FA3ADADAFB2A79BB8B5A5B9ACB5AEA9A6ACA29CA69CA6B1A9A1ADAAB9AFAAA5A5A2ADA8B0A8AAAAAAA7AFB3A4A8A8BBA7AFB3B6B6A6A9A1B3B1A2AA9FA1ACACAFBBADAEB9B3AAABAAA0A2A29EADB8ABA6A4B2AFACA3A7ABB2AEAEB3B69BAAAAACAFA7AFB6ACB3A3A4AFA9A4A2AFB4ABA7A1AAADAEAAA8AFADAAAEADA9A6AFBAB0B1B7A3A6AAAAA79EA7A6ACA59CA0AFACAFA7AFB6ACB3A301FEAE000801D8E0B7AEACB1AAB2ACA8AAB5B3BDB7C0A5ACA7A89DADA9A8ABA2A7B4AB9BAEABB0A0B2B4A9A6A7ADB1A5A89FA9B0A8AAB0AAAAACB2B6AEAFA9B5A6A5A3A0B1ABA4A6AAAFA5A7ABAAACAAA7B2B9C0B4B0B3A5B1ADA8AAAA9FA7AFBFBEB9B8ABA8AFBABDB3AFA89D99A1ACBCB2A6AB9EADA8B2B5B8B9B5ABB5B0AEC2A6A9A2A4AEACB2B5A3AAADB0A7A6AFB4B6B2A9A8A0ADA9ACB3AEB0B2ACAAA8AEA5AAAFB3A6ACB4B5B8B9B5ABB5B0AE01FEAF000801D8F0B4AEAFA1ADAEA6B3B1ABAEB1AD9CB3B0AFAAB6B4B5BEB19DACA7A7AAADB1B8B0AEBAB3A8AEA5B0B0ACB2ACAEA9ACB3B7B3AEB2ACAAB2A9B1A9A0A9B6B6B2A3B0ACB5B8BAB39EA5B3AEAFA1B2A6AAB4AAA1ADA6AFB9B5B3A5ADAAAFAFA7ACA9A6B7ADB7B2ADACB3B1BFB1A7A7B2B6A9B4B0A6B1B9B8B7B4ADA7B5ACA1B2A6B2B1AFB3B4B5AAB4B1AFB6B1AAB0B7A0A9B9B6A4B2B9B0BAAEA8A2A3A3A9A5ADADAAB0A6B1B9B8B7B4AD01FEB0000801D800ADBCACA7C1B9AAAEA4A5B3AFB9A3A1ADAE99A0B8B1ACA6B2A4AEB3B2BBA9B7B3ADB5A9B5B5B3AFB8A7ADB2B0BEBCB1B5AAAAA9B2B9AEAFA7B0ACB8ADACB0B3B1A5AEAAA8A3A4A1AFBBB4AFB4B5B7AEAFB29DB6ABB6BABCAEA7A2AFC0C0BBB1B8B1BC9EA29EA4B5BCABA5B2AEB3B2AFA8AC9FB1B5BABAB1B3A4BBADADADAFABA4A5ADB4AFAEAB9EA4A2ACADA8ADB7A5AB9FAFAEA6B7B6B1BAB2BAAFADA6B7ADC3AC9FB1B5BABAB1B301FEB1000801D810A7B3B1B1B8BAB0ACAFAEABB4A7B7BDB5BAADB0B9B2ADAAABB7B2AFB2ACA3C6B2A8B3BDAFAAB1A7A1A29EA3ABB9C0B0A5A8B1BEB9B4A9AFAAA7B1B4C1BBAFB6AFB1A4ADAAADB5C9BEABB1A6BAB0BDB6BBB2A4B5B4A4A89FB4B8B6A9ADB6B0ACB4B8B9B6AFB5B1AEACAFA8A7ACACAABBB6C2BAB0A7B3C2BEB3B0ADAAAEA9AABAAFAFB0A4ADA8A7A4A6AAB3B0AFB7BBB1B3ABB1ADB4BCB6B4A9B1A7B6B8B0B0B4AFC2BAB0A7B3C2BEB301FEB2000801D820B0B8B1A7A7ACB3AFADABADACA9B5B0BCADB3AFB6B5BBBFB1B3BEB3BCB4B2AEB2B5ACB5BAB7BBAAA6A5ABB7B9A2B1B9B0B4ACB2B2B7BEB9B2B5B4B1BAB6A8ABABA1ABBCB9B1BEACA3ACB3B7ABB1B6BBB1B7B6B9B9AEAAB3B2BBBBB8AFADA5A7A7B19AAAAFB2B7B4B8B9C0B3B2BBBEB3BFB7B0B3B6BCACA19EA3AFABAAB0B2BCB8AFBDC7B4B4B9B2C3ACAEADA9BBBEB7B4ADADBDA9AEB9ADC0C7AFB2B3A7A8ABA7B7B0B3B6BCACA19E01FEB3000801D830A9B3BFB2B1B4B6BCABA8B6B6BDB6B6B7B4A9B2B4BCAEBAB8B9B9B7B7AFB5B2B1ADA9AFBCBFB4B8B5A8B6BFBBAFB3AEABAABCAAB8ABB2A7AEB4B1BAB7BABFB3B2B9B8A9ACA6B8B5ABB2A7AFACB6BAB8BAB8ADB5B3B5BCBABCC5B6B6B8AFA0B6B3ABA7B3AFAAABABAFB9ADB2ADA4C1AEB5A2B1ABB3B3B4BDBBB7C5B7AFB3B1AFABADB6B9C3BEABB7A3AAAFB9B5B4B4B2B2B7B2B2BDBBB9AFA5ABBCBDB2B4BDABB4A2B1ABB3B3B4BDBB01FEB4000801D840B2BFB8B5B1B7B0B4B2B6B7BDA9ACBBBAA9AAB1B5AAAFADB0B6BBB1C0B8B7B0AAA9AAADC6B0B4AAB5B1B8ADB5B3BDC6B2BAA6A9B5B2BDB4B6B6B3C6BABFBABDBCB7C2B9A8A9ADAEBAAFB9B7B5B2B4B8B0AAB6A2AFB5B7ADADABACBAC1AFB3B4C8B7B1B6B5C0B1B1B0A1BEBDBBB4ADB8B8BAAEB1AEB0BBBDB2AABBAFAFB9C1B5BCB1B1AFBAACB5B2BAAEABB8B6BDB6BBB2AFB4B9BCB3B3B2B6ADC5C4C9B9B4B6BABAAEB1AEB0BBBDB201FEB5000801D850B9B3BFC0BCBEC0B7AFBBC1B3B6BEABABB3B1ADB4B0B9BBBFBFBBB9B8BCB1B6B7B5A7B2B3C5C1B3B4B0AAB6BBB3B8B0B2B0B0B5ABB7C1BFBBC3B8ABB9B8AFAEBABCBAB5BBA3AFBAB7BAADB4B5B3BDB1BDAAB3B4A9B6B7B6BEB0BBC4BAACABABADB2B0AEABAEB2C3C1BABFBEC6B8B8ACB6AFAEB5AEBAC0AEB8BAB4A8B0B8B3AABCB8AFB7AFB8B5B3C5C1BBB8B7B6B5BCAAA8AEB0B9C8C6BFC2C1C2ABA4A5AFB7A8AFAEB5AEBAC0AEB801FEB6000801D860B0AAB2B7C1BBBFB7BEB0B7C1B2AFB9B9B3BBBDBCBEC2C6C0B0B7BCB7AFB3B2BCAFB2B5B6B4BBB2ADB5BABBADADAFB3B9C2BFB9B3B0B9B2B6C0BCB5B7ADB3C3BBB8BEBFBAB0AEABB8B0A9B4C4B4B8BBB3B6C5B7C3BAB9ACB5B7B4B7B0ACB5B1B6B0B8BBAEB6B6BCB3ABBCBCB5B2BDC0C6BCC5B6B0ABAAB3B6C0BBB3BDAFB1B1B4B0B1B4B9B8BCB4AEC5BCB9ADAFBAACB8B0BCB0B8B6AEBCBAB8BABFC2B3C8BBBCBCC5B6B0ABAAB3B601FEB7000801D870C3AEB9B4B5C4C5C5C7B1B3A9B0B5B6B0B9BEC1B0B3A4ADC0BEB6B2C1ADB9B6C8BEB9B1B9B1ADBFC6BEC6BFB7B4BCB8B6B7BFBABCBBBAC0C1BCBFB6ABB9B3B3B9B4B9B7ACB4B4BAB9B9BCABA8AABBBBBFBBB8B3BAC1C1B3BAA9BDC2A3B5BBB9BFB2BAB9B1B4ACB3B6CCCEC1ACAEB4ADB7BCBFB6B7B8C1C2B9BBB3BAB6A7C1AFB3B4B7B9C4BFC5C2CDB8B1BAB1B9B7B3BDC4BDACA3B1C6BFC6BEC6BDC9B7B8B8A6BCBFB6B7B8C1C2B901FEB8000801D880B2B6B8CEBDC8C7B6C2C7B8BFC0BBB3BAACB7B1B3B4BEBBBBB8BBB4AFBBBFC7BAB0ACB7B7B9C4BEB9B3C2C3C1C0AEAEBCB3AEB0ADB0AFABBACAC7C6C3BDB4B7C0B2B2B4B7B7B9B1B5BEB8BCB1BBB7B2B7BFB8B1C0BBB0B8C2BAAEBDBCB3ADCEC2BFB5BBB6BEC8BBBABAC0BDBEB9B4B5B6B1BEC1ABB5B6AFB8B2ADB9BBB7B4B4C1B8B6B9B4B7BDB9C5B5BDC4C9B6C4BEBEC3BDC3C3BFB3ADC1B9B7C0B4B0C6C3C8B1BEC1ABB5B6AFB801FEB9000801D890C1C0C0BBBDC9B6C0C0C8C1BBB3ACB3BFB0B3B6CDBBB2BFADAEBBBDB1B2BDBCB9C3C0B8C3CEC4BCC1B4B6B1B9B9B8BBB8B5BDB6B5AFC1BDB3B8BDB8BCC5C8C6C9C1BEC0BEB2B2B9BAC0BDB9C7B3C2B4B0B0C5C7C3C7C3BBC0B8B8BAB3B6B0A7ADB7BDB9C3C4B7B2B4B7BAB6BBBCBCB1BCB8C6CCB8B9BDC6BEC0C6C3BEBAB9BABEBBBDB3B3B9C2B3B7C2C6BBC3C4C3BAC2B5BDBEB5B2B8AFAFC3BBC1B9B9C0B6A4B8C6CCB8B9BDC6BE01FEBA000801D8A0B9BCC0BEBBB3C3BDBEB8A5AFB1AFB3B8BECAC1C3B7BBBDB6B8C1BDB5BFC5BFC7C7BFBAC6C4C7BDC2B2C5BABAB6C5BBADB8BEB3B4B8BBC3BBC3C0C8CAC3BCB9C7C6C8AFAAC0BDBCB7BAB2BEC5BAB5AFB7B9AEBCBBC5BEC0C9B4BABABABBBEC2B8B4BABAC7C0C5C5C0BFC4B6C4AFBDB4B6B9B1B7B7BCB5C3C1C1C5B9B9C2C1B5BCBCC1B4CABDBEBCBAB7C6BBC6C3BEAEC2B9B7BDBAC3C5BDBCBDC5C7B8BCC3C0B9B9B1B7B7BCB5C3C101FEBB000801D8B0BFBDBCC1B4B5B8C5C1BBC0BBBCC0B6B6C0C8BEC4BDB9BBC1BCB5B9BDB6BFB5AEB8C2B6BEB3CBB8BABFBFB4C5C1B9C4CACCB5B4CDBCB7BCC3BAC2C1C2BEB7C8CBB7BDBFBFC9C6CBB8B0B2C5C7C3C6C3B4BCBFB7B6B6B9C4CDBFC8CFC0B8B6C0BAA9BBB7B5B8BABFB8C8BEB9C5C3C6B0C0B3BABEC4C1CDC4BFBCB2BDC2C2BBC2C9B5C8CFC9BAC2B3B4B7C3C2B9BBB8BFBCC8BCBFB8ADAFB7C0BEBEB3BBB9B2C4BEB3BABEC4C1CDC4BF01FEBC000801D8C0B6BBBACDC4BFBCB7BFCABAB3BFBEB7C4BCB5B7BEB9BCB5BCCFBCBDC0C8D4BEBEB2C0C3B4BEB4C1BEBACFC5C2BBBDC3BECACAC3BEB4BCC4C6CAC0BEC0CAC8BFB2ADBBB0C2C0C6C1CDC0BFB4B1B8C9C4BBB4C4C7BAC1C7C0BFC7C4B5C4C1C2C1C6BFBCB7C4BFBDBDBDC4B9BFC1B6BDB9CEB7C5C8BEB6BDB7B8BEBDB8CCCFBFB8C6CFC6B2BFBEBEB9ABB4B1B7C3C5C2C3CBC5BBBEB9C7BEC5BBBEB2BFCDC3C0B6B6B7C5C8BEB6BDB7B801FEBD000801D8D0BEC8C0C1C5C4C0BFC1BDC5D1BFC6BAC0C4C2CDC3B9C3C3BABAB0C0D5BEC0C8CFBBBBC9C1B4C4BFBDC2BABFCBC5C3C5C1C0C2CCC4C3B3C5C1C6BEC5C2B2BBBEC0B5B4BFC9C4C9BABCB7CDB9BDB8BDB3C3C0CABCCBBCC9C4C0BABBCBB0B3BFBBC5C8CCC7C5CCCCCCB6BEC5C5CFC5C0C1B6C0C5BBCCBEBCBCC1CEB9C0BDBBB8BDBCB5B6B3BCB9B2B3BAB5B9C8BDB9C4CDD3C6B8B5BFB4C1C2B8B6C5D3BDBAB8C0B5C0C5BBCCBEBCBCC101FEBE000801D8E0C9C5B9BCB8C0C7CDCECCCDC7C4C8C2C4BBBCC8CBD6C9B5B2BECAC6BEC3C2BEB4B6B0BDBCBDCCC5BBBECDC4C4CCC7CDCDCDB8BCC3BFC6C5C0C6B5BDBDCCC8B7C2BCC5B5BBC7C7C1BAC4C6C2C4C2BECBBFC4CACBBDC2BAB9C7C2CABEB5C6BDBFCAC5C8C1B6CBBEC0BFBBC0B8B9B3BDBEC3CECBC5C6C6C8C4B8B8BFC0D0C1BDC5D0CAC1C4BCBFB1B1C4C2C4BDBBC2C3C4C1C5B8C1C3C3CAC0AFC9C3C7CAC1C2B7BACECBC5C6C6C8C4B801FEBF000801D8F0C6BEC4BAC7CDC1CEBDBCC1BBBDBDBDC8BFC3B3BBC2C3BBC8C9C0CBD2D0CCC4C6C8C7C4C3BEB9BBC3BFC2C6BFBDBDC4C3CEC9C5B4C5CAC7C6C0C6C7C7CDCAC6CABEC0C6C5C1C3C2D2CAC3C0C1BECAC0BDC3ADBEB9CCC2C6C3C4C0C6D3BABEC1C8C0D5BEC4C0C1C9CEC3B5C7C6BBC5C4CEC1C6C2CCBCC1B8B7C2BAC5C1CBC0C5BFC0BBBABFC2CBD4CBC6B7B3C1CCC6C5D3C3C9BAC9BEBEBFC4BDC4C1BBC9C2C5C0C1C6C2CCBCC1B8B701FEC0000801D800BCC4D2C2C7C3CBCAC5CED3D4CCC2C8C3C9C7CCBDB7B6BCC6BDBEBCBDD7D0CFCBC0BFC2D3C4BDC0B2C1CBC2C6C8D4C1CCD5C2CBC6C3C1C4C5C1BECEBDCCCCC1C6BFC3BEBEC2CAC1C0C4CECDCFC5C7C7B7B7C4CCBEBFC7BCC6C4B4B1C4BDC2C5D3D0B3C8C7C0C8CCC9CFC8C4B9BDCCD2CEC6BCBDCAC7C7C3C4BFC6C9C6C3C6BCC3C6C1C1C1BBC0C1B8C0BCBFC1D0CDD1CFCBCBC3BDBEC1D5BBC6C1CAC4C4C2CAD1C6BCBDCAC7C7C3C401FEC1000801D810C2B5C2C5CFC3C6C8C6C9C7C0C7DBCFC8BFB7BFC2C8B8BCD5CAC0C5C4BAC5CEB9C2BFCBCECACBCBC7D2D3BDD3C1C1BABAC4CCC6C4C5CDBFC9DAC8C4CBBDB8C8CACFCAC2D0C8C9C7BFC8BED1BFCCC1C9CBC4C6C8CFC4BDCACCD2BCBAC6CBBCB3BFBEC7BEC4C1C4C3BFB3CFC4C6C7D2C0CECBCBCCC0B2C3C7BFCFCDCBCCCAC9CEC5C0B9C7C0BBC2C5C3C3CACCC6D7C8C5C8C8BFB3C2CCC5D0CBCAD0C1B9BDC5BCC7CBCBCCC0B2C3C7BF01FEC2000801D820C1BABBBEC2BDD2CCC8C6CECEBFC1CCD0D3CAD5D1C3B7BABDBEC9CAC4CCCFC2C3BDC6C6C9D4CCCACCBDC4C1C5C8C6C8C6D2BFC9C9CAC7CECAC4C8C4C4C6C3DBD7D7C9C5CAC0BAC8CEC4B3C8C2C0C5C5C5C5CDCDD0D1CBBAC5BECCB9BAC6C2C8D5DBD7CCC3C2B4B4C6CBCFC3C2C4C9C3BDC4C3C4CDC2C1D5C5BCC2C8C8C6CDD3D0CCD2C8BFCAC4C4D0CFC5CDD0BFC1BACBBFC3C8C5BEC1CABCC5CACEB9C5BDBEC3C4C3C4CDC2C1D5C501FEC3000801D830D7D4CEBEBAC3C3C9C8CDCDD9D5C7C0D3C2CBD2B4C4CCCBBFC8B6D3C4C6D5C8D3C5C6C2CBBEC5CFBABED6D7C6C2C9CAD4CDC2C5C8C8C4C3D4C5CBCED0C5CBCCB7C2C3C0C7BBC1CED2CCC8C3D1D5C6D3D4D3BFCECEC1CCD0C8BEC0C7CAC8BDBDBBC3CBB2C2BFBDCEC1C1C7C4D4CDC9D3D1CBD8D1CAC6CEC9C7C0CAC1BDC8CACEBBB8C8D4CCCBC0C4CED2CCC5C4C8BDCFCFC7CDC8CFC2C9C0D1CCC7C3BECBCAC1C4CBD8D1CAC6CEC9C701FEC4000801D840CDC3CAC5D3DEC6C4CDD0C8C8D5C1C8C8C9C9C8C7CFD6C6CCC7CAC3C9CED6CACEC3C9BBC2CBD7D0C4CCD3D0CBBEC2C4C0C2C6D0C4D3D2CDC3B8CFD4CACBBFBAD2D6D0D7BDC0C5C8C9C9DFCCCDBCC9C6C8C7C2C7CECFD7D0CEBEC2CAD6CBC8CBD3C9CBBABBD6D0CACCC5CDC1BCC8BBC6CBCCD1D4C6BDBEC3D1CAD1C5CBD8D8CDCDB9C2C7D2C5BCC9BDB9C2CCC2C7CCCAC9C2CAC7C9C4CACCCED3D1C0D0D9D2C9C6CCD1D4C6BDBEC3D101FEC5000801D850D4C7C3CBD1CFD3CFC7D7D3CAC3C7C3C0BAC6D9C6D4CCCDCECDCDC2C7D4D1D6D3CAC6C8C6CCC3C4CBCDC4C2D4CDCDCFD1BEBDBBC2D1D0CACBBEC8CCCCDACDD2CDD2C4CECBC0D6CEC3C6C3D9D0C9C5D2C3C0C3C6D2BCBAC9D7CEC5D2D3D3C0BECDD2D2CEDAE7D9E0D2C8CAB8C3C5BACCC9CBC5C9CAD3D0D1D7C6D4CBC5C8C9CFC8C6CACFC8CAD3CEC9BEC7D3C5C8D2CEC6BECEC6D5CCBAC6C7CDC2BACCCAC8DACDCBC5C9CAD3D0D1D701FEC6000801D860D7C9C4CAC1BDCED2D5D6CFCDC7D0CDC2CBC3D8D0C6C9C8CFDAD0D7C0D4CDC2CFC4C4CCD0C0CCC6C4C6CBD7D5C6BBD0D6D4C7BEBEC1D1CBD1CFBFD6D4C5CDC9D0D8CCC8C3CBCECDCEC9D1C4D0DCCBCEC9DDD7D6CFCCCCC7D9CBD7CDDDCCCEC8D5BFC2C6D2CED1D9CFC7BFC8D5BEB7C3D4CACFD5D4CCD1D1CCC6D4D6D8D7CED2D3C8C1C9C3C6CCBEC6C2CEC7C9C6D1D2D4D1D4CCD6B9C1BAC2CECCC7D2CDC8DAD3CACFD5D4CCD1D1CC01FEC7000801D870C9CEC8C9CAC6D0CDC8CDD3D3BCC0D2C6D1CDC5CAD2CBD1D5D6CDC6C1C2CDC1C3D6D1CECEC6CECDCAC0CBCAC7D1C6D0D5D7DED1C7C2D4C6C7CEDAD6D1D0C8D1C6BEC7D4D5DAD3CDCBCAC8CAD5D0D0D1CFCDCACCC3D0C7D3DCC9D7C9CFDDD3CDCACBD0C4C9D4D3CECEC4CBCACDCCCDCCCCC6D0D4D7D5CCCECDD3BFC8C9C9CDCDCBCDD2D2D2D7D5CDCBC9C6CFD3CDCECAC3B7C6BDD0D8D8D4CECBC7C2C3CFD4CECFC6D0D4D7D5CCCECD01FEC8000801D880CEC9C3C5C7D4D6CFC7D1C8CFCDCDC2CCD6CFD6D7D1DDDBCCBFC7C8D4D2D4CAD3C7CEC4BCD4D4C5CAC9C2CADBCAC9D2E0D8C8CAD2CCC7CED4CACED1D2C3CBD8D0D5E1DBD0C9C7C2D3CFC2CDCCCBCFC5D4D3D3C5C4BCD5D6D5C7CAD7CAC9CDDEDECFC8CDD7CCC8D4D7D0CFC4CACEC5BDC0D2D2C8CFD1D9DDCAD3C3D4CED2D8CBD7CBCFD2CACFCCD3C8C8D0D0DAD0D0D6D4CFCCCAC1CDC9CAD0CECFD6D6D1CAD4D2D2D2C8CFD1D9DDCA01FEC9000801D890CFD2CED3D3D4CFD4D9E1D9DCD2C8CABFCCC2BCD0DACACACFC6CCD7D5D3D2D1D9CFDCDBCFD6CFC6BFCEC9D2D2D5C1CED8D3DFD3CACECCCBD4DAC8C6D6D4D8D7D0D4DCD5D8D4BDC8C7D4DCD5D6D6D3BEBFC5C1D7D8D4D6CED1CEE0D5CFDADDD2C7CECAD5D6D4CCCEC9C8D4CCCBCCCDCAD6CCD5DACFBBDADAD2D5D6D2D2CDC1C5CBCBD8CFCDD5CECAC7C7DEDDD6D0CFC6D0D7D0DDD5CADBD6CECCCDC2BECFCFD0D3CCD5DACFBBDADAD201FECA000801D8A0DDCED3D8D9CEDACECADADAD0D8C6CAD2D2C7C7C4CED5D1DDE9E2CFCFD2D0D6C6D7CAD2C8D5CCCFDCDAD2D2CFD3C5D6C7D5C9D3CCD0CBD5D1D0CCCDD5DDD7CFD4DBD8CFCBBECAE2D5CDCACBD3D6D3ECD4BFBDC5CAC8C2C7D5D2E2D8CAD4D9CFCBD7DAD1C8D5D3D6D3DBE6D9CFC7DACDBFC7CCD2D6C0D0D7E0DFD4DACAD2DBC7CFC9D2D9DAC2D3CCDEDAE3CCD8DDDDD7CDC3D8D7DED6C6B7C6CED9C5D5C8C9CCC9C7CCD2D6C0D0D7E001FECB000801D8B0DBC9D3D4DAD6CDC8D4E3E6DAD3D8D9BFC1D2D7D4CDCEE0D7CFC1CFD5D2CED0CED3D1DFC9C9D1D9D2CCD1D5CFCDC7D8D1CBC8D5D3D0D1D5D1CAC5D0D4E6DACED2D1D6CED3D7D2E5DAE0DCD9CECBDECEC2D0D4DDDDC9D1CDD6D2C3D2C6C8D9D2D1DADAC2C1CDD1DFD4D2DECED0D4C3D1D2D5DED8E0DFE1DBDAD7D2D2C2D0D5D4D3D8CCD1D7CED1C7D1DEDBD0D8CED4CBD2D2C8D7CDD0CBD6D7CCD3C9CBC8DBDBDAD5DED8E0DFE1DBDA01FECC000801D8C0D4E2D8E3D8D2DFD5DAD2C6CBD8D7D6D3C7C6C4D6DED2D6CAD7CED5DEDAD9CBC4D1DADDDFD5D8D8D2D8D5CFCDCDCAD5D4CDCFD5D1D8D1CBD6DDD8CDC3CECBD1C5CCD3D9DBD5DDE1E6D6D0D0D2D7D4CFCBD6E0DCD8D5CFCACEC8D3CADBD2D5D7CED6D3CFD8D7D7D7E3C8D4C6CED3CFE1DCCED0CBDEDDDBDFDAC7D8D2C9D5D9D2DFD3CAD0D2D5CFC7CCD9CBD9D3CED2DAD1CDD7DAD3CCDFDCD3E2D7CDD8D5D5D8D3CED0CBDEDDDBDFDA01FECD000801D8D0E1C3CFC6C9D5DBD7D7C9CED7E2DBD3D0CAD4D1C6C8DDDFD1D3D1D0C3CED2DFDDD7E7E2D0CBC8CFD3D7D9C7D1D6D2D7C5DACDCED7CBCFD2DED8D5D7E3D8D0E1DFD3CDDBD5CCDDD6D8D1E1DBDFCDD7D7DDCFDADCE7DAD7D4E0D8D2DFDED2D3D8D0D3D9C7D5DBD7DEC9D4D4CED1CED1CBD0D0DCD7DBD2D8D6D1D2CCD1DED7D0C3CFE2DADFD1D3DCD9E8D4CED2CFDDD7D1DAE2D4D5DBD0D3CBC4C9D8D0D0CDD9CFD2D0DCD7DBD2D8D6D101FECE000801D8E0D3CBD3D0CCDADDDFDAC9CFD5D1D0D1D3D6DAE1E0DDCFD5E6DFDFD3CFDEDED6CEE1DDDDC9C7C8D0D8CFD2D1CED7DDDBDED7D8E4E8E1D3CBDADED2D8CCCCD8D7DAD4D6C7DADDDDD3D3D6D1E2DAC9D4DCD4E5D4D0D3CFE0D1CDCEE0DCDAE2D6C9D0D4D0CFD3D3DAE5D3D8D8D7DAE2D7D6D1D4D6D5D5DDCFCCCDD9D9D8DCDED8D7D4E1D8D9D4CED7D1D5C9D8D1E1D9DEDBD1DDCDD7CBCDD4CAD3D8D0D8E3EEE0DEDCD4D6D5D5DDCFCCCD01FECF000801D8F0EAD5D7CAD1D4D4D0D7CECBD9D2D2E3DBDADBDBDDDBD5D9D4D3DBD7D3E4CBE2CDD3E0DDD7DBD7D1E1E0D7D0E4CFCAD6D7D2CECAE3D9D9D6E3D5E1E8E4D8D2D7CFD9DED7D1D0D6D7DCDADEE4DFD7EDE4D8CFC6D1DBDCDBD0E1D7CDD8D9DDE1CFD1DED3CCCCDDD8D5D9D8D0C4D4D3D1CCE3DCE5D8D3D4DFD6D9E0EBD7CDD3E1D8DFE0D9D9DCE0E1DBDAD5DAD6CED2D3DFE1CACED6D1DCD9E3E6DDE0DFD6CBD1D6CFDCE5D8D3D4DFD6D901FED0000801D800E1D6DAC7DBD4DAD2DCD4E2DACED2D2E7E8D4DAE4DDE1DADCD7D2E4D7D3DED3D3DEE1DDDFD7E2E1D7D5D3CFDAE2DBDABCC4D0D4DCD7DED8D6CFD6D4E5E4DDD9E6D1DCDDD9DED0DDDCC9D1D5D7D4E7D8D2E3E2D5D8D6E8DDDCDCE2D5CEDCD5D0D7DEDBDAD5D9DED9DADAE2DADAE2D4CCD4D8CEC5CCE1CBD5D9DDDADAD1CFE1DAECE2DAD4D8DCD8CED5E0EAD1E4E9D8DBD5D1E4E7D8D8D2D9D8DCD5D6DBD6D5D8DFD8CEC5CCE1CBD5D901FED1000801D810D6DFD6DFDBDBDED5CDDBE1DADFD6D5D8E2DCDBD5CCDADFDDD2E1DFECDADBD4D7D8DAD8DFDDDCD5D1D8DCE5DCE2E3DAE4E6DADFE0DEDFD7D2D8D5DBDBE1DDD6DAD4D4D4E6E1D7D3DBD2CEE1D9DBDFDBECD7CEC7D5D6CBD1D0DBE1DCD6D6D5DED9E6D4DBD5D0D4DBD7E8F0F5E2E1E3DCE2E5D4D9CFD2C7E0E2D6DCDBD2DDD3D4DBDBD6D4E4DFE0E1DEDCD9CDD7E2D6DBDAD9D6C7D2D9DAD5DCE5E7D0D7D8DFEBE8E5D4D9CFD2C7E0E201FED2000801D820DEC7D7DCD9D8D7E6E8E6E5D9D3D9D1CBE1E0DDE4DBDBE6DDCFDEDCD3DAE5E5E1D8E0DBDFDFD5D5D6E4D9E4D7D5DED2D0C8D9E9DBE3EDDDDCE7E3D9DAEBCBD3D8DCEDDEE2E8D8DAD4D9E0E6D6D6D3CDD7DBDCE2E5E0E0D5D8DAD7DAD7DCE7E2D1D9D5CED7D5CFE0D7D7E0EAE7D8E2E0E2D4D0DBDDE7D4CADAD6CFD5D7E4E0DFDBD5E2D8DED5D5D9D5DEDED9D9E2E0DFDED5DAE2DBD6D8D7DEE1E2D6DDDDDADEDBD4D0DBDDE7D4CADA01FED3000801D830DAE4DFDBD9E1E5E8DAD6E8E9E5E8D9E0D9DEDCDCD6D6C9D0CECFE8EAE2DCCFDCD6E9DEDEE0E4EDDEE5E2DDDAD8DDC6D7DEDBD5D9D9DBECDDDFE2E3D9DBE2CCE0E1DFDCE4CFD8D6DBDADAD5DCDCD9EAE3E2E8D5DDE0D9E8D6D8EAE2E1DAD6D5E4DFDED2D4D2D6E2E8DCD6D4E3D5E3F3D5DDE3DEDAE5E7DCDBD1DDE4E3D1D4DBE5E6DBD9DCE1DCD7D6E4DBD4D6DEDADEE7E1E0D7D4D7E3E6EDDDCDD4DFE5E2D3D2DDE3DEDAE5E7DCDB01FED4000801D840D6DEDEDBD1D4D9E4E2DCD4DBE4E7DFD0D8D2E2DEDFECDBD8E3DFE1E7E8E0CFDCDBDCE2EBE2DDDDE4E2DFE3E4D9DFDADDE7E7DBE3D6D9E0E5D4E3EBE3EEDDDED4E2E6E1E3D4D4D4D2DDD5E5E4DADDD9D4DCD8DEE5DFDDDDDFDFECDED9CFDBEBDEE0E1DBE8DEE7DCD7E4EBDFDCCAD6E4DEE5E1DDDADEDDE6E2E2F4DCE3D6E3DDE0E0DFCFD8DDD3CAD7D3DCECDEDDDEEAE3E5E0DFDCDDE4DDE1E5EACFDCE0D7DADFE5E1DDDADEDDE6E201FED5000801D850E5E0DDE5E7F3DAE0E2DDE4D7DFE9E4DCE9D2DCE0D5E0E0DFE4EADCD5D4D9E2DEDBD5D7E0D4D0E7E5E2EDF6DFDCDADFD7DFDDD7E5DEE7DDE6DDD2D8E1E5E2DCCFE7D0E0DEDDDCD3E5D7DEDEE6E7EDE3DCDCE3E3D0E4D9D0E7E3E9DED6E0E6E6E6F0DBDFD7DDD5D5DDDCE3E4DEE7E0DFE6D7D9DFD7D9DBE6ECEDDFDCEBE5E6E2E6E6E0E4E1E2E0D7DBD9D7DDE2D5E1E8D7DAEBE7E7DCD7DDE1D6E3E8E4E2DAD9DDD7D9DFD7D9DBE6EC01FED6000801D860EAEAE3E6D9E4E3E4DDE5DFDFE5E2E9DFE3ECE7DFE3E4D3DBDFE0DDD9E1E0D4DEDBE2EAEBDFDFD7E0DBE9E4DADCE0E2E4DDDDE3E1E1E3DBE2E5DBE8E1E6DCE3D9DDE6DDE5ECE8DFE6DFDEE5EBE0E4E3D8D8D4DBDFDBE5DAE2E1E4EFEBE6EEDCDDDCD8DED3E1E3DFDCEAE3D8DFE5E1DEDCE5E8E4ECE2EADFE2E9EED3D4D3D9DCDED3D8D8D6E0E3E0DBE2E5EAD8EFE4ECE5E6EAE4DBDDDCD1D4CED5D8DADAE5EAE5E5E8E4ECE2EADFE201FED7000801D870E3E5E5DCE4ECE6EDDBDADCDBE4DAE3EAE1E1D6E1DFECE9DBDCE3E4F5EFD4CEDBD7D3DDEBDFE6DEE8E8DDDCDEE6E1DCE9E2E0DADFF2ECDBF1DEE3DEE7EFE4E6D7D9DFE5DAE3E1D9E1E5F0E6D8EAE9DDDADFE4DEECD6EBDDDDDFDFE1D2DBDCD2E8EADDD9E1ECECDEDDDCEFEEE0E3E7EDEDE6DDDDECE8DCDDE6DEE9DAD7E8DEE0DBE6E1DADED2D7E0EBE5D9DBE1E4F0F1E9E9E4E1E3DADCE1E1E3E1DDE9ECE6D6DFE6DDDDECE8DCDDE601FED8000801D880E4E6E5F0E0DDECE8E7E0E4ECE4DFDBDEDCE3E6DFE3EAE8F3ECDCD1DDD9D8DFDFE5EFE2DDEBE9E8D9DDECE0DCE5E1E9F2E6E2CDE4DCD1DAE7E3DFE6EBF4E5E5E1EBE5E2E9DAE4EBF5EFDFD2DEDCDAE5E9EAD9D5DAE1E9E0E6E0ECECE2E2E6DED8E4EAE1DCE6D6ECF9F2E6F5F1DEE1E2ECE7DDDBDCE6E1DAE7DEE1DFE6DADFDED9E7E8E6E4E7DFD5E5DFDDE8E6E6E9E4E3D2E0E9E6F1EEE6E3D7D5E0D6DFE8E6E1E7DDDBDCE6E1DAE701FED9000801D890E6EADDD7DAE2F4E9E8E8D5DFE2D9E7E8E3E3E3D9DAE4F3ECE4E7EBE4EAE7D7E2E3E9E5E8E5E9DFDCDAE0E1D8DBE6EADAE2E2E9E3D8DBEBEFE3DDECF8EED5D3D3E6F6EDE6E1EEEEEDE8F4E1E3EBE9DEE4ECE0E2E2E6E0E5DDE9E6DFD0E0DDDED4DBEBECE1E5EAE0EAE0E8EEE6E0E2E4E8E5F1ECE8DAD9E3E3E4E0E2EBE6EAE9E7E2ECE2E9EAD7DBE1E1DDEBE6E6DDE7F1E9E0E4E5EADAE8F1EFEFD7D4E4E3E9E7E5F1ECE8DAD9E3E301FEDA000801D8A0ECEFF4E8E5E8E0E1E3E8EFF0EDE8E4E9E0E4EBEBE9DAEAE1E9E6DBDAD9DADFECD8DFDFE2E1E7E5E3E8E1F4E4E7E6EBE6E1E5E6F0E0EAEFE3DBD8EBF2E0E7EBDFE4EBEDE2D9E0DFE1EBE5EAEFEBE5DEEAEAEBE1DDE9E7DDE5E9E9F4F1F2ECEEE8E7ECF5F0EEEFE8E6E6F2E8F1F1DFDFE6DAE2E3DCE3E9DFEAECE4E2E9E3EDEFE0EAE2EAE4E6F6DDD8DFF0ECECE3E3E3EBD8E6E0D7DAE2E8EEE8DAD7E7F3E9EAEBDAE2E3DCE3E9DFEA01FEDB000801D8B0EFEAE7DED9EADBDFEEEFE9DDD6D5E0DFEBE3E0E9E2EAE1F2EAD7E4E2EDE6F0F2E4E6E3F1F4F4E9DBF0DBEAEBE7E6E5DEDEDCDCDEEBE3E8EBEAECE2ECEEDDEDF2F7E6F2F1E9DCE4F3EAF1E1EEE9DCE8E5D4DFF9FBECE9E8D9EAE7F5EBE6EFEEEFF2D7E1EFDEE2E2E5EFE1EEE6E8E1DBDBDCE2DCEFE2E6E1F0F2EFE5DCE3E2E3F1EBECE1F1E6E1E6E6ECE7E1E3E5F0E8EBF4E0DFE4EBEDF0E8E2E1DFE6DDEBF1EBDCE2DCEFE2E6E1F001FEDC000801D8C0DFDFEEE9EAE6EADFE8E8DFD8E0E3DFE1E9F0E2E7E6E5F2F1EFEEEDEBE0ECEFEFDCEFF0DFE7E4E4DBE9EEDFEEEDEBE6F1EAE5E6E2E8F3EEF3E4E6E8EBE6EEF1EEE5E7F1E7EAE8E2E3E5E0DCEFEDF1E4E8E3E1DEDCDBDAE5EBE3EDF4F4F4F4F0ECE6E0E3DFDAD6D5E8DFE0E5E6DBEAE3E3DFDEE6E3F1EEF2E5F4ECE3E7EAEFECEBE9DCDEE3EEEDE8F4F1F8EEE8F2EFEEE2DCE5F7E9E4DEDFF3EBDEE5E5EBF2E8E8DFDEE6E3F1EEF2E501FEDD000801D8D0F0E7F2E1E9EBF2F4EAF0ECF0EEE8E8E3E0E7E7E7E5E0F0E7DAEDF9F1ECF2DDEFF0E7E1E2E0E9EBF1E0F2F0EBF3EEDCEAE5E8EEE2F5ECEFF8EFECECE7E3E6D5E7EAE4E9EEDDE8EBEDF1EAE1ECEFEEE8E5EEE8E3E0EBE3E8ECECF9E0E1DCE7E6E3E3DFE4E7E6F0E5DFEDEEF5F2EAE3EAF0E1DFF2F3E5E8E7E3F4F4EAECE6E6DCE5EAF7DEE4F0EBE2DDE7EAE8E8EEE7E0F2F8F7F3DFE8DBE6E5E3E4E7EAE3ECE1F4E1DFF2F3E5E8E7E301FEDE000801D8E0ECDDE2F1E6E4DFEBEFEFF2F1F3F7F1F8EEF0ECE7E3ECFBF5F3F8ECF6EBF1E5EEF5E7EBEAE9F3ECE9E6FEE9EADADBE4E7EDE9EDF1E8ECDCDCF0F3ECE8DFECECEEE1E4EFEBE9F1EAE9EFE3E3FDF4F0F1EFE4E9EFE6F0E5F4F1E9E5E6F5F0FDFDEEE8EDF0E8EDF5EEE8F5DFDEE2DFDDE6E7ECF0DDE5E8F1E9E4F3F4F1F9EFE5E0EBE5EBF5F6E6EFE6EEF9F1E9E3EEECEBF4F7E0F3F1ECE9EDE7E7D5F2E8E3EAEBE9ECF0DDE5E8F1E9E401FEDF000801D8F0F5EEE9EEE8EEE3EBF2FCEEE9EBF3F9DBE3EEE3E1E2EEE8F6EFE9FAEFE4DFE2F6EEFBE8E9E4EDF4FFEEECEDF0E5E7F3F0E9EDF2EFECEDF7F9EBE3E4E9E2E8F2E5E7E9F7F6EFE7E3E7E9F8EEDEF4F2F0EBE3EFF4F1F4F5F5EDE6E8E7E8F7EED3E3E2EBEAFBEEE1F1EBEFF1F7F6F6FCF0E0E6EAE1EAECEEE0E8E8E7F8E9E6EAE0DBECEFFCF5F2E9E1EBF0E5DCEFF0EDF8EAEAFEDCEAF7EEECEBECF5E4E3F0F5ECEEE6EAE1EAECEEE0E801FEE0000801D800E9EEECE6E6DDEEEDDEE7E4EDEFE0EDF2F5E8F3F2FBF2F8EFEDF3EFE9F5F3ECE6F3EFE5EEF4E3EDE4F1EFDFE6EBE5E6E3E7EFF3F1EAF0F6F4EBF3F2E6EBF3E6EDF4F5F6FBE8EADFEEE2F7EAFCF4FFF6F5E2EAE1ECD8E1ECF0EDE8EEF1ECEAF0F0E6EFEEF6F0F5DFE6F2F5ECF2E4EFEFEEF4F3EFF4F4F2EFF1F5F3F1DFE8E3E1E6F8FDF2F1DEEAF2EBEDFDE5EFE8EBF4F9F3E1E5E9EFEFECF3E5E8EDF0F2F0E9F1F4F3EFF4F4F2EFF101FEE1000801D810F6E8E9E5E9FFF5EFE8F3F9E8E8E9EEE7F5F3F4F9ECF5E5EBF7EDEFF3F4FAF5FAEFE2D8EFE7FCF2F5F2EFE4E2EDDFE4F9F8F2EDF2F6F4EDF2F8E9EAEEEAF4FDFAF4E9F4F4EFEFF2F6F1FFF1EAE7E9F0E5E5E2F1EDE7ECEBE9E5F0F8F7FAFCF8EDE6EEE6F1D8E2F0ECF9F3F4F0FAE7E9E4EAF7E7EFF0F5F3EBEFF6EBF3FEF3DCF9F2E9EEF7FBFBF8EEF3F2F6EFF4F4F3ECF0E9EBE3E5E4F3EDE6F3F4EDE4F8EAE2EAF7E7EFF0F5F3EB01FEE2000801D820F9EFF4EBF5F0F0EAEFF9F6F0F3F5EBEFE6E6F4F5EFF8FCF6F3F5ECEDE7EBEEEEF2F7E6EDF7FFF1E8F1F2F2E5EAF1F2F1DEFFF1EDECEEE3EBE1E8F4F1FEF0EFFCFDF4ECEDF2F7F2EFE7EBEDF3EFF7F0ECE8EDEBFEFFF7EDEDFFEBE2F1F1ECF4EAE8EEF7FCECFAEBE9F4EFEDE5FFFCFDF5FFF1EFF4F1EFFDE9F0FBF7E9F2F7F1E8F0EAF0F6EDECEEECF3F6EAF4F4F3E2EBFEF1EBEDF0EDF3EFEEE9F0F4F7E8E6ECFFF1EFF4F1EFFDE901FEE3000801D830E2E8EDECF6F5F8ECF2EDEAF0EEFBF8F6F4FAF4FFF6F6F4E2EEEFEDEAECE8E6F5F6F8F4F6EBEBF6F9F2E9F0F1F6F2EFF2E4EAFAEBF9F0F2FCEFF5F0FCF7F0EDEDEBECE2F4EDF3F3EEEDF0F0E6FCFFFFFCFAE2EBE4EFF0F1F2F8E9F7E5E8E6ECF4F3FBF3E9EFFFFFF4F1FBF5F8F7F7F7F8F1E4E5F7EBE9EFE6EAF1F7F2E8EAECE9F6F7F7F0FFF4F8F5EFF2F7EFE5EAFEFFEFF5F5FAF4EFF0F7E2E2E3FAFDF8F7F9F1E4E5F7EBE9EFE601FEE4000801D840F4FCF4EDF1E9E6FFF5F8FDFBE6F3ECE4F1FFF3F4F4EFFEFAF8FAF9E9F9EEF7F0F0F3EBE2F0F0EBE9EAEBFFF1FDF7FFF9EFF2E9FFEFF6ECF6E7EEEDF4FDFEFAECECF8FBFAFFF3E7F7F6EBEEEAF1F2F1F3EBEDF2F0F3F8F4FCE8ECF9EEF7FEEDF0F4EEE8EAF0ECE9F1F4FBF9F2EFF2F5FFF5F7FCFDF1EFE6F8F1F8F6E8F5EDF0F3E7E4F6F4E4EEFEF8F6F1F3EEF3F5EFEFECF0F9FCF5F6F5F2F7F6E8F1FCFBEFE8F5F7FCFDF1EFE6F801FEE5000801D850F0F0EDEFF4F8F4F7EAF6FFF9FFFFFFF8EEEFECEFEFE8FBEDE6E8F8FBFFFFF7F4EBE8EDF0EFF4F6F9ECE8FCEEFFF2F6F2F4F5ECF7E9F2E7F1F0FCFEF1F2F2F3F5FAF6EDF1F7EFEEF1F8FFF0F1F4EEF8EBF8FCEEF5F1F2FFF5EBFCF0F0FAF9FFF9EBF4F6FFFFFBEEF2F3EFFAF5F2F3FFF9F1F4F5FBFDFAE9F4EFF0F7F6E8EEFCF3EEECEFE7F6F7F1ECECF3FFFAF7F5FCFEFFFAF0EFEFFEFEFAECEEECF7EEF7FBF1F1F4F5FBFDFAE9F401FEE6000801D860F7EFF3F4F7FDFFFBF3F3EEFCEBF9F3FFFFF3F6E7EEFCF6F5EBF2F4F6FBF2F5F5FFF3F1EEF2FAFCF7F6E9F1EEFBFFFFFFFFE9F4F4EEF8EEEBECF5F8F1F4F0F1EAEFFBEBE7F9F4F2FCFFFFFDF5F2F4F5FBFEF3F4F9EEF8F2F1EFFEF2F8FCFFF4FEF8F8FFF0FAF9F6FBF3F6EEEAEFF1F3F7E8E7EAE8FBF5F7E9F2F7ECEDE6F5FBF2F5F5FFFDF7F3FFFDFAF4F4FDECFAF2F3F4ECFAFAFEF8F4F4F4F5F3F8FFEEEFEEE8E7EAE8FBF5F7E901FEE7000801D870F0FCFAF4E8FCF8F4EEFCFFF5F6F1F9FFF6F7FFF8F5F0F5EEF3F4F9F7F5F1F7FCF5F8FCF7ECFAF9EEF1F6EFEDFFEFEEF4EFFFF3F5F4F6FEFFFBFFEEF2EDF4F1F3FFFFFDF8F2E5F7F9F4EBF1FAFAF9FFF4F8F1F4FAECFFF6FCF8EFF9FFE5F0F7FEEAFFFBF4FCFBF6FEF5F0F7EEE0EBF1FFF5F1F1FFFFF4FCFFFFFFF6F6FAFEFBFBE9F7F1FFF2F8FEFDFAF8E5F3ECF8F1F7F7E7EFF2F3FAFEF5F9F7F5F7F1F6FCFFF5F1F1FFFFF4FCFF01FEE8000801D880F9F4ECEBF4F9E9E8FDF1F6FFFEEFF5F6F3F7FBFDF6F3FAFEF8F9F4F3F8FEFFFFFAF3F8F7F8EEFDFFFAFEF1FBFBFDEEF5FFFFF2EAF0F6F2FFF6EBEFF4EAFAFCF3FDFFFCF3ECF1FFF3F9F2EEFFFFFBFFFFFBFFF8F6F2FBF6FFFFF6F3EAF6F6F2F7F8F5EEEBF3F4FDFFEFFFFEF9FDFDFDF0F5F8FDF2ECFBF3F3FCF3F9F9EBFAFDF2F7F8F5F7FFF6FBFAF8F7F2EFF0F9ECFDFAF1FDF4FFFCF8FBF2F6F9FEFFFAFCF5F5F8FDF2ECFBF3F301FEE9000801D890EFFDF0F9FCF3FFFFFFEFFAFFF4FEFDFFF0EDF4F4FFFCF1FFFFFEFFF6F5FFF1E9F2F3F4FDFFF9F9FBFFFFF8FAF5F3F6ECF3FDFDFFFEFDF8FFFFFFF3E7FFF6F4F7FDF4FEF3FAFBF5F8FBFFF9ECFFF6FDFBFFFFFAF5FAF9FDF6EBFCEBFDF8E9FAF8F2F2FFF7F4F4F7F2FBFFFCFCF3F3FBFFFFFFFDF8F9F4F8FAF8F3FDF8F7FFFFFFF2FBFFFFFFFBFFEEF9F7EAF2F4EFEEFFF9F7F4FFF5FAFEFFFBF8FBFDF5FFECF5FFFFFDF8F9F4F8FA01FEEA000801D8A0F4F6FEF9F1FCFEFEFFF6F8FFFBF8F6FAF5F2FFF8FFF4FFEFEEFDFAFDFFFCF1F2FBF4FAFFFFFFFCFCF8FDFAFFFAFAF5F5F5FFFFFFFFF3FFF5FFFFF9FFF6FDFFFFF9EDF9FFFEFCF3FBFEFFEDF0ECEDECFCFEFFFEFFF5FFFFFAFFFFF0F6F4FFF7FEF5ECF6FFFFF9FFF8F9F0F5EBF8F7ECE4FDFFFEF2FBFCF6FDF1FDF9FFEFF2FFFCF2FCF6FAF8FFFFF8FBFCFEFFFFFDFEF8F4F0FFF9ECF9F8F8F9FFFCFFF3FBFFFFFDFFFEF2FBFCF6FD01FEEB000801D8B0FFFFFAF4EAECF0FEF4FFFFFFFFFFF7FFFAFDFBFFFFFCFAF3FFFEFFFFFFFFF8FBEDF9EFFEFAFFFFFFFFF7FEEEF7FEFDFDFFF4FFFAF9FFFEFFFEF5EEF7F3EDFBF9F6FBFBFFFFEFFBFCFFFFFFFFFCFFF6F8FEF9FBF6EFFBFFF3FFFFFFFFFFF9FFFFF5ECEFF2FFF6FDF2FAEEF6F9F7F9FEFFFBFBFFFFFFFFF1FFFFFFF6FBF8FFFFFFFAF2FFF6FEFFFFF1EDF8FFFDFFF4FCFFF8FBF7FFFCFAF8EEF5FBFFFFFFFFFDEFFBFBFFFFFFFFF1FF01FEEC000801D8C0FFFFF2FAF8FFFFFFFFFBF5FAF1FAF8F9FFFFFFF9FFFFFFF2FFFFFFFFF2F8FFFFFFFFFCFDFAFDFFFFFFFAF5F4F1FCFCFFFEF6FAFFF8F3F1F8F3FCFFFEFFFFFFFAFFFEFDFBFFFFF3F9FCFAF6FFFFF8F3F8F7F7FFF0FAFFFFFAFDFFFFFFFCFCF5FEF8FFFCFFF7FAFFFFFFFFFFFEFFFFFFFAFAF8FFFFFFFFF3FEF4F7F6EEFAF9FFFFFFEBF6F7E9F9FAEDFAFEFFFCFEFFFFFFFDFFF8F7FEFFF4FFFCF7FFFFFAFFFDFFFAF8FFFFFFFFF3FE01FEED000801D8D0FAF1FCFFFFFDFCF7FFFFFBF4F7FFFFF6FAFEFAFFFDEEF6F2F3FDF9FFFFFFFDFFFFF7F3FBFFFBFDF6F3FFFFFFFCF6F2FFF4FFFFFFF5FFFAF5F8FFFFFFFFFDF8F8F7F8FFFFFCFFFFFFEFFFFFFFFEFEFEFFFFF7FFFFFFFFFDFDFBFBFFFFF9FBF8F7FFFFFFFFF4FFF8EFECF2FFFEFCF8FFF2FFFFFCFFFFFEFEFFFFF5FAFFF3FAFEFFFFFFFFFFFDF4F9FFFCFFFCF4FFFFFEFAFFFFFFFFFFF2FBFFFFFFFFFEFAFEF2FDFFFFFCFFFFFEFEFF01FEEE000801D8E0F5FFFFFDFCFFFFFFFBF3FFFFFFFFFFFFFFFFFFF3F7FFFBF9FBF6FFFFF2FAFFF8FFF6FDFEF5FFF8FFFFFFFBFFFFFFFCFFFCF5FFFFF7FFFFFFFFFFFFFFFFFFFFFFFDFFFDFFFFFFFFF7E7FDFFF7F5EFF9FFFFFFFFFBFFFFFFFAEFFAFFFBF2FFFFFEFFFFFFFFFFFFFFFDFFFFFAFFF9F3FEFFFAFFFFFAF4FFF8FFFFFDEDFDFFFAFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FDF6FFFFFCFFFFFEF3F2FFFFFFFAFFFFFAF4FFF8FF01FEEF000801D8F0FFFDFFFAF2FDFFFBFEFFFFFFFEF7FCFFFFFAFFFFFFFFFFFFFFFFF5FFFFF2F7F5F4FFFFFFFEFDFFFFFFFAFFFFFCFFF6FFFFFFFEFFFFFFFFFFFFFFF8FDFBFFFFFEF5FDFFFFF8FDFFFFF5FAFFFFFBFBFFFFFFFFFBFAF9FFFDFCFEFDFFFFFBFFFEFFFFFFFFFFFCF8FFFAFEF6FEFFFAF2F1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFBFDFDFFFFFFFFFCF8F6FBFFFEFFFFFFFFFEFFFFFFFFFFFFF9FDFFF5FAFFFFFFFFFAFFFFFFFFFFFFFFFF01FEF0000801D800FFFFFFFFFFFFFFF1FAFFFFFEFFF8FFFFFFFCFFFFFFFDFFFFFFFFFFFFFFFCFEFFFBFEFFFFFFF5FBFFFFFFFFF7F7FFFFFFFFFFFFFEFFF8FFFFFAFFFFFFFFECF8FFFFFFFFFBFFF4FBFFFFF9FEF5FFF3FDFFFFFFFDFFFFFFFBFFFFFFF8FCFFFFFFFFFFF9FCFEF6FFFFFCFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFEFFFFFCFFFFFFFFF3FFFFFCFFFFFFFDFFFFFAF6FFF8F9FFFFFFFFFEFFFFFFFCFDFFFFFFF8FFFFFFFFFFFFFFFFFF01FEF1000801D810FFFCF5FAFFFFF6FBFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F7FFFFFFFFFFFCFFFCF8FBFFFFFFFAFFFFFFFCFFFFFFFFFFFFFFFFFFFFFFFFFFF7F4FEFFFFFFFFFFFAFFFFFFFFFFFFFAF8FFFFFFFCFFFFFEFBFFFFF8FFFFFCFCFFF6FFFBFAFAFBF8FFFFFFFFFDFFFFFFFFFFFFFFFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3FFFFFFFFFEFFF9FFFBFFFFFCFEFFFFFFFFFFFFFFFFFFFFFFFFFFFAF6FFFFFEFFFAFFFFFFFFFFFFFF01FEF2000801D820FFFFFFFFFFFDFFFFFFFFFFFFF7FFFEFBFFFCFFFFFFFFFFFFFDFFFCFEFFFFFFFFFFFDFFFFFFFFFFFDFFFFFBFFFFFEFDFFFFFFFFFFF5FFFDFFFFFFFFFFFFFAFFFFFFFFFEFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFEFEFFFFFFFFFFFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8FFFFFEFFFFFFFCFFFFFFFFFFFFFFFFFDFFFDF6FFFFFFFBFFFFFFFFFFFDF7FFFFFFF7FFFFFEFFFFFFFFFFFFFFF7FFFFFFFDFFFBFFFFFFFCFFFFFFFFFFFFFF01FEF3000801D830FFF7FEFFFFFFFEFFFFFFFFFFF8F3FFFFFFFFFFFFFFFFF7FCFEFFFFFFFFFFF3F2F9FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5FFFFFFFFFFFFFFFCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAFFFDFFFFFFFFFAF8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFAFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFFFFFFFFFFFFFEFBFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCFFFFFFFFFFEFFFFFFFFFFCF6FFF6FFFFFFFBFFFFFFFFFF01FEF4000801D840FFFFFFFAFFF8FFFFFFFFFFFDFFFBFFFFFFFFFFFAFFFEFFFFFFFFFFFFFFFFFFFFFFFEFFFFFEFBFBFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6FEFBFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFFFFFFF7FFFFF7FFFCFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFF6FEFBFFFF01FEF5000801D850FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFDFFFFFFFFFFFFFFFDFFFFFFFFFFFFFFFCFFFFFFFCFFFFFBFBFFFFFFFFFFFFFFFAFFF8FFFFFDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFDFCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFDFC01FEF6000801D860FFFFFFFFFFFFFFFFFFFFFFFFF5FFFFFFFFFFFFFFFFFFFFFAFFFFFFFFFFFFFFFFFFF5F7FFFCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAF4FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFEFFFFFFFFFFFFFFFFFFFCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01FEF7000801D870FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFDFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFEFFFFFFFFFFFFFFFFFFFFFFFFFFFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFEFFFF01FEF8000801D880FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAFFFFFFFFFFFFFFFFFFFFFFFFFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFEFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01FEF9000801D890FFFCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01FEFA000801D8A0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFFFFFFFFFF01FEFB000801D8B0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01FEFC000801D8C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01FEFD000801D8D0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01FEFE000801D8E0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01FEFF000801D8F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF010100010801D800FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2516 2516 0 02B000600003000900042004300000000004030009001820043001804F00040300090020200430080080000403000900242004300000FF0104030009002C20043001000000040300090040200430FF030000040300090044200430E6030000040300090048200430E703000004030009004C200430E8030000040300090054200430003E010004030009000021043000000000040300090004210430010000000403000900082104300100000004030009000C2104300100000004030009001021043001000000040300090014210430010000000403000900182104300100000004030009001C2104301F0000000403000900202104300500000004030009004021043000000000040300090044210430010000000403000900482104300100000004030009004C2104300100000004030009005021043001000000040300090054210430010000000403000900582104300100000004030009005C2104301F0000000403000900602104300500000004030009008021043000000000040300090084210430010000000403000900882104300100000004030009008C2104300100000004030009009021043001000000040300090094210430010000000403000900982104300100000004030009009C2104301F0000000403000900A0210430050000000403000900C0210430000000000403000900C4210430010000000403000900C8210430010000000403000900CC210430010000000403000900D0210430010000000403000900D4210430010000000403000900D8210430010000000403000900DC2104301F0000000403000900E0210430050000000403000900A0200430EFE100000403000900A4200430000000000403000900B0200430000000000403000900C4200430140000000403000900C8200430000000000403000900CC200430200000000403000900502004300002A8020403000900A8200430FE210000040300090004000038000700000403000900080000380015000004030009000C00003801030200040300090010000038010702000403000900140000380C0C05000402008005FF8307205F820720FF8307205F820720FF8307205F820720FF8307205F820720FF8307205F820720FF8B0720608A0720FF93072061920720FF9B0720629A0720FFA3072063A20720FFAB072064AA0720FFB3072065B20720FFBB072066BA0720FFC3072067C20720FFCB072068CA0720FFD3072069D20720FFDB07206ADA0720FFE307206BE20720FFEB07206CEA0720FFF307206DF20720FFFB07206EFA0720FF8507206F840720FF8D0720708C0720FF95072071940720FF9D0720729C0720FFA5072073A40720FFAD072074AC0720FFB5072075B40720FFBD072076BC0720FFC5072077C40720FFCD072078CC0720FFD5072079D40720FFDD07207ADC0720FFE507207BE40720FFED07207CEC0720FFF507207DF40720FFFD07207EFC0720FF8707207F860720FF8F0720808E0720FF97072081960720FF9F0720829E0720FFA7072083A60720FFAF072084AE0720FFB7072085B60720FFBF072086BE0720FFC7072087C60720FFCF072088CE0720FFD7072089D60720FFDF07208ADE0720FFE707208BE60720FFEF07208CEE0720FFF707208DF60720FFFF07208EFE0720FFFF07208EFE0720FFF707208DF60720FFEF07208CEE0720FFE707208BE60720FFDF07208ADE0720FFD7072089D60720FFCF072088CE0720FFC7072087C60720FFBF072086BE0720FFB7072085B60720FFAF072084AE0720FFA7072083A60720FF9F0720829E0720FF97072081960720FF8F0720808E0720FF8707207F860720FFFD07207EFC0720FFF507207DF40720FFED07207CEC0720FFE507207BE40720FFDD07207ADC0720FFD5072079D40720FFCD072078CC0720FFC5072077C40720FFBD072076BC0720FFB5072075B40720FFAD072074AC0720FFA5072073A40720FF9D0720729C0720FF95072071940720FF8D0720708C0720FF8507206F840720FFFB07206EFA0720FFF307206DF20720FFEB07206CEA0720FFE307206BE20720FFDB07206ADA0720FFD3072069D20720FFCB072068CA0720FFC3072067C20720FFBB072066BA0720FFB3072065B20720FFAB072064AA0720FFA3072063A20720FF9B0720629A0720FF93072061920720FF8B0720608A0720FF8307205F82072000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A0008001003181C1003181C030009000020043080000000040C000100020D0028001400003800006E000000010000008F00FFFF00FF01000000000002000000010000000F00020000000E001000000000000000000005000000000000010F000100011000010002110002006000120001000105000E000C20FD00FFFF000000000208000005000E001020FD00FFFF00000000000500000300090004210430010000000403000900082104300100000004030009000C21043001000000040300090010210430010000000403000900142104300100000004030009001821043001000000040300090044210430010000000403000900482104300100000004030009004C210430010000000403000900502104300100000004030009005421043001000000040300090058210430010000000403000900C82004300400000004150008000000000020280000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 16896 16896 0 01FE01000505C81094599157955A9457975A975B9D5C9F5D975B9359985C9459955A9459985D9259985A995D965A945C955A955D9C5F985D975D9358915B925A945892589259965890579559945A91588F579558905795579559995B985C945992589A5D9A5C9A5C975B93599258985A935991579159965A995C945A925992599559975894599357945897579457925795579258975B925B945B965B9158955C985D965B995D995D995C945A9259925901FE02000505D820975996599259955991599357955799599A5A965C965A985B9D5D985B975C995C9659985C9459985B965D965C9A609C5F96599459935A9058915790568D569258925892588C58965B965A935894559459985798599558925996589A5C975D965A935B935994579558915A9458965B975B985B965B965992579159965990599559965A9557945896589859925A975B945B9459945790599A5C975B9759935D9C60985B965B9659925701FE03000505D830955B9559935A975999599D5898589A5A9C5A985A9759965A985A985C9D5B97589559955B95589456955D9E609A5C9C5D9A59935991589156945893599058975A965A9559965A95579055955691568F55995A9658945994589159995C9A5B9B5B985A9457925895579258985B94569359945A9559985C93569358985A9457945A945796579759935791589659955A975A965C9B5A9158965A935D985D965C975E945A9559985C935601FE04000505D840935A955A965A95599558965A94599959985B995A91599659995D96599B5F995A9A5A995C975B9358955D955C9A5E9C5E96599156955B94579259955691588F57945995598F59945A91569257955794589459975A965A965B945A9A5C985A9659965A965995569359915994599A5B965A995B945A9559935692569259955994579557945991569458995D9557935A955A965C965995599A5C975A965A93599C5D995B945A9559935601FE05000505D85093589257965A965A9758965998599A59995B9A5A975A975A995B98599A5B995B9C5A975A965A975B975C9C5D9A5D9E5B975A9B5B9557945892589458935891569057955897579457935792569655985697579356985A945995599757985A965992599557915896579558965B955A965C98599458975B955894579559965896599958935491558F579859945A9A5C9858955A97599458965B975A9A5D9A5D975C98599458975B955801FE06000505D86098579558995A9559965895579A5A9C5A9B5B96599656985A9A5B9B5B9559985A9C5D995B9558975A985A995A975B995E995A975996579055945B9357925590549458945894589557915390569759955894579155975C9459945A985D975A9C5A985B985996598F58995A97599358965C9959985B995A9556965A98589659975892569957935692599157985A9959995B9558925991579359985E9E5E975C9A5E9959985B995A955601FE07000505D870975795589557975B975893579C589958985A99599959915A9C5B9B5B9A5C9B599A589C5B945994589A5B9C5B9E5A9A5C995C9659935891559456925595599155915A945994569659975891559455925597579758985B93599856965A965A995B9259945892589859985A985997589458995A9359975994589557975793569959975792559656935997599559995C975A975C975A9959985A9358945A935C9A5C995A93599759945801FE08000505D880975795589A599457965897589957995A96599759985A965A9C5D9A59995A975A965A985B9D5D9759975A995E945C9B5C9859945A955996579359915795578F569457975794599357965495559256955697589457985C93589957995A9C5D9A5993599555905594569157985999589D5C985A92589859965695589757975696569A5697579755945796589858965B9B5C995A975891569459955B995C975C9A5D985A92589859965601FE09000505D890925996579A599458995A9A589B5899579B5A9457985796589D5A9659975A94599A5B985A965A97599B5C985B985C9C5C985C94599357975A9455935599589153905696579357935694559657975595569658985A985993579556965A9358975A985A94579659955996599B599759995A9759995A9D599758965996569356965691569254975794559558995A9659995B9658975A955A9557985C9A5B965B9B5D9759995A9D59975801FE0A000505D8A09857975895589A5B945693559A579C599D5A9457975898599C5B96599C5997599759995A9558975A94599A5C995C995B9C5C9457985994579857915494538D57945793589659935692539056955597589B5A9F5B9757945994579C5C9A5C965A935698589959975796579656975896589759945A995A91569357985A965897569357975797569B59955995599758955992589A599458975A945A9D5E995C9B5D9759945A995A915601FE0B000505D8B09959945596579559985999579A5898589A5A9B58975797589A5A9C599B5897579759995A995A975A995B98599C5E9C5B97589156995A9456965A8E559C5A9154935790569257955997569957985795579A579B579A58955698589A599459985896569257955795579556985997589A5A96579559985A9556915697579658935596569456995896579A5A955A9B5B95599959985A91579259975B9F5B965A9A5C96579559985A955601FE0C000505D8C09858965895569659965697579E5A9B5B9E5A985999589A579A5A99599B5A965A99599A5B9B59965797599A5C995B9B5A995998599555965997579455955691559657945592579555965693559756965799599459955694589257995A965A9B59985A9456935899579758965698589B5A9B5893589A5899559054965894579958975693559557975794569558975C9A5B95589758965995599F5A9A5B975B985B9B5893589A58995501FE0D000505D8D0985696569759955699589455985799599C589A59995993569E5A985A9B5A995A97579B59965995599A5B9A5B9D599D5C995896579658915798589657965793569257965592569756925499579857945595579957975994579A59975997579959995993589758945694569456995A99599E5B935798589757945598579756945593559658925594559459975A965796589659975894579B5B9A5A9A5C975A9B5B9E5B93579858975701FE0E000505D8E09857975895589657995994589B589D589B579C599C5A99579657985895589A599A5B9A5D965A99599659995A995B99599B5B985A965A9657935497579357985694599656945595569556965494559756975A99589956965592559A5A9C599C5B9758985597569756945993559458995A9A589459985795559957985A9B5898579A5692519255945795589457975897599C5A98599557985895599D5C985C9D5F9A5894599857955501FE0F000505D8F09A57985798589356955598579D589C579C5A9856955596579C5A97579B5A9959995A9D5A96569A5A9959985C9B5B9A5B9457955A975A9A5997579455995893569757955597579455935594549754965399549658995999569354985898599A5A965895579858975798589557975497599B599B58985895559454995999569B589355965397589455955895599A5A96599A5A975992539859975B9B5B9C5B9C5A9B599B589858955501FE10000505D80099589456945997579959995897579B569456985898599C589E5A9A58995C9A599C5A985997589D5B9C5B9D599C5B9E5A9B59965798589055985696569253935692569A57985695539454965394539455985695579A5896569754975899599C589B58975696559657975694559B589356995A945697579556945697579856975695559957975797569D58985A995894579959975697579A59965B9A5C985B9A5B995A94569757955601FE11000505D8109A5698599858995694569A569C599C589C58975799569457A15B99579A5899589C5A9A57995B99589D5A985B975697589D5A955697569856955696569453955597559554975598549753925497569856955699589B5696559956975799599D59985798569A589A57935592569C5A9958985694559759985796579A579B5597589955935395559A5795579C5796579A589B57985697569B579655975A98599C5B985694559759985701FE12000505D82097599B5795559B579A599A5797549D589D5899569556985A9A5792579A599A589A589C5B9957955796599C5997599A5A9D5998599F5A98579654955395559657965796569655975696539754955697559A549856945796559A569A5A9A589A58975797549657985899569458965597589B589D5A9A589A559454945798579D56955394549A559755945595589B5E96589A589C5A955695579A599A5A9C5D9F5C9B589D5A9A589A5501FE13000505D83098579A599556985799579A569B5498569D599757975695579D5898579C5C93569A5A9F59995897579B5A9A58995A9D5B9958985A985691559557915593569856985599589556965694559552985694549A5895559B58945796549E5A9B589E599C5896539355955896559556995799599E5A9A599D5899579455935596579656955593549B569854965697569558985998589D5A94579456965A9858975A9A5C9E5A9A599D58995701FE14000505D84095559A579A579C5895579C569D559E5798559354975797579E5999589C5899589D589A5996559657975996569A599E5B9C59985798569456925693549556955498579856965797569555975697539553955693579657995998589B5999579F5B985799579B569856935599589B5898589A5798599E599A5493539754985597559554995597549754985A9656955895589958955996589858985A9A5B9C5A9C5C9A5798599E599A5401FE15000505D85098559A5697579856985397559F589D5798569B579D5799569E599B579B5798589C589F5B985799579E599E5A9B599A599A5794589D579A579953935294539855965594559757965392549A54975595559B589A569856975396549F599856985496589F599A579A569A56975698559B569A5794579959995796559958955596569C59995493519153965697569758995798589A5B985697599859995A9858985A9A5794579959995701FE16000505D86095569756975697579B5797549C569E589C599D579A579A559F5B9C579D5897559A579B579B5894549B599B589C599A5B9E589B5A9D569655945695539552945498569A59935498539955975396549655975696569857935498569F599E599A5598569854935697559B56985699569457995997579C599253955696569A589B579A5593539653925394569156965899599558985797569A5A9B589C599C5AA05E995997579C59925301FE17000505D87097569A569856985798569854A1579A579A579A5799539855A05A99569C589D5897569C5699589C5997589B5A9D599F58945697559A579354945496549C5795559556965693549C559654985399549C569A569955985899569B56985699589D599854985697559C57905392559858A0589C589A56995691549A559C56965398569C5592539A5593539B5996559B599A579856975798599D589B599F59995898579C589A569956915401FE18000505D88099579657965698569A5698539A579C569655955497559D589E5B9C599C599D5B97569E5B9A599C5897579B5A9B599E5A9D579756995695559153955296549655985598549254955598549854945599569A5698559D58955595539A5799589D589857995798549A569C56995798559B55985697589B5998559955975795549A569B54955196559553965797589B589A589A579A57945499569D5A9C5897589C5A985697589B59985501FE19000505D8909B569A5697549957975594549C579F57A05997559A549758A05998579D589D5999549A57965798569A599B5898579B5A9A5897579D59925696569655965595569758955499549653945298559A5597559D5696579755965592539C5699579655975799599B5699569B5597589A579B579B5698559C5896559856985496539C5697549551945498569956985799589C589A569F5A97589F5899579F5A97579D599B5698559C58965501FE1A000505D8A09B5898549A55975495549B559A559A539D5796569B5897559B579A59A25A9D579A559557975699579A5A9A599D5B9C599A579957A05999549653915297559455995599559653965499549652945196549C569855955598549A579D589A589D5A9B569A549A57965594559655975597579E5799579A5696549654A05996559B549B5394559B5695539655975599589D579C579E5695559A5696589C589555995A9E5799579A56965401FE1B000505D8B096559C589C55965498559A569F55A1589F559A57995595549C5898579F5A9B559A5795569B569E599F58985799589B559B5998589B589A55995692539A55935397549754935397529854995396549B5498559B56985596539C569C5797579D589C579A54935599549755965497579B59965695569C589855935598569956A0589B5598549A55965395539B549B589B589A579B569A579A589B579F599A5A9B56965695569C58985501FE1C000505D8C098569D569F56985499569A539E5499549B5398569A559A569F5899549F5A9C579B589D5797599A55985598579B599E5A9D59955799549454995694549C55925498569854945598549453975297529A569C579E579C57985397539B5798569D579B5694559456975698579A559A5698579F579B589D5896549A539953975595549555965499569B5798559B569A599A589A559757955597579A58995A9C5A9C5B9F579B589D58965401FE1D000505D8D09C589A559854965698569E549C559F5799549F579B559B589D5598579A5799559B57A05A9A559C579A579F5B9E589E589B559B5795549553985394529653955597569A55995595539653965497529A53995497549553995598559A579A599B5698559B5899559A5798559955985599579B579C549955965296549B569B549C56965596539A5397559B57995498579A569B579A56975799569C589C589957A15B9B579C549955965201FE1E000505D8E09C579D599B569A579C569B549F579E579D569A559E57A0569E5396539D589C5797559C569C579654995A9F5B9E599E589B579B57995699559855945399569253945397559D559C55955195539550995299549B549855975499549C5698569A589B5698549B579755945498569E5A9A58A05797539756955196549A5799559B5698549752975594549A559A579B55985798559F5A955596569A559C589B59A55EA05797539756955101FE1F000505D8F09E5899559B569C569A569D549C55A056A05598569E5599559F5599549E5798559A56A05899559A5499599E599A58A0599C5597559D5796549A569B5499549755965498539853965399549A52985497529A5498559954975498559D579A569D589D579B54975596549A549C55965497549A5798569757955296559C559B539753965496539A56975397539B57985999579D589C57995798559957A0599A579D599A5798569757955201FE20000505D800985499549E569A559A549955A2559F549C5597539C569D559D579E57995398549854A0589E599854A0599C569B579B579D569754975594539B55965499549953905399559A57985396539652995394529C5698559C5595549957975499579A5699589A55965397549A5595549C569956A0599E589D579D54965499549B539952995499559E54985496539B589D5699579955995699569A56975599589B56A55CA0599E589D579D5401FE21000505D8109A549C569E56985499559B549F569F559A5398539B569754A0579C57A15999559D569A589B54995499569F5A9F599D589A599B559B579A5597529655965298549753995296539552965294529A53945396539C569A5498559A5699569A5699569E569A549A5797559A559B5397549B559E569C579B5698539854965297519B5699539453975299539C5699579B579B579D589A5697549A559957A05A9A579A579E569C579B56985301FE22000505D82097539B559B54A05799559954A356A0569E559853955398549B559B58A1589B539B569B55975699559A569D579A59A157A05899579C559A559A55955297539652955399569753975195549751995299549856985396559A5598529B5599569B59975499549B5698559853985598559E589E589A5798559B5699549A55985296529E55965299559A55955497559A5795549C5898559A559D5997579D589B57A1599E589A5798559B5601FE23000505D8309E5496539B55995497549C559E55A2569E569B55995497559B57A0569F579C559A549E57965399529D589C589E579C569E5A97559D55985499549A54925295519953995497549A5399549451975397529C559E559F579C5593509755995499559C5794549C53985396539C5598569E579F569855985599549552975398539A55A0579B539A53965399569B569A569A56995698549A5798579F589A5B9B589C5A9F5698559855995401FE24000505D840A05798539C559E55995595549D549D569D559A569A569C559C559D569C579A559A559F579A5597549F599B589B579D59A05998559A579A55965499539754985599569C5699539A529751955196529A529E559E559A5396539A55A05599569F559B5494529A54965399549B559D569B569A55975298569551975299569C569A5496539D549A529C539B559A5498569C5696559C5897559A589A569B56995798599A5597529856955101FE25000505D8509A539A5497539A5598539B539F53A257A356A05598539752A2569A559E559955A0579B55995495519A569E58A1599D589C5697539A559755995293519C55975397539B5398549A55975298539B5198519A5399549E569B5595539B549A569B549B569E579C56965399519852955497569C5597569D5699549652975298559B539B529951995493539B569A5599589A579E589D579B569E579C5897559C569B599C5597569D56995401FE26000505D8609A539C55985498549B529E549F549C549E549E559B5499539C569B55A0599A559E579C5798549B559A579A569C559D589C5898559B559B559B55955197539A54975498549A559A5394529650985298549D58955398549A5699539F5598549C5699579A539A5698539D5498569D559B549D5698559B569A539550985498529A54985695529B549B5699549A569C559C599B559A5799559B559B58A25999559D5B9D5698559B569A5301FE27000505D8709B559C559C54995497529B539D53A054A459995599559A569E569D549B549B559C569E579B569A5498569E579F579C58955696569F569953975298549953985195549E579854995399549B5297519A549A5395539E5697549F549C5699579C559952995398549C54965396519A5498569D589D5699569A5298539C539D539C539A51995395539B529B5493549D5795539A549B569A589F579B5999579957A45B9D589D5699569A5201FE28000505D8809B5599539B5497529B549E549E55A1549C549C539B539A57A1579854A0579C569C559F5798539955A0569D569C579F579A549D569A5490519853975399549454965297559453935296539D5395509C539D549B52A057945198529B579D579D5599559C569653985192539C5699559B579D5697559C579A54995299569A549C549C5398529C5399549A559753995898559C579B569B559A579C58A0569A559A569D5697559C579A5401FE29000505D890985299549A539C5296529B52A054A254A0579A5397539A56A0589E56A0579D559E579D56995598549D599F579B569E589C589B569C559851965299529A5494519752995595529550934E99529C5398519B559D55995494539C55A0589B579E579C5498519953985498539A549C559B55A1549B549C56975299549853995298519752985197559D559D5497549B57975396559B5699549D569C589F589B58A058A1549B549C56975201FE2A000505D8A09C549E549B539A549B5399549D54A0569B5199549A539A549C559E569F589C559F549954995599559F59A1589B569F579E55945598569B5598529452995395549B5495529852995199529A5297529C51985298529D579A549B539F579C539B5598559C5395519B55995298529C5498549A559C549D56955199549C549A549F5399529653965297529C5499569E5798569B569D5594539B589C589F589B589D5A9A559C549D56955101FE2B000505D8B099559B5597539A54A0579F539B539E52A0549E549F569D56A5589A54A05597529A5495549A539C569E579C569B56A4599C569C55A05597529A529350985497539653995496539A549B519753955197529D5499549A53955399539D559B57A2569D55A05598549851935197549B559D569D579B549F559B54985198549A519A529C539851954F9B539D569A549D589E569554975197539A559E589F5798539C569D579B549F559B5401FE2C000505D8C09B559D559B5598549A5399539D54A054A0549A549E559B559E589B549C559B579A549E579B55995599599E589D5AA2599E559955995196539A5397529753955299549854985496539751965093509B53A0579A55A3579A5297539D559B56A057A0569753985398529C539A519B53965297539E569954995099549C549A549C549A5398539A539B559854975497569A559A569B53955599569B579C599959A55B97539E569954995001FE2D000505D8D095519C559B5297529C539B529E529E539D559852995297519D589F56A0569B549F57A2589754A0559C559A579C57A1589B569D569A539A54975492519A5196519A559B549C54985297539A5297509A519C569C5397539A5398529E549A549E559B559D529A569A5498539C5498529A549D569A5399559C52955296529953985296529A5399529A5598539D579B579E569A569D569A5799559C579D5697559F579D569A5399559C5201FE2E000505D8E0A0569A5499539B5499549C53A0549F539D569B559E569854A05899549E5497549C559F569D569A539A5696569A599F599B559B559753995499559A539552935298529A53975299529A5498539954985299549953A05695529B53995398559B539E559D549E539B539E539B5498539D579C569A569E579B5498559F559A529C5397529C53954E98519E569A529A53985699549954985298549C57A0599C569B599C569A569E579B5401FE2F000505D8F09D579D55A05599529B539A52A2559D52A0569E5495509A559E589C559F5599539B549B569D559A5598549C569E579E579D55995599529B559A5295519E549552975599539A5396529851994F9D53995399539A539C54985398539B589E579E569C539F549451965299549D55995499559C569C569C549B51975398519852975397519B509A4F94539C569A569B589D569B5698539B569C579E57A4599A589E579C569C569C549B5101FE30000505D800985499559B5398539C549D539E53A354A0559A539A539955A0569D559D589B559B55A056A0569E559C569B57A158A2599B5499559A549452975394529852995499549A54995497539850975294509A559C539B549B53965297539E579B57A0589E549853975299549C539D539B5299559E5596549B559850965398549B549B539A52985299539752985399539A5697559C579B559D559A56965598569A569F599E5596549B55985001FE31000505D81098529A539B569A539D589E529952A255A1569A549A529855A1589F55995499559E57A0579C5799559C55935399569E5A9E5699549A549754975396549953995598559E5597529A5297509B5397519A549B5298549F53985298539E5AA156A15699539B549A54955199529A529C569A559B5498549F5698529550995499539D53974F97529952965399559A559B5798569B5499549F579E569C589D579E579E579B5498549F56985201FE32000505D8209C529C5395549A549A539B55A0539D539D5598539E569C549B53A1599F569A549E56A059995497559B569F58A0599F589C559B559B569753985399539E579A519352945395559A539C559B519A549C53995197539751995499519B56995597569F559E55985595529A5498539A559C56A1569D559E55995094529B5599529B539551985196529C559B5497549E5796579F579D55955397549A549C599C579F5AA1569D559E55995001FE33000505D83095539E549D539D5598509D539C529E559D549C54965499549F559D56A056985398549D569C579C549C579E589B569D57A1579B52995194549B5594529751965299549854985597529650985197539B539C549A539D559A529A529C549C57A3579B569B529752945499529A5499539A54A0579A559D56995397529A529D53A0539B5296519852985294539752995598549E56985795559C5699559C589E58A15AA0579A559D56995301FE34000505D8409952955198529C549D559A529D549E55A1579A539A539B5399539C569E569B569753A2579E549B549E569E5698569D569E579D569E569A559E54955299519652965299549452985195529A51995296519C539A529952985496529A5797579C579B559A5598539A5697519C5798549955A15699539B559C5596519A539D539D5395519E529B549B55A054985398549B559952995695539A569B57A0589D56A058A15699539B559C5501FE35000505D8509955985399549E579B5497529B519C549F569B5597549C559E569A579E579B569A549B559C559C559D559E599F589C579C5498569D579853935097539651965198559D54965396539852975296519C549B549C559A5598519953A05798579A569A569755975497539B5598559E549A579C55945498549C5398539F559C559D559B5397519A5297539B5398539D569B569B579B539553985499579E5899589F579C55945498549C5301FE36000505D8609A5499549B559D5195519952A658A2549E5294529854985596539D579E589C569F589B579C569955A1579D589B569B559C569A559A5596549C54955395529554955298539853965198529751975399539C5698539B559B549E559B569A559C549C569A539B559A539855985297539754A0579E579C56995297529B549B529D539851995197539851975496549C589E569853995598549D559B599D5697569C57A0579E579C56995201FE37000505D870975398539E5898539D5598539E549F559C54995497539E589E57A2589C5499549B549E5797549D559E579C579A569F57985597569D559A559954925196539552995399559955995397519550975099509B549B549E5798529752975499569C569A579A54985498539C56955399539B569B569C579C5498529A549A5397519E55995299549A549A54995499569B5496569B559D56965598569A5697579C589C569B569C579C54985201FE38000505D8809C5497559F549B5497549A539F53A4569E559C539A549A529F579F579D559B559A549D579C549D57A0589F579856A05897559954955396529C5399539A54965496539A55985195519752975297519A5198529B539D54985395539D569E589C559C559753985298529252985499559B56A3599C549D569C559652975399539D5598539B549C52955199539A53995494559A56985499589D5898579C589F5A9B57A3599C549D569C5501FE39000505D8909A53985397539752985299539C53A155A2579B5497549D579E569D569C579C5599539B559C5597549B5697569B56A0579A5699579E569554955394529954965499549554975399549752944F955099539B5598539B559B5598529C5698559D569A569B54995598549753975598559E5699539B559B58974F96529E56975299529B52975397529A539C5798559B599F599954985498559B569B5699569B599C5799539B559B58974F01FE3A000505D8A09C5399529754945198539A539B539A539C549A539B549A569E569A56A0579D589C569C5598549A559C579D579D599F569A579A569C5498569853965198559753985599539552975194539A53935197519C549A539C5698539A559D589D579D559A549A53925198549A54935396549B569C559C569A569A549553965399549F559E5398539752965297549C559A5799569A55995596559A569B569E599A56A15B9C559C569A569A5401FE3B000505D8B0995597559B54995399559F559D56A3569D5496549B559B56A05A9B55975295559E599B569A569B569C579B569A599B579C5898579854975397569752945397559D56995695519A5396529852995399539B539E56995395529952995797579C579B589C53955295539A5496559B559955A35896559B56965199539C559B5798539A5296539652975599569E579856995696569B55965396559B59A15A9D5A9F59A35896559B56965101FE3C000505D8C0985395529B559A5299549D539E569C54985298539954975399559E579E5799569B55A05A9E57995697559F589C579E589E589857985393549A54975396509552975393539554965294519B54995198529A539955995496559A539A589C57A0599D569D55955398559A53995599529A55995598549F56965498519A5495529B539751985498519B549A5599569B559A569A55955394549A569A569D589C599F58995598549F56965401FE3D000505D8D096549A5494559D559C539E55A2549C549B56975699549B56A0589C549A57985497549C57975696549B5897549F599B569C559858985696549754935495539A53965496539554975498549752975398549D5499549B55995497539C599F599F589B579B54945399539453985397559957A056965597569A53965399559953985399539752985199559B5699569A579A559554985698569E5796569B579C59A158A056965597569A5301FE3E000505D8E099549653945398569C549957A156A0559E559A55985399549E589C569A55965597579D5796569B569B59A1599E589D58995696549C5593529653935194529E5594539C579754995294529A51985398529A5298539A559752965299589B5699569B569B5497549853945396559B56995597549B579B55995499569E5695539A529850955399539553995596549857995697559B5697569B5799579E5898589C5997549B579B55995401FE3F000505D8F0965596569A559C55955399529B549C569D559A579B5794559E589B579B5697569D579A5596549A559A5698599A599F5BA057985698579854975390539854965097559B569A54975296529652985295529A569A539953985498539C5698559C5597529A549554995495539754985397559E5697559A589653935296559A529C5499549453995598549753965699589C5794559E5799589D579C599A5595569E579E5697559A58965301FE40000505D8009C539854975499559952935099549A539F5598569F5698559E579B57A05798579D579F589A5599559A5797579A5A9E589F579B56965498539754935295549654945798559A56925196539C549A5295529B549A549755975599559C589B57985399559C5599539B549853955397559A579C5599589C56965391529C549651975298549B52965494539C5795549B589D5797579A5796559B5699579C579A599B599C5599589C56965301FE41000505D8109954975396549B559A559B559854A1579D569753945598559D589B569A5899579D569B5697579B579956985799589D5A985596569B589556955390519955935395559A5595549A5595529652965399549A53965497539B58975399569B579C569A57965599569A53995597569A5696539E5696569F579A5795539A5499549A5397529153955393539A58975696579A589B589856995596549B58A15A99589A589E5696569F579A5701FE42000505D8209A549756935396569A5598549C589E55A65A97569A559B579E589E549A5599549B549B549B55995598569B579C5A995A9A58955399579655975396539855925394559A5598549B5695529450945092539E569A549F5698539C579B5598559D5798579854955396539954975595549A579856975499559953925296549A5697549652985395559954965597579A579C5899579C589854955599599D599B5A9E5C985697549955995301FE43000505D83095549B589B569954965499549A5799569A549C569D5699549D56A15A9B5795569A579C57985697579D5998589C59A1599B56985596539254985598559654955296539453935396539453965291539655985693549A5797559353975595579E59995797589B55955597589C57985496559A5795579755975696569E579854985394539355935292519A59995697589756975797579C5798599B5898589759A05C9A5795579755975601FE44000505D8409A5497579A569A569A5597529A56A0569F559755995694559D579D579955975597569C57965497579A579E5A99599C589F599455955596569C549451995493549656985793559352975594539A569851995696539B5897549A569A5797579B579A579655975495559454985595539B599A579A589C579B569653995496549754995599539652935397549A5998599A5694549855905496589B579C5796579B599A579A589C579B5601FE45000505D85092579A589356975797589A599A579A5A9B58935695599A599B5B995B99589558985D9D5B9656975A9B5A9358975D99599B5A9056905699589154915697589558935695569155915692538E549655935693559056965692599558935B9A5B985A955A985893559558965895569356975B9457965A9959945993589859945895589656945694559657955A96599459925A9659955895599558955A9A5C9659985E9457965A9959945901FE46000505D8609658935694569A57975796579D58985597569155965792569C5D99589A58945A975B9659965997599759975D975A99599459965A975B935893568F54935691599359925893589656905592569656955796589456965797599459995B95599858965992569556955690589457995693589658965A9A5A975894569B5793559A5995559053915593579659965B9659965A9359995A955A985B995C985B9459945B9658965A9A5A975801FE47000505D87091599556995B955998579455985996599A5C9959935894599B5A9459975C945A935A995C92589457985B9C5C965B9C5A975A9357975A90588F5691569056905799599558945692559054935593589156935895589958935A98599859945A955A985A9557935692589056935A955998599A5C9B5D99589458945997589255995A92549154915694559458965B9758915991569157965C985B975C965B965B995A9A5C9B5D9958945801FE48000505D8809359935591579658945897589D599A5999589A5994589459995B9759975A9559955C9A5A95589458995A9659985A975A9B5A935793569059935896589056935893589557935691569454905695579B5899579155975991559158965995589657955995579358945A935993589658935A995B995C96589355905792579959965B965893579457915593579458955A975A9359975A9357955C995B925A985D9B5C995B995C9658935501FE49000505D8909758945894589357925A96599859975B995A94589358945A975A985B945C985B975C9B5A9659975B965A985C965B995D975B925A9358905790588E57945794579158905790569357955791579456955794589756955B945A9357955B9A5B95599458955890589557915893599559945C9C5D955997598D5590599A5A935995579257905692579358935993599159925A985B925B965D97599559935A945A955B9C5D955997598D5501FE4A000505D8A0915894589357905893589559975996589A5B9257955B955B9558975C9B5E995996599A5A91579358985B975E995D955B965B9459975D915792589258905892598F57925A8D5592569157955A9357945893569A5B975A93579057975C9259955A925996589659955A95589559995B965B955A9759975891579557975B9658985992568F569357935691588F57945994579759965C9158965B975D975A9259955D955A97599758915701FE4B000505D8B0955A9659945A965A975994589559985A9A598F588D58975C9A5D985B945B935A93599359945A955A9B5F965C945B9B5E965A945B975C925990588E57905892578D55945891578F578E56925890568F589259955995579359955A945C925A93598F58945C975A925993598F5B965A925A945A965B955A93579258965A935A945993578F5693579559975A9359965C935D955B955A925B9559965B985B925B945B945A965B955A935701FE4C000505D8C090589257975B945A94599659965995589659955A95589557965C965C985C955C915A9A5E975D995A985D945D925E9A5E945A915A965C91578F5690568D58965A8E59915B9258935993559055905697599458955A92598E56925A955B925A9A5D975B935A92589659955A90589259975D975B965A965A90548E55915994579459975991549156915995598D58935C965B985C91599159955D945A955E975D955C975B965A965A905401FE4D000505D8D092599459955A915C955C945A9859975A965A955A9157925A955A985B985C955E955C945C9357965C955D985D975D965E945B905A92598F5A93578F58945A955B93598F588C58935A8B5693578D5592589559965B935991599259965C905B945A8F58905A935893599359915A945A985C965C955C945994579057945992578F579359905892579159935C915A955C915D975C90588E5A955C945F945D935F975E965C955C9459945701FE4E000505D8E09559915891588F5A94598F599B5B985C975B965D945A935A9A5D985B915A945A905C935C905B935B985C945E9660985D975C975E955C8F5991578F578F5792598F5A955C925A90578F568B58905893589355915B915A9159955A945B955C965C935B925B925C985B935A9258925B975C955C965A965A935A9057935B8F579058925991588E5891588F588F59925C955D955C9459925A935C965D945C935D985C955C965A965A935A01FE4F000505D8F0955C965B935C9058935C975B975B9A5E9D5A905A935B955A935C975C955C94588F5B955C8F5B915B915E955F985F945E975E8F5C945C9257925A93588F588E578E5A93598A588F5992598D578D56915C955B915C945C90579159955E945E975B955D8F578F599158925C945C945B945E995D915B925B90599059965B945A95598E5991588F588F5A915B915E955D935B8D59945C945B925C935F915D965F955E995D915B925B905901FE50000505D8009459925C91598F598D5A915A9A5C985C985B955A975B925C945D995D965C915C945C9A5E975D925B955D935C965D975F985E915A90578E588E5A8E5691578C5A90598A5A8F598F598D5990588B56945C975D8F5A975D9559915A925C8F5B975C935C915993588C59955B905A905C945D955B965B8F5A9258905A935B9159955C9258925A8D579059965C8F5B945C905C925C945D8E5A945C935D9B5F955E975F955B965B8F5A925801FE51000505D810955E925A8D598D59905B935C965B985D955D945C925C8F5C965E945D955C905B905A945C8F5D8F5C9C5E96619B5F945D915D8B5A915C8E5C905C8E598D598C578D5E925C8F5C905B93598E579058915B925C915B945A8E5A905A935C965F955F8F5C8F5B8E5A8F588E5B8E578F5A925D925D935E975E925C8D5A905C925A935B92598C5A935B905A935C915C915E935C905C905C8F5C985D945F96608F5E985F925D935E975E925C01FE52000505D820955D945C8F588F5C945C9059995B915B935B925C945C955D975E985F975E925D945F975C945A935C945A955F8E5C935E955C8E5B8E5A905A905B925A935A915A935A905A8F59905A90578B57935B935991599259925C915A8E59915D965E945A915C925B915B8B59905D935A915B9560985C945B965C8D598E5B935A965A955A93598D5490598F58915C915B945C8C5A905B925D925F935E9560985F9360995F985C945B965C8D5901FE53000505D830925C925B915A8E5C935F915C935D975C955D97609559915B945C935B925D925F955D905E9460955D975C925C945E965E915C915E925C8D5A8E5A905B8E5B905A925C905B935C8F598D588C588E5A8D58925B935D935A8D5B8E5B945F905D965F965D945A915B8D5A8F5D915D8D59955C925C905C935D93598A588F5A8C59945C90588D588F59905C945D915E945B8C5B925D945E945F9460905C965E9461925E925C905C935D935901FE54000505D8408F5B8F5B925C925C915F905C995E965C965D905D915B925F915D955F945E935E915B925E925D935E945F9360975E945F975D8E5B925C8D5A905A8D5A8F5A915C905A915D8D5A8D5A8F58905B8E57905A935B935C975C8E5B945C925E975F915B905B925C8C5C92598E58925C8F5C925C925C925B8E5B92598C5A905C915C915C925A8B5A8D588A59935D8C5B8E5F8E5F955E9660925E945E9360956196619461925C925B8E5B925901FE55000505D850925D8C5A905C8F59905C935C975D915D945E915D925B8E5C98619660945E945F8D5D925C915D8D5D8D5E915F95629460945F8D5B8E5C915D8C59905C905C8F5C905B945B8E5C8C588D588F5A905B915B945D905B8F5C8D5A8E5A905E915F955E905D925C8D5B8E5C915C8D5C8F5C925D945E935E925E915D8C5B915D925C8E5C8D5B8F5A8F598F5B8E5C915B915B915F8F5E8F5C945F925F925F945E9460955C945E935E925E915D01FE56000505D860905B915C8E5A905C915C925C985C915D985F905A8F5B915E925B935D955E905F935D935F955F8F5D935F945F9361935E8F5C905E905C905D905A88578B5A8D5C905C925D915C8E598F5B8C598C59915C945D945E965C8F5A8F5D955E9460955F8F5C915C8C5A8E5B8E5A8E5D8F5E925D98618F5B915B8D588B5B975F915B915B93598D598D5D955C90598C5B935E905C8F5D935C895C905E925F905F9561925F98618F5B915B8D5801FE57000505D8708E5E945E945D8E5E8E5D915B8E5B94609560925C935C916197609660955F8C5B8E5D935E8F5C8D5C905F936191619962965E915B8C5D8E5C8D5C895A8E5E8C5A8C5C8B5D905C8A5A8E5A8C5B915D905D925B8F5C8F5D8B5D8B5C915F9460925E8E5C8B5B905D8E5B8F5E9160915F8E5E925E925E8F5D8D5C8F5A8B5C905D915E8F5B905B8D5A8F5F8F5F8F5C8F5F905E905D905F8C5E925F9363936090609561925E925E8F5D8D5C01FE58000505D8808C5B915F945D905E925E915D935F965F955C905D935D8E5E925E9260935D8E5C935F935D945D8C5C906096618F609662925C8E5D8E5D8A5A8A5A8A5B925F8D5B8C5E925C8D5B905B8B598F5D915B945F935B8D5B8F5A8E5C8D5D93608F60945E915F9059895A8B5E915D8F5B915D8E5C94608D5E935F8E5C8E5E905D8F5D8F5A8B598E59905B8D5C8D5E8F5C946091619361925C8F5E925F8E6196608C5E976194608D5E935F8E5C01FE59000505D890905E8E5B8E5C9260915D905D93619260945B915F935F905F905F915F94618F5F8F5F91608E5E8D609462926090619061915F8E5E915E8A5C8C5D8B5D8B5E8A5D905E8F5E8F5D8E5B8B598D5B8D5B8D5B915D8C5D905D8A5D8E5D9162946293609060915C8D5D8F5D8F5D8E5C8B5D935D925D8E6093608F5C915F945C905F925C8C5A8E5B8A5B8E5C8F5D8F5E8E5E8C5C90608E5F8D60915F8E62925C91628F61925D8E6093608F5C01FE5A000505D8A08F5F905D8C5D905F915E925F935E925E95608B5C8E5F93629460915D9160905F9160905E905F8C5D9161905F9164956095618F5D8E5D8C5C8D5C8A5C8C5C8E5A8A5D8C5C905F905E905A8C5A8D5B905D935D8F5C935F8A5A8F5B936090629161915F925C8A5B8E5B8E5D925B8E5C8F5F905D8D5C8F5C8D5E8A5F905C935D8D5E925C905D8D5C8A5B8F618E60905E8E61945F8D5F905D8F619262906093649462905D8D5C8F5C8D5E01FE5B000505D8B08C5D8F5F905E8B5C8F60915F8F60916094628E608D5D8F62966193628B5D88619162965F8D5E8D5F90628E62916393648E5F8D5D8C5C915F8E5D885A8A5E8D5F8F5F8F5F8B5B8B5A8A5D8D5E895C895C905E905C8F60925F8E5F905F8C5F955F8E618C5B8C5D8C5F905E8D5F8C5F906291608C5F935F8E598A5C8E5C8C5E8F5E905D8C5D925E8A5C8C5E8C5E916190618E62926094618E5F906091618F62916091608C5F935F8E5901FE5C000505D8C08E5F8F618F5E8D5D8D5C8E5B8E5F925D90608F609060906192618D6091618C609060916197608B5C8D5E91638E63946192608E608E60925F8C59875D8B5E8B5B8C5B91608B5C895D8D5B8C5985578A5D935F8B5E8F5F8B5F8D5E935F8F6197608D608E5E90608D5D8B5C8F5D905F8C5F94608D609260905E8A5C8E5D8C5F925E8C5D8D5C8C5E8B5D8D5D89618E6190619363915E8C5E8E5F8B61946292648F6294608D609260905E01FE5D000505D8D08C5C8D5E905E8A5D8E608B5E9063936392618D5F90619161946190618D5F8D628D6092608B5E906092619063906592618F608D5F90608D5E8B5E885B8B5D8B5B875D8C608C5C8B5F8C5E8C5E885C8C5B8860936090628F5F8F618D618E6193628A5E8F5F8E5E8B5D9060875F895F8D618F60885C8F618E608A5F93638F6191628C5C885C8C5C8C5D8E618D608A5F8D5F8E5F8D5D8B5F91628F638F61916294618F60885C8F618E6001FE5E000505D8E0905D895E8E5E8F5F8F608E5D925F9362925E8F618E5E8C6093628D608D5F9364956496628D5E906089608E618E63906392608C5F8C5F8A5F90608A5E8A5D8C5E8D608F628F618A5B885B8B5C8B5E8A5D92608D5D8A5E8B5C895D9264906291638D608E608A5E8F608E648D60905F9160925F8A5C90608B5A885E91618F5F9060895B915E8C5C8C5E8D5F8A5D8A5D8B5E8B608E5E8D628E628E6093608C649264925F8A5C90608B5A01FE5F000505D8F08E618C62926090628C618C5E8D5E8E608E5E89608D628F60906391648E648F6192628F618E628C608D6194648D6194638E628A5F8D618C618E5D845B8A608A60895E8A5F885E8C5E885D8A5D92638E5E885E8B60916290618A5E8F6492628C608E608D5F8B608F608B5F8B5F8F628B628B608D6290618E5E8A608B5F8B60925D8C628C608B5E8E5F8A6089608C618B5F8E618D628E638B608D638F5D8C6393648B608D6290618E5E010100000505D80087608C5E8D628E6092618E5E936292618D618F608C608D5E8C608E5F8D6191628E638F618C608D639161926493638F6290628E63895E895F8D5F8B5F8F60895D8A608F61875D8B5C8B5D875B8B5F8B619162905F8D618C5C8A5E8D618B6191618D628D608A5E8E5F8E5F8C5E8D609066905F90638F608B5F8B5E8D608C5D8C5E865E8B608C5D8A5E8A608C5F8B618E638E648E618C5F8B619061916491639063905F90638F608B5F +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2742 2742 0 02B0001C0003000900042004300000000004030009001820043001804F00040300090020200430080080000403000900242004300000FF0104030009002C20043001000000040300090040200430FF030000040300090044200430E7030000040300090048200430FF03000004030009004C200430FF030000040300090054200430003E010004030009000021043030000000040300090004210430010000000403000900082104300100000004030009000C2104300100000004030009001021043001000000040300090014210430010000000403000900182104300100000004030009001C2104301F0000000403000900202104300000000004030009004021043030000000040300090044210430010000000403000900482104300100000004030009004C2104300100000004030009005021043001000000040300090054210430010000000403000900582104300100000004030009005C2104301F0000000403000900602104300000000004030009008021043030000000040300090084210430010000000403000900882104300100000004030009008C2104300100000004030009009021043001000000040300090094210430010000000403000900982104300100000004030009009C2104301F0000000403000900A0210430000000000403000900C0210430300000000403000900C4210430010000000403000900C8210430010000000403000900CC210430010000000403000900D0210430010000000403000900D4210430010000000403000900D8210430010000000403000900DC2104301F0000000403000900E0210430000000000403000900A0200430EFE100000403000900A4200430000000000403000900B0200430000000000403000900C4200430140000000403000900C8200430000000000403000900CC200430200000000403000900502004300002A8020403000900A8200430FE210000040300090004000038000700000403000900080000380015000004030009000C00003801030200040300090010000038010702000403000900140000380C0C05000402008005FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F20720FFF3072080F207200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A0008001003181C1003181C030009000020043080000000040C000100000D002800A02104300100000001000000010000000100000001000000A02104300000000073000010010000000E00E00000010001000100000000000000007E0000010101000100000000000000007E0000010101010100000000000000007E0000010101010101000000000000007E0000010201010101000000000000007E0000010401010101000000000000007E0000010801010101000000000000007E0000011001010101000000000000007E0000011001020101000000000000007E0000011001040101000000000000007E0000011001080101000000000000007E0000011001100102000000000000007E0000011001100104000000000000007E0000011001100108000000000000007E000F000100011000010002110002000200120001000E05000E000C20FD00FFFF000000000208000005000E001020FD00FFFF00000000000500000300090004210430010000000403000900082104300100000004030009000C21043001000000040300090010210430010000000403000900142104300100000004030009001821043001000000040300090044210430010000000403000900482104300100000004030009004C210430010000000403000900502104300100000004030009005421043001000000040300090058210430010000000403000900C8200430040000000405000E001420FFFF00FF0000000000008300150008000000000020280000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 4928 4928 0 01FE01000000C8106E686E686D686D686D686D686E686E686E686D686E686E686E686E686D686E686E686E686E686E686E686E686E686E686E686E686D686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686D686E686E686E686E686E686E686E686E686E686E686E686D686E686E686E686E686E686E686E686E686E686D686D686E686D686E686E686E686E686E6801FE02000000D8206E686E686E686E686E686E686E686E686D686E686E686E686E686E686D686E686E686E686E686E686E686E686D686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686E686D686E686E686E686E686E686E686E686E686D686D686E686E676E686E686E686E686E686E686D686E686E686E686E686D686E686E686E686E686E686D686E686D686E686D686E686E676E6801FE0100000088105A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4E5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D594D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D594D5A4D5A4D5A4D5A4D594D5A4D5A4D5A4D01FE0200000098205A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4C5A4C5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D594D5A4D5A4D5A4D5A4D5A4D5A4E5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4D5A4E01FE01000000C81037213721372137213721372137213621362137223722372237213722372236223722372137223722372237213621372237213621362137223721372137213621362137213621362137223721372136213721372237213621372136213721362136223721362137213721362136213722372137223721372136223721372136223721372137213621362137213721372237213621362136213621372137213722372137223721372101FE02000000D82037213721362237223722362137223621362137213721362137223722372137223722362136213721372237223722372237223722372236213721372136213622372136213621372137223621382237213621372136213621372137213722372237213721372137213621362137223721372236223621362137213721372137223722362237213621362136213722372136213721362137223621372136213621372236223621362101FE0100000088100F030F040F040E030F040F040F040E030E030E030E030F030F040F030F040F030E030F030F040F030E030E030E040E030E030F040E030F040F0410030E030F030F030E0310040F040E030F040E040E030F040F0410040F040F040F040F040F030E040F040E040F030F030E040F040F030F040F040F030F040F030F040F030F040F040F030E040E030F040E040E040E030F030F040F040F040F040E030F030F030F040F040F030F0401FE0200000098200E030F040F040F040F040E030E030F030E030F0410040E030F030E030F030E030D030F040E040F030F040F030E040E030F030F040F040F030F030F030F040F040F0410040F040F040E030E030F030F040F040E040E030F040F030E030E040F040F030E030F030F040F040D030F030F040F030F040E040F040F030E040F030E0310030E030E030E030F040F040F030F040F040F040E0310040F040E030F030F040F030F040E040F0401FE01000000C810080B090C080B080B090C090C090C090C080B090C090C090C080C070C080C080C080C090C080B090C090B080B090C090C090C080C090C090D090C090C080C070B090C090C080B090C080C090C080C080C090C080C080C080C080B080C080C090C090C090C080C090C090C090B080B080C080C080B090C090C080B080B070C090C090C090C090C080C080C090C080B0A0C080C090C080B080B080B090C090C090C080C080B090C090C01FE02000000D820090C090C080B080C090C090D080B090C080C090C090B090C090C090C090C080C080C080C080B080B080C080C090C080C080B080C080B080B080C080B080C080C080C080C080C080C080C080B080B090C090C090C080B080C080C080C080B090B080C0A0C080C090C090C080C080C090B080C080C080C090C080C090C090C090C080C080C090C080C090C090C090B090C080C090C090C090C080C080C080C090C080C080C080C090C01FE0100000088100F190F180F190E180E180F190E180E190F180E180F190F180E180F190F190F180F190E190F190F190F180F190E180F180F190F190E180F190E180E190F190F190F190F1910190F190F190F1A0E190E180F190E180E190F190E180F190E180F180E180F190E180F180F190F190E190F190F190F180F190F190F190F180F1910190F180F180E190F180E190F190F190F190F190F190F190E180F180F180E180E180F190F180F190F1901FE0200000098200E190F190E190E180E180E1810180F190E180E180F190F180F190E180F190F190E190F190E180E180E190E180F190F190E180F190F1910190E180F190F190F190E190E1910190E180F190F190F180F190F180F180E190F1910190F190F1910180F190F180E190F180E190E190F190F190F190F190F190E19101910190E190E180F190F190F190F190E180E190F190F190E190F190F190F190F190F190F190E190F190F190F190E1901FE01000000C8101A251B261A251A251A2619251A261A261A261B261A251A251A261A261B261A251A261B251B261A261B2519251A261A251B261A251B261B261B261B261B251A261A251B251B251C261B271B261B251B261A261B261A241A261B261A251B261A251A251A2619251B261B251A251C261A261B2619251A251B261A251B261A251A251A251A251A251B261A251A251C251B2619251A251A251B251A251A2519251A261B2619251A251B2601FE02000000D8201B251B261B251B251A251B261B251A251B251A251A251B261A261A261B251B261B251B261B261B251A261B261B251A251B261A261A251B2619251B251B251A251A251B261A251B251A251B261B251A251A251B261B261A251B251B251A251A251A251A251B261A251A251A251A251A251A261B251A251B251B261B261B251B2419251A251A251A261B261B261B251A261A251A241B251A251A251B251A251A251A261B251A251B2501FE0100000088102F3B2F3B2E3C303C303C313B303C303B2F3C303B2F3B2F3C2F3B2F3B303B2F3C2F3B2F3B2F3B2F3A2F3B2F3B303B2F3C2F3A2F3B2F3B303B303C313C323C303B2E3A2F3B2F3B303B303C303C2F3B303B303D303C303B2F3B303B2F3A303B2F3C2F3B303C313B303C303B313C2F3B2F3C303C303B303B2F3B2F3C303B2F3B2F3A2F3C2F3B2F3B2F3B2E3B2F3B303B303C303B303B2F3B2F3B2F3C2F3A303B303B303C303B303B2F3B01FE020000009820303B2F3B2F3B303C2F3C303C2F3B2F3B303C313B2F3C2F3B303C303B303B303B2F3C2F3B303C2F3B2F3B313B2E3B313B2E3A2F3B2F3A313B303B303B303B303B2F3B303C303C303C2F3B2F3B303B303C2F3B2F3B2F3B2F3B2F3B313C303C303B303B2F3B2E3C303C303B303C2F3B303B2F3B303C303B2E3B303C2F3C303B2F3B303C303A2E3A2F3C2F3C303B303B313C303B303B313B303B303B2E3A2F3A2F3C2F3B303C303B2E3B01FE01000000C81045544553475547544754485548534754465446534754465347554754475546534754475547554755485447544754475347544755485446544855485547544754465447544754475447544754485546544754475447544754475446534554485447554554465447554754475446544754475446534854485346554853465446534553465347544653485546544754475447544754455446544654465447544753475446534854485301FE02000000D82046524854465347534653465446544754485547544654465447554653465346554753465347544653455347544654465447544754465547544756485447534854475446544654465347554855475446534754475447544754465447534853475446544654475546544754475446534654475446544754475547544754465548554754475448544654485446544754465346544754485447544A55475548544554475446544754475501FE01000000881059655965586658645A665A665B665A655C6659655B665A655A655A6659665B665A655A6659645C665A665B665A6559655A655B6759655B665A665B665A655B665B665C655A665A665B665B665C665B6558655A665B655A665B665A655C665B665B655A665A655A665A665C665B665A665B655A65596559665B665A655B655A655A6557655A65596559655C665B655A665B665A665A655A6659655A645A6459665B655A655965596601FE02000000982059665B655A655B6558655A65586458645B655C6659665A655A6658655B6659665A6558655A665A665B655C665C6659655B6659665A665A665A665A655B655A655A655C665B665B6659655B655A655B6657645B6659665B6659655A6559665B6559665B655B6659655A655A675C675B665B665B6558645B665C665A6559665A665B6559655A6659665A665D675C665C675A655A665B665A645A675A665B655A665B665B6558645B6601FE01000000C810656E686F666E676E666F666E686E676F676E676F686F676F656E666E666F666E666E666E676F666F676E676F676F666F666F666F686F676F676F676F666E666E666F666F676E676F666E656E676F666E646E666E656E656E656E676F676F666E666E666E686F666E666E656F656F676E656E646E656F666E656E666F686E676F666F666F666D676F676F676F666E666E666F676F666E656E676E676E686E686F656E646E656F666E01FE02000000D820676F656E676E666E656E656E656E656F686F6870656D656E676E666F6870676F686F696F686F676F676E666F656E656E666F666E666F666F666F686F696F686F686F686E666F676F676F676F666F6970686F676F686F656F666F6970676F666E686F676F6870676F676F686F676F666E656E666E666E656F666E666E666E666F696F676F636E676F6770676F676F666F676F656E666E666E666E676F676E676E656E666E666E656F01FE010000008810777A7879777A777978797879777A77797779787978797779777977787679777977797779757977797879787A7679777A777A76787879787A78797779767A7879767A787A777976797779787A777A77797679777976797779757977797779787A78797779767976797678767977797679777977797778767975797679787A797A7779797A7679777977797879777977797679787A7779787A7679777975797779777977797778767901FE02000000982078797779777A7679777977797779767976797679787976787679787A787A797A7779777A797A787A77797679777977797779787A7579777A7779787A787976797678777A77797779787A77797879767976797678777976797779787A787A77797879777A7779767876797779787A787A777978797679787A777978797979787A77797879787A78797879787977797679787A77797879767978797879787A7779777978797679787A01FE01000000C810777A787A797A787A787A787977797779787A7779777A797A7779787A7879777A787A787A787A797B797A787A787A7779797A777A787A787A787A7779777A797B797A787A797A7879787A787A7879777A797A787A787A797A777A787A787A7A7B7A7B7A7A787A777A777A787A787A777A787A787A787A787A787A797B787B787A777A787A7A7A797A787A7779797A797B797A797A797A787A797B777A797A787A787A787A787A787A01FE02000000D8207779777A7879787B787B7879787A777A777A787A787B787A797A787A787A777A787B797A7A7B787A777A787A787A797A787A797A777B7979797A787A797B787A777A797B797A797A787A797A797A787A787A787A797A797A787A777A787A787A787A787A787A777A787B787A777A787A7779787A787A787A7779797B787A787A797A7A7A787A787A787A787A797B787A7879787A797A787A787B777A797A787A7779787A787A787A01FE010000008810797B797A797A787A797A797A7A7B797A787A787A787A787A797B797B787A787A787A797A7A7B777B797A797A787A787A797B797A7879787A7879787A7879787A777A787A797B787A787A797A787A777A787A777A787A7879787A787A787A787B787A787A797B787A797A797A787A797A7879787A787A797B787A787B797B777A787B797B787A787A797A797B787A787A787A797A787A797A797B787A7A7A787A7879787A787A797B0101000000009820787A7A7A787A7A7A787A797A777A777A797A787A787A797A787B787A797A787A787A797A787A787A7779787A787B79797A7B797A787A797A797A787A787A797B797B787A787A787A777A787A7779787A787A787A7A7B7A7A787A787A797B787A797A787A7A7A797A797A787A787A767A787A777A787A797A7879797B797A787A787B797A787A797A787A787A7A7B787A797A787A7A7B787A787A777A787A787A787A777A787A797A +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2612 2612 0 02B000200003000900042004300000000004030009001820043001804F00040300090020200430080080000403000900242004300000FF0104030009002C20043001000000040300090040200430FF030000040300090044200430E7030000040300090048200430FF03000004030009004C200430FF030000040300090054200430003E010004030009000021043030000000040300090004210430010000000403000900082104300100000004030009000C2104300100000004030009001021043000000000040300090014210430010000000403000900182104300000000004030009001C2104301F0000000403000900202104300400000004030009004021043030000000040300090044210430010000000403000900482104300100000004030009004C2104300100000004030009005021043000000000040300090054210430010000000403000900582104300000000004030009005C2104301F0000000403000900602104300400000004030009008021043030000000040300090084210430010000000403000900882104300100000004030009008C2104300100000004030009009021043000000000040300090094210430010000000403000900982104300000000004030009009C2104301F0000000403000900A0210430040000000403000900C0210430300000000403000900C4210430010000000403000900C8210430010000000403000900CC210430010000000403000900D0210430000000000403000900D4210430010000000403000900D8210430000000000403000900DC2104301F0000000403000900E0210430040000000403000900A0200430EFE100000403000900A4200430000000000403000900B0200430000000000403000900C4200430140000000403000900C8200430000000000403000900CC200430200000000403000900502004300002A8020403000900A8200430FE210000040300090004000038000700000403000900080000380015000004030009000C00003801030200040300090010000038010702000403000900140000380C0C05000402008005FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F24720FFF3472080F247200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A0008001003181C1003181C030009000020043080000000040C000100010D002800A021043000000000010000000F00000000FFFFFF01000000A021043000000000011C02B0010000000E001000000000000000000000000000000000000F000100011000010002110002002000120001000105000E000C20FD00FFFF000000000208000005000E001020FD00FFFF00000000000500000300090004210430010000000403000900082104300100000004030009000C21043001000000040300090010210430010000000403000900142104300100000004030009001821043001000000040300090044210430010000000403000900482104300100000004030009004C210430010000000403000900502104300100000004030009005421043001000000040300090058210430010000000403000900C8200430040000000405000E001420FFFF00FF00000000000083000300090084210430010000000403000900882104300100000004030009008C2104300100000004030009009021043001000000040300090094210430010000000403000900982104300000000004150008000000000020280000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 5632 5632 0 01FE01000404C81037213722372237213621372237213721362137213721372136213622372237213721372137213721372137213722372137213721372138223721372137223621362137213722372137213622362136213621372137223621362137223722372237223721372136213722372237213721362136213721372237213621372137223722362136213721362237223721372237213721372137213722372236213721362136213721372201FE02000404D82036213722372137213722372136213721372237213722362137223721372237223722372237223721362136213722372137213722372137223722372137213721372137213722372237223721372137223722372137223622362137223721372137223621372236213621372237213721362136213722372136213722372237213721372237223722362137223721372136213721372137213722372136223722362136213722372101FE03000404D83016001600170016001600160016001600160016001600160016001600160016001600170017001500160016001700160017001700160016001700160016001600160017001700170016001700160017001600170016001700170017001700160016001600150016001600170017001700170017001600160015001600180017001700160016001700160017001600170016001700170016001600150017001700170017001600160001FE04000404D84017001700170017001600170018001600170017001700160017001600160017001600180017001500160017001700160017001700160016001600160016001700160017001700160017001700150016001600160017001700160016001600160016001600160017001700160016001800170017001600170016001700160016001600170016001700160017001600170017001700180017001700160016001700170017001600170001FE05000404D85000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE06000404D86000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE07000404D87000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE08000404D88000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE09000404D89000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE0A000404D8A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE0B000404D8B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE0C000404D8C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE0D000404D8D000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE0E000404D8E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE0F000404D8F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE10000404D80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE11000404D81000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE12000404D82000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE13000404D83000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE14000404D84000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE15000404D85000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE16000404D86000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE17000404D87000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE18000404D88000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE19000404D89000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE1A000404D8A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE1B000404D8B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE1C000404D8C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE1D000404D8D000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE1E000404D8E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE1F000404D8F0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010100000404D800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2625 2625 0 02B000200003000900042004300000000004030009001820043001804F00040300090020200430080080000403000900242004300000FF0104030009002C20043001000000040300090040200430FF030000040300090044200430E6030000040300090048200430E703000004030009004C200430E8030000040300090054200430003E010004030009000021043000000000040300090004210430010000000403000900082104300100000004030009000C2104300100000004030009001021043001000000040300090014210430010000000403000900182104300100000004030009001C2104301F0000000403000900202104300800000004030009004021043000000000040300090044210430010000000403000900482104300100000004030009004C2104300100000004030009005021043001000000040300090054210430010000000403000900582104300100000004030009005C2104301F0000000403000900602104300800000004030009008021043000000000040300090084210430010000000403000900882104300100000004030009008C2104300100000004030009009021043001000000040300090094210430010000000403000900982104300100000004030009009C2104301F0000000403000900A0210430080000000403000900C0210430000000000403000900C4210430010000000403000900C8210430010000000403000900CC210430010000000403000900D0210430010000000403000900D4210430010000000403000900D8210430010000000403000900DC2104301F0000000403000900E0210430080000000403000900A0200430EFE100000403000900A4200430000000000403000900B0200430000000000403000900C4200430140000000403000900C8200430000000000403000900CC200430200000000403000900502004300002A8020403000900A8200430FE210000040300090004000038000700000403000900080000380015000004030009000C00003801030200040300090010000038010702000403000900140000380C0C05000402008005FF8307205F820720FF8307205F820720FF8307205F820720FF8307205F820720FF8307205F820720FF8B0720608A0720FF93072061920720FF9B0720629A0720FFA3072063A20720FFAB072064AA0720FFB3072065B20720FFBB072066BA0720FFC3072067C20720FFCB072068CA0720FFD3072069D20720FFDB07206ADA0720FFE307206BE20720FFEB07206CEA0720FFF307206DF20720FFFB07206EFA0720FF8507206F840720FF8D0720708C0720FF95072071940720FF9D0720729C0720FFA5072073A40720FFAD072074AC0720FFB5072075B40720FFBD072076BC0720FFC5072077C40720FFCD072078CC0720FFD5072079D40720FFDD07207ADC0720FFE507207BE40720FFED07207CEC0720FFF507207DF40720FFFD07207EFC0720FF8707207F860720FF8F0720808E0720FF97072081960720FF9F0720829E0720FFA7072083A60720FFAF072084AE0720FFB7072085B60720FFBF072086BE0720FFC7072087C60720FFCF072088CE0720FFD7072089D60720FFDF07208ADE0720FFE707208BE60720FFEF07208CEE0720FFF707208DF60720FFFF07208EFE0720FFFF07208EFE0720FFF707208DF60720FFEF07208CEE0720FFE707208BE60720FFDF07208ADE0720FFD7072089D60720FFCF072088CE0720FFC7072087C60720FFBF072086BE0720FFB7072085B60720FFAF072084AE0720FFA7072083A60720FF9F0720829E0720FF97072081960720FF8F0720808E0720FF8707207F860720FFFD07207EFC0720FFF507207DF40720FFED07207CEC0720FFE507207BE40720FFDD07207ADC0720FFD5072079D40720FFCD072078CC0720FFC5072077C40720FFBD072076BC0720FFB5072075B40720FFAD072074AC0720FFA5072073A40720FF9D0720729C0720FF95072071940720FF8D0720708C0720FF8507206F840720FFFB07206EFA0720FFF307206DF20720FFEB07206CEA0720FFE307206BE20720FFDB07206ADA0720FFD3072069D20720FFCB072068CA0720FFC3072067C20720FFBB072066BA0720FFB3072065B20720FFAB072064AA0720FFA3072063A20720FF9B0720629A0720FF93072061920720FF8B0720608A0720FF8307205F82072000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A0008001003181C1003181C030009000020043080000000040C000100010D0028002021043000000000010000000F00000000FFFFFF010000002021043000000000011C02B0010000000E001000000000000000000000000000000000010F000100011000010002110002002000120001000105000E000C20FD00FFFF000000000208000005000E001020FD00FFFF00000000000500000300090004210430010000000403000900082104300100000004030009000C21043001000000040300090010210430010000000403000900142104300100000004030009001821043001000000040300090044210430010000000403000900482104300100000004030009004C210430010000000403000900502104300100000004030009005421043001000000040300090058210430010000000403000900C8200430040000000405000E001420FFFF00FF00000000000083000300090084210430010000000403000900882104300100000004030009008C210430010000000403000900902104300100000004030009009421043001000000040300090098210430000000000403000900A02104300000000004150008000000000020280000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 5632 5632 0 01FE01000008C81085738673857385738673877387738673877386738673847386748774867485738673867386738573877587748674887486748573857385738573847285738473857385738573857286738573857284738773867385738573857387748774857386748673857384738573857387748673877486738773857383738673857386738672857385738472867486748774877485738674867486748574867486748673877486738773857301FE02000008D82087738473877386738572857387748673877387738473857386748774887486738774877486738674867486748573867487738573867486738572857385738572847384738573857385728573857485738673857387738573857386748673857387748673857384728572867386738473877486738674867384728673867386738572857385738573857385738574867486738774867486738574867486748774877486738674867301FE03000108D830896F896F8A6E896E8A6E896E8B6E8B6F8B6F8A6E896E8B6F896E896E896F896E896F896E896E886E896F8A708B708A6F8B6F886E876D886E876E896E886D876D886E8A6F876E876E886E886D886D876D886E876D896F896F896F8A6F8B6F8A708B70896E876E8A6F896D886E8A6F886E8A6E896E896E886E896D896F896E8A6D896E8A6E866C876D8A6F886E896F8B6F896E886F886E886F8A6E8A6F896F8C708A6E896E896E886E01FE04000108D8408A6E8A6F8A6E896E8B6E876D8A6E8B6E8A6F886E876D896E8B6F8A6F8B6F896E896F8A6F8A6E8B6F896F8B6F8A6F896F896F896E886E8A6F886E876E896D886C886E896F886E886E886D886D876C886D886D876E896F896E886D896F8A6F8B6F8A6F876E896E886D896E8A6F886E8B6F8B6E896F886F896E876D886E896E896E896D886D8A6E8A6D896E886E896F8A6F886E8A6F876F8A708A6F896F8A70896F8B6E896F886F896E01FE05000208D8508F688C678D678D678E6791688F68906990698E678C678C678D688F688E688F698C6790698F6A8E69916A8E698E69906A8E698D698C688B668B678A658A688A678C688C688C698D678A678C678E668A668F678E688D688B678D678D688C67906A90698E698D678D6790688A678B688D678E698C688E688C6688678C678E678E6689668B678D678D698D688D698C688E698C688E6990698D698F6A906A8B688E698E698C688E688C6601FE06000208D8608E678D678C688D678E688D6791688F6891698E688D688D6890698F688E688C688F69906A90698F6A90698F698F6A8E688F6A8E698E698D678A668C678A678B678C678E678D668E688A668E668C678E668F678B668D678B668D688D698C678C688A678E698B688E688F698F678E688E6890688D688D688D668E678D678B678D678E668C688A668C688C678A688D698B688F698C6A8F688E6A8E6990698D698E6990688D688D688D6601FE07000308D8708F648F6591658F638F649164916493659266906591638E6493648F64916691669266916692658F648F659267906792679266916590648F648E638C638F648C638E638E648F648D638C6290638C618E6290648F6491658F648D6491668F65906590648E6490658E638D65906390648F649265926590658F638F648F648F6490648E6491638E638B648E638D6590668F658F658D65906590678F679466936792679265926590658F6301FE08000308D8808F638E6492648D648E6492649365946491658F648D648D649266926694669065926692648D649066936790679166936791668E6490658F658E638D648E648E638F6390658C628E648D638C628F638E659364916590658E638F649165916591668F6591668F6393648E638E648E64906492658F65936490648E6390638D638F638E628E628F628E638F658D658F64926792659166916591658F658F658F66956892658F659364906401FE09000408D890935F945D955E935F955E945D955E965F985F9A5F965F9860955D98609760955F945D985F945D935E945F986096609A62945E935D915C935D915C945C945C8E5C945D8F5C935E955C8F5B935C935C965E935D985F935D915B925B925E97609A60995E955E935D935B915D945D945E915D965E945F965E925E935D945D975E935B935C945B965B8F5A905D955D945E9560955E935F945F96609460946094609A62965E945F965E925E01FE0A000408D8A0945F975E935D925E965F955D995E955B955E915C935D945F9A61985E985F955F93609960925D935E955E956096619A61985F945C945D935E935D8F5B945D905D925D925F8F5C945C945D935B945C905A965D965E965D945F935C9760945E965F945E925C945D955D955F985F945C955E975D955E955E975D915A925B925C945C8E5A935D935D945C965E935F9660955D925D925F915E956098629860975F9662975D955E955E975D01FE0B000508D8B09B549C549B549C55A0559953A053A0569D5599549B539E569E559C55A2579A559E539F579D5696519C589C579E589F579D549A5297559A5395539953995498549754995497529751965194519B539C53995398529D559B539A539F559F559B5499559B539C549A539A539E549A53A0569B539C55985599519A529D5498539E559B5297519B539C559D529C559C559C559952995394559A5497569D56A158A4599B539C559855995101FE0C000508D8C095529B529751965197539552A056A1559F55975298519654A3579955A0599A559F56A2589D57995499569E59A1589D569A5399549853985294509A539C5499519B539D559A549452934F9952985297529E549B549A53995296529C569D569E569E559854985299559A5398529C549B55A3579A549953965196509C53A0549C52965199519751994F99569A539B5698549D579F569A559E5698569E569D57A059A3579A549953965101FE0D000608D8D09E4A9E4B9F4CA44CA14AA74BA44BA249AA4CA04EA74B9E49A14CA44DA94FA64DA14BA24A9B4AA64FAA4F9F4EA54DA44FA14E9E4A9F4A9B4A9E4A95479F489F4BA149A04A9E4A9F479E489A459B45A34BA14BA1469F4C9E4AA24AA148A64C9F4DA04CA04BA34DA24CA24B9A49A04CA44FA14CA24CA249A04A9F4AA34B9948A24B9A47A2499D479D48A34DA34CA24DA04B9E4DA650A34A9C49A750A750A650AA4FA14CA24CA249A04A01FE0E000608D8E09E499E499F499E499F4AA448A54BA44DA74CA14B9F4B9E49A950A24CA64DA14EA34BAB50A64EA24AA64CA54DA14CA74FA34C9E4CA44DA14B9C489A469B489C4A9D499D499D48A24AA249A0489D499F48A44BA1479D49A04AA24AA8509E4AA74D9C4AA2499B4799499D4B9848A24DA451A44EA44DA14AA1499B48A44B9F48A04BA14AA5489F499E48A04A9E4CA14F9C499949A34EA04BA54E9F4DA2509C4DA74FA44EA44DA14AA14901FE0F000708D8F0B536AC32AD32AD35AF36AD34BA39B735B737AE32AA32B039AE38AE35B43BB238B638B43BAC38AE38B53CB23CB73DBD3CB337AA30AE36AD38AC34AB30A831AE34AB33AB38AB33AA31A42EAF33A72FAC2EAC31B637AC34AF32AD35BA3BB438BB3AAD35AE34AF32AD30A732B734AF33AE3AB135AA35B336AD35AC34B636AC31B333AD33A932A32CAC38B438AE37AE36AD39B038B938A931B338B239B038AF3BB638B135AA35B336AD3501FE10000708D800B232A931B335B239B338AD33B835B635BD37B133AF33B135B133B338B83AB73BB437B337B536B238B43ABA36B53ABC3AB03AA631B232A634AB32A331AC32AB34A733AD35A631AC35B233AB2FAB2EB136B134B638B035B235AD2EB83BB638B435B337AB33A92EA531A635AD34A735B237AE34AF35B038AE32A031AD33AD33AE32B032AB30AC30A730AD33A835BA3DB13DB237B338AE38B139B93EB93CAC3BB83CAE34AF35B038AE3201FE11000808D810BA17C01CC218BA1BC41FC117C81ECA1BCF21BE1CC21DB419C623C623D723BA1BBE1CC71FC61EB71AC01FC022D029C622D027B91FC21AB816C019B61BBE19B618C121C41CB215B513B315B917C61CBE17C417AB11BD1BB819C91FC71FBC1ACE22C21CC31CC41CAE18C11BBF19B518BF23C41BBA1FC920BC18BB16BE1CC918C01CC119BB17C319B515B71BC51BC71EBA23C520C220BA21C41FBE1DC82AC01FC525C41BBA1FC920BC1801FE12000808D820BD19C119C71DBE18B715C319CC1AC219CA1CBC1BC219B518D022BF1BCA22C720C223CD21C31EC01BCB26C319C022C91FC421C319B91CC71EBD17B815BD19BD1CAF17C71CB317BE1EB612BE18BC15BB15B217C11CBD19C01CC41BD420B61DBC19C322C61EC21FBC19C61FBC15B617BF1ABA19C320C61DBD17B717BB19C21FC718BB17B612BF19BC17C422C021C322BB1CB420C71EBF1DB717B61CC827CB28CE28BA19C320C61DBD1701FE13000908D830CA08C403C805D60CCC0BC301CD03D307DC15DC0FCC03D00DD812DA15D00AD30CCB07CB0FCD0DC703D20BD617D40FD20BD315C70DCE0BCB08C307C40AC605BF02CB07C106CD08C000BB01C804C207CA05CD0ECE10C606C406C605CE0BD40DC90BCB0ACE08C202C200C70AC20DCD0AD313D10CCC0ACB0AC205C40BD00BCB0BC60BC606C307D90BD40DCF0AD90ECC0DCD0CC305CC0AC30AC508C20BD10FD117E014D10CCC0ACB0AC20501FE14000908D840CC0ACD0BC604C80DC90AC602DD0AD408E20FCF06CE09CA07CE0ED00EDA10C70FD40CD50FCE0ECD08D113CA13DA18DB11D50CC008C604CF09CC05BD01C103C904C804C207CB08C607C100CB01BB00CA06CE05CF0AD40AC703CD09D80CCE06D510D005C405CE06C701C102CC0BCC0CD912D608C207D20FCB04D309CD09D105E00DCC00C500CC02D10CC504C90BC50BD00DBA03BF09C40AC10DD410D814D50FD614D608C207D20FCB0401FE15000A08D850DC00D700D500E600D900DE00DE00F000EB00E000E600DB00EA00E800E700DE00DF00E800E500E400EB00E400E300EE00D300D800EB00D000D300CC00CE00D500D600D900CC00D400D200D300D300DD00E000D200D800D600CD00E300F100E300E400DE00D200CF00D300DE00D500D000E400D800DE00E400DA00E000E300E100D600CB00DA00D400D100CE00EB00E500D900D400D200E500E100EF00DA00EF00E400D800DE00E40001FE16000A08D860D700DB00D300DB00D800E600E100F900EB00DE00DB00E100F100E000E300DD00DF00EB00E800D800E000E701E200E900E600EC00E800DA00D500D000E100D000D300DF00CC00DB00CD00D700CC00E000D500DA00DC00D500E200DC00E600EC00DD00D900CF00D700D700DC00CF00DE00D700E000E900CE00DA00F500E400D800CD00D900DA00D500EA00D600E600D900DC00CA00C900D700D500E000DC00E300D700E000E900CE0001FE17000B08D870F300E300F400F700F700FF00FA00FF00FF00FC00F200F200FF00FF00FB00F500FF00FF00E000FA00DC00FF00FF00FF00FF00E900FF00E300F100EC00E600E700ED00F600E300F900E900F900E300EE00FB00FD00FF00FD00E300F400FA00F900F100FF00E300E600EA00E700F000FF00FF00FF00FE00EA00EF00E600E900F900F600E100F300F400FB00EC00F300F400EB00F800F100EB00F000FF00E800FF00FF00FF00FE00EA0001FE18000B08D880EB00F900DE00ED00F800F800FF00FF00FE00FA00F900FF00FF00FF00FF00EB00FF00FF00F000F100F700F500FF00FF00FF00EE00FF00F200DF00E100E600EA00DC00E600F500E600DE00F400DF00E700FB00FC00F100F400E500FF00FA00F400FF00F600D700D900E600F000EC00FF00FF00FE00F600F100E400FE00FF00FF00FA00EA00FA00EF00E700DC00F800F000F900FA00FA00F900FF00FF00FA00F200FF00FE00F600F10001FE19000C08D890FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FC00FF00F300F300EC00F300FF00EA00FA00FF00E300FF00FF00FC00FB00F200FF00FF00E800F800FF00FF00FF00F900FF00FF00FF00FD00EE00F600FF00FF00FF00FF00FF00F200F900FF00FF00F800FE00FF00FF00FF00F500FF00FF00FF00FE00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF0001FE1A000C08D8A0FF00F400FF00FF00FF00FF00FF00FF00FF00FF00F800FF00FF00FF00FF00FF00FF00FF00FF00FF00F600FF00FF00FF00FF00FF00FA00FF00ED00ED00F900F900D500FF00FA00FB00EA00FF00F000FF00FF00F000FF00F100F500F000FF00FF00FF00FD00FF00FF00F500ED00FC00FF00FF00FF00FF00FF00FF00F000F400FF00FF00FF00FB00FA00ED00FD00FF00FF00FF00FF00E900FF00FF00FF00FF00FF00FF00FF00FF00FF0001FE1B000D08D8B0FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00F800FF00FF00FF00FF00FD00FF00FF00FF00FF00EA00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00F800FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF0001FE1C000D08D8C0FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00F000FF00FF00FF00FF00EB00FB00EE00FF00FF00FC00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00F500FF00FF00FF00FF00FF00FF00FF00FF00FF00FD00FF00FF00FF00FE00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF0001FE1D000E08D8D0FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FD00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FE00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF0001FE1E000E08D8E0FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00E600FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00F800FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF0001FE1F000F08D8F0FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00DE00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FC00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00010100000F08D800FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FC00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2666 2666 0 02F0000E0003000900042004300000000004030009001820043000000000040300090020200430080080000403000900242004300000FF0104030009002C20043001000000040300090040200430FF030000040300090044200430E5030000040300090048200430EA03000004030009004C2004300A00000004030009005420043001DE010004030009000021043000000000040300090004210430010000000403000900082104300200000004030009000C2104300100000004030009001021043001000000040300090014210430010000000403000900182104300100000004030009001C2104301F0000000403000900202104300800000004030009004021043001000000040300090044210430010000000403000900482104300100000004030009004C2104300100000004030009005021043001000000040300090054210430010000000403000900582104300100000004030009005C2104301F0000000403000900602104300800000004030009008021043030000000040300090084210430010000000403000900882104300100000004030009008C2104300100000004030009009021043000000000040300090094210430010000000403000900982104300000000004030009009C2104301F0000000403000900A0210430040000000403000900C0210430300000000403000900C4210430010000000403000900C8210430010000000403000900CC210430010000000403000900D0210430000000000403000900D4210430010000000403000900D8210430000000000403000900DC2104301F0000000403000900E0210430040000000403000900A0200430EFE100000403000900A4200430000000000403000900B0200430000000000403000900C4200430140000000403000900C8200430000000000403000900CC20043020000000040300090050200430000074010403000900A8200430FE217401040300090004000038000700000403000900080000380015000004030009000C00003801030200040300090010000038010702000403000900140000380C0C05000402008005FFF98720BBF88700BBF88700BBF88700BBF88700BBF88700BBF88700BBF80720BAF80720B9F80720B8F80720B7F80720B6F80720B5F80720B4F80720B3F80720B2F80720B1F80722B0F80722AFF80722AEF80722ADF80722ACF80722ABF80722AAF80722A9F80722A8F80722A7F80722A6F80722A5F80722A4F80722A3F80722A2F80722A1F80722A0F807229FF807229EF807229DF807229CF807229BF807229AF8072299F8072298F8072297F8072296F8072295F8072294F8072293F8072292F8072291F8072290F807228FF807228EF807228DF807228CF807228BF807228AF8072289F8072288F8072287F8072286F8072285F8072284F8072283F8072282F8072281F8072280F807227FF807227EF807227DF807227CF807227BF807227AF8072279F8072278F8072277F8072276F8072275F8072274F8072273F8072272F8072271F8072270F807226FF807226EF807226DF807226CF807226BF807226AF8072269F8072268F8072267F8072266F8072265F8072264F8072263F8072262F8072261F8072260F807225FF807225EF807225DF807225CF807225BF807225AF8072259F8072258F8072257F8072256F8072255F8072254F8072253F8072252F8072251F8072250F807224FF807224EF807224DF807224CF807224BF807224AF8072249F8072248F8072247F8072246F8072245F8072244F8072243F8072242F8072241F8072240F807223FF807223EF807223DF807223CF807223BF807223AF8072239F8072238F8072237F8072236F8072235F8072234F8072233F8072232F8072231F8072230F807222FF807222EF807222DF807222CF807222BF807222AF8072229F8072228F8072227F8072226F8072225F8072224F8072223F8072022F8072021F8072020F807201FF807201EF807201DF807201CF807201CF80700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D8F82720D9F82720DAF82720DBF82720DCF82720DDF82720DEF82720DFF82720E0F82720E1F82720E2F82720E3F82720E4F82720E5F82720E6F82720E7F82720E8F82720E9F82720EAF82720EBF82720ECF82720EDF82720EEF82720EFF82720F0F82720F1F82720F2F82720F3F82720F4F82720F5F82720F6F82720F7F82720F8F82720F9F82720FAF82720FBF82720FCF82720FDF82720FEF82720FFF8272000F92720D7F8272000F8272001F8272002F8272003F8272004F8272005F8272006F8272007F8272008F8272009F827200AF827200BF827200CF827200DF827200EF827200FF8272010F8272011F8272012F8272013F8272014F8272015F8272015F8270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A0008001003181C1003181C030009000020043080000000040C00010004110002000E001300040018000000140004001E0000001D000A000800A800E682A00A260607003C000000000018000000FFFFFFFF780002000000000018A25503D3A25D0018A25503D3A25D0018A2550320808000FF100F0100000000000000003803000005000E000C20FD00FFFF000000000208000005000E001020FD00FFFF00000000000500000300090004210430010000000403000900082104300100000004030009000C21043001000000040300090010210430010000000403000900142104300100000004030009001821043001000000040300090044210430010000000403000900482104300100000004030009004C210430010000000403000900502104300100000004030009005421043001000000040300090058210430010000000403000900C8200430040000000405000E001420FFFF00FF00000000000083000300090084210430010000000403000900882104300100000004030009008C210430010000000403000900902104300100000004030009009421043001000000040300090098210430000000000403000900A021043000000000040300090020210430080000000403000900602104300800000004150008000000000020280000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 3328 3328 0 01FE01000000C80002A01602CB01400002A01E02D309400002A01A02D309400002A01802CB01400002A01900CB01400000A01900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE02000000C800BA070000AE070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE03000000C8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE04000000C8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE05000000C8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE06000000C8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE07000000C8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE08000000C8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE09000000C8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE0A000000C8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE0B000000C8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE0C000000C8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001FE0D000000C80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010100000000C8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 64 32 0 0000000000000000000000000000000000000000000000000000000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 57 57 0 1290020000FE030000FF1FFF1F0000000018A25503D3A25D0018A25503D3A25D0018A2550320FF8000FF040F01000000000000000038030000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2561 2561 0 02F000140003000900042004300000000004030009001820043000000000040300090020200430080080000403000900242004300000FF0104030009002C20043001000000040300090040200430FF030000040300090044200430E5030000040300090048200430EA03000004030009004C2004300A00000004030009005420043001DE010004030009000021043000000000040300090004210430010000000403000900082104300200000004030009000C2104300100000004030009001021043001000000040300090014210430010000000403000900182104300100000004030009001C2104301F0000000403000900202104300800000004030009004021043001000000040300090044210430010000000403000900482104300100000004030009004C2104300100000004030009005021043001000000040300090054210430010000000403000900582104300100000004030009005C2104301F0000000403000900602104300800000004030009008021043030000000040300090084210430010000000403000900882104300100000004030009008C2104300100000004030009009021043000000000040300090094210430010000000403000900982104300000000004030009009C2104301F0000000403000900A0210430040000000403000900C0210430300000000403000900C4210430010000000403000900C8210430010000000403000900CC210430010000000403000900D0210430000000000403000900D4210430010000000403000900D8210430000000000403000900DC2104301F0000000403000900E0210430040000000403000900A0200430EFE100000403000900A4200430000000000403000900B0200430000000000403000900C4200430140000000403000900C8200430000000000403000900CC20043020000000040300090050200430000074010403000900A8200430FE217401040300090004000038000700000403000900080000380015000004030009000C00003801030200040300090010000038010702000403000900140000380C0C05000402008005FFF98720BBF88700BBF88700BBF88700BBF88700BBF88700BBF88700BBF80720BAF80720B9F80720B8F80720B7F80720B6F80720B5F80720B4F80720B3F80720B2F80720B1F80722B0F80722AFF80722AEF80722ADF80722ACF80722ABF80722AAF80722A9F80722A8F80722A7F80722A6F80722A5F80722A4F80722A3F80722A2F80722A1F80722A0F807229FF807229EF807229DF807229CF807229BF807229AF8072299F8072298F8072297F8072296F8072295F8072294F8072293F8072292F8072291F8072290F807228FF807228EF807228DF807228CF807228BF807228AF8072289F8072288F8072287F8072286F8072285F8072284F8072283F8072282F8072281F8072280F807227FF807227EF807227DF807227CF807227BF807227AF8072279F8072278F8072277F8072276F8072275F8072274F8072273F8072272F8072271F8072270F807226FF807226EF807226DF807226CF807226BF807226AF8072269F8072268F8072267F8072266F8072265F8072264F8072263F8072262F8072261F8072260F807225FF807225EF807225DF807225CF807225BF807225AF8072259F8072258F8072257F8072256F8072255F8072254F8072253F8072252F8072251F8072250F807224FF807224EF807224DF807224CF807224BF807224AF8072249F8072248F8072247F8072246F8072245F8072244F8072243F8072242F8072241F8072240F807223FF807223EF807223DF807223CF807223BF807223AF8072239F8072238F8072237F8072236F8072235F8072234F8072233F8072232F8072231F8072230F807222FF807222EF807222DF807222CF807222BF807222AF8072229F8072228F8072227F8072226F8072225F8072224F8072223F8072022F8072021F8072020F807201FF807201EF807201DF807201CF807201CF80700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D8F82720D9F82720DAF82720DBF82720DCF82720DDF82720DEF82720DFF82720E0F82720E1F82720E2F82720E3F82720E4F82720E5F82720E6F82720E7F82720E8F82720E9F82720EAF82720EBF82720ECF82720EDF82720EEF82720EFF82720F0F82720F1F82720F2F82720F3F82720F4F82720F5F82720F6F82720F7F82720F8F82720F9F82720FAF82720FBF82720FCF82720FDF82720FEF82720FFF8272000F92720D7F8272000F8272001F8272002F8272003F8272004F8272005F8272006F8272007F8272008F8272009F827200AF827200BF827200CF827200DF827200EF827200FF8272010F8272011F8272012F8272013F8272014F8272015F8272015F8270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A0008001003181C1003181C0300090000200430800000000405000E000C20FD00FFFF000000000208000005000E001020FD00FFFF00000000000500000300090004210430010000000403000900082104300100000004030009000C21043001000000040300090010210430010000000403000900142104300100000004030009001821043001000000040300090044210430010000000403000900482104300100000004030009004C210430010000000403000900502104300100000004030009005421043001000000040300090058210430010000000403000900C8200430040000000405000E001420FFFF00FF00000000000083000300090084210430010000000403000900882104300100000004030009008C210430010000000403000900902104300100000004030009009421043001000000040300090098210430000000000403000900A021043000000000040300090020210430080000000403000900602104300800000004150008000000000020280000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 4800 4800 0 01FE0100080808106C756B686E646A6A646E6A6C6466636C756C6D80756E6A6F696767706B645F6D74706C6360616C717A717A7178707577747572757373777373636A70686E75656D746C75766E72747B7B7F7A7A746B776B7466726A5A63747672696A656258666269646D6767636367687379686B656B646968646E6866646E6761796E7373707A786B6B747367787F80736F6A696B69706A677368686B695E5F5F645A53463C666C73676766716F736D6C6B5A54565A5F586456666D6B646262656268585463676F6F715E606163707988827B777D796C797675778A757A7E80828685827A805F586456666D6B6401FE020008081820736862635C646A69656466696273696F6D667160686D675F6D73737676786B6E656270636764626A716E6D666A737578806F776B71797C7D746C716F73697579716B6E6E6A706B746B747878716F6F7277737373646D606B7573645A686C595A576C676A696C756A726F6F74606D7373675B62636B736D676F7063686167737B6E73777C726B64787A777875616A6A686761696870726F6B656464655F554B33696C6F6F7171696A75716269646257575559646763726C5C6567625E5A5D5D5F5E5D6261646B686B6F7C8C86847B77767478777F7177768389817B858488918F5559646763726C5C01FE0300080818307569666865646C69746D656A66635D6B7B7164777171635F6E716C78726E6E776A6A646C696B68656A737C7479676D6C7773726F68726D717A7B74716C6A6D706D6B626974797982898B787A706C6B6E72706D796C6A657872806052625F5F5F5B6660716E6169686170706761687B735E5C66786C7571696A5F6C6C68727667696E6C7065708072677C735C57627F6B6C6F6E6A726E7264595A5F6364585F3F5F767E807E6F7872756664695C5F605A5B5D615F57666568645C6C6F686666545A5A646E656B67687583948A8887827C807E798184867F7B797A737F77837F825B5D615F5766656801FE04000808184070706B6F6D6F716F736C6C626B6F707574676866726E766A5D6469737A697169646D636269696B666D70756F6E7A72758B7F826F6E7576736D6E78717469736C715D6074747B6D677B778076696E6F776B74686F69666E6C6F6B66676F6863615C656A6452626968606E6E7C85716F6B63656E6A6D69605F5F75706B6A6C84766B6E737A746D797A757C6C665961667262696966646074706964615E655F5442767D7486746C84767D70696B65665C5A6056556262586C6C6C69716F6A6E6755576257695C516064677987777381716A6F8679728489857E8A7A737D7D7E829C6056556262586C6C01FE050008081850716D62665B63596D7E686365676470637168636069686C6A5A65686F7C7C6679646466656264657D7962676E6D6A6B767C7876766C7E76766E666F696F6D7A707478696864757077726C7B6E736F746D6A846F796C646973736C6052606264706B6D5B766A676966716E6C7472737879715C636D6265595D6D6A6158696D73767D6C79767E7677777B816D6268706B6E61697465696C726E69576468605C54406A665D657468736D796B74706259625463686B6A5E6E61615B6D62626D645A5C665F5B6864646D6A687E8B8088857D7B7F76716B707D837C877E7E7E827D7D8263686B6A5E6E616101FE060008081860786A6A6F746D6C6D7A6D636C5A6665677C6F67626D656A656270747D6A63636D646A6C6D756F6E7680736D747274727381827C716562736E6E6D6D636C68656C6074726F7D77756D78717472786B786F72777172686B737A8071686E6E725D5F576E676764646F6D7E6F6474645D717B6C625F5F6A6C69615C61616B5E6674666F7469655E6A787F847970626C667274786A665C695E646B62574E565756544573757479727280718176676066646D6264655C5C6A6A6C6B646658615D6A646F6B6566726870655C728188898D877C816E73827B727B767A7E77787B8583839064655C5C6A6A6C6B01FE0700080818707B705966636868736E63656A7261636C6B6C6871695D5F63716775797675787B7B7861636E6A6F6B7263655F7075706A81788186736E7B746B75706F6E6A6E6C716F68667274737B7C706F7562647166606E6D6F6A5F6B6D76746C6B706E647561636167676462676E767774616A75787A716A65736658596D686A68696D75786C74787277756E767E7E6F66685E6B716767746C726D5E6670635A5B675A55406D6F697A7576736B6B6E6F716A605B6566606058686D606668636C6D6C66636869636B6D5F6560616D86868D8B7C78786C7D7470707D747F7E817F817E6F798066606058686D606601FE080008081880706F64605E7C72706F6A69755D6F606576767973736469655E6B717D7B706468695C65676F6C7472646E7B7165777B7D7771786F676A68727A7871797473787674687075726D68757D707363656C7A6C7971686B757274776474646A666A5D5F58665C666B5F6E68696E7179747464746A505A6766616B62707265757A6F7379667B716F77807462717B756760636D6B666B686F716E796C5B57606A6864593C6B6970777367797672656972616269635E61646A65636063615C6369696A69636B6A6F6B616A63656D7D8E7F83827E777C757A817A8980788080767B7D8187855E61646A6563606301FE090008081890716C52566461686F6F606B67706D676B6B7169666864606D676971778077696871646C666C64767671646568776C716475777B70667B73766F67736E6660746F736D6266677271718079737370626E6F68727B6868697480776F71666A6D6863606D6E6A65696D7273766A776C6E6F6B6E686564696A6368696C6A6B63676477736D696F797C7571807E70666A6779706D706B656E647F6A645E596165625751716B787B816C747370706D6F6B6D68636C5F6865656B6C656B6162655D6160616C655A66686756636E859283827B7E7D6D6E767676897F88867A7984818882836C5F6865656B6C6501FE0A00080818A083766A6B6A676B6A6F6C726A676A7176716A6C65746F6A5C6B69707469656B736C65686E6C6A6B71726A6D626E7278807E7D7B765D6A72746F656E706D6E6D676A72677077797B7F847E7B6E70656E626975676D70676F6A7B71705970666364616662755D6761696B63716E6E7774736B6067657970736A6B6A7474696A757575746572696F6B78787F695E5F61676A6C6F706F667368746959626360584E33606B7B7B7E707C6D757C756763696467635A5D4D5A6158666563706A6260676C6E7268665D6967676A77847C827A7372756968787A827E7A8B7E86897B838883635A5D4D5A61586601FE0B00080818B0716A6A72606262546B71766D666A71686C6A6D6A6A69646C6F6D716F6E71727B6E625A626A5A6C666973727A83707984827C7374736F76756E7364706D6C686D7A756F6C7276747E7B72747E72676B6E70716D75615165717E7A6A6F5D5E5F6D62666969676864696A81757A796B6F7070545F68706E796F64675C5B61656374737674737A6A6969757B6F6C7171645F645F6A746D726D6A695E6059575D5234626F7A8385817974767172736C6556576D626A68666A6C717268636A616067615D62575C5C676A6F6A7F8786878182765E7071737680778588857C7C7E7B858E6D626A68666A6C7101FE0C00080818C07D8574726E74776E787A706B636B726D7078776B736668717B786D7A746E646D726465626A5E5F7379776F717C7469778B756F70607279756F6D6D6368676D6A6665606E676E6F76847E8079736C726E726C716D6D5B5368697266596860645E5959646C66696B6A6D777371676B73617768686167736D6171676272736F6F6E7B78766F74757376787E766D6059696E66687465736B7A6E6C60585E5A5C5644787E7E807E808773786F77725E595462626062696768646D656C6664675D5B6E6768685F5E6A6E696982898782867B75776D6B717283767D848679848179808E626062696768646D01FE0D00080818D06D7455596B685C74746D64636D6E6774767B6F67726B5E5F7777756E6E6E686F70596D666D67696C7A686971787D70777C716D61677373716E6A6C686A71766C64696767737569737D7D828075716E7A7266686A6A7369707379645E6265656B635C5768626467746B7B6E79716E6D6F6A686763626863626C66686E6E5D7F7375706C6F62706A79788177605E646E6C6C6F6E5F6A747376606463655D584F406B726E78756D7A797D6C766F60606364686360585A636D606C685A5C5E63665E695E615F67726E6A70728C8587877E78777E7C868680726B7D8174817C7B868F686360585A636D6001FE0E00080818E07A6D69737165676E6F6F6C7664677072796F6D65646757646165667574736D6F675D606C6B737A6F7168726F7077756E7B72786C6C68736D6764626A6A706C70747B70706C797477817B706E656E746E6F8377737571606F8178646B747172746F6A6B6F755B6E6B63687375717D6663585F5A6873786D7069626D6B6C6D6A6773666A76806F6B717574675B655D69615F67665C65646C66706162695B5A4941787274856B636E6F7B735F6B60695E5A63666D60616A676D6769646466605F696859596A5A5F676C677B88858984837D79756A7577828C83717879787F89828263666D60616A676D01FE0F00080818F06A6E6C64656D7D676F595D5B6361626F7169616B6C696B616E757E7C76726E7775736769736B766A7578676F6A6B736D77747B75737F736967676C6C78606471646C73746B7C71727D797472786F736F706B6D7E70606D767F73636864646262585A586A6878747574667B78747973786266666A7868656A6F646B67685668675C717D767B7E6B707B75716E65606C666C63686D5E707B6265676970675C533B7784868C827B7D7A7274727A6F736E69605E6455646D686D6C69686F6F67666769675E6569716E5C6879807E8084787C7B7B70756E7E79837D798186867D8083605E6455646D686D01FE1000080818006A73646659666966756C635565685E74726E6F76756569726B70737D7A746D6F686B6F67726E6D6E656A6E6A716A6C7788827C707577767A6B7467606D756A766F7567676A6C6E67827B707E79747173666071705965676C6B6D635F5E5F6C5E5A686D6D6C626D6F6C6F727B637B717667616C6361706B5E706E6671706E7873686C726F787C787A7D7B70646C676C756A70736B68656565676A616B645E4E347879839387747B6A706C76746F64576468625F655E62676B6F5B57616765666969736B6660656362667E8082878180757574807A7A7C777F808A85878880818568625F655E62676B01FE110008081810706D6E61636A726B79727675696D6A726A6C6969655D5C686E6C6E7F837C6D706C5F6C5D69686D6A786F786D676C737B80776B796C7D7076766468676D6D73696E6D69746E7577757D7176736B6A696E766F6372616465717A71675668666269616C67606F69706F6E6E78776E736F72606A6B726F6F666D6567696E6E5F757F74767C6D6A6B6A747C7D6666636B6E6B6B6C6A7066687468655266706A6159396680828B8A847D71747575766164676166676C555B646E706E666370696F6F61646662686C726A687477868B797881757878777A7783818281787B8572778A8C66676C555B646E7001FE120008081820707A76776A766978776F6C7469766D696B77796E6A666872706C677B7276626C686B726A71696E6D6B6C7D706971777F7C757672666D71746F67796C6B727370616A67786D7F727C857D79707469756763696274726063667277686E77636D6F605D5D6E6D67676F746F747B686F716676696E7168606E676D66686771707576696873746F6E6A7171686B6C6068666C61637967677065635F5C5E62605D563A77767381776C6970786D77726B6A5A5D5E63645E5F5C595F6B615770626466676B70716F676F6D6C71828E8C7E7D776C6D78797F7F7C7481857C767A807E7E7F5E63645E5F5C595F01FE130008081830756A71646B63717169676E706B666378686A716D6C6B5F616A6F767262656575626A6D6D6F696E6B77706F736B6775767B7F817A7B756F636D6F636A6163646F71716F777D7B7C797A7A79777570717363696F64655C716D746C685F6B6F6568616D5B7269635F6F7B6C79756A796762696067706D7276676A6B66746D7073726C6E63657272746770826A665F6A69696B6E7165615C6A6D6865665556554E42686B7576706E777271697570645C52576465655E5E62676667686164676563686060696C5B5F616C658085938589837B77707A7B7A78757F837C8089817E7D826465655E5E62676601010000080818406B70747B726D6E6E6669726A6A60676D6B727672736A706B6A71746A6D6D65726A6A6A65716E747C7C6F6E676F717276797C847777746971686A686665667474745F64697A817674797479716A6C706C686A6B736B6B746E6A726B6268655A5F5B67606763607868656A6C776C6A716F67656D7D7D6E686A685F676D6E63706A62746A727F6E6F71817E716F686B6B6D6F6D736E6D667073626859645D54563F707C8479757D797E7C6C73776B64605C6E6D7676716F6F64626462696A6C5D686665646A686D60656C73869084767672717B75797A8171767E89858286827E846E6D7676716F6F64 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 27 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 22 0 00008A131700645E06CB7E569617900D6C3B5712A6C0 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 3794 3794 0 066B066A76C818D454EF7114CC1C589111AA80F42CFC9F5FDF040262BA6A5A9717CC4622FA2ABE03873C9EFE26F6967EFA112766BA3A5ABA3ED54F03DF5F7F9F1BF0A2EF33B3D3139370FA964EC6A6C646A52FE33BB3D333B350E8A47CF494149477C9E53DB5D575F516A8A47CF494D454B709E53DB52DF474CF295C845414AA2E95F7E03CEC8C52D63D7B0ED6068249C9727C18C01010F672C9C3A870A0D877F3480604D808905BDB6036439B4BD4E39CB8F172551A8E57D76CDABE66D6EA3DBF04B2CE16A606DE5EE5B7C31BCB479F1FA43E5B8353538A0AB193F921F131E664DF95E038E8B46DED561D8E56E679B9C6E2624F9702408065B80E07C27237BE3E00F2B8F16D0E6FC21AA0C4952FCD44C4024428F0401697177DE48BFE4C0DE360FD4B2734A6CDB610C07C98427292262160264C9525A003A650EC9DB50553D252A97E122F65FA1A7CB4125E863A50F553ADBAE63D3C6DAECB33ADDCF444129313F97D12EB680BE221E7A1CD15A5F372F2AB1F7EAA01E1A125A8066DB90C60A664AD1565BA3014662278FC944C4E259BD906B1EA8935621E8F69D47F1CA0FD3177AD1B40A410B7CC4DAB16D70C016287BF4C505AD83B50E72CB3B71F46A0576B469893FAC7C18945DED7C3C3BBCFEEEEA8B3DF614BE6040440DAAC43DA9A1525457DEA0C3A7AD487C543771DC676D4B65A4B3F915598C2CE8C5BED5399206DA6F1962141BB168646C61D9DB068693DFEC6162C2B5140402A01BFB3FF8A383D51F4327418C07026A7275DDEB1D85E3D30B20CECA5CC4427C76D16015A81FC9E3BEE1017419A0A5030726ACC01E0533FFD548C136C9D0E47B4D159CA17F34010EACAD3A6DAA3284B6EBC42F89D75FF3FCD8E45E81DEC5F7487612363A2797BBBDE72E5B67B8B9AC70435D065CBD04441D1741EE8876FE52544FB23A708F489EACF1EE0E7C91292C8A88913A607DCC9FA1F2EB10458BAAA6BE86B7DC8018B1ECF49CA21AD6118ED8E83003ED99078E222FF8F54D4F9211037F4FC2F153148B0D336C1329905DD6D3BBA3A6091FEAE16FA7253C075FC51C90C38995F1975AD1D4BCA4A3C880140D233B43764DA3AAABB9350F55AC4B59D2D7BFA7A84177B22D8BBEA588097B269704900894F0965BD0D5BDA5AB0325D891E468554C4718F54ECEE8F7FAF90EA7ACC7DF172A57919C6F45D61F72498D253EB26E40167F7B664C959F33059FC9BD16505D368B8687DB5C7B38F592E925CC77F3DFE73881F77B2F29E55578F349A610C7BD35C15AEC216B4C22BA5756AA43181A767E7308428D060A271F9E033FFAB0104228442040299FB9F5FB97FF521DBC6A500609D8B07AB7D03E2D345F06EBD0D4BA4238A771BCF75309633E46A946F01A141C1885B97CD3E56D053889CE33C001AA86CB7A3DC039614F27EB71C80EA49218B4885F893893D5D5F133393C31C4E2DE0E21D2A51E707F538B8754A2AFE5C370E7CEA5CB67ECE2C255CD1FF660694599A7F7DED2169ADC69F497BC7A774C8E4C6656307C9650FBCBC1CC7D3AC7C2E2B4BB93FF759C27A0C86F423FB75E9599B48C07E13590772ED008750E945BD0DCF1C94CD1ED21C36A580D9248F13C775535B2447D312C95CE80E2E65A7AD6CFB975C0EF69D33498D2724649F29972A3AF82BA30AE0F2967C7655D96F0B29F1E39058BDB020CA1BABC778F47B8FA070AA89BB7FA4A0DF0C200B79AD8A30A6724AA82CAC12703A70D4481A53795D6541D3B07DDD2795E4CC5136702F0B1F6743E55F77FBA89CB46C6AB060ECCDDE639D0F7B47E5FCBBF57935530E714F29639621073B449F1F32EA0B5F9C449A6EA28A7055A72378E8A74ED8FB08E979CCD145F69AF254EC757F248AE65547B9D17D8535C76141A85AB6DC690466E13A3CE13D3DF5A68418AEDFF75ACA069508BED20685D7535395D3B3384A0F1151AA1CB20C1CBA89F62DAD8058D9F7349501B4F13A9707C7479C1C31E9C89C5F4795AF6A1089345474BB2B7DA7F2D031AC87072AF2E3D211B02194C9239061F17228CCA3F26B22E1C84AE17DA51543C242B85D3262F057FF6218FA9528D199C81DC5B288535265A68E77791E061C6C3C26EDEB1D567F3D5811EF44D800B0E667E79D7F102DDF97B66EB6411FC44576B539EE80CFE6016215F8010A6979CD64AB865F685D86D62BCBD22A157DC0385829F32B357AAE1CCCA60674E190B8046F691F3BBB964EE24A0D1FC05760BB1686EB6997E3AA5FE598A828F3735E864760A3FF704E2571894C92128F38542DD5B653EF1C0269BD04F67C640D1B049645E78773CF453A5FED25E2AF778B4D374D096CA95A5E92394F2AEA2DCD6FBE647C1B19399660C0D822E88AC03F6C43B3B171C2FE70A1F62634F035505AC8E23D8D5F3FCB777A1E64701633639CACC31BA7CDD552852F81143CB9B612EC5E3202B537F9E1F60EC353E025DD75B3F59941F1A726A64CBDD23281C05CDF2DE80F5476D50118A08FB0E1628B68CAD399DC47EA7ABA3AE1614C94C1B272EFC44469B10D2742E21B8CA77C412B73F1268A64D5428758FA5D372711ADE59D1FC869A7148C5DD6554ED8B4FE65ADAD0DD610E51D3F345C1CE751CF3C248464E4BFF6BA904B838323F89CDBA9D99959393F9927948E2ECE4E37AA6C74E48484AE657176041528EBCE0094F42F2745890FD82BA73C9DF13888B0F67A4CED3D0E2E974E08DC73DB19097B3D4A0B2BDB6F05126EC8C27E3775F9080C6C91A14998A8C037E97DE85810B0B307D60636E9AAC0C6C054CD8FA34913625630C0C2EE070758AF41D34B4DC4FEAD19D80339CA80B4DD4006546ABAC1B1D0EE00D047A52C4417A3C3102093C3C9E6A2E11329A797E8C38F0D17A9E3C14FBD8B2BE2B21EFEBC3AE0E92090FC35BE303E50931040B044AFFA66047062CE605BAED35D58CDAFE42B1C2EF5D79C796BDB44E810A0488089D9CAF109A434F474AF2F02DA4B6CAF875E4AEC20B58D6D459CA1679AB9FE32F8C1D8343DC6A5A505DEAAEB87F7B7774F96C060A8DAD7A39161F0F929BB63A12DECE8AF5F0A6D8F1239B9944CAD864505FE48669B9F3FDF5FB4463AA25010927718B32FF747119010C7726C14D4E562E13696429F1FBC8CBCC4D26C9E04D4D8F8F39804067A9854F0CB3E43FD55092B81741056BC4794B33EF2E68676C6BD3DBDD0C7DBB818D8B80C677B374F5F4BCD4D962C4A203FDF3A4367690062069479D700AA3601A0303E2D34EFAD6EEDBD4DB904F13D6E75B0F55224907DFB48E80888DB65806A7F56B62B0080AD754463A000B9FF1BCB705313A1EADCE29A581DF7F74A5C40EFAFB55385BA08469C0A287B8BD04429D149189230EB7F02FA6A3BD90AA1551CEE1E3A0AC05DA9C13F2E11D2D24DFAD646C701D55924502FEBA9D5EDEF67A18B51E167B533E45030E1C3F04060190FCB190B0EFC614ADEB04D7BF4CB4B90103DE5593BF772E81976A251F93D7D7452AC69B5C35ADD0D32DE86C220BD51DCE28890D212309F6E6416E84609EF41B66634BB5956BC1C5513BFFEEE2CE54F2699DC849EEF9FB54EF493E90408E2CE87387339C34B26A45A1F8C12A9C9122CD7C35F475D9DEF00F1F7200802C8BA30C195F30232E9385838AE70F529631F3DEC7DB32078B577FB2B78FBDCA4C02A763F8400740D665F2DBBE5419D07BB9914274DEF9A28449F3F66208CC6D624CD677C428EC6EF7F252D74CA81DB26AECBA783FD9546C5BE5CFC07C5FF3470826EC790AFC899ABA74E02C1922205A838F878A3230ED62727E455EF5ABE221BF900C4024428F0401697176E1A661B98D88969B18F6130C9B48404DF5F72AAA7C524C61E80EE3A06ED8FAA73ED00BB08FAF8682ACE3BA1989AD655B793E2CA7A2CAD2DC7137C9C2FFD2EB661CBA09339C856D5CED39FE5067E7EDE052B4E14B7D1B3F03B17F3A26164882841E4905F046A1201567B9F4C5133139B40DBBD783854960B20A08D55D4D615AD75710FC3BB7810B3A2AF7A01164DDCFCBCCA24EF47BEDD4AF964CABAF574D0537075D9219123F06802FF90A8C5B5876C17734C8CFCBC7C5EAE9834CC7CDCB6265F826EF041214300CB5813EB9BDB1B0A8F3AD41FA95198BAA204F2A29B882D89724CA3D664E42CAC6A2C4098287EFF7FE6F86B22F794E507DF587FA4ACC7C55E9D27666E1252508B483E72AAB8FB9BB2D2A4E830024121619A2CD08020D2B33378460A50834343E338ACE3BBCB8B4B8B72D4FA863616F454AD7894511147C646FB791D47F4B3B132CF1F4B9984E69B180EBCF5B5275A6A42CACE0221218D5D1F8717BB43F301CB475CCAA6CEE797C50FD873EF3787FD3CBC67D1BD65D5519C1EA5177AA21272B232E9EF8D5787CD0F8F54E28E56E666B4368D274B9B2B36F20CD3E19F45958152D06B453AE030F023A11A740CD6067EAB2992146EB46430E567DCD2AB71A1C101815A1C8FA8E78747C71C5AC9EEA1C101815A1C8FA8E78747C71C5AC9EEA1C101815A1C8FA8E78747C71C5AC9EEA1C101815A1C8FA8E78747C71C5AC9EEA1C101815A1C8FA8E79740C279EB904A9AEE36B40F1962B86808C8489325499121418101DAA0D40CDC6CB4348FC1B46CBC30F070AB1D71A91978B838E35438E15130F838E35439E05170A024FD6A02FB4F0E4ADA43E49950F1D83A9E6798E677D5FC6ED71EFD800DAC994C99534F097BE12B416B9A7940CD281D885D53B00984E12B012B1E0280F2AC7A1721171796F8A5736E35336BE9DF813F84EB8DE572743FE1CEB593DB496F21BF88B793DB486E21BE81FEDA582DF5257DA4249FD5A078A8FC3CBC67D1BD65D5B575F52E98F42C9CFC3CBC67F99C4494D019992284588232528808B37518C0706CAB2B909AFB21F1AD65E55EFC9E449438F674CFED875F8F4B8406BD4F25FD2DC10E8C377104DC0CB877F54E4835EF3FE72FAF1482FC26F62AED6DD6344A9040E83AB8035D37EF3F3BE361DA2C4A92421495154F7B1178482EF27832056F15EE8EC74EB0046855E181E466BDEE875F0A62A207DF69A071C10043C5AF9DF78A6027FA8A51D1FC24A54086277ACA8F8429B979F922A28F57D631F75605B5F06BC6569616CD4D60B839DC1ABBE9591C57FA6AAA2AF1715C8415F83E8FD86895C77190DB5D0FF0B56EC3539313C84865BD9C72B438EBDFFA22F79656773C8C510EB81956D0C27FBA399404C4449F1F32EA6B9A5CFDB404418A27B777F72CAC8159689C5AEBA3135E13A5EC0F068E25B961D1870686CCEC86DFF89ED77EC0761ADF9FC948C8B29CF69C8C60088279AEC29208D2A8B477CDBD6954D63C948F19757F81EDEF24D84B807BEB6DBE2ED563123A8AEA2AAA71C7AB73C3A363E3388FE33F8F8B51D368 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2565 2565 0 02F000140003000900042004300000000004030009001820043000000000040300090020200430080080000403000900242004300000FF0104030009002C20043001000000040300090040200430FF030000040300090044200430E5030000040300090048200430EA03000004030009004C2004300A00000004030009005420043001DE010004030009000021043000000000040300090004210430010000000403000900082104300200000004030009000C2104300100000004030009001021043001000000040300090014210430010000000403000900182104300100000004030009001C2104301F0000000403000900202104300800000004030009004021043001000000040300090044210430010000000403000900482104300100000004030009004C2104300100000004030009005021043001000000040300090054210430010000000403000900582104300100000004030009005C2104301F0000000403000900602104300800000004030009008021043030000000040300090084210430010000000403000900882104300100000004030009008C2104300100000004030009009021043000000000040300090094210430010000000403000900982104300000000004030009009C2104301F0000000403000900A0210430040000000403000900C0210430300000000403000900C4210430010000000403000900C8210430010000000403000900CC210430010000000403000900D0210430000000000403000900D4210430010000000403000900D8210430000000000403000900DC2104301F0000000403000900E0210430040000000403000900A0200430EFE100000403000900A4200430000000000403000900B0200430000000000403000900C4200430140000000403000900C8200430000000000403000900CC20043020000000040300090050200430000074010403000900A8200430FE217401040300090004000038000700000403000900080000380015000004030009000C00003801030200040300090010000038010702000403000900140000380C0C05000402008005FFF98720BBF88700BBF88700BBF88700BBF88700BBF88700BBF88700BBF80720BAF80720B9F80720B8F80720B7F80720B6F80720B5F80720B4F80720B3F80720B2F80720B1F80722B0F80722AFF80722AEF80722ADF80722ACF80722ABF80722AAF80722A9F80722A8F80722A7F80722A6F80722A5F80722A4F80722A3F80722A2F80722A1F80722A0F807229FF807229EF807229DF807229CF807229BF807229AF8072299F8072298F8072297F8072296F8072295F8072294F8072293F8072292F8072291F8072290F807228FF807228EF807228DF807228CF807228BF807228AF8072289F8072288F8072287F8072286F8072285F8072284F8072283F8072282F8072281F8072280F807227FF807227EF807227DF807227CF807227BF807227AF8072279F8072278F8072277F8072276F8072275F8072274F8072273F8072272F8072271F8072270F807226FF807226EF807226DF807226CF807226BF807226AF8072269F8072268F8072267F8072266F8072265F8072264F8072263F8072262F8072261F8072260F807225FF807225EF807225DF807225CF807225BF807225AF8072259F8072258F8072257F8072256F8072255F8072254F8072253F8072252F8072251F8072250F807224FF807224EF807224DF807224CF807224BF807224AF8072249F8072248F8072247F8072246F8072245F8072244F8072243F8072242F8072241F8072240F807223FF807223EF807223DF807223CF807223BF807223AF8072239F8072238F8072237F8072236F8072235F8072234F8072233F8072232F8072231F8072230F807222FF807222EF807222DF807222CF807222BF807222AF8072229F8072228F8072227F8072226F8072225F8072224F8072223F8072022F8072021F8072020F807201FF807201EF807201DF807201CF807201CF80700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D8F82720D9F82720DAF82720DBF82720DCF82720DDF82720DEF82720DFF82720E0F82720E1F82720E2F82720E3F82720E4F82720E5F82720E6F82720E7F82720E8F82720E9F82720EAF82720EBF82720ECF82720EDF82720EEF82720EFF82720F0F82720F1F82720F2F82720F3F82720F4F82720F5F82720F6F82720F7F82720F8F82720F9F82720FAF82720FBF82720FCF82720FDF82720FEF82720FFF8272000F92720D7F8272000F8272001F8272002F8272003F8272004F8272005F8272006F8272007F8272008F8272009F827200AF827200BF827200CF827200DF827200EF827200FF8272010F8272011F8272012F8272013F8272014F8272015F8272015F8270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A0008001003181C1003181C030009000020043080000000041700000005000E000C20FD00FFFF000000000208000005000E001020FD00FFFF00000000000500000300090004210430010000000403000900082104300100000004030009000C21043001000000040300090010210430010000000403000900142104300100000004030009001821043001000000040300090044210430010000000403000900482104300100000004030009004C210430010000000403000900502104300100000004030009005421043001000000040300090058210430010000000403000900C8200430040000000405000E001420FFFF00FF00000000000083000300090084210430010000000403000900882104300100000004030009008C210430010000000403000900902104300100000004030009009421043001000000040300090098210430000000000403000900A021043000000000040300090020210430080000000403000900602104300800000004150008000000000020280000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 2368 2368 0 00000000FFF98720BBF88700BBF88700BBF88700BBF88700BBF88700BBF88700BBF80720BAF80720B9F80720B8F80720B7F80720B6F80720B5F80720B4F80720B3F80720B2F80720B1F80722B0F80722AFF80722AEF80722ADF80722ACF80722ABF80722AAF80722A9F80722A8F80722A7F80722A6F80722A5F80722A4F80722A3F80722A2F80722A1F80722A0F807229FF807229EF807229DF807229CF807229BF807229AF8072299F8072298F8072297F8072296F8072295F8072294F8072293F8072292F8072291F8072290F807228FF807228EF807228DF807228CF807228BF807228AF8072289F8072288F8072287F8072286F8072285F8072284F8072283F8072282F8072281F8072280F807227FF807227EF807227DF807227CF807227BF807227AF8072279F8072278F8072277F8072276F8072275F8072274F8072273F8072272F8072271F8072270F807226FF807226EF807226DF807226CF807226BF807226AF8072269F8072268F8072267F8072266F8072265F8072264F8072263F8072262F8072261F8072260F807225FF807225EF807225DF807225CF807225BF807225AF8072259F8072258F8072257F8072256F8072255F8072254F8072253F8072252F8072251F8072250F807224FF807224EF807224DF807224CF807224BF807224AF8072249F8072248F8072247F8072246F8072245F8072244F8072243F8072242F8072241F8072240F807223FF807223EF807223DF807223CF807223BF807223AF8072239F8072238F8072237F8072236F8072235F8072234F8072233F8072232F8072231F8072230F807222FF807222EF807222DF807222CF807222BF807222AF8072229F8072228F8072227F8072226F8072225F8072224F8072223F8072022F8072021F8072020F807201FF807201EF807201DF807201CF807201CF80700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D8F82720D9F82720DAF82720DBF82720DCF82720DDF82720DEF82720DFF82720E0F82720E1F82720E2F82720E3F82720E4F82720E5F82720E6F82720E7F82720E8F82720E9F82720EAF82720EBF82720ECF82720EDF82720EEF82720EFF82720F0F82720F1F82720F2F82720F3F82720F4F82720F5F82720F6F82720F7F82720F8F82720F9F82720FAF82720FBF82720FCF82720FDF82720FEF82720FFF8272000F92720D7F8272000F8272001F8272002F8272003F8272004F8272005F8272006F8272007F8272008F8272009F827200AF827200BF827200CF827200DF827200EF827200FF8272010F8272011F8272012F8272013F8272014F8272015F8272015F82700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000038A483F58000000000000000150000000300000008000000000000000000000017000000080080000000FF01000000000100000000000000000000000000000000000000FF030000E5030000EA0300000A0000000000740101DE0100000000000000000000000000000000000000000000000800000000000000000000000000000008002028000002000000000000000000000000000000000000000000000000000000EFE1000000000000FE217401000000000000000000000000000000000000000000000000140000000400000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000001000000010000000100000001000000010000001F0000000800000000000000000000000000000000000000000000000000000000000000010000000100000001000000010000000100000001000000010000001F0000000800000000000000000000000000000000000000000000000000000000000000300000000100000001000000010000000100000001000000000000001F0000000000000000000000000000000000000000000000000000000000000000000000300000000100000001000000010000000000000001000000000000001F000000040000000000000002000000000700000015000003080200010502000C0C83001003181C000000000C0000000C000000010300000000000000000000010158026F0000848418620000000000000000000000000000000000000000000000000000000000000000000000000000000000A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A508000000C0014000FF1FFF1FE123FF1F18A25503D3A25D0018A25503D3A25D0018A2550320FF80003F040F0100000000000000003800000000000001000000000000000000000000130000001400000000000000FFFF00000E000000C20000000000000000000000050000000000000000000000000000000000000000000000FF00000000000000EE000000980000008800000011000000000000000000000000000000FF0000000000000000000000000000000000000000000000000000000000000000000000FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 36 0 000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 4800 4800 0 01FE01000808081073766C6D6F6E757876766E706871766C6F75726C666C676063646B7C7D767A707373666A6E6A7169736C6C756C746F736B767271706A6E7E7466726D686F7A6F6A68676E6B74787B7D797F716E70756A6D7468766866697B8078666C6E5F606660665E68695F615E666B6F7A6C70757674686B6C6B6B625A65616262676D737C6C717775737571767175726D676B73756C62607670665F5F646A61625D574832736B7F7B726F73776E717C7363605C5B655462565B5A606E636C6769695F696863676668697170726D7D8B847D8B857F7A7072787A7975797F787E868A777781655462565B5A606E01FE0200080818207C716B696E6B6D6E7569616E6C6A71716A716E6F75695E615C69717C796874777F6B696965656B74746B7060716E737674717C757485726D6F6F6A676A7969616D6C666E687875757B716D78746A756F626C737A6E6F697078716B6A7268616868685A6A665F706F72756E727273726E6460626365586666696C676F676F7676716A736670797C787D7A706A61656F71726E6E6A67686469656966605D614C3A797E7A7E83817670746D716962656A5E626C6664626A69706569615E6462576E6C6775676B7867637079827E848272757A7D787B7F7E74758076777E7A788B92626C6664626A697001FE030008081830767A605F64606F706C656A73696769787B7170696D59635D657376777C817273636E6B6165656C6B73706F67746E6A76828572686D6C6E716B6C69736F6A7578656C6D74827A7B717A786B65636A786E677872706D6C6C65706E5A676F6A615F5C615D5F5D646E7676716E75716D756E626C69666A64796D68636A706A6F6D787A7274748069726F6A7163675A59686D70656D6E7161746B5D5F5D61575854376C62707E7675707E7C71696766645A57665E6A69726E72696A625F5D65605E6A64636368646D6370717F8B89817878727470787F7C80797D83877A827D7B8184665E6A69726E726901FE0400080818406D696766615F716A686971686367666B75806A6D64665A6466686A716E7C6F756C6D68636A6D70746E626E6F757B6A777274836871777A7A726B71636D6C6A6C666E656F78706F717D7B777070707670656A676F676B717B7F816E67606B6463676A5A6363656F7D786B74716E666C69595359666C706B59686B746E7B717E6C697367656A6E727D788177696A6970706B71716C6A6A72675D6161606456543D676773767B766972656A6A717063625759606E6366656B69676E67676E6F7371726F69645B626C6B6F757F828687766E717073807284887A8274767E78818A8959606E6366656B6901FE0500080818505D676164685C6A6D7464676464706B76747772695E68705F677562696C7865746B64605F7266726D707C77747478747E7C757481737B796769636268736F707573655A706B756D778279677075657173646F717B6B656D77787C6D5C6C716E6864625B5A7675696364687876736F6E6D5F676562746B685B6566636C6B6F727273756F7070706E737A7B6E6665686E6D76776C75676C64666260595B5B5350376C6E7B8167717467746D766B675D58555F5C5C526265646E79735A6159515D5862645666616E75726F758D80897771757C777B808080787C7C6F7381887780845F5C5C526265646E01FE060008081860847C82756F656F7A75746D7767796E76726E666B726D676C656A716B6D77676C666B686678776D746D7B6A707179726F84707E6D6F696B7873797B636C6D74736B706E6A74706D7A7984767A6E686D6C706D646A665F6876867B6862676D6768596A6C6C606C5F687B747D7B756B717D6F6B655F666A655B646C6A73666F636D6C6C6B637174657E7E816E68626267766E5F5E6C5D677D665D555B655C4E55366E797171826C717A6D707677686C6662645E675866616B616B635F646C6B5C70726859646D686A5F69727E807C7C7B797F6A6E797B7B7F7C827783857E7E7F85645E675866616B6101FE0700080818707D6D5D6F6D73687A716D716F74736D7773767174756E66697075777475666965656863676F667071777375737A6570757E79826A6B796C756C72716A756D71716063686E6A6872748074697376787B7B706C6A735E6A5E72757D736570706968726668626164636B767568756D6E6E655B576B5E6C727065676D6265626C71736970667274706E7C7A7A756F605F6171756E6F6E716263675C6B6C606653573D79787D7E79747470726B6F7A73645F6A72686C5455565D6A716B63625C5F59646C6567606764646472778481827F7B7B6D707B7A7F827E7B877A84857E7E868772686C5455565D6A01FE0800080818807A757070726D68666C6E76686366757B7A736E7079776B666F6F746F736B6665615E6C6B64696D6B7A736D6E7975727A7F75796E6971707478686E647162636A686C626F6A7B787482796D666A5E766E72717476736760656C776960696569686465636F656E656071756E796F6D71707366646A6968605B6D626B6767666B7972717273767C6D6F7A8067675B5E716E6A72706D67686A67635A5B605C4F5D416F7075747C6D6F6973716F6F685E59666266655865676A64635F626E6E67646B6E656F69686C5E676B7C7C838D777D786F7A7A777C756F6E83797D8589787C846266655865676A6401FE090008081890766B656A636363727678737367626E736A6A6E6A6F656D666B6B76807776746A6664556370666A77677171797076707F807B756E6A6C706373797E72715E646F6F79626F717E767F817678736C6D6D675F726F7661636668757375666C6A696D6764617160686266687379756A646567686A666F606665555A6F68656561736B71757277707D68747D82696B5F616879806F6A7A72656B636772696B585558457376787978757F6C71765F6C6A645F6072626F665B5D5968685A65696A6669666C706B605F646562707D918D88878380727C7A73787A6F86807E737C7C73878472626F665B5D596801FE0A00080818A0686E6C61655C7064695D5E6D65676F726D6D6D5E70696F6567716C7A76787172645A6C6A656678736F6C706B747376757B85807472656C6F68707A646F6D6E666675696D6E75747586757C7A6E6976696A6B6F6E626C6C7172766B5E6961636C59796A6C776B71686C70797068716E6767646167766B64625F6564636B716A6D6F71717370707079767773666A67676C6B6D6267696C666C675C665A68514834727B717E877980777B7B7B786A5C5F5F72616663676B5A716B5F5E675F5E6766626766635F726972717E8F8080787E8077797C7E7E8079757F7B757D7D7C818C72616663676B5A7101FE0B00080818B06A6A646E5F66656068766D6D64615F757375756C5D5D636B756E71777F6C6F756F6F6268656D646B7A676D706E85757A7C71727870656B6C6D6A696368776C79656E75655D6668707C7F7D6E6F6A706C717F7E786965626A75736968786D7064636F70766B6768646B7273736661706C705D666B6863616F6A676D68636A75767170736B74717A72737E726C626169726B6C6A6570666D756B666A5E67544C395F707283766F787777716E6D62636161655F6262666D696864616467585C5F676D655D6769665F6269798C8E898483837B797A73757E77787C82817C79788882655F6262666D696801FE0C00080818C05F5F5354556063606E6760606565645C626D6F6A6C5F626E68706C68767569705962595E69667265746D69747282806976717C676B757374746D746A647165676E6D6E6673736A707F8478776E707873616E79776F63627874776B696B645A596D6B64696662716C71717A6F78786973765F5E5E6F685B64656467737F7D736C666B7268756B6F6B837A6E6960636F6F666575726E63746F61646F69635C4C416F7F79857A73716E6F6B68696A635E61635D586A5F5F6B7268686A736F67675F686D636A686D6464687B8581838C807F7B786D747B837D7E8E79717E7C7C8288635D586A5F5F6B7201FE0D00080818D077737471676871696B6E726F72696E6E6A72736965616A60646F687A7469696E6B756B7172677771776B707C726D646E7376826F7B737272746C6A6B696B676862756A636B7A7770726F7972787674766A6B6F6B6568656B757D6962747068605B615D6761686270707169716F707A6E6F626C6872726C6660605F6675727273726C6A757B696C73777B6C685D6475646C6C726B64606F776765636B6264573C7271757A7E7C6D69786F64695C61585A6A65665E5E636B736C63666D747865686C6F706A706C65626576877F827E84767276707A7E8182788483867D797F8A846A65665E5E636B7301FE0E00080818E0726B6B6C635E61636866616D5E6D756F726A687175716A66686771736F706B6B6C6A665F6C65635B695B697C717475817D7F777472787D72696C6B6672707369676F69756D7A77787880876D7C5B6769726E68625D625D67767D766562656269676361646F6C7174837867716C5F6971756E5663666B6A64686D7675716F73676B71727976756A687673666A6969676E796B766B6670686F61534D675657554471706D74766C727063636470695F5D62634D575F5F5B6D6C6966646D66606475675D606367706A7075818C8886827C7F7B6D717476847E77767A8188787D878C634D575F5F5B6D6C01FE0F00080818F085766E67616966655F615E676666707379686C6D6C6C646C696B726F7E73726E706A6A6466686F736E726E7379747570846F77746A75686B726960606F60707068696A707177677A77767474757B74756E7372715F6768788275585D6C6B6665696B686E6C6D5E67697A6A74717376696C69626C676467676E6D6768627A7777746772696A6E6C747A7D5E655F74706A6D6E676863686E6D655E4F576356563C6C7C7576776B716A6E79656E5C656A656A605E6E6E625A6160605B6A63596565695E5E6366626368747C8B858C8585837074777B79827574787876828682898F6A605E6E6E625A6101FE100008081800735E64706C69696466626E6D6D686B77767C73767362636F6E6F65727477646E6F68665F656565666C707565747E7878807A77715E6B6271646C7179795E6B6A73717571667F62707F7D6E74767674707B7D6B726A6E6471696D6357645C5A64676A62696863676E6D6E858079767A6F6D63606E766C696E6F65666A656D6E6F6C6E6B7174796C8C7B71726E6364777D6E6B63695F736C68626F666566554D2E66726E72756E6B697376736D625C525B6256646263696366666962665A5C5B66615A5F67676B615D6E7D8B7F827D778184817C757B817978857A707F787A7C90625664626369636601FE110008081810796A6B64625E686D6D616F70586560626F6C676C636E6971757278747E7E726B66626A727765706B696C706A6B6A70767F7F796E67746D6B6B6A736E666667656867666F6A717A7E807D7B7A6B6E796F636D6E7466615F6D767668676E626268666860636D5E62787C7374796F6366676D655F5E5F656B746C6C6F7077707C79696B686E766D6873756F6D6665626873736D7C7C6A6E6F6D6760615A665E513D7C93867D8079726E8279827B675F4D626B6A6D6E5C645F7474676C656B61636768615B636C6B6B606781918D8590807D787D707D6C777584827D7D81767D87836B6A6D6E5C645F7401FE12000808182078786567645E636470666465595F65797176755D6F6D6C6E6E64676375796B5E5D606963696A6F6D6F6E70777B807E8074777567687E75806B616E6268656C65716B71756F6C776D7C79726B7066716E677568786F59676F667B676A7A6D5B555D646E726C706A5F6F75787A7574737565635E6464617167756F6C6267726D807874777669687C817E826A5B5F59696F6E6C656767666B706E5B665B65544D387474747275716E6E69685E695A5A55555E5D6A5E5C5F5F616C6D6B6C6067676C6E7366666C625E586878928C818483716971797D7E7D828682787D7D777F82895E5D6A5E5C5F5F6101FE13000808183068737A7B6C5E74727072827E6C686B6777635D72746F69796E637471767068706E6D6A59696E7A6B7E797B6F7E6E717C73776D65666A5D6F6975736F756365696D776F6B6D6E6579747B736972657E73637173705D5C6C7D767C7A656E68636467696B716A6E6D6C6F64666E7470756A625B6E6F6C706562747562696B6168686E7D736B6E6F686A67817574646567656764606A696E726F66625D6163585A46697570767476777C777B70626061595E685C68595B6660696666646A6165646E6863645B6B66686075848E8774818A79797D767A78817C78816F788A81827F90685C68595B66606901010000080818406F766A6C6D74736F6D6E6462676E74756B676D716D6866677168717071756A6E676A5E69676D766C6F64776A7472787B84717471726F706A6E676D7168676D6B667070766B7167767E7A78706E6675717672646F6D656673897A6C5E5F6365636A6860726B63636E74766F7C706B6A726F63666569676A616A5E646F786C6E706F6F696E6C7A736F7A7373686D6D67696C666B606B69746D5669576657534F41767C73746A747171716E6F6F585F5B6267646755605B59586366635D6A5A62686264676C696C5D646678887F81858F7F6D6C707B797F6C7C818482807D86879067646755605B5958 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 117 117 0 2A0000000000000001FF0000FFF401000000000000000100000000F40100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020BF0200 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2903 2903 0 02F000000003000900042004300000000004030009001820043000000000040300090020200430080080000403000900242004300000FF0104030009002C20043001000000040300090040200430FF030000040300090044200430E5030000040300090048200430EA03000004030009004C2004300A00000004030009005420043001DE010004030009000021043000000000040300090004210430010000000403000900082104300200000004030009000C2104300100000004030009001021043001000000040300090014210430010000000403000900182104300100000004030009001C2104301F0000000403000900202104300800000004030009004021043001000000040300090044210430010000000403000900482104300100000004030009004C2104300100000004030009005021043001000000040300090054210430010000000403000900582104300100000004030009005C2104301F0000000403000900602104300800000004030009008021043030000000040300090084210430010000000403000900882104300100000004030009008C2104300100000004030009009021043000000000040300090094210430010000000403000900982104300000000004030009009C2104301F0000000403000900A0210430040000000403000900C0210430300000000403000900C4210430010000000403000900C8210430010000000403000900CC210430010000000403000900D0210430000000000403000900D4210430010000000403000900D8210430000000000403000900DC2104301F0000000403000900E0210430040000000403000900A0200430EFE100000403000900A4200430000000000403000900B0200430000000000403000900C4200430140000000403000900C8200430000000000403000900CC20043020000000040300090050200430000074010403000900A8200430FE217401040300090004000038000700000403000900080000380015000004030009000C00003801030200040300090010000038010702000403000900140000380C0C05000402008005FFF98720BBF88700BBF88700BBF88700BBF88700BBF88700BBF88700BBF80720BAF80720B9F80720B8F80720B7F80720B6F80720B5F80720B4F80720B3F80720B2F80720B1F80722B0F80722AFF80722AEF80722ADF80722ACF80722ABF80722AAF80722A9F80722A8F80722A7F80722A6F80722A5F80722A4F80722A3F80722A2F80722A1F80722A0F807229FF807229EF807229DF807229CF807229BF807229AF8072299F8072298F8072297F8072296F8072295F8072294F8072293F8072292F8072291F8072290F807228FF807228EF807228DF807228CF807228BF807228AF8072289F8072288F8072287F8072286F8072285F8072284F8072283F8072282F8072281F8072280F807227FF807227EF807227DF807227CF807227BF807227AF8072279F8072278F8072277F8072276F8072275F8072274F8072273F8072272F8072271F8072270F807226FF807226EF807226DF807226CF807226BF807226AF8072269F8072268F8072267F8072266F8072265F8072264F8072263F8072262F8072261F8072260F807225FF807225EF807225DF807225CF807225BF807225AF8072259F8072258F8072257F8072256F8072255F8072254F8072253F8072252F8072251F8072250F807224FF807224EF807224DF807224CF807224BF807224AF8072249F8072248F8072247F8072246F8072245F8072244F8072243F8072242F8072241F8072240F807223FF807223EF807223DF807223CF807223BF807223AF8072239F8072238F8072237F8072236F8072235F8072234F8072233F8072232F8072231F8072230F807222FF807222EF807222DF807222CF807222BF807222AF8072229F8072228F8072227F8072226F8072225F8072224F8072223F8072022F8072021F8072020F807201FF807201EF807201DF807201CF807201CF80700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D8F82720D9F82720DAF82720DBF82720DCF82720DDF82720DEF82720DFF82720E0F82720E1F82720E2F82720E3F82720E4F82720E5F82720E6F82720E7F82720E8F82720E9F82720EAF82720EBF82720ECF82720EDF82720EEF82720EFF82720F0F82720F1F82720F2F82720F3F82720F4F82720F5F82720F6F82720F7F82720F8F82720F9F82720FAF82720FBF82720FCF82720FDF82720FEF82720FFF8272000F92720D7F8272000F8272001F8272002F8272003F8272004F8272005F8272006F8272007F8272008F8272009F827200AF827200BF827200CF827200DF827200EF827200FF8272010F8272011F8272012F8272013F8272014F8272015F8272015F8270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A0008001003181C1003181C0300090000200430800000000405000E000C20FD00FFFF000000000208000005000E001020FD00FFFF00000000000500000300090004210430010000000403000900082104300100000004030009000C21043001000000040300090010210430010000000403000900142104300100000004030009001821043001000000040300090044210430010000000403000900482104300100000004030009004C210430010000000403000900502104300100000004030009005421043001000000040300090058210430010000000403000900C8200430040000000405000E001420FFFF00FF00000000000083000300090084210430010000000403000900882104300100000004030009008C210430010000000403000900902104300100000004030009009421043001000000040300090098210430000000000403000900A02104300000000004030009002021043008000000040300090060210430080000000415000800000000002028000018005201080005000A00FA001E00C80000009F00380000000000000000000403FFF9FDFEFE00FD0203020101FF03060C08080C060A0B060B0A0C0A0A07020507060A09090C0C110B0D0807090909080609FEFFFF010601FDFB000104010205040002020507050305020A060304000102040101FAF7FAF9F6F7FDFE02FEFCF7F9FBF7FBF5F8F8F9EFEEF2EFF0EDF2F7F9FAF6F6F5F4F3EFF1F5F4F1F5FAF8FAF9FAFE0102FEFE0301FCF9F7F6F4F9F7F7F5F7FAFB00FCFDFDF6F2F4EDDCCEFF0507080E0E0F0A0C060505F6F2F1EFF4F6F4F5F6F7F5F8F8F8F2F7F3F0F3F5FDFBFCF9F9FCFAF8FD0B1C1713140F0D0C0B0B0F0C0E100E1112141C1C202024F4F6F4F5F6F7F5F88080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 04 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 64 64 0 010100007F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 84032 176 0 7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 64 64 0 01FE3063070718008374625F696D6F74826A706A666E686A6D70686F6D6C716B696E6E72766F6C776D6C6E6D6E68716366676E78746870707C7A726C6C726973 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 84032 1616 0 68736E726A6B71696C6E6D6E7371747A797B7A7268696E6C6E78787C7770707475777C7276686867626B656D6D6C6F74787F7E7A72767D746F6B6773776D6E736E6C79746F6E74746A6F73746B77717277766E766C6F767A7B72777A6C747575666C6A68605B614B6A696C7C787A7B77746B696B797B7B7978797E7E747E76707476777473666B6C69717A6E70747476776F717477726D6B716E787C7B7177707D7A787B8688888378797E7E747E767001FE31630707181079777B76767B796C6F716F6E6A716F747B6B696F6F7166706B647171746C6A6F68746E7973686A70686C6F7E71726D6F6E6F6C706B757371716D6C756E7569706E6F6F6F6B676C6D78707B7672656D6D6E72747F756D7675787E70706D6B696C6F6F6C76777374777C7774726C75767C646874716F717075746D656C6F74706F6F7273676974707A76817875656C7A767D73717072716E6E6C656569595E63507277787277777573777B73787D7B807E7E76777D7A75787C75666D77716E6E736C767979787071787D717772726F7177736D6C787C766F767A747A817C827E837E76777D7A75787C01FE3263070718207671737573746F777A6F716F66696C78746E6B676A776F6E6F706B696D706A6D6E68696B6F6B756870626E736E6275716C6D777270707677736E7170716D6C6E696F6C6D6F7074737275786E736C787270757774776C67737679727072726D696A6B6C6C6A6B70757879837A746F757876726D73746E6C756F78706E7074706F707770726B74747F787D706D6669777A7D737A7176707576737269626360604D747A7C797D7A7E6E7B70707284838882837D7B79807571787976746E6B717373717972777873777177767D6D726F73726C6E6B726F7572747A7F7F83827B8185837D7B798075717801FE336307071830726D615E5E5A716F6B676C5F66706E6B726E6D6B6E696B6C6F6E707269716D66685B6B70716A6C6264626D6E6B6B69656774706E696D767372777474766A70656A6D6D70737C777476747C7374747379737A6D776E6975758580756C7273726B676F6C716A6A6D7176777C7C767574746F6E6D71746F6A6C76757C736E737477726E7072706E768083796C717371776C7378746F70746F7170696E6D635F594A7577797E757176796F6E6D707A79787A777B80787D7E7B7A787B6F7A75686D6F726D736F72797073736775727C70756E746E7573727878767A7781847E7E7C7F777B80787D7E7B7A01FE34630707184074707070626B716B73726B71696B6D706E6F6F77696C68656A696E767B756E72676D686969696D6E696D6B6F776E67706E6E6B68676E7079756B77717370686569686E6B6C6E6C74767178737568696F71797B7B6F6C6C778581786B726F656E606A697073726C7279777D80767973727175696E6A7076686E7171757A78746F6D77696D68706E7377786D726A717E807E707C7F7175746C70656062675C5F4871727276787472706F6971747D7C7B70777A7C7A7876716E7978746F6F6E6D6B6E74736F70716C6D6F797E79716B6F76747572747779777677817B807D7F8181777A7C7A7876716E01FE3563070718506D6A6563676C697474656C6568676A67626D696F686E6A68726B717272727175766D6B756F6A66676C6765746F6C67727273706864727874706D737272736B6E686E6C6864696B72736F6D70726873736F7B717B746D7379837D766A77746E6E69706E766C706D697474767573757979786D757C707278737A77747474736B6C6D6A6C6A73697073797E6F706871767B767476737976726C69696A696A63554E6F7973796C7071707676716F807C79767A7F79717578757A77716E76726A7075716F6F787473716E7474777B7C78746B6A70736F7C85747D747778818083837B7A7F79717578757A010100007F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 2 0 0000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2565 2565 0 02F000140003000900042004300000000004030009001820043000000000040300090020200430080080000403000900242004300000FF0104030009002C20043001000000040300090040200430FF030000040300090044200430E5030000040300090048200430EA03000004030009004C2004300A00000004030009005420043001DE010004030009000021043000000000040300090004210430010000000403000900082104300200000004030009000C2104300100000004030009001021043001000000040300090014210430010000000403000900182104300100000004030009001C2104301F0000000403000900202104300800000004030009004021043001000000040300090044210430010000000403000900482104300100000004030009004C2104300100000004030009005021043001000000040300090054210430010000000403000900582104300100000004030009005C2104301F0000000403000900602104300800000004030009008021043030000000040300090084210430010000000403000900882104300100000004030009008C2104300100000004030009009021043000000000040300090094210430010000000403000900982104300000000004030009009C2104301F0000000403000900A0210430040000000403000900C0210430300000000403000900C4210430010000000403000900C8210430010000000403000900CC210430010000000403000900D0210430000000000403000900D4210430010000000403000900D8210430000000000403000900DC2104301F0000000403000900E0210430040000000403000900A0200430EFE100000403000900A4200430000000000403000900B0200430000000000403000900C4200430140000000403000900C8200430000000000403000900CC20043020000000040300090050200430000074010403000900A8200430FE217401040300090004000038000700000403000900080000380015000004030009000C00003801030200040300090010000038010702000403000900140000380C0C05000402008005FFF98720BBF88700BBF88700BBF88700BBF88700BBF88700BBF88700BBF80720BAF80720B9F80720B8F80720B7F80720B6F80720B5F80720B4F80720B3F80720B2F80720B1F80722B0F80722AFF80722AEF80722ADF80722ACF80722ABF80722AAF80722A9F80722A8F80722A7F80722A6F80722A5F80722A4F80722A3F80722A2F80722A1F80722A0F807229FF807229EF807229DF807229CF807229BF807229AF8072299F8072298F8072297F8072296F8072295F8072294F8072293F8072292F8072291F8072290F807228FF807228EF807228DF807228CF807228BF807228AF8072289F8072288F8072287F8072286F8072285F8072284F8072283F8072282F8072281F8072280F807227FF807227EF807227DF807227CF807227BF807227AF8072279F8072278F8072277F8072276F8072275F8072274F8072273F8072272F8072271F8072270F807226FF807226EF807226DF807226CF807226BF807226AF8072269F8072268F8072267F8072266F8072265F8072264F8072263F8072262F8072261F8072260F807225FF807225EF807225DF807225CF807225BF807225AF8072259F8072258F8072257F8072256F8072255F8072254F8072253F8072252F8072251F8072250F807224FF807224EF807224DF807224CF807224BF807224AF8072249F8072248F8072247F8072246F8072245F8072244F8072243F8072242F8072241F8072240F807223FF807223EF807223DF807223CF807223BF807223AF8072239F8072238F8072237F8072236F8072235F8072234F8072233F8072232F8072231F8072230F807222FF807222EF807222DF807222CF807222BF807222AF8072229F8072228F8072227F8072226F8072225F8072224F8072223F8072022F8072021F8072020F807201FF807201EF807201DF807201CF807201CF80700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D8F82720D9F82720DAF82720DBF82720DCF82720DDF82720DEF82720DFF82720E0F82720E1F82720E2F82720E3F82720E4F82720E5F82720E6F82720E7F82720E8F82720E9F82720EAF82720EBF82720ECF82720EDF82720EEF82720EFF82720F0F82720F1F82720F2F82720F3F82720F4F82720F5F82720F6F82720F7F82720F8F82720F9F82720FAF82720FBF82720FCF82720FDF82720FEF82720FFF8272000F92720D7F8272000F8272001F8272002F8272003F8272004F8272005F8272006F8272007F8272008F8272009F827200AF827200BF827200CF827200DF827200EF827200FF8272010F8272011F8272012F8272013F8272014F8272015F8272015F8270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A0008001003181C1003181C030009000020043080000000041700000005000E000C20FD00FFFF000000000002000005000E001020FD00FFFF00000000020500000300090004210430010000000403000900082104300100000004030009000C21043001000000040300090010210430010000000403000900142104300100000004030009001821043001000000040300090044210430010000000403000900482104300100000004030009004C210430010000000403000900502104300100000004030009005421043001000000040300090058210430010000000403000900C8200430040000000405000E001420FFFF00FF00000000000084000300090084210430010000000403000900882104300100000004030009008C210430010000000403000900902104300100000004030009009421043001000000040300090098210430000000000403000900A021043000000000040300090020210430070000000403000900602104300700000004150008000000000020280000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 2368 2368 0 00000000FFF98720BBF88700BBF88700BBF88700BBF88700BBF88700BBF88700BBF80720BAF80720B9F80720B8F80720B7F80720B6F80720B5F80720B4F80720B3F80720B2F80720B1F80722B0F80722AFF80722AEF80722ADF80722ACF80722ABF80722AAF80722A9F80722A8F80722A7F80722A6F80722A5F80722A4F80722A3F80722A2F80722A1F80722A0F807229FF807229EF807229DF807229CF807229BF807229AF8072299F8072298F8072297F8072296F8072295F8072294F8072293F8072292F8072291F8072290F807228FF807228EF807228DF807228CF807228BF807228AF8072289F8072288F8072287F8072286F8072285F8072284F8072283F8072282F8072281F8072280F807227FF807227EF807227DF807227CF807227BF807227AF8072279F8072278F8072277F8072276F8072275F8072274F8072273F8072272F8072271F8072270F807226FF807226EF807226DF807226CF807226BF807226AF8072269F8072268F8072267F8072266F8072265F8072264F8072263F8072262F8072261F8072260F807225FF807225EF807225DF807225CF807225BF807225AF8072259F8072258F8072257F8072256F8072255F8072254F8072253F8072252F8072251F8072250F807224FF807224EF807224DF807224CF807224BF807224AF8072249F8072248F8072247F8072246F8072245F8072244F8072243F8072242F8072241F8072240F807223FF807223EF807223DF807223CF807223BF807223AF8072239F8072238F8072237F8072236F8072235F8072234F8072233F8072232F8072231F8072230F807222FF807222EF807222DF807222CF807222BF807222AF8072229F8072228F8072227F8072226F8072225F8072224F8072223F8072022F8072021F8072020F807201FF807201EF807201DF807201CF807201CF80700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D8F82720D9F82720DAF82720DBF82720DCF82720DDF82720DEF82720DFF82720E0F82720E1F82720E2F82720E3F82720E4F82720E5F82720E6F82720E7F82720E8F82720E9F82720EAF82720EBF82720ECF82720EDF82720EEF82720EFF82720F0F82720F1F82720F2F82720F3F82720F4F82720F5F82720F6F82720F7F82720F8F82720F9F82720FAF82720FBF82720FCF82720FDF82720FEF82720FFF8272000F92720D7F8272000F8272001F8272002F8272003F8272004F8272005F8272006F8272007F8272008F8272009F827200AF827200BF827200CF827200DF827200EF827200FF8272010F8272011F8272012F8272013F8272014F8272015F8272015F82700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000038A483F58000000000000000040000000300000008000000000000000000000006000000080080000000FF01808000000100000000000000000000000000000000000000FF030000E5030000EA0300000A0000000000740101DE0100000000000000000000000000000000000000000000000800000000000000000000000000000008002028000002000000000000000000000000000000000000000000000000000000EFE1000000000000FE217401000000000000000000000000000000000000000000000000140000000400000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000001000000010000000100000001000000010000001F0000000700000000000000000000000000000000000000000000000000000000000000010000000100000001000000010000000100000001000000010000001F0000000700000000000000000000000000000000000000000000000000000000000000300000000100000001000000010000000100000001000000000000001F0000000000000000000000000000000000000000000000000000000000000000000000300000000100000001000000010000000000000001000000000000001F000000040000000000000002000000000700000015000001020200030502000C0C84001003181C000000000C0000000C000000010300000000000000000000010158026F0000848418620000000000000000000000000000000000000000000000000000000000000000000000000000000000A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A508000000C0014000FF1FFF1FE123FF1F18A25503D3A25D0018A25503D3A25D0018A2550320FF80003F040F0100000000000000003800000000000001000000000000000000000000130000001400000000000000FFFF0000040000008E0000000000000000000000050000000000000000000000000000000000000000000000F000000000000000EE000000980000008800000011000000000000000000000000000000FF0000000000000000000000000000000000000000000000000000000000000000000000FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 36 0 000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 4800 4800 0 01FE0100070708106F67666B6A6B716A746E6662646D73716B68696F6C6A71686D6B6A67726C6C6C6462675B746C6F6A6564656B70727078766D706F6D716E716F7370717577796F6E7766706F72726B736D6E706C6F7974717A726F7273737B807A776D72716E6A6C6F64717171736D78797476726F73726B6B73757A6F77766D696F727371706B677069666E767972787A77767271767E78706F716F7771706A646769625F5E526E73787175737278736E65767D7E76736D7371746E6E757F7B74757A7472707A7073736D716F72767D727D74797378726D6D757B737A746A7A7C7880808182826D7371746E6E757F01FE0200070718207670686A686D716C767373686C746F726B65676A6A6D6E7371666B767171726E676662616B696B6E6B6F6A6373737675706D767A73706D6F6D696E696A6C6D696D70737270716B7B8172706E70697870676A717374756C7E817D7370726F706D71686D6C6D737775777882807774777370716E6E6F717171767375757974757665636B686E6D7479827C746A6B71736D7174757870747C756C6968676153544A797977798073766E737771747C7B76757C747773737B767A79777A717971716E7470716F70757573766379757A7672716F6E6F7779827C747375747D827F7D807C747773737B767A01FE030007071830776D62656B6B7673716C686B6B716E6A71706B716E7469706E75706B736F6B6E6E6663676E63686D6C65676D686A6F6979777570747E767E71736E696766656672726D726E746E736F726E7571797D737575787C6D6A707079807B727C7467716C72686F636B717275787277767A6F716A69716A70767A6B79726B746B6D686C6F6C717075717975787D77777072767880776E6F7C6E7C7168626167615C5E497B736B74797A7870776F766F7C7F807E7F777E7A827177787C746C6D727979726B71736E6E656B6B72757F7775737774736C77757C76787675797C7F7E7C76877F777E7A8271777801FE040007071840787D6A70686D6B6B76696D6B6A717677746C707476756D6C716C6B6F736A6969656D696B6E757165645F616970697074746C75706E6F7173746E6C67726B746B75717073686B6C75796F757471737B7672727776697471767B7A797373766A6861696D72726D6D827E7A757C74717672706971746E6E717570727377797377717A6E7270766F6E707775737368747D7D756C726C747B74716C6A5F626060624D807B7A7778757273757A7975827576837F7F7679737C727B7A75717673737073797971786C6C6C7978707E7278626A78777171756C7770777D7D7E807A7D77907F7F7679737C727B01FE05000707185079736C65636A746C706D61605A6B676C6B6D6C666465676E6F6B7178717A6C716C6C6F6D6C646D67636367666969726E736F6F746A797A777B6E72726B6B726E71746D70707571737F7370776D73766D6E797578757270727872797471696F6D667272757768717C727A6F847973756F6B6C6E707C6F6F68656F707372757A6F747F796A6F746E717379776E706C7279717E7F70737178767174656563575A4B767D716D747B747874726D767C7D817675717B7E7776756F78766F706E6977787679786D71777678796F7A7373706F7271736C796B6F707A7D7D797E7D7D7B8275717B7E7776756F01FE06000707186075716C6E6973747D7173796E647075736F74736F706969687470796E6C6F71706E71787B6C6567676366666C6D676B6D7178726C6E6F70797677756E6D6A6B6B75716E79697874797A7C726E6F73746E6D767177716E6F787F7A7171736C68686D6B67676E6B767473767F81737E7A6F6C726B6F76796A6A6A726C7B6F66726E656C696E747B7C76777B7971716B6D707582777B73787870716A6561635C5E4C7879756E7879757B7E72746C787A79818388807675767571757273746C776F6F6F75757375787372796E78757572747C7A7370716F71747E7F7F747E7E818283838880767576757101FE0700070718707370686E6A747575756C6B6D666871716E6F696E696765686B616C6277736C727071646868666D646365686D6F726F73747176727073757B747071696E6D6A6B6C6768716D75747883796A7B6F70716B6B7C73787173756D7C7C7368706D6F6868667073716F6B6E7B838083757D73776B6676717070727173736767717374706A6B6A706C67747E80766F706B72737B7A7371737A78777570716963655A5E3E6972786F6A78747174726F747C7D817B78717A7972777977706E72746F6B747979756B73716D7975726E787573737B766D6B6E74797D73787A807984787F778078717A797277797701FE080007071880706E666D6A6E74736C696F716F696F6E696B68696B6A706B686B727579726C6D6B6F7076716D645D676D6F606F656A6D70716F676A746D6F79696E6F6C6572707575706F7175737782786F74786E6E746F7877806F666B70747D786F71676D626B64726F6E6F7A6F71778280757979796B6A727079716D6E6B6D6A6E70737677706E706D74737C7979767D79756D74797D7168706E767A696F696F776960605178797175787878797B647471797F777775737E817D78766D7475736C727575837A787D776C7075706F6D767178766D6C6C727A7471766D7979767D817B7C7B8575737E817D78766D01FE0900070718907072646F707C7574787C75726C7071716E6B66646D6C72717173757172726872707772787A716B6361626C6B6C6D6E756D6872716D6F7178706E73706C6C6B696B70686D7572656D70766D706E70767B757A7474787072717776736C6C736C6E6F6F747B72707475757672736F756F7870707673746C6D70736C72736F6D7069737378767270747377797A72697476777277807774767376726F6D68606058487573797680797A7A7E776D7670807C7E7D777B7978767774727579756D6A696C7476767276707479817575757373766969746E74747474758179827F807F7F887D777B797876777401FE0A00070718A0766D6A6D666B7A6C706E6F6565626771676C6369696E646E716F6F777266686F696A696F6669666B66656A6B7072736E716E746B69666E7375776F6D6D6C6C717771706A6E717272766D6F7477797D7C78717278766965787E817B697074666D6D706B74707373766F79717973717375706A6A71717275717071736C787876747572696D716E7379797172656271776D766F7D767B7379756F6D6D6464605A4F797976776F6E6C7872746B737D7F76807C6F757479787772757273796E75726E737268716F687275767276777970717178746D77727477727D7D7B807D8182837C6F75747978777201FE0B00070718B0796E5F585E646D6E696E65675C68696D6D6B776C6663636667646B70716C696C636B6E72696765666A6665686C7177757A757274676E7776736D737A766F686770706F6A71706D6E6C7671706C6D756F6C747377787069757C7C726B74776C6D636A707372716F7370797C7F786A767B716E6A6E75777B737A756E7278747A726B6B6F6B776A6E737875757571727F79807B72797271706B6F6673665E5C564A717D72796F77706F6D6C717782767B797B75786B7775767774646E747B707775706E7672706F6A6F6B7077756E6F726E737C767D767A767A7C7D758079767C7F7B75786B7775767701FE0C00070718C0766F706C7272757581787B67746F697271716E6E6D726C70676E6D706D6F757467676A696D6C676B73646968736C7475717C736B656E6A6D7673766E6F746F6C67746D737174686D76736C6E786E796D6F7D6E726E6F676E7C797469716A6C6F6E6A6779756E72767B7B7773737A7B776D6C696871696C6A6F7C75787278726D726F6E7570736D757F82737271777474766D776975757A747A6F6162615C59497076797B767C7776746D787F84817E7B777374687B77767F7A7978767B757476687074726C726B727A737B7A6E6A6F74716B6C726F7C6F787E797E867D7D7F88777374687B77767F01FE0D00070718D07370696E5D61656B746F6F6C666E6A67726F676B6D696B6D697076706C77706F6B6D6A6B70626E6D5C5E6B6C6C767074726F7570647077737075766C726A6A7170706E706B716C6B7970746B727E7B7070697F7D716F726F72777373776D676872766D697070767D7D7D7B7A7D767A6D6B64687064687269756F74737A74766D70746F6A797D7C727779716E716C76747D7A78706B72766A6372716B5F5A57466B6A6E6F75757075796D6E6B747A847D7D7273707C7A747974756E6D787470757171766763687977756E737A79756F7375727378727E757472757D7D787F7F867D7273707C7A747901FE0E00070718E07976707472747D74746D7D7A676C646C686871606A6E6C6B716C706B7A797371666C67706F62686B6966696474696D76756D6D676C6E79757571716F6E6F70766F7268746E717C757D65656E6A79766F6F746F7E78727974787B786C726F6473707162747074777A8276797A68747E776C686B696B6C7278806873717573746F7171636A7274726A727372776B7681847B7474757473747267645E666056544D6B686F6A6D767078706E747B7F7F807B7F7C7972797774797C73717271706A6B6F726F75726F79727070797B7478736E73716F6C78766975757B78847F7D7D827F7C79727977747901FE0F00070718F0746E696B6D6A706D80706F636D615F6C716C6A6C6E6B6D6F706C6B7672716F767167736A6F6C71736D6A6964676576747A6C726C6E6F6B7571726D69676C6566726E7371777771707A6E726E6B6B746E6D7573746B676D777C87737270726B696673737374747A72788A767974787670656A72717370716B67726E6E6A73767772667472706C6F6B787570736F6C747974747581767478706D696B5C5B5A5F4C7480827B7D7A75717D76737D7E7D7873757C7E7A7C7B7772786C686F777472766F79797475767579706E7A797C7974717673746C7676767B767A7B82747B8585757C7E7A7C7B777201FE100007071800756B6C726A6B68706F676F71636D716D6B6F706A696D656B696A6E72757976766D6D726C696B6866706775666A696A70767873776B756B7174726F6A6965646E757170746F74716F7E7674777979776F75717274717174777D857771746B746D706B60706B606A6F727A7F7C777B8079696871737372766E6F70706E716E6E776E6A736A6E6F7C6F6F6C7974746F70767B707578747A736F6A6D666B6A625E477270777A7377716A6B7A70767A837F7576717880747C796E787373726F6B7C75757166717071727172717A7874696E7473737173787471737B6C79887C7F7E8276717880747C796E01FE1100070718107A766B766F6C716F786E776F6E6F6E75666A707067696B696E676E72786F6E6D646D6C6B6D6D6B6C6C6B696C73696D6A6E7573726C6D6C6C6D6C7479786D6E686A7166726E756C6F82767474716A73746B7677776E7274737473746F7A6F636D5D6B6A736C737474756F817D7F76767775647978757F786F6A706B6A706E697070766F7574747C797B79726E7178767070737977756C696A6F686B5C6459624C6E7B7B8181787C737A78737082867F7E80767873777B7B7A746E716E756E737679777279707A76766F6C808081716B6B7273777A7D75727A857F797C7E877E8180767873777B7B7A01FE120007071820747267726D717873786C6A66686B7271716C6C747167666C61666A756E67686D7270706A71696D726966646A746779747D736D7070776E7873716E726F67736A6B716F746F6F7776786A697275746C70776F7171747273747C7C76717069696E62656D766F747B73758179787771796F6D696B776B6D7674756C6F727A7A7C72756D6E7974797370757D787474726A78726C7070707075706D68656A6D5C5E4D7B7C71786F727A6D7175747079827C7C7F82806F78757B73786F75747D74797A78786F6C6E71676C6F69747877726F7571757A7976736C7674717D7B817D7C847F82806F78757B7301FE1300070718307A716E756C6C7376746E6C70646B6C716A6F70736B68726B696A7A79797A786A6B676F6767696D66676B6768676B73727674786A6E6D6F726D6A7A79736672696A7170716E726A6F726F777578727B7C7471797970726C7E797878746D6A6B6E6D6361666E707473757978786C6469736E6F6C72716B6A6C6D697876787F73796E69716E79727A727B7D74746C6978817B7C7C777671716573726B665E5857487A6E7173737477736F7174747D80797A797C7F7279777673767B77787E6A6A6E6E7671717279736D7C6C7971737E797C7170716F74766E6F7B7D7383797A7B82797C7F72797776730101000007071840746D64736B6D6D6B68656D6A666E6F6E787670736E6F6C73746D6A6C6F6E656E6C686C6D666E6B646A5F6E64746B706870757074696F6A766C77737272696D6D69666A7564786F6E7F6F736D7277747175777871726F6F727D7973727363676A71746B6D656F706D77737E808076726F6A68686F727477756A6A747A7E75726C7472757878797779787D7A73706873797C6D6E7B78767870696F65635A625D4E736D6F6F726A6971796C757C7979767C80756F767E797670747675776E6A6E7B7374747075746F777F7277707072716A75716D75807A706D787C827A807A858280756F767E797670 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 2368 2368 0 00000000FFF98720BBF88700BBF88700BBF88700BBF88700BBF88700BBF88700BBF80720BAF80720B9F80720B8F80720B7F80720B6F80720B5F80720B4F80720B3F80720B2F80720B1F80722B0F80722AFF80722AEF80722ADF80722ACF80722ABF80722AAF80722A9F80722A8F80722A7F80722A6F80722A5F80722A4F80722A3F80722A2F80722A1F80722A0F807229FF807229EF807229DF807229CF807229BF807229AF8072299F8072298F8072297F8072296F8072295F8072294F8072293F8072292F8072291F8072290F807228FF807228EF807228DF807228CF807228BF807228AF8072289F8072288F8072287F8072286F8072285F8072284F8072283F8072282F8072281F8072280F807227FF807227EF807227DF807227CF807227BF807227AF8072279F8072278F8072277F8072276F8072275F8072274F8072273F8072272F8072271F8072270F807226FF807226EF807226DF807226CF807226BF807226AF8072269F8072268F8072267F8072266F8072265F8072264F8072263F8072262F8072261F8072260F807225FF807225EF807225DF807225CF807225BF807225AF8072259F8072258F8072257F8072256F8072255F8072254F8072253F8072252F8072251F8072250F807224FF807224EF807224DF807224CF807224BF807224AF8072249F8072248F8072247F8072246F8072245F8072244F8072243F8072242F8072241F8072240F807223FF807223EF807223DF807223CF807223BF807223AF8072239F8072238F8072237F8072236F8072235F8072234F8072233F8072232F8072231F8072230F807222FF807222EF807222DF807222CF807222BF807222AF8072229F8072228F8072227F8072226F8072225F8072224F8072223F8072022F8072021F8072020F807201FF807201EF807201DF807201CF807201CF80700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D8F82720D9F82720DAF82720DBF82720DCF82720DDF82720DEF82720DFF82720E0F82720E1F82720E2F82720E3F82720E4F82720E5F82720E6F82720E7F82720E8F82720E9F82720EAF82720EBF82720ECF82720EDF82720EEF82720EFF82720F0F82720F1F82720F2F82720F3F82720F4F82720F5F82720F6F82720F7F82720F8F82720F9F82720FAF82720FBF82720FCF82720FDF82720FEF82720FFF8272000F92720D7F8272000F8272001F8272002F8272003F8272004F8272005F8272006F8272007F8272008F8272009F827200AF827200BF827200CF827200DF827200EF827200FF8272010F8272011F8272012F8272013F8272014F8272015F8272015F82700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000038A483F58000000000000000360300000300000008000000000000000000000038630000080080000000FF01808000000100000000000000000000000000000000000000FF030000E5030000EA0300000A0000000000740101DE0100000000000000000000000000000000000000000000000700000000000000000000000000000007002028000002000000000000000000000000000000000000000000000000000000EFE1000000000000FE217401000000000000000000000000000000000000000000000000140000000400000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000001000000010000000100000001000000010000001F0000000700000000000000000000000000000000000000000000000000000000000000010000000100000001000000010000000100000001000000010000001F0000000700000000000000000000000000000000000000000000000000000000000000300000000100000001000000010000000100000001000000000000001F0000000000000000000000000000000000000000000000000000000000000000000000300000000100000001000000010000000000000001000000000000001F000000040000000000000002000000000700000015000001020200030502000C0C84001003181C000000000C0000000C000000010300000000000000000000010158026F0000848418620000000000000000000000000000000000000000000000000000000000000000000000000000000000A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A508000000C0014000FF1FFF1FE123FF1F18A25503D3A25D0018A25503D3A25D0018A2550320FF80003F040F0100000000000000003800000000000001000000000000000000000000130000001400000000000000FFFF000004000000FE0000000000000000000000050000000000000000000000000000000000000000000000F000000000000000EE000000980000008800000011000000000000000000000000000000FF0000000000000000000000000000000000000000000000000000000000000000000000FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 64 36 0 000000000000000000000000000000000000000000000000000000000000000000000000 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 4800 4800 0 01FE0100070708106E6F6D6A6A6E6D716F736C6D69677474706B6F717369686E6D716C717272686E6973707176676D696765677370707572736C6B6B656F6F797276787C7B71676C6A69676C6F726F71817A71797378736E72746E79726F6F757B786A6D76716B6C69746B716E726D7074727671717272756A6C716E797B7C7A766A677371717670736E747572797873807679776C74747C7873767574767172736D6C6764605F4B76727C837E777876837A756D7D7C7E7D7B70787578806D6F74686E7878706E756F73677072726F6A76767D797A77737070717575747A6E71797780807F7C7F837B70787578806D6F01FE0200070718207C726B73696A6A747A706B68686B7574707166626D6B6A6D6C716E7573746B6C6466736E686A6D66656C716D6D646B6F70726B787771706D74767A7373706E6A6D6D6A6F6E72716A7C6E727972726C686F777573736F6B79817E7875746C6A6F69666770726E71737C7E7374707C77746E6E7379716D71746F6B6E747674736E6F7171686E6C79777A7B77786C6B727870777E79807474766961636862615C4B717C73787B72767B7870717B777A7C787C75766F75787E7B776F737B7770686A757A70716F787A7378757878776B6C6F716E6E7872736F707E80838B817E82897C75766F75787E7B01FE030007071830797775717174726C7369716A6C78696B706D6F6B6E6B6F716D757C796B74717767686F6163637570696A677071707070736D6E6A696F6E6F6C666D74726F6E6F6666646670716C7675726F6F70696E747279807F7371757678787270696369706B6E6B6E70796D6F7C7C787A787D7B7F726C68706D766E686F726F736B737A7A74706C727276787B7477746E6970797679737977737875727167626964535949716F747B6C6B736F6B716A6E8280867D76777B75767A767B7575717170746D7A757170726974767B7973796F717573716F747576707070787D75777B7180888876777B75767A767B01FE040007071840796E6A6F606D716E7474676D6F707A776D726C706D686B6D666C777971706E75665E63606F6A70676E67677A736E6C696C7468626C6F7B6F6C7073776D75606D6E69697072757072756C70767170727B7B74767C6B6E67747E747771716E676B6872696F6B697071777A7A747571747D786D666A74716D7576747171697178717377766E72757178797A6F71726B7B6B72736E6A7B75757875746975635B5A4B787A7B7A7A7C7A71756D707D797A847F706E727879797B817C7A766E777275777475767671707C757970777575726E7371716C767B747077757479807C787F83706E727879797B8101FE050007071850776D656A6A6D746E706D706D646B676B6868666D6668706E6768686C7B7C6A6F736B646D736D64626B69696A6F6F6F71716D727C746C73787070706E6C6F736D6A6D68626E7175797779767A726E737471706F746B6B71707E81707068656E69626868716C766F70777172777772727379716F7B71716D736A6C726B727573706D6F7077716B70807D797876766D76757C797480787371726B676261655E6046667071736E6F7273747073696A76828277757677797179716D6E6E7477776D676F737172696E7377786B7D7D766F757572696F7678766D71777875817A848081777576777971797101FE060007071860786B6C6E656D747175666A69696B69796C646468676672746A616E706D706670696D6D717768676864626E71757471716B73706D6E677171696B7074666E6D6B78746C69686E6D6E766E6E8072776F756E757A80756D6B7178746B71726F6E736A6B71776B6E707D7F78787E747C767B706C73746D6A736E736A74726B707475676571746D6C72757978756C6470797773737D7A707A7273706C6B6B6653584C7B7B756F747073757B6E73717C8182857E747B6D7D776F777B76776C6B6B72776C71727B7578766F756F7B7975796E6D69767B76787B7175797679807A857F857E747B6D7D776F7701FE0700070718707472696965717067706A6F706864726B6D71676B69656D6E6B6E79716E706E6F686769676E6F606465686B6A7364796D717975756A777273736A70717278766C69656B6D69786B7476747477716A7475717273786B7479767B827B716B6A746F6D6C6B6F756F6D6F76847A76717E7C8271676D69736B796F716773707272776E6A726566706F6F78787771747273757075747676757B766C6B6866646355554B727274706D6C736F6D6F6A71757C747E78707877757C7775727676716C7076756B7476707876727574767C6A7673756E6F71777B787B71777B7F7C827C78828178707877757C777501FE08000707188075726E6E646774736E6B6F6A696C6F72756A6769676061656B6C766F6E766C6E686A6E66636F6F646B656B676E736C78776E6D6D6F6A70717173796C71706F6C6F6A646F70726F71747575746A72766F6D75747675696A6F7D8075737B736F6D6470666B6B73727878787C7E7975767C6F6F7A6F70756C6E63756D707074706C74716E726F6E6C74757973767370717279737B757A837B7278695E6661595F5180827C7E76766E747E736E6F7A7C7A7C79747D7C767A7C72757B78766E6F737C6C6E72786D6D71787771767267726B757672787E75796F726F6D80817C7E787779747D7C767A7C7201FE090007071890736C686A676C736E72696C6F71716A706E6F6E73706B70646368716F7371706F66676B6E6B6866706C6A6B7772807769706D7080707973706E716F7473626A62637260716B7170777873727D6F7072716875727672736A7C7C8079677879696664676D74707772797277757D767974746C6A6F6B7E766F746F756C706E776A71766F796A6E706A7678786F71757479737A6C6F767D7C7A73766C6A6A6561584671797C8A7C73707D7A72727E797B7E80807A6F797C797079787675777C7075717177676766707475766C7C7A7F776E6E73787572767873727E7A7B79807D7C7E807A6F797C79707901FE0A00070718A07873606A656C75706D63696C666D7178776B716D716C5F6A666A717577716D6D66636E6B696D6D6A6A6872756F67696C68627273767067726D74797B717672665C60726A6D716D737170746F717976737A776F7B72777672747875707175666767737878726D7577737B777B756F6C8180716B6E717372746D6F6A77767A747073736D74746678777A7D786D6264737D77736E75777970766862666659636253797F80807F767E797F7B7A788180767474717A81777B77807A7B7277716C6E7978786D7B7B6A71737370797D77746A6E6E6E7C7676756E787D7F7B827883828574717A81777B778001FE0B00070718B079716A676B7174727769736F6F756A726B706B6C706E6A6D6D69727778736C72646B6E6066646C60646F75716D6A69706C6D6F73726B72717272716D736A70787074736C65766F6F77726A6D6C797272777A70766B796C7C82837A6D736F6B6C656A6E776A6D6F7A717581797B7E7879796F70786F6D6D6A6D6A70706B74707269707779716D6D6A7A75796F6D6F7A75767E78747377716F6A6B686A6564655374747E81757B7878777970758079776E767F7E7D7D7D717A7A787477716774736D7C78726F77757A70687674716A706E6C6D75756F7A727A727677797C7F8187767F7E7D7D7D717A01FE0C00070718C0716A6B7771727372756E767265666B7469736A6669656B6B706B726F7A6F7270706C7072726D6463625F6C736F6C6A7172796E74656C7375797778746F706F66627074736A716D6B78797C786C6F7D776B757177706E72767B7B71666E6B64686771667B6B6F6E7770777C7B77777A776E6D6A7373736B65717277716F75726C7773716F6B6E6C77747D75807D6D6F7A7B73727977746F706C6D6A6E65665D496D6E7A7472686F6C777C6D74757D7D737A736F797978777778726F77766D6F787C7774726E757679766A6B75766B6D736E6C69787379797B7C7B81847A79787F7A736F797978777701FE0D00070718D0737069726C6D71716C66727663656D747A6D6968706C72716B6D6C7071727176736D6E6B7166666C686A6378727074687870706E71736F74746F7174706D6D6C727166746E756C787F70736F727376737371747B746671727E787271796E6765636F6E7471706C72737D797872747578776E6A6B696F6C6C7077746E707679726B6C727177757876757E7A796C677376756D75757575737272706D6B60675B52727C7780727A766E6F776B6E707E797B817F7D7C7A74737073727574766D6A717A78767468666F6E73707F706C71726F766D6D74767573777F7B79817E7C7B82817F7D7C7A74737001FE0E00070718E07D6A72756B6D757479716D706C706B6978737478736B716B736F79787C746D6C676571717671746A6666677A6D6E6A66716B716C6A6E6B796F736E6F706B6A67696873716F6F6D7A73706E776E6E77767873777873726F797B7E6D636E756E7269716D706C6D6C6E7A7D7C756C79757F71696F706E6A6D74716A717B75777B716C6C7071726673747C8475766B6970797770706F70767A676C6D6D6D6C62524673756E716C6775767A746E727076767C76767777727776787E7770777C6F6D757371716D716E7675706B7680796E76706C6B6F7E7A7B7C847A787A807D7F8684767677777277767801FE0F00070718F07A81777E706C787979766F77726B6D6B736D6E726B7474736D766F6F7D686567706569716C70726D6A6769706E777673766B7874686672756E6E6C726A73716C686F6E7A7378777279706E6F6D7577796A706E7876726E70776F747877746F726B68687072787A73726B7B7A6F6D7477726D6A71707873717A756A727C6E6F72727672777072797271786A6F6D747D74747675737670736E636C68675E5753496C7473776C70707578736E6F7A7E7D808078777579786C6F77746E7A76716F73757471747070747185757172706A696A6C7175746F77737A757C737F7B7C78838078777579786C6F01FE10000707180070766F7F7476797B8377716D676A677D75737570666E6C686E6B7275737576786D6B736C6F696D6B6B636C756C6F6970736E79736A7C6D7477707372736E66696A726A7169666A6D73706F726B6E72787076776E6D6F707A7979727079706A7168767471656B73807978756D6D737C8071666C76716C707572676E7779737474727071726F71726C727C6A6D6C6771797878766F7373767670756A635B605E5374747579787E767972666C70757C7977736E73787D75777C77756F747477737B716B726D7172796D7B6F7872757175726C6E6F7377727679747D7981797C7D83736E73787D75777C01FE110007071810766B6262656067676C6E6B65726A6D756E6E6B646B6366756F6C6764736D6F6F696A6E666E6C6B6E696964686B6F6B7075707A71747673736E777474686A706D6D6964636D756F7370766D75786F767374736B78726B63777C8073726D6E6D656B6A6F73676D6D757B877F7B79787A816F67717477646E6D6C6A6E706F71796D7978717275707574737674776568737D7673797B777B78766E696B7564635548737B777F7C7C7C737E6F767181808183827D7A797B7470817E777977766E6F7373746E7274737275776F73757F7A6C7373716E7B7274747273737C8281837F81827D7A797B74708101FE120007071820766E6B736A6F77716F696C67656C707875776C6D69696C706D686B6F6F76647374716E696966645E6868727569706B7470737171656A7273726D7C6F6A6F62696A746D6C686D726F737476756E696E776C7274737175777A827C73737175676C6A6D72746D747271767A7C83776E73786D6E676B7271746F73716E756D7A696E746C717F777F7270747D6F6E77777A797276746F73767368716C65646757594D6E767C707371756B7A7870747E7C7D83817C8270777A737679766F6E697273746A6E706E6C6F7374796F7D7C7973746C756E7071767D73737980777A857C7C82817C8270777A737601FE1300070718306F6761756D6A727477756C6B67716F7471746B6A5E6A70696B6E6B6866736E73756D686D726E6F6566636A7173726F747078716B6773747F7C7974716A676B676F736E6673806E70746A6D70646D7E736B6F707F7277757B797D726F6F736C6670717079787778747571776B726B6D736D6A6D76716F6B6F71697271707674767D707170727773737379796E6A6F75717072777A7175776A6B685F635F5E5E496C686F71726C716D71687074777B74777579776E78736F777472726F716E7A84776F6C79756F5F6B716D757C78797577757171767A74727C7F78717C788181857579776E78736F7701010000070718407E746F6C6A7076746E6B6A73706E6D6D6C6A6D6F6E6A6B6666777A6D71736B706F656D6E6E676C676E656A746D74727676727272616D6C72697870707071696E676E6C6F6F776F7174796F776C6E7767717479726D69697785827579767266696C6F6A656E776E807881796F6A7377746F6E6871716F6D6E7B7C7977717D717275716966716F6A6D807F7A74686D7B7B747E78757C74777774626D735F5A554276807E7E786D7877817A77727C7F7D7B817C7C75777775777B7C73767574707A72767477726C6F6E787479727570747971706D7370777B747B7479807F758182817C7C7577777577 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2903 2903 0 02F000000003000900042004300000000004030009001820043000000000040300090020200430080080000403000900242004300000FF0104030009002C20043001000000040300090040200430FF030000040300090044200430E5030000040300090048200430EA03000004030009004C2004300A00000004030009005420043001DE010004030009000021043000000000040300090004210430010000000403000900082104300200000004030009000C2104300100000004030009001021043001000000040300090014210430010000000403000900182104300100000004030009001C2104301F0000000403000900202104300800000004030009004021043001000000040300090044210430010000000403000900482104300100000004030009004C2104300100000004030009005021043001000000040300090054210430010000000403000900582104300100000004030009005C2104301F0000000403000900602104300800000004030009008021043030000000040300090084210430010000000403000900882104300100000004030009008C2104300100000004030009009021043000000000040300090094210430010000000403000900982104300000000004030009009C2104301F0000000403000900A0210430040000000403000900C0210430300000000403000900C4210430010000000403000900C8210430010000000403000900CC210430010000000403000900D0210430000000000403000900D4210430010000000403000900D8210430000000000403000900DC2104301F0000000403000900E0210430040000000403000900A0200430EFE100000403000900A4200430000000000403000900B0200430000000000403000900C4200430140000000403000900C8200430000000000403000900CC20043020000000040300090050200430000074010403000900A8200430FE217401040300090004000038000700000403000900080000380015000004030009000C00003801030200040300090010000038010702000403000900140000380C0C05000402008005FFF98720BBF88700BBF88700BBF88700BBF88700BBF88700BBF88700BBF80720BAF80720B9F80720B8F80720B7F80720B6F80720B5F80720B4F80720B3F80720B2F80720B1F80722B0F80722AFF80722AEF80722ADF80722ACF80722ABF80722AAF80722A9F80722A8F80722A7F80722A6F80722A5F80722A4F80722A3F80722A2F80722A1F80722A0F807229FF807229EF807229DF807229CF807229BF807229AF8072299F8072298F8072297F8072296F8072295F8072294F8072293F8072292F8072291F8072290F807228FF807228EF807228DF807228CF807228BF807228AF8072289F8072288F8072287F8072286F8072285F8072284F8072283F8072282F8072281F8072280F807227FF807227EF807227DF807227CF807227BF807227AF8072279F8072278F8072277F8072276F8072275F8072274F8072273F8072272F8072271F8072270F807226FF807226EF807226DF807226CF807226BF807226AF8072269F8072268F8072267F8072266F8072265F8072264F8072263F8072262F8072261F8072260F807225FF807225EF807225DF807225CF807225BF807225AF8072259F8072258F8072257F8072256F8072255F8072254F8072253F8072252F8072251F8072250F807224FF807224EF807224DF807224CF807224BF807224AF8072249F8072248F8072247F8072246F8072245F8072244F8072243F8072242F8072241F8072240F807223FF807223EF807223DF807223CF807223BF807223AF8072239F8072238F8072237F8072236F8072235F8072234F8072233F8072232F8072231F8072230F807222FF807222EF807222DF807222CF807222BF807222AF8072229F8072228F8072227F8072226F8072225F8072224F8072223F8072022F8072021F8072020F807201FF807201EF807201DF807201CF807201CF80700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D7F8A700D8F82720D9F82720DAF82720DBF82720DCF82720DDF82720DEF82720DFF82720E0F82720E1F82720E2F82720E3F82720E4F82720E5F82720E6F82720E7F82720E8F82720E9F82720EAF82720EBF82720ECF82720EDF82720EEF82720EFF82720F0F82720F1F82720F2F82720F3F82720F4F82720F5F82720F6F82720F7F82720F8F82720F9F82720FAF82720FBF82720FCF82720FDF82720FEF82720FFF8272000F92720D7F8272000F8272001F8272002F8272003F8272004F8272005F8272006F8272007F8272008F8272009F827200AF827200BF827200CF827200DF827200EF827200FF8272010F8272011F8272012F8272013F8272014F8272015F8272015F8270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A0008001003181C1003181C0300090000200430800000000405000E000C20FD00FFFF000000000002000005000E001020FD00FFFF00000000020500000300090004210430010000000403000900082104300100000004030009000C21043001000000040300090010210430010000000403000900142104300100000004030009001821043001000000040300090044210430010000000403000900482104300100000004030009004C210430010000000403000900502104300100000004030009005421043001000000040300090058210430010000000403000900C8200430040000000405000E001420FFFF00FF00000000000084000300090084210430010000000403000900882104300100000004030009008C210430010000000403000900902104300100000004030009009421043001000000040300090098210430000000000403000900A02104300000000004030009002021043007000000040300090060210430070000000415000800000000002028000018005201080005000A00FA001E00C80000009F003800000000000000000003FFFBF9FCFDFFFDFE00010000030101020605050605080A0609090608050403040305070709050403010202020202FF00FF00FBFDFFFF01FFFDFF010201FEFF01FEFC00FF01010000FFFF04030001FE0202030300FFFAFBFCFFFF02FF01FFFEFDFFFEFBF9F9FCFCFCF5F3F8F5F5F5F9FBFEFCFAF8FCF9F7F6F6F7FBF7F9F9F8F8F1F6F9FCFEFCFE00FBFEFCFCFCFBFDFBFCFAFCFA0102FEFEFCF7F4F4EDE1D701040304080B090909050608050300000100FFFFFEFDFDFCFF02FDFBFCFAFCFDFFFFFCFCFBFCFEFF00010B0907060306080706070808090B0D0E101515191B200100FFFFFEFDFDFC8080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 2368 2 0 0000 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 61440 61440 0 01FE305A070718006E6C6C706D6A6677777279706F6D75727170706B70727078746F747F75727274757A7D717C7B7E777672767681868A91918784868DB1D7FFFFFFD8B27D54413B3D486A8EB2E7FFE5985A3C3D557CBFE2D0A789603F282520363E302B313435362E33383B374344555055575B59595B5E5B5A606365635C60666C626A696666696B676C6B696B636870706A686C636E727676747877777970706B677061615F4A707A8D969196937A6C5B464248525D6F8894989A837E76707272747C8D84898C7E81788285868E8D8F6C8F9594898C918C847B85818783818D8B8A848A8A84878894989A837E767001FE315A07071810837770726D6C777B7C73716A6871757B7C747079737374727473787E7E7975747A7B73737F7580737076777A82878E8F9185827B91ABE0FFFFFFE1AF7A543E333C526891B6E5F7D8A55D3B314476BFE7CFAF907452351F25283B382D2C2D3030313A3E3D383D424B4D5D56585C605D5D5E56545960605F5D5D61646A6568666264686F716C5F67716E6B716A6F6D7E73797374777270727168615D695A5A5F4E747E87939694958C89654943444A5C7587919798867C716E6B72758387877C837E787B7C87858A9194708F918F8B888A88828986898E848A8D8F8B8D848A8E8D87919798867C716E01FE325A0707082085796F6D696C7575746E746B686B6D79746D6B7A6F73737571737A7E7F7979707274767F8581827B7772757E8787869497847C7381A1DEFFFFFFDEB3794D3E2F3F536D8BB6DEFEDE9F5A3E3C5681C7E7E1B9966947301D2131352E35332C2C2B2E3537393C3B3F4347585B5D4E56505F59505E5965615F6065565E68676A686C6B6F72706D676C6E6E726E7173717177716B6F727471706D6565656A68625A4B7279848C8E96938D8458503D404E61758A8F918E8A76756D646C817E8D8481867D7B7B827B8290969B71938F9388898A8487878A8D88878A8A8D8D8E8489878F8A8F918E8A76756D01FE335A0707083086777379707D727574777677727A737871746B686D6E6F6B747B818084807B7773787D798588827C766F777F88848D93A08D747580ADDCFFFFFFE1B078523C37384C6F94B8E4FFE5A050382F4688D6F0E3BC98724E2B1B222830302F2E25262A2E373A3B3A43454B4F4F4E545550505557555657615F605F5F64645F5F736C6B6363605C6A686C6D6C6C6C6E6E6B6E7072736F70707172636A646A6F6656594866808F9A939290867E644F434C595D678A959188877E716C6C6873717D848D877E7B787C818685878D65889391968E8F8D87888F8A88828C8D8B898A8B928C928A959188877E716C01FE345A070708407172696A666F6E71746F6D6A656F746F736C6B6F6970757A6D797476807D787F70777F84818286847B6C7A7B868D999D9A897E6F80A4DAFFFFFDD6A8774E31303C547B9BB8F0FBE09D5C3A314479D2FAF0C89B734C3118222D2F2B2F321F29242A2F323C3435434A45465357535B5A565654535E525B615A62666B67646D696A655C68686B636F687A75686D67647B76746C7374707A6E6C74696A646E5F5B4A778B949EA2A3978C8768533A3F555F7192939D9A86787871636F78818B9184927C7E787F84888F9197719391909290959688858A8C8E8D8B8F848C8E898A8D8D92939D9A8678787101FE355A07070850766A67706A687270706F6E6C656D67706E6D79746B66686E767D80808081797B79787B7D7D83817C7A72758B8E879096978A7E767EA9DAFFFFFFE0AC7B4A363131536893B7ECFFE19B543032568BE5FFF1C0A5804F3113252D31262435271D1D26293239363E3C3E46515051534C506356545A54525E575654575E625F616C6968676E696D686F74717C7871696C75685F677473727978676B6867696B645A4E5D7487A09AA09186755F56413C4E5C728D9D9F8E837D706A666A72858E958B828588737A80888C8D8F6A9397908E8D8B8F8B87888A8B8C8E8F878C8E8C8C90878D9D9F8E837D706A01FE365A070708608173676E6C6E75787B757B716C7979736F7A6F77736D767A74707B7A7A7B797976797E88898986837E757680899299999B847C7780A8E1FFFFF8D7A4704B3A313B5378A2B9E5FFE59F5E35344B8BD7FFF2CDAE80512F1B182F36353029252626342D27343D363C424251505751514A5B4D5458545D56575663635D6B59625F6A615E5E656C6A6871777A706B6568756F6F7273756F776F686964626361585C4A6C778D94939B92887666433235465A6B8995ACA3967A706D69656C78878B908D727578827E929B9C9972948E99949493898786908F8F8B8C8883809189838A878995ACA3967A706D01FE375A070708707B746B6C67736F78707A7768727D7A7370726E67756B757D7D7B777E797F737B7777818388918C7F776C757A83929A9E9E85766C809DDAFFFFFFE9AF77472B3435496291B1E0FFF2935B413C5794DDFFEFC9A181532A19223338332B2D221F1F202B303434353D3C3E4F484D4D544D5354514E5F60605253666E69626468625F66645F6D696F697471716B6A736C716B6B68716E7472756E6C72716461605C437A89969EAEA497968273533F454B57748B9AA29F8679726A6B6E6A838F998D8A8178787C7985959A97618A949793928E978D938F888F8B8D8E8F858C889593918B9AA29F8679726A01FE385A07070880706E6D6E6A70776B71676F6663746E6B73756E6C6D6F6F7579757C8A88817C7C6E6E838C98938D837369717F889C9DA69C89827B7DA6DBFFFFFFCFA77649312C38476894B0DCF2E0964D30305892E7FFFACFB4995F250B1D302D2E2D27221F2B2B2630322E32354148545258555A545C574E50515C5655534D61626B66626560676164686B6C726D6D666B675C686D807974726D797B7A6D6A66605F61545B4B697C9B939C9EA49780673F3436445771949BA292887D716975786E7B8E8A8A877673717C828E919FA163899D92978D8690908D988F93858B8C8C9193928F8C8A949BA292887D716901FE395A070708907A66616A726D7277776F6D6C60716A6F746F78747274797678797987847B7C786E7A8784949792867A75747C8C8C9695988B7E7B7CA1DCFFFFFFE2A06F48332B3C3E68A0B9EAFEE99E572A2C4E99ECFFF7CFBDA06430172333302F2426202128312D343A3933383535444A50474C50574E4B50575C51585B5B625E645E6B5D6C65595A6366666B6B69767B6D63686D6D74746A726F70706A6D6C6D72645E5951788893A8A5A0A398806650383F4B5874939BAE9F8F8A777961626E828C8C8E8A75827C78858E8898A063819898978F8D8F8C91969894918C8E8D8690908E8C8F939BAE9F8F8A777901FE3A5A070708A06B69586862666D6467626C6A656A726E6D73737570726E7675797C84877D807F787D7B8B97939789756C79808C979B9E9A887373769BD2FFFFFFD9A971423326314D67A1BBE9FFE79F542A2E508DDCFFFFDBBFA36830151B2A424035211916161E29272F2B323D424144494C52474C494848565357585A605962626968665F61605D5F5F62686D696E6F716B7070736D67677572756D6E6C686866685E695D47607A95A7ACA4AD9D836249363C47597590989F9C977A706760646C858D8D8D85736F7081848F9499956297949D9793949D96918E8C8C8A9695908F8C908A929390989F9C977A706701FE3B5A070708B072766F74756A6E6F75777671636A6E6D7273797680737576797B808B967D7F78757D8189908B96877C716E8A91949A9D9D8C776D7CA4D5FFFFFFCAA46F3A2D28364C6D92B9ECFFE59756302A4B8EE6FFFCE3C7AC663112162E4736342D1B201D2A2B29312D31403A3E3F3C474553545244414F4E58555D5A5D605D5660686060615D63636964686C7A74666D67676D73746E696F657276726E6F6C6F645B594A7B8992ABAEA4A39B865F422E454F597398A7ADA18A837E636269747E8C9388877775777B7E889A9BA267949795919190948F9592858D939094899094998C959398A7ADA18A837E6301FE3C5A070708C071726E72747173717C7970706D756C70757174756F6F74767778908B90908583797977899BA8A186796B757D8A9B9DA3918E79656F9ED2FFFFFEDAA6704425252C496492B9EEFFE59F5D34375490E3FCF8DECFB7813F14202C4438302F24151E22292130353336383A404D503F464247454C4F51524B554C575D5B5963625E6364696664616B72766E6E686C686971726F6C73716F6F686863686F66655D6345738BA9B6B8ADA08D7D7145373D435C7D9CB0B2A49380756B6662657B919B9B8D807771818A918F929668909A9B97919A9588979B8E958F9192959291968993909CB0B2A49380756B01FE3D5A070708D06B6D6C746A70706B72716465686F6C7276707874786F746E767E7A86857E82807F767F98ABA7A1947C746F7E9596A19A97826E747399D5FFFFFDD89F6E452A2A334A6794B8E5FCDFA1503A335394E0FFF8E9D3B2713919162A403E362E1A161D20212A34312D2D3740414B49404C4C48464C4C4D5A59595453545B5D565E5E6362666860716770736E75696A6264696E716B6E6F6D6D6C746E6C646467625D446C8493A9A5A59A948B6F4A3C3D3D577B93A7AE9E8D7C716A60636F78888E8F8875757676808D9CA2A85E919E98969C989A8C96998A998B918D8F97998C898A8F93A7AE9E8D7C716A01FE3E5A070708E06863676668666B7074736B71616E7373686E6B7575696673828587988F888179767A8393AAB5AD927A7374888F999996908979676B9BD9FFFFFFD5A96C3A2D1D294C668BAEEBFAF09F502D294490E7FFFFE6D3BA86421D213551443C332119191721272B2F222E35323B4344414A494B4B3D49484C5556524E515A59545C6C5C5960635E676F72747D7A785F6D69676E6F6B6B6F6A676F646870736E6559524275849AAAB3AFACA28B6C4F373E45597799A4AA9E918371626366757E91978B816D746A737C85919C9A5F96A09B94979C91949A9C9593899196958F938491998F99A4AA9E9183716201FE3F5A070708F06D71646C6C6D6C716A6D746F727C6B7A76787C736F6E716B7A808191998B7E837D838AA3B7B7AB9D846F6B7C969CA3A9957E6C5C6891D2FFFFF6D9A0653B24282E456B96BCF0FFE399582933448EEBFFEDDBD9CD813F141E354B4A463C25162021282E33212C2535313A363E3E444C51474A4A575B4A5354545356575A5F5F6868716A6268666A6B6C6B69686065736C78706F6B6E6F7473696D646E655B534B6382A4BBB7B3B6A5906A46393D4A6281A1B2B1A49A85796664626C7F939E93857468686F7C8592A19C5D94A4A3B39F9C9B9B9CA0939C8E999594918F868F979AA1B2B1A49A85796601FE405A0707080070716563696E6E6A6D6D6B6B6D6F70716E6E7B78767172737C7B8F969695838781798CABB6BCB09A7A626E738A959DA09B866E586E94DCFFFFF9CFA166412C1F2C375D86A9E7FEE49E4B272C5094E9FFF8E2D2D68D491B253E58544C351713221D232D3A2825252D3138363E3E3F424B454041494E4F505B575C5A6255626366616A6768666369736E6E69696A646A716F6B6E6B7071736C686E6B6B645D584A778C9BB4B9AFB1A894644A353541537098ABAFA8938477665D5B7084949390867D746A7A8795A29EA45F8C8A94939996989B979D9B958B97A197979289928C9598ABAFA89384776601FE415A07070810746A656E697578777267766E6D6C716C6D75717B76726D7D7B858D9AA2968D8B787988ABC3C3B59D7468707F90A09DA194856F656893CFFBFFF9CE976235212430436B92BBDEF5D6934D32395199E5FFFCEDE6DE98401D1F435F684A38171B1918261923232423292C2829383B3B42443E34404C5451514D535756666264605E5E6565586265676967706F6D6B6771726A70757074726B676A68605F5E5959477290A5AEA5B2AC9F9171472E313D5081AFADB19A9B857A6C6A6D6B85929492896F666A7985899C9FA1558799979C999B9997959A9C9992959A99929599989598AFADB19A9B857A6C01FE425A07070820706A7878776A7579797275706C736E77787874736975737D7B878C9CA897897C767C8DB4D8E0B69D79656672909A9DA3977F63566190CEFFFFFCCF9E613823162B44678FAFE6FBE99858342C5992E3FFF9DDD6C889411C2D526468543D1B161B232A282719271F2731313941403D3B30323C4347464749525859605B57685E585C595C606A66656772737169676D6A6F75767173786E6D736C635B60595D56456E87A2B0B8B5B5A79366463F3F405D7B9CAAB0A499776667606169899695917C716762717A959FACA65E8A9895939599969D9A9E979A8F979AAE9B97909395939CAAB0A49977666701FE435A07070830766F68666F6A74716A706D71666B747874787479776E707C848B9597A09A90837D8599C3E9EFD8A37A5E5D758E969A9C8879605A618CCAFFFFF5C598613B232227355A8BBBE5F8E99A4C29285295E7FFFCEAE2D38E3F2028577A75593A10060B202B2725212722252C3235352B403B45343A40404D544E4350495C5756675C5B585D64606665646E7675706A6A6C726A666E6D767973716F646B6C6B58585548748CA8A2BAC0BDAA96783E2437455C7D9BAEACAD977E756F6B656A889493907A665E5D757C96A1A0AC609790909694A0907F979B9E9D90929A9B999F9794979D9BAEACAD977E756F01FE445A0707084077716B756C6C6B6C6B6B6B716A707B7D77868B867E706975768B93A3B6AE907C7E7DA2CDF0FFECAD7960546A8E959B9781755A4A5481C3FBFBE7C38E5E33231A27396287BDE6F7DDA34D2A264C99E9FFF6E3E8D893401936668E7F6B3B190E1B2C261F2022251D232C2F2A2C3E443841393A413F40444E514D4F52595C595D5B5F6360656A6C65676B767071656B736F665E6E76796B6B6E6A6963545C5C55477597ACBBC2C2B7A096774A32314451779FB1BBA29482756F646C778A9694957D6560636D7D8DA0A7A65F8B909E90969BA09D979F9B9B908A9E999A8F8E9E9B909FB1BBA29482756F01FE455A070708506F726C64606E6C6F75717372636C7277757C7C787870767976889EA9B4AA9F8D7C829DCEFEFFE4AD775552758D879192906B504C567EC3F6FFEFCE9D64321F1D193C618CBBEBFFEA9B4D201F4691E4FFFAE8DDCC913F1C35678A957549190B1F2B2F2A2D191E1E1B242A3131302F3B342D38303D404C4E44494B5659555D5F5A555D5D676A60646A717471675E606C73716B6F6C66716E616567626D635F5B4E7E96AABBC8BBBBB1A377502F353E4F7D9DB6C2B49E81756C695C718699928C7B725F646C82848CA4A45E8E8F97929CA1A49A989596A1969698969D9C95949D9C9DB6C2B49E81756C01FE465A070708606E68646C6A6B6D708075726A6A69707373777A7E787B7B7B7C8699B0BBB39889757E9FD9FFFFE3A86E54526D7F9495958C6F644F5682BFF7FFEBC7926235171121315981B4EAF6E5964E272B4E8EE3FFFFEAEED18E3B1E3468969F8E5B250B142B34281E131A1615181F2E30323638352A28404C484240454D4C56544F5758584E565D605E64646A7474706B63656E6C6D716B6E75756F68655D6663625F5A4F7C97AECCCEC8BCB79D7341343A3C567BACBBBFB0977F7D645F617A86979A93814E528D79829299A4A3578B9095939EA4A1A098A99595989A99989F9B9794919FACBBBFB0977F7D6401FE475A0707087077716E6C71757A69706870737777737A78757574756F73737D92A0B2B9BBA08B7A8096D7FFFFEDAD78534C6C848F90988A69584C577CC2F4FFE8C69363381B101C366685ABEAFFE1914528354F89DFFFF1E9E4D59B4721376B9AAC945D250D2132432B201910060B151824292B332D3635353F514C3E42423D464C5B575F60605C575B66665E676E6C6C656A6B6C776D6F6A706E676A6A6E615E5E5B645E5E437C97B7BCC0B7B0A69B6C472F353E527EA7BCC1B59683796B5E627987979A8F9B6F60576780949A9CA160969E99999EA59CA3A59E989B96959A9599959A9D969FA7BCC1B59683796B01FE485A070708807A736D6E736C78777F75786F6D68707A7C78787F82797077868AA5BED0B99F88727CA1E0FFFFE8AD7350536A8E90978E806C5548567DC4FFFFF1BF8A552A1915213B5E88B0E4EFDC9E4B202E5193D7FFF6E5DBD79C4C283872B3B99F5F1C0A1C2D38281C080F1E161521222F372F2C34262C363A43433A424751465151555E626064565364656A72676D67606560676D696463677B7277706469615E645E614B6D86A6C5C4C3BDB0A27544262E3E53789FBBB7ACA78A7A725D617D92BAA6968164545B688097A6A3AE51899A9E899298A2A6A7A1A29897999D9B919E9A9B94929FBBB7ACA78A7A7201FE495A070708906D73676A676964656F7476746C706E79787875797F77787A7C8F9CB6CBC7A8847C7CAAE5FFFFF4B57244526791909996857051464D7DBAFBFFF0CAA2602E1E1614265186A6D5ECE1963F25294A98E5FFF0DFE3DA9C4D2D3B7CBFD0A86622071C3B4A32261814100E12161C1C1D2B2A2C232E313C424447464548474D515253545B555A565C5F6465666968655A68696D6B6D6D70727672716F6F6C65615A5651728BB1BEC0C0B1A3925D41293035587EA1BFBEB294777581655D677E959692825A53636F6F8CA4A6A0598E9A97969A9FACA39EA2A6A5A1A1989B979B9F93929DA1BFBEB29477758101FE4A5A070708A07C706F6D72737A7A706E7373777472717984807F7C73707D7A929FBDD0C6A1937581ADEEFFFFF9B0674D4A6A88928A8D82684F4A547DBEF8FFEEBE94652D140F213D5E7CA9ECFBE49444222B4B8DE2FFE9E5D7D6944324366EBBD8BA762506294249301D121A0D0E0E1728312728252C272736403E453B4048484F4C48535157555C5D5D5E6469645F67655D64686D6E6762717373716C6D69636F6C665D5C507B9FB4C4CFCFC3B09F77423031334D878DAEC7AC9D8B7A715D5A6587979B907F5E535C647A8FA1AAA8619099999BA6B0AC9FA7A49E9398979EA599A3A39D9C9F8DAEC7AC9D8B7A7101FE4B5A070708B07A6F6D7067676F71757377736F6C73727E7F8581807372758496AAC7D4D2AE8D757AA0DDFFFFF3B16D474E6176888E8A78634F3F5081C3F0FEE1BF935A35151622405F7AB0E4FBDF9D4F2B2D478CD4FFEFEAE0DD964C233775B3C3C2732A12254E59371C120E040610181B1C1F1A28333135373C40443B3E434F4B514B50525F5C51525C65665F6261736A6D645E626A746C707172686A707367625D615C5D4B829FBFC3D3CACAB59665452C31365084B0CAD1B5A48B7A6A5C657284A3A39A8465555D647C96A9AAAF5689909D9497A1A5A7A29EA59A9E9AA5A59B9E999C9FA3B0CAD1B5A48B7A6A01FE4C5A070708C073776A72696E6E7976787372676D757E7A79827C7B7580798097AECCE4D0AE867A83A4DAFFFFF5AB69414760767F8E8F7E7049394776B2FBFFE5C89C592B160D1A345383B5E1FFE590451E264B8DE9FFF6E1E5D4984723326EBFD3C67A2F131E515A3B291414070C0F1410211D24272E2A2F3236423F443F484F444F4B45584F585B5C5E6156646966665B675F677776686C6C71787D6B6C656A5D655E535A4887AADBE7EAE1D6C6A9805430473E5F8BACC6C2B1A1927672696E6F869598937E5E5857657992A7B3AC5597A29F959BA5A2A2A1A5A3A19AA0A3A2A29F93909B9BACC6C2B1A192767201FE4D5A070708D0736E6B74706A77726E6F6D6F6E78707581857B78766A737A828FA9CDE2DEBC9079789DE2FFFFF5A76A474A6386898B8883694A3C5073B5F1FFE8CB8D5C34170828375D89AFE2F9DD9142281F4F8BF1FFF6E6E1D6954A283B7BC3CBCF812E092E65673E1E1911090005101C1E1F24222426202834353C3C42424A414B505451554D5459625B605A64676D6F63615E6E70696A626D72706E7D6D63635F5E5753488299B3CCD0D3BEB8A1773F292832507EA8BAC0B19C856E6661656E889CA09274635352607B8BA2A8B0639091A0979EA5A1A1A4A49AA69FA29C9C99A09B9F989CA8BAC0B19C856E6601FE4E5A070708E07B6D757972737478746A6E786F6F7476717D7D7A7374777B839DB3D0F1F0BF947D80AAEBFFFFEBA768404A61768E878C7F6257455080BFF6F8DDC0854E29110A12355B90ACDEFBEBA24825234391E0FEFAE6E2DC9A492B457CBBD2C5802B18386E71432D1D0E0400060E16181F221C2426252C30383D3936434B465251524F56555250555F5A5E646D7168675D5B60636B656E727171656D646865625C5453477BA3CCD7D3C8CEB99E753F272336517EAEC7C6B89C8F7969585F6B849D9A937B56525863828DA1ACAE6091969B95A0AAADAAA8A1ABA6A0A3A39997A0989B9CA1AEC7C6B89C8F796901FE4F5A070708F0776F6C70756A74797877777974798A7E7D7B78847F70777D8396B3CFF1ECB48D747AA2DEFFFFF1A45C424561818F95967F614B3B4B79C3EBF7E1C291582C101020355788ADE0F1E3964824264790E1FFF6F1E8DE994D1F3A81C3DFC87A331B3F7E8D481D13130200000D0E14171B1A222A2628323732323E37424050474F55564A4D5A625F5F5E6365716362636371706E726E686F6E6968646967655C5B5D4D7996B9DBD7C7C8B9A16F41222D3F5B7EABB3BBB39A807F66635D668296A68F7E524B5B637492A9B1AD5B8F8F9595A0A8AEA7A2A5A0A39B9DA49E989EA29D9EA2ABB3BBB39A807F6601FE505A070708006F615C6B666A6E6D7775746B6B6D6B7D79808280807A6B798A9DBBD8FBDFB9897079A1E0FFFFF1AD683E42658A9194947F5C412E416EBBF1F9E2B38C5B2A130E1F3F5B90ABDAF0E698431F224E99EFFFFBEAE4D8933B1E3C7FCBE4CE802E133A7B814C2C1D0C030000000D171B2222202029212D31353A3B443F45404C52584E4F55585D5F5664616B766B6260636E6B6B6C606B666E6E62676662615D61554F6D85B0C9CBCFC8C1A6743F2021254B77AABABBAA99856F6861636B86A2AA8E70534951657894A0AFAD5391989C9998A5ACA8A5A0A6A997A1A4A39BA2999DA29EAABABBAA99856F6801FE515A070708107062686B696E7D72776A716F697B786B7B76858179776F6D7A98BAE5FEF1BF8D7278A3DEFFFFEE9D643F4A627A7D8D91796B4B3A4377BAF0F6DEC39566331A1021395E89AEDBF2DB903F22224997EAFFFAF2E4D4963A284074BEDFD278301F43888550301A10020003140E15171F1E262621282A3633363E3E3F3A464350564E5251545A5D6061606867666261606F6B6D706D716A6F6965666A675B5A5956457993B9CBD1CEC9C09F783C1F2C2E4E7DAFC8C3B9A58074715A5D5B8297A69A704E48425E748EA0B3A552929294969DA8AEAFA9A798A4A09CA9A4A2A6A39FA6A1AFC8C3B9A580747101FE525A0707082070645F6263667C707773746B6E75787F8279847F897D77808498B0D9F8F0BD8F6E739ADFFFFFEE995D4542607E908682755E4C3B407BB7E9FDE4CF9F5A2A130E18395988A6DDEFD1974827234590E4FFFEDBDFD49C47274189C5DFD5782F1B3E82854D2F1B0D010006010B141519161E1718262E3434393D424A4B4E484B454C4D52535A595D64646970696A6669686866636E706B6F6D7369636368695E5C46829EC8DDE0D1D2BFA1723E2426384C80B9C6CDBCA48773656155607EA1AA906F534B58636B84B8B3A159929D9D9BA0ABAFAAA49EA3A29EA2A6A1A2A8A8A19EA2B9C6CDBCA487736501FE535A0707083073676D72676A71787A727B79786B6C7C76818B8A8A7A697388A2C0EEFFF8BC8E6E739ADEFFFFEAA0674245657A8B898D7D65473B4170AFDBF6DCC48C53300D15203A5C8CAAD8F5E3A14223294F99E3FFF9ECEADB9E43233E82C1D5C2803213438B905125160E0500000319161E271E1A1B1E272F2F353D313D3F3B404D585A4A4E4C5D575B595C626C695E635F696D6C6B6A6869706A73706A626B656460593C7999C3DED7CBC5B3AD784219292E4481ABBCC8AF9D8879615F5E6B879E9C887A57525154638AA2B1B45C8F92929AA1AFB3ADA6AAA1A6989EA4A7A49C999A9BA3ABBCC8AF9D88796101FE545A07070840766F6C72707375766D6D7C726D79727A7F85867E817A747B819FC2EFFFF4C189727BA5F0FFFFE8A75D46416184918C847E5747363E6EB9E5F5E2C38D59230E0C12385085AFD6EFD68C4821234C95E3FFF9EAEBE19D4B27347DC6E3CD822B16418F9457352815020000020910191829281C201F2D343332353A464F514E5557524F4B4D515D5A615F5F625C606567686B6E6A6D72726D62626C6566625D5A5A4988B1C3C5D2DAD0C7A07F512E2A2A5480ADC4CEC1A381756B5A54598AA0A3967F5C434859708BA0B0AA558E8B8C83979AA6B4BAB3A8AE9A9CA1A4A3AAA3A7A2A4ADC4CEC1A381756B01FE555A07070850726B6E6F7174747A7571707169727E797989908B7D7A7D8388A3CEEDFFF4C5897078A4E8FFFFF39C5B373E5C798C8790715A433F4376B1ECF6DEBE9857220F1A183D6085ADDCEED89C471A254988E9FFF7E0E0D99D4B18337ECAE5CF843A1D468F8C502B1B0B0101000512181A1D2321111D1A24312F3936433E494A4A55555A535451545858595E5E645E685C616A7372696964687574786F6C665D5A5D5A436D8FB5D3D3CCCBC2A774442C1B314267AEBFC5B7A586686162566484999F90734A434D5C718DA7B2AD6094A39C959FA9A8AAADADA7A19AA3A7A0A7A9A1A79E9DAEBFC5B7A586686101FE565A07070860757A77716E747F787275727A6F74717983807F8D8075767686A0C8F4FFFFC3866D7297E4FFFFE7AC6243415D758898937D6144414A70ABE3FBE6C69952281007122D568AABDAF0D497431E264C8DDFFFF9E8EDE5A050213E81C2E5D2842B133D80904F2E191702000306091C1918221D1A1B2322333638403D46474B50504B4C4E4F524F585B616161675E6664676B71747169726B6D70666B5E616354595A4A7298C6D7DAD3CCBEA47749252843587EA2BAC0B5A4877260565166879BA58D734C4246526C97AAB5A15DA89897949EAEB2B2B5AAA3A79EA4A5A2A9ACA1A798A5A2BAC0B5A487726001FE575A07070870786E6F7872767E787D7683797674717E7D828A89898379848EA1CAF6FFFFBD916D6B9AECFFFFE3A75A3C39598191958773564A363B75BCEDF2DCBC8E4B190F050A2B5488AFE6EFD29A4216264E96E4F9F1E6EADC984D214185CFE5C380351F409A985028251F10000007061611151917201F24272C333130393D424B4847484C55565A5E5E6264626A69616166626C6D7068686C6A6C6B6564685F65635C5343708DBFD5D9D9C5BCA77749313231476BA1CBBCB79C887F6A6562607EA3A498674747465C6994AFB7A4569191989E9CABAFAEACAFA5A09DA7AAA29D9BA7A5A9A7A1CBBCB79C887F6A01FE585A070708807C786D7472777B8177736F6F6D738181888A918A7A79788482A4C5F1FFFFC48E6A6C9FE7FFFFEDA96C3B415F838D8E8F785E4A373B75BAEBE7DABB925A30130A17375785B4DFF3E5984D24244790D7F2F4EAE7DA973E2C438FC1DECB7B2F1442879358392723110500000A1B14201B2119161A242F333130353339424349505454494D58575B625E696965646069616D6F6871716874797465646367645C5547799CC2E1E5D5CFC4A4724F211C2C5191B6C1C6B2A1857A7065545F7B9D9B757A574744586F85A6B4B261919CA29B9AA6B3ABABA8A8ABAAA2A2A8A1ADAAA99FA3B6C1C6B2A1857A7001FE595A070708907E79696D706A7070747670746D77787E80888D90877578848B99B7EEFFFFCC8061729DE6FFFFE09F5B4341627B868D88736647303F77B6E4F1D7B59559240B041437608AAEE0FAD7914324254690DBFFF5EBE6E09D42254190C4DCC480352247858C5337302B100000060E17121E1A251D18181F232E2D34344348504B4D594C494F5652524C5E656168685D66606A716E68646B67686D6B6F606365625F5A4E8EA6BFD2E2DCDCC6AB78492328314D69AECDC6B4A4847B6B574E5886A4A49475424143596C95B2B5AD678E8E9F93A3ADB9B6B7A5A5A59BA2A8A6A8A2A3A2A0ADAECDC6B4A4847B6B01FE5A5A070708A075776F686E767C7375697F78716E7775848C8D8C8B7F7A7E8BA6D5FDFFFFC98E6476A2E6FFFFDD9E55353C5E777F8789786846344276B6EFF7DEB49353280B090F315B92B3DCF0DF9B4C2B22458FE7FFF6DDD6D39141293E79CAE6D385301C478D90553A3836130100000A1A1B1A151D201C121C2C312D2E403F394847475251495255595C596565616861625D5B666666646973716E6A636E62645D6060574C79A1C5CFDADAC4C19D663C3F2B305084A9C7CCB7A0806F55565D6387AA9C836E4F413752658BA8B7B05D91979793A4AFB0AFAAA5A8A89C9EA6A1A1AFADAB9AA6A9C7CCB7A0806F5501FE5B5A070708B06F687073706B7876807976727277728587899790897E787E8EA3CBFFFFFFCE8762689CE6FFFFE3A0533A4E5C6F80858076553C39437BBAF8FADEBE9A5A2D180E0E234B83ADD3EFDBA15118254196E9FAF8E7DFE29641273B82C6E1D987360B40818F4D413529120902050D120F1A17231F1829262C2F36322F38405047494B504D4D46525D5D5C5A6464595E5765636E6C7270686E686C6F6567686C6D6153477F9FCBD9E4E0D3C9B5784621242F4D90BAC9D3C69F816D6558546183A4A9946C4D40434F6B91B0B4B7618A898C95A7ABB3B5AFA9AAA8A8A9A8A39BA39EA3A8A2BAC9D3C69F816D6501FE5C5A070708C0757A6F726D6B7B776F7379717274777E85929394887D7B77839FCBFFFFFFBE92647798E2FFFFE2A36039315C7086878A715C4439456FB3F7FFE7BD8E54270A070E2E5389AED9F0E3994922215189DBFEF3E7E6D39E45183983CBDDCE833514438E995A443D3D1F070000040D0C151F1D1617252228292D313B3E3B48494B49454D4A535B585A546062635E5D666B686F6A666B6D717671716B6561685F5A5749729BBDDDE6DED0BAA17B4421112C4488ABC4D1BD9E7579695C61618B9FA7926C483B404D698DABB5B15C8E9C9C989DAAB2AFABACA6A09CA0A6A19DA3A8ABA6A8ABC4D1BD9E75796901FE5D5A070708D0787170736E6E6E72727881727371787F7F8C8F8F887B7A7C8CA7D2FDFFFFCC8C626B9CE5FFFFE6A35D3B3A5B8199938F796039333E78B4E7F2E8C391531D0E0A1734618DA8D6ECDE8F430F1F4C91E0F8F9E2DBE5A646243280C6DAC7823316419199594D3F2E0F0300000E1214191C1E1B1B1A251F202E363A3D46483F505450514F5352555B55605F6462605B5E6868686467666C6E6571636A6F5F5A5B50507AA0D6E3E9E5D4C2A982462524374985BBD0C3B19F89715A565C678EA1AA98763C24384B6E8AA7B5B15E97978E989AA8C0B9B7B1A5A8A3A3ACB5B3ACACA6A5A8BBD0C3B19F89715A01FE5E5A070708E06F76766F72737678858475776D796F798294A8A38B7E7D7F8EA7CAF7FFFFCF8A5A669DDBFFFFE2A15A394058808F928B714B413A3C70B8E5FAD9C7985E26110B13275B87A6DEEFE78D401C204A8BE5FAEEE6E1E5A146244082C5E4CB7F301C4C8C935A4148412304030005131012141E18161D222828343434364C4A4549504E4851544E4E5A5D6965676465615C66666867696D706E6C726460575859595347769CCCE0DFD8CBC3B17D46232A2B4B7FB1C4C5BDA3867466515B617E9CA4967440343D4A5F8FAAB2B1618895989D9FB1A7ADB5B6A8A2A0AAAFA6A8ADACA0A7AAB1C4C5BDA386746601FE5F5A070708F0846D70677173757A737A867B73787B7E8D90989B8C7C817B84A4CEFFFFFFD3885E6297D9FFFFEF9E543A3B60788B938B7B573A2E4072A7E6F4E3B98A542D1007183A608DACD9E6DB8F472B275091DBF9EBE4E0DA94441E3A7BC8E2D290301A50999C57414B411D0000000F1717171D121C13292A2726242B36383D4545534F4D444751555A5D655D5C6169685962646D74736C766B686E62615F5C615E5C5740769BC5D6E2E8DAC4A471442B2E314A7FBAD1D3C0A38267655C5E6189A3A493663E353A455F8DA1A5AD679B98969CA4ACADB6B4ACB2B0ABA5A4A3ABAFA2A2A5A6BAD1D3C0A382676501FE605A070708006A746E746771747A747174705E72737B838D9890897D74798DA2D0FFFFFFCA8669669ADFFFFFE19D5433345A7A8A8E8D735B41313B79B5EEFBDBB48950240E0310365884AFDFF2D38E4120274B8BDEFBF4DDE1D79D47243885C9E4D08335284791935B4A4F4020000000030C171D1D2219131A2A332F2B2F373B3E3C3F47494E4E4D4F4C52555B57626B645E6160666C666E6A6968686E6C65605D605E5D65456CAEE6EBEEE8E9C9A47B331E252F3A82B7CCD8C0A082706263587182A1A79A6C402631456E93AFB8AC5B91A08492A3B5B1AEBAACA7A7A5A8ADB0ABB5A8AAB0A8B7CCD8C0A082706201FE615A070708107A6D6A716F727C807A7B7A7A7A8187898692969A8E8380808CA8D3FFFFFFD17B5D6599E8FFFEEAA25D37305E7785958875533C283B76BBE8EFDEC28E5D1E0A101D37588CACD4EBDB9744211B4194ECFEF5E4E1DD963F223F8CD3E4D5843215458F995C4A5D542A02000001081319171B0E0A151A31373227373F3B43474B544847555357584E565C5A65616C5C59637261605E686C666E74685F655E5F665443739ACDE0E0D7D8BEA16B401C24314777BACCD3B6A2856C67615B5F849FA3896F4236334B6C95B6BDB76094999193A6BCB4AAA88FA4A3A0A5AFAEAABBB0A3A2ACBACCD3B6A2856C6701FE625A07070820767474736E6F757D807E85766C6971828F98A3A4997E7D778FA6D5FFFFFFCF83635D86D6FFFFE9A85A3037547C928C8A785C3A304069BCEDEFDCBE8F522409060E326090B3DBEBD78F3E1B1E4C92E5FFF2E9E7E2A64722367EC9E1D28730214597995C4B654F160A000107130E1C181C1819191B2A1C22303535373A414C4D4F4D4852544F575356635E60585A636A6A60626A68646D6C655E5C576164656147658ECBDBE3DED8C7A87C3E202131497BAAC4D2C6A3836E5956505E87ACA68C66352C324A668DB0B6BB65928D8C8DA5A6B9AEB1A5B0ABA6A5ABABACA2A6A0A3A8AAC4D2C6A3836E5901FE635A070708306D66696869716F73807B7474757E7B7989969D9E8F7C74718BABD3FFFFFFC3886A6B93E3FFFFF09D50322F4E758E8A8D7D5B41293E6EB6EDF1DCC18F5D2611080F2F5D8FAFDCF1E394462224488DD8F2F5DDE0CF9B4A253980C4E4D3842C1C4A8B895F596B59360000010C131212141B1511161124312923303D3A4341425350504D504E4E51605F5D63626459606568656268686C6F746F5C6562625C5D524071A3CCEAE2E7D0CCA975371C292F5184B5D3C8B99E8175665858637F9FA392663530263E6294BAB7AF5F8D888D94A3B9B9BCB3A8B1A99BA2A9A2A3A9ABACAAA5B5D3C8B99E81756601FE645A070708407B787B7C817F7E83807D808072797685869EA4A89582777989A2D0FFFFFFC687656D93D5FFFFE59B503135557B8B8E8B765436354071B2F0F1DDBA885228110E15385B89ABD6E1DB8D451827478EE5FFF0E2DCDBA04D2E4080C6D8D17D2D144E95965852695D2909000005121015191B1712161C23252A2734303E383B404A464D4B4B4A525359666E6B5C5C5B696A696B626D7268656F67646D65604F5750447BA0C8DBE9E5E6C6B37B3B211823528FBDCCDBC29F8273685D5763809BA88F6F453436456C8AB0BFA65788989894A7AEB4B2AFB6B2AFA4A3AFB4AEADA6A4A6B0BDCCDBC29F82736801FE655A070708507E7073786B69708780756E6B5F6C78808793A4A08E7E767A91A4D2FFFFFFC88E666692DBFFFFEAA658352D5170888C8676574236466DB7EFF5D6B98655260A040B2A6484ABDCE3D9963F1F27488FE3FBF2EAE4DB9E472F418EC8E2D09031174F959365546A5C2F020000000B1D14120F0E0D111C232B292F2F3E3D41424F49424946484B4D555D61616C625E5B5E5B67656E6C726769666564636A6256575749769FD3EBE7E3DAC4AF703E132632547EAFCBCDC09C907A6C5B4E5B859AA1926337252B426389B2BBB15C91898898A7B8B3BCB9ADA5A7A8A9B4A7A7AEB2A0AAACAFCBCDC09C907A6C01FE665A07070860737A6A70666C7B8073737C8077787E8B859D9BA28E777E7D88A6D7FEFFFFCE7C536494E3FFFFE29D53333F527581818779513729416FBAE0F1E3BD965D260D080E275B81B2DCF1D38F461E27458DD9F8F8E3DEDE9E4F253A85D2E7D5893521509B966159685A2D060000000A171E1B141110141E242B25252A30393B414944434C474D565E595D635D5E66605A63666B6872706969626E67686A685F5C5D54406D9CCAE6E7EDE7CBA96E351C252D4E87C0CFCCB6AA897364534F5483A4A08E6B3A363A455F8AB7B7B0628C918E93A3B6BDB8B7A8A4A7A2A8ACA6A7AAACACA8AEC0CFCCB6AA89736401FE675A0707087074716773657180817E75827974717B81829D9BA5967D7B7684ADDAFFFFFFD07F616295DFFFFFDDA35A34325B74868E86715B40353875B9EBEED6B696592710040B2E5685B3DDEBD98F461A214385E2FCFDE9E0DD983B1B397DCAEDDB8D361A4C9694595E716E2F0B00000812151B16201312161A241F23262F312D3D393B4A474D4F4D534C4E585D62606060586268766B686E70666C6C616960646A575A5745719ACAE1D9DCE1CFB27E3D1F32334C7FADC9D2B79D82736253595582A7AE96753F262C395D86AFC4BA5C898F9194A3B0C3B9C0A9A2ACA1A5A4A39EAFAFB5A7AEADC9D2B79D82736201FE685A070708806F747072686D6E6F7C7B79776E747D7D869CA7A8957E737689A2CEFFFFFFCE855F688DE0FFFFE396502D33507A8F918972593E2B3068A9EAFCDFC08F602B0C000E2F5F8AAED9ECDA95472524478EE6FFF5DDD9D3994B284688C0D7D3842E114B9596645876673807000003131925141A0E0A0F2024222C2F2E31363D3C44474D49484D4C5B565D62666267695B6B68726E61615E606967655A625F63665E593B7598D1E8F3F0E6D5A67B401829304985BDD7D4C2A2886C654B47517FACAB9D6D3B28263E6391AFBCB25E928B8892A3B3BDBEB4AFAAAEAFB7B2B2ABABABA8A5A3BDD7D4C2A2886C6501FE695A07070890806B68666E71707786837C746C7A8282889AA9A38C7D716E84A9DFFFFFFFC5765B5F95DCFFFFE39953343A5B7D8D8C887B534132396FAFE0F3D5BB93571A000715356485A0D3ECE29A451C1C3E89E4F9EFE1DCDDA042244589D1E4DB912C144994985E5A7975320B00000519211D111204070715211F2127303532353E4D47483E495453555C545A655F5F5C566067636862687A6F6A7566675F6564635A523E63A6E3F7EAEDE5CEB6843D1926394487B4CED4C0A0726E6456545F87A3998667332E2D42629EB1C4B65F92968E98A1B9C4BDB8AEA6A79FA0B5ACAAAFA9ABB3B2B4CED4C0A0726E6401FE6A5A070708A07B777874707483838A7E867F7B82787E93A6B1AF928878718AA6DAFFFFFFC67D526792D5FFFFF0A85630395A7A8F8F8B714B33293E64A4E8F0DBBD8F4F280802132E5C92B0DEE9DE9642181B478FE1FFF0E3D6DC9B4324388ACFE0C7792A154C929D5F5A81773C0D000008161E1F1E120B0F0B16132028263031393E444E44433E48435057515759666461656864697269666A68646761635E635D5F5B5358467BB3D6EBF8ECE6D4BA833F192337518AB6CECBBCA281685D57505088A0A9916F4331373F5D82AEBDB76092968E98A1B2BBADB1AEAAA8A5A8AFA5AFB4AEB0ABADB6CECBBCA281685D01FE6B5A070708B074666A727372736D75748575737A798191AAAE9E8C716A788BABE0FFFFFFD28D564E93DBFFFFE697582D2E5482918A8C7D54342B336BAEE9F1E2BF8D54220A000E315D86AAD1E8D58F461F214995E2F7ECE2DBDE9B44243D89C3DCD68F341E5296925D5E7E73360000000F1A221B1E1609071214211B22272D3433433E444E454C4946514F4D5E626562615B5D5A5F6B6A696E6E696D6F65625D5F635F5052446A96CAE1DED6D5C1A679381C30234381C9CFDCC5A6807161494C567EA6B09D733A2529395886B3C3B6618B8F9398A3B7BFBBB1AAB6AFA7A6A5ACACB1ADABB2AAC9CFDCC5A680716101FE6C5A070708C07B726C766B6E7C75787C807D787B7E8B8CA7B3A695847B7380A8D9FFFFFFCA7D5C5E8ED6FFFEEAA6512E2B548693928E774D2F233E71AAE5F5E3BC9556250C050930638CA4DEF3D88F3621224891E4FBFBE1EAD1943E253E87C1DBD78B371B4C8D8C5C5C867037080000091A13241A18100C1319171F1D272E38353E4646484A4F4946484C504F5A61655F635B5A686C636667665D5F685F69635D5D6054554874A9E6F7F9ECE6D1AA7730211F1F497CB2CBDAD0A4796D604E4D5D89A8A38F62371C1F275A97B8BFBA5B919691919FB6BFC2B5AFA9B2ABABB1AEADB3AEADACACB2CBDAD0A4796D6001FE6D5A070708D073747C7A7977787F8481827C7F7E7B878EA3B6B5A2817C6F88AAE2FFFFFFCC7D535685DAFFFADD9D632C39577C818E866F553C2C3D6DAEE8F6E4B98F561D080B172A5984AEE6EBDB8D4517224992E5F9F3E2DCD99942254487CAE1DB913B1E4890956860837A3D070000041C151B1A130E0E151819242621282E383F414A4D43454C4C505155575759655D625D5E6666666160676B686D636B666363625E4F387CABD6F3EBF3EFD1B9833B1E27313D7FC3DAD6C9C1836F6454475882A1A29364322C26385C8BB7C0C262898D8C93ABAEC3BCBAB4B3ACABA5ABAFAAB3B1ACAFBDC3DAD6C9C1836F6401FE6E5A070708E077716B71727476757E7B7B79776C76919BB1BDBB9E84696F85A9D9FFFFFFC87C5C5D84D2FFFFE39D5B2A2E5A7E869993734936282F66B5E6EFD3B99451230D041237628FADDAE6D78E481A1B3A84D8F6EDE0DEE1993E243E82CBE1CE87351B4493906A6287813C0500011323211D1A1617140D171A1E2728302C31333A39454047484B4E58505A605E6761645B605E6969656B6967666F6B5D685E635B52503D72A8DAF1E4E3D5CFB17C3C0F1E2E4C83BBCED2C2A6816B6250445981A2B0A06E3C251F3E5688B0C2BC588A908C91A5B6C6C8B9B6BAA6A4A4AEAFA8AEB1A7A8ABBBCED2C2A6816B6201FE6F5A070708F0777172736E7578778880817A7171828E96AECBBEA08372737EB0DDFFFFFFC17B575B8AD9FFFED8A14E2532527A8A969276523B203168ADECEBCFBD935B1C09020E366087A9D9E8CF8C3E161D448AD8FAF7E4E7DD944221418AD0E4D6902C19569F9A5A597F7C44070000101C1F1C1B1A07060E13191D1D283434323934443E3E3E4A4F535153575A5F69605F596664645C67685F65706F63626862676259584C70A8D1EDE5E0F0D0B0763D1E2A2E4C83B3CDD8C6A17D655A4E4D567198A4996F4133283E6294B3BBBA5E8B969394A9B6BCBCB0ACA1A8A1A7B3B1B7B2B0AFAFAAB3CDD8C6A17D655A01FE705A070708006E6E6977716E73777D7B817A7D7E7B8D98B8C2C1A57C706F83A6D8FFFFFFC17F54558ED2FAFDE099552C3356848C928876543A2E316EABE4EDDBBD935B1F07010D2E5B8EAAE5F3D48A3B1818458CD0FBF4E4E0DCA64D263F84D5E5CF812E2150919B5B55837E440800000A20282923170C070A15181D2327383131383E42474643454C4E5A585656535F56575D61666A696C6265676A786E605B5F6B6055504282AFD1EFEDE2D4C7AC743D2824384D84B2D5DCC6A18568634F4452769A969A6F3B1F26425B89B7C4AB5E9298888EA2B3B3C1B8B4ACB4A5ADACADACAFA8ABA7B3B2D5DCC6A185686301FE715A070708107070746A6A6C68707C7C807A6C79728991B4CCC29D76676F829FDAFFFFFFC17155548ADFFFF2D0A35F3E355E7D858A826955302F2B67B2EBF0DDB7894A1300000C2E589BB0DBF1DE964216254F9BDAF3F1E8DFD59D45224683C8E4D189331B4C899863677F7D3D0B000515202220181A05070F0E18171C282C33353C3B38424B495157484B53574F5B605C62655E5F61535D6C6A676D626664645E535A5755446A94CADFEBEAE1C9B0763E1E1D324E7FBECBC2BB928A775D514C51809EA89872422A1A2B5686ACBEBA5D8F8E8F91A9BAC6C7BBAEADACA8A7AFB2B3B8B3B3ACAABECBC2BB928A775D01FE725A0707082071756D6A686E7A7F88867C7D737E77869CBAD0CBA37C6D6D82B0E0FFFFFFBD7B504F7FCCFFFFE0934D2E354F7A8995987753352C2D66AFE0E5D5BB925C220B000F31598DB0DDF1D7863B17223B91D7F7F9E3E4D99C3A1A3D92C7DACB872F1D5C9B9D5A5C7C773D1000000A201F1E201E13111309102622272B30373E3D4140404049494A50525B605D6658585D58676A645D5E76776D68615F5D5E5D5958513C6E99D7E8F4EDE6D3B480412124233D86B0D0D0BFB283665E5347477DA9AA906D372A212E5389B6C9BD5E8F888697A9B8C2BFB7A6A9A6A3A6B0ADB3BCB7B4B4B2B0D0D0BFB283665E01FE735A07070830746F696D666F6C7575807D7A7A7575819ABDD0CEA8816A697AA9EAFFFFFFC47952598AD4FCF7D28E4E2E3352888F918C7A583E2E3B6FADD6E3D9B38A58230A00072C5E8BA9D8EFD5883D1A164590DCFFF6EBDED69A47273A91CDE1D186331D4A90995F5778794309000012282A2C1E2516040D11181721252C2F2E343C413F46494E4F4F5B58555A636463565A5A61636468655E6C696B6A6667665E5F4E4D426E9BDAE4F9F2F1DDB67740201E2D478CC0D0DCBD9F7D605E534A4B78A4A09068382328385192B8C0BC648C898893A4B2BABCBFB7B3A5A1ADB5B3B4B8ABB0B7ACC0D0DCBD9F7D605E01FE745A07070840756E6572616D7478807C7E7B6C6F7A8BA1BDCEC3A9806B6F84A4D5FFFFFFB476465A89D8FDFFCC8D512C2B567B8C93927A58422E3F6AADD7DECFB6925E2000000E2A5680ADDEF7D38C4916234689D4F8EFE9EDD193411B3978D2E5D68130224F989A64688A934F1704000B191E261E1412080C1216201C1E212D2E313A4040424145474E54555F5A615F59575158686662696A6B6B6B6B676D6565575C574A3E6F97ABD9E1D4D5C5A56F3E1927324E89B7D0D5C4A26F6F60514C537C9CAD98632E1E2532577DAEC4B86A8F898B90A4B5BBB2BCAEACAFA8B5B4B1BFB7B6B1B0AEB7D0D5C4A26F6F6001FE755A070708507D76727B7B797B7E818789767B847D7FA0B7D3C9AB7E6F6B78A8D8FFFFFFC580506290DCFFFADA9652282D537C8887836E523B2E3163A6E3EADAB693522405040F25528EABD5EEDC8E3E221F3D8AE8FFF1E3E4D296411A4392D3DBC884301B559A9563607E8A3F0D010A132C272D231F110906081312202225313238383744433F44454C4E525B58575D5C625E64636262646B686566665F6563675E65615E446398C5D6D9CCCFC8AB7935101320377DB1CDD2B2967C66584C45527E9BA892692C1A21305C8DB7C6BA5E8C898285A1B8C7BFBBB6A6A1A6AEB9B5B0AFAFB3B1A9B1CDD2B2967C665801FE765A07070860807C7B7972767B83848589837E7D7884A2C2DDD9B3836E767FA3D1FFFFFFC578545582D3FFFFD3964D25305181999890795738243770B6E2E7DCBF955D1903040A2656849FD8EACC853A1A29489EDFFFF3E0E9E0A244244A92C9E7D1852B2045999766658A8A4C0C000013231E2825180B020C09101221211B2A333B3941433F414B44515053565E5D625B6557596963615F686C656C71696658545E604D504577A7DCEEEEECDECAAD71371A1D28508DBFD9D4C2A07D6A563F3C4C7EA9AD94623928242F568ABBC3BB658E8D908CA4BEC4BCABA7A6B2A7B0B8B0BABFB2B0ABB1BFD9D4C2A07D6A5601FE775A07070870716E6F736C6D727F8A867D777B7B7C8899B7E0D4A580696A86AFE6FFFFFFC0794F5684D1F6F8DB974B222A4F868987917C4E322A2F69A9E5F3E4BA965F26010002245490A8D3F0DD97491B1E4D8EDDF4F1E5DFD28F4C294181C4DECC90361C4D8F946D6B868C550D00001030221E22140C120D09141E161B243030332F394C3F40474B4C4B53515E625F565C555D6468665B676870636B5D5F5C5A60615A534D769CCAEDF5E7DACBB27C491D1E2B4080B3DBD9BAA5836C5944384B7B9CB0956A331C1E355482B5C9C1668F867F9BACC3C7C8B9B1A9A9A6ADB3AFAFACB1B3B3AFB3DBD9BAA5836C5901FE785A070708807A716E77707575888C7C8485787B7B8AA6C3DED8A4766C6E7CAAD8FFFFFFBF72545B89D3EEF2DE9A4C30335C8289918E75502F242F6FB4DBEAD3B6975E2A00000834628EA9D1EBD58B3B11113F93DCF5EFD9D7E1A148223F84C5EBDE86312151959060618B8E4C1600000C2A2D2B25200B040B0E10171F18222B3335413D4042403D4652504A50545B6C655B605D63696D655F68616E656A66555B5D57535F4375A0D7EBE0DAE2D3B9823D171A254683B5D1DBBD9E85725E4F484B7CA7A796622E151B2A4D85BCC9C16987899598A9B5C0C4C5B9ABB0A9B3B5B4B9BEAEAFA9ADB5D1DBBD9E85725E01FE795A070708907E816C796F79808A837A81837675718DABD0EED89F7666677EABD8FFFFFFB6744C5585CBFBF2D3924C2C2C507C938F8B754935283366A4DBE5D4C4995B2602060F2C5E8AAADBE7DA913F11193F96E5F0FCDEDBD3A047274182C7E2CE88351950949D685D8895541404000A242B2B2F22140A090A0B12181B252E27373A463F3D4449464D504C545D5B6062644D535A6267656863626363636062626059554E4474ABDAF3F6EEE5D0AF6E32171C2C4581BAD5DEC8A18E6B51524249749BA397673D1D13234683B2C7BF6A928C848CACBCC4CABAB2ABAAABB5A8AEB8B2B5B2ACB2BAD5DEC8A18E6B5101FE7A5A070708A07874796F797B75878E808A80837180889DC0E6E3B6846A6681A9DBFFFFFFC3784B4C81C5F3F4DD9C4D2F304D869B998F784F33282B5AADDBEFCBAF91582A0B000C2F5285B6E2E0D1914424193E8BDEF9F9EAE9D69E43213E7FCAE6D18A381B579DA56761878744100004193433302A1D0D0A050B16101C1A202530363938394540464C494C505150575E5663626464615D635E666A7372635E5D5A61535B5543779FD8F3F0F0ECD9BD78391620275282BED2E0C99B726B5E4D3C4879ACB09B67301B172A4A89B7C9BC60928E86949BB8CAD0C4B0A5ACA9AEB8B0AFB6B6B6AAA9BED2E0C99B726B5E01FE7B5A070708B07470676F6A7575808B7F83857A747B89A1CBEBDDB5846468749ED4FFFFFFB97747497ED5FDFDDE984C1A28527D868B98805130243063A9DADFD4BE955E280E010C306190B5CEDFD08A40121A4C8BE1FFF5EAD8D79746234C90C3D8D1813119539A9C6E6582834B1401081B2B32321E190B0603110E13151A2333303735333942404C4C4C434C50545B5F605D5A625B57625B63636C6765615D63635E585853486BA0D4EDF7E6DED2C18B3A1421234487C3D7DCC49F747056443E497AA9B09A6A3A281C224986B4C9C35F94918C8BA5BED1C4B4B1ABAAA5ACB1B5BBC3AFABA6A5C3D7DCC49F74705601FE7C5A070708C07573676C6D6B7E86868B887F777A788BA5CDE6D8AF7C6B637CA3D6FFFFFFC376484B7FD4F5EAD495501F2E587C8E908E825731233C65B1EBECD6BA97581D00000A28618CAAD8E7D190370F1D4191E0F4EEE3E4D19446254997CFD8CB852E2454959363608F97581F000819303139261A0A00040714221D2325302C2E303A3D3F3E444B4052514D5A595B5C535865695C68675C63666F6E62616666605D5D5A4576A5DCEEF6F0E5D3B2733C1C1D2C4D8ABDD9DCBF9B78695B483D51849CA795703A1B19204F8AB4C5C3638E888B8EADC1CCC7C1ABA7AEAAACAEB2BBC0BBAFACA5BDD9DCBF9B78695B01FE7D5A070708D0797971786E73757D888F887B726F738A9FC7F1EAB47C63687AA7D0FFFFFFBF70465178CCFCF9DB9B50272B548690908B7C573C29366BABE1F0E1BE8F4717000009365D89A8D2DFD287431E1D4286DEF9F4DFE7D0934C284886CCDDD2873718509192695F8B86551B000E203E3B3A282407080E0C13172824292E313030333F40313B44495054575959575A61535B58566063666E60676B6C5E595F6B5D584E4066A4CCE9F9F0DACBAA6F360F1E22438EB7D4D5C39B746556373C4572A0B1A5612F19161E4683B3C7BA6885889196A7BDC9CBBCADABA9AAA9AAAEB1BCBBBCB4B9B7D4D5C39B74655601FE7E5A070708E06F6A6B716C6E8386858B8A8274737E8F9EC3EDDFB1805D607FA3DFFFFFFFBF72434F84BFF0F2CC945727335686959E98744A322E3261AAE0F4DCBC8E571E05001631598DB1D9EECE8637191E498EDEFEF7E2EAD69A48273980C1DEDD8E32164C9597645E969C581200091E2E3B3A29150C08050A0A11181D28343034343137443C43403D484F55625A5959555A5B615E5F61656062686C716166646660595846709DD5EBF0EFE6D4BC7C34181D2A4986BED5D9C99B765A4F3E3C4872A0AA9A6738201F2E518DBCCCC25B8A82828FAEBCC4C5B8B2A5A5B3AFB1B5B3B0ABA8A6B2BED5D9C99B765A4F01FE7F5A070708F07973757D6E697A80868D8B8A7E798390ABCBF0E4B37D63627AA7DBFFFFFFB7703D4885D2FFF1E196482A274B818A8F8C82522F273065A9E1E7D9B88D5B22070208285D94AFDCE4CA833517244386DAF8F6E6DCD58F40233C7FC9DACD83371C539C9A5B5F828E521100071C3C473E33250C00070012121E16232D2F393C343C3D3F4A4A434C554C525A6157515262565C6560676C6B6C6B66646661666754603F81B0DEEEF9F5DED7B5753D1C1D27538CC1DBEAC69181605B46384A80A3A8926C311B16294B80B4CDBD658F858986A0BECFBDBAB0B0ADAEA8B6B1B3C2BAB1B1ADC1DBEAC69181605B01FE805A0707080071746E6E6F6F79858C838E857276788D9CCBEFEAB08A6666719ED3FEFFFFC26F445385D1FFF8D69953212C5384889C90725230233165AAD5EBD9B79D5B24040006275A8FACD7E7CE87431E244793D8F3EDE2E2D69A46233E89CCE1CA89381649889E68628E965B1400052539443B35210A00060613121F1F212829322D3441413C40464E474C515352615A5F575E666D685F6566526164666563656A62565C497EB1E3FCFCF2E4DEB6843D1C272A4F8BC5DEDDC9A37A645A4E3F4381B6B39F68291912264682BDC8BD6790838A96B4BEC5C0B8ABA2A9A6AEB3B2B8BAB6B0BAB8C5DEDDC9A37A645A01FE815A070708106D75706A5E65768A87898B7A6F708390ACCCECEAB57A64637299CEFFFFFFBF71464C7CD1FFF5D98E4A1D2A557E8E9296734E3A243464ACD5E3D6BBA0531A03000C2B5284AADDE8DB8D411216448BD5FFF5E5E1D7994D293F83C5DFCA893618599C9F686D8A91521400112840484033170E0000090C1414191E1E283833393D38413E35414B505555595E635F5E5752615E5A5F646268656E66615B5E5D58544873A3D0E6F3DFEAD19268370F19274881BADBE3C8A5776A564A3A3F83AAAE9C64330C0421448CBCCFC2688E7D858AA0BBCBBCB2A4AF8AA9B1B7BDB7BDB5ACB0B2BADBE3C8A5776A5601FE825A07070820747B747B6B77818791888081737F8483A1BCF0E7BF776566719DDEFFFFFFBD6A404F7ED1FAF7CC944D1821527E959D9A7B4C31262E5FA5E6E9D7BC9E5B2C0D0007325686B4E1E6DA8B3920143D96DDFBF9DEDAD58D50233D83CBD9D1833527519598685C828C5209000D284041523929100A07061111121C281D2735373E38363B3A3F484A4B4B4F5458555658616169655F63696063685D5F5F5B62585A5B4C7FB4E2F8F3F8ECD4B97B3B2015274B92C1D8DAC39D77695E3B34467CA9AE7D621E1F16254E87BED1CC688F898288A1C8CCCABFB8ACB4AFBCBBAFB7C0B6ACA5B4C1D8DAC39D77695E01FE835A070708306F6E62605B62767B87898A82767A7E849ACCFAEFB6795C5A7AA8D7FFFFFFB56B464C83CBF3EEE29A4E243253818E968E76512C222F6BA5D2E7D2C79F612009010C265785A6DEEBCB913C1D224791D9F2EEE1E2D38E48243C87CBD3C8852F1A5BA19B6D628B974C1701082F464B503922110100090D0E111D20232235332D333E4243474E4446524E5A5E575555536063575C686568686462655B5F665E5558476E9EDAF1ECF7F1D5AF6D2E1424254883BAD8D4C59C78665D42344577A9B7996D3A2817214481B1CAC5698F828A8BAABED6C8BEB5A8B29AAEB6B3BEC0B0B3B2BDBAD8D4C59C78665D01FE845A070708407479717271737E7F938E9A887B778191AECBECF2BC825F6676A6DFFFFFFFB96D424476D0F1F1D8944C242455809098927E572D282566A6E9E6CDB48A562506001630558CA7E0E3C993471A1D488BD9F1EAE3EDDAA44C2E498BCAEBD682311852969866618D895213000A23444B473A280E030507100B080B1C282A37343133373B3E404949464F54585C5D5F585960667163666563646B68615255655857534571A4D0F5FBF4EEE2BA803E1E27294994CAD6E1C7A17C655A43314189B0A2935D311E0D1F3A7DB5C4C76F8C8E868B9CBDCECEBCB8AAA5A9B2B9BABDC4B5B5AFAECAD6E1C7A17C655A01FE855A07070850717772736E77817F8C908C817670778EA7D4F7F0B680695D74A1DCFFFFFFAC623E558BCAEEFBD1894B2B2753818D8B83774F2E273973B1D4E3D3C1935C1C08001127578BB2DBE3C682311616478CE0F8F6DCDFD89542273C84C2E8CE833E2A5B989A5E6889985E16000E294B51433B29150A00030008111A252E2F32282F32313C3D3C47485252555F5C5B58535B606266616466666469635B595C5659595B4488AFDFFAFFF1ECCFB9874120313E4E92CDE8EBC4A5836759432E4683A1A89C6B391E0B1A3E8ABAC7C65FAC906985A2BECFCBB7B1A8A7A8B3BAB8B6C9BFB3AAB4CDE8EBC4A583675901FE865A0707086074696E6B63707B869297918774737687A9CEFFE9AD75585C7DA5D8FFFFFFA569484982C7F9F3D8964B2C35557A8F8A827B5136263269ABD7E4CCAF955321060008225D8FADDBECD483402026498FE6FFFBEEDBD09F471B477EC6E5CD82322154939964628788521000092A515D59462B140805030B110B13182A2C3135353E3C403C453D4542475652545352575D5256615B6061696C6F6C5E61665F58555A4375A8DDEDF1EFE6D3B1773720242B4681C7D7DDBBA17D6352473E4E72A4B192623015131E4486BFCDC5688F857785A5C4CBCFC5B2A9AFA6ADB9C0C4C1CDB0ABAEC7D7DDBBA17D635201FE875A0707087071746066677383868991867E736E758CABD5FFF6BC805C57729BD3FFFFFFB867414D84CFF6F5D2954A1F284C84939498844E30212565A6DCEAD7B98B501700000D32588EACD8E8DC973F1B184585DAF5EEEBD3D0A03D233F8ACCE5CD7D311A52929D6A6289885E1100112E4A60634A290A01020E050E13182429252C323C39393E3C3A3F4B4F4B4E4F58595E515A636258575E645C6362656565656359584B3C6F95CDF3F6F0EDDBBB6C2D0F23243F80B4D2CBBEA5856659493B4579A7AA8B7C391C0923457BBACDB75E86808187A6C0D4C5B9B3A7A4A9A5B0B5BABDB9B5B1B0B4D2CBBEA585665901FE885A07070880787D7074676A788492979081747C8088A8D3FFF7BA775D5B7BA1D6FFFFFFB4693E4A7FCDEDECCC964728284E7E919391805335202D609CDDEED7BF8E58210D0302255689AACEE7CA843C191B3E8CDFF4EDDDD6DB9349224692C6DDD88833225798986F5B8F955012010E264D6759483611030003080910172B27242F31373035363B43404C495453515A505652555A5F645D60626B646E6B626759665C53503B5191CFEFEFEEE7DBBB82460A1F30498CC8D6DBC09875655244373F7DA2AE975B331E0C1D4B81BED1C46C8C5D6D84A6C2CCD0C4BAAFA3ADB8B9B2BCC1B9B2B2B3C8D6DBC09875655201FE895A070708907A70726762747A868F9390827A756E91B0D3FFFBC7755460709BD9FFFFFFAE623C467AC3F1EBDA95472C2A51889091907B532F283468ACD6E2D2C6A35C1900000A2C5B93B0D3E0CC8D3E1C1A388FE4FAF0E4DFDA9F432E438DC7DBD1883D1B598F95605A8697561E040C3455756A502A0A000000010B171F172327313234333B423A343E4245434E5151515750546162655D6560686B68655D5D57595B5B564378A4DAEBF8F2E0D6B77E3B25272E4E83BAD2D2BC9C786357462D3B70A8B5A36732160F24457CBECCB76A84877B8BAAC3CDC8B9C7B5ACA8B2ACB1B7BCB0B6B1B2BAD2D2BC9C78635701FE8A5A070708A06B6862686466758287908F8871646A81A7CFF4F9B87A5B5A6DA0D4FCFFFFB36A3D4878C6EBF8DA9F4B252C5A819B9795754A2D272E66A0D7DDD3AD9354190401042C5699B7DBEBD5943F1A1D3B89DAFEEEE7E4D89840203E80C2DFC68229185B989767688D8F581400112D547169472F100100000003171B1A242A2A342F302C3035404648514D4D525057544E566B6A5C5963666969705F585B625F585A554871A1D7EDF2EFECD4B479370C1A23417AB6C9D6CCB0805A4D48354479A8B29366361D0C1C4584B0D3B6638A817F82A2BDC9D2BFAEACA5A7A7BFBEB8C4C3B8B1BAB6C9D6CCB0805A4D01FE8B5A070708B0757075716E79838E978D8E7B6B6C7B92A8D5FFF9C288645A65A2DAFFFFFFB271424A81CFF2F7D4924922294D8490928D6C5834202F58A7DDE7D4C49B4E16000007306394AED6E4D08F38171C4189D8F9F8E1DCD5943B1A3D86C3CDCF863522599994535B908E59160415356679704F2E1800000000040B161E25242D243435393B3C3B3C434751525C5458514D525F62646062685C586265656162585B514F437BAAD6EEF5E8E3C8AE722D11132C3E89BFD3DBC3A574634C452C3B76A5B19A663B1C0E1C3F8CC1C3BB5F8D7F858FABC8D1C1B5B1ABB0ABAEBBB7B4BFBABBB4B3BFD3DBC3A574634C01FE8C5A070718C07B706B7574707B839593988D7D797991A4D2FFFEB9795B606BABDEFFFFFFB56B3F437AD3F5F1D4964A222751838C8F93735139243168A3E3DDCAB7915B2E0800132C608BA4CBDED18D3C1723458FD7F1F6DEDBD29F4F1D4781CBE3C589371D569F9B5C58888B511002163B63787254301302000007090B131918243030292E2E32383D464547484E565651565158585F625E60666567615D5A6060625C56513C7CA8E4FAFDF7F7D6B87E401E1A2B468DC8D7DBC7A47862593F3D447DACB8A0682E16111F3F89B7C6BD6187747990A0C1D2CBBDB7A5B2A8B1AEB0BEC3C4BBAFBAC8D7DBC7A478625901FE8D5A070718D07A7577796D79868B9B9B988B80767989AED4FFFFB879514D79A6DEFFFFFDAC613C3E6EC5F2EBD1974B2129537E9C97937C4F261F2B5FA7D7DBD7BE99581704010E2C5893ABD9E0CF88431C213D8EDAEDEEE4DFE39147223881C0DFD484352154949365618A94652006183F7D927B5331100000000108080F1D1F201F29322C322F393941444B4653555A5750505A5F595D645F656360615E5E695D586555544380B6DFFFFFFAF0D2B57F39222A2C4B89CAE0E0C09B776A554D3B3F7FA7B3A069491900114081BDCDC86A8B847088A3C8CDCABFAEA3B1A5ACB8B8BDC4BFB7BEBBCAE0E0C09B776A5501FE8E5A070718E07D74656F7674738D9999968174787B8DAFDCFFF8BA7B60516895D1FFFFFEB0654D3D71CDF6F8DC8F4A23244F8A92959471471D162960A2DFE7D8BC9C54230F02122B5A7FB2D6E7D08E44181A428AD5F1F3E6D4D1993B193887C3E2CA8C351C56948F645C8E995F1D011237698E845E30180000000205081313162126212B3436383B3D404C4A494D515656524B56505A625E5F6461696667645F5B585359534070ABE3F5FFF2E8D9B2753E1522314B8BC7DCD3C196785C5743373C739BAB9A6C381100164381C3CFC96586857B8BA5C4CCCAC2BBA1B2ABABB0BEBFBCB7B0B8B9C7DCD3C196785C5701FE8F5A070718F078797175696C7E8D9D9F8E84736D7087A9D1FFF5AD77595376A6D7FDFFFFB569424076C4F1F1C9883D1C2052829799927149381A265EA7D5E6D6BC9F55170000132E6090BBE2E8D08E3D1A164992D9F3EEDCD8D3A14B20488AC4E8C8802F1B5198935C5E83995B22011647798F875D391000000002070E111B21242C2F302B29303B4246474549434B565346534D48535A5E596168686860615B585C5C50524674BAE2FBFFF5F1D7C1783F202B33588ACDE3E1C3A57B605545283974AAA2956E340E14254C8FBDAAB76988888187A5C2D2C4B6A0A9A4A6AEB9C2C9BCB9B8BEBCCDE3E1C3A57B605501FE905A0707180076796F6E6C676E80968F9A836A717B8A9DD3FFFFB78159516A9FD7FDFFFFAB65403F79C5E6E4D08D471926578C99918B6F4C2B1D285FA6D2E9D3C59A6521030005316991ADD7E0CA833D141B4586E1F5EEDDD9D99C402B4584C1E1D77A2E24578C8B5A5F8F94591B001D45749A9567390C00000000040B10192022312A2B302D2F3C3D444C3F4C5950534D534E555D5C5755585E64646B6359595E5B60535B447491D5FFFFF3ECCDA770361023223B82BFE4D2BD997A644F3C2B3473B5AE9265291801183477BCD0C36D9596785798BACFC6BDB3ACAFB0BDBFBAC3BFC0B8B4B0BFE4D2BD997A644F01FE915A070718108479727C70798193AAABA090706F7D91B6E1FFF8BD7C5B54779ED4FFFFFFB8663E4078D2FEE9D093481D26528693928C7C523325295DA2DAD8CDB69B5A1B01000E2A5E8BB7D6E3C7813A1B1E4488D8FBF6DCDACE9D4F2E4486C6D0C888331652949863659297521E031C52819E95623C1500000000060011121C1A23242A2D292B393D3B46454C4E584E525449555D575B60635E605F656162554E5856584D3D76AFDFF4FFF2F0E6B77522061A2B488DCDDDE3CF9F775D5349343D78A7AD9B6D381C121D3D89BFCFC76D8F7E7189AFCCC9C4BAC0A9ADB1B0BBC5BFC3C1BBADB1CDDDE3CF9F775D5301FE925A070718207568696F6671758F9F9CA18A73686B8AA2D0FFFFB77E5B586D9BD2FFFFFCAF653E477CC9F1EAD89E462A23538798A49C764A21131A61ADDEE6CFBF985B18000004255C96BCDDE0C68239150F3284DBF1F1E4DDDC973E244697D6DDD2812C1A509799615D8D95571C001A498FA3915F350D000000000005111D191A1E232A363234313034414B474D515B564B4A52575F6164605E5A63626161635D60595851426AA7E1FFFFFFF0E1C37E39172031488DC7DDDCC8BE7B635449393E6BA6AD976A320406134081B7CAB96B837A7A85A0C3C4C7C8BFA9ADA5B0B4B8BABCB9BEB2AFC7DDDCC8BE7B635401FE935A07071830786F6E746B718A96ADA29D897A6E7286A9D0FFF7C1795A51659AD6FFFFF5AB6141437DC9E9E6D18C42222B58879BA0987B492D21265DA6D0E3D6C199561C000000335E94AEDBE6C8843817163F89DCF7F0E1E1D6994C234886C8DBC987311550958D5E5D939F591D11203E7EA39F784E1800000000000B0C131D21212E2824242E2F353B3C3D41534C58525B50555E6466605D5F6161666A575D686353555B417CAFE5FAFFECEBE3B87529192123478ACFDDDDC49973645740303E78ABB39A693415071F4381C1CDC65D8E7E798CA3C3D4CEB6AEA4A3AFB3BCBBC2C7BABBB4ADCFDDDDC49973645701FE945A070718407372747470717390A19A95896B686D8AB4DEFFF7BD795F4F6BA2D0F7FFFFB05E3A4379CEF6F1D691431E2D53858D99927847301A2B57A6E3E2D5BE8A47250D02082A6692ACD1DED0893917183E8CD7FBF1EBE0D395491D438CC5E2CD8430105498945F60878E57180420497FA8A27041270000000000030A101A17222F2027312F3C3C3F41443E46565B574E515E58585D615E5B636467645E586461625C4F3975AEDDF9FFF9F6E5B3712E0E1326467EC8D7E4CAA37B594D3E252C7EACB49F6E310D0F113A84BCD3C668927F7184A1BCD4CFC8ABA8AAA4B1BAB9B5C1BCBCB5B6C8D7E4CAA37B594D01FE955A070718507D84787A71748294A0A09A8B7D70768BB2DBFDFFBA75515E77A3DEFFFFFEAE61413F71C8EAEDD39546232B5183969F95654D2723375B9ADFE6D5C2995A1D0E000728567EA5D0ECC8863C1E194185D6F4F8EBDCDC95431C3F88C3CDCA86352A5499A46E678E9D561802144384AF9E703E150000000000010A0715191E2B2B2C312B3338384140484B515751504D575C555D5E6367655F5D69605E505359584E476FA7D8EEFBFCECD6C179381C1728418EC0DCE0CAA67B5A4E3E323077A6AE9A733218091E387CB7CBC563837E7187A4C2D0D6C8BAADB3B2ABB9BCC8C0BEB2AAB8C0DCE0CAA67B5A4E01FE965A070718607D7F737775767E8DA0A0A386706B7285B5E3FFFFB47E564C6B9AD4FFFFFFA85F3F4578C0E3ECCD90451B234D83969C8F7955301D25569CDEDFD5C191541C00000A315C8BBCD2E5C8853C15164685DAF2F5E5E1D59744234D88C9D9D07B2A1B559E9B625C87914E1C09234B83B7B07D440D0000000001090C12141C22212E27272D2D393443474443495657514B4E58605C59645E656570675D625E575E4B503F81B5DAFFFFFFF8E8C07B3F1E1D26478ECFEFE5C79B7465533E313D6DB0B89F6A2C0D090D3781BACEC06288807B7D99C3CFCBC2BCA5AAABAEC1BECBC3B8B9B0AACFEFE5C79B74655301FE975A07071870786A6E6A6A6F7E8EA2A59E8A79737587AFDDFFFBB77B594C6499CFFFFFFFA56138417CC8EDECCA8F41222D628594A095795228232760ABD7E0C9C691592A02000528538AAADAE2C883341C1D4187DDF3F4DFDDCF95381C4089CED7C781381D5396946065909557140B22558BADA87B4713000000000005080915211E2922352E272C333940434F54505850564B4B595F625B625C62606462655E60655C5952407198D9F1EBE7E7D9BA7D350127344086BED5D8B9A1765B4F4230397CA9B19E63230A071A4080B8D1C5668D80687DA2C3D6D5D2B9AEAEABADAFB2BDC6BFB9B7B8BED5D8B9A1765B4F01FE985A07071880706E5E605F6A728CA09F9A8A7673778CADD7FFFBC17A534A659CDAFEFFFAA55F303E6DC5F0F0C48F4019254C829BA08B7648221A3066AFDEE9DBC0935325010000295987A8D0E5D68B31101B428ADAF4F8E5DCD19D42193B8DCED7C285261A4B9491605E93935B190A1D4F87B3B47F4A16000000000000050D1718242A353431313337373E3F4952474F464A525254585B605E616363646065615F575C58544270A7E5FFFFF0E8DFAE73321A282E478AC8DFDBC7A16E5D604740447AA8AF9B6C341B081F427FC5D2BB5D88726D6EA6BBCEC6BEB0A6A6AAB0BEBFBFCBC2BCBDB4C8DFDBC7A16E5D6001FE995A07071890716B687062607691A1A99C906669718BA9D3FFFAB672594E699BD1F4FFF8B067403574B7E0E5C78E4A2225508B9F9D92744B2919285798CFE5D2BA915726060001295587ABDBE1CD8F3E181A3B91D6F5EEE1DCD9904020458BC6DDC9852F1D509D965B698E985D220F245787AEAD8745140000000000000F120C131D2529302B352B3136413D46504E52515051494B57616063605E656B645F5A6259565056447AB0E5FFFFFFF3D2C292350D16234F8FCADFE5BF9A6C5B5A492C3A70AEBAAF742F0F0F103388C0C6BC628176727EA2C7D4D9BEB8ACA3A699B1C1BFCEBCBBBBB9CADFE5BF9A6C5B5A01FE9A5A070718A0736C696F6A6B7A95A6A7A18F70726A87ACDDFFF8BF7C534F76A3D6F5FFFAA35E474A77C8E7EAD78C3F16214C7C95A28F73512F1A345DA1DBDBCABA915B2303000831557AA6D0E6D0853D19213F8CDFFDFEEBE4CF9341244384C6DEC77D2F205A959B675C8B9A51200C214B8CB5B5814419010000000000081116141A1B21282A343334383F45494F4D53505750455659625B5C5D5E615B5B605F596158554B4370A3D8EEFFF3E7DBBD7634141E294787CADCE1CD9E75614D36333D7EA9AB9B6C2B0D04103281B6CFC064827A6C83ABC3CBD3C7B3B1A39FB4BCC0C6C2C1BAB4B3CADCE1CD9E75614D01FE9B5A070718B08379736E696F7790A7A49F957F6D778AA7D1FFFFC27E555167A0DDFFFFF6A45D3C3B6EBEEEEFCF8745101D4C8DA1A38F76553219225CA4E0F1D6B798612300000E325880A7D1E1C181391716468FDEF4F2E7E4D29C4423438DCBDAD4813620519795625D8791511605285594BCBA8449180200000000090D1117141C22282924242E3035383D41424F5752575154575C55635D6060625D64696C615D5554493D75B2E6F3FBFAF6DDBE802F1D2327469FD0DFE2D0A57A655242353B78ABB8A06B330D0D164580B5C9AF5F8176697E9AC2D3CBC0AEA5AFABB0B4BCC5C9BFBCBDB2D0DFE2D0A57A655201FE9C5A070718C06D6B646C6065728799A09F826B605F88AEDBFDFCBD795349649BD4FCFFF9A75D36427DBEE3E5BC873E1D224D82939D9A754A21172667A5D5E4D3C29B5F190000142E578DB7D8D8CD893E16193D8AE7F0FAEDDFD49C461E4280BADBC9853A24549A9064608B9B5F190C2E5797B4BA874C130000000000040E1212161F2423272625293C41423C444A504F56555A575351555E626265615F5E565B5D5A555154417CCEE7FFFFFFFAEFC48E41191E315695CAE7E3CD97765B5448304078AEB39E6B2A0D0E1D3D87BFCDC46D8876747DB6C1CECBC0B1A3A8B2B9BDC1BEC4B7B7AFAFCAE7E3CD97765B5401FE9D5A070718D075746D68636D72889BA398876D677283A2D7FFFFBF71504B6598D4FFFFFFAA59393F7ECDE9E7C8894315275E8CA09C8F79452617195599E2F3D9BC9B5D1A00020D295C84A5D2DDD08F3317174192D3EEF2E8D9D8924C234788D8DFCE87281C539E9E615D868B57180C295E95BEB78C4B140000000000000909161421272A2D2D2B2D30303942464A4B514C4A4A505A5B57565661656A705C5E5F5E5C55524F4777ACE6FFFFFFFFE5B77E3B272A244A93CADAE1C89F6B5F563D33407AA4AEA75F371A150D3786B1D5BE6283736979A0C7D3CAC2AFA6AAB0B0BEC4C6C4C0BAB4B1CADAE1C89F6B5F5601FE9E5A070718E06C6C645F6161788F9FA39B8870646F7DA7D5FFFFBE7D534E6D9CD2F9FFF2A161383C7ACCF0F2C7913B232D588C92918B72522A1B2558A6D5E8D5BD9B5E170000092E5B8CAED0EAC789390A184491D9EEEDE7DFD79845253B86C6D3C2843A235A9C9C615D8D90541C0C1D5596BFC78F5315000000000000020F0F1225282C32272630323B3D3C40494F4D4A4751596361596062626264675F59554F615852553F72AEE4FBFFF7EFE1B9743C10212E4F84C8DFEAB89F79594E453F4B83B8B4A6742B1701173C8AC0CFC267806C757C9DC7D2CBC1B1AAB3AFB0BDBACBCAC2BBBCABC8DFEAB89F79594E01FE9F5A070718F078776765616A768DA4A19A816C667290AEDEFFFFC072514E61A4DDFFFFF3A963394176B5ECF0CC8F4817214E849A938D7B4B2A202158A4DAE2DCBC9D5621000005285A87A8CCE8D5833C131C4989D7F4EADFDDD29D4C264786CCDED385281E50999957618699531D08215792BEB98A50170000000000010C0F101314162027272B342F3C3D454346585C5258504F566065605C63655F6160615C5752544C4C4C75A4D9FEFFF6F3F2BB782C0919224883BCDED9B89C7860483E32407CB1B8976E3617101D3D87B6CBBF607E6D6A81A3C4DAD6CBC0AD9DAFAEB7C6C6CDBFBFB1B5BCDED9B89C78604801FEA05A070718006D6E717263707A8DA9ABA8896E677285A9D9FFFFB56C4F4E639BDFFFFFF6A665343F78C2E8EED8893E23284E8A9EA293784829121D55A8D4DFD9C599541F0000092E608FAAD1E8DA90380D133E80DBF8F2EFE8D59B3C173786C5DED0882B165C9A9F635C868E581509265FA2C2B98950150000000000000008111B1D28292E23202D303E3E3F474551554D4E4D524F595B5359616360615D5E58575653514E437FABE8FFFFFFF7DEBD8145161F305988C6D9E2CB9F765D53392A2E70ADB39F69421705173782C1D2C668896A647BA1BBD3CCBEB3A7A7B3B6C3C8C1C9C3BFB8BEC6D9E2CB9F765D5301FEA15A070718106C736A696061778BA8A39D8F75636A8CAED4FFFFB96C53586AA3D6FBFFF19C5C343F6CC8EEDED68F431B2A5D8D9C8E8B6D472016275EA8DEE9DAC5A15A1D00000A295485A6D3DAC786331615458EDFF8F8E7E2DC9D45203F8CC8D9D18826144D9B925C6389925C250A266599BFBF8C531C000000000008030912111C252E2A262E313833383C484E4F5451534D505C595C5A62655D61646662615B53575353386194CCEFF8F3E8C7B2782E0F1C294986C1DBE4C19B6E584B3829307BB3B4A36E2C10111B3984C5D0AE5C857D6674A3BBD3D1B9AAA8AEAAB7BFC3C6CDBDBCB7AAC1DBE4C19B6E584B01FEA25A07071820838077766872839FB4B9B19868696689ABDAFFFEC3735B506B9BD0F7FFF99F5A33447FC3E6D9C48843232E638395AA9A7B4D26182B55A3D4E7DBC499531F0000102B5E8CB2D6DBC479301718408ED6F6F2E8DAC89E42294889BEDFCC7C261D589B9C60669594530F092B5E9CBDC196491800000000000611151516181D1D212422273343423D454C5758535148525C555E615A5D6263655E5C645F645154584B73B1E4F7FDF5EBD8B476431C1936438CC9E0E2CBA8815D5541334377B8B49A65320400133A85CDD6C66682787482A3CFD2D3BFAFB6A8A9A9C0C3CAC4C4C5B4B8C9E0E2CBA8815D5501FEA35A0707183074707465636D7B89A8A5A1817A717686AFD7FFFFBC664D4C639CD6F6FFFAA95C2F3477B3E9EFC67F401F2659909D9895784F28152752A0E1E1D3B496571600000031589AB9D7E2CB823F17133889D7FDF8E6D2DF9857274687C6E1D38435275C8C8A5C638C93541B0A1A4F96C7BB995B23000000000005100B10101A1E2825262F322D343A3A3D46474E5253564C525D5B595A5E626A6868616657545B5D4A3E6AA3D9F3FBF6EFCEBC793215172B4883BEDEE0BC9C7B57453E37407CAAB1A667370C0D153D85B6D0BF5A7F6F5F72A1C6D3D7C7B2A8ACADADBDC6C4C5BEB9B6ADBEDEE0BC9C7B574501FEA45A070718407C757375746C7A96A39F9E7F66666B86A9D8FFFFC175504F649DD5F8FFFBAA5E354678C5E8E7CB813E132048889DA09074502815245B9BD5E5D6C2955415000007235A8EB4D9E6C77E340F144287CFF0EDE5D5CEA54B233D87D1E2CA882D17529A9F60618B9C591803215CA5C0C49154100100000000000509141C202A1F2228303439373B3B3F474B50454A4B4C5A5A5F5A5A5D62595D5D57595C605E57584274A9E2FFFFF2F5DFB87B2D181C2A4D94C3DBE0E3A773564B3F303870B2BD9952291A08144388C5D5CB678C7768709DC5CECEC4B2A2A5ACA3AEB8BEC7C0B8BEBCC3DBE0E3A773564B01FEA55A070718506C6B666968677A8BA5AAA3846D676F7CA0D2FFFFBA74514868A0DAFEFFEE9D53343A7EBBE1E6CE8D4E241B578A9A9A95794E2D1924599ECADACEBEA25D23000003236393A7CCDAC7873C11194592E2FAEEE3E4D0953F21408CBFCFD18E392D5897955D5C8892531A0A1F50A5C1C29B621A000000000000080E1A1A201E2224292B2D2D33373A3E494F4B4B4C4F4D525F575D605E5C62666666585C54524C503F6EA6DEFFFFECF0D6BB7B311A18264E96CBF5E6C59D71535143343A76AEB69463331306123B81BDD5BC6A7F636A7EA6C5D4D5C8B0A4A7A6ADB6BEC8C8BDB7B9B4CBF5E6C59D71535101FEA65A070718606F6F6B606363758FADAEAD8D69636680A1D0FFFFB1654B466998D5F8FFF3A760353573C5F3EBCC8D3D0E20598F9EA18C79522B132D5C9CDBEBCBC2935D1C000004315F8AA8D0E4C887390E1D488DE1FBF4EADDD49B411F4288C6DCCD88321E5898A26E64899451170A27559DBEC58E4C1300000000000104111918121C232E2B32312F353A394C4A49564F51495358605B5F555E6069615F60595654514D514681B5F3FFFFFFFDEDBF803C1B233C488ACFE6E1C39E786255382E3C71AAB99F6F3113081A3F8BC0C8C566816A6777A6C5D1CFBEAEA2ACABBBB8C0C7CABEB9B6B5CFE6E1C39E78625501FEA75A0707187070777977706E8292AFB0A5867265768FB0DFFFFFC3734F50609BE0F4FFF29B5F303B7BCDE8E3CA904315255C969E9D9671462E282D68ABD9DED2B1905A260000052A5882B3D4E0C78A391116428FD5F7FAEDDFCEA036203F80CBDCCD862D1E5994925E619097531B082465A2BCBC8F5519000000000000040B14171A29302C2933292F3D3C3D3B4C4B53565350535856605A5B5F5D606161585B575957474E476FAEDEFFFFFFF2DEB66F341F24255193CAD7E6CA996F6459432D316FA8B29873381005194380BCD2C55E87706B729CC6D1D3C4B2A4ADACABB8BDC4C4BCB1B8AFCAD7E6CA996F645901FEA85A07071880696A736F67687787B2AE978868625E8CADDBFFFFB5764C455F9BD4FFFFFC9E4E2C3678CDF2F0D68A44242D508190968D704F211D295AA8D6ECD1B58F5C1B00000830578EB1C8D9C88A3611153E8FDCF2F4E4DDC89945234185CBD8C77F31205AA192645A8C95541D132462A7C9CA9D6122000000000000070C09121D212C26232229383D3B383E484F5754514848525561545F635E5D5D59545B5F555952574075ABDBFDFFFFF7E3C384371323273F86C0D6E1C39B745645362C337CB5BB9E753D0C0D133B79BAD5C1638877687899BFDDD2CDAEA5A9ACB0B5B5C9C9BDBDB6C1C0D6E1C39B74564501FEA95A0707189073706C6C60647E99ABAFB48466637386AADDFFFFBF794D4C5B8ED1FEFFF69E562E4576C5ECE3C78D3F2227538C9D9A8F714F2517255BA1D6E3CEBC985D21000005264D84B1D8E4D789391318418AD9F6F0E6E8D99D401D4088C5D9CE7F29205796A16B658D8F5C1D0F285DA1CDCA96551B0000000000010108140B12212B23202C24353B3F3B46444D4F4C4F504E5653515561626B626D6459545B5E5350514384B1E8FCFFFDFCE4BC7A2E25242B5393C9DADCC8996B5F533A27457AADB89D6D2D120D12387FBED8C56183686E78A6CADECBBDACAEB1A6B7BABBC9C9C1BBB5B3C9DADCC8996B5F5301FEAA5A070718A06D796F7163737D8DA7B1AF8C6E716D82ABDFFFFFBA714D4C669ADBFEFFED9C5E333E80C9F1EACF92411426558DAA9897723B29111C54A3D9E1D2C49A551D000005256288AED8E2C77D35111A4690E1E9EBDEDEC69542263C87C6D7CB8A311A5A9D975D6A9599581C0C2A5D9EC0C697521C00000000000007111819202A27242A2C2C2B373B41474A4A4E473F4155585C5E5A6363646163605A5C5B59574F4A4374A2DFF7FBFBFAEBC2783119222B498ECBE4E7C3A0695A5040334485AFB3A06C310C03103789C0D9C1607B686379A2C0CDCDC2B3A7ACA9ACBBBCC2D0BEB9B5B0CBE4E7C3A0695A5001FEAB5A070718B07C76706C5F6A788AA0B4A997746C6D84A6D2FFFFB4754D4D669ECFF6FFED9E56353D74CAEFE4BD873D24275897AB9C8B70441E0F2264A5E4E8D3C195521A000000265B92AAD7E0C17A3A161C4693E4F1EDE8E5DD9642284488BFD2C382341D53989C5D5F919C561901295EA1C4BF90531D000000000000050A1718181C212223303437383C38414E565751594C485860666056635F6263605E555360575F4C3E6FB5E3FFFFFFF5E3C1773C231F2A4184C1E4E1CCA06C5A4D432A3F77A9B7A3692E0E000D4381C3D3BA5B79686B709ECAD3D8C1AFA1A5ACACB7C9CBCBBFBAAFACC1E4E1CCA06C5A4D01FEAC5A070718C07570716A6A617A889DA29B846B6B6880A0DBFFFFBA6846455F9DD0F3FFF8A75F394075C2ECDFC68E3E1428558A9F9D92784F3022245D9AC8DCD8C29F5915020009295A87ABCDDBC28B3C1516478CD7F3F0E6D6D29945264C92CFDCC6842C155994945E5F9498531309265D94B8C0945718000000000004080618131D23272A28272F2C3744353B4248504D544D504F50545661676262606A5F615D615950514674ADDFFBFFFFF4E6B8864019292D4B9ACEE3DEC89F755C4A3F2E3E72ADC19F70371405143A7FC5D2BC617A716E78A2C4D2CEC1AEA3A9A3B2B2CCCACBC4BDBEBCCEE3DEC89F755C4A01FEAD5A070718D06D6D6B666469728CA8A6A687695C6486A4DDFFFEC171524866A2D6FCFFEE9F5F2F3C71C3EDEFCE8E4B132E5A8797998D7C4B2A1E1756A4D9E5D4C5A6611D03000823548BAFD4E2CA842C03134198DCF9F5E3DAD09342213989CBDDC388302360988F645E8791541D12345C96C0C39C53190000000000001012131A1F232029242332333E4541414647554C535152535957605E635B6065615F595D5A575547357FADDFFAFFF7F7E2BC7C2D161E1D458BC7E3E7C59A7256523B30447CA9C29E6A320402133E8DC1D3B36488706B83A4BFCBCDBDB4ABABAAB6BAB7C0CAC3B5B0B1C7E3E7C59A72565201FEAE5A070718E07C756B6F63667894B3B6AE8E6B627082B1E4FFFFC1744D455E9ADCFFFFE9975534417CCBE6E3CC8C3E232D5893A2978D68441E132A57A4D5DEC4B39A631E0000102B5988B1DEE5CB873B1419398ED8F1F6EFDAD99A43234183C4D3D98B321B59A09B5D6296A3551C042D5DA1CEC893562500000000000008090F151B1D28251E282938343237484450524C504D5252565B5B6865636169615B5356594F4E543E729ADCFCFFF2EFE5B479390F24344C93CFDFE7D19F6C52443E2D3E79AEB8A364270E0308377AB6CCC25E7D6F5B72A5CCD6C9C4ADA6ACACBCBAC2C3CDBFBBB0B6CFDFE7D19F6C524401FEAF5A070718F076827472636D7B99B4B2AF8E6E687C91B0D7FFFFC3704A4E6098DAFCFFE998502A3E77C8EEEACC853F2426568E989D8F714B22142567A3DEE9D4C2A45D1A000004235593AACFE5D18B3C10183D90DBF1F1E5E3D39944253885CDD8C38930245F949B655E8B93521A003364A0C7CC9D5C2006000000000003060A0D171C212526232D262E3E4B3D3C4456484E455451595B5D66615A526166645D5C635B52594379A6E3FFFFFFF5E7C67A3F1F272E4589C4E9E4CB9974594F4333417AB0B6A4712C0D03173483BDD1BF607E676D79A7D1CFCCBFAFABAAA9AFB7ACC3C3C0BAB4B4C4E9E4CB9974594F01FEB05A07071800747675666369728FB4AFA08877696E87ACE2FFFFB86B4244619DDAFEFFF09F50333E7BC6E8EFD08D3B17245984A097927248231C2B669BCEE0D9C89E61240000012D5F8DA1CFE1C6872F1313388BD8E8F0E2E3D29442233E86C1D8D28934215B92915F738E975617072360A9C9CB9852120000000000050C12140F1D2220292622242C35403E3C4C525049504A525C56546162646168655D61625A5C5454594570BEE7FCFFFAF0D5B9762F19282B458DC4EADEC2995F51523A2F4286ADACA068311904193C8BC6CBBA72836A6B73A0C7D3D9C3AF9EA7A1AFBBC4C2CBBCB9B6BAC4EADEC2995F515201FEB15A070718107D79675F5F70718CABB5A8896A606E89B8E3FFFFBB724A4A659FD0F4FFF19C52314281CEDADFC4853A1C3164979C988F724725142A5FA4D4E5D6B8995D1E0000022A5393A9D6DBC88233101F458FDBF2EEE4E8DA91412A3A82BECAC78231235F9B926662859461210B2E5FABC8CA9359260000000000000006131514231D2926223231363C3F404D4D57515647495760615C595F57566065615D5A5C5555554270A4E3F8FFFFF5DAAB7D4211192B4585BFD8E3B7916D4E49352C3B7DA9B0986A380E0C173B84C1CDC159836B63759AC3D7D4C5ADB0ABB2BEBBBCBED5C9B9B3B8BFD8E3B7916D4E4901FEB25A070718207370676B616B758CAAB5A3807067728AA7D7FFFFC8794A47679DE0F6FFE79259314983CDE3E9CA803C19265287A499976D472E1A286098D0E6D3B4945A190600001E5B8DAADDE4CD88340D154994DCFFF5E6E7DCA040203B7FC5DFCC8A2F1C598D9D5C5E7E8D5718163265A5CACB9E541B000000000000090E151D201F2226252A253238393238434948484B4C535B5963565F605E5B63635D5C5D615655533E8BB9F0FFFFFFF6EFCC853D1723304C96D2DCE0C29B6F5A4B3D383E80AFBE9D6E29140611397BC0D1C26890685C7D99C7D5CEBFB0A6ABB2BBC0BCC7C9C1B8B4B4D2DCE0C29B6F5A4B01FEB35A070718307D7F746D5C6B7A8AA8B8A894726E6A84ADE6FFFFBE6B4F46619FDBFFFFF197542F3571C1E7DCCB8B3814295D9EA599886F44200F1B5998D2E1D5C59C5C19000000256391B2CFDCC9823819133B8CDCF3F6EEE0D3914320448EC0D7CB8833215C959258599397581F0E3059A0C3C4A156260000000000050C1311151D12201A242A282F32333C3D43414E4B4F4A565E615D565B616562615956565959565459466FA8E6FFFFFFEFD5AE78341B1C244585C3DCDED09F7E68573B2B3A7AACBCA05F2B0B091D3E87C0D1C1647C72636C9FCDD5D1C2B2A6A8ABAFB8BEC4C9BFB3ACB3C3DCDED09F7E685701FEB45A0707184077737572666C758DACB0AA86705C647CA8E1FFFFB269413C659BDBEFFFEA9153313B85CBE6DECB8A3C1A295B8D9B9B876C40211221679DD0E5D2CC935F280000062C5A88B0D2E6C9853813184287DBF2FDE3D5CA9E41203583C5E1CD8034255C9F9869678F9452170D3264ACCACB965A1500000000010A060B131617252723232828292C343C4042444C565444485C575554665E6068625F625D57555F4E564281B1E8FFFFFFFBE5BE753A2526234E8BC9DDE5C79C6D5E543D2E3D80ACB39E672A150F154086BEC6BC687D7963719EC8CFCFC2B5A7A1A6AAB2BEC7D4C9BBBCB2C9DDE5C79C6D5E5401FEB55A070718506C7570736E6B7D95AAB5AE9273686A89B3DFFFFFB26A4B465DABE2FFFFEA9755303D7DC2E5E4CB813D1D2055949DA1866D4C211424559DD1D7D4BC99591E0000092D6097B3C8E1DD86350F163E91DCF9EDE2D8C99038244495CAE8CA8A32275C9890605A87824714052C649FC1C9A15C2200000000000008131412231D2D2C1F252B2F2F3A3D3F3E4852514F4E4F5655565B5B64595C5F616261605B60544E3B6EADE9FFFFFCE9DFBF77301420354A8BC8E4E6D2A175463C38283C77ADAB956F331A001A4891C5D1BE5E876D6277A0CEDCD7C6ADACACA7ADBDBFA5BCC4BEC0B5C8E4E6D2A175463C01FEB65A0707186072736E6A6267818FB1B1AD9877617087ADE5FFFFB76E414A6494DAF8FFE0995536427ABFF0ECCB853E1B285D95A39A9572431D16195598D6E1D6C19B5C1E0500072A5C92A7D3DCC9922F13194185D8F1EEE5D7CDA041234990BFE1CB8832175F9D9C5B65898A521B0B2965A3C4D49B571800000000000A04131010172123252824292F353948463F4F5243484648555A6059615A5F5F5E5F59615C5D5A4C53438BBEE6FFFFFFFFF4CD7F3A1925355398C7DFE5CCA97E5E4D432D467CA8B6B474361B1412448AC4D4BA527B7460749FCBDBD8C5B3A0A5A4B4C3BCCCCBC1BFB7B2C7DFE5CCA97E5E4D01FEB75A07071870767E7B7467677D9AA8AFA6846F666B87B1E9FFFEC0794E4F629EDBF7FAE69C4E304179CEE7EAC88D4322276099A5A78962381B181F58A2DEE1C7BE8D5325000000215A8BABD1DFCB883708164897DEF9F7EAEAD198401F3484C4D7CB8336275A9595636898A0591F142061A9C4CA9856140000000000030E0709111F20242026292F31363539404C4F5A4A4B4F545654564D5B5D636265625F5B555A5C5055427ABBEDFFFFFAF7D7AF7D38141C214B8FBFE9E7BF9D7056493A2F387CADBEAD6D33140C133C88BDCFC55D7B6A807D9EC6D5CEC4AEA9ADB0B1B7C7D0CEC2B2B3B2BFE9E7BF9D70564901FEB85A070718807272696C5F686B96AFB09F8466616784A8DDFFFFBD6C4C486391DCFFFFE7A058314484CCEFF6C8863514225D93A49C8F6D3D18092560ABDEE2D0BEA0541100000729578BACCFD9C286420F113A93DFF9F1E5D8D0964225408EC7DBD0812C2D60AAA06A65888B4611053069A2C9C59F631B0000000000060B0E0C1C16121B281F262A2D2D3B403948484A4A4A524F55585B625A61635F61625F6563625855544B7CB7F3FFFFFFFFE8CA813D24243D5698CCDBEDCEA66D5D5246304380B4B9A26A300F010E4385C1CEB55A80626375A6CBD5D9CAB8A7B6ACB1BBC5CDCBBDB6BDB0CCDBEDCEA66D5D5201FEB95A070718906E71696C6A687A8DADB5AE8B635E6A88B0E6FFFFB97649485A96D3F0FFEC9E583F497EC5E3E3C58844172856899D9E836D3F1E162661A5E1E6D3B5985813020006295B88B3D1D7C582370A164586CDECF2E7D7CA9743275192D4DBBF7A2E1B50968B5C5D8899521B0D31649FC7BE98641D000000000001060C131D1C1C252422262E2F363C3C36384E4C50494A4C566359555A555A666D635F5556615855523E79B6F7FFFFFFFFEEC17B381D2524448ABBDADFD29E715C4937304480B2BB9D672B1008153F7DC5D8C25B86685673A1C4D0D1C3B6A3ACADB8BBC2C3C7C7B9B6AEBBDADFD29E715C4901FEBA5A070718A0827A736E5F6B7894AAB3AA8C69636586ADE0FFFFC57146385295D6F4FFF59B5A2F4786C5EBE3C4884013256498A4A18D6D3F1F132760A7D6E2DAB3995516000000305A8CACDCDBCA763118143A8DD5F3F5ECDFD2983B254490CBD4CE812C285B9791655A92904C0E153268A7C4C5A55E2001000000000005180A0E151E282529282F352F353B3B3E49504D4B485058595A5B595D64676351565A635F565B54486EADE9FFFFFFFAE6C1813A1821285290C3E8E4CB9E63584B4433427CACBA9C6A2C0D06173E85C6CBB763816F6A70A1C1DAD1C6B4B2B3B0AFBECCC7D8C0AFADB4C3E8E4CB9E63584B01FEBB5A070718B07A79737567637D9DB3B9AC8863636686AEE3FFFBB66A484E6B9CE1FAFFDE9A4F374181C4ECE1C2843B1B1B5A8A9B9A8F6F44231C2665A5D7E1CCB68E521D0000002C6694ADD7DEC5863B17173A88D6F1F6E8E8D09744213B89C7D9CA6F2E2063A08F5A61848F511405296DB5D1D3A5652600000000000F150D10162015202926232A3135423D3D48504E454E4D4E545C5F58545D5D656168585555575C5853407AB6EAFFFFFFFDE6C18538141C264C8FCDDFECD1A27453513C2C4482ACBA9C6A351709033685BCD1BA5D7E6D687AA3C3DDDCC9B0A5AEB1B6C1C0C1BFB7B8B5B3CDDFECD1A274535101FEBC5A070718C0766F67675F63758D9FA9A08D615C6782ACE6FFFFB86D453E5A9ADDFCFFE3894B30477DC4E1D4C3883C132C6AA0AFA98A6D422513315D97D0DED3BF9D4F1B010000255F91ABD8E8CD833911174793DDEAF5E7E7D28B4422408DC3D8C17F363163A295605D8D8F5818102D64A9C4C59D5315000000000006091314151C151E22342C232B3235404646455048454852585D5C5E5A60666B5F5D5B5F5B554E554F3A53A9E8FFFFFCF7E9C27839132A23428DCFE7E8D3A061554E432F437AA9B7A16A35130D103381BFD8B5646F6765709CC7D5CDBFB2B0A3ACB6BDBCC5CEC0C1B9BECFE7E8D3A061554E01FEBD5A070718D07E6C686A66647891A9ADA686685E6C85B3E6FFFFBF784943689EDAFBFFE0934D313C7BC1E4DABF893E192C648C9D988C6D4022152A5CADDEDDD0B797581900000321598EA4CBECCD8A3A1614458DDCF6F9E4DDDA9649204089CBE9CB7E2C1B5BA09266678B904B12123066A3CFCB9F59250000000000000D12131917171B282B27262932383C424A47554D484D48525C5E65615E5A53635E5558525A5B574F4366ACFFFFFFFFFFE7BE7F3E1D2F334D91D4E5E1D3A26D57524131447EADBC9C69300902113885C3DAC06C956A4E729FCDD5CABFACA8ACA9B2BABEC3C9C1BBB6B9D4E5E1D3A26D575201FEBE5A070718E0726B6E6C5A647694B0B2AC906C58638CAEE2FFFFC16A464861A4D4F5FFD98B4E2E478ACFECE9C27E3F152D62909889816A3923162A67A8D4DACEB99A52080000042A6089AAD8D6C1763B1A1F3E98DCF8F6F1EED49240224183CADCC77B26195BA19564648B894D1A0A3671B7C5D3A45F12000000000001051619161C1F2B1E1C2535412E40424847474C4946414D58505255535C605D6363665B5B5158504E3E83B8EEFFFFF5F9DEBA77370B262A4893D0E7E3D3A26A554B37273D78B2B79B703611051E3B88C2CDC15473626288A2BBD7CFCBB2A6A3B5C7C2C4C7C6C5BCB3B5D0E7E3D3A26A554B01FEBF5A070718F0796C6F745D647E97B5AFA7916A63667DAFDDFFFFB46846465F9FE1FCFFEE92543B3E88D0E6ECC18944172A67909C9490653B1A092A64A8DEDFD3C39A571800000129698FABD9E5C5893C0F173E89D5F5F5E5E1D7963F233685CED8CE83261B57978F5862838E541C093067A6CCD2A35119000000000002000D0E191D1D2326282A2A283A3F47473E47524A4F4551515259565F6165635D6059555C645E53544576B8E9FFFFFEFAF6BEA533171D2B4B8DCBDFE6C69776554837313981ACB49D672E1506043F87C1CCB2577D6F697FA1CBDACDBBA3A4ACAFB2C3C7C3C9C3BFBBB9CBDFE6C69776554801FEC05A07071800727175706B697994ACB3AD9270696D90A6E0FFFFB46042425FABDAF6FFE286512F458FCCE7E1C4804315265FA0AA9E866342161B2160ABD6D4CBC29B5415000009315A97A5D8EFC4813A0F1B4388DCF6F6E5DCDA94421F3788C4D2BE7A291D63AA8E555E9397520D073668A0C5CD9F5E18000000000003070E0F121A161F293331322A34333940474B464B4E505461585655575A5B615C5D5D565D56644F4B4276B2E6FFFFFAEFE3B26D31182C334B8FDBEEE4BFA3685540372D3980ADBBA3692F0303193B87B9D0B85A836F646FA3C8D0D4C6A197ABAFB0BACED0CBC5BCB5AFDBEEE4BFA368554001FEC15A0707181071786E646B647798B5B8A58865626C8CAFD7FFFBB266444B679EDBFAFFDD8C48254488D2E6D8C58A4120275F90A79D8A66391C10245CADD5DBD0B798560F0000002B628CB6D8E3C17F3E19124290DFF1E7DFDBD79A45233D94D2D4D4822A1B5D9C926763878E4B0E05256BA3C1C59E61250000000000030E0A0F1C1E1D1E212B292D2F3237373E4A4B54534C454F56605D5957574E63645D5B58596352474A4670A2DFFFFFF7ECDAB277311012243F8ED5E4E9C59D694D45362F347AA2B79A6C370E09113B84BECFB95B75696377A6CEDAD7CCB9A9A0A2A9BBC3D0D1BFB1AFB8D5E4E9C59D694D4501FEC25A070718207E76706D62657589B0ADA483635E6E81ADEAFFFFBE744B3862A3D8F6FFE1904B2F438FDAEBE4C77B3811275B9FA3A3915D311E16276B9AE2ECD0BA984C11000000345F90ABCDDAC688280B1B4A8ED1ECF2E1E2D298381E4494C7D2C67B2C2B66989561698F864914083172A9C6CFA26B2800000000000401070C161B1F26292F2A2D2E33403D3D4046514D4E4E4E585E5B5D5E595F565A5C575C544E4F51513D70AEDEFFFFFFFEE7B876331A252A4A93CCE1E2CC9D6C4B493C2F4A89B5BCA16423080B1D3B86BECFBA5266635D6CA5D1E6D9C3B6A2ACB3B8C0D1CECEC4B0B2B4CCE1E2CC9D6C4B4901FEC35A070718306964605955587083A1ADA18865505C86B1DDFFFAB55C43456EA7D3F2FFD78D442D3E82D0E9E2C6832E12296799AC99836B3518132366ADD7E0C2C38C500E000003306090ABD7E2C1813C171D418BD1F2F7EAE2C19047214291C2E2CA73261E5DA292605D949146120B356FB0C4CE9C59160000000000060E1012112226262028242A2D343136434348594F50455053565A5058625C5D5F5C58526161594D4D4A71ADEBFDFFFFF0E6BD703913182C4B87CAE6E6CD9E624C48432C4383AEBB99632E1811194285C2D1C054766F6970B5CEEFD8C0AB9DA4A4B2B8C0C5CCC3BEB9B2CAE6E6CD9E624C4801FEC45A070718407274706D646B8092ACB29E857166678AB2E8FFFCB262444669A1E0FFFFE4864531427DD5E8E7C7813D132167929B9992643C19182A67B2D6EFCEB48A4C110000002E6B93AAD6E4CA87330B193F8EDDEBF2EFE1D5974420468CC5D3CE71252765A5905D648D8C45100E3273A3CDCC9E561A000000000000141312191A141C1A21222D32323E3A38464C4D4E4A4347565C645B595D6263686A5D5B5D5E58574C3971AEE7FFFFFFFCD8B176401B1E1C4D94D3FFF1D29968513C342D3A80B2AE9A6929150C164884BDCAB85A7567607DADCCD3D2BFA79FA6A9B4C0C7D1CEB6C6B6A1D3FFF1D29968513C01FEC55A07071850807975766B6E7F96AFB9A484675E6A7DAFE7FFFFAF6943426EAEE8F7FED7904D30437DC8ECE6C07A3C1A285E99A5A284623A2318276AB4DCE0C4B9994B0C000007316A8DA8CEDAC3782D121A478BDFF4F8ECDAD28F3B1F3F8BC9DBCD7A2524619B8D5C6A938F471009336EAEC9C799571100000000010905131A1C1A1F221D1E252929343B393E4054524A494254615B5D5A5C6162615F5E5A55555656464F427DBEFFFFFFFFFFE3C784341C23274B93C8EAECC99767514D45284089B4C09C72301008162C8EC9CFC35A836D6686A5CFD8D6BFB3A5A3A7ADB9C3C7CFBEB8B4B7C8EAECC99767514D01FEC65A070718607C6E6B61606B7DA2BBB39E8068666483B5E3FFFCB56A4441649EE5FAFED7864E26417AC3E3EAD1793A1C306FA0A492815935160F2B6CB8DCE4D2B98B4E130500062F6596BFD4D0C27B2A151C4999E4F3F8EAE6CC8B40194189D2E2D0753323629A8F61688F92511917346FACD2CF9A57160000000000010A0E1117201D1E2A1A1E202D3B3B3D423D44474446404F575A5D585E5D6160585C6061615D57504B4381B6F3FFFFFFFFF0CF842B131F365490D0EDE7CFA26450463B314285B7BE9C642B100A1E4594C7CEC15F8069637FA9C9D3CFBDA69BA8BBBEC3C9C7C4BAB9B1AED0EDE7CFA264504601FEC75A07071870726D635F5D687090A9AEAD8D6B676A83A5E1FFFCAF6F494364A9DFFFFFDE894829428CCBE3E1BF7742192A60A3AC9A8D61381B192E6EB8D5DAC7BC8E410C000006296B9EB9D5CDC37F31101E4191DAF1FAEEECD38C391A3D8AD1D6C7722A2265A0925865998C49130B2C75B4C7C5A15E22000000000000001213101723221D2A262D2F2F383C3C4B4A4D4F504E58525A5954555B5A60605F5958595F55564E437EBBEBFFFFFFFBE7BD722E151C2A599BD3E3E7C3986F5043372D3A7BA8B4C7722D0D01103E86C1D0BE577669686FA2CBE3DAC3AFB1ABAEB4B7C8DACFC9B9B3B3D3E3E7C3986F504301FEC85A0707188070736766646C7798B3B4AE8A685C738AB2DFFFFFBB6A444464A8DDFFFFC783452C4085D7EDF0CA783419326C919D97845A3318152C72BEDFE2D2C29547090000052C6A9BB5D3DCC077351414418AD9F4F5E6E7DD913A1E3F92D3E3C9782E215E9992606C8F8541130E3673AECBCA946121000000000000070B100E1F20171B202734373E3D3C464A4547454E46555C5555565B59596063625C5D5E53544E523F7DB3ECFFFFFFE4DDA5703B2424294995C7E3EAC59D6D494333314581B7C3A465260906174188C6DAC7617D6A6575A1D5E4DBD9B9A8AEB0BBC6C4D1C0B7B4ADADC7E3EAC59D6D494301FEC95A070718907C726C65575E7790A8ACA1855F636E91B0EEFFFFB45A3B455DA2E0FEFFDE854026428BD1E6EBC77C3A1A346BA7AA9B825D2917142F70BADFDDD2BD95460C0000042A658EB0CAD2C2713714194A90E1EDE9E1ECCE99441B418BCDDFBC6E29226097995C608E8F531B193E73AED5D4A45620000000000005121819191413111A1E2226303736364446484E47474F5450565865665C5D635A595B5C5D5F525152407DB4F4FFFFFFFCE2B16E3A1B212B4497D6E4E4C8A4654E473A314083B7B39D624F1501124182C5D8B75679665E7EA7C6D5CEC4B3A6ACAABDC2BEBDC3BBB8B4BCD6E4E4C8A4654E4701FECA5A070718A07170625B4F58738CACACB48C6460688AADE8FFFFB26B484970A3DCF4FFD4823E264E8BCAE5E3C8732F122D669AA68A8367391C0D2962B2DBE7D7C18A400A00000C325E8CB2D8DAC37A3111164F98EAF4F2E7DED18B48234688C4D6B775332F6B999366729A934912023878B3D0CC995919000000000002080E0C17221F1C1A262A2A363130383A3B4B504E45404A505862575A5D5A5967615A575C5C5B52503C78B8F3FFFFFFFFE6B672312623033C90CDE8F1D49F6E553B3932498ABABD97682F10090E3B84C7D1BF5988746B81A3CBD6DAC8B2A6A4ABB9D9CAB4C1B8B1B2B7CDE8F1D49F6E553B01FECB5A070718B0797D716F686B7C96B5B5A98A6D5E6990B7E7FFFFB16A3B4569A7DBFFFFD27C43344A8AD5E4E2C57E401733739F9C8A81622E170F236EB9DBE2D8BE824809000005266D97B2D8E4C2782E11214297E5FAF2E5E2D4993F1D4891C3C8B278231F659F925F689D84421513416FB7CBC89E541A000000000007100E0C1C1B19221C1D20292F34393C3F4149524F4F515254595A5E5D615A6C66605D5452574D4D4D3F70B2F6FFFFFFFFE7BE742D1E2F2F4896C9DEE0C396644D3A3923448BBCC79D5C270B000D3E88C5EBC33E74606687A7CDDDD5CFB3ABADAFBCC8CBC9CCBDB4B4B4C9DEE0C396644D3A01FECC5A070718C0746E68645856769AB0B8AC8562606D87B1EFFFFBAE5C36466DAADCFFFFD3855136418BD2F0E9C57C30163469959F947D553817133174C0F0DECCB48840100000103B6F96AFC6D5B175341E1D4499D6E8EFE8D6CB8E43234489CBD4BE762C295FA7935C65848C4D0C0A3872A8CCCB985A1300000000020F0F11151C1E1A1A2026242C272D3B3647514D55514E4D494F5B5D5661655A5852575B595D6058585A406FA9E8FFFFFFFFEBBD7A3419211E4899CCE7EAD09D634449431E498CBCC19C692A0E0021478EC7D9BD52776B63789CCDDFD8C7AEA7AEADB7C1C6CCCDC3BCADB2CCE7EAD09D63444901FECD5A070718D07A7F665C5A5A708BB1B8A9856F616579A9E7FFFDA9633F4969A0E5FBFFD4814B2B448AC6E7E0C67A3013327798A197825B351B152D6CB6E2E5D4BB8B4309000011376899B8CFDDC577280B16489CE4E9E8ECE3CF953A263B86CBE4C6762728659F975E6F97914317143B70B0CAD696561F0000000000020110121D2520201E2823242E2C373440465050474F484A595D56515A595965625D595B5D5D584F533C7BBCF5FFFFFFF8E7B77A3C3C2E334C98D4DFECCB925944463D35477AAFB998622709041E4988BCD2B753756B6E79A9CCDDC5BCADA7ABB6BCC4C5CCCFC2BAB1B3D4DFECCB9259444601FECE5A070718E07277686E60647690A5B7AA7E61666F8ABBE8FFFDA56C3C416BABEFFFFFD0793B2A4B94D6E8EEBC7029162E6C9AA3998561341C123871AEE4DBD2B280491500000F2A659BABD4E5C8722A0518489BDAF6EEE3DBD08C39204990CCD9BB6C2827639D906168828B3E1A0E30789DCBCE9B58170000000000140F0D1A1E2520251F27252429362D344347504E4A4B4E4F565559625B5D5D6262625D5B5650564450398ED0FFFFFFFFFFFCCE8C49262D32529CE6F3E9CE9D724D4737395592BBB097663014121E3F89C7CCBF5F7566637FADD3E2D8BBA9A0A7A5BCC1C6CDD4CABBBFB9E6F3E9CE9D724D4701FECF5A070718F06F7372685E647487A6B2AA8D6A647383B6ECFFFFAF5F424361ACDEFCFFD37E4625428BD7E5E1BE6F34202F69A1A1A3835A32160E2A77BDE5DCD1B090460D0000103F7399ABD4E2C46F2B131D3B95DFF3F2E1E7D28C3D214C92CDD4B860201F6FA38D616D8F85431010397AAEC7BE8B521700000000000A0D151B131623221E221E282B2D31373F42465152504A5C56585C5F5D68655A5E595D58595A514E493D80B7EAFFFFFFF5E4B87247232C325594DAEFE6C4945A45463E334B83B2BDA25A250F041A3C84C1D2B85881746180A9D3E4D6C8B4A3ADAAB3BEC4C5CBBEBAB5AEDAEFE6C4945A454601FED05A070718006A686E625D5C6A92ADB5A77B675F6B85B0D9FCF3A76643476CA4DCFDFDC97A482E4A97D4E2DBC17D361E38749EAC9B7C5B2A0D1D2A67ACD7DAD0B887400E000002326EA0B9DADFC571300F1D4EA0EAF5FCDCDFD692431D428FBBD5C86D281D6AAB9B5F6C907C3C08193C7DB5CFCA93510E00000000000011110717141B22262B262D30343C373E474852524C4D49515759565D5355657162595F5C535252523F73B6ECFFFFFFF2E5BD70361A222E468ED5E8E4CF954F413328293A82B5BD9461290B0819478DBACCC05D7C686279A9D3D6D1C6ABA6A8B0B2C2C4C9CBC1B9B2B2D5E8E4CF954F413301FED15A0707181070706D615E637196B5BAA180655E6F8BBDEDFFFAAC6044446FA4E6FFFFC8773F234796E1EFF2C86D33182969949E8B75522E12132B68B2E8E8CAC3884A04000006387298BCD6DCBC732B05144B94E5F0F1EADECD9243234493CBD4C1701F2869A68A5D6B8E81370B0E3C76B3CDCDA2551D0000000000000110171425202224261F272834383D434E454F4D453D4B57605E5A5D6755625D5D5755505B56524B4176B6F2FFFFFFFAE5C47C361C2A314A9AD1E4E2C69A68483F37344E89B8B5A862220900144090C5D2B65D7C615E7BADD0DDE3C5B1A4A8A6B4C0C8CFCCCABE98A7D1E4E2C69A68483F01FED25A070718207C746F705D5D7392B4B6AB7E5E5C678CAAE2FFFDAE5E414B6DACEBFFFFC1743E2B4384E3FBF8C67336103269A4AC937C602B0F11356EB0DADECCBC84390A00000F38709AAED8DDB16E2A111D469ADAF9EAE6E4CA923E2A4D8ABFD4BD66262364978B5C6B9A964B12123E72ACD3C396501D0000000000080E10120E1B211F2426282D3A3136363E4249494A504851575D565A5F695D5864685F5F5E5B5352523D74ADECFFFFFFF1DFBB5E2A1220284B9FD3EAE3C09662493934334690BBB897691F1008104087C2D2BE6379696B74ABD3DDD9C9B09FA2A0ACB0C8D4D2C5BAB6B4D3EAE3C09662493901FED35A07071830746C6B5C554F7391B0B3A07B5F5F7188B8EFFFF29D5A373F64A8D4F6F8D684452B4492D8EEE8C37A361834729AA59A7B592E161C3377B9D7E5CDB88445020000003476AAB6D5DAB3772D10164897E5F2EBE8E3D3943C1B4994C8DACB6F212573A498616B97813A0B04367FB6CACC935D12000000000004131A1B191712262524262B2F32373E404445434647494D5B575B58565B55595F5E615C5B5A5D5251427EC1FAFFFFFFFFEAC27A3A18262D4C9EDEF5E9C79D6856433F324184BABB924D14000A13468CC4D8C25F77626579A9D8D9DDCDD2A5A3ADBBC2C8D0CBBBB1AEB5DEF5E9C79D68564301FED45A07071840807B78635D657895B5B4AA83645A718FC1EEFFFCAE6442466AACDDF8F4C47D3B2E4C7CCDF0EAC5742812336DB6B89E8658351C102E74C0D7D6CCB98B410900000D3C77A9BBD7D3B275260F204999DAFBEAE4E0D98B3619438CC7DEBB6E2B2378A58E54628277400A0C3A78B5D5D59D5B0F000000000009060C161514192B1D1E2E242D3B36364346474F4B4952485861605F5D576163655F5B67625858534E4079A5E5FFFFFFFFE5B97330251D264894D0DEEAC992624F3E2D375097C1B9995C280A0115439DD2D5BD50785F6278A1D4CCD3C8AEA7A7A8BBCED3CAC1C6BDBDBDD0DEEAC992624F3E01FED55A070718507E7C6867515C7B8CAAB5A280605E7093B1EEFFF3A1543F446EB5E1F7FFCB7C452F509AD3E6EAC06F26102C75A3A5907A562418193171BCE3DFD2BA894210000010357296B4D3DFAB6A2705194D95DBF5EADFDDD288371E4393CDD9C06C3025689E905E68919143180E3471ACD7C9944F2700000000000813131215181F211D281F21302537353B43464B464F4F56615D5B5053535F61605E5958545E5457543B88C2F3FFFFFFFFEEC871372630225EA8D2EBEACA9E5F4A3B3D394F90BDC1985B271601114795C5CCBE5779736967A7D2E1D9C0AEA3A7A4BAC2CDC9D2C4C1B8BDD2EBEACA9E5F4A3B01FED65A0707186079786B6855698098ADB2A8825C5B6F8CC2F7FFF8AC57393F64A3E3FFFDCB7841294799D7DCD3B67828172F72A2A192814E251B0E3074C2E4E5CDB37E480C00000C387AA5B5CCDAB170230B1E4C9CDAF1F2EBE5D5953B214C90CDDDC96D212064A38A5B6D91843E0C144479AEC5CB97601A00000000000B1019191A241E20182024253030384047504C5355484D4F5B5B57545F5E58625F5F5D5C56575A504C4374B9FFFFFFFFFFE4B677371D252E4A94D7F0EEBE8E5A403E38345090B9B99658210F0D1D428DD6DBD0607B6A6377A9CDD4D3BFABA0ADAFBCC7CBD6CABBB9BAB5D7F0EEBE8E5A403E01FED75A07071870716972605A5A6D89ACB4AB8E5F53638EC1EBFFF4A65C374165A6E9FEF4D074442A4995CFE7E1B67034172D72A3A9987E582D140E357BB6D9E1CFB18742010000083977A4C0D5D5BE752C0B1C4888DBF3EDE1DDD3923A214691CFDBBF6C1F2172A78D5C6C947D3904104389B7D2CE8C47110000000000090911130E14262628252338312F33393D3E4E4F4D484A4C4C525C585D6461665F5A56545E574E4B544679BEFAFFFFFFFFEECA79332C33365994D6ECEEC9935D4C32343C4C8DC0BD9E5E301500195090D3D5C3567B6C6881B4D0E3D2C1AD9CA5A8BFBDC7CFC4C3BDB5B7D6ECEEC9935D4C3201FED85A070718806D7469615A557597AAB0A97B5A5F6A88B5EAFFF4A7664A466FB4DFF8EFBC6E3E2C5399DBEDE3B46C2F1B3C78A69F8A744D33140A3573BBE8E0D7BD843A0A00001139789BB2D0D2B781351319479DE2F0E9EDE2CC8A3A214891CAD8C569242872A1895C698C7C4811153A82B2C8CC9B6016000000000510100C171E201F241A1A1F2D292F383745464F4F484942454F54645C5C5E565B615D6359565D5A504B4486BBF7FFFFFFFFF9C07B381D322F4D9EDDEEEACF9D67523E42375191BBB29B5929090B144A8BCED8BF5C7367667DAAD5E3D1C8ADA8A5ACB2C0CFD0C9BBB9B8B3DDEEEACF9D67523E01FED95A070718906F6B6C63555A7893ACBAA97C5C596B83B0F0FFFFA157414A6CACE2F1FAD3753D274193DCE8E5BD792F162C75A8A598794D29110D2673BEE6E5D1BF84370400000C377CA4B0D6E1B46A220D18539DE2F7F5E5D9D08C4124498AC6DCBF5F241C68A39C6169947E3E18164479B4CBD39F54160000000000000E1116111B1B221F26252A2829332E3B3F425951464C4D594F5358555D596B555C5B5F61585B51514684D0FAFFFFFFFCE1B4762F151D26509CCADEDCC5905544312F334797C3BF9559250604204098CCD3BF5F8274757AABCDE0DDBFA5A2A6A1ADBBCCD0D2C9BAB8B7CADEDCC59055443101FEDA5A070718A0736D696054566D92B1B7A38663526692C1EDFFF5A8633F426AB0ECFAFAC9753D305196D2DEE0BA722C183676A7A79D7D552209142F7ABAE4DEC7B7803A050000073C7CA3B2DCE2BB6C3013164A9BE3F7F0F0E8CF863C244993D1DDC378201F6AA49460698B7A2E0F0B3677BACECD97561800000000010B1D0D17111F15191D1E292432313740423A434644424646555862625C536565575C5D655A5A59564B4680C2FFFFFFFFFFF3BE7F3720302850A2CFF1EAC58F61493F3A334F8FBDB8965C240F0C204693CBD8AC557E606172A5D1DCD6C0AEA6ADB1B1C6CDD0CFBEB3ADAECFF1EAC58F61493F01FEDB5A070718B07C6E6C66585C7583B0BFAC81675B698BBAFAFFFCA7553A4163ADE4FFFFC56633244F9CD3E5DDBF6C330C3875A6A99A7C4D260B0A2F70B0DCDEC8B58A3E0900000F4176A2AACBD1BF762E141C50A5DAFCF2EFE6D488361E458EC8D6C1752B2D719C91696E9484410D114089BAD5C5864D11000000000000060D1A14181C28251C272A283942403F464654454742515D5A5C5A5F6264695F62606152575548493C79B3EFFFFFFFFAE3BC73321A20224A98D1E7E3D19258434636355A8AB2B99453200B0B144284C0D5B6587A615F79AED2E7D2BCACA0A6ABBAC3BBC6C2C4B8B5B3D1E7E3D19258434601FEDC5A070718C0707B6F5E56627292A9B3A07C584B648BBCF4FFF7A8553C4266A9E0F8EBBB773F2D4C95DFEBE5B2722E143577A4A0917C4E291605276FB4D3D7C5B98840030000103976A4B7CED3B4642511184DA7E1F8F4E9E3D0873D225493C5CFB46925296FAB95657993853809113A78AECCC79455150000000005091B0E11182A22221E1B24232B38312E3F434E5350544A4956525E5568615A5E5D4F5A5F6056595053437AB7EEFFFFFFFFE7CB7D3F1320294E98D9EBE7CF965645332F375896BBBA9550190D07184295CFDBB75C81697083B5D4DED9CAAD9EA5A6BBBFCEC6C7C3B8ACBAD9EBE7CF9656453301FEDD5A070718D073826D6A57546C96BCB2AA835A55608DB7F2FFEEA5553E3761B2EAF2F9C976352B519EDFE7DEBB6E281B3972A2A4997951230F133176C0E1D4CCBD823C0C00000F3F7FA2B7D6D8AA6A290A10509FDBEEFEF1DCD896361C4190C9DFBD6F252A6B9D8B6870997E3A0D08387EB8D8DB9B5416000000000006101D13131C242222202A293032323D3E424852514D4B505350595D4F5C5F646B615B5E55555658564278B9F0FFFFFFFFE6BB74391B222D4B94CDEEF0D39B5B3F363A345B90C0B69965270B061B428EC5CFAE55735E6581AADDE3DAC7B19899A1B2C6C9D4C9BBBAB9AECDEEF0D39B5B3F3601FEDE5A070718E07B7A6E626166759EB3BAA07F61536A87B9E9FFFBA55F3E446CACE9FFF8C0763C205299CFD9D9BD7027123377A5AF997B4D21090F3176B6DFCFBBBA8A490D000006387BA0AEDADFAF6726121A49A6EAFEEEE3E2D88340254794DCCDB467252A71A38D5E72987F380F163C79B4C7C99A561E0000000000010D101C211D1620211E232C2D2F363C414A45494C454649575156615C645D6661585F565354584D513F89C4FFFFFFFFFFF2C57944242F2F59A1DBF2F2CC9B5F483A33294D9AC4B995601F050517419BCAD4B34E85786E7CA7D1E7D2BCA7A4A9A7B6CAD3CACBBBB4BBB6DBF2F2CC9B5F483A01FEDF5A070718F075746B615C63799CB5ABA185654E6884BBEDFFFEA457333064A8DFF8FBC36A3C264DA6DAEDE3B36B2A18346D98A59280582C16103077C1D5CBD5B7874708000011427598B1D0DCB6712B171A5099E8FBEEE1E5DC8E3B14488FC6D0AC6920276E9C99616A95843514193F7CB2C6C99058180000000000050A0F0F14281F281D1822262C313133464E4C4943455157595E5D5A5965616164615856585B5854483F75BAEEFFFFFFFFE7B06E341B292A4B9FE2E1E3C590603B362B315597C6C0944E1D050612479AC0CCAF5E7F5E5C80B0DADFD5C6AEA1A5B2B5C8C7CEC7BDBEB4B7E2E1E3C590603B3601FEE05A07071800717C6A5F56597295BBBEA27963556985AEF3FFFFA95835436AB2E2FDF1C162362C469FDFEFDEB86A2C173676A5A895754B200B122276BEE2E3D8C28C3C050000053F799EADD1E1B7742A0F1E559EE0ECEDEAE1D6833821438CD3DDC06D2722729E8A5664967D340D134086BACBC69755110000000000020D16161A1E2C24201F2123272634363A43514942455050525B60565F60555B65605F625E5A5050553B72B8F9FFFFFFFFEAB368301E2D365CA1CFE8DBC394613F34343F61A1CABF99571807011A5095CCDBB0487161697BA7D6DEDAC9B7A4A9A3BAD2CDCBC4C2B5AFB5CFE8DBC394613F3401FEE15A070718107074686356627192AEB9A5806252648CBDEFFFF598542C3560A6EAF7FCC76F41385A9FCFE3DBB96F2814387DA1A79A7C55260C0D2F73C1E0D7C3B5853B0900000D3977A5B6D4D5B26D281026579BE1F8F1DED4D2913A1A4389C6DCBA6D1F2D71A28B5A74A3813B0E164386BBCBCF96531B00000000000C0E0F1A18251D1B22222D2A243130363C403E413E4348465150605A525A525F615B64605C555151523E83BBFFFFFFFFFFF0CC7B301F242B4CA3D9EAE3D598563A3432314F97C3BE8D521D080A194794C3D3BA4C72676885BDE3E2D5C1AFA3A0A1B4CED7C9CEC6B7B1B1D9EAE3D598563A3401FEE25A070718208687746153596D9DB2B2AA856450638BBDF1FFEE9C57374666B0F0FBE1AF6A3A304C9AD3E8DCC36E2E132970AAB1967B4A2610113280BBD9DCCAB7843D000000053980A2B4D9DAB36A28161E43A2E2F8EEF4E9D8903B1E529FCCD6C6681A1B70A892627195813D0B0A4287B7D6CD894F1500000000000B13181F221C20201F22212434362F3B3F4A4E534D4641514C52555C60635F58645C5A5F514D5552483E75B4EFFFFFFFFFE5BE763924252A56A1DDEDECC28D5039382E40518DBDB697551F0F0C203F8DC5CDB05D706D6878A9D9E2DEBDA899A5A5C0CBC9D5D0C8B5A7AEDDEDECC28D50393801FEE35A07071830746E67564B587A94AAB0A47A5A4C5F87B3F1FFF9A35038376AB8EEFDF1B565372E48A0E0E9DBBE6E2C10306E9FA2957A4F2619123372BFD8DCC3BD8E4106000007487E9FA8D1CEAB65260A0C45A7E7F9F2E3E2DB8F3D234F94CCD9C2621E2574AD9D6073927D3A0C154684BFD9C6915512000000000006111C140F181419231925252C3137353C484D4F51494350595A5952575B5C60635B5E585655594B57447FB7EFFFFFFFFFE3B075361E1D2A5E9CDFE5E8C58B56413029345097C5BA9651250903183B92CBDBB65D82706880B3CCDFD4C4A59BACAAB6CCC5DCD9AFAFB4B2DFE5E8C58B56413001FEE45A070718406D75706655576C8AAEB9A57E5E4C628DC5F3FFF7A95B373C62B1E1FAF6C3703A2C4D9AD2EDDBB9752F143577A9A7987945200E1D447DC2E4DAC6B57E370B000011407D9EB1D2D49F6B210A225BA5E8F1EBE5E9D58639183F8AC1DAC36D212672AA9265789278390D173E80C3C7CC974F180000000000050E111D1E1D1D182329272A2B2C3638404948474F564B52574F53565A5E59695E5C5D5654534F4D47478EC0F9FFFFFFFBE8C0712E152031509DDCEDE8C69D5C42332D32559EC8B9974F200C08144E92CDD6B65578665C80ACDBE7DAC7B3A0A7A3BDCBCECAC6C4B2AAB2DCEDE8C69D5C423301FEE55A070718507C6A6C5C565A718CACB1A27E5C526084B9E3FFF2A35A38446DA8DFF7F0BF71402856A1DFE8D6B571321230699AA692724B241B1F3C7AC5E0D5C0B47D39030000124A87A9B9D2DAAA591806124DA6E6F0F6E2D7C58333274096C9D9C65F242778A4955D779D843B171D4883BBCACF8F54150000000004071116111624172025242727232F3938404448504C4D50504D595B575759655C5E5D5B5551524E4F524183BEFFFFFFFFFFECBE7A3E292428449ADFF4EBCF8D5B4639313059A4C5B3925A170701174B9ED6D6BB5372595D83B2D6F8D8C4A9AAAFB0B3C0C7C8D0BEB8B5AADFF4EBCF8D5B463901FEE65A070718607774645C53567698B3BA9E755C4E5E80AFF3FFEC9A5134466FB1E1F8F1C271402B4BA3D5DBDEB66628132C76A3B1917350281114387CC0E5DFCCB17E3B06000014417CA4B7D7D5AB5C26121856A5DBF6F2ECE5CE8F35204596C8D5B466242F77A3916074A080350B144782BECEBC89461400000000010F15151B181A1A1B1C26222A282A2D38443D4B48474A46515A56585B5B5E57645E605C5D5C5F5C53494178C2F4FFFFFFFFE2BF81351E2B2C53A1E5F2F1C28958422F322E4D93C4C49757210C08195195D3D9B457766C657ABBD6DAD6BFB4A5A49BB2C2CBCBCBBCC2B3AFE5F2F1C28958422F01FEE75A07071870747664565159728BADABA48261606A8FBEF9FFF29C50353663A2DDF3EFBB6C382F5BA0DCF0DBB36727113478A9AA946C451C11142E7CC0D9DBCEB48239080000063A7BA3A8D7D8AD6B28162359B2E2EFF9F1E6D28E3A1F4495D4D6B0661D1B649E8D5F68957F310F114480B3D6CF9D591700000000000D19141C18181B1B1A20192126312D393B42444F4F465055505F5C58585D5E656867605A59595759554A8DCEFFFFFFFFFFF0B9713E1B342E5DADE2EEE7BD89564233363A5887C3CB99561D06011B4D94CDCDAE5B716C5887B2D6E3DFC5ADA7AFAFBBC1C6D2CDBDB2ACB3E2EEE7BD8956423301FEE85A07071880787D6D5C50607094BDBEAA75574F698CC4F2FFF6A34D30416EA9EFFFEEBC703829519EE1E1ECB863310E3878AAA7947E4A200E10397FC9E0DEC9B181360100001B4688A4ACC7DDB46424111E559DE3EEF2E2DECE8931145094CCD5BF6D21236EA7916567967D3415184183B5CFCF9052190000000003101B161A1B1919251F201E2A2D2D2F3B373B3D403E3E434C595958575A5E626365615A596158564E46447AC2FCFFFFFFFFE6B674381F252C5DABDAEBD7C18F594030323A559EBEB89153220007164F95D2D5B2557C66697EA8D2E7DAB7A69FADAAB9CDD6D2C7B4BBB8B8DAEBD7C18F59403001FEE95A070718907A7A706558667294ADAEA07B63646F88C2F8FFF5AA573B3868B1E4F2F7BD69352846A0D2DDDEBD652C142D7CB0AD9E734B290A123087C7DFD2BFB87F360B00000D3C7EA1B6D1DDAB6624171E4E99D8F2F5F1E3CF7C321F4387C8D3B76421256EA990637898813910154689BAD6CB94501400000000000612181D15171E1D161F1E2C3332383842484648504C44454F54604D5150595F675C5D57575C57514D4277B4FDFFFFFFFFF4BB722C222D3151A0E3ECE6C3985332362D3A5D9DC5BB9D5B130B0018459FD0D0B4516E595C80ADE1E3DEC7A89AA3A8C2C9D0D0CABBB7BFB1E3ECE6C39853323601FEEA5A070718A07F846D6167637E96B5BDAF795B4C5C88BAEFFFFFA35A44466EACE7FFF9B56C39345FA1CEE6E6C16B2B0E3677A4B2906C552D14103275B7E0DBD1B67F390000000C4685A1B7DBCDAC6C1D0B1A509FDFEDE2EAE1D57F38204A92CBD4BA5F1B2A6FAD9261779C7F2B11205490BED1D09A4F1800000000080E0610151616201F1D18222A2E2F2B2A373A404C4B4B414A505E585B4F636165675E54525A5A5C4F503B7AC5F7FFFFFFFFEDBC733A1A233557A6D8E9EBCA9157433837365F97BAC0934F1B0E081B4894CBD0BB547C6B6280B6DDE1CCBD9192A5A5BCCAC8D1D4C2BDB2B5D8E9EBCA9157433801FEEB5A070718B06D6A665A4D48658AAEB09F7F604E5689BAF3FFE99E57354670ACE2F7F0B7613A204BA2DDF1DEB76427112A71A1B59B7A4F2611213388C0E0D0C2B179330300000B4686A4B2D1CEA962230D1C59A4E3FFF5F4E2D88C3B26589BC3D6B5661E2E70AA91636A8F7737070D4C87BECCC195571500000000030D11171710121C191A252930242E393E3E43434D4D4F454E4D5B534E545F54645E5958555855514D524480BAFFFFFFFFFFE9C779421C283C5098CFEFE2C88B5336313638539FC6CD9E561D0F03104193CAD0B05578675E84C0E1DAD5C3A8A6AAABC5C8CACCCCC0B9AEACCFEFE2C88B53363101FEEC5A070718C072726D614D547586A2AF9C76534F6480BCF2FFED9D5A343F66B2E6EEDEB16D3C2958A2DCE6CFA9621D0E3A78B0ADA57B5025101A3987C5E1E3C2B77F3B00000012467DB6B8CECEA15E1C102B5BA6E4F2F6E5DCCB872F1C4996BFD2B8601B256BA2885B769D80350623508FC3CFC49A5319000000000006121F1E1A1C201E1F1A1F24262A333E414550594C4D474D58585653545C5C5A5F5A5554585B6351513E80C1FDFFFFFFFFF3CB7948213049518FDBEDE5C58C4B3C3134375A9EC6BF8C521B090C1C4D98C7DAB3557B666C86A8D2D6D6BBA5A0A8ACC4CDB4C9CCC1B6B8AEDBEDE5C58C4B3C3101FEED5A070718D06971625D5159738DA4A59F7D57545784BFF5FFED9B4E343E64A9E4ECF0B77A412F509BCFDEDCBF64291B3D7BACAE9873421809102F81C7E2DFCFB77D360B0000124483A2AACAD2A9641F08164CA2ECFBECE3DAD3893B1A4B8ECDD2B36B26327AA39660719478350D103B85B4D0C186531C00000000090F180C1C1F1E1023222523222C2E333D4146484846454B505656605E5E525B5963575B575D5C5650503B72ABF4FFFFFFFFD0AD6B2B17212E539BD2DFE5CF934D3F3833325394C2BE8E592208081A4281D2D7BD5476605F81B4E2E6D9C4A79AA1A7B4CACBC3D1BEC0B2ADD2DFE5CF934D3F3801FEEE5A070718E06D6A625A48546F93ABB1A27955506288BBFCFFEB954E413D66A5E1F5ECB7603031589FD1D3DBB2662615307BABA995664C20100D3086C1DED5C7B47C430B0000123C78A9B4D8DAAE6C2811154F9EEBF5EFE8E7CC83322E5298CFDEAD5F1B2876A08E607496763E0E1B3C88B8DDD193460F00000000000C141B13161C1A1D1E1C27272D2C3536323C4C504E4A404D5A5659525765585A5F5D62545B5854514A387CBCF8FFFFFFFFEBC0763D0F25335EA7DCEFE9C181544137373D5A9FC9B88E4E1903021C4D9ECBCBB04F6C596188B0DBE8E1C4B096A1B2C1C1D0D1D1C6B1AFB6DCEFE9C18154413701FEEF5A070718F06C696A5E494E6791A8AFA17354486586C5F7FFF1975339436CADE3E7E8B96536234AA2D6E9E2BA6421113081ACA997784B1E17183580B5D6D9C8C185430600000A458AAFB9CED8A55B22161C4DA5E7EBF7E2E1C5842D1E4B93CBE0B75D233779A38F606B8B752D0A124B90C5DBD18B521000000000000B1D1B1B182419201E181B212A2C3639393F42454947484F525E5D5C5C5658625F615F5B55524E50543F7ABEF7FFFFFFFBF1B16A371E2B3358A9E2F3E5C68C643F29323A5994C5C391470F07061D54A3CFDABA55685D5373B5D8E2DCC5B19CA4A7BAC8D4CECBBAB7B5ADE2F3E5C68C643F2901FEF05A070718007367685249566F81A6A89C76524F6391BEF7FFE8955137416BB1E3FFEFB167372756A5D7E5DEB56424122F79B0B19176472208102F7DC3E3DCC7AD742F0000000E4281A4BBD4DAAC601D0D1C4EB3EFFFF0DBDFD78638264F91C7D4B6611C267AA78C676B927B30111B4486C1D4CE8D501A0000000009091C1516181819141B261C23293036414845464A4040454A52525659625D696B605D66605A545D52574099D9FFFFFFFFFFFED1984C28314662B1DDF9ECCE9D5C3B343B3E609FC1C1975B1406101A4A9BCED0B55273676C78B9DFEBDAC7AC96A5ABB6C2D4CFCEC9BAB7B9DDF9ECCE9D5C3B3401FEF15A070718107A7A735F514F6F89A8C0AC845E566289C4F1FFF09F502B3861A4E4F9EDBD773A33569FCEE6E7B5642206337AB2B3956E4A270B134279C9E4D8CBB079310000001D4A81AAB2C6D3AA5F170F2357A6EAF4FCEBE3D185301E539CCFDDB4612529799C9059689884380A154A8EBFD3C69D501400000000000D131A231C1C131A1C0F131F2531373D363D3E46484A424B51585C524F504F5F5F575A5A6063514D514079BDFFFFFFFFFFF0B47A4227353261A8E4F2DBC283563A2D2A38639EBFBE8C4918060B144797CBD1B45269676A79B8E3E7DDC3A79EA8B0BEC7D4CDD0C2B0B1B4E4F2DBC283563A2D01FEF25A07071820756C6B60574F6F90A7A59C7350476487BDFFFFEBA251343963A6E8F5F2B85F312C589CE1F2E8B45F24082D7AABA89872441B0A163C84B7DCD6D0B8743808000012487DA5B5D7CBA25E2010275DAEE6F0EDE9E7C77D351F4DA0C3D0B15E21377EB0916167967C2D1418488DB5D0D494501200000000070D11121216241C2612282621283037373A493E4147524C535059525C5B5C575D625A57565B5C5C50523C7FB4F8FFFFFFFCDDB26D352034364D9ED5EDE4BC845037292E3865AAC1BF92531B0003184093CED4B1546F5D678DB6DBE2D2BAA9A4A7A6AEC3CAD4CBB8B0A6AED5EDE4BC8450372901FEF35A070718307E7668574C597195A3A8A17D53546387BBEBFFF09851363C67A5E9F5F1B75939254B9ADAEDE7BB6424163277A1AF90714A1908153B8AC3E1CFC8B3783600000114418DADB0D4D2A86725121A53A8EAF5E9EDD5CD7E3211438AD3DBBB5E1F2E7AA4956A64987F3510214C83AECCBD94531700000000081A181A201F241E17221E1823282E30353E4446533B454249535A5557555C57655D5D5B5D5A5C5152544886C1F4FFFFFFFFE1B17133212B2F56A4DBEBE5C27E5137312E3A5BA3C7BD914F15060E21498FC3CEAE4B6F635F7BB9DCEAD9C2B3A8A8ADC1D7D4D0D0BCB7AEB7DBEBE5C27E51373101FEF45A07071840807D70614F506B8BA8B8A3715D4F6287B7F3FFF3944F333E669FE3F3EDB66A40324EA0D2E9D9B961190E337AADAD8F70451904113981C5D8DBCCB67A31020000164E88AAB1CED5B46323071C55ABEDFBEBE5E6D28A3A1D488FC9D6AB52192B81AB9267789A733503124485C6D2C4965319000000000411101518211D161E1D0D232C343434403E463E45484B454E50535F59515A5E5E625F57584F514F544D3F88C9FFFFFFFFFFE6C47F3225252F489FDFF7E7BB894E44383B3967A9C9C79E4B1704071D4D91CBCEAC5776655D80B6DBE6D7BCA99DABA5B7B4D0DDDABFB9B5BADFF7E7BB894E443801FEF55A070718507776695645546E94B5B49E764D4A628AC1F9FFF09A4934395BB5E1F0EBB56431284C9DD6DED6AF592017367AAFB397774221130D388BCBDBD7C4B3783206000014438FB3B3DBD29F63200C1F5CB5E2EEE7E5E6C87E3519489AC7DCAC651B2778AF93677590742D08165089C1C8C695541600000000000915181D15211F2614181928262C363B39434A4A4044474A525D5457585D60655E5759585B57514F4A3D84BDFBFFFFFFFFEDC2783A1A2D2E5DB3E5EFE9BF7D4C4230273A5D97C2B69444120105184E93D0DCB7567464657FAFE7DED6C4A591A6A5B6CBD3CCC5BAB6B3B7E5EFE9BF7D4C423001FEF65A07071860656F685E4E4F6690B1B4AB7C4C4A5E90C2F3FFED915032335BABE4FAEFBE68332743A6D6F0DAB7611F142B79ABAD9972471F11193783C9E7D1C3B27B3504000421497DA8B7C8CBA5591F0C1E4EABECFCE9E5D4C57A35174692D3D1AE5E20307AA99466709E7C3D131A4D92C3CDBC974E1B00000000010B13191413171F1F212421252F33303230414B514C4C4242505356565B5A63636261625E59575659503C7FBDF7FFFFFFFFECBA73322A2A2D58A9DEEFE7B88850392D30325DA2CAB98C4C1F0706164397CBD3AC4D74687083ACDDE2D3B6AEAA9DA5CECBCFCCCDBCB3AFBFDEEFE7B88850392D01FEF75A0707187071716B513F556E8CAEAE9B7647465E90BFF5FFE8903D283B64ADE9F7E4B15F352857A1D3DFDDAC5D23153F81B2AC9D7A45180E1A3D85CBDECEB9B4802F000000164E8AB2B0D8D0A4551B162453AFE0F5F3ECE3D18230213E96D4D1BC601B307EA18E667391722D08145894B9C8C19C5314000000000410091915191F1C1B1C21231F29283741444B4C4B433F404553525B4B5B5F6160605F6160665458544D3B7CC8FFFFFFFFFFE4B6793E252E3451A5E4F0E8C189583F30342F5AA5C8BF8F5D090519244D99C9CDB94C6D636176B4D9E7D1B7A89FA8A5B8C7D2D3D3BCB1B2B2E4F0E8C189583F3001FEF85A07071880737D614C42506C93B3B2A2705149557EBBF9FFE98D50303F61ABE2F5EFB65E3C2C4EA5DAF3E9B75F1E0D3682ACA6916C3A190E0F2F82C1E2D7CFAC763306000015508A9FB4D9D9A9581C0E2A5CACECF6F4EDDBCB84331C4890CAE2B95E1A266FAE8D6361957A2F0F1B5393C9D2C89050140000000009101311211B1E1812141B24282A262E3B3D3C3C544B50474F52555858596767666B5D5E585E635750503D85C4F7FFFFFFFFE6BF753525232F80B2EBF4E6B88B563026373A65A0C2C1955616040413469AD5D0B5517166627EB6D7E1CEB8A49EACA7B0C7DEDAD5BBB8AAB1EBF4E6B88B56302601FEF95A070718907573634E37496486A1AD98784C4A5282B9EFFFEC8B5031385AABD9EDE0B4632C24559BD9EBE8B55F20133B81A3A5946F48240F103A88C9DDD6C7AD7A2C0000000E4886A4B1D4DDB05F2B111A4FACE5F1EFEADECB7A32184B95C9D7BC551A3877AC8F6472997C2E08164C86C5D6C59655170000000010121919191D261F21181E1722302E2E35384042453C45484B49584E56605C5A5B63675E5A52545B54564680C2F7FFFFFFFFE4C17339292C3760A7DDEEE7C38F503527323665A9CBC38F5118080C16479FC8C0BB3266646383BBD8EAD8C9B4A0A9B0BECBD2D8D6C8B4ABAFDDEEE7C38F50352701FEFA5A070718A071745A533A3F608AB4B39E73504A5A85B8F3FFF0934F283A55AADBF9EFB35F382347A1D3E0E8BD6C230B3781B3AF937240190D113D83D1EAE1D7BB7F300100000F4088A4AED7D7B36718111C55ACF0F5F1E1DFCD812E184990CAE1B555172973B099656F9572230417478BCAD6C48D4E1F000000000512201E2922211E16161C1D2A2C2C2F333B3E45403C4E484A5151545052515864635A58595C52524E4B387DBDFFFFFFFFFFF6B872351F2E3459A4DFEFE2C89756333D375A6EA1BCB4934A12000F1D4994D1D4A951635C5D77B3DAEAD3BBA79FA5A6B1C4C7C4CCC4B2B7B5DFEFE2C89756333D01FEFB5A070718B07E7860594A576C8BAFB79C75504D5289BFFFFFE0904E393969ACE9F7E5AE6B362E5FA1D0E3D5B8642312357AB2B0957B44120F163587C0E0D1CAB17C330000001D5086A5BCDADCA9601E0A1E4EA4E5F1EAE7DDC976341E4987CFE7BB58202E7AA68C626C9A7A2C0C194F93C8DBD58D5019000000000F121518171919162019141D2A342E363B3941434C42444451514F555B615C4E535A60515052585759534399D6FFFFFFFFFFEDAB762920342C56B3E3F3EBCA93502E34334065ADC9BE9A4F1C090B1E488FD0D3B6597068637CB0E2EBE0C8AD9CA1ACA3BDC8D7CEBFB2B2A6E3F3EBCA93502E3401FEFC5A070718C0746F64563B54688EAAB7A37A52475587BEF7FFE493472D4069B2E7FFEBA95B2E2254A3D1E6D4B55F2713387BAFA994673E1B0C133783C4D8CDD4BE7831000000164982A1B1D6D2A95D1E101958B2E6F6EDEEE1D6812D1A5395CCD2AE5820387DA89A5D77927D2C031D5398BFD2CB974C1E000000000313181B20182622251D221B1F2330272F3C404347454940474E4E5A525E62595961605750565B585B503C79B1FCFFFFFFFFF1B8712F1C2E2B5AACE4F1EFC58D503C352E305F9EC3B58D4A1B0904284F93C8D6B64F585B5D7DB1DFE8E1BEA5939EAFC0C7D0DDCCC2BBB4B5E4F1EFC58D503C3501FEFD5A070718D08387665947506E91B0AD977752416195C3F8FFEA9344273363ABDCF2EDB25A362A57A2CFE2DEAD6A1F17347DAAAA9A6F410E13103983CBE2DDD2BA6C2A000000144588B7B0CACA9F5F1C0D2154AFEEF9F0E7E3D38133244B92CAD4A95B212978A8916C778D6D280E1E5A8FBCD3C48C581A000000000D1416201C1018131F1B211E202A31332F3443435242413C474A50585855616060615E5C585B555155514578BBF8FFFFFFFFEEB970321E2C384E96DEE8E8BE8F4F38262D3C6AACCCAD8667221206164093D2D3B252735F5F7BB4E0E1D3C09E969EA8B0C7CFD1CBBBB5AEAFDEE8E8BE8F4F382601FEFE5A070718E0707969573B3F61829DAB9A7450465F87C1EBFFEE8E4E323363B7EBF3E6A865302B53A5D4E5D2AA65210B417DAFB3896F401D111A3F89BDD7CEBFA37932010000144C8FABBBD8CCA95C21122254A6E5EFF0DDE3D78236204794C9D2B56C182A7FAD9462768D722E14194B92BCD3C89758190000000006181C201C141A181E1C1C1F282C2A3236423A434E43433E4E50545B545B595E625B5557545657554C51437CBCFBFFFFFFFFEBBE76231D2C3658A0D8EBE6D08F3A3230313A5CA7CEC28F471F0A0E244798D7CBAA4E79616178B4E1E7D6C0A29FA9ACC0CFD6CDCCB9BDAEB2D8EBE6D08F3A323001FEFF5A070718F06A7060504146607FAAA8A4794A4C587EBEEBFFE49340303A5FACE5F2E9B2633221549DD3E1CFB0682221407BAAAF90654B1D05113B8FC6D3D9BBA97D2D0000000F418EAAACCCD2AC5B1C0A2757B3E5E9F5EEF2D0892A1F4799CDCFB25A1B2C7CA19C666E97752A03114994C5CCC494551A000000000616261D24201E22221A1D172528283730373F4A4A434A48565B57555455585E626161575A4F555451504172B1F8FFFFFFFFD6AE6F310B27325BA9E8F5E1BF824C4235333A619EC8BC91461C10141F479CCBCFAE5274676A7FB1DCE5D8BC9F95A1B2B8CCD1D6CFBEB8ACB9E8F5E1BF824C423501FE005B07071800797E6D55474D6282A9B1997656445B8BC5FDFFE88A4E33305DAFE6FBEDB15737254EA6DFEBD1AA611F133981B2AF956F42180B1C3C89C6E1D3C6B47B34000000194E86AEACCECAA55E23141D57B1DFEFDEE6DAD27F36245593C0CCB96520387AA0915D749077310B1E5691CADCC793541E000000000518132222191F1A1920232727282A3A393E424B494D45414A53585554595A595D5A595C454E525652503F80C5FFFFFFFFFFF6D1793B2D302848A8DAECE4C58E4F33222E3B63AECBB9894A1C080E22509AD8CEAF516E595A7EA7DEEADCC8AA9DA5B0C1D0DAD0C5B4ACAFB2DAECE4C58E4F332201FE015B070718107B74685A464D698BB0B29F734C465C85C2F6FFE79044383665ABEAF9E5B25934284F97D9DBDABA5A20153C7FA7A0907243210C163486C7E1CBCDB87B30020000185385A3ADCED1A85D1E182756B2EFFEECECDCD187341F4791CDD1B65B1E3676A99763748F722B0819598BBAC6C9895123000000000319251C121E21191B1F161C2A2E2D3B3B393D3E4540404349494F5A5D605C5C5F59605C5652505A4D503F72AAEFFFFFFFFAE1B772341A202957ACDDE9E8C07C4B302F383168ABD1BB89400D02041C4595D0D7B04465655A7AB6D9E9D5C0A798A4B0C0C7CFCFD4BFB3B4B6DDE9E8C07C4B302F01FE025B07071820696E5F4D3C3D5A839EA69A6F4B465F8BB4F1FFE3904B29285FAAE8F6E6B051302955A0DAE4DEA85D23122E7CA7AB916B411707143687CBDECED1B973310000001D4D8EA3B7CDCE9C521F0F2F5DAFEEFBF1F0DBC483301F5299CCD4AB5B25357DA6895E6F91742405184B88C1CEC893561A000000000B1923212B241E151C1920201B2E30313C313C42474A4A473A45504F52565E5B636661605A5455534C4A4179B7F3FFFFFFFCDDB4672E1D232C59AAE0EAE0BD8649302E343870A2CABF9150160403194697CBD7B1486B5C5C7FB0DEE9DCBCA9A2ACACB8CDD7D4CDBDB3B8B4E0EAE0BD8649302E01FE035B070718307E7770564C4B5F7FABAB9D734B436286BEEEFFE594422B3761ACE6F5DBAC583C28519FDAE7D9AA6823153C84A8AE8D604220060E438BCBDDD1BBB576330000000F4C93A4AACAD5AE5E130D205AB5E8EEE8EAD9D784341E438FC5D9B1571A2F7BA78F6E759B732F11245490C0DCD28E4E17000000000B15282E2517220E1D19141C262728283533404A504C3E404A5550564D50575E605956555A594F504B4D4180BFF9FFFFFFFFEAB87A3F22242565A4DBE8E3C491513D262E2D5FA7D6C3904B1D0E14204A96C9C9B54967605D79B2E1DBDFC4A6A5A3A7B5CACFD0CEB9B6AFB4DBE8E3C491513D2601FE045B070718406E6B5F4935395A89A0AD94664A455787BAF7FFE48B38263E6AACE1F5E4A65F2C234B9ED4DCDEB0671E0D2D75ACAF8E6C471D060D3C8CCADFD2C6A66F2B000000165096B6B6D0D0A8571F0E2757A7E4EAF0EBDBCA882B234B94C2D1B8601C2F7FA6905E6E97803405215995BAD4C3864A1E0000000014222025211B1C191B1D1B2021202B35343D40424C4243464E5457575E5E605E5D6061635453504E4E4F397DC2FFFFFFFFFFF6BD6E3726312A5BA4E7F0EEC5885029272D4169ABCCC6914A1C0D06234B9FD4C7AC546D5D6380B4DFE1DBBDA1939FA6B8CBD5CAC9B5B1B3B8E7F0EEC58850292701FE055B07071850757E684A374A617E9AA99D6F513E5781B7E4FFE6914B2B375FA5E2EDE7A2572C2350A1D7E7DFAE6521123980A5AB9C7D4723090A357BC3E5D5CCB47932030000154682A8B0CCCBA864220B2157ACE9F8ECE9E6DC842C23549FDDDDB0581A317CA995616E8D722F04274E93C2DACA97541000000000041718142320271D1A1B12211E34373835373737423F3E433C474C5050595F5E5E585956565957544D4A4279B6F6FFFFFFFFE3BC7534232B2C54A4DBEBE3C88A4F3328384467A2C8B48846170C0A194D9ED5D7A74E665C607AB1E1EED7BEAB9EAAB1B1CAD5D2BEBCB0A1B3DBEBE3C88A4F332801FE065B070718606F6D5A3F3D43597C9DAB9265444A537EBDF4FFE3934924315FA3DDF2E9AA5F2E2348A6CEDCD4AA6527143E81AFB2926D401F0A153680C3DEE1CAAC7531020000114A93AEB2CDD7A259200D2656A9EAF2EBECDBC8852B1A4A90C6D3B05E203686B08F5E628F792B121C5792C9D7CE935716000000000B1A221B20251117191A191D282E3330393E3C404E41433A49505559655C5C5856595557615E625D4D4C3C7DBAFBFFFFFFFFE8B4752F1E202E539DDEEAE7C18B4C3234363D69A9C9BB924A06020B1E449ACCDFB8536F57587FB3D6E4D2C49E94AAACBACDDACFC9B7B0B3B6DEEAE7C18B4C323401FE075B0707187071715A483C456184A6A9916243415582B8F1FFE2904D303465ADDDEDE2A858311D599FDFE4DAA8591C0C3472A6AC9470412019183985C7E2D8C8AA6A2D040000144891B4B4D3DBA95310161E5DAEEBFAF7EDDCC57C2D1B4B9AD1D69C57213683A58B6474966E350A1A5691CAD5CB83571E0000000016181C231D181A1E1D201C261E20282D2732373A444E504E4753595F58555A5A5F645B5B5C54505B4D524584BEFFFFFFFFFFF3BF70342D303461AEE0EDF2BF844A39252D385B9EC7C49B56200A06184B94CDD4AB4968646176B2DEEAD2C2A09AA8ACB5D2D5D8C9B3B4ACA5E0EDF2BF844A392501FE085B070718807B7A68513A465C80A1AA9E6F4D4F567DB3F5FFE38E4A393C6AA9D8EFDEA55E27264FA8DBD8D2AC55191A4689B0AB9367411A10103E8EC8E4D5CCAE7F2D0A000018498EABB0D0D0A760160F1D56A7E9F4EFE7E9CF86301D499AC6DDBA5F1E2C6FA793597A95722D001B4D91C2D5CA94561E00000000071B2F2B232021131D111B221F262E31333C3A43443F4041414F4F5A55535A565E5E5B5E555F574E50564386BFFFFFFFFFFFEBB4763B1C282D59A5DBF5EDC28A51381F303763A5C8CA954A260B07133D90CDDBB852665F6188B4D9E8D8B69D9CAFB0B7C9CDD1C7BFC1ABA6DBF5EDC28A51381F01FE095B07071890777364533F4661829AA9A26A4A3C527CBFF5FFE6943E283F6AB1E3F1E0A6592E255CA3DBE4DCB15A26133A82A8A494743D20120D3982C4E5DDCCB6752A030000114690A6ABCFCCA353270E2556AAECFEE7ECE6CF7F33214497D1DBAA57233880AF97646C977C361024558CBDD6C18E4B1B000000000E191D2118191A191513171A1F26312D343E4335473C463D4B574C544F58605A585558585C515656484A4381C3FFFFFFFFFFEAB7803B2140384EA7E1F5E8C3824935272F3D6DADD4BD8948180A0A194C9DDED5B14B6A625E81B5DDE3DCC4A2A4A4A5B3C9CCCAD4C0AEAEABE1F5E8C38249352701FE0A5B070718A07084675540435A80A0AC9D7752485879B1F2FFE79442263C68A9DEEBE3B55C271E55A5CEDFD3B46220113D7DA6A48E6042200F093D89C6D7E0D0B1752F000000124B85A9AED4D8A95A2B0C1D5BA9EBF7F0E3D7CE7D2E194296C8DDB4591F2A7BAF91606F947227142B4F8FBAD6CA8D5A230000000009181626232424241E161E2220222E2E32393541414A4640495550584F49545A585E5C5C55595C4E534A3F86C7FFFFFFFFFFEABB8241272B365AAAE4FAE9C98A52322E2F3D649ECCC0904C1204092053A7D2D1AD5172636175AED2E0DBC1A79AA3A7BBD3D4CBD1BEABABAFE4FAE9C98A52322E01FE0B5B070718B0796F6A553D40597AA2AB996C3A40557CBEF4FFD98A3B1C2B63A9EAEFE49F5F32284B9ED5E3D8B35A1C153E86ABA79A794313070E3485C0DBCFC4B6792E050000124890B3B9D2BFA76121141F52A5E6F4F1DDE3CF803423418CC9E2B460203582A189566F9A6B230F1F5B94CAE2CA956324000000030821281E1F282723131A1B1B1B21312F3B333D46424548434B50515A58575859525D5F585D565A53514E387ABBFFFFFFFFFFECBB7D432E2C2859A0DAE6E0C4814A3325384170B2CBBC8E4919000021499AD5DCB053716C5A7AB3EAF5E3BEA69998A2B7BEC8CFC7B4B6B3B5DAE6E0C4814A332501FE0C5B070718C0847E63483B3D5E7EA1AD9C7051375683C0F2FFE7874A2D295CB2E1F2EBB15C2C2858A1D6DDC7A05323143C7CB5A6926A431C030E398FCDDFD4CAB9792C0000001E4C90AAB2CACEA6673215225AAFE2EEEBECD9C46E2D21509ACCD9B55B26337FA98F62738D712904185B93C4D5C79B581E00000000141A2628252221131013191C2C2E312D3335373D4A403F4447555354515F5F5762675C575756545A5559418DC7FAFFFFFFFFF8BD733D26303A5EAFE4F2EECE944E362D343A68A7C5C089401D09061C4EA1CBD1AF5D6C50567AB3E0EEDAC7A49AA5ADB9C3C4CECDC2ADAFB4E4F2EECE944E362D01FE0D5B070718D06A816954393F4B7DA2AC966A49435287BCF3FFE884442D2D64ABECF8EEAC592B284EA2DDE6D5AF6620153A82ACA894713F16020D3A7FC3D5D4CEB3752A000000104695BCC3D7D3AA5F20052757ADE0EFE5E7E1D2852D174891CDD2AA561D2E81B19C6C7591712B0F165295CACFC6945B2100000000101D2226212115150F12131B20232E332F3B384046424245504C525A6260554E5A5D56594B5E595A56583E82B8FFFFFFFFFDE6C06C2B24262C56A8D6ECECBE854C353E3B476DA6CEBF8F401500050D3B8FC9D2AE56685E627FBEE2F8E0BDA68F9BA5B9C7CDD1C8BAA1A5AFD6ECECBE854C353E01FE0E5B070718E07A7A6A563B37477C99A98F6A48425A7CB6ECFEE08740243D69A8DEEFE3A9583228599FD2E6DBB26028133A80A7A891704218060D2E88C4DED6CBB47931000000124B8BAFB6D4C89C5318071E52ADF7FCECEBE5CF76311B4F98C9CBAC5F1C3D88A5895D6999722F081B5897C2CDC4965D1F000000001827242C2B1F141316211D1B1C2B2B2A2F333B494F404944474D5850525C615F5B5C605A515354514E4C4179B2F9FFFFFFFFDFB263331E2F345AA3DAF4E4C9854B322A363975A4CABF9949170009144D9ACCD5A04C65646B83B7E0E5D5B8A597ABA9B5C8CDC7CBBEB3B0B8DAF4E4C9854B322A01FE0F5B070718F082826850333D4C7CA3A695653B3A557EBAF1FEDD8B4931315FACE5FAD9A24F27245BA6D6E3D8AC5D22083B81AFB0946E3F180A0A3480BCE5DAC1A67229060000144B8EAFABD0D29E50190B1752B5F0F8FBF0EDC87D381F4A99D5D9B7571B307CAA8C676E9371260E1E4A97C6CBCA99562500000000101C201F201C1E2519141E211F203033333936384A493E41494D484D4F565A5F5D5F5C5C564A575E594A4079ABE9FFFFFFFFDCAB6A2A18262B4BADE2F0E6B4834C2D30353C5DA9D2C18F441810001A5397D1D1A9475E5B6283B1E0F0D4BEA598A1ACBBCCD1CCD1C1AEAFA9E2F0E6B4834C2D3001FE105B07071800746F614932344D799BA8957344395280BEF5FFE0843D2D2C5FAFE5F1ECA957292A509DCBDED4B45D280F3B86B0B594703D190A093990C2E1CEC1B4753204000012588BACB2D6CBA45D1A0C2062AAECF0E8DCE4CD8428184490CBD6B75E223981AC9563728F69200A245792C9D2C98A531C000000001B2C292A21211D1E19211C1B201A232E322B3A41464041415152525353565D605364635C5F5C594F55534483B6F2FFFFFFFFDDB8703C2A2A3059A4E6F1E8C3894E382A31466AA0CBBB8B4917030F204A98CFD1AA516E5C597CBCDFE8DDCBBF9C9EA1BBC7D4CFC9B8ACACACE6F1E8C3894E382A01FE115B070718106C6A5E4B27325D7AA0A791603D3D5576B3EDFFE4853B303160ABE6E9E09B5F291E539CCFDFD5AC651D0C3C7BB7AA94643D1F0B19388CC9E3D0C5B5722E000000184F95B7BDC4CDA05619081D60A9EAEBE9E1DFC8802F224498CCCCB05B253083A38F68739B76290E1B549BBFCCC2975F1E000000001A252929281C29231A17141E242B312C38343C3B45423E3D444E564E584F575C6364605A545456574C4D3C7AC3FFFFFFFFFFEBB8722E182B314CB0DAF5F6B983522D3037447596BFBC9945100B1619479BD3D5B45566575A80B7E3F2E4B5989A9CA4ACC9D2DBD1B7ADB5B1DAF5F6B983522D3001FE125B070718207A77684F3A394B7CA0A995603C37507DB1E5F8DD8C4126265FA5D9EDE0AA5C292352A2D2E2D2AF5F27152977ABA1946D411E0C103D83BBDBD6D1B67733020000134790ADA7D1CC934E140C1F5BB9F3FEF0DDD6D186361B4D9ACDD8B359243386AD8B566F8C722B12255AA0CCD7BF9155200000000112202C252025311E1B1212152327272D2B2B3E434041443F404E4A585F575757525A5D55515659514D47327CB4F3FFFFFFFFE5B26C322129345EAEE0EAF0C1904A3629293D56A8D3C494440D01091C50A8D6CFAC526259606EB2DAE4D3C0A69BABAEB9D1CED5C8BDAEB5B9E0EAF0C1904A362901FE135B07071830807A60483541537C9AA48F67443D4774B5F2FFD87C3D2130609EE6F6E4A64F2C2352A1CFDFDEAA542813397CB2A695773B150A1E427FCCF4E0C7A7702E000000164F92AEAAC9C6A6591A10215CB0E9F3ECE7DFCB833121478FC4C99E58223581B19462799770260C1E599BBEC9C9995B1D00000000192129282B241B1F1815171F1D1C27352C32343C454041433F4D525359575A52575E57595D5D5858504C4284BDFBFFFFFFFFEABB763C25303A5EA9DDF7EABE924F32232B4174B2D1CA904B15020B194B96D4D2A24C64615F75AEDAE5D6C49F8B97A8C3D6DAD8D6B994A5ACDDF7EABE924F322301FE145B07071840707D6B53352E4E7A99A3945B3D3E4B79BEE6F8DE7F36292E58A4DBF5E7AB5C2D215AA1C9DCD0B567230D3382B1A992673D18040E3882CBDED4CBB676320100000B4A92AFB4C7C99C581B0D1B59B5EBF0E5E5DACA832A154798D0DDB258213076A793657A95712410275F9BC7CAC08F5D1D0000000114272C29272127181A101B142A24252B2C3B363647403E41454A53504C53615B5D575153605C5A564E4F3E7EC8FFFFFFFFFFFDC7763D31333B5CB6E8F7E8C080493D3233456BA8CBC486542608091C4599C6D2A93F6C555581AFD7E4D9C3AE9693A3B9CFDADACDB2B4AEB2E8F7E8C080493D3201FE155B07071850787E5644323B4B7994A394673F374575B8F1FED98239273064AADDE3E1AA59251B4EA4D6DED2AA5A170F3183B1B3926F3D1905063684C8E4DDC7B07328060000154891AAAFCEC0A0572512224DADE2F2EDF5F0E08438193C99CFD4AF5223317D9E99657B9C6D2B081C579BBAD5C6915E25000000041B302F26241B1E101F1E1B1C1C232D352F333D444346424249534F55525159555D5F5157645E545246453978E3FFFFFFFFFFEBBB762F1C2C325BA3D9E7E1BC784935233A4563A3D5C890481301001547A6D0D2AC4C735D617AB7E1E7D9C3A59697A2B7CADDD2C9BCB6B4B6D9E7E1BC7849352301FE165B070718607471624626315077909F8C5E3F345784B4EBF8D78342222D5B9ED4E4D8A15E2D284AA1D0E1DBB15B250A4081AEAA9568461C0B0A3082B8DED4CBAB6B2D00000013498EACACCED0A15D220F265BA7E7F3EEE6D9CD7E31254F94C6D6AF5719398AB49A6079947C240B1E579BC0D2C1935F2100000000102628282527241E14121318171F2226272D3742433C473F44455850525759555D5C5A59575759554A4D3882C3FFFFFFFFFFE7B87239212A2B58A4E6F3E5C587512F26313468A5D0CA9144090605194898D8D3B15D6B5E687AB1E1E9D7B69E9BA8AABDD7D6D5CABFB1AFABE6F3E5C587512F2601FE175B0707187071765B3C2A3248779499975430334D73B4E3F8D9883E243862A5DBDFD09D5032234EA2CEDFDAB257161535719EA496773E1E110E3B7EC0DCD5CEB17A2D040000134C96B2BBD4C5A05B19082156B3EAFAF0EBDDD0822922509CD2D2B057192C83A88F646E8B61260D1D5598C6D7CB915F2A0000000F1C2D2D2E1E1D2018211B1C191F25262B2F333A383B3D4344445253515750504F575E5F545C545550464C3A89C0FFFFFFFFFFE8C07D362C2B375FB5E4EEE9BD854A32273A3C61AED2BE964F16060E19469DCED0A548695C5E81B8E1EBD9B89A9DA8A8BCD0D4CFCCB7A4ACB7E4EEE9BD854A322701FE185B0707188072775D3A212A46738F998B5431364E7CBFEDFFDE7E3929385FADE1E8DA9D56322952A7CFDED9AA5D21123B7DACB7926D3D14050B327EC6E2CFC7B8792E0000000F4D90BAB6D4C39D570E112154AEE9EFEAE8DBC06F3224559CD4D7AC58122F78A9956B7E996E280E265593C4DBCB92541B00000000212F2B282822231513181521211C212C302F343C45404042464D5B54504F5D585D585A59595454544D504378C6FFFFFFFFFFE5B8732A2A263664A7E9F5ECC4833C2B2E2B355FA7C6CA984E1701031A4F9ACDDAB35B64596279B2E1E6E0B99A94A1A5C0D4D5D4C9B9B7B2B4E9F5ECC4833C2B2E01FE195B07071890706A583D22284C6A919C86572E2B476EA9E8F8DB883C253C65AEDFEDE4A2542A2259A1DCDDD29E58170B3878A7A58D62471807193C89D5E5DABEB47B320600000F4884ADB9D0D6A15713071D55ADEEF7EAE7E5C37A28144E9BD1D7B05316327CA997686F937023041A649BC7CFC295591D00000002183130232529222320140E17251E2725313A3E3A423F3D394752575D5F5B525F5D635E5A504E585551503E82C3FFFFFFFFFFE7BF7C3C26323955A1E1F3E3C08148322E324167AACFC28C4614090A1C549CD0CEAB5A6C575076AFE4EDE0C0A197A3AAB9D1D6CFD3BAAFA9B8E1F3E3C08148322E01FE1A5B070718A07376543B2429437596A08953372C4579B7E6F6CF84371B315FA6E1E1D7A352332751A3D9DCD4A15A170B3A84AEB28F6F3F1F0E143687B7D3D2C1B07429000000114E8FB4B5D2CAA75C16001651B0E2F3F2F0E3D18033214BA0D0D0A353202E7BA585687E967128131B50A6CCDEC995571E000000001C2E322F2C2B2A1E1B141B14191E25312B373C4543444844404B494C4F51555A585B5A5D59585654494A4074B7F6FFFFFFFFDDA9733017212C58ADEDF3E9C688452B1F293D6BABC0C18C430E0D0A184799CBD2B14C645F5876BAE2EAD8BEAB999CAFBFC9CDD5D1BCACAAACEDF3E9C688452B1F01FE1B5B070718B0788263422C2F4D7E97A98B5B2E334877B4F2FED1814223345EA9DEEEDDA047221F539DD3DBDAAF6417003C81AFA0967743210518378AC7DECDBFB46F31000000165394B1B1D3DEA5551B111C57AAEFF1E8EBE0D17B311B4C9BC8D1AC51193189A98F62738C7426071B5998C5D2CA8D5522000000001A2C3B38342623230E0D0F171C2325262A32414848494A43444E545155585754555A545658595E594F4A3B81C3F9FFFFFFFFE9B6732C1E2C3050A9E9F7E7BC824D2E2D363E6DABCFC5914415020C2356A5D6CBA8526B535979B2E6EDD8BD9E96A2A9BCCDD8D0C9B9B0A8A8E9F7E7BC824D2E2D01FE1C5B070718C075715841292B45728E9C865D343A4B79B7E6F2CF8142212D59A9DCEAE2A5541F234DA2D3D6CAAA62250F2F7AB0AB936B410E04194089C6E1D7C5B1702B0000000A4C8FB4BACFCB9A582408215CB5E7F6F2E6D2CF7A34285298CDD9A957213582A89969819C7525051F4E90C8D5CA90571F0000000819312F2F2A1919241D13131C161D2226302B2F41443F41444A534B5354535455555E594F595756514C534088C7FFFFFFFFFFFBC77F432E2F415CB1E7F6E7C59347332633396EA7D4C28B4615050A214199C8D2B24F6F605772B2E1EEDDBEA39AA4A4B3CDD9CCCBB5A9B0A8E7F6E7C59347332601FE1D5B070718D06F6451331C1E43708D99885322254378AFD4F1D180351F1E5DA8DDE7E1984D1D2054A2D2DAD3B260230E3276ABBC96763D1D040C337AC4E4DBD1B26B32040000134E89A7AFC9C89E5E1F071A53AFDDF4E6DBE3D57F311F4B94C8DBB164223985B09B67748C682F081E5895C4C8C09763270000000020353A332A2924131F0C1013241F2A282E313240413943413C4B5659555A5159535B54525A58535252564880BFFFFFFFFFFFEDB36D37222C365FB0DFFCF2BC8450311C2D3D61AAC7BC8E3610020A1B589AD1D6AA54655A5A78B3DEF1DBC7A296A19CAACCD4DDCDBDB09FAADFFCF2BC8450311C01FE1E5B070718E07477633E212C446E91958D562D274075B0E9FFD689311F235AA7E0F9E49C561E2551A2CBD3D3B15B210E3983B3AD9666381E09153B8CC8DFD0C6B37930000000104A98ABB4DCCD9F5D1F031A60B6EFEDE0E2D6C17A30264B9BD6D6B15A212F7EA1965A768A6E290D245A96BFD0BC8F5E2500000000172C2E25362C1C1F1D1B1A1D28282F27302E2E36413D463D3F494B51524F535F585D5A554D53574E5054427AB9FBFFFFFFFFE4BC6C321F233166ADEDF3F0C086472D2D324067AACCBA8846130C0B205399CACEB4535B555D78BAE6EBD9B2A298A8A1BDD0DED0D5BFABABADEDF3F0C086472D2D01FE1F5B070718F075744F32162643658CA2865D3432446DB2F3F7D17A3A28245D9DD4E8D59E4D1F26519DCED7DDB55F180B317BACA78D6B3A190B173E88CDE2D5C6AB70280000001F568EB0BCD6CD9C551103245EB3EAF3E8E4DECB8232214C93D5DAAD51203887A68061678D72310A245997C2D5BC93611E000000071D383E302520221B1514131018222F2E2E2E3740414145454A4B50584F556555555952515056575649493982C6FEFFFFFFFFE7B76F34243B305DACEBFAEAC3864B2E2A38486FAACDC28B491209030F4997D0D6AF4B6958596EB9E7E4DAB8958DA7B2B8CFCED2CBB7A6A3A9EBFAEAC3864B2E2A01FE205B070718006D70623D211C43688FA28B5F3932386DB0EDF4D17B341F2858A7E3E8D59C4A201F529ACDD9E2A65E1C0D317BABAC8E6C38190A0F3E8ACAE8D4C5AE742B000000105396B5B5DBD29E5619082755ABEBF0E1D4E6D4843B21509CCED6AC581C2D73A8875E7592732E0A274F93CED3BE8B581A000000032438333C302C1D1B191212181C21232F31333B4140393D3E414C4950595A5559595B5958514C5652454C4186CFFFFFFFFFFFEFB3783E2028345DA7E0F0E4BC7F47241D2F396EABCBBD8E4C200F10294BA7D1BEA651685A5D7CAAE1E6DBC2A79DA4ADB5C7D6D7CABAAEA6AFE0F0E4BC7F47241D01FE215B07071810766C5B311C1A3F668D958E57302F3C77B0E1EDCE7B371F265BAED6E7E5A34927244B9CD7E1CBA54F1A0F2E75A7A594753A18060C3C8DCAE0DAC9BC8241000000175398B6B3CFC59E571A082057B0E9F2EBE3DDC7762F204C8CCCDBB5591F377EA2975F74946A240925559ECAD9CB9F542200000006273C373635341F1E130D191519232522261F2E36443A443E3F4A4A4D5457595B586559515854544A4D4F4283CFFFFFFFFFFFF2CA764D33313765ACEFF9F2CC844125353B406AA5C4C38D4919020C194899D4D8B25C6B5C547DB1D8EBDACAA79D9FA3B5C3D9D3CDB5A8ADA1EFF9F2CC8441253501FE225B070718206F774B2D1F2342658E998D542E23486DABE6FBD27B331D2A56ABE2ECD49B59292551A1C7D8D1AC621C063071A4A0836C40170513318FD3DDD7BEB46A25000000185294B4B9D4C99D5412081A54ACEDFCF6E2E1CE81362A4EA3CADFAF56253382AD9064759678270A1F4A95C6D0BB8D592600000008273D413A3426211E11160E1118292C23332B393E3B413E3C4748494D535A534A5A6154545A545450534B3C86C9FFFFFFFFFFEEBE6D3F2F323961A8E6FAE7C68A48392332466E96C6C592481303122454A3D1CFAC4A63535472B9E1E8DEBFAB9BA4AAB4CED7D6CCB6ADABAEE6FAE7C68A48392301FE235B07071830737F562E151A395F8D928B562A24406DACDCF3CE7B2F172861A3D7EFDBA252211E4D99CDDCCBA55D19032E87B2A897763D140014368CC7DFD5CAC27B31000000174891A6B0D1D09B581C0B2256ADE7F9E4E0DBC881321B549ACACFA852213786AC9A6776926D280728669FC1CAC59458250000000A2A372F292C2E241B1B1411111B201A2C24253D3D3F3E404044424E54525C5A5958595853574C4B534F493385E1FFFFFFFFFFF1C77C45222C3761B1E2F9EFCC84512E3A324166B1D4BD904114100E1F50A1D4D3A93A5F59529CC1E7EBD7BDA6939C9FA7C3C8CDC8B39C9CA6E2F9EFCC84512E3A01FE245B070718406D6F56311615386387948151291C3E72A3DEF2BE6D311C2756A3DDE5CF964D231E4E95C2D9D8AC591D103679B0A8916C371C10153688C3D9CCC3AF6F3300000014569AADAFD1D0AB5B120C2053AEE4F9EEE7E5D2883A1F4991C7CFA84F1E3880A7856A7796712D08245C98CAD4C599571A000000001D37393D2B22221B140F100F121E28242C383D4046403F38414A4C58615557596159505D5A4E5453504C3587C3FFFFFFFFFFEDBA7C35202E3060B2EBECE0BE7B472532323F64AFD0BD954C0E040317489ED2D6AF556E5F637AB5E7F5D6C299959EA9B5CBD1D1C4B7A5AAADEBECE0BE7B47253201FE255B070718507571502F111A345D8988835028233D6BB1ECEECA7E3E20225A9DDBEBDD934F1C234A94CCD9D9A5581B0C397EAFAD92683D180509368AC0DCC9C3AC7B2A0800000E5293A9A9D0CA9C5B1A0F2157B0F0F4EDE7E0D18A2F1D4691C7D0AD53193183A98A5E70966E2B05215799BFD0CA905A270000000825393B2F323B261C1410191F1825253425303D3A423F34324144494D565B5A55585F5F58514F504A44523F8DC5FFFFFFFFFFE7C06F2E1F293158AFE4ECE0C38A4834313B4668B2C9C18D390B040E1B4EA1CFCCA84D67625D7ABDE9EBD9BFA08994AABDD1D6D4CBB2A9A7B2E4ECE0C38A48343101FE265B070718607068492D171C3A5E84917B4F2D304167ADD8EFD078301B224F9BD2EDDAA4552C245497CCD2C5A2571F143983B1A39A6A43150817337EBAD6D0C2AF78250000000F468FACBFDAD4A05C1906265DB5E8F6EBE1DEC9803623569ACDD4BA652A3680A19165778E6C290A225691C7D0BD8E59260000000E2C3E43372B2C2B2B17101313171B262733333738393D403E3F4346594D5B58525E5A5A525556534F4D483678C4FAFFFFFFFFF4B9693B2522235EA7DCEBEEC78F4A2A262A3667A8D0BD934A180B0F1E4694D1D5AF525E545774B4DFF1DBBD9995A0A5B1C7D8D3CEB4AAACACDCEBEEC78F4A2A2601FE275B07071870827358351A1D3A658C9B8C5022223B6EA9DDEEC9733920215EA9D6E4D19D531F2053A7CFD9D7AC54220A3179B3AE91643F14030E3E8BBFE1D7BEB77A2A00000011539DB2BCCCC698581E05245FB4E9F4F0DCD8CA7E38214F9CCFD4A9521C3182A78A5E789369310D1A62A3C1DCC695601B000000122B3C3F352E2A2722180D060B1D27221F2E2F38393E394241414951544C56535F5F5D564F52484D4B4B443C83C7FFFFFFFFFFECBC732F202A324EACE8F9EABA8A4B2C312E4A64ABD0C89753120A0C1F5296CBCFB3455C53587BB4DAE3D1BAA09697A5BECFD6D6CDB2ADACADE8F9EABA8A4B2C3101FE285B070718807F7865401C253C688B98764D2A2B3576B1DCF0C8853B212F66ABDEE9DC994E241F4B93C3DCD2AB5A1F0B377DA8AB93653913090E348AC4DDCDC1AB732A000000185691ADB2D0CFA1571F191E54ABDEEDEAE5DDD58532194C98C5D4AA521D3284B1936A7B9B6E2603175E9FCDCDBB99682C0000000F2B40452F2D2B2A1B0F0F160C19241F1C212C2E343C3C3A3C4B56575C585151515D645E5753545B4D49483778B6F9FFFFFFFFE7B06B2A16283061A8F2F8E7BB81392935343963AACFBD87421804041A4BA3D5D1AA5364514F73B2DDDBD6C2A293989AB5D3DBD4CBB8AAB3AEF2F8E7BB8139293501FE295B070718907C7A58321E213D6498997D51302B416AA9DAF7D27C3718285EA3DDDED79A52242158A1CCDCD6B86224143576A8A38C663D16000F3184C7E2D6CFBC772D000000125598A8B9C6BC905A140B1E56AEE5EFE8ECE4CF843930539CD1D5A54C173980AC9968759471280E2155A1C5CFBE8F591F0000000B29453A36302B2C251610080F101A202D2C32383849403C43474E4C505157595151595656534F584F57514084C1FBFFFFFFFFF4C0793C2C242F5CB0E7F8E7C088492E27373D61B0DBD48E431207091142A2D1D8AF4B6C5A597FB2DBD3D2BC9DA09FA8B0D5D1CEC4B9A1ACB5E7F8E7C088492E2701FE2A5B070718A06B614D2A0C0A305882847A4A26193963A6D6ECD4712E1B2C5FA3CCE2D69C502B1A4296CBDAD5AD5D24123280A9AA8A63441B03112D86C1DAD9BCB06C280000001C4F8BB1AED4D59E5419101E5BB5E6F1E4E6DECC823328519BCCD6B15A1E3386AC9C647799661E00195C99CDD0C496611D00000010223C41372E2D2516120D0B131923252B2A233335463D3436424E54554B52595C5A59575C4E4D504F5351427FC4FFFFFFFFFFEDB66E372D323558AFE7F2EBC8894D34222D3B69A5CCC0884C110B0D224F97CFD0AB4C615C567CB2F3F5DCC59C93A0A4B6CAD0D7CBB3A7A9A8E7F2EBC8894D342201FE2B5B070718B078735335151F34617D857B4C2F222864A7D9F3CA793E1A2756A1CEDFC1974E241C53A9DCDFD3AE601A0B3E77A5A98F66321B08103288BFE6DDC8B1742D0000000F4BA3BCBBD3CE8F4D190A225EB3EEEFEEE7E8D77E3322529ECACFB25A132E83A79764728B66260A21649BD1CAC0935D2500000011283E42362B2827140E070C0E1919222229332E313B3F3D393D4B4A4A5158575C5E635C4F52585857564F388DCEFFFFFFFFFFF7C081412A232E5FB2ECF5ECBC7B43321F3D416EA3D1C58B602509102854A2D7CE9E4162535373ACD7E7D7B296959EA4B3CDDBD2CEB2B3ADA9ECF5ECBC7B43321F01FE2C5B070718C06E734D2B0B13275287A17F451E25406CACE5F0C57827171F58A6DDDFD399542824469FD7D4D1B15A1B082B75A9B28F6C3B1E1518347DBFC8CBCBB3712D000000145195BABDD7D09E5719111B56A8DBE7DFDFDCCB843327539AD1DBAE5A1D377BAA8F6A7188722F1223629BCCCCC596551C00000007324440313328201B131610060F171E2835353D3940373E3D434C484F5152565B635C5F5E605758514F513595CDFFFFFFFFFFFCB96F402E2D3C6AB1F0FFF4CB864F3028283C6D9ED1B68E412503021B569ED4D7AD535F5A5979B3E8F1DCB0A2949BADC1D4E0CFCAB5A6A7A4F0FFF4CB864F302801FE2D5B070718D075774B2A0F1535598A8E7A4F1F253965AFEAEBC2742C1A1F57A5D8DDD999491F224894CFD5D7A8591A183285ADA6906E3C16080B3A8BC2DDD2C6BC7228000000165387ADA7C9C9A4571E0E2557ABEBF4EDEDDEC8792D1D4E95C4D3A760223D8DAB916A7B9A6920052067A3C5D5C88E602A0000000C2D483E3A37322A17110E0D1518192936212B29363439373E434D4A53484A534F555257534A4F50574E513B8DCFFFFFFFFFFFE9BC79442937375F9FDCF3EEBB81412727393D6AA7D0C5904C16040C1E50A1D2CDA5505C554F71C0EBECE1B69C8D93A4BDC7D4D1C7C0B6BBB1DCF3EEBB8141272701FE2E5B070718E07D7B482E171A3562838874552E283E74ABE2F4D17130112353A3D9E6D09545201C489FC8DACBA7531D103C88B0B4916E4017000E3980C7D9C8C4B76E27000000155098BBB3D1D499572111265EB3F2F9F0F1E0CF802E264C97BFCAAA4A1D2C77AE9D6C80946D2404225B98C6DCC68A5619000000072C4A423F3827281D160E0E141A262A2C223038353C3E423A3D49564C504F5A4E54555A4F4F4B5354474E3883C2FFFFFFFFFFF4BF6D23272D2E61B0D7EDEDC58A4C2B22283A6FB2CDC4944A1603081E46A5DBCDB05E67564B80B2E1EAD7B49E87A0A9C0CED3D5CFB5A4A8AAD7EDEDC58A4C2B2201FE2F5B070718F07473552B100F2D5C809A7E4325213E6BA8DBF0CF752B13215DA9D8E3D99F4B1B1E4F9DCDD8D6AE53150830779EA7936838150C193F87C5CFC9C3B48037030000155698B5ACD5D1A4561E102051A3DFE9F3DFE0CC843023569FD1CFB15715368C9D8A646E946F24001E619CC7D6CB975E1E0000000B2D3E4C463B2E2620160B0B10101E23222F2C2C353E343C3E424650575B5251575E565F56575C544A4743387FC9FFFFFFFFFFE5AF6838202E3D63B8DFF6EAC2864A2F25313B68A3C5B8884A12040A204CA2D1D3B0506859577FBFF3F2DAB797939FA9AFCBD5D1CEBAAEAAA2DFF6EAC2864A2F25 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 61440 61440 0 01FE305B0707180072795A2B08062E6281927C431C203C6CA7D4E4BE7633192558ACE0E6D1994424255198CDDACCAF531E14397DA5AC95713B140A1A2A81C1D6CAC1B4712A0400001B4D99B1BCCFC99D51170C1A56A8E2F0F2EBD7D58D36204490C9DAAB531C34809F8C5A778C752C12245B9FBCC8C59B60220000000E304C4A3F332F271F0F02020F161F2931232A37423C3B453A404A4C4C4D46525252524F5D4D57554C4A483B85CAFFFFFFFFFFFFC578312C353E6CB5E9F6E5B487472C2C2D376DB3D2C7904708000D2757A2D4CFAB5762504F7ABDE2EBD6B9A0929CA6B3D3D1D9C8B5B0A7A6E9F6E5B487472C2C01FE315B0707181071684423030F26578892774A1F1A2E66A2DAE6C97137092459A1D9E2D69550201A4E98CBD8D5AA57140F3877ACAE946C3F1B0E152D7BC9E0CFC6AB6D28000000174F9AB6B9C8CD9B511B0E255AB4E8F2ECECDFC6822A1E4098D6E4B7571C327CA88D6F7E926E1B05296292CCD5CB98611F0000001134544B38322A25251106090B13162024262B34393C38403E3D47465256585350515554545A575A574A49377FBCF7FFFFFFFFE7B3673D1E2D3660ACE7F1E6C6884E282327406AA8C9BE8A401109061E4D98D6D5AC485D565E76B6E7EAD1BEA59091A2BED0D0CDC6AEA1A6A8E7F1E6C6884E282301FE325B070718206C70502E0412375B7E8E7F4C1F1C386FA6E1F2C86F2D142758A6DFE8CD9A52201A4C9DCBD7CEAC5D160C397DA8A5916B3C1101113B87C8DDD2BEB77E2E000000175294B7AEC8CC9A63280F1B5CABE1E5E8E1D9C9822E294796CBDCAE551B3778A79267759E6E2A011F589ECDD8C38B581B0000000F325149442D352A1B130C0910171B25242D2F2C3B3C34393B39474A4F53555B4F575B605951545A55454E3985BFFFFFFFFFFFF6C5793C28303961AEE5F7EBC0894B2C26282F65A9CDC390481A1207154398C9DD992F6A545780BAEBEFDDC49D8FA3A5BBD4DBCBCEB3AAADABE5F7EBC0894B2C2601FE335B0707183080744F2D0B122F5D8498834F221E3D6BA5E3F6D77732172154A4DDDCD39345241F4F9FCCD4D3A5621D0B3787AFA892723D1602103A80BBDFD1C4AF7523000000115496AFB1D8D59D551E0B264DA8E2F0E8DBDDD08033284F8EC2D6AC5A2B3C83AC9263698B70260A285F98BFD4C58B5C1A000000133D534942342A28110D0C0C17141A1B2729313035373B3B384A4C4949444F555857554F574F535D5D5C513D75C7FEFFFFFFFFF0BA70352930335FAEDFF9EFC182412A1F2A366BADD0C28E461A09152581A6CFCFA44D57504D7AB7DFEEDABF9F8F989DB7CEDCD8CCB7A7A9ADDFF9EFC182412A1F01FE345B07071840827A50270713335E8B987D37191D2D5EA4D6ECCD7B30111F5499CEE0D8954D2523549EC7D5D3B2581C0C3381B0AC9B713F18050B307DB9D2D5C3C4792E000000155095B7ACD0CCA0571C061E5CABE0F5F3DCD2BE812A2B589FCED1B2511A3680A185617795782C0B13619DBFD3BF935D2400000015415659492E2B281D1811140F191A1E2C222F2B2D364439353B52515251595350495A61574F55504F51504282CEFDFFFFFFFFE7B666372A2E2F64B6E6F5E7BD7D40312728396AADD0D28037170D0728539ED0C8B04A61555880BDE2E9E0B59B8E9AA7B8DADAD5C6B1A7A49FE6F5E7BD7D40312701FE355B07071850746C53290D0F23559791743C26223F68A6D6E4C6803023234DA3D2DED9975021235195D0DBD0A85D15152479A9B2936F450900083686C7D8CDCAAF8033000000104B9AB9B6C9D19D51180B1B52B2E3F3EDDFE1D180281F4A9DC7DBAD56163079AA92687D92682C10256498C0CDC79965230000001636534D443C302213100B091A211F1B1F2636333A3431363C3F4550474D535656585956584D4D5B514B48388DC7FFFFFFFFFFF6BF78362C2E3962A6E9F7F0C3855A3556414F6BA8C7BB903D060A111D4D9ECECDAB4A6F565786BBE1E3D0AD938E99A1B5CADAD7C9ABABAEABE9F7F0C3855A355601FE365B070718606E6B561F060E2C5678847A46170B3067A1D6E0CA763A1A2658A4DDE3D1984D20194A9BD2D1CEAF541F0E3982A4A6976B3F100818388EC1DDD3CEAA711E00000013508AA5B0CDCBA15013081D60ADE7F3E5E8D6CD823420559FC9D2B254292A7AAA90647F986C250B285297CED5BA8F5A23000000163B5D59442B2B2D150E0C0D10161C1C2A2D26313845403C3D3E4B53444D544D4956565B5158575451524F407EBCF6FFFFFFFFE9BB6C3114233255A3DBE9EAC3914B2F2935376099C6BD8B3A12030427529DC9CCA35065584E6FC8EDE5D9B39A9596A2BDCFD7B2C4D1B2A9AADBE9EAC3914B2F2901FE375B0707187075754C2A0B12275C7F93824A1F1F3467AAD7E5C7752C142657A5DCF2D2954C261C5095CECEC3A55719113B75B6AA90663C10000C3B92C2DFD6C1A4712E000000104694B5B2CDC59D521D0C1C5BAFEBEDEEE4F1CC7D2E1D5491C9DBA95B223382AF9769829F641F08285E9EC2CAC48E57230000001E4960543C31271D18160D0A0D0C181A23252C2E363538393D4945504F505254585B6253564A4F525A54523177BAE5FFFFFFFFEABB744B2C403E63B8E2EADFBC813F2C28323F60ABCCC58A48170A03124A97CDD1A74F625B5D7CBCE6EFD4B59C919FA5B7CFD2D4CCB4A4A4A7E2EADFBC813F2C2801FE385B07071880747953250D032B587A88754921172D60A2DEF6C36A2A1721529BCDDED0934C25174E9DD3E0D3A95E200E2F7EB1AA87663713080B3485C2DACFC3B67B350600001B5394AEB9D1D094521D0A2059AEE5EEE9E4D5D27E3320468ECFD8B2501D3887AC8C637B96721F08255699C8C8C3945F270000001048595545402D1C16171207060F1A161F20262A37433C3B3C3E4952524B554C59534F4B595A585F5957453677B4FFFFFFFFFFE5BA743C32302E5FA8E2FCE5C4843A27252E3E6AA8BCBA8B4E180B041B5C9BCCD5AE5264495778C4ECEADFBB92919BAEBFCFD3DACBB9A9ACA9E2FCE5C4843A272501FE395B07071890756C5126070B20527C887D3D221E3864A9D7E4BE63250C234EA2D2E3D1954F2A1E55A4CCE5DCB05B1D0B3A76A9AE876C3C15030C3884C8D3CCC4B27A35030000115097BEB9CAC198521706205AACE3EDEADBDEC77D3422579DCEC8A55519358AAC926977946F220A225DA1C4D1C79E5E280000001849655F4C372D2D21110B090907181B1E282E28303E3C3F474B4C4D474652515A5657554A4C56544F554E3C85B6F7FFFFFFFFDEBA6C321C293260ADE2FAECC6863F161A0F3775BAD7CA92441A030B2256A4D8D6AE4C5E575577BAE7EEE1BD998E9CA1B4C6DDD8CDB1A4A8B0E2FAECC6863F161A01FE3A5B070718A07B764411000B264C7C886D38181B2D529BD6E4B86D2B142A60A0D8DDCA9B51281C429AC8DDD0A85A18083580ABA9986A3E1B0903327FC3E1D4C4B1743000000015548AABAAC3CCA05B260B205EADEAF3ECE2E3C4833D2B5A9ECED0B1481D2B809B93677A936D2604225FA3BFD1C28C611A00000017465C5B4E462C2C1E180909080D0E162126282E3535343E3F3B3B44504D52504C585C51545A4C4C5247493688C8FFFFFFFFFFE1B3653328383668B6EBF3E8C2893F2B2B343E71AFCFC9903D1204081B4799CBCDA6425F5A5780B9E9EBDCB6988094CBC8C9D3D8C9BDB1A4A7EBF3E8C2893F2B2B01FE3B5B070718B07B78541C0A072354828879411B1A2D69A3D0ECC07036192B5DA6D4E3C997421C1F54A3D5DBD2A552170C3979A2B39566391A04083F8AC3D7CFBDB06D300000000E519FBABAD3CC9B50150A2B59B9EBEEE5DADFC57A37204B90C2D4AE5E203A7EAD966B828B642A1123609BCBD7C596561D00000022465B564E3933211A0807050D161D1916232B2E333B3839333745454B4C4A4F4C625C6155544E4C5351483F7DC2FDFFFFFFFFEEB674392B24325FB3E1F1F1C78545211B294272ABD3C08848090206194179C6CFAB5C6B4E5172BDE7F4DEB59B97A3ABC0D4DFD8C5B5B1B5B3E1F1F1C78545211B01FE3C5B070718C067663C0F0002204F808371401316265CA6D3E0C3692D091A4FA0C5D1C49B49261F4C9EC6E3D8A95D280F3377A3B2917444180E13428BCDE3CFC1B07922000000125699ACA8CEC8925618061E57A8E6F2E7E3DCC98731224F9CCDD8AC581F4087A491636F98641F082159A1C6D3C49C61290000001A4B61525233311C190500060C171E262831363937403736354245494B4A4F515850595156585352474A494382BFFFFFFFFFFFECC2753716292E5BACDEFFEFE9924121112B3B64A6CCB9874A0D000B19489AD2D19C475F4E5881C4E7F1DDB89B899AA5BCCAD7D4BFB4A3B7B2DEFFEFE99241211101FE3D5B070718D068663E1600002052697B713D09122B639CCEE0C17B2F15274A98CCDED1944A1E164596D1DFD6A84B16073287A8A89E6A3E1601053782C8E7DDC1A37232000000185399B9B6C7D2A6510E08235DAEE8ECECD8E4C983291E519AD4E2A8461E3585AF9166778D62210A2A66A4C2D5C08D5C19000000143F635F4E3A3027140A090E0D131A1A231F2A3235373235333B43494E4B4D50515B5B5D56514E59514E4B3485AEEEFFFFFFFFD6AA7338282A2C59A7D8EDDCC589412717283866B1CAC58D4212030D175297C9CDA85375627679B1DDE9D6AF948896A0BACED3C9C2B3B69EA8D8EDDCC58941271701FE3E5B070718E07B764E220104204F7A89754B1B16305DB6DBE9C16B22102B5AA7D6EAD593491A1C549CD2DDCBA95516113582A9AD8C633A1902153285C2D8CAC6AC732A0300000E4794B3B4C8CFA4561E0E2153ACE6EFF0DEDED47C34215D95CBD3A847163A8DB495617E8B5D1E1227649EC3D2C7975922000000244C6C64503A2D2D181302000C101B1E2A222523343C30323A3C3F4E4E4851504E54575F525056544946503790CFFFFFFFFFFFF5C67232212E3866B6EDF6ECC8805334272F446CAACBB8873C0F0E0823459FCBD0A84A615A5973BAEEEFDBBEA1829EABBBD6D6D9C8B6A8ABA5EDF6ECC88053342701FE3F5B070718F074704F1E000025506E817A3D170F316FACD2DFBF6926132152A5DEEAD8974B1F204EA1C9D5C6A75D17013777B0B29A794415030E337EBED5D0CEB0792900000012539BC7BDCFCA965411071A4EAFE5F1E3DFE3CD7E301C4B9ED3D5AA55203589AD986E719469200B2A6499BFD6CB9C64160000001C4F675D4B343129190F080004151C1C2221222D333A323D323F42515250504A5150555A60584A4A4B444E3E64A2EFFFFFFFF9DBA2581908132959A7D8F0DBB87A382626213165ADC9C187430C0A0F1E52A1D0D0A5466173627BBFE4DBD7B58E8B99A2B7D1D6D7C5B5A3A2AAD8F0DBB87A38262601FE405B07071800787E60290708284F70897F43181C356AA6D0E5C56E2B1B2E5799D2E0D8A64D221A4A99C7CAC5A15316133B85B2A1916840120518367FD3D7C4B6B0732F000000195793ADB8CFC59458100A1F60AFE8F5E3E6E4C57E31284E9EC9DEB6601D35889983737D9A6522041C639ED1D1C28E5929000000204B5F574D3B332D180B06060A151C1E2022292E2F3B3030313E4B52534A4D535450585E54555358554A45398CC2FFFFFFFFFFEFBF783E272C306AB1E4E2DBB187492D23323D6BAFD6C6883F180A182053A2C9C7A34865565775BCE7E8D8AC8F8A99A4C0D3DFCFCAB6A9A3A1E4E2DBB187492D2301FE415B0707181077684C1B00001F4E6B807039151C2A67ADE3E6C2702D132353A2D1DFD690502014439FC7D2C99E5316033175A6B5976E401A09124083C5E0C6BBAF7532000000104A9BACADC9C79D52120C1D4EA9EEF2EFE8E0CA873726599EC7D6AC521F4091A69E63768B6921022965AAC7CFC59E541B000000144E6C60524F30211811000205061119251E24363931363A353F423D40514D585461625759555A5955454A2A87C9FFFFFFFFFFEBBC77401B33335FAEE9F0E8C485452C2A2C3B6AA8D5C68F410A0008234AA2D5D0AE4C624E577EB7E4E1D6BA948C9CA8B5CFD2D4CCB3A6ADA4E9F0E8C485452C2A01FE425B070718208077501F00052752777E6E3B201F2D64A2CAD4C46D35132154A8D2DDCF8A43261F4B9BC6D9D3A5561C142B7CAFB88D6E3E1204154191C8DBCCC4A876290000001D5396B6B4CECB964E180B265DB7E7F6E7E9E4C86D2C174CA1C4D1A6532A3585AF926579976F2113285FA1CAD5C3985A1B0000001E506C6050342E241C0E010304161E2128332B2D393F3A37362C414C5041474C4D4B585152555755504E47378ED2FFFFFFFFFFF3C378312A313265BDEAFAEDC0864631282D3E72B0D6B78C4314010C1E4EA2CBCCB0525F57587DB2EAEDDAB6908DA5ACB9C9D4D5C9AAABA7A6EAFAEDC08646312801FE435B07071830776E43190002214C758872481E152868A5D4EEC572300D1C4895CDD6CB8B471E1553A4D1DCCC9C50160E3777A9AC99773F180A133E8CC6E2D7C9A87233000000184F9EADB2CAC69D5117061B50ACE3E8E6EBDED37E301F4E9BC7D3AB52233884AF8D647C95682B112859A0C8D7B98359170000001F516966544437251F1701010C1C161C281F2B2C29343430383A3C4647545355575A5B5F5B565858534C4D437CBAF7FFFFFFFFF1C66D42242A3E60B4E7F4E2BC85402B1226426CA9D0C496470B000D284FA5D3C6A0495C4C4A70BEE9EBDBB0928D8B97B5D1D9DCC4B7A9AAABE7F4E2BC85402B1201FE445B0707184076764C1B00001A4B74806B3B09142A66A0E1E5BE5B250A1E4DA7E3E2C589412123519DC6D5D4AA581807387CAEA78E6E3B120418378BC2D9CEC9B8782A000000155496B0B5C6C99A431506225DB1ECF3E8E3DFCA7A35265896CDD1AC4B1E3E83AD8567829762220029649FC6CFC08E591C0000031855735F53493C2D1C1205000C0D14151E172428303635323E434B474A4D4F535A5E5758585A534D4A44493B7FC3FFFFFFFFFFE3AC6E35212D386BB5DAF2DEBD844A241C2B3670B2D5BF863A000120244FA0D2D1A84762544C7EC0E6EDDCB3938B9CA3B9D5D8D5C2AEA5A2A3DAF2DEBD844A241C01FE455B07071850796F4B1E0003244D748067340F112C68AED9E2C36729091F5CB2E4E8CD9843141E5598CAD5CFB053100E377BAEA690633A180D103990C4D5CFC8BB733000000010509BADACC6C69A551F151757A9E0F5F5E2DBCA782B1B509ECBD9AD511A3C91AE91687D927024052A5D9BCCD5C990581D0000052C5373644D3D3327130704070B0F121D231E262A2E383A3239434652474D4650545150514C4B4C4E504D563F8BDBFFFFFFFFFFF5BF733C282E3664B5ECF5E9BB8346212031387AAECEC28841120A131F4D9CCAD0A6444C484B83C5EAEDDFC1999098AEC6CFD5D5C8B1AB9FACECF5E9BB8346212001FE465B07071860767B541C000A2B50728366421313285EA2D9EFCB6C21101A59A3D0E3C690411F1B4EA3CED5C79D5011093880AFAC88713B1106113F8EC9D7CFC29E6F290000001D5697BFB4CEC295541C0F2461B5EDF3E7E7DFC17E251B4B97CDD7AC4A1F4496AF92697A9360210C285CAAD7D9C391541D00000027577A684A40322D1A01030003161915282B33333A3D3630393B3948474E4B4E4C535F56524E4A504E434A3983C7FFFFFFFFFFF0B97A3222263767B5E5FADDBB79382C23303E72B0D0CC86440F030C215498CDCBA14656545D7AC0E9F1D7B4A6949BA6B4CBDAD2C8B39DA7ADE5FADDBB79382C2301FE475B07071870867C461200002049727F6F3C1A132A60A8DDDCB7691C091C52A6D9E7D2893B171F519CC9D0CA9B531C0B3877A6A78E6934110012438ECBDAC3BBB176330000001B5C9DB9B7CCC29C50190C2059B3E6FFF0E4DDC16F302A5D93C7D3A94F1E4586A9945E778A641C072A65A0D0CEC390651E00000124576C5F524642230F0E0304040C202524292C23333D313231383D46544E5057555558595B534F5B4A444D3C79C2FFFFFFFFFFEAB66F3426302658BCE7F6E3C685412D2A2E436BAAD8B98B440907082C52A6D5CFAA4C66564D76B5EEEDD6BF9A8B9FA6BDCFE8CFC0A8A9ABABE7F6E3C685412D2A01FE485B0707188074704414000020466D82683E16102F68A3D9E3BA6D230A1F5998CCD1CA90471E164AA1D1DFDBAD520A062F72A2B07F66381105173D83C5E3D2C7B076310000001A54A1B5B2D5C593491910215FB2F0F3E2E7DDC9702C1D4C98C8D2A055223D84AB9268828F641D102A649FC3D4CA9653110000002957807258463032110000030F0F0A101A14242E353C3A3A353949464D4B4649525D625F5C5A5453554A4C308FD1FFFFFFFFFFEFB57A3A273B3E6DB1EEF9E9A1703D3026404C81BDD8CD8A3A0A0C0F1752A5D9D1A554675D5D79BCECEFD5AA8F9AA0AEC4CFDDD5D0AEC0A6A8EEF9E9A1703D302601FE495B0707189079704C1E0006204F7686723F1E14346BABDAE7B96B281A29569FD6D6D08648232256A6CED5CDAC52160A3581ACAA91693508000D3985BEE0D0C2B376270000001F5399BFB4C8C6975418112155B6E7F3E9ECE3CE7E2A1C5497CECAA55121408FA38C60758A6122032562A7CCC9BA945C23000000255E786A544134201D10040B0918161E191C25242C313938323B4C4A4A534E53524B504C5B5158564E4C403576BAF8FFFFFFFFE7BE773D1F2E345CBCE9EADFBE893F221D334E7EAAD3C8933C110C0A1F53AACCD4A24B65565E79B7E4F1D7B490869498B8D4DFD4BCAEA6A2A4E9EADFBE893F221D01FE4A5B070718A07C754C12000332567988723311112B6EAED8DBB86628192A5CACD4E1D281401D25589BCFCDCC9E5214053681B0A68C64351406063A92C8E8DAD1B472260000001858A5BDB4D3C79E53190D225BB8E9EDE5E5D6C2762C1F59A4CDCDA24F264387B59F687D95581D0F2E72A4CBD0BD88491D000000286376704F49302C0E000500000E18121717222F38363E3D34353F4E4E484C5053555E574D5654565247473A7FC0FFFFFFFFFFF6BE7E3E2A273462BBECF0E7BA7F3C261E2D6387B4D5BF833D0E04031A439AC5CA9C405D595882C5E3ECD4C198919DA6B9C2D9D4CEB2A89FA4ECF0E7BA7F3C261E01FE4B5B070718B079734C0E0000144D777C703B19183066A6D0DBBB68280E2254A4D5D4C1813E1A1F539DC6D7C9AC4E140A3184A8AB9269380E0610419ECBD7C7C4A76E210000001D5BA3B0A9C5C89C54140C225EB4F5FBEDEAE8CC7627205399C4CE9F50213882AD915E798C6715032667A9C9CBBA975217000001295E8070524E372714070008101216212E2A2D3131342C2E3B3B434A4D484E5660585A5556544E5A4D4B493B83BFFFFFFFFFFFF6BB73352E353A63B7E5FAEFBB773C221B2F4A78C6D9C280390B080C1C53A5D3D0AC4D6450557DB7F1E8DBB494889DA7BFD4D4D4C2AFA4ABA8E5FAEFBB773C221B01FE4C5B070718C0786D3B10000420487C816B3511112A67A8DCE0BD6C27112456ACD9DFD78D3D151C59A1D1C8C9A849140C397BB6B399672F04000C438FCADFC1C5AD6F250000001754A6BEB9D2C59645120D2068B9E9EEE4E9EAC67532225698D0D3A74E1D3E8BAE956977925F1B0D2868ABD7D3BD8E52170000002663796A5844331D1608030005121515201A212B37362B30383C4052524C504F59585C574E4A494F494E4D3D72B9FAFFFFFFFFF3B86F3A252C3359B9EFF2E3B77A421D253B3C71BADAC18B35050006164CA8D1CA9E45564D5587C7E7EFDBB48A919DA8C7D1DFCDC7AEAFA6A5EFF2E3B77A421D2501FE4D5B070718D07573431100000E3D6479673D141A3368ADD1E5B1591F162457A0D4D6CB88401F2754ABD7DAD2A24F1608337EAAA7966E371506124796C9D6C7C2B0661E0000001D54A2BCB5CBCA8D5219092F71ADDCE1E2E9E0C27A2521439CC7D2A44E284888B59D6E7D8B611B113272AED3CFC29256140000002669746D513F241A08080304060D171F2026292A32372E393C32454849544D4E5B5B524E5251504B4144474183B5FFFFFFFFFFEBAE6C3326273D5FAAEAFBE6B976391F28384B7BBDC4B8823A0404131657A9D1C39B4268545D7FBFDCEFE0B98E9096A1B2DAD9D3C8B59EA1A7EAFBE6B976391F2801FE4E5B070718E07B704815000020527B7A5D311B192D68B8E1DBB35924101E54A7D4DAC5853A132251A2C9D4D29B5317093781A8B3A16D380A000C4593C0E0C9B7B064240000001854A5B7B9CEC696501509216DBFE8E4DCDCD6C97F2D285BA2CBCB9B5229428FAC8A6C8793601E092C61A1C5CBB98D5C1B0000002E7484775E4B362812090A060008171C1A1E2123363A313A3639464943474E4C50545156504D545A5546453B8BC3FFFFFFFFFFEDB2653F27353964AEE4F3EDB0743C261A2E4F83B6D2C181370E0A052160A2DAD09D4658575E80B5E1E3DBB697889BA9C3DCD7D4C0A9A2A2A4E4F3EDB0743C261A01FE4F5B070718F0726B4A150000164770766430131A3769AAEAD9BC631E091D59AAD8EAC47D3B0C18539CCFD7D5A7530E0C3172A5A693693813000E408FC4D5CABAAB7233010000175DA7B7B5CEC9944B1205215FB0F2F0E4E1E1C66F23215499C8D0A44E26468CAE896A8392611D022567AAD6D9C3884D1B00000028657F6B553A2E22130902060915101C1A1C252D33362D31363F424B4E494B4D4F555F5C59534D53534C4B368CBCFFFFFFFFFFF1BC763E27343F78C5F3FFEEB976442820344582BDD6AF8231130811294F92D3D6A750574B4D80C6F0F2D7A9848E979FC5D5E7D9BEAFA3AB9DF3FFEEB97644282001FE505B070718007665410C000013486D7768310E0B2E64A3E0DBBD621808215AA4D0DDC8883C1D1953A0CADAD09E57140E3785AC9F8A632E1710113490CADDD4CBA5672A0000001F5FB0C1B8CDC6964F1604275AB2DDF4DDD8DECA72251E569FC3C6AA5728499DAA8D6880925E1A123272A1C9CCB98B51150000072F6B87745B472C291C0D000008100C171815202A34413A333138394642504C4E515856585C464F4E4C4F543C89CCFFFFFFFFFFE8C6783D2A2E3670BFEEFCE6BD7B42221B374B70BCD6C78C3F0B060E1C529ED2C19E475D545F7EC8E1E8D3B89F949DB0C3D5D8D5C1AAA6A6ABEEFCE6BD7B42221B01FE515B0707181077744E1A000A1F4B728C683C0E103573AFE3EFB75F1E12315CB0D7DEC8883E22254FB0D5D2C9964F180F3B7DAD9D86632E0600124596BED3CBBCAD682D020000205DA7C5C1CBC28E4B1F0B175FB4EDE4E3EBD6C7772D2B619DCBD298471C3A8FAC925F7F94631E0E3077ABD3DCB487571600000033677B675A4D34240D00000108121818151C28242D312B3B343A45424B4D4B504F575C575A484C4A4F433F3E7DCCFFFFFFFFFFF3B873403135356EB7F4F3DDB57F372A1D333D7EBCD8BF86480F080C1D4FA4D3CD9F3C58565A82C2F1F0E0BE908D94A4BBCFE0DFC0AAA2A4AAF4F3DDB57F372A1D01FE525B0707182078744A1D00001E4C7F7C683C10112B66AEE2E2B961240E1B5AA5CEDCC4863A1E22589FC2CED09D4F17033889B0B08C632F0D0014459CC6DAD2C7A86B270000001A62A5B5BBCDBD89470F081767BAF5ECE0D8D9B874332558A2D4D79C4A264891AB8A6A7E8E58180E3572ABCBCFBC85500F0000002C6E896F5E493B321505000107150C10191823342D3033302B3841474B525750504B4F5559564F5C4C47453772B3FDFFFFFFFFF1BB6B33232D3868B4F1F8F5BF72382A1B2E4881B9D0C580390D04051950AAD8C4A945584B5481BCE6F0D6B09B9493A0C3D9DFD0C7ADA3A6A8F1F8F5BF72382A1B01FE535B07071830828251170000224B747F6B310F132F6CADD0E2AF5C23113267ACDFEAD18A39181A5498CAD2CFA656180E3B85ADAE8E67370D050E358FC3D9CFC0A85C1C0000002164A0C1B9CAC5944A1C0D2069B5E9E7E1D3DECA733325579BCCC99F4B1B4295A69773838C531D082F77B5D3D0C2995A14000007316F81725F4B34200B09030001090D131C1C25232E30333731393842454A4F5D53505C5F5B4A4F4F4D484E347CB6FFFFFFFFFFEEAC642D29273974CDEBF8E4B9763D1E1527508CBBD9C57C3C0F030B1D50A6D7C5974061575E82C0EEF0D5B19B949CA5C2CBD2CBCBADB4A4ABEBF8E4B9763D1E1501FE545B070718407B7153230000245276806D3C1A1C3561ADDCEDC35E220F2361ABD3E4CC833E232356A7CCD4CA9C480B154387AFAE8C5F30140A123D9BD0DBC6BBA86A250000022661A7AEB7C3BF904414012668BAECFBE6E6D5C37628295495CECAA54419488BAC936C81904F16043172ABC5CCBD865314000011426B897153483E2E14000009121216131F1D1A2C2B2E2D32353845484F514D4D4453524B4F51514E53514D437FB5F3FFFFFFFFF6AB622917283964B2E7EBDFB279330D13325384C3D9BA7E3D0900122259ABD3CDA4456154577EC7EDECD4B2868C96AABDD5D6D0C1AEA5B0A8E7EBDFB279330D1301FE555B07071850817B480E000024536A7C5D310F103470B7E3E3B36221182E5BAFD4DECA833B111B50A3CCCAC69C491A0F3F86ADAB8E61310E00114599C3CAC9C6AA671F000000225EADB6B7D2C1834315062963B9F3F6E9DAD6C26F2A24519ED2CE9F471E4391B092749192591D0F3572AED8D8BE854A14000003386F81705B4536270D030508150F12192221171D242A3D36353E43484A4850524D4E594F4D524D564E4448388DC4FFFFFFFFFFFDB9713D262F4373BDF2FBEDBD7228231B3A4D83BCD5BC82310802101B58AAD3C89D425F5E6191CDEEF3D7A8848593A9C6D7D8CDBEAAA6B0ABF2FBEDBD7228231B01FE565B0707186079754916000827557876612B13153A69AFDDE1B76126091E59A1D8E0C37D3D10215AA4C9D5C697470C0D3D7DA5B1956B3B0D00154993CFDACAC0B36F1B000000245DA3B3B0D3C08B4213102D63C0E3EBE4E0E5C674211753A1D7D294411E4E98B9936A84985C180C3677B3D1CDC080420E0000062E6D8A796445372812010001080A1313191D2D22243233322E3843434D4B4A4E4B515953564B4A54524E4E3879C6FFFFFFFFFFFBB4773C272E3F73C0EFF9E0BB83331F1C314980BED9C3803A16130F2053AAD4D39E404E4A5E8CC3F1F0D6AE8F949CA4B7DBE2CDC1ADA4A1A3EFF9E0BB83331F1C01FE575B07071870736F541200001C4B73785F2912113872B6E3DFB0631F0B265CA5CADBC27A390A1C58A6D0C9C1994E0F0D468FBDB09665270B04104E9EDCDFCBC8A8611C0000001466ACBCBEC8B8823D1208286BC8ECDDDFD6D5C0692125609FCDC7973F1C3C98B79C68868E551F163474AACFC6A77A3F0600000C2E7399805E5239250E030000000A0D1B1C23222937322C3B3D3E3B474D4D444351565755565A4B554F49453C8EC8FFFFFFFFFFECB470332E3C3C7ABDF5FFF0C0743D2F28435D92C6D6CC7A1D0904122956A6D8C2904157545F89CFF0F0D8AF908FA3ADC9D9DCD2C0A99CA4A4F5FFF0C0743D2F2801FE585B0707188079743E1000001E4F6B7F64351115306DB2E2E2AE5A251A245FB0D4DDC1783B171A59A8C3CEC99D3F0A02398AB2AD8F642C15090F4B9DD5D9CDB9AB641F0000002675BCBFB5C4C0823D09032168BAECECDEDBE1BF7125265AA4CDCF974321498FAA93738B8E4B13113076B8CCCEBA7E5212000000366E8A70644F3A1D0E0800060E09151C19161E242C272C31393B3E4F525455524C494F574C514D4D4949473C8BCCFFFFFFFFFFEBC3723123303D7CCCEDF5E7B46F36241D346690C8DDCA77340B000C1B56A8C9CF9E43594F5597C8F1ECDAB68D8498A8C3D0E2CABDA4A4A5A4EDF5E7B46F36241D01FE595B07071890666837080000194A6F76552E050A2E70B7E6E7B556120D2767B4E0D9BA8030172853B4C6CAC68F4515184493ADA8866732010B1E46A2C4D0C9CCA65B18000000246CB2B9B9C8B57F4109043174C0EAE6DDDFDFC16D2E285F9DCEC5933E1B4692A78A6E868D531A103E7AAAC9C8BE85500C0000083B79916D614D2E1E0F02000004080A15161F2425303B3F3C3C393C3E4A494A4C4C53524B56514B5454504F3898DDFFFFFFFFFFF3BA723E2F354171CAF9FCEFBA7C3522203E5C8FC9D9C582391006101950A4C8C49C4A515B628BCEF1FFD2B19394A6A6BFD1D2C5BFAC9CA3AEF9FCEFBA7C35222001FE5A5B070718A077724C1600001538607B582A0C0F2979B2E8DDAD5718082064B2DBDFC37D31122462B3C8D4CB913D0D164B90B2AF8D5926060217459FCCD6CABDA664170000002263A8B5BACFC07E3C170A2674C3EFEDDBE2DCC469211F569FD5C88D431F5298AB967482864E120D4076B7D2CBB37E470A000003437E8D785D483329150500000012191A1616182332372A2F3236454B524A4B4D4B545658544F47534A484D3E8ACBFFFFFFFFFFEFB16D372A353C6BC0F5FCEDB672361716395F8DC5D3BE7F3A12000C13519FCEC897405A4F558BC7F1F2DEB7948B969EBED9DFDBBFA7A1A7A8F5FCEDB67236171601FE5B5B070718B078764C1800001E4D7277582E120F3668BDE4E4AF4B21192963BAD4D5BF8139132064ACC7D0D19D4717104187BAB2885A2C0604184A9DCBD6C4BFA1570F0000063271ADBFBFCCBC86410D0E2B70BEECF7E2DDE6C86A2E1F5CA0CCCB933F20498DB199718184521C0E3B73ABD6D0B07B40170000093C7690715C433621060000000F101913201B1C1C30323238363C46444A444D55545555485356564E514F493D94CDFFFFFFFFFFE7AD603928314471B8EFFFE3B6763B1B15405887CBD7BB752D0005142659A7D1C3953E504F588DCDF2FAC7B58B8E9CAACAD5DCC4BCA7A29DA9EFFFE3B6763B1B1501FE5C5B070718C07272490F000023466A6F531F050A2673BAE2E3A9511813265EA5DCDBBF7E3714265FB2C6CFBF8C3F07063F8EAFA792633708001558A5D4D3C1C0A85F1C0000002467B5C3BBD7B97E37110D216DB4E8EEDDE5E0BD752A285798CDC78E42114997AC94708C8D5115083278AAD1D3BA7E451000000C477E938367483A240C050000000412111D2127272C2F2B342E3A3C45503E485356535B57504C5253544A4F3A84BCFFFFFFFFFFECBA7143323E4679CAF7FFE0C06C34121339628CC5D9BA73290D08162459ADDBC9903F5152648BD1F2F0D3AB838696ABCAD8DED9BDA59CA0B4F7FFE0C06C34121301FE5D5B070718D0726F460B00001C4374765931130A3176C5E5D69F491A0A1767ADDEE1C47635152663B1CDD6C290450C144A83AFA48F591D0504184CA0CBD0C2BBA063210000052A73B1BEBDD2B9823E130D286BB7E0E4E7E7DFCB6C222460A0C3CD9A47264D92AB976F8E8C56150F3C74B1D2CEB7804513000006478390775A472F220B0500000F10121E211A232D2931333638323A3F54525652454A5A50534D4F57574F523E94CFFFFFFFFFFFECB972312D584773C7F3F6E1B4662D0F1A445D95CBDCBF7C330A02121F52AED6CA9A4A48495F9ED6EAEEDDAD90889DAFC0D0CFD5BCACA6A5A7F3F6E1B4662D0F1A01FE5E5B070718E06968401100001E4A6A755F2607163971C0DCD8A94D170D2764B2D3D6BC772A0F1E60ADCCD6D29A440B0C3E8AB5B393532B08051F4BA1CBD6CCC1A14F180000062D70ABC4C4CEBB7C45100B2871C1E7E9D9E5DAD173231E5EA6CDC3953F1B4D97B09971798046150C357CABCCCAAC7A410300000E4281987A634A312808030000040C161E241A242C3132333729313C45474B4C4E5356585353574F584F4F453688BEFFFFFFFFFFCEAC5E282D3E486CBFE7F9E6B1713C1F1845689FD2D9BA6A2E0300142466B7DBBE96425C575E86D5F3ECDCB78F8CA1A9C0D7E1D2B79DA19F98E7F9E6B1713C1F1801FE5F5B070718F076753F1300001C4D6D725A2D0719377BC3E1DCA65D1E0A245FB4D7E2C07F321F1867B4CAD1C7973D0C144799BCA98D612106001252A5BFCCBBB9A35519000000286DB8B7B2CEBA7E3F130C2B76C2F0E3E1D6D3C975352F619CCFCCA5461A448FAD926E8D8E450A114280B4D3D4BB7A4F0C00000140768E765E4234301B000000030A12131A18242C302F282E363836434E454E4C5054554F48554A4C4C443F3E93D2FFFFFFFFFFF3B56C37303D3F78C3F1F8EAB1713723164B6B9ACCE5C170311505102D58ADD7C0923D525A6995D4F6F8D4B18B91A3A8BFDDD9D2C1A39D9EA8F1F8EAB17137231601FE605B070718007C73431000032B496F77542F1A21337ABBDFD9A7591A152C76B9D2D8BD6D2F171F62ABC9D1C2924110195293B9AB92572506001553ACD4D5CDC5A85D14000006236AB4BFB9CDB1753919142C66BCF0EBD4D7D4C37926235DA1CED29345214F92B0936D92873B16113277AEE3D5AF7449080000024482937E6C4B2F1D07000006040F151E181F292B2A2D33302D3F46444844454F4A4C5B585E594D52504D4D3A8EDCFFFFFFFFFFF4AF6735263E4382CEF9F9EDBD74311A1F406F97C7CEAB6C2E130C0A2453ABDAC79440595B618ECEECEFDAB2878F9DA7BFD7DCD2B99DA1A5AFF9F9EDBD74311A1F01FE615B070718106A76440E00001C4C6B6E5A2307163B80C3E2D3A65B18112768BDE0E7C172331F226FA8C6CBC48A3B0D104386AFAF8B532404041855A8D1CCC6C6A559120000012E70BDC7C6D2B37B360B03236DC4F0F3E2E5DCCA6D2720559CD0D09535175595AB9F7D92854B090A3E77B3C9CCB47C4C0B0000043D808E81614A3A24090500000508101B1A221A213037333332383C43484B475051515B62605C5650534B40347EB5FFFFFFFFFFE6A368392B3E4680CBF8F8D7B2723510173A6096C5DCBD792B04080E3055AFCFBE873D574F6999C7F9F3D8AA8D8392B2BDD6DDD3B99F99A2A4F8F8D7B27235101701FE625B070718207D6F441700042B4F6F7A602B13163A79C9DED3954D110A246EBFE2E2C2793A17276DC2D2D1CA8E370F144A88B3AC89542A0F0A245CA4CFD9CCC5AF5E1F0000042C76B3C6BFC6B6753A080A2972BEE8E8D3E2D7BA6A27245CA5CAC78E372357A2B99F768A84450E0A4A89B7CDC8A6783C060000094885957960473C1C10000000000A11111B17262931333534313839413D42474E54515457584F56554B454A3682C8FFFFFFFFFFEFA3623B2C2F3B75C8F6FDE2A36F351B1E38639ACED8C371230705111E5FB0D6BC8D3A4B596CA1D3F2EAD9B29592A3B2C0D4DACBB7A49CA1A4F6FDE2A36F351B1E01FE635B0707183076703E07000026546F744E220F0D3381BFD8DCA04E1D11296DAED5E0C56E3416256DB3C5D9BC8838070B4391B5AE895322090C1D59A4D0CDC8C3AC570A0000082771B8CCC0D7C67B35090F2C6DBEEAE2D2DAD4B85E222B63A6D2C7913C2254A0B89C768183400409478AC2CFD8B6743D0400000847879878543F311B0500000005130A0E2024262A28333733343D3D404A464D4B4F54545B5B54514F4F47473480BAFCFFFFFFFEE9AB6F3E3D37427ABFFCEFDCAC703013164472AFD2DFBA6F2E05030B2258B4CCC1883A4B596AA0D3F2F1DBB08F879DABC0CED7C7AFA1A6ADA7FCEFDCAC7030131601FE645B07071840837D511C0009284D6F7B5A2E15223E84C9E4DB994C180C2D72B8E1EACA7830172977B6D2D3C79A3C060E4C91B5AE864F2506061E50A2C4CAC6CBBC59110000043171B7BBBDCDB26E2D0D0D3B79CCEEF0E1D7DBC1651F2460A6D1C987371B489CAB967686753F0E0A3F7AB6CEC2B37A4809000016488B9C7E5E433723060000000A12151C1C1E25282C342C37303B4649443E46484D52564B50535D4D5146533B79AEF3FFFFFFFFD5985D30282E4379D5F0FAE2AA6432191A3A6C9EC6D3B4732900000D245FBCD7C08B3E4B556D9ED2F1E6D2AA889092B0CADFD9C7BB98A1A7B0F0FAE2AA6432191A01FE655B0707185072673C14000025466C6F492B101B3B89C8E1D0984C150E2A6FC3DFE1B6722D152974B5CCD3BE8D3F11104E88BCB0854F240803175EA9C5D0B8BAA05C160000022D80C4CABBD3B8712F090C2C70D0F3EDD5D2D5C05F211F629ACDC78A3F295BA1B29A6D878647080E4080A7C6CBB17D4A030000184892A27B5B4A2C1B0300000308121B1919181F2A2A312C2C2F32393F473E454A49555B544F485156534B463E8CC2FEFFFFFFFFE1A9653F343E4486CEF9FCE3B272351F22466A9DCFE6BA792A0F00061F62BCD4B7893E4F546DA3DCF2F0D0B1888A8EA2C2D0DEC9B39B8FAA9DF9FCE3B272351F2201FE665B070718606D6F3E0E000724567679532E0D1C3A72C0DFD3AC581D1D3D75BBE3D2B36A3219287EBCD3D5C28C36060E4886B2AD7E5B2909062066AECDD9C0C4B25E140000002B76B6BCC2CEAF682A06083076BDF2E6E1E6DFC4661F2763A4C2C291462F5E9FB08F7784813906094193B4D9CBA7763D0300000D508C9E7F634B3823030600000013131B222421202C232731363F494644474A494C544E535353494C4D4B493C89B1F3FFFFFFFFE59D60382F374B82D1F3F7DFBB672413164171A3D5DCAF6C2A090E0C2366B6D1BB84384B536093D6F1EACFAE6F7193ADCCDAE0C7B6A1A8A4AAF3F7DFBB6724131601FE675B0707187076714B0F00021D50706C4C2105133B82CAE2D59B4A1D0B3775B9EAE0B867231A3178BED1DBC57931090B409AB3B1884D2304091E63B0D9C2BAC1AA5A100000003175AFC1B6CFB6723006033579C7F2E0DCE7DFBF66242760AECFCA994124639FB591748A8B36021B3C81BDC5BFAD733C0000000C478A9B78614736240A000000051311162226282F2F313038283C4040494246514C525952525152534B47483988B6EBFFFFFFFFDDA2633A263E4B7CDDFFFDD3A05D2A1B16486CA1D2DDBA69230000062A59ADD1BF88354D506BA1DAF5EFCFAB8C8297AACAE2D9CFBE9EA09DA6FFFDD3A05D2A1B1601FE685B07071880797C440E00062957767B59300C1C3F8FD3EADF9B4916163A73B0D7E4AF67270B2D74C1CED5C38B3F0813558FB0A080521500092463B0DBD2C7C3AA51120000033573B6C0B8CBB57330050D377BC3E4EBDCE3DBC265282D63A8C1CA884028589EB693718B7E3007124A8BC3D2C7AE6E2F000000104F8D9A7A6344312009000005010F121A1F1D232525313B3931373C4E494F46504D52565454445158504948348ABDFFFFFFFFFFDAA9662E2D444F85D9FFFCE6A7642E16244476A4CACDB3672F0D09092162B1D9B78238525E6B9DD6ECF1D2A6808390AFCDE4D9C8B5A19CAEAEFFFCE6A7642E162401FE695B07071890747F4C1C000A2B4D6F74532F0E1B4196D7F1D6985116143171B5DBE9C074261D306CC0DCCEC883330F164992B0A78B5A2B0303275CA7CDD2C0B99F55190000023682BEBDBCD6BA743310083674C8E7F1E3DFDFB96216125AADD0C2853A225B99A7967987803908174A84B8D4C3A8693F1000001253909E8165492D1C06000000070D0B081423232428312C35293A3D474A4F49525051525451524C554D524B438DCAFFFFFFFFFFEAA0643D38465390D9F7F2E1AD582B0C19437BB5DDE1AE5D1D0512142060B5D4BC8436505A6EA2CEEDECCDA57F829FADCADDDAD5B89F9895A1F7F2E1AD582B0C1901FE6A5B070718A0777A3F13000020526F69531A0813377ECBF0D79745130C3574B5DBE3B371271F297FB7C9D2BA82320F125195B6AB87521C0D022269A5B5D4C1B79C5A170000023A7EB7B9BBD6B26F2D100B2E73CBF1E2CED7D2BD61242972B3D3D08E391A60A3B99C7987713400054B91BBCFC3A9643E000000185F9AA484605237190000000001090B161C1C2623252F292D323749494948484D4B505851545356585346493D8BC4FFFFFFFFFFEDA6664136435094DDFDFDECB1692B1F2B497DAFD6D4AC6328080F0F2964B8D8BF7D4051596F9CD4EFECD2A488989BACC5D6D5CBB9A2969E9DFDFDECB1692B1F2B01FE6B5B070718B07F784510030022516F774D2C0F1F448FCCE3E1A045101A356EB7DEDEB06223182F80BCCCD1C279340B155091B5BC884B1E05103268AFCFC9AAAE994F150000093C86BEC0C6CEAF67300E072E76C7EAE8DDD4DACC621E1C6AADCEC98B38285D92B09172897B310616468DBDCAC9A3774000000013629C9D77604A2C1C01000005080D151A1D1F1A3031312A2E322F3B4C514A4C515A595A46474853514D4B49388AB9EFFFFFFFFFE1A6603229385C8CD2FFF9D7A4702517224179AADCDDBC72250912181C63BBD5B87D3B525C6D9ED6F1EFD7AC818293A9CADBD2C7B4A58997A5FFF9D7A47025172201FE6C5B070718C0747C4F1600103054676D522E14213D8BD4EEDB9A441A123577B6DED6B470281D2D80C1D7DCC2772D060C5CA4B9AA7E50200000256DB5C9C6B2C4A14B0B000007367EBFCABECBA4702D0F093B80CCE9D7C9D7DBC46924245FA6D4C988341D5E9FBA9A7D91743510154F92C1D2C5AD7037000000155DA8A5815F4023220D0000000010131011191E242D37363131303F4340464B4F4D5250494D59575A51504E358BBFFFFFFFFFFFE79E6839353E5495D9FFFBE7B362361B1C487FB8DEDFB36627040314336BB4D1B67C32505F75A6DBF6EACFB08E869DAEC4DED1C1B8A39699A8FFFBE7B362361B1C01FE6D5B070718D070733F1300062C4B6D6A4B1E0E1C3D8BD2F2D8953F1D11326DB6DEDFB0672D223981CAC7D2C17D2F0B14599CB5A4864A1C000A2E6DBBCFC2BEBCA148130000014593C3C1B9CBAB65240B12397BC1E8E5D7DED9B9601F2A68A8CBC48B36275CA4AB8D7B83772D06145091BFD1CAA36F320000001461A4A685674F2D2009000000031208131620232929303735303E474A4A3D4B534C50585051574B434750493584C5F4FFFFFFFFE5AF5E373F3E4D92ECFFFFE998542F161E4488BBDBE0B4642310060D2066BBD1B67B2D51556EA7E0F6ECC99E848598B0C4DEDDCBB197939DAAFFFFE998542F161E01FE6E5B070718E080764D1A000D30587366542F111F4895CCECD48945151E3275BDDCD5AC6A270E347AC8CBD5BA82300B14559CBBBC8D4F1502022276B5C9C5BABA9A4E0F0000023986C2C4C8CEB06924030A3182D0F1E8D0D3D4BD53192460A7CFC08039276AA7B99F7F8B7434111E4D98B8CBC19B6A3B0300001F62A5A7816A5130160000000000050A131A1B21242834333832323A3B40464C4548565352534F5C524D49483988C9FEFFFFFFFFE5A96442394459A4E1FDFFDFA36137191B4A86B5E1E5BC6C260502122A6BB7CEB6A139534D6DAEDEF5E2C6AD868199B0D6E0D4C3B29DA3AAA4FDFFDFA36137191B01FE6F5B070718F06F784F1500092A536A68511E061E4585CDE5D08B4225183177C2E6E1AC5C211A3D8DC6D8CFC47E260D105698BAAD81491A0C0A2876AECEC0B3B49A530E000015448BC4C6C0C4A5611D050F3788D6F0D7C8D4C9B66721266CB1D7CD863A3068A7B9A7788C692B0514508DBDD4C3AD642F00000011649FAB865A46331F0300000000070F1B2121242A2836333735363D4140454C5558595C5E5646454A493F433A80C7FDFFFFFFFFE59F6346433D629BD6FFFEDDAE6A2B151A4188BADEDEAE5E230212193165ACD1B27C2B4F5670AADFF1EFCEAC89849DB2D3DFD6C19B959A9DA9FFFEDDAE6A2B151A01FE705B070718006E7143130000214F676B431A07174091D7EBD2954B151F3373B1DAD6AC632517408BC1D7CABB81300C23588FAEA67F4F1D08093577BECDD4BEAF9A4C0400000D3B8FC9CECBCDA65F30070D357CCAEDE4CDD7DBB756212F6FADCEB77D35295CA1AE9177896B3105165297B8CDC5A1672F0000001F68A4AE7C5B462F150900000008151114191B233128312E383B3E444147494A44444D5D4E544B47545156462D85AEECFFFFFFFFCD975A3236385297EAFFF6D6A04E281E21528AC3E0E3BC5D1B0000122660B7C8AF7A3B46546CABE9FEFBD4A68A899AB3D2D9D8CCB295979F9BFFF6D6A04E281E2101FE715B070718107A793F0F000932557469481F0915458CCAEFCA8F3C13153677B9E1EAB65D180F2D8ECBCED4C0882A0707469FB5AB7A431C0416367BB9C1C3B2B89C4F1500000A4289CFC4BCC4A85827080D478DD1E9DED3D9CCB7692B387DB6D4C47E353063A0AD9A7A8465260317509BC5D3CDA1784100000018629CA689614C33190000000B02091617131520232D2C2D31393940443F3A484F4D505A5752524E544A4046377BB3E4FFFFFFFFD595513E33424B8BE0F9FDE79E57280D1D488CBAD9DCAC5E17070A142B6FC0CFA56D2C52607EB6CFDDE8C5A18A89AAB6CAE2E0C8B1A79EA19FF9FDE79E57280D1D01FE725B070718206D71410E0000264365613C1A0E244B99D9E6D294420E133A85CAE9E4A254211B3B8BCAD7CFB46625071E5B96B2AE824A23010B357AC3D2C7B6BB9B4A0400000E4096C6C2B7C0A9651D00113F88CEE8DDD0D7D5C15C1A2276B0D4C2803025719FB4A17D856F2F04205E98BDC5C8A467310200001E69A2AF825A45241501000000080813141A182022242D363732343D4644495255534E514F505050534E46433587BEFCFFFFFFFFDBA5643933435DA5ECE2DFD9A15F27181E4F96C4DFE2BF65240D060C2971B7D0AE752A4B5874AEE3F1F0C89F8A849BB8CAE1E5D1968F95A1A9E2DFD9A15F27181E01FE735B070718307D7B460E00082F496F64461F0F1C52A5DDEBC383370B163F86CBDEDAA1591412318CCCCFD6C0731E001E589CB7A788471E00063274B4C9BEB5B6A0460900001F4F92C3CEB9C7A45E2B0C103C80CFE6DCC5CDD0BE69213473BADAC57C373162A9ABA076826B240B215C92B7C3B293692D0000002669AEA4826B4A2D100200000712181618201A1B262C3328292F323D433E485157514B55525052504F4D454C398EB9F6FFFFFFFFD69E5C423B4053A3ECFFF5D8A95A2812235A94D5DFD8AF5D261412172872B7BFA770344E6477AFE0F1E9CD9A83848BB9D6DDE0CAB29B9CA1A6FFF5D8A95A28122301FE745B07071840727B431600083554625E4E200C1B54A2DDF1CB8139141E4192CDDCD9AC591F193B91D3D0CCB57020031F64A3B29F7B4F1D04053675BBC2B9B5BE96430D000012438BD1C7BAD19F5123091D4B99D3E5D8BED3D3B851192C7FB1C2B97D3F386FA7AD95818A642608205998C4D3D1A76D2E000000136FA6A6805E47261600000000000F11181F201F282C38312B32453F3C3F424A585355534E5155594F494B4D2F7DA7E7FFFFFFFFD99E5C3139485AA5E8FFF7DB9C58210D225490C9E0EAB6611C060D172B74BFD5AB74384A5C77AFE5F7E9CF95737997ADD0E3D5BBA79E9A9DB0FFF7DB9C58210D2201FE755B0707185072733E1100032F50685D341E0C1E52A2DCEFD2833A0F1A4284C4DCDDA15624183F97D3D4D9B96C260F1A62A4BAAF7B4A150107367BAFB9BEAFC19C490900001C4C98C8C8C3BE954B1F0315418DD2E7D4C6D2DAB153183F7BBCD5BF7C2C2764A7AAA084895D1E061C4E92C1D8C2A26F32000000296BABAF866F4629120000080200061014131C1D222A302B2C29334341474B4E4A544E4C4C5B5854515F4C55387FB2E5FFFFFFFFD38F523A3C5562A5E7FBF2C2935F2A161F4B99C7E0E4AF5B180B13153474B9CEA2702C4D5B7EB3DEF6EBD09C79849FB9C9DAD7BEB59D9396A0FBF2C2935F2A161F01FE765B070718607F8248120008325F746C451A111F57A1D6EECD7B3E0C194D8CD8F1D8A249201F4D97D6D8DCB9762108135E9DABA07E4510010C327EB8C4BDB1B18E4A080000135995C7CEC7C5A150280E154C8CCDEBCFB2D0D8BA521E3A74B2D2D382362D65AAB29C818D6516001D548EBDCEC3A25D2D0000013273B9B5815C422615070000000D0C101113161B24232B33362A2E37414147555550515B5953554C4E5249423C83ABE9FFFFFFFFCC92573745485FADEBFFFFD592532315275695C8E4D2AD6226030315317EBED9A4683252607CB5E9F8F0C984787F9CB1C9DAD7C2AD959AA0A7FFFFD5925323152701FE775B07071870817A491000072B4C655B3C1C1422559FDFE9D3823816264C90D1E6E0984F2017409DD3D1D2B9661A000E5EA6BBAA7A481A030C3687BFC0B0B6BA96450700001E52A2CCD4CBCF944B150B184F95CFEAD3BECFCEAC591C3876B2D1CA77262369A3AC9E858E671E00145797C7D0C1A56D30050000267CB0A485603B26110000000007060D161823292A31303C383140443F45424D464E555F52514C51534C4B502F7EA9EDFFFFFFFFD99D67455E606EBAEAFFFBD494512814185699C5E5DEAD55250400132D70B7C7A5662E4E627FBBEAF8E5C2988E7D8BB6D0DDD7C7A9928FA4A6FFFBD4945128141801FE785B0707188081824A09000D3552665E3F24162553A1E1EEC66E31162B4A8FCBE4D5A44E1B194399D3E0D6B36B1D032369A1B1A97C3F12000C3E8BBECBBCB4B5954505000012569CCFC7B9C495481B06144298DDF9CFB9D2DABB57163481BBCCB7732D236EA8ADA0858D5B20041F5C9BBBD6C29F6A2D0000023077B4A584654124110000000100140D181E1A22202B2B1F34322E46414448535358584F484A4E5A58544A4D3A80A6F2FFFFFFFFD19564402A467DB8F2FFECDB98592C151F5AA0CBD7D8AC551A0705153480C3C99E7236495E85BEEBFAF4CC9D7A7693B5EDDEDBBFA28E9C9EA5FFECDB98592C151F01FE795B070718906265360400002852684E3E1E152455A4D8E7C56D33141B4F89BAE3D79E521C1C4995CBD8D4B27124021B619AA9AC79431300104382BBC4BBB7BE8F3F0000001D59ACCACCC5BF92521D05174C96D5E7CBB7CCD1B44C283982C6D1BB68303171ABAE95897B5B15002567A0BCCBC9A16F37000008316DB3B37F5E40180500000000040C120D0F1A291F28372C263429364045494A4D55565B5551474D504C454D3888C0F4FFFFFFFFCC8C5F4A41587BBBECFFF6D4935929092267A9D2DDD7AC521A0E031A3789BBCA9F703A4A5D8CBAECF4EFC398747696B3CADFD0ACA293989DA9FFF6D4935929092201FE7A5B070718A07672380700022657696443251328519FD5E6C375320E174F97C8E9D4A0451C1E489ACBD8D7BE691707256DA9B6A074340C00104087C5C1B9B1B1894E0600001F5DAFCACCC4C997491104134D9DDBF1CEBDCED5AD561D3580C4D2BF76302F6BB0B19F868F4F13012A579CC9D0BCA1651A000000287EBCA48D6B4322050000000000100F0D12111E24282D2D332D3A49424B3E474F4B4E4D52545656524C49524186ADEBFFFFFFFFCB91683F42577BC7F6FFF7E4996522111E5AA6D3E3D6A5521F0E01193577C8D29B562F4D6585B7EAF4E3C08D70759AB9D2DDD5BBA2928C7495FFF7E4996522111E01FE7B5B070718B07D72430E00163A537361461C0F2562B7E5EBBD66311529548AC2E5D3A6451E2A5BA3D3D7C4A464170C2275A4BEA57B3F150A07478FB7B4A5AEB787360200012760B1D7D0C3BE904C190D17419EDDE6BCB7D0D8AD4B1B418FBFCFB8692E3479B0AAA188854D08032468A2C3D3C59C68240000003282AAB68B65441F0D00000000040D14141223231F2A342D3432343949403F4241495C574C4B5354584D4B432F749AD4FFFFFFFFB9864D37444D72C0F6FFF6CF8D4A270E1F5CA4D1FFDCA14C0E0503143576BEC29B5D304A5C7FC4EAFFE6C897747181AACEE0CFBF9C8F96A5AAFFF6CF8D4A270E1F01FE7C5B070718C08B86451602203C596D654A1D162B60BAE6E9BE722B12295594C4EBD18F3F0D2459A1CDD7CAAE5F20082A6FA8B19D783C191019438FC0B5BABEB689410600002867A7CECED1C38A441A0E174C9CD9EABCA9BFCAA647224181C2CEB377342F77B3BAB09286480B011A68B1C4D0CDA4692E0000043D7CC1AE896E4A2D1100000001000B191018111C1A2725222A30333F3A48414349585C4F594F5152524E4C4C387EA8ECFFFFFFFFC9815834355483CCFFFFEECF974F1F121758A7D4E2DEAA531607090A347EC0CA996835505D86BFECF8EEBE96707998ADDAEACDB69F93979DB0FFEECF974F1F121701FE7D5B070718D0725F2F0A00002D4A55573B14092D66B1DFE4BF6A2B19245298C1E3D7964813245DA9D0D1CCAE5B0F001E6EB3B1A0793E1205134C93AEB9B7B6B6822F0200012566ACD8D2D3D1963E18051B5A9EDCE8C8B4BECC9A40254984B6CFB667282876B2A99E8683410B06276BA2C0CBC5A2702C0000113F8FC0B98D7553280A00000000080A0D1311151E2226282B352C363A3B4D45464D5157554A4B4E5056534C4C3D7B9DECFFFFFFFFD193543F445A7CCDF4FFF0CD7C4C27161F6DADD7EBE9AA4E1A0C061A4486BDC79D6C2948598EC1E7EDE4BE8D6C7493AED4DFD5BDA291989AA9FFF0CD7C4C27161F01FE7E5B070718E07E7C400F0011395F6C5838190A306DBDEDEAB666270C27589AC8E3D98C3E0F1F4CA7DCD8DAA7551C112875AEBBA7743F10071C5198A9AEACADAB85421000022F71B4C7C7D2CB943F140C1F539BDAD5B4A2BFD2B44C1F3D8BC5C9AD64333877B1B49990814511022C63A1BDCEC1A7702B0000033D8EB5AB927D50270900000000080A070A1616161E1F2A32322E2E3B41484D4B484E58564D554F4B514F4449337A9EDCFFFFFFFFCB80554748608DD4FFFFF2C1894422122670A2D3EADBA74814050B164993C9B890552D576983B6EFF7E1C39870869CB4D0DBD7B4978C999FA8FFF2C1894422122601FE7F5B070718F0837547110013365163643A22173172C2EBECC26E2618225CA7CEE2DB9345272B59ADD1DCCCA94F0F082474B7B59D79430C041557A2B9A4B0B4B38539000006346EBAD1CDC9BF7D2D0A001D61A9D2DCB9A3C8CFA449194789BCCFAA5726377FABB1AB937F410E023B73A8C2C8C6A26C25000003418EBFBA9D76471E0A00000000020B090F1E201C2732352B333234394342455157565657554E4B454B433F3E2D7494DEFFFFFFFCBB7852494E5991D9FBFFE8C38344181C1F69A8DAEDD29F4F08090F193E89C6BB935A2A4A5E8AC9EDF2DFB88568789FB9D1DAD1B39E93999AA4FFE8C38344181C1F01FE805B070718007A662C0D00063F56615C3519132A6ED0E5EFAE5925142E68A1D7DFCF80380E285CB8DCEFCBA05213062F81B8B1967338160C2566ABBAA9ACB5AE7D31000007327ABCD0CCC9C88A2F06002763ACE9DEAEA7C4CE9643284A8FC0D5A857203175A6B7A49A7E3B04012B71ACB6D4BFA4712A0000023F88BFB8977F4D1D040000000009080A0D1816191A27332D3231353D414D494A51474C4E4A4A4E4D4F444F4B3A7B9AEAFFFFFFF7B27963534B6393E2FFFFE6BA7B3B20182E73B1D9EBDA9E5111090B244B93C8B88A5B30465C89C1EAF0DAB2886B819BB5CFE0CCB09590999DA5FFE6BA7B3B20182E01FE815B070718106F6336100619415A615E4C2B193874C6EEE6A958200B2C75ABDBEDCE81380D2862B7DDE3D3993E0605357EB2B398793B11072D6BADB1A3A4A7A17123000008438DBBDEDFD8C1823308033173B8DED2AB9CC1CD923C194B90B8C5A44D214881AEBAB89F7B1F00023870AAB1C2BFA16D200000084498CDB1A28347240500000000080A0D0E140F181A272F282B2C30373F49504B4D525557574A42444D484348337B9ADAFFFFFFF7B07D61545A6AA0EAFFFFECC4792F26082E7CBCE2EACB854C1A1517265091CFB8844A2542658CC4EAF9EABD866E759CAEC6D2C8A78B8F9196A2FFECC4792F26082E01FE825B070718207B6B2B1D132547585A644B281F3581D3F0F3AD5020173C75ADD3DFC7773A152171BDD7E0D1913A06032D82B9BBA56E2F0A0E2968AEAD9FADB4A66D1F0000134A9AC1CAD0CDC0782305072A72C5E0D9B1A1C2C189341F5A93B8C39140294B7EAFB5AD9E7828000A4387BDB7BABAA2702C000012599CBCBCA88849190000000000000712100C0E12101E2D28312A2B3B41413E4A494A54534B5449564E4A4D4B38748ACBFFFFFFE8A779615F6581B8F0FFFFDFAF6C362928436FB8DEE3D08B3B190D0C27589FBEAE733822425C9EDBF2F7E0B17E686C8DB2D7E0CA9A878F899DA4FFDFAF6C3629284301FE835B0707183076692B1114264B55675F49352F508EDEFCF49B4316214485BCD8E9BE6F1D132E7CBDD1E3C68030020A3F8CB4AD9C652A100E3B7EAFB09EBABB9F551C0000175098C9DEE6DBBB742C06103A8ABEDDD6A89BC3BC78241F59A5BFBF9642223E86B9B7B2AB6F1900094680B5CABCB2A66D2400001E65A3B4BAA68B5313000000000006040B091212161D1E2E2D292A3946413E3D3E484B535854534E4C5548484336748FD4FFFFFFE0AA7E666A6787BBEDFEFDDBAF68323523307EBFE2EBC883350902152E6BB0C1A46E41253C5495CEF5F0DFA9796C7793B0D9DABA9485838C8E9AFDDBAF683235233001FE845B070718408362331E233F5C7684816237305EA6EDFCEAA1401A184B8FC0D6E5B6622C0D3D7ABDD6DAB8772600134D95B9B19566240C194B83AAAAA0B4B78F450A0000155EB1D2D3D5D8B76B250812468ED1DFD9BBAECAB27424256CA3C9B7813C24498BAAB1BEA36519000C4690C6AEAEAEA36D2500001E6CA7BDB4AC85521400000000000C0A0D121B0A1A161E212B2E28363F3748434244484F4D46534C4F4F464A4735869BD5FFFFFFD7A484706B7198CFF6FFF6CFA163332E2A488AC6DEE1BE752A0005092C69ADBE925B341B2D5CA4E4F9F0DAB17D6E6882B2D0DCC48B75808697ACF6CFA163332E2A4801FE855B070718507D5A2E14294E6A708782673F345FB4ECFCE991370C1E5292BFD6E1AE5E29193A8AC7DADCB36720081C59A0C6B4A467280613489FBEB1B0BCBA87430200002466B2D7D6CECDB35F1F0E1E4598CCDCDDC5B4C6A1531E2771A2BFB676282B5692ABB1A998600A0013599DB2B4A7AE9F6E1E00002E77A1BAC8B07F3E140000000000020C0F0906171D1922302E2C30343C3D3C423F4845484C4B484A3C474F49443F7C95D5FFFFFACEA787776F82B4E8FDFFECC99D533C34274491CDE2DAB9772B0A00143474ADBD90543128345CA4D9EDEAD0AA7F736F90BCD2D1B98D77817E889BECC99D533C34274401FE865B070718606D531E1A274B687C9C9661292C52AEEDF2DC842C0E245BA0BED5D5A14A1C154083B9D0CEAC571E002762A2BDB9A66119061D579FC1B0B5C6B47E3C120608346FB6C5CDCECCA4460B03124EA0CCDFD6C3B5BE93490D2B6CAEC0B580312B5695AFA8B99F5401001A5F97B3ACADBBB7701A00033B82A9B4C2B58842070000000003051010030D1216131D241F252622364442454944474E4C4A524E49454A4B4E397793D3FFFFF8BF9568737083B1E5FFFFE7C38D6448404558A0CADFCFA9762100000B4481AFB385492C1C376CAFE3F0E4C3936A5F6672A9CBD9BC95787C888DA0E7C38D644840455801FE875B070718706948241E2B516889A2A0653D3765BCF4F8D6842D1A285E9BCACBC3843D130F4189CDD9D6A1561B122C6CA4BDB99F6D2B0D1F5BA4BDBBB8B7AA69250000002B68B6D0D7D1B995430F091F64ACD0E0D9D0C2B97A34103A86B0C2AB72372F60A3B9B3AA8D4100002966A0BAAFB8ABA5651F00013F84ADC3C3B37D380900000000080D0D11081315191F1E21262B242E3B403D42424145504C454B4C4B4E464A4C3375A0DBFFFFEBBDA28E7F7383B1E3F7FFDDC2975D4A47526F97CED7CF9E5C1B0000134788AAA66A3A25234972B3E5EFE1B699756F6E87B8D7D4B2806E707E87A4DDC2975D4A47526F01FE885B0707188078593229375B768CB3AE6E3D306EBCF0F5D5772C142768B2CDD6B77A351110459CC8DACC97420B0D306DA2B6B88D6124112764B0C4BBBFCCA067280000003676BCD7DAD0B88F3A08042163AFD8E1D0C9C6B3742C0B3485B7C0A96E2C3165A2ACA6A6843A01023067A4BCB0AEB3A76B2000044890B2C3C1B580320000000000080E09151516170E0D1D283127282E363A44393C3E434C484A49494F4E554F403987A2E0FFFFE5B7A19A83758EC5EEFFF3E5B995655D5C4C6B83C5D8CE95572400000B438AB5AD6F3B22184771B4DCE9E0C3916D636E94BACCCCAD7B7278838394E5B995655D5C4C6B01FE895B070718906C502425355F8399CAB663333369BCF5FECF7B28163069AED0C5AB712609144C98C7CFC78D3808154181AEBCC1965A1F173473B9CFBCBFC6A866180000002B79BEC7CECFBD8E360907266AAFCDDCE0D7C8AA631D0A4792BBBFAB692A346A9AA9ACA9863B0300327EB1BBACACB3A15F0B000C4E99AECAC4C4813300000000000D0E0E0B100B0B1913152E2C29282A394045363B3F43494F4A4A4F5B5449413A2F76ADF4FFFFDCB68F87807084BDEFFFFFE4B1956656655B77ABD6D8C0905F1600001F518DB6A1643120214178B6E3E6D7AB836E6F7693BACDC7A981746E76819AE4B1956656655B7701FE8A5B070718A075472521345C87A6C4AF6534346DCAEEF8D0691E112067B1C1B79E58251018579BCCC9C28B3B0A0A3A87B1C5C3A359201B3884C3CDC6C0C297591A0000003B82B6CED7C3AC86320A132871A7CDD5D4D0C89A5422144395B9B59B5D2E3067ABB3B2A485320000387FB4BEB7B9B2A05C18000D5394AFBAC2B9843500000000000A1415190F070B0F181A24252D282A30323A393D48465051504E444C524249433C82AFE8FFFFDAAA968073728BC6EEFFFFDEAE8C645661627FB8CCCABD8A4A090000014689B19D5B31211F3B78B9DCE3D9B48C6E727393B5CFC9A770636A7C7E90DEAE8C645661627F01FE8B5B070718B073471B21336487ADC3A85D30366FBAEDEFCC6A24153977B5C2BB9C59210B185F94C8D8BD7A2A17164389ABAFBD934A19133D89C4CBBFD3D2A559110000003785C0D1C9CFA9782B01072D77B3D7E0D2CCC79A4B0F114997B3B19C5E313673A9BBB3AD762D00003A81B6BDAEB3B4A85A1D00195B96BCC2CAB37A2A000000000614121616130E0D111815221B252725323D3F3B3D41444B4D4D4A524C4B4746463875A9E9FFFFC7AB97836E7C92C7F0FFF2D2A7896E64636078AAD1D2BA89410C00000F4B8FB29D622A191A457AC4EAF3D1A8845C6A7B9AB8D5CA9D716D70747D98D2A7896E6463607801FE8C5B070718C075522927437095C5D6AD6734347ABBF1FACA6D22183478C8C4B5924E1D112064A4CFD4B47329061553809CA9B194542424428FC5D0CBCAC89D5010000005378CBDC3D5C5B27326000B2F70AAC2CDD8DECA944A140A55A3BCB29853323674AAB6B3A8812E00004089B8CFAEB1BCAC5A13001E5A94AFBCC3A3712C000000000911181B11151415091318282F2D212B383B473D453F4E4D4945434C4744453F3D387AB8F3FFFDCCA39F947B749DCCF4FFF5DCAE8B6960686E8AB1D0D1BA8D4D1A00000D5792AA995A2B21204A82BDD9D7C0AB826E6C789BBFDDCAA278686880808DDCAE8B6960686E8A01FE8D5B070718D0744A1B2332619EC3DDA962393270BEECEDBC551810347BBBC2AB8148220920629FCACBAD742C1419518DA2B6C0904B231E4693CBCFC4CCBDA5550A0000093E90BED5C7C4A879230002357DB8D5DBDBC9C28E3A0E105CA6BAAB9C5E303B74A2C1B3AB7C26000A4F8DB4CAAFB4B39A4A0A00225EA2B6BFC6B07F2F000000000B191B201E100E0814160D20222C2429313C373A3C4144464C4B4A52524A4A473E2679ACE7FFFFC1A2A698757F9DD6FFFFF7D1B28F6A69786B78A7C8CEB88D3F0400000D5A96B98F4E322E253D8DCAE5D3C2A97F71727896B6D6BD98756C72777E8FD1B28F6A69786B7801FE8E5B070718E072462422366D94BCD6A253263079C9E9E6B857201B3888C1C5A186441F0F23629EC5DCB56F27131B5394A5B2B98A4F1A175096BBC8CBCCC7924A0900000B4888BECDCDC8B2782A0506327EB4D1DADCD2C2883D0D115AA7C2BA92431A397AA5B9AAA56D1900114B8CBFC2B3B9B4AD530B002361A7BCC9C9B47323000000000518201B110F0E0F11111E22202A2C33352F3636424242444D4F414B4D4A4642403088BFFBFFFFD2A2A39B6D7496D4FAFFECD4A78772686D6B8AC3D7CCB383390E0000205697A6924E2418265092CEDAD1C3A37D667D808FB7D2C59A7E6A62717A94D4A78772686D6B8A01FE8F5B070718F075481A17346496C5D69F562C3C76BFEAE7BA641F153F7EBEC39A864B170A2158A4C4D3AA672B0E1C569CB3C6B58C492926579FC6D1CAC0C29F5A0C0000054B8CBAC8C4B8A977240009317ABBCDD9DFCEBF863516195BA4B0AC84472B447CB0BAB6A66C26000E579BC0CBB0ADA59D480F031F69A7B8BBC6AC6D1C00000000061620201718110B0E0816201C272425313C403A3C39454B4D4A47494B4C49524C2C88BBF2FFF7C79C98917D739EDCFEFFF3D4A678666673758EB4BED3C17D3D04000012589CB796522B1D24478BC9E1D8BC9E82646C7BA0B9D2C99F6D6970707C9CD4A678666673758E01FE905B070718007D4B120F325C95BCD6A24F28437DBAE0DCBA6021174289B5B8A9753E0D062863A3C2CBB2722400225E9DB7B1B38840181E539BC6D8D6CFCA975606000000488EC5CEC1C0AA7B280009357ABEDDD6D0CEB4822D060C59A1BBB58D4E2F4274A0B4B39F682B09155891C1C6B7BABEAB541400276CA5BAC5C8B2671800000000080E141512110B141211222C2729242E2C393342443B3D4950454D4440454C48432E74A6E4FFFAC1A29B94747CA0DCFFFFEDCCA1806F6C77748BB9D7C3B47F300000000B5595B68B462B221F4A8AC0D6D5BA956D6D737B91C6D8C79A7A776C747A96CCA1806F6C77748B01FE915B07071810743B0F1D39599DBED79F472B3B7BBDE5E3AF551617498BBBB6A6763507002568A7D0D1A95F190827609CAAAFB78E3A14215C9EC5CFD1D1BF984A0600000A4A8AAAC2C9B3AE6E29000E3A81BED4D1CACDB5792A071662ABC4B191543A4B799CB6ABA2661E001553A0C7CFB5B7B3A14908072369A4B5CAC5B16D2000000000081D1D1D1D12120907151E28241E1622373C4335343F424B4F4B4543434946433E357DB9F7FFF1B89D9C8775769EE1FCFFEECCA5816B5F767190BECEC6AE803A01000012499AAB8741202826528BD1DDC4BB93747178809AC1D1BF9F7B6C71767C8FCCA5816B5F76719001FE925B07071820823D15182D6291BDCF944C2B397DBDE0DEB6571F1A498DBFBD9E6C3711032E6BA5C7CBAA5B1D0D34669EAFAEB7854614225DA4C5D3D9D9CB96480A0000005497B6C0BFB8AB6F1B000C3D89BECBD0D5CAB37A2403186AB0C6B68B5636417AA9B2A798681E04165DA0C6CAB7B7B1944108042C76A9BBC4CBB27320000000000E15151618180F0E0A03152323232825363436384145443F49464E4946534345422E83C9FFFFFEC2A1A4958273A0DDFDFFEAC5A6826E6C797C95BCCBBDA67D2E08000019679EAE83382722235294D5E6CFB8907771797795BBCCC3A07B7E77767C91C5A6826E6C797C9501FE935B07071830783B14213A6999BDD5984A193675C5E6DEB25521204492C3C19A6B2D08102D6EAFCFCEA151140E2A6B9DBBB7B5864515245DA0C3D2D6D5BF9C46030000024595BDC2B7B6A96E24000D3787B8CCC6CDC9B86E200C2471B5C2A88A5D373F7AA8B1A89B5E180224679CBFC7BFB9C0A3450E0D2E6AA7B7CDC2AE640F00000000031E212025130C080E132026202C29232E3734343E3B4047444040444B4A4C3C413491C8FDFFF6C5A4988A7680A7E4FFFFF4CE9C816C717D7B9CBACED1AF7A3500000010609EAC8A472318255595C7D6C0AF9777607183B2C3D6B99C7F746469778DCE9C816C717D7B9C01FE945B070718407645181D32639EC2D28C44283E7CC6E9DEB554191A579ABAB999663D100B3377ABC5C9A3511A0F2B69A2BEB1B48535092463ABC9CBC7CDC09B460900000B4A8BB3C8B7BCA66A2205104186BDD5CECCC9B06920081D6EADBDA78458384779AEB7A69A6D1A001E639FC9C0BDBCB79A450E0A337CABB5BBBCAE662100000013161C1E1C150716100F17191921202A29313B3A33303D404F504144494A464B483A288DCCFFFFEFBA9997907A7CA6D5FFFFF2C89A807070798199B5CACCB26F3100000018649FAD7F4422231A479FD8D3C8B19B827B7D7F96CDD6CA9479646B707397C89A80707079819901FE955B0707185074310506306493C1CD893D253A70B5D9E3AA4E1819509EC2B5915C2E04052772AECDCAA35816102A719FB1ACB084390E2664ABBFC6CDC8BC9F42000000105196C4C6C3B3A4671C00163C89BED0CFC8C4B86B1F0F2271A5BCA686523952819FB1ABA15A1E042B6F9FCDD0C0B7B1934A0F02336BA7BDBCBEB562100000001119161C1B1B1B170E070B1D1E1D25222F31394336363F3A4547444B504148414038368ACFFEFFECBE9B95947A7CACE8FFFFEEC6AC7A6F7F788BA2BFCEC4A779380600001E5B98A67F3E171E216B9ED6D8C0AC8E776F7889A5CBD5C09575635D657192C6AC7A6F7F788BA201FE965B070718606C3E0F182D669ABBC37D3D20317AB8DAD4AD541F205194C5B38D61330A0F2869A6C8CB9A4D0B0D306E9AAAB7AF7831172965B0C6C8C5C5BF984000000013529AC0BFB9B6AC701D00134288C4D2D3CFC1A76923091F79B5C4A4804E3A4977A5AEB1A25712002367AAC2CFC3C0BC9F3D0A083D79A9C1C4BFAD6A16000000061815231D19180A0905071D2520241D20313640343D3E444B404A495149464A3F45349CC9FFFFFBC5A19A937973ACEEFFFFF1D1A083696B84829EC3C9C6B080380400001D6CA5A479451C1F24599FD5CEC5AF8F6D647F7C9CC4D6CAA67E6257626B8ED1A083696B84829E01FE975B0707187079380C09336490B8CB8541203576BDDDE2AD471D1E5292B7AF8D6126171A2A74B3CFC599470C072A72A8B1B9B17F2D172B62A4C7D0C9CBC197430000000C558DC2C5BAB1A2671E0512408AC7D3D5CCCB9B551B0A2477B3BAA68A4F354A73A8AAA6985219002B71B1C6CCC0C9BAA04B0B0B4585B7BBC3BEB26B1200000008191919211F0D0A00101218211A211E2032323E3A3C3E3F484B473E484C4D48433E3484BBFAFFE5AF8F998A7272A9DFFFFFE6C9A27E666D8284A0BBCBBEA4682A000000185DA1A1713F1F1A235BA4CBD4BFA38D7E7B8180A9BFD2C69B6F685E6A6E99C9A27E666D8284A001FE985B070718807C3605123B6B96B8BF894529377CB3D1DBB045181D4B94BCAA855220030A3476ABC7D0964817133074ABBDBAB382361C2F74BDC5C7CFC6B08641040000174F92B6B7B3B0A26D1D071D4789BED4D1CCD1A65F1F081F73B1C2AF85513F4C70AAAFAAA35615072C6B9CC0CDBCC8BC9D460E0E4C80ACB6BFC1A765150000000B272A2B20240A0708090B1219111C202E2C33363A4041444648474B4D444A403C393694D3FFFFF9C29C9A9A767EB0E3FFFFF2CDA787746E8292B2D1CEC7A2732F0000041E75A5A3723011201F60A5D4D4BB90927570728A96C3D6BDA0776B6A657897CDA787746E8292B201FE995B07071890733D0D072C608FB4C07C37183C81BAD7DA9A500F1556A6D1B67B4D22050F3777BACECF964F1A1B3F7BAAAAA8A76E30112769B1BFCBCECACB984201000014549EBEBEB5B0A5631400163F8ABAD2D4D3C5A25B14082A80B4B9A9725C434D74A4BAA8984D1406256CA6CFD1CCC2BC943405104E80ACB3C2CAAE5C0F0000000D2123201D191215090A06191E211F1B262F322E3C373C40404A4B48504D444343443584CAFFFFE3B79389787583B6F2FFFFE9CFA17D646F8483A7C3D3C8A1742A0000002568A7A47F381321215FA0D5D3BCA08E706A7C83B1CAD7C697786B5E6F7B8ECFA17D646F8483A701FE9A5B070718A0673B040D205386AEB979391D3877B0DACEA7451A225AA2BFAF7F4E1A0611387CABCBC7974816083179B2B0B7A46D32113575B4CAD9D2C5BB8A36000000164D9EC2BDB1ACA1641C00184996C1D3CCBBB6A352170E2B74B3B9A07D4C465B7C9EA9A3944A12002D6FBACCCEB7C2B88D36080D5791B4C0BFBE9F55090000001827251C231B0E0B0002051122211D131C2832393E4240463F494A4551504E4E47453A87D0FFFFE6AE858C7D737AB2E9F8FFE9C9A0836C71858CA7C2C2C4A16A1E000000246CABA374371B1F1D5CA2CCDEBBA47E687A8785A7C5D0C19A79746166788FC9A0836C71858CA701FE9B5B070718B06F3300032A5E84A6AA6E2E18327AB7D9D89D46111D57ACC3AF784E1E0A15427FB0CCC5893D07093575AFB9B0A6692A1E3176ADC8CBC8C0BD8A310000001D61A1BDB6B4B3AA6211001A509FCBD7C8C8C49C5512102D81C3B7A47458494F779FAEB490460D0E3479B2D2CCC1BDB58B350B174F90ABB7BDB8A7620D0000000C2A231C22120F0B0C0707151C1D281E293733323F47423B444044484B4849403F373191D4FFFFEFB49992886D86AFEDFFFFDEC19473656E8188AACECFABA16D200000012E77A3A26636161D1C6EB7D0D0B69E867B7C8B8FAFCAD3BA89766964617793C19473656E8188AA01FE9C5B070718C06727000023588FB4AD6C2C1E367FC2DCD599430C1861A5C0AB7D471603094086B6CFBF893B0A10367FAAB3BCA969341C306FB3CCCED1C8B9833100000019589BBABFB2B5AB611700115294C5D8D0C0BC8F470E032B83C3C9A373504B4A76A3AEA99E410D033A7DADBCCBC2BBC081380E0C5796BABEC0C4AC5B0B0000001C292D36261612070000081620191F1C2332333D3B373B3D454744504945494442443384CAF9FFDFB37B837E7C90C7E8FDFFECC398806A76888CAECCCDBEA167190000042E769EA56E2D19241966B0D7CFB69E776C7D8088A8C9DCBC906E685D5F7299C398806A76888CAE01FE9D5B070718D06F340200265E89B2AC6F2813387EBCD3CEA840142A5FA3C0AB784515040C3C85B8C5C5853C110C3D84B0BBC0AB6C2D213675ADCDCACBC5BC85340000001963A2BBB0ABBDA5621C00194D99CFD1CDC4B78B4712043C83B7BAA17A574955729AA9AF883D0C083980B0CCD0D1C8B6882C001C609CB8C0C5C2A2580E0000001A282F2F29120D090003071A2021181D222A35333230423946454841474C4C4A43432E8ECBFFFFE5AD837A846D84C1EAFDFCE2B793847880828EABC6D1AD9F7625000005246BA79E6A2A0C1B255CB3CFC5AD917E706B8797B2CFD5BD9985706C607C9BB793847880828EAB01FE9E5B070718E0742A000218598AB0AE5C281F3780BBE0D0A139112169B1BFB278380E000E3A85B8C9C7823A0F163E83C4C6C4A86823153471B6C7CDCABFBA792B000001225E97BCB3B2B59E5B170120508BC2DACFCABA894B0F0F3286C2B89C7559515375A5ADA284430B093A76BACFCDBFCCB77B2E0F2A679BAEBEBDC3A7530B000001252F2E2F2015150500000A101C1D19242B2A29262D343D3E3F43404346463E44423E3795D3FFFFEDA7838A877788C1F9FFFFE3B6927F737C8998A9C6D3B8995F1F0000003382AAA1642D11242162ACD2BEAA7C74706D808CB2C9D5BC927D6C67687D9DB6927F737C8998A901FE9F5B070718F06E270000115083AEAC5F23102A71B7CFC38F3816256BABBDA0662E070016438FBFCAB67F2C0209387EBDBCBAAA5F251E3F7BB2CDD3C9C4B67F2A0000001D63A6BDAAAEB9A3540D002A599DC8D4D3BCB3914911153C86BCBC90675053617A9BACAD904710093E86BED1DAC4BEBA7F2F07306E9CBAC3BBC0A04B00000000233533322619090700050C131D1E161527332E34373538444A4842444E473D3F3E3F2B97DAFFFFE3A485807D7B96C3F2FFFDE3BF927469718BACB5C9CCBEA05F1B0000002A6BA696672B1424196AAFD3C2AC8D746E737D89B4CBCEBE98836B5A6482A8BF927469718BACB501FEA05B07071800722D00001F5486A79F5422153A78B5CECB9438122A70B4CD9E6A4015050D3C8FB8BEB57B380C0B4187BFC3C0AA6426133D81B8CEC4C0BBB07E260000001D5E9AB6AEAEB39B5C11032B639EC0D7D6CABB853613133691B4C0976C564C57739AAAAC8B3C0C10428DB3CDD1C8C5A7812C0B2A70A8B9B4C4C1A1540D00000B2A3B3425262012070000131720201B1A2D2C332D32333F413D403C3C394442473E41309AE0FFFFDD9F73707C7189C1F4FFFDE2BD9B8A7D88939FAED5C8B597641E0000023582B29D621000192C77C0DEBEA7927A6C6F7A88B9D3DEC296806D5D667BA6BD9B8A7D88939FAE01FEA15B07071810722400001E648CA8A55F2318377EB3C8C8943A172879B8C4A273350D001B548CC0C7B176350D113B90BCC1BA9F55221A3677B0CBBFBCB7AE78220000002D64A0B5A8B0A98F521C0024699EC9D0CDCFAF7B3D0B083D90B8B4A37B68545A6F9EB5AE873709104887BBC3C8C6C0B979230E2B739CB6BFB5B8A65D080000082D3D3436251C110601020508171D201D1F292F2A2C2F3A3E3A454B48393E454C3F483C9FF1FFFFE0A0888E8C4E88C7FEFFFFE4C49C887A7E91A5C2CEC5B79A601F0000093E83ACA45C261327206AA6CDB89E8F7A6D728186AED2D7BB99816F5D60749AC49C887A7E91A5C201FEA25B0707182077340502245C8AAEA56129203B86BFD5CE8E3F152F73BCCBA969330A09225696B9C5BB6C2D111E468CB2BAC1A35923194089BFCAC1C2B1AB6D240000003069ABC0ABA9B196541D0A2B5E9AC3D3D4CBA97333090F478DC5B99570656059709BAEB17D2E10154A89B0CCCFD0BFB3781C032E77A7C3C6C2BB9B510100001139433B33251D0F040001000117191B18192A282B2B3B3839404341424D4741434247309BE0FFFFE299727C80808BC3F3FFF9DEB7977E75808E9EB6CBC3B48C5C180000093F84AB904F19091A2079BDD2BC9F85767475828EAFC3C6B2957D6D5763789DB7977E75808E9EB601FEA35B07071830792400001A518AA1944C18103E76B2C5C18A3C1A2F7BB5C8A4643518071D4C94BDC5AF6E2703103E85B7C4C0A45626244D89B2BBBDC1B2A266200000002F6EA2C1B6A5AB9D4F1508295A9BC0D4D0C8AD79390E1E478EBCB7996A6364576E9DBDAB792C0B104F86BECFDBD2C6BA70210E317CABBEB9C1AE9247000000083F5845351E1203000000080616191C202332362F2E33353647413D3D4239484C3E3D2D9EEAFFFFDD9879737C7090BDFBFFFDDDB5937E858C919AB2D0C8B3875A1800000E3E84AE964F231219226EB4D1C29A81786572798BB7CCD8C695727464617CA7B5937E858C919AB201FEA45B070718406D1C0000215D8DA399461A1C307BB2C2BF7E2A0F3379BBC8A66A2A0800154D99C0D0AC652D000F3B8EC3C5BF9D52131C487FB8BDC9BDB5A868200000013071A8BEB0AFBC9B4C0C002E6FA1CBD7D6CBB976321020498EC0C7926C5D5F5B789BB1A2732606164F86BDCAC8BDC3AF6620033B7FB6BFBCBFBB9A4100000013505E483C2A1A130100000A0C15191C181521272C383A363A433E4340403E44423F45319EDEFFFFCE99796573778BC8F9FFFADBBC948383929CA3BCCBCAAB8C57150001104A89A39B47121F271D6CB4CDB18B76736A798891C2CFDBC2A183735B55789FBC948383929CA3BC01FEA55B07071850872C00011E518CAA99491F1A387DB4C8C38536132E81C8D1B2692801001E59A3C6D7B86A2B091A4591BECCC99B45181C4988B0BBC4BEADAE66240000033A79AFC0B3A8A583460B002B72A3CBD3CABDA47531111C529BC2B0986F66695A6D9FAEAE762603165593C8D5D6CDC8B06C22103D7FA6BBBBBBB6A24A000000184E644E402A220C04000000111015141C1D28262C2B3136333C3B3B43453B3C3C393F2FA8E6FFFFEBA16B6C828196CBF5FFFEE0B3877A7C8B9CAEBFC8C19D8B551000001D4D87B1954D1D1C21227AB6CEB59B84766E69788DB2D0DCB896786247598AB0B3877A7C8B9CAEBF01FEA65B0707186071280000155B8DA8994C1E153374B4C8BB8029123588CACCB164280700276498BCC8AA5F1D03043D91C6C4C19C511A225795AFBDC2B6A9A6691E00000B337DABBCA7ABB8953A09102C6899C7D4CEC5A06C310F1F4C9AB9B5967677715C7295A6A56E250615539BBED1D6C7BCA5612710418CAAC7CDB8BA8F440100002A5E64503A2D1C13000000001317140F1216261E293132363C38414040403A3F403F402FA8E9FFFFD9977B74776A9DE3F8FFFBD7A68074748E90A1BCCCCBA888481A000018478CA294531E05212A72B9CDAC887C796E6C8F9AA5CDD1B4927F6D60677EA2A68074748E90A1BC01FEA75B070718707B220000245684AEA7521B183D75B2C5C0812F17378AC9CEA15F250400205E9FC3C99A5820010F5590C3CDCA903F13235690BCC2B9B4B2A35706000004397EA9BAB5B9B68B400C0D3976ABD1D4E0CAA5692207255890B3B38F6D6B66586D90B1A6682309205E9AC9CECCC2CAA55A1C10428FB4BBBCBAB69E470000002C69745340311E0B000000020F1112141A242223202D31393A3D4541473C3C46473D36309DE3FFFECF97696D777496D6F7FFFFDBB7868179889CA4BAC6B5A57F4613000218528BAA92531D1A232F7DBBCAB48879736974849BB8BFD2BF967B71605F7DA9B7868179889CA4BA01FEA85B070718807A290000225A8DB39544101E4080B2CAC57B2719338ECFC7A7631F0102255EB2C5CEA5561B00094B8CB8C6CE984419265F8DB8C6BDB8A6915A120000103A8DB7BAABABB08A39090B34739DCBD4D7C19E642202205892C1B68D716C685B699CBBB06D22061A57A3CED4CBD4C9A355100D4089B6BAB7B8B19B4A000000246E74553B322C160000000004121715141D2028282B2A343A3D433F3A3C3D3E3C3C3E2C9FEFFDF9CF9669736573A0D6FCFFECCCB38579788797ABBCCCC1A1744A130000195694B292511E0E2A347FB3CFAD847C7166718594B3CBCDB8827264555E7FA9B38579788797ABBC01FEA95B070718907620000027508EA88A370A1C3A78B5C7B77D310E3A94C2CEA7541400002268AEC8C2995A200514498EC4CCC99B47242E5C95B8C6C3B8AF894A0F00000E4786B0B5B3A3A6893D0C073A72A4C7D6D1BF97591F062A60A6C6B28F747476646D93B09C6115021F619ECCD7CEC6C3A95914134A8CB5BEB7B1AE98400000003570806545382103000000000409130D12151E2B31272A2F303A394043423A423F3C3E2DACE3F8EBC3815962617091D3F6F8E5CDAC876D647C94ACBDCAC0977E4E1000051B5792AE8B44160728327BBECCA880777768728298B9CCD1BB8A7572606981BAAC876D647C94ACBD01FEAA5B070718A0742400001A608DA5944B1522418AC5CFBC722E133C91C8C0A75E150100255FAFC7C398531001104FA3D0D0C3913B12265B99BFC5C0B5AA92520500000E4C84AABEB5ADB4823103123975A6D4DBD9C69D5D21072E61A2BAC09C6D6B70526695BDA05418061C5FA7C4CDD4D0C99751111A4D94B7C0BCB6AE8B3C0000003E7E865647382A0B0000000003110C1314191E2228262D3233383F39343339403E393A2EA4D7F0E4B27C594A597391CBEEFFF8C5937366718094B1C2C9B899793C0800011B5A92AC814310001F3782BBCA9C776C70716F8492B8CDD4B98B776D5A6D92B2937366718094B1C201FEAB5B070718B071200000285987B5953E13123C82B7C9B77222113E94C3D4A45B1A00002770B2BEBC9F4D1300154690C2C5C39340152A5D9EC1CCBBB4AD894B020000104690A7B0B1B3BF8B36100F4176A0C5CDD6C9A55C1C092C5E9FC2B18B817C7C556C91A18C5816072964A8C7C6D2D0C3984E1E195093B1BBC4C1B98F420000033A858B5A3F40240900000000040C08131313212827282C373F413B403F424341362E34259BCDEED2A165484D50638DC0E6E9DDC5A47468758A95A6BAC0AF99673C02000F285084A5863F19001F477FB4C5A17B686C6B7B889FC0CCCBAE89735F5D678BB9A47468758A95A6BA01FEAC5B070718C079210000245993B28E4013193B85B6C2A96B27184091CDD7AA64290400327DBBC6BB86421000144D9BCCD0BC863D1A306D9DBBB8B6ACA48B420800000F4583B0B4A9B2AC773C040B4A81ABC7C6C4BF9656220F366C9CB9B19467767A606794AD9855190E2B65A5C2DCDCC8C49E4C0E175199B2BEBAC2B68F3B020000417D825B503D280300000000000B12150C111D1A282F2F30353C3E3B4139464139313A31A0CFDCBFA56C433C535F96CAE9EBEAC5927770717D8CA2B5BDB58D603203000D2F5996A37B45150B2A578CBCB78F6F65716C707795C1CDC8AD8F7C6E546481B0927770717D8CA2B501FEAD5B070718D072280003265F909E8934101B4388C2C4B0622012358EC5CBA85B1C00032679B5CAC38D4218001F4F97BCCFC5883C1E2863A2BEBDB8AA968443070000205992B1ADABB1B5833403134B8AADCAD2D1C7965D1F0E3A70ABC5B38A78797C576994A6834D140B1F6AA7CBDAD8D7BB954E0A165AA3B5BBBEC3B894360000044C7B88644D3F301500000000000E1111080E1E28251B26373534384241423B3B35353A30A0C6D5CF9760333446769DD5F6F2D9B38B716373818CAABEBBAD8F5E3300000524548DA88149160224507CBAB9977371786D6F8495C5F7D5B080665E566383B68B716373818CAABE01FEAE5B070718E06E1E0000206487A28D3A11143682AABFA65E14043D97BECCB1631B00073679B2CAC48F450D061156A5CAC7C39032112E65A3C0B5B5AFA47F390D0000194F95B4AFB4ABBF83350515447BA9C9CBD4CB9A57200D326F9CB1A58B787C7F626796AC8E4907022974ABC7D2D8CEC6994D191553A0BABBB9B9AD892C0000044592957150442F0A000000000B0E0E0D1310191B2127282228353E35343F3D414133332598CFDBCF9A615047585F8BC2E4EFE3C59C6D656D7B92A8B1C1C2826130000009276299A2874A19002A4C7FB9C39D6B61717270849CCCD2CFA7847363566482B09C6D656D7B92A8B101FEAF5B070718F071260000295D85A28F3E10163C83B7B9A25E1E0A4594D0C6A858130007397CB7C5B693471300134C99C8CCC1883A1A3374A2C0BDBCB2957942000000205196B6B1B5B6B979310D0A3C7DAECACAD0C79F5A281845769EAEAA87767C7A616998AF8E4C060C2E70A7CDD1CCD1C595400A145599B3BBC5C7B685360000064992967257462B0700000000000D1210120914241E212F363636413D3D41403A3332382896CFD6C59965423949668ECDE8EBE1B99A6C5E6F759BB6BABCAD8F6C340000072C5E95A57D3C0E053C5189B4B9926B74716C6E8097C4D3C4AD806E61546885AE9A6C5E6F759BB6BA01FEB05B070718007E3500022B69A5B48C3E0E164688B5C2A55C1C124390C3CBAB66180005337DB9CDB9863E0D001D51A6CBCFBC813818366FA7CBC2BEB39B873B0200001E5991AAADADAFB470320210437EAAC9D3D3C5995217073F729FB8B9908385794E578DA180410A0E3268B7C9D2DBD5C58D410D1D5CA2C4B9B7B6B58F330000074A95A174594E2D1300000000000810100C1112222B241E2C312E36393B433E443E3A36259CCED4B98D533135606F93D4DDEEEBB8896665678499A7BFC4AD8E5B2902000C2A5A91A27E401706275184BBB98C685F716E758BA0BFD1CDB17C746260658ABC896665678499A7BF01FEB15B070718107B2A00022E7199A484431019458BBDB5A2591E0F4E9DCFD3AE57170000327BBFCFCB8B350B000D4F96C7CBC4862F12367BA9C7C3B1ADB3803A01000022589AAEB4AFB4B6773312125082B8C5CBCECF9753211142789DB0B18D788575546798A7823C140E2C7AAECBD5D6D4B98F40111356A6BDB6B4B8B1822F0000055296956F654E3207000000000006080E01060C1E202B2B302C283B3A3841403A3D34373099C3C4A879442929446085BEDCE3D5B8876C5B5F788F9CBEB8A37A4F2400000029589AA7743D1207316297C2BA896B6E746970809BBECCC7A47E7464606B88B2876C5B5F788F9CBE01FEB25B070718206E1B0000265888A378340F053E83AFC0A151160C4096CECEA75E1C00012678B8C7C07E370200104D9CC9CEBF84360F3478B4C1C4B7ABA77F2F07000028639EB1B0BFB6B2621D0C13588AAFC2C6CBCAA54C150D3F7293B0AD8A75857F666F9FA87B3A0708367EB8CFD3D5CEB183350F235BA0BCC1C1C0B1812B00001259A1A37B685641180000000000020811080F18202720262633313239343337353B37372799B2B6AD7F4927254C5D9AC7E1E4D4B08E6C5A5F798EA9BFBAA3804C24000011376E9D9C793B15132C5E8AB6C08C69687A7971868DBED1CAA57B6363526588B68E6C5A5F798EA9BF01FEB35B070718307026000023618BA37C380C173D7EAAB39C5317104499D7CFA95B180006347EAEC8B283340800114A9EC9D6C6842A193172A2C0BEC1B79C7832000000296E9EB5B3B8BEC174330B1C5086A8C3BCC7CB97551B184578A3B4A487758581636490957C3503053373AED1C5D2C9C586360F1E5FA6C6C0C0AEB380290000105D9D99796957371700000000000B0A0E0B0A181D1F25212933323835333B3A3E39353B2E9CC1C6AE804E28303A6490C6DEDDDAAD866759667497B3BDBDA58156230000072C559AA57D361C0F285F8ABBBC8B656E7275757FA1C5D8C8A27F6D655E688CB5866759667497B3BD01FEB45B070718406E21000024568AA27C2B06123F7CADAB90421719409FD3D2AD5B1200103989B8C7BC82300200174D9ED1D0BB772A1A3B70B2CFBEB3B3A174320000002364A1B2BAC2B3B2712B0B124E85B3D4CFCCCEA254110C39789BB5A79279897D5764869C7E3400093783BDCED0D0C7B78B3C0B1A639FBDC3C4B2B0832C000012569EA4735B592F090000000003070D0B080B1E1F191B2A3038323834393A39494739312199B6B1A47A48211C376593CDE5FBDAAA815B51637791A5B5B2A07C451200000836659BA67637180D2B6B9BB3AB7D57666E656A7FA2D0CBBCA97B5E6466778BB7815B51637791A5B501FEB55B070718506E2400002B688BA57E360013458EB5B68D55120E479BCED0AC581B0001387FB5C3BA7B2A0800104D9BD4D7C67B291F3981AEC2B1A4ACA77727000002275F9CAAB0C0BAC1722108184D93BBCBC4CAD19F571B13497B9CA5A38C8592825D688C9D69260C124186BCC3D1DDCBC27F330B226FA9BFB2B1C4B783270000105DA3A3795C553C1700000000000A0904020C0D1217162328302E343B3941403D3A413A2B9DB0B7996A3C28314A5C91BBE6DFD1AF8C6256637897B5B7B49B7D44210000062E61959A783D0E101A6594BAB4856F7285847385A4C2CBBAA07B635F5A7090B58C6256637897B5B701FEB65B0707186078250000256890A1802D070E4A87B3B88E4B0F0F489CCCCAB05D0D000B3E87BCCABA7A3700001E56A4CED1C881331D437FADC6B5B1A79370310000012361A6B0B5B8B9B87127011B538AAFC2C8C6C78F481C19457C9AAFA78A7C988267687F8F7931030F3C7EB5D9D5C7C7BD893C142163B1C3CDC0B7AE7B2900000D60A6A8786D5D34120000000000091007070511221B141C27303C3A352F3032403B2D332B94B4B796723A161C436196CAE6E5D0A17C63585F7C97ADC1C5996D4919000011326DA8AA793A2210326391BFAF79576A76766F84A7C9CDC19F7666625B6C8FBA7C63585F7C97ADC101FEB75B07071870801F00002A6699A8822F05183D87AEB791470E0C4697CAD0AA5D1200093D8AC4D0BB6E2900001A57A2C8C9C075371F4086B0C4BBB0AC9B6E290000002566A3B3BBBBBAB26C2906206092B4CDC7C9BD9A53180A4280A0B7B085828B7E65617C93752E000B388BBADBD8DBCCBF742605235F9ABDCAC6B5B47C2500000963B0B080755D380D0000000000000B0A06101A1C281E1C203137363A353637373C4246279BB8B59E78472031495A9BC2E8E6CFAD876A5D607798ABC1C1A471491B000009367BA0AA6C301A1538758FBEA87A63666C707482BBC6CCBEA17465625B6D92BF876A5D607798ABC101FEB85B0707188077280008356B9EB1792800133C88AFAC8144111248A4D7D2AE5006000D3481BBC0BA6F2F0900205AB0CECEC3842910397DAFC8BDB3AC93671D0000001F62A2B5BABCBAB0742A09185D8DADC9C9CAC3A2521D1946809AADB1917E897C546391966A25000B3E7EBED7D8D0CEBF832B0D2065A4C4C7C4BBA5791C00001860ACA67C6F65421D000000000210090A0009140D1E1D2024293534313C3A383C3834382B8BA8AD8C5F3618173A547FB5CDD5C4A77E5B4B58708EACBDB09B6B3A180000173672A4A27033180D2F749CB9B8835A627E706F85A5CCCBC29477655C62738FBB7E5B4B58708EACBD01FEB95B070718908028000031669DA37D35131F4489B4AD893F0E0B4197C8D4AF5B1E010B3F8CB8C8AC762D05001753A9CCC8C07A311C3A7BB3D4C1AFAD9D68240000002460A7B3B5B4AFA7672307205E88B7C8C1C8C49355191D4A7CA0B4A596798A88645C8BA0763000124483B5D1D7DDCCB87F300F276DA7B9B6BBC3AD792B00001667A4A78B745D3C180000000000080F0D070E1112151A2D21222A353D3C2E34383E3B2E27859CA087522B1013385E8EB3D1DCC296775A54536D93ACBDB69F6F5C1821000A336C9198653118122A688EB2AD76555E716B6F8CB1D3CDBE9D6F665B607794BE775A54536D93ACBD01FEBA5B070718A0732000002D75A0A4812A0D12427CA0A5853E060D489DCDD3B85B14000D418CC1C9B3722100001A58A5CBCBBF8A35214588B3C1BFA7A79965240000002663A9B6C2C1BBB26718061A5796B4BEC5CDBF9E571C1548849AB7AA8A8293825C638B966723000B4281B9CCD2CBCBB47A2C0A2170A7C5C7C0B5B3822700001A64A6AF85776240140000000000080B0D0009121B1C1C1D1B2736382D35353B3A3D32352C97A9A290623B1F1F3E5A8AC0D9E4D199794F58587494ACB1B490713B100000114276A49D7040241B306C9AB8AE825D6870617089A6CCCEBD916A616159739BC9794F58587494ACB101FEBB5B070718B06F1E00001C65869D6E2001143D8AA4A57A3A080E4099D1D5B0551200063E8FBFCBB3702501001664A7C8D1B67A321D408CB4C5B6AFB39858160000042D6CA1ADACB8BCB36C21001B6198B5C9C7C7B994450D10528E9FACA38883968463658D94732B060F458AC4CECDC6BEBC78280D2970A3B9C7C6C1B4781C00001C6BABB58D7864451200000000000302050200131518202A2E2F323A353232343A3335382A85A49B7C591E161B365D99C1DED9CCA1755B49597490AFBAB3966B3A120000103C6FA09C6C3B23142C7494B3AC75577175736B81A8C1D1CB9C7A5A5D5B739AC4755B49597490AFBA01FEBC5B070718C07B22000025699A9C73230A1A5492B0AA7F38110F4B9DCFD6AF5D1F00093E90C6CBB46F2600011F60A2C4C9B87C2C213F8AAEC6BFAEA89358150000013277A3AEB9B7BCB5631E071A6090B8C4D2C5C4954A1A164C899BAF9C85859B84665D839A5E2105174B83B6C8D9D0C5B17B200B316AA0BDC2B9B1B0761D00001D73AFB9937565420C000000000001000604060B1E2422262A2838383938343C3D35322C238EA19E7E5D29131E385D90BAD5DCBC987451475F7597A6B7AA916B3F190000153B7E96986B2C1F122D7897BEA47E586476746683A5C9CCB7947462625C7597C97451475F7597A6B701FEBD5B070718D0751F00002F7192977132050F3E7BA4A6803D09134AA3D6D7A25116000B448FBEC3B6722304021458A7CDD4BF6A2F1F4E8DBBC6BEAEAB94601700000B2C6594A2AFBCBDB26A1A041E639BB5C6CACDC8A956160F4E8899B1AF90849283616C93925A2104163B85BAD0DCDFCFBB7E2B0C30689EBCC6C2BCAE751800002870B0C2937B63450E0000000000070E080406130A181911282A31312C332F393939363328909A9487591D071B3D558AB8E1E0C5A07D584E566F92A7BDB894623B0400001D4378AA9B59292313387A97A9A667526D8070778AB3CFD3C397765F69667197BD7D584E566F92A7BD01FEBE5B070718E06D1000001B5C859E712100093E7EA09E73330A0D449BCDD2B05B1300093991C0BFAF651F00001555A4CACDC1782C264B8EBFC2AEA5B29B64200000062B6DA0A0B3B9BFB36218031C6791B2C9CCCBCAA24F1C164F7F97A4A58C808C7C636C90925E2400145291C9CFDEDACDBC7620042D79B3CDC6B0ADA06A1500001A71AFBCA180743B10000000000003060200090D10131721242F2F383C3B363A35423C3C268BA093774A200E0D346595B7D0D3BEA07A5546556F90AABBBA896235130000154E7C9F9A613623233A5C96C3A872535B7466697CA8C6CFBD9770656469839DC07A5546556F90AABB01FEBF5B070718F07B21000024628E9F7322030D4686A8A47B340C144BA3C8CBA64B0D000B3E90C6C6A76D2200022261A5D4CFBF7A2C1C5490B8CCBCABA79457190000063769A6ACB7B9B7AF5F1C062A639ABBCDC8C3BA934D0E1652809FB0AD87858E8A6363908A591F001C4E8ABFD4D4D1C8AF6D260D2B6BA6BCC9BDB6AC751E00002179B9BE918070410A000000000003070000031712141418242A312F35393939413A35332B8C9F96714D260F15385F96C8DCDBC3956E5444596A91ADB9AB875E310900001B42809E996A311F02308697B9A46F586A7B6E6F96B5CCD0B89C72585960799BC86E5444596A91ADB901FEC05B070718006B15000025679C946818090F4B85A3A17531090F4799D7D7B65B1500094490BEC6A8631400001D65ADCDD2C27C2E214D8AB8CFB7A6B189530F0000043C6F96ACB6BCBAA760230620649DB7CFC3C7CD964A12104E8E9FA8A79886917E696F8C85580F001C5293C4DBD4CFCFB0651D0E3280B4C6C4BCBEB46A1700002F8BB7AD8D836D3D1100000000000806020C0B001115161E2D2D2D312D353E42453A34322695978C704615020E3F6694C2D9D4C59C6E57525A7096A4B3B0946630000000144F7AAF9B7D281919388097B9A26F5663786B768EA9CABEB79A69535960759DC96E57525A7096A4B301FEC15B070718107D2B000027679D9E7819000D4686AEA5712C00014792C3D0AE5417000D398EC5C7AA5F1802061D66A5C9CCC47A291C4890BCBEB2A9AA9B631E0000002A6C9FA9BACBC2A9611D062065A0C4CBC5C0BF9D4C1A124F7C9CA8AE918896876A6C8A875A1C020C499DC1D1D1D2C7B4661D113B76B5BEC5B4BAAB701800002B7BB6BA927E683D0F000000000000000A0209151A1A192124212C2E2E32363C3E37353126899C83764E1A041241699CBED1D8BCA2785B4358799DA7B0AC8F60340500001B387BAFA2652C181E367EA1B9A2664A64716B7A90B2D1D0BB946C6452657C99C2785B4358799DA7B001FEC25B0707182072200000205C88A06A24001C498BA3A16328050A4594CCCDA95111000E439AC7C9A56C1C00001B60B2CECAB676301E5196C1CBB9A69F8E520F0000073278A4A2B5B9C299581F132E669DBDB6BDCDC6A547161E668998A6A28B83957A646582895615011B4E9CC9DDD7CBC3AF5E1F0D327BB0C3C2C3B2AA6F0C00001E83AEBF9B856A3F0E0000000000010506030C141613151D23272D3332383B3C3D393030298690876E4212070A38688BBFD3CEBE906E4F4B527491A6B3B38377270100001F48809E975E2D22163784A7B9A36F536F74706C94B7D0C9B4856B5E576881A2C96E4F4B527491A6B301FEC35B0707183074220000226493926A15000D4687A5AB6B2100093FA1CACDAB5915000B4092CAC8B0631200002862A6C3CDBD7B3122508EB7CABBACAD91550E0000013175A0A2B4C3C0B05C1D07286E9EC0C1C1C4C79C430A1B5D8F95A29E8B8C8B7E6B768D884E1700104796C7DAD4D8CBA95B2316387FA7C7C2BAB9B9701100002881BEB9958C764C0C0000000000000002030512161A1D2529253435343B2F34323F3633208B8F8A5D38101013376696C5CED2B192725747576E97ADAFA68353260400002551819F975B2E19123A86A4BFAA75596D75707194B8CDCFB693645F60677CA5C5725747576E97ADAF01FEC45B07071840762300002B709B9E6813001145889F9B642A0A13499DCCCDB45816000D4591C9C7AA61160005206DADC5CAB26B211E5596BEC8BEABAB98571000000B38729FA8AFBFC1A7571B0018609FBFBCC2CDC49E4C19175996A1AEA98F84968A5F7391894613001F559BC4DFD1DBC79F551E10397EB1C4C8C2B9AE6C1700002C80B9BF9887663B0200000000000C0504000410181C172024292C2C363731353C3A2F35287D8377613211000E376499B5C0C6B28F7050384D6D8CABB8A87C53250000001E4982A7A162291F163588AEBAA05F4C6A78687797BBCCCAB78A6056626A85AFCF7050384D6D8CABB801FEC55B07071850681E000023669096541F02183B87AA98520F000D50A3CFD4A95D18011D4D93B6C5AC671F00001963ADC7CFBD742B285692BABEAEA8AA96591300000E3F6D96A8B6C3C699571B05296AA0B8C0CACBC19B4D19185F8F98A6A8938F947E62698383490D0019599FC3DBD2D6C89F5A14103D7EB2C3C7BFC4AB610D00003087C0C2978A69450C000000000000000000040F181F1D1F242A2F3B3234353138343B30208C998F5F331000153F6196BED6D9B2A1685642496796B1B2B1834B20000000214F8EAB9D6B291616448BA7BDA05649667D757A92B3C6C5B28860535B718FAED2685642496796B1B201FEC65B070718606C1C0000266A99935F1F000F508CA193511C061953A1D0DBB3610D0012418FC0C7AA541B0004256EB6CFCEA96E2722539DBFC3B8A6AF8D4B08000009376B939DB5C6BA9A4F1B0E2B6EA4B6BEC5CAC0A34B1B23648D98A7AA8E8E888369758A703802001D5F9FC1D3D8D4C1AA581C093B83BBC6C4BFBEAD641200002688BDC39D89653F09000000000000010B070807121A171F1C2D35332D312F3B3F37333329857F6C4F2904000E356194B4D1CBBC9A6E4D444A7394A8B4A8814A1C000000204781A5A163321C1942939DB09A654D6E7B727690B9D3CBB4965C4B5B677BACD16E4D444A7394A8B401FEC75B070718706D1000001D689398541B000C418BA4945D1B000A47A1CFD0A9621D01154997C1CDA1561400002173B1C8CEC0742E255BA0BCC8AFA8AD8F50070000033C769BA8BAC4BE9D4D1B042C6CA0BFC6BFCDBD9D4413225F8998A1A78C8A9B886E70937B3303001C5197C2D5D6D1CD985B120D4084BAC3C2C4AEA35E0900003690C9BE938D6B3A0E000000000310060200030C1719152027242E3A303232373738363E2A7C7E725930070016406699B9C2CCB4856944454E7190A9BAA9854B22050000264883A893581A18143A91AEB89B6C5374846C7E94ADCFCFBC956B595A6B84AAD36944454E7190A9BA01FEC85B07071880802700002E6E928F5D1D08194F8DAC9459240013469BD2D5B2581C01114299C3C3AB5B0D00002A6FB8D4CFB3612C25599BBCC0ABA4B08F4F0D00000B477E98A1AEC5BE9D4919082978ACBEB8BEC4C59C4A1023668994A2A98F8C97896A768C74360700215B9DC4D4DAD4CB984A1412468DB4C9C4C0BBA05A0800003E86B5C598826D431100000000000100030408060D0D15262C272E3334332E333539303A2883926D421900010D396C96B7CFC9B4966A4E41526F8BA9BCAD7A421C00000022598DAC93581C17174499ACBB9E5B49707668799CBCCFC8B68F654A536D86A7D56A4E41526F8BA9BC01FEC95B07071890712A0000287290975E1400114E83A19D5317001151A0CDD7B75E1700143D92C6C5AB5C1900032063B0D0D0BD732E2B5FA8C9D6ABA3A694590800000F447499A9BFC2B8904815152E78A1B1ABB7C0BB9749111B608D8CA6A0878BA389707A907A380D001F55A3C9D1CFCCBF994D0B164C8DB2C1C9B7BEAE5C1600003192B9C39F826942090000000000050704080F1226160F202B1F1E2D302E3B2F3D363332277E7E69440F000011446A97BACFCDBF9161433D51649DB0B1A77943170000002A4F8BA991592612153D8EA6B1965A5B8187747893C1CFC9B5865B4B5E7294B3C861433D51649DB0B101FECA5B070718A074240000236FA097550C00185289A38446180612469EBEDAB0511500205A9BD1D19F51140000216EAAC0C6B369232E60A5C2D2B09DAB8D430000000D42719599AFB1B8945119133876B4C3B5BEC4B59C54131E658895A8AF9F8FA28A7975856F3800002167A1CDD5D3CFC1923E0E0D4193B8CAC9C7B5AA58020000408FB9C3988271450D000000000008010A020911101A1822292B272F2E3331352F343636287A725D3A1000000E3A6E9BC1D3C9B58D5E4031406C9AAFB69F70410A0000002C528A9A91561F15164297AEBEA05F4A757E7C7DA0BECACBB08B6555615F89A1D45E4031406C9AAFB601FECB5B070718B0761C00002F7A958A570A001B548C99884F1102114AA0CBDBB65E1401124C9AC1BB9D570200002471B2CDCBB97025276CA7C8CCB0A8AE914F010000154477969AC1BAB38E3A14082F75ACC1B8BBC0B4934B1424648D959EA48B8E9A8873759075310700295AA2D7D6D9D3C4914312134D9ABED3D1C6B9A5510000004792C5C09A7D69430000000000000A030600050C0A181318212832332F2E3338382F333229817862460F00001C4F71A3B6C5C3A58A65453B56779FA9B7AE7A3A0A000001214F84A0925E2413104BA1B3BA975D487782737697BECDCAAD82614E577691A6C865453B56779FA9B701FECC5B070718C0721B0000316F8F8E5B10071151809F8B460A001149A0CCD2A95C13041C5690B6BC9F53090004286DB3C6CAB864202364ADC7CCB3A5B698490000001A4A7890A3B2AFBA924A170D3A82B5C5BCBDC3BC8B410E1E5F94989EA18B84948E7A84906A2A04001F65A8CCD9D2D9C58634111C5194BED0C5B6BCA3450000004DA8C7C19B8A6F410600000000000D0A0A000408131214161B20373536313E363C382C3020766F4E2A000000114071A2BFC6C5A98A643545497793A1A29674430C00000023508BA4985217161B4B9AB6BE995749787C7A7C99C8CCBEA8815757626F93B8C9643545497793A1A201FECD5B070718D0722900083378A09B551409255095A2824F0C00104999CEE0BE6814091A539DC9CAA6511100042B7DB6CED1A85A222B6AB9D1CDB8A6A4924E0600000C4F799699AFC3C58C3C0D033886B3BAB1BABBC0904D142B679A98A6AB938D99917B8A85652500002860A8C4D1D3CEB8863506155197C3CAC3C5C5A2530400004894B9C49E83753F05000000000004050B0300090D191919232C322E323437323736263627897855390C0000204E77ADC4C3CBB08F65443241709EB4B8A275280100000031538EAC9D5F1B0B134BA3B1B188524771806D7C99C1DCC7A97B5A49607494B6CE65443241709EB4B801FECE5B070718E07E2600023C809D904A150021548EA88F441108154C95C4D6A35916081E54A5CCCBA64A1303002871B4C8D3BD5C202565B2C8C5A9A8AA904808000020517E8C9DBFCEBF863A0F0F3987AABBACB4BEC99C3A1526699596A49B958F9887818C92621E00002B68AFD4D6D8D1B5802B0A1A5890BEC2C2C5B4A1540A00004B8FC8C8A38866350000000000060C020406000B1215101B25262A2F3932323437332D261D7C6F4D1F000000184C7996BED0CAAC8263342F4B6D93B2AA9E753204000002336096A69A5C1F12174A9BB3B18B4A5C77796B84A9CDD5C4A8875F56607590B5CA63342F4B6D93B2AA01FECF5B070718F0711F000028749988480C00194F91AC883D0900134994C6D1B35B170B215DAACAC4964A0A00003782C1CAC7B15C2A2B6FACCBC7A99CA5904C0200001657788795B6BFB97D3704093A8DBBBCBBC0BFB8964017206D939BA8B2998B9C91858A8F5C1600002C71A7CCCCD1CFBF7F2B07185CA7BCB9C0B7BE9D4D0100064E96BEBA9782724C13000000000208000700080E0E141B1C2928313134323330383B3832148275512D000000155790AEBCCAC2A7876147404D749AB8B9A27030000000003863999592531F0B09469FBBB993545278847F86A5BECDC2A2845F5560728ABAD16147404D749AB8B901FED05B070718007127000034748E804C0E051E4B89A8783400000C4A9DCCD6AC63150D275FA0C7BC94420D00052E78BECEC7A75F24306CB6C6BDA6AFBA90440400001A4E748A92ADC7BE873B050B398BB7C2B2B4B6BD92421B226E968C969D8D90A29991919A591500002F6DB1D1D1D6CDB27122052463A0C6CDC6C4C19D4801000D4C95B8C1A285703E0600000000000C00000003121019192D212C2E2C342F2F2E32343937217560351600000020336E9EB9C5BFAA8557413D3A6E9AA6AD9D6F2E000000002B6B9FAA914F190A1755A2BCB3884A517D827482A3B5C6B9A2845E525F7492B6D557413D3A6E9AA6AD01FED15B070718107A3000013881AD994D110A2D599BAA8542060010509AD2D9B261150A2866ACC4CF9E4B0D00093A82BACFC7A655212D7BB8C2C6ACA2B29241010000225079869EB0C5B17C3005154B86B8B6A4B8B5B48C3315277B9C969E9E8A999DA18F93894C1500012F73B9CCD3CFD5AE6C1E0C306D9BBFC0C8BBB796400000074EA1C1D0A483733A0400000000060A000007040E191919171F26232930393B323B3137362472633913000002225278A1BBBFB799705F3532426E98BFBDA8672900000000305E92A38E561C14294AABB0AD834C487A896B7BA5C9CFB7A082534A61839CBBCD5F3532426E98BFBD01FED25B07071820812B0009468FAA8F410F0E2D5D9EA88A3C15081E56AAD5DEB35F170C255CA2C6BE8C4306000B377AB7C9D0A75829347DCAD5C8ACA6AE933D0000002B607F8A99B6C4AA7A2903022F7DB8C5ABAFC8BB92361D31709896989C9494A098899C945B1400003678BCDCDEC8D1A8641B0D346A9EBFC1C6C1B482360000075AA0C5BCA4846635050000000005100D00050010100C0E141D242F3738332F2E3033302920786F3917000009266082A9BDC5BDA57D59443D476E99A8AE9A601E000000073265998D9161240B1C52A9BBB68B4F4C837E788BA6B9CDC1A7855C4363829AB6D359443D476E99A8AE01FED35B070718307E2F00133980A4904A16042C6796B4873807001A61A4D3D7AF5D27122662A5C1C29A4208000E408EC5CFCAA94C243078C6D8CAABA5B0943F000000245D6C7F97B1C5B2751F18114A93C0C0ABADC1BB8C3D223482979997A5898CA197959C8C4B0400003D74B5D1D9DAC8A1590F0F3B72A1C0C6C5BBB28E3000001361AAC0C2A3886A390100000000080F060B020108090E18161B1F272E2B2D3230363B2E2F2C816B400B00000825648AABBCBFAC9B72533E354D749CBAB5955C1E0000000028689AAA8F5921081960B8C3BC864A507A7C7183A8CBD0B8A1875B5A608096B5D7533E354D749CBAB501FED45B07071840752D00063E87A49143110723619BAA7F340000225EABCFCEA25C110B2D65A9C6C18D350A000D478EC3CBC9B05621377FBFD4CCA49FB2933E0000001D5D767B96B1C5B1762608194A95C3C2A9BAC1C0963814317A918C96958796A49F94A1854100000D407EBAD6CFCCCDA35D1408316DAFC9C6C6C1C0862C0000145CA4C0C8A98B6C3A00000000020708000006080B10111D1C182229322E322F37353A372F236A562700000002216188AEB7B5AD8E7064442D496EA1ABA9956714000000002A699FAC91551E09206AB7BBB984475586776B7EA1BAC8BFA4733E4A6A82A0C7DF64442D496EA1ABA901FED55B07071850661F00064C8AA28D3A06012B67A1A6752A00001758A3CBCEB05618172F6BA9DAC8973A07000A438BC4CDCBA04B123687BECFC9ACAEBA953B0000002B657E8690ACB6A76E270B114396BBBEACB0C8AD893311287AA393939F91909F9B96A890410000003D81BCD1DFD3CFA15114093C76B5C6C6C0BAB78C2B000013619DC3D4A78D673201000000060B080902020B020D0E141C1F242A372F2A2E29323531322767542600000000235E90ABB2B8A995755744354F7DA6A8A3925E1B000000002A6499A3975D241D1C67AAB9B4803E497779767AA3BECDBAA783434D677EA0C2DA5744354F7DA6A8A301FED65B070718606A2800154D96AD9743110C3974A4B3753407001C64A2D3D8A2541D12376CA4C9C2913D06000A4194C4D0C59C4F203B84C5CABFACAEB8894100000031697E8E96B5BBA8641F02124A8FBCBAA3ABB8BB96351934849494A5A18997ADA8B0AC8E3B000000388BBFD7CCCCD2A24D0711487BAFBAD2C4C4B078290000206FAAC0C6BA8E5E300000000000060E030000000D081113121A202734312A303534322D331F6D5321000000062A5F91ACC2C0B09A7156363C4E74A7ADB3915E1500000000326C9CB398611D0E1A6EB3C4B381515487827680A9C4CBB1957057506984A9C1D756363C4E74A7ADB301FED75B070718707D30051C5298B6975016195084ACB67D360C0B1E619ED5E9AD561A163569A6CBC78B360000125294C1D1CC92471F3188CBD6CBAAA7A5893A000001456D748292B6BCA2591300164894BEB5A0B8BBBD903A13378BAA989B919498AA9CA3A1874100000B5088B6C5CED0C9914105023F8CB8C2C6C6CCB6812800001167B3C8CEA482632500000000020D11120000020B08181C171C29252D31312A2E37333335276C4C2300000013337097BBC0C2B78B725A38365485A3BDB681580E000000012B70A6AC9E5E1A182375B4B7AA7D4E5479787C8BA9C5C3B794684E567188A1C6D35A38365485A3BDB601FED85B07071880792F0019589FB390471017447FADB07D2B00002465AAC5D0A05C23133F76A5CBC7993E09000952A3C9CFCC96421B3D8EC2CCB7B1A7AF7F340000003D7B807E92ADB79C521204144C9BC5B89FAFBFC58D33193B76A0938A8F8F91A9A9ABA591400000003F8FCAD5DCD2C789400401408DAEC0BFCED4BE842200001567A6C0C5AB82662E0000000006140E09080103070F1110161A21302D2B292F31323633311F664D1C000000053B6494B6B7B8A48C74504241517CA3B0A58C5D13000000002B649DAC9B5B230F2670B5C1BD7D474D8081778CADC6C7B4966C4F4D6791B1C5D6504241517CA3B0A501FED95B07071890702C0C226AA2B9914211194084B2B87E3401092668ADD8D7A64C201B3D70AAC9B980340406214595BDD4CD8E431E3A8ECCCFCBB6B6AF87320000003F72797EA0B1B397511300154E9AC1B3A5B0C3C98F32193E8C978D9497899CAEADABA687370000074D96C6D9D3CEC3822E05175392B9CBCBC5BEB177210000266AABC1C6B3825E29000000000514150C0604070E0912131A201B27302D333B3639332B322D684D1D00000019416C9CB7BEBFAA7D645740425A7EA7ADAB804908000000062C69ABB59E672B152170B9C9AD753C5A757B7C8BB8D3CEAF9577464C6E87B4D1DA5740425A7EA7ADAB01FEDA5B070718A07A3B172E72ABC9A25A2420548BA9B57A300E0B3066A4D1CFA14B2223497FAECFC08A3008081763A3C6CACA983F1D4590C8C1C6B4B2AA802C00000A4F7B857C99B3B98B48140A1A509EBCACA7B9C3C192361F43839C8D8E8B8198AFAFB2A9762400000E5492C3D5D3D4C77B3100124D94BBC7BAC8BDB8742000002C7BAFC6CAB0825E2800000000051B160C0A00000B0810081B1B262E302C3031363A3B37302A6A3C0C0000000C487096AFC1BAA97D67513E3A5787A6B7B08F5B0E000000052763A5A7915221131D6CB1C2B67538447D7C7B8AB0C5C8AB8F625A4F6D8DABD4E0513E3A5787A6B7B001FEDB5B070718B06D2E15326BA7C7A2551C274E88B1AE6B2103083067B2C4C39C561F1F497DBECFC0893204001E67A7CECDC78B431E4192D2D6C7A2A8AF7E2B000004508C868598AAAF90460D09204A8DBDAFA8B5BDBC8E35214D8B99918A8A899EAEB1ABA67E290000125695C2D3C8CBC17D26051F569BC0C2C0CAC2AC6A1400002674B3C6C4B77D4F1D000000001218180E0F02000A050D112022212B30303132373834312C19653F1A00000019457E9FC3BEB19A8A64514B415988A8B3A98D4B0B00000000316E9EAC9A5F23021B6AB7BC9F753C4479787C94BBC6C6B18B634E4D739DBED8DD514B415988A8B3A901FEDC5B070718C07A3E1D447BBAD0B1612C336B98B8BB7C3011033A78ADD0D1915126305588B9CECF873705001861A9CCCFC7863B15439FD4D0C4B7AAA46A1A00000B4E8A8A819EABB1853F04061F578BB1ADA1BEC2B98C2F1F428A9994958991A3B2B1BAA8802F0000125D96C6E1D7C8B86426041D5CA1B8C0C7C3C0B0721A00002C7CAEC4C6B283511A00000000161C1A07050101030C140B0E19222B2E32342F2B34383431206730000000020F4C7899B7B4BA9F84646A4A476587A9A8B9915B12000000023365A3AE9759210E2374ADBBA9783C5584887C9ABDC8C1B6896848457599ADCCD86A4A476587A9A8B901FEDD5B070718D0743B194183C5D7A65F2C34709FBFB07C2F0D153372AACCCB9547252B5991B8C8C37E2505092B689FBFCCBF7F30264D9ACAD6D1B6B09F6D2000001159978889A0B3BA85330002185691AB9FA2B8CBC37E2319478C958F808B8DA2AFB0AEB0821F000017619AC6D8D8C6B77022001964A4BFC9C7C7C6AA680F0000317EAEC1C3B07B491400000007202321171400000308111217191E28292D35332D3932312A2A592D06000000143B81A6BDC0B49C7D5A50363A707FA1B1A9824108000000002A6FA5AA865E1A05297DB1C0A5713D4A797A82A0AFC9C5A38E6540547F9CBBCAE150363A707FA1B1A901FEDE5B070718E0763A264590D3D8B0622C3B69A2BDB4702A030E3B7BAFD5CE984D242E6496B9C5C5832D030D2869A7D0C5BB6E34204998D9E3D0B4AAA9711800000D589A8B849DB1AA782E0003225699B09EA1BAC3C182301B488D9B958883849FAEB3C1A76E1B00002968A9CCD5D1CBAF701C00216BADC2CDC7CABFA05E0100003481B1C7CCAA7A4B14000000061629240C0901000403080E1A202731312E2C2D2B2D33302A215D2F00000009234692AAB7B9B8A078524D323B6695B3BDA78A4100000000063471B0AF995D1B022582AAB4A16E2A4273817A9DC1D2C9A78E67385B739DB8CED64D323B6695B3BDA701FEDF5B070718F07348385798CDE4BE5E434774A3C0AB762D15123E7EB7D3CF8D3F25355F9BBDC8C18A36070E2C7CB8D0BAB07632224DA0D0DCCAB7AA9D651C000015669A988B9AA3A86C2708031D61919F9A9FB4C6C18131245690A692897E859FAFA4ADAF7E2200002B69A4C9D1D3D5B95C18011D6EABB7C1BFC3B69F560C00003B8EB1C6C6AE7A4410000000082A28170A060500060A161120242A2D2A2B2B2B28302F303221583600000000274D7DA3ACB5B5A6835D553B436890B7BDA9844503000000082F739FB2955C20042977AFB9A26927417B7A739FC4D7CFA887564C4F7DA9C2D8E1553B436890B7BDA901FEE05B07071800724B4360A4D3E8AF5D344A76B6CEB871290F1E477CB2DBC988462B3D6F9FBABEC780310E123377BED5C8AC6E2E1F4FA9DBD5D1B3BAA6520E000014589E9196A3AAA35F2A0805205E8E9E99A5AFC6BF8134214B929C938D8B8C9AB1B5B8B0711700002C67A8C3DFE0CAB55619092D6AB3BEC1C8BEB8A7570700013C8BB1C2C7AB793D070000000A1D28200C05070C04090E131321202526272C2D2C2C303334235A310000000E325591AFB8C2B196665650334F6B96B4C0AE904400000000003884A5AB9C692E00337CBCB993652B42677E818FC3D3CCA48A5F41537A9AB6DDEB50334F6B96B4C0AE01FEE15B070718106F433266A5D8E3A96D3A4A7FB8CDB4672B121C4C89B6CDC6803A253B7CACCACBC07D31131C407DAEC6C1AE6D38255094CED5C6AFAFA2621A000015649E99969BA396622400052B5A9599929AB6C4CC7F2E265592A29B958695A8BABCB8AC741D00003377A0C9D4D7C6B55716012572B5C6CABFB8BC9E4D0400055098BBC4C2A8714204000000112E1F1E130C00000909010B111B1D2B3038393633282C2D251A54280000000B1356A2BABEBCB99261534833446C9BB7C0B9884000000006042969A9B4965C20002E7EBBC5A765333E6677809FC1A8C3AA7F554558809DC1DAE74833446C9BB7C0B901FEE25B070718207E4A3868B1EEE5B169434B8AB8D1A664260A204C91B4CBC07B3C2D4C78B4BCC9C07D220719398DC2C8C6A6602F22519AD8D8C1AEAE9B571200001C64A3A1A5B3A38B4D18000D2B5D888B919FBACBC77B2F21529BA9A89689889EBBB9B29E641500003C89ACCBD6D9D5AE5511003887B9C1C6CAC0B9A14500000C4B89B4CDC4A5732D050000001B2D3527140C000000000507131E29263427282F312B2C2F2320622C05001613375F8EBAB8BBB29376524B404A78A4BEBCA3894107000000003E76A8B1945A2901267BABC3A8602C40648489A9C6CDC3A38560404B83AAC5DCE14B404A78A4BEBCA301FEE35B07071830774F3A5FA8DAE8B76D3E537DBCD3AE7423071B437BBBD7B8743A2D4E8CB4C4D1C57E2D09164480BAC6C49D5D291E57A8CFD8C5B4AD99551300002568A8A6A1A69F844717001031708E8A959DB4CAC97B2A275DA0AA967B7A89ACBABABBAA5E1200004178A6CBCAD5CCAC5A1A0A3579B0CDCFC9C9BF9D44000008579FBBC1C2AF773B000000001C3330260A070000000C0E1112151A2C2D2C282D2E3932312B1C591E010005223A4388C1C0B6AA855B5045414D7AAEC2C9B1853C02000004123872A4B7905510002B7CA6B3955F3341697786B4CDE9C5A57C59415887A9BAD1DA45414D7AAEC2C9B101FEE45B0707184077535075BAF5F2BC6C465C91C6D5B16D2E1A2B4E88B2CBB76C3A32549AB8C5CABC772C10214880B6C9B98C532020569EC6D6CAB3AE93460700002E75A9ACA9B3A0824313000A2A5A888D8397BBD4CD7D32336199AAA3847A91A9BFBBB9B45D0C00073D85B9CCD4D7CD9C4D0D103B85BCC0C7C1BCC3913A000012509EC3C0C4A96F34030000001D34302B130400010805110C0B131A2F2625292B322E2D35302347110000071F36528BABBBB1AC8860443D394D629FB7B3A6874900000A1818317693ACAA631A083280B0BA955A2438637B8AA5BBD2C3A78063455C88B0C5D3DF3D394D629FB7B3A601FEE55B0707185079504477B9ECF4B973436199CBD3A6662A1F274A89BDD0B26E3B2D5196B9C8D9C1802C07174C8DC4C3B9985A252163A9D1D4CAACA4974D1000001D74A2A3A5AE9A75431100093267818890A0BFCEC2742D2A659EB4A8928296ADC1B2B39C541400023D86B1CFD6D3D9A54E06044590C0BFBEC5C5C7992E0000125E99BBC0C6B46F2B000000002536372B170400000405070B131F222927252A2A292A2E262D1C4D2200061D2A436B98B6C6B4A2936B4C42083677A9C2BCB5873F02002115153B6FA3A78E5B1A073688B1AB9B6C3230696C7C9EC5CCB8A17E5F4C6287AED3B5CE42083677A9C2BCB501FEE65B070718606E49446AB2D9EEB66C4E598EBBD4AA61291524518DB4D0B776353158A3C4C0C7BC7D280B174494C2C6B77B48191859B3D8DBCDA8AA964C0200002978B4B1A6A8987433090014366D877F8898C3D2C1742F2D6BA5B2AA918094A9B9BEBD99520700024792BACDD3D5C69645130E4B8BBBCABEC9CACA9D3200000C5B8FB3C1CEAD662F0000000025423D2D1B07000000000704141E1C1C26252A232C2D332F2F235E3909031012345C8EA8A9A4A189594239434C70A1C1BAAA832E00001717172F6E9EB192550E022A759DB5996037383B6E80B3CACFC0937E654B5D86A8C2D5E139434C70A1C1BAAA01FEE75B07071870724F427BC0E5EBA7664A6499CFD5B26D2B15244C90BCCFAA5D3A3B67A4D1C4CFC675260D195094C5C3A8773E18225FADDDDDCEB3A693430100002777B3ADA9AC966B370D00104169816E85A3BFD6CD6F283367A9B2B28C83A0B1B3BDBC9847000008458EC2CFD8D0CD9D3F0B1A418BC5C6C7D3C5BB983800001454A2BBC0C1AD6D25000000052F40372A120C0003000103051515161D2C262D2C25312E2D29234C1904141C2E446D96B5B7B7A288643D2F35436DACC1BAA7753402041B1A1A535385A084561B0B3486AEB79A572835637286B1CCD0C6A17B61405787ADC8D5DC2F35436DACC1BAA701FEE85B0707188076584D7ABBE9E9B3714E6096C8DEAE6E311D20599ABCCEB764323664B2D1CCCFBF70270A224B8BB9B7997C3F242768B9E0E1BFA3A58E3C1200003585B9B6B4B38F67240B051A4371766F7C95BCCBBA6E2C3D6CA0B2B4908799B2BDCDBB9A4B06000A4F80B6C7CBD3CC8A400E0E4C95C6C3C8C0C8C0902300001B6C9EBFC5C2AA6D2F0000000128443B2413100000010105110A181D2A262D2E2D292A2A30321F47190A111B24416D9DC2C0BFAA84533D373676906DB7BBA773430A0E201D213874A4A88654200B3383A7B08D5C262E546F7FA8CAD7BEA2836655628BABC9D2CF373676906DB7BBA701FEE95B0707189071504D73BFE3E7B3714E66A1C7D5A9592419234D89B6D9AE6D343C72B3D2C9D4BB6D270C135699C3BAA26F35181D68C3DDCFC1A3A48D4009000A2E82BCB0ADAB8E582700001044737B74879EC1D2C76E2C2E6BA6BAB78E7798BAC3C5BC95460200105498B9CDDADCCF9B40100C4B97C1BEBFC1BFC4953E00001E6EA5BBC7BCAA63200000000E3355433217090000000009081118161C282E2928252D2D25271745120512282B5095AA82AEAAA188664537395083A2C4B79F783400002522173973A5AC9059150C3483B0B49459172B48648DBACED5BDA18B6C4F658BA3C2D8D537395083A2C4B79F01FEEA5B070718A0715B5B80BBE2EEAA735B6B9BCBD5AC69281E35569EBFCFAA63363E71B2CAC7D0B8691B02285E96C2C5946D34101D65BDE1D2C69DA57D37050000358AB8B0AEAF91601C0C002046726B6C799EBECEC56F353179B9BBB4857FA0BBC3C5B48C3B03001F5796B4D0D9D7C3843409134F99C1CACEC5CAC38D2C00002667A6BEC0C2A4661C00000010345148320F0300000000010A12141D1F242027242821262B2F1D6145373F454F6E9CC3D1CCBEB59462493D446992B8D0BFAE7C330314312A28427EA2A582542305358BA3BE91532E32586C8BB4D8CAB79F806552638BA7C9D8E13D446992B8D0BFAE01FEEB5B070718B07752537DBFE2E9AD6A5C74A2CCDFB5682D112867A5CBD4A0622F3880C8DBCDD8BC661A0329599AB7B9A26D310F1E60B5D5E1C4A49D753200000B468CB3B4BDB78D50140001205069756A809FC1D3BF6E293678B3BCB4947B9BC2CBC8B9883403000F5596B5C9DBDBC684360C1A609BCFD7C7B9B8AF82240000256EB0C7D2BDA460190000000F3C59482D0F08000000000305101C20212A2D2C292C2D222D291C572619292E3C4673A2B7B9B0A781503830355387B1CABF9D7931000D342B273E7A9EA48A5A26003987A7AA85512024516E90BED5D5C2A08160506B8DA7C4D1D330355387B1CABF9D01FEEC5B070718C07A5E5A80BDE0DCAA644D6EACDAD2A564311E395EA3CCD2A96331427CC6D6C2D2BE6A1C0B1E519CC4C09664241D2A74BDDBD3B79E9B74290A000A448CBCBBBEAF784F1E0000225476686B7F9FC7D7C56C2D346EB8BEB09685ACC3C0B5B682330000185C96BACFDACAC18B2F0E125CA9CCD4CBC1B8B379150000267AA4C9C6C0A86D1C0000000D35554832100800000002080A0C0D191E2A2C2523282C2E2E261C502A1B222E354D7699B4BCB09D8244262B395183A9BDB9A2832E000F2F35233975A89485501A1232859FB08B562125466295BED5D2BF9D80655A6895B9D0D7D32B395183A9BDB9A201FEED5B070718D0755D5091C6DBD5A66A5575AEDBDFB36B2D1F2B57A5CADCA65E343A84CBE0D1D7B673240C2A639BBEB2945821122272BCD8D8BE998F6E2A05030E4D88B7C0BBA281401C03001A4B766B5E7AA9C6D5BD632A3E78B2C7C09882A6BFCBC4B086360000246595C2D0D7D5BA84320A1D62A3C9CECDC9CABA812200003176B2B8BEBFA05B13000000144457522D170A000000000000141A181D271E2026212823302C17502321373336557CAABFC1A99C774C36313C5D8BA7BBB19D6C2B00083F34293E79A6A983491108468099A77C5222294E6D92BDD1D3BA987C6C5D6D97B0C7DFDB313C5D8BA7BBB19D01FEEE5B070718E06D605C8BC5D7D8A6645575B5D5DAAC63321D34689CC6D59E5A424B86C6CDC9CAC06D24112F6492BFB796552316216DBEDBD7B39B946E2504000B4695BAC2BCAF80470E00042D5B79726776AAC3D3BA62273D79B9C3B19493ADB8CCB9A67822000026649FC3CBCEDAD2842C0F2065A4C8CFB9C5C4BF8A2100003676A9B8B8B8A3500C0000001C495E4B3019030000000000000A18121A20212F2E33332F2D241D461F222D2E3D5880A1C1B8B69C78492E212D4987ABB9BDAD7524001E3F371C417E9CA2794214063F8CA3A186511A28486293C5DADBBD957F6D5E759AB0CEDBD9212D4987ABB9BDAD01FEEF5B070718F06E636190C1DBD99D685C79B1DEE0B46A2B2039689BD6D2A3573A4E90D5DBD7DABE62190A276AA0BCB5824414142670B7DCE1BE9B92721E04000F4996B6C2BDA4784312000630597E6B6379AFC5BFB15C2A417DB9C9BD9A94AEC6C5BFA56C2700002B66AAC2C9D1D4C7872A042970A5C5D2BECCC5B7791900003184AAB7C7C0A6560A0000001D55685C4416040000000000001110161E1D20201C27362E232F26481F292C36335C85AAC4BAB39B7C432D24375488B4C0BAA3712E03193A31254781A89E70401B0A4491A0A4805E1C1F385C8FC6D9D9C396796B637994B2CFD9CE24375488B4C0BAA301FEF05B07071800755B6388B9D4C890615380B6D1D3A7592F1A336CB0D7CF9E54405596DDE1D4DCB1611F06286BA0BBAB7D4E17082973C1DCDBC1918C622206001C5FA8BEB7BDA475470C0406316A806B637EAEC4D5B45628307BB7C8C29996A7BFC5B6A06C1C00002670ACC1C7CED2C4793A1B336EAFC7CFBFC1BAAE741E00003884BCBFC5BA9D520B0000001E5B7B5C370E0000000000020D08110F231F2724301D1F2525281C48272131383C5980A6C3BEB3A0784A232F33588BBBBDBA9F662A001535282F4C80A9A36B3C1E044390A4AB814E1E213E6A97C1D7CEB2978171676E9EA4CADED32F33588BBBBDBA9F01FEF15B0707181076555E8CBDD0D493635680BDDED5A45828273967A9D6DBA0533C5292CBDBD9DEB5611C12346B99B3AB8340170B2D79C0E3DCBC908C651B00001A56A0B9BAC0B67C2B08000831607B67617CAFD1D3AE5B2D3F82BECEBB9691A9BEBEB397642400003870AAC8CCD7E4C27829182E76ABC7C6C9CBC2B56E1C0007468FAFBAC3B799520800000030676D5F360900000000000000090F0F1A1F22202724212627281A463535343545608DAFBFBCA89676472820245B94BBC8B89A5F1B001D3E412C4B8FB3A07746261346919EAC834718203E6791BEDBD1B199827068728FC1D0DDDA20245B94BBC8B89A01FEF25B07071820755F6199C0CDCA97675B86C4DAE0AE682B1B3771B8DEDA9D5C34549FD5E0D6DBB75818152C619CB6A0773A19162E7DCBDDDAB99588641D00001B59A2BDBBCBAF732F100006316273656D88B0C8D9AF5A26418CC7CFC2A492ABC3BDB49D5D0B00002C71A6C8D0D3DFC0711A103471ADC6D4C8CAC2B6781000063D8DBAC4CBB79A5B0F0000002F5D765936140100000000000809110C171D222022252B2C3231254F2D38393F45648DB4C4BFB199764B3123326698B7CAB6985F2801164243345798AB9C8142170F4D919AA76F451817366B9ECEDFD1B3987F70616E96ADD0D5D623326698B7CAB69801FEF35B0707183077676B87B3C5C0915E4F85C6E5D8AD66342634679DDEDC9C483C5CA7E0ECDCE0A756170D356AA0B4AB7343130C3679C5E6E6BDA384501903001D5B99C9C5BDB1692C070008336A7961688AB1C8CCA85128448ED1D7BDA694A0C4C0AE9A550E00003277ABBACDCFD4BD7720133E87AFD7D1C9BCB8B96D150003478BB7BEC5B89848080000002D647A67410F05000000000000010C11192523242A30322A2632175033343E414F7091B9C8C3AD937449261B296397BBCEBC9A662000143D40395B8FB29F764217145293A0A38A4316193C6496CDDFD4BF9C7F72657898A9CCD4D21B296397BBCEBC9A01FEF45B070718406D667096B8BCBC88656087C3D6CFA45B2E2F4877B8D2DAA2533A539CD1D3D5E4A75A10123F73A5BCA76F2E16123480C7E3DBBB907D5C1C0B031C60A9C0ACBBA3772B00000441767C66637EA9C7D0A750274285CCCEB99A9AB2C3C2AD87470C0002367AB2C6D5DBD3BF7A2314408DB7CEC6BDCBC2AB6D1000065394BBC2BEB689460000000032718B6638150300000000000208090C17201C232822252F282817523D4A4D524C6B91B6C2BFB393724522232B508DB9C7B79B631500123946386097AB977D3F1B1A53969D9C743D1223436C9CCDDFD8BB957E7269788AA4D3D4D7232B508DB9C7B79B01FEF55B070718506F657090B1C4B48B5E699ACCDDD2A764392C4072ADD9E6A850385DB6E5E1DDD7B0561D10316AA0B9A66B35110D3981C4E6DEBB8B7C4D160B001C5EAFC4B9C3B769340000073E748D675981A6C8D19D4A2B4C8DCDD4BEA8A1B1CFC0A38545040011467FB4C4CCCDCFBD68240E4290B9D1CFD2CCBAB4710F00024C9BBFB9BAB49245000000013A75906A3C18060000000000000004120E1A1B1F2325292126261E4D4748433C487598B3CFBDA9926D441D2036609AB8BFB699571B0024423B456B96B19D6C370D1959929E9D6B401D1B3A689AD3E0D2B6867E7C556D92B3CEDFD62036609AB8BFB69901FEF65B07071860786F79A0B6C3B77F716B9ACFF4E1B06B3B24416CA6D2DF98544561B8E9ECE7DCA34C0F113B709ABCA7712D06093788D5F0E3B7926E470F00132859A1C1B8C3AA5C2805010B3C808967658FBACACE9D3F1E3D94D1CEC9A999B6C3BBA785470600124F85B9C5CAD0D5B56C26174590C1C5BFBBBFBEB26B19000B599FB5BAB8AC883A000000013670896C361000000000000000000A141A1C141D1A25303129281D534646444E5778A1C3C7BFAB97734B27243462A3C8CFBD9B5E180026413A376B97B5A1683B211B549198927F4620273966A6CED9C1B28A807E6D6C8FA8C9DBD7243462A3C8CFBD9B01FEF75B070718706D5E6B96A6B9A37353699ED0E4D49A572F293868ACD3DC9D5A4665B9E5E7E9E69D420B0D3E6E91A691602607012F88D7E0E5C08C694317050E2671ACC8C3C2A763260102183E7F8A6B608EB8CAD29344254791CACCC4ACA1B3BEC4A87E360500134888BAC8CDD0C8C36B201F5096BDCBC3B6B8BDB56809000D6398BDBDBBAD863700000000397A90693E1A0B00000000000106080F21191C2021292A282A2C2046353D40465B7EA5C1C8C3A68A68421B18355C9DC0CBB291561A001E36434A6FA5BB9B622B1D265892939C7A3E171E3B65A6D1DCD0AF8C81806E7090B1CFDBD018355C9DC0CBB29101FEF85B0707188074666E98A6B6A586626387C6E5CE9D5B2A294581B8DCE09050416FC1ECF7E8D4943E151A46678DAD9E591B040E3288CCEBE6B58E663A0C00082C6CA7C5C2C0AB6B270001124D8185696093BFCECD8A43244094D2C9C8B19EB5C2B4AB75320000185290BDBCCBD7D4B9662121569DBEC8CBBBB9ADA8610C001D6C9FB9B8B9A88345000000003B798662411B00000000000000000C1022222029232C2420202415503A424348607C95B8C4C8B48F693E22224473AACAD0B8955C0F00183F475077A6B7945B361C316D9D8F9D6F331D12306BA5D6DAD1AC9381806D7C91B2CCD5D6224473AACAD0B89501FEF95B0707189077717E9CB8B0A376586894DBF3DEA95D38344E74BEDBDF965A4C76BFF2F3E1DC9E3B141D3E7295B39B4A21061A3D92CEEEE7B88761310D00083870ABC3C2BCAA6C290511164B818262588EBECBC488391F4399D5CFCCB6A0AEBEAD9A6B2B000020619BBEC1CCD3D5B568231E5C9ABECFCBD0C3BDA45403001F64A3BBB7BAA58334000000064085937343140000000000000204050E0E1D23251B2428212524194E43484C5B677E9DC0C8C0A7886D4A1E153C6EA7C4CEB88C5313001A39443F74ACAD93633B0E1E609B978D5F3616203B66A7CFE1CAB2897C766A7F91B6CDD2CD153C6EA7C4CEB88C01FEFA5B070718A0756F769CAFBA99746B6DA1E6F6E5A36637294174B1E7DF91545280CBEFF3E3D68B46131342748A9E8E4D1C0A0A398ED5ECDDBF8B63310D0410346EB5BDC0C1AB651C08071A518888706B94BDD1CA8A39223F90CDC4C0AFA8A7B8B7995F2300002960A3CCCED4D6CEAD5B1B2156A6C0D3CFC7BCBBAB5200001E71AABFB1B3A67B31000000124A7F8F76431B0200000000000000080718161B181C20242B25291B5B404850506489B5C7D7C7AA906E452B2B3D6895BFD2BA9357190016383B4C82A7C29A6B36151F648D83916C2F1125336EA7D6E2CCAF8A7B807C7E99B5D5DBDB2B3D6895BFD2BA9301FEFB5B070718B073728AABB0B09B75666CA0D7EEDEA7633C2F4676BBEDE490504072C4EBF0EEDC943D14224F7096A8904916021B448FCFF2E0B9956029030010337AB4C6BDC2B5671F000D215B938E6F638BBDD0BE8A301E529AC4BCBDB5A2AFAEA78D602600062B74A0BAC6D6DAD6B4581B2363ADC0CECCC6BAB1AA4B000029729EBAC0B5A9843900000012498694794612000000000000000108121923201D251F2324282A1B503B4C46476696BACAD8D3B48E733D23254172A9C9D2C89C611D00102A4B568AACB799603A2F2A75988195642F1A263D64ADD6E2CBAA8F7D74686C92B5D6D9D3254172A9C9D2C89C01FEFC5B070718C0736B79A1A9B2986F5F6FA2DDEDE0A55F352C4275B2ECE5A2554C84CAF9F8EDD68E310E1B497194A68A40130218468DC7D8E2C48B5A270604164781BBD8C6D1B66B20000017518A8A666797C0C9C3813E14489AC5C0C6B9A4AEB6A1794F1A00033370A2CAC8CCD1D8B85B172372ACC8D0C5C1C7BB9C4801002578AAC4BBB7AA8432000000034995997740130100000000000002060A111B1C281E262722242616473E4C4B456196BED4D6C69F8F69450D1A4377A3C5D5BE8F5919081C353A5486ABB88E57311B2A69A3868C69361533447CBED6E1BB9B857D836E6B8EAEC8D8D91A4377A3C5D5BE8F01FEFD5B070718D0706B7F9DA2A9926E5C6FA2D5F0E8A15338325279BEE9E9944A4580D4F8F6E7D57F2D0C1D4C76879473391409174198CFE5DCBD9057280D0725408AB7CACCC2A45721000B205C9896716188B0CBBB7122204EA3D4D3CAB3A7ABAAA3753F0400053388B7CCD0D9CBCEAC511B2973B5CDD2CEBEB9BBA44C06002B7AAAC2B7AF9E7430000000145499A47E4A1E00000000000000000C0C151B1A1D1C1F2226181B165A4C524F586F95C2E9E6D1B8937044293A4F81B2D1CEB4885B1B08153A3D4D859FB28E612D18225D9A8B8D6B2C17274F78B8D9DCCFB08A726E6B628CB9D5E1D03A4F81B2D1CEB48801FEFE5B070718E0737482A39C9C896A5B6EA5DAEEE99A4D383D4F76C2ECE59D554B85DCF7F4E0D07E26031C597C9BA580300F0210449AD3DCE2C4926228030B1E498DA9C0BCC2A3622305001F5F9B92746B95B8BDAE6F23194792C5C1C2B7A1A7B29F7348110011518AAAC7CAD2D2CAA451162C7AB6CDD0C7BAB6BB924301033A7CA4C2B1AF9D7D2D0000001E589FB683431800000000000000000C0A0F151D181920161C2122175452544E597CA0C9E4DDD6B29479502C355285B5D0D2BA90591E061E333B6093C0BB8E552B1F3473A68591592E26333970A7DCE1C4A77B7774676D94BFD2CCD1355285B5D0D2BA9001FEFF5B070718F06D737CA2AA9D8361566795CAE4E0A0613A335183C1EBE68A504E89D2EBF6E3C5792D16215C7A8C9E6B3110051C479AD0EDE3C99C5D28030E1D4D86B4CECCC39E5218000422619C95776B96BDC4B56327174796CBC3CCBCA39E988C6B341000094986AFDAD3D3DCD2AE501D2E7EB2C3D2C6BABBB29C4500002B83B1B6B4B2A27C30000000175F9BAA7E510F00000000000000000D0C181F1D1F1B1D262222201256536052677BABD8EFE4CBAF96694838354789B7D6D5C4974F1404182D42648FB9B68C572F1D206CA0808A56251C2E447CBCDDDFC3A57C6E72727589B2CCE5D5354789B7D6D5C49701FE005C070718006F768CA2A29789635A6AAED8EEE8A45537334E7BB9E2E18D48528FD9F4F7F0CC782D10275E7A8FA472280C06174894CDDFDECE9D58250A09274C83BCC9C8D0AD571E00001F629D9A776C95BAC8AC601E11419FC4C3C8B498969B8C6D2F0400155C98BCD9C9D0D8CCA64921307DB8D0D7D3C1B3B28E3A00003D8EBAB8C0B29B712100000015659AB08D58230500000000000000060D10131A1F1C1B222B252416604C444A5272B6D9EBDED5B98C64522F3B4F7FB4C9CBAD81561F0D0E28315EA1D6C29658302D3773956F875927202B4C74B9DBD9BE96796D70625D94B9D9E1D73B4F7FB4C9CBAD8101FE015C0707181065788AADA5A17E585D6BA0C6DFE79C5D34314E80BEE7E198575A9DE4F1FDE8C96B2A132C6181929A703107031A4E92CFE7E7C4A44F13000924538BB7CBCBC9A361190409336E988E757693BEBB9F5818104495CAC8CFBCA39290835F330A001C6AA4C7D9C4CBD2CB9F4F1B3980A7C4CDC3BABDB48A3500034F95BBBBB7AE9075280000001D62A1BA8F58210000000000000000060F151D1E16151E261A17140933322944657CB7ECE8E5C5B18E6C45223B588CB5D4D9A7875B1F121F2E3A6BA0CBC08A522B2128759F717F5D25212C498CC4E2DFC4926F6566676596B8E0E1D73B588CB5D4D9A78701FE025C07071820776D91ABA39B83635A6D9FCDE4DE9D5D3B395F80BAECD8874E5C92E3F0F7F5D67528102B6A8698A4662303001B448BC7E5E3CBA05C2711092B548ABECBC9CCAD5D180010276BA29D7873ACC2B590471E123E98CBC7CBC09F858977592002001A65A5BEDED3D6D7CD9A51193383BACBD6C4C0BAAF892C000D4E98BCBDBBA9967629000000206DA9B48B4F130000000000000000080C151615191B202622212313483A4456628CBCDCEFF0D9C2986548363C5790C0DDDCB78758190D1B2B3B67A0CABA86543E2B397CA27687503325335D8FBDDAD6B88C6A6D7162668AB2D1E6D43C5790C0DDDCB78701FE035C07071830798095C0B79B7B605F78A6D5DCDD9C5A3D3F5D8BBBE6E28D565B9EECFFFEF3C4661E0A286A8A90965C1E04031D589ECDEDE7D0A5521B00101F528AC1CCC7CB9E5819000C3476A19A80809FC2C9A4561D114290C9C0C7BB9B867B67441800002566B6CEE0D0D7D6CA9545234187B6C8CDC2BCC6B78B340B11599DB5BEB7AC9C7224000000266DA8B08B521500000000000000000507131616181716241F1F21124A403D465E84C3E6FCE8E1B98A6A4B33365593C0E0D9C0875927131B213D74A6CCB9874F2F273376A36F7C5028213B5496C1E0DAB590686370645D8CB7E1E0DC365593C0E0D9C08701FE045C070718406E7BA2BCA2998361616EA1CCE6EB9A5136365178B5E7D68E5D61B3DAF1F5EAB55C1E0B33698F94926B1E00092753A0D5E3DACE9F541A00172A6196C3D6CFC5A350160008316892967D7DA0BDBF90410F124593CCCFC9C0988279673E1400002B75BFCDD9DBD7CCC7943E123A81BDD1D3BCB7C3BE862E0D1A5B95BBC6ADAC99862D0000002776B4BA98511E0000000000000000000C0C13181E151D23221921104E3341466C98C2E7FCFFDAAE86764938375D99C7E5E7C191551B15202D447DB7C9BD83523A2B3B78A56D8154271F2D4A92CDDFD2AE7F606A645E5783BADBDDC1375D99C7E5E7C19101FE055C0707185065819EBCABAC7D605F7198C6D8E09855383D5381BCEDE0875161AEE7F7F7E0B2541415366C999497581D00081B509ACFE4DDD5A6481205122C5E96C7C8CCCCA44F0E000E3A7C9E9C8A86A3BDB68B3811154293CBCAC9C29A796F563512040B2A81C8DADFD8D3D6CA9148184791C3CED2C2B9B3AE7D24051263A0BCBCB7AE91772D0000002B76ACB68E491F0000000000000000020410141318171A242C261D0D514C4C53678BD4EAFDFCD9C78F6447314469A0CBE7E5BC88572514242E4E81BAD1C18554302C3E82A4627E53291C30569BC5E3DCB18665625A5A5B81B7D3DCD04469A0CBE7E5BC8801FE065C070718607B80A6C8B3A37C51506C9BC5D8E09B53303F558CB7DCCB875466AFE9FBFEECB0511D18407E879B9A581C000A1F5A99D6DFD9CEB3561700112F62A1BCC9CAC38D4611000D37709FA08586A1B3AE7D3D1012428DCDD4D1BE956C6250290D0001327FC5D0E3DCD3CFC6843B26549AC2D3D9BEBCBFB27F24021C65A4ADBBB7A9997734000000307CB0B3895625030000000000000000040E0F0806191F20211C22174B3138446796C5E8FDF5D7B690744E3C4B769DCEE4D1AF845F2218213A4690D0CEBA815236303E799B68834F2C24235D83BED8CFB187646E6C5E5B87BDDADBCC4B769DCEE4D1AF8401FE075C070718706F83A3BFBB9F7A53616C99B9DADA995843425783BFE1D4814D60A9E6F9F4E2A64F18173A809E9F9E631D0000285695D2E3E2D8A64815021F3B659EC8CEC3C697460E000C3F76A4A3947D9DBBB27A2E13184F93C5CAC8B38866614C2E0D03023B8CC0DBEACED2C6BE8535214C99C5D0CEBDB7B9AC682C032A6EB1B4C4BCAF9A7C2B0000003481B1B6915222040000000000000001030714121B15181F211D1F1948393C4D679DD5FBFCF8D9BB90795C2C53689ACCE1DFB58A4A241C2F315A8AB4C4A77E3D372C43859F5F7A4C32333562A4CDE0CBA17A61616C615D90C1DDD7C753689ACCE1DFB58A01FE085C070718807C8EB5D5C8A77C59536E97BCDBE49A56413E5282AADAC8874C71BCF0F9F2F0A548171C4D8EA29D97520A000A2157A3CBE5E2D6A43E0400123C6EA8C9D2D1B58C3E0D00133D719AA7928FA0BDB474280C124891C6D7CDB98B6153391C0400094093D1E3E8D5DAD6C583302661A0C4D4CEB8B0B7AC6D1B002067A7B6B9B0A79D8E360000003D8AB3BA8F55160000000000000000040F141A110E1B17201D141B17442C40455F96BFF8FFF7E2AE8C63543B4B6B99C7E2DDB1916123192B354F88C8CBA5754023414C818E4A7856312A385B9DC9DBCDA8794F5D585E6691C0E4DBBD4B6B99C7E2DDB19101FE095C070718906B85AFDEC7A680555361839FCCDA894B30365C7DACE0CB73496CBAF8FEF2E5A14B13153B8AA5AF9B551500011C579FD7F2E4D0A4430D0015396BADCED5CFC095330000084181A69F8C8DA4C3B16721070F4394C7CEC5AE7D634D442510000C4CA1D1E6DEDFE0D5BB762C20599CC9CFD2B0B5BFAB691703357FB1B9C2AEA99A7D340000073E7DAAB398552A000000000000000000040A1110131318232322210C4B34405277A8F0FCFFFADFC29874574D5177B0DCEAE6BE844E282029455E9ABECBB7734A3B3A4A85984D71523B2C4A6E78C9DACB9C7053555D5F5987BDD6D9C85177B0DCEAE6BE8401FE0A5C070718A0718AB3D6C09D7756576C8CA8CFDE91543D405D86B4DBC4835C6EBCFAFFF9CE97401618428EA9A7974B0F000C2467A3D8E1DBDAA9480C001C456FAAC7C8CCC88A430D0117407C9EA689889CB6A66D26071C529BC3CECBBD7E58432D1400000E5AA2DBE6EAD7D4D1BE7F342058A1B6C9C4B5B3B6A3631A03387BADBABBBBB29C82360000003F88A7AE94552206000000000000000002060C0F1213231F221C1B0F5B48414D79B5E9FFFFFFE5BA9774642A4D7AACD9EEDDB6815D2F2A333E6996C2CCAF7A41313646809854845D33263362A4C2DACB9B6F51565855598DBCD8D3BF4D7AACD9EEDDB68101FE0B5C070718B0788FAFCDB7996F51496183A8CDD78B4341496186ABCEBA7B5177BFF6FEF4DD9A43111F4898AFA69E501900072C61A2D7ECDFCD99451100194B7DACCDD8C9B6823C00001E4E809BA89C9498B49568250A16468FC5D1C9AC84533C301300001659ACD5E3EFDDDFDDBB602F2255A2CBDBCCB3B3B5A96114002778ACB0B9B4A79B853E0000084D90B3BB9B6023000000000000000008040814121314151B1B1A2219453D3C5976A4DCFCFFFFE3BF9B6C54515074A7D7ECE1B7814F1E25343B6398BBC8B577483F3D4A849E517454312C375E9ED4DDC799654656615A5C82BAE4CFC65074A7D7ECE1B78101FE0C5C070718C0798EBBD4BC9D7758526384A8C6C7884937496690BCCFBA724F77BBF8FFFFDB97381C1C4D8FB5AC934C11000C2F69AAD6DBDAD09D430E001D4A7BB3C7D4CDBE7C350200154C81A1A89998A3B2965C1D0D0F459ACBD2CCB27D4435260605001A5DABE0E7E5DADED0B76A2A275EA8D2D0D0B2BEB29D53120A3788B7B3C0B1ABA7852500000E4A94B4C09E5B1E000000000000000000050C180F10121B251E191D126152596985BFF9FFFFFFF5C3A1886261657AAFD8DED7B28E602B2B32456A98C9D0AF6D3C3839498596567A55322E4369AED4CFBC996751495850548FC4DFDBBF657AAFD8DED7B28E01FE0D5C070718D06F89BFE6D3AE724F4B63829BB7CA8C4A3A446993AFC6A76A517DC5F9FFF3E1993B1110559EADB09E540E000D275DA5D3DFD8D4A3470C0B21527DB2C3C8BDB17D2C0A001D4E83A8A7A6A1B1AA904D1400174786C4D8D8AB75413C22090008225EADDCE8E4D4D5D3B963202A6FABCECECBB3B9B79F590D03388FB6B6BDAEA19E86310000175299B3BB9D5D1B0200000000000000000009100B151C171B181D19124F39374B6DABE0FFFFFFE0AF867053535872AED1E9E0B67F4D221B303E6FA3CBC8AB6C353B414E7D94517D5E372D4476AACFD3BB8E5731475A5A569AC2DFD3C25872AED1E9E0B67F01FE0E5C070718E07793C6E6CEA966454C5D7794BDC1864C36385D86AFCAA8675C82C0F1FCF9D78138181F509CB4AC9B4D0D00092E71B6D0E1E2CEA7481301254F86A9C7CAC6BA863200001D5D8F98A8999AAAAA904C1D061A4C8DC3D7C9AD6B422E1A00000C2B71BBE1E6E3E3E2CBAB5C272766AAC8D6C5B4BEBE9B4F150C3784AAB7BCB5B2A68A3600001C5B90A8B38B5C200000000000000000000304101810191A1C15171F0F584B4C6286B8ECFFFFFFDFC0A07975616478ADD6E2DEAF7F492730333772A8D2CDB0775343334374945379563C3C4674ABD3CDBC895B35475D515C93C8D7CCB36478ADD6E2DEAF7F01FE0F5C070718F07891BBDBCFA4715347577A93C2C481413D49698CADC6A8655880C5F7FFF6CF882F0C1B59A0AEB99E50160011397AB2D6E0D9D0A53B0902235982BACBCAC6B67F2C0000236089A5A9AB9AA2A384440902124C8BD2DDC6A16A2F261A040007347AC8DFE4EFDBDACFAD5A262A6CB2CED0BFA9B4B29A4D0A0B4C9BB3B0B7AFB0A286370000135D9CB9BA8E5C26000000000000000000000107160C181A201B1B180D4E49535B79C8E3FFFFFDDBBE99826D54617AB7E0E5DAB77B4E2B1D374C77A8C9C9A1733D3E42547E824975663F3E466C9CCEC8B1905D434C5653528FC9DDC9B1617AB7E0E5DAB77B01FE105C07071800698EBFE6C8A36A4847587492ACAA71403A536D8BA8B5915D5689D6FFFCFEDB7C2808195290BCBC954C0F000F3A70AEDCE0D6D0A4380906285A93B1C1C5CFB96F230200306692A3A2A69E9EA081411005164E93D0DDC59E5D2D1C0C0000102E7BC5DFE0E9DCD0D2B35C273779B1CCCACBADB5C09C410D114792ADB2BCB8B0AC8A2E0000225E8FAEAE8F5B21000000000000000000050D08121510151E221B22135B404D6D89C2F3FFFFFFDBAD8A7A676B6576B1E4EED5A9854816172F4C75ACCDC5AC6D3C3D40507F9B50805F3D2B416CAECAD0B17F583B404B4F5A8FD2DAD7B86576B1E4EED5A98501FE115C07071810708CC9E3C39D694A5060688FB2B57045395773919BA48F595584D4FFFFF5DD821F121F54A2B6B9974108021A447EBAD0D3DCCC9E3C03002D5E97BFD4D4C7AA701B00002A6A959B9FA39FA6A28031110B20488ED4E1CEA15F2A100300020D3282C6EBECE7DAEAD5A1511F307FBDD5D8C1A9A4AE8E3A0519458FB7B8BEBBABAB7D2E000026679FADB5935C2900000000000000000000070D13120C1C22212A1A0A635E636F86BFF8FFFFFFE9AAA37B6F61768FC0DDE8DEAF764E222432517BB4D1CAA36142434A527A90437A653C384779AECBCEB67B483234484A5889D4E2D0AA768FC0DDE8DEAF7601FE125C070718207098C5DCC7976D4D4A617087A8B06E393955758F9FA6855B5483CDFFFBF7D1782C111F5AA2C8C297490F00153C7DC1D5DBD3CB973D0805285994B1CAC8CEB8761B00002B6E8E9D9FAAAAA5A1773310051B5D9FDBDAC190572A190400000F3492D6ECECEADFDBCA94511A3184BCCBCDBAA6AAAD85380B215099B6B2BAB2BAAE812B00002D71A4BDC496512000000000000000000004040E16101D1B1A1216191263585B7899C2FCFFFFFFF4BE96796C686C88C0E2EED5AA76471D242C5D8BA6D2C89762433F44517C8F4274663C344B7DB5D1D6B7804E2E344345629CC6DDCEB16C88C0E2EED5AA7601FE135C07071830689FC4E1C59C5B43505C6D89B0AA61383F598294A5A68453487FCBFFFFFACA6A1B081E6095BDB8924504021A448DBAE1D8DACA832A070E346397BDC4CCC9A462200005377697A7ADB4B0A89D6E2604041E549AD1D0B891562D0C000000133F92D6EFECE2DAD6CB9741213E80C0D2CDC4A4B0B18F360E1E5DA2ABAABBB2B8A5802800012E6D9AADB5985E250000000000000000000307101415191D181F201F0D67566287A4D0FEFFFFFED9B0A19173727498BADAEBDAA675471A1A445587B0CFBF995E3B4345567E9042705D3E2D4876B5D4CBAE693925293B3054A3D1E2C1A87498BADAEBDAA67501FE145C0707184074A2D8F2D2A9634B4A67778DB1B2614A485B7A989B96734B588BD5F9FFFAC96B260A235FA5C1C7984911091B4889C2DAD4D5BC902E010A3A73A4B8C4C2BFB3711B00063579999DADA2A5A395622F0F0824558BC3D0C18D4F210E000009164E9ED9E5E6E3D8D4CC924A1F3D86C0D3D5CEAFB7B07929091B61A9B8ADB1B5B6AE843000003B78A6B0B68A5A1A00000000000000000000040E0A111C171C1D121716534E5B7EA9D5FFFFFFF9D7B79B886C676D88BFE9EDD7AD763F1E1B365993C5D0C598613E3F3C4D80904A705B4B2C4380B7CFCEAB754523303538559ED0E2CAA96D88BFE9EDD7AD7601FE155C0707185089ADD8ECD0A575544D5A708BA8956241425D7D97A5956F4E5992D8FCFFFAC86725112B5EA6C4C09142100A1A5291C5D9D7CEB98532040C447B95C0C3BFBCB35E1800113B7D969BA8BEB4AD8E5F1902091F5C9CD6D3B482491E090000061A539EDCF6E9EFD3D2CA913C163E83B5CCD7C8ABA9AA712B0B2E6CA8AEA6B6BCB9B07E2700124B7CA6AFB8915317000000000000000000000407120B12141B211C240E57505B7591CDF6FFFFFDCBAD8D7B74526585B9DFE7C9A06F391A2B3B598EC2C7B18F593846364A748A3D7764402F4583C5D1CAAD6C3E1F1E38435EA5D0DEC5A96585B9DFE7C9A06F01FE165C070718606EA1CFE0C08E5F404B62738AA0945E3D4464829B8F876B50598ADDFFF5F5BB5D210F2D5CA4B4C095411A0F24599EC6D4CCC0AF7B310908437EA9C4C7CABBA2641500174C8AA09A9CACB0A5854D230004265AA7D2E0C07A491D0A0000040F52B6E9FBE9E7D8DCC18E381E3C8FC1D1CEC3B3ADA66F2E162D64A2AEA3BBBDB7A9782600034C8AAFA9B38A4414000000000000000000070B060D1415141714151A135E546780AEDEFFFFFFFCDBA5909679657590B9E0E4CDA873432122305A8DB1C9BC9A6346394F517391427E64472B4988BACDCAA2663E262A33315B98D7DDCCAA7590B9E0E4CDA87301FE175C0707187077A2D2E9CD9F693C46596E81988953404C688990988861415A9CDDFFFFEABF5F1F062769A8BAC192440F082D5B99CDE3D1CDB47420000C477CAFBBC1C9C7A9600E00084A87A89EAAB3ADAA7E480E09072A659FD1DDB6763919070000081C5DA9E9F4EEEFD8D5AE6E352741A0BDD7C7B498ABAD7838163072A7A79FB2B8BFA8732A00105C84A4B3AB803A1300000000000000000203040A09101315181B1B21145765767D9ADBFFFFFFFBCFA5937A6F646C95C2D8DEC39E723E1915356596B8C6B790614441444671903E79603F375273BFDCCFA6693C1922334366B1D7DCC2A76C95C2D8DEC39E7201FE185C0707188077A4D0E9C78F593D4A5E6E8C9E885C3E436B919A947E5C435596E3FCFFF1B15B1A0B2965A7C0BD9042090B2C61ABD0D4CDC3B26D2105174D8CA7BEC6BCB0A45312000F498DA4A7ABBBB0997A471305062E659CCFE7BA79310D0400000B256ABBEEFCEFEDDAD4B9712F174DA3C2D0C5B59FA6A86A26162F6CABACACB5BABFAF7115001F6597A4ADAC763E17000000000000000000000413120F1618191B1A15105A556A83AEDFFFFFFFFFD2B59F85746C6A8BC1D7D4CDA06639151738699DB3CAB484573C3C5D56748A40786047335688C3CEBAA06B381A1D314363AFC9DEC39B6A8BC1D7D4CDA06601FE195C0707189078A9D8E8CC94513C47476C7788794D41547395A98D665347569EE8FFFFFAB45417102D6A9BC2C08A4016093470AEC6D2C6B5A97125010B4388AFBFC7CAC2AB540700155E98A49CABBBBFA477380A010B2E5D98D0D4B76F360F0100000D2864BEF1F8EFE9DCD1AF682B215295BED0CBC3A8A5A46624113D80ADAB95B5BDB5AE7223002D70A3A2A8AE7A441700000000000000000004050A0B0E1A181B1F171E13676A7387B1E6FFFFFFF8D3B18F8072696A96CFE1E0BA8E6E3B1A1B526E78B6C7B6885A44414B56788A427D653F2B5A92BFCFBF965929141F2D476EB3DEE0C2996A96CFE1E0BA8E6E01FE1A5C070718A077B4DFECCD95523A455370808A7243384D7A94A58A624C3C5AA4F0FFFFFBB64D1512246A9AB8B18C3E07133070AFCEDCDAC7A5631C09164C86ADB9C8C6BAAD5A1801155190A0ACA8B7C3AA733407000C316FA3CCD2B57A3610000000042472CBEBF7F1E4CDCEAB651F184EA5C9D9D8C8A8A3A169220C3B85ACAC98B5BDBEA36B1C052D7AA3A4B09C794A12000000000000000000000A07090E0D141D1C1A1D186B667997B8E1FFFFFFF8CDAA868B7267758CB9DCBFB2705D321E1F4073A4B9C3B6885638464A546D8C417C684A3B5499CECCCA975A2C0A17344A6AAEDFDEB69A758CB9DCBFB2705D01FE1B5C070718B075A8DFECD1985D35455B6378856A48344D7B9FA28B5F484159ADE5FFFFF7A94711123468A2C0BA89360309337DB9DFD4C6B99E5724081A558CB8C0C7C8C5A44B08001E5C8EA09FAFB4B8AB7B3606000C4071AADBD0B36F3206000000052A78CAF2F2EBDDCBC3AE62231E4EA2C2CBC8BEAFA69A561A164783B0A696BCC1BCAB6916002C81B0A8ADAC804F1D0000000000000000000000090B1215141B1A170E086E687D8EB4EFFFFFFFF8CFA083807672767DC1DCDDC394662C1D284A80ABC3C5AE8A50384942586C7E357B6C49456696C8D2BD934D2A1C1C304775B4D9E2C89B767DC1DCDDC3946601FE1C5C070718C06F9FCCDAC7824A314F5B697C7F643B3F4979ABA07D5734325DAEE7FFFFE6A3420C0B3079ACCEBF8131111A397CBBD7CEBDB2934712091C62A8BBBEC8C4B79F4C10001A65A5AFADACB4B8A8792F0000124573A5D8C9B0702D0200000004347BC2EAFBF2ECD7C191581D245298C7D1C1BDA5A9A0591C174F81AFAC9BB6BBAAA6621A0A3F8EABA7A7A789471800000000000000000000010C13070B131E1C191D16707B888FB8EDFFFFFFE7C993826774727198C4DDD9BF905C301B1D4B7CACCBC5AC8355464A53556E8435847054385F9CC5CCBB93551F01122B4683C0FFEABF8C7198C4DDD9BF905C01FE1D5C070718D068A7DEEDCD8759444E5C6F7E80583C3C5D85A8A385613F355FAEEEFFFFF19D440D11356BAAC2C08137080D397BC6DDCDC7B38E4B0C031B679EB2BCC4C8B9924300022E70A0BAB0AFBEB89C5C210000184185B0D6CCA260270B010000123D89D2F3FCEDE2C8BC95520D1558A2C8CDC9BFADB18B55231B5897B8AAA3B5BEC09C520902398EA4AFADA972482100000000000000000005010B0A17100C1F1A151F0D6776809DBCE5FFFFFFE8CEC089886B5F709DC4DCDAB988592910174173A6C1CDB1865543424E516C823079764B4465AACAC9B485441203161D4765C3E1DBB98B709DC4DCDAB9885901FE1E5C070718E07BB4E0E7C88D563A4E5A73838163313E5F86B4A7784C353463B2EEFFFFEC9C3F0F143F78A9B8B67E30071A3F8CCCE6E0CEA5723A09002270AAB0ACB5BCB898390C002979AAB7B0B8C2C5A2611D0000134C86B5CBCAA3612A09000000073588D4F7F0E8EBC9BB8743182A60ADBFD4CFBDA09F8C430E1D649EB7B09AA5B2B599530A085396B4ADB3AE794B18000000000000000000010A090A101B171213171F0E777388B1CFDDFFFFFFF1CFA58C876B717BA6C8DEDEBF905F2F1E244C7BB0C0CEB084543E504D526887387F725245689DC8C9B7865D1E000525587CC8E1D9B38A7BA6C8DEDEBF905F01FE1F5C070718F072B2D5E8C47C4537486271766B55363F6492B2A4723D2E3969AFECF6FFE7963A0210427AB0C0B678361014478DCEDBD8B398763B0F021D63A4B7B9BDC0B495450B093179A8ABA8B0C2BA9C652100011C5080B3CEC89A6024000000000F3D8FD5EEF3E9DFCCB68340181E61AFC9DBCCBDB1A18A50172B5CA6BFA4A6B4BDB89A490B05558FA8A2ABA882492200000000000000000000040D140A1309181116240E968B5EA1D4F8FFFFFFF6CFA29886706F84ABCEE1DBB77F58371B1D477EAFD0C8A47F5A47404E525A8E3778775E526EB9D2AAA9784618080B2C5481BAE4D6B18684ABCEE1DBB77F5801FE205C0707180077B0DBE5BF7E4F394F68717876463B37619BC2B17E3D282F67C1EDFDFFE38A340C1D4783ACC6BA83320C13468ECFD2D6BA936C2D0805266FA7BAB8BBBBAA7E3C06033381AEB6B3BDB9B699601C00001E5889BFCDCDA46626000000001E4795DDF3F1EEE1CDB07D3D111D60B4C7D2CDC2B0A579420C1F6AA9C9ABA1AEBABD9D4C0D0A4E9EB0A6ABB4864C1D000000000000000000000B130E0A0A1812162022127E8195ADDFFFFFFFFFEEB3ADA3817467759ED6E0DAB87C47211B214B7EABC7BEA7885C49547B876680006A74534E78B0CECAAF7F3A0C060A2A6296C7DDD7A474759ED6E0DAB87C4701FE215C070718107BB4E0F3CE864B3D5966727C6D462F3A5F96BBB074442E2E67BCF6FAFAE3893303144986B0B5AD76280D144F9FDCE9D4B6995B210000286FAEBFB3BBCDAC782A03043A89B0B9B8AFB3B08E4E140000265E99BCD3D0A85D1E00000000154C9CDEF4EDE9DCC3A874320E206CAFC6D6CCBFA9A977300E2267AEBFA9A7BBB8BE8F420C1057A5ACAC9DA08254160000000000000000000005070E0F19181F1D1814086E7E9FB4DEFFFFFFFFDBC3A3986F60626BA3D0DAD7B288512521274A7DA8C3B9AA725A4D4F6E807F8331787B615A81A6C6C0AD783A0E000821578DCFDCD39B776BA3D0DAD7B2885101FE225C0707182071A8E5F5D27E4B475A6A7B7A654624325EA2BCA36C3A1C356BC1F5FFFADA7C280618438AADBCB96F27021C5394DADFD1B586592302062E73B4C2B9B6BAA7782F00093D8CB5B8ADB7BDB99B521400032C6795BCD2C0A25D1E000000001451B5ECF4F0E6ECBF9A621F061F71B2C3D9CFC8A5A2722E1C2E78B1B7ABA1B6BBB98B3A091563A3B4A4A3A87D4814000000000000000003000801070E121118181D180C7F839AB2EDFFFFFFFFF5BBA29381736B84A4D9DDD1A56E4E3B25275181AFC9BB9E76564558757C77883075745A5884B7C3C5A37A3900000B285A99D0D6CBA06A84A4D9DDD1A56E4E01FE235C0707183076AEDCE7CD73434561788C83603E263768A2C3AA6B371D3267C7F4FFF8D27023001B5194BECDB5722A0D1D56ABD9E2D3AB82541500002C75AFC3BFC4CBB2762E000A4895BDB9B9BBB9A894480800023272A5AFD0C4A86822000000001C4FA7E2EFEEF1EBCC925D28082D70B0C9CBCEBBA895662D0D2A79B3CDB6A9BEB3B28938091A66ACBBB2AEA9784518000000000000000000030902040C090F1915111C147A788EC0E8FFFFFFFFE4CAA66D7E6F647CAADBE1CEAB7C4D382525437CABD0C8A3805A4D53717B777B276C72645E7FADC3C1A7742F110008365FA0DAE4CE986B7CAADBE1CEAB7C4D01FE245C0707184073BEE8EFCB81513F5C767E755732213472B2C8AC5D2E202F6BBBE7FFFFD76F2502135499BFCEAA6821081960AFDEDACFB478470B00003174B8C8C3C9C7A9711F00144894BBC5BBBAB9B38D48110001346996BECEC4A15D27000000001F4BA0EBEFF1EADCB0874819082F79B1D2DCD9C6B39C61270C3A83B7BAA9A4BEBCB289400A1874B3B8A7A4A47D4E1B00000000000000000006080B090D0D12141A131B0BA5C0D3EDFFFFFFFFFFFFEEC9B5A4878393BEE6E7DBBC8B5E3D332F5B81B9D3C8A781634F637B777A8626737262688BB8C8B9986727050316376CA5D4DBC4935693BEE6E7DBBC8B5E01FE255C070718507EABDDECD37F4B4270827F6F5438274174C1CFA960251A3068C3F9FEFFCC711E051D5C9DC3C1AB65290F2665AED5E6CFB086470C00002C77B8CAC4CDC6A15B1A001753A0B6CAB6BEB7A98A460B00023B769FB9CEBFA45D19000000001B59AFEAF4FFEADBAE7B450D08307DC0D3D1C8C5A48D4E1B103A8EBFC9B4B0BBBCBD7F3A041D78B2ADABB1B086542000000000000000000002050C02110D0B1820191F14808999ADE5FFFFFFFFE6CDB2A4846C657DB2DBDDCDB1824B312F314F86B0CAC29F7D5B53647E81707C216F76656F90B8BDB89267200A000D4266A2D3DEC2875A7DB2DBDDCDB1824B01FE265C0707186080AFCFE4CC7B4138657E8776502C223E83B8CAAE6926162A70C5EDFFFAC6622503165B9DC4C2AA6B1C0A2970B7E1EED2B371380700012F82BBC6C1C4C19D621E0412569FC2C4B4B4C5B3974C0800083C76A4B9C6B69B5D1C000000001A64BDEDEFF7E1D4A66D330E003482C3D7DBC9CDA98D5924203F84BAC0A7ADC0CBAD7723082686B7BCA8B0A88053190000000000000000000003050B0C0D101B18171810798E94B6E7FFFFFFFFE9C2A8947B656C88AFD5E2D1A975593F352B4D7DA7C6B89473605B637E7D7A881E6C74636C91C4CABDA25B280200083463A1D7D5BA815188AFD5E2D1A9755901FE275C070718707BA3D3ECCA70464970938E76552D1D4A7AC1CBA4622D21325FBCE1FFF7C1551A092E65A2CFB9A85E21103071B4D0E0D5B1702A0000032878BDC7C3C8BDA05F10011655A3C5C8BDBBC4AC8D3E0000004083ACB3BAB9935D1A010000001E5BBDE7F2F1E5DD9E662509033B85BDD0D4D9CCAE814912154C97CBCAB6B9C0B6A76F21062F89B9B8A7A3AC8B581B0000000000000000000000050D131618131416150D92928BB5FAFFFFFFFFE5BBADA58B71708FC2E2DCC7A773543C30264C89B7C1BB9D7D66615C747B71791E63695F71A0BCCEBA9355160000113976B8DBD7B97E4C8FC2E2DCC7A7735401FE285C0707188077A5DCEECA7B414D809387743F29254C89C5C5A1621C163767BAF3FFEEB34D12021D5CA9C9C6AA5F22102868BEDDE6D5B36C2E000000368CCCE0CFC7BE9A4A12001B63A3C2D4B6B8B1A57A37000007468BADB2C3B9926218000000002E60BFEDECEFE9D9A05E250003318CC9DAE0DFCCB18A3914144F9CC6C7B5BCC2BAA85C15042889BBB3A69FA98E5D1B0000000000000000000205090F0E09191F1D1E1E1382818EB7F1FFFFFFFFE2BFAD8D7F6A577FBAE3DEC29A7252383B345780AFC6C0937B6561697A7F75791B626C60749DC9E1BD92551B020005357CB9DBDCAF743F7FBAE3DEC29A725201FE295C070718907DAEE0EFC8784C558B9EA17B4F272A4083CBCEA4572B182F77C2FAFEFDC35310012576B3C7CDB15C1909307BC3E4EAD0AC6E1F00000A3D8BBFD0CCC5C59D4C0E001760A3BDC3B3A9B5A5792800000C4B96B0B2C4C0A06721040000002367B9E1EFF1E7D8994D1700053890C3DEE9DFD1AF7536061856A0C8D4BEBDC6C0A4641603358FB9AFAAA5AB9F602300000000000000000000000E13040D0A150F18161180829DC7FDFFFFFFFFF0CDAFA188726690BEDEE1C9A3754B4B333C588AB3D0BD8479615E637E7D7C7E19696A728B9DBBCFB78F53190300093B7FB6DDD5AB6C4B90BEDEE1C9A3754B01FE2A5C070718A07EA0D3E5CC7E454D8EACA57D492A1F4C95C9DA9F541E182A75CAEEFAEEA44413062474AABFC3A4591613427BBCDBECD6B86B220000063F88C5CBD5C7C6933F0400156DB4C6CBBFB1B2A1711E0000024E96ACA6B1ABA86522000000002B7DCDEEEEECE7D89A4A160301408EC3D6D6D7CEAF7D320C1554A3CAC9BFBDCDB8A25B190C448EB4AFA7A9A58B681B0000000000000000000004080A1110161216171405868B99BFF0FFFFFFFFE8C5A29A7E747A8FBCDFDCC69982536941365285B9C8AC97836D6A5F70766B741653555879A6CCC8AF8B551A00000F438FC6E5D6B3693E8FBCDFDCC699825301FE2B5C070718B07BA7CDE3C777474A84A7A77E4221274F99C6C490531E153577CDEAFDF1B2450805336FB3CBC6A74713114684C6EDE5D0BA6C160000093A90CFD6D8C9BD8E450000165AA7C0CCB9B1B9A7772500000A5894B2B3B8AFA55E1F000000002B7AD2F4EDE6E9CC85380700084496C7D9DBD9CCB17428011860B0C8D4BEBCBCBE974D1A104C96B5A9A299AC905A1C0000000000000000000005070A0A1715161916190AA09E9ECAF7FFFFFFFFF0C7BAA081697CA0CFE3E5C59B6C5650453C5790B7C3B1917B7D68678277637120705D5281ACC1BDAA823C090000124B8BC5E2D09F6F48A0CFE3E5C59B6C5601FE2C5C070718C070A6CDEEBC734B5C8FADA7803B2B254C89BDCF9E5220192C7FC8F7EDE3A04010062F71BCD0C79B4615164D96C9E5E1D2BA67190000034799CCDED3D3BC8F3500001F5EACB8C6B7AEAF9F6C20000009509BABA8B5B1A061290000000C357EC5EAF5ECDDCC89310A000D4693CADBE3D1CEAE651602215FAFCBD1CECEC5B596450D09459CBBB79EABB0AA783000000000000000000002050A090809100D16131F12828A95BEFFFFFFFFFFDED1B8A3877E7B83D2FFE3CE9F785D5A48385185B4CBBE9875655D6C837D6C680D4A5B647EABCBCAA884431C0800154D8DCCE1D6A1764183D2FFE3CE9F785D01FE2D5C070718D0789DCAEBC3744A5A9FB6AB7C3B1D285493C8C7954B1516317DCCF2EEE6943A08052977B8D9C79646170F4290D2E7E3DAAF611900000A42A3CCD5D3C1B7843300001F6EA5B9C7BEBBADA56A1F00001456A1B4A9A4AB9D6626000000093C8CD0F1EBF1E8CF7D2C0000144E9AE4E0DACBC8A9641D07296BAFCFD3CECBC8BD933F03013F93BAA6929CB1996D1F000000000000000000000A0A0806030A0F1D1F1B0C899281BBF9FFFFFFFFF0D0AD9D7D6C63A2CBE2DCBF986E59573F345A90B4C7BC8A7C7469697D70675E1256555F7BABCEC8B17F461508021C5099D0DED3A65F49A2CBE2DCBF986E5901FE2E5C070718E075A9D8F8BF774E65B2C4B68443292C5F9FCBC79A4C1F174081C1E8ECE099321515307CC1D2C3964F221F4A98D3E7E6D3B2591000000A46A5CAD6DACCBE873000001F65A7BFCDB7B8AE93611800000D5EA2B4A8ABB9A16127000000073A8AD2E7E9E4DCCF762900001B57A5D3DBE0DFD4AB5C15002475AFC7C9C9C4CABC8A4107094B96C7A68992B2A976210000000000000000000003110B0C0B10150C0C19068A8688D3FFFFFFFFFFE5C0A79D7C6B759FD0EFE1BB966A555850415D82B8BEC391726C6A657D756364114E59618AADCDB4A182440F0208175698CFE4C99B5F4A9FD0EFE1BB966A5501FE2F5C070718F071A0DDE1B56B4D6DA6C8B5773D2224549CC1CC8F4822214183C7E3EFE59B370C043175BFCECE9D44101B4D9CCDD6E1E1BC5D080000064598CADED6CDB88A2D00002B74B2BEC6B4B9B599591700001353A0B49BAAADB06928000000023E8DD9EEF2E2DCD26D210000165EA8D0E3E7DECDA35611062272B0CAD0C7D2C4B386400A0F56A5BBA78C90B09F711F00000000000000000000000B050913131C1B151905898891B8FFFFFFFFFFEFD5B5937E6F72A8CBF5DEC29A626460493D5C8CBCC2B6897B74687079786C651246465F90BDD6C3A4783B0D07141D62ACD4D8CA9E5B47A8CBF5DEC29A6264 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 61440 61440 0 01FE305C070718007CA5DFEAC2744C73B2CCC47D42292D63A8BDCA924A181D458ACCEDEBEA99340F10347BB7CBC4943E0C215DACCFE4E8DAC3651B00000B469BD2D8D7C6B57F260000276FAAC7D7B9A9AA90551400000D6195A99EAAAFA97722000000155099D4EFF1F4E1C7792300002161A5D4DBE6CFC1994909002D72B9CDCDCECECEB382340A0F549BA7A282A0B2A16C1D00000000000000000004080A0E0F0E0D181914190B958C91C5FFFFFFFFFFE6C7B99F8C6B7AB0E2F0E7C3986E5E5A483C53A0BCC6A985756F727378715A59093D405D8FBDCEC1A974340D040B236FADD4E7C2986451B0E2F0E7C3986E5E01FE315C0707181082ABDAE1B16E5574BDCAC28943323C68B4CCB88943171D4885D4E9F3E4973A0E0B3D82BED9CE8F4119235DAED1DDDDCFB35D0500001156A4D4D9D2C4B26F2000002676AECCCEB9BCAB82450200000F5C9FAC9EAFB7B26E21000000175597C9ECEEF1ECCA721A00001B68B0DDE2D8D8CB994600002A80B1C8D0D1C4C6B46E2A07145DA1C0A1849FA8A76E1700000000000000000000090304050C0B15181D1B09747D7DBBFFFFFFFFF6D6BEA88B766C83AEDAF4DFC097726762523C5093B6BAA885716E6C717B70625E0D3B3D588EBBCECEA375370D0B0B2A6DADD6E6C09E6356AEDAF4DFC097726701FE325C070718207CA0CEE5AE644E6DBAE1C57A432B3473A9BFC489451E22468FCEEFEAE78E2E040A377EBCCECA8538131E63BAD3E0E0DCBB640D00000F53A2C7CED2C5B5761C00001B71AFC0CDC1B7B58E540B0000166398A7A0A8BCAD7026000000164C9AD2EAF3EADEC56F1C00002564AFD9DDCFD0C99C460700357ABACECEC9CFCEB87328001766A6BA98819DAFA77919000000000000000000000304070E0A11171917190E889184B9FDFFFFFFF8D9C4A68E82718BB6D4E5D8C18F6A5C62533E567FB4BCAA8A736F7C747D71615C113E5A6499BED0C1A16D2D050F092B70B7D6E8C98F564CB6D4E5D8C18F6A5C01FE335C070718306EA6D4D6A363527CB3DBC37F38263476B9C8C3813A17224999C9E6E2D791300D06387DBDD3C99036102063A6D0DDD7D9B65D1200000D56A6CDCCCDBCAF6E1900002D72AFC6C1BEBCB08B440100001465A0AAA6ADB2B4722B04000013449EDCEDE7E6E1C869180000266EBBE2D9DCD4BD993D06003082C2D1CEC8C9B9A7671E000E62A6BF9F8194A1A67022000000000000010000000509060F1317101615160C7A818BC2FFFFFFFFFAD9C6A795727188B2DAE6CFB3976F655E493F5D8FBCC1AA8D8470656977715A4D07363E6298B7D1DBA46A31040B1B2B7BB4D4E6C4906057B2DAE6CFB3976F6501FE345C07071840809FDCE1A9656182CAE2CA7D3F1F427DBBD3BE83431C265394C2E3E6E1831E00023580BCD8D8823210246DB0D6E1E1D8B4560900001864A9CBCBCFC2BB6B1700002F73B5CBBEA9AFB08A430600001C6699A99CACBBB46E220000002256A3DBEBE9F1E5B7600A00042672C5E6E6DECFCC994104002E83BCC3C5CECABFAB642700135DA9B697838CAAB1731F00000000000000000000090908090B14171B1615078B8B8CC8FFFFFFFFF8DCCBBC8D7D7590C7DFE9D9BA9F75676C5A49588DB0BEA880796C686B71715B4A102935609CB8CDAC8964280915133F7CC1E5EDC3906759C7DFE9D9BA9F756701FE355C070718507298C3CB965C5576C7D8CA732F1E3677BFD3BC7831162A5E9EC9E1EBDC802100013582BDCFC679300D2D71B9D1D9E5D0BE560B00001B61AFC4D4D3BFB5712100002283AAC0C5B0ACAF803A0000001460A7ACA8ABB9B77A2E0000002059A9CFEBE6E6DDC0651300002F83BCE1DFDAD2D1972B00003B93BBC3BDC6C2BF9F611F00106DAAB5A08694A9B2711200000000000000000000040201010B0D1514201A11948FA5DDFFFFFFFFF8D8BEB4A07E8797CEEEFCD9BC97747B6D4E40588CB4BDAD87767877737A7451460328305F9AC4D9C092642B01131C4685BCD9E2C289574FCEEEFCD9BC97747B01FE365C07071860699ED6CC915F517FBEE6C8873A293B84CACBC07732172B5CABDCECE9C87E210A0F3482BCD3B67626123171B6DBE2DCD9B45F040000145DA9C3CCD2C0A8681100003C82BBC8C1BBB1A873360000002768A4AEA4B2B2B877220200001E67AAD4E3EDE6E2BB600C00042B79C3E1DBD4CEC0882A00002E85B7CAD1CBC4BB9D5B1F001A6EB2B4938891ACB47E18000000000000000000000E0805091214141B161C0C7C8695DAFFFFFFFFFAD5B4A7937E9DA0CAE0F2D8B599756E61473D4B91B4C0A18472757579806F4D4E022A346998C2CDBB92582F1405193F84C2DCDBC38D6856CAE0F2D8B599756E01FE375C0707187072A4CDC48D5B5F8ECEE0D087372C5094CFDCBB853C1A3660A2CEDCE5D8751D01093883BCD8CA7F32153478B5D7DEDCDAB6560300002269B1D7C9C7BC9D570D00003385B5BCCBB5B0977B36030000226096A5A7B8BEB273260700001F65ADDAF0EEE9DCBA530F0005357EBADFD6D1D2C47E2200093B96CAD1C4C4B5BD955114001D75B0C1B192A1A4A36C13000000000000000000000006050010110E1D1A25068A90A5E2FFFFFFFFF3D0BCAA928989A0D6E9E8D5B59675756A4B345494B9B99E7D74707F74726A51440A29366CAAD2CDC1925825020A123C8CC4DFDBBA8C5A5DD6E9E8D5B596757501FE385C07071880699BCCC8815D5D91E1F1D573362D4990CDD6C87C301E2C5AAAD5E0D9C9751E0A053F90C2C9BB6D2918387DC5DFE4DDCEB4560C0000236AA4BCCDC3C8AD610D0001478FC0BCC6B5B1A2742A000000235AA4B7B2C4B1B06B24000002195CADDCF1E5DBD6BC5B0B000B428FC7DCDCD7D0BD7E2E00024B93B6C1B9BCBDBB954D2006257EB3BFABA2A1A8A76E1100000000000000000000000304060B15111515170F7B8CA3D4FFFFFFFFE7CDB3AA908B87A3D3E0E5DABD9A777166503A578DBBB69E7E75717A716A5D4C44092D3866A5C8D3B9985E2605040F3A95CCE1DCBC925A45D3E0E5DABD9A777101FE395C070718907799BBBA81515592D7ECCF7A30204DA2D4E9CB7C36152867A6D9DCE5CF741E020E3C86C5DDBA7727133186C0DCD7D7CDAA4E0000002475A8CBC6CFC3A8681600003C8FB3B7BAAFAE9C71240000002159A3B2ABB5CAA86B1C0000032A76C1D9E4E0E3CEAB520500093D93CFE2DFD9D6C17E2400094F96C0CACBC6C3B8884611011E78B1B4ACA499A5A96C0E0000000000000000000000080201080A12110D110A8189A6DCFFFFFFFFF7C6B4AB968798ADDCEDE9DCB7A48277664D2E4486BAB9A282717278766F6E4B20001B286AA7C8D2BE8F5731040F1D479AD1D8D9B8875448DCEDE9DCB7A4827701FE3A5C070718A0779DCCCA8D5D73ABE2F6D9893F314A99DDEBC06F23163072B4D9EAE3C96812000D3E97C0D3BC6629143A7CC3D7E1E0C8A84E0A00002274B9C7C4C1C1A45712040A4188BEC3BCB9AF9D6B1E0000002064A7B8AEBEB9AC5B1702000B3876B0DFEBE5E0D2AC4B0800125098C3D9D3CFCDC07D1D00004099C5D3C7CDCCC3904B2105206FABBAADAD99A5A2600900000000000000000000000001060D0A10141B1608868AA3E9FFFFFFFFEEB3B19D908897B9E2E6F0D9C0A1847E64452D4784B3BA9F797570766D74563B340E1C2E6DABD7D0A884522200121C55A3CAE3D1BC8C564FE2E6F0D9C0A1847E01FE3B5C070718B0729CC5C382616099DEF3DB8043314CA8DBCFBC742A122C71B6DCE4E1C9771C000E3C8BC0D6B56028194788BBD3E1D1BDA045040000308BB7BFCBCCC39E4F0A00004B94B8B8BEC1AE9A601D0000002364A7BBB2CECBB6672601000B2D79BDE4EBDCD7D2A34D06001659B1D3D9D6CDC5B566120004539EBAC8BFB8B8B288501F022675A0BAB8AA97A2975E040000000000000000000000000207060514181517098691AFE9FFFFFFFFE5C4B79E9396A0BCD7EBE8CEB69D8A76563E395395AAB7967C68736C787060402C0018316AB2DDCBAA855627100C1357ABD4DDE1BA784D4BD7EBE8CEB69D8A7601FE3C5C070718C07C9DC3B37E5E6C9CE5EBD87B342D5EA5E4E9C86F31223D71B0D9E5E7C36A1D00114A90BCC6B46A271C4285CCDAD7D9BF8B3C0000002C79B7C5CDC6CD9D510200105099C0B9B9BAB19857180000002A6CA2B9C0D0CDA96321000007277CC2DFDFE5DDD4A9480000206AB1CFD8CED8D2BB71140004549BB6BFBCC1C2C18A5020062981ABB9BAAE9EA89F5C0D0000000000000000000000020202060D1B12160F008089AFF4FFFFFFFFE9B6B19E938F94C5E6F4DEC4AA9B8E7962473A5A84ABB4937E6F62636F7060453600202F75B6CFCBAF854F1C000D1456AFE4E5CCA8774D45E6F4DEC4AA9B8E7901FE3D5C070718D06E93BDAD766170AFE3FFD07D443A5AA9E0E8C5722C1D3783BBD0E0DFBA6118061C5D9BC5C8AF571F11408CBBD5D5CBB989330100004086BAC1C6CABFA24F0800145498BCC2AFB6AA975A13000000226EA6C0BCC2C3A559120000083780C6E2E2E0E2D4A64602002167B7D2DBD0CFCEBB631200104D9DBBBCB5C0BCBB8D582905307CB3C0B8B1A9A89354000000000000000000000100000106090C13131417038788AAFFFFFFFFFFE4C6B49B8C9E96C3E7EEE4C4AC9D927D633E395292B3B490666B706E7C6F5841230E1D3B78B1CEC29C7A461404000B59B0DDECD0A7785046E7EEE4C4AC9D927D01FE3E5C070718E0709CBCAD73556CACEDEECD7C363369B6EAF8C26C341E3D8AD0DADADEC15F11001651A2CED5B65B1F1E4B9BCEDBD1CCB2863B0300083E88C3BDBABEB79643080019569CB7A9B2B7A99B4E100000002B6DB3D0CCCAC7AB56130000153C81C0D8EEDBD6CCA03F00001D76C3D9DDDDCEC5B85A0200035DA8C5C1ADBABEB17D4E1A062D79ADC5B8B4A8AC964906000000000000000000000000000008080C15151E0A8D8DAFFCFFFFFFFFE4B5A6A19598A6CDE6EBE6BBA99F9B7D5D3A2C488EA7B991775E517872695838230E21377DBDD5C49269431D02080F57A6D7EBE1A96E4639E6EBE6BBA99F9B7D01FE3F5C070718F07797BFB77F6177B1F2FBD17A403C5BB6E7ECBE653416418AB5D9E3DBBE601004115391BACDA55C1D244F9BC4D7D6C5AD833203000A509FBEC1C8CCC18A43060015589DC1A9B1BDB6954D0B0000022E70AAC0CDD0C3A35513000114378AC1D2ECE6D8CB983500002C77BCD5D4D6DDCEB25306000A63A7C9BCAAB8ACB1835C25113480A9B2B7ACA59F964C000000000000000000000000000002050E0A17151506798BB7EFFFFFFFF6CDB6A1857E97A9C1DDD8D5C6B6A593766141204E8BB7AA92715A5E6E706453322000214886BEC8BA8F64381E0806135FAEDCE9D3A3694140DDD8D5C6B6A5937601FE405C070718007493A89A715872B6E4F6CA683B3E66BEE7E7B95A271C3F8DCEE2DED9C0731C131C599DC8D0AF591D18559ACBD8DBCCAB6F3101001047A0BCB6BEC0BF8B3900001666ACBCAFAEB0A3904C080000073776ABC3C9D3BF944D11000116408CC7DEE9E0DDC48C2C05002D86C2D6CED1D8CAB15C0800095CA5BDB5AABABBB8865E2C133081AEB0BABEACA99740000000000000000000000000010A000D06120E120F0A7F8CBFF2FFFFFFF6C4AB97848A93AEC5E2E6D6C5B7A88F82714E2E4F8AB4AE9063555D68786650301E0A1B3685BAD9C6956B3C1C00001B5EB8D9E2CDA26A4431E2E6D6C5B7A88F8201FE415C07071810628C9D8967567CB1EDFAC76D3F3C68B2EFF8BC5C221B4B8BD5DCDCDBBA5E100C20579EBDCAAA58202F5D9AC3D2C7BFA3722B00001056A7C2BEC6CBBB812D0000225FA0C8AAAAB2A58D450F000005327BB2CDCFD2C4A44A090000164786D1DFE2E3D9C9933A00043982C1D9DDD8CDC2AA500A00125BA7C0C0B7C6C5B5815A26082C88B0B7B0ADA99B80380000000000000800000000000004050D0C151111110A808FB3F7FFFFFFF6CCB08B7B819AB1C9D4DBD5B9B19D8B7C6940314C90A7A0825C55536F6A584E321E141D3D92CCD4CB7C5F371400001766AFE4E4D3A4694135D4DBD5B9B19D8B7C01FE425C070718207688A88D696580C4FBFBC871374071C0F3F3B86832225792DBE1E9DEBF61120C1F5EABC5D2AB5314245B9CD0D6CFBEA6651D00001956ADCBB8C6C9B98530000016639FCAAAA9AC9F8F41000000093377A5CCDCCFBD9753140000203C8CC5E7ECE3DCC6872E020D3F94C9D7E1D8C7C2A34B00001868A3C3B8B4C3B5B380632F183D7EA6B7B2ADA7A08A3F0000000000110A0000000000000001000A0F160C0D008493B6EEFFFFFFE3B39F8D87899BBED5DEDDD4B2A89D88705B391F4486AAA0835E54546A695D492B1A191C4895C0CFC1895B331A0000156EBDD7E9CD9C5F3C38DEDDD4B2A89D887001FE435C070718307C8EB2916D678BCEF0FACB6D43446EBBF8FCC4673B2D4786C6D7DFE1C462180D205DA9C4C6A54B213363A0CCD3D6BF9E691D00001C63B5D3BDC4BDAD6A2200002670A9B6A6A3B4A78341060000124170ABD4DEDAB38C460500091D4889BFD7EBEAD7C489240004499DD0DCD9D2CACAA13D00001968ACC2B6A8B3C6B587693012418AA9B9B8B7AAA07A34000000000B0E000000000000000208060A0D120B17017284ABE6FFFFF5DBB19884807A9CB9CDE2D0CBB5ABA28D77663E1E4E82A2A571504052666C593D24161C1D5291BCC9B38C552E160509257BC8EBE3D09B612F2CE2D0CBB5ABA28D7701FE445C070718406A819085687194D8F5FFC97646426FC3F4F7C1622E274B90D1E4DEE0C25E160B2166A3C0CBAB54212A67A2CCD2D7C09E56100000186CB4CDCCC4CBBA762000001E70ACB99DA4A6A9803B020000154784B8DCDDC9B4853A0C000A194B8BC5D5DFECDCC57A210008499AD3DEDAD2CCBB983600001F74B1C3B8ABB7BEB38866391B3A85ADB9B9B1A9A28026000000000608000000000000000000080F0A0B1418068F89B4E6FFFFF0D6B696817F7F95B8D0D5D1C8AFA5A38D745C3120417DAD9D7C4D434A636A4E23130E24244AA7CBCDBF8B5336270D052973CAE3E3CA97541F2AD5D1C8AFA5A38D7401FE455C070718506F8299866A6E92C9FAFFBB6F464772BFF5FDD06F2F2243A0C9DCDFE0B85813143567AFC9D1A2501B356EAFC0CAD0B397530900002373B6D0D0C8C8B3681D00002B79B6C9A09FAEAE8A34000000184E8AADD5D8C1A97F360F001220538CCAD0DEE1CFBB741600094CA3C9E2DED2CCD0A23600001E71A5C2BFB1B2C0AE816D441D4A8EB2BCB4B1A6976B19000000000E0A02000002000000000004020710100F038693BBE5F9FFFFD2B58A7B6E658FB8CBD6D6D2ABA5A3917E592D1D4989A196754E344563593D231518283662A6CECEB485583F210F0A1B75C4EAE3C1955B2C28D6D6D2ABA5A3917E01FE465C070718607693968560719DDBF7ECBC70435088D3F7F7CF6B2F2D529EE0E1ECE9C2601611316FA8C7D4A94820287CB0C0D1C1B5954E1300002574BFDAD3D0C89F5D1300002E76B3C1A1A7ACA275320000001C478CC1DBE2D2AA732E00000B28508FC5DDE7E5D8B06D15000F55A2D4E2DED0CBC68E3B01002175A8C0BFA9B7BBAE8168351C4798B1B3BEBBA89D6C1F000000050E01070000000000000004020C120F0C1002818AAFEEFFFFEBD3B4907A6D7093B6D3DCD3C4AAA49F8B74552E16488FA59968463D4D62633D000C11313E6AB5D2CEA77F5A371102062E8BC7E9E0C387522A25DCD3C4AAA49F8B7401FE475C0707187077818E856B77A6E2FFFEB668495485CFF7FFBC6C3D35569AD3E1E1E3B95415183367A6C6D09F40203375B0C8D1BEB796510C00002B79C2DBD0D1C39D5F0B00012779ADC1ACA9ADA27E350100051D588BBBD6CFC5AD6D2C0402112A5698C7D5E4D4C9B0701B001357A6CED9D6DFCBBF902F00002579B2CFC3ADC4B9AA866F391F4390A9B6BCB7A89E681700000009190B01000000000000020300030C111416008B85B5E6FFF5E8C79E8373697191AFCED7D1C1AEA8A28C78562D205092A189663B322E57613D1C0B15384A70B2CDCFB57D532F25080B267ECDE8D2BA82522623D7D1C1AEA8A28C7801FE485C070718806E7881746671A4E4FFF5B06B464B80D3FFF4BC5D322B5AA0DFEBE9E5B6531516366FACC8D0AC52203E75B2D2CFB8B494470A00043784CAD9D1CFB890440B00003473BEC5A3A5A19A73290400041E508EC5DADDC89E672602040C245288C2DEE8DED0AD6313001661B1DED8D7D2D0BC832200001C83B5C8B4B1B9BDA78579441E4F8AABB5BEB5AA965E140000000C110E090000000000000003060C0B1A1012029193B4E6F4F8E5C3A48077696893BDC5CEC6BBA1869C756B5036275196A69762393238535D2E1513152D4585BED4C6A77843261F0C062A86CEE5E1BB8C491F21CEC6BBA1869C756B01FE495C07071890767D7F787081B5E9FFFFB267485E8DDFFFFFCC61343057A1D2E8EBE7BA5E211C3D6AAECAC8A04E244582ACC7CBB7B696430500043F94C3DECED7B086410100073681B4C79CA4AB97742400000D3162A3C8E2DCC299521D00010F346194C0DAE3E0C7A06914000B66B4D5E1D8D2CBB6822300002B89ADCFC6B9B7C0A6867F3A15509BB1B9B9AF9F93570C000007171612000000000000000000000414121009008CA1C2EFFFFDEAC098746C646D9FACD6C9D5C2A7A09F9074563A28538AA8956C3F2C3C53553526121A3D5889C7DDCCA775412B11070B3391D4E5D2B178381D0AC9D5C2A7A09F907401FE4A5C070718A0727B77787082B1EBFFF2AA654C5B94DDFFFFC55F2B2F5C9FD5F1E7ECB8510F204682B5C7D2A44A204085AEBFC1B6B4A0480400074793C9D6D7D3AC8239080004317CC6D1B4A8A29A641B0000092D669ECFE3D7BE83552800000D345C9BD0D6DCE1C69B590C00186FB6DEE2DCCACBB87E2B00002A7EAFC3C4B3B3AF9C817E452F5D98AAB1AEB2AC8E520800000720261A090000000000000000050901080716088DA0C3EEFAFEE5B593726366679AC1D4D9CEC59EA59B8D6C51361F52979F84663929364F5E2B120D193C5492C2D4C49E76462A230A113B92D4E0C9AD79442119D9CEC59EA59B8D6C01FE4B5C070718B071717A6A758BC0F3FFECA764465E9DE1FFFFBE5E2B2F5CACDAECECE5A4511B22468BBAC6CCA949213F80B8C3C0B1AB864300000B4792CADDD5C2AB8236020000347DBED1B3A2A1895B2302001B3D78A4C3D8D5B5935C1C00001738568AC6D5DDDFC2944F1203146CB7E2EDE9D6CDB57A2200003895C6C4B5BABCB097837639225396ADABBBB2A58D450200000D242A1F090000000000000000030D14100A0C097DA0C6EBEEE8CFB08779665F7899B7CFCFC8B9A09199856A4B312A5895AD8F5E2F32344B57320A061F315E95C6D6C5A66C41241302064092D3DFD1B178471F21CFC8B9A09199856A01FE4C5C070718C072777A69778CC1F1FFF2AB5D4E6599E0FFFFC262363561A1DEE3F1EEAE4D0B204979B0CAC8A043294A86ABBFCABAB0914200000953A5CEE4D0C0A1742C0000104A90B6CFB59F9B85562400001A4076B2CAD2CCB8935320020125416198C3DCDED4C596510A00166ABAE0E0E2D5D4B7722100003984ACD0B9BBBEA79D8F7F41286095A4AFBEACA28E4C0000000C2B2B1D03000000000000000000050E0C0505008CA5CDECFFE6D5B88E795F5C739CB8D2DBD2C0A2A29C9874553A285F96A386583430314C5637111B2A426C9FCBCBB796603A2112070B258DD2DCCAAE763D1822DBD2C0A2A29C987401FE4D5C070718D070726A696B93C3F5FFEF9C64516595E6FFFFC071383863A8E0F3F4E1A14814244688BFC7CF9345325088ABB5B8B7BA84350000115BA7D1E4CEC4A376270000114A82B9D1C0A6978453180001235484B9C4D4C6AC803C090005294A6899BEDBDAD2B7854808001E76B6DCE9ECDCCFB56D1700093E82B7C9B6B6B4AD9B947F3D276295A3B7B8B3A88D430200002236332A0900000000000000000000000C0D110080A2C9F3F4F6D1AA8663544D6C97BDD1D4C8B89B9A9B966C4832316798A8875B3C303348553C1722314774A3C2C6BD91694C2D09000C328CCCCCC29D693E1D1DD4C8B89B9A9B966C01FE4E5C070718E06F767D758197CBFFFFE29F6A486D9CE8FFFFC56137345EA3EDF7FADFA3461C244B88BDD5DE9D4E244D8DB3BAC0AEB48A3400000F57A8DBDED9BB94661F00000F498BB5C8BDA79C814E11000225548DB8D1D5C1AF82440F001021426FA2C3CED3D2BE853D01001F78C7ECEEE0DACFAB691A0000388CC1C6BFB4B0AC9B8E753D25639CB2B3B0B2A985360000001A3E3924020000000000000000000B0909020C0291B1D6F0FFF3D6B08C69605D76A9CDE0E6CAB89DA09B8C674C302B619CA08C65403637464C2E202A3F417EA7C1C6B38F68361D0C0000338AD4DEC29969401E17E6CAB89DA09B8C6701FE4F5C070718F069706667749CD0F7FFDA9B5D5372ABF1FFFFCC6E3B3560A8E7EEF2DE974419325289BCD1CD923E1D4D88A9AFACABAF943A0000195FB1DAE5DAC09054150000174E9BC4D6C9AB92764609000C296496BED8D9C3BB793E07000D2B55739AC4D4D2CCAE71300000267DC2E8E3E4CCC7AB71170009469AC5CAC2B3B59F918F863D316EA2AEAAB1A5AA87370000002E4737180B0000000000000000000010100A100290A8DCF7F8E9DEAC8E73595B7DA8C4DDD1CAAF9CA2AA9C73552C286A9DB7895C34381F424F42282A433E80B9D3CBB58C5C39180E03083491CED9C1925C341C1AD1CAAF9CA2AA9C7301FE505C070718006E6B71828AA8D1FFFFE0965C5173AFEEFFFFBC613C3863AEE7FFFEDA8D421C2C6093B9CBC8933D224895B0BBAFA5B5863000001E6BBCD4DACFB988512100001C4D93C1D3C4AC9C794B0F00042B6A8BBFDEE1BE9A762F06000F275380AAC9D5D2C5B27E320000217CC9E0EADCCABDB0621C00084395C1C9C2B9BBAB999872382D6B9CAAB6B1A59F7D26000000314E45291000000000000000000000050E1104008AACD9F4FFE4C8AD896C525478A7CFDEE3C8B190949C9068514334649AAD8F5D3433324B543E27354F467BB8D2CEAB86502410070005378FC8D3B7A069352315E3C8B190949C906801FE515C07071810767A7B758BADE1FFFFE0945D5877AFF5FFFFBB61353368B4EBF9FDE6993D18316A99BCCCC68E37245793C1C5B4A9AD8D2B00002775BED5E4DBB98A4B0A000022529FD4D5C2A385663903000E376BA7CDDADFC1A3753206000B375A74A5C9CECFCAB4743207002D79C6E1E7E1D9CDA76117000D4698B9C1C4BEBDB09D8F773D356A9BA49EAFAFA780260000003A533D1E0200000000000000000002050400100389ACCAE7F6E8CDA182604E4573ABC1CAD0BEA88E93A68967503A3972A8B09B623A3C354D524A273A504279ACCBBFA38353251E08000A3996D2D0B4885A321B11D0BEA88E93A6896701FE525C070718207274728391BBD9FFFFD08A635A79B1FFFFFFBA582F3360A6E8EDF4D48C3C20386C9FC7CBC4893E275696B2AEA7A8AC8C3100002780CBE0E4D7BA7E380700002A5C9CCEDDC7A57F613B0A00193C75ABC4D1D3B1A072330D01113A5D82ABC8D4DACEA6712600002572C1E5E0E4D5D6BA5E2400124B94BBCBC8B9BBA48A8A6D37317497AFA7B6B1A3712600000D4760432006000000000000000000060607040A0091B1DCFFFAE2CBA380665B5C75ABD6DDDEC6AE988A97906E49434075A2A58D5F3334304F5644374560508AB0C9C69A754A2A130300063299D1D2AF8C50241A0CDEC6AE988A97906E01FE535C0707183071706B7A8BAED6FDFFD0825F4871B4F9FFFFB15A343868B5E8FDF9D77E32214273A2C3C6BE8535254D97AFB4A6A7B384330001318EC7D8E7DFBE7A3A0A00012266A7CCD7CCA98762360100165385ABD2DAE0B5A0672C0B001035627CABCACEC8C1A16A2A0000297BC3DFE8DFD9C8B06117000F4F94C0C6C9B5B59D7F8F7A34386C9EA3A7A3A3A26E17000018537051250100000000000000000003050B0F0D009ECBF4FFFFF3D2AC91715D5F7BABD7DCDCC6A29191988B714338488BABAE9A6C403932425B503A4F73418ABBC2B89D72451F0F0F010F3593C7D5A67E4E33201EDCC6A29191988B7101FE545C070718407073707791AFDAFFFFD1854E4D76C2FEFFFFBC572F396CAEE4EBEDCB722A1D4576A7C9CCC0803A2F5297B4A8A2A4A983290002398DC2E0E4E1BE7631000000296CAACEE4D6AC86592F0100195C91B6CED9CFC1A46B2700000C376A89B0C8C8C6BDA360280000227EC4E0E5E1DBBE9A5A1000084CA5C0C3C2BBB8928C8B683A3471A2A6B2ADA8A37119000023547545250400000000000000000000000906050092BBEDFFFFF3D2A9856C5F5E8AB4D3E5D7BDA9989DA294714E343E82A8B1986A3A393B5362504651704292B3C9B08F6A411B070300103C99CBD4A986452D100AD7BDA9989DA2947101FE555C070718507775798EA3C5E6FFFFC47F555172C3FEFFFFBC60394472C2F3FDEFD37A37204A79A3C3C1AF77352C649EB6AEA8A5BA8A3700023A94CFE3E7D6B56B250000043169A9CBDAD6AD78592D00021C5A8CC7D2D5CEB49E642C0000123B6F92ADBDD6D6C299541300002D7BC5DFE9ECD9C9A66016000A4A9ABECED0C5B494858669303878A4A6ACB5AFA365180000206176511E0800000000000000000000040D0E09009AD9FFFFFFF8E5AB8474636B7AB6D5E8DDD1B19B9EA091755241518EB5B19364453C3A4959574C607A3B88C1C7B293623A18190500033DA0D2C7A58044201812DDD1B19B9EA0917501FE565C070718607D7E72889EC9E3FFFFC57D5B5B82CEFFFFFFAA5030457BC2EBF5EBC37537275189ACBEBAAF7133295991B4B4A4A4AF8130050E4C9DD9E1E6E0B36D20000006306D9FC0D9D5AD714D2202072A679CC3D4D8D6AC94591F030B234A7693ABC3D6CAAF8F571A00002C84CBECE6DECFC29C5D11000E4B9EC4BECDC0B3907786733C45759DA8ACADAD996C1700001F627C5B290900000000000000000000030100040091C3EFFCFFF1DBAB846B5F637DBED9E7D9C0A48E8E9B85725B445691AEAE945E40373D49625C5256713891BAC3AF8D692B10090100093698D0CD9D76482D141AD9C0A48E8E9B857201FE575C0707187074767583ADD5E7F5FEB97F586183CAFFFFFBAC52344C7DBDE8EDE3BD6F2F254A8EB5BFBDAC70312C619EB0AC9F9BAB7B340202449DCCDEECDEB6621800000C397AAFC8D9CFAB73491E07022C6DA5C8D2D0C5BCA06A2000001D4A7D96B8C9CBC1AF954B0E00002E79C5DFE5E5DDCB9B581C01185AA6BAC8BCBBB2826D836D39447799ADAFB1B6AD6B190000206A8B5A2B110000000000000000000007010601039BCFF5FFFFF5CFAA8E665A6D9DB6D9E8E0CAB3959FA591775540588CB4B4956A4A3E30486360576D7C3F9BC2CCB08D612C0C040000063D97C0C6B2763E241B1EE0CAB3959FA5917701FE585C070718807A6F717DACCEEDF9FABC735D5B7FCEFFFFFFAC5938476FB3E1EBEABF672F285C8AB9C3B9AB64332F6796ADA5999C9E6828030D449CDAE4E1DBB9681E0000154376AEC9D0CEAA793E1501103470ADCEE3E1C9B29E581F01001D548091BACBD0C4B18B4D090000287FC9E1EAE1D8CE9D661A0413519FC5C4BEBEB77F727C5D2B41849CA1ABA7AEA65B11000031788A5A2A02000000000000000000020300070A009BD6FFFFFFF0DEB78E6A62648FBBE2E5E3C9B6A298988A715A496699BDB18F6850372D4178705D6A8D3497B7BCA1815F25090A00000B4EA9CBBC9E6C381B1E1AE3C9B6A298988A7101FE595C070718907A7F7D98B5DBFBFFFFB37958608AD8FFFFFFA9572C3576BAECF5ECBA602E315D98B8BBB59C5D2B3765A5BAA29C9DAA762400134FABDBE4EBDDAC59180000144176B4CCD8CDAA6E451E01083D77AACFDBD0CFB39A68190005235592A1ACC3C5CFAF8A4C010000348CBFD9E2E3DDC7975B1E091C4E9DBACECBBEA66D637461384E80A2B3AFBBA49C4F0C0000327291622E080000000000000000000000040709009CDFFFFFFFF5D9B08D754B508FEEE6E5DEC2AF9B929A8B785C4862A1C0BF9D7A5731314E5F635D728B2996BBC3A278532B090400000D48A3C69E765E42262A24DEC2AF9B929A8B7801FE5A5C070718A06F6F738AAFDAF3F5F0AD765F5F8CD0FFFFFFAE4F36467CC3ECECE4AC61272E5F99BDC0B29B5C242A5F9CA4A3A4A6A272250D1751AFE4F0E7DCB05B0E00001D4482A8CCD1CDAE753F15000F3989BFD8DCDBD2B8996218000127628EA5B6BBBDB5B17E450A00002E7EBEE6E2DBDAC9A763220A1A5AA6B7C6BFB9A56E646F522D4A8DB0B8AFAEA1954300000033808F5A2602000000000000000000000003030400AAE1FFFFFFFCE4B0866D627097C8ECE6D5C5AB8F949B827A5C5869A6BFB39C6B431D3453686B6A7B862EA3C5C2A8864D25000500001250A2CCC59B6A3D2A2826D5C5AB8F949B827A01FE5B5C070718B07B757D94B9EAF5FEFFB87A59548ADAFFFFFAA454364E82C6E7EAE2AE5B2D28609FCCC8AB96572B27679DAD9E979E9F65240F0F5CA6DCEEEAD5AA5A1B000022498ABAC6D9CEB27F361100154488C9D9DAD3C8B19C561E00012A5D94A3B4B8B9B79B76330000003687C2D5E5DAD2C6A4662510225CA1BEC4B8B7A86F617349305C8DAAA7ADA5A98F5202000146848B55220700000000000000000000080E010C0091E4FFFFFFE6E4C7835E4E6A9ED0E0F4EFBEB19B9A9D8D785D506EB0C3BC9D64443A3751666B6E80A12898BDC4AC75451D000000000D5AACC9B795612F212521EFBEB19B9A9D8D7801FE5C5C070718C07A7A789BC1EFFFFDF4A570595A8CE0FFFFFCA254404E84CAE5F0E1A95D242E70B1CEC29D7D48212B62A1A3948A979C6C22081962B4D3E2DFD4B062170002254E8DBFD3DED2A978351402124887B1D1CFCCC1B293501D0009295F96A7B4C0BAB5A07A310000003A82C9E3DBD9D4C1A161190E276CA3C4C8C2C29860556754345C91B2B0ACAAB09F4C00000341878D6632000000000000000000000000060001009CDAFFFFFFF1D7B2826F556C9FCEE6ECE4C9A794958784735E616F9DC0B6945E4734354F706B788BA4299FBFC79F724922000000000A54ADCAB9915C35262423E4C9A7949587847301FE5D5C070718D0685D6E95C5FBFBFFE7A0654A5598DDFFFFF69A50344B7DBEE4E8E8A151272F76AAC9C4A78142252F5D9EA5978C9697641D092162B5E4E1E7D7A95A1100002B5A88BACAD7D6B077361A00125190C6D4DBD6CAAC92571B00002166959DB2B6BDB79D6C250000063A90BCD9E1E4CEBC9B6A27132765A6BDBDC4B5995D5964513A5B97AAACB4AEA1893F000006528E915E300C000000000000000006000601010300A9F5FFFFFFEDCDA7876B5F67A2CAE8ECDBC5AF938F86896F656B79A9C3B89C6B412E466168696888A0228DBEBEA4724116070000001158B3D3BE8A593A233224DBC5AF938F86896F01FE5E5C070718E0666E789ADBFFFFFFF099674E5B84D6FFFFF191443A5294C7F1EED8914F2F3B77B1D9CEA6713A17285E949A938D9C905C21052964B4DFE0DAD3B45611000D36558BBAD1DDC8AF76290D0619579DC4D6DBCFC9BB91501A0008306A9EAAA9C1BEB19964260000053A85C4DDE6E2CFB5976926173465A1BFC2BEB39A635C63402D6697B2B5B2B2A28C3B00000657949E703207000000000000000000000400010100A7EEFFFFFFF9D4AE987D6675A0D3EEF2E9C9A396878A887C6B6783AAC0B7996540313B58757D79979D2096C5C4965C3100000004001B62BAD8B7995A33292F2EE9C9A396878A887C01FE5F5C070718F07B6B769CD2FFFFFEE7A6614C5D9EE0FFFFF19A4B315590CFE6DFD9955832397DB1CAC7A673371D2C699B998981918D58250F2275BCE2E8E2C8A04C1000163C6F8FB8CCD2CEAF813404002161A9C9CFCCD2CBB497511200003175A0A7ADBBBFAE8E5918000000388ABDD9DCDECAC59E6D3318366C9EC2C3C7B9905A585D3D366698ABAAA5B4B38D420000025990A66E290A000000000000000000000301060A02AEF8FFFFFFFBD9B69071697EA6D4E3F3D4BFAC9D928E816960638DAFCCB194723E373A64827C7D92A01F9DC8C39C653E12000600001263ABBAB6A2602E1C3531D4BFAC9D928E816901FE605C07071800787679A3E1FFFFFFE8A462505F8ED9FFFFF39A483D558DD4DDE0D99152273F87C3DACC9B6D34152E5C838E7F8E9F9050140A2674BBEAE9DDD4A64B030012477495B9CFE3D4BB7E300F072161ABCAD2CEC6BDAE8F4A1900093574A2A7B5B6B5AC9862220000003F8CC6E3E6DBC8BAA279391C356AA6C2C0AEA98D5657614138689BB4BEAEACA7863900000D5AA0A16E2D03000000000000000000000004020100A1F1FFFFFFEFD0B190756D79AED9FBF3DFC5AC8786888E775D728BB7C2B092693D2D3753767E869AA6299CB9BC905A390B000000001F6CB8CAB37A60342E3B2EDFC5AC8786888E7701FE615C07071810787C7EAAE6FFFFFFE19F624E6197DDFFFFEB8B46445694D5E5EED28C49233F84C2DBD1A96321142E6D93947D8091814D130C2C73BCE9E4E1D0A14A130516527B93AFC9CDC3B37E3706092A6EABC9E2CECAC2A48E4D16070B3E7496A3B2B6B3BA9862160000004189BCD9DEDFC7B9A4793625427BA5B5B7B8AF805850623B3C6C95B4B5B4A6A97F31000013618F9D703008000000000000000000000100000500B4F5FFFFFFFCD0AD937A5F81ACDCFBF1DFB79C968A796A645D7090B6C5C3856139243D62839393A6BC2E9EC5B78A64310A000000002C7BC4D1B6804F302E3428DFB79C968A796A6401FE625C07071820717082ADFBFFFFFFDB945648599EE4FFFFEB8B403857A6E4F3E5D88443224390D5E0D9B16B230C1E598479728D947B44190A2F70BFDADEDDCEAD460A00185682A2AFC7D0C8B987300712386AB3CED8CCBDBBA58F521E0417497490A1AAB3BAAE8552130000064A98C4DCDED6CCB49D7640314C7FAFBEC2B4B48F4E4A4F31376CA4ABB3B3A49C81290000186898A1723809000000000000000000000000000700AFF1FFFFFFF4D2AB94736274AFE6F4E9D2AFA3948B7C6F696C7699BBC6C1A3741E1F185D878E8C9BB42E98C5B8874C1700000000022F84BFCAAD7151372D3F34D2AFA3948B7C6F6901FE635C07071830747182B6F4FFFFFFE78C51455E9BDEFFFFE6893F3653A5CDD0D8D18E47284796CBD7CDB166180B275D847D72878F7A40191B3477C0E1E1E1CA9E480A032A697F9EB8CAC8C3B67F37070A3C76AECDD0C8BBB5AF913C1502185185A4A1A4ADBAAB8E4B0B0000014A9BBDCCDCD8BDABA2783B335081B1BFC0AEA17F4A4A4B363974A4B8B1B4B5AE7C2C00000F5F96A27B400D000000000000000000000004080600ADF2FFFFFFDBBB977F685D74ACD3F7E8CCB79887817B6F6E6F7488B5C8B4986F352B3961B8A39AA3BB36A3B9AB844A1B00000000023187C1CEA46A3E2B2F3C2FCCB79887817B6F6E01FE645C07071840797D88B8FBFFFFFFE98F5B495D9EE8FFFFE28C4D3868A6DCDFE2CF77422750A4CFDCD4B05917021F5D747A79888C7A3E180E2C73C6E9EAE4D191440F0B386E809EBBC6C9C5AF84300D104381B3C9D5C6B2B7A58B4013001B4D839F9F9A9FB5AA8C490A00000D4F9EC9D0E4E0BDA29B773F355A8BB0BAC0B9A873454C4E3141809EB1BAB2A6A17121000023719FA4833D1200000000000000000000010105080096DDFFFFEACEB38F72585E699AD6EAE5C8A39282766D6962667898BDC4AF955F2C21365E8B8E90A9B63598B8AA753E1100000000052D8CC7CFAA75482B263F3BC8A39282766D696201FE655C070718507B858FC1FFFFFFFFED8F5A5364A4F6FFFFE9874C426AA7CFD3D7C679342B51A5D1D9DBAF601E0A234B71757589836B3C11113C85C2E9EEEBCC9439080930708EA3A7C2C7C0BA82340E1A4384BDCDD9CFBDB9AE893F120812448DA4939AA2A1B2924F1400000550A4C6CDDDD0B3A6A07A3C3D5E88B1BBB6BA9E72404F462F4173A3B2C3BBAC9D6E1D0000146FAFAE914C14000000000000000000000000000700A8E5F9FFE4C2AE987B64536EB0DCECDEBFA189877169595A617499BAC5B299643A28325A8BA9B6B6B53BA2BA9F763A0C00000000063596C8D1A4623C2129423BBFA189877169595A01FE665C07071860737686AEF2FFFFFFDC855A47639FE3FFFFED81413E67A5D6E5DDBE75321E59ACD4DFDFB35C0A031949697069828E642F1014357FC5DEE3DFCF8D3B0905307D9FA3B5B9C4CCB87F380C175396B8CBD0D1BAB9AB893D14031C5584A6A39FA4A6AD8B460000000C4197BECFD5C9A69C9B773E457097B2B3BBAEA175454F482A4B759DAAB0AEB2A36D1E00001F71A0B3944B1C000000000000000000000000000400A7DBFAFBE1BCA28A6D575669A5D0E4E7C19C8A6C72715A687186A5BBC2B4985F2F212E6090A2B9BCC24AA2B4935F2A0400000000003999C8CB9D614735304E38C19C8A6C72715A6801FE675C07071870757C88B8FFFFFFFFE689534A60A5E9FFFFE087483767ACD4CBDAD278352352AEE2ECE1AF5408001A4E6478787D845C3014113D8BBEDCDBDACA8F461B174180A8ABAFB6B1B6B0832F121D639DBBCCD2C2AEB1A1843E1606205E93A29795A2A5A58145020000105798BED6DCD1B38E9D7B3F436BA2B2BDC1B1A96B45483E2D4282A6B5B5B0A9A26E1C00001B78A0AB8F4D1A000000000000000000000104000100A4D5F3EAD6BDA4867253436795CCE0D9C4A18E72694F50586C869FAEBCAF936126183E5E9AB3C0BBC053AAB89E652500000000000E4998CFC29F673824314A3AC4A18E72694F505801FE685C070718806C7189B8FCFFFFFFCC7F544160AEEBFFFFDD75433064B2DBD6E3C466372C58A9DFE5D6A9510B0518586E6E6E757C612811144A88C3E0E2D4B2833F16174690A2B0C2BCB7BCB27C3419215894C4D1E1C8B4B4A9803B13091B5E95A793959C99A2833E000000146298C5CCD1C2A58F9B7649537899C2BFB8B0AE5D3E44443154899FAAB1ADAF995A1500001F6F96B1A25B140000000000000000000000000000009FD7FAEBD3B19B7F694F4964A0D8EADBB4887D716756575E7081A8C6C6AE8E6127052E609DBACDBACA539FB38E5B230400000000244FA8C9CB9F61422D2B4636B4887D716756575E01FE695C070718907E7993C5FFFFFFFFD181505270B9F0FFFCCE7D43496FB8CAD3DBC0712E2860BADEE9D8AB5407001E5A696D73807B5324080F3986C3E8E0CEC88A3716174698ACB7C2B9B6B4B27C370D2C6DA6C0D0CFCABCB5A77631180D2E6F99A9998B9AA5A07A38000000146098B7C9CDC89F858F754C59769EB3BBB5BCAC7344454130488BB3B1ACA6A48D530E0003307BB4C1965011000000000000000000000000000000A5DCE8C1C09A8A7F7056416E9FCCDBC7AB867C575F54585F7A86A0C3C4AB87571914387095BCC5C7C95CAAAC804900000000020E185395C8C091643D33394B38AB867C575F54585F01FE6A5C070718A0727693C2FFFFFFFFD37F464C67B6FAFFF9DA7B3A4272B5C5CAD0BB6B313165C4E1E5DEAB4A04001B4C6974748070531D0A133B84C5E5E3E2C184310B1550A1AEB6B1B9B6B0AA7A33132C75A3C7CDD7CEB9B2A56C2F0A0729709DAA898A97AAA176340000001E62AFC0D1D2B88B7685644B6183AEBBB8BEB9A46A3B5043364C8BABB5B4B6A599551100002C7BA1BFA554150000000000000000000000000000009FC5DBD0B8907A7360523F5B8BC8D2C19D78615955584E637091B3BEBAAC80541D06336193C2C6C3CA63B2AE8A4D1600000000021857AACCC29B603E3530343E9D78615955584E6301FE6B5C070718B06F7484BEFCFFFFFFC369444B67B0E1FAFFD77D404171BED7C7D7B95E262F6DC0E4DDDEAF4F0A011C5C67646673753D1C0C1C4789C3E8E7DAC68B3013174E9FBDB8BCC5B2B0B4813018326FB1CACFD7C5B8B8A4671F0B0B2A72A0B1928A93AAA779340000001C6CA2BEC6CCC1827A8A7947608DA3BAC2BAAEA46C434A382F5B83A1A3B0ABAA9C570500003183ACB6A55820000000000000000000000002030A009FCCD4C7A58F7E6B5241465D9AC9D4C0A07A634C53524B58728EB1C6C09F81450D092A6FB0CACCCDC76AB1B085490500000000021D6DB4D5B58A5F4229334B43A07A634C53524B5801FE6C5C070718C0776F8BC2FFFFFFFFB97553466CB8EDFFFFCF7B3F417DBFCBCADDBB6A332D65AED7E9E4AB4F0C001E52726A7875613D12030C4189C2E3DDCEB87A3C141F5AA5B9C0C4B3ACABAC7332203A80BAD7CEC6B9BEB7A85E27170E2D78ACB2898598949B783A0000001968A3B4BCC2B586728460436B92BAB8BCB8B4A067424A41295695A3ACB6ACA9944D0100023089A8AE945E1D00000000000000000000000000030097C3D2C3AE90736951383873A0C1D3BE9B72615855454A627E95B0C6BE9C753C15142F71A5C0CDD0C870ADB1813E000000000014195DB5DFC38D613C253850439B72615855454A6201FE6D5C070718D0767B8CC1FFFFFFFFB96F4C4573B0EBFEFFD37149517EBCCCCBC6AE65333368BAE0E2E3A84205001F5E716D79796031140714438ECCE4E2D7B47A30191F5CAAC2C9C2B1ABB0B37C321A3E87B9CBCCC8BAB2C4A46526120D3E7CA7A88E8697A293752600000025679ABABDC2B0747385755C6991B2BCB8BCB0975F32462F3A63909EA6AAB0B197520400083E83AAB7A065220000000000000000000000000000009CBFC5B4A17D735E514231619BBDCCB39067564E47433A557EA5BDC0C09E854B1A092662A2C0D9D6C46EA6A7873B04000000000B307BBCD5BB7E5D3C20344C489067564E47433A5501FE6E5C070718E06F708EC4FFFFFFFFB46B42456ABFF0FFFFD06C424182C5D8C7DABC58282978C1DAE2E0AD460900275F7B74776E572C140413458AC3DCDFD3B67737172262A9C4C9B8B0A8B2AF6F2E1C3A85C0CAC8C0C5B2B28B5F2A1917317CADB29A88919F9B74270000002676A3ACB8BFA26F6D8267566E9EBEC6BAB7B49C5B2E3F34366F9ABCBAB3B0A491500800013484A8AF9D581F00000000000000000000020400000091B9CBBD976F5D5843293C599EC2C6AF926B624B3A3D3B5880A8BDC7C09F704311022A70A5C4CCC8CF87B09D783800000000001B427FBDD4C4905A433933544C926B624B3A3D3B5801FE6F5C070718F07B7F9DC8FFFFFFFFB967444E7BC1F2FEFEC7733A4979C9E0CCD3B05A2B2F72BEE5E5D4AA41020124617C79737650280A010B4088C4E8E0DAAB75230A1C6BAFD1C6BA9F9EA9AC732C1E4D90B8C8C7C9BAB7BA9A612A1F18448DB2AE8F8794979A742A000000286DA5B8B7BC9D666A755B557EA3B5C0B7B4B29356364D3E356693AFB2B1A5B18B4007000D3F91B1BAA7641E0000000000000000000000000404008DA9A99A79574C4140323A6496B7C5A4744941343C393F5C83A3BCBCB0966C350F1C316DA1C5D1D4CE7FB1A77A1F0000000008244A8EBED0B28D60442E3B5053744941343C393F5C01FE705C07071800747B94CFFFFFFFFFBA66464D75BFF3FBFCCC72414980C2D6CED5B6562D386CBDE2E8D6A93D0802316D82807564481E0509194684BAEEDACAAB6C28133069B9D2CFBFA597A9AD742E1C4497C6D5CAC2BCB3B69A5F2B1B0E3E8AA1AB99888EA38D61120000002C7DA7BAA7AF9366757B5D5073A8C3D1C8B8B4905136483C3D749EADA5ADAB9789450000014990B1BAA06A1B00000000000000000000000000030088B4BAA47A59423F312F416493BDC0B77A62382E37313C5B8CB5C3C4B885683406082F6DA4C6D8D4CB7FAF9F6E280000000014325FA2C8CDB0835D462E31434C7A62382E37313C5B01FE715C07071810757C94CBFFFFFFFFB06B4A557CCFFCFFFAC06F405488C3DBDDDDB45B242A71C0DEE3D7A4420307306F8E7D7C6C46180206134680BADCDECEAE6E28142B79BED4D1C6A092A8A76E271E5896C4D5D1C0B7BBB0894C2F21193A8BB2AF927F92A29A611F0000003580ACA898B99D656B74614781B4C3C2BFC1A4904A2D48364875A6AEABAF9F998D3F0300144699B3B8A8671700000000000000000000000000050098B2B2A480513A353231386A9BC4CAA16E55362F30443D5C8EB4C3C3BA8B64350C002473A8CAE0D9D084A8A37123000000001C406CB3C2CEAD75493920315A536E55362F30443D5C01FE725C07071820797B99CFFFFFFFFCA36044496FB9F1FFF4C16B44508DC9DAD8DEAD5B21366EC0E3E7DBAA440302327392848060300A0001174080B6DBDFD2AC5D28192B72B8CFC4C59D9BA5AE6C292B5C9FCFCFCCCABDBEB3864A20180F4093B3A997888D969F741D0000002F79A6ABA5B1976B7C80605B8BAEB6B9BBC2B38E3B2F3F3C4678A7B6B3B6A99E833B00000D4B86AFB0A15F1C0000000000000000000000000000008AA9AD946E423026211F34638DBABC9E6E40342D263A3C568DABC9BEB48762390D023775A7D0E3D3DA8EB29966180000000020436EA1CFCDAE76614038344A4D6E40342D263A3C5601FE735C070718307E7E97D1FFFFFFFEA863445A75C4EAFFF0AB61405086C8DBCED1A64A28377AC8E7E3E2A447030031749596816739050000144A82C0DFDFD2AC60200D2D72C0D8D6CAA79EA9A2602C2D5CA6C6C8C7BBC0C6BA8E472416194B91A6AD96849996875B0E0000003A899EA1A3AB95667871556087A8BFC0C3B8AC8F482F36364D81A6B2B7AEAEA5852D0000194888B1B1A86624000000000000000000000D00000800879EA48F6C4D30252422305FA0BCBC9369462F2836333E5E89ADC4C5AB895A2B0F012E77ACCFDEDDCE94B29A66200000000025567DB0C7D29C704F3C2C2B545469462F2836333E5E01FE745C070718406D7C9BD3FFFFFFFA9D55424872C2EEFAF1B76441528BD1D8DCDCA94C253372CCE3ECDB9E420002356E96958866360C0002234F80B9DFE4D3A35A1D113273BDC8D0BC9D8FA6AF642E326CACCCCAC4C2C8BBAE8A492F1B13428EB2B097979897905E19000000417EA3A09FA98F5E737353538AB3BEC0C1BCB285453138334889ABB5B1A5A7A17E320000255695A9B1AA6C2900000000000000000000000000050082A5A9865B33281513203A68A6B8AD8C663830262B343F5684B0C5CCAD885F36150E2665B3CEDCDECD96B0A46A1B00000000264F80B7D4CCA5674136242F4B55663830262B343F5601FE755C07071850777FA0D5FFFFFFFFA964495279C2F5FFF4B85A3E5A97CCDCD0D7A651203A76BFDEEADB9A37020036809CA0845D310A00081B477CB6D9DECDA0552313306FC1D4D0C39888A3AC67342C64AECACEC8BFBCBCAD7B47231E1D478BB6A89492938D7D500D000000428FB6A49BB49770726C4C5793B6BDC3BBC3BB8C462B362D4E86A4B0B4AFA59A7D24000024658CA2AE985F1F00000000000000000000000000000087969784632D150F0B102B6DA9CDBD9262362A1F2E31316593BCD2D9B17A5E39160C316FA1D6E4D7D1A7BD9F600D0000000029668CC3D4C39E66442E1F33565962362A1F2E31316501FE765C07071860747C9FD2FFFFFFF595574B517DCDF2FFEFB45D455D99D4DEE2D2A152263979CFE7EFDA8F2D0000357F959C856B310C0000204F87ADD1D9CDA851160E2E6EB6D1D2BF9493B2B061222975B0CBC2CAC2BAB5AF7D4A2D231E4A8EB1A89E8A8F8C7C530B000000518EA49EA2B28C6E796E4B5F93B2BBBCCFB9B3853B2834264D96B5C0BAB9B09C7A2700022A5A9CAAB999591A0000000000000000000000000000008FA59687572E18161119306DA5C1BA9D632F1B152A313A6495BBD3CBAB7D6037131C3D6CA1CADEDDCFA0B7955E140000000031699DB0CCC29A6D443928325158632F1B152A313A6401FE775C070718707783A2DEFFFFFFF6A2633E5184C1F6FFF7AE6344659FDAE5E1D39B4B273980C8DFEDD2912A020C4082A6A8875D250000001E5590B6D1DED5A14D180B3780C5D1D1C1918DADA862253A77B0CBC7BFC3B3B4A97C3C2C291B4B97B7A798959691783D0A0000004F91AA9794AC95697B71485B9FC4C7BFC2B9AA82422630324F8BA7B5BCB3A8A57A2701102E5A99BAB297531D0000000000000000000000000201008EA19989502311040C163475B4BCAF865826242926324968A3C4CED5A4805E3C25213D6EABD2D8DBD99CB7935C0C00000000347196C4D0B28F593B2C2C2C5360582624292632496801FE785C070718807D8BB0E2FFFFFFEF995D4C588BCBFCFFF0A963475D9ED8E4E1D2A34525397DC1D1D9CB812801063688A8AF9B692A020002255685ADD6EACBA047200D2B6EB6D7D7C89A8D9F9C522A317AB4D4DED9C1BABBAA7043221E1B498BA7A9A09E917474410100000F5B92A2A3A0B38F7C886E566A9DC1C7C6BEB1AA854015261C4F91B3B8B6AEA7996C200413406C98A6A9925F14000000000000000000000000000000919C9D865320060B08132E68A5C2B48C562D17213635467DA5CCD0C7A36E584427213D659ACAEFE4CB97AD90580E00000000376F97BBCABD92603725212F4A63562D17213635467D01FE795C070718907885AAE9FFFFFFF18B51454E81C6F1FEE1AD584C63A2D7E4E3DDA148294082D1DFE3CC80270001377EABA89068270000001D5B94B5DADECE97451D0F3470BBCBD5B989849FA05B28377EB9D4CECAC9C8B8A970392C1C194D93B1B0A7A8837568380A0000126395A59899AA8A718162516AA3CAC8CEC7BCAD8839161C205D8FADB3B2ABA9A46E2A131A3E6590A6AE894714000000000000000000000300040100949B987D471A0D000C0E3A76AFC6B692512C0D2A3542536EAACED5BFA67C57432E1F2A6797C7E2E0D39CB1A05E11000000003270A9C9D3B38D492F261C325E7B512C0D2A3542536E01FE7A5C070718A0788AB0E9FFFFFFF89C544B5686D2FDFDF5AF58445FA4D8E5D8CB8A45202C76DCE4EBCE7C1C000E3F86AAB4A36723000000235383B1D1E4DEA05111193B80C2D6D2BC9485A69C51203B7CB5CCD7D2CCC6BDA0652F21171B4C90AFADA29C8C79632C060000186D959F929BAD9779776A47699EC8CFC3BDB7B2803A111A285E9CB3BCB4BBB1A36C28121C427491A89D834B0F000000000000000000000001000000788B8673321400000007327DAEBBB3864C1D10242F3D4780A9CAD1C4A6775541291B3468AED4E7D8CE99A8875D06000000044478A6CCCFC18C4627241B2B576A4C1D10242F3D478001FE7B5C070718B0778CB6E7FFFFFFEC9956475481C3F4FFE79C5C4E6AA5E4EDE7D58E411F3780C0DEE7D07E1F05063982ACB4AA6C300B0004265C8AA9DCDBD19246170D2C76BAD4D0C1968C99905023478BBED8D1CAC2BDB79B5B35291D124689A9ABABA88770602C0C000015679EAA97A4BB89818D684E69A9BACAC8C9BAB57E3618172A5BA0B7B9ABB0B39E6719002C506E97AE9B7C4C130000000000000000000000000000008F8F997A49080000000B3283B3B5AB7E511D161D233F547CA9CFD2BE9D74654E4226366FA2CCDBDACAA2A9884F0D000000004581ABD0D6BE824021140E2B576A511D161D233F547C01FE7C5C070718C06A7DB3ECFFFFFFE5874F41517FC9FFFFE2A05F405B9DD2E4E4D08C34274487CAECE4D1722100043C83B5BDAA6D2B00000B335F90ABC9DCCF9F4415153A79BDD2D2BE8A819E9142264690B9D7D3C7C4B8B092572D22151F4D94AEAFAEA588614B2A0C0000276D9DA997A4B193788164506CA4C4C7C3C1BAAB822B02122867A3B4B5BBB0AE976A1C1231546A93AAAB88480F000000000000000000000000010800899A937642050000100E3284B8C5B2844415001A353E5181B8CFD9CBA8746254422C3A68A3D1E4D8CB9EA7835802000000003E8ABCD0C8AB8047161B1F3154744415001A353E518101FE7D5C070718D06E83ADE9FFFFFFDF8A4B404E7CCDFEFFDF95594A6BADD3DEE0D2833921438AD1E8E4C6721E000D3C83A5B8AF6621000004316C91B3CFD9C9903C1216387DB8CBD8C59E90A48C3D214B8BBDCFD1CEC8C9B490502420141F418DB1B3AAA48F6746240B0000246C9FADA4A5BA9E8184614874A5BFC6CBC4B1A97D290B031E6CA3B3C0B5BDB0A05A1F1A38607490A9A2794B1400000000000000000000000000000082968F652D03000000002A6CB2BD9F7B47180F18363C5A87ACC4D9D4AC75604D3C32396597CDDFDAD498A17D4000000000004182B2CAD5B87B3723131F3D628247180F18363C5A8701FE7E5C070718E07389AFF8FFFFFFDE804F44507FC8F0F7DD8E544B69A7D6DAE8CE7637294C94D3E5E8C7741A000A3E88AAB5B074230000053D7399ACC9D8CF933C11173776B7CFDCC78F859E8638255391C0CDD7D5CDCAB68A45252718134989A1B2AAAC815B3D1600000024739CADABB7B8908393665072A8BACAC7BEC3B7802808002070A7B8C4C3B7B2AC6B211941637B98ABA376390900000000000000000000000101000086928A692E00000000003783B2C7B38944170B1921375285B3CCD3C8AD78685B3E2F3062A8D6F8EAD19BAB884000000000054898B7CDC9B2803A10111831577944170B192137528501FE7F5C070718F0708AB8FCFFFFFFD979423D5885D5F8FFD98D4C4468B2DBEDE9C87C2F2D478FCEE8DAC5651300033380A8BEB57D2901000D4074929DC8D1D8983A0E154186B7D9D1C496929C7935204E92BBD3D3C5C7BEAE89432B201512498CABABB0AD8B52381C0A00002975A1B7A5B4C2918283584E7CAFCBCAC9BFBBAD7D320F0B3375AAB0B6B7B4B09556181A48717C9CA79B7B3C0D000000000000000000000000000000839B93703D00000000003889C4C9BC7C42120A203649578BC3D6D6C7A27B67583C2C2A60A2D2D8DCCD9CA283410000000009438BBBCCCFB87C3E0F11142B5F8342120A203649578B01FE805C07071800798BB5EEFFFFFFCF7444374E7DD3FDFFD589443A6AB2E3E8EAC36A2729458CD2E8E6BC621500003B83ABC2B2832B00000E508796A3C5D3C787380C1E4384B8D0D6CB948397742D194A99C8D2D7D2D3C5B37C422A1A0C194888AFBBB6B0884D2E15000000317FABB9B5C4BC908486514669ACBCC1BDC1B8AF702D0C0C3077B1C2B6C0B2B196502731548183A19B9D7939010000000000000000000000000000007D88876028000000000A3A7BB6C8BA7A350E0A1633475484BDD4D9C7A782635E463138579EC7D9D2C19BA1804200000000014595BDCDD0B37D370B0A1A386488350E0A163347548401FE815C07071810738EC3FFFFFFFFCB794B3D5987CAEBEDD38A4C456FB0E3E8E4C26E271A4698CAE3E0B5510E0003417EA9C1BF823208000E548AA0ADC9C6CA98430B154385C4D3DCC893898D6F2B2755A1C9D6CEC1C7BEAF7A3F1E20101B4B86AAB7BDBC884626100C000B4582A7C0AABCB987837B575476A8C9CBC7C6C8B2712308123578A3AAB7AEB7AD975A2B385F788C9FA09C7E33000000000000000000000000000000008990805E2F000000000B3F8ABCC4B0763B1009183347688FCADADCCDA36E615D49352C5C98CFE4D5C4A2AF814A0000000000488ABAC8C7AD7A331C1214335F8A3B1009183347688F01FE825C070718207E93C2FFFFFFFFCD7F51465588D1FFFCDF84434472BAE7E1EAB56123204F98E0F3E6BE5C0F00013D7CA8BBBA80350500155F9CA09EB5D0C389360A174184BED9DACB9384936C2C21569FC8DCD6C7D0BFB3752C1A0E0C193F90AFBFB9BE833D1A0C07020D3D8DACC4BABDBD8B8A7748527CAAC5C4C0C4BDB3762402063784AEC0BFBBB7B99B54264062828A9FA39A6F44000000000000000000000000000000007E8379581F00000000003485B7C89E713304001D354D6C99C4DCDACAA26B615E45272E5E9CCAE4ECD79F9F784100000000004899C0D3C1A97437141015385E883304001D354D6C9901FE835C070718307794B9FFFFFFFFBE6B3E3D5691CCEDECCF783D3F72B6E6EEECAB5F26285299DBE5E5BA53100003387AA5BFC38B3D060016539AA9A3C1D0C3812F1219448EBDD2D5C5928A9460231D61A3C6D4DCD6D8C4AE7027141406114688AAB9B9A97B3B1A0E09040C4B87B0B7B8CDC78B8B83475A74ABC0D3CDC8BDB97A2A0012428DA9BCB7AAA8AF93512944728C9696918E66380000000000000000000000000000000084958D6229000000000E4189B1C7B0733A0E051B3F4F5493D0E3DFC2A87A645A3F2E2B5CA3D5E9D8C7A2A5763300000000065494B8CECEB57C2B091114336E8E3A0E051B3F4F549301FE845C070718407A90CDFFFFFFFCB56E4A4F6193D0F2FDCF7E454374B5DFE3E3B0612B345FA9D7E6DFB44604000B3D7BA5B8AF853309052667A6A6A6BDD0C782300C114390C6DED2C7987E8558232B68AFCCD6D6CFCAC3AC652B190E0D0D4189A6BDC3B67B3C190F140B194189B0C2B8D0B78A786E4B547BAEBDC6CABFB7B07620060F3F8BB3C0B4B8AAB290482554758B8C9DA294763F040000000000000000000000000000008287754D0800000000043082B7C7A96B2F1003183448649ECADFDFC6A17B6A5848382C61A1D2E5DCC89A95793400000000005595C7D3C9AB69300D0D13355D8B2F1003183448649E01FE855C07071850768BC5FFFFFFF9AC6F39445F95D1E7F4C984454367C0E3F1E4AC6027285FADDFDFDAB74C040007396B98BEC791390A01206DA4AAA2B1BCBF7E300F194B95CCE0E0BB9F878F531F2360A6D6D5D1CCCDCEA6581D0F14060F4780AABAC4B17739110317081A478CA7C2CFD2C3898173465175B2B9C7C7C0BBBC7E21000F4D98B2BBB4AAAFAB91442259829F96AEAC99733E010000000000000000000000000000008A8D815F1500000000093C8DB0BC9D6A300105112743639BCBE1E0CFA974625C46152F5C9DD1E2E0D3AAA17536000000000658AAD2DECF9B601D040F0F306296300105112743639B01FE865C07071860698DCCFFFFFFF3B06A40486891C7EEF3C97C45467FB9E1E2DCA351262658A0D5E8E5AF480000012F6DA0CAC195420F072978B5B69DADC0B5732A121E4F95C3D5D5C4958D834D172A71AECDD9D2CCCFC2A4561A13101019458BB1B6BDAF732214121D13174A8CB9C6BECDBC838273485177B1CBCCC7C3C8B2732700155C95B1C2C1B8B39F833F2C648A9693988F8E6D3B04000000000000000000000000000000858C77551B0000000009397DB1C7A568320A0016325076ACD5DFDDC3A571665F442D37659DC9E8D9C1929E6D2F000000000757A9D3DCC6945E1C02041738638F320A0016325076AC01FE875C070718706E8CC8FFFFFFE99F5B4245699FD2EEF2B76B434B76C3EAF0DC9D48272E59A4D9E5E6AD410B000C306494BEC3943F0D063175BAC1A1AEB8B5692B0B224B97C8E4DECBA18F7E411C2B7BB8D6D7CCC6C7C09B521A0C010218488BAFC4C6B16B210F162718154086AEC9C2E1C27D77613B4C82AEC8CDCACCC0AD731F01154F92B2B5B9B4B3AE9240376D88A397A39588683F0800000000000000000000000000000081867A4E120000000000438DB9BE9F6427000013234873A8CFE2DEC9A9745C563C2D3476B6D2E5DBBE9A996A23000000000553A4C6D7BE8E5225000913305E9127000013234873A801FE885C070718806D8FC4FFFFFFE29F603B4E6993CCE5E9B66A3C3D71B4D8DCDD9B4F2B3069A9E3E7E49F3705000032638EB9BD89410E0A3984CCC6A4A8B3AB631A0D1F56A2CDDFD0CD9C837E46142A71B5CCD0D4CCCFCFA14F19110D0E184183B5BBBFB174281219261B1E4688AFC7CED0B7847559455C93BCCBC5C5C7B7AC6A1400165A94BAC5BAB3A6AB8A3F2A6E95AEA3A5998D6640070000000000000000000000000000007C877C45070000000000368AB7C2A6631500091B2D5879AAD8EBE0D09E68554D38322F5B9BD4EED6CAAB966E31000000000B57B4E0D7C7964E19030A143772C21500091B2D5879AA01FE895C070718906B8FC4FFFFFFD78B583D446DA5D1E8DEB15A313C6BB5E4E2E29B461C2B65B6E3EAE39F2D0100002D5F89BEC497410E183A8FCACD98A5A1A75B1D0D1D5598CCE3DEC9B197733B15368EBECEDCDCD1CBC396491107000E1C488AA8BEBCAB6B2A0C132818244D92B0CECFD4B28360533E5C7FB2C7CACACCCCAB6819001D69A7AFBBBAB1ADAF783A2D6D9A9F9A9B988B6C4300000000000000000000000000000000788678400000000000064089B6B48F5A1B010B232E4F77AFD3E1E3C1915E5059432E2A62A2CFDEDDC1AE95702A00000000004CACD7D7B98547180D0D183368C01B010B232E4F77AF01FE8A5C070718A07288D0FFFFFFD7905639547EB6D9E8E1AC6333426FB3DDE8E49E44242E65B2DBEBDC9932000008346288B7C595461B173E93D7C9A5A4B19D5815051E57A3D3ECE4D8A5966E340E2E89C3CBD6D1CECEC88A3F0E000412204F92B8C5C0A65B1F0B0E2B1A19408BB6D6D2D8B67C5F58415F88B0CCC9C2BDC0B06B1800216FB0B6B8B3B7B5A98D4139739FABA49D96886E43000000000000000000000000000000008786663E0100000000004393C5B798501C010F11284D77AED9E3D9C59A6F533D341F3061A5DBE8DEC4AE91612300000000065EBED9DCBB86400D030C182F69B81C010F11284D77AE01FE8B5C070718B07490CDFFFFFFCC85523D497DB5DAE9DEAD613C4077B4DEE7DA9D532A2D65A8D6E2DEA03B0000092D5F8BB5BF8C4414133A85CFCBA8A7AF934D170919539DD0E4DBE0A4906A300D338FBDDAD9D3D1D9C59A43120F060B1C4E95BDCAC1AA60120915251B214C8FB8D5DCD2B17C664A3A5293BEC9C9C8C2AFAE6B21031E73ACBDB7BBB2AEA18131417A99A8A0939A916944000000000000000000000000000000007D8883430600000000024A97B9B79D60240003212D4A84B4DDE6DBC4976345402F2B3F6AA2D3E1CFCAB4A26221000000000466C0D6D8B2843E160C080E3B6EBA240003212D4A84B401FE8C5C070718C07096C5FFFFFFD08B5A3D587FAFD0E6DBB35939406CACE0F0D98B47283573B6E1E9D3952E0B00052A5F87BECE95450F204895D1CCA9A8A6843E0F06224F9DCBE8E7D7B6A66E2C0E4098C9D1D0C8C2C2C6904611071018244F89ACC5BBA4591509253022235098B4CAD5D1A16D5B3A366490BFC9D2CCC6C8AE6616002474A7C2C5B2B4AEA87A394284A5ABA19C9088784B00000000000000000000000000000000767765340000000000075794BBBE8E4B16000B152B4E7CAFD1DACBBE9E6C4B462D2F2B64A3CEE0D5C9B390651A00000000116AC1DECDAB78380A0015103371C316000B152B4E7CAF01FE8D5C070718D07B99D0FFFFFFC88055435B89C3E5EBE09C4F354670B2DBDED5904E29376EBCE1E1D58E28000003375C7EB3C8934B161D4BA3D8CFA9A3AB8F511D0B2354A0D2EDDEDBBC966B2B0C4091C3D3D9D6CDC7B583390F040D1A255093BCC2B9965A1911253D2628478EB3D4D3D6A76551383F6597BCCED6C0C4BFB06419002F80AFB8BDBCB6B2A87D37407AA7ABA9A19289724900000000000000000000000000000000897C6D3E00000000001759A5CAC1945C25071E1F2F558AC2E0E6D9C69B6C46322E25386DB0DDEAD6BBA9955D0D000000000D80C9DACFA878370B000A112C7ACA25071E1F2F558AC201FE8E5C070718E07991DDFFFFFFC57D483F5B83BEE9DFCC9A57273C70AEDEEFD489482A3972BAE1DFD1882900000F375C84B5C59D42171E56A3DADAA6ADAD803A13091B5597CBE4DFDBB49D5F231146A1C1CCD4C8C2C5B98A3507100B152D5B98BBBFBD9A57151C2846271D4A8ABBD5E3D8AB714A374276A5BCCCC6C8C7BDAA651E0A3175A7B7B9B4B3B09F6F35478AA8B1A6968F8278440000000000000000000000000000000088856E41000000000000358EBDBF9B5A20132325365C80B9DED4DCB795663F302830376DB1D6ECD6BFAD95661D000000001C67C3D8CF9F742F0606151A316DCB20132325365C80B901FE8F5C070718F079A8DDFFFFFFC07C53486298C1DDDCC78A4A304179B8E5EFD3833E203E73BADDE2CA85270000122F5A7BBCCB984F222856A7D9DBB5AFAA7A350606215397D3E0DFD1BFA76728124BA1C5D2CCBDC2C8C4813C0C0D1D292F589ABAC2BA9B4F0F0B3043232F5593B7D4E2D7A05D44334474A4BABEC6C9BEB1AC6311053988BBC8BBB4AFAFA3672D448FA3A7A59E8F937C460000000000000000000000000000000075725A280000000000005090B9B48D4610091D12274D87BED6E2D9BD935D3626211E3679B4E1E9D9BEB497621C00000000267AC4D6D19A602808000D102A7CD310091D12274D87BE01FE905C07071800608FC7FFFFF6B96E453E5891C5D7DBB978482B376DAFDFEACD8038264175C4E8E5CC7D22000009315187B7C49347212E64B0DECFA9ADA578340A001B5A9BD4E7ECE2BC985518054AACC3CACFC3C0CDBD8E3E05051B272D5F9EC3C6B699491619313A1B284C8FB9D3D5D39C583C2D4181A3C1C5C0C7C4B1A762140B4083B6C1BCB6ADADA577345588A7ADA6A28D80734E00000000000000000000000000000000806B532A00000000001059A1C2AE864D1C14231F2E599CBEE1D5D1B3905B29151C252E6FB5DCE5D6C3AA99601000000000257EC4D6CE935F2C08000A142F76CE1C14231F2E599CBE01FE915C070718106F91D4FFFFF7BB6F55476C9DD4E0E5BD7D41293666AFD4EAD8843F2D4173BBE6E9C9801E00090D345E8CB9CA9446192B5AB0DFDCB3B2AD6F2902081E5495CBE6E1DCC09B4E180C49A1CEC8D2C1C3C4AE7531110C19353759A5C6CDB7944E11143A42292A5094BDC9E4D29C5933324E82B5BFBEC5C6C2C1A2530F053F9AB3BEB2ADA9ABA269355D93A6B79D9993917543000000000000000000000000000000007D6F541F00000000000B619FB4B78349221C1D1A245885BCD1D7C3928C5F3A1B1921437FB7DBDCD8BFBB916014000000002C88CAD9C28F462008010B162C74D5221C1D1A245885BC01FE925C070718207C92CBFFFFF6B37548436DAACEDDE2B6703F283A6CABDADFD37B472D3C7AC0EAECC7741F000616335B8CBDCC9B47203664B7DDD7B9B5A76B2403001E549ECBDFE6E2C493460E0F51AAC8CBC8C0C4C0C07F2C0A0E223B395FA0C8C7B4943F09193A46292B4E95C4DED0C8874C2A2A488AB1C0CACCCEC5BD9D520D154E99BBB8BFBBAD9F9263314F84A7B1AC9F918C784400000000000000000000000000000000746A4F220000000000176BA2BDB0834F1F181A1C295189B9D1D1C5BC834A1A0D1426417DB3E4E9D2B7A7925813000000003489BDD1BD8D551F0A0211113483D41F181A1C295189B901FE935C070718307598CCFFFFE8B0734C4471A5D7DEDDB86932294567A5DBEAC7813425417CCCE3E8D170170200133B538DBBC79C4B232E6BBDE7DFCAB4A5602000001F5993D1E4F0E6C799471A124EB3C7CFBCB4C6CEBE722D0F14333A3960AAC4BEB8944410072D42252A5494C3D2D9C89045242D4E91BACCC6BFC0BEB39F48110D5099B3BEADADA9AE9F5D486498A7B6ACA79D937D4600000000000000000000000000000000785C4A1E0000000000226CAABCB68D4C2024211A275D8EC2D1D2C8B58B482208051E4E86C1DFE0CEB4AF8A531C000000003690C8D8BB904F1200001011357FD42024211A275D8EC201FE945C07071840759DDAFFFEE09A5E434E79AFD6DEDBAA6A36292E6BA3DDE7C36F33274484C5E5E6BF681B020C13315A8CC3D29642223370BBE3E6C3CAAC5F1B0104165096C2E0E1E2C68D40111056B1C6C3BAB8C3CFC071240D1C2F3D3B63B0CFC5BA8A420E0F39442D304C91C4D4D5C6823E21235595BBC8CCC8CBCBC39C510A0E569DBDBEBEBBB5A9955F345C93ACAA9D9892826D3F00000000000000000000000000000000675B3D0B00000000002C73A5B2A785511B12261D2C5584B5CBD2CCAE79431E04001C458BB9DEE7D2C6BA9D550D00000000438FC1D0C6844B1A050008102E8BD61B12261D2C5584B501FE955C0707185082A6D7FFFFE7A065504A79BDDAEAE3AF6836283862AADFF1CF6E312B4986C5E3E0C17320000C213A5E91C3C48D4329397BC3E6E9CBCAA0580B0002155E96CADDE2DCC595410C0E55ABCCC0BFB1C3CFAE6523040A344C4867ABCAC3B3954D121239362F385EA4BAC8C7B97741252F65A0BCCACFC5C2C8B1953E0B105196B9B4BFB5B4A99565356293ABADB0A29D8D723A00000000000000000000000000000000736C3B0F00000000002671A9B9AA884C211F221E315391BFCECFBAA072320A001024488AB7E0E1CEB0B1934A15000000003394B8D4C3864113050B1018398CE7211F221E315391BF01FE965C070718607B98D7FAFFDFAB65464C76B8E5E2DBA0532521416DA9DDE9C57133284C8BC8EBE1B45C19000D31445789C8C68A4227346FC8EAE0CFCBA654130000285F9FC6E3E4DBBF903B120D52A9C1BEB09EB5D0BA632C1A1D38574D69A7C6BFAF8842181B3F472736669ECBCECEB879391E365EA0BDC7C3C6C8BCB39641091559A0BEBDBBB4B2AF935D3B6195A8AFA79F929075350000000000000000000000000000000075663B0D00000000003B7DAEB8A97E4E0A0F292743669AC6D4CABDA6782F000000194788C1DAE0D4BCB0915F19000000004295CBD2C086410E090F2013749EE60A0F292743669AC601FE975C070718707497D9FAF5DB9A573C4B7EC2ECEFD69C52301E3463ABD8DDBE70322A518FCFEADCB2611A080E1E385D94CFC897412B3981D4E7D9C8C9A8541000001F5EA2C1D9E6DEBD8B3E121459AAC0BEADA0B1C5BD692A09244156416BAEC4C5BC8A421C1E3A3A28345B9ECCCBC9A96638253366ACC3C5C2CBC3C3B58F4009195BA6BEC4B6ACA5A0965939649EB1ABA69B978D6F33000000000000000000000000000000006A5B36000000000000367CA7B4A88148191A2A2D497194BECBCDB5A76B150000002B5698C8E8DECBB9B38F5721000000034399D3D7AD7A3D110310101F3D99E9191A2A2D497194BE01FE985C07071880749AD1FAF7D389503A4C81C7EBF1DC9D4620233A6DB2D4E8C1703424468ACCECDDA96218000C27496791CAD28C3A234286D9FCE8C9CCA7600D00001B589BCDE4EAE7C68937020E51A4BCA58E89B1CAB75F2E182F4E61546DA1BCC8C094391314373930366BA2D0D5CBB2612C1B2168ACD5CDC0CAC8B4A98A3E0F195E99AFB9BDB4AEA78B533F7398AAB2ADA4958B743B000000000000000000000000000000006F5B4F00000000000E5285AAAF99773D10122726476C9BBFD1D0B39864230000002B5792CADFE0CFB1AC89642100000009569FD1D3BC7F45160006111248A4E110122726476C9BBF01FE995C070718907AA1D7F6FBD1915940417FB7E6EDDB97522A27416FADD0E3BD652B245497D6ECDBB55809020D2C476699C3CB86462B3C89D2E9D7BFC0A74C0F00002056A0C9D1E6E4C5843608145BAEBDAE8D8DADC4B2662A2C325A65516AAAC1BFB98C3D091A2F392F4473B3CDCDC4AC642D1E3169B1C5C9BDC4BFBCB08F37081963A2B1B8B9C1ABA6965F4A6F94A5A69F9D8F90772C000000000000000000000000000000006E564105000000001E5892B9BBA67F3B10180029497BA6C9D0CCAF8A5C18000002275AA0CBE4E4CEB5B2894E160000000E61A3DCDFB3743008000613375291E610180029497BA6C901FE9A5C070718A07099D1F2EBD187463C4B86CCE2ECD2905226223961A9DFDDB8662A2D52A0CCE7DB9A450A061623526498C8CA823B254587D0E4DACAC5A0461400001D659AC8DEDDE2C58C32090F5AADBAA18B90AEC6B9632A193F69705871A3BCC9BF97380D20313C314575A9C3C8C2AD6130173078B5C2D2C3C5BAB1A17B2B12276EA0B1B6B8B1BCB285504873A4B2ADAAA89F9D792F0000000000000000000000000000000062402000000000001E528AAEAD95793F0F0C1A31467FA5BFC9C3AF8A5718000000315E96F3F2E4C9AFB788440C0000001767A5D4CBAE6B330D0017111D55A2E60F0C1A31467FA5BF01FE9B5C070718B06E9FBEE0EBCB7744424E88D2EEE9D9964A28213E6FA9D3E3B96822265498DAEFD29741060316364E6C98C7B97F3B294590CCE6D9D3C698510E0000256BA7C6DADCD1BF7D2E091058A3AD8F7E80B5D7BF6935243C6D79586CA4BDBFB996380D0C2E35315678B4D2CCC495561F103682C1CFD0CECAC5C4B06C230E236DA3B6BAB3B3B0A582494A7495A8B2AAA399917327000000000000000000000000000000006D572C00000000003B629BADCFB578420C03193A5582A3BCC5BBA37F53160000062C66A0D1E8E2C7AAB17E4B1B000000225FAAD6D5AD672F0904070C225AB6ED0C03193A5582A3BC01FE9C5C070718C070A4C4D7E9B77544384990D8EBE6CE93451F1E3D6DB7DBE2C164262C5B9FD8E0C8823D0405173A5370A2BCBE722E2C3D8ACAEEE3D0C8924D0700052570ADCBD8E6DBC08123000E579BAA8C6F78AACEBB5B29254175765B60B0C7CABD9B3B1013293A345481B8CDD4C090441E0E3381C8DFCACCC4BFC1A26E2E062873A6B9C2C5AFAC987D4B487CA7ADA3A7A09B997923000000000000000000000000000000006C531E00000000003473A4C0B78869370C07263D548AA9C9CFC09C7E46050000133C7095C9DFDECBA7AD844C1E000000296AB1E1CBAF6F2A070002101B61B2EA0C07263D548AA9C901FE9D5C070718D0729FC8D8E7BA73443C579CD7ECE7BE8945211C3B6AB4DDEBB0582F2D60AFDADBC27D3504071B486280ACC9B77028214199C7E3DAD2C78D420B0009246CA9CDE1DEE4BA7722020D4A9AAE8D6B7BADCBC06D312A42717C606EABBFC0B396450B0D283A395990C7CBCABD964B200F3A8ABEC7CDC7C1C9C1A86F24022B7DA6B4B7B1A8ACA97F484C7BA1AEB1A2A6A0947A25000000000000000000000000000000006646200000000000386996AFB69B6A2000041D396883AFC3D0BEA47B43020006103A74A8D2DEE3C3A7AE8452170000002F71BADBD6B26D2C0300000E1B53B0EB00041D396883AFC301FE9E5C070718E06FA8CBE0DFBB7A433A569BD8EDE9C8894721203C72B2D8E5B450223367ACD9DABF823807072748637FA0C6B068271F4CA0D4E0E0D0C98C4A0500002F76A8C9E3DCD6BF7223000A53A3A58B6174B2CDC0632F2851818C5D62AAC3C9C399370C0E2A2C427391C0CFC8BA8E441C0F3887CACED2CDC1B9ADA0681B092F7AAAB8B9B7B5B2A26D4B558DABAFB3A4A69BA275240000000000000000000000000000000069481800000000004480A1BEBA956D2E0402143B6585B8CDCBBE9B723D010000144B7AA7DFE9DABF9DA9844B170000002F6EB5D6CDB26D190000040C215FB4EA0402143B6585B8CD01FE9F5C070718F07A9DC5DACDB274443E539EDFEBE4C982441D1B4680BCE6E1AE541F2E6DB1E0D8AE6B29030F2C56717EA2BBA7652F28559ED2E9DFC7C68C4B0B00002F72A7CEDBDCD1BB7922000C5296917C5A6AA9CABD662D275C919165659CBAC0C1943E090926375479A3C3D3C4B5843B19113B99CFCECCCDC1BFBB9C580E04338EADBFBDB1B6AEA375545084A5B2AD9D99928E621700000000000000000000000000000000644A1E00000000014B8BA4B8BA9268320000153C6FA1B8C7D0C19C7F3A0000001A487EB5C9E4DAC0AAAC864B12000007387CAED2D0AB68270400020F2160BDEC0000153C6FA1B8C701FEA05C070718006EACC8D4D5A76535324C98DBEEE5C682401C21477BBAE2E5A84B1D2D69AAD5D8B6662900021C587B86AFC6A1622D2B4EA6D9EDD4D1BB813A0600072E89B0D9DED4D3BF7B1E000A44938D6B5F6EACD4B669313B61948D5C5299C0C6B890470A0F1F2F537C9FB8CBCEAE753D231B4091CBC7CCC8CEC7B6904D0F023380A7C1BDA9AEAEAC7D595688A5B0B5ABA8A6957011000000000000000000000000000000005C390200000000075186ABB7C0A66A2900000D347495B7CEC6AD8A6731000006294873B2D3E1D5B399A67E4B080000084082C2E0CF98732E030001091B64BBED00000D347495B7CE01FEA15C0707181070A7CFD5D9AE623C3B5B9EE6F4EFD07E3C1A1C447EBFDEE6A749223B74C6DCDBA5581E000E2C627F91ACCAA35C262155A4D1DBD0BDB8844C1000053872ADDAD9DCD9BB7B23001148968B6B5C71ABCEBD663D30629A965E6C9BCBCAB9953B06051F35527DAAC8C7BAA86E35141E5091C5D6D3CEC5BFB69D4308033789B1C2C2BCBCBBA07653588BA4B0AD9F979B8E69140000000000000000000000000000000061310000000000084E87A5B2AA945B25000016467B99B3CDC9B88E622C000000294883BADBD2D7C497A78143110000104988B9DDC4A6661C03000908226FBCEB000016467B99B3CD01FEA25C0707182070A5D2D2D5A85B312C56A0D7F3EEC77F3F1E264990C5E6DB94451B3C7DC9ECDFA25E17000A325F8598B0CA9341262B529CD3DCD4C2B48B441200073684B4D3DAD9D2B76B1D03073D8B815B526DA7D6B0613C3D71A4975B5F97BFC8C09543120C1C325A8BB6D0C1B4A465280B15569FC9D6D2CCC7C6B58D480C0D4799AEB9BBB8B0AA9C7B5A6B95A9A8A49BA19C855B050000000000000000000000000000000063410E00000000146392B8BAB29B602500001D487DA8C3D1B3A375572A000009285D96C2CADBCAB08EB27F4B2001000F518DC5D3C4A75F250000040A2571B7EB00001D487DA8C3D101FEA35C0707183073A0BAD8D59A612A2D4898DFEEDFB9752F17224B98C2DFD49442273676BFD8D9A45618000E36668998B6BD854F1B2954A3D7E7D0C1B27D380100053C87B7CBCEC6C8B4731E00003F7F7F61506BB1DCBB6D3D376AA297635E9FBFC5BD92430E0620376FA5C0CBBBBD9F5C2013185395CCD7CFCFC2BEC2974407034493B3BEC5BFBFAAA373646E93A1ABA89E9D918F5E130000000000000000000000000000000055260100000000095786A3B4AD8159180500144582A0BFC6BB9F856224000007295B8BB1D8DCDFB78CA468351900021E5296C8DBCDAB5E1B01000200206CB9F30500144582A0BFC601FEA45C0707184076ACCAD5D2A1532E3155A1E1E9EEBF7534232E5189C6DDC58A43193884C4E1E2944C1C001540769497A7AB793D24315F9FD5DFE2C9B173410800074085BEDCDACBD5BC731C00003B76705C4F72B3D5B55D303979A29B5E608EB3C6BA93340202113C6AA8C8D1C1C0A3562513164E9FCAD4CAD5CCC5BE813100114E98B7C7BEB7BAB3A973646A8CA5AEA3A6A591915D000000000000000000000000000000000063380A00000000016599B2BBAD8E5F250100164082ABB9D7C9A56B421900001337638DBED9DFD6B482AD6C3C160006266196B8CEAB96611C0000000A2F70BCF00100164082ABB9D701FEA55C070718507CB2D0E8DA9F5E3537529BE7F0E8B46E2F192E5D97C6DFC97B361D3B87CDDCD5994B12000E377894A9BBBA794016265AAAD0D6CDCBB585381100103B88C5CDD1CCCCB07414000033747061527AB0D5BE68394075A99C5A5684B4CBB589380A0D124371A9CBD6C5BD9B50180E1852A1C9CFC4CFD0CDBC832E010F5AA8C6C6C5C3B2ADA06A646990A5B6AEA49F9B87530000000000000000000000000000000000643300000000000E639CB5B4AE865B2300000F4876B2BFCBC5A97344150000002B7090B8CCDCD2B188AD78451A020D2664A8CEDCC59F581B000000102E6EB1DF00000F4876B2BFCB01FEA65C0707186074ADCEDED19E5A1F2655A5E8EDE0B85F291B335B97C4DBC485381A4A97C7D5C2863E1100083A82AAB0BBA46E32193162A9DCE3DBC4AF803E08000C3E8DC0D3CAC6C5B06D1A00002B6869655D7DB9E1B1603A457BAA9F534B8DBDC1B6893913101D4282B1CACEBEB9915020152053A5D4D7D5C6C9D3B87F24000461AFB9BEBCB9B5A9A069647183A6B1B5A9A1998C4D00000000000000000000000000000000005A2E0000000000196EA2B8B09F93612100000C427CA8C2CEC9A1723B0800000A377198C2E0D5C79B7EA86F2F130C042F68A6D4E3D0AA6318000000153778B4E200000C427CA8C2CE01FEA75C070718707BABDFEDCF9A522A30599ED4EAE7B66624203A5A9BCCD1C27C3722449CCEE4CA893D0F001A4080B0B4BEA669301A2D68AAD0D7D9D0AF7C3F09000D4591C8CDC4C0C2BA691600002A5962545B85BBDBA55C39477EAB9A5F4F82BBC5C68F3E040517508DBEDADAB5B1893A100F1A5CAAD7D9D4C1C7C8AE732200146BA7BFC7BBBBB9B3976F73768DAEB0AAA4A59C904500000000000000000000000000000000006E3700000000002F7CA0B8BAB58E58220000164780B5D7D6C19C623010000011427094BDD8E3CB9F80A6652E1D0A1D4373B2D3D9CBA6581A00000510316BBCE90000164780B5D7D601FEA85C0707188077B2D9F3D3925429295098D7E6E5B364271B3464A3CBDABB6B352A5097CFD6C9873F1000185187A6B1AE9A6121102677B2D1E3D9D0B67C3703000D458DBACEC5B7C4B55F1500002757585D5F79BDE0B260364E81BAA067598EB2C3BC812E040518468BB6CED8BDBC8C42140E205FB9D7D3D2C6C8C6B2691E001365AAC5C9BABAC2B89F74737085A8B0A7A7A0958744000000000000000000000000000000000054250000000000096AA7BAA59C7B611F0000094B8ABAC3CCBB91632F0B00000C3F759AC8DBDECCA376B572431807113F76B2D6E2CC9D5D1600000014316DA8DF0000094B8ABAC3CC01FEA95C070718907CAFE1E8D89754292945A1DAE7E2AA5D1B152B5EA7C7D0B05E282249A9EDE6D08A360209174C89ADC0BA9A61260B2671B5D9E7D5CAAD7A39050014478ECACDC1B5BDA65D1200001F4A5D5E6591C5D7AB573A4386AB9A544F82B4BEB78F380010235792BDC9C4BABC8C4112102466B2D5CFCAC0C0C3AD631500186CB3C0D0CBBCBEB7996866728AA6ABA99CA89C8D450000000000000000000000000000000000633200000000001A76A3C1B1A1865A2800000F3F81B3CCCFB193581C0F00001B4580A6C8DCD2D0A379B06B3A0B0B1D477BBAE0E1CAA05617000005143E73A9DD00000F3F81B3CCCF01FEAA5C070718A072B1D8E2D19549292B4F9CDBEDEAAE552711326BABC7C6B16E2A295EAED4D4C6873705001E5192B6BFB089421A153372B6D4E0D7C8B27C370100114F9ECAC1BBBAB9A660190002214E58596893C1E2B258303D8BB2A05F507EA7BBB4742A0B0B1C5698C8D4CAB7AD823C1709226EBADFDAD3C4C2C4B9660E002173B0C4CDCBC2C3B19A78756D899AAAADA2A28886430000000000000000000000000000000000633100000000001A6D9FABAC9D89572600000E4189C3CBCFB583542100000013487EAFD4DEDDCD9C6EAF663815021B4C88BCE1D9BFA267230300031A3F70ACDE00000E4189C3CBCF01FEAB5C070718B07CB9E4E9C889422432499BDFF8DAA255241A346EABC8CCA0611F2364BBE0ECD2812F00000A4E96B6C2B1803A160B2B6AB4CADBD7C3B4883D080017549AC3C7B5B5B8A8570C00002D4C5A616C9BBEDEB452354C86B69D5D5085B0BDB46F210001195FA3C2CBD5C7BD803211131E66AED0DBCBB8C3C19D570B002A7EB6C3C9C5B9B4B6A97A79758CB0ABAFAAA6A08D460000000001030000000000000000000000652A0000000000217CAAB7A697844E2100000C4181B9CDCAB28A4B1D0000001A4976A6D3DDD3C19363AE6F411F151D4885B4D9D8C59D63210000091C3E6CADD600000C4181B9CDCA01FEAC5C070718C078ADD9EBCF894B2531519BD5E5D4924D19112D73AED1BE944D19245DB6E2DEC379320100205A9DB7D2B2824017153A73ACD9E1D6CDB9783705001B5C9FC4C2B1A2A69D4B0C0000224C615D6A98CCDD9F4A2E4790B3A8635A87B1B1A66F2100001668B0D0DAD6B9B97A2D10132871BADCE3D1BFBFC4AC530E00217DC4C6C8BCBEB8B093766D6D8AA5AAAEAEAAA28E3E00000000030600000000000000000000005F2500000000002B779FAB90846B461D0000024187C3D2CAB6824A1700000420457CB0D6DECEBF8C6CAD734B190A1F5496CBE4DFC6985B25050000264369A7D20000024187C3D2CA01FEAD5C070718D073AEDAE7D18D4D223159A0D8EADDA247191D3B73B9D5BB8C4D202971BFE0E0C78131010021599BBAC9B276320E08326EB0D8E6DAC7B47D3500011A5FA5C8C5B5A49E974D0A0000144C6C737A9BC7DDA14A344897BCA7695185ABB5A05F1800022A72B8D8D0D1BDBE81360A052976BCE1CDC6B0BEBDA44604002E89B8C9C4BCBEC0BB977A6C6E8BA5A7B0AC9E937E4600000000060000000000000000000000005B2400000000003586B1A99480645220030012427FB3CBC4A7823F0E0000001F5182B3D8D9D2BD8D66B0724520111A4B8BC8E8E7CAA15B320A0114385A749CCA030012427FB3CBC401FEAE5C070718E073AED1E6CF8740252C55A2DFE7DF9943171B3C88BACBBE89441F336EC2E4E2C6792E05001E63A6C3C4B36A3110133077C3D5DFD3C6B386400A0010599FC4C6AEA9AA9243000000214E6C7D869AD5E3A046294592C0A45E5486A9B099661D000D276BB8D9D6CFBFB875310B132974BBDAD2BFB4B8BC9D4806002E83BDCDCDBFB9ABAEA17C656886B1B1B1A6A99D8D4600000000040000000000000000000000005B2000000000003482A4A78D7669481A02000C3280B7D0BFA37E3E0D0000041A4281AFCED8CEB18462A86A4B2313205D99CBDDDDC99D5E2C020617455C7EB6D602000C3280B7D0BF01FEAF5C070718F080B5E5F3CE8841282B55A4DFEFE290461C1F4084BED4BB793F293471C6EAE3C1702404002261A0BDC8AD6C2A0B153174B5D7E2D3C3BB8C4204001D5999C1C2A69EA99849000000174F6D7E81A4C6D1984B224A95BFA46A5E95AEB498541000062E80C7DDCAC5B5C280300E132F80C9D6CCBBAEC2BE984400003195C1CFD2C7C2B4B1916965688EB0B1AFA0A1988A4600000003140800000000000000000000004F2000000000002E81A4AB8B715C441E00000A367DB3CEC69E733C00000000295088BAD7D3D3B68066AF79532F23255299C7E7E2C3935C2C08011F4B6477A0CB00000A367DB3CEC601FEB05C0707180077B1D1D9CA88411624539CD9E5D786461F1C4990BDC8B27230182B75C1EEE9C373200200225EA8C5C6A964200C0E3078BDC7D5CCBCB18C4412052761A0C9CDAA9DA3893F000000205573848DAACED8943C2D4990B6A4695D8AAEAF84490C00032C88BBD6DCD5CDBA72361010337FC0D5D7C3AEAFB7984200003E95C4CFC5C3BBB4AE906F6A688AA5B7B5B0AE948E3A0000000E191002000000000000000000005610000000000031809BA5836F583A120601032E7CB5D1C9A774390C000000234787BBD0D4D0A88C5DB37D5A2E1626589DCBE7E3BF98613812001B566D80A8CE0601032E7CB5D1C901FEB15C0707181079B4E2E3C27A392126569FD2DFCE7E3810204795BBCCA87537223378C8EDE8BA702400052969B6C5CAA35F1E000E336DB6C4D5CBC5B386460B0B275C9DC9C6A7A5A2853B00000020557C8999A3D5D18333294C95BDAB685E8AA9A684420500053186CCE2DAD4BBB072300D123785D0E1DCCEAEB6BF99430300459EBAC3CBC4BFBBAD8F746B6A8BA1AFB19DA698894000000008100F0000000000000000000000582100000000003C81A89D846C553E1E0E08173D86BCD0C1996B300B000001204684BDD5DACAB67E56A27F5A3F182467A8CDE1E7CC975333160F265F6A709FCA0E08173D86BCD0C101FEB25C0707182073B0D2E7BA702A122454A3D0DAC17D381F28589DC3CCAA6726182F7DC8E8E5BD681601002876B0BDB89F631A0413387ABBDBDCD8CFBE893D060028609DBDCAAA999A7631000000245D869DA2BED4C181382F549EBEA3645E94B1A5742E0000022B8CC4D7D2CEC5BC7C38181E327FD2E3D7C5B0B7B28B2D00004597C2C4C0C4BDB7B88E76686089A0A9B0A8A59C87440000000B12140E00000000000000000000501E00000000004086A79C7A5949311601031A377FC2CFC09362240100070D3E5F91B7D0D4CDA36F53AE785D31112660A0D3E6DCC3985C33120722607983A8C901031A377FC2CFC001FEB35C070718306CAACFDCBC6C321C2F64AADBE2C07D3615245AA7CEC79E6021153381CEE9E5C26B2600032C79B6C6C49F5F200709356DBED2DAD5C1B88E3E17143468A3BEC1A6938F6728000000226D92A1A3B4CCBB792221549CBEA8796990B1A570260000003284BCCFD4D1C8BA793310153894CDE2DAC2B2BFB78730000154A1C2C2C7BCB3A3AAA5816D62809FAEAFAAA4938B3D000000172621010000000000000000000054250000000000428DB0997559422B07030F1C3B86C5CAB58D642C070000042A5591C3D2D0C3A3775FB186633B262F62A7DEF6DFC48F5A3717021B677D849EBC030F1C3B86C5CAB501FEB45C0707184078ADD1DAAE672B1A2952A2D3D6BC82300D245FAAC9BE9C5E23173876D1E6DEC96D1C00003584C2D6BDA7591700093781B3D3D6BBBCB3933E100731649BB1C19DA29968240000002D6298AEB1C4D7C36C1E1A4A9ABCB47E6A8FAEA1692C030005358AC4D7DDD4C2B270271010348CC3DED8BFB0C0B6832D000350A3C0CDBFBAB2BDAAA58C676483A0ACB1A6A1A0943E000000232F180400000000000000000000562100000000004484A99773443A30141218254A8DC8CBB78457210400000B234F8CBDD3DCBE977859B286643B162964AFD3F2EAC292633E26053A6F7F85A1C21218254A8DC8CBB701FEB55C0707185076AAD2D3A96E39152C4A9BC9D6B1733D162368B3CEC89F501D0C358DD2E4EABE5D1901063983BCBEBD9D5D200313376FAFCBD6D5BAA68B46131A3D7CA7BABFA7898C5D18000000347694B3B0B9D0C5672019529FC5B7816F9DB6A9651E000008428FBEDEDFD1C3AF6A2A15153D92CDD3CDB9ACBDB78020001067AFC4C3BAB0B4B1A78D79655F83ACB4B2B0A9A18A3E0000001E33200D000000000000000000005A2F00000000094E8CA796693C392C1A0C0B194494C4CEB3845027040100091F5192C4D7D8BF946B57BB885A421E3269AEDBF2E7CB9C64411C0F33727F8FADC10C0B194494C4CEB301FEB65C070718607CAECCD7AC52281B285C9DD2DABB6F2B212A67A9CCC1975420254082CAE3EDBC541700033C7CBCC5BCA45A1201133175B1D9D1C5C2AB893708144274A5B3BCA9A8835F110000024088A6BEC0C5C8B1601E1954A9C5B28270A2CBA3541A0000003E96C7D0D6D1C3B1692806114091C4DFD8C2ACBFB37322001563A6BFBEB9BBB7B2B29F745963879AAFABA4AA9B834000000022422907000000000000000000004D250000000000478DA4986B322510080C0B1D3C88CACCB3804C1C000000112A529BC6D0CBC098715BB28162381A2E70B1DDF5E5C38C583C291A437E8087ADBC0C0B1D3C88CACCB301FEB75C070718707FA3C2CE9D59241320619AD2CEB46B2E15316CB1C9C38B441A163E79CFE5DCB35A13000A3E88C5C8C39E5C0D000C3974ACD6D0C7BFAC86340D224F7CA1B8BFAF97804D18000005408DAEBCBAC9C8A85D171E58A7C8AE827896BE9B4C0C000001379AD1E3DBDAC7AC611C04123E9CD0DBD4C2BFC3B66E18001162A2C6C4CBC0BCAEB092765B5E7EA1A2B0ADA39E7B2E0000042E433312000000000000000000005B2000000000084E8EA18E5C3016110E0B151A3A82C1C9AD7043150108040B244C9BBFD4D7C2996D5AB3896845213568B1DDE8D6BE88634C2D183788888AADB10B151A3A82C1C9AD01FEB85C0707188074A6B5C08D4A17152F61ACD2CEAD6325133571A9C6BC8E3E10193787D0E7E6B85B1200134F86B7BEAF9F5F1900083373ACCFD2CDC1B681360E134B82B1B7B9AE967C461200000D4A83A9BBD0C0C39F49161757A2BFB293809EBD9852090000003A9FD0D9D9D1C4B2682E1413439AD0D9CEC9BBB7B96615000E6EA7C1BCBEB8BAB7A19A765065849CA7ABB29F988F3500000A353F240F0000000000000000000054230000000013639FA38F5830100F102426274090BFB9A56C340D070C08102C5395BAD2D3B9936C50B0896E47212F6AB8E7F0E5B58C5F432C265388868DA6B02426274090BFB9A501FEB95C0707189074A2B7B1974D1D0D2C63A2D1CCAC5E291F3A7EB3C6BB853B0C153D8BCEE5E2AB561903124893BABFB39B4E100004376EAFCADEC5C2AC823B142967899DB3B5A69E78390600000F4DA0B5C7CBC2C69B3B071752ACBEB98D82A5C09A470600000E4097C7D6C5CBC2B268280D1341A0CDE8D6C5C1BBB36919001679B3C4CABBB1B4B6A591794E668AA0A9B0ADA29A863A000018374A3113000000000000000000004D26000000001357928F80552509050B19252A4289C4BFA06833080106040C245FA8BBD4CFBC946655AC795E442B3472BBE7F5E8B48F61422C1A4888888FA0AA19252A4289C4BFA001FEBA5C070718A07392B8B57E2E0B062F66B1D2CBA450180E3D80BED6B9823413113F93CFE3DFB94E13000D5893B1B3AB97501200063877B3CAC7C3BBB07E3B101F5B8BA8AFAAA59675340C00000656AAC3C4CEC1C394421A2257A5C3BC8D7EA8B5A245080000074595C9D6CFDABFA963261215509CC9E1D4C9BCBBAA5E0E00247CB6C1B7B9BAC0B1A6966656638CA1B0B0989A9D7F3000001641523B0E0000000000000000000062370000000026649B9D8D4A1E010011252C234690C7C398662F0A060801122760AABDD6D1BC996D57AC8E6646273676BFE5F3E0B98463473D1D548C8B97A39F252C234690C7C39801FEBB5C070718B08095B4B082321916356FB4CCC4A458231A3A86C8D9C2823215114085D7E5D8AF510D00195891C0BDB7975A190012407FABC6CFC5B8AB73340E276B9AA8ADB2A5926C2F0100001254A3C0D3D0C1BA873C061C62AFBDB6898AAEB993470000000B4899BFCCCBD0BDA85928141A4AA3CDDCCDCCCABFA9611600217BB4CAC7B7B8AFACB388644E668FA4B1B4A69F9B7C2000002153624311000000000000000000005A2F00000000306D9A9A7E48150504182A2123448BC1C18E5E280A060C00142764B2C8E3CEA7806059B98B6B4C2C377BBEEAF0D7BA8A63553323517A8093AFA52A2123448BC1C18E01FEBC5C070718C07097ACAD783F12102E7EB7CAC39D5323224085BED3B78731061A4398D1E2E3B4520C03175C96B0ACA4954F0D000C427CB7C8C1BFB7AD7A36122D6E92ACAFAC9E976A2C000000115BACC9D1D3CABA7F380B1D61A5C3BD8E88A4BC983D000000054F9ABECBC7D5B79D5229181D4D9FD0DBCCBFC9C4AE5C09002F84B5C4D2C4B9BBB6A58360536287A9A9ADAB9A96762E000026526C4F1B0000000000000000000057250000000033789BA3844B1904001C352F2A428BB9B490531C0400111510306CB4C6D4D2B1875E54B18372493B4986C6E2EED8B67A5450351F54848DA2B2A2352F2A428BB9B49001FEBD5C070718D07596A9A06D30150A3A77AEC5B7944C1724488EBECEBD833708083D93D9EAE4AE400A002174A5A7A1A697491300134484A8C5C1B2BCB06C33133A74A0A9B7AD9D816429000000195FADD0D6C9C7AF7C2D031765A6BFB79D93B1B88C39020000074A99BBCECCC5B9A45E2919174DA2CFDBD4C9C3BAA24F0D002E87C1C9BEC4C0B4ACAC97694B698DA7A7AFA59693751D00012A63775311000000000000000000005839070000093E75969A6F3D1D0C0B1F3736203F88B2B68C441700070A020B2C66A8C1CFD3B0865253BF8070583D4391C1E7E7CFA986616548325383929DA7983736203F88B2B68C01FEBE5C070718E0809BB7B07D32120F3C85C4CFC38F521A1C4C98C5C7B37734060C3789CBE2E5AF491200206DA0B1A6968D480D001A5486B6C9BCA4AEB06733233580A7A8A6A9A080571A0000002473C0DCE0D6D0B1721F021D61A8C3B09693B5BC9639000000094C9DB9CBDDCCB2964C23122156A6CBE3D7CDCAC5A4470D083A93B7C2BCB7BAB4A3A483654E6696A5ACA9A0A092621E000531667E551300000000000000000000603B00000007427C9CA08B460E0000123331304D95BFB6833E0F000C121514386AA7C1DED8A98D695BB07E725B39498FCAE6E4D3A981594F32285D8D8691AE983331304D95BFB68301FEBF5C070718F07A98ABB2752E050A3C80C4CCAE8A3E15164B9AD2DCC2732A000E4197CFE1E2A54805082E74A3A39D977F3A05081A5082B2C0B6AEB9B3752F102F86B1B1B6A7927D521A0200001E6CBDD9D0D0C0AD6F28000B52AABEBE9E9BB6BE91340000000F559BB6CBD5D2B9954D211A1E4D9AD0DADBCFC7CCA8470C054495AFBEC1C0B3A8ADA171574574929BA2AFA9A08B6A1B000840697C5A22000000000000000000004D26000000003D809F9B874A20080A203C39264D92C3AF7C370000000800103682BBCCDBD1B087655CB97D6558464C8DD0E9E3CBA07A4C574331617A8998A89C3C39264D92C3AF7C01FEC05C070718007DA1ADB0702A0D1E428DC8CDBB8A3D1A265EA2C7DAC5712302094399D4E8E4B743050029709E9DA1987A360704265897B9BEAFA4B3A46D281A4088A6A8B0A78E8554170000052E74BEDBD9D5C2946117001B5BB0C5C69C95AFBE8D33010000004896B9C0CCCAC19757291A2750A2CCDCD7CEC3BD9D410C114A9CBBD0CBBDB1B2AE9B744B476D9DB2ACADA3968B5D23020C3E6F7B491600000000000000000000592E000000053D7E9DA2794311000015323D2C4B9FBDB1733713030F08041B407DB1CED9D2AD846564B983705C4C6091C0E0E2C48B6B5C62422757748BA2AA84323D2C4B9FBDB17301FEC15C070718107596A0AC641E000B3D8EC5CDAC7B3C16195AA5D0D8B96F28000B419ED7DEE7AA4301002D82A4A4989478370D001C5594B7B3A4A4B0AA712A1A4989B4AFB3AC977D51240000032F75BED2D5D4BB9D561200216EAABFC2A8A2B5C191300000000D5195BBCECAC5BB9A56291E2C4F97C7D7CCCCC5CD933A0C235CA0B9C9C9C3B9ABAA9A6F49416F91A9A5AAA1A8855614000A457A774D18000000000000000000005E2F0000000C4177A0A2793A0800001A394136529BB6AB6F370A001C1608174082BAC1DBD1B18C736BAA81706A4A6091C9D4D4BA8A6D5B5A432461848397A98B394136529BB6AB6F01FEC25C070718206E8B9E9C571000093290CBC19C70301C2E5BA7C4CFB6671A02054D97D5E8D9B44002033C7B9D919C997B3F0D001A649DB3B0A498ACA9642E1C4F8EB8B9B19E866B4A2307000A2687BFD2DBD6C68F4914001E63ABCEC5A0ADC3C2842C0000000D5297B1CACECCB8884022151C44A5C6D8DDD6D0CA984108115B9CC2C2C4C5B5ACA89D6446477495A4AAADAEA584521900174D7D78511B00000000000000000000563F0600000D4A83A1A679420F0001184A3D2E509CBCAA6D320C000E1312194294BFCDD7D3AC907270B2786B61556C9EC9DDDCBE8B6952584031607B80949E7E4A3D2E509CBCAA6D01FEC35C0707183071899D9D55190000388CD0D2A9712E162868A8CAD3BC671F010A469CD7E4DBA64308093D8497978B8E653206061F5DA9B9AE9C9AB5AB652C234798B7B8AC9D8D71440900000A3182BECAD9DBBF843F06042769AFC4C8A8A8BEBF882F000000245997ABBAC0C2B49B4F27202B4A93D1DADBCCD0C68F3401195998CCD2CCBFB8A7AC94623D48769EA6ABAEB5977D4814002051736F4C1C00000000000000000000533700000013447BA19D783F0D00001B4C423656A6C2AD6C280300081C0E204D98B9CAD5C8A4A27266B2806F60546A9ECFDFDAB9835E464E2F19577D869D9D8E4C423656A6C2AD6C01FEC45C070718407591AAA9651F00054099CCC89E682F184170B3CFD0B36820000D499DCDD8D1A639050F44919B90878E6A2803012970A4B6A5999AB2AB6133294D9BBEB7B5AA8A67480E00000C388AC0C9D8CEBE84450600236AADC3BEA1A1B7C37F2F0000001D5F91AEC0C0C6B58F4930282B5095C6E1DCD6CFC5983B0A1D6AA4C2C5C4C0B5B3A98D53314D85A1ACA5A79D9A7E3B0D071E507F804A17000000000000000000005E34000000135E95B0A082481600002B56453E60ABC4A85C3010000E1A162351A0C4CED0D5B98D6B60A87D6E6C5E90AECEDBCBB2815C4A4C3A2A607E8694A17B56453E60ABC4A85C01FEC55C070718507394A39C4F15020C3C92C9C5835C271D3C7FB8D1CDB96C190012499FD7E1DBA340050C4294AC9183865B2100002F71A1AAA09497ACA25F2C2F589AB9BFB09E8266400D0A000E429AC1BDCDD6BE7D3B07002570B2C3CFB5B1C5C1832400000011568BA8BDC9C7B98B482C2B2D4B98C7DCD8CDD2BE8F360A1D71BAC5D1CDBEACB2A67C442752839DA1A9ACA19A88420E00215B87744719000000000000000000005E3D1B000A215494BBAF83461200001D4D533E6AA9C39B622900000B1417276AB3CFD2DCD1B38E725FA673606C607DADCCD5D8AB8054454928265D7284A9AC804D533E6AA9C39B6201FEC65C070718607C9BA196480E000C4E9FCFC18C5E1F0B3486B6C9C3AD601B05154EA6DBDBDE9B38081145969E7E898B582201002E7DADB0A1938FAAA356241D549FB9B3AFA182623D120100194D94BDC5D0D3BA772A02053174B2C3CEB6C0C2B976270000001B569AAFC9CED1B88A4A36292D5892C0DED5D6CCC0923C031C6DABC6C1C0B4AEAEA78B4D334F859BA5B1B09E9778370100255D86744E1A000000000000000000004F380F000019578EA59A7A32010000104A423570B0C39E66260B030C1B183277A9C3C9DCD2B3876B5E9869646C6587A6C5DACCAC7E513C442522526C7AA6A1824A423570B0C39E6601FEC75C0707187078979B914E110015519DD1C1874A201E4788C9DAD0BD630D001151A3D3E4D697320B0E4897987F848D531100053282BBBAA39493B3A75E2D2B5096B8B89E98745834160B0B20539DC2C2C7D7BA712F0000266AADC0C9B7C0CFC87A17000000326098ACC4C4C9BB893F22242D549BCFE3DBD2CFC18F2F0B2B7CB3BEC5C0B7BCADA883452B50829DB3ADB5A29C752700042E5E7C69461300000000000000000000664B290005246493A7A573330900001D4A524D7AB0BCA4631809021628193E79B2CECDDDCDB08C71549370687C6F8EB7C5CFC4A77845322D16214F698CA7A17E4A524D7AB0BCA46301FEC85C070718806C839B91440A000B4093BAAF793D12194B90C7D6D6B4590C001355ABD0D9CF9A3A00134A949D8288804D110003388FBEB7998E96BBA1541F2554ACC8C3B2967B5A3A1C0F0A114FA4BDC9CFCBBE652300002E65A5C0BCAEB3BBB56D19000000296E99A8C1C6CEC785422523314A90C7E7D7D3CDBE8D320D3283B8C9D1C3C1B4A09970382852899BADA7B0A39D6A21000B407A94774311000000000000000000005A56391B182B5F96B5A3733C0200072C56575580B9BA9A5B2300000F19164287BED5DAD9CAB98B705A8E6C63717086B3C2CEC2A97950433222194E6B81ABA57556575580B9BA9A5B01FEC95C0707189074888C803F0A00003E9AC0B37B3C1B1D569CC4CDD2B359150015549BCDDDC7882D041556999F7F8C7B461000063683B8C2958B94A79247232254A5C4C5A9906C5733170E0C2660AEBBB1C9D1B46B1D00012E6DAFC6CBBBB8BBB27520000006316A88ADC5CFD7C1883C2B262D4F94C3DAD2CEC3BC83300C358AB7C7C4C6BCC0B49C7832235A8EA7B1ABAFA9955C150011457388733C0D000000000000000000005147351A272F729CB1A171350000002A4D5E5D8AC2B9964D0C00000A1A1F518DB5CBD1DCCFAC91675B895E5775758CAEC2C6BE9F7646352619295C7286A79E764D5E5D8AC2B9964D01FECA5C070718A0778593833A02000545A3C9B9773D151C569AC5D0D2AB5410001651A7D6D0C3883100114A9BA4888582471100003584C1BC9390A4B59C4921254DA3C8BDA4916C58331D130D3166B7C0ADC4D1AA5C2D0000287BB5BDCBB1B6B8B66F160000033D6C91A9BDBFC4B27B443C26344B93CCDBD9D4CFC1822A0C3F8FC5C9C0BBB5B9B0A47930154E899FACADA4A7975D09001146768E73340A00000000000000000000555744221D386F9DB7A97F3C0A00001E4D596288B4BE8E4E1201000B151D5295C8D3D6D8CDA7896B5388565A6F7B98B7C3C5C5A870582E2B102056718AABA0784D596288B4BE8E4E01FECB5C070718B07083907E36000002449EC3AB6D310D1850A4CACBC3A95C1D001256A4CEC9BE833502134F9FA7888976390A0003408EC0C19F9998B1A1501E295EA4BEB09189744D331E1216316FA9BBA7C8D9AB551100002978B4C3C2B3BAC5B265150000083F7A96A6BBCDCBC1753F2D2A374F89BFE3D4D4C7BF8434233A84B6C7CBB5BEB6B7AF76281A5495B2BCB4B9A58D510000094D7C8B6F3D0D000000000000000000005D675B44395086AEB4A581370D00002253586894BBB4944D1C06030F201C58A2C5DFE0DBCFAC8A604A7F555A7C818EA3B5C3C99F70502D2E181E5B6F85A7A66C53586894BBB4944D01FECC5C070718C06F848B763600000041A3CAAC682D1122569EC2CBD1A95307000954A7D8CFBC822501114F9DA28C86703708000F429CC7C79F9499B0974414245BAABAB28B7962582D191D1D2C77C1B9ABC0D3A74E1B00003885B2C8D0BDC0C9B66615000007407D98A5C4C3B7B8763F27232E508BBDDCD3CACCB97722164597C6D1C8B4ACB9B3A169221F5CA1B0B2B3A5A48F5401000C41849A7340150000000000000000000052566C4E415B90AEBE9E7A430A00001E4D6374A0C9BC78430701000C24265DA1C0D3D9E7CFAB81685183534C7A8E989FBBC4C59B693B1F1813245C7993ABA5694D6374A0C9BC784301FECD5C070718D075848B7E2C00000243A0CEB1722C071E60ADDAD9C8A95718001460A8BFCCBE7223000B48979C8E87742E0300153F9FC8C3A39A9DB58F401A1D61ADC0A88376695436272D263877BAB29FC0D2AC4D150000327FA7C5CBB2BBBDB45C0D0000084688A6A9C4C0BEAE68352F2224599BCBD4DDCFCAB56F24144897BCCFC7B7B8B5BAA5681F195A91A7B1A5B29E8E3B00002664888F74320E00000000000000000000576C6C574D619FBFC7A78A3E0F000422505984B4C6B28340160E00001B1E5CAAD3DEE0E0CAB788685477545977869AA3B1C1BD996E3B1D2212225E7C9DB0A26F505984B4C6B2834001FECE5C070718E07984867328000000409EBFA569310A1D68A7CBCCCDB4570B001064ABC8D2AD6F250517548F9B929172320700104A96D1CFB19DA5B38C320D1E599EC1A77E7A6B4E271E2927407FC1AEA2BBC6A5561200004185B6C3CBBAB2C0A4570900000B4E94ADB8BDBEBFB2654131172C5590C7E1DBD9CDBB6828194994BFC7C5ADB4B0A79B5E14186D9EACABB2AB9F803800001E5F909C72310D000000000000000000004F555C504B5893B8BBC5893B04000013506479A5BFB1703D0E0000121C235DADDED6DFD8CAAB89605073574F7893A5B7B5C1BE997C4E461F0D21587896B0A071506479A5BFB1703D01FECF5C070718F07984816A200000003D97C8A55921022363A7CDD3C7AC5404001761AED0C4AC651A00093C8E9C928C763000000F56A5C8C0B1A4A9A97C311B2962A1BA9F7A6B6354362B2E324E8DB4B5AFC8C99D501200003587B5C4B9B4B9C4AF52110000125897ACB1BFC0B5A06336221E26569FC1DBD0CCCABC6E1C15479FD0C5C7B9B3B8B0A7650E165695A6A7AFB0A8812F00002867949467300700000000000000000000555E6F6D697EB0BEC4B074460A00071B4B6181BBCFB2723D110000131D276DB2D6DADFDCD7B59C6B44694B547A8C9FA5AFB8B0A5703C170B0B225D8AA0B5AB6C4B6181BBCFB2723D01FED05C07071800718C86631F00000044A3D9BB672300256AADD0DBD5AA550D00165EADCDD2B16614000844889A96987B3404000F4A9BC3C9ACA3ADB07C2E112B62A2BE99736A6947382E3235458CC9B4AEC1CFA5501300003F96C0C7B3AEB2B6A5560F00000E609DA6B5D1BAC7A75B2F22222F5B98CCDFD7D1C7A966201145A0C6C5CDB1B2B9B29A4F101B6D9DB1ACA9A89A7B2100002F69929B6B330500000000000000000000505C67657484B6D2D6BA803D0F04002E5B6089B5CEA460521606000E202A71C6DEDCDADDD2B08260436541557F9DA4B2ACBCBA95684419160E2F6D91ABAAA0695B6089B5CEA4605201FED15C070718108387815D170000005197C6B0581A011D69C4D6DEC9A6480B001460A2CBC6A05E140001418BA7B1A0772B00000E45A3CCD6BDB79FA7692E152169ACBE95716A654D3B4946334692C0B2A7C3CBA3490E000043A0C0C1C1A0A9C19F530000001D6093A4ACBFCAB8A163382B2A31599ABFDCD4C7C8B761241A57A1C7C9C1B0AAADAA93450A2167A0ADADACB49A751A00002F7394835C3711000000000000000000004F596967638BB3D2D2BB83430B000A1D4F7897BAC5A76026060005191A2875BDDCE3E1D9D1B581492B5D3D598A9FA9AEAEC1B79A5E290903132D6B9CAEB092614F7897BAC5A7602601FED25C070718206F89805D160000004A9ECAAD5B19001F6AB3C9C9C5A84A09001A63ACBEB5A05309000238809CA1A3782B030017549DC1D5B6ADB0A469260E286EB2BEA5746C68413547503F488EBFB7A7C3CBA2480D00004696BEC0A69AA6BCA5560800001B6CA8B5B2BBB5BD924A28261F3257A2C5CCD3CBC3A2561B195BA3C3CAD0B9AEB5ACA04B0D1C69A4B4B4BAAC9D711200002E779A9676370800000000000000000000606E81857DA4C7CED7C78C5216020D2A5677A5C5C99F5A2B090600191C3D84C6E1EED9DECCAC8862345532407E9FADA9B5C8C39E603114100D2B7798B4BA945D5677A5C5C99F5A2B01FED35C070718306A7A754D0A0000004097BCB06221001F6CB1C9D3C4AC4C0C002260A3C4C79E4A040002307DA6B0AA7E2D040011519EC6CDBAAAA29D6623122966A9BF95737271472F45513C4D8BC9BCB8CBC69A470800003E8EBDB5AAA3A1B8A3460A00002173A6C0CBCCBFBA924E29352A2C649DC5D6D9C9C1A24B1D2B529BBFC7C4AEA3B0A99543061B71A3AFA1A4B1A26E13000039849895673910000000000000000000004E638B918999C8D8D7C2834510000B204F6CAAD0D29E5A3008040B20253A87C3D8FFF3E0C79B7C4F295745568FA3A8AAB4BDBC9D683811070F2A759EB2AD95544F6CAAD0D29E5A3001FED45C070718407E8A875C0A00000052ABCDB25E1C0A246EB8CFCABEAA5104002165AEC9C48D4806000037749EA8B6862C00001C5BA5CBD1C3B8A5935A200A2969AEB3A07E756D523A495A444F84BDBFBBC9C59E4D0D0000428BB9B09D9697C69B4B0C0000276EAAB6B6BDC0B78848282B1A346C9DC9D7D3D4C7A04F1A1B5F9EC3C5BAAEACAAA98F4108277398B4B3AFA0976C1100003B869D9B6336090000000000000000000054617F938EA0BFD4DAB58B4F11080A2250749FC4C49058191426101424397FC5E2E4E4D3C19F6E4F2D583E6190AFA8A2AAC1C3A774420E1416326C9DA8AC904D50749FC4C490581901FED55C070718507B8F8258030000004E9DCEB3661B012470B1CCC9C6AA5014092266A9BDBE97480400012F6F97A8B68F3300001451A3C9CECCC2A37F5315113476B4BD9A7C756A463C5B6A4F5F93C5C4BDC5CB9A3B080000429CC1B09B8B97B69E4A0C00002676AEBFB3C7BDA980452C2B2F3875A8C5D1CBC4BE954212225EA0C2C1C6ADB3B2B08B35021B75AAB6B7B3B2A2680200034787A098632A03000000000000000000005C6C8D929AA9CED5D8BB95571D0210195D778DC4BD9151280C060B151D3787CDEEF5E6D9C1A1724625564F679FACB0AFB6B7B59A583412070F3178A5B3B7904C5D778DC4BD91512801FED65C0707186078827C3C00000000419AC5B36B1D071E64A8C6D5C6A94007002674A3B2B7852E00000534729EADC69337000016559CBCD1CBCCA9804D17143071ACBEA4778073483E596A4E5891BCC1C9CCC8993B0000024593C3B394889EB48D420F00032979A3B0B7C4BAA97839272C2B4680AAD0D1DECDCB933D0D20699CBACABFB6BDB9B78F310026738FA7A8ADB1995B000000478E9F94673002000000000000000000005C628190A6BDDFECDDC4994323180D2E5481ACC9CD8E4321100E0C171B4689D7E7EFD8D7C0AB793F2054405D9DABAEA6B1BFBB995C2C1409104685A8B4AE884B5481ACC9CD8E432101FED75C07071870697E7638000000004497BAA9631D00226EA5BAC2BD9F5109072E72AABFAF802F0000012D67A2AFBC874002001A5197C0CCD4BE9E7640130C3177AFB79D7C7A75554F6B784F5D99C1C8CBBFC49F470000003F96C9B68D8198C19941040002327AA8C5B2BBB8A36437322B273E80B8C7D0C6C0BC8838112564A1C3D1C2B4B3ADA3812D00236DA8B7AFADB49A57000002458CA194693205000000000000000000004F5A7B809FBFDDF6F3CF91511F08031E4E75B5D1C18F451F100F0E1821418FD5E5E1D9CDC1996B3B31524A72AFC2C2B3B4B9B58750240E02153785ADB7A87A4F4E75B5D1C18F451F01FED85C0707188075796C39000000004797C2B96110002163A9C1C2C2994309002C74A3B7BA7E2F0000001D5C91ACBD923F00001858A4C7D5C8BE987340110E3A6BA6B99E878673544F6867565F92BECDCACDC88F36060000419FBFAE887F9CB99A40080000337DB3C1BDC6B5976C2E2E31304581ACC1C8C1C2BD86360B1F70AEC9C6C6B5B4BAAA7D28032276A5B1A8ADAEA1530000034F88A49F6633060000000000000000000045627E8EA6C0F4F4DFB3805A1A091526587DB1D0C477370E0D12171A264599CDEDDDD3C6C0996A422548426FA8C8C3AAB6C0B3985E32040C174881A5B8A47F4A587DB1D0C477370E01FED95C070718906975773F000000004693B4B06D1B001E68AEC1C5BD983D0D10396EA7C2AF7D200000001C588DB2B386390B00225EA2C8D0C8BE94673110113A76A4B29F848A7F535674775B5F96C1CDCCCBC89A400000004397CDAC7F738CB28A3D00000C3B82B1C1BDBFBFA3642F2628344A8EB5C9D2C0BCB6812A0B3173B5BFCCC6B7B3B2A5761D002C7794ABA9ACA7985300000D5A90A79264301100000000000000000000515C7498BECAECF4F4D5AF622B0C12254984B8CEC2883C1F1B181F18234E9EDBE4E8D9D6C4926A3B2E3F4D74B0C5C4B0B2BCBB91532B0E0815418BB1B4AB7C414984B8CEC2883C1F01FEDA5C070718A0757A6734000000004C9BBCA5621B001C60A8C3C1C296451110397A99B4A978250000001B5B83AEB9943D0703265E9ACAD2D4C69A5B2303093664AAAEA08E8E775657877B5A729ECADDD0CABB943B0400003F99BBA27B6E85B08F3503000A4383B4C1B6C3B69B54342A332D529FBED3D4CAC2B2832E0A296EADC2C7C6BDADABA0731A022978A2B3A5A3A8965200000D60929983652D03000000000000000000005B648EA1B6D8F5FEF4D2A36E310D171C538AC3D9CF80401A1E2222262D4F98D9E5E0CEC8B692673528474C78B8CDC3B5B6C0BB864B27120B1A5495ADAEA07241538AC3D9CF80401A01FEDB5C070718B082856A32000000004E96BBAB681A001C6AA8CFC2B59A410A184785A7B6A7701D000000215B8DABB48E3605072E61A1C0D4D5BC9456270B1037729AAC9F8D918059648A876277A1C9D5CDCCC1903E0B00003C8CB697757188A97C2F0000183F86B6CBBCCBB79250353133215097BBC6D1C9BAB67F2510317CB0C9C4C7BBBAACA26818002F7AAFB2ABA8B09448000002689C9695602D0800000000000000000000575A7C97B3D1F5F3ECCAA15C29130E1C538CBFDDD081422219262E1E21459DD5E2DCD1C6BA8D6139243B4770B7D1BCB2B7C9BA945720100B225C94B3B19B6B35538CBFDDD081422201FEDC5C070718C07A71642B00000000458FB1A9600C00196DA0C0BBBE8C350C184C80A3B1A6631A0000001C4580A7B5944E19082A69B0C0CBD9BF8950250310357190A5A2939F7F666A8680586DA4C1CECAC3B685380000004198B5A97E7895A87B2C030014498AB4C5C3BCAF8A4B2A3034305991C7DCD2C9BDBC7224092A7BB0C2C5CCB9B2AE9E5915073D869FAAA3A7AF823D00001A709E9C8F5F2B0800000000000000000000536A849CB8DEFEFCFAD29D6835111D265D8FC7D9C283401E162432252258A6D8DDEBCEC5AC93623D2D3E4878B0CBC3B0B0BBB9834D1905071F619DC0B7965A365D8FC7D9C283401E01FEDD5C070718D07D796532000000004C92AAAD6518001A63A2B8BDB990370A154D7E9FB3B466110000001B5381A8B18E410B08306BA1C6D8D2C68D511A030D336B8D9EA39EA27F657B9782617399C3DCD7C8C38836040000458FBBAD806D75946F2B000010558CB8BDBEBDB48B4C342F2F2A69A5CAC9C7CAC1B87B280C337CA7C1D1C5BFB9BD984E05013883A0B6AEA4AE8A3F0000116D9E978A5B270400000000000000000000525F7E9FBDE0FFFFFEDC9F67331A0F254F87C6DBC47C2D1B21343228265BACDEDFDACDC3B29764432D3E4270B6C4C3BDB8B4AD834219110F1F61A2BBC0985D304F87C6DBC47C2D1B01FEDE5C070718E0666C611B000000003D82AA985514011964AAB7B9B7963F0F285C84A3AAA9620500000017517CAAAD9A400C083A72AFCBD1CBBC7B390C0513386790A79F9FAA865D789A85667BACCCD7C8C9AE782B0100002E84BFAA807483906D2A00021F529CC4CBBDC1B3854A31362D3762A9CFCFBEC5BCB16A1C103675AFBCC5CAC7BDBB965814003A85A4ACACA09D892F00001673A2A0906326040000000000000000000046577793B9E4FFF8F5C9A161411D000F5085CADACB823320283F391D2C58A9D9E1DDBEB9BB8E5E3020394A79AFD4C2B8B3BFA0763C1A0B092971A597A58D602C5085CADACB82332001FEDF5C070718F075755B1900000000468CAFA4610E0008639FB9B9B3833619306284A4AAA56211000000184D7EA3BB9E46140F3E80A6B5C3CBBB76340300193864879BA8ACA9846780A08F6F7CA4C1D2C9C5B47D360400003888BEB07D74849A6522000020599BBAC6BDBDAE7E412A2B30315E9FCED2C5BEBCAB6B2016388AB2BCC3C6BFC5AB90540C0A3F8BA9B1A0A1A183320000227BA2918A6A300600000000000000000000646EA9A6C4EBFFFFFFE2A16B3C190E1E508FC7DCBC7C39272C4B483A2955A3D4E0D4C0AEA38B4F34293E517FB6C9BAB7B8B3AE7C3A12031C3876AAC8B4905520508FC7DCBC7C392701FEE05C070718007B765719000000004A87ACA45E0E00136CA7B2B9B3853C16347499A2A9A8600E000000205782A0B39940060F438AB2C8CECDB977330600123B628399A9A5A7816D88A795718DABC7C8C1BAB574230600003380AFA883797990681D0000245A9AC5C3BBC1B2863C252F273367B7D2D8D2CDC0A25D1A094083B3C6C3C1C2C2AC8F490B004391ACA8A4A7AD842C000029779F9C8F683004000000000000000000004A5C8599BBE9FFFFF4D399673510091F538CCCD3C0753033345A492C2557A4D9E0CAA0A5B5945A3324364C76B6C7C8BBB9B5A5742B0F01183A7BB6C5B888542D538CCCD3C075303301FEE15C0707181077785F1D000000044785AD975C0A001768A5C2C2B0863B233B699CA1A994520A0000001D4986A5B496551317448FC1C2CDC4AA6B2300011742647E9FBAB3AD827091A48D6788A6BDD1C9BCA87734080000327CAFAC87717777571C00052B6298B7CBC1BCA36E403B3739386FB3D7D4C9B6BCA15815093B93C2C8C4CDBECBB4884103004690ABAAACA49369260000337C9AA5925F2A0100000000000000000000566685A7BDF4FFFFFFDDAB7030211A234F9AC9E1BE78352F456058352D53A8D3CBC8AFB1A96F462B2337487DB6CDCDC1C4BC9B6C27070617387FB5D4B8914E2B4F9AC9E1BE78352F01FEE25C070718206E72571D000000024489AAA4580D001960A7B8C4B986391D45819C9BA6924E090000001A587A9DB2914513144693BDCECCCAB7762102000F395D8EA3ACACAF857190A686769CB2C6C1B8B3AB752E0400003E85B5AC89787A76551702102F66A2BCBCB7BDA876433C35303D7FB1C6C9C4BDB69F5612134E94CACBC2C8B7B0A4823A0100408FAAA6A6A7A1722500002E79A3A28D612E000000000000000000000069768FA3CCF7FFFFFDDD9F613A1D1C2A5995D4E3CF893A2F457061343053A3D4D7C9AEAA9C77412D252E3B76BAD5CCBDB3B896602C1008203789B1C7A98048315995D4E3CF893A2F01FEE35C07071830746B4E1600000006488EA799621200236FA2BDBBAF7D391A49849BA5A0904600000000215E7EA9B89A3D160E4C97C6CACBCBAF7226050013345882A8B4C0AA8E77879D8F7999B1B9C5C8BAA36F2C0500003789B0A685777C744B0E00002467A0C1BEC1C1A86E493E36314775ABCCCBBBBCB8A1631B0B468DC3D3C5C5BBBCAC8136000A5391B1A9A8A8A9741A00002D89AAAC9D5F250300000000000000000000536585ABDAFFFFFFFCD8A8643720212B4F8CD4EFCF814145587362332751A4D2D6C9ACABA87F3F2222354373BBD4CBBEB8AB9B5D201418224087B0CBB17847234F8CD4EFCF81414501FEE45C070718407872540E0000000E5C89A2995A1C02216AACC5C0AE80362151859E9FA5954D00000009345D88A5AD9949060857AACECBCCC0AE5E140000132F6292A3B8BDB68A728E9B8F77A1BBC1C9C3BFA6612B0B0000327AAFA990817673461100002374A9C5C8C1C8A171413833313175AED2D8D2BBB3954B150A4595B2BCBBBBBBBCAA763000135A9AAAA5A8ADAB72190000397E9BA792623A04000000000000000000005A738AAFD8FAFFFFF8CB975F341A21284E9BD6EBD17D434A6C806A3E3560A2CED8BCA09DA57B442E25304973B6D5CFC7B9AF9459180D0D1C4590BDCFB07C38154E9BD6EBD17D434A01FEE55C070718507A7455110000000C5489A09B551100266CADBABFB07B36325A91A6A7AB9F49000000062D597DA3AA924D131853A0C4C9CCCBB464200000143464839EBBC0AD796CA3B299798FB3C2C8B5B9A5642B0B00003A82ADB3988472663D1300072E73AFBFC5BEB9A261433639334D87C1CECCC0BCB59A520D0E4D96C2C4C5BEB3B1A37724000C609AA9AFAFADA46C1700003A81A1A19E682B06000000000000000000005A6B87ABD5F4FFFFFFD2975C3616182E5193D3E9CE754252618164372959ADD5D6B5949DA77C452D19214272B9D4D0C8B1A38F51200C0E274F94BBD9BB7A44275193D3E9CE75425201FEE65C0707186076745410000000116097A3995A0C042D75B6CBC4AD74302C609B9CA3A7934B08000000245C7DAAB39446131C5EA8D1CFC0CBA9581D00001741688DAEBABAA27D769DA28785A1B2C5C3B9B6A5612F1100002D78B4BB98826F5E3606000B3977A6C2C2B9B69C6A3B473D31458DBAD3CFC8CAB48B3E0C11549DBBCEC6C2BDB4A6722A00075A94A4A1A6A8A06F1000003A89AAB09C6B2D00000000000000000000005F6C8BB1DFFAFFFFFFD79D663B201D254E97D9EEC8804A596B816C33285A9CCBD0B999919D8754211F2A4076C1D0CFBFBAAB8F4C111019324793BBCAB680451E4E97D9EEC8804A5901FEE75C0707187075784F160000002371A2A092491000226CA6CCC2AC6C30336A9FAD949D90440000000A376687A6BA94450E1764ACC9D4D2CAAA5F0B00001C3F6799B5C1BFB27F739A9C857EA4BDBEC6C5B69B531F130000327DACB297916E5C2C00000F3686AEBDC7BDAF8E5E473E332A4A98BAC6CBC8B7B58A400B115795B8C4C0BDBDB19A661B001F6D9BB8B3B5AEA9671400004187A1B29B6631080000000000000000000069779DC3E1FEFFFFFAD89E67342123245699E0F5D2884C5874857136315CA6D1BFAE929FA68C412717283A75BED1CBC3BEA17645221712255FA2C4D9AE7544235699E0F5D2884C5801FEE85C070718807B724F090000002F78A5AC93470D032775B5C4C0AD6028377197A093A39A480600000C416E8AACBE9A3F0D2360AAC5D8CAC3A45C13000012336B9BB6C3B8AD766E969C7D80AEBEC4C8B3B08C4C250D00003380B0B9B19473541D000215497FAAB8B3AFAA925A464B40365490BFDDCDCEC0A8853C051B65A3B8BBB9BEB4B9A15E16001A699AB1B3B5B7AA661100003B8DB6AE96662C00000000000000000000005B6B7CA5D6F4FDFFF2C892543A1C232D4A9DD8ECD2925B5F7986753D355BA1C9C9AB8894A8833E221E2D4177B8D1D4C4BA9F793C13121B3366A0C3CBAB7443254A9DD8ECD2925B5F01FEE95C07071890736F4D0B0000003179A2A88D430B052C74B1C2C9A054223378A5A896979150030000163C678EB0B98E42171370B3D3CEC6C1995314000019386C9DB9B9C3AB74709C987A7CA6BAC4C2BBB49352251101093A80B3AFA490674A2400001C4F8CB0C1BCB4B08E584E51352D4D9CC3D4D9CBBFA58432021361A0B2C7C4BFBBB4AE5D11002070A1B5B1AFBAA85D080000508AAEAD9A62210000000000000000000000607BA2C2EFFFFFFFFED69C683A1B23274F9FE6F6DBA4646C818477432C569DC6C0A78993A7804824141D3A75C0CACBBCB09E80442323264370AEC5CEA77132174F9FE6F6DBA4646C01FEEA5C070718A0747240030000002D86AFAF8E3E10012273ABC7BA9852243D79A59D909F924A0200000F386A89ABB99041142167B9DCD4D1C39E510E0000183A6597B5C1C0A0736F98956F80AEBEC5CBCABB92442E1F0400377CAFB6AB9A6E4717000519558FACB2BFB8A279534E54383E66A0BFDACCBEAC9A723200105EABBEC9C2C9BDBB924A0D00277CB3B5ACB5A99E550C0000538AA8AC9E75370200000000000000000000667790B9E7FFFFFFFFC88D5A3629282F579AE6FEDDA273798C8E6A342F5FA2C9BDA88CA1AA85401E11213E6FBFD7CFC3AA92743A1219263C6CB3D4D1A2693116579AE6FEDDA2737901FEEB5C070718B06C663B040000013579A2A1833500023183A8BBBF9B4D29397EA9A68B978E3F00000016437585ACBA9140122267B4D7D1CEC09C470600001D3B64A1BCC0C3A37675A0A0808AB3BDBEC2BFB0863E2A1D0502377EABB7AE996A3B1900001E5B92B1A7AFAFA770464C583E3E5DA0C7D8CEBFBBA17622051363A6C1C5BAB8B4B59F551001327CB4B1ACB3A5A1560800005B97A5AB9D69330000000000000000000000647193B8E2FFFFFFFFD18C563426202C59A7EEF2DDA77A798C9572392A58A1C0BA9E7A85A1824D3025203A78BFCDD1C4B1896C2F241E253875AFBECDA861371659A7EEF2DDA77A7901FEEC5C070718C0706836040000003790A9A67A3A0403327DAEC0C0973C254A94B19F8895823B000000113C7890B1BA914C121F6FB7DADBCABD9E4B05000017396BA0B3C1BF996872968F7888B0C2BCC6C7B78C4E2E1F06123979ABB6B0A1703C100000256693B0ACA7A9A2704851574C4471ACC5CBCDC6B09B6C2300125E9DB4BDC9C3B8B3964D09003082ACBEB8BBB7A45600000E6099B1B5A8712A0000000000000000000000596F8DB0D0FFFFFFFBC8965936312E2F57A6F5FBE2A97F869492683431579ECAC59F7F89A2894D2E1D22407DB8D3D0C4AA936D3F232F304288B4C9C99657280D57A6F5FBE2A97F8601FEED5C070718D0755A24000000003D90A5A3722900002F769FC0BF8634284C95AD958088762F00000020437791A9B68F3B1A1F6FB6D3D5D5C09B4C0800001949769EBDC6CEA16C6F988C667CA6AFC2C7B9AC834F3A210A0D3580B5C0BAA56A34130406306C94ACB0A8A698694D5C644B3E6EB7D5D5C8BFB49B5819000E59A4B8C2BFBBB8B5984D0500337C9DB4BDB1B59D500A000B6094A3B3A67C2F00000000000000000000005E6680B9D9FFFFFFFFC9865231303635539FE1F0EAAB8275868E63362E5C9DC7BD90757FA48B562F24294180BDE3D7CAA78C5A2D1C2A35477DB2C6C794632D17539FE1F0EAAB827501FEEE5C070718E074712A000000004391ACA6792B00002877A7C1C17F2D23509AB48D7A877C2E000000144E7B98B8BF8038112566AECFD8CEB789460A0008204C80B0B7BABD9A62789E886F85B2BAC5C8C1BC7A53402C06073E7AB0BAB3955F310C00022A64A1B0A19EA59F67445B64484481B5C5D4CEC5AC9A5C14001466A4BEC7BDBDB9B19B4B0000358AABB0BABEB6A250000012619CA5ACA26C2900000000000000000000005F6585AEDFFFFFFFF5CD7A503F322F3B58A1EDF9EABD92928E8367332C51A8C5AF97717D9D854C262032457FC5D0D0BBA282532B1D2B324D84B5C3CF9D50291758A1EDF9EABD929201FEEF5C070718F0735620000000004991AF9D73270008387EB2C5B97B2E175097A99A7A8B823100000020537892AAAE7F32192467B0D2D4D8C5943D0B0604275185B2BAC3C19862799E796471B2C0BDCBBBB57E4C3F3915143D7BB1BBAEA65D2A080000367DA0ABA291968B64546369524E87B6D7D0CACCB1853D05000F62A1C0C2C2CBB9B39B4800003E8FB0B1B7B4AC9B4C070023619DADB1A374260000000000000000000000656B7CABDAFBFFFFF4C68D513928323952A8E5F6E6B28F898688622C2561A9BDAF8B84839C7C4C312B26528FCCDBD2BA907158291A35395486AFC0BA8C4B291652A8E5F6E6B28F8901FEF05C070718006C4D0F00000000458DA18E6D250000327AAEC4AB661E1C559DB197818E73340000002C5A839EACB08735091B59B2D3DFD3BC8F3B00000B28508EB2B5C4BD8A626993805778B1B9B9BFBCB785524433181A4582B4B9AF995E2D0F00104381B6C29989A09762495D694E5589C1D0D6D2C0A6803702001162A3C2C2C2C3BDAD933B02024990BCBCB2B9B19B4600001F6FA0ADAA9A6F210000000000000000000000565F75A8C9F5FFFFF2BC7A4F463B303054A9EBF8E1B792878E8B61381F54A5C3B691627B876B4E3329305789C0D4D7BD9C745125243C375882B9D2C29050160F54A9EBF8E1B7928701FEF15C07071810755010000000045C92A69770200009438EAEAFA55F182152A0B6947A82742C000000315B89A3B3B68035151E61ADD5DBD2C18E4608000829568BB2BFBCB5825865937B5D7CACBCC0C7C5B582514F461B144B88ABC3B9A45D26000009437DB0BE948A8E8863497174535595C7CEC9CEC2AA7E3600001163ABC2C6BEBFC3B8953E00045390A8B4B9BCB6924200002E7197B0A7965F1B00000000000000000000005C647DABDBF1FFFFF4C078462F323D355EAEEAFAEFB492938A835430295CA4C6B58C657B9E81534B40395597CCE1D0BB886738261A2E30528ABECDC692471B115EAEEAFAEFB4929301FEF25C07071820704E06000000085894B2A3692000003A85ADB89E561A2152A1BB987E7D6C1C0000002C5A8B9DABAD7631161E66B3CED7CEB9883F0300082E6193BAC1C2BE8C5A7294795C7CB3C7D1C4BFB57C4C503C1C1C4589B7AFA99F621F00000B4592B2AC938080815554757B615F9BCED5C9CAC1AF6E3000001B6EADB9C1B4BFC0BA933700055A9DB5B9AFA6AE933900003068A0A6A694611C000000000000000000000053607EAACEFFFFFFF7BB7A453231343762ACEBFDE1C09C928C805B2F2E5CA6C3B4896D789283503E382C5998D2D3CEBB96693C191627305688B6C8C2914E1A0D62ACEBFDE1C09C9201FEF35C07071830755301000000095C99ABA2651200083B88A6BE9E54132261ADB09A777A5D1B0000002A618C9DB5AA7929142461ADD7DAD6BB82390400082B5594BFCDC2B38257748C685175ADBDC8C1C2B279505E401E204986B2AFB29F6424000011518FB6B28671777E5E587D72496DA7CDCDCBC5BEA36B2300000B65AECBC3BFC9BDB88C390009669FB3B0B3BDB38F340000407F9AA5B39C5F1F0000000000000000000000605E71AAD8FAFFFFEFB76F463941463D62AAE2EFEAC39C7F8275522D225EA6C0B98F6577A27E514142325DA2CFD8CDAD8663411521372C488DBDD3BA854E241862AAE2EFEAC39C7F01FEF45C070718406E4C000000000067A1AFA05E0B0003408AA9B18B3E012168A1AE8F6A735A180000052C7195A0ADAA703216226DB0C7D9D9B17B24000010315294BFCBC1B0795C739A664A7FB0C1BEB6B6BA7C526D4A2227498AC2C0B89C51220000175E8DA7B18465737C525F91895164B1D4D9D5C7BC9F571000001467AFC8CCB9BFBEB19035001469B1C0BEBAB6AD862D00003E859BA9AF9C662300000000000000000000005E698AAFD7F7FFFFF1B478483C40464051A7EAF8F2C492807A76592E2F67B7C2B482627C9285523E3D326BA8D7D5CFBA8359341E2B34345590C5D4C88444230E51A7EAF8F2C4928001FEF55C07071850753D00000000156297B2A8661400024298B0A4873903206EB2B6957A6C5710000012356D9398A79B642B0C295EB2D6DDD3B6792F03000B31569EB7CCBCAF7D5E6F86665376A4BCC9C9C7B2795B6B5828285386AFBAB596560B07001663A3B5AE845E666349548F804F6EB7D6D1CFC8C89A500B00002269A3C8C7C2BFB7B78C31001576A9BBB2B3B3AA8C2700064081ACB2A6976615000000000000000000000056617699D1F6FDFFECB16C37314550485BADE8F9EBC2968B8276431F2571ACC6A77A676A958053414E4273AFD3D9D0AB7A532E1A243620528FC7CEC0873F21145BADE8F9EBC2968B01FEF65C070718607545000000001C699DA1976305000E4F92B0A37331022261A8B498726A421200000E3A799CA7A896601F082668BCD7DAD7BF7D3400020C3864A3C1C9C2AD7655758C625275A8BCBDC2C5AB6C5B734B30325694BABBB998501901011D5F9DBFAF7360666A4F5A89835F77ADD2C9C7C3BF8D500D0000206EA5C0C0C1C5C7BF9735001374ACBAB9B7AFAB821D00024E84A7A79E99651700000000000000000000005B5D7CADD3F8FFFDEDB3703F394D564469BAEEF1E9BD937C756B4B2C3168AEC7AB7F5970906F5646503672B3CFDAD1AF72483725293A40688EBCC6C089421A0969BAEEF1E9BD937C01FEF75C070718706C410000000019719FAA905208000E4D99ADA9802E072273ABAC8E725F3C0400000541829EA4AC9F62260D1F5BAAE0D9D6B98B3102000931729FC8CDC8AB7B4C667F5F536EA9C3BBC3C8B27565756542495E89B7C5B4914E1000001F6397B6AA755A5F605063837A5A78B7CCC8CBCBB48F44030000166EAECFC8C1C5C0B98B2F00217CB6BCBEB4B2A37E28000D508AAAADA3986420000000000000000000000074708AABDCFFFFFFEFBB5C4934535A557FC0F4FAE5BE948277714E232E6CB2C8AD7A5F70937F4D4049367ABDDFDCD1B87B40251B2435456B93C3D4BA873B1E107FC0F4FAE5BE948201FEF85C070718807C3600000000136B909E95580A00135C9AA9A8781C002176B3BFA176633900000015497F9AA5A1935B240F216FB9E3E1D1A97C2E00000D4274A8C4C6C1AA794E6D8654416EA7C6CAC7C1A96B5B786D554471A0B2BCA3853D0A0000196B9FB09C7A5C5E675262947C5371B4D1D6D5CAC989360800001D70A0BDC4C7BEBAB6953800207AACBCBCBDB7A46E1E000E578FAEAD9D915E1A00000000000000000000006C7788A1D4FFFFFFF4BC75454353515479CAF4F7E6C0857A6F60362C3473B7C5A07B5A758A804B44543D86B3D4DACDB07749251B2D384A6C9AC4CAB67740180A79CAF4F7E6C0857A01FEF95C07071890753600000000146DA1B396580B001D5AAAA8A46B1B00347BAEBD9A7C61290400001F5988A0AFA58A58240F1F64BDDDDFCEBB823100000F4377ABBECAC7A1685371865B4669A8C3C9C3BCA66456745844517197B9C2B282390F00021C6994B4A6754B5861466797815E84B8CBC9C5C7BB8B2F0000002A77BAC1C4B5B0BEBB9331002D8CAFBDBABAB3A46E17000C5A8CA9A69298651B00000000000000000000005C6587AADAFFFFFFEDB675503440485384C8F9FFEEC18778786746223177B4CCA57564758C7C504253327DC4DEE3CBAD7746271D25394C6C9FC9D7C280311C1384C8F9FFEEC1877801FEFA5C070718A07B41000000001B70ACA79A521202216AA5BAA95D12002A78B0C19E7169320000001F5B8CA79C9A84501F072272B6E2E6D8B4822C000006417DACBCCFCBAD6D52687554466FAFBAB8C6C5AC65607F68495678A6C6B1AC90420400002575A7B8A979504E4F3E6893805E8BC2D5CBC8CAB5792D0000001F79ABBCC8C3CBC9B48532001F89ADBFC2B0B2A66B18001564979B9895915A1800000000000000000000005E637BA3DAFFFFFFE7B16E3A31464C4A80D1F8FCE8B580746F5F41263373B6C6A67D5C6A8A77453B593A87C1E4E1CBA9723C271E2441507CA7C6CCB37437140780D1F8FCE8B5807401FEFB5C070718B0763300000000247D9CA1994A06002C699FA6A16017002F87B0BFA48163230000001C6691A8A7A07D451008316EC6E9EFDDBE812C0000144271A9C4C6BBA66A42688154456DAAC4BDB9B49E655A846E5A5A79A5BBB5AA8A3203030029669FBAB277544D4E3A6CA18D5C8CBCD4D1CEC3B6732A000000237CB1C4D3C9C3BAB78527002D8EAEBAB5B6B79C6113001D6D8DA9988E8B601600000000000000000000005A6481AFD4FFFFFFE7AB7740364B5A5180CFF8FBE6B6806666614026347FBCC8AB78586F8A714B40502D84C7E7E1CFAD6D3A1A0B223A5488A4C3D3BB7333191F80CFF8FBE6B6806601FEFC5C070718C06A29000000002382A5AE9D4903002C669AB4A85818003287A7AD98705A240000002C609CACA69C7E48240F3477B9E1EADAB87E320000103E7EAFCCC4C0A3674D6C83474865A5C3BABFC6955E5B7C6A56658BA8B3B4AB823C1000002D7EADB3A6795547453468A5776089BDD3D7CFC1B67E240000003186B3C5C2C5BDAFB77C2400307CB2C5C4BDB89F68090020708A9A9D899266200000000000000000000000626A8CADD6FBFFFFE6AF6D4139434E5E95DAFFFFE6B479575B5C3B234681BFCEA9735B6D807644344E3991CEE0E2D2AD6F361E11203F5A7EA5C2C9B77C351D0A95DAFFFFE6B4795701FEFD5C070718D07931000000003283B1AB904914032D7CA7AC9A5A11012F7EB6C3987658210000002E6EA5B2A497754715102F75BEDFE4D9BE84330000184A7DAFCED9CD9564416877554265A3BEC9C5BA8751577A6B5B6E82A3B8AEAB8A340E03033176A9B6A57A404B40407395725E97BED4D5D4CDB672230000003182B0C8C7C0C7C2B67D2400358CB2C1BEB9B3975106002573979F9696945E1600000000000000000000006E7C84A7DBFEFFFFE3B170464650576992E3FFFFE6AB82636055402E428DCACFA8735B6487724739643A9BD0E9E2CCB1763B13141C3F5385B4CED2B3682B141192E3FFFFE6AB826301FEFE5C070718E07629000000003B86B8B7904A0900347EB4A5934D17043E8EB6B69C79541E0000003777A6B6B39E7843160F3685C8E6E1DDC589340000144F86ADD0CEC3A361416172433B5DA1B3C0C5B3844C59816C6A7791ACC1AFAD8838000002337BB1B8A3754E4C4A416D9670538BC0DDD6D0D0B36E200000002C76A7C0C7CAD1BAAB7D1F003689B2B7B7B6A6A65B0E002B829D9B8C8B8E5B1D00000000000000000000006F7595B2EAFFFFFFE3B3784843586072A5DCFFFFE4A8755D5650382D4C98C7D5A57D5B6B7A6A433D5E338ED0E6E4D6AD6E3C1A1123406085B2CBC9AB6B2C140CA5DCFFFFE4A8755D01FEFF5C070718F07B35000000002E86AFA9843400013583B2B2934208053F86A9AC957E5A200000033B77A9B4A89B7D410C0C2680D2E8F3DCC3933500001A538CB3C7D0BCA15C4968643D3C63ABBAC0C4BC8445527E71757E9BA9AEA8A2792E0000002B75ABB2B27F4C3E3C3F6C9E806199CDD7D5CEC3B868160000003281AFC9D2CCBEBAB47B11003592B7B8B9B6AC954D050030749BA18F82865B1C00000000000000000000005F6E8BBAE5FFFFFFD8AE775448535569AFE5FFFFE3B26B51514D31254995CFD5A3784E68806F47455B3399CFF1ECD2A06D35120E254A618FBACECFBB76281D1CAFE5FFFFE3B26B5101FE005D070718006E3A000000003F98BBAC8741000A3E84AEAD945207063784B1B7967A5323000009497EA7C3B4986E400D123581D8E3E4D9C595410000185999B8CACAB99455406C6D3B3567A9CDCBD3B67D3E5483747A8AA3AEB0B6AD80240000032A7CA6AFAF7E533E322E6C9C6B5D95C7CEC9D2C0B6652A0000003883AEBAC6D6C4C0AC6E0C002F96B8B9BBBAAD8D4000043C91A99A87878D560900000000000000000000005C6981A5D1F9FFEFBB93604046556176B0EBFFFFDA945A40404531294799C7CC9E75596175694C436539A1E1F6EFD5A56D371716294D6C90B5C8C2B16E2E140FB0EBFFFFDA945A4001FE015D07071810702A00000000388FBCB6873D0510408BB0AA8E400302448CB1B39681561A00000A438DB7C4B7A57B46110F2C89D4E6DEE5CA902F0000245C8EABC9CABA924C3F62643C40689EC6C4C1A56F3C4B7F7C7E94A4B0B8A59E732C0100023380AEACA578504A343D7C956F5E9CCDDBCDC5C1B4691F0000003287B5C1C6CBD2B8AA6D1A00418DB3C4B8B1AA8F430401328A968E7C7B8254120000000000000000000000557084A8D3FFFFF6CF96623D4C556387B2F0FFFAD696604A4A45302E51AACACCA27D5D647B653A306535A2E3FAEAC9A55D3C19131F4E78A4C8CCCAB0671A0612B2F0FFFAD696604A01FE025D070718206F2B000000084A9BC1B77F35000E3D93ABAA99460A00488AB7B8937A52180000134980ABB7B5A275310913388DD4F5ECE4D19C3900001E6192B2C7C5C197483E5C6141416DA8C6D2C2AD66334C71778BA1A3B1BBB5A671230000092F7FA5B5A47B593B2B467F835F619ED1D6D0CDBCBC631D0000034192BCC9C4C1CEBEAD7012003F90B7BDBEB3B18E360113468D9183767983581E00000000000000000000006A7594B0E7FFFFFFC8946B475158658BC4F0FFFFD18E635A524835375FB2D0CD9D635358725E3F39643DA4DBFBEDD3A36B3F1C1524537AAAC6D4D3A95F150607C4F0FFFFD18E635A01FE035D070718307C3B000000004894B8B17D3209165293AAA8873F00104685ACB6A0825110000110498DC0C8BD9E6A3310103B8BD0ECDFDACA90410702266EA5B9BFC3C0924F4464522D446BA1BECFC89C572B44797E819BBABBBCADA6731B0000063782B3B5AC84603E30387A8D615E9FD5D9D4CBC4A55F190000054088B7C4C4C3C7C5B2611400489EB5BEB2B5B081380006428A9C896B7C884D100000000000000000000000747D8FAFE5FFFFF5BA94614F4E496C93D0FEFFFED99A503C3E4032336DB4D5CD9C69564D6F6C40376E3DAAE5F5F5D69F683A1C14235084AEC8C5C899662A1014D0FEFFFED99A503C01FE045D0707184073240000000E4E9EC5BE8B3203165790A193824204134C8DB4B39B7551130000185490B6BEC0A5723616113B8ED6E8E9E0CA963700012170A0BCC8B9B88A41365C5A3A4473ABBDCACE9A54274A737A98AAB0BCC5B298711E0000014282BAB5A68B66422639747F5D5C9FCAD8D4C6C7A75D120000074A99B9C5BECDC0B1A76517004993ABB4BAB4B28B350011459092806A73845B170000000000000000000000738395BDEFFFFFFFC19363585A5D7299D2FFFFFBDA8E5A413238363567B7DED294674E586D633A386C3BACEBF2EED29E5E4128121A4B84B7C9D2CB9F5C270812D2FFFFFBDA8E5A4101FE055D07071850783E00000017529EC5B37F360A1C5E989F99883C030C508CB3AE8F79440E00001D5CA0C1CCC2A775340D143E91E1F0EEE5CA963A06072E62A0B7C5C7BD8F47385658344372ACC1C3B88C461E4C7B8091B7C6B5B9ABAA6618000008428EAEB8A08F6D482F386C795958A3CADDCAC5C3B2662100000A4A96B8C0CCC6C0B4995704004198ACA9B5B9B4772500084E969974647795581A000000000000000000000074818EB0E5FFFFFCC0865E45505E7298CDFEFFF8CE95614A3B3C33396DB2CFCF9B6D4F526751363A6A41A8EBFFF4DCA15F341315285984AEC5CECAAA662D0F09CDFEFFF8CE95614A01FE065D070718606F340000001957A4C3BD8D320B1D539BA09E7E350B135794B3AC9377461400001C63A4C2CCBDA05D2906154BA3D9F0E9E3D39C380A063371ABCCC5C3B082402F4E4F3A5173B0C9CCC8873E16356681A3B6B8BAB3B29D7820000009428CA7B2A48B69401F356E755960A2CDDAD3CDCAB4601900000D509EC5C8C5BDBFB2A24A00004198B9C5C1B9B37F300005528A88746777845418000000000000000000000079888DAFEAFFFFE9B5865F5360687FA8DEFAFFEEC681483A34383E4D82C0DBCA9372464A5A4C393D6E32AAECF6EBCFA46141241F2C5C96AFC5CEC4AB5F240A08DEFAFFEEC681483A01FE075D070718707B410000001B5FA1C2BF7E2C0E275B9A9B9F7F340F124F96B5B090703D110004296BADCAD0BD9D60200A1F489EE5F5F4DFC98A31000B3080A9C2C5C4B97F34294849354878B0C4CFBD80301C45637BA1BFC3BDC3B2A76A1900000B499DBBB4A8966D392C386570465DA9D3E6E0CBC3AA551B050008529CCBC7C9CBB5AC90480300409BB5C3BDBFB37E24000A5A927E5E637984521500000000000000000000006E7F8BB1E9FFFFE9B086564A596783B0DBF4FEF0C98A4F40353A334088C9DBCEA56E4C42573C2F3A6D47BAF0F5EFD2A6673D231F2A6082B2C7D2C4A65C1E0D0EDBF4FEF0C98A4F4001FE085D070718807E3C000000236AACCABB7D2B0F27629BA19B77320F215998B6B49F7B3D0D00032B64A9CED2BF9F6225121755A0D5ECEDDFCC843809062D79B0BCD0C8B680392B3F43304D82ADC5C2BB772D1C46708594B4B8C1C1B7A95D120000135F93A8AFA999684229386955495EACDCE0E2D8D0A7582D0A00165D9BBCC1B9B3B8B18A3E0100459DB8BBBAB4C16C1A000864A08A6960727D4B0F0000000000000000000000767E86ABE9FFFFE1AC8356525C6884ADD9F9FFF2C68858422A283B4494D0DFCD94654D3C5143312E6543BDF3FFF2D49D5D40231C285B8CBCC7C6C8A2551F0702D9F9FFF2C688584201FE095D07071890732F0000002B6FAAC7BB8030142A6EA7958B6D2B0314599CB0AFA167370D00072065B3CED8C9A15D1E04184EA3E2EFE3D7C78532040C3C86B9C3C8C3B27740293C2F2F5488B3CBCEBB7D270E376583A8BCC3C3C3BCAF641600001F5E9BB7B0B6A07436122557544364AED3DAD0D7CEAD632707001B629ABAC2C5BABAB08F3200024A9BBDCABEBCAD630E0019609B815A526D7A491600000000000000000000007D888FA1D6FFFFDA9E735C53607286B0E1F0FEEFBE8854372534334B98D3EACA9E6541434C4425346A44B9E7FCEBCAA1653D281D305D8AADBDC7C2A666211407E1F0FEEFBE88543701FE0A5D070718A0752F0000001E65A6CDB77D33122C7AAB988F6F320C115C98B5B2A670390D00062A6DB2D3D5C6A655200A174DA6DEF0E7E2C7822D06103C92B3C1BDBEB2772F2235262B518AACC9C5C0712B15335C82ACD1CEC5BFB7A164170000184F98B6B0A990773E1E255B523A5EB1DDDED6D4C19B53270300145CA0BBC9CBC0BFB58A3700004F9EB4C5C1BEAE611F001E6B937B5E66767C4E0F00000000000000000000007A7D7EA2DFF9F6CD8D624C3D597D88B5DAF0FFEEBC7957361D273751A3CFE1CD98603B3746412D398258B8F3ECE5C79E6239271B2B4F88B2C9C6C1A45922080CDAF0FFEEBC79573601FE0B5D070718B07D33000000247EB0CDB77B301532749E9090802F111F5BA0ACB09A6E350500072674B9DBD5C8A05E1D00175AA8DDE9E2E7C6822B0517518FBAC5BCC3B2703121312C26538CBED0CCBD69250E325175A4CAD0CABBB4A163100000246096B8B3AE9B72351921534C4564ADD6E1E0D8BDA2522004002264A4C6C2C5C5B7A98322000256A6BAC8C3BFA95F130018658E76505A6C7D4812000000000000000000000072737797C9EEF1C3865243344E677AAAD4ECFCE5BA8B593E2C272B419CD1DFC298653E3F453F273B7C5ABBECEEE1C09C6640291E2A5293BECECABB9D66170007D4ECFCE5BA8B593E01FE0C5D070718C07D3A0000003A8EBECEC480331E3A76A5938C6E2B082167A5AEB59E63360F000B2E74ABCCDBBD9D4D1B0C1756B3E3EEEED8C27E2D0E215696BDC6BFC5AD6927182B31306696BEC4BFAF591B1631557EAAC3CDCAC7B5A0560E00001B63A0AFC4AE9C7A33142045423D5CB5D8E3DBCCC99B592A0C0C317AB1CACCC3B8B3AA791F000050A4BDC8C1BAAE600F00206C8B735259767C4C1600000000000001000000007A8679A1DCFAE4BA7B5346455B7B94B7E0F4FDECC3875B451C243D59AAD3DEC88B5E3A394737273A7850BAF3FFE6C89C66441D17415F90B6C9CDC5A25D1A0700E0F4FDECC3875B4501FE0D5D070718D0733C0400063680C0D0BC7A341C3C81A6908F6D28092166A7B1AA9D622E0700103C82B8D0DCCA9E521F071658B7EBECE6D8C47B310C2A599FBDC5CAC3AD6B291A232D346798BDC1B9A562190C2B5976AEC9C5C5C5B6A3520C00001E619CB0B2AF9E77371B24393D3A65B2D5E1DED6C5905A30170A2F65B1D1CEB6BBB7A979230000599CBEC7BCB4A0510C002374926D565D78724C190000000000000000000000726B6A9FD7F3E2B5794537385B7595C0E0EDF3DDB4825B3C1014184AA6DBE2C1945F3E39392F1B398369C6F0FDE3C29261432C202D518ABEC6C3C69D551B060CE0EDF3DDB4825B3C01FE0E5D070718E07F410C000E478DC8D8C17B38274E88A69793732E132169A5B7B094622A080010397FB8CADCCCA45921031B67B6DADBE7DFC374280A21649FC3C6C3BF9A68210C1A1A2F7195C0CFCBBC58110527537DB7CFD4CBC2B79C4E0B0003256BA2B4A9B2AC863811183639366CAEDBEFDACDC3956034130A3380B9C7C5C3B6BEA56E1C0000559ABEC6C6C8A2500A00236C8C67505C736E3C0F0000000000000000000000706B6090CBE8DDA56D402D3A5C7791BCDAEDF1D6A97C5D441D132558B1FFE7C4845C32283932263E8B62C1F0F3DDC0906D47291625528FB3C4C6C4A85D27030FDAEDF1D6A97C5D4401FE0F5D070718F07B36000006448FD2DBBC722919418DB098976E2F0A2663AAB2AF9D501F0200173C88C5D9DCC89D4E15041B60BBDFE4E4DCC57B29032C68AAC7C5C0C2A45F1B0913193275A2BCC9CAAF5612031D4777B1D5D3CFD3B99D53150000276CA5AFAFB2A3723A170E2A2E3E6DC0E7EAD3D6C39657311B19377AB5C4CBC2BBACA2690F000F5FA8B9BFBBBE9547090029759970595777733D0C00000000000000000000008475729FCFF6E9B6754B2B416B848797D1F2EAD9B582644925203D6BB5DCD7BE895F341D39302B4B8E6AC8F4F5D3BB8D6B49291D335E91BCD0C4CAA55D15000BD1F2EAD9B582644901FE105D070718007137000002428AC6D2BA712B2653A0A79F9E742708255EABAB9F874C270500173F87BCD3DDCE9B4113001E68AAD5E6ECE1C36D26102F69A9C2C5C7B9A257190B0D113D7FAABDC3C4AA4E06001F5382C6DCD8CDD3B5A350080004336AA6B8BBB09B793B0F0820313B76B7DCF3E2D1C99C5B2F15154381BDC9C9BEBFB0A05B0C000C659FBABEBBB799450000276E8D7058627C77380C000000000000000000000079666A99CEE5E2A767382640537294B4D7DFEAD1A87B613F121A2D61B8D7CCBE895D3527302E2B438B65CFF3F1DBBE90655629191F4A8FBDC6C9CAAD58230008D7DFEAD1A87B613F01FE115D07071810783E07000947A3E1DEBA703A205DA3AC9E8F6823092B6E9EA9A6854F210702194794C5DBCCC599531910206DB8E0EBE5E2BD651E07367EB1C5BCC9BBA25A19010712387AA2B2BBC3AA4B0C09184778BFD2DDCECDC49C4D0A0001276CA5B8B1B2A07B380A1124293D74C2D5EAE2D4C08D5A39111C468BBCCCC5C2BEB3955909000E67A3B9C0C2BC9A430000307690715F5C716E320A07000000000000000000007C766E9ED1E6E3AE663C3F516D80A1C8E0F1E8D4A4836E3915063270B9D6DFC08A5628223C332D488D6ACCEFF0D4AE8A60432C1A144E90C2C9D5C0A6601C0000E0F1E8D4A4836E3901FE125D0707182077350F14205BA5DAECBF712E2F65B6AFA09E6B1F0A2774AAA9AB8B45160103194C9ECBE6DDD5974311072569BCE5E2DDD2B86917083885B0CCCCC7B3995818090C0E2E80ADC2C3C0AC460002133579BFDDDBD9C5B4944D0C0000407FB0B3B4AC9D893812071A1D447FC2E8EBDFDDC6895D3A191D4988B4CCB7B7AAAA965808001366B2C3BFC2AF8A3A00002E789D6E5766736E3B080100000000000000000000725F639AD7EBDCA75D393D50667B9DC6D7E5E8C5A17D6543141A386AC0DCCFB9875629242D2B26428C65D0F4F7D7A884683D232123479AC2CBD2D2AA61230605D7E5E8C5A17D654301FE135D07071830672E02001854A2CDDBAB66353069A6AFB0A2711A0D27709DA78D823D0C000316539ED7DFD7CA9B3F0701277CC3D9E0E6D6BB66200A428EB8CCC3BDBA98410D00000F3B7EB2BEB6C1A84F0A03164788B5DADBD4D2BE984C080004397EAABAB7AB9F7931080A17174081D0E1E4D6CBB38665391D27598CBEBFBFC0B4B1965102002579ADC0C0B9BB8C3F00003081926B5C637D65350904000000000100000000007C626CA4DBE4D8A4613C48577497ABC4D5DDD4C19F75614411113677C2DFD4AB81522B1F2E342B47996ECAE9F3D0AC7D6A483323364C99C1C7C7C5A35D1D0504D5DDD4C19F75614401FE145D07071840752905011165BFE6E1B566323675BABDA59868270D1E60A1AE9D6F3B0C00021856AEDCE1DEBB823D12092D71BDD7E3D9DFB9691C154990BCC9C8C2AB903D0100000E368DB5C7BCBFA04507000F3D87CBDBE3E4D7BC95530C000A467CB0B6B0A4A27F2E0B0004103985D0F3EDDFD6BD82593A1C275B90B7B8B0B7B2AF8D4C00002775A9C7C8BCB480300000376E927E6C6B7D66260000020000020000000000007565649CD5EAD69B613B435F798EA8C7D1D5DEC69778613B09083B7BC7DADBA9774C21222B2F2A509F65D1F2F2DCAE835C412C262B5596CFCAB7B7A16F250400D1D5DEC69778613B01FE155D070718506F3D0B031D61BEE8D8B16D343D83BCCAADAA621C132B669D9E9575370F03012966B0D6E1E1C88136100A327AC2D5DDDDDCBE5C140E5398C3C3C0BCB38938090000053E8BBABCB1B6A74C1000134387C4DDE5DCD0BF8B3906000B4588ACC3B8AAA87C2E0500081C3F82C9EBEEDFE0C28A61431D2E5F97BBC7C4B9B3A6893800002C7DABBFBFBBA97C260000286C8F7C77707B632A010000000501030000000000786770B0E5E9D3A1604055708297ADCAD3D3D9BB9C745E3D0C0A3B8DC5DFCFAD864D0C1832332558A371D6F0ECCBA176573B17283A63A4BBCBC9BF9662190000D3D3D9BB9C745E3D01FE165D070718607C3E11102E72C2EEE1AE6A323B87BAC5B6A8672309366F9EA08D632F1100032F71B7D7E3E1C28137080C2D6CC1D3DFE2E6AA5D191661A2CAC7C6B9B47D3300000009418BB9B9B5BC973E09000A3F8DC9DDE4E1D8BB8F4305001A5290BCBAB8B0AC862B0000001B509BD4EFF6EEE0AE745B4723306998BAC2B6B7B8AA83300000357EB6BAB4B5AD7A2700002F7A9C866D797E5F2D000000000000000000000000705A6CA6DAE0CA925438475A7F96B7C1C2D2CBB989665B35110D3D87C7DED0B7804F2D22393126549A5AC5F0E6C9A67C573020062C58A0BBCACFBD9B5924090BC2D2CBB989665B3501FE175D070718707C430B0A2A80C8E3E6A7643A4D89C5D1CBAB71240A2E699BA08964290A00002A6EBCD3DCDEBD823E0E093170BFD1E5E5DFB0581E2C6DAFC3CAC3C5AD8032000000074597B1B7AFB9903E0500093986D0E1E1DACBBA954904001D53A2BAB9B4AEA78E370200000F4392CBDFE2DDD2B0796545203876ABCAC1BEB1AAAE732300003C83B0C0C6B5A467190000357EA18483727F571A00000005090002000000000067667AA6D9E1C595613D597D8F93ACC1C6CACEB88A62592F000B3C83C6DECCA76E4A2E313E2F345BA668D3DDDBC39E7A4E372B2E3D67A3BDCDBFB9A2561E0503C6CACEB88A62592F01FE185D070718807D4920203D80C8EAEFB063385598CCD6C5AE68190230719A958358321609174182C4E3EEE4C5742F10002E70BAD1CED5D3B3611B2478B7CDCBC2C1A56D23000000104A98B7ADACB898410000134590D4EDF0EBD7B88B3F0601175392B5BCB4A8A47A2B010000154B97D6EFE7E2CFAD7063482B4B87B1B7BCBDB8C0A66C1F00004483A8B0BFAE9E5F09000026759C86848582561B000005000103040000000000726F83B6E1DDD3874A3D61808BA2B7BEBCCCCDA488655E401710468CCCD9CBA87345302F372F314E9E41BAEAE2C4A27A4B2F1B243D6CB0C4C6C6B49654150607BCCCCDA488655E4001FE195D07071890743A1C193881D3F8E7B263385193D0D2C9B15D1B1639749CA282582F0D0C0D3685C7E1D8D7AC7A2B05083573C1CDCED6D7B1511D2B80B5D3CAD0BC9E712800000015579DB8B8B4B88E2E00000E4A91D6DEEDE5DCB6843708001B5DA7C5BEBFB9A67D2C000000115599CCEBEDDEC99C6658392D4280AECAC1C0BBB5AC721F00095394AFBBB7B3A3680900002F709092878373561C000000020003000000000000738087C0EDDDC2894E4B60658A9FB7BEC4BCC6AB7F554D320D124396DBE6D6A26E432F364033305FA25FC5EBE2BF94664C381724447AA9CEC7C6B2915914090AC4BCC6AB7F554D3201FE1A5D070718A07333060C2F80CAEADF8F513358A3D0D8CEB063160E32698D9B7954240F0710468FCEF1ECDBB07B2A0901307CB9C8C8D0DAAA4D15317FB7BECDCBC6A96C170000001749A5ABA8A4B0853102000E4B9EDBF1F5EAD7B0773100002369A7BCBAB7BBAD79270000001A4A91CCE8EBDAC99A695A43304487BCBFB7BABCB79C6816000A5B98B7C3B7AF9F59110000307D9B968F878C5E1A00000000060000000000000080859BD2F5F1C98A544C688290A0B9C5BEC2C7B48044434211164C8BCDDECEA46941364343343764A760D1E4DCBE9062431F1A2C4478B1C7C7C3AE8A49131112BEC2C7B48044434201FE1B5D070718B07A4516224E94E1FBEBA359445FBDD5CFC5A45F180C3A6FA28D7851250F0A1D5293CBDFDBD9B66B2503042878BEC5C9D6DDAB5122357EB7CED7D4C59E63180000001863A6AEA5A2A7792100000946A8D8E9E7E0D1AB7A300902296DA9CDBFBCB1A58226000000174FA7D5E3E9DAC796645D402E5690AFC0C2C0BAB39B60140014619CB7C0C2B19D5500000030779A94969386501800000001000D0000000000007286AFDFF3F5D7905B51738B93A4B8B2B8BDBBB579424A3912134999DDE9CCA0693C2F474D363359A161C7EFE3BA8F5E422C232B4677ADC1C8C8B68B55220B09B8BDBBB579424A3901FE1C5D070718C0783E202D4A97D7FFE29A573561B8E3EAE0B86A22153871949263391C15181F55A4D5E0D5D0AD511503072673B9C9D2DCD1A54A1C2681BFDBCCCBC1A15F1B000000175AA6BDA3B1AB752D00000E4EA9DDE4E9E2D3A86D2000082A74B3CBC8C0B8B280250000001C60ACD8F0EBDAC089604E3D395896B4C4CBBCABA0925E0E00136A9DAEB6B0A59558060000367D9EA18E92874F15000000050E090300030000008699B7E8F7EDCF8E6861768D94A4ACC5C1B5BCA56842443616225A9ED9E7C7A0603D3B4E533D3068AF61C8E2D8B07B56472F20294E8ABDC2C4C8AF7B410E080BC1B5BCA56842443601FE1D5D070718D0704121374B96DFF0DF98543F63B7D8E2DBAB6A1E193A78938665441C130F1E5DACDEDEDCD1A664200002337DC4C5C6D6DAA03D213A7FBCD7DCCFC5A14E110000002068AAAB9CA2AA752500000847A6E8F2EAE1D2A2611B00032C7DBAC9BBB2B3AB81290000002467A7D3E3E3DFBC7F584F3C3563A6C2D0BCB9B8B29F5D0800177097ACB4BDAC8C3F000000327FA6AD9C9886400A0000020C0E090400000000008597B0DBEEE8C789625E778C9BA8BDBFBDBCC6A2653B3A27071751A2DADECF9E66393A50504C3B66B460C2DECDB48B50372D1B284C8DC4C8C5CBAB7645110516BDBCC6A2653B3A2701FE1E5D070718E07A422B34538EE3FFE3904C3C6ABDE0E4E1AB591F19478292806745271818316CB8DFE1DED19B58160506377ABCC4C2CCCF9D4D1C3C9CBED0C8C9B9914D0C000000206FA8B3A3A8A0681C00000852A9E5F0F4F3E2A4681B00003D78AFC5C9C7B5AF80250000002766B3DDEBE4D5B56E47493E3B6AA2C6C2C5C2B2AB904904001C71A6B7BFB3AB8C460000003278A1B0A592733B0C000400070C0800000000000089B2D2F7FFF5D69B6C5B7A8F9FA9B7B6B5C0C4A06E303333101E6EBEDFE0CB9850353C5A5A4C456AAF54BED6DDB07650400D1D2C539ABCCCC8B9A26C3718120CB5C0C4A06E30333301FE1F5D070718F0773F1D284E9CE9FFE6904F436DBDE2EED4B255201F487C918A69401B0C182D6DB3E1DECACA97481E05082F7EC0D1BECED09C4E273996B8D8DAD3B386430E000000386EA8B09AA4A666200000114DACF1F5ECEAD88847120215428CBFCCBFBFB9AE7B2C0200002F73B7DFE4E4D8A960414C3A3B66ABC1CBC5B9BFAA844301001B6BADBBC2B8AA84360000003283AFB7A5976F341000000210110C000500000000809AC5EBFAE8CC986A5F768A96A7B1B1A1B4BA9E5C272F23061A6BBAEBE4CE94552F3B6456494C76B952BADAD5A777503A2D18345DA0C3CACDC19F68381E0C13A1B4BA9E5C272F2301FE205D07071800774227365FA6EDFFD98D4F4A77BEE3EEE0AC561D18427E8988754D261A1D3478C3E6E4D6CB964B10000A397CBCC5B5C7C69D4925478FC2E1D2CFA67E44030000043672A8B09FA49C59110003165DBDF0F9F1EDD895471600094192BFBFC6BAB6B47C1C0000013376B7D9EAE0D7A957454C40437AB5CDCDCBC5C1AA7A2B00002680B1BDC4B39579230000003F8BACB7AB9E67330700000110190B080000000000809EC4F4FFE9C59875627C818DABB9B1ABB2B995502325230F1F79C9E5DFCB984D334669664B4574AE55C5E4D5A57C50382D253163A5C5C6CAC0A66E3E1C1215ABB2B9955023252301FE215D070718106D3B243654A1E3FEDD814D3C6FB9DDE6DA9F522016447C907B6A472C171D387BBCDFE3DDCB8E3907000F3E7CBAD0C1D7DF9640203E89C1D1D6C1AA6A35080000113A7FBAAAA5B9A7591300000F57B3ECFFF6E3D885390A00144C8DC0C3BBB5AEA879220000003B81B9D9E6ECD3A3513C4041497DB9CED4D0C2C0A67C2100002B7DACBBBBA597802D0000003683ABB0AF9B70320000000E151B1208000000000089B9D7F3F8F4D69A7464779194A4B8B4ACA5B496572912110C1F7DBDE9F5CE924B334669624F3F77B758C5E0D7A4774D3828233A5CA0C4CDC5C29D692F05080FACA5B4965729121101FE225D070718206435272E5BADF2FCD982393D6BC6E3E5D89F451612438290857D542A22223A77C6E1DBDCC985431400093C83C6CCC3C3CA8E3A1B3D8AC5E1CEC0A06B2E0A00000D4489AFB9AABD9B4D0700001C62B3DFECF4E5CA80370A00184792BCCBBBB7B1AD761D00000A4082B9E2EFE3D59345323B36518BC1CFD1C7B8BCA6692100003B94C0BABDB8A07726000000388BAFB3AAA05F2B0900030E1114131A070000000092BBE5FAFEECC89E7670748492ABB1ACA5A8AD885719110D152786D1E9E9C78C3D2C4C696E564177B356C6DEC8A5764E3224223B6DAAC0CDC0B59A5D300E1B0FA5A8AD885719110D01FE235D07071830774D383F67B3E6FED679524070C6DBE0CF9B4817194F7A85827654301F243F87D3E8CFD1CB8C3810000E3D80C8D0C2CAC4933520418FC5D3D5C09E622E0A00000B4589B5B5ACAB8C470F00001E74C0E6F1EEDECF7C2600000D4C9FC4CABCAFAEA3742C000006518EBEDDE3E8D09841344045598AC1D1CAC7BAB391581400034898C0C0C1AE9676240000024C8DB7BAAC996C210100000E181707050C020000008FBAEDFFFFFBCEAB8C76798E9AABB7A89DA7A9863E120A100D2E80CAEDE4CC9049314268815E568EBF5BC5D9C99872442E26283171A9CEC6C7BA955C26120C109DA7A9863E120A1001FE245D07071840713D2D396AB3F4FDCC7340476DBEEBECD8A04B141A3F75817B795F2C1C23489BD4E4DDD3C57C3106000E3A87C2CDC6D0B67D40203F8FC9E4DAC49A6127000000195088B8B1B8B88B360000001F6DCAF0FBF6E1C3722A000022599AB8BDB9B7B3A86E1B00000B5390CCE4F0F1D38934303542699DC4CEC6C4C0BA925007000048A6BDC8C3B3976C1E00000B468CAEBBA9975D1C0000000E18180903030000000093BDF5FFFFF8D7B3897C778D98B0B8A59F9FA387481B100C123A93CDF2ECC49D4E2F4C696E57568EC44CBBDECFB1734E30211A3473AAC6CBC3B5945B2E18150F9F9FA387481B100C01FE255D07071850704A36527CC4FFFFCF7D494A72C9E3F3D890401F1A49767C7A825F38252B4F96CFEEE1D4C382280001134190BDCBCED3BD77301A3B91C7E0DEC6975D1F0500001E5094BCBFBAAF88390000002276C1E8F1F6EAD5711B00001C519FBFC5C0B4BAAC691200000E5CA6C9DDE0E1C67F2B2B334375AECACDC8C9BDBC8A3E04000D61A2B8B9B4A68F5D100000054F93BCC3B7965D1F0700001221271E16010000000093C3FCFFFFF4C9A58E756C8191A7AEA295A6AD83461A0C1111399ED2EEECCF934C2E4D7973655B8ABE52C1D4BF9C6A483B2A1F3E74AAC2C3C2B8875327050E0F95A6AD83461A0C1101FE265D070718606C443C527AC3FFFFCD753F4978C9E1F0DA9A3C131F43697B9196704632374794D0E9DACFB86B2900000F4691D1E0D2CDB86F2A12419BCCDCDDC38F532A080000115598BDC2BAB372300000002877C8E7FCFEEEC36B200000175AAABECDC6BAAFA6520F0000226AAAC6DDDCE3C669272A334571A7CFCCCCC9C2B8853600000C60A4BCB8B7B59B5E0B0000064D94BCCAB0914E160000000F241D1619030000000097C7F7FFFFF2CFAB91797E8A8BACAA9A94A29B78410B08071748A4D9F7EED1A1543E4869726A6E99BF55C1CDB38F56373325173A7AB4C1C7BFB79156211B140B94A29B78410B080701FE275D07071870734D3F4F7AC8F8F7CE76495575D2E9F2DF973F1217446078859C74442A324C99E1F0E4DFBE761B0001164C93C3CED1BFB5662D1D3DA0CCD6DBBE7F401A0000001E5C98B8C9BEB2722E0000063980D6F4F7F9ECBD62140000195A9DC3CEBBB4B1AC681700001C6EA9D2DBE9E1C36C1F172E4F84AED1D4CBBEC2AF7A2B00001474ABB6BDB9AF8D500B0000004B97BAC0A891562A0701082028221B0E0A0000000095D3FAFFFFF0DBB48C787F7E92A9AD9A96AD9C753310080C16429FDAF3ECC79E5C3B4F6F747375A0C54CB8CBBA8E5C3B281D133F7BAEBDCAC2B8894A1C10141296AD9C753310080C01FE285D070718807D52405C83CDFFFFC37341517FCCECF0DF934310153767748CA4755238354F98D7E2D1CAB9702807081D5294CBDCCCB9A85519134393CFDFD9C98446220802022369A2C2C3CCC37F25000004388BD8F3F4EDE8BD5B1300001252A1C1C5BCABB796540A0000267AB6CFE1E8DCB45C1C1739628AB3C9C2D1C1B8A96B2B00001977ABBDB3AFAF975000000017629CBFC5AE8644130000101F2B261B1408000000009ACCFFFFFFF4D8B68976758791AFA6929A929369340D0A0B15449DE1F8E6D09161414961827B79A0C049B7C9BD8B57351D1913417CB4C5CDC9B6944C1F0D1A169A929369340D0A0B01FE295D07071890755446588CC3F8FDC8734D6087CCF1F6DE913813183D537396A276483B3A53A0DEEDDDD7B369280600245C94C4D7C9B89054181853A8D6DDD2B8833A1B11010427699DB1BECEB36C1F0000053F92D6F4FAF8E6C5580800001C5FA0BFCEB8AFAAA651090001397FB6CEDEE1DEB54F1D1B436699B4C9C8D8C9C2A4631A00001A76AABDBFBBAC8C460000001964A6C2C7B780461303030F232B271A0F0C00000000A8DBFFFFFFF7D3B28F7F778599B6B199A09895672D0F0A141F54AEDBEFE6C9965E3A516375787C9EC44CB7CCAE8168421B151B3E83B9C1CBC9B3854924101B0FA09895672D0F0A1401FE2A5D070718A0784D466996D7FFF0CE704C5D92D8F1F6D481290F1E445673A0B587533B3262A8D7E6D6D4C4641B00041E5A9ED0E5C9AD823F0E1647A0D2DDD1BE7E3F1A06041025719DCCCFD1B3681A00000C459BE6F3F3F6E6AD55080000206099B8C0B4B5B49D52090000338DC9CFDBDADFAE540F1D456D98C2D5D2D3C7B6A45A130000226DAABFBABAA8823D0000002077A7C5C8BB8743050000031E281E190B000000000095D8FBFFFFEECBA787766E778DAAAA978E9C926C340800021C63BCECF8E6C59A583F4C67828683ABC852B6C6AC825B4B2B1916427EACC5CCC0AF7D481D1018108E9C926C3408000201FE2B5D070718B079584466A6DCF8FDBF65505F93D7EFFBE68634091A3B5975B1C4875A423955A4D2E1D3C9B2651300022B72A3C9DFD1BC7733171B53ADCED4D2A9703A1A0805032F6BA3C9C9D0A65D1600001155A3E6FFF7F6E4B1530B00001B61A0C2D4BFB1B0994B0A00003D90C5DEDCDCD7AC3F02183B72A1BBCCDBD3C5BEA24D0A00002986AFC5BEBAB07E320000002270A0BBC4B08C430E0000132735311D0D0300000000A4DFFFFFFFEFCBAE8F7A698193A7AE9A908C86592A0A030B1C69B5E5F5E4D09E63474960737688ADCC44AEC0AE7F5F391F1920478BB7CCC6BEA47A3D1713110C908C86592A0A030B01FE2C5D070718C071585674B0DAF5F8C8714E5F8ED0F6FFD7883E1219385375A8C39263493754A0D8D6CDD1B35D1B0004206A9ECAD9D1A97332121752AED9DBCEB4652A120F050B2B6DA5D0C9C6A6511200022157A3E3F6F8E6DAAA48090000266190B9CEC6B9B590450700053A9ACBDCE3D6CFA03B0510508CACC5D3CDC4CBBA9F4D0100002F7DADC7BBBFAE8636000000286EA6BCCCAF8740000000102B2E2D1F0F08000000009ED6FFFFFFEBCFA3806D706F8CAEA49A90927E582314000B1A5DB7E9F3F0C49C5D40475C7F8799BED154B0C3AE7D563D2E23265291B4BCC0BEA3723C1116141190927E582314000B01FE2D5D070718D0644F4E7BA7DBF1F6BB6E516591D1F4F7C97B361319375A72B7C9975D5237569DD5E7C7CAB65C150007366FA6D1D9D4B06F250F2457AAD4D6CFA56C34101810172973A7C9CFC19447100006296EAFE9FBFAEDDC9C4101000023568CBCD1C2B2B58D38010006409FD6DFDBDDD5963F061C5599B3C6C5D2CACBBE9C480C00003387B4B5B0ACAD7B1E0000002575AAC0C3AC7D40150000152B311D120E0900000000A2DFFFFFFFE6BFA28273717595A29E7D8A8C82541803030F1E61BFE4F0E4D19F5C3D4C64738FA9C3CF4DAFBBA4825C452E202A4F8AAEBFC0C0AD722B0E1211148A8C82541803030F01FE2E5D070718E07758507AB0E1EFFFCD7A597098DCF0F4D2782D101F3B5277BAD19B6A424257A7DDE2CDCAAB5414010C3D77B1D6DEC9A2561F051C61ACC8CECAA16528201E160D2E72A6D1CAC28C3B0D00083775B9EFFBF2E5DCA3440000012A6392BECABBB5B08A3F05000D4EA2D5E2E6E0D1972D00135D9EC3D6D3CFC6C5B491410000003B8AB8C0B7BCA576210000002C76ABC4C4A3813B18000011282E281C140400000000ACF4FFFFFFF1C8A2806A727C9AA59894959677411C0806082467B9DDF0EBCAA061423A607993A0BBD753B5C5A870644D39312C5F89AAB3BBB69F682F040D0C13959677411C08060801FE2F5D070718F07458658FCBEEFCF3C56D5871A5DEFFFDD071301620305979C3DB98634B465DA9D5E7CAC2AC561600184277B0C9D6C5925F19051E66B0C9CFBF905F36251F17162B6AA7C1D1C88A450900032F7CC2E6F3EAE9D39F3904000C286297B9CBD1B4B3843A03001047A0D2E6E3DED7982E00206AA4B8CAD5DACAC4B385360000004097BFC1BEC6AD74120000003180A1B5B8AD89430800000D2835291A0F0200000000A0EBFFFFFFDDCB9C836D617A93AFA5968E9068461B07070A186DAECDE8E7CB9D69453556738FA7C6CE53B2B3A076695D4836396193A9B5BBB595622A0B00101F8E9068461B07070A + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 61440 61440 0 01FE305D070718007063699DD4EBFBF4C97D617CA9DEF4FFCC6A2D15243E558BD3DC975C464560AAD4D7C9BF99451000154E8AA5CDDBC28F470A002363B5D1D0BE9C6032141216193275A9D3CBC882350700082E86CCF2F0E9EBCB91310000042C6099BBC7C8C1A97F3000000E58B3D7E1E2E2D3841E00116CABC5D2DCC6D3CFB487410700004391B3B7BFB1AF7522000003407BA5BEB9B2894603000019292E291B040000000000A8DCFDFFEFE4C19E8072637797A18C86898B72331A0700052170BCE9EEE3C895563435537590AECED25AB9BA99795D574D3D477799ACB8B7AB834D1905071019898B72331A07000501FE315D0707181080697094DBF5FFFEC67B5778A9E8F1F0C66D321826446291D6E596624F3A68AAD8E1D2C7913805001B569CB7CCD6C391471108256DB2CACAB995572D252324172F6E9FC4CFBE652D0600164A8AC1EDEDEEE5D499300000002D598EB1D2D7C9B97B2600001761B1D4E1DFE2CB852200277CAAC3D4D9C7BFBBB080330000054CA0C0C2BEB8A36B150000034383AFC5CEA4862F0000001D32392D1B0A01000000009DCEF1FBF6D9B29069594D6C8EA49A898F866F3A130900021573B9DFF4EFCE9959332B4B6F8EABCFD061ACAF9472706754495D8096ADB3AFB781411100000C168F866F3A1309000201FE325D07071820705A669AE0FDF5F7B8635371B5E8F6EEBD5B1D141E3E6892E0E39760464362A8D3D1C8C095440E0729629CBDC2D3C88D3405002467B0D0CAB688572F2B311F1A3372A1C8CCB2692603000F4596CBEFF4FBE9CC7C2500000A2A6496B8D6CBC5AD742500001467C2E8E2E2DED1821B00237BB0CECFD9D0C7C3B5833106000F5599B2BCBDB9A55E0F00000B477BA8C1BA9F863A03000019353A311B090000000000A0D6F1F4E2CEAD8E7058647198A696879483623B040A00002675ADCDDEDFCA93583E31516F97B8D7DE5EACAB866D6E675A49577C96A6ADB297733E130708051A9483623B040A000001FE335D070718307D7786BCFEFFFFF6BC6F5983B3EAFCF0BD682723324667A0E2EA9B694F4967ACD1D8CFBE88380C092D69A7B5C2D3C4842F02002B76BAD0C6AF855E373034261D3372A3C6C9B3652100000D4B9ED4EFF2F0E3BD771E00000D315F91B2C7CEC4AB6E1F00001B6BB2E0E8E9D8CB811B002A80B9C6CCD3D2C2C4A2803400000560A1B7C1B4B1A6610F00000F4E8DA8B3BBAD8B3D07000020373C29160F0000000000ABDDFCFAE8C5A77C695B4B6D8B97918C938E673212060500216FB2D5DAD6BD8F4C2D41507B96B5CFD76CB2AB856B5B6A6661628492A9A3A48F64341405011B17938E67321206050001FE345D070718407F717EBBFFFFFFEEB375677BBAE3F9EAB259271B3B5074ABE0E09A5F524967A7D0DAC8BD7F380D11386FB1BDBDBECD843F040D2679C2C5C5B181563B323A2818306CA5C2C9AF5C180000134FA1D1E3ECDBD1BC701D0000173F638DA9DBDEC7A661170000206BBDDBE3E9F0CC721701287EC0D4CBD1C5C8C0A6763815001464A1BCBAB9B4A15900000013477AA5C1B8A2853B0100001B34382F19080400000000B3EAF5F9EBC7A2756153587395A6998E948F62260F0502082578B4CAD3F5CA934E252D45709BB9CED673ABA18062666E61687288939CABAA8E5D2E10000A0A20948F62260F05020801FE355D07071850736276BBFFFFFFECB7765C81BAF1F4E3A4502A2534516EA9E5D9996251496DB0D8DFCCB3772D0C0B3B83B8B8C9C5BF853608082C72C1C7C9B28C4C382D312C1D386CA3CDCAA4540E00001A4EA7D9DDE6E9D5B2611F0000103B5A8BBBD6CEC8AB5C1500002876C1D8E9E2D5CB741D003493BAC9CED3D7CBBAA2733508001A69A1B0BCC6ACA355010000144C81A1B4BBB58F45040000224137220F000000000000ABD6ECEBDCBD9E705A525677A2A5938992875D200F00000F32799BC9DAE0C2935124204870A0B5C7D581B8A876625F6F7F6C6D7F94969DA883541D0A0005102B92875D200F00000F01FE365D070718607B6A8DD2FFFFFFFEB3736A90CAEEF8E3984E2825395D7AA6E9D6986B514F75AED0DFC6AA702304134689BBBFBDC6C07C2A01042C73C2CECCB38A54413B3F36233874AEC5CCA55C0C0000105CAAD1F0E3DFD3A65E0E000019447095B2C6D4C8A6620C0000277FCAE3ECECE9CA6B0D003793C1CED3C8CDC5B19763330B000E5FAEB9C0C1B9A552000000135184A2BBB5B88C3B000000243D3A281705000000000098CFE2DFD7BB996C5241415D8597847A8E87591C0806000C2E74A1BFD1CEB993502A204C73A9C6CFD772A79F775F5E7A7171748A9A97A1A180471801000010218E87591C0806000C01FE375D07071870787B8BDBFFFFFFF7AD6C608ECFEAEFDC9447222E406C7DB1E6DD8F644D4D74B6C7DAC4A56C2800104C86B1B9B4BDC079260000337DC2DAD6B2835237363F36243579B1CAC7A053120000125BA8D5E0DCE2D0AB54050000193D6793B0D2D8CFA1511000093682C5D6E9EBE8CE691304368CBBC7CACBCFBCB5946A300F002072AABBB5B2B4A24F0000001B5C8FB0B8BDBA8D3600000221373A1E0F040000000000A0D7E1E2D8B28A644B3F416B8D9D8589947F5121200D000E2F79A7C2CFCBB17D4B27224681B0C6D1CB6AA19A735F6D787E72748A908C999C754216000406162C947F5121200D000E01FE385D07071880787A97E1FFFFFFFFB15E6893D2F2ECC88946223151738AB7F7E391613F476DB2D2CCCA975217021A4B96C0BEB3C8BF762400053686C7D0C5AC82604A474E4123337EA2C0BAA64D0300000C5DB3D5DBD4E4DEA852030000244C759AAFD5DECFA5530900033584C4D7D9DCD9C85D0900348FC6D8D0D2CDC5AC885D3A1500207AADC2BEB9AC9D44000000236494A0B5BDB78E340000032240402914080000000000AADCEDE9D0BAA070513F4E6B9AA992779A8057270B0A0007317EA8B9D3D3B2884D26244B7DB0C7D9D37FAC976E6173877F7D808F8C8B9994712E0D00000017309A8057270B0A000701FE395D07071890767792E7FFFFFFFAB56B5D8AC8F6F2CB7D3D274063828EBBDCD18C5F484577AFCFD3C996541711205395B8B0A3BCBA6D23000D3787C1CED7A99166434D573E304978ACB6BB9B410200001968B5D3E1DCD6CD9F4D0900002C577FA0C1CDD8C79B3E020000318FCBE5E1D9DDBD5C0A004393B6D1D0C3CCBEAB86604417062B7CAEC7BFB9A89144000000256990A5B2BCB48A28000000293C3C2D14000000000000A1CEDDD5C3B195604D3A4B678A9C868D8E81541E060C000D3978A0B0CBC3B07F4124223A80BACBD6CF77A19364536C8784818290948A918D6C290F01000914448E81541E060C000D01FE3A5D070718A0727C96E9FFFFFFF7A1636587C4E9F3C76C342B3E648E99C7ECD3844E424675BDD3D1C2905419042968A3C2BAB0BBB46C1A00083E87BDC6D4B3745A495E5F4E34427CB2BEBE9A340000001361B4D9E4D9CCC494430000001F5279A3BDD9D8C198420400003394DDE4E6DDCFBC550A004094BBBFCACBCBB6AB7A60491C0C3C7BACBABABABB9C38000000265E84A4B6BDB38536000000253E30270E000000000000ABD2EEE5D8AF8A61493C527DA3A78F879C7F481B140B0D0E3887A5B8C7C5AA89482520497AB0D7DCD17FA28D6C5661838F878D96877F8B9270280400000E18459C7F481B140B0D0E01FE3B5D070718B06E7793F2FFFFFFF89A645F87C2DDDFAC6A37283D7A949ECADFCB855E4A5583C2D1D2C086480E00296EB0C2BCA6B2AA661B0010488DC1CFCCAD7A614C576E5B324083A8BAB793380000002466B2CCE4DAD7C47D2E0000002E6592BAC7DBD0C798360000053B8DD3DEE2DFD8BF570C053F8EB7C0D0C7CAC4A37E544419133777A6B2B2AFB79638000000226693A6B0B4AF842700001D33473E1C0F000000000000ABD4E6DFD2AE8C63524E5D819B9983879F885A2210120B0C4A87AFBABFB89E73402826417FB7D5DDD87FA38662536786908485908682958B611A0600000D1E4D9F885A2210120B0C01FE3C5D070718C07E7D9DFCFFFFFFF39A655E8BC1E2D5A762342C5187A3ACD1E6CF8058424B83C0DBCFAE7D450E092D6FA1C5B3A2AEA1621E000C478FC5BDCAB78C644E637A593A4685AEBEB1952E0000001C6AB2D0DEDBCDBD743600000C32719CBAC0D5CEBA8D3A0000004198CAD9DAE3E0BA4902004293B7CAC2CEC6CAA6624D411A0D418FA6AEC0BCAB862C000000336B8CA5B3BCB27C2600000A3A43341E09000000000000A4D6EEE5CDB589483E42527CA2A4949CA08155280D0F03063E89A7B9BEBDA6723E1D2A508CBAD4D1D1759286685976959486889583888A896221060000122260A08155280D0F030601FE3D5D070718D076719BF2FFFFFFFF9F56548AC0E4D9994E29315792ABB6D5EAC7785B494E86B8CDC5AF7D3B06072C77BFD0B09FAFB6671A000F4C8FBEC9C8AD896D4F61745933467BA7B8B2882F0000001A6BB6CBE0D7C4A86E2D00001245819FB5CFD7D2C5912E0000044FA3CCDADED9DCB7520F005298BCC1C6C1BAB99B5E5547231B4585AEBBB2AFA9882A0000082C718E9BB5BDB17F2600001330412F180E0100000000009ECEE6E2C2A67D553D364D79A097898BA793601E090D101142879DAAB9B3917535181B4685C0D4DFD680A183655569919792999887869490501915000004245AA793601E090D101101FE3E5D070718E06C7FADFFFFFFFFFF9C576080BED5C39358303A68ABC4C4DDE9BF77453E5187C6D4CDB3773008002F79BDC5A9A1AAA9571300155192B9D3CEAC805E537182614250829FB2AD88300000002767B2D0DECEC1AE682000000F508AB1BED3CFBDBD8F320000053FA7D2DEDCD4D0AA48050554A2B2BFC2BBBFB6945C4E432A1A4A89AFB8B0ACAA81260000013C7B8B9CB1BEAD692100000D2F47322310020000000000A6DBE8E4D1A6815A333C4E799A9F919BAA9068260D170915568A99ABADA1955C2A1D214C89C8DADDD785977D5859739594939595817D92905818000401132A65AA9068260D17091501FE3F5D070718F0737FB1FFFFFFFFF7975A5A8CCACCBC82422E3C67ADCCD8DAE6BF754E3D5788BACEC7B1652900033579B3CCB8AEAB99521400115AA1C8D0C8AD876553787F5A374680A5B5B99129000000206FB3D7D5CEC79C61210000124E8CB3C2CACECAB97E2B0000064DA1CCDDDEE4D9AF45000B52A0BBC7C6C9C5BB8D554E3915165291B0BCBAA99A741A0000034A7B8C9CB6B3B36E1F00001A4346361F09000000000000A5DEEBECD7A67F4936335679AAA2918FA8926D2C1D0F0623719D9A9DB19D865B2F1E20428BC2DBDCCD7199815D597083999EA698787D8D8148160401000A3176A8926D2C1D0F062301FE405D07071800707BABFEFFFFFFF8975B5989B9C6AE7434253A6FBADFDDDFDAB26E4C365594C7CDC3A869210312448DBADFBAAAA9A05A0F001A5D9DC0C3C9A484655F79845D384A7F9DADAD7B25000000236BB5D1CFC8C2995C2200001C5D9DC2D1D5D5C4B87F1D00000A4B9CCCD8D7D0CE9C3F040861B4BCC8C2C8C1B587544B3E1F265699B2B6AFACA8771C00000C407A8898ADACAF6E1C0000153A3D2D1908000000000000AAD4F1EDD19E785235445685A7A08D96A292682F1B140A3474A3A39C9A968359311C2A4F87C9DCE0D4728E7A605C7498A29FA09E8289A08449100000010D3A78A292682F1B140A3401FE415D070718107A81B5FFFFFFFFF493505985C5C79E7145254185CCDFDAE2E3AD66493D548DBCC7BFA46217020D4A96BEC4ADB2B3A05007041C6096C3C9C8A37E6963797F5D445389A4AFA17A210000002775AACDDBC8C09C5B1900012D74A4C8D3D1D0C4B374190000154C96CED7D2DDCAA43D10115FACAFBABABEB1A57E4B413A1C29689FAFB5AEAD9F6B0D0000135175929FACAFAA611400001439462F21030000000000009ECBDEE2B8896238232946789E9A9FA09D8661291912063482A49E9BA1866F4227191A5192CADBD7C1798972515178939EA7AC927D86928243070002000E367F9D8661291912063401FE425D070718207A8FBBFFFFFFFFEB875B6A97BDB6985C372C4C8ED4D8DCE2DFA15B3B365895BCD6CAA35C2500144996C3D2BEB1B08A480D002067A3BCD0CCA584705A707B56435A84A1AAA071170000002E70AFCBD3CDBA934E180009336DAAC7CECDD3C0A5661900000C53A2CFE1DFDEC89A3600095AA6BEB7BEC3BFB98C4B433E243974A4B4ACA8AA9E650700001C5E849A94A1B29E5C1900001C3B3D2C1C12000000000000A9CBE1D4C39366413032478BAC9291A1A88F662E1B15164589A391969982704B1B15265690CADEDECA75816658597A919FAAA79381879683490E000000103780A88F662E1B15164501FE435D070718307A83BBFFFFFFFFF28D566697BDB288563138529DDDF6E5DAD792573F455EA1C3CEC5A55A10000C5092BDC9BAB1AA833A090A2A73A4C1CAB7A78F5F4E75765C4E6195ABB8A164100000063080B3CBC8CEBD95481D000F3984B8C6DADACCCBA9600500001D56AAC6D0D4D4CC932A021164A6BCB5BEBFB7B57B3A3E2E25427E9EB8B1ADAEA35D000000296B8D8A8FA3AA944803000020403E311304000000000000A7D4F1E4C09D673E302A4983AD9494B3B2A06D321D0C134D93A09C8E99745A3F191329619FC6E2DFC07982685B597B9AA8A7AD9A8687927A3F08000000134681B2A06D321D0C134D01FE445D070718406C88C5FFFFFFFFE0844D6598AEA27C4E3432599CD6EFE9E4D79558364A67A0BED1C09F5116021E4C9BC6CFAEA7AC863B0E06296CA3B6C3B9A3966C4E6D82664C608AA0A492620E0000093A7AB4CBC2CDB89444150111458BBFD9CFC5C0C0A75E0300001B59ABD8DAD4CAC18123041E6FA7B0C2BDBBBDAC703D3B29274C7FA9BBB7B3AB905000000020688E969BABAE8D450A0008203D3D2C0D00000000000000AEE0E3D9B2885B301E234C85A99D9FA9A88A5D372023245298989493A179583C211F274CA0D7EADEC47185644F4D658AA7B4AAA08A899E784A1100000015498FA88A5D372023245201FE455D07071850737BC4FFFFFFFFE281525A9BB1A7774A1F3C5B9FE0F2E6E5D8824A3F49649ABEC8BF974919041B5DA3C5CAB2B0A770310611337FB8C3C7BBA38A67556D6E5E566993A6A18D4E0E0000094079B3C1C1C2B88B3E1500155292BACDD2CBCEC3A1530300001D66B4D3DEE3DBC28528002581AEB8C4B8B2BBB17040322726458DABB5B7B2B2944D0000002B6F8B8D94A2A4852E04000021443A240D00000000000000A8D1E3CDB4895731222B528AA79C9CADA791642B1611286B99A0989B87614C3C1C141D58AADBE6D7C6748962574D7394A6A9B3978190A07C40020000000E468EA791642B1611286B01FE465D070718607387C4FFFFFFFFD97B5266A4B4A37146373D66AEE4F6ECE6CB7942343B699FC0CABC9E4509002166A7CFCBBEB9A05D2200023987B3BAC5C9A28F654C6B7463597291A59D8747080000063984B3C3B9C6BF934D1C04185398C3D7CECAC6BDA34F000000205EB0CCD7D9D9C0731C001E72B4BBC8C3BBBCB66D2B26231A4F8BB2BABDB7B293410000023972909095A8AA7D3302000121362F1A09000000000000009DCFCED1B784533127275181A7A9A0A9AF875A2A1E142373A9A99A928365432B140E235BA3E0E5DDB9738165555A76699DAFBD9E919BA0803805000C0711438DAF875A2A1E14237301FE475D07071870788FDAFFFFFFFFD27E5C6B9EBE9D6F44334172ABE7F6F5E9C57D3B31486CA3BBCCB88A400E022863A7C5D1B4BCA6682A0513438FAFC4C1B9A3835B546F79726A839CABA57F3E0000000C4382B9BCBFBEB08D421707225D9DBFD9D8CAC1BC8C40000000176AB2D4E1D5CDB87321052B80AAC0BFC1C3CBA362351B11235294B4B9B3B5B28A35000001447A8F8D9BA2AF762C020000223F37240E05000000000000A2D9E1D4AF6E472D21254F8DAEA3A9AEA58489401D0E2678B0AEA28B7D4A2C2714222B5EABE6E8D5BC7980614C546F90A1B4B8AA989F9E79390800000411508DA58489401D0E267801FE485D070718806F95CDFFFFFFFFD2805D6DA0B2966A442C3C6DB6E8F3F2EBB666322C3F73A0BDC8BA893F12072E68ABCCD8BFBDA96E1D000A3D90B7C2BEBFA4875C5A6E66605D7D93A99A803D0000000A4586B8BEA9B7BC96531C051D5FB2DADFD3BDCCB5812E0000003374B2CAD8D5DAC2760F003780B5BFBCB6C1B9AC71280E071B549CB5C2BCB8AC86380000154E7E999290A29B701F000000283E39220A00000000000000A9DDDFCFAB734629242B4F92AEACA9BAB98E572C11082D88BDA39494845A2F16161F255AACD2E4E0C080866C55556D8AADB1BBA4929DA476300300000314508FB98E572C11082D8801FE495D07071890788AC9FFFFFFFFC6695674A2B494623D2B3C7BC1E3E4E8DBAD5C252D5074A6C1CDC28E3F0E012B79BCC7CCBCBBA45C1200044A99C0BBBFBEA6845C4B68706770849D9FA17B31000000184C8CB7BAACB5C799501C0A267AB3CFCFC9C5BDAC792D0000002F7DC1D7DCD7D8B76413042D8FB2B9B7B9BEBAA6602209001B6AAABEBDBAB4AA80250000095C869D87899BA76D250005132B3833190600000000000000A8CCDFCCA86E3C1F14225587B1B4A5ACA289512B1C183985B7B29A94704E252419112766B3E0E8D7BA7D7D635C60728CAEB7B99A97A89D751C000000001F5397A289512B1C18398501FE4A5D070718A07187CFFFFFFFFFCD725B76A3AF9160372B4991C9E7F1EAE8B8532A29417FAEC8C1AF7D330A08327CBDD7D2CCBFA15B110007498EBEC1BAB8A28A4E436766687087A5A2A3792D000000165697C1B6AEC2B29B4D1F0A2478B1C8D8CFBDB8AD7B20000000397DBCD8D7CDCDAE580B003C95BBB6C4C4C9B5A865210D04226DA2B7BBB9AAB174200000186796A38D8CA5A4511D00000C334435130500000000000000A7D0D5C5975326182125448EB2B3ADBBA986562913083586BCB59A8E77422D20121C3469B4E3EBDAB9877A5D56577185A4C2C0BBA0A3A4752400000000125E95A98656291308358601FE4B5D070718B07393DCFFFFFFFFBB765D719EAE8E63322E549AD1EEF4EAE1A44B231E4979B5BAC2BD83360F08317EB4CFCFC8BDA74C0B000C4C9AC5B9B4ADA08A55445D696E7592A8A6A673330000001C6392AEB1A5B7B59946160D3889C3D9CACFC5BDA06A1B0000003A8ABECAD1D2C7B254080D519EB5C1BEBABCB09C560D00002A7BB2C9C1B6B0B369180000256E969A8486A59A601E0000122E42251302000000000000009FC2CFBB8F551D121127509DBEABA89C957A442511104894B9B4AB9D713A21111620316CBCE4F3DFBC8171685A546B94A6B9C1ABACAAA277240000000020679E957A44251110489401FE4C5D070718C06F98D2FFFFFFFFBB745971A6B39658323C6697CCDFE5E7D7A05620265196AAB6C1B987340B0B397FB2BCD6CDC39D4D09000D50A5C0B7BAB49A7541445A6476849D9D959E6A230000002664A0BDB39CAAB6944B18104092C7D7DCCDBFBA9F5D0F0000035098CCCED4D4D9A5440009509BBABBC2B1BCB29E540E00062B75B3BBBAC1BAA46516000025779C9C88859B95512105001030442D100000000000000000A6D3D0B78947210E0C225195B8B5B2B2A1753E121318569BC2BBA79F612B11121215316FBBE7F1D9B47E775C50597290B0C2C7B5A9A79F6A19000000001B6591A1753E121318569B01FE4D5D070718D0769ED8FAFFFFFFBA6F57709BAD915A34295EA9D1DEEDE7D78E3F18265B90B5BCB1B3792E11173A85B9C8D2CED1964717000B599CB9B3A5AEA37E3B3F5C687F86A1A99A9E661E000000286CA2C1C0A4ADAB97591C134B94C7DDD5C4BABC9E5E020000005097C4D1CFD1C7A241020A5EA7B8C5BBB2B6B5A15A0900002D84B1BBC5BBB2A864100000377BA2A38B8DA896501D0000223B3B18050000000000000000A9C8C7B2894615171B2B4C98B9C4CDB5A37D5223120B42B0C9B7A88D682E000E18163072BFE8F2DBAE8A77625E53698BACC1C7B2B9BF9E6514000003061D6399A37D5223120B42B001FE4E5D070718E0789AE1FFFFFFF9AB624F76A5B38D52323167A9D3E3EFE4CC822C15285F97BEBCC0B580390E0A4C86BEC9C8C3C79C4700000448A1C4B5AAB3AF7E4643536C848BADAEA5946A18000004326BA6C1B9AAACA98A421B154B98C4D1D0BBBDBC934C0000000850A3C8DBD5CFBC8F2E000E63B5C1C6B9B7B8B5994F0700002B7EB7C5B6B8B79C510A00003683ABA79086998B5218080C223B3518000000000000000000ABCFD0B7793611071921539DC6C3BCAE9D834D2316194C9EBEB0B2975D291016231F3A79BEE8F0D5A97F705D52596589A6C5BFB3A7B1A064170000040425659B9D834D2316194C9E01FE4F5D070718F06B9AE1F7FFFFF1A16A6485A4B284502D3567B6D9E3D7D9C97F34151C5692AFB8B3C28B3210155190B9D0D2CDBE994A04001154A9C4A5A1B29D6D3E3E53647C99A4A89F985D220000073472ACC2B69DA8A28749201D55A6C3CCD0C4C5B38E3D0000000263ABCFD3DDCDC2882D04125EAFC4BBBEB0AEB49D4D0A0000348AB1C5BAB8BC9D4B000000388DAFB594869D8E4E1C0000213A3515010000000000000000A3BFBFA06E2B0C040C2156A2C7C4C0AA9C67331D1C254BABC0BBA8946310011F18193880C1EBECDCA37F725752587192A7BCC3C4B5B59E5C0F0000000825759E9C67331D1C254BAB01FE505D0707180074A1DAF1F2FFEA9F665A7EA1AD905433447BB8DCDFE3DEBC6D25092C5EA0BABEC1C2833211194E90AFC1CEC7C1923701000851A6B69AA5BEA9633A344F63879DB2B999934F1300000B4373B2CCB4ADB1AB813F0F1F5A9FCAD9D2C4C7B781340000000F70AEC8D5D6D6C27C24001971B8B4BCBDBDB8AE9B4C000000358CBFC8C3B7AF933E000000498EB3AF878D9D87471A02041F373416020000000000000000A0B7AE89591800030C255994B2BDC6B896562F181C2158A9C1C1B2945619040B0C213980C5EFE3D3A88A745553596982A3C0CEC0BDB893571000000B072A699896562F181C2158A901FE515D070718107BA3EBFBF7FEF09B69658CACAC854D2E387BCAE3E7E9E0B758150B226BABC8BABFB5802C0B1C5A91B3CED4C5BD8E3704000D60AAB79BA1B9A5683B374A6591A4B9BAA6975E130000063F82BECDC6A9ABA06F3A1F215CAFCCD1C8C1B8AE732C0000001A73ACC6D5CDD5BD741300197ABCBFBFBDB9B9B19749070000439DC4C2B6BFB39138000000498DB3AD98949E75381E0B0C243D340C000000000000000000A3C5CA814D170005132867B1C2D4C6B1865E4127132764ADC9C2B896541800070C1E397DCAF1E7CAA98D714D60587E85ABC2CEC7BCBA9763190000000C3078A1865E4127132764AD01FE525D070718207A9FDDE9E8F2D48D606688A9A77C4D364081C4E5E4E1D7B35511001B5F9CBDC1C2B9812F070F4B9EBEBFD1C9BB933E00001B64ACBC9B9ABCA5602833436296B0B8B196915C0A0000154290BDCFC4ACB39E6E29141F66AFCED4D7CEC3AA6D1E0000001278B9C8CDD1D1BD660B00217ABCC8C2B6BBBCB4984402000047A1C6C6C3BABC86270000096098B0B08E95996A321600082B443911000000000000000000A1B4A2773B0F0000082169B0C6CFDDB9854D34241C2A69A9CAC3B1954C0B04130D1D4192C6EEE0C39A8E63483E4D6888A9CBC9C2B5BC986412000000002D7C9C854D34241C2A69A901FE535D070718307EB1EBF1E4F6DA8B63688AA7A6813B24428CC8E0E8DFD2AD490C00206FAACAC3B6B66E3108255E9DBDBCC7CAB5933900001A649FAE8F9AB8A35A32334C7799B6C2BEA08C550E0000174684BAC0C0A9AF9B662E171F6EB4D4CFCCCBB8B36917000000217ABAD9D9D8C9B56106002778C1C5B1B7B4B1AA873D0000004EA1BDBEB1B7AE832E0000165FA2C2B09994A36E3213061635503718000000000000000000A3ACA673450B00000D2465A0D7D5CAB18C4D322A21296EB0BFBBC3913F0C00060D234A8BD8EAE8C4967F644E4348637EB2D1D0C6BDB697550C0000000E3C779B8C4D322A21296EB001FE545D070718407CB3ECEADFD8CB846A698AA6A37F472E4B8CC7DBDFD0D0923B04012A72B0C6B9B7B37929021F60A4BDCEC2BFB4863100001F63B3C5939FB5A35224274776A0BBB9B1949045060000265E98C7C9C3B3A18E602D15236FAFC8D0DACBC1A3680D0000002887C4CDE2DBCBAF4D04002E8EC5BFB0B3B5B0AC85370000005CA2C7C8BAB4AF7E2500001361A7C2BB8D8A8E6134140B173554320D000000000000000000A0A99D7137030000123A77B4D8D4D0AF7C534330262F6EB1D3C5B28D38070008091D4D94D0E8E9C0917F554D4D48547F9CC2D7CFCBB49B5B130000000A44849F7C534330262F6EB101FE555D070718507AA9E9DCCCDBCC795E6D91A4A2753A2E488FCFDDE3DECF833100002A6FB1C4C2C1AF7027062565A2C0BFC4BCB47F2D0000226EB4BF9BAFB59F532728476DA4BCBAAA8D884C050000204E95CCD1C6B7B2965625192C7AB1D4DED6CDBEAE62040000002C96C7CBCCC9D4A951050D4291BABFB9B9BBAFA4873B0000004FA1BEC8C2BFA9701E00002272A3BDBA9C968E643B1303113D4B2E09000000000000000000A0B29255240000001A2F73B8D6CDCDB8855434382E3376BDCFC7B0883508000004214890DBEFEABE83856848403F557AABC8D4D5D5C29A590E0000061851809E855434382E3376BD01FE565D070718607AB0E1DBCDDFBC734F6B8C918F703324519FCCD8E0D4C0792200002B7AAFCCC7B7AF75290A277BABC0C2C6C0AF7B2900001C75B2AB96B1BE945226203D78A7C1BEAB948544020000285B9CC4D0C3C6AE784A1B0E2A71B4CCD6D6C4C0AA51000000003B8FBAD1D1D7C9A0400000398BC4C6C2BEB0B3A5793B07000C60A4C1BFC2BFA56A140000226DABC7B2959396632C160E254B502B000000000000000000009DAC9063220000020C3275B3D0DAC9AD7342313D2C337DC5D3BEB1823200000003125796CEECE3B98E86604940495077AFCAD8DAD0C2954D0D000002135D8DA07342313D2C337DC501FE575D0707187074AED5CDC5D2AA6F596689968A6D332C4A9BCAD5E0D6BA6C1C0000287DB6C7BBB6AC631C072E87B2C7CAC2BDA6712400001D70C1CAA5BACD9D481C1C40759DBABCB69E773400000525609DBBC3C4C0AD7D461F12297EB1CBDAD5CCBFA147000000003491CED1D8DFC79B3500003B93BDC6C0C3B5B7B480320000085EA6C8D0BEB0AB660900002A76B0C9B09B937E5C2F1C0A1A3D4F290B00000000030000000094A688591F010000103878B9E2E3C8A87A43403B203E8CC4D7C5AB7D300000000726589DD6E6D9BA828558453638497AA7D7D1D5D4C2904A05000006266999AC7A43403B203E8CC401FE585D070718807BB3D7C0BBC1A86058708B9C8E6D3927549BD2DCDCCFB15E0E00002E7EB3C3BDBABC6C23113B7FB3BFB7C2C2A86A1D00002378B8BFA8B2C3A04916164380ACBABFBA8D74380000002D6BAAC5C9C9CCAC774118102A7DB5D5D9D7CCC09745000000003E9FD2D5D3D2C38F36000148A1C7C0BBBAC3BAAF7C3405000C63A9C6C7BCB5A6630000002C80C1C3AC98978557331A0A2848592F09000000000000000000A3AB895118000000104A8DC8E1E2CDB57D523E423E418EB9BDB8B07E3800000002235F9CD2EFE4B67A8459413B384D6E9FC7E4E7DBC78D4B09000004246D98B17D523E423E418EB901FE595D0707189077B7DABFB1CCA0615B7688948D5C222559ADD6DDD3C8A95F0900002F80BCC2C4BCA8631E0D3383B2C9C3C5B297550E00002E86BFC2ABBEC59B4A191B3E7DB1C1B7AD8A6C2E0000063B71A2CACAC3C1A66B3913172D76BAD4DFDFCEC1953E0000000746A0C9D3D8DCCA882C00003F98C5C9B4C5BEB4A9713702001366A7C1BBB8BBA351000000348CB9C3B99C8D8C59301E13335153320300000000000000000095AC854E0C000000044285BBD8DDC4A267453C422F438AC5D4BEAB7722000000062B65AACFE0C6A8747E51342E2E4171B1D7DDE0C4BC7B460C0002112F7C97B667453C422F438AC501FE5A5D070718A080B3D2BAB4B8A461546C848A804F262F579BCADBDECB984A0A00003783B6CDCDC6AB6217143D8FBDBCBBB5A6874D10000A387FBFC5A9C3CCA24313153A7EABC2B8AA9273310000004277ABC6C4BDB9A3642F0E0F368BC0E1E6D7CAC6932D0000000856A7CED7CDD6C38236000657AEC9C4B7C1B8AB94622F01000D62B3C9BCC3B6A3510200003789BAC5ADA69E7D4B31261E375E532B050000000000000000009898763C0000000004388EC7DFD8B8976447463E304188C3D1BCA27122000000123E71A8D0E4D5B16F844A29242B3D68A9CEE2E3D8C4914B090000063C80B2BD6447463E304188C301FE5B5D070718B075B7C9BCB4B394534A698C91754824265EAACBD5D0CA8F41000000408AB8C4D2C0A9551E133B95BCC9BFC0A3804A0A0008338CBEC8B8C0BC943C05103388AFC9BAB29164250000033C81B2C6C7C7BA9A57230B092F7CC1E1E4DBD1C08829000000125DB5D6DEDBCEB67B2100005CA5CCC1C3C2B1AE9C5E280200116CA9BED0C7B59E4B0500004295C9D1B6A795744034291F3D55522802000000000000000000939E6D3D07000000133F8CCFD8D6C6975B394D39283E92C1D2CAA6761C0000020D3775B7E0E6D2AD6F825A392D2A3B6EACCCDCD8CDB58E510C0000093E8298BB5B394D39283E92C101FE5C5D070718C07FB7BBA9B0A68854526986867B502A3561A5C4D8D4CC9A450000003789C8D0C6C9A45718133E99C2C5B9BAA3743B060009398BC8CFBBBCC4993F0B033B8FBBC6B8AB9363200000065079B4C4C3CCC18C4C1B04133677BDDFE4DFD0BA82240000001D67B7D3D7D6D5BD6F1200156AAED2CDC0C1B5A88A55290B00176FB5C1BFBDB0943C0000014A99C9C5BB9F9E734536291F4965582A06000000000000000000A1956C3902000000114F93BFDDD0C5965E405449254587BFCDC9AC6F1E0000000B4184B7E0E8D098647C522D2A253E60B4D6EAE4D6BA844A0E000012448BA2B35E405449254587BF01FE5D5D070718D080B6C6C5B1A870454A6681866B491B1F59A2C9D7D9D28F320300013D91B0B9CABEAA56180A3C8CBBBDC8BE986E3204000D499ECCD5C8C7BE8A3708073E8ABEC1BAB6975D180000064381B2C6C2C6BA8E3F170F153886C5DDE2DCDBC57C210000001F6CB4D0DBDAC9B76A1100116AAFC9CBB6C6B0A08455310E001877B3C6BCB7B28D4100000A4A99C3C4A89A9D74423D252B4965592C00000000000000000000948A69290000000016549DD3DAD3B995583D493E2C4B94C7CCC1AE73200000000C4384B7D7DECA915D7A5343312E386EB4D6E2DFC6B57B3B080000134F8AA7B6583D493E2C4B94C701FE5E5D070718E06FA1B3A89C916D4A4A5E8087684117235DAAC4CFD6B783330000003C9BC1C0C5C09F4E11144C95B9C2C1B4915D1E0000144AAAD3D4C2C5C58D3702113B8CB5C0B4AB8C651C00000D4D83B3C9BFBCC18F39130016358DC9E7E8E3D5BB7311000000247EB6D1DCD9DCAC5E1600206EB4D4D0CAC2B8A16F4C3308001174AFC3BCB9B8893702000D68A7C8CFAEAAA1663F3D282E4B69582D0000000000000000000096986D310000000014549AC6DBD6BC8C674C4930264692C5D7C6A36C1C000000174E94C6DFDFBF8B5B7E4B3129273967B0CFE2DBCAB173400600000F5A94B0B6674C4930264692C501FE5F5D070718F081A3ADA29C816337446C868862351C2B63A6CCCFD2B37C21000000489BB9B3CDCFA44811124193C2C6B6AD82522100001557ACDDE1D4CFC290360203378AC4D3BAB38E5712000010598CB7C5B6C0B6823811071A3D8DC5DFE5DED6BD6B0A0000002888CAE2D7DCDDAA5506000772BCCACABCB9BA9A7540260E00277ABEC8CAC7BC812E0100195DA9C5C2AEA49266443A2D39577C5D23000000000000000000008D835C2A0000000025659ECFD9DABD8A5F3441362B4FA2CBD1C9A467240000001A5189B8E3E0C08F57854F3229283362A5CEDED9C2B3783E1204001A5EA2AAB95F3441362B4FA2CB01FE605D0707180078A9A9A7A482572F486E83875F2B0F1D61A7C1D3D2B374200000144EA8C1C8D6C5934A18113E93C3C1C3AE874B1500001862A6D2D7D4CFC7903206054295C3CFBFA58E460B000018599FBFCBCAC5BA85311509114088BFDCEAE5D3BB63080000003A8BBDD2DAE2C59C4A0100247DB3D1CFD2C3AD90552E1A09002380B8CAC5CABB7D3307001767AEC4C1B1AD935A3C332B34678C6B330100000000000000000097986A23010000002B78AFC3D6D9BA8A573D4C382A5BA0CECCC2A270260000000A5091CDDCDBC08D5C7E47302B293362ABDCE9DACAA66B2C0202001859A0AEB9573D4C382A5BA0CE01FE615D0707181077A4B0B4A37A4A293D6682855F2A142568B6C4C7D0B6661F00001255AAC3C5CFCF8F40140D4095CBC8BAA56A370B00002461B4D3E2DECEC3882F060D3D95C5D5C9B99B4B050000226096B5C3C8C7C1832A1203143B8EC2DCE3DFD5B962070000003992C9DCDECDD1A03E00002688C6D7CAC1BEAF9C60281A02002E7EAFC8BEC3B781360001206DB8C3BFACA48A5B433A38425F815C29020000000000000000008A845A15000000052A71A0D3DBD3AB7B4B41433D2D549FC8D3BBA863180000000E4F94CAD6DDC0824E7E4C37352C366AADDDE0DBBDA0792A0300031E61A2B8BD4B41433D2D549FC801FE625D070718207CA6A9AF9D78472E315F7B90632807276CAEC2CAD0BC621600001B61A9C2C7D2C7833D0F124E9ABFBFADA0672E0C0000286ABCE0E0DFD2BE7A22000C478CC2C8BEBB9A4B0A000022699CBBCDCBCAB5792E01000E3B8FC5D9EFE8D7BB5E0C0000003D90C9DCD9D9D0994106002F8AC5D6D1BCBBAB9449241B00002A85BDCDC2C0B07E3300002576B2BCBDA1B090523B433039718C6A3000000000000000000000827B550F0000000034759DBCD2D4A37D54393D30265EACD6D4BE93510D0000000B5B9FD8E5DCBC7E53814D342B2B2E67B3D6D8D6C199672D020000297DAAB9BF54393D30265EACD601FE635D0707183070A1B2B2966F361B345C868B5421112E70B2CDCEC9A765160000176FA8BEC2C8BB8F4312133F9AC1C1BA9C682F0900062F72C0E0DFD6CBB97C2600003C91C2D0BCBE9246050000216CA7BDC8CDD0B978210303163F8CC4E3F0E3CCB5570300000959A2D0E0CED5D68D3300002F8FBECEC8BEB7B48A43251F02002C83B4C0BABBB4793300023485B9CDC8B6A8864B3F4337447D91652D0900000000000000000085794903000000004781A4C5C8BEA06F492F3E262161A8CACABA8F4D13000000114E9ED1E0E2C28851834F3C2B273465A7DBE1DBB88E66300000032E81ABB7BB492F3E262161A8CA01FE645D0707184075A8A6A98958251F396084905525072E73B9CFCED8AC5B1400001665B0C9C0CABE7C2C0A1C54A1C0C9BC9D68200000023A82BADFE1D2CCBC6E25070E499FD1D4BEB78F4A0700002272A0C4C8CCCEB8761C0000023B85C6DCDFD7D5B65C0000000856A3CBDEDBD6C18E3300013B90C8D6CCBCBBAE7D4320130000328EBDCFC6BDB2732A08033686C6CBC9B09D7148393F3B457991632D0400000000000000000085785111000000003977A7B9D5C39565432728252B6EBAD4D5B09C5015000000085FA5D0DBDCBB765183472F3326346CAEDEE8DDBF8A5D300000002B85B7BCB9432728252B6EBAD401FE655D070718506B8E8F91855021153165867E5C160C2C78BAC4CCBEA9581500002272BAC7CAD2B26F2808185292BBC6AE9E5C200000013383BFDBE2D9CDBA65160410489ECAD1C2B890480000002F76A8B9C4D2BBB6701E000115448DCAEBE6E8DBAA53000000145CAAC8CFD6DACB8B2C0006419DC6D3CAC5C0AF7B3109110000418FBBD1C3BAA36A300003448CC0D2C9B1A17B4B44492F53798A653007000000000000000000866A3D00000000084480ACC4C6B9925E3A17261E3472BAD5D6AF8944090000000F59A2D9E4D8B2804C86402A312E3974BAE3E4D7B28652230000053B8EBDBFB63A17261E3472BAD501FE665D07071860739E9EA480491819386C9E965720132A6DA9CEC6CFA546080000287DBDCDCAC9BA792B021A609BC3CBAF945A110000063990CBE0DACEC0A56C1A000D59A4C9D2C2C189400100012C87A9CBD0BCB6AE6718000019488EC7E5EEE6D1A7550100001A67B8D4D6D1CDC77F2E02024D99C1CCC2BEBFA96C320A0A00033892C1CFC2CCA3652508033C91C1CBC2AEA57A4449403C598C9B6E3400000000000000000000916E3200000000054E82A9BDCABC97633824291B207CB8CDC5A885440A0000000F5BA2D8E8D9AA7C548B483532323172BED7E4D6B78A531A05000042A2C4B4AC3824291B207CB8CD01FE675D0707187078A0B0AC82491D1E4B72A5A56C291C3F72B3CDC8B8964B0C00042B7FC3D7CECCAA64190A1959A6C6CABD8F4C1A000000388BC9DED6D1C1AB590F00135AA6CDD0C5C7964C0000002D80B1CDD0CFC1A85C1602001B579CD2E6EFE3D19C420000001D78B2DACCCED3C07422001454A8CFD3C8BFBBA8651C00000009449BBFCFC2BDA05F290C14519DBBC4CAB6A96C3C403E3F5B93A4713700000000000000000000786F3B080000000D639BA7BDC5B896684028241E3678B2CECDA77B3F030000000B63AADAE6D3B47F548C4B3D3535467FBEDEDED0B3814C1C090000489EBFBDB54028241E3678B2CE01FE685D070718807594A09A70350B0F3F729EA05612072F77BDC8CEC491370200063798CFDCC9C39B5415082165ACC5C0B39551110000043D8EC0DFE0CEBCA35F1B050E57A3D5CDC5BB87370000003482B4CAD0D1C1AC631200001C5299C2DDECDDD19B400000001C79B1C9CED5D0C77326000957A5C6C7C2B7B79E6D270700000A4390C6D0C4BD9E6126071654A7C3CECEACA367404A47406696A67533060000000000000000007A6A390B00000013527DA1BDC3B193603C2D2D172D7CBAD1C3AA7C32000000001067B2DADCD8B476498F40323332417CBEDDDFC2A37D462300000A57A5BFBDA73C2D2D172D7CBAD101FE695D0707189078A4ABAC72410F1D5081A7AA5C210E307DBAC3C0C2884204000450A2D6E2DDCF975C11021A5E9EC2BCBB904113000003488FC7DBD6D4C0A55114000762B6CFD4C3C38B3C000000347FC0D2DBCDC39F5512000426599BD2DDE7E2CAA23B000000287DB9C5BECCC6BA671E001562B7C3CDCABCB9A9641E0400000A4195C7CED0B08C5B2D051B59A6CCCEC4B29865374C4E455F979F6B2E04000000000000000000765D21000000001557839AA9C1B68A673726201A3385B7D7C4A46B2A00000000146EBDE3E2D2A7773B9152353B37457FBDDFE0BF986B331500000A59A9C7C1A83726201A3385B7D701FE6A5D070718A0679498925725040D497BACA75A17133778B6BEC3B3853700000E4EA0D3E0CBC7874408023371AFC8C7B08E4A070000074996C5E2DAD2BB8C3E0C001B66ADD7D5CDBB8A37000002328CC3D7D4C7BF9D4F0800082F6CA5C3DCE1E3D39B350000003487B4D7CCC9C8C2661B001065BBD5D5CDBCB2A15A0C000000084B9BBDD4D1B1804622051F67ACC4D0CFC298623A4F4D4D6796A4692D020000000000000000006F5A29000000001E618D9CAAB6A985592B1814103085BECCBEA46C2900000000187AC7DFE8D4AE7E3F93493235384A81BEDCC9C29E6E2F0D00000666BBC9B8A12B1814103085BECC01FE6B5D070718B06F95A38C56240A1D5A8DAAA961271C3F89BEC2BFAB7B2A02000958ABE0DDD1B886360B00347DB1C8C8B78B4507000008488CC0D6D6CBB7873802002364AACCCBC6C18C33000000358FC3DBD0CDC4A35906000A34759DC6E0DADBCC9D420000024290BBCFC9D0C4B0550A001568B9D1CCC6C0BDA557090000000851A2CDD1CBBA804827112260B1C9C9D4BF9B563948474066A6A169240E000000000000000000785D29000000002564859EA4B3A98558282026174E8FC0CBC09D662B000000002F86C3DFDECBA8724290362B353B4F84C1DCDBCA92572D0400001B6EB7CDB59B282026174E8FC0CB01FE6C5D070718C0759F9E88581A021F5B84B0AA591C0A348ABCC2C6B6772F00001058B3D7DCD5BB7C2B090D4082BDC7C0AA7D3A0700000D4D96BDD0CFCEB0873702002B6DB9D4D7CEB8742900000C3E92CDD5D6D2BB944000000B4485B4CCDDE3E0CA9433000001459BB8C8CBCAC6AC5712002278B9CECBB9B7B39A4C000000000E52A2CFCDC2AA7249300D2478B6CBD7D3B89962415A514863909C6723000000000000000000007C5C1B000000003E6680919BB9A68556291310254EA0CAD0C18D5D24000000002980C6E8DDC9A17844983E223A3A4E8FC8D7E6C5A656240000001374BECBBD89291310254EA0CAD001FE6D5D070718D087A5A392532812326499BFA4562916498BB6C6C1AC702B02000760AFD5DDD5C2752D06084384ACCAC4A7753A000000104C8FB8D0D1C1A5772B01002B75B7D5DCD1BD802A0000073C9DD0DADAD2BA994404000B488DB6CBDBE1DDC4882E00000C409CC3CFC7CBCAAB540F00277CB6CDC9BCB9B3965002000000095E9ACDCAC7B1723F2A1C327AB1CBCFC4BA8A473B4D4742749B9E632B0000000000000000000075511600000000306E80899DB7A4804E1E0F1B23498EC2D3B6824D18000000003091C4CFDAC1A6824F9C3B3036355D9ACFE6D5C484471A0000001F7ABDCBB1901E0F1B23498EC2D301FE6E5D070718E0769BA08C51220E376A99C0A2571D114791C8C7BFAD6F2B0000206AB7D9DBD1B66C26050C5098BABDBBAD853C0900000B4D8AC0CFC4C0A4762E0604307FB5D3D0D5B97722000000439EC9DEE2D6BB8F320000114E8BB7CAD8DAE3D5962900001058A4C3CEC9BFCAB0420A03277CB7CFCDC6BFB9964500000000145AA7CDD6BF9667473A1C2D78B4CCD8D2BB834D3B51514C7AA9A26628000000000000000000006D420B000000002B6B8590A2AFA483522912101546A0CADBB689440C000000043A8FCBD2DCCBAA824A96402435365AA3D1E4E3BB823E120100002088C2C6AB8A2912101546A0CADB01FE6F5D070718F074989285522C1B437A9FC2A24C201E509DC1BFBDA16C1F00002C76BDD9E0D1AF5F20071D689EC9B3B3A17B420000000C4A91B8CDCCBFA5701C00082D7CB6D6D2CCBA7A1F00000249A4CED5D7CBB5863100000C519BC3C6CEDAE4CC9130000019569BC4C7C3C7BEA24206092F80C4D6D2C2BBB29B3E000000001E68AECCD6CA94594130163485C7DBD7D0B4853E3A524A4D6FA29F6933070000000000000000006A4C0000000000366F7A8E9FAA9B794E22111C2758AACAC5AF8B4F1400000002389DCEDFDCCBAD7C4C923F2E3236699AC6D6D6A67B3F0A000000208CC1C7A88022111C2758AACAC501FE705D070718007FA99980551E15396A9DBF9D541C235091B9C4BD994D0F0000317CC6E2E6D7B6621E051C5CACBBB7A89D6A2E0000000A5391B0CDCFC3B96C2300044286BEDFD6C6AE6E230000084FA6CBDCE3DFBB772800000C5C9BC9CDD2DEE1CD8F2A00001E5D9EC1CAC0CAC3953E0D113989B6CDD4BFBBB28D49000000001665A9CDD7B8844E42341D478EB7C8D0D2B67341404A4C5884AB9C702E0100000000000000000065310000000000326B858B94A29A743C0A01172560A8CFCCB17B3D08000000114196D0E0DAC6A87E5D9A4D353439649FC5DCD2A96A37050000002699CACAA7780A01172560A8CFCC01FE715D070718107A9B967D452120426EA3C59A45121E54A0C7C5B98D490B000B2D73BDDBDCD0A8510F082770A5BBAEA79171300000000F5587C0D2CAC5A8651F010D3984BDD0D2BFB3791E0000155DB3D8E4D7CCB46D1900001E6DAAC0CDC8D0D3CB832000001E69B3CACDC4CBBA8E35070E418FB9C3BCB8B4BD9C3F00000000186FB0C8CAB0835B493D284F8DC2CBCCD3B06F4038544B5B8CABA2702401000000000000000000632D00000000002B6F818A9A9F9E693A0C03132C66AED7D1B76C32050000000B50A1CAE4DDCDA2814C974B34333E6B9FCDE2CFB66E22000000012490CFD19D6D0C03132C66AED7D101FE725D07071820819FA4824C2A254B81AFC392400F2158A6C7C7A77E39140013387DC3E5EDCFA04808002E84BDBB9C94967441060000125897B4C3C6C1AD781D000C4285C3DAD6C9A96A1700001754B0DAE3D8D8A6601E00001664A8CECCC9D3D8C47E2600001E7AB3C5C6BEC7B88C3B0C2359A0BFC9C2AEB4AE8839000000002883BED9D4B377454B37274B96BDDADECEA26B36394E4D5D8CB39E662A050000000000000000006233000000000E4774848C98A69E75390E08162F68A9C6CAAD7A330E000000065CA6D0DFDBC9A77D4E984F26293E6FADD0D2C7A25624000000003595CBBC9C650E08162F68A9C6CA01FE735D070718307F909A863A1A214984B7BE8A33161553A6C6CEB26C330E011B4585C3D7D6CF9B3E0A003086BFBB9B9E966E3B000000175A90B4CAC7C2A7691B00094394C5CDCBBEAC5A1B00002166B8DFDAD5CAA4612000001F6BABCBC7C6D7DFC1701C0000347CB4C7C4BEC0B4913C0A1967A6C8CDC9B5B0A9984000000000317DB6CFCEAE684C484029559DBBCDD7D2AE663036544B6195AFA76522060000000000000000005C2E000000001A497185879E9D9F72370300184271B9D3C4A56D2D000000001863B6DFEDD7C3A678559D421F314576B7D3D2C49B5B0E000000002197CFCD9C6C0300184271B9D3C401FE745D07071840749C9A84532B254C86B7C28D3D162758A1C2C1A77322080420529AC6D9DAC7943809002F92C0B38A9B8D78310000001C548CB4C8C8BAAA682101144490BFD4C3BFAA640E00002265BFDEE0D9CF985E1700002872ADCCC8CBD5D6C06D1100003E84ABC9CCBCC3B985300F306DA1C4C3CBB0A8A9914400000000338DBACAC7A4624654402D5B9CC8CFD5CDA55629334950738EAC985823000000000000000000005D32000000002347798D898A9EA2722F16061F4889BFD7D1A36B2E050000001B70B7DAE5DBBF9D7949944226334771B5CED2CAA5541C0000000031A3D5C68E5216061F4889BFD7D101FE755D070718508297A08F5D2F345983B6C6833008165DA7C2C8A35A1D0D0B275296D0E1E1D28739060C4394C2B3918B8766370700052E608CBBC9C0C3AA6B17000F4797CAC9BFBAA7511100001C61BFE2E3D7CAAA5F1100001E70ACC5C4CAD7D1BE711D00134A90BFC4CEBBC4B27325112A6AA5C0BCBBB1B1B69B38000000004A94C7C7CC9B5543513E39679FC5D2D5CA9E4C26314D597597AF9A5F2B030000000000000000006B2E00000000295780868091A2996730131027458EBAD7CDA2681F00000000226EBAD5DBD0BB9B7047984B242B3B80B5D5D3BC924B1800000000289AD4C38A58131027458EBAD7CD01FE765D070718606F878F784822224A7DADB4732B151C649FBFBB9F5E22000330599CC9DEE2CB832D00023A9EC6BA838D8A6A440F0003215E8EAFBCC2C3AB641A00084D9ECEDBB6B09E4F1100002B73C9E5EBD3C896500700001D74B0CBC5C0CFCEBC5A15000F508FBBBBBEC1C1BA7023194689B4C5C2BDB3AEA98C37000000004D99C5CAB996483E54453E6E9DB9CACDCA954F1627445974A5B6A168260000000000000000000061300000000020557C8D888F948768250515344F8BC5D9CAA05A26000000001F77CBDEE4D5B6906D50963E22213D72B9DCE0C891471200000000329CDDCC86550515344F8BC5D9CA01FE775D0707187079A49F8D5A37304F87ADAA75230F3361A8BDC19D4F1C0006285A9DCBE1E7CD7C260004489ACABC938383773D030000256589A9C8C3C3B46F1B001058A5CBD3C3BE994C0D00002474C6DDDCD2CA954F0400022D78B4D3CBC0D2CAAC590A001B5896BDC0BDB5BBAF631E104B8AB9C7CFC7AAA1A6842F000000015DA8C4C9B7844B4557433D6BA2C3D1CEBD8843293347527FA1AC986E2B060000000000000000006224000000003D657A8384929E9361290A0C326396C7D4C1995919020000012D7BB8DAE3D3AF8D50419744251F4486C1DADBC3893D0F0000000C45ADD7D07B580A0C326396C7D4C101FE785D0707188073858C7E4123275282AB9B461C132B5E94B7B48E4715000C346AA6C4D5D4BB741C000F4FAAC5B085867B703C000000326294AAC2BEBCA75D170014509ECFD1B8AA904306000E347CCCE4E3DCC38F4C070002327AACD7D2CDD3D6B04F10001F5898BBB9BEBEB8A55F1B1A50A3B7C1C6ACB1A9A79231000000055AA0BCC5B67F3E3956494878A5BFC9CCB9904D21294A5B81A7B59E6923000000000000000000006021000000002C5873827D879B8E6527050B275D9ECCD7B792621600000000367FBCDEE7CFA5855D408F4223254182C3E6D9BF8439090000001544B2DAC18D51050B275D9ECCD7B701FE795D0707189075939994502C264D87A4964F13172A65A6B6B88B460E000D3675A7CCDFD5AF662201115AB2D2B7898B7969390100042D6891AAB9BEC7B1671B001A559BC0C9BDB68C3D0B00042C8DD1E9E3D4BF933D0100002981B8D6D0CBC8C7AE500C002168A3C4C3C7B7BAA05916194F9BBBC8C4B3AFA8A1861D000000076CB3CABEB67A3D3D4B3F4078AAB9C7C8B8863F25234455819DB79E672F0000000000000000000058240000000027597B897984A0916334190D315F9ED5D1C5934A10000000003994CAE1D6B6A38353379A451C23467EC5D9DDC08A380D0000000F48B7E0BF814A190D315F9ED5D1C501FE7A5D070718A0768E8F884732355480A887430B0A34629EC4C6872809000B437BB9CDD2CFB16B1A00105EABC8C0997F7974390700012F65809DBAC3BCB06419001A5CA5C5C8BAB68A380200063A89D2E9E2D5CA9340000003337EAFCDC4CAD6D3A04009092B7098B9BDB8C4BEA955152162A8C2C0BCB4AEACA481220000001471A6C1BBAF7A473A593E4577ADC3CFCDBC792D1722375996A9B99A5B22000000000000000000004C17000000003E637E7C7B8B9E8D6323120F2D649FCDD8C495481100000000448FCAD7DDC09E734B338D311C1B478ECAE3DDB880360E000300174FBFE7CC7B42120F2D649FCDD8C401FE7B5D070718B077899B8755363B54859D793A1225457398BEBB80320A02165391B5CBCCCEAD5D11000C4AA2CCB89D9488743E0C000A3671909FC1C2C0A55116051A5CA7C8CFBCAC81370000053F8ED6EBDDD4C292400000023785B9CDCCCED1C89A3404002E749FC5C9BAB9BCA44F0F2266ACBEC0BCBDA19F9B7B220000001974ADC8C9B26B363A524A4B79A9BECBC2B9783015203C7293AAB8995D27000000000000000000005C230000000041738D89868A9F8B682917173E71AAD7DBC5954B0900000003479AD1E7DBBC8C623C288B3B16214491CEE6DAB47126000000091158C2DDBC813E17173E71AAD7DBC501FE7C5D070718C0878C938D563D4F5D8FA27B340B17416DA0B6B8803200002A68A3C3C3CCC4A75D1000135EB3C1C69D8984793900000B44728BAAB3BBC4A85716021B70AECDCDC2AD7D2900000D4096CDE0E1D6B4873600000C458FB8D6E0D5C4BD812E00003D8BB2BDBFC4BEB69B4E132C6CADC4BFB8B6A1A69A7C21000000207EB3C7C2A35E283341394680A2C3BBC8B26E2D12263F689EC0C2A2682C010000000000000000005A28000000004265827C8292978B5B2D1B1A4274AEDEDBCA984C1100000019549DD4DBD6B285513427903D1727509CD1E6DFB67A2D0B00050C1663CDE1B9733D1B1A4274AEDEDBCA01FE7D5D070718D078909789563A4B648CA27123041D52708AA6AC742300052264A1C5CFC6C3A76919000C5BA4CEC29A90887C3D06000C3D7E94A4BBB7BD9E521A041D64AAC6C8B4A67B20000015509CD7DCE0D2C2933C000000468FAFC3D6D6D5C4882C00003B8BA3C1BFBDB8B38D43153284B7C6C1BEB4ABA8A16E1E0000002080B6C4B9A35F353B45404F82ACB7BAB7AC6B2C161C4063A7BEBDA470260600000000000000000045190000000841718E80769094826035121B3975B6E1DCBC85440D0000000F58A2D3D7CFA37E432F208C3D1F2557A9E5E8DEB96D26060000011C5ECAE8BE743F121B3975B6E1DCBC01FE7E5D070718E07C8E877241303F4D73815118001A4468879F9C5B1500002972B1CBCEBEBB92570F000D57A2E1D3B0A690813F0200184A849EA3B8BCBDA24A0000176AAEBCC4B6AF6B160000175CA2DCE7D9D5B6812D0000024B9CB1CECED2D2BB7B25000B4488ACBABFC6BEBF8A380F408DB3C1BBB5AFA3A8A276180000003390B5B7AF9C50222F413C5583B6C7BDB9B06728191C366B9FC0C59C6A2E0B000000000000000000551F0000000750819090878D9A875B311C233A80B8DADABD8F440B0000001D4EA6D9DDD1A3713B2C1A8C35162764A6DAE3D7B26B230300060E2B6CCFDDB673471C233A80B8DADABD01FE7F5D070718F075888B773A3D49577876510B000F5269839D9B551400002070B3CCC1B7B29B4D1100105DA2C6BDB0A9957B380C011A558F9B9AABBCC59C4B0A001C6EADC3CDC7AC71150000105EA4D7ECE6D2C58A2C0000094092ABC7C8C7C5B7691500105597ACB6B9B5C0B48F34184695BAC0B4ABB0A09E976B140000003E94B9C7C1A758242C433E4D90B9B6BABEAD6A1F120E336CABB7B6A6662E0000000000000000000053140000001350789682818992874E2D23285386B6E8D3B68A4B00030000135EABD5D7BF9D5F362715863E253265B9E6F0DBB16A1E090007062681DFE9BE6F3F23285386B6E8D3B601FE805D070718006677856B3127445F7A7237030019516B7D9A8D530F00032C7DBED2C6B2AF904A09000B589DC8C3BCB5986C370300115099A8B0A2B0BA8C420E002369A7C2CDC4A8611300001B64A8D9DED6DBC1802500000D519CB9CAD4C4C09C560E000A539EB5B1B8BCBDB5722D1A4798B9CFBFBCBCAF9C9B6316000000429BBDBFBE9148182A3B3C5A95ADB3AFBAAD601B0B1B407EB4BDBB9F6D340700000000000000000050190000001D628EA19A8C9B9A8F552922355F96CCE6DFC17F3F010000001565A5C1DCC18B55301C1080412D3A75C2EEF7E1B06B220400040A297CDDE7B9734922355F96CCE6DFC101FE815D070718107A878C6C3D3448637D662B00001E50657B917B4A0D00003394BED8C1B4B193440900104A9BBEBFBCB09C70320000165D99A7B0B4B5C1893C06022575B6B4CCC1B2611000002062B5E2DDDDD3C884300000034791B4C4CECFC4A6490A03185D9AA6AAB0BAAEA76A2B144C9DC7BFB4B6ADADAA9468100000005AA0BBBFBF97451B2D42405A9BB0BFB9B1AB5C110B14356EB0C1C3B37633070000000000000000004D0C0000002B5E8F9A9390919F7D4F332D336A94CCE3D9B47E4F090600071961AFD0D7B78749271913873B283376C7E6EEDCAD651300000A1B3094DDE3B1643D2D336A94CCE3D9B401FE825D070718207381836C2D365568795F2300002662747587743B0500002D84C3CEBDBAA88A3E00000D539FC5D4D1BE9E6E2D000018559DB3BABAB3B48A3408032B73AFC4C2B8A25C0800002872AFD7DBD9D8BD74210000155294B0CDD9CEC48D3E0504286C9B9F9CA3BBBEAD6E22135FA7C4BAB7B6B1A8A49C5A070000085BA9BCB6AE883E212D3C4B6899B6B8AEB19E56150713467FB0C3BEA9723A0F0000000000000000004009000000195D8CAB988A95967E4D32244083B1CEDCD3BD793F000000001561A7CAC7AE753A1F1115843A303D84C2E7EAD7AF711D060108113893E1E6B2633B244083B1CEDCD3BD01FE835D0707183075787C5A304258737A5712000027686767725F260000033F97C7C9C0AFB0844403000B4895BAD0D1BDA171280000156AAAB4BAACB2B0762507053281B1C4BEBCA2580500003174C9D3D1D6D3C17D1E000015519FAACDD1D6CA8F3B07001E6A909992A2B8BDAC701D2065A8C3C8AEADB0ADA894580E00000F68A5B7BEBC8B3B1628384E6798B3B3B2B6AB501D0A184683B4C4B7A97732070000000000000000004702000000236788A4958D968B7247342A498EC2E1E4D1B07A2F0D0B04082973ADC6BCA66B30121A118437224088D7F3ECD6A65F1D00010C123F9DE4E3A164362A498EC2E1E4D1B001FE845D070718406B796A52262D556D714D0500002E656867745528020006409BCBD4BDADA979390000044494C2CFD0BC99662800001F6EA8B7B8B2B0A76D2C0B0E3279AFC3C3BBAB600800002D91C7E1D5D5C6B4792200000E63A4B6C8C2C0B9852C0006256B9B848BA0B6BBA05D2E2471ACC8C0B7AFB3ADA5914B000000197CB0B0B7B5883611183F5B7DA2ADB1A8AD954A2009104282A0BBBEB77E3C0B0000000000000000003D06000000206E9AAA9F9A97906B422A354D94C8E4E0C5A76B3109120B0B2872B0C5C5A25F2E0E060E7E402A4088CBF0E1CD954D13090211224FABEFE1AC5F36354D94C8E4E0C5A701FE855D070718507866655C2D416D83794E0900003570636A6E521C00000848A0C5C4BBBFB4762E0600074793B7C7CAC6A3763200002474ACC6C1B3AEA7612707103878B4C3C3B8AB540200003081C1DDCDCAC3BF761A00001E639CB5CECEC7B8732500033472A1888187AFBB9B541A267EBFD0C6B4B0B0B1A1894C0000002E83ADBCBAB8883B1C21345B83AAB6AFA3B396480E071C487EB1C0C4B16D3D110000000000000000004318000000387895B39D96938754483535509ACCD7E1CFAD7C2E1E140A083178ABC3BE995F210D020B7C382255A0EAFDF8CDA24D0E00000B1B61BAEFDE95503D35509ACCD7E1CFAD01FE865D070718607E745F5230476E807938010000477D756E643E1700000F4E9ECBD0C1B8AD773501000C4492BBC5CAB79B753100012976B8B9BAB3A99C5B16071B4A87B6C2BFB8A1540000002F89CEE5DCC6CEB96F1B0000226BB0B6BBBEBDAA570C0000367E9D7E789ABDB9A05117237CC1DACCAFB2C3A8A792430000003186B4C1C6C68F36132037698BB1B2B4A8B68D461C0A1F458ABBC5BFAA653106000000000000000000380E000000306899A7A39293825D2D23314C96CADFDDD3A26F280B140F0A2D6EACD6C0864B230B07097D41365FA2E9FFF4CA9852160100092157CDEFDD9A5726314C96CADFDDD3A201FE875D070718706B6456462741788C73360000004972645A50350700000E51A8C9CDCCBCAB6F3100000D4997C8CCC5B8A67B3303002B7AB7C4C2BBBA8C551910174E90B7BCC3BB9E440000003F94CED4D0CCB9AF701300002F75B3BDBECDC3B3601100003382936D6A87ADC2A3520F257CC8DABAA5ACB6ABA0803C0000003B9DBABEBFBA8539121D396A98B4B8B6AFB586381A0B194E8DB9D0C79D582A09000000000000000000400B00080E31709BB39C939B7F4E3128335D93C3E7E3CAA55B1E1A221514397CADC2B388471E0C08157D3B396AB8EAF4E3CD95410E0000091D6AC4F1CF904B37335D93C3E7E3CAA501FE885D0707188071716044223F7889762C0000034F826E624E2F0000000E4CA8D0CEC3BDAF752700000C479CCCD7C3BBA97A3500002E7DB5C9C1B3AD94531D0816528DC6C5C8B4964700000D4FA6C5D4C1B9C1B3670700002D7EB2B0BFC8C7AE4E07000A468C925F5C85B1B39151213A88C4DEBC9BA3BEB4A07A360000004297B4CDBFBF963812113A79A2B6B8B4B5A7863C100E224F8AB4D1CE9E63310D00000000000000000042120F091D4776A2B2AF937E6E492D264763A0CEE5E3C6A25E22021A111C387BB8C8BF8B4911010008783B3F79C0F2F9EAD28B54110100022371C7EED182432E4763A0CEE5E3C6A201FE895D070718906E6B60452B4980986E27000012618E7B634A210000001A61A9D6D9CAC1AE742E00001B498BB6CCC9C2A6752900103474B7C3C4BEA38A47130F2A5597B5B8C0BC9B3F03000049A6D0DED0C9BFA95E0300003378AABDBECBC5A44300000041838D605485BABF8B3F123D8FC5D8BEA0BAB9B2A6823500000055A1C2C0C2B58C380C164782A7B0AFADA5A5802D0E0D285A8DB4C2BD996835010000000000000000003C1513161A4173A8BAA79D876C472F2C4562A8D9EADCBD9A501E002521243D72AEB8A3783B0D09090A7F504D86C1ECFDEECB88360E0C000A257AD7E8C17C3C2B4562A8D9EADCBD9A01FE8A5D070718A073705841365A8797742700002A6E977F65401C0000001861B6DFD2CBC1AF6D250000023D87B9CEC1B3A7823A09083981BDC4D0CBAE843C1E162E669AB8BDB4B2903D00000B59ADD1DAC7CCCDA5510400003073B1AEBCBEBE994B00000D529990504676B5B77F33133CA0DADFBB9FB1BEB397672700000D62A2CBC2B8BB862E091B4D8EADADB9AFAAA0692711172C4992B7D1C7995730120000000000000000003D112C2B334F8EAABDA8997F5E33262E4A63B3DAE9D2C3934E15091E2123438BBED3B27630160909128043548ACCF2FDE8BD8234050004102E7ACFE9BD643B2A4A63B3DAE9D2C39301FE8B5D070718B07973583F2F5984927823090A287B978A6B3A0F0000001667B5DDD3C4C8A76A1C000015559DC2BFB9B5AD862C000B3586BAC6C7C2B68636101F386BA4C1BCC6BC8B3A0000116AB2D6D1C9C9CDA2450000003E7DBBBFC6BBBB8F3B0000184D97914C5080B1A66B27184099D9E2C39AB9C2B48D5E1800001566AAC9C9CBC288320D1C5B9AB0B8AFB5AFA66F2915162F5A9BBBCCCA9A552A0A0000000000000000003A17303A28518DB5BEB697825D392F334173B1D1ECE9C288541A0921212C4E8DB1BFAD70340B08020B7E435295E0F7F6E6B27A2D0B00000F3590D0E1BE6E34244173B1D1ECE9C28801FE8C5D070718C06C67542D27588E935D200A123C82A5946338060000002166B3D4CAC7C5A26C210000165495C8C5B7B4AF7A3206113D91BFCEC3C1A3752F0E194C76ABCACCB8AF8D2D00001B64ACD1DBCED2CC93470000004093B5B7BEB8B28F2E00001A5C90824C3F69B7AB6A291A4AADD5E2C8A6B5CCB584510800001B71B7D0CDD2C18F350B0D549CB4BBB3B5AF9A64240E19396393B7C7C293451D020000000000000000003B143A3D45649AB1BDA892764B32222D416DC1DAE9D7BB8E43130B2A2832639EABBFAF6F340C0606006B4057A1D7F8FDE3B76C330C07001C4BA9DCE3B0693727416DC1DAE9D7BB8E01FE8D5D070718D0797B5D4037709DA26C2315164B8BAE976F32070000002770BFE3D1C7BE9D5F1900001E5292B5B8B0C2B9802B0B16397DB9C9C1C3AF76280E1F5683AFC2BFBBB68C3600001B75ADCEDED3D3CA9735000000468EB9B9C4BFB58E2F0000185C9B9144417CB7A25C19104BADDFE5CCB1BAC5B47A3D0B00001F7CBDD1D5C9C784350A14529EB4BCB1B3B59F5A1B0A193B6B9FBDC0B98F4A1E000000000000000000003417363C354F86A8BBA4855F442628365384B4DCEBD39A73380800251D2B5D99BCC69D5E1F09000A0F7E446AAADEF7FAE1AF6525010A0F114BB3E4E5AB60392A5384B4DCEBD39A7301FE8E5D070718E0737B5B3A356D9E9C6A2C102B5AA0B7A87334010000052E7BCBDCD4C3BF8E540E0000194F96BFBCB1BDC3792C010F3C94CFD3C4C4B56F241129618DB6BEBCB4AC7B2400001F77B7DAE4D2CCBB83370000025395B6BDC7B9B68A340000205C96813F4578B29C53141D52B1D9EADFB3B7C2A476340100002F8BBDDDD1D0BB701F051763A4B4C2BFB8ABA14F1C1520346398B5C7B38B502304000000000000000000372046534B6D96B5B6A5906C58322135537FC9E3E2CFA8793507021D1936669DC0BC9758200306010F6D456DB8EAFFF8E0A75F1F080B05154AB5CDE3AB5B312F537FC9E3E2CFA87901FE8F5D070718F0778A633F3A6595995E252038649FB7BA7A3A06000000347BCBDEDEC6B58B501500001D579DB1BEB5C3B87722050E4599D2D4CECDAE681D09276296B5B8B2BDB06E2700002376C0DBDDD3D0BA85290000045295C4C5B9B1AF822B00002D77B092494478A98E45121350B7DCE6CDBABFC7AC752A0000002B80C6D7D3CFC57B1B01135EA5BCB6B7ADB998521F1722467C9FBBBFB8804621030000000000000000002D2F455A506993B4B8A387653E2A203E5E92C2DFE3CEAB72290A001A233E77B0BBC2A14E1A060E0316834468B7E0FBF7EDA966180000041960BAE8D79A4D322D5E92C2DFE3CEAB7201FE905D070718007B81674139619A966030274477ACC7AF7C27000000043D81CDDED4C3AA82491800001D5488B2AEB4C5BC76240E1C509ACCD5CBC6AE6424112E70A8C9C8BDB69A5D160000297DBCD5E1DBD1B56E1B0000055E9DC0C5C5BBB0732100003472A889474181A18231101152AADDEAD6B7C0CAA7681F0000003A8DC4DECFCDC0742004146AAAB9BAC3B7B893481B0E246693A2B2BDBA7C431A0000000000000000000041274452456399BABFA58663361121466788CBE5E2D7A065270C1213295283B0C2B5954E170602000A614D80CAFFFFF7D5A84A130F07001463BEE4DA994E27266788CBE5E2D7A06501FE915D07071810737E60372F61928C572C2B4E82B2C9B78127000000063C8DCEDFDBC2A982410D0000165D8EA4B5B4C8B76925101A609DD8CDC8D0B664140C3376ABC0BFB6B2955D1700002E8BC1E7E4DDCCAF5C0F0000095FA0BEC6C4B1A17A2000004185AD8C494D80A47A2D0E155CC0E9EED9BBB1CAA8581A0000013F98C4D2D9D5C07421001966AABCBDB5B2AA883E100F286091AAC3C6B1773F1D05000000000000000000383057636277A6C4BFA787644521214768A6DEF7F6DBA96B320803222F4F85B6C6BD964C0F00000F0E75537FD0F1FEEED0954B1501060A2074CCE1D697452D2B68A6DEF7F6DBA96B01FE925D070718206E79562C2858807250203C6595B9D3C88C350000000E3F87CADBD0BA9C7C3B0F00072E5788A8A9A9C3AB6C2E0E2362A0D5DCD3CCB8641612307FB5C8C0B9B792480900003783C6E0E1D8D4B15E0900000862AAC4BBBDBCAF6D2200033D83A78B5350879D6B270F1C69C3E9F4DFC5C7C49C4D0B0000004695B9D2C4C9B16221032377AEB6B8B7BAB48C37141A34719DABBCC0B579361000000000000000000000352640524C5FA2C0C0B38B583B201D477DA9D6E6D8CDA76C2808071A2C578CB7C6CD914910070008166C558FC9F8FFFCDC944017000000207BC6E5D892452E247DA9D6E6D8CDA76C01FE935D0707183071835536336182784A2E43709ECBCDC0832B00000007419CD1DFD9C1996A360500052D6091AAB0B4BCA959200F2A65AECCD4CFCDB86217153E8FB8C5CEBBB791490000003590BCCCDAD6CD9F50090000196AABCACEC1AF965610000A4396B3964F52919A5C1E000C63C1E4F1E5CDCDD0A34E00000008498EC2D6D8D2B2581708237DB1B7CEBCC1B07539211D41779CAEC6C1AB6A2E0F00000000000000000000362D484B4D6FA9CECEC18F5730101E3F7EAEE8F5F0D0A1662815111929699AB8CAC68A3A060005081373609ED1F9FFF7C4884313090B0C3382D4E7CC793128227EAEE8F5F0D0A16601FE945D07071840716F582B235172603B21417BAACCD0C39033000000154D90D2E0D8BB9C68340800072B66829EB4BBB3A0612715306BADD4D9CECC9E5A14144693B8C2C7C1B78730000007469ACCD8DFDECF9E4E000000186EAEC8C8C6AF97560900065288AE925360949B4E13000E63C7E2EEEDD0BEC8924A0000000B50A8D3D5D8D0AE5A13002D71AEC8C3BCB7AB76381419357DACB5C6BEB66B2A1600000000000000000000492D4C58567CB0DAD6BA905E33272A517BB3E6EFECCF9D6E2E180015316DA2C6CFBA8F410B0E080D196A589EDCF8FFEDC68D4009040906378DDBEED67F3228227BB3E6EFECCF9D6E01FE955D0707185077875D322E4C69633C2E4D8DB5D2CBC48334000000124E9CCBD1D0C39B5D20020002325991A9B6B2B7A75A1B133776B3D5D0CDD2A95D13164E9CC0C1BCBDBA7F2500000043A3CED5D6D1DBA3410000001D78B1C4C7BEBD9E490A00145698AE8A566D998D420A001066C3E7EBDCDACCCC994000000009569FD6E0D8D0A1530D002480B4C7C3BAB7AC773F201B377DA6B3C7C49C62320B00000000000000000000503954596780B9DBE6C4925A2E1D2E5A89C0F0F4EBD6A47A3513171B3B79A6C7C5BF8836070003001464609AD8FCFFF1BE85350805080E3895E4E8CA813E202E89C0F0F4EBD6A47A01FE965D0707186072845B2D2849593E2828578FAED4D7C88E25000000154D98CED8CEB389561F0000103C6690A9B7B6B39C53140E2C76C2E2DCC8CBA8560C1A5A97C1D0D2BCB77A1D0000054FA9D4DADDCECD9C3D0000002277B3CABCC3B497400400136295B7936A708D753904001E70CFEAF5E0CBCDC994390000001458A3D1E0DFC58D4F0900247EB7C9C3BBBEAB78331B284489AFBBC2C0A157250B000000000000000000004A2D45545B85C0D5DEC38A48232A2B4D8FB4E9EDE4C99D6B341F151C3D78AACBC6BC8A360B17110D1060609FE1FCF8E5BB7A340700070038A6EFF3D07B311D1E8FB4E9EDE4C99D6B01FE975D0707187072734B17143549312B275299C3D9D0C57D2D01000014539CCDD9CDAE8A501E0200092B658BA8B4B8BB9349130B3C7CC1D8DCCEC7A057121050A2C8D2C6C0B6711800000D50AACCD5D7C9C48E2A0000002F86BED7BDBEAD873400001B699BBF9B63768E652C02001A6BCDECEAE3D0CDC18C3A0000001B69B3D2DCDCBE96440C012983B6CDC6B9B3AD6A341E365793B3BAC0BF92532406000000000000000000003C2B3F4C6188C6EEE4D796522426396798CAE7F9EBC99F6E301709143D84B3C3C4B57A30030000040F656DB3E8FFF6E9B9732A0800010F3CB0E7E9CC7E311F2198CAE7F9EBC99F6E01FE985D07071880777644251E3D4434192452A4C3CDD1C58E310000001660B9D3DCCCB68645100000083B6B94BBC2B0B48D3E0404377BC3D8D4D4C8A756161A53ACC2D8CDB7A3611200000855B3DCD9E4D3C9872B0000002780C5CEC7BDA5742602002670A4C3A070838C5C1D0000105CC4F6F2F4DBC6C9903C0000002365AFD8C5D9C3903202002886BCCACBBCBC9C66331E295199BEC6CBC09D571800000000000000000000001F293146578FC3E9EDC9965430232F659BD6ECF6E0C4986336211A1E4089B6D5CFBA7B3C0D020802135E63ACEEFAF1DFB273340D07031656AAE6EBC5703D261A9BD6ECF6E0C4986301FE995D07071890727E511C1427282616285D9CC2D0D1C18A2E0000001F69B0C2C6C0AC81451600000B447897B9CCC1AD7E3D1012388EC9DCE3CFC3A54D101C61A0D3D4CCBEAE5D0300001160B2CACDD7D5CB8C2B0000003291C3DDC7BFA2691500002876B5BD987C8B95671A0000186AC7EFF4EBD3DACB8626000000216BAAC7CEDCBC6D1900002F88C2BDBDB7C39D60292F384E9AC3CDCFBF9B481D0000000000000000000000301F3842548AC9F0EACF9052342D3F689CCDEEF9D9C0965D2E191A1B4192BBD0D0BD84370105060B105063A8E3FFFBE2B0671C05040D1457BDEBEBBB752B16209CCDEEF9D9C0965D01FE9A5D070718A072784310081A201204215BA2CACDD0C788290000001E67ADC4C8CEB38636050000024679A1C5C5BFA3703407143D95D0DBDBD0CB9C4E0D195FA5CBCFCBB9AF4F0000001562B6C5D0DCD5C17F270000083494BFC7BBBC9C531100033E8AACC4A77C9196570A00000B6AC1E7F2E9DECFC586220000002574A4CBD2D1B66C22000C3785C0CACDC4C29F5A34263B5F9EBEC7C8B8894619000000000000000000000032272F456291CFEEEDC9874A2F344673A5D5E7F4E0BB91542C190D244D94C0D6D2BE8B3809040C07185E74B7EEFFF0D8A35B1E06020A1359C4F9E3BA672B181EA5D5E7F4E0BB915401FE9B5D070718B06D6B2E030015170208255B9DC4CEC3AF7E31000000255DB1CCC7BAA779390600000E4B77A6CAC7BE98631A02114198D4DDDCD3CFA14A0F1962A6D1CFC2BCA653000000186CB8CDCCD0D1C17C220000003187C2D8CFB191470200033B95C1C1AC8D99984A0700000F67CEE9F2E4DED3C5861E0000002A74B8CBD2CCAA5F1D00113689C9D5D2BDBC994D312D3C6CA1C3CAC5B48D42130200000000000000000000422A36527CA0DBEDF7D38F412C354973ABD3EDEEE0C08C53210F12255A99C1D7D3BD8D3F030202091B4F76C4FAFFF2D3A1541C000007165DC1F4E6B65D2C1F25ABD3EDEEE0C08C5301FE9C5D070718C07366330C05110E00062266A6B7C7C2B77A2B0000001F76B8CAC6BFA2702C000000285287ACC8CEB88E5A150617488FDAE7E6D3C79C3D051B60A9C8CFD0C0A24E000000206DB9C7C7D7CBC4771F00000841A3CFCDC6BA81360000004597BCC4A9949E863B0000001261BAEBF7E7DEDBCC7F240000042E78BBCAD0D0AA561100053D90C4D2CBC5BC9A553D35406799C6BFC3B97E3D1305000000000000000000003425445E7AAFE7FFF9D39352302B5071AFD9EDEADCBA85502B191025559CD1DADBBC82380800000A1D517AC0EDF2EFD29F5A1E0700021968C5EFE7B36122191FAFD9EDEADCBA855001FE9D5D070718D0736D390C00070100011F659CB9C3C6AD7426000000297BC1CBBEB797622A050000205496B5CACDC19B5419000C4395CEE6DDDED29B3F0B1C60A8C2CECEC6A4490000001E74B8CDCECDC8B37A200000114CA6CAD5CAA8722500000A4F98C9CFB497A38A390000001A66BDEAF5ECDAD0BB83260000023077B1C5C6CC973F0600104798C9DCD6C6BA9F472E304464A1C5C2C2AC7A3F0F00000000000000000000003F31456786B3E2F8F9D093522E3A457CADDAFDF2DFB276461B101B2A6BA7D5DED8C1853E09000006164473C6F4FAF1CB984F170000081665C5F8E6AD642A1622ADDAFDF2DFB2764601FE9E5D070718E07B75350000000000041F5B90B6C1B1A76F190000002879BFC8C1B9936927000002236598B8C9CAB883430F021053A3DCEAEDDFCC953F051C62ABC8CAC4C1A44B000000287EC6C8C9CDD0BF731B00000F4FA8D0D3C0AC6A1A000008489AC0C8B7B1AD802F0000002361BAE3F4E3D4CBC17F170000043780B6CCD4C7903D0A00165391CCDBCBC5BD974A353847659CC2C5C6B177370B00000000000000000000004637455890B9EDFDF8D0904B2734436AAFDEFFFBE4B97A401B14151F5CADD3E9D2BE883508010002234A82C9F0FBF0CF93420C05090D1369D1F1DFAE611D1D20AFDEFFFBE4B97A4001FE9F5D070718F0715E1F0000000000051C6496B0BCB7986119000000256CB5C5BAC39360210000002D64A4BFD1D0B88F490C001C509ACDE6E2E0D2933D0B1C6AABBEC9C9CAA3420000002F79B3C8C0CCCCC2791C00001056ACCDC7BFA4561700000E529FC5D5B8A5A07C2B0000001E6BC4E8F7F0D4D1BD701700000C4687B6BFC9CD913800001B54A1CCD9D9C6C08C48383D48619EC2C4C0A766330C0000000000000000000000463C4A7484BAF1FFEBD18B3E1B2C4574ADDFFFEBDBAF703D1C171E3076B2D8EAD8C58030040002091D4B80CFF3EDE8C289451F1106101C71D0EDDBAA5422171CADDFFFEBDBAF703D01FEA05D0707180073621A0000000000002B6792ABB6A099630D0000002D7AB6BDBBAD8B561C0000002E71A9D4D3DBC089330C0213479BCDE8DBD8C08D360B1E66AACBBFBEBD9D3D0000002B7BAEC4CDD3CBBA761B00002262B4DECAC09D480400001B65A4C4CBBAAFAA802E0000001864C9E8EFE7DFD1C1680E0000114C92B4CBD0C592350200265DA8D1D7CDC8B26F3C32424964A6B9BFBBA66D2A100000000000000000000000392F436D92C6F6FDF4CB89421A314274ABDBFBF2E4B06E3C1C0F113F71A9D5E1D1B7873F0A00000017458BD1FAF8E3B1843C0C000208237CCDF3DA9E5422121EABDBFBF2E4B06E3C01FEA15D070718106C4F12000000000000275A92AEB4A88A5106000000287EC2D1BEB28C4C0E0000033073B4CCDADDB773280600154E97D5E5DDD8C99531052467B3CDBFC7B58A380000003483BEC1C6D0C2B9681500002B67ABD3D4C6A14B0000001E74ADC1C3B3B9B67A200000001C62C4EBEDECDAD1B765070000185A9FBFC8D3C07D2700002060A3C6D9DCCFB67F3F38444F67A4BAC6BBA871350C00000000000000000000003A3746759FCFF7FFFCCF7C2F1B333D6CADE7F5F1D8AE6D3914000A286EB8DCE7DDB47F370A0000032B518CD6F7F7E4B87432120D040A2381D7F6D788441C172BADE7F5F1D8AE6D3901FEA25D070718206E5721000000000000306784ABB6A280570B0000002778BDCFC2B4885413000005357EC0CAD3D7B972220B00194C96D5ECEDD2C4873A0C2564A3C2CAC4BD92380000003684BBC8CBCBD4B5610F00002F74BCD2CCB393440000001D73ACCBCCBBB3B580240000001468BEE0ECE1D8D3B45F0300001D6397B8C9CAC27C230000205DB1CBD5CDCABD734038464667A6C1C7B9A576320600000000000000000000004541547E9DD0F1FFFCCC7F3D1D2D4162AAE8FBF5DBA26A321D0C1C3670B1D4EBCCAC7934060000001F4891D7FFFCDDB3743A150201192B81D7F3DA954B281D27AAE8FBF5DBA26A3201FEA35D070718306D500A0000000000002B6A8DA5A89E753900000000257CBCCAD3C39347100000083681C4D8D5CAAE66230503145494D3E3E0D6C08133132D6FAAC3BCBDB78E2C0000053C82B5C3C5D0C8B4641100023276C4D3CABB802F0000002B81C6CEC5BEB9AD731F0000001472C0E0E8DED3C3AD54000000265E9BBACED4BA751900032D71B2CFD7CFC6B8724142474E5D9BB3C5C5A6733A0A00000000000000000000004E39517BA4D5FEFFEFC785462B314875BBE2FCF7D3A7642A150A133F80C0D6DDD7B16F3306000000275496D7FEFAE1AB6D321705050E278AD4F0D38D4C202B29BBE2FCF7D3A7642A01FEA45D070718407E6A300100000000153E6F96AEB59A7940000000002575C5DADACB9F520C000011448DC9D9DACCAF64220005225097D1E0EAD7BC7E2C08256AADC3C9BAB58F2F00000F4B89B9BBD0C4C0AA5912000B4184B8C5CCB67C2A0000003187BBD0C2C8BCBA6B1E0000001D6DBFE4EDE8D9C5A94C000000216DA7B3BBC7C2761600003A7FB3D5D5C8BEA6602E414C4666A0B9C5C4A87A400C00000000000000000000004E2C4679A3CDF8F9EFBE7537112F4566ABE8FFF5DAA264250A13144285C1E8DECAA36B3011000007315697D5F5F2D8945C250E09000E2E90E4F1CF854E1E212BABE8FFF5DAA2642501FEA55D0707185079611D00000000000A3E6A94A9B18D6D33000000002A7DC4D8D0C8984F0F0000054291CBDED2C6995B2000022A5A94CEE3E0D4BA812D042C73AABBC4B8B18827000009518FB4C0C9C6C5AB5512021B4D92C0CBC6B27F1C0000003B8EB9C1C4BDB2AA6619000000266DC4DEECE2CCC397450000002F79B2C0C7C7BC762400133B80B6CFCEC5C7AC6A34453F3E6DA5CEC0BFA2753202000000000000000000000044384D79A4D6F5FEF1BA7B36192C3C5EB1E8F9FBDA9B56240D00114EA1C3DFE3CCAE783107060507254C92DEFCF5D59D6122030204162C97EBF9CB7743242829B1E8F9FBDA9B562401FEA65D070718607857180000000000074A7699AEAA8D5B1E000000002176BAD9E0CE9E4C1300061D539FC6D1D0C394491206093563A6C8D1D3D3B5732B0F2B75AFC5C1BEAE832600001F5282B8C4C9CBD0AC4C0A001D4792BBC4C7A96E1C000002468EBFC7BBB9B6AC5D130000002870B7E1EDE2DABE90350000033B7AA7BFBFC7B8650F00094D8DBECBD9D9CDA35E2D323C3D70A2BDC2BAA57E37070000000000000000000000483D4376A9D9F3F6E7BE773B18132C83C0E9F6F2D2954E1F0B101F5A95BFE4E0CDA165270E04000127569EDFF7ECC9915221110A0E18338DDEECC97938282528C0E9F6F2D2954E1F01FEA75D0707187075501804000000001351849DAAA1885519000000002A74B8DBE6CA9C4C150009276297C4DECEC7874E130513325596C1D5D9D0B578220D3677B3C2C8BEAE83210000185B8BBABCBDC7B791410B062F599EC4CFBEA76107000001449FCED7C3BBBDAA58130000042E77BBDBE4D1BCAC762F0000003377A9B7C0CBB7661C061B5B92C3D6D7CCC3995032423F4471A7BFC5B5A17932000000000000000000000000503D4B719ED2F5FEEFBB72371829407AC0ECF9EAC992431C100C205198CCDDE2C28F5E35190903073763A0DFFCDFC29649220D0115184AA3E3F1BA7437202E32C0ECF9EAC992431C01FEA85D07071880755B1A02060000001E5E7F98A9A7804F1C000000002069B1D7DBD39E541C0008265DA0C4E2D3C58E4E1B00113A7093C3CBDACFB5641200286BAFCBC6C4B4731D000027669CBFC8CACCCA8E39070029609DC2CABEA45E0700000A51A3D8CFC5B7B5A360130000003277C5D5E7DBC9AC742B0000084682ADC7D5CAAB63100019619EC3C7D2CBBD8B452D3D38386EACC1C3C19F80420C00000000000000000000004D343D659BCFF5EDD6AD6B3417113B75B7EBF3ECBE86431005011C5BA2E1EDE0C3905631170105113763A3E3F4E6C7884B1C0D02050E32A1ECF5BB75311B242BB7EBF3ECBE86431001FEA95D0707189066420C00020000001D5B74929C99743F0800000000216CAFDEE4CF9D571400092F6DB2D6D6D5C492490C0013326695C6DBD5BFAD601A07287DA6B6BFAF9C6B1E00032F6591B8BCC7C6B5923E030C356FADC2C6C4A0500000001459AECACAB9B7AAA15506000006368ACAE1E7E4BFA1731800000C4891B8BBBBC3B3711706256AA2C4D5D3CBB487462231374270AAAFC1BAA6833E0200000000000000000000004743496D9BD0EBE9D5A3642B19292B6AB4E0F4E6B677250904122B62A8D9DADEB87C4C231C130E04385BABDBF0DFAF773F1706090D093CB3ECF2BC6B31202B2DB4E0F4E6B677250901FEAA5D070718A06946020004010000275C889BA29A754305000000022774A6D2E7D1AA5D0F0014357CB0CDD1D5C78A3F170916456A8EB8CDCBC6AA5F1A052B7BB1BFBEB89C6C130004366C92C3CCC9CBBA903600083779ABC6CAC499490000001159A5C2C0B1B2AF9C4C050000014094CDE6E7D0C08E581100000B4B8CA9C4CAC9B05F13042675ACC9CCD7C7B49447222D353E6AA3B5BFBCAB93370300000000000107000000004B44496A95CDEBEECF995E250F193871BEE1F8DDBB752B0D08072C69B2D3E5DEC1824F2810090C093466A6E7F3DCAE71340A070B0A2543B0E5E1AB633721252BBEE1F8DDBB752B0D01FEAB5D070718B0784918111F06000030709B9BA99E753306000000013066AAD7DDE0AD5C0F0015447CB3D6D6D2C58C43120A204F749ABAD3D0BA9C541506327AA5BABDB1A3600E0010476A97B8C1C0C7B88D31071C487FB1CCD0BA923E000000206BA9CDC2AAB4AB954C0C00000D3F90C6D8DDD7C69452000000124B97B3C1CAC7A5530C093276A3B9CDDAD5C28F3E1E2A303B729FB6CAC6BB9540000000000000000300000000514B4C6993C4E6E2D09A541D0A1C3B70B6DCEFE7B8691F0A0E062969A7C6DCD9B383472B2415120B3E74B4F1FFE4A763311B0A0610264DAEDEE4A1512C20292DB6DCEFE7B8691F0A01FEAC5D070718C0724E1319280A0000367294979793672A00000000002A67A5D8D7D2B55919001F4C84BCD9D6CFBD87431A0E314A7596C0CCBDBD9B4613003A79B2BDB9AB99630B001555819DB4C0BCC0B87E2300154A8AB5CACFC18E440000002369B8CDCAAAA9A5904A0C0000104697CED9DEDBBE7C43000000145792B7B9C8C9AB530A03387FA2BDD1DBC9B5853B222B263977A7B9C0C2B490400200000000000000000000004E49455D7EBDDADDC98C4B180A192679C5E5F2E4AE68260907041D6DAED1DFDBB67D3621131205144168A5E2EBDAC6672B150C150C1F4AACEADAA25A3023302EC5E5F2E4AE68260901FEAD5D070718D06F3E0A0E210B000037768C8E9A9F6430040000000024629DD3DDD7B35B170D1D5499BCD5DED4C283361B132C537292B7CAC3BA8D3700003088B5BDBAB3985E080014587CA0B5CBC3C2B07722052E6691BCCCCDBC822E0000002D75B3C1CDB3A5A79A42090000114C8BC6D5DBCEBB8038000000275D97A9B7BFC2A54F1411408EB9CBD2C9CBC0862D1822223876A5C3C0BEB3853C0200000000030004010000005346445F8EBFDED7BC9E4B130C21346BB6E5F4E8B4641C0000042271B6D8E7DDAC7E461D1B0C02023E71BBE2EECC9C5E330F07030D1F51B6E7D29F5332263333B6E5F4E8B4641C0001FEAE5D070718E07046192638190006417D9099A09972270000000003255CA6D8DCE0B7621A0E2B6199BACCD2C7B4823D161034647A96B9C2C3B9883B0500347FB0BAB8B39652070021608DA0BBCAC8C6AA64150B266189BCC1C7B37A3A0000003E87B2C9CDB1A7A68833090000125D9BCFCCCDD7B77E370000001E599EB7C2CAC6A1450B004490BBDAD4D1CCBA7C2A13151E3F77AAB8CDC6A99741050000000000000C020000005D595D678CCAE7E4CB8C4A20202D4163BDE3F0D9AA60160000093178B5DDE4D8B4723A1C20150C0E4369BEE7E4CE9F5A210F100D15254FABD8CE9C532C27303EBDE3F0D9AA60160001FEAF5D070718F07648182F3D2009124E899D9D93916223000000000B296A9CD9E2DDB761200C3374A1C0D5DEC8B2754417183968859EB8C2BFB27F2B0000358DB4B8B5B68C4604002C6D96AAB8B4B8C2AC6117002B6A9EC1D3C9B0752A000000408BBACFC1AAAFA9842B070000165DA5CEDAD8C7B4762700000027689DB2BDC1C9984107093E88B6CDDAC7B6B37A24111C274677B6C3CDBCB3943E0900000000030600000000004D3B42557BB4D5D8B57D2C0D202F357DBAE9EED5A757170000002677BFDFE4D6A4794623210F030D4372B7DEE5C79F52280B0513141855B2CCC58F572F20353FBAE9EED5A757170001FEB05D070718006C44244050220218558EA296A0936626000000000832659ED6EEEEBD59180F30779FBDC9D5D5BC7F4C1D214D70839EB5BCC0A86B1B00053A87B4BAB6AD953E00002D73A1ABB7B9B6C7A04E0B083580AFBDBCC5B27C260000004E92B5C3B3A6AAA07E320D000B205FA0C6D4CDC5B17123000000346F9DAABACACF943A080B478FB8C2CFC5BBB274280C131A3881AEBFCBC7B390430C0000000300080C0A0000005E494E6091C5E3DDBB84381618324683C9E8EED7A657150000103E85C1DCE5DEAE7F38231E0A040D527ACAE9E3B78447220B101E10235DB1CBBD7F4830322F31C9E8EED7A657150001FEB15D07071810724425515B2F0E246296AFA8A18E541200000000143365A5DBE8E3B6621F103C82B0BFD2D9C0B676472727597B828CABBEB5A767150000388EBDB6C3C2934E0801347FA4ABBEB8B9B4964A04033A7EB0C2BCC5B27A280000004F99BBCAB8A8ABA57D3B0A00001E5FA3C7D4D3C2A866180000002B679BAEC4C2BD8C3B01084999BDCFCDC9C7AD6A21040C18418CB2BBBFC7B38C43110000000003080900000000524531487CC0DFDFC0853B131F384E91D0E2E0CA9E4608000007377BBFD8EBD2A7713B1D261202174D7BBEEAE9BB842D21101217232B5FBCD0AF83512B282D38D0E2E0CA9E46080001FEB25D070718206E40345C672E122C73A4AB8E9787572000000000133B669EDCEBE8BB6520113C94B0B9C8D1CFB582502E2D56868994AEB4B4A0611B0000398DB7B4B8B18E3A00023B8CADACB9B9C0B791350002458FB2BEC8C7B378260000126A9FC6C1B9ACA2956E2B060505286AA3BCCBC6C3AA58180000003A7AA9B2C3C3B98225000F4E9DC2CEC9C3B7AB6E21060E1E4386B2C2C3BAB18236050000000908110B020000005938474B87B8E2DFB56F2C071034468DC7DEE1CE9E470A0000093A8ECBE8EAD0A66E2F18140609155B88C4EEE1B5763411050E1221346FC3CC996A45223F4646C7DEE1CE9E470A0001FEB35D070718307F553C636B43223D75ABB29E97855019000000071F3E73A7E4F6EDC25F201859A2B3B4C3D0CBAD765335496D8E8D9DAABAB29E55000005468DB6B5ACB5883B0003439DB0A1BFBEBCBA8930000A448EACC6CEC4B16D1F000016729BB5C2B7B1B199691D020202216AACC4CDCDBEA55908000009417AA3ADBBC8B36E2C080E559DBCD1CFC8C0B866180609194A86BBC7D1C6B4813805000001000808040000000054443E5C8ACCEEE0BC743010263B5796C9E0E6CD913C0100000B3F8EC5E1E7D09F662F1D150F07155B84C6E5DDB4783C151510151F3072BDCCA2613E342A3A3BC9E0E6CD913C010001FEB45D070718407546446C6F3C2F4C70A7BBA8917D491900000006193E6DABDDEFEBC364212761A2BCABC0D2C9B0744D32396F999A98A0B3B3994906000043A2B3B1ADB0852A0000458EAFAFB8C1B6AB8934090D3F9ABCBCC8C7AD6F2600001270AAC5C3BDA9AC95662413050C2B75A6BDCECDB49F4D0700000B4A87AAB4B9C0B07022000C54A2C2CECDC8D0B26111040913488EB2BDCABFA683350A04000306111110000000004F4243527AB9D3C9B786321820385D94D3E3E5CD8535060000043D8ECBDAE5CD9B68340D0B12141E6477C6E7D6AB743718161D1C273D7CC3C58355362A2E3F40D3E3E5CD8535060001FEB55D07071850724940777547314F7EAAB3A0877D440F00000006204F7DC1EBF6E3BC61262567B1C7B2BFD1C5A6714E39447B988C92A6B0B99E3F00000C539CB6B4B1B18A2900025797B0B4C5BAB7AC7624000C54A1C6CBC8C8AA6A1B00001B75B0C3BEBEA7AD9760200B110D2876A3B0B9BBB39946060000144C85A9B1BBBDB4681D000F52A2B9CCC8CBC5B15C0C00091E578DC1C2CEBBA47B380300020109060008020000006444405590CDE5DEB6722D10264064A1C9E4E0BE8330000000094389C5E6E4D3A7692D14120D0E217A83C9E7CE9C5C2B100D1625264382C3BF8C5331302C393EC9E4E0BE8330000001FEB65D070718607A4B4E7A7A4F48588EAFB5A0927143130000061C334B8CBEEBFFEDB061273269B5C6BBC2CEC1A46F553A4A889E9299A8B5A88731000009589EB7B7B9B6832A00004998B6BBC5BBC3AE741B00125BA3B4C0C5BDB0772100001E81B5C1BBB3AFA4955D2114121233779CC3B6B8B69040020000185B91ACACB7BBA96519001854A8C4C7CFC4C7AA5309000328579BC7BEC3AF9C7A2D0500000313110B0302000000593D466091C2DDCBAD692E0A1B3A619BD9E5DEC28126010000114D95CAE9E2D4A16A25130F070820718DD2E0D08E632D10131D21283B7FC2B27C4D3E2F33434AD9E5DEC28126010001FEB75D07071870784F4E7B7E5748628DADB9A6846B3C1903000D2A3D5B8ABFEFF6E9C06B302B6DBEBDA9BAD5C2936B5038508AA5908C9FACAA872B00001158A3B9BDB4B8842600005698B4C0C2BEB1A76B1600176CA7B9C6C8BDA8721F00002F87C4C6C4B3A9AF985B21180E093179A6B3C4BFB08031000000226696B2B1B8B9A9510E001861A4C9C6C3C6C7AC4C110006245EA2C5C1C8B69F752E09000710100E1109060004005C555C6191CBEBD7A6612E142641649DD3EEEBBF7E29000000094091D7E5EACF97643612100E122D827ACEDBD2985626120918182C4D90C2AD7D47362C323E4BD3EEEBBF7E29000001FEB85D07071880734F50817D5A496B99B2C1A47C612E1904060B1937619CD1EBF5F8B968262A73BFBDB5C8CEC4926D56435D929F9A99ACB5B07F2D00000D5CA0B9B6B1B380250000559DBDBABDB7B99F5D0D000F6AB1B5C2C6C1A86E1A0000318BB8C4C1B7A19E914E1E1817173384A4B4BFB6A986330000002571A8B1B1AEC5A45F16021858A5C4C4CAC8BD9F4E0B000D2A6AA5C4C4BFAD9F74210700000C1A130D0E0100000062575570A3D5E0D6B36E341618365FA6D5E3E2B97E260000000C4898D4ECE9C6956023110C1615348F7DCDE1BD8D4D201B151B20335692C3A56C42322D303E44D5E3E2B97E26000001FEB95D07071890714658847E61597A98ACB6997A5D30100B081D2E5178A7D4EFEEE1B45E272C73BBCBC1CCCFB2866156375B96B2A69DA8B7A8811F00000A5CAAC6C1C1B47D28000B5FA9BBB5BBBCB4A6510B001466B4C4C7CBC0B1691100002992BBC2B8ACAFAA915424221A15377BA7B5BAB6A97B2A000000296C9DB2B7B5B29B4D0D001D59A5C3CABFCBC3A94802000E3571AED3D3C6A69274240000000A10130C0902000000655F667EAAD3E6E0B37330121B3672A6D3E8E3B97230060003103D96D3EBE8C7956026140A0915328889D4DFB9844B2610191E2932589EBC9F6944313B414940D3E8E3B97230060001FEBA5D070718A0685D5F7D7A5F667DA1B0BF926A46260C03111D31517BB3E1FFF1E5AB5A28337CC4CDC5CED2B388634D3B5F97A9A89A9AADAE801D0000136AA7BCBAB9AD6C1B000761ABC1C3B9BBB7A14E0A001A6AABC2C0C8BEA45E1200003BA0C1CABEBDABA6924F2934211A347AA5B3BCB1AF822E0000002976ABAEACB1B190410700105A9AC0D1C9BEB39A530F00042F7AB6CDD1C5B193692601000B0D1418140603000000706B747BADD0EBD9B06D2D13233B70ACE1E9E0BC761E000000144B95CBE1E2C89A672B150B0E1F479982CADFC1795228131717212A5FA1B1935D3D3337374147E1E9E0BC761E000001FEBB5D070718B074565679725E6393AFA9AD93654726160D1A293A5982B2ECFEEDD9A55121367FC0D9CDD4D1A97244423B6FA0BCA3A4AFB7A5771C00001E71B2C5BDC0B87A25000466A7B9B5BEBDB297400000166BB7C6CEC2BB9D5C0C0000379DC0C4BCB2ACA99151313327193993B1B4BFB9AD7911000000347BADB4A8B0B38F480500185EACC6CAC0BABA964C07000E487EB1CACFC8B69B631F00000B2520180700000000006B70899ABEE2F5D9B76D271A263F6AB2DCF0E3BE7120050000134499D7ECEDCE9D602C15050C1848A17ECFE0B773452320161E23355FB8C9A55B392E2C2F3E4DDCF0E3BE7120050001FEBC5D070718C07D60617F7D6E78A3A7A3A88B6A502A1C0B152B445F95C4EBF2F6EAA5512E408CCDD9D5E1C7A56B504D4976A4BBA8A1A5A69C650F00002774ACC1C3B8AC6D1B000F71A6C6C3C5BDBF9A4100001F72A7BCBFC4C0A76B110000389DC6C2BDB2ACB2964F243B31163A7CA4BEBDBFA76D170000003680AEB2ABB0A88F3600001063ACC9CCC3C4BB9B4000001B4A8DBBC3C9C0B29E641B0000061A1E231311060000006C6C7D96C2DFF5D9AD622C11213A76B6E6FAEBBB6B240000000F50A6DFFAEFBF8D66290F090E1C4EA473CEDAB4683A241F1726293B67ADAD7D4A352C2B394F51E6FAEBBB6B24000001FEBD5D070718D0795C597E7A787CA3A9A3A08263412B150C1829416198DDF2F5F0E0A35623378ECFE4E1E6D79A64433A3A689DBFB2A3A8ADA15C0D00003181B0C1C1BEA8691B001470A8BFBACCC0BE963000001B6BA7B5B4C0B293600E0000479CC0C1B8B0B1B29C58394734234485B2BCB9BAA967180000003D8CB2A7A8ABAD8A2E06001661ABC5C3C9C5C09F410200175191B9C7CDC7A896621701000D1B2C221703000000006D7285A6D0E5F0D7A46D2C182C4D77BBEBEDE0B7712D0002060F47A2D9F4E5C2915E291D131D1C59AE70D2E1B36342322C211E232F5CA9B67B4332312D3A4152EBEDE0B7712D000201FEBE5D070718E06A515769646484A4AA9A9D774F352B1510273F4B679FD7F8F7E3D59D4F2F478DC9E4E4DBD28F5F413D386FB3BEB7B4A6AB935709000C3A80B8B7BBC0AD6810001070B1C5C4BFC2BC893000001C68A4B5C2C0B09F590D00004298C7CBB9B7BBAA9B59394C3924418CB8BDBBB3A165170000003A87A8B49FACB185330000105F9ABFC1C1C0C08F3D0100295B9CBEC7C7BCA9965B190000081C2B231B0E000000006D778CA7CDF1F5DBAC5E382A2A446EB6E9F1DEB871270000000751B2E7F3E0BF8F582E0D0B162F69B670CDD6A76741412919182D417BAEAC734D39403743454EE9F1DEB87127000001FEBF5D070718F079555A6F6F8195B4B0A0907A51371C17152D3F4D75AAD5F3F8E3C9974E31448ECBDAE2DED38E544542396EA3BCB8ABACB09F580400043F8EB7BCC3C2A65710000F6BB6BFC0C6BFBA9137000024689EB0B8C6BBA36614000241A2C5BCB4ADAAAA95524363421E3F89A8B3B4B8A1640E000002458EB2B0A0AAAA76260000185AA5C4C3BEC4B49332000016539CB7C7CFC0B8914D1F0303102B37281C0A02000000748291BBE5FDF9EAB75C2622344975BFF2FEEAB26C2F16150C1E56B3E1EBE8C08955340D0B072F79BD6DC4CBA8624344431D1C343D7CB0A86E3E33413E324556F2FEEAB26C2F161501FEC05D070718007E625B6D7487A7C4AE9D906F4F36211E1E2B446B89C1EFFFFFE7C9864C2D4A9AD3E8F0E4C878493A3D487EBCCABDA9A6B69D560900044491B8C6C2BAA4570B001974A4BCB9C4BDB88F2B0000136D9999B5C3BB9D5E10000349A2C8C8B6B2B2A8995F48694A2D5591B9BCB8B19C680F0000004D8FB3ACA5A9A26F1E00021D6493B9C4BABDBA842C0002266AA7C4CBCDC6AE8D500F00000F353C31150F010000007B8D9FC7F2FFFDE5BF723D2A364A84C6EFF0DFAF6F280B16121851A9E3F0DEBC875C2B140E1A448CC66EC8D3A26946463D211E264078AFA3681A263F463D4049EFF0DFAF6F280B1601FEC15D070718106F5A586A6E80B3D3C1958D6C442915141E40546D86BAEBFFF3D7BD7B42304692CFEDF0EFD07F463A2E4881B5BFBEAFABAC974700000648A0C6CACDC59D4804000A67A5C3BEC0C5B6852B00001D6698A3BBC2B5A3601800004DA5C0D1B0AEB6AF92554772462F4E95B4BBB3C0B57409000004528EACA2A1AFAB6F1700001967A2BBC3B2BEBA7A29080A306CB1C5D5C5BAB28E4C080000182D3C38180F000000008997B0D4E5F6FDEBBA65382A335296D9F2FCE2AD681F0B0F0E1C57ADD9EFD8C18A4C31180E18428BD071CBCB9A634D573C222739459BC3A85A322A34413C4346F2FCE2AD681F0B0F01FEC25D07071820705C54646783B9CCC08D725E34271D1E253D4E6989C2F5FFF4D2B677382A5596CFEAEFEFC5763D3B323E8ABECBCAB0B5B78B4300000E56AFC7C8C1BF984600001661B1C4C6C4C7C17E1C0000225F8BA4B3C1B5A65912000056A5CCCBB4B3C0AF9F5C466D41254C8FB5BFBCB7A86D0C000009599EAEB5A2AC9B6617000016548DAAC2B7B7B3771B0006357AB4CBD6D2CABA90430C00050D333A351E0A040000007B80A8ECFFFFFEE0A9592C2B355289D3F7F1DFAC6823181109185DB4EBFCE0C5865D2E1003204999C765C5C79C5A4D5A4028172C4A95BDA963372A4053414548F7F1DFAC6823181101FEC35D07071830776A6C686F9AD3E9D0886450392D1F242C4063789ADAFFFFF3CBA56B3C31589FDBEBF5EFC77440382C3F8CB7CCCCBBAEAE84400000185DAACAC0C2C1A8370000116EBCD0C9CAC6BF821A00001B688DA1B0B9BBA1581000004CA9C2C7B8AFB1B18E55547D4F345196B9B6B3BEA56C0C00000A5A99B9B39DA49B5B18000016558BADBDC1C9B5772100023C7CB9D1D5CECBB489460300011A374238240900000000849DBDE7FFFFFEE4AB5F2D293E5CA1D8F5FBE7B66023212815215DB6E3F5D9BC81562A190E1248A0DC63C2C89F5B61676F3C22204494BA9A5A2E29484A403B43F5FBE7B66023212801FEC45D0707184077636367729ACBE8C58E60422B201E202E457290A0DBFEFCEEC19960302C57A6E2F9F8F2C6653831344487BFC8B4AAA6B68C3600000F65B0C3CBC8BB963B00000966AFC1BEC5C6BD832500001D608A9FABC3BBA3580A000253ACCACEBCAEAFAD925B628349274D92B4BCBFBCA7640E00000F6AA6B2ACA09E9558130000184B8FA7BFC1BDB076240012468ECCCFD5DCCBAD853B07000515375548230B000000007B9BBDEBFFFFFFDFAD5C312F2D5296E1FDF4E0A56B23102A161860BFEBF3DBB57E562A13091852A3D557CAD4906C61705D31203258A3BE9851282D4549413D42FDF4E0A56B23102A01FEC55D07071850776262656F94CEE6D28861432F1C1C242A4571849FD8FDFFE8BE915D2E2B63A5DDF1F0E7C2603F443A3B80BBD0CDAFA9A8822E0000256DB5CBCBC5C1902B00001168AFC8B8C7CDBA76120000185F83A2C5C9B7A75904000A5DACD2D3BDB2B4AF926156724B2F5DA2BEB8B9B2A65C060000136CA7B9B7A69B985B0C0000194B8BA1AEBEBEB46C1C00094788C1D9D2D0B8B082360700001F4A60462A0A00000000809CC6F6FFFFFFE4AA5F3B2E395BA3EDFFF9E0A85D2E1D221A1A60BBF4F2D9AC77492B180E1B53ABE164C1C79A65677B592B21255EB6CCA24F271E3C4C403A3FFFF9E0A85D2E1D2201FEC65D070718607A62535B699ED1EBC78A6E3F291518233B5D7A9DB6E9FFFFD9B17A3F232D60ADDDF0E6EAC06B3B3E3C4887C5D4C0A9A8A4701F00002578C1C8C9C5BA863400000A67B1C7BACBC4BC681400001F4E89A3BBCBC39E5910000258B9DAD7CBB1B6B18C5B647B4B315F9BB7B3ABA5A55F040000267DADB1B59FA2944E0900051F437CA1B8BEBCA5631C00124D93C8D6D1D4C2A97F350303002250674D200E020000007E99CCF9FFFFFFE3A4593D354973B6EAFFFFE3A6522823240F2775C4F4F6D8AC773E201E122B63B4E85FC3C79A5E69876733223172B4CB94482525474D3C3B4AFFFFE3A65228232401FEC75D070718707867686575ACE6F3CB8E5F3E1F201B2D365C83A8C4F3FFFFDDA379472A3368B4D8EAF1ECC46E413A2E3D91C7C2B9AA9C96661E00002F8AC3CEBBC8BC83270000196CBDCBBEC2C5B57415000018558EA2C5D1B6A25108000D5BBED8D1C5C0BCAB894D6076463B6492B2AFB6B6A35C0600002978A9BAA8AAA28D4A00000C1C416E8EB1C0C1AF560C0017589BC9CBD3CFCAA67A3904000D2A5C6F502409000000007993BBF6FFFFFEDB9D5630354065A3F2FFFFDB995B281F28233A88CFF4F2D9A773471F0B072461B7E15BBFB97C566E8A743C1A336BC1D19248201C4C4F3A3948FFFFDB995B281F2801FEC85D070718807D6A5C5C75AEEDEFD48A553824221F26396389AAC4E8FDEDD1905E302B3C7BC1DAEBECE8BB5838342E408CC3CBBCB0A3AC631900002880CCC8C3C1BA832800002478B8CFC3CAC4B86D1400002660899EC7CAB89F4E00000359B9D0C7CAC5C1B28A5C6A7C493D729EB8AAA4A7905B0A00002E7BA5BDB2B4A68A420B00041B2F598CA6C0C7A357140A2353A2D4D9CDCBBDA269290200073061785C361007000000849ECFFFFFFFFFDF9C5933344F81BEF1FFFFD79A511D11201B4083E0FFF5D3A06F46201A162166C6EA5FC0C18959718D763B1B357FC6D69C4E1B184444334248FFFFD79A511D112001FEC95D07071890756C5F576CB1EFFED48C542D22191426426794B8D1F8FFFAC1845122263770C1E6F3EDE3BB643F352D4B96C2CFBDB6B6A5681000003496CACDB8C9AE70180000197FACC7BCCDC8B861120000225888A7C5C6BFA3500400084DB1D2D9CDC5C4B0865264754C40759DB2A6A4AB9D58050000357CA7C4B8AA9D883E0300020A2A4F73A4BAC6AC5A15092F699FCCDCD8D8C59F642800000F2B5D7A573216000000007C96D4F8FFFFFFDFA7573A39548ED0FBFFFFD694491C0C1717398DDEFCEDCDA66936150D172676C2EE61BBB5905878987D40253B7ECBCE8F3C101F394E373148FFFFD694491C0C1701FECA5D070718A07069656F79B0E3FFD389563418181D243F77AACCDFFFFFF9C88A46201D3470CAE3F2F7E2BC633333324A99D1BDBFBCAEA2530F00003990BFC2B9BEAE691D00002279B0C6BEC8CCAF59090002275F83ACC3CEBA914703000B5FC0E6E2DDCCCBB48C57656E384171A5A9AEA5AF9251000004427FA8BFB7B39D823603001018283F709AC4C09C510C01226FACCED8CFCAC5A55D1F000011406E7D582D19040000007E94C6FCFFFFF8CF8A5A42395380C6F4FFFFD18E451D0C18193B90DEFEEBCFA25F30120A1F286ECBF166B7B783517292834D295397CCCA8E35121D3A3D393A4FFFFFD18E451D0C1801FECB5D070718B07D6C605C77C0FEFFD08C5A2B1C111D294C81A9D1E9F6FFF7C57B381B162C79CFDCEEECEABC65322D244C9CC5C2B4A6AF934A0D000D50A7DACFC0C99E530C00002E83C4D3CDC3BBA75B0C0000275E97ADBACFB5934A0600005CB5D0D7CAC3C2B4945968784A537D9FACA3A4AB974A0100074689B3BDB0A9AB7F310000050C21396394B2BB9F430D10377BB3D3DAD5D3C19D5918000210356879582E1710000000827FC7FFFFFFF9BF884F39485D8ECFF9FFF1D183432C1C0E1B409FE7FFF6C78A5C2C1714173085C7F153C0B2805A798C8646294890D3C98436150E3C4628354EFFF1D183432C1C0E01FECC5D070718C06B66625F6FB9EFF6D4894C270B181B304D85B8D0E2F6FBECC4793316133374C6DBECF3E8B7603938274F93C4B3B2B2A6854B0B000250A3C6C7C3C69C500B00002E8BC1D4BFD2BF99580B0011396C9CB0C0CFC49A3800000556B8E1E6DAC7C1AE87525F653C5080A4B3ADA59F8E4803000D5293B7BFB4B19B74260000090A13275399B8CA98461920488EBFDCD3DDD4C694480B00011C4077795F391D05000000768FCBFFFFFFFFC6864D35435C94DBFFFFF9D1824018160F1F49A8E9FFF5DB9955302121223583D0ED5FBAAC7F5A7C8F743E33599FD7C985310F0F2F4035334EFFF9D1824018160F01FECD5D070718D0716A616077B7EFF1D58953291A14192E5189C8E2EEFDFFEEB86F2F0F0E2975C4E2EFEAE4B462382C2E529FCFBEB9B8A2793C05000B5CB1D7C5BAB4913C0500003681C0D4CCD3C49C4B0400144675A7C2C8D4C2953B0000095AB7DBDAD7C4C4AF814F6168445984A7B1B09CA39041000018599CB2B4B7A79E742000000E1012285296C2C88F3C0B0D4593C1E0E1D8CCBB8E490C00001B4A7183643919080000007990CFFFFFFFF1BE8A453A31629DD7FFFFF9CE763913181C214FA9E9FFE8C78655341E11132F93DAEE61B3A873517BA0873E2A5C9DDCCA7C2411163840323653FFF9CE763913181C01FECE5D070718E06F69656078B8F0F8D88551301D1A1D2A5393CFE7EFF7FAE2AB692A0F1A2A70BBDBECF1E0B75928272556A3CBB5ADBCA27E3D0700145FB3DEC5BEBC9547080000448FC2D0CFD5CF9A400200084278A0B3C7C7BB8C3600000C5EABCEDADCCDC1AE80515E61495E8CA7B2A09CA6823C000029639BB6BFB7A8986A15000311030718457FBCBE8F461B1E479BD4DBD5D7D3C5933E080000224C7E815A3222000000006778B1ECFFFFE8AF7339393A6198D1FFFFF1C36C3211130C1D52ABEBFFEBC388532A1E121F388FD9EC5FAB9D734F749575453964AEE8CA723114132929283660FFF1C36C3211130C01FECF5D070718F0716B635E7DBEF4EEC4885B2C1B121934539BDFEDFCF8FBEEAA562203112971BCDBEEF1DDAB5C31292F61A8D3B8AFBC99622604001664ABD6CBC0BD8F480400053991BED6D3DEC9863500000D4672AAC3CBC5BE933300000856B3D7DAD7CFCBB57641525A406998A5A69EA0A4843900002172ACBCBFB2AF9B6117000013090C174286B3B67B340F2161A1CCE6DFD3D7CB8E450C000036607D805E3B250E0000008095CDFFFFFFF1B98249353C66AAEDFFFFF3C27A39180F1B265EB4F2FFE9C48E44221A181C47A8E1E855A9A36C486D8E7542367ABDECC77D2E0810313D34345DFFF3C27A39180F1B01FED05D070718006E75615C7CC0F1E3C58C542C1813203B57A5DAF0FFEEF2E09F5A1F0B112C6FBDDBF3EFE0B45E2B1B2A4BA5CAB9B1B797692400002273B9D8C7CBC287370100124099CFE3D0D6C07E3301001F5381AFC3C6D2C0782500001E6EBBDEDDD3C8BDB06E43505148709FA1ACADA2A5813800002D76B0BEBAB2AC9D540D0000180C01103E72B3C3802B102D60AED3DDE3DDDACF913E0200002D667E7E552E1A010000008894C9FFFFFFF1B97B4D484879B4E9FFFFE7B671311A141C2169C0FDFFE9C08745221E201E469CDDF463AF986C416F917842407FBEE8C476310F0929354A3B67FFE7B671311A141C01FED15D07071810706D646180BBF4E8BE824E2D1A1A24346CB2EAFBF0EFF4E3994613030E2E6BBAD4EEF2DCB4592420275BAECFA8A5B788562000002072C8E4B5B6B7823706000D519ECADBDEE1CA86270304275A8BB2C0CFCAC3822B00001B65B3D8E0CEC5B6A2613B4A50466394B3BAA7A39F833900054186AAB8AFB4AB995A0C0008180900113673B4B57835192D67B9D6ECE9DDD3C6903F03000031557574533B21080000007480B4F6FFFFDDA769352E3C6CAFF3FFFFEBB25A29170C1D3768BDF1FDEFBA782A1F151A2658A9E2F165AF9A633F688770434C8ACAE9C06F2C020C272D2C326AFFEBB25A29170C1D01FED25D070718207D705F6B7FBBF4E0B48853281C20243F6DB9F2FFFFEAEED8924C1308132E66BEF3FCECE3AB4B2A18245FB3C9A5B0B47C441400002781D8EAC8BAC08927000421519DD3E1D7D0C1792A00012A6A90BCC6C5B9B6862700001C62B4D5DFCEBEB4A6592E44544F75A1ACB2A49D997934000B4A8AB2C1C3BAAC9257040002210E02082C6FB4AB692613346FB1D0E9DBDBDBC7913B01000A38707D704A3022090000007A82BDF8FFFFE3AE6B3A363E81BCF8FFFFE7AB53200F0E132374C7F8FCF1B679432E1D19214EA9EBF46B9F8F5733668D743B508FC8F0D06F250B0A26342C3364FFE7AB53200F0E1301FED35D070718307378686E7EBEF6E6BE84572C22202A3E6DBAF8FFFFF7F2D68D45150114306BBEE1F8F0E9A44C1D142061AFC7A5ADB47C411400093688D5E0B6B2AE7E2A0B011E54A5CBD9DEDDC16E29000C306092BDC9CDC5BA7C2C00001F6BB6DBDFD9CEBC9651293C435180A5BAB2A19FA26F1A000C5099B6BABAC0B0844600000D1D0D0009366BA4A05A23153584C0E2E9D7D2C9D19F3704000644767F6E503520090000008090CAFFFFFFE0A36F3E41547BC1F1FFFFE9B75E2D1914172B75C7F4FDE7B2753A27201C1A58B2EAEB5BA2825432568C66475999DFF3D17A24090A2031233275FFE9B75E2D19141701FED45D0707184072716E707EBEE0D8A781502E1715193C72CAFFFFF6E3F2DA8842180611336CB7F1F8EDE3A94318172761BFD39FB2AD6E2F0A00023E90DBEFC7BFB86F2000072056B0D1DFE5DAB9721F0004336494B6C3D0D0B6772600002662B3D6DCD1D7C39B481C2F41487CAEB1B6ABA199712900074E97B6C1BEBAAA8E4400000D1F1403022D6BA49B5A1F183884D0E4E8DED9D9CC973E0000143E7B80673D231E0F0000007C7CC3FFFFFFDFAC65474C6380C8F5FFFFE0A7582219161B2E77CFFBFFE7A8663323181D2661AFE0EA54A08B5333638A724864A1D8ECC677251509252727406DFFE0A7582219161B01FED55D07071850706E65667CB6D5CE9A724B2D1C1F32447CD2FFFFFFEEE9CE85420C010F2C66A9DAEFEBE7B5571F132860AECBADA49E6C2E0E001242A3D7E8C4BDB5732502061C62B3DBE2E0DDB26C1E03063D66A3CCC6C6C6BB80290000286EB0CFD3CFD2C19641192D384886A9BFAFA69F9C672200175DA0B8BCC4BFA67D370000212F0B000022609A95572421488ACBDDE0DAD6CACD9B3600001250838A70493321090000007675BBFBFFFFDE93433632518DD4FEFFFFE4A9512818261D2877CBF8FFD9AB6E3215191B2867B6E6E65997814B3F6C896C4069A6E3FFCA73270B081E282B3A74FFE4A9512818261D01FED65D07071860767665707EB6C8B59A6340211E1C365086DAFFFFFFE6ECD4803C130010356AB9ECFAF4E7AB54190D2164BDCEACAC9D6924000004469DD8E6C2C1BA702600012763ACCEE2E0D9B565180011447EADC7D3D1C7C57F1B0000256AADD4D7CBCFB78E300B2B3B508BACC5BCA8999860180015709FB8C6CDC0AD7A420000102C1600001C679F894B20204A8FDBF2EBE1D3CFC99B3C030019578B7A50403529110000007183C0FFFFFFDD98643F455593D8FFFFFFD7A24F331304133981D5FAFCDDAF66261F0E0F2C79C2F1ED589E71482D567A6F4F74B5E0FFCC7229090D1E25274075FFD7A24F3313041301FED75D07071870756D59667BB7C7AD916D3D1F1B21294B85DAFFFFFBDEDCC8793A130F15346DC0EBF5EAE5AF4C1A122166CAD0AEA997551D01001149A5DFE7C0C0C56F17050A2C75C2DDE1DFCE9A5217001D4D7DA6C7CFCACDB66B1F00013C6EB1CECED3C4BE8D2B132742608EB2BDADA4B39A51110012609CBABDC2B4A0733200001B2F14000129589087552C274493D3E7EBE2DBD7CA943C040022538E88533C35240F0000006F82C0FCFFFED296614B486188D9FFFFFFD69943271D1419367ECEF7FAE2A668241B1D27327DC6F4E64C9571442D5C7863537FC4EEF7C975230D101F2A193772FFD69943271D141901FED85D070718807C745F6883BDCBA9805C3E302722325C89D6FFFFFFE6F2C57A2D140A163E6DBCE9F2F3E19A4617112968C3D5B3AFA4541100002253A7DFEDC6CDBF6E21000C2F73B9DEDCDED4AE541700184F88A7CECCCBC7B36E2400053073BCCDD1CBCABB8819061F3F5E90BEC8AFA59F8A430A0023729EBCC1BAB49A712300001E321403012657937A4D2B2D559CE4EFEEE4D7D7CE862D00001C6298875B3A30230E0000007581C3FFFFFBD8936244485F90D4FFFFFFDB9A56251C1D173283CDFFFFE3A364281216193288CAE9E2568868342C5976605581C0F4FFC671200F051E1E21397AFFDB9A56251C1D1701FED95D0707189070635D6A86B3B897774F372C1B273B5685E3FFFFFCEFF3D178310B0E234473B9E6F1EBDDA742130A2C6EBBDDB5B99A4E0C00001355BAEAE1BDC0B45F1A000E3671C2D5E2DBD49E4E0D05265F8AABC7CBC4C7AB711B00074088BED2CBD3C6B17914001835609BC3BBAB9EAB923F04002576B0B4C2BAB59060250000233215000225588D7F47262B56B0E3EAF2D7CDD6CE93360D03296092854F3838281C000000717EC3FFFFFFD99254484F678DD5FFFFFFDA924E2A15171A2B83D5FFFFE69A541D100F1B4196DFF5EC48896F3E2759685F5086CFFBF5C5681A0C031A22283C7CFFDA924E2A15171A01FEDA5D070718A078776D7B80AAB8A47D4E4437232E38568BDFFFFFFFE5F1CE71300D0C163F79BEF0F0ECE79C3717132F6EC3DBB4AB8A500C00001C5AB4E5E5CBD4B15A1401104383C2DDD4D4D29B4B10001E6690ABCCCDC6CFB26C1900054A95B9CBCFD1C5AD740A00114E6CA3BCC0BCB0A3762300002071B2BDCDC7AF8C51100000213D1E061026628B753A1B285DA5DDEFEEDDDBDCCC913107002465988C4B2E312D1D0300008392CBFFFFFFDF9358524D6E9DE8FFFFFFE5A1502E170D163089DDFDF2D79D52292018284DA0DEF4DB4E876C31294D64475798DAFFFECB691A09111B1D273372FFE5A1502E170D1601FEDB5D070718B0707068738ABEBC9C7B4E3929282D344C86D4FFFFFFF2EDC56F2C1109214074C4EBE7DCD39F4813133474CDD9CCBE974D0D0000185BC2EDE4C4CBB55C1500133E80C5D2CEDDD0984104012A7498B4C7CECDBEA16815000D4B86C0D6CFC0B8AF6B0800124A71A0C3C3B0A6A17B2E00002973B5B6BBB9B08C4C0500002D40230C0F275C7D68391E2763C2E7EFEBE5DED7CD92320A073477A87D4C35322B170000007585C0FFFFFDC58C5C43445186E6FFFFFFD592442A221614368DD5FFFFD5955627201C2857A7E8F4DF448865361E3A554B579CD5FCFFCB6C200B081C212A3B7DFFD592442A22161401FEDC5D070718C07E71657E90AFB38D735043302F28305E93D6FFFFFFF9F9CD76240C0B20427FC3E9EFE6DCA24417072A7BC1D8C7BD95470E00021B6CC0ECE2CDD9AE5D1200094088B7D7CBCFCA8D3409032A6E99B5CED5BCBCAF6C1A01165D91AFC9C1C5C8A75F0000164E7CA2BDC3C0AE95731300002E84C0BFC5C3B17E370000001E3B24161830597C61342A3275BAEFF6E6E0DAD5C0892C07003675A793513A362F130200007996CFFFFFFFD7916848425A9EEAFFFFFFE69D5D3C221E243488E0FFF7CC924F2515152B62B6E3F4DE437E5E3423495D445C95D3F0FCCF7226080A23222F4789FFE69D5D3C221E2401FEDD5D070718D07176768694B6B38A694C3F2C2B3434558DDCFFFFFFF0FBCB69350F162F4A90D3F1EEDBD5943A0D12357ECBE5CFBE8E430300002670C4EADFC8D3B7510B0010508EB3CBD0D1CB8E3D0902317FA9BFD5CCC0B6A257110016649EBDD1C4C7C4AF6100000F517FA8BEC1AFA89667070000288BB3BAC1CAB87A350000002837301D142A586F5636284378C4E6EFEDE0DBDEC390390C0D3476B08D4A30272D12000000768BD4FFFFFFD584564E455FA0EAFFFFFFDE94473329272E378FD9FDFBD597441C161A2A6FC3F4FCD84480621E1C344D4664A3E5FFF9D2702111182022223880FFDE94473329272E01FEDE5D070718E06D68657089A5A57B64413B342C37394C82CCFFFFFFF0F6CB6B2C0A142A528CD0F5E9DAD2903D110B347DCCEBD2D3973F01000A2873C9E6EBD6CCB2480C00104E8CB8C0CAD5C6883A0D022B81ABC1CACDBFBD9B4E0D00156EA0BFDBD7D5B7954D0000165E8DB6C3BBB2A196600900002F88B1C1C9CEBD732B0000001D39251F203454705B352A4384CDF2E9E7E7D8D2BF83290B14487DAA904B30312B0F0000008195D5FFFFFFD69467504F63A6F3FFFFFFD89851382F1B2D4895D8FBEFCF8E431D151F4588C9F9FBD53B6F53291D2D453F67A7DAFEFFCB702E1101101B2C3D87FFD89851382F1B2D01FEDF5D070718F0707367748BA3A8866A523D2C2D433E558BCAFFFFFFFCF3C16D2C1918375599CEE8DED3C8893212104387CBE0DCC69337040000206FBFE1EAD0CBA84E0A001E5B98B8C7CDCDC8812E02063886B2BFCDC1BBB9974D0D00277BA9C0D7C2D2BDA04C00000D6F95AAC1C1AFAC905D030000307EB6C6D0CEB064140000002B423C2627305B594D302F4582D0F6ECE6DFCECCBF782A0A164880A98B583D3B35180000007588D7FFFFFFCE834F4747619AF5FFFFFFDB93593C28202A3E97E0F5F0C48F481F23163083CAF0EFCF31624C2A1D3E45456CB1E5FFFFCF722B0805171F264487FFDB93593C28202A01FEE05D07071800786D698295B1A67D5C43392E3C383E6385CAFFFFFFFFF6C56B2D171B3A5597DFEDE4DED28C2C04183F89C4DEDDD490390300002F7CCDEDEFDFD5A24503000C5090B5CCCBCCBF762D00003084AEC6D5CDC5BF944F0C09317DB4C1C5C8C8B7993E00001171A1B4BCCAADAA793F0000003C89BEC6CFCDA955090000002738322D303A58563C3135518AD3F7F6F2E0DBD6C076290B1E4685B288533A3D3D1D0000007889D9FFFFFFCF8861525065ABF7FFFFFFDE975940332B23419ED9F8F3C37F400F14193A86D4F5F4D33A744A281E4542466EB0E6FFFFCB6D28101519202A4091FFDE975940332B2301FEE15D07071810776C7083969A8966523933312C38465982C3FFFFFFFFF2C56A2A0F193260ACE2ECE1D9CF823819185097CBDFE6D0933D000000317AC5E9EAE0D8A7440A001857A1C4B8BCCABA772000053993B4B6CBCCBAAF89471309378BB6C6D2CCCAB399450000207BA9BCC3B4AF8E703F0000004894C5C5CACFB34F000000001B393222203E4F5B4431435F94D7F6F1EFE3E1D4BB6C1F0D194B8EB190533E3A362202000086A3E9FFFFFDCF91675F5B719FF3FFFFFFDE9863432F2B293F9AE3FBECC28536140F21499AD9F3F4CB3C664329192B3D456FBCE5FFFDCC7E2808061118213C97FFDE9863432F2B2901FEE25D07071820676F6B879197896F5D42403C343E49587BC5FFFFFFFFFFC66926171F385DA4E4FAD6D9CC812F11204485CFE1E0DD91300000042D84CCDFEEE1D4A34003001A61A4C3C0BED1B86D1A00023990ABADC0BBB1A7803B0609428EBAD1D8D1C5B995360000237EB1BEC2BEB29E6F3900000246ACBBC5CFCBAB4A0000000026453F2A2B3E4645302C3C5F94DEFDF6EDDED7D4A8681805225494BA9A5F3F3F481F0200007A95D6FFFFFFD084614C5B6BA2F3FFFFFFD39A60372E21233D97DDF9F1C36A34131B235198D5FFEBCD295F41261F33303C75B8EAFFFFD1702C1105132225419FFFD39A60372E212301FEE35D070718307D6D60778F94856C604142433B434A5783C7FFFFFFFFFFBF56221C213966AEDEF4E3DECC7B2C0D165587CDE9E4CF983402000E3E84C8E8EAD4CA983500001961ABC6BCBDC1B06F210308388CB8B7C4C2ABAC724A10123B93C3C8CDCFCCC59C3B00003082A9B8B8B1B697642500000D51A9C1CFCECB9D3F000000002240423C30374A462D39456693DAF4E7DDE5DCCEB6641E05205191BD96624444441F0700007D9FE8FFFFFFCA8B5C4D4D63B6F2FFFFFFD4965F3F28262D44A4E1F9EBC1702F16202756A7EAFAECC0355D3E1D16233D3F81BCF0FFFFCD74320D072E2B3159A4FFD4965F3F28262D01FEE45D070718406F5E5B7683947E6B4A443E403D434E6484C0F9FFFFFFF0A54422131E3870B4EBF0DDD5C9832611265DA0CFEEEBDA8F2B0000063A84C5E3E7E1D6973C0200116BA4C1B3BCBCA8631900004397B8B7B8BBB2AB76491D0B42A5C4D1CDC7C6BD8A2400003290B0C1CCBFB0844F1A0000125894B3C6D5CE9E39000000002C5148433D3B4F362E30446399CFF4EAEDE7DCCDA059160B26649FB8965E364138210200006F9ADCFFFFFFC47F5C48596EB2FCFFFFFFC8955B4A362A2446A1DDFCE8A65F24120F2F5DA7E4FAE0B2385842201424354282CCF1FFFECC7A24090B1B2A425AADFFC8955B4A362A2401FEE55D0707185084706B7F9B9B88655D535046454B45598AD0FFFFFFFFFBAA5424132A4B81B8E7EDE3D4B9772F0E275A9CDEEBE8D890320000143688C2DAE1E0D48A3102001E6CA0C0C1C5C0AC5A1500053892BAB6B6B7A89F69320B1853ACC7D8CCC9C0BB8F3000003B91BDC0B8B7B98E3E0000001663A1BFC9C5C19939000000002E5050454742413C26385379A0DCF2EAE5E5D8C4A1581B1738629CB99F694B4C452C00000079A4E8FFFFFFC58364575F77B4FBFFFFF5CC945A3E31212C4DA4E5FCE5A86B2915172E61B1E5FCE5B2344B37181D1D2D4893D6F2FFFCC87130110A152E3B56B5F5CC945A3E31212C01FEE65D07071860745A56707F8C7C625C4C47484D464A6089C5FFFFFFFFF2A3481E1426508AC8E5EEF3DAAE601C12295FA5D4E5EFD78D300000063B84C4EDEAECCE882F0000216DAAB8B6BDBEAB560E00014A93C2B8BCC0AEA1692A0814529CCCD9D1C6CAB8822500002A8CC1C8C3BBA9862D0000002067A6CDD7CFCE903400000000345357494A44432E28355073ABEEFDF0E8D2D0C192460E0B3163A0BE95674F4941280000007390EAFFFFFFCA8C62595F81B5FFFFFFF3C2904B3235172351A8E6F7D4A15C261519275EBFF4FDEAAF234933222426284185CDF5FCFBC9712D171223253167BCF3C2904B3235172301FEE75D070718707D6E6974828778655A4D4C484D5352668AC6FFFFFFFFE9A045211A325284C4F4FCEEE0AD541C102F6AB9E5DCDDD78E3C00000E4A89C2E0E3D5CD802700002977ACBEB6B9BC99510503053C8FB4BFBBB8B79C652E10185BACD0D7DAD3C5BD85290000409BBCCAC5BBB77E1D000000276EABC8CFD4C9953100000006315E604A4943372C2936557AA2CCEEF2E5DDD6C28F39050F306EA6C1986E4D4B44230000007E9BE2FFFFFFC98663536380BDFFFFFFF0C3894A3A28252154AFE4EDDAA256241A152D5FB6EDFFDFBA34412B1D20212B3E90D8F7FFFFCF7B2F1B101F2E3B63B4F0C3894A3A28252101FEE85D07071880736A66787984736A655D4C4847495D769BDBFFFFFFFFEB9E471F10365B91D1F8F5EDD2A5531D162D6DB4DEDEE5D9922B00000E4289C7DCEAE8C9802700012982BCD4B9B8B59A470D00004397BBB2B5B3AA94662A0B1E5CB0CED7CFC3C4B2781F000048A1C3C5C2B8AA75190000002C74B5CDD3D0CD973A0000000138636D5F503D32252A415D7CABD6EDF0E2D3C8B37E32000F3471AAB99C725D5A4B1D0200007A9EE4FFFFE8B17458546983C6FFFFFFE1B97E4730281B2A58B5E8F0D4994317131C3170CAE9F5E5AA30462A1D1F2934428BC7F4FDF8C47225150F1C2D3D65C2E1B97E4730281B2A01FEE95D07071890796C637B7877766657535355525859709BD6FFFFFFFFDF8E53261E2D5988CCFEFAEBD39D521B0C3371B6D9ECE0DD942D00000A4792CED9E6E2CF872000002B84B5C1B7B7BB97450000004496B5ABAAB4AB95562811186BBED9DED8CFC8AE7C1F00004EA9C4CCC2C0BB7F0F0000003575ACD8DBD7CC913300000000345364645A4D342425385F8AA6CDEBE1D9CFCAB378310C113171B0C2A071474F471A0400007D9DEDFFFFFDBC775D556389D6FFFFFFE1B17D5134221A2B4FB6E5E9D2905E220F1C2E72CAF6F6D4AB2E3824192029313B8BD6F3FFFFBD732C10161E223F7ED3E1B17D5134221A2B01FEEA5D070718A07E6B6972727B6E616250535A57566177A7E2FFFFFFFFCC7F341D223E5597E0FEF0F1D198481C1A417FBEDDE6DDD18D36000009478EBBE2E2E0C1782700033E7DBDC4B8C1C0A1420100034996B7B5A6A4A19551230A1763B5DBDBD3CDC6AD741B00005BB2CBC6B4BCB16F02000000368BC2D3CDD8CE8E3500000010446D6E605D4B2B231B376A8FB0D8EEE3D5CDCBA666280A153976AFC19D7C5343341300000075A2F5FFFFF4BF735D4F6490C5FFFFFFD5A979412F2C242D68C1EFEBCE8F3E1B0C193479C6EDF9D89D2B371A203E2725428BC5F6FCFCC4713410161F314179C9D5A979412F2C242D01FEEB5D070718B0786A6170746C655C5B52565658606176A4E1FFFFFFFFC9783D2023386B9EDFF5F5E4CF9D47141C4488BFDAE6DFDC933204000F469ECADFD5D4C2731E0000338BC1CEBFBEB697420000043F98BCAB99A6A587502A0D256BBDE4E3DECEC2B06918000762B0C0C5B8B5AD6101000000488FBBCAD6CBC5852400000007466F7B6A62422C191B3D7296AEDAE1D8D8CCBF99612208134180B2C7AA80614C431F0000007D9CEFFFFFF0AE6F5E516B8DCEFFFFFCD2A471422A2D29336AC3E0E9C382461D06213B81C9F4FFD19C35382B24261D264C94CAEDFDF2B66C2826181F354A8AD6D2A471422A2D293301FEEC5D070718C071695D686D6F6D5C5A5B5C59555A6076A5DFFFFFFFFFCA703B1A193A6A9DDEF4EBE1CD8E4C1B1E3F89C3D8E4DDCC9D2B0000135788C0DCE8DCBF711800003A8EBAC3C3C2BD9C460400044190B6BBA49EA990401810287BC3E4DCD6C6B4A2660D000861B4C3C2BABCB071040000005C9FC2D1CCCABE8B320000000B547A80756C4A261C1E427F97B0CCD5DAD1C8BF97582507164482B7C3A2785B4E431E00000089C1FFFFFFF7AF80655D628BCBFFFFFBDBA4623A242337336ACDF6E6C0823C201427347ED8F6F3D48C333A272A25242F4794CFE9F1F0C0672E1A1D26344394DEDBA4623A2423373301FEED5D070718D07B6E637670726C65685D6064676D6B82A9EAFFFFFFFECD7B3A1E284472ACE0F0EFEAD08E4621224891BDD5E4D1CC992A0000125B9DC6D4E6D7B96A0D00003F89BCD1C7C7BC9C380000053A8BB9A891A5A3824D240E1977B9E1E1D4D2C2AC5D0A00166DB6C7CDC1C1B76303000004639DB9CED3CBC89933000000195076838272533113123B799CB1C0CDD9CFCABC80491700113E83B6C6A58E6652371F0000007DAFF3FFFFD9A073515D6089D5FFFFFDCBA27A473129252C69B4DCD1B870331B18263B83CCEEEFD3982B34211C312D2F509BD5E9FAE6B569191417243758A0E8CBA27A473129252C01FEEE5D070718E0775F63716E6872616760647363656084ABF5FFFFFFF5B968382829467AAAE5F3F3E9D28F3F0C174A9ACAE3E9DDD1962D000018589EC0D9DBD0B25F1000003E90C4C3C1C1B88F350000024199C8B29E9E997D39170E2E82C8E0DDD5D0C2A15908001174B4CABFBAC3AF58000000066FB1D6CBD6D4C7923600000014547E8C847749210F1D4580A1B4C7CFC7C7BFAF753D1000174A89B6BDA17F63593B0B00000081CCFFFFFFEFA97262646C87CCFFFFF6C49768382D3233407CC9E7D9A76434180C244396D5F5F1C77D2B2F21272C29214098D3F2FEF0B15F271E1C2E3D67A0E7C49768382D32334001FEEF5D070718F07969656A6667635B655D616E76625C72B1F2FFFFFFFAB35F2A22264678B2E0F7E7E2BE8340111F4FA0BFD4DAD8CD973900001D5EA5C7DDD6D2B3570A00064796C2C7B9BFBD90330000074195C1AE929B91653C150B2F7ECCE8E2D6C9C59B4A0000217BC5CACABAB9AC54000000166AAFC8D3D6D3BA8D2D000000165D85958C854C220A174589A6ADC3C9C9BFC3AF7038090012428BC3C0A883615033110000008DB0FFFFFFE6A17962626A8FCCFFFFEEBB8B67391931334982C4E7D5AE67341C18294691D5F5E5B87E3C351B202F3336559CCEEBEDEBAD5B1E1718253668A1EEBB8B67391931334901FEF05D070718007665666D6A6266756068626F7B696D7FADF6FFFFFFE9AE602B1D294C7CBDEBF3E6DDC5773618225EADD3E4E1D3D8922500001666A7C1D0D1C9B95B140009499EC7D0CCC8B48C2F0000003E97B9AB949F8F682D1C102886C8D9DFD0C2BC984800002780BFD2D3C1BDAF5B0000000D74B8D2CCCFCFBD912C0000002360909B918257210C164388AFB1BDBDBDBCB4A468340F0A1B5296C6CEAF8B614B26080000007EC1FFFFFFE397726A666091D9FFFFE1A58B683C28333A3F7FCDE0CDA45E351B2C2F5C83D0FEE4BA7829281721302E2B47A3DBE6F3EAAC5C2B1A252F3F67B5F7A58B683C28333A3F01FEF15D070718107D6D67726B6A6A736D656A72726A6E7DB6F7FFFFFFF3AF602E1C2D4F81C6E6F0E9DCBE7734182871B6CADAD4CFD5972F00001E67A6C7C7D4D5A6540600044FA4C5CCBEBDB790290000093C8EB4A2969D9F643413103685C6E7D2D0C8BE832D00003994C3D6D9CCC3A057000000087DB6D8D7D4C9BE9534000000206D95A2938A5932151E4C90A3AAB0B9C0B4B2A162240E0D184E97C8C7A48767432A120000007FBBFDFFFFD99661646B6A8BE0FFFFE4AB8C623C2121314998D9E8CCA3552C241D2D569ADAF9E2AF6E282F1926322D2F55AFD8E3F1E59C552C13191F2E6AB3F5AB8C623C2121314901FEF25D0707182078676D726A5D616E6662727A7A68668BC8FFFFFFFFE0A9572720335286BBEBF1E8DAC57E3C1B2462AECDD1CFD7CE993100001C6DAED9DCDBC3A25A0D000055A9BFD3CBBBB181270000003695BFB196998B5C23120C2C8DDCE5D6D3D1BD813500003393C9CAD1D0CBB65C0000000C78B9CDCECDC9BC933E0000002970919D97875B1E10133F82A3ABB5A8A6B6BEA364290603216298B9C9AB835E442D1100000086C9FFFFFFDA8E65656A6894E2FFFFD7A27061382F38314B98D9E8BB8A4E2B1B283755A2ECFAE3AC6C2C291F292F273664A5D7ECE8D79953281D202C3C81C0F2A27061382F38314B01FEF35D07071830776A65695E5E636C69656C7174747387BCF3FFFFFFE89F532425354D84C2E5F3E4D3B06E2C102C6BBDCFCFD7D6D4923E00002B73AFC8D7D8CFB05600000957AAC8CAC5BDBC84290000004097C6AC989D8150250D12328BCFDFD6CECBBF7A310000398FC1CAC5C7BCAF5B0000001D83BCD2CCCDC3B694370000003180A3ACA6926724000E4890A8AFA9AEADB2AD9753230D08215E9BC7C2A2886743210A00000091D4FFFFFFDE95745E606496D9FFFFDBA97C61462F2E3758A0E0ECC9854F2F1926315CAEE9F8DDB171242C262B2B2A365AB1DCE2F0DC99542D1C1F223C77C0FAA97C61462F2E375801FEF45D070718407660656C68686E786A71747C887D6C83BAFEFFFFFFE096422B2430538AC6E6E2DADCBF722D183880C0CDC4C8D5C8893000002B7BABD5D9DBD3AC5E06000E5CA4C7CBC5B2B481290000003896C3B090968A4D1E0E083A8DD0EDDACBCEBB792A0000439AC6CED5CDCAA8520000001C7FB7C4C2C2C9BD963B000000357BA6AAA6A061220C144994A6B2A49DA4A9AE9B602508041E5B98C1CAA8836037260C00000086CBFFFFFDC884635B586291D5FEF2CF98725B332B1E3F72B3DDD9B27C4A25161F33569DDDEFD8A764363425272D2A3769AFD9F0EBDB9F5325171F1C3F7DCBFF98725B332B1E3F7201FEF55D070718507068686C6B696D7478797F9695816F7FBFF9FFFFFCDC935023222C5494CAE6E0D3CFBA73331B3579C3CBD5CDC0C08F2B00002C76B7D6DBD6C9A2550F001371A4C9C8C2BBA374240000003692C0C09A9D893F120D0F3197DCDFCFCBC9B3721E000053A7D1DBCBCAC4AA5B0000001C87C5CBD2D5C3B3923C0000003682A6A7AA8F582309124E8FADB5A7999EABB5985F270F07215B98C7C6A9875F35190602000087CFFFFFFFD38663645B5D96EBFFFFDC924F4C38363D4869B6E3E8C37D482A2221345AA8E3EFDA95582C23232733303B73B7DFEFEFD7964F29272A34457EC2FE924F4C38363D486901FEF65D07071860695E5D69656C747D8171778F907C767DB8F4FFFFFDD88C503230455C95CEDBE3DDDAB66E2B1D3775BBD0CDCFC0C28A2C00002B7AB5D1DADACEA5450000156EB8C8C6B7B6AB782200000243A3C9B1A39B773B100C103D8DD1E2CBCACDB96B18000054AACDD0D2D0BAB664000000218FBDC8C9CDCBBC963A0000003A84A3A7A58F5824001C51A2B9BEA58E98A4A789542A09032860A7BFC5B3865B35120A0200008AD6FFFFFCC07D58645A7596DEFFF6CA845A54312F435174B8DDDBB47A48261B29385CAFE4F8CA92542A251926252A3A6CB5DFE8F1DD9154382E35353F80C5FF845A54312F43517401FEF75D07071870736D6F7C706B797A837A80A0987C6D86BCFEFFFFF9DC8F4B29283B61A1CDE2DCD6D8AC5D281A4288C4CFCDCED0C4893100002C7CB1D2D2D7CE9D450000156DA9CDC9BDC1AD771C00000A469FC1B79F9C68370B07003290D1E3CFCCCEB8621B000058A4C9D2D0D5CCB5540000002794C8D0D1C9C0C5A23C0000004197AFAAA69E5F1D05115494B1AF9D8E97A7AA8D522601002E6E93BCBEA7845C230E070C000096E6FFFFF8BB76565E5E548BDBFEF9C3865E48352F3D4672BBE4D9A86E412320324165A7E3ECD295522D281D2928293065B0DAEDECDDA25832262F314E8ADAFF865E48352F3D467201FEF85D07071880716C6069656D6E757D728698A38B7987C7F7FFFAEECA784423263F6699D4E3D1D6DAB567311F4289BBD6D2C5C2CA872800002588B0D1CFD2CE943C00001374B3BDC7CABCAB741600000E4A8FBFC2AE9E7932090A003490CEDDC7CACAA96417000970BBCECBCFC2C9AD5C0000002C90CED3CFB9BEB99D3E0000003F8BAEB5AEA1652300144A98AAB09F8997ACAA86452912092B5F99BEC3AB7E59240605040A0097E2FFFFFFC77B5753516599DDFFF5C08361422C2F3C4F78CDF0E3B16C3E2120263F72B7EBF1CC865124271B202B2E366FB9D8E3F0D99958322722304F95DFFF8361422C2F3C4F7801FEF95D070718907A6E6C726E7883908A82939F9B8E7D97C8FBFFFDEDC37F4B2C28415FA4D7E0C7C8CDA453251B3A88C5D4CCC2C3BF8B2F00013085BFC6D5D0CD9F4308001E7CB4CCC2C3B7A36D16000018489ABDB1AA9D72270100083492D9E7C7CED2A25315000769B6D2D1C9C5C2A253000000369BCAC8CBBBBBB197440000104693AEB2B0A76A1A0114539DB1B09A878D9EA9914B27150C366D9EB4C4A57D512306000200008AE7FFFFF5B97447564E4E84D4FDF3B7784C433431425987CAE6D7A6623C16272B4472C0E9ECC48042272B23262D2D426DB7D4D9EAD7905B2B2934385397D5FF784C43343142598701FEFA5D070718A07A716D716E767F8C9E8EA1B4B28E7793C9FCFFFFDEAF7745292F426DB2E3E4C7D1D5A5582A214595CBD1BDC4BCC48C3402003991BBC8C8D5D09C3F03001C7AB1C9C8BCB6A66B1000001C54A3C0B7AD9267240000002A8BDAE5D1C9D19B510800076ABBD2CDCDC8CCB05900000035A5CAD3C1B6CDC3983E0000024491A7B7ACA0671E06205C9DACB6977F97B0B08F512E18092F6A95ADC0AD7C461A02000A0A0097D9FFFFFAB5714F4B525486DBFFF7BC7652462E2B3A5C88D6F7DCA4633B252227457AC2EBEFBE7C4D2A28272822273477AFCFD7E1CF91552F29363A5998E1FF7652462E2B3A5C8801FEFB5D070718B07C71686F76788793968D9DB6B3927792CCFFF9EDD3A5633924324470B2E4E4D5D8C99C5020204B9BC2C9C3BAC1BE8D330200378FC4D2D1CECCA03900032B7CBFC0BCBAB59E5A1400001C51A2C3C2B99D5C1D0000022F92DCE1C9D0C89C4D08000B6DBAD5C4C6C9C7AF4C0000003F9ED5C3C3C1BACA97410000075391B0B5AB9E5B1B071B66A9BCBB9375819CA87D4C2C1C0D3D719DB1AFA37F4816000013080096E2FFFFF9B473524E525597E7FFF1B77849342C29436192DBFBDFA75F3C1E222F517CBEECE6C889402A23222A28313D81C3D9DCDBCB8E5D382F2B3554A1E5FF7849342C2943619201FEFC5D070718C073726D77737983969A9495BBB8907C98D3F3FFE5CC9F684B2629497CB6E1DFC6CDC89253211C4B9CC6D2CBC0D2C07C28000B4290C7CAC6D2C4914608002780B5C1C2BAB3AA650C00001C61A0C3BFBAA4521000000A3085D9EED6D1CF9B4007000C7BD0DFD8CDC4C9B456000000449DBAC7B7BBBBAF93300000095A9EB5B0B6A2681B0420689EB9BC978990ACAF864A23110F32729EB1B4A67D441100030C0C0093DCFFFFE7A6694945464C87D3FCF6B270402C252A435D8AD6F9D897582F1B21305483C5ECEFCE7E3D25231A27272C4A82BBD0D0E5D08D584133374255A1E3FF70402C252A435D8A01FEFD5D070718D07E72787B7E7D87A1AB9BA5CAC7A57D91CBFDFFF0CD9568432F35527AC0EFEFC9C2C5914C1B234B96BDCFBCB7C2B4792C01084499C3CBCED3C9903805083784B3BCC1BBB7A2600400001D69AABEB4C0AB5D17000008328CD4E7CDD4CAA23C03000A71C7D1C5C7CFC9AD520000004198CFCEC8BDBBBB963B0000125DA3B2BAB79B67240B1D719EB3B0957E84A9A27A4D2E21133D7E9CAAB9A17C4219050105050092E1FFFFE1A8624348455590E5FFF1B26E4B3B3230445490E2FCDE9A612E2425315086C3F1E9B8743F2F1D1D30252D3D7EB6C9D4EBCB8357423138475FABE7FF6E4B3B323044549001FEFE5D070718E06D6F6476717889A9AC99A3C7C79D7C8ECDF6F3E2C38D6549393A5185CCF5E3C5C3C18C421C1D4C97CBD7C0B2C2C17B2E0B074296C9CCCAC2BD893500043792C9D0C1C0B99D5C0500002871A7C4BDB89551050000073686D7E5D3C8D0923800000D7DBCD2BFC6C7C6A84600000046A8D3CCC7C4C3BE934200001B639BB1BBA693621E081C61A4C2C09C7F8EA6B08B4C3819143E7CA3AEB19F753F0900000B1100A2E8FFFFE79D61434E485895E6FFF1B364363025354C679ED9F2D79F5A2D1D16255191BBECECBC6D3B2D291F27252A3B78B0C8D4E1C77E514035374467A8E7FF64363025354C679E01FEFF5D070718F0787076807B809AAEB2A1A5CCDAA48591D4FEFCE4B5895B493B395889C8ECE2CBCDB97C32161D4791C5D2C5BDC6BD782D06054897C6C9CACEC8902D06113F8DB7CBBAC5BC9D620400072F6DA7C9BBC2974C04000000318BD2EBD9D0C09B330100107FC9CBC4C6C5C6A53F00000056AACDC9C8BFBDB38E3A000019609EB3AFB3A17228031C73A7BAB48C7D88AEAB8153331C184D7AA1A5B1A67C41060000031300A4F5FFFFE5A15F4D42475A9DF1FFF9A65D3E392828476DADE4F9D8A04B271E22345982D0ECF1BC6B2C2427202625254086BBC3D3DDC881564034384E7CBCF1FF5D3E392828476DAD01FE005E070718007E747A827F87A2B4B89CAAD5D6B07E93D0EEEED9B0765C443A4A5896CEEEEEC8C5BA6D3419124B92C3C4C2BABCB9782700083D99C9C9CAD0C4933201124A92C5CBBEB0AC94570300063979A7C5BEC697510B0000002D8CD4F3E3DBC5892A00001379C0C9B7C4D4D2A44500000059ABD3D1BCC4BDB48B3200001E6798B0B3B1A36B27042F6C9EB9B6988898A29E7757392516477FA0ABAE9C7B3D0C0000050F00AAF8FFFFE8946849444B5E96F2FFFAAD6B332A1A3141619EE2F0DDA05F372A2938538ED1F3E8B16D382D23262621283B85BCC2D4D7CA794E3837354974BEEDFF6B332A1A3141619E01FE015E070718107B75767C798AAAC9C3ACB7D5CFAE8591D0F6F6E5B4845B403B48609ED4E4DBC2BFB3631C12184C9ABFC6BDB6BAAE6D27101847A3CFD2D3CDC88931080D4893C0CCCFB8B49D5600000A3F7AB3C2C9CD9445080000033983CCDADBD8C28D230000128CBBCABFD0CEC8A6380000005CA7CBC4C6BDBFB58B3500001F74A7B6BFB7A86617001D6DA4B9B8A2868D9B9E7B583D21255482A5AAA097753B0000000B1400A8F6FFFFD68C59343536539EEFFFF4AB623E312B2B3F67A6E8F4D79859341F18355E8EC9E7EDB96F3A291F212A2621387BB2BDD0D9CA74463838344871C0F6FF623E312B2B3F67A601FE025E07071820746B73817E8CA0C0CDA6BDDDD3A37D8EC9F5F1CDA07054443A405E99E1EAEBC4C4AB5920071A54A2C1C8B1B7C4AE681C020B4CA0CED1CBCFBC842B001B5C9DC3C4BCB3B79A4701000A4780A7BFC5C19B45000000003A90D4E8DDDACA822800001981CBC4A7C8CECCA53A00000061B6D4CDC1BEB2B8933800001E6AA4BCB1ACA05D15052B6DA8BAC39E8B8DA9A47E604F29235382A6A2A098672B0000000F1300B3FBFFFFDD8E4F47464D66A7F2FFEDA65B332927284261A6EAFFDD9E673C27272F608ECEEDDAA2552C2218252B2B2B4C87AEB9C4D8C5794F4033314A72BEFAFF5B332927284261A601FE035E07071830787D7784878EABC6C2B2BDE1E6BC87A3D3F3F1D09C69584E3B4466A1D7F1EBD6C4A34D16071858A3CBD2BCB5BBAA5E20000C4895BFCBD8C7C28B3A08215F9EBAC4C0B6AB904E0000154887B3C2BDBE8D39000000054098CDEFDFD5BF7D1B00001685BCC5BACAD2C9A94100000067B3CBCABDC4B9B68932000022699FA9B1B5965C1211306EA9BAB49B8691AB9F7D62512128698EA3A6AE997330000000121900ABF5FFECBE6F4B38333B5BA4F2FFEE9F5E33251C243668B8E3F4D09A6037241F385C8AC5E7EDBC602C301A2F3023254582B3B9C4D4C178453331364E77C9F4FF5E33251C243668B801FE045E07071840696E73798195A8CCCCB5BEE8E0A28295D0F2E2C58B61494D484F6CA0DAEAEDD7CB9C4E0B0017519AC3C8B9B1C2B56024091A4C99BEC6C8C7BA7E2C082465A8C2C2C3BEB9964900000D4484BAC1C2B38C4605000003338BD5E6E6E1BF701B00001F8ACCC7AFC2CDCC9A3700000067B6C7C5C3B8B4B0852A0000276FB0B5BFB2A466290530749FBDBE9F8A8DA5A274614B2C28669AA4A7A09A7426000000161A00C0F3FFF7C47F4B3A3D3B5AA7F1FFE6A55F2C261B28406BAEE7F8DA9C5F3E2D24375C86C5EDDDAA612E3C2926312E20357CAEABBBCAB77643312F404B78C4FEFF5F2C261B28406BAE01FE055E07071850777B7D8E8D9FBEDFD6BBC8E9DDAB799AD4F4F5DB9E5D5453464470A9D2E3DFD8C29E410B00145FA7C9D3BCB3C6AF521800144C9DC9D4D0C8B0722C092873B3C5C6C7B7AB8F3E0000165291C0C9C1AE8D4701000008388BCEE4EAE8BF6C1200002186CBC4B4C2CEC8963400000060B3C4C6C5C3BDB48B2E00002A74A8BCB3AFA4631E003078AAB9AEA79599A8A1746756352E7095A3A2998972270000000F0F00B3F6FFFDBF74453538355AADF9FFF3B25B302B2B2E3063B5F0FBD9A77347291B30628BCCEDD7A5562C322C323223193B7A9AA4B5CEC6764532363B4873CFFFFF5B302B2B2E3063B501FE065E070718607A88828A8FA1C3ECE5C4D1EFE1B68A9EDFFFFFD78D635B63555877B6DEE4E8D3C28A340C061C5BA4CAC0B6B5C4994F1201174B90C5D3CEC6B8802F05237AB4B7B9BDB8B195410000165791BABCB6BF9649000000004195D5E0E8E1BF6A1700002191C9BCB5C6CCC98C3000000674BBCAC1C2BBBAAF7C2B00002983B1B1BCB29D6117011E73ADC0B99D979FAA9F7960602C2E749FA5A19C94671F0000000F2000B4F9FFF5B36C4D3238365BB1F4FFEAA65B302D30273461B8F0FFE3A968452822344F86C2E6E0AC5B233628353020253679A0A2B5C9C0713F2D3534497BC8F4FF5B302D30273461B801FE075E0707187080807C899499C1E6DDC2CEF5DDB38A93C6EFEECE8C5A5057535074AFDBEAE8DFBD892900001958A1C5C9C0BABDA6521E0D154998C8CCD6D4BD7A29073175A5B4C8C4BBAB8839000022639BB4C0BCC0973B00000000388FCBE2F3D9B85F1800002186BCCABCC7CDC2822E00000268C0C3C0BFBBB5AB7D2A00002D7DB0BBBCB0A7611900337EAAAFB09A9C9AA49D6F676034336F98A7A29A826B30000000121C00BBF7FDEBAA623B3127315EB4F1FFE697532925292D396DB9ECFADDA465423521355784BEE0D1A357272F2035392725418C9EA1ABC6B36E45382A2F4C7BC8FBFF532925292D396DB901FE085E07071880757E888F95A1CAFBEBCBD8EFDFB68394CBF6EFCC8B6061614F557CB2D6E6E5D8BE7C200000135AA8D1D0B9B4BD9B4A150A1B4C93BBCDCDD0AD741E08287BB7C5C3C1BEA88E3F00001A60A1C1B7B1AA8D3A0000000441A1D4EDE4E5AF51080000158CCFC0BBC7CCC3801C00000276B0CEC8BCB5B8AC72240000337DA8B4A7A6985D1C0D2B7CACBAB5A097A0AEA27E7264343776919499A49163200000000F1A00B4E3F4D1944B24202A3256B4FDFFE5A2512E2F1F242669C1F1F2DAA76A4E311929497FC8E4D7A54F24341A39341C203D859695B6C2AE6D39353830497AC8F9FF512E2F1F242669C101FE095E070718907A817C8992A8CBF2F2D0E2FAEBAD8098CEE8DFC981545E715E5E83BCDEDFE4D5B175190000125A9BC0C3BDB9C4A34713061F448BC0D2DDD2BE7420082D83AFBBBDBFB2AC86380000186B9ABFB4BEBD8F430000000A499BCFE3E8D7B44C090000349CC5CCC0BFCECC87260000027ABBCBC8CAC6AEA76D1E00003477A4AAA7AC9B521B042B78ADBCB2A498A3AD9F7172632D39809DA2A0A58D671B000000121B00ADE7FFDF9543151529275DB1F0FFEA9851232A26223772B8E4F7D9A5794F3120364B81C9E5DDA54A243A20262E221D3A7CA299B0CCB66E43353239537AC7FEFF51232A26223772B801FE0A5E070718A06A6A7B808FA2D0F7F1CCEDFFE5AB839CC9E5EAC97D5D5D6F606484B7D8DFDED9B671160000145C9DC6D2B6B8B792441806184A93C7D9CFD2B76A1F053590B8BABEC8B9AC742B00001D6EA3B6BDB7BA91450000000B4DA1D2EFE2D5A9560000003A96C3C9C2C9CDC780200000006BB0D0CEB8B3BBAA702800002D76A5AEA59D925F1F0D377DA9B2B19C9AA7A5A06C786C3A3672939D9E918A6A1E000000152104B8EEF1D78E391814222155AFF0FCE093472B291D263568BCFEFFE2A077502A202B4A81C0E1D59A4D214823292D201F3F84979AAEC3B666382C2C344177CFF8FF472B291D263568BC01FE0B5E070718B07272788B8EA1CBF5EAD1DEF7E8AA8698C0EBE1C0784D5C86756479ADDADAD5C7B5731E00001C56A3C3C4BBB6C2923F0F0D274C9CC3D1CFCCAA5F15083987B0B1C2C5B3A7732400002475A2BEBCAEB19B430200000D58A3DAE8E1D2A0450700003E9DD3D1CBC9CAB4721500000C80B8D1C6B5ACB1A76E1600002E7D9AA6A7A0975E19033484AAACACA9A3A7B19D6F7164423A819F999F9F8A5F1C000000161300B3E7F1D19241261F232E62BAF0FFDBA04C2B251A1E2B6BB6EFF5D2A46F532922395780C3DFD598490F4022302E22234D8E907CA2C3B2642D3435394E75CCFDFF4C2B251A1E2B6BB601FE0C5E070718C07C797C8790B6DDFFF7D7F0FFE4A98DA0BFE5DAB7754E677D6B6287BEE0E9DACFB8731100002060AECAC9BAB7B68D3A0C091F5C9DC5DACBC7AD5B18064393BBBBBDC1BAA46D2100002779A8B6AEB0B2953E000000115CA8D1DBD8D4A54B0800004096C5C8C5CFCEBE791E00000E7BBED4C8C0ADAFAB681800002F7CA6A5AA9C946019072B7AAEB6B7A2A8A8AF9D7D7A7343437FA1A29B998E600F000000141C00B2E7E7BF732F12181E1F53B9F7FFDB97481E201A1D326CC0F1F8D7AA815132222A507FC0E2D38F461D432630392526377E8C86A1BCA4663A2F2A2E4181CFFFFF481E201A1D326CC001FE0D5E070718D0796F7A8F9EA9CCFFFFE8F4FBDEA7869DCEE7E6B571527D9280708AB8CDDDD5C0AC640000001C5A97BBC1C0B2AD84350C0B2F5B9DCDCFD1CAA85A0F083F8AB4B7BDCAB49E5F1C0000267FB1C3BFC1B6903D0000001060B0D6ECDFD7A4390300014EA1C7CDBBC3C7BF6D1100001681B7C2C0B5B1A69C691000002E80A2AAADA49D5F1D0C2E78A2ADB1B0ABA9B19E757165373E7E909EA599945B1E000000192400A7D9D5BA67280E1419235DADF0FFD98E451E261F232D6DBDF7F6DBA273512D1D274587C9D9CC98431B4B23232D181B49898F7FA5BFA369422E39364671CEFAFF451E261F232D6DBD01FE0E5E070718E07F8786A0A6BDECFFFFEDFFFFECAF8EA5C7DFD5B3725B6F8C7C819DC0D4E5D0C7B26A0E000012579DB8C1C4BAB5883F191A305797C6D1C5CEB35709034095BEBCC3C9B694571600002C7BAFC1C2B7AB94380000001961B2D8E1DACF974101000B5BA7C9CFBFC9C4BA63040000188DC1CBC4C4B9B19D59200000347A9DBEA69D8C461A08367AA6B8AFAEA7ACA195716C653948789B9A9AA0905F15000001181700B7D8DCB0671B0E101B2467C2F7FED993431F271F222E75BEF2F1CAAA7A4D28191F4B7FC9E2CC974C174E2D232717174080847CA4BEA662373B37364677D0FFFF431F271F222E75BE01FE0F5E070718F0798185979FBAD3FEFFE9F2FFE7AB97ACCFE3CB9E6C57708B847993C0D9CFD3CFB45F0500001B669FC0C6C2B5B8873B141E3B5C92BACECABB974A0F0E4C91B3A8AFBDBA945C1800002D85B3C0BFB7B79B410000002069B4DFE3DCCA923E07001267AFCCC7BEC8C3B361070000137FBBC5C2BEB7A98F4D0F000035819DA6AE9F87531A0333769FB7B7A3AFB8AA95787B6D3B478991949CA98F5713000002201A00A9C5CDA85D200300081968B3F6F6DA8F3F262617112F77BBF0EFD1A87A502A1A2A477CC4E7D08F40134F2A292C1A1E41857A75A1B49E623E2E2F3B466ED3FBFF3F262617112F77BB01FE105E0707180080808696A4B2D4F7F4E7FFFFE5AA96ADC4CFCCAA684F74908E8092C4D2D5CDBBA75C0400001859A2C0CAC3BDBC863E181D3C5F9BC4CBCDC593400B074C9AB5A6ADC4B9984A120000347CB4C2CCBFB89E4B0000001D6BB0D8E2EAC8894213000B5FB0C5CAC6CAC4AD530000001484C7CEC9BBB2AC964F1700033A809BA7A09B804218043575A3BCB5B2BBABA08D6D735D3C3F85999CA2A19861120000051B1D00A9CACEA24E1100000F1E68B7E4F2D17F371A1718183478BFECE8C5947B4F1F172F4482C5D9C58A321157262925162246808476A0AD9E583D3336424A89D5FFFB371A1718183478BF01FE115E070718107176838D9DB5D6FEF4E6FFFFE4AB95A8C7D3C79A5E4F708F897E9EC2E4D7D2CAA6620200001A5CA1B8BBB3ACB1872C0F1B40649EC4C9C6C2A3490A0D4A96ADA1B0BEBFA03D000000308AC5D0CAC1BD973F0000002370B5D3DCDBD490310000186EAFD1DACACBC8A6500000001A7EB8D3C7B4A9A9944C0C0000387F9DA8A48F8C4A12092E74A2B6B7AEB5B5AE96757766474E818F9EA7A8925E15000001141D00A0C1BD9948060000001E62B6E5EDCA7638181B10183376C8E9E0C5A47745301A234581CBE3C790400C68281D1E1016428881739AB1915C3F34313F4D7FCCF9F638181B10183376C801FE125E07071820818A8E9EA3C7E4FFFFF9FFFFDCB39CABC4D5C799644C75968C7FA1C4D3D9D1C6AF5E000000125CA0BCC4C5B9AC782D112053709BBAC1C7C09C4406135692B3A0B1C1B588310200003888C5C7C8C0C39B3A0000032177B9D3DFDAC1823B00001E68B2D4D7CBCDC8AC530000001B88C1CDC0B1B4AB8D541100043C7E9D9F949C824509002A75A3B6B7ADB0B1A48D7C806D3859889291A3AEA05D140000000F1800A3BBAF883E000000081D6DB5E8E8C27B2E0C15090F2B81CAE9DEBD9F78462714224787CAE4CE8D3E0D6021201A12174D888379989C855A3A3631333C7BD3FEF82E0C15090F2B81CA01FE135E07071830808394A2AAC3DFFFF8F3FFFBDEA9A3BAD1DECD9C5848769F9495A9CFD8CAC5C2AD570000001C6CA0B8BAC0B8B3762B0C23536E9EBDCDCFBC954200034B97AB9EB1B6BC7E370000003B8DC7D2CAC1B7964A0000002A79BFD4DCE2CC872F02001F75B9C9CAC7C2C29F510000001881BEC5C4B8ADA2873F070000397D9DAF9A9C864B1B022F72A9C0BAADBAADAE947075744D5B818E979F9E8D6316000007190C008FADA57929000000001D68B3D9DBB8682D0F140C0E2D80C5EAE0C39D6C411E0F254488C2DED1984512631F202012164A83827393A48450333E3B324680D6FFF32D0F140C0E2D80C501FE145E0707184070767E8FAAC5E1F5E5EBFDF9CDAEA2BBD6DBBD94534874A59C93A2C4D9DCC5C0A256000000195F9EB6B6B6BEAF8033122E5D83ACBEC5B8B88A360405519EA8939EB8BB802B0000003C91BECECAC4B795400500063485C4D9E1D5C6892F05002381C1D0C8C9C3CA98400000002289B6BDC1C2AEAC83440F0003447A9BA3A193813D05072B609CB7C0B3B5BBA37E647769455E8A8A86A0B39E601F000008211D009AACA8752E000000001D5EB3DBD2B66625141300002F78C5EFE5C4926541241D264B89C8DECD8E43167732171E131C57756D698D9F8652383A3B394D8FD9FFF525141300002F78C501FE155E070718506C75879AACC2E1EBE8E7FBF9D9ADA5C5CDD4B989594D75A09B9CB2D3D2D4C5C2A65A0000001E6AA2B7BFC3C8A86D280A2E637EA0B6BFC0B07C2E00044591A597A0BAB376250000003795C3CCCAC9B8954102000A3D89C3E0E1E2C9873205002079B6CCC9CCCFC59E38000000198BBECCBDBFB7AF89490E00003D789AA4A392813E0C022B6595BBBBBAB5B3A094767B6242609090909DAD9762110000071412008BA09C6420000000001568B4D2CEAE6521000C080D3A88CFDEE1C1926743180E21508CC7DFD1913A10842D1E0F011D4E85776C90A2724D363F39374583CEF1F021000C080D3A88CF01FE165E070718607888939FABCFE4FBE3EDFCF7CAB1ACC0D5DCBB874F4C7DAC9A8FA5CFD9D4C8BAA95C0000001C6CA0B8AEB9B9B56F2918326B7EA9BAB9BAB57B26050A4B9BAB9498B0AF741C000000459EC7D2D7C7BF9238000005368AC2E1E2DFC884340A002E86B5CBD4C7C2B88C38000000208FC0BAC3BBB2A583440B0004407D9BA69A90723A0E052D6EA7BAB6A8B9B7A79766746647598C8F87A1AB9D671700000D190F008E9D985F0D000000001B6EB3D3D0A05B23070100113D84C7E8DABA966A3619121F4C82BDDFCE96420F7625140B0D1D5289726995A2774C3C3C42424C87DBFEEA23070100113D84C701FE175E0707187080908FA6BAC7E0ECDEE3F2F3CAB6B8CEE1D2BE80504F80A5ACA9A7C7D0D7CEBCA14F0000002775B2B8B0B4B8AD642C15286A90A5BBC3B7B67C25000E508EA58498BAAF6F170000003B9DC0D9D6CDBC953D00000C3F85C3E6E3DBC0803100002688C6C8CBCDC2BC97340000002F85BEC5BCBCB5A5803B07000B4D80A49B9199733006002A7AA0B7BFBEBBB4A78467766047688888859EAA9C572100000A1C1000949A905F11000000001A75BCDED2A75F1F0000010B3B89C6E1D6B7895B37180723518ECAD8D1924416822711130B225E8673648E91643D333D3C3F508ED3F5E81F0000010B3B89C601FE185E07071880708A8B9FC3DDE9E4DEDAF6E9BEA6C0DCDFDDC27F4E5280AAABA5B3CDD3CECDB89F520000001D77A4B3B5B7BAB16B1D15376D9BAAADC4BAB77B1F00054E98AB989EADAC6F0C000000479ECCD7D1CAB59E4001000B408CBDD7D6D6C77E2E00002D94C9D3CDBBBEB695380000003090BFC0B1B2B6A982360C00014B7C9CA4A398742B050328639BB9C8BBC1B5A58E626A5E486B8C868096AD995B190300101E1A008A92874C04000000001C68A9CBC399521900000009448DC6DAD3B0825D270E0C23488FC9D5C38E37087E29110A1B2460917D74978F5D422B3F323E548EE4FFEE1900000009448DC601FE195E07071890737F97ACBFE1DEDDD6D5F5E0C2B9C2D6E8D9C67E473C78A2B1A7BCC5D1CFC3C9A8530000002674A7B4B6B8B9AA611E11377E9AA7AFB5B8B06E1500054C9FAD8BA4B6AB620A0000003EA2C9E1DDCDBF973A0000114490C8EAEADAC07A3400002D8DCBC6D3CDC3B8842F0000003398C0C5B6B9A9A7763A0F000D3A7CA5ADA8A1792C0000195999C2C0BABBB0A590656C624F7A947E869DB6985C1C03000C1513008982784A00000000002371B2C3BD945509000000064494C9DAD2AF865322130F18419DCDDBC6903E138D29170F041C6889776F8B90663C313C3D395297E0EAE209000000064494C901FE1A5E070718A07A8D9EB0C5DEE9DBD4D8EEDCBFB5BEDFE1E2C07E4140739CA8AEC3D7D9C9BEC5A3560000002F68ADB6BDBCBAA45D1C0B3D7A9EB5B7B9A8AD7721000A4B93AC899BB7A46C02000000449DCED6CDCAC0953300000F4E95D1E1E8DABF742F03003593BDC9CAC3C2B881310000003B8AC0C5B3C1AAA16D300400014D84A9B5AFA1712C00001C60A1C1C3BBB5B6AC8766604C3D75958A8AA9B2A05A18060F10181100868F80460100000002337BADC4BA914A1300000007438DCFE6CAA677552811101F4B95CBD8C98E440F8F320D100225658E817598825C402E3738324B97E6F3D81300000007438DCF01FE1B5E070718B0768396ADC2E3E3D1BFCDE5D6BEBDD5F0EDDCC0713C3D7AAAA7B7BEC9CEC9C8C2A74D00000038739ABDAEB9C0A34E141142879FAFB0B2BBB66A2000084A9CAE97A2BBA469070000014893C3D6D3C7BA8F3400001B5190C2D2DFE2C7782803004496C8C2CFBFABB582270000003A92CBB9AAB6AD9C681F000002497FACB3A99F772F020626569EC3BFB7BEAF9C7B61625256819B7E7FA7B19E5F260E151E2312007382683200000000002768A3C0B990510D00000007408FC4D8CB9F72492615151C4C92CBD6C18B35108A350B0D1934738F77718E885C38324F373859A0E2F6D20D00000007408FC401FE1C5E070718C073829FB1CDEAEED9C4C8DDCEBEC0D6E1EAE0B3713F4279ABAFB4BFD0CDCDCEC2985400000024729EB9BBBAB6994C07083D89B1B0AFBCB5B57721000D5B9EB38E9DBAB060060000003D98C3D4C8C6BE872D000017579FC9D8D7D4BA672902004198BAC9D3D4C7BA79160000003F92BBC1BBB9AEA5642E0200045078A4BABEA979250000114C8FBDCDBDC5B8A87E5857545078908288AEC3A66C2A080A142114007877612900000001002A73ACC8B7814901000000074994C4CFBD9B6E4F21130D1F448CCAD6C08D490F923C170D0528688F797A95784D3628373D455C9EE4F0D901000000074994C401FE1D5E070718D07E8798B5C7E4E6C7BAB6D2C2B4C4D9EBE9D1B060373C6792B5B8C9CCD6CAC0BEA14B0000002872AEBCC2B8B19B4D111A468EB1BAA6A7AEA75A12000B579BAF99A1B9A7580000000049A8CFD1DAD2BF7C2F00001E5A9EC7CDD3DDC4762B07064E9CBBCFD3C7BCAB7115000000429BBFBBB2BCBAA46B2D0100024384A3B2B7AE712300001B4E92BCB7B2B8B0A27C585044517E918D8A9DBBA45726151A182013007E82623000000000002F78AEB5B37F3E00000000074794C5DBBE916B411C180C1A4295CEE0D19946138F2F0A0B0625769D888794744E3731403736549BE2EBC800000000074794C501FE1E5E070718E07689A4BFD7F2E4C6B2BFD3BEB7CBE6F6F5E6B46230336393BCC2C8DBD5D6CBC19C490000002567A9ABA3A9B89C4F14114492B9B9AFB8BAB26412001161A7B3979CB1AA5D00000000479FC1D6D0CDC38D2D00001C64A5CADBD3CAAB6F2506094B9DBCCBCDC4C3B9751900000049A4C3B7AEBAAD975C160000124988AEB7B09E69240000135596C4C2BCC3BCAD8357534B578397838E9DAD995F201A1E261500007F7E622900000000002A86A7BCAD82480B0000000E5397CCDBC19C6E341917091A489DDCD9C28943139033241A0A37809E84878E7B4F392A3C323B5EA8E2EAC00B0000000E5397CC01FE1F5E070718F06C8193BCD5EEDFB5A2B4C3BDACD0E4E8E9E5B15430305F91B5B7C0D8D3C6C4C5A3490000002F74A6B4B4BCB3913A0E0F3C8DA8A8A6B4B2B55A15001769A7B69FACC1AC590000000045A0CFDCD4C8B27B1D00001C68A0BAD5DFD2B26C24000754A9BBC6C8C0C3B16C0E00000047A1BFB6ACBCB89C5C280200175E95ADB2B7B074130000234E97BFC4C5BFC09A7D4E474053859F8182A0B6AD6B322220171403007B80612100000005003481B3BDA47E4101000000125396C3CFBE89633A130301144D99D4E2C1904D149A340706002B75A0888A8E744C322941363663AEF0EAC401000000125396C301FE205E07071800738DA4C1DEF3D8BCA5ABBDB3B0CCDAEBE8E3B25D313A6395AFB3C5CFD3CCCDC19C4E0000003A7FAFB3B8BCB99441090E4C95B3BFA7ACB8AB5A0D00146BADAFA3AEC2A453000000024FA4D3DAD6CAB7751D00002768A7CEDDD9D1AE6222050B4A8FC2D0D6C2C4AD6E180000044AA4BDB5ACB9AB904E1D0000155786ACBEBAA9751D000009579FB6BFBDC3B6A48055493B5586A1948BA5BBA0612F1D2522200B0081785D230000000000307FA6B7A77B3C00000000094F9DCBCAB598612F14000F1B52A0CEDFC685380B9A2B0908143880A498958D724D282B3E3A3A5EB5EFEBBA00000000094F9DCB01FE215E070718107387ACD2E1FCECB7A7A5A4A2B0DAF0F1EFE1AF59292B5795B5BCCED3D9CDC2BB98430000003286B4BCB5B4A8863A050C4699BFB7A2ACB89A5D1C001C6FA8B4A6B1B79C460000000252A5CFD2CECCC67B1E0000216EB2C8D6D6CCAE641B030E56A2C4D2CBBFC1B560090000095698BFC1AEA7A690521700000E589AB2C4C6A975210000155592BDC2B3B9BCA7784E40415F929E96879EB9A7603B2D2E23150200897B681B0000040B014A7FA6B9A8843E02000000135299CED0AD8A602D140606184F9AD9CEBC9045149D3E0A0C0A358AAC95949579432F2E43383E64B5E5E3B302000000135299CE01FE225E070718206A7EA2C9D8FADDA8908EA59AB3DDEEEDE7DFAA4D262A558BBEC3CFDED7D4C3C193420000003980B3BAB2BAA3782B01084494BCC1A2A0AF9D5C1A001C6EB0B8ABBBBA9D4C0000001064AED6DDD4C9B86C1D0000266DABC7DFD8D1A7603217114FA3C3CAC9C1C7B4631200000C5BA1B3B4AFB6B89244160000126B9DBDB7B9AF72180000105594BEBCAEB8B8A676473C3A5C8F9C9A93A4B9A45E3A2937311702007C71490800000000033B7FAEB4A57D3800000000145DA0CBC2A9835A30150C141F4F9DCDD8BA8A3E1DA238100B0E3586B09A918C7351262438373E70BEECE6B200000000145DA0CB01FE235E070718307592B5CAF1FFEAAE97A2A5A3BBDDF3ECE3DFA95321285B8FBCC5C5D7C9C5C7C7A2450000083F89ACB2BAB4A97A2806134A9FC3C5A0ADB6B05B14001870AEC2B3BCB9943C0000001564ADCFCDD3C7B2691100002878AFC7D5D9CEA45614040958A0BFC6C8BFBFA9590C00001266A7C0AEA4B1B39554130000185C9AAABDC4B4731600000F559EBEBFBBBDC4B4724731395C90A38F93B1B6AC60413F3D311B0200746A511000000000003E7EA7B79C7833000000001867A7CEC69F755C39160811164F9AC9D7B6804214A13A17060C4089AF9E9290734A212743353674C1E3E7AD000000001867A7CE01FE245E07071840718EAFD7EBFAE2A690899E98AFEAF2EDE6D8A1551B1A4582B6C9D0D3D7CECCC899400000043C91AFC1B8B5A9752900135298BFB3A09CB9B65E0C002881B2BDBCC1C0A247000000155FAAD4C9C6C3AC6B1200002774B0C5DCDACC9D5B1F071668B3C4C8C4BCC0A6570000001B62A8C2BBA7B3B190460D00001B6B9EB9B8B4AB691400000F599FC7C1B3BEBBA7724839315C95A99E92ADC3A56A484045332001007F714A0400000000024189AEB89E773E0000000015679ACECCAB735632160C1322529FC6CCAD7D330C9D38130F18448FB5A292816E41292136374A7DC5F3E7A80000000015679ACE01FE255E07071850708AAED3F5FFCFA58C8F9097B1E9F4EADCD49D4D212B4E89B5CED4E2D6C3BCB6963E0000084E96BCB8B2B09E69260710579EC0B4A4A1B5AD6116002C7EB5C4C1BEBB973C0000001364A6C6CDC7CCA55C0500002D7BB5D8DAD9C69E4B2009105AAFBDC2BFB3B6A5550000003672B2C1C0ADB7B58F440800001E6B9DB5B4B6AA731E0000205D9EBBC0BDC1BDB0774325396289A79C98A3B9A466564C47331900006C67430000000000003D91ABAFA9792F000000001B6CACD2C69E6D4319090D07225AA6D2CEB078471CA4320E0010429DB7AB98845B2C1C293434428FC8F3E7A2000000001B6CACD201FE265E070718607FA4CDEEFBFFE0AC9593898CB3DFEBECDFD89A502B274A88BAD1D1D2D0C4C3CA8F3C00000A4A9DC0C4BAB59E661C011852A1BCBCA4ABBEA04E10052482B1BFBCB9BA93420000000F6ABAD5DAC6D0B05F0A00002D73ADCBD8D5CC924C25001066A8C5C3C7BBC4AD560000002572B4C5C1A7AEAB8D320D00001369A6B2BFBEAC6B170000155895B9B5ADC2B9A875352B366CA0AAA19DAFB49C634E5159461B0000776D470000000000084386ABB0966E39000000001E68ADC3BF92684F2613130E1B509DCECAAA7B441DA13F240D1750A3C2A5947B503124273B484E8FD5EFE8A2000000001E68ADC301FE275E070718707293B2CDEEF6D69B7C808289B4E8F1DFD9D7974C1E264683BECEDED6C7BBC4C0862B00001458A6B7B6C0B1935E1100124B97B8BBA7A5B8A95E1507358BB7C1BABDBD9433000000136AADCDD2C2BFA1550400003086B6CECED2C8915020101668A8C8C6D0CBC79D430000002A7EADCEAFA8B5B78D370300001669A2B7C5BAA8661D0001185E9FBEB1B0BAB4AD683A2E3469A1B79F9DB2C0A46B585E53431B0000745E36000000000000448DA6AE9D6837000000002070AFCFC1966041210C1111195CA4CEC7A5713C18A83E181C18529EBCB2947D582F262E373D4B8FD3F4E0A6000000002070AFCF01FE285E07071880778FB9DCF5FDC89887808078B8EEF7DFDFDB9F4A1C153E7CB4CFE0DFC9B9B9B5892F00001D5B9FB3AFB3AD976428000F5CA6C7BBA6AAAB9E5714003C82B3C2C2B4B691350000002A6FC0CCC3C0BD9E500400003375B6D1D0CAC38A3F13081E72A8C4C8C9BDBA9D450000003183ABC4BEB8ADAB82350C000014699BB5ADB6A3621000002469A5C2B1ABBEB8AC6F2C253568A0B4A39AB3BDA17061646C4B1E0000706738000000000000468EA7B4986626000000002565AAC8B78E6645270A0A1E2160A7DAD0A1773D09AA3818161A4996C4B59C7B5D331F2A3A464B92D8FEE7A6000000002565AAC801FE295E070718907794C4E2FBFFDE968C847B83B6E8F2D9D6CF9144191C3C7DC4DBEBECCDBBC1C2842C0000145EA5AFB3C3B99B5315001552A0C7BBA6AFBDAF590B0B2E83B9C6BEBFB4912D000000267AB4CFD3C8C79A520400003887C0D2D1CCC07A381A0C1D74B3C7CEC5BBBC9E430000003980BDC1B8A5B1A6813D0700001F719EB7C2BCAA610C00000E5E9CB6AEB8C1BAAA6E352E3B77A5B8ABA7B2AF976C646E60421E0000745E360000000000004292ADB1906421000000002471B4CDB78A5A47280E13191C509ECDBC976E3D1AB84E1D0D114F9AB6AA8F704B35222B3C4858A1DBF7E29D000000002471B4CD01FE2A5E070718A072A0C6E5FDFFCA93827D7D82AAE5F2DDD7C18A491714437DC5DDF0E7C7AAC0AF79250000256DA4B4B7B9B4934F15001658A2B5B39AB4BBA158160F3C86C0C5C5C6C197340000002B82BCD6CECBC19B450000003781B4C9CFD5C27F39180F2376B3D0CEC9BEAA8D3A0000024B8EC4CAB2A1A9AD7E23000000186FABBEC2BB9E5B1E0000256EA9BBAFAFBABBA7652C1B397AA9B0A9A1B1BBA66D74716F541000006D5F38000000000000508CB5B8925522000000002B76B0CBB47F5A3B1A01011A2564ADC3BE9C673917A14515191854A6C2BB94724937232F3F4962ABE1FCE5A0000000002B76B0CB01FE2B5E070718B07199C3D9EFF8CA8D817D787BAEEFFBE2C7C0873712173783C4D7E5DBC2AFBBAF772100002A70ADAFB1BAAE8F4C0900104F9EC7BBB6BBC1A24F100D3C9AB7C2C2BFB78C300000003B94B8CFCBCBC68A3E0200003685B8C5D4D1BE772E1A0F247CB5CCD2C8C6C39D3D000009508AB5C2BBA0A7AB7727000000116FA9C0C1BDAE5B0C00001B63AABBB2B5C9C6AF6C26153172A8B8ABABB3B49971778076551400006C5A370000000000004584ACAC875B2C02010000297BB5C5AC7852351C0513121D5CAAD1C692572F21B13E231A1B5AB1D1B58F72492A1E282B3A6AB1DEF9DBA002010000297BB5C501FE2C5E070718C06C9BC3E7FDFEC58F7F746D6CB1EBFADCD2C17C3513143083C1DEE7E9C3B0B9AF6A1D00002A6FB4B6B3C0BD95470A01205499B9B5AFBCBDA7560D0C3D93ACBFBFBBB38F260000003889C1D0C9C1BC8D3A0000003889BAD8D3D4BD752A120B256FB7C6C5CBC2B89E3600000D4F92BBC4C1A4A3A674280000001F6CA7C5C5BCA6561100001F669EB8B1A4AEBEAF5A2D1A4686ACB4A5A7ACB79476707D80591F00006654240000000000004A89A8AA905529060000002E7BAACFB8884A36201111152F6DA7CCC58C562110BD460F111B64AABFB5865B472831333D486CB0E9F8D5A0060000002E7BAACF01FE2D5E070718D0789CC9E1FBFCC289827E7075ADEDFEE1CECD85411917427EC8E2E6E6C9A6BCB3671400003285AFB2AAA8A384470B001359A3C1BCABB2C0A35015124795BCCFCCCAB8832C0000003E8CC0D8D1CEB8812E000000468BB9CFCCCCB574240D062B7BB6C7C2CAB9BB973600000E5293B9C6C4B2B4AD781E0000001C66ACC0BBBDA55D0E00002564AAAEA3B2BEBFB1692E1B417CACBAB3A7BBB49D7B7F7B7C5617000074522E000000000005548FB2AB8E5015000000003787B2BFAA804F361F0F0E0D2A6DAECFB8865C3A15B2451C122064A8C7B2845B3D28252D3C547CB4E7FFD886000000003787B2BF01FE2E5E070718E0719EC6E2ECEFBD7A6E6B6269A4E0F4D6CFBC7B310E0A3484C5E0E5E0C4B5BCB2632100003986BEB7B0B6AB7C411002155C9DC2C5A9B7BBA04D16144895BAC4C3BABD82280000034A92C4CCC3C2B283310000004393C2D4DAD1BF722A07082876B2D0CCD1BAC3992B000012619ABDC3C0A69AB06E210000001B6DA2BCBEB5A7550900002267A7ADA39DBAC2AD63211C458DAFBEB3AFADB4A0808293846212000070552C0000000000005697C3AD8C531F000000003C83C1C7B383483116010B142E70B7CBB584522F1AB43215161D5CB8CBBF835B412E252D375981BDE5F4D88E000000003C83C1C701FE2F5E070718F0768FC0DFF8F7C089716E6477ABD8EDDFCBC1783312153282CED8E5E0C6A5B7AA5F1600004C90BBB4ADB4AE7E3702041D589EC9C5B1B1BD9A50191A5390BDC4C5BEB07B2E00000A58A1BCD5C8C5A97E2E0000003E8DBED1CFD1A360200E08297FB2CFD5CABAB9953A00001E70A5C0C3BFB1A69E651D0000001979ACBDBBBC97520B00002467A1B1A397B5C4AD642616408CB9B7B5B3B6B4957D828D885C2000007258370000000000005795B6B78E5818020C02003582C1D8C1804D34151111232C74AFD0B47548301FB54213151B60B5CAAB784F352B2E35395D7FC8EDFCD993020C02003582C1D8 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 61440 61440 0 01FE305E0707180075A0D7F0F2F8BC8776725F6FA2DCF0D4C8BB742F12183A87C0E6E4E5BCB0C0A9621300004A92BCA8A5B5A673350800165592CAC7BBBDCAA13D0C1051A6C6BDC4BBB1792500000F58A8CCC5C1C6AA761F000000438EBFD2D5CDB65E2601002684BED0CFC5C2B59D3000001A67A4C4C7B8AFA5A166170000001475A8BCB8A899591500022D6EAFA9A39BB3C0A85B1D154388BABEB4AFC0BD997A8A8D916817000079623B0000000000075099BCAB89562907070003398FC0D1B279483720090E192E7FB0CCC27E4D2C0DAC401F1E2B67B0CCB37D4931271F2D3F6391CBEFF5DE9407070003398FC0D101FE315E07071810769FD5EBE8DEB489856D5865A4E0F9DBC8BA7426020F2970C1DDE4E2C2AEB5A25A1500004E91BEB7A4B7A4752E0000115CA4C5C4BBBEC799430F0D509EBFCFBFC0B5802100000C68A9C3D8C9CDAF751A0000004D92BCCBCDCCB45C200B062D83B5C5CED0C1B988240000296CA9B6C1C0ABAB9C5D120000002176A5BDC3B596480F00063576A0A19C91B5C1B75D2016448EBABEABABB6BDA1908B8C8063130000715F2D000000000000579CB3AE854018080700003F8EC6CDB3754932180A1325357FB5D1BF7644271EBC451B172674BFCCB6734C3A2A1A24436B95CFF2F2CC86080700003F8EC6CD01FE325E0707182080B2D9E7F5F4BA8B7D6F636CADE0F6DBCEC0692C0A0B2E7BCEEAF1E9C2A6B39F5A0C00015D97BDAFA3AFA169270000195BA4CED0B8C2BD934716245A9CC2C5BDB8B0771C00000B61ABD1D4D1C5B36D19000000488EC4C9D1CEB35B1D0B0E2B84AFC7CBC9BFB7903200002A71A8B6BFBDAF9F9C690D0000002174AEC7C0BC995016000A3077A89E919CB3BEA35E19184496BBBEB5AAB7BD9C878A958B681A00006B55300000000000005198AFA6804C130004000A408EB9C6B17F47421709181C3578B3D0B16F3C1F15B8441D17276AB6CEA8784A2F2B22263D6D98D7F2F3DA8E0004000A408EB9C601FE335E0707183078A2D1E3EEE7BB7F7D725E6CACE5EEE2C9B16826050D347EC0DBE3E4C7B3BB9B4C02000158A0C6B7ABB89F642300001355A4C0C9C6C8BE99400A1B58A5B9C7C1C8B676170000186CACCACDC1BBAB65120000004EA1C4CBCFD2AC601C140E3385BDC3C8C6B4B37A2D00002C7AA7BCCDBFA6AA995B110000001B79ACC4C1B2994A04000F3879A8A28888ABBEA65D2D244F93B3B9B0B1BABB9B8E939B966F2400006E55290000000000055DA1B9A5753E150002070C4887BCCAA7704432180F1C204286BFC4A4682D1E00AD472D242E70C2CFAC694626292C294071A2CBEBF6D48E0002070C4887BCCA01FE345E070718406AA0D6E0ECE1A37F846F5A68A2E0F2DDC7B26F2C14113280CBE7E8E6C1A5B6A15100000667A3C5BDAFAD90611F00000E4EA2C5C5C1CBC8943A0F185A9DC5C0C7CBAA640F00001775B3CCD2D0BDA966110000004096BDD2D6D0B752190F0A3586C0D6CAC6BCAB832700003286ABC1C3C5ACA1965D0D0000002377A8BBB7B9A1450E000B337CADA3848CB1C2AA53171C579CC4C4B1AFB9B79F8C9F9A98641F0000624820000000000000509BA8A4754112040000094A8BBDC8A4714A301C0E121E3C83B5C9B27B3D1B15AE421C2A316DB7CDAA7335332E27353B74A7DCF3F5CD7A040000094A8BBDC801FE355E070718507A9ECBDBF0E2AE7584736069A2DCF3E3D0BC702702072C73C4D9E6E8BEADB797480300125DA0C5B1ABB298602300001B5AAFD1C0BCC9BF9139041A66A2BED2C7BEB46F0C0000246BB0CCD4CCC4AF6411000000489DC4CED6CCAF57180F0B358BBDC4CACCC2B4842C00073983A8BDC1C0ABAA9255150000002471B1C0BAAD96480C000F37779F97888AA9BAA852222259A4BDBCB1AABCC2B092A496936A2000006E44230000000000005399ADA8763410121600094C90C2D6AF684534170A11234385B7CEA9663A2015AE40181C3176BECDA366352F322B314778B1DAF1E6C28C121600094C90C2D601FE365E070718606E9CC3D4E7D89D797C6652679EDBE4D9C6B163220912347FCFEAF0DDC2ACB28C4400000A65A1C7BFABA892661E00001351A5D1CCC3C3C896370E2066A7B9BFBDB6AA67160000237BAECAD0D2BFA7630C00000152A0BBD6D4CDA348070B0C277FB7CEC7CEB9AB852600004090B5C0B9C4AAAA98530A000000237EB1C5BFB98F440800093676A89B787FADB49E4F19205BA5C4CAB6AEB8B7A4989A9E97701B000068461B000000000000619FAEA372340E060C08094393C4CBA76E302318141628528FBDC7A26D331A0CB346211D2376C0CA9F63392B241F334782B5D9F0F2C980060C08094393C4CB01FE375E0707187076A9D4DAE7DEAA7876694B5E9ADBECD9D1BB6A1F0F0D3070C6E7E3ECC7B5BD8E3503000E77AFD0BAABA48952120000144F99D1D6CCCAB987300B27669DC1CBC4BDAB580900002378B8CCD7D5C9A554100000004B9AC8C9D1CD9E42100E123683B8CACCCCBBB9772600003E8DAFC3C9C4A9A18B49040000003182B5C2BBA88E3D04001A3E81A29C7D7FA6C3A1511C2259A3C3BDB3B3B9B9A29CA19C9B6D1600006950300000000000146A9BB5A26424040914130C488EC8D3AF702F2F1A0C191F388BBABDA166341714C04B1E25307EC5CBAA5E34262F2F2F4B8BB0D7F0EBC27F0914130C488EC8D301FE385E0707188079A5D6DCECCAA08182695A5C9BD3EED4C5B3621E08052978C5E5EBDBC8B0B18D3300000D76ABC4BEB7AA8B5B1A00000C4B9CCFCCC6C9B97C350E2472AAC4CABDC5AB5B0C00002F80BDCFCECAB9A15B050000004997C4D2D4C7A247190B162A85B4BBC6CAC1B7801D00003D90B4BECAC9AC99894C02000000347CB2C2C2BD903906011B467996906C7EA4B4A3581F2A5D9ABDC9BFB0C4BBA997A5A99E731B000075542600000000000160A1AE9F612A0A03040315549AB8CFB081433429161A294D8CB7C29D6C2E1B0DB4452027397ABCD0A45F2F262F2A324886B6E2FFF3CC7D03040315549AB8CF01FE395E070718906CA5CCD8DFD89F76796B535D90CDE3DDCEB1591B05032D85CFE2E6EACAB8B8833400001670B5CBB7ABAA88451700001052A9C7CECAC6BC8B340D2468AFCAC5BDB9A9500800003089BEC9D0CCC4A4580A00000454A5C0D0D4C19441100A062F87C3CCC5D0BEAE782100034A93BDC4C4C3BAAA8A3F00000000377EAFBEB5AB7F410B061E4083A2876A7BA2B3A54D18266CA8C2C6B8ADBEBBA8979BACA4812E000063431300000000000066A2ADA46A340402050011609DD1D6AE663C2F20141B27448AABB5985C33160FB94325233489CFD6A7593015242738528FC2DFE5E6C07902050011609DD1D601FE3A5E070718A080A8D3E3E8D4A2858767575696CEEFDDC7BA642204002275BDE3E4E5CCB6BB7B2E03001872B6CFBEB2AC81461100000C5298D1D2CFCCC688330F2973A9B6C1C4BA9B520800002788C5CCCDCFBB9D4E0B00000C58A1C7C9CAC597440F060A3098BBD3C9C5B5AA7013000E5DA4BEBAC3CCB9A58D41000000073184BDC7C0B37D3300002050859A866074A5C8A14214286BA5C8C9B1B3BCBFA79B99A0997C220000704A2300000000000C63A5B79D662F0A0708050C609FC1D4B16D392E1B1F202A5798C2C19A61341414B25D221B2B77BEC6984E341A23273F5693CEE8F1DFC3710708050C609FC1D401FE3B5E070718B06990CAD4DFD69672785F4B5187CEDDD1C8B3601A02002575BDE2EAE1C9B1B1822D00001684BFC1B9ADAA8141060000144E9EC9D0C2C9BB7B2818347FAFC2C4BCB99746080000388EB7CBC5C7C79E4E0000000456A1C3CBCEC39C40110205368BBBCACDCAC1AD681B00044FAAC3C1CBC2B5AB8B3E010000043A88AEB9BBB77C2C02022250889C76616A9EBBA551263371B4C7C9B6B4B3ADABA1A2A09B752800006E5B260000000000025FA0BBA2662D100809161B5CA2CCD4B0663428231720305D96B6BC995827100AAF3F1D20398CCACEA75D3214222C355D95C8E1F0E7B7720809161B5CA2CCD401FE3C5E070718C0779ECBDFE5D098847A60415291D0E1DFD2B3591D09002A70C4E1E9DEC5BBB3803000001885B8C3BFB5B48338040000084A97CCC9CDD1C5822C122D7AAFC4C1CBC59E500300002F8DC2C6C4C0C5AA56050000085EA1BDC9D4CA8F3C0D050B338DBACBD1D3C8B66F1000075DA1B8C3BBC5B19E7631000000003B8ABBC3BDAF802B08062551838F785E6B9EBA9B4E192D71B9C2C1B7B8B9BFADA5A99F9E7229000063471C00000000001162A5B39E652A080504081F6198C0CDAB6B2F2C21292830639CBBAF8E4E1C120EBE4526263A8CC7C59F592C212B24455587C4EAF1DBBA720504081F6198C0CD01FE3D5E070718D070A7D9E0E7D99C8B836A545A92D2DFDFCAB0581E08082E76C1E0E3E1CAB9B17E2900001C85B3C3C4B8A97F380C0000105293D0CEC9CAC484350E3179ADC3CDBDB79D450000003891C0D5CACBC29D400000000C5E9FC2D1CBC592350A040D3782BEC6D1CFBDA66A15001660ACC3D0C7C7B2A78430000000083D84B6C4BFB1732700031D5892A0775A6F9DAF9B55273176B5CDBFBDB9BCBAA7A5A0A39878280000654B1F0000000000116DAAB39B5F190A07020B1552A5BEDAB56F372C251A2E3E639EBDC0955728100FB844281D3B85C7CCA4542012202C305093D1FEFFEFBA7007020B1552A5BEDA01FE3E5E070718E078A5CEDDE2CA957D8462495B8FD0E8E4D0B05D1C10021F79C0DAE4D9CFC4AE6C1D00001C8ABECEC2B4B083340400000D549DC4CDC7C6B770220F3885B9C1C2C2B192430100004293CED0D3C6C7A450000000074A93BECBD1C8963A090C0B3989C5CCC5CBBFAC6917000C57B1C1C2C3BEAFA48934000000064786B1C3C2B1803C0300315890906F5A6697B9953C173076B6CBCCB1B2C2BFA5A6A8A69C712000006E4D28000000000011679EAE955920000100051E67AAD4DAAD6D36332F25232C598FBBBA8C4D201010B0451D233D94CFCD994A2121362C304899D7F1F4DFB06B0100051E67AAD4DA01FE3F5E070718F0739EBDD4CEC789747D5C435994C9E2D2C8AF602607001F70BDDEE0E5CEC1B76D1A00002280BDC1C7B8A472310000001251A7C7D2CBCEC27C2C153B8BB4C1C8BDB88E37000000459FC1CCD0CBBE9A4C0200000B52A5BAC4C8CA8D3B0B02063B89BFD1C5C6BAAB651500165FAFC1C1C3C5B3A47C3100000006478CAEC8C2B9772700012C5C8C8B6E4560A2B9974D1F337CB5C3C5BCBCBCB4A8A0AAA19A72240000664E2000000000000E63B1BBA96026000000001B68ABC6DABD712F252E27213769A0B5B99A54190706AE48202E45A2C5C69343241D2D21284FA4D7F0F4DAB7680000001B68ABC6DA01FE405E070718007890BDDADDCA8D7F8060405189CAD8D6D5AD54160300186ABAE2E4DED4C4B3671A0000208BBBC7C7BDB26D2F0200000C4A9FD3C5BFD2B57A30143782B8BFC9C6B694340000004A9DC6CACEC9CC9849050000155CA3C9CFD7BE8E3C07080C338FB8C1C8CBC1AE6908000D58A4BEC8C2C3B0AB7D280000000A4E8DBCC0BAA35D190008377392936F4E6297AC874711357EB3D1BCB7AFBBB6AFACA89F967928000066360500000000000B6A9FB992591D0A0C0900247BA8C3D5B372322B33202A396FA1B4B68D4D250B08B13A16194A97CAC19449191A2628325CA4DEF7E7D5A7680C0900247BA8C3D501FE415E070718107BAFCDE1E6CA9781886548538BC0DCDAD4B6562702002469C2DFE1E0D9CCB1631300002688BBCABDBAA979270000001152A5C9C9C6CBBC7728103E8EBCBFC3C0B68D3C000008479EC7D2D6C3BB8D49020000185E9AC0C8CEBC8631120B11308CBDC4BABFBFAA5C0900176DB4C3C4CAC3B6AC7C2D000000185299BABBCBB2651500123A6F8F9566475E9DB3924118397FC3C3CFB9ADB5B4AB9AA1A6A0771F0000663E0E0000000000156EA3BA995515010400031464ACCED6AD602E2C371B253777AFBDB57F441E1006B3432124519EC6C08C45262027253157A8DEF4EAE0AF680400031464ACCED601FE425E070718206DA2C7DAD7C094828A6B4A5384C0E7DFD1B05E2002071C6EBBD3DCD5D6C7AD620B00002188BECDD0BFA772260400000F549DC5D0C8C7B477291A3E87B1CAC2C0AE80310000135CA6CDD0C6BDB7A748000000135EACC6CECDBF882E08000D3B8DCACBCACDC59C450200206EB2C0C4C6BFBAA87D280000001A518DB2CBBBAF651C000B3A709B9562445693AA873C122F8BBED0C5BDB5C5B3A5A9A7A39A6D2600035E441100000000001876ABB48F4E1C070000061E6DAED0D0B4692F152E2E304476A7B9B58745190209B15124234DA4C8C38F4A20132D2D284695D3F7F2D0A2630000061E6DAED0D001FE435E0707183079A2CAD6DCC78D7B8D69444D8ACDE1E2D2AE571D0B012B75C3DDE6E1CCC4AA5D0A0000228FB5CECBC6B780290000001863A3C5C8C5BEB4702E224688B0B9B9BDAF843200000F5BA6C1C1C6BDBDA74F0000001768A7C2D1BFBF8635070B1A3691C1CCC9CEC29B5205001B6DB3C8C2BBBAB3A4701D000000215896BFC9B6A76118000E4476A18D65445797A882371A3688BDCCD1BFBABFBAB3A79F9FAF75210000603D1000000000001373A5AD874510000000092B72AFD4D0B76D332C39322B3C72ABBAB1824108060AC0461B214E9BC4C38348261F271E2A5EADE2FFF1D39F5F0000092B72AFD4D001FE445E070718407AAECCD6E0BC7C818E60435087C8DAD8D7B254200C09297AC2DDE1D0D0C6A45E0B00002487B2CECECAB27C20000000114DA4C7CBBAC2B6702E164296B4C4BEBCB0802700000D52A1CBD4D3C6BB9C4900000017649AC4CBCCC4863A0F00023891BDCECBBEBA984C0A002079B8CABCC0C5B6A071180000032867A0B7BEBAA2611D0319507F988357415E9DB18B3317348EBDBFC2B9BCBDC8AFACA394936F1E060A6C3D1500000000001477ABB386521000020508226DA3D0E1B46E281F2D292B4577A5B9B37D3610040DB4431E2A62ACC3B2813D27262A2D2558AEE0FFF2C89355020508226DA3D0E101FE455E07071850749EBACED5B98274835F41518EBED1D0CEA953180B041C65B2C9CED6D2C4AF5A0100002190BECABFC6AF71210000001054A1C1BEC3CEB87028214D97BDC4C5C2B0772A00001A51A4C4CFBDC7B8964100000022679DBAD1CAC38C2E0400083F8CC3CFCDCCC0924503002474B7C8C9CCC9B4A1701C0000002C619ABBBBB8AE641900164C7EA3915331598AA87E3824498CC1C9D0C1BFBBB2B0A09F9F9C731B000D643A0C00000000002280A7AD8A4C0C000009102571B1CCD1B6752B2838362D4976AAA0AC75340F0C0FBB41242C5DA0BAAD7E422015272B3866B0E8FFF7CA94570009102571B1CCD101FE465E07071860799DB8D7DABA817B7960464C8AD2D9DBD3A65C2A110B1F71BDCED8DED4CCA0480400002287BBC8D1BEAD70210000001254A6CCCACBCAB56D1F164A99C3C7CABFBB7A1E00001761ADC8C9CACAB6983F020000216DACBEC6C0B672240703134486BCD0D3D2CC9C4D07001A79C1C8CCBEB4B2A171100000022967A3BBC0B09F541500194F92A79A5D3A4E8CA2762D133C9BC1CDD2B8C4B7B8B1A5A6A09B7422060C6A43090000000000277EAAAE904D09000006092C7AB7D1D9B26C2321372E2C517FA7B8BC813A0F090EB34D1E2A5C9DC5B4763B221723203162B2E5F6E7D495510006092C7AB7D1D901FE475E070718706DA3C2DED6A97E748A613E588DB7C7D3D6A252180C0C1D62B3D3DBDED5CDAA480500002A96C2C7C0BBAD8025000000145EA1C1C3C5CBAD671F184F8FB5BEB9BEA8762400001B67AFC8C7CAC2BF9B44000000236DA4CACACBC1812D100A163D8AC4D2D1D4BC913D0200227ABDCEC7BCC1B19E69160000002B6AA4BCD2BA975A0F00205190A488573F558CA06A2C173A90C0CAC9BFBBC2B2A4A29CA79E6C230C17572A000000000000126FA6AE7F3700000308082670AECBDBAB692A1F3D3B335284ABBAA974360E060EB34C242D5AA6BEB4792C1F222929305FACD7EEECC086560308082670AECBDB01FE485E070718807391BCC7C5AD81777D50454B8AB8D3DACCAA57241000196BB2D5DDD4D0C29242000000298FB8C9CABBB27522000000165EA9CFC7C0C3B672281A5395B5C3C2B3AB781600001A6CAAC5C2CBC7B8923F000000256AA5BECECFBB732203021A4281BBCAC7C1B7954100002886B8C9D4C2BCABA06F170000033672AEC7C7B79F4D0D0012538EA28B5B32508A9A6B271A4899C7CFD5C5C2C7BA9FA3A79C9A6A18021057350200000000001A74AEAE7F420E00070609317ECBDCE4C07023192E0F29548EACBDAE752A00080FB34A232A60A2B8B37C3A1F14181E3C68AAE4FFF2C58F51070609317ECBDCE401FE495E070718907CA6B8CED2AB7B7D895F3B4682BCD1D9CDA94A2112071B5AAECDDFDFDCBE8D45000000228BB6D3CDC5AE721E000000195EA6CBC6C3C8B0631E225C94C1CCC3B8A96E1500001D6ABAC6CEC5C1BF9F3D0000002B75AAC1C2C6BC772C040A11448CB6C1C7C9BD923F02002672B0CBCDC2CCBDA66B180000073A71A6C0C4BC9C5115001D6797A9894F3354888E6A25194B9DCCCBC7BEC0C6BCADA2ACAB9E6E1C05135E3800000000000018779FB27F3900000003112887C8E8E5BA6321243239365C93B4BEB77226080105AF411E2468A0BAB4743115171C222A63B0EAFFECBE7D4F0003112887C8E8E501FE4A5E070718A081ADBFD4DFBB7F7985593A4F8FCCD6D2CDA8503323010D5FB3D7D1D1CCCB983E0000002C92C8CFC7B9AF6F2A000000126BA4CCC3B4BAA4631B14579AB7C3C2C0AE671A00001D6AB0CAD7CDC8BD993A0000002D76AEC5CEC5BC772B0112174F8FC1C8BFBDB48C3200003087BABEC4C3BFB19C63170000114179A2ABC5B6A9510500236794AB8D50365285985D2218479BB6CCD2C5BEBFC0ACA79B96986B170D13592B0000000000001C7AADA87E3A08000000032886CBECE0BA682723453B395B89A9B9A9662D070009AB502A2C68B3BDA468321E1319273168B7E9F7E3B1774D0000032886CBECE001FE4B5E070718B07396ADBFC2AD6B6B7D4B395080BAD1D7C7A1481F1807155CA4C6D5D6D7CF993B0000001C85B8C6CED0B474230000001561ACBBC6CCC7A3621B235DA0CEBBC6C2A762160000186DB5D2CCC4CDC3933E00000D2F6FABBFC6CEBB7326120E1B498DBDC5BEBDB58B3500003384C5CEC9B3B4AAA06D16000001457EA5C2C6B3A3500B00215F95A4864F3C55839156211453A3C7D3CFC6C0BFB0B1AE97A29A701B121B65360000000000002783ABA8843A08000100012883C6E2DAAF64291F3935335B95BEBEB1742B09010AB44B282D66AFBDB070281916231D2D62B3EAFFEBB37A470100012883C6E2DA01FE4C5E070718C07BA1BAC6C5A57C7177583F5390C0D4CCB59A412C14061A62B5CFE0D2D0BA9132000000269DCAD9D0C2A76F200000000B68B0CAC2BEC0B26022205C96B7C2BEBCB6601A00001C6CB0D0D2CEC6B99A400000063C7EACC0CCD0B46D190109134993BBCFC5C8C1872B0000388DC2CAC5C2BEB89965080000155886A3BEBEB89E45090022639FB09051344E818C55120F4DA5C5C4C7B5B3BDBAB3A698A0966918011755240000000000002383A5A3823B10000000122C87D2DCD1AD5A242139392F5E8FB1BCAE782500000BB04F242F6EAFC2AA6C26171A221E3B6CB8E6F6E4B173400000122C87D2DCD101FE4D5E070718D07B98B5C3C4AE766D745237528EBAC9D0D0A65E2E1D06165DA4BFC9CFD0C19B31000000248ABCD4CCBAB474180000001768AAC7C9C7C9A15D1C295A99B0BDBCBCA46B1200001D6CB3C9D7D2C9BC89390000043383AAB6CFBCBC6E1E08071E579DC2C9C8BFC1952E00002F87BFC8C2BDBDB5965908000013558DABBCB5BA994706002671A0A88A4E394A808455141255A2D1D1CBBBBEBBB6A8A79C99996B240F20623E000000000000318AB5AC872F05000207143C93D0E9E4CB721F13383B43668DB3C0AC6B2F040807AC44263171B1B6A0632D231A25232F60BAEDF2E4AF76450207143C93D0E9E401FE4E5E070718E076A4C6CCBF9B756E7C523A5387B5C0C2BC944C291E0A195FA5C0D2CBD4C99737000000289DBBCAC8CEB1761F0000001969A9C3BBC1B8A15718215FA5BFC5C9C8A95C0B0000266AB8CEC6C5BEB89B380000073A84ABC0C8C5B85F1A00091C4E99BACAC5C8B2812300003891BED1CBBAB8B5A2680C000018528EB8B9B9B09B491000206D9CAA9156364E7E7048181B499FC3CACDC3C0C2BAA4A08E9D9B6E26142653260000000000003381AAAF742D00000000002B8AD2E8D9B569281B3B393F74A4BCBEA76620090610BA3D1D3072A6B7A35F31191F24252E6BBCE7FFECAD6B420000002B8AD2E8D901FE4F5E070718F075A3B9BDC5A07066774D335293B4C1C8C892522D22051257A0CAD0CCCDC28E3D0000002B92B9D4C3C7B678250000001969A9C7BBC5C7A558161F58A3BABFBCB59B580300002E74C1D3C7C4BEB4914200000D4581B7C3BFBCBA6F21130D1C5497BCD0C5BBB0812000003296C5C7C7C0BCA8905A030000266196AEBCB8B098410500266FA8B78E503645717A451D1953A6C8CFD4C8C4BDB2B3A1999C916E201A3168390000000000003283AFAB7D28000000010B3293D9E9DBB06726193D32416B9CBCBFB26A2206020CB2481E3574B4B292582A242426293E6FBCEBFFEEB25A4500010B3293D9E9DB01FE505E070718007998AAB7C59A706E784D2E518DBCC7D0BF8F4E34220B0A4D97BCC6CAD7CD88290000002E8FBDCCCABFAB67220000001364A9CCC6C2BFA45216206DAEC3C2B7D1AA5B0C00002D74B9CCBDCDC5B289350000124A8FB4C2C4C4BC6B25010827589BBBBDB5C7B2841A00003E94C4C9D1BEB3A6995705000026629AB0BDC1AC9D3E01002A739EB18C48334D6F6E390E1654AAC8D2CDCDBBC5C1B4A29D9F9F5F1717285F2D0000000000003689B099721D00000409133396D4E2D7B45E221A3D383D64A3BEC1AD671A000603A9421C3486B4B7965627151926223476C4F0FBD8A2653E0409133396D4E2D701FE515E0707181080A4AEBEAE8E70646C402B478AB5BFCDBB8F41291B040F6094BDCCC7CBC28D2E0000002898BECFCBBEB1781F0000001A74B6D0C5B9BCA0541D266195B9C1C1BCA1530500002F80BACBCBC6BCBC8F390000234B8CAABAB9BCA763200B1534619AB6BFC5C4AA701A00013F91BCC0B8BAADB09B5B0D0000306C89BAC6BDB0913F020029789CAD85523C4E686C42131759AFC4CAD6CAC4C6BFBCA68D8D986410142C672E0000000000002A80B0B17D2600000005093C96CADDD7AC641B1C3D444A78ADC5C0AA6C26000E16B3482C3A7DB1AD96561E1A14181F3E73B7F1FDDCA75D430005093C96CADDD701FE525E070718207696A2B7B691626E6A3C344D83B0BAB9B88F4A2F2908054C9AB5C6D1C9CC8223000000288DB8C8C2BDB3792B0000001770B3CFCCC4B89C5818207AA9C2C1C1B7964F0200002C83BED1D0CEC8C18F350000144287ADBCB9BAA6611F0902205C93BDCCBBB8B7761D00003E95CBC9C8C9C5B19E510200002F659BB1B7C9BD8E3600001669A6B595593B46615E2E101859AEC9D5C2C7C7BDB2B4A896A79B5F191335673B060000000000368DACAC7E2A0000090F123791D1E3DBA961181737384076ACC4C7B7701F030910B34B22388CAEB390561C182320253575BBF3FEE7A15A34090F123791D1E3DB01FE535E0707183076A0B7BABC9A6C67724C31478EB4C1BBBB9455321D011055A4CAD2CBD3C0842E0000002E8EB9BFC5C8AE701B000000217CBBD1CAC3BD9E4D1C2473A9BCBCB7B69F530600003076BED1CCCBCABB89360000245692AFB1BAB6A76923100F286998B5BAB7BAAE6C0F0000409ABECDC7C2C0AE9954030000256B9DB5BBC3B4A03800002A72A9B1864B3547645E381A1A5DAED3D0C4C6B9B2B2A99B969B9D5D1F1239612B0000000000002F86B2A86E2F080002000C399CDCECD7AB5E2225404A4F81B2BEBAB06B270F0E0DAD492C4775AAB0894C211519111F2F74C1EFFFE69F644002000C399CDCECD701FE545E070718407890A8BEB593605E60362E518BB3BEB8B48D49342F100D4D9CBABFC2C9BA88320000002995B3C5C9BFAF7521000000237ABEC8C7C8B19C460F2175B2CAC6B9B69F560B00003685BDC8CDBFBBB28A390000285A9FBEB7B6C0AB5614000B265DA4B7BEC1B9A2610F00004795BDD0CEC3B7B69E4C0000002F72A0B5C3C0B68D340000287CA9A88A5A3F4B605230121165ABCFD2D3CABFBBB7B2A08D98956120113C56210000000000003083AD9D70260000000A193993D7E5DCB164231537354B88B2C4C2B3712000010FAC4128488AB7AD864F1E161720304378C3EBFFDE9E5D3A000A193993D7E5DC01FE555E07071850748C99B0A38555585B36285087ABBBB9AB864B3C371512498FB6C5CAC8BE7E220000002D8FC0C5C4BFB1751A000000207DB8CAC0B5BB9748122477B0C7C8C0C0A6560300003388B6D2CFC7C2BC872C0000275C97A9BFC2BDA65F20020625679DB9BDBBC3A7611200004994D0C1C3B8B3A78E4400000028739FB7BABEAE80390000367CA4B7915646495944220A1555A9D0D2CDC4CBC3B4B29F959B956719204A612A000000000000338BAFAD6C1A00000008173E95CDE0D7AE69151C22384997B3C4CEAF6D25020A10A83E26568FB2AF86481E1918242D3365C3F5F7DE9D5B410008173E95CDE0D701FE565E0707186074A0A9B2B58D57595C39245293B0BABCB6864B34350C0A4788B8C0BBCFCA7B200000002C91C1BFC0C5B0812A000000247CB1D2C1AFB997461A276DA3BEC6BDBE994A0300003D7BB5C9CEC6BFBA9530000030599BB2BCC0AEA458150307316FA4BBB5BDBAA65E1000004193C3D1C8C1B2AD963C0000003F85A9BAB6C8B3862E00002D84A6B18B5B3A495B482908195CB9D1D1D2C4C0B5B6AA9A8E9F995F25194464290000000000003B8EABA567180000030715479DDAE7D5A6561A19384A5B8EBDCBC6B1601D000010AE442C5495B2B0843A1F1F1C1E203A78CAF9F8D28D5941030715479DDAE7D501FE575E070718707C97A8B5B38A5B60663F2E528EADB9BAAC88524032080C4696B1BFC0BBB184230000002795BBC3CDC7B57C280000003786B4CABAB8B891471C2A75A7BABBAEAFA14D0800024282BCD3CEC1B5AF80290003326E9DB5BABFB8AC551B03112B729CBAC3C1C1A86305000046A6CCD2BDB6B3B093480000003B82A8B4BFBBAC7F2300002785B0B08A5947505A3D1D0E156DBAD3CDD3CCCBBBA5AFA194948E5E232A4E63230000000000004C90AE9E65240500000324489DDDE0D2A6551413383A4D91BACAC5B27521000710B241254C8EACA5813E1F111A2A24397CD6F5FFD58A553C000324489DDDE0D201FE585E07071880778A99AAAA865B5254281E4D88A9B7B3A578443E31100F3F95B6C3C2BDB877250000003594BEC2CDBAAF731A0000002777AECBC7BEB88B46142C7DA2BCBABCAF974B000000408AB9D1CDBFB7B1782E0005406FA6B5BFB3B1A45E190D062D7AA7C2C8BFBAA355050000459EC1C3C6C2B6AB974F0000004986A9B9BAB4AE812A00003882ADB78E4E314646382000135FB5C8CFD2CAD4C7B0B3A28F9B92511A3057591B000000000000438CB5A465130000000016419EE0E5DBAB521A152C39538EC1D0D0B06B21081311AB40205997B8AD793D1B120E19222B78D0FBF9D596593D000016419EE0E5DB01FE595E07071890747C93B0A1764C445A34295583A4ADADAA81473B36140F4686B4C1C3C5B27E240000003098C0C6BABDBA80290000002787BCCCBBB2AF893F142A7BAFBDB7BBB1934B00000B498DBCC0BCB9B5B57C2900003983B4BBC0B7B09D521D040C367FA4B8BEB5B39D570B000043A7CECDCFB2B5A98A410000054A8EACB2BAB3A7751F00002E8AADAE90635450482C0C00175CB4C3CDCEC8CDB7B4AEA28D9B9E61192749551E0000000000004197ADA86113000000000D45A6E1E6D3B15D201A2F3D5A98C1D4CCB36E240A1012B3442264A5B9A676321616221D192C72C6F2FBD582512500000D45A6E1E6D301FE5A5E070718A07A939CA8AC8A5444492720528CA7B0AFB0864F473B11094285B1B5BBC3C8811A0000003294B7BEBAC0B785240000002883BDD1CCBBB0893E132885B6C3C3C8B18F3A0000054991BCCAC8C2B9A87F3000094277ACBFBFB7B09B511F03063279A8B6B0B6C09D430000004FAACBC9BEBEB5A9914A0000004688ACBFBDBAB07F280000257DACB7955F433F4E2D09001466B1C5D7D6CEC3BCB0AD9A8CA094581D2E4E561F000000000000458DB2A3641C0000060B1C4BA2DCE1D3A4561F1F2A3E578FC1D4D2B8702709141EB64B285CA1ADAB763815121818223A7CC5FBFACD8B4835060B1C4BA2DCE1D301FE5B5E070718B06B848E989D76433D42242A577FA0A9A3A0794A503D180B4089B7B6BFC1BE7E1C0000002383BEBEC5C2B17D2C0000002D84BFC4BEB3B6883F102E82ADBAB0A4B39F4B000005468CC2CDC4C5B9B4771E00084A81A5B2C6BDB5964619000C3A81B4B6BDAEB4924000000047A2BFC7C4C1C1AC923B0100024990AAB0B6B8A871200000378FB1B08E6353483A1C0B08196BB3D8DCCEC3C6B3ACAE9D939E985921335353160000000000003C8EAC9A5F2200000C02154FA3DAE2C7A057291A2B355A9EC4D4C9B5732800150DA83F225EABBFB07D38130D1424243A83CEFFFDCD7E4B330C02154FA3DAE2C701FE5C5E070718C0757E909C8E7448483F1B1E5790A6B0AFA78054554415053787B0BDB3C5B276170000002C84BBBABBB5B883270000002B89C0CDCBB5B083390A297EB7BCB9B7B295460000114E92B4CCC0C4BCAF6E2500014F7FAEB3BDBAAE965317030D367DA8B4BFBABA9B490000004E98C1C5C9C8B7AB8E420000055196ABB8B3B49F741F00002C86B3B38A665152461C040B226ABBD6D6D6CDBABCADA79690999353192E55571C0000000000004495B297541100000000124BA6D9DECBA3612A182A3A62A3CFD1D2B26D20000E1CAF4A225CA7B5A96C35171E1F1A1B3780CCFDFBCA854F3B0000124BA6D9DECB01FE5D5E070718D0728E8D9C92693C3C46212857809CA7A7987246474616113C88AEC2B9BDA9701B000000268EC3C0C1C5B881340000002C84BFC8C0BCAE80320A3281B2C4B6B2B0873B00000C549EBBCBC8BBB9A87A23000F5487B1B4B6BAAF8F5316000B3682AFBAB7B2AC90420000004AA2D0CABEB4BBA38B4100000C5993B0C1B7B9AF741600002A7BB8B39F614E4C42220C031C6DB3D1D0D6CABABEA7AD978C93954E1B2E5B59100000000000004092AD9766190000070B1E55AFDEE7CD9646171D1F3062A6D3E2D2BA7922060A11A0472461A9BBA4712E13172025223283D0F5F8D2844B31070B1E55AFDEE7CD01FE5E5E070718E0778C959D976F494E482021528DA9ABB6A57B58584B150C3B7EA5B4B3B5B67B240000002B85AEAFBBB6AE7D1F0000003493C0D7C5B2AA79320B3174AABDBBB7B38E3600000E5894B5C6CAC7BDAB6E200014578CBAAFBBB3AB934C190400317CABB1BBB3B0923800000043A0C9D0C5CBBCA98B2A000015599BB2BAB5BAAB6E1D0000348EB3AF9069524C3D120001226DB8DAD5D0CCC5B8A7A9A49798914A19325755130000000000004288A78D580C000000041551ADE0E1C8934F140A223C61AAD1CCCAB46C11000712AF3F2A62AAC5B37E3D181E1A2118377CCDFCFEC57E4D3500041551ADE0E1C801FE5F5E070718F06F8991978D72444A35121E6A88A1A5AAA374545556250D3979ADB8C3C1B77C1F000000257EB0C1B8B7B9852C000000288DB4BFBEB8B689360D328BB7BEB7AAB0943F00000F5992BFCDC8B8B1A76A1700186095B2BAB0B5AC985118070E3F89BAC2B6B4B78B2F0000004FA8D3C9C0BEB8AA843100000D669BBBB6B5AEA2731400003B87ACAD97634C4E351105001A6BB8D5DBDBCCBFB0A7ACA89CA48D4E1E395C5B19000000000000539DA5905613000005091C59B6E4DAB897451C1B233667A6D1DDD5B3731F03121BAB472D6DB7C0AB692D121D1A221C3685D6F1FECA79412F05091C59B6E4DAB801FE605E0707180079848697876C4B473514164E859DA5A7A37351554D22063888ADA6AEB9B46A130000002584B9C1BDBEAD802C000000327CBDD6C3B4A7753917327DA6BCC0B9B388350000145C8DB9D0C6C3BFA9641300176096B0B4ADB1AA914A1400083986ADC8BBBEB48F3C00000149A2C8C4C0BAB7A37F330000176EA5B7BDA7AB9C70190000308FB7B0906D594F331907002775B3D7D9D5C3B3B2A4B1B09FA39444223B5D5E220000000000004A92AF8D53120000050B2658BDE9E1C18B511A0D1B2F6BB0D6DCD2B66E21000C10AE503B7FB0C3A86B24211D1A23243182C9FCF6BF7E3E38050B2658BDE9E1C101FE615E070718107B8385908E71434130111B548B99ABA4906B5262561F093786ABB1C0B9B173110000002A89C4BDB9BAA9752C0100002D8DC0D1C1B0AC71290D3987B8C4BAAEA586380003215E9CB9CBC1C0BEB8671500186AA0B2B0AEB0AF924F0E020B3787A8B9B8B1AB872B0000004CA7CFD5CCB8BEB2872A0000145B9BB1B5B4B29C69130000307CB6B99D77635A2C0C00001F75BBD8D1CCD0B8AD9CAFA79A9889481D415F5E14000000000000458FA08F550800000204225CB4E4E6C78942141B2C3B6AAFD0CFCEB8711E081217A9472D6DBDC4AB6A331912151C1E396DCAF9FFC374432E0204225CB4E4E6C701FE625E07071820787C849A916546372E0D195A85A0A3A7A07052615622092F7CA9B1B4B7A86E100000002683B4B7BBBAAE852A0000002D8BBBC8CAB5AF732E0D2E80B4C3C0BFB98C3E000019669DB1CEC3BEB0A36414000F73A1BDBEB4AD9F834715090D3C83ADAEB9B7B1882900000050A9C4CDC6C2B5A07A250000217AADB6B3B6B2A76A1900002C7FAAB39B6C5D50290606031F68B9CCCBCFC7B6A392B2AD99A5974B183A5A612800000000000060A1B38E530C000000051D57B6DFE4C176471E1024326CAFD0DFD9BA752A0B0A15AD483474BDBEA4622C151E1B1F26367ED2FFFDC37C493000051D57B6DFE4C101FE635E070718307B85898E8B6F473D2E0D1F648A959EA1967C566E681F0E367F9FACBEB6AA6410000000257FA9BFC1BCAC7E32050000318ABAD1C3AAA7682F10378DB2C2B8B1AF823300082868A1BCD2CABBB2A25D1000237BA4B4B5AEAFAB83401000093B89ACB8BCB4B07E2C00000050ADC7C0C3C5C4AB7A2700001878AEBBBEB2A59A5C130000327BB4B1927464512E0B00002576C5DBD4CFCBB9AB9FA7A695A18F4D1B40694A000000000000004F89A1964408000000001656B2DECFB989491819233969B6D6E9DBB87223061219AC3C357AB9CBA56622132621211F388BD2F3F0B56D3B3000001656B2DECFB901FE645E070718406F81818C7A58383C2608225F7D8E99AD9B6B5864561703337FA9A2ACB5AC670E0000002E81B7C0BDB4A77131000000348DBAC2C8BFA3722810408BB9BBC1BAAF8F3600001D6B94BDC0BEB8AB9E601B002070A6BCB9B0A69E7D3E16020C4D93B8BFB8AFA9772200000052ACD0CCC6C0BCAD7F2300002479ACB1BCB6B9A2681500002E83ABB89B776C502B060200287BBFD5D9CFC2BAA397A3AA9FA083462748684E0D0000000000005096A0864F060000060C2066BCE5D5AD793A0E13233873B5D5E1C8B36D23000A13AD45397DBDCDA35E1C1328241C1F4587CCF5F9B65F3B2B060C2066BCE5D5AD01FE655E07071850757C7E8982603D4432071D5D839A9C99917A566D5C2409317DA3A5B0B2A768130000003383B6B6BBBBB17A2C0800002D8DC1CBD0B9A16C1F083787B3C4BBB7AD8731000023649EB7CAC8BEB5A75A0B001A72A4BEB9AFA8A5823C12030D438EA8ADB6B6AB7B230000004CACC7C2C8C3BBAD862D00002A7FA5B4BEABB8A8620E00002F85B1B5A5756D5826040000277ABBD1C5CAC6B89C9AABA995A1833B20486A510C000000000005589AAD8E390700000A0E1853BBEAD6C2864910161C2E74BFDCDED1B47426050B17AE462D7CBDCFAB6A2110231E25223C86D9F5EEAE6037260A0E1853BBEAD6C201FE665E07071860777677887B59404122091453818193A090725871642708307AA1ACABADA364050000002E86B2ADAEB7AA7B340800003287B8C1B5AD9B6C290B3E8BB9B6BCBDB48D3000063471A6BCC7BEB4A398540800217EACB7BDB3AF9F753014020D4593C5B9B6A8A0741C00000455A7D3CBC7C6C0A5761E0000377EA9B3B6B0AC9A590800003085A8B29D7D6B5A2E0606002A7AB5D2D9D7D0BF9F93AEA8999E81422B47725606000000000007569CA9874A07000000172460C3E1D5B081440B12173D77ADD8E8D5C07224000F1AB14D3A86BDCDAA66211329291E13368ED8FBEEBB6B323000172460C3E1D5B001FE675E070718707282818A7D6740402D10205C7D979B98916B536A621802347F9EA7BAB89D560B0000003B83B2B6B7BCAE73390A00003893C1CBC1B29A612102398FB3C0B3BCAD8237000A3A7EABC0C3B7B5B29B530C001B78ACBAB5B7A59D7F390C000B4887A9BEB6A89C712300000056A6CCC6BEBCC6AE762000003179B4BAB8B0B79E5C0E0000347B9DB1A186825E240000002877C1D8CEC7BEB6A09AA8B2A7A18640284A745B0A0000000000085797AB894A0F000000000D61C7E0D3B58142160C213471BDDAEBD6BB7321080F15A7443E83BBCAB0692A102C251C18308BD6E5EAAD67402B00000D61C7E0D3B501FE685E07071880738387877D5544351E091E5F858AA19F8A69566D6423112B78ABA5ABACA054040000002A7AA5B7ACB2AA76391500003F8EC6CFC2B0A8602813478FB0B9AFB2AD8A2D00003583A3B4BBC0BBAD9C4F0B00277CA8BAB4B1ABA07B3516000A3F8BB6C6C1A9A3751C00000054A7C7C4C1C0C3AB75240000328AB5B6ABA5A8955C050000287AB3B6A88F805C240000002082C2D4D6C9C6B8A59BADB9B7A98A352050755A060000000000005D97A87D38020000040D226CBBE1D8B379301817293A7BB7DEE9D7B36E2200000DAB443B8AC4CFB65F1513231D12203B94E0F8ECAE613630040D226CBBE1D8B301FE695E070718907582818381513C3E2D0826557B92969588615D6E5824163375A0A4AEB39C5A020000002F83A2B4A4A9B0803A100000308FBCCABDAC9B671E094189BEBFBAB6A8823800083E80A9BDC5B6B5B5A45309002587ACBDB9A897997B330A00074395B8BDBBADA77A1300000053B0CBCCC3BAB5A3671D00003189B5BCBCAEB5964E0A0000387BA0B3A4938060230200072E83BFCFD8C6C5AE999AAFAFAAA7893D245171570D00000000000963B2A77D3804000201082068C5E9D3A7743C2207244179C4DFEAE3B76320080518B142378FC0C3A660261933251B263E89D8ECEAA560312001082068C5E9D3A701FE6A5E070718A0737573806E523D3D240919587A7F8D998E74626F5C1E1332789FA1A8B49A4E130000002E76A5AEA7A6B77F440C00013692B5D2C4B49D55160D3F8CAFBCB7BBB3822F07123F83A7B7C5BAAEA892460A002486ACC0B7B1AFA6703311000F4689AABDB0B2A7711A0000095DA6CFCAC6BFB9A7731100003587B1B9B8B9B99C550200002B77A9BFAD978969260500002179BBD1C8CCCAB48E99A6ABB3A47D33275A6E4D150000000000005BA3A37C2E06000004141B63BEE5D8A76534151423467FBDDDE7D9B26A2402120EAC493E89BFCDB96B1B112E1C1A1C3993D7F0EAA65A3C3A04141B63BEE5D8A701FE6B5E070718B0706D7782785141361F0017547889949089645471601D10347EA7A3B3BCA358040000003174A7ADBBC2AC7B3E1600003795BFBCB9B39C571F0C408FB4C7BCB9AD793107134485B0C0CBB4B3B198460000247EAAB3A6A2AB996A330B00043985B6BBBCB4A465120000075BB5D2CAC0C4C7AB6F1400003E86A4B3BEB2A5A1560000003A7EA9BCB29290682A0200052480BCD1CACEC4B1908CAEADB1B48B352A6078652800000000001476A8AC843B06000100182F6EC3E6D5A971381D231D4080C3E6EDE3BB6A24050F14AA424B9BCCCEB4701E0F32271F183B91D7F4E9A4613F3400182F6EC3E6D5A901FE6C5E070718C06D727677664442341B00185079758C957E6159725F240C38789DACA9B2965804000000397BADAAB0B2AF7E400A00013C97BDBFB4A5844E1A0E469AC1C5B9C3B68A3200104B8DADBABEB0A8AA983F0A002D83AEBABAB0B19C62200000003F91B9BACABDAF681200000057B2D9CCBAC1C5AB681500003B8FB3B5BAAEB69A530C00083279A2BAB49F8B64250000002B83C0C8CAC1C3A88F92ACB5B3AD873D2B5E75500A0000000000136BAC9C712C000000010C2176C1DECBA76C36130D0D337CBFDBE9DBB0741F0A0B139A424F9FD9D2AC631F16331D13233A94E3F7E49C5E3237010C2176C1DECBA701FE6D5E070718D0807A727A764939411A000B4F6B7B928F735D616B642111367693A5ABB59A51000000003A7B9FA5A6B4B380411300003A8ABAC1C6BD91541309429AAFBEB9C1B7842F04145190A8B5C1BCB5B58E3F00003387AFBBB6A2A7A26B280000003A90C3C9C7B4AA69140000065BAFD2C7C7C7C2A45E140000418FA9B1ADAFAF954B0800002975A4B3AD959065260300003982B9CDCBD6BFAF9193A4B0B2AF7B41375F75500D00000000001672AEA270300A000003153578C8E6CB93632F1D1D253C7BBFDDEED1BC712408070DAD524497CFCEAF691D102A151B1B3D95DDF2EC9C55383D03153578C8E6CB9301FE6E5E070718E0787478767852463F210712567A808F8F7E5D647A6319193F7AA4A0B9B2A14D0C0000002B76A3ABADB2AD863D190001388EBEC4C1AF8C4B140B419BBEC1B7C3AC7B250017529BACB4BABFB0B08D3E00002889B9BAB7B0AE9F662A00000A4389B2B9B6B4AB670E00000B5CB2CABEBBC1BBAC6B1200003F90B0BABBBCB2914403000133749FB4B39F936C290000003089C2C2C7C7CEB99D88A7A7B1AB7A312E647D561900000000001F7DABA8742D00000008092B75CEF1CD9C66301F11273C80C5E0EFE6B4772001060FAB4753A4CED6A65A19142F18141E4098E3F7ECA954252908092B75CEF1CD9C01FE6F5E070718F074877E80775849501E0624577175918F7352537261211E3580ACA7A4AA8E49000000044581A1A4A6B3AB7C421900064C8EB6B9B4AD9059200C4794B9BDC2BFB081320E225B8AA4A6C2B3B2AA8C3F0000327FACB3B3B6A9976123010005468DAEBDC2BBA8610E00000D62ACD4C5C1C3BB9D611200004195B4B0C0B5B18E460000002874A2BCB9AC976C280300003B87C5D3CAD0CAAF8A88AAB3B3A772343254745B2100000000001F75A5A47D2F0800090C1D3078C9E0D49B682F1F161E3577CAE8F1DEBC712402070CA54357AEC9CAB0621F21301D13194195E4F5DEA25D33360C1D3078C9E0D49B01FE705E070718007D736F7B6A4A3E3506001158767888897C52566B57281D4282A59DA3AF99420000000B4375999FAABEB87F441E00003C8ABBBFBAA188430E0D4597B8ADAEB4B2803103205D96B2BAB9B1ADA286360000368EB2BDB0AFAF965D1F0000003D95BBBAC4BAB5630C00000D63ABCCBFBDBBBBA75D110004479BB4B7C6B5BE97400000012E7AA7BAB59D9B641D0200003386C7D1CACCC9AB7F7EA3B1B6A87335326984571F00000000001B7AA6A26C2C0400000C1B2F88D3F2CF966527162A213E79BEE9F0E7B8652804050EA94956ABD1D4AD6217152D191A1D3BA4E0F5E69E522F320C1B2F88D3F2CF9601FE715E0707181073747673674E3C3A1D06184D7175847D744E66755B1C123C859BA5AFB4934A0100000E4D80A2ADA9B4AB78452204003386B2BFBCAF8C460F0A3C9BC2B5C2B8AC782E072A659DAFB9C0ADAEB3934000003C8CB3B9B4B0B0995813000000378EB2B7B9BDB2611200000A5BA5CABEC1C7C6A7660D00004EA5B7B9B7AFB88E490B00022870A5B6BBA2A46F2D0200003788B8D3CAC4BCA17C84A9B2A99D6B3B3D6B885B1700000000001E7AB0A8682A000000060F337DCFF2CF945D25181A29397CCBE1E9D8B667240C0C19A7485EA9DACC915616131A1C212248A8E0FBE6954C3132060F337DCFF2CF9401FE725E0707182088827D767251473F1D051A547680978D73595E815A26114680A6A4B3B08A42010000074F89A7B2B1B0AB77502705083695B9BBACA98A4213053E95A7BDB4BAB57C2E0B29609CAEB9B5B3B2B0913300003191B7C0B2AEAC92551902000B408FBCBBBEBEB6610700000665BBD1BFB5BDBF9D4E0B000C4E97B6B7B7B1B595490000083771A1B7B6AAA16C29070002308BC3D4C7C1C4A57B87A5B7B6AB7A303B6B7D5D1D00000000003083AAA16F3008000205183F85DCEAD29C512E1B202C3E7ABDE5ECE2B16D240F0C12A8485EABD5D4B76C1C1528191D184BA7DDF4E9944D333305183F85DCEAD29C01FE735E070718306B757278744F493F1D00125A7979848062496279561C1B3E80A0A1B2B68A3D0000000C4C7FAAADACB1AB8055250E0A4198B8B2ABB8883609084996BEB6B4B6A66A1C083473A6C3C1BEB7AFAA8D3A00003289B0B4B1A6B1914F1B0000054090BCB7BEB5A35E0200000E5BADD2C5C3BFC5A55707000B57A5BAB8BEAEB69A3E00000829599AABBDB6A36A28000007318EC0C9CDCDC7B27E96AFB7B0A6742F366D815F0E00000000002B81AEA16D270000010A143892D2EBCE944E281B24314780CBE0EDDFA75A1D000816A24B62B0CECAA6702314271D221F4498E5F6E5994B37340A143892D2EBCE9401FE745E07071840767A6F7661423C3A1C011B52726D8A7B604B5C7265271C4A85ADACAEAE8839000000195687A8ADACAFAE7B4D2303063B8AB6BBBEAD8737110C4697BEB5ADAFAC6D1B013B75A0B5B7B4ADADAA8F370200398BB2B9B2A9A48A4C0C000002469BBBC0C1C3AC650500000D5FB7CCCBADB7BFA95E0700004C9BB2B2B5BDC3903E0100052D679FB3C0AAA36D2A000005358FBCDED8CEC4B0798AB0ABAE966B2C3F6F7A531B00000000003186B5A65E28050000051D4791D4E2C78A572817202E5B7FC8E2EFE0B15B1C00050FA65366B5E3D7AF52110A2215171F47A0F2F8E498563536051D4791D4E2C78A01FE755E07071850827F767F6C4D46351000225A717A8279584A637255231D528DADA3B7A58738000000165A87A4AFB3B7A77B562504093E8BADADB8A585400C0E4997B6B8B9B9B26F220A3C789EA3B1BFB4B3A8852A00003F94AFC4BAADA48A54250000003690BDC2C0BAB1610600001366ABCAB6A9BAC89C510900135895B4ABB2B0AB923C030007306A9AB4BCC0A96E210000044097C1D1C0CAC29B788EB5B2ADA7713B417C8152120000000000318DAD9A611E0600040D224693DCE2C18F4B241A1F1F347BBEE2EFD6AA63290B040DB0536CB7D2D4AD5A1E182A251C1E45A4EDFDE191583D250D224693DCE2C18F01FE765E07071860747272715E4140341D031A546E7981775643557552241B518CACB4B4B37C2D0000001F5E8DA7A89AAAA57C5A2B040E479AB3B3B9A57A3D0D095499BAB9B2BAA868220D3F82B3ACB0AEAEACA8852800004397B1B6B2ABA79145100000003F94BEB6B9BCAA600300001560B5DCD2BEC2CAA74E000006599FB9B3AFBDB1883700000C346997A7BAB79E6A2008000B3C99C5D6C7CFC5A07480A8B1B59C6633436F795A1200000000002C89A89B591B000000131A4191D8EDBD854F2013222C3B7AC3DDECD2A8671F0E030BA05071B2D6DDB65C1E0C251C1A2442A1E0FBE98D452E26131A4191D8EDBD8501FE775E07071870746A6D6866444E411B06194F73778378543A587457201F5F99ABB5B5AB7B31000000216592A4A3A4A59D7F55390B0B4A9EB0B3ADA9782D0E0B519FB5B0AFBDAF66210B3D7F9FB2B1BAB5AFA5803100004899ADB3B2B6AA8747140000013E86BDCAC6BBAE530000002166B0CCC1B6C1C59F49020003509DBFB8C5C1B98E3500000D326294B2C4B4AC732C0000074A95BECBC6C7C7A0757CA9B1B0A972313B6F7F5F1D00000000002E8CB2996626060000131C4B99D4EDC78A4C1E1117243E85BEE1F0D6AD61220111109B5B6EB8D7D7A74E160F251D1E1B4CA7EAFEE39B4F322F131C4B99D4EDC78A01FE785E070718807272727361424F3E17021555747A89724C355871471E2B579BAFAFBCB0842E000000236699AEABA0AAA583653404084794B6ADB3A7772F01004F9DB7B8B1BFA966200D418AA8B4B9B6B4ADA379270100489CB8BBB6A89D803D07000000389BC2C6BFBAA1530000001E70B8D3BBAFBCCBA94500000E59A3B1A5ACBDC7943F00000F326595B0BFBBA76B2200000C4790BDD7C8BFCDA16A82A2B1B09F6E35497C8E5E1800000000004593B59E5C1B02030512205294E0DFCA88481E152223417BC9F1F8D6A957280A0C11A14A6CC2E0CAA54A16111E151A1F54B4E8FFE8965A343212205294E0DFCA8801FE795E0707189070745F5F5D494936150D20596C77856A44386177481C24598DA6BCAFAE842D000000296D9AB0A8A5B09F7B5D3302013F99B7B3B1AD7D2F020550A5C1A8ACB9A5651B083C7FA6ADB7BABFB0B27C2400003E95ADC1BDB7B0893E04000000478CB1B9C2C0AE57000000266CB7C9CCB5B9C1A8460000125A9EADAEB3B3B48C3500000D2B5B92AEBBBCA96A1C00000E4FA0CCD5CCC6C19C667A9FAFADA362334675854B0D00000000004596AA975C1C000001091954A2E2F0C67942170E182A4888CFEAEED6994F210F0411A15979BFD3CCA25D1F112017242956ACF1FFD68F47302B091954A2E2F0C67901FE7A5E070718A073796F6D5A3E493A18052450727C876E4A3C59764E1D2A5A96AEB5B6AA781B00000036749CAFA3A3A797795F3A080B489FB7ACADA47A2E030A4894ACB1ADBEB06C1E114E95B2B3B9B8B2AFA2741900004295A7AFADB0A78641060000043A9BC0C7C2C3AC560000002970B9D8C0B6BEBA9F4800001161A7B6AFB5C1B881300001143A618EABBEBDAC67210900124B9FC3C9C2C6B3976F88A3A9A6A06838477B855A1100000000034AA0C0A45E210A01010F2558A9DCEFC77B46190A1A27467DC6EDF2D3A54F1D000E1DA7577EC1DFD7A55318101421222553AEEEFCE490492F260F2558A9DCEFC77B01FE7B5E070718B0746E61655737403211011C556C7B80623D30556F4616296D9EB0B3B8B67B2F000000347DA1ACAD9DA99976613A11104D99AFADB19766240113609CBCAFAAAFA35B1B124D90B2B8B5BCABA5A075250000489AB6B8B4ABA17B31020000063487B3CDD5C5A8570D0000247CB7D9C7A6B3BB9A4000000D62A4B4A6B8C1BF843100000C345C87B2BCB8A8662C00071854A1C6C9C8D5BD936B81ABB5AFA45A32547A855D25000000000850A1BAA45F1E12070006256DB0E3E7BE732E17171D334280D2E9E7D0A25718070D1AA45182BDD8D1A343160E1023251C5AB0F1FFDB934A2B2C06256DB0E3E7BE7301FE7C5E070718C0796F6666543C3C300B001D566E768360322E526D4A1E2D6794ACBCB6A7782B0000003482AFB9A8A7ADA17B663807145B9AABACB7AD7A22030C5FA8B2ADAFB49D551E125589AEB5B6BBB0ADA6732100003D93B4BAAEB1A37331050000014B8EB5C8D0C2A853030000267BAFCCBDB7BECD95310000195F9FA6AAC1C2B882310000173F668CB1CAB5A65F2702000C51A5BFCBBFC7C49C657EACA6B3A4602F51828662150000000008559FBDA666210C0D0D0F216BBFF7EAC37D41230C0A253E7DC9E8F2DD9C501605020C9A527CC7E5DAAC4B0E0A1B17232758BCF5FFDC884C34350F216BBFF7EAC37D01FE7D5E070718D0615D5C655432392C1309234C7376876E352C56653D1A2B65A2B2B5B3A776210000003680A7AAB2A59D9A786F370A134BA2AFA2AAAB782B000D5B9FB4A3AEB0A550140C5193B5C8B8BCB5AA9D75250000489EB3C6BAB0A97027000000054494C4BFC9C0A3510400022D79C0D8C3B5BACA923900001C70ACB8A0ADB9BB8B2F00011C3D598DB1B9B5AD762705001156A5CAD0C5C8C18C5E76A5AAA7945A3E618592521C00000000004BA8C09E572709020410286FBCE5E7B7783A150A161B387FD1EDEFCC9A4A1D09050B975186C9DFD4A24F1A122421162A5EC4F2FFDE86492E2D10286FBCE5E7B77801FE7E5E070718E07263615F52343D2C16172E5A7A848861222A55684921346AA2B4C0AFB06A230000004182A8B9C2A6A49F757049161F4F9BAB9E9D9A641C0011599CC2ACA7B4A050191D5597BEBEC2BAB1AC9D6C2100004794B3AAADAD9E7231000000085194BDBFC7BEAC570700003581B9D7C4ACB1B4883500001A65A69D9CB6B0BD862D00001C456490B4C5CBB2732600000C529FC2CBC9CBC1977078A5B5AD9C5D2C5B8D93532100000000085FA1C1AC6129140B0214366FD1F2F7C1763B1F0D0F203B83C5EAE9CD9B4715131111975B85C4E1CA9E501D092422172452B8F0F6E08442342A14366FD1F2F7C17601FE7F5E070718F078766B5D4A3C483210143666767D7F5F2F2C57643B152C70A5B9C2B9A76B24000000488CAEAEB4A89E8F77714814225CA0AFABA89B622400095299B7BEACB2A4551216528DB1B1B9BDC1B3A674240000579CA9A8A4A7A1712102000002449CC6C6C1C7B3530300052981B9D1C2B0BCC588380000176DADACA1A6B8AB7A2D0000283F6388A6C3C4AC67290000105A9FCBD8CFC2C58E6080ADBDB093613859848C601E000000001360B6C3A55B250D0B0C133175BEECF1BD7B3E120A131C3786C4E8EACB915023080415955490C3DED3944D1D1113211F2364C5F0FCDA8B4A2D2F133175BEECF1BD7B01FE805E0707180072706059452B3F2C0E163065788480592223505F39253078B1C3C4C4A56B1C000000468FB2B8BDB29C917A714F1E1E59A0AEA1A6946119000F59A6BCB3B2B2A44C0D145397B8BBBFC6B6A29765120000569EB1ABA7ADA87223000000034E91B9C6CABEAA57000000338ACBDAC4AEB8B68E2700001573B0A39BA5BDBA82290311333A5783A4B7C0AC6A1E00091858A7CACDC8C1C48F5C7DADB9B29056355E8C915725000000001A6FA6C1A3591E0D0F0A103579C3EEECCA7C381508161D3E82DCEFECCA9B47220E0E17965580BFDACA8D4116161A18212669C3FEFFE089442F30103579C3EEECCA7C01FE815E07071810716C5C53482F3A240F18376580888B592D22545D381F2B74ADB7C5C2B371200000004E9AB0B9B8A597856F714C1C1D5A95AA98A7A26516001467AFC6AAA3AA99450C18579CB9B3BEBBBAB2A76E0F00005AA5B5AAAAAEA06218000000044DA1BCC4C0C8AC52060000388BCAD2BEADB5B8802B0000246CAEAE9DAAB0B876220B102B49608CB5BBC1A65A24020A1B5DA8CCD1C9C9C0986484A2B4B09E6037638387662D000000001C75BFCDA16025190C0D143F7FC9F7EAC274320B0C101E3C82CDECEDC8894B12090E20986686C6E4D39039150F20251F2662D0FBFDDD824A2E2C143F7FC9F7EAC27401FE825E0707182074635654442F2F2C1E203C6D817E85501F225C623B223A7CAFBBB9BAA46A210000004799B3BCB0AFA07E7A784D1914559BB499A79A671B001960ACBDABB2B59E47090E5A9EBAB3B4BBB3B2A9720B00004B98BEA9A1AF9D692400000008469ACFD1CACDA7450000003A91C4DABAA9BAC1821D00002177ABA397A9BDAD7619000B3847647FAAC3C9AC66250500205EA3C3C8D0CCC48D577196ADAF9E573F658B815F31000000001F75BCC6AC5D34220A0A104585D2F0EEC5742C150B1025327FD1ECEFD49141190B08108A5F94C3D9DEA0450E06171F262A67CAF7FFD57D45322F104585D2F0EEC57401FE835E07071830836C5E582D20342A2221456B858D814B1E244657341A3381B2C1C0C2AA6B240000085FA0B9BABBA49B7D77724B1F1C58A3B1ABB0A15D16000B65A9BDAAA1A9994C12216D95BBB9B9BCB1A59A600E000056A6AEB5A5A9975C220000000B4A9FBCCDCEC6A9490500054594CBD5C5B3B8BE871D00002275B1A095AAADAC6B1F00173B52668AAFB6B3A96B1C00051C62ADCAC9C5C9C18B5974A0ADAB9654406B9186612D000000002476B9D0AF632C211A121B3E87C6F1ECB8722D121416233B88D2EBEAC78A45120E0F178D5789D2D3C9924C1A131A141D2972CFFFFFD77C422C291B3E87C6F1ECB87201FE845E070718406E5A423B281D2F301A23386B858E79461E1E4D5D33244280ACBCB8C09F672300000A519DB8BEB8978E82727B521C1765A4AAA0ABA36513000F5DA2BCB0ACAB9A43181B6DA1B5B1B5B9AFAC9E600700045A9DADACA2B0A0611E0000000F5997CDC5C6C0A9560000035099C7DBC9B7B9B77E1C00003079A9A893ABB9B47420001B3D4A6080A7B8BEAF6B1900002870B0CDD2C4C7C0866070A0A8B8924D426982954D2B000000003379BECEA9642E2D1F110F3A94D5F7F3BC7228050C242F4980D2ECE6C58E461A121217885293D1DBC98B451E161E201F2C6FCDFBFFDF824830320F3A94D5F7F3BC7201FE855E070718507D6D53522F1E2E281E374E7E919487511718445C31184682B2BFC5BBA5631C00000E5D9EC1BDBFB693767277491B235C9AB2A5A99F4F0F00176FACBCAEB1B398401326699AB7B5BDB8AEB09E5708000057A3AEA3A9B2955616000000094F9DC9CDD6C3AD500200064D94CFD7CCB0BBC47C1E00002F77A9978BACBFA76211001640596B829BAEBEB25D1C00082769B2CCD5CBC7BE8C527EA9ACAC8C423E608F8650260700000B2683C5CBBA5B2E40271B0D448ACEF9F3C07528121115243B87D0EDE3CA90431B0D0C1A905F97CDE0CC93400C0A161F263270CEF7FFD67F392B310D448ACEF9F3C07501FE865E07071860806C574B282132272133557C82817C4C14124D6037294693B3B7BEBA9F5E12000012609FC1C7B8A08C727781511F2B5FA3ACA0AA99500C0012669EC5BBAAAD90440B206FA3B9B2BEB1B9AFA06212000057A8A19C9FAE955E230000000C579DC4CACCBEA244040016589BC1D0C2B8B2B0782300003586B49690A9C0AC6515002147636987A6ADBDAA601D0001266CB1D5CFC1C6BE8255759EAC9F8E503C6C928C6329070000002B7EC8CFAD582D28190B143F9AD8EEECC06F27080810283C7ED8EDE7C48444160F1B19825A99CEE0C77E45170C15242D2D77DCFFFED87B3E3338143F9AD8EEECC06F01FE875E07071870776C4B47281B28242A36537F8D9B8845131C444E2A1D4883B5BABABC9E571500001267A7CEC4BDAE826B687D4F2D28609CADA9B199611200126C9EBBB8AEB2933C10226DA2BFBCB6B7AEAA94560D00075FA5ABA1A6B39E5317030000125099BDCFCDBFAE3D00000B56A8C9CBBFB0BCB8761A0000267CAFA18FB2B6B0641501264C666880A3BCBCA45C1400012D73B3C2D0C9C8B8835672A2AEA88B553D7688805929010005003980C9D1AF603C2F221217419DDAFCEEBE722208021C263E86D0F5EEC58D4215181A13746A9ED2E0CA84350F0C1F18212D80D6FFFFC9743E2D2D17419DDAFCEEBE7201FE885E07071880735C3A3116141A1C23415B828E92813D1016414022153D85ACC2BDB99A5A1100000D5FB1CCBFC9A78C73757F4D212D65A3B2A9AC9D550900196DA6B4B3B0B0903C11257CA9BFB5B4B9B4AB9C550B00065CA7AD9DA5AB95592000000015579CC5CDD1CBA44A0000095EACC9D4B6B0BDAE6F1600003289B1A18AA2C0B16B180021586664869EB9BDA7582100093980ABC5C4BDBFAF794F759EADB084433F748D8254230200030A2E8CCDD8AA5935361F1217459DD2EBFBBB73381A0912203785D2E9E6C8863C1A100F1C815D9DD2E6C5853B130E19201E2F7ED8FFF5E17A36242F17459DD2EBFBBB7301FE895E070718908262472C1A0C2014244D6781928E923C0A143F53311A3992BCBEBAB499571300001C6AB0C9C1B9AB856B72824D252F73A5ACACAD914C04001A6DB0C7BBAFB68C35061774ABB7BFC1BBB2AB9B5A0A000562A5A5928EA29151100000001053A5BBC5D3D3AF4A0400145AADC7CDCAB5BCA9691000003687AD9C90A6BCAF5F14001C5A73718095B6B1A3551A000B3583B8C2C8C2C4B5855F719CAAA8884139718D8655360C01030A3E94DAD5AA622E3323121752A7DCFEF1BC68250C041627458FD6EEE5C4803820140F157263AEE0E0C780381312171D283889D9FFFCCC853428351752A7DCFEF1BC6801FE8A5E070718A07A5743290F0D231D283F648294977D3C061242482F1F4B91B7C0C1B690471800000C63A6C9C4BDB58C66798A5225366FADB3ADB691520600156BB0C5B8B0BC913E0D2278A2BBBAB0C2ABAD9C5D0900065EA7A38E9FAA994918050000164899C3C6CEBDA5440000226AAFCFDBC9B9B3A9590C0000348DA99889A6B2A9532506205E777B89A1AFC3A45B12000F3D7EB6C9C9C5B9AA7B517797B1AB7642416E928A4F2E0F0A0C144596D1DAAB5E2F362C222456AFE6F8F4B7722C0D110F234787D7ECE7C38841140C0B21705C9DCFDBC1783D1F0E1E232C418AE0FFFCCF7B452A2D2456AFE6F8F4B77201FE8B5E070718B0715A42290811191E26506B858C968041121438442A224695B9C5BFB688481B00001863AECFCFC5A87B6276805424376FAAB5A5AF8F4707001970A9C6B2B1BC91350F2F78ABB3BBB6B8B6AA9C4F0100095FB0B08DA1B6924B1B0000000A54A0C8CFD2C9AC460000156AB6D3DAC9B7AF9C5E0600003D84B89E8EAEC2AC591400205D7C7B8997AAB39C511500062A85B7C1BCC2C6B47F53779AAE97783A3D7496924F341A0D08244FABDED5B3603D3E2F272457B0DEF1F6C17229150C1922428ED8F1EEC47E3A1A1112187960A6D5E8C3702D110D1728313C8CE5FFF3CC793E2F2F2457B0DEF1F6C17201FE8C5E070718C0665A3727130B15242F4B7789949578350910394B220E3A92B8C2C3B9864D0E0000186FABC5C2BCAA806172805C2A3570ACBA9FA9934400002274B3C3B5AEB28C35102685B6BDB8BBB5ACA89B5300000465A89D96A2AE85481202000014519ACCD9C9C0A44400002770B4DADCC7B8BCAB54020000358BB4A28FA9B9A84E08032B677D8081A5B2B3A6540E00053D83B0C3C7C2C0BC7F597693AAA872444970958B5126110B0E1C4AA1DCD8A24E2E372B213062B3EBFFECBB6C230908122B4B93D6EEDDB5843D1B0E081C755B9BDBDBC480390C13171F28398EE7FBF8C8743B37303062B3EBFFECBB6C01FE8D5E070718D0756142290008141D3463748D97A28031091339462B194E97B9B9C5BD883F080000236CB4C4C4BFAF795A6F8956303977AEB2A6A6904400001B7DB0C7B5B2AD8B380D257AB3B7B5C1B7AFB09B5200000B65AAA08D97A1863C0F0000002263A6C2CBD0CB9F3A0000287AB7D2D6C9BDB79D4E0600004292AF9689A7B59E4A0D0C3669887882A4B2AD9D50180008418BAFBDC5C4BFB1785172A1A49D72363D6E898857352013141D58AFEBECB05C394735202061BBEAFCEEC5662B0C0D192F499AD6EBE2BE7A39200D1018736C9FD7E5BD6E2F1916192329429FF1FFFBD677382B2D2061BBEAFCEEC56601FE8E5E070718E073522A1A0000131C405E74879791732800133A46201D4C94BCB2BBAD7B360C00001F70B0C5C6C0A271567789592F497AADB3ACA78E3600002283B7CBB4B1B28C310F3173A5B8BEBEBCB2B2A35205000667B5A68A8EA3893E130000001C609FC3D2CBC2963500002880B3D1D3CAB5BDAF50000000369BBDAE91A8B4A24E0B022D77937E88AAAAAD95500D000E4585A8B5BDC5BFB97B4A6B9CB0A2743C4774978B6A463329283164B0ECE7B464364638273272BBEAFFF2C36625171616274A95E2F1E4B46F351A1B171F736894D1DBBA722E1215161D2B459EEFFFFDC76C3B2E363272BBEAFFF2C36601FE8F5E070718F06C522F1300000C0E3261718393917836000D3228181D448FB6BBC6B57B3B0800001D75B5CFCFD0AA6E59657C552F4989A7B1AEB28A3D0400247FB9CCBFB4C18B340F3880AAB3B6BFC1B0A6935700000A6DA5A4828CAB814A180000002662A8D5C7C6BF97290000207EBCCED5CAC1BD984A000000399AB59F92A9BAA2470A07367492818CA1B7B19F560B000A498EB9B7BBBAB8AF784C6299A59E6B2A468099944E2A28221E2459A4E5EBB369314A2F282E68B7E7FFF5BE65230507081E4B9BE9F6E8B37D33171D111A6B619BCDDDBB782E121A2328294798EDFFF4CD763335372E68B7E7FFF5BE6501FE905E0707180072553210000009133D6C8895A79B6E2501123231181F58A0C7B8C4B676330B02021F66AEC8C5C7A56F57678058344B87B4C0B8AF92440000207AB9C3BAB6B67D2D083383B3B8BDBBB1BCB19C4F04001369ADA1909AA48242120200001F67ABC4D1C7BD972F0000217FB6D2DBC6C1BBA24D0000004291B4A690AFB99B4906003175918A8AA6B9B09A4500000C5097B0B3C2BCB7A171467399B19F6A304382999055262826202658AAE6E7B15E3C463E28326EC6F0FFF4C16D3111141B2E4E9ADFEFDCAC7031141114166355A8D3E0BA71311F13171F2F45AAEFFFF2C372373239326EC6F0FFF4C16D01FE915E0707181072572804000000054268809A999B6C29010B392E141D5199BABCC7AB73300E0201216BABCBD0C4A66C5374835F405A8EB3B4A8A3893900002482B0C7B6AEB08D2D093279A3BEC0C1B4AEB3A25406000D63A7A08392A68B48190300002D71ACC0CDCCC294310000227CBCD3D5CABEB6A04B0000004795AF9D8AA4BE9746130E487D8B9292A2A9AD8E4B0800215896B6B8BEBABAA66E47679EA7905D2F498292825130362C262766B9E2E9AA523A463433417BCDFFFFEFBD6722070D132D469BDEF6E4B36B2B1B160F166862A2D7DEB67729100F1E242743A1F2FFECC56B3C3C3B417BCDFFFFEFBD6701FE925E070718207356340200000016476D969BA2966B1D000F36331C1F54A0BFBBBCB376310201002265A3C2C9C0AB654B698A653D5C98B4BAB6B4853300002F8AB9C4B2B3BA86290A2D85A5B5C1AFB0B0AF96500000117AB09E89919D86400F000000216CACC6BDD1C29A3200002F86C5D7D5CFC8BC964000000A4D8FB39F96A5B89F3C00004586968C8D97B5B09B46000018599DB9B3AEB9BEB36E436B95988A573152809A885843383D2D2A62B3E7E7AB563448372E366CC9EBFEFAC374220D06152747A5DDEEE3B47C321C0A1421685CA4D7D7B6612813191F263051B2EAFFF5CE6F423033366CC9EBFEFAC37401FE935E070718307B6D341200000222526F85909F92602F000C3026111B53A5C4BFC4B36E2E0F090A236FB3CACEC4B16F466B7956355595BEB5B5B780370000318CBABDB6AEB07B2905358DADBEB9C1B7B0B2A04E00000E64AFA68286A080411A0300003166AAC5D0CDC08E3200002480CCD7D8D2B9AE92360000004DA0BDA8A2A9B18539000C4B859B9397A9AFB0984A0D00145D97A8ADB3BEB99F5E476A9AA28D4F294B7D998E4D383A3B343E74C0F5F0B7604441392D3A7CCEF4FFF3BF6C2D11080F2858ADEDFAE0A06642221515206866A5C6D5AE66241810141E2A4EABF6FFFCCC763C30403A7CCEF4FFF3BF6C01FE945E070718407F663104000000174D7D989A99996B24000C2C26172358ADBCBACCA35E200205042B6EB3D9D0D4AB6543698559396099B1C3B4AE832900003596BBC1BFBAAA761F033685ADBCB3ADBEAFB4955000001167ADA28893AA78430E0300022D7FACC4CCCBC48A2C0000298DBDCFD3C8BDBD8F2D0000054D9AC0B09CAFAC8131010D4C8E9C9399A0ADA592450C001B559BABAFB3BAB4AC65406996AC8B52304B7E9E90584444392B4576C6F3E8B06343423F2E3C77CCF7FFFABC682315111A3260ADEBEEDFA760331812171B554C9DDBD3B4662B18141C283355B3EDFFF5C16F3A343F3C77CCF7FFFABC6801FE955E0707185080652B000000001A4D738B929E8F602003132D2D0F1F5BA7CAC8BFAF6B260206082A6DB2D5C6C4A3654F637B593F6BA1B0B7BAA97C260000368AB5C1C5B7B47A280D3489A4BAB9B4BBB0AB93480000096DAAA7888FA7804A190000003B7DADC0CFC7BC8D2100003692BFD3D2D1C5A9872B000002489AB6B6ADBABD903100044E92A196949CABAC9B440D001C68A8B09BA2B5B5A567416C969C8B48324F7F9A8B5546525247357BD4F7EDA7603841382D2E75CEFDFFFFC069261314182F59B1E6EAE0AC6728111811175E70A7DAE0AD65231A191B293150ABEEFFF1BC6A363B432E75CEFDFFFFC06901FE965E070718607A5F2C02000000144C859299928A6213000D202119255EA4BFC2C69F5C290800062D6CAAD6CDC3A565415F76544A71A1C0C2B5AC7B2900003488BBCBBAB8BC85250B3988B0B8BCC1BCB1A7944A00000D69A3A98695A77C3F1E0400023972ACC4CBC6BA8E250000318DBDCDD7D3C8AF7720000007499CBDB5AAB1B18725000E538E9C9D9CA6AFAD8D4306002568A8B1AEB6ADBAA568405E989B7C422C518A9A8F4F4647453D4E8CE3FDE8A75F3F4430293680CBF8FFF5BD672B130F193364B3EBF2E1AE6A29100B0B20566CA2CBD8B05B301323202E3657B6F4FFEDBF76403A3F3680CBF8FFF5BD6701FE975E070718707F652300000000105077948D999B5A11000C2A24192C6DAAC6C8CBA156190900042770BDD0CEBE9D523B657551446F9AC4D3C2B6792200003F8ABDC8CAB4AA6D1C05438EB4BDBDBBC0B7B1903E00000D71A6A4828EA3823D130600084092B4C1C2B9BA832800003B90BDC1CBC6C4B27D2100000B5497BBB7A1B3B58424001966A2A8A299A0A9AA923C07001D62A0AF9FA3B1B2A56B42609291743F306187A69F5044524E3D4687D7F8E0A754334C42363A83D4FBFFFFC3631F1409112655A9ECF7DEA45F2A171D231C5A72B3D7D8A455321D25262A2E5DBDFFFFEEBE6E3931403A83D4FBFFFFC36301FE985E07071880785A320000000017577F919AA790671A000B221F152868AED0CBC19F5318000513336CBDD5D0CAA15A3B576B4F4477A5C4CCBEB6762100003495BBC6BDBAAD6F22063D8CAFC0AFB5BBB4AC974400001473AAA78E9AA47D46150600094485B1BDC3C5BE781500003A99C9CFCBC1C4B5761700000852A1BFBBB5B9AC7E28001260A0ADA598A7A6A28D330300276FA4AD9AA1AAB6A6644A5D93996632285D90A29C52454A533C528EDEFFEEAE5D38433A2B3A8BD8FFFFF2C064262015152E67AEEAF6DA9D623A1C1F1E2C5A78ABD5D5A8652615141B292D5EC2FFFFF0AF5E3A394B3A8BD8FFFFF2C06401FE995E0707189071551B00000000155984918E9589570D000421170A276DB8D0C7C79B4D1D01060D2E72B2D5D1CF9B4F30546B505079ADBEB9B8A9701900003683C2D2C2B5B2771D0F3F90BDBFC4BFBBBCA5974300001377AEA690A0AD81451F0000034A8BAEC9C1BBAE801800002A85BFD2D4C7C2AB6C12000011599FC1C0A8B2B67B200014629EAEA59996A9B18E3F0A003775AAA9949DB1B3A45C4C6090886539245190A38C4E4250533E4589D7FFEC9D582D303126407BE5FFFFF6B560121412162965BEF1EDD0A15D311C1C262B5372A0C9D1A55D261A20282A3D69C9FFFFEAAC65353941407BE5FFFFF6B56001FE9A5E070718A0745616000000000E6187919397894E0900091D1F102970B5C6CDBE974B1C0D000A3875BCD3CDC9A44D27485E495287B5CCC1BCAF6C1800003994C8CFC8BDB07314023B89AAB8BAB8BEB3AB963900001D73AFA48A9FA37C481C08000B4A94B7C6BAB9B06F190000408CBFCBD9CABC9F710C00001C58AACCC1B4B4AE78240014639B9BA8A5AA9FA5903F02002776A39B9095AEB1A46046598A91643331628EA29652455956404389DBFEE59E50424E4036458AD4FFFFF5B86028181C25346DC6EDEDD9AB5F2B16181B2B5877A7D1D1A55B22162027223569C9F8FFE2AF64373A46458AD4FFFFF5B86001FE9B5E070718B068642B000000001667909B9DA0894A0B001120150C3073A8CBD4C39947160609163C83B3CBC5C9974A2D486244487FB0CCD2C7AB6A1A00004B9AC3C7C2BCAF6A12184798B4C0B8BDBFB9B89D3C00001877ADA78A989C7F45280B000F5892AEB8BFB4A5731200002E88B5C2D2C4BDAA690200000F61B0C6C6B9BDB7701C001E65A0B2A5AAA3A4A17E3808003179A0A38794A5AD9A5C39648884602D306297A4A04B4D5C674E559AE5FFEAA556323D3A314C95EEFFFFF9C26924181B1E306EC2F7FED59E5728201C192D4C73A3D9DCA35C2B12292E2C3268D2FFFCE4A95B382B3A4C95EEFFFFF9C26901FE9C5E070718C06E521D00000000186383969A9D834E0A000A16100F3875B5C3D3C6994D19101214327CC4CFC2C1923F29455241578CB0C7C9B6975012000B4C9BCAD2CFC0B46F120E4283A4C3C9B6B2B4AD884000001975B6A69BAEAC89533008000A5095B7C3C3C2B4630800003588BECEBBAEBBB1610500001166B0C7C5B8B7B773100021799FAAA89BACAAA78B2F01043781AFAE8394A4AE9F583D5A897D52253C7198A2945A4F655C505196DDFFE7A44D3A4035204699E6FFFFF4BB5C1F21252E4876B5F1F2CE914827162A1F30557DB0D3CD9B492019201A243E6CCDFFFFD6A8593936434699E6FFFFF4BB5C01FE9D5E070718D07D6623000000001E708D9CA4A88C46120014231A102A7EB8CAC9CEA44F210C09193E81BAD2C8C293422735513C4682B0BEC6BAA86011000A4CA4BFC4BBC5AE6413094892B9BDBBBEBDB6AB8D3B0000187CB4A69BA9B6864D2A15000E5F99B7C0B8B7A7660800003591C4CACBC5BDAA630000001669AEC7C6BDBCBC6B0D001F68A3B3A2A59EA09D833403043B89A7A98895ADAF9A5D365A7882532C2F6A8FA4954D495A59565C98DBFFE19F533C4035345191EBFFFFF6BE63221B24202F6EB1EDF7D290572C1719233D5686B5CEC9984515181D242D3C73D6FFFFE29F553740515191EBFFFFF6BE6301FE9E5E070718E079662A000000001A6D8399A2937C3C0900091709173D7FB9D2C8C396411A0E0E1B487FC3D5CBC793361E374636598DB9C5C2BD9F500F0009559BC3BFC1BFA75D1C0C4199AFBFC3C3B4B3A8994000001778AFAFA1A1B88E52260B00105196B6C6C0BFAA5D0000003694B9C2D0C7C1A34C0000001E6AACC1C0CAC0B8731300226698ADA5AAA7A59D892D00004486A99A838CB0B29855335A806B472B3B7398AB9E57586C7C53599CEAFFE29E53384135374599EEFFFFEBAB51271E242C387BCCF7EFCE8B442316121F40577FBCCFD4964F2D25282C353A75D2FFFED19C533137474599EEFFFFEBAB5101FE9F5E070718F07E702A000000002A77878D989D874710001B1E15114288BDD1D7C39C441E101B2E5D90C6D2C3BF893B1D354439588DB0C9CBC39C4E0B000A57AAD0CEC0BBA7570E0A4693A7BFC2B9C3B2AD893600002B83B2B7A5A3A087532C0D00125F9AB7B5BBB096550000003889B6CAC1C8C4A4500100001D66A7C3C6B9B5A75D10002773A8B4BAAEA8A69D793508003F8AA5A6878FA5A98D4A2C51747143263C779FAFA6545467645752A4EDFFEA9E51303036374B93F5FFFFF3A85C251A1D233F86CEF2F2CC8444210B1110405487B4CBCB924D21231E37353C7AD6FFFFCE8F50303D494B93F5FFFFF3A85C01FEA05E07071800785C290000000029759094A2A1813C0900160C0E0E357EB0CCDACF8F4B1A1214245C9FC8C9BCB68532152C2C36549CB4C3CDBF9D4707001357A2C4C1CDC9B85D12094D98BFC3B7BAC1B6B28C2F00002680B9B5A4AAAF9274390F000B57A1B0B1B5B2A0550000002B86BFC5C4BDB49D530000002773ABC4CBCAC4A6630C002C78A4B3B6AAA5AAA37E300008498CAF9B7C95A8AF8C5C334E63653B213C789BA99D51485E5E585DAAE9F7E1914F363A2E3B4F9EF2FFFFE39950271F21274582D3F8F4CB894C251C1821415388B5CEC890481F252F292B3C75D8FFFFD5934F2C37494F9EF2FFFFE3995001FEA15E0707181073602B00000000267B8A90959E7E40080710110E134A8EC1E3D9C88F412016162F6999C7D0BCBD82341022362F5698B6C4C9BA913E00001658A8C5C4D0BFA1500A0E4E92AABCBFCDC5B9B39D2D00002981B7BEB2A6AA8B6C340D00186398B5BAB8B09848000000308FBAC5CDBBC29D48000000327DB3C3CAC4BCA55806001F74A6A7B0A9AAB0B4832C060B4B8DA6967F869FB0944D2B4A695D2C254581A5B7A5525660624F67AEF0FFE78F4C3633353D52A6F9FFFFE3984D222026254B91D2F8FCD284381F1A2821475096C2D0C083401E1A243235428EE2FFF9C88C4635474352A6F9FFFFE3984D01FEA25E070718207A5B1E000000002E7B90919D997F451000101413135197C5D3D0C5854127221B306AA5BEC6B9B9772803191F245A9CBDCBC2BB953F00001F5DA7C4C7C6B9A856001051A2B7C0C6BBBBB5B08B2C00002C84B7C0B6AFAB976F351000115C99B5B1ADAD91440000004594BCC6C7BFB7983A000000337DB1C9CBC5C19C5602001F77A4B8B1B7ACA9A97F33010A4786A5997F8E99AE884D2D435D56301A4A89AAB6A3515E5F624E6BB0F1FEDD9244353F38344FA4F7FFFFE48D431C1A1A2C4B9BE3FFF7C8774116131A1F424D92C5D9B78250231E2225324090EBFFF2C28949373B4B4FA4F7FFFFE48D4301FEA35E0707183071632300000000347F87899E9B8244090009180B1D519EC3DADBC89348241A223C6CA1C6D0BAB57E23000C19316DA1C6D5CDBD90320000165F9EBFCDD2C2A84F060751A6BECABFBDC3B8B3862C00002C8EBBBFB6ACA7907C521C001C5D999DADAAA9903E0000003090B3C0C8C0B392340000064276B0D0BEC1BCA1510000277CAAB0B7B0B1ACAC80290208478FA5A37E91A5AF9450253A564A241F508BA9B5A15D5367624F6EB0F6FFD98443343C373D5DB4FAFFFFDD9441201E1E2F4E85DDF6EEC48142221F1C305355A1BED1BF71321C18162930458FECFFEACE874D2F3E495DB4FAFFFFDD944101FEA45E0707184075672D0000000031828A98ACA7823E0E00130A05154498C3C0CDC27E472B1E244280AFC8C4C2B47C2E000F1C3168A8C1C7C5B48B330500145EA5CACDC6BBA6500410529BBAB9BEC5C2B1B08B2E0000307EB3BFB6AFAE91794C100013639EA4AFA1A48B38000000419ABDC8C6C3B8842B0000023E82B5CBC7C6B79B4200003A8CAFB7AFBAAFA7A3852600115194A8937B979BA18247303E4B3C23275493AEB7A45F5264614F69B5F7FFD5984B323C313E5EB4F2FFFFDA8940211F25345BABE5FCEBC67945171414204D669DC6D1BB702B16192C2C23468ADFF6E6BA844A364C545EB4F2FFFFDA894001FEA55E07071850706B2E0000000038879093B0A9873F0E091314101758A5CCDAD2C18A492E2F363E7BB2C6DBBDB370210000062A6AA4C8C0BFB4732100001F68ADC6CCD5CCA3500B0B4FA7C1C8BDC1C6B5AD831D0000338EB6BAB1A1A798835517001A6696A0ACB2A67D300000004298BEC8C8C4B07926000008488EB8C6BFBABBA04800003286AFB0AEAEB0B0AF812603135F9BA5A58A96A6A8833F1D35463C261F5890A6B2A35A505E5D5871C1F7FBD384413735343866B6FEFFFFCE7842362422335FABE8FFF4BC6E2C1E141D275B6699C1CFB36E32151A182C354C9CEEFEE4B0794132395166B6FEFFFFCE784201FEA65E07071860757232000000003C9698B0B9B083491F141B1105255AA4C8D7D6C48942383732518EB3C6CFBAB27B160000002163A5C1C9C6B0702000002468A7BED1D2C6994605075DAEBFC8C4BDC7BCAD781800004285BFC1BCB3B09D7C4F1700126495A7AAA49983340000004A90B8CCC5C3B77E1F0000105485B4CECCBFB5984500002980ACB9ADB5ACA7A6782307126098ACA68F93B2A686402430362815265998AABAAE57505D635271BEF1F8D38346382A343E63B8F7FFFFBC73371B1D1B2F60B7F5FFEEC3763A1A1919276462A8CBD2BD662E171D202A30429AEEFFDFA06B49353A4663B8F7FFFFBC733701FEA75E070718707E7A3700000000418CA2AAA5AF85330D03120E0A2661AACECFD8BB84473A302F5495C4CAC9B5B170160000072563A5CAD9CDB86E1F0000236A9FBFC1CABE9A3900065AADC0BEC6C8CAC0B5761800003F8EBFB7C0AFABA08B5821011D6798A9A8A2997D2A0000074896BBC0CDBAB278220000125399B9C9CBC8B6913F0000298CB7B5B0ACAFA7A27627001B5B95A8A290999BA1793E2627322E232166A0AEBAA35154695C5171BCF4F9C07240302E313752B8FFFFF6C17E32201D223F6DBAEBFFFAB96D2C1818242F6369AACADABE6C340F1919283351A2E7FFE0A26F462E3A4B52B8FFFFF6C17E3201FEA85E07071880767533000000004294A2A6B19F883B14050E0D0A2963A7CECBCEC27C453A3A365392AFCAC2C0BC791A0000001F6CB2C3D0C5A6671E00052C70A9BFCCCFC4973B0D0A50A4B5C7C3C9C5B4A67F190000448EB5BEC3B0A293855A16002A709BAAA9A5A17D34000001499BBFBEC7B3AD791C00000B6092B5CBC7C2BF81290000408FB2B4B4B0AB9FA67A290B15619FAAA18D929CA27535162014190F3376ABB4C1AE504A534B5475CCF9EFC77546333D383778C9FFFFF1B35C2F1F17213478BFFBFFE9B164291114132B6168B0BCD0B96C2D19131F2B294BB7F1FFD9A0673826384678C9FFFFF1B35C2F01FEA95E0707189071712B00000000408D9CA5AC9D863907060C0D062867ABCBCBC9A675454D43385E99B6C6CCB7B3780C0000001D60A7C3D1CCA05F1700003277AACBD2D5BA9430000A54A4C1C8C7C5CCC5B06E1700004D96B5BDB9B4B4A79A611C0024719DA7AC9C9B7E2700000E4E9BC2C4C1BBB0701A00001E5F96C6C9C3B9B4802600003A91B0B1B2B5B0AAAE742E051B6E9EACA3958F9CA2713813120F171430749EAFB6A4554A575A527ADDFAF2BF763E3737444976CBFFFFE7B5682F1F17214486C7FBFFEEB2692E211920346A6BB6BECFCF752C1D1E1C292E48A9EEF6CD9E5E3725304276CBFFFFE7B5682F01FEAA5E070718A0727838000000004B90B0BBB1A683490C0A02090C246EB2CFCFCCB875494B443D6AA2C7C5BBB9AA6D0F0000001D6FB5C8C6C3945C0B00083C84B8D6D3CABA8736010E57A3C9CFC3C8C4BEA9630B0009599CBBBBC7B9A7A2925E1D021E6E95A8A7A498651D00001061A9C2C1C9BAAE660A00002075A2BDC9CABCB3782E00004098B7BFBBB9AAA1A36F22031F67A2B8B3989B9F886D3416141413113C7C9EACB0A64E4646494477C9F7E4B36A2E2A282E3E79D2FFFFE9A55A2621161F3B8CC7F4FFF6C469271A1500287971BDCDD1A8572A19191930335EB3F0EFD08D51262A2F3979D2FFFFE9A55A2601FEAB5E070718B0716A2F0000000153A1B4B2B1A6813A0D000406072D71B3BECCCAB2744A4E4C4F65A2BDC2C8C0AB6405000000116AB7CCCAC09F560D00003882A6CBDCC9BB893100105DA9C5C7C5C0C8C1AB610B000B5CA3BAC3B8B6A590966820032A6D95A9A1A19E751400000F61AAC6C2CBC2AF5D0C00001C65A7BEC1C0C2B86B1900004099BBBAB9BFA9A4A4682000247297B8B6A096A49C6D2F0E0603000A3586AEBEB8AD49434A3F457CCEFBE9AB61312D2B313C82D5FFFFE7A750291220213F8DD4FFFFE9B9672B121E26358072B2D6D1AB602A161B192F3752A9EEF8C59150372E304B82D5FFFFE7A7502901FEAC5E070718C072682000000001579BABADACAC7830050C0301113575B3C0C3C6AB69465A4A4D74A4BFC0BEBFB5680F0000001678B2BDCDBC8F4806000A4488B6C9D0CAC38E36001054ACC0CBCCC4C5BDAD650A000B5EA4C7C1BBA9989C955818052B6E9094A6A299701A0000185FA5BEC2C6B2995B070000337FB7C7C0C0B5AA610F00004295B4BDC3ADB6B2A27128082673A5B5B2A297A29A672B0D040000203A8BB5BCB4AC584852525383D8FBE6A365352D37364386D5FFFFDF8F56311C20275193C2F4FFEFB266280F0B17318270B5D3D7B3642B150E1A353666BAF8FCBD794F2D28324486D5FFFFDF8F563101FEAD5E070718D07A6112000000004A96AAB4AAA27C3209000000152F76B3C0CED3AB63505E404E79A0B6BCBDBFAC5C00000000217AB4BEC5B6883800000B538CB3CCD8CABE812800115DB2C6CFCEC5C6B9A95F07001569A2BBBEBCAF9E9C895B1A03307D929AAA978C681400002169AFC2C2BDB5A14E0600003B86B2C9CCCABDA4620D00003D95B0BBADBAB9B4A46C1E0D3174A4C4BAACA39D92683002000000164185B3BFAF9C4D494D4D4C84D3F6ECA45F312D322E3E89E6FFFFDD8E4724322517378BD2FFFFEDAE6022090A153A8B75B9D6D6B556200F0F1D293363BBF8F5B573513B28304089E6FFFFDD8E472401FEAE5E070718E0725C0700000000559BBAB8B399732A080C0100083981B1C7C4C49F5E4A634A4D7B98B3B0BCAC9C5500000000226EB9D2CBAE843E030014639AB0C9CAD5C1852000125BAEB8CECBC6C2BFA45B0500176DA8C4C4C9A5888C90661D002D7D949EA79B86651200001D6AA5C5C3C1B59B460100003C8CB7CDD4C9B9AE5D0C0000449DB8B9B9B6B3ACA65E120D247C9EB5B7B1A29E8A6131070000001D4A8DB2AEB4A35345564D518BE1F1D79F5736342E3F4F96EAFFFBD49048222823234485D0FDFFE5AE58271610193F8270BDD2D7A8542219111D313870CBFCEEB86E49341F293F96EAFFFBD490482201FEAF5E070718F0735900000000065896B0B7AC9B6B2B03070000143980BAC7C9C791585767595E83B1BABEBCB19C52030000002677B8C5C8AD85270000185994B4C4C8CDC27D21000B66B3BED2C6C4CABCA65000001773A9C3C3BAAD9B8E8E5D14043777909AA2A094601100002875A7B8C3CCB88B3D0000003594BBC5C2CAC1B15E0300003F90BAC4C6C0B8B899601C143376AAC0C0B3A89A8966320E000000215E96C0BAB9A2543D413B4E8BD3F2D2A15636282D374D9BE5FFECCB8B5029231B244D9BDEFFFFF0AC541D10131C378F76BECDD6AE54181B100F252E71CAFFF1AE6D3D2D2F394A9BE5FFECCB8B502901FEB05E070718007449000000001A6CA4B8BAADA07435161107021A4289B2C7C3B9955B53685A5181A8C0BFBFB5A04B000000002C8FBCC8CAA3651D00001E609EB9BFCED1C2711B001966B4CBCFC4C5C4B8A84D00002177B3BCC3BDBA8E83945C1906367A98A9A69D8C5F0F00002E7CA5C3C2C3B089390000004693ADC4CCC9BFA44B0000004A99BAC6BEB8B2ADA8621E123C7C9FB7BBB49E917F532B01000000235996B1B1B3AA5B4B4D424E9CDAF2E396492F343D3E55A6E0FFF7CD7F462E1C1C2A4DAEEBFFFFE0A34C1F051722469572C2D8CFA656251A111931336AC3F9E7A96C4515313747A6E0FFF7CD7F462E01FEB15E070718107654010000001C6CA3BCBDAF96682C0D0E08091E5185B2BFC7B793514973536080AAB4B8BABCA44B000000002C8DC8C2C1A4662200001F7AA0BCBFD1C5AA751F001A62B1C0CCC3C5C2BC964400002783A9C4C6C1A289868E5A2213428B9693ADA191540400003A81B9CCC4B8B3822C0000004498BDC5BEB7BDA6450000004D9DBEC5BDBAB0B3A354180D3E82A3ADBEBAA6887B52350C000000275E9BB6B7B2A35C4F4F4A4F92D5FBDC9A5E4335333C55B0FAFFFAC78942211D1D2851A1E1FFFFE1AA5A27161421499E78BDD0CDB54E210F1E2B292373C8F3DE944D353131333CB0FAFFFAC789422101FEB25E070718207045000000001168A2BABBB09E6427111106041A4B89B5C3BEAD7D494F715D5F81B3C0C0C3B9964100000000358FB8C9C097591600002672B2BBD1D3D4B16711001275B6CCCCC3CAC5B9923200003084BECCBEC8B28E858C5718054280969C9E948B510800004790B7CDC6C1B680260000003D95BFC8BFC4BC953C000000559DBFC4C6BFB5BAA051180B3F88A5B2B1AF9F8271533E1600000028639AB4B2B29A514F4256559AE5F5D583483229373C65B4EEFFFBC3733F1C1C2022459FECFFFFDB985020191F2551A477C4D5D0A75A1C15121B343883D5FEEB9B583A2A38343FB4EEFFFBC3733F1C01FEB35E070718306E4500000000136DABB8AFA38C511A060C0803214986B6C4B6B882494D67687188A8B6BDB2AA8F3600000000439CB9B9C79C561200002370B1C1D6D7CBAE680F00136EAFC1D2C8C5C9C18D3D00002F7FA9BFC3BFB187768052140F3F8C97A3A4A4924F0800003E8CAEC0CCC5AE7A1D00000050A5C3CACEBEB793340000085BA7BAC2B3BBBCBCA24F0D114688A4AAB2B2A081615047180000012F74A9BCB1AEA162515C5D64A3F2FFD98D53383630396BC4FEFFF5C281481C20242D48A1E8FFFFCA9B511F1113204B9977BEDACFA5571B15121F293E8DDFF5E29C553926302F40C4FEFFF5C281481C01FEB45E07071840783F000000001768A0C0C0AD90582517151109285592AEC6C0B7723A50745C6D9CB2BBB8B3AE8F34000000005097BED0C2964B0300002C78B5C0BFCCC9AB5F08001778AFC1D3D0CEC4BD8C2D00003894B8BBBDBCAB82798B581D1750768DA3A59B884B000000509BB4C8C2C3B3771700000254A4C1C8C2BBB58C3000000553AAC2C5C2BBBBB89A4D15154687ABB7BEB99F806454450C000005376A9EC0BFB2A2555E554E65A4F1F0D186452B25313D6BC3FAFFE7976C3D2D2C1B1F55ABECFFFFE89E4F1E141B295DA870B5CDCAA258250E1D192F3689DBF6DC8A4A38322C2F39C3FAFFE7976C3D2D01FEB55E070718507640000000002072AEB4B3A38B521E1D2019162A4D88B5C0C2A770364E74626C9BB1C2BDB0AA8931000000004C9AC2C3B887450900002E83B0C0C1D0BEAE5A03001879B2C0CFD2CED0C0842D00003788B1BEC7C1A4737879432625588E91959194873B0000075596B7D2C8C3AB7A1B0000005AA9C0C5CAC5B985330000035EA6C1C9C9C4B7AF984817184D8FABBABEB49A6E544A44170000053D6FA0B5AAB29D5F5D635865A8E9F6C6814A322D3A437AC9FFFFE6AA6D31222127234DABE7FFFFCE904D1912152262B36FBFDDCA9B4D2015130C1E308FDAF8DB874D392B333640C9FFFFE6AA6D312201FEB65E070718606F2300000000266DA2B3A4A3874B1523261B1731609CBEC1BFA66E46516B5D739AADB5ADB2B790310000000049A2C4C6AD8035000000418FB3BECEC6CEAD5711002482C5C6C6CAC3CCB5772E00003F93B7C5BFBCA976727853171D5A8092AAA89C8E430000025A98BCC8C9BBA8710F00000964ACC1BCBEC6C3912B00000B62A9C5CECBBDBCB299450A105196A8B6B9B99D6C4C48450C000008437EA7B8A8B39C5A615E5379BEF4F1CA7C46282A2E4082D4FFFFECB173422C231B194EA8E4FEF6CD84400B13183670B876C5CDD8AD571F161F1C2B4A9EE6F9DA804234272C383ED4FFFFECB173422C01FEB75E070718707C3900000000397DB4B9ADA88547262E3220193B6A93B6BCBAAA65364E71697893B1B7B6B5AD87290000000460AFCACFB8722D000000359AC5CDD7C5C5A64D0000227AB7C1D2C4CFC4B3751E00003E93ACBFBDC4A274687A4E1926618E96A3A094853A00000F69A6C7CDBEC0AD660A00000463AEC9C3C2BAB4902000000A5CAEC4D0D8C9C3BB8B380E184B90A8BFC6B6976A4D4E491300000C4B7A9DABAFB4A268645B5775C2FAF2C88347383C3B4C88DEFCFFE4BA6D40232119235BAEF8FFF7CE8C4512111A2F69AD73BEC5D09D4B211509142A4BACEDF6D68A4626312F3644DEFCFFE4BA6D402301FEB85E07071880722E000000002977ADB4AEA3844E1E31372421456197B2BFB2965D3D526B5C7D9DB0B3A9B7AA721A0000000C65A9C7CBC1822E000004378EBACCC3CFBE943F00001C75AFC5CEC6CCC6AE692400004B95C4CCC9BCAE746A6E441520658C9BA4A99C7C350000136AAEBECAC7CEA0600600000364A8BEC7C2B6B2811A00001D67B5CAC8C7C7BCB98B35061B5C90B5BFC1A794644A565A26000013527C9CAAA7ADA3654D496088CCF6F3C37D4A31323D4E8EDEFFFFE89C65382425282B59B2F5FFF5C07F41201E153170B56FC4D4CA9A451D1C1F242952A1F2FFD28146342A2D373DDEFFFFE89C65382401FEB95E070718906D2600000000357FA9B0B2A28B53273043252E436A91B0BBACA5592D4D625D7BA5B6BDBFB9A77F200000001067ACCEC5B969220000073B91C9D3D2C8C0994100001D7EB8CBD2CDC7C2AC691600004F96C2C6C5BA906364683D182A68989AA3AAA98B3700001473B6C7C1CABFA75C0000000464B0C7CDC8B5AF7E1B00002165B2CACECDC8BBB17F2C0114588FB1B2B6C18E5E48545A2901001D5381A2B3AEA39C6561655D89C5FFF8C585503A3B3C5897E8FFFFD6A668392322253762B0EAFFF4BC73330D141D2F75BB68C0D2CF92451F0D1A222C51ACEDF2D57839241C33354DE8FFFFD6A668392301FEBA5E070718A07824000000003A8CB4B6ADAA864A1E3349332B4A6D8EAFB9AC9850274A625F84A9B3BBBEB3A47F110000001879B3D1C8B36D1D000005498CBFC9CEC5C69B4000001B7DB9B7D2BEC0C5AD570900115A9DBECBBEBB97605B603128327B9BA4A4AD92823400001B74AAC3C5C0C7A7500400000F69A8CACDCDC3AF761400002266ABD0C6CCCCC0B57A2C081B609CB1BAB5B59A6348565F2B00001C5684A4ADA89E8D696C676D8FDBFFFDC3794F3A474C62A1F8FFFFDC93572A1E25253469C8F3FBEDB26F391620283B7AB668BBC5C18B46281F1B1E2E56BDF3FFD77A3C292D36353DF8FFFFDC93572A1E01FEBB5E070718B0762C00000000428CBCBAB7AB824D2D494D39305C7B96AAAEA98D512A3C59638CA8B5BAB5BBAA7E1A0000001F82B8BFCCAD6716000005479DC9CBD0C7B78B300000227EB6CCCCC6C4C49C500800115FADCCD4CEC8985D584F2C1A3A72949AA4A691712400002C83BAC6CFC9B69B590000000569A8C4CCC7C3B9801A00002C74B5C5C3CDBAB5A87726051F66A9B4BFB8BA8C4D3B5F621A00002B5C7EA1B3A2A6976E7369709CDFFFFCC674443D414A5FAEFFFFFFD49A5C301E261B2E65D2FCFFE6B1682C2D222A3E7EBD6AC6D8C892431E1016253261BFF2F8C8633D292427354BFFFFFFD49A5C301E01FEBC5E070718C07F3400000004478FB3B9BAAD894D2D525741445D769EB5AFB08C3D1C3C536386A9B5AEACB3A56C090000002D8DC9D0CABC6610000005428EC1CECFC9BA8D3000002B79B5BECEC3CCC78F4100001869AFC6CEC8CB9A584C52281E41789DA6ABA594712600001987B8CBC5C5B8A0500000001372B5C9C5C2BEB1701200033883C0C4C0C4C8C0A96820001A659FAABFBBBFA557385F5B1B0007335C849BA4B0A7955E6467689BE7FFF5C4744A3F44445CB6F8FFFFD993542C182325386CC8F8FFDEA3672520222F4582BC5AB9D0BE84401A1A1C243665C3FBFFC3703C362325333FF8FFFFD993542C1801FEBD5E070718D0762C00000004589FC5B9B2AC7E502D514D354C6487A7ABB3AA8434143F5E5A96ACAFBDB2B0A56D12000000348FC1CACBB062160000004892BFD1CFC6BF83280000247BBCC8CDC4CBC18F3A06001B64B2C2CAC6BE9057514A2A1E4980A6A3ABAF8C6A2800002D88C3D0CDC5B4A14D0200000F67B1C8CECCC5B4751300033683C2C4CBC9C1BEAE6C13001E68A0AFBEC2BB8C4D375D5820000B356D7F9DA2A2A0856F6C7D79A8F4FFFBC16D4B3B494C62B5FEFFFFE4995D31242A27356BC8F9EBD89B64412A1A243E85BD5DBBCBB47D38241614203973D0F5F2C4663E302E3C3843FEFFFFE4995D312401FEBE5E070718E0792F000000055A99B9BFBBA67F503758594749687697A7A8A383331A33425B96AFB9BCBAB8A56C100000003C98C0D3CBB56614000003569AC1C2C7C8BC762300001D75BFC6D3C5C8C58D3B05002570B5C3D0BDBF844F454528254289B0A89FA2815C1500002588C3CBD0CAC9A54C0000002178BECEC8C1B9B4720C00044690BDCBD1BDC6BCA15308002A70A1B1C1BFB8954D40616026010D366B9096A2A0957E737A818BABEEFFF3BA764E5053566DB0FEFFFFC9974D302A2B27357AD6F6F2D58D57331B26344D91BD5DB3C7B5733B2525282D3980E0FFF7B4603A33293C4345FEFFFFC9974D302A01FEBF5E070718F06C2A0000001A599FBDCABDB4865035526240497082A4A69A9D8126051D3C568CB9BBBDB7B8A363090000004CA5CECEBBAF640500000A57A4C7D7D6C3AF6A1B00002C77B8C1CDD1C4BD7B2700002B7FB5C1CBC4C38A51433B2726417FAAAFBA9B73591800003385BFD7CECBC29A3F0000001670B6CDD1C9BFA76B1000074692C0D7D9C5B9AF9D5F0A022D6CA6B8B3BABB924C40655F260D1A48798B8A959C9B7F74717F83B8FAFFF5B3674A4B4F4D6DC8FFFFFFCD994731292C2A3D85D5EDF6C78B532B1D22304F98CC5BB0C1B16F391F2223304285E1FFFBB5603C3034393042FFFFFFCD9947312901FEC05E070718006C340200001366ABC5C1B7AA7E51456A654E5F768199AAA49F772E0D2A3D5A9AACB9BBBEBBA85C01000000469CBDCDD0B36C1100001564A9C4CCCBCAAD6F1A0000267CAAC4D7D2C2BE6C2000013F87C7C8D3CBBD7C43363525284E90B5B8B2A176501800013A8DBECFD8D1B8A0400000001870B5CDD8C3BDAC630E000D4D94BDCDC9C3C0BC9F500C002B70A9BDC8C6B992514170592805184B748F94A5B3907274868988C1FFFFF2B3734D48484A81CFFFFFFFCF904E2F2D2A2B3A88D7F9EBBC834B2A1F262C589DC15AB1C7B1773C271F1D2B458EE2FAEEAB683A1F2D343C4BFFFFFFCF904E2F2D01FEC15E0707181074240000000F5E9CC0BCC5AE88563A6A5B46577D899FA3A6A27C210A1E2E5492AEC2BFB6B9A55B000000004AA8CAD1C4AF660D00000E5AA6C1D2CCCEB6650800001E7BBCC6D0CBC7B262150000408BB8CACFD0AF80463F361B2E5091B8B8B59A64420C00063E90C0D8D7CAC794450000001E70BBC6D8CFCBAA5F0D00155699C5CEC6BAB7B7933E09062C71A7B7B6BCB1834A4C716A2B0B254D8390979D9E936F6A6C7389C1FFFFE7AF644D474E5C84DBFFFFFFC282461B1D1E2A3F87DDF0E3AD71412D29222953A1C95AB5C8AD6C3424262931438FEEFFFBAC5833293441384EFFFFFFC282461B1D01FEC25E070718207B340900002B7DBCCBCAC8BB875643705B4C668B97979AA09E6E2A03123459A3BEBFB6B7C1A051050000004DA3C9C0D2B35C0B00001B68B2D1CCC3C5A75B0900002989BFCAD6CABFB0630E00004C98BEC8C1C4B66C382C271C356F9FBBB4B79659390300053D91CDD0CDCBC4A745000000257EB3D7D1C8B9A66108021C61A1C4C3CFC3BEBC8C3D02003172ADBAC4C2B19A4D56745E15032A5D858885989C92717C768CABD9FFFFFEC4804F4C50538BDFFFFFEBB77D4530242F355591E4FEE8A67D5430202C365498BC5BADBEA964361F1D2A314B91E5FFF4B259312E2F35433BFFFFEBB77D45302401FEC35E07071830743B0C06013283B7C7C6BEBA905B4B746A6072888F96919B90671A0213265291ABBDB9B6B8A24E040000095DADC7CECEB9660B00001162B1CED3CFBEA64F0000002C88B7C7D5CAC7AC5A13000A4598B9CBC9C1B06A352E2623386AA0BEBDB08F5B2A0C02094799CED1D1C4C59237000000247AB8C9CFC7C4A8621703246CA7C0C3C5CBC0B3833700004487B1BAB7B1AE84505276632D182D62938C83929995646E778394CFFFFFE1A860413B4F5B8ED6FFFFEDBE80442C322A31438FEAF3D7A367402E2B2930569EC259AFBD9A6528171D27294B9BEFFFF7A15432363836484DFFFFEDBE80442C3201FEC45E070718407D42090F102E82C1CEC6BDBB8D574F72656071919A99979CA16A18020F255296B8C9C2B4B098530400000E6DACBECFCEBB5C050000156CB9D6CAC9BF9E520200003184B9D1CBCDCDB4590C00034EA0C4CECDBEB2662D231D1C3F71A7B8C0B490491700000B50A4D5DCD0C5C1843A0000002B85B8CCDFC4C2AF5C0B002671B2C7CDC2BEC5AE772C00033785ADB9BCB3B0894C5876521F1E44708F968892968359747F98B0E6FFFFF5A45E534754619AE4FFFFEDBE7F3E2639332D4C94E9ECDB9E65481D25303C6EA5C855B6C99A532E242828305AB0F7FFF1A7512F2432333B46FFFFEDBE7F3E263901FEC55E07071850703A11151A3A90C3D7CECBB98A5752776E69859B908F949D9D570F0009285498B6B9C4BDBEA14D0000000869B3CAC6CAAF67030000216CB7D5CCC0C0A44F030000307DBAD5D3D0CAAD4B0A002264A6CCD0BFC7A65A2529201E3D72A2BDC2B385441300000F52ABDADCD4CABE95380000033790BED3C7C7CAA24E0A07377EADC6CEC3C7C3B36C1D00003984AABAB4BEB1834B5870521912487E958484969D7F4D6D788FB0E4FFFFE0975A4546566196E5FFFFE1B17140362326304A9CEDF5CE925F39262635436DA7C35BB2C4964E3020212C395BB1F6FFF39C4F3B3433324242FFFFE1B17140362301FEC65E070718606D2E040A152B78AEC7BCC5C589605F70645D859A988D88A18F510B0004204F8FBEBFC4BFBCA14D0000001364B2CAC6CFB0590400002179C2D4D3C6BE9B420000002D85C7D8E4CBC9A44505001A60A5C3C8CAC1A8541E2020234274A4BFBCB27A340F00001560ABCFE0DCD5CA9E32000000378CBFD3CCC4B99F530C083B83B8C6C2C1BDBDA66518000B5086B5B6B9B2B4874B5773501B224A809A887D8C8F734D7B8692BDF7FFFFE094624C4A506399EAFFFFE6AA6F3B2529313151A9E9EFC77E503C3528314A71B1CC5CBDC99F532618292D3C66BCF7FFF3A0442429352F3951FFFFE6AA6F3B252901FEC75E07071870702B1D0D123B8BBAC5C0C7AF875A5776656C8FA49E93939F964305000413519CBBC4C9C5BA96410000002173C1D2CBCAB1580A00002982C9D8D2C5BF993B0000003383BACAD7CFC0924100002369B3CDCBC8BCAA561B191F1D4C84AFB8BDAF7229000000205DABD9E8E0D0CB8E27000003328AC0D9CCCABD994200034187BBCBD2D3C2C1AE62150006458BB1B5BAB5AE7D545C6449171E52869B897C8A9B7D4779748DAFF0FFFFE2965647484C58A3EDFFFFE19F713C2C342D3358A9FAFBC37B4B352628344670AEC960B5C1925034241D2F426DCAFFFFF0A5442F2825333947FFFFE19F713C2C3401FEC85E070718807542201D295393BCCDCAC4BB8D5B5A78687795A39A939094854004000025569FC3CCC7BDB885400000001D76B9DBCBC7A9520500002C89D0D8D1C5B49441000000338BCCDAD4D0CC973000002C7BB8CBCECDBA9E4A1115121F5891B0BDC3AE75250000002066B9DDE2DDD1C8832C00000B4A95BFD0C8C3BA9B4107103C86B8D7DBC2CEBB9E5608000C4A94B6B5B1B7A97C535F72421B235D8B9D8174848F6F416F789CC3FAFFFFE49A584E4A5158A2EBFFFAD6A7703F333A37315AB6F0EBBF7C4F392221354578B4C656B2C6904A2E272128376AC7FFFFEF94462E273539454BFFFAD6A7703F333A01FEC95E07071890783F26292D599BC2C9C6CBBA89595F6D6F85A0AD998B9090883F0700042058A2C9BFC1C5C393410000002783BAC7C9CBB350090000268AC2D5D7CCBA8B2D000000378EBFD6CBCAC6993000003A86C1CDBFCDC39E3E120B13255184B7C5CBAE6C130000072465AFD7E0E1DBC88B2E0000134C8EBDD0C5C7C6903D09104D9BBCCCC7BCC9C69E5006000C548EABBFB7BAB38653586D3F19235B8D9D85798589683579899FC8FCFFFFDB8D5E514A5162AEEFFFFDDD9D623F29363B3A5ABBF0F2C57B46271D2E34437BBBD262C3CC8C3A202223314B6EC9FFFFDE943D293033353645FFFDDD9D623F293601FECA5E070718A0754B2B2427548CB4CECDCCBC815C60726A82A4A89E7F858D7E380B00051E5FABBBC3CBC4BB96400000002B87C4D0CCCEA74F0000003090C6DADAD3C085270000003893CCD9D8CDC3843100003788C2DFC4C7C49B360D02112A62A0B9C5BAB1680A00000B206EB2D4E0E4D5C4802C00000B4990C6CAD3CDBF983A081354A2C7CAC6BCC1BE9C3F0000176397B9B9B9B4B6825060733920326E979F7664768F65256878A0C9FFFFFFDA8258483F4255A4F0FFF4CA9B5731323C333963BFF2EEAF69381F273A344684BFD460C2C9934823262937407CC8FAFFE5943E2E2D34373454FFF4CA9B5731323C01FECB5E070718B07441282E376096BACAC7CDB1875F626B7084A1AB9D81828E742B0000022965A2C9D6CCC6B785380000002D89C6D9E0D2A04C0000003196CFDBD9C5B47D1E000000388FBFD1D5CBC18A2900003D87B4C1C6C3C496410C0C19306C9EB8C1C2AC69090000082976B5D2E0E1E0CA89270000195D9FC4D8CCBABB7D32051755A3C9C9CCB7C2B38C390000125AA0AEB3B2C1B17D5D6A6D2C1D396F9D9C7A6982776C23757C96C7FFFFFFD38D654E434C60ADECFDF3C48B5E3B1E2E37366BC1FBF8BF753F27282D354B8DC7D15FC1CF904A242828384788D3FFFFDA8F41303834354058FDF3C48B5E3B1E2E01FECC5E070718C0703F242C436AA0CDD8CFD3BA7F5C5B66708FB4B29181838F762F0000032B5FA9BFD6CCCAAA7E310000003F96CEDBDEC6A4480000003999C8DBCACABB7D22000000449FCCDCE2D4C1771F00004891BECABDC3B3903A0D01113878A7BDC1BF9D580800000C2D73BAE8D8E0D5C67A240000285C9EBCC2C5C6C98C3603196AA5CCD0C7C4C2B0752B01001C6BA2BDB9BEB5AB7A5166723B184380989C7C66718456147A7B99CFFFFFFFBE7A4E46474B61B9F2FFEAD383523934232E3771C9F0E8AE64362E282E364F90CBDB5FB8C49246232021394389DCFFFFE59045292826283E50FFEAD3835239342301FECD5E070718D0794E3B404874A5CDD1CFD8BE845C5B6A6B94AFC29D7E829B752D000009346EB3D4CECDC3AC7325000000348FD4DED6D09F47080000358FCFD7D8CCBC6D220000004498CED7D8CDB36F18000D4B94D2C3C4C3B784280F06113A7DA5B6C4C0A55001000012347CBFE1ECDADDC1811A0006316CAAC6C7CCC6BE7B27001D5FB0CECECCC1BCAB7D2500001864A7B5BEB5B4A56E4C67673018447C9FA57960757F48097986A9D8FFFFFFD07E595341426AC2F8FFE6B5805A3E2F2E3C4679C2F4E9A3593527202A335999C9D85FC5D38E49251B29334C8ED9FFFFE3823D3034362C324CFFE6B5805A3E2F2E01FECE5E070718E0775252545C7DB3D6DED9E2C78665606C769FB1B497807D896D320504083474BAD7D4D7C7AD6A230000003FA8D6E0E7CBA24106000043A8D4E0D4D0B77C1E00000048ACC8CBDDC5B06412000A4C9BCAD5C9BFBB892C0400133A80BEC3C4C4A14D000000123B81C5DCDADFDBCA841500072D6BA8C0CAC3C0AB7123011F66A6C4C9C2BCB8B16E240000236EADBEB3B9B8AE7261746833204E84999E775D6E715300787F9FD7FFFFFFB67C5C4D48436FBAF5FCDC9F774B362131313E7BD3F8EBA75C2E252E30445F9ED2E468C4CE873D1C1720264096E8FFFFD57F392F302C3A3756FCDC9F774B36213101FECF5E070718F07458484B5686A9C9D8CCD7BC7151585D72A5C3CAA58D898262210200103670AFD2D7CEC0AA67260000003F9DD6E0E1CEA34B07000040ACD7DED7CCB275140000014AA1CADFDDCDAD6613000C5BA4C9C9C3C8C28C2408000D3A8AC2B5C8C196470000001B418CC4E3E1DBDEC371180009396CA2B8C5C0C3AC6A1F00216FAFBDC4C3BBB9B36B120000347EB1BAB1B8B2A37958705E34214F8CA2A274546B6F4D006B729EE5FFFFFFB96F585A484F74C0FBFBDDA8744C2D243A393F84D8FFEFA85A30222C323B65B1D8EC62C3C7832F20261E264498E1FFFFD77F442D3A32364358FBDDA8744C2D243A01FED05E070718006F5D415A6D88AFCDD3D4DBB2664D4E58719BBFC6A5867D855D1F00000E417EBAD4DEE1CEB06A2300000A46A8D4E8E7CA9C450000004BA8DCDACEC2AB6F1300000A55A5DAD3D4CAB15908001253AFCEC9B9C8BA772202000A408CB4C0CFC89848000000174388CBE1DDD8D6C1721900073A7BADBECEC4B8AD7016001F6EB3C7CEC8C0BAA85F0C00003587B3C1ACA9B8A7784C675A372B5C919F9C7150677540008F849FD7FFFFFFBE7355534F506FC3F8FFD19D60432B1E30384081D7FBE69F503833292B386BAFD6EF6EC5CE8336191820334B8DE6FFFEDA7C31222F2F323A54FFD19D60432B1E3001FED15E070718107C6951577295AACDD8DADDBB6E5152566898CAC99882796A4E18000B164998D1DDD0CBC7A1571B0000194FA6DFDEECD0892C0000094FA9D6E4D9C0AD69080000135BB0D3D4D1CB9F4D05001863A2C2CAC4BDAB722300001D4C95B8CAC4BE8F3E0000001D4891CBE0DCDFDAC57A2200084281ADBBC7C0B8A5631803257BB5CACAC5C7B8A75C0400003987B0B7AFA6B9A4735771632E265D94A9A06D485B6830007B7EA5DDFFFFFFB76D4F484A4A85BEF3FAC8895C3D3232323B478BD8F7E3984E2E22262E3A6DB9E1EF70D0CF8C36201F1E3052A0E8FFFFD177332A3938363E5BFAC8895C3D32323201FED25E070718206E5849586794A5C2D9D1D8BB7148464F78B5C6CEA97E766C451100031E4C94CDDEDCD1CBA04D0E0000094DACE2E7E8D08E3300000C5DB0D5E2D8CBA5560A00000565B1DADED1CA9A550B001867B0CDCFCCC2AF6D1E0006104897B7C3CBC18940000000215894C8D9E0E2DAC66C1000174287B7CFCBC1BDA2521100328DBFCEC6BDBBB3A25B0A00003B8DADB5A5B3B1986F596C57262B6593AE9C694A5C663100726E92DAFFFFF89F615A55484D7DC9F9EEB57C4C393726323F448ED8FFE4954F362E262C3777C1DDE96AC9C7853D1A2226274DA1E9FFEDCA6E382944352D2D5EEEB57C4C3937263201FED35E070718307461516A88AFBFCCD7E0DCB66A41435470B1D3CCA586846E44180006215EA7D9DFDCD0C49F421000001656A4DDEAE1C27F2700000F60BFDCD9E1CBA35A0800001267ADD5D9D8C49C4E0A00176AB1CCC5BAC5A96917000014589ABDC4C5B8853500000627529FDBEAEAE5D8BC6411001A4E91BABDC0B8C7A75D15002F7CB3C7D0C7C7BC9E4C0000014395B6BDB7B0AB905E5B6C542B2F6C95ADA067464E5A310077799CDCFFFFEBA76348554C487BD2F8EFBD7F513F382F333E488CE3FEDA894E362F29243D71C3E0F973CAC8823F242521254AAAF2FFF4C26B31273E3735375CEFBD7F513F382F3301FED45E07071840696251657FAEBAC0D7D7DDA65E3A374475ADD9CDA0897F6D451308082154A5D5E2EFE4C994470C0000165DACE2E5E3C77A2A00000F5DBAE4E3E8C29A470000001861B5CFDFD1C2944305001A6DB3C2C6CFC1B965130004114A9EC2BEC2B4853A000004335D9FD2E5DBDFDAC261160025619DBBC3BDBABEA84D07003585AAC1C2C5BDB79E4C00000A4E92ACBBBEB4AB9064557F5D352F669FA8A26C4C5457180077709BE1FFFFF4995B4955444685D7F1E5B7735237232723315397E1FFDE904D31282A334280C5EBF274C9C687351D191D2456B2F6FFFAC2732F2C4946303E60E5B773523723272301FED55E070718507467637192B0B3D0E7E7D9A25F39334D6DAAD6DDBA9581683A130310275EADD9E1DAE0D19D450E0000205FB3E7F1E7C16A1D00001069BFE1E8E4C89F460000001C6FB3D9D8DEC98C3B02032973B3BEB8C1C8A35D140000144F9FC0C1C6B681320000133969A5D9E5EBE2D2B26512002A699EBAB8BFB7BB97430E023183B9C8C6C2BEB89A430200085897B5B6B1A9A9956259774F333E71A0AB9A5E43535323005E5B88D2FFFFE08E48443B304080D1FAE7A6684B2F25212336549BECFDD88E5034221E264185CCE5FA74D3C37D35211F1D2250B1F4FFE0AD5F2B284338374374E7A6684B2F25212301FED65E070718607E6D5D7994BFC5D5DBE0D69C573841527CBBD9D7B59086683E0D03032665BADFE7E6DFC591441200001D62AFDEEADCB66A1C00001C67BFDEE0CDB2944C000000277EBDD8DFD8C0873700002C7CB2B9B9B9C3A3601C00002B5EA0BDC0BDAF722C0000184179B5D5DFE7DDD5C15D0B002F73A5B5BEC6C1BA89420800468CBCCAC7C3C8BD973500001460A7BBB0A3A8A5855B5A6F5133457596A593633D4E491900646690E0FFFFD8874E474C444A84DEEFDAA06647312D291F2F4CA0EBFFDF85492C25182D4B91D4EEFA7CCEC3752F1F2316244DACF0FFF5B6632A29494236396ADAA06647312D291F01FED75E0707187061515A6FA2C6C4CACDDCC8914731334C79B9D6DAB792805A3005030C2F7CC0DFE4D3CAC491390800011B6CB5E2E2E1B2641800002678C7E2E0DDB3863B0400012A80BDD4E0D6C07A2401012B81BCBDB7C3BF96520900001F5EACC4C2C5B0711D00001B5386BFDAE3DCD7D1B3520C00307EB4C8BEBBAEA77B340003559BC1C4CDBEB5B7954200001A64AAC3BBB0A4A4855D516853363F859F9F976236433C02006C6A9EF1FFFFE48C53494D4C4E90E4FDE19A683E3025262E385EA1EEFFD7804F3F2A22264484CCF3FF76CDC375311A1C192256B2F1FFE4AF662927504B313A6CE19A683E3025262E01FED85E07071880736F7389B0CDCCCBE1E7D89A522D2F467BAECFD2B49E7D4F2C0E0A143C7FCAE7EDEBDACF8A3D0300032974B4D7E6DEAE681200062B7FC6E1DAD5AE78300000002F88C3E2DADAB4753004032F94B3B5B4BFBA93520D00052059A9C2C6CBAC6D2400072A5F8EC4DDE1E8DBCCAD510B003980A5C2C1BAB1AA782B0007549AC9C9BEB7B5BF8F3300001C67A6BBBEACA7A1805C5E784C314D83AAB4A155353924010067659BE7FFFFDE804A4B47414E9CE3F4D1915B43433428313C62B1F4FFCE6F3545352D334998D8F2F770CBC57633221918234CABEDFFE8AF5A2D26463B39447ED1915B434334283101FED95E070718907370648AB5D4D6D9E2E8C9873E2E284880BDD8E3C4A6834A2612071D398CD4E8E0DDD4CD8B310700002A6AB8E4E5E1A05D0D00002681C4E5EAD4B07C280000003C92C3D4D4DCBA641F00024285AFB1B2C9C5934B0100002260B3CDC2C2AA6326050E366B99C4E4E0E9DDD8AE5206003D81B3C2C3C2B1B3802D00074E9CC9C9BCC2B2B08D2900002170A8C2B5A9A998745462674C37527D99A3905C3C3C3B000062649FE6FFFFDA8C474A524D4498E6F7D28E5630362D232A3A5FA8EEFBCA753F35392E2E55A4E1F1FF74C1C37C2F16161D2354BBF1FDE3A45821254B312B4379D28E5630362D232A01FEDA5E070718A0787B7B8EC1EDD8D4EAFCD18E402829437BBBDCDCC5AB8450250B0E1B43A0DCE4DAD9D3D091390300002C6FBCE3F6E3AD480E00062982D3E5DFCC996B160000063893C5D1D8D5B4621900063C8DBFB6ADB9BE893D0200022A68B0BECCCAA5641D05143E799FCBD8F0E1DBCDA74B0D145293B4BEC0C4A89D6D2200084D95BEC0BFBEC4BD931A00002174ABBCB1ACA8997651566344415F8DA2A591633E412100006E78B2F9FFFFD691513F574A559FE4F0C68E5A3C30282B2C496AB0F2FDC77A4A4C422E355A9FCEEDF970C1BE74381617141D52B6F0F9D6924D23284F40364287C68E5A3C30282B2C01FEDB5E070718B0756D6683C6E6CDC9E4E2C17B3A26284471B6D6E6D0AA884B270F151D458CD7E6DFE1C9CB92421000002B7BBEDEE6D5A14A0300033086CAF0E8D1A0601600000C499AC3D1DBD6B9541400054591B5A9ADC5B5853F05000B2270B0C8D3CBA14D14000C3377A7D1DCE2DADCCAA643000F5196B8CAC4C2AEAE6821000C66A4C4D2C2C1B8AC812600002D83ACBAB0AB989C74545E5F4743688A999D97573C3F2000005F72C0F7FFFFD38B4C465142509FE6F1CA7F56372D2A27323A6CB5F5FFC36B434736293464A7DBEEE86DCCC67E3A1624211653BAFBFFD18F4E212542433D458ECA7F56372D2A273201FEDC5E070718C08072719AC8EAE1DFEAEEBF7A3A222A467ABBE8E3D7B58844200C0F23549BDBE3DBDCD6C98A35060006337BC2DDE5D6A24C0700062B86D1EADBD69D510B00000F53AAD3DBD9CDA04908000A4B98C7B1ACCCB87233000100236CAECED2CB9D4E0D081D4B8FB5D2EEE2DEDCC39D41000B5094BEC0C0BBB8A16516000867AABDC6C7BDB7B6822500003483B4C0B7A7AB92634C5364424768929CAA9D552B301400006076BAFEFFFFCA7B5151524A4EA4EBF2C67A442B2C3228343668AFF8FACB6C4D58472C3163A4CEECEF6AC5BE77372C1A182B5FB4F2F8CC89462627464030449BC67A442B2C32283401FEDD5E070718D07473668BCAEDE6EAE2DFAF66301D284978B9DFEDCFB7964A25101222559DDFE4D9D5D4C591390B000A3080BFE4EDDC9240070001308BCEE8E3CA99520B0000104FA5D5C7D8DEAA480B000F4F9FC3A8A9BFB46E280000033570BCD9D7CB9A501D00205895BDD8EDDFE1DECFA03100065898BEB9BFBFB5A25A1200115AA7C6C6C0BFB8A87E1C00003F8CB9B7B0A8A28E64415861444D7299B39F9051302A1D00007080C9FFFFFFC98053405A4A54A3E4F7BE7B4C39332B32394367BEEBFCC97041524131396CB6DFF0F76CC2B27737141016225EB8F4FCCA8448292C4332314697BE7B4C39332B323901FEDE5E070718E06A767998D8F3F3E5F1E9B060332425487EC0EFE0D0BC89462517151C53A1DADEDADFD5BF88440E00063C7AB4D2E4D491400F00003996D0EAECCF88440500001258ABCED0D3CC924210001450A3C1A8A6C6AB642300000A306CC1DAE0C3984E1C00185498CCE2E7D2DCCFCF933A05135B9EB3C9C1B9AE9E510D001666A6C1C7C3BDB7A77F1E0000488FB5B3AE9F9B945F4A5C5C4A51759C9DA58E5B2A2F0C00007684C7FFFFFFC37942465D5362B8ECF4CF784A2B222B30323A72C7F7FFCB6B44564C334070B5D5F6FF6BBDB46E20080D1D205CC7FCF6CD823A1B2743413D4CA0CF784A2B222B303201FEDF5E070718F0787C75A0E0FFF4E9F4D8A15D321F274776C3E3F2DBC58B4A280C132758AFDED5D9DED9CB934213000F387AB4D5DEC794430600003F96D3EDE5C4872C0000002168B5D3CED6CD8B2E0000115EB0C4A9B3C5A95A2700000C2F79BAD2D9BC863E0A001B60A6D7E9E4E2DBC7C79730021366B2BCCCC2BBB69D460B03146EB0C1B9B8B8B5AA761800004790B1B7B19E9B85514B5E61465680A2AAA38C5530200500006982C7FFFFFFCF7B3B49584E65A8EEEFC1814E2F262528364777D1FFFEC865425E52262967BADFF6F568BBB0692A140D1E3369C0F3F9C87338262342373D53AEC1814E2F2625283601FEE05E07071800747F7FA4DCFFFFE1E4CBA254221C2C4986BDE1EFDBCF94462711102865B6DFDFCFD9D2C78A360C03143F77B8DCD6CF9341090005429ACDDBDDC385320000000E65BBD8CED5CA8F2B11001860B0BFA4A6C2AB572209000A2F7DC4DED9B77C370300286FAED9D9EEE3DBD5CA9536070F5E9DBCC2CCB9B9904500002276ACCAC9C5BDAFA37412000A588FB5BBB6AA997F543F545E4C5C848D97A2925D3626020000738ADBFFFFFFCF7B59515B4F71BAF5F1BE77533830332C364E7DC8FCF5C762425E4C273474BDDAF0F568C0B36B32191413216ACBFBEFBA6F3B2124353B405DB4BE77533830332C3601FEE15E070718106E7075AFE3FEFFE5F2D39A4F2422214580C5E3EFDBCB96481A1D1E2753B3D2D3D8D2D4C88D3F12000D3882B8D6E4D38F3A0000103F99CFE5DECF842B0000002074C0D2C5C4C58A240000155BA9C8A7B0BE994F1A0000124383D0DDDAB36F3209052C75B6D8E3EBE9DFDBCC922F001975AFB6C4C3BCB1944200003082ABBBBCB1B0ADA77D180005589CBBB2AF9998784B4952575D6893A39B9D8F5F41280000007290DCFFFFFFD67E53544D4959ABF0EBB475423B3A363B3D3E72D6FFFEBF5D515C5634427CC8E5F7F45EB0B26F210D1015286AC3E9EAAF75402121323D466DC0B475423B3A363B3D01FEE25E07071820756976A0E2FFFFF6EBD68F441E1B1F4F82C4EFFAE3DA903E22191E2E67B3D9D3D1D8D6C996431E081A4178B6DDEBCC7E26000000479DD2DBE0CD82220000002176CCDCD4D3CC7D2100002A67B7BCAAB1B991481901041D3886C7DDDAB36F2E08002277B5D9E6EADFE1D3C28C29001D6FA8C2BEBCB9B6903607002E87BBCAC4C0B5BCA36D16000A5A9CB9BAAF9F956F44435C61597190A2918A84534529000000768FDBFFFFFFC774473D564686BEF5F3C67643313333252E427FD0FCFEBA6746635B304478BAE4EFF15CB2A760221312232A7CD6F6ECA86E311F0B31353E6BC6C67643313333252E01FEE35E07071830767275AADCFFFFF7F3CE8C4618162F4A80C9F0F8E8DA9F442C1F1C2659B7DED6D0D6CDC4984A1C03113676B2CFD9D1882900001A519AD5E6E2CF851F0000001A75BED0CDC3B4752000002A6FBDC0AEB4BD86411506081A4A90CED9D6A8682302022B7CD4E9EADED8D2CEC28E2802227FB6BAC1BDC0B78F3400003078ACC3BFB3B7B6B07208000960A1BCBAB49E966E3C41616551709E9F988C855D49220000006E7CD6FFFFFFC4755444495478CFFFF1B76E4634333B37374D82D1FFFFB55E4B6855384186BFD7E9E455B49B5A261800193B81D0F3EDB169402924413C3E75C8B76E4634333B373701FEE45E07071840787B7FB1EAFFFFF0EDC8823B14172A518CC4E2F0ECD99E4F3123272A70AFD3D2C8DED6BD874B2006193C79BAC9D7C8862B00000D47A1D2E3D9CD7A140000002983DFDECECCB9681200021F7CB4BCBAB0B6933C1300021C4C8ED5D8DBA6540F0705348DCFE2EAE3E6E2D5BB8A19012075BAC5C3C8B4A6873100003290B7CCC3BCA2ADA77110001068A1B5BDAAA3986F3C3D55575A7697988E8C7E5D4A1C0000007A9CDCFFFFFFC17D554E57506FC6EFE3AB6340383839363F4483D7FFF9BF5F486249304188C5D7E6F157AA9D64221314173185D9FFE79C5E31222A3A354171C7AB6340383839363F01FEE55E070718507B7980ABF0FFFFFEF9CD7A3A1F1E315D96C9E9FDEED79550372B242F6AB0CACDD3D9CCC78B4B230E1B407CAEC7D6C57A2600001545A2C8E4D7C47417000000308CD1DDCACAAF5A1300003578BBC1A7AFBB863A0A0006194B9FDBDDD1AE4D1401083383CAE2ECECE8E3D3BE741E002778B1C2C8C3BAAB822D0006408FB6BFC9BBB0B3A76D14001F6CA1BCBDAA8E8C5E403C5B5D5F819FA18491876B422700000074A7FAFFFFFFC184514D494675D0FCF3B9634235382D2E39498BDFFFFFBF64496F5E38468CBFDBEBE852A08A5A260F18183687E1FEE49D5A312A3135354778D6B9634235382D2E3901FEE65E07071860777386AFECFFFFFCF9C0713B181B335994D2F2F7F0D990433A36222860ADD4C6C5C9CCC4874B2F10203E6AB5CDD6C5802A00001851A1D1DBDEC36F0F0000002A90D2D8C6D3BD5F1000023188BEC7AABCC483230000001865A8E0DFCF9D4A19000A348BD1E9E4E0DFE2D3BA6F1A0C3484BEB8C3C2CCB5851C00003C81B7C1B9B2AFB3AF6F11001E74A6BEB9AA9189653B455A545D7EA59D8C9C8F644A230000007CA5F0FFFFFFB369463D384875CAFAEDA9614330313B32374484DDFFFFBF604E695533438EC2DFEBED4DA48D531F111A233590E5F5DD8E512E1F213C314983E1A9614330313B323701FEE75E07071870747B85B0E1FFFFFCF5BB6535161D3C6AA1D3ECEEE9DD914E413A272965AAD4CFC8D4D2C1924D2516274275B3D2D1C0702100001456A2D4DED8BC68100000002E8EC4D3CACEAC4F0F00023C88C4C0B6B4C279270000051E5CA9DEE4D49546060007448FCEEBE8EAE4D5CFC07415002C8EB3C3C4C7C2A9721B00004392BEBEB8BAB3AFA76313002477ABBCB4AB9C82532A4263516E81A3987E938F6D4E2F00000077A9F3FFFFFCB96E4D4B43476EC5F2E29B62472C36323D404C92DEFFFBB85C466554374E8DC1DFE8EC56A18950181616204790DFEFD7914C31202C313F4C8BDE9B62472C36323D4001FEE85E07071880727582B7F8FFFFFBF3AC672C1C223365A5D7EFFCF4D99A624B41362D66B5D2C8CBD8D1C48749200C234577A8CCC6C372190000245EA7CED8D6BB650E0000002F8BC8D1BDC1A8470900083C8EC8CAB5B5B7792F0B00002863B0DBE5D18B2F01000A3D96CFE2EDE4DBD5D1BD6F1C072F83B3C2C1BFB9AB74180009549ABBCFC7BCB9B09B5D06002872ACC6BDAD977C3F2A3C625A7790A490738A8A71613500000076ABF6FFFFEAA6664B403C487CD6FFE89A58412E27322F334A87E6FFF8AF5D4C6051414A8AC6E5EBE5589F784A261C15214094E5F7DC8E4821191E2B364B8BE59A58412E27322F3301FEE95E07071890737E8FC1F4FFFFFCEEB667341F24436CABE5F0F9F8DB9354524E363A6AB3CCC6D1D2C4B57F4B2D172C5084A5BEC7AD6A2500001A60A7D2D9CEC0690C0000002B92CDDFC6C19E3A00000D3B86D3CEC2B8C070260400032969B4DDE9C983310600043C98D6EBE2E9DED7CDB16515064092C3C6C1C1BFAD6B1A0003519DBFCEC5B8ACB0A26108002B7BA1B8B4AB906E432C465F57648DAB9269819881693400000083B9FFFFFFF3AA6E484548487DDAF8DE905B3E3A332B32444E98F3FFFFB263475554334B90C6DCEEEA4F987144231D1B24449DE7F6D78F40322A22353851A1F6905B3E3A332B324401FEEA5E070718A072778CBCF2FFFFFFEBAA582917223A75B6ECFFFFE7C58C57494C38306AB5D8D3D0D1CAB481481F1F2C4F83A6CACAB3641E00002A5FABC7CAD0B1660000000242A4D6DCCBC09A3A0000104E94CBC4BBBAB776190000082D6CB5D9E6C07E320000003F9EDBECE9E4DBD6D0B35A09094BA0B9BAB5BBB4AC63060015599EB7C3BFB9B1B29B560C003188B0B4B5A89A73462A4460596E90A68F6D848A82672F0000007DC1FFFFFFF5AB5E473D3D498FDFFFE79B5A3E2F38333C395491E6FFF3B7594B6651365191C7D7E6DF568F733A1E1F181F49A1ECFFDC83462F2727373F53A2F69B5A3E2F38333C3901FEEB5E070718B0768197C7F7FFFFFFE69B562B191D3B73B8E8F7F8E7D08F5F5F5C3E4376BFE1D0D2C8C1BB794C3022335479A9C2C2B1661700002F6AABC6CFC0AD6604000000388ED4DBD0CA983400000952A2CFC3B4BEB0661C0000063372B7DBD5CB7A290000003BA4E1EDE3E3D9CAC6A4561410449CC3CEBFC1BBA7660D00095FA3C0C9BAB4B1AF9C4B00002B81B1BDBBB599753D27395B567399A38B748C8A846F2A00000084C7FFFFFFEFA2623B353A4682DCFCD38C574032393C3D3E5299F0FFF6AB55505B56364D8BB7D3E7E5559074452513252B52AAF0F6D7803C2C2E28342C4BB1FD8C574032393C3D3E01FEEC5E070718C07F7F96C0F7FFFFFFEEA15D35272A5189C0ECFFECE4CA8F62696644366ABBD6D3D1DBC5B17B462622325D7F9AC3BEA6611A0000346CA1BECECAAF56000000043B9DD2DEDBC48D2B00001C5AA6C7C7C0C0B2641B0200093E7DC0E5D9BD71210000053C9EDCE6EADFDACDBC97470605509DB1BDCBBCC3AC610D00166EA2B3C0C2B8B7B8954300003687AEC0B4AA94663C253F646987A6A78A738797836E320000008FD5FFFFFFF0AE6E453D425A94E3FFE59950482E2D413D3B5B9BE4FFF6A55A4B5B4735478CBDCFE7DE4D8B723F291D28285AB8F7F6D27F4435272A343D68BAFC9950482E2D413D3B01FEED5E070718D06E7A91C2F7FFFFF4DB89511C19285685BEE2FDF7E3C98C566561393468B4CED3D0D1C1AA6D4B2923455E91B4C5BE99580E00002E70AAD0CBC1A14C04000001479FE7E8D6C282200000115CAACBCDB6BCA6580700000D3E86C7E7DAB6732700000A43A2DCEDE7E7E1C3B797520C1048A2BBBEC2C4C2AA540000196BAFC1C6BCB6BBB1924908003889B2BBB3A799673E224B615673A0A27F69809B86702C0000008EDAFFFFFFEEA76B4D453F4D9DE4FEE8975139342B352B3554A6EEFFEF96554B62493A4C87BBD8EBE652876D49271C29275DBDF5F5C67D432B2E27394263BAF5975139342B352B3501FEEE5E070718E0727E9AD0FFFFFFFFDC8A43231C335494C2E9F0F2EBD28F6A706E474570BBCED6CAC6C7A46E4B2F2E456385A6C2BDAB5B0D000033679EC1C5C19C4902000004428DCBD7D6C3791D0000216CAEC9C4C4C1AB5D1900000C438CBFE1DDBA651500000243A5D1E3E0EBE1C8BA913C0A1757A8B7BDBBC0C4A14300002E7EAAB8B5B9BBB5AA913E00084B8DADC0BBB39862382C4C63607C9DAE906C8B948E762E00000098E5FFFFFFEA985F453738458EDAFDE0965B47392E2C34364FA7F8FFEC9C543E5941314B88B8DAE9DF4E7F5F342F20203061B8FDFDD3773B292526324070BAFC965B47392E2C343601FEEF5E070718F0797E9EDAFFFFFFFFD3814C1D1B325DA5CEE7F5EFEACC8560838346336EB5C7D5C8C9B69A6C3F38364A6992ACC1B3934A0C00003877A9C4C4C0924600000004499ECFD7DBC2770F00001B5FA8D0C8C3C3AD6B180000115299C8DED0B0661A00000447A5E1DBE0E7DDC1B28A440C205FB3B3ACBCC9BF973D0000297BA6B7C2BCB7B6AF914300034A99B5BEBFA6875526274B5C5D80A5A5866688938F782C0000009FE3FFFFFFD8A462503D3C498BEAFFDA955D3C29232C36425DADEFFFE9A4553A483D314F81B7CCE8DA4F7E5E35251B222864C7FDF6D1813E2B2B2C3D4879CCFF955D3C29232C364201FEF05E070718007083A4D9FFFFFFFFCF853C201B3065A4D5E7F1E6D8C38971878A584B74ACC7CCCEBEB39A653F293F58738FA9B9B79E4E0C00084883ADBDB9B091430000000B4D97D5E3DCBB680800001F64B1C9CCC6BFA7650F0000195398C5DCDAAE591000000047A2D7EDEADCDAC3B18338091A64B2BCB6C1BCC79B4000002B7EAFB8C4BFB5B5AC8C300003519AB6BFB5AD915E25274B5C63839CAE8D77869E93732300000093E9FFFFFFDC8C574B393D4C9DEAFDD98A4F362A303037465AA8F9FFE89C4E475347304F8AB4D7E8DD5C7D583E21191B2A70D6FDFDCB7541382F35394671CDFF8A4F362A3030374601FEF15E070718106F829DD9FEFFFFFFDA79341A13336FA9D8EFF2DED1B87E68968C514074BBD4D6CCCAB48A65433A39587E9FA8B5AE94440D000E5486A7BAC1BE9237000000144D9CD6E0D6BE69080000286EBCD1C7C8C6A6550E000019559BC9E0CBA75C0C00000651A4CEE1D8D7DAC1A4742E0B2C70B4B0B6C1C2BC8A3500002C88B8B9BBBEB9B5A2842A000A549ABCC4B6A78D51232243585F86A2A08E768E9F9A7B280000009AE9FFFFFFD78C5C4035364D9EF8FFCF844F37333032393957B2EFFFED9F4A3B493B404B7FA9D3DCD6597650341F212A366CC9F3FCCC7D3F2F282E2A4485D5FF844F37333032393901FEF25E070718207C8BB0E6FFFFFFF3C36E3423203D79B6D8F3FCF0DEBB7A6F979A5A4B73ADC3CAB9BDB58A5D382F43667C9AA9B8AD964B1D00044686B3BFC0AE822B0000001852A6D5DACFB5580000002175B8DAD6D5CBA45404000012579ACCD9CAA762140000074CA3DBDDE1EAE2C29F692C0E3476BDB1B1BEC5B78A2D00003D98C0C0B9B3AEB9A78835001754A0B9BFB4AA895627204D575B88A8AF88718F9F9B771E000000A4EDFFFFFFD4945F4A43455CA7F1FFDC834834282B32364660B9FFFFE493514142382D47729DC1EBD452785B342A302D3C79D3FEF4BD733A302B333E457FDAFF834834282B32364601FEF35E070718307B85ADE8FFFFFFFDBF6634221B4483C0E1F1F7ECD1B78475968C51497CB4CAD4CFBDB5855440395171858E9FAAA28F43090017578AA7B3B3BD832E0000001B549BC8DBD5B256070000347DB2CCC8C2C39C580A00001969B3CDCED1AA570E00000B46A6DCE0DBD8CDBE945E250C367DBDB1ADB2C5BB8E340000418FB5BBBEB9A9B7AB7F2707155CA7BFCDC2B790532629475A5F7BA0A08E7C8D989B7A25000000A6F8FFFFECCD8F5E392C374CA3E4FFCF7848342B3030364362BAFAFFD785493A3A3D364471A3CDE0D7657D58382B2F22307AD4FCEFB670402B292F3F4687DAFF7848342B3030364301FEF45E070718408290B6F2FFFFFFFBB258311A214E96CEEBFCFCE1CFA576809D955B4874A9CBCDB9B79E764E3B33587C8599A9ACB280421100116496B3B1BBAF73250000001E63A7CDD9E0B9510000093D8CBDD3C4C5B599470000001B69B0CFD8CAA5520500000A49A8E3F3E7DED7AB8C521A0F3B85BAB2A8B9C2BB812500004395B6BBBFBFAEBAB1802A00245F9AB4C5B7AC8A50231F4660627EA3A89681939494741A000000AFFAFFFFF5CB8D5339262A4EA4EBFABE783E3422302F324764BEFBFFD793462A353230486AA1CCE2CE626844363025222F86DAFDF6BE6D3C372F383E4381DBFF783E3422302F324701FEF55E070718507680AEE8FFFFFFE6B161301C1F3E97D2F5ECE3D5C5A16E709E9B57466FAEC3CFBCB3A3744D3B3B5A7C93A2A8AEA47E3D14001A5F9EB9B3BBA96A1E0000002358A3D7D8D0AF4500000C3387BFC3C4CEC1A8580200002770B1C2C9CD9848090000104B9CD0DEDEE1DBB08847190F3E92C4ADA3B7C7BB7F1E00024CA3BFC2C5C1B1AEA6771F052671ABB2B6BBAF8F511C183B525A8BA5A2847F9AA49D661E000000AFF6FFFFF4B1764C3522234AA6EAEDBB76382A1F24302A3D76BDFFFFCE85452425362C48609CCAE6D86A774D352421304085E0FDE8BF76392B2F313E5A9CE7FF76382A1F24302A3D01FEF65E07071860748FBFECFFFFFFF7B2542713204F9FD7EAECE4CFB5936C7EA7995F4D72AAB9BFACB59B66432D3A608B89A4ADB5B68D46160A1C5F93ADADB49F6D190000002663A4CDCBCCA5430000044C93C4D3C3BDB89D540A00002173B6C9D2C48E4104000003439AD2E0E7DBCF9F7C3A111D509EC3A4A9C2C8B87C2B00054DA4CDD1CBC2B7A9A1731600266EAAB9B5ABAE8B4E1F25414D5883A9B196899B978C6019000000B2F3FFFFE1AE7A402F24224EA6E5EFC76B44371E313625366FBDF4FDC4713A2B2A33303E6195D1EEDB746F513437322E3E91E5FFEBB1624335333140639DEBFF6B44371E3136253601FEF75E07071870728DB7F6FFFFFFF7A45023152252ACDBF5F0E4C2B4907380A9995E5477A9B6C2AB9F91613B353564909FA8B0AC9D7C421A0825729BB6B0C0A15A1D000000316BA6CFD4D8A74000000E439DCCD0C1CAC49E45080000247AABC9C5C18F3B000000054A9DD7E0E0D7D1A674261521549CCBA6AEC4CFBB7623000A5CA9C8C6C4B3B1B49E6619022E78AEBBBCB8AF844621153E434C82A4B0A09EABA2966717000000AEE9FFF3CBA36F41261B2541AAECEAB66836281D2B2E333A6BC6F8F6C77833222B23293A6294CBE6D177784C43232D314D93E6FFE2AB57382927273F55A5F1FF6836281D2B2E333A01FEF85E070718807284C0F6FFFFFFEB9A482617225EB1E3EDE3CEC1B2916C8AAE98614D7DA6B9B6A4A087573B31386B87A6ACAFB4A27947170C28759BA7A8B69C50100000003273ABC9DACF9F390000124FA0BAC8C0C1C39C51120000337EC4D3C3BB84370000000950A4D2E6E4DBC79F5C1C142659A5CFAEACBDC3B0701A000B57A3C7C9BEACA3A8A15F18083E8AA9BCC5BFBB964C1A0F3E3D5283AAAFA293A0A1946819000000AFEBFFF2C3875F2E211D1946A3E1EAB763302A26202B344173CFFDF1B873362320282F455688CCE7CE756E513D2A2A2A469BE8FFEAB169302D2C2E465DADF4FF63302A26202B344101FEF95E07071890779AD1FFFFFFFFEB995223162969C0E4F4E9DECEC0936B8EA99A625584AFB8B39C91704B301F3E749CA7B2BCAE9D7441210C33769EA5ABAE994E05000000377DB5D6D6D1A33E00001162A5C6C9C0BEBAA4500300003385AFC8C7B07E33000000034AACDFE2D4DDCC975B180C256AB0C5A8A2C6C5B97720000E62A7D0D6C5B0AFAFA16017083B8FAFB5BEB2A983411423343F537EA5ADA8A29B9A896111000000A4CFEEE6C68750251212193FA5E7EAA85B2F201A232729316BD3FCFAB469362A2828293E5380C7EBC47F78463729312B3E9EF1FFE6A856312C322C335CB3F8FF5B2F201A2327293101FEFA5E070718A07091C8FCFFFFFFED94431B15246BC5F1F0E7E0C2A57E6A929C956A5D80ADBEBBA2846F3A1C243D7B979EAFBAB4976A3F290C2E749FAFADAD924C0C0000044B7BB4D2C8C99B3600001562A7CAC9B9BDBA9C3F0500003784BAC8CBB47D2B0000000B4EA2DBEADFD3C18D4E1C173982B6C3A0AABCCFB76816000D68AACCD3CCAFAEA88D4F090A4495AEB1C2C3B1883F141D3B395794B0B6B0A1A3A38A590B000000B1E8FCE3BC7856271111184CAFEBE2A7553023232527203B7FCCF8F1AD5D2F21252B31475882C8DDC07D72453827292742AFF3FFDDA256322A313C3C67BBF0FF553023232527203B01FEFB5E070718B0708DC0EEFFFFFFEC9D4C150C216EB9DFE6E9D4BDAE856B87A39A745C7BA0AEBB9F90713D1A113675939FAEC4B7955F4524132C799CABA8BE9144000000074B7EB8E3D6CF992500001969A3C6C7C3C1C59C40000000418DB3B9CEAE7D330000000D49A9D6E8DEDBBB854615072F80BCC8A7ACCACDB25C1300156CABBEC8C7B5A8B4964911125A94B1B7C4BEB1853C152138404B83AEBCAA9F9A9D8B530B000000AEDBE8D69E6B451009090845AAE9DAAC511F1A1A21232B3F7DD7F5EFA8572D231D323B405786C4DABB8D6F453224282E4FA8ECF7D7934F28282A35496DC0FFFF511F1A1A21232B3F01FEFC5E070718C06695CCFFFFFFFFE6933B110F256AC7EFF3E5D5C0A883718EAB936F67859FB0B4A088603115133E7EA9A8AFB3B196684C311F3883A2A19BAC8C380200000B5391B5D2CEC6862600002871B5D1CDBABDC99D3F0000013E91BFBBC5B6772C0000001358A5D0DDDFD6BC773E0D053A8EC8D3AFBFCCC79F4801000E6BB2C5C7C2A8A6A3963F030C5898BCBEBFB7B07C2F0914383B4F84B0C3B9B5AEAD8E4D0D000000A0C8D5AF8A522B0A0100053DA0D6C48A3813111020201A3580D8F9E3A5552617222A32495380C0DECB997850322228384EA6EBF5C78C512E2A313C4379CDF8FF3813111020201A3501FEFD5E070718D06D90CDFFFFFFFEDE8F3C13143B80D7E4F5E8D9C6AA836E9AAF94725C82A2B8B397815B1E09153F7B96A8BCB4A08B6755391A398099A1A1AD8E35000000126596BAD4D4CC892400002C71B5D0C1C0C5B7963A0000004097B7BEC1B06C24000000175AA9D9E0DADFBC813B01144294CACBB9B9C8BA97420000116DB4CBCDC7ACA7B0923C011A60A0B3C2BAB0A67A280F1F3840568EB5B9B8B1A9A38E4706000000A0CDD4B68851281303030C51B1E2D488330F0D161828213A74D4F5E19F4D29231D33414C4A77BCD3B5A87851342823304EAAF0F8C68549292B353A5376CBFFFB330F0D161828213A01FEFE5E070718E0709CD7FFFFFFFFEC8E3713143588CAE3EDEFE0C4AF7D6D929B94856E86A3B3C49E7C4F1C0912368F9FABAAB2A38957533525407BA0ABA5AD7A370000000B5197B5D4D2D08E2900003084B3CBC4BDC0B8903A0000024C96B3B3B7A963190000062560A0D7D6E9D9BC682F02195D9FC6DCB7B8CBC0953B0000166EB2CED0C7B2B4AB8B32102060A2B9BEC0B7A26C270E1E2E344D87ABC0C2BBB1A2834200000000A6C8D0AF824522080B000C59B3E5D5913C101615131F2B3E87D5EDD5954B1F1E1D2A43515585C5D6B4A96E4A3A26223153AEF3F3C27F462B2E312E4B7FD7FFFF3C101615131F2B3E01FEFF5E070718F07C9EDFFFFFFFFEDF95451B193486C8DFF3EFDAD0B984768A95887C6C81A8B4B49279411406165390A9A9AEB1A57A615B4E313985A8A19BAE782E0000001963A1C1D0D0C7932500003E8DBAD0C3C1BEB6883D0000014490AAB0BAA6641B0000001E64B2DBDFDFCDAB6721001A5A9CC1D1AEB4C8C791300000166DBDCAC7BAB1A1A97B30112F68AEC4C3C0BCA3691C0A1A38315794AEBFC5C0AD9F8842030000009BC0B9A25F33120000000154AAD6C47B37150F191723243888D7EBD58C3A20241C2136474D81C3DDBEB47F553427222B56B8ECEBBE80442C2F353C538CD3FEFF37150F191723243801FE005F070718007CA6DDFFFFFFFFDA87380F133E8CD0E2E3E7DBC3AC777598988684798EA7ADB0A06938120613488DA7B0AEAC9C7C5D5F4C2D408099A39BA7742C000000206BA1B9CCD0C3842900024190C4CBC1B7B5B2893800000E4D95ABABC1A75B1B000004296CA6D6E5E0DBA55C2200215AA2C8CDB9BDC5BC892E00001077C6D6D5C5B0A8A0832402317FB0B8BBC4C1A86A220E132D3D5885B7C1BAB5AAA48032000000009AC0BF945E30130000000F5CADDEBE69220E061012171C4C92DCF1D388421F1B1A253E4D4C80C5D2AFB57F5238302B325AB9EFEAB06C3A302A28314B93ECFFFF220E061012171C4C01FE015F070718106E9BDDFFFFFFFED07639161C3C8FCBDDE1E9D7CAAD826A888F808C7C7EA5AEB599663601020D4F94B8B4BAA59E6E586859293F7B98A4A3A468230000001977AABFCFC8C48A2C00074A98BFCAC3BEBDB6842B0000015395989FAF9B5E21000000307AB1E7E3D4CAA0551E001F67B8DBDAC1BEB9B47A2800001D77B8CEC6BFB3A69B6D23093885B3B9BDC2B89D641E0413263B5B84AAD0C8BDB7A97637000000009FA9A4885718000000000051ABCEB368220C060A1015224A9ADFEBCD7F361A1A15254E545B83C0C8ADBD7C473224252C63BEE7E1A46D3D2C2D403F5797E0FFFE220C060A1015224A01FE025F070718207CA1E7FFFFFFF1D478381F1F3C8FCACEEBEAE0D0A8726A878B808D8490A8B7AA9A642700000B579AB4AFB3B0966C59684C2E48859E9BA79E69180000002B71AFD3D7CFC27A23000A5C9BC6CBC2BABAA97F2700000453929BA7B398570D000006337EBFE7E9D9CDA7551400247AB8D8C5B3C2BDAF6E160000247AC2D0C9C5AAB0A46E260D4387AFBDC5C0B6A45A1C0C1324345B8AB3CBC6B3B09E6F2F0200000091A4A0733F11000000000051A0C6B76D28000005150F183E94DFEFCA7C33191B1F2A4C42467BBDCDA1B56E493A27292F68C4F8E4A35F33292D293256A0F3FFFC28000005150F183E01FE035F0707183085B8F1FFFFFFFFD17326161949A8D5D7EAEADCC6A2756D847A82928B98A8B8AF9F5D1B0000125A9CB7BDB6AE99715E6D52394780A194A1975E13000000337EABCACDD4B3781C00125EB6D1CFB8B6BAA56F23000005559C9A9DB39444180000083E87C4E5ECDDD5A4500D03297BB8D4CDCCC2C6A8731300001D7DBBCAC4C0BABCAB5D1C06398AB8BABDC2C0A057211116333C5593AEBDC0B8A79F7128000000008FA9A5764410000000000657B2D3BA6724040A0002171C479FE2E5BA772B10151E30485E5783C3CDA0B97A4B382B353069C6F2E29D512B2B29303B66B2EAFFF224040A0002171C4701FE045F070718407FB8EFFFFFFFFFC87737151F529BCDCADDEAD9CAA671686F7882A29A97A3B1AE9B5A1C0000185EA6BFB6BAC2A36B5D6A52385284A89EA493540A0000002472A3BFCFD2BF7718001B72A9BDBEBCBCBFAC771D0000095A8C9797AE94480600000C408AC4E2E9D9CEA24C07003479B8DED4C8CEC7AF600A0000308AC2D2CEB4B8B19B5916084A94BEBCBCBFAE954B151111253F6D98B6C1C6B7A68E6A2800000300849E93642E06000000000660AFC5A85A1900050608121A51A4E4E4B46E32100D142A4F4E4A8CCACC9BBF66422D2E293874C1EBD5925C2E1F2D3A3769B6F7FFE31900050608121A5101FE055F0707185072A7EBFFFFFFF2B36228131A4C9FCED1E7EAD9C2A071606C6C7B9AA198B0B7B696541300001F64ABBDC3BFB491635E75453050869C9EA0A44F01000000307AA8C3CFCFB96F17002474B5CED1C8C1B1A776170000185F7F8592A68B3E070001185391C5EBE5E2CF8F3F08043795C6D9D9CEC0CCA04E000000207BBEDBC9C1A9A3944F0F095598BBC0B7C7C0A4521B00111E366C9EB0BBBFBFA99A6121000001008F9D91682500000000000057B3CBA5651E050204020B1556B1E5ECB65A261320242847595A90C6C69FBE6D4A2E2F2D3C72C8EED496542D2127303C67B2F8FFE91E050204020B155601FE065F070718607CAEEEFFFFFFF0C5732D16234FA6D0D4DEDED0BFA37865656576A2A3A4B9BBB7924F0000001863AABBC0C1B391626A7C55365C99ACA5A29748040000013378A8C8D1CBB8681800277EB8CFCBBBB6B2A86B15000008568891A0A97F410600001A5098C7E3E5DECA9B4308084597CFDCDAC7C4C39E4B0400002783C3D7C4B4A2A4924A0F11549FC8C6BFC3B18E420A0B161E3E709BA9B6C1BCA89D5C1B0000060888928763240000000000116DBBD1AC5A1E0600070E102265B1D8D8AA5B250B181B2A5C5C548DC8C192C17348382E2C3983CDEFD87F472A292A283770C3FBFEE61E0600070E10226501FE075F0707187079A2DDDCE1E3DEA450180A18449EC6D6E4DADABC956150505882A3A7A6B0BCB08F430000001D72AEBFB5B6B88C655F745146698FA3A0A48C3D000000003981A4C3CFD0B55A0F002A85BBCAD5C2BFB8AA650C00000C55808A9AA6803E06000423599DCFECE4E5C6984713014696CBD7CDC9C1BD973C000000328DBFD4CFC3B1A18D42101866AFBDBACBC6B590390E020422456B95B0B8B9B9AC8D55100000060495948C59220000000000096CC0CEB45A1E010900061A256BB5E8D8A95D2913131628575F609BCCC394BD754F3E30314384C6EACC8147231D2B30417DD4FEFFE81E010900061A256B01FE085F070718807EB2EAF2F4F0E2A0552D1A2048A4D1D7DCE5D2BB8A665756517EA9AEA6AEB8AE9041080000237AACAEB6B7C68B646C794D3D6C96A9A4A0883D000000053677A5BBC8CDAB551800348EBFD4C6BEB8B197510000000A52767F97B18A300300022F6AB4CFE6E3D4C682321D1655A6D0D5D2C5BCB88B3E0000003E94BAD8CAC6BEB28B3607185FA2BFBCC5C3B98C380C000A213E7B9FADB9B3B5A5884C0F000012188D9687551900000000001479BBC19B522209000705142A6CC1DFD2A35425110D132F555C5F9ACDBE85C26C4D343635408CCDDAC67A3B1C191B323F79CDFFFFE02209000705142A6C01FE095F070718906EACE0E1D5DFC5965215131B468CC0CAD3DCCCAC886352494B7CA9A7AAB3B6B18C3A0200002C86B4BABCAEB486616A7B574B72A0B2AEA276250000000C3778A4B6CECAB14E13033D9BC0C5D1C0B6B3974B00000010547A8796A9873A0C00102E74AFD2DEE5D5BE833612165CA5D1CFD6CBC8B2811E0000003B99C8DACAC8BAB1832C031465AABBBDC2C6C0863E0C000325477F9FB2B5B6B3AC88400600000E1A918D73521400000000000575BBB99F50240602090F132C82CADECA923F1D0D17173A6566649DCFB185C56840362B32448CCFE4BB683C21222E2E3A8AD8FFFFDE240602090F132C8201FE0A5F070718A075A8D6D7D9DFBD864714191D55A2D6D6E2DFC8A17C55453B427DB4BAAEAEB9AD7C330000003681B4BEB1BBB29166757254486F91A59CA57A280000000B4680ADBBC4D09E4B03004490CED6CECBBEAB8E380000000E557B889BA376300A00083980BADCE7DAD2BA76310D1E69B0D0D5D2C8C1BA78190000003E98CBD5D2C1ADAD7F2B052473B2C8C2BAC3B07A3405020D1F538FA1AEB3C0B7AC8239000000201F899982501200000000001B82C6C998440F0C03080E0F2E84CBE3D1934B1C0C101739676C72A5CAAD77BA6846382D304C91D7ECC1703114172227448BCFFFFFE10F0C03080E0F2E8401FE0B5F070718B076AED6C4D1CFB473441307215DA3D8D9DAD5CBA1725D493B5183B8BBA3B5B7A57229000000388DB5ABB1BBB58C707C654A4C70A4B09E9D7517000000094688AFB9CEC39447110B53AAD2D9CFCAC1B887300000001B5C87879AA576270A00113F81BBD8DFDDD9BB6A25092975B8D9D6CCBFC2B56C190000054D95CAD9CDCEB5AA731F001C77ABBABEC1C6B174320A0007205787A3B0B0B8B7A6792D0000082528888A723F0200000000002B89C4CA9F501C0403030808438ECFE5C6853A0D0811203C717577B1C8B375BD613928292B509DD4E9B5633318171F2E4893DFFFFFD81C0403030808438E01FE0C5F070718C073ACD6D0C7D5B878401B131A4CA3DAE3E3D7CB956C4636344686B2BDBBBDBFAB76210000003E8AB7B3B0B8B78069756B49487BABB2B2A4651300000017468BB1C2C3C88F3A090A60B4DCD4CEC6B8AF812C0000000F4C708E9EB2762D0A0019388ACFDEDFD8D3A6693212307AC4D5CACAC1C5B66814000003519CC7C9C5BCADB16B2C03257AA9C1CABABCAA70290C010C2C5D94A1A6AFBDB8A3682505000E1B2D899382430000000000003090BEC49B4F11000000041148A5DAE6C380381C191613407A7782AEC8B075B86739352C2E51A6D7DFAE60291B161D31499ADBFFFFD011000000041148A501FE0D5F070718D0749AADB0BDC9A8664618112560A3D3DDDFD5BF83594931314882B6C6BEB6B9AD671D000000489AB3ABAABAB27C697A63474D7AA2ACB8A3590D000000205687ADB9C8C18B33040B60B5D5D2D1C6C1B5791D000000185F8B90A2AA6F31030221428DCFE0E4DED4AC631C122C80BFD3D1C7BFBBAA610B0000004BA3C8C9C5CCB8A8651B022A82A9C0BBC7C7AC6928010000215E9FB4B0AABABAA476200100112D3385806E320000000000003388C0C48F4B1100000305124FA8D7DDB4733421120C1A45797184B8C5A368B55E342E2E4362AED8E0A85421161B1D28459FE8FFFFD31100000305124FA801FE0E5F070718E06C95AFAAB0C39E6C35110A24559FE0DBD8CDAF73543C2E374E86BFC7B6B5B19D5B1400000048A0C1A9ADBCB582706C5C3D577EA9B8A994540A00000222698FBDC1CAC58736020B6CBDC7CCCFC1B9AF6C110000001C638A91A5AE69180A0D2D569BD4E2ECE3C8A258130F2C84BFC8D1BFBFC0A85B0700000E63A9C4D5D5CEBFA1590F032E8CBDBEB5BCBEA16A270200082D70A4B0AEAFABAC9E6A1F00000D343A8D846A2C0000000000003F96C5C9913A070000050A2051A9D4DCAF6C2F12111A194F7D7F8BBBC3A65AB1552C232F4670ADDED5A75224192025334CA4E3FFFFCE070000050A2051A901FE0F5F070718F073A6B2A0A7B38D583113101D4C9ECAE2D5BCAC78543028224483BFC7C0B7B2A556090000004AA2B6ADB0B1A16C676D4E3C5089ABADB3935C04000007306C9EB9BCC5BE872B030B6CBFCBCACBC1B39E67150000001C63939AA8A56D230309275E9AC3E2E6DCD9A34E1D103B99D2D4D1CEC3B99E4C0B0000105FA9C4CED0C7B68E4B0600338EBCC9C7C7D0A2682309000631689FA09B9CA3B19A5F1700001D3E3A8A836725000000000000468FC0BF864213000000061F64AED7CDA85B2A12171B215288869ABEC29959B35F3121334E81BAD3CF9F50250F17212B489DEAFFFBC613000000061F64AE01FE105F0707180072A5A593A0A68A593C0D07205A9ECADDCCBF9B6543361A25468DBFCFBAA7B19D55060000065B9CBA9FAFB1A077645F50445D8CA7B7BA9E580000000E377399ADB0C7B87F2D041572C4CEC8CFC1B49F57050000002B6E96A6A6A9691E07172E5FA9D5E4E0E1C88D4E18114291C4D4CFC3C1B9A0460800001B67AFD1D3CDC6B9944301003387B9C7C1C8C1A3582702000C376FA0ABA5A09FA68C5312000013413E797C6925000000000000399BBEC28D3707000000041D71BBDCC79C6124110E0A244C8B9098C0BD9D65BA592A21335685BDD7CC9C5C291A101D2C49A5EAFFF9CC07000000041D71BB01FE115F070718106DA1918598AB7E5C3E180A3165A8CFCBCAC99D62422D171E4286B8C4BDC1B88C420000000C62B0B5A6A3AA99736E66463A5992ABBAAB8D40030000124A809BB3BFC4BE7521031B80C3D5CBCFCDB1A15706000002307696A9B9A85B170006326CABD7DADEE2C496451A1C509DC5D1C7C8BCB0964F0000001D74B7CBCBC6C3B2843D00024097BDBEC1C5C59B622700000634739BA9A08D96AD914A1000001D4E558A856B3400000000000151A8D1BD913A020000000A166CBED7C698551D050A102765918B9DC8C08F4FB05A352C386A93BCD2CE8C39160D1426284FA9EBFFF5CD020000000A166CBE01FE125F0707182077A38F7D8A997E583F160B2A6EA9BFCDCDBD8D4C2C2621274991BCCABCBCAE8C350000000F5EA6B9AAB1A98B67645C4141649BB4B4B69141060000205492B1AFC1C3B4682701227CC1C7CCC9C1A89649000000093A78A4A8B5A55F1700153A72A2D7E2E6D8BD7B3A0D1458ACCDD5C9C4B7BCA0440000002375BCCECAD0C9B68D3500033D94BCCBD0C3BA9055250C00112E769DA8968D979583430900041B545A8785641700000000000055B0D1B98C3D020000001A2D73B8D9BF864B1E0E131331709192A1B7B8884CB5562E253D6D9FC4D6C38D371209161C2F58B6F4FFFABC020000001A2D73B801FE135F07071830739F957F8F9378583D1A112E689DB9C9C0BC86392719251D489AC8D0B6B5A87D300000000F62ABBCB3ACA28B685F534443709DB9C0B08D420000001F5E8CAEB0B8C0B76D22002B83C6C5C3C1B6AC953E0000000B3E81AFBAC0A05512071F4576B3DADDE6D6BF7834071254B1D6DDCBC3C0B08F3C0000003181BDD1D0C3C0BB7B290001449FBECEC7C5D09655240300063777A8A596818B9F8B43100000305D5984815C1200000000000A64ACCBC38B32060000000B287AC9D0C5884516090B263578A2A0AFC0B28050AF4D28274974A0C0CEC7893A1C0E0F17325AB5EFFFF6B5060000000B287AC901FE145F07071840749A88808D8B695841160F2F71A3C2C9C3B17B3813130F19488FB8CDC3B9A77D2C0000001166A9B7AEABAA8B645E553A416FABBDB9BB8D380000002F6096B2B2AEC1A5611A002D8ECBCBC8C7C7B18430000000124196B6BEC3AC580C09164575B1D6E1DAD1AB72340A1F65B0C9C6C5C1BEC09032000000337FB9CBCFBFC3AF7D25000F54A0C6C9C1C4B98D542E12000B3D76A29A96848996863A0500012B62627E7D5B100000000000075CB2C9B9832D090000000D317DC6D2C27535130B10203E7BA4A4B1BCA87940B24D2623467BB0D1D5C68535130D111A2659B8F5FFF7AD090000000D317DC601FE155F070718506A81786F7F7D644E4214102F77A6B6BDC4B3812E0D0F101C4D98C0C5C2B6A56F1E0000000D64A9B6B1ACA573554544364073ACC1BDC48C300000003C759DB9B3BDC09D5213022998CABACBD1C0AB7A290000000F4E9EB8BACBAB4C130B1D5388BAD3E1DCCCB068280E1A77C2D3D7C9BEB3AD802A0000003687BDCDD0CBB8A56720000E5AA7C9C7BCC1B4895E3609000C43719AA690788996732E0400083462617B775A0A00000000000E66A7D0BA812B00000000003687CFD9AD77401110101F418DA6B0ADB99D6F39A84721275689B7CADABD7E2E170F061D2964BEFCFFF4BD00000000003687CF01FE165F07071860798C8070696C5D57400A073474A9BABEBFA365250A0403095498C0C2B5AB9C6D1A0000001763B0C1B5B097744B5344354989B5C7C2B87F340000103D76A9C0B4B9C4A35310062F8DCFB8CBCCC8AD75240000001A589EBEBBB8A44F0A00206090BBD3DBE4CAA26322001F6CAEC3C8C2C8BDAC86280000003D94BEC6C9C5BEA86A1D000D58A5C3C4C7C6B88958290200124A80A0A58C79808B722E0000123B6F75787A4E000000000000146AAEC6B8812F00000000093886C7D1A267331D13131B3E86AFACB9AD986638AC4520275697BBC8DBBD7D2B0C040F192761C4F9FFE9AE00000000093886C701FE175F07071870727D726963594E4A3E070537719FB2ACB3975A150300021246A2BDCACBB2995805000000216FAFB7ADA2936A444A3F2F4893B6D1C8BD7E2D0000124171A9BEBAB4C6A64603053392D2C1C0D0C0B17312000000266DAFC9CDCCA4460A09236398BBCED3D1C1A25D2000206AB2CACCCCBFBFAC752400000A599FBEBFC6C1C09E5A0B001466AABDC2C1BCB88B653107050B468BA098846B797A6E29000319436B757B6C440000000000001879B3CDB77C2600000000024196C1C89D6120100F13223D8BAAB4B9AE966239B749272C5A9CC5CCBDB8772A0D030C1E2765C1F7FFE5A400000000024196C101FE185F070718807489897B71584E594214063B82A7AFACAFA0520E000006105398BEC4C2B0944F090000001868ACBDC2AB88593B3F3B2D4E90C2D5D0BF822700001E5385ABBFC8BFC69D3A0B003AA2D2BEC5C9BA9E600F0000002D6EAEC9D0D39D3B060C307497C1CFD9DAC59E4E12001B77BACDCCC7CFC3AE731900000457A5BBC5C6C3C89D480400145EA5BDC4C1C4BA825F3607021D5A92A69E845F627C6A2E0803194483747F734C0600000000003584BCD3B0782600000000074B9FD1D4A26025060B10144392B4BABFAC8D6531AE46203B6CAABECACFBA7E3107060A162968C1F4FFE6A200000000074B9FD101FE195F07071890718479706647424F3B130A44809EAEB1B29E540E0000002351A5C5C2BBB48847020000001B71BFC9BBA378472E3D352E5592C7D8C8B477240000285E95B9BFB7BBB9963D060A4298CBB7C1CABE955805000000307CB2C4CED290380008397DA6C9D8D1CEBD92470D002C7BBED0C8C7BFC0AC68250000085BA2C0C1CFBFB48D480600216DACC3CAC8C9A37C653914001B508DA29278605B6B5929070419507D81746E41000000000000328AB8BFA76D16000000001353A2CBC69F592108000B1C469EC1B7B6A982502DBB4822306FA9C6D0D6BC7A2F140916222963C7F2FFDFA0000000001353A2CB01FE1A5F070718A06C797072593C3255480B084586A4A1ACAA8C52030000001251A3C2BCBDA28A49080000001E71AEC4B99A723F302E2B2A59A2CBE0DCCC812500001F608CC0C6C1C0BB7E38070C50B1D3BEC1C9CC9243000000003976B7C9CED0A43D00043D7BA8C7DAD7D6B68F380A013686BBCAD3C2B9AFA26C1200001265A8BFBABCBCAE813800002275A9C5C2B7C2AD796B3D0900205B8BA5917E606A70581B000627588882736935000000000000468CB8BAA16C14000000000E61ABC8BB85461C130E10285494B7BCB0AB804D37B5462C306CACC1D1CDBA6D2400000C153673CFF4FBD687000000000E61ABC801FE1B5F070718B06C848078503C3B533606083C74A3ACA5A99C42010000001560AAC1BBBFAA8043000000001A6EB9C6CCA665322C2D303D6BA7C7D9CEB5762800053177A3C2CAC0C6B87D26000C50AECFBBC6C6BD8B3D00000003428AC0C7C6C88E3408104888B5D0D0C5CABB96430E00308FC3C1C3BCC2B69B610D0000186DADC4BEC2C1B481350100226CABC0D0CCC4A26E623F0D03286193988B755C595C4811000D2665917A796C3A000000000011578FBCBF9D5E12000000001364A8CDBA8F5218121413265498AFB7B89B6B442EB54D2B2A6BA2CCCDCCB0722006000B1C2570C8F1E7C090000000001364A8CD01FE1C5F070718C06F7E806D4927284D38090546829AADAAAB8837000000000552A5C1B5B5AE7E3F00000000206BBBD2C09B662A2022232B6ABAE1DFD9C47A1F00002A78B1C3CCCDC2B4752D001551AFD2BCC4CEB38038040000064793C2D4D6C78F2E0315579FB2C8D3C3D2BA8B3B00003990C9C9C9C3BDA696550E00001877A5B8B7C0BCA86A1E00003372AEBDCEC4C79D7C703A09082763949F8A73514E593F1A05082D6D968D71642E0000000000104B8DA6C1A7580B000000001267B2CBC3843A15040707245DA7B6B6B79A723B21B2502F307EB5C7CCC9B37D22090305142E6FCDF9EAC18E000000001267B2CB01FE1D5F070718D06E75776C4423234A31000C447E9EA4A59D8934000000000F5CAFB7B2C0AF7A3300000000217AC9D6CA9550231C1D24336CBEDDE6DABD68180003387FB9D4DECFB5AD6421021160B5D0C0C2CCBA7533000000094E94BBC9CFC98E30000D539AC0D0CACECFB28B370000368DBACACFCACFB19A4A0900002579A7C0B1BDC0B26A2601023C88B4C2C2C1B9987678430D082D6698A497735349482E16050D2D69928B6C623800000000001F689EB1B7A1590F000000001F75B6C7B77F33160604091D5CABC2C2B49D683728B45328397CB2B3C2BBA9681F0B0B0C192771CCFAE9B475000000001F75B6C701FE1E5F070718E07B848D7D31141E422A100D448EB1A3A7A1833000000000145AAFB5AAB3B16D31000000002676BAD2C18C4A1B101C233173C0E5E9D3BF7320000D4C8EB6CCCEBCB9A16611031769BACFC9CECCB36C250000000C539CC7C9CACA7D2B04175698C5C7D3CACFBB8D3903003590C3C6CBC9CBBA95450100002F86AEB9B0BEB8A4661D00063B87ABBEC4CEC39D6A7546120D346B95938D624B493E310E0810376FA38E765D29000000000025629ABDB89A5100000000002783BAD3B5723410000A0E2A63B4C7C2B38C5B3A2CB8512A3C7FB7C3D0BE9D592501040F172F7EE1FFF1B96C000000002783BAD301FE1F5F070718F07D7E857A451A2A4D32000546839EAAB0977832000000001D68ABB8B1BBA87529000000003982C2D6C9833B120B131E3C82CAE7EBD8BB6C19000D4B92BEC8CFC2BDA4621B061E6CBDD2B9CFCBAD651E0000001D62A5CDCCD2D18B27021D63ACC1D8C9BEC2AB7E2E00003F91C4C1BAC5C5B79142070000358DB6B0A8ACB2A3570E00104991B5BAC4C5B291727A45160C3274A19F9866413B3F210507164A799F8C715A2900000000002A76A3B4B28B470000000000368FBFC4A76F30161519114272B3CDCABD91512926B34C2A4688B4C2BAB4994A16000006163385D9F5E4A86600000000368FBFC401FE205F07071800747D81723611293C2B00064A84A6A5A3957025000000001063AEB5A7AFA8723400000000357CCCD5C6803C1110171E317ACCE5E5E1BA5F180311489DCED5D2BFB6965614002266BDD2BDCDCCB2601B0000001562A6C0D4CFCA802406266DB2CACAC8CEC6AF7A260000419FC6C3C9C0BCB08B320000003F8EB7A8A3AFBC9B470900145996BBBEBEC1AE8B7A77441615357C9F9B846B503C2B1E040016407DA38A85733D00000000165089B0C0BC984904000000003E9AC6CFB46923140B10132D71B5C1C3B79051302CB75727498FB3B7BBB197601A000000102B7AD4F6DC985C000000003E9AC6CF01FE215F070718106F858672310E1A402B0114447DA19FA591762300000000176FBABEA7B6AA6B29000000033D85C0CDBE7E3210030A18408AD2EFE7DBB6601C00154DAACAD8D1BFAE91480E052778C6CEC6C4C4A35D100000001D6EAFC8D2D1CA7D1F03176CB2CED4CFCAC5AC853500004CA2C3CDC3B9B5AF792D00000853A1B8BDA2A9B0924005001B6193BCC1CBBBB08677784C17154181989E875F302C28120503205098AE956E541E00000000001F6E9FBCB3873B00000000004C9AC8D1A25B2A0F0408092D7DB2CECEB5874E2A25B648254A94AFB6CBB2894C140200091E3682E0F2D59F5E000000004C9AC8D101FE225F07071820717B7C742B05183625000C4C83A0A29D9B6E2500000000186EB9BDA5B5AC7135000000033E7DC0E0C1842F030002193F8ED3E7E0D5B86324001856A0CDCACFC0B1914B1907347ABFCEC4C7D2A04A0E0000002475B3CFCCCFC6761A09246EB6CED4CEC9C7B3802C00094E9CC7CCC5C5C2A4792600000656A4BDB2A0ABB68F35000017619DBFCCCCBDA7866A80491D1C44829B9D89663C2A190D02031B5591B3956E5B2B0000000003418AA6BA9E6F3E00000000054FA0BEC0A4501D130D080F3382CBCCC4B58D3B282FB04C34509CB9B9ABAA8D4A160400040A2C83D1E5CF8C5A000000054FA0BEC001FE235F07071830747A7C7127041A3728000744809AA5A1946D24000000000E6AB6BDA7AFAC6C2A000000063484C2D1C9752300040A1F4591DDE0E0D6AF600E03245A9ECDD3CFC2A78337060D2E84C5D8C8C9C2984A110000002678B2D8D4D6BC741F032676B6D1CFCFC3C7B4862D000341A7C4C4B9C3C3A0782E0000085CA6BBB7A8B5B88A2A00002867A3C2C4C7C6AA74707C45112056839FA394573E2C16060009285C8DB49376562600000000084687ABB6A7823C000000000964ABC8CD9D4E20170D10193781BECFC6B08A44241FAA4F345B97A3A5B2A28C49120000000D328DDCEEC288510000000964ABC8CD01FE245F0707184086888F7A3409193A20001C4F7D9EA7A39C661A00000000166CB0B3B1BBBA8026000000123F87C9D7C5731A000003254C9ADEE7E5D8AD5D17002166A8CBD1D1C0AD802B08093B87C0D1C6CDC48D3C070000002979B9D1D6D9B56A200B3275B6CBCDCACEC3B8883200044AABC7C7C2BCB4A87A2300000B5AB4C5B5AABBB67725000026639FBAC3C8C3AE7678804515234A88A89E9266441B12080009235B94AB9968481700000000034E87ADB0A47C3C050000000F68ABC5C69A43100F080A133F8DCBD1C9B283362922B14B2B5A9DB4B0A9997037170101081D3A92DBEDC9835D0000000F68ABC5C601FE255F070718507484806C25000D291404164475999C9697681D000000002573B4C2B0B9B38229000000024785C2D6BB7320040004174AABD9E1DDD9AD451B061A5DB3DBE6DAC8A16E2C0B0E398BC4CEC4C9C08534010000002780C7D1CDD1B66C200F3F85B0D2D6D8CCCAAC8028000655ACC3C9D0C5BFAB6A1D000012639AC1AEA0B1A7721B00003572A5BEC8C5BDA8706D77501E255A8BAEAE9965361F050000082A679AA18E6F5D2800000000105D90B4B9B47A30000000001A6CB2C6B492641C1E1204134B9CC7CCCAB97C3F1E1CA6462D639DB9ACA994663208070005183386DEE1B877490000001A6CB2C6B401FE265F07071860798E87671C00162815052552809698A290650F000000001D84CBBFA1ADB9792E000000164B8FC4D5BF68200000062051A2D8E3DED5A8541A0A206DACCFD3D1BA9B6C230D0F408FC2D6CDD4C0862D000000003480B9D0CCCDB05E1C0C3A7EBBD8DDCFC8C7B48125000150A0C7C8CEC5C1AA6B1800001373ABB8AEA1B5AD791700003874ABBEC4C3B89873627D50282F6195A9A59A6D3416010000072F6697AD8F65461400000000064D91A8AB996729000000001566B2CEBC913D1612120E1A4FA1CCCEC6AF8C342920A7463076A8B6B0AA9260360D000005153D90D8E4AD75470000001566B2CEBC01FE275F070718707B7E7B612004182914031E4D7A8BA1A28D6512000000002A80C3C5AFBFB87D2E000000095097CBDDC16D1A0000001A58A6DBE5E4D49F430F01256FBDDFD5CCBB8E5A15070C5091C2D3C7C6BE862E030000014482C1CECBC6A05D1805378ABEC9CDD5D9CABA8820000657ADC6C4BEC3BEA6641E00001473BACBB5A3C1AA6C0E00003274AEC6BCC3C19E776D77431F296C9DA59A985E2912010000062F73A2B197664B190000000012618DB2BAAB792A000000001E7BB4CDB78035132C23121852A1CBCBC4AC7732231AAA433972A3BAAB947A63290700010D1A439CE4DEAB5D490000001E7BB4CDB701FE285F070718807C847C712E09212C1211315D7A909C9D915C1300000000287EBEC2B6BBBE872E0000000F519DC8D1C268140000001A57B2E0E1E0D5993810072D70B8CADAC8B88E541A02134E91CAD1C8CBBE8623000000073C7ABAD1C6CBAB4D0E083D92CFD6D4CDD0D0B3812800185DADC9C8C5C1BAA5640E0000116FB6C5A7A8B0A3621100003F87B4BCBCCFC69E726B7F4522336E98B1A796663211000000023674ADAE8867651A000000000B5491B5B19F6B2B00000000277EB7CABC7B4326230D11236599CDD7C8AC73381A11A5453B76B3BB9D8C754C12000600051B418DE1E1AB5F42000000277EB7CABC01FE295F070718907476696812000E170605305280979E998C4900000000003287C4C2B0B4B38B2A000000125B9DCBD1B4620C000005285DADE1DCE2C28B3B0B073380C0D8DACFB67D4A0D00174A98CECFC5C1BB761D0000000A4387C4CFCCCB98460C0E3A92C2D5D6D5CEC4BC7C22000F66ADD1C9BEB6B79F5D1A00001A73B7C6BAADBBAB690E00064B8FB0B7BEBDBB9A6A716F411E307696ABA78F622D0B000000083C7BB0B08964471600000000116490B4C19C6928000000002F89BACCC3882F0C2118042770B2D1D0CAA86D33221BA7453C7CADAFA083754C230000000F19419DDAD9964F3C0000002F89BACCC301FE2A5F070718A0707A856C2B081E2914223F617D999F98965F0D000000002D87BAC4C0CFC69631000000135698CAC7B061120000002966B4D8D9D6D1923C180A3A8BBFD5D1D0C17D3505000E5795C9D6CBC8BC701A000000173B87C4D4D3C29348090E4C88BED1D1D6CEDAB87721000161B7D6C6B8C1BC9F591600001F7DB4C7C0ADBAA15C01000E5289AAC8BDB1B58D5A6A6943313D76A1A3A38E5F2C080000000E3A84A4A98F62541900000000196B9DBDB49D682800000000288DBFD2C87E2304271E12296EADD2D4C9BD6E330F0DA04F4F83BAAEA4805D3B1502000310215099DED39A563A000000288DBFD2C801FE2B5F070718B07D867E691C00171A061846678499AAA485490200000000337FBEC5C3B9B0933A0000001860A3CCCCAB5C0E000000246BB7DEDDDDC5853210123281C3D7D8C9AD733108001763B0C8D0CBD5C1711B000000144C8BC4D2D1C48A430C0B3B95BFD1DBD8D0CEBB7421001666ACCECCC7C1BD9F5A1100002083B5C5B5B0B89E500000085A92B9C1C6C2B992636C6640223D7B9CA29F8B622A0900000013437EA5AB90704C10000000002573AABBBCA56D1A00000000408FC3CBB1732E0B28200E2D79B4D6D4CAA466281114A844578EB3B59D775832190307080D2754A4E9D1914F22000000408FC3CBB101FE2C5F070718C079716E651F080E0E00164C687F8A9F9E7F4300000000003481C3CCC4CCC6983A000000206BAAC5C7AC59090000002469B5DBD5D7B87A2F11113D8BBECDD5C3AF722D00002363ABCED8D0CDBF65150000001A4CA1CDD7CFBD8038030C3986C0D1D3D7D6CEAF641500136FBBD0C0C8C1B5AA520800002983BBCAC4BAB89D420000195898B6BEBAB7B7855C687242314C80A1AFA3A1612308000000174087ABAF92603D0000000000236EA2B1A9936018000000004A99C8CAAB6F2A122E1700387EB4D0CBC3AD6B29140CA4585D8FB1AE8C6E4F2409000D07152750B4E9D48748310000004A99C8CAAB01FE2D5F070718D0767673530D000B080014576F7C959D94743C00000000003182BDCFC8C7C9903B000000266DA4CBC9AF580B0000002F81C0EBDADAC7751B01133A91CDD0D1C3B26D1A00001B5FA3CFD1D3DABC65130000001A4D98C5D6D4B6793409144B84BAD0C9D7DACDB1680E00106CC1D2CEC8CAC2A04B0400003291BDBEBAB0AE9F44000014669AB2BABBB7A77E526C6C462F578CA3AA968D6124040000000A4392BAAE8F643D0500000000277CACBDAEA0631600000003539DC7CBA97125112416083A89BAD3CEC49D6C270F0FAB616D93BDB08A6847240B060803071555A2DDCA834B35000003539DC7CBA901FE2E5F070718E0666C6A4D17040A0B031E5F737A888F8D7E3300000000003187C0C7CEC5C094340000002A6CABC5C5A457100000012E84B4D8E2D7BC6C250F164C9BC1C8C9C4A7651D00002473B5D1D4CDCDBF5B0C000000295E9CC2D0CBB6782602114A90B7CADCD9CDCCB3630E001874B8D2CBC2BDBC9C47000000308DB8BEC4B6B0963F0000216997AEBCB9BCAD76506064432E488CA9AFA79B60250E000000184E889FAA8B66450F000000002481B1C7B8A25C1B000000015EA8C8C7B4752516231B14498DB2D2D6C7AA61230D15A05777A4AFA57F62310F0B000506182157AFECCC8648340000015EA8C8C7B401FE2F5F070718F078716C51190D1E08053370867988978D6B2E000000000B478AC6D0C8C6B990360000003778AFBBBBA45A030000003287CBD6D4DDB95F1F07144797CAD7D2C3AC601800002F7FB3D4DCD1C4AA58070000002565A4C6D7C4A86C22010E539EB9CAD4DFD6D1AB5A0B00197DB9C9C8C4B9B597450000003B8CB9C6BFB4B895360000156198B8BEBEB8AB785654674A22518FA7B0AA9D6320000000001A5A94ADAC93624100000000001D7FA6B5AC8D4F100000001263ADCBC9A462160A301A184891C2DAD0C58F682B0F0A956E80A8BAAB795030100500070A0D255CBAE9C5863C2D00001263ADCBC9A4 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 61440 61440 0 01FE305F070718006C6E64450E020A020627677A848B9B84621C00000000094194BFD0C8C7BF90370000003C7EA7C3C1A34B000000023A8DCDDAD3C2AC58130C194C9BC7D0C7C4AB580600002D7CB7CDDACCC4AD5E1E010000316BA7C3D7BFA15B19070F4E8CB6CBD6DED9D1A35405001A7BC0C5C6CBC8B79E410000003D94BFC9C3BDB88B2D000021739AB8BBC0B7A36F54636941426298AFAAA39D5B230000000319498FB6A988604200000000001E86BCC2B89A5C130000000E65ACCCB3985411122C1C1B4699C2D3D3C29D59220816A77484B3BAB27A562B0D00000E1821245CB4E2BE6C403100000E65ACCCB39801FE315F070718107E807B63170B11090C3A778C8C8F968A61240000000014508ECBD9CBD0C58B3A00000E408CB1C2B9A154040000003A90C9E3D7D0A34F0F05184A97D2CECAC1A3510900003F87BAD7CFCDC5AB64160300002E639ECBD4BF995A1D0012509FC4D0D4CEC9C4A2500C00227FB8CFC2C4C2BD9938000008439CC2C4C5BDB38A2C000030759AB5B7B2B0A164485A60463F6A94A5AEA3985D1C0000050E1A508BA0AF94623E00000000002B88AEBBB38D4D070000001875BAD1CA994B120C19161C53A0C6D4CEC0975C1C040E9B6683ACC4B5743F1A060000030F212E6EC9F4C16E332800001875BAD1CA9901FE325F070718208086754911040D0610437595868D907C530B0000000011549EC3CCCECCC296320000075192BDC4BCA657030000044396D6DED9D2A54D0908205DA9C4CFC7B997460300003A8DBECCDED8CEAB5A15000004396CABC1C9C294481001135195B1CCD4DBD5C78D3F01001D7BBDC9CCC6C1B68E3B03000C5098BCCAC6C5B8802400003379A0B6B9B8B5A36448575F474B6790AFADAB99571B020002081E5C97ADAA955E3C00000000003D93B2BDC7995D120000002683BDCCB48F4C140E221E235DABCCD2D0B68F4C1900139A7793B7C0B0723A1A0000000A0B222670BFE5BC76413200002683BDCCB48F01FE335F070718307473704C120401010F46859E8D868C7A4A1700000000195A97BDD8D4C9B98834000004498BB5BDB3A05600000000459CCFEAE2D2A04B0B072B69AAC8D1C2C399460000033C8CC1D3D5D7C9A9510E00000F3D74A8C7CDC0893E0B00135792C3C5CBD3CBC3973C00002884BFCDC2C0C4B3923400000C5297BBC1C7C3B97A2900003E7F9EB4B7ACA895664460594A5079A6B7AAAE8C59260701041025669DAC9D8960380000000000398FBEC2B79C54140000002983C1D6BE89460E0F26201E61AFC6DDD0B6904E1F0D1A9C7D9EBABAA76D361B0A00031212112F74C1E9B868342800002983C1D6BE8901FE345F070718407B77754D0600050010447A9787868A6B4012000000001B5990C1DBD7CAC38B340000165F9BBEB8ADA14C050000004498D5E1D7D58E3B0607256BA6CCD9CAC6903A0000084991BDCAD3CCBD9C46100000144D80B0CAD0BC823A1100175DA1BBCBD2DECDBF8B360000217FBAC3CAC3C4B78A3100000A58A1BEC7C3BDAE74200000447D9DB1BAB3B496574B546752446A9FA8A6A89A601F0B0902052956A3A7AB90663000000000004596B8C1B6904F15000000318EC4CFBA854A0F14201F1863AECED7CFB8934F1A051A967AA2C1BB9E692E070400000913252A76CDEAB66537270000318EC4CFBA8501FE355F070718507071705019090805185485A58F828A713C0D000000003169A3C2CED2C8BB913300001E5FA6BBC1B69F4D0100000C56AAD3DEDFC3933E05092672B6BFC6C8B88B310000055B9ABEC7CCD1C39D490D020011558EBEC5CFBC7F320400105B99C2CCC8CDD1C3832D0000238EC4C9CDCCC1B1803400001867A5CCC9BFB7B06E1A00004484A3B3B6B3A1955C455C5940507DA8AFABA495551F040600142B67939B9F8A583100000000004498BAB8BFA148070000004194C5CCB28A3F03132421226BAACDDCCCB28D421A09199A89AEC8C6AA68360E040900100F1E3579D4E9BF5E2E2E00004194C5CCB28A01FE365F0707186072776F4F140500062B5B92A189978C683A06000000042D67A8C7D3D6C8B2813400002567ADC0BFB29A4C040000085BA4C8DDD8C68933000F3676ABC7C8C7BC802A0000094EA8C3DFDBCAC29A4A1203000F5790B5C1CDB76D2B0000205DA0BBC7CDD7CEB9762300002B8EC8CCCCC8C0A8843500001C61A7C1BDBABAAD681200014389AEB9BBB7BB90524A5C524A5480A0B6A39F9047190C000F14316490A39B835D36000000000050A3BBC6B89154090000003F91C2C8AE8A4211152118316BAED0DBCAA1773A0700189584A8CCCAB56F24110004010A151C438EDBE6B35B2B2500003F91C2C8AE8A01FE375F0707187071757E561D0C0C091C639BA8948285612B09000000053A72A1BBD4D7CFBD833800003673A7C7C4BE9F55000000075BB1D4D2D9B98234000F3E80A9C9CFC5BA822700000C559BBCD5D4CDBD9349110A0A276391AFBBBDA76A1A0003146CA7C3D5D3D0C4B3791A00003899C9C6B8C7BCA77F2200001A6DB6C5C1C2B5A2660F00064C8BACBEBAACA88C56495A52465C84A1B2B1A0954B1106030B152E6898A6A38A602E000000000055A8C3CCB89357100000014FA9D8DABF7C35040B1A172C7AB6CFD9D0A977380B0A19949AB4C8C3AF692610000000081419398ED6E6A45C332B00014FA9D8DABF7C01FE385F070718807E7C794A23100904215A9EB0978D7F54300C0A0000123B79ACC3C4D4CFC180290000347EB9C0B9B7A2490000000562B0CBD3CEB2802C0212498CBACFC2C0BA751800000F5AA0C0D2D6CDAF9248170E0F1F6B9AC0C8C7A75E1700002266AABDC8D1CAC4AE6B1F0000349BCED3CBBCBEB26C1800002373A3CAC9C6C6B2610A00116093B1BAAFAFA08D54495D5E486191AAACAC9D8C3F0C01071318285A8AA4A38C5429000000000E5BAEC0CAB087480000000D53A8D3CBB47D3A0A0F18102B73B7D7E6CDA5753D0D002B9C90BED0D6AF76340D0000010B13224297D4EAAA562225000D53A8D3CBB47D01FE395F07071890626266470B060000236799A493907E4E1D00080000174E84A3BBCBDAD0B87A2700033586B9C8B7AE9C4B0000000B55ABCED7D0B7752303114789BBC4C3C9BC6D260000135FABC2C7D0CDB3923C15110E296B9DB7C8C39F4E1301053666AAC7C7CBC9BCA96C1F00003491C0CBC6C7B89C6D1C00002F83B6BDC8C2BFAF5E0A000C589AB2B4B9B4AF834E445754536181A3B5AA9D8A4514090C12232C6995A3A685582D00000000176DBACCC9B495540E0000126DB1D2D8AE732F060811133371B5D3DFD0A36A330E0B1E9A94C1D1CEB16F2B0700000613122B489CDBEAA951312900126DB1D2D8AE7301FE3A5F070718A07A91824E1B040B20487CA6BBAD9488531C00010305245B8BA4C6D8D2D0B96E2500003B8BBAC3C0B59F4A0000001558A3CED0C2A06A250316529CC8D4D4C2AC6E180000156AA9C2D0C7CBAF95481E0D173178A0B9CAC7A04E0D00052671A9BDC6C6C6B5A5610A00003E9ECCD1CECCC6A76A1600003181B7BBBEC5C3A64F0300125D96A8B6B6B1A6854D4C5254505F90A8B8ABA585390D060A13172E6693A19E8E522A000000001D6FB8C5C6B7944E0A00001569BCE0D0B07129020B10132778BFD7D9B99B6E360C0D208F96BED0CEA266290E00000515223256A7E6E3A8502F26001569BCE0D0B07101FE3B5F070718B07A887E571F0E0A164986BAC8B19E7F451E050F03062D6593B3CCCBC9CDB8712807094A90BAC9BCB296450000001368ADD0D8CDA86A23031D5AA1C8C7C0CCA85B1A00001E73B2C9CAC7CABE9241191C153977A7B8C2C49A480500082E6DB3C9CECEC3B49A500E00033B99BACFCCC5C0A0691400003980ADC8C1BCB79F460B001D649AAAB1BBB29E7C49484D535A668CA7AB9F9C763A0B02121E2A4676989E9F88461E000000001C7EBCD7C7B58D4D080000136FB1D3D4B8803006070D173487C3D0D4C2905F32100C2F959ABAD9D5B6742B0408050E10192450A6DFDE9F4F293000136FB1D3D4B88001FE3C5F070718C06C88895C2E0B0C265E93C1C2B39A775019111D0B05356B97BCC1D1D1CDB0672100154E97B8BFBEB99A4B000000106CA8D7D5C2A25D1100276DAABBC7C5B9A7630D00001E79BBD7D0C7C4B9853829241C3A8AAFC0BDC29F3A010008367BABC2CCBEBBAD914700000046AAD0DDCCC0B593500100024194C3C5C9C9B9A64B01001E6098ABB3AEB0A582464A4C5E616A93ABB1A79A77380C08061F26406F93979B91491400000000307CC1C8C9B78B390000001F75B8D6D3A66625040814132E7CBCDCDDC39865340E0C279299BFD8D1B4702005000804111D2B58ABE4E6A54D2F2D001F75B8D6D3A66601FE3D5F070718D0757D7B5218010C236686BFCCBC9E7F3E180F0F16184078A1BCBFC9C3C3B26B2100105BA6BCC3C2BBA1460000000A6BB2CFD4C39D5B1804276CA7C1D9CBBAA255030000287DB8C4C6D1CAB7873D1C21264685B2BCC1BC87300300063E87AEC4CAC7C2AF8D4200000846A8C9C9CEBDB997450000024795B5CACEC7BC9A4E0200266B96ABB3ADB0AB7E49464F5F65728EA5A8A7A581300F07102730386F9DA8A0814218000000002C7BBACDC1AC85420100001C7DC0DDCBAC672000000C13378FC4D8DBCB9A602E1810389A9DBED9CEB46E2300000015071C3365B0E3DA9750332B001C7DC0DDCBAC6701FE3E5F070718E074908B522B1C19336699BECEC9A87641170C1F1B1D4883A5CAC3D3D2CAA0651C001A69A0BDC8C9B48F3E0000001B68ACCDD1BFA04711072D71B3CFD2C4B399450B0000338EC0C5C8C4B8AF813A2D2B2A498DACBDB9B88D340000144885B5C5CAC7C1A8823E01000B55ABC2CACABCB6843C0000034097C1C3C6CCBC9E4C01002A73A0B7B3A7ABA77C4E4C5263606991A4AB9C9C752D05070F2F2F4172909C9E864C2A000000003F86BCD6CFB7894A0600000F79BDDDCDA56A2C030D161E3E8ECCDEDBBC8D5931190C268CA2C5D6D2AE6C22050004071C1B3363B6E2D88D432D24000F79BDDDCDA56A01FE3F5F070718F07A938552271C27446FABCED2C3B07935150E21242C568DB3CCD3D5CECEA55F1E021960A4C0BDBCC4A6490500001067AAD1D2BC854112052E7DC5D3CCBABF9F420000003B97CACAC5C6C0B2873F2E3333539EB4C0B2AF732B0000134480B2C2C7BEB7AA7F3200001559A8CDCFC4C0B7863C0000044C97C2CBCDC4B79C4A0A00266EA4B0B2B4BB9E714A574C626A7296AAABA8A1652809000F2B364F72969899823E1600000001388CCCD8C5AE84410D00001788D7E6D09A6723010005183984C2DBD9BD9050311E193899A6C4D4CBAF6A250B000318192F396DC0E3D88E4C2E30001788D7E6D09A6701FE405F07071800738B87592B22315586ABCDDFD1B67B370F1225223056A0C3C6CCD1CDCEA351220A2B7EB0CBCBC1B19A46000000166CB0C7D9BD7C360B0B4082BDCFCBC1B09147000000399AC2CECBC0C1B2833C2C3E425792B3C7B9AF78210000124C8EB6C9C5C8C39E772C00000F60BBD4D9CCBEA26B300000085BAABECCC7C0BF97400C002F82AAB8BCAEA096674451535D627F91A2ABAD966B2708091835384C7596A69A814C20000000135498D1DAD6B689440400002684CAD6CC9E56240C0E19223187C2E2DABB7A4A2B111C3087AACBE5D7BA732400000B1018253970BEE1CC8B493936002684CAD6CC9E5601FE415F0707181078918256342732609CC9E7E3D0BF6F32111029283465A7C4D4D0D9DCC78E44120A3181AFCACFC5B89B420000001B74A3CDC8AE642C0C0E4382BDC6CFC2A88E3D0000004898D0D2C9C4C1AF773C354447669CB5B0A59B72210000265C8FBDC8C1BBB59A6F2400001467B7D3D7C9C5A36E1F00001464A2BBC6BFC3B2943A03084085A3B3BFAFAC9669474E5565777D96A5A5A596672304062232424A768C9F9A814D240404000657A2D2D3CAB081470900002188D1DCCA915923030E0E123D94CFE6D6B58649311E164297AFD3EADCBB75270300000A1C26387ECCEBCE7D3F2D33002188D1DCCA915901FE425F0707182073887F6036323C74B3CFEDECD7BF6D34201B2B2B2F6AACC9DBD9D4D7C5904A1C07368CBCC9CCC7B5963F0000002463AEC6CDAF6B250009438DBFD2D0BCA48D3E0000003FA0C3C3C4C7C4A87E443A493C6AA3B2C1B89F6D210000215792B4CBC3BDAF8D61180000196CB8D4DBCFC1A3690C00001862B1CDD0CFBDB7913000024884A4ACB7A6A89F624652556C7682A3A9AA9A925B1700082036465079979E9D7F44110402001061AAD6D6C9A378390000002388C9DACB8D5315040E14213C8ACAE0DFAE744A27161B4095ADD4E5DCB57026000100101B24418BCAE1CD81433B33002388C9DACB8D5301FE435F07071830768980533735548AB6D9EDE6DFBD723716233433366DAAD0DAE1DCD5BF813D1A12378BBFC9BDBEB79E3B0000002273B3D5D4B2611B06124795C6D2C9C0A883350000004AAAD3C7C6C4B0A46F443E5651779CB9BEAAA46C1D0000235B93B6BEC2B4AA7D531900002071BAD5D4CBB9A8610D0000186DACC4C6C6C3C0962D05185389A6BBB3ACAA965D4A4C536F7D8D9FA3A4AB9862190002253F4A58849A9699823E170105001665ABDDD5C8A37F41030000238AD3E3C5874A1C04101B214194CEDDE0BD743F2B1E255098AED1E4DCB76B2106000509172A529BCBDFBE712E383700238AD3E3C5874A01FE445F070718407A94875E3F40579AD3EBF8FFE5C1723E1C28372F3F72BED6E1D3DAD8B6743A171D3C91BFCCCDCABC96480000001E75B2C9CEA65918001048A1C7D2D2C4A47E2F0000005AABC8CAC9C9B4A67143475A5D729DB5C5B89C621200002C6FA3C1BEC9B2A681510D0000267AC9D9D0D3CDA4560000001D6FA8D0CACAC0B98A2D000C528DA9B4A9A4A7965536535D72808DA3A5A8998E5A1C000D2B4A51527A969493803E130300002071ACDAE0CDA775380700002288D0DBC886451B071314293F8FC9E5DAAE763E2D1F1E5086AFD6E8D8B46E1E0200000B18334E93D2E6C0773F4036002288D0DBC8864501FE455F070718506F7974543B3C5BA2D6F2FCFFEDBE7034191E31324D80BCD4DFD3D7D0B16F2E1C154F9FBED5D1C7C198430000001E71ABCDC5984C16001B65A4D0D7DCD7A9781900000556ACC5CEC6C7B3A3723E4E615A76ABBDBAB29C540A00012C6A9EB4B8B0B29D79480300003085C3D2D2CDC499520000002C7EB6C9CCC2C1B6852C00115699B2B3B4ADB09C5E4B545A74738594A29F9E924B0E00012F49545D828BA29D853B10050A022E78B2E3DFC9A6772F0800002E8DC5E0BF803912090612214695D5E6DFAC6E3C2D1E255697B8DBE8E4B1681B0005120C212B509DD8E3BE663A3E2C002E8DC5E0BF803901FE465F070718607B827F5C42436CB6EAFFFFFFE8C6742D232A36314989C8DCD7DACACCA56836181C4EA4C5D2CDC5BEA2490000003075B7C3BB904B0C001D56ABC8D7CFC7AB722100000B64ADD2CDBECBBCA169474B536287AABBB0A59B550000023171AABDC3C2B6996F380000003990C2D0D6D9C28F470000002A82C1C7CAC1BFB3832300115EA3B8C0B5B0B1965B415765768995A09F9F9783450D000634504F5E728E968F7C3F1D110A0F378AC2E1D6BCA07C3D0600002B89C1DCC77B3810091A1820358ED7E7D6A7694537352C5B93BEE0EADDB9722B0D08060C1C3764A5D9D8AE5C354C3F002B89C1DCC77B3801FE475F070718706C7C6C53373D72C4EAFEFFFFF8D16F3227232B374D98C1DDDEE0DDD2A35D1D161655A2C6D3C4BDBCA1460000003274ADC6C59A3E09001963ABD2DDDBCBAA641600001263B4D1CCCCC9B19F634655766791AABDBDAD95480000063F81ADC3B3B9AC995622000006479DC6D7D2D3C08539000000248BB8C9C6CAC3B57C2A01186793AFB8B1ADA59056446074838D8D9A9F9C9A85340C030F3A4E535F7B91948A714F211F1D1C3B89D3E5E2C49B7D401000052E8CD4DDC4853817100C15244893D3E5D7A269382F202F578CBEDEEADAB67A2E0A0103061C3E72B1DFD9B05C36443E052E8CD4DDC4853801FE485F07071880777E775F444C79CAFAFFFFFFFAD67B36212D393A5199C7DFDBD9D7D1A355251E245EAAC8C1C5C6C4A0410000043A79BCCDB3863000002674B1CCDDD8BCA960110000126AB2C7C7CBC8B397673D57676D8CACB5C3B08F3E0000124F8AABBDB8B8B28D52240000064FA3CEE5DFC0B4762E0000003391B1C6CCC6C1AB6E12002470ABBBAFB4AEA58A473954667A8593A4A1B09D7E4211000838685C617E8F91867246221812244E9BD0E5DCBA9F7D3D0A0000369BCFDBC1792A0D0A151E214A97D2E2DA975F383232336093B7DEEFDFB1732A050009141F3F7ABAE5D3A35229443B00369BCFDBC1792A01FE495F070718907170614A38477CD0FDFFFFFFF7C57132202932334D91CDE4E4DADBCE95481A1B2F65B2C9CCD0C7C1A1410000033A7DA7CFB788250003277ABAD1D5D6C8AB6B0B00001772B8D4D2D2C5AE9863435871738EADB6BDA891460000094989B0B8B5B2BA894510000013519BCDD8DAC9B3792A0000004394C3D0D6C9B7A57016032C7CA3B6AAB1AAA0914B3353677F999EA8A8A7967840050008426466687F908E88633A1B2122184199DAF6E2C89F6B3B070004379AD0D7AE6D30090B0F1A254598DDF0D69F5B33343030698CC0E6EFD8B26A2508000811173985C2DFCB9F4D31474204379AD0D7AE6D3001FE4A5F070718A0736E5B50404C92DCFFFFFFFFF1C168331D2A312C58ACD1E3E4E1D5C58B441A163874A9CBCCD1CFC59B400000003C79B2D0C881290000337EB8D6D0DAC7AD600A00001A78BAD0CAC8C5B2986043557A809FAFB7B9A78D390000105C96B1B9ADB4AD87491800000B4D97D1D2DACAA370200000004290C1D8C7BFBBAD641A022E6D9AB2BBB3AEA77F433358698F919DAAAA9C9E8038020013496F686D8290978E6443292C262454A5DCF4E3C39B73330000003396D6DFC1733410101B141848A0DAEADF94563B3124296A8AC2EBEBDFB9702305030A151F478BC6DBCA944B354A3C003396D6DFC1733401FE4B5F070718B078756B584E5892E2FFFFFFFFF4CB652F232B332E5CAAD9E3E7E0DCC88737121F3678B0C5CFD2D3C5A24100000C4082B4C8BB6A1F0000337CC0D6DAD1C9A5570B00001A74B3CDC5C6C5B193603F56777F9FB4B8C4A98A3C000016549DB6C7B8BBA0763B060000175AA1D3DEDAD0B36D15000000459AC5D7CCBEC2A66717002F79A5B3B7BEB3A77B4436586C909BA3A5A4A99B6E320000145470646C8697998F7046242C292A60A2DBEBE6C997703E0D07073D99CAD5B36A250C0913211D47A4DBEDDA9A593D3631326F8AC0DFECD8AC6A220B020F0B205490C7D8C38B4A3A4539073D99CAD5B36A2501FE4C5F070718C0807B6759475A9CFAFFFFFFFFF9CE74382B232B3C67B3DEEBE1DADABB8339151D3975BBCCCED4C8C9A73D0000144684BDC9B66C2200003594C9D4D1CFB99E4C0000002577B6D4D1C8C5AA895342627B80A9BCB2B6A77D3500001C5E8EADACB5B4A676280100001C73B4D3DEDBCDA867170000034CA5CDD2CAC5BB98590D003183AEB4BBB0ACA07D44324F6E8EA0A6A6A7A189703400001550667A7B8A979288623F2825262C63AEE4F7DEC58E68340000053289CAD8AC5D28080E1E22384BA5DBE9D2955741352A2E7188B4E5EBDBAE681F06051517205397CFD4BB9341364936053289CAD8AC5D2801FE4D5F070718D0777A6551515E92EEFFFFFFFFFDBE70402C252B355EB2DCEAF2E2D5B6773D1E2E4982C3CCC0CCCDC1A03F00001A4388C3CFB0661100003D8DCAD5DACCC9AA4B0400001C7DBDCBC9CEC8AC8D563A6073809EB5BAB7B17B2E00001F659FB9BDB6BA9F68230000001E73B6DAD5D4CDA85B1300000158AACECBD3CBC7A5610700388BA7B5AFABA59D7C3D304D6E8BA1AAA9AAA5966F2F00001A597E7277859890805A4A2B312C3B72B7E8FCE4C29974340E01093B9ACBD59E5B180C1423202A4EABE1E8D1884E383D31407B91BFEEF9D7B1651F070C0D192A539EDBDEBB8038273736093B9ACBD59E5B1801FE4E5F070718E07A6F5445405A9BECFFFFFFFFF3BB622D1C2130385DA9DFF0EEDDDEBE6F3512274C88C1C7C3C6CDCFA845000014488BB8C2B067180004419BC3C3D1D3C898430000002A89C5DBCEC3BEAC864B37657D93A6C1BBB89F711D00002A689AB5B9BABAA56D210000002D77B8DBDBD6CBA24F0900000056A7C4D6CBCFB99C4C09063E87ACB6BFB7ABA07632294A73999EAAA9A9A3956B2C00002163817571879289895F4B2D29353D7DC2EAF8E2C99C703E0A000436A0D1D0A65E17020A1C1F2A50A3E6EDD2894E4244353F788FC4EDF3D4AC67290E07090C215DA8CED1B379412E35420436A0D1D0A65E1701FE4F5F070718F07468564E52649EEBFFFFFFF9E8B6643225202D3860B0E0ECECDDE0B36A3313254E8CC1BEB9D3D2C7A73E0000205497C0CEA85C08000150A3CCD3D6D5CA98430000003288BBD3C3C2C1A48347384F718DA6B2BDC7AA721D00002F78AAC0BDBBB1A961130000002C80B7D8DAD0C29F490A00000464A8C7CFCEC4BDAE500801408EB3C3B8B5AEA07031284C8098A6A0ABAC9E935B1B0003256B8C8B7E8A968F835448202827447CCFE9EEDFBF8E68361702093B9ECACFA0511708151827275BB4EBF4D894584C4E3C457386C5E1EEDCB05C1E01020410295BB0DDDCAB7A3A273834093B9ECACFA0511701FE505F070718007B75614F485F9EEAFFFFFFFFF2AF643F2D302A3A6EB5E7EAE6E0DEAE5F25102B5C97C9C6B2BEC9C3983A01032B6192B3C7A55B1000114CA8D3E1D5D5C68B3A0000043A90C1CEC6C5BCA1833C345F788AA6BABFBDA5731D0000357AA4B9BBB0B89F5F0D0000003D7BBADDE5DAC79549030000146AACCFD0C6C9BD933D000E4791ABBEBFBAB19F64302552779B9FA3AAB1A894611A0000205F837F878D93938D52462D3039478ACFEFFAE7C18C68330E00073C95CAC79C4C220F0C18162C61B8E5EAD2845246503E427C80C6F5F4D1A65F2000001112315FAFD1CEA56E35234133073C95CAC79C4C2201FE515F070718106F6A554A48649EF0FFFFFFFFEFAE5C2C292622336EBAE5E7E4D8D0AB5E2A0D3066A2CAC2B5B8CDC2943E060C386EACC1C89E4E03000548A6CCD1DBD2BF92340000054095C8D8CDCAC2A27440395B7792A9AAB6AC9D681E00004383B7BFB8AEA89B4E0D0000004492C2D1DCD9C79B3C0000000B6DB5C4D3C9C1C19D3F07085294AEB9C0B5AA9A6025214878A3AEAEBAB29F8C5D1E00002A6D8E857D898A8B8346412D2C2F4C8FD6F9F5E0C2936D391702063DA1D1C894461811131625305DB7E4EDCB8A4B4D50364A8C82C2EBE6D3A3641A030613122868B1DFD2955B352F3D31063DA1D1C894461801FE525F070718207C6D5D525174A1FEFFFFFFFFF0B05E3631302C376CB7EBF1E7D8C89B502620316F9AC3C2ACC3CCBD913900063973A8BEC3994208001052AACED4D8CDCA893A000004469CCACDD4CCBAA174342E4E7C98ADBCBAAF9D6D1A00044882A4B8B1B4B29755030000094D9DCCE3E2D9C289350000001273B3D2D3CCC7B6983C0005509EB2BCBABFAD995C271F3F74A3B2A8A9AAA69D611C0000226E938A868B94948850492E3A435F99CDF0FBE9C492683208031849ACD3C48C3B12040915263969C2EDF2C78964645C434C8776C1E9E7CE9B521F0103070C346AB9DBD29B5C2F21313C1849ACD3C48C3B1201FE535F0707183077654B4A4D6CA2FBFFFFFFFBE9AD5F3E292D2C416CBCE2E9E7D8CC9A5118124172AACDC0A6B6CCBA904106104172AFCAC28E3B02000D56AFD4DBDFE0CA8B2A00000B4A97CBD5CDC9BC96703A345D7C9BADC2C4BBA25E0A000B4D8AB2B7B6B4AA9A4C00000003589CC5DAD8DCC3872D000000157DC2CDD2C8C2B4813300094F97B9BAB7B8B09A581D1B4D73A6ADB3B0B6A286501A00072E6D8C838C938C8D7C4F472D363865A3D5F8F7DCC394683C0F05164DA5DAC18632170A10141B3770C4F0F2D08C605B5C43588C81CCEDEED39D521900000B10236DBEDEC68A4D2F263B2D164DA5DAC186321701FE545F0707184075684F49495FA0F2FFFFFFFBECA35C342A24334177C8EBF2E6DDC593451E183E81B5D1B9A6BACDCB8F2F03134C7FAEC7BB7F3909000958B9D8DFDAD7CB822700000A4DA6C0D2C4BEB1996D3A39617D97ADC1B6BDA4581000075B97B2BEB4BAB092430000000D5AA8C9D2D7D9BF81260000001F80C0CFD1C8BBB17F2703135BA0B0C2BFB1AD965021213C6D9CA3ABB1B8A386491300002C7095908E99978D85484035353F6DA9DFFAFBE0C2936235130A194FB0D3BF7E33140F13141E3479C6F3ECC88F63615E54609679CAF0F0CB964F11000006112774C0E2C5854A26213635194FB0D3BF7E331401FE555F0707185079604A4B4260A0EFFFFFFFFFEDA25B3F2F1C263671B8E5E9E7D8BB8A471D204587BED5ADABB9CFC47B2E0019557EBBC4BD8B3800001256B7D8D1D0D9C3862700000E5BA5CAD1CDC7AD9F67322C567A98B6BCC0C09D510800126396B9C6B7B4AF9145000000135FA5D3DDD3CFBE76230000002B87BCCCCCCAC7BD7A2B0013589EB8C6BEB0A9894B16163678A2B5AFB2ABAB84491501013377969899998992813F47313A486DB0DEF4FCE0BD8B653112041351A4CDB87A2A0C12181C253A84CDF3F8CF9063675D485C8F74C8E4EAC388480E00000D0B2773B5E5D28E42252D35331351A4CDB87A2A0C01FE565F07071860715B4B505067A6F7FFFFFFFFE2AA5E3832282D407AC2DCDEE6D8C1853E16104A8EC3D1B7A5BECCB9731D001D5787B2CCBA7C2A00000D63B2CCD8D7D8B5762300001863ADCCCDC8C3B1986B21294C76A1B8C5C4C39F570100095DA0BBCCBFB2A9983D0000000F74BAD0D6DBD7C167140000002C8AC3CFCBBCB6B7792300185BAABEB7ADBAA98C4B1B183D75AAACA7B7C0B1924C0D060A317C96948E948B81793252313A4C7BB8E5FAFDE1B786623E1D071557B1D0C0722D0C09161722368CDEFFFDD49766606451569373C8E0E5C284440D000008113B7DC3E4BE694824282A2D1557B1D0C0722D0C01FE575F07071870715E49484B64ADF5FFFFFFFAE69A543939342C3D7FBCDDE3ECDABE783210134F9BC8CFB59AB7C4B76E1B08246A92BECCB173240000146CB9D8D3E2E1BF7C2800001C6BACC7D6D3C8AF92581E25446EA6B6C8C9C59B460B00186199BCBFB4ADAF8633000000166DBFD1D2DBD7BD6D150000002A85BED3D0C0C7B96D21001667A5B5BDC3B3AB894416173771A2AFABB1AEA6804412000A49849C9F9B9C87888239422B3E5183BCE9FFF7D4B38E5B361E0C2568B0D1B4732B120010132D4583CFF5F7D2896863635668A378D6ECDAB3783D0A0000070C3582D5E4B97639202B2D252568B0D1B4732B1201FE585F070718807755493B475A9DF7FFFFFFF8DB915432332D314281B9D2D8D7D4BC75321D2863A7D4D1B394AAC6A565230D2C699EBEC7B66F2700001665C0CCD5D8CBB7731D00002276C1CDCBD4C4B58C531F2142659AB2CFBDBCA34C00001374ADB6C2B5A7AB91310000002A7CB8CBD2D2CEB76C140000003A93C3D5CEC7BEA46119001663ADBDBDC3B6AE7D3E13123C80B0AEB2B2B3B1863A0300034083A5A89394928E7C2E5032345189C7EFFEFFEAB5845439150C2165B2CDAF66231011121026489FEAFFFBCF846B6761576C9F7ACDDEDEB8763C0500020F15347CCAD6BB71381D1F2A352165B2CDAF66231001FE595F07071890765F4D4E4F67A9F4FFFFFFEFDD965C44362B2A507EC0D3D9EBD6A86B2F102664ADCAD6B99EACC2A25D1804297AB1D8D0B96D1E00001368B6D0D6D5CAB2631800003283B8CDCFCEBCAB8A531E1F40709BBDD5CAB9984100001F7AABC4CCC1B7A589320000002A93C6DED6D1D3B4690D0000003A98CED1C8C6BBA8681C001E72A5B4B8B4BAB1752F070C4376A1AFB4B9BCAC823907000F4285A49D9C938C8B7830453731528BC9FFFDF7D2AA79563E2809195FB6C9A45C1C0C0F1723355CA3D8FFF8CD856966645561A56DBAE7DFB472200000000B193B86D6DEAF643523213330195FB6C9A45C1C0C01FE5A5F070718A06F5C43444369A3F4FFFFFFFAD2935245332532538BC1D0D7E2D6B2622B102966A9CFC9A79CB0BA965817074080A8BCCEBA711D00001E63BACED9CECFB865190004398CB4CDD5D3C1AA845412133875ACC6CECBD09D4100001E76B2C1C5B8ACB47C28000000278CC7D1DED7D5B55D0A0000003E95C6D4CDB7BFAB6815002972A5BCC0C4B9AC71360F133E83B7B9B8BCB4AB7F310000144A8DA69F94969D8770215642425F96D0F9FFF4D9BB82573A1F212472BCCCAF5D260A1016252E55A1EAFFF3CD91675D605466A76FCBEDD9B4642A03000007183487D0D4AF652E22222C2A2472BCCCAF5D260A01FE5B5F070718B08468574E4C64A5EEFFFFFFFCD38A514E432A325088B7CDDCE3CFA36021142D66ACC7D9AF9CBAB887410A0A4089B6CFC5AE5E170000266DC1D8CBD3D0AF601100064391C0D0CDD3BDA9823F0B113367A8BEC9CDC2973E0100277EB1B9C3BFC0A980260000003194C7D6E7E0D1AB5A09000000419ACDD8CDC6BEA0510F012C7AB0C0B5BBB1A76E250515427EADB8B6B5BCAB82300D000E478B9FA2999B9C8D6C1F593441679AD8FFFFFCD6B07D5E3C1F12276FBCC9A156210C0E1F24345AB0EFFFF4C78C6C66635667A96FC6E1D8AC6B220000010D123883CACC9E5C3120283334276FBCC9A156210C01FE5C5F070718C0766641474261A7F2FFFFFFF4D28753473E34345492C3C0D0D9CBA35921111F6ABBE0DAAD9EB0B27C380D0E468FB7CEC9BE6A170000146DBFD2C7CAC6AC5217000C4593C8CED5D2BD957740010F2C6BA6D2D3D6D0923E00002886B7C3BFBFC0B27A270000003A9EC8D8D5D1BFA74F0000000353A2C6D3C6C7BA97550B02317FADB2BAB9AAA3601D0A13498CA7B1B1B9B6B07B300B0010538D989DA89F98906A204846516AA5E6FFFFF4E1AF8364411B15367CC5CFA04F1F0F161C222F6AB1F2FFF6D494636D685971AC64C4DFD7AB682D0000000210398DCED39A533220222A33367CC5CFA04F1F0F01FE5D5F070718D0775A423C4864A7EDFFFFFFFDC685574D352A3D5794BDBEC6D4C99C4F150C296BBAD9DDB9A8B9A276410D125498B3C2CFB0590D00001A70C5C8C8CFD6AC5D0F030950A0C2CED3C8AB9070350E093370A8C6D1D0C69B400001328CB8CBC0C1B7A373180000003897C7D0D5CFD2A2470000000E57A7CCCEC8BCC1A25D17003B88A8BAC1BDBC9D5B1A01104D8BA8B3AFB4B0AB6D2B0402165D94A7A3A79C98876817483A4665A8E9FFFFF7CFAB835D432521368BCFD69B482B10121E233173B5F6FFFAC18F7160625476B365C8DBC6A955170000000922459CDAD0975D2B1B22312A368BCFD69B482B1001FE5E5F070718E0746146444D65A4F2FFFFFCF6D7895A5546353B609CC5C7C8D4C28E4D16112971C6EBDBBBA4BB9C6D250A195AA9BCCCC9A8500D00001865BECBBFCCCCA65C12000F55A1CFD3D4CFAE8F673900063067A4C9D0D8CC933300003896C2D1C6C2BEB7701000000044A2CDD1D8D6CDA3480000000A539FC9D2CCC5B79D4509063D92B3BEB6B5BB9B5C220113488BB5B9BEB8B2AD7632110015528FAFB09D94898469114C444E79BCF6FFFFF8DAB66F58442E26418FCFCE954C1D181124273C74C4F1FFF4CE856561645676B566C6DBCF9C4E160000050A1F4AA0D0CA925532281C2D3C418FCFCE954C1D1801FE5F5F070718F076513F3F466DB2F7FFFFFFFECD825B5F3D373A6296B9ACC5D6C28B421A112977BEDFDFBBA9B8995B2802125D9FB8C8CAB2580800001467BDD6D0D8CCAC5910001B56A6D2D0D1C5A97C5A2200022B67AFC7D4E1D7963504043794BFC6BEB8BAAF690F00000050A4C5D1D6E2D39A380000000D65A0CDD1CEC7B39F3F0609428EB6BAC1BBB59E5515060F4C8BB8B6C4BEB4A0712C02061B629AA199A2988C815F1249405375AFF1FFFFFFD29D746A4D2F244B95CFD094461D160E1B273E7CC6F4F7EDCD95726C595E81C05EC9DBCFA848120000000619459AD5C4854B2C25312A384B95CFD094461D1601FE605F07071800826352585B79BBFFFFFFFFFCCE895E5C543B4A7EACC1AFC5D4C2823509062A7BBBD9E0BCB0B7924F200D1360A6C6C8C4A94E010000176DC3D0C5D0CC9E5B1A001868B5D0D1D7CAAC8059200004256CBBD7EDE2D88D2700003E97C8CCC0BFC0AC630B00000043AAD1D6CDD6DB98350000001961B2C6C3C2C1B88D3300035795BEC7C1C0BDA35B1305175191BAB7BBB3B0A465210B082663939FA5A396987F5A185D49597FC8FAFFFFFFD6AA76634A242858A1D9CB8F45231912202D4782D9FDFFF3CC8C5C55555378BB5EC7E2DD98410F000000081F54ACD7CE81351F2126303858A1D9CB8F45231901FE615F070718107B674A4C527DB4F8FFFFFFFFCC7F65614D3F4771AEC5A6BDD2B87036170E3B80BCDEE2C4BABF894E18001365ABBFD1CAA94A050000236BBEC6BFC0C99B5507001F6BBAD8D4D3C19D6F4C0F00002667B7CFD7DAD6883503053793C9C8CAC6BEB1661100000055A8D4D8D1D1CB913B0000001C68B1D3D9D5C8BA882D040C58A9C6D3C5B3AC984B14001C609BB9B7B5B5BCA15D250704236BA0A39A928A8F7C590F584D5380C5FEFFFFF6C3937C6851391F569FD7CC86432C2317212A488CCEF3F6E3B87B56595F5279B95CCADFBE94530D000003151F5CB4D4C177402224303235569FD7CC86432C2301FE625F070718207760454F5476B9FDFFFFFFFFC47D6C69493F4376B7B9ACB6C7B169280A10317BC2E3E6CEBFB2833711002075B3CDE0CCAB490600001764BBCDC7CACA8F4110072A7AC0D1CCD3BF956B480B00002470BCD0E7DBD07A2900074097C3D9C8C1B6B365110000025EB1CCD3D6D9BB9233000000287DC1E1D7C9C2A7852B030D56A5B9BDC1BBB39E491000186099BABAB6BEB49E5A1D040B20658FA5A3A39A857F4F0F5452578FDFFFFFFFFFD4A1746853363064A4DBD68B3D2C21181D27509CE0FAFFE5BF7F5956555586C558BED8C192400D00000015266EB4CDBE763424232A343B64A4DBD68B3D2C2101FE635F070718307B5953454F7CBAFDFFFFFFFCBC7C5E69573F4C75AEBFAFB6BC945D200C123C8ECDE6DDD2CFBB792C01001D6FB5C8C3CBA24D040000246CB6CCBCC6CB9C4A11072E7ABBCAC8DAC6945F3D000000276CC1DAF0E7D07B1F001147A3C3CCBAB4B6AE630700000C5FB9D0DCDCD8CB8E230000002879BED2D3C0C1B47B2F0D216CA7C7CBC1BBB29B41020018649FBDBBB8ADBEAA691D08132E6C96ADA59D978C824F02584A669DE6FFFFFFF8D1977C6654362E6BABDDCE8E452F251F202A5CA9E0FFFFE5B76F584C515686C453C0D4C0954705000008112D60B4DDB86E3926203C3C426BABDDCE8E452F2501FE645F07071840785D474C5785C8FFFFFFFFF8BA8175745642557AB6C0AEC6C5A0581804123885C5E5E6CDCCB778260000237ABCD8D6C59E41010000226CBEC6BEC9CC943B110F2D7EBBD6D6D7C48D4E270000002A75C3D7E8E5CA6E24020F4CA2D6E5CEBBC5A4550600000661B4D3D2E2D7D08E2D0000013487BACECACAC6AE771C001663A3BFC3C4B6B597450C00176DACD2C0C0B9B294541D0B0B2570989D9B969C9085510664546290F0FFFFFFF9CC9B777356424172B8E4D0914630231C253153A5E2FFFCDDB4755345494884CB59C1DBBA964303000000112668AED2AF703D30312E2B3372B8E4D09146302301FE655F070718507A564E58537CCBFDFFFFFFFFB782777959465A8CC3BDA2B4C1975019101D4085C6F0F0D2CAB8691F00002A78B3C5CAC596390000002C7EC4C0B5CCD59B4B1B0A338FC3D6D1D7B1814F200000003677C9E2E8E5C2661D0010479AD1D5CFC4BEAD4C000000115DB4D3E0E7DEC88C25000006398DB7CFCFCBBCA76C1C002270B2CDCBC1BCA88E450D001A6AA0BAC0B5B3B0A7612713162F64969F9F948E897C41006A6386B8F7FFFFFFF3C48F6969583B4680C7EED286432D251C182853B1F4FFFFE2B16A4C4852458CDB57CBD1BF8F440E000003142B73BACDA95932292831383F80C7EED286432D2501FE665F0707186075614754648BD4F7FFFFFFF8B077767A5F4A5B92C4C8AFBDBB8F501B0A113581CFE3E4DBD5B9681000002681B6CBC9C492370000002B82C2C9C0C8CB863A12143F94CBCDD2D0B3763F090000002B7ABEE2E9EDC56A210919519EC9D9CDC2C7AE4D010000116DC1E5E4E4D3C886220000104087BBC6C7C3BC9E6313082873A5C4C5C9B9B78B2F0000267AABC0C0BFB9B3985B1C0F0D2A7199AAA49C9F88783800626385AEFEFFFFFFFCCC98756A5F455093D2ECC9823429291511326DBCE7F7F4D8A36542434D5389C64EBDD6C1853C0D000009173D7CC5DEA66B352A31343B3C93D2ECC98234292901FE675F070718707A5B3C4C5385D5F7FFFFFFE9AE7B78775D486C94C4C1A3B0B6864108000C3A94D1E7EBDDDDB25B1000003082C3CDCBB888380000012A71BCC3BFC8C8953D0F134795C5DADBD1B17138050000002B79BDE4EAE2BF642105154EA7D6DECAC6C8AD4E0000000D67BADEDEE0DACB821F00000F4E8DC5CECCC5C3A45C0E002B84BEC3B6BFC7B58B340200277DB0C1BBB3AEAA934C241615347B989FA3939389762F005C6180B4FAFFFFFFF5BB886E5D55444A9DD3ECCF75393132272A3160C5EAFFF4CA9E5B38393A5392CC56C2CCAD7C3E0900000A294B8EC9DC9E5B372730353B3B9DD3ECCF7539313201FE685F070718807F694B53669AE2FFFFFFFFEFAB8480846557699FD1CBB3BFBB863607000F4687C4E9E8E0DCB15A1300003B90B9D4CCBE852E000000357FC2CDBDC6D0A3430D0B46ABC9D0CDCCA85721000000003186C9DCF5E4C9661A081B569FDCDBCBCCBDA9470000001B71C0D2DEDCDCC87D2200001E4F9ACAD2CDC7BC9D500E083184B1BCBFB9BBAF822200003681B4C9C1C4BEB48C481A15143770999CA39599887135006F7082BAFFFFFFFFF1BD8C6E615A4A589EEAF1D07831352921253071C3E8F2F4D293563C3A3B5698D147C0CFB97E30030000071D4592CCDEA255352A2B34353B9EEAF1D07831352901FE695F07071890776147556E9DE0FFFFFFFFEAB58985815E4966A5D1C3BAC2BA7C3C0907163B8DC1E1ECDED7AF5A1100083B8CBEC8C6B97F2B0000003883C9D2CBCFCF9F39081350A0CAD7D5D49D5820000000083C8AC4E4F5EDC15A1800224FA5D6D8CBBCC1A247000000207EB3D3D3DDD3BF731C0104265C98C1D4D7BFB59145040F418EACBFBCC0C3B3782A00063384B6C6C2BCBAB58E42111019357793A1A198978B6F3600686E87BEFFFFFFFFF7BD85677062565AA2DDF5C777363C2E1E234882C2E9FFF1C18E4B3E3640569FD451C4C5AB7732000A05192A4A92D6D3954F2A303B392B3CA2DDF5C777363C2E01FE6A5F070718A07153504C639EE9FFFFFFFFE3A8828C8B5D4C66A0C7CCBCB8A76D410D0718438EC2DDE0E8DBAE52080008368FC6D5D3BA7A29000004328AC7CEC3CFC8883C161458A2CFD4CEC08E5219000000003B94CDE5F9EAC06014032E5DA3D9D7CFC9BA9C39000000247EC3D6D4D8DDC8741E000628689ECACCC6BAB9923703074C96BDBFC8BFB8A67B320002398EBBC4B8BCB7AE90492314163D76959E9B918B8E652500696994CFFFFFFFFFE7AA8A6F5553495EADE6F2C475383B2E23243E79C9F5FFF8CD904C342B3B5E97D249BBCCAF7C2907000010295298CDCE894B272625273742ADE6F2C475383B2E01FE6B5F070718B0785C4D54649AE6FAFFFFFDD79B7C8F8F665174B9CECBC0BEAA612D040C164687C9E5EAEBD8A24C02000E4D95C6D1CAB86D220000044780CED5C4CBC291460D1653A8CECED1C68E451300000000317CC1E6F2E7BC591A00215DA9DFE6D7CEC29D330000002E81BDD7DCD8DECB721200143D72A3BFD2CBC3AF8B36000350A2C0D0C3B6B1A57C1E00003C8ABCC5AEADB0A47F401C1319447C99A3978F92885C2A006F6E84C2FFFFFFFFE0B5836062594C60B2E9F6BE6738333921274287D6FAFFF4C08A4D37393A53A1D94BC6C8A9702505000C103356A3E0DE924A272C292F4448B2E9F6BE6738333901FE6C5F070718C08263495E74ADFAFFFFFFFAD79E92998B604F7FB7D2D5C6BFA5642C0A09224B88BCDCE3DECA954708000E5199BCDBD3BA711C000006459ACED5CED2BF873C0D1A61AAC7DAD2BE893E0E000000003E95D0E8EFE2BD5916001F64B5CFE1D4DCC78A2A0000032D82C5E0DAD6D3BE6C1904184879A5C6C2C6BBAC703100144995C2BFB7B2B1A77623000B438ABDC9C4BDB5B17B3717161547798D939693918462250071728ED2FFFFFFFFE8B375666060516ABFEEEFC4703D3739282B4B9BE9F9F9ECC08439332C335FAAE155C1C19462200C0905172C65AAD8CF834025272E3F3C45BFEEEFC4703D373901FE6D5F070718D07A61566375B1F5FCFFFFF1CC9982958D604F7CB6CACFCAC7A5582E0B0A264885C1E5E0DDD1A73E0000154F9DC4D5D3B1651F0000044291D1D8D9D5C78134162572B1CEDAD5BD7C280000000002449AD8EEF3ECAE4D120E306BA7C9E2E3D9B9882A00000F3883CBD2D2D9CAB7671600224C7EA9BDC7D5C6AD752100095F9AB4C2C4BBAFB0701A00054699C1C3BEB0B1AD73351C21264A8092A39C928F865E1D00697589E5FFFFFFFFE6A983695C5C5283D1E8EEC6733648302430559CD9FFFFECC27F3F2B292E57A1D947B4BF8B662D110A161A4076BCD7C288422930292A3F40D1E8EEC67336483001FE6E5F070718E0705D4A5263A9FDFFFFFFE8C898889079555083BADCCEBFC5A258250501214D93C3E1E1E8D6913F00001756A2C8D4CDA76516000019478ACBDDCFD6C18237152B70B2CBD1D1BC713201000000014791CFF1E9DFB54E1A103670AED4E7D5CEBB8524000008337CBFD2D1DCD4B4601003165787B2C4C9D1C4A16213000C67A8C1C5C7BBB0A6651A00125193BCBDC2BEB7A975281228285281979992878781581B00677794D7FFFFFFFFD3A371615F5A5577CDF2F4BF663433372D3255A1F0FFFCEEB1724223122B66A9D947BBB58860221300061B3E73BEDFCC8044242628313242CDF2F4BF6634333701FE6F5F070718F0745548516FA8F9F4FCF4E7BD91909F895A5687B9D6CABDBE9459170308225297B7D6E5E1C4883001001F65ACC8CDCBA9611B00001950A6D5D0CFD4C1742C09276CBAD6D8D8B66F26000000000A57A2D5EBEDE2AB43100C336FB9DFDAD6CDBF8019000011328EC9D7D1CECAAE5E1910296098B4C4C8C4C19C5409001773ACC3C2BEB6B59F671400045799C1BCAFB6B6A76E251E1E1E538FA59C91848F8250170073758ED4FFFFFFFFCB93685451555D8DD7F7F1BF5E333834142C58AAF0FFFFE1A861322525255FAEDC43B8B680512B170A0B1C3773BFE0CB77312D333E3C3E42D7F7F1BF5E33383401FE705F070718006F5A4E5A76B6F5FFFFF9D2B68887997A534D8DC8D4D8CBC38F551E000B254B8ABED8E4DCC3812D00002264A4CED9CCA5591500031E5CB0D5DED6CDB76F2F182C75C7D0DECFAF681F0000000009509CD6E5F5DDAA3A12163A78B3D0DEDFCCB1741A000010408DC0CEDAD5CDA74A14072F72A3B6C0CCC9C29A460800176AACBFBBB2B1B6A9661B000758A3B6C3B5B7B39A6D2F1B2333608C9CA39D8D837B5818006B7096DBFFFFFFFFCF8C5C5462615D8BDFFCE9BD67343F3C2F3467BFF8FDF9DEAB70351F252D58A4D849B9B67F451D040A121D3B85C4E0B5743C25353540334ADFFCE9BD67343F3C01FE715F07071810765E575D80C2FFFFFFFFC7A48B849B7D4D4C92CBD5DAD0C4944F230908255096CCE3E2E2D280290300225AA4CFD8CEAA571400002858A2DBE4D9C9B277361C2F81BACEDBCCB76813000000001661A3D2E2E5D49F3D0C18497DB6DCE3DACEAC6D110000144790BACCD4D2C4A24C130E36759CBDC6C1C1BE913E00001A80B3C8C4B7B9B7A8651A000C5B98B4B8AFB2B79B55252026305B8C9798948B8A83470A007C7899EAFFFFFFFFD890615453605F8BDFF5EAB76A353732263575C7F7FFFFEBA7612F1E242E5DB5D93DAEB47A4A291206001D3F88D0DFC0643B30362A2F3C3BDFF5EAB76A35373201FE725F070718206E605D607FC2FFFFFFF9C5A5828F9B7D54568DCAE5E7D7C68E4B231415315796CBE1E0DEBA6F240000337EB0C9D2C6A8490E00062467ABDADBD4D7B0783111277EC0D1CAC1B0610A000000001764ABDCECEDE19D3914204E7CBCD9E4DDBDAF641100002E4F90C7CED5D0C39743090D387DA6BFBBC3BEA9933D00002C7CC1C5B6B7B5AFA76812000E5FA1B8CAB7AEAD8C5C1D1F2D3E628E989D8F8B84844B0F006C658ED8FFFFFFFFC181605253596295EEFFECB267394034292E7AC8FDFFFBDE9E5D2D1F1F2864B0DA47B3AF6C3C160B0813193E83D8E3BC663A31332C343D4CEEFFECB26739403401FE735F0707183076695A6482C6FFFFFFF3C597788695735660ABD6E0D9DBC98945180B132F619ED0DCEAD2B4631D0007317BBCD4D9D5A84D08000C2766B6D7DCDAC6B06B2A113285BFC2D2C1AE5C15000000001D66ABDAECF0D9992F0E195F88C4E7D8D3BFA7600500002C52A0C2D5D3C5BC8E441513487DA9B9B5BFB5B38B3C0000287EB8BEBFB6B5ADA76E19000E5EAEBDC4AFABA58753261923346585A09F9A878672420A00757193DCFFFFFFF1B47951474B526BA8E7F8E5AF672E332F364883CAFEFFFCE1945728201D3763B7DD45AEA76C3C170B13191E488ED0DFBA623A2A293839404EE7F8E5AF672E332F01FE745F07071840796355667FC4FFFFFFECB68A748B936B5060A5D1E4E3DEC88E511F0F1A356496C7DBDDDFB6591300053881B6CBD5CCA6520D001240759CD0D2D9D1AF6825143687B8CFD5C7A75F0A000000001A6DB0D3E7EDD695310B205796C6D5D8DEC894530800002E5994C3D5D5D6CA9A3A091A4D83B1BDB9C2BDAC762D00003081B4C4BCACB0B3A3610F00186AAFC0B7B1B0AA873C1017313569979AA1958B8A75400B006B6B94E9FFFFFFEDB46F4E49535C64AEEDF8ECA24C2C3F371D387DCEFCFFF9E19E622E1A202967B7DF54B89A5A2D120C131A264493D7DDB26430322F30333F44EDF8ECA24C2C3F3701FE755F070718506D58546782D1FFFFFFE1A77D748C8D66465AA3D1DED8D3C98A461806203769AAD6E4E0CC9D601500073F81BACED3D0A34A08000C3569B1D8D9CBD0B36A2C1A4883BFD0D6CCAF5901000000002465BADDE7E2D28D3110236698C1E0D2D3C58E4E0000063F61A1C9D0D8CAB7852D121D5794AEBAC1C1BDAD77210000308EBCC1C4B8B4AFA05F0F001368AEC2BEC4B7A7783B1A272B386590A4A7958E85763403007D86A8F4FFFFFFFFB7805045506078B5F4FFEBAB5B323C33304B8ED7FDFFFDD99A572F191B2366B3DE50AB9B5E3517141C17253C98D7E6B46523222F312F374AF4FFEBAB5B323C3301FE765F07071860766A5A6383C5FFFFFFD99A70637E7E705365A6D3E3D7DECA84421F0D204173AFCFDEE3D6A25114000F4B8EBED7CBC99B3E0000194280B4D1DED4C2A16223183A8CC3CCC9CCB65608000000002077BFDEE6E5D08B2B0B29699CCED2DAD7C893470000114167A1C3D2C9BFB881290B1B549CB5BABDB4B8AA6F220000328CBAC9B8B5B9B79B5A12000F66A3C4C7B0B09F6D2F142A29406D8FA297938B8A79390900757BA8FAFFFFFFFDA7694D4851647FC7FFFFEAA6533232262B3F89DAFFFFF6DA8F56291F192B6FC1E65DB69D54281218131D244691D7E3A95A302B2C353E3A54FFFFEAA65332322601FE775F070718707E65606B97D9FFFFFFD397685F8B7F684C6AAFDCDEE8DFCF944B2414214876B8CFE2E7D49B460A00013D94C3DBDFD09F470804113D7FB2D1CBD9CA9B6523183A94B8C8C9C9A94D0B000000002075B9D2E6E7D382250F3774ACCDD6D1DCC2823300001B4D7CA6C9D2D3D0B86D220B275E99B6C0B0C4C1A7621D00002782BAC4B4BABDBDA36517000C6BA6B6BEB7B7A66E2C1A2338467A9DA29B9884896D2A00006D749FE8FFFFFFEA9F664541485E85C7F8F3D7A5513A372E224592DDF5FFEFD5975126221D2E66B5D94DAA8C582E1819181628418ED6E2A558322C2D2A3A455EF8F3D7A5513A372E01FE785F0707188078736774A2E5FFFFFFDA99676A87815F4D6CADE8EDE6E7CF95411E0B2A4A7FB6D7E2E5C0933C03000949ABC2E0D9D5993C0400144B8AC7D8CCC8BF944F231A4296BBCDC8C1B35009000000002F80BDDEE5E9C87328103176AAD3CFDADBB77420000021647EB3C8D0D5C1AB6C1D05225C9EAFB9B1BDBDA7661600003E99C1C3C2B8ADABA05F18001679B9BEC3AFA897682309232E477A9CA1A29C978D702B00006F70A1E9FFFFFFF5A8634E38516580D1F7FDE09149223837244F9EDDFFFFFDD494552E23192275BEDE50A2804F2610151616234E98D6E0AD5D3024373F43395AF7FDE0914922383701FE795F070718907063615F8FD1FFFFFFBD774A5071765F4A63B2E5DFE2E0CA8C3C22102D5787AFCAD7D6C98F3910000C55A6C6DDDBCC943F090B20558CBBD3D3C4BB9350211D4891B5C6C4CBA75700000000003A85C7CBDAE4BB6A1F093184B9D3D6DAD2B267180000296683B2C7C7C2BFAB6B1D002972A1BDBEB6C0B9A35F0C0000429CBFCBB6B8B2ACA2651C001168A7BCC1BCAF95571E0D29374A789BAC96918687732A00007370A2EFFFFFFFE29E5B43343E6DA6D5FFFBE18E4F293B3A324C99E6FFFFF0CF863F271A172A7DC1DF57A98E4F1B040D1613294491D5D9A4552C2B39363B3C52FFFBE18E4F293B3A01FE7A5F070718A0715B51678AD5FFFFFFBC733E547B7658496EADE3E8EBDCC885411C0B2F5588C1D8E7DEC7863100001356ACD1DCCFC598420E091F5899C1CECFC8B9864A15163C8CBDCAC6C2B45C06000000003080C3CCD9DDC17721133E86C5DFD7D9D6B860160000226587AECDC2C4CB9D5313104079A9B2BEB0B4BFA7561000003A94BFCBBFB6B3B79C6018001678B3B6B5B4B792531B0C1D2E497E989F9A918887631800007176A2F5FFFFFFD08252343C4167A1D8FFFBD9964B283830234BA0E8FFFBEFCF884824171E3B83CAE454957E4B1A0C151816213DA1E0D9AA57322E423B353C5AFFFBD9964B28383001FE7B5F070718B06A5A4D6791C8FFFFFFB36D3E466A6F5A5974BDE6EAE3DFCA8B42170C2E608ECAD8DDDCC97C2600000E5FB1D0DDDCCC942E000128639BC6D4D5C8B77E3F1818468BBBCECBC4AF4E00000000004597C5D1D7DBB069200E3E90CBE6D9DAC8AD4E0E0000287194B5C6D5CDCE9E530C0D3772A4BAC4ADB3B6A3500500004A97B8C1C4BCB9B3A6670E001A77A2B7BAB8B2944E130C2B324C84A2A2A0A09B855C1100007271A9FCFFFFFFDD8D5440394D6D9DE2FFF7D7914D2B3530284E9CE5FFFFE9C68245241A1A3580CEE253A07B381B060F18251C3E91DFDC91513A35393E314160FFF7D7914D2B353001FE7C5F070718C073655C7795D7FFFFFAA9653A4B736F464C7BBDEBEFE5E1C77E371814366397C0D8DEDDBE752700001167B5D5E0D2CF9B4000083575ABC7CDD5C1A97336141E4E8ABAD0CBC3A6540B000000003D94BEC5D3DEB65E0D094B97CDDEDFD5C89F4D0300003C89A0BED2CBC6B9913F03094786ADBBB4ACAEB8964900000356A0C3C2C0B1BAB1A1610A002377B1B2B2A7A58A400B0821374F85979793918F936C2600007376B1FEFFFFFFD37B4433384573A6E1FFFBD78C461F2B31284FA2F4FFFFF4C88A4C1C1A1D3E8DD0E55698703C18110A19132651A1DCDBA2582E2C322C304060FFFBD78C461F2B3101FE7D5F070718D07A645F6E9ADCFFFFF4B2693D4A6960535C7EBCEDF3E5E2C5813A1C143B6E94C3DADED7B3731F00001167B9CADCD8CF934413143D84ADC7D5CBC6A86B2909124D8FC4C0C3BAA6450400000000439BC7C9CFD3B7641C154A98D2E6DCCEC493370000063D88A1C4C8C0BFB29241051F548BB3C0B4A4B5BA91410300085896BFC8B0BDB9AC9D6213001A80AFB7B9B4AD7F2E02001836608CA6959189888A5E150100797DBBFFFFFFFFDD8A5139405576BBE7FFFDCA89462C292F2455ACF4FFFFE7CA7D331B14224496D9EE47A37B44250E0E1218204F9FDCD5954829212E3B393E5CFFFDCA89462C292F01FE7E5F070718E07560556D8DDCFFFFF5945537456759535776BAE4F3E1E3C8792C1E283E749BBFD5DAD0B46D1F00001368B9D2DDDFCF953808103F84ADC7D1CEBD9A5C2B0A1F549AB6CBC6C0AD54000000000053A6C1C6D2D9A9530F0E4FA0CCD6D5D2CC94310000094B94B1BEB8C6C5C0883C060E5594B3BCB4A4A8B8903300000E5795B7B9BBC1C2B6A1611A002071ADBCB2ABA0813609041C3A5D899F9590919793590E00006C76B6FFFFFFFFCC874936364372BBF5FFF6CC80461E25252056ADF5FFFBE5C07B3C1919244790D4DF49A1793F1B081517081D51A4E7D59348262B4140374163FFF6CC80461E252501FE7F5F070718F077625B7094E3FFFFF0955D304158594C5B7EBAE4F0E8DFC2813715194B71A2C7D1DAD4A7561000001B6CBED1DADAD98C370C114683B2CDD0C9C4994F1F0D25569EB4C6C6B8A94E0000000000509EC3CBCDC7A656181556ADD3D8D1C6CE912F0000044DA0BABFC2C1CABD8B3702175E99B3B5B6A8AEB285360000156CA5BEB9B4B1B2B09A5314001C77B1BEBFB1A379380B0628335B879E97969C9B84571300006F7BBAFFFFFFFFCE7F473933487BBCF4FFEFC47D443425272864B8EEFFFDF1C47E3C1F182A4B9FD2E847947F441B101315110F469CE4DA8E4A2A243432434368FFEFC47D4434252701FE805F070718006D5B517197DDFFFFE7894527345C4E425681C2E2E6DAE5C27A3317184387ADC6DADAD6A1520B00001C71C3DDD9D6C4862B0E15508BB6CCD0C8BD91521E0C2A629FB5C3C7BBA44500000000004FA0BBB6CDD3A752141959A8CBD7D9CEC18C2700001365A4B1CACFCBBBAF7B31061F699CB5B7B5A1ADB37E250000196CA8C1BFBEB6B6B1A05E0800217CBEBFB7B4A375360A001B405F91A19089909A91500B0000737ABCFFFFFFFFC66A3D36334884C4FBFFF0C08A472B222C386ABEF3FFFFE4B682421F1B2B52A1DDE84B95793E170C0D15152450A7E9D78F3F262C2E35474765FFF0C08A472B222C01FE815F07071810795C52709DD1FFFFF08D46273A5A4F4B5A86BFE4F2DDDEBE7336111C4888B3CDD5CFC9A0560F00001C72C6DADBDDCA822A03085099C1CCCECDBE914E18111D5398C2CDC9C4AA51010000000059A2BFC3C7C59D50121962AFD7E3D6D1C7892100001A6AA8C3CBC5C6BEAB7023002474B2C4C1AFA1A3AA7D2800001C6DAAB4BFB1A5AAAA99550E002874B3B7C3B9A369270800173C648FA29385939C8A4A0A00036F82C3FFFFFFFFC36C372A315680C9FFFFF9C685482D191E2B60B5E7FDFDDCB071371F1E3968ACE2E649937B42180B06131F265AADE8DB8A3E2A303D44414B6DFFF9C685482D191E01FE825F07071820755F54649CE6FFFFE277342033544C516A95D1F2F1D8D2B25D2D18215194B8C8D4D2C5954B1000002380C3D7DAD7C57F2B0418599FC5D1D4D4C08B3C0B022B639ABBBCC7C0AB470400000008589EBCBED2CB953E12195CB3D7D3D4CBBA84180000216CADBBC2C6C4B5A76C1D00296CAAC2B9ACAAA8B188320000307DAEBDBCBCB2B4AD925906002475A7B6B9ACA5692109070F336692A796969696854F0C00007486D5FFFFFFFFC37D4C3235478AD5FFFFF6B67C463525243573C5FEFFFFDBAA63341B282662AEEDE84C9779471E120F0C113657B6ECD591442D293638304775FFF6B67C4635252401FE835F070718307C6455699FDCFFFFE4844324365A4B52618ECFF6EBDED7AF632A17245691B7D7D8D9C38F400000001D75BEDEE3DED07B29062165A9C5CCC8CEBF802F090734639EB7C5CAC89C480B000000025AA3B8B4CBC6914D13165AA8CDD8CEC6B482240000227BB5CACFD1C1ADA66410002D78ABC3C1B4A9B09E74210000327CB4B2B6B6BAB6A5904E0300217DAAB6AEAEA0642002061B40659A97948798997F4007030A6885CEFFFFFFFEB3714936365390D5FFFFE7BB783E25231A2761C1EFFFFEDBAC6C3819223178B9E8E34D9D753522120F0B11285AB0EAE28C472F2D3D363B4B7EFFE7BB783E25231A01FE845F0707184071584B5C88DEFFFFD37C351A2F46453D5C93CAF0ECCBC79F58200D205BA7C3C7D4D7C1813B010000277AC5D7D6D8C371250A2368ACC6C3D3D0B77C3108032D75A4BDBEC1BFA43E00000000076AAEC1C2C5C78D39091B64B8DDE4D7CAB9781400003180BDC7C0BDC5BEA65E10002E82A9B2A8B2B0B1AB6D1E000A3C789FB6B6B5B1ABA3914A08002A7DBAB5B2AA9D652000011C41759EA79582929680430B0003738FE6FFFFFFFFB56B414142578CD9FFFFE5AB704A2B222A3C75C7F3FFF7D2A96B2C10214276C4E6EC4E9A743C1C130B10182264C3F5DC8F412A2B3C363A4979FFE5AB704A2B222A01FE855F070718507A6D636DA0E3FFFFDC7139263A453C53709DD3F3E8CECBA355220E1850A7C6D0CFD2C47C35000004307ACAE2DBD1C36D16021C6AABC7CBD8CDBD752C00043E82AEBBC4BCC0A23E060000000D6CAAB9B6B8C087350F1C58B4DBDED7CEBF7B2000003988BBBBC3BEBAB0965618002F8CBCBBBAB1A9A899651900134787B3C0B9B7B7AAAA853D00002576A9B7B6A79B591C0204193B6C9DAC8F7D8F8C823900000A6F93D8FFFFFFF9AF613B353F5398E1FFFFE6A76F402724273372C5F6FFF7D19F63341C0E3A83C8EDEE438A754F241712090E2465C1ECD47D3A25253D383D528CFFE6A76F4027242701FE865F070718606C58506494DEFDFFDD77351C2B45424D6BA2D9E5E9CFC195441B0F1B5EA0B6C2C9C8AE76280000073183C2D9E0D5C372270F317BB1C9D0CDC9AA742D0B0A3A74B2C9C6C3BC8B37000000001B67A4B7BDC6C88830072053B0D4DFD5D0BD731300004080B1BAC6CFC5B6964B08003F89C8C5B1B2B2B69D680D0009448CB0C7C4BCB2B3A3903B0000276E9CB3B8AF8F561A00001F4466949D84848E9478360301087F9EE5FFFFFFFCAD64433B4C62A1E6FFFFE0A36C4329272E3E7BCBF6FFF0C4945B231D2B5188CEEEE53E8D663022100E10193264BCEDDB82302425383F424888FFE0A36C4329272E01FE875F070718707A66506AA7DFFFFFD7753816233F3A5172A1CFF0E4D2C38E421D0D2869B0C6CDD1CFAD73280200053282CBE3D7D9C1681F0F3681B3C5CCCBCCBA5B1B00023A81A3BDC6C2C09D3F120000001A6CABBDBDC7B87729062066B4D1E2D5CCBD711500003C8CB9BCBCC8BEB2933B02003592BCC2B6B4AAB2AC6408000F497FAEC0BCB8B6A49F963B0000297FA2B1BAA89057160A001B3F7998A183829BA1853600030A7897E0FFFFFFE3995940343B64A3E3FFFFE49E6F412C203C3273C3F2FCECC691552110244C97D1EEE93E8D70382711151520306ECCF4D27D3424302D393F4B86FFE49E6F412C203C01FE885F070718806B5950638FDCF6FDCF712F0B21383D4F75AED9E5E2D4BF8C4314101D68A8BFCDD8D2AE631F000005418BC3DCDACDB7691E073B89B8D3CCC7C0AB580A00064B88B3C6BFBCAF903F050000001972AFB3B8C2BE71290E236CABD3DED0CCBA621100094E9CC0C0C3C5B7AC802E0400368FBDC2C1B9B0B59E5F1000165890AEB7C6BAA59293803200003581A5AEB3B19753190B031A406893A97E78938E722E080E2481A4F0FFFFFFEC9B62433A345DA4E1FFFFD5975C3D2D28272B7BC3F2F3EABE875927162858BFE6F9F1428F683F1F11111B1A2774C7F3D07B36232F302C395489FFD5975C3D2D282701FE895F07071890765E516DA3D7F3FBD06D2B151B3D3B577CB2DCF0E2CFB8822E0B0B296EB3C9CBC7CB9F5F22000006398CD0DDE1D8B95F19124993C3D9CDC8BEA7511500094E8EB1C5B4C0B081310F0000002479B1C1C2C5B5661F021B64B0D2E2D7C7BF630100084E9AC7C2C7CCC9B1883C02004485AEBCB5B2A1B99F5D1202236099B2C0C1BAB49E977C2C00002F789EB3B4A78546160502124578959C837B988C702800061788AFFBFFFFFFE7905F3F2C3C66B7EEFFFFD5925D372B262C3B76CCEFFAE7B98B522F242E61A9E3F3EC408869401A0C090E1C2D82C9FFD76C302B2F3A2E3F4897FFD5925D372B262C01FE8A5F070718A0725C5166A2E3F6F7D2702A12273A3A5A81ADD9E3D7B7A8732F100D2A72B3CBD4CCC49F5919000008509DCBE4DECAAF5D1D16458EB3C6C7D1C6A54B0D0013579AC4BEB8BAB57E2E030000002D81BABABBBFAF651B032764B3D4DCD4C3B25A050009539CC4B3B2BDC7A97B280000469BC1B4BBB7ADBDA54E07022A619CB1B9B3BBB4AB92782E00003589B0B8B5A2803E1500070C417A97A78876928F682000041A7FB8FFFFFFFFDD9C60433B4174BCFEFFFEC99057362A272E4580CEE1E8E2B87C5630192665AFE7F1E3438969321D15131B293B80CCF2C975402C2530363E5891FEC99057362A272E01FE8B5F070718B0786855749DD4F8F8CF6B2E162032415E8FBAE1E3D5BAA471340D081D70B0C7CDD2BE9B52130006194E94D9DDDED7B2601E11449BC1CEC9D0BA9B4D0B0017639CB5BEB9BCBA8D36040000002374AAB7AECAB65F1D022676BFCFD8CAC1A8590300165F9CC0C3BCC3C1A36C150000509FC5C0BFC0B8BCA3560C001F60A0B2BABCB3AFA08F712100003881A8B6ACA4823C0D0805194D7AA49C797C9A9A6F2D0B001E8AD1FFFFFFFFD1884E3F353C60B8EDFFF0C77C4F37222C2F4383D4EBF2E3AF794F2C232C5FA8DCF2DD478766391C0812161A368ADBF9C97B352328333544519BF0C77C4F37222C2F01FE8C5F070718C06D545173A4D5EAEED4722C0D0C252A5C92BAD9E7D7C2A05E2103092C72B8D1CDD4C993420D0000134FA0D6E9E8CDAD521111599EC4CCCDD2D3A549010008549BC1C4C3BDB07D2B0D0000013282B6C1C0B8A45B1B082868B1D2D9DDC4AC590A001167A0C6BCB2BDB7AC772000004C9FB8C6B8B0B6B4A14F08052A659EA8B3ACB8A99B865D1400053B84B3B1B2A6833E1D04051E5480A8A976788B92621900002A86C3FFFFFFFFCD8B573B464771C5FFFFFBBE805731242830458CD1E3F0D5A96A462D223172B8F0F5E24187603A1A161520243C91CFF5C971302E2C3A3A3C569CFBBE80573124283001FE8D5F070718D07B615575A9D9E7DFC46D1B040B27355D91C1D8D8CFB2915E1C050F2278B4C6CAD0B98B440000001556A7D2E6EDD79F4913155AA4C8D6D6C8C39E3F00001767A6C0C4B9BCAD733010020000327EB2C4C0BF9C520F00226EB3DBDBD4C9B54F0400196DADC0AAACB4C0AA6F1A0000509ABDBFBFB6B1B1A1540C0B35689CACBDAAA49F9083692000004583B0B1AFA2753A16020019547A9EAB777D968D6415000B3091DBFFFFFFFFC579473A343E71C6F9FFF9B27C48332224313E82CFE3E6D4AA5E3F2A2A337AC2ECFAE4447E56341614121D1F5697DBFAC6702A212C3D3C405CA5F9B27C483322243101FE8E5F070718E0775E627EB6DFF0E4D0782B03082430548BCBEFE5CEAD84561B0008296CBDD3C9CABE8D371200001F5AA0D1DBDBCE9C4A161D5CAAD1D0C6D3C7953B06001E67A8C7C2B2B4A6661C000302022D8BC2C0BDB9965612052D78ADD9DCD3CEB45600002077A2C3BAB8B9B2A1601600004B9EBAB9BBB7B7B799470A083D7BAABBC3BEB8A8847051190000347DACB9B1A0713A12060020558C9DA880809991551A00042491D0FFFFFFFFC3754B2E263777C5FFFFF0AB7645291E2B31387EBFDFE7D7A267412E1D3377CBF0EFD34A82622B1C0C1323224B9EE4F2C46F3325242F34445CA6F0AB7645291E2B3101FE8F5F070718F07569607CA7E1EFE3C96B2D0F08273B65A9D4E3E9C49F834618040D3385C5CAD2C6C686360700001C5DAFD9E4E8D29245161960AECCC8BED0C28B3702021E69AABFC5BFBB9E702C040300124587B2B6C2C2964003022B74BED6D9C9C3B04F01002C81B9C8B4A8AEB79C590B00004B97BAC2C2BCBBB9954D1112488EA3B5B1BFB1A88D6D4B0F0005418BA8A9B0AB69301806001D588CAAA5868B96935511000C2B9FDEFFFFFFF5BA6B442D3B4181D1FFFFEBA262322F2E28303D91C6DEE5CC9A653E2F2A3883C8F3F8E34D7F5D2D17151B1D1F4DACEAFDC5682A1D2937384666A6EBA262322F2E283001FE905F070718007A706897B9DDF1E8CA682A0E0B26386BA7CAE4E3D1A3753D0E00093788C5C7CEDABB742E0500062A69B4E6E4E3CE9341191B65B8CAD5C7C9C3933400001372A4C4CCC3BDA5642508080F1E4C83A5BCB6BB993E0F04347FBECFD5D4C0A34400002780B3C5B7ACBCAE964E05000155A2BFBAC1BCB9B59241040D5288A9B5B0B3B59A715D490900064689A9B5B79D74341A0C04225388A2A7817F9B83471609163AA3E2FFFFFFF7AA674031314A8DDAFFFFE19B6E442D2C2F2F398DC5D9DECB8D5D371D1D378CD2F9EDD05173552D1A1F1F2A315AABE7F9BD6F272123243A4A61ACE19B6E442D2C2F2F01FE915F0707181078636882B8DFEAE1CD692601091D3C78A8D6E7E6CDA16C3D18030C2B82BFCACAC4C5812A0000072C76B6D8E7E2BE8D420A1764ADC9CFCBD9C1863906002077B7C6C2BBBCA46528110911264F8CAFC1C3BA8C3D08072D78AACCD7D6CBA43F00002B7EAACABAB5C2B4A048060004529BC8CDC2BEBFBD963F0C12488FA5A7B9A9B4A3775A3D0800044191B1BBB6A4652D0D02021E5E8EB1AD85909F874408001A37B0F1FFFFFFE8AC634035344887CFFFFFF19A643429262F30447EB6BDCAC4915D2F1F29418AD4F8F6DD55784E29161F20223055A4E9F9C2672B2024363C4E6AB5F19A643429262F3001FE925F070718207D767C9DCEE9F2F7C8772D070520406EB5DEE7E6C38561320800113F8BB7C8D0CFC0762E0000083875BBECE7DEBB82320D2469B5D5CAB8C7BA882C0002287DB6BECEC3B7A662291108121D5198BACAC8B0842A0000377EBBC9DADFBCA04506003887BAC6B3A6B5BD934300000454A8C2BFB7ABB1BA8A36091D6189A3BDB7BAB7A57A512F0A000B4D92B3B8BA9B67330C0105226096B0A987879685440B001643AAE5FFFFFFD8905B3F2C32478DD3FFFFDE9153352D28252E4D94C6D3D2BD884D2A211C4595DFFBEACE4E71482916181D26325FB1F0F8BC5A26232E313B4B6DB7DE9153352D28252E01FE935F070718306A7683A4CDE2EFE5C767250000153C75B9DFE4E2C78B59280908164587B6C2C9C5B97528000008327EBBE6E9DCCB7F35182564B1CBCBCCC9C3842400103583B5C9C1B5BC95581C100A13245894B8C3C0B07C2C02052A7AB3D8DCD6C09B480002448EC1CDB9AAB8B490460100085C9EBEC2B7B5B9B1862A001E5C96ACB9B0B3B1A4694A220000125F97BFB6AE9A60210D0C0B2A6195AAAD9292A080490F00144EABFCFFFFFFD88E4E2A2A334991DCFFFFD3834F2E20212F324989C0C7D8B07B492E21224698E5FDF0CD536D4E33201827325166B6F0F3B16632201D30324374C3D3834F2E20212F3201FE945F07071840797F8AAAD4E6ECE6CB6D2707051F407FC7E8EEEDC9824819000118488EC0D3D0CABC7623000012488CCEE0E3ECC876300C2776B5CDCACFC5BA782502013586B2BEC3B9B69D5724110B1A256398B4BABEB57B250005367FB6D2D8CBB699450000438FBCC4B2B7B8B28B2F000009559AB7BFB6BFC8BC862200186A96AFB4AFABB298643F1F0000165092B8C0BB965E2A15050F2B68A7B8AF94879981400D081F47ADEBFFFFFFCD7D5036222C4293DBFCFBD3843C2D272A2A2F478ABABCC8B8874C2E273049A7F5FFE8B44965482C1D222D273E6ABEF4F9B7652F1F2630354D82C8D3843C2D272A2A2F01FE955F07071850757783A2C3DDE6E6C6671D0406234083C2E6E5E1B97045170200194D97C6C9CFC5BA6E2C0000134082C1E0EEEAB95923123077C2CFC5BCC3B280360B0D3E7DB7C7C1BEB08E592514081A4061AABABABDAF772100003592B4CCD1CBC29A35000654A0B6CBB1B2B7AA813000000859A0CAC2BBB2C6B97821021C63A2ACB7ACB1B59E6233150000285C99C1AFA995572914010F2F64A6BFBA968FA1853309001348B2EAFFFFFFCB853F2423344FA4DFFFFDCC8646261E272A2C4993C1BEBBB36F45202B2C4D98DBFFF2C45B6A4720212B29293B6AC2F5F8B45A2C2627393E5989CDCC8646261E272A2C01FE965F07071860747E89B6D0E7DBDAC6752D060018488FD5EBE5D8AD733F1C0001195799C4D0C8BDAB642000000B4694CCE5E7D3AF60281B3A80CAD3C0BCCEB57D2C060C4393B4C9C1B8BB8B4F2B1B11234B709CABB3B4A86C1C00003B84C4D3D3CFBF902B00005298BBC9BEAAADA991330000035999C2C1CDBBBCB77716002471A1B9B9B7BAAF935C320A00002660A0B3B9B59A4D270F0C0F3366A3BFB49D8E9C7E3408031644B8F2FFFFF5B37A422B26335099E4FFFCCA7C46202527262D4B92AAB3B8A76D45282B2046A0E3F9EDC55C6B3C2419232C334075C6FFEAB05D2A2228353C4C85D3CA7C46202527262D01FE975F07071870738293B6D2EDE0EBC56E2100001B5197D3EEE0D6B5703A1000002561AFCDC7C8C4B16C2B0E00154694C8DFE5DBAA51180A2B82C0CDC5B9C5BB7B28000A488DB7C2C8BDAF8A4E271B142853749FAEC3C1A863120000388DBAD1CCCDB69831000D53ABBACCB6ADB8AB762800000D5FACCAC1C0C6C3B16A14001A709DB0BFB0AFA69C57250900002A68A0BFBFB6935C2B13080D3B83ABC1B08D8C9379340A041C4EA9E7FFFFE5AA6A371C223349ADEAFFFDC76D38242521252E4A90ACACB8A96A3A271E2E4FAFE9FFE9B25464412021142B3C4B7AD2F7EBAA643519253435568DD7C76D38242521252E01FE985F07071880656C8CA7C3DED9D7BA5F2600001E458CD0D8D4CAA7692B0300002661A4BCC4CCC3B5691A00001C4C96D3E6E8D2995420103A81C1CCB6B8C5AC6D2A111C4895B0B8BEC5C2A0512D1E1E365F7A9FAEB2B0A1580D00013B8DC6D8D6C2B18132000A5BA9C3CBB6A3ACA5762A0000005EA1C7C5C2BBBAA86412002870A1C1B5BBB7A29C4D220300003173A4B5BFC091562A1400083272ABB8B49592AB752E0F0C2C53B0E4FFFFE7A26A381E253348A7E6FEF8CA7B4523252629294C90AFA5A7986A4333293058A8E9FAE7B65A663D220D1D2F344B95D6EFECAA5632212830315199E2CA7B45232526292901FE995F070718907184A5B7D3E9D9DBBB67270800164F97CDE3DAD0B36D340000032368AEBAC9CBCAB05A1700000D509AD0E9E4D49F4A121A3A87CBCDC7B9C7B7671E091F5897B6C5C7BEAD824C32211C3B6178A0B4C2B39552100000378DC5D3D7C6B07B23000E58A3B9C9B2B0BBAC7B1B00000B539CBAC8CCC1C2AF6E0F002772A1AEB2ADB1A58B4E130000023676B5C7C7B6924729150A143B82AABBB99A9F9E652500051E57BAF9FFFFEAAE603628213354ABEEFFF1BE663D2328243033498EA6A2A08D6541262C3458B0F0FFE6BB68633C231F202739508AD3F6EAAC5B2A2624202F5F9FD8BE663D232824303301FE9A5F070718A0697DA0C8DEEAEDE0C9651F02001D5A9AD3E0CDCAAC5B1E000001275FABBCBCC1CAB3642204021E55A5D9E3E4D5994A1C144691CEC8C6B9CDAC5A15091F5D97B8BFC0BFB88D472B1014375784A9ABADB19C570F00003391CCD5D1C9AC7529001D64AECAC7B7B5B3A4751B00000B6BAABAB7C6BAC0AE630E002B80AABDC0BCAAAC8F44050000023874AAC9C2B88F4823110A15498AACC3C099989C6B2500002754B2F1FFFFCE9C5E32212B3A52A4E9FBF9C467332929232D2C5196AEA6A28B5D3322222E64B1F2FFE3AE635E331A1E232D455999ECFEEF9951251F252B3C57A5E1C467332929232D2C01FE9B5F070718B07A92B1CCDEE6EADAC6783200012A599ED9EEDDD2A259210000062F72B6C2C5C4C1B456190000295D9ECBDEDED79C4510104BA1D1D2C0B6C8A5520F102D599DB9C3B8B2AC824C2E211D3B668AA0B2ACAF91420200023E97C7DFE2CAAA7620001971ABC1CBBCB7B5A06215000015619CC0D0BDC5BCAB5309003679A5BBB7B1B4A98833050000003979B0BFBDBB92492A1C16254789BFC2B39F9A9E63200D042152B6EFFFF9CD8B481D15142253AFEBFFF7BC682C2026222E355596A297A28B5B3A30263560B8F8F8D3AC695E392A1C1D2A4566AAE7FFDF9140211C22373C64A0E6BC682C2026222E3501FE9C5F070718C06983ADD2DDE9D9CEB7651E02072A5CACDFE7CFD0A2571A0000053374BFC5C0CBCCBE601E00031A50A4D1D7D5D48E420E1D4892CCC8C6B3C1A0561B0E375F9ABBC5C8B5B08D553F171F376C8EADACA9AA7F360000003D95C9D3D4CAAE731F012163B3BDCDC0BBBAA36C1C00001861A1C5C3C7B7B49D4606003980ABB6B6B7B3AD8136010000053D89B2BBB7B687492616101C4F88AACFB9AA9B97612309112C63BEF8FFFFD09C552B111C265FB5E9FFE9B75B2D1C2827282F559AA59E957C54322B2F3767C0FAFFDBA6665D341E1C282D4072AEE8F4E08D462F1A28314370AEEFB75B2D1C2827282F01FE9D5F070718D0768DB7D7F1FAE3DFB8662A06052F66B3DCE4D3CDA65D1A0000073574ABA9B6CFCDB15F1E00072569BCDBE0DCD48C31101350A4CCDCBEABBAA25419173B69A3B6BDBFC0B575422D121D387493A9B1ADA78C410000084FA3C7D7CEBFA5630F001E78B1C3CBBCBAB1A55D170000095E9FC2BFC2C5C0A54A06013585AFC0B2B4B6A5772C000000084F8FBBD9C9B47F4A22140C205090B9BBAD9D96965B200308224EB2ECFFF0C5823F24170C2A54AFE7FFE7B054220B1E2B3234588E8F89997E5131222A3863B7FEFBDCA46E5A311C19152D4569AAEBFBDE9B461B1C2732396CBBEDB054220B1E2B323401FE9E5F070718E0708EB6DDEEE7DDD0B06A2900032466B5DFE6CCBF9A511800000B3784B2B1A9C2CDAF5F14000A2870ADDAD7DBCB852F041754A0CCDAC4B9C895461C1F4073A2B9BABCB9B77D412C1A1A3A7093AFB0AEAB833500000A4599C4D7DDCF9F5D16001D71B0C0CBBCBFB3965F1400001E6CA8CDC9BFBDB8934405003080A7C2B1B5BAAA7E29000000175193B0C6C3B48446261A08145088B3C3BAAD9E9258220004285AADD8EBE2B883462119222A51B3E4F8E2A952231615192832609B9296A17B472F1E2B2E65C4F4FAD990725734241C1F315379B6F1F8E29145282627304676B4E7A95223161519283201FE9F5F070718F07497CEEEF5F0DDD9C068260A10326BB9E5E9CDC594470F00000B3C83B7AAA8C1D1B4551801072874B0DFE6E0C87D250417509ACBC7C5BCC796431118467FABC7C7B7BDB178452F1F1A478292B7B3AC9B7B2D000000439EC9D6D2B5954D0F042D83BACBCBC2B6AFA35F0E00001D649FC1BCB5C0B28C3E0700428CB6BCB3B7B8AF822F000000185092BBC3BCB6873D2517091C5F8FBCC6BEA4998C5B1403063360B2E6F2E6B46737100E132362BFE8F7E1944618141E272C2B549193858E80502A2236366EBFFBF3C488765739251C28305C80C2EFF0D28B47241E252C3D74C4F3944618141E272C2B01FEA05F070718007CA3C9E5F3F3E3DAC2673007083C80BFE2E7D2D294490F0000073E7AACA8ADC9D4B3520E00083677B7D4D7DABA7B2C0B265CADC8D7BFB7BC93421A205479A8B6C3B8B2A7784824141847869BAEA2ADA37A2900000350A4CED7DBC095530A002C7CAABDC5BFB9B9A55C0B00001F6AAFBBB9BBBBB3943700004291B8C3BAC0C2B2812C000000125F97BACBC0AC76452C190A215D96B5BDB4A3928F591600063466B2D4E7E3AA62270C0F131D59B6E7F5D898411C162218223466989A837F76422F2C2C386ECCFFFDC98B75512724131C366486C3F3F7D07E3E1E131D2F4079C5F498411C162218223401FEA15F070718106E8DC2D6E6EBD5CCB85B1F00053679C7E4E6D9BE864A0D00000F4087AEA6A3C7D3AE5811000E3C71B6D3D7DCC5742A0B1F59B0CDD7C0B1B48B401823598AB8B9BBB8ACA9693A23171B4B849CB0B8ADA0742700000951ABD7E7DEBA9B570F00307FB9CCC4C1C2B19A540A00002772ABC3BEBCBCB6914300003C89AEC3B5B7AFA9762300000018629DBBC3B8B57F4B2F150D235B97C0BCB6A997884614020A3966AAE2E6D4A764280D03102063B7E8F1D69542251921312A2D65A09B828271472E34305277C0EBEDC78672502B23181F356887C7F1F2C57B3B281D1F2B4682C7F49542251921312A2D01FEA25F070718207B9ECFE4F1F0E1DAB55C29090A4087D6F1F4DECB8C3E0C000011418EACA1A4CBCFB14E1301123A76BBDDE2DEBE701C0A2263B0D7C9C3B3C3833718215486A9B6B4B8BDB06A3C271219478FA1ADACA894601C00000B50AECAD6D8C18A3D09002A7DB9C6CBD4C1AC9C4E0600003180A3C0C3C0BBB9973900004392B5B7B0B6AEA66F200000001E649FC4CFCABE7743361A0E2A5A97A7BFB1A39893511403073B6CACE1E0CE9A52140000082160C4E2F3D498471D1624140C306CA9978A7C75422828363B74D4FCE7B886774D2C1D1A24336CA2D9FCEBC56D251C1B23384C97CCEC98471D1624140C3001FEA35F0707183077A0DEEFF1EDD4CDB2682600054287C6EFECD5BB87410C0000194A91A59CADC7D1AF570D000C4281B7D5DACEB96820052E68AFDDD9C9BBC680381127658BA8B8BEB8B6A362342E141B5790ABBAADA992651A00000758A2C8D7D6C48F4002013A85BBC5CCBAB5AE95460100002770A0BFCAC9C0BA8B2B00004789BCBCB0BBB1A9741A0000001A65A9C2C5BAB97B3B2B1A1C2D679DB7BCB2A7948E4B1A0C0930609EC6CEBC8B47100500030B57B4E9EAD383300F0D0C14293070A0977F826B3C2F1F293177CEF7EBBC857E4B231B3027426D9DD0EFE4BA6B371E18242B548EDAFF83300F0D0C14293001FEA45F07071840739BCDF6F3F6D7D7A45222010B408DD0E5EDD3BA81430A0000124C90B3A0ADC7CEB85D0F03174A97C2DAD6D5C3691E05276BB7D6D3D2BCB56D2C09235E96B6BABDBDB1A1572D1F0F1A58A1B2B4A79E91560F00000354AECCE1DDC28633000B3E8FB2CFCDBDBFB98940000000337BA4C0C3C4C8BE8C2700034E93B9BDB6B0A69F6D16000000205FA2C6C3C1B278472A1C1533639EB6BBB0A09B8B4614020D386FAFCDDDCC8B41190100001968C7EAF6CB873920151A261F316AA39A817B5F412F27343C7AD6FBEEAF777C4823211F2A4972A7DCF8EABD642E1920233A508BDAFE873920151A261F3101FEA55F070718507CA9D1E6EDEBE3C6AD60261018499CDCEFF3D9B57D36080000134D97B19AA5C9D3B9550B0012468DCED4D4C7AA58150B3279BBDBDCCBC7B7712A17356C9DB6BCBCAAAC965F36280E164B8BA2B4ABA893591A00001363B0D2D8D6C97B310000418FB6CED4C6B3A48A3C0000003A7FB5C9C2B9B9B5892A0001529EBEC3BBB7B0A27018000000266BA8C2BDB4AE783A2B171C3B769CABBEB69F988A481002153C6BA5D2D7C192521C000000196BC7F0F0C28433121319212C32749F9D847A5E3C292032427ED8F3E6A8687E49251B1E243F70A4D4FAE7B0652616161B355797D4FF8433121319212C3201FEA65F07071860759AD3F2E8ECD9C4A46022000A459CCCEAEECEB77628000000185A94AD93ACD0CCA94E190B13468FC4D2D3D7B5611C0A2E6FB6D1D3CFBEBD721C1336799EBDBCB7B5ADA66335240717488EA1A8AAA68D460700001059A1CADFDDBA712C06064297C6D1CCC0B19E7D3E0500073983ADCBBDB2B7B38E2700075BA0BDC5B1B5AFA970190000002978A9C3C3BCB7783D2C1A12336E9BBAB3ACAC9E8F3C120315396BACCBD3B88242190B00011263BBE6EDC47B2D1709181E22387DAB8D797E5A321C1A313A87D2FEE4B56E814B2C271A294B7EABD8EDDCB360352223182B5599DAFF7B2D1709181E223801FEA75F070718707EA8DEEEF0F6D8C09C5523040E4DA1D7EFE9DEB778270000001C5A9DA695A9C9D6B25619051B4C91C8D9D5C7AB5A15083074B9D6DAC9BCAC6A210A4083A0B1B2BAB5A193532A1711214F9DB8ADAAA786430500000F63B7DEDBDBB6712000004693C6C4CFC3B4A5813D00000E4185BACFBFB4B4AB782300055598B3C2BDBCB8AE741A0000002B7FADC0CFC1AD6E34301F16367999B5B9AEAAA0894513020F4579AED2D1B183360C0005011C68B8DDDAC56C250D0D1120292D79A994817C613525222E3A8AD1F7E19E688245231F192C4978ADE0F9E5AE612E2818203659A5E1FF6C250D0D1120292D01FEA85F07071880699DD1E6F4F2CEBF925111000A509CDDE4E8D8B56E2A000000156099B09FA8C4C7AB531710225A9ACBD8D4C1A05815012F90C7D5D9C6C6B25E16144785AEBAB9ADAEA5965D2D1B03135799AEB7A4AB88440700001161B2DDE6D4B06D240008448DC4CFD6CAC1A779330000164B8DB2C8BFB8BAB17D1E00004B93BAC1B1ADAFA6600D0000003183ABCDCBBFAA753E2A1A1C4088A6BCB7B49B977F3C0F00154A749EC4CEBB7135010000001963B3DCDAB774260A0A0F17233D7AAD9A7977553728262B4185D5F1D7985B85523A1A18254A7BB8EEFADDA05A2B2419263751A7E1FF74260A0A0F17233D01FEA95F070718907FA5D1EBEBE5D6BC8D4A2B070D4DA1D7E8EAE5B464240000001C5AACB394AFCDD6AA510D011C5298C7D3D7DFB15F210C3786BFD4CDBEBFB05B150E4688A7BBB5AAADAA944D221507175DA1B9B3B6A574320000000B5CA7D5ECDDBC6C26000A4E9EC2D1D0C6C1A375330800184886ACC6C1C2C3B076200008599BB7B9B3B7AEA65F160000003783A7C1C8BFA86C3E3222234B7AA2B1B4B8A99F803D09000F4469A5C9C3AD793B07000000096BC1D7D9B2652610000E182C4283AA98807158322D24314189DEF0D2935A86412C211D2D4E95C2E8EFCF9E582D1D1C2C3D609EECFB652610000E182C4201FEAA5F070718A080ABDDF7ECEEDEC49A58260A1C56B0DBF9F6DEA96221070000225BA9A896A9CED9A85213061E6093C9DCD3D7AB4D07073B8EC5D4D0CBC5AF5914154687B3BBB0B6B0A989532A150B185591ACB0ABA97D350000001662B4DDE4E1B25E1A000954A3C1CED4CEB595672D010015508FB4CCB6C3C2AD7418000D57A5B6BDA9B6B29E65150000003C89B3CAC5B4AE6A453018203D77A1B2B4B0A58E8037050210476F9BB8C0A7661D000000001865B5E1D3B266120004151C2A4183A99D8478532D231F263D8FCCF0D69862884C2417182D598DC3E2F7D39E521F141E243C60ABE6FF66120004151C2A4101FEAB5F070718B0749DDAEFEDDFD2B08A5122051B5AACE0ECEDDFB86C1C0000001967A8ACA0ADD1CAA64C0F0D2C66A4CCD5D3C7A3440E083B90C0CCC9C2BFAA4A1217518CB3C0BFA9A4A3834C302005175D9EB4AFB5A473360000001971BCD4D4DCAC6019040C57A2C2D1CCCDBA8A65320700125190BDCFCBB8B1A96E1A00105A9DB6C7BBB6B1A2610B0000003C8CB2C8CAB9A36A412E2123487DA0ACB3A59C8E853C0900145074A8BECEB07932010000001570C4E4E2AF611A03090919284388AC9686754E302A25264D93E1F9D69961994A271B22265396C9EEF2C887431E1C272E3F62AAE4FB611A03090919284301FEAC5F070718C07BA1D6E6EAE8D4B58C4C2909185AA4E4ECE8D4AA691B0000022961A9AF93B3C9D6B55415133166A4C8D2CFC898420F00388CBFDBD8CEBAAB56101D518EB4BDB2B7A9A2854E2010001B61A1AEB3AE9F75290000001769B3D3D3E1AB5913000F61AAC0CFD7D8AF8A583209001D569EB9C7CEC8CBB46D17000C5C9CB0B8AEAEA8926118000008428AB3CCC2B29E673E311724457EABBDB4B4A5A3843D0200114B7095BABE98661E00000000136CBDDED2A15F1C0A091D252B45809F948871462D1D1A2C3E8DDDFACE8F578E412322191C5493C7E7F7CA93491D1A1B2B3866B8F1FF5F1C0A091D252B4501FEAD5F070718D077ABDBE0E5E4C9A88A4C2A081258ABDDF2EFE1A65C1E0000002B5AA8B3A0B5CBD3A8461C102B609DC8E0CFB7973C09063D8FC8D7CACBCDA54C0F1952A2B1B1B4A9AAA27437110A001662AABBB7BCA96F23000000256ABEDCE7DEA95309000B5DA9CCCAD9C8B591572E0100145DA9C7CAC3C2B9AC681F001965A8BABEB8B2AE9D5F11000004448EB7C5C8B6A9663E3524214378A5B5AFA5A795752A0000185277A2BAB3A45F1200000000116CC1E4CEA55D1903080F1D234886AF90786D3B2B2722274390DEF5CA81537C371F2824354E93D2F5EDC48343211E272D3973B9EEFF5D1903080F1D234801FEAE5F070718E0779FCBD9E0E1CFA77F5222030F52A1DFECF3D8A255170000002E69B2B0A0B4D8D9AF4716193067AACBD2CDCA993F0D023E97C1D1D4CEC2A24B0D17579BB9B8B9B5B09F84371300001C5AA2BBBDB7A368200000001C70CDD9E1DCA64A11000B58A8C0C7D3D0AF7A4829040020649EC1D2C3C0C7AA6A0D00196AA3C1C5AFB1B0A6610F00000A438FB6C5C3B5A269412D1C1B4E8BAAB3ACAA9F9A7E3102111E4C77A1B9BA9D5911000000002279C5DAD3A85A1810091A21304992B3987B674532281B264495D9F4C982478F3C242922356091CFF2F1CC7F3D171317214681C3FAFF5A1810091A21304901FEAF5F070718F077A1D6EAE8E2C7A7875521060D5BB3DFEDF1DBA54E11000004216BB6B9A1B2D1CAA94712153271A2CCD2CFC28F3D00023995BED1D7CEC39E44001F599CAFBAB9B1A8A4874A1A03051F659BBABAB69D631F0000002882C5D6D6D19A4B0A001467AFBFC5C2B899764728100D3569A7CAD0CEBFB7A8650F00196FAABFBAB0B2AE9F52120000105898BEC0C3AFA5593F302026578BA7B4B4A19D9E7C370A06165479A1C6BFA25B1100000000186ABAD9D2A85F180A0409212D5099B499876A3D2928262D4C9DE0ECC5793B884C28221D2E5598CDEEF6CB8234141E23314C7DBFF7FF5F180A0409212D5001FEB05F0707180073ADE5E1EAE3D6AC7A4E240B1A5DB3DBE8ECD19E56140000053774AFBBA0B0C2C59D45100F4073B7D0DADCC4863100003B92C3D3DAD2CD9F41051A69A3BCC7BEAEA8A07A290C00001F62A4C0B8B4A45F0E0000002775B4E0E6D99B4B0B00166CACC2C8D4D5AE7A471F09012E6DA9C3D0D0C8BA9F570F001167ADBBC2B4AAA1A6630D000011568FB3BEB6B0A156383B25294E88ACB4B5A8999A7D28000024597CA7B3B79C5C0C000000001362BAD8CA9349170B080B1E275399B69B875F4325131F2B439AE1F3CC7C448E451D22192A5AA0D0F3F2BA7A2C15111F284382C6FCFC49170B080B1E275301FEB15F070718107FACDBE4E8E9C9A88B4D250C1764B4E1EBE5DC9E4F120000003478BDBBB3B5C8C7A44710213977ADCCCCCABA862F000B4798C7D5D8D0C5AB3E101F6CA8B4BAB3B1AE9876300A00002067B1C6B9B09B5C080000002C86C6DFE7CF9A4E01001165B0C6C8CEC19F71482A0E063672B2CACCC4B1A69D5A08001C6BA7B5B8ADABB4AD500900000D5D9EBECBCDB298623F362531538FA9B1ABA69C93713200051F5779A2C3AE90580D00000000157CC4DFCF984A0609000B1E31539DB79C7A5A2D1A1218264A96CFE6C570558F401C1E283A61ABDFF6E7B97A3A221F2829468FCFFFFF4A0609000B1E315301FEB25F0707182076A2D4DCDBE1BD99734A200C1966AAE1F0E7D895490E0000023076BCBEB3BFDCD0993F14183A77B3CBCFCBB8852C00083C97C6D1D5D9C89E40051B659DBCACB3B4A8A16C341800011D6BB1C9BFBC9C53070000002B76CAE9EAD58D4009001668AACECFCEC7A06E422D0A083071B2C9C7B6B7C3A15A0E001A65A4BCC0ABB2AF954F0D000012529AB9C3CABCA35F372A1126548AADAEA59E9A9E7831060620627DA1BBB59A4D09000000002172BFD6D399460D0A0B0D1B375C98AEA683674924221E1F4B9BE6E9AC673D883E2021242B62B0E1F1EAB76C2E1A1E1F274282D2FDFF460D0A0B0D1B375C01FEB35F0707183077A8DDE1D7DCCA9573461A0A1C60ADDFF1EACB9742100000003177BECAB2C2D5CF903B0D0E488AA9C4D1D2C2832B00084897C8D1CCD6BF9C3D0A2C6EA8BCBFBAB5AB976521070000255CA8C7C3BD9859090000002F85C8E5E5D8994207002677B0C3C4C9BD976440220C043A72AECAD0C9BEBBA35C0B00156BA1B9BCB4BDB4A250100000115D9BBAC0C4BCA664482E1B225992ACB5BAA3A3937124030323587E98ACB1884302000000001874B3CDCA924904000009253E6CA8B89B7957331A1B1E2749ABE0E1AD6F3B903E1F1B14276CA8E3FFEAB16F2D22181E2B4987D3FFFF4904000009253E6C01FEB45F0707184084AAD8DBDEE6C69D6B4326072369B4DCF3F0DE984A0C0000103D84B6CCBBCBD4C994360612427CB5C7C8D2B87B29000D4798CAC8CDD0BD923E0E3374ABBEC4B2B8A8966021050000296DB2C3B8B58A4C080000043787C7DCE5DB953A00002473ACC5C9D1C39F61331F0808337AB3C4CFC8C4C0A3560E001D70A1BEC3A4ACAFA5570E00001B68A5BFC7BFB09B5B39331E325E95B6B2AEA699A778290001205E7B97B5B4884300000000001982B7D8CE933C1004060D1C366CAEC2A488622B1A16121E4CA1E9EFB1643991402A201F2C66AADDF4E4AA622F141516335285DAFEFF3C1004060D1C366C01FEB55F070718507298CCDEDFDFCB9971422710296BB7D7FAEFD69244120000153986C1DAB6BEC4BE8C30041E4E83B5C8C9C8B1712D030D459BCBD4D0D0C493320F2677ACC1BAB8B2AB9C671C0000002463B2C2C0B38E44060000003B98C7EAE9DA943501001F73ABCDCAD3C4995B42301310397BB6CDD0CCBAB98D3F0300206BA5B4B8B0B2ABA6581300002365A1B7BEBAB79F6B46371C295A96B0AFA89E9791772A000025657C9AAEB895490F000000001D78B9CCBB843A0006000D30416EA9BA9B7D5E3D241E152355B0DCDEA36538934221190C2967BBE3EEE0AA5E341B2427294B90DEFFFF3A0006000D30416E01FEB65F07071860769ECEE1DCD8C7996B4727031C67ABDAE4EBDC8743120000104180C5CCB2BEC6C98D380D224C8AB0CAC9C8B16A27030449A0CDDED5D4C28C2E082C74B1BABAB1AFAD965D17040005216CAFCDBCBB924B000000024196D2DBE1D48F3905002878B6C2BFCECD985E33280D05388DBDD2D5CBB5AB8F3D00001E6CA3B4C2B6ACB5905A190000266CADC1CABDAC925132281D286299B6C1BAA5A4926728000234698099AEB290500C000000002080C6D1C6833A0E07030826487AAFBDA88A61341F16101A4AA0E3E2AB623287371D2321306BC0E5FDE3A05C28141D2C394B99DCFFFF3A0E07030826487A01FEB75F0707187071A0D3DED8E4C79366422C112463A8E7F1E7C98A300200000F4385C0C4B3C1CBC38D3108265D92BED6CCCAAF701300054B96C7CDD3CAC28F36013281ADBCBDBAA9AF9758170000022B6DAEC3BAAF8E40000000084091CEDBDBD799350100397FB6C5C3C8C294573428090E3F8CC3CDD1BDBDB089380000256DA8B3B7A9B1B4A3590F00043171ACBEBEBCA89A59362E1536609BA9AFAFA39A98753301062659749CB1A58E4704000000001D7BBFC2B583310800010E264A7BB3BF9F8453290F0F13314897DBDEA05C2C8F37261D273970B1E8F6EA994F26232128335798E1FFFE310800010E264A7B01FEB85F0707188072A2D3DEDADCB98B6439210D1B66C1DFE5EACE86430A0000073F88C7D5BCCAD9C784360C1E568DBBC1C7CCAE67200000419DC8D6C3CCBF933A123778A7B6C7B5AAA89E6315000000226FB0C8BDB484460000000A439FCCE1ECD1903600002683AAC9C2D1C7904E3A260E0A4697BBCCDBC0C0BD903D00001977A6B4BBB1A8A09C531600022C7CADC7C0C1BD9B644A341F346798B0B2AAA29C936D1F00002A618496AEB3894000000000002F88B9D1BB8439020308112A4A85BEC79A885F2B180F091F4AAEE2E09E502B8C34211D222C69B6EEF7E2985123182023315897E2FFFF39020308112A4A8501FEB95F0707189074A6D2D3D3DAB97F633D28082761ADD4E3E1C88B35000000043786CAD2B7CED6C6813814255D97BEC9C8C1A85B16000546A4CAD2D4BEBB8E22052B7DB0BBC0BAB7B59C52110000002A71ACC4B9B380370000001544A4DAE5E7D57F2D0000348AB9C9CDD6C0854934280D04408BC6D2D2C7BFA787400000216EA7C0BCB3AFB19A591200003579A6BCBEB9B098623523112D5E97ACAFA8A19A97751E000926617F9DA8A88A4C03000000001F79BCCDBD88340107020B235286B7B4A6835A2410060E2152B4E0DFAA522B93441F191E2B6ABEE7F8DD8D4E21181C233252A4EEFFFF340107020B23528601FEBA5F070718A078AACECED7DAB17E573B2B12286AB8E2EAEACA873D0000000F508CC7D9C8C9DBC07A200827639EC7C8C9C8A55714000142A0C6D6D5D5CD89270A348BB3C2BBBCB2AC9357120000002772AEC3C3AE7A320000001254A2CEDBE4D188300004338ABCCDC8D0BB8B4D322A0D124B90BBCDD1C3B7AE853E02001F76AEBAADA5B0A792520F0008337BAFC4C3B6A9975B3F2E253D6990ABAFAA9B989C721D0004316B7C9CAFAF8D480A000000002580BED3BF803205020007254D8DBDC3AA84532B0A0B14244DB0E4DF9F5335944019141C2C75BAE8FEDB934D212226202853A1F1FFFF3205020007254D8D01FEBB5F070718B07FABDACFCCCCB0855B39200D256FB3E5E6E4C67F370600001A488BBBC9C7CDD9C28125092766A2C0CDC8C0A45B1100054DA5CCD4CEC6BB8227023B89ADC1B4B0AEAB945006000000347CB7C5BBAE8E350000001153B0DDE3E8D4872A00073A92BEC4C5CAB6813C2F2C201C4A89C1CFCEC2BCA97B370500246AA4BDAEA1ADAF964C1B000D3A7AB0BDC5B6AB8D5B402C1D366795AEB2B7AD9F91621A040B2A6D889CB8AD8C4300000000002B7FBCC8B1782B0500000D246396BFC0A288512A1613112355B3E2E1A54B2F94492714193675B7EAEED68A4F1F15191E2B5BA8F4FFFF2B0500000D24639601FEBC5F070718C07DABCBC9CCD6B8795239261C3371AFDEDFE4CC7C2B000000164691CCD0CACED0B881300E2E6EA7B5C9BEC6AA5A15000351A8D3D8D8CCBD832404377CB7B9B7B7AEAE834605000000257FB6CDBDB9842C0000001852AADAECE5CA8127000A418EB8C5C3C9B079422A241A184298BBCED8C2BEB37A3000002372A7B5B3A6ABB0964A100113407BB5CBC8BFB1925336221D35668EACAAB0A598916418000F2D728B99A6A57B4204000000002881C2CBBA7F2300030004355B98C4BBA083572F0D0F122C5DB0E3D5934A218D3D1D181B306DC7F0F0D58345221918202C5EB1F4FFF92300030004355B9801FEBD5F070718D07CAED6CDC9D2B37D503523143172B4E1E7DFC371260100000D4B9FD3D7CAD2D1B675280D216B9FC0BEC9CA955914001250A0CFDBD1CBB17C230C4085AABDBCBBA9B9904E050000003480BFCEBFAD73200000001456AFD4EEEBDC802C09093A92BBC3C2C6BD7E402E2C171D5997BAC7CFBDB8A27F3C00002B70A3B9B7AEAEA7985211020A4389BDC0B9B9B0935138291B47739BA6B1A7A499835E12000835678B98A2A5883C00000000001C71B7C6AD6E2606000001306BA3C8C6A5884E291E160E145BB3DFD5983F208E3C291F1F3B75C0EEF6D2853E1A1D2227345FB4EAFFFE2606000001306BA301FEBE5F070718E07AAABBBBC2D2B16E4F29170C266EB4D8E2DEC37128000000174D9ED4E1D8D2CBB06E220A246CA3C1C6C3BE9C510C000856A1CCD9D5D5BD872F0E3B8CB1BEB6B2ADA6904E020000003684BBC0BAB27729000000135EB6DCE1DFD7852404104B8EBAC4BCCAB97B3D332A1913589CC0CECBBFC2A86D2100002A79A7BEC1A3AEAD9E531503124189B6BEC1B2A78F5B35231D3A729BADB8AB9E93866816000C3168799AA9A687490B000000001D76B6CAAA6A22070009082F6CADCCC8A38F5D250F0D09265EB5D6D1964423923E152315287BC2EEF2D7883C201B121D3158AEF0FEFE22070009082F6CAD01FEBF5F070718F077ADBBBBB9C5B370583423122C74B4DBE0DDB76A22000000145096DBD8CBD3D1B96C2B132F79AAC7D1C8BD994B0C0002559FC5D4CFC9BE86230C3A8BB6B2B1B0ABA5813C00000004397ABCD0C0A973270000002466B7D5EBEDCD761C00004998BBBDC6CBB47C3F33291A1357A3C4CACBC3B9A3661D000329739EBEC1A9AAB29A541800144686B2C3C3C3AD8757361E1B3C7793ACA9AEA8A795660F04072E708197A4A1793100000000003389BCC3A165200001000C406BB1D0CBAC9254240D1C14285EB2E8E0943B218C3B1D0A173B79C5EAF0D1833A0F11212C2D5DB5F6FFFF200001000C406BB101FEC05F0707180075A7C5C0C0C7AC6F4D371A0C226FB8E3E9DDB964150000001B4D99CAE0D4E3D4B36C1E052E74ADC5C9C6BA974700000555A6CCD8D4CFB87A2B0D4E9BBDB7BBB3B2A87D3500000001367FC4C4BCA16D290000001959B1E6F3EACF7A1B00033A8DBCBDBBCDC071373C2F1D27609FCAD3D0C2B29E732900002D6F9FB6BFABB2A38D471000204E8FB3BFC4B4AD986344251F367995A0A5AEA6978E6411000940738694A5997C2B00000000002B85BBC1A25E230405000E3971A3C8CFB18D481C0E090F2063BAE1D6943D10913D201F203486C9EDEED97A34180915293067B9EEFFF8230405000E3971A301FEC15F070718106FA4C8BBB8CBA469502A170F2C75B0DFDED3B76917000000115A9ACDDCD3CBCBAE681E103980AFB7C4C5BD9C4B0500004E99C9CFCECDC27821124C8FB5C0B9AFAEA7753100000002347FC4D3AEAE6C23000000246ABFE7EAE9C47D20000E48A1BABDC1C4AC6E3538301D1B55A3CAC6CDC7B99A6E1400002D74A4BBBDA5AFB28D49210F1F5999B8C3C8BBB1884B2A241F41718FADA7A39E93895D140007367581848F8C6C2A0000000000287CB0B7965610000500103874A6CDC9A589561D070407215DB6DDD98F491E903D2A1A20357ACFEEF2C86B341D191C263061B3F6FFF710000500103874A601FEC25F0707182075B2C7B7BBC9A266462F190E3379B7DEE7DBB86A18000000154D9ED9DEDAD4C8AB671D143483B1C0BBC0B998470000004DA6C7CCCDD1C38027174B90B3B8AFB0AE9D7A2D0000000A3C8BC0BDB5AC741F000000256AB7D9EBEDD57B17000844A0BDC1BFCDB86B38363B281E59A2C6CDDBCAB79E5D16000F34719EBDB2A9B1B68B4C150A29578FB1B6BCB2A38754391B20407995A4B1ADA2918B5E10000138748F95A5A7793800000000002F82BAB59F5413000000103C76AFCEC7AE8F581F0608001A5DB4E4DE9A3614903F201F1A3E81C9F6FACF75321A1724293468B7F3FFF713000000103C76AF01FEC35F0707183079A5BFB2B4C0A26034241D0F2F7AB4D7DCDBBC6515000000185094CDDEDCD3CDA6612303397FAABFC0C1BD96400000094EA1D3DCD0D7C381320C4E98B5B6B4B5B5A6702C000000053F8DCDC9B2A36A160000002A79C1E4E9EDCE7C1E000C4695C2B7C0CDB4763C322E1B1A5A9FC7D2D0C1AE955C0D000134779CBEC3A3ADAA8B4D1E0B275E99B5C1C3B8AF835435251D447499B2B0B5AFA8885E13000A3D738A8BA29E742B00000000002A85AEB8A05C12000000104278ADC9C6B18958170005031A63B2D7D58D3D128C391E16122D71C7F7F4C77038131F1B273864C6FBFFF112000000104278AD01FEC45F0707184079ABBBA5AAB9945B361C16152D79B7DCDAD2B46412000000155799C1DDD9DACA9F551C0E3E87AEC2C0C2B68A3B0000065BA3DBD8D2D0B97B240F5298B2B6B0B3AC9D69280000000B4994B9C8B4A86A120000002C7AC6E1EEECDA7215001057ABBFBEBEC4AF6D3F3B341C225BA9C0CFD2C7B0935D1A000038799FB4AEA9ACAD94581E0E27639AB0B0BBB4AA8F572E16184A779BB1ACA8A196864A04000C4C6F8289988F732E00000000002C76B1C69C4C0E000004124D84B2C7C3B08D511B000B092A6DB4E2D29339128D381C1E1B3684CDE8F3C9743511171B1A2B63BEF8FFF70E000004124D84B201FEC55F0707185081AFC9B9AFC1A0663D281A163B84B2CDD5D1A957100000001D5CA1DAE9E2D0CEA4551A0E408BBEC7C2B6B3913E00001159AACAD7D5C9B5721D0A5099B7BFBBB7A8977620000000003983C5CEAD9B621A0000002E7CC8ECEEE3D06C1A011B5F9FBEBCCAD4BC743A3B331D205FA3C5CCCABFBB91570F0006327D9FB9BBA4A7AD8A4A1F14326DA0BBBAB9AFAC8C5632201E4C7893A39FA59B95833F00000E3A7A9191A699793900000000003188B3B893460B0000001B4C87BAD1D3B088491B0504041D67BCDFCC8A351A984415141D3B8BCFF5EFC8702E1A16151E3071C2FAFFEA0B0000001B4C87BA01FEC65F0707186081B1C3AFA7C69D5F341E13103581BBDCDBE0AA5B12000000235BA3D6E3DED0CF9656190E3F82B6C4B9BAB98D32000002599FC3D9DBCDC47A19115BA6C0BCADAFA69B651E00000000499CC6C7B09A62180000042C77BFDFF1EDCE7423081458A1BCC3BBC4B065313931212A62ABBFD2C9BFB68E561A000B407EA2BBC0AFABA6854D1908316C94A6BDBEABB0925B34190F447E98AAABA99C988B4C090012487881849E90702600000000002878B6B5914D0B0000001A4F8FC0D5C5B38A491D0001012167BCDCCC8C3613963C1B1F1E3D88CFEFF3C26F25110D1A232C68C7FBFFF30B0000001A4F8FC001FEC75F0707187077A9B5A8B4B88F4C322011163487B9DBD5D5AA5111000000225DABCFDEDAD0C4A250120D4092B7BEC0B9B78B3905000951A6CBCED0D7BE70190356A3BBB9BEAFB39C5F1E0000000E569BC8CBAE96580B0000003176C1D8EEE9D46919011C6AABBDB5BDC4AF63343B32272463A8C5CACBBAAE904D0E0005377795B4BBADABA78A4D20204174A7BEB5B3A7AD905533151A4F7B9AABABB0A58B783C04000A55848F97A4A3702F00000000002780B7BF8D460C0000011F5F99C4DBD7B1914D0D00090F1E75BAE3CC85340A91331D0B1A358BD5F3EBB26426160C18272D6BCBFFFFE80C0000011F5F99C401FEC85F070718807BA7B4A0A5BE944A26181A143B86BFD4DDCBA350090000001A589FD5D9D8DBC89E4C10143C8ABBC8C5B9AB803100000D5BA8CDD2CEC7B86E1E054F9BB2BBBCB7B59F5B15000000175FA6C6CBA684561100000D3A77CAE8F1E0CF6F1200095FA5CBCAC0CCB2653F3B3724255C9CBFCED6C3AF8E4B09000F3F7BA6BAB4B2BAAE81461A093A7BA6BFBCADA6AD92583417244E7C969DAD9DA2937A4100000F4077929AA3916E270000000000197BB5BA8E4B0F0000001C5996CBDACFAD8F50170109031C6FC2DCCB8C39158F38171A12348DCAF2EBA957281213151C3674CAFDFFE80F0000001C5996CB01FEC95F070718906DA0A68C9AB390481F1309152F80BBCBD0CCA24B140000001E58A0CBDADECFB2814417094090BFCBBCB2B383380000155BA1CDD5CAD3B56C140854A2C1C5BEB8AE9E530B000000145DA2CBCBAD8C52080000013578CAE0E4E0D16C0F052063ABCBC0BCC0AC6330433E272261A8C1D8D5C5AE8E420E00184388A7ADB1A8ADAA844B1C1B467EA2B3BAB19A98824D2D1D21468998AAA7A3A6967C3F00001B46848C88968E5F1A0000000000237AACB0864B0800000021619DC7D7CEB48541090000081A74C0E2D088321099391F1C13318AD6EFEEBF60240D1821222B6EC4F8FFE60800000021619DC701FECA5F070718A07CB0B7989DB294451B0A0F143D91C1D2D2CFA24F080000002567A0C5E5DDD2B6873D05074D94BBC2C0B4B597370000115AA6D0C8CCBCB56F23185E9FB8BDB9A8A29257070000001660A2C5C2A67F410400000E3C7EC9E4F0F1D06B15052467ADBBBAC4C0AE68434A37252963A3C7CECCBDB9823502001344839FACB0A3AFAC87501B0F3F80A3B1B1A8B3A489532215285B829CA5A4A3A5928C3D00000E5385858E9488622400000000002C88B0AA7F3E0A000000175396C2D9C4B585460D0007002B7DC5DAC87935148F34291C173593DAF2EBB75223191919273674C9FAFCE70A000000175396C201FECB5F070718B080AEBA9E9FBA924D231418183E8CBAD7D5C8954903000000216BB5D8D8D7DAC3873F03033F92C2C7BBB4AF863600001859ABC3C9CFD0AF6618155BA7BCB6B9B5A89757070000001E61A8CDC9B27D4A140000073E81CCE6E8E9BF5E0D00216BB4CECBBFC2A55D364046262868A8CBCEC3BEAD753813071551849CB6B8B0B1B0874F1F174780A9AEB7ABA39D8A50291A23508691A6A5A394937338080015578E9A8D9D88641D0000000000287BADAF8841090000052968A5C9DED0AB894D0D000B042376BEE4CE7B3114963720181B3B8BD4FCF2B359280C0A17253579CBFCF7E1090000052968A5C901FECC5F070718C0709FA59392B085411E0C0C1A4089B5C9CBBF8F44030000002063B1DADED9C8B374390B0A4F97BED1BEBCB082360000145FACCDCFD9D6B567211454A4B8C2C4B8AB9248020000001D65B2D1C1A67838000000084A91CDEFF2EDC97010062373B6BEC4C2C4A15A3E4943222463A7C5CFC4BFA8802F00001949829CB1BBA7A5A17C4B2226528DAAAFBAB09FA28E5133141B607B9DA9A1A9A59A783300000D588D8E9F98886B2700000000002B80B3A97B3C0C0000092768A5C9DACCB784460B06010A2C7FCDD7CA81260C9939230B0D499FD3E8ECB4582107191B253479CFFFFEE10C0000092768A5C901FECD5F070718D0699C9B8693A079351007090F398AB7C8C7B7943F000000002066A5CEE8D8CCA970310C0B4DA1C8C8BDAFB6852E0000135BB0CECECDD0B66A160F68AFCAB8C6B5B49740000000002163A5CEC3A977440600000C4A88D3E2EAE1C66713002F7CB0D0CDC2BEA35E3A434C231F66A8C4C2C1BDA16D2503001D5A93A8AAB8A5A8A6834D2222598BA8B5B9A79D9A894E291921557B96A8ABA9998F732C00000C51878D909A976D2500000000003392B7B48C3D100000092861A6D1DCD9C5924C120205152B7AB8CDCB86370E943A22150D3795DBF0E7AE5528100D161F2D7FCEFFFFDD100000092861A6D101FECE5F070718E077A6A28094A87E2D150907155094BDCBCBB58D33000000001C5FAFD3DCD7C8AE6F27010649A3C5C2C7BCB6872700001660B5D1D0D8CCAB5909055BADBCB7BDB9B4924804000000306EB3D5B69E6B3B02000010508BD3E6F0F0C2661C062F6FB2C9C8C7B8A757303D38213564A9C9C9C7C5A96F2B060927568FA7B5BBA9A69B7B4F21244F89AAB4B2A49B9B894A21152C608B9DA8AAA49F9A662A00001A668893838181631300000000001F79A39F792C0100000033729FCCDACBB1874A0F0000042B80CBDAC37A30109E3D290A164AA0DEF0DFA94D1F1011191D3683D3FBFFDD0100000033729FCC01FECF5F070718F078A3A68D9CAB79371A12131C4C93BDD4D5C0923A000000002D71ABD3DCDCD2B26126020C5599C5C8BBAFAA802700001166B1D3D1DAC5B4560E1867A6BEC7BBB1A88E4600000000327EB5D0C0A675320000000B5496D3E0E9E3BA5D0B032F76B6C7C5C0BF9D56393E3B2C3467A3BFC3C1BCA669210008246197A4B0BAA4B2A671481A2A5D91A5BBB9A6A0A89454210A22698292A1A3A7A49A682E0000275F86888789825B0100000000002C73A4A36A28050002113266A9D6DFD7B17C3A11000008377DC7E0C385360C9E3B2818224DA8E2EBEDAD4D1E0E0D00163583D9F6F7DA050002113266A9D601FED05F070718006C96947682966720000000104682B7C8BBB9872C000000001E6AA6C5CED3CAA563270A1153A1C0C7BBB1B0822900001563C5D6D3CDD0A25910106AA8C4BFBCB9B3822F000000063A72B8D5CFA37030000000105597DAF4EDDCC564180D2F7EB9C7C7CBBE9F54344B4025345FA2C4D1B9B8A5611E00001D5C8CA8B1BDA2AC9E75462C275995B1B8B0A2969785542313266789A3A1A9AE9E996E2000001F668D90909390581600000000002977ADA775360A000006367CABDEDDD3BB823F0800000D378CC2D6B8803D189D4126141B4B9BE4F4E19E40190C131E203585D6FFFFD50A000006367CABDE01FED15F070718106C9D947D7F9A701E000000174B8CBFCDC2AE7F2A000000003375ABCFD7DECCA96123000B52AAC5CDAFAFAC722700001A6DB7CDCED4C8B057171260ACC0C8BDB9A18A3C000000003778B5CFBFA46C2C000000225CA2E4F7EDEDB7610F063180B4CCCBC1BC9C5540413C2A3066A8BCC9C0B4975B1F00052E65939DA6A7A3B0A97A4F26276691A1B3B6B0939B874E21132D6A8FA3B4A6A18E86621D000024608D8C8E9387570D00000000002B88B0A66D2D000000083A7BA7CADDCABB84490F0400002F89C0D8C281321296372B1C154BA2DDECE4AC492511121A1F348BD4FDF9C8000000083A7BA7CA01FED25F070718206998947975865F1B0100011B4FA0BABFB3A7761E000000002F6DA5C3D6D1BB9C5A12001263A0CDD2BAB5AF711600001670B8D0DBD2D4B156110F69B6B8C0BAC6B6902C000000003D8EC0D4B399622C0000001758A3D3E8DFE5CC630F013783BFCBCACAC6975449513F2C3261A1C7BEBEAF96571800042162939FB4B0AEAD996B46212466A0B8C3BDA7938E7E521F0A32638D9EA6ABA7A796621900002B698D8E858E8A5A1200000000002F84A7A4702A000000053985C1D7E5CCB6823A0C000100368BC6DFBD812F119240220F1C45A0D6F6E8A7451513101A213080D9F1F1CA000000053985C1D701FED35F070718307CA48472818956180100001E49A7B8CDB8A87827000000002A78AEC9D4D3C0914C0F001056A6CDCBB7B0B080210000206FB4CFCDC5CFA84F0B1E66ABBFBFBCBFAE802C000000084188B8D0BF9D601F0000001E63A5D1EBEAE5C5560D143A85BBCACDC2C199523F5145273169A2B5C0BFB3975A140001356AA2A7B6B9ADA4936B51353E6D93ACB5AD998C918048221D306A949E9D9EA69A89571301012D6A939184857C5C0A00000000002B84A6A67135030000114287BFD3DCD0B4814605000010398CCCDBC5792C129A4224100D54A1DFF1E29E431D0A1117264584D1F9E9C6030000114287BFD301FED45F070718407892917175895111000000204599B0BAB1AF8128000000002C7AACD2D3D0BE8D4C10000D58A6C5C0B5B3A9701800001F73BFD1D3CDD0A25A0F206BB1D0C8C3BEAC7C26000000003A94C1D2BEA6581C0000001D5DA7D2ECEFEBBF540C0A398BBEC4C8C7C79D52384C492836649DC3BDB2B6924D160513407499A1ACB2A2A29871442436749DB1B6B39B87948B4D241032778A9DA49EA6A08D501600002865878A878C733D0100000000002B7DACA66325000000124490C3DAEAD2AD8342050000054098C8D2B97F310E9B3D24170D489FE5FAE3A24315070F182A398CDAFFEDB8000000124490C3DA01FED55F070718507F9B9A7E82865919000000245B98B7C6B7A27D2D00000003397CADCFD9DBB67F480E00125BACC8C7B1A8AD761E0000176FC2D9DAD6C5AA4D061374ADBFBABAB5AF8D280000000F4B91BCC8B89453230000002165BEE0EBDDE3AF48070C3F95BBBFC2C7BF9F543D573C23316BAFBFB6B0B4944E0C030F40779BA3A8BAAFAD906D492632799DABB7B2A2939C8B501F11396C92A2A0A2A69D84450000002B6B95948E8A76450200000000003178A59B672900000017518EC2E2DFD8BA893F030000033B96CED4C47D2A0F9B391D0E194FADE5E8D39A4126181212243688E0FCE6BB00000017518EC2E201FED65F070718606486846A6E7A4800000000195994ABAAAA986E10000000013D79B4CBD0CCB57D3D04000D5BA7C6BBA9B2AD661A00002581C2D4CAD2D39F52121372B3C5BEBDC1B17B200000000B4F9CC9D2C59A5315000000276CABDAE3EBE4BC5A0D043C81B5C0CBC5C4954A4B573D2939669ABEBEBBB38A3A04051D437CA7A2A9ABA0A198744B2E437BA0A7B1B1A69893814A2114316E979FA1A8A99D8548060000296D8D907D8472440000000000003480A4946924000000144A89CEDDE4D7B77F400B0000003F96C7CBB97B2A089A41211D1C53ADDCF5E399491C0812171E3487D7F3DBA3000000144A89CEDD01FED75F070718707E94967A8988510E000001255B9BB9BCAE996714000000073F7EADCBD4D5AE6F3104001B66B5CEC7ABB0B1601100002279BED9D9D5CDA3510D2474ADC1C0C5BEB075180000000F59A1CDD3BB964D0F0000002D6EB4E3E7E8EBBB46050B4192B4C0C5BCBF93574D5147304171A5C3B1B8B583320100184482A29EA0AFA3A09276552938759AA6B2B8A58F92884819193E7891A2A9A2A69B81420B00002E719B957D8C794C000000000000347DA9955C20000000135A9ED0E5DFD4A87E34100000084693CADBBD772E109E361F172057B1DCE9D7993A13090517203E95DFF9E2B4000000135A9ED0E501FED85F070718806C827C68757E4F07000000204E94B4BEAC93661C0000000040729CC9CCCEB96F2F00002068A4D3C8B3ACB06F1A00002076B7D5CDD4DBA64C0E1D6FBABEBBBBB4B07413000000155F9CC7CFBD984E130000022877B1E0EFF3E7B5490C07438DC2C4CCCBC38E4F405A43253A73A7BCB7BBAD813500001A4E86A99D99A9A79B88614B2C3E86A4AFB4B393918B874D1C2048829B99ADA4A6A4833B060000377A9190838A74450600000000003383A8965A220500001E5495CBDEDFCDB97C3E0200030F43A2CACEB07830089B4622111A53ADE2EFD69D3F1D0E111B1C38A2E4F1DDB30500001E5495CBDE01FED95F070718906C95906F786C3300000000245B94AEAFA19B6010000000043D78A9C3D5C9AA682D04001366B1C3C4B2A6A7661C00002880BFDDDCD1C6903B0B1D73ADC7C2C3BDAC6A180000001B6CADC6D5C495470E0000063279B7E2F0EAE4A84B0C124998BCBEC2B3B9964E45463A374B79A6C1B3C7B97E2F040029537CA4A1AAB5A99E8E6F52224379A1A9A8ADA48D918149180A357E95979AA1A9A07C320100002F799392808374480300000000004485B6955113000000185C9CCBE9E7CEA572380C000005409BC8C9BC742703A03B180B1C64BAEAEFD1913B080B00192A48A1E3F1DEA1000000185C9CCBE901FEDA5F070718A07183837072763600000000255E93ADB29C925D0A000000013E85ADC4D9CFA5682F00000D68B1CEBABBBBA7531300002E81C4D2D9D1CD9E3F102179B1BFB9C2B9AE640E000000196CADD4D3BC974E0B00000C397BBFE2E9EAD79C3D0C174C95C0C7C7C5B2894746543B3B4972AAC5B4B3A5722B02011B568AABA6A2A9A89A887B562E4281A1ACBEAC9D85997D3A19193E78909BA6AAA09A813D0000003775949B7D77643F0000000000002978A39655160000001861A0C5E2DBCFA8753A050000084BA4D3D4AE7931049B391D10185FB8E1EDDA8D39160D131A2A439EDAF1D9970000001861A0C5E201FEDB5F070718B0758A85757474390000000029639AA8B0A28A56080000000A467EB0C7CEC9A15C2100001D6FBBD8C1B1B49F5B0A00002984C0D7DFCFCC95420F1D71A9D0CEBFC2AC66060000001F70AED0D2BB9B3B090000002E78B2DFE4F0E1A340061D53A5C4C8C6B6BE874B4C573F354978A2C3B0B5A3772905082A668D9FAA9BAFA5A982715130457CAAA4B0AC928B857B3D131645879BA5ADA89F94722A0000083B82A59C7B796E430000000000004086AB925214000000195BABD0D9D2C4AC7135040000064496C8C8B1762D0BA24A221F2569BBEBE8D69A3A140C050D1D4DABE4F0CF98000000195BABD0D901FEDC5F070718C077998276756E3100000000366E9CB0B59C845302000000094487A1C6DCC995551600002679BDBEBAADB2A05A0D00003384C4D7DED0C48B39071F74B6C2BEC1C8AE680B000000297BBDDAD8C49941040000022774B5DEEFEDE09B35061959A3C9CAC5B9BE94484B4D4134417BA1AFABB3AE792A0102326B94B49899B0A39C8373522E4986A8B0B0AC9C8B817A471A1E448597A1A1A8A294712900000B457B9D9E79785F360000000000003A82A08A45140000052463AAD0E0DDD7AD77310000000B4798CDCAA9681D04A34F1F0C236EBEE4E5CF8C3A1915141D2246A4EAEECC930000052463AAD0E001FEDD5F070718D07C9188797F782F000000013E6D9FADB19F764F1800000012548FA9C7D5C39E4E170000176EBACFC0A6AAA35B120000338CCAD4DADEC894370E1C77B7CABCBABDAF5E070000002874B6D8D6BD923D0300000A3B7BB2E0EFEAD898380C215EA1BDCFD1C1BA874B485B3C304880A2B3A8B1B06E2600032A5893ABA899AA9E94817A54344E8EAFAAA4A3958A857A39162C4F8FA89FA2A3A19E692800000D467195907D785E2C0000000000004A89A69554180000001365A8CEE2E7D9AC6C320000001558A0C8CCAB682D09993326182A68BAD2DDC88E371D090D21224CAEE9EEC5900000001365A8CEE201FEDE5F070718E0718085737C712E000000002B739FB2AB99774A000000000E5492AABDC8C28A490D00002579BDD0BFABA396581500003793CBD5D7DFCA852F05227EBDC9C2BCBCA1620B000000287ABCCFDAD09A3A0100000C3A84C1DFF0EED29425002165ADC4C0C1BDBD90514D5E4B355487ABC0A8A7A3661A000A3B7291A69F95A49E958076523A4580A3ACADAD9B8288773916214D869FA5ADA89796641D00000F48869A91848060300000000000003C88A58C4406000000216DB9E1E8E5D1AC752F0300000B5AA6C5C19C682503A43A1E172B6BC0E8DFD48A2B0F1214192647A7E2E5BA8B000000216DB9E1E801FEDF5F070718F07C8C91847D6D2C000000033F6CA5ADB89F7A4205000000185798B2C4D7C4904B1400001E75C2C8BAAAAF9946080000398ACDD9D5D2CF8E33062381BFCBBFBAC3B25E070000003089BCD6D8C7923F04000004468DC4DAEBE7D1872E001A60A2BEC7C7BEB38A47495C40415D819EBBADB2A75F19000A406B9BB5A496ACA48B727A5F325290ADAAA6B3957C8B71331725528CA6A9AAA69D94611800000E4C7D9F9A7878622C0000000000003380A48A4518000002246EACD8E9E0CCA8752B07040112549DCCBF99642B089A3C180F3071C3E5E5CC913218020820304EADE9F1BD83000002246EACD8E901FEE05F070718006B8082776B6120000000003D6E97A9B696733E000000001D609AB6C7CFBD8A380400002880C1DFB6A3B69B4C0200003893CADDD9DBC77F330C2C81BACAC0BAAEAC5E000000003780C1CCD8CE9C46010000033B85BDDDE6E6D48630081A5EA8BEBDBEBEB8854850503F3C5F85B3C0A8A2A05F13000C4B7C9EB59EA0B0A1907B6F552B5194ACA5A39F93797B773E1B2D5A8E9EA0AAA1A6975C1300000C47889D956F685126000000000000467D9B823E050000032578BBDBE2DFCE9B68280000000857A5C3C4A3631E099C3F201B3178C8E3E0C48A34170909142845AEE2EAB87F0000032578BBDBE201FEE15F070718107889796E6E57180000000042749CA9AA8F6B33000000001B6193BCBED2BA84470400001E7ABCC9BAAFBCA7530E00023A96C8DCD6D2B57522001F7CC1CFC3CCC0A95D00000000378DC8D7D9CD9A35000000094A86C7D9E0E0D68926032770AEC6CBC1C4C1813A4A543E395691ACB4A2A6965915000E4F77A7AAA097A49E8B7783542B538DA9ACB3B0937D7F6B2610205390A3A6AAA0A18C590800001D56869598717554200000000000004086A28E4007000000347AC1D3E4EAD1A6732C0300030F66ADD6C79762280BA1421C19307BC4E1D9C270280E0C1A1C2A4DB0EEEEB07B000000347AC1D3E401FEE25F070718207282796E695C2000000000476E9CADB18E6A3500000000195A97ADB4C8B878300300003384BDCEB8A9AE90480D00094198CBDED6C7BB83360E2A8AC0C6BFC2BCA45900000000389CD1E3E4CA9436000000003E90CBDDE6E8C77F27072564A7C9BEC0C3BC79464B5C3C3D5F96A6AC99A19D5A190020467A96A49D97AEA7876A765D365088A79DABB5A08682772B172D5B8C9BA9A49E998D5C1200000E518399927971521C0000000000034589A1893A050000092C80BDDEDFDAC29B6526000000145DA9C6B99D5923089A4319173585D0EED9BD7C3C1B0C13212452B0F2EBA86F0000092C80BDDEDF01FEE35F07071830747C867F694F18000000004974A1ADA08D612F000000001863A1B3BBC8BD7C2D050000338ABAD3BAA5B8A6490A00004099CED7D0D6C5772902278CBBCBBBB7BEA654000000004093C8DBD1CC9B34000000134290C5E4E6EBCB801F00206EAACCBEBBBEAF854A515943406A8FA9ADA0A6994D08001B4A7BACB09898A69D816D7B53315392A49BA9AF9D848A702E1630669AA4A3A9A7A5934F0400001D59808E8E75744B1C00000000000051869C843D03000008207DB8DEE3E1CF9D68290000001068A5BDBA945D2508A1360D0D3686D5E5DAB97A2F1D16261E2658B0DFDFB06F000008207DB8DEE301FEE45F070718407B7F807E73651F00000000487A9CACAA966131000000001866A6B9C3C9B77A2A0000013686C2DCBAABB594480400054097D2D9D3C9BD7629062B8DBFDAC5B9B6AA5B010000003B97D1DAD6C5963B0100000D4C8FC6E1E0DECE741A002969B8CCC3BAB7B3814C54542C3C6095B4BB9DA5974F0000195A89A8ADA795AC967B6F80542F588EAAA7ABB3937D8176301A3964979EA8A7A89B874D030000205284A597786846140000000000004489A7893A0700000B327EC4EBF3DACC9D60210C00000E5BA3C4B98E5A1B08A23B1A1C4090D5E5DAB67B2E170A1827285CBFE2E0A76900000B327EC4EBF301FEE55F070718506880847967570D000000075377A2A9A6825219000000001C70AEB3B6BBAE6E31000000398CC8C9B2A7B89B4A100005439FD3E4D0CEB97120002A86CFD0CAC9C1A459000000004CA0C5D3CFBE9729000000104B97C6DDE1DBCB6F2504327AAFCDC1B9B9B6824453574C487399A5AF99A390460A001B4D809FB5A09BA6A081697B5538619AACABA6A79380786C2E1938669C9EA6A79F97864F0A000017658E9A928772501700000000000C5C8EA4852C03000000327FC2E0F2E7C8A35B26020000185DB0C9AF835D21089B361B2D4893DADECDB9742517081922255AC6F1E7AA69000000327FC2E0F201FEE65F070718608083847B765D15000000004773A0AAAD8A5318000000002582AEBABDCAAA671D0000053699CECEACA6B1974303000E469FD1D5D3D0BF6D1F022985C6DECDC1BDA854000000004EA9C7D1D1C9952F0000000F509FCBD8EBE8C363110D317AB3C4C3C3C2AD77424F5D46456B9AB1B08C9F84370200206084A4B3AA94A18C7B6E775531609FB1A0A6B3977B806A351D346B92A4AAA9A59B8B4B0000002C5C889D99755E48140000000000054C8C9B8337010000012D83C9E4E7DDC59B65200000092467AEC6AC87532612AA3A191D4698D5E0CCAA621D0C0B141F3462B9F0E0A7550000012D83C9E4E701FEE75F0707187069808074684B0C00000000436F9EACA483501F000000001D77ABB6BAC9A55E200000014195CDD5ABA2AD90400100074793DADAD7D9B76C22013A8EC2D1C2C7C2A455020000004EA7D6D9D6C692360000000B5598CFD9E7E1C16D1E0A2C77B2CCBCBFB8A96F3E5B5F454B7398A6AE939992480B00195182A2AEA79DAC926A627D5A335A97ABA7A3AD9E7E7E67240F3A6C9AB3B1A9A39D8F4C0000002F5E88A19B7C744A1500000000001B5D87A38B3C0B0000033287C4DDE7E1C78E521F0102001C70AFC9AD804C2300A444151B53A7DEE3D0A86F2B160F101D2B6AC4E5D9A3680000033287C4DDE701FEE85F07071880748682756B4F0800000004467EA3AAAD7C4415000000003180B0B9B3B5A161130000033C8DCDD6AD9FB68D3600000B4AA5D4E1CFC6CB6D24052387BFD8DAC6CFA8590100000045A9D5D6C7C08A2F0000001A4E92C7DBEFE3B5641105358CB5C5C3C5B7AE7E4E544D3E4B75A5AFB49FA38337000022618DADAC9E8E9D947A616E55335C9AA09EA7AD9B7B786632233F7A9FA3A6A3AC99874B02000032668697907B71460F000000000018588DA77F3C0D0000012B87CCEAF0E3CB8F4F18000005256AB1C5A8824C1D13A6361E2B549BD5E1C29D6A2E1814172B3670BFEBD99B550000012B87CCEAF001FEE95F070718907176777168460A0000000249769FA39F7F4308000000003483B3C0B4C1A7631F0000043E94C6D2ADADB994310000064D9EC8D6D4D9B86620052A8DC4D5CEC7C0AF5B0300000054A7CDCED1CC8E28000000246099CCDEDFE2C6641502338BBACAC1C0B9B971415D5A46546E9CA8AD949B8239000025669CAAACA099A889746F774F325FA0A89AA2A0927675613A2748819CA6A7A99C9A80370000003B68909C95685F3605000000000010598CA6813C0B0000002980BEE2EEE3BD864E1F00000E1572B7BFA36F42140CA1401D1C55A6D6E1C69E6B2513131C1D346BC9EACD91630000002980BEE2EE01FEEA5F070718A0737F7F75644300000000005386A9AFAF81400F000000002F84B9BDC0B498570D00000749A3CFCFA3A6B28D3800001451AED7DCD6D4B25610033088BECFD8D2BFAE5B0400000354ABD0D2CDC3912D0000001158A0CEE1E0DFBC6314013389B5CDBFC2BAAE71505C564855849C9FB9A4A581370400337191B2B0A08D957F665E6B462F5A95AD9BA0B39B827C692A27437BA0A2A7A699917A2E000000386E88988C72673F020000000000226CA3AC852E000000002A8BD3EAF1DFC28E4B27050010286BAEC49973471F14A643283061B3E1E0C7A05E240F100D1A2E6EC8E3CD8F4D0000002A8BD3EAF101FEEB5F070718B080867E7D714B050000000A5A8EA8ABAA804409000000003189B9C8B5C790500F0000094998D0CDA5A7B8893809001153AAD1D8DED0B45B15063094CAD9CAC3C9A75B0000000151B0D5D8D4CA94290000002668A1CBDEE2DABF4F0E0B4084ABC5BEBEBCA7694665604D608E9FAAA79AA07E280000336595AEA5979AA085605A6D4D37649AB19F9DAAA68076622B224F8CA6A2A1A5999485340000003E738BA099746A3C0000000000001C6395A57A36000000003887CDE8F7E4BD864E1D000000227DB9C6AA753E1605A4361E3363B4E4DEB8915E241819182C3B78CCE0C58C530000003887CDE8F701FEEC5F070718C06C726E67653E0000000000507A9EA2A17B330900000000338FB6B5B8BD98490D0000074998CECCB0A9AE7F2F00001254B1E4DDDBD6BC6018042E98C7DAD2C6C2AA530000000961A2D0D9CBC08627000000175CA3C9D8E9DBA9530702458CB6BFB9BAB4A47250646151618BAAA9B396967B2A0005347295A6AB9F949C856964764A285C9DACA2A8AD9D7579572D2F4F7E9CA3AEA19D99772F0000063C73878E8B78663A090000000000256399A47A31020000092D8DC6E5F3E4BF905018030105207DB6C2986C361911A245232D68BEDFD9BF9A66281213182C3E7BCAE0CB814F0000092D8DC6E5F301FEED5F070718D0797D8475653F00000000034F879BADA2723103000000004395B4BCB3B39B4A1000000443A1D6CFA7A5B07C3700001551A6D8DFDACCB95A0F013998CED3CECECAAA58000000085FB1D9E2D3C19226000000245D9EBBD2E1DDA5460B084996BFCBC3B8BAB474466064576D929DA0AE989A7B2F00003A7699BBB4A2959A7A54626D442C689EB79295B3A47A7451282954889DA9959B98977A2D00000441758E99906A53270000000000001E62989A77370A0000022D84CAE3E4D5BE83481E01000D257EB2BE995C2E1A13AD45263470BEE4DBB588542319141A2A3B7ECEE3C7864B0000022D84CAE3E401FEEE5F070718E06D7D78685D340000000007517DA19CA16F3200000000002D86BABDBFBD873E0D00001056A7D4CEA9A5A7792D0000105AB1D5DFD5CFB05B16043597CCDCCCC8C5A75B0000000E63ACD9D1D2BA842D000000226CABC5E0ECD7A840090B4794BACFBEB5B7B272446F5B515F84ADB0AF9D997322000030759CB1AFA1999F7B5A5D693F2F5F92AE9B9FA89C7C714F31386685A3A6A8A39B93711F00000E59858B938870531E000000000000357995A081310400000C3388C9E6E6DABC80421105060C2682B4B69466361214AA47204282BCDCD7B07F4C231617191C337CD0DCC3874700000C3388C9E6E601FEEF5F070718F072757C755F3200000000095D809DAC9E702B01000000083D9CC1B8B4B691470C0000145AACD0C9A3A7B5832700001B63BCE0E2D9D1A44813002F8DC5E2D0C7C4A74E0000000C5CAACCD0CACA841C0000002276B3CAD2DCDA9E3907094B96B8C6C6BFB1A360446C5F446893A8A0A59697711B00003B719CADB3ADA2A78556656B402F678FA49A97A7988072582E30628A9DA0A2A0A296641F00000E4C7389928C644E240000000000003C7B9A9F7E2F000000023194CAE1EAE3BE864C1C0F020A2F8BBEB98E5E2D140AA23D1D3280CBDBD4AF7F4F1F15151E294187D2D7B8794A0000023194CAE1EA01FEF05F07071800757E8583633300000000116194B2A7A47B3800000000063E94C1B6B8BB89340400001954AECBCBA6B0B27A3200000A5BB7DCE3D2CCAE4611063897CAD6CED5C2AA4C000000105EB0D2D4CFC27D200000002873ACCADEE2D9A33D0B084A94B6C6C1BCB3A869436964527095A6A6A892A07B260000397E99B3AFA99F9D7457637C4A325F90A195A1AA9D7A714E283A6489ACA7A69D95856D1F00001849748B989365481E000000000000437E989B7436080000082F8FD5F1EAD7AF78371600040A2682B6B9955732201BB2462C4D85CDE0CE9D6D4A2417141A284385D4DBBA7C440000082F8FD5F1EA01FEF15F070718107B8884806B3200000000025B89ACB3A270310000000000449DC3C2B4B1873A060000135CB3DCCEA4ABAA7A2700002363BCD9DADDD3AB4E06053A9CD1D9D8CFBFA84A0000000B65A9D3DAD9C88B24000000266CA1C0D8DED295350611549FBEC3B5C1B5AD6A4E696154758DA6A3A89EA26D1700024884A4B4B199969C7D535F5D35285D99B09AADA6977A6D4421466A8DA3ADA2A8958D6C1400001C5C7E8C948965471700000000000039719A9F792F000000083090D5F0F0DCBC8246210000113B8CBDB7895A2B1119A748273F85C5D7C99C703E241B141B234091D5DCB26D390000083090D5F0F001FEF25F07071820767677705A2E00000000055889A6A39A6D2700000000003B90C3C1B6B6813D0000001560B3DBD0A9ABAE732C01002368B5DADAD7D0B04A09023498C7DAD6CBC3AA4E0000000F67B4CECDD1CD851F0000002B6FB0CFD7E5DB9D2E071353A1C7C9BEB3B2A85F46696052799FAAA09E95A16F1B00003B86A7B1AA9F99997956616535275DA2A68F93AC967C694C314B729DA4A6A19B98905D1E0000205A868E9D8D674B1B000000000006467B99967A300000000B2D8BC8E6E3DAB57C3D1B06000B3397C2B8895B2B0D05A43F22478CCBE5D49E69422215111D2A4695D9CFAF6C4800000B2D8BC8E6E301FEF35F070718307E7B776A53240000000011638E9BB3A0682303000000034AA6D0C3B4B5812E0000001559B5D6CCAAAAAB742C07031869B7D9E2D9CE9A3F0A02399ECCD7D0C8CDAE4D0100000F5DACC7CDCBBF8C220000003A77AFCCD7CFC99C38010E529CBCC9C0B8AFA36A4B6760507BA2A8ABAC989C661000064B839CAEAF9DA7A47F4F626D39255B92A2A1A2A88F74644B31436C99A7A29EA390805B09000020628295998D5C460D00000000000B467D959F7C33000001022B92D7E5E1D9BE8340140000062C8BB8B98753281112AB3E2B548FD4E6C8976C3E1C17181F2B4D99D7CEAF67340001022B92D7E5E101FEF45F0707184072737869502000000000085387A3A8A37428000000000146A3C6BFB1B670260000001F6EBED8D5A8AEA6752800001B66BFE0E7DCCDA3410200379CD0DAD6C5C9A64F000000186AAED6DFCDC58A210000003181B9D6E3D7CF8F2D04105295C0BFC1BDB4A1664C6E66577C96A99DAA9D98630A000C4C7B9AAEA99E969C7852626A342969A1AB9D9FAA9E725F37264A799DA3A5A99992804A0D00002065888DA19970501E000000000019568FA9A0722E0A00000B3A8ACDE6E6D9B6703E1E04080C3E98C3B97D4A280713A94A324E92CEE5CD98613F1A1419222C509ADED9A86C3200000B3A8ACDE6E601FEF55F070718507B786A644A1A00000000156390A3B1A4682500000000004497C1C5B6BC80310100002064BCDABD9CA4A8701D0700175FC0E2E5DEC895400A003D9DD1DDE4D7C8A2460000001465B1D2D9D4CE8C200000004186B7C6D3D2C987300110559BC2CCBCC4B5965E4967715E799FAD9EA7A18858080000528BA4A9ACA79F9D664B676033346999A78F9BB3A17364403359738FA2A8A5A7937449000000216E8193999368440A00000000001B5987979D7831030000033493CEEEE9D7AC6E3F1109020C3D96C5C17F46231911A53D295793CDE6CA885B331B1C1923254B9CDDCE9E6A380000033493CEEEE901FEF65F07071860767D7C6A4D1900000000135F8EA5A39E6B2C00000000074FA4C3BCB8C177200000002274BAD9CBA09DAC74240201216DC1E1E9E0C78A4202003F9BD1E1D1D6CCA947000000156ABFD3CAC5BF83210000004390BDCFD4D8D18629010E59A0BAC1B9BCBA97624C71645D81A29CA4A5A29F620B00094C83A2ABA9A599957A45657241356B98A08E9BA299705C3E315A86A0A6A59F9C887740000000306C8690928C694413000000000013588DA2A76F28000000002D87CEE9F4DBAC6725130706104998C2BF7E441D1116AA49395BA5DBDEBE8A5A341A1A1827255AACD6CCA262490000002D87CEE9F401FEF75F070718707B767D76491C00000000156C92A9AD9C6C2300000000024A99C2C5B4B26A290000012D73C4E3CCA2ADA86A220306236DC0E7E9E0C8923600033D9ED4E3DAD0C1A2460000001863B0D9CED2C577180000004A96BCCFD4DCC88327021960A4C3CDBDBDB39B625671666484A3AA9DA29F955805000E52889DAA9C969E946C4262632F2D6D9DAF969EAFA0685C353B5E7F9FABA5A4A38B744E00000025739091978D6B470F00000000002E678BA29A792D0000001A3B94D1F2E6D8AF6C31060F0E134493C2BE763E19161DAC4A3060A2D8E4C5895531111019223459A8DACA985C4100001A3B94D1F2E601FEF85F070718806E7361593E0A00000000116A95A6A6A1792700000000094D98B4C7B9AF772A0000002B71BEDEC8A3ADA55E1E03092271C6DEE3DBC194390505379DCAD7D2D2C4A3490000002077B5D8D2D0C47F1B0000004895C5C7DDDECC761F051A64A9C3BFBBBAB59D57536C676188A9A99898979147020010588DAEA5ACAB9D8E674B63622F2A619BA59A9EAB9C6C4A323E638DA7A7A3A0A493813C0000002E6C8697A09365420F00000000001D6784A2976E21000001083090DAE6F0CDA06C2707060E0D459DC5B6764526171CAB462E60A4CBDCBB7F512E2010162F415BB4E1C5975A3D0001083090DAE6F001FEF95F07071890717F7562350D00000000196E99ABA79C681900000000044BA0C6CAC7B572250000002672BDE8C6A19CA15F1E0002246DBBE3DFD9BE8F3B110A3D99C5D1D5CECBA5420000001F74B9D5D4D0C287200000054D92C7C8D5CDC57F23001364A6BCC9BBC4B49A4C477C686C8AAEAEA2AB9E974F06000D5A88A1AAAEA7968F62476F5B282668A8AA93A6AB92654D35345E89A4A4A2A6A0927230000000437A96929C9961400000000000002C6E98A39D75210000000D3B90CCEBEDD8A86C2B11040311519CC6AF6E401F1218B04C3466B1D3E3BD7D4629141A1A293F67AED9C296593C00000D3B90CCEBED01FEFA5F070718A0776F6D63310000000000156E98ADA5976319000000000D4EA9D5C0BDB372240000002B76CAE3C49C9D9D571D00002873C2DCDFD6C3883009053F8ECCE1DCCFC99B4A0000001A73BBDAD9C9B6771C0000064B94C9D5DDEACE7A0F042368A7C5C1BDBCB59954456866658EADB3A6A49B8B4F0100106791AEA9A89F968C5944695D27266C9BACA4A7AD8B6346333B708BA0A7A8A598896A2C000000477E92929488653C0900000000002C7293A08D672D020000033E95E2F3EADFB25B32170C041E4D9EB8AA6F321F1214B2492A66AEDFDDAD794C27140E14243B64B1E5C38C55360000033E95E2F3EA01FEFB5F070718B07B756F603A090000000019659AAAB29A6D1E000000000C4DADD2CCCAB96C170000062972C1DDC8AEAE9854160000287CC7D9DBDAC885330100388DD1E4DCCFC29D410000001C73ADC5DDD5C57E1D0000004099D2CAD0DFCA7A2108256DA7B0C1C2C2BA974E5375637398AEABA49C9B8A3A000012649CAAB3ADA294956148675F282C649FAA98A1AC9163462A42648EA0A4A6A0A28E68290000004B7C949A9D9358350900000000003573939E996F230000001544A2D9EDEDDCAD5D2C16080C1C49A3B9B6752E0E151BAD513072BCDEE4B2723C2C1C200F263A66B3D9BC804C3100001544A2D9EDED01FEFC5F070718C077756E572D00000000000B658FACA89B6321000000000D4E9FC1C1C4AD65180000002C77C2D6D4ABAA9A481700002B6EBBDFDCD2BA7A24071545A5D7DFD9DAC7A83F0000001772B2D4C6C8C180160000075792CDCFD7E2C67C1F002174B0C3C9BEC4BB9A504163596195AEB49F97988D3F000019628DA6A79C9A9EA05C496B5B2927709CACA9B2B3865D4B32456E8EA2A8AA9E99835B2D0000044B87978E958C5A280000000000002D77919F9361230000000C3F9AD6F0F1D2A861231A0E0C2551A4C7A8652E1B1419B14C2E6BB6E7DEB35F3216101E1E243B6DAFD1BA88553A00000C3F9AD6F0F101FEFD5F070718D077807A5B2F0000000000126D96A1A5985F1A000000000A5EA6D5DCCAB5601900000D3877C6E2C5ABAFA2571503082C6FC2DEE4DAB37A280106449ECCD1CFD0BA98340000001F7DBBD9CCC1C88218000009509ACBCBDBDBC4691E072273B9C0C6C2B8BA9B564F6A54719EA8A89DA5A08A4403001C648DA9ACA4A19F92553E5F552527709CB19EA9A386554E30416E99AFB0A39CA2805B2800000C437E959391875A2C0000000000003B7497A0865F1D0000001044A1DAEEF2D7A45E291A03051E50A6B6A26233140D18AB533376C2E7D9B0653B22171F222A4773BDDCAA7D4A3300001044A1DAEEF201FEFE5F070718E0746D6A4B1A0000000000236E9EABAC956521000000000E51A8D7CEC6B765150000003085CEE0C8ADB3934C0F000C2A83CDDDDCCEB56E1F04013E9FD2D8DDCFBE93390000002676B9D4D8DABA7A1A00000555A5C8CFD0D1B9681C042877B2C8C8C2C2BE8B43516E5C7896A6AE9DA999853C00001D78A2A9ACA1A4A08E62496655232D729CB0A2A8A07552412F4D7C9BAEA9A99F967E52140000064D859EA19689532B0000000000003C7A999B8B551F050000013297E0E7E7DA9B571A1C06020D55ACC6AE693620151CB24F346FB9E8D5A56138180B2031304178BDD8B27B4C3D0000013297E0E7E701FEFF5F070718F079746E451B00000000001E6C95AEAC935B1200000000135CA2D1D4D1B866190000032D79CBDECEABB4924A0D01002F79C1EBE5DCB86F24020D409ACAD4CED2BF9A3C000000267BB1D5DDD0BD771E00000F5AAFCFD8D7D0BE7015002679B5C1C0BBBCAE914A496B5E75A3B6ACA59EA4883D0000247189A0A0A4A39D8854436256212B70A6B9AEAEAA8541352C547B989DAE9D979A794A130000125A8D9A9997995A200000000000004D84A3A18A6122000008053C9FDCE7F0E1A2582A131416235FA5C1AB6935130A16AC4B3774B8DCDDA65C3018171D202D3E75B7E1AA6A3C3D0008053C9FDCE7F001FE006007071800766D6C501800000000002C7498AFAAA56820000000000C5BB0CEDBD5AF641C00000A3A83C7E8D4AEA486461000022E79BEE3E4D7B7751B00074197CAD6DFDCBB9132000000277EB5D6D0D0BF791B00001060A2D1D6D1D3C0661B002976AFC6BBC1AEA5824C516D677B9CAFB0A09EA38040000028789FAEB0AB9F96874E4463522A3573A2AAA9AFAC794C382B597E99A7A8A4A99D7943060000124B8A9E9690895A2F000000000007568195A58E531B0003090F4AA3E1EFEFD3A15828150B051859AFC4A861271B0111AB523F73BCE2D7A4582618171D1B324C86CBD3AC6F4C3503090F4AA3E1EFEF01FE016007071810707576480C0000000000296C9AB1AF9A641B000000000D60A9CED3C6B6661100000E3D88CDD8D3B1B9943F0600042E84BFD9D7D3B86E1900083F9DCCDADFCFC598360000002C7EB8D2D4CFC3721B00000C61A7CECCD8DEC26B170B287CAABABBB7C2B1904945646280A8B7AB9AA9A77A2B0000317BA8B0BAB39D968E534E6B45222A6C9FA7ACA9A7764E2F20548698A6A7A6A0987343120000185F8C95999B80522D000000000000598CA1A5824B29090D0619479FD4ECEFD8A75720160F132E62ACD0B15D1B0D091AAF4E3C78C0E8D3AB6129180E1B27263D7BC3DBB37144320D0619479FD4ECEF01FE0260070718206F6958340800000000002E759BA9B1925A1D00000000105AACC7D0D0B85C0D000013458CD9DACFAFAF8D38080009387DC3D6EBDAAC601700093996CEDBD9D3BB92350000003A7CBCD8CEC9B974170000136CB3D2CDDBD4B668120D3A8AC4C4B6B8B5AE8037425C5768A2B5AFB2A7A5803900002D7D9DA8ABA4A593854F47574D25297AA0B0B2B39F764435335693A4A9AAA1A59A762F0100001A648C9591958E5A240000000000005591A8AD89561400000B1646A6DAEFF1D69E532A150A121F5FB5C9AC60261F111EAC4F4180C3E6CF985229221017122F488ED2D9AC6A3F34000B1646A6DAEFF101FE0360070718307D6B60390100000000002C7DA9A8A88F5312000000001F56A7CCD9D1B05F100000113C8DC9DAC9B5AD852E03000A3182CFE0E5D1A0622001113C92CDE0D8D3C188340000002C7DB3D6CFD0C6741A00001564ADD0CDD3D5C667160E318ABEC2C7BAB3A770454A675F7E9CAEAFA1A29E7D270000387A9AA1B5A89694834F4B6A4E28366E9BB1AEB59A6D3A282E5D95A4AEB0A6AB9B74300000001D628B9DA09E805B230000000000115A92A9AB8C52220709001650ADE2EEECD498502320160C2269B0C7A45B1F13131BA64B3878C7E6D79E50291B142222315098D5D99A66423309001650ADE2EEEC01FE046007071840716E633500000000000027749BACAB975714000000001157ABCBD3C5B25B100000194695C9D8C9B0B986420D010C2977C1E4E2DAA8540C010E45A0D6DFD0D3AE77280000003384B8D0D5CFC07B1F00001A71B6C2D6D4D1BC62160D3B80B8C3C9BFBFAD84494559607DA6B6ABA29EA4792B00003E7A98A7A49AAEA68851475D4E252A6AA1B3A9A4956437293B6992A8A8ADAAA09C652B000000246F94A3949A88491900000000000C5D9EAAA27E491B0D080D1D489EE2F6EFD199461F1F18061C6AB8C0A05C241B140EA9504184C8DFD495451D0F122029355595D4E59F65422E080D1D489EE2F6EF01FE0560070718506862573200000000000037839DAFB1985B130000000014549FCDD8CFAB5E040000134C8BCAE0CEB5AE74320000093276C2E6E6D49F511100124A99D1DBDBD4B37B2B0000003A79B5DBD6D4C1711D00001673B6D8CDCECAB8611E123A7BB1C6C7B7B5A77242495C4F75A1ADA99EAAAA84200006438A9AB0A7A2A8A18D4B41624D1A2D71A0AFB7B3A26C2F1F2A6897AFA9A8ABA295632E0600002168969D979C894D10000000000014699BB09F7E43140000010E49ABCAECEAD29D5129171A0F2266B0C7B1622B170C17AB4D4284CAE3D0824A281814272D36659BCFD2995D372F00010E49ABCAECEA01FE0660070718607E79693E010000000000338AA9BFB49B5615000000001A5BABD1DDD2B95E0A00001C508DD2E1CDB1A87027040003387EC3DCDCD7AA4D0A000E4797D0DEDED2BE7B20000000417FBCCFD9CFB9681A00001C7BB6D4D0D1C3BA5A1016438CB2C4C8B6B9AD6F433F5D5278A4B2ACABA6A27B2400003E8CADA8AAA19CA4864340675023306F9DACB3AF9C612A19296C9BACB9A6A5AA95601A0000002A6B91979598855218000000000016659CAC9E77461D080E08184EAED7E9E5CE9A47251E141A357DBAC2975921131B1F9F4C388FCAE4CB8E3E20120F1D1C27519EDCD9955941390E08184EAED7E9E501FE0760070718707570622D000000000000377EB4BEB58D501302000000215DACC8D3D2B3550F00001F4696D1DCCEC5AD68210200043281BDD5D6D4A34A0900194A99D1DFCFCAB6731D0000003C7BB8DAD9D7BE6F1900002A81B7CFCCCFD3B95213184488B2CDC8BFB69B63354B58577AA0B3A6A89F96741F00094C8AA2A39E9DA0917B4337644B25347DAFBDB5AF9C65251628719FB4B0B7AE9A9361200000002C748F98A09D8C511000000000000C679EA6A27F401D0C0B152156ACDCEBE1D1964D33221C082570B9C4A35A190B0C1BA54E3E8CD0E1C7895523131F24263453A6CAC99259333A0B152156ACDCEBE101FE0860070718807A776722000000000001408AA8B4BA984919000000002469B7D1DFD3A859090000235295CAD8D4C6B46C2300000C2E82BBDBE0CA8F3C08011E3F9AC7DCD8CDAE6F1E000000398CBCD5D2CFBC6F120000237DBBCFD7CBCEB8611F1E4A88B9C2C9C6B29F693A48585075A2BBBEACA8A46C1400064B85A9B0A9A9A3997E3E396C4E193379A6B8AFB89C53251D447D9DABA7AFB3B19A63170000002A6B8B9B9B9A8156170000000000186E9EB29B79410B00070A235CB1E1E9E9D1914E20120E0A2F83BBC89D571C141822A3504086CEE2BC803F1B1A2120283360B7EBD68F5D4034070A235CB1E1E9E901FE09600707189076775A270000000000004294A9AEB4984F19070000012566B1DDDED8B7540E00001B5D9CD1DBD1BFAE631A0000083480C4D6DBCD8C3600082750A1D3D8DDCFAD681A0000003E84B3CBD4CCB56F1C00002B80BCD8D2D7CFAD5518143F85B5BEBDB1B7A66D373F4E5579A7BDB5B3B79D6D1600085196A6B0B0B1A89C7E3E395D42213975ADB4B3B1974C151138799FAFAEAEAAA0874C10000000337A9EA3989180450700000000001A77A2B8A47D46290C0A0E195BADD2E5EAD29550282219163D81C0CA9D5920110818A53D4494CFE3BB7A3E251719312F3F62ACD6C88A5F3B3A0A0E195BADD2E5EA01FE0A60070718A073746220000000000000508CA7B3B2944F1300000000206BB7D9D7D2AD520D000021579CD9DFD1BFAE681F00000D3183C3D6D2C68A4100022252A2D2D9D3CD986B1C0000004391C0CBCDC8B3611000002E8DCCDDD5D0CBA95417244A98BCC3CABEBCA75E2B414E5673A1B9B9AEA797661200155492A8ACA6A3AE9C7C503E604C1F3377ACB2BEB4984D16113577A0AAABB2ADB09357180000003478979E978B804D120000000000237AA5B4A2703E1D030D0E2164B6E5EDE7D49A47272013173C85C8C199581814181FAA4E498DC8DABE7F3621101B131F3A68B9E1D1895336360D0E2164B6E5EDE701FE0B60070718B07471591D0000000000004A8EA7ADAF915111000000052A66B4CDDBD4A85C120000265DA5D1D5CBB9A75C1900000E3A85CAD6D9CA883208031B4DA1CEDCD5C7A56219000000458DB5D7DBD6BE6E1B00002B84C7E5D9CED5A84D141B5297BEC2BAB5B79E5E343E505383AFB9AEA5A7A16B1C00135E94A4AEB0A9A4A17C40406045203A789FB0B4AB8B4E100E337C96A9BBB7B3AD9E520E000008377EA4AA9E917F4A0D0000000000297DB1BC9D693F120E10183466CDE3E5DFD1944C261E0E143884C6BF984C160C171DA351408BD1DDAF683B171A0E172B4170BAE2D78A51583410183466CDE3E5DF01FE0C60070718C07D755E200000000000005D9CB3B6AD884611000000002C6AB3CDD3D7B34F0D00002566ADD3E3D5C6AC580D0000093682BFE0ECCF80340F061F5D9CCDD7D0C09A5512000007418ABBE1D4D3AE5B1A00032E8AC5D6D1D3C79950171C5196B9CCC3C5C29E5D2D3D434370A5B6BAA4B8A65E0900005A97B4A5B3AAAD9F7A433E5E44213385A8B7B5B28C4810073C8BAEADAFACB2AD8F500D0000004688A8AA999B793F0500000000003483ACB89B673B150711192E66B7E0EEE5C885402E271F15388CC3B98A522017181998545496D4DDB0653C2024171E23416EC6E5CA7D45373211192E66B7E0EEE501FE0D60070718D08372531A00000000000856A1B2B6B48E3A1500000000226EB4CADCCAA64F0800003273AAD1CFCEBEA855110000124381C8D2DDC5832D07002C529DD1D1D7C69C47070000004E8EB9C9D3DEB7601A00052F8FCAD4D0D3D3A659212A58A1C0CEC1C0B89B522234454182ABB0B3A6A390530A0017669FB7B5B5A19BA3753E3E5740254089AEAEA9A588400513427FA6AFBAB7B2AE914B140000033B829B98939383420000000000003188B4BB9A6D380C050D0D2564B7D8EAE2BE843E221C170D4293CEC38F4B22150E1DA6534297D1DDB16F2A11171C2A303C78C4DCCB7E4C363B0D0D2564B7D8EAE201FE0E60070718E07A77591600000000000D5A97B6C3B8973F1C0600000A3675B8D3D1C69E480A000B3D74AAD8D2C8C2A64F0A00000C397DBFDDD8C87326000F23569FCBD8D4BB9448070000124C9AC0CFD7D3BD5A0C00043B8DC6D7D2D2D79D461C295E99BCBFBFBDB69656263D3F497BA7ACB5AFB1A65C0E0018669BB8B3BFB1A39774383C503C22488BB2C0B2AF873607073886A5BBB2A7ABAC934E0C00000F4F8E99A19F9680440500000000013787ACB9996937150D0E182B73ACD5E9E8CA90452B2413114F93C6C1914D2419151C92495399C9D3A3642D1E0F14282F4B82C9EAD1804B37340E182B73ACD5E9E801FE0F60070718F07274531400000000000568A3B7C4AE89431B06000007377BB1D3DAD6A8470000063477B1CDDDC5B994400700000D3A91CFDCD5C6832500052E5EA5CCDCD0BB8748000000085298BDD5CEC8B3541108103D8CC8E2D4D4BF9E451D2E61A7C1CFC8C8B18F44132B374282B5C0B9B2AE975D0900236A9DB2BABDA39D9A71302F4B3E27528FA8B3B2A77834100E498DAEADBCB0B6B293410800000954879D98A28E7149000000000000358FB7B3A26434170610163073B7DCE3E3C48A4725221A25569ED2B48B3E23231A1399454594D5DBB160291613122B35538ECEE9D67C543D2F10163073B7DCE3E301FE10600707180071694411000000000008669EA8B4B89042110000000B3478B8D4DDC79C4200000F4A77B8D8D7CDBD9D3F010000114486B7D0DAC670160005205FA4D0E5DDBA8335000000055BA0C1D6D8D3AE5506000F4B9CD3DFD5D1CB9E471B30679FB4C2C2BCAA884C252F35427BADB9BAB2B69D5A050020649FAFB8B19B989D7B363C59391C4689B6BDB6AE742C00095092B0B6B2BCB5B29A4804000010548E99A5998B7A38000000000000418CC1B897652E16080C11346CB8E3E1DEC68D3F201D1B1B55A2C9C493432113071D994C4DA1D5CDA45B2B241C1B22324D87CCEDCA724A34340C11346CB8E3E1DE01FE1160070718107A71480A00000000000D72A8A9BEB2874D1400000015417FB2D8D5CAA8490B000F3C7EACD2CFD3CBA14B000000093F8DC6E2D1BD711E00082A63A8C8E0DABC7F310000000D56A2BFD8D5D4B35A0A0012399AC4D4D1D0C89647233366A6BCC1C4B6B28E472438344578B3C5C5B6AE8E5101002A71A7AEB5AFA9A3A37931384E32284987B0C4BBAF6C2600104E89B1C6C4C2B9B28C430700000D5489A6A8A189783A0800000000014395C0B8996328141012183579C2D7DFE0C181382321181C59A9CFB6914B26110F1AA05553A8D2D38E5625181A252B344B95D8E6C6714B332F12183579C2D7DFE001FE12600707182086694A080000000000186FA1B0AEAD7E38120E000017477EC1D4D9D5A9420000104685B0C9D2CDC097370100000F408CCADEDDC2651F0010386AA6D4E1CFA9782B0000000B5896B6D8D1CDA45E14021044A8DAE3D2D8C1913A1F356CAEC3C3C5BDB386431A29364B83B5C0C2AEA58E4F0000266FAAB3B0AFAA9FA06A2D2E4B3A364C8EAFBFC0A4692200094B9AB6B8BABBB0A87F30060000135E92A09E958E74350300000000003B93BCBB9276361804100E2B71B6D0E4DFC97F361C1A101E5DA7D7C38948240C161C9E5152A6DBD59E521F14122226274E93DCECC779443834100E2B71B6D0E4DF01FE1360070718307166460800000000001581A8ADB8AA88391A110000114280B3D2D2C6983F0500155285B5C9D2CCB28A3700000011498FC9D5D8B46214000A3B6AABD2EAD2AD793300000012629FC0CEDDD6AC5810041E4E9BD1E2D1CFC98B452D4076B1C4C1B9B8A88230142225407DA8BAB6B7B1A15A0600367DA4B4ADADA096926D31344134295395B4B2B5AB6E1D0010559AA9BAB9B6AFA6893E0000001C6791A4A49D967D3400000000000B49A2CAC18F572C08061E244075B9C5DEE1C0833530241F2466AFD8C084471D160F19A3524FA0D5D1984B2018211B283055A7D7F0C17141433A1E244075B9C5DEE101FE1460070718407A6E38040000000000127FB0ABBBBA843B180E000115487FABC2CCCC93390000125090BFD5D1CDC79E3A0000000F4196C6D5CCAF5A18001E466DADCED8DAA6742B0000001861ACCCCEC8CEA5470800144B9BCADDD2D2CD893F1F3D77ACBCC2C0B8B78438193C34467DA1B8B8B7B18C4603003691B3BDB1AEA39C90622B303D30234F8CABB6BFAC6810000F62A4B5B3B7BEAEAE7C3D0500001A6B97989098947D3F0000000000044EA1C6B6895229151718203A7EB4D6E3D4B9753A1E1B1D316AC4D7C3824D2918231C9D4D51A9D8CD9A53251D181B2C3757A3E1E4C56E3A363618203A7EB4D6E3D401FE1560070718507A76450400000000001E74AFB3C3B18040170E0200154C81ACC9D4C8903C0300135688BAC9CCCCC18A2F0000000F4991C3DACEB3591E02214172AED4DAD6AC66250000001C65A1C4CCC8C7A94F0E0017539BD2DCD2C6BD8140234272ABC2C2C4BFAC793A1D26304185B1BEB9B0B3964905003784ADBDB4B6A0A297692B2C37312E598EB6B7B1A0611200156999AFBAB3B2B3A979330700001E7194A3AE9F927D3D0000000000025E9EBEBA944F2B1101151F3E89C3D9E4D7B2752C1F1A1D2D69C1E1B47D4B21181820974350ABC9C5944C1A0B1924283660ADE6F0C170443139151F3E89C3D9E4D701FE16600707186076714C000000000000238DAEB8B9A46E3018130609225489BCCBD7C694340A01185F96BBD1C8B9BA87320000000A478FCCD1D5B35F1809164178B7D6D7CFA85D170000001B68A3BEC6C6D3AC4D11011652A8CDE1DBCFC782301E4D7CB7BFC1B2B7B378381B2329458EBACBC5B5B0883D02063E92B5B6B2AEA5AB9A641F213F282F6394AEBCB8A36009001A629CB4C0BAB7BCAC7F410C00001D6B969DA09D87723300000000000550A2BEB0905B291213172A4381BACFDAD7B1723B221C192E77C0D5B980431A13141D944754AEDCCA8C4D200F232932395FABE3EBBF6B3B3634172A4381BACFDAD701FE1760070718708471480500000000002F8BB0B7BBB478321C130C0F265F91AFC3C6C78A3104001E67A5C2D5DAC8B98D350000000C5996C7DED1A7500B0423527AAEC9D4CAAD56170000001863ACD0E2D1D0A14100031C4FA7DBE1D0D4BB7C301D4985BBC9C5BAB7A5702E0D262A3F7EAFC2BBB5AE944000023D89B7B8B1B0A2A6A0682B1D3837365F95B9C2BD9E5B1D002870A9BAB9BCB6B5AB7933020000186B8A9C9F9494753300000000000355A3C5B98D4D1D130E16244781B9CFD4DAB37533271C162871B0D7BF82411F1E21188F4F5CACDFCC8B471F1E1E242B2A60B7F2F5C06436343916244781B9CFD4DA01FE18600707188074693C0000000000002477A8AFBBAA6B2B191308092B628FADC5C5B37F25000021619ECBD4C9C9B780240000001153A1C7D2CAA85417002D5C87AFD3D3CB9C4D19000000195EA1C4DCD0CCA24D0A012658A6CEDFD7CCB46D27285589AFBEC8C1BAA76F2312222D427FA7BFBBB1AE9C4505054996B4B3B9B6A7A0926221193428326598B2BEB9A3550E001B74A9A9B8BEBFBBA97C2E0100002E6E919C99A290773100000000000357ABC4BC9154251C1416254687ACBAD1CAAF713226261C2877C4DCBE7D432520111794485DADDFC9884A24152D2E2D3B67B9EBE8B16938332E16254687ACBAD1CA01FE1960070718906C68470000000000002E8CA8BBB39B612C141201072D688EB2CCCFC0843000003173AAC8DFD2C2B6802A000000175199C4D2D8A44D15001C5B83B9CEDBCC89411B0000002171A5D1D3D7D5A94E110C2C68AED7DBD1C8B06B312B5782ABB2BDB9B3A466240E1A2A528AADBBB9A9AF8B3903034591B6B8B6BCA8A7935B211D322C3A649CB7BEB19A5001002871A4B4BEBDB5B3AB782C000000226E94A2A092897B3B00000000001E6FB0C2BF8C4B2B1812131A488DB9CED2D0B06C2F2C1E203081C7DCB8813C13061624965462B1E0C88B451D201F29232A5DB7EEE6BB6B44303A131A488DB9CED2D001FE1A60070718A07A72470000000000003D92B3B8B8A1673115190E151E5C95B2CAD0BE85330000256FA2C1D4D2C7BE84250000001557A4D1D3D3A34A07001D528DB2CDCDC79A410B0000042E76ACC7CFD4CB9938010B2357AAD4E0D6CBB369322E6491BEC8BBB4BDA669260D25283D82A9C1C0B8AF8F4000064E8BABB0BAB1A4A59C56211E323644699FAEAEAA9A4910001E78A9BEC1C2BDABA17B2B0000002474999F9F9192763D00000000001F70BFCCBD8E532B1A101A254D8CB7CED9DBA2703623231D2A86C9E0BE803D1A1D17208E4E62BAD5C487421F1A1A252C376DC2F1EFB9603C34341A254D8CB7CED9DB01FE1B60070718B077713A0000000000003293A7AFB3AB682C1A1C0E0E27649DBDC1CABA782700053185ADC6C9BEBFB97F210000002367A8CDCCCAA24D1101236191BBCDD5CA8D480C0000022E78B2CED5CFC2913705022866AAD5D2D1CBB061302F668FBABFC3C5B29C591E0C1C274386B4C7C8B9A7873100044B92AFB1A7B6A5A5995D171B2C2E3F6CA3B1C2BC944301002478A6C1C3C2BCB6AB742A0000003475899D998B7D6A320000000000186EB8C9B28854250E12142C4E87B0C9D8CDA76A2C2526213485CDDCB28139170D1029955566B7D7BF82411B14222033306BC5F5EABD6142323A142C4E87B0C9D8CD01FE1C60070718C07A744F0000000000003C9CA3ABAF986034231A0A1B316A9CB8C4DBC0781B00023580ADD0D4C7C1A9821B000002205BA6C1D0C79A430A0625638FB6CED1BD8433000000042E75B6CACFCFC595420E0F2E6BB2CFDCD3C7AB692E33628DA4BFC0BEB29E5717061128458AC3C2CBB5AF873100094F8FBAB8B4AFA09896561E1627344477A7B7B8AF894100001A74A6BAC9C9BDB9AD6A250800003484989E9A9C8E6A3800000000002778BCCBB388542117111B1E508CB5C7DDCBA16126292A1F3583CEE5BE85461C1A151A904E70BDDEBB7D3917141D1D2A3371C4F3E4B36A4330331B1E508CB5C7DDCB01FE1D60070718D077764A0200000000004296A4A4AE9563241A18130F3470A1B3CACBB5762000003690B2CFCDC4BCB679220000001C66A6CED4C59C440F0126688AB5CCD2C3883901000004317CB3C4CAD1D5A13900082E6FB2D8DAD8CBAF5F2B306999B9CAC8C5B69E510B0010244988B7C3C2BFAE8E39000B5F91B5BBB0B8A29E905A1C0C253C507498B0B5AC853F07001871B1C0BFBFBFBDAA6B1F0000003282919BAB9B866C4307000000072F7FC3D2BE8B54271A1817285B95AAC4DCD2A5672E2328273893CDE7BF7C43241E202A8F5675BED3BD7E3A191C2326283778D1F9EFB666422D3617285B95AAC4DCD201FE1E60070718E074734E0600000000005294ABADBE9B592C1F1A1210437DA7AFBEC8B2742400002E7EB3C7CDCCC2B06D190000002667A8CED6CF9A40040130638FB2C8CCC085350300000C3279B5CED3D0CA953109133D73AEDAE0C8C3A361212E6D9EC0C3B9BAAC935018000F28478CB8C1C7B5B2893500135E9DB8B6AFB3A0A79B52150825334D7FA2AFBAB28E3900002E81ACBDBFBEB4B59E681B0E000030899E9D988D95724606000906153889BECDC2894E261618212B578DABCEDBC8A56B303031274791D4E5B8773619161C1F894D6BBCD7BA76341D24262F3E4177CDFAF0B05B3F3E36212B578DABCEDBC801FE1F60070718F070734E030000000000529AAAB2B5A45329231D11173B77A5B8C3CDB8691F00003387B3C6D0C8BAAD75170000002876AEC7CDC192390309387296BDD0D0BF8130040000062D80B0CCC7CFC58B38040C4179BBCCDACEB89B4B1B2F749FBBBFC0B8AE8E471304172C508FB7C7C6B9AB8C31000B5F97BABBB4AEABA38F52140B1D385381ACB4B0B2873600003083A4BCC7C6BEBBA96B220100083E8089959D97866F2D00000000002E86C3C9B3743B29171E1D2E6097AECAD0BF98543127261E4398D1DDC0773D16151A208D597FC0DCB4723A17282B25323E79D6FAECB5663D32381D2E6097AECAD0BF01FE20600707180076714800000000000352A5A9A4A29153231D230F204E85A3AFC2D3B160220006439CB9CACFC1C5AF6917000000256BACC4C9C28C2E000239759AC4CDCCBD7F2E000000103174B6CDC8CCCF8535000B417AB8D8E3CEC99F561F30759DB9C4C2BEA889410C001327508BB0BCC9B1AE832E001B6FA4B2BEAFA59DAA9D5B150920365485B0ACB1AC8E2800002E8BB5BCCABEB5B09C6E29090001387E8F96968E886D3100000000002E85BBC5B07B452414141E306590AFC3CEC08E4F2C27231E4B95D6E3C07C3D21151D27905B78BAE0B67337231F272830417BD0ECE7AC573033301E306590AFC3CEC001FE2160070718106D6F40000000000008599FA9AAB5975B252D1C171C3778A4B0BDCAAA691A00074798C5CEC8C1BFA15E140000043174B0D0D1BE883C0A05366FA0C9D2CCBB803404000006387FB4C9CFC9C4883101144E74B2CDCDC6C7A05524397BACBBC6C1BCB08A3F0C0003255F92C4C4BEBBB883220016609EB2B7B5A6A8A392580E071D3E5186A6B2AFAB822B00003A7DA7BCBCCBBCB9A15E251100073D829196988B80613903000000003D8DC1CCAC8A46221B10202F649CB7CDC8B09A5831262A204797D7E5BE7E461A1C141E875878CAD0A968311B1E21292C3984D7F3E3A35E2E3430202F649CB7CDC8B001FE2260070718207C794500000000000C54A9AAA6B28C412828290D163C85ACB4C4CFAD631B00054BA2C3CBCACEC1AA64130000042B78B7C9C7C28D390507357DACC0C9CEB67B280000000E3D88BDD0D4CFB47E2303134288BBCDD5C4BF9048234377A5C1C3BFC5B68C340100142B528FB9C4C4B4A78732002169A7BDBCAFB2A0AA925F04001B45618DA7ADB1A674310000378EB5BBBEBFBDBCA1641E0800023F788F8A988E8568390C0001060F44A1CDC7B07A4F251416222E6CA0B4D1D2B7895434302739469EE8EBBB6E330F11212E885985C8DBAC6434182B2F30384887DCFDE3AB5C343532222E6CA0B4D1D2B701FE23600707183067724500000000000D67A4A5A2AB8A502323181724488BB0ABBECFA4570C00084CA2C2CECABFC3B5761A0000002C72B3CED2C3823100003E7EA1BBCECEB87120000000154388BEBBCECBC178280A1B5285B3CAD6C4C29B411C447DACBCBCB8B8AD833B0204172B5899BEC3C1BCA6792300206CA1BEC3ACA49E9C8D45040923446395A6B4B49E7F2400003D88B2C3C7BAB1B8A6682508040A3F85958C9F9789713D0A000304084199CCC5A2764A2A121C23326D98C5CACFB1885333372C2A51A9DEECB86B36231619248D6187D0D8AD6530181E262638478FDBFFE8A962342F3023326D98C5CACFB101FE2460070718407685510600000000185EA1A9A1A984462C2A2619234E9CB4B3C3C8A15C0F00064BAAC5D2CEC8C0AA59100000052E7BB7CBD3C7853400013D80AEBFC5CBBB751D0000001E4690C3CECDCABA7A25091B608FBFD4D2C6BE9448233C83A7C2C2B5B09D7C32000008275693BCBBBEBDB27A26001F6C94B3B6B6B6A6A68D4C0A0022456D98B4BAAEAB681B00063782B4B5BEC9BEB3A45C210A010539859793938C8F6A31080000010B449AD2C8A4783B13151A2240759DA8C7C4B186512B302A3961AEEBF6B8783C241B192A8C5C93CAD9AE6B281E1E212C314A8EE1FAE5A6554935382240759DA8C7C4B101FE2560070718507D794900000000000E68A9A3ADAD843B262821141F5093B8AEC4C4A1510C000650A9C6DECEC9BF9A5E080000053C7CC2D0D7C57823000B478DB2C8C8C2BD752600000027488CAFC3D0C6BE7D1E00225A92BDD3D7CEBD843B183D8DACB7BAB4BDA16F2D04000B3559A4C8BECBBEB38620002473A9BEB9AEA69C9E894612001C446594A5A8A2A6761C00094689A9C0C9C1B7B39B4F200800104C88969F978E835C32080002101E539CD4C8AE713C191C1B284076A6B4D2CEA77449272C322B5CADE6EDC26F3A10121D277F6296D8D9AD642F201F2631384D91DCF7E1A556362B32284076A6B4D2CEA701FE2660070718606F6D3F0000000000176BA79B94A0803C2134291D255593AFB5C2B6964E06001962ADCACBDBD1C1A95B060000143779B1C4D8C77F1F02104D90B7C9D0C2AC711A000000235094BECEC8C3C07D2500165C8EBCC9D7C6B284331A3A85B0BDB9BABAA26A2100000B35619CBBC3C9B6AC7125002C7CA9B5BFACAAA4978E45000024516D8BA9ACA89D7528000D5593BFC4BFB6B4B0975D240F080B437E928D939C8F69380C09070D1D50A9E0CFA56B38222020253D7199B0C9CEAE7B4B282D2C346EBDEFEEB6682D1F101931896795D2D4A65B230C1A2C372E468EE7FBDE9E5739323B253D7199B0C9CEAE01FE2760070718707576440000000000116AA2A69FA97F3F22302D19215BA4C1B7BFBD914106001565B4D3D9C9B9B59D59170000143881BBCDCCB9732F03105A96B8BFC7CAAA781F000000214992B9C7CAC1B8771F002A6D98C7D2D9C6B67B3318409BB7C5C0B4BA9E661800000D336197B6B3BCACA47829112E83A4BEB8B3ACAB9F883B060010567D9BADADA79B632000084D94B6CCC8B7B6B29B561E08000546899F90919689663C0C040806145AA8C6CBA474432E222427397297B3D0CEA6763F2B2D35366BBDE7EEB96A351818213085639AD2DAA7622A1F1D28262D4A9DEBFFE29A583A3C3627397297B3D0CEA601FE2860070718806F7B4B00000000002373ACA19AA878453A3C331D1D5799B8BACBC190470600106BBAD2D2CCC6B89C5A00000010448EB2C9D8C5752500064A94B2C6C2C6B3681D00000622539ABEC8C7C3AF601B0323659ABCCCD1BDB17A2E1C5295B4C4B8B2B39C5E1300001236629EC0BEB7A9A271320A2F82ACC0BDA7AE9DA18C3F0600245984A7B7AEA497611400135595B1C3CBC0B1AE9B552511051550819099999684532B0C0A0E1D2066AECCCAA164432C2D2327447EA2B5D0D7A87645352F37366EC5F6F2B86E3317181E2A7C6691D6D5A15531241B26292E52A3E9FFE2995138343627447EA2B5D0D7A801FE29600707189079764F04000000002572ABA5A8A4693825302A1F2D59A1BCBACFC78F440C001663ADCFCECBBBCBAE5A0F0000103D8AC2D7D7BD7F2300116090B2BDC0BBAC68160000082B5B9CC3CBCAC8B266180029659DC5C8D7C4AF712819468CBCC2B9C1B7A160180000133C6B97BDBFB7B39E6924082C79ACC0BAB2A79895863600001A5E7A9DB9AB9F935E150418589FB9C9CCBABCAC924F1F14000D448794979492864E410D161F182975B9CEC59C603C3222242E3C80A2B6D0D2A6833F222B353A6EC2ECEFB467341A11251D7E6FA0DADA9F5722151D29313754A8E5FFE89A4F31333E2E3C80A2B6D0D2A601FE2A60070718A07D7E570D00000000318DBCAAA7A6783A2638311A2969AABFB6C3C0963A0000196FB9D2D8C8C7C19F4E0A00000F4387BDD1D7BA6E2C0B1A5DA1C6CCC4BDB76D1C0000072A4E8EBCC8CEC7A661120029669FC8D3DAC2AC7525154D96B6C4BEB4AC8F530B0000154875A7B9C2C2BAAD7126092D74A7B7B4A7ACA39A7E2F0D001C5F8A9DA8A09A9E5D0E001A5AA0C2C3C0C1C2B7934A2A090013508285949A8E844E3913151D1B2F67BCDAC191643D2C2D2F2C5289A8C2D2CAA5733F2234383E80C9F5F5BC682D1D16262D7672AAD6C99554231C232C29385CA8EFFFDE994E3933322C5289A8C2D2CAA501FE2B60070718B06F825606000000002B8FBFAAA5AC7E3E2D3A342A325FA2C8BEC7C2833B08001369C2D1D0C6C8BEA7530500001B4192CAD3D5B56D2806135FA0B5BDC0B4A8691500000E35599CC3CAC4BCA8590C002A6FA9C4C5CAB5A46725194C9AB8BDC1B8AD925600000017476EA5BBBCBBBBAC661D0B338EACB9B2A8A79C97823500012A5A87A5ADB09D9C621A00195F9BB4BAC2C2B9AC864B241209145C8A97969594835E3F0F1118132976C5DCC58B5E38232124384382A7AFC7BC946C352836343F82D3F3F2B5612F18121C387E76ADDED898492216202D2E394FA1E6FFDCA057383336384382A7AFC7BC9401FE2C60070718C07C8C550F000000002981B8AAA49A653432433326305EACC6BDC3B9803F01001676BFD2D8D4BEBDA54F0000001E508FCBCFC9B26223030E5B9EBBCAC0C0B46A2000000F3262A7CCBDC8C1A65D0B01337CAEC9D2CEB8AA60210E5192B0BDC3BBB3874F0700001E4C7398BFC0BAB5A25A1B023689B5B9BFB4A89391702E0300346C99B9B6A5A6824F0900155FA2BAC8C4BBBDAD964222090011528C9992979480533F1A111D1E227BB5D6C78B5D34212627334A8A9BB3D5CF91623A303A3E4789D8EEEDBB5C28171720397D79B0D8D4944F1C1D262D2F395EBDF7FFDA8E47352C31334A8A9BB3D5CF9101FE2D60070718D0737B4C00000000002D87B3A4A1A2703E323C24223774AEB7BCBEBB823000001B77BFD5D2D2C1BD9B4A0100001A4A9CC5D1CCB87026001464A8BDC4C7C0AB650F00001337619CBABDC1BFA4530F002676BCC3CBCEC0AB5E221F4D91ABB7C2BCB08A4500000026517CA2BAC2C9B4A35E18063F83B3C8BDA7AA95937D33000731728FA5A9A2978B550B00185D9EB3B4BDB7B9AC87472809111E5D8F92889293864C41201F25243C89BFD3C08E5E3A3E2A2D314B8CB2BAD4C2966335232C3B3B88DAF8ECB55F2F191B1F2D747EB1E5D894572B1F251F2E3C59ABF0F2D2945C3B393A314B8CB2BAD4C29601FE2E60070718E085885B15000000003B9BC4B1A3A66C3630453A2E3F73B2C9B7C1B87C2C00001A75BFCED7DBCDB995400200001A5698CAD3CFB46C28001458A1BAC6C5C0B168190006174D71A2BCC2C0B9994A00002C73AACEC6CBC3AE5919135BA0BCBEB5B9B98E410000001B597BA4B7C8C4A7A45F1C03398CB0BAB1B0B09C9C6C2D0000296888AAAFA69C925911001A62A0B5C9BFC0B8B38240201B021B588F96919A9074423E1B1A1C193389C5CEC081502F2C28272F4D95B8C1DECE9361361E343E4985D8F7F4B46327101E23347475B7E3D294481E27252E33335BABEEFBD99A4C3F2C352F4D95B8C1DECE9301FE2F60070718F073804C01000000003695BDABAD9C5B30263B36263A7AAAC2BCBEBC77260000237DB6CDCFCECBC09F4E0000001E529EC4C6C5AE672407185CABBFC4BAB5AB6818000118476EA7C2BBC1B890450C032F7DA9C7C9C4BE9D56121C5C96AEC6C7C3B3833B00000026608CA3B6BFB6A8995A1C054791B8BEAEB8A6919A72260000347E9DA9A8A19C8E420600256CA2BBC3BDC2BAA8844326160009568997969F8E7E3E401C1C1D1F3689CFDCB78B4F352A2A334355A2AFBBD4C6905A352E3A3F489BE3F7F4BF67281012263C7077B7DDD68C4728161D242E436DC7FAF4CF7849362B404355A2AFBBD4C690 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 61440 61440 0 01FE3060070718007A7A4406000000003395C0B9B09F61212B422C1F4077B9BFBACFB36F230000217FBCD1CECDBEBF9D4A010000275FA8C5D1CBA860290E155CA0B2B8B8BCB2681B0002194871ACC4C5BFB7943E01073E83B5C9BBC4BA955017164C99BDC8C8BFAD7A32000000286283AABDBDBDB59B57170A3F8BB6C0BAA8AB9B926C2600003C759EB6AE9B9B874A02001C6EB6C8C4B8C2C3B07F3D1C0D00175E8E90978E8B793A421E28232F418AC8D2B17B4E2D2B2D2532518CB6C2D2C990593A262F38539BD9F8EFB062240D141A3B747EC7E4D190431716202B303E6ABBEFF8CE8455312F3832518CB6C2D2C99001FE3160070718107079460B0000000038AACEB4B5A95F342E3E30243870B4C9CEC4B36D2000002A85C7D2D6CDBDC39D3F0000003464ACC8CECDAB6124091261A0BAC4C3C0A85D11000323527CA1C1C9C3BA903F08023882B7BEBEC1B89A480E185496BEC1C4BBB77F25000000296185AABAB8B5B7A04A13134D93B3B3B6B49A959574260004478497A8AFA08E843C07002671ADBEC9C0B8BEA97E402613001B558A959594977E353B1A20201C3F92D5D3B16F4B30262930335890B3C5D1C38A572A273A485B9EDBF9F6B45D2E11171B407983C2E5C188401D2428312C386FBAF5F4CE834A352630335890B3C5D1C38A01FE32600707182070744105000000004095B9ADA29753342A3833343B7AB5C7BFC2AA6D2000002885C4D8DFDECFC194400000013068B1CED7C7AC602204136CABB5BAC4BFA663110004205278A6BAC2BFBD8F3B00004287BABEC4C3B095410C155A96BAC4B4B8A67A2D000000306C91ADC3BAB8B2A350140A428FAFBFBEBFAA938E6220000045809EA6A8A192823E00002D78B5BEBAC0B6BAAB79482B21051D63978A8C90907836402826251E4A99D4DBB6784A3F312E303668A1B0C5D3C68B4D2F273A3A569EEBFFECB0672B1818213B8082BBE5CE884221181A212B486BC0F7F8DA8340292F3A3668A1B0C5D3C68B01FE3360070718307B85500F000000044B9FC0B8B99E522F37423528477AB4DBCBC7B1641800002F92D0DAD4D4BDB79647000004366DA4C4C9CEA96A2C081264A9BCC2BCB4A55A1F0005235581A5C0C2C8C3943C00034180AFC9BDBEB08A410D145093B3BEB5B8AB7B26000000327491AAC1B7BDB19C5212004B90B0BBB6B5AA9C935F1700004180A3B1B3AC987D350000337CABBCC3B9B5BCA77E422A1D0B1658949F919792772C3C233035304F9CCCD9AF6F3C32313235456AA5BACDE1CB834C2928394B65A5EFFEF3B2662108121D3D6793CADFBF803E2119192B324574C0F4F7C57B4D383135456AA5BACDE1CB8301FE346007071840797F4F130000000B4AA0CDC3B99C5B352E42342D4373B3CBCAD4AF601A00033597C8D7D5CDCCC3953E0000113C6F9BC7D4C5A1691F081B62B1BFBFBDBCAA5F1400072F5E8EA9BFBCC9B7822F00004891B0BFBDBEAF893E0F225FA5B9CEBEBDAA7224000000357094B2B2B7BBB29B480B0A488FB6C2C2B5AC90855B1800003F83A5A6AC998F773802083476AFBBC7C0C2BBB0764629100C205989988D8B8F702E44303D3A3E5AA8E1E6AF744F3B323B3B496BB0C3CED8D18C56393A454466BAF3F7EBA5561F0F1921476790CFE3C77D4424191B2A344B6FC2F2DCBA7D46382D3C496BB0C3CED8D18C01FE3560070718506F7249140000000B50A2C1C1B09B5C292C433A2D427AB5C2C0D1AE5F1E00003997CAD1DACCC2BA9233000000366EB0D2D5CDB16E250E1B66ABB9B9C2BB9F5D10000B2C6386ACB6BBC5BE872600024691BAC4B7B8B08F37051160A3B6BEB1BCAE721A000000407395AEBEBDB2B5994A0D0E4A90A6BBAFAFA6988B5F1200065395B1B5B0A09A782E0004347AAFC3BEB4B8B8A375402B1201155D968C99908A6E1D4A272C292E5EB5E0DAA770432E292C343C6CB3CCD4DCBF874E2727344469B8E3FDFBAD5B1B121B24486A94C5E5CD7B3B201116252C4984C6F1EFBF79383634323C6CB3CCD4DCBF8701FE3660070718607B7241040000000552A2C9C5BF92502A34483D3A4E8AC4D5CDCDA754120000368FC9D6D6D7CFC5913300000B4373B0CACCC3A16529031A6AA6BBC4B2B79F501807112C6691A5BBADB9AB7A260000418FBAC4BDB6A98D36032063AABDC1BCBBB67D16000000417D9CAEB3A7B8AB934B0E044E99BBB8B7B8AC8E81510D00054E8D9FAFADA497782E0A08367DABBAC2B9B8BEAE7A41270C0A1B5F979A9498936D2733191A25284C9DCDC99C623D262232363F6CA9C3D3E3CB7F452C2E34466EACEDFFF5B2551A0D1E214B6C98D3F1C573351C111932365070BAF4E5BC7B3D2F31333F6CA9C3D3E3CB7F01FE376007071870707342070000000D54ABD6CDBC9C562D2B49382C4885BACCD3CE9B591400023B96D7DECECFC6AE87330000103F7EB5D0CBBDA56226051C65AAC0B6B2B7A1500904132A7090ABB5C1C5BC7E2700004B9EB9C5C7C7A97B330D24609CBDC9B5BCA86B12000000477D8DA3BDC1BBAF904C080E4F98A7BCBCC1A28988541800094B939DB3AA9E976F380807418CB0B5BBBAB6BEA263412D170B1E6484929A9288671A51424A3A436ABAECDBA973443A3D333D4E74AFBED1E4C77E502A303A3969BEF7FFEFB3591A08162A4E7392D5E8CA72301418252A284B83C8F3EFBE7B473A3B374E74AFBED1E4C77E01FE38600707188069694209000000125BAAD0C6B795582C383E36334082C4D6D9D09F521300004C9ACDDDDBD0C4B185380000104786B3C5D2CDA269330B1F70A2B7B7B8B09C4C0F020D386886A1B1B9BAB57E2600004D96BBC5C1C0AA782C001664A2B3C2B2B4AF67100000084D8895B0C4BFB3A9853B070C4E95B6B7B7B5A88E7E4C0C0014619DA6A3A9A093722F0E094180B3CFC2BAC5C19C6B3929180A27668D9896958963124639443D3967BDE2D8A3684A353831404678C9D1D9DFCB7E493029304875C8F9FEE6A465180F0C24536EA2DAEBB66A3217161C333A497AC1F0EFB972422F343A4678C9D1D9DFCB7E01FE396007071890806F3B0B0000001257AEE0DEC79E582D3040392E5385BDD0DBCE9951100004409FC8D8D4D4CEBD8B2600001B5189AECAD1C8A66C2A1216679DB6BBB0B197460C081640718FADC4BBBBAE721B00014896B8C4C2B6976D200021659FB6C1BCC4AA6E0C000000418598B2BFBBBBAF883A000C5593B8C8B9BBA98B7247090009599F9FB1B6A3915F2D0216528CB5BAC3C1C6B4A1693B2E1F0E215C9397959E8F61144428372D3370C5E3DBA9653C313F3D3B4480BDC9D5DEC07C442E2A3F487AC7F4FCE5A753150B102C5C6FA2DCF4C4702B1A211E20365982C4E9DBB0682E282E344480BDC9D5DEC07C01FE3A60070718A06C643702000000145EACD3CBBF975538443B33395086BEC7C8CE96501300003C9CC7D8D8CAC5BF87250000154981BDD2D5CBA2652D131D6BADBEB6B5B3965405001C41769AAFB8BEBCA56E1E00024595B9B8B9C1A36C1B03236DA2B9B5B9B7AD6810000000528BA0B4B8BFC2AF843906045897B4C2BDB6AB84773C0700086093A8ABA89D927328040D4E8CB6BCBAB2B0B5A273462E1D11215E959F9A90885B113D35363A386BB7E5DB97553A333637384C8AC2CED7E1BD7A442B232A4C7DC9F9FBE5A74F211417195867A5D7E4BD70361C170F2939518BD1EAEAB17F3E2630324C8AC2CED7E1BD7A01FE3B60070718B072603D02000000125CB0DDCCC094482C353D373B5189C0DED7CC9A4A1100003B9DD2E5DFD6CDBD7C2500001B497FB3CDCFC9A0702D131871AEC4B5A9B18F4F160E22447B99ABB0B3B1A46C180000579AAEC3BEC09B681F0C2A76B2B6B2A7B1A4610600000F569BA3B0BBB5BAA7813900005197B9C8BCC1AF7E643404001E71A3B0ADAE9E90701F000D5199C1BFC3B9B6B58E63442C200E2B69929890968F6B0E462E35343F77BFE1D6A0533937363A3E4D77BECBE0E7C272482520425189D1FFFFE7A9501E111925576CB0E1EAAA58291F13202339588CCEF0E8AD673730353E4D77BECBE0E7C27201FE3C60070718C0766D3D100000001C6EB8D7D4BE9258433B4540486194C8CDD4C99A450C000052ADDFE1DCCEB9B67A230000165C93BCD0C7BE9E653B1D20689DB8B5B5BC954B1210234377A2B0BEC1B5A2691400004B94B4C6C6C4A1571800286DA3BFC4BFACA258050000065994A7BAB8C1BEA87C2700055398B1C0BDBCA987733604001A62A0B0B5B3A3A16C2105175999B6BDC1A8B1B8896B3E322814285D8E93969B8B620A48393A3C3B75CEEBD99C563D3E3E3941498EC5CDE2EACC784128263D4886D5FFFFE79C5616150E2A6065A6E3EBBA692C1C151F233D5E91C9E4E2A0603733373B498EC5CDE2EACC7801FE3D60070718D06B5A360D0000000E68B8D7D3C1944534363D3D455B8ABBDEDBC2954409000251A3D1D9D5D1C2B37C1D0000174C85BECFCEC5A76C390A1C74ACB2B9ACB3933F1710225287A1AEB4B8BFA8621200004F98B7C6BEBE9B6017001F6FACC6C9C2BA9F5B000000005997A1A5BAB7BEB67B2F0008589EB6C1BDBCA389642B00001F7097ADB4B19C936621031E5D96BDBFC1B5B7AD9471473C1D132366979B9B958557004E424947507EC7F9E39862413C38444C5290CDDDEBF6D073452D373B6393D3FBFFE69E451B16131D5564A5D5E2B2632F1B1F1A223D5F8CC4E9DAAA68423932315290CDDDEBF6D07301FE3E60070718E06F5B32000000001863BBE0DFD194603A413E3644628CBDD4D8CA883E0E00034FACD8DBDBD3C9B6801C000026659CB0C9CBC3A474360D19699EAFBBB0AA874712192A44819EADB1B1BBAF600F00005FA2BFCFC4C28F561300256CA7BEBEBDB9A15D0800000B598F9CB0BAB6C1AA7B290000579DB6B8BEC2AA80592F000019619EB2BABAAE9D692405205C9EB8C2BBB9B99E80654937201122618D9C958D835802393033363D73D0EDD1894E3C302A39435793CCD8EBF1C77435272C3F588CD2FFFFE09849150D0C2B726AAFDCE7AC5E2E1A0F162F47648AC9EEE7A95B3732352E5793CCD8EBF1C77401FE3F60070718F06E663413000000186CBADCD4C0964C373C3C364B688FC9DAE0CB8D3707000852B2DADDE3D6CAB2711E00001D5D9ABBCAD1C89F64340B1D78ADB3B3AAAC9C4718172E4D7E96B1B3B0B89F640B0003589CB8BBBBB6955B14002C6FACB7C7B8ACA1540000000C649695A3B1BAB6AC802A000B5BA4B3BFC0B5AC846B3003002275A0B0B4ACA19D6A1C04216C99B8C1C7BFB6A9855F523223182C609B9C9597915C0347304B394582D5F1DD9556323D3E373E6191CEDCF0EEBF723B2A2133549EE0FFFEE49845140815205D68BCE3E1A45A281D0E1B274D6D93D0E1E5A861343839396191CEDCF0EEBF7201FE40600707180077633C090000002B71B7E7E0C892593C3A40404964A0D2DADFCD933A03000853A8D7DFDAD0C5B97218000025649BC0CCD4D09B73400D1C639EB9AEB2A59140171C2B5188B0BAB1ACB19A580F00076098BBC0BFB488510D032D75AACABAAEB2A0510200001067A3A697A9C2C3AE722700095298ADBEC5BEA36F552100002073AAB3BCB8AB8D6821012764A1BBB8B5B5BCAD7D67513B1C0F2C5F8FA0A099895400494C48444586E4F8DB9356393D39404C5C9BD8E2F0F3C56B352C33435CA6D9FFFFEA9543131219276761B2DBE3AF5B25130F202C457397C6E1DBA660382C29355C9BD8E2F0F3C56B01FE4160070718107A62360700000A2D73B3E6E1CF97563B3F4835466098C6DBE8D3913800000855ADDCDBD2CFC9B16B2000002B70A7C2C9CDBD987336151F73AAB1BCA9AA873E1B1D2A5687A1AEB7B2BD9D5201000B58A0BFC3C8AC7D4903003985BDC8C1ADB39D4E040000136A9EA8A4B1BBB2A36D2102075098BACAC0B7A77A5B1F00002373A8BCB7B5A998671B09276BABC7BAB7B3BAAE8763443F2C1F23628A9E96967F480041313240438CDBEDD7875241363C3B415A98D3D7ECE6BE704A292239539ADCFFFDDE9442160A1A296666BFEAE9AD592515151D28467096C3E6D99E563A2F343B5A98D3D7ECE6BE7001FE4260070718206F5D3606000009276CC1F1E7D49E523F45493B476B9CC7D9D6D0833500000D63BDD2DED8E0D3B9711900002368A4C3CACABC9A763D081C68A3B8B4B6B389431D1D385C8A9DA9A4A7B8955207000A5FA3C4CDC5B3823F09072D7BB4C1C0B7B59647000000105D94929EABADC3A9762902125398B5BBBDB79F6F50280000357FACB8B9B1A8925412002268B2C4BFC1BBBCB28257503D1F17296395929090825008473C4A4B4D94D7F0CB93563F3F3B3E4358A3DDE9F1F1BB733B2633375FA1E0FFFFE792480E0609276D6DC8ECE0A759280D111C34496C94C1E3D39F5E38282C2E58A3DDE9F1F1BB7301FE4360070718307853281000000E2E74C5ECECCF8C4F3D3434375366A1CCD3DED8832F00000D52B1E2E2E0D8C4B26D1D00002874A4B7BFD3C2A683431D22659EBAB7ABAE8B4419192B4D8BA0B1A7ADAD944F0000146BB0B7BAC0B7803D00003486B6BEBCBEB59F4F0000001C77A1A2A0AEB9B1A3712100055A99B8C3C0B7A3704C1900002B79A8B7B9BDB1A3571805256EA1BEC0C2B9B9A4825E4A3F3016336895A19D9A7E45003A3639424E93DCE8CF864C433F3B42435BA7DEE6F2F3BF6D3219243668ABE2FFFFE39439110E10267068BBEBE3A34F1F191E293D4B6F93BCD5C79155333333395BA7DEE6F2F3BF6D01FE4460070718407C61361D0300163D80BFECECCE9A4A4442443D5C7D9DD6E0E1D98C2D00001064C0E9DED5D5C7B2671700002D77A3CBC5CEBB9C80441317699EB3BBAAA286441A1F275A92A4AEB1A5AE9B4C060007699DBDCAC1AE793B00003583B9C3BABCBA9E490000001477A59995B1BEBD9F6223000C579DC2C8C3C7A26F400C0000317CA4B9B0ADACA9581B0C2B7CA9B8BABAB7B9A883605249291F2E718E8F9890804200513E3F434783D2EECD7F513A3643425167A0DBF1EAF0B564392C283A6EA7E4FFFFD1873E0D0910216C64B0E9E9A251231A191E3250768BBADDD0916239322E3D67A0DBF1EAF0B56401FE4560070718507547200E0000093272BDEAF9CA8845383E353E5C74A5CEDADDCB7E2B00000468B8E0E5DBD7CAB5671E00002D78AAC4D0CDBF9B7740101C6CA2BCBAB3AC843D1118385F8EA5B3B5A5B08B4800000F65AAC2C5BFAB783001033687B7BDBBB1B3A14C0000001B73A6A199AEBBBAA66418000D64A3C3BCC6B9A2764E1100003583B1B3B1B0A395561C03317EA9BBC4C8C9BAA07D5C4E3D2D203671979794907944005A404C5953ACF1F9D5924A3B3F3E424C71ADE4F0FBF5CA6E3629324572B6EDFFFAD08342140911236566B6E3DC9746221718192F537291BEDAD78F543C2E3A3A71ADE4F0FBF5CA6E01FE4660070718607859341C020617347CC5F3F2D2924D3C463A425477A7D1E2DDCF7C2D0000025CBBD6DFD6D3C9AD631900003384A6C2C8C7BE9B7740101C62A7B3B8A7A08137202E3D609AA7AEA9A7AD8D3F00000664A6B7C1C2B8723000083F8CB0C1BAB1B68E400000002A73A79B95AFB2B2A9712900075EA5BCC3C3C4AB6F44160000398DB7AEAFB9A6985B1B082975A9BBCCC5B5AE9D82644D49302332688F919393723D0051444B4B4D99E1EBCB884D35343A3A4A6CABDEE8EBEBBF6B35352F466AB5D7FFF8CD823E0D0D112B7166BCF3E49C4528201A1B335E859CC6DCCF9655352B373D6CABDEE8EBEBBF6B01FE47600707187071592A09010117337AC9EEEACB994F4643423A5982A7CCE0D9C7842E00001369C0D9D6D9D2BFA7651800003282AAC5C8CEBDA2824B1521679EB2B2B4AA8A451B1D366187A0AFAAAEAD8C4300000B69ABC1C2C0AF713800043892BBBEBEB1B689420000001E77B29A94ABBAB7A6651B00095896B4C1C8BBA671461100003388ADB2BFB9B0925107003082B0C0B9BCBDB4A1805857432B213A6992A2999B8446005641383D4097E2EDCB8A54474448454D6BB4E8EFF2EAB5692B2D2F4477B9F1FFFDD38534080019346E5FB4DED5A04A2C1A1219264F7C91B1DBCE8E4F3127343B6BB4E8EFF2EAB56901FE486007071880724D1D0700000C377ECAEEE4D0875246484240627BACCBE1D9C77E2300001667C0D7D6D9CFC7B5660F00003E7EB3CACDC4BE9681441B1A6F9BB1B3B7A88B3A1824396796AFB39DA2A48E3E00000A68A2BAC1B4A7662300034497B9C4C3B6A89C3F0000001E76A38991AAB1B5A45F1804105EA5B8C7CABFAA6C3A0600013C86ADB8B8B9A7935517103986B4C5BCBABAB9A1715858452B2038728E9894967943005145434849A3E5F1CE78443F3C40425072B6E7F5F5E9BA5C2A252D4478B9E1FFFDD8893110030C338265B6E8D9984C281512182E508591BCD4C688533731383E72B6E7F5F5E9BA5C01FE496007071890795A37150C0E12428DD6FDF6D186534A4A3C3F5B85A8CEDED4C1832A00000E64B7DBD8D6CFC9B2681100003E8FB7C0CBCABB99874C172073A0B3B9ACAF82301930416A949EADAEB0AA853900000761A3BCC0BFA26521000D5096B2B3C3B9B3933B0000002A7DA19590A4BBB8A25B18001164AAC3C9C0B9A064390B00044183ADB9BABCA8884B12084988AFB7BCC2B4B3A678585E492D2132698B92A19C844200484040435799DEF4CC7F513A343D464670BAEBF3FBEEBE61332A35457AB9EDFFFBD488310F000C327263C4EBEFA3581E11121F355A7E94C0D5C58847322D373670BAEBF3FBEEBE6101FE4A60070718A07C552B0E0A051F3C81C2FAEECA805A424549406485B2D7D3DFCC823101001771C3D8DAD5DBC7A8661400003E89ACB9C5CEBB9C884E1C23779BAAB1A4A4853D1731416490A1A3ADAAAE833B00000C5EA4C3C9C0A4682300074296BCBFB5B2AC8D3C0000002980A9988E9FB7B6A2671A010F5F9CBDCEBEBB9962340700053B88AEBCC6C6AE944D12043684B2CBBDC3B9B2966E60534B262434649FA0A298783400503E414C5FA8E9FFCA8445383B3C474B72C0E8FAFFF2BF6D373C2A4A81C2EEFCF0D27F300B0B193A8361BFE4CE944623140F122B5C8195C2D5C7855032242A3572C0E8FAFFF2BF6D01FE4B60070718B073532A160115253F91D2F8F7D8975849463E446687ADD6E0DED0832C0000186CC1DDECDCD3C4AF5D1200004099BCC4C8CABC8F823F0F236F9FA8B9B0A678291C2D4165929FA197A5AC81310000066CAAC4C9C1A6671D00024F9CB7C6C1B2B0912F0000002980A28C8EA4B3AE965812001169A5BCC4C7BFAA642F03000A3E8BB4B5C7BCAD9850180F438EB5BEC4BABABAA87B64503F2A29376B999DA1907938004C4446495BB4EFFBC88A4E394645445173BBE9FCFFEBB3632E222B3E75BDF3FFFDD17632040B0E327F5DBAE1D4944724161C1E31608599B8E0C786512F22314173BBE9FCFFEBB36301FE4C60070718C06F4C251007090F4793DBFAF0C78A5948463E4E6B92B7D7E1D8B870200200157CCFE5D6DFDCD0AD60100000428BB1C7C5C8B99E8F4A191D6091ACB2ACA68037242A42688EA0B5B1A9B48C2F00001974ACBACAC2A14E10000A4E93B6BCBBB4A58A3A000000398CA49994ABB5BC9F651500125AA3BABDCABDA36D330700064383AEBBB9B09E904C09105699BCC2C2B9B8B79468585A452F2D3C7292A39F987A3000524E4D4C62A8F3F7CF8543403E4447527EC0F1F4FAFABD64332D333F7FB5F2FFF2CE8025070A14338462C1E7D793472B1D13222D5E8D9DB6D8BA834928252F437EC0F1F4FAFABD6401FE4D60070718D0744B2214020E1D458FD4F9F2CA815144413C3F5A81B5CCE3DBC9813002001874BED9DBD4DBC8AE630F0000448DBACDCBBEC09C8A4A19196B93A8AEADAB7F311B31476E94A9AFAAB0A8823700000F6FA6BEC6C4A55A1200005098BFC1C5BDAF94380000002877A39487AEB3BBA25309000C58A4BFC7D4BAA7672B000010428FB7BAB4B2AB9851110C4A96BFCCC6BBB9B6906858624F2D263869879E9790743900524953576DB0F3FFCC79413B4748465180C3F4FBFFF0B85B2C222D518AC2F3FFF1C9702410121A31865FBFDBD18C3D2516171F32668291B3D6C0875131282E3680C3F4FBFFF0B85B01FE4E60070718E075421A0705041C3B93D9F3EFBF864F414336426D95B6D6DCDDCF7B2901001F79C6D9D8D7D5C7A7580A00074492BBD2CED1BC9D864C161D6892AEBAB0A47533232C436D9BABA7ACA5A478300000146C9EB5C7C396521000085AA0B7C7B5ABB38B340000003385A49082AABBBC9A5C1200165EA9C4C0CDC6A25A290000094893B6B6C9BCB6914910144891B5CDC5BDAFB48E5D565C553728496F969F9E9273280053414C5168B7FFFAC57A4E3F3D423E4E7EC5F3FEFFF7BC67322328498ECCF1FFF1CE72280C030A3B8F5EBFE7DC9A431D18141B3366919ABBD1B7774E3A2B323A7EC5F3FEFFF7BC6701FE4F60070718F0804D29110C0A295296D5FEFDC8835E4F463B4E7292B5CDD3DBCD7E2500001979CCECDDD4D4CFA660040000529DBEC8C9C8B79C894F141F6797B2B3A9A2722B22384C6499A0B3ABB3AC7C2C00000E6EA5BDB8B59B510D001063A5C1C9BAAFB3922A0000003084A88C7E98B2C0A15715001466A5C2D4C1C4A85F3200000C559CB8B8B8B1A28D48100C4293BDC9C5C3BBB3896A515C533330386D91959A97712A00574C51516AB6F9FFCA7D4C443E4544587AC5F4FCFFF9BB6830202A488ACBF1FFFACE7A310E061633895FC1E4D298442B24201E36698E8DADCCB27C53342B3A447AC5F4FCFFF9BB6801FE5060070718007E4D220B090B235396D8F3F6D0805945443D4A7B9FBFE2DEDEBE7B1B00001A77BFE4E3D6CDC8A353080000499DB8C6C4C5B49A8F55161B689CA9B0B5A871322735516E959DB2ABA2A1762C00001E73AAB8C2B498460600155FA5BFC3C1B3AE8A210000002D8BB0917DA4B7BEA35314000E61A9BCC0BFC2AD5D2100001554A0B9BBB7B3AA95420A0B5199B3C2BCC7BBB98D5151635F3832446B8E9D9D906E1F0066564F5A6DB1FFF8CE7741433E48496085C4F4FFFEFDB66F402C324A87C8F2FFF2CC762D08040B2F8C60C3E0CB813B1E20172039639092B6D2B077442A2C363D85C4F4FFFEFDB66F01FE5160070718106F4929170E15264B91D1FAEEBF8558533F3D497A9BBBD7E0E0BC741D00001C7CC8D9D8DFE1D9A753080000519BBAD0CDCBBC998A5218246AA3B2B3ACA2753626344A6E8CA7B0A3A9B27D2600001369A6BBC7BB974509001066AEBBC8B5B3B57E2400000031849F877FA6C0C49A4A00001063AAC7C9CABBAA5B250000095593BCBDB4B3AF8D480E1655A4B6BEBBB5B9B5905D5C635B332F3C6D989799896A1E005A4C555E6CB8F4F0C1754F4437474E588AD3F3FFFFF9B762282B315893CAF1FFFDCC6F240C10133B9055C4EBCF854026251923376D8A8EAFC4A377442D2A36398AD3F3FFFFF9B76201FE5260070718207A592E160C0E25579CE1F1F3C7855F4F4C374C75A5BAD6E4DEC3792501001E81CFDAD3D1D7CCA45102000458A3BAC9CBC7B4938C4F211D6F93B3AEAA996F2824314A6E9AAAAAAFA8A97A2E00001471A8C0D0C9994900001463ABC8C6C4AAAD8E30000000388EA78276A1B2C5A04E1100105FAEC0C2C6BFA8551C01000D57A1B3BDB9B7AE8E430B12569CB8C2C2CCC6B582574F614B2B2D3D70909A998C6B27005351574C6ABAFCF7CD834D3E3C444D5B89CDF5FFFFEDB4572C27294A92CAF1FEFBCA6A240C0D0E3C8B55C7EBCF913A2719121241748B91B1D3C571412C2F363C89CDF5FFFFEDB45701FE5360070718306E42230D0C10295290DFFFF8C081584742445877A1C7D3DED9C2722100002186CFDDD4D1D7CBAF530100085BA1BAC1C1CDB39F87471A2C789AA5ACA79663352B304B6F979FB3AAABA8712800001169AAC4C6C3A24300001765A6BCBEBDBAB68427000000358EAA80769EBCC19E520E00195E9EC4CDCDC2A25F22000018559EB8BEBCB4AD95440F175693B8C4BEBABBB78555575B533941466E9198A0986D2300594B524E62C5FFF9C5804D313B464A5B8FDAFDFDFFF7BD5928222E5690CFF5FFF4C26B250D0609408C5AC3DEC8834328251C2242769590ACC8B17743372C2E3B8FDAFDFDFFF7BD5901FE5460070718407F51291B0E172F57A5E6FCF7CE8A5B504C4C5481A0BBD7E7DABD6C1B0000208BC7DDD7CCD4BDA65205000A61A0C2C9C5C1BA958A4E1C1B6AA8B5B2ABA1722F293B4F7394A4B2A7A4AF81220000106EA9C0CFC38F3900000E64A8C2BDC4B8B88126000000468DAD8B759DB8B8924505001464A7BCC3CBBD9E541D00001756A6C1C3BEBBA98F40062165A8B7C2BBBFC0B88A61586159382D4B7E989194816E27006058555774D0FCFEC6854B3A4350535892E0FFFFFFF4BA5C28232B5398D7FBFFF1C5631B1210122C8555CAE8D5843D2B231A1F33688B8DB0D2B16F442B2C323C92E0FFFFFFF4BA5C01FE5560070718506C44190B101B325B99DEF4F6CA89564B403B4B7BA2C3DCDDDDBC6D1F00001B84C3E3D8D9D2C6A85500000B5DA4BDD1C8CBBD95904C1F22679AA8B5A69864271B2D4F7290A4AFAAA2A3752000001576B0B8C7BD993900001767B2BFBBBFB4AA7E210000004497AA8A859FBBBC9F510B000D65B2C4CFCBC1A75B1D00001063A0B5B0B9B0B3933A161B5499B8BEC2C0BEB57B54576C573831467092948C906E1A005651555975C5FEEFBF7946464448475A9AD7F9FFFFF3AD59292A275697DEFFFFF5BD66260900003E965AC5EFD086421D1A242D3B7A8483AAC9B2724F2F373A3B9AD7F9FFFFF3AD5901FE5660070718607A43250F1C1F3161ADE8FFFACB83604D4C425288A9C1D6DBD6BD6F2200002484CEDBDDDCD5D7A7500000015EA0BCCBCFC4AC938D5115216F99AAA9B09A6C31293E476D94A8AAA8AEA0711E00001C75B3C4CCC38E3700001972AFC2BFB5ABB384280000004597A9827CA2B6B18F4905000F63A3BEC7CCBEA5591100001E6DA9BDB2BCBFAF9840081662A9C0C8C0BABDAF80554E655A37334472959FA2946F1C0051484F5168BDFFF5C4774F383E484B5893DBFFFFFEEDAD5328292F4C95D1FFFFEBC2662411070C3D9455CADFCE893D2023191838689584AACAC2774930272F3993DBFFFFFEEDAD5301FE576007071870723A1B1710192D62AEEAFEEDBD7B4E5440394786A6C7D6E4DEBF712100002B8CC9D7D3D0CAC2A4530100105FA5C6CFC3C5B99A994F1C266B93A2B1A793682B293D57709EA5A6ABA7A4761800001670B1C1C3C2882D00001B71B6BCC4C5BBB37E250000004395B085779EBAB6914A08001664A1BCD1D2CBA5551600001A5CA0B8B5C1B9A98342101461B0BDC6BCBCB6AE8A5C656A57303B52819F99979367180050505C5B73C6FFFBC9734E4B4D49515A98E8FFFFFFF0AB592A2C2F52A0D8FEFFEEC86721000611379B58CBE5D2833A211E1E2C3F70958EA9C7B26E432B30384298E8FFFFFFF0AB5901FE5860070718807240231F15173659ABEBFFFCB87F585749354D87AEC3D1D8E3BF64180000228DCFD9D0D9D1C2A74406000869A7C3CBC8C4B79E8E4F111F699EABA4AA9665302C4857749AADAAA8A49F6E1500001B72ABB8C7C8892A01001372B5CFC6C6B8AE7C170000004696AA7E6C94B4B7904605001264A7C7CCC3C3AA53140000256CA3BBBFBBBBAE87380D1663A3BEC3BBBABFB9885653715D3D354D74938C969C6D21005D4F4C5A70C1FFEFBD744A373B505C6099D9FAFFFFFDBD5C2F353762A3DBFFFEEDBF60180D080A2E9850C0E3CD7B391A1E16213F78948DB3CCAF73452E32323899D9FAFFFFFDBD5C01FE59600707189072451E140D142C5C9BE9FFF2BD7F65534D39568BB1C6C9D8DAB8631600002282C7DAD4CFD7CBA84B00000D61AFCCC2C7C0B4A08D59191E6A99AAAFAE99622928445B7792A9B7A9A69B711200001A76ADC5C9BD882600001576B3C0C5C3B6A07323000000499BAE837093B5CA94440800196FADBDD4D0C3A1571300002868AEBEBDC3B4A87C350B1866B2C4C5BAB3C0B683535D7449403A4D78979E978A6218004A4C505471C7FFFFBC704A43413B525D9FE3FFFFFFF4BB5C302B3A599ED9FBFFF8C4631B0202093C8C49B9E5C87E3B201F1F1C3E748F82A8CFBC6D3B2B1938409FE3FFFFFFF4BB5C01FE5A60070718A0734026221A264167AFECFFEEC57A5F5947344E8AB3D0E3DCD4C26D1E00002785C3D7D2D1D3CCAC4904001361A4C1CDD1C9B198944F22207298B1B2A5965C26273D5F6D92A7AEA09F9C751500001C7AB9CDC8BC831F00001A76B0C7C2B8B8A87A17000000459DAC8473A2B1BE8E3C08001068AAC7CCC3C5AF5A1400001464AFC3BABFC0B18035041D5EA4CBC2BEC2BBAE734D5D6D5F3F4854869A9898935A140063565E5F76C8FFF7B777583F464B5066A8E9FFFFFFF7B2582F2C3456A0DFF6FFF5C5632000000D469552CAE5C474371B14202140718E83ABCABE764C362F303DA8E9FFFFFFF7B25801FE5B60070718B077442C2E26233262B2EFFFFFC1835C553B355A9BB5D2DCDBDDBE6B1400002485C4D7D3DDD5C8A05100001A71A5B7C9CCCDB49B9151141F70A3B0AA9D91642B2545556C98A7B1A2A89A71170000187DBDC1C7C4852100001E75B9CBC5BEADAC6F110000004A97A27B76A0BDBF903F05001C60A9C4C5CAC69F480500002C73ABBCC0BEC5AE7D32052A70B1C0C4BFC3C3AB7553657D5A3B3B5679969B977D560E005B5B606A81CEFFF8B977534E54554F5EA4F4FFFFFEF3B25B313B415BA2E4FAFFECB85C2500040D3AA363CBE6C375361D1B1C24417A9B85A1C5AF6842292D364AA4F4FFFFFEF3B25B01FE5C60070718C0814C322826243763B3EDFFF7B4775E504D405690B5D3D8DACDB8612100003090D6E3C9D4CFBF9D460500166CB4C0C7C0C8B4A08A4E1D266AA2B1B0A98F58282547587E9CAA9E9FABA4671C00001973ADC2CCC0842100002585B6C5C7BEB19F721600000250A3AE80709EB4BB96420C001667B2C0C3C2BDA2500C00002373B4BEC9B7B6AC7A3408266DBCC5C3B9C4C1B2755360735A3B3D567B8A9198885909005A59565579CBFEFFC0754540484F5569A2E4FFFFFFF1A5563431405EACD7F7FCE5B0581B0501113C9C55C0E6C57A3A1D0D1823367A8F80A6D1B0674124343544A2E4FFFFFFF1A55601FE5D60070718D06736151E1B253160B0E7FEF7B8785C4E40384C84BBD6D6E7DFB7661400002F85CAE0CED0D8C9A24305001A6BAAC2D2CBC1A99597561C245D93A1ACA69C58252648557F98A2B3B3A39F651200002178AEC2C6B77E1F00002186B7C8CCBAA8AC751000000450949F7A6C8CB4BD8D3E00001265ADC5D0C4B9A0510900082F78B3CACCB9B6A6792D052879B2C9C6C4B1BAB0824F6171563F49557F949F938D5F0D005A5B606583CAFFF8BD775449454C4A69A1E7FFFFFFECAF54262E3C63A6DBF8FFE7BE5C1A060B0E40A756C7DEC47B3C221C141B45799380ACC8AF623B282F343CA1E7FFFFFFECAF5401FE5E60070718E07A4E261B1C253669B7F3FCF3B7785F5E533C5A9EBAD5D9DDD7B659120000288AD1DBC7C4D6C79B5309001671A5C2CFC4BFB8988A572D266BA3AFAAA18F4F262550597FA39DA1A8A9A25E1300001E7CA8B8C8B77F1E0000318AC9C4C9BAAEA76A0C0000024FA6A47973A5BAB48D3803002161ABC4CECFC4A1530C00003173ABBFC1B9C2A9762C102774A8BAC9BDBFBFAF774962795B3E4F6586909F8D864C02006B51585F79D3FFFCBF6F4D414C50546DAAEDFFFFFFF5A5512C343A65A4D9FFFFE9B14F16030C10449850CBE3C3803B221E1C1E457E917D9FBEAC5E3D2D32393EAAEDFFFFFFF5A55101FE5F60070718F07446221D1D273A76B6E5FEF3B275625F58415991BDD4DDDCC9AF5A1200002D8DD0DED2CCCDC79C4900002071A3CACDBFB9AC97895A272A6C98B1B1A78F5D2E37545A7F9CA7A6A4A190620E00001B82B7C8CCBB821B00001F8CB7CCCFBEADA0650E0000054C9BA875648EB1BD8A3605001E64ADC8D0CECCA6490400003480B4C4B8BDAFA678320E297DAFC0C0BFBBC1AC764E6C7A5D484B56779594978F520C005D5A4E547BD5FFFDC46D4548434A536BB5F4FFFFFFEEA65731323A68AAE1FCFFE5BF5A13010013409753C6E1C27F34231B1F23457C8E78A7C9A9623D2830393CB5F4FFFFFFEEA65701FE606007071800783D191B2126456CC7F4FFECB3725D5C4B385A9EBEC4D5DED7AD5F1800023A95D2DBCECECBCAA1470000156FAFC7D1C4C0AB98844A232B68A0ADB7A89452232B5B5A8095A6A9ABAF95560500002584ACB9C8B8751D00003993BCD3C2B9B7AC77100000015CA6A66F6C9DBEBC852D05021A69AED2CACFC597440000003585B8C1C4C0BDA86C240B237CB4C4BFBBBFC3B06F4C61765F424965868E8D8F805809006057595A7CD2FFFCAF6C44363E494C68ABEFFFFFFFE7AB47222E3966B4EAFFFFDFB3561900050A469F52C7E3BB65291C1F202D4E80928CA5C5A9663B292C2D41ABEFFFFFFFE7AB4701FE6160070718106637202422283B73C1FBFFF4B5765F67503E6499C3DDE1DED5AA5A1300003B9DCECCC2C7D7CDA34B00002B77B0C5CBC2BDA28F8D5B25387EA1AFACAF90542A2B4D618099A7A49D9E9B540200002379AFBCCBBD7D2300002F83BEC9C5BBB7A7680E00000753A5A66D5F8DBEBA883503022374AFC3D4C9C79B470200073F89B5C1CCC5C2AC681C0A2C7DAEBABFBFBEC6B564486676573F4B5F7A9099908D450000736C606A84DFFFFCAB6B4F414E545973BEFBFFFFFFF1A64E2D344569BCE6F5FFEDAF4E1B0002103BA24EC4DEBB632F1C251A204A8A8F7BA9C5B4664335353541BEFBFFFFFFF1A64E01FE62600707182072452A262430447ACAFFFFF1AE746560474163A0C4D9E4D5D0AD56020007379DD5D6C6C9D1CC9C3400001D83BCC7CDCCC5B094885B1F2A739AA4A9A884431F34535A8898AAB6B2A696560600002076ABC1C7B27A1100002E91BFC4C4B8B29F580000000A65ACAB7B6F8AB1BF873300001866B0C1D2CDBFA2490000043C8FBAC6C4BFB8A46A210D3087B8C3C4B9B9BFA5634B6C7F5C4D5B617C88938F874D0000585655587ACEFFFAB96A4F4C49474876C0FCFFFFFFEDA85B2B364067ABE0FDFBE7B14D1B02111049A14EC2DBB86C2D192021234E878F80A0C2AB6A402F323B44C0FCFFFFFFEDA85B01FE63600707183079402223242F457AC1FCFFF3B27B62674C445B9DCED5DBD7CCA4480900063A99D3D7CDD2D1BE953B0000227FC2D2C9C5C0AD90824619277C94A6B1A3904F2437505C819BAAAFB1AF9E55000000247BACBDC9BE760E00003893BECBC3B9A39B600E0000035FA0AE796F9DB2C58C2C00062167B0BFC9C9B999460000084690B9CAD1C7B79D62230B3B88B6C2BBB8BCBCA2664F6576604157668591938D843C0000675A57628DCFFFEDAE624C42454F4A72BFFAFFFFFFDFA853342F406EBBE5FAFFE2A8501902000C53A146C3DEB46B2C222523204A87907DA5C6A55F39222B323BBFFAFFFFFFDFA85301FE646007071840703B25242B2B4E76C9F1FBF3A6706367464161A8C7D4DFDAD7AF561100013A94D4D2BFD0D7C5933C00002C82B5CCC4CAC2A5968A5C24356A99ACB4AA904C2531475880A3A1A8A1AE974C0300002281B5BDC1AF6B1000003F99C9D6C2BDB09A5D0A0000095EA4A66F6297B3BA81310000216AADC8DBD6C5983B00000F499AC2CBC0BBB79B5319013589C1CBBCBEBDBEA26E4A6588604F626D879491917A45000065615F6589D9FFEBAC625F4842495576C1F0FFFFFFE7A1402C374574C0F3FFFFE1A4471600030D4BA64EC7DFB05F2B1F27252B4C8F8A78A9CEAA503C2D34333CC1F0FFFFFFE7A14001FE6560070718507952372A2C32417ED5FFFFF6A56B595D564769AED4DFD8D8CEA8540900003F9AD2D6C3CDD4C9963F00003178B2C6CDC2BFAC8F7F4D1E2D76A3ABAFA888432B3C5A688A94A9AEA49F8F480000002A86B0C3C9B770110000389BD0CEC6B8B19B5D040000075FAAA66C6497B7BE852800012A69A5BFC5CEC5954400000A51A1BDD4C0C2B09D5C1E154189B5C1BBB7B3BC9C60426E7F654A62728D9897907A440000645D5A5B8CDBFFF6AD60403D4E4F4C74BFF9FFFFFFE59C4F2F363E73C3EAF7FFE2984B14010A1148AC5FC9DFB0592B171E1823578F9582A0C29B5F3830353B47BFF9FFFFFFE59C4F01FE6660070718607A4F2E312E3A558CD8FFFFEDAE6F6A6A534670AACFD9D7DBD2A1450800003FA0DADBBDCAD5C7933900003988BBC9BDC6C7A28B804A1F2F7EA4B3AAA37F4F24395562859FAFACABA48D490000002E81ADC4CEBA6D0500003993CAD6CAC0AC9C5E0300000E60A9A7726991B7B0772D05002270AFCAD5D2C38D3700000F53AEBCC6CBC0B18C4C0E093D98BBCDC3BDB3BAA0614A6A8061456770828C9491813700006F68616D96DFFFFEB66F4D504B4D5985D0FFFFFFFFE19E50353A5280BEE4FBF5D9A0480901001255B452C7D7AB561B1A29213155968A75A0C5AE58312D332C3CD0FFFFFFFFE19E5001FE6760070718707541302F3236548EDBFFFFFBA86E68634B4975B7D8E6E1DCC99B4301001648A8DBDAC1C4C7C2903300002D8DB7CABBC8B7AA8D84481E367DA9B9AAA07B3C223455638EA9AFB0A2AB883F0000002B88BDC4D0B1670700004B9ECCCAC7BCB09651000000106EAAA9706095BFBF761F00002B6FACC1CAD1C295360000165B9DC0CCBBBCB8985711104CA1C5BBC7C0C0BE97554B797F6144576E818F8A95823800005B565F648ED7FFEDA361504A3E53587ECAFFFFFFFFDC8F3E30414B82CAEAFEF8D9A1441000001658AF4BC4D4995318151E16314F878C78ABD3994E3A2F272D40CAFFFFFFFFDC8F3E01FE68600707188076412B2B29335693E1FCFFEAAD736768474371BAE3DFDDD8CB99440400054099D0D6C5CEDFCF8E3100003C8BB9C9D4CCC19F897E44293B7EA7B0B1AB87402642576981999FA49AA08135000000288EB9C1CFB9700100004DA7C6CBC2B9B49B5E0000000A64AAA5756694B9B7792200012775B9C3D1C8B38A3A0000185BA9CBC5C1B7B6A04B0C074892C0CEC5C0BBBFA0543B69905D546E7788939294773800006C5B646C9DEAFFF1A365584947555D89D6FFFFFFFFD99844343E4E84C2EFFEFFE099440800001B54B544C2D9A44A2A1E201F29578B84639DC5A25A392C282B3CD6FFFFFFFFD9984401FE69600707189074573E3A3942579FEAFFFFF5AA716663544B71B0D6DFE4DECD9D4C0A001046A3DCDAC2C9D5B58D3400003583BEC6CEC4C9A88184552439859FABACA279351739636E8D9AA2A9A9AD8A2F0000002E81A7C3CBB2660000005AA8D2CECAB5AF99510000001E72B2AA75749DBEBF742100072D71B4D2CFCBB38B3B000025599CC0CBC2B6AA884003164F99BFBCB9BFC1BC9F5A4B74865C52697C8699948A722F00006F6673779CF1FFF8A869525153525A8DE0FFFFFFFFE09B493C435187C7F1FAEFD79D430B00091C5FB957C6CF9C4A171924292C628A85759AC19E54372B273A3FE0FFFFFFFFE09B4901FE6A60070718A074412A2C2E415C8CEAFFFFEE9C717066584A7BBFDBE8E2D7CE833C0900194DAACBD3BCBDC9C18C2A000048A1CACAC6C8B9A3897742284187ACB8AF95743B233B56638BA9AFAFB0A9842E0000002F87B9BFC1AB620000005AAFD7D0C5C1BD9B450000000D68B3AB81739DB5A9601300022973A8CCD3CAB7892A0000286BB5D1C6BBB3A181400B0E52A8C4CDC0BAC2C19E5B52767E53566F8085918B876E2900006A67686D9DE5FFE59A665B4C50556195DDFFFFFFFBCF84463C495590C7ECF7F2D398440500010A5FB850C2C493452D11151C30628D836DA5C2A15A40322A364EDDFFFFFFFBCF844601FE6B60070718B0764D313533416BA6E6FFFFEA936A676754517CB6D5E1E0D4C58B3A07011656A4D8CEB6BECCBC8328000A58A5C1CBD5CFBB9D827F4B243F789EAAB1A4662C1F3C596C9CAEAAB6B1AF802C0000003E89B6BCC9AA610100015BA8CBC7C8B8AB9141000000106BABAC7F659BB8B6691F000C357AB0CBCACCC28C2D00002671AAC2CCC0B8AC883A0A135A9DBFC6C5C5B9B1925A4F718C625E7E81909091926C1D000057545A6797E2FFEC956656424C4E6588E4FFFFFFFBCC793938455E9AD5F6FAE5C79739060000155DB24DBFC492511615271F24568F8374A8CCA3633D2B35393EE4FFFFFFFBCC793901FE6C60070718C07E583B3F484E64A8F5FFFFE6906A6C67545578C0E2E6F0E4C683290A00135FB4D8CBB0C5D9BD792700024AA6C9D6CDD1C49F7F6D3E294589A4AAA2915F2E22455B7397AAB0B7B79F73290000003592BDC1C0AF570000055AB2D2CFB2B4B6993B0000001876B2AA7E789EADAE621300012F74ABCED2C7B6833500002B7FAFC8BEBBBEB4843D091862A6C8C4B3B2BBB39855456C80575B7A818C8E948A702100006466646C95F0FFF6A265534751526693E4FFFFFFF0C97F3A383F5BA0D1F2ECEED0923F0600071158BC46BEBF8E44181724213473988C73A1C3A157322A2E3745E4FFFFFFF0C97F3A01FE6D60070718D06D453334344271AEEFFFFFE58E666765535C84BCE5E3DCD9B7802B01001D60B6DAD7BFC7D2BD7724000B529DC2D2D4C7C2917F6F40254198AEA9B3A2672D1B40546D92A4ACB1A0A77A290000004595B5C2C6B35900000562AFD3CFBFBEB49238000000217DAEA98178A0BAB46F1E00063077AEC7C9BEAA7B21000B3F7FB2C4CBB6AAAB742E08166AB1C7BABDADB4BB91594981855B55737E82898384691B000065676C7AABF7FFF1935F5558525461A7EDFFFFFFEAC27F3D344B65A9E0F8FEF1BF8934040000136BBB4EC0BE863D1218212B316793726DA6C29B5A37303E3C47EDFFFFFFEAC27F3D01FE6E60070718E068473233354675B3F4FFFFDA83696466585786CAF0EBDCD3C07B2F00001C5CB5E7DAB5BDCEBE7C26000E57A9C7CECFC9BE8D745F312057A0A7ABB08E5A2E234859738FADABB5A79C6E21000005509CBDBABDA1510200036EADC6D5BEC1B38F300000002373AEA38E7CA8BEA76114000D3C7AAAC6D5CDB27C230005368AB6C6C2BAAB9E6C2500105FAACAC4BEBCB8BD9858507D8458547A87978E90895E0E000071696564A7FEFFF1A66C5E52564961AEF6FFFFFFEEC37B35444E6CA9DBF0F3EABF7F320000001970C84FC2BF863419202321306B99867C9FBDA0563A31303540F6FFFFFFEEC37B3501FE6F60070718F075503947485075BCFEFFFFDE85676C67514D80C6E0DEDDDEBA73280000226AC4D9CCBBC7CFC57328051865A9D1D3C7C3B189686632295696B7ABAE8E521E1D47576987A9B1B4B2AB6C140000044F91B9BCCBAB4B00000975C4DCD0BFBBB3872A000000176EBBB6847FA4CBAE560F00114283B6C1C6BFAA701F0007479EC2C9BCB3B0A0621E002366ACCCBFC4B3AFB1855F527C7A526587898F8F89875C040000626F6567A2F2FFE8A2635B56475672AEF7FFFFFFE8B76D383B5271C0EDF7F6ECC276280600032471BE4AB7B8722A0F1A1E1C356F917B7EACBC945D3E3D333C41F7FFFFFFE8B76D3801FE70600707180073593D44465485C9FFFFFFDA82635E6E5C5B8BCCEEECE0D2BA6E2C07032369CAE5D6BAC5D0B46723002169B1C9CFCBD1C38A64522D295F9DBABEB29152242442517391B1B4B7B0A8671E0000064C91B8C9C7A74400001678BDD6D0BEB8A78235000000296DAFAD9A8BA2C2A34800000E4591B5BDCCC7AB721D0013488BBBD0C8BFB090530D072770B2C0C2BDB1B3B79151567F78505E8287869789825008000072645E75B1FDFFE98A67635B565B6DB9FFFFFFFFE3AA5A383A4C78B5E9FBF6EEC37F280000052175C74AB2AB762D191817202E75928680A5BC8D4D3F3C3F3B48FFFFFFFFE3AA5A3801FE7160070718106B453B37415580C3FFFFFFD97D5961675E6E97CCE5EAE1D4B56D280106266DC1DCD5B4C5D3B2601B001B6EB0C7CFD1CDBB85534D282966A2B3BDB7884A1E2649537294AAADB1ACA46412000008559BBBBCC7A3450000197CB6D3D2BCBDB58928000000237DB7B19A90B4BDA845000009428DABC3CABFA9661300185697BEC5C3BEA989541C002277B4CBCBC3B2B4B59F594A7A7D566283909F8D92814E00000076666A7EB9FFFFE68D695D54555378C9FFFFFFFFD6A05B35405280C7F5FBEFDABC752A000000287EC649B7B26529191320233277998178ACB58E5A3B3A3A3F50FFFFFFFFD6A05B3501FE726007071820765A433B445681CAFFFFFFD17C5B5F6462759FD3E7E0EDCFB45C1D0000317BD0E5E4CBD2D3B46A12001F79BACED4CDCCBB835A3D212A69A7B7B0AE843F1A29424F7592ACC2BAB89E5B0D00001055A7C4C7C4A04600001D7DBCD1CCC4C4B383200000002973B2B5A495ABAF914302000C4590B7CBCEBAA0671D001569A3BDC3B8B8AF884D0E00277FBED2C8BDB8B0AB8E585582755F6F888E96988E703B000000767E6F7AC1FFFFF2956D6E514F5974CEFFFFFFFFD48F502B3D638CC7E9FAF2DEBB6A1E0300023B93D350B5A2652E19181E284A79917674A4AE95583843453A58FFFFFFFFD48F502B01FE7360070718307464504648638FDEFFFFFFD3765261676E779ED9F3EBDCD0A051160011307EC9E7D5C5D0D3AD6016062E87BDD6CFCBBCB4805438142C72A0B9C1AB6D371928435372A5BFC0B9B6A254010000286CAABEC6C0913000002986BDD0D9C9C3B280140000002B79ACBBAA91B1BA963900000F548FADBFCDC5A35B13031E74ADC4C2C2AF9B764008003389ABC2C0BCB8BBB791585B8281556B8D8A8D8C86743900000070696475BFFFFFE3815B57504D5C89D8FFFFFFF6C588533E394D96D4EEF8F2E1AF6C210700054095CF4AAB9B5F21130E15203C83947B82AEBC8347384441485AFFFFFFF6C588533E01FE7460070718407E504A4D4E6390D4FFFFFFCE75535B637084ABE1E9ECE1D7A4531500003585D0E6DACBD5D4A65A0401308EC5DAD7CEC5AF643E321C2A79B4B9BFBA792F17204B5A84A1BBB3BBC293480000001F70ABC0C5CB912F00002894C0D5C6C3C1AD75220000003282B0AFA1A1AEBE933700001B4C8AAAB8C1C3A15B18002178ADCDC3BFBD9F833003003B8CB3C5BCBCA7A5A48A5E55867257698D8F968F8C783800000076787482C7FFFFE58D5A5950556286D7FFFFFFF3BD774B34435C93CFF5FEEAD4A6641C0001094AA1D84FB19A512314171A26447E8E818EB3B07C4C3B45424063FFFFFFF3BD774B3401FE75600707185070525450476597E2FFFFFFCD734F56686885ADE0E3E9E4D199440900163A8EDAE3E8D8E1C89E4A08093D8DC3D8D2CCC8A55E3C24152E82B4B9BFAE78351A21404F7BADBABDBDBF963E0000003183B8B3B9BD813000003194D3D6D4C5B7B079190000002F85B7B8ADA8B9C2973B0000155093B3BFC9BD924B08012B82B0C3BDC0AAA16C3300003C8FC0C3C3B5ABB1B595535E837D5B6A8A8D938C8370300000007A808091D0FFFFE4945C635057578CDDFFFFFFF0B9734A3342619ED3F6FFFDDAA657170000084AACD140AB9149180C1423233E849A8784A9A682493A3A4E496FFFFFFFF0B9734A3301FE7660070718606E5D4D4D4F679DE2FFFFFFB9695057717C97BFDCE7EEE9CA92360D071B4A94DAE9DED6D0CF94400706379DC5DBCFCAC3A468311D113887B8BBB3A77137272E3A547CAAC1CAC9B286360000002B87B4BCC1C3882900003998CFE1D4C0B7B173130000002E81B7C3ACAEB4AE8B3000021A4B8DACC3C5BC9E510E002B7FB3C7CAB6B4995F2300003D88B5C4B6C6B7B8B388545A85795366888B8F88816E2400000874727A8BDBFFFFDE895F504C536191DAFFFFFFE9A76C392B365AA5E2FFFFF7E49E571103001357B0D94EA6904C16130512294B94987D90A29F6D514053554F67FFFFFFE9A76C392B01FE776007071870785F52505E71A0E6FFFFFFBC69535A5E7E9FC1E4E6DEDFD3933C0A000E4495E2EDEADCE4D490300005439DC3D1C9C9C6A25529190A398DB7BAC2AE7938222E414A769DB8C7C4B78B3A0000002E7DB4C4C0C182240000419FD2D9D3C3B8AE70150000003781B6C2B8ACB9B6882600001B5890B5C9C3B891480609438FC0C4C9C3B68E521F00094FA2BFCDBFBBABB4AC7B4B5C867D557591989792876C25000012767A8797F4FFFFD5885852584E6190E7FFFFFFE4A96C40313A519DDBFFF9F1D0A05B200000145FBBD34AA7844316080E1C264F87927883A89B704B45514D4975FFFFFFE4A96C403101FE7860070718807569575F5E77A7F6FFFFFFB76A5653678FAEC7EAE4DAE7C78334060B154FA3E3EFE6D8D4C08931051453A4D0CDD0CABF9D4F2108103894C8CAC5B973321F2A3A46799CBEBFC3B386230000003687BBC9C1BD701E000047A3D4D8DBC1C1B06E130000014880B2BFB9B4C0AF7A260000295897AEC1C4BB8E40110D4491C1C9C3B8A88C4C0700004E9FBCCEC3C2B4AEA4724A557B79617F98A2A09684682000001072697592E1FFFFD08A61544F545797EAFFFFFFE3A15A36334058A4E7FFFFEDD59E4C160005206EC4E0479D873D192018182A4B85847989A7946F4D49505E4D7EFFFFFFE3A15A363301FE79600707189071666A61647BB4FEFFFFFFB2624B507298BDE2EADCD9E0C4772F01001857ACEBFCE7DEE2CE7928001753ABCCCDCBCCC597491B000A499BBCC1BBB47C3D2E373D497EA8C0BBD0C684240000004187B9C1C5BC691B000048A6CFD3C8C0C6B5690900000B478BB5BEBFB4B1A6661C00022B668EB5C7C2BC95400D164097BAC8C0AFA98640000008569FC3CCC1B0B1B0A27D525783755F7F9497989091691C00001B7A777799EDFFFFD0805E535458609CEAFFFFFFDD9161372B3D5FA6E8FFFFF0CD9B53190000227BC2DB4B9975431D18201E2B4F898B7E8E9A8B61514458565280FFFFFFDD9161372B01FE7A60070718A0766750545878AFF6FFFFFFA7624E4A6EA2C6E1EBE1E4D8C5722B00091556ACEAECECE6E4CE6E1D031D57AECDCECECFC2903F10000D4EA2C0C2BDB36E3B31332E4274B0C1BEC9BF85260000004F91BCC7B6A96019000858A7CCD9D1C2BAA95E0B0000085395BFC4C4BAB797661600002B5F98B7C0BCB5883808145197BCC5CDBFB17F3A0000195BABC1C1B4C0B5ADAA78515A807956809E9A948A7C4D0D00002371666588DCFFFFBB724B4B4752648FE3FFFFFFD28D54382A3154A7E6FFFFE7C88D4C15070B1D7EC7DA4E936B340E101620295B958A7990A48564515058624E8AFFFFFFD28D54382A01FE7B60070718B06C615665657CB5FAFFFFFFB159484D77A2D0EAEBE2E4D8B56B20000C2C59AEE9F2E9E5CEBE6B1B071A5DAFCDD0D2CAC388400400214CA5C3B7BEB07846343528407DB3C4BAC1BA7517000008519AB1C0BCAC5E18001265B6DAE1CFC9B9A95D010000134E8EACBCB5B1B4A0641B04032C679CAEBABFB48134101557A1BCBABDBDA0712700001468ADC2C3B8B4B4AE9C6B4A6480725D8C9FA599937B4F0C00002C73747CB2FBFFFFD47D4D43515A5C9DEEFFFFFFD1844F2E2B3F5EABEEFFFFE8BD8B4A1602001D8BCDDE51906B31170E1A263055908C7A8B8979624C43565C649BFFFFFFD1844F2E2B01FE7C60070718C06B57545F547BB2FCFFFFFFAA584A537BB2DCF3F1D7E5E0BE712200081F5DB5EDF0EFDED8B96414082369B7CACDCFCDC3813B0000094B9DC6C2BAAF72524B3C334682A8C8B8C1B87419000010549DBFBAB0A04B0800176BB7D4DCCBBEC3A35600000016589CBCBDB9B3C09B4F05000E3C719EB2B7B8B57D2F102667ABBAC2C0B89D6D3200001D6AA8BEC4BAB1AEA69D6C546F857B65829295978E7D4C04000036706A71A6FAFFFFC3665245515065A2F4FFFFFFC5774E39303956B1F6FFFFEABC74410A0D093684CDD151896C31141326232F5C8A84828C9478524F545E5E5B92FFFFFFC5774E393001FE7D60070718D072686264658BB9FEFFFFFEA45845537EB6E6F7F5DADBDAB7642502052C6CB4EEF6F1E4D0AB5414092B75B9D2D6E0D6BF802B00000155A2C0BFC1BB7C474933313C86B4CBC1C8B26B0D0000145A9DC4C5BC994A07001A6EBBD8D6C7C6B6A854000000155A9EB3BAC3C0B8905205000F387DA3B8BCC2B4762E092861A9B2B7BDB8A2632200001472B6C4C7B7ACAEB6A76C426485725A839A9D9D997B3F000000347A8187BBFFFFFFCE705549484F5EA7F3FFFFFFC678442B2C2C61AFFCFFFFE3B2783C1601042B97D2E0498D69360F1122203366958472939271514C5460605C9EFFFFFFC678442B2C01FE7E60070718E073716F73758DC2FEFFFFFF9B5E4D5989D3E9FFF9DCE0D9B1611800062169BEE8F3F3E7D0AD551B072985C1D6DBD0C8B36F1D0000115998C2CAC8B67F524D3D28408CB7C5BBC5AA65020000135B9DC0C0C197490D001F79B6DAD8C9CDBB9742000001225794B2C0BFB2B690440F00074B87ADBDBBC3B071250D2F70B0B6B5B7B699681300001E77B4BEB8B2B9B8ACA460486B897364839DA6A3957244000008427B8289C2FFFFFFCC784A4E49505D97EEFFFFFFBC754631313664BCF7FFF6D9AF763B13070A3C9CDCD844895A2C12151C1E3660967A7C90866B56485162646EACFFFFFFBC7546313101FE7F60070718F0796B6570798CCBFFFFFFF3935F48578BCDFFFFF7E4DDDCAC590A00052D6DCAEAF2F9EDD8933F0E0B3587C2D3CED3C7C1782100000A5FA1C6C3B9B6825C5A402E4189AEBABEC2AC5E0B0000155599C5C2C19B380200267BBEDCE0C9CBC29F4A000000295A9CAFB3B8ACA6813906001B538AB1C7BCB7AB6920152D72A9B0B1BABC99591100003885B0CCC0B1B0AEAC94583B6B8E776187A6A59398753800000B42626B7FC2FFFFFFC2703C3F4643559CEEFFFFFEC4764E37353D61B4F8FFFADB9F612C0C061147A7DCD34B88542B13172220306C967B788F8064524851555D66B7FFFFFEC4764E373501FE806007071800756D6467708EC4FFFFFFF69E5B40589ADDF3FFECD7D5D6A95A1D00092A6CBDF1F8F2EEC88836050F418AC0D5E0D9CFC36D160000105EADCFC4B7B579625431223E88ADC9BCC4B15C0200002070A3BAC2B68C2D07002877C1E0D8CBB3B892410000003A6A9CB1BBBDB0A77C310002215B8FADB8BDB8AB631D013580AAAAB1C3B798531200003887ADBCB9B3AAB3AC8F5E436C8968669DB7A49D937B3B00001C4D7D7392D6FFFFFFC2733C3A474864A3FAFFFFFFC17D422C313B64BCF1FFF7D1975F2D0D0D1048B1E5DD4B815C2C17131A1F2D6E97837F8875574D51575A5F6ABBFFFFFFC17D422C3101FE8160070718106F736D6C7E94C7FFFFFFEC904B3E599FE4FFFFFEDEE3D9A34F1700072A78BDEBF0EDE0B8862C050C5294C1D6D9E0CDBC631000001F64A8CEC6C5B087665235274088B4C6BAC6A45B0000001F68A4B5C7B6813400003480C6E2DACBBBB9A03F0000063D7096ADC4CBB199712E000427608AADB5BABAA1621D164180B6AEA8B7B99A400000003D86B2B7A9A1AEB1B48F5E4568856A6D8FA7A7A593733200001A4F7D7F9BECFFFFFFC6755945465766A9FBFFFFFFB87149302F3769BDFAFFF9DC985927140E1151AFE6DD487852231518212D397696737479725E5048545D6074BEFFFFFFB87149302F01FE826007071820766C6A74859FD4FFFFFFE38A4E415C9CE0FFFFF5D7DCE4AB571500112D77C2EAF8F9ECBE7422010E5AA1CADBE3DCD3BC6F1B00001D60A8C1BBBDB97E665A39294691B0C5BBC8A0500400002077ACBFBCAD78320000388CCFD8D3CBC4BD923400000B39729CADBAC7B39A6E2C000B31618BAFBFC4BA9A590E0B4483ABA8B4BDB990410000003593B7C8A596AFBDB68D4E4A667C726FA1AAA6A893682300001953696B8FE3FFFFFFB66F433E3F425BAFFAFFFFFFBA733D26243764BCEDFFF0C88D492F1211255CB0E4D9447C5121121213233B769778728871564D4F4A535D78BEFFFFFFBA733D262401FE8360070718306E6768747B9DD7FFFFFFE08B494262A5E6FFFFFADDE0D9A24C0E0507327DC2EAF5F4E4B96B1E00195FA7C9D7D9DBD8B8640E0000145FAFD4B9B5AB8672683D293886ADC5C3BCA3510000002C779FB0B4AF6F290A094391CFE6DCCDC1BF8827000014508D98ACBABAAE9C5E2101102B6E8EA5BCACA6924C1219458CC2B1ABC0BB8B3C010002468DB7B0A1919EB0A783523D768C8482A1ADA59F906E1D000030607985ABFDFFFFFFCA6F4B403D496EB1FAFFFFFFBA7242302B2E62C4FFFFFBCA7B371E12101454AFE6DA4973482D19141520377A997B7B7E766248595B616974CCFFFFFFBA7242302B01FE8460070718406F6B687C7DA1DCFFFFFFD9844E4162AFF0FFFFFADDE0D9A0460C010A3973B6F2FEF0D3A96212061C6DA8D7DFD7D6C6AE4C0700002C69A6D3CBC5B68167613B254E8CB5BEBEBA9A48030000327BA5B5BBA96C26060F4A9BDAE2E3C4C1B5891E0000124D819DAFB9AE9A88581C00083C76A6B4B6A8B09141191C538FADA3A5AFB1833800000C4E9EB8B09D91A7AEAA7E40436F907473A8B7B1AE91681E00002B64807FA4FFFFFFFFC1734A404B5666ADFFFFFFF7BC6B3D272A3565C4FEFFF3C37C422417161A61B0E3D54C75461B120E20333E7D9472747A67544752526B587BCFFFFFF7BC6B3D272A01FE8560070718507F6C677382A3DAFFFFFFCD8649455CA7EDFFFFFFE3E6DC914310001A3A81C2F0EEEFDBA05214002871B1D1E1DFD3D0B4570200002D73B1D7CBC9B17D704F34244D8FAFC0B9B4AB450000003579A0B7B5A55D12000D4DA1C7E1D7CDD0B7772300001855809FAEB3ACA287541B06184880A5B1BBB2AF8F4C121D5298B4ACAFBAB4752E0000065999AFA9958EACB2A881454A6F866B7EA6B8A9A6915F1B00003367727DB5FFFFFFFFC174453A40545CB8FFFFFFFDB96F3E2C263569C3FFFFEFBB79432A0F121D66BADCD341653A1B1B232A2B45838E6A78775D4B4E5F575A6A8ED5FFFFFDB96F3E2C2601FE8660070718607E76706D769CCDFFFFFFC9744E4660BCFFFFFFF9EADFD792410100103D8CC7EEF4F2D390430D092971B9D7D9D3D9D7B14E0100002A6DB2D0CEC2B881825E2A1E4A8AB2C5C2C39D3A0000002D78A8BFBBA25B180D1653A2CCD9D4C8B9B47F22000025648596A2B0B09D774513021F548EB2ACB5B1AA8A41163059A1BCA0AABCAB73280000135B9FB19E7884A4A9A2683D467B907479A3B5AFAC9B671A000032718385B8FFFFFFFFC8734A43444D6DBAFFFFFFF5B76D3B28263C71C6F8FFEBBF7939250A0F1F65BFDBCF41693B1F130C1F31448CA06E7B7D5E4C4B5853576897D9FFFFF5B76D3B282601FE876007071870706E6A767AA4D8FFFFFFCE78414962B0F7FFFFFBECEAD19346120317488CC8EDEEEDD78E370000268ECAD3CFD7D6C9A94A0000002E73B1CECCC1B07C6F4C2E234590B3C4C1BF96460000013C8BAFB9B798570F000957A8D4D8D1D3C6AF711700002C7195A2A7ADB58E67340001235D8BADBABEB1AD833B0D276CA7BEA8A7BFAB64210000145CA8B28E7782A8B7A4673B4A73847684AEAEA9A5904B0B00003E707B88C5FFFFFFFFBE7448333B466ABEFAFFFFF3AE6C46332E356CCDFFFFE9B07036150B0B216FC8E9CF4262371C0F192228418E957273705A4544535353669FE6FFFFF3AE6C46332E01FE8860070718807574797A8AA8DBFFFFFFC771404266B5F7FFFFFFEAE9D88B33010019478BD7F7FAEED4833400003396C6DBDCDBD6CB9D3C000008347FB6D2D1BCA7746A4C2E205991AEB5C0C593400000054188ABB3B495510C051F66AAD0DAD9C5BCA86C1E0000357196A2B9AEA3885A2609072E6392B0B5C2B3A77D330D2D70AFB99EA6B09E6A2200001D61A5B38E7389ACB3A965393E7D8D7B80A8BDACA99F500A00024275788CC6FFFFFFFFC2683D363A4F6FC5FFFFFFF0B4713327282A6AC5F6FFE5B4652B1300052176CCE6D3446A3C25151D252C518F9671786759544A494E506090DDFFFFF0B47133272801FE8960070718906D6C6A7A8CAFDCFFFFFFC56B3F4A6FC5FFFFFFFFF0E9D58C3E0A001B4B86CAF0ECEAC2702700063998C6E4E3D2D7D09D3500000E4688C5D9CDBCA9715B4025245E9DB4C5BCBC7F2E0000074A84A5B9BC964A0D0A1D73AEDDE3E6C6B2B1650700003E7C8E9CAEAFA27C4A1D060A336CA1B4B5B6A79E842F093D7BA3BF9CBABCAD602000002168A8AE87767194AEA761334372888393AEB8ADA8944904000C4C716286CCFFFFFFFFC15C322F3B3F71CAFFFFFFE9AB6638272A346DCBFDFFE5AB662D120F0C257ACEEBCA385A362414092024508B927374775942404A545067ADF4FFFFE9AB6638272A01FE8A60070718A07774758889B5DFFFFFFFB9664E4A64BCFFFFFFFFF2EBD7923A05001A5390C8EAF4EAC66822000B3B9CC8D2DFE2D7CA923A0000124A8DC1D2D5C5A370634D2223589CACBDB9B484300000065099ADBDB58C4407012C7BB9DEDED3C5C5AB5F010000467D979FAFAB96683A12031047759FB6B5ADAFA46B29093E82ABC0A3AEB0A253150000307EB4AA7E7078ACBB9755304A7B8D798EB2B7ABAA92410000084B777296DBFFFFFFFFBB714336404C7CD0FFFFFFEBA7693C251D2A77C8F6FFE3A25D2A0C0A1C206FCFE2BE3554341C17161F3C578F906B777557434D4F515368B0F0FFFFEBA7693C251D01FE8B60070718B07170737B90B9E9FFFFFFB067474B6AC7FFFFFFFFEDE6D6933904031D4D96D5E6EAE3B55A1D00053FA3D1E1DDE1D9D89D330000195486BACDD2B59269573E1A1F65A4BCC8BAB46D1F0000144F9FA4AFB2943F05052A7BBDDAE5D5CCC5B667060000487FA0A9AEA590653304001B4D89A9B6AAB3A0A06725194890B4C4B1BABE9F541600002574A8A87B5F70A1B49F5B355072878CA0BCB9A9A58A3F00000C5B7E6D97DBFFFFFFFFC06B3C32334689DCFFFFFFEBA5703325273A7FC7F8FFE3A564250703001A74CFE2C5365431190D1D2432619A8A7886805541404A525874B9F2FFFFEBA57033252701FE8C60070718C0717678828EB3DBFFFFFFAA573B416DC6FFFFFFFCECE8D583360505215D9DD0EAEFE5AB4D1200004EA8D5DEE3D8DACD8E2C00001B6092CED4C7B08E6354321C1D6DA3BCC6C2B972240000175E9DB6C4BE8A3600002C89C3D7DCD8CCBDA24C0000004C83A7A89E9D905F270010154D86A6B3BBBCAFA5671F175486BEC2A6ABB2A45C1100003081B7A46D516DA3B0894B35486985809FBDC7B4B38E3D0C0017578072A0E2FFFFFFFFB26138393A5387DBFFFFFFE6A36E3C292A3575C2FCFFCF995928140C15227CCDDEB939522C0E09131B345C9998808B6948394548566677BAFCFFFFE6A36E3C292A01FE8D60070718D073747A9299B4E4FFFFFFA95E3E406FCFFEFFFFFFFEF1DA7A360E0A1E64A0D4E0E7DBA34C0E000849A6D1DDD6DBD3CB7D2300002969AEC8D5CCAD875742291C2768A3B8C6BFB2621A0000276FADBAC0BA8B390005348FC1D5E2D2CFB7A44B00000B5B94A0A79DA3835116000023578AB1C4C5BEA697611D1754A6C2C5B3B5B7A1500B00002D7B9B905744689CB38D4F344B77938A97B3BDB5A6873D0600225E7A83AAF6FFFFFFFEB6683D37465694DAFFFFFFE7986A3E21253977C8FCFDD58D5B1B10080F1E87B6DEBD3A552E1B18111E2A67989583917750433D4B564B77BAF8FFFFE7986A3E212501FE8E60070718E0777C798499BAE0FFFFFFA760424779D3FFFFFFF9F2ECD37C2B120E2E619ED1F4F1DB8E420C000C4EA9D2DFD7DBD9C27E2300003473B6D2D2D5AD745238240F2678A3C5C3C2B76F2000002A75A5B5B7B5762800033B8EC6D8DED8C8C3A049000000569AAAAAA9A480321000001C649CBDBEB9A69F8958221A64A3C6CBBBB8B5933B0800003989B491563E5FA0A9854F334D788F99A5BBC7C1B4893C000010638881A8F3FFFFFFFFAC6238343A4F98F5FFFFFFE89F5F47221E2D7FC2F1EFCE8C511D10070E2A93D5E1B12D502A1E1A1821396BA29582926F48443F4249456DC0FCFFFFE89F5F47221E01FE8F60070718F076818092A1BDE5FFFFFB9857333F7AD1FFFFFFFDF8ECCA76370B0A2C68ADD9EEE8DB983500000E52B3CCE2DFE1DDC1791C00003A7EA2C4D1CC9F6445280E003780B6BCCDCAB1581100002F76A5B1B1B87B2B01164E96CAD7DDD4D0C3A2460000105892A4A4A79E7D3203000023719FC3C0C1B6AA88551E1A5FB0C9C9BEBABB95531400003E849F76443B5EA8B58D45344F738D959DB9BBB9B186350000296D7D83BDF5FFFFFFFFAE623D3937609BF2FFFFFFE4936C46312E3C8AD4F9F7DA88380A140A0C2A87D0D6AA364C29170412293B6FAB9A8295754F44434A4E5A79C4FEFFFFE4936C46312E01FE9060070718006C7887969FBBE9FFFFF09850333D78D5FFFFFFFFF5EDCD83380C182A64ACD7EAE4D6923400001856B5D8E5E0D8C8C3741400003382B5BBCDC7926E3C2A0D042E82B4C3CDC3A6610D0000367BB4BEB9B77E26001658A5CCE4DEE1CBB8943700000C5A9CACA8A09B732D0000002972A5C2CEBBBBA97C5117216AA7CBBFB6BCB58C3E140005468BA180483C5D9EAE874B2E4870959BA4B9B7BAAC81310000246A8678B1FFFFFFFFFDAF5F3931395BABF1FFFFFFD9966747231F2B78B8F1F5CF8E4926180C09338DD7D9A3324024161422262E6CB097899474473C3A444E527EC9FFFFFFD9966747231F01FE916007071810757589A2A5CAF1FFFFED8A533E3B79D4FFFFFFFCE2E9C3732D0D183776BCDDEEEACE872A00000651AFCFDDD4DCDABB6113000A4990B6D5D8BE8A4A2E210A0F358BBEC2C2CBA84B0A00043D7CAAADC1BB7F2E020D56AACFE2E4E2C1C1983B00000967A0A4A39493691B0000003283B3C2BEC1B39E7C3E19276EB2C6DAC3C3B58D431800054491A27D434371A9AF8649304E6F8794A4BDB6AEA67E32000034737F7EBCFFFFFFFFF39E5D4033446FB8FFFFFFFFD4946843291F3479D2F6F3D2833816130D0F3D91C8D0A43447250F131F2E397BA99285966E4A3A353845518BD8FFFFFFD4946843291F01FE926007071820767A849CACCBDEFFFFED863F35477ECFFFFFFFFDF9E9B16D2A0C1C3888BDDFEFDDBE812C00001366B9D6DEE4CDC6BA721000004795C3CBCBC39652250C060C2D7EBCD5CFC3914E0B0011488BB4B4B4AB6D2706225FB1CEE2DEDDC7BB88320000185E9EAE9B9F966C1C0000053789B9CBCEBCB59C7E360A2C75B2C1CDC0B9B78A4123000C5297A3643134559EB2814326466D8CA4AFBABEB7AE7123000033728272A9F3FFFFFFDE9F5432283E6FC0F7FFFFFFCD94603B2624378BD8FCF2C972330A03090D349ACDC29A3540241A101C273D78AAA18D9A754D393E52545B89D5F1FFFFCD94603B262401FE9360070718306B778AA0B1BBE4FFFFDA844630487BDAFFFFFFFDEFD9B35A210F174680BADCF1DCCA7F1B00001E6AB6D1D8D8D0D2B6630F00035197BAC6D6C084401E0F030D398ABECED1C09E4E0B00174C91BDB5C0B7661B001761B9CDD7D7DAC6B8852C00001561A1B8A596925C160000003A91BACCC0B8B79F722C0F2E83B0C5CDC5C3B9803A12000D5795A56D2F2A61A7B07A3D2A3D6F8F9AB7CEC6BAA47824000C3D7E898AC3FFFFFFFFE8A9592A234A79C9FFFFFFFFCE8A673E28233C8CDBFBF2CC723415131210479DC9C89B312C1F211C1B2B4181B29E959D7C3F333141414B87D5FAFFFFCE8A673E282301FE9460070718407784989FACC3E8FFFFDF7F4D3D4677DFFFFFFFFEEFE5C168290F163F90C7E5E7DAC3782800001D62B4D7D7D6D5C5AD5F09000A5C97BAC5C8B979350A00030C4599C0CAC7C9A03C06051A5697B9B6C2AB6B22041C67BED7DCD8DBCCA8741B0000236E9BA49D9B935A190000094290BFC6BEC2BF9D7838103C86BEC9D1C4BEA87D30110518569A9B6633245FA9AB703D304964819BADC6C6BEAF7521000D39748481C3FFFFFFFFDB9E6439374B87CBFFFFFFFFCE7B583A2225398CD3F9E7C57432110B0A0E409BC2BE97323F27141C21274C9EB79F9EAA7F4B333B45495A9ADDFCFFFFCE7B583A222501FE9560070718506F7988A2B0BEDCFFFFD7805431407FD9FFFFFFEEEEE6B65D201920458CC2DEECDCBB721D00002170BCD1D8D2C7D0B04E00000D58A6C8D1CABB6B1E0100000F4493C6D2D2CE963D00001D5E9CBDBABCA45C16012974BAD4D7DCD4D0B1671600001B79A4ABA49A86510B00000C5197BED5D7BDAF99642F133585BECCCDC5BDB2703612001265A5A76322345299B674382F466292ABB8BDC7BAB0731D000F47839185CCFFFFFFFFC9945B33374E9BE0FFFFFFFAC37A523E2B1E4B90DFF7F0BD692A130D0B1D50AAD1BE902C422E251A1724468FBAACA29D6F3F353536454F86DFFCFFFAC37A523E2B1E01FE9660070718607E8BA9BBC4D0DBFFFFD8824A364D7ED9FFFFFFEFF3E2B2511C122A509ED2E9E2DAC26A1B00002675BBD8D9D4D6CEAC4B0200135FA5C2BFC0AF6916000200184D9AC7CED3BD833100001E69ABC6BDBEA8621B032A76BBCED5D6CAC2A36A0A0000247AAAB7A6A7924F020000124E9EC2DDCEC1B0945D1F0B3D86B6CED4CBC5A4623215091D69A79E60232063ABB27C3B2D406398B1BCBDBDC0A7601600205A848F98D3FFFFFFFBC67D493839519AD9FFFFFFF4B77A4E392E1F3A99DCF7E0B0702B120B131D5EABCBB8892B352C2213212D5CA1C9A8ACAA6F3E353241435393D7F7FFF4B77A4E392E1F01FE9760070718706C7A9AAFC3B7D0F8FFCF7E372D447ED4FFFFFDF2F0DBA552201727549DC8DFDCD5B25C1200023985C3D5D9DBD5C7A14900001D5FAECBD0C8B05D19000000114C9CC4CDC2BE88290002287AB0C4B9BAA2501008327EB6D3DFD9D5CAA8640E00002277A6B2A39A8D430700001757ADD2D2BBB5C29D561C114294C0CAD7D4CBAD6930120B2D6E9D98501E275CA2A56C342B416796B4B2BBBDB7A36E1A001C5589938FD8FFFFFFEEB97C4C3336549DDDFFFFFFF7B771614430234C92D5F3E4B664260B09080F57B1D2B77E37351E1E1E212E56A2C1B4ACA26F413D353F4A5396DCECFFF7B7716144302301FE9860070718806E899EC6C5C3D7F5FFBD6F41324775DDFFFFFBEFEEE7A7541E153568A9D7E5EEEAB0580E00002A85C7D9D6CBC5C7973C00002071A8BECCD2BD640F000000154F9ECBD0D1BD7C270000277CAABFC0BE98531B113679B4D7E4DBD1C0A0570E0000348AAEB89D9D96450000000F60B3D3DCCABFAA8D4E130B3E8EBFD2CCC3C5AB64301A1325759B8C501D275B9DAF6A3421346DA0B3B7BCBCADA26318001C5D878F93DCFFFFFFEDB48343362A56A1E9FFFFFFE1B771482F2121459CD7EDDEAF65270E0B10246FB9D1A87E373727161C1B325DAAC5B2AEAC6E3528313F4B529ADEECFFE1B771482F212101FE996007071890708BAEBFCBC3D2F3F6B2733B274381D4FFFFFAEADDCD924822213C6EB7D6E0E3CEA44E0900043387C5DAD3D0C1BD983400001F6CB5CBC8CCAF600A0000000F4D9BC1D6D1BA852601012D83B9C7B6B6974F1501357BC0D5DEE3DFBF92470400043E84AFB79F968A31040000175DB5CCCFBEB3B2984E120F4A8FBFCEC6CAC3AA69381D0F3278A58F47232963B5B26A2D2A34679DB6B5BFC6B79D52110014578D92A4E9FFFFFFEAB9764E2F3956A9EEFFFFFFE3B1794C3831294F9BDDEDD8A9591B100C1B2E6FC5CBA36B2F30211A1D29336AB6C7B6B5A9703C3036394F5699DDEAFFE3B1794C38312901FE9A60070718A0768EA9CFD3C0C2E9F0A96E4A2F4087DDFFFFFBEEDFD1A04D20274771ABD7DBDCCE98480400003987C2D1D4CDD2CC902A0000267DC0CFCECAB258080000000C55ABCED0D2C0701E00053686C0C6C4C28E4A0F093990CAD3DFEBD4C08C38000000388BB0B5AFA784340000001364B9D6D3C3B9B59353120F4B93BBD1D4D2BB9B52331418387EA9944D232E699F9E652A243D5B9CC4C4CBC1AF955B0A002C6794989EE2FFFFFFCEA66E43352B58A5EAFFFFFFE2B0644D4A332B4EA5DEF3DEA1591D030509257EBBC19B613136242B20232F6CB3D0C3B79D6238334344445297DEE0FFE2B0644D4A332B01FE9B60070718B0758AAEC3D8BFC4D5DCB66F4034457CD6FFFFFFEBDDCB8D41191F3E79B7D4DEDFC58C4603000B3289CCDCD7D3D3C4812A00002A7EABC2D1CFAF550C000000165FA6D0D5D1B56B1A0007388DB7CDBDBD8F3F120C3A8BC2D5E2E7DEBE8333000009458DADB9B1A98A34000000116DB4CED1BCB8B186401419519CC4CAC8BEC19A522E1713417BAC9E4C1B376CA3A5592D243F6CA2B8BFC7C1B7A94E0300246998919BDCFFFFFFDC9F6C4530335DB0F1FFFFFFEEAB634B41262450ABE1EFD9994A20080E14347FC5BCA16432361E20211D3A7AC1D2C9BCA861392826353B509CE1EBFFEEAB634B41262401FE9C60070718C0778EA7D1D0B9B8D2CDA15A2E263E75DAFFFFFEF7EBD99845251A4279B3DBE8DFC37F3804000E4A8DCBD0D2C6BEC18E1E00002B7DB9CAD0D1B04D00000000185CACCFD2D4BF6A1A000E3C9CB8C4B7A27F381103418ECDE4DDD7DCB879390000004997B7BEB0A583330000001F64B9D0DAD5C2C08835061B57A5C5C9D5C3C8934B3423203785AB92471A356F9E9C5D281F3866A1BBBABDB7B99D4F0508266A988E95DAFFFFFECD8B623E2C3862A8F5FFFFFADAA06447392F2959AAE0E6D2944B120B06144584C5C3895E2E2E2120211F427FC8D6CCB89B6139323241515697E1DAFADAA06447392F2901FE9D60070718D07591B3D6DDC2BDCAC49460362F4480D1FFFFFFE9E8C9874326335087BBD9E1D4BF85390200114997C8CDD6D0C3BD841B00003A84BBD1D6CEAD52000000001462ACCCD2C8A86E1600063A8EBACFD0AB812E0A12539DC5DADFE2D1B5772C00000B5395AABAC2B77F270000001E6CB7DCD8C6C5B1853E0F1458AACDCBCBC5BB92502017163991B29649223676B3A95726213E76A9BDB6BEBEB385430308246C949A9FF2FFFFFFC28A613C323866B8F1FFFFF3D9925C4D48302F5FB4DFEECC8E4A1A0111124490CCBF83592A2A1C24242E4889C9E4CCBCA66232283134495D9DE2E4F3D9925C4D48302F01FE9E60070718E07799BDDAD9BFB1B1BA88542E293A79D4F8FEF8F0E2C07B3F24315695C0D9D9D2BB6D2C00001F5A9DC6C6C9C9CCBB7D1600023F86BDC4C9C8A84A000000002264B3DAD2C9A96312000A4291C6C6BDAC7E2C030F4D95C7DFE1E4D9B3691C00000C5B9DBDBBADA7822E0000001F78BFD6D7D1C2BD893806135A9BC0CCD3CEC08A42261A1F4484B48F4F223570AEA45625143A71A0B7BBBCBDB48F400008377F9897A7E5FFFFFFBE7F563F28325EBDF3FFFFF5C9925740402A2E68BBE5EDC88F511C0B0E183C97D0C38A512C3327221D2E5093D1D7C2AD9C61373733373F55ABDAE6F5C9925740402A2E01FE9F60070718F07798C0D9CDAE9CABA5774B3825427DD7F4F8F4E7DDBD7F3F29386993C4DCCECEB3782000001858A9BFCACFD6CDBF7C1800003D94C5CACBC7A84E000000001D69B4CCD1D19D500C00073E8CBECCC9A9712801114BA4D1E7E9E2D8A75B110000135A9CBAC4C3AA77220000002377C3D7D7CCC1B88E400C1C5EA3C3CCC5CCB6793D23101E4490B08E49263D6AA69E5F24233F73A4B7BDBFBAAB8A3D000638798E91A6DFFFFFFFBB865836343360B2FFFFF7E1C49A57403B33366EC8EEEBC685482419171C4EA1D3C284552B3222261A345E9DD6E1CBAB9053302E2D374665AFE3D7E1C49A57403B333601FEA0600707180078A0C7E4DBBAA59897714C332D417CD7FAFDF9F3E2BD7040234374A6C7D2D3D0AA5E1F00001D61AEC6CACDCEC0B5741200003796B9C4BBC9AE57000000001E75B2D9CFCFA5560D000A4789B9BAB89B6426061758A4D3E1E9E7DBA954190000125EA8C0C1BEAB7D210000002368BED5D6D1C3B570280C2B6EB0D0CECEC2B46A351B1C264E8DAC955231497FA9914616123C73B4C2C4C3BBAE883700003D81A393ADF5FFFFFAB78366503D3161C0FBFFFFEFC2804A3C41363A7AC5EBECBC7340120E0F1154ACD4B5824B2C2C1F30222E5BA4DFEACAA78B493C332C31506CB4E7D2EFC2804A3C41363A01FEA160070718106595C2E0E1B39497845D3A2924397EDAFFFAF7EFE0A574372D4373A5D0D8DEC698550D00002562AEC4C4C2C5BBB3721400034C92CCD3CDC8AD41000000001E6EBAD0D7CD9C470600003888BDCBBD9B6520071361B2D7DDE0F2DAA2480F0000256DA6BCC4BCB274160000002A76C2D6DEC5B5AE7B29101B67ADC8C6CBC4AA683731211E4D92AF9346294883B2954920213C71A4C1BCBEB8B6842C02093980A297A8E9FFFFEFAA7A524A3B3B6DC2FFFFFFECB48042343B2E3C7DCFE8E7BD7A342718081A5EB1DAC57C3F28202423243772B4E0EBCDA7895B302E2F414C64AFDDD9ECB48042343B2E3C01FEA26007071820789BD1EFEAB39385764F3922223E7ED4FFFFFFEDD7B06A2F234C7CC2D0D9D4CA975A10000935669FB9BCBEB8BCB16B0900015095BED6CAC7A34B000000002878B0CEDAC79D42090003448CBAC1BA9B591C001564B2D3E6E2E1DFAE43090000296DA7C1C5B3A66B240000003484C2DAD6C1BFB57127001E65B0D0DDD2B8AB6F39281E226097B2925C334686B19237221C4780ADC1B8BBC8B27C2D000038799690A9F2FFFFF8B4815E4F423462C1F5FFF8DFB082533B3E2D478DD3F1E2BD7B3E23110F226FB5D6B16D3E26272629253877C1ECE9C59D78463A3236384767B3EADADFB082533B3E2D4701FEA3600707183080A6D4F2E5B6997E6A483322244283D7F5F8F1E8D19D643431537DB1CDD8D6C38F411100163C78B4BFB8C6C7CEAD610B0008529CBEC4CFC19B46000000002278BCD2DBC58B420000053E97B3C7BB88481100196DB6DEE7DCF0D797480800023474ADC0C1B6A66B230000002A85C7D0CBC8BAAD6F21112975B2BACBD1C7AF62292E27325F91B1955A385090AA8F42111F4983ABBABFB3B3A3742E021B4D709B94A3E6FFFFE8A67C5741333A6DC8F8FDEFD9B280463A41334788D4FBDFBC75391F0D172F6CBBDAB56E362A211A1E27406CB6DBDFC090764834302D454A6BB4EBD0D9B280463A41334701FEA460070718407CA2D0F1E4B1866D6340241E214386D6F9F6FFEFD0995A2C295490B7D5D3D6C18E460600174977B2BFB9B4C0BCA85A08000B5BABC3CDC5C69E48000000003186BACCCFBE893C000001498AB6B2B586471B0F256DB5DEE3EDEDED9C380000002D7DB9C6C0B5AE6F170000003183BBC5CACAB3A467240C327AABCFD3D0C697592A28222F6293B19B5E3B518AAA872B10225587B7BDB5BCB3A3782500103D809893A2E4FFFFECAF7E5541393B6DCEFEFFF8DCB0784733353448A5E2F7E9BD74341D1D1D3376C1D9B5724A322C201D213D79C8DFE0BC9671472E332E373E69B4DFCCDCB078473335344801FEA5600707185075A4D8EADFB0875B49231A111F3C79D9FFFFFCE7C8945D3F2E5D99C1D7CCC4B57D360000144985B8C4B1C5BAB5A85B06000B5BA7C0C0BFB69E4200000000348FBACED6B87E360000124E83A9B2B3924612062D79BBE1E7E2E1D9993500000B3B83B7C5BDB7AC69190000043C86CCD1C8C2BAA466210D397FC0CDD0CDC2A5502D2E282B5A96B9955C436499AF7D3311104889B7BFBAADAFA07A2500104A7F9290A3DDFFFFF1AC6C54433A3E73C8F5FFF1CCA76E3E2D2B224F96DCF7DFAE6B3A211A2B3684CED4AE703A362A232B223485C6E6E5C694634233292C3A5270BEE4CECCA76E3E2D2B224F01FEA6600707186077A6D5EADCAB795036271B181A4084DAFCF6F2E2C18755333A6799BBD2D7D2B2772D00001E4A87B7BFB1C3C2C3A74B00000D65A0BBC0BEC89F36000000003686BDCDCABB6D2D000009478FACB9B4803D1111297FC9F0E8DBDBCF8B310000094386BCC9C1C3AA6C130000073882C0D8CDC2B89E5F1E053C7DBBD7CCC7BCA559262B312F5EA2AEA4634F74A4B9833511184D84AAB8BBB2B3A26C130018547F9683B6D7FDFFDB9A6C4C402B306DC5EFFFE0C0A06D3F342B2A51A0E1F7E7A45E321F22213C8FCEDCC370381B2524261D3F8DC5EDDFB58E65492B282E394877CAECC7C0A06D3F342B2A5101FEA76007071870719CCBE4DAA573482E1B0B19204383CEE6E5ECDEB97D4A283473B4CEDADBCDAB631D00001E598EB3B6A3B5B6BB974300000A65ADBDCFCFC6983C000000004598C2CFCDBC6D2B0000164E88A1B19F7B3A0F0C3489CEE4E6E2E4D79B2C0000154E8DBFD1BEAEA5610C0000003A91CBD2CDC7BD9D4E200F398BC1D0CBC9C2A04823202430719DAC9759426CA2B6832E08184D89ADBFBDB2BDAD651100214F849583A3E0FFFFE7926549412C3976CEF4F6EBC1946233343C3454A5E0F2DAAA69322A26304792CFDEAF6C3733282328233786CEECDEBD835D3B2E333B3B4F7ACBE7CCC1946233343C345401FEA8600707188084A4D4EADEB27C4D29181A2027498CC9D8E7EAE2BC7F40243576A8BFD3D1D0A15C2100023168A3BFB8A4B4B8C19C3A00000D6CA7C8D0CDC0983300000000409BC0CDCAAA5B1D0000184E889EA8A471350C093B8BCBD5E0E0E7DF95260000155993BEC9B6BAA55C0B0000093991CCCDC8C8C29E551F104996BCD6D5CCBC804822282E3A6CA1B7A26C52749CAE792609214D86B2B9ADAFACA66417001F65919684A5CFFBFFE2966B42383A396DC5EDF6DCB7815A3833292B58ACE6F2D2A05D271D293A559CCED6AA66383A251F232F4492D0EDD0A6795F452B36323A4A7BCFEBB9B7815A3833292B5801FEA960070718907CA9D2E0D9A5662F15000713204387D3ECEBEBD9A76839323D7AB0CACECEBC984F1600032E74A0BFB7A3B3B3B18B3400001F70ABC1C7C3BC8D30000000064C9BC4CBC8B3621E000026567D8E9F9F62260B073899D8EFF0EDE2D9942F00001B569CC0C4B6B89F53020000133890CAD2D1C0B68E4E11145097BDCFCED7C1823C211D2F3E72A6BCA15E506C97AE7A280D0E4684B6B9B6BFBAA661130022568A928298C0F0FFE19B665142393F76C7ECF3E2B77C5C4339354163ADEDF7E3A5603526223E62ABD8D8A85B332B241E1E1F3F94DCF9E0A66C54443A342E3A5289D7F6C2B77C5C433935416301FEAA60070718A07EAAC2D8CCA66C2C0F04051220447CCCE1E2D7CA9A603E314883B5D0D0C7C5AA5D110002346D9FB7AF96AEBBBB8E370000126AACBEC7C7C6902F00000001489CCCD7C99B58150000225576909CA16F2B0B0E41A1DBDFEAE7E0CF802300002465A9BDC1B8BC9F590A00001A5291BFC6CFC4AF8C481420529BBED7D2CAC18A39261E22417AA5B09B654A80ACB472220D19588DA7B2B6BEAD9A611500235A888C7B9ECCF8FFDA99684546384177D5F4EBD8B576522A3734496CB4ECF1D29C58332A203B67B0E0D7A45D2E261C1D2A264FA1E4F1D8A56E53442E2D3142528DC7E6C4B576522A3734496C01FEAB60070718B07AAAC8D6CCA6783306000006214B91CDE0D3DACC9E62422C3C8FC5D3D1CDBF91430A0006407BB1C0A9A0B0BAB1873200001B7CADC0C9BAAF9031000000094F9CBECCC5A1531000002860758A97925A1F041050A9DDEAE6E8DFD2801D00002965A6CCCDC2B89F4D020000115397C3C3C0BBB4873E121C5E9DC6C9CBCFC890372420273D78ADAE9D7C5B789DAD7821041B5587AFC3B9B1B297501200255B8694818CB8E9F2CF8F6C4C37364280C5F1E6CFA87D502D2C2E407BC4F1F1CF8F522D23254873B0D8D1945F2E282029221C47A2E5F0E1A4674F4B3839333D548AD8E7B9A87D502D2C2E407B01FEAC60070718C079A1C7D7C8AE6A26000000051A4D93C8DBD8CBCB9E53302C4680BDD1D4CAC28F3F03000A4581B4BD9985A9B5AF7C2B00001973ACC0CAC6BF862E0000000A58A2CAD4C2994B0C00001F648886988D5A1D001A4CA1D7F3F7E7E6D57E2800042072B0C8C1B8AD993F0000001E4C9CC9C7C0B7AF7E4314195BA7CBD2D4D2B986382620294777AEC0AA6F54779FAB6B1900175B8EAAB9B5B0B2965313002D739D916E99BCE5F8D89E6C4C40394783D5F3EECCA272492D30333C7BC4F6F4D79857272E374E7DC1DFCF94491F292E2F282448A1E0E9CE9F664D4743323038548ED6E8C7A272492D30333C7B01FEAD60070718D078A8B9C7C1A46520000000001C4790CDD9D7CDB38852302F4993BFCBCDC7B983310000154A8BB4BCA087A2B2B1751C00002685B9C2C3C5C57C270000000C62A5C8D5C394440800002C65857F867F521A061852ADE7FFF3F3F3E2741100002876B5D7C5B2B39D480500001B50A0CECBB3C1AD813613205DABC8CCC5CDB88235161C274589B0B79369537DACB06F1D011F628FA3B1B5BBA98A4E1606396F898F6899B5E6FCD2956950463B478CD2EBE7D2A169483033373E7FD7FFF7D1944A2A27365D87CDD8CB8B47242B2D2E25264DA8E4F7D28B4E494B37342D3E529EE0ECC0A169483033373E7F01FEAE60070718E07698B7C2BA985B11000000021B4793D2CFD4D5B2794229264594CAD4D8CAB378280000104D93BAC99D84A2BBAD711A0000267EBBC8C1BFC47D200000001F65A8C6C8BC8C3F0500002D6F977C897646170A205DB8EBEDECEAECD27D1900053780B5B9C1B7AB8F480200011E4696CEC3C2B8A9773D1F3067AAC6D3D1C7BD7B311B17253D85BDC6A8706883A1B86510001E6A97A9B2ADA79D874203003875948E6893B4E6FBD59167453E373E84C9E8DFC291633A28322D5094D9FFF6CB7F4D2E283D6997D2E8C9823F222D2F2A1E2450A8E5F4DE924F4B503D2A2C4258A4E7F5C091633A28322D509401FEAF60070718F0729FBBB8B6A55F12000000021B5997C2D5CFD6AE6D32231E3D8FB8C2BFBFB580270000185B92BCC19A87ABB3A8681300002980B3BBBECDBB76240000001971AFC6D0C990320000003C7890817D714318041C50B2F0F9EEF6ECCC7A140106458EBDC4BFB1B08F3F00000021539CC8C3BDB59A652A15286DB2D3D4CAC8C4782E1B22214A87AEB99E705C7CA0A66B1E061F6197AFACABA9B2944701094077958C608CAFE1EAD7A05E453A384A89C9D8D1C298613B2929324A91DBFEFBCD7F3C2A25336FAAD4DEB8784125342D332D215DB6EAF4D98457525B4338333D56A0E5ECBC98613B2929324A9101FEB0600707180078A7AFB3B3AE6118000000001951A2D2D6D7C9A466371A244B8FC4CDC8C0AE7723000321629FC4C6997D9DAF9A5D0900003683AEC1D2CABA6F22000000176CAEC9D0AF6F27000008307D8488786E3F12102260B9E6F5F8EDF2C9761B000F3C8FBAC1C3B6B09438000000335FA0CECCBDB4985D280E2C6CB5CCCCD4C8B86D301C1A1F508BB0B2996B6482AAA75B14111E6597B1BAB3B7A8813D00084483A28E5C8BAED6F4D8925E434043529ED6DDD5BE915B3B3936375398E4FDF8C27E3D222A4386B8D9E3C87A331934272A1F275BB5EBE1CC84484756463834405CB0E8F4BF915B3B393637539801FEB160070718106F89A4AAA4964F08000000001D589EC1C6C6C5AA5B221829519CC5CED3BFA6681B00002769A1BFBC977D97AC984D0000003185B7C5BCC4B1731B0000002478B1CAD3AA712900000B478A957671604411082A61BAEAF7F3F7EDBE6315050C458DBEC6BDB7AE903705000A34619ACEC4B8B8A4561D0B3170B2D0CBCCCDAF70271819295195B4B8926F648CAAAA630B051E6F8CABB8AFB2A37F30030C50809A82538AA5DCF1D5885F40373A549CE1E2D7B9855943262B2D54A7F2FFFACA7F38221F458EBBDDE1B6732D122926291C2E6AC1F3E8C8794A46594F373C3B62AAE7F0BF855943262B2D54A701FEB260070718206D8F9CAFA88A5308000000002E5E9EC5C7C3BD9254241519499EB8C2CABAA35C1B00002E75A4BDB8978397A7894A0000003688B8C3C7BDB07217000000307CBFC8D2B36E220000104C8E92736F5F3611112968CEE3FBF7FCE8BE681A031D5699C3CEBEB9AF7F2F0000082F62A3CFBFBAB38E531C103481BDD6CBC7C7B1681E101014568FB9AE91675F89B5BA6A1603236999ACA6ADB4AF7938091151869B85527F9AD7ECD3905C3737364C98D2D6CDB98F673B272C3158A5EDFFF7C978412C1E3986BBE0E5B4652D1C312C1E22286EBDEDF1BF7C444765514140396CB2F2F4BD8F673B272C3158A501FEB360070718307B98A0A89F985B07000000002868A3C8CDBBB78D491810245A9ABFBFCAC19A580E00003479A4C4CB9F7B9BA082340000003488B4CDD5CEB365130000003890C4D0CBA65C1700000B56A19C83835D350E001E62C8E6F6F5F4EAAF5A1100044899C6D0BCAFB38A320000103A6FB3C9CDB5A481471B114184C1D9D5C3C7B366240A07194E93BEC19363608CABA15C17072F709FAEB2ADB6B0772F091A5B85967F508297DDE5C2845339343C5A9DC2CFC9AE8157332224365FA2E5FFF5C47E4421253F7FBCE3E3B56C291E3B2938253971C3EAF4C97C363F645836333A61B1EDEDC08157332224365FA201FEB4600707184071938F989784450000000000245E9AC5BEBBA98D471C131E519BC4C0C3C0A4560F00003784B1C7C298739EA5762B000000448DBCCACFCCB3651B000005398BC4CEC3A151110000094D92978179542805082479C5E5F0EBEFDFB55008051657A4C7CDBAB6AF7B2900000D4172ADD1D0C7B692440F103B7CB1CDC7C1BF9E5D1F0C121D5293B8BA98736088A9A6591C132E79A4A9BAB0ADA3701D001A5D8F9B794C8CAADBF3D98C60423C3662AFDDDFC5AC84553C36323E6FB6F8FFEFBD6F3421213D8BC2EFE1AB60260F35291F202A73CDF4EEB971455875653A293470B5EBF1C484553C36323E6FB601FEB5600707185077868B908F874C0000000000266AA4BAB7B5B1842C05061F6198C4C5BDB19447010000398CB1C5B9928096A775240000024990B9C8D2CDB55E120000083F93C0D4CB9F420400001A62A4A47F734D271008256AC4E3EAECF0E8B059100922649EC9C5B8A8A4792D00001C437CB6D3CEC6B483410C1A488BBFDBCFCAB9B5601402091B58A0C0B692696294A6A0510E092D779CAEB6B6AEA2661C0A27638C9A72478398D1E1BC8250373A3E6AB5D8D2C3A275523020253B68B8F5FFEDB76C3117233A93CDE6D9A759261939332E2C3477C9F2E9B9723D587A613E3B427AC5E7E0BA75523020253B68B801FEB660070718606F878F8F89823A00000000013A6F9EBEAFB1AA7A3003031A5BA3BAC1C3B383320000004794C0CEBD916D88926D1B0000093F93C4CED3D2AC530900000E4694D3D9CE95420000001859A8AD8A704B210C063380D0F1EEE3EBDCAC4B0C0D2468AEBFD0B7B99F732A00001E4A7CB2C8D5CCAA79400E16528EC3C7CCC9C0A75E11000514519CBDAE97736B8BB09C5612133F87AEB6AEAAB0A1611502226A939C75487E97C1E2C47A493932406DB8D8C9C29B6A49362A2E4570BDF5FEE8B4672A1E264491CBE6D5A2522717402127192F7CD7F1E1B26733527E633B3A3F79C6F0EBB96A49362A2E4570BD01FEB7600707187077848B86897F3F0000000006397EA0B7A8A0AA7C2C02001061AABDBFBAB6853700000945A1C4C6C5937D8998690B00000E559AC2CED4C6AA601C0000104C9BC9CBC98B420500001F6BB5AD8C66401C000A307BCEE6EDF1E8E29D460B03296BAFD5CAB6AB9E691F00001B4E8AB0D2D8CAAB753F0913559DC5CDC5C6BB9C4B0C0005195C9BC0B2976E6690B8A14708053385B0B2A6AFA4924E0F032A6D9AA2814A7E89C4D6AB6D41342D3E6BB8CECAB8916A3D26242A3D7BC3F9FFEBAF6131202F4797D6ECCF8A42201040282C2C3986D3EDE7B36130537665442F4286CAEDEABA6A3D26242A3D7BC301FEB860070718807E9183958B7F3D00000000014882B1C2ACA7A3662605051F60A3BEBDC5B074280000005AA4C2C6C397748886500200001565A3C2D2CFCBA7550D0000195AB4D4D8C58C320000001B6CA9A28A74410F0B0D367BD3F2F2EBECD090350F06206AA7D3C4B3AD9D6A1C0000285C88ADC7D2C1B4772D0A175491CDCBD4CAC39C4409010B19599DB6B2986B6D96AE8F4002093E88AAB3B5B4B5914808012C74939E7548749CC1CAAB623C272A487EB4D2C8BC926132202B2C3E80CAF9FFE4AD612F191D4BA2D3F0D394411B1A432C23233F8DE6F8DEB560315A7D673A334781CDF3E9BB6132202B2C3E80CA01FEB960070718906E817F7D796D2B00000000054B87A5B4A096975B0B00002869ADC5C3C7AE6B190000075F9FBAC1B9966E8482410200001557B7CBD4D6C49D481800032558A8C6C5C1863B0000002A6EB1B297783A0B020A3A85CAEBE9DDD8D48837050D2C73B5D0CAB8B59C671600002F6997B9DED8BFAB6D3013215998C0CACDC1C2A3520A00091C4D98B5B78E6C7094A29147090D438CAEB6B6B7AB833F09002E7198A58146849CCAD5A9663B32384B80BDD8C4B78B5C34252B2B4187D3F4FFE7AE612C1C213C93CEE4C882411E13452D23263E94E1F6E6AA5D3752766A31324586DAFDEBBF5C34252B2B4187D301FEBA60070718A0818C8A8B7D7238000000000B5394B3B4A098955E2200001E68ADC6C2BAA8672400001862A6C3C6BC98848C7D420000001D64B6D5C4CECA9F480F00092A68B0CDCBC181370000002275BFB490642908000E367ECEE9E8EADDD2862E0310398ABCCDCEC2B69856110001386FA3C1D0CCB9A26B2B0C18559EC1CFD2C6C696440D00001052A4B8B89A777191A992420B0A4196AFAFABA7A5833805002C7093A583507B94C0C294532B1F243C81BACEB5A68959321B1B204187C8F6F6DCA95C2B161A4599D4ECCA833610114D322B314498E1F8DFA6543851776644314389D7F2E5B959321B1B204187C801FEBB60070718B0707C7D7B766A2E000000000C5691AFB29F9C93570B00001B6BABBCBDBAA9681D0000186EB1BCB3B28A787B71270000002D6AB8D3DFD6CCAA491800002D6DA6CBC9C17C220000042D79B5B7A37336080004378AD1E4EDF0E9CA7E251113368CB7CBC5B7A9905C18000238739BB1C8C9C9A65C1D021A679EC4C4C5C1B99B4318000019589DBCB5976C64A2A48B3800115094B0BEBCB2A97B400B08367599A28A54809CBCCA96532B1F24578AC2CBBFAD7E4F312B22243D86C5FCFFE9AC5E270C1145A4D6E5C276331314572E2C26499EE9FCEAA7562C57806D3D2D3E8BD2FAEDB74F312B22243D86C501FEBC60070718C0707C7A796C6632000000000B538FADA99697954D0100001E7CB1BFC6B79D570A0000186FB2BFC4BB9878706324000000337BBDD1D4D7CCA04F12090D337BB1C7C9BD77250000002787B9BDA175340A000A3B93D0E5D5DDDFCA742608163986BBC6CBBFA389400F000D357DA3B8C6CAC69E6117002263B4C6CBD0CFC59A4C030000195595BDB58D7376A2AD8837040D5499B0B2B3B5AB792900002C7FA2A38C5C8B9EC0C5865030242A5C95B8CCB7A77D4B1E2119214B90DCFFFFE1A9622E181948A1D7E3BA6E2F150B51342A2950A5E3F8E4A358365773623D2D3E99DCEDE5B94B1E2119214B90DC01FEBD60070718D0757776747B6924000000001C5F98ADB3A2A7984F000000357DB2C7C2B78D490B00001877B9CBB9BA976C64571A0000003983C2D5D2D3C1A14A2017173972A8BCC4B8782D0000003A83AFBDA27A310B000A4392D1E1E2DAE1C1741E10193785BFC7CFB6A183420D000A3D83ACC6D0CDCEA55F11001F6FACC4D2C7C8B79542090000155AA5C5C0A1797399A9822F00155FA3B8B7A8B09E671C00002E79A5A3855A7FA2BBBC833C22202F5B8CBFCCB59F7B3B24151C1D4492DAF8FFDC9F522E1F184EA7D5E9BC692A0E1D5734293153A5E7F9E0A1543859745E37324695D6F4E4B13B24151C1D4492DA01FEBE60070718E0788079807D682E00000000196CA2B7B7A29B8F430000002777ADC4CABE9E440000001C73BAC4C3C09D685C4A0C0000003787C0D3DDDDC99A411613204784B4C6C3BB721E000003428AC7C7A87A2D0400124D98DADDD9DCDCB55E1A051F4284B7D5CEC3A1733F0B000A4890B2C1D1C5C3A65012062F72B0C8C7C2C1B785350100000E54A8C1BB9C8170979A792B041B62A0C9BFBCAE9C631100033D89A9A6935C82A5B6AA74412319265A98C3CEBCA26A3B2419222948A0E1FFFFD39644230B1C4DA1DFE2B668291215542E2E2A5AADF8FADD9D4F2A4F7167422F49A3E7EBDDAA3B2419222948A0E101FEBF60070718F0746B70797A671D000000002B6BA2ADB0A09295430000002C78B3CCC7B783330000001E77BCC6C3C49C685232050000004096D2E0D0D2C996461F1F24528AACC3C2B7711F00000B3893C2BFA5762D00001852A3DBEAE3E5DBB55B1708273B89B7C8D0C0A8682D0400114C92B2C2C0C3C29C550E012974B5C4C1C5C4BC98350100001C58A0BDBA9C787D9E9E6E2B071B5DA5BECABFA792511100003E8DA8AC99648BA7B4A3732E1600265997BFC3AA966C3C12151D2356A7E5FFF4C98C492013224EA9DCE4BD661E0B075732282552AEE8FEE1A4472C4F695D38354B98E3FEDFA33C12151D2356A7E501FEC06007071800707D726C715E1D00000000276CA1B3AF9DA08438000000317FB8C7C9C080320000002284B6C6C4B98D69492B000000004C9FCBD4D9D2C8944C201B2D5A9AC0CEC4B5701B00000A539BC7C7A56C28000012549ED5ECE7DFDAA4500B1027477EBCCBC8BC9E5C240000104B94BBC4C9C8C9A75417022978BCD3C9C5C8B98A340000000E5198C2C0A78D909E9B6523001567A3BDCDC2A8A0561000064992A8AC905D8799AEA263291C0C205998C1BEB3956F3A211C19255DA3E9FFF8BF8C3D1A1B1F5CB7E0DFB15D2305075E3B2F294FACEEECD89453364F6D65373751A5E4EAE0AB3A211C19255DA3E901FEC160070718107676777B7F6B1F00000000377AA7ACAFA4998632000000327DB6C7C4B87521000000218EC8D2C6AD8A58442400000006519FD4E4DAD2BC8441271F336B9CBDC2C9BA6F1900000F4F96BFC4AB71220000175D99DFDED1D7D4A4571207325293BFCEC4B890571B00000F5B90BBBFC3C4C19C520F0C3884B8D4D1C5C2B2812E0100031C60A0CFC4A88487948F601C0821689FBAB8AEB094530200044D8EA6B19D6976909B86511C120015539BBAB5A29765301A10121C54ABEBFFF6C2813D0D0C154EB2E4E6B0571C0B116939223256ACEAF6D29441244169633E2E4CACEEF5D7A6301A10121C54ABEB01FEC2600707182068736F78795A170000000027729CAFB0A79F7E2F000000267CAEC0B6B680240000002183BCCFC5B8965936190000000253ABDDE3E8DDC28B381D2C3A66A5C5C8CBBF6C1000001654A4BFC8BB681C04001D67ABD9E6DDDBC99F420D0C24518EBFB8C7B996431200001E69A9C3BFC4BEC89C500D0C3783B9D5BBBCBFB07E260000042164AEC1C89986839A925D0D002C70A4BFB6ACAD874302000A4F9CA4A29B6796A7AD995E1C090F265C9CBCBEB19A66321517152A65AAE9FFEABE7B42190C1B53B6E1E0AD5B200811673E2D2B5AB1E8EFD5953E1F3D5E58423561B2E1F0E09E321517152A65AAE901FEC360070718307C76727D80602D00000000417CA6B7AFAA957B370000003289B0BFC7B26E1B0000002B93CDD3C2B5915D27040000001969AED9E4E7E8C58A3C262F45799CBAB3B8B46B0A00001861A8B9BDB06C2700001D5CAADDDDD2DCCC9D430A12315090B8BDBAAA85420F00002168A6B9BBBEC5BF925412053C83B0C1CDC7C3AF7F330000001E5FA6BBBCAB929CA27E501200317AA9C1BFAFAB8640090007549CA7A8966E8A9CA48D50150200145696B8B4AA89602318121C2A57B8EBFCE7C17D330F0D205CBFE9E6A5511409106533293565B9EDF5E1954C2F3B4F4B383958B2E9F1D2932318121C2A57B8EB01FEC4600707184074746C6E6D551A000000064B86A1A6ACA2987D230000003088BAC3CAAF5C0B0000002D8DC8D5C2BC8F4D24010000001663AFDEF0EAD9C17A3C29355081A8C1CBC3AD611600002367A8B6BFA96C1D00002971B3CFD8D9D7C58F3D1715385A91BCC4BEB48E460F00002C75A7C2BEC1C1BF943E1302388DBEBDC3C5BDAE7A26000000186AA6CABEAB8F8E9F834808002982B0BEBAB0A4843B00000C4C94ADAA9C777A8C907236000000085694AEB9A7925925060514205BB6E7F6DEB1712C0B0B205FB4D9DDA1480B0611733928285FAFE6F4D59A492838524E36335CB6F6FFD99625060514205BB6E701FEC560070718506E767176735210000000004B93ABAFB5A8A2851E0000003C86B3C1C0AE6403000000238EBAC9C4B18E5422000000001B75BEE2E8E3E3C37C392D425B80B2C4BEB7A95C0A00002A76A9C0C2AF6A180000215FB0D4D5D8D2BF8D3A1023465D98B5B1BCB47C2F0200013279BABFB7BFBCB79243110C4090B9CAC0BFC2B16B1D0000032A68ADBEB6A7939097743C1307367FA6C1BAB0B0843E0000185894A6AAA07593A1A07E3B0B00000D519DBBB6B6985225170B1C2A6DC7F8FCEBAC682C1A12225FB6DFDE904012081274342B3161B6F1F9D78F4029384F4E3E426DBFF2F6D9A325170B1C2A6DC7F801FEC660070718608084787E8361260000000B5885A4BBBAA7A0761F0000003F91ACBFB8B85B08000000309EC5D4C4BD8B461C000000001D77C9E7E7DCDBB8743835536B8FA9C2BCC3A3550000002D70A7C3C0AB64100002296CA7D9E5D2D9C17D3E0C214D6E9EBFBBC1AE812D0000003874A5C2C5B9B9BF95400A184495BFC7B6B9ABAF6B340000072363A1BFBBB39B9896723300003886B8B8BFB3AD812500001D6198B4A59F778A9CA16F2B0000001E5D9DB8B4A984531A0C0C13276BBBF1FEE2AA632A15112463C1DED89239100C107C3A262E62B9EFEFC98F431F2B4D493C385EBCF6F8D5941A0C0C13276BBBF101FEC7600707187070807E8580570E000000185E93A9BAB0A6997B150000003D8FADBDC0A94F03000000349DCFD1C5B9863A18000000002480C7E8EBDEDBB5733D41527196B1C3C4B3AA57000000337AB1BFBC9D5B0E0000307CB6DDDCD6C8C173260B26587499BAC7BBAE7A2A0000003383ACC9BCB3BAB28A3D0D0B408CB5BDB5BCBEA4732800000A2362A0BFC7B4A09E90672A01003C83BAB9B6B8AA7D2600002169A8A9A9A17384918B5C1B000000095397B0B3A188501006160D205EBBF4F0DFAD6A2D120E1E6AC5E7CF87320A06047B3A2A3164C1F5EFCF9248292C3E4B3C3D6CCAFDFED49B1006160D205EBBF401FEC860070718807F758E897F4F150000001E6B94A4ACB3AD9F771E0000003B94B7B3B5AD58020000003399CED8C9B684350100000000328AD0DBE5D9DCB66F2E34627CABB8C1CABB9E4F060004377DBCC5C0AA581200012E83BEDAD1D6D0B7702309265F779AC0B3BFA0751A0000053881B4BCB9ACB9B98838001552A3C1C8BFBBB6B174230000002564A9BDBCAD9FA38E531700003D95B8BEC3AEAC792D00001A679EB0A89A7B7B88835A1100000017447D9FA6A48247230C04102A71B9E8F5D19F612E1514256CBBE6D689390600037D39262B66BEEEF3D2994122253B45393D76CDFDF8CE97230C04102A71B9E801FEC960070718907783818E80530C0000001F6498AEB3ABABA67C1C0000004294BFBCBDAA49000000003E9CC6CFC3B3823D05000000002F97D9F0EADFD0A95F38376889AEB3C7BBB49F46000000357EB2C6B7A3530C0002337EC0DBCFD4D6B8641F0E376685AABEC0B0A3641700000A3D85AFBAB3B9C3B6832E081B5699BAB9B4BDB5A36C240000102D6498B7C1B2A39D7E4D1500044B97B6BDB9B4A56C2300002874A2A8A5A77384968C6513000000074B829AAC9C8354190A090A1C6CB9F6FBD996572B1D142E70C2DFD483331006097E36253072C4EFF0CC8C49231D33472E3878D5F7EEC98A190A090A1C6CB9F601FECA60070718A07A747D867A4F12000000206E95AEB9B5A89670160000004E8BB4B2BDA74E000000002DA6CDCDC2AE762E0000000000429AD7EAE7E2D39E5D2E416C91AFB8C1C3BC9A400000003488B8C4C396491000004094D1DFD7D1D2A65819073D6D80AABFBDB7A367140000004996BFBDADABB0AC7B300A1C4D93BBB9C2BFB7A85F1E0000083063A0BEB1B8ABA1804A0D0006419CC3C9C1B8A0651E00002C75ABAA9DA478859089520800000008508BA1A69A813C1A0605111E65C1F0F0D69E602611102C74CCDAC586331009058C3C1F2C6BB9F3F2CA8845232C2F39303A7BD2F2F0C8861A0605111E65C1F001FECB60070718B077867E7B6F4E0600000027778DA4ADB0A69C69130000005193B5B5B6A3470000000039A1D1DAC5AB802C00000000003A99DCF4E9E6D4994F2D46769BA5BFC0C4B891380000064890AFB7BE94480900094D98C3D5D7D3CA9B51251B4A7C8EA5B9B9AF9E5D0A00000A4696C1BBACA3A8A4813913185E9BBDC3BFBEBCA6551900001032669FAFAEB5A79B71330000064A91BCBEBFB4A8602200003280AFBDAE9E728E94955F0D0000000D4A8098948E7745120700051D6DC4ECF2D89258371D122E76C9DDC9853108040B803324346EC6EEE1CC8E4A28292D3C33448AD3F3EAC082120700051D6DC4EC01FECC60070718C0838F9595845A0F0000002E7E9EAEA8AAA49D6B170000015A99AEBBB99F44000000003499C5D5D4AC782A00000000004BA2D7EAEAE4D799542C3E7E98B3C3C8B6B78E320000104792C5BDB8914A0500114B9CC1DAD4D4CC9E49171149778FB5BEB5AF965308000007549BC3BAB2A8B0A7722B0C2369A5C3C4BAB6B49760220000183B6799AAB0A8AAA16E2F0000044FA1C2C1C8B3A4621900002B86ACB4AEA06E8D948B4F190000000F41799BA09E81471303040C2272C7F1EFC98D4B2D10102A7DC6E0C1702A0C0008844126347FCDF3E3B5773C27223234334E86DCF5EAB3811303040C2272C7F101FECD60070718D0728080858251110000003682A0A3A2AFAF95630A0000005EA0BDB3C3A14A000000003895CAD0CEB06F28000000000046ACD6E4E1DCD290472C418AAFC7C7C1B5B3873400000A4A9CC6CAB78E410100085195CCE1D9D4BC8D43171B4B85A0B4B7B0B38D490300000858A9BDBBA2A9A29D772D11396D9FBDB8BCBAAD975B1D01001E305F97AEA6ADA998672600000854A6BCCDCBC2A76A1200083D87A1AFA5A56C82897D5A0E000000003D6E88969F8A44090006001F75C8EBE7CB8E432414143186CBE2D0862A090908903826276FC9F0DFBC7F3C222A2C2D314B96E4F6E8B47C090006001F75C8EB01FECE60070718E074878F917A54090000003B81ABB0B5B1AA995F0800000362A3BDB8B1A044000000003E9FCBCDC7B46A1B00000000024BB3DFE8EAD4BD8346274A8DB4B4B9C4BCB8802500001657A4C5C1C2903D0000074EB5CED3D1CEC38A421C30598FA1AEBBADAB8F4300000008519CBCBBA7A59DA8793515306DAABFBDB8AEAC9C4F14000021406D9DABA3A9B28E561300001164A7C3CAC1B99E550E00004599B9BBA9A3728385814F0000000000406D889598833C0D000503227CC7EBE4C48647261C1E398AD2DBC3761D00050C903420277DCFEBD5C07F42212329383D4C97DCF3E0AF760D000503227CC7EB01FECF60070718F081878E8C7B4B120000003A819FA9AFAAA78F550400000067A5B5A8B0A043000000003D97CED2CDB1691A000000000A57BAECEDE7D3B67132204A90B3C4C1C8BFB3772300001D5BA7C3C7B58E3500001854ACC8D5D4C6C38036102C6AA4A3B2AFB0AA8C45000000156AA8C1B7A4A1ABA26222103475A4BAC3B5AFAC9150200004263F739CB1A1ADB3844F0900001E66ABBFB8C5B7985B0D00044E8FB4B2ABAB6C7E8776420800000000416880979E7C3C0A00030A227ACFECE6BB744827171A408DCFD7B96B240604109840303178C6DFD7BB75492A252638325597E5F8E8B0800A00030A227ACFEC01FED06007071800818D968B88420400000B528DA4A6A7AFAA96580000000462A0B2B9B796430000000047A8CBCCC4AD6815000000000F58BCF0E4DDD8C1722E234892C3D1C2C7B8B7761C00002159A4BBBCB1833D0000155CAAD3DFCDCCB57C2E0F316B9AAAB7B0BEB3863B0000001670AEC3BBACA9AEA05E21103A7FB2BCC4C4B9AC914715000A1C3B649B9A9EA5AC874C110000156BA9C1BFBABDA04F120009468BA4ABA5A06E858778430400000003406A7A919F803A14000303237ACCEEECBD824D250D154096D1D8B9741C00000790381A287DD3E9D0A8783D27212C3743529CD8EAD8AF7114000303237ACCEE01FED1600707181073818B967A3F0600000F448DA2ACABAEA08E4F00000004649FAEB9BF9C3B00000000439ECDCCBB9A5811000000000450CCE3F0E9DCB36F311A4693B8C3CAC4C1B8791D0000226FA8C1BDC28A350000176CB5D8DFD5CBB7752B1239789EAEB2ACB3AD7A300000001F5FA0BBBDA0A1A09C601D184A80A2C0BDB0B6AB925721070622466F9A999CA2AB8D450C00001D6AAAB6BEBCC197531300144C98BCB4ACA0637479612E000000000036546E818F77350E0000001D70C6EBE4B4734C2110184698CFDDB86D220000079948222E85D1E1CEA16C3426272530355BA8EFF4DAA7720E0000001D70C6EB01FED26007071820727980866B2C0000000944899AA4ADA39C82380000000169A8BBB6C09842000000033E9DC9D2C7AC5C0E000000000C65CAE3F4DFDAAC6323124393BCCFC1C4BDAF6F1600003875ABBEBDB98B340000166CAAD5D9D7C8AC672515487BAAB1AFAFACB3722B000000286BA9BCB39F9FA0945018144C8DAEB9BEC1BEB092471600032D4F71999A93A9A8813F0300002570AFC1BCC1B48A5014000D559EB9AFA993567977643B00000000002A5D768F9A7233050000092780C5E8E2AF6D3D1211124CA8D5D6B660150005059845233583D3E7C99C793F28212B333D69B3EAEED19F6A050000092780C5E801FED36007071830718F9D9579400400000741849DB4AEAAA48F49000000106C9BB4B0B08E3F00000008579EDBD1C6A75E1200000000126DC3EAF2E2DFAA531D1B4C9FCED1BCC9B6AD6F170000397EB9B4BAB4802700001D6BB6DADCD2C7A86020184781A5B6BAAEB1AA70220000001D72ACB6ABA1929990541B155695B6C4C1C2BEB590441C090D2554748A878CA3A279330000002278B0C3C0B7B692440E0012599CB9B6ABA25E7C7A5F3C000000000034576D878F77340A0002062B87CBE3DCA66A41231D1B5CADD4D0AC62200000069B3D233D87CDDBC195663B291E1F314567B5EEEFD7A0630A0002062B87CBE301FED460070718407B87888C73410400001554909EA3A9A8AA8D4500000004659EB5B4B295410000000C4FB7D2D0BF9B510A000000001667CFE9EAE1D3984B19154B9DD1CBC2C1C1B25F1400004083B6C8BCB67D2F02061F6CB0DBDADBC0A55C20143F8AA8B4B3B3B2A0571C0000002476B5B8B19D9BA58A4D122361A2C2C5C0C2B5AF894C1A0010335A7A9C8F929BA076290000002770A6AAB5C0C38F450B00176AA9BABDAC9A577D6F642A00000000063C6077979A7137050002002486D4ECE5AA724427171A5CA7D6D1A95B1C0005079C3E1C3C90D0E0BE8C613E261C213A3C71B4EBF3D0955B050002002486D4EC01FED5600707185079938F957B3A0C000017598CABB0B7B0B08835000000157AAAB9B5B797400000001359A9C6CFCD9C4800000000001E74CBE6EDE6CF9A43150C52A2C5C9C5C0BEB561070009518EB4C5C2AF83270000246AB5CBDED9CCA84718144C90ACB3B6B1B7AA65110000003581B6C0B19A9C9D8440102E6DA7C2C7C5BDB1AD894F2101093D617B8D80879A9A65220000002B77B0BFC2C1B98A3C09001E73ABBFB6A0964B7776643800000000063E5E7E96907B350F00040D328ED3EFDBA76F3B25152563A3D3CDA7591E00000D9A39184495CEDEB58B633B26251F345074BCECE1C58C5C0F00040D328ED3EF01FED660070718606E787C8269280000000A4D88A0ACB4B0A5762E000000186BA8ADBAC1983D0000000D579DD2CDBE924700000000001F83D1F1E6E7D28E41120D59A7CDD2C7B5C8B3610A000E529AB5B6C4AF6E2302002371BFCBD7D3C1954618134C94B0B5A9B6BAAF6113000000378BBACDB59E959A8C3E122A6BA9C3C6B7B8AFB18D542805134063708E7B7896A6681F0000033486AFB9BCC1B8862F00002B6AA7B6BBA7914A75725A2B000000000D41607790907028010000003490C8E4D2A35A3B20182D6AAFD7CEA9570A00000FA33321499AD0D0A6804F2E2B2D283B5D79BCDEE4BB8453010000003490C8E401FED7600707187074888E93722F00000016639AADA9A8ACA48437000000196BA4BCB9B49539000000195CA8C5CFC192470000000000227DD4F9F9E6CF85381112479DC4C5B5BCC3A75A0700195F9CC7C8BEB371200000277BBECCDAD4CA934014236399B6B5B7B7B6A3550D0000003085B7B6AB9E9F9E7132102F6CA6C3C4C0B5B8B28B5B2809153F69899973758C88621F0000074B8FB7B2AEC1B88D2F00002475A9B7BBAC97487A72582F00000000184B5F6F8B937136050000032D7EC1D9CF98532B221B337CB9D7D29A52150001139F3A285099D1D2A67350311E30243D5990C6E7D1BA7F47050000032D7EC1D901FED860070718806C7E868D6D30000000195790A3B2ACA7AA81250000001D7BA5C4C2BE90320000002261B2C7CFC49A3700000000002183D3F2F0E7CB84370A0B50A9D0D2B7BEC0A14C02001A679EC1D2C3AF6F1400002B73B9DDDAD2BA9540151B63A7BAC2A6AFA49754090000004091C0C0B59C958C6F30123075B0BDC8C8AEB6AF93571C000B4F76868A75708D924D1C0000124788B0B1AFB7B47D2C09001E73A5BDB8AA92507260502300000000284D5F76978F6925000000002A8DC4DFD18D5431190D2467B5D5CB96430F060510A84325469AD3D19B724E34262430497090D9F7DAA67547000000002A8DC4DF01FED960070718907B888D8C67290000071D578BA0AFB2AEA5752C0000001A84AFC2BEB991330000012672BBD7D6C58F3F00000000002B84DAF7E9E4CB7D2D151A53A4D2CAB3B3BB9C4200001863AFC9D8C7A66E1800002C79C1E0DACDBB84300F2867A1B4B9C0BAB18F45000000034493C2BCB59E92976A2915407EB3BFBDC5B7B3A68F5E2B0C1C516E8C8E72708B9454120000184582AFA9ACBAC47E2C00002A70ADBDB4A18B517562411B0000001F395C668392946418000000093A8DD1E4CB914B2723143781B4D4C08C4A1302000AAA45254EA4CAC8986252332D312F45709DCDE5CB9A6344000000093A8DD1E401FEDA60070718A0757B7C86581E000005205E909AAAB6A9965D20000000297CADB9BDB381280000083481BFCCCABF893700000000002690D6FFFBF1CC8231071253A6D5D6B1AFBC994905001B6EACC2D0C0A9610C00023176B7D1D9CBC9862B152567A2BFC3BDC2BD983C000000004394BCC0B8A695926122114890C3C6BCC1BEB6B1946C36191E587B8585796C8C8B46160000194996B2A9ADBDAF762D00003174A5BAAD9F8C40715B3D13000000023A55657D8E804C0F000000023B99CED5CB8D462E1D1C3B7AB9CDC088420500050AA841254FAAD7CE99654F30292C34587EA3D3DFC1906340000000023B99CED501FEDB60070718B06E7276885C1500000010538BA4B0B0AFAB6A11000000176CAFBFB6B9802C00000C3A72B6CBCEC98C3900000000013382D7F6F3E3BE6E1B001153A7C5D2BABCC0974603002B77AFC7D8C7A8630F0007427DBED8E1CEB370210E327BAEBEAEB1BBAC833501000001459CC0C4B99B948467231F4C87C3C9C5C4B6B6A58B6237171F5687938A6F6C84864510000019529AB0ABAABAB36E2200002F79AABAABA28B4A795E42110000000B486B7C89978F4B1900000001489EDADEC67E3E1E120E378CC1D6B485380B060C0EA33C1F59AED0C58B5F3C342B3447658BB0D4E3C38D5B3F00000001489EDADE01FEDC60070718C0727179855A1B0000001E5A94AAADB4AFA86B11000000237AADC1C3B27B2C0000114985C3C4BCB67D3000000000052D8EDAF3F4E3BA6D1E041C59ADD2DEBABCC5A34600002674AEC2C3BFAE5C1200053681BEDDDFCEB35A1E10307AAEBEBAC3BEB58F33000000054A97C5BFB9A49A7C4D180F549CC1CDC8C2AFB3B29767441C285F7D938671658A8136090000225F93ADA1AAB6AD672706033579A6A7B39F883C7965400D000000224B6A718EA38E591100000006419AD5DDBE783A1F16154094CBD9AF823D0800030DB2492C5BAFD6C48C5439372C2A3B6898B8D3DDBA88583800000006419AD5DD01FEDD60070718D0706F6B7F4D17000000175691A0B0B5ABA55F120000002274A5B6C3B77927000019508CC1C5BFB2823200000000003892DAF1F3E2B5641B081C62B2D8D4C2C2C4973900002C85C0BCB7C19D570400023E90B7DCE2D8B4612510367EB1BCBDB0B8B08D3900000007519FC8CDC49C927E4F13115FA6CDCCCDBFB6B4A991733D242E627891876B65807B38010000266199B09AA3BCAF651800003179A6B3ADA98D3B6B4D2B0000000018516A848B947F41130000000B54ACD3D9B978351C1B1F3D8FCDDDB3782404020512A13B2B5EB8D7BD7B4E3A3827283D6F9CC4D7DAB17554390000000B54ACD3D901FEDE60070718E07C61627B4910000000205C8CABADB6B09D5B0B0000002572A3C1C3AA6E2300001C569DC6C5C7BA752F000000000F459BE3FAF5E9B85E13000F5DBEDAD4B3B4C0942F0002338BB2CCD7CA9B4E03000C498DC4D6DED2AE511F143A7EABBDC3C2BBA78324000000144FA2C4BBBAA18F763F111E63AECFC9BFBEBBB5AC97704A1D2E648C908E5E5F84803F0000002D70A0AA9EA0B0A05D110006377EAFB6B3B18D39725A2701000000295D79899A9A844209000000065AACD6D7B66A2F221C23418BC6CAA46B3409020B14B6452E6EB0D4B77E4839342A324A7CA8C8D6D6A96C402D000000065AACD6D701FEDF60070718F06F584E6C4608000000145491ADAFA7A99754000000003276ABBAC8A97A2700001A5D99C5C6C6B57C26000000000E3D9BDCF6F5E8B25C1100195DAEDBCFBAB5C590340100328ABFD0CFBE965813001B5397C8DEE4CAA24905033180B1C9C7C8C4A67B2D0000000E56A1C1C3BC9E94713E0E1B6BB0C8C6C5BDB9AAA597714B2A34668C917E6360806927000000377EAAB89D9FB1A5581400003583AEC0B79D893068441A000000001F5B767A838D7D3B02000000095EA9CDC8B774331609134899CED7A15C2300050109A43E2D79C0D1AE77473B322D355087B4CACFC9975D4232000000095EA9CDC801FEE060070718007751566C430100000013578DA9A9B6AB9348010000003580A9B7C0A56C1700053165A2CCC5BFAA72200000000014489CDBF7F4ECAF521501135FC4DBD4C0C5BD8D2800104095C3C2C7BB91420200144F98BDD1DAC79B40080E3C8CC3C8BDC2BFB17B27000000115CA9C7C3B9A4946E360C196CB7CDCBCAC2B7A3A39986502A426D9291836657766C270000114678A9AA9B9FAEA2530F00053B7DACBBABA38328694A1500000000206786919091733F030000000E58AECFD5AF6935251A15529CC7C69B5C1705090610AD504280B8CFB4733E36312E33538CB8D1D2C2966A462F0000000E58AECFD501FEE1600707181074524B65380000000023598EB1B2A8A6924B000000063875A6BCB5A9661700032C77AFCECABEAE7527000000001C49ABDEF1EDDAA34F14021962B8DCD9BCBDBE8C2D00104495BDCBC2BD8F4101001F549EC8D7DECA962E00114182B6C5B6B9B3A374250000001B61AAC8CFBDA793692C042473AEC1D9C4B1ABA99D9B7F572C467C898E7D64577968260600114E84B8B99FACAC99430300024284ADA8A7A183265F421800000000296286888E9D7936040000000E69B7D3D2A2692E1D101D4F9CCBC9995B19060C0F0DA8473385C9D5AE693C393F33394F91C4DAD3BF845339350000000E69B7D3D201FEE2600707182085535A6025000000001C5186A9A8B5AF8D49000000073B7BA7B0BFB15F1300083777B6E1CAC8B279260000000020569BD2F5E8E2A2490802166DC1DDD9C3C2BF8A2A0016489AC1CCCBB9842D0000165699C5CBD4C98A3408124386C7C5C8B8AFA8791A000000276AA5BFBAB8A49B67320B257CB3C6CECFC1B3AFA38D7F50334D798D92764C5C6F5A240200164A89A0A8A0ACB7A44E0A00064381A9B4ADA08125653C0D00000000326F8C8B979A752A00000000156FAFD1C99A59281D14245DA8C6C29D510F05000205A94A4681C7D2B164463A3333385CA0C4D6D1B77C503A2D000000156FAFD1C901FEE3600707183083625F6835000000001D608DAAB1BEAE9340000000074781A9B9C69C5C1800074481B6D5D1BAAA742600000005255DAAE1F2E7DB933C0300206EBBDCDDC8C0BA7729000C439AC3BECDC48A2F00002761A2C7D1CFBE933100164789B7C4BDBEB1A06F13000000246AA3CAC4C4A6986726062F7CB9CACBC0B8B0B2948A7C5C364B8793907D554E61481500001C5989B0AFA9A8B0944505000D4586A9B4A8997B215C440C00000000306C8F959C97732B040000001976B3C9BF925220211E2063AEC6C99448120000070EA94E428DC6D5AB6C373340353E5EA0D2DFD6B16E432F220000001976B3C9BF01FEE460070718407C54545E2500000000254C84A1ADB5B88B390000000849818FAEC39A501A00093C86C9DCD5C3AF661A0000000B335EA5D7E1E2DC934905001E72BAD8DACED4C48327000B519FC0C5C3AF7721000027659CB6D9DBC187300C1F478AB6BFB9B7B09C650F0000002A6FA7C3C4BBA996591F023387C3D8CBC0B9B6A69D9180513358818C99704E53664A150000236B9EB2ACABAAB48E3906000A457EA6B0AA937023553400000000003571889094956D2E000000001D73BFC4C88F56282C1E1C60ABCDCD914A1200000616A8484B96CCD4A6662F2D2E34406AA7D8DDC8AD6E37272F0000001D73BFC4C801FEE56007071850764D4B5513000000001B527D9AB3ACB0772B00000016527693A7B78F4D1200094995C2D7DEC4AC6E18000000113767B3E1F2E7D2893409042165AED8DFD2CBB476280012509CBFCDCFB4702900023173A3C1D6DEBD761701134087B4C6CEC4AD9F6B0D000000317BB3C2BFC2B29B5E14002B8BB7BFC3CAC3AF9987768658416D8A928A715244503718000223659CB2B7AFABA9893500000E4484ACB4AE9E7E245F29000000000037708F93A1976830000000001C7EC6D7BB8C4F1F26172C66A8CBC68B420A00000E17B15154A4CCD8A55B2B26322C3E6FAED4DFD0A5603329310000001C7EC6D7BB01FEE66007071860744F4F501500000001275185A4AEB2A57B330000000F567B91B5B9954104001046A2CAD9D7BEA85915000000073D68AFDAEDE6D3973904062273BBD2E0D6CAB66B19011A5497B5B9C2AC691D0004397CB5C9D2CFBC721800245B8AB0BDBBB6BA9F6410000006357D9DB4C3C7BA985B170A3A8EBEC9C3C6C2B9AC8F878358426684968C6C4D3839300B00063874A7ADB8A7A5A87C350000144E87A2AEACA471135E2C00000000003F839790989E703200000000227CC5D1B8874C1414162A70BBD1C184380C0000000FAD4A5AB4E2D0AA5C2E242B2F406FA8D4DFD3AA63332D2C000000227CC5D1B801FEE7600707187072574E4A0500000000214B86A5A7AEA970210000001F486F89B4B1834108001257A4D1D8CBBC9D5A1E0000001B4174AFE1EBE6CE89350A092770BFD3DBD8CEB16A2000175D9FB6BFC4A46B1C00073E7BB0BBD2D3B87B16001C518FB8C3C8BBA79D5C150000003878ACBDB8BFB69A571C0E3A98BECED3C1B8AE9B837478523C6D939588684B3745330E0B0C387AA5B1BBB4ABB2762D00001D4B88A4B5ABA46C155530000000000052859AA8AEA3742A000000002F90C7D0B3824B1F1D18327DBBD4C788460D00000615B05168B0DAD89F53262A37303D73B8DAE0CE9E562E242E0000002F90C7D0B301FEE860070718807350453A0000000000264D6A9CADA7A7701A0000001C5D7D8DA7A7782B00001058ADDADFDEC19D5D18000000194F82AFD6E5DED08C3200022974BFD9DCD0C7B06115001C60ADC0CABE9C5D13000A3E82AAC4D8D6AC6D2508205A90C5C2B9CABA9C5D0600000D3372ADAFB9BEA4894C1715449CBFC6C2C8C2AF947279795F437C90978B744E3731180B060E437EB1C5BABAABA3701900001C578EA8ADB1A66F1157310000000000508C9DA3A89A712E000000093E8ED0D6C180431C211A2B77BACDBF8535000005020FA65870B9E2CF98552A283533467DBCE3E5D29B4F27242C0000093E8ED0D6C101FEE96007071890726657470000000000365C7EA4AAB7A6730F0000002D66747DA2A97A3F00001950A6D6DED8C2AA611A0000002A5489B5D9E2E0C7843403003475BDDFD4D1CCAF5B13001960AAB0BBB5965311000B4A8BB8BACCC6B0611009265C8CBDCBC5B9AF9A5C0F000015456F9DAEB9BFB28F4A12094796BBD1CFCEC3AF8F736C6D514379969E8E72462D36270A0D154983B7C3C4B0B29F602200041D558A9CA3A09E680E582200000000004A899BA2A299742C000000054297CDCFB47638141C1A407CB5C8B77D3A1100000010AB5679BCE5CD954E252728364E7DCCECE1CF8C4225192C0000054297CDCFB401FEEA60070718A07C6B5A43000000000235547EA1B5B59C621200000029677A849C9B652200001952B2D5E7DFC3A2661400000A295389BDDEE4DDCB883609112D77B8D1D7C3C7AC4803001E67AAB0B8B18C420B000F5093B4C5D2D2AB5C130A326995BDC7BFB7A68F5A100000224B7897ADB7C9C58F4A0D0944A7CBC1C7C0BCB18F63716D5145739FA08A72462D29131000154D8AACBAC1BAAD95591B0106255F8C9A9DA9A66C0C5A2600000000004A93B5B5B39A6C29000000034392C9D5B3783E1714233A84C0CDBB7030090002111BAC6185C7DFC58F4720262E334985CFE8E7C88E482823290000034392C9D5B301FEEB60070718B06F66543B000000001446547E9DB6A9885402000000266C7C7DA098611500001E63B1D2DDE3C7A9691B00000E2F6891B9DEE3DBCE782902023772BADED9D3CEA34611022D6EABB6AFB4933E02001C5A92B1BBC4BD9C5C120C4276A1B8C9C5B9AB91460100002C497190A8BABDB1893D100E569DC5C1C4C9BEAA855E636857508098A19D87482418100501125191BDCEC9B5AB996918000025607E9294A49E6609582800000000004894ABB1B0A6762F0000000853A1D2CFAE6D341723243E85C3C7B8712B0000010C10A26290C9DAC58C512824272F4287C6E5E6C8863A1C222C00000853A1D2CFAE01FEEC60070718C07759532A000000000040597798A39E9550090000013D7B7A80918E4F1700001D5AAFD1DEDBC39F5F18000009366598B6DBDACDC37F29060E2D7FC3D8E1D3DBA0510C072E6CA4B9B7B682350300165CA1B6C7CEC899460314407293C1C2BEB8AF974904000425507394A5ACBDAE8F40120F58A2C9C5C5C2C1AE81505362484D89A2A89B7B4E1F110A000D275897BCC8BFC2AE955614000F2C638A9598A19E680F561F00000000004D9EC4BBB3A371280000000E4CA7D1D6AD6A3011162B588EBBCCB4722B0900000617A9688FC6E6D59D52231925303E82C9EDE6C38A3B1E1C2E00000E4CA7D1D6AD01FEED60070718D07561532F0000000018505D6F92A7A37E360000000043777F7797954A0D00002B6CBADCE4E5C7995B0C0000093E709CC3DFEADCC37E2E0D132D7CBDD1CAC6C49A3C0B0C406F9EADAFB27D2E06001969A1B5CECCC690450F0D427BA9BCC0C7BDA9904700000330536C869DB1B3B68A3D1D1B61AAC4CCC8CEC6AB7346535D49568394A49B7848200C03080E246097B7B9BABBB5935A120404346F728C949C977013511C00000000004C9DB9B2BAA56E25000000145EAADCD1AE5E321121376399CBCEA860280000000313A377A6D0DDC3843A1A1A2A2D4990CFF2EBC78E47181F260000145EAADCD1AE01FEEE60070718E073675320000000000D4F616D91A3A28236000000023B7D7E7894843F0700001C67B1DEEAE4C49352180000103F74A1C3D4D7D9C3832F0111327CC0D9CEC4C39C3C0A04377CA7B3B1AC78260000266E96B2C1C1B8873C0F124080ABCFCCC4BEAC83370000103059708EA7AFBDB286370F1C63ABC0CDC3B9C1A2713F385C535391A3A7A9894F1400000A1A2465A6B8C5C1B9AC8D4D1603113A6C777685989865094D1900000000004E96B5BAB7A666220000001663ABD5CDAE683016253B5C9ECCCBA0641E000003011BA670A7CFDBC2883D21172A284498D5F1EBC47C2E1C162100001663ABD5CDAE01FEEF60070718F0756D5624000000001E4B636A92A9A57A2D0000000A4F868D819479340000002566BCDCE3E8D0954F0E0000195D91B7BECFCDCCC17E340A183D85B7C8C9C7C3892E060E427DA2A9ACAC692800002060A0B8C0D2B2783514205584A7C1CCC5BAAD833B0000103C555C778FAFC3AC812C0C1662ABC1C5C5C0BEA4713C364F495C97AEAEA7934E0C000007132564A2C1C5C5BBB2894216040C45718275829B975E104D1700000000045AA7C0BEB6A16B270000001C68BADACFA36A2F131E3C6EA5C9C9A4601F0400000014A17EB1E0DDBC7B3611191D234E9AD5EDE2BE7D3322142100001C68BADACFA301FEF060070718006B635012000000001D546260849E9A6B200000000B4C8A837E9E79290000002571B1D6E5E4C192490F00011E5498BDCCD5D5D3BA7B2A0A124887BBCCC7CAB5822A02124E86AAAAA69E5D1E0000356FA1BFC3C2AB67290228659BA6BFD1C7B1AF832D0000225160677C93AFBEAC7524162A6EB0CDC9C7BEB2975F2F3240546595AEA3A693520C00000E1D2F74A0BFC3CFB9A57C390F0514487D826B758A8A5D0A521A00000000004F9EC1C7B59F6C2C0000002871AFD6CF9F6930151D3D72A5CBC9A65E1E0000000A25AD86AECECFB4703117181C2456A4E7F6E8C77C3E1B1A1E00002871AFD6CF9F01FEF160070718106F6C5915000000002A656C6A7F989E651F00000015608F8886937027000000326BBBD8E0D0C38A46070000255D9EBDC5D8DFD7B8813009225498C1C7CBC7BA852100175487A7A6A8984E0400003576ABB8C5BDAB6722002D6A92B0C9C9C7B9A3762F02001A48676E7393B8C1A26A250F3274BDCCC7C2BDB7A15A242B504A6696A8A7AA95590B00000D16357BAEC0C3BDBDA2743C0D0210517E79617386945B13520E000000000357A6CDCEC09F6823000001327DC0DDD0AD672B102C4B6FA7D1CDA35C1A0000000021A594C0D7CEB172300F0D2033539ED7F2E9C9853A241E250001327DC0DDD0AD01FEF260070718207067570F000000002D5F6059708E90671E000000205B91958A9568230000002D79C2D8E2E2B978380A000B296CA6CBD1D1DDC3C87A230F254B8EBCC7CDC0B7801A001F608AA9A7A7863C020000427F9DB8C2B6A251140A3380AFB8BAC9CBC0A5711E0000255560666688B0BDB2712D0D327BB1C3C6C4BABBA25A242344506DA4B2B1A8995105000005133681B3C4C6BAC19F6D2A0A09165182775E6182925F133F05000000000056A1BBC0BEA36B270300003B85C9E1CD9D612D121D4E87B6CBB99656110000000025AA98C5E1D4B26B27131A182857A2DCF4E9BB763113132200003B85C9E1CD9D01FEF360070718307C705607000000003C69615E73979058120000001F5F91978F966815000000357DC5DDDBDDB8843C0600083E76ACD2CFDECECFBE7E240D306099B6CCC9C1AE761200135A8BA19F9E7D330000004084A9BCC5B998440F0A3984A4B9CECEBFC3AD6C200004295E70565A83AFCBA2642A192D88A7C0BECAD1B8954B0C0E2E4663A0B0BCAD9C5D0C0000021A3991B6C7BFC1B8AD692D0C0520638C7958577A915B0C4C0D000000000854AAC8BDB99A5826050008428CCAE6D19E632B1F285789BAD1C189420A0000000031A6A4C0E0CAAE5F2812151E2C58A4EAF0DEC0742C1814250008428CCAE6D19E01FEF4600707184086805C0C00000000547A77656990925F1A0000063367A4A2969E6918000000327FC8DBE4DDB3632706000C3E82B4C6D6D8D6D3B4752F1C365C9AC5C9C7B7AA700F00256F949D998C74320000074487A1B9C8C188410E01428FB4BEC5C7BFB9A65F1C00002C5F7B595B7FB5BF9C622915378BC9C6BDC0C5BF99501A1B34457BAAB8A5A392560A00000B164B88B4C6BEB4BB9B5B250C09256D9671434B71905A144005000000000662AED3D0C6A0571E0400134E97C7DCD49E6A3128316491B9C8BA853E050000000C26A4A9CBDACC9156200E080D1954A8E8FBE8BB732D14121B00134E97C7DCD49E01FEF560070718506D713E00000000004B70704D5F8A854C040000002D74A4A6A4A058140000003C7FB7DAE2D9B068280200154988C2D6DCDED3C4B364231C386E99B9BABCB6B5641300256F8FAA92957530000009519BA3B3C3AF7F300100469EBFC1C0C4C4BD965B1300083C6980615380AAB6935A1B164891C3CFC9C8C2BB94410B1B335176ACB5BAA597590D000013204B8AB1B1BBC0BA884E20070A31799677414C738F5711450E00000000116BB3CACCC0965B1E0102175A9CCBE1CF9F643931326C9BB8C9B38737080000000025A2A6D3E3CE9A5B1F091C162260ADE4FBE8B6762C111A2202175A9CCBE1CF9F01FEF6600707186081774A000000000858857D52649280480000000C3C7DA7ACABAB5B110000024088C3D9E5DFB261220400185CA0C8D9D9D5C7C4A7673021456394B9C9CEBE9F580D002B729D998988671F00000A49909FBBC5AE7A280604549BC8CBC2D0BEBF9F58140005397C775B577DA9B79951221852A3BFC3CBCEBCBA973D151F3852759BADB2AF94510A00000E224595B9BFBEB8B18C5413000A32799870393E7C8D5410500A000000000969B3D7D0C4954D210503185FA1D3DBD6A1694939406992C0CAAE793500000000002C98AFD8DCC68C3E0F020D171F63AFE8F2E0CA7B3113162503185FA1D3DBD6A101FEF760070718707A7639000000000B608A71495D917E390000000B4F80A7A8A3A35508000008417EC6CED9DAB95C2901001A5CA5CDCDCED2CCBEA2662A174371A5BEC0B2AEA0570800347F9E8F8E825A0E00000C5397A5B5C7B5722201094FA0CCD4D0CACCB795490100164682845F517BB0B8975A201F4A96C8D2CECAC4BE903501133852779FAEAFAF99551500000F225A9BB8C5C2B7B185491F0810357495683A426C8A4D0E440E000000000861BFCFCFBE9A551C05012066AED3E9CCA57654384571A1C1CDB57727000000000030A7B7CBD1BC8D44181415232463B0E6FAE8C07B2F111C29012066AED3E9CCA501FEF860070718807F713A000000000B6784724D497D6F2E00000014557FA3A4A596570E0000114E8BCADCDBCAB55E1804002065AED3E6D0CCCAB89F652118507BADBBC1BCB2994B05073C859B868D7F4D08000011579DB5C3C6B4731E00075EADD1C8C8D4CDBF923E0000124D8583544471B7B78C47222761A3D3CDC4C5C6BB8F3E0D0F305C81ACAFAFAF995810000012255A9EB7BCC3B5B182351400163D8199672E2C608F53104A0E000000001177BFD5CDBA914F2304082B6AAEDDE0C89E73594B4873A9C2C8B27B2500000000003B98AFC6CEBA894013011113256AB8E2F8E3B66C310B1F27082B6AAEDDE0C89E01FEF960070718907B6E350000000017758D724547777030000000236088AFB1AEA352040000114B94C2D5D7D7AD581703022A6DB1CED4D5D3CBB996512D286090A7B2BBB6AF8D4201004B8B998C6E6A3C0700001763A0A7BEC4A55D1400025FB2CFD9D7D5D1C79B42030015548B865D4A78ABA88244182C5E9CC9D5CED2D7C68F33000A3E6790A1AEAFAC91460400000F234D9BBACFC5B6A57A300C010D488D995A313165864C174309000000001B73BFDED0B58B4D1D040B2D7DBBD8E2D0967558525382AABCC6A0642300000000003C9EB1CEDBB97C390B0913162268BBEBFDF1C870311D271C0B2D7DBBD8E2D09601FEFA60070718A0686323000000001B6A8C70333F755D23000000206496AAB2B29D410000000A5396CAD0D5D3AB531400083072B6D2DCDBD5CAB68F51282B598BABB7B9A9AA8E3F00004587A18D7868340000001763A1B9C0CBA3540400126AC1E2DBD2D0C5B3823600001A5F96905B5174ABA176341C336CACD7D2C4CAC3B683320309406B91A9BABCA88F4F0C00000A24509AB6C6B9A69E70280802134A9297612C347A914D17430F000000001E83CEDFDABB874B1D03063682BCDCDDC59D745A4F6896A5BFB49F652400000000003B8CB5D2D6AE742D090A15202C77C3E8F0E4BC7831222424063682BCDCDDC59D01FEFB60070718B0786925000000001A6B89694246715C160000002D6B96AEB3B99C3C000000175899C6CED7D3B25212060C357CB2D4D7D3CBC6B07846222F6A99B8B9B7B3A78A3600044C919F886C52250000002B70A2B1B6CDA0520C000C68C3E0D8D4C9CEC48D2D0000186590945D547AA59D6A321F396CB1D2D9E0CACCAE7D29000941769EAFBAB6AD88400700010F305493B8C3C8AF9E68210F0C25599AA454252E7481411A3910000000002A87C5D5D0B4843C19000C4387BEE6EBC29C716A62608BAECBC1A1611A00000000043E9DBCD3CEA76B260B0B1D1D2D72C4F8F3DEB972241627280C4387BEE6EBC29C01FEFC60070718C076641C000000003286906841496F53150000003A81A0AFABB2943700000021629BD0E1D2D4A45813000D397FB8CFD0D5D1CEA36F432540779BB0B7A9B3B385390000518E9A896A531C0000002E73ABB7BBD2955903000F7FC8DBD4D7D4CAB4862B00001E62A29D714C6FA998662A1E3B81B5D5CDD1C4C4A97426000B4F7299B8B2A5AA853500000913234696C3CABAA399672B0E0329699FAE67262B6887461C3C05000000001C80C8CFCCAF793D1300105092C9E8DEC69B6F675C6D8CB3C7BD9D590500000000004097BBD3CBA45C240D091720367EC7F1F9DFAE6223232F28105092C9E8DEC69B01FEFD60070718D06D5F1700000000357C936F3B3A624C14000004438CA8C3BDB5933100000024679FC7D8DBD2AF4F1602144186B7CCCECEC6BCA16B30224485A7ACB7ABB1A7842800085C99A0906A49140000003881B1C0BBC39B460000196FC1E2DCDBD8CBB17A25000022639995654E78A7975C27213B83BED4D3D2CCC7A87D1F00135092A2BAB1A9AF893D00000317284E8CBCBFBAA5895A2303001B5AA0AA59283974873A133F10000000003797D2DACFB37E33180818579CC4ECE6C68C7A7C6875A0B4C6C492500600000000004B95BCD3D59858200B10241C307CD0EDF3D7A5682923272A18579CC4ECE6C68C01FEFE60070718E0715E0E00000000337C88723D3D6144070000004D91B6BEB5C08A2B0000022566A1C4D1E1D5AD56170112418CB8D5C2BCC1BF9D602C22548EABB5BEBAAEA47B1E00105F9F9E8963340B0000003D8ABBC0C9C18D3E0000197ECDE3D8D8DCCEB9751D00002968AA98635474A8903F181D4B82BCD2D7C6D2BD9D6220001A5E95B2B4C1BBA77F2F00000813275599B3BFBCA68A571E0D072568ACA7561D32788341173B0B000000003A98CED9D0B57C32100116579DD1E0DABB8D757C6B7B91ABBFBA8F450300000000004B97C0D0CB9B4E18030F161C2E8BCEEFF5E3A5713526242816579DD1E0DABB8D01FEFF60070718F079560C000000004A8D9C7E43426B4B0C00000C589FB9C1B7B27F27000000316EA6CBD7D5D9A0521E08245195C2CCBFBABABD9054232D5898ACB6B7B3A6A06D1D00166D9EA18A54270400000C4595B8C9C5BC85370000197DCAE7E2D3D3C3A7611500002968A2A67D6487A37E3F23214D8AC5CFD0D4CFBD9B61190011609CB8BBB1A5A57F2F00000913244696B9C8BCA38D4E19110F2E76B0A65D2F426F7A381740130000000049A1D0D7C4AC773013082564ADD4E7DDB5866D7073849EBEB7B388410800000000005892C0D8CB9C5217041520183489D0EDE4CD9F5D20282A292564ADD4E7DDB58601FE006107071800755413000000004C92987A465278440100001863A1B6C3B2A9732700000A3D78ABD0D4D2D5905E2715215496C4C6BCC1C6B1773E1D2F6DA2B5BABCADACA46E0D000E68A0A794582D010000084A9CC2C8D3C87D2E00001C8BD0EBD4C7CBC6AB620C00002E7AA8A98061839D762A0B265A9DC3CED3D9CCC590591600226AA7B6B7BAA6967120000010142C579DC0BEB0A28C531C0E083480B8A357304881783D144726000000024FA3D1E1CFA9713914092774B9D8ECE0B48274747E8BACB8C1B39040000000000008699FB8CCC1874510011723244491D7F3E8C89D6527202B302774B9D8ECE0B48201FE0161070718106C41000000000051A0A27B464E69390000002464A9CCBFBCA6681E0000073D8BAFC9CBD4C8965B25192E65A4C6C5B2B1C6AF813B1B2C6BA1BBBFBBBCAE9F610600136992AC9859280000001353A1C7CBD3C37B2700002781CAE5D7CFD5CCA3590700002D71A5A5796A809573301D36699FC4DBDDD6C9C89E4610001675A7B2C1B7A39F732500000E132F589BC1CDB09C823C0E05002D79B5AB57303178753C213F130000000551A0CADFD1A85E2300002D72C3DFE3D1B073637D7D8CA3C1CCBD843A00000000000B6398C1D9C9873D1000131C2A4494D5EEE2C498592B2E31282D72C3DFE3D1B07301FE0261070718207D59020000000F65A5AA935C5E6F3A0500002C7CB4C5BDB7A45A1100000C478DB8CFCFCFBB8E5E3219306B98BBC1BBC5BEB273321A337CACC5BDB7B8A99C5C05002176A7A38C54120000001F64ACC6C6C9BC732000002A86D1DCD1D4CEC19D4A0600003375A7A98F7A90946A2C16326DACCAD2D7D4CBC08D4A1300266BAEBBB8ACA8975C1C00000C13325A95B9B9B0A78742130F0C3785B3A25E2C40806F2B1740110000000857AADADCC49D62280E113D82C3E3E4D3AB796E79798EB5BEC7B680310000000000186C94C5D7B780371003102A1E39A4D1E5E8C6995A36212B2A3D82C3E3E4D3AB7901FE036107071830824A0B0000001876B2B69568696F3D0E0000307CB8CBC5C2A4661700000F448CC3DBD5D0C6A162381A2C6AA0C4C0ABB4C6AF6224113787AEB9B8B5AEA89D5D03001880AEA69955110000001B6EAECEC7C8BA6A1C00002995D5E4D3CECFC29B470000073E77ADB09D787C94531C123571B1CFD3DEDAD4C68A3F08023286ADB8B5AAAD914E150005141B28549BB4B1AA9A73370E0F0E337FB4A46535537E75391B44130000001767B1DADCCFA263251515478FC5E2E5D4A7735C768194B8C6C8B37E330000000000297B98C6CDB1762F0C0418282E50A7D7E4D7B88948191D2D33478FC5E2E5D4A77301FE046107071840733E00000000226BAEB6986D716A360300003180CCCFCBBB985D0A0000185499C6D6D7CDC49A6E462B4586ABCDC8A8B1BC9F5412023D87B9C5BDBAB8B4A05600001F80A5AB97570F0000002376ACC8CFC7B2651500001C7FCBE5E2D4D7C792420000003776A4B39C858A87511B103B7DAECFD6D6C8C0B4893600023B8CADB2B1B1AA8D52100001171D3861A4BABBA8966F2F1611113A84B3B65F36528971312043120000001062B2DEDDBF9763210F154091CCE3F0C99B6B5D747C9FB8C8C7B9632000000000002C8E9CC8C9AA7038060013202757ACE2EBDAA0864D283030374091CCE3F0C99B6B01FE056107071850734101000000257DC2D1B27E78743104000A3893CAD9C9BC953E0200001B5CA3CAE5DEC5AE8E754A314B7BA6CCBDADB2C29B4A1103469DBCBCB6B0B0AFA05C000023719FB19657140000003387AFC5C6C5A3581200002082C8DFD5CDD2C38E29000008426AA6AE97898A8F4C1D204E8ABBCECFD7C8C4B87C420C024096AABAB6B1A3865204000C1B223B629EB9B2A19C6D270A09163897BCAC6140598C77321A3C170400001F6AB1D2D7C38F53210F1A499DDEEDEACE9A67626D7C9CBAC6C5A872280000000000399092D2CFB5721E04021A2A2D63B8E2E7BEAC7E4628212E32499DDEEDEACE9A6701FE0661070718607A410F0000053C9DD3DBBD8B7E7A3F0C00114D9ACCDAD8BF8F430300001D5EA3D8DDD9CBB48B7A5735508AB7C5B5A9B7B8964207034B97B8B6B6B2BDB4994C00003084B2B499530E0000004281B6CBC9C6A1500A00002590C8DCD0D5C6B783370000073F76ACBAA5939181431017458FBFCDD4D2CAD3BB812C00054A8DA8B4B0A9A7954D08000621213A70A1BDB0A89B5E1D1209163E94B6B4623966855E2D184317040109277CB7D8D7C19152230C195CA5D7EADEC99967627A80A7B5BFC6B6712200000000033F9792D2D8B36A1D000015253868C0E7EBCBA47C44231F36435CA5D7EADEC9996701FE076107071870723A0C0000104BA9DEE6C39791873C0E00174CA4D4E4D2C8923B0100002663A1D0DCD8C7AD898A63425695BDBDC5B4B4BE934206034599BFC2B3A8AFA592450000337AABB19F51060000043D8DB4C6C1B592460300002A81CAE4DACED1B8772100000E487AB0B2AF99846B360E1B5C9FBED4E0CFD0CDB781390A024290B4BAA6A39E823D09000720274573A6B4A7A8A1672A0B0D164B91BCA362416E895825203B1201090A3088BCE0DDC1843A251C22549FD7F8ECCC8A5D556E7FA1C7CEC7B473180000000006449B88CCC8B16C23050C0D22296BC6E5E9CFA26B4529212232549FD7F8ECCC8A5D01FE08610707188071471606072766B1EBEAD0ABA3813B16111F5EA8D7E4D7CE943E0000002B71B2D9DFD5B8A3879B6D42548DB6B9C7BAB3B38935000052A2BDBBB0B6B1B69E4400002C84A4B4954C0C0000054694C1CAC5B997340000002D8AD5DAD3C4C3AE7120000015445FA6B2B79B8F723614265EA8BDD0D3D8D2D3AF89450C0A55949F9FA9B1A5823F00000C2030567EA6AEA29D97611A080E19539DC0B16C4C6C8155291B44171109153391C9E3DAC08B4D241E2A6AB1E9FFEAC98E6A5D6D87A5CED2CAAB6E1C00000000004EA297D0D1AC621A060014223D77C5E5E9BD91703E151E28386AB1E9FFEAC98E6A01FE0961070718906E41161219336AB3EBF2DEC3B58639100C2E5EB2D4D5D5CE8A3300000B346DB6DED8D3B29882946E576BA7C3C4CBB3C6B97729000053A3BFBDADAAA6A78A3D00003C86ACA38F4B080000115B90AFC2BAB082310000002C88D2E6DACBCFB1671C00001D4A7CABB9B4A98564250B316FAACDD4DCCECCC1BC953D00115D9DAA989CA19F793502001026315C82B0BCA59E8B521C03001751A1C6BB78546B8C54202946210E151D4CA3D3E8D9BC8A4223193377BDEDF8F1C3865B5B6C80AACED6C9A66617000000001563AE82C8CAB15F0D00001423377FC9EAE5BC8B5D3B2227373777BDEDF8F1C3865B01FE0A61070718A07C4F2F1E244181D1FFF9EED0C48F3B190F2E66B6EBE9DFC687280000093482BEE1EED4A38D8B9F7E566EA6BDC3CFB9BCB8801F0005509ACCC5B7A9B1A27F270000418CA4A493440300000E5A99BEC2BFA67D300000002E88C8DED4CFC7B65F1600002A5179ADBBB9AE8F5227113179B1C8D3D4D7D0C4B9814609025B909FA4989E9F6D23000014323E6788B5B0A2AB894E160908245997C1B26B527C854F22214729160F2558B0D8E1D6B17842242A3F74BEF1F0E8BE8A5B4C5C7FB5CFD5C7A85A0E000000002172B78ECACCA85B16000C16264690C9E5D8B07C593220212D4174BEF1F0E8BE8A5B01FE0B61070718B0704A3625315088D3FFFFFADCCC934421113662BBE7F2E9C581280000133E81D0E3E7D8AD89869C836479A3C2C6BEB5C1B2772D000053A3BFBDAEAAAFB0842F00003C87ADAC8036010000176CA5B9D0BCAA72250000004096CFE2D9CFC5A44B09000128607BA3B9BFA990591B0E3E81C1CCD2D2CECDCAB89C4D0E0C5A968C80889A936C28000118383E5B81AAA8A29C8C430D04071655A4CAB67A5F7F8A471926492514263068BEE0E5E3B472472B294684BCFAFFE7BD8057526F8EBCDFDFD9B16D10000000002173B97DB5C69C53140006112E5292D1E3D8AD7A533D2526364684BCFAFFE7BD805701FE0C61070718C0725235363A5EA3F2FFFFFCE7C98B411D123274BBE4EEE6C5772800000B4887D7E8E9CE9C787BA18E687AA8BDC7CBC3C7B37517000B589DBABEB1AEACA984260000418BAEA77935010001226DA9C7CBCAAB701E000001358FC5D6D0C6BDA35305000D366781A9B8BFB3834A1C093C90C0CCD1D0D1CEBBB39E4B0C186F998A80899EA171250000163648739EABADA7987B3709000E2561A5B9B57F66797739122B4F2C2A343872C4DDE7D8AE7B502F2B4E84D6F8FCF6C4805D526890BBDDDACC9E5811000000033477C179C2CEA250150007213B6BA0D7E0C9A06C46392527334884D6F8FCF6C4805D01FE0D61070718D072502C272E61ABF6FFFFFFE8C6893E24263E78CAE6EBE2CD801E00000F4D89D1E0EAC88D6B7BA0826C91B4C3C7C6BBBFAD6810000365A9ABB1B7AAACA9761C00034891B09A6F2400000A4683B1AFC8BBA65D0B0000034396D1DED3CCBE9C4B080010416F88AABABFA67839120E4397C2D2D0C8C9C0BEBC9A5010186393837E829AA2681D000630444F6F9BAFBCA5A07A3307010A2167AAC1BA7962808333162C543A2B2C4288CDF3F5D9A76F4F352F519CD6FBFFE7BB86575C6D9AC5DEDED1A5510B00000002387CC277BECB964B140109193E7AA9E1EBCC96643C2B2622253C9CD6FBFFE7BB865701FE0E61070718E0675541394B75BAFDFFFFFFEBCA7E411F2F4982CEF3EFE2B86D270000124194D3EAE3D0866575A8917992BFC9C4C4BBBEAC6813000C61A0C0C0ABAAABAF781500074D91A193631D0002143E86A6B4C0C49F5506000000389DD1DBD2CFC5933B0400204B75829FB3BDAE7330030C489FCEDED3C8CDCDC2B7A2450B1D74A0876C739494591A00002B4453789FB3B4A3A46E320A06052163B4BEB97E72826D3914354E3B3D475090DBE9E2C8AE734C36304B9BE2FFFADEB07C4F4A6A9CCAE2DBC59C5110000001084491CD71BFBA973A080312193F78B9E0E0CE925C3C37273037479BE2FFFADEB07C4F01FE0F61070718F07C5E4E50608BD7FFFFFFFFFCCF834524305F8FC6F2EFE7C17126000019529FD4ECE3C7866178AC938197BCC9D8D4CBC8A85507000B6AA4BCC0B7B1BBA36E1500084F86A598641A0001234386B1B8C5C693490300000F4CA3D7EAE4CFC78D3607032A4C73819EADB3A9692E0C175B9EC6C8C9D7CBD2C3B7975418216D93796870909055160006344A537DA2BDB6A99C742E0400102068AFB9AA817387662B163D55453E495FA0DEECDDBEA57753393356AAEFFFFFE2B27F5B5A6D9ACFE6E0C1924B090000001555A1D26AAFAE86390F0A192C4C83BDD9DABB86563A302F2F314EAAEFFFFFE2B27F5B01FE10610707180076533C496090D1FFFFFFFFECBC743321355A92CAE9EDE6B264250000135AA3DFEDEBCC865170A28986A1C0C2C7CCCBC19D5106001065ACB8BDAFB7B6A2581000135B8FAD975112080F23548FB0B9C7BC8E3D0200000C53A5CBD7CFC6B79032090137618B8A96A6B1985E1D061F5EA1CBC5D4D5C9C7CBB89D4D0D2672906A52628487571100003C526187A6B5B6A9A1792304050F327BB4C7B688758A5E1E11305C4E485069A9DDE8D9C6996D433C394EABEEFFFBDFA17561596CA6CDEBE2C4944109000000165BA1CD62AEA67C390F000E234C8BC0E5D1B97C4C3735312F3648ABEEFFFBDFA1756101FE116107071810735446496597DDFFFFFFFFEABB7F3C2E3D6EA3D3EFEEE8B5611D00001C5BB5DEEBE6C170476EAA908AAFBFD0C5C2BFB28D4900000868B9C2B6ACADA9A65813001A6A98A67D440F001334629EBABDC9B48432000000115EAFD9D0CCC5AE7B2A0209336A888A9DB2B2914F0F0A1A68B0D1CDC4CCCDBFBEB49849121E748E6C516A93945810000936536E9AB3C7BFAD97661D010215387BB0C0AA857B7A581617485B50464972B5E2E7D6BC8B6351473C6BBCECFFFFD39B5D52546FA2D3EBE4BF8D46030001052068B0CE62B09F83381414132764A0CBE9DAAD74402C3838413751BCECFFFFD39B5D5201FE1261070718207A554F5B6FA8F1FFFFFFFFE9B17037304982A5C7E0F3E9B6631500022762B3E1EDE0AB61496FA49997AEC6C7C4CBC4BB8F4200001869B4B5B8ACBAB9A0510A0629689B997F42030823406C9BB0BACCB674230000001973B4D6D5D4C2BC802A05043C7A9793A6B2B38C49110A2771B6D3D6C4BFBFBBB5AA9B5813256D8F5E3E52848B460E000D3F6A7BA1BCC4B8A99F5D1D00000E3576B3C7B0867F7B4B13184A534D465E82CDF5EBD0AD815B4B434A7DCDF5FFF6D4A174515277B1E2F3E0AF783803000000347DB7CC6099906C3713071E286BACD5E9D3A67542353430444456CDF5FFF6D4A1745101FE136107071830776E666983B9FFFFFFFFFFEDAB6540425F95AEC1E1EDE5A9541A00002D70B6E6EEE8AF664066A19495BBC8D1D7C9CFC0923800000B6FAAB6B6B7B7B6A24A070039799EA4753205052E4B73A9B4BEC6A55D170000002273AFCADECFC0AE671E07115380A3A7BCB9AB834207092D7EBEC6C5CABAC3C6ADAA985917277B8A58365C8A7F3D0C000C4465769CBBCAB2AB9F58210000153E85B8C9B0928C804E1F1C465950545F8DC7F2E7CFA279604A4C4D87CBF9FFFCCF96604A4E75AFDCECDFB77B2D0F00050A3581C1CE5D92875B320E121A3A7AB0D3EAD0A366332B4043374757CBF9FFFCCF96604A01FE1461070718407863526589CAFFFFFFFFFFE49956393E609FB6C6E6EFE3A44D12000C3E72C0ECEEE9B55C3B67A1999EBCCACED0D0C9AE802800001771AFAAB7BEC3B59748070C3D819AA9712A0A163A5B7AA2B5C3CDAA570D0000002E75B1CAD3C5C2A2631C131B578DA5A5B0B7B279350901368DC0CEBEC0C5B9BFAEA38D56152A7288524051807A430A00154E697FB2B7CEC3B09557160006144383BEBB9B84837F4313205D65585963A2D9F8EBC594715B404B5491DEFFFFF7C4845A495082BEE6F5DBB06D2A040000094090C3C95D85765D2C0F232F4177C1D2E7CBA0593D373D39343966DEFFFFF7C4845A4901FE156107071850736D6B7B9DD8FFFFFFFFFFD58C53364473AFBDC7E8E6DB98491905114385C2E4F3D999583C6CA19CABC6D7C9CDC6C3A1722A0000166CB1B5B0C1C1B68E3E000D4F88A7A3672501134D668CA9BACBB68E430A000000307BABBDC8C2B8A85B1207277095ABA0A5AAA4702D00053D8FC5D6C5C3BEC1B4AF9E8F511A2B78814F2E5480752F010021527A89B2CAC4C3B8934F14090D1D4F88BACDAA8C8C733B0C1D556A63586BA7E7F1E6B689644F494F6098E7FFFFF6B88F62515677B2E3F2D3A67126060006164D9DCCC559736C4D2312121C4488CBDCEACF8F563B35363D414867E7FFFFF6B88F625101FE1661070718607369647EA6DFFFFFFFFFFFD58442263A73BCC4D1E1E4DC934714091A4380C4EAF6D7A04734669C8FA7CBDED2D6D3C0A4682100001875A9AAB4BCC4B4862F081B6290ACA467260A17507495B0BBC0C3883D010000073F77ABBCC3BDB78B47080D3876A5ACA8ADB295551C000F4A93C1D3D7CEBDBCBAA8998052112D7B7D50384D716D380D001C577A93B4C7C5BCAF9A501D020B285E88ADBCA68D896F300326706A665B81BAEBFDEAB27B624D4D465CA3E6FFFFEDBB78624A5584BFEAF1C49E5A1A0000001657A7C5BD5D7B5E4924191E25438DC6DCEDCD8F4B253F4F4A3F446CE6FFFFEDBB78624A01FE1761070718706E707087B1EFFFFFFFFFFFC3763C3B4F8FCFC9C7D8E0CE82381211235A81C0E6F1D9A15435559E9DB2CDD9D0CFCBC195612100002275B9B6B1C9CABA9031051B5F9AAC9E5F1B0B275D82A9B7BCB7B77E2D00000015407B98AFC1BDB0823E140D3877A7BAAEAFA68C5417001259A1C7CED1C6C1BDB9A4918F470E257782523A4E7061240F011B5B899EBCC5C6BDAA984B0A02113162AFC5C09F82826020052F7570676185C6FAFFE2A9745A5A544466AAF1FFFEE9B5725044587EC2DFEBC68D49211005102376B7CFB24A7059432B1A1A285D96CCE3DDBD7F46333C4B4445476CF1FFFEE9B572504401FE1861070718806F64607BA3EEFFFFFFFFFDB65633365C9DDAD8C3CDD9C3782F0D1A2D588CB9E0ECD08B442C5491A7C1D2D9D0CFD8BB91511400002B83ABAEB8CDC6BD852B05206BA5B5B162200B2F7292A7AFB6B8B36E220000001852839DABBBBDAF7C3A0A10428AA3AEA9A89782491200146DABD1CFC5C1BBBAB39087804016287D884F36527A572407001E6497AAB8BFBAB5AA944B2713103263A2C6BFA79176581A073B797D797792E5FFFFD29C78645F524D75B8F8FFFFE0A86B57405188CCEFEDD298531B0A03052C7ABAD0AF485A443726241E285BABD4E6DBB17C413043504E4A4E81F8FFFFE0A86B574001FE19610707189074697187BEF6FFFFFFFFFEAA5C302F5FA9E6E2D6C7CEC16C301D1A2F5B8BB5E5ECC7853E2E5D92B1C9CFDBDCCDCFB9834B1800002A7FB8AAA9C6D3C07D26052A709DAE9E5623163B7A96ADA6B6B9A95B1100000625588893AABDBCA06F2A0D1D5B9BADB7A5ADA5823B0A00186DBCD8CFC0BCB5BCAE8E746F4621328089533C53674A210D07206391ABC4CDBDB2B2883D1308153676B1B9C19D7E80521B0E42836F62639BE4FFF7D2925D5655595480C7FAFFF7CE966750475889CBF5E8BE874A1D04030B307ABECCAE424F42322124273A66B1D0E0DBB06D47303C4D4A445193FAFFF7CE9667504701FE1A61070718A0776D708FC3FFFFFFFFFFF79D4B2F3966B9EDE2C3CFD4B5612C1A1E3C5A86B0DAE0C27644345297B2D4E0E6E0DCD4AD6C350C00003187BAADB5C8D9C4771D083483ACBBA35E1816467EA5ACAAADAF934707000016386D94959DBFB995521A102E709FB8C3B0ADA4743206001E70C3CFD6C4C2BBBCA1786E68381B327483574147554A25130C23609EAECECCBEBBB088370B051F436FAAC2BFA0918150170E49827C6D7BBDF2FFFFDD99665C6D656294D7FFFFFACE955F4540508DD5EEE5B57F3C1401071542A2D0C59D344C3D26142122377DC4DEE9D8A05A38313F564846599EFFFFFACE955F454001FE1B61070718B0786D7393D2FFFFFFFFFFE79536263F6DBBF6F8D5CFC2A95A2E202A456285AFCED3BC753C2D5499B9D4E2E0E0E3E0A86D431704002E86B6B0AFCDCEBB69240B3C83AFBA9F541A22518FABAAAFADB48E430200002745798C839BAEAC875418082A77A5BAB6B1B3996D2A0300277CC3CFCFBFBCB6AEA37B696239223B6B7857474D5A2C1714122B74A3C1D1CCBDBDB37E42220F1F4B8DB1C5B4A27E6640120D4A8D787996D7FFFFFFDE93615670756F9ADAFFFFEBC38E604C4B5495D2EDE1BC79350A040510519ECCBF983647332C18222F3C7DC4DAE8D4975A2F373F594E405D9BFFFFEBC38E604C4B01FE1C61070718C0716E7498D4FFFFFFFFFFE18E38243B77CEFFFFD9C4B0914B2E2736466C80A3C3D4B566322E5394CAE5E9E0DCCFCCA7673C110404409FC8B8B4C7C9B764171A498BAFAE93591F26699EB3B5BCACA682330000022B437B8B8398B69F7740130F3E7CB0BBBBB7B19A592000002683CAD4CCC9C3B8B59268605E2E1F417D96694F4D4B332016082768A5C5DAD5BAB2AA75371A0F225090BBCAB8958C6036111C5D8D7A7386D6FFFFFFDA985F557B7873A6E1FFFCDEA77A5136455697D6F1EBB4823D1300010D55A3CBBE80283430221515314D95C6E8EADA944C2B233A59474A72AFFFFCDEA77A51364501FE1D61070718D0807E7F9BD4FFFFFFFFFFDA793B2D4787D8FFF8D9C1A77C3B20293D657B82A3C6C9935A2324589AC6EAFCF1E2E0D6995F3B120B144E96C0BBBBC7CAA8651B1C528BABAB95461227699BAFBCAFA6986F1C0000002C5B8A928793B8A370380F1F4988BCC1BFB4AD884F1A01033A8BCAD9D6CBC6BBA58762575C392047898B724A52402B2019162B72ADC4D4CDB0B0A47C38190D255996C1C5B79C87602F0B1F5A8F7C8CB4E0FFFFFFDC886167858283B4E8FFF4DDA26C453B3D5FABDAF5E9BF72280D02061865B4CFC0782D36281B201E214C92DDF0E9D5904C312F4956485177B8FFF4DDA26C453B3D01FE1E61070718E078737B99CDFFFFFFFFFFCF7F39364A84DBFFFFF1C697673423385375837A8CB2B3864E2924539FD1E6E7E0E2E1D494583C290E1651A4D3BFB6C3CFB14F1C215188AAAA903B214076A1B7B5A7A99A65190000083362939D8791AD9A622E0A14598DAFC0B2B2AB8F531F0004459BC7DBD9C4BFB2A27E61625432294A827E614E4235262325202C76B3C8D1B5ADADA269392420306BAAC3C6B8A58458270C1B6D937A8CB5F1FFFFFFCF8958608C8086B3EEFFFAD6A1704F383856A1DEE9E0B0712A0802072272BFD7B0662E382B1C1A1D2A5AB1DBEBE4C989452E35475E535576BBFFFAD6A1704F383801FE1F61070718F071767F9CD5FFFFFFFFFFBF6E3C344F90E7FFFFEDC68D5E292C3F5C7C8A828FA3A2763D232951A1E5F4EBEDE5E6C486563D2E0D235AA8CECBB9C0C9A959212A628FA7AE8C41233A74B3B2B4B1A3925E0D0000094782A9A9878D99824914011E5491BAC5C0BBB89555130000409ED3CCD2CCC2C2A0735362552D20508F906F553A2525251B172F72ABD0DDC1A0A99E6A38211F3878A3C0BCAD9E864A1803226C9A7B89C6F6FFFFFFDC824E618A8489C4EDF5E7CB8A5D402E325CADE2EAD4A95F2502020D3387C4C9AA6724282B2220223068B4E5F4E5C9834A2C3C445646547CC3F5E7CB8A5D402E3201FE2061070718007C7789A8E2FFFFFFFFFFAD6B3E36529CECFFFFFFCA814D2A2938678E997E7C96966F3D222D52A5E2F9F7EBE7EACF8F514437242561ABCFCEBABAB291401C306792A7A27D39224581B3C4B8ACA4914E000000105E87A1A08383A67D48140A1F5D99BBC2BCB7A6813B0800043EA0CADAD6C5BFB7966643574F343B569595745443322A231A1B397BAEC2CAB49BA49A65352A1E397DB4C5C1BEA272531F10326D9A8298CDFFFFFFFFCC8656678B929FCAF0FFF7C884533B30356CB4E5F2E3AD6D2C09080B2B86D5D09F6125201F1F20263670BBE5F3E7C1773E292E4B6156578FD0FFF7C884533B303501FE216107071810717C83ADE5FFFFFFFFF0A3653437589BF1FFFFFFC67E431924517DA4A68E7A908A612B1A1F469EE6FFF8E5DEDEC37E4E4943242273BCD4CBC0C7BC9140233A7091AFA075342E518FB7B1AAAFA18C4000000020628DA49D7E85A3772F090C36679FB2C8B7B0B0883A00000048A5C8E3D3C2BFB6906C4752553D3E648D9177583D292530301F3983BCCBD2B39C9C925E3E342B488CBBBDC5A49C713A150229789C839CDEFFFFFFFFC570495D8E8D9AD5EDFFEDC58856452D356EB5E6EAD29B591D030B0D4599CDD59D551E1B201F171F356CBCE5F3DFB985332C343F534D5AA1D6FFEDC58856452D3501FE226107071820757B84ADDFFFFFFFFFDA905B374267B0F3FFFFFFAE63231430588BB7B389737D69362212205CB2F0FDF9EFE7E2C67D4E4C482B2A6DBFD7D0C6C7BF893821416290A99C722623589AAEB4ABA8A7863A00000022759BB3A87C84966B2E06003270A4B9BFB9B3AF892E00000049A9D1D6D9C3C0B585654E595138487195A5844724202532271F387FB6D3DBB1A18E8D4A313228468BBAD3BFA9A06C2B040739809A7C95DCFFFFFFFFBC6D48598A899ED2F8FFEBB0754732313873C1EDF0D0985524080E134BA0D6D49651151D2020272D3E7DC2EBF0DEAB653A2D3642555564A5D7FFEBB0754732313801FE23610707183079747BB1EAFFFFFFFFC98053354A71B6F5FFFFFFC2641B10326498C0BB94777A5D331B031A50AEEEFFFBE3E2E4B9765C625D3A3C84C3D4D8D1BDB26C2A1B477B92A4A2732B215D9AA8ABA7AFA3852A0000023378A4AF9C8788925614000B387EA8B6B1B1A6A2772A00000752A8D6D8D6C9C6B9894B4C5F4E414B769BA181512B1322322D264889B7C6D9B6A0A27A41303B385591ADB8BCB29665320B0C3E88A27398E8FFFFFFFFBF75575D8695A7DAFFFBE2A0634136314783C4EDE9CF904E240E17205FABE0D69545191514201C21397DC2EEFBEAAE63311F344D595174B0D5FBE2A0634136314701FE246107071840707580B0F6FFFFFFFFC5814B3C4C77B9FFFFFFF7A64D0E023479AAD8C4987B704229100B1E55B9EFFAF9ECE8D6B06257705E35448ABACED5C3C3B36B2725518099A799622731699EABA4ABA9A17E3400000B4385A6B5A18C8F854D0800024182A6ABABB3B5A5732401000E5BAFD2DBCFC1B6AE7C524760564B6984A9A58545150C1F3B322B4687BDD7CBAF9292713D323B325B9BB8C4BDA795652708124C8D9C74A1EEFFFFFFFDB7794764868AA6E1FEFBE2AC5E4033324997C5F0E1C1865525091B236FBADFCD9047110F151F1A2B418FD4F2EAE2AE5E3626354D4C5479BBDDFBE2AC5E4033324901FE2561070718506F7984A9E6FFFFFFFFB86F4530406FC5FFFFFFF9A545090C3B81BCDDCD9C846A3817040A225CB3F3FEEAE1DCCFA06C65786745478BC3D4D5CAC1AB682124658E969682582E31779CA29FADB0A16C1B0000134E93AAB8A88387883E0000114F899DA5A5B3B5AE6D2800001260ADD2D1D6BFC3A87A5240514B4B6799AFAE79411B0E314035244182BCC7CEA98B90633D41403F609FBDBBB7B29A531505043B8EA17FA7F6FFFFFFFFBC6D4B588D91B5F1FFFFDAA161423B355B98D7E7DAC27E3C170D0B2674C0E8CB8B401211111E212D498FDAF8FDE1A557353332364F5883C4DAFFDAA161423B355B01FE26610707186077828BB1E5FFFFFFFFAC72403C517FD0FEFFFFEF92410009418BC8DAD1A485633814080E2D53B6F7FEEFDFEDD697606C816F414895CBD0C3C1BB9C521B1F679B9E8B8157263C77A09C97A7AD9F6D1E00001A548FA9ACA29494813A00011D5E94B3A9A2ACB6A1641F00000C62B1D9D7CEC4C1A77B4A434E48587293AAAB77390D0F3347371F4D86B7D0C9A19A90633F3A424D6C9CB9BFB7B091541B00104D929D7C9BEAFFFFFFFFB5683B518B96BBF2FFFFDA95573C36365FA1CFF1DAAF703C200F052A81C8E3C78336141524242828418DD8F1F5D59D532E252D42584E88D0D8FFDA95573C36365F01FE2761070718707C8392BBE7FFFFFFFAA05F473E619DD1FFFFFFE2882900044299C7E8CDA7805F200900002557B5EEFFF1E4EBD4926F7587794A5999B7CBD3CEB87D3C1528709A948F724421407E9F9D92A1AC975B0F00002A6CA3ACB4A6988C71250000186FA7A19597ACAFA65F120000176DBED6D7D4B5B6A6684C4D4B43577DA5B7A9773E0E0D385440365088BEC8C2AF9F8E513A4C485370A3BABDBEAA84360B000F5493A180ADFCFFFFFFF9B36B485D8692B8E9FFFDD99961413E3660ABDFF3E4B074321E0B173089CCE4CC7D3C101B0F1A1C3255A3DFF6EBCB93472D2C2E3B49629EC9D3FDD99961413E366001FE2861070718807D8393B6E4FFFFFFEB8F4D3D44558FD9FFFDFCDF812F00044DB0DFE8D3AC8D501D0000031F5EB6F5FCEEE4E5BD775E7FA27E475C96C3C3D2BFB27B291C31799C918373451F3C869F8E859DA68E530C00013475A9B3B2AF9C8A5F2200002B6DA9A1838AB2AC95520A0000196EB9CECDD8CABBA569463F3B4E5786A7B9B87A2A040B44624B3E5597B8D5D0A49A804C2E4C5C506AA8B1B5B3AE8A3B010016558F9C80A6FAFFFFFFFFB06D48577688BCEEFFFFDB9057413E3B76B8E7F2D5A35E391B0C11398ECDDDC67B2D06141D25202F5BA9E2F1E3C7884836412E3A4858A9D7D4FFDB9057413E3B7601FE29610707189079879DB8E1FFFFFFDB87463542608FD6FCF5F4CD731D001657AFE9EAD5B7884810000004326FC3E9F0E1D5DEB67E6183A88051619AC2BFCDBFA46F2E1F39799A82796C3F274A80937A7A9CAB96530B05103F7DABBBACAA9C7D4F12000B3F7DA08C728296AD93480C00001E7CBED2D7D2BDB99964424043587C9EBCBAA96D24071243654D3A5C92BED1C4A48F72424250624C71A6BBB8B0A583370000165B9A9A6C99F1FFFFFFEEA9564452748DBBF3FFFDCA89504E3F457FC5E4DCC095592E190E143599D5DFB674240C0D11181C2F5CACDEEFE4C1884F393031324269B2DCD4FDCA89504E3F457F01FE2A61070718A0748FA1BBD7F7FFFCCB743D3C3E68A6E0FFFDE7BB631A00125BB6ECF4DCCB984608000000346AB6EFF0DBDADEB682738EAB824A67A3BCC8C1B39B5024133D85928F78603228588D978884A1A37F3D1200195988AFB0AEACA782460D00054088A88E6A78A7B396490B020A2784CECECFD1C1B28F554632405774A0BAB7A96520000E4B644D3D5DA0C1C8C9A9916C3D3A5D5E5A76A8B8B4B8A3792D00001E6D9E9A76ABFFFFFFFFEA9D5D4D5D8397D3FAFFF9C88B5A49455290C9E5DCBD925A31160B124495C8D6C0702D0D0B131324365FB8E5F1DCB17F504035333A5377B8DECEF9C88B5A4945529001FE2B61070718B0748A9EB7D4E6FAEFBA5C2C2C466CA4DFF4F4EFBD5C18001164BCE7E9D6C094410C0000062F6BC1E7E9DCDCD9AA75779FAA834A60A3B0B8C6BD87461C172F859686805F2B2E6A95996E819A9F72370906295D8DAEACAFACA3783F00000B5696A47E6275AAB0863E0E000C3787C2CBD2D3C1BB8E533930396093B0BCB8A55C1A021B4D76634F6F9BBFCCC2A1955E394565716089ABB7B4AE956C1D000020649FA778ABFFFFFFFFEA9D6448597FA1CCF4FFF0C27A594D4C639CD0EFE1B68C643F1C0F1954AED3CEA55D2008131B24323469B8E7EFD2A67D48343135364D7AC5E9CAF0C27A594D4C639C01FE2C61070718C0717E94A8B8D3E5D38A452A2F4D73ABE5F4F4EEAE5214001166C7EEF0D2C88D3F000000032D6DBCE4EAE2E1D2A77379A0AB795570A3C0C0BFB7833B1913387D988B745B2F29639791787BA2936220010C3876A0BDACA9A09C672D00000E4D9BA58463799CA67F3100000C3893C5CCCFD7C4B18A513733385D93ADC2C3A35B1104175171615A82A7C0C6C3A98D56323C64746E8AADB0AFB7A16F200000226EA4A182B5FFFFFFFFE99B654D5183A0DAFFFFE3B37A5B57597AA9E1E7DFB1805330160D215CB2D1D2A0652D0307131B283878C5ECE3CEB27F4C3A2D2E30468AC5E3C1E3B37A5B57597AA901FE2D61070718D06F809DAFBED2CDB4733E202C487EC2F2F3F6D79A4209001063BCE2E6D9BC812F0000000D4173C6E1EDE3D8DDA96B7AA2AE7D4F6C96B2BBBFAC7D300F173685A7947C4D2E386C9394707D97864E1003234A85B5BDB3A8A499601C00001160A4AD7D5D80AB9C7831040218438EC6C9CDCCB6AB83433423296999BEC6BFA4560600215A7A6A6084AFC3C5B9A985472D446D7E6D92B4B3B5BBA3691400001F67A79A70AEFFFFFFFFDC8458444D7E9EDBFEFFDEAC724D4A5782C2EDECD6AB8454372B173B75BED0C18D541C061317191B3E88D5EADDC28F7D51423E3D354E8BC4DAA9DEAC724D4A5782C201FE2E61070718E07C909AA6A8B4B4A3612D142B5490C9ECE9E5D28C3303001C74C2E8E9DBC17B25000000084988CDE8E8DCD8D19F6D7FA2A6756282B5AFAEBAA6732B111748809A8A764835417796856D7896833C05001B548CACB3B2ACA28B490D00002266A9AD7A617BA2A46528080A224DA4D8D5CCCCBBAD7C48301A326AA7B8BDC09B4B11041F5D836E6A8BB8C6BAAF96733F2D4D78777592ACB3B0AC99590800002F7FA2A372B1FFFFFFFFCB835A4E6186C0F2FFFBD69C725C5E6891C2E7E3D4A3744E3F272D4082C2D1AA7E451501110E141D4390D4E9D0BA987F6046373C3B518FCDDBA7D69C725C5E6891C201FE2F61070718F06F929E9E97A0A37B4716162E5492C4DCD5DFD0893200001475C4DBDFDBBE751C0000000D5394CAE4E7D8D5D18B5D83AAA5735F7FA6B4BFBA9D5B1C0D15488596947D5036487E9D83747F8868310503306C9CB0BBB2A3A1863F0000002572AAA06C5575AEAA5C22040D2257A2CFCEC7CCBAA4723D2A153984B6BAC6B98B4005001A598778729BBAC6BCAD9B6A3E284D767984A4B8BEB0B88E470F0000227A9EA394CAFFFFFFFFD384584D618FC9FFFFFED29B746B6678A1D2F3EBBF9A74553A1B264A8CCACAA373451E000C1617314F93D2DAC7A88B7D604F39303A5A98D8D39ED29B746B6678A1D2 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 61440 61440 0 01FE306107071800718E909694927C5C2809111E4A91CAD7E9D9BD681A00001871BDD3D4CBB2751D0000001F5F95CCDEE6D7CBC78E6D8EAB94645F86ADB3BDBF9F5312000D448FAA9F7F4C38477B8F7B788180572100032E71A4BBC0B9A8A37C380000002A80A99F786B8AB09B511800102E59AADBCFC6D3B39A6D3022193B7FABC3C1BE893A000020657D706E9CBBCDC6AE9C66342D58787B88ACC3BDB5AA8A3D0000003889AEAB84B9FFFFFFEBB67552466693C9FBF9F2C39B7F727685B2DAEDE3C68F6F4F2D1F3C5E94C0B8925F3718061811172F59A1D7D9C2A1847F69523D3332509FD8D195C39B7F727685B2DA01FE316107071810748F9C8F837D6E490C0000225FA0C8D7CCD0BA5D130000267CC5D8CDC6A55C100000001F65ACD7E4E4E1D3BF8D6D89A593625F8FB0B0B7B4A252170D165295A59F7E413654879676737B784A0E000C3A8CAEB4C2AF9F9864270000002A78A397766F87A98544120A163E77B8DEDFD2CEB49C5A2A12103A89C0C4CAB78C3F080015557D7D81A8C4C6B1AC96622925577B8490ADC3BEB1B188330000003A83B7A281C7FFFFFFE7B4744F4D6D97CBFFFFEDB68A7F7F7C95C7F0F3DDB6936C392E364272A7C4B5845A3110000E1D23395FACDEDEC4987C887A5F3F283B5BA4D4C781B68A7F7F7C95C7F001FE32610707182072819283826345190000001B62A5C3D2CDC39A480200002A8ABBCFBDB89752140000002B6FB0D8E3DED3CECA8B698DA48C636D98A1AAB1B59A51230A1B5791A99A7441465B86927A737C5E3A0600044389AEBABEB1A892561B0000003488AF9D777091B4834914001C4978BEE2E2CFC6A2825326070F3A8FBCC7C7B2763401001A55847B89B2C9C5BFAF94571D1F517F8696B0BCC1BCAA7E300000004090B3B08DCAFFFFFFDAA5785B476495D5FFFFE0B1897C808FA0CBEDF1DCAD86654B27285885B0CEB47F50230C000B10203C82B6C3D4B287798785663A303871B6D8C276B1897C808FA0CBED01FE3361070718307989947F7C63390C0000002070A6C2CFBFB98F380000002F8EC8D1C4B78645040000002F83BED5E7DFD0CDBD856A8CA981596F92A9AFB5B5904E1710295F979D98794349639492787B76541F00000A5097BFCABBA9A48C47050000003C8CA7977E8199AB71300E05244D7CBDD1E8D3C4A2824E1D090D4192C6C8C5B37C2F00001C51818791B4C3C8B8AD8B4E212650768C93B0BCC7C2B1741C000000438BB4AA90DEFFFFFDCB996249516CA5DCFFFFE5AB8589969BABD1EBF0EAA67960412D3F5B8EB9C6A16339220D101115214483C6DAD09C716E917F5931283D79C4E1B86DAB8589969BABD1EB01FE346107071840718F817E6C552E000000001571AFC0C4C2BE902F0000003A8EC9D8BCB0793000000000388AC2D2DAD5D4CCC4826C90997967809AABADBFAA81491D0C246B919E9D79475E688F8F83856F401200000D529CBBBFBAABA07B390200000F4996A99A838F9EA2672A0910215A93D3E5E4D6BB8F65300B0C0D439DC3C0BEB778230000195983929AACC4BFB5B5904B1F21577084B0BBBAB7BFAD6E200000004E92BAA79CD6FFF3EAAC7D58524A60A6E7FFFFDC94788792ACBED9F4EBCB93665B442B41579CC3C4975E2D0E000F0F0B1F508CC9E2CC9C716A8C8F68402B4F91CDDBB05C94788792ACBED9F401FE356107071850818A8480764006000000002070A9AFB1B6A56916000008409BC9CFBDA87129000000043798CEE5DED2CDCAAB82748C9071577DA8AFAAA8A07B43130A225A8BA5966D525D73959988856B320500001B69A7B7C3BEA8937436020000185B9AAA97859AA78D5F200210397398D2E5E6D6B77F4E2312051A48A8C6CDC4B37526000016508B9098B6C1BFA6A08A4B15214F7890AFCBC6BDB598560C0000034E8EB4B19FD8FFFCD3AA7C493B4664A3E7FFF4CD886B788DA7CFEAF4E3BF8B654F3926486BAEC2C38F4A1E0507180E1A1C4991CCE1C78E676C908E613C30499EDCD8AB5E886B788DA7CFEAF401FE36610707186077807876703700000000002E80A5ABB3B4995E1A00000A5492B3C6B9A261140000000D4AA0CFDCD6D3CBC9B3886F9C9D6D6990AFA6ADB19F6F3A1F102064939E8B5E4E647C98928C855D19000000166EAFBEB7B8B2A1772B05000013649F9D9091A3A989501B0E17417AA1D6DECAD0AA724C1F050C205DB0CEC7C6B265130000185096A29FACBDB7B6AD8B3A1519456784ADC6CCCABC9E59030000035197BBB59ED3EEDAAE7E5A382F4265AAEFFFF5B6825F768CA5CFDEF0E9C37E5A4727264C7EAED0C478351C1000221E15285BA5D5D7BE865E5C888B5B452F609FCACD9D4C825F768CA5CFDEF001FE3761070718707E736F6B663D00000000002D7C9CA8AAAF954C0100001B5C9EBDC2B192430D0000001C5FABD3D7D5D5C5C8AC706991846F6A8EA1A5B0A7A37943251620629CA595634C6F8994868D814E110000002172ACC7C3B0A9A07525000000266CA4A5A09DA1A67B3608041D4D8AB4D6E2E2D5AF67380B00041862ACCBD0CCB0671A00000D5598ADAFB6C8BFABA27D37131F49688FACCBCAC4C5973E080000005198B9B097C0CABB895A39251F24599EDBFFF2AD6E587385ADD6F3F7DCA676503C2C316687BBC5B2762D1D000036231A2B62B0DBDAB176485A898A56304075BCD2CD8D486E587385ADD6F3F701FE38610707188079766F7B68320000000000488C9FA5B3B08C380000002E74ADCACFAB7E37030000002369B7DDE6D8CDC0B3916A709381668199ADB8B1B69E6C3A240E18678EA98B5D5E7B819A91917E4807000000266CA7BBB7B4B7A672200000003174A8AAA6A7B89A641D0706225992BCDBE5DDC6994D261000041768B8D7D0C9B35B17000010528DB0AFC2BFB6ABB3852F0A15446195C0D4DADBC48A37000000095795BBB09BC2CAA8714A2C1A2027599EDFF1D99A6A536A8BBBE6F0EAD2A15A3F3A1F306197CACFB5682B160003442A1C2C6CB0D7D2AC67455781835F3B4C84C6DCC38A3F6A536A8BBBE6F0EA01FE3961070718906F74737E653100000000085183A0A0A7AA83300000003581BAD0CAAA772A00000000307EBFD5DCD7CDC7B691617095856B8297A4ABA1B39661312516306D94A17E52597E9B9A9A988134000000002B7CABB3AAB2A89F5D230000083F83AFA69CA8B296602E040E316F93B9DCE0D2C69F51110000012C72C0D2CFC5AB5F1C000715468EA6A2B0BCAAA9B989360F143C6194BDD0DDCCBD7F310000001A5BA5B7B6A1BFB68E65391A1422304E90D6FAD7974E456595B8D9F2E7CA98563A2D223569A5D1D2B66F2A0C0C04542E1F3272BCDFD7A2573737788E5E40548FC7D2BA76334E456595B8D9F2E701FE3A61070718A0737E737F6730000000000968A4A1A3B8A973230000115A96B2C5C1AC6A210000000E4C8ECEDCD8D6C9BFA17C556B8880738C9EA7ABA6AA8B5D472D15266591946E4F6A8790A89B8F7425000000003380B6BFB5AFACA3601D00000A4691B3AA98AEB1904F130A17317BBDC5D5D1D1C09339020000072375BBC7CBC1B2622400001E5192B5B5C1B6A2A6B47632151A3D61A3C8D1DBD6BA781E0000001C65A5B6A996B5A772402F20150D27469BE0EEC4814E3B5188C0E0F0E9C9894B31301F327BABD9D0A95B16080000583B234384CDE4CD9550313A747D5F3F66A4CCC7A960304E3B5188C0E0F0E901FE3B61070718B06C7F787856200000000025769FAA91B0A766190000235C98BDC3B99F52110000001E4A91CBE1DFDACEC5A4654C678D857A94999CA6B0A589523C36213478AB9C684D658F9FA4909B6A1900000000377BACB8ADB2B6A1581A0000164E9EBAB1A4B1AC7B441106134985BCD6E5D4D1C2892700000009397CC5D2D4CDAD5D11000A1A4F9CB5B5B2B8A4B6B47B2807103367A8BED7D0CDBF6D1E0000002168AEC3B88A9D82553016090B0E103C8DD9E0AF7B3F38608CC0E8ECE9BD7C402718163C83C4D9D3A8511D000001613C264991CFE1D49C5139416C71544E75ACD1D2A161253F38608CC0E8ECE901FE3C61070718C076798C8D6029000000003A86AEABAEAE9D5E1400002D72ADC3CBC19544110000002E67ADD6D3D4CEC5B691573B658A7970A1A09DAEB7B38A4D443F1A2E769A8E67456B95A0ABA3926610000000183D86B8AEA8A0A395580C00001D5DA9BDA9AEB0A367330D0F194C92C1DDD2D6D0BE842A000000003888BED4D6CBA84B090010205791BBAEB5A6A3AFB4732F08153573B1D5D6D2C7AF64110000012E74A8BCB78987723A1106030015184799DBE4B8703E304680BFE2ECDDAF74341E0D124289BFDBD6A34A1100000B7136264CA2E3F0D39E512E316366564585C0D6B98F53293E304680BFE2ECDD01FE3D61070718D074868C8862240000000647A1BFAAA4AB924D0600003C82B7D3CEB6854A0D0000003A72A8D7DFD0D8D5B27C382055837676A6A3A0A8B8AA824E534B374980968C5A5180A0A6A4919057100000001C558EAFB1A29DA095510D000C2A69B2C4AEB8AC9B5B2A090E21559ACCD8D7C7C8B3771C0000000D4494C7CDD5D29D4112000C204B96B3AFACB0B1B4B45F25010B377DB0C8E5E1D0A95E160000003E7FAFB9A287896335080007080A133C97D4DBAD5E36285294C7EBEDD8A55829181A184895CBE1D6A74411020007773C2E5BA4DDE3BF92502F2E57674B568DBFD8BB874C2336285294C7EBEDD801FE3E61070718E06E7489895A250000000E6CACB8AAA5AE80380400044F98BCCAD1BD8A3A080000144D84AEC7D1D5CBBCA86D31234F827A9BB8A99DB1C0A9683A42442740799C7A585783A2B4AC979855090000002D5294AFB0A6A5A386451304143777B3BFB4B5B19E4D2406072874ACD3D1E3D0CEC177140000000A4C97C4D5CEC59345160006124185B9C1B5A4A4B1A2601C0B164281BBD4DBCFD3AF540C00000B4E8BB4C2AE8E83561C0000001314022D8EC6CFA5562922538CD4ECE2C48F4E1918191857A2D3E9D198470C000002813A295FB0E0E3C08E44302B465E4E6397BFD2AA6936152922538CD4ECE2C401FE3F61070718F0798CA1965A27000000297EC0BEB2AFAF7A3200000B60AFCFDAD0BC7222000000235E99C5C9C2CCCBC9AD6718114B7F7B98BCAA8EA3B798623844543647828F6F525F8CB2B6B1A1864E00000008376AA1BDA9A6AF9D864701000C3C82B5B8BAB9AA8F4616061A3472ABC6CED7C5C2B86F10000000155195C3DBD3BE95360E0009284F93B7B4A89F97ABA2662C0E1F438CC7D2DBD9D5A34E0B0000175397C1BBB37E692F000000051104073997CCC6964A252C5C97CBDDD4B5894C2013041F65B2D5DECA903A0C0600008B3F326EB4DADCB67344222D4952446EB0D4D499662810252C5C97CBDDD4B501FE40610707180075868680460E0000103C86BEC0B6AC995B1E0000176BBDCACFE1BC7428000001267CA6C7C6C1C6CFC79B440308407084A4B9A28FA2BE9C553150493468979B6F5B5A8FB7B8BBA6812C0000001141699BADADA9A3A5852D0601264B7EBBC2AFACAB883D1A141D417EBEDBCDD6C3C6AE620E0000001758A6D5D7D0B98F3207010A254D8EBAB8AB9CA5B69A5933141F4CA0CEDAD5D2D7AB410000001D629DB1B2AF79693A0000000003050C3997CBC58D432D3767A0D1D8DDB38140170B042970AFD9DAC78D360800040A913F3C7FB7DBCFAF7B5128253F3B4F73AFCFC3905728192D3767A0D1D8DDB301FE41610707181075798E76431200031D489DCDD8CBB38A4A1500002785C3D7D5D7BA662000000D4780B9D4BDAEBABEC58B3A06063C6C98B1C4B09DAAB9914124414B39638E84605A70A2B8B6B8A4802E00000029618CA5B0B5B2B2AE74280000204A80B5ADB0ACA87B300E102B5490BAD2CAC3C0BFAA5B0E0000001B5DADC3D1CEB2823203091826528DB6BDAF9FACBA9F511B0C1E59A2C8C4CCD2CDA0440000002260A1AFADA7886E2C000000000004083E8BBDBA843F22426EAACFDAD3AA6E391B0B133884C6E0E2C9822D010008088B373683B9D2CDA876432822343E4C7FB6D0BB7C462A1622426EAACFDAD3AA01FE4261070718207C86907543170E162D64B1DEEBD1BE854A10001242A2CDD2D8DBB25A18000016539BCFC8A7A9B5CBC4842A00033C75A4C4CAAD90ADBA843F293D4C415F957D575979A2B6B4B9A26E290000013B7298B4BFB2ABA99A6E2503092C588AB0B1AFBAA26C2E1412355E99BED9D0BDC2C59B4E050000002E6DADC7CCD2B87D2501081D364C88B9C1ACA2A8AE9244210C2C70B2CCD2CFD0C8A13E000000297AADBAADA27B621A00000000000000459ABDB8703C23407BAACBD0C19A5732100A184A8BC8DCDBB679250200030C9336428EC5D2C4986D3F2D262942558ABECAB36E35241C23407BAACBD0C19A01FE436107071830788379663B140A1B4268B9DBE5D7BA713708020E50AACBDDEED4974B0A00033067B5D3D1ADA3C2CBC37425000034769FC3CBB8A7B8B374311E3A41366889764B5991B4BCB9C0A458100000004B84ABBDBBB9B5B392510E0011336C90ABA8A29F8A58251820497FAECAD2C5B6B9C09345070000002676B8D1D7CAB4681D08112C3C5D8FB6BEB3A0A7B5894A1D153271A9C9C8D3CBC08B400000003080A6AEB19D725F1700000000000000479DBCAC77302F5D92B7D4CEB3985F381A0013488DCBDDDDAF752B0000000B9345579DC7CBB58E6D47261D2E3A5998CDC59F56331A172F5D92B7D4CEB39801FE4461070718407C856C471E0D12264E7EB9DFEDE3B9743408061D61B6D5CDE3D79C43060009327BBFDAD2B1A7B3C9BE752300072A73B4D5D4BAB1AFAF6A2E1C3334366D8778546D9CB7C4BEBC954E0B000012528CA4BDBDBFB7B7913E0D001648739BB7A598988851271D2D517CB0CEC5C1C1B8A98645000000002F82BBCDC9B9975D0F0011324C6394C8D0BCA2B2A9753313103384BCD0C7C9CAC5912D0000053E85ABAEB49472520A00000000000000549FBEA560302D5988B4CCBEA9824F28110C1A539CCDDFD3B66B200300080B974E5EA0C6C6A2746136291B1B3367B7D5C08E4328131F2D5988B4CCBEA98201FE456107071850656D58461E121B376294C6E5E9E2AF611B0105225CB5D2DEDCCC89370D000A479CD4DEBE9BA1B0C7B56B1900083C80BFD8D4BCAEBEA0561D1A1C23305E6B63587FADC4D1CBB7913800000020619EB9C6B9BEB2B47C3000001D5091A4AA95848A6D3C142A476B92B3CBC6BBBAB9BF8842050000074188BBD1C8C19E5811021631506394BDBCB6A7A8A172401E163F91C3CDC3C4C6B47024000003499FBCB2B68F724A0E0000000000000456AEB89D58383C629ABCB9B39177492615152E71A8D0D9CFA156120000090AA44C64ABD1CB9E6A4D3D1E1F264180B0CDC18D421E0C153C629ABCB9B3917701FE4661070718607C7D6145221D2B5576A4E8FEF3E2A85814000E277BC7DED6DFCE7A260702235EA3DAE8C5A7A4B7CDAE570700104C89C1D8CFAFABB99B4F1A0516152E606E615B88B1CBCFCDB08A310400002D7EADCCD1C5BBBDB97B2B00062A6297B0A6857978582C102B446F9EBDD0CCBDB4B4AA86310000000A458DBEC7CCBA974C0308294F5B689CB5BDB8A6A89C643B1C17438FBDC8C4C8BFAC75290000105898B1B7AF8A6B430000090000000003609DA8835534386B9CB7B8A48265411C120A3075B5DDDEC9914B1200070B0D9B5473B6C4B28B6249372B282F4887BBCAAF73401A1118386B9CB7B8A4826501FE476107071870785F44391F2D3D698BBCE5F5F3E7954F1A091D478FD9E9DADCB9671A010A2B71B8DFE8D2AEAABEBC96480000044393CDD8CEB2BFB994431012100A254F585E6693C2D2DFC8B469230000002E87B0C0C2BFC4C4A2671D00093D79A5AD9F726462482216304D78A2D4DBCCBAADB4AC723B0700001852A1C6CFC3B7863607072751646E8EBBC3B4B4B191583C2427609EB8C7BEB8B3AC732900001D7199A4AAA6766C4208000900000000136D999A83462645729BAFAC8D7A542D0D00154F89C7E4DFC189450C040502149F5F8ABEC4AD855B45433428335292C2C9A5662B1B141C45729BAFAC8D7A5401FE486107071880745A402E272756729FCBF3FDFCE9973C180B21488FD3DCD9DBAD5E22151F3C86C5E6EBCBAEA6BCC093400000154EA6CCD9C8BCBCAA712A0607060A26545C5566A2CCD4DCC8AE6B1C00000A4C91BBD1C1BDC4B8965015041D4A83A5AF97786250341719385F8CAECAD0CCC3B9B3AD67350A00001E569EC3CCBCB48439060838677A73A2C5C4C0B2AB815C412A2B5A98ACB6C0B6B7A86D1C0000226DA1A6A29A616344030013000000001776908F63372E4272A3B2A2866C4E34261021609CCEE4CFB276310900030510A97094BCBB9C6A4B413029274263A1D6CBA15E1C17191B4272A3B2A2866C4E01FE4961070718906C583E3125385C80AFD7F4FFF5D38A38141128559FD6E0DEDAA14B1600204597DAF2EED1B7B5B9AF802600003071B1D2D2CFBDB9AE6E230000000E234C5C5979B1D0D2CCBFA24D130000124E99C7D8C2BEB9BA93480A00225F9AB6A89C71523D1F0B17376293B1CED2D5CBBDB4A6602F0C00041F66A5BEBFC2B57B250816426E7A7D9EBCC0BBAEA68954351E2966A0B0C2B5B6B4A0591800002D7FA9ACABA15A643B0207160000000024759C85663C364B79A9A293795040291908256DA9D1E7D8B378370A01070B1EB4769EBCBE8F613C3D302C2D4073ADD0BE88421B1420244B79A9A29379504001FE4A61070718A06758422E2F4A6A9FC6DDF4FFF4C7763515162D65A3DEE2E8D8883D160C2154A8E0F6F0D4BAABC2A9661E00003C8AB5D3DBCCC4BDB16D20000000002159565D8AB3D3D8CDAB8E390000001E60A2BFC6BABDBABF893E00002773ABBE9C8A6B4939130A1E40648AB9E3EAD8CBC5B0A15D2B0F0109387AA7C3AAADAE6F1F08255888968CAAAFC1BCAFAB744932203273A6BAB7B5B9AF98590A0000377C98A5A5994F5D3F000B1B00000000357F88775B392D4E7BA2A38C62453C341D1C4384B6D4DDCCA86D3E1100060924A97FA1BFAD874C2E33373633457CB6CFB67B3A110619264E7BA2A38C62453C01FE4B61070718B0705A4D4C3F5988BCDEF3FFFFE9B365311A1D4374BAE5DEE7CF86390D123467B0E7EFEBD1C7C9C29D550800045194CADED9D2CAC6AC57160000000024535B6B92CED1DCC89769200000002A67A8BCC6C5B9B5A07925000D4489BDCDA99473411B000019466A97BDD6D6DCD1C9B2895634210C18418AA4A7B2B8AF6015043072A0AA919EB0BEB9B1A06B47322A377CA3A9B4A3ABA88C44070002378AB1B0A3923D5C3706081E10000000468992765436295187A39777584A352E2229518CC0D0C4B89B714622070E1329A095BAB699723831252D2E384B85BECDAF652C1217222D5187A39777584A3501FE4C61070718C070524847495E90CAEDEEFFFFEDAF62291E24477ECEF3F4E1C1752D0B143778C6F2F3EBD2C4C4B8854203000863AACADEDCD8CABB9646030000000025555C80A1C5D5CDBB8F5B1100000B387FB0CED7BEB9A384581200145999CBC8A9947B451800000C3A5F8DC0D4D6E0DACFBC834F33242332569AB79DA6AD9F581C13397EA89D98A1B1B9B7B7976647352D5684ABB4ABA0A3A37F390000004C8EABAF98853B623A080320060000005997956C4F372D5C88AB8C70513C313B323266A6C5D5D2B9905F4631180D183DA498B1BE96582D212B2F313C65A2C5CA9259210E091F1F5C88AB8C70513C3101FE4D61070718D07A635C5C5573A4DAFFFEFFFFDCA85A322D305C91D8F6FCE5B36125131B4A7DCBEEF9ECCFCDC9AF742D00002082C1D2D4D1CACECA9042080000000030646B7BA2CBDACEAC6C3C0B0000104781BFCDD4BBAA9F77400E00176BB3DDC9A39E844F10000009386393C4DAD2CBD3CEAE775847322F3E75A5B49894A9893C140D4588B0AFA3A9AEB1B1A78B584638335C8DADB1A59DACA372360000095492AC9F988221603E0A081C0700000263848A6C412B375B8CA78E6B443B393E2B4B76B6D2DCC5A891644B511E15254CA9B2B9AB7D46241226292F426AA6CDCA8F411C131212205B8CA78E6B443B3901FE4E61070718E0785A57646884C2E8FFFFFFFFCA8A4826224461AAE0F7F9D99D4F1F0E1E5297E2F4F4F3D4C7C59B5D0E0000278BC7DCD7D1C7D0C2974413000000022E63718CB7CFDEC998652A0000001A548ECBD7D4C3A784552301073285BAD9C7A79E8A3F0D000008335981C2DCCFD1E0CE9B7459523F335483AFA89087A280360B10539DC1B5AF9298B0B7AB835A4C303D5E8FA2A8AFA8AB9A791C000013529EA4A59F6A19622F00001100000014688F815F42433C5E98A5825137252F2D314884BED9D4CBA2764F4F4132263A73A7B0B3A66B3B1E0F1E2D2F4781B4D5BE7A3318080D1C2C5E98A5825137252F01FE4F61070718F07563525E739CC2FFFFFBFFFFCA7D4231314E7DB9EAFDF0D8893C0E112965ABE7FEF7E9D2C6C28C39080000339AD9E7E1D1D2C3BC902F010000000C3A6C7291BFD7D8BE935217000007356298BCD6DAC19F6C3B22030C458FC6CFBEB6AD91470900000B2F4D87CBDDCBC8D7BE92655D5E504E679BBEA686829C73260313689DB5B5A39399B3B5A97C5C4C37496C8EAAA9A3A09E9B661800001D688EB0A899680B562300000F0900003A74917B5C3C3039688D92784E36273B42425A99D4D9CAC1966D52594E38384F81AEBAB097602D10101E1D2D508DB5CBC1762A0803071F2B688D92784E36273B01FE50610707180076716A6F7A9CD2FFFFFEFFFBB3723A26315D87C6E6F3EDC57B3B1B1E3472B3E9FDF9E4D3C7C1822500000049A8D8EBE2DAD3D1BE7A2300000000194D8A7E8CC2D9CAAB7831030000123A72ABC9D9D6C98B561E0E051857A7DEDCC8BAB2934501000009244B8DD4D8CBCDCAA98B6D6D715D5C7BA5BD9E6C74946D26091766A7BFB7A78991A9B8956B4B4331527E9EACB0A5AEB19E590B00001D72A3AB998759094F24000007000000418295835E444143769694704A39313242345FABD2DAC6B18457505E5C3D41678EB0BEAC8D521E0E0319232B5599C4DCC1661F0F0D151F26769694704A39313201FE5161070718107C706B7893B0DDFFFFFDFFEDA3623434375790CFF0F9F4B6652B0F153D7CCBF5FFF8E5D5D7C06A1700000352B5DFE2D6D1DAD1BD6D2000000000195B8D8090B4CAC3AD6F200000000E3F82BACAD8DDC486391208052665BFDDEFD4B2B3994C0A0000001E4F8DDDE0C3C7C6A679657887727493B5BEA07371875216052574A5C6C5B1868CA8B08A5A3E33385D92A5ADA99F97998C420800001F7DAAB5AF8D5400532A0000080000085898908058443D5D8E9C906E4B40353E4B4A6CB1DAD7BB9D7D59485A5D43557AA9B0B9AA904517080A1522315EA0C8E6BA5F141015161B258E9C906E4B40353E01FE5261070718207D767492A8C8F3FFFFFFFFEB9759362B456DA1D7F6FFE8A1561D0D22438ECFF4F5F4E4D5D4B0580900000865B9E2E1D5D3DDCEBB7321000000022D6B979293ABC5B6894D0E000000216195C9D6DBD3BA6C2E0A02043A7AC5EFECD2BDB7943F0B00000125589DDAE8C3BBAF91606292958485A0BEC49C79798B4B0600287CB2C2B5AB857F9CAC8E5543313962919CA6AAA8A29F792C000000297C9EA8A08D41005621000000000010608B8569504D485B8FA4935A44423C393B4B7EB7D0CFB495665259605D515F84B0AFBFA76A311C0E14141B386FA7CCE0B151190E071A27308FA4935A44423C3901FE53610707183078716C8AA1C9EDFFFFFFF1CB83432A2D4972ACD5F2F6E49B41051124549AD8FEF9E4E2E2D6A14C0500000668CCE6E5CDCACACCB66114000000052D7DA9959CB0B7A0753D080000083466A5CEE0DBD4B2601E0900042C7CC3EAF2D8B4AF893904000000265BAFE3ECC3BCB2864D648F9D9698B2B9BD907C81783804002C85B8BCB99677879C9875422E35437D9BA5B1AEA89E9B6A26000001398DACB3A2833F00551A000000000029889C835D5554527298AA8C5C45493D41475D87CAE2D8B0886648435E5F566F98BAA7C09B67391A1013161C3678BCDBDEA54214080914263698AA8C5C45493D4101FE5461070718407A7D8098BCD7F5FFFFFFF8CC7146373E4F7AB4E4F7F4D1762B07092055A6ECFFF4E8E3D4CD9637000000147FCCE1DAC8D2DDD3AE591300000014488BAF9A99A3A3926C2A0000000B3469B1D0D8DBDBAC47100000154495D3EDE9DFC6B482350000000A3066B6E5E0BEA98F664A65A1AC9AAEB6BCB19B8B857C3000003088ACBEB4A0848B9F9A6E3825264887989CA7A6A7A3925E130000083997BEB19C7927004B12000000061E4785A3815E566167769B977F46413E4046466392CADDC8A17552423A4F585776ADC8A4B6855D2D1C17151C1B488FC7E0DEA544180E08202B2C9B977F46413E404601FE5561070718506C6E84AEC6D9FCFFFFFFDDA45F3828415991C5ECF8F0C26B300A072C63B9ECFFF7E6E3D5C38627000000248BD5ECDDCECEDED19D460A00000019509EB6A18D9F9A785A1E00000018496AB8D0E2E3E5A442040005174E99D5EDDED8C1B78239020000053B6DB4E7E9CEA383553B63A2AFA6B6C4C9BAA19992692100004198BDBFBBA07D88A37F4A1B141A4890A7B0B2ACAAA2864A090000074A90AFAA9667250050170000000A3365899681595F6474859B9C724A4A55443E5473AFCADEC79F6C403B40535A6184AFC0A5AF7C4D251B1913111D4891D3DDD89C48150B0F1827389B9C724A4A55443E01FE566107071860717C93B6D4D9F9FFFFF8CE954A29293E669CCFEDFCEEB35E2212223F70C8F6FFEED9E2D7B668180000002D89D1E5D4D3CCD9D0933B0500000C2460AFC0A6938D7D66402900000120537ABFDAE6D5D0993500000C1A5EB0E1EEEBCCC7C17C310000000A468CC0EBE8BC915E3B4178AEACADBAC2CBC3B3AB90671B00064C9DB1BBAD94748D8E6F38100F204F97B1B9B6B1AEA97F3D0000001A559CA6A9955417004C12000002093C739CA87F535C5E68829495774E5C5F403F5475ABD4D5BB875B2C353C526976A7BCCD9FA97C4F2D252923171757A6D3E5D6973E1A060A1822329495774E5C5F403F01FE576107071870707996CFE7E8F4FFFFFBB4712F202C486E9BC8EEFBD98E47130A1D4390D9F9FCE8E3DFC2AB5A0800000038A6E2E9DDD6DCD2BC7E27000000062A65A3BFB4907F5E593914080A0D295380B7D0E3E6D8993E04000F296BBBEFEFF0E1C8BD741C0000001C5195D4ECE2C17C4D2A3381AEB4B1C3C8C0C6B8A38D4806000F59AABAB1A18E7D7E7D4F1A0102184FAABBBCB7C0B6A17C34000004216CA2ACB292460800430A0000000D4D80A7A2804F5D6C7F90A28B6352606B48365986B7CDCBB17A492F3941596C89AECACF999F683B2E33312113225EA6D7E6CB8331070D141C252CA28B6352606B483601FE5861070718807488ACEBF1E4EFFFFFE2A05D3229344D77B3CDE7F3DA8C421812305098E0F7F7DFE3DFBF8C350000000A4DBBEDEFE6E0E0DCBF6818000000093378AFCAC3946852412E17000412385B79B1D3E4EBCE86300200123375C9E5F0EAD9CCAA66120000001F68ACD8F2E1BE7F42253181AAACA7B3B7C2C8B8AC813A0000125F9EBCB6A18E7A7B723C1600082363ACBEBEC2B8B892682A0000002D7CA6BEA27F470F0844170000043172A9BAAE7A54576B81A0AE8A61617C7D5B556F96C1D2B8A17340283146516E91BAD1D198915334344A472D1D2966B0D9DFCA8434131212181F33AE8A61617C7D5B5501FE596107071890758FB8ECF4E1EFFFFFC87E3E2820375F8FC0D4ECE4B7742D1C17265AAAE4FFFFF3D8D1B07C230000000A49AFE5E9E5E8DCD7B66B1A000000093C7EAAC8B58B4C3E3F2116131920406281B6D9EAE9CE7E3106001E4682CAE6EAF5E0C2A6580A0000072E76B9D3F4E5B6723E1B3486AAA0A2AAB9C9D5C5B2782500001171BABAAD9F957F67552800000E2370BACCBFBEB2B29D551900000F3D7EB2B19B7536110F431A0A10093386ADC1A76B46536089A5AE8158588079555B8CB2C5C4B58358331F36364F6EA0CDCFD1968C513A3C5C4C2D152770BAE3DBCC7E2D121912172B36AE8158588079555B01FE5A61070718A07895CCF2F1DBF2FFF5BA6D321119305C96C1DDE3E2AE60230E13346EB6F0FFFFEAE0D59F5B0E0000001768C3F1F7ECDEDDD7AA53120000001A4080BACCBB7D411E1D221F181D31477087B6D4E0DCCC792400092C4C8DD8F3F2EEDAC7A14B0F00000C3F83C0DCDEE0B3732C10327B9396A7B4C3BDC8B5AB661900002484B7C1A8A28B6F5A391800000E2E79C9CCC5C6BCAD894A0E0005255496C1B49A6725090E4D280C19234D9EC6C5A76A595A6B899EA2795F68807969759BB6D9C9A8754224243B455580AFD4D7C280864E344E705E301B3274B0D3DDC0732B1C1E141E2B4DA2795F688079697501FE5B61070718B07697CDF8E8D9E2ECDDA455210E1B3A6AA0CCE1E5DE9D49130A173478C5EAF7F8E5DAD08E39000000001C72C5E3F0EDE6E7D8A64A0D0000001C4889CBCEAE65301E27231D1D283B637885AED8E3E2B7601C0513335991D3F4FEF0E5C99343040000145090C4E4D6D4B56924174280968F9DB8C3BEBFC09C500900004291C0C8A89E8F6C472F0A000010307CC4CCC7BEBBBB8D4007000036629CB8B785581C0A1E462A160C23539BBABFA46C49586D81979074507078766E7BA2C2CDBC99693D2A29394C6494BED7D8B97D7C4735506E5E29193E8BC1DCD4A860181A2C1A2B2C4B9074507078766E7B01FE5C61070718C0708ECFE9E3C7D9DFBB7E460F031C3E80B7DDD9E7DE97411309224280D4ECECEBDCD2C4792500000000287CD4E7E1E9EBE2CF8940050000051E4A7DBED0A260311319262F383F5172848DB4DAE9E0AB571500174870A7D6F7FFEFE1BF7E3000000021549AC4D4D8DABA6D271130868E89A7B5C7C4C6BD953F000000379CC3BB9EA09369371B060000154B9DDBD1B8C1C6AD8A44080608386FA8BCA27839110B24502E1B1E337FC1D9C6AD6F47566B8A99976D5268807E8592B4D3CFA97C5A3D1E2D3F4D72A0C8E9E2C576653E34536E592A214E9AC9D8C6AA5D211B1D1A273351976D5268807E859201FE5D61070718D07CA2E1FEE9DFD9CEA67339110A21458EC5DAE8F7DF91350B0C204E91E0E9E7DDDDD5B8671C000000003492D9E2D0E0FBE7CC8E3D100000001C448BB5C0994A1D0F2934343F5175929789B2D0DFC78F41100624527FB9E3F6FFF6D5AC640F000005205D99C3D9D7D7AB651E0F3D848D8BA9B9B9C6BBB68B330000074E9DC7C1A5A6915625090000001960ABD1C7BEBFC0B475341100124388B6C1A8743C0F0B3972403B35519BD3DDD9AE6C52566E959D9171586E818A8DACD3E3CCAB7143281F30455778B4DBE9E3BF665C373B5F7A5B2B2353A2CCDDCA9E561F1D2B182537589171586E818A8DAC01FE5E61070718E0759AD6EFEFD0C4A38352210002284B91C9DDDEEDCD7C2F08082961AEF3EEE8DFD9D3B158020000000035A7D1D5C6DFE6D9BB7F48140000051C4785CDC5813F11092A3442476D809B9D91A4D1D9B37B33040E376A92C3DAEAF7E6D192520E00000C3A6EAEC8CED6D7AF611F113D899998B3C7CABABEBC74110000105CA1C5B9A8AA955324030000002267AED7C9B7BEC5A8652E0300174D8CBAC6A4642E071344523D353755A0DAE3DCA4684E5D78959D8B5D4E6D8D99A2CBE2E3DAA56C391D222A4B628CC3DAE1D7BB5D522D476076512A3370AFCACFBD96491B1F28202D3A5E8B5D4E6D8D99A2CB01FE5F61070718F07DB5E0F5E9D9BA896032040011305EA5D6E2E5E4C3671E01122D67B4EBE0E6E0DCD8933D00000000144DA6E1D5BFD7DFD6B97C3F1200000A1B3F86B7C0792F121B34434F638298B0AD9CA9D0CBA26D280C15467CABC8D3E7E7D7B773360100001E5481B9D0D0C4CCA65D1B1140929DA3B5C3B9CBC3AB6D1500001663ABBDB7A9A18E4314000000022373B9E3CEC0BEBEA2611F00022D669FB6BE9E622904225A514C514878BFF0F3DEA86F4E6281959777695E78919EB7D7EBECD29A592D171E304E649FCEE7F4E0A83C4838526A68522F4183B8CBC3A388410E1D2B1E3B426777695E78919EB7D701FE6061070718006DA4CCD5D2BC9B6D43200800092767A8D3E6EDE4BE60210C0D5284C8EAE7EDE2D4C68B2E000000001259B2E0D2BDD8E8D7A877400C00000322437AB99D591B031639415A6A93A2C6AFA2B0C9C18D5E24011D588DBAD0DDDEDBD09A551D000002255A92C0D9C9D0CDA9531912448DA6ADC2C2BABAB99B5E0F0000237CB6C3BAA7AC88470D000000023583C9D5BFC7BEB59C5426000C266A95C1B8A060140019575B4D505788BEE5F1E6AB644B6490A28C745C5F7B90A6BDE9F4EBD58F4B2920312D4D7BA8CCE9E8C99C4550454D61604836569CC4CABF9A6939170F2630435A88745C5F7B90A6BDE901FE6161070718107393BACBC09F724E331107000C3F6BB7E0E6DFD899440E001C4981CDE8E5E0DCD5C1752200000003296AB7E1C1ACD5D5BF98713D140000131A4579A292481A061A2C36628FBDC6CFC49FA6BEB47C3B0601296BABC2CEC3D3E4B77A370B00091A3974A9C8CAD1D2C9A65112104080A6BBBFCEC2BEBF8F4A0100003384BAC5BDABAB8A3201000000034398CADBCEC2C9AC884A1808033382AAAFAE964E10001F6C62584F658EC5E5F9EAA768466A8C9E8B795B6B8093B7D0E9F8F9D18648232430405174B5E2F7E8C89D444647575752454262ABC6C6B48065340F161824596B9E795B6B8093B7D0E901FE6261070718206F9AA6B7AF8B5832170900021C407CBEDDE6E1C684310C0B23558FCAEAEEE2D8C8B371140000000E3477C9D1C0B0CCDEB98E6A421509070D264578917032100A1732466FA4C7C6D3D5B4B1BA945A26090B3076C0D4D6D4CDCEA964351200002B5584ABC9D2CBC1D39B400B0C3982A4C5CFC3C1C1BB893300000F3584B8B9BEB2AE863006000000104E98C8CECBBDC0AC804F1100144187ADB9B694540D001F645D485470B1DFECF7E2AC6C5066969C736A55677599C4E0FEF7F6DE86412729373A587EB5E4FBE5BD85393E49585545375579B5CFC79B76492806111F37667FB46A55677599C4E0FE01FE636107071830798AA5AB9D82471B0800000A27417EC2E1ECDBAE68240E0D3169A3DCF8E6D6D7C29E5000000000144490CBDBC4BFC6C6AA7F62402021182839576D825A2E0F03162F387DC4CED8DCD4C1B3AC7A371100064EA0D2DED0CBCCC6874523060001396DA3BED5D0C8CDC9872C02003077B1C7CCC7C3B9AC722C000009438FC2D3C1B6AD792A000000001861A8CDDAD1C1B796714316010E4C88AEB7B7984F0E0836735E565B7AA1D0E7ECDFA16253749A8767545A6E82ACD8F0FCFFEDBC7C38222A3D374880C3F0EDDAB37D31353E4C43383A6199C2D5C0905D3620111022497A9BC4545A6E82ACD8F0FC01FE6461070718407B838D8F8365330A00000012295088C1D5DACCAA52180D0E4577ADDAEAE0DFD0C1923C00000000195B9BD9E5D0C5D6C38C6358381A1D2C3B3E536566431D04051939448CC9E9EDF1E0BBB399642206000B5AABD8CFC7BBC4AF713918000115418AABC5C9C2C5CABD753107062D77B5CBD3C8BEB5965B1600072A4C96BAC8BEBAAB7826000300042461B6D6D6C5BAB99366300C0C1A5A9CADB9B69443110C4577564D517EC0DDE7E6D2945554819F86644F435F75AADBFAFFFBEAC1682E242B423F5089C9E9EBDAB1713B364B533E364778A8C8CEAB784831160812224D84B6CB4F435F75AADBFAFF01FE6561070718507B757889764A1A0000000528435F88C2D0D3C3834314001F5895BBD9E1DDD7CCBC7E20000000003873A3D8D7D2CAC1A566524C351F314355596A67562A0803000F21418FD9EBE6E7DEB8AB8A4B1200002864BEDAD7C9C3C2A8682F1513051A5FA2C4C9C6C7BAB09A5A200305297CBBD7E4CCC9BA82400A000D2E5EAAC3CAC3BFA960280C08070F2A7EBBCDCCBDBBAF915B2D0E0A26629EB4C4B58D360B0C53794C404878B6BFCAC7BE7F4A4F888E6B4E45546787A9E3FEFFF9DBB86B2F2B39494F5D8DC7E3E6C39858372B38382D30578CB0D1CEBD6C2F1E100C0F255C9ABFD845546787A9E3FEFF01FE6661070718607173747C67320B000000153152779CC8D8D3AD6C3405081C61AAC5E1EDD4CCCAAD6815000000103B78B6E2DAD2CBBD8B4C3A393632486165626A5535180401000C204DAEE9FEEBE0DCB89A6B310700033281CCDED5C6B8C3AA66311609102A79B4BEC8C4BCAAB994430E000C276FBDDCD6D8C9B07A2603001B3B73AECFD2BFB6A5621E090A0F173E7DB8D3CDBFB8BA8C582B0E13407DA8B2AFAA863401124B7C462E4984B4C6C4C2A1674A5183876A493A4D6580BCF0FAFFF0CBA1663538494F405A9CDEE9DDBA874E3635362E2125699CB6CCB598592619090F132261AFDBE63A4D6580BCF0FAFF01FE676107071870706B6A674916000000001C375871A7C3D9C49C56150009317CB7DDEAEDEBCEB08D4C040000001B588EC8DADDE1CFA2682E293628356C80837B765C290C00000009184CACEAFAE5E6D9B68A572006000D3B94D3E8CCBABDC29B58371E14163585B1BAC2BCAAAEA986410000082F85CDDFE5D5C2A55C1B00003B5D7EA9C1C7C2C2944D2019161623418AC2D0D7BBBCAD884D1F010F4891AFB5B9A97D2E01115785533B4F93C8BFB9B599614A67847F533E2E384F83C6F8FFFADEBE9457324847584C589ACDE6E4C1864A372C2E2A1E3171ACCBC9AF784C201A091A1F2A6CBEE4EC2E384F83C6F8FFFA01FE68610707188064635F562A0B000000002350757BA9D1E2BD75340800163581CBDCEBEAD9C0A97B3C080000012E65A0CDEAE2D9D0904927231C1F44819FA48F7F5329000000020C1E4BAFECF7E5E2D8AB7B49120000184DA7D0E0C1B5C1BD94603F220D1D469EBDC1C3B5A59F976B26000008339CD1E9E2CCBE844A13000E43718BB3BFC4C8BD8F4714121C26345C98CDD4D0B8B9A37B3D0F011B4F99BDBAB29B612500186C904D3255A3D9CFBDB9956866798A744D2733355D8FD2F2FBF3D4A77E58374B584B466CAED3DBD5AD6C443C2B2F28253A7DB1BFB99D6A3619120D1B223B77BCDDF033355D8FD2F2FBF301FE696107071890747266512D000000001144778B95B9D4D5AC68240000234A94D0DAE8EDD4BD9C6228000000134785AED0DEE2DFC3722C0E091C31539AB0B3AB914E0F030005000D225CB7F5F7E3D3C8A661290000062E5EBFDCDCB8B6BCBB95644A2C252A599ABAC4BBA98B747B4D1D020010439BD7F3E3D6B678330B0020648AA2B2B9B7B7A67E38111320304870A1D0D8C2BDBE9874340000145BA0B5B6BE98561B002B7590504365A3C7BDBDBBA16E738989643523273759A1D5FCF2E1B08D64413B535448477BAFD5D6C29F6A3D3A2E292422488CB5C4B48E602A101D1917243F89D8E9F3273759A1D5FCF2E101FE6A61070718A07C75694D1F0000000B2F5C98AB9ECADED69B4E0D000023579ECEE3EDEDD0A97F3C0F00001029609DBCE2E3E1DBC6610C00020A2B60B7C3BDC2A1551100000000051C60BBE7EFD4CEC49C6C20000000296BBBD9D8BDB9C5BF977052291E366EA4B9C3B5A575635F310A00001A54ACE9FEF6E7B364210001327CA0ADB2B2B9BAA56A290E123044597CA9CCD8CCBCB093683504001A63A2B9BFB08A441609357C8A433C7BBED2CCC8BE9C7176908357311C213465A3DAF0EFDEAD7E543D3D4249454881B9D6CFAE8D553747443C202A598CAAACA174451D11241E26244891D7F8FA213465A3DAF0EFDE01FE6B61070718B07C72643F1A000003113877AAAAA8BAD6BD80370300142D6EADD5EAEBE3BD895F240200000D327AB5DDE2EBE4D7BA4B0000000C2F66AEC8CBC8A655110000060B0D316BC8E4EACECBC9A14A1B00000E387BCAE7D5C0CECAA1725E4B32293E6F9CB4C6B49C7354421700020B2865B8F0FFF1E49D421200034690B5B9ABB4BEBE9F58251524405F7094B4BDC0AFA9A696682000001B6AADC5B4AE8132111947899B4F5C93DBEDDFDAC6A6868F947B451D0F142D68ADE4F5F2D191604133414851516899CCDECDAA7749283344322B3A72A1A69C846A361F152A2F3025489FDEF4FB142D68ADE4F5F2D101FE6C61070718C0727C623A160605162C578AC1B8B6C7D1B4722807061D4B7CB1D9DFE8DDA66B3F1C0100072D5392CAE2E9DBD8DDAC37000000163A83BEC5D5D7A64C13060610161A3372CAEFE5C3C2C18D4C140000184F92D3D6CABDCBC59E7B714B2A25437BA3AFA7AC985B3A210800000D336FC3EAFFF0DE99410E001756A4C5C7B1B4C2B88A4D20171348728BA0BFCEC5BCA4947B501C0000246FAAB5C1A96E27060D4780985883C1F5F2EAECDDBAA59FA2783F0C12283E78C2F1FCE8C08A553834474F44445BA4D9DABE9A67393932404D4A4E88A1A19174522917152227272E5AB2E6F6FE283E78C2F1FCE8C001FE6D61070718D0847F6340160A0F224078B5E1C8C0D1C0A14E200806275C95C7DDE5E6D48F4D1E0800001F3965A3D4E6E1E6DECA86210000001A5090C1D5D6CDA84D060003111A294C99D6EBEACDC4BF8A470D000013519ED1E7CDC8CFBC907176553434667FA2A99FA59A521C0500000820418ACBF2F9E9DD913906002075B6C2BDB2B7BFA070320A13275E8296A5B9C9BDAB9A8672411200002B6EA8C3B79E5A1818366C9DA46DA2DFFDFFF8F8E5BFB0AC8B69321D1F254492D3EDF6E2B88045263B5C4B485D7FBCDDD1B180533C4230565E556B99A599795A421A0D092537313363B9E7F7FB254492D3EDF6E2B801FE6E61070718E0766D512D0E07192D5B95CADED2C2C5A97C3712080F3F6CAAD0DBD9E8C37834120000112E4D80B2E0EFF5E1D2BD6617000000245A96CCE2D4C79237120B0F111D365C9FD8EAE6CBCEBE923E0400001F74B2D9DAD2C5C7B17F677060363E698CA89B8DA38F4011000000051D58A2DAE8EEEED17C210002267BBBCCB6B4B2B999471C0D09296F96ADC0D8C9BEA48972673C0C000A37729BB2BC974F1C17397AA7A285C1FCFFFFFFFFEDC7B2A48F59311C264365ACE7FAFBE7B0643D2D3C525B587098C8D4C6A37240314826545D7A87A8A288624A3619100D2A41293471BBE8F8FB4365ACE7FAFBE7B001FE6F61070718F0746A4D20010D153C6FA4DDE5D5C4B49E6426060A244D84BBD0C9C9DBB35B190001001A406A97C6E1EFD9E2DCBF57030000123D77AFCECDC5BB8A3C100E101D2C3F70B4DCD9E0CBCFB98D3B0400002B7AB6D4DBD0C4BDAA7A5F6D50293F719BA79087897D3E00000000163973B9EAFFF5D8BD741C00012F87C1C9B3AEB7B38240150E1433759FAABBC5BBA99A745B57310B001C3E7EA2B9AD8843161A528EB2A484CAFFFFFFFFFFF3CDBC9B8559372E29527CC5F2FBEDD1A563342D354D60667FB2D1D7B58B4C30334218567A8B97AAA28A5E4D2A110A0E242E293A82C5DFEFEA527CC5F2FBEDD1A501FE7061070718006D613A200E152B588DC6E4F2E4CCAB853F150D103669A1D2E1CBCEC5974A1300000B214D7CA8D7E7E2D9DAD3A73D000000125A87A2BDC5C7BB6D30131B1B25395A87C0E6E2E3D9CDBA72290000003883C1D3D0C1BABFA46763764D274A80ACAC89898E75290000000B224680CFE6EBEBE0B55C0F000F4E95C6C1A7A3B2A968280B06093E82ACC3C2BEBBA1875D4844200902294F7EA2BEAA7E381525649FB2A895E1FFFFFFFFFFECC6B5A57653351A2D6C9CD4F4FFECBB925D31273E6169739DB6D3C5A068361A3548235D7D93AEB4A78D6B4C2C0C00041A2A2F3E89C5DEE8E36C9CD4F4FFECBB9201FE716107070810766447322E314C7AB2DBFFFFEEC38B6438251B395A7FBBD7DFC2BEAB7C36050002114477A3CBDAE5E3D5DED3982C0000002A6496ACC3BCB8A25B2A1A1A1D2D507498D1E0E3E2D8C7BE72290000003493C2C6C6C4C5B98F5B6077442D5798B3B4938B9066100000000A32599ACEEAF4E6C7A24C06000F60A3BDC3B3A1AB9B5C23110B183B79B5C8C6BCC0AB7A5644341B0A142A5A83A5B49562291E3F7BA2AB9EACE7FFFFFFFFFFDAB2A499733E241E3378B6E6F6FEDEAF774B232640616C80A3BDCEBC8A522A1E3445306181AAC0C7AA926A49230B0E091C30305499BBCED9DA78B6E6F6FEDEAF7701FE72610707182084634A3A3D4A6F93D6F8FFFFE7B16D4C2918264479A6D6EFE1AC9A9761220200081F599AC8D6EAE8F0DDDFD18E170000053A83ACB2B3AFA9884F1F141B27366B88ABCCDCD6DAD7C0A25E180000004293C9C9BDB1BCA37B5E676941355F97A4B08B8B85540C000001254070BDD3E6E6E7C0893800002168A9C4C5A1A2B39849120B121F3B80B6C4CEC3BB9B6C3D2D2C180F25507690ABAE995019184C91AFBDA7A2D9FFFFFFFFF7D6A99E87582E22274C8DC7E9F7F1D59C66402B3B4E6D8095B7CDD1A5663E1D183237215990B8C4C8BFA0765721050A101D3038639FB8BCCBC38DC7E9F7F1D59C6601FE7361070718307056403336547DB1E4FFFCFFE09F5C3319162D5A9FBEDCEECD9B807C561401030C2E7CB9DBD8ECE5E1D6CEC584180000124D9AB8AFB2A7A36F2B11121F2A46739DC1DBE3D8E1CBBD9C4A0E0200034B9FBBC0BABDC0A470505C5C3C39699BAAAC999586490300000123538CC9E8E7DAD8B6722900062F7AC1CAB9A7A9A68A2F0F05010C3D96C1D1CCC9B2945D313436161B315E84989B987C3F141B599BB7B5A09EDCFDFFFFFDE7C7A08E794E3315284F9CDCF8F8E4C28D582C1622517097AED0CFC89D642D0B13313D2C4D7FBECFCFBAA98B5F1A07150E0C264A7DA0A3BAC5A99CDCF8F8E4C28D5801FE7461070718407D5A3837446088C4EBFFFFFFC9814F2C191F3B6EA8CED8EDC19B6C5B391E0314264694CEE8F1ECE3E3DECFBE630500000E5D9DAFB0AFB0984C220C1825325C99B9CFE4DBD0D1C5B99246120000005AA2C6C1B5B5A88652415E52373D6EACB9AC999A793E0300000A2E6A9BD4E5DEE1D79B4D1100084A97C2CAB99E9AA776290A041B1E4597C2C4C9C2B58A544239210C2150849CA5947E5F341325629BB4B59CA3EBFFFFFFFFEBB69F8A7A5B302C4371B4DAF2EBDDB17A5031222E467AA3C6CCCFC28E47140016353E344F8ABED2D1CBB18A561A0A221724405080908D979586B4DAF2EBDDB17A5001FE75610707185079644E4C5C7AAFDCFFFFFFFFBF7532190F225293C8D6F0E2BB784A382B11101E2653ABE3F7EFF3E8DACFC59E420000002475ACACB1B7B88F4B1607131D3A66ABCBD0D8DED1CAC1B485361102001164A9BDC1BEA8936E4A3F4A45364583ACB4AD9691763A0400001C488CC5DEE4E2CDBE883011001E56A0C5C9BA9FA29961250509102A58A0C8CDCDCBB38158433924192E5F8C9D987A774C230E3472AFB7A98FBEF0FFFFFFFEE0B59388805C3F436092C5E7EFE7D5A36E39201C2E518DB6CFDBCBB687370A0009243A31558CC2D2D9C6AB8A5714062F211D456487837C7C826FC5E7EFE7D5A36E3901FE766107071860705B5062658BC1EDFFFFFFFDB260371D223B64AAE4DDD9D9BD6C38251200061E4067B7ECE3DBEBDFDAD8C5A1320000113882ABA4A7B7BA8A35100C162C3E7ABDDAE0DAD3BFC2BAA56D2E100205267CBECDC7B8977B543233393A315795ADB0A6918B66230000012A59A3CEEBEAECEFBE621600002975B3BBC7B4ACA78B451A0D101A3A6CA2CCD5CCC8B57F574B37181B4378A1AE9B71502F0C093679A8B6BA97BDF1FFFFFFEEC99A83797A605A5C76A6CADFEDCFB49468402815284D87B7C1CBC1A86D2800000D1B2D385994D5DDD6C2AF7E4A0D002B3934608E806F5C6B675CCADFEDCFB494684001FE776107071870856358627BA0DAFFFFFFFFF7A2542717243873BBE8DCE3D8AB592B14100F1B385280CFF3DFD8E6E3CED5BE8429000017469AB3A5AFC3BB80250907162B5AA3D1DDE2D4CCB7B0AB8E60301D12103389C5CEC5AF8B5937191F2B203065A2B5B4A494774F220401032D71AEDBF3E3E1DBB14C090009368DBAC8C6C1B1A47039180618203175B0CAD9DAC7BE915E5638191D4E89A9AD925D331200083F85BBB4AA98ACE6F7FFF0DABE9169656A726D737DA8CADCDBCEA282563A1D0E1B478BB6C1D3C5985F1900000520213D5D9CCAD6CDC5AB7E3A000028485882927E6243494D3CCADCDBCEA282563A01FE7861070718807661616988BAEEFFFFFFFFE78740241C25478FD2F9DCE0D692481D0808112342567CD2F4E1D2DFDFC2C0B46617000C305B9DB19BADD1BC792A0A051C3E6DAADAD7DACEC9B3A79B7B442D21192758A9D1D7D5B3672A15000E1D2B406EA9B6B4A5957241200D121C4791C8DDEEF0E8D7983D00001651A1C3CECBC1AB925E230D0D1D253C79C4D7DED4C3B9866A603B1B206491A6A887441E00000D5298B2B5AA91AEDEF0F9ECC2A4746659667D807E7FA1BFDBD9C7AC7D5631161015478CBBC6D0AD813C000000001F2C4E68A4D3E5DECCA66E3500032953729799734E35433A27BFDBD9C7AC7D563101FE79610707189072666B839ACFFEFFFFFFFFE7813C2326385BA4DFF1E6E0CE8635120008132D485F8FD4E5D9DADCC8B7B19B540F00163E75ADAF9CB8D1C477240F17284F80B3CCD0D3CDBFA2858160373531234579BCD3D3D5A9621B000000171F3D74B3BEB6AC976C3D261E19284D99D1E5F0E9DDCB83210000216AB4D3CDC7C6A17A4915121918274382C4CBD5DED6B58F7A5C2B13286999B1A8712F040000275CA8B8B0A391AFD5DCD9D4C1A46E4F5468738D8D8899C3CCC6B2947052240C0C194D8EBDC6C2AB85430000000214295A73B3DEE3DEC28E591F0000366090A79D643F4541322BC3CCC6B29470522401FE7A61070718A072707796B4E4FFFFFFFFFFC86D3719223C6CB4F5FBEEE2C879330A04031A3D65739AC5E1DFDDCCAF9AA5843703163C6688B8C0A3BBCFB26C1B060E35629CD2DDCDCFC8B38864554B3F3C39345680C6D2D6D4A34800000000151D4187B3B7B4B7AC7B302226282D5BA2D3EDEFE9E1B96D14000E2C76B8D1D3C5B98B562A152127242D4B85BFD0D6CACAB489886D27102E6E9FB3A167210000002973ACB8968B829BBFC6C4B7A27F5C45405D7A848B8E94BCBBBCA48A653E2816081D598EB0C3C3A87327000000050E25667CB7DED9D0AD783E0A0002306EA8BBA45E3D31342413BCBBBCA48A653E2801FE7B61070718B078758A9EC7FFFFFFFFFFFAB668301D26457BBCF3FAFAE6B45D1F000307224A6E7A9DBFDBE0D7BD94888E722501114F80A1CABEB5C8D8B3591D0B142E6BA6C7D4D3C9BEB4734A3D33404A434E739FD0DBCBC5953E02000000041B3F82C2CFD3CDB56E322936343B5CA6E1EBEFDECEA4530F0016478AC2D4C9C2AD7C45100E252D2E35498FC3D4DCDDCBB697935E130A3175AEB19A62190000002D78AEAA887F858EA6B7B09A85664937395A7D8D827F90A8B5AB9E7F664B291005255C93B4B5AE945E140000000015387086C7D5D8C6AC6B2D0200083E71A9C1975F49463A2626A8B5AB9E7F664B2901FE7C61070718C07F828AAADAFFFFFFFFFFE4964F2E1E345F95CFF6FFF9E7A8501400000D2B658189A2C8DEF9CFA7735672652009266AA4C7CFCAC1CBD2AA5E1E08194281B4D7CCC4C5AB954F3115253B4A41568CBCD9DCCFC280320000000009244594C4DBD2D0B76C282734353E73B9CEE0F3DDBE8B3B0C0B2A589BCFD1BBB6965B1E021B3A3D3A3F5A98C6E4E0DCD2B19A8A4D16124279A3AA904E190000013A85B4AB7A77859AA5B5A69E8B684F32395D80968C8483929A97807963492D1B1A36739BB4B8AD83580E000000001942859CBFD8D3C29F5A15000000306DA9C6A75F5459412817929A97807963492D01FE7D61070718D074839BC6EDFFFFFFFFE2B98748322A4A739CD2F5FFF7E28D461E04000E3C64908EAFCEE4EECD8F4E3960431C173D80BBDCE3CDCACECE9B4610061E5195C3C9C2BBB7A7904516001F3F4E456DA0BFD3D6D0C37929000000001436518AC7D0D9D6B574303444484071A4C2E0E4D7C26E20071E4D6B9FCBBCBBAD823D0C012C4451494C70A8CAD6D4CFB3999A83440B174588A6AA864C0B0000005199B9A17483798A9BACAA9685643933486884908B817F8E8D8C70615848311C1F4C80A9B0A8956C3F070000000A2D6D87B2E0DCC3AE8951110000002C74ACBB97625B5E3F211A8E8D8C706158483101FE7E61070718E07892A9D7F1FFFFFEEAB9935A382D364977B5E2F4FEFAD47B290404011C487E8EA3B9C3D7E5C16C2F1C3F3719245C9ED6F1E9DEC4C6C1874A16082257A3C8D0B6C2ABB18E3801001C4D5F4A71A3C7CFC7C4B5681700000000283F63A1D5DECCCEAA653B474F394B70A9BDD4E2D4B155100C2C668EA8CACCC4A86D240208325660595671AAC1C6D9CAAF8987672905205C91AAA3853E08000010629BB59F717B8095A6BEACA38F785645557D909184747C84857566625441232032598DACB1A5846435020000001B407693B4CDDECBA97E3610000000276FB2BFA6645953351920848575666254412301FE7F61070718F07492C3E0F7FEFDFACD8E653E21273B5E93D0E8F6FDF4C4672D01000411567F95A6B7BECFE9BB5E1E1830281C3775C2E1EEE6D2C6B8A46E351E12286BABBFBFB0A9A89F712900002253575383BCD2D3D5CDA154090000000634577BADD7D2CBC9A6623849534E5575ACCCD4D7CD9F3D0A1E5481ADCAD1C5B598490B000D4667685A5F84ACC2C8C8C7A48980581E081F6493A593783D0800001170A6BB9B7D8A798CA7B3B7A890774F587488989C8D757070555D4E5356412E35527AA9B9B0997447280F00000034659698B9C9C3B2936B2F01000006276AB6C8A55B4E4D2D201F70555D4E5356412E01FE8061070718007CA9CDEDF9FFF3DA9F6B41271B254A75B1E4FCEBECE1A44F1B0B0E1931638091A9BBBCCDE2B34E1609100E1D398DD1EEF0F2CFB49F85563025132170B1C7C0BBB3A68A681E000028685F70A1D1D0D6D0B5853B0D000000295B6D8CAFCECDCDBD9451405D54425C77A4BFC9D4CB802A0C277199A0BABBB5B0802C02001F597971666D94B0C1BFBFB69A85844D0A00297799A99C7F4D1100001473ACB8A38886738A99B0AE9E8A7163655E8A9D95847E6D583E3D35353B3627456889ADB7A8886140280D04000B4F8FB4A8C7D3BD9C734E1200020C11297BBCCC9C5B453A2E1A25583E3D35353B362701FE8161070718106A9ECAE7F4F1DAB56C30160F0E245B92C7E1F2E6E7D696461009070829657C88A5BFBCBED3A04D0D030306254FA5DBEEE8E6D19F84643D32241B357CBBC8D4C9B9A681440700043864767CA8C7D3D8CEBC86320A000000356690A7B2CACAC6BB834B3B5746436182A0BFCECFB66F2710368AB4C0C1BCB1945C16000026677F6A647FA1B9B0B6B5A4938B7D4200002E75A1A89E8F5D1C00003177B1B7A585835B99BBB7AEA4967F6B7A8C8C9A99877169523634292D3E433E5F7C9BB2B3987148241C181905296E9EABA1C1C0B17F5F3715010101113787CBD19D61402E1D1A25523634292D3E433E01FE82610707082077ABD0E6E9DACB94500F0701052A6AA8D5E3E5E9EDC770310E00000A3767809FA2BDBDC2CB8C370B0000002363BAE3F1EBE2C68763403132271D3780C1D2D7C3BD98692B00000F2E6184A5C0D2D0CDBFAE68240200000C588FA9B5B8C9C2B3A16A414363584B6087A5BACBCFA959110E5594BAC3D5C0B2904A08000D41778A70708CA0B0ABADB396848F6A240000457A98A7AC97601E04002E76A2AAA19282497F9192958C82777483939E99948C75602E1311181C324149708FB3C3AD8B5637261F1A191A4076A0B8A8C3B9A56C431F05000304144A95C7CDA45A4423151C212E1311181C32414901FE83610707183074A9CADDD3C8AF6A250000000E4484C3D5D6DCDDD7AB59280900020C36698EA1B2B4B5C3C3771F010000032B76C0ECF7E7DEAE653E222230312A4489C9DDDAD2C694551B000003305F94C1D5E6D3CCBC99611D0300001870B7C6C6B9B8B2A28C574350675346738BAEC7C4C299470C0A65A1B8C5C1BCAA762E000037629287716C90A2A79CA4A1837B84641D000743839CA3A99D621D000A367C98A99E8F713574807C7E837872788293919D9892785520000D0F2232425B8AA2B6C3A084492720262D2A285587A7C3A9BBB493463521120810101A50A0D8E0AB6D380D04110F20000D0F2232425B01FE8461070718407BA0B4C0BBB7853F07000000185A93C7D9D6D5DCC59543190E0109173C6691A0B8BFBBC4AF671A0000000C3586CEE5E8E3CDAC5F1E08112434283E90C7D3E1CEC8934A070000062B6CBFD5E0D8DACFBE905D231500002477BECAC5C1B8AE9C764B415C6E534B7D9AA4C0CDB982270A1C64A4BBC9C0B4945B19000E4A7B9587686E8DA59E9D988C6F707A500C04185A889FA39DAE702E040E4984A8AB9C8455156967706D6B676F7F95A4A3979A96714A19000006172844668BA2B8C4A974342015292628335C8CA4BDAAC1A9783A1A1811142B153066B7DEDAAB6A290A050417190000061728446601FE8561070718506DA4BAAEA993671E000000062D6CA8D4DEC7C5C2AB7E330F0100031A416E98ABB2B7C0CBA74C0C000000134389D0E4D4E0CC98430E051A36261E4790D0DED9D7BC7730000000092E74BEE9DFE4D6CFBA98662E1B11183982C2C0B9BEC0A07850354F637557547A98A7C4C2B16523002172AEB7C9C8BF8F3E00002C66949C93626D8EA89E979784676D6A3703002359869EA2AAA46C2800145898A7B29E834201735C4C4F525869859C9A988E9D9472400000010D1A2F4C7497B5BBBDA3612918223731343C70939CACA9BC9C692A0E040C283E344886B9D4DBB76A2300000B1F0000010D1A2F4C7401FE86610707186077979DA4A08E4B03000000124B8CB6D4D2C5C7C2A15A1C0C0705032C507698AFB8B3B7B18C3F03000000264E9BD3E9DECCB57A250408192B25244B8ED3E0E7D0B9681C00000010347ED1E9DCDBD7D3BEA774402C1E2C4C8ECACEC6B6A88B5F3A36536B7F61628C9EB0BCBC9D4A11002C83B1AFBCBDB575270005387C95A5905F728F96A1909A886363561C000B3D7499A1A8B2A86D22051F639DB5AB9B652200654D3535475166869EA2A69DA69B7435000000100D26478AA8C3C4B9945A201027342F323C6B8F9EBDB4B59B5D2100071C414F4868A2D0DDDBB0611500000D17000000100D26478A01FE87610707187077868EA08873390000000026619DC5D5C9BBBBAF7C3E1000000E1F3C5E7991B9C4C1B4B07D27010000083C5EA3DBE1DACDAB662503051D27242B459DC9DCDDC999580D0000000F478CD3E2DBDBD8D3CAA67C503B37465E92C2C1BBB5B084452839657686707B97ACA7AEAC8C3C0D053493B6C3C9C2A5580B00194E87A7A88A5E70919A91928772584D3C1600145982A2A9ADABA16920063075A6A7A5A25F180060423D313D51658A9CA5A09FA49D6F3A000000142039649FB7C5BDAC85420D0C292F293647788A96B2ABB2835B23070C234F667289C2D5E3D8A55B0D00000219000000142039649F01FE886107071880768A808979571D000000043584B5C9CFC0B8B89A6726050202112F63717A84A2C0B7A3996B220200001D5177A1D4DCD7C18F460D00172431242C599BC1DEDBCA9A540D0000001143A0E1E9D1D8D7D1CAB17C5857484D7099B8BAB1AB9C732E1B326B849181839CA4B4AA97682500014199C0C3BFC2984508022E6DA5ABAB77556A90989692816459492A0C0A3E789FA6AAA6A79D62271D44859EA0A29344010060462D2C39506B83A19D99A29F9676300000000F29437093BBCBB7A86C3A0A101D21132E567A8C9DAAB09F84481F0D0B1E507593B2C9D1DCDFA45A0A000000210000000F2943709301FE8961070708906E857B8068370000000005418EBCC2CDCEB49B7D450900000D1E3C6D7D7983ACC1B19F85471A000003386D8BAFD5DBCEAC70320C071F242A2A34659ECCD7CFB79143060000001C58AFE5DEC7DDD8DBCAAA785650566B84A8CBC5BBAF89511712356778878191A4ADA898803A0800074CA1BFD5CEBC7E2C050C5D93B6A69F604554869D969B7A4F3F34190E1B528EB1BEB5B0ACA04F18224E92A8A9A984360300614F3E36424D6F91A1ADA7A6A09B742E0000000F20436FA0B8CAC0956330000E1F131B3D58798A9AABB59D6F4D1E2928455F9CB3C6DDEADFCF9B4000000000250000000F20436FA001FE8A61070708A076898B89511F000000001F6FB6D3C6C7C5B197631F00000016325D84836C839EA98F7B683B180002185AA1A4B7E3E4C5A04A160510273437314277ACCBD7CAB18031000000112F77D0F4E5C4CFD6DBC49564535358808FB3C9CBBE966D250400205C6A8591B0B5BFB0854A1600002464A1C7DAD3AF601A031E69A1B6B697594A608BA4AC885D443D2C11113979A8C0BDBEB1B39A4E1D1D5C8CA6A8A57E3100005346383641547B96A0A3979CA28D66230000000A1A3C7AB4C8CDB58C552006101B1C214764767F9E9BA2986D403039454E7B9FB8CDDDDFD6BC8337010000003A0000000A1A3C7AB401FE8B61070708B07C9287702F00000000063986BED3CCD1C9B8994E0B0000041C4B7F9A85697A98997C5B4F1F0F10113885C2ABB1CFDBBF743D1105192E36383E5187B6D9D0BAA46921000000053086DBF8EECFCDD7D5C683524C4C52829BBFCFC9BA844D1200002543517CA1B7C3CDAA743B0C000B306EB1D4DACB96441402308CB1BDB6874F385F85A8AB95613A3521191B5894BDC8BFBEB2B08E45293A759DA7B29B702200005D5A505153657D92ACA3A99F98825728040000001C4682C0DDCDB7884515112A222227597E757E9CA6A78854383F554A5C7BB0C5D3D7CFC3AA6C24000000103E040000001C4682C001FE8C61070718C06D7D805C2100000000114E92C8D0DAD6CDAE7D2E000000102F649AAF96827B92886644321001060E3F92BFAFACD5E3BC61200613243334485B78ADCEDFD8C291541E000000113995EAF8E9DEDEDCDAAD5C2D2B3D4F80ADC7D9D4AF76350B00000C354666A6D0D3D3A3541C0203193C85C3D9CCB273390F19589FBBB0A87945455C8DB2B185512D271A123475BCDADFCBC2BCBB8434224C879EABA897661800006E5D6673727AA0ADADB0A18E8D744D1F010900081E4E81C1DCCDB08D3E0C1C302121285C867A8B999DA2774433425057699DBDD1DFD2D9C099600C000000074B010900081E4E81C101FE8D61070718D08092884300000000002D6AB3CEDFD8D2CFA9681F0000001F5289B4BC9B9C837B63392C1F0A060715479AD6B8BFDADDA8591405152C4046596E92C3D3CCC9B89C58110000000B40A7EAFCF7E9DED6C08C471A12234676B1C5D5CFB16C26000000112247789FCEDED6A24F17050F305092CFCDBD90532E122C69B2AE9A997A424071A5BCC991531F161121438AC5D9E1D5D8B19D763F33678FA2AFA79D5F0F00026065585C6986A3B3B6AB968F7A67401200000000155094C7DFD4A96A2D1B2A3E3C323C798E7E7D9F8C917946323C4F5678A1CADCD8CCC0A889410F000000135D00000000155094C701FE8E61070718E07C7C5822000000000E447ABAE1DDD6D5C2934101000000356CA2C7C1B9A7805B3C1C151904080A19499BD3D9D0E0DBAF4A0E00081C30497594B0C9D9D6C8B9954A0D0000001B54A6E2F5ECE9CEC8BC762E0D08264E86B0C9CBC7AF6A2A00000000214983C0D7DCCF8F410600104172ACD4D9A96E2E12144491BAB39D805A373D709DC1BF843C1D0F0A275FA9D2E5E4DCD0B29155323B6E9CBAB5B0985C1505197B68636B8298B3B8B5A6957E6D482902000000032964A2CADAD6B377332C3F49444558778481969D8E896234253F5B6482A4D0E1CFC5B094622400000000216A000000032964A2CA01FE8F61070708F07263370500000000185193CAD4D8DACEB9861F000000084186B5CBC2B5AD713B2616171609060A2660B5D2D8D5E6E0AF4613030A21336683A3B9D0CEBEC0BB9646030000002150A6E8EEE8DDC5B088480D00043469A0C0C2C1C0AA6425000000002B55A0C8E6EDD387340A00175A91BAD5D1944A14061D51A2C3AB896039263E7EB3C6C58337100410336FBFE3EAE3ECC49B70462B528AA9B4B4BA9A4914042C6D6D6C6E86A2B7B7AAAC9E764C3B1800000101072C77A7CFDAD2A86736354E55606477878785928C7E7E56384151535E71B0D1D7D7B4967243100000000D38A3000101072C77A7CF01FE9061070718006F542000000000002C6596BAC4E2DBCDBA6C13000000176C9ACAC9C5C1A4622F0C051F1A0A030D2760BAE8E0E1E3D3993A0600051C3F72A1B7C3D0C9AFB4B78D37020000002960AEE4E9E7D5A48D712D0400093984C0D1CDBDAA8E65290000000D3D78B2D9E2E7D0763202031D66A5D1D6B474320B07276CA9C09E794E281C467BAECFBD782B04010F3A84D0E3E7E5E1BE7C513430649BBBB7BBAF87450C17496F5F5E6985A7BCB7AF9F886443230800001013164179A9C4D7C8AA5C2D344762778395968E8D8B987F82564B3F514D6588B6C3CFC1AF844A23060000031055AC001013164179A9C401FE9161070718106B3800000000000A4276A7BFC9D6D8C69D4403000000227AB5C7D2CDC6A75D200003222915162D4479BDE4E6E3E5D0852E000004133E81C0C6BBC0B8AFB5B78B3300000011386DB4DEE4E4C59F7C51180000105393C7C3BFAF9F713D0C000000256596C4E0E2E4C96B2504123680BED0D6A1561A0811418DC5CBA1744420254E88BCC5AC5C24000027529DD3DDE3E2D5A76334233B7AB1C1BCB89F7531142D5E705A586888ABBBB2AE9B794B2812040C1F2D2D294C83ABB6BEB794451D2348708892A2ABA3A3A4966E71544653565E6F95B6C7CABA955D381400000004237DC01F2D2D294C83ABB601FE9261070708207A3C08000000053D7FABBFCBD9DCD7BF842C000000003A92D0E2D5CFCA9E5D210009291E181A3D5784C3DFE9DBDBC5742A0000001B4EA2D6D1B5BBB3ACBBB6884200000B2A5B88C1D2D9CFAF7543290F00001C6B9EC0B7B7A57A4B2B0800000B327CAAD2E7E9DFB0592306133F93C7E2CB8C3B0A00105AA8D1CFA177421F2C5391B3C1A7571600022F6AB6DBE3EFECCB95441F224188B4C8C7B79C6B200C356F6659445985A9B8B1AA926630130510103643464B74959BAAB1AC774C1D1B4D7490B0BCBFB8B7A68B6864493D4B4F5A7890B2BDBFB58E5825000000000C4A9AD43643464B74959BAA01FE9361070718307E36040000002466A2CEE1D9DFDBD2BC7C21000000184DADCBDFDEDDCA9C4310000122291720516E9BC1E2E9DCD5A05C1A0000052058A8D7D7C1AFBCAFB6B47C4205061740668BC2D0CDC592552F180B010C377BB1C5C0B8A3754313000000174591BAD5DDDCCE9A4713001850A7DFDFC4752D0A012478ADCDC3AC7F371F2E64A0C4BA8B361000023185D1ECE1E9DDB1723B0E174E9BC3C5C2B79B48100A467D645038568CB2BEB9AF8755320000072A405F6158889595A4A19465280A164475A1BEC0C1B8B9AC95676E4D36484E587F9CAFB6B8A7854215000000092D6FADDB405F6158889595A401FE94610707184079481608091F5191D4EBF0EBECDDCDA25712000003276DBBD3D3D9D4CD93471100001B1B18417789AEDDEBE9E1BD894C18000013317BBAD6D4B6A7B1B8B7A47C3B1409326186A4B8C5C2AD773A171510000D3A86B0B0B2AD956A35090000001764AFD1E9E6E6BF7C2B0E112265B6D8D8B9712600003487C4D5D1B9883A243873A9BAB0742300000C4390CCE0D9DAD1A25B14021F69AACCC8BFAF772C0A0E4E8072565074A5CEC6BAA7875C27050A1C2C567C8C879D939A9E9D7F5727031B477BA8C5D4C1CBC7AE9266634B44454B5A84A4B5AEB5A8784013000000133387C1DE567C8C879D939A9E01FE9561070718507143211A173672BDF1FFF5EAECCCAD7C3C0D00011F4E88CCDED9D7D8D298460A00081E2423588EA9C5DFEAE3C7AA652D0A00061E5391C1E3D3B4ADB8CDBD9B6F411D23567B8D98B0B2B59C502508090D001C4D89B5BFBEB19D622202000000236DB6DBE6E3DAB0651B04112D68B4DBE4B5611801084090CACFC9B4893C2C457BACC29F621500001E5FA9DBE2D5D1C1773A15052E7DBFCED4C3A463180018598C6355546797BBC4BA896E3D110A132D4765929EA6A39A999882633E150A173D83BBDCE0DDCBC2B09068644B382F2B4D819BA0A0B19775370E000003184CA7D0DA65929EA6A39A999801FE96610707086071462B272F5590E2FFFFFFFFEEC48F5B28040319447BBCE5D5CCD3D9CB923B0E00021A172D6EB0CAD5E3E3D9C18A41140504083170ADD0E7DFBCB1B7BCB39878552A3C698E9492A0ADA984370D021B0F06245B97B1B7BEBFB56C1F000000002F83BACDCCE0CF8E492319173A79B6DFD8AF4E0A000A439AC3CCC8BC8A3D415D96B2B38E3D0B0008347EC1D9DCD6CEB1732600063485C2D1CEBE8D4304001E71947563719BAFD0D6C1A1663D3136323A5180A3AEAFA28A8F8F754B200007265487B6DDDDD4CAC5AF8A545537321E264C7FA1A8A4A89F85431602040E2367B0DCDE80A3AEAFA28A8F8F01FE9761070708706F4D4346547FBDFEFFFFFFFFF7B47E3F11060D305D9FD4F1DAC4D2DFD1903B0D000012285591D0D1E2E1D3D5C37E320C0409194188BDD3E0D8C2B5BFB9AE85726130428799918895ACA06D2C02061B14132E5587A3B8B7BDBB7721000000002D83C0D5D3CEBD7D46251C204083BDD3D3A74504000C549DCCC8CBBA7A414D72A1B6B47F360500093E87CDD4E0D2BD82411100154C93C5D7C5B9732B00002C7C9C746F6889BED0BEA98D663C2937424E5E84A8B8B99C81827E6D3A1805001F569BC5DCE2E3C6C5AF874B6336191918387A999895A4936F37160E0E0F357BBBCFD384A8B8B99C81827E01FE986107070880786750606C9DDAFFFFFFFFFFF4A55C340E0A22448CCAF0F0C4B8C9E7D5853508000E254274B4DCE7E0D6DEDABE76280000001658A4CCDDD7D2C4BCC1B6936B6D5C345088979B8089A69B6D1F040D1E1917435D7390ACB1BAB6782300000008438EC7CDC8CCAF6B4332393A569ECED4D191350000084FA3C2CEBEAB773F6085A3AC985F1600001D5CA4CBD9DBD0A36D230000165CB2D6D6D0B15F0E000D4085A575797E9BBBC9C0AB91673A2F4450617389AEBAAB94828178512207010A476BB5D6E0D5CAC6B194743F3F38260F124682A28A99A18E6A371C030E115889BEC4B789AEBAAB9482817801FE9961070708907B6D6A6C84B8F3FFFFFFFFFFE48A3D2016173369A4E2FDE8B5ACC5D8C9762F0E050E306DA4D0E5E7DDDDDBC4AA581C0005000D64BBDADBDDCEC9CCBD956B556764415C9EAFA1909EAC915613061E34241C44616886A1B4B9B271230000000E489CBFC4BFAE8A4F4753595D85B2C9D1C68C2900000050A2C1D0BEAA6855739AABAF9451100000306BADCBD8E1CD8539080000256BBEDEDDCFA4460500185491A285939AB1B6BDCBB2825F4637445D71759AB1BDAF8F757E77431B00061D3F7BB3CFDFD7CFB8A1905B404C2F1C0C174B8A9D97939D926835231D0A1A599BC5BB9A9AB1BDAF8F757E7701FE9A61070718A07D7C7591ACD0FFFFFFFFFFFFD2843E231E273D81CEFFFFE9AEA6C0D3B96B240601143782CCE8E6E1E2CCCFC79E5C310C0000225AA5CDC9CFD3CDC6A67D554A574A4367A0B3AA9BAAB58838101C374C38365659596F94B6B9A4641D0000000B4FA5C1ADA78C6445486E7E81A7BECED1CB761800000C529DC5CCBD905450879C97A37E3C0200134F8EC5DED3D0B2732C0000032E83C1DFDECF902A0001306FA098899FADC1BCB7B39E85552826465A7193AAB3BDB2927B6455290800031C4281C1D8E4DFCFA38A62422D4E3A271D2551949F8E98958B6B461F1E0D237EB8C39E71AAB3BDB2927B645501FE9B61070708B07E737A98BFF0FFFFFFFFFFF5A96229202B395B98E3FFFFCFA9ADC7C19A4B150400164B9EDEECF5E3DECFCBC48E442911060E1E5FACD2D1D5CDC5C19857232F3B404579AFBAB8B2AAAA823C1D2A5268524E6E63525073A9BEA859160000001558A5C6AF9372433B6A97ADAEBACCCECAB55A020000105197B0C7BD8A5659959F9E976B250705296F9BC5DEC9DCB1550700000A42A2D4DDE7C7781A000D4182A3A98B9AA9A9BCBAAD976C4B252029527596B1B6BFAB8F735034110000192A5D90BCDADFD6B8936843333154373428346695A3A5A0907855383224184291C3C79055B1B6BFAB8F73503401FE9C61070708C075788CAADEFFFFFFFFFFFFCB8243312C324268B5F3FFFDE2B7BDCEAB6A340B00071755ACECF2F2E1DFD1BEA76B352523130C2771B9D3CED5D1CAB28639101421274788B2B5B1BBBAAD73331D436F70575B7C5F434568A9B58E480B0000113466AEC4A27E4C2B3D7FAEC4C9D3D2CCBBA049020000185AA5B8BB9E64485F97A4A5905B1F040B4887AFC5DFD4CFA746000000235AA4D1DDD8A95717000D5CA0A799899CA5A9A198A28C5C301D133C5D7189B1C7C0A2896D3A0E0400000F33609DC3D1DBCFB3804E2F2F37684E4F456D7E95988A96916B4E302312174999C7B38249B1C7C0A2896D3A0E01FE9D61070718D079859CCFECFFFFFFFFFFF2AF602D22263C5990CAF9FFFEE5D2CBD1914F1D0000012965B6EBE8E2DAD9C9C29250322D321E1D437DB6C2C9CEC2BC9A722200000B1D4991C8D0C6C2B79E621F295A768876808D683E486FA5A96C2E0800041A407CB4C29366321F4289CAE3D7DBD8C4C68F360000093362A7C3C3924A3E69A7B7A9813003001669AAC4DBE2DCBD8C350000003170AFD5DACA873705082870A3A59992A7AAA3A6A2A5905E3323203B5C7D9CA8BCBFA9886218000000001E375B9ABDD2D7CBA970382E2C36885E56566C8A96847F848461483424231D5CB0CEAE6A2CA8BCBFA98862180001FE9E61070718E07C93AEE7FFFFFFFFFFFFDE8C44221F3453719DE5F0FEFFEFE0D9CD8234090000043175C5E0CFCADACAC8BA71291B3A47383B5189B0C0BBC2BFAD894C0A0000001B62A6D6D7D2C8AF9155283C778E896F848B63463A6CA49D52230000102A608ABEC69F562015318EDBDDE8E8DFD2B66B1A0000133A739FC5AC74383E74A8C5B881300000196FADCFD5DCC8B37E280000105194C3D3D5A8641900003977A9BC9F849C96A294928C7E52331A1C415A7A9CAEBCBA9784570B000000041E3F587EB5BBC0C0A15632183D3B7B5F5D768A8E85796F8B80563B32291E367FC0D2AF5A24AEBCBA9784570B0001FE9F61070718F07387AFE9FFFFFFFFFFFBBD66342025375C86B2EBEFEDEFE6E7D4B36C1C0100000E417AC5CCB5B4D4D8CFAB5A291B3C53514D679FB3A3A2B3C4A66125000000001A6EBDE5E5DFC59764342D4E88A8927782927D5D4D80AD8B4011000012487A94BCC0995014043291CEE3EFE7E0D0AE5C0B0000235388B2C3A561374881BCD0BB601800001E6FBBD4D0CAC4A259130004285FA1CBDAC694470C00164292A5BBA6849299929798A2725E2A1E1D3157748DA9AEAF987E4900000000021A314C719FA9B6A591513236374A947379919F94715C616156413F3730294892CBCBA05026A9AEAF987E49000001FEA06107070800778CB8F7FFFFFFFFFFF2A7522614234A7AA7C4E4F6F2E6E1D2C8AB510F00000011479ACDCCA9B2CFE0CE8F3F11122F5071768AA8A098A0ADB8833C0B000000073884CCEEEEEDB3753E1E2C649FAE98909BA97C655D7C93672E0D000E2D618BB6C5CB8F4408032D8BCEEAEBE6E2C7934804000E3E7590B6B779442E5A9CBDCDA8560800003486BCD7DAD5C7974506000B3F83B8D0D19B612003001B61A9BEBC9A7F7F887F7D7D886F4C251A223D577B9AA39CAD956F3A0000000000172A466A8C959C958152383B46569D81849299826C5D5A624D343941464965AAD7C1974E20A39CAD956F3A000001FEA16107071810728CBDF2FFFFFFFFE7CF863B0E1325539FBCBDE6E7E8E6CAC4B2863A080000082E63A7CDC6A39CC2D3C67B2E050D346C8F9EA2B7A596A1AEA06F23000000000A4085D4F3E9D292603011216FA4A09791A5BA9B8D74836E481B0300184D85A4B5D5BE813200072B78C1E7E4E7DFC876290000245C90B3C7B56A282C62A4C7C39F4A0300002F89BFD5DBC9BA771D000014549BC3D4C0853C0E00003380B7BCB9A57D7F7B8485847E5F3A21112B456A7C9DA9AB9D926A1E00003A140C0E1D49728888908A724834304158A28D9A9EA78A645E584E3F263144516A89BAD6C68B3F0EA9AB9D926A1E000001FEA261070708207194C7F0F6FFFDEBD9B96A2B0B0F3369B5D5CBD4E0E3D3AAA4985B2203000022478EC1DCC79596BDCCB57222081E3466A1B7C9BEA39FA6A6753B0800000000195EA0D5EDDFB6713419082772949A9B98B3C2B19E7D705B331A0E173B6A90B4C2D4BB63230000267FC8EDF2EDDFB0561300003779ABBDCBA453253478AAC5B78628000001388DBFD3DED9A95F12000E326D9FCCC9AD742202000B4898C0C6C2A3707174767A7A744D28151630526A87A1B3C1A4895E1900000D0D07042851818A8B877A5C3E2626366AAF9AA8B1A59578655245291828436F8DA9C4D5B67F3411B3C1A4895E19000001FEA36107070830748DC9E2E0F5FAE6C68F4A12030D3393D5EBCBC8DBD9BA8E867040080006183875BFE4E4C69690B7C4A14F1D100A306CABCDC6BFADA5AC84511500000000003976A6D7EDD9A95E270B0C2E708D8397ABB6C6C1A87245351D1414365F94A7B9C7CA9F521603082874C0E7EDE7CE88410D071155A6B9CFCF954E28438DBCC0B374140000113F92CFDADFD4964A12001E5194BCD1C091511C000213539FD3D4C3A07472707271786C3C290C132E3F7091A2B7B49C7F5316000008000E15345886A0978B7365401E153E6CB0B8B0B8AE95867C552C13112B447EA8C8D1CCA86E2E10B7B49C7F5316000001FEA461070708407186BDD4D2DDD9C7A169240901134995D6DDC5D0D4C7A475503920020001205096D1E3E3D5B897A5AE803F241A152A63B2D8DAD0C1B2A6772F0000000000184C93C3E1EFDCAA501A0000254A5976A7BDD4DADBB87B321E0F1D30578AB1ACB6C0BC8F4B100000317CBBD7EFF1D280280D042570A6CBD1C394362B5196BCBDA04C0600000A3C8BBADDDCC9812D09093575AFC3CBBE883F00000C357AB4D0D0C2976D61655A64613E1D08031224416795ADBDAFA87E4809000003101B2F557D96A49E967D5E423B344278B0AABBB9B292877552270E001B47849CC8D1D1AA69220BBDAFA87E4809000001FEA561070718507593A7B1AAB3CBA5651C0000001359B0E9E8C7CBD7CC89522C1F0800010F336AB9DEEFE1E2B79689987139341C182667C0D8D9D8C2BD9B4C1400000000052B63B3D3D7E1D2B25616050010253E6CAACFD9DFD9AD571A091C28507BA6B097A5C1A96F300F01113B7AB6D3E2F2C561180B16408ABDD1D2B876322766ACC1BD913E07000020498CCAE0E1BB7131131E5397B3C5C6A8622200000A4793C7D4C6BAA76A7169675E48391F1003192943749DACBDBBA58B460100000125323D709BB3AFA3906C50454141637AACB3B9B7AD9E88745E1700001A5791B0BFBEBDA368351BBDBBA58B4601000001FEA66107070860707D86908BA0A76D2E000000001369BFDCD6C5D0D3B86C3411020000021C3E86D0EEEFEAE1C29C838565474125161868AFD1D3DCCEBC802F0000000000044A91CCDAE1DBD2B856150000000C2B5CBEE1DADAD5B1571F060F356A9ABCBF94A5BA92561C020A224B81B1CFDDDE994C1C2D446496C1CECD9D58213584BBBDB77B2E0100052262A0C8E5E1A24F2115286EACC8CDBAA35A1E00032061A9D2CAB9B0A1726B635A4B3E290D000D131D48799EB2C5C5B17E410100000120415E8CA7BDB49F7D5B514F47485F7DAAAFBCB9AC9F96763E140000225187B8C3BEA98E5C3B39C5C5B17E4101000001FEA7610707187074665E728295824500000000002F82CFDCD9C2DAC8A14911000000000D26639DC8EBEBE1DFCFA0695C56575D351F3174BCCFDBD7C9BF74340000000000175AACD4DFDCDBD3B8571C00000005296CB4D3DADDD8AB4D1400184B7BAAC1C1A6ADB27A3600000E376CA0C0CCD2DA933A1A386387ABBEB9B780401B489AB8BFAC6A240400153C6DAED6D7C37F341B1D4A8FBFC7CDB77F3A0E00082C78A7BEBDB3AD985E6265453112010000151423407DA5B8BFAF956E3B00000008355D7299A7BBBDA17549504C56656D92C2B5BAB5AFA383673B0B00002661A2CDCBB4926C4B3B40BFAF956E3B00000001FEA861070708807760496C828264230000000000388FCADBD0C4C7C38A3D0900000000122965C2DBE4E2E4E5CE8A583E2F56663F314475B9CFE0D4CBB581360000000000276EBCD7D6CBCEC8B65A17000000001C54ADD6E3E7D59A40030B3877A8C9C9B5A4A19354150000164E88B4CAD4D8BC691F204F809BB2B19983502124589BC6C1AA611D0712295B8CC4DEE1AD641C14295699C1C4BFA75E20000011579DCCCBC1B4BD937174673F1800000519180E1E427CA7C2C3AC9E6F380000000C406285ACBFC9B48E634A535367757A92B6B1B8BBAB96885B2700071133639EC5BFA78558413D53C3AC9E6F3800000001FEA9610707089069574A70807145040000000001448DD2E1C6C2B8AE6F2C0700000002133980BAE1E6E6E3DFC0864231315B5F48446389B2CBE0D6CFBC832700000000002471BAC5CCC5CECAB4591B000000001A58A8D2E0D7C8852D020F3289C6D8D1B9A59E6E2A0300092173B9D2D5DED6A34E15296F97A7B9A481583311205BA6C4C4AF64200E123B75A6C4D6CA9B4E1F142C72A9B7CBC49C4C1600002A6DB0C3C5A9B1AB866D6E5D380B00001B1F1A140F4A81AAB3A1A0885F360700001A597B99B4C0BCB08F6A504E4C62758D9CB1B2B9B6AB8B754D1B0007133B81BAC9A99D7746343D72A1A0885F3607000001FEAA61070708A0715D4F72835A290000000000205BA7CFD6CABCB890551F05060200031B4778BEDBEBE9E4DFBF7827001148534D5B8997A8C3D7E0D1C7953A00000000063385C5D6D7D2D0D2A9531D000000011B599CC5D5D3B86A24041955A3CAD7C6B097814E0D00000A3A90CDE3E3E6C27C2F183987BABFB9855D2E1409216EAECDD4B963220D155095C5D2D2CA95390F183B7BBCCEC6B2813F06000C4580BDCEC5A8ADA46A63594D250000001518110A17467EA3AF9E847359311F1018436F94A4AEBBADA68256584A33546F93A1B1BEB5B7A17F5B260E00131D4C7EB6C4BF9C663E2D49749E847359311F101801FEAB61070718B0736A637374481500000000114665B3E2E1D1BA9E7942271A0905050F295B8FB1CCD9DCE7E3B75E1700062E45527FB7A4A2B7CFD8D4CF953E0A00000010499AD5D4D0CDC4B4934216000000042A529CBCD1CFA44C0E022060AEDAD5BDB2A7752E000000164CA1D3DEE1E3B6601C164AA0C1CBB67F431900052B74BFD5CDB3642010215EAECFD2CFBB833218204C8CB8C4C5A173280000195C9DC1CEC2BBB19B576355431C000007212D2018385E7899B79C7E7667433D333D648B9DA3AAA6A596745944474E597B88A4ACB7BAB8A8734E2811000D2A6DA0C0C7A78536222242869C7E7667433D333D01FEAC61070708C06F706C74501D000000000022578DB9D8E0C9A98A65382D2C220D0C20356C94ACCADEE5E2D9A551120002283A609FCBAC95B1D2DBCEC5923E100500001D5AA6D1D8CDC1C3AB74350F00000D2E486CA6C1CAB4713004051F68B8D6D0C2BCA967210000001D60A8D8E3DED69C4E1A1F60AFCED8BA732E0600124E9CBDDFD8B25923081F5CABC2D2CFC176270A204790C5CDBBB6732000002671ADC2C6CCB6B88D39695137100000001F2D2A2D446C81969181695F574C5053668597A4B2ACB0A59374573A4F3A54769CB0ADBEC3BA906F4B1D0001103879AAC4D1AD814718173E7D81695F574C50536601FEAD61070708D07981765A2A00000000000854808EACD1D5C49369442D474C41231F2D4A7A9690ABCFEDDFD087370A000621366AB1C7B09AB2D4DFD5B67D37170B09082B77ABC2BFBBB5AC8D4E1706000013486A80A6CFCFA4501900002575C5D8C9C8C6AF621B0000012E6AB4E6DADED084411E2472C3D5D9C880210000165BB0C7D9D5AA5710061F5EB0C5B9C6AE5E200C145796C9D1C5AD641A00023780B8D1C3BCAEA9600866532E0200000011223E43346E7380816E5957526366617290B0B2B2AEADA1937967524D49527599B2A4BDB8B48C60381E0D0E2D4E7CADCEC8996C401512417F6E5957526366617201FEAE61070708E0686C58360800000000001D68858BA5CDD2BC8E48352F5D7A542B0E26517B939297C2E1DCC47E2F12080D244180CBE1C7AAB8CBCCC1A36129201911183778ACC0C3B0978E5E2B0800000B3E73929DC3C0B4863A1000012982C5C7C3C5C5A0500D0000145086BCD0CFCBB7722A0C3D8ECFE1D9B46E2300003073B5CBD4C29B471309206AACB4B0BA9A48140312479CD5D4D8B470270A154891BAD1D1BFBD964D0061412710000000173E4F687783858D8164444B5D665A5F87A2B8A4A9A3A4978F7862574E454F749EADA8BDC0B48760492F271F34638EA1ACAD9354310E0A419064444B5D665A5F8701FEAF61070708F0736E5C2500000000000058A5B79CB0C1C6C7844025437A8E592E2E4571949F8B9BCBD9CDB15F20090D15295F90C6DFD5B3C1C3C4BA844B2F3A4228213C749FB7BFAC75642900000005215590BBBCC6CAB97F2C0000053885BCCFBDBDC0832D000000276EAAD9D0C1C39A5628194696D1D4D5BB6A1A000D488DBAC4C1C28A310F113480C2B3A0A485340506184CA5D8DCD1AE5B15002266A2CBCBC8B1AA793500703508000000001A4A53737A767B85774D33466066676A8AAFB0B09D9E929087756B5B47424D6D8DA89EB686A189553E39434659718A8A8F8E744931191D4A9B4D33466066676A8A01FEB061070708006D65461C00000000111A7CC3C2A2AFCAC2A96F2A2B578F8F59424D66909FA99CA5C3D6C38F3E1B131C20436CB1D6E6CCC1C4BAC2A868352B444B422B457697ACB1925B16000000001B4782C2C3CBCAC6B679260C0006367EB5B6A6ACA66F270000144F9FC9E7C9B6B880340A1755AEDFD9D9B3550E0019589AB7C5BBB5762C081C5997C0BEAAA3692900002055A5C5D4CDB65F15052372ABBCB7B4A693541E005D33150000000D2B535A768782828A6F483750655D65708AA7A59A9395928F847D7669554D466F99C09FBEB7A880583A404656687C896D5D9D62372F2B3665A7483750655D65708A01FEB161070708107564361F060216182B3998DED9C2BED7CA945C3746789C8A5A517091ACC6CBBAA7BFC1A065241A242C2E538CBBCDDFD1D2CCBCB57C391F2F415F53334F7990AFB98F3302000000002F6DA4CCDAD1D3C8B6751F000016417B9A9D99998C491300001B6BB9DFE2C9BEB7772C102161B0DFE2D49F47090827609CA6AECDAF752913316AB3CCCAB8A15F1705052766ACC6CBCAA34307002A82BABEB3AE9F8137090064320D0900001C3C50687A87828785643A2F4D5B616B7D8790968B7C8883847A85837561515D7A92AAA1B7AFA2764E3E47585B737D68454746402D36364E7FB83A2F4D5B616B7D8701FEB261070708206E5F4428101D28445569B5F3F2E4D6CEA97C4F3A57849578667C9DB6C9D8DBCBB1BFAC793D16242C283465A5C2D8D0B9B3BDB69F6329152A44766B5457849F9CA88D350000000012549DCDDBDBD0CFB79F5F1C0806213A638B908D7D632F04000B3885CCE0E1E1D8C86B2518366EAAD0D8CF832E060843879F95A8B6A3571E143E90B5CECFBD9C3E0406214A84B1C3BFBA933A060D3E98B7B8B2997B50160000583928271C21334C5A728D9194897E4F202541596B6E7E959D89777A7C7371797E89786755698B9CAF9CAFA793694F414A5D728278633D231A13112E3F6793CD202541596B6E7E9501FEB36107070830806852493B405673808EDAFFFFFFFBDCA576564F75938E6F6394C6E3E2D8E5D5B7AC93642B11293D293880B9D2D6C7BDADB2B58A3511111D3F8187737393A3ACAF7B1E000000002780BBCDD6D0DBCAAF8C4B1A0F153C4556707B84694918000A204F99D6E6DDE2DCBB6A211E448ABDD3CEAF582006125C97A29699AB8C49152158A7CDD8C7AB75240D0F406DA6CBC0BFAB631A000B569EC4C0AD8A5A2F0400006A50504440444B577C8D979F9C947C4C301C3550667087948D7C7570747571868F8B745F546F8AA8B98EA19B7A57434D4B657F877E612D0D030009274678A4CD301C35506670879401FEB461070708406F645251434F6695AD9CEFFFFFFFEABA87594E577888776972AADBE0E7E6E1D2AC9B7A4522264C523E4788C5DFD7D2B79FA9AA7421080E1F3889A49E96A0ABACA77610000000003B9ED8DFD4CDC7B5A56F381319395D655E6C878B5D2E0800092D5B98D7DBDBE3E0A653222D5B96C4D8CDA34A110A2F75ADA18D9A906322002167A9CACFCA994E1D0A22649CC3C9C7B88D500D012267AFC2C0A3613B0B0000016858525654535D6A7C8E9BA09F9371452623354969839598897C6F71716C636B808772615E7A97A0AA899F927758303257738B978960220000000018518BC8E3262335496983959801FEB561070708507C70635F65798BB0BEC0FFFFFFFFDDAA7C605C616D8167597CBBE7EDE6F3EDC69369503E2F415F584262A0D5E4E0DCB7888F945E23100D163C8EC3BFA19AA7A8985C0F0000000241A6DFD4D5DAC6B8834E30103D6192896E6D9595531D0000154077ABD5D2DCDFC6893014356EB7C7D2C38E3206104494BCB58D776A3D1B002C81B9C7BEB66F2B010A3978BACED6CDA67224030B347AB7C4B9A76B250000000C6865736463617B80A3ACC6B1A48E6A43312C3D4F7189979B856763656D6B6B67727B62636D8AA3A6B3738880684134384C6DA5A28F5719000000001263A0CADA312C3D4F7189979B01FEB66107071860726D626B7487A2CCEED8FFFFFFFFC387545058656461546487C4DCDBE7FFECB96D462D202B406566507BB5E4F8F8E1B77F7C8C562A1E15133792D2D5BAA4AFAE8F48000000001D64C8DFE4DFDBC19F67311B143780B1AF8886A195490D0000255886B3D7D8D2DAC1712813387EB0CECAB4702B0E1A54A8C3B8935D3A1A00012A7EB4C3C3A96018020F4998C5DCE0D0A05520061A4797BFC8C2A5551700000021707C7F81807D889AB1B59AA888927C50344058738A979498826B70737164585E6E7A706B7F92AA9F9E617D6E58493E38527AA4A693660000000000297BBFE1E6344058738A97949801FEB76107070870776A686F7A94BBDEFFFFFFFFFFF0A96D554F58544C565B6F94BBD4D5DFEADE9C502D1D1E394C5F4E6194E7FFFFFEE4B17263704D251F162354A3D3DECDA4A3AC7B3404000006306EC2EEEDE7E4BC844616131E458EB6C7A499B290400900003873A8C0D8D6D8CBA84F0E0E3C7EBACCD0AB591A052660A8CAC18C53200000003B85B9C8C79E4911082264A3CAD9D1C284430F1442759FBDBFB690440D000008396A70848995A1A7ADB8C2C1BBAF925E4742426271909BA39A8C6E646D685A5B556C7677838C9FABA590537466514943436085B4A9986D21000000002786C9DBE742426271909BA39A01FEB861070708807575787B87ABD4FFFFFFFFFFFFD180574A404C534D557583A2C0CEDBE7F1C57B360E09143543514C61ACEAFDFFFFE098533A51462C21242D5EB0E6E5D6B7AFAF823000000014347CC2EFFEEDD1A061200B0E20418CC3CCB8BAC0913C00000E509DC2D8D5CECFBE83370B093485B7BFC4893A0E0C2D6EACD1C6995B1F01010A448EC4C6B8802E0E133C83B7D4D3CDB36F2A12244182B3CDCBBA904100000018467A7C8E9796A9C8CBCDD3C8BBB08A6A4B35425D81AAB7A2A5937C726A5F564F556475819297ABA1A48A475C5C4E3E464C7186AAA89B753D140000004486B7CCCE35425D81AAB7A2A501FEB961070708906E69718697B5F5FFFFFFFFFFF0BB7B4124334A46495F7899B3CAD4EDEDE2B8702B0503062034415780C5F3EDFBEECC7842304830302B263477C0F6F0DAC3B5B376240000001C4A7AC6EDEDF1C47743190914253E8CC8D2CCD1BD713003001E66B7CFD1D8D0C7C06F19000C4092CAC4C0742604134A89B1CEC198531E00001A4D91C0CBB0732B020D4487CBD5C5BEA6541D163974ABCECCC9B48C32000000265B6D7488A6C6BCD6DBE3DFD2C698745A383C4B6C79A4BCB4B2A396836E544C51556A7C8897A3A8A39274344F5B46524D61889CABB098794D331C0F1F599DC2C4B93C4B6C79A4BCB4B201FEBA61070708A076797B90B6ECFFFFFFFFFFFFD99B5F3A312F35414674ACC5D6ECE9ECDFD7A9551A040006152A2F5497D8EEEBEDEAAC642C202E2F36382D4185D6F6E6DACCBDB6761E000004325794C8F2F0E7A2581600040C27528FC6E3DDD4C574280700297CC4D4CFC4C9C89A4C0B000F5A9CC9D1AC60170C305E91B7CFCDA9600E00001C5A9ABBCAAE591A0C1E5BABC4D2C9C78D3B0E114F94BFCBC2BCAE74220000003E7C6B6F8CA9C3D8E7E7F6E5D9CDA974583F48476588B1CEC8BBB5AC8E76604C535E667E8B8D9C9D96885F364D5F635156698FA4AFA295754E3C3E25316995BBB7AA48476588B1CEC8BB01FEBB61070708B07E808697ABFFFFFFFFFFFFFFC88553302F3132435884C2ECF3F1EAF1D5B0803F0A0000001423406CBCE8E9E0E7E5A2552320111A222839598FD4EDE5E1D4D3C6761B0000053770A5E1EBE0B9823F140607202B5692D5F2E7E3C1621D000A4492C4D7C2BFC2BD822700002167A4C1D4AF5215144585B1C6D4C4AD610C000B306F9EAEB584390D042679BAD8C7BAB87A2C0E2166AAC5C3C5BEA66019000011517F6A7494B3CEEFFBF7FFE5DCBA9968565546395981B2CBD4CCC5A791736156505F66839FAA9C9C84635929475D60585A7E94AAA39F95544B4240484B8394AEA89946395981B2CBD4CC01FEBC61070708C07A76789CC2FFFFFFFFFFFFEB9E6738222F262C3C6592D5EFFFF8F2E6C29D67310000000112224A8ED3ECE7CEDADB96452016151731373E588ED6EBE2DFD4CEBA732400001D5C90B7DFDAC69456310E1210283864AEE7E6E6E5B14B0A00145299C5D5D1BBBBAD5F1A00012C67A8C9D09C3F0D285EA0C1C9CACAA655140008377AA0B7AD5E2100002F7EC2CDC9BCA46B26112575B0BEBCC8C0A55A150000236093575E749BD1F2FFFDF7F9CEB294735B5B504C5C82B0CAC2CDCCB89A87604B5C5F698B9BA49A896A5648255268676B718A9DABA69775553736443C538BADB4A086504C5C82B0CAC2CD01FEBD61070708D07A7E8DA8D7FFFFFFFFFFFFD58D533126192635457BBEE0F9F9EEF3DCAA784D2411010B1115234D9EDCEDE3C3D2D2854C241E21283D556A7CAAD8DED3D7C9B2995C1C00002C76ADCEDDCB9E6B401E0C0C0A234B89CAE8F7E6DFA23E050015569CC8DBD8D1BF92450F00083480B6CBB67E2B104090BFCFC4D0CCAC541800144B90ACAA90450600002D76B7C5BAB9A9642B103083ACB1AFC2C39E5B110010447B9668687296C7F7F8FFFFF4E3AF986F6E645E5F7B97A3C4CFD2C9BDA17E6556585E6A879EA39C8368243D1F4F6D6A6C819CB1B2A393663F223746577BA6AEA47D6A5E5F7B97A3C4CFD201FEBE61070708E07A7D90A5C7F4FFFFFFFBE8B06F422F2A2432315B8EDFF9FFF0F0E8DEA9692B0906060F14172F5BB1F1F6DEBFC9C680351E22323D4B71818AAFD8DEDCD0B18661280E001055A9CED7CABA8147180100021A2F579BDCF6EFEDE0883901001852A0CDDDDCD8BE7E2E0004194C8CB6C1A8591C1942A2CFCEC6C7C3AA4D1C0D3874A0A39D7B3500000C4082B5BFB7B59750181B4891ADA3ACC1B6953A0506205998A255495A89BCEEFFFFFFFADEAD846F6C6F666587A5BFCCCCCECCBBA18A725554667B9BA9AB9063513E3D214E705D7B8FA6AEAE9B774325191C40277DB1B39C8168666587A5BFCCCCCE01FEBF61070708F07E8A8390A9CCF7FFFDDEC5A5623D2A292B364A6EB2EDFCF7E7F5F5DFA34513070C07111D1C3876C9F4EBDBC6CCAB6633252E40576B8BACB3BAD3DACFBA875D391200001D65B3CFC8C6A4692D0B000508213F6CB7D9E6F0EACF743201061456A9CBE3DBD39F601D131F3E6CABBEBE8C3A121751ACCFC4C4CEC69A481B1E49809C9E9567200000164E8BBAC6BCB186411B2961ACA99DA9C3C0843609012C709EA448404874ADDBF0F5FAE5CFAA8366706C6E75839BBAC9C3CBC5AF967B6156547D8378A6A48A6D543F4229546269849DAFB3B0996E3A201C31447196AFA9945B546E75839BBAC9C3CB01FEC0610707080078827C98A9B9E2FBEFCCA77E5A36302F353D5B82B4EBFFFAF3F7F4E199430E03071A1B1A234381CDF6F0E4D5CFA1572012243A568CB4C9C3C0D4D4D3AB673E160500002886B9CCCEC9A964230200040F285383CAE4E5F4E4B5571E0A071B549BD0EAD6BB7F41191F467096C4CCB6632204094BAEC6ADBBCAC49444203A729CA8998E4F12000019579CBBC3AB957337132D81B7C0AAC3D3B7692100093A86AA9E42364977BADCFEF2F6E9E5A77D6266637388A1B0C3CCC0CBB297887C69545E6E8FA5A993845B3F44432345586D889BB1B3A5906438271E495B819EB39E8556467388A1B0C3CCC0CB01FEC161070708107078838A8FAFD0E3D0A3896A453632353D4A779ECBEBFFFFF5EDF1E291320E000C1A1F27305491D9F7EBD0DBCA95481B0D173A67A4CFDBC8BEBCCCCDA45A18000000053084BBCACECFA15519000006103D6FA4D1E7EEEED99E58180E142857A1C9D7BB8C4F1B173A7D9FC5D0CAAC531600135EAEBFA8A7C7BF8B43305886A9A89B86530700013173ADBBB4997E5A2D1B488FC9C7B0BBBD9B4B0C05115090ACA0513B4F7DBBE0F9F3EDD8C39E8676738C9293A1ADBAC9C3BBAA93796C6456537898A4AFA286634C494B2435526D8FA1BBBE9F876B3D3137485F82A1BCA06F564D9293A1ADBAC9C3BB01FEC26107070820787C79818D9BB4C6A37D6548303431344A6191C0DDE7FAFFFFFCF1CF7D23030112262F252E5597DBF6F8F8DEC8823A14070E275EB4E2E5CAA7BDCCBD7A3700000000073D86C6C7D3D5A95E1B08000E2D5A95CBE5F1ECD2AB72371911233868A2D6DAB77725121D5F9CCBDAD8D09C4D0A000F77B6C1A5ACBAB37936326AA3AEA69B883700000F498DB9C7AA7C552E0C184FA7D2CFBEC3BB842400001E729AB5A0544F76A9D0EAEAE6E3D5BCA28C81868E99A2BBBDD4C4BCB29B8270615D5A608498A7A1978167514D49234D628096A3AEAB957B5C44454F647591A6A687634C4799A2BBBDD4C4BCB201FEC361070708307C7A7F807D90AAA38F684C362A2F33405272AEE2EAE2F4F7FFFAEAC26F280C1116252A2C385891CBF4FFECE5C38F481D0D0B1E65B0E3E8C7B0BCD1B76B160000000007338EBDC2CCD4AB4719090626457AB9DBF5F0DCB88749291E232E4A7ABACDD694521D0D2A81C6D4E4DBC398460D033181C0D0B8B8BC9A54264282ABA39D90753004002161A3BFB7A0603305002268A6D1D6CCC2A05F1200004089B3C0A154648CC2D4E3E4DADBDABCA4928C8896AFB6C1C7C4BDB2947D6B6662615A6A82A9B0A69A7A6657544F1D51708498AFB5A9876A53434D59627E9FAAB08C5D3C43AFB6C1C7C4BDB29401FEC461070708406F706D787C8790926A41302D25282A394B73C1FFF3E3DEF5EFF4E0AF6120090618222936456586BAD8F4F2E1BF9368350F0C2561C2E0E5D0BBCED4A4510E00000000104892CEC5C7D59C4E18030D2A579DD6E0EDEDE3A9532416212E4A6799BDCCC1863B0D0946A6D9EADDDCBE8C310109368BC1D1C9B4A58746184C8DA9A9A494722200032F7BA6B7BE94591800012970B1D3DACFB27C2E0000004696BEC2A6636F9EC3D6D1CCC9C6B4A38F8E777B8DA1B4BEBBC2BCAF92755B464A57605F809FAABBA684635B5A662C5A708B95AAADA3815A3C414F5E6B82A0A5A287664839A1B4BEBBC2BCAF9201FEC561070708507A756E7C82917C6F54392F212029364F5185CEFFFBE2EEEFFFF0D1924E16060D11212B49668595A8CEDEE8D8B693773F14112863ADDCDDE4D5DBC3883F05000000001A5197CACBD8CB9B491C13072361B1DEE8EAE6C67538120F283E6C8DB5CAD0BB742907104DAED5DFDBD2C68B2B03114FA5D2E0C5B1A3782F21588CB5B2968A611E00064088AAB7AD90520000083B7EBCCDC3B286530E00001B69A2C7CFA67B87A5C3D1C6AFB1AAA395867277848CA6B4BCBBC5AF8F766953475052546C83A4AAAF98886E68616E395E81979EA3A68F6856343B384F6B8B9EABA67B60473DA6B4BCBBC5AF8F7601FEC661070718606D7479858D8B7A6B4C342E2D2D3B465A6691D9FFFDE4F6F0FBE5C279432119141429395C889E9AA6BADADECBAD9B8A4A22203A6BABDFE7E6DDDEBF6C2501000000031A5DAAD5C8C7C084461D1811336EC2EBE3E0DAB16329121D244179AEC7CEBBAA5E24011A6DB1D4E2E1D0AC7628021B65A7C3C9C7BA996622205E93AAA19F81491100155591B1A6A48536080006468DBFCDBD9C6A2700000C377DB7CEBC976C95B2C4BEB4ABA296948079767C878AA4B8BAB7AE9E7D6C53494C4B4C59708D9FA69F917F676D5F715371899EA4A39C8453382F254955708C9EA79778594144A4B8BAB7AE9E7D6C01FEC76107070870707277888B856A56453A3635313C545F749FE7FFFFF4F9F7FDE3AF6B3C270D1D19274A70A6BFABA4ADA9AFA699B19F4D24274E82B0D9EDF8E4D0A75B240000000003154F9FD5D5DAB26831161C1B347DC2E6EBE9D7AD571B020B265198BAD3D7C79C501400166DC4DED2CFCCAB5813063172ABCDDBC6BA9F591C215E9EACAA9F7B380A001D6CA9B6A8A5753600001C5797BFC4A97836070000184D9ABBB9A6718593A6C2B7B09F8B7E807C7178737C919FB1C3BCB3926B504F474E545B5E6A8698A28B7F78767D6B70567D92A0A394917E4A382D3949546C8CA7A596785B3D399FB1C3BCB3926B5001FEC86107070880777B747E83716A5B4A413E3E464D5A7D8CA9E3FFFFF3FFF5E5C38D59372F1B191D2D4F92C2D3BFA3867076869DAB9A5A3342679AC2E9F1EBE4BE884C180E00000A16295BA1D1D9CDA94F2322252A3F7BC2EDD9DCCC9F4F2011092B6DACD7D9CCB68C4010032784C6D8E7D7C292400C0B3384B7C9CED5BF8A42182A75A1ABA9A26F2400002F7EACAE9993692B00003778ADBDB79F520F0000002F79B0BFA683497495A5AAA49D92806D6768676A6E7C8FA1ACBEB4A888634E4F4D4A59636B7690958E796D666B8173765B819CA1A5A084664926242F4A56839AA3A29168594842A1ACBEB4A888634E01FEC96107070890716F696E68625A4E4F46494843516C99B0B3DBFFFFFFF6F5C78C6C4A3C332D22242C5FB4D5DDCB9A6D51475E80988A6559739FBAD4E2DEDBD6BA662215110A0C142C395B97CAD2C99C53252A2A1C3974BADDE7E7CC924B070A083480C3D7D8D2AF82370F002B81C7DBDDC69C6526071B60A6C5D4CBCAB46A291F3C779BADAF99611A0003468CA9A78B895F15000C448EB2BFB57F2C0300001C509ABFC89C6423757F8E9791918169524D5A6066627580A2A0B0A8947D5A4845454D5C6A738990917F63565A636F6A74728F9DA8A4997C6246342C3A4852929F9B807D60585857A2A0B0A8947D5A4801FECA61070708A0707067685E5E564B5A545848445885C3D1C4DFFFFDF6F8DAAA69443C43413F3B2B4C7AC7E3E7DEA45D2D183A5F7B79697391C0CFD8DFDAE7DFB45C1F17111118394049567BBADAC48B4E373125284275BDD7E5E4D9973E0705072D80C8CFD2CCAC632205063295D3E3D0A87226080B307BBBCBD2DDDBB45D26224F7A9EB6AE95571200084FA0C0A78F78451D000B5A9DBDBAA3682A070001366EA5CCBC8043066C767C878477735A463A44566461768CA19BA0A78D7A544D4E494A5E677D939884735E4F5457595C73838F969B987F7255382F2F3B477B7B9DA6977E61595065A19BA0A78D7A544D01FECB61070708B07F78716C665F666C695E605D5879AEEEFAE3DDF9FFFFF3CC834E38434C43332A495CA2D2E9EDDAA5420600284E5F66768FA8CFD7BDC8DDE0D9AE4E200B0611306A856B55678EB9B182443F4B4038517DBAD8E5EACC813307000D3386CCDBCBC7A9571D060D449EC8E0C57F430D041B5290CDEBE8E0C59A470B255D839AA4A9823400002772ABBEB1996C3207002367A6BCBF96480C0202204788B8C8B98444066D6F807C847462543B274151606A7C92969AA09C8E80473C405B5962757E8C8580745548434D5A58708A90ABA49D7B6F563C3438405A688AA69D907463585F77969AA09C8E80473C01FECC61070708C06D66625A52595568756C635F617CB0FFFFE0D8E2F7FFE3B9622B223048494246658DB3DFE2E4D08C3705031F333B4886B6C9DCBDAABFE3F3E0933C1707001445909A815E4F66918664515C5C5353799ECEEBDFDCC4742E0A0C102A7BBFCBD1CAA84E09001365B8D4DAB1631F000C346EB3CBDBE4DDC180350F2D6682A0B39A632400175695BFC6B295541F00003787ABB59F89400B000D2D68A1C8D1BD8431006C727F6E6E6D5C3F322B34485065698396999E9785765E4A4F4C5A6A7D87878B846C463D364647566987979EB494584D34373E5453667B9FA8A18E725E58627B96999E9785765E4A01FECD61070708D07C665A5351556B6F897B6A666D88BEFFFFEBE3EEFBF9CA8D4D2720283D41415F8DC1EAF5EAE2CA934500000625384E95D2D9C8B5A2C1D4D8BB7C38170C02265BA0B99F6245536A6B57576E69697291B0C8D3D6DFBC8742190109236CA9B3C2C5954304042766B0CFCF9F440F0421619AC5D8D5DFD8C07020154480918FA5732F03002170A6C1BCBB87450900024587B4BEA7793509071C3A83BACFCABF913400776D747C79795E383C3D3A4156627E8E9E9AA88E85735949444E61788C878A8B7673503E31374059729998AA9A7E644D4148555557708E9CA9998A6D5E5E68879E9AA88E8573594901FECE61070708E0716C636464646B85977F75757C9DE3FFFFFFF9F1EDE3BA6B341B142136394779ABDCF7FDFADABC782902000E284066B1D9CCB3959CC0CDC3975F281411183B76B0C6AF764D40413E3C6182959FABBFC9C9D0D6CFAF7B4F25030A2E6EA0A7B5B97D290000075BA9C4BD8B40180E488CC2DAD9DCD3CE944410174F95ACA091591D00004089BEBEBCA66D31050006529BB9BCA3702F0713264B80B6C6BFB27B2E007676747D6C5F4F31312A35455D71808D939D9A8F806D5C524C566276888D8B968A65462B282E315A808FA7AD9A73563A374953636F8D9BA5A5A187705E5F7899939D9A8F806D5C5201FECF61070708F07C746260647077858E77787B87ACECFFFFFFFFFFE0C197522B18131C30385089DAF6FFF6E8C69C5E24050618364F81C0DDC89382A4C3C29D6739160F1C2C5582BDD4BE97633D281E34518EBBBEC1E4E1C9C6CEC3B592712C1D174478989BA89B530A0000094791B2AA7B370E215CB4DCE8E8E2DCBA6D27071C60A3B397733300000A47A0C4B89885561D00081C62A9BFC1AD6E34171F3C678BADBFC3AB6225007F7F807E77735845383349565E75839193959785786B5A5B5B63748397968584726448342332465F8F9BA39E8E7D5547425566666F8393A5AC9E847761566F8E93959785786B5A5B01FED061070708006F65585C64727A869289898699C0EDFFFFFFFFEEBA8E693E1F171D262F4363A1EFFFFFFFEBC383371300112C4C7DAAD6E2C08883B5C1AB713211010B21477FA4C6E8D8B67C411A11244A90B2D1E0DDD0B1B7BBC2B1A08550202F5C9BAAA4A58F37000000053A6D8D7F552C1A2F76C4E4DED9D9D1A5521A12326CA0A47C4B1A02082165B5C4A77B5E321302092770B2C8BE9A59282440617F94A7B7BC9D5513007979797C715E424232354B5766738B9C9096978578685E5E6670788A99938A8B78674421344051698B97A7A09374503D504E505E73909DA9A18C716C616D7F939096978578685E5E01FED161070708106E675D5A5C6B7F8186848C99ACDAFBFFFFFFFFE5985C4B312B34242B3B4870B3F2FFFFFFF4A65E2713061A3A72A2B8E6F3C48C8AB0C28E48090000092662A4BED2DDD3C8AA5C1C070E2F75B1D4D8E1C8B9C7B0A591948F6050618BA9B3A2905B1A0000000F3B5F8680501C163377CEEFF7EAE7CD84310D1E4F849EAA7B4114000D3576ACC1A56A43230F01103076B6C2A891543231507E9EA08F998F7034090079766F5D59514D3E3A38475F778193A5A4909174776966646C7F86908F8E8D8572613B312F4552738E92999B8F745D494C515B6A7E8C9C99998A736B5F668498A49091747769666401FED2610707082072685E6A63707D847B7F89A2BCE6F2FFFFFFFFCE804C353232332B2E3B557BCEFFFFFFFFE29A4B200A0C1D4C8CC5D9DFE9C9A0A8BB9F661B0000000D3074BCCEDBE8D1C7A865190002185BA6D4E2EECCB3C2A6845977836B7299AEC6C4B88E41000000001B4B7E94764019193983BFE4E8EDD8BB652719457BA6A39F7B360003224886BAB78846170902041A387FB3B6936831283C6BA8B8A88B7768512000006A63605F524740304C3F4A5F808C989896887D6A6864646E78818F94957D84876C634E464848586E8182999C8C6E5B4E464D5E738C95A09384735E59677A94A396887D6A6864646E01FED36107070830737571766D7180858E9099B5CCF1F9FFFFFFF9B6774335364A463638435E88CAF9FFFFFFF0984C1D08062353A3D9D7EBE7D8B9B2A67F30020000000D2C70BFD1D8DFD8DEBD641F00050E418CCCE9E2D7CBC997542F3948649DC4D3D2CBBD7C2A0000000A2E6B9BB6813B1D1E4290CCE7E7E2D39E4217246B9AACA5AC7F35060D376A8FAB97672F0B0000041C4583B3AF8B572B2B4885B8C8B3765D442209000076655C52474754443F465F6B8A90999992837365655D616D7287908C97918878655C4E464F4A577981868F8B877458574E5268747B8D8D7B75685562687C8EAD92837365655D616D01FED461070718406D6C6363616F7E85918F9FBAD3F4F9FFFFE7C499603F374E615C444C527195C5F6FFFFFFE698441B0F11245AA6E0E9ECE8DAD4BEA3652100000000114184B7C9D1DED1CDBB6C210000062D79C2DFF0E2DBC38A350F183259A1D6DED6D5B86C1C000000225384BABD802F0F1654B1D8EDE8D0BC783317408DB2B1ABAF80360717488099A284542700000B1A2D48789C9C704432315A9BC7C4A4774A27100000006864584E484D594B4A52656C8A93A1A09C8B7A6A60645E6B7B8D968D8D816670715545525164718293878E968669554D475A6D7E80927E6D69615B5F6C829CA69C8B7A6A60645E6B01FED561070708506E756D6E767E8B99A7AAACBFD8FAFEFFEBBA9569523E4A5F726759556B92B4C5DBE5E3F0ECA15225120C285FB9E9F1EBE4E5DAB492662A000000001D3475B7C6CAD3DFD0B3702F06000A1C6CB0E4EDDBD3C5752900001656A7D2EDDFD5A75A1200000C4578A3C6BB7730223D76BCDAEADBD0B5681E184C9EBDBEA7A4792C0D2A6388A09C804A20000012253A557E8A815D2F20376DA1CEC08A653816040000007B6B584C424C5647545A5D79959D9B9A7A7E5C756E61636482868D908E8971655552515C56677D848B848C838069564E475B748C8D9079675E5A5060618BA3C97A7E5C756E61636401FED6610707086078716D7280898F9FA8A1B3BFDAF9FFFBC69B7D5C4C4E5D74837E686278ABC3CBC5CDCCDAD29355331A223777C2E6E3E7EEDFCAB18974350900000A245085BBC6C6CDCDBFA25A210900002058A0C5E2DDDFBE621E00001C4E94C8E3EDD19A4606000032739DC7D8AB61312D51A0D0E3E4D3B5924F1214539EC2C1B89E6725083370A3B19F84642B050718395D77807A6341201A316DAACAB184552909000000007D6E4E4439303B3F425054859EA1A58F8D7A736C6C62626F7C7E88988E776F6250484B505D6F7C80828E8A7F6E44415C66697B928A8064585B55556777929E9F8D7A736C6C62626F01FED76107070870717580888A93A2B0BAA6B2B9CBEFFFE3B6956A554D525F708E81807F8BB5D6DAE6D7BFC6B28456342C2A4C82C2EAF0E8DCD7BDA296895414000015336488BABBB2D3BCAF773E1D0F0608295B92C3E1D8DEAF4F120000174A87B6D4E9D67D2A00001056A1CDDACC92471C3268B6DDEBE4D5AA8037132364B5C3B8AE9B5D180C3E8FAFAEA0936E320C0834617B8F8A6F4B1E090C2968B2C09F644017060000000066664F4741353539405162849696979F987E7B6A72666E7A878B8C91997057534C484650627380878489807A6D5854536168778F8F7E67555967656E7A8CA5A3987E7B6A72666E7A01FED86107070880706A74828F8E97A4A497A7B0CDEFF0DDB47F6D52566060747B84909393ADB4D4E8E6C19F8A6C4F4C4C5173A0CCE5E1E8E1D7AA7D8891622A0C07285B80A5BBC0BDBFAF814B311F1215061E5694BACDCDCF8F300000001F5A92C0DCE3B267220200286DB8D4DAB3703C1F3882C0E2DED8C69B642D22306BBCCBC6B3833A11145194B2BCAAA1803A122056869A9E8D653C0F00022361A1A3845C331000000000006A634C442C3329364C3C68AAA6A3A1948F7D7467676F636F7C8B8B8983735D4F494D556170818987828284785F4F4E575D6F8094887F6351505A6273809AA69F8F7D7467676F636F01FED96107070890787171858D9DA7A3ADA5ACB8D9EDEAD3A28064646D6868667695B9ACA2A6C0DDF1E0B1866D5D4D4F57699CB4CFD3EAE1D8C48E7B8A9D612717265983A4AAAAB2B6B8905B372E2B1A1515356BACC5BFB4A2591E0000063070ADCADDDBA1420800074780BFDACA914F1C173D92D5F6ECDCC5894B31233565ABD3CBB0762605296AA7B5B2B1A47A381D3978A3A89F815C280500002D5A84846A4E2E0D0000000000666050443C2B3942536D7889989AA79B8E8372615A5B5D718289898C836E54464E3949656785908E858279644B515B6764788B9090836B6063616A7A9494A19A8E8372615A5B5D7101FEDA61070708A0766F687A87959DA6AD9AA6B9CBD6D5C393786F696F6F696486C2E9DAB09496BAD6CEA46B4A4841446392C7D3D0D0D7E6DCBD795774845C3D2D4189B3C4BBB19FAAA87C3F2E4A4D391D2D4B7CA7C4B1865C320300000D4988BECDDEBB7D361109144688C1CEC47D310D154497CBE7DDDABE7D493A3E4B729EC1CC98481C0C2E7CAAB9C3BDA66C321F3F8EB5C0A98C4817000005225775745F3F1F0500000008006F6E574C4C4948536474828C98B0A193978170665C5A687A8A8787877F6F544E40444B61758E98957B7F75644B4D5B61677B898B8D7E6350618A788682909789978170665C5A687A01FEDB61070708B07C7B79838E9199A4A7979FADBAC5CDB6877470747B7A6F6D9BE4FFF4C689839FB8A6735639434F5172B3D5E9E1D3CCD5BB8B554C6E795E474F77AAE3D1BAB1AEA79E652D45696150504E67798EB6AA6E2D090000072D62B2D4E6D69B560B000C307695B6BCA25C290A093790CCE5F0E8B863433E565B689AC7C885350E164584A5ADB7AF975A292C5F9EB7BDB182440C0000072A4E606B4F331E100D040E0C016C656458594F5262777A7F8B999D999595836F645B5A6E7A867C888C7C6F554A3D67565E75838C88837F75685C59586171778A91848565616C67768A8C989A8B95836F645B5A6E7A01FEDC61070708C0777E80818B98AEA4A19CA19CA1ABB290837C848E96807C7AB1FDFFFFC18E78878E7C623B403A465480C2E4EEE7E6E0D3AD653D3E5F76626A8BAED1E7DABBBFBE96663525436F67657E8793938DA9A05914000000053C7BBDE4E1BB762E01011F5F9DABA89E773F1A001B417DBCD9DDE2B56139637C655383B8B3722F0D204C6482949E9779462A346FBAD0D5B782490B0000184457605C46301A0D0F0F0B110C697170666D60716D747C83869796918F847F807777736E797B85847B7B685C454653577072909194806D70605B5455686E8594938A77666268687C97999D897C847F807777736E7901FEDD61070708D0787A7883839EA0A3A5A0A794908C8987848294A392837F84BEFFFFFFCD9B857D6A594232373A4C64A2E4FDFBF2F7EEC87A40202735516F8DBACEE1E1E5C7C5BC7F3A060E3665667AA6B2B8AD97A8A5450000000010559EDAEED5A25313000A448CBBAF99845A24080013316C9ED5E9E2A65B588BA8694A649C975829213C5D695A6776735933264C93D2EEEDC6893F0B00071C425A524B3D2A10191A150D0D0B686B71736F615D7077828E99989289827F7F897D7972717C85867B787162504E4B54536B7D8995918F746D6A5B5C60647B8AA1A08573636570778093A29987767F7F897D7972717C01FEDE61070708E0756E6077799090959695977E75726A70708891A099868193C9FFFFFFD0A37B6F51483A30343D4A66C0F5FFFFFFFFF2A24C1B0A16284265A7DEE4E6EAE5D6CCA8601F00002650608EC0D6DAB7A4B8A246000000002181BED9DCB98136100C1C62B1D5BC9F7243190000163D719CCFD7C3845D76B6BC7B535466673A202C537C6F494851483E303C5FA4E1EEE9BD803A120714335F5E443C2B1A120D161620270B667676756D696A6A788488919392807868738580827D7F7C80787C756E5C49474B5E586F8389918B8D68716A6B5C5B6D78888C897D656067767B909B9991786268738580827D7F7C01FEDF61070708F0726C6D708183909A9FA58C7364625A6C6E7E8A8B8180859FDBFFFFFBCEAF8063442F2B2E3A3C5178D2FFFFFFFFFCE895490B000110286CB5E6F2EDEFDDD5C58D4A0B000016374D91D0E5E9DFCAC08F3B0000000B3889C4D6C297631208123984C1E2C9A7682F100A122F5488BFE2D3A0694B88DDD193523C483C1D274481AA8A482E2C2B1620457FC8E3E7D4AA662C0F1015384A4E42362C261D1C2323211D07837F73746B747F7F888C8A94928B7F877E75878C7C7C868085767273555D5456505A5A6978879399966D7577695D65737E809B965E68615D6F888B998E87745B7E75878C7C7C868001FEE06107070800747271737B8187889685867160615D6B637E8A857F8794ADD5FFFFFAD1B88E6A39292A383E4F5D80DAFFFFFFFFF4C57C38080400001971B8ECFAFFEDE4DACC833B0D000003304D93CCDCEFE4E4B87730000005234D8FC1C7AA6F2F0D111C50A7D0F1D1B56C2C0F08234479B3CFDCAD6E435EABDFD5AE6938261B1C375E9EBF9F5E321A0E11214185D2E4CDB5844526110716374943372C281F1E22302C2121147071737071787581889794948F8A776A6E7C727E6A7F79797D6664586255545C505A576F7A7D8D92896D7A7A6E6C676F8A8D94918574696C77869593956E5D406E7C727E6A7F797901FEE161070708107E78798582818E9792927C74686C6B7B757E8283828399C0DFFFFFFFE6B984542C2B2A2A3A495B8DD8FFFFF2FFEE9F542D0F090A1B3267B1E9FFFFE0EDEABF6A280100010833599EE5EAECEBDEAA6425000011396282929A87552A1019396FB6D5F1EBDE7C2E0E17376E9FCDE6E49F573B69B3E5EAC0713B0F05153A74AFBFAB623211030D1C5DACD7D7BBA26B341405001130393B38291D1C20232729222615728883827B7E8A8F9C9E92998F857D7471727A808880898B737362414A4156696167676C72788987887477716A6B687D8C9198918376736E7A81959B83665D4E71727A808880898B01FEE26107070820776D6F7B737C8185908481726B6B6E7272707D747D87A7C3EBFFFFFFFFC787563429273344455994CDFBFDF1F3C57C301C1013172A3F81B3D8FFFFE1E6DFB0531C01011626496399CBD8D5E8DD994A180A1535678B857F866D371B0C22427EC1E2F5EFD7743217223D83C0DADEC28240356EC9DDDCB47E290600115787C3CEA660230000082E7CBCE6E3C1975F2A090104152F382C2A1E19241A20242226241B797D7C8385838F889A9990818A756C646579777980898790806C5C685B525A63595E5261777C7D8182716F616B616C7E9099A89A8F8071727A818D9888865E51657977798089879001FEE3610707083066686A7574787E7B7068716B696E656976746C707A97B1D8EAFFFFFFFFCD844925182124334F769CD4EEE9DCE6BB652A121212232E508DC3E2FCF9F2E6CC8D4917020410336281A6D1C7CFE1D6954C18061E428BBCA37E6E46230B0B275590CDECF3E7CA6D2A17294B7AADCBCAB46E373473C0D7DBD2AC570D030E5BB6CCBD94511E0000033D8CD6E2E2CF9D562109020B1C293124201D11141C2323301E1B04A9B6C6C8C7C4CDD1C8BFB3AE95928A7D877D7E939BA2A4A09A7E7068605E606965727778767C775D702450626B717B87A1A39F978A7B748890959D98886C5E59877D7E939BA2A4A001FEE4610707084079786F7B82827C7C73706F6C6B76747A6B71777A7E9DB2DBF0FFFFFFFFCE845131202A30435887BBDFEBF6F2E39D4F1E0E0F18385282BDD4D1E8F5EADFAE6821060002234B82A4BDDDDCD6DFD5843D0B0B2C5FB6D2C3A27540170001174473BDD9E1DBB05D281429597C8BABA88B5325467FC8D9DBDABF6015102B7AAEC2C78D3C0700000C4FA6D6DCDECFA25A1300020A182E301F20140F131A272C3024210A83898C939DA4B7ABABA7918A8C867B746C6D6F798B9590A0887F6B665F505C616779787B62696F696852776E786E818B96A1A29489787D7E8A8F94997C6D66596C6D6F798B9590A001FEE56107070850676E69687A79787B7470676D6B7C827A7075736F87A1B6CEDFF0FFFFF8C781543A35393F50738ECAEFF1FFE9D58445221215234A6FA7E4E3CFCEE8D3CA7E380B00000C3A6F93BACBD1E5F5F4C26F2D070C3880C4DCD8BF86411E0000093073AACEE0CA8E3C131D4A7F8C879181533633599FCBDBE5E0C45F110F2675B0C5B886370E00001A539BD5D3D6C08D400F0007112D37352D231D18161D1B2D2419110A777C869DB3E1C4AFA6999383807D726161716D778A9C9E968A80666257595E625D6F7C84827C716664525D60706A7B8D989D908B7B7072768195938B736A575461716D778A9C9E9601FEE6610707086074756D6E6E7668697668797D7A82827875777A808C9AB6C7D4E1DCEBE3BA7B57424445485776A5D3F3FCFFF2B874331B1D172D5E9DD7E0EBBBBBCEBB935C260F0A0C183A80C4CFC5D2E3E6DFB05B1D09184697CDD9EAD59C4B140000023069A6C7D7B67F31122A71A59F897A5F34244476ADCCD9E1D8B8581C092872ADBEB28238030005144892BCC8C6B67A3E1409122132443A322922151C231E262A2828107A8694A09DACAFB1B4A09E8A827E7F74786C787F8994919D927A695D5D52565F687B86907978766159525C667278868E95979B856A6E676E8492948972615F5E786C787F8994919D01FEE76107070870766B6D706969736F75716C747F82827F7E7F80888C99A4C1CDD4CEC3BA99725F5B4B525B7499BFD5F8FDF8DFAE54280F13214273B9E5ECEDCBCBC8A6763D14060714285196CFC6B9C7DDDDCF9D471D081F65B4D7D8DEC7863D130001193D64A4C6CBAC6324233F90C4C099583A2E2E67A0D1E2DBD6CCA1400D06296FAED0B77F2C0501001343719AB3BAA178330C0918334A49433A25161D28262F2C201B20157787979C9A9BAAB7B2A390867D7B7A7374737B81829597979686706C5858655B667D86938B7D75645B4D606B6C7985939888847A706F6E7B828170814059637474737B818295979701FEE861070708807B83747673787A7976797A8F8D8F8A7F79788D9A98A3A4B5C3D0C0AA967867686D6A697F94C1DEE2F3F7EFC3783E1C181C2D528CCFF5E8F5D5BDB385533213110B172E67A9E1CACCD9E2D4B07230100F2A6EB1E1DCDDBE662B0605193F678FB5CAC58843161F5699CBCCA2673223387ABCDAE0DACCC17E330D0F3069A9C3BA7B2F0400081B3B527A959D8D5C200C1A2C4050554E412E2B2A25302B2A21251C1277788BA2A3A8B5ADB5A48E777D80766E7774888191918B97936F727E665E5E6D737C91918A83787167546162727C8599968E7971666D697486998A7D656365677774888191918B9701FEE961070708907D7C6F74766A726F757977958280858384858F9EA2A19EADBABBB08F7E7B707F7D8693A5C1E1FAE3E9E8C88E5E27121520345B91C5F8F7F7E3AF93613A1D10121F27457AB7E4D8D6E3DDB272471F0C0E3D75B8DDECD59D51200B142E588AA7C4D6C7773D0F20499BC9D3B978332A4F8FD2DDD7CEB9985617051A4075A5C7BA772C12111D2E223C637D7E6048241421304B4B534C3931272C2B292725271E21157091958C89A2ABABA8928983887A7B777B77878F96979F9B8A8B7864646C686E77858E968B897068674D5D626F8291928B7E7C6A656E70818C8783776E6366647B77878F96979F9B01FEEA61070708A0787172736D727875767474757A808087879297A5B1A39992A3A198807C7A7C9598AAB8C6F5FFFFF8E2C9985E321605041F3D628DC6EAFCFAD8AE6D43261A131821486FA1C7E3EAF9E7B5724123040720468BCDEBECC887431A0D17498CB2B6CCD1B96530122667A2D5DDC57D3B305C9DCDCFC5C2AB76431312326696A2B69754250A1B3B382A30426468503218172C40474B51463A312C2A262D2E272E27221C78828C8E8D9FA99B968E83767A80796F757883868995929D9E8A7C69656A6A7283928F9A907F726C644D6D6A73849291888078776970747F8F897F76625B6369757883868995929D01FEEB61070708B0717370716C70797877737C838083827F949CA6ACBAB3A28E8A81786C6F757F92A5C3E1FFFFFFFFFFE2AE692F190C09121F376991C3E5F0FCD79B5C35190814222F5B93D1E9E3E2E7DF96552B0C000D3059A5D3EBECBC632B1517316EB6CEB0B4BD994C1B113067A8D0D4BD74393B63B9DEDBCAC1925415071B4B7FA4B498663B151442645D412E4355514426151C3747465050473733302A272A2E37302C21106F87898485999B938A7871696C7D797780858B8D899286908C8A6E6C7073797E81919294827F6768605170757B7D8A8D85796E6B5D6F76848D867C796966626980858B8D8992869001FEEC61070708C07C826A756E75767A82828576798589949697AEACBEB99A8E7E7A6C65696F8396A2CFFBFFFFFFFFFFE198512603000B1F263D6893B7D5EEF4D39158331D101F23437CBCECF2DCEBE6BA6D28060006244C80BCDDF1DC9B4D2415213782C0DAC5B1A1763A1D1A4B99C0CED6AB64312E71BDD2D4C7BD773908082A638AA7987B461C172C698C7A584453523B190B1825404C5140423D2F332F322D2D342C2C2428197E7D84818A8B8A78716D6169727B7B83818587927F808084837979756B767D89948C998D80756F63635465708584858A7F756670647680868C8B8C826E6B636A818587927F80808401FEED61070708D066676068677070737A757074716E7B939596A5B0BCB6A18D7B6965686A6E6B8AA6DBFFFFFFFFFFFFCA7B3812110F161C2F3D6F8CB0CFE6F3CC86542B181C19345697D5FFF7E5E3CF96500F0001173D6E9FCAE0EBD7913B160D2E4E91CCD9D3BC8D4B281320589DD3D7C48B4A232D74BED5BDB1A46D361A1A4D949F8D6E49240C173B7AA5956A5359492F1D181A2D42544A373933332C2D2D38373032332A332381958F7A7F8077806C665E5E6D78777D948A8F888C817C7C766D71697078848688928D8580776F70685B6C7B7F898A83776E6C70697B838D9497747074686C67948A8F888C817C7C01FEEE61070708E06B746F7377777B7A7F797575787B878999A3AAB2C7B6A2876D62585C667C7E8EA4DCFFFFFFFFFFFBB06A3B2B1C141A2837486B91ABCEDFE3C07D452F26282B4272BAF2FFFFF2EABB74240100011B5E98B8CBDFF0C3823F1210275598D2E1D4B56C3610102667B1D1CAA6602316327BCAD5B99E885B2B18306AA7A1895D3D18101A438DB19E856C5844250E13223443464C3939302E2D373336303736323329177B807F7E776F6B645F5C5B5465707D8387888A848A7E746A6B68667A71777D8C91A19B6E6D716966636A7E7F898880787464676F777A7C8A918C877E76646C7587888A848A7E746A01FEEF61070718F06F64646F6868727675747E7D798088808D95A1ABB0AF9B85706364626C798293B5D1EFFFFFFFFFED9752463E2B2C30343D536C89ADCED5CBA16844362E1F2A4873BDF0FFFFFFE3A85D150001123172AAD0CACEDEAE642B12244372A1D1DBD5A962280611285EA8C3AB8A4D160F3D92E5DBAA8668412C284785BBB59E622C160A1F4E819F9D7C5D4E3D211A2128384752453337343030383A343B383D37292D1D87807E7B80646A5C6056556A676875868F8C98907E767164606467686D6F7B9298968B84776D6C636C6F7981888581786C6773777180807B858185806670747A8F8C98907E76716401FEF061070718007A74736C6E7880797F716B727E85808F8FA4A1A19C9994826C687068747C8FA5BFE0F6F9FFFFFFE08757555D5B4D434855555C6992BFD0AF82502E2B302B41558AD5FBFFFFFFDB84390500081D4B7BCBE6D5D4D89C4E2A1D375684B3CED3C28D3C140005235590AE956335112158B2F3EEB882553C26406090B8B88D57391E252B4F7B9090775B422F2926232931474B4F3A3634363A4245372F3B3B39392E1C768092817D725D534F4B51526A737D8A988F95928E89766B5D565565727688919598887B6A54596571737A85878C746F6869656E6F888D8F898483776B6A7781988F95928E89766B01FEF16107070810777673717777716E786F7A7D79818D90979095969B9288817A7271797E8196C2E6FFFFFFFFFFFCC07B567590796355687952505E86A5A67E4F3232322F2D4A649FDEFFFFEEE19F5B28020014295595C8EAE7D2C177422625426A9CC5DEDEB3712405000D21507B8E7B4F2C152B66B8FAFFD3814A44385C8EA7AD955E371A1327496B7C8A8D6F51371E26304241564A4341323A38333740403C3F333F3E3544267D89857E7467645A4E465754596780828D9F926D7E7C7668635B62637A807D8D9495827B6E6A6862707380867E76806C6365706D788F8A948F80786D676873858D9F926D7E7C766801FEF261070708206D6B6B736C6C79787C726B7280888690968981878B8880807F7A78888298AADEFFFFFFFFFFF3BF85554B79A68977889EA58C6A5769858A6138282A28303E517CB0E3F6FAE3B9753116060819346CA1C1DEEED1A35F28243D5A8594ADCAC499501301030F2B46707D6B482A212B68BCFAF9C8835B4D5B91BCC2C2845528100F2A577382767A5B3E282D32304345484C453B3736363D3F3F3E424243453A2F2D21828386776C5C574340494D5363788187918D907D83766E64615B5A687076838C9792807A736370767E7A8887827966735E5A5E63737F8686857468656A676981918D907D83766E6401FEF3610707083074736766696F757E78776F7D7782858E888C8880757C7A77818185888F9CB6E2FFFFFFFFFFD0906044507FA39388A4D3DECC976A57605840251B1C22365D78A1D5EDF8F5D290441F04000D203D729CB3D8F2BB7D442129518DA39491BDB9803B0E0000223D5C77795B3D21182F6FABDCE3B28672758DBCE3E7C9883B0E0E1B345D78866B5A43231A212A354943454752453B393C3A43424543433F48393744337E828180736157505153515264757F8B958D948B837366716F605A6667727C8A978E7C766A73756D7D81908980746962555C5D6F7C858582847C766B656C7D88958D948B8373667101FEF46107070840686B6C7067737569776E76797B8C888B7E7F8677796D707680807E8293A2BBE5FFFFFFFFF1A6634533407189828EC8F3FFF8C982614936231B1E2935477AADC4E1EBEDF3CB7E2B000000152F597E939FC6DCB16E35213B79B8BC877CB4A565270100062A4C7D8C8354302622315898C2BE9D86869EBBDBF4EECA7E351515203C65716E594533201C2831354844454D4B433B443A3F48464D4C403F42463A38296C7D7B6A5A52554C4F5454546567787F9092867F7E7570675A595F5D6B7B8389827C6F6A73747A7C7B818D8D7E78706356545C6D748182847972727C727A838F9092867F7E75706701FEF561070708506B71636B6769716C797279747D7B7A898D837F787573797B8586918D94A5B7DAEEFFFFFFDB834A30283F61788896D8FFFFFFF6BC6C3D23191A1A2C425995D4F4F3EFEDE9BB71250000000D26406284A0B1B495612B1F3F8CCDCE9F839B8E5720050C1A3C6C949586593C2D1F426292CEAC8F83A3C6C9E0ECEEC06D27101529424E605C47312920202A3436443F4449474341454347474B49483B3D3E3E403C3281827069544D324D53495161767B868C8981898375746D5F5B605663787687897A7372645D6976768C8A9287837C746A5F5B72707F8080837D6D70817B808A908981898375746D5F01FEF66107071860737569686D7072747E747079738781797B737979726B71797C80848E959EBCD2EAFAFFFFD079463D3638536C799EDDFFFFFFFFDA7E371A130C1F2D4968A7E3EFE1CEE4E2A65A1D080711213950748C9FAE9179592C244A93E1E8A692A4803F150005264E799BA5865E3D2722376491B9AB918CB6D1C5CEDED19F56210D12294150464030282B2C30343E394545464B4647363B45474D4A4B4D414143413C403376706C604D4D4F5459565B65798589888E8880756B6E626A60505B687179828C817264655A676E86957489879284766A59555C677C817C7D7A7B7582838E8A888E8880756B6E626A01FEF761070708707374727874777E7A7B766D75787F817D7F867B776B6F7177808A8F9C999EB2CEDDE5F3E1AF795237383E516D7EAAEFFFFFFFFFE087461F0F0E20335581C2F3FAD2D8D9D2984F16050C17264467819DB6AF814C36212F4F8EDAF6D3BCB6793217040D285281A7967D5039261E376891B29693A1CECCAAB9D9C888401D11262D3C413A353529272930354343484046474D4C51484E5054544B4245454A45403D2C656D5E5F464C4C554352596876898F858B857C6462665F59585A5F687881889A88785F5A60605D758B878A97877C6B645B6065737F7C7D6E666E6E7E7D8083868B857C6462665F5901FEF8610707088075605A64686B6C6F736F6C6C73767C7E79747673706B72727A889799A0A5B5C0BCBEB49F8870574B4C565D7492C2E7FFFFFFFFD38345232619253C5687CCFFFFE3DCDFB679431E101D263A6184ABC9C69962301D1D28468BDCFDE7DDB3692700001438748E9B9E8F5A3421152B578294939DB9E4DCACA8BEA76A2C0D0E1F314043312A282C1F2A2D373F414B484245454042505A4F53524D4B4A44454F443C2F787569563E444A4D57505D77839395888D8A8274615A6159587C5F7285818981756C59575C66717D888D919089756465595362787E847B5C5B60667C808C7E7F8D8A8274615A615901FEF96107071890706E65746E6F726F6E716D72776F7B787175727B727171787B81919EAFB0B5ADAAA9A08C7F655B5958606983B0CCEFFFFFFFFCCF7E4F34262730354C82CAFEFFFBEFE0B6632D16162735476D9ED0EACB82491E15122B4B88D5EEEBDDB358250A051C408394A6ADA16835150F26587A9390A2D2EEE0BDA9A383471A120B243134312E3B2B1D1C27363B4344494745494B4644484F585C5C534C47414A4A434533736D645C5856494A56636E6E7894968C88947C6568575F665C5E67747E7F8B8471635D60656B8482938D7F81816868604F5B6D8082847E7B6D6B6D767D8E817588947C6568575F6601FEFA61070718A079706B7A746F77777A7976797D7F7B7D717270727574787F817F8C9EA39D9EA295938F82796560555D6581A8D5EDF1FFFFFFE0A8735945372330446180B1EAFFFFECCC92513D2B2745636D83AED7DCB6723616181D3F5D80BDE4E9DEA24D220B17306292A5B5C5AF692E180C2A4C7A828C9FD1F3F2C6A8865F2F120709263A383B302D2C1D262F35403B3B423F44463A464144484F4C544E4E51504D4F46453666655C4E4E4249534E5A667781938B867F6F6C65635C505A6263747D827C817F77655A59576A7A8B9190897C746D5F6669646F828480756B665E5F748185896E7F6F6C65635C505A01FEFB61070708B0737368726A756C6E78727972746B717B7C7A797675717F767B7C8C939FA1A2A196978C726A5D6B6366757799CFECF3FFFFFFC490635A463831353D4F79A7D9F8F1CE9E7147372E4C7894979CB1CCD7AA5A2817252859799CB5DEE0D39F4F200D1F4887B6C2CAD8D67F3012051744789DA0B6CFDFDBB685613713020A132E333A3A373225262E27303E3642414243414A47414A48494C53484E514A56514B4D3E656656505E524B5A5A5D687E7286948D826A69635E5853616B727C858F8B857D6E584F5A5D617D7780848D8075635C6264687781848C755D6461686177797F72826A69635E58536101FEFC61070708C06A6A666B656A6769676B716B6D74777B7E7B7E6C6E6F7D717A82888E9D9C8B8D8886766A645E65656C7486A1CAFFFFFFFFE0A675614F494F4B48526E80A7D6DEC4A06F523A3E5275A4BEC6AA9DB4B684522D1A27356288AAB4CEDAB87B4025222A5C98C3CBC1CAC7814018111C4D8BB7C6D4DCD6C4995F3015090E0F24313F413A312A2D282C3433364A41423B40484A4A42494D4F56504D484C4A4F4C494A376B625C5E524C45486262697B7C868983746261535C615F646C757A81899779765F5A5256696F7D7E95928F85665C5E61605C78807C866E556966676B80948476746261535C615F6401FEFD61070708D07375777D747977818275716C6C7777747B78716F717480707C8883839294908B7D7A716564696A716D7C91B2DAF9FFFFF6C5956754535A64595B6E838AA4C7DCB87E4F3B2B395884C3DDE9D3ACA5A86535211E334267A1BAC3C8C797693F2424376DA2D2CBC4C5B8873E150E2461A0D1D7D9CFB8997645180B0B122736384B424936252F293038383B4442444B4447484F4B4C5054565A594E4F4D4F494F40326E5B575B4C464B50636C7978828585796862504B4B4A4A5972777A8B8A7E76786454595D6D797D88918C8A7365575965636C7B7E8E8F746565606E80898883726862504B4B4A4A5901FEFE61070718E0726F62706E748175726668717178727B7273766F7C75787F7F887D81878B888D7B7577756D67626B7C8894B1CBE5FDF4D5A9835B5268606F6E717C848DA4C1CCAE734B3531476097D3F1F8D5B5A68A52272D26364E74A6C2C7D3B2874E261E3350779FB0C3C3C6A068321D1B3A689EBAC5C0C3A57A58371A17253740383E404B3A3A3A2A373339424950483D3A404C474B4E4F56585957555B564C524D474342917C6A5A57525A57646C7683878782766D604C48455058697A7B848C817C7566595D605E5E72848E90908F7D756758676B71818A8D82696360647282878F89836D604C484550586901FEFF61070718F06B66676867656466635F766D6D70767B6D7B756F737472807A7D83838B8B848172726B666D6863767B839EAEB8D6E1D2B78C725B57677781848F949DA6BAB3AD8F693F333F485D88BDE0F2E6D0A37D4A2F2D2C41526E9BC1D4E3C27E4729263F648EA39FA8B0A580593B282A3C6D98C1BEB697805D41271B27313E4F484B4D46403D343A3C3749544D554F514F475D5F5D554F53585F5C55574849534C4F483C746463625953545C646D7278898B7B776A4D4845505564647581868F8C816A5D5959575B6C7F7F808A85877A61655C5B6677878E8A81726E6B6F789290857D6C6A4D48455055646401FE00620707180073776E766F6D7075785D65746B70697A736F726B7B71747D7C7F8087918B7B7A787775686F68727E798191A3BAC2C2B39D836764576C829B989BA8AAAAABAF9C816443474659718ABEDAECF2E0A66E432E2934585D7294B4D7E4B27A442F2B3A6E96968B8694856844322B26477994A598897C734D312C2C3D485C615D5D58534544403D47514E525B59524E4C4E53594F5C5C5C5E5B5551625654575149483C787A7E7972646A6A7F76738083847C7473584F4C4A5A627A85939590887C6D765F5D5C676E79818E887D756864565E62727D858F8E816E707279818D8C8E827A73584F4C4A5A627A01FE0162070718107B716266656F736E746F6C676774716D7476756B696D767775887E7B7E847779747874746E7176787B919AA2AFA8B29D91726763617B90A0B9B7BDAF9FA293806C55454E59697A9CB1D0E8F1D09A5E3F27333C5C707D85A0C4D6A671472E28407B9C9385797C694B413B413B526D8E9C887C6951493A333A455A635F575A62514B49414A5143525D5D6362584F4B4F566160686163646564665D5F5B474D4539827F796D6E656B6B71818583928A7E6F5E514D4C52547084879992878574646553535768718285847F7E7B776F605C65757F8A918F8B837374838A8D908C7E7D5E514D4C5254708401FE026207071820756F76736D6F7074736266726F71777A77707375787A6E7473707E82797D7878756F6C6C7576797E878D99A4A3A19F8C7867655F617C8FA4B1B8C8BCB392826B58524C556A8B96B3C1C8E0E1B3855640333E557F80858EA1C2B288563D32385983A8998370644934323E4149617B92927C655349423B414C5366616564645C59574F414951525B636262616565525F5C5856595E686E72675E5B64604B45493D7572756E6D72777A7F7577888A7D746654424851576F81858F8F8D8E82706E5F5B585D6D6B85838380797A736D65667276878A918D8278727B808690968F807C54424851576F818501FE0362070718307872656665697270766D616E7171716E75726065717374787478797181716A707573767073737C8083819398A3958A7C7B726267738098ABB9CCBDBAAE86715B545C525D7C9AB6C8DBD5DBD7A8764E3728425080949F9FB4ADAA764A3A2834557B929D97705C4A39333B3D525F7E928C775D4944353B4E4E535F63616162594F4D5850545C5C595C625D5A585A5F66635D66606161685D5E5F6268645A52513C71747F8888757B80898583838A84756D5841474853717892999E9088796D6566615B5B6F8285857F706D7675746A637183878E8F918F7F74767781988F989380584147485371789201FE0462070718406E64656B645E6B6A776A6E766577686E7A7370717071726E7273777B797F77796E7274727B7678797B79838D89867F7C7470676E76849AB0B9BBBDAE97866B5E4E57626C92C0CBE5E5E1D2C89861412E3152648192A1A5BCB5925D3B2E3246597E958D9175553E383A3F4B4B5B7275856549443B43424F4B5B63616C615E5E5A50544D58645F66686670666A575E61686C6565636471605C605E5D5F5E5253486D70787F8283828C8D937F877E775F585147494D58747F8A9598999082746D6865676477778A87766D6E767B7A726570807A888E86807A77777E859494908B7E5147494D58747F8A01FE056207071850725F6769645D6F716E696D656870766F7476746F696C74796C727B767D7571766D6F6D6B727F7875837A8A8E8C807F776C696E7D7B85909BA7ADB9AA90796E5F5A606D829AC8DCE7E3DDCBA4714D4637394D658092A4ADB7A5815A3C34384762758987806E5046383C4F585569707D7D614B433A51515E68656061645D685D5756545A5B58606062646763655A5C6167605C6B6B6E706B6269606060595D5049748173818985888F8A7E7F837F735C5B60524E595F76859E91938C837A6A666354636D7B8C8E85796A756C6D6A6B6A7E868E978F8E8A7B7E72808A9397988B8760524E595F76859E01FE0662070718607B70667967706E707465706D68687174716F7470727671716F707D78797A746F696F6E697670717770728084847D716F7073757A8086869A9BA9A9A28A7A6A5D5C696783A4C6E0E1EEDEBF9569504C464E5C6A7889A1B4B1AB906442343C55606D767B7161534B4348505A5D6A646F6B5F5D514A4E464C58635D6266635F515C53585F60646869696762615E52646F706B6E6C6E62616B6765605D5C62575B4E7067717979868C8F91817F7E7A66615C5F574C57637C8F98938F8A7D716A5E6055676F7B848283796A6E706E6F6A6E747B878F928C83787A7C858F9A9B918E8D5F574C57637C8F9801FE0762070718706A666C76676E6F6C6B66676F6D68666D74797064676E6D717374776B746B746E6B656E6E766E797A81727A84807D7E7F73747C7E8184839091949391877362555B6976879CC9E7E3DEC1A68A61584E5150646C828B95ADAFA7885942363D506B7A7A71695A534B4548585D5E6169736A634B49555B5A59625D5F6364616565615E585F6064636E6C6B6B635F5E656E6C6F66656F7270656667655E6962565148737774757E85888780817B76797568625654575C6A78898D8F8F847B6554575B586373837F848175666F636A6B6D6C7C888C9991938C787E847C8B918F918F905654575C6A78898D01FE0862070718807676716D736F7D7576706A7068756F6E6F7876696E696A696C7273767B6F74796D6C706871767A7572717F8081797376726B70728183848F8F948F81736C6A696871768696B1C4D4CBBE97715E575C63656D7B7E8493999B9B79604E50585962646A6F7675684F5355546E685F72686D5957514E555C5B5C6363696C676567625A605D63685C65766E6C656D606A67686E7A716B7070736A64665E65615E5243706F6B767C87879487887D7A776B635A57545E6267727F7F8C7B74756C554F586673797C878C8977777366686B6D6E757F83838E8383777B7B7A828C92928F9057545E6267727F7F01FE0962070718907B6C5F76737A737A7D726D716A6B777A71796B6B6A6F6D736A6B757674777A7471786C696B737379736D727E747775786F72747A7B7F81837C838A7C716E726A676D73848D9C9F9FBBA48C766D68706D7E807C8A87828B90897163575D615C676C6A6D76635E5657555E6A6D6C70746B66626169625F646262636C69656B675D5E5E696B5A616C7A6D6D6E66606A6E6E6A6E7370767D71746E645B66585F554B7A7A797D807A8589858775767B6F6D62686065656E7078828178756F6662615C6C727D7C80847F75726D776D746E7276737E87827C7F79718182858C8B899392686065656E70788201FE0A62070718A0747163695B656463655E646865696C7074676D6B6B646F686C74717275716C73746D6F6C75646C6C6A74727879727174717A77777F797B7F88817F796F6D706D727573758284868690967E776C69747B797E808375727B82787B6569646A5F65687076746D6A5E696B6C746C7170767A6C625E585F6365676F6A6C645F6267636967656B6D6A6A7A7C7F6B69686D6671767466706D6C7B6C6B6969605A5D5941746F6F6D7373797D8278726B72756E6D696664666A7E7B807A706B6F6A6A6B6D6A747981797674717678776B6C6B6E72767675777E7871737D81819490868885696664666A7E7B8001FE0B62070718B07A736A6B68696B6A756972696E6E676E6A676A73677071787A72757C7A7A666A6A656D716F71696C7070707C7270716F746D797F76757B7F7F7580786F69736C7078757F7C857E859381796E7271747772757F7C787A70797B7969676D6A666E6A64677266636A6A75756F6D706E76786F626565636269646C6C686F6C6F76736465646C716B6F75717770686E6E736B6D6B6B766F746C6B5F66655E6255564671756F73737877767B736A7C8082806A776C6D747D7474786F74666F717165756D6B7A797B787C7A766A787D77737375767575747B817A7E7F7C828683818A84776C6D747D74747801FE0C62070718C0777477726F6C716E7E6E776D6C7266726A6A6A6B726C616A6C7B6E73757574717270766C756F706E6B6A6D76757C736B7073756E6C7875747577818071696D7A76787375767A6F84897776747B78727C7D7D76786F6C716F79737166666F73706B72727269666567716F70727180757A71696972696A6965696D6D69746F696B71686F6F6E6264767771706C7068716F727176797B7E756D6866616A645855427270677B746C7476737A7C76797D7477727374737171737C73696770696667706F747170757074707B737D79767273717372767E7C6C6A727F8083807F847F8C727374737171737C01FE0D62070718D0777771777376726B7564676F63706E7973706D7276666B7077716D737379737971686A6B766E73676867707E76707067736B79756F77726D73817F7E7378706F6472737B77746874857D757179766A75727B767A686E70727F7A796A7B6C66626E6B71726E766C7779757E68666B7680716966686A70686C6F72726D72736B6C686A6C6F6E727070797C75736B676F746E636A726C6E756E6C5C6868605F604E73777A7873717277767A7A78817A7B7B7F797B7C78797A7A786E6A686D6A6A726C717B7D7C7C6D716D6C756C72757372786F77787779727675857B7B828581827F797B7C78797A7A01FE0E62070718E07679687069707976766A72706D726F777373726B6C6F6D706A6B787472706C67706D6B6C7970716C67636E78706E74777071726F777972777B787B756874716F73716E776F71737883777C707772787976757B7E746C6A78787C73656B6B6861646E74747172726E7679796D68777E77726769676F676E65666F716C6D6C736A646671696E6871747C70786D6E737E7B6F7A6C787B6F7276646A68645A5B5B4F6F686D75796E747073747176797976786F7C6F716B716E6E81766D7674747170747D7072797D7A6E7271746F75676F6F6A717B7E7A6E7276727B8087827F7F7F6F7C6F716B716E6E01FE0F62070718F0746465696467666F736966646375706B6870696D6F6E69677070626A76726B7D6E6B6E6A746768676C67727E7F796A76757073737275777B6A6E78756D6B736C686B6E71767768727974706F6E6F737C6E79757D746F6C71797977716D70716C67676A6F7566717B767C7371757F7D887D6A6971706D6C69766E67666B6C7870696C746E726E7272787974776B6C6D6F79717C66766C706E636468645E585349777578756C747A717C716A72797F7A7B7A7A767A777B7D7A7972707375726D6C6F736E74786E787073737D726E6D727673716E7A797A777A7A7A7C837E8289817A7A767A777B7D7A01FE1062070718007C7C6E69646E6E696F6B6B6A686F6C7571716B6470736D656869757775676C766E6D736C746F706D6266727A777174767977776C6A666D73737B73766F6C66676C766E707074716C716F6C6B6A707577777A79806A6A70717C7D71747973706F6B6E6E72686B6F76767879716D727D80726E6C736D716F6F6E7579706D7676756E6870686A6B6D7475717374756E6F6E746D79757774736F6E67696A6B615E4974797370747168667273707080827D7A787578736F6F6E7577746C6E726E777778767876767A7A797A7D7B706B6E716C746B757A757270767E7F8180827D7C87787578736F6F6E7501FE11620707181077706F6E71707578746F69676768686F706F6F706D72716D7474726C75726D716F6F686A6E6F726F6764697C6D71716A706D6F6E7376727C70747573716E67646D6B6B6D6B74677680787070717B7C707471776F6A72727682757873746F706B6E69726B6C766F6B6F707070726E7A80766D6A6E75726A6E6F6B767376706C686767676A6D6D71787E7C72766E737274786E6D79787477716B6E646D605E5B4770706F7773716E6B7371756E707675817A74756E6F74726A6D777573756E687C7A7E74736D737E70786C7673776E767471746A756D7B737B7C787C878281857F7A74756E6F74726A01FE1262070718207576726F6B73746B736E6E6667726B7B6E706E657077726B666E72736C6F6B69726F6E72706F6E686C70737F746E6E6E726B736F6A6E7271747B7A7B6C726C6C6D6F6B6E73756B67797671786A706E6A6C75787C727271727C7E686F727A7578696E7076706F77737577736F64747F85736B6E786E6968676F777371737F786F6E72676E716F696D6E74757373737773756F747572716F74717266685D58544D797D7D7E8279797A77727A767B7B7678747374757B7B77777579787673677178727D75766E72757777757C7976746E72706C6F6E6F726E777F757A7F7F7C7D83747374757B7B777701FE1362070718306D6C6267646966737466686762666D746F6C64626C716E686E6D6F7074766C736F6E6B6B747276656A5D6F79786C6D7B727069706D756F76726E73786E746C6E7774696B676F646F7778706E6E706F756C707476757073717F8271756F70686A5E6670767277757E7B6B72687173797E7175736B696C6E706A6E70727473747068686C75747B7275757A736E706B6A77707571776F7574727166656F655A5D4E747976787A7971746F73746F7D7983787E707775777B6D7679756C6A71756E777874736E74777F7473697278746E7971686A7075797573767974767D818086807E707775777B6D7601FE1462070718407768656F67656C6E6B62666B706B6D67736A726C6C6D6F6E746D7178757977756B676D61686C6E6E6564757C73726E6C766C6A6E6B6473736C73847F7E73666A68746A6D696D7373747770746F707380717474716C6F7B7C7E80737571676E72737365676D726874777E756F7A7B7B837175686B6C706C636A6A6A72727B6F71726F7371677276746F796F797C7F7B71766E73646D72746D5E6A686B606A624D7670767571746D6E6F6D6F6F6E7B77706E677A6E777472707A76696A6E7268726F6E706F6F7278727271777673727072676D727D786E7475796F828A817E82896E677A6E7774727001FE15620707185074796D7475766D7F736E69646670746F6F636C646669717D757669706D7076706B6A786D6C6F716961716A767578716D6970766B76746F726C787C7A7270716D6C635F6B6C6F6E7D7270726E716D77706F796D7A807977737377736879716A5D5E6F7075676773786E7B7A6C6F737B807A766E74757376776F6F706E727B756F6F716F706E6A6F7C6F7876737069787F797373766D6C72716E696166625A5B48786B72757879797B787C6D747C7975838178777A80776F7574717270736E6A666C72776E6D6E7C74796C7872777072736D697575736F7A7C7B7A7E857F827F858178777A80776F7501FE1662070718607A70776C6C6A6D71746E74706D6C6E776E6E6C756A726F676D6A72747D6E71756B6B66686A69716D6E6A71726F6F637270746A66727573797573726E746C7B676B6C696869756A75706B7177726D7F867B7573726B6C6D72747D76766A6F7972716864726A6B72767A7A70706C777E81776E726D7073726F696F706E696F6D73746D74757472777B817B6B6A65657375757972797974706B65676664615C59556C69677078756C67666C6D6D76707D767977766B74786D7A7E7D77706E636567746D6D6C6D7873777E7276727B7271736F6D727771757172797E7C7F7E807F807977766B74786D7A01FE1762070718707B786A646A767D7570676E6A72767D676B74736C686C66646A6E7872796E706C6B716D6D786C6C6C68686E7A74736F77696A6D60656D6A71787369717775746E6E7565706E776F6E716B707C757375736C7A767B6D6A6B716F75717277716C6D656E737B716C7A797A7E7A6D6E71797A7A72766F71686B69686D7174747E746F6C726F6877726F6F777973706C6E73777175777E7A78786C706563645E565A4B717174707B717977827D747B797A7C757776756C6C786B7273777374716E707964767274786A6F70796D7A716D7370756E73788378747779807E7B7D797C86877776756C6C786B7201FE186207071880736D686F67706D757D6F6E68696B6E707168756F6B647368716F6472726D6F6B72716C677768666B666E757E756A6E6C70726F6B667474797673767770726E71687267657374716F767E71716F6D70746A756D72707971787C76716C6C6D6B6961696A76716E72717B7B7E74667276826D727672766B71727879746C6C707C716E757C766E767576747473726C6A6E736E6E717674716C746D736C69635C54476B6966676C6A6F6C6B6D70707E7E7C78706D7071757478747471736E726A6C696F7774716D6E6C746D6D777578717570717671737174797E7C7474837A80897E706D70717574787401FE19620707189077786B7068746E756E686967626F6C71726973746E6A6373756A6B6D7A79736C6A6F6E6568656F6A676F7373707B7573716B6C676D6D646F6F6E777B76666F666B67666D6D707075767373726C757B76757476767271767E807F746A71706668666D7B726B6A6D6C6B72727070737D897370757478726F5F74746D746F707270716C6E6C6F73706F7775726C697175766F746E7370787972666E6C61695D5C4D787C7C7B7D7577777E7B808080757E807B7E807A79777874716E6C757572706B787871737B7676817672767874686D70766F7A7B777B7A78817B76787E7984847B7E807A7977787401FE1A62070718A07574626A63716A706C66717A6F716E73736F6F695F6C6D706D6F6466716F746E6A67706C756A6B6267677078727273736C72756E756768757A7675736F676C706B676476727772707A7868696A747C787382706E6D7076787D827A726975696D6C706D73776D7777756C69676E737F7E78746E787B757569766F6C737C70706663676C6C7373776E716F717D77757B70746D74787D6D6C6E6A676C655D52584E727374757270766F70776D7476737B75767E7F79827D78747978727D72776D716D726B6865696E7475707A7D7B7475746D676E7477747A747A767C8884818285767E7F79827D787401FE1B62070718B0746263676570666D716B6665696667716B6A6E726E6E6E696C6B716D75706E6A70746A6E7076726A6A666870796D6D6F70716A696A756F787873716B6967686C6D746F7164796E75736E726A72717B7370736B76726C6A7C8473736C796B707063726D7370686D6E707E7769727B7C81796D726C71737176776B6C747B7A6E7375706F6C6D716F77737B7072736F767B706F76787476737071656961645B594B6974717C6D6C7575736A717B8276796F7D787A767A7D777A787177736D647077777A70717578727874737774706B727676727175686D76797B7A7E7A837E79837D787A767A7D777A01FE1C62070718C0726D6966677170707166747072686F6E6A706A696562696C6D6E6F75746E7070656C655E7069746E6A706E7F73736F74716E6F69676E7372756D71736B6A6B736D69706F716F6674786870756F717571757F7871676F6C797A7D757974746C75696E6670706E69727A7C716D68787878716F766E757677776D6D74716F6C70797375686A69736F767D79786D65696E717D777C7C77757874776D6868606267487779787C76726B7475746D767C7F877B86756E787277707A767C7A7680736F7264746F6E6871767770697C837C6B706F7674736B6C75767B8279767F7B797F7C86756E787277707A01FE1D62070718D080766D7A74737878736674786871797A75767774726F6A6E7175717A7B6E72787364766D6C646A67676D6879726E676B706A6F6A656A6F746E757E7673746D616876677272726070737D7572796F76747475737A6F74767B84826D6D6F71746A677064716A6A727470747470686D78797778747077787A7172736A77717768746D746E6E6D6D73727574716B6C6D7A807972727471787672676C6B6F675F5D477A7F7E7D7D7E797A737471767D7F7E797D717A7A72766D797D81726C716F75776F747176697C75767976736F72636D7277757775777B71767B7B817A817A7B827D717A7A72766D7901FE1E62070718E0827665706C7274767E746465636F686A6D716D7178676B6370767B6D6F7568786D676F6D6C6D6E6767666C6D716D6B6E6D706B6F7371707A7A777E7572726A675F6A61696A7364717C7670747471797A7371787E73766C718679766F6E746C64666F68746D69727B797A786F69777378736A7072777970696E706A6E6F75736D7075687270727377727979786A6C717B7074787D7973716A6B676866615C5C4D73787C7B78737176786E736E797F7C77807679777C7475837D7377766D656F71707777746F74736F817B7A6F6E716B736D6B6C72756C696F7A7B7B847E808085807679777C74758301FE1F62070718F07876617073756C6E716A6B6866696F737669706B6D656870786B74767A6E736D6B6A6A6D6C62646D68696F7871766A6E73716C6A6C737276756F767D766F6F6F6C6A666C686B6A6D77767E6A736F6D6B73777172656E717681797A766C6F696B63706D7564776F727F7F7677707072746366666B727071737270797A72717775626D6C7376766D727A7E787070697480777C7576797776786D67615E6359594E7E82857B7C7A7D757C807A7F7E7A7E7C7C737B7D787C6F6F756F77747572777F73747678707270717B767770736A707073737B7770736E777E7A7A7F84818B8C7C737B7D787C6F6F01FE20620707180078736F6B6F6C707B77766C7272767A75757576706866696F6E6A7270746B74746767666A6D6A6D6869687970756A6E6A6B696B6970736C6D72717C7275717163706B6E71676F6C7C717C776D78757268706C6E726E71767378767075686B666B646A727571707077777878736C6C747E77706E707A6C727871776E7469796C6D736B6D73746D7B7E7B7B7372747073777675757B7E78796B686C66605B575A4C7D7B82797B75817E76796E747E7D837D7B7A848278786F76727677777378707C757874797B75746E6F697A6D6E6E696F726E7A7C717171737A748283797C81807B7A848278786F7601FE216207071810766B6469686D6C6C7263696161626869726E696668666C746F62687577796A6F706A7272796E726166616B76756E6A6D63676D6A6B757575787077706E6C71736E6B6B696E6D707180777175757A85717179717A6A6A6D717C79786C766A65696C676E706C6C7571727A77766E74707E817373697776716E73736E74717D6C6970717073746C73746A707971706D73747A7D767F797373716C6468645A58604B70707C6F756B69696E716C727A807B747972737371737076747577776C667074756F716A6B7376777B707D776F6C7168686870747875767B7B838183787A7D84797273737173707601FE226207071820776F64786766736E7A74786D716E7777756E686F6C6B696D6A716D70797577756E67666B6D6D6D5E68686B6F7B69676A72726E71696E6C776F6B7F7A70706F656F7165767778706A7172726A666C7B747576767B6B656D767B767573716E6E6D6A69636C6D707776757A7B766C7C758177736C697277746B70756C7370737372707372706E707D787A8270726D6E7A7A7B6D6D687371746F6C736268625B574E72787C7C73746F6F706F666E7779807C79706F7A75787771756D7077777C74707472767975736F70706D797B7D7176766B686B79717A787382837F8280857E7E79706F7A7578777101FE236207071830726F67706B6F75746A6D716B68736D6F726C766D695C666B676D74716B6F71736B6D6974766E6E726F6B7076796D6A7174696B6763676C7E7A707A7475706D6F646D636863706E7077747A766C6F71726E7572766E647271827B78707275686967676B736B7678777579766C7378747971746F75696F74726D656C73707A7D72756F6E7D70707472767F7972697072716D737476767778736E6A6E66645A524A69707077777C786F7A77706D767B797D77797B7279706D7078706E75797370747A736C6F70757180796B76797976747A787076786F6E6975797885817C7E797F77797B7279706D7001FE246207071840686761676A6D6C6C6D6A62686270686E756B6E71646C757C7170626B71766A6B65606668706B706A66687274726772747A6F716F6B6F6E706A6E6C717A6E626D69726A6473766F737B736D706772776F757670796F7173797D80777479766A6E646E6D77726A6E696C757B6E677A758171706C73706D6E6C7978777271737774676A6E6A736F6B737B8074796F756D74726D697479766F76756B646B6E615D507873767C72736E75737470787A79757D787978777577737B736C6872796C7070777A70777C767672786C7172777379746B6C6E7F737B6C70827F7E837C7D8088787978777577737B01FE2562070718506B75696F666370706E6D6C696E6B707172746B697876786E6D6668747E746B6C67716F706E6D6B636463766D6D6E616E6F6F706D6E70697372697176776B716A7473666D677377767E7A76786C63766E6E72747D787573767778737A7568706C696D6B696B6E7275777A6E6E7578797E7C7274787C746E71717267747272726D7172716D726C767A767B7D796B6E787A76777770727871696366626B61665F4F6F73787B6C707078776D66768079777775717575766E6C7E73717278716E696F70736C6E726D75767D6E747C766C75716D6C7A757C7B70727781797B7B7D7E8475717575766E6C7E01FE2662070718607C78767774747B767771706A70736D757370716E6A676B6E74726F73686D68706972706970616767646973727571656B746E67676E7A6A7278796F71706F726E6F737370777370717D7372717173786E6E767A736D6C756C6F7572717C726E706174706E696B6971787570737576758484717372796A6D67677277727573696B74687871756B7C7F7B7B75736A727A707175757A75746E70656660655E5E5E4D7574707478777E787170706F6F7B807B79767777797971727975747971747472716B6F707072787279707F76726E746F707970766A70707E787A7A837E807781797677777979717201FE2762070718707176636A61747075726762626671767179786973656D726E6D6C69646F6C6B777175706E706C5D6A6A6A707C74736A6A6E6A6370666E68726E6F796A6668736C74706A6B706D707173786F72726C74636B7476766F7174787D7E73766D7566706F6F6A6D6D6A777476766E766D76808174666F6C706D706C6B6D776F717870726D71726D7B7173737E74727476737671787174797A7F76696D69646863635A4D6E737D837A7D767276766A75817F7E7F857F7D7683787179726A73757B7573796F6D6769746E787177716E7576696D726D757A7C767976747B787E867E837C83857F7D768378717901FE286207071880766B6A726E6B68707A6E67696B70706F6A686B65646D726D6D69747A7973656A6D66646B6B67616C6C6C7177786D65736E6F716C6B717074727C766E6C6E6F6F766D696168716874756D737574756F636D7676756C7274727E7A6E697772696B6B6C666F6F6A7377747D77706B71757C7176756E72766E707671757374716E7376747270706B6C798585807A6A6E786E767A746F71776F706E706C665E5B5E506B6B676967676E6D7369686874747578787A766F72747B7F7D787774756E757072717270706B646672757678767275737674736F737A79797478827C787E8185787A766F72747B7F01FE2962070718907674606C706D727470676C71736D666E6E707378706B6E716D6D70757678746D6D7267656B6968676465706F76707A706B6C6A6F697A737875786B6F736D64686D7A706E6C6F65627175717C7675787373676C786F76757874766F6E6C6D68716F6B69766B6D6A73777B7F79757D7C6F756C716A71716D6A726D6C6A70787F75716D706E726A716F7679737870717774766E737779787C757B6E6B636559594975747878726973767C75707880777E74737A7D7E7D767E727177766A746A6371726D6C70736E71717C6F786D6E6A6D6F6E72737A76747C77797D808684827981737A7D7E7D767E7201FE2A62070718A07874676E6C7073726E66676962716E75706D707266686C7771727273736F70746A6971716F6C66676F6272716F6E746F756D73666A7772766A7879796D6C6B5D686F6A6E656F70737C77746D717275796D717675767177767A79777976706B7268776B72786E72767B7D7B736B6E737C7674776F716B7269676E6A6E717578746A6D6B6D797077797582786E696B686F7770737B78796D6B6F76756C5C57574C7475797D7B79746C746F7478797F7E7D79727A727B7C757370707472716E74767A7877706D6E707376727D76746E73706B6C6E76777C7A7776797C7C817D838979727A727B7C757301FE2B62070718B06B666A62686E6D686D686773666B6673706D717475626367656A6D73786C75776E666D666A6F6F696565797A766B707178746F685F68676E6C6E777B71716869756C6F6E6C6A6073786E6F74767577777976747274766D777376766E726C6C7468666974697276757176757C707C7F79776F746B6D7071736C6B6C71747578696B6D746C7271716C72797D776D706E6F786D77777F7A7B77716B66685F5F5E466E6D7775776B777572656E757F7A797476797175756E6A7C7D77747B756E707673786E6870746F7B756C797C7A7571707373767B7676716D787B7B7C7C7F7E7D76797175756E6A7C01FE2C62070718C0776F6D6B63727366676365696B6E76788278736E706B696A76756A717677736A676668686A68696E6F72796E7077706C75796C6D647776736C767D76726F6F6B6669696E677A6E6C75726B6C766E757772726979686D6F7984747071767167636761666E6F75737B7B7F7E686D72767E706465767A716B6B6C6E6D717B7974726E6C717478787777827F766C776B727B807C76797A7B776B65636661655F564A827C867C818183827671737E767C81787F7C7D7380797876787270757572727D7272727B717177707A7476787B6E707071696F7B767B7678777678807C7D7B837F7C7D738079787601FE2D62070718D0696769685F6A657468656F7361706A6674646C676567666D6E73737B726F6F716B6D67676C6F6C6364686A7170717970716A6C6B656672766E7575787F7C73676C6C6A736D74737E71747675716C7B7B7572726D6D6F6E767D7170776F6A6E6F686B6B6F71736E7372727A706971767C78737770706D726B73757472766D6C6C6D756F707175776D707C7579637474757273717A7472756F71696F62605C5A446F74827D8078797B7B7674777C757C7F7D776D75797675787377716F72716E6F6D7375777978746F736F74727178736D706D7077767976807E7E7C797C7F84827D776D757976757801FE2E62070718E0746B6B605F67676F78666B6E6B6E6C7470776F726C6B6D6F71686A696D6E6C746E716B6F6A696E6D6D626D6F727267776F726F6E707171777676766C6B6C68626C706469606D71747A766F757871717A6B7271726D6E74727B82737873766C696E6B6B706E716A6D797674766F7775807C727672757A747077736F74767A72716871776F686C6F76767074766F78767575737975757470726D72696260585C4A786E73756E7272726B7571747E7A7D7579777F7D7972797A7C777B7479726A756E6F72717571767577686C71786F726F7075747776726F746B78797E8481817D79777F7D7972797A01FE2F62070718F0736C68726F707074716568696B71646E6F6C666D7166727173686C706F756C757568666C6E6C6A6867636D706A767070726F6A6D6F6774726D7678726F72616F68706A6E777B6B6E6A6E71706F727A717379787B6B717479757A7770726D646A726D7077737273736D777A756F717A7F71736C716E6C72746D7172746C74716F6D756C7074736C74797B74726B6F78726F6D7176747978746B6C6A6B685C6651757786867C7976827D7976798080868884817B7A787E79797C787A7978746E6C756C74726F7168696D6E79857A74746E6F6F6E7076786F767F7A77847D82808384817B7A787E7979 + USBDEVFS_REAPURBNDELAY 0 3 130 0 0 61440 61440 0 01FE3062070718006F7374777068746A6E6C6871716E6A767472736F6E686A64656C6E787B6E69695D6D676C6F6A6D6C68686A7B6E6E6F717A776E726B69707074747E7B75706B6C676868686D6B706C717B7575696C76776C7477807C7176797E7A6C6E6F716F70676866717C70756D7179826A7072787D74706573716E6C686D6E6F6F737A716C6A75716D797D7E726E767065646D767A7E707676736E746A67716D6C62615F4E707A8084828685717A79777A868881837D7F797C7E7F738378737176777579746E75717879737B72747378766F6E737B73717979717C6F7274757D7B7D7A7D857D7F797C7E7F738301FE3162070718107771717062666C707A6F70676B716C7873716E6F6E706C6B6B6E6E7379736D6A736B6C6A6B6D6F6D646E6B806D7268736F69706D6F6D6E74737A757173756D686B64686B656D6B6D766C72706A6C726D786F73716974727B7C7C7677716E6C6B6D707270706D7471707779747A7A78806D67707A76717869676A7673767A71737472747675727073726F6D68656274717177767A767C766E6A6D6864646552457677797E7573726F726A6C707D80777C7B7C7D7A7B776C737D736E6D69716B6B7372626D70726B7072757C767C786E6B6E707178747270777D797E7F7F8087817B7C7D7A7B776C7301FE326207071820736E6D6A69696F6F75686B6D656568716D746F6F6C646C6C66636E6E75787173696B6C70706D6E6C69646A726D726E6D6F6B6E67697171766D73737971706D646B666A6F6B716F72787B706F6E7580776C7870766D667075797E7670726C6A6F6B6E676E6F7574717978737273777A7A6F6C706C6D6E756A6C6D7172747677737873706B6C716C7279847F76757474746C7575717470706C69696A656461574C6D7A7574736D6E6A7675786B77797B7877778077747A76787271776E756E70727379726D6C717473736A787D747176756F6B7472757E7B78767B78828081818477778077747A767801FE336207071830777068606364666F736B6969666B65756C6576736B6A6E6673706C71746F71756C6675696A686A6667676D7175696A70777C736E68736E6C73737A6F6F6F6D61666F6A6F6B6F6E71776D66676A727B7973797B7E746A69727F7B71736D6C696A67616B6F757871757377706A7677757D757675737C74717075726C7071756F70736E6F7574707979787676796D6B73777971797F7B7975726365646A5F5C534C6C77757373757670726D6E6B6D78828280777B7579786C7673727170756B70706F776E74716B7470726C7A79766C6C6F706B707B7A797973787B7A867D84838180777B7579786C7601FE34620707184072736C756D697A78796C6A6E6C726B6C6B736A6D6D7073756571726F726D777B746F6D6A6E6B726860676F6C75716C6E7370756D6A706D6E726E72767C70726C686C696D6E6C6A687F747A707068787A757779726E70666D757C78717B73716D66646473706F7378777A76716C747D7C6A6D6E736E756E777C706D6F6E737E73796B757A73717276757A716D6E6775766F70737971767472706F5D5E615D5D487D77747776756C6C79746C6E7E807C7779787A736E736D7079726A7575726D6F7375756E787A6D7272747378736F73736B6B747773796F727E7A828C89827D7E79787A736E736D7001FE3562070718507A726D6A686F636E6F6B6B63647477706871716D6E666B6C62716A6C6F70726C67676C6868696D7062656B726C6D6C736E71706D717C70746B75747A716D756D6F6F696366736C727D757772696A70747573737B6F6D6A747B7F7573726C6A70666C6D706C71797575796E7A786E82827869726D757A7073686C6E6E6C727A716C706D707A6D6E74757876766A6A6E7877777C7B8178786C6B696C685E634E487576727F7C7873687477706E847A7E807F76847D77767079797871736E6B6C756B756E726F756F70786B7770716C736E7C747B756A78727B7881818B7F7E827E7F76847D7776707901FE366207071860786E6D726A676C6C6B68666869706A70686A7374756769706A686E717B7D6D6C6D666A656B6E716D6A5C6F7478746E70727E7179706B6E6F75747D75786F6867676C64647070716779756D6D7077776E716D79786C6E777387787D7E706967716B706C71666D6A71707A7074787A7579766F736D7075746F70717171736F716D726A6B71786E7175757D7B747E7B7E6D696C757D72776F746A6F686D685D5547787C807C7B6E777A75707670797C837B7B787475717B75736F70736F7A6978747B7E7576716F74797D717170756F6F6F6F776C777578717176727E86888A86837B787475717B757301FE3762070718707575716F726B707279626D7374706F6669707274706C666B6971746C786C68676C7168706E696A6F70686E7276686467746966726C73736A676F78796E696E6C6E776A65696D6E6F76736D68726D7E7168746F7A736B72787C7F76717574686C626D6C6E69696A7C7D7178716D7277807C6F76706F747173746E717878746B6E697B7375746E7376778173786E6F747B727178787978777464606268645D534873797C706F726D6E6C6967766E7B71747776736E7C75777073706B7277706B6E716F6A75706E6E7275727B6E70767378777A758271797475757D7F847B7A7E827776736E7C75777001FE386207071880766E71706F70776B726869726A636C78727B6F716A6E726C6B6F726B726C6C7170716C6B686B646E6A6B6B7771716C74717371736E7966747174727877737168666E696367716D7471726C6F6E6E72746F817A776E6B746B777A7971756E666D716B687273667875786F6F6C716E7970747575707371756E7F7671716A7370736C736F6A706F75767D71797A727273796F707772737979736363666B6B5D5B4F6D71727B766C7B7474786E757E827873717070777C7870737778767A7772787577736F796F726A6C716F747A7872766B6E6D686E747C75797D7E8187807B7E7D717070777C78707301FE39620707189073676C69676E6D6A706B6A6A6C736F62716F65746E6E6769676E717C746F6D6F6E6F6F6B6D6D6A67635E6874746A6B6E766A6869716B70787C687D74726A7572696D6E6E69696B736A7173787C777579737F797F726B69727E74736A76726D6F6C6A72756A6F6F7376736F6770766F7A70766F6F7274736D726C716B717378796E716C747273786A797A706F7676767E756F77797A7A746D636467635858574E7C77777576747D786E756B73787E78777B7378727877746F7F7270726F6D6E746E746E6A736E716C7A73747A726F70736B72767B7678717B827B7A777F7C827F7B7378727877746F01FE3A62070718A0706E6E6B676B6F747268656A63686A747969636A72656D7373736B76736D66676F6C756D6D6B6E626E69706F6D776665666F776D706D716C767378767171686C70717270707066676D746F736D70756E70737B757C74797D77717570736E6D726F7070757370707377797565707A837F74676C6C6E676D6B6F7273807B7A80756F6B6F6E6F71727071726D716E6F707A7F7572726D78726D6C6D6B665E5B61466A6A7C7A756F7D6D756F6E6B707D727C7B7D776B777B777A75728275747275806F6A72726D6F74717770757E6B6F72726D6B7579737572757E7F777C7D827D807B7D776B777B777A01FE3B62070718B07B786C78666E73717173756D70667276756D70706D6B6A6D6F72727271716A776B6E656A6E6B686969676D727961697570706B746975787174707A6C6B7169696D6D636D6C74686A6E6C6B6C6D76747B767272787167697E7C7F6E6F6E756F6D6B6F6C6F666F747A7B7B6C6E6C767A7E6E6877726C686D6F74726D776F7A756E76747471757A7F797E8579686B707175766D7976776E6D6B6E696D6F5E585B4274727C7A7E72796D7A71696E7D7E7E7E797A7C73777975767475797C78706C726E7171676F7977767272787E736C6D75786F6E7A737276767E7B7A8481817C8A797A7C737779757601FE3C62070718C07269646365686A717068676E5E6C6D756D72736872796F6B706971787164666A746F77716F66716A6E6B7471656D6D6E6E76796D6A77706F6D7574716E696564615D62676E73757975716F72777570706A737180777A7C77858476746F706A6D756F76756C73736E7876726F767B79796D726A75786F756E6E7477666F7476726B6876767766687D7B75676F6D6D727B7F797074777B737366676F676A5D634C74706E756B736F72757379707B7B777A8073747575786C727A777473717179787171696A7470736D76718274757474746E6B727873727274837E8088807F7D7E8073747575786C7201FE3D62070718D0786D69746D70756F786C6D66687175766B706F6A676E736F6C6A7473706C7B6A5D7970746E695F6C656B7077776D6C706C716D6C666D63787B74727571696D65666B6B686B7C6D777A726D696D73746E7775716F6B68727C848073797C6F6B6C69676A7367717971707772766B76788071766E7A716B747876757373726D727767776A6B7170737776827A727574747573767676767672696C695D6463545949766E78736B6B707775787079797D79787A7F79797277706C71797578787667717C747772736D6C7C6E79797C7C72767873666D726F75697679777D857F7B7F827A7F79797277706C01FE3E62070718E0746D65706D6D6A6F746B696961726C6B6E6D6C6966676E7B6F7077776F736E6D716D7471716B6D7562636C71676F6E75706B6B6F6869727C6E757173706E6C6B736E666E6D766C6A6B747179796F76716F7774796D706F78807A766C71746F70696D66686D71757C6E7A7977767F7B756F6573737169747374736B746F756D716D6E6D727A757075797874707069787B7B707474787779686F665E66695A604D77707A7A7476797773716B65737A787A7C71727772727279807977747468717474746C777579726B717277707472776E6D6D7E7674767172787E7E8280857F877C7172777272727901FE3F62070718F0837F747E7974787070716668606E757376736D74746E6769686B7579726C6D66677B76726C676B6D695E6B6F717271716F6D6E6A6E6D73706C72736F71716C6F6C6E6D716A6B717888756C746D7A7C7374766F78646C6F6C777B726D72676A67646E6A6D6A6B6D737E7A75726E8076857B6969677576776A71717579768075757075766A72667570787E77746B7075747A7A7077727079706A6A6367625F61526E78797D75726A6D7A6E6C78777A787A787381787F7E6D7475716D6F71757370746F746D75727B75746D7A7977777269766B6E74727978717F797A8482838684787381787F7E6D7401FE4062070718007573747562656F6B736C6E726F75786B70746C6C6B6B686D6970706E6E706B7170656D6970696866625D6A757D767F767169726E6A7374796F716F726264636172736F6F6E6F6A737A787876756C7273746F70766C6B6D728180777873746F6F626B7178716F767A7575726A6D74757C796E717974746F6B656C6F726E767972756C6A6E70736E78747B7375776B7975767273727479746F6B6A636060575A496E727373676D7372766E716F72787A79747273757D787C8077697073766870787A7A717374727478796A7671746B756D716D7276777A71797B757C7F7C807A81747273757D787C8001FE4162070718107E796E79776D74777D6A6F6F706D6F6D7672706F74736F6F716F77707975716D676B6D616A73746C6C6C76737B6B6767687161616A746D717872717576636F6C6D6B6A6F6F736F7D8778736C7C707073707074736B6C6B747E777971726A706D6F6B676C666A72776D7B71716F75787B7A747875726B6C6D71786D797178757266666E6C6D786F73718077766B697B7270777B7F7D806E646B686B6C6A5D5A496F79877E7C76777476766F787E81817C7B7E7F777674797878706D7070706F7271716E6D6F706873767C837974696C70767875767C7A75707A797C82777D827D7B7E7F777674797801FE426207071820726A706E69697370736C6A6D6F796B6E73686A6770716C65686C7A6A6A717070696B65707073776D6B6171766D6B6E676C6D726B767D6D736D68706B71736A6B7068687970746E71746F66707A7076737080827B747175787C7A746C6D6B666369696A7161707B7E767B7C6C7576797B6A7170766A70716F6D767275766D6E75766863717578727579797A70717275797670756E73787673686C6E6D6262574A727B7F807F797B71767770787D868A7F76777E787B7D807574777271706E727675767075696D73766F6D767377737577757A7573747273747F727D81717C777F76777E787B7D807501FE436207071830766671747375746E75656375756B726C6C6B7875736B6E6A6C6764707078716F6D716B7162666A6C6D6D6E71706869726F78706C6B706D7072707774756B706B6E706271666F6C707C6E7471787475726B746E6F6B70777E7A787A72746C66655E666E6F6D716F7A75847D73777A7781706F70797978736871717372757471736E727474727078787C7E78706C6C6E6D73717877746F7A71706B696B5F565855747274758377787C8283777D7F85897E81827D747A797270756D7477777778766D6D767872726B6F72707B796F6678706F6A6878757870707D787C807B7F7F7D81827D747A79727001FE4462070718406C70606E675F6C66746B6769676868616F706F686A74766E6A6C676D69726D617269696468666D6B68646C726F6C6E6F7277716A706D6E7372726B776D716E6D706B6A686F6F6C70706E706F6C6D6F7B7A8077746F797878787C736E7069686A686468737170706B707D7C777975767D70726E737C6C69646E6A717276767B7374706D706D757A72737C75706E6D73736E71787C75808171766A7267605A5C4C716F7A71757A7771726C6A73757E7E787B7C80787576706F726872796F74757472767073777372727A727E80716D6B757574717D7272646E7873858A827F85847B7C80787576706F01FE4562070718507272747C75767C75706C6F75687A7376777371716E65676F6F6E70736C756E6F686662666E6E6E68676D687A7671696E6F6C716E6C7B7477796C6E736A6B6978726C6C6A776F6D6E796C716E737779706F72767668737070727C78696B7976736B71736B7172726F7B7A7D76776E76736E6E6C6F7076696E747878757C706C6B6871716B706F7076747771736D6D807E7C737C7679786E676D686D68655D5C50726D7674787673797A80777674757376817A7C7A767D74797B74726470736B6E736F6E73757773707975806E6F726F726A6C7F7E73707B7C807C787A7A7E7C87817A7C7A767D747901FE46620707186074756B77666C72767568697065756971716E766B7367706F716C6B69686D6C706769656D696373666C7475796E72706D6D6F7270696F7379757777787672796A6567666F6C6B696A7271736F7670737670777B756F7170787A7C786D7171676A62667177756F777572726E70707D7E7D7370686D746A73706D6A7170777B6B6E667A7578726C717A70787A7271776E7B7079736F7E716F677067696266635C4F7777897E7778777471706E6E76777D7B7F7E757A7F7B7A787C77807E7B6F6A6D6A7076726F777A75746A757275716C6B6775737470786E797A7F828F7E7E7A857F7E757A7F7B7A7801FE4762070718706C716966676670726D6571696D6B7E776B71716E6D69716B6B6D766F77726A736B71766B7872686A6A6B6D78737169716A74716A6D75777373706C7B7575686E6765686B6B6A7073787A6B71736A74776C6F777D7069737C817F756B676F64626D667471706C6C6F6C7B77736E7D7B7A6F707474706A6C6667767077727573766F70706A7A7274817F7A7B6D6969787678747D7C8275746E6764646568625E47766D756C6E6D7173747070737B817578796C78747D7C747876707573706B6C6C6D6D70706E76756F746D6E776D6D69707271747B7B797B787B787A7D7E7F7981796C78747D7C747801FE4862070718806F66636266656E756B60666F68697272737476696B606A74746E6673706F6E6F6C6C6F6E7668686E66626E73726A70686F6F7468696F69797970747578727772706E67666F786874807274717772776C71757870737270757C817575746F6B6C625F6B7077746E7678777970787775817A6E6E736F666C6B7669716F7179737B6C686968696E7973767975726E6F747F77767D7A708170726E6D6F6263625C4D7172746F68737A7276736F6577716976797A77787E7D70726A726B7876717077726E776F6F76736E79707A777A71706F7372726F6E717478767A7D8086808584797A77787E7D707201FE49620707189075716165676E6E73766E746871676A6C6F6D7076666D6A6A646D7676726E6C6C6665656B6F686D6A686475797D70656E666C6D6C6C77757B76787B78766E6F65656C69676C726B747E7A73716D70686D6E7A797C6E767F7980807B686F68656C64737171727175716A767A72797177756B6876736F6D6C6F7775716D75746F6B6E716F756D787B747674746E707170787A7177727679786B66696A6B655A504B767A797B7B727875787471757F837C77757974756F71757177787B6D6D6E6873767378787478726E796D7975736E6F766F737A7A7C6C6F7B857C7E877F7C7F80757974756F71757101FE4A62070718A077766D6964647275716A6968636F737174716E6D60706D6F676A6B656D706B6F6C65656D6F6C6C706668746F7469707078737370687573736E7274706871766D696B676B5D6C6F72776E6A6F6E6876757576747570736F6F7B70756F786F6F706F6768737373717C81826E737A787F79786A6B716F6F6E716C6D6A7373737A7B6E6F766C6E6B72736F7D7B6E6B72727B756F71716E72736B6F6D676B645B5D5078748178717473767B7A717376747B7C797479757B7471797175726F706D78777179736C7C726F6F707176777C716B6B72756F757A6E6F76807D81857E858085797479757B74717901FE4B62070718B07C746E7A70737074786A726B6064626C70706E6F68646C7271717478797B69706D6B6A73676A6A6764656B7377696A6E756F7376746E6F74747D786D7A6968666A72646E6D7874698074706F6D6F73786F717B7E7166707D797E706E6F6D666872696F79726E707A7278797A6D7A797772756A6D7A7173706C71687266717574706F716E7371716E76776E75706E76807E7E7774706C72706C6A6A6A695C644C6E6E747776797B7476676B6D787A7A74726D7476808079797A767275786F777570736D666E7171766E6C737C826D6D6566717674707070747B80818382888482726D74768080797901FE4C62070718C0787667666F6A7276766D726A676A636E706E6A6C69656A6C6B6F7373736E737266686E6A6E6A6C6B686772706B66706F6E6974716D74727F74747575716F70696F6C6A656B78706C75786F6A7171737572786B7D777474778082737272666566696774706E737372737872756F767B76706B6C6F7176766F7273727675737570676D736F6C7271707C807175707B7B7A716A78757265766E6C6A6966665C5C4976746F73757B7675827C72777C757A7D7D717D727D7A787976746F74717276796B766E72716F74727C6F716E726B726F6D717C7A73717C7C787D8084757B76807D717D727D7A787901FE4D62070718D0827762616B6C666C746C756C6A67696A72656C656B706E707072707576717674737670726A64626D696E73736E6A6C706E637075666D727671736E746C6F6667686C726A6B6C6A6F7575737B736F756B68787377697376757D7E716A7475746B6A6B6E7773727879777C7C6F6A7275816F706C77746F706C6E75716F7274776E746E6B6E7470727D7983767A7372717672696E6E7171746B655F5E635F665D4F7A807B797879757978706F757681807F7B75757676707276746D72697470707C7279767974757A7A7B70797778717272706C767B6E77767671717883828083847B7575767670727601FE4E62070718E07E767369715F706E716C737063736B737073716A746A736F72786E72757367727071716C6E6D6F6D7067676D726F69746F6E63696B70777A776C77786C7067716D7774736D666E707D7173716F6C6E776C776E716D7375787682746F74796F70626D6C736E6D776B72797D727775827C7674716F80727569736F7972716E727372706D6D73736E7274797069676E71737970736D7378776A6F6F6D65645E5D5272767D78747676727879706F7B787A777B7778767D706971796C6E74776E6F7577726B6970716E71716C7F7F78716E6F73707775707976767B7780837E7E7F837B7778767D70697101FE4F62070718F07C756C69656C7573746E726C666F7777716C6E6B6B6D7374706D6F727D6F6E6E696E776E7269676B64626A74776E6F6F7074796F706D6D6B6F72746E716F736E696C676A6D756A6D716D7679736C76766C757478716F6B6E7D85787072706D716C706F786B6B72707E7D7C7A7077787B75716F6C6F69707371757C717A6F70716A6A68767B787C797D7C6A6E686E6E7071736D6C6B6D77726B68757168564E4F6D727F70766C717771656D777A85787E7A7D787A7572737A78716F70746C706E676C7077747A77707273707C8076727672717A79747876747D7F7E857E7D84817A7D787A7572737A01FE5062070718006B6E686C6766706B675E696569736A6E7372736A5D6162696B62746F7571687269736C6B6E6B6369646B72726A6F6B7372656D6E6970787777706F7C72676F6B6E666A69686D6874706D6766726D75716D7A788374716B79827D736F7A686964646F7A736A6D6F77757F797672747273767073757A77727169717779737E6C636A776B6A696A737A728174727573777B8174736E73786F7277645B655F605B4B6E777B7374777479807D7375737D817A7A7A7F7C7A75777D7A6F70727B706E7974716B6D7276756D6F6F787476746F6B6E707576757875837D7A79827C7F7E827A7A7F7C7A75777D01FE51620707181077696B6C6C75726D6C6B6F696F6C666E726B726A746F6B726B626D6D6E74766E6D68726A6E6C6D6C66697178767370716A6F7A6C656A7572737478756E696D68676A6469696F74726F786D706F6F7174717671776A6B7079778077687577666B6B72776F706B7E7775756E716F7A7C7C69696B6F7A7577706D7274796F6B6E726A686B716F757C6D6F6E73796D697B786F71787777807D706F6B6C6A635B61547275717675767D757A6F77767A757C727D747D7C7E7C77787578726F6772717B7575776E6E7977697570776C747573786E6D697575767E7C777B717C827E82817D747D7C7E7C777801FE526207071820706F656B6D6B73766E6C6E6F676E706E6C6F676E6B6C71747478746C6B736D6E676262626B6E6E656E656F74757173707373746A6D747F7B727472726D716D70686E64666D71666E7572767175736F77686B7A7E786A7D757777706E7C6F726966706D6F76636B7A7981756C72696F796E716F6E71736C67716F6D747A71706A6F78776E70777C796C76706D686F7B6E777675777474736F666B6465615B634D6E6D6C6A6C6F6B71796F6A6D7C7E79857F72797379786E717A776B7072696C7269777070717279747A757F7A6E686F6B6F776D767377747473757C80827C87827F72797379786E7101FE5362070718306D736464676C756F7B6F686C69606D6D6B6767686D6A6E6B646D6A6C726C67696D6E6967716D6D6C6F6B6B71626F696F72747B717371756F7472777474746E6C7269656E6B676F6E7E7173796C6879746C717B757373787672787B7274726668706E70756B74737278717072666F7B7A6D6A7476706E6F6F6C717A7B78706B7076716269717374767E747B74726A75777B747274717A72696D716F7066585E4B74796E75776A757376787A74797A717A7A79867B7E77737B7572707370696D6B707676756F726E6E73757D7B7873776B6F666D7A73756F7877767D85797A7C807A79867B7E77737B01FE54620707184069716F6D6F7773727070706E6C6F6A6B646C7168716C69666D66706F73716D71716F6A76746D6767646F6E7A746A75676E70766C6B677271707A71736E6A6B6D6B646A6E716B707876706E7976726F736F6E767A71717278797D78726B766B73696C65706B706C776F767A746D7079756F6A6B727272756C6F74787A716C73726B6F716D707579717B8170756D70706F727576777B77716C6C675D6C6A6B59487777837C7E7471757671767D7B888581847D7971797C7C7976747579776C7272706D746F6F6D706D79717A807D7372736C73747A74746F78767A74807D79847C847D7971797C7C7901FE5562070718507E7772736E746F7A746C7373716B6671757A706A677272696E6C777B796B6E6F75726B727A716A6B64666D726E686871726A736E69706C78706E6D6F79756D68686E68686D6D6A747B72747171716E716E767C7C6E676F787B82736C73716B6C706C6C717872706F6A71716D6972787B77716F6C786E70667272707269796B7076706F797D717775817C72756A6E6E6B70737177757372766E6F65655F5A5D4C6F6774777371697071756D6D7A737B7D7477726E73787E7377706F7E706F707274786F76777271777074766E70716E756E706C737878746C72727C807D777D817477726E73787E7301FE5662070718607271686C636C77706F6461706F6B6869686C6C6E726F676B67766A6772666C6F696B6E6D6F6E70626E6271726C6A6B6E73767C6D65687479777176796E6E6A6E666D66656E73716C776E6E7470717572707C75726E6C6E76877F757073706E6B6A6B6C726D72796C7D767473737A757F73757178766B6F6B6E6A6C726E6C706D6B747B726E74747A7A7A7A756E676A74736E677674807869716F6C6763665D4E7C737D828476737A777D7C7D81868076797A76707373717479746E787C73717D71746D696F7B74727B6B7C7C7572717573727D74757675748082807F7E7B8187797A76707373717401FE5762070718707E736D6A6B6E6771786D6967656A6F7A726C6F686A7768646E696D76727270776A6C6A686B696D6F6966637D75787573696D686F6E6D7573797172746E646A686C6F6A7162716D707C736E7277757B766A7A777E746C7275717A716C71755D67656C6673746D747179796E70727D848A78717373706B6B6E716E757B726C6C75716D6F6E726A747872736A7A767C7979777777767E777467686B69635F60574E787574797C777B717274686E737F797477717678787D787A7678757A726D6B7078756971747072706E727D747772707573716B73797A7B77797579767A82828577717678787D787A01FE5862070718807E7373786D6B6F72716F7A766B73727B6F716F6A636B656B716C76717F746876686C6B6A6E63666C686C7078736E6A70707270696C6A71736F6C767274656C70656F697069746C676E7280787371787C717F7684796F73777C85767174706C73686D6B76686F6A707675797271797476796E796A746E716C6B70677576737A74767072726E756A7272706F726D6C787A7C7171736D747374736B696862586049717572766F687B707270707479707779807A7B75787378767B7272717E7370746F6E6D72786F6E77716E757271707B7A73797B6E737771768075757E7B7C7B84807A7B757873787601FE5962070718906D7171707278757774646F6F6A6D6B746C6D7069696D6F6B6F726E827778686D6A676C68666C726F6D716B73766D6A70706E686C71786C727A6A6B716D70706C727473686B77716A7C787271687B7A777974716D6B686B737A7A7871756E756D73736973676472737876756F6E6E7780777579767977746570777B7C7B726E6B6A737367737075707479776467757B757377787C7778786C6F6A665C5F5B644F77736E7675717B6D796F747D7C7C74837374706C767A787C837B74807971757579807576706A6F6E726C6F706E756F717278747977787073767372807E777C7F7374706C767A787C01FE5A62070718A0767A71797273736B79756D74647468716E7574706C6E79747676716C767573766F6B6470706964666E6575756F67666D6B7078716D746E7570767476716C70706D6D686D6F6E716F79746B706E717774706F796D6F7478787C807573726E6C67666C6A726F696C72757B7B766F757C81737270677A6B677278716F767479726E6D7071697872736E727D7177676E7579767A6A6C716C746F6D736D6961555B4B747076777171737279736F71797B7574716F747B77756F7376747574766C70666A6E7672787C76737B727A7672746E71666C73716E6F7B7F7875767F84827C87716F747B77756F7301FE5B62070718B072736B666A6C6A6E6D636366676D70736C726E62686E6D69676E726D72717170696C716B676B666664686D766B666870706F7367727075726E707277756F6B65716468686D6D6F72757A7773727172716C6C6E776D6F74707B787775726F686C67687077707473777377827C747778776D696F6C7B74736A6E706C7C7B7E7A686B6571726F6D6F7073777972736F75777670717779837A756C6C5A5D645F534E726F70767678777771677279897F7F83867A70787576717970776A6C716F716F70787271757B7D777C6E787A766F6A726E6C696D7D7E76757E7E7A807F807D82867A70787576717901FE5C62070718C070736466636C6D69726A777468696E70736E6A6F7175686B69796F7373736871726A69676C716A666C6A696E686A6E7A7F726D67656B7275676C726F7167676D6F706B71737574727D766D756C6F716F716B75736D6B6F76827D756E70736D6F74677278776F7175767578707674797A7E666A747773706F72746D717071716971717471707273747C7671796F6E7278747D7F7D7479757572695E6A645F53417B78707E7375786B77737B6E7C7C777B7481817A777A76746E7173746F6F6C7477787270737377726C757A7773696C6F6E777679747571747D7D7E8F7B8485817481817A777A767401FE5D62070718D07A696C676B6B70696A68626D66696E757067686A666E726D69716F6F7776696F676A6C6B6E6C6D6C6B656D777370747374726D6A6B6A706C6B7D7072676C6D73676F726D6C686C6A7A73696C756D7B7C6D72727673737577727778726D6F6C6F68756F7674777479817B777170766E78716F6D7474757B6F6F74727A6F7273716D686C6F727779777778716D697173787B737876727A786E716A696760605F4E7477736D757276737572707680857B717B7D7E6F796D6E797C776C6C6F6B6F746C756E716E75756B6F727C77756F71696D71727C7575717A757978837F7A7B867B7D7E6F796D6E7901FE5E62070718E07774706768696B6C73646B6671687968777570716761616E68696B6D6B72696C6B666C69696B5A696C6B7A7A797377736C6D706F666976807575747270767266706D666D6E736F6E727874736B66737069787C7D6B686A7977756F7A777370756C757268737070757B7C7C707175757975747970696F746E707B76757273766C6D6D6E6E716A727A757D7979726E717375726C71727474696966656A635B5C5275737677777A8178776E6E7C7E87837C7E77747B78727474736F737A787274727072706773706F73776F7A786E6F6D71716F697078787073777C77827D7982847E77747B7872747401FE5F62070718F073696267746E72746A5F5F635D6A646E6D756E676960656A71767070776F666C677166676668676E6C6E7276736F6E6670686968616A6F777179807B71716C676B73666A73756A757B727471746975706B727379706F6D70787B75706F6E6A6C666D6C6E6C76737378757B6F726D7680706A636E6F726B747372766F7773726D6F777A68736F7974727B716C72747E817676777675747D776E6A64646C5B5E4A726C6D7B746D6C7172696A767C85766F7A7B797A7E726A6E7478787878706B706C6A647272786F737A65727D7F72736D74717671757976737174787B858083807A7B797A7E726A6E01FE60620707180074646A6A6665666E6A64646F6A6D71696A6E6C686164626F68736C726D6F7273746B6768737165616968727A717371616D6E6561666F6B746D777178686467666A7072696F6C6370766F7175766B7772706A6F7A756E767883877C76746B716961686C7373737478767874787073777570666E73736F7072707A6B76796F7775736F6B6B747976726F79767B7573706D7478777273707369636C5D686C64594A7170797477727777726C6C737A7C767674727D76777471737D6D6C6E6D6C6979757C737979797164766E787C6F6972787476757672757E7A8077777F7A7F828674727D767774717301FE616207071810707A72746F6974746D69736767766B716D686A706F6E657077696C7378787374696C70696C656C6A656F6E6F727370716668666A696A6E786B6B716C736B6E6D6B767175716E71737E78736F726E6D6F6973727A726B6E7A80787571766C6C6D6C746C736C6F7075857A79716D6F76756B6F72696F71716B7874787A71747B706F6A716E73706D7A75746F786A7270667876757E717D7D75696E686C645D60507677767A75777A756A6C69787C797E7976777D7A7B7572817A7368707B737375706F79727572777973737778747D77707175697B7477707975738082807F7A8576777D7A7B75728101FE62620707182079706E6C69696F74767571726B7570676E68776F6B696B6F6C6B75786D736C75716869676A696E686967707D726F6D6F6D6974766C7071716D7881756969676D66667173726A71747682706D746D6E716E787B7773686B7B7574786B797172696C6669676E7975757A78756D6B817D79736D757677756F7076726E6E6E7277717A766A6F78676A76757D70746A6F6C777B7777697275796E6A66676A675C6248787B81747375777673737B7E81867E7F7D7B78766F6E74797B767E786D75747470726D73716C69757B797873726F736C707571747D7E76787981798884827F827D7B78766F6E747901FE636207071830786D5F6E6568737276716B716A706E75706E6D6D6C6A656A6C6B72747B73756E68706771696E706C6A6B74726F6A6B777276706F616C6F707273766E71646C6C6C72706D5E6E6C6E7E75787776707C757174666E6C70747B7E7E726B72727164646A6974746F6D746F767370747E78736B656E7770756D70727272777B797D7E706F6F797275787F767E7777716E707370726F73757077776D6868675B615E4E77727F736F697B7B6D6C6A70717A7C77847F7B777D7575787D747970756C77786C6B6D6E6A6B6D777D76747B7A72736C6D70777A77766C72797F7B7B7B7A7983847F7B777D75757801FE64620707184075696677726C746B7667736C6F6F6D6A706A6E697572766F616C69797475666E76606A656A6B616A6C646C75786E6F706E6A6B6C637374817A6B727A706D626471626C6E6F7573757D75787075717A707773797B736C717F7B796E676C70686B65696E6E636570797778787C6A777F796E6173726D7376706A72707A776E6B6D6F6A6E756D7070757B7D7470706D6B7374727170787879706571696861605F4A75747E7879797474737072727D78787E7A7375758281757B8478747B79716D6974716A717C79747479747C78717674747573777378767276787A7E7C75757C807A7375758281757B01FE6562070718507E7A786F746E7A75786F6C6B6B6E6B706F7170716F6D706A6F727273726A687673706C6F6E61675C68696B6E726D6D706F6E70706C747173746D76766E6B66656F67606B74706C717773777471737E7166757C7A7A7878797C81706C7571696F656B6D726F69716C76756E6B73767F7B6B6A706A756F766C737A71737377746D6D6D6A69736A76707378756A7373787374766E767975766C6764636969616050726E7B75736B7275727176757576817578787C797D75727577706D70736E6E726F736D787470737979737C76726E76746D727A7C75756B707B807B79767D788478787C797D75727501FE6662070718606A6E636764686A666568676F6B6B6D7472716866676065716B6E6E6B76717070666A6B666D6A6570726A706E6C74717172706C6D6A6A6D7C7174706F7172727169656A707678716D7C7569726F717E767375737A676C7C7B847E776C7472696D6C726E6D69656F7B6C7571666D767573736E7576706F6E6E6E7674747777727775766F6F736A756F777470726772737575716E7379736D6D6C6A64725A5F5B566D6F767677747A73766E756F787C7B7D7F747376787270757073707576777579737570746E707A7679767B7872777571736F6D7375726971767D7A8085887E7B7F7473767872707501FE6762070718707572716D6D65786E6E6968706B6F6779707271736D6A6E6E6872706D73786B6C7068686572786F6965666A716B706E6B7479766C6A7271706F706C6767696F6B656C67756F7C6A7C7D72726F72716C6D747B7476736B6F7678817B726E70696C6F75706B6E697779727B796E6971767E6E747273736D7C707A716E6B737D75746C7065656E70787D787576776D6A717074797479787E7B7577696965655A5A4A7A78887E7C797E7B6A7072837D827F7A817A7E76777C6F777A7A777671716B726E6E6E75786D7476756E7B7A757277666772707974736F737C75777E787E7D87817A7E76777C6F7701FE68620707188076756B696A737377736A656C696F6F77736D7073736C696A64686F756E72687F707172686A6468636B6C6669706F696D6E6A6C74757677756D7176776D6E666E6A6A686B6D6A717B7B7A7477736E6E6D6D736F71726B7574797472737B756D6E646C6976717B72727775787278787C80716C697372736F787272716E7A726E696E696571737371777684797971767A6F776F6F7974707678685E676969585C4D7A807D7F7D747A79756D6F7179797E7D79797B7D7A7A6E787677746C6F716F737D7D706E73707279786B7679746F6A6B6E6F6E7C71786F7D7B797D837B82857D79797B7D7A7A6E7801FE696207071890796D7A7A777275717B716E656E686E7878766D6B6D6D6C6F6E706C71777366736969706C6F62696B666C6A717674697B717B72736C676865796B757676766F6F6B6F706F666765676C6D74807E7476796E77777D6F776476767B75737C737065696C757B6B6A69747A77786F71736E696F6A747F7B7C7A716967747071776D6B706E6D6D7970757A75727A707069737B77716F72707371736D72716E6A5C5F486C7671807C6E766F7374797A787D7D7D81797A787A79737B7C7773726E717379747A747175766F727A6B797A716869706C6C6E7E7D78737973737A7F78787F8481797A787A79737B01FE6A62070718A068696268696F706D73696D73657369737371716C6963666D6D686564737371696D6D6C6A6E6A66696C6E767874696670766D73766978746E636F7571786C6F6F747568716E7163707B75756A6F6E79776878737C696B717C77727971766D6D726B676D6D6E6B6B7B6B767D787A7479757A6C68737476747269656C68686B6F737476756E7274706D6F6B7173767475717270747A777974726E6C6C645F585E467A71777B7D7D7E7473707574817E7A7476767B75747774787C7977766F75776F7272706B6F706A757B747C77787472767174707071736D79747E8288827A837F76767B757477747801FE6B62070718B08070626A696A6D726B6B6C6F6C6E6F6D6C6D7777786C656A73756F77727470756B6C6F6A776C6B64626867716D776A6A6F6F6C6B69717976757276756D6A6B6E6E6B6B6D707574737B706D76746A6E6B737A7372756E6A757A717D7D776E637F676869685D676E717581806E7178737D7270737D74736C706B77716F7374706C756A6C6D757175797579796B726875717C76767A787A716F6A6A6B6366615451666B747174707A6A716C6C727D7C7F78797B71737C787577786D72737B6F71706C7673757375747A776A7374796D6D747871787B7B7A75747D78757E807F757C797B71737C78757701FE6C62070718C0686A766F6B7175756F697466726C7172736269716B646C66686B6D717671727071716E666D6973726A676F6C6F6F71686C6C756C5F636F77736D6F75786E706C6D716B726A6A6C787075776E6D7A7A6E6D7672827B716C79797D7376776B6762606A6D6F706A786E78796E6F7C797B7A6F746D706D6E7277777D70757A796E6C6C736B717371746C7A8079776E6D716F726F7470717C7B76686A5E625F5D5C487579757779747269757268727D807C797E7C787A72736D6D70726C707574747A7579696B68727475796F7979726A7472786A71787376777B727F797D7D7E81897E7C787A72736D6D01FE6D62070718D072706C645E6768686D6E72686B687874766D706D746C68656C6C737C7773666668666E6F7474705F61696B6D7170697175686A706B6B737974756E7765696B6568626C706A756D717A7A80796A6C746F727A76796E717577747C71757973686C616B6C6A6B6E737D7175717A6F747083786971737F6E6F737C726B73776D7071696A6F666E677276707474786E7774838275706F7575746B68696A67666760507C7D7B7E847B7475747472767980837C807B7979807A77706E71716F7673676D6E716C7173717C7076707373777A7C6F6D757276797875747F7C7F85837D8382807B7979807A777001FE6E62070718E0766B6B696A6B6D6D71756B6E6D6A6F6E6F727170736E6B6B73736A6E74716E71686C6A6D706E6B6464696F6D6B656A6E736F6A6C6A7472717373756F7A71626F6C71656A7976757480776E796E6F6B656E74777D6A6A6A6A787A727572686D646B716974776D747A7F7B757473797980707472717A76686F687971737676726D747774706967767073746F6A726E6F727B7E746E727477756B685A68645B5B45807E7C827C716D6D71777972767F7E7675797B75707A7A7B80796D7B74727270737A707676756C6F756E7A6C6C71747B7475797477756A7A7D787A817A81857F75797B75707A7A7B01FE6F62070718F06A726C696E626E6B7266706F6E7D6D766F726B6A6B6A6C6E7369706D70646D6C686A6C6969656D6467666875726F71736C6C676B6F766D6F70696B6F786C72756B6E6D72716F6B797D736A6B696F7671717275786A6F7177857C7A6A666A656E6F72727A7170756E7678747B6B747071727373756F736D6C6C6978758875717C726B6D6D73707278757467706B707979746F6D67727A7E756D656566675B5B4A76767C80776F797B7B7B757D8478827C7A7678797A767A7471767278707579726B736E69687B796F77717673746E72706F65756F6C757B7D7E777E887E7E7E787A7678797A767A7401FE706207071800746A62656A6C6C676C626C69676C70717070676B6A675C6C666C7372746F6A68696A676C7074706B666B727378776C6E6B7073736F696E6F6C76757675706D6769716F697073696F7C7170756D6F76716D7578776D7476757D7B6F6C6D6B676967626E706F76747F7A7579736D71747B776F6E6F776E70706D6A72706A7274756B74726D686E7074797E7B77706C6D73707671716E7D73786D6769635C5B5749737D7D78776C6D69756D69737E8388787F77777D7B7A7574716E71756B6D7671787275706E696A7876747D79737676787473767976726D7378747A7C797885867F77777D7B7A757401FE7162070718106878696D6B6D6F6E67656E6661706D7473726B6E696A6D6C696F6D7274776F746F64686965646E6869676C78716F6F6E74706E666B7278736A767B786971706E756E7170676B6B727A7A726E6E756F6C6F6E7877776D6D6C777373737076746B626E686E62657670787971706F73807D74746962727774727A75717A757D6B707176706A716F7A6E7E7E756F726D6A6B71757E777472736C6D656E67635968526F7B7F7A7B7677747978727676877C7D7E74756E75777377737973787A6D6D707878707076746F707F787C76706A6E6D6B687073716B73757881818982777B807E74756E7577737701FE7262070718206D70716B65716E697170726B696F6F7472766969626C696B6D667A6E6E7772736871656869706D6F66686F776C676A766F69626872707575767A75716B6A70696B6E69676B6F77767B76746C6F7279717C7679787275787B7475686C6D67646A667375747877757B7173797873737079776A696F7873626A6A6F6D72716F6F716D6E7171727873717778747973706F6E7A7275757476787570746A6465645D4C71757B7376777478737A736A747E797C7C7E7E797A7D777E7B706C6E6D6571736D6E6C7268717179786D7C8371717474767275797174707582777A85817C78827C7E7E797A7D777E01FE7362070718307C72707070667078746A656F63726E6F6E6B736F6869686A6D696E777C6B6B7A786B6D706A656D6C6D666875746B7968737178766D6B6975707877717B706867716A6A686D6F6F756E79766E6F657473767675726F776A7D85797369717172686C666D71756B6B717A7F7B6F756E717570697275777A6C726C746D6F7375796E6C71746D7371707A7A7A706565677071756F777B6E787E756C6A706A70655D4B6974748179767576796D6F7581767E7D75717A756E7A787A7F7B7475706F737873716F6E6D69757676707A767873706B70676E7278756F77747B81888283838275717A756E7A787A01FE746207071840726C6864666469686B6660715F6C68706F6F706167656D666C6B6E6A756E6B706A6364706F696363676D7C776C6E63736A6F6D686676746D6E6A7975756B64696071636B6C7675757A777871756F736C6F73747C6E6F6977877D7D706E696F7271706E72706B797776737A6F697676736B7773737573726E727174716A76686B71746E6D7473747A7771786D6577807D777A77716C70747464696E706E645D4F75757E7C7677737B7F767275727C7F7B7770736B767B7976777870777378706F71756D79797375747E6976797271746F767778747974717B807573787B837C7D7770736B767B797601FE7562070718507471606D726E757177676E68657369706D6B69696A71756C696E706673746E6A65697171716C656567696F7A786B6F7570726D6F70706E766E7272717970676B6D72657873706B707B74726D676971726E7E7774686A6F717C787D7671726F68676B7074696F716E7578726E71767C807575716C736F716B686C7374757676746D69716E7978737C787973736E69767071756F71797A7B6E6C6D6D6E605D5D4F7E7B7D8080767779797B7872777986808779816D70796D766D697274736E747D767A7074727A776D72717D79776E7772736E71787478716F77747E7D817A7B858779816D70796D7601FE7662070718607971686860706D6D6B6A5F715A6C68717072746B70726F716C706D726F737171646669727468696D6A6F6C7777686A70726F6D706C756F786F707672686F7068716A686B6B76707676776E6C736E716F6D7770766E6D746D767D786F78706A69686E716A656E76787580757E77757C7E6D64716A726D6B6A757173727A777C76666E6A6A6C7878756B787D746E6A737778727A73717572726B6A6A68655E5B47797379777070717C777278717A807D7D867E817777757472756E707674726A6C66717272767A72716F6E727276736C717370777A787F7B7B7D717881817D7E86867E81777775747201FE77620707187071706770666B6C757666636161676E6A676C706B6D6F6D706D716E7179686B6C666E706B6B686F6C6B6A6C70736A7173746A736E6A707D70717379776D6A65766C6D626E6A75686C7571676F7270777176827B7371706C6F8075706C76777572666A71736E78797374757A7074746F7A6C6B6C756B74756D6E7069686F7479706E6E777A77776D6F71717173696A7B7670727773737975736765696D62645E4D737D7B7C7E7B7772757176787F7A777C7C7875757572727C807A7C74716E6B7B737373777178726A6F727C7B7671716E7774737A727B74747179757E7B82807D7C7875757572727C01FE78620707188072716667646E75827A6468666D6E6A706C736C756974746B6B7472767465626C726D6A6E6B6E6F6866656A777370746E7071787676746F746573767670717764676E6D6E6A7068727072696D7073786D6E7277726C6673757E827A6D6D686D71696D6E6D7074756F7B797D7B72727578717A6F736B6D7068696C72777A7372736D6D7076716F717B757A6D777070777E807576766C6B7072726A646B625E5D577B77817478726F717F73737F83847F7A7D7376797175737678756C6D76776E686F7B736F79786B7576717A7B786C6874686266687875757876807B817E80818A7D7376797175737601FE796207071890787A70726F7174747470726A6D6C6F75747669686D6A606B68676E6F7473707068706C65696C6B6F6A6877746D71777176736D6F6E6A6E79726C807274666D736D676973646F6B757B7577697972787574706E726D6F717A7B766F6E6D656D69676F7076727576707370747076747D806E6E6974707069706E6B74717A6F757070756A68696A71777B7D75716C72817A73727776787574707276686A6A615B477A7C78767371767B7A726D7C788080837B8280827980787975777C7C746A7176746C6D70726E7875756F747474716D74736A717B76767A7575787D817F7F83897B8280827980787901FE7A62070718A0746F636760626969736F6C6F6D686C777068736B7472696E696D6C707468716E6B6C70646F67716E666D6973766E6C696A7475726B6F727E74766D6D6B64766B69766E706E6E71706B77707571717B776E74787B757274717E7D746B706A646463726C706D6E737072737678707A7879736E706E72706F7670726D736C72747A6A766D6D746E6F767B72756E74707575707371747977776E67666C6C605F5F4B756E757B786C6D75776E6A777E7F7F7A737A7D7C74756C7874766E75717473776F7470786F6E6E7673727C786D6972796D7374737574717E78757C8484817F79737A7D7C74756C7801FE7B62070718B0756C69605D6476776F6A756969706D6F69666D6B6C6A6C6B6F6474717F73746C64696A686A716768696A73737779666369646E6F656868737470747A7E6A6E6F79716A646E7B707479776E746566756B6C7679706972737C797A7770796965676A6B69726E6F6F71797C72746D747B736D67706D787377736F6E706A767B7B70766E6E716B706F7A74786A6D7273787679727675788077786C6F6D635D605F4F797C737875657272756C767B84807A6E7173776F797C7A717768686B7274796E73726B7775727372726D76767C6F707677736C7674737778757D7C837776767A7173776F797C7A7101FE7C62070718C0767576746B71766B67696B71696E75787470706D76726B6A655F6E707171717064616560706B6C73726D6C727A706D6C6C6D6C706B7070796E76726D786E706A6C6F696E646B73787174777171737774766F6E7B6E6B7474787D787271736F6D60706A7067696E717A7D76716D6F7A7C756A6B70736C6D7777756A696C6E7174726571727A7171726C796E7D73707777767472787A75857B6D6D62616B635F507B7A85807D7172727674796D7E7F787675796D7A7E7871737A787370777770736F7679787672757079787F7A6E6D73756B6F7179727A7E7479777B83817D828275796D7A7E78717301FE7D62070718D07B7E7C76726F736E7C727875726B6E6D73746D6A6E616F726F70777581736C7369706E6C6A6D6F72726566706E6D6867737373716D747179757A716D666970696F6D706A6B726E767C6D716D71747B6E757473766A79787E7E827866726E636A6B70637E696D696D717674797A74807F756F6E7A75766D6B6A6F7273737778706D696F6B6E6B6F70757577746E6D767B77767B797B7C807865676564635E594D747C80817C737E6F7A747576737A82727474797D7E7B7C797C7D7073787372706B7472767071737774718281796B71656E6B6E717A7E797577797E81878080837474797D7E7B7C7901FE7E62070718E0746C646F6767746C79706F6C636D64727376726B6D6E716A706E766870746A6D6573686A6D6B777069626A6A6474766E6B736D706D766D6B717679726F726E686A746871666B667476787571756E77736C75787D6D7069767A7A7678736E625F6A6F6A6E686C76747B7C787F75777E796C6F6B6B7375736F737170797277666D6B71716F767A6D7C737C72716A717677787871737A817B7567656564646262466C79797B7978796A7B747774717D736F73777A7B746C7377747770766E6D73777076777A6F787176796C7475766D70716D70687A768480827D7B7D827A7F858C73777A7B746C737701FE7F62070718F07265605E62615E6C7267606360636D6F756E676863646D63726B746F6C696A7273736A6A6F6F706F6D6A67756F6A6B75746B736A6E68716B737070776B736C6F69696B656F7071687478706E727477757E7A8185766F7075737A7573746C6E6F6C65636969716F6F778077747276787F6C67666E766E757076727071737A76766C656F70766F726E777B766E6D6A697574767B77777579757067716A665C604A6A72717970646D716C756F6E76767C73807373717A777779756F686D74776C767C7776796F6D796E73727A76706F6C676B68757A7B7972777C7B7B847D83817F807373717A77777901FE8062070718007A6D6970676C726D7467696067716E6E6F707274696A6B6C696C71727C6F6F6A6A6E6E716C706C6963666A76736D736E727773716D736A756B65767071746B706B6E63636273677775727579716F7A75727B6D79727875757A777470706E68686B67667A7377716874777B7E7A7779786F656C666E6D6F72716B74786C6C706865707972747C7D77747B747D6C727374776E707674767862656F666E665C634C7B82818A7A7A807A837A7A7F857F8A7776757D7974856F79797970706F747778706F6A736F7A716F7C6D787D79716B6D6F6974797B776B7B797E81837F80818076757D7974856F7901FE816207071810696C676B646664666465606764666F696B706A6565616C77696E706D6E756D6B68736F69716C676C6B686D747066696C6B6C74686B7077716A77736F7774796E706C66706E6A6D6D717775727573797572767177706B6A7C7C84777676696B65626F726D6F64686B72727973777179796B6F6B7C7475776D6B74716D7876786B726A6E727277757576736E70676F79797A7D7C75746F756A6D716B705F5D57497C7D7E877E7C797D807D7871898D83818379706D7577757D7673797F7870737B6F78766F7774727171757B7D7A7271766C6B6F786E726C75747979787D7E7F838379706D7577757D01FE826207071820786B6465676D736D716E656A6C6D6A6E69636C6B7169736971716F7C6F706F6F6D6F6C6667666E66616A777C7570736F6A6C76716E6B6B6B696E707773696E6468736B6E6A726F708070726F737A7770757B737A726C6D78777C7A726D71676E647267736C6F75767E756F6E6A7B7B826F7167747B6E756C7471687176727D71726E6E6F7075797B787575767972666971737372707375756F656968625E5949797F7C7E7E7C7975776F7772777D7D7C7F80796E78796D7476747876736F706C6F756F6E70726F7379737A7F766E70716D666C797A7B72797B797D8383807C7E7F80796E78796D7401FE8362070718307D7A74736D717673726E666E6C686D6D6E6873707B6F6C666A767072757371766B65696E7669746868667268707373757671786F706A6E6F6D6F757B6C6E6D726A686E7070727A7B8672746F6F6F75706C7470797277757A7A786F6A717166646269757666677174748379736E6A7379726B6D74746D71757675666D6B756C6D7575717470747577727A767C696B7478766E71777779766F697467676463574C7177797A787182737A716A6B797F7C7673727E757E79737375787B6F6D7177706C746B6E6A7975736D6E7875756F71716D7272766F76757A7F7E7F817A7C858A73727E757E79737301FE8462070718406B646363616671786F6861645C6268676469666C7172686D6D6A6366757575776A64645E696F6B71756E72756E6A646C7172726663717477756F72777B7768716C6868696D78686D776E72706A6274797270727870757573768381747C6E6869626F646C66757179817C7C75797879797C786A716D6A6A7077666870756F6970737171767A6F727C797B76706D7172767471797A71706C6C6F6B605F63585D4C7775807D7B737A73736D74777F77737778777A7A887674727175737176716D696C7076756E757B80806B7971726C7171676B707075796E77757C7A838084828178777A7A8876747201FE856207071850796E6973796F797571686F73696B6D74756F646A7169676B6F727074767B76706463666471696D67655D6B6F7171727479767579706876768074716D6C6C6A69646E69706C6C71706F69747A6F7675726D7E7777756C716E7A757B737B73686A66656C73686F75717D807E77687171786F6C716E7671786E6E6B7176716B6A776F76776D706F74716D78786A717374786D70766F6C7C726C756D6B676A6363496D686D6F7171717774676464797778767C7E72747E6E6D7E7E747175766F7075666F6B75747C716B776F817870676E6C717071767F7777787B7C778284807A807C7E72747E6E6D7E01FE8662070718607173626D696C707878666D6965656D6C6B6A6B6E71696767716A71716E6C736D716A6B6A6A72736D6962727070686D6D6A6E6C6D656D69777275786F71686B6C67776F726F7B66707D73716D6A6C786D74737078767269778075706B71706A736D72687B6A7670777773796B7076797D776E707772706A6966666C6C71757A686E6E74767672766E757873726F737975757074757A7B7A76736E68676764574D6A75797E76787C7C7472737E7E82877E7D787A73737776787072726C77736C7070716D7370707570716E7B77746A686D636A787C7673777A797F82837F79827E7D787A737377767801FE8762070718707A737974747677787D7168686A70716D6C7272706F686E6E6B6D6D6E7B7469706C656F6875756B6D626A6F78787066666E6A6F68697370806F74767675726361637269686C706E6D767271797372757D797D7674696E767A777D787683726F686E6D696E666A686E72787A73717878776C6D727082746C757874767C766B7070726C6C65706B7976747A72776A70747975716A6C7176726D7A6B6B6064585B51707B847875727871736E757873857F76736B7671747972767679676D7173757471746F6F6F737078767B79746F6E777579767375717773757A7E7D867C7C787C736B76717479727601FE8862070718806C726A6C6B6A6D6F6C6A6B6D6466686C6864616F706D696D6977767273716F72666C6D6A6F6C7071736E687D6F6A7070716F7A6A736F6B72666D747B6F6D6C63706D6A70726C72757775746C706C79716F736A7A6E6C6B78807F77717174706C6A716A6766677274747D7174707A7C816F6B70737572726B646F717674756F767073746F7476726C7B7C7A786B6D7773766D7375807276756F6B5F6662625B4273796F7D807F7E747A7174787C7F7B77777D7B7C7774757577716E777B706B6F72776F6F72716E726E66757376706E766F777977757C80767A757B80847E7D81777D7B7C7774757501FE8962070718907977696B6E696C6C76726C6C666B6B756E74747A6D6E6E757A766F766D7270726B6B646B6A6C6967666B6D74766C6B6A706F7D706C706D72736E7675786E6F6F696B6E6C6E77716B79747B766B6A6F79787873766F756C6F7A76786A6E6C69726C6F7A78706976767476756D6B757C8271716B737A7573696F736E6E73756F7374756E6970737579787E756F6F73767D776F77727876736E6A6A66655F58524B7072767073737873767176827E84857E726F7A76757775757A747676786B6F736B6B7172717473727B76787774737B726D746C727775767B79797B817E7D7F7F726F7A767577757501FE8A62070718A07870737574757B79777271716C6A69777A71746E6C6C696C7274707173756E736A6A666A736D706A6B706C7669656A67696D6B676C6F6E77777B76757561686E6E746D696D77747179756A6C6D6D6B6978756C7773717B767D837B7272646A736864696F6E6875777A7B7A7671697A7D76707270776F6E6C72756B7374736C7078706D686D6A6D76797778747472787A7274727978796F6C6E7271756B65554E7C7A74766D73767C78767675807E767073787C757776767F7978747077716E7372726D7C7570747073727B83767570716C6A6F726E797B7B78877E847E7D797A73787C757776767F01FE8B62070718B07473666A6564717172686B685F656F7D70736A6F6C6168746E71736D6E68676B6866676B6E686B6D686A6C797B726E726E6A73706C6C73717A736F726F6E7068686B70736C736E6E7A706D716D727B7674757F796B7075747B79736F72756D666E63696A6C6C71727783747464737B7C6766706A727475757279737E7C76766A68716D7270716C787E806F6B6769737C737D78787678797278696C655E5155507980847B738083787675727D7C7C7B7D787E817D7E777275777F7B76737272746E6C717473746E747A6F7A7275766C6C6A676E786E6C6B7B7A7D838C857A7D84787E817D7E77727501FE8C62070718C078717370727374727173766D616D6F6F6D71706A706F736A7173777173706F706E6F65696F61676B676F6D7271706C6E70746E6877747275666E7370726F6A6B706D6E6D706E6A6C7C786973656C71747475747A6B69707D838276716E776A6869757173726F777572707B746D757E81706B6F6F746B716B6D716B72747572776C73746F6E77777D7F7E7170696E7B756F737F7C786E796C73696B6A5E5E63477C7C7C7E7B74847A757F767D808079766E6B7A7980807975797573757E756D7470716B6A7276727377727D736B6C6D74776A6E7B797C787D787C7C857D7C80826E6B7A798080797501FE8D62070718D073626D6F70726B7479736F72717679737175707262646A686F6F717471686D706A66686F74686766656464787C6E6D6C717678776D687C697276756D6768646D71746B7780766D67766E6D787972796D6C70736D696C6C7986787A7582757074657268726D746C7B777975656A7D7E7D6C706D7272726B6E6D6E68747379736D6A6D6769757B7C74717D767275697A7C7A7176747A76796F6A636866685B59496C73706F6D73747474746C6E797B7C79747B7F797A7275737E7E787377757A78687473716B746F75716A7E73776F73726F6D73808578767A807578857C797D82747B7F797A72757301FE8E62070718E06F676B6D6A6C736F6C6B716B626468726A696B7269686174726A696F6C6E6869707170686A6E6E6C6D6F717671786B6B6C6A656373726F767270778576706E67676D736E6B6B676E757578767069727570787F7E6E737772747C6C6C67706C716B696571707674747779756F6C7E7B877B746F776D717274736E707376786D6B6C7273706C6E697371766F7B736F6E6E6C707372787A726C6D706566695C5347797C777774737C79746F6F717A7F7D797E777374767B78827C7473736E6B6D756D737276767B7371746E7A767E716F7B73746C70717773727C7A7F88807582867E777374767B788201FE8F62070718F0756B646766656C6B776A726D626E717172746F7468625F6E6D69716F726F6F726A6D60666B686A756F666D79716A6F746A6568706C7B6A746B73766F775E6F5E73716E6C66716B6C7972736E78717D736B766E726E6B70797E7D76797068656E6E6C6E7071706E6E79747A7575737E7C76726D716E75726D6C736C766E7575757770706F707872757A7B75716974757877757773767A7776736C666864605C4676787D838583797079706F7B7F847D75747A837D74757B737B727679756F7376716971746B7278777D7673757776676D7277787979737077787C7E7B7C80848A747A837D74757B7301FE9062070718007F77756D6A707876746B6E6F6C6D6B766E6C6C7171746E70777278777771687169686B676C676D6C6E6E68746C72677474726E70746D6D716B6C786A6770686B6B746C7169716D71756C6C777272747072776C7275736F6F7A7C796B716E63726E6E6D756967776A75777C7973797B79736A716C6A74716E74776E73827C746E746A6C6F6F6B6B7783857473706F7C7F796F6F6C73757B7565675F6567645E4B777E73747A71727277787B7B7E80837C7E808279716E7676737A747D7B7271717772717B7472746E74727B766C70776E7276787A7A746D7A79727C85797D80867E808279716E767601FE9162070718106E675F6B65626B676D6272645E676871607377606569716E7770737174757571766A65696E6B696A6C646D70726B6A69666A64686E6D6D6C6E726F7571716872686B686F71777173776E706E7675736D747F797C6D6F737F857C7F6F7C737563666B6A6C737172737077767372716F7375727A79726E756D73707577716D7272706C716E737178737D776F676E6D71787377766F747B71796868696D6C655A4678817D7B89757F7F8086736E7C7E847F6F777A797D7B7C7C75717076786D706E7C7E7179787B6C70786D727574746C656D6D7279757E797F7779797C7D7B797D6F777A797D7B7C7C01FE926207071820707569666D686E6D6E696D6968666D6A716D6F696E6F676F6F70767B746E65716764606E786F6667676C6D796C766E6C747572716B6D6E74776E72726B6B686A6E6E6771676B7571796D73736C6F7E6F7270716F637474757F7E7B707E6E626561666E7C71777A746F7A807C6A6E72787875716B7976716C7E7469757570686D67666A6A707270737B7F7876706D7D6F7D7D77747578736E726A6C695E5560487170737276717671716D7075797C827C7F6D6F707574757B757276707868747A74776F716F73707279747D717471746E6F6C6C776E71717F7D7A7C827C7F7D887F6D6F707574757B01FE9362070718307774766E69726D717C706F66686E6B71706E6E70746C6F706E6C6D676E716C75707067696B6F6A6B6263677A6F6B686D7372707469736F706A7A7775766B716A6F666A6D686B6D73757172716F6E737374757B7F727670747B7C75786D646B70646864706D7675707275767E767972756D6B726F6573757B6A6F706B76716F6D717B6D736F6C74727A7F716F67717C7B797468726F79736B6E6E6163645D584F706C73767A6A696C6B706E69808582727A77787A6B6C6C70716E767B756B696E747C717071777269796F7F717375777C727677797479716B75807783807D88847A77787A6B6C6C7001FE94620707184075786C6D6B6B6B64717672706C6E6C786E6F7365696862646B696A737D737077696C7073766D6E6F68626A6D756A7372716E6F74637171746E7875736F7269696B6F63736E706E6F79787570776B70776C79756F6871726E75827E6E72776C646C64676C6675776E777777796E7E76746C796B737072746C6F71717B78796D6B71676D717075707B6F7E7B787076757773737A767179786E666A6D68615E624F7D7A7E7D80797E7573787476878188767F7970798676757B766F73727A767174697B737378767174787579717478746D7674767172767777777779837A7887877F7970798676757B01FE956207071850807B6D747378757875706D706B736D777C6E73686E74706D6670676D6D6E6E696B6A6E6E727775706A666772776F72717265696868746B706F69737471676F5F666A73717073766C777173746D6E7675747A7B7D7667707A80757C6F79756A7069746676726C73707B7682726C6E7A756A686D72797367777976666E74767C797A6F646B6C737373727C796F6E6B70767072727D757C777166686066695C5E4C6E72767F7872766E7B7673747D7E78756F727274797D797275757176776F6C79737872756C6E6E6A757474747675707178717577707F707071797A7C7E7B81886F727274797D797201FE966207071860776C6C6768727270757070746F6E70727068716B6667696D686C6F74796D666A6B6B666A73716B6B696179726D6B71696E736B6E6978717875757C73746A6E676C696B6F6F726D6B70776F706B757A777070727A71716F7A79836F6D7575666E6C67696C746F706D78727673766D7579786D6A6D7D7B787476747B6D727B77706C6B6E6E72687072747C747870717475736D7776707772776767666A6457564F726F79737A6E6F737773747479817E7E7A73706F6A766E768274737076746F707371746F6F726F7277717C7D71707373747474746F7B6F757F797A81847B81877A73706F6A766E7601FE97620707187077766C7770717674716C70706A6F6A6C6B6E666D716C6E6B7671727D7D756B6D6E706B6B716B69615F6675756E6E626770726D6D6D706D6F70717276716A6C6A7368696E68716F7E7B73667C7574757B726F777F746D6B7B858073747973686B686E6A6F69676E6B6E776D7176787C7F716970707D7C77736B69697174766D656870737571737A786F7C77736E6B7D72696C706E75797C71726C6D6F676161477A7D6E6D757D7B807F757077777D7E7C7C717875747A6E7776746F7C74766F716C726A6A78797773756C797C7A6C6F74727476797B77757476777E84778079857C717875747A6E7701FE98620707188078746870656E756D756D6E725F676E777872696D7371666B68766E7476696F726D6B6B6B6F6D6A68656F716E757474757D6D6F79636F64706C77787F786C6A66676F6C7071766C727C7470636A6E7F6C737273786F6F74727E76706F6B7070706F72746A656C6774707E7F746B77737D766E7776716E6F6C6F756F746E736D6B6A7068697276727B7A7A7471677176707C6C827A79777276706A67636357594D807C7E7E747C717A76787475768080767B77887D7E70807577716A7A7672726B6F6E73736F777072726C7779786F7573746D7978737876727C7B7B837E7E777C7B77887D7E70807501FE9962070718907670696E686A6D6E756E706E666A6F70676B6B6E7176796A6D696F78766F6B676B6871717C706F696264676F71716B6A6970786C6B6A6F6C7475737668707A7F6D6E676164736F6C7E6E6B7474747D7368776F787068676C86857978716C66686A766D766B707875797A6E6E6A727E72757072766F6F6C696A6C6E786E6B6F7C6E6B727173736F7C7D7C7573717275716D736C6F717B7F796D6B6667616355467A737E787E716E76747A72717F85837B7A7B7D6E7D807A71746E6D7570707A75726F6D726B7473796B6D797170717376736D787673747571827F7681867A7B867A7B7D6E7D807A7101FE9A62070718A0707374787575807D6E6C736A676B706E6F6F70797470706C6A70766E8079756F6D676C666868756C6E6F667079707162706D68676A6B71767E767074736E6C6D66706871656F777C74756D717072756A6D7675706E6D75757B8071736F7A6A6C71717872716A6E74777C757C727A75716D6F7673726E666E68687076817976706D6F6F706B7569747C786E786A667378706770747072757571645F69675D635179757C76767575767B7874797F817C7D7577827D76827579747A757A706E6D72737674736B6C7A767E717977787077757774747A7073747375827C7D7F7C7B797577827D7682757901FE9B62070718B07B7672726C6F6C6A786D7C736D6D7372706B6B666E6B6E6F6F70706E747771726F656867736A6D6665696F727B69736F70707471706D6F6E6D757577776E7067666A6E6E737378747B7C7C767170746E6E756F6F6D706A768081776E727067716873676D67757C777774787472757B77706B76726C6F6F797371696F707675796C73686E6C6B75737F7E7974737273697874776E71797C796D656D675D5E5650797B7E80716E727973687272797E847F8076777C7877787377707873716F78757073697176786D7278687879796368726A6D777874707178737A79837F8389848076777C7877787301FE9C62070718C06A67656261686C72706B6B6D606E6C7F71776F666D686B666369686E74706A6F6D6E737470666D656A687071656D6F7477706F6A6A746674716E767470696D6F69686573727870767370756E64677473727B757C736E7175726C74737071736F647077786D6E716F777D726F706C737A6A6B706E79767072706B6B707A746E716B6B716B7B757F7775737B756F6D797E77747670737A74726D69625C655F5E4873716F6C696369666A6F68727A76747C7D75777578767271736B6E6D6F6F7171717473767471787D71707074736D74756F6A777372776D747A7C7C817E85827F7D7577757876727101FE9D62070718D07074696D626A697076726F65676E6F666C6E6D6D6D706B6C6F756A71757B7371737370706D6A5D62645F6F787174716C7778706B727474796B706F6C7279716D6A6C696C6F7A7376776E6C6D6B6A777270706B74666E747C7B7D707B7B6E67696870757469726B71747C747A757976777E6E6D6F747C7C6A6E76707477836E68656C6C6F6C747B7E7D767873686C726C6D6F7A796C727765686C656260675C4E757F7F7D7C7D787671727578857E82857B757D7675796F7472767279736F6C706D78756D6B6F757785747B74776B6D726E74797B727B797673766F7984837C7E7B757D7675796F7401FE9E62070718E07B776B6F6D5F6D737971706C67756D6F767965726F6B727474737A696F6B6D6C66676C666C706B626A7071726A71737978796D716E6D76726E727C76696C6F7067686B66676A6F6E807374736F717070677375786E707180807E7572766F707B6E6D6A716B74737C75777278767771736F656E767B736D6B667063727472736E7272777372797670767A72716B6E747479736E717576707370756F6B655C5445737175737270737873716F6E7A777A7A79737875857B777D7E736C6A6B6E71726E75706D7072766D7B6F7375776C6F6F6C6C72717278787D7A80727C7D817D8879737875857B777D01FE9F62070718F07C7B78786E6F716C756C686E6B776B706D6E6E706D706F7172766B6B74716C7D716E6C6B6D6D676570656C747668766E727E74676F6F6D6F6F6C6F746C676B6873706A69686E6B757C76737672716D72766F6F73727274787879747370746D6B646F696F6970736F73757F7470777E7E6C6E69777778726776717C6D7A6F7375706C706E756F71707B797B73666C7B797B787672767976706A6361615F5E5950706E79777B77756F71747A707E7E8D7D7D7C758078797079736F727B72716673776B6A7371716F6F726D777C786E7A75726C737B7A6C6B747E7B757C828280817D7C75807879707901FEA06207071800786E60666667666B71616A6A66756E70666871716A6B6162655F6F69716D7372736D71716F726B64636D706D786B7A777570686764717777797A7E74736D6E6C6766616F67736C6D6F7678746F686F70767A767A726873787C7E7A7071696E716A7169706E696E7273726B726C767D7B726A666E7B76726F72756C6F7A76716A6B6F6F697A6F7C78777E6D796C666F7073727377707275736F716A6F5F615A537474767E7F7C7970706C71707D7B7B6F786B767F747977726D7774707D73707671747677716A6C6E7E6A74797B736E6B716A6C7677857474797D7E7E79827E86786B767F7479777201FEA1620707181077706A6D6767656C6B69696A70706A726C706E6065636E6670737373707571736064606C6B6B6D6D696A737A6F756A696A706D64697174757576736D7465676F736D656D6E766F7473726E717874776F686E6F796C706F76807A6D7270746D676B72726D6B747672786E7C736C767475726C6A7270787A7A7D7D737273797B73686C726A6F6B6D6D73747B776B70737574766B747877827068666866625F5C456F7C7B7A7470706773746F6F7C7F737E7A767B786E807676736F7173776D73747B757975736F736A72747F767E7775797978747C7776746C7C78787D82847D847A767B786E80767601FEA26207071820807E74716D737C75727667717375706B696472686E6E63737274707A7E72726C726A756C766E68695D6473747D6F6F6F6F77736D6E677073777F72737B666C656A686D6F756C747F7E776C726C656B776D71727F7A677A73787B716D766A656C70726E6E6C747676757A787370797A7B7467657677736A686F7772686F7378736C7175707A77787C7F7E6E756D728275727276786F726E6B5E63656561585A4F7878767D74737D7E796D77767A7B7E79746F7A79736F767273717F7F7A6D747A77776F6F7374727074737D78776C6D716C71717B73796E6B75838283817B817E746F7A79736F767201FEA362070718306D6B5F6E65677670756B6B6562636A686E70706F6D6E6D686D73726C746F6A72676671696D6E666E6C6176767566716E6C756C6B6D756E776F6B7772706E726D6A6B6B6C69737374776D6D716D6770767275757C726F7A79867778626E6E6E6A60636C79676D71767E7574757470807F777B6D7177716977716F77746E66776D6D6E74706D77737B747C756C706B737577786E787D7B7373707370615F5E59437370737C747678798575756D747A7A74797D7B7B787A787A7A757870726A6B756E75767874756F74726F7A7476796A6F6F747B78797B74767D7B7E8682798081797D7B7B787A787A01FEA462070718406B675564605D656A6970676D61606C69767272665F616B6D786D786D6F6B676B6A6370666F6567696E6774736F706B6D6C7173726F6C7365736E736B676B6B777565726A6F6D6A6C7D79726C787478736C7C71736A6E767B7E80736C756C686C66666B6F71756F6E6F787A7A73736A6E77716F756C716F726568656F727378716A6C707E767C857A7F7F7A787868736F716F6F71766C716E676B6E6B655F5C438077868382747D757C776D717D84827F82797671757C7C717A76746E72756C7673746D767176767673677773786B6E6C6A707375727071706F766F7E7E7B7A7A82797671757C7C7101FEA562070718507F796A76676F717876786F7064686870746C736E71706E67776F6F767C7574737962666B6F6E69646F6C6C787D696D6D6F70746D66736D7366766C737069776E766C6E6B6B6F6E77777270676D6F77716574747674767575817B7472746D6D6D676F6C7271696972798179767278727674696E6E72697173727375727178697471706B74757B81757376797F717577766C7267687475786C69686B72665F5C4B7278787F7B77736F78716F747A7F787A7373777075706F6F737473726E7272767A777270706E697571697B78777273706E6D73757172736F77787F7F7C8586857373777075706F6F01FEA6620707186070646567635D646F7C7070666D726E66646E6F6C686E716D6F6C6E777876646D6A665F626D626F726461686F6F73726B6D686A77677C7477737070716A6D696C637269706E7A737379787772757077757275766F6C7072767B797573716E6A70706A69746E71797372757A7176787475736A727376797471766A6974777573717272726C7174717A747B757374767C7975767B6F736F6F6A676F70635F605E4A70726A7675727A74757477767D817F837A7479777D7D747D7568716F736F6E726B746B716D79756C75727078736C71706E6B6E7A737171707D837F837B8080807A7479777D7D747D01FEA762070718707976796E72727976786F6C726E6F74707368707473696D6D766B627370716A716E6E716C6F5D6B70616C6E727768716A767372706C78697974706E74766B6A6C6D686B6A6273686F7E74777B77787F776E75707B6E6D6B6F767B7577766867626A6E68707774747A707B777373717B75756A696E71776E6D676C6F7C73757478706D716B73736B7375746E656D707B7B7E7A7D807E787C6F6F6A61615E5E5E4C7D7F837F7D72707B7A72756E7B817F7E7B747F77827E7A796D746F6C767476807270727674707A7A7A72787B747578767070777679787071787A81857C7C7B807B747F77827E7A7901FEA8620707188074776D736A716D76706A67706C6F6F726F73706D66676B6D6B6F6B6E706F6B6E70706D6E7571656B6A6C7674717074666F6865716D7270727071757D706A6769686E6969686F6870787B6E70697177746D6C737D6E687371807E7473787D706B626B736E6A6D717674807973707B7D7C6F6974777C6D716E7569686C7077756C6C72726D6C6D70727B7F7372696D747C7671706B7672706B6D6A6A7266645E4B7C7B7D7A74737A77797A737782748478787C7D7C7B78747677756E707271737573746D76787873706A6B7D6D6F717675756D737F7C78797A7F797B83847A7B81787C7D7C7B78747601FEA9620707189075696A6C656A656A75676E6C64676C73706B70646465716A65716E6C766E68756D716C6F656A6F6F67656D787B757170787C72736C6F6D6B6D6A6D6A726C636A6C73706F6E726F72746B6D6D67717878747A777675706D7B7E7C737271736D736C6871706B72736E72736D7F777A7476786B6870756F6D6C6E7D687C797177726F71716E746B777B777677716B6A71796D6E75787A767D76676A6A6A6560584C7674747C706F766F767C7B7B80787A7E70767E797B75737875796879737471767670697678747169767578707470786D6F70807F747A717E767E7D8982807B7F70767E797B75737801FEAA62070718A0756C656B666B756C6E6C6E6A626F6B71706C6B696B63686B72747A716C6E68726E646969726B686A70676C716C7070727A6F6B6E65656E746B6A7A78766B6D7166615D6771756A777F6E756D75757B70797971807C7A736F79777371736E6870696A67706B696F73817A777468697480746E6C716E777372726F706D73727272707A7475707273757A7A7A6C6A6C72766F6E767C7D7574706F646B6E65615B4D7D80817D757471737C787272798A877D817C7D747B77787B7F727676776F747172706F76747376717A707A7977646C737068717C787A77787B75777A7D7D8685817C7D747B77787B01FEAB62070718B06F6D6C645F6A6C696864626A6D6E6A6F6A6C6C74686170716C69676D6C6D6F6C7267656A6A646B726F746F69686C66686973716A6F6877787080797572746E726C6E6C6568716F7173716866777776716C6D7970797470707183787A6F69666F656A6E7A73707071787A787A717576787473707678676C6E70797766717A776F6A71716C6D77737077787674726A7172706F83827574776F6D736F61665B5D42747F8073757B7B777D78747683857E79767779776F7F766C7173707476747277767374726C776E6E7B757C7172747471717076787877777882777F837C82857E767779776F7F766C01FEAC62070718C07270616C626568707069726463676C69686664656A726D716A696A6A6A6A776D6C6F6F6F716D6C6C66676B737677736E716F6E686D7171796B6C706F75636F7570776C6B696C67696F6F6F73766A707C7F79797E747371757E797274717171716A6E706D696A6A736B72727470737A7B766C7173776F7B7B736D69727074756C6D6565676F757476777A766F71707A7A797A7D7379757372706D6A6961605A4B76777C7E707278807B757571778080827E72747A7E7377787D7B78767C7A738079776F6D7572757572697770766A6E74717A79797478757D7C7A797D81827E817E72747A7E73777801FEAD62070718D0767371615F696C6C706A71726C666D6D726E70696F6A64726B6F6E786E686C736F72636E746F736D6868686A75706B736D71736D687176766F717673726F6F6F67656A6D6A706D767B79716F7470737175767D7D706B7271727573747778706D6B6A6671766F6A7076756C716E737177716D7379736F726F766F696F6B726C6D6B6E6F746C77747A818573766E73716B70707975797878726B6C7267655C584975696D7877706E76736D6D777C7B817D776C7B75758178707B706B6F6E736E7B6F7972687371746E746B7D77706E6E726E6F7177767778797874797777777980776C7B757581787001FEAE62070718E0796E6C715E67706E726D6A686A6A6C746C6968726E777472676B6D6F6C6B686F6E66716B696A70726D686F77776A6D6D736F6E696C7070757A7475727567686F6C73736A6F6B676F756A787B736E746F6F6D7670717B7974807F767378716B6C67706B6E6C6E6C6C7076797D767977776B75697570776E756A706C6B707C71736A6E716C6D6E71777B7A7A706D677470777A706F75796E716A6F6A67655D57497D7D847C7B8078747E756F747D877F7976787F767978747D7C73727671757B736E74697277756D7175737A766F7476796F66706C6D776E78747B7B828084867E76787F767978747D01FEAF62070718F07D79747168727372766B75746B787C6F7B6C6A6F75716D7367706C6E786A71726A626A6F756E6769656A6D72736B686F7372736A72756E666872737370776C72716D706C74756B72776E67706C7072767771747D7467717A7D7670706F69646468687076727179797B77787678787973666574757D73736E6F6B7174727874726F6470696A6B6E6A787C7674737472767D7A7B777977796F6F6F6568645F53437267727D7D807A77827574797C7E7E7C7E717876747B7981786E73757A736C706B776E78727274747C6E7A7A776C72786F6D73767A766E797D7F7C837C7E827F7E717876747B798101FEB062070718006E6D5D696E6465656E6F6A6664786C72746F686B6D6B6B706A63696F6E6F6B646A6E706970646B68706C6F77706E6E6C756D7B686A7272796C69757273696D696D6D656665666F6F76766973717C76747A7E79836F7A7076787D786D70706F716B6D676A696D727076767F76737475827572726C777370716C6A6B69757575716C6566666C6D70737679796F6D6D73767071747A787E76766869666B62695A486C767B7974747B747B8174777B8479807A7C84727F7C69687B7177747A6E75726E76717273756F6F766C75757B6F6E71736F7374767A777B7E778381777775787A7C84727F7C696801FEB16207071810686559605B57616565625D666C63666C6B6F6C6A6960656A6C68707970776D6F6E6C6A646966666965656D72606A7173776F6E6C776E6D6E6F716974716C6B66656B6763706E737B7D7A6E7677777A73716F78706E6D777379807A6F6F716872706C78766E717872706D7C76767377726A69706D6871747169756E7669767272736D756C73707B757B75797873757A70796C71706C7579776A6A6362625E594B6E71726E6E757571737178727E827D7C7D747171827C72737471746F696E716C6F7278747772767776707676766E71787672717376766F797E797D8684837A7D7D747171827C727301FEB262070718206A6D6B696368746A6D696A746770686E61676A6974696D63696D71737674706F686D6D6F727067646B7568766D63676C6E6C71756B736D7171696B76736D6465676F717B73746F74796B73686B72766E68727B766B7676807E857F7777726E756D6C64657071727874717175686F7272726B6E7B7F7B7A6F7072706D6C767371726D6C756B726E6E7878726C697367737C7973727177706E696B6267656253446C6F727C70696F6E6F686B6B7B7D807B7B7672716E79726F7772757B71786C7376777575706F71747674707470746D796C71767F79726E7778727683808386857B7672716E79726F01FEB362070718306F6E666E6B72717572676F68666A696D7470766D756D6E716D6F6D6C796A6F6C716F6E6A6C70676766666F7A6D6A696E7275787260756F6E6D6970717771616B6468677270737071727174706E7075716E767279716D76727673767C7574716E6D6B6C6D67686D707074757A7172797D736C6D6F6E72717078727074727B736C6C737775706C716E797D70717170787A757077737476747871696E6A615B614A8179807B83757C87847C6D797A7C807A8275747979777B7A7472756F776D716C7A7E73727A776D74736E7D77766F6B70717079817075797D727A7E877C827A7C8275747979777B7A01FEB462070718407B776E706C6A747975686E72706D697170736F6B6268736D6A70737878736C6B6A6C6D65706F66666465706C777472726E787173676A6D726B737C796E6C6D6A71686D6968746973707570797173796F78776E707675717976817D7574706C6C6A706C726B73716B767A7974707579766C6D6F6A6E736F667073737376717378787073766D7273717373716C6D728074796C767979797676736F716D6657594A747B777777737A7170776E7C827A7685787A7C7A7E7B77787674726E74756B7371726371727982777B75767D76757170676C7171757A707A7D807D8483817F7C787A7C7A7E7B777801FEB56207071850736F666C676D717D7C686269676B676F6C6C756D626A6C6F6F6C69726D7262676D6B797676716E61696872776C74716F6D7572646F6C6C71726F76756E69666E6B6D707174706670797D6E7370746E69697275707B7575737C7A7C716C69656A6F6A70747C717A6E79817A6D68727885716E73707E776F6A6E726875797C7A716D6C6F68716E77756D73736E6B6D7C7971737B79777477656C6A5E655C5A5C4C78737A7A7873797473736C78747A7779807A837E7E75787474747077716D6D6B6A71787C6F6F73707A747C7C777576706C74707779746E7373747A7E79807C83807A837E7E75787401FEB662070718607B6F6E6C716C6C726C6D666B6877706474686A71706C6874746F737072716F716F676D6B716A6B6F66636C7A7271706A71676C6B6E756C75746F797A716C69636A6C6C707271717974816D736D7178736F7673776C6B6F767B7B7A77756F6A60646D7178757677787C7A70726D76727872676F75756E697175746B766A706B6F706E6D6E706B747578797170666D7A797E6E7C7A776F6F6D6972696C655F614D797B7B7B7270737976747D767A777778776F73767B787E7577756F787172727278746F78736E737A7A747670706E736A7479777773727377777780807F7C7B81776F73767B787E7501FEB76207071870716C666861676F6E716C6B6F756E6B6F6B667273706B706A6E7170757A716D6B656A70676F766F6F6B6B7571696E706A79706F696F7574716A6E767B716F756C6D7370706868656C717770666D71757474767B7A71696B74707973716D6E6970726A6B77716F6E79727B7C7C79777B7B79696660716E697371686D746C7E7577706D6F727276787C72726B696869767C7A7775746F716D6C6F70686D615C5E4A787676747C7B7978756F726E757981797C75797B807674767B7171727C7B74706873787775747B74726C73746C7674766C6C7372727875747976757C7F79827D7C75797B8076747601FEB862070718806F736F61646D676C6C6D6D68676D656E6972676B6E6C696B6B6D79796E78756C6E6E6D656D66686062687274716C6D6D747A786F6E736B726C6F7774736C6E656F75726F6C6D6E7A7E786A747372727368786B7973746D7F7B7C68707468666F6C6E6C6C6D726B7379817570767C787871686D69767171756C7070767178717270716B6E69766D7D7A707076686D6E7576716F706E7D7B6F6A65656D6C5D5B4C6B78767876736E6D6D69666F766E747578707B72707B7082786F6F74767070766C6F77756F74747175677479747371737270717471716A6E777E8383807D828278707B72707B708201FEB962070718906E726A66666B7671766C656E667068726E6C776069646B6A6B736D73717B7370686D6B676A6666686B6A6C7E6F6B676A74756F6F7168696D70756F6F71736C67696A6F666F7265767A6F68737B7779777774787A736F6C737576716C78726C6D6D736D7171726F7B73777C7A7475787B6D707170776F6F72767072726E757377696D6E6D7874756D6D8477766C736E7D7570747D7D76756E736965596655584980787E7C827C7C79766C686C81788487807A7879798174727B7A7272767067706D72747372706D7A767B757D807372726C6E706E76786A737E747781827A7D8E807A78797981747201FEBA62070718A0726E676B656E6D65736F6A6362626B747674726C6B686C67786F7176777167746C6C64666E6F6D666A6B65757A6C6B6A716D726D676E71786E766D7E776A6C61666E696871706F75787571726C796F69717873726E6C74808478706C75766C6569676F6A6C7279726F7B73786C767776766D766F7173736A6C73767470766D786F6F75726E6E6D797979746E6F656E77786C7274767B7D77776C6C6B5E595A4B707A77737D77756D73766D6E6F7D77748482818275756C72737771797071717173777273696E6B717C7474747572746D6F6F7271777F7579777E80847A7E797A8482818275756C7201FEBB62070718B07470696F66606E6E7B6F6C676769636E716E6D6D63616F676F726E72737174766E6F636E676D68666F71717A707265706C6971766A696C72716B7677706B6B6A6E7469726675726D7472746F716A727073757A7A6E7576787876786D7462636B706C736E7375717679747A72797879806E696A7472766B69727779736E6C706C6C676A6D6F6F777A7A7D7377696D74737D7C72787C757F6E686766685F5959506D6D6A756772766D7A6D6F737A897C8173737D80787C727373767172747370787976727173767E77726D6E6E7372796D6C6E7074797A716F787E7C847C7D7B7D73737D80787C727301FEBC62070718C0776E6A707274776F74706D65636D767B70726D6D6A6969746C6D6E707273756E6D6D6770696E796F67706F727C7A796A6B706F6E676C7170717772736F6C6F6A72776B69697971777F72756D6D7076727071737D726C707581766E6A71736C6C69686A76747075787A7A73706D6C7D767470747072777D74706F6C696B786F716E7063686D6E7073798682756D777A7676727972776D798077746D6558575A4F777A757B726E736E7C776F77727C80807B787576757A7670737A717671776E6F706D706C716D717A79787D79726B676B70727C70747377747C7E767D78787D887B787576757A767001FEBD62070718D06F6E6D6B6A6D6A6C6D7470666671707D7272676868676C6F727472746D6E6A6F676B6871636A606961636A75706F6E6F6D666B6C706A73747877786F6F6C6E72696764677373706E75777B6A6B75726E6773777D7A7066747C7F7D7375696B6D67766E716B6D757376797D777573797A72786F73736D6E63736B7473727479786468697077767A7B787B706C70697A7C756E72707777736F736B5E675A5A6154747473747A71716F716C73677D7E7D758071727270747A7D7774757178737278706E6E6D6C706E74746E757476747D7272727478767A78757C737E7B7C807D848071727270747A7D01FEBE62070718E0746E71706D63757176726E6F6969646F716E77776D6B6363666F6E71706C6B716F69716F75716B6677726F726F73766B696C7971706E736F6E687370726C69656565656E717274737F6E6D6F797A77726F6E7176756F7B757573716E70776D696D6F687071706F76757674776E7177746C6A727A7C6D6C6B776E6D7671716C786F7A70706F717A72797D71736F6F76776E68777A76786D6467696B6C68625B44717273787175697176747777807A797578727C74767275787576717274736869727570757372757378707E717C6C6A6B6D6E797573767676838081817D837C8078727C747672757801FEBF62070718F0736D6B6C6266796C70686A6E6D616C726A75776D736B6A6D6C76737373747275676D686369656A65665F6E71746F6D727372726D6F6F6A7177707076706D6D6C696A69686C716E76717177776E6F78736C6C787C736E6F787F807572786E6D716D76726F706C73797B80786F6F7B747172676F74736C766F706B676A6F6C6D6C696A6C6D726F7573777B7A766A7C75777279747673777C766F6D626E6961584A747F837672766A747B746F7581777B73766A756A76766A787B787277757270776E787178766C757070707170716C7874727473747A7E766F7C78788082807377766A756A76766A7801FEC062070718007C7E786C626973696F6F70706F73707775756A6D6372626A6A6772717A71707171706C666F6B67646165707B796F77746D736C6B677668746D72786F786F6F6C6A6E636E656A6C726F706871716F787A6F7979807170797A8181786B696C6D6D6C7374736D7270717681756D6A717C75706D6C6B68717A7D7473696770707876766D746F68767576797E7875696F74717072727B787C746D72706863655D58456E7A7F7F787C807B7B7171737A7B7C7B7E7D797277797C7D7D746D726C7072777278727771707E767670777A7574726E6C6B747B707875737B82767C7C7E7F807E7D797277797C7D01FEC162070718106F6E6B696567706B756670646B626B76716E7671676A71716961706F727366716A71686E746F6F6F6C686D69747868706B6E706C6E766E76756F786F71716A76676E6E7667736A68716E6B767B6B6D726A6F717974706B737F817D74796C6967676D716E697068737577756E72767D756E6D6F74726E6B74716D7477767F78736F7A687C7474747E757372726B687479786E71727280726771696664625D644A6E75756B73737779786E62767C827D79767177737B7A67777C7479787A726F6A73716C756C7276706F6B807676687276706A7278767774787E7E777E7D7B8289767177737B7A677701FEC262070718207B77706C6B7070767071697164697178776A6E73716D716F6E756F71736C7066756964656F6B6965696A6D7676667275716F6A6A69736E70706E7A7575736C6D74706C676B6869767D706F7A736B717070726C737072757D77767E71736D666A686D68756E74737B777E71716D75727C7873747272766F6871767375756F796E6B635C6971716F757C84796D6475767B7D6B7A737871716E6B716F6D6761564D757C77757C7E7A6F756D736B787D82847E76737875776C77767074717274777C7379757172706C6F7B737A7675716E6E776A707377756D777A7777837B76757E7E76737875776C7701FEC362070718307B76757A6D6E6F737A6D6A63646B6E7B75746F6F726E67696B6A7072726B6472726968716D6B6C6C68676C6D6E6F696F6F746F6D706F7179666A727668675F6F73797175726D6B6F7A73776F6F737174737A747C71636675777B7A68736D717A6A736F716A6A7074807B72786A6E7273716C767573706D6C6F7471787C7075796E6F6D68726F716B7280797574727A7D79747E717375726B6B71645F5A64574971767573777475757675736E787A867F75797A7B7F84737C73787572706F6E6E6E72726E7074767471717975726C686C6B717772697770768078778480837E7E75797A7B7F84737C01FEC46207071840756E6568666D757474706C67656E726E6B6D6A696C6B6B68726B70676F766F736D6D696C776A6B6662646B706E646B756E6C7174697278747173766A696A696F7172686E6F7475757B72706C70737A836A72707670717876857D7075776C6765696D71716E6F747870767A746E77767F6B636A796F72707975787576707179726967687074767876748071766D747278766F797B79737E6C6563665D625B57496C7376666E697B74786E6871737A787A7A797478817971727977716C6F74707372757A7472727877776F767B6D6D716F766A7372727E7675757A807F857180827A7974788179717201FEC562070718507C7778707373757977717A7072707176656E7170716D73756C747677706E686A6475706C6F6D6C6861616F6C716B706D767470706969707274767778776A67676F6C67676670746B7D727A767C73777B74736F7B70747079717674697772756A676C6E736375767B7879737577767A7771666B736F767070726A6F6E6C726F6F706D707B73797670777377706F7679777470737174807668646C6C6B695A55466268666D6F6B6C69706B6D7574727772756B767B8378786E767A7775757067736E726A756F6F7074726F767E797968737372756E737A777E8377787F7D81787A756B767B8378786E01FEC662070718606F726E6B64676D706E6B6772636F636D6D736F6E766A6E7070727872777667716765676C7166675E696D6F7B716E6C6A646A6E7271706E746C74737268696F726C7168727075686A6E74696A65717671767C7E75716B6777788172747570726C676C69726974747677787B766E7D778077686769756B6A70746F6E7172766E6B756D6D7071796A6F817776757372767276787076747C77756E6D61645E615C45756F777873748072707976797B81807C797478777771757978706A75776F706E7B79777673666C726F70787A6E7270746F6F797271787B77817F7B7C79847C7F797478777771757901FEC76207071870726E707874727073786F736E6F6C6F6B656C6C6F767369696D746E70726C6B6F666C7372736D6B6A68686A6F756F6A676C6A6F6D646A726B737173717A71707571746B6E656B656C747077746E73727970776D7469707979808478757A6D646564636369686A736F7A737073716F737D7474777574706E69757970766E73707969706C6F6C6E7172757B7C736C737970757577788079767270726D6D5A5756487071737167737371776B696F73777E6F7E69756A7F71727974797170735F6E6F73767877787D7B74787277766F6E6A726C656C75757A727579767A8483847E867E69756A7F71727901FEC862070718807C7769616B6C6F686F6D686D707369656670696A6670716F7471737278786C6E6B606B6A666B726865666D7A7373766E736F6F6D6B6F747475747270706E6B676B6D6D736F7769747D76706A6C707F716B7072746E6F6A7D7A74706C716E6C656764676F707975777F8079746D7C77767262697477757776746E74707B74726C706B716A7076787979816D686671726E766E737B7771786D666C6B725E64694E7069726E70707276746F696A797E857775737774787A7A746F6D6E737674787370746E6D747670666D687472667377777075747A6D6E68757B74777A7D7F808575737774787A7A7401FEC962070718906968606069746C7374636C6D6D6D706F68656366666A716A6A6C7670736F6D726D6C686C6F6E6A6A6A656B6C716F7771716F666A69686F6C717570717369726A6C756D6A65726B727372716D777272756F7881746D6B79807580847373706C6E666D69706A6C6F717C847F74757A797B687072716B72726973776D7777777774646E6A7075736C737976726E6D677F7D796E75706E77777673685D6467575D4C69787375756B7B767D787A78797B7D7878747B7D7E766C727D7C6F6C7573676C6977757F76756F6B786D7273716D756B726F7577777A74747A7B7D817B747F8078747B7D7E766C7201FECA62070718A077736C6E6A717074716C6D71706D6D7671706F6E6A686D6B696F6F7079746C6B6360726A70736F6F6C67727871766F6A7370696A72756F6A73746F6C6B6D6B686F6A6E707A76707073716B766D717175707577767774777C7D7C7A7072726870636769716B6B6D7676787B746F7577806B73736874787369756F6D71707B73756B73746F7C7278717A7377706E76717A7175686F776E6F6F6965686366605C45767E797D756C717074706E7279767B7F7A777F7D797E7B707C727573766C68726D75766E73717573787280756E6D69756D6F77767275767E79777C82778387897A777F7D797E7B7001FECB62070718B06D6C66706B6B6C716D6A6F6B6A7276716F6F6E6F6A68676C77687271716D6A6D736E6C7269696E69666B686D72716A70716572716F716C747A7C7B78796F6D63676F686E69686A727D7779736E6C777379767276696A727C7A7E747877726C6F7372706B6C6A7673737B6D757375777E74746D7277727367696D6A767475716B6C68736E6E6D6E79787C78736C787577757A7C73777D7B7776645D66615B54487874766F7171767673746F6D837B75797E71736F7D77757B757479787367716F6F74797571736C6B72747672747477736C70707E79796E6C77757B85807B7F817E71736F7D77757B01FECC62070718C0776C646B656E6976706A62696A6C74736F686969687773756C68726E706D706F6C6F6C7474756D62646471737178786E6F6F6C6C71796E6B6F6D736E79717071686E62726E706F6E73706F6E6C727A756F76757E73717074797A7470776A6C66666D71776D757176787778797770727B6C6A6F737976737C71787876737A73696E6B6D76797375727776777565617076717479757A7A766D667069635D605947787A7E746F6E6F767A77716E797C887E767775767C776C757B76737B6F71717370706D6C736F726B72657173706D77746C7578717276726D76877E7F7E7C8183767775767C776C7501FECD62070718D077786B7065737B6F6A6C6468696D656D706F6E6065646D6D717268706D72686F66686E70726F7169696B6C70716B726F6E75746E6C6C737172706E7575776D68676969636E727173777A77736C767676777577746D6C6E767482716B6869666C6B796A716C7B707C7C7E787678706C7775667170716C7071757079707375727070726D696B717370707277776C7074767D797B77737C7979706C6966675C5C4A71726C6C6D757A6F7671716C7179807A76757476777A6D787174736E7B6A7A7671797771737579707B68786D6B6B7677746F6E746F767475767A83857B75798676757476777A6D7801FECE62070718E0756F686164697070736D6F6B6B726B746B6B706D6E666968697172726E726D706F6B6E69706B65626B6F70727371676774746D67686E6E6B7070777B78686E6A7267747572766D6F646E6D787A807872746F76746C6D69767C807E6F7173696A6974736E746771746F767876707C777C6C626A757268716D7B787471707772776C6F6F736F6E7774807A6E6C6E78746F7E787877767C7572676C666868615D4A76727474736971707C6E73767B767E807C7872716E7872737A78727672736F73737A736E656D6D6C7174837D7A6F6E71736E78727778727274777F83818278807C7872716E78727301FECF62070718F084797B716F6A7675746B7570706D6A676B767371706D696569706E6E74726D71746B6D647174706364716F776D706E6A6D706E7076746E7D767276726C6A7172786D6E696A69677579766D70716D73757173797A77767075747A6E6C716D6866696C6C7A75757578736E727B747878786E6D696C74746C6B6C6F717673746A6A6D6A72717771838173807474776B787C7F756C7570746C79716C706B5F5B545072747D7B6F7577757B787477777D7B737674777280776E7A79777874716B6C6B6D747D7B70737473766A76797275716F7472707A747E7B827D7E7A7C778279847674777280776E7A01FED0620707180070715D6C6A7372736E6D6A6C69686B746D73706B65676674726F6B6B736B6569626A6D6C6D6F6C6B6E666E76767365716D69656E727A776A6F6B776A706C6F786C6C65747472686E7C696A667971736A727A7480706F6E737E807A7A6D7566726C6F6A6B716B6F7B7573787A6D767D7971636A73746C6E6F6675787472777A737068716E706D727877746F6F69737D7C746E76707B737A716E7065675E5A584C78777A767D776E737A786B726E76787F7F79746E797A6B7978796E707377707172776E6F706A7275716E8480736F6B716F71737776776D707474818C828183887F79746E797A6B7901FED162070718106D706A6F6B6A6B696C6F686D656E6C6572786E646D636A6F696F6E787F71776E656A686368616E6A68646E716C6D686D7C7474696F6672776D7377726B6E696B697575766C69707A7A6C7176786F6D7574777079726A71777A7D726B746D6B6B60666E706B727072797B8079796F6E736A6C717E746D6F74746C7372727C747076696F706D73707277786F6B6672787774737A736E6E726C696A726669675E4B7472796E70676E6D786A7274777E777976737E787978787A796F6D726E6F74717675706A6E7277707271756E737176726F6D6F79797D747478837B7F7D7D7B7E76737E787978787A01FED2620707182077796F716F6E756F71706E6D6C6F6F747076766A706D717068667273706B6C716E6B6E71727172696961706E78716C6D716E73736C736D7A707576716A6C70636C717472686C7475767371786F65706B707379716B6B746E7579776C7E7271706E706D716B6E6D77747B787A6E7977797A666B73787470746D7278746D76767268636C7264686D70748074786F7478757774797B7B76787670746A68695D564E73777170746C706C746F707083817C747E707D7674726C707D726C7370766E707877717077766C6B7365777F7E726E72746C7275727E6F6D787C7D83817A828B7E707D7674726C7001FED36207071830736E5D5F696D6D6E676E726B6A696C667069696B666F716F676D6E6A72746D6869606B6F6C7167746963636E6E6E6F777374756D6B68656F6E6D7A7B71616A657274676A69716C7276727277756F79706D747A75696D787C7A7771756D6C606A72716F736E7476776B7776776E74737B6E70736F70727D6B6C757D77716E6F6B7069767C78797D747579786B6E73747B7578787C7377707272686A6666605B4F757B807C7C727A72756E716D7677787B7D717878737375746D7C77727072717B7779796F6B66746F7779747B79757A74656A6D75737A77757B7E787A7E807C7E7D7178787373757401FED462070718407F6F67666C656C747A666F646861716B6E6C6A75696C666E7068686F6A7373707171646E70716C6C6C65737670676F6B7770686965726A726978767A726571696F746B6C686E716A797B6F716F7075797477767775706D72797E706A71696C6C7273706D697772726E7778727F7E816C746E6F6E7F706E6D7572777A746B6B726B6E6C6E6C7A7976797F786D70717E79777870747C7A7474666B686D5C5C5544747F8A887F6F7874716E74707E827775767F7F797E7770797B76717A746D72746D74777A787C78696F70767576756E726C697076757678727A7B80847F868087767F7F797E77707901FED56207071850726F6D6B687573767B6A656C656F6E6B6E67696770636C6D747E7C726C72656E686F6B676C6A6C6D6A656775756B6C6C6F77726B7878717A737278766D6B6B66626B6C6674727475737671756C7675797172737D716C6A6E79827477746F6E6C6F6E70726F75767A7C7C75776F72756E646A666A6D70726A6A7470736D75777277707C72716F767979746B76706E777278746B7476747C6C696C6C6F5D5F574C6C7676797875746F73716E747A788079797C7D7774727974807575706F6C6F6D746F6F7574737471766E7777757C7A716F727A7774746A747D81737C80847D81797C7D777472797401FED6620707186071626060686A6B6B686464666461716B6C706D6B6C676A746F76726A76726F6F6C6C67666E6A696B77776F746B75736C6D6B686E6D757173687771706A5F6D6B7077696B6A6B6C7C7A816D62646F796F6E786D70736F7379717B766E7171706668716F787173786F69757B797A7480726C6B6B74726D6D746F71707874777579736772726D70797C737676797372747B78796D6E6B77746B6366646E69605E517475767B7A7479717D7D7A71827F797B7B7975747E7472737873767679716A736E6E7074726F7179776D7A7A78706D746C7278746C7F726E79797D877D7F838B7B7975747E74727301FED76207071870786F6E7278686E7368786E6D676D687870727471696A676B6A6C6F76767063706C646D69706B71686666716F736E6D736D74706A6E6E7B7172707374716F736C6C6D626B647173778075686B7074717072797B806D727277857E757573706C6A687170716A6B707274757A747B79777D7270746A6F6F757671676F72757F746F6A6E686C736C737B717C7670656D7B79717978797773707469636C68635C58517674767B736A6B706F6C6C78778285797E7B77747C75757476746E7178756C726D7573766B7072716F737A787767746F72747A7B717777807F7B798179767F887E7B77747C75757401FED8620707188073746572736D7473796C71746E6D6E6B706E74726867706F706E6F75797276766E6C6E706B676A705E64606D726E716F756D72676D7C6F736A6F7679706A6C686F73656F696E69727474717474737B706F777476706C6B7782837C77777471666163696F7373717477797C82727071776B6D726A7579756F6A6E6E7371807A757071746F6F65777481887B796F6E72746C6776727C74706B69646B5D615D614E74757B7A7B7C757777706D6D7A7A7D77767E7F757678737A787A776F6E6A75787C716D7B77736C73726F7E707B7E747C7275727777776B737F7B7C7A7C7B7F84767E7F757678737A01FED962070718907C71706B707275706B6D6E736A676A717269706E6E6E78706E73767471736E6968706E6D6B636A6D6A676D757272726F727E796F686C6F73797375756D6E6F646976756D6A6B737B7E74747171736E6A6F7B71706B6B737A7C6D7471706D6E6C6D73736E6D666F6F71787B7C76828181796D70727374666669717A7A757772726B7071716B7173757D7C7972666A7377737071767377746D6E6C6467645A5E48666E71726C6A68647172716B7A767E766A787C6F737579726C6F6F7A786D78796E6F747072747275726C72756D6A6C6B6C747A797C82727470707B7C7E7D7B7F6A787C6F7375797201FEDA62070718A074686765645F666671706B666D71666F6969756E69696C6F68726D727A766A70676C7066756C6C666F6A6574706D6B6B716D6565667079717678767072706A75797467696A6F6F787C7A70746E6D716F70797F756D7072727B7E726B6868656E686A6374767276796D7B79726D767C7F7A73736B6E646A6D6D6E6C79686D676C7977746D6F74747483777978716C717373757B75707A737062606760675F594A777B74787F74766F71686971777F7B7C7F7D807A7F7772756C67687780796F797473707077727471746C717674717A786E6566666C777271737D7F837F8483857F7D807A7F77727501FEDB62070718B0626C606A677269706C6E6D7367726F7E736F6C6F62636E6C6E6D6E7372736F6A666E7175736B6A646361787C73706A6D6D7770756C6C70727172727376686D71687375786D6F6D74786D7B7877676F676E7A6F7A676C77787475756A776C68666A6A72736C74797C7B7F737072767778757773746D6A70716D706A72777F776C75716F6E6D706F7570746C736F757D7A75707A747677726E6C6B646A6054564C777D888079737D7D7F7374737F7D867C73727C777E7C777A71707976746D747C7671706B6B777A78766F7276706B6C6A6D747576777476758278777F8178808073727C777E7C777A01FEDC62070718C06F776E7068686C697575666C666A75706E6B746E716B6F706C6E7272777274766E6E716D74605E66626F6973726E7170676C777064767078727070686A69696D696D6B6D70756A6D736F7173756F78706E7A727C7777707588767B7672685F66686F67796B70797E7D8075767572727A786F6B686C6E726C716F70787878716C6E6C69706D7B7371797F7B706F6A717C7B787375707876726D6769615B58554A7672746B74707478766A68707E797E7E8274777178756D73706C6D72796E6E706A71716E6970796F73757B74746E70706A6C73737580787F7771778477787F838274777178756D7301FEDD62070718D0777269665E657371756E6E696E6D7976707671676F6A6E6F6F6C76767A746F6C7064686C6F666765706C766B6E6B707075766F71706C6C716E716F6E7476696C696C68737270677887736E6B6C6A727878747379736A747C7F7E7B6F7168716D646D70786C686B79717A7F756D757C74736473706F6D6C67777C7C716E7277706D6F6F747573757C72776F746B6E76777873707C787A6E6B736D6B6A585458476E767E7E7E747F766D757B757F7B7C7878777A7280777B757C7971747A6F71766C75776D6F64746F79717579756F7171716E7271717276787D7B7D807C827B8878777A7280777B7501FEDE62070718E07C8175746D6C6E6D7263726F646F707976736B656D686F6F67686E766F705E6B646A6D69706C6B6A6B706E7D736E716A6C736E706F6F70686D7579716A6B6977736A676C6D6D6D6E707A7C7A716F7A76777A7279686D687783757671756C6B706E6C6A737879787D7C7777716C736F74766F6C6E787072706C726A6D6D7077757270736D72746E74747C7D6F64737B76736D6E79727A7B6C6D6F666460595E4A6A6F72736D70727478737275767574798075747A7C7C7072706D7178746A6972737974787472736F7E6D7C78746F6F6C7472797B706E6B7876747B7E7C7E84868075747A7C7C707201FEDF62070718F07B75727A7B74767B776E6C6E6C706D7971686264676D6D62666F6B807B766A6D676D6B6F736660656C696B727D74736B7072726A6A7465706F7A72706E6B746B6A6F6A646C6B6B78757A6E7374746E6B736C707E7C727C787C7F7B676D716E7265646B6F7074787176797B7A767476796F707170757770786C7576736C6C6C76706C7368676D7474747778776A6B71797776797971747D7C6A6D6868655A5B4A79786D7A6F66726C727371767A8280758577817E817F727C776D69746A6C6C6C6C6F787673746F7983717372706D7A72606E6F7F767A72737479777E827E787E8577817E817F727C01FEE0620707180078756E78716D6D7478726E726E6D6F787A726D6369706E7263757B7776776D736A67706E6C6A696965666B716D6B7073707077726A6D656D766F707975766B716D77716665686B707C6D74707077716F6F6D6F766C676A7478857B79766F6B6E6B6F72697475737971737076727A798178716F727A716E6B6D6D7179736E656869677370717875787D7B6F6F7370787576756F7A767577716E71626661625D487C7B7575767B7A7473787079787D7F7B7B8085797C7C767275786C7477747979747B6D6C756B6E6969686A72797677727675707D747571797B7E7E8376797C827B8085797C7C767201FEE162070718107274666F6773747B776C68606E6E73706A60677166696D686E697168736E706A686F74736E6C6F696C6B6E7B766C6A6A74706D6B6A6D70726E727B726C6C706C6A70696A696A7072736C7784777772706E726D76747174758483786D6A686C736B73706F685D72757A827D82727580796F6D65656E7371707375717A6C70716F676A70686F7A7C7A787D7772646A767A74836F7774726E6D70767068695D5A4A717575747375756F6F707478837B7880797778727B7A7976747078777079747772726B6E70676E6D776E7673736D73716C70727570736F727D817A8D847F7F86797778727B7A797601FEE26207071820776A67696D706A6967636B69646B6577707069756769666F7B73756A6B736576736B696A706164666A656F706C6768726F72726B7677757675717B6F666B6F786C6E6D7177717D71757778736F76787A75696974696C7577767C70706A676B70696970736E71787A7B7A767866746F736966726D6B7E7669706A686F767C7876716D6A72797772757A7473706A6D7373736E7378747E746C6768686B665D594D7C7A79747774776C6F6C6D707A767E7B777B7D7D7078757D7271727775706D7472727575727A6F74737073707A746E756E707A7C76796E787974758C807E7F83777B7D7D7078757D01FEE3620707183068686766666A6964756D766E6762686C65607266696D70656B6D6D7576757176646C686770736F686A61656C6C726E6D6C706D72697268726D6C766B737070635D6767706775666D787A7B746C6E75726B716B726C6D777C7F8380737871696E68736C7476767B7673797C766F6F767866716775787B6D686F6D737470787A7672696C6B666F747A737D74706B6C756E7B77747A737A7D73726E636A5E5D5E4E676E737373666D72766F6C6D767C7B757C787C7874746F7D78716C726F6D6A716F716F767B736E6E6C68716B766D73797371747A736F6E797E7A757E737777837C787C7874746F7D01FEE462070718406C6960635F6C66687669666861636D6D726A68616F6B6F6A676F73736B73736F6E6F696A696B67696C656C796A6A7574786E70656B6F7379716B6C6B7570706E6F73706C6C70656A737273736F6E7A6E6D717373726E78787A82766F6F6C6E6D6569687071777B7B7F727384717D7A75676F6F75786D72736F6E726F6E716B726E6D6D766C776D727B786F6F6B707D74716E74787973707469656769645E5F4B6D6E6B706F686C627277756F817F787D7A6F707577767F7E767574727B676D716A76737276796D7178727C807B7478766B6E73746E7570747B7373787C7C7E7B7A6F707577767F7E01FEE56207071850817C7B7277746C7C75726E6E707D766F6A686D7272706977737674747473767B6B706A6F6C67676E726F6A756D6879686B6D726E67696A766E706B736E696D6A6A6B6D71757D7367807969706F6E6F766A7678767077756B797E726F7074706A706F6D6C6B66707C78857F776F717377796B6A6B6D6E716B7073657773737B70696D7071707B7C78787C7470646A6E747875807A736F76706768666B6B645A4876696D6D717770686F7077797877757B7677787B7D7A787C7E7B6F6D6E6B6A79767072737E757072786A75757975736C6F7176787677767A807D807F7D7C827E7677787B7D7A787C01FEE66207071860746C6D706C70697370706C72656771706B6B6B6B6C6870726B707672727367706A7370727372696B6868666E6F6A6C697371737670756C777372706E65646965746F6A6C6F70757473746D706F73706C6F7378746D676F7E7F837571707269666475707675786D7473797C7576807B816F6A6A7979727370716D6B6B6B71766766706F7176757B80767878756F73766F707575757E79757265646262655C5A4F7174766D6C746F6B74727174757A837D75757273707D7A74766F6E76777674736F676F6A69797574786C767D787472686F737172747E767A7D7D7A7F777B817C75757273707D7A7401FEE762070718707275686D616E766D706C6D6C706E6F776A66636B6A68736C65646F6E7571726F636D6B65737B7667656670716F71666B6B706B6D6B74776E726C6E72726D6D6F6B6E686B666F76717E7E766F6A6971676B7C7877736A74798379746E6C67686A69666A77717E77767D7B7B7572707D7D71736B786F766E6F72676C7276717168756E6F6B6E73787B7F8075716A777A8079737B6B7077746B657068625F64644A6C7171726D6577717C7173747B7E7A77706D7879798073756F747170737077796C6F6E707A7A7675786F7C6E7174746F76787973767883767877797A7F837E80706D78797980737501FEE862070718807275696D6F7470737876646B6C6C70766F6D6D6A6E6C6A6C686E6F787572746A706B6A6A7172756C6C656C6E726C6D6A706E6D6B656A6C756D7B78706D6B776F69665E646F7369757779777275727C7972767C7F6D7275727E7876727274697065696E776B747B717B8075747074717F6F6C6D7670666E7071766C7771706D786C706D7069716976808076736C737371716E717476737170686A6A676159524D727D7878767080787B746E78818386817D737A7B73767A7B7D787777777371767477686F6F737E76726F776F73636F736C70777C77717178827878867E847F837D737A7B73767A7B01FEE962070718907E6B65646870706C73727372696B7677676B6D6565656A656A687A767673716F6B6D6E6E6F6C6A6765686D6B7379737270656B6C716E6E726F707777736D6D6A7574636D6A6A64677B767473766E7773717F6F78686E7177807776756B6D6D6A64686D6E716F7376747D7C7272787C7473686B737975746F706E677172706C736E6E67747B796F73707D7173716E79776D6B6E73727076756A65676665675B5074787A7772727977796D65787C837D727474737780787B7B7B786B736C6D6D6D73736C776D70706F766F79777675727176766E717872787575737A88817C7C7C7474737780787B7B01FEEA62070718A07375716D676F6D77786A6C6E70717B6F776F72756A716E6E6D696A65756F6A6D7472736562686D686A6F726E696B6E7072717E7162716D756E6C6F767168666C6C716670676C706D767370726B73737572786C7474717278857F737077736C65646D6D73776D7A727574777276797D816E6B6E7671696E7177736D6D717A6B6D696E706870676C77787C716B71757B736F6D72757675766C7167666B695B5A537679777A7D807874717672737D887F7F7F787877797B758079716A707373737970787A766A6F6E7673747D727772747472716F76737A7278827E7881837E81817F787877797B758001FEEB62070718B0707374676864726B6B6C6B696768717470746D6A68626E7370707177776F716E6A686C6D6E6D7669696C727776736B69646B6E6F71696D6A72757A75716F7675636A646C716E6A70817070776E71727A74786E7B7A6A71717D767170716C676E676E6B6C707478777A7A7570696F717C737473736F6F6A6571767269707478726A7372766775727A787B716E7170717E787579757878706B676D6865635A5E4A6A6D717A7371796E756F66707880807C7278766B747974726B6C7A717372717574766D76756E7B7872697A6B797B7570756E72707478757A747C777E7B7D7C8B7278766B7479747201FEEC62070718C0786F68766F6F6E706B6B73696C706C6666686B6C67656365706D6C6C716C6C686B6C686577706B7274676C73726F6D716D7070706971717578777271625F6A656863666B6B73707670776E73727178757671787C747571767783746E6E6A716D6D6D706C697075787E72787170777082706F6B6B73757365736D716F6974767073726F6D74757474797D686B6A77757C78756E767A797C776E6C6866666159517179787E787975717D6D6F6F7C797C7373767B727178717876797A777272706B72707C76716A726C79727A74786F71786F7470797A7D767570737E7C7C84807C73767B727178717801FEED62070718D0716F6B70756A6A6A756E666E66746C716B696B6C71736C7274676C6A6A6F6971717066666E736A666B696F757069726B706E72726C7770707571716C6B5F656E696D6D706974797780746C77726C72716B73787A7070706C77786D71777674686A696A75737571757177717A737B8484776E6668706B6D6F706973757879726F6E7068696C707D72787D787A6B626A73746F767D7B8479746D6D70625E5D5F4B777E7D777D76817B7E7E777770767C7B797B797574737172787670767D75737F707676716D73736D776E77736F767B6A6B71747B75756C757F7F807E79797B84797B79757473717201FEEE62070718E0766D6D685E6D7275776E71706A73686F726D6E6A6F646B69706B6E746F6B69716B6E736D6C676868686F6E756F7B71666F6F6F696D747274706F76796C6F62666B6C6E6C6B6E7276816F6D736B777874747F77766E70647177757E737B6B6D6B6869677569656E6F707C7E7A80767476716E6B68707478767B73716E7674726D727073746E75727173756F706D717F787472776F7C7D756F6A67616657555A4B7A7E867E7D81747976787584838581877A7778777C7774767977787A7F6E7376696A6E747374727D7A73817A76756D686C6C757B727672758077747B7879757E7A7778777C77747601FEEF62070718F06E6B616C656D6C6B6E6F6F6761626C6C687278726C6765666D6C74706E6C6E746C6A6D72796E756767626C717070726D696D746E6774776E776D696F6A6E716C6A6F6F6C75716B70716B6E746A6F6D796C71737F716F737A7F7C6E67766C6C6963677074787279737274797B757A767D6E6C76717A71706F6E736578797D6C676B73716E6E6E747F7878707C76756971777D797778726F6D6963666F635A5942767D787C6D676D6E766E716E7E7E838274767C737A70717B746C7474787573746F73707667726F6C777176726E73746F74736F73767A706C7F7879817E82838B74767C737A70717B01FEF062070718007C746E746F6F7A707A76786B6D7372747371706A6C6D6A6F766A71676D726C76676A6D6C716F6F7069656B787267716B6A666B6466716E746E73756F6E72746E69716A6F6E716C6D7673737277747179657776776C6D6A717879737674777369676E6974676E707C737670797577787A6D6D71736C6E716F78766C756F706F6F6572746D74707B7F7F80746F656972757B757876737478776A6C68686356564D717478736F796F7577716B7374858279796D767275747B7A7B867C75756E70726B706B6D717175707D7683746E6C6F7474737E7C777B7B7E7D7A7C807A84887F796D767275747B7A01FEF162070718106B6A6766656C6C686C5C5F6565716B706D69666E66746A6873716D6B7E76656A6869686A6C626B7072696973746B7178707C6A696A716E7777696E776C6E706D676E666F6E7B727678656E726A6C706F7E7975796D67727A777B7B7173706F6A696E71726A6B726E7676767471747E746E767973767374726E736F736B706E746C6E746E707379737C76786C71706C7678766F72797B78766B6B5D64645D5C4B7A7B786E6D7577756D6F766A7A8483858378807D7475807A7A7674756B66716F6A73696D6D706F75807579817E716F6E6D6B72717076707770787681827F84808378807D7475807A01FEF2620707182071786D6B6C6D6D71676B6B6566686E79706473686C6B69686C6C70766E696A6F7270716D736B6B68635C676C68716F75776B7469656D6C736C7375797B716D5C6B6D69746A746D7476776D6D6D6F787B7879737670707371797D73746E71716F6C6E69706A716E787A757B6F6F797F7B73736F786D706B7570696F747070696F6B7375706F6B6E74737A706D72707D7F77747479747273736F675F6E5A5959517A76777A737D80787A757772757A7A757D787D817374727D7C7B7770746E7170666A6F7171787473776C7D74777574747D6E71777075727C74717782867E7F857D787D817374727D01FEF362070718307561656B6D66716E69626A655E64756D686A686D6963656E686B7470757A6A66696B6F686F77736C6A686C706C6C6E736D6F716B687073756D6F7C73726E6C66646F6267706D6867776F7B736E78767B74757178756F73777F7B7175746A616D6F736E6E6A747676757F7D766F6B7476706C6F7574706C6C69726F737071797376706871716C7273797F7175716B7779807871777375746D66716F6C625D624B736F75797B827C807A7770787D7B837E787B7D777A7E727473777C7C76686B7475706D726D6E72767C6F787C71726D737475787A78776F7879727881837F7D85787B7D777A7E727401FEF4620707184079736D71636471756B646F6B65666E766C6B6A68726B69656C7475707170716C6569636B706C656467677478766C706F72706C73727168727370736E736E6C676D706A6B696F737675706970706C6C6E7278727C706F6B6F737B776A727371706B6F727D717372757B7779767377777F7A6B706C6A6C76737171717174767270766C6871756F73707B7D70736B697478766B6B7B70767679746D666468625B426F7471777C7772676C7574757E8077777977756D707779786A76706F77777279746C717172656F766E707A707C7473766B6F7077747F7D726F787C85787B7B807977756D7077797801FEF562070718507C767576717378747A726F716A64686D747C716E705F6B69776D7279776C6F7468686C716F6C6A67706D777B7A746671766C686D706A676A6E6B6C6D686B6E6F6766686F717273737B726F7275727872767476787A7673787D79786F706C6C746272717274766C737980747D6A6B75786E686F71777C757C787374717675726E6A6D66686D767D737574796E69736E75666A70757A76746D7069676961635B4D6D707879787A7F777C797576817C7A7A7575787B7D78797C736B6B6D726F7478717B72756F736A6A73727D7B7878706F7672777A797A6E737874777E7A817E857575787B7D78797C01FEF662070718606B636464656A706A64606364606C6D746F676F6E706E6F706E6674766F696B72646B6D7573696E66676A72726D727172696E6B77667473838171786F75676A6B626C637067706B7679706F737767726F717A69776C70717B7B78756F696A6670666A70726F7E6C76757B7479716F767F76676B6F7678736F6E817A787577736D7176746F6B6F7172748375706B6E7B7C766E6B73716F726D706E6A696960694E7A76727A787672747A75727078777A7B797C827A7D737679736D73716E71676F7878707176776F7176757C7E797068726E727D707678747780807D817D7E7C80797C827A7D73767901FEF762070718706E6C6B656B74736D726C6F69626B6A6D6C6F696C6C696D6A6C6D7B78767E6F6B686B686674666E706E6866686D6E6A71777573706D707074697375757269796D5F6D6E70676B6E7E7D777472746F7B706D717A726D6B73717C8172696F716E6C696E7272676B73727A7F7C81706F73727072757170676A707976746D787A6B70707671767375767175717879676C78787B7B7B7A6F7775686C6A6967675F574E76737370716E736B766D6274717B7D7D7E73746E786E717A797C6C686C6E6A6B7075757673747769736F7B7678716C746C747B74787A76767F757A80807D79817E73746E786E717A01FEF862070718807876716C666A71747F72696A616772736E666A6871666A6C7A72736F7376727769656D69726E6968636C757B6F6865696F6670626F776D6D6D71717679746C736D686D6D736D606C78796F736971736F75767D796F6F71787F7A78756B71666663696D72706B7377727974727470757370767175797E6F6F706B6B736F6F6E717769726F727472797674746F6F6F7C73777675837573707172686B6C6658584A797E81797A6B768A8B7276707B7E7674837479737F7C7B867F767076756B6D7A72706C6F6A6E6F74766E757B7774706F706E767D797D6F787370838A827E777A837479737F7C7B8601FEF9620707189074746F6D6572736C676D71736A6F6F6D6C6F76716E706C6C717473677D73726E6B6C6C6E72756D6B666D686E716B6F6E78706A6D6C6E727D6C6F68686C64676165736C7171736C6D777666746F79827D6C797673727370777F766F6E73706E6B6A706E74736C7875737C7A7C797471786C6A6D6A72706A72727073817A7771766A756C6B78707572767E776E6A6A697276757A6C7775776B6D7364656E6A594D7980777A7C7A80767F79757D7D7D777876777A797479767979737975796C6E706D6D7175736F736D736D757C76767670606A767A77776F70747984877E7B808276777A797479767901FEFA62070718A07974736E687479726F75686F626C6D7B706D736D695F67696A7474797A7573766F6C6F6F7467676B6A646968716D716D756E7573676F70766B6E71726A70726B6A696B74726A6F787B72746E6F747D6E6F6E7976706F6F797B80746A6D6D696E6D6C6D6A7273727A7A7E7777707E77857C6C6D7372656B6A716F7870797079747173696D7272717C7475746F71727A747778727672787D6C6D6D64706158584B6C716D7572687269756B6B736E747A767A746E6F727775777C776D7A746C606A6C757775767273717F6C7C7A747068716A6A70777E7C796D77797489817F7E857A746E6F7277757701FEFB62070718B0686F6C6B606964636D68736876686966646E656C6E6A6D73706C6D6B7374746F6F6D69686E6D72666A6D6B736E696D696C7772746F777272766F73716F726E6B68756B686B736C7179737774726A726D6B717780726B6E6F7378756C6F6968686769687B776E787A7776726D707478756F67696F7477727375706F6F78777B7168726C6B6E726F78717A7C73706E7674727474777676797B6F6C6F66665F5C4C7472677276706F7871756E737479788083747373796F7079797171727976716E6C6B69767A746E747579807870706C757573717A76746E6F7C7879857C7C7D7F83747373796F707901FEFC62070718C075706D756F7375757C62646C696465676E726D766F727376686D726C6B6D6E72726E73707266696A616574706C7578747674696F6B706A75736A756A73706A6B6D6A5D676E7B71767974786F746B766C736E7272636F6B717B7C7677706F6F6963696D78656970727E77817E728179797167716F6D7277706F7171726F6B6C6F6B6E777473706E75777B74736F7579767D726D6A6F717C706C68696F61625B487B7A7C867B797B6F6F736F6E7D837A837C7F7D787B75767578786F707A716A72737674787175736E74707878766F6F6E7C7071726F73757A7B837C7E7D747D8B7C7F7D787B75767501FEFD62070718D07870677067666C6D706876716265726D656B716C6B696C6869656C76766E6A72746B6E6B716569706A6670766E6C74777171766C6775727A7A6F75726D6B67716D6B64686874756E6F6F7071726D7676767A7F85716A7173727C766D75676F726367687475767E787D7A737271747C8173686A6A6C70706F71676A7075716D736D73686D7773737A767D7B746E6D687275736C7275797E776F606770635E5C516D747A7573727A7475776D68777D778080797A707F817A7B7B79706B7277757977786F76768178727A7271787272727272716C717273777D7B74747F7C85828780797A707F817A7B01FEFE62070718E0796E66696A6E6E706A706D71676F776F72727468655D60736C6E73727A7171706D6D6E6A6E68636D706C6E7770757171757169696A6D6D72706E746D7368696C6C68696F70776E7A756E727171636F686D75737C746D727E82807A7575706F6B6A706E6F6F727071707570716F75717A77716F6D706E716C7075697578727477706E757D80726F6C727E726C746F7A7775747177737771686D726A6C5B595D4A6F737574706E70757B746A6D7A847E7F7C747D707B7F7571746D6F73746F6F6F6F676B717373737A7977837775706C74716576787679706F74777C7F788182827C747D707B7F757101FEFF62070718F0797672736D706B76776F626A6B7170776C6D72726B606B6C756A6D6F6D726E72736E776A6A67706D6A656E72686B767A7774746E696D738279717173726D6B6C6C7A676466766B686E6E72757471796D737D78816E676A76777B6B726F6E686465727076766A7A74727478716D6C7479716E707973716E7870707C75787370756F68706F6B6D7B79717A76736A7073797671757078767B72666B6C676358584D697070737477707378706F6C7C7C7A7E816E7C727378777C7E797475756A6E7176716D716A6B6D66707376777C7575777B7775727B747E75807B777A83827B86816E7C727378777C01FE0063070718007878767774736E7679707277737577717669667369636B6B6F767C717B6E6768646573796E6C6866646763767177716E6D6F6F66636B75786C727B767270676866696368656E6B717D77797878717674747577766D6B737A7B80767875686C6D68697174736C737A7B796F75747677786E6B6F757A77717172737074767374706874686E6E717C7B7D7D75766A6A77756A78756F70717A7F74665F63605C5A486F747B7976777475737073847D7F8180767A7F757179756C7576667473716F7B6873626B766F787A7D7078776F6A7176797E7F7D6F777477797B78837B857C79767A7F757179756C01FE01630707181075766D786A68717676746C6B6B756D796B746A756C6E72676F6E7B756C726D756E736D6E76776A665D66716F6B6A717375737062706A74706D6D7975746B7275686B6B6A68666B707A71726E7C756E767879707A76777478827A7575747571695F64687874767770797470746F777A7C716D676B6E70746A696E6F6D717971716B78757479697270747376736B77767B7269787B7E7B7772686B6265625F5B4D6A706F776A706D66717271686E7585797776797175746D7177757579777068706E73737474736D6C6B6A7E7775727672706F6E75777B7B757A808081767C81827776797175746D7101FE0263070718207468657065676F6E6E71646D656C6F70757877696862686F6E6D7472746F6B6D6B6C6E667B76736E6F686D756A71706E71686869726D6D6F747370786C69666E726A6F6B7772766E787C6C6C6E6976726873767B757075777B7B77757B6E726D66746C666863787A737672766C7675726C666A6D6F73797173786B70747A77716E6A656A676D74767A7A6E76746F707A7876706C767471776D716B676060594E6A717E6F79757C7B717574737F7B72747E757A77777978787174747C776F6B74776E707571727273726C7573756D717175727679777D7A797379777C7A7A818A7E757A777779787801FE0363070718307C7773706F6E746F7B726F736C6E736F746A716A6C69686B6D746C6F766C6C727669686C6B686464686D687271756C6A6B77736C6E6D73717077776B6C6B6D676C6D706A6E726E787C77756F686473756F777475726F797F7877766C6E6C6E6C706B727270676E6D6B7576737574757779736E6E716E716E6F78747A75766B7277736A6C6D6D757E79776A74707077737E78736D6A77766F686766696157644675777878737773766E7871727D7E7E7874707174737B6F75727B7774767076766E706D7972746C7373787E706B71746F68736876787473787B7C7E8B7B7E7D7C74707174737B6F7501FE0463070718407D6A647068696F6B7264656A606A757B7571686870676A656E686B6E7774787A6F746C6D6E6C68656A6166757667686E70736D756D7B78736E6D6C7478696E6C6F73676864686B77826E6E71787078737179777A6E6E6E7A7D756B687E7374706C75686D68686D74716E7C797E747A76756A75777976706C6D6F726D767E786C6D63696C6D726F7A7D7170717070727F78747B776B757274646D726F645E5E586E7078797873726874746B777C757F7479788675746D736D727570736E6F747B746E7C7271717570746E74747071767A7174717378786F767E7E7C7B7B7D7E7F79788675746D736D01FE05630707185078786B6D656C746F64646969676E6A6B6A736D6A616764687170756B7771676C6976706A6D66686F64686C7070766D7A6D72636871686D6E706C756F736E766F6C6A6568726E6A6F7C75716E6E6C7A787678757A6A707178757B6C76726F6D6C676F66696A71798179707479797880816E61716F696F6F716E74727C727C75716F676A6F72657675747A7874736D727777717A7972767460696F615F605F6049747C797C757578777267676C75767C7B7077807A807477757C7578757571706D717D746B72747A7D796D7B73746F7170696D787877777078757E7D7E7D7A79807077807A8074777501FE0663070718607878726B7470706A747373746A6F6F736A72706A69746C68716B716E767572776E6E6D71706C72666366696D6F6D646B7071756F6F6F6D6F726971727670756F6B756D6E71746F71736A737072707175707271797976716F7A7D7273776B6D69666A6E766A71706F8181726D6E6E76776F686E6C6E76716F7575716B7073746E727573747D71727273766F6C6F777874796F73767679816E78696165626058516778767C71716F6D736F707879797F78807A80757472747D73757175726F767F7779646C6C6C6D6E726E78787A7070726D70727678737772737B7F817779798A807A80757472747D01FE076307071870786F6E6D70716B6E7364716B707371796B6F6F69686A766F716E6C6E76756B74686A68706E6C6466766B717272676F706F6E716B716E7D7E6F6C747167686969667373737074677073706B6D706D726D7173747F72756F7984776F72747071726F7167736E6E6C717078787877756F7A6A6B6E766C727B6F6E72766F70746A6A716D7A7776716E6E727E7876696F6B7671726E737D787D7777676A68575C5749737377747C74756D6B6866747B767B7E73767D7B737A777179716E717372757B6D6C726E6E727373756C77807D7A6D737A6E6F7570736D7271787E808580878A73767D7B737A777101FE0863070718807D716D6D67686E696F71737372716B6A696D6B6E6D6D6371726C777C716E7675696B66676C6D6F67696A6B6E6F676F70706B73706B6B68757570776E766D6F707071646C68666D717F776B7175757A6F6E756D70676D6F7E7F767F706D656C6D66746D726E6F6C6E79817F7676737F7A786D7079797A6B70736D7C797674707171716F75716E6E71707A78706C716B7074717670756F73736C696B6F686055477173787174736E6F7F796F71777B81717B7B7D70747573726C6E7072817874737171717475727371736D77767075717571746E76727474737B80867E7C8180887B7B7D707475737201FE096307071890766D697071717474746D6F6F6B666C6A6A6D746E6E706E7273766D756F6D707467686067696C6A666D6E747672706A6A717271686C6D6F736D72707179686E6D686A74786C7976766F6E6D716F7380766C7576766C7868757B7A76756765736C706A6F696F6B79807A7777776E72736F776A736B727272716C6D6C7D787B6D6E6D6773637A6A6C6A7271727570767D83837073757A7B7A70776B69676563564C716F756D726F727278706D6F7A82787E796C717D817877757179717979796A746F6C70736C70706D796E7873716F6D6C707C7377757B6F737B767E8483758283796C717D8178777501FE0A63070718A06F6E6A69656A6C68776863646F71766B6A7074646564666F716C6C727B7E77716A6B626C7164666769676C71686A626E6C6E67726A75776F7B737A7775676A6C676969696A7476757A767973706D7771727778736C7977767C7A7470746867716D716E706D70756F78797874737E797C7264756E6C6B727770756F7072787478677075716F7472747A7A75776D6B7B777B75707271707A756C67666561535A476F7976787376766F776A6E687B7A7B787E7878757A776D76736A666E777472777371756F6B6A6E7577737772766F72687378767B7177737070737B7D7F817F7E7E7878757A776D7601FE0B63070718B07F7A6D74747A837E7B7378786F76726E68717068676366726D686D717379706E696B616E6E7068616764716F6C6F6F7673727075737D6F73766E71687476716D6B6D6A666B7171777E766F6C6F687D716F7971776D6F7A7478746D7174776B6C6C6F6D7672746C6878807B746D77787E74677175706E736E7373766E7371736D6F716A706D6E7C747474777E71746F7D747672787E76726F7962656B6B5A5A44757A80817E7477767974747778797A7976767A797B81797B7770726E7376716B6C7372757A72797376746F73787371666A6F737D77797380777A8184837F827C76767A797B81797B01FE0C63070718C0777373706C6C736F6E696B6C6B6E7A786F6A6D6D6A666772767372766D656969656D6C6A746C7279736D70727676666C6D7971766D6669726F75766F6567706A666F636D6C7367756D7577716C6B76776A7F747B6E796C747C787A6E75746A68636E67706B6D6C77787A6F7179827A8375666B726C76736D7472716A747E756B706F706D6C7168787A807376726F76787773717B797D777874656A696A605A486D736A6D72727269717D7A6F847D827B817E767D8178747B7A6E6E707674706D6C73747C73716D6C6D6F767271726C6E70767876747175768279767B7E807A80817E767D8178747B01FE0D63070718D06C6B6E64646D6B6E7466676C676A69736D68736D6C7175746E727077706E6F6F716F6E6F7066696C67726A726E6B686A6E6E76736C736B7465737374706A6F6A77796B716D6D686B786D64726D70777875757677756E68707D7D7D7672797169666F6C73666B70746F737B817A80797D776F6E72716F626377677174716D6A6F7170676D6F706F71727676716F74767A7171777A716D73706C696068635A574E7571717C787C72737F7275777F747E8079787B797C7A76757775706B79757474746B6772767973767B6F7C746D707178777073737274767878797A817A79808279787B797C7A767501FE0E63070718E0756873756B746C7A6F6F6C6C6674787578676667685D686C6F6D6A747771696A6B6973746E6B6E6B6E5D6F6C6F6C6D6E6C7A7073757176746D7679786B6A6B6C736C68706B766A6F887F73716F6672736F7470786C717775877C786B686D7469696F6A706E7173757A796D78747780756F686D7175706D6A6E746D747575786F6A726D6F686E7B74787D78766F6D7676756F71717975746C6D6A6365635B584877777C757C7A7E7B82746F757C8084858077797577787070767A756C726F6D71666B6C7077707B727A717678766B706D757273727076787B817C828379788184807779757778707001FE0F63070718F080736B77687673796C6F6E6B646C716A6E706E70746E726F716E727D7C706F6D6D69686A6A686A686466797B6C676D6B706A67746D756B7E75757469726B7064687164706D706C7775747A6D716D7D796B7573786E6D6E758582736D757171706E6D6F7668716E77717C77736776797C726E68706E777A6E6B6F706E717571786E6F6F6E76796C717181766E6671737B6C6C6676737E79726B6C6C6E625A5E4B73767A746B6C70727B6F73706F7874736D7584767678756E736F7574737169746F7375726C6D757674757270736E6E706E737B81727B717A7C7A7F81858786826D7584767678756E01FE106307071800736F6764666C6E6D69616B6E636C746E71706A6D676B736D76676C6D6D766C706A686D6D6963696A696D7A7B79746E6D6C6667746F6E6C6B73717070756D6569656A73736E7574757D7078716C6B7677748071716F6D6E7C82796F70716E6B72716F70736B6C6B6E7A79747476737C7B756E7773716F6E6771716A6F6D6C7572696A747276777678747D706F71757C787A7271757F827A79727260656866594F727471776E6E6D76776C7771767E767777707C7B777971776F6B7271727671766B6E707677737B7A726C7870727375736C7F797A777874767A777C847C79828177707C7B7779717701FE1163070718107E6D707678747B7B74656B676368777369726B6D6B6F71726B7471706F73706C6F66696B72706C6867706C7A70696D6E726E667170777F7F6F6B6B6C6C6E6A73716A696A67696D747673737A7571746C707A7370726A7381837B7871726E716D6769687072797573717C7C82748078777C756F6B6D6E69676A6D62706572786D686C717274776C6A7977767375737A7D76727179737578746F6D67656457514B746D79737778787773776D707E7D797273707673777771727A7572706E6C6F776F786E71737577767973737977736D746D7171777977737B887C747D7D7D7F88737076737777717201FE1263070718207470686967757772766A7263696E70736F6C6A6B6E716F6771716E717B6E697070676E716C6A6F756568706B6B626D70766E6F716F6E7675716F776667656D756B6E697567716B7576727E79776B7177696E75766A696A75717D716A6F736E716A686D75766F7774797C7C786F7576736664717A78757377746C74736F777A726E70756F77717178747F7473686F6A7479706D6D717A766B6F67676C655C5C407B7F8282807B7B74797468767A807B7B8278787779767374716F7372766E6B706B6F71737272737A796D797A7776767471717676707075787E7D7B7A7F838082827878777976737401FE1363070718307A76686F6C736E797B726F68696E73706F736E6C616770656C6F6D706F717175756865706B696A6C656D6576706D706D666D68736F776D7C736D756F726C6E6B6D7371706F7C70797A726E756B73706D72767877716870717A7E776F766A64696C6E6C747372747A7B7C7776716F79837C70726F777369686C6C6D756F726B72706B6D686E6F7A867874746C696E787C78707476706E74756B676D655E645C486B727C79737171736F81737476807E7E7F747A737482757C786D6F6773746C77737070747979776E7E6E7F7676756B6D666C7576777A7574787B80827C7879837F747A737482757C01FE1463070718407B73757669746E7371736D706669707A6E6A736A716F777374777079757671706B6861646D6B6B68686A6471706B68686F766F636C7371776B7078736C66716B686A696C7174757178716B746A67706D7A75767D746874737E7D827978736667666B6B786F7078727B737B6E6D7572786C68786E736F6A686E6C716C737D787B76756A6C706E707973727170746B757A7A7370747A7873777277696E5C635A5174747C7E656C6F7777726D7481807D757D766E7C7E7A787D7D7369696B7172767472736A6C72707875757C717C7172706B716F73797F6D767D8082867979777B7D766E7C7E7A787D01FE1563070718507A73696C5D636F696F696970647066716C6768706E6868746C6C6871786F7077696C706B686D6C6B66686E6667706E76776B6D6D696B676D74777672716D6D707A726966646E6F6D7A7E7B7477787B6E6E7476796E6D6E7A8475767977686C726D70637074617071786E787A7B7A7A726E6E6E72716E686269697775766F6F6C6A6F716870736D767A7A79716B6E777771787D8078737B726E60676D635B57496D6C71797671747D716D6A747E82847778737973787D79777670736D6A6872716D736E7471757973796D7470766D6B6F766D747A777B76757B7D82847D817B7E78737973787D797701FE1663070718606A71656467606B6D736F6C6062666C746E6C6B6673716E786D787471736E6C716B676C6B70686E626569717671736E6A6C696D686C716F7770746D7B7173686B6B726C6E6A686F687576676C777D77736B72707978656D70847779726E786E75636A69766F76756E7776787B73758480706B726B7270706D6A74726D6C717374707B7178797A747A7875716C716570747A797C7E7D7273726E716663645B514772757473766E7C7D7C6E66747F80807F7C7F73767678787573757470726B746D6D6B676D72747870746F7E7D736E6F6B746E757C75797B7E7A6F7385807C828C7C7F73767678787501FE1763070718706B7070726B6D6C7975666C656E70727D76726A6C666F72797470666D6F6E69686B6D746E6964626872676B74786A72797573686D636E6B727175726E77747971657060676470786C7A726F6F707A7672696D6D827A78727375787173786E686B686F6E76756E70727C77787A6F767976736670707A7373716B6A75717874786C67696A6B707870707979727667767879807A7C777676776E6E6466695E585D52726C716F70706B707B6C6D747B7F7C797776716B7A7C79797D73736F746C727571757077757077767F777774726F726B766D7175777B7470727B7A877F817F847776716B7A7C797901FE186307071880746E6F62667276727F6E676F6873737675726767716C696E736B7073776F736B6C6F6C6F6E6A65676E676B727473756F6B6E616C6E716C776D6F806B7B666C6E696A63696A7D767C7370776F6F637B6C70766F7577787271817F797070706A68656E6A756B767477787E76766E76737C73717478757074707172706E71796F6E61726D707165726D727A827A6F737779797B7A6F737B79726C6C6C696668644F67766C7473787A6D716C7372817D7B7171747675756E6B71787B7679787672776F75747A786C736B7376757671716F6C7274787D7675707A817B80807880828471747675756E6B7101FE196307071890666C616C6A626F716C606F675E6665706F6E6B69686F786A6268727074726D6C6B6D68676F686C636A607479766E6B6D6F6A6B6E6B716D72726F7974766D66605F6C69656D727C747877766D746F797F747B707C7871736F757A7A726E6F666F656B6C686D71777B7D777A74697171756A6D6E7B747072717169737273767077697671767974797369757073707176786D726F7571716D6F72706E67635D564D70797A7E7970726A7574726F7D7D72787A7879707C766C7876717072736A6B76727A7071716D6F6B76707C716F71746F677978757C7875797B757D817B807B817A7879707C766C7801FE1A63070718A071726D726C71716970736E78666B63706C6E716C6E6A6D66666F717770786E6C6B6F7064716F68676C6E71776C66636A6D756F70686C676D75737D7D726C666A72726B6A7277746E7670757B6D737C7471786F75746F717D817C76686E6D6B6A6E666A737170747F7F7F81737270747C6C62626D6A6E7C727474716C706F68766E776D6F767673727F777575727276767676766D7778766D695A63696464624A767D847E757674767D75756F75787D7E817E787C7E807C757978757A76726B74686A676C6E6A6D6C78717E757473807B757174756E727370777B7B818381817D817E787C7E807C7501FE1B63070718B076716A7279717174776A686E6B6B6F74676F6E727363646D696F6B72726B70746B6F6C6A74716B6D6D606A7878756C706A7271727072746F6E71707072766F70656B6B686B6E6C75706B6C6D706C77756A736979726F626D7B807B75756F6E6B6D6C6B746B767075777B7B796E76797D7370686C78757769747268716B6C6F706F716B737874747C79767C756C6C7A8575767A7A72786C6A67696B5F65605B4B717F76787073737376697278777A7C7B737275777876727676787575766D717C71756C6B6774746E74747976797374686A6B6E79747D76717A7E787F83897F7F737275777876727601FE1C63070718C07B786D706864696B706B706D676C726F6F646A736B72746B727D727471706B77736966656D716C766B6B6C74756E6971726F6F696A6B6E6A6E7970776A726E6C5A68686F6B7379717574736E73727672757875787672717C7C8177757063696E5F66716B6B707D7F75767C746F70717B71757370716B6F776E7E6E726C6374786B6F6F747D6C6D73728178796F6D74747771727C7B736C706F70716D60615F4D717076777B7D76797D706B6F727B80777F768276777E6E737E72696B656F6F75787B787375706F6B736A737577696D6D6E70727A7B706C6F73797E83817C82857F768276777E6E7301FE1D63070718D06E6F6B6C6870716A695D6464656D6E777B6A6C6C6F6B6C6C6C6D6D716D6F6E6E6C6D706B6C646D70646B6C73726F6D7A78766F66686B6B7872777075686C6F6A6E6E6A676978717377726F7674767479797A767B717570717D7579786A6C74685F6D676F69707175777A7A797B707D766C6E72707A7A70696B68666B6E75796E6B6F646A706F7076817F76706F6F78756A716E7B797F756C6C686968675E5D4C77887C71757A7375757C777D797A817E80807B717376757776736F767A746D7673746F76737576767678776E6F6F6D747B69737575776F6E7E787A7D8485858380807B717376757701FE1E63070718E07071616E69687A71716B6F69666568706C716B6E6E6A6B6B746E6A75707373716B6966696A6D6D607070706F746D6D6E7374776F6A6D70716D6E72716D656B6B72737074777C6A736D6D73747077737A6E6F73756C6A6A7374806C7273726C75696F70726F7476706E7D75796D77787B776E6B6E7676767377766C7171707076687171706A706D7A70706767686C7F757977808172726A6D676C5D656A635948717477757973807A76796F7876817B787A757E80797873787A726F73767675706D6E7374706D7076726977797C71716E696E7B7A76777178817A7886797174817A757E807978737801FE1F63070718F082716A6B71786A6F726D6C686B716D6E6A73726A776F6D6E6E7B6C6D75726B6864646B676F716E6066696671767772757275726C716C697171726D6E69696D6A6D726A6F6F6C6B72716E7876706F75766D7976796E6A6E7678817770717970756D736C71706A6E756F7173757371787B72677273736E796B6C746D7075756D737071646A6B7D7C7E797C706A6F6D7679817B777F737A736C6869696C6C5F6049737E728472727572736C7279767978857C7979787E786B7375796A74736E6D7479796A696E767973776F7B7476726E6D696F757A777C6F717E7F777D787C7E887C7979787E786B7301FE2063070718006D6A6A736E6C6A71736A6866646B656E72716D6F6C696B696C6C73727271726E69656C6E7F736F70676A70746E6D746B75726F6C6E6F6E6E687176797A656D6B776F706F6D746D6F7473736B6A706F6979717176717871797D7F726C6D726C686F70747275717770807C6E786F6D787F7D6F6E756F6F6B6573726E7072727D7071676B6F74797C77737672766F7275746C7471716D7D82736B6A6D6A61555D4B7B7E817A7F82837776776C7683837477797A81787B7C7878787A747C7772707A7171747174787A7172707D7C6D7073756B6C7373777D76727A7E7880817B747F797A81787B7C787801FE216307071810796E75777673737672706D6F6871766D6F6B6A616B6C6E6F6D6E6F7F73726A6A7269746D716D6A6E686B6B71756D687172666E6760666C7172717A7D736E736B706F6C6E6D6E6A797C7376727176756C7B73767C6E676B797A7B746F79716C6A6D5E6F63676D717E7573727875747B84736F716D766665707373717C75716E766E6A70777372767270797971696C706F747377797171766E6C6F6667645F594B6B6C676D666A6F6C79706D6D75787977746B777E7B7978747E74746D6D6D7172736B6D6F6D6D6F76777473786E74757B7473717B747A746D7D7A798482817E7E746B777E7B79787401FE2263070718207A726E6F6568646F7674716269706E7272676266696F6E6E6A716D6E6B726775716A696C69726F6967626C736F796C73736F6C6A6B7177706D757777726663706B6E6E716F776D6F776E736E686777707773787F716F7173838478646D6978726270646F6E6C75766A707173767477807376706F7271706E71706971757674777375726F6E6B6F717A79746E656C716F7A76776D7C83786E69676C6E675D5D4A7782827F74696E6F706F7C7E7880807F7D7B7D7271786D76777177727673757A6D75706F74746C6B7D6F79777A6A69716D666D776D757073747F777F757C827D7D7B7D7271786D7601FE23630707183077716F75676F6B716E75707168636C696760716B726E6E6D6771696D6B7169706A6B676971636C616B6967636E676B6F6E6D6E6E656C75717775767A6D726E6F6D716D6D6975687175726D6A73767F767272797F76706C707E78706D716C6D696872768070666F6D7D7B78757A6F777D7169676A6D716F7276756E6F69676B69717472707277757A7E85797376707876767C7A7A707976766F696B645D4F594472727A70736B706D77716F6F72757C7E7C7577787A736D7A767075787C73717574757575677470727768757572786E6C6B6B6A76797A74797E74757A7E8282847C7577787A736D7A01FE24630707184071656A686F676B6C7777747167736C716B6D6C64636B6C6C746A6B757B6E75716668706E766D706E646B676F71686E6F746D7A6D67706E71707477766A676B7169676D6C7077706E81717476716F7570736E6D797463697C7F7F787681756B6A656E6E756C6B77797C77797A6E7777726E6D737B73706B6D6A73717370766F716B727174737279727672776F757079717470736D697276736F6A696B62665C5077797D857E7C7D747A787A7B80817D7977777D807D7A757D7A7A747279716D76716C6B6C72756F74756C7B7C7B6D71726F727580877570797D7A7C7F73827B7E77777D807D7A757D01FE256307071850736F7068636968656C73716F676966726D736B6A6C68706B736E72736F7366696567676C727173736D6B6C6F6D68676C717B77736D716F6966766B7273696B6B6D6C67676E7B7373786B6D6D717176786C736C7675756F78807C6D686D6B6B6D6C696F6C78726B72727576817478727C7670736F7073766F6F7574716B6E71776E716A7274687677827B736B686E76777671757275746F6A6C6D66626260634A737479777C70797170726A6E7C83827B7B7879787A817C7A78727170767576727178707A797774777C737E7374677469696968696E7B75707A7D7A7A7D7980857B7879787A817C7A01FE2663070718606B78797269707A7A7169676B6F716D67766C686B6B6C706C6B79776B6E7276726A637465756E6D677269616A6B666C706B6F69747176716F75737970716A686A646B6C6D69746C777D7272706D7270737879797071726C7581837472767170706A6C6A6C6B6B747975807E7C7076787E746D767173706C6A726967756A73716E6C7071716E706B72737172736A70756C6E767776767C766C6D68636464615F466E777F82817D7673756E7474757B8085817C77756F7C767A71716E706E70706E6B74737770777875796D76726C68707771767674737372707A7386827C81777E817C77756F7C767A01FE2763070718707A696F70737779727471726E676866726C6A68656469696F6C7274747773736D676B6E69707271727A6E73766B676F6B716E716B676D657770747771776A686570746C72646F6466796D736F737374726B707370686974757B7F827476776E7167696F7C7A766C7570747C7C7F777B7D686C6F69696C727074747D767A787170726D67706A6D7476777E75717175787A73747B7A78726D697163626B655F5C50716A7B70796E76696E7471767876777A7E7E807A7C78767478777478766C6D757675696F78727374747177767E706E6E777370786F6F71797C7D7D817C807D857E7E807A7C78767401FE286307071880787C746769747B7071766E6A6E7166716D6766636A746D6D6C757C75716F6D6B677173686C6C73676371717C6F7571707070736C69686B716C6F7C6F6F6B6D6D6F6B6A6F706669747C70706F707375716E737B76706F7B717A7E7574707A67666A6B6875757C6972727279757A7579777576717578806A686E70727477706F757474776F76716B707A7074767271736F736F71776E746C776F6B6470685F644E787C7A7D7E77787C7A74727A7D7580827E747E7B7979757C7C6F6E73726D757C6F6A726B72767274776D746E726E74757C776D7673797679808481837D80878A7E747E7B7979757C01FE2963070718907F7F797A6E70787A7F7D7677747573716463736C70726F746E7475717C6F71666A636E6C6F6D6D6B6D686D6B6F6A6C6A746D697071777A706979716C65666F6671786772716B646E74777D7C6A6B7D7370726B716D697A71767A786E6C6B6A65666D6971686D6F776D7F887971727A7F6F6C6F686C7475777378727776787D7670717577746F737A7778706D6D73726C767E747376757B766E67636A6660574875757E7976777C7B74746C737D7876707C74817976736D6D7B737271746E716F7679776F757076796E717B706F6C6D736F696F736D7B74837C7585807A8081877C74817976736D6D01FE2A63070718A0746F73786C6E736F706D65706C706B7467686E6C6A6A6E6E6E71726E706A6D6E6C6B6C6B716E7065656663677574686E717A716A6B7471716D74767870756F666C696F6B6D74787679727A706C6A7571737277766D7275797E797D7976695F6666636A7676716D707D73787B777F7F786A6E6E6E7576726D71716D7072716D69647670706C6B7B837B7F7473696874747970767A737477746F665F605F51584D727B7D81837F7871726F76767C827A7F777779747874736E7476747276786A70747370697770706A726E6F767A7B78736F7376777672777B7F7C7D837C81817B777779747874736E01FE2B63070718B0737470706972747D7B6B6868686F6E6D736A707A706C706A68746A6D776C736E6A616D6B69666E6969656A7870686C717574756E686F6D77787372706A686D6C746D6B6D6F7670746F7171787170726F6D726C7978726E717A7F726E6D6F6B6D6F6A716D7274776872787B7471776C736E676D73727A77857A706D6D76747973766E72757474706F757774746E6C70697C73737772726C706C786D656E645A436F767672797474726B6E71757B7880827D707777747B7A77746C6C75786D696D73696A6E74827672766E797B7772746F6869717B7176737E807A7D80857D76837D707777747B7A7701FE2C63070718C07A70706E6A646F7279716C6764636673716F68696B706964686F6B7776726C7B73757771696A6E6B67666C716966666E676E777063646F73777274717370716F6F7E6A706E706C6E6E707472726F71757673747A736868727683796A72666866696C6C6F7970737674847B766E76756D736B67656E716F6D7971708070757073736D6F6C7677727474797C7C756D767A756F6D6D7A747B736A6A676463605C537B797C816F7D797D7E786D7A89758583847A78747D7A77817973727071696E707172757379736E7D727F78787C6F707075736E717D73746C72797C827F797F80847A78747D7A778101FE2D63070718D07C7E6D72696F72706F72716F67606C746D786F75736F74706970766F77796C706F6B61686668696867686F6E777173727974616F77717579767876726F656967606B6A6E6C7573787A7373737576756B6B6D74786C756E7883857A6A737164656671676E70726D73746F7375737573786E6F7575707A707A726F6D76777670727673777271697072747D6E6E6B6A77797D726F73716772756B6A666162615D4869787D736F75756F6B67677676786E71767879707C6E737177737878797576736D726E767674767075737B766C67716A6D7370757D746A7B7F74757F7F778081767879707C6E737101FE2E63070718E06D656562606C6E706B676A66696E726B6F636D696B6964676E706D786F7376746B676B6B6B6E666B6767796A6E676A7070726C6E6D6C717A7E737073706C6B6D696F6C6E676865727B6C6A6D6F75796F707972766F727569737C757173716D68636A676D6F707D727880787E7272767E7368706E7270756C75706E71807B72777D786F6C7065737B737972767272747379717C7571786F6C6E6668656A605A52767076757874706E6D6F6E778A7F7A77736F6D767B7B6E777477726E71777E6B707272696B776B777D6E7778776F6D757574716F747A75767B7E7C807B7C7D7B736F6D767B7B6E7701FE2F63070718F07673646E666675726F676963606C676E7670716E6C7173707A73716F766E687267646363636466666B646D726F726D716F6C77706B767A79747077726F756B6C6D6A637177786F687E7377747772787A71756D72656B6D737B807472796C666A696A6C706D6E6E72717A767376737775716D726F6A6F6D6B6C6F6A7074706C6E6C6873737473737676787B726C6D6977757478837E7C7C73706F62605D595B506A706371706A6A6966666B6F6F76757473757579786F7073747C716B6B6F666C73756D797A6E6F6771737B707F6E6D6B72726E747779747380787F7C787B808573757579786F7073 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 2368 2 0 0000 diff --git a/tests/vfs5011/capture.png b/tests/vfs5011/capture.png new file mode 100644 index 0000000000000000000000000000000000000000..c33f01a7c4c7c83269a3b54935adda862c120cd3 GIT binary patch literal 65243 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

+^#@0) znQoV*PufPkU~DukJByZ+Tn~g=`8+7^!Ju!YlO)s$P%psjEDU@ti?y;0OV-{+ERH7dH@pu&prtk0Ni% zQYeZ3m0{GoOre&eCtSeyISs=s#S|1Q+AY|X;O_nR)5yOm=pc=`Ya^AmHgotx9>mJd zBo7R#Gsgw{s!|a1YV3A6yHKGkMawpr(!(aYK}-BRL15L}_!6M>E^PPp1;bHtVtz7W z_eoQ!)g-$p&0Cz#y+~JoEQhw19K|e9{hs{Q5L4EItc_>WO-@Nh36mk z9m;IMOkuoz~ zShO)qDS1CRD3q}GLYA%Dfi<0H$Fs%4LrJsGx7XKBCMZ6rVvY^k9OacW?}+!9C35mg zY(UxpoOJFzhU6SHdtTQfJ{DxePf{5@`{X8%h8?lJCo-pVqG>c-iG&pMrN`0mhnBFa z4d0xc^7dT$Zohcb`_(6Da4(+T0@V!%GG`AIYy+C6!#4t>thK8B4O5B~VX{W$#tT)+ z1&?!%yoW2SVgZHq@R06gpxG7f0TZATwZr4#L>gFVaq+6Dk_BKDdVYRBJNxzN;L_7j z3?`glaH81s_Fd4C*-jy7oIxpp#|S}@ce=BaSJ#7NU}Qwz)wu8gE*=Yj1B@7vABpx@dj? z`O80>bCRbq!jM#j`?dm!VzI8!p88^Z z-?lDJTIF|si}!GItEz@!I}f=-V3OY)1krVnM$w|j_bMFGfCRQPJQsx$JV7xu4m1Lg zoi&P!g*G~xGXK3;wv366PDuJie;;Z9sBp@@gzf;Rd9hTD+;`w?wDhF03A9l7*ON)m*G7HoRs22WpTan9$D4{9+>}^BT464)YvTm7n|ivi$8x zTY5L-fY!Y39uWl7Kd{-4O-!trt#kTmZSTL-(s)QsL)>E4j%n3)M2)C0Y~VQeAOkyL z6UwQo_1PxFy%ysTCsP%m)etZdfJ21iaP=@;=%s=f{e~mN#l*IaDfAGNIQLlnZF`h~ zx~z_S*nYe5RZ?2o!o=i-0X?~L*lMZ)wd)ciPm3U9!>3s5Mg2XT?W>e0U*W7!Dk*Af}^``nkuZMifE1$V*8Dn zvPv_bV|#8x2Bjb=+)3%kV~9(=J*h7TuV_oBX32kOJ*0ok@o7G`OMCCafj=J>x}mxn zNykE%s~{zC0q0ZxmQrlY|8CCyBcOOFqHxlf>8lS&sTo>Hr8FBx*5dAtu0>~7PM1oa z{z^_timkzNz7+Z=LHPEiJKO^2_u0SVh^=1a9|{seblIzet`JQFK1LiB`rwN%>+AV* z=&Q&kdXlpb`$N2xw*tfj1qFqKNM(($3PQ-e+)L+Xv-&WH9<&~tjT@`{#lUKf?v#vr z)9*I6zwg9O!M`)#kB#eLpwwpC+tX75Zftz3V^ zNE*Rktf=ttbk9}xl-?je8g{KAhU zXYQo3ej#vZHdA~0`8n!jxKAxEF2d0^R|OX>90t6I%6<=K=gt_u1Ct98Lvs?efvj8>O|~eu$;b$0=2SYGi9@N$cW+24 z%>N4?`h$c|P>)032Xi2hn1uA|gYw83AwQ=@`1%u79h<8c8w7Z4cXr~?0FJ8DObEiLuMKPoS($8j2iusK$VQkZm z!79oyLs;y`VboYS{Nb^xkDE*@m6M;J7+_Q0(#5zxgY8f$`!te*RM=+Is#<^I-+o<| za~MCH5~ETAqIYyOG!|CYFmF4i$i3+%Ng}Je&^b~gNjIc#7jI5~8JgPt0hHUvN@7|A zgm3_o^;=;td0_~ck-X6uLXAMkC<`&g=C<_lfFF;Qt3=$xut!HnAGYzbv5`aFKWzQ< zAN{mjWL{iodf9|?a>8s>6F?u{7;;BHI-x)uHcehNU2+BeI8kuMx#lK(+xdHs1sP z*tznAf&y9--zQJ>@a0EwIwG`xB41ND)OlB?AiuHAl=9mn4-QzAi?v^&G=KX1c^w`K zJ#v-=AFR)&CMJ9>KcRH(SN!%<|872o>RIiOUjeGOR8*2GHm$lKh(R zMdH=_AdX(UbuV)vs=u&`%=|Sp{c*2lAfUkY%~0O!GOK

G)3NshEwqCS%?;mCA+j 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 literal 0 HcmV?d00001 diff --git a/tests/vfs5011/device b/tests/vfs5011/device new file mode 100644 index 00000000..4c75e596 --- /dev/null +++ b/tests/vfs5011/device @@ -0,0 +1,80 @@ +P: /devices/pci0000:00/0000:00:14.0/usb2/2-6 +N: bus/usb/002/017=12011001FF11FF088A13170078000000010109022E00010100A0320904000004FF00000007050102400000070581024000000705820240000007058303080004 +E: DEVNAME=/dev/bus/usb/002/017 +E: DEVTYPE=usb_device +E: DRIVER=usb +E: PRODUCT=138a/17/78 +E: TYPE=255/17/255 +E: BUSNUM=002 +E: DEVNUM=017 +E: MAJOR=189 +E: MINOR=144 +E: SUBSYSTEM=usb +E: ID_VENDOR=138a +E: ID_VENDOR_ENC=138a +E: ID_VENDOR_ID=138a +E: ID_MODEL=0017 +E: ID_MODEL_ENC=0017 +E: ID_MODEL_ID=0017 +E: ID_REVISION=0078 +E: ID_SERIAL=138a_0017_6c3b5712a6c0 +E: ID_SERIAL_SHORT=6c3b5712a6c0 +E: ID_BUS=usb +E: ID_USB_INTERFACES=:ff0000: +E: ID_VENDOR_FROM_DATABASE=Validity Sensors, Inc. +E: ID_MODEL_FROM_DATABASE=VFS 5011 fingerprint sensor +A: authorized=1 +A: avoid_reset_quirk=0 +A: bConfigurationValue=1 +A: bDeviceClass=ff +A: bDeviceProtocol=ff +A: bDeviceSubClass=11 +A: bMaxPacketSize0=8 +A: bMaxPower=100mA +A: bNumConfigurations=1 +A: bNumInterfaces= 1 +A: bcdDevice=0078 +A: bmAttributes=a0 +A: busnum=2 +A: configuration= +H: descriptors=12011001FF11FF088A13170078000000010109022E00010100A0320904000004FF00000007050102400000070581024000000705820240000007058303080004 +A: dev=189:144 +A: devnum=17 +A: devpath=6 +L: driver=../../../../../bus/usb/drivers/usb +A: idProduct=0017 +A: idVendor=138a +A: ltm_capable=no +A: maxchild=0 +L: port=../2-0:1.0/usb2-port6 +A: power/active_duration=624952 +A: power/async=enabled +A: power/autosuspend=2 +A: power/autosuspend_delay_ms=2000 +A: power/connected_duration=624952 +A: power/control=on +A: power/level=on +A: power/persist=1 +A: power/runtime_active_kids=0 +A: power/runtime_active_time=624676 +A: power/runtime_enabled=forbidden +A: power/runtime_status=active +A: power/runtime_suspended_time=0 +A: power/runtime_usage=1 +A: power/wakeup=disabled +A: power/wakeup_abort_count= +A: power/wakeup_active= +A: power/wakeup_active_count= +A: power/wakeup_count= +A: power/wakeup_expire_count= +A: power/wakeup_last_time_ms= +A: power/wakeup_max_time_ms= +A: power/wakeup_total_time_ms= +A: quirks=0x0 +A: removable=fixed +A: rx_lanes=1 +A: serial=6c3b5712a6c0 +A: speed=12 +A: tx_lanes=1 +A: urbnum=7 +A: version= 1.10 From b92e6d6acd04c623ac9e006e22e88482b64cceef Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 12 Aug 2019 16:30:40 +0200 Subject: [PATCH 51/73] tests: Add testing to the synaptics driver As the driver is not a normal image device, we need to add a custom script to test it. Note that the ioctl dump must also be manually modified unfortunately as the state is tracked incorrectly for the device by umockdev-record. --- libfprint/drivers/synaptics/synaptics.c | 11 +- tests/README-umockdev | 3 + tests/meson.build | 19 +++ tests/synaptics/custom-recorded.ioctl | 129 +++++++++++++++++ tests/synaptics/custom.ioctl | 183 ++++++++++++++++++++++++ tests/synaptics/custom.py | 42 ++++++ tests/synaptics/device | 75 ++++++++++ tests/umockdev-test.py | 15 ++ 8 files changed, 474 insertions(+), 3 deletions(-) create mode 100644 tests/synaptics/custom-recorded.ioctl create mode 100644 tests/synaptics/custom.ioctl create mode 100755 tests/synaptics/custom.py create mode 100644 tests/synaptics/device diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index 0621b08f..8d08f0d6 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -476,6 +476,7 @@ list_msg_cb(FpiDeviceSynaptics *self, uid); fpi_print_set_type (print, FP_PRINT_RAW); + fpi_print_set_device_stored (print, TRUE); g_object_set (print, "fp-data", data, NULL); g_object_set (print, "description", get_enroll_templates_resp->templates[n].user_id, NULL); @@ -782,6 +783,7 @@ enroll(FpDevice *device) uid); fpi_print_set_type (print, FP_PRINT_RAW); + fpi_print_set_device_stored (print, TRUE); g_object_set (print, "fp-data", data, NULL); g_object_set (print, "description", user_id, NULL); @@ -974,9 +976,12 @@ dev_probe(FpDevice *device) /* This is the same as the serial_number from above, hex encoded and somewhat reordered */ /* Should we add in more, e.g. the chip revision? */ - serial = g_usb_device_get_string_descriptor (usb_dev, - g_usb_device_get_serial_number_index (usb_dev), - &error); + if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0) + serial = g_strdup ("emulated-device"); + else + serial = g_usb_device_get_string_descriptor (usb_dev, + g_usb_device_get_serial_number_index (usb_dev), + &error); g_usb_device_close (usb_dev, NULL); diff --git a/tests/README-umockdev b/tests/README-umockdev index 6b44792e..cabbace1 100644 --- a/tests/README-umockdev +++ b/tests/README-umockdev @@ -10,6 +10,9 @@ To create a new umockdev test, you should: 4. Run the test, for a capture test this would be: umockdev-record -i /dev/bus/usb/001/005=capture.ioctl -- ./capture.py capture.png This will create a capture.ioctl and capture.png file. + Please set the FP_DEVICE_EMULATION=1 environment variable. You may need + to adjust the driver to adapt to the emulated environment (mainly if it + uses random numbers, see synaptics.c for an example). 5. Place all files into the driver subdirectory test/DRIVER, i.e. device, capture.ioctl, capture.png 6. Add glue to meson.build diff --git a/tests/meson.build b/tests/meson.build index e461c6de..c8bdf769 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -1,9 +1,17 @@ envs = environment() +# Enable debug messages and abort on warnings envs.set('G_DEBUG', 'fatal-warnings') envs.set('G_MESSAGES_DEBUG', 'all') + +# Setup paths envs.set('MESON_SOURCE_ROOT', meson.build_root()) envs.prepend('GI_TYPELIB_PATH', join_paths(meson.build_root(), 'libfprint')) envs.prepend('LD_LIBRARY_PATH', join_paths(meson.build_root(), 'libfprint')) + +# Set FP_DEVICE_EMULATION so that drivers can adapt (e.g. to use fixed +# random numbers rather than proper ones) +envs.set('FP_DEVICE_EMULATION', '1') + envs.set('NO_AT_BRIDGE', '1') if 'virtual_image' in drivers @@ -21,5 +29,16 @@ if 'vfs5011' in drivers find_program('umockdev-test.py'), args: join_paths(meson.current_source_dir(), 'vfs5011'), env: envs, + timeout: 10, ) endif + +if 'synaptics' in drivers + test( + 'synaptics', + find_program('umockdev-test.py'), + args: join_paths(meson.current_source_dir(), 'synaptics'), + env: envs, + timeout: 10, + ) +endif \ No newline at end of file diff --git a/tests/synaptics/custom-recorded.ioctl b/tests/synaptics/custom-recorded.ioctl new file mode 100644 index 00000000..f7edc72e --- /dev/null +++ b/tests/synaptics/custom-recorded.ioctl @@ -0,0 +1,129 @@ +@DEV /dev/bus/usb/001/070 +USBDEVFS_GET_CAPABILITIES 0 7D000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 01 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 40 38 0 00009C37FE5C669C2D000A01014101C10000D11BB7134A090FA1000000000100000000000003 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 5 5 0 A7FE011100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE01130100 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 37 37 0 A7FE02512000014650312D30303030303030302D302D30303030303030302D6E6F626F6479 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE025400 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE0255010C + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550119 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550125 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550125 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550132 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE0255013E + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE0255013E + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE0255014B + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550157 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550164 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 37 0 0000FE02591F014650312D30303030303030302D302D30303030303030302D6E6F626F6479 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE046000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 39 0 0000FE0468214F2B014650312D30303030303030302D302D30303030303030302D6E6F626F6479 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 5 5 0 A7FE037100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 41 0 0000FE03752301012007014650312D30303030303030302D302D30303030303030302D6E6F626F6479 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 5 5 0 A7FE037200 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE037600 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 35 35 0 A7FE04651E4650312D30303030303030302D302D30303030303030302D6E6F626F6479 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE046600 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 36 36 0 A7FE05811F014650312D30303030303030302D302D30303030303030302D6E6F626F6479 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 37 0 0000FE05831F014650312D30303030303030302D302D30303030303030302D6E6F626F6479 diff --git a/tests/synaptics/custom.ioctl b/tests/synaptics/custom.ioctl new file mode 100644 index 00000000..4739bfc4 --- /dev/null +++ b/tests/synaptics/custom.ioctl @@ -0,0 +1,183 @@ +@DEV /dev/bus/usb/001/070 +USBDEVFS_GET_CAPABILITIES 0 7D000000 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 01 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 40 38 0 00009C37FE5C669C2D000A01014101C10000D11BB7134A090FA1000000000100000000000003 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 5 5 0 A7FE011100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE01130100 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 37 37 0 A7FE02512000014650312D30303030303030302D302D30303030303030302D6E6F626F6479 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE025400 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE0255010C + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550119 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550125 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550125 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550132 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE0255013E + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE0255013E + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE0255014B + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550157 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE026000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE02550164 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 37 0 0000FE02591F014650312D30303030303030302D302D30303030303030302D6E6F626F6479 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 5 5 0 A7FE037100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 41 0 0000FE03752301012007014650312D30303030303030302D302D30303030303030302D6E6F626F6479 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 5 5 0 A7FE037200 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE037600 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 35 35 0 A7FE04651E4650312D30303030303030302D302D30303030303030302D6E6F626F6479 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE046600 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000000 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE046000 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 06000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910101 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 7 0 0000FE00910100 + USBDEVFS_REAPURBNDELAY 0 1 131 0 0 7 7 0 05000000000100 + USBDEVFS_REAPURBNDELAY 0 3 1 0 0 1 1 0 A8 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 39 0 0000FE0468214F2B014650312D30303030303030302D302D30303030303030302D6E6F626F6479 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 36 36 0 A7FE05811F014650312D30303030303030302D302D30303030303030302D6E6F626F6479 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 37 0 0000FE05831F014650312D30303030303030302D302D30303030303030302D6E6F626F6479 diff --git a/tests/synaptics/custom.py b/tests/synaptics/custom.py new file mode 100755 index 00000000..60167997 --- /dev/null +++ b/tests/synaptics/custom.py @@ -0,0 +1,42 @@ +#!/usr/bin/python3 + +import gi +gi.require_version('FPrint', '2.0') +from gi.repository import FPrint, GLib + +ctx = GLib.main_context_default() + +c = FPrint.Context() +c.enumerate() +devices = c.get_devices() + +d = devices[0] + +assert d.get_driver() == "synaptics" + +d.open_sync() + +template = FPrint.Print.new(d) + +def enroll_progress(*args): + print('enroll progress: ' + str(args)) + +# List, enroll, list, verify, delete, list +print("enrolling") +p = d.enroll_sync(template, None, enroll_progress, None) +print("enroll done") + +print("listing") +stored = d.list_prints_sync() +print("listing done") +assert len(stored) == 1 +assert stored[0].equal(p) +print("verifying") +verify_res, verify_print = d.verify_sync(p) +print("verify done") +assert verify_res == True + +print("deleting") +d.delete_print_sync(p) +print("delete done") +d.close_sync() diff --git a/tests/synaptics/device b/tests/synaptics/device new file mode 100644 index 00000000..6da3eea7 --- /dev/null +++ b/tests/synaptics/device @@ -0,0 +1,75 @@ +P: /devices/pci0000:00/0000:00:14.0/usb1/1-1 +N: bus/usb/001/070=12010002FF10FF08CB06BD0000000000010109022700010100A0320904000003FF000000070501024000000705810240000007058303080004 +E: DEVNAME=/dev/bus/usb/001/070 +E: DEVTYPE=usb_device +E: DRIVER=usb +E: PRODUCT=6cb/bd/0 +E: TYPE=255/16/255 +E: BUSNUM=001 +E: DEVNUM=070 +E: MAJOR=189 +E: MINOR=69 +E: SUBSYSTEM=usb +E: ID_VENDOR=06cb +E: ID_VENDOR_ENC=06cb +E: ID_VENDOR_ID=06cb +E: ID_MODEL=00bd +E: ID_MODEL_ENC=00bd +E: ID_MODEL_ID=00bd +E: ID_REVISION=0000 +E: ID_SERIAL=06cb_00bd_317bb11d90a4 +E: ID_SERIAL_SHORT=317bb11d90a4 +E: ID_BUS=usb +E: ID_USB_INTERFACES=:ff0000: +E: ID_VENDOR_FROM_DATABASE=Synaptics, Inc. +A: authorized=1 +A: avoid_reset_quirk=0 +A: bConfigurationValue=1 +A: bDeviceClass=ff +A: bDeviceProtocol=ff +A: bDeviceSubClass=10 +A: bMaxPacketSize0=8 +A: bMaxPower=100mA +A: bNumConfigurations=1 +A: bNumInterfaces= 1 +A: bcdDevice=0000 +A: bmAttributes=a0 +A: busnum=1 +A: configuration= +H: descriptors=12010002FF10FF08CB06BD0000000000010109022700010100A0320904000003FF000000070501024000000705810240000007058303080004 +A: dev=189:69 +A: devnum=70 +A: devpath=1 +L: driver=../../../../../bus/usb/drivers/usb +A: idProduct=00bd +A: idVendor=06cb +A: ltm_capable=no +A: maxchild=0 +L: port=../1-0:1.0/usb1-port1 +A: power/active_duration=33942 +A: power/autosuspend=2 +A: power/autosuspend_delay_ms=2000 +A: power/connected_duration=33942 +A: power/control=on +A: power/level=on +A: power/persist=1 +A: power/runtime_active_time=33702 +A: power/runtime_status=active +A: power/runtime_suspended_time=0 +A: power/wakeup=disabled +A: power/wakeup_abort_count= +A: power/wakeup_active= +A: power/wakeup_active_count= +A: power/wakeup_count= +A: power/wakeup_expire_count= +A: power/wakeup_last_time_ms= +A: power/wakeup_max_time_ms= +A: power/wakeup_total_time_ms= +A: quirks=0x0 +A: removable=removable +A: rx_lanes=1 +A: serial=317bb11d90a4 +A: speed=12 +A: tx_lanes=1 +A: urbnum=12 +A: version= 2.00 diff --git a/tests/umockdev-test.py b/tests/umockdev-test.py index 7115298e..931dcae5 100755 --- a/tests/umockdev-test.py +++ b/tests/umockdev-test.py @@ -56,10 +56,25 @@ def capture(): # Compare the images, they need to be identical cmp_pngs(os.path.join(tmpdir, "capture.png"), os.path.join(ddir, "capture.png")) +def custom(): + ioctl = os.path.join(ddir, "custom.ioctl") + device = os.path.join(ddir, "device") + dev = open(ioctl).readline().strip() + assert dev.startswith('@DEV ') + dev = dev[5:] + + subprocess.check_call(['umockdev-run', '-d', device, + '-i', "%s=%s" % (dev, ioctl), + '--', + '%s' % os.path.join(ddir, "custom.py")]) + try: if os.path.exists(os.path.join(ddir, "capture.ioctl")): capture() + if os.path.exists(os.path.join(ddir, "custom.ioctl")): + custom() + finally: shutil.rmtree(tmpdir) From 0b87b21d5260e25212146e4e37de8e67e82d827c Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 12 Aug 2019 17:50:10 +0200 Subject: [PATCH 52/73] cocci: Remove spatch/cocci files again They were just committed for archival purposes. --- cocci/00-misc-cleanups.cocci | 78 ------ cocci/01-endpoint.cocci | 8 - cocci/02-type-renames.cocci | 64 ----- cocci/03-function-renames.cocci | 80 ------ cocci/04-misc-renames.cocci | 29 --- cocci/05-libusb-1.cocci | 118 --------- cocci/06-libusb-callback-1.cocci | 344 ------------------------- cocci/07-libusb-fill.cocci | 163 ------------ cocci/08-ssm.cocci | 20 -- cocci/10-driver.cocci | 386 ---------------------------- cocci/99-insert-checking-code.cocci | 38 --- cocci/all.cocci | 19 -- cocci/apply-all | 9 - 13 files changed, 1356 deletions(-) delete mode 100644 cocci/00-misc-cleanups.cocci delete mode 100644 cocci/01-endpoint.cocci delete mode 100644 cocci/02-type-renames.cocci delete mode 100644 cocci/03-function-renames.cocci delete mode 100644 cocci/04-misc-renames.cocci delete mode 100644 cocci/05-libusb-1.cocci delete mode 100644 cocci/06-libusb-callback-1.cocci delete mode 100644 cocci/07-libusb-fill.cocci delete mode 100644 cocci/08-ssm.cocci delete mode 100644 cocci/10-driver.cocci delete mode 100644 cocci/99-insert-checking-code.cocci delete mode 100644 cocci/all.cocci delete mode 100755 cocci/apply-all diff --git a/cocci/00-misc-cleanups.cocci b/cocci/00-misc-cleanups.cocci deleted file mode 100644 index dfaba641..00000000 --- a/cocci/00-misc-cleanups.cocci +++ /dev/null @@ -1,78 +0,0 @@ -// Remove USB device reset, lets hope that we do not need this. -// If we do, maybe do it elsewhere? -@@ -identifier r; -@@ -- r = libusb_reset_device(...); -- if (r != 0) { ... } - -// Functions that have uneccessary returns (i.e. error cannot happen after refactoring) -// NOTE: Make sure that these function are fine to modify in *all* drivers! -@ prior_int_func @ -identifier func =~ "capture_chunk_async|alksdjflkajsfd"; -expression res, res2; -@@ --int func -+void func - (...) -{ - <... -- return res2; -+ res2; - ...> -- return res; -+ res; -} - -@@ -identifier prior_int_func.func; -identifier res; -@@ --res = func -+func - (...); -( --if (res < 0) { ... } -| --if (res != 0) { ... } -) - -// Remove useless checks of fpi_timeout_add return values -@@ -expression a1, a2, a3, a4; -@@ --if (fpi_timeout_add(a1, a2, a3, a4) == NULL) { ... } -+fpi_timeout_add(a1, a2, a3, a4); - -@@ -identifier timeout; -expression a1, a2, a3, a4; -@@ -timeout = fpi_timeout_add(a1, a2, a3, a4); --if (timeout == NULL) { ... } - - -// The VFS5011 driver has some stupid "radiation detected" logic, that should be asserts -@@ -expression expr; -@@ --if ((expr)) { -- ... -- fp_err("Radiation detected!"); -- ... --} -+g_assert(!expr); - - -// A number of drivers call both fpi_imgdev_session_error *and* fpi_ssm_mark_failed. -// While this worked fine, it is plain wrong and considerably complicates memory -// management of the errors. -// Remove this duplication -@@ -expression dev; -expression ssm; -expression error; -@@ -- fpi_imgdev_session_error(dev, error); - fpi_ssm_mark_failed(ssm, error); - diff --git a/cocci/01-endpoint.cocci b/cocci/01-endpoint.cocci deleted file mode 100644 index d3507208..00000000 --- a/cocci/01-endpoint.cocci +++ /dev/null @@ -1,8 +0,0 @@ -@@ -@@ -- LIBUSB_ENDPOINT_IN -+ FP_USB_ENDPOINT_IN -@@ -@@ -- LIBUSB_ENDPOINT_OUT -+ FP_USB_ENDPOINT_OUT diff --git a/cocci/02-type-renames.cocci b/cocci/02-type-renames.cocci deleted file mode 100644 index e37fc92f..00000000 --- a/cocci/02-type-renames.cocci +++ /dev/null @@ -1,64 +0,0 @@ -@ fp_img_dev @ -typedef FpImageDevice; -@@ --struct fp_img_dev -+FpImageDevice - -@ FpImageDevice_cast @ -typedef FpImageDevice; -expression dev; -@@ --(FpImageDevice*) dev -+FP_IMAGE_DEVICE (dev) - -@ fp_dev @ -typedef FpDevice; -@@ --struct fp_dev -+FpDevice - -@ FpDevice_cast @ -typedef FpDevice; -expression dev; -@@ --(FpDevice*) dev -+FP_DEVICE (dev) - -@ FP_DEV_cast @ -expression dev; -@@ -- FP_DEV (dev) -+ FP_DEVICE (dev) - -@ FP_IMG_DEV_cast @ -expression dev; -@@ -- FP_IMG_DEV (dev) -+ FP_IMAGE_DEVICE (dev) - -@ fpi_ssm @ -typedef fpi_ssm; -typedef FpSsm; -@@ --fpi_ssm -+FpSsm - -@ fp_img @ -typedef FpImage; -@@ --struct fp_img -+FpImage - -@ libusb_transfer @ -typedef FpUsbTransfer; -@@ --struct libusb_transfer -+FpUsbTransfer - -@ libusb_device_handle @ -typedef libusb_device_handle; -typedef GUsbDevice; -@@ --libusb_device_handle -+GUsbDevice - diff --git a/cocci/03-function-renames.cocci b/cocci/03-function-renames.cocci deleted file mode 100644 index cd261529..00000000 --- a/cocci/03-function-renames.cocci +++ /dev/null @@ -1,80 +0,0 @@ -@@ -expression w; -expression h; -expression status; -expression dev; -expression a1, a2, a3; -@@ -( --fpi_img_new(w * h) -+fp_image_new(w, h) -| --fpi_ssm_new -+fp_ssm_new -| --fpi_ssm_free -+fp_ssm_free -| --fpi_ssm_start -+fp_ssm_start -| --fpi_ssm_start_subsm -+fp_ssm_start_subsm -| --fpi_ssm_next_state -+fp_ssm_next_state -| --fpi_ssm_jump_to_state -+fp_ssm_jump_to_state -| --fpi_ssm_mark_completed -+fp_ssm_mark_completed -| --fpi_ssm_get_user_data -+fp_ssm_get_user_data -| --fpi_ssm_get_cur_state -+fp_ssm_get_cur_state -| --fpi_dev_get_usb_dev -+_fp_device_get_usb_device -| -// HACK: We just insert an error return here! --fpi_imgdev_close_complete(dev) -+_fp_image_device_close_complete(dev, error) -| --fpi_imgdev_open_complete(dev, 0) -+_fp_image_device_open_complete(dev, NULL) -| --fpi_imgdev_activate_complete(dev, 0) -+_fp_image_device_activate_complete(dev, NULL) -| --fpi_imgdev_deactivate_complete(dev) -+_fp_image_device_deactivate_complete(dev, NULL) -| --fpi_imgdev_report_finger_status(dev, status) -+_fp_image_device_report_finger_status(dev, status) -| --fpi_imgdev_image_captured(dev, a1) -+_fp_image_device_image_captured(dev, a1) -| --fpi_imgdev_abort_scan -+_fp_image_device_retry_scan -| --fpi_std_sq_dev -+_fp_std_sq_dev -| --fpi_mean_sq_diff_norm -+_fp_mean_sq_diff_norm -| --fpi_timeout_add(a1, a2, dev, a3) -+_fp_device_add_timeout(dev, a1, a2, a3) -) - -// Some can be nested -@@ -@@ -( --fpi_ssm_next_state_timeout_cb -+fp_ssm_next_state_timeout_cb -) diff --git a/cocci/04-misc-renames.cocci b/cocci/04-misc-renames.cocci deleted file mode 100644 index 8bf40a6e..00000000 --- a/cocci/04-misc-renames.cocci +++ /dev/null @@ -1,29 +0,0 @@ -@@ -typedef FpImageDeviceState; -@@ -( --FP_IMG_COLORS_INVERTED -+FP_IMAGE_COLORS_INVERTED -| --FP_IMG_H_FLIPPED -+FP_IMAGE_H_FLIPPED -| --FP_IMG_V_FLIPPED -+FP_IMAGE_V_FLIPPED -| --FP_VERIFY_RETRY_TOO_SHORT -+FP_DEVICE_RETRY_TOO_SHORT -| --FP_VERIFY_RETRY_CENTER_FINGER -+FP_DEVICE_RETRY_CENTER_FINGER -| --FP_VERIFY_RETRY -+FP_DEVICE_RETRY -) - -@@ -@@ -( --enum fp_imgdev_state -+FpImageDeviceState -) diff --git a/cocci/05-libusb-1.cocci b/cocci/05-libusb-1.cocci deleted file mode 100644 index 0b6cc48f..00000000 --- a/cocci/05-libusb-1.cocci +++ /dev/null @@ -1,118 +0,0 @@ - -@ dev_func @ -identifier dev; -identifier func; -@@ -func(..., FpDevice *dev, ...) -{ - ... -} - -@ imgdev_func @ -identifier dev; -identifier func; -@@ -func(..., FpImageDevice *dev, ...) -{ - ... -} - -@ self_func extends driver @ -identifier self; -identifier func; -@@ -func(..., driver_cls *self, ...) -{ - ... -} - -@ transfer_func_imgdev @ -typedef FpUsbTransfer; -identifier imgdev_func.func; -identifier imgdev_func.dev; -identifier transfer; -@@ -func (...) -{ -<... -( --transfer = fpi_usb_alloc(); -+transfer = fp_usb_transfer_new(FP_DEVICE (dev)); -| --FpUsbTransfer *transfer = fpi_usb_alloc(); -+FpUsbTransfer *transfer = fp_usb_transfer_new(FP_DEVICE (dev)); -) -...> -} - - -@ transfer_func_dev @ -typedef FpUsbTransfer; -identifier dev_func.func; -identifier dev_func.dev; -identifier transfer; -@@ -func (...) -{ -<... -( --transfer = fpi_usb_alloc(); -+transfer = fp_usb_transfer_new(dev); -| --FpUsbTransfer *transfer = fpi_usb_alloc(); -+FpUsbTransfer *transfer = fp_usb_transfer_new(dev); -) -...> -} - -@ transfer_func_self @ -typedef FpUsbTransfer; -identifier self_func.func; -identifier self_func.self; -expression transfer; -@@ -func (...) -{ -<... --transfer = fpi_usb_alloc(); -+transfer = fp_usb_transfer_new(FP_DEVICE (self)); -...> -} - -// None of the release interface calls had error handling ... -@ extends driver @ -expression usb_dev; -expression interface; -@@ -dev_close(...) -{ -+ GError *error = NULL; -... --libusb_release_interface(usb_dev, interface); -+g_usb_device_release_interface(usb_dev, interface, 0, &error); -... -} - -@ extends driver @ -expression usb_dev; -expression interface; -identifier imgdev; -identifier r; -@@ -dev_open (..., FpImageDevice *imgdev, ...) -{ -+ GError *error = NULL; -... --r = libusb_claim_interface(usb_dev, interface); -+if (!g_usb_device_claim_interface(usb_dev, interface, 0, &error)) { -+ _fp_image_device_open_complete (imgdev, error); -+ return; -+ } -( --if (r != 0) { ... } -| --if (r < 0) { ... } -) -... -} - diff --git a/cocci/06-libusb-callback-1.cocci b/cocci/06-libusb-callback-1.cocci deleted file mode 100644 index 643163a4..00000000 --- a/cocci/06-libusb-callback-1.cocci +++ /dev/null @@ -1,344 +0,0 @@ -@ usb_transfer_cb @ -typedef FpUsbTransfer; -typedef FpSsm; -identifier func; -identifier transfer; -identifier dev; -identifier ssm; -@@ -( --void func(FpUsbTransfer *transfer) -+void func(FpUsbTransfer *transfer, -+ FpDevice *device, -+ gpointer user_data, -+ GError *error) -{ -... -} -| -// this is weird, one function in uru4000 didn't get the types -// converted by earlier rules. But, this does not seem to work either. --void func(\(FpUsbTransfer*\|struct libusb_transfer*\) transfer, -- \(FpDevice*\|struct fp_dev*\) dev, -- \(FpSsm*\|fpi_ssm*\) ssm, -- void* user_data) -+void func(FpUsbTransfer *transfer, -+ FpDevice *dev, -+ gpointer user_data, -+ GError *error) -{ -+ FpSsm *ssm = transfer->ssm; -... -} -) - - -@ errors_generic_1 @ -identifier usb_transfer_cb.func; -identifier usb_transfer_cb.transfer; -@@ -func(...) -{ - <... -( -- (transfer->status != LIBUSB_TRANSFER_COMPLETED) -+ error -| -- (transfer->status == LIBUSB_TRANSFER_COMPLETED) -+ !error -| -- (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) -+ g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) -) - ...> -} - - -@ errors_1 @ -identifier usb_transfer_cb.func; -identifier usb_transfer_cb.transfer; -expression ssm; -statement S; -@@ -func(...) -{ - <... - if (error) { -( - ... -- fpi_ssm_mark_failed (ssm, ...) -+ fp_ssm_mark_failed (ssm, error) - ... -| - ... -- fpi_imgdev_session_error (...) -+ _fp_image_device_session_error (FP_IMAGE_DEVICE (device), error) - ... -) - } - ...> -} - -@ errors_1_alt @ -identifier usb_transfer_cb.func; -identifier usb_transfer_cb.transfer; -expression ssm; -statement S; -@@ -func(...) -{ - <... - if (!error) { ... } - else { -( - ... -- fpi_ssm_mark_failed (ssm, ...) -+ fp_ssm_mark_failed (ssm, error) - ... -| - ... -- fpi_imgdev_session_error (...) -+ _fp_image_device_session_error (FP_IMAGE_DEVICE (device), error) - ... -) - } - ...> -} - -@ errors_2 @ -identifier usb_transfer_cb.func; -identifier usb_transfer_cb.transfer; -expression ssm; -@@ -func(...) -{ - <... - if (transfer->length != transfer->actual_length) { -+ _Pragma("GCC warning \"Driver should probably set short_is_error instead!\""); - ... -( -- fpi_ssm_mark_failed (ssm, ...); -+ fp_ssm_mark_failed (ssm, g_error_new (G_USB_DEVICE_ERROR, -+ G_USB_DEVICE_ERROR_IO, -+ "Short USB transfer!")); -| -- fpi_imgdev_session_error (...); -+ _fp_image_device_session_error (FP_IMAGE_DEVICE (device), -+ g_error_new (G_USB_DEVICE_ERROR, -+ G_USB_DEVICE_ERROR_IO, -+ "Short USB transfer!")); -) - ... - } - ...> -} - -@ not_useful_error_prints @ -identifier usb_transfer_cb.func; -@@ -func(...) -{ - <... -- fp_err (...); - ... -( - fp_ssm_mark_failed (...); -| - _fp_image_device_session_error (...); -) - ...> -} - -@ error_or_wrong_length @ -identifier usb_transfer_cb.func; -identifier usb_transfer_cb.transfer; -expression ssm; -@@ -func(...) -{ - <... -- if (error || (transfer->length != transfer->actual_length)) -+ if (error) - { -+ _Pragma("GCC warning \"Driver needs to set short_is_error for this branch to be taken!\""); - <... -( -- fpi_ssm_mark_failed (ssm, ...); -+ fp_ssm_mark_failed (ssm, error); -| -- fpi_imgdev_session_error (...); -+ _fp_image_device_session_error (FP_IMAGE_DEVICE (device), error); -) - ...> - } - ...> -} - -@ error_or_wrong_length_2 @ -identifier usb_transfer_cb.func; -identifier usb_transfer_cb.transfer; -expression ssm; -@@ -func(...) -{ - <... -- if (!error && (transfer->length == transfer->actual_length)) -+ if (!error) - { ... } - else { -+ _Pragma("GCC warning \"Driver needs to set short_is_error for this branch to be taken!\""); - <... -( -- fpi_ssm_mark_failed (ssm, ...); -+ fp_ssm_mark_failed (ssm, error); -| -- fpi_imgdev_session_error (...); -+ _fp_image_device_session_error (FP_IMAGE_DEVICE (device), error); -) - ...> - } - ...> -} - - -@@ -identifier usb_transfer_cb.func; -identifier usb_transfer_cb.transfer; -identifier out; -@@ -func(...) -{ -<... -- goto out; -+ return; -...> --out: -( -- g_free(transfer->buffer); -| -) -- libusb_free_transfer (transfer); -} - -@@ -identifier usb_transfer_cb.func; -identifier usb_transfer_cb.transfer; -@@ -func(...) -{ - <... -( -- g_free(transfer->buffer); -| -) -- libusb_free_transfer (transfer); - ... - return; - ...> -} - - -@@ -identifier usb_transfer_cb.func; -identifier usb_transfer_cb.transfer; -@@ -func(...) -{ - <... -- transfer->user_data -+ user_data - ...> -} - -@@ -typedef gint; -identifier usb_transfer_cb.func; -identifier usb_transfer_cb.transfer; -@@ -func(...) -{ -<... -( - fp_dbg -| - fp_warn -| - fp_err -) - (..., -- transfer->length -+ (gint) transfer->length - , ...); -...> -} - -@@ -typedef gint; -identifier usb_transfer_cb.func; -identifier usb_transfer_cb.transfer; -@@ -func(...) -{ -<... -( - fp_dbg -| - fp_warn -| - fp_err -) - (..., -- transfer->actual_length -+ (gint) transfer->actual_length - , ...); -...> -} - -@@ -identifier usb_transfer_cb.func; -identifier usb_transfer_cb.transfer; -identifier ssm_var; -gpointer user_data; -@@ -func(...) -{ - ... -( -- FpSsm *ssm_var = (FpSsm*) user_data; -| -- FpSsm *ssm_var = user_data; -) - <... -- ssm_var -+ transfer->ssm - ...> -} - -// A lot of drivers abuse the SSM user_data for the driver -// Convert FpImageDevice usage to simple cast -@@ -identifier usb_transfer_cb.func; -identifier dev; -@@ -func(...) -{ --FpImageDevice *dev = ...; -+FpImageDevice *dev = FP_IMAGE_DEVICE (device); -... -} - -// A lot of drivers abuse the SSM user_data for the driver -// Remove FpDevice getter and use argument -@@ -identifier usb_transfer_cb.func; -identifier arg; -identifier dev; -@@ -func(..., FpDevice *arg, ...) -{ --FpDevice *dev = ...; -<... --dev -+arg -...> -} diff --git a/cocci/07-libusb-fill.cocci b/cocci/07-libusb-fill.cocci deleted file mode 100644 index 04fca269..00000000 --- a/cocci/07-libusb-fill.cocci +++ /dev/null @@ -1,163 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// bulk transfers -@@ -typedef FpUsbTransfer; -expression transfer; -expression usb_dev; -expression endpoint; -expression data; -expression size; -expression cb; -expression user_data; -expression timeout; -identifier ret; -@@ -- libusb_fill_bulk_transfer(transfer, usb_dev, endpoint, data, size, cb, user_data, timeout); -+ fp_usb_transfer_fill_bulk_full(transfer, endpoint, data, size, NULL); -+ fp_usb_transfer_submit(transfer, timeout, NULL, cb, user_data); -+ fp_usb_transfer_unref(transfer); -( -- ret = libusb_submit_transfer(transfer); - ... -( -- if (ret < 0) { ... } -| -- if (ret != 0) { ... } -| -) -| -- if (libusb_submit_transfer(transfer)) { ... } -| -- if (libusb_submit_transfer(transfer) < 0) { ... } -| -- libusb_submit_transfer(transfer); -) - -/////////////////////////////////////////////////////////////////////////// -// bulk transfers -@@ -typedef FpUsbTransfer; -expression transfer; -expression dev; -expression transfer_ssm; -expression endpoint; -expression data; -expression size; -expression cb; -expression user_data; -expression timeout; -expression storage; -identifier ret; -@@ -- transfer = fpi_usb_fill_bulk_transfer(dev, transfer_ssm, endpoint, data, size, cb, user_data, timeout); -+ transfer = fp_usb_transfer_new (dev); -+ transfer->ssm = transfer_ssm; -+ fp_usb_transfer_fill_bulk_full(transfer, endpoint, data, size, NULL); -+ fp_usb_transfer_submit(transfer, timeout, NULL, cb, user_data); -+ fp_usb_transfer_unref(transfer); -( - storage = transfer; -| -) -( -- ret = fpi_usb_submit_transfer(transfer); - ... -( -- if (ret < 0) { ... } -| -- if (ret != 0) { ... } -| -) -| -- if (fpi_usb_submit_transfer(transfer)) { ... } -| -- if (fpi_usb_submit_transfer(transfer) < 0) { ... } -| -- fpi_usb_submit_transfer(transfer); -) - -// The following only happens due to some prior simplifications we did -@@ -typedef FpUsbTransfer; -expression transfer; -expression usb_dev; -expression endpoint; -expression data; -expression size; -expression cb; -expression user_data; -expression timeout; -identifier ret; -@@ -- libusb_fill_bulk_transfer(transfer, usb_dev, endpoint, data, size, cb, user_data, timeout); -- libusb_submit_transfer(transfer); -+ fp_usb_transfer_fill_bulk_full(transfer, endpoint, data, size, NULL); -+ fp_usb_transfer_submit(transfer, timeout, NULL, cb, user_data); -+ fp_usb_transfer_unref(transfer); - - -/////////////////////////////////////////////////////////////////////////// -// control transfers -@@ -typedef FpUsbTransfer; -expression timeout; -expression direction; -expression request_type; -expression recipient; -expression request; -expression value; -expression index; -expression length; -expression callback; -expression user_data; -expression usb_dev; -identifier ret; -@@ -( -- data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE) -| -- data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + ...) -| -- data = g_malloc0(LIBUSB_CONTROL_SETUP_SIZE) -| -- data = g_malloc0(LIBUSB_CONTROL_SETUP_SIZE + ...) -) -- ; -+ _Pragma("GCC warning \"control transfer filling is a mess due to automatic translation\""); -+ fp_usb_transfer_fill_control(transfer, !((request_type) & 0x80), ((request_type) >> 5) & 0x3, (request_type) & 0x1f, request, value, index, length); -+ data = transfer->buffer; -+ fp_usb_transfer_submit(transfer, timeout, NULL, callback, user_data); -+ fp_usb_transfer_unref(transfer); - ... -- libusb_fill_control_setup(data, request_type, request, value, index, length); -- libusb_fill_control_transfer(transfer, usb_dev, data, callback, user_data, timeout); - <... -- LIBUSB_CONTROL_SETUP_SIZE - ...> -- ret = libusb_submit_transfer(transfer); -( -- if (ret < 0) { ... } -| -) - - -/////////////////////////////////////////////////////////////////////////// -// We have a field in the transfer just for a state machine, use that -// We also later modify all similar code on the callback side to use that field -// instead. -@@ -expression transfer; -expression timeout; -expression cb; -@@ -+ transfer->ssm = ssm; -- fp_usb_transfer_submit(transfer, timeout, NULL, cb, ssm); -+ fp_usb_transfer_submit(transfer, timeout, NULL, cb, NULL); -@@ -expression transfer; -expression timeout; -expression cb; -@@ -- fp_usb_transfer_submit(transfer, timeout, NULL, cb, dev); -+ fp_usb_transfer_submit(transfer, timeout, NULL, cb, NULL); - diff --git a/cocci/08-ssm.cocci b/cocci/08-ssm.cocci deleted file mode 100644 index 00397797..00000000 --- a/cocci/08-ssm.cocci +++ /dev/null @@ -1,20 +0,0 @@ -@ ssm_callbacks @ -identifier ssm; -identifier cb; -@@ -fp_ssm_start(ssm, cb) - -@@ -identifier ssm_callbacks.cb; -identifier ssm; -identifier dev; -identifier user_data; -@@ -void cb(FpSsm *ssm, FpDevice *dev, void* user_data -+ , GError *error - ) -{ -+ _Pragma("GCC warning \"Check that error is returned/free'ed properly!\""); - ... -} - diff --git a/cocci/10-driver.cocci b/cocci/10-driver.cocci deleted file mode 100644 index cac0212d..00000000 --- a/cocci/10-driver.cocci +++ /dev/null @@ -1,386 +0,0 @@ -@ orig_driver_struct @ -identifier driver_struct; -@@ -struct fp_img_driver driver_struct = { - ..., -}; - -// Grab the type of the main device struct using a rather blind fashion, -// and remove it from the init function. -// This assume that only device init calls fp_dev_set_instance_data, which -// is a fair assumption after all -@ orig_device_struct @ -type device_struct; -expression dev; -identifier dev_init; -identifier data; -@@ -dev_init(...) -{ - // Note: We redefine it to an instance access for now, which will be - // made to work correctly with a later transform/cast. -... - device_struct *data; -... -( -- data = g_malloc0(sizeof(*data)); -+ data = FP_INSTANCE_DATA(dev); -| -- data = (device_struct*) g_malloc0(sizeof(*data)); -+ data = FP_INSTANCE_DATA(dev); -| -- data = g_malloc0(sizeof(device_struct)); -+ data = FP_INSTANCE_DATA(dev); -) -... -- fp_dev_set_instance_data(dev, data); -... -} - -@ driver_ids @ -typedef FpIdEntry; -identifier driver_id_table; -@@ --const struct usb_id driver_id_table[] = { -+const FpIdEntry driver_id_table[] = { - ... -}; - - -@ @ -identifier driver_ids.driver_id_table; -expression entry_vid; -expression entry_pid; -@@ -const FpIdEntry driver_id_table[] = { - ..., { -- .vendor = entry_vid, .product = entry_pid, -+ .vid = entry_vid, .pid = entry_pid, - }, ... -}; - -@ @ -identifier driver_ids.driver_id_table; -expression entry_vid; -expression entry_pid; -expression entry_data; -@@ -const FpIdEntry driver_id_table[] = { - ..., { -- .vendor = entry_vid, .product = entry_pid, .device_data = entry_data -+ .vid = entry_vid, .pid = entry_pid, .driver_data = entry_data - }, ... -}; - -@ @ -identifier driver_ids.driver_id_table; -expression entry_vid; -expression entry_pid; -expression entry_data; -@@ -const FpIdEntry driver_id_table[] = { - ..., { -- entry_vid, entry_pid, entry_data -+ .vid = entry_vid, .pid = entry_pid, .driver_data = entry_data - }, ... -}; - - - -@ driver_info extends orig_driver_struct @ -expression driver_full_name; -identifier driver_id_table; -identifier dev_open; -identifier dev_close; -identifier dev_scan_type; -@@ -struct fp_img_driver driver_struct = { - .driver = { - .full_name = driver_full_name, - .id_table = driver_id_table, - .scan_type = dev_scan_type, - }, - - .open = dev_open, - .close = dev_close, -}; - -@ script:python driver_gobj @ -driver_struct << orig_driver_struct.driver_struct; - -driver_id; -driver_init; -driver_cls; -_driver_cls; -driver_klass; -driver_class_init; -driver_ns; -driver_cast; -driver_cast_no_prefix; -@@ - -import os - -driver_id = driver_struct.split('_')[:-1] - -driver_cls = "FpDevice" + "".join(d[0].upper() + d[1:] for d in driver_id) -driver_id = '_'.join(driver_id) - -driver_ns = "fp_device_" + driver_id -driver_cast = driver_ns.upper() -driver_cast_no_prefix = driver_ns.upper()[3:] - -coccinelle.driver_id = cocci.make_expr('"%s"' % driver_id) -coccinelle.driver_cls = cocci.make_type(driver_cls) -coccinelle._driver_cls = cocci.make_type('struct _' + driver_cls) -coccinelle.driver_klass = cocci.make_type(driver_cls + 'Class') -coccinelle.driver_ns = cocci.make_ident(driver_ns) -coccinelle.driver_init = cocci.make_ident(driver_ns + '_init') -coccinelle.driver_class_init = cocci.make_ident(driver_ns + '_class_init') -coccinelle.driver_cast = cocci.make_ident(driver_cast) -coccinelle.driver_cast_no_prefix = cocci.make_ident(driver_cast_no_prefix) - -############################################################################# - -@ driver @ -typedef FpDeviceClass; -typedef FpImageDeviceClass; - -type orig_device_struct.device_struct; - -identifier orig_driver_struct.driver_struct; - -expression driver_gobj.driver_id; -identifier driver_gobj.driver_ns; -identifier driver_gobj.driver_init; -identifier driver_gobj.driver_class_init; -identifier driver_gobj.driver_cast; -identifier driver_gobj.driver_cast_no_prefix; -type driver_gobj.driver_cls; -type driver_gobj._driver_cls; -type driver_gobj.driver_klass; - -expression driver_info.driver_full_name; -identifier driver_info.driver_id_table; -identifier driver_info.dev_open; -identifier driver_info.dev_close; -identifier driver_info.dev_scan_type; -@@ -struct fp_img_driver driver_struct = { - ... -}; - -+static void -+driver_init(driver_cls *self) -+{ -+} -+ -+static void -+driver_class_init(driver_klass *klass) -+{ -+ FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); -+ FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); -+ -+ dev_class->id = driver_id; -+ dev_class->full_name = driver_full_name; -+ dev_class->type = FP_DEVICE_TYPE_USB; -+ dev_class->id_table = driver_id_table; -+ dev_class->scan_type = dev_scan_type; -+ -+ img_class->img_open = dev_open; -+ img_class->img_close = dev_close; -+ IMG_CLASS_FUNCS; -+} - -///////////////////////////////////////////////////////////////////////// -@ optional_activate extends driver @ -identifier dev_activate; -@@ -struct fp_img_driver driver_struct = { -- .activate = dev_activate, -}; -@@ -identifier optional_activate.dev_activate; -@@ -+ img_class->activate = dev_activate; - IMG_CLASS_FUNCS; - -///////////////////////////////////////////////////////////////////////// -@ optional_deactivate extends driver @ -identifier dev_deactivate; -@@ -struct fp_img_driver driver_struct = { -- .deactivate = dev_deactivate, -}; -@@ -identifier optional_deactivate.dev_deactivate; -@@ -+ img_class->deactivate = dev_deactivate; - IMG_CLASS_FUNCS; - -///////////////////////////////////////////////////////////////////////// -@ optional_change_state extends driver @ -identifier dev_change_state; -@@ -struct fp_img_driver driver_struct = { -- .change_state = dev_change_state, -}; -@@ -identifier optional_change_state.dev_change_state; -@@ -+ img_class->change_state = dev_change_state; - IMG_CLASS_FUNCS; - -///////////////////////////////////////////////////////////////////////// -@ optional_bz3 extends driver @ -expression dev_bz3_threshold; -@@ -struct fp_img_driver driver_struct = { -- .bz3_threshold = dev_bz3_threshold, -}; -@@ -expression optional_bz3.dev_bz3_threshold; -@@ -+ -+ img_class->bz3_threshold = dev_bz3_threshold; - IMG_CLASS_FUNCS; - -///////////////////////////////////////////////////////////////////////// -@ optional_img_size extends driver @ -expression dev_img_width; -expression dev_img_height; -@@ -struct fp_img_driver driver_struct = { -- .img_width = dev_img_width, -- .img_height = dev_img_height, -}; -@@ -expression optional_img_size.dev_img_width; -expression optional_img_size.dev_img_height; -@@ -+ -+ img_class->img_width = dev_img_width; -+ img_class->img_height = dev_img_height; - IMG_CLASS_FUNCS; - -@ remove_placeholder extends driver @ -@@ -- IMG_CLASS_FUNCS; - -@ remove_orig extends driver @ -@@ --struct fp_img_driver driver_struct = { -- ... --}; - -///////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////// -@ type_declaration extends driver @ -@@ --device_struct { -+_driver_cls { -+ FpImageDevice parent; -+ - ... -}; -+#include "TYPE_DECLARATION" - -@ extends driver @ -@@ --#include "TYPE_DECLARATION" - -+G_DECLARE_FINAL_TYPE (driver_cls, driver_ns, FP, driver_cast_no_prefix, FpImageDevice); -+G_DEFINE_TYPE (driver_cls, driver_ns, FP_TYPE_IMAGE_DEVICE); - - -/////////////// -// Change some function declarations -@ extends driver @ -identifier a_driver_data; -@@ --int -+void -dev_open(... -- ,unsigned long a_driver_data - ) { ... } - -@ extends driver @ -@@ --int -+void -dev_activate(...) { ... } - - -///////////////////////////////////////////////////////////////////////// -// Replace all old data with a cast to the new class -///////////////////////////////////////////////////////////////////////// -@ rewrite_dev_struct extends driver @ -identifier func; -identifier data; -identifier dev; -@@ -func(...) -{ - ... -( -- device_struct *data; -+ driver_cls *self; - ... -( -- data = FP_INSTANCE_DATA(FP_DEVICE(dev)); -+ data = driver_cast(dev); -| -- data = FP_INSTANCE_DATA(dev); -+ data = driver_cast(dev); -) -| -- device_struct *data = FP_INSTANCE_DATA(FP_DEVICE(dev)); -+ driver_cls *self = driver_cast(dev); -| -- device_struct *data = FP_INSTANCE_DATA(dev); -+ driver_cls *self = driver_cast(dev); -) - ... -} - -@@ -identifier rewrite_dev_struct.func; -identifier rewrite_dev_struct.data; -@@ -func(...) -{ - <... -- data -+ self - ...> -} - -@ extends driver @ -identifier func; -identifier data; -@@ -func(..., -- device_struct *data, -+ driver_cls *self, -...) -{ - <... -- data -+ self - ...> -} - -// Remove unneccessary self check -@@ -@@ --if (self != NULL) { - ... --} - -// Remove g_free(self) -@@ -@@ --g_free(self); - - - diff --git a/cocci/99-insert-checking-code.cocci b/cocci/99-insert-checking-code.cocci deleted file mode 100644 index b830f202..00000000 --- a/cocci/99-insert-checking-code.cocci +++ /dev/null @@ -1,38 +0,0 @@ -// If we have matches on error conditions, the we likely have a memory -// mangement error. -@ forall @ -identifier error; -statement S; -@@ -if (<+... g_error_matches(error, ...) ...+>) { -+ _Pragma ("GCC error \"Inserted possibly wrong g_error_free!\""); -+ if (error) -+ g_error_free (error); - ... -} else S - -@ forall @ -identifier error; -@@ -if (<+... g_error_matches(error, ...) ...+>) { -+ _Pragma ("GCC error \"Inserted possibly wrong g_error_free!\""); -+ if (error) -+ g_error_free (error); - ... -} - -@@ -expression transfer; -identifier r; -statement S; -@@ -( -- r = libusb_cancel_transfer(transfer); -- if (r < 0) S -+ _Pragma("GCC warning \"Removed libusb_cancel_transfer call!\""); -+ g_warning("USB transfer %p should be cancelled but was not due to a lack of code migration!", transfer); -| -- libusb_cancel_transfer(transfer); -+ _Pragma("GCC warning \"Removed libusb_cancel_transfer call!\""); -+ g_warning("USB transfer %p should be cancelled but was not due to a lack of code migration!", transfer); -) diff --git a/cocci/all.cocci b/cocci/all.cocci deleted file mode 100644 index f031f411..00000000 --- a/cocci/all.cocci +++ /dev/null @@ -1,19 +0,0 @@ -# First some cleanups; some of these are required for the later stuff to work -00-misc-cleanups.cocci -01-endpoint.cocci -04-misc-renames.cocci -03-function-renames.cocci -02-type-renames.cocci - - -# GObject and "driver" defintion -10-driver.cocci - -# -07-libusb-fill.cocci -05-libusb-1.cocci -06-libusb-callback-1.cocci - -08-ssm.cocci - -99-insert-checking-code.cocci diff --git a/cocci/apply-all b/cocci/apply-all deleted file mode 100755 index f2e7f485..00000000 --- a/cocci/apply-all +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -pushd $( dirname "$0" ) -all="all.cocci" -real="/tmp/real.cocci" -cat "$all" | grep -P '^(?!#).+' | xargs cat >$real || exit 1 -popd - -spatch --sp-file $real "$@" From dcc04089d129d4f291194a455298cd97bedd9ede Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Mon, 5 Aug 2019 18:55:41 +0200 Subject: [PATCH 53/73] lib: Remove num_stripes from movement_estimation() fpi_do_movement_estimation is always called with num_stripes set to the length of the list. Rather than using the passed value, assume we should consume all stripes from the list. Closes: #132 --- libfprint/fpi-assembling.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/libfprint/fpi-assembling.c b/libfprint/fpi-assembling.c index b6403cb3..ccd96439 100644 --- a/libfprint/fpi-assembling.c +++ b/libfprint/fpi-assembling.c @@ -128,13 +128,12 @@ find_overlap (struct fpi_frame_asmbl_ctx *ctx, static unsigned int do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx, - GSList *stripes, size_t num_stripes, - gboolean reverse) + GSList *stripes, gboolean reverse) { - GSList *list_entry = stripes; + GSList *l; GTimer *timer; - int frame = 1; - struct fpi_frame *prev_stripe = list_entry->data; + guint num_frames = 0; + struct fpi_frame *prev_stripe; unsigned int min_error; /* Max error is width * height * 255, for AES2501 which has the largest * sensor its 192*16*255 = 783360. So for 32bit value it's ~5482 frame before @@ -142,12 +141,11 @@ do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx, */ unsigned long long total_error = 0; - list_entry = g_slist_next (list_entry); - timer = g_timer_new (); - do + prev_stripe = stripes->data; + for (l = stripes; l != NULL; l = l->next, num_frames++) { - struct fpi_frame *cur_stripe = list_entry->data; + struct fpi_frame *cur_stripe = l->data; if (reverse) { @@ -161,18 +159,14 @@ do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx, } total_error += min_error; - frame++; prev_stripe = cur_stripe; - list_entry = g_slist_next (list_entry); - } - while (frame < num_stripes); g_timer_stop (timer); fp_dbg ("calc delta completed in %f secs", g_timer_elapsed (timer, NULL)); g_timer_destroy (timer); - return total_error / num_stripes; + return total_error / num_frames; } /** @@ -197,11 +191,13 @@ fpi_do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx, { int err, rev_err; - err = do_movement_estimation (ctx, stripes, num_stripes, FALSE); - rev_err = do_movement_estimation (ctx, stripes, num_stripes, TRUE); + g_return_if_fail (g_slist_length(stripes) != num_stripes); + + err = do_movement_estimation (ctx, stripes, FALSE); + rev_err = do_movement_estimation (ctx, stripes, TRUE); fp_dbg ("errors: %d rev: %d", err, rev_err); if (err < rev_err) - do_movement_estimation (ctx, stripes, num_stripes, FALSE); + do_movement_estimation (ctx, stripes, FALSE); } static inline void From 3b480caab151573cc185ba7ad9f15b917d8d6d9e Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Mon, 5 Aug 2019 18:57:55 +0200 Subject: [PATCH 54/73] lib: Remove num_stripes from fpi_do_movement_estimation() --- libfprint/drivers/aes1610.c | 3 +-- libfprint/drivers/aes2501.c | 3 +-- libfprint/drivers/elan.c | 2 +- libfprint/fpi-assembling.c | 8 +------- libfprint/fpi-assembling.h | 3 +-- 5 files changed, 5 insertions(+), 14 deletions(-) diff --git a/libfprint/drivers/aes1610.c b/libfprint/drivers/aes1610.c index 0d3ca4a6..e5977723 100644 --- a/libfprint/drivers/aes1610.c +++ b/libfprint/drivers/aes1610.c @@ -590,8 +590,7 @@ static void capture_read_strip_cb(FpiUsbTransfer *transfer, FpDevice *device, /* send stop capture bits */ aes_write_regv(dev, capture_stop, G_N_ELEMENTS(capture_stop), stub_capture_stop_cb, NULL); self->strips = g_slist_reverse(self->strips); - fpi_do_movement_estimation(&assembling_ctx, self->strips, - self->strips_len); + fpi_do_movement_estimation(&assembling_ctx, self->strips); img = fpi_assemble_frames(&assembling_ctx, self->strips, self->strips_len); diff --git a/libfprint/drivers/aes2501.c b/libfprint/drivers/aes2501.c index 50b34987..bb94d65d 100644 --- a/libfprint/drivers/aes2501.c +++ b/libfprint/drivers/aes2501.c @@ -435,8 +435,7 @@ static void capture_read_strip_cb(FpiUsbTransfer *transfer, FpDevice *_dev, FpImage *img; self->strips = g_slist_reverse(self->strips); - fpi_do_movement_estimation(&assembling_ctx, - self->strips, self->strips_len); + fpi_do_movement_estimation(&assembling_ctx, self->strips); img = fpi_assemble_frames(&assembling_ctx, self->strips, self->strips_len); diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c index 2c4e3be4..36088970 100644 --- a/libfprint/drivers/elan.c +++ b/libfprint/drivers/elan.c @@ -302,7 +302,7 @@ static void elan_submit_image(FpImageDevice *dev) assembling_ctx.frame_height = self->frame_height; assembling_ctx.image_width = self->frame_width * 3 / 2; g_slist_foreach(raw_frames, (GFunc) self->process_frame, &frames); - fpi_do_movement_estimation(&assembling_ctx, frames, num_frames); + fpi_do_movement_estimation(&assembling_ctx, frames); img = fpi_assemble_frames(&assembling_ctx, frames, num_frames); fpi_image_device_image_captured(dev, img); diff --git a/libfprint/fpi-assembling.c b/libfprint/fpi-assembling.c index ccd96439..116d01d5 100644 --- a/libfprint/fpi-assembling.c +++ b/libfprint/fpi-assembling.c @@ -173,7 +173,6 @@ do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx, * fpi_do_movement_estimation: * @ctx: #fpi_frame_asmbl_ctx - frame assembling context * @stripes: a singly-linked list of #fpi_frame - * @num_stripes: number of items in @stripes to process * * fpi_do_movement_estimation() estimates the movement between adjacent * frames, populating @delta_x and @delta_y values for each #fpi_frame. @@ -181,18 +180,13 @@ do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx, * This function is used for devices that don't do movement estimation * in hardware. If hardware movement estimation is supported, the driver * should populate @delta_x and @delta_y instead. - * - * Note that @num_stripes might be shorter than the length of the list, - * if some stripes should be skipped. */ void fpi_do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx, - GSList *stripes, size_t num_stripes) + GSList *stripes) { int err, rev_err; - g_return_if_fail (g_slist_length(stripes) != num_stripes); - err = do_movement_estimation (ctx, stripes, FALSE); rev_err = do_movement_estimation (ctx, stripes, TRUE); fp_dbg ("errors: %d rev: %d", err, rev_err); diff --git a/libfprint/fpi-assembling.h b/libfprint/fpi-assembling.h index ae9adc24..33adcfd2 100644 --- a/libfprint/fpi-assembling.h +++ b/libfprint/fpi-assembling.h @@ -65,8 +65,7 @@ struct fpi_frame_asmbl_ctx }; void fpi_do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx, - GSList *stripes, - size_t num_stripes); + GSList *stripes); FpImage *fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx, GSList *stripes, From f25d0a0dc904ab57a61564025f5ef388d61bc1bb Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 5 Sep 2019 15:26:16 +0200 Subject: [PATCH 55/73] lib: Remove num_stripes from fpi_assemble_frames() --- libfprint/drivers/aes1610.c | 3 +-- libfprint/drivers/aes2501.c | 3 +-- libfprint/drivers/aes2550.c | 3 +-- libfprint/drivers/aesx660.c | 2 +- libfprint/drivers/elan.c | 4 +--- libfprint/fpi-assembling.c | 35 +++++++++-------------------------- libfprint/fpi-assembling.h | 3 +-- 7 files changed, 15 insertions(+), 38 deletions(-) diff --git a/libfprint/drivers/aes1610.c b/libfprint/drivers/aes1610.c index e5977723..374252ea 100644 --- a/libfprint/drivers/aes1610.c +++ b/libfprint/drivers/aes1610.c @@ -591,8 +591,7 @@ static void capture_read_strip_cb(FpiUsbTransfer *transfer, FpDevice *device, aes_write_regv(dev, capture_stop, G_N_ELEMENTS(capture_stop), stub_capture_stop_cb, NULL); self->strips = g_slist_reverse(self->strips); fpi_do_movement_estimation(&assembling_ctx, self->strips); - img = fpi_assemble_frames(&assembling_ctx, self->strips, - self->strips_len); + img = fpi_assemble_frames(&assembling_ctx, self->strips); g_slist_free_full(self->strips, g_free); self->strips = NULL; diff --git a/libfprint/drivers/aes2501.c b/libfprint/drivers/aes2501.c index bb94d65d..c321b8c5 100644 --- a/libfprint/drivers/aes2501.c +++ b/libfprint/drivers/aes2501.c @@ -437,8 +437,7 @@ static void capture_read_strip_cb(FpiUsbTransfer *transfer, FpDevice *_dev, self->strips = g_slist_reverse(self->strips); fpi_do_movement_estimation(&assembling_ctx, self->strips); img = fpi_assemble_frames(&assembling_ctx, - self->strips, - self->strips_len); + self->strips); g_slist_free_full(self->strips, g_free); self->strips = NULL; self->strips_len = 0; diff --git a/libfprint/drivers/aes2550.c b/libfprint/drivers/aes2550.c index 62797549..b8fce056 100644 --- a/libfprint/drivers/aes2550.c +++ b/libfprint/drivers/aes2550.c @@ -227,8 +227,7 @@ static void capture_set_idle_reqs_cb(FpiUsbTransfer *transfer, FpImage *img; self->strips = g_slist_reverse(self->strips); - img = fpi_assemble_frames(&assembling_ctx, - self->strips, self->strips_len); + img = fpi_assemble_frames(&assembling_ctx, self->strips); g_slist_free_full(self->strips, g_free); self->strips = NULL; self->strips_len = 0; diff --git a/libfprint/drivers/aesx660.c b/libfprint/drivers/aesx660.c index 5ea4cae4..b0cc4029 100644 --- a/libfprint/drivers/aesx660.c +++ b/libfprint/drivers/aesx660.c @@ -312,7 +312,7 @@ static void capture_set_idle_cmd_cb(FpiUsbTransfer *transfer, FpDevice *device, FpImage *img; priv->strips = g_slist_reverse(priv->strips); - img = fpi_assemble_frames(cls->assembling_ctx, priv->strips, priv->strips_len); + img = fpi_assemble_frames(cls->assembling_ctx, priv->strips); g_slist_foreach(priv->strips, (GFunc) g_free, NULL); g_slist_free(priv->strips); priv->strips = NULL; diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c index 36088970..9771bb50 100644 --- a/libfprint/drivers/elan.c +++ b/libfprint/drivers/elan.c @@ -288,14 +288,12 @@ static void elan_process_frame_thirds(unsigned short *raw_frame, static void elan_submit_image(FpImageDevice *dev) { FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); - int num_frames; GSList *raw_frames; GSList *frames = NULL; FpImage *img; G_DEBUG_HERE(); - num_frames = self->num_frames - ELAN_SKIP_LAST_FRAMES; raw_frames = g_slist_nth(self->frames, ELAN_SKIP_LAST_FRAMES); assembling_ctx.frame_width = self->frame_width; @@ -303,7 +301,7 @@ static void elan_submit_image(FpImageDevice *dev) assembling_ctx.image_width = self->frame_width * 3 / 2; g_slist_foreach(raw_frames, (GFunc) self->process_frame, &frames); fpi_do_movement_estimation(&assembling_ctx, frames); - img = fpi_assemble_frames(&assembling_ctx, frames, num_frames); + img = fpi_assemble_frames(&assembling_ctx, frames); fpi_image_device_image_captured(dev, img); } diff --git a/libfprint/fpi-assembling.c b/libfprint/fpi-assembling.c index 116d01d5..6df8fff6 100644 --- a/libfprint/fpi-assembling.c +++ b/libfprint/fpi-assembling.c @@ -269,48 +269,37 @@ aes_blit_stripe (struct fpi_frame_asmbl_ctx *ctx, * fpi_assemble_frames: * @ctx: #fpi_frame_asmbl_ctx - frame assembling context * @stripes: linked list of #fpi_frame - * @num_stripes: number of items in @stripes to process * * fpi_assemble_frames() assembles individual frames into a single image. * It expects @delta_x and @delta_y of #fpi_frame to be populated. * - * Note that @num_stripes might be shorter than the length of the list, - * if some stripes should be skipped. - * * Returns: a newly allocated #fp_img. */ FpImage * fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx, - GSList *stripes, size_t num_stripes) + GSList *stripes) { - GSList *stripe; + GSList *l; FpImage *img; int height = 0; - int i, y, x; + int y, x; gboolean reverse = FALSE; struct fpi_frame *fpi_frame; //FIXME g_return_if_fail - BUG_ON (num_stripes == 0); + g_return_val_if_fail (stripes != NULL, NULL); BUG_ON (ctx->image_width < ctx->frame_width); - /* Calculate height */ - i = 0; - stripe = stripes; - /* No offset for 1st image */ - fpi_frame = stripe->data; + fpi_frame = stripes->data; fpi_frame->delta_x = 0; fpi_frame->delta_y = 0; - do + for (l = stripes; l != NULL; l = l->next) { - fpi_frame = stripe->data; + fpi_frame = l->data; height += fpi_frame->delta_y; - i++; - stripe = g_slist_next (stripe); } - while (i < num_stripes); fp_dbg ("height is %d", height); @@ -331,14 +320,12 @@ fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx, img->height = height; /* Assemble stripes */ - i = 0; - stripe = stripes; y = reverse ? (height - ctx->frame_height) : 0; x = (ctx->image_width - ctx->frame_width) / 2; - do + for (l = stripes; l != NULL; l = l->next) { - fpi_frame = stripe->data; + fpi_frame = l->data; if(reverse) { @@ -353,11 +340,7 @@ fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx, y += fpi_frame->delta_y; x += fpi_frame->delta_x; } - - stripe = g_slist_next (stripe); - i++; } - while (i < num_stripes); return img; } diff --git a/libfprint/fpi-assembling.h b/libfprint/fpi-assembling.h index 33adcfd2..77e3c558 100644 --- a/libfprint/fpi-assembling.h +++ b/libfprint/fpi-assembling.h @@ -68,8 +68,7 @@ void fpi_do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx, GSList *stripes); FpImage *fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx, - GSList *stripes, - size_t num_stripes); + GSList *stripes); /** * fpi_line_asmbl_ctx: From 6a1e7103f60f9f61ceb031c52c920b5fe322dbc0 Mon Sep 17 00:00:00 2001 From: Vincent Huang Date: Thu, 31 Oct 2019 08:05:43 +0100 Subject: [PATCH 56/73] synaptics: Put sensor into lower power mode after closing --- libfprint/drivers/synaptics/bmkt_message.c | 3 ++ libfprint/drivers/synaptics/synaptics.c | 33 +++++++++++++++++----- tests/synaptics/custom.ioctl | 3 ++ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/libfprint/drivers/synaptics/bmkt_message.c b/libfprint/drivers/synaptics/bmkt_message.c index fe0bebe9..78dec262 100644 --- a/libfprint/drivers/synaptics/bmkt_message.c +++ b/libfprint/drivers/synaptics/bmkt_message.c @@ -405,6 +405,9 @@ int bmkt_parse_message_payload(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) ret = parse_get_version_report(msg_resp, resp); resp->complete = 1; break; + case BMKT_RSP_POWER_DOWN_READY: + resp->complete = 1; + break; } return ret; diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index 8d08f0d6..d5efa2a8 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -1013,6 +1013,31 @@ fps_init_msg_cb(FpiDeviceSynaptics *self, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); } } +static void +fps_deinit_cb(FpiDeviceSynaptics *self, + bmkt_response_t *resp, + GError *error) +{ + /* Release usb interface */ + g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE (self)), 0, 0, &error); + + g_clear_object (&self->interrupt_cancellable); + + if (!error) { + switch (resp->response_id) { + case BMKT_RSP_POWER_DOWN_READY: + fp_info("Fingerprint sensor ready to be powered down"); + break; + case BMKT_RSP_POWER_DOWN_FAIL: + fp_info("Failed to go to power down mode: %d", resp->result); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Power down failed"); + + break; + } + } + fpi_device_close_complete(FP_DEVICE (self), error); +} static void dev_init (FpDevice *device) @@ -1043,16 +1068,10 @@ static void dev_exit(FpDevice *device) { FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); - GError *error = NULL; G_DEBUG_HERE(); - /* Release usb interface */ - g_usb_device_release_interface(fpi_device_get_usb_device(device), 0, 0, &error); - - g_clear_object (&self->interrupt_cancellable); - - fpi_device_close_complete(device, error); + synaptics_sensor_cmd (self, 0, BMKT_CMD_POWER_DOWN_NOTIFY, NULL, 0, fps_deinit_cb); } static void diff --git a/tests/synaptics/custom.ioctl b/tests/synaptics/custom.ioctl index 4739bfc4..370a8e07 100644 --- a/tests/synaptics/custom.ioctl +++ b/tests/synaptics/custom.ioctl @@ -181,3 +181,6 @@ USBDEVFS_REAPURBNDELAY 0 3 1 0 0 35 35 0 A7FE04651E4650312D30303030303030302D302 USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 39 0 0000FE0468214F2B014650312D30303030303030302D302D30303030303030302D6E6F626F6479 USBDEVFS_REAPURBNDELAY 0 3 1 0 0 36 36 0 A7FE05811F014650312D30303030303030302D302D30303030303030302D6E6F626F6479 USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 37 0 0000FE05831F014650312D30303030303030302D302D30303030303030302D6E6F626F6479 +USBDEVFS_REAPURBNDELAY 0 3 1 0 0 5 5 0 A7FE06A100 + USBDEVFS_REAPURBNDELAY 0 3 129 0 0 266 6 0 0000FE06A200 + From 65e602d8c72baa7020efb62d10bf28e621feb05d Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 13 Nov 2019 17:56:55 +0100 Subject: [PATCH 57/73] log: Re-indent fpi-log using uncrustify --- libfprint/fpi-assembling.c | 4 ++-- libfprint/fpi-log.h | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libfprint/fpi-assembling.c b/libfprint/fpi-assembling.c index 6df8fff6..634a50f0 100644 --- a/libfprint/fpi-assembling.c +++ b/libfprint/fpi-assembling.c @@ -183,7 +183,7 @@ do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx, */ void fpi_do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx, - GSList *stripes) + GSList *stripes) { int err, rev_err; @@ -277,7 +277,7 @@ aes_blit_stripe (struct fpi_frame_asmbl_ctx *ctx, */ FpImage * fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx, - GSList *stripes) + GSList *stripes) { GSList *l; FpImage *img; diff --git a/libfprint/fpi-log.h b/libfprint/fpi-log.h index 177e0f7e..1c3d5ade 100644 --- a/libfprint/fpi-log.h +++ b/libfprint/fpi-log.h @@ -80,19 +80,19 @@ * * Uses fp_err() to print an error if the @condition is true. */ -#define BUG_ON(condition) G_STMT_START \ - if (condition) { \ - char *s; \ - s = g_strconcat ("BUG: (", #condition, ")", NULL); \ - fp_err ("%s: %s() %s:%d", s, G_STRFUNC, __FILE__, __LINE__); \ - g_free (s); \ - } G_STMT_END +#define BUG_ON(condition) G_STMT_START \ + if (condition) { \ + char *s; \ + s = g_strconcat ("BUG: (", #condition, ")", NULL); \ + fp_err ("%s: %s() %s:%d", s, G_STRFUNC, __FILE__, __LINE__); \ + g_free (s); \ + } G_STMT_END /** * BUG: * * Same as BUG_ON() but is always true. */ -#define BUG() BUG_ON(1) +#define BUG() BUG_ON (1) #endif From 33530d62c7d1729476715d0da81eea96880c5a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Mon, 18 Nov 2019 16:44:05 +0100 Subject: [PATCH 58/73] device: Only connect to cancellable if device supports cancellation We are actually using the cancel idle source in case the device supports cancellation, so only connect to the cancellable in such case, and use an utility function to do it and disconnect and reset the state everywhere. --- libfprint/fp-device.c | 184 +++++++++++++----------------------------- 1 file changed, 58 insertions(+), 126 deletions(-) diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c index fe477982..ed33322d 100644 --- a/libfprint/fp-device.c +++ b/libfprint/fp-device.c @@ -285,19 +285,50 @@ fp_device_cancel_in_idle_cb (gpointer user_data) static void fp_device_cancelled_cb (GCancellable *cancellable, FpDevice *self) { - FpDeviceClass *cls = FP_DEVICE_GET_CLASS (self); FpDevicePrivate *priv = fp_device_get_instance_private (self); - if (cls->cancel) + priv->current_idle_cancel_source = g_idle_source_new (); + g_source_set_callback (priv->current_idle_cancel_source, + fp_device_cancel_in_idle_cb, + self, + NULL); + g_source_attach (priv->current_idle_cancel_source, NULL); + g_source_unref (priv->current_idle_cancel_source); +} + +static void +maybe_cancel_on_cancelled (FpDevice *device, + GCancellable *cancellable) +{ + FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device); + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + if (!cancellable || !cls->cancel) + return; + + priv->current_cancellable_id = g_cancellable_connect (cancellable, + G_CALLBACK (fp_device_cancelled_cb), + device, + NULL); +} + +static GTask* +reset_device_state (FpDevice *device) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); + + if (priv->current_cancellable_id) { - priv->current_idle_cancel_source = g_idle_source_new (); - g_source_set_callback (priv->current_idle_cancel_source, - fp_device_cancel_in_idle_cb, - self, - NULL); - g_source_attach (priv->current_idle_cancel_source, NULL); - g_source_unref (priv->current_idle_cancel_source); + g_cancellable_disconnect (g_task_get_cancellable (priv->current_task), + priv->current_cancellable_id); + priv->current_cancellable_id = 0; } + + priv->current_action = FP_DEVICE_ACTION_NONE; + + return g_steal_pointer (&priv->current_task); } static void @@ -435,13 +466,7 @@ fp_device_async_initable_init_async (GAsyncInitable *initable, priv->current_action = FP_DEVICE_ACTION_PROBE; priv->current_task = g_steal_pointer (&task); - if (cancellable) - { - priv->current_cancellable_id = g_cancellable_connect (cancellable, - G_CALLBACK (fp_device_cancelled_cb), - self, - NULL); - } + maybe_cancel_on_cancelled (self, cancellable); FP_DEVICE_GET_CLASS (self)->probe (self); } @@ -735,13 +760,7 @@ fp_device_open (FpDevice *device, priv->current_action = FP_DEVICE_ACTION_OPEN; priv->current_task = g_steal_pointer (&task); - if (cancellable) - { - priv->current_cancellable_id = g_cancellable_connect (cancellable, - G_CALLBACK (fp_device_cancelled_cb), - device, - NULL); - } + maybe_cancel_on_cancelled (device, cancellable); FP_DEVICE_GET_CLASS (device)->open (device); } @@ -805,13 +824,7 @@ fp_device_close (FpDevice *device, priv->current_action = FP_DEVICE_ACTION_CLOSE; priv->current_task = g_steal_pointer (&task); - if (cancellable) - { - priv->current_cancellable_id = g_cancellable_connect (cancellable, - G_CALLBACK (fp_device_cancelled_cb), - device, - NULL); - } + maybe_cancel_on_cancelled (device, cancellable); FP_DEVICE_GET_CLASS (device)->close (device); } @@ -909,13 +922,7 @@ fp_device_enroll (FpDevice *device, priv->current_action = FP_DEVICE_ACTION_ENROLL; priv->current_task = g_steal_pointer (&task); - if (cancellable) - { - priv->current_cancellable_id = g_cancellable_connect (cancellable, - G_CALLBACK (fp_device_cancelled_cb), - device, - NULL); - } + maybe_cancel_on_cancelled (device, cancellable); data = g_new0 (FpEnrollData, 1); data->print = g_object_ref_sink (template_print); @@ -991,13 +998,7 @@ fp_device_verify (FpDevice *device, priv->current_action = FP_DEVICE_ACTION_VERIFY; priv->current_task = g_steal_pointer (&task); - if (cancellable) - { - priv->current_cancellable_id = g_cancellable_connect (cancellable, - G_CALLBACK (fp_device_cancelled_cb), - device, - NULL); - } + maybe_cancel_on_cancelled (device, cancellable); g_task_set_task_data (priv->current_task, g_object_ref (enrolled_print), @@ -1090,13 +1091,7 @@ fp_device_identify (FpDevice *device, priv->current_action = FP_DEVICE_ACTION_IDENTIFY; priv->current_task = g_steal_pointer (&task); - if (cancellable) - { - priv->current_cancellable_id = g_cancellable_connect (cancellable, - G_CALLBACK (fp_device_cancelled_cb), - device, - NULL); - } + maybe_cancel_on_cancelled (device, cancellable); g_task_set_task_data (priv->current_task, g_ptr_array_ref (prints), @@ -1189,13 +1184,7 @@ fp_device_capture (FpDevice *device, priv->current_action = FP_DEVICE_ACTION_CAPTURE; priv->current_task = g_steal_pointer (&task); - if (cancellable) - { - priv->current_cancellable_id = g_cancellable_connect (cancellable, - G_CALLBACK (fp_device_cancelled_cb), - device, - NULL); - } + maybe_cancel_on_cancelled (device, cancellable); priv->wait_for_finger = wait_for_finger; @@ -1276,13 +1265,7 @@ fp_device_delete_print (FpDevice *device, priv->current_action = FP_DEVICE_ACTION_DELETE; priv->current_task = g_steal_pointer (&task); - if (cancellable) - { - priv->current_cancellable_id = g_cancellable_connect (cancellable, - G_CALLBACK (fp_device_cancelled_cb), - device, - NULL); - } + maybe_cancel_on_cancelled (device, cancellable); g_task_set_task_data (priv->current_task, g_object_ref (enrolled_print), @@ -1352,13 +1335,7 @@ fp_device_list_prints (FpDevice *device, priv->current_action = FP_DEVICE_ACTION_LIST; priv->current_task = g_steal_pointer (&task); - if (cancellable) - { - priv->current_cancellable_id = g_cancellable_connect (cancellable, - G_CALLBACK (fp_device_cancelled_cb), - device, - NULL); - } + maybe_cancel_on_cancelled (device, cancellable); FP_DEVICE_GET_CLASS (device)->list (device); } @@ -1839,12 +1816,7 @@ fpi_device_probe_complete (FpDevice *device, g_debug ("Device reported probe completion"); - task = g_steal_pointer (&priv->current_task); - g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); - if (priv->current_cancellable_id) - g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); - priv->current_cancellable_id = 0; - priv->current_action = FP_DEVICE_ACTION_NONE; + task = reset_device_state (device); if (!error) { @@ -1887,12 +1859,7 @@ fpi_device_open_complete (FpDevice *device, GError *error) g_debug ("Device reported open completion"); - task = g_steal_pointer (&priv->current_task); - g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); - if (priv->current_cancellable_id) - g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); - priv->current_cancellable_id = 0; - priv->current_action = FP_DEVICE_ACTION_NONE; + task = reset_device_state (device); if (!error) priv->is_open = TRUE; @@ -1922,12 +1889,7 @@ fpi_device_close_complete (FpDevice *device, GError *error) g_debug ("Device reported close completion"); - task = g_steal_pointer (&priv->current_task); - g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); - if (priv->current_cancellable_id) - g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); - priv->current_cancellable_id = 0; - priv->current_action = FP_DEVICE_ACTION_NONE; + task = reset_device_state (device); priv->is_open = FALSE; switch (priv->type) @@ -1978,12 +1940,7 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error) g_debug ("Device reported enroll completion"); - task = g_steal_pointer (&priv->current_task); - g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); - if (priv->current_cancellable_id) - g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); - priv->current_cancellable_id = 0; - priv->current_action = FP_DEVICE_ACTION_NONE; + task = reset_device_state (device); if (!error) { @@ -2036,12 +1993,7 @@ fpi_device_verify_complete (FpDevice *device, g_debug ("Device reported verify completion"); - task = g_steal_pointer (&priv->current_task); - g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); - if (priv->current_cancellable_id) - g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); - priv->current_cancellable_id = 0; - priv->current_action = FP_DEVICE_ACTION_NONE; + task = reset_device_state (device); g_object_set_data_full (G_OBJECT (task), "print", @@ -2100,12 +2052,7 @@ fpi_device_identify_complete (FpDevice *device, g_debug ("Device reported identify completion"); - task = g_steal_pointer (&priv->current_task); - g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); - if (priv->current_cancellable_id) - g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); - priv->current_cancellable_id = 0; - priv->current_action = FP_DEVICE_ACTION_NONE; + task = reset_device_state (device); g_object_set_data_full (G_OBJECT (task), "print", @@ -2153,12 +2100,7 @@ fpi_device_capture_complete (FpDevice *device, g_debug ("Device reported capture completion"); - task = g_steal_pointer (&priv->current_task); - g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); - if (priv->current_cancellable_id) - g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); - priv->current_cancellable_id = 0; - priv->current_action = FP_DEVICE_ACTION_NONE; + task = reset_device_state (device); if (!error) { @@ -2206,12 +2148,7 @@ fpi_device_delete_complete (FpDevice *device, g_debug ("Device reported deletion completion"); - task = g_steal_pointer (&priv->current_task); - g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); - if (priv->current_cancellable_id) - g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); - priv->current_cancellable_id = 0; - priv->current_action = FP_DEVICE_ACTION_NONE; + task = reset_device_state (device); if (!error) g_task_return_boolean (task, TRUE); @@ -2245,12 +2182,7 @@ fpi_device_list_complete (FpDevice *device, g_debug ("Device reported listing completion"); - task = g_steal_pointer (&priv->current_task); - g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); - if (priv->current_cancellable_id) - g_cancellable_disconnect (g_task_get_cancellable (task), priv->current_cancellable_id); - priv->current_cancellable_id = 0; - priv->current_action = FP_DEVICE_ACTION_NONE; + task = reset_device_state (device); if (prints && error) { From 951d482bc6d968b1dbc9631c422a2657d7a02704 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 18 Nov 2019 21:09:50 +0100 Subject: [PATCH 59/73] tests: Skip umockdev based test for missing dependencies Also print a warning if umockdev-run is too old. Note that we still try to run the unreliable tests as they are still useful for development. --- tests/umockdev-test.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/umockdev-test.py b/tests/umockdev-test.py index 931dcae5..f1387d6d 100755 --- a/tests/umockdev-test.py +++ b/tests/umockdev-test.py @@ -10,6 +10,18 @@ import subprocess if len(sys.argv) != 2: print("You need to specify exactly one argument, the directory with test data") +# Check that umockdev is available +try: + umockdev_version = subprocess.check_output(['umockdev-run', '--version']) + version = tuple(int(_) for _ in umockdev_version.split(b'.')) + if version < (0, 13, 2): + print('umockdev is too old for test to be reliable, expect random failures!') + print('Please update umockdev to at least 0.13.2.') +except FileNotFoundError: + print('umockdev-run not found, skipping test!') + print('Please install umockdev.') + sys.exit(77) + edir = os.path.dirname(sys.argv[0]) ddir = sys.argv[1] From 9b3725617582f2e49da532364fd391a2348347e5 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 18 Nov 2019 21:17:43 +0100 Subject: [PATCH 60/73] tests: Only run tests when introspection bindings are build The tests cannot work without the introspection bindings. So put them into a corresponding if branch and also add the correct dependency on libfprint_typelib for them to be run. --- meson.build | 2 +- tests/meson.build | 57 ++++++++++++++++++++++++++--------------------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/meson.build b/meson.build index a5891c2f..6c922e23 100644 --- a/meson.build +++ b/meson.build @@ -6,7 +6,7 @@ project('libfprint', [ 'c', 'cpp' ], 'warning_level=1', 'c_std=c99', ], - meson_version: '>= 0.45.0') + meson_version: '>= 0.46.0') gnome = import('gnome') diff --git a/tests/meson.build b/tests/meson.build index c8bdf769..d02b05a6 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -14,31 +14,36 @@ envs.set('FP_DEVICE_EMULATION', '1') envs.set('NO_AT_BRIDGE', '1') -if 'virtual_image' in drivers - test( - 'virtual-image', - find_program('virtual-image.py'), - args: '--verbose', - env: envs, - ) -endif +if get_option('introspection') + if 'virtual_image' in drivers + test( + 'virtual-image', + find_program('virtual-image.py'), + args: '--verbose', + env: envs, + depends: libfprint_typelib, + ) + endif -if 'vfs5011' in drivers - test( - 'vfs5011', - find_program('umockdev-test.py'), - args: join_paths(meson.current_source_dir(), 'vfs5011'), - env: envs, - timeout: 10, - ) -endif + if 'vfs5011' in drivers + test( + 'vfs5011', + find_program('umockdev-test.py'), + args: join_paths(meson.current_source_dir(), 'vfs5011'), + env: envs, + timeout: 10, + depends: libfprint_typelib, + ) + endif -if 'synaptics' in drivers - test( - 'synaptics', - find_program('umockdev-test.py'), - args: join_paths(meson.current_source_dir(), 'synaptics'), - env: envs, - timeout: 10, - ) -endif \ No newline at end of file + if 'synaptics' in drivers + test( + 'synaptics', + find_program('umockdev-test.py'), + args: join_paths(meson.current_source_dir(), 'synaptics'), + env: envs, + timeout: 10, + depends: libfprint_typelib, + ) + endif +endif From 728335581f977c2afbc2ca57cfaec6a70f8f94cf Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 19 Nov 2019 16:32:46 +0100 Subject: [PATCH 61/73] ci: Run uncrustify in test mode Add a simple check that no one introduced whitespace errors. --- .gitlab-ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5441ee31..20257bde 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -48,6 +48,12 @@ test: - ninja -C _build - meson test -C _build --verbose --no-stdsplit +test_indent: + stage: test + script: + - dnf update -y --nogpgcheck && dnf install -y --nogpgcheck git uncrustify + - scripts/uncrustify.sh --check + .flatpak_script_template: &flatpak_script script: - flatpak-builder --stop-at=${FLATPAK_MODULE} app ${MANIFEST_PATH} From ad920f95972b42060b97b154ac3f7c747523a581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Mon, 18 Nov 2019 19:09:54 +0100 Subject: [PATCH 62/73] device: Complete driver operations in idle When drivers signal that an action is completed, they might be still in the middle of a SSM and so its callback might not be called properly as part of the completion. This could make impossible to chain operations like open->enroll/list with some drivers (hey, synaptics, I'm looking at you!) when the next operation is called from the GAsyncReadyCallback of the previous call. To avoid this to happen, ensure that when a driver completes an operation, we handle the notification to the caller in a next idle iteration, not to end up in a possible broken state. Abstract this by using a function that handles the task return for each used task type to avoid duplicating similar functions doing all the same thing --- libfprint/fp-device.c | 211 +++++++++++++++++++++++++++++------------- 1 file changed, 145 insertions(+), 66 deletions(-) diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c index ed33322d..f9ccb3cc 100644 --- a/libfprint/fp-device.c +++ b/libfprint/fp-device.c @@ -72,6 +72,7 @@ typedef struct GAsyncReadyCallback current_user_cb; gulong current_cancellable_id; GSource *current_idle_cancel_source; + GSource *current_task_idle_return_source; /* State for tasks */ gboolean wait_for_finger; @@ -312,8 +313,8 @@ maybe_cancel_on_cancelled (FpDevice *device, NULL); } -static GTask* -reset_device_state (FpDevice *device) +static void +clear_device_cancel_action (FpDevice *device) { FpDevicePrivate *priv = fp_device_get_instance_private (device); @@ -325,10 +326,6 @@ reset_device_state (FpDevice *device) priv->current_cancellable_id); priv->current_cancellable_id = 0; } - - priv->current_action = FP_DEVICE_ACTION_NONE; - - return g_steal_pointer (&priv->current_task); } static void @@ -361,6 +358,9 @@ fp_device_finalize (GObject *object) g_slist_free_full (priv->sources, (GDestroyNotify) g_source_destroy); + g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy); + g_clear_pointer (&priv->current_task_idle_return_source, g_source_destroy); + g_clear_pointer (&priv->device_id, g_free); g_clear_pointer (&priv->device_name, g_free); @@ -1792,6 +1792,97 @@ fpi_device_action_error (FpDevice *device, } } +typedef enum _FpDeviceTaskReturnType { + FP_DEVICE_TASK_RETURN_INT, + FP_DEVICE_TASK_RETURN_BOOL, + FP_DEVICE_TASK_RETURN_OBJECT, + FP_DEVICE_TASK_RETURN_PTR_ARRAY, + FP_DEVICE_TASK_RETURN_ERROR, +} FpDeviceTaskReturnType; + +typedef struct _FpDeviceTaskReturnData +{ + FpDevice *device; + FpDeviceTaskReturnType type; + gpointer result; +} FpDeviceTaskReturnData; + +static gboolean +fp_device_task_return_in_idle_cb (gpointer user_data) +{ + FpDeviceTaskReturnData *data = user_data; + FpDevicePrivate *priv = fp_device_get_instance_private (data->device); + + g_autoptr(GTask) task = NULL; + + g_debug ("Completing action %d in idle!", priv->current_action); + + task = g_steal_pointer (&priv->current_task); + priv->current_action = FP_DEVICE_ACTION_NONE; + priv->current_task_idle_return_source = NULL; + + switch (data->type) + { + case FP_DEVICE_TASK_RETURN_INT: + g_task_return_int (task, GPOINTER_TO_INT (data->result)); + break; + + case FP_DEVICE_TASK_RETURN_BOOL: + g_task_return_boolean (task, GPOINTER_TO_UINT (data->result)); + break; + + case FP_DEVICE_TASK_RETURN_OBJECT: + g_task_return_pointer (task, data->result, g_object_unref); + break; + + case FP_DEVICE_TASK_RETURN_PTR_ARRAY: + g_task_return_pointer (task, data->result, + (GDestroyNotify) g_ptr_array_unref); + break; + + case FP_DEVICE_TASK_RETURN_ERROR: + g_task_return_error (task, data->result); + break; + + default: + g_assert_not_reached (); + } + + return G_SOURCE_REMOVE; +} + +static void +fp_device_task_return_data_free (FpDeviceTaskReturnData *data) +{ + g_object_unref (data->device); + g_free (data); +} + +static void +fp_device_return_task_in_idle (FpDevice *device, + FpDeviceTaskReturnType return_type, + gpointer return_data) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + FpDeviceTaskReturnData *data; + + data = g_new0 (FpDeviceTaskReturnData, 1); + data->device = g_object_ref (device); + data->type = return_type; + data->result = return_data; + + priv->current_task_idle_return_source = g_idle_source_new (); + g_source_set_priority (priv->current_task_idle_return_source, + g_task_get_priority (priv->current_task)); + g_source_set_callback (priv->current_task_idle_return_source, + fp_device_task_return_in_idle_cb, + data, + (GDestroyNotify) fp_device_task_return_data_free); + + g_source_attach (priv->current_task_idle_return_source, NULL); + g_source_unref (priv->current_task_idle_return_source); +} + /** * fpi_device_probe_complete: * @device: The #FpDevice @@ -1809,14 +1900,12 @@ fpi_device_probe_complete (FpDevice *device, { FpDevicePrivate *priv = fp_device_get_instance_private (device); - g_autoptr(GTask) task = NULL; - g_return_if_fail (FP_IS_DEVICE (device)); g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_PROBE); g_debug ("Device reported probe completion"); - task = reset_device_state (device); + clear_device_cancel_action (device); if (!error) { @@ -1832,11 +1921,12 @@ fpi_device_probe_complete (FpDevice *device, priv->device_name = g_strdup (device_name); g_object_notify_by_pspec (G_OBJECT (device), properties[PROP_NAME]); } - g_task_return_boolean (task, TRUE); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, + GUINT_TO_POINTER (TRUE)); } else { - g_task_return_error (task, error); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); } } @@ -1852,22 +1942,21 @@ fpi_device_open_complete (FpDevice *device, GError *error) { FpDevicePrivate *priv = fp_device_get_instance_private (device); - g_autoptr(GTask) task = NULL; - g_return_if_fail (FP_IS_DEVICE (device)); g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_OPEN); g_debug ("Device reported open completion"); - task = reset_device_state (device); + clear_device_cancel_action (device); if (!error) priv->is_open = TRUE; if (!error) - g_task_return_boolean (task, TRUE); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, + GUINT_TO_POINTER (TRUE)); else - g_task_return_error (task, error); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); } /** @@ -1880,7 +1969,6 @@ fpi_device_open_complete (FpDevice *device, GError *error) void fpi_device_close_complete (FpDevice *device, GError *error) { - g_autoptr(GTask) task = NULL; GError *nested_error = NULL; FpDevicePrivate *priv = fp_device_get_instance_private (device); @@ -1889,7 +1977,7 @@ fpi_device_close_complete (FpDevice *device, GError *error) g_debug ("Device reported close completion"); - task = reset_device_state (device); + clear_device_cancel_action (device); priv->is_open = FALSE; switch (priv->type) @@ -1899,7 +1987,7 @@ fpi_device_close_complete (FpDevice *device, GError *error) { if (error == NULL) error = nested_error; - g_task_return_error (task, error); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); return; } break; @@ -1909,14 +1997,16 @@ fpi_device_close_complete (FpDevice *device, GError *error) default: g_assert_not_reached (); - g_task_return_error (task, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, + fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); return; } if (!error) - g_task_return_boolean (task, TRUE); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, + GUINT_TO_POINTER (TRUE)); else - g_task_return_error (task, error); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); } /** @@ -1933,33 +2023,30 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error) { FpDevicePrivate *priv = fp_device_get_instance_private (device); - g_autoptr(GTask) task = NULL; - g_return_if_fail (FP_IS_DEVICE (device)); g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_ENROLL); g_debug ("Device reported enroll completion"); - task = reset_device_state (device); + clear_device_cancel_action (device); if (!error) { if (FP_IS_PRINT (print)) { - g_task_return_pointer (task, print, g_object_unref); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_OBJECT, print); } else { g_warning ("Driver did not provide a valid print and failed to provide an error!"); - g_task_return_new_error (task, - FP_DEVICE_ERROR, - FP_DEVICE_ERROR_GENERAL, - "Driver failed to provide print data!"); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Driver failed to provide print data!"); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); } } else { - g_task_return_error (task, error); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); if (FP_IS_PRINT (print)) { g_warning ("Driver passed an error but also provided a print, returning error!"); @@ -1986,16 +2073,14 @@ fpi_device_verify_complete (FpDevice *device, { FpDevicePrivate *priv = fp_device_get_instance_private (device); - g_autoptr(GTask) task = NULL; - g_return_if_fail (FP_IS_DEVICE (device)); g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_VERIFY); g_debug ("Device reported verify completion"); - task = reset_device_state (device); + clear_device_cancel_action (device); - g_object_set_data_full (G_OBJECT (task), + g_object_set_data_full (G_OBJECT (priv->current_task), "print", print, g_object_unref); @@ -2004,20 +2089,20 @@ fpi_device_verify_complete (FpDevice *device, { if (result != FPI_MATCH_ERROR) { - g_task_return_int (task, result); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_INT, + GINT_TO_POINTER (result)); } else { g_warning ("Driver did not provide an error for a failed verify operation!"); - g_task_return_new_error (task, - FP_DEVICE_ERROR, - FP_DEVICE_ERROR_GENERAL, - "Driver failed to provide an error!"); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Driver failed to provide an error!"); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); } } else { - g_task_return_error (task, error); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); if (result != FPI_MATCH_ERROR) { g_warning ("Driver passed an error but also provided a match result, returning error!"); @@ -2045,30 +2130,29 @@ fpi_device_identify_complete (FpDevice *device, { FpDevicePrivate *priv = fp_device_get_instance_private (device); - g_autoptr(GTask) task = NULL; - g_return_if_fail (FP_IS_DEVICE (device)); g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_IDENTIFY); g_debug ("Device reported identify completion"); - task = reset_device_state (device); + clear_device_cancel_action (device); - g_object_set_data_full (G_OBJECT (task), + g_object_set_data_full (G_OBJECT (priv->current_task), "print", print, g_object_unref); - g_object_set_data_full (G_OBJECT (task), + g_object_set_data_full (G_OBJECT (priv->current_task), "match", match, g_object_unref); if (!error) { - g_task_return_boolean (task, TRUE); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, + GUINT_TO_POINTER (TRUE)); } else { - g_task_return_error (task, error); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); if (match) { g_warning ("Driver passed an error but also provided a match result, returning error!"); @@ -2093,33 +2177,30 @@ fpi_device_capture_complete (FpDevice *device, { FpDevicePrivate *priv = fp_device_get_instance_private (device); - g_autoptr(GTask) task = NULL; - g_return_if_fail (FP_IS_DEVICE (device)); g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_CAPTURE); g_debug ("Device reported capture completion"); - task = reset_device_state (device); + clear_device_cancel_action (device); if (!error) { if (image) { - g_task_return_pointer (task, image, g_object_unref); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_OBJECT, image); } else { g_warning ("Driver did not provide an error for a failed capture operation!"); - g_task_return_new_error (task, - FP_DEVICE_ERROR, - FP_DEVICE_ERROR_GENERAL, - "Driver failed to provide an error!"); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Driver failed to provide an error!"); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); } } else { - g_task_return_error (task, error); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); if (image) { g_warning ("Driver passed an error but also provided an image, returning error!"); @@ -2141,19 +2222,18 @@ fpi_device_delete_complete (FpDevice *device, { FpDevicePrivate *priv = fp_device_get_instance_private (device); - g_autoptr(GTask) task = NULL; - g_return_if_fail (FP_IS_DEVICE (device)); g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_DELETE); g_debug ("Device reported deletion completion"); - task = reset_device_state (device); + clear_device_cancel_action (device); if (!error) - g_task_return_boolean (task, TRUE); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, + GUINT_TO_POINTER (TRUE)); else - g_task_return_error (task, error); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); } /** @@ -2174,7 +2254,6 @@ fpi_device_list_complete (FpDevice *device, GPtrArray *prints, GError *error) { - g_autoptr(GTask) task = NULL; FpDevicePrivate *priv = fp_device_get_instance_private (device); g_return_if_fail (FP_IS_DEVICE (device)); @@ -2182,7 +2261,7 @@ fpi_device_list_complete (FpDevice *device, g_debug ("Device reported listing completion"); - task = reset_device_state (device); + clear_device_cancel_action (device); if (prints && error) { @@ -2197,9 +2276,9 @@ fpi_device_list_complete (FpDevice *device, } if (!error) - g_task_return_pointer (task, prints, (GDestroyNotify) g_ptr_array_unref); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_PTR_ARRAY, prints); else - g_task_return_error (task, error); + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); } /** From d91ec2d044f3d10227c08b21ba92d1b059cd78bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 19 Nov 2019 20:21:03 +0100 Subject: [PATCH 63/73] examples: Add manage-prints test to list and delete prints Simple example program to list prints in a device with own storage and that allow to delete them (by manual selection or full deletion). --- examples/manage-prints.c | 327 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 examples/manage-prints.c diff --git a/examples/manage-prints.c b/examples/manage-prints.c new file mode 100644 index 00000000..9e6696a8 --- /dev/null +++ b/examples/manage-prints.c @@ -0,0 +1,327 @@ +/* + * Example fingerprint device prints listing and deletion + * Enrolls your right index finger and saves the print to disk + * Copyright (C) 2019 Marco Trevisan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include + +typedef struct _ListData +{ + GMainLoop *loop; + int ret_value; + GList *to_delete; + gboolean any_failed; +} ListData; + +static void +list_data_free (ListData *list_data) +{ + g_list_free_full (list_data->to_delete, g_object_unref); + g_main_loop_unref (list_data->loop); + g_free (list_data); +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC (ListData, list_data_free) + +FpDevice *discover_device (GPtrArray * devices) +{ + FpDevice *dev; + + if (!devices->len) + return NULL; + + dev = g_ptr_array_index (devices, 0); + g_print ("Found device claimed by %s driver\n", fp_device_get_driver (dev)); + return dev; +} + +static void +on_device_closed (FpDevice *dev, + GAsyncResult *res, + gpointer user_data) +{ + ListData *list_data = user_data; + + g_autoptr(GError) error = NULL; + + fp_device_close_finish (dev, res, &error); + + if (error) + g_warning ("Failed closing device %s\n", error->message); + + g_main_loop_quit (list_data->loop); +} + +const char * +finger_to_string (FpFinger finger) +{ + switch (finger) + { + case FP_FINGER_LEFT_THUMB: + return "left thumb"; + + case FP_FINGER_LEFT_INDEX: + return "left index"; + + case FP_FINGER_LEFT_MIDDLE: + return "left middle"; + + case FP_FINGER_LEFT_RING: + return "left ring"; + + case FP_FINGER_LEFT_LITTLE: + return "left little"; + + case FP_FINGER_RIGHT_THUMB: + return "right thumb"; + + case FP_FINGER_RIGHT_INDEX: + return "right index"; + + case FP_FINGER_RIGHT_MIDDLE: + return "right middle"; + + case FP_FINGER_RIGHT_RING: + return "right ring"; + + case FP_FINGER_RIGHT_LITTLE: + return "right little"; + + default: + return "unknown"; + } +} + +typedef struct _DeleteData +{ + ListData *list_data; + FpPrint *print; +} DeleteData; + +static void +delete_data_free (DeleteData *delete_data) +{ + g_object_unref (delete_data->print); + g_free (delete_data); +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC (DeleteData, delete_data_free); + +static void +on_print_deleted (FpDevice *dev, GAsyncResult *res, gpointer user_data); + +static void +delete_next_print (FpDevice *dev, + ListData *list_data) +{ + FpPrint *print; + + g_assert_nonnull (list_data->to_delete); + print = list_data->to_delete->data; + + g_debug ("Deleting print %s\n", fp_print_get_description (print)); + fp_device_delete_print (dev, print, NULL, + (GAsyncReadyCallback) on_print_deleted, list_data); +} + +static void +on_print_deleted (FpDevice *dev, + GAsyncResult *res, + gpointer user_data) +{ + ListData *list_data = user_data; + g_autoptr(GError) error = NULL; + g_autoptr(FpPrint) print = NULL; + GList *deleted_link; + + fp_device_delete_print_finish (dev, res, &error); + + deleted_link = list_data->to_delete; + print = g_steal_pointer (&deleted_link->data); + list_data->to_delete = g_list_delete_link (list_data->to_delete, deleted_link); + + if (error) + { + g_warning("Failed to remove print %s: %s", + fp_print_get_description (print), error->message); + list_data->any_failed = TRUE; + } + else + g_debug ("Deleted print %s from device", fp_print_get_description (print)); + + if (list_data->to_delete != NULL) + { + delete_next_print (dev, list_data); + } + else + { + if (!list_data->any_failed) + list_data->ret_value = EXIT_SUCCESS; + + fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, + list_data); + } +} + +static void +on_list_completed (FpDevice *dev, + GAsyncResult *res, + gpointer user_data) +{ + ListData *list_data = user_data; + g_autoptr(GPtrArray) prints = NULL; + g_autoptr(GError) error = NULL; + + prints = fp_device_list_prints_finish (dev, res, &error); + + if (!error) + { + guint i; + char buf[128]; + + g_print ("Device contains %u prints\n", prints->len); + + for (i = 0; i < prints->len; ++i) + { + FpPrint* print = prints->pdata[i]; + + g_date_strftime (buf, G_N_ELEMENTS (buf), "%Y-%m-%d", + fp_print_get_enroll_date (print)); + g_print ("[%d] Print of %s finger for username %s, enrolled " + "on %s. Description: %s\n", i + 1, + finger_to_string (fp_print_get_finger (print)), + fp_print_get_username (print), buf, + fp_print_get_description (print)); + } + + if (prints->len) + { + gint64 idx = 0; + + g_print ("Want to delete saved print? [/A/n]\n"); + if (fgets (buf, 3, stdin)) + idx = g_ascii_strtoll (buf, NULL, 10); + + if (idx > 0 && idx <= prints->len) + { + FpPrint *print = prints->pdata[idx - 1]; + list_data->to_delete = g_list_prepend (list_data->to_delete, + g_object_ref (print)); + } + else if (buf[0] == 'A') + { + for (i = 0; i < prints->len; ++i) + { + FpPrint *print = prints->pdata[i]; + list_data->to_delete = g_list_prepend (list_data->to_delete, + g_object_ref (print)); + } + } + else + { + if (buf[0] == 'n' || buf[0] == 'N') + list_data->ret_value = EXIT_SUCCESS; + else + g_warning ("Invalid finger selected"); + + fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, + list_data); + } + } + + if (list_data->to_delete) + delete_next_print (dev, list_data); + else + { + fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, + list_data); + } + } + else + { + g_warning ("Getting prints failed with error %s", error->message); + g_main_loop_quit (list_data->loop); + } +} + +static void +on_device_opened (FpDevice *dev, + GAsyncResult *res, + gpointer user_data) +{ + ListData *list_data = user_data; + + g_autoptr(GError) error = NULL; + + if (!fp_device_open_finish (dev, res, &error)) + { + g_warning ("Failed to open device: %s", error->message); + g_main_loop_quit (list_data->loop); + return; + } + + if (!fp_device_has_storage (dev)) + { + g_warning ("Device %s doesn't support storage", fp_device_get_name (dev)); + g_main_loop_quit (list_data->loop); + return; + } + + fp_device_list_prints (dev, NULL, + (GAsyncReadyCallback) on_list_completed, list_data); + +} + +int +main (void) +{ + g_autoptr(FpContext) ctx = NULL; + g_autoptr(ListData) list_data = NULL; + GPtrArray *devices; + FpDevice *dev; + + g_print ("This program will report the prints saved in device\n"); + + setenv ("G_MESSAGES_DEBUG", "all", 0); + + ctx = fp_context_new (); + + devices = fp_context_get_devices (ctx); + if (!devices) + { + g_warning ("Impossible to get devices"); + return EXIT_FAILURE; + } + + dev = discover_device (devices); + if (!dev) + { + g_warning ("No devices detected."); + return EXIT_FAILURE; + } + + list_data = g_new0 (ListData, 1); + list_data->ret_value = EXIT_FAILURE; + list_data->loop = g_main_loop_new (NULL, FALSE); + + fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened, list_data); + + g_main_loop_run (list_data->loop); + + return list_data->ret_value; +} From 256c7cea074de05d74f1aba9b4a5b4d8f315f1d1 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 19 Nov 2019 21:44:16 +0100 Subject: [PATCH 64/73] examples: Remove x11 based examples These examples have not been ported. In addition, they are also not very useful these days, as the demo application offers a much nicer view to view images from a sensor. --- examples/img_capture.c | 108 ------------- examples/img_capture_continuous.c | 261 ------------------------------ examples/meson.build | 10 -- meson.build | 8 - 4 files changed, 387 deletions(-) delete mode 100644 examples/img_capture.c delete mode 100644 examples/img_capture_continuous.c diff --git a/examples/img_capture.c b/examples/img_capture.c deleted file mode 100644 index c65c73d0..00000000 --- a/examples/img_capture.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Example libfprint image capture program - * Copyright (C) 2007 Daniel Drake - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include - -#include - -struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs) -{ - struct fp_dscv_dev *ddev = discovered_devs[0]; - struct fp_driver *drv; - if (!ddev) - return NULL; - - drv = fp_dscv_dev_get_driver(ddev); - printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv)); - return ddev; -} - -int main(void) -{ - int r = 1; - struct fp_dscv_dev *ddev; - struct fp_dscv_dev **discovered_devs; - struct fp_dev *dev; - struct fp_img *img = NULL; - - setenv ("G_MESSAGES_DEBUG", "all", 0); - setenv ("LIBUSB_DEBUG", "3", 0); - - r = fp_init(); - if (r < 0) { - fprintf(stderr, "Failed to initialize libfprint\n"); - exit(1); - } - - discovered_devs = fp_discover_devs(); - if (!discovered_devs) { - fprintf(stderr, "Could not discover devices\n"); - goto out; - } - - ddev = discover_device(discovered_devs); - if (!ddev) { - fp_dscv_devs_free(discovered_devs); - fprintf(stderr, "No devices detected.\n"); - goto out; - } - - dev = fp_dev_open(ddev); - fp_dscv_devs_free(discovered_devs); - if (!dev) { - fprintf(stderr, "Could not open device.\n"); - goto out; - } - - if (!fp_dev_supports_imaging(dev)) { - fprintf(stderr, "this device does not have imaging capabilities.\n"); - goto out_close; - } - - printf("Opened device. It's now time to scan your finger.\n\n"); - - r = fp_dev_img_capture(dev, 0, &img); - if (r) { - fprintf(stderr, "image capture failed, code %d\n", r); - goto out_close; - } - - r = fp_img_save_to_file(img, "finger.pgm"); - if (r) { - fprintf(stderr, "img save failed, code %d\n", r); - goto out_close; - } - - fp_img_standardize(img); - r = fp_img_save_to_file(img, "finger_standardized.pgm"); - fp_img_free(img); - if (r) { - fprintf(stderr, "standardized img save failed, code %d\n", r); - goto out_close; - } - - r = 0; -out_close: - fp_dev_close(dev); -out: - fp_exit(); - return r; -} - diff --git a/examples/img_capture_continuous.c b/examples/img_capture_continuous.c deleted file mode 100644 index f5b5f028..00000000 --- a/examples/img_capture_continuous.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Example libfprint continuous image capture program - * Copyright (C) 2007 Daniel Drake - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include - -#include -#include -#include -#include - -#define FORMAT 0x32595559 - -static int adaptor = -1; -static char *framebuffer = NULL; - -static Display *display = NULL; -static Window window=(Window)NULL; -static XvImage *xv_image = NULL; -static XvAdaptorInfo *info; -static GC gc; -static int connection = -1; - -/* based on macro by Bart Nabbe */ -#define GREY2YUV(grey, y, u, v)\ - y = (9798*grey + 19235*grey + 3736*grey) / 32768;\ - u = (-4784*grey - 9437*grey + 14221*grey) / 32768 + 128;\ - v = (20218*grey - 16941*grey - 3277*grey) / 32768 + 128;\ - y = y < 0 ? 0 : y;\ - u = u < 0 ? 0 : u;\ - v = v < 0 ? 0 : v;\ - y = y > 255 ? 255 : y;\ - u = u > 255 ? 255 : u;\ - v = v > 255 ? 255 : v - -static void grey2yuy2 (unsigned char *grey, char *YUV, int num) { - int i, j; - int y0, y1, u0, u1, v0, v1; - uint64_t gval; - - for (i = 0, j = 0; i < num; i += 2, j += 4) - { - gval = grey[i]; - GREY2YUV (gval, y0, u0 , v0); - gval = grey[i + 1]; - GREY2YUV (gval, y1, u1 , v1); - YUV[j + 0] = y0; - YUV[j + 1] = (u0+u1)/2; - YUV[j + 2] = y1; - YUV[j + 3] = (v0+v1)/2; - } -} - -static void display_frame(struct fp_img *img) -{ - int width = fp_img_get_width(img); - int height = fp_img_get_height(img); - unsigned char *data = fp_img_get_data(img); - - if (adaptor < 0) - return; - - grey2yuy2(data, framebuffer, width * height); - xv_image = XvCreateImage(display, info[adaptor].base_id, FORMAT, - framebuffer, width, height); - XvPutImage(display, info[adaptor].base_id, window, gc, xv_image, - 0, 0, width, height, 0, 0, width, height); -} - -static void QueryXv(void) -{ - unsigned int num_adaptors; - int num_formats; - XvImageFormatValues *formats = NULL; - int i,j; - char xv_name[5]; - - XvQueryAdaptors(display, DefaultRootWindow(display), &num_adaptors, - &info); - - for(i = 0; i < num_adaptors; i++) { - formats = XvListImageFormats(display, info[i].base_id, - &num_formats); - for(j = 0; j < num_formats; j++) { - xv_name[4] = 0; - memcpy(xv_name, &formats[j].id, 4); - if(formats[j].id == FORMAT) { - printf("using Xv format 0x%x %s %s\n", - formats[j].id, xv_name, - (formats[j].format==XvPacked) - ? "packed" : "planar"); - if (adaptor < 0) - adaptor = i; - } - } - } - XFree(formats); - if (adaptor < 0) - printf("No suitable Xv adaptor found\n"); -} - -struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs) -{ - struct fp_dscv_dev *ddev = discovered_devs[0]; - struct fp_driver *drv; - if (!ddev) - return NULL; - - drv = fp_dscv_dev_get_driver(ddev); - printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv)); - return ddev; -} - -int main(void) -{ - int r = 1; - XEvent xev; - XGCValues xgcv; - long background=0x010203; - struct fp_dscv_dev *ddev; - struct fp_dscv_dev **discovered_devs; - struct fp_dev *dev; - int img_width; - int img_height; - int standardize = 0; - - setenv ("G_MESSAGES_DEBUG", "all", 0); - setenv ("LIBUSB_DEBUG", "3", 0); - - r = fp_init(); - if (r < 0) { - fprintf(stderr, "Failed to initialize libfprint\n"); - exit(1); - } - - discovered_devs = fp_discover_devs(); - if (!discovered_devs) { - fprintf(stderr, "Could not discover devices\n"); - goto out; - } - - ddev = discover_device(discovered_devs); - if (!ddev) { - fprintf(stderr, "No devices detected.\n"); - goto out; - } - - dev = fp_dev_open(ddev); - fp_dscv_devs_free(discovered_devs); - if (!dev) { - fprintf(stderr, "Could not open device.\n"); - goto out; - } - - if (!fp_dev_supports_imaging(dev)) { - fprintf(stderr, "this device does not have imaging capabilities.\n"); - goto out_close; - } - - img_width = fp_dev_get_img_width(dev); - img_height = fp_dev_get_img_height(dev); - if (img_width <= 0 || img_height <= 0) { - fprintf(stderr, "this device returns images with variable dimensions," - " this example does not support that.\n"); - goto out_close; - } - framebuffer = malloc(img_width * img_height * 2); - if (!framebuffer) - goto out_close; - - /* make the window */ - display = XOpenDisplay(getenv("DISPLAY")); - if(display == NULL) { - fprintf(stderr,"Could not open display \"%s\"\n", - getenv("DISPLAY")); - goto out_close; - } - - QueryXv(); - - if (adaptor < 0) - goto out_close; - - window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0, - img_width, img_height, 0, - WhitePixel(display, DefaultScreen(display)), background); - - XSelectInput(display, window, StructureNotifyMask | KeyPressMask); - XMapWindow(display, window); - connection = ConnectionNumber(display); - - gc = XCreateGC(display, window, 0, &xgcv); - - printf("Press S to toggle standardized mode, Q to quit\n"); - - while (1) { /* event loop */ - struct fp_img *img; - - r = fp_dev_img_capture(dev, 1, &img); - if (r) { - fprintf(stderr, "image capture failed, code %d\n", r); - goto out_close; - } - if (standardize) - fp_img_standardize(img); - - display_frame(img); - fp_img_free(img); - XFlush(display); - - while (XPending(display) > 0) { - XNextEvent(display, &xev); - if (xev.type != KeyPress) - continue; - - switch (XKeycodeToKeysym(display, xev.xkey.keycode, 0)) { - case XK_q: - case XK_Q: - r = 0; - goto out_close; - break; - case XK_s: - case XK_S: - standardize = !standardize; - break; - } - } /* XPending */ - } - - r = 0; -out_close: - if (framebuffer) - free(framebuffer); - fp_dev_close(dev); - if ((void *) window != NULL) - XUnmapWindow(display, window); - if (display != NULL) - XFlush(display); -out: - fp_exit(); - return r; -} - - diff --git a/examples/meson.build b/examples/meson.build index 90c5257b..216a96e1 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -17,13 +17,3 @@ executable('cpp-test', root_inc, ], c_args: common_cflags) - -# if get_option('x11-examples') -# executable('img_capture_continuous', -# 'img_capture_continuous.c', -# dependencies: [ libfprint_dep, xv_dep, x11_dep ], -# include_directories: [ -# root_inc, -# ], -# c_args: common_cflags) -# endif diff --git a/meson.build b/meson.build index 6c922e23..8d06d450 100644 --- a/meson.build +++ b/meson.build @@ -111,14 +111,6 @@ if get_option('udev_rules') endif endif -# if get_option('x11-examples') -# x11_dep = cc.find_library('X11') -# xv_dep = dependency('xv', required: false) -# if not xv_dep.found() -# error('XV is required for X11 examples') -# endif -# endif - if get_option('gtk-examples') gnome = import('gnome') From cddd0f465311f80cfe1f8a1951f14247e5b41497 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 19 Nov 2019 21:46:56 +0100 Subject: [PATCH 65/73] examples: Remove old verify_live example The example has not been ported and it is not very useful as verify already shows how everything works. --- examples/verify_live.c | 188 ----------------------------------------- 1 file changed, 188 deletions(-) delete mode 100644 examples/verify_live.c diff --git a/examples/verify_live.c b/examples/verify_live.c deleted file mode 100644 index 4c02ff2f..00000000 --- a/examples/verify_live.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Example fingerprint verification program - * Copyright (C) 2007 Daniel Drake - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include - -#include - -struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs) -{ - struct fp_dscv_dev *ddev = discovered_devs[0]; - struct fp_driver *drv; - if (!ddev) - return NULL; - - drv = fp_dscv_dev_get_driver(ddev); - printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv)); - return ddev; -} - -struct fp_print_data *enroll(struct fp_dev *dev) { - struct fp_print_data *enrolled_print = NULL; - int r; - - printf("You will need to successfully scan your finger %d times to " - "complete the process.\n", fp_dev_get_nr_enroll_stages(dev)); - - do { - printf("\nScan your finger now.\n"); - r = fp_enroll_finger(dev, &enrolled_print); - if (r < 0) { - printf("Enroll failed with error %d\n", r); - return NULL; - } - switch (r) { - case FP_ENROLL_COMPLETE: - printf("Enroll complete!\n"); - break; - case FP_ENROLL_FAIL: - printf("Enroll failed, something wen't wrong :(\n"); - return NULL; - case FP_ENROLL_PASS: - printf("Enroll stage passed. Yay!\n"); - break; - case FP_ENROLL_RETRY: - printf("Didn't quite catch that. Please try again.\n"); - break; - case FP_ENROLL_RETRY_TOO_SHORT: - printf("Your swipe was too short, please try again.\n"); - break; - case FP_ENROLL_RETRY_CENTER_FINGER: - printf("Didn't catch that, please center your finger on the " - "sensor and try again.\n"); - break; - case FP_ENROLL_RETRY_REMOVE_FINGER: - printf("Scan failed, please remove your finger and then try " - "again.\n"); - break; - } - } while (r != FP_ENROLL_COMPLETE); - - if (!enrolled_print) { - fprintf(stderr, "Enroll complete but no print?\n"); - return NULL; - } - - printf("Enrollment completed!\n\n"); - return enrolled_print; -} - -int verify(struct fp_dev *dev, struct fp_print_data *data) -{ - int r; - - do { - sleep(1); - printf("\nScan your finger now.\n"); - r = fp_verify_finger(dev, data); - if (r < 0) { - printf("verification failed with error %d :(\n", r); - return r; - } - switch (r) { - case FP_VERIFY_NO_MATCH: - printf("NO MATCH!\n"); - return 0; - case FP_VERIFY_MATCH: - printf("MATCH!\n"); - return 0; - case FP_VERIFY_RETRY: - printf("Scan didn't quite work. Please try again.\n"); - break; - case FP_VERIFY_RETRY_TOO_SHORT: - printf("Swipe was too short, please try again.\n"); - break; - case FP_VERIFY_RETRY_CENTER_FINGER: - printf("Please center your finger on the sensor and try again.\n"); - break; - case FP_VERIFY_RETRY_REMOVE_FINGER: - printf("Please remove finger from the sensor and try again.\n"); - break; - } - } while (1); -} - -int main(void) -{ - int r = 1; - struct fp_dscv_dev *ddev; - struct fp_dscv_dev **discovered_devs; - struct fp_dev *dev; - struct fp_print_data *data; - - setenv ("G_MESSAGES_DEBUG", "all", 0); - setenv ("LIBUSB_DEBUG", "3", 0); - - r = fp_init(); - if (r < 0) { - fprintf(stderr, "Failed to initialize libfprint\n"); - exit(1); - } - - discovered_devs = fp_discover_devs(); - if (!discovered_devs) { - fprintf(stderr, "Could not discover devices\n"); - goto out; - } - - ddev = discover_device(discovered_devs); - if (!ddev) { - fprintf(stderr, "No devices detected.\n"); - goto out; - } - - dev = fp_dev_open(ddev); - fp_dscv_devs_free(discovered_devs); - if (!dev) { - fprintf(stderr, "Could not open device.\n"); - goto out; - } - - printf("Opened device. It's now time to enroll your finger.\n\n"); - data = enroll(dev); - if (!data) - goto out_close; - - - printf("Normally we'd save that print to disk, and recall it at some " - "point later when we want to authenticate the user who just " - "enrolled. In the interests of demonstration, we'll authenticate " - "that user immediately.\n"); - - do { - char buffer[20]; - - verify(dev, data); - printf("Verify again? [Y/n]? "); - fgets(buffer, sizeof(buffer), stdin); - if (buffer[0] != '\n' && buffer[0] != 'y' && buffer[0] != 'Y') - break; - } while (1); - - fp_print_data_free(data); -out_close: - fp_dev_close(dev); -out: - fp_exit(); - return r; -} - - From fd5f511b33ef2dcbd77793b5a8ed8e537c9752ff Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 20 Nov 2019 11:19:14 +0100 Subject: [PATCH 66/73] nbis: Add patch to fix unused variable warning With the spatch to use GLib memory functions a lot of error paths were removed. This causes an unused variable warning, so drop in a further patch to remove the unused variable. --- libfprint/nbis/glib-mem-warning.patch | 13 +++++++++++++ libfprint/nbis/mindtct/shape.c | 2 +- libfprint/nbis/update-from-nbis.sh | 6 +++++- 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 libfprint/nbis/glib-mem-warning.patch diff --git a/libfprint/nbis/glib-mem-warning.patch b/libfprint/nbis/glib-mem-warning.patch new file mode 100644 index 00000000..75b82b45 --- /dev/null +++ b/libfprint/nbis/glib-mem-warning.patch @@ -0,0 +1,13 @@ +diff --git a/libfprint/nbis/mindtct/shape.c b/libfprint/nbis/mindtct/shape.c +index 28bc66c..c399f36 100644 +--- mindtct/shape.c ++++ mindtct/shape.c +@@ -86,7 +86,7 @@ int alloc_shape(SHAPE **oshape, const int xmin, const int ymin, + { + SHAPE *shape; + int alloc_rows, alloc_pts; +- int i, j, y; ++ int i, y; + + /* Compute allocation parameters. */ + /* First, compute the number of scanlines spanned by the shape. */ diff --git a/libfprint/nbis/mindtct/shape.c b/libfprint/nbis/mindtct/shape.c index 28bc66c7..c399f363 100644 --- a/libfprint/nbis/mindtct/shape.c +++ b/libfprint/nbis/mindtct/shape.c @@ -86,7 +86,7 @@ int alloc_shape(SHAPE **oshape, const int xmin, const int ymin, { SHAPE *shape; int alloc_rows, alloc_pts; - int i, j, y; + int i, y; /* Compute allocation parameters. */ /* First, compute the number of scanlines spanned by the shape. */ diff --git a/libfprint/nbis/update-from-nbis.sh b/libfprint/nbis/update-from-nbis.sh index 4e243a24..c8cde80b 100755 --- a/libfprint/nbis/update-from-nbis.sh +++ b/libfprint/nbis/update-from-nbis.sh @@ -180,4 +180,8 @@ sed -i 's/[ \t]*$//' `find -name "*.[ch]"` sed -i '/usebsd.h/d' `find -name "*.[ch]"` # Use GLib memory management -spatch --sp-file glib-memory.cocci --dir . --in-place \ No newline at end of file +spatch --sp-file glib-memory.cocci --dir . --in-place + +# The above leaves an unused variable around, triggering a warning +# remove it. +patch -p0 < glib-mem-warning.patch \ No newline at end of file From d1fb1e26f3b79e54febc94496c1184763cf2af3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 19 Nov 2019 21:13:11 +0100 Subject: [PATCH 67/73] Uncrustify everything except for nbis --- demo/gtk-libfprint-test.c | 664 +- examples/enroll.c | 218 +- examples/manage-prints.c | 23 +- examples/storage.c | 251 +- examples/storage.h | 12 +- examples/verify.c | 306 +- libfprint/drivers/aes1610.c | 1208 +- libfprint/drivers/aes1660.c | 103 +- libfprint/drivers/aes1660.h | 3412 ++--- libfprint/drivers/aes2501.c | 1261 +- libfprint/drivers/aes2501.h | 194 +- libfprint/drivers/aes2550.c | 837 +- libfprint/drivers/aes2550.h | 132 +- libfprint/drivers/aes2660.c | 105 +- libfprint/drivers/aes2660.h | 3374 ++--- libfprint/drivers/aes3500.c | 193 +- libfprint/drivers/aes3k.c | 255 +- libfprint/drivers/aes3k.h | 25 +- libfprint/drivers/aes4000.c | 193 +- libfprint/drivers/aeslib.c | 192 +- libfprint/drivers/aeslib.h | 29 +- libfprint/drivers/aesx660.c | 1069 +- libfprint/drivers/aesx660.h | 63 +- libfprint/drivers/driver_ids.h | 42 +- libfprint/drivers/elan.c | 1676 +-- libfprint/drivers/elan.h | 223 +- libfprint/drivers/etes603.c | 2464 ++-- libfprint/drivers/synaptics/bmkt.h | 244 +- libfprint/drivers/synaptics/bmkt_message.c | 548 +- libfprint/drivers/synaptics/bmkt_message.h | 111 +- libfprint/drivers/synaptics/bmkt_response.h | 578 +- libfprint/drivers/synaptics/sensor.h | 89 +- libfprint/drivers/synaptics/synaptics.c | 1765 +-- libfprint/drivers/synaptics/synaptics.h | 130 +- libfprint/drivers/upek_proto.c | 77 +- libfprint/drivers/upek_proto.h | 3 +- libfprint/drivers/upeksonly.c | 2300 ++-- libfprint/drivers/upeksonly.h | 407 +- libfprint/drivers/upektc.c | 626 +- libfprint/drivers/upektc.h | 3793 +++--- libfprint/drivers/upektc_img.c | 1029 +- libfprint/drivers/upektc_img.h | 164 +- libfprint/drivers/upekts.c | 2230 ++-- libfprint/drivers/uru4000.c | 2079 +-- libfprint/drivers/vcom5s.c | 478 +- libfprint/drivers/vfs0050.c | 1029 +- libfprint/drivers/vfs0050.h | 514 +- libfprint/drivers/vfs101.c | 1968 +-- libfprint/drivers/vfs301.c | 351 +- libfprint/drivers/vfs301.h | 133 +- libfprint/drivers/vfs301_proto.c | 946 +- libfprint/drivers/vfs301_proto_fragments.h | 4902 +++---- libfprint/drivers/vfs5011.c | 1291 +- libfprint/drivers/vfs5011_proto.h | 12164 +++++++++--------- libfprint/drivers/virtual-image.c | 346 +- libfprint/fp_internal.h | 36 +- libfprint/fprint-list-supported-devices.c | 80 +- libfprint/fprint-list-udev-rules.c | 131 +- libfprint/fprint.h | 1 - scripts/uncrustify.sh | 2 +- 60 files changed, 30386 insertions(+), 28683 deletions(-) diff --git a/demo/gtk-libfprint-test.c b/demo/gtk-libfprint-test.c index c460e14a..c6dd90e2 100644 --- a/demo/gtk-libfprint-test.c +++ b/demo/gtk-libfprint-test.c @@ -22,35 +22,36 @@ #include #include -typedef GtkApplication LibfprintDemo; +typedef GtkApplication LibfprintDemo; typedef GtkApplicationClass LibfprintDemoClass; G_DEFINE_TYPE (LibfprintDemo, libfprint_demo, GTK_TYPE_APPLICATION) typedef enum { - IMAGE_DISPLAY_NONE = 0, - IMAGE_DISPLAY_MINUTIAE = 1 << 0, - IMAGE_DISPLAY_BINARY = 1 << 1 + IMAGE_DISPLAY_NONE = 0, + IMAGE_DISPLAY_MINUTIAE = 1 << 0, + IMAGE_DISPLAY_BINARY = 1 << 1 } ImageDisplayFlags; -typedef struct { - GtkApplicationWindow parent_instance; +typedef struct +{ + GtkApplicationWindow parent_instance; - GtkWidget *header_bar; - GtkWidget *mode_stack; - GtkWidget *capture_button; - GtkWidget *cancel_button; - GtkWidget *capture_image; - GtkWidget *spinner; - GtkWidget *instructions; + GtkWidget *header_bar; + GtkWidget *mode_stack; + GtkWidget *capture_button; + GtkWidget *cancel_button; + GtkWidget *capture_image; + GtkWidget *spinner; + GtkWidget *instructions; - GCancellable *cancellable; + GCancellable *cancellable; - gboolean opened; - FpDevice *dev; + gboolean opened; + FpDevice *dev; - FpImage *img; - ImageDisplayFlags img_flags; + FpImage *img; + ImageDisplayFlags img_flags; } LibfprintDemoWindow; typedef GtkApplicationWindowClass LibfprintDemoWindowClass; @@ -58,483 +59,506 @@ typedef GtkApplicationWindowClass LibfprintDemoWindowClass; G_DEFINE_TYPE (LibfprintDemoWindow, libfprint_demo_window, GTK_TYPE_APPLICATION_WINDOW) typedef enum { - EMPTY_MODE, - NOIMAGING_MODE, - CAPTURE_MODE, - SPINNER_MODE, - ERROR_MODE, - RETRY_MODE + EMPTY_MODE, + NOIMAGING_MODE, + CAPTURE_MODE, + SPINNER_MODE, + ERROR_MODE, + RETRY_MODE } LibfprintDemoMode; static void libfprint_demo_set_mode (LibfprintDemoWindow *win, - LibfprintDemoMode mode); + LibfprintDemoMode mode); static unsigned char * img_to_rgbdata (const guint8 *imgdata, - int width, - int height) + int width, + int height) { - int size = width * height; - guint8 *rgbdata = g_malloc (size * 3); - size_t i; - size_t rgb_offset = 0; + int size = width * height; + guint8 *rgbdata = g_malloc (size * 3); + size_t i; + size_t rgb_offset = 0; - for (i = 0; i < size; i++) { - guint8 pixel = imgdata[i]; + for (i = 0; i < size; i++) + { + guint8 pixel = imgdata[i]; - rgbdata[rgb_offset++] = pixel; - rgbdata[rgb_offset++] = pixel; - rgbdata[rgb_offset++] = pixel; - } + rgbdata[rgb_offset++] = pixel; + rgbdata[rgb_offset++] = pixel; + rgbdata[rgb_offset++] = pixel; + } - return rgbdata; + return rgbdata; } static void -plot_minutiae (unsigned char *rgbdata, - int width, - int height, - GPtrArray *minutiae) +plot_minutiae (unsigned char *rgbdata, + int width, + int height, + GPtrArray *minutiae) { - int i; + int i; + #define write_pixel(num) do { \ - rgbdata[((num) * 3)] = 0xff; \ - rgbdata[((num) * 3) + 1] = 0; \ - rgbdata[((num) * 3) + 2] = 0; \ - } while(0) + rgbdata[((num) * 3)] = 0xff; \ + rgbdata[((num) * 3) + 1] = 0; \ + rgbdata[((num) * 3) + 2] = 0; \ + } while(0) - for (i = 0; i < minutiae->len; i++) { - struct fp_minutia *min = g_ptr_array_index (minutiae, i); - int x, y; - size_t pixel_offset; + for (i = 0; i < minutiae->len; i++) + { + struct fp_minutia *min = g_ptr_array_index (minutiae, i); + int x, y; + size_t pixel_offset; - fp_minutia_get_coords(min, &x, &y); - pixel_offset = (y * width) + x; - write_pixel(pixel_offset - 2); - write_pixel(pixel_offset - 1); - write_pixel(pixel_offset); - write_pixel(pixel_offset + 1); - write_pixel(pixel_offset + 2); + fp_minutia_get_coords (min, &x, &y); + pixel_offset = (y * width) + x; + write_pixel (pixel_offset - 2); + write_pixel (pixel_offset - 1); + write_pixel (pixel_offset); + write_pixel (pixel_offset + 1); + write_pixel (pixel_offset + 2); - write_pixel(pixel_offset - (width * 2)); - write_pixel(pixel_offset - (width * 1) - 1); - write_pixel(pixel_offset - (width * 1)); - write_pixel(pixel_offset - (width * 1) + 1); - write_pixel(pixel_offset + (width * 1) - 1); - write_pixel(pixel_offset + (width * 1)); - write_pixel(pixel_offset + (width * 1) + 1); - write_pixel(pixel_offset + (width * 2)); - } + write_pixel (pixel_offset - (width * 2)); + write_pixel (pixel_offset - (width * 1) - 1); + write_pixel (pixel_offset - (width * 1)); + write_pixel (pixel_offset - (width * 1) + 1); + write_pixel (pixel_offset + (width * 1) - 1); + write_pixel (pixel_offset + (width * 1)); + write_pixel (pixel_offset + (width * 1) + 1); + write_pixel (pixel_offset + (width * 2)); + } } static GdkPixbuf * -img_to_pixbuf (FpImage *img, - ImageDisplayFlags flags) +img_to_pixbuf (FpImage *img, + ImageDisplayFlags flags) { - int width; - int height; - const guint8 *data; - unsigned char *rgbdata; + int width; + int height; + const guint8 *data; + unsigned char *rgbdata; - width = fp_image_get_width (img); - height = fp_image_get_height (img); + width = fp_image_get_width (img); + height = fp_image_get_height (img); - if (flags & IMAGE_DISPLAY_BINARY) - data = fp_image_get_binarized (img, NULL); - else - data = fp_image_get_data (img, NULL); + if (flags & IMAGE_DISPLAY_BINARY) + data = fp_image_get_binarized (img, NULL); + else + data = fp_image_get_data (img, NULL); - if (!data) - return NULL; + if (!data) + return NULL; - rgbdata = img_to_rgbdata (data, width, height); + rgbdata = img_to_rgbdata (data, width, height); - if (flags & IMAGE_DISPLAY_MINUTIAE) { - GPtrArray *minutiae; + if (flags & IMAGE_DISPLAY_MINUTIAE) + { + GPtrArray *minutiae; - minutiae = fp_image_get_minutiae (img); - plot_minutiae (rgbdata, width, height, minutiae); - } + minutiae = fp_image_get_minutiae (img); + plot_minutiae (rgbdata, width, height, minutiae); + } - return gdk_pixbuf_new_from_data (rgbdata, GDK_COLORSPACE_RGB, - FALSE, 8, width, height, - width * 3, (GdkPixbufDestroyNotify) g_free, - NULL); + return gdk_pixbuf_new_from_data (rgbdata, GDK_COLORSPACE_RGB, + FALSE, 8, width, height, + width * 3, (GdkPixbufDestroyNotify) g_free, + NULL); } static void update_image (LibfprintDemoWindow *win) { - GdkPixbuf *pixbuf; + GdkPixbuf *pixbuf; - if (win->img == NULL) { - gtk_image_clear (GTK_IMAGE (win->capture_image)); - return; - } + if (win->img == NULL) + { + gtk_image_clear (GTK_IMAGE (win->capture_image)); + return; + } - g_debug ("Updating image, minutiae %s, binary mode %s", - win->img_flags & IMAGE_DISPLAY_MINUTIAE ? "shown" : "hidden", - win->img_flags & IMAGE_DISPLAY_BINARY ? "on" : "off"); - pixbuf = img_to_pixbuf (win->img, win->img_flags); - gtk_image_set_from_pixbuf (GTK_IMAGE (win->capture_image), pixbuf); - g_object_unref (pixbuf); + g_debug ("Updating image, minutiae %s, binary mode %s", + win->img_flags & IMAGE_DISPLAY_MINUTIAE ? "shown" : "hidden", + win->img_flags & IMAGE_DISPLAY_BINARY ? "on" : "off"); + pixbuf = img_to_pixbuf (win->img, win->img_flags); + gtk_image_set_from_pixbuf (GTK_IMAGE (win->capture_image), pixbuf); + g_object_unref (pixbuf); } static void libfprint_demo_set_spinner_label (LibfprintDemoWindow *win, - const char *message) + const char *message) { - char *label; + char *label; - label = g_strdup_printf ("%s", message); - gtk_label_set_markup (GTK_LABEL (win->instructions), label); - g_free (label); + label = g_strdup_printf ("%s", message); + gtk_label_set_markup (GTK_LABEL (win->instructions), label); + g_free (label); } static void libfprint_demo_set_capture_label (LibfprintDemoWindow *win) { - FpScanType scan_type; - const char *message; + FpScanType scan_type; + const char *message; - scan_type = fp_device_get_scan_type(win->dev); + scan_type = fp_device_get_scan_type (win->dev); - switch (scan_type) { - case FP_SCAN_TYPE_PRESS: - message = "Place your finger on the fingerprint reader"; - break; - case FP_SCAN_TYPE_SWIPE: - message = "Swipe your finger across the fingerprint reader"; - break; - default: - g_assert_not_reached (); - } + switch (scan_type) + { + case FP_SCAN_TYPE_PRESS: + message = "Place your finger on the fingerprint reader"; + break; - libfprint_demo_set_spinner_label (win, message); + case FP_SCAN_TYPE_SWIPE: + message = "Swipe your finger across the fingerprint reader"; + break; + + default: + g_assert_not_reached (); + } + + libfprint_demo_set_spinner_label (win, message); } static void -dev_capture_start_cb (FpDevice *dev, - GAsyncResult *res, - void *user_data) +dev_capture_start_cb (FpDevice *dev, + GAsyncResult *res, + void *user_data) { - g_autoptr(GError) error = NULL; - LibfprintDemoWindow *win = user_data; - FpImage *image = NULL; + g_autoptr(GError) error = NULL; + LibfprintDemoWindow *win = user_data; + FpImage *image = NULL; - g_clear_object (&win->cancellable); + g_clear_object (&win->cancellable); - image = fp_device_capture_finish (dev, res, &error); - if (!image) { - g_warning ("Error capturing data: %s", error->message); - if (error->domain == FP_DEVICE_RETRY || - g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - libfprint_demo_set_mode (win, RETRY_MODE); - else - libfprint_demo_set_mode (win, ERROR_MODE); - return; - } + image = fp_device_capture_finish (dev, res, &error); + if (!image) + { + g_warning ("Error capturing data: %s", error->message); + if (error->domain == FP_DEVICE_RETRY || + g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + libfprint_demo_set_mode (win, RETRY_MODE); + else + libfprint_demo_set_mode (win, ERROR_MODE); + return; + } - g_clear_object (&win->img); - win->img = image; - update_image (win); + g_clear_object (&win->img); + win->img = image; + update_image (win); - libfprint_demo_set_mode (win, CAPTURE_MODE); + libfprint_demo_set_mode (win, CAPTURE_MODE); } static void dev_start_capture (LibfprintDemoWindow *win) { - libfprint_demo_set_capture_label (win); + libfprint_demo_set_capture_label (win); - fp_device_capture (win->dev, TRUE, win->cancellable, (GAsyncReadyCallback) dev_capture_start_cb, win); + fp_device_capture (win->dev, TRUE, win->cancellable, (GAsyncReadyCallback) dev_capture_start_cb, win); } static void dev_open_cb (FpDevice *dev, GAsyncResult *res, void *user_data) { - LibfprintDemoWindow *win = user_data; - g_autoptr(GError) error = NULL; + LibfprintDemoWindow *win = user_data; - if (!fp_device_open_finish (dev, res, &error)) { - g_warning ("Failed to open device: %s", error->message); - libfprint_demo_set_mode (win, ERROR_MODE); - return; - } + g_autoptr(GError) error = NULL; - dev_start_capture(win); + if (!fp_device_open_finish (dev, res, &error)) + { + g_warning ("Failed to open device: %s", error->message); + libfprint_demo_set_mode (win, ERROR_MODE); + return; + } + + dev_start_capture (win); } static void activate_capture (GSimpleAction *action, - GVariant *parameter, - gpointer user_data) + GVariant *parameter, + gpointer user_data) { - LibfprintDemoWindow *win = user_data; + LibfprintDemoWindow *win = user_data; - libfprint_demo_set_mode (win, SPINNER_MODE); - g_clear_pointer (&win->img, g_object_unref); + libfprint_demo_set_mode (win, SPINNER_MODE); + g_clear_pointer (&win->img, g_object_unref); - g_clear_object (&win->cancellable); - win->cancellable = g_cancellable_new (); + g_clear_object (&win->cancellable); + win->cancellable = g_cancellable_new (); - if (win->opened) { - dev_start_capture (win); - return; - } + if (win->opened) + { + dev_start_capture (win); + return; + } - libfprint_demo_set_spinner_label (win, "Opening fingerprint reader"); + libfprint_demo_set_spinner_label (win, "Opening fingerprint reader"); - win->opened = TRUE; - fp_device_open (win->dev, win->cancellable, (GAsyncReadyCallback) dev_open_cb, user_data); + win->opened = TRUE; + fp_device_open (win->dev, win->cancellable, (GAsyncReadyCallback) dev_open_cb, user_data); } static void cancel_capture (GSimpleAction *action, - GVariant *parameter, - gpointer user_data) + GVariant *parameter, + gpointer user_data) { - LibfprintDemoWindow *win = user_data; + LibfprintDemoWindow *win = user_data; - g_debug ("cancelling %p", win->cancellable); + g_debug ("cancelling %p", win->cancellable); - if (win->cancellable) - g_cancellable_cancel (win->cancellable); + if (win->cancellable) + g_cancellable_cancel (win->cancellable); } static void activate_quit (GSimpleAction *action, - GVariant *parameter, - gpointer user_data) + GVariant *parameter, + gpointer user_data) { - GtkApplication *app = user_data; - GtkWidget *win; - GList *list, *next; + GtkApplication *app = user_data; + GtkWidget *win; + GList *list, *next; - list = gtk_application_get_windows (app); - while (list) - { - win = list->data; - next = list->next; + list = gtk_application_get_windows (app); + while (list) + { + win = list->data; + next = list->next; - gtk_widget_destroy (GTK_WIDGET (win)); + gtk_widget_destroy (GTK_WIDGET (win)); - list = next; - } + list = next; + } } static void activate_show_minutiae (GSimpleAction *action, - GVariant *parameter, - gpointer user_data) + GVariant *parameter, + gpointer user_data) { - LibfprintDemoWindow *win = user_data; - GVariant *state; - gboolean new_state; + LibfprintDemoWindow *win = user_data; + GVariant *state; + gboolean new_state; - state = g_action_get_state (G_ACTION (action)); - new_state = !g_variant_get_boolean (state); - g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state)); - g_variant_unref (state); + state = g_action_get_state (G_ACTION (action)); + new_state = !g_variant_get_boolean (state); + g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state)); + g_variant_unref (state); - if (new_state) - win->img_flags |= IMAGE_DISPLAY_MINUTIAE; - else - win->img_flags &= ~IMAGE_DISPLAY_MINUTIAE; + if (new_state) + win->img_flags |= IMAGE_DISPLAY_MINUTIAE; + else + win->img_flags &= ~IMAGE_DISPLAY_MINUTIAE; - update_image (win); + update_image (win); } static void activate_show_binary (GSimpleAction *action, - GVariant *parameter, - gpointer user_data) + GVariant *parameter, + gpointer user_data) { - LibfprintDemoWindow *win = user_data; - GVariant *state; - gboolean new_state; + LibfprintDemoWindow *win = user_data; + GVariant *state; + gboolean new_state; - state = g_action_get_state (G_ACTION (action)); - new_state = !g_variant_get_boolean (state); - g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state)); - g_variant_unref (state); + state = g_action_get_state (G_ACTION (action)); + new_state = !g_variant_get_boolean (state); + g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state)); + g_variant_unref (state); - if (new_state) - win->img_flags |= IMAGE_DISPLAY_BINARY; - else - win->img_flags &= ~IMAGE_DISPLAY_BINARY; + if (new_state) + win->img_flags |= IMAGE_DISPLAY_BINARY; + else + win->img_flags &= ~IMAGE_DISPLAY_BINARY; - update_image (win); + update_image (win); } static void change_show_minutiae_state (GSimpleAction *action, - GVariant *state, - gpointer user_data) + GVariant *state, + gpointer user_data) { - g_simple_action_set_state (action, state); + g_simple_action_set_state (action, state); } static void change_show_binary_state (GSimpleAction *action, - GVariant *state, - gpointer user_data) + GVariant *state, + gpointer user_data) { - g_simple_action_set_state (action, state); + g_simple_action_set_state (action, state); } static GActionEntry app_entries[] = { - { "quit", activate_quit, NULL, NULL, NULL }, + { "quit", activate_quit, NULL, NULL, NULL }, }; static GActionEntry win_entries[] = { - { "show-minutiae", activate_show_minutiae, NULL, "false", change_show_minutiae_state }, - { "show-binary", activate_show_binary, NULL, "false", change_show_binary_state }, - { "capture", activate_capture, NULL, NULL, NULL }, - { "cancel", cancel_capture, NULL, NULL, NULL } + { "show-minutiae", activate_show_minutiae, NULL, "false", change_show_minutiae_state }, + { "show-binary", activate_show_binary, NULL, "false", change_show_binary_state }, + { "capture", activate_capture, NULL, NULL, NULL }, + { "cancel", cancel_capture, NULL, NULL, NULL } }; static void activate (GApplication *app) { - LibfprintDemoWindow *window; + LibfprintDemoWindow *window; - window = g_object_new (libfprint_demo_window_get_type (), - "application", app, - NULL); - gtk_widget_show (GTK_WIDGET (window)); + window = g_object_new (libfprint_demo_window_get_type (), + "application", app, + NULL); + gtk_widget_show (GTK_WIDGET (window)); } static void libfprint_demo_set_mode (LibfprintDemoWindow *win, - LibfprintDemoMode mode) + LibfprintDemoMode mode) { - char *title; + char *title; - switch (mode) { - case EMPTY_MODE: - gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "empty-mode"); - gtk_widget_set_sensitive (win->capture_button, FALSE); - gtk_widget_set_sensitive (win->cancel_button, FALSE); - gtk_spinner_stop (GTK_SPINNER (win->spinner)); - break; - case NOIMAGING_MODE: - gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "noimaging-mode"); - gtk_widget_set_sensitive (win->capture_button, FALSE); - gtk_widget_set_sensitive (win->cancel_button, FALSE); - gtk_spinner_stop (GTK_SPINNER (win->spinner)); - break; - case CAPTURE_MODE: - gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "capture-mode"); - gtk_widget_set_sensitive (win->capture_button, TRUE); - gtk_widget_set_sensitive (win->cancel_button, FALSE); + switch (mode) + { + case EMPTY_MODE: + gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "empty-mode"); + gtk_widget_set_sensitive (win->capture_button, FALSE); + gtk_widget_set_sensitive (win->cancel_button, FALSE); + gtk_spinner_stop (GTK_SPINNER (win->spinner)); + break; - title = g_strdup_printf ("%s Test", fp_device_get_name (win->dev)); - gtk_header_bar_set_title (GTK_HEADER_BAR (win->header_bar), title); - g_free (title); + case NOIMAGING_MODE: + gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "noimaging-mode"); + gtk_widget_set_sensitive (win->capture_button, FALSE); + gtk_widget_set_sensitive (win->cancel_button, FALSE); + gtk_spinner_stop (GTK_SPINNER (win->spinner)); + break; - gtk_spinner_stop (GTK_SPINNER (win->spinner)); - break; - case SPINNER_MODE: - gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "spinner-mode"); - gtk_widget_set_sensitive (win->capture_button, FALSE); - gtk_widget_set_sensitive (win->cancel_button, TRUE); - gtk_spinner_start (GTK_SPINNER (win->spinner)); - break; - case ERROR_MODE: - gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "error-mode"); - gtk_widget_set_sensitive (win->capture_button, FALSE); - gtk_widget_set_sensitive (win->cancel_button, FALSE); - gtk_spinner_stop (GTK_SPINNER (win->spinner)); - break; - case RETRY_MODE: - gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "retry-mode"); - gtk_widget_set_sensitive (win->capture_button, TRUE); - gtk_widget_set_sensitive (win->cancel_button, FALSE); - gtk_spinner_stop (GTK_SPINNER (win->spinner)); - break; - default: - g_assert_not_reached (); - } + case CAPTURE_MODE: + gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "capture-mode"); + gtk_widget_set_sensitive (win->capture_button, TRUE); + gtk_widget_set_sensitive (win->cancel_button, FALSE); + + title = g_strdup_printf ("%s Test", fp_device_get_name (win->dev)); + gtk_header_bar_set_title (GTK_HEADER_BAR (win->header_bar), title); + g_free (title); + + gtk_spinner_stop (GTK_SPINNER (win->spinner)); + break; + + case SPINNER_MODE: + gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "spinner-mode"); + gtk_widget_set_sensitive (win->capture_button, FALSE); + gtk_widget_set_sensitive (win->cancel_button, TRUE); + gtk_spinner_start (GTK_SPINNER (win->spinner)); + break; + + case ERROR_MODE: + gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "error-mode"); + gtk_widget_set_sensitive (win->capture_button, FALSE); + gtk_widget_set_sensitive (win->cancel_button, FALSE); + gtk_spinner_stop (GTK_SPINNER (win->spinner)); + break; + + case RETRY_MODE: + gtk_stack_set_visible_child_name (GTK_STACK (win->mode_stack), "retry-mode"); + gtk_widget_set_sensitive (win->capture_button, TRUE); + gtk_widget_set_sensitive (win->cancel_button, FALSE); + gtk_spinner_stop (GTK_SPINNER (win->spinner)); + break; + + default: + g_assert_not_reached (); + } } static void libfprint_demo_init (LibfprintDemo *app) { - g_action_map_add_action_entries (G_ACTION_MAP (app), - app_entries, G_N_ELEMENTS (app_entries), - app); + g_action_map_add_action_entries (G_ACTION_MAP (app), + app_entries, G_N_ELEMENTS (app_entries), + app); } static void libfprint_demo_class_init (LibfprintDemoClass *class) { - GApplicationClass *app_class = G_APPLICATION_CLASS (class); + GApplicationClass *app_class = G_APPLICATION_CLASS (class); - app_class->activate = activate; + app_class->activate = activate; } static void libfprint_demo_window_init (LibfprintDemoWindow *window) { - FpContext *ctx; - GPtrArray *devices; + FpContext *ctx; + GPtrArray *devices; - gtk_widget_init_template (GTK_WIDGET (window)); - gtk_window_set_default_size (GTK_WINDOW (window), 700, 500); + gtk_widget_init_template (GTK_WIDGET (window)); + gtk_window_set_default_size (GTK_WINDOW (window), 700, 500); - g_action_map_add_action_entries (G_ACTION_MAP (window), - win_entries, G_N_ELEMENTS (win_entries), - window); + g_action_map_add_action_entries (G_ACTION_MAP (window), + win_entries, G_N_ELEMENTS (win_entries), + window); - ctx = fp_context_new (); + ctx = fp_context_new (); - devices = fp_context_get_devices(ctx); - if (!devices) { - libfprint_demo_set_mode (window, ERROR_MODE); - return; - } + devices = fp_context_get_devices (ctx); + if (!devices) + { + libfprint_demo_set_mode (window, ERROR_MODE); + return; + } - /* Empty list? */ - if (devices->len == 0) { - libfprint_demo_set_mode (window, EMPTY_MODE); - return; - } + /* Empty list? */ + if (devices->len == 0) + { + libfprint_demo_set_mode (window, EMPTY_MODE); + return; + } - if (!fp_device_supports_capture(g_ptr_array_index (devices, 0))) { - libfprint_demo_set_mode (window, NOIMAGING_MODE); - return; - } + if (!fp_device_supports_capture (g_ptr_array_index (devices, 0))) + { + libfprint_demo_set_mode (window, NOIMAGING_MODE); + return; + } - window->dev = g_object_ref (g_ptr_array_index (devices, 0)); - libfprint_demo_set_mode (window, CAPTURE_MODE); + window->dev = g_object_ref (g_ptr_array_index (devices, 0)); + libfprint_demo_set_mode (window, CAPTURE_MODE); } static void libfprint_demo_window_class_init (LibfprintDemoWindowClass *class) { - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); - gtk_widget_class_set_template_from_resource (widget_class, "/libfprint_demo/gtk-libfprint-test.ui"); - gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, header_bar); - gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, mode_stack); - gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_button); - gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, cancel_button); - gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_image); - gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, spinner); - gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, instructions); + gtk_widget_class_set_template_from_resource (widget_class, "/libfprint_demo/gtk-libfprint-test.ui"); + gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, header_bar); + gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, mode_stack); + gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_button); + gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, cancel_button); + gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, capture_image); + gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, spinner); + gtk_widget_class_bind_template_child (widget_class, LibfprintDemoWindow, instructions); - //FIXME setup dispose + //FIXME setup dispose } -int main (int argc, char **argv) +int +main (int argc, char **argv) { - GtkApplication *app; + GtkApplication *app; - app = GTK_APPLICATION (g_object_new (libfprint_demo_get_type (), - "application-id", "org.freedesktop.libfprint.Demo", - "flags", G_APPLICATION_FLAGS_NONE, - NULL)); + app = GTK_APPLICATION (g_object_new (libfprint_demo_get_type (), + "application-id", "org.freedesktop.libfprint.Demo", + "flags", G_APPLICATION_FLAGS_NONE, + NULL)); - return g_application_run (G_APPLICATION (app), 0, NULL); + return g_application_run (G_APPLICATION (app), 0, NULL); } diff --git a/examples/enroll.c b/examples/enroll.c index 7542f306..81535f2a 100644 --- a/examples/enroll.c +++ b/examples/enroll.c @@ -24,155 +24,171 @@ #include "storage.h" -typedef struct _EnrollData { - GMainLoop *loop; - int ret_value; +typedef struct _EnrollData +{ + GMainLoop *loop; + int ret_value; } EnrollData; static void enroll_data_free (EnrollData *enroll_data) { - g_main_loop_unref (enroll_data->loop); - g_free (enroll_data); + g_main_loop_unref (enroll_data->loop); + g_free (enroll_data); } G_DEFINE_AUTOPTR_CLEANUP_FUNC (EnrollData, enroll_data_free) -FpDevice *discover_device (GPtrArray *devices) +FpDevice *discover_device (GPtrArray * devices) { - FpDevice *dev; - if (!devices->len) - return NULL; + FpDevice *dev; - dev = g_ptr_array_index (devices, 0); - printf("Found device claimed by %s driver\n", fp_device_get_driver (dev)); - return dev; + if (!devices->len) + return NULL; + + dev = g_ptr_array_index (devices, 0); + printf ("Found device claimed by %s driver\n", fp_device_get_driver (dev)); + return dev; } static void -on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data) { - EnrollData *enroll_data = user_data; - g_autoptr(GError) error = NULL; +on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data) +{ + EnrollData *enroll_data = user_data; - fp_device_close_finish (dev, res, &error); + g_autoptr(GError) error = NULL; - if (error) - g_warning ("Failed closing device %s\n", error->message); + fp_device_close_finish (dev, res, &error); - g_main_loop_quit (enroll_data->loop); + if (error) + g_warning ("Failed closing device %s\n", error->message); + + g_main_loop_quit (enroll_data->loop); } static void -on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data) { - EnrollData *enroll_data = user_data; - g_autoptr(FpPrint) print = NULL; - g_autoptr(GError) error = NULL; +on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data) +{ + EnrollData *enroll_data = user_data; - print = fp_device_enroll_finish (dev, res, &error); + g_autoptr(FpPrint) print = NULL; + g_autoptr(GError) error = NULL; - if (!error) { - enroll_data->ret_value = EXIT_SUCCESS; + print = fp_device_enroll_finish (dev, res, &error); - if (!fp_device_has_storage (dev)) { - g_debug("Device has not storage, saving locally"); - int r = print_data_save(print, FP_FINGER_RIGHT_INDEX); - if (r < 0) { - g_warning("Data save failed, code %d", r); - enroll_data->ret_value = EXIT_FAILURE; - } - } - } else { - g_warning("Enroll failed with error %s\n", error->message); - } + if (!error) + { + enroll_data->ret_value = EXIT_SUCCESS; - fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, - enroll_data); + if (!fp_device_has_storage (dev)) + { + g_debug ("Device has not storage, saving locally"); + int r = print_data_save (print, FP_FINGER_RIGHT_INDEX); + if (r < 0) + { + g_warning ("Data save failed, code %d", r); + enroll_data->ret_value = EXIT_FAILURE; + } + } + } + else + { + g_warning ("Enroll failed with error %s\n", error->message); + } + + fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, + enroll_data); } static void on_enroll_progress (FpDevice *device, - gint completed_stages, - FpPrint *print, - gpointer user_data, - GError *error) + gint completed_stages, + FpPrint *print, + gpointer user_data, + GError *error) { - if (error) { - g_warning ("Enroll stage %d of %d failed with error %s", - completed_stages, - fp_device_get_nr_enroll_stages (device), - error->message); - return; - } + if (error) + { + g_warning ("Enroll stage %d of %d failed with error %s", + completed_stages, + fp_device_get_nr_enroll_stages (device), + error->message); + return; + } - if (fp_device_supports_capture (device) && - print_image_save (print, "enrolled.pgm")) { - printf ("Wrote scanned image to enrolled.pgm\n"); - } + if (fp_device_supports_capture (device) && + print_image_save (print, "enrolled.pgm")) + printf ("Wrote scanned image to enrolled.pgm\n"); - printf ("Enroll stage %d of %d passed. Yay!\n", completed_stages, - fp_device_get_nr_enroll_stages (device)); + printf ("Enroll stage %d of %d passed. Yay!\n", completed_stages, + fp_device_get_nr_enroll_stages (device)); } static void on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data) { - EnrollData *enroll_data = user_data; - FpPrint *print_template; - g_autoptr(GError) error = NULL; + EnrollData *enroll_data = user_data; + FpPrint *print_template; - if (!fp_device_open_finish (dev, res, &error)) { - g_warning ("Failed to open device: %s", error->message); - g_main_loop_quit (enroll_data->loop); - return; - } + g_autoptr(GError) error = NULL; - printf ("Opened device. It's now time to enroll your finger.\n\n"); - printf ("You will need to successfully scan your finger %d times to " - "complete the process.\n\n", fp_device_get_nr_enroll_stages (dev)); - printf ("Scan your finger now.\n"); + if (!fp_device_open_finish (dev, res, &error)) + { + g_warning ("Failed to open device: %s", error->message); + g_main_loop_quit (enroll_data->loop); + return; + } - print_template = print_create_template (dev, FP_FINGER_RIGHT_INDEX); - fp_device_enroll (dev, print_template, NULL, on_enroll_progress, NULL, - NULL, (GAsyncReadyCallback) on_enroll_completed, - enroll_data); + printf ("Opened device. It's now time to enroll your finger.\n\n"); + printf ("You will need to successfully scan your finger %d times to " + "complete the process.\n\n", fp_device_get_nr_enroll_stages (dev)); + printf ("Scan your finger now.\n"); + + print_template = print_create_template (dev, FP_FINGER_RIGHT_INDEX); + fp_device_enroll (dev, print_template, NULL, on_enroll_progress, NULL, + NULL, (GAsyncReadyCallback) on_enroll_completed, + enroll_data); } -int main(void) +int +main (void) { - g_autoptr (FpContext) ctx = NULL; - g_autoptr (EnrollData) enroll_data = NULL; - GPtrArray *devices; - FpDevice *dev; + g_autoptr(FpContext) ctx = NULL; + g_autoptr(EnrollData) enroll_data = NULL; + GPtrArray *devices; + FpDevice *dev; - printf("This program will enroll your right index finger, " - "unconditionally overwriting any right-index print that was enrolled " - "previously. If you want to continue, press enter, otherwise hit " - "Ctrl+C\n"); - getchar(); + printf ("This program will enroll your right index finger, " + "unconditionally overwriting any right-index print that was enrolled " + "previously. If you want to continue, press enter, otherwise hit " + "Ctrl+C\n"); + getchar (); - setenv ("G_MESSAGES_DEBUG", "all", 0); + setenv ("G_MESSAGES_DEBUG", "all", 0); - ctx = fp_context_new (); + ctx = fp_context_new (); - devices = fp_context_get_devices (ctx); - if (!devices) { - g_warning("Impossible to get devices"); - return EXIT_FAILURE; - } + devices = fp_context_get_devices (ctx); + if (!devices) + { + g_warning ("Impossible to get devices"); + return EXIT_FAILURE; + } - dev = discover_device (devices); - if (!dev) { - g_warning("No devices detected."); - return EXIT_FAILURE; - } + dev = discover_device (devices); + if (!dev) + { + g_warning ("No devices detected."); + return EXIT_FAILURE; + } - enroll_data = g_new0 (EnrollData, 1); - enroll_data->ret_value = EXIT_FAILURE; - enroll_data->loop = g_main_loop_new (NULL, FALSE); + enroll_data = g_new0 (EnrollData, 1); + enroll_data->ret_value = EXIT_FAILURE; + enroll_data->loop = g_main_loop_new (NULL, FALSE); - fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened, - enroll_data); + fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened, + enroll_data); - g_main_loop_run (enroll_data->loop); + g_main_loop_run (enroll_data->loop); - return enroll_data->ret_value; + return enroll_data->ret_value; } diff --git a/examples/manage-prints.c b/examples/manage-prints.c index 9e6696a8..16ab54f0 100644 --- a/examples/manage-prints.c +++ b/examples/manage-prints.c @@ -122,8 +122,9 @@ delete_data_free (DeleteData *delete_data) } G_DEFINE_AUTOPTR_CLEANUP_FUNC (DeleteData, delete_data_free); -static void -on_print_deleted (FpDevice *dev, GAsyncResult *res, gpointer user_data); +static void on_print_deleted (FpDevice *dev, + GAsyncResult *res, + gpointer user_data); static void delete_next_print (FpDevice *dev, @@ -145,6 +146,7 @@ on_print_deleted (FpDevice *dev, gpointer user_data) { ListData *list_data = user_data; + g_autoptr(GError) error = NULL; g_autoptr(FpPrint) print = NULL; GList *deleted_link; @@ -157,12 +159,14 @@ on_print_deleted (FpDevice *dev, if (error) { - g_warning("Failed to remove print %s: %s", - fp_print_get_description (print), error->message); + g_warning ("Failed to remove print %s: %s", + fp_print_get_description (print), error->message); list_data->any_failed = TRUE; } else - g_debug ("Deleted print %s from device", fp_print_get_description (print)); + { + g_debug ("Deleted print %s from device", fp_print_get_description (print)); + } if (list_data->to_delete != NULL) { @@ -184,6 +188,7 @@ on_list_completed (FpDevice *dev, gpointer user_data) { ListData *list_data = user_data; + g_autoptr(GPtrArray) prints = NULL; g_autoptr(GError) error = NULL; @@ -198,7 +203,7 @@ on_list_completed (FpDevice *dev, for (i = 0; i < prints->len; ++i) { - FpPrint* print = prints->pdata[i]; + FpPrint * print = prints->pdata[i]; g_date_strftime (buf, G_N_ELEMENTS (buf), "%Y-%m-%d", fp_print_get_enroll_date (print)); @@ -247,10 +252,8 @@ on_list_completed (FpDevice *dev, if (list_data->to_delete) delete_next_print (dev, list_data); else - { - fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, - list_data); - } + fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, + list_data); } else { diff --git a/examples/storage.c b/examples/storage.c index d2f4832b..932163e0 100644 --- a/examples/storage.c +++ b/examples/storage.c @@ -31,183 +31,196 @@ static char * get_print_data_descriptor (FpPrint *print, FpDevice *dev, FpFinger finger) { - const char *driver; - const char *dev_id; + const char *driver; + const char *dev_id; - if (print) { - driver = fp_print_get_driver (print); - dev_id = fp_print_get_device_id (print); - } else { - driver = fp_device_get_driver (dev); - dev_id = fp_device_get_device_id (dev); - } + if (print) + { + driver = fp_print_get_driver (print); + dev_id = fp_print_get_device_id (print); + } + else + { + driver = fp_device_get_driver (dev); + dev_id = fp_device_get_device_id (dev); + } - return g_strdup_printf("%s/%s/%x", - driver, - dev_id, - finger); + return g_strdup_printf ("%s/%s/%x", + driver, + dev_id, + finger); } static GVariantDict * -load_data(void) +load_data (void) { - GVariantDict *res; - GVariant *var; - g_autofree gchar *contents = NULL; - gssize length = 0; + GVariantDict *res; + GVariant *var; + g_autofree gchar *contents = NULL; + gssize length = 0; - if (!g_file_get_contents (STORAGE_FILE, &contents, &length, NULL)) { - g_warning ("Error loading storage, assuming it is empty"); - return g_variant_dict_new(NULL); - } + if (!g_file_get_contents (STORAGE_FILE, &contents, &length, NULL)) + { + g_warning ("Error loading storage, assuming it is empty"); + return g_variant_dict_new (NULL); + } - var = g_variant_new_from_data (G_VARIANT_TYPE_VARDICT, contents, length, FALSE, NULL, NULL); + var = g_variant_new_from_data (G_VARIANT_TYPE_VARDICT, contents, length, FALSE, NULL, NULL); - res = g_variant_dict_new(var); - g_variant_unref(var); - return res; + res = g_variant_dict_new (var); + g_variant_unref (var); + return res; } static int -save_data(GVariant *data) +save_data (GVariant *data) { - const gchar *contents = NULL; - gsize length; + const gchar *contents = NULL; + gsize length; - length = g_variant_get_size(data); - contents = (gchar*) g_variant_get_data (data); + length = g_variant_get_size (data); + contents = (gchar *) g_variant_get_data (data); - if (!g_file_set_contents (STORAGE_FILE, contents, length, NULL)) { - g_warning ("Error saving storage,!"); - return -1; - } + if (!g_file_set_contents (STORAGE_FILE, contents, length, NULL)) + { + g_warning ("Error saving storage,!"); + return -1; + } - g_variant_ref_sink(data); - g_variant_unref(data); + g_variant_ref_sink (data); + g_variant_unref (data); - return 0; + return 0; } int -print_data_save(FpPrint *print, FpFinger finger) +print_data_save (FpPrint *print, FpFinger finger) { - g_autofree gchar *descr = get_print_data_descriptor (print, NULL, finger); - g_autoptr (GError) error = NULL; - g_autoptr (GVariantDict) dict = NULL; - g_autofree guchar *data = NULL; - GVariant *val; - gsize size; - int res; + g_autofree gchar *descr = get_print_data_descriptor (print, NULL, finger); - dict = load_data(); + g_autoptr(GError) error = NULL; + g_autoptr(GVariantDict) dict = NULL; + g_autofree guchar *data = NULL; + GVariant *val; + gsize size; + int res; - fp_print_serialize (print, &data, &size, &error); - if (error) { - g_warning ("Error serializing data: %s", error->message); - return -1; - } - val = g_variant_new_fixed_array (G_VARIANT_TYPE("y"), data, size, 1); - g_variant_dict_insert_value (dict, descr, val); + dict = load_data (); - res = save_data(g_variant_dict_end(dict)); + fp_print_serialize (print, &data, &size, &error); + if (error) + { + g_warning ("Error serializing data: %s", error->message); + return -1; + } + val = g_variant_new_fixed_array (G_VARIANT_TYPE ("y"), data, size, 1); + g_variant_dict_insert_value (dict, descr, val); - return res; + res = save_data (g_variant_dict_end (dict)); + + return res; } FpPrint * -print_data_load(FpDevice *dev, FpFinger finger) +print_data_load (FpDevice *dev, FpFinger finger) { - g_autofree gchar *descr = get_print_data_descriptor (NULL, dev, finger); - g_autoptr (GVariant) val = NULL; - g_autoptr (GVariantDict) dict = NULL; - g_autofree guchar *stored_data = NULL; - gsize stored_len; + g_autofree gchar *descr = get_print_data_descriptor (NULL, dev, finger); - dict = load_data(); - val = g_variant_dict_lookup_value (dict, descr, G_VARIANT_TYPE ("ay")); + g_autoptr(GVariant) val = NULL; + g_autoptr(GVariantDict) dict = NULL; + g_autofree guchar *stored_data = NULL; + gsize stored_len; - if (val) { - FpPrint *print; - g_autoptr (GError) error = NULL; + dict = load_data (); + val = g_variant_dict_lookup_value (dict, descr, G_VARIANT_TYPE ("ay")); - stored_data = (guchar*) g_variant_get_fixed_array (val, &stored_len, 1); - print = fp_print_deserialize (stored_data, stored_len, &error); + if (val) + { + FpPrint *print; + g_autoptr(GError) error = NULL; - if (error) - g_warning ("Error deserializing data: %s", error->message); + stored_data = (guchar *) g_variant_get_fixed_array (val, &stored_len, 1); + print = fp_print_deserialize (stored_data, stored_len, &error); - return print; - } + if (error) + g_warning ("Error deserializing data: %s", error->message); - return NULL; + return print; + } + + return NULL; } FpPrint * print_create_template (FpDevice *dev, FpFinger finger) { - g_autoptr(GDateTime) datetime = NULL; - FpPrint *template = NULL; - GDate *date = NULL; - gint year, month, day; + g_autoptr(GDateTime) datetime = NULL; + FpPrint *template = NULL; + GDate *date = NULL; + gint year, month, day; - template = fp_print_new (dev); - fp_print_set_finger (template, finger); - fp_print_set_username (template, g_get_user_name ()); - datetime = g_date_time_new_now_local (); - g_date_time_get_ymd (datetime, &year, &month, &day); - date = g_date_new_dmy (day, month, year); - fp_print_set_enroll_date (template, date); - g_date_free (date); + template = fp_print_new (dev); + fp_print_set_finger (template, finger); + fp_print_set_username (template, g_get_user_name ()); + datetime = g_date_time_new_now_local (); + g_date_time_get_ymd (datetime, &year, &month, &day); + date = g_date_new_dmy (day, month, year); + fp_print_set_enroll_date (template, date); + g_date_free (date); - return template; + return template; } static gboolean save_image_to_pgm (FpImage *img, const char *path) { - FILE *fd = fopen (path, "w"); - size_t write_size; - const guchar *data = fp_image_get_data (img, &write_size); - int r; + FILE *fd = fopen (path, "w"); + size_t write_size; + const guchar *data = fp_image_get_data (img, &write_size); + int r; - if (!fd) { - g_warning("could not open '%s' for writing: %d", path, errno); - return FALSE; - } + if (!fd) + { + g_warning ("could not open '%s' for writing: %d", path, errno); + return FALSE; + } - r = fprintf (fd, "P5 %d %d 255\n", - fp_image_get_width (img), fp_image_get_height (img)); - if (r < 0) { - fclose(fd); - g_critical("pgm header write failed, error %d", r); - return FALSE; - } + r = fprintf (fd, "P5 %d %d 255\n", + fp_image_get_width (img), fp_image_get_height (img)); + if (r < 0) + { + fclose (fd); + g_critical ("pgm header write failed, error %d", r); + return FALSE; + } - r = fwrite (data, 1, write_size, fd); - if (r < write_size) { - fclose(fd); - g_critical("short write (%d)", r); - return FALSE; - } + r = fwrite (data, 1, write_size, fd); + if (r < write_size) + { + fclose (fd); + g_critical ("short write (%d)", r); + return FALSE; + } - fclose (fd); - g_debug ("written to '%s'", path); + fclose (fd); + g_debug ("written to '%s'", path); - return TRUE; + return TRUE; } -gboolean print_image_save (FpPrint *print, const char *path) +gboolean +print_image_save (FpPrint *print, const char *path) { - g_autoptr(FpImage) img = NULL; + g_autoptr(FpImage) img = NULL; - g_return_val_if_fail (FP_IS_PRINT (print), FALSE); - g_return_val_if_fail (path != NULL, FALSE); + g_return_val_if_fail (FP_IS_PRINT (print), FALSE); + g_return_val_if_fail (path != NULL, FALSE); - img = fp_print_get_image (print); + img = fp_print_get_image (print); - if (img) - return save_image_to_pgm (img, path); + if (img) + return save_image_to_pgm (img, path); - return FALSE; + return FALSE; } diff --git a/examples/storage.h b/examples/storage.h index f4199954..bcbd0090 100644 --- a/examples/storage.h +++ b/examples/storage.h @@ -22,9 +22,13 @@ #define __STORAGE_H -int print_data_save(FpPrint *print, FpFinger finger); -FpPrint * print_data_load(FpDevice *dev, FpFinger finger); -FpPrint * print_create_template(FpDevice *dev, FpFinger finger); -gboolean print_image_save(FpPrint *print, const char *path); +int print_data_save (FpPrint *print, + FpFinger finger); +FpPrint * print_data_load (FpDevice *dev, + FpFinger finger); +FpPrint * print_create_template (FpDevice *dev, + FpFinger finger); +gboolean print_image_save (FpPrint *print, + const char *path); #endif /* __STORAGE_H */ diff --git a/examples/verify.c b/examples/verify.c index 69e3cbd9..e5432822 100644 --- a/examples/verify.c +++ b/examples/verify.c @@ -24,212 +24,236 @@ #include "storage.h" -typedef struct _VerifyData { - GMainLoop *loop; - int ret_value; +typedef struct _VerifyData +{ + GMainLoop *loop; + int ret_value; } VerifyData; static void verify_data_free (VerifyData *verify_data) { - g_main_loop_unref (verify_data->loop); - g_free (verify_data); + g_main_loop_unref (verify_data->loop); + g_free (verify_data); } G_DEFINE_AUTOPTR_CLEANUP_FUNC (VerifyData, verify_data_free) -FpDevice *discover_device (GPtrArray *devices) +FpDevice *discover_device (GPtrArray * devices) { - FpDevice *dev; - if (!devices->len) - return NULL; + FpDevice *dev; - dev = g_ptr_array_index (devices, 0); - printf("Found device claimed by %s driver\n", fp_device_get_driver (dev)); - return dev; + if (!devices->len) + return NULL; + + dev = g_ptr_array_index (devices, 0); + printf ("Found device claimed by %s driver\n", fp_device_get_driver (dev)); + return dev; } static void -on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data) { - VerifyData *verify_data = user_data; - g_autoptr(GError) error = NULL; +on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data) +{ + VerifyData *verify_data = user_data; - fp_device_close_finish (dev, res, &error); + g_autoptr(GError) error = NULL; - if (error) - g_warning ("Failed closing device %s\n", error->message); + fp_device_close_finish (dev, res, &error); - g_main_loop_quit (verify_data->loop); + if (error) + g_warning ("Failed closing device %s\n", error->message); + + g_main_loop_quit (verify_data->loop); } -static void start_verification (FpDevice *dev, VerifyData *verify_data); +static void start_verification (FpDevice *dev, + VerifyData *verify_data); static void on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data) { - VerifyData *verify_data = user_data; - g_autoptr(FpPrint) print = NULL; - g_autoptr(GError) error = NULL; - char buffer[20]; - gboolean match; + VerifyData *verify_data = user_data; - if (!fp_device_verify_finish (dev, res, &match, &print, &error)) { - g_warning ("Failed to verify print: %s", error->message); - g_main_loop_quit (verify_data->loop); - return; - } + g_autoptr(FpPrint) print = NULL; + g_autoptr(GError) error = NULL; + char buffer[20]; + gboolean match; - if (match) { - g_print ("MATCH!\n"); - if (fp_device_supports_capture (dev) && - print_image_save (print, "verify.pgm")) { - g_print("Print image saved as verify.pgm"); - } + if (!fp_device_verify_finish (dev, res, &match, &print, &error)) + { + g_warning ("Failed to verify print: %s", error->message); + g_main_loop_quit (verify_data->loop); + return; + } - verify_data->ret_value = EXIT_SUCCESS; - } else { - g_print ("NO MATCH!\n"); - verify_data->ret_value = EXIT_FAILURE; - } + if (match) + { + g_print ("MATCH!\n"); + if (fp_device_supports_capture (dev) && + print_image_save (print, "verify.pgm")) + g_print ("Print image saved as verify.pgm"); - g_print ("Verify again? [Y/n]? "); - if (fgets (buffer, sizeof (buffer), stdin) && - (buffer[0] == 'Y' || buffer[0] == 'y')) { - start_verification (dev, verify_data); - return; - } + verify_data->ret_value = EXIT_SUCCESS; + } + else + { + g_print ("NO MATCH!\n"); + verify_data->ret_value = EXIT_FAILURE; + } - fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, - verify_data); + g_print ("Verify again? [Y/n]? "); + if (fgets (buffer, sizeof (buffer), stdin) && + (buffer[0] == 'Y' || buffer[0] == 'y')) + { + start_verification (dev, verify_data); + return; + } + + fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, + verify_data); } static void on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data) { - VerifyData *verify_data = user_data; - g_autoptr(GPtrArray) prints = NULL; - g_autoptr(GError) error = NULL; + VerifyData *verify_data = user_data; - prints = fp_device_list_prints_finish (dev, res, &error); + g_autoptr(GPtrArray) prints = NULL; + g_autoptr(GError) error = NULL; - if (!error) { - FpPrint *verify_print = NULL; - guint i; + prints = fp_device_list_prints_finish (dev, res, &error); - if (!prints->len) - g_warning ("No prints saved on device"); + if (!error) + { + FpPrint *verify_print = NULL; + guint i; - for (i = 0; i < prints->len; ++i) { - FpPrint *print = prints->pdata[i]; + if (!prints->len) + g_warning ("No prints saved on device"); - if (fp_print_get_finger (print) == FP_FINGER_RIGHT_INDEX && - g_strcmp0 (fp_print_get_username (print), g_get_user_name ()) == 0) { - if (!verify_print || - (g_date_compare (fp_print_get_enroll_date (print), - fp_print_get_enroll_date (verify_print)) >= 0)) - verify_print = print; - } - } + for (i = 0; i < prints->len; ++i) + { + FpPrint *print = prints->pdata[i]; - if (!verify_print) { - g_warning ("Did you remember to enroll your right index " - "finger first?"); - g_main_loop_quit (verify_data->loop); - return; - } + if (fp_print_get_finger (print) == FP_FINGER_RIGHT_INDEX && + g_strcmp0 (fp_print_get_username (print), g_get_user_name ()) == 0) + { + if (!verify_print || + (g_date_compare (fp_print_get_enroll_date (print), + fp_print_get_enroll_date (verify_print)) >= 0)) + verify_print = print; + } + } - g_debug ("Comparing print with %s", - fp_print_get_description (verify_print)); + if (!verify_print) + { + g_warning ("Did you remember to enroll your right index " + "finger first?"); + g_main_loop_quit (verify_data->loop); + return; + } - g_print ("Print loaded. Time to verify!\n"); - fp_device_verify (dev, verify_print, NULL, - (GAsyncReadyCallback) on_verify_completed, - verify_data); - } else { - g_warning ("Loading prints failed with error %s", error->message); - g_main_loop_quit (verify_data->loop); - } + g_debug ("Comparing print with %s", + fp_print_get_description (verify_print)); + + g_print ("Print loaded. Time to verify!\n"); + fp_device_verify (dev, verify_print, NULL, + (GAsyncReadyCallback) on_verify_completed, + verify_data); + } + else + { + g_warning ("Loading prints failed with error %s", error->message); + g_main_loop_quit (verify_data->loop); + } } static void start_verification (FpDevice *dev, VerifyData *verify_data) { - if (fp_device_has_storage (dev)) { - g_print ("Creating finger template, using device storage...\n"); - fp_device_list_prints (dev, NULL, - (GAsyncReadyCallback) on_list_completed, - verify_data); - } else { - g_print ("Loading previously enrolled right index finger data...\n"); - g_autoptr(FpPrint) verify_print; + if (fp_device_has_storage (dev)) + { + g_print ("Creating finger template, using device storage...\n"); + fp_device_list_prints (dev, NULL, + (GAsyncReadyCallback) on_list_completed, + verify_data); + } + else + { + g_print ("Loading previously enrolled right index finger data...\n"); + g_autoptr(FpPrint) verify_print; - verify_print = print_data_load (dev, FP_FINGER_RIGHT_INDEX); + verify_print = print_data_load (dev, FP_FINGER_RIGHT_INDEX); - if (!verify_print) { - g_warning ("Failed to load fingerprint data"); - g_warning ("Did you remember to enroll your right index " - "finger first?"); - g_main_loop_quit (verify_data->loop); - return; - } + if (!verify_print) + { + g_warning ("Failed to load fingerprint data"); + g_warning ("Did you remember to enroll your right index " + "finger first?"); + g_main_loop_quit (verify_data->loop); + return; + } - g_print ("Print loaded. Time to verify!\n"); - fp_device_verify (dev, verify_print, NULL, - (GAsyncReadyCallback) on_verify_completed, - verify_data); - } + g_print ("Print loaded. Time to verify!\n"); + fp_device_verify (dev, verify_print, NULL, + (GAsyncReadyCallback) on_verify_completed, + verify_data); + } } static void on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data) { - VerifyData *verify_data = user_data; - g_autoptr(GError) error = NULL; + VerifyData *verify_data = user_data; - if (!fp_device_open_finish (dev, res, &error)) { - g_warning ("Failed to open device: %s", error->message); - g_main_loop_quit (verify_data->loop); - return; - } + g_autoptr(GError) error = NULL; - g_print ("Opened device. "); + if (!fp_device_open_finish (dev, res, &error)) + { + g_warning ("Failed to open device: %s", error->message); + g_main_loop_quit (verify_data->loop); + return; + } - start_verification (dev, verify_data); + g_print ("Opened device. "); + + start_verification (dev, verify_data); } -int main(void) +int +main (void) { - g_autoptr (FpContext) ctx = NULL; - g_autoptr (VerifyData) verify_data = NULL; - GPtrArray *devices; - FpDevice *dev; + g_autoptr(FpContext) ctx = NULL; + g_autoptr(VerifyData) verify_data = NULL; + GPtrArray *devices; + FpDevice *dev; - setenv ("G_MESSAGES_DEBUG", "all", 0); - setenv ("LIBUSB_DEBUG", "3", 0); + setenv ("G_MESSAGES_DEBUG", "all", 0); + setenv ("LIBUSB_DEBUG", "3", 0); - ctx = fp_context_new (); + ctx = fp_context_new (); - devices = fp_context_get_devices (ctx); - if (!devices) { - g_warning("Impossible to get devices"); - return EXIT_FAILURE; - } + devices = fp_context_get_devices (ctx); + if (!devices) + { + g_warning ("Impossible to get devices"); + return EXIT_FAILURE; + } - dev = discover_device (devices); - if (!dev) { - g_warning("No devices detected."); - return EXIT_FAILURE; - } + dev = discover_device (devices); + if (!dev) + { + g_warning ("No devices detected."); + return EXIT_FAILURE; + } - verify_data = g_new0 (VerifyData, 1); - verify_data->ret_value = EXIT_FAILURE; - verify_data->loop = g_main_loop_new (NULL, FALSE); + verify_data = g_new0 (VerifyData, 1); + verify_data->ret_value = EXIT_FAILURE; + verify_data->loop = g_main_loop_new (NULL, FALSE); - fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened, - verify_data); + fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened, + verify_data); - g_main_loop_run (verify_data->loop); + g_main_loop_run (verify_data->loop); - return verify_data->ret_value; + return verify_data->ret_value; } - - diff --git a/libfprint/drivers/aes1610.c b/libfprint/drivers/aes1610.c index 374252ea..30443f7f 100644 --- a/libfprint/drivers/aes1610.c +++ b/libfprint/drivers/aes1610.c @@ -28,24 +28,25 @@ #include "drivers_api.h" #include "aeslib.h" -static void start_capture(FpImageDevice *dev); -static void complete_deactivation(FpImageDevice *dev); -static int adjust_gain(unsigned char *buffer, int status); +static void start_capture (FpImageDevice *dev); +static void complete_deactivation (FpImageDevice *dev); +static int adjust_gain (unsigned char *buffer, + int status); -#define FIRST_AES1610_REG 0x1B -#define LAST_AES1610_REG 0xFF +#define FIRST_AES1610_REG 0x1B +#define LAST_AES1610_REG 0xFF #define GAIN_STATUS_FIRST 1 #define GAIN_STATUS_NORMAL 2 /* FIXME these need checking */ -#define EP_IN (1 | FPI_USB_ENDPOINT_IN) -#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) #define BULK_TIMEOUT 4000 -#define FINGER_DETECTION_LEN 19 -#define STRIP_CAPTURE_LEN 665 +#define FINGER_DETECTION_LEN 19 +#define STRIP_CAPTURE_LEN 665 /* * The AES1610 is an imaging device using a swipe-type sensor. It samples @@ -59,333 +60,352 @@ static int adjust_gain(unsigned char *buffer, int status); * images returned from this driver vary in height. */ -#define FRAME_WIDTH 128 -#define FRAME_HEIGHT 8 -#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT) -#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2)) +#define FRAME_WIDTH 128 +#define FRAME_HEIGHT 8 +#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT) +#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2)) /* maximum number of frames to read during a scan */ /* FIXME reduce substantially */ -#define MAX_FRAMES 350 +#define MAX_FRAMES 350 /****** GENERAL FUNCTIONS ******/ -struct _FpiDeviceAes1610 { - FpImageDevice parent; +struct _FpiDeviceAes1610 +{ + FpImageDevice parent; - guint8 read_regs_retry_count; - GSList *strips; - gsize strips_len; - gboolean deactivating; - guint8 blanks_count; + guint8 read_regs_retry_count; + GSList *strips; + gsize strips_len; + gboolean deactivating; + guint8 blanks_count; }; -G_DECLARE_FINAL_TYPE(FpiDeviceAes1610, fpi_device_aes1610, FPI, DEVICE_AES1610, - FpImageDevice); -G_DEFINE_TYPE(FpiDeviceAes1610, fpi_device_aes1610, FP_TYPE_IMAGE_DEVICE); +G_DECLARE_FINAL_TYPE (FpiDeviceAes1610, fpi_device_aes1610, FPI, DEVICE_AES1610, + FpImageDevice); +G_DEFINE_TYPE (FpiDeviceAes1610, fpi_device_aes1610, FP_TYPE_IMAGE_DEVICE); static struct fpi_frame_asmbl_ctx assembling_ctx = { - .frame_width = FRAME_WIDTH, - .frame_height = FRAME_HEIGHT, - .image_width = IMAGE_WIDTH, - .get_pixel = aes_get_pixel, + .frame_width = FRAME_WIDTH, + .frame_height = FRAME_HEIGHT, + .image_width = IMAGE_WIDTH, + .get_pixel = aes_get_pixel, }; -typedef void (*aes1610_read_regs_cb)(FpImageDevice *dev, int status, - unsigned char *regs, void *user_data); +typedef void (*aes1610_read_regs_cb)(FpImageDevice *dev, + int status, + unsigned char *regs, + void *user_data); -struct aes1610_read_regs { - FpImageDevice *dev; - aes1610_read_regs_cb callback; - struct aes_regwrite *regwrite; - void *user_data; +struct aes1610_read_regs +{ + FpImageDevice *dev; + aes1610_read_regs_cb callback; + struct aes_regwrite *regwrite; + void *user_data; }; /* FIXME: what to do here? */ -static void stub_capture_stop_cb(FpImageDevice *dev, GError *error, - void *user_data) +static void +stub_capture_stop_cb (FpImageDevice *dev, GError *error, + void *user_data) { - if (error) { - fp_warn ("Error stopping capture: %s", error->message); - g_error_free (error); - } + if (error) + { + fp_warn ("Error stopping capture: %s", error->message); + g_error_free (error); + } } /* check that read succeeded but ignore all data */ -static void generic_ignore_data_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +generic_ignore_data_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - if (error) - fpi_ssm_mark_failed(transfer->ssm, error); - else - fpi_ssm_next_state(transfer->ssm); + if (error) + fpi_ssm_mark_failed (transfer->ssm, error); + else + fpi_ssm_next_state (transfer->ssm); } -static void generic_write_regv_cb(FpImageDevice *dev, GError *error, - void *user_data) +static void +generic_write_regv_cb (FpImageDevice *dev, GError *error, + void *user_data) { - FpiSsm *ssm = user_data; - if (!error) - fpi_ssm_next_state(ssm); - else - fpi_ssm_mark_failed(ssm, error); + FpiSsm *ssm = user_data; + + if (!error) + fpi_ssm_next_state (ssm); + else + fpi_ssm_mark_failed (ssm, error); } /* read the specified number of bytes from the IN endpoint but throw them * away, then increment the SSM */ -static void generic_read_ignore_data(FpiSsm *ssm, FpDevice *dev, - size_t bytes) +static void +generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev, + size_t bytes) { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); - unsigned char *data; + FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev); + unsigned char *data; - data = g_malloc(bytes); - fpi_usb_transfer_fill_bulk_full(transfer, EP_IN, data, bytes, NULL); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - generic_ignore_data_cb, NULL); - fpi_usb_transfer_unref(transfer); + data = g_malloc (bytes); + fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, data, bytes, NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + generic_ignore_data_cb, NULL); + fpi_usb_transfer_unref (transfer); } /****** FINGER PRESENCE DETECTION ******/ static const struct aes_regwrite finger_det_reqs[] = { - { 0x80, 0x01 }, - { 0x80, 0x12 }, - { 0x85, 0x00 }, - { 0x8A, 0x00 }, - { 0x8B, 0x0E }, - { 0x8C, 0x90 }, - { 0x8D, 0x83 }, - { 0x8E, 0x07 }, - { 0x8F, 0x07 }, - { 0x96, 0x00 }, - { 0x97, 0x48 }, - { 0xA1, 0x00 }, - { 0xA2, 0x50 }, - { 0xA6, 0xE4 }, - { 0xAD, 0x08 }, - { 0xAE, 0x5B }, - { 0xAF, 0x54 }, - { 0xB1, 0x28 }, - { 0xB5, 0xAB }, - { 0xB6, 0x0E }, - { 0x1B, 0x2D }, - { 0x81, 0x04 } + { 0x80, 0x01 }, + { 0x80, 0x12 }, + { 0x85, 0x00 }, + { 0x8A, 0x00 }, + { 0x8B, 0x0E }, + { 0x8C, 0x90 }, + { 0x8D, 0x83 }, + { 0x8E, 0x07 }, + { 0x8F, 0x07 }, + { 0x96, 0x00 }, + { 0x97, 0x48 }, + { 0xA1, 0x00 }, + { 0xA2, 0x50 }, + { 0xA6, 0xE4 }, + { 0xAD, 0x08 }, + { 0xAE, 0x5B }, + { 0xAF, 0x54 }, + { 0xB1, 0x28 }, + { 0xB5, 0xAB }, + { 0xB6, 0x0E }, + { 0x1B, 0x2D }, + { 0x81, 0x04 } }; -static void start_finger_detection(FpImageDevice *dev); +static void start_finger_detection (FpImageDevice *dev); -static void finger_det_data_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE(device); - unsigned char *data = transfer->buffer; - int i; - int sum = 0; + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + unsigned char *data = transfer->buffer; + int i; + int sum = 0; - if (error) { - fpi_image_device_session_error (dev, error); - return; - } + if (error) + { + fpi_image_device_session_error (dev, error); + return; + } - /* examine histogram to determine finger presence */ - for (i = 3; i < 17; i++) - sum += (data[i] & 0xf) + (data[i] >> 4); - if (sum > 20) { - /* reset default gain */ - adjust_gain(data,GAIN_STATUS_FIRST); - /* finger present, start capturing */ - fpi_image_device_report_finger_status(dev, TRUE); - start_capture(dev); - } else { - /* no finger, poll for a new histogram */ - start_finger_detection(dev); - } + /* examine histogram to determine finger presence */ + for (i = 3; i < 17; i++) + sum += (data[i] & 0xf) + (data[i] >> 4); + if (sum > 20) + { + /* reset default gain */ + adjust_gain (data, GAIN_STATUS_FIRST); + /* finger present, start capturing */ + fpi_image_device_report_finger_status (dev, TRUE); + start_capture (dev); + } + else + { + /* no finger, poll for a new histogram */ + start_finger_detection (dev); + } } -static void finger_det_reqs_cb(FpImageDevice *dev, GError *error, - void *user_data) +static void +finger_det_reqs_cb (FpImageDevice *dev, GError *error, + void *user_data) { - FpiUsbTransfer *transfer; + FpiUsbTransfer *transfer; - if (error) { - fpi_image_device_session_error(dev, error); - return; - } + if (error) + { + fpi_image_device_session_error (dev, error); + return; + } - transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); - fpi_usb_transfer_fill_bulk (transfer, EP_IN, FINGER_DETECTION_LEN); - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - finger_det_data_cb, NULL); - fpi_usb_transfer_unref(transfer); + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + fpi_usb_transfer_fill_bulk (transfer, EP_IN, FINGER_DETECTION_LEN); + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + finger_det_data_cb, NULL); + fpi_usb_transfer_unref (transfer); } -static void start_finger_detection(FpImageDevice *dev) +static void +start_finger_detection (FpImageDevice *dev) { - FpiDeviceAes1610 *self = FPI_DEVICE_AES1610(dev); + FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev); - if (self->deactivating) { - complete_deactivation(dev); - return; - } + if (self->deactivating) + { + complete_deactivation (dev); + return; + } - aes_write_regv(dev, finger_det_reqs, G_N_ELEMENTS(finger_det_reqs), finger_det_reqs_cb, NULL); + aes_write_regv (dev, finger_det_reqs, G_N_ELEMENTS (finger_det_reqs), finger_det_reqs_cb, NULL); } /****** CAPTURE ******/ static struct aes_regwrite capture_reqs[] = { - { 0x80, 0x01 }, - { 0x80, 0x12 }, - { 0x84, 0x01 }, - { 0x85, 0x00 }, - { 0x89, 0x64 }, - { 0x8A, 0x00 }, - { 0x8B, 0x0E }, - { 0x8C, 0x90 }, - { 0xBE, 0x23 }, - { 0x29, 0x04 }, - { 0x2A, 0xFF }, - { 0x96, 0x00 }, - { 0x98, 0x03 }, - { 0x99, 0x00 }, - { 0x9C, 0xA5 }, - { 0x9D, 0x40 }, - { 0x9E, 0xC6 }, - { 0x9F, 0x8E }, - { 0xA2, 0x50 }, - { 0xA3, 0xF0 }, - { 0xAD, 0x08 }, - { 0xBD, 0x4F }, - { 0xAF, 0x54 }, - { 0xB1, 0x08 }, - { 0xB5, 0xAB }, - { 0x1B, 0x2D }, - { 0xB6, 0x4E }, - { 0xB8, 0x70 }, - { 0x2B, 0xB3 }, - { 0x2C, 0x5D }, - { 0x2D, 0x98 }, - { 0x2E, 0xB0 }, - { 0x2F, 0x20 }, - { 0xA2, 0xD0 }, - { 0x1D, 0x21 }, - { 0x1E, 0xBE }, - { 0x1C, 0x00 }, - { 0x1D, 0x30 }, - { 0x1E, 0x29 }, - { 0x1C, 0x01 }, - { 0x1D, 0x00 }, - { 0x1E, 0x9E }, - { 0x1C, 0x02 }, - { 0x1D, 0x30 }, - { 0x1E, 0xBB }, - { 0x1C, 0x03 }, - { 0x1D, 0x00 }, - { 0x1E, 0x9D }, - { 0x1C, 0x04 }, - { 0x1D, 0x22 }, - { 0x1E, 0xFF }, - { 0x1C, 0x05 }, - { 0x1D, 0x1B }, - { 0x1E, 0x4E }, - { 0x1C, 0x06 }, - { 0x1D, 0x16 }, - { 0x1E, 0x28 }, - { 0x1C, 0x07 }, - { 0x1D, 0x22 }, - { 0x1E, 0xFF }, - { 0x1C, 0x08 }, - { 0x1D, 0x15 }, - { 0x1E, 0xF1 }, - { 0x1C, 0x09 }, - { 0x1D, 0x30 }, - { 0x1E, 0xD5 }, - { 0x1C, 0x0A }, - { 0x1D, 0x00 }, - { 0x1E, 0x9E }, - { 0x1C, 0x0B }, - { 0x1D, 0x17 }, - { 0x1E, 0x9D }, - { 0x1C, 0x0C }, - { 0x1D, 0x28 }, - { 0x1E, 0xD7 }, - { 0x1C, 0x0D }, - { 0x1D, 0x17 }, - { 0x1E, 0xD7 }, - { 0x1C, 0x0E }, - { 0x1D, 0x0A }, - { 0x1E, 0xCB }, - { 0x1C, 0x0F }, - { 0x1D, 0x24 }, - { 0x1E, 0x14 }, - { 0x1C, 0x10 }, - { 0x1D, 0x17 }, - { 0x1E, 0x85 }, - { 0x1C, 0x11 }, - { 0x1D, 0x15 }, - { 0x1E, 0x71 }, - { 0x1C, 0x12 }, - { 0x1D, 0x2B }, - { 0x1E, 0x36 }, - { 0x1C, 0x13 }, - { 0x1D, 0x12 }, - { 0x1E, 0x06 }, - { 0x1C, 0x14 }, - { 0x1D, 0x30 }, - { 0x1E, 0x97 }, - { 0x1C, 0x15 }, - { 0x1D, 0x21 }, - { 0x1E, 0x32 }, - { 0x1C, 0x16 }, - { 0x1D, 0x06 }, - { 0x1E, 0xE6 }, - { 0x1C, 0x17 }, - { 0x1D, 0x16 }, - { 0x1E, 0x06 }, - { 0x1C, 0x18 }, - { 0x1D, 0x30 }, - { 0x1E, 0x01 }, - { 0x1C, 0x19 }, - { 0x1D, 0x21 }, - { 0x1E, 0x37 }, - { 0x1C, 0x1A }, - { 0x1D, 0x00 }, - { 0x1E, 0x08 }, - { 0x1C, 0x1B }, - { 0x1D, 0x80 }, - { 0x1E, 0xD5 }, - { 0xA2, 0x50 }, - { 0xA2, 0x50 }, - { 0x81, 0x01 } + { 0x80, 0x01 }, + { 0x80, 0x12 }, + { 0x84, 0x01 }, + { 0x85, 0x00 }, + { 0x89, 0x64 }, + { 0x8A, 0x00 }, + { 0x8B, 0x0E }, + { 0x8C, 0x90 }, + { 0xBE, 0x23 }, + { 0x29, 0x04 }, + { 0x2A, 0xFF }, + { 0x96, 0x00 }, + { 0x98, 0x03 }, + { 0x99, 0x00 }, + { 0x9C, 0xA5 }, + { 0x9D, 0x40 }, + { 0x9E, 0xC6 }, + { 0x9F, 0x8E }, + { 0xA2, 0x50 }, + { 0xA3, 0xF0 }, + { 0xAD, 0x08 }, + { 0xBD, 0x4F }, + { 0xAF, 0x54 }, + { 0xB1, 0x08 }, + { 0xB5, 0xAB }, + { 0x1B, 0x2D }, + { 0xB6, 0x4E }, + { 0xB8, 0x70 }, + { 0x2B, 0xB3 }, + { 0x2C, 0x5D }, + { 0x2D, 0x98 }, + { 0x2E, 0xB0 }, + { 0x2F, 0x20 }, + { 0xA2, 0xD0 }, + { 0x1D, 0x21 }, + { 0x1E, 0xBE }, + { 0x1C, 0x00 }, + { 0x1D, 0x30 }, + { 0x1E, 0x29 }, + { 0x1C, 0x01 }, + { 0x1D, 0x00 }, + { 0x1E, 0x9E }, + { 0x1C, 0x02 }, + { 0x1D, 0x30 }, + { 0x1E, 0xBB }, + { 0x1C, 0x03 }, + { 0x1D, 0x00 }, + { 0x1E, 0x9D }, + { 0x1C, 0x04 }, + { 0x1D, 0x22 }, + { 0x1E, 0xFF }, + { 0x1C, 0x05 }, + { 0x1D, 0x1B }, + { 0x1E, 0x4E }, + { 0x1C, 0x06 }, + { 0x1D, 0x16 }, + { 0x1E, 0x28 }, + { 0x1C, 0x07 }, + { 0x1D, 0x22 }, + { 0x1E, 0xFF }, + { 0x1C, 0x08 }, + { 0x1D, 0x15 }, + { 0x1E, 0xF1 }, + { 0x1C, 0x09 }, + { 0x1D, 0x30 }, + { 0x1E, 0xD5 }, + { 0x1C, 0x0A }, + { 0x1D, 0x00 }, + { 0x1E, 0x9E }, + { 0x1C, 0x0B }, + { 0x1D, 0x17 }, + { 0x1E, 0x9D }, + { 0x1C, 0x0C }, + { 0x1D, 0x28 }, + { 0x1E, 0xD7 }, + { 0x1C, 0x0D }, + { 0x1D, 0x17 }, + { 0x1E, 0xD7 }, + { 0x1C, 0x0E }, + { 0x1D, 0x0A }, + { 0x1E, 0xCB }, + { 0x1C, 0x0F }, + { 0x1D, 0x24 }, + { 0x1E, 0x14 }, + { 0x1C, 0x10 }, + { 0x1D, 0x17 }, + { 0x1E, 0x85 }, + { 0x1C, 0x11 }, + { 0x1D, 0x15 }, + { 0x1E, 0x71 }, + { 0x1C, 0x12 }, + { 0x1D, 0x2B }, + { 0x1E, 0x36 }, + { 0x1C, 0x13 }, + { 0x1D, 0x12 }, + { 0x1E, 0x06 }, + { 0x1C, 0x14 }, + { 0x1D, 0x30 }, + { 0x1E, 0x97 }, + { 0x1C, 0x15 }, + { 0x1D, 0x21 }, + { 0x1E, 0x32 }, + { 0x1C, 0x16 }, + { 0x1D, 0x06 }, + { 0x1E, 0xE6 }, + { 0x1C, 0x17 }, + { 0x1D, 0x16 }, + { 0x1E, 0x06 }, + { 0x1C, 0x18 }, + { 0x1D, 0x30 }, + { 0x1E, 0x01 }, + { 0x1C, 0x19 }, + { 0x1D, 0x21 }, + { 0x1E, 0x37 }, + { 0x1C, 0x1A }, + { 0x1D, 0x00 }, + { 0x1E, 0x08 }, + { 0x1C, 0x1B }, + { 0x1D, 0x80 }, + { 0x1E, 0xD5 }, + { 0xA2, 0x50 }, + { 0xA2, 0x50 }, + { 0x81, 0x01 } }; static struct aes_regwrite strip_scan_reqs[] = { - { 0xBE, 0x23 }, - { 0x29, 0x04 }, - { 0x2A, 0xFF }, - { 0xBD, 0x4F }, - { 0xFF, 0x00 } + { 0xBE, 0x23 }, + { 0x29, 0x04 }, + { 0x2A, 0xFF }, + { 0xBD, 0x4F }, + { 0xFF, 0x00 } }; static const struct aes_regwrite capture_stop[] = { - { 0x81,0x00 } + { 0x81, 0x00 } }; /* * The different possible values for 0xBE register */ static unsigned char list_BE_values[10] = { - 0x23, 0x43, 0x63, 0x64, 0x65, 0x67, 0x6A, 0x6B + 0x23, 0x43, 0x63, 0x64, 0x65, 0x67, 0x6A, 0x6B }; /* * The different possible values for 0xBD register */ static unsigned char list_BD_values[10] = { - 0x28, 0x2b, 0x30, 0x3b, 0x45, 0x49, 0x4B + 0x28, 0x2b, 0x30, 0x3b, 0x45, 0x49, 0x4B }; /* @@ -393,129 +413,141 @@ static unsigned char list_BD_values[10] = { * 0xbd, 0xbe, 0x29 and 0x2A registers are affected * Returns 0 if no problem occurred * TODO: This is a basic support for gain. It needs testing/tweaking. */ -static int adjust_gain(unsigned char *buffer, int status) +static int +adjust_gain (unsigned char *buffer, int status) { - // The position in the array of possible values for 0xBE and 0xBD registers - static int pos_list_BE = 0; - static int pos_list_BD = 0; + // The position in the array of possible values for 0xBE and 0xBD registers + static int pos_list_BE = 0; + static int pos_list_BD = 0; - // This is the first adjustment (we begin acquisition) - // We adjust strip_scan_reqs for future strips and capture_reqs that is sent just after this step - if (status == GAIN_STATUS_FIRST) { - if (buffer[1] > 0x78) { // maximum gain needed - strip_scan_reqs[0].value = 0x6B; - strip_scan_reqs[1].value = 0x06; - strip_scan_reqs[2].value = 0x35; - strip_scan_reqs[3].value = 0x4B; - } - else if (buffer[1] > 0x55) { - strip_scan_reqs[0].value = 0x63; - strip_scan_reqs[1].value = 0x15; - strip_scan_reqs[2].value = 0x35; - strip_scan_reqs[3].value = 0x3b; - } - else if (buffer[1] > 0x40 || buffer[16] > 0x19) { - strip_scan_reqs[0].value = 0x43; - strip_scan_reqs[1].value = 0x13; - strip_scan_reqs[2].value = 0x35; - strip_scan_reqs[3].value = 0x30; - } - else { // minimum gain needed - strip_scan_reqs[0].value = 0x23; - strip_scan_reqs[1].value = 0x07; - strip_scan_reqs[2].value = 0x35; - strip_scan_reqs[3].value = 0x28; - } + // This is the first adjustment (we begin acquisition) + // We adjust strip_scan_reqs for future strips and capture_reqs that is sent just after this step + if (status == GAIN_STATUS_FIRST) + { + if (buffer[1] > 0x78) // maximum gain needed + { + strip_scan_reqs[0].value = 0x6B; + strip_scan_reqs[1].value = 0x06; + strip_scan_reqs[2].value = 0x35; + strip_scan_reqs[3].value = 0x4B; + } + else if (buffer[1] > 0x55) + { + strip_scan_reqs[0].value = 0x63; + strip_scan_reqs[1].value = 0x15; + strip_scan_reqs[2].value = 0x35; + strip_scan_reqs[3].value = 0x3b; + } + else if (buffer[1] > 0x40 || buffer[16] > 0x19) + { + strip_scan_reqs[0].value = 0x43; + strip_scan_reqs[1].value = 0x13; + strip_scan_reqs[2].value = 0x35; + strip_scan_reqs[3].value = 0x30; + } + else // minimum gain needed + { + strip_scan_reqs[0].value = 0x23; + strip_scan_reqs[1].value = 0x07; + strip_scan_reqs[2].value = 0x35; + strip_scan_reqs[3].value = 0x28; + } - // Now copy this values in capture_reqs - capture_reqs[8].value = strip_scan_reqs[0].value; - capture_reqs[9].value = strip_scan_reqs[1].value; - capture_reqs[10].value = strip_scan_reqs[2].value; - capture_reqs[21].value = strip_scan_reqs[3].value; + // Now copy this values in capture_reqs + capture_reqs[8].value = strip_scan_reqs[0].value; + capture_reqs[9].value = strip_scan_reqs[1].value; + capture_reqs[10].value = strip_scan_reqs[2].value; + capture_reqs[21].value = strip_scan_reqs[3].value; - fp_dbg("first gain: %x %x %x %x %x %x %x %x", strip_scan_reqs[0].reg, strip_scan_reqs[0].value, strip_scan_reqs[1].reg, strip_scan_reqs[1].value, strip_scan_reqs[2].reg, strip_scan_reqs[2].value, strip_scan_reqs[3].reg, strip_scan_reqs[3].value); - } + fp_dbg ("first gain: %x %x %x %x %x %x %x %x", strip_scan_reqs[0].reg, strip_scan_reqs[0].value, strip_scan_reqs[1].reg, strip_scan_reqs[1].value, strip_scan_reqs[2].reg, strip_scan_reqs[2].value, strip_scan_reqs[3].reg, strip_scan_reqs[3].value); + } + // Every 2/3 strips + // We try to soften big changes of the gain (at least for 0xBE and 0xBD + // FIXME: This softenning will need testing and tweaking too + else if (status == GAIN_STATUS_NORMAL) + { + if (buffer[514] > 0x78) // maximum gain needed + { + if (pos_list_BE < 7) + pos_list_BE++; - // Every 2/3 strips - // We try to soften big changes of the gain (at least for 0xBE and 0xBD - // FIXME: This softenning will need testing and tweaking too - else if (status == GAIN_STATUS_NORMAL) { - if (buffer[514] > 0x78) { // maximum gain needed - if (pos_list_BE < 7) - pos_list_BE++; + if (pos_list_BD < 6) + pos_list_BD++; - if (pos_list_BD < 6) - pos_list_BD++; + strip_scan_reqs[1].value = 0x04; + strip_scan_reqs[2].value = 0x35; + } + else if (buffer[514] > 0x55) + { + if (pos_list_BE < 2) + pos_list_BE++; + else if (pos_list_BE > 2) + pos_list_BE--; - strip_scan_reqs[1].value = 0x04; - strip_scan_reqs[2].value = 0x35; - } - else if (buffer[514] > 0x55) { - if (pos_list_BE < 2) - pos_list_BE++; - else if (pos_list_BE > 2) - pos_list_BE--; + if (pos_list_BD < 2) + pos_list_BD++; + else if (pos_list_BD > 2) + pos_list_BD--; - if (pos_list_BD < 2) - pos_list_BD++; - else if (pos_list_BD > 2) - pos_list_BD--; + strip_scan_reqs[1].value = 0x15; + strip_scan_reqs[2].value = 0x35; + } + else if (buffer[514] > 0x40 || buffer[529] > 0x19) + { + if (pos_list_BE < 1) + pos_list_BE++; + else if (pos_list_BE > 1) + pos_list_BE--; - strip_scan_reqs[1].value = 0x15; - strip_scan_reqs[2].value = 0x35; - } - else if (buffer[514] > 0x40 || buffer[529] > 0x19) { - if (pos_list_BE < 1) - pos_list_BE++; - else if (pos_list_BE > 1) - pos_list_BE--; + if (pos_list_BD < 1) + pos_list_BD++; + else if (pos_list_BD > 1) + pos_list_BD--; - if (pos_list_BD < 1) - pos_list_BD++; - else if (pos_list_BD > 1) - pos_list_BD--; + strip_scan_reqs[1].value = 0x13; + strip_scan_reqs[2].value = 0x35; + } + else // minimum gain needed + { + if (pos_list_BE > 0) + pos_list_BE--; - strip_scan_reqs[1].value = 0x13; - strip_scan_reqs[2].value = 0x35; - } - else { // minimum gain needed - if (pos_list_BE > 0) - pos_list_BE--; + if (pos_list_BD > 0) + pos_list_BD--; - if (pos_list_BD > 0) - pos_list_BD--; + strip_scan_reqs[1].value = 0x07; + strip_scan_reqs[2].value = 0x35; + } - strip_scan_reqs[1].value = 0x07; - strip_scan_reqs[2].value = 0x35; - } + strip_scan_reqs[0].value = list_BE_values[pos_list_BE]; + strip_scan_reqs[3].value = list_BD_values[pos_list_BD]; - strip_scan_reqs[0].value = list_BE_values[pos_list_BE]; - strip_scan_reqs[3].value = list_BD_values[pos_list_BD]; + fp_dbg ("gain: %x %x %x %x %x %x %x %x", strip_scan_reqs[0].reg, strip_scan_reqs[0].value, strip_scan_reqs[1].reg, strip_scan_reqs[1].value, strip_scan_reqs[2].reg, strip_scan_reqs[2].value, strip_scan_reqs[3].reg, strip_scan_reqs[3].value); + } + // Unknown status + else + { + fp_err ("Unexpected gain status."); + return 1; + } - fp_dbg("gain: %x %x %x %x %x %x %x %x", strip_scan_reqs[0].reg, strip_scan_reqs[0].value, strip_scan_reqs[1].reg, strip_scan_reqs[1].value, strip_scan_reqs[2].reg, strip_scan_reqs[2].value, strip_scan_reqs[3].reg, strip_scan_reqs[3].value); - } - // Unknown status - else { - fp_err("Unexpected gain status."); - return 1; - } - - return 0; + return 0; } /* * Restore the default gain values */ -static void restore_gain(void) +static void +restore_gain (void) { - strip_scan_reqs[0].value = list_BE_values[0]; - strip_scan_reqs[1].value = 0x04; - strip_scan_reqs[2].value = 0xFF; - strip_scan_reqs[3].value = list_BD_values[0]; + strip_scan_reqs[0].value = list_BE_values[0]; + strip_scan_reqs[1].value = 0x04; + strip_scan_reqs[2].value = 0xFF; + strip_scan_reqs[3].value = list_BD_values[0]; - capture_reqs[8].value = list_BE_values[0]; - capture_reqs[9].value = 0x04; - capture_reqs[10].value = 0xFF; - capture_reqs[21].value = list_BD_values[0]; + capture_reqs[8].value = list_BE_values[0]; + capture_reqs[9].value = 0x04; + capture_reqs[10].value = 0xFF; + capture_reqs[21].value = list_BD_values[0]; } @@ -525,285 +557,321 @@ static void restore_gain(void) * report lack of finger presence, and move to finger detection */ enum capture_states { - CAPTURE_WRITE_REQS, - CAPTURE_READ_DATA, - CAPTURE_REQUEST_STRIP, - CAPTURE_READ_STRIP, - CAPTURE_NUM_STATES, + CAPTURE_WRITE_REQS, + CAPTURE_READ_DATA, + CAPTURE_REQUEST_STRIP, + CAPTURE_READ_STRIP, + CAPTURE_NUM_STATES, }; -static void capture_read_strip_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - unsigned char *stripdata; - FpImageDevice *dev = FP_IMAGE_DEVICE (device); - FpiDeviceAes1610 *self = FPI_DEVICE_AES1610(dev); - unsigned char *data = transfer->buffer; - gint sum, i; + unsigned char *stripdata; + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev); + unsigned char *data = transfer->buffer; + gint sum, i; - if (error) { - fpi_ssm_mark_failed (transfer->ssm, error); - return; - } + if (error) + { + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } - /* FIXME: would preallocating strip buffers be a decent optimization? */ + /* FIXME: would preallocating strip buffers be a decent optimization? */ - sum = 0; - for (i = 516; i < 530; i++) - { - /* histogram[i] = number of pixels of value i - Only the pixel values from 10 to 15 are used to detect finger. */ - sum += data[i]; - } + sum = 0; + for (i = 516; i < 530; i++) + /* histogram[i] = number of pixels of value i + Only the pixel values from 10 to 15 are used to detect finger. */ + sum += data[i]; - fp_dbg("sum=%d", sum); - if (sum > 0) { - /* FIXME: would preallocating strip buffers be a decent optimization? */ - struct fpi_frame *stripe = g_malloc(FRAME_WIDTH * (FRAME_HEIGHT / 2) + sizeof(struct fpi_frame)); - stripe->delta_x = 0; - stripe->delta_y = 0; - stripdata = stripe->data; - memcpy(stripdata, data + 1, FRAME_WIDTH * (FRAME_HEIGHT / 2)); - self->strips = g_slist_prepend(self->strips, stripe); - self->strips_len++; - self->blanks_count = 0; - } else { - /* FIXME: 0 might be too low as a threshold */ - /* FIXME: sometimes we get 0 in the middle of a scan, should we wait for - * a few consecutive zeroes? */ + fp_dbg ("sum=%d", sum); + if (sum > 0) + { + /* FIXME: would preallocating strip buffers be a decent optimization? */ + struct fpi_frame *stripe = g_malloc (FRAME_WIDTH * (FRAME_HEIGHT / 2) + sizeof (struct fpi_frame)); + stripe->delta_x = 0; + stripe->delta_y = 0; + stripdata = stripe->data; + memcpy (stripdata, data + 1, FRAME_WIDTH * (FRAME_HEIGHT / 2)); + self->strips = g_slist_prepend (self->strips, stripe); + self->strips_len++; + self->blanks_count = 0; + } + else + { + /* FIXME: 0 might be too low as a threshold */ + /* FIXME: sometimes we get 0 in the middle of a scan, should we wait for + * a few consecutive zeroes? */ - /* sum cannot be negative, so is 0 */ - self->blanks_count++; - fp_dbg("got blank frame"); - } + /* sum cannot be negative, so is 0 */ + self->blanks_count++; + fp_dbg ("got blank frame"); + } - /* use histogram data above for gain calibration (0xbd, 0xbe, 0x29 and 0x2A ) */ - adjust_gain(data, GAIN_STATUS_NORMAL); + /* use histogram data above for gain calibration (0xbd, 0xbe, 0x29 and 0x2A ) */ + adjust_gain (data, GAIN_STATUS_NORMAL); - /* stop capturing if MAX_FRAMES is reached */ - if (self->blanks_count > 10 || g_slist_length(self->strips) >= MAX_FRAMES) { - FpImage *img; + /* stop capturing if MAX_FRAMES is reached */ + if (self->blanks_count > 10 || g_slist_length (self->strips) >= MAX_FRAMES) + { + FpImage *img; - fp_dbg("sending stop capture.... blanks=%d frames=%d", - self->blanks_count, g_slist_length(self->strips)); - /* send stop capture bits */ - aes_write_regv(dev, capture_stop, G_N_ELEMENTS(capture_stop), stub_capture_stop_cb, NULL); - self->strips = g_slist_reverse(self->strips); - fpi_do_movement_estimation(&assembling_ctx, self->strips); - img = fpi_assemble_frames(&assembling_ctx, self->strips); + fp_dbg ("sending stop capture.... blanks=%d frames=%d", + self->blanks_count, g_slist_length (self->strips)); + /* send stop capture bits */ + aes_write_regv (dev, capture_stop, G_N_ELEMENTS (capture_stop), stub_capture_stop_cb, NULL); + self->strips = g_slist_reverse (self->strips); + fpi_do_movement_estimation (&assembling_ctx, self->strips); + img = fpi_assemble_frames (&assembling_ctx, self->strips); - g_slist_free_full(self->strips, g_free); - self->strips = NULL; - self->strips_len = 0; - self->blanks_count = 0; - fpi_image_device_image_captured(dev, img); - fpi_image_device_report_finger_status(dev, FALSE); - /* marking machine complete will re-trigger finger detection loop */ - fpi_ssm_mark_completed(transfer->ssm); - /* Acquisition finished: restore default gain values */ - restore_gain(); - } else { - /* obtain next strip */ - fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_REQUEST_STRIP); - } + g_slist_free_full (self->strips, g_free); + self->strips = NULL; + self->strips_len = 0; + self->blanks_count = 0; + fpi_image_device_image_captured (dev, img); + fpi_image_device_report_finger_status (dev, FALSE); + /* marking machine complete will re-trigger finger detection loop */ + fpi_ssm_mark_completed (transfer->ssm); + /* Acquisition finished: restore default gain values */ + restore_gain (); + } + else + { + /* obtain next strip */ + fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_REQUEST_STRIP); + } } -static void capture_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +capture_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - FpImageDevice *dev = user_data; - FpiDeviceAes1610 *self = FPI_DEVICE_AES1610(_dev); + FpImageDevice *dev = user_data; + FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (_dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case CAPTURE_WRITE_REQS: - fp_dbg("write reqs"); - aes_write_regv(dev, capture_reqs, G_N_ELEMENTS(capture_reqs), - generic_write_regv_cb, ssm); - break; - case CAPTURE_READ_DATA: - fp_dbg("read data"); - generic_read_ignore_data(ssm, _dev, STRIP_CAPTURE_LEN); - break; - case CAPTURE_REQUEST_STRIP: - fp_dbg("request strip"); - if (self->deactivating) - fpi_ssm_mark_completed(ssm); - else - aes_write_regv(dev, strip_scan_reqs, G_N_ELEMENTS(strip_scan_reqs), - generic_write_regv_cb, ssm); - break; - case CAPTURE_READ_STRIP: ; - FpiUsbTransfer *transfer = fpi_usb_transfer_new(_dev); + switch (fpi_ssm_get_cur_state (ssm)) + { + case CAPTURE_WRITE_REQS: + fp_dbg ("write reqs"); + aes_write_regv (dev, capture_reqs, G_N_ELEMENTS (capture_reqs), + generic_write_regv_cb, ssm); + break; - fpi_usb_transfer_fill_bulk (transfer, EP_IN, STRIP_CAPTURE_LEN); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - capture_read_strip_cb, NULL); - fpi_usb_transfer_unref(transfer); - break; - }; + case CAPTURE_READ_DATA: + fp_dbg ("read data"); + generic_read_ignore_data (ssm, _dev, STRIP_CAPTURE_LEN); + break; + + case CAPTURE_REQUEST_STRIP: + fp_dbg ("request strip"); + if (self->deactivating) + fpi_ssm_mark_completed (ssm); + else + aes_write_regv (dev, strip_scan_reqs, G_N_ELEMENTS (strip_scan_reqs), + generic_write_regv_cb, ssm); + break; + + case CAPTURE_READ_STRIP:; + FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev); + + fpi_usb_transfer_fill_bulk (transfer, EP_IN, STRIP_CAPTURE_LEN); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + capture_read_strip_cb, NULL); + fpi_usb_transfer_unref (transfer); + break; + } + ; } -static void capture_sm_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +static void +capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - FpImageDevice *dev = user_data; - FpiDeviceAes1610 *self = FPI_DEVICE_AES1610(_dev); + FpImageDevice *dev = user_data; + FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (_dev); - G_DEBUG_HERE(); - if (self->deactivating) { - complete_deactivation(dev); - if (error) - g_error_free (error); - } else if (error) { - fpi_image_device_session_error(dev, error); - } else { - start_finger_detection(dev); - } - fpi_ssm_free(ssm); + G_DEBUG_HERE (); + if (self->deactivating) + { + complete_deactivation (dev); + if (error) + g_error_free (error); + } + else if (error) + { + fpi_image_device_session_error (dev, error); + } + else + { + start_finger_detection (dev); + } + fpi_ssm_free (ssm); } -static void start_capture(FpImageDevice *dev) +static void +start_capture (FpImageDevice *dev) { - FpiDeviceAes1610 *self = FPI_DEVICE_AES1610(dev); - FpiSsm *ssm; + FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev); + FpiSsm *ssm; - if (self->deactivating) { - complete_deactivation(dev); - return; - } + if (self->deactivating) + { + complete_deactivation (dev); + return; + } - ssm = fpi_ssm_new(FP_DEVICE(dev), capture_run_state, - CAPTURE_NUM_STATES, dev); - G_DEBUG_HERE(); - fpi_ssm_start(ssm, capture_sm_complete); + ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, + CAPTURE_NUM_STATES, dev); + G_DEBUG_HERE (); + fpi_ssm_start (ssm, capture_sm_complete); } /****** INITIALIZATION/DEINITIALIZATION ******/ static const struct aes_regwrite init[] = { - { 0x82, 0x00 } + { 0x82, 0x00 } }; /* -static const struct aes_regwrite stop_reader[] = { - { 0xFF, 0x00 } -}; -*/ + static const struct aes_regwrite stop_reader[] = { + { 0xFF, 0x00 } + }; + */ enum activate_states { - WRITE_INIT, - ACTIVATE_NUM_STATES, + WRITE_INIT, + ACTIVATE_NUM_STATES, }; -static void activate_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +activate_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = user_data; - /* activation on aes1610 seems much more straightforward compared to aes2501 */ - /* verify there's anything missing here */ - switch (fpi_ssm_get_cur_state(ssm)) { - case WRITE_INIT: - fp_dbg("write init"); - aes_write_regv(dev, init, G_N_ELEMENTS(init), generic_write_regv_cb, ssm); - break; - } + /* activation on aes1610 seems much more straightforward compared to aes2501 */ + /* verify there's anything missing here */ + switch (fpi_ssm_get_cur_state (ssm)) + { + case WRITE_INIT: + fp_dbg ("write init"); + aes_write_regv (dev, init, G_N_ELEMENTS (init), generic_write_regv_cb, ssm); + break; + } } /* jump to finger detection */ -static void activate_sm_complete(FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +static void +activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - FpImageDevice *dev = user_data; - fpi_image_device_activate_complete(dev, error); + FpImageDevice *dev = user_data; - if (!error) - start_finger_detection(dev); - fpi_ssm_free(ssm); + fpi_image_device_activate_complete (dev, error); + + if (!error) + start_finger_detection (dev); + fpi_ssm_free (ssm); } -static void dev_activate(FpImageDevice *dev) +static void +dev_activate (FpImageDevice *dev) { - FpiDeviceAes1610 *self = FPI_DEVICE_AES1610(dev); - FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); - self->read_regs_retry_count = 0; - fpi_ssm_start(ssm, activate_sm_complete); + FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev); + FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); + + self->read_regs_retry_count = 0; + fpi_ssm_start (ssm, activate_sm_complete); } -static void dev_deactivate(FpImageDevice *dev) +static void +dev_deactivate (FpImageDevice *dev) { - FpiDeviceAes1610 *self = FPI_DEVICE_AES1610(dev); - /* FIXME: audit cancellation points, probably need more, specifically - * in error handling paths? */ - self->deactivating = TRUE; + FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev); + + /* FIXME: audit cancellation points, probably need more, specifically + * in error handling paths? */ + self->deactivating = TRUE; } -static void complete_deactivation(FpImageDevice *dev) +static void +complete_deactivation (FpImageDevice *dev) { - FpiDeviceAes1610 *self = FPI_DEVICE_AES1610(dev); - G_DEBUG_HERE(); + FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev); - /* FIXME: if we're in the middle of a scan, we should cancel the scan. - * maybe we can do this with a master reset, unconditionally? */ + G_DEBUG_HERE (); - self->deactivating = FALSE; - g_slist_free(self->strips); - self->strips = NULL; - self->strips_len = 0; - self->blanks_count = 0; - fpi_image_device_deactivate_complete(dev, NULL); + /* FIXME: if we're in the middle of a scan, we should cancel the scan. + * maybe we can do this with a master reset, unconditionally? */ + + self->deactivating = FALSE; + g_slist_free (self->strips); + self->strips = NULL; + self->strips_len = 0; + self->blanks_count = 0; + fpi_image_device_deactivate_complete (dev, NULL); } -static void dev_init(FpImageDevice *dev) +static void +dev_init (FpImageDevice *dev) { - GError *error = NULL; - /* FIXME check endpoints */ + GError *error = NULL; - if (!g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error)) { - fpi_image_device_open_complete(dev, error); - return; - } + /* FIXME check endpoints */ - fpi_image_device_open_complete(dev, NULL); + if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error)) + { + fpi_image_device_open_complete (dev, error); + return; + } + + fpi_image_device_open_complete (dev, NULL); } -static void dev_deinit(FpImageDevice *dev) +static void +dev_deinit (FpImageDevice *dev) { - GError *error = NULL; + GError *error = NULL; - g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), - 0, 0, &error); - fpi_image_device_close_complete(dev, error); + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), + 0, 0, &error); + fpi_image_device_close_complete (dev, error); } -static const FpIdEntry id_table [ ] = { - { .vid = 0x08ff, .pid = 0x1600, - }, /* AES1600 */ - { .vid = 0, .pid = 0, .driver_data = 0 }, +static const FpIdEntry id_table[] = { + { .vid = 0x08ff, .pid = 0x1600, },/* AES1600 */ + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -static void fpi_device_aes1610_init(FpiDeviceAes1610 *self) { +static void +fpi_device_aes1610_init (FpiDeviceAes1610 *self) +{ } -static void fpi_device_aes1610_class_init(FpiDeviceAes1610Class *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); +static void +fpi_device_aes1610_class_init (FpiDeviceAes1610Class *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); - dev_class->id = "aes1610"; - dev_class->full_name = "AuthenTec AES1610"; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->id_table = id_table; - dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + dev_class->id = "aes1610"; + dev_class->full_name = "AuthenTec AES1610"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - img_class->img_open = dev_init; - img_class->img_close = dev_deinit; - img_class->activate = dev_activate; - img_class->deactivate = dev_deactivate; + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; - img_class->bz3_threshold = 20; + img_class->bz3_threshold = 20; - img_class->img_width = IMAGE_WIDTH; - img_class->img_height = -1; + img_class->img_width = IMAGE_WIDTH; + img_class->img_height = -1; } - diff --git a/libfprint/drivers/aes1660.c b/libfprint/drivers/aes1660.c index cde7b482..93da6967 100644 --- a/libfprint/drivers/aes1660.c +++ b/libfprint/drivers/aes1660.c @@ -25,66 +25,71 @@ #include "aes1660.h" #define FRAME_WIDTH 128 -#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2)) +#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2)) -struct _FpiDeviceAes1660 { - FpiDeviceAesX660 parent; +struct _FpiDeviceAes1660 +{ + FpiDeviceAesX660 parent; }; -G_DECLARE_FINAL_TYPE(FpiDeviceAes1660, fpi_device_aes1660, FPI, - DEVICE_AES1660, FpiDeviceAesX660); -G_DEFINE_TYPE(FpiDeviceAes1660, fpi_device_aes1660, FPI_TYPE_DEVICE_AES_X660); +G_DECLARE_FINAL_TYPE (FpiDeviceAes1660, fpi_device_aes1660, FPI, + DEVICE_AES1660, FpiDeviceAesX660); +G_DEFINE_TYPE (FpiDeviceAes1660, fpi_device_aes1660, FPI_TYPE_DEVICE_AES_X660); static struct fpi_frame_asmbl_ctx assembling_ctx = { - .frame_width = FRAME_WIDTH, - .frame_height = AESX660_FRAME_HEIGHT, - .image_width = IMAGE_WIDTH, - .get_pixel = aes_get_pixel, + .frame_width = FRAME_WIDTH, + .frame_height = AESX660_FRAME_HEIGHT, + .image_width = IMAGE_WIDTH, + .get_pixel = aes_get_pixel, }; -static const FpIdEntry id_table [ ] = { - { .vid = 0x08ff, .pid = 0x1660, }, - { .vid = 0x08ff, .pid = 0x1680, }, - { .vid = 0x08ff, .pid = 0x1681, }, - { .vid = 0x08ff, .pid = 0x1682, }, - { .vid = 0x08ff, .pid = 0x1683, }, - { .vid = 0x08ff, .pid = 0x1684, }, - { .vid = 0x08ff, .pid = 0x1685, }, - { .vid = 0x08ff, .pid = 0x1686, }, - { .vid = 0x08ff, .pid = 0x1687, }, - { .vid = 0x08ff, .pid = 0x1688, }, - { .vid = 0x08ff, .pid = 0x1689, }, - { .vid = 0x08ff, .pid = 0x168a, }, - { .vid = 0x08ff, .pid = 0x168b, }, - { .vid = 0x08ff, .pid = 0x168c, }, - { .vid = 0x08ff, .pid = 0x168d, }, - { .vid = 0x08ff, .pid = 0x168e, }, - { .vid = 0x08ff, .pid = 0x168f, }, - { .vid = 0, .pid = 0, .driver_data = 0 }, +static const FpIdEntry id_table[] = { + { .vid = 0x08ff, .pid = 0x1660, }, + { .vid = 0x08ff, .pid = 0x1680, }, + { .vid = 0x08ff, .pid = 0x1681, }, + { .vid = 0x08ff, .pid = 0x1682, }, + { .vid = 0x08ff, .pid = 0x1683, }, + { .vid = 0x08ff, .pid = 0x1684, }, + { .vid = 0x08ff, .pid = 0x1685, }, + { .vid = 0x08ff, .pid = 0x1686, }, + { .vid = 0x08ff, .pid = 0x1687, }, + { .vid = 0x08ff, .pid = 0x1688, }, + { .vid = 0x08ff, .pid = 0x1689, }, + { .vid = 0x08ff, .pid = 0x168a, }, + { .vid = 0x08ff, .pid = 0x168b, }, + { .vid = 0x08ff, .pid = 0x168c, }, + { .vid = 0x08ff, .pid = 0x168d, }, + { .vid = 0x08ff, .pid = 0x168e, }, + { .vid = 0x08ff, .pid = 0x168f, }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -static void fpi_device_aes1660_init(FpiDeviceAes1660 *self) { +static void +fpi_device_aes1660_init (FpiDeviceAes1660 *self) +{ } -static void fpi_device_aes1660_class_init(FpiDeviceAes1660Class *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); - FpiDeviceAesX660Class *aes_class = FPI_DEVICE_AES_X660_CLASS (klass); +static void +fpi_device_aes1660_class_init (FpiDeviceAes1660Class *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); + FpiDeviceAesX660Class *aes_class = FPI_DEVICE_AES_X660_CLASS (klass); - dev_class->id = "aes1660"; - dev_class->full_name = "AuthenTec AES1660"; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->id_table = id_table; - dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + dev_class->id = "aes1660"; + dev_class->full_name = "AuthenTec AES1660"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - img_class->bz3_threshold = 20; + img_class->bz3_threshold = 20; - img_class->img_width = FRAME_WIDTH + FRAME_WIDTH / 2; - img_class->img_height = -1; + img_class->img_width = FRAME_WIDTH + FRAME_WIDTH / 2; + img_class->img_height = -1; - aes_class->init_seqs[0] = aes1660_init_1; - aes_class->init_seqs_len[0] = G_N_ELEMENTS(aes1660_init_1); - aes_class->init_seqs[1] = aes1660_init_2; - aes_class->init_seqs_len[1] = G_N_ELEMENTS(aes1660_init_2); - aes_class->start_imaging_cmd = (unsigned char *)aes1660_start_imaging_cmd; - aes_class->start_imaging_cmd_len = sizeof(aes1660_start_imaging_cmd); - aes_class->assembling_ctx = &assembling_ctx; + aes_class->init_seqs[0] = aes1660_init_1; + aes_class->init_seqs_len[0] = G_N_ELEMENTS (aes1660_init_1); + aes_class->init_seqs[1] = aes1660_init_2; + aes_class->init_seqs_len[1] = G_N_ELEMENTS (aes1660_init_2); + aes_class->start_imaging_cmd = (unsigned char *) aes1660_start_imaging_cmd; + aes_class->start_imaging_cmd_len = sizeof (aes1660_start_imaging_cmd); + aes_class->assembling_ctx = &assembling_ctx; } diff --git a/libfprint/drivers/aes1660.h b/libfprint/drivers/aes1660.h index ccfb0bce..55a94e20 100644 --- a/libfprint/drivers/aes1660.h +++ b/libfprint/drivers/aes1660.h @@ -29,912 +29,912 @@ /* INIT1 */ static const unsigned char pkt107[] = { -0x44, 0x02, 0x00, 0x04, 0x00, -0x0d, 0x23, -0x42, 0xca, 0x00, -0x00, 0x20, 0x23, -0xff, 0x3f, 0x1d, 0xc1, 0x2e, 0xa3, 0xbf, 0xc2, -0x2e, 0x00, 0xdf, 0xff, 0x2d, 0x02, 0x5a, 0xbf, -0x22, 0xc1, 0x2e, 0xa3, 0xbf, 0x02, 0xcf, 0x0f, -0x1c, 0x10, 0x18, 0x26, 0x83, 0xc8, 0x46, 0x00, -0x5b, 0x01, 0x0c, 0xa2, 0x32, 0xa8, 0xcf, 0xf1, -0x1c, 0x0c, 0x18, 0xa8, 0xaf, 0xaf, 0x31, 0x0a, -0x3a, 0x5d, 0xcf, 0x30, 0x1c, 0x05, 0x55, 0x5d, -0x41, 0x03, 0x5b, 0x5d, 0xcf, 0xfc, 0x1c, 0x01, -0x18, 0x5d, 0xaf, 0x02, 0x43, 0x00, 0x2e, 0x09, -0x5a, 0x0c, 0xef, 0x56, 0xaf, 0x2e, 0x23, 0x02, -0x2e, 0x0b, 0x87, 0x83, 0x23, 0x84, 0x23, 0x81, -0x23, 0x82, 0x23, 0x24, 0x23, 0x0a, 0xef, 0xbf, -0x22, 0x00, 0x2e, 0xa9, 0x8b, 0x57, 0x23, 0x3c, -0x23, 0xf9, 0x34, 0x6b, 0x81, 0x64, 0xef, 0x64, -0xaf, 0x09, 0x88, 0xdf, 0xef, 0x27, 0xff, 0xd6, -0xaf, 0xd7, 0xbf, 0x46, 0xef, 0x46, 0xaf, 0x2a, -0xef, 0x2a, 0xaf, 0x05, 0x81, 0x05, 0x27, 0x10, -0xef, 0x99, 0xaf, 0x9b, 0xaf, 0x04, 0xaf, 0x3d, -0x23, 0x44, 0xef, 0x20, 0xff, 0x1a, 0x27, 0x05, -0xef, 0x27, 0xff, 0x06, 0x27, 0x05, 0x27, 0x9c, -0xcf, 0xdf, 0x96, 0xfe, 0xef, 0x27, 0xff, 0x19, -0x27, 0x65, 0xdf, 0xe1, 0x22, 0x1c, 0x55, 0xe0, -0x97, 0xbf, 0x03, 0x19, 0x5e, 0xfe, 0x0c, 0x9f, -0x22, 0x0f, 0xff, 0xe1, 0x22, 0x10, 0x55, 0x20, -0x00, 0x0e, 0x52, 0x82, 0x03, 0x03, 0x53 + 0x44, 0x02, 0x00, 0x04, 0x00, + 0x0d, 0x23, + 0x42, 0xca, 0x00, + 0x00, 0x20, 0x23, + 0xff, 0x3f, 0x1d, 0xc1, 0x2e, 0xa3, 0xbf, 0xc2, + 0x2e, 0x00, 0xdf, 0xff, 0x2d, 0x02, 0x5a, 0xbf, + 0x22, 0xc1, 0x2e, 0xa3, 0xbf, 0x02, 0xcf, 0x0f, + 0x1c, 0x10, 0x18, 0x26, 0x83, 0xc8, 0x46, 0x00, + 0x5b, 0x01, 0x0c, 0xa2, 0x32, 0xa8, 0xcf, 0xf1, + 0x1c, 0x0c, 0x18, 0xa8, 0xaf, 0xaf, 0x31, 0x0a, + 0x3a, 0x5d, 0xcf, 0x30, 0x1c, 0x05, 0x55, 0x5d, + 0x41, 0x03, 0x5b, 0x5d, 0xcf, 0xfc, 0x1c, 0x01, + 0x18, 0x5d, 0xaf, 0x02, 0x43, 0x00, 0x2e, 0x09, + 0x5a, 0x0c, 0xef, 0x56, 0xaf, 0x2e, 0x23, 0x02, + 0x2e, 0x0b, 0x87, 0x83, 0x23, 0x84, 0x23, 0x81, + 0x23, 0x82, 0x23, 0x24, 0x23, 0x0a, 0xef, 0xbf, + 0x22, 0x00, 0x2e, 0xa9, 0x8b, 0x57, 0x23, 0x3c, + 0x23, 0xf9, 0x34, 0x6b, 0x81, 0x64, 0xef, 0x64, + 0xaf, 0x09, 0x88, 0xdf, 0xef, 0x27, 0xff, 0xd6, + 0xaf, 0xd7, 0xbf, 0x46, 0xef, 0x46, 0xaf, 0x2a, + 0xef, 0x2a, 0xaf, 0x05, 0x81, 0x05, 0x27, 0x10, + 0xef, 0x99, 0xaf, 0x9b, 0xaf, 0x04, 0xaf, 0x3d, + 0x23, 0x44, 0xef, 0x20, 0xff, 0x1a, 0x27, 0x05, + 0xef, 0x27, 0xff, 0x06, 0x27, 0x05, 0x27, 0x9c, + 0xcf, 0xdf, 0x96, 0xfe, 0xef, 0x27, 0xff, 0x19, + 0x27, 0x65, 0xdf, 0xe1, 0x22, 0x1c, 0x55, 0xe0, + 0x97, 0xbf, 0x03, 0x19, 0x5e, 0xfe, 0x0c, 0x9f, + 0x22, 0x0f, 0xff, 0xe1, 0x22, 0x10, 0x55, 0x20, + 0x00, 0x0e, 0x52, 0x82, 0x03, 0x03, 0x53 }; static const unsigned char pkt112[] = { -0x42, 0xca, 0x00, -0x64, 0x20, 0xfe, 0x0d, 0x7f, -0x20, 0xf6, 0x55, 0x08, 0x50, 0x5f, 0x90, 0x82, -0x01, 0x1f, 0x90, 0xc1, 0x97, 0xa0, 0x01, 0x82, -0x01, 0xdf, 0x21, 0x80, 0x03, 0x00, 0x5e, 0x3f, -0x20, 0x29, 0xbf, 0x03, 0x0c, 0x05, 0x27, 0x01, -0x0c, 0x10, 0xff, 0x29, 0xbf, 0x05, 0x27, 0x9a, -0xcf, 0xdf, 0x96, 0xe0, 0xef, 0x27, 0xff, 0x19, -0x27, 0xfe, 0x0c, 0x9f, 0x22, 0x00, 0xff, 0xe1, -0x22, 0x10, 0x55, 0x20, 0x00, 0x0e, 0x52, 0x82, -0x03, 0x03, 0x53, 0x02, 0x0d, 0x3f, 0x20, 0x0f, -0x1f, 0xf5, 0x55, 0x5f, 0x90, 0x82, 0x01, 0x1f, -0x90, 0xc1, 0x97, 0xa0, 0x01, 0x82, 0x01, 0xdf, -0x21, 0x80, 0x03, 0x02, 0x5e, 0x7f, 0x20, 0x00, -0x53, 0xbf, 0x22, 0x29, 0xcf, 0xbf, 0x03, 0x01, -0x5e, 0x5f, 0x20, 0xdf, 0x9f, 0x28, 0xbf, 0x03, -0x0c, 0x05, 0x27, 0x24, 0xcf, 0x10, 0xdf, 0xbf, -0x01, 0x06, 0x1e, 0xe1, 0x2f, 0xe6, 0x5c, 0xdf, -0x2d, 0x00, 0x5b, 0x9f, 0x22, 0xdf, 0x96, 0xc8, -0xef, 0x20, 0xff, 0x1d, 0x00, 0x00, 0x13, 0x1a, -0x27, 0x07, 0x27, 0x9b, 0x22, 0xdf, 0x96, 0xbb, -0xcf, 0x1a, 0x88, 0xbb, 0xcf, 0x1b, 0x88, 0x01, -0x0f, 0xbc, 0xcf, 0x15, 0x88, 0xbc, 0xcf, 0x16, -0x88, 0x01, 0x0f, 0xbd, 0xcf, 0x10, 0x88, 0xbd, -0xcf, 0x11, 0x88, 0x01, 0x0f, 0xbe, 0xcf, 0x0b, -0x88, 0xbe, 0xcf, 0x0c, 0x88, 0x01, 0x0c, 0xdd, -0x97, 0x25, 0xaf, 0x05, 0x27 + 0x42, 0xca, 0x00, + 0x64, 0x20, 0xfe, 0x0d, 0x7f, + 0x20, 0xf6, 0x55, 0x08, 0x50, 0x5f, 0x90, 0x82, + 0x01, 0x1f, 0x90, 0xc1, 0x97, 0xa0, 0x01, 0x82, + 0x01, 0xdf, 0x21, 0x80, 0x03, 0x00, 0x5e, 0x3f, + 0x20, 0x29, 0xbf, 0x03, 0x0c, 0x05, 0x27, 0x01, + 0x0c, 0x10, 0xff, 0x29, 0xbf, 0x05, 0x27, 0x9a, + 0xcf, 0xdf, 0x96, 0xe0, 0xef, 0x27, 0xff, 0x19, + 0x27, 0xfe, 0x0c, 0x9f, 0x22, 0x00, 0xff, 0xe1, + 0x22, 0x10, 0x55, 0x20, 0x00, 0x0e, 0x52, 0x82, + 0x03, 0x03, 0x53, 0x02, 0x0d, 0x3f, 0x20, 0x0f, + 0x1f, 0xf5, 0x55, 0x5f, 0x90, 0x82, 0x01, 0x1f, + 0x90, 0xc1, 0x97, 0xa0, 0x01, 0x82, 0x01, 0xdf, + 0x21, 0x80, 0x03, 0x02, 0x5e, 0x7f, 0x20, 0x00, + 0x53, 0xbf, 0x22, 0x29, 0xcf, 0xbf, 0x03, 0x01, + 0x5e, 0x5f, 0x20, 0xdf, 0x9f, 0x28, 0xbf, 0x03, + 0x0c, 0x05, 0x27, 0x24, 0xcf, 0x10, 0xdf, 0xbf, + 0x01, 0x06, 0x1e, 0xe1, 0x2f, 0xe6, 0x5c, 0xdf, + 0x2d, 0x00, 0x5b, 0x9f, 0x22, 0xdf, 0x96, 0xc8, + 0xef, 0x20, 0xff, 0x1d, 0x00, 0x00, 0x13, 0x1a, + 0x27, 0x07, 0x27, 0x9b, 0x22, 0xdf, 0x96, 0xbb, + 0xcf, 0x1a, 0x88, 0xbb, 0xcf, 0x1b, 0x88, 0x01, + 0x0f, 0xbc, 0xcf, 0x15, 0x88, 0xbc, 0xcf, 0x16, + 0x88, 0x01, 0x0f, 0xbd, 0xcf, 0x10, 0x88, 0xbd, + 0xcf, 0x11, 0x88, 0x01, 0x0f, 0xbe, 0xcf, 0x0b, + 0x88, 0xbe, 0xcf, 0x0c, 0x88, 0x01, 0x0c, 0xdd, + 0x97, 0x25, 0xaf, 0x05, 0x27 }; static const unsigned char pkt116[] = { -0x42, 0xca, 0x00, -0xc8, 0x20, 0xff, 0x00, 0xab, -0x00, 0x72, 0x00, 0x4c, 0x00, 0x33, 0x00, 0x22, -0x00, 0x09, 0x88, 0xbf, 0x9d, 0x05, 0x27, 0x09, -0x27, 0x05, 0x88, 0xff, 0x97, 0x09, 0x27, 0xf6, -0x9f, 0x5f, 0x02, 0xbf, 0x9d, 0x05, 0x27, 0x0f, -0x1c, 0xc0, 0x9f, 0x8a, 0x80, 0x80, 0x10, 0x00, -0x13, 0x0f, 0x1d, 0xc1, 0x03, 0x00, 0x5f, 0x7f, -0x90, 0x05, 0x27, 0x53, 0x80, 0x2b, 0x0d, 0x05, -0x27, 0x9f, 0x22, 0x8f, 0xaf, 0x67, 0x2e, 0xe0, -0xdf, 0x04, 0x1e, 0x00, 0x52, 0x8f, 0x30, 0x67, -0x2e, 0xe1, 0xdf, 0xdf, 0x22, 0x00, 0x54, 0x8f, -0x30, 0x67, 0x2e, 0xfe, 0xdf, 0x04, 0x1e, 0x00, -0x52, 0x8f, 0x31, 0x67, 0x2e, 0xff, 0xdf, 0xdf, -0x22, 0x00, 0x54, 0x8f, 0x31, 0x8f, 0xcf, 0x03, -0x1c, 0x03, 0x1e, 0x00, 0x55, 0x0c, 0x27, 0x0d, -0x27, 0x4a, 0xcf, 0xdf, 0x96, 0x10, 0xcf, 0x5f, -0xdf, 0xbf, 0x03, 0x02, 0x5f, 0x5f, 0xcf, 0x10, -0xaf, 0x04, 0x50, 0x5e, 0xdf, 0xbf, 0x03, 0x01, -0x53, 0x5e, 0xcf, 0x10, 0xaf, 0x46, 0x88, 0x01, -0x2e, 0x1e, 0x80, 0xdd, 0x97, 0x0a, 0x40, 0x1c, -0x5a, 0x37, 0x43, 0x0b, 0x5b, 0xe2, 0xcf, 0x0f, -0x1c, 0x06, 0x1e, 0x07, 0x52, 0x62, 0xdf, 0x18, -0x1f, 0x07, 0x53, 0x04, 0x16, 0xe2, 0xaf, 0x04, -0x11, 0x62, 0xbf, 0x02, 0x50, 0x62, 0xcf, 0xdf, -0x22, 0x0e, 0x54, 0x0e, 0x88, 0x62, 0xdf, 0xbf, -0x03, 0x04, 0x53, 0x62, 0xaf + 0x42, 0xca, 0x00, + 0xc8, 0x20, 0xff, 0x00, 0xab, + 0x00, 0x72, 0x00, 0x4c, 0x00, 0x33, 0x00, 0x22, + 0x00, 0x09, 0x88, 0xbf, 0x9d, 0x05, 0x27, 0x09, + 0x27, 0x05, 0x88, 0xff, 0x97, 0x09, 0x27, 0xf6, + 0x9f, 0x5f, 0x02, 0xbf, 0x9d, 0x05, 0x27, 0x0f, + 0x1c, 0xc0, 0x9f, 0x8a, 0x80, 0x80, 0x10, 0x00, + 0x13, 0x0f, 0x1d, 0xc1, 0x03, 0x00, 0x5f, 0x7f, + 0x90, 0x05, 0x27, 0x53, 0x80, 0x2b, 0x0d, 0x05, + 0x27, 0x9f, 0x22, 0x8f, 0xaf, 0x67, 0x2e, 0xe0, + 0xdf, 0x04, 0x1e, 0x00, 0x52, 0x8f, 0x30, 0x67, + 0x2e, 0xe1, 0xdf, 0xdf, 0x22, 0x00, 0x54, 0x8f, + 0x30, 0x67, 0x2e, 0xfe, 0xdf, 0x04, 0x1e, 0x00, + 0x52, 0x8f, 0x31, 0x67, 0x2e, 0xff, 0xdf, 0xdf, + 0x22, 0x00, 0x54, 0x8f, 0x31, 0x8f, 0xcf, 0x03, + 0x1c, 0x03, 0x1e, 0x00, 0x55, 0x0c, 0x27, 0x0d, + 0x27, 0x4a, 0xcf, 0xdf, 0x96, 0x10, 0xcf, 0x5f, + 0xdf, 0xbf, 0x03, 0x02, 0x5f, 0x5f, 0xcf, 0x10, + 0xaf, 0x04, 0x50, 0x5e, 0xdf, 0xbf, 0x03, 0x01, + 0x53, 0x5e, 0xcf, 0x10, 0xaf, 0x46, 0x88, 0x01, + 0x2e, 0x1e, 0x80, 0xdd, 0x97, 0x0a, 0x40, 0x1c, + 0x5a, 0x37, 0x43, 0x0b, 0x5b, 0xe2, 0xcf, 0x0f, + 0x1c, 0x06, 0x1e, 0x07, 0x52, 0x62, 0xdf, 0x18, + 0x1f, 0x07, 0x53, 0x04, 0x16, 0xe2, 0xaf, 0x04, + 0x11, 0x62, 0xbf, 0x02, 0x50, 0x62, 0xcf, 0xdf, + 0x22, 0x0e, 0x54, 0x0e, 0x88, 0x62, 0xdf, 0xbf, + 0x03, 0x04, 0x53, 0x62, 0xaf }; static const unsigned char pkt120[] = { -0x42, 0xca, 0x00, -0x2c, 0x21, 0xdf, 0x01, 0xe2, -0xcf, 0x3f, 0x00, 0xe2, 0xaf, 0x0e, 0x88, 0x4a, -0xdf, 0x3f, 0x00, 0x4a, 0xaf, 0x00, 0x2e, 0xc4, -0x8d, 0x05, 0x27, 0xff, 0xef, 0x4a, 0xdf, 0xbf, -0x01, 0x0a, 0x88, 0xa1, 0x27, 0x5f, 0x21, 0x7f, -0x20, 0xfb, 0x55, 0x05, 0x27, 0x62, 0xcf, 0x03, -0x88, 0x1f, 0x22, 0x7f, 0x20, 0xfc, 0x55, 0x05, -0x27, 0x10, 0xdf, 0x02, 0x1f, 0x02, 0x5e, 0x04, -0xff, 0x00, 0x2e, 0x0a, 0x50, 0x05, 0x1f, 0x02, -0x5e, 0x03, 0xff, 0x00, 0x2e, 0x05, 0x50, 0x06, -0x1f, 0x02, 0x5e, 0x02, 0xff, 0x00, 0x2e, 0x00, -0x50, 0x01, 0xff, 0x05, 0x27, 0x10, 0xcf, 0x60, -0xff, 0x3f, 0x00, 0x21, 0xff, 0x00, 0x13, 0x1a, -0x27, 0x07, 0x27, 0x05, 0x27, 0x01, 0x00, 0x02, -0x57, 0x42, 0x87, 0x52, 0x80, 0x92, 0x81, 0xd2, -0x6c, 0xe2, 0x80, 0xf2, 0x80, 0xf6, 0x7b, 0xfa, -0x7e, 0xfe, 0x8b, 0xf9, 0x45, 0x04, 0x5a, 0x40, -0xef, 0xf9, 0x44, 0x03, 0x5b, 0x80, 0xef, 0x01, -0x50, 0x41, 0x2e, 0x7e, 0xdf, 0x4d, 0xaf, 0x05, -0x27, 0x28, 0xff, 0x54, 0xef, 0x19, 0x27, 0x4d, -0x26, 0xe0, 0x2f, 0xfb, 0x54, 0x27, 0xff, 0xe0, -0xef, 0x1b, 0x27, 0x10, 0xef, 0x06, 0xaf, 0xfc, -0x97, 0xfc, 0x9f, 0x1c, 0x82, 0x1c, 0x82, 0x1a, -0x27, 0x4d, 0xdf, 0x6d, 0x80, 0x5f, 0x9f, 0x06, -0x25, 0xf5, 0x55, 0x05, 0x27, 0x26, 0x1f, 0x00, -0x5f, 0xbf, 0x22, 0xff, 0x96 + 0x42, 0xca, 0x00, + 0x2c, 0x21, 0xdf, 0x01, 0xe2, + 0xcf, 0x3f, 0x00, 0xe2, 0xaf, 0x0e, 0x88, 0x4a, + 0xdf, 0x3f, 0x00, 0x4a, 0xaf, 0x00, 0x2e, 0xc4, + 0x8d, 0x05, 0x27, 0xff, 0xef, 0x4a, 0xdf, 0xbf, + 0x01, 0x0a, 0x88, 0xa1, 0x27, 0x5f, 0x21, 0x7f, + 0x20, 0xfb, 0x55, 0x05, 0x27, 0x62, 0xcf, 0x03, + 0x88, 0x1f, 0x22, 0x7f, 0x20, 0xfc, 0x55, 0x05, + 0x27, 0x10, 0xdf, 0x02, 0x1f, 0x02, 0x5e, 0x04, + 0xff, 0x00, 0x2e, 0x0a, 0x50, 0x05, 0x1f, 0x02, + 0x5e, 0x03, 0xff, 0x00, 0x2e, 0x05, 0x50, 0x06, + 0x1f, 0x02, 0x5e, 0x02, 0xff, 0x00, 0x2e, 0x00, + 0x50, 0x01, 0xff, 0x05, 0x27, 0x10, 0xcf, 0x60, + 0xff, 0x3f, 0x00, 0x21, 0xff, 0x00, 0x13, 0x1a, + 0x27, 0x07, 0x27, 0x05, 0x27, 0x01, 0x00, 0x02, + 0x57, 0x42, 0x87, 0x52, 0x80, 0x92, 0x81, 0xd2, + 0x6c, 0xe2, 0x80, 0xf2, 0x80, 0xf6, 0x7b, 0xfa, + 0x7e, 0xfe, 0x8b, 0xf9, 0x45, 0x04, 0x5a, 0x40, + 0xef, 0xf9, 0x44, 0x03, 0x5b, 0x80, 0xef, 0x01, + 0x50, 0x41, 0x2e, 0x7e, 0xdf, 0x4d, 0xaf, 0x05, + 0x27, 0x28, 0xff, 0x54, 0xef, 0x19, 0x27, 0x4d, + 0x26, 0xe0, 0x2f, 0xfb, 0x54, 0x27, 0xff, 0xe0, + 0xef, 0x1b, 0x27, 0x10, 0xef, 0x06, 0xaf, 0xfc, + 0x97, 0xfc, 0x9f, 0x1c, 0x82, 0x1c, 0x82, 0x1a, + 0x27, 0x4d, 0xdf, 0x6d, 0x80, 0x5f, 0x9f, 0x06, + 0x25, 0xf5, 0x55, 0x05, 0x27, 0x26, 0x1f, 0x00, + 0x5f, 0xbf, 0x22, 0xff, 0x96 }; static const unsigned char pkt124[] = { -0x42, 0xac, 0x00, -0x90, 0x21, 0x99, 0xef, 0x21, -0xff, 0x1d, 0x00, 0x00, 0x13, 0x1a, 0x27, 0x07, -0x27, 0x1a, 0x27, 0xd6, 0x97, 0x05, 0x27, 0xa3, -0x01, 0xa4, 0x01, 0xa3, 0x01, 0x2e, 0x00, 0xb0, -0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb4, -0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, -0x00, 0xb9, 0x00, 0xba, 0x00, 0x56, 0x00, 0xae, -0x00, 0x54, 0x01, 0x44, 0x01, 0x55, 0x01, 0x44, -0x01, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbe, -0x00, 0x83, 0x00, 0x84, 0x00, 0x81, 0x00, 0x82, -0x00, 0x24, 0x00, 0x44, 0x01, 0xdb, 0x00, 0xdc, -0x00, 0xdd, 0x00, 0xde, 0x00, 0x04, 0x00, 0x9b, -0x00, 0x99, 0x00, 0x9e, 0x00, 0x10, 0xef, 0xe6, -0x81, 0x65, 0xaf, 0x10, 0xef, 0xe6, 0x81, 0x9c, -0xaf, 0x10, 0xef, 0xe6, 0x81, 0x9a, 0xaf, 0x05, -0x27, 0xe5, 0x31, 0x1d, 0x81, 0xe5, 0x39, 0x05, -0x27, 0xc8, 0x46, 0x0b, 0x5b, 0xd3, 0x45, 0xfd, -0x5a, 0xd3, 0x45, 0xfb, 0x5a, 0xd3, 0x45, 0xf9, -0x5a, 0x41, 0x2e, 0xa1, 0xdf, 0x9f, 0x28, 0x41, -0x2e, 0xa1, 0xbf, 0x00, 0x88, 0x05, 0x27, 0x9f, -0x22, 0xbf, 0x22, 0x1f, 0x20, 0xfd, 0x53, 0x3f, -0x20, 0x14, 0x1f, 0xfa, 0x55, 0x05, 0x27 + 0x42, 0xac, 0x00, + 0x90, 0x21, 0x99, 0xef, 0x21, + 0xff, 0x1d, 0x00, 0x00, 0x13, 0x1a, 0x27, 0x07, + 0x27, 0x1a, 0x27, 0xd6, 0x97, 0x05, 0x27, 0xa3, + 0x01, 0xa4, 0x01, 0xa3, 0x01, 0x2e, 0x00, 0xb0, + 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb4, + 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, + 0x00, 0xb9, 0x00, 0xba, 0x00, 0x56, 0x00, 0xae, + 0x00, 0x54, 0x01, 0x44, 0x01, 0x55, 0x01, 0x44, + 0x01, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbe, + 0x00, 0x83, 0x00, 0x84, 0x00, 0x81, 0x00, 0x82, + 0x00, 0x24, 0x00, 0x44, 0x01, 0xdb, 0x00, 0xdc, + 0x00, 0xdd, 0x00, 0xde, 0x00, 0x04, 0x00, 0x9b, + 0x00, 0x99, 0x00, 0x9e, 0x00, 0x10, 0xef, 0xe6, + 0x81, 0x65, 0xaf, 0x10, 0xef, 0xe6, 0x81, 0x9c, + 0xaf, 0x10, 0xef, 0xe6, 0x81, 0x9a, 0xaf, 0x05, + 0x27, 0xe5, 0x31, 0x1d, 0x81, 0xe5, 0x39, 0x05, + 0x27, 0xc8, 0x46, 0x0b, 0x5b, 0xd3, 0x45, 0xfd, + 0x5a, 0xd3, 0x45, 0xfb, 0x5a, 0xd3, 0x45, 0xf9, + 0x5a, 0x41, 0x2e, 0xa1, 0xdf, 0x9f, 0x28, 0x41, + 0x2e, 0xa1, 0xbf, 0x00, 0x88, 0x05, 0x27, 0x9f, + 0x22, 0xbf, 0x22, 0x1f, 0x20, 0xfd, 0x53, 0x3f, + 0x20, 0x14, 0x1f, 0xfa, 0x55, 0x05, 0x27 }; static const unsigned char pkt128[] = { -0x42, 0xca, 0x00, -0xe5, 0x21, 0x25, 0x85, 0x01, -0x1e, 0x17, 0x55, 0xdc, 0x8a, 0x41, 0x2e, 0x53, -0xdf, 0xc1, 0x2e, 0x79, 0xdf, 0xff, 0x96, 0xdf, -0x96, 0x41, 0x2e, 0x55, 0xdf, 0xc1, 0x2e, 0x78, -0xdf, 0x9d, 0x01, 0x5d, 0x01, 0xff, 0x22, 0x00, -0x54, 0xff, 0xef, 0x2e, 0xaf, 0x05, 0x27, 0x07, -0x80, 0x9f, 0x22, 0xff, 0xaf, 0x00, 0x2e, 0x5d, -0x89, 0x05, 0x27, 0x03, 0x1e, 0x3c, 0x55, 0xaf, -0x8a, 0xa1, 0xcf, 0xfe, 0x1c, 0xa1, 0xaf, 0x05, -0x81, 0x47, 0x81, 0x76, 0x88, 0xff, 0x96, 0xdf, -0x96, 0xa1, 0xcf, 0x01, 0x18, 0xa1, 0xaf, 0x05, -0x81, 0x64, 0xef, 0xbf, 0x22, 0xbd, 0x80, 0x47, -0x81, 0x6b, 0x88, 0xff, 0x96, 0xdf, 0x96, 0x9b, -0x22, 0x14, 0x1e, 0x03, 0x53, 0xff, 0x22, 0x01, -0x55, 0x00, 0x20, 0x0a, 0x50, 0xc3, 0x97, 0xc4, -0x9f, 0x81, 0x01, 0x42, 0x01, 0x03, 0x52, 0xfa, -0x1e, 0x03, 0x53, 0xff, 0x22, 0x01, 0x55, 0x00, -0x20, 0xf2, 0x50, 0x00, 0x2e, 0xf0, 0x8b, 0x03, -0xcf, 0x7f, 0x1c, 0xff, 0xaf, 0x05, 0xef, 0xff, -0xaf, 0x00, 0xef, 0xff, 0xaf, 0xdd, 0x97, 0xff, -0xaf, 0xc2, 0x97, 0xff, 0xaf, 0xc3, 0x97, 0xff, -0xaf, 0xc0, 0x97, 0xff, 0xaf, 0xc1, 0x97, 0xff, -0xaf, 0x04, 0x0c, 0x00, 0x2e, 0x5d, 0x89, 0x05, -0x27, 0x06, 0x1e, 0x00, 0x55, 0x0f, 0x27, 0x0a, -0x1e, 0x07, 0x55, 0x00, 0x88, 0x66, 0x76, 0x3b, -0x30, 0x07, 0x35, 0xff, 0xff + 0x42, 0xca, 0x00, + 0xe5, 0x21, 0x25, 0x85, 0x01, + 0x1e, 0x17, 0x55, 0xdc, 0x8a, 0x41, 0x2e, 0x53, + 0xdf, 0xc1, 0x2e, 0x79, 0xdf, 0xff, 0x96, 0xdf, + 0x96, 0x41, 0x2e, 0x55, 0xdf, 0xc1, 0x2e, 0x78, + 0xdf, 0x9d, 0x01, 0x5d, 0x01, 0xff, 0x22, 0x00, + 0x54, 0xff, 0xef, 0x2e, 0xaf, 0x05, 0x27, 0x07, + 0x80, 0x9f, 0x22, 0xff, 0xaf, 0x00, 0x2e, 0x5d, + 0x89, 0x05, 0x27, 0x03, 0x1e, 0x3c, 0x55, 0xaf, + 0x8a, 0xa1, 0xcf, 0xfe, 0x1c, 0xa1, 0xaf, 0x05, + 0x81, 0x47, 0x81, 0x76, 0x88, 0xff, 0x96, 0xdf, + 0x96, 0xa1, 0xcf, 0x01, 0x18, 0xa1, 0xaf, 0x05, + 0x81, 0x64, 0xef, 0xbf, 0x22, 0xbd, 0x80, 0x47, + 0x81, 0x6b, 0x88, 0xff, 0x96, 0xdf, 0x96, 0x9b, + 0x22, 0x14, 0x1e, 0x03, 0x53, 0xff, 0x22, 0x01, + 0x55, 0x00, 0x20, 0x0a, 0x50, 0xc3, 0x97, 0xc4, + 0x9f, 0x81, 0x01, 0x42, 0x01, 0x03, 0x52, 0xfa, + 0x1e, 0x03, 0x53, 0xff, 0x22, 0x01, 0x55, 0x00, + 0x20, 0xf2, 0x50, 0x00, 0x2e, 0xf0, 0x8b, 0x03, + 0xcf, 0x7f, 0x1c, 0xff, 0xaf, 0x05, 0xef, 0xff, + 0xaf, 0x00, 0xef, 0xff, 0xaf, 0xdd, 0x97, 0xff, + 0xaf, 0xc2, 0x97, 0xff, 0xaf, 0xc3, 0x97, 0xff, + 0xaf, 0xc0, 0x97, 0xff, 0xaf, 0xc1, 0x97, 0xff, + 0xaf, 0x04, 0x0c, 0x00, 0x2e, 0x5d, 0x89, 0x05, + 0x27, 0x06, 0x1e, 0x00, 0x55, 0x0f, 0x27, 0x0a, + 0x1e, 0x07, 0x55, 0x00, 0x88, 0x66, 0x76, 0x3b, + 0x30, 0x07, 0x35, 0xff, 0xff }; static const unsigned char pkt133[] = { -0x42, 0xc2, 0x00, -0x49, 0x22, 0xc2, 0xbf, 0x0d, -0x27, 0x0c, 0x27, 0x0d, 0x1e, 0x02, 0x55, 0x28, -0x85, 0xf5, 0x5b, 0x7b, 0x76, 0x12, 0x1e, 0x07, -0x55, 0xdc, 0xef, 0x05, 0xff, 0x1a, 0x27, 0x56, -0xdf, 0x3f, 0x20, 0x6d, 0x80, 0x3c, 0xaf, 0x05, -0x27, 0x13, 0x1e, 0x01, 0x55, 0x3c, 0x23, 0x05, -0x27, 0x23, 0x1e, 0x0c, 0x55, 0x00, 0xef, 0x02, -0xff, 0x19, 0x27, 0xbf, 0x22, 0x20, 0xef, 0x7f, -0x9f, 0x5f, 0x20, 0xfc, 0x55, 0xf0, 0x81, 0x9f, -0x22, 0x41, 0x2e, 0xa3, 0xbf, 0x05, 0x27, 0x30, -0x1e, 0x0e, 0x55, 0x7e, 0xef, 0xff, 0xaf, 0x02, -0xef, 0xff, 0xaf, 0x00, 0xef, 0xff, 0xaf, 0xff, -0xef, 0x17, 0xff, 0x1a, 0x27, 0x07, 0x27, 0xff, -0xaf, 0xff, 0xbf, 0x00, 0x2e, 0x5d, 0x89, 0x05, -0x27, 0xcb, 0x74, 0xc9, 0xcf, 0xf3, 0x1c, 0x04, -0x18, 0xc9, 0xaf, 0x39, 0x81, 0x10, 0xff, 0xff, -0xef, 0xc1, 0x2e, 0x7c, 0xbf, 0x41, 0x2e, 0x7b, -0xbf, 0x02, 0xef, 0x41, 0x2e, 0x7a, 0xbf, 0xc9, -0x31, 0x18, 0xef, 0xc0, 0xaf, 0x04, 0x27, 0x41, -0x2e, 0x7a, 0xdf, 0xdf, 0x2d, 0x08, 0x5b, 0x01, -0xef, 0x41, 0x2e, 0x7a, 0xbf, 0xc0, 0x23, 0x18, -0xef, 0xc1, 0xaf, 0xcb, 0xcf, 0xcc, 0xdf, 0x05, -0x27, 0xc9, 0x30, 0x01, 0xef, 0x41, 0x2e, 0x7a, -0xbf, 0xc0, 0x23, 0x18, 0xef, 0xc1, 0xaf, 0x9f, -0x22, 0xbf, 0x22, 0x05, 0x27 + 0x42, 0xc2, 0x00, + 0x49, 0x22, 0xc2, 0xbf, 0x0d, + 0x27, 0x0c, 0x27, 0x0d, 0x1e, 0x02, 0x55, 0x28, + 0x85, 0xf5, 0x5b, 0x7b, 0x76, 0x12, 0x1e, 0x07, + 0x55, 0xdc, 0xef, 0x05, 0xff, 0x1a, 0x27, 0x56, + 0xdf, 0x3f, 0x20, 0x6d, 0x80, 0x3c, 0xaf, 0x05, + 0x27, 0x13, 0x1e, 0x01, 0x55, 0x3c, 0x23, 0x05, + 0x27, 0x23, 0x1e, 0x0c, 0x55, 0x00, 0xef, 0x02, + 0xff, 0x19, 0x27, 0xbf, 0x22, 0x20, 0xef, 0x7f, + 0x9f, 0x5f, 0x20, 0xfc, 0x55, 0xf0, 0x81, 0x9f, + 0x22, 0x41, 0x2e, 0xa3, 0xbf, 0x05, 0x27, 0x30, + 0x1e, 0x0e, 0x55, 0x7e, 0xef, 0xff, 0xaf, 0x02, + 0xef, 0xff, 0xaf, 0x00, 0xef, 0xff, 0xaf, 0xff, + 0xef, 0x17, 0xff, 0x1a, 0x27, 0x07, 0x27, 0xff, + 0xaf, 0xff, 0xbf, 0x00, 0x2e, 0x5d, 0x89, 0x05, + 0x27, 0xcb, 0x74, 0xc9, 0xcf, 0xf3, 0x1c, 0x04, + 0x18, 0xc9, 0xaf, 0x39, 0x81, 0x10, 0xff, 0xff, + 0xef, 0xc1, 0x2e, 0x7c, 0xbf, 0x41, 0x2e, 0x7b, + 0xbf, 0x02, 0xef, 0x41, 0x2e, 0x7a, 0xbf, 0xc9, + 0x31, 0x18, 0xef, 0xc0, 0xaf, 0x04, 0x27, 0x41, + 0x2e, 0x7a, 0xdf, 0xdf, 0x2d, 0x08, 0x5b, 0x01, + 0xef, 0x41, 0x2e, 0x7a, 0xbf, 0xc0, 0x23, 0x18, + 0xef, 0xc1, 0xaf, 0xcb, 0xcf, 0xcc, 0xdf, 0x05, + 0x27, 0xc9, 0x30, 0x01, 0xef, 0x41, 0x2e, 0x7a, + 0xbf, 0xc0, 0x23, 0x18, 0xef, 0xc1, 0xaf, 0x9f, + 0x22, 0xbf, 0x22, 0x05, 0x27 }; static const unsigned char pkt136[] = { -0x42, 0xca, 0x00, -0xa9, 0x22, 0x25, 0x85, 0x44, -0x1e, 0x01, 0x55, 0xe2, 0x2f, 0x7d, 0x50, 0x49, -0x1e, 0x02, 0x55, 0xe2, 0x2f, 0x79, 0x50, 0x05, -0x27, 0x4a, 0x1e, 0x01, 0x55, 0xe2, 0x2f, 0x74, -0x50, 0x4e, 0x1e, 0x01, 0x55, 0x00, 0x2e, 0xbb, -0x79, 0x4f, 0x1e, 0x00, 0x55, 0x7d, 0x78, 0x55, -0x1e, 0x00, 0x55, 0x05, 0x27, 0x58, 0x1e, 0x0d, -0x55, 0x02, 0x44, 0x01, 0x5a, 0x00, 0x2e, 0x07, -0x78, 0xfe, 0xcf, 0x75, 0xaf, 0xfe, 0xdf, 0x76, -0xbf, 0x41, 0x2e, 0xa4, 0xdf, 0xdf, 0x29, 0x41, -0x2e, 0xa4, 0xbf, 0x05, 0x27, 0x59, 0x1e, 0x02, -0x55, 0xfe, 0xcf, 0x10, 0xaf, 0x2b, 0x7e, 0x63, -0x1e, 0x1a, 0x55, 0x28, 0x85, 0xe2, 0x2f, 0x50, -0x5b, 0x0c, 0xef, 0x20, 0x80, 0xe2, 0x2f, 0x4c, -0x5a, 0xf0, 0xef, 0x00, 0xff, 0x19, 0x27, 0x08, -0xef, 0x06, 0xaf, 0xfe, 0xcf, 0x5f, 0x9f, 0x06, -0x25, 0xfb, 0x55, 0xfe, 0xcf, 0xfe, 0xcf, 0x41, -0x2e, 0x40, 0xbf, 0xfe, 0xcf, 0x41, 0x2e, 0x41, -0xbf, 0xfe, 0xcf, 0x41, 0x2e, 0x42, 0xbf, 0x05, -0x27, 0x64, 0x1e, 0x31, 0x55, 0xb0, 0xef, 0x00, -0xff, 0x19, 0x27, 0x0b, 0xef, 0x06, 0xaf, 0xfe, -0xcf, 0x5f, 0x9f, 0x06, 0x25, 0xfb, 0x55, 0xfe, -0xcf, 0x56, 0xaf, 0xfe, 0xcf, 0xae, 0xdf, 0x1f, -0x1c, 0xe0, 0x1d, 0x5f, 0x02, 0xae, 0xbf, 0xfe, -0xcf, 0x41, 0x2e, 0x54, 0xbf, 0xfe, 0xcf, 0x41, -0x2e, 0x77, 0xbf, 0xfe, 0xcf + 0x42, 0xca, 0x00, + 0xa9, 0x22, 0x25, 0x85, 0x44, + 0x1e, 0x01, 0x55, 0xe2, 0x2f, 0x7d, 0x50, 0x49, + 0x1e, 0x02, 0x55, 0xe2, 0x2f, 0x79, 0x50, 0x05, + 0x27, 0x4a, 0x1e, 0x01, 0x55, 0xe2, 0x2f, 0x74, + 0x50, 0x4e, 0x1e, 0x01, 0x55, 0x00, 0x2e, 0xbb, + 0x79, 0x4f, 0x1e, 0x00, 0x55, 0x7d, 0x78, 0x55, + 0x1e, 0x00, 0x55, 0x05, 0x27, 0x58, 0x1e, 0x0d, + 0x55, 0x02, 0x44, 0x01, 0x5a, 0x00, 0x2e, 0x07, + 0x78, 0xfe, 0xcf, 0x75, 0xaf, 0xfe, 0xdf, 0x76, + 0xbf, 0x41, 0x2e, 0xa4, 0xdf, 0xdf, 0x29, 0x41, + 0x2e, 0xa4, 0xbf, 0x05, 0x27, 0x59, 0x1e, 0x02, + 0x55, 0xfe, 0xcf, 0x10, 0xaf, 0x2b, 0x7e, 0x63, + 0x1e, 0x1a, 0x55, 0x28, 0x85, 0xe2, 0x2f, 0x50, + 0x5b, 0x0c, 0xef, 0x20, 0x80, 0xe2, 0x2f, 0x4c, + 0x5a, 0xf0, 0xef, 0x00, 0xff, 0x19, 0x27, 0x08, + 0xef, 0x06, 0xaf, 0xfe, 0xcf, 0x5f, 0x9f, 0x06, + 0x25, 0xfb, 0x55, 0xfe, 0xcf, 0xfe, 0xcf, 0x41, + 0x2e, 0x40, 0xbf, 0xfe, 0xcf, 0x41, 0x2e, 0x41, + 0xbf, 0xfe, 0xcf, 0x41, 0x2e, 0x42, 0xbf, 0x05, + 0x27, 0x64, 0x1e, 0x31, 0x55, 0xb0, 0xef, 0x00, + 0xff, 0x19, 0x27, 0x0b, 0xef, 0x06, 0xaf, 0xfe, + 0xcf, 0x5f, 0x9f, 0x06, 0x25, 0xfb, 0x55, 0xfe, + 0xcf, 0x56, 0xaf, 0xfe, 0xcf, 0xae, 0xdf, 0x1f, + 0x1c, 0xe0, 0x1d, 0x5f, 0x02, 0xae, 0xbf, 0xfe, + 0xcf, 0x41, 0x2e, 0x54, 0xbf, 0xfe, 0xcf, 0x41, + 0x2e, 0x77, 0xbf, 0xfe, 0xcf }; static const unsigned char pkt140[] = { -0x42, 0xca, 0x00, -0x0d, 0x23, 0x41, 0x2e, 0x55, -0xbf, 0xfe, 0xcf, 0x41, 0x2e, 0x78, 0xbf, 0xfe, -0xcf, 0xbb, 0xaf, 0xfe, 0xcf, 0xbc, 0xaf, 0xfe, -0xcf, 0xbd, 0xaf, 0xfe, 0xcf, 0xbe, 0xaf, 0xfe, -0xcf, 0x83, 0xaf, 0xfe, 0xcf, 0x84, 0xaf, 0xfe, -0xcf, 0x81, 0xaf, 0xfe, 0xcf, 0x82, 0xaf, 0xfe, -0xcf, 0x24, 0xaf, 0xfe, 0xcf, 0x02, 0x33, 0x05, -0x27, 0x66, 0x1e, 0x0b, 0x55, 0x60, 0xef, 0x21, -0xff, 0x1a, 0x27, 0x0b, 0xef, 0x06, 0xaf, 0xfe, -0xcf, 0xfe, 0xdf, 0x06, 0x27, 0x01, 0x0e, 0x06, -0x25, 0xf9, 0x55, 0x05, 0x27, 0x35, 0x74, 0xff, -0x96, 0xc6, 0x2e, 0x01, 0xdf, 0x3f, 0x2c, 0xdd, -0x9f, 0x05, 0x27, 0x01, 0xef, 0x20, 0x80, 0xe1, -0x2f, 0xeb, 0x5a, 0xfe, 0xcf, 0xdf, 0x22, 0xe7, -0x2f, 0x1e, 0x54, 0x01, 0xff, 0x05, 0xef, 0xff, -0x96, 0xdf, 0x96, 0x2d, 0xff, 0x8d, 0xef, 0x19, -0x27, 0x03, 0xcf, 0x7f, 0x1c, 0x5f, 0x9f, 0xdd, -0x97, 0x5f, 0x9f, 0xdd, 0x97, 0x5f, 0x9f, 0x05, -0xef, 0x06, 0xaf, 0x9f, 0x22, 0x5f, 0x9f, 0x06, -0x25, 0xfc, 0x55, 0x5f, 0x9f, 0x06, 0x25, 0xfc, -0x55, 0x20, 0xef, 0x08, 0xaf, 0x09, 0x23, 0x00, -0x2e, 0xd1, 0x8d, 0x67, 0x81, 0x03, 0xef, 0xfc, -0xaf, 0x86, 0xef, 0xaa, 0xaf, 0x08, 0xef, 0xe3, -0xaf, 0x9f, 0x22, 0xe2, 0xaf, 0x21, 0xef, 0x41, -0x2e, 0x47, 0xbf, 0x27, 0xef, 0xf4, 0xaf, 0x28, -0xff, 0xa7, 0xef, 0xe1, 0xbf + 0x42, 0xca, 0x00, + 0x0d, 0x23, 0x41, 0x2e, 0x55, + 0xbf, 0xfe, 0xcf, 0x41, 0x2e, 0x78, 0xbf, 0xfe, + 0xcf, 0xbb, 0xaf, 0xfe, 0xcf, 0xbc, 0xaf, 0xfe, + 0xcf, 0xbd, 0xaf, 0xfe, 0xcf, 0xbe, 0xaf, 0xfe, + 0xcf, 0x83, 0xaf, 0xfe, 0xcf, 0x84, 0xaf, 0xfe, + 0xcf, 0x81, 0xaf, 0xfe, 0xcf, 0x82, 0xaf, 0xfe, + 0xcf, 0x24, 0xaf, 0xfe, 0xcf, 0x02, 0x33, 0x05, + 0x27, 0x66, 0x1e, 0x0b, 0x55, 0x60, 0xef, 0x21, + 0xff, 0x1a, 0x27, 0x0b, 0xef, 0x06, 0xaf, 0xfe, + 0xcf, 0xfe, 0xdf, 0x06, 0x27, 0x01, 0x0e, 0x06, + 0x25, 0xf9, 0x55, 0x05, 0x27, 0x35, 0x74, 0xff, + 0x96, 0xc6, 0x2e, 0x01, 0xdf, 0x3f, 0x2c, 0xdd, + 0x9f, 0x05, 0x27, 0x01, 0xef, 0x20, 0x80, 0xe1, + 0x2f, 0xeb, 0x5a, 0xfe, 0xcf, 0xdf, 0x22, 0xe7, + 0x2f, 0x1e, 0x54, 0x01, 0xff, 0x05, 0xef, 0xff, + 0x96, 0xdf, 0x96, 0x2d, 0xff, 0x8d, 0xef, 0x19, + 0x27, 0x03, 0xcf, 0x7f, 0x1c, 0x5f, 0x9f, 0xdd, + 0x97, 0x5f, 0x9f, 0xdd, 0x97, 0x5f, 0x9f, 0x05, + 0xef, 0x06, 0xaf, 0x9f, 0x22, 0x5f, 0x9f, 0x06, + 0x25, 0xfc, 0x55, 0x5f, 0x9f, 0x06, 0x25, 0xfc, + 0x55, 0x20, 0xef, 0x08, 0xaf, 0x09, 0x23, 0x00, + 0x2e, 0xd1, 0x8d, 0x67, 0x81, 0x03, 0xef, 0xfc, + 0xaf, 0x86, 0xef, 0xaa, 0xaf, 0x08, 0xef, 0xe3, + 0xaf, 0x9f, 0x22, 0xe2, 0xaf, 0x21, 0xef, 0x41, + 0x2e, 0x47, 0xbf, 0x27, 0xef, 0xf4, 0xaf, 0x28, + 0xff, 0xa7, 0xef, 0xe1, 0xbf }; static const unsigned char pkt144[] = { -0x42, 0x88, 0x00, -0x71, 0x23, 0xe0, 0xaf, 0x08, -0xef, 0x10, 0xaf, 0x8c, 0x8d, 0x05, 0x81, 0x01, -0x2e, 0x54, 0x80, 0x01, 0x2e, 0x56, 0x80, 0x9b, -0x22, 0x9b, 0x22, 0x2d, 0xff, 0x95, 0xef, 0x19, -0x27, 0x28, 0xff, 0xa7, 0xef, 0x1a, 0x27, 0x80, -0xef, 0x06, 0xaf, 0xdc, 0x97, 0x5f, 0x9f, 0xdf, -0x22, 0x01, 0x54, 0x00, 0x2e, 0x66, 0x8a, 0x06, -0x25, 0xf7, 0x55, 0x2d, 0xff, 0x91, 0xef, 0x19, -0x27, 0xdd, 0x97, 0xdd, 0x9f, 0x5f, 0x9f, 0x7f, -0x9f, 0xfd, 0x0d, 0xdf, 0x22, 0x01, 0x55, 0xff, -0x22, 0x01, 0x54, 0x01, 0xef, 0x1f, 0x98, 0x2f, -0xef, 0x41, 0x2e, 0x47, 0xbf, 0x11, 0xef, 0xf4, -0xaf, 0x28, 0xff, 0xa7, 0xef, 0xe1, 0xbf, 0xe0, -0xaf, 0x01, 0x2e, 0x54, 0x80, 0x01, 0x2e, 0x56, -0x80, 0x9b, 0x22, 0x9b, 0x22, 0x2e, 0xff, 0x15, -0xef, 0x19, 0x27, 0x28, 0xff, 0xa7, 0xef, 0x1a, -0x27, 0x80, 0xef, 0x06, 0xaf, 0x00, 0x2e, 0x3c, -0x8a, 0x05, 0x27 + 0x42, 0x88, 0x00, + 0x71, 0x23, 0xe0, 0xaf, 0x08, + 0xef, 0x10, 0xaf, 0x8c, 0x8d, 0x05, 0x81, 0x01, + 0x2e, 0x54, 0x80, 0x01, 0x2e, 0x56, 0x80, 0x9b, + 0x22, 0x9b, 0x22, 0x2d, 0xff, 0x95, 0xef, 0x19, + 0x27, 0x28, 0xff, 0xa7, 0xef, 0x1a, 0x27, 0x80, + 0xef, 0x06, 0xaf, 0xdc, 0x97, 0x5f, 0x9f, 0xdf, + 0x22, 0x01, 0x54, 0x00, 0x2e, 0x66, 0x8a, 0x06, + 0x25, 0xf7, 0x55, 0x2d, 0xff, 0x91, 0xef, 0x19, + 0x27, 0xdd, 0x97, 0xdd, 0x9f, 0x5f, 0x9f, 0x7f, + 0x9f, 0xfd, 0x0d, 0xdf, 0x22, 0x01, 0x55, 0xff, + 0x22, 0x01, 0x54, 0x01, 0xef, 0x1f, 0x98, 0x2f, + 0xef, 0x41, 0x2e, 0x47, 0xbf, 0x11, 0xef, 0xf4, + 0xaf, 0x28, 0xff, 0xa7, 0xef, 0xe1, 0xbf, 0xe0, + 0xaf, 0x01, 0x2e, 0x54, 0x80, 0x01, 0x2e, 0x56, + 0x80, 0x9b, 0x22, 0x9b, 0x22, 0x2e, 0xff, 0x15, + 0xef, 0x19, 0x27, 0x28, 0xff, 0xa7, 0xef, 0x1a, + 0x27, 0x80, 0xef, 0x06, 0xaf, 0x00, 0x2e, 0x3c, + 0x8a, 0x05, 0x27 }; static const unsigned char pkt148[] = { -0x42, 0xca, 0x00, -0xb4, 0x23, 0x37, 0xcf, 0xdf, -0x96, 0x08, 0xcf, 0xdf, 0x96, 0x3d, 0xcf, 0xdf, -0x96, 0x00, 0x2e, 0xd4, 0x8d, 0xdd, 0x97, 0x3d, -0xaf, 0xdd, 0x97, 0x08, 0xaf, 0xdd, 0x97, 0x37, -0xaf, 0x03, 0xcf, 0x51, 0x1e, 0x00, 0x55, 0x44, -0x8b, 0xa0, 0xcf, 0xbf, 0x1c, 0xa0, 0xaf, 0x05, -0x81, 0xfb, 0x39, 0x08, 0x45, 0x00, 0x5a, 0xfb, -0x31, 0x0a, 0x42, 0x00, 0x5b, 0xa2, 0x39, 0x02, -0xcf, 0x5c, 0xaf, 0xe1, 0xef, 0x40, 0x2e, 0x95, -0xbf, 0x9f, 0x22, 0x25, 0xaf, 0x69, 0xaf, 0x6a, -0xaf, 0x16, 0xaf, 0x40, 0x2e, 0x96, 0xbf, 0x29, -0xaf, 0x02, 0x47, 0x06, 0x5a, 0x0a, 0x41, 0x04, -0x5a, 0x0a, 0xdf, 0x30, 0x1d, 0x30, 0x1f, 0x00, -0x54, 0x01, 0xef, 0x44, 0xaf, 0x09, 0xef, 0x60, -0xaf, 0x0a, 0x40, 0x06, 0x5a, 0x10, 0xcf, 0x27, -0xaf, 0xe2, 0x23, 0x6e, 0x23, 0x08, 0xef, 0xe3, -0xaf, 0x6f, 0xaf, 0x0d, 0x8d, 0x5d, 0xcf, 0x30, -0x1c, 0x00, 0x1e, 0x07, 0x55, 0xf8, 0xcf, 0x5f, -0x2b, 0x9f, 0x29, 0xf8, 0xaf, 0xa1, 0xcf, 0xc1, -0x1c, 0xa1, 0xaf, 0x09, 0x50, 0x10, 0x1e, 0x07, -0x55, 0xf8, 0xcf, 0x5f, 0x29, 0x9f, 0x2b, 0xf8, -0xaf, 0xa1, 0xcf, 0xc1, 0x1c, 0x08, 0x18, 0xa1, -0xaf, 0x41, 0x2e, 0xa4, 0xdf, 0xdf, 0x2d, 0x04, -0x5b, 0x75, 0xcf, 0xf4, 0xaf, 0x76, 0xcf, 0xf5, -0xaf, 0x00, 0x50, 0x0f, 0x88, 0xe2, 0x23, 0x08, -0xef, 0xe3, 0xaf, 0x81, 0x82 + 0x42, 0xca, 0x00, + 0xb4, 0x23, 0x37, 0xcf, 0xdf, + 0x96, 0x08, 0xcf, 0xdf, 0x96, 0x3d, 0xcf, 0xdf, + 0x96, 0x00, 0x2e, 0xd4, 0x8d, 0xdd, 0x97, 0x3d, + 0xaf, 0xdd, 0x97, 0x08, 0xaf, 0xdd, 0x97, 0x37, + 0xaf, 0x03, 0xcf, 0x51, 0x1e, 0x00, 0x55, 0x44, + 0x8b, 0xa0, 0xcf, 0xbf, 0x1c, 0xa0, 0xaf, 0x05, + 0x81, 0xfb, 0x39, 0x08, 0x45, 0x00, 0x5a, 0xfb, + 0x31, 0x0a, 0x42, 0x00, 0x5b, 0xa2, 0x39, 0x02, + 0xcf, 0x5c, 0xaf, 0xe1, 0xef, 0x40, 0x2e, 0x95, + 0xbf, 0x9f, 0x22, 0x25, 0xaf, 0x69, 0xaf, 0x6a, + 0xaf, 0x16, 0xaf, 0x40, 0x2e, 0x96, 0xbf, 0x29, + 0xaf, 0x02, 0x47, 0x06, 0x5a, 0x0a, 0x41, 0x04, + 0x5a, 0x0a, 0xdf, 0x30, 0x1d, 0x30, 0x1f, 0x00, + 0x54, 0x01, 0xef, 0x44, 0xaf, 0x09, 0xef, 0x60, + 0xaf, 0x0a, 0x40, 0x06, 0x5a, 0x10, 0xcf, 0x27, + 0xaf, 0xe2, 0x23, 0x6e, 0x23, 0x08, 0xef, 0xe3, + 0xaf, 0x6f, 0xaf, 0x0d, 0x8d, 0x5d, 0xcf, 0x30, + 0x1c, 0x00, 0x1e, 0x07, 0x55, 0xf8, 0xcf, 0x5f, + 0x2b, 0x9f, 0x29, 0xf8, 0xaf, 0xa1, 0xcf, 0xc1, + 0x1c, 0xa1, 0xaf, 0x09, 0x50, 0x10, 0x1e, 0x07, + 0x55, 0xf8, 0xcf, 0x5f, 0x29, 0x9f, 0x2b, 0xf8, + 0xaf, 0xa1, 0xcf, 0xc1, 0x1c, 0x08, 0x18, 0xa1, + 0xaf, 0x41, 0x2e, 0xa4, 0xdf, 0xdf, 0x2d, 0x04, + 0x5b, 0x75, 0xcf, 0xf4, 0xaf, 0x76, 0xcf, 0xf5, + 0xaf, 0x00, 0x50, 0x0f, 0x88, 0xe2, 0x23, 0x08, + 0xef, 0xe3, 0xaf, 0x81, 0x82 }; static const unsigned char pkt152[] = { -0x42, 0x24, 0x00, -0x18, 0x24, 0x4d, 0xaf, 0xdf, -0x96, 0x64, 0xdf, 0x93, 0x82, 0x93, 0xbf, 0xdd, -0x97, 0x77, 0xff, 0x93, 0x82, 0x94, 0xbf, 0x9e, -0x23, 0xe4, 0x23, 0x05, 0x27, 0x14, 0xef, 0xf4, -0xaf, 0x00, 0xef, 0xf5, 0xaf, 0x05, 0x27 + 0x42, 0x24, 0x00, + 0x18, 0x24, 0x4d, 0xaf, 0xdf, + 0x96, 0x64, 0xdf, 0x93, 0x82, 0x93, 0xbf, 0xdd, + 0x97, 0x77, 0xff, 0x93, 0x82, 0x94, 0xbf, 0x9e, + 0x23, 0xe4, 0x23, 0x05, 0x27, 0x14, 0xef, 0xf4, + 0xaf, 0x00, 0xef, 0xf5, 0xaf, 0x05, 0x27 }; static const unsigned char pkt156[] = { -0x42, 0xca, 0x00, -0x29, 0x24, 0xfe, 0xcf, 0x58, -0xaf, 0xfe, 0xcf, 0xfe, 0xdf, 0x00, 0x2e, 0xa9, -0x8b, 0xfe, 0xcf, 0x3c, 0xaf, 0x07, 0x3d, 0x58, -0x40, 0x4a, 0x5a, 0x3c, 0x26, 0x48, 0x55, 0x37, -0x45, 0x46, 0x5a, 0xe0, 0x88, 0x44, 0x5a, 0x77, -0x88, 0x00, 0x2e, 0xd1, 0x8b, 0xfe, 0xef, 0x16, -0x80, 0x02, 0xcf, 0xdf, 0x96, 0x61, 0xef, 0xc0, -0xaf, 0x04, 0x27, 0xc1, 0x46, 0x04, 0x5b, 0xc0, -0x3e, 0x40, 0xef, 0xc1, 0xaf, 0x01, 0x2e, 0x94, -0x84, 0xd0, 0x41, 0x06, 0x5b, 0x2d, 0x88, 0xf3, -0x5b, 0x6c, 0x86, 0xdd, 0x97, 0x1f, 0x2d, 0x05, -0x5b, 0x03, 0x50, 0x01, 0x0c, 0x02, 0xcf, 0xc0, -0x1c, 0x00, 0x55, 0x05, 0x88, 0xc0, 0x23, 0x20, -0xef, 0xc1, 0xaf, 0x00, 0x2e, 0xf0, 0x8b, 0x05, -0x27, 0x9b, 0x22, 0x37, 0x45, 0x05, 0x5a, 0x41, -0x2e, 0x52, 0xdf, 0xdf, 0x2d, 0x04, 0x5b, 0x00, -0x28, 0x02, 0x50, 0x3b, 0x43, 0x00, 0x5b, 0x00, -0x28, 0xd3, 0xdf, 0xc6, 0x2e, 0x15, 0xbf, 0xd3, -0x3c, 0x40, 0xef, 0x09, 0x80, 0xdd, 0x97, 0xff, -0xaf, 0x00, 0x2e, 0x5d, 0x89, 0xc6, 0x2e, 0x15, -0xdf, 0x10, 0x1d, 0xd3, 0xcf, 0x3f, 0x02, 0xd3, -0xaf, 0x05, 0x27, 0xc1, 0x83, 0x07, 0x45, 0x05, -0x27, 0x3d, 0x23, 0x07, 0x3d, 0x02, 0xcf, 0xdf, -0x96, 0x2e, 0x88, 0x26, 0x88, 0xfe, 0xef, 0x16, -0x80, 0x05, 0xef, 0xc0, 0xaf, 0x04, 0x27, 0xd0, -0x41, 0x02, 0x5b, 0xee, 0x8f + 0x42, 0xca, 0x00, + 0x29, 0x24, 0xfe, 0xcf, 0x58, + 0xaf, 0xfe, 0xcf, 0xfe, 0xdf, 0x00, 0x2e, 0xa9, + 0x8b, 0xfe, 0xcf, 0x3c, 0xaf, 0x07, 0x3d, 0x58, + 0x40, 0x4a, 0x5a, 0x3c, 0x26, 0x48, 0x55, 0x37, + 0x45, 0x46, 0x5a, 0xe0, 0x88, 0x44, 0x5a, 0x77, + 0x88, 0x00, 0x2e, 0xd1, 0x8b, 0xfe, 0xef, 0x16, + 0x80, 0x02, 0xcf, 0xdf, 0x96, 0x61, 0xef, 0xc0, + 0xaf, 0x04, 0x27, 0xc1, 0x46, 0x04, 0x5b, 0xc0, + 0x3e, 0x40, 0xef, 0xc1, 0xaf, 0x01, 0x2e, 0x94, + 0x84, 0xd0, 0x41, 0x06, 0x5b, 0x2d, 0x88, 0xf3, + 0x5b, 0x6c, 0x86, 0xdd, 0x97, 0x1f, 0x2d, 0x05, + 0x5b, 0x03, 0x50, 0x01, 0x0c, 0x02, 0xcf, 0xc0, + 0x1c, 0x00, 0x55, 0x05, 0x88, 0xc0, 0x23, 0x20, + 0xef, 0xc1, 0xaf, 0x00, 0x2e, 0xf0, 0x8b, 0x05, + 0x27, 0x9b, 0x22, 0x37, 0x45, 0x05, 0x5a, 0x41, + 0x2e, 0x52, 0xdf, 0xdf, 0x2d, 0x04, 0x5b, 0x00, + 0x28, 0x02, 0x50, 0x3b, 0x43, 0x00, 0x5b, 0x00, + 0x28, 0xd3, 0xdf, 0xc6, 0x2e, 0x15, 0xbf, 0xd3, + 0x3c, 0x40, 0xef, 0x09, 0x80, 0xdd, 0x97, 0xff, + 0xaf, 0x00, 0x2e, 0x5d, 0x89, 0xc6, 0x2e, 0x15, + 0xdf, 0x10, 0x1d, 0xd3, 0xcf, 0x3f, 0x02, 0xd3, + 0xaf, 0x05, 0x27, 0xc1, 0x83, 0x07, 0x45, 0x05, + 0x27, 0x3d, 0x23, 0x07, 0x3d, 0x02, 0xcf, 0xdf, + 0x96, 0x2e, 0x88, 0x26, 0x88, 0xfe, 0xef, 0x16, + 0x80, 0x05, 0xef, 0xc0, 0xaf, 0x04, 0x27, 0xd0, + 0x41, 0x02, 0x5b, 0xee, 0x8f }; static const unsigned char pkt160[] = { -0x42, 0xca, 0x00, -0x8d, 0x24, 0xfa, 0x5b, 0xbf, -0x50, 0x31, 0x82, 0x04, 0xef, 0xc1, 0xaf, 0x9b, -0x22, 0x41, 0x88, 0xdd, 0x97, 0xdf, 0x22, 0x02, -0x55, 0x58, 0x40, 0x02, 0x5a, 0x09, 0x50, 0x58, -0x40, 0x07, 0x5a, 0xdd, 0x97, 0x1f, 0x2d, 0xb8, -0x5a, 0x7a, 0x88, 0xb7, 0x5b, 0x9b, 0x22, 0xc7, -0x8f, 0xb4, 0x50, 0x75, 0x88, 0xdc, 0x5b, 0xb7, -0x8f, 0x58, 0x41, 0x01, 0x5b, 0x01, 0x0c, 0xad, -0x7f, 0xd6, 0x50, 0x41, 0x2e, 0x52, 0xdf, 0xed, -0x1c, 0x04, 0x18, 0x41, 0x2e, 0x52, 0xbf, 0x05, -0x27, 0x00, 0x2e, 0xb9, 0x8b, 0xae, 0xdf, 0xe0, -0x19, 0xae, 0xbf, 0x57, 0x40, 0x00, 0x5b, 0xa1, -0x32, 0x57, 0x43, 0x00, 0x5b, 0xae, 0x3f, 0x05, -0x81, 0x05, 0x27, 0x41, 0x2e, 0x52, 0xdf, 0x03, -0x18, 0x41, 0x2e, 0x52, 0xbf, 0x05, 0x27, 0xd3, -0xdf, 0xff, 0x96, 0x9b, 0x22, 0x0b, 0x88, 0xd3, -0x3c, 0x07, 0x80, 0xdd, 0x97, 0xff, 0xaf, 0x00, -0x2e, 0x5d, 0x89, 0xdd, 0x9f, 0x10, 0x1d, 0xd3, -0xcf, 0x3f, 0x02, 0xd3, 0xaf, 0x05, 0x27, 0x37, -0x45, 0x0e, 0x5a, 0x40, 0x88, 0x0c, 0x5a, 0xd7, -0x8f, 0x00, 0x2e, 0xd7, 0x8b, 0x00, 0x2e, 0xeb, -0x8b, 0x41, 0x2e, 0x52, 0xdf, 0xdf, 0x2d, 0x00, -0x5b, 0x00, 0x28, 0x00, 0x2e, 0xf0, 0x8b, 0x05, -0x27, 0xf9, 0xcf, 0xdf, 0x96, 0xf9, 0x3d, 0x00, -0x2e, 0xd1, 0x8d, 0x28, 0xff, 0xa7, 0xef, 0xe1, -0xbf, 0xe0, 0xaf, 0x09, 0xef + 0x42, 0xca, 0x00, + 0x8d, 0x24, 0xfa, 0x5b, 0xbf, + 0x50, 0x31, 0x82, 0x04, 0xef, 0xc1, 0xaf, 0x9b, + 0x22, 0x41, 0x88, 0xdd, 0x97, 0xdf, 0x22, 0x02, + 0x55, 0x58, 0x40, 0x02, 0x5a, 0x09, 0x50, 0x58, + 0x40, 0x07, 0x5a, 0xdd, 0x97, 0x1f, 0x2d, 0xb8, + 0x5a, 0x7a, 0x88, 0xb7, 0x5b, 0x9b, 0x22, 0xc7, + 0x8f, 0xb4, 0x50, 0x75, 0x88, 0xdc, 0x5b, 0xb7, + 0x8f, 0x58, 0x41, 0x01, 0x5b, 0x01, 0x0c, 0xad, + 0x7f, 0xd6, 0x50, 0x41, 0x2e, 0x52, 0xdf, 0xed, + 0x1c, 0x04, 0x18, 0x41, 0x2e, 0x52, 0xbf, 0x05, + 0x27, 0x00, 0x2e, 0xb9, 0x8b, 0xae, 0xdf, 0xe0, + 0x19, 0xae, 0xbf, 0x57, 0x40, 0x00, 0x5b, 0xa1, + 0x32, 0x57, 0x43, 0x00, 0x5b, 0xae, 0x3f, 0x05, + 0x81, 0x05, 0x27, 0x41, 0x2e, 0x52, 0xdf, 0x03, + 0x18, 0x41, 0x2e, 0x52, 0xbf, 0x05, 0x27, 0xd3, + 0xdf, 0xff, 0x96, 0x9b, 0x22, 0x0b, 0x88, 0xd3, + 0x3c, 0x07, 0x80, 0xdd, 0x97, 0xff, 0xaf, 0x00, + 0x2e, 0x5d, 0x89, 0xdd, 0x9f, 0x10, 0x1d, 0xd3, + 0xcf, 0x3f, 0x02, 0xd3, 0xaf, 0x05, 0x27, 0x37, + 0x45, 0x0e, 0x5a, 0x40, 0x88, 0x0c, 0x5a, 0xd7, + 0x8f, 0x00, 0x2e, 0xd7, 0x8b, 0x00, 0x2e, 0xeb, + 0x8b, 0x41, 0x2e, 0x52, 0xdf, 0xdf, 0x2d, 0x00, + 0x5b, 0x00, 0x28, 0x00, 0x2e, 0xf0, 0x8b, 0x05, + 0x27, 0xf9, 0xcf, 0xdf, 0x96, 0xf9, 0x3d, 0x00, + 0x2e, 0xd1, 0x8d, 0x28, 0xff, 0xa7, 0xef, 0xe1, + 0xbf, 0xe0, 0xaf, 0x09, 0xef }; static const unsigned char pkt164[] = { -0x42, 0x6c, 0x00, -0xf1, 0x24, 0x10, 0xaf, 0x0e, -0x8c, 0x05, 0x81, 0x01, 0x2e, 0x54, 0x80, 0x01, -0x2e, 0x56, 0x80, 0x20, 0x82, 0x7b, 0x8c, 0x37, -0x82, 0x26, 0x37, 0x00, 0x5a, 0x0c, 0x50, 0xff, -0x96, 0xdf, 0x96, 0x79, 0xcf, 0x7a, 0xdf, 0xff, -0x96, 0xdf, 0x96, 0xc2, 0x97, 0xc3, 0x9f, 0x9d, -0x01, 0x5d, 0x01, 0x07, 0x53, 0xdd, 0x97, 0xdd, -0x9f, 0x79, 0xaf, 0x7a, 0xbf, 0x3b, 0x3b, 0xdd, -0x97, 0xf9, 0xaf, 0x05, 0x27, 0xff, 0x22, 0x01, -0x55, 0x32, 0x1e, 0xf3, 0x5f, 0x02, 0x0c, 0xf6, -0x8f, 0x3b, 0x33, 0x00, 0x28, 0x05, 0x27, 0x0d, -0x27, 0x3c, 0x26, 0x07, 0x54, 0x3c, 0xcf, 0x3d, -0xdf, 0x3f, 0x20, 0x3d, 0xbf, 0xdf, 0x03, 0x01, -0x52, 0x3d, 0x23, 0x0c, 0x27, 0x0d, 0x27 + 0x42, 0x6c, 0x00, + 0xf1, 0x24, 0x10, 0xaf, 0x0e, + 0x8c, 0x05, 0x81, 0x01, 0x2e, 0x54, 0x80, 0x01, + 0x2e, 0x56, 0x80, 0x20, 0x82, 0x7b, 0x8c, 0x37, + 0x82, 0x26, 0x37, 0x00, 0x5a, 0x0c, 0x50, 0xff, + 0x96, 0xdf, 0x96, 0x79, 0xcf, 0x7a, 0xdf, 0xff, + 0x96, 0xdf, 0x96, 0xc2, 0x97, 0xc3, 0x9f, 0x9d, + 0x01, 0x5d, 0x01, 0x07, 0x53, 0xdd, 0x97, 0xdd, + 0x9f, 0x79, 0xaf, 0x7a, 0xbf, 0x3b, 0x3b, 0xdd, + 0x97, 0xf9, 0xaf, 0x05, 0x27, 0xff, 0x22, 0x01, + 0x55, 0x32, 0x1e, 0xf3, 0x5f, 0x02, 0x0c, 0xf6, + 0x8f, 0x3b, 0x33, 0x00, 0x28, 0x05, 0x27, 0x0d, + 0x27, 0x3c, 0x26, 0x07, 0x54, 0x3c, 0xcf, 0x3d, + 0xdf, 0x3f, 0x20, 0x3d, 0xbf, 0xdf, 0x03, 0x01, + 0x52, 0x3d, 0x23, 0x0c, 0x27, 0x0d, 0x27 }; static const unsigned char pkt168[] = { -0x42, 0x50, 0x00, -0x26, 0x25, 0x08, 0x44, 0x12, -0x5a, 0x07, 0x40, 0x01, 0x5b, 0x4f, 0x80, 0x00, -0x50, 0x53, 0x80, 0x27, 0x0d, 0x25, 0xcf, 0x1f, -0x98, 0x29, 0xcf, 0x09, 0x27, 0x28, 0xdf, 0x3f, -0x02, 0x5f, 0x98, 0x62, 0xcf, 0xdf, 0x98, 0xd9, -0x0d, 0x02, 0x0d, 0x00, 0x2e, 0xd5, 0x7f, 0x05, -0x27, 0x01, 0x0d, 0x41, 0x2e, 0x56, 0xdf, 0x5f, -0x9f, 0x41, 0x2e, 0x57, 0xdf, 0x5f, 0x9f, 0x41, -0x2e, 0x58, 0xdf, 0x5f, 0x9f, 0x41, 0x2e, 0x59, -0xdf, 0x5f, 0x9f, 0x06, 0x0d, 0x3b, 0xcf, 0x5f, -0x9f, 0x05, 0x27 + 0x42, 0x50, 0x00, + 0x26, 0x25, 0x08, 0x44, 0x12, + 0x5a, 0x07, 0x40, 0x01, 0x5b, 0x4f, 0x80, 0x00, + 0x50, 0x53, 0x80, 0x27, 0x0d, 0x25, 0xcf, 0x1f, + 0x98, 0x29, 0xcf, 0x09, 0x27, 0x28, 0xdf, 0x3f, + 0x02, 0x5f, 0x98, 0x62, 0xcf, 0xdf, 0x98, 0xd9, + 0x0d, 0x02, 0x0d, 0x00, 0x2e, 0xd5, 0x7f, 0x05, + 0x27, 0x01, 0x0d, 0x41, 0x2e, 0x56, 0xdf, 0x5f, + 0x9f, 0x41, 0x2e, 0x57, 0xdf, 0x5f, 0x9f, 0x41, + 0x2e, 0x58, 0xdf, 0x5f, 0x9f, 0x41, 0x2e, 0x59, + 0xdf, 0x5f, 0x9f, 0x06, 0x0d, 0x3b, 0xcf, 0x5f, + 0x9f, 0x05, 0x27 }; static const unsigned char pkt172[] = { -0x42, 0xca, 0x00, -0x4d, 0x25, 0x9b, 0x22, 0xbb, -0x89, 0x22, 0x88, 0x75, 0x88, 0x14, 0x86, 0x2b, -0x86, 0x2b, 0x86, 0x2b, 0x86, 0x2b, 0x86, 0xa0, -0x88, 0x2e, 0x89, 0x24, 0x89, 0x02, 0x33, 0x07, -0x80, 0xdd, 0x97, 0xff, 0xaf, 0x00, 0x2e, 0x5d, -0x89, 0x05, 0x27, 0x6c, 0xcf, 0x6d, 0xdf, 0xbf, -0x01, 0x6c, 0xaf, 0x6d, 0x26, 0x00, 0x2e, 0x33, -0x55, 0x00, 0x2e, 0x4e, 0x50, 0xdf, 0x96, 0xff, -0x96, 0x32, 0xff, 0x07, 0xef, 0x91, 0x81, 0x7f, -0x20, 0xfb, 0x55, 0xdd, 0x9f, 0xdd, 0x97, 0x05, -0x27, 0x9f, 0x22, 0x6b, 0xaf, 0x00, 0x2e, 0x6e, -0x8f, 0x00, 0xef, 0x41, 0x2e, 0x44, 0xbf, 0x7f, -0xef, 0x41, 0x2e, 0x45, 0xbf, 0x80, 0xef, 0x0a, -0xaf, 0x00, 0x2e, 0xd1, 0x8d, 0x88, 0x82, 0x8c, -0x82, 0x6b, 0xcf, 0x10, 0xaf, 0x02, 0x2e, 0x02, -0x81, 0x40, 0xef, 0x6d, 0xaf, 0x80, 0xef, 0x6c, -0xaf, 0x00, 0x2e, 0xc4, 0x8d, 0x05, 0x81, 0x01, -0x2e, 0x54, 0x80, 0x01, 0x2e, 0x56, 0x80, 0x7f, -0x89, 0xff, 0x2f, 0xca, 0x5a, 0x6c, 0xcf, 0x6d, -0xdf, 0x3f, 0x00, 0x6c, 0xaf, 0x6d, 0x26, 0x03, -0x54, 0x6d, 0xdf, 0x16, 0x82, 0x6d, 0xbf, 0xeb, -0x50, 0x6b, 0xcf, 0x08, 0x1e, 0x11, 0x5f, 0x6c, -0x24, 0x02, 0x53, 0xff, 0xef, 0x6c, 0xaf, 0x10, -0x50, 0x6c, 0x24, 0x02, 0x53, 0xff, 0xef, 0x6c, -0xaf, 0x0b, 0x50, 0x6b, 0xcf, 0x0a, 0x1e, 0x08, -0x55, 0x6c, 0x24, 0x02, 0x53 + 0x42, 0xca, 0x00, + 0x4d, 0x25, 0x9b, 0x22, 0xbb, + 0x89, 0x22, 0x88, 0x75, 0x88, 0x14, 0x86, 0x2b, + 0x86, 0x2b, 0x86, 0x2b, 0x86, 0x2b, 0x86, 0xa0, + 0x88, 0x2e, 0x89, 0x24, 0x89, 0x02, 0x33, 0x07, + 0x80, 0xdd, 0x97, 0xff, 0xaf, 0x00, 0x2e, 0x5d, + 0x89, 0x05, 0x27, 0x6c, 0xcf, 0x6d, 0xdf, 0xbf, + 0x01, 0x6c, 0xaf, 0x6d, 0x26, 0x00, 0x2e, 0x33, + 0x55, 0x00, 0x2e, 0x4e, 0x50, 0xdf, 0x96, 0xff, + 0x96, 0x32, 0xff, 0x07, 0xef, 0x91, 0x81, 0x7f, + 0x20, 0xfb, 0x55, 0xdd, 0x9f, 0xdd, 0x97, 0x05, + 0x27, 0x9f, 0x22, 0x6b, 0xaf, 0x00, 0x2e, 0x6e, + 0x8f, 0x00, 0xef, 0x41, 0x2e, 0x44, 0xbf, 0x7f, + 0xef, 0x41, 0x2e, 0x45, 0xbf, 0x80, 0xef, 0x0a, + 0xaf, 0x00, 0x2e, 0xd1, 0x8d, 0x88, 0x82, 0x8c, + 0x82, 0x6b, 0xcf, 0x10, 0xaf, 0x02, 0x2e, 0x02, + 0x81, 0x40, 0xef, 0x6d, 0xaf, 0x80, 0xef, 0x6c, + 0xaf, 0x00, 0x2e, 0xc4, 0x8d, 0x05, 0x81, 0x01, + 0x2e, 0x54, 0x80, 0x01, 0x2e, 0x56, 0x80, 0x7f, + 0x89, 0xff, 0x2f, 0xca, 0x5a, 0x6c, 0xcf, 0x6d, + 0xdf, 0x3f, 0x00, 0x6c, 0xaf, 0x6d, 0x26, 0x03, + 0x54, 0x6d, 0xdf, 0x16, 0x82, 0x6d, 0xbf, 0xeb, + 0x50, 0x6b, 0xcf, 0x08, 0x1e, 0x11, 0x5f, 0x6c, + 0x24, 0x02, 0x53, 0xff, 0xef, 0x6c, 0xaf, 0x10, + 0x50, 0x6c, 0x24, 0x02, 0x53, 0xff, 0xef, 0x6c, + 0xaf, 0x0b, 0x50, 0x6b, 0xcf, 0x0a, 0x1e, 0x08, + 0x55, 0x6c, 0x24, 0x02, 0x53 }; static const unsigned char pkt176[] = { -0x42, 0xca, 0x00, -0xb1, 0x25, 0xff, 0xef, 0x6c, -0xaf, 0x03, 0x50, 0x6c, 0x24, 0x01, 0x53, 0xff, -0xef, 0x6c, 0xaf, 0x6b, 0xcf, 0xdf, 0x96, 0xb0, -0xef, 0x00, 0xff, 0x1d, 0x00, 0x00, 0x13, 0x1b, -0x27, 0x6c, 0xcf, 0x9f, 0x9d, 0x6b, 0xcf, 0x1f, -0x20, 0x6b, 0xaf, 0x0a, 0x1e, 0xbc, 0x5f, 0x05, -0x27, 0x0c, 0xef, 0x41, 0x2e, 0x76, 0xbf, 0x10, -0xef, 0x6d, 0xaf, 0xae, 0xcf, 0xe0, 0x1c, 0xae, -0xaf, 0x0b, 0x78, 0xcb, 0xcf, 0xcc, 0xdf, 0x0a, -0x1f, 0x07, 0x52, 0x01, 0x5e, 0x00, 0x1e, 0x04, -0x5f, 0xae, 0xcf, 0x6d, 0xdf, 0xbf, 0x01, 0xae, -0xaf, 0x03, 0x78, 0xae, 0xcf, 0x6d, 0xdf, 0x3f, -0x00, 0xae, 0xaf, 0x16, 0x82, 0x6d, 0xbf, 0x05, -0x81, 0x64, 0xef, 0xbf, 0x22, 0xbd, 0x80, 0x34, -0x81, 0x53, 0x81, 0x6d, 0x26, 0xe5, 0x55, 0xcb, -0xcf, 0xcc, 0xdf, 0x0a, 0x1f, 0x02, 0x5e, 0x04, -0x52, 0x00, 0x1e, 0x02, 0x5f, 0xae, 0xcf, 0x5f, -0x20, 0xae, 0xaf, 0x00, 0xef, 0x41, 0x2e, 0x76, -0xbf, 0x05, 0x27, 0x00, 0x2e, 0x6e, 0x8f, 0x02, -0x2e, 0x6b, 0x81, 0x00, 0x2e, 0xd1, 0x8d, 0x73, -0x23, 0x0a, 0xef, 0x10, 0xaf, 0x02, 0x2e, 0x02, -0x81, 0x80, 0xef, 0x00, 0x2e, 0xc4, 0x8d, 0x05, -0x81, 0x08, 0xef, 0x06, 0xaf, 0x01, 0x2e, 0x54, -0x80, 0x01, 0x2e, 0x56, 0x80, 0x06, 0x25, 0xf9, -0x55, 0xb3, 0x88, 0x40, 0xcf, 0xe0, 0xaf, 0x41, -0xdf, 0xe1, 0xbf, 0x41, 0x2e + 0x42, 0xca, 0x00, + 0xb1, 0x25, 0xff, 0xef, 0x6c, + 0xaf, 0x03, 0x50, 0x6c, 0x24, 0x01, 0x53, 0xff, + 0xef, 0x6c, 0xaf, 0x6b, 0xcf, 0xdf, 0x96, 0xb0, + 0xef, 0x00, 0xff, 0x1d, 0x00, 0x00, 0x13, 0x1b, + 0x27, 0x6c, 0xcf, 0x9f, 0x9d, 0x6b, 0xcf, 0x1f, + 0x20, 0x6b, 0xaf, 0x0a, 0x1e, 0xbc, 0x5f, 0x05, + 0x27, 0x0c, 0xef, 0x41, 0x2e, 0x76, 0xbf, 0x10, + 0xef, 0x6d, 0xaf, 0xae, 0xcf, 0xe0, 0x1c, 0xae, + 0xaf, 0x0b, 0x78, 0xcb, 0xcf, 0xcc, 0xdf, 0x0a, + 0x1f, 0x07, 0x52, 0x01, 0x5e, 0x00, 0x1e, 0x04, + 0x5f, 0xae, 0xcf, 0x6d, 0xdf, 0xbf, 0x01, 0xae, + 0xaf, 0x03, 0x78, 0xae, 0xcf, 0x6d, 0xdf, 0x3f, + 0x00, 0xae, 0xaf, 0x16, 0x82, 0x6d, 0xbf, 0x05, + 0x81, 0x64, 0xef, 0xbf, 0x22, 0xbd, 0x80, 0x34, + 0x81, 0x53, 0x81, 0x6d, 0x26, 0xe5, 0x55, 0xcb, + 0xcf, 0xcc, 0xdf, 0x0a, 0x1f, 0x02, 0x5e, 0x04, + 0x52, 0x00, 0x1e, 0x02, 0x5f, 0xae, 0xcf, 0x5f, + 0x20, 0xae, 0xaf, 0x00, 0xef, 0x41, 0x2e, 0x76, + 0xbf, 0x05, 0x27, 0x00, 0x2e, 0x6e, 0x8f, 0x02, + 0x2e, 0x6b, 0x81, 0x00, 0x2e, 0xd1, 0x8d, 0x73, + 0x23, 0x0a, 0xef, 0x10, 0xaf, 0x02, 0x2e, 0x02, + 0x81, 0x80, 0xef, 0x00, 0x2e, 0xc4, 0x8d, 0x05, + 0x81, 0x08, 0xef, 0x06, 0xaf, 0x01, 0x2e, 0x54, + 0x80, 0x01, 0x2e, 0x56, 0x80, 0x06, 0x25, 0xf9, + 0x55, 0xb3, 0x88, 0x40, 0xcf, 0xe0, 0xaf, 0x41, + 0xdf, 0xe1, 0xbf, 0x41, 0x2e }; static const unsigned char pkt180[] = { -0x42, 0xca, 0x00, -0x15, 0x26, 0x4e, 0xdf, 0xf7, -0x1c, 0x41, 0x2e, 0x4e, 0xbf, 0x01, 0x2e, 0x54, -0x80, 0x01, 0x2e, 0x56, 0x80, 0x4f, 0x82, 0x40, -0x2e, 0x8f, 0xdf, 0xdf, 0x22, 0xed, 0x55, 0x30, -0x88, 0x4e, 0x23, 0x4e, 0xcf, 0x31, 0x88, 0x37, -0x88, 0x3f, 0x9f, 0x4e, 0xcf, 0x2d, 0x88, 0x39, -0x88, 0x1f, 0x9f, 0x4e, 0x24, 0x4e, 0xcf, 0x04, -0x1e, 0xf3, 0x55, 0xf8, 0x0f, 0x08, 0xef, 0x06, -0xaf, 0xf6, 0x97, 0xbc, 0x03, 0x01, 0x5f, 0xff, -0x0f, 0xfc, 0x97, 0x06, 0x25, 0xf9, 0x55, 0xf8, -0x0f, 0x08, 0xff, 0x06, 0xbf, 0xf6, 0x9f, 0xdf, -0x01, 0xa1, 0x27, 0x7f, 0x21, 0x3f, 0x9f, 0x06, -0x25, 0xf8, 0x55, 0xf8, 0x0f, 0x04, 0xef, 0x06, -0xaf, 0xbb, 0xef, 0x00, 0xff, 0x1a, 0x27, 0xfc, -0x9f, 0xfc, 0x97, 0x09, 0x27, 0x5f, 0x02, 0x3f, -0x97, 0x06, 0x25, 0xf8, 0x55, 0x81, 0xcf, 0x24, -0xaf, 0x05, 0x27, 0x54, 0xef, 0x28, 0xff, 0x1b, -0x27, 0x05, 0x27, 0xdf, 0x96, 0x40, 0xcf, 0x41, -0xdf, 0x1d, 0x00, 0x00, 0x13, 0x19, 0x27, 0x05, -0x27, 0x0f, 0xff, 0x0b, 0x88, 0x40, 0x10, 0x00, -0x13, 0x8e, 0x81, 0x05, 0x27, 0xf0, 0xff, 0x05, -0x88, 0x04, 0x11, 0x3f, 0x22, 0xff, 0x97, 0x09, -0x27, 0x0f, 0x1c, 0x05, 0x27, 0xff, 0x96, 0x9b, -0x22, 0x9b, 0x22, 0x80, 0xef, 0x06, 0xaf, 0xe0, -0x97, 0x02, 0x03, 0xbf, 0x22, 0x00, 0x00, 0xc1, -0x00, 0x1f, 0x90, 0x7f, 0x90 + 0x42, 0xca, 0x00, + 0x15, 0x26, 0x4e, 0xdf, 0xf7, + 0x1c, 0x41, 0x2e, 0x4e, 0xbf, 0x01, 0x2e, 0x54, + 0x80, 0x01, 0x2e, 0x56, 0x80, 0x4f, 0x82, 0x40, + 0x2e, 0x8f, 0xdf, 0xdf, 0x22, 0xed, 0x55, 0x30, + 0x88, 0x4e, 0x23, 0x4e, 0xcf, 0x31, 0x88, 0x37, + 0x88, 0x3f, 0x9f, 0x4e, 0xcf, 0x2d, 0x88, 0x39, + 0x88, 0x1f, 0x9f, 0x4e, 0x24, 0x4e, 0xcf, 0x04, + 0x1e, 0xf3, 0x55, 0xf8, 0x0f, 0x08, 0xef, 0x06, + 0xaf, 0xf6, 0x97, 0xbc, 0x03, 0x01, 0x5f, 0xff, + 0x0f, 0xfc, 0x97, 0x06, 0x25, 0xf9, 0x55, 0xf8, + 0x0f, 0x08, 0xff, 0x06, 0xbf, 0xf6, 0x9f, 0xdf, + 0x01, 0xa1, 0x27, 0x7f, 0x21, 0x3f, 0x9f, 0x06, + 0x25, 0xf8, 0x55, 0xf8, 0x0f, 0x04, 0xef, 0x06, + 0xaf, 0xbb, 0xef, 0x00, 0xff, 0x1a, 0x27, 0xfc, + 0x9f, 0xfc, 0x97, 0x09, 0x27, 0x5f, 0x02, 0x3f, + 0x97, 0x06, 0x25, 0xf8, 0x55, 0x81, 0xcf, 0x24, + 0xaf, 0x05, 0x27, 0x54, 0xef, 0x28, 0xff, 0x1b, + 0x27, 0x05, 0x27, 0xdf, 0x96, 0x40, 0xcf, 0x41, + 0xdf, 0x1d, 0x00, 0x00, 0x13, 0x19, 0x27, 0x05, + 0x27, 0x0f, 0xff, 0x0b, 0x88, 0x40, 0x10, 0x00, + 0x13, 0x8e, 0x81, 0x05, 0x27, 0xf0, 0xff, 0x05, + 0x88, 0x04, 0x11, 0x3f, 0x22, 0xff, 0x97, 0x09, + 0x27, 0x0f, 0x1c, 0x05, 0x27, 0xff, 0x96, 0x9b, + 0x22, 0x9b, 0x22, 0x80, 0xef, 0x06, 0xaf, 0xe0, + 0x97, 0x02, 0x03, 0xbf, 0x22, 0x00, 0x00, 0xc1, + 0x00, 0x1f, 0x90, 0x7f, 0x90 }; static const unsigned char pkt184[] = { -0x42, 0xca, 0x00, -0x79, 0x26, 0x04, 0x0d, 0x06, -0x25, 0xf5, 0x55, 0x03, 0x0c, 0x05, 0x27, 0x04, -0xef, 0x10, 0xaf, 0x02, 0x2e, 0x02, 0x81, 0x05, -0x81, 0xf7, 0xef, 0x16, 0x80, 0x6b, 0x81, 0x05, -0x27, 0x73, 0x23, 0x08, 0xef, 0x0b, 0xaf, 0x02, -0x2e, 0x6b, 0x81, 0x00, 0x2e, 0x6e, 0x8f, 0x00, -0x2e, 0xd1, 0x8d, 0x0a, 0xef, 0x10, 0xaf, 0x02, -0x2e, 0x02, 0x81, 0x88, 0x82, 0x02, 0x2e, 0x9f, -0x80, 0x80, 0xef, 0x00, 0x2e, 0xc4, 0x8d, 0x05, -0x81, 0x0b, 0xcf, 0x06, 0xaf, 0x01, 0x2e, 0x54, -0x80, 0x01, 0x2e, 0x56, 0x80, 0x06, 0x25, 0xf9, -0x55, 0x1f, 0x88, 0x20, 0x82, 0x02, 0x2e, 0x76, -0x81, 0xf7, 0xef, 0x16, 0x80, 0x81, 0xcf, 0x72, -0xaf, 0x02, 0x2e, 0x6b, 0x81, 0x02, 0x2e, 0xc0, -0x81, 0x08, 0xef, 0x02, 0x2e, 0x51, 0x80, 0x08, -0xef, 0x02, 0x2e, 0x7a, 0x80, 0x01, 0x2e, 0x89, -0x81, 0x2d, 0xcf, 0xdf, 0x96, 0x2c, 0xcf, 0xdf, -0x96, 0x2a, 0xcf, 0x2b, 0xdf, 0x9d, 0x01, 0x5d, -0x01, 0x83, 0xaf, 0x84, 0xbf, 0xc8, 0xef, 0x0b, -0xaf, 0x05, 0x27, 0x0a, 0xef, 0x73, 0x43, 0x02, -0x5b, 0x73, 0xcf, 0x09, 0x27, 0x0f, 0x1c, 0x81, -0xaf, 0x73, 0xcf, 0x09, 0x27, 0x30, 0x1c, 0xfc, -0xdf, 0xcf, 0x1d, 0x5f, 0x02, 0xfc, 0xbf, 0x81, -0xcf, 0x10, 0xaf, 0x02, 0x2e, 0x02, 0x81, 0x88, -0x82, 0x02, 0x2e, 0x9f, 0x80, 0x40, 0xef, 0x6b, -0xaf, 0x80, 0xef, 0x82, 0xaf + 0x42, 0xca, 0x00, + 0x79, 0x26, 0x04, 0x0d, 0x06, + 0x25, 0xf5, 0x55, 0x03, 0x0c, 0x05, 0x27, 0x04, + 0xef, 0x10, 0xaf, 0x02, 0x2e, 0x02, 0x81, 0x05, + 0x81, 0xf7, 0xef, 0x16, 0x80, 0x6b, 0x81, 0x05, + 0x27, 0x73, 0x23, 0x08, 0xef, 0x0b, 0xaf, 0x02, + 0x2e, 0x6b, 0x81, 0x00, 0x2e, 0x6e, 0x8f, 0x00, + 0x2e, 0xd1, 0x8d, 0x0a, 0xef, 0x10, 0xaf, 0x02, + 0x2e, 0x02, 0x81, 0x88, 0x82, 0x02, 0x2e, 0x9f, + 0x80, 0x80, 0xef, 0x00, 0x2e, 0xc4, 0x8d, 0x05, + 0x81, 0x0b, 0xcf, 0x06, 0xaf, 0x01, 0x2e, 0x54, + 0x80, 0x01, 0x2e, 0x56, 0x80, 0x06, 0x25, 0xf9, + 0x55, 0x1f, 0x88, 0x20, 0x82, 0x02, 0x2e, 0x76, + 0x81, 0xf7, 0xef, 0x16, 0x80, 0x81, 0xcf, 0x72, + 0xaf, 0x02, 0x2e, 0x6b, 0x81, 0x02, 0x2e, 0xc0, + 0x81, 0x08, 0xef, 0x02, 0x2e, 0x51, 0x80, 0x08, + 0xef, 0x02, 0x2e, 0x7a, 0x80, 0x01, 0x2e, 0x89, + 0x81, 0x2d, 0xcf, 0xdf, 0x96, 0x2c, 0xcf, 0xdf, + 0x96, 0x2a, 0xcf, 0x2b, 0xdf, 0x9d, 0x01, 0x5d, + 0x01, 0x83, 0xaf, 0x84, 0xbf, 0xc8, 0xef, 0x0b, + 0xaf, 0x05, 0x27, 0x0a, 0xef, 0x73, 0x43, 0x02, + 0x5b, 0x73, 0xcf, 0x09, 0x27, 0x0f, 0x1c, 0x81, + 0xaf, 0x73, 0xcf, 0x09, 0x27, 0x30, 0x1c, 0xfc, + 0xdf, 0xcf, 0x1d, 0x5f, 0x02, 0xfc, 0xbf, 0x81, + 0xcf, 0x10, 0xaf, 0x02, 0x2e, 0x02, 0x81, 0x88, + 0x82, 0x02, 0x2e, 0x9f, 0x80, 0x40, 0xef, 0x6b, + 0xaf, 0x80, 0xef, 0x82, 0xaf }; static const unsigned char pkt188[] = { -0x42, 0x9a, 0x00, -0xdd, 0x26, 0x00, 0x2e, 0xc4, -0x8d, 0x05, 0x81, 0x01, 0x2e, 0x54, 0x80, 0x01, -0x2e, 0x56, 0x80, 0x20, 0x82, 0x02, 0x2e, 0xe6, -0x80, 0x0a, 0x5b, 0x73, 0x43, 0x18, 0x5a, 0x81, -0xcf, 0x5e, 0xdf, 0xbf, 0x03, 0x14, 0x5f, 0x5f, -0x20, 0x81, 0xaf, 0xdf, 0x22, 0x10, 0x54, 0xde, -0x50, 0x40, 0x2e, 0x8f, 0xdf, 0x1f, 0x2c, 0x0c, -0x5a, 0x5f, 0x2c, 0x09, 0x5b, 0x82, 0xcf, 0x6b, -0xdf, 0x3f, 0x00, 0x82, 0xaf, 0x6b, 0x26, 0xe8, -0x54, 0x6b, 0xdf, 0x16, 0x82, 0x6b, 0xbf, 0xd9, -0x50, 0x05, 0x27, 0x82, 0xcf, 0x6b, 0xdf, 0xbf, -0x01, 0x82, 0xaf, 0x6b, 0x26, 0xf4, 0x55, 0xdc, -0x50, 0x88, 0x82, 0x8c, 0x82, 0x9f, 0x22, 0xbb, -0xaf, 0xbc, 0xaf, 0xbd, 0xaf, 0xbe, 0xaf, 0x05, -0x27, 0xf9, 0x44, 0x08, 0x5a, 0xc1, 0x2e, 0x81, -0xdf, 0x01, 0x1f, 0x0e, 0x52, 0x0c, 0x5e, 0xc1, -0x2e, 0x80, 0xdf, 0xfe, 0x1f, 0x09, 0x52, 0xc1, -0x2e, 0x81, 0xdf, 0x03, 0x1f, 0x05, 0x52, 0x03, -0x5e, 0xc1, 0x2e, 0x80, 0xdf, 0xfc, 0x1f, 0x00, -0x52, 0x0c, 0x27, 0x0d, 0x27 + 0x42, 0x9a, 0x00, + 0xdd, 0x26, 0x00, 0x2e, 0xc4, + 0x8d, 0x05, 0x81, 0x01, 0x2e, 0x54, 0x80, 0x01, + 0x2e, 0x56, 0x80, 0x20, 0x82, 0x02, 0x2e, 0xe6, + 0x80, 0x0a, 0x5b, 0x73, 0x43, 0x18, 0x5a, 0x81, + 0xcf, 0x5e, 0xdf, 0xbf, 0x03, 0x14, 0x5f, 0x5f, + 0x20, 0x81, 0xaf, 0xdf, 0x22, 0x10, 0x54, 0xde, + 0x50, 0x40, 0x2e, 0x8f, 0xdf, 0x1f, 0x2c, 0x0c, + 0x5a, 0x5f, 0x2c, 0x09, 0x5b, 0x82, 0xcf, 0x6b, + 0xdf, 0x3f, 0x00, 0x82, 0xaf, 0x6b, 0x26, 0xe8, + 0x54, 0x6b, 0xdf, 0x16, 0x82, 0x6b, 0xbf, 0xd9, + 0x50, 0x05, 0x27, 0x82, 0xcf, 0x6b, 0xdf, 0xbf, + 0x01, 0x82, 0xaf, 0x6b, 0x26, 0xf4, 0x55, 0xdc, + 0x50, 0x88, 0x82, 0x8c, 0x82, 0x9f, 0x22, 0xbb, + 0xaf, 0xbc, 0xaf, 0xbd, 0xaf, 0xbe, 0xaf, 0x05, + 0x27, 0xf9, 0x44, 0x08, 0x5a, 0xc1, 0x2e, 0x81, + 0xdf, 0x01, 0x1f, 0x0e, 0x52, 0x0c, 0x5e, 0xc1, + 0x2e, 0x80, 0xdf, 0xfe, 0x1f, 0x09, 0x52, 0xc1, + 0x2e, 0x81, 0xdf, 0x03, 0x1f, 0x05, 0x52, 0x03, + 0x5e, 0xc1, 0x2e, 0x80, 0xdf, 0xfc, 0x1f, 0x00, + 0x52, 0x0c, 0x27, 0x0d, 0x27 }; static const unsigned char pkt192[] = { -0x42, 0x7e, 0x00, -0x29, 0x27, 0x53, 0x80, 0x01, -0x0d, 0xf5, 0x97, 0xff, 0x0d, 0x1f, 0x99, 0x49, -0xcf, 0x5f, 0x99, 0x08, 0x44, 0x00, 0x2e, 0x32, -0x5a, 0x0b, 0x0d, 0x44, 0xcf, 0x0c, 0x41, 0x00, -0x5b, 0x1f, 0x20, 0x44, 0xaf, 0x5f, 0x9f, 0x04, -0x0d, 0x11, 0xcf, 0x5f, 0x9f, 0x12, 0xcf, 0x5f, -0x9f, 0x1c, 0xcf, 0x5f, 0x9f, 0x1d, 0xcf, 0x5f, -0x9f, 0x4d, 0xcf, 0x5f, 0x9f, 0x49, 0xcf, 0x5f, -0x9f, 0x06, 0x0d, 0xe0, 0x97, 0x0f, 0x1c, 0x5f, -0x9f, 0x0a, 0xcf, 0x5f, 0x9f, 0x09, 0xcf, 0x5f, -0x9f, 0x78, 0xcf, 0x5f, 0x9f, 0x9f, 0xcf, 0x5f, -0x9f, 0x92, 0xcf, 0x5f, 0x9f, 0x19, 0xcf, 0x5f, -0x9f, 0x02, 0x0d, 0x85, 0xcf, 0x5f, 0x9f, 0x44, -0xdf, 0x02, 0x2e, 0x8c, 0x81, 0x5f, 0x9f, 0x4d, -0xcf, 0x5f, 0x9f, 0x01, 0x0d, 0x6a, 0xcf, 0x09, -0x27, 0x69, 0xdf, 0x3f, 0x02, 0x5f, 0x9f, 0x05, -0x27 + 0x42, 0x7e, 0x00, + 0x29, 0x27, 0x53, 0x80, 0x01, + 0x0d, 0xf5, 0x97, 0xff, 0x0d, 0x1f, 0x99, 0x49, + 0xcf, 0x5f, 0x99, 0x08, 0x44, 0x00, 0x2e, 0x32, + 0x5a, 0x0b, 0x0d, 0x44, 0xcf, 0x0c, 0x41, 0x00, + 0x5b, 0x1f, 0x20, 0x44, 0xaf, 0x5f, 0x9f, 0x04, + 0x0d, 0x11, 0xcf, 0x5f, 0x9f, 0x12, 0xcf, 0x5f, + 0x9f, 0x1c, 0xcf, 0x5f, 0x9f, 0x1d, 0xcf, 0x5f, + 0x9f, 0x4d, 0xcf, 0x5f, 0x9f, 0x49, 0xcf, 0x5f, + 0x9f, 0x06, 0x0d, 0xe0, 0x97, 0x0f, 0x1c, 0x5f, + 0x9f, 0x0a, 0xcf, 0x5f, 0x9f, 0x09, 0xcf, 0x5f, + 0x9f, 0x78, 0xcf, 0x5f, 0x9f, 0x9f, 0xcf, 0x5f, + 0x9f, 0x92, 0xcf, 0x5f, 0x9f, 0x19, 0xcf, 0x5f, + 0x9f, 0x02, 0x0d, 0x85, 0xcf, 0x5f, 0x9f, 0x44, + 0xdf, 0x02, 0x2e, 0x8c, 0x81, 0x5f, 0x9f, 0x4d, + 0xcf, 0x5f, 0x9f, 0x01, 0x0d, 0x6a, 0xcf, 0x09, + 0x27, 0x69, 0xdf, 0x3f, 0x02, 0x5f, 0x9f, 0x05, + 0x27 }; static const unsigned char pkt196[] = { -0x42, 0xca, 0x00, -0x67, 0x27, 0x00, 0x2e, 0xf5, -0x88, 0x39, 0x81, 0x84, 0x88, 0x05, 0xcf, 0xdf, -0x22, 0x33, 0x55, 0x04, 0xcf, 0x2a, 0x1e, 0x30, -0x55, 0xfe, 0xdf, 0xfe, 0xcf, 0x00, 0x1f, 0x1b, -0x55, 0x00, 0x1e, 0x0d, 0x54, 0xc6, 0x2e, 0x00, -0xdf, 0x3f, 0x20, 0xbf, 0x03, 0x14, 0x55, 0xc6, -0x2e, 0x01, 0xdf, 0x3f, 0x2c, 0x10, 0x5b, 0x46, -0x2e, 0x00, 0xbf, 0x00, 0x2e, 0xdb, 0x88, 0x09, -0x78, 0x00, 0xef, 0x46, 0x2e, 0x00, 0xbf, 0x46, -0x2e, 0x01, 0xdf, 0x1f, 0x28, 0x46, 0x2e, 0x01, -0xbf, 0x00, 0x2e, 0xbc, 0x88, 0x13, 0x88, 0x05, -0x27, 0x46, 0x2e, 0x01, 0xdf, 0x1f, 0x2a, 0x46, -0x2e, 0x01, 0xbf, 0x41, 0x2e, 0xb6, 0xdf, 0x01, -0xff, 0xab, 0xef, 0x19, 0x27, 0x42, 0xff, 0x7f, -0x98, 0x9f, 0x98, 0x24, 0x28, 0x2a, 0x85, 0x24, -0x2a, 0x05, 0x27, 0x2c, 0x85, 0x05, 0x27, 0xfd, -0x0c, 0x00, 0x2e, 0xab, 0x88, 0x14, 0xef, 0x00, -0x2e, 0xef, 0x88, 0x32, 0x88, 0x3a, 0x88, 0x34, -0x88, 0x38, 0x88, 0x32, 0x88, 0x36, 0x88, 0x30, -0x88, 0x34, 0x88, 0x2e, 0x88, 0x32, 0x88, 0x46, -0x2e, 0x00, 0xdf, 0x1f, 0x9f, 0xe2, 0xef, 0x1f, -0x90, 0xe0, 0xff, 0x7f, 0x90, 0x0e, 0xef, 0x00, -0x2e, 0xe7, 0x88, 0x80, 0xef, 0x1f, 0x9f, 0x9f, -0x22, 0x1f, 0x9f, 0x1f, 0x9f, 0x1f, 0x9f, 0x1f, -0x9f, 0x1f, 0x9f, 0x1f, 0x9f, 0x01, 0xef, 0x1f, -0x9f, 0xb8, 0xef, 0x1f, 0x9f + 0x42, 0xca, 0x00, + 0x67, 0x27, 0x00, 0x2e, 0xf5, + 0x88, 0x39, 0x81, 0x84, 0x88, 0x05, 0xcf, 0xdf, + 0x22, 0x33, 0x55, 0x04, 0xcf, 0x2a, 0x1e, 0x30, + 0x55, 0xfe, 0xdf, 0xfe, 0xcf, 0x00, 0x1f, 0x1b, + 0x55, 0x00, 0x1e, 0x0d, 0x54, 0xc6, 0x2e, 0x00, + 0xdf, 0x3f, 0x20, 0xbf, 0x03, 0x14, 0x55, 0xc6, + 0x2e, 0x01, 0xdf, 0x3f, 0x2c, 0x10, 0x5b, 0x46, + 0x2e, 0x00, 0xbf, 0x00, 0x2e, 0xdb, 0x88, 0x09, + 0x78, 0x00, 0xef, 0x46, 0x2e, 0x00, 0xbf, 0x46, + 0x2e, 0x01, 0xdf, 0x1f, 0x28, 0x46, 0x2e, 0x01, + 0xbf, 0x00, 0x2e, 0xbc, 0x88, 0x13, 0x88, 0x05, + 0x27, 0x46, 0x2e, 0x01, 0xdf, 0x1f, 0x2a, 0x46, + 0x2e, 0x01, 0xbf, 0x41, 0x2e, 0xb6, 0xdf, 0x01, + 0xff, 0xab, 0xef, 0x19, 0x27, 0x42, 0xff, 0x7f, + 0x98, 0x9f, 0x98, 0x24, 0x28, 0x2a, 0x85, 0x24, + 0x2a, 0x05, 0x27, 0x2c, 0x85, 0x05, 0x27, 0xfd, + 0x0c, 0x00, 0x2e, 0xab, 0x88, 0x14, 0xef, 0x00, + 0x2e, 0xef, 0x88, 0x32, 0x88, 0x3a, 0x88, 0x34, + 0x88, 0x38, 0x88, 0x32, 0x88, 0x36, 0x88, 0x30, + 0x88, 0x34, 0x88, 0x2e, 0x88, 0x32, 0x88, 0x46, + 0x2e, 0x00, 0xdf, 0x1f, 0x9f, 0xe2, 0xef, 0x1f, + 0x90, 0xe0, 0xff, 0x7f, 0x90, 0x0e, 0xef, 0x00, + 0x2e, 0xe7, 0x88, 0x80, 0xef, 0x1f, 0x9f, 0x9f, + 0x22, 0x1f, 0x9f, 0x1f, 0x9f, 0x1f, 0x9f, 0x1f, + 0x9f, 0x1f, 0x9f, 0x1f, 0x9f, 0x01, 0xef, 0x1f, + 0x9f, 0xb8, 0xef, 0x1f, 0x9f }; static const unsigned char pkt200[] = { -0x42, 0x66, 0x00, -0xcb, 0x27, 0x00, 0x2e, 0xab, -0x88, 0x40, 0xef, 0xfc, 0x9f, 0x5f, 0x20, 0xfc, -0x55, 0x03, 0x0c, 0x01, 0x2e, 0x6e, 0x86, 0x01, -0x2e, 0x05, 0x86, 0x00, 0x2e, 0xb5, 0x88, 0x00, -0x2e, 0xb1, 0x88, 0x14, 0xef, 0x00, 0x2e, 0xb7, -0x88, 0x05, 0x27, 0x40, 0xef, 0x28, 0xff, 0x1a, -0x27, 0x05, 0x27, 0x16, 0x27, 0x04, 0x10, 0x00, -0x13, 0x1a, 0x27, 0x05, 0x27, 0xd9, 0x9f, 0x3f, -0x9f, 0xd8, 0x9f, 0x3f, 0x9f, 0xd7, 0x9f, 0x3f, -0x9f, 0xd6, 0x9f, 0x3f, 0x9f, 0x05, 0x27, 0x7f, -0xef, 0x28, 0xff, 0x46, 0x2e, 0x1d, 0xbf, 0xc6, -0x2e, 0x1c, 0xbf, 0x93, 0xef, 0x28, 0xff, 0x46, -0x2e, 0x1f, 0xbf, 0xc6, 0x2e, 0x1e, 0xbf, 0x05, -0x27 + 0x42, 0x66, 0x00, + 0xcb, 0x27, 0x00, 0x2e, 0xab, + 0x88, 0x40, 0xef, 0xfc, 0x9f, 0x5f, 0x20, 0xfc, + 0x55, 0x03, 0x0c, 0x01, 0x2e, 0x6e, 0x86, 0x01, + 0x2e, 0x05, 0x86, 0x00, 0x2e, 0xb5, 0x88, 0x00, + 0x2e, 0xb1, 0x88, 0x14, 0xef, 0x00, 0x2e, 0xb7, + 0x88, 0x05, 0x27, 0x40, 0xef, 0x28, 0xff, 0x1a, + 0x27, 0x05, 0x27, 0x16, 0x27, 0x04, 0x10, 0x00, + 0x13, 0x1a, 0x27, 0x05, 0x27, 0xd9, 0x9f, 0x3f, + 0x9f, 0xd8, 0x9f, 0x3f, 0x9f, 0xd7, 0x9f, 0x3f, + 0x9f, 0xd6, 0x9f, 0x3f, 0x9f, 0x05, 0x27, 0x7f, + 0xef, 0x28, 0xff, 0x46, 0x2e, 0x1d, 0xbf, 0xc6, + 0x2e, 0x1c, 0xbf, 0x93, 0xef, 0x28, 0xff, 0x46, + 0x2e, 0x1f, 0xbf, 0xc6, 0x2e, 0x1e, 0xbf, 0x05, + 0x27 }; static const unsigned char pkt204[] = { -0x42, 0xca, 0x00, -0xfd, 0x27, 0xfd, 0x0c, 0x00, -0x2e, 0xf5, 0x88, 0x0d, 0x84, 0x05, 0xcf, 0xdf, -0x22, 0x00, 0x2e, 0x98, 0x55, 0x04, 0xcf, 0x14, -0x1e, 0x00, 0x2e, 0x94, 0x55, 0x00, 0x2e, 0xab, -0x88, 0xbb, 0xef, 0x1f, 0x90, 0x91, 0xff, 0x7f, -0x90, 0x14, 0xef, 0x00, 0x2e, 0xe7, 0x88, 0x14, -0xef, 0x00, 0x2e, 0xef, 0x88, 0x33, 0xef, 0x1f, -0x90, 0x71, 0xff, 0x7f, 0x90, 0x18, 0xef, 0x00, -0x2e, 0xe7, 0x88, 0x00, 0x2e, 0xab, 0x88, 0x40, -0xef, 0xfc, 0x9f, 0x5f, 0x20, 0xfc, 0x55, 0x01, -0x2e, 0x6e, 0x86, 0x01, 0x2e, 0x05, 0x86, 0x00, -0x2e, 0xab, 0x88, 0x7a, 0x88, 0x0a, 0xef, 0x00, -0x2e, 0xb7, 0x88, 0x76, 0x88, 0x00, 0xff, 0x80, -0xef, 0x19, 0x27, 0x0a, 0xef, 0xdc, 0x9f, 0x7f, -0x9f, 0x5f, 0x20, 0xfb, 0x55, 0x0d, 0x84, 0x6c, -0x88, 0x0a, 0xef, 0x00, 0x2e, 0xb7, 0x88, 0x68, -0x88, 0x0a, 0xef, 0xdc, 0x9f, 0x7f, 0x9f, 0x5f, -0x20, 0xfb, 0x55, 0x5e, 0x88, 0xa4, 0x8f, 0x9e, -0x8f, 0xa2, 0x8f, 0x9c, 0x8f, 0xa0, 0x8f, 0x9a, -0x8f, 0x9e, 0x8f, 0x98, 0x8f, 0x9c, 0x8f, 0x9d, -0xef, 0x1f, 0x90, 0xda, 0xff, 0x7f, 0x90, 0x0f, -0xef, 0x00, 0x2e, 0xe7, 0x88, 0x80, 0xef, 0x1f, -0x9f, 0x9f, 0x22, 0x1f, 0x9f, 0x1f, 0x9f, 0x1f, -0x9f, 0x1f, 0x9f, 0x1f, 0x9f, 0x1f, 0x9f, 0x03, -0xef, 0x1f, 0x9f, 0xb8, 0xef, 0x1f, 0x9f, 0x00, -0x2e, 0xab, 0x88, 0x40, 0xef + 0x42, 0xca, 0x00, + 0xfd, 0x27, 0xfd, 0x0c, 0x00, + 0x2e, 0xf5, 0x88, 0x0d, 0x84, 0x05, 0xcf, 0xdf, + 0x22, 0x00, 0x2e, 0x98, 0x55, 0x04, 0xcf, 0x14, + 0x1e, 0x00, 0x2e, 0x94, 0x55, 0x00, 0x2e, 0xab, + 0x88, 0xbb, 0xef, 0x1f, 0x90, 0x91, 0xff, 0x7f, + 0x90, 0x14, 0xef, 0x00, 0x2e, 0xe7, 0x88, 0x14, + 0xef, 0x00, 0x2e, 0xef, 0x88, 0x33, 0xef, 0x1f, + 0x90, 0x71, 0xff, 0x7f, 0x90, 0x18, 0xef, 0x00, + 0x2e, 0xe7, 0x88, 0x00, 0x2e, 0xab, 0x88, 0x40, + 0xef, 0xfc, 0x9f, 0x5f, 0x20, 0xfc, 0x55, 0x01, + 0x2e, 0x6e, 0x86, 0x01, 0x2e, 0x05, 0x86, 0x00, + 0x2e, 0xab, 0x88, 0x7a, 0x88, 0x0a, 0xef, 0x00, + 0x2e, 0xb7, 0x88, 0x76, 0x88, 0x00, 0xff, 0x80, + 0xef, 0x19, 0x27, 0x0a, 0xef, 0xdc, 0x9f, 0x7f, + 0x9f, 0x5f, 0x20, 0xfb, 0x55, 0x0d, 0x84, 0x6c, + 0x88, 0x0a, 0xef, 0x00, 0x2e, 0xb7, 0x88, 0x68, + 0x88, 0x0a, 0xef, 0xdc, 0x9f, 0x7f, 0x9f, 0x5f, + 0x20, 0xfb, 0x55, 0x5e, 0x88, 0xa4, 0x8f, 0x9e, + 0x8f, 0xa2, 0x8f, 0x9c, 0x8f, 0xa0, 0x8f, 0x9a, + 0x8f, 0x9e, 0x8f, 0x98, 0x8f, 0x9c, 0x8f, 0x9d, + 0xef, 0x1f, 0x90, 0xda, 0xff, 0x7f, 0x90, 0x0f, + 0xef, 0x00, 0x2e, 0xe7, 0x88, 0x80, 0xef, 0x1f, + 0x9f, 0x9f, 0x22, 0x1f, 0x9f, 0x1f, 0x9f, 0x1f, + 0x9f, 0x1f, 0x9f, 0x1f, 0x9f, 0x1f, 0x9f, 0x03, + 0xef, 0x1f, 0x9f, 0xb8, 0xef, 0x1f, 0x9f, 0x00, + 0x2e, 0xab, 0x88, 0x40, 0xef }; static const unsigned char pkt208[] = { -0x42, 0xca, 0x00, -0x61, 0x28, 0xfc, 0x9f, 0x5f, -0x20, 0xfc, 0x55, 0x01, 0x2e, 0x05, 0x86, 0x00, -0x2e, 0xb5, 0x88, 0x72, 0x88, 0x7c, 0x8f, 0x76, -0x8f, 0x7a, 0x8f, 0x74, 0x8f, 0x78, 0x8f, 0x72, -0x8f, 0x76, 0x8f, 0x70, 0x8f, 0x74, 0x8f, 0x68, -0x88, 0x14, 0xef, 0xfc, 0x9f, 0x5f, 0x20, 0xfc, -0x55, 0x01, 0xff, 0xab, 0xef, 0x19, 0x27, 0x60, -0x88, 0x11, 0xff, 0xbf, 0x90, 0x51, 0xff, 0xc2, -0x97, 0xdf, 0x01, 0x7f, 0x98, 0xfc, 0x9f, 0xbf, -0x98, 0x24, 0x28, 0xc2, 0x9f, 0x7f, 0x20, 0xbf, -0x90, 0xf4, 0x55, 0x24, 0x2a, 0x1d, 0x88, 0x72, -0xef, 0xff, 0xaf, 0x14, 0xef, 0xff, 0xaf, 0x00, -0xef, 0xff, 0xaf, 0x00, 0xff, 0x80, 0xef, 0x19, -0x27, 0x14, 0xff, 0xfd, 0x97, 0xff, 0xaf, 0x7f, -0x20, 0xfb, 0x55, 0x00, 0x2e, 0x5f, 0x89, 0x03, -0x0c, 0x02, 0x2e, 0xdd, 0x81, 0x05, 0x27, 0x2c, -0x85, 0x05, 0x27, 0x40, 0xef, 0x28, 0xff, 0x1a, -0x27, 0x05, 0x27, 0x02, 0xef, 0x06, 0xff, 0x1a, -0x27, 0x05, 0x27, 0x01, 0xff, 0xab, 0xef, 0x19, -0x27, 0x08, 0xef, 0x1f, 0x98, 0xe4, 0x29, 0x00, -0xff, 0xff, 0x96, 0x20, 0xff, 0xff, 0x96, 0x00, -0xff, 0xff, 0x96, 0x40, 0xff, 0xff, 0x96, 0x00, -0xff, 0xff, 0x96, 0x60, 0xff, 0xff, 0x96, 0x00, -0xff, 0xff, 0x96, 0x00, 0xff, 0xff, 0x96, 0x01, -0xff, 0xff, 0x96, 0x20, 0xff, 0xff, 0x96, 0x00, -0xff, 0xff, 0x96, 0x02, 0xff + 0x42, 0xca, 0x00, + 0x61, 0x28, 0xfc, 0x9f, 0x5f, + 0x20, 0xfc, 0x55, 0x01, 0x2e, 0x05, 0x86, 0x00, + 0x2e, 0xb5, 0x88, 0x72, 0x88, 0x7c, 0x8f, 0x76, + 0x8f, 0x7a, 0x8f, 0x74, 0x8f, 0x78, 0x8f, 0x72, + 0x8f, 0x76, 0x8f, 0x70, 0x8f, 0x74, 0x8f, 0x68, + 0x88, 0x14, 0xef, 0xfc, 0x9f, 0x5f, 0x20, 0xfc, + 0x55, 0x01, 0xff, 0xab, 0xef, 0x19, 0x27, 0x60, + 0x88, 0x11, 0xff, 0xbf, 0x90, 0x51, 0xff, 0xc2, + 0x97, 0xdf, 0x01, 0x7f, 0x98, 0xfc, 0x9f, 0xbf, + 0x98, 0x24, 0x28, 0xc2, 0x9f, 0x7f, 0x20, 0xbf, + 0x90, 0xf4, 0x55, 0x24, 0x2a, 0x1d, 0x88, 0x72, + 0xef, 0xff, 0xaf, 0x14, 0xef, 0xff, 0xaf, 0x00, + 0xef, 0xff, 0xaf, 0x00, 0xff, 0x80, 0xef, 0x19, + 0x27, 0x14, 0xff, 0xfd, 0x97, 0xff, 0xaf, 0x7f, + 0x20, 0xfb, 0x55, 0x00, 0x2e, 0x5f, 0x89, 0x03, + 0x0c, 0x02, 0x2e, 0xdd, 0x81, 0x05, 0x27, 0x2c, + 0x85, 0x05, 0x27, 0x40, 0xef, 0x28, 0xff, 0x1a, + 0x27, 0x05, 0x27, 0x02, 0xef, 0x06, 0xff, 0x1a, + 0x27, 0x05, 0x27, 0x01, 0xff, 0xab, 0xef, 0x19, + 0x27, 0x08, 0xef, 0x1f, 0x98, 0xe4, 0x29, 0x00, + 0xff, 0xff, 0x96, 0x20, 0xff, 0xff, 0x96, 0x00, + 0xff, 0xff, 0x96, 0x40, 0xff, 0xff, 0x96, 0x00, + 0xff, 0xff, 0x96, 0x60, 0xff, 0xff, 0x96, 0x00, + 0xff, 0xff, 0x96, 0x00, 0xff, 0xff, 0x96, 0x01, + 0xff, 0xff, 0x96, 0x20, 0xff, 0xff, 0x96, 0x00, + 0xff, 0xff, 0x96, 0x02, 0xff }; static const unsigned char pkt212[] = { -0x42, 0x38, 0x00, -0xc5, 0x28, 0xff, 0x96, 0x02, -0xff, 0xff, 0x96, 0x82, 0xff, 0xff, 0x96, 0x02, -0xff, 0xff, 0x96, 0x05, 0x88, 0x46, 0x2e, 0x01, -0xdf, 0x9f, 0x28, 0x46, 0x2e, 0x01, 0xbf, 0x05, -0x27, 0x0f, 0xef, 0x5f, 0x98, 0xdd, 0x9f, 0xbf, -0x98, 0x24, 0x28, 0x5f, 0x20, 0xf9, 0x55, 0x24, -0x2a, 0x05, 0x27, 0x7f, 0xef, 0x28, 0xff, 0x1b, -0x27, 0x05, 0x27 + 0x42, 0x38, 0x00, + 0xc5, 0x28, 0xff, 0x96, 0x02, + 0xff, 0xff, 0x96, 0x82, 0xff, 0xff, 0x96, 0x02, + 0xff, 0xff, 0x96, 0x05, 0x88, 0x46, 0x2e, 0x01, + 0xdf, 0x9f, 0x28, 0x46, 0x2e, 0x01, 0xbf, 0x05, + 0x27, 0x0f, 0xef, 0x5f, 0x98, 0xdd, 0x9f, 0xbf, + 0x98, 0x24, 0x28, 0x5f, 0x20, 0xf9, 0x55, 0x24, + 0x2a, 0x05, 0x27, 0x7f, 0xef, 0x28, 0xff, 0x1b, + 0x27, 0x05, 0x27 }; static const unsigned char pkt216[] = { -0x42, 0xca, 0x00, -0xe0, 0x28, 0xe1, 0x97, 0xe2, -0x9f, 0x46, 0x2e, 0x28, 0xbf, 0xc6, 0x2e, 0x29, -0xbf, 0xad, 0x88, 0x0a, 0x5b, 0xe9, 0x97, 0xea, -0x9f, 0x4f, 0xaf, 0x50, 0xbf, 0x46, 0x2e, 0x28, -0xdf, 0xc6, 0x2e, 0x29, 0xdf, 0x10, 0x10, 0x00, -0x13, 0x01, 0x78, 0x03, 0x10, 0x00, 0x13, 0xff, -0x96, 0xdf, 0x96, 0xd6, 0xcf, 0xd7, 0xdf, 0x0f, -0x1d, 0x01, 0x10, 0x00, 0x13, 0xff, 0x96, 0xdf, -0x96, 0xc8, 0xdf, 0xc7, 0xcf, 0x1f, 0x1d, 0xff, -0x96, 0xdf, 0x96, 0xc2, 0x97, 0xc3, 0x9f, 0x9d, -0x01, 0x5d, 0x01, 0xf5, 0x52, 0xc3, 0x03, 0x02, -0x5e, 0xf2, 0x52, 0x82, 0x03, 0xf0, 0x52, 0x02, -0x0c, 0xf8, 0x43, 0x03, 0x5b, 0x08, 0x44, 0x01, -0x5a, 0x00, 0x2e, 0xf3, 0x8f, 0x7f, 0x88, 0x6d, -0x5b, 0x41, 0x2e, 0xaf, 0xdf, 0xdf, 0x29, 0x41, -0x2e, 0xaf, 0xbf, 0x46, 0x2e, 0x28, 0xdf, 0xc6, -0x2e, 0x29, 0xdf, 0x03, 0x16, 0x00, 0x15, 0x46, -0x2e, 0x28, 0xbf, 0xc6, 0x2e, 0x29, 0xbf, 0x15, -0x27, 0xff, 0x96, 0xdf, 0x96, 0x8d, 0x88, 0x94, -0x88, 0xcd, 0x88, 0x01, 0xff, 0xab, 0xef, 0x19, -0x27, 0x6b, 0x88, 0xbf, 0x22, 0x3f, 0x98, 0x05, -0xff, 0x7f, 0x98, 0xdd, 0x9f, 0xbf, 0x98, 0x24, -0x28, 0x04, 0xff, 0x7f, 0x98, 0xdd, 0x9f, 0xbf, -0x98, 0x24, 0x28, 0x66, 0xff, 0xbf, 0x99, 0x12, -0xff, 0x7f, 0x99, 0xdd, 0x97, 0xdd, 0x9f, 0x19, -0x27, 0xe0, 0x97, 0xff, 0xaf + 0x42, 0xca, 0x00, + 0xe0, 0x28, 0xe1, 0x97, 0xe2, + 0x9f, 0x46, 0x2e, 0x28, 0xbf, 0xc6, 0x2e, 0x29, + 0xbf, 0xad, 0x88, 0x0a, 0x5b, 0xe9, 0x97, 0xea, + 0x9f, 0x4f, 0xaf, 0x50, 0xbf, 0x46, 0x2e, 0x28, + 0xdf, 0xc6, 0x2e, 0x29, 0xdf, 0x10, 0x10, 0x00, + 0x13, 0x01, 0x78, 0x03, 0x10, 0x00, 0x13, 0xff, + 0x96, 0xdf, 0x96, 0xd6, 0xcf, 0xd7, 0xdf, 0x0f, + 0x1d, 0x01, 0x10, 0x00, 0x13, 0xff, 0x96, 0xdf, + 0x96, 0xc8, 0xdf, 0xc7, 0xcf, 0x1f, 0x1d, 0xff, + 0x96, 0xdf, 0x96, 0xc2, 0x97, 0xc3, 0x9f, 0x9d, + 0x01, 0x5d, 0x01, 0xf5, 0x52, 0xc3, 0x03, 0x02, + 0x5e, 0xf2, 0x52, 0x82, 0x03, 0xf0, 0x52, 0x02, + 0x0c, 0xf8, 0x43, 0x03, 0x5b, 0x08, 0x44, 0x01, + 0x5a, 0x00, 0x2e, 0xf3, 0x8f, 0x7f, 0x88, 0x6d, + 0x5b, 0x41, 0x2e, 0xaf, 0xdf, 0xdf, 0x29, 0x41, + 0x2e, 0xaf, 0xbf, 0x46, 0x2e, 0x28, 0xdf, 0xc6, + 0x2e, 0x29, 0xdf, 0x03, 0x16, 0x00, 0x15, 0x46, + 0x2e, 0x28, 0xbf, 0xc6, 0x2e, 0x29, 0xbf, 0x15, + 0x27, 0xff, 0x96, 0xdf, 0x96, 0x8d, 0x88, 0x94, + 0x88, 0xcd, 0x88, 0x01, 0xff, 0xab, 0xef, 0x19, + 0x27, 0x6b, 0x88, 0xbf, 0x22, 0x3f, 0x98, 0x05, + 0xff, 0x7f, 0x98, 0xdd, 0x9f, 0xbf, 0x98, 0x24, + 0x28, 0x04, 0xff, 0x7f, 0x98, 0xdd, 0x9f, 0xbf, + 0x98, 0x24, 0x28, 0x66, 0xff, 0xbf, 0x99, 0x12, + 0xff, 0x7f, 0x99, 0xdd, 0x97, 0xdd, 0x9f, 0x19, + 0x27, 0xe0, 0x97, 0xff, 0xaf }; static const unsigned char pkt220[] = { -0x42, 0xca, 0x00, -0x44, 0x29, 0x46, 0x2e, 0x28, -0xdf, 0xc6, 0x2e, 0x29, 0xdf, 0x13, 0x10, 0x00, -0x13, 0xff, 0xaf, 0xff, 0xbf, 0xe3, 0x97, 0xff, -0xaf, 0xe4, 0x97, 0xff, 0xaf, 0xe5, 0x97, 0xff, -0xaf, 0xef, 0x88, 0x06, 0x0d, 0xdd, 0x97, 0xdd, -0x9f, 0x46, 0x2e, 0x28, 0xdf, 0xc6, 0x2e, 0x29, -0xdf, 0x06, 0xaf, 0x4e, 0xbf, 0xff, 0x22, 0x11, -0x54, 0x15, 0x27, 0x1a, 0x27, 0x01, 0xff, 0xab, -0xef, 0x19, 0x27, 0xdc, 0x97, 0xdf, 0x99, 0x28, -0x28, 0x0f, 0x27, 0x68, 0x2c, 0xfd, 0x5b, 0xe9, -0x97, 0xff, 0xaf, 0x6a, 0x28, 0x06, 0x25, 0xf4, -0x53, 0x4e, 0x25, 0xf2, 0x55, 0xdc, 0x97, 0xdf, -0x99, 0x28, 0x28, 0x0f, 0x27, 0x68, 0x2c, 0xfd, -0x5b, 0xe9, 0x97, 0xff, 0xaf, 0x6a, 0x28, 0x06, -0x25, 0xf4, 0x55, 0x41, 0x2e, 0xaf, 0xdf, 0xdf, -0x2b, 0x41, 0x2e, 0xaf, 0xbf, 0xbf, 0x22, 0xbf, -0x99, 0x7f, 0x99, 0x05, 0x27, 0xdd, 0x97, 0xdd, -0x9f, 0x06, 0xaf, 0x4e, 0xbf, 0xff, 0x22, 0x05, -0x54, 0xfd, 0x97, 0xff, 0xaf, 0x06, 0x25, 0xfb, -0x53, 0x4e, 0x25, 0xf9, 0x55, 0xfd, 0x97, 0xff, -0xaf, 0x06, 0x25, 0xfb, 0x55, 0x05, 0x27, 0xff, -0x96, 0xc6, 0x2e, 0x01, 0xdf, 0xbf, 0x2c, 0xdd, -0x9f, 0x05, 0x27, 0xc6, 0x2e, 0x28, 0xdf, 0x0f, -0x1d, 0x04, 0x55, 0x0b, 0x88, 0xff, 0x96, 0x10, -0xef, 0xdf, 0x96, 0x06, 0x50, 0x06, 0x88, 0x3f, -0x20, 0xff, 0x96, 0xc6, 0x2e + 0x42, 0xca, 0x00, + 0x44, 0x29, 0x46, 0x2e, 0x28, + 0xdf, 0xc6, 0x2e, 0x29, 0xdf, 0x13, 0x10, 0x00, + 0x13, 0xff, 0xaf, 0xff, 0xbf, 0xe3, 0x97, 0xff, + 0xaf, 0xe4, 0x97, 0xff, 0xaf, 0xe5, 0x97, 0xff, + 0xaf, 0xef, 0x88, 0x06, 0x0d, 0xdd, 0x97, 0xdd, + 0x9f, 0x46, 0x2e, 0x28, 0xdf, 0xc6, 0x2e, 0x29, + 0xdf, 0x06, 0xaf, 0x4e, 0xbf, 0xff, 0x22, 0x11, + 0x54, 0x15, 0x27, 0x1a, 0x27, 0x01, 0xff, 0xab, + 0xef, 0x19, 0x27, 0xdc, 0x97, 0xdf, 0x99, 0x28, + 0x28, 0x0f, 0x27, 0x68, 0x2c, 0xfd, 0x5b, 0xe9, + 0x97, 0xff, 0xaf, 0x6a, 0x28, 0x06, 0x25, 0xf4, + 0x53, 0x4e, 0x25, 0xf2, 0x55, 0xdc, 0x97, 0xdf, + 0x99, 0x28, 0x28, 0x0f, 0x27, 0x68, 0x2c, 0xfd, + 0x5b, 0xe9, 0x97, 0xff, 0xaf, 0x6a, 0x28, 0x06, + 0x25, 0xf4, 0x55, 0x41, 0x2e, 0xaf, 0xdf, 0xdf, + 0x2b, 0x41, 0x2e, 0xaf, 0xbf, 0xbf, 0x22, 0xbf, + 0x99, 0x7f, 0x99, 0x05, 0x27, 0xdd, 0x97, 0xdd, + 0x9f, 0x06, 0xaf, 0x4e, 0xbf, 0xff, 0x22, 0x05, + 0x54, 0xfd, 0x97, 0xff, 0xaf, 0x06, 0x25, 0xfb, + 0x53, 0x4e, 0x25, 0xf9, 0x55, 0xfd, 0x97, 0xff, + 0xaf, 0x06, 0x25, 0xfb, 0x55, 0x05, 0x27, 0xff, + 0x96, 0xc6, 0x2e, 0x01, 0xdf, 0xbf, 0x2c, 0xdd, + 0x9f, 0x05, 0x27, 0xc6, 0x2e, 0x28, 0xdf, 0x0f, + 0x1d, 0x04, 0x55, 0x0b, 0x88, 0xff, 0x96, 0x10, + 0xef, 0xdf, 0x96, 0x06, 0x50, 0x06, 0x88, 0x3f, + 0x20, 0xff, 0x96, 0xc6, 0x2e }; static const unsigned char pkt224[] = { -0x42, 0xca, 0x00, -0xa8, 0x29, 0x28, 0xdf, 0x0f, -0x1d, 0xff, 0x96, 0x05, 0x27, 0x46, 0x2e, 0x28, -0xdf, 0xf0, 0x1c, 0x09, 0x27, 0xdf, 0x9f, 0x46, -0x2e, 0x29, 0xdf, 0x0f, 0x1c, 0x09, 0x27, 0x5f, -0x02, 0x05, 0x27, 0x78, 0x88, 0x6f, 0x88, 0x0a, -0xef, 0xdc, 0x9f, 0x3f, 0x9f, 0x5f, 0x20, 0xfb, -0x55, 0x05, 0x27, 0x9f, 0x22, 0x41, 0x2e, 0xab, -0xbf, 0x50, 0xef, 0xdf, 0x96, 0x3a, 0xef, 0xdf, -0x96, 0x29, 0x88, 0x68, 0x88, 0x0a, 0xef, 0xfc, -0x9f, 0xc1, 0x2e, 0xad, 0xbf, 0xc1, 0x2e, 0xac, -0xdf, 0x3f, 0x20, 0xc1, 0x2e, 0xac, 0xbf, 0x6a, -0x88, 0x5f, 0x20, 0xf4, 0x55, 0x5b, 0xef, 0xdf, -0x96, 0x50, 0xcf, 0xdf, 0x96, 0x17, 0x88, 0x5c, -0xef, 0xdf, 0x96, 0x4f, 0xcf, 0xdf, 0x96, 0x12, -0x88, 0x5d, 0xef, 0xdf, 0x96, 0x9f, 0x22, 0xdf, -0x96, 0x0d, 0x88, 0x5e, 0xef, 0xdf, 0x96, 0x46, -0x2e, 0x29, 0xdf, 0xdf, 0x96, 0x07, 0x88, 0x5f, -0xef, 0xdf, 0x96, 0x46, 0x2e, 0x28, 0xdf, 0xdf, -0x96, 0x01, 0x88, 0x0f, 0x27, 0x05, 0x27, 0xdd, -0x97, 0x41, 0x2e, 0xad, 0xbf, 0xdd, 0x97, 0x41, -0x2e, 0xac, 0xbf, 0x44, 0x88, 0x05, 0x27, 0x9f, -0x22, 0x41, 0x2e, 0xab, 0xbf, 0x10, 0xef, 0xdf, -0x96, 0x02, 0xef, 0xdf, 0x96, 0xef, 0x8f, 0x2e, -0x88, 0x0a, 0xef, 0xfc, 0x9f, 0xc1, 0x2e, 0xad, -0xbf, 0xc1, 0x2e, 0xac, 0xdf, 0x3f, 0x20, 0xc1, -0x2e, 0xac, 0xbf, 0x30, 0x88 + 0x42, 0xca, 0x00, + 0xa8, 0x29, 0x28, 0xdf, 0x0f, + 0x1d, 0xff, 0x96, 0x05, 0x27, 0x46, 0x2e, 0x28, + 0xdf, 0xf0, 0x1c, 0x09, 0x27, 0xdf, 0x9f, 0x46, + 0x2e, 0x29, 0xdf, 0x0f, 0x1c, 0x09, 0x27, 0x5f, + 0x02, 0x05, 0x27, 0x78, 0x88, 0x6f, 0x88, 0x0a, + 0xef, 0xdc, 0x9f, 0x3f, 0x9f, 0x5f, 0x20, 0xfb, + 0x55, 0x05, 0x27, 0x9f, 0x22, 0x41, 0x2e, 0xab, + 0xbf, 0x50, 0xef, 0xdf, 0x96, 0x3a, 0xef, 0xdf, + 0x96, 0x29, 0x88, 0x68, 0x88, 0x0a, 0xef, 0xfc, + 0x9f, 0xc1, 0x2e, 0xad, 0xbf, 0xc1, 0x2e, 0xac, + 0xdf, 0x3f, 0x20, 0xc1, 0x2e, 0xac, 0xbf, 0x6a, + 0x88, 0x5f, 0x20, 0xf4, 0x55, 0x5b, 0xef, 0xdf, + 0x96, 0x50, 0xcf, 0xdf, 0x96, 0x17, 0x88, 0x5c, + 0xef, 0xdf, 0x96, 0x4f, 0xcf, 0xdf, 0x96, 0x12, + 0x88, 0x5d, 0xef, 0xdf, 0x96, 0x9f, 0x22, 0xdf, + 0x96, 0x0d, 0x88, 0x5e, 0xef, 0xdf, 0x96, 0x46, + 0x2e, 0x29, 0xdf, 0xdf, 0x96, 0x07, 0x88, 0x5f, + 0xef, 0xdf, 0x96, 0x46, 0x2e, 0x28, 0xdf, 0xdf, + 0x96, 0x01, 0x88, 0x0f, 0x27, 0x05, 0x27, 0xdd, + 0x97, 0x41, 0x2e, 0xad, 0xbf, 0xdd, 0x97, 0x41, + 0x2e, 0xac, 0xbf, 0x44, 0x88, 0x05, 0x27, 0x9f, + 0x22, 0x41, 0x2e, 0xab, 0xbf, 0x10, 0xef, 0xdf, + 0x96, 0x02, 0xef, 0xdf, 0x96, 0xef, 0x8f, 0x2e, + 0x88, 0x0a, 0xef, 0xfc, 0x9f, 0xc1, 0x2e, 0xad, + 0xbf, 0xc1, 0x2e, 0xac, 0xdf, 0x3f, 0x20, 0xc1, + 0x2e, 0xac, 0xbf, 0x30, 0x88 }; static const unsigned char pkt228[] = { -0x42, 0x9a, 0x00, -0x0c, 0x2a, 0x5f, 0x20, 0xf4, -0x55, 0x1b, 0xef, 0xdf, 0x96, 0x50, 0xcf, 0xdf, -0x96, 0xdd, 0x8f, 0x1c, 0xef, 0xdf, 0x96, 0x4f, -0xcf, 0xdf, 0x96, 0xd8, 0x8f, 0x1d, 0xef, 0xdf, -0x96, 0x9f, 0x22, 0xdf, 0x96, 0xd3, 0x8f, 0x1e, -0xef, 0xdf, 0x96, 0x9f, 0x22, 0xdf, 0x96, 0xce, -0x8f, 0x1f, 0xef, 0xdf, 0x96, 0x01, 0xef, 0xdf, -0x96, 0xc9, 0x8f, 0x0f, 0x27, 0x05, 0x27, 0x02, -0xef, 0x06, 0xff, 0x1a, 0x27, 0x05, 0x27, 0x02, -0xef, 0x06, 0xff, 0x1a, 0x27, 0x05, 0x27, 0xdf, -0x96, 0xff, 0x96, 0x7b, 0xef, 0x00, 0xff, 0x1b, -0x27, 0xdd, 0x9f, 0xdd, 0x97, 0x05, 0x27, 0x01, -0xff, 0xab, 0xef, 0x1b, 0x27, 0x05, 0x27, 0xdf, -0x96, 0x81, 0xef, 0x41, 0x2e, 0xaf, 0xbf, 0xdd, -0x97, 0x05, 0x27, 0x3a, 0xef, 0xff, 0xaf, 0xea, -0x8f, 0x0a, 0xef, 0xfc, 0x9f, 0xff, 0xbf, 0x5f, -0x20, 0xfb, 0x55, 0x50, 0xcf, 0xff, 0xaf, 0x4f, -0xcf, 0xff, 0xaf, 0x9f, 0x22, 0xff, 0xaf, 0x46, -0x2e, 0x29, 0xdf, 0xff, 0xaf, 0x46, 0x2e, 0x28, -0xdf, 0xff, 0xaf, 0x05, 0x27 + 0x42, 0x9a, 0x00, + 0x0c, 0x2a, 0x5f, 0x20, 0xf4, + 0x55, 0x1b, 0xef, 0xdf, 0x96, 0x50, 0xcf, 0xdf, + 0x96, 0xdd, 0x8f, 0x1c, 0xef, 0xdf, 0x96, 0x4f, + 0xcf, 0xdf, 0x96, 0xd8, 0x8f, 0x1d, 0xef, 0xdf, + 0x96, 0x9f, 0x22, 0xdf, 0x96, 0xd3, 0x8f, 0x1e, + 0xef, 0xdf, 0x96, 0x9f, 0x22, 0xdf, 0x96, 0xce, + 0x8f, 0x1f, 0xef, 0xdf, 0x96, 0x01, 0xef, 0xdf, + 0x96, 0xc9, 0x8f, 0x0f, 0x27, 0x05, 0x27, 0x02, + 0xef, 0x06, 0xff, 0x1a, 0x27, 0x05, 0x27, 0x02, + 0xef, 0x06, 0xff, 0x1a, 0x27, 0x05, 0x27, 0xdf, + 0x96, 0xff, 0x96, 0x7b, 0xef, 0x00, 0xff, 0x1b, + 0x27, 0xdd, 0x9f, 0xdd, 0x97, 0x05, 0x27, 0x01, + 0xff, 0xab, 0xef, 0x1b, 0x27, 0x05, 0x27, 0xdf, + 0x96, 0x81, 0xef, 0x41, 0x2e, 0xaf, 0xbf, 0xdd, + 0x97, 0x05, 0x27, 0x3a, 0xef, 0xff, 0xaf, 0xea, + 0x8f, 0x0a, 0xef, 0xfc, 0x9f, 0xff, 0xbf, 0x5f, + 0x20, 0xfb, 0x55, 0x50, 0xcf, 0xff, 0xaf, 0x4f, + 0xcf, 0xff, 0xaf, 0x9f, 0x22, 0xff, 0xaf, 0x46, + 0x2e, 0x29, 0xdf, 0xff, 0xaf, 0x46, 0x2e, 0x28, + 0xdf, 0xff, 0xaf, 0x05, 0x27 }; static const unsigned char pkt232[] = { -0x42, 0x18, 0x00, -0x58, 0x2a, 0xd3, 0x45, 0x03, -0x5a, 0x0f, 0x27, 0xd3, 0x45, 0x00, 0x5a, 0x05, -0x27, 0xd0, 0x41, 0xf7, 0x5b, 0xc1, 0x83, 0xf5, -0x50, 0x05, 0x27 + 0x42, 0x18, 0x00, + 0x58, 0x2a, 0xd3, 0x45, 0x03, + 0x5a, 0x0f, 0x27, 0xd3, 0x45, 0x00, 0x5a, 0x05, + 0x27, 0xd0, 0x41, 0xf7, 0x5b, 0xc1, 0x83, 0xf5, + 0x50, 0x05, 0x27 }; static const unsigned char pkt236[] = { -0x42, 0x22, 0x00, -0x63, 0x2a, 0xc8, 0x46, 0x0c, -0x5b, 0xd3, 0x45, 0xfd, 0x5a, 0xd3, 0x45, 0xfb, -0x5a, 0xd3, 0x45, 0xf9, 0x5a, 0x41, 0x2e, 0xa1, -0xdf, 0x9f, 0x28, 0x41, 0x2e, 0xa1, 0xbf, 0x02, -0x2e, 0xdd, 0x81, 0x05, 0x27 + 0x42, 0x22, 0x00, + 0x63, 0x2a, 0xc8, 0x46, 0x0c, + 0x5b, 0xd3, 0x45, 0xfd, 0x5a, 0xd3, 0x45, 0xfb, + 0x5a, 0xd3, 0x45, 0xf9, 0x5a, 0x41, 0x2e, 0xa1, + 0xdf, 0x9f, 0x28, 0x41, 0x2e, 0xa1, 0xbf, 0x02, + 0x2e, 0xdd, 0x81, 0x05, 0x27 }; static const unsigned char pkt240[] = { -0x42, 0x50, 0x00, -0x73, 0x2a, 0x07, 0x3d, 0x02, -0x5b, 0x6c, 0x86, 0xc2, 0x23, 0xd3, 0x3c, 0x02, -0x44, 0xd8, 0x2f, 0x1d, 0x5a, 0x02, 0x45, 0xd8, -0x2f, 0x7e, 0x5b, 0x58, 0x23, 0x3c, 0x26, 0x02, -0x55, 0x02, 0x2e, 0x31, 0x84, 0x01, 0x50, 0x02, -0x2e, 0x80, 0x84, 0x07, 0x45, 0xea, 0x5a, 0x41, -0x2e, 0x53, 0xdf, 0xc1, 0x2e, 0x79, 0xdf, 0xff, -0x96, 0xdf, 0x96, 0x41, 0x2e, 0x55, 0xdf, 0xc1, -0x2e, 0x78, 0xdf, 0x9d, 0x01, 0x5d, 0x01, 0xff, -0x22, 0x00, 0x54, 0xff, 0xef, 0x2e, 0xaf, 0xd8, -0x2f, 0x62, 0x50 + 0x42, 0x50, 0x00, + 0x73, 0x2a, 0x07, 0x3d, 0x02, + 0x5b, 0x6c, 0x86, 0xc2, 0x23, 0xd3, 0x3c, 0x02, + 0x44, 0xd8, 0x2f, 0x1d, 0x5a, 0x02, 0x45, 0xd8, + 0x2f, 0x7e, 0x5b, 0x58, 0x23, 0x3c, 0x26, 0x02, + 0x55, 0x02, 0x2e, 0x31, 0x84, 0x01, 0x50, 0x02, + 0x2e, 0x80, 0x84, 0x07, 0x45, 0xea, 0x5a, 0x41, + 0x2e, 0x53, 0xdf, 0xc1, 0x2e, 0x79, 0xdf, 0xff, + 0x96, 0xdf, 0x96, 0x41, 0x2e, 0x55, 0xdf, 0xc1, + 0x2e, 0x78, 0xdf, 0x9d, 0x01, 0x5d, 0x01, 0xff, + 0x22, 0x00, 0x54, 0xff, 0xef, 0x2e, 0xaf, 0xd8, + 0x2f, 0x62, 0x50 }; static const unsigned char pkt244[] = { -0x67, 0x05, 0x00, 0x00, 0x02, 0x2e, 0x00, 0x70, -0x67, 0x05, 0x00, 0x01, 0x02, 0x2e, 0xe5, 0x71, -0x67, 0x05, 0x00, 0x02, 0x02, 0x2e, 0xa9, 0x72, -0x67, 0x05, 0x00, 0x08, 0x02, 0x2e, 0xb4, 0x73, -0x67, 0x05, 0x00, 0x07, 0x02, 0x2e, 0x29, 0x74, -0x67, 0x05, 0x00, 0x0d, 0x02, 0x2e, 0x26, 0x75, -0x67, 0x05, 0x00, 0x03, 0x02, 0x2e, 0x4d, 0x75, -0x67, 0x05, 0x00, 0x0e, 0x02, 0x2e, 0x29, 0x77, -0x5a, 0x05, 0x00, 0x00, 0xaa, 0x08, 0x67, 0x27, -0x5a, 0x05, 0x00, 0x01, 0xf4, 0x08, 0xfd, 0x27, -0x67, 0x05, 0x00, 0x09, 0x02, 0x2e, 0xe0, 0x78, -0x5a, 0x05, 0x00, 0x02, 0x82, 0x09, 0x58, 0x2a, -0x5a, 0x05, 0x00, 0x03, 0x78, 0x09, 0x63, 0x2a, -0x5a, 0x05, 0x00, 0x04, 0xe1, 0x02, 0x73, 0x2a, -0x0d, -0x42, 0x04, 0x00, 0x73, 0x2a, 0x07, 0x3d + 0x67, 0x05, 0x00, 0x00, 0x02, 0x2e, 0x00, 0x70, + 0x67, 0x05, 0x00, 0x01, 0x02, 0x2e, 0xe5, 0x71, + 0x67, 0x05, 0x00, 0x02, 0x02, 0x2e, 0xa9, 0x72, + 0x67, 0x05, 0x00, 0x08, 0x02, 0x2e, 0xb4, 0x73, + 0x67, 0x05, 0x00, 0x07, 0x02, 0x2e, 0x29, 0x74, + 0x67, 0x05, 0x00, 0x0d, 0x02, 0x2e, 0x26, 0x75, + 0x67, 0x05, 0x00, 0x03, 0x02, 0x2e, 0x4d, 0x75, + 0x67, 0x05, 0x00, 0x0e, 0x02, 0x2e, 0x29, 0x77, + 0x5a, 0x05, 0x00, 0x00, 0xaa, 0x08, 0x67, 0x27, + 0x5a, 0x05, 0x00, 0x01, 0xf4, 0x08, 0xfd, 0x27, + 0x67, 0x05, 0x00, 0x09, 0x02, 0x2e, 0xe0, 0x78, + 0x5a, 0x05, 0x00, 0x02, 0x82, 0x09, 0x58, 0x2a, + 0x5a, 0x05, 0x00, 0x03, 0x78, 0x09, 0x63, 0x2a, + 0x5a, 0x05, 0x00, 0x04, 0xe1, 0x02, 0x73, 0x2a, + 0x0d, + 0x42, 0x04, 0x00, 0x73, 0x2a, 0x07, 0x3d }; struct aesX660_cmd aes1660_init_1[] = { - { .cmd = pkt107, .len = sizeof(pkt107) }, - { .cmd = pkt112, .len = sizeof(pkt112) }, - { .cmd = pkt116, .len = sizeof(pkt116) }, - { .cmd = pkt120, .len = sizeof(pkt120) }, - { .cmd = pkt124, .len = sizeof(pkt124) }, - { .cmd = pkt128, .len = sizeof(pkt128) }, - { .cmd = pkt133, .len = sizeof(pkt133) }, - { .cmd = pkt136, .len = sizeof(pkt136) }, - { .cmd = pkt140, .len = sizeof(pkt140) }, - { .cmd = pkt144, .len = sizeof(pkt144) }, - { .cmd = pkt148, .len = sizeof(pkt148) }, - { .cmd = pkt152, .len = sizeof(pkt152) }, - { .cmd = pkt156, .len = sizeof(pkt156) }, - { .cmd = pkt160, .len = sizeof(pkt160) }, - { .cmd = pkt164, .len = sizeof(pkt164) }, - { .cmd = pkt168, .len = sizeof(pkt168) }, - { .cmd = pkt172, .len = sizeof(pkt172) }, - { .cmd = pkt176, .len = sizeof(pkt176) }, - { .cmd = pkt180, .len = sizeof(pkt180) }, - { .cmd = pkt184, .len = sizeof(pkt184) }, - { .cmd = pkt188, .len = sizeof(pkt188) }, - { .cmd = pkt192, .len = sizeof(pkt192) }, - { .cmd = pkt196, .len = sizeof(pkt196) }, - { .cmd = pkt200, .len = sizeof(pkt200) }, - { .cmd = pkt204, .len = sizeof(pkt204) }, - { .cmd = pkt208, .len = sizeof(pkt208) }, - { .cmd = pkt212, .len = sizeof(pkt212) }, - { .cmd = pkt216, .len = sizeof(pkt216) }, - { .cmd = pkt220, .len = sizeof(pkt220) }, - { .cmd = pkt224, .len = sizeof(pkt224) }, - { .cmd = pkt228, .len = sizeof(pkt228) }, - { .cmd = pkt232, .len = sizeof(pkt232) }, - { .cmd = pkt236, .len = sizeof(pkt236) }, - { .cmd = pkt240, .len = sizeof(pkt240) }, - { .cmd = pkt244, .len = sizeof(pkt244) }, + { .cmd = pkt107, .len = sizeof (pkt107) }, + { .cmd = pkt112, .len = sizeof (pkt112) }, + { .cmd = pkt116, .len = sizeof (pkt116) }, + { .cmd = pkt120, .len = sizeof (pkt120) }, + { .cmd = pkt124, .len = sizeof (pkt124) }, + { .cmd = pkt128, .len = sizeof (pkt128) }, + { .cmd = pkt133, .len = sizeof (pkt133) }, + { .cmd = pkt136, .len = sizeof (pkt136) }, + { .cmd = pkt140, .len = sizeof (pkt140) }, + { .cmd = pkt144, .len = sizeof (pkt144) }, + { .cmd = pkt148, .len = sizeof (pkt148) }, + { .cmd = pkt152, .len = sizeof (pkt152) }, + { .cmd = pkt156, .len = sizeof (pkt156) }, + { .cmd = pkt160, .len = sizeof (pkt160) }, + { .cmd = pkt164, .len = sizeof (pkt164) }, + { .cmd = pkt168, .len = sizeof (pkt168) }, + { .cmd = pkt172, .len = sizeof (pkt172) }, + { .cmd = pkt176, .len = sizeof (pkt176) }, + { .cmd = pkt180, .len = sizeof (pkt180) }, + { .cmd = pkt184, .len = sizeof (pkt184) }, + { .cmd = pkt188, .len = sizeof (pkt188) }, + { .cmd = pkt192, .len = sizeof (pkt192) }, + { .cmd = pkt196, .len = sizeof (pkt196) }, + { .cmd = pkt200, .len = sizeof (pkt200) }, + { .cmd = pkt204, .len = sizeof (pkt204) }, + { .cmd = pkt208, .len = sizeof (pkt208) }, + { .cmd = pkt212, .len = sizeof (pkt212) }, + { .cmd = pkt216, .len = sizeof (pkt216) }, + { .cmd = pkt220, .len = sizeof (pkt220) }, + { .cmd = pkt224, .len = sizeof (pkt224) }, + { .cmd = pkt228, .len = sizeof (pkt228) }, + { .cmd = pkt232, .len = sizeof (pkt232) }, + { .cmd = pkt236, .len = sizeof (pkt236) }, + { .cmd = pkt240, .len = sizeof (pkt240) }, + { .cmd = pkt244, .len = sizeof (pkt244) }, }; /* INIT1 is over, 0x07 cmd returns @@ -944,1034 +944,1034 @@ struct aesX660_cmd aes1660_init_1[] = { /* Second init sequence * INIT2 */ static const unsigned char pkt433[] = { -0x0d, -0x23, -0x42, 0xca, 0x00, -0x00, 0x20, 0x23, -0xff, 0x3f, 0x1d, 0x40, 0x19, 0xc1, 0x2e, 0xa3, -0xbf, 0xc2, 0x2e, 0x00, 0xdf, 0xff, 0x2d, 0x02, -0x5a, 0xbf, 0x22, 0xc1, 0x2e, 0xa3, 0xbf, 0x02, -0xcf, 0x0f, 0x1c, 0x10, 0x18, 0x26, 0x83, 0xc8, -0x46, 0x00, 0x5b, 0x01, 0x0c, 0x57, 0x23, 0x3c, -0x23, 0xf9, 0x34, 0x6b, 0x81, 0x64, 0xef, 0x64, -0xaf, 0xdf, 0xef, 0x27, 0xff, 0xd6, 0xaf, 0xd7, -0xbf, 0x46, 0xef, 0x46, 0xaf, 0x2a, 0xef, 0x2a, -0xaf, 0x05, 0x81, 0x05, 0x27, 0x9c, 0xcf, 0xdf, -0x96, 0xfe, 0xef, 0x27, 0xff, 0x19, 0x27, 0x65, -0xdf, 0xe1, 0x22, 0x1c, 0x55, 0xe0, 0x97, 0xbf, -0x03, 0x19, 0x5e, 0xfe, 0x0c, 0x9f, 0x22, 0x0f, -0xff, 0xe1, 0x22, 0x10, 0x55, 0x20, 0x00, 0x0e, -0x52, 0x82, 0x03, 0x03, 0x53, 0xfe, 0x0d, 0x7f, -0x20, 0xf6, 0x55, 0x08, 0x50, 0x5f, 0x90, 0x82, -0x01, 0x1f, 0x90, 0xc1, 0x97, 0xa0, 0x01, 0x82, -0x01, 0xdf, 0x21, 0x80, 0x03, 0x00, 0x5e, 0x3f, -0x20, 0x29, 0xbf, 0x03, 0x0c, 0x05, 0x27, 0x01, -0x0c, 0x10, 0xff, 0x29, 0xbf, 0x05, 0x27, 0x9a, -0xcf, 0xdf, 0x96, 0xe0, 0xef, 0x27, 0xff, 0x19, -0x27, 0xfe, 0x0c, 0x9f, 0x22, 0x00, 0xff, 0xe1, -0x22, 0x10, 0x55, 0x20, 0x00, 0x0e, 0x52, 0x82, -0x03, 0x03, 0x53, 0x02, 0x0d, 0x3f, 0x20, 0x0f, -0x1f, 0xf5, 0x55, 0x5f, 0x90, 0x82, 0x01, 0x1f, -0x90, 0xc1, 0x97, 0xa0, 0x01, 0x82, 0x01 + 0x0d, + 0x23, + 0x42, 0xca, 0x00, + 0x00, 0x20, 0x23, + 0xff, 0x3f, 0x1d, 0x40, 0x19, 0xc1, 0x2e, 0xa3, + 0xbf, 0xc2, 0x2e, 0x00, 0xdf, 0xff, 0x2d, 0x02, + 0x5a, 0xbf, 0x22, 0xc1, 0x2e, 0xa3, 0xbf, 0x02, + 0xcf, 0x0f, 0x1c, 0x10, 0x18, 0x26, 0x83, 0xc8, + 0x46, 0x00, 0x5b, 0x01, 0x0c, 0x57, 0x23, 0x3c, + 0x23, 0xf9, 0x34, 0x6b, 0x81, 0x64, 0xef, 0x64, + 0xaf, 0xdf, 0xef, 0x27, 0xff, 0xd6, 0xaf, 0xd7, + 0xbf, 0x46, 0xef, 0x46, 0xaf, 0x2a, 0xef, 0x2a, + 0xaf, 0x05, 0x81, 0x05, 0x27, 0x9c, 0xcf, 0xdf, + 0x96, 0xfe, 0xef, 0x27, 0xff, 0x19, 0x27, 0x65, + 0xdf, 0xe1, 0x22, 0x1c, 0x55, 0xe0, 0x97, 0xbf, + 0x03, 0x19, 0x5e, 0xfe, 0x0c, 0x9f, 0x22, 0x0f, + 0xff, 0xe1, 0x22, 0x10, 0x55, 0x20, 0x00, 0x0e, + 0x52, 0x82, 0x03, 0x03, 0x53, 0xfe, 0x0d, 0x7f, + 0x20, 0xf6, 0x55, 0x08, 0x50, 0x5f, 0x90, 0x82, + 0x01, 0x1f, 0x90, 0xc1, 0x97, 0xa0, 0x01, 0x82, + 0x01, 0xdf, 0x21, 0x80, 0x03, 0x00, 0x5e, 0x3f, + 0x20, 0x29, 0xbf, 0x03, 0x0c, 0x05, 0x27, 0x01, + 0x0c, 0x10, 0xff, 0x29, 0xbf, 0x05, 0x27, 0x9a, + 0xcf, 0xdf, 0x96, 0xe0, 0xef, 0x27, 0xff, 0x19, + 0x27, 0xfe, 0x0c, 0x9f, 0x22, 0x00, 0xff, 0xe1, + 0x22, 0x10, 0x55, 0x20, 0x00, 0x0e, 0x52, 0x82, + 0x03, 0x03, 0x53, 0x02, 0x0d, 0x3f, 0x20, 0x0f, + 0x1f, 0xf5, 0x55, 0x5f, 0x90, 0x82, 0x01, 0x1f, + 0x90, 0xc1, 0x97, 0xa0, 0x01, 0x82, 0x01 }; static const unsigned char pkt440[] = { -0x42, 0xca, 0x00, -0x64, 0x20, 0xdf, 0x21, 0x80, -0x03, 0x02, 0x5e, 0x7f, 0x20, 0x00, 0x53, 0xbf, -0x22, 0x29, 0xcf, 0xbf, 0x03, 0x01, 0x5e, 0x5f, -0x20, 0xdf, 0x9f, 0x28, 0xbf, 0x03, 0x0c, 0x05, -0x27, 0x24, 0xcf, 0x10, 0xdf, 0xbf, 0x01, 0x06, -0x1e, 0xe2, 0x2f, 0x13, 0x5c, 0xdf, 0x2d, 0x00, -0x5b, 0x9f, 0x22, 0xdf, 0x96, 0x9b, 0xef, 0x20, -0xff, 0x1d, 0x00, 0x00, 0x13, 0x1a, 0x27, 0x07, -0x27, 0x9b, 0x22, 0xdf, 0x96, 0xbb, 0xcf, 0x1a, -0x88, 0xbb, 0xcf, 0x1b, 0x88, 0x01, 0x0f, 0xbc, -0xcf, 0x15, 0x88, 0xbc, 0xcf, 0x16, 0x88, 0x01, -0x0f, 0xbd, 0xcf, 0x10, 0x88, 0xbd, 0xcf, 0x11, -0x88, 0x01, 0x0f, 0xbe, 0xcf, 0x0b, 0x88, 0xbe, -0xcf, 0x0c, 0x88, 0x01, 0x0c, 0xdd, 0x97, 0x25, -0xaf, 0x05, 0x27, 0xff, 0x00, 0xab, 0x00, 0x72, -0x00, 0x4c, 0x00, 0x33, 0x00, 0x22, 0x00, 0x09, -0x88, 0xbf, 0x9d, 0x05, 0x27, 0x09, 0x27, 0x05, -0x88, 0xff, 0x97, 0x09, 0x27, 0xf6, 0x9f, 0x5f, -0x02, 0xbf, 0x9d, 0x05, 0x27, 0x0f, 0x1c, 0xc0, -0x9f, 0x8a, 0x80, 0x80, 0x10, 0x00, 0x13, 0x0f, -0x1d, 0xc1, 0x03, 0x00, 0x5f, 0x7f, 0x90, 0x05, -0x27, 0x53, 0x80, 0x2b, 0x0d, 0x05, 0x27, 0x9f, -0x22, 0x8f, 0xaf, 0x67, 0x2e, 0xe0, 0xdf, 0x04, -0x1e, 0x00, 0x52, 0x8f, 0x30, 0x67, 0x2e, 0xe1, -0xdf, 0xdf, 0x22, 0x00, 0x54, 0x8f, 0x30, 0x67, -0x2e, 0xfe, 0xdf, 0x04, 0x1e + 0x42, 0xca, 0x00, + 0x64, 0x20, 0xdf, 0x21, 0x80, + 0x03, 0x02, 0x5e, 0x7f, 0x20, 0x00, 0x53, 0xbf, + 0x22, 0x29, 0xcf, 0xbf, 0x03, 0x01, 0x5e, 0x5f, + 0x20, 0xdf, 0x9f, 0x28, 0xbf, 0x03, 0x0c, 0x05, + 0x27, 0x24, 0xcf, 0x10, 0xdf, 0xbf, 0x01, 0x06, + 0x1e, 0xe2, 0x2f, 0x13, 0x5c, 0xdf, 0x2d, 0x00, + 0x5b, 0x9f, 0x22, 0xdf, 0x96, 0x9b, 0xef, 0x20, + 0xff, 0x1d, 0x00, 0x00, 0x13, 0x1a, 0x27, 0x07, + 0x27, 0x9b, 0x22, 0xdf, 0x96, 0xbb, 0xcf, 0x1a, + 0x88, 0xbb, 0xcf, 0x1b, 0x88, 0x01, 0x0f, 0xbc, + 0xcf, 0x15, 0x88, 0xbc, 0xcf, 0x16, 0x88, 0x01, + 0x0f, 0xbd, 0xcf, 0x10, 0x88, 0xbd, 0xcf, 0x11, + 0x88, 0x01, 0x0f, 0xbe, 0xcf, 0x0b, 0x88, 0xbe, + 0xcf, 0x0c, 0x88, 0x01, 0x0c, 0xdd, 0x97, 0x25, + 0xaf, 0x05, 0x27, 0xff, 0x00, 0xab, 0x00, 0x72, + 0x00, 0x4c, 0x00, 0x33, 0x00, 0x22, 0x00, 0x09, + 0x88, 0xbf, 0x9d, 0x05, 0x27, 0x09, 0x27, 0x05, + 0x88, 0xff, 0x97, 0x09, 0x27, 0xf6, 0x9f, 0x5f, + 0x02, 0xbf, 0x9d, 0x05, 0x27, 0x0f, 0x1c, 0xc0, + 0x9f, 0x8a, 0x80, 0x80, 0x10, 0x00, 0x13, 0x0f, + 0x1d, 0xc1, 0x03, 0x00, 0x5f, 0x7f, 0x90, 0x05, + 0x27, 0x53, 0x80, 0x2b, 0x0d, 0x05, 0x27, 0x9f, + 0x22, 0x8f, 0xaf, 0x67, 0x2e, 0xe0, 0xdf, 0x04, + 0x1e, 0x00, 0x52, 0x8f, 0x30, 0x67, 0x2e, 0xe1, + 0xdf, 0xdf, 0x22, 0x00, 0x54, 0x8f, 0x30, 0x67, + 0x2e, 0xfe, 0xdf, 0x04, 0x1e }; static const unsigned char pkt444[] = { -0x42, 0xca, 0x00, -0xc8, 0x20, 0x00, 0x52, 0x8f, -0x31, 0x67, 0x2e, 0xff, 0xdf, 0xdf, 0x22, 0x00, -0x54, 0x8f, 0x31, 0x8f, 0xcf, 0x03, 0x1c, 0x03, -0x1e, 0x00, 0x55, 0x0c, 0x27, 0x0d, 0x27, 0x4a, -0xcf, 0xdf, 0x96, 0x10, 0xcf, 0x5f, 0xdf, 0xbf, -0x03, 0x02, 0x5f, 0x5f, 0xcf, 0x10, 0xaf, 0x04, -0x50, 0x5e, 0xdf, 0xbf, 0x03, 0x01, 0x53, 0x5e, -0xcf, 0x10, 0xaf, 0x46, 0x88, 0x01, 0x2e, 0x1e, -0x80, 0xdd, 0x97, 0x0a, 0x40, 0x1c, 0x5a, 0x37, -0x43, 0x0b, 0x5b, 0xe2, 0xcf, 0x0f, 0x1c, 0x06, -0x1e, 0x07, 0x52, 0x62, 0xdf, 0x18, 0x1f, 0x07, -0x53, 0x04, 0x16, 0xe2, 0xaf, 0x04, 0x11, 0x62, -0xbf, 0x02, 0x50, 0x62, 0xcf, 0xdf, 0x22, 0x0e, -0x54, 0x0e, 0x88, 0x62, 0xdf, 0xbf, 0x03, 0x04, -0x53, 0x62, 0xaf, 0xdf, 0x01, 0xe2, 0xcf, 0x3f, -0x00, 0xe2, 0xaf, 0x0e, 0x88, 0x4a, 0xdf, 0x3f, -0x00, 0x4a, 0xaf, 0x00, 0x2e, 0xc4, 0x8d, 0x05, -0x27, 0xff, 0xef, 0x4a, 0xdf, 0xbf, 0x01, 0x0a, -0x88, 0xa1, 0x27, 0x5f, 0x21, 0x7f, 0x20, 0xfb, -0x55, 0x05, 0x27, 0x62, 0xcf, 0x03, 0x88, 0x1f, -0x22, 0x7f, 0x20, 0xfc, 0x55, 0x05, 0x27, 0x10, -0xdf, 0x02, 0x1f, 0x02, 0x5e, 0x04, 0xff, 0x00, -0x2e, 0x0a, 0x50, 0x05, 0x1f, 0x02, 0x5e, 0x03, -0xff, 0x00, 0x2e, 0x05, 0x50, 0x06, 0x1f, 0x02, -0x5e, 0x02, 0xff, 0x00, 0x2e, 0x00, 0x50, 0x01, -0xff, 0x05, 0x27, 0x10, 0xcf + 0x42, 0xca, 0x00, + 0xc8, 0x20, 0x00, 0x52, 0x8f, + 0x31, 0x67, 0x2e, 0xff, 0xdf, 0xdf, 0x22, 0x00, + 0x54, 0x8f, 0x31, 0x8f, 0xcf, 0x03, 0x1c, 0x03, + 0x1e, 0x00, 0x55, 0x0c, 0x27, 0x0d, 0x27, 0x4a, + 0xcf, 0xdf, 0x96, 0x10, 0xcf, 0x5f, 0xdf, 0xbf, + 0x03, 0x02, 0x5f, 0x5f, 0xcf, 0x10, 0xaf, 0x04, + 0x50, 0x5e, 0xdf, 0xbf, 0x03, 0x01, 0x53, 0x5e, + 0xcf, 0x10, 0xaf, 0x46, 0x88, 0x01, 0x2e, 0x1e, + 0x80, 0xdd, 0x97, 0x0a, 0x40, 0x1c, 0x5a, 0x37, + 0x43, 0x0b, 0x5b, 0xe2, 0xcf, 0x0f, 0x1c, 0x06, + 0x1e, 0x07, 0x52, 0x62, 0xdf, 0x18, 0x1f, 0x07, + 0x53, 0x04, 0x16, 0xe2, 0xaf, 0x04, 0x11, 0x62, + 0xbf, 0x02, 0x50, 0x62, 0xcf, 0xdf, 0x22, 0x0e, + 0x54, 0x0e, 0x88, 0x62, 0xdf, 0xbf, 0x03, 0x04, + 0x53, 0x62, 0xaf, 0xdf, 0x01, 0xe2, 0xcf, 0x3f, + 0x00, 0xe2, 0xaf, 0x0e, 0x88, 0x4a, 0xdf, 0x3f, + 0x00, 0x4a, 0xaf, 0x00, 0x2e, 0xc4, 0x8d, 0x05, + 0x27, 0xff, 0xef, 0x4a, 0xdf, 0xbf, 0x01, 0x0a, + 0x88, 0xa1, 0x27, 0x5f, 0x21, 0x7f, 0x20, 0xfb, + 0x55, 0x05, 0x27, 0x62, 0xcf, 0x03, 0x88, 0x1f, + 0x22, 0x7f, 0x20, 0xfc, 0x55, 0x05, 0x27, 0x10, + 0xdf, 0x02, 0x1f, 0x02, 0x5e, 0x04, 0xff, 0x00, + 0x2e, 0x0a, 0x50, 0x05, 0x1f, 0x02, 0x5e, 0x03, + 0xff, 0x00, 0x2e, 0x05, 0x50, 0x06, 0x1f, 0x02, + 0x5e, 0x02, 0xff, 0x00, 0x2e, 0x00, 0x50, 0x01, + 0xff, 0x05, 0x27, 0x10, 0xcf }; static const unsigned char pkt448[] = { -0x42, 0xca, 0x00, -0x2c, 0x21, 0x33, 0xff, 0x3f, -0x00, 0x21, 0xff, 0x00, 0x13, 0x1a, 0x27, 0x07, -0x27, 0x05, 0x27, 0x01, 0x00, 0x02, 0x57, 0x42, -0x87, 0x52, 0x80, 0x92, 0x81, 0xd2, 0x6c, 0xe2, -0x80, 0xf2, 0x80, 0xf6, 0x7b, 0xfa, 0x7e, 0xfe, -0x8b, 0xf9, 0x45, 0x04, 0x5a, 0x40, 0xef, 0xf9, -0x44, 0x03, 0x5b, 0x80, 0xef, 0x01, 0x50, 0x41, -0x2e, 0x7e, 0xdf, 0x4d, 0xaf, 0x05, 0x27, 0x28, -0xff, 0x54, 0xef, 0x19, 0x27, 0x4d, 0x26, 0xe1, -0x2f, 0x28, 0x54, 0x27, 0xff, 0xe0, 0xef, 0x1b, -0x27, 0x10, 0xef, 0x06, 0xaf, 0xfc, 0x97, 0xfc, -0x9f, 0x1c, 0x82, 0x1c, 0x82, 0x1a, 0x27, 0x4d, -0xdf, 0x6d, 0x80, 0x5f, 0x9f, 0x06, 0x25, 0xf5, -0x55, 0x05, 0x27, 0x26, 0x1f, 0x00, 0x5f, 0xbf, -0x22, 0xff, 0x96, 0x6c, 0xef, 0x21, 0xff, 0x1d, -0x00, 0x00, 0x13, 0x1a, 0x27, 0x07, 0x27, 0x1a, -0x27, 0xd6, 0x97, 0x05, 0x27, 0xa3, 0x01, 0xa4, -0x01, 0xa3, 0x01, 0x2e, 0x00, 0xb0, 0x00, 0xb1, -0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb4, 0x00, 0xb5, -0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9, -0x00, 0xba, 0x00, 0x56, 0x00, 0xae, 0x00, 0x54, -0x01, 0x44, 0x01, 0x55, 0x01, 0x44, 0x01, 0xbb, -0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0x83, -0x00, 0x84, 0x00, 0x81, 0x00, 0x82, 0x00, 0x24, -0x00, 0x44, 0x01, 0xdb, 0x00, 0xdc, 0x00, 0xdd, -0x00, 0xde, 0x00, 0x04, 0x00 + 0x42, 0xca, 0x00, + 0x2c, 0x21, 0x33, 0xff, 0x3f, + 0x00, 0x21, 0xff, 0x00, 0x13, 0x1a, 0x27, 0x07, + 0x27, 0x05, 0x27, 0x01, 0x00, 0x02, 0x57, 0x42, + 0x87, 0x52, 0x80, 0x92, 0x81, 0xd2, 0x6c, 0xe2, + 0x80, 0xf2, 0x80, 0xf6, 0x7b, 0xfa, 0x7e, 0xfe, + 0x8b, 0xf9, 0x45, 0x04, 0x5a, 0x40, 0xef, 0xf9, + 0x44, 0x03, 0x5b, 0x80, 0xef, 0x01, 0x50, 0x41, + 0x2e, 0x7e, 0xdf, 0x4d, 0xaf, 0x05, 0x27, 0x28, + 0xff, 0x54, 0xef, 0x19, 0x27, 0x4d, 0x26, 0xe1, + 0x2f, 0x28, 0x54, 0x27, 0xff, 0xe0, 0xef, 0x1b, + 0x27, 0x10, 0xef, 0x06, 0xaf, 0xfc, 0x97, 0xfc, + 0x9f, 0x1c, 0x82, 0x1c, 0x82, 0x1a, 0x27, 0x4d, + 0xdf, 0x6d, 0x80, 0x5f, 0x9f, 0x06, 0x25, 0xf5, + 0x55, 0x05, 0x27, 0x26, 0x1f, 0x00, 0x5f, 0xbf, + 0x22, 0xff, 0x96, 0x6c, 0xef, 0x21, 0xff, 0x1d, + 0x00, 0x00, 0x13, 0x1a, 0x27, 0x07, 0x27, 0x1a, + 0x27, 0xd6, 0x97, 0x05, 0x27, 0xa3, 0x01, 0xa4, + 0x01, 0xa3, 0x01, 0x2e, 0x00, 0xb0, 0x00, 0xb1, + 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb4, 0x00, 0xb5, + 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9, + 0x00, 0xba, 0x00, 0x56, 0x00, 0xae, 0x00, 0x54, + 0x01, 0x44, 0x01, 0x55, 0x01, 0x44, 0x01, 0xbb, + 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0x83, + 0x00, 0x84, 0x00, 0x81, 0x00, 0x82, 0x00, 0x24, + 0x00, 0x44, 0x01, 0xdb, 0x00, 0xdc, 0x00, 0xdd, + 0x00, 0xde, 0x00, 0x04, 0x00 }; static const unsigned char pkt452[] = { -0x42, 0x52, 0x00, -0x90, 0x21, 0x9b, 0x00, 0x99, -0x00, 0x9e, 0x00, 0x10, 0xef, 0xe6, 0x81, 0x65, -0xaf, 0x10, 0xef, 0xe6, 0x81, 0x9c, 0xaf, 0x10, -0xef, 0xe6, 0x81, 0x9a, 0xaf, 0x05, 0x27, 0xe5, -0x31, 0x1d, 0x81, 0xe5, 0x39, 0x05, 0x27, 0xc8, -0x46, 0x0b, 0x5b, 0xd3, 0x45, 0xfd, 0x5a, 0xd3, -0x45, 0xfb, 0x5a, 0xd3, 0x45, 0xf9, 0x5a, 0x41, -0x2e, 0xa1, 0xdf, 0x9f, 0x28, 0x41, 0x2e, 0xa1, -0xbf, 0x00, 0x88, 0x05, 0x27, 0x9f, 0x22, 0xbf, -0x22, 0x1f, 0x20, 0xfd, 0x53, 0x3f, 0x20, 0x14, -0x1f, 0xfa, 0x55, 0x05, 0x27 + 0x42, 0x52, 0x00, + 0x90, 0x21, 0x9b, 0x00, 0x99, + 0x00, 0x9e, 0x00, 0x10, 0xef, 0xe6, 0x81, 0x65, + 0xaf, 0x10, 0xef, 0xe6, 0x81, 0x9c, 0xaf, 0x10, + 0xef, 0xe6, 0x81, 0x9a, 0xaf, 0x05, 0x27, 0xe5, + 0x31, 0x1d, 0x81, 0xe5, 0x39, 0x05, 0x27, 0xc8, + 0x46, 0x0b, 0x5b, 0xd3, 0x45, 0xfd, 0x5a, 0xd3, + 0x45, 0xfb, 0x5a, 0xd3, 0x45, 0xf9, 0x5a, 0x41, + 0x2e, 0xa1, 0xdf, 0x9f, 0x28, 0x41, 0x2e, 0xa1, + 0xbf, 0x00, 0x88, 0x05, 0x27, 0x9f, 0x22, 0xbf, + 0x22, 0x1f, 0x20, 0xfd, 0x53, 0x3f, 0x20, 0x14, + 0x1f, 0xfa, 0x55, 0x05, 0x27 }; static const unsigned char pkt456[] = { -0x42, 0xca, 0x00, -0xb8, 0x21, 0x25, 0x85, 0x01, -0x1e, 0x17, 0x55, 0x1b, 0x8a, 0x41, 0x2e, 0x53, -0xdf, 0xc1, 0x2e, 0x79, 0xdf, 0xff, 0x96, 0xdf, -0x96, 0x41, 0x2e, 0x55, 0xdf, 0xc1, 0x2e, 0x78, -0xdf, 0x9d, 0x01, 0x5d, 0x01, 0xff, 0x22, 0x00, -0x54, 0xff, 0xef, 0x2e, 0xaf, 0x05, 0x27, 0x07, -0x80, 0x9f, 0x22, 0xff, 0xaf, 0x00, 0x2e, 0x5d, -0x89, 0x05, 0x27, 0x06, 0x1e, 0x01, 0x55, 0x0f, -0x27, 0x01, 0x70, 0x0a, 0x1e, 0x0a, 0x55, 0x00, -0x88, 0x66, 0x76, 0x02, 0x46, 0x00, 0x5b, 0x08, -0x3b, 0x3b, 0x30, 0x07, 0x35, 0xff, 0xff, 0xc2, -0xbf, 0x0d, 0x27, 0x0c, 0x27, 0x0d, 0x1e, 0x02, -0x55, 0x28, 0x85, 0xf2, 0x5b, 0x7b, 0x76, 0x12, -0x1e, 0x07, 0x55, 0xdc, 0xef, 0x05, 0xff, 0x1a, -0x27, 0x56, 0xdf, 0x3f, 0x20, 0x6d, 0x80, 0x3c, -0xaf, 0x05, 0x27, 0x13, 0x1e, 0x01, 0x55, 0x3c, -0x23, 0x05, 0x27, 0x1f, 0x1e, 0x06, 0x55, 0x37, -0x35, 0x08, 0xef, 0x40, 0x2e, 0xf0, 0xbf, 0x40, -0x2e, 0xf6, 0xbf, 0x05, 0x27, 0x20, 0x1e, 0x06, -0x55, 0x37, 0x3d, 0x16, 0xef, 0x40, 0x2e, 0xf0, -0xbf, 0x40, 0x2e, 0xf6, 0xbf, 0x05, 0x27, 0x22, -0x1e, 0x19, 0x55, 0x21, 0xef, 0x08, 0xaf, 0x09, -0x23, 0x01, 0xef, 0x0b, 0xaf, 0x31, 0xef, 0x0a, -0xaf, 0x81, 0xcf, 0x10, 0xaf, 0xbf, 0x8e, 0x82, -0xcf, 0x4a, 0xaf, 0x00, 0x2e, 0xc4, 0x8d, 0x08, -0xef, 0x9b, 0xaf, 0x99, 0xaf + 0x42, 0xca, 0x00, + 0xb8, 0x21, 0x25, 0x85, 0x01, + 0x1e, 0x17, 0x55, 0x1b, 0x8a, 0x41, 0x2e, 0x53, + 0xdf, 0xc1, 0x2e, 0x79, 0xdf, 0xff, 0x96, 0xdf, + 0x96, 0x41, 0x2e, 0x55, 0xdf, 0xc1, 0x2e, 0x78, + 0xdf, 0x9d, 0x01, 0x5d, 0x01, 0xff, 0x22, 0x00, + 0x54, 0xff, 0xef, 0x2e, 0xaf, 0x05, 0x27, 0x07, + 0x80, 0x9f, 0x22, 0xff, 0xaf, 0x00, 0x2e, 0x5d, + 0x89, 0x05, 0x27, 0x06, 0x1e, 0x01, 0x55, 0x0f, + 0x27, 0x01, 0x70, 0x0a, 0x1e, 0x0a, 0x55, 0x00, + 0x88, 0x66, 0x76, 0x02, 0x46, 0x00, 0x5b, 0x08, + 0x3b, 0x3b, 0x30, 0x07, 0x35, 0xff, 0xff, 0xc2, + 0xbf, 0x0d, 0x27, 0x0c, 0x27, 0x0d, 0x1e, 0x02, + 0x55, 0x28, 0x85, 0xf2, 0x5b, 0x7b, 0x76, 0x12, + 0x1e, 0x07, 0x55, 0xdc, 0xef, 0x05, 0xff, 0x1a, + 0x27, 0x56, 0xdf, 0x3f, 0x20, 0x6d, 0x80, 0x3c, + 0xaf, 0x05, 0x27, 0x13, 0x1e, 0x01, 0x55, 0x3c, + 0x23, 0x05, 0x27, 0x1f, 0x1e, 0x06, 0x55, 0x37, + 0x35, 0x08, 0xef, 0x40, 0x2e, 0xf0, 0xbf, 0x40, + 0x2e, 0xf6, 0xbf, 0x05, 0x27, 0x20, 0x1e, 0x06, + 0x55, 0x37, 0x3d, 0x16, 0xef, 0x40, 0x2e, 0xf0, + 0xbf, 0x40, 0x2e, 0xf6, 0xbf, 0x05, 0x27, 0x22, + 0x1e, 0x19, 0x55, 0x21, 0xef, 0x08, 0xaf, 0x09, + 0x23, 0x01, 0xef, 0x0b, 0xaf, 0x31, 0xef, 0x0a, + 0xaf, 0x81, 0xcf, 0x10, 0xaf, 0xbf, 0x8e, 0x82, + 0xcf, 0x4a, 0xaf, 0x00, 0x2e, 0xc4, 0x8d, 0x08, + 0xef, 0x9b, 0xaf, 0x99, 0xaf }; static const unsigned char pkt460[] = { -0x42, 0x34, 0x00, -0x1c, 0x22, 0x02, 0xcf, 0x0f, -0x1c, 0x40, 0x18, 0x37, 0x31, 0x02, 0xaf, 0xe2, -0x23, 0x08, 0xef, 0xe3, 0xaf, 0x05, 0x27, 0x23, -0x1e, 0x0c, 0x55, 0x00, 0xef, 0x02, 0xff, 0x19, -0x27, 0xbf, 0x22, 0x20, 0xef, 0x7f, 0x9f, 0x5f, -0x20, 0xfc, 0x55, 0xf0, 0x81, 0x9f, 0x22, 0x41, -0x2e, 0xa3, 0xbf, 0x05, 0x27, 0xcb, 0x74 + 0x42, 0x34, 0x00, + 0x1c, 0x22, 0x02, 0xcf, 0x0f, + 0x1c, 0x40, 0x18, 0x37, 0x31, 0x02, 0xaf, 0xe2, + 0x23, 0x08, 0xef, 0xe3, 0xaf, 0x05, 0x27, 0x23, + 0x1e, 0x0c, 0x55, 0x00, 0xef, 0x02, 0xff, 0x19, + 0x27, 0xbf, 0x22, 0x20, 0xef, 0x7f, 0x9f, 0x5f, + 0x20, 0xfc, 0x55, 0xf0, 0x81, 0x9f, 0x22, 0x41, + 0x2e, 0xa3, 0xbf, 0x05, 0x27, 0xcb, 0x74 }; static const unsigned char pkt464[] = { -0x42, 0xca, 0x00, -0x35, 0x22, 0x25, 0x85, 0x44, -0x1e, 0x01, 0x55, 0xe2, 0x2f, 0xf1, 0x50, 0x49, -0x1e, 0x0d, 0x55, 0x37, 0x39, 0x01, 0xef, 0x72, -0x88, 0x00, 0x2e, 0x45, 0x8d, 0x6b, 0x81, 0x08, -0x42, 0x03, 0x5b, 0x3d, 0x23, 0x9f, 0x22, 0x00, -0x2e, 0xb2, 0x8b, 0xd3, 0x3b, 0x05, 0x27, 0x4a, -0x1e, 0x01, 0x55, 0xe2, 0x2f, 0xdd, 0x50, 0x4e, -0x1e, 0x01, 0x55, 0x00, 0x2e, 0xbb, 0x79, 0x55, -0x1e, 0x16, 0x55, 0x28, 0x85, 0xe2, 0x2f, 0xd4, -0x5b, 0x07, 0xef, 0x20, 0x80, 0xe2, 0x2f, 0xd0, -0x5a, 0xfe, 0xcf, 0x0a, 0xaf, 0xfe, 0xcf, 0xfe, -0xcf, 0x41, 0x2e, 0x44, 0xbf, 0xfe, 0xcf, 0x41, -0x2e, 0x45, 0xbf, 0xfe, 0xcf, 0x52, 0xaf, 0xfe, -0xcf, 0x53, 0xaf, 0xfe, 0xcf, 0x5a, 0xaf, 0x05, -0x27, 0x58, 0x1e, 0x0d, 0x55, 0x02, 0x44, 0x01, -0x5a, 0x00, 0x2e, 0x07, 0x78, 0xfe, 0xcf, 0x75, -0xaf, 0xfe, 0xdf, 0x76, 0xbf, 0x41, 0x2e, 0xa4, -0xdf, 0xdf, 0x29, 0x41, 0x2e, 0xa4, 0xbf, 0x05, -0x27, 0x59, 0x1e, 0x02, 0x55, 0xfe, 0xcf, 0x10, -0xaf, 0x54, 0x7e, 0x63, 0x1e, 0x1a, 0x55, 0x28, -0x85, 0xe2, 0x2f, 0xa6, 0x5b, 0x0c, 0xef, 0x20, -0x80, 0xe2, 0x2f, 0xa2, 0x5a, 0xf0, 0xef, 0x00, -0xff, 0x19, 0x27, 0x08, 0xef, 0x06, 0xaf, 0xfe, -0xcf, 0x5f, 0x9f, 0x06, 0x25, 0xfb, 0x55, 0xfe, -0xcf, 0xfe, 0xcf, 0x41, 0x2e, 0x40, 0xbf, 0xfe, -0xcf, 0x41, 0x2e, 0x41, 0xbf + 0x42, 0xca, 0x00, + 0x35, 0x22, 0x25, 0x85, 0x44, + 0x1e, 0x01, 0x55, 0xe2, 0x2f, 0xf1, 0x50, 0x49, + 0x1e, 0x0d, 0x55, 0x37, 0x39, 0x01, 0xef, 0x72, + 0x88, 0x00, 0x2e, 0x45, 0x8d, 0x6b, 0x81, 0x08, + 0x42, 0x03, 0x5b, 0x3d, 0x23, 0x9f, 0x22, 0x00, + 0x2e, 0xb2, 0x8b, 0xd3, 0x3b, 0x05, 0x27, 0x4a, + 0x1e, 0x01, 0x55, 0xe2, 0x2f, 0xdd, 0x50, 0x4e, + 0x1e, 0x01, 0x55, 0x00, 0x2e, 0xbb, 0x79, 0x55, + 0x1e, 0x16, 0x55, 0x28, 0x85, 0xe2, 0x2f, 0xd4, + 0x5b, 0x07, 0xef, 0x20, 0x80, 0xe2, 0x2f, 0xd0, + 0x5a, 0xfe, 0xcf, 0x0a, 0xaf, 0xfe, 0xcf, 0xfe, + 0xcf, 0x41, 0x2e, 0x44, 0xbf, 0xfe, 0xcf, 0x41, + 0x2e, 0x45, 0xbf, 0xfe, 0xcf, 0x52, 0xaf, 0xfe, + 0xcf, 0x53, 0xaf, 0xfe, 0xcf, 0x5a, 0xaf, 0x05, + 0x27, 0x58, 0x1e, 0x0d, 0x55, 0x02, 0x44, 0x01, + 0x5a, 0x00, 0x2e, 0x07, 0x78, 0xfe, 0xcf, 0x75, + 0xaf, 0xfe, 0xdf, 0x76, 0xbf, 0x41, 0x2e, 0xa4, + 0xdf, 0xdf, 0x29, 0x41, 0x2e, 0xa4, 0xbf, 0x05, + 0x27, 0x59, 0x1e, 0x02, 0x55, 0xfe, 0xcf, 0x10, + 0xaf, 0x54, 0x7e, 0x63, 0x1e, 0x1a, 0x55, 0x28, + 0x85, 0xe2, 0x2f, 0xa6, 0x5b, 0x0c, 0xef, 0x20, + 0x80, 0xe2, 0x2f, 0xa2, 0x5a, 0xf0, 0xef, 0x00, + 0xff, 0x19, 0x27, 0x08, 0xef, 0x06, 0xaf, 0xfe, + 0xcf, 0x5f, 0x9f, 0x06, 0x25, 0xfb, 0x55, 0xfe, + 0xcf, 0xfe, 0xcf, 0x41, 0x2e, 0x40, 0xbf, 0xfe, + 0xcf, 0x41, 0x2e, 0x41, 0xbf }; static const unsigned char pkt468[] = { -0x42, 0x46, 0x00, -0x99, 0x22, 0xfe, 0xcf, 0x41, -0x2e, 0x42, 0xbf, 0x05, 0x27, 0x66, 0x1e, 0x0b, -0x55, 0x33, 0xef, 0x21, 0xff, 0x1a, 0x27, 0x0b, -0xef, 0x06, 0xaf, 0xfe, 0xcf, 0xfe, 0xdf, 0x06, -0x27, 0x01, 0x0e, 0x06, 0x25, 0xf9, 0x55, 0x05, -0x27, 0x35, 0x74, 0xff, 0x96, 0xc6, 0x2e, 0x01, -0xdf, 0x3f, 0x2c, 0xdd, 0x9f, 0x05, 0x27, 0xf9, -0x35, 0xc1, 0x2e, 0x4e, 0xdf, 0x0f, 0x1d, 0x09, -0x27, 0x5f, 0x02, 0xc1, 0x2e, 0x4e, 0xbf, 0x05, -0x27 + 0x42, 0x46, 0x00, + 0x99, 0x22, 0xfe, 0xcf, 0x41, + 0x2e, 0x42, 0xbf, 0x05, 0x27, 0x66, 0x1e, 0x0b, + 0x55, 0x33, 0xef, 0x21, 0xff, 0x1a, 0x27, 0x0b, + 0xef, 0x06, 0xaf, 0xfe, 0xcf, 0xfe, 0xdf, 0x06, + 0x27, 0x01, 0x0e, 0x06, 0x25, 0xf9, 0x55, 0x05, + 0x27, 0x35, 0x74, 0xff, 0x96, 0xc6, 0x2e, 0x01, + 0xdf, 0x3f, 0x2c, 0xdd, 0x9f, 0x05, 0x27, 0xf9, + 0x35, 0xc1, 0x2e, 0x4e, 0xdf, 0x0f, 0x1d, 0x09, + 0x27, 0x5f, 0x02, 0xc1, 0x2e, 0x4e, 0xbf, 0x05, + 0x27 }; static const unsigned char pkt472[] = { -0x42, 0xca, 0x00, -0xbb, 0x22, 0x09, 0x46, 0x0b, -0x5b, 0x08, 0x31, 0xf2, 0xcf, 0x0b, 0xaf, 0x15, -0xef, 0xf4, 0xaf, 0x30, 0xef, 0x0a, 0xaf, 0x44, -0xef, 0xfa, 0xaf, 0x10, 0xef, 0xf8, 0xaf, 0x5c, -0x88, 0x37, 0xcf, 0xdf, 0x96, 0x08, 0xcf, 0xdf, -0x96, 0x3d, 0xcf, 0xdf, 0x96, 0x00, 0x2e, 0xd4, -0x8d, 0xdd, 0x97, 0x3d, 0xaf, 0xdd, 0x97, 0x08, -0xaf, 0xdd, 0x97, 0x37, 0xaf, 0xa0, 0xcf, 0xbf, -0x1c, 0xa0, 0xaf, 0x05, 0x81, 0xfb, 0x39, 0x08, -0x45, 0x00, 0x5a, 0xfb, 0x31, 0x0a, 0x42, 0x00, -0x5b, 0xa2, 0x39, 0x02, 0xcf, 0x5c, 0xaf, 0xe1, -0xef, 0x40, 0x2e, 0x95, 0xbf, 0x9f, 0x22, 0x25, -0xaf, 0x69, 0xaf, 0x6a, 0xaf, 0x16, 0xaf, 0x40, -0x2e, 0x96, 0xbf, 0x29, 0xaf, 0x02, 0x47, 0x06, -0x5a, 0x0a, 0x41, 0x04, 0x5a, 0x0a, 0xdf, 0x30, -0x1d, 0x30, 0x1f, 0x00, 0x54, 0x01, 0xef, 0x44, -0xaf, 0x09, 0xef, 0x60, 0xaf, 0x08, 0x45, 0x0a, -0x40, 0x06, 0x5a, 0x10, 0xcf, 0x27, 0xaf, 0xe2, -0x23, 0x6e, 0x23, 0x08, 0xef, 0xe3, 0xaf, 0x6f, -0xaf, 0xce, 0x8d, 0x5d, 0xcf, 0x30, 0x1c, 0x00, -0x1e, 0x07, 0x55, 0xf8, 0xcf, 0x5f, 0x2b, 0x9f, -0x29, 0xf8, 0xaf, 0xa1, 0xcf, 0xc1, 0x1c, 0xa1, -0xaf, 0x09, 0x50, 0x10, 0x1e, 0x07, 0x55, 0xf8, -0xcf, 0x5f, 0x29, 0x9f, 0x2b, 0xf8, 0xaf, 0xa1, -0xcf, 0xc1, 0x1c, 0x08, 0x18, 0xa1, 0xaf, 0x41, -0x2e, 0xa4, 0xdf, 0xdf, 0x2d + 0x42, 0xca, 0x00, + 0xbb, 0x22, 0x09, 0x46, 0x0b, + 0x5b, 0x08, 0x31, 0xf2, 0xcf, 0x0b, 0xaf, 0x15, + 0xef, 0xf4, 0xaf, 0x30, 0xef, 0x0a, 0xaf, 0x44, + 0xef, 0xfa, 0xaf, 0x10, 0xef, 0xf8, 0xaf, 0x5c, + 0x88, 0x37, 0xcf, 0xdf, 0x96, 0x08, 0xcf, 0xdf, + 0x96, 0x3d, 0xcf, 0xdf, 0x96, 0x00, 0x2e, 0xd4, + 0x8d, 0xdd, 0x97, 0x3d, 0xaf, 0xdd, 0x97, 0x08, + 0xaf, 0xdd, 0x97, 0x37, 0xaf, 0xa0, 0xcf, 0xbf, + 0x1c, 0xa0, 0xaf, 0x05, 0x81, 0xfb, 0x39, 0x08, + 0x45, 0x00, 0x5a, 0xfb, 0x31, 0x0a, 0x42, 0x00, + 0x5b, 0xa2, 0x39, 0x02, 0xcf, 0x5c, 0xaf, 0xe1, + 0xef, 0x40, 0x2e, 0x95, 0xbf, 0x9f, 0x22, 0x25, + 0xaf, 0x69, 0xaf, 0x6a, 0xaf, 0x16, 0xaf, 0x40, + 0x2e, 0x96, 0xbf, 0x29, 0xaf, 0x02, 0x47, 0x06, + 0x5a, 0x0a, 0x41, 0x04, 0x5a, 0x0a, 0xdf, 0x30, + 0x1d, 0x30, 0x1f, 0x00, 0x54, 0x01, 0xef, 0x44, + 0xaf, 0x09, 0xef, 0x60, 0xaf, 0x08, 0x45, 0x0a, + 0x40, 0x06, 0x5a, 0x10, 0xcf, 0x27, 0xaf, 0xe2, + 0x23, 0x6e, 0x23, 0x08, 0xef, 0xe3, 0xaf, 0x6f, + 0xaf, 0xce, 0x8d, 0x5d, 0xcf, 0x30, 0x1c, 0x00, + 0x1e, 0x07, 0x55, 0xf8, 0xcf, 0x5f, 0x2b, 0x9f, + 0x29, 0xf8, 0xaf, 0xa1, 0xcf, 0xc1, 0x1c, 0xa1, + 0xaf, 0x09, 0x50, 0x10, 0x1e, 0x07, 0x55, 0xf8, + 0xcf, 0x5f, 0x29, 0x9f, 0x2b, 0xf8, 0xaf, 0xa1, + 0xcf, 0xc1, 0x1c, 0x08, 0x18, 0xa1, 0xaf, 0x41, + 0x2e, 0xa4, 0xdf, 0xdf, 0x2d }; static const unsigned char pkt476[] = { -0x42, 0x3a, 0x00, -0x1f, 0x23, 0x04, 0x5b, 0x75, -0xcf, 0xf4, 0xaf, 0x76, 0xcf, 0xf5, 0xaf, 0x00, -0x50, 0x0f, 0x88, 0xe2, 0x23, 0x08, 0xef, 0xe3, -0xaf, 0x81, 0x82, 0x4d, 0xaf, 0xdf, 0x96, 0x64, -0xdf, 0x93, 0x82, 0x93, 0xbf, 0xdd, 0x97, 0x77, -0xff, 0x93, 0x82, 0x94, 0xbf, 0x9e, 0x23, 0xe4, -0x23, 0x05, 0x27, 0x14, 0xef, 0xf4, 0xaf, 0x00, -0xef, 0xf5, 0xaf, 0x05, 0x27 + 0x42, 0x3a, 0x00, + 0x1f, 0x23, 0x04, 0x5b, 0x75, + 0xcf, 0xf4, 0xaf, 0x76, 0xcf, 0xf5, 0xaf, 0x00, + 0x50, 0x0f, 0x88, 0xe2, 0x23, 0x08, 0xef, 0xe3, + 0xaf, 0x81, 0x82, 0x4d, 0xaf, 0xdf, 0x96, 0x64, + 0xdf, 0x93, 0x82, 0x93, 0xbf, 0xdd, 0x97, 0x77, + 0xff, 0x93, 0x82, 0x94, 0xbf, 0x9e, 0x23, 0xe4, + 0x23, 0x05, 0x27, 0x14, 0xef, 0xf4, 0xaf, 0x00, + 0xef, 0xf5, 0xaf, 0x05, 0x27 }; static const unsigned char pkt480[] = { -0x42, 0xca, 0x00, -0x3b, 0x23, 0xfe, 0xcf, 0x58, -0xaf, 0xfe, 0xcf, 0xfe, 0xdf, 0x00, 0x2e, 0xa9, -0x8b, 0xfe, 0xcf, 0x3c, 0xaf, 0x07, 0x3d, 0x58, -0x40, 0x4a, 0x5a, 0x3c, 0x26, 0x48, 0x55, 0x37, -0x45, 0x46, 0x5a, 0xe0, 0x88, 0x44, 0x5a, 0x77, -0x88, 0x00, 0x2e, 0xd1, 0x8b, 0xfe, 0xef, 0x16, -0x80, 0x02, 0xcf, 0xdf, 0x96, 0x61, 0xef, 0xc0, -0xaf, 0x04, 0x27, 0xc1, 0x46, 0x04, 0x5b, 0xc0, -0x3e, 0x40, 0xef, 0xc1, 0xaf, 0x01, 0x2e, 0x94, -0x84, 0xd0, 0x41, 0x06, 0x5b, 0x2d, 0x88, 0xf3, -0x5b, 0x6c, 0x86, 0xdd, 0x97, 0x1f, 0x2d, 0x05, -0x5b, 0x03, 0x50, 0x01, 0x0c, 0x02, 0xcf, 0xc0, -0x1c, 0x00, 0x55, 0x05, 0x88, 0xc0, 0x23, 0x20, -0xef, 0xc1, 0xaf, 0x00, 0x2e, 0xf0, 0x8b, 0x05, -0x27, 0x9b, 0x22, 0x37, 0x45, 0x05, 0x5a, 0x41, -0x2e, 0x52, 0xdf, 0xdf, 0x2d, 0x04, 0x5b, 0x00, -0x28, 0x02, 0x50, 0x3b, 0x43, 0x00, 0x5b, 0x00, -0x28, 0xd3, 0xdf, 0xc6, 0x2e, 0x15, 0xbf, 0xd3, -0x3c, 0x40, 0xef, 0x09, 0x80, 0xdd, 0x97, 0xff, -0xaf, 0x00, 0x2e, 0x5d, 0x89, 0xc6, 0x2e, 0x15, -0xdf, 0x10, 0x1d, 0xd3, 0xcf, 0x3f, 0x02, 0xd3, -0xaf, 0x05, 0x27, 0xc1, 0x83, 0x07, 0x45, 0x05, -0x27, 0x3d, 0x23, 0x07, 0x3d, 0x02, 0xcf, 0xdf, -0x96, 0x2e, 0x88, 0x26, 0x88, 0xfe, 0xef, 0x16, -0x80, 0x05, 0xef, 0xc0, 0xaf, 0x04, 0x27, 0xd0, -0x41, 0x02, 0x5b, 0xee, 0x8f + 0x42, 0xca, 0x00, + 0x3b, 0x23, 0xfe, 0xcf, 0x58, + 0xaf, 0xfe, 0xcf, 0xfe, 0xdf, 0x00, 0x2e, 0xa9, + 0x8b, 0xfe, 0xcf, 0x3c, 0xaf, 0x07, 0x3d, 0x58, + 0x40, 0x4a, 0x5a, 0x3c, 0x26, 0x48, 0x55, 0x37, + 0x45, 0x46, 0x5a, 0xe0, 0x88, 0x44, 0x5a, 0x77, + 0x88, 0x00, 0x2e, 0xd1, 0x8b, 0xfe, 0xef, 0x16, + 0x80, 0x02, 0xcf, 0xdf, 0x96, 0x61, 0xef, 0xc0, + 0xaf, 0x04, 0x27, 0xc1, 0x46, 0x04, 0x5b, 0xc0, + 0x3e, 0x40, 0xef, 0xc1, 0xaf, 0x01, 0x2e, 0x94, + 0x84, 0xd0, 0x41, 0x06, 0x5b, 0x2d, 0x88, 0xf3, + 0x5b, 0x6c, 0x86, 0xdd, 0x97, 0x1f, 0x2d, 0x05, + 0x5b, 0x03, 0x50, 0x01, 0x0c, 0x02, 0xcf, 0xc0, + 0x1c, 0x00, 0x55, 0x05, 0x88, 0xc0, 0x23, 0x20, + 0xef, 0xc1, 0xaf, 0x00, 0x2e, 0xf0, 0x8b, 0x05, + 0x27, 0x9b, 0x22, 0x37, 0x45, 0x05, 0x5a, 0x41, + 0x2e, 0x52, 0xdf, 0xdf, 0x2d, 0x04, 0x5b, 0x00, + 0x28, 0x02, 0x50, 0x3b, 0x43, 0x00, 0x5b, 0x00, + 0x28, 0xd3, 0xdf, 0xc6, 0x2e, 0x15, 0xbf, 0xd3, + 0x3c, 0x40, 0xef, 0x09, 0x80, 0xdd, 0x97, 0xff, + 0xaf, 0x00, 0x2e, 0x5d, 0x89, 0xc6, 0x2e, 0x15, + 0xdf, 0x10, 0x1d, 0xd3, 0xcf, 0x3f, 0x02, 0xd3, + 0xaf, 0x05, 0x27, 0xc1, 0x83, 0x07, 0x45, 0x05, + 0x27, 0x3d, 0x23, 0x07, 0x3d, 0x02, 0xcf, 0xdf, + 0x96, 0x2e, 0x88, 0x26, 0x88, 0xfe, 0xef, 0x16, + 0x80, 0x05, 0xef, 0xc0, 0xaf, 0x04, 0x27, 0xd0, + 0x41, 0x02, 0x5b, 0xee, 0x8f }; static const unsigned char pkt484[] = { -0x42, 0xca, 0x00, -0x9f, 0x23, 0xfa, 0x5b, 0xbf, -0x50, 0x31, 0x82, 0x04, 0xef, 0xc1, 0xaf, 0x9b, -0x22, 0x41, 0x88, 0xdd, 0x97, 0xdf, 0x22, 0x02, -0x55, 0x58, 0x40, 0x02, 0x5a, 0x09, 0x50, 0x58, -0x40, 0x07, 0x5a, 0xdd, 0x97, 0x1f, 0x2d, 0xb8, -0x5a, 0x7a, 0x88, 0xb7, 0x5b, 0x9b, 0x22, 0xc7, -0x8f, 0xb4, 0x50, 0x75, 0x88, 0xdc, 0x5b, 0xb7, -0x8f, 0x58, 0x41, 0x01, 0x5b, 0x01, 0x0c, 0xad, -0x7f, 0xd6, 0x50, 0x41, 0x2e, 0x52, 0xdf, 0xed, -0x1c, 0x04, 0x18, 0x41, 0x2e, 0x52, 0xbf, 0x05, -0x27, 0x00, 0x2e, 0xb9, 0x8b, 0xae, 0xdf, 0xe0, -0x19, 0xae, 0xbf, 0x57, 0x40, 0x00, 0x5b, 0xa1, -0x32, 0x57, 0x43, 0x00, 0x5b, 0xae, 0x3f, 0x05, -0x81, 0x05, 0x27, 0x41, 0x2e, 0x52, 0xdf, 0x03, -0x18, 0x41, 0x2e, 0x52, 0xbf, 0x05, 0x27, 0xd3, -0xdf, 0xff, 0x96, 0x9b, 0x22, 0x0b, 0x88, 0xd3, -0x3c, 0x07, 0x80, 0xdd, 0x97, 0xff, 0xaf, 0x00, -0x2e, 0x5d, 0x89, 0xdd, 0x9f, 0x10, 0x1d, 0xd3, -0xcf, 0x3f, 0x02, 0xd3, 0xaf, 0x05, 0x27, 0x37, -0x45, 0x0e, 0x5a, 0x40, 0x88, 0x0c, 0x5a, 0xd7, -0x8f, 0x00, 0x2e, 0xd7, 0x8b, 0x00, 0x2e, 0xeb, -0x8b, 0x41, 0x2e, 0x52, 0xdf, 0xdf, 0x2d, 0x00, -0x5b, 0x00, 0x28, 0x00, 0x2e, 0xf0, 0x8b, 0x05, -0x27, 0xf9, 0xcf, 0xdf, 0x96, 0xf9, 0x3d, 0x00, -0x2e, 0xd1, 0x8d, 0x28, 0xff, 0xa7, 0xef, 0xe1, -0xbf, 0xe0, 0xaf, 0x09, 0xef + 0x42, 0xca, 0x00, + 0x9f, 0x23, 0xfa, 0x5b, 0xbf, + 0x50, 0x31, 0x82, 0x04, 0xef, 0xc1, 0xaf, 0x9b, + 0x22, 0x41, 0x88, 0xdd, 0x97, 0xdf, 0x22, 0x02, + 0x55, 0x58, 0x40, 0x02, 0x5a, 0x09, 0x50, 0x58, + 0x40, 0x07, 0x5a, 0xdd, 0x97, 0x1f, 0x2d, 0xb8, + 0x5a, 0x7a, 0x88, 0xb7, 0x5b, 0x9b, 0x22, 0xc7, + 0x8f, 0xb4, 0x50, 0x75, 0x88, 0xdc, 0x5b, 0xb7, + 0x8f, 0x58, 0x41, 0x01, 0x5b, 0x01, 0x0c, 0xad, + 0x7f, 0xd6, 0x50, 0x41, 0x2e, 0x52, 0xdf, 0xed, + 0x1c, 0x04, 0x18, 0x41, 0x2e, 0x52, 0xbf, 0x05, + 0x27, 0x00, 0x2e, 0xb9, 0x8b, 0xae, 0xdf, 0xe0, + 0x19, 0xae, 0xbf, 0x57, 0x40, 0x00, 0x5b, 0xa1, + 0x32, 0x57, 0x43, 0x00, 0x5b, 0xae, 0x3f, 0x05, + 0x81, 0x05, 0x27, 0x41, 0x2e, 0x52, 0xdf, 0x03, + 0x18, 0x41, 0x2e, 0x52, 0xbf, 0x05, 0x27, 0xd3, + 0xdf, 0xff, 0x96, 0x9b, 0x22, 0x0b, 0x88, 0xd3, + 0x3c, 0x07, 0x80, 0xdd, 0x97, 0xff, 0xaf, 0x00, + 0x2e, 0x5d, 0x89, 0xdd, 0x9f, 0x10, 0x1d, 0xd3, + 0xcf, 0x3f, 0x02, 0xd3, 0xaf, 0x05, 0x27, 0x37, + 0x45, 0x0e, 0x5a, 0x40, 0x88, 0x0c, 0x5a, 0xd7, + 0x8f, 0x00, 0x2e, 0xd7, 0x8b, 0x00, 0x2e, 0xeb, + 0x8b, 0x41, 0x2e, 0x52, 0xdf, 0xdf, 0x2d, 0x00, + 0x5b, 0x00, 0x28, 0x00, 0x2e, 0xf0, 0x8b, 0x05, + 0x27, 0xf9, 0xcf, 0xdf, 0x96, 0xf9, 0x3d, 0x00, + 0x2e, 0xd1, 0x8d, 0x28, 0xff, 0xa7, 0xef, 0xe1, + 0xbf, 0xe0, 0xaf, 0x09, 0xef }; static const unsigned char pkt488[] = { -0x42, 0x6c, 0x00, -0x03, 0x24, 0x10, 0xaf, 0xcf, -0x8c, 0x05, 0x81, 0x01, 0x2e, 0x54, 0x80, 0x01, -0x2e, 0x56, 0x80, 0x20, 0x82, 0x3c, 0x8d, 0x37, -0x82, 0x26, 0x37, 0x00, 0x5a, 0x0c, 0x50, 0xff, -0x96, 0xdf, 0x96, 0x79, 0xcf, 0x7a, 0xdf, 0xff, -0x96, 0xdf, 0x96, 0xc2, 0x97, 0xc3, 0x9f, 0x9d, -0x01, 0x5d, 0x01, 0x07, 0x53, 0xdd, 0x97, 0xdd, -0x9f, 0x79, 0xaf, 0x7a, 0xbf, 0x3b, 0x3b, 0xdd, -0x97, 0xf9, 0xaf, 0x05, 0x27, 0xff, 0x22, 0x01, -0x55, 0x32, 0x1e, 0xf3, 0x5f, 0x02, 0x0c, 0xf6, -0x8f, 0x3b, 0x33, 0x00, 0x28, 0x05, 0x27, 0x0d, -0x27, 0x3c, 0x26, 0x07, 0x54, 0x3c, 0xcf, 0x3d, -0xdf, 0x3f, 0x20, 0x3d, 0xbf, 0xdf, 0x03, 0x01, -0x52, 0x3d, 0x23, 0x0c, 0x27, 0x0d, 0x27 + 0x42, 0x6c, 0x00, + 0x03, 0x24, 0x10, 0xaf, 0xcf, + 0x8c, 0x05, 0x81, 0x01, 0x2e, 0x54, 0x80, 0x01, + 0x2e, 0x56, 0x80, 0x20, 0x82, 0x3c, 0x8d, 0x37, + 0x82, 0x26, 0x37, 0x00, 0x5a, 0x0c, 0x50, 0xff, + 0x96, 0xdf, 0x96, 0x79, 0xcf, 0x7a, 0xdf, 0xff, + 0x96, 0xdf, 0x96, 0xc2, 0x97, 0xc3, 0x9f, 0x9d, + 0x01, 0x5d, 0x01, 0x07, 0x53, 0xdd, 0x97, 0xdd, + 0x9f, 0x79, 0xaf, 0x7a, 0xbf, 0x3b, 0x3b, 0xdd, + 0x97, 0xf9, 0xaf, 0x05, 0x27, 0xff, 0x22, 0x01, + 0x55, 0x32, 0x1e, 0xf3, 0x5f, 0x02, 0x0c, 0xf6, + 0x8f, 0x3b, 0x33, 0x00, 0x28, 0x05, 0x27, 0x0d, + 0x27, 0x3c, 0x26, 0x07, 0x54, 0x3c, 0xcf, 0x3d, + 0xdf, 0x3f, 0x20, 0x3d, 0xbf, 0xdf, 0x03, 0x01, + 0x52, 0x3d, 0x23, 0x0c, 0x27, 0x0d, 0x27 }; static const unsigned char pkt492[] = { -0x42, 0x9c, 0x00, -0x38, 0x24, 0x08, 0x44, 0x12, -0x5a, 0x07, 0x40, 0x01, 0x5b, 0x4f, 0x80, 0x00, -0x50, 0x53, 0x80, 0x27, 0x0d, 0x25, 0xcf, 0x1f, -0x98, 0x29, 0xcf, 0x09, 0x27, 0x28, 0xdf, 0x3f, -0x02, 0x5f, 0x98, 0x62, 0xcf, 0xdf, 0x98, 0xd9, -0x0d, 0x02, 0x0d, 0x00, 0x2e, 0xd5, 0x7f, 0x05, -0x27, 0x08, 0x44, 0x22, 0x5a, 0x07, 0x40, 0x01, -0x5b, 0x4f, 0x80, 0x00, 0x50, 0x53, 0x80, 0x0b, -0x0d, 0x07, 0x40, 0x1b, 0x5a, 0x44, 0xcf, 0x1f, -0x20, 0x44, 0xaf, 0x5f, 0x9f, 0xc1, 0x2e, 0x57, -0xdf, 0xff, 0x96, 0x41, 0x2e, 0x56, 0xdf, 0xdf, -0x96, 0x41, 0x2e, 0x58, 0xdf, 0xc1, 0x2e, 0x59, -0xdf, 0x9d, 0x01, 0x5d, 0x01, 0xff, 0x96, 0xdf, -0x96, 0x40, 0x2e, 0x59, 0xdf, 0x5f, 0x9f, 0x50, -0xdf, 0x7f, 0x9f, 0x1d, 0x00, 0xdd, 0x00, 0x5f, -0x9f, 0x7f, 0x9f, 0x05, 0x27, 0x01, 0x0d, 0x41, -0x2e, 0x56, 0xdf, 0x5f, 0x9f, 0x41, 0x2e, 0x57, -0xdf, 0x5f, 0x9f, 0x41, 0x2e, 0x58, 0xdf, 0x5f, -0x9f, 0x41, 0x2e, 0x59, 0xdf, 0x5f, 0x9f, 0x06, -0x0d, 0x3b, 0xcf, 0x5f, 0x9f, 0x05, 0x27 + 0x42, 0x9c, 0x00, + 0x38, 0x24, 0x08, 0x44, 0x12, + 0x5a, 0x07, 0x40, 0x01, 0x5b, 0x4f, 0x80, 0x00, + 0x50, 0x53, 0x80, 0x27, 0x0d, 0x25, 0xcf, 0x1f, + 0x98, 0x29, 0xcf, 0x09, 0x27, 0x28, 0xdf, 0x3f, + 0x02, 0x5f, 0x98, 0x62, 0xcf, 0xdf, 0x98, 0xd9, + 0x0d, 0x02, 0x0d, 0x00, 0x2e, 0xd5, 0x7f, 0x05, + 0x27, 0x08, 0x44, 0x22, 0x5a, 0x07, 0x40, 0x01, + 0x5b, 0x4f, 0x80, 0x00, 0x50, 0x53, 0x80, 0x0b, + 0x0d, 0x07, 0x40, 0x1b, 0x5a, 0x44, 0xcf, 0x1f, + 0x20, 0x44, 0xaf, 0x5f, 0x9f, 0xc1, 0x2e, 0x57, + 0xdf, 0xff, 0x96, 0x41, 0x2e, 0x56, 0xdf, 0xdf, + 0x96, 0x41, 0x2e, 0x58, 0xdf, 0xc1, 0x2e, 0x59, + 0xdf, 0x9d, 0x01, 0x5d, 0x01, 0xff, 0x96, 0xdf, + 0x96, 0x40, 0x2e, 0x59, 0xdf, 0x5f, 0x9f, 0x50, + 0xdf, 0x7f, 0x9f, 0x1d, 0x00, 0xdd, 0x00, 0x5f, + 0x9f, 0x7f, 0x9f, 0x05, 0x27, 0x01, 0x0d, 0x41, + 0x2e, 0x56, 0xdf, 0x5f, 0x9f, 0x41, 0x2e, 0x57, + 0xdf, 0x5f, 0x9f, 0x41, 0x2e, 0x58, 0xdf, 0x5f, + 0x9f, 0x41, 0x2e, 0x59, 0xdf, 0x5f, 0x9f, 0x06, + 0x0d, 0x3b, 0xcf, 0x5f, 0x9f, 0x05, 0x27 }; static const unsigned char pkt496[] = { -0x42, 0xca, 0x00, -0x85, 0x24, 0x02, 0x2e, 0x23, -0x80, 0x02, 0x2e, 0x4c, 0x80, 0x99, 0x88, 0x37, -0x41, 0xdd, 0x2f, 0xc1, 0x5a, 0x0a, 0x40, 0x11, -0x5a, 0x1f, 0x88, 0x41, 0x88, 0x4d, 0x88, 0x37, -0x42, 0x08, 0x5a, 0x09, 0x46, 0x0a, 0x5b, 0x23, -0x26, 0x08, 0x55, 0x22, 0xcf, 0xc6, 0x1e, 0x09, -0x52, 0x10, 0xcf, 0x27, 0xaf, 0x6e, 0x23, 0x08, -0xef, 0x6f, 0xaf, 0x62, 0x23, 0x6e, 0x26, 0x00, -0x55, 0x6e, 0x24, 0x05, 0x27, 0x67, 0x2e, 0xff, -0xdf, 0xdf, 0x22, 0x00, 0x2e, 0x25, 0x55, 0x67, -0x2e, 0xfe, 0xdf, 0xdf, 0x22, 0x00, 0x2e, 0x20, -0x55, 0x05, 0x27, 0x61, 0x23, 0x67, 0x2e, 0xff, -0xdf, 0xdf, 0x22, 0x00, 0x2e, 0x19, 0x55, 0x67, -0x2e, 0xfe, 0xdf, 0x65, 0xdf, 0xbf, 0x03, 0x00, -0x2e, 0x13, 0x5e, 0x3b, 0x43, 0x01, 0x5a, 0x3b, -0x41, 0x0e, 0x5a, 0x29, 0xdf, 0xff, 0x96, 0x25, -0xdf, 0x5d, 0x00, 0x10, 0x1f, 0x00, 0x2e, 0x08, -0x53, 0x07, 0x1f, 0x05, 0x53, 0x61, 0x24, 0x3b, -0x41, 0x02, 0x5a, 0x03, 0x1f, 0x00, 0x53, 0x61, -0x24, 0x05, 0x27, 0xff, 0xef, 0x61, 0xaf, 0x05, -0x27, 0x3b, 0x43, 0x09, 0x5b, 0x28, 0xdf, 0x6e, -0xbf, 0x70, 0xef, 0xbf, 0x22, 0x1a, 0x27, 0x29, -0xdf, 0x6e, 0xcf, 0xdf, 0x01, 0x6d, 0x80, 0x6f, -0xaf, 0x05, 0x27, 0x62, 0x26, 0x01, 0x54, 0x61, -0x47, 0x1d, 0x5b, 0x10, 0xdf, 0x27, 0xbf, 0x61, -0xcf, 0xdf, 0x22, 0x18, 0x54 + 0x42, 0xca, 0x00, + 0x85, 0x24, 0x02, 0x2e, 0x23, + 0x80, 0x02, 0x2e, 0x4c, 0x80, 0x99, 0x88, 0x37, + 0x41, 0xdd, 0x2f, 0xc1, 0x5a, 0x0a, 0x40, 0x11, + 0x5a, 0x1f, 0x88, 0x41, 0x88, 0x4d, 0x88, 0x37, + 0x42, 0x08, 0x5a, 0x09, 0x46, 0x0a, 0x5b, 0x23, + 0x26, 0x08, 0x55, 0x22, 0xcf, 0xc6, 0x1e, 0x09, + 0x52, 0x10, 0xcf, 0x27, 0xaf, 0x6e, 0x23, 0x08, + 0xef, 0x6f, 0xaf, 0x62, 0x23, 0x6e, 0x26, 0x00, + 0x55, 0x6e, 0x24, 0x05, 0x27, 0x67, 0x2e, 0xff, + 0xdf, 0xdf, 0x22, 0x00, 0x2e, 0x25, 0x55, 0x67, + 0x2e, 0xfe, 0xdf, 0xdf, 0x22, 0x00, 0x2e, 0x20, + 0x55, 0x05, 0x27, 0x61, 0x23, 0x67, 0x2e, 0xff, + 0xdf, 0xdf, 0x22, 0x00, 0x2e, 0x19, 0x55, 0x67, + 0x2e, 0xfe, 0xdf, 0x65, 0xdf, 0xbf, 0x03, 0x00, + 0x2e, 0x13, 0x5e, 0x3b, 0x43, 0x01, 0x5a, 0x3b, + 0x41, 0x0e, 0x5a, 0x29, 0xdf, 0xff, 0x96, 0x25, + 0xdf, 0x5d, 0x00, 0x10, 0x1f, 0x00, 0x2e, 0x08, + 0x53, 0x07, 0x1f, 0x05, 0x53, 0x61, 0x24, 0x3b, + 0x41, 0x02, 0x5a, 0x03, 0x1f, 0x00, 0x53, 0x61, + 0x24, 0x05, 0x27, 0xff, 0xef, 0x61, 0xaf, 0x05, + 0x27, 0x3b, 0x43, 0x09, 0x5b, 0x28, 0xdf, 0x6e, + 0xbf, 0x70, 0xef, 0xbf, 0x22, 0x1a, 0x27, 0x29, + 0xdf, 0x6e, 0xcf, 0xdf, 0x01, 0x6d, 0x80, 0x6f, + 0xaf, 0x05, 0x27, 0x62, 0x26, 0x01, 0x54, 0x61, + 0x47, 0x1d, 0x5b, 0x10, 0xdf, 0x27, 0xbf, 0x61, + 0xcf, 0xdf, 0x22, 0x18, 0x54 }; static const unsigned char pkt500[] = { -0x42, 0xca, 0x00, -0xe9, 0x24, 0x5f, 0x00, 0x00, -0x57, 0xbf, 0x22, 0x5f, 0xcf, 0xdf, 0x03, 0x00, -0x5f, 0x5f, 0xdf, 0x27, 0xbf, 0x61, 0xcf, 0xdf, -0x2d, 0x00, 0x2e, 0x19, 0x5a, 0x26, 0x88, 0xdf, -0x96, 0x6e, 0xdf, 0x09, 0x88, 0x6e, 0xbf, 0xc0, -0x97, 0x62, 0xdf, 0x05, 0x88, 0x62, 0xbf, 0x6f, -0xdf, 0xdd, 0x97, 0x06, 0x88, 0x6f, 0xaf, 0x05, -0x27, 0x8a, 0x80, 0x20, 0x10, 0x00, 0x13, 0x1c, -0x82, 0x05, 0x27, 0xdf, 0x96, 0x9f, 0x22, 0xd9, -0x81, 0x1a, 0x27, 0xdd, 0x9f, 0x6d, 0x80, 0x05, -0x27, 0x0c, 0x88, 0xdf, 0x96, 0x6f, 0xdf, 0xef, -0x8f, 0x6f, 0xbf, 0x6e, 0xdf, 0xc0, 0x97, 0xf0, -0x8f, 0x6e, 0xaf, 0x62, 0xdf, 0xdd, 0x97, 0xec, -0x8f, 0x62, 0xaf, 0x05, 0x27, 0x27, 0xcf, 0x61, -0x47, 0x00, 0x5b, 0x1f, 0x20, 0x09, 0x8c, 0xff, -0x97, 0x05, 0x27, 0x28, 0xdf, 0x06, 0x88, 0x2d, -0xbf, 0x2c, 0xaf, 0x29, 0xdf, 0x02, 0x88, 0x2b, -0xbf, 0x2a, 0xaf, 0x05, 0x27, 0xff, 0x96, 0x72, -0xcf, 0x01, 0x16, 0xdf, 0x96, 0x57, 0xef, 0x25, -0xff, 0x1d, 0x00, 0x00, 0x13, 0x1a, 0x27, 0x07, -0x27, 0xff, 0x96, 0xc1, 0x9f, 0x3f, 0x22, 0x01, -0x11, 0x8a, 0x80, 0xff, 0x96, 0xdf, 0x96, 0xc2, -0x97, 0xc3, 0x9f, 0x3f, 0x22, 0x01, 0x11, 0x8a, -0x80, 0x01, 0x00, 0xdf, 0x9f, 0xc0, 0x97, 0x04, -0x0c, 0xff, 0x96, 0xdf, 0x96, 0x72, 0xcf, 0x07, -0x1e, 0x04, 0x53, 0x03, 0x1e + 0x42, 0xca, 0x00, + 0xe9, 0x24, 0x5f, 0x00, 0x00, + 0x57, 0xbf, 0x22, 0x5f, 0xcf, 0xdf, 0x03, 0x00, + 0x5f, 0x5f, 0xdf, 0x27, 0xbf, 0x61, 0xcf, 0xdf, + 0x2d, 0x00, 0x2e, 0x19, 0x5a, 0x26, 0x88, 0xdf, + 0x96, 0x6e, 0xdf, 0x09, 0x88, 0x6e, 0xbf, 0xc0, + 0x97, 0x62, 0xdf, 0x05, 0x88, 0x62, 0xbf, 0x6f, + 0xdf, 0xdd, 0x97, 0x06, 0x88, 0x6f, 0xaf, 0x05, + 0x27, 0x8a, 0x80, 0x20, 0x10, 0x00, 0x13, 0x1c, + 0x82, 0x05, 0x27, 0xdf, 0x96, 0x9f, 0x22, 0xd9, + 0x81, 0x1a, 0x27, 0xdd, 0x9f, 0x6d, 0x80, 0x05, + 0x27, 0x0c, 0x88, 0xdf, 0x96, 0x6f, 0xdf, 0xef, + 0x8f, 0x6f, 0xbf, 0x6e, 0xdf, 0xc0, 0x97, 0xf0, + 0x8f, 0x6e, 0xaf, 0x62, 0xdf, 0xdd, 0x97, 0xec, + 0x8f, 0x62, 0xaf, 0x05, 0x27, 0x27, 0xcf, 0x61, + 0x47, 0x00, 0x5b, 0x1f, 0x20, 0x09, 0x8c, 0xff, + 0x97, 0x05, 0x27, 0x28, 0xdf, 0x06, 0x88, 0x2d, + 0xbf, 0x2c, 0xaf, 0x29, 0xdf, 0x02, 0x88, 0x2b, + 0xbf, 0x2a, 0xaf, 0x05, 0x27, 0xff, 0x96, 0x72, + 0xcf, 0x01, 0x16, 0xdf, 0x96, 0x57, 0xef, 0x25, + 0xff, 0x1d, 0x00, 0x00, 0x13, 0x1a, 0x27, 0x07, + 0x27, 0xff, 0x96, 0xc1, 0x9f, 0x3f, 0x22, 0x01, + 0x11, 0x8a, 0x80, 0xff, 0x96, 0xdf, 0x96, 0xc2, + 0x97, 0xc3, 0x9f, 0x3f, 0x22, 0x01, 0x11, 0x8a, + 0x80, 0x01, 0x00, 0xdf, 0x9f, 0xc0, 0x97, 0x04, + 0x0c, 0xff, 0x96, 0xdf, 0x96, 0x72, 0xcf, 0x07, + 0x1e, 0x04, 0x53, 0x03, 0x1e }; static const unsigned char pkt504[] = { -0x42, 0x2a, 0x00, -0x4d, 0x25, 0x04, 0x53, 0xdd, -0x97, 0xdd, 0x9f, 0x05, 0x27, 0x00, 0x88, 0xd8, -0x71, 0xdd, 0x97, 0xdd, 0x9f, 0xd8, 0x81, 0x05, -0x27, 0x00, 0x04, 0x00, 0x02, 0x4e, 0x07, 0x8e, -0x03, 0x19, 0x02, 0x0c, 0x01, 0x32, 0x04, 0x1c, -0x02, 0x0e, 0x01, 0x87, 0x00 + 0x42, 0x2a, 0x00, + 0x4d, 0x25, 0x04, 0x53, 0xdd, + 0x97, 0xdd, 0x9f, 0x05, 0x27, 0x00, 0x88, 0xd8, + 0x71, 0xdd, 0x97, 0xdd, 0x9f, 0xd8, 0x81, 0x05, + 0x27, 0x00, 0x04, 0x00, 0x02, 0x4e, 0x07, 0x8e, + 0x03, 0x19, 0x02, 0x0c, 0x01, 0x32, 0x04, 0x1c, + 0x02, 0x0e, 0x01, 0x87, 0x00 }; static const unsigned char pkt508[] = { -0x42, 0x8c, 0x00, -0x61, 0x25, 0x53, 0x80, 0x01, -0x0d, 0xf5, 0x97, 0xff, 0x0d, 0x1f, 0x99, 0x49, -0xcf, 0x5f, 0x99, 0x08, 0x44, 0x00, 0x2e, 0x39, -0x5a, 0x0b, 0x0d, 0x44, 0xcf, 0x0c, 0x41, 0x00, -0x5b, 0x1f, 0x20, 0x44, 0xaf, 0x5f, 0x9f, 0x04, -0x0d, 0x47, 0xcf, 0x5f, 0x9f, 0x48, 0xcf, 0x5f, -0x9f, 0x1c, 0xcf, 0x5f, 0x9f, 0x1d, 0xcf, 0x5f, -0x9f, 0x1e, 0xcf, 0x5f, 0x9f, 0x49, 0xcf, 0x5f, -0x9f, 0x06, 0x0d, 0xe0, 0x97, 0x0f, 0x1c, 0x5f, -0x9f, 0x0a, 0xcf, 0x5f, 0x9f, 0x09, 0xcf, 0x5f, -0x9f, 0x2a, 0xcf, 0x5f, 0x9f, 0x2b, 0xcf, 0x5f, -0x9f, 0x2c, 0xcf, 0x5f, 0x9f, 0x2d, 0xcf, 0x5f, -0x9f, 0x02, 0x0d, 0x16, 0xcf, 0x5f, 0x9f, 0x44, -0xdf, 0x02, 0x2e, 0x5f, 0x81, 0x5f, 0x9f, 0x4d, -0xcf, 0x5f, 0x9f, 0x09, 0x46, 0x04, 0x5b, 0x90, -0xcf, 0x5f, 0x9f, 0x91, 0xcf, 0x5f, 0x9f, 0x05, -0x50, 0x01, 0x0d, 0x6a, 0xcf, 0x09, 0x27, 0x69, -0xdf, 0x3f, 0x02, 0x5f, 0x9f, 0x05, 0x27 + 0x42, 0x8c, 0x00, + 0x61, 0x25, 0x53, 0x80, 0x01, + 0x0d, 0xf5, 0x97, 0xff, 0x0d, 0x1f, 0x99, 0x49, + 0xcf, 0x5f, 0x99, 0x08, 0x44, 0x00, 0x2e, 0x39, + 0x5a, 0x0b, 0x0d, 0x44, 0xcf, 0x0c, 0x41, 0x00, + 0x5b, 0x1f, 0x20, 0x44, 0xaf, 0x5f, 0x9f, 0x04, + 0x0d, 0x47, 0xcf, 0x5f, 0x9f, 0x48, 0xcf, 0x5f, + 0x9f, 0x1c, 0xcf, 0x5f, 0x9f, 0x1d, 0xcf, 0x5f, + 0x9f, 0x1e, 0xcf, 0x5f, 0x9f, 0x49, 0xcf, 0x5f, + 0x9f, 0x06, 0x0d, 0xe0, 0x97, 0x0f, 0x1c, 0x5f, + 0x9f, 0x0a, 0xcf, 0x5f, 0x9f, 0x09, 0xcf, 0x5f, + 0x9f, 0x2a, 0xcf, 0x5f, 0x9f, 0x2b, 0xcf, 0x5f, + 0x9f, 0x2c, 0xcf, 0x5f, 0x9f, 0x2d, 0xcf, 0x5f, + 0x9f, 0x02, 0x0d, 0x16, 0xcf, 0x5f, 0x9f, 0x44, + 0xdf, 0x02, 0x2e, 0x5f, 0x81, 0x5f, 0x9f, 0x4d, + 0xcf, 0x5f, 0x9f, 0x09, 0x46, 0x04, 0x5b, 0x90, + 0xcf, 0x5f, 0x9f, 0x91, 0xcf, 0x5f, 0x9f, 0x05, + 0x50, 0x01, 0x0d, 0x6a, 0xcf, 0x09, 0x27, 0x69, + 0xdf, 0x3f, 0x02, 0x5f, 0x9f, 0x05, 0x27 }; static const unsigned char pkt512[] = { -0x42, 0xca, 0x00, -0xa6, 0x25, 0x5c, 0x46, 0x00, -0x5b, 0xfb, 0x31, 0x2d, 0x8a, 0xa9, 0x89, 0xbe, -0x89, 0x06, 0x8a, 0x18, 0x89, 0x18, 0x89, 0x40, -0xcf, 0x41, 0xdf, 0x45, 0xaf, 0x46, 0xbf, 0x07, -0x38, 0x01, 0x5b, 0x01, 0x2e, 0xb7, 0x80, 0x3b, -0x40, 0x00, 0x2e, 0x42, 0x5b, 0x5c, 0x47, 0x00, -0x5a, 0xad, 0x89, 0x09, 0x46, 0x00, 0x5b, 0x75, -0x8d, 0xc9, 0x30, 0x41, 0x2e, 0x7a, 0xdf, 0x1f, -0x28, 0x41, 0x2e, 0x7a, 0xbf, 0xfb, 0x39, 0xfa, -0x33, 0xc8, 0x46, 0x10, 0x5b, 0xd0, 0x46, 0xfd, -0x5b, 0xd3, 0x45, 0xfd, 0x5a, 0xd3, 0x45, 0xfb, -0x5a, 0xd3, 0x45, 0xf9, 0x5a, 0xd3, 0x3c, 0x41, -0x2e, 0xa1, 0xdf, 0x9f, 0x28, 0x41, 0x2e, 0xa1, -0xbf, 0x02, 0x2e, 0xb0, 0x81, 0x0c, 0x78, 0x64, -0x81, 0xd3, 0x45, 0xe9, 0x5a, 0xd3, 0x3c, 0xc8, -0xcf, 0xdf, 0x22, 0x02, 0x55, 0xc7, 0xcf, 0xdf, -0x22, 0x02, 0x54, 0xd3, 0x33, 0xd3, 0x31, 0x64, -0x81, 0xf7, 0xef, 0x16, 0x80, 0xf8, 0xcf, 0x9f, -0x1c, 0xf8, 0xaf, 0xfb, 0x39, 0xfa, 0x33, 0x5c, -0x47, 0x03, 0x5a, 0x08, 0x43, 0xdc, 0x2f, 0xec, -0x5a, 0x02, 0x50, 0x3d, 0x23, 0xdc, 0x2f, 0xe8, -0x50, 0x02, 0xcf, 0x0f, 0x1c, 0x10, 0x18, 0x02, -0xaf, 0xe1, 0x72, 0x5c, 0x46, 0x01, 0x5a, 0x01, -0x2e, 0xcd, 0x80, 0xd0, 0x41, 0x00, 0x5b, 0xc1, -0x83, 0x52, 0x26, 0xe6, 0x2f, 0xbd, 0x55, 0x53, -0x26, 0xe6, 0x2f, 0xba, 0x55 + 0x42, 0xca, 0x00, + 0xa6, 0x25, 0x5c, 0x46, 0x00, + 0x5b, 0xfb, 0x31, 0x2d, 0x8a, 0xa9, 0x89, 0xbe, + 0x89, 0x06, 0x8a, 0x18, 0x89, 0x18, 0x89, 0x40, + 0xcf, 0x41, 0xdf, 0x45, 0xaf, 0x46, 0xbf, 0x07, + 0x38, 0x01, 0x5b, 0x01, 0x2e, 0xb7, 0x80, 0x3b, + 0x40, 0x00, 0x2e, 0x42, 0x5b, 0x5c, 0x47, 0x00, + 0x5a, 0xad, 0x89, 0x09, 0x46, 0x00, 0x5b, 0x75, + 0x8d, 0xc9, 0x30, 0x41, 0x2e, 0x7a, 0xdf, 0x1f, + 0x28, 0x41, 0x2e, 0x7a, 0xbf, 0xfb, 0x39, 0xfa, + 0x33, 0xc8, 0x46, 0x10, 0x5b, 0xd0, 0x46, 0xfd, + 0x5b, 0xd3, 0x45, 0xfd, 0x5a, 0xd3, 0x45, 0xfb, + 0x5a, 0xd3, 0x45, 0xf9, 0x5a, 0xd3, 0x3c, 0x41, + 0x2e, 0xa1, 0xdf, 0x9f, 0x28, 0x41, 0x2e, 0xa1, + 0xbf, 0x02, 0x2e, 0xb0, 0x81, 0x0c, 0x78, 0x64, + 0x81, 0xd3, 0x45, 0xe9, 0x5a, 0xd3, 0x3c, 0xc8, + 0xcf, 0xdf, 0x22, 0x02, 0x55, 0xc7, 0xcf, 0xdf, + 0x22, 0x02, 0x54, 0xd3, 0x33, 0xd3, 0x31, 0x64, + 0x81, 0xf7, 0xef, 0x16, 0x80, 0xf8, 0xcf, 0x9f, + 0x1c, 0xf8, 0xaf, 0xfb, 0x39, 0xfa, 0x33, 0x5c, + 0x47, 0x03, 0x5a, 0x08, 0x43, 0xdc, 0x2f, 0xec, + 0x5a, 0x02, 0x50, 0x3d, 0x23, 0xdc, 0x2f, 0xe8, + 0x50, 0x02, 0xcf, 0x0f, 0x1c, 0x10, 0x18, 0x02, + 0xaf, 0xe1, 0x72, 0x5c, 0x46, 0x01, 0x5a, 0x01, + 0x2e, 0xcd, 0x80, 0xd0, 0x41, 0x00, 0x5b, 0xc1, + 0x83, 0x52, 0x26, 0xe6, 0x2f, 0xbd, 0x55, 0x53, + 0x26, 0xe6, 0x2f, 0xba, 0x55 }; static const unsigned char pkt516[] = { -0x42, 0xca, 0x00, -0x0a, 0x26, 0x07, 0x3a, 0x00, -0x2e, 0x38, 0x7c, 0x02, 0x2e, 0x49, 0x81, 0x45, -0xcf, 0x46, 0xdf, 0x19, 0x27, 0xef, 0x88, 0x02, -0x89, 0x05, 0x27, 0x12, 0x82, 0x05, 0x27, 0x41, -0x8a, 0x10, 0x5b, 0x49, 0xef, 0xff, 0xaf, 0x05, -0xef, 0xff, 0xaf, 0x9f, 0x22, 0xff, 0xaf, 0x10, -0xef, 0xff, 0xaf, 0x22, 0xcf, 0xff, 0xaf, 0x23, -0xcf, 0xff, 0xaf, 0x9f, 0x22, 0xff, 0xaf, 0xff, -0xaf, 0x02, 0x2e, 0xa1, 0x81, 0x0c, 0x40, 0x29, -0x5b, 0x4a, 0x80, 0x0d, 0x34, 0x10, 0x5a, 0x49, -0xcf, 0x5f, 0x9d, 0x49, 0x38, 0x53, 0x80, 0x49, -0xcf, 0x5f, 0x9d, 0x4a, 0x80, 0x9f, 0x22, 0x1f, -0x9c, 0x5f, 0x9c, 0x1e, 0xcf, 0x1f, 0x9d, 0x48, -0xcf, 0x1d, 0xdf, 0xdf, 0x01, 0x9f, 0x22, 0x11, -0x50, 0xbb, 0x88, 0xf5, 0x97, 0x49, 0xaf, 0xd4, -0x89, 0x49, 0xcf, 0xf7, 0x1c, 0x5f, 0x9d, 0x44, -0xdf, 0x3f, 0x20, 0x44, 0xbf, 0xff, 0x9a, 0x02, -0x2e, 0x5f, 0x81, 0x20, 0x0d, 0x9f, 0x99, 0xe0, -0x0d, 0x1c, 0xcf, 0x1d, 0xdf, 0x9f, 0x9c, 0xff, -0x9c, 0x00, 0x2e, 0xe9, 0x8f, 0x0c, 0x41, 0x01, -0x5b, 0x00, 0x2e, 0xeb, 0x8f, 0x0c, 0x42, 0x04, -0x5b, 0xe4, 0x40, 0x01, 0x5a, 0xe4, 0x3a, 0x00, -0x50, 0xe4, 0x32, 0x0c, 0x43, 0x04, 0x5b, 0xe4, -0x42, 0x01, 0x5a, 0xe4, 0x30, 0x00, 0x50, 0xe4, -0x38, 0x0c, 0x44, 0x10, 0x5b, 0x18, 0x23, 0x1a, -0x23, 0x1b, 0x23, 0xe4, 0x42 + 0x42, 0xca, 0x00, + 0x0a, 0x26, 0x07, 0x3a, 0x00, + 0x2e, 0x38, 0x7c, 0x02, 0x2e, 0x49, 0x81, 0x45, + 0xcf, 0x46, 0xdf, 0x19, 0x27, 0xef, 0x88, 0x02, + 0x89, 0x05, 0x27, 0x12, 0x82, 0x05, 0x27, 0x41, + 0x8a, 0x10, 0x5b, 0x49, 0xef, 0xff, 0xaf, 0x05, + 0xef, 0xff, 0xaf, 0x9f, 0x22, 0xff, 0xaf, 0x10, + 0xef, 0xff, 0xaf, 0x22, 0xcf, 0xff, 0xaf, 0x23, + 0xcf, 0xff, 0xaf, 0x9f, 0x22, 0xff, 0xaf, 0xff, + 0xaf, 0x02, 0x2e, 0xa1, 0x81, 0x0c, 0x40, 0x29, + 0x5b, 0x4a, 0x80, 0x0d, 0x34, 0x10, 0x5a, 0x49, + 0xcf, 0x5f, 0x9d, 0x49, 0x38, 0x53, 0x80, 0x49, + 0xcf, 0x5f, 0x9d, 0x4a, 0x80, 0x9f, 0x22, 0x1f, + 0x9c, 0x5f, 0x9c, 0x1e, 0xcf, 0x1f, 0x9d, 0x48, + 0xcf, 0x1d, 0xdf, 0xdf, 0x01, 0x9f, 0x22, 0x11, + 0x50, 0xbb, 0x88, 0xf5, 0x97, 0x49, 0xaf, 0xd4, + 0x89, 0x49, 0xcf, 0xf7, 0x1c, 0x5f, 0x9d, 0x44, + 0xdf, 0x3f, 0x20, 0x44, 0xbf, 0xff, 0x9a, 0x02, + 0x2e, 0x5f, 0x81, 0x20, 0x0d, 0x9f, 0x99, 0xe0, + 0x0d, 0x1c, 0xcf, 0x1d, 0xdf, 0x9f, 0x9c, 0xff, + 0x9c, 0x00, 0x2e, 0xe9, 0x8f, 0x0c, 0x41, 0x01, + 0x5b, 0x00, 0x2e, 0xeb, 0x8f, 0x0c, 0x42, 0x04, + 0x5b, 0xe4, 0x40, 0x01, 0x5a, 0xe4, 0x3a, 0x00, + 0x50, 0xe4, 0x32, 0x0c, 0x43, 0x04, 0x5b, 0xe4, + 0x42, 0x01, 0x5a, 0xe4, 0x30, 0x00, 0x50, 0xe4, + 0x38, 0x0c, 0x44, 0x10, 0x5b, 0x18, 0x23, 0x1a, + 0x23, 0x1b, 0x23, 0xe4, 0x42 }; static const unsigned char pkt520[] = { -0x42, 0xca, 0x00, -0x6e, 0x26, 0x01, 0x5a, 0xe4, -0x38, 0x00, 0x50, 0xe4, 0x30, 0x4a, 0x80, 0x2b, -0x0d, 0x02, 0x2e, 0x9d, 0x81, 0xe4, 0x42, 0x01, -0x5a, 0xe4, 0x30, 0x00, 0x50, 0xe4, 0x38, 0x0c, -0x45, 0x00, 0x5b, 0x0f, 0x88, 0x0c, 0x46, 0x01, -0x5a, 0x01, 0x2e, 0xb7, 0x80, 0x0c, 0x43, 0x05, -0x5b, 0x0c, 0x45, 0x03, 0x5b, 0x0d, 0x45, 0x01, -0x5b, 0x0d, 0x37, 0x05, 0x27, 0x0c, 0x40, 0x00, -0x5b, 0x0d, 0x3f, 0x05, 0x27, 0x60, 0xcf, 0x0f, -0x1c, 0xdf, 0x9f, 0x0c, 0x1c, 0x12, 0x82, 0x03, -0x1d, 0x19, 0x82, 0x5f, 0x02, 0x60, 0xcf, 0xf0, -0x1c, 0x3f, 0x02, 0x60, 0xaf, 0x05, 0x27, 0x28, -0xff, 0x64, 0xef, 0x19, 0x27, 0x01, 0xff, 0x5a, -0xef, 0x1b, 0x27, 0x06, 0xef, 0x06, 0xaf, 0xfc, -0x97, 0x5f, 0x9f, 0x06, 0x25, 0xfb, 0x55, 0x05, -0x27, 0x10, 0xcf, 0x72, 0xaf, 0x0a, 0x40, 0x13, -0x5a, 0x27, 0xcf, 0x10, 0xaf, 0x07, 0x43, 0x08, -0x5b, 0x3b, 0x31, 0x02, 0x5b, 0x3b, 0x36, 0x3b, -0x43, 0x03, 0x5b, 0x6e, 0xcf, 0xe2, 0xaf, 0x6f, -0xcf, 0xe3, 0xaf, 0x02, 0x2e, 0xd5, 0x80, 0x07, -0x40, 0x02, 0x5a, 0x61, 0x26, 0x00, 0x55, 0x07, -0x33, 0x88, 0x82, 0x02, 0x43, 0xdb, 0x2f, 0xc7, -0x5b, 0x02, 0x2e, 0x72, 0x80, 0x05, 0x27, 0x05, -0x27, 0x05, 0x27, 0x0c, 0xcf, 0x03, 0x1c, 0x0b, -0x55, 0x0c, 0xcf, 0x0c, 0x1c, 0x0c, 0x1e, 0x07, -0x54, 0x08, 0x1e, 0x03, 0x55 + 0x42, 0xca, 0x00, + 0x6e, 0x26, 0x01, 0x5a, 0xe4, + 0x38, 0x00, 0x50, 0xe4, 0x30, 0x4a, 0x80, 0x2b, + 0x0d, 0x02, 0x2e, 0x9d, 0x81, 0xe4, 0x42, 0x01, + 0x5a, 0xe4, 0x30, 0x00, 0x50, 0xe4, 0x38, 0x0c, + 0x45, 0x00, 0x5b, 0x0f, 0x88, 0x0c, 0x46, 0x01, + 0x5a, 0x01, 0x2e, 0xb7, 0x80, 0x0c, 0x43, 0x05, + 0x5b, 0x0c, 0x45, 0x03, 0x5b, 0x0d, 0x45, 0x01, + 0x5b, 0x0d, 0x37, 0x05, 0x27, 0x0c, 0x40, 0x00, + 0x5b, 0x0d, 0x3f, 0x05, 0x27, 0x60, 0xcf, 0x0f, + 0x1c, 0xdf, 0x9f, 0x0c, 0x1c, 0x12, 0x82, 0x03, + 0x1d, 0x19, 0x82, 0x5f, 0x02, 0x60, 0xcf, 0xf0, + 0x1c, 0x3f, 0x02, 0x60, 0xaf, 0x05, 0x27, 0x28, + 0xff, 0x64, 0xef, 0x19, 0x27, 0x01, 0xff, 0x5a, + 0xef, 0x1b, 0x27, 0x06, 0xef, 0x06, 0xaf, 0xfc, + 0x97, 0x5f, 0x9f, 0x06, 0x25, 0xfb, 0x55, 0x05, + 0x27, 0x10, 0xcf, 0x72, 0xaf, 0x0a, 0x40, 0x13, + 0x5a, 0x27, 0xcf, 0x10, 0xaf, 0x07, 0x43, 0x08, + 0x5b, 0x3b, 0x31, 0x02, 0x5b, 0x3b, 0x36, 0x3b, + 0x43, 0x03, 0x5b, 0x6e, 0xcf, 0xe2, 0xaf, 0x6f, + 0xcf, 0xe3, 0xaf, 0x02, 0x2e, 0xd5, 0x80, 0x07, + 0x40, 0x02, 0x5a, 0x61, 0x26, 0x00, 0x55, 0x07, + 0x33, 0x88, 0x82, 0x02, 0x43, 0xdb, 0x2f, 0xc7, + 0x5b, 0x02, 0x2e, 0x72, 0x80, 0x05, 0x27, 0x05, + 0x27, 0x05, 0x27, 0x0c, 0xcf, 0x03, 0x1c, 0x0b, + 0x55, 0x0c, 0xcf, 0x0c, 0x1c, 0x0c, 0x1e, 0x07, + 0x54, 0x08, 0x1e, 0x03, 0x55 }; static const unsigned char pkt524[] = { -0x42, 0xca, 0x00, -0xd2, 0x26, 0x0c, 0x45, 0x01, -0x5b, 0x0d, 0x44, 0x01, 0x5b, 0x0e, 0x33, 0x05, -0x27, 0x0e, 0x3b, 0x05, 0x27, 0x0d, 0xcf, 0x06, -0x1c, 0x09, 0x55, 0x09, 0x46, 0x04, 0x5b, 0x15, -0x88, 0x02, 0x5a, 0xf2, 0xcf, 0x0b, 0xaf, 0x10, -0x50, 0x02, 0xef, 0x0c, 0xaf, 0x0d, 0x50, 0x0a, -0x41, 0x0b, 0x5b, 0x0c, 0x39, 0x0c, 0x46, 0x03, -0x5b, 0x4a, 0x80, 0x0e, 0x88, 0x29, 0x89, 0x00, -0x50, 0x0c, 0x31, 0x0c, 0x38, 0x01, 0x5b, 0x0d, -0x3f, 0x0d, 0x34, 0x05, 0x27, 0x23, 0x26, 0x02, -0x55, 0x22, 0xcf, 0xc8, 0x1e, 0x00, 0x5f, 0x0c, -0x27, 0x0d, 0x27, 0xf0, 0x97, 0x47, 0xaf, 0xf1, -0x97, 0x48, 0xaf, 0x05, 0x27, 0x46, 0x80, 0x08, -0x46, 0x0f, 0x5a, 0xde, 0xef, 0x5f, 0x9f, 0x10, -0xef, 0x5f, 0x9f, 0x00, 0xef, 0x5f, 0x9f, 0x28, -0xff, 0x54, 0xef, 0x1b, 0x27, 0x10, 0xef, 0x06, -0xaf, 0xfc, 0x97, 0x5f, 0x9f, 0x06, 0x25, 0xfb, -0x55, 0x62, 0x80, 0x05, 0x27, 0x46, 0x80, 0x08, -0x47, 0xfb, 0x5a, 0xdf, 0xef, 0x5f, 0x9f, 0x06, -0xef, 0x5f, 0x9f, 0x00, 0xef, 0x5f, 0x9f, 0x28, -0xff, 0x64, 0xef, 0x1b, 0x27, 0x06, 0xef, 0x06, -0xaf, 0xea, 0x50, 0x28, 0xff, 0x64, 0xef, 0x19, -0x27, 0x0f, 0xef, 0x6b, 0xdf, 0xff, 0x96, 0xbf, -0x22, 0xff, 0x96, 0x7b, 0x00, 0xc1, 0x03, 0x6b, -0xbf, 0x0c, 0x53, 0xdf, 0x96, 0xc2, 0x97, 0xbf, -0x01, 0x5f, 0x90, 0xdd, 0x97 + 0x42, 0xca, 0x00, + 0xd2, 0x26, 0x0c, 0x45, 0x01, + 0x5b, 0x0d, 0x44, 0x01, 0x5b, 0x0e, 0x33, 0x05, + 0x27, 0x0e, 0x3b, 0x05, 0x27, 0x0d, 0xcf, 0x06, + 0x1c, 0x09, 0x55, 0x09, 0x46, 0x04, 0x5b, 0x15, + 0x88, 0x02, 0x5a, 0xf2, 0xcf, 0x0b, 0xaf, 0x10, + 0x50, 0x02, 0xef, 0x0c, 0xaf, 0x0d, 0x50, 0x0a, + 0x41, 0x0b, 0x5b, 0x0c, 0x39, 0x0c, 0x46, 0x03, + 0x5b, 0x4a, 0x80, 0x0e, 0x88, 0x29, 0x89, 0x00, + 0x50, 0x0c, 0x31, 0x0c, 0x38, 0x01, 0x5b, 0x0d, + 0x3f, 0x0d, 0x34, 0x05, 0x27, 0x23, 0x26, 0x02, + 0x55, 0x22, 0xcf, 0xc8, 0x1e, 0x00, 0x5f, 0x0c, + 0x27, 0x0d, 0x27, 0xf0, 0x97, 0x47, 0xaf, 0xf1, + 0x97, 0x48, 0xaf, 0x05, 0x27, 0x46, 0x80, 0x08, + 0x46, 0x0f, 0x5a, 0xde, 0xef, 0x5f, 0x9f, 0x10, + 0xef, 0x5f, 0x9f, 0x00, 0xef, 0x5f, 0x9f, 0x28, + 0xff, 0x54, 0xef, 0x1b, 0x27, 0x10, 0xef, 0x06, + 0xaf, 0xfc, 0x97, 0x5f, 0x9f, 0x06, 0x25, 0xfb, + 0x55, 0x62, 0x80, 0x05, 0x27, 0x46, 0x80, 0x08, + 0x47, 0xfb, 0x5a, 0xdf, 0xef, 0x5f, 0x9f, 0x06, + 0xef, 0x5f, 0x9f, 0x00, 0xef, 0x5f, 0x9f, 0x28, + 0xff, 0x64, 0xef, 0x1b, 0x27, 0x06, 0xef, 0x06, + 0xaf, 0xea, 0x50, 0x28, 0xff, 0x64, 0xef, 0x19, + 0x27, 0x0f, 0xef, 0x6b, 0xdf, 0xff, 0x96, 0xbf, + 0x22, 0xff, 0x96, 0x7b, 0x00, 0xc1, 0x03, 0x6b, + 0xbf, 0x0c, 0x53, 0xdf, 0x96, 0xc2, 0x97, 0xbf, + 0x01, 0x5f, 0x90, 0xdd, 0x97 }; static const unsigned char pkt528[] = { -0x42, 0xca, 0x00, -0x36, 0x27, 0x5f, 0x20, 0x02, -0x1e, 0xf3, 0x53, 0x02, 0xef, 0x01, 0x0c, 0xdd, -0x9f, 0x6b, 0xbf, 0x15, 0x50, 0xdf, 0x96, 0xc2, -0x97, 0xdf, 0x01, 0xc1, 0x03, 0x05, 0x52, 0xdd, -0x97, 0x1f, 0x20, 0x6b, 0xdf, 0xe0, 0x01, 0x6b, -0xbf, 0x00, 0x50, 0xdd, 0x97, 0x02, 0x0c, 0x6b, -0xdf, 0x28, 0x1f, 0x01, 0x53, 0x28, 0xff, 0x6b, -0xbf, 0x68, 0x1f, 0x01, 0x5f, 0x68, 0xff, 0x6b, -0xbf, 0x05, 0x27, 0x01, 0x81, 0x50, 0x8f, 0xf1, -0x88, 0x05, 0x81, 0x00, 0x2e, 0x32, 0x8d, 0x01, -0x2e, 0x06, 0x80, 0x00, 0x2e, 0xd8, 0x8e, 0x5c, -0x47, 0x02, 0x5b, 0x00, 0x2e, 0x16, 0x8f, 0x01, -0x50, 0x00, 0x2e, 0x14, 0x8f, 0x08, 0xef, 0x0f, -0x80, 0x01, 0x2e, 0x54, 0x80, 0x05, 0x27, 0x07, -0x40, 0x01, 0x5b, 0x54, 0x23, 0x18, 0x50, 0x9c, -0x8e, 0x0d, 0xcf, 0x06, 0x1c, 0x08, 0x54, 0x14, -0x88, 0x02, 0x2e, 0x9d, 0x81, 0x01, 0x2e, 0x50, -0x82, 0x4f, 0x8f, 0x68, 0x88, 0x01, 0x2e, 0x44, -0x84, 0x5c, 0x8f, 0x54, 0x88, 0x09, 0x46, 0x02, -0x5b, 0x37, 0x82, 0x90, 0xaf, 0x91, 0xbf, 0x00, -0x2e, 0xe6, 0x8f, 0x90, 0x8e, 0x0c, 0x3e, 0xed, -0x5a, 0x05, 0x27, 0x37, 0x82, 0x4a, 0x82, 0x1c, -0x82, 0x1c, 0x82, 0x9d, 0xbf, 0xff, 0x97, 0x08, -0x10, 0x09, 0x27, 0x0f, 0x1c, 0x5c, 0x46, 0x03, -0x5b, 0x02, 0x1e, 0x04, 0x53, 0x02, 0xef, 0x02, -0x50, 0x03, 0x1e, 0x00, 0x53 + 0x42, 0xca, 0x00, + 0x36, 0x27, 0x5f, 0x20, 0x02, + 0x1e, 0xf3, 0x53, 0x02, 0xef, 0x01, 0x0c, 0xdd, + 0x9f, 0x6b, 0xbf, 0x15, 0x50, 0xdf, 0x96, 0xc2, + 0x97, 0xdf, 0x01, 0xc1, 0x03, 0x05, 0x52, 0xdd, + 0x97, 0x1f, 0x20, 0x6b, 0xdf, 0xe0, 0x01, 0x6b, + 0xbf, 0x00, 0x50, 0xdd, 0x97, 0x02, 0x0c, 0x6b, + 0xdf, 0x28, 0x1f, 0x01, 0x53, 0x28, 0xff, 0x6b, + 0xbf, 0x68, 0x1f, 0x01, 0x5f, 0x68, 0xff, 0x6b, + 0xbf, 0x05, 0x27, 0x01, 0x81, 0x50, 0x8f, 0xf1, + 0x88, 0x05, 0x81, 0x00, 0x2e, 0x32, 0x8d, 0x01, + 0x2e, 0x06, 0x80, 0x00, 0x2e, 0xd8, 0x8e, 0x5c, + 0x47, 0x02, 0x5b, 0x00, 0x2e, 0x16, 0x8f, 0x01, + 0x50, 0x00, 0x2e, 0x14, 0x8f, 0x08, 0xef, 0x0f, + 0x80, 0x01, 0x2e, 0x54, 0x80, 0x05, 0x27, 0x07, + 0x40, 0x01, 0x5b, 0x54, 0x23, 0x18, 0x50, 0x9c, + 0x8e, 0x0d, 0xcf, 0x06, 0x1c, 0x08, 0x54, 0x14, + 0x88, 0x02, 0x2e, 0x9d, 0x81, 0x01, 0x2e, 0x50, + 0x82, 0x4f, 0x8f, 0x68, 0x88, 0x01, 0x2e, 0x44, + 0x84, 0x5c, 0x8f, 0x54, 0x88, 0x09, 0x46, 0x02, + 0x5b, 0x37, 0x82, 0x90, 0xaf, 0x91, 0xbf, 0x00, + 0x2e, 0xe6, 0x8f, 0x90, 0x8e, 0x0c, 0x3e, 0xed, + 0x5a, 0x05, 0x27, 0x37, 0x82, 0x4a, 0x82, 0x1c, + 0x82, 0x1c, 0x82, 0x9d, 0xbf, 0xff, 0x97, 0x08, + 0x10, 0x09, 0x27, 0x0f, 0x1c, 0x5c, 0x46, 0x03, + 0x5b, 0x02, 0x1e, 0x04, 0x53, 0x02, 0xef, 0x02, + 0x50, 0x03, 0x1e, 0x00, 0x53 }; static const unsigned char pkt532[] = { -0x42, 0xca, 0x00, -0x9a, 0x27, 0x03, 0xef, 0x69, -0xaf, 0x53, 0x80, 0x1b, 0x0d, 0xe1, 0x97, 0x0f, -0x1c, 0x69, 0xdf, 0xdf, 0x01, 0x00, 0x53, 0x00, -0xff, 0xe0, 0x97, 0x8a, 0x80, 0x04, 0x10, 0x11, -0x82, 0x0f, 0x1e, 0x00, 0x5f, 0x0f, 0xef, 0x6a, -0xaf, 0xc1, 0x2e, 0x47, 0xdf, 0xf0, 0x1d, 0x5f, -0x02, 0xc1, 0x2e, 0x47, 0xbf, 0x10, 0x0d, 0x05, -0x27, 0x01, 0x2e, 0x56, 0x80, 0xf7, 0xef, 0x16, -0x80, 0x66, 0x80, 0x20, 0x82, 0xdf, 0x8e, 0x02, -0x2e, 0x3e, 0x81, 0x02, 0x2e, 0x93, 0x81, 0x00, -0x2e, 0xb4, 0x8e, 0x5c, 0x47, 0x09, 0x5b, 0x6c, -0x38, 0x3b, 0x43, 0x00, 0x5b, 0x6c, 0x30, 0x41, -0x2e, 0x71, 0xdf, 0xc1, 0x2e, 0x72, 0xdf, 0xbf, -0x03, 0x01, 0x55, 0x00, 0x2e, 0xc7, 0x8e, 0x67, -0x8c, 0x01, 0x2e, 0xcd, 0x80, 0x05, 0x27, 0x3b, -0x40, 0x01, 0x5b, 0x02, 0xef, 0x0c, 0xaf, 0x05, -0x27, 0x52, 0xcf, 0xcb, 0xaf, 0x53, 0xdf, 0xcc, -0xbf, 0xdf, 0x22, 0x01, 0x55, 0xff, 0x22, 0x01, -0x54, 0x0e, 0xef, 0xc9, 0xaf, 0x05, 0x27, 0x0e, -0xcf, 0x6e, 0x1c, 0x49, 0xdf, 0x10, 0x1d, 0x3f, -0x02, 0x49, 0xaf, 0x0d, 0x44, 0x06, 0x5a, 0x0a, -0x41, 0x03, 0x5b, 0x49, 0x43, 0x02, 0x5a, 0x48, -0x26, 0x00, 0x55, 0x49, 0x30, 0x9f, 0x2c, 0x05, -0x5a, 0xdf, 0x2c, 0x4c, 0x5a, 0x0e, 0x41, 0x15, -0x5b, 0x0c, 0x46, 0x13, 0x5a, 0x9f, 0x22, 0x1c, -0xaf, 0x21, 0xaf, 0x45, 0x88 + 0x42, 0xca, 0x00, + 0x9a, 0x27, 0x03, 0xef, 0x69, + 0xaf, 0x53, 0x80, 0x1b, 0x0d, 0xe1, 0x97, 0x0f, + 0x1c, 0x69, 0xdf, 0xdf, 0x01, 0x00, 0x53, 0x00, + 0xff, 0xe0, 0x97, 0x8a, 0x80, 0x04, 0x10, 0x11, + 0x82, 0x0f, 0x1e, 0x00, 0x5f, 0x0f, 0xef, 0x6a, + 0xaf, 0xc1, 0x2e, 0x47, 0xdf, 0xf0, 0x1d, 0x5f, + 0x02, 0xc1, 0x2e, 0x47, 0xbf, 0x10, 0x0d, 0x05, + 0x27, 0x01, 0x2e, 0x56, 0x80, 0xf7, 0xef, 0x16, + 0x80, 0x66, 0x80, 0x20, 0x82, 0xdf, 0x8e, 0x02, + 0x2e, 0x3e, 0x81, 0x02, 0x2e, 0x93, 0x81, 0x00, + 0x2e, 0xb4, 0x8e, 0x5c, 0x47, 0x09, 0x5b, 0x6c, + 0x38, 0x3b, 0x43, 0x00, 0x5b, 0x6c, 0x30, 0x41, + 0x2e, 0x71, 0xdf, 0xc1, 0x2e, 0x72, 0xdf, 0xbf, + 0x03, 0x01, 0x55, 0x00, 0x2e, 0xc7, 0x8e, 0x67, + 0x8c, 0x01, 0x2e, 0xcd, 0x80, 0x05, 0x27, 0x3b, + 0x40, 0x01, 0x5b, 0x02, 0xef, 0x0c, 0xaf, 0x05, + 0x27, 0x52, 0xcf, 0xcb, 0xaf, 0x53, 0xdf, 0xcc, + 0xbf, 0xdf, 0x22, 0x01, 0x55, 0xff, 0x22, 0x01, + 0x54, 0x0e, 0xef, 0xc9, 0xaf, 0x05, 0x27, 0x0e, + 0xcf, 0x6e, 0x1c, 0x49, 0xdf, 0x10, 0x1d, 0x3f, + 0x02, 0x49, 0xaf, 0x0d, 0x44, 0x06, 0x5a, 0x0a, + 0x41, 0x03, 0x5b, 0x49, 0x43, 0x02, 0x5a, 0x48, + 0x26, 0x00, 0x55, 0x49, 0x30, 0x9f, 0x2c, 0x05, + 0x5a, 0xdf, 0x2c, 0x4c, 0x5a, 0x0e, 0x41, 0x15, + 0x5b, 0x0c, 0x46, 0x13, 0x5a, 0x9f, 0x22, 0x1c, + 0xaf, 0x21, 0xaf, 0x45, 0x88 }; static const unsigned char pkt536[] = { -0x42, 0xca, 0x00, -0xfe, 0x27, 0x03, 0x5a, 0x9f, -0x2c, 0x05, 0x5a, 0x9f, 0x22, 0x04, 0x50, 0x9f, -0x22, 0x0e, 0x3e, 0x0e, 0x3d, 0x00, 0x5b, 0x5f, -0xef, 0x1d, 0xaf, 0x49, 0xcf, 0x87, 0x1c, 0x01, -0x18, 0x49, 0xaf, 0x34, 0x50, 0x20, 0x26, 0x08, -0x55, 0x1f, 0xcf, 0x48, 0xdf, 0xff, 0x2d, 0x00, -0x5b, 0xff, 0x21, 0x3f, 0x00, 0x00, 0x53, 0xff, -0xef, 0x1f, 0xaf, 0x47, 0xdf, 0x1c, 0xcf, 0x3f, -0x00, 0x1c, 0xaf, 0x1d, 0xcf, 0x48, 0xdf, 0x3f, -0x00, 0x1d, 0xaf, 0xff, 0x22, 0x1f, 0x54, 0xff, -0x2d, 0x03, 0x5b, 0xff, 0x1e, 0x19, 0x5b, 0x60, -0x10, 0x02, 0x50, 0x60, 0x1e, 0x0a, 0x52, 0x60, -0x16, 0x1d, 0xaf, 0x49, 0x30, 0x49, 0x3c, 0x12, -0x5b, 0x21, 0xcf, 0x47, 0xdf, 0x3f, 0x00, 0x1c, -0xaf, 0x21, 0x23, 0x0c, 0x50, 0x59, 0x1e, 0x0a, -0x52, 0x49, 0x34, 0x01, 0x5a, 0x21, 0x23, 0x06, -0x50, 0x21, 0xcf, 0x47, 0xdf, 0x3f, 0x00, 0x21, -0xaf, 0x01, 0x50, 0x06, 0x1e, 0xf4, 0x5f, 0x05, -0x27, 0x0d, 0xcf, 0x06, 0x1c, 0x06, 0x1e, 0x00, -0x54, 0x0d, 0x27, 0x0c, 0x27, 0x09, 0x46, 0x0c, -0x5b, 0xa8, 0x8e, 0x07, 0x52, 0x0f, 0xcf, 0x01, -0x16, 0x02, 0x53, 0x02, 0x2e, 0x36, 0x83, 0x04, -0x50, 0xf4, 0xaf, 0x02, 0x50, 0xf2, 0xcf, 0x02, -0x10, 0x0f, 0xaf, 0x05, 0x27, 0x5a, 0xcf, 0xdf, -0x22, 0x10, 0x54, 0x3e, 0xdf, 0x3f, 0x20, 0x3f, -0x1f, 0x0a, 0x52, 0xbf, 0x22 + 0x42, 0xca, 0x00, + 0xfe, 0x27, 0x03, 0x5a, 0x9f, + 0x2c, 0x05, 0x5a, 0x9f, 0x22, 0x04, 0x50, 0x9f, + 0x22, 0x0e, 0x3e, 0x0e, 0x3d, 0x00, 0x5b, 0x5f, + 0xef, 0x1d, 0xaf, 0x49, 0xcf, 0x87, 0x1c, 0x01, + 0x18, 0x49, 0xaf, 0x34, 0x50, 0x20, 0x26, 0x08, + 0x55, 0x1f, 0xcf, 0x48, 0xdf, 0xff, 0x2d, 0x00, + 0x5b, 0xff, 0x21, 0x3f, 0x00, 0x00, 0x53, 0xff, + 0xef, 0x1f, 0xaf, 0x47, 0xdf, 0x1c, 0xcf, 0x3f, + 0x00, 0x1c, 0xaf, 0x1d, 0xcf, 0x48, 0xdf, 0x3f, + 0x00, 0x1d, 0xaf, 0xff, 0x22, 0x1f, 0x54, 0xff, + 0x2d, 0x03, 0x5b, 0xff, 0x1e, 0x19, 0x5b, 0x60, + 0x10, 0x02, 0x50, 0x60, 0x1e, 0x0a, 0x52, 0x60, + 0x16, 0x1d, 0xaf, 0x49, 0x30, 0x49, 0x3c, 0x12, + 0x5b, 0x21, 0xcf, 0x47, 0xdf, 0x3f, 0x00, 0x1c, + 0xaf, 0x21, 0x23, 0x0c, 0x50, 0x59, 0x1e, 0x0a, + 0x52, 0x49, 0x34, 0x01, 0x5a, 0x21, 0x23, 0x06, + 0x50, 0x21, 0xcf, 0x47, 0xdf, 0x3f, 0x00, 0x21, + 0xaf, 0x01, 0x50, 0x06, 0x1e, 0xf4, 0x5f, 0x05, + 0x27, 0x0d, 0xcf, 0x06, 0x1c, 0x06, 0x1e, 0x00, + 0x54, 0x0d, 0x27, 0x0c, 0x27, 0x09, 0x46, 0x0c, + 0x5b, 0xa8, 0x8e, 0x07, 0x52, 0x0f, 0xcf, 0x01, + 0x16, 0x02, 0x53, 0x02, 0x2e, 0x36, 0x83, 0x04, + 0x50, 0xf4, 0xaf, 0x02, 0x50, 0xf2, 0xcf, 0x02, + 0x10, 0x0f, 0xaf, 0x05, 0x27, 0x5a, 0xcf, 0xdf, + 0x22, 0x10, 0x54, 0x3e, 0xdf, 0x3f, 0x20, 0x3f, + 0x1f, 0x0a, 0x52, 0xbf, 0x22 }; static const unsigned char pkt540[] = { -0x42, 0x50, 0x00, -0x62, 0x28, 0x3e, 0xbf, 0x3d, -0xdf, 0x3f, 0x20, 0xdf, 0x03, 0x02, 0x52, 0xbf, -0x22, 0x3d, 0xbf, 0x0c, 0x27, 0x3d, 0xbf, 0x0d, -0x27, 0x3e, 0xbf, 0x0d, 0x27, 0x0d, 0x27, 0x0f, -0x1c, 0x69, 0xdf, 0xdf, 0x01, 0x00, 0x53, 0x00, -0xff, 0x05, 0x27, 0x37, 0x82, 0x4a, 0x82, 0x1c, -0x82, 0x1c, 0x82, 0x9d, 0xbf, 0xff, 0x97, 0x08, -0x10, 0x09, 0x27, 0x0f, 0x1c, 0x5c, 0x46, 0x03, -0x5b, 0x02, 0x1e, 0x04, 0x53, 0x02, 0xef, 0x02, -0x50, 0x03, 0x1e, 0x00, 0x53, 0x03, 0xef, 0x69, -0xaf, 0x05, 0x27 + 0x42, 0x50, 0x00, + 0x62, 0x28, 0x3e, 0xbf, 0x3d, + 0xdf, 0x3f, 0x20, 0xdf, 0x03, 0x02, 0x52, 0xbf, + 0x22, 0x3d, 0xbf, 0x0c, 0x27, 0x3d, 0xbf, 0x0d, + 0x27, 0x3e, 0xbf, 0x0d, 0x27, 0x0d, 0x27, 0x0f, + 0x1c, 0x69, 0xdf, 0xdf, 0x01, 0x00, 0x53, 0x00, + 0xff, 0x05, 0x27, 0x37, 0x82, 0x4a, 0x82, 0x1c, + 0x82, 0x1c, 0x82, 0x9d, 0xbf, 0xff, 0x97, 0x08, + 0x10, 0x09, 0x27, 0x0f, 0x1c, 0x5c, 0x46, 0x03, + 0x5b, 0x02, 0x1e, 0x04, 0x53, 0x02, 0xef, 0x02, + 0x50, 0x03, 0x1e, 0x00, 0x53, 0x03, 0xef, 0x69, + 0xaf, 0x05, 0x27 }; static const unsigned char pkt544[] = { -0x42, 0xca, 0x00, -0x89, 0x28, 0x0c, 0x42, 0x00, -0x5b, 0x18, 0x23, 0x0c, 0x23, 0x0e, 0xcf, 0xe0, -0x1c, 0x0e, 0xaf, 0x0a, 0x40, 0x02, 0x5a, 0x3b, -0x46, 0x00, 0x5a, 0x05, 0x27, 0x37, 0x43, 0xfc, -0x5b, 0x08, 0xef, 0x0c, 0xaf, 0x0d, 0x40, 0x0a, -0x5a, 0xee, 0xcf, 0x64, 0x1e, 0x01, 0x5e, 0x0c, -0x3b, 0x05, 0x27, 0x0d, 0x30, 0x0c, 0x35, 0xbf, -0x22, 0xc0, 0x2e, 0x96, 0xbf, 0x05, 0x27, 0x0e, -0x45, 0x01, 0x5b, 0x07, 0x88, 0x00, 0x50, 0x0e, -0x88, 0x0d, 0x41, 0x1f, 0x5a, 0x0d, 0x42, 0x11, -0x5a, 0xd6, 0x78, 0x51, 0x88, 0x19, 0xcf, 0xfe, -0x1e, 0x03, 0x5c, 0x0e, 0x3d, 0x0d, 0x39, 0x0d, -0x3b, 0x0c, 0x27, 0x0d, 0x27, 0x64, 0x88, 0x19, -0xcf, 0x02, 0x1e, 0xfa, 0x5a, 0x0e, 0x3e, 0x0d, -0x3a, 0x0d, 0x33, 0x0c, 0x27, 0xe4, 0x37, 0x04, -0x89, 0xe4, 0x3f, 0x01, 0x2e, 0xef, 0x82, 0x0d, -0x45, 0x54, 0x5b, 0x18, 0xcf, 0xdf, 0x22, 0x67, -0x54, 0x0d, 0x3b, 0x4f, 0x78, 0xf9, 0x88, 0x01, -0x2e, 0xef, 0x82, 0x0d, 0x42, 0x06, 0x5a, 0x0d, -0x45, 0x48, 0x5b, 0x18, 0xcf, 0xdf, 0x22, 0x5b, -0x54, 0x0d, 0x33, 0x43, 0x78, 0x15, 0xcf, 0x1a, -0xaf, 0xe4, 0x37, 0xea, 0x88, 0x15, 0xcf, 0x1b, -0xaf, 0xe4, 0x3f, 0x0d, 0xcf, 0x60, 0x1c, 0xdf, -0x22, 0x00, 0x55, 0x63, 0x78, 0x16, 0xcf, 0x13, -0xdf, 0x2a, 0x1e, 0x02, 0x5f, 0x2a, 0x1f, 0x00, -0x5f, 0x5c, 0x78, 0xbf, 0x03 + 0x42, 0xca, 0x00, + 0x89, 0x28, 0x0c, 0x42, 0x00, + 0x5b, 0x18, 0x23, 0x0c, 0x23, 0x0e, 0xcf, 0xe0, + 0x1c, 0x0e, 0xaf, 0x0a, 0x40, 0x02, 0x5a, 0x3b, + 0x46, 0x00, 0x5a, 0x05, 0x27, 0x37, 0x43, 0xfc, + 0x5b, 0x08, 0xef, 0x0c, 0xaf, 0x0d, 0x40, 0x0a, + 0x5a, 0xee, 0xcf, 0x64, 0x1e, 0x01, 0x5e, 0x0c, + 0x3b, 0x05, 0x27, 0x0d, 0x30, 0x0c, 0x35, 0xbf, + 0x22, 0xc0, 0x2e, 0x96, 0xbf, 0x05, 0x27, 0x0e, + 0x45, 0x01, 0x5b, 0x07, 0x88, 0x00, 0x50, 0x0e, + 0x88, 0x0d, 0x41, 0x1f, 0x5a, 0x0d, 0x42, 0x11, + 0x5a, 0xd6, 0x78, 0x51, 0x88, 0x19, 0xcf, 0xfe, + 0x1e, 0x03, 0x5c, 0x0e, 0x3d, 0x0d, 0x39, 0x0d, + 0x3b, 0x0c, 0x27, 0x0d, 0x27, 0x64, 0x88, 0x19, + 0xcf, 0x02, 0x1e, 0xfa, 0x5a, 0x0e, 0x3e, 0x0d, + 0x3a, 0x0d, 0x33, 0x0c, 0x27, 0xe4, 0x37, 0x04, + 0x89, 0xe4, 0x3f, 0x01, 0x2e, 0xef, 0x82, 0x0d, + 0x45, 0x54, 0x5b, 0x18, 0xcf, 0xdf, 0x22, 0x67, + 0x54, 0x0d, 0x3b, 0x4f, 0x78, 0xf9, 0x88, 0x01, + 0x2e, 0xef, 0x82, 0x0d, 0x42, 0x06, 0x5a, 0x0d, + 0x45, 0x48, 0x5b, 0x18, 0xcf, 0xdf, 0x22, 0x5b, + 0x54, 0x0d, 0x33, 0x43, 0x78, 0x15, 0xcf, 0x1a, + 0xaf, 0xe4, 0x37, 0xea, 0x88, 0x15, 0xcf, 0x1b, + 0xaf, 0xe4, 0x3f, 0x0d, 0xcf, 0x60, 0x1c, 0xdf, + 0x22, 0x00, 0x55, 0x63, 0x78, 0x16, 0xcf, 0x13, + 0xdf, 0x2a, 0x1e, 0x02, 0x5f, 0x2a, 0x1f, 0x00, + 0x5f, 0x5c, 0x78, 0xbf, 0x03 }; static const unsigned char pkt548[] = { -0x42, 0xca, 0x00, -0xed, 0x28, 0x44, 0x54, 0x1d, -0x52, 0x01, 0x2e, 0xef, 0x82, 0x9f, 0x22, 0x1a, -0xaf, 0x18, 0xcf, 0x12, 0xdf, 0xbf, 0x03, 0x00, -0x53, 0x24, 0x50, 0x09, 0x88, 0x01, 0x2e, 0xe3, -0x82, 0x9f, 0x22, 0x1b, 0xaf, 0xb1, 0x8f, 0x1d, -0x78, 0x0e, 0xcf, 0x9f, 0x1c, 0x0e, 0xaf, 0x05, -0x27, 0x0e, 0xcf, 0x5f, 0x2d, 0x05, 0x5a, 0x9f, -0x2b, 0x5f, 0x29, 0x0e, 0xaf, 0x5f, 0xff, 0x1d, -0xbf, 0x1c, 0x23, 0x05, 0x27, 0x9f, 0x22, 0x1b, -0xaf, 0x18, 0xcf, 0xdf, 0x22, 0x0a, 0x54, 0x18, -0xcf, 0x12, 0xdf, 0xbf, 0x03, 0x00, 0x53, 0x05, -0x50, 0x06, 0x88, 0x01, 0x2e, 0xe9, 0x82, 0x9f, -0x22, 0x1a, 0xaf, 0x9b, 0x8f, 0x09, 0x88, 0x05, -0x27, 0x0e, 0xcf, 0x9f, 0x2d, 0x04, 0x5a, 0x9f, -0x29, 0x5f, 0x2b, 0x0e, 0xaf, 0x1d, 0x23, 0x1c, -0x23, 0x05, 0x27, 0x0d, 0x45, 0x1e, 0x5b, 0x8e, -0x88, 0x18, 0xcf, 0x12, 0xdf, 0xbf, 0x03, 0x57, -0x53, 0x0d, 0x44, 0x02, 0x5b, 0x0c, 0x35, 0x0c, -0x78, 0x85, 0x88, 0x17, 0xcf, 0xdf, 0x22, 0x08, -0x55, 0x18, 0xcf, 0xdf, 0x22, 0x05, 0x55, 0x0a, -0x88, 0x0e, 0x3b, 0x0c, 0xdf, 0x24, 0x19, 0x0c, -0xbf, 0x05, 0x27, 0x11, 0xcf, 0xff, 0x1e, 0x01, -0x54, 0x1f, 0x20, 0x11, 0xaf, 0x05, 0x27, 0x1a, -0x23, 0x1b, 0x23, 0x05, 0x27, 0xfb, 0x8f, 0x0b, -0x88, 0x6d, 0x88, 0xf6, 0x8e, 0x34, 0x5a, 0x0a, -0xcf, 0xc0, 0x1c, 0xc0, 0x1e + 0x42, 0xca, 0x00, + 0xed, 0x28, 0x44, 0x54, 0x1d, + 0x52, 0x01, 0x2e, 0xef, 0x82, 0x9f, 0x22, 0x1a, + 0xaf, 0x18, 0xcf, 0x12, 0xdf, 0xbf, 0x03, 0x00, + 0x53, 0x24, 0x50, 0x09, 0x88, 0x01, 0x2e, 0xe3, + 0x82, 0x9f, 0x22, 0x1b, 0xaf, 0xb1, 0x8f, 0x1d, + 0x78, 0x0e, 0xcf, 0x9f, 0x1c, 0x0e, 0xaf, 0x05, + 0x27, 0x0e, 0xcf, 0x5f, 0x2d, 0x05, 0x5a, 0x9f, + 0x2b, 0x5f, 0x29, 0x0e, 0xaf, 0x5f, 0xff, 0x1d, + 0xbf, 0x1c, 0x23, 0x05, 0x27, 0x9f, 0x22, 0x1b, + 0xaf, 0x18, 0xcf, 0xdf, 0x22, 0x0a, 0x54, 0x18, + 0xcf, 0x12, 0xdf, 0xbf, 0x03, 0x00, 0x53, 0x05, + 0x50, 0x06, 0x88, 0x01, 0x2e, 0xe9, 0x82, 0x9f, + 0x22, 0x1a, 0xaf, 0x9b, 0x8f, 0x09, 0x88, 0x05, + 0x27, 0x0e, 0xcf, 0x9f, 0x2d, 0x04, 0x5a, 0x9f, + 0x29, 0x5f, 0x2b, 0x0e, 0xaf, 0x1d, 0x23, 0x1c, + 0x23, 0x05, 0x27, 0x0d, 0x45, 0x1e, 0x5b, 0x8e, + 0x88, 0x18, 0xcf, 0x12, 0xdf, 0xbf, 0x03, 0x57, + 0x53, 0x0d, 0x44, 0x02, 0x5b, 0x0c, 0x35, 0x0c, + 0x78, 0x85, 0x88, 0x17, 0xcf, 0xdf, 0x22, 0x08, + 0x55, 0x18, 0xcf, 0xdf, 0x22, 0x05, 0x55, 0x0a, + 0x88, 0x0e, 0x3b, 0x0c, 0xdf, 0x24, 0x19, 0x0c, + 0xbf, 0x05, 0x27, 0x11, 0xcf, 0xff, 0x1e, 0x01, + 0x54, 0x1f, 0x20, 0x11, 0xaf, 0x05, 0x27, 0x1a, + 0x23, 0x1b, 0x23, 0x05, 0x27, 0xfb, 0x8f, 0x0b, + 0x88, 0x6d, 0x88, 0xf6, 0x8e, 0x34, 0x5a, 0x0a, + 0xcf, 0xc0, 0x1c, 0xc0, 0x1e }; static const unsigned char pkt552[] = { -0x42, 0xca, 0x00, -0x51, 0x29, 0x0d, 0x55, 0x9f, -0x22, 0x1f, 0xaf, 0x20, 0xaf, 0x19, 0xaf, 0x1b, -0x78, 0x0e, 0xcf, 0x05, 0x18, 0x0e, 0xaf, 0x9f, -0x22, 0x47, 0xaf, 0x48, 0xaf, 0x17, 0xaf, 0x18, -0xaf, 0x05, 0x27, 0x20, 0xcf, 0xdf, 0x22, 0x05, -0x54, 0x05, 0x1e, 0x19, 0x55, 0x1f, 0xdf, 0x80, -0x1f, 0x16, 0x5e, 0x02, 0x78, 0x1f, 0xdf, 0x10, -0x1f, 0x12, 0x5e, 0x9f, 0x22, 0x20, 0xaf, 0x1f, -0xaf, 0x0a, 0xcf, 0xc0, 0x1c, 0x80, 0x1e, 0x0a, -0x55, 0x0d, 0x41, 0x01, 0x5a, 0x0e, 0x35, 0x00, -0x50, 0x0e, 0x36, 0x0d, 0xcf, 0x06, 0x18, 0x0d, -0xaf, 0x0e, 0x31, 0x9f, 0x22, 0x19, 0xaf, 0x03, -0x78, 0x1f, 0x20, 0x06, 0x1e, 0x00, 0x5e, 0x20, -0xaf, 0x0d, 0x47, 0x01, 0x5b, 0x01, 0x2e, 0xa2, -0x73, 0x0d, 0x44, 0x0b, 0x5a, 0x0d, 0xcf, 0x06, -0x1c, 0x08, 0x54, 0x0c, 0x30, 0x48, 0xcf, 0xdf, -0x2d, 0x02, 0x5a, 0x9f, 0x22, 0x1d, 0xaf, 0x01, -0x50, 0x5f, 0xef, 0x1d, 0xaf, 0x0c, 0x31, 0x0d, -0x45, 0x11, 0x5b, 0x0a, 0xcf, 0x30, 0x1c, 0x0c, -0x55, 0x0d, 0xcf, 0x06, 0x1c, 0x06, 0x1e, 0x0b, -0x54, 0x11, 0xcf, 0x07, 0x1e, 0x02, 0x53, 0x04, -0xef, 0x12, 0xaf, 0x04, 0x78, 0x05, 0xef, 0x12, -0xaf, 0x01, 0x78, 0x01, 0xef, 0x12, 0xaf, 0x18, -0x23, 0x9f, 0x22, 0x11, 0xaf, 0x0d, 0xcf, 0x1f, -0x1c, 0x0d, 0xaf, 0x0c, 0xdf, 0x24, 0x19, 0x0c, -0xbf, 0x0a, 0xdf, 0x30, 0x1d + 0x42, 0xca, 0x00, + 0x51, 0x29, 0x0d, 0x55, 0x9f, + 0x22, 0x1f, 0xaf, 0x20, 0xaf, 0x19, 0xaf, 0x1b, + 0x78, 0x0e, 0xcf, 0x05, 0x18, 0x0e, 0xaf, 0x9f, + 0x22, 0x47, 0xaf, 0x48, 0xaf, 0x17, 0xaf, 0x18, + 0xaf, 0x05, 0x27, 0x20, 0xcf, 0xdf, 0x22, 0x05, + 0x54, 0x05, 0x1e, 0x19, 0x55, 0x1f, 0xdf, 0x80, + 0x1f, 0x16, 0x5e, 0x02, 0x78, 0x1f, 0xdf, 0x10, + 0x1f, 0x12, 0x5e, 0x9f, 0x22, 0x20, 0xaf, 0x1f, + 0xaf, 0x0a, 0xcf, 0xc0, 0x1c, 0x80, 0x1e, 0x0a, + 0x55, 0x0d, 0x41, 0x01, 0x5a, 0x0e, 0x35, 0x00, + 0x50, 0x0e, 0x36, 0x0d, 0xcf, 0x06, 0x18, 0x0d, + 0xaf, 0x0e, 0x31, 0x9f, 0x22, 0x19, 0xaf, 0x03, + 0x78, 0x1f, 0x20, 0x06, 0x1e, 0x00, 0x5e, 0x20, + 0xaf, 0x0d, 0x47, 0x01, 0x5b, 0x01, 0x2e, 0xa2, + 0x73, 0x0d, 0x44, 0x0b, 0x5a, 0x0d, 0xcf, 0x06, + 0x1c, 0x08, 0x54, 0x0c, 0x30, 0x48, 0xcf, 0xdf, + 0x2d, 0x02, 0x5a, 0x9f, 0x22, 0x1d, 0xaf, 0x01, + 0x50, 0x5f, 0xef, 0x1d, 0xaf, 0x0c, 0x31, 0x0d, + 0x45, 0x11, 0x5b, 0x0a, 0xcf, 0x30, 0x1c, 0x0c, + 0x55, 0x0d, 0xcf, 0x06, 0x1c, 0x06, 0x1e, 0x0b, + 0x54, 0x11, 0xcf, 0x07, 0x1e, 0x02, 0x53, 0x04, + 0xef, 0x12, 0xaf, 0x04, 0x78, 0x05, 0xef, 0x12, + 0xaf, 0x01, 0x78, 0x01, 0xef, 0x12, 0xaf, 0x18, + 0x23, 0x9f, 0x22, 0x11, 0xaf, 0x0d, 0xcf, 0x1f, + 0x1c, 0x0d, 0xaf, 0x0c, 0xdf, 0x24, 0x19, 0x0c, + 0xbf, 0x0a, 0xdf, 0x30, 0x1d }; static const unsigned char pkt556[] = { -0x42, 0x46, 0x00, -0xb5, 0x29, 0x20, 0x1f, 0x01, -0x55, 0xf9, 0x1c, 0x0d, 0xaf, 0x05, 0x27, 0x17, -0xdf, 0xff, 0x21, 0x47, 0xbf, 0x18, 0xdf, 0x84, -0x8e, 0x02, 0x5b, 0x0e, 0x46, 0x03, 0x5a, 0x01, -0x78, 0x0d, 0x43, 0x00, 0x5a, 0xff, 0x21, 0x48, -0xbf, 0x05, 0x27, 0x14, 0x23, 0x15, 0x23, 0xff, -0xef, 0x13, 0xaf, 0x01, 0x2e, 0x00, 0x83, 0x0d, -0x3e, 0x13, 0xcf, 0x46, 0xff, 0xbf, 0x03, 0x00, -0x53, 0x0d, 0x36, 0x05, 0x27, 0x05, 0x27, 0x05, -0x27 + 0x42, 0x46, 0x00, + 0xb5, 0x29, 0x20, 0x1f, 0x01, + 0x55, 0xf9, 0x1c, 0x0d, 0xaf, 0x05, 0x27, 0x17, + 0xdf, 0xff, 0x21, 0x47, 0xbf, 0x18, 0xdf, 0x84, + 0x8e, 0x02, 0x5b, 0x0e, 0x46, 0x03, 0x5a, 0x01, + 0x78, 0x0d, 0x43, 0x00, 0x5a, 0xff, 0x21, 0x48, + 0xbf, 0x05, 0x27, 0x14, 0x23, 0x15, 0x23, 0xff, + 0xef, 0x13, 0xaf, 0x01, 0x2e, 0x00, 0x83, 0x0d, + 0x3e, 0x13, 0xcf, 0x46, 0xff, 0xbf, 0x03, 0x00, + 0x53, 0x0d, 0x36, 0x05, 0x27, 0x05, 0x27, 0x05, + 0x27 }; static const unsigned char pkt560[] = { -0x42, 0xca, 0x00, -0xd7, 0x29, 0xe1, 0x97, 0xe2, -0x9f, 0x46, 0x2e, 0x28, 0xbf, 0xc6, 0x2e, 0x29, -0xbf, 0xad, 0x88, 0x0a, 0x5b, 0xe9, 0x97, 0xea, -0x9f, 0x4f, 0xaf, 0x50, 0xbf, 0x46, 0x2e, 0x28, -0xdf, 0xc6, 0x2e, 0x29, 0xdf, 0x10, 0x10, 0x00, -0x13, 0x01, 0x78, 0x03, 0x10, 0x00, 0x13, 0xff, -0x96, 0xdf, 0x96, 0xd6, 0xcf, 0xd7, 0xdf, 0x0f, -0x1d, 0x01, 0x10, 0x00, 0x13, 0xff, 0x96, 0xdf, -0x96, 0xc8, 0xdf, 0xc7, 0xcf, 0x1f, 0x1d, 0xff, -0x96, 0xdf, 0x96, 0xc2, 0x97, 0xc3, 0x9f, 0x9d, -0x01, 0x5d, 0x01, 0xf5, 0x52, 0xc3, 0x03, 0x02, -0x5e, 0xf2, 0x52, 0x82, 0x03, 0xf0, 0x52, 0x02, -0x0c, 0xf8, 0x43, 0x03, 0x5b, 0x08, 0x44, 0x01, -0x5a, 0x00, 0x2e, 0xf3, 0x8f, 0x7f, 0x88, 0x6d, -0x5b, 0x41, 0x2e, 0xaf, 0xdf, 0xdf, 0x29, 0x41, -0x2e, 0xaf, 0xbf, 0x46, 0x2e, 0x28, 0xdf, 0xc6, -0x2e, 0x29, 0xdf, 0x03, 0x16, 0x00, 0x15, 0x46, -0x2e, 0x28, 0xbf, 0xc6, 0x2e, 0x29, 0xbf, 0x15, -0x27, 0xff, 0x96, 0xdf, 0x96, 0x8d, 0x88, 0x94, -0x88, 0xcd, 0x88, 0x01, 0xff, 0xab, 0xef, 0x19, -0x27, 0x6b, 0x88, 0xbf, 0x22, 0x3f, 0x98, 0x05, -0xff, 0x7f, 0x98, 0xdd, 0x9f, 0xbf, 0x98, 0x24, -0x28, 0x04, 0xff, 0x7f, 0x98, 0xdd, 0x9f, 0xbf, -0x98, 0x24, 0x28, 0x66, 0xff, 0xbf, 0x99, 0x12, -0xff, 0x7f, 0x99, 0xdd, 0x97, 0xdd, 0x9f, 0x19, -0x27, 0xe0, 0x97, 0xff, 0xaf + 0x42, 0xca, 0x00, + 0xd7, 0x29, 0xe1, 0x97, 0xe2, + 0x9f, 0x46, 0x2e, 0x28, 0xbf, 0xc6, 0x2e, 0x29, + 0xbf, 0xad, 0x88, 0x0a, 0x5b, 0xe9, 0x97, 0xea, + 0x9f, 0x4f, 0xaf, 0x50, 0xbf, 0x46, 0x2e, 0x28, + 0xdf, 0xc6, 0x2e, 0x29, 0xdf, 0x10, 0x10, 0x00, + 0x13, 0x01, 0x78, 0x03, 0x10, 0x00, 0x13, 0xff, + 0x96, 0xdf, 0x96, 0xd6, 0xcf, 0xd7, 0xdf, 0x0f, + 0x1d, 0x01, 0x10, 0x00, 0x13, 0xff, 0x96, 0xdf, + 0x96, 0xc8, 0xdf, 0xc7, 0xcf, 0x1f, 0x1d, 0xff, + 0x96, 0xdf, 0x96, 0xc2, 0x97, 0xc3, 0x9f, 0x9d, + 0x01, 0x5d, 0x01, 0xf5, 0x52, 0xc3, 0x03, 0x02, + 0x5e, 0xf2, 0x52, 0x82, 0x03, 0xf0, 0x52, 0x02, + 0x0c, 0xf8, 0x43, 0x03, 0x5b, 0x08, 0x44, 0x01, + 0x5a, 0x00, 0x2e, 0xf3, 0x8f, 0x7f, 0x88, 0x6d, + 0x5b, 0x41, 0x2e, 0xaf, 0xdf, 0xdf, 0x29, 0x41, + 0x2e, 0xaf, 0xbf, 0x46, 0x2e, 0x28, 0xdf, 0xc6, + 0x2e, 0x29, 0xdf, 0x03, 0x16, 0x00, 0x15, 0x46, + 0x2e, 0x28, 0xbf, 0xc6, 0x2e, 0x29, 0xbf, 0x15, + 0x27, 0xff, 0x96, 0xdf, 0x96, 0x8d, 0x88, 0x94, + 0x88, 0xcd, 0x88, 0x01, 0xff, 0xab, 0xef, 0x19, + 0x27, 0x6b, 0x88, 0xbf, 0x22, 0x3f, 0x98, 0x05, + 0xff, 0x7f, 0x98, 0xdd, 0x9f, 0xbf, 0x98, 0x24, + 0x28, 0x04, 0xff, 0x7f, 0x98, 0xdd, 0x9f, 0xbf, + 0x98, 0x24, 0x28, 0x66, 0xff, 0xbf, 0x99, 0x12, + 0xff, 0x7f, 0x99, 0xdd, 0x97, 0xdd, 0x9f, 0x19, + 0x27, 0xe0, 0x97, 0xff, 0xaf }; static const unsigned char pkt564[] = { -0x42, 0xca, 0x00, -0x3b, 0x2a, 0x46, 0x2e, 0x28, -0xdf, 0xc6, 0x2e, 0x29, 0xdf, 0x13, 0x10, 0x00, -0x13, 0xff, 0xaf, 0xff, 0xbf, 0xe3, 0x97, 0xff, -0xaf, 0xe4, 0x97, 0xff, 0xaf, 0xe5, 0x97, 0xff, -0xaf, 0xef, 0x88, 0x06, 0x0d, 0xdd, 0x97, 0xdd, -0x9f, 0x46, 0x2e, 0x28, 0xdf, 0xc6, 0x2e, 0x29, -0xdf, 0x06, 0xaf, 0x4e, 0xbf, 0xff, 0x22, 0x11, -0x54, 0x15, 0x27, 0x1a, 0x27, 0x01, 0xff, 0xab, -0xef, 0x19, 0x27, 0xdc, 0x97, 0xdf, 0x99, 0x28, -0x28, 0x0f, 0x27, 0x68, 0x2c, 0xfd, 0x5b, 0xe9, -0x97, 0xff, 0xaf, 0x6a, 0x28, 0x06, 0x25, 0xf4, -0x53, 0x4e, 0x25, 0xf2, 0x55, 0xdc, 0x97, 0xdf, -0x99, 0x28, 0x28, 0x0f, 0x27, 0x68, 0x2c, 0xfd, -0x5b, 0xe9, 0x97, 0xff, 0xaf, 0x6a, 0x28, 0x06, -0x25, 0xf4, 0x55, 0x41, 0x2e, 0xaf, 0xdf, 0xdf, -0x2b, 0x41, 0x2e, 0xaf, 0xbf, 0xbf, 0x22, 0xbf, -0x99, 0x7f, 0x99, 0x05, 0x27, 0xdd, 0x97, 0xdd, -0x9f, 0x06, 0xaf, 0x4e, 0xbf, 0xff, 0x22, 0x05, -0x54, 0xfd, 0x97, 0xff, 0xaf, 0x06, 0x25, 0xfb, -0x53, 0x4e, 0x25, 0xf9, 0x55, 0xfd, 0x97, 0xff, -0xaf, 0x06, 0x25, 0xfb, 0x55, 0x05, 0x27, 0xff, -0x96, 0xc6, 0x2e, 0x01, 0xdf, 0xbf, 0x2c, 0xdd, -0x9f, 0x05, 0x27, 0xc6, 0x2e, 0x28, 0xdf, 0x0f, -0x1d, 0x04, 0x55, 0x0b, 0x88, 0xff, 0x96, 0x10, -0xef, 0xdf, 0x96, 0x06, 0x50, 0x06, 0x88, 0x3f, -0x20, 0xff, 0x96, 0xc6, 0x2e + 0x42, 0xca, 0x00, + 0x3b, 0x2a, 0x46, 0x2e, 0x28, + 0xdf, 0xc6, 0x2e, 0x29, 0xdf, 0x13, 0x10, 0x00, + 0x13, 0xff, 0xaf, 0xff, 0xbf, 0xe3, 0x97, 0xff, + 0xaf, 0xe4, 0x97, 0xff, 0xaf, 0xe5, 0x97, 0xff, + 0xaf, 0xef, 0x88, 0x06, 0x0d, 0xdd, 0x97, 0xdd, + 0x9f, 0x46, 0x2e, 0x28, 0xdf, 0xc6, 0x2e, 0x29, + 0xdf, 0x06, 0xaf, 0x4e, 0xbf, 0xff, 0x22, 0x11, + 0x54, 0x15, 0x27, 0x1a, 0x27, 0x01, 0xff, 0xab, + 0xef, 0x19, 0x27, 0xdc, 0x97, 0xdf, 0x99, 0x28, + 0x28, 0x0f, 0x27, 0x68, 0x2c, 0xfd, 0x5b, 0xe9, + 0x97, 0xff, 0xaf, 0x6a, 0x28, 0x06, 0x25, 0xf4, + 0x53, 0x4e, 0x25, 0xf2, 0x55, 0xdc, 0x97, 0xdf, + 0x99, 0x28, 0x28, 0x0f, 0x27, 0x68, 0x2c, 0xfd, + 0x5b, 0xe9, 0x97, 0xff, 0xaf, 0x6a, 0x28, 0x06, + 0x25, 0xf4, 0x55, 0x41, 0x2e, 0xaf, 0xdf, 0xdf, + 0x2b, 0x41, 0x2e, 0xaf, 0xbf, 0xbf, 0x22, 0xbf, + 0x99, 0x7f, 0x99, 0x05, 0x27, 0xdd, 0x97, 0xdd, + 0x9f, 0x06, 0xaf, 0x4e, 0xbf, 0xff, 0x22, 0x05, + 0x54, 0xfd, 0x97, 0xff, 0xaf, 0x06, 0x25, 0xfb, + 0x53, 0x4e, 0x25, 0xf9, 0x55, 0xfd, 0x97, 0xff, + 0xaf, 0x06, 0x25, 0xfb, 0x55, 0x05, 0x27, 0xff, + 0x96, 0xc6, 0x2e, 0x01, 0xdf, 0xbf, 0x2c, 0xdd, + 0x9f, 0x05, 0x27, 0xc6, 0x2e, 0x28, 0xdf, 0x0f, + 0x1d, 0x04, 0x55, 0x0b, 0x88, 0xff, 0x96, 0x10, + 0xef, 0xdf, 0x96, 0x06, 0x50, 0x06, 0x88, 0x3f, + 0x20, 0xff, 0x96, 0xc6, 0x2e }; static const unsigned char pkt568[] = { -0x42, 0xca, 0x00, -0x9f, 0x2a, 0x28, 0xdf, 0x0f, -0x1d, 0xff, 0x96, 0x05, 0x27, 0x46, 0x2e, 0x28, -0xdf, 0xf0, 0x1c, 0x09, 0x27, 0xdf, 0x9f, 0x46, -0x2e, 0x29, 0xdf, 0x0f, 0x1c, 0x09, 0x27, 0x5f, -0x02, 0x05, 0x27, 0x78, 0x88, 0x6f, 0x88, 0x0a, -0xef, 0xdc, 0x9f, 0x3f, 0x9f, 0x5f, 0x20, 0xfb, -0x55, 0x05, 0x27, 0x9f, 0x22, 0x41, 0x2e, 0xab, -0xbf, 0x50, 0xef, 0xdf, 0x96, 0x3a, 0xef, 0xdf, -0x96, 0x29, 0x88, 0x68, 0x88, 0x0a, 0xef, 0xfc, -0x9f, 0xc1, 0x2e, 0xad, 0xbf, 0xc1, 0x2e, 0xac, -0xdf, 0x3f, 0x20, 0xc1, 0x2e, 0xac, 0xbf, 0x6a, -0x88, 0x5f, 0x20, 0xf4, 0x55, 0x5b, 0xef, 0xdf, -0x96, 0x50, 0xcf, 0xdf, 0x96, 0x17, 0x88, 0x5c, -0xef, 0xdf, 0x96, 0x4f, 0xcf, 0xdf, 0x96, 0x12, -0x88, 0x5d, 0xef, 0xdf, 0x96, 0x9f, 0x22, 0xdf, -0x96, 0x0d, 0x88, 0x5e, 0xef, 0xdf, 0x96, 0x46, -0x2e, 0x29, 0xdf, 0xdf, 0x96, 0x07, 0x88, 0x5f, -0xef, 0xdf, 0x96, 0x46, 0x2e, 0x28, 0xdf, 0xdf, -0x96, 0x01, 0x88, 0x0f, 0x27, 0x05, 0x27, 0xdd, -0x97, 0x41, 0x2e, 0xad, 0xbf, 0xdd, 0x97, 0x41, -0x2e, 0xac, 0xbf, 0x44, 0x88, 0x05, 0x27, 0x9f, -0x22, 0x41, 0x2e, 0xab, 0xbf, 0x10, 0xef, 0xdf, -0x96, 0x02, 0xef, 0xdf, 0x96, 0xef, 0x8f, 0x2e, -0x88, 0x0a, 0xef, 0xfc, 0x9f, 0xc1, 0x2e, 0xad, -0xbf, 0xc1, 0x2e, 0xac, 0xdf, 0x3f, 0x20, 0xc1, -0x2e, 0xac, 0xbf, 0x30, 0x88 + 0x42, 0xca, 0x00, + 0x9f, 0x2a, 0x28, 0xdf, 0x0f, + 0x1d, 0xff, 0x96, 0x05, 0x27, 0x46, 0x2e, 0x28, + 0xdf, 0xf0, 0x1c, 0x09, 0x27, 0xdf, 0x9f, 0x46, + 0x2e, 0x29, 0xdf, 0x0f, 0x1c, 0x09, 0x27, 0x5f, + 0x02, 0x05, 0x27, 0x78, 0x88, 0x6f, 0x88, 0x0a, + 0xef, 0xdc, 0x9f, 0x3f, 0x9f, 0x5f, 0x20, 0xfb, + 0x55, 0x05, 0x27, 0x9f, 0x22, 0x41, 0x2e, 0xab, + 0xbf, 0x50, 0xef, 0xdf, 0x96, 0x3a, 0xef, 0xdf, + 0x96, 0x29, 0x88, 0x68, 0x88, 0x0a, 0xef, 0xfc, + 0x9f, 0xc1, 0x2e, 0xad, 0xbf, 0xc1, 0x2e, 0xac, + 0xdf, 0x3f, 0x20, 0xc1, 0x2e, 0xac, 0xbf, 0x6a, + 0x88, 0x5f, 0x20, 0xf4, 0x55, 0x5b, 0xef, 0xdf, + 0x96, 0x50, 0xcf, 0xdf, 0x96, 0x17, 0x88, 0x5c, + 0xef, 0xdf, 0x96, 0x4f, 0xcf, 0xdf, 0x96, 0x12, + 0x88, 0x5d, 0xef, 0xdf, 0x96, 0x9f, 0x22, 0xdf, + 0x96, 0x0d, 0x88, 0x5e, 0xef, 0xdf, 0x96, 0x46, + 0x2e, 0x29, 0xdf, 0xdf, 0x96, 0x07, 0x88, 0x5f, + 0xef, 0xdf, 0x96, 0x46, 0x2e, 0x28, 0xdf, 0xdf, + 0x96, 0x01, 0x88, 0x0f, 0x27, 0x05, 0x27, 0xdd, + 0x97, 0x41, 0x2e, 0xad, 0xbf, 0xdd, 0x97, 0x41, + 0x2e, 0xac, 0xbf, 0x44, 0x88, 0x05, 0x27, 0x9f, + 0x22, 0x41, 0x2e, 0xab, 0xbf, 0x10, 0xef, 0xdf, + 0x96, 0x02, 0xef, 0xdf, 0x96, 0xef, 0x8f, 0x2e, + 0x88, 0x0a, 0xef, 0xfc, 0x9f, 0xc1, 0x2e, 0xad, + 0xbf, 0xc1, 0x2e, 0xac, 0xdf, 0x3f, 0x20, 0xc1, + 0x2e, 0xac, 0xbf, 0x30, 0x88 }; static const unsigned char pkt572[] = { -0x42, 0x9a, 0x00, -0x03, 0x2b, 0x5f, 0x20, 0xf4, -0x55, 0x1b, 0xef, 0xdf, 0x96, 0x50, 0xcf, 0xdf, -0x96, 0xdd, 0x8f, 0x1c, 0xef, 0xdf, 0x96, 0x4f, -0xcf, 0xdf, 0x96, 0xd8, 0x8f, 0x1d, 0xef, 0xdf, -0x96, 0x9f, 0x22, 0xdf, 0x96, 0xd3, 0x8f, 0x1e, -0xef, 0xdf, 0x96, 0x9f, 0x22, 0xdf, 0x96, 0xce, -0x8f, 0x1f, 0xef, 0xdf, 0x96, 0x01, 0xef, 0xdf, -0x96, 0xc9, 0x8f, 0x0f, 0x27, 0x05, 0x27, 0x02, -0xef, 0x06, 0xff, 0x1a, 0x27, 0x05, 0x27, 0x02, -0xef, 0x06, 0xff, 0x1a, 0x27, 0x05, 0x27, 0xdf, -0x96, 0xff, 0x96, 0x7b, 0xef, 0x00, 0xff, 0x1b, -0x27, 0xdd, 0x9f, 0xdd, 0x97, 0x05, 0x27, 0x01, -0xff, 0xab, 0xef, 0x1b, 0x27, 0x05, 0x27, 0xdf, -0x96, 0x81, 0xef, 0x41, 0x2e, 0xaf, 0xbf, 0xdd, -0x97, 0x05, 0x27, 0x3a, 0xef, 0xff, 0xaf, 0xea, -0x8f, 0x0a, 0xef, 0xfc, 0x9f, 0xff, 0xbf, 0x5f, -0x20, 0xfb, 0x55, 0x50, 0xcf, 0xff, 0xaf, 0x4f, -0xcf, 0xff, 0xaf, 0x9f, 0x22, 0xff, 0xaf, 0x46, -0x2e, 0x29, 0xdf, 0xff, 0xaf, 0x46, 0x2e, 0x28, -0xdf, 0xff, 0xaf, 0x05, 0x27 + 0x42, 0x9a, 0x00, + 0x03, 0x2b, 0x5f, 0x20, 0xf4, + 0x55, 0x1b, 0xef, 0xdf, 0x96, 0x50, 0xcf, 0xdf, + 0x96, 0xdd, 0x8f, 0x1c, 0xef, 0xdf, 0x96, 0x4f, + 0xcf, 0xdf, 0x96, 0xd8, 0x8f, 0x1d, 0xef, 0xdf, + 0x96, 0x9f, 0x22, 0xdf, 0x96, 0xd3, 0x8f, 0x1e, + 0xef, 0xdf, 0x96, 0x9f, 0x22, 0xdf, 0x96, 0xce, + 0x8f, 0x1f, 0xef, 0xdf, 0x96, 0x01, 0xef, 0xdf, + 0x96, 0xc9, 0x8f, 0x0f, 0x27, 0x05, 0x27, 0x02, + 0xef, 0x06, 0xff, 0x1a, 0x27, 0x05, 0x27, 0x02, + 0xef, 0x06, 0xff, 0x1a, 0x27, 0x05, 0x27, 0xdf, + 0x96, 0xff, 0x96, 0x7b, 0xef, 0x00, 0xff, 0x1b, + 0x27, 0xdd, 0x9f, 0xdd, 0x97, 0x05, 0x27, 0x01, + 0xff, 0xab, 0xef, 0x1b, 0x27, 0x05, 0x27, 0xdf, + 0x96, 0x81, 0xef, 0x41, 0x2e, 0xaf, 0xbf, 0xdd, + 0x97, 0x05, 0x27, 0x3a, 0xef, 0xff, 0xaf, 0xea, + 0x8f, 0x0a, 0xef, 0xfc, 0x9f, 0xff, 0xbf, 0x5f, + 0x20, 0xfb, 0x55, 0x50, 0xcf, 0xff, 0xaf, 0x4f, + 0xcf, 0xff, 0xaf, 0x9f, 0x22, 0xff, 0xaf, 0x46, + 0x2e, 0x29, 0xdf, 0xff, 0xaf, 0x46, 0x2e, 0x28, + 0xdf, 0xff, 0xaf, 0x05, 0x27 }; static const unsigned char pkt576[] = { -0x42, 0x1a, 0x00, -0x4f, 0x2b, 0x09, 0x43, 0x04, -0x5b, 0x00, 0xef, 0xf8, 0xaf, 0x32, 0xef, 0xfa, -0xaf, 0x03, 0x50, 0x01, 0xef, 0xf8, 0xaf, 0x42, -0xef, 0xfa, 0xaf, 0x05, 0x27 + 0x42, 0x1a, 0x00, + 0x4f, 0x2b, 0x09, 0x43, 0x04, + 0x5b, 0x00, 0xef, 0xf8, 0xaf, 0x32, 0xef, 0xfa, + 0xaf, 0x03, 0x50, 0x01, 0xef, 0xf8, 0xaf, 0x42, + 0xef, 0xfa, 0xaf, 0x05, 0x27 }; static const unsigned char pkt580[] = { -0x42, 0x18, 0x00, -0x5b, 0x2b, 0xd3, 0x45, 0x03, -0x5a, 0x0f, 0x27, 0xd3, 0x45, 0x00, 0x5a, 0x05, -0x27, 0xd0, 0x41, 0xf7, 0x5b, 0xc1, 0x83, 0xf5, -0x50, 0x05, 0x27 + 0x42, 0x18, 0x00, + 0x5b, 0x2b, 0xd3, 0x45, 0x03, + 0x5a, 0x0f, 0x27, 0xd3, 0x45, 0x00, 0x5a, 0x05, + 0x27, 0xd0, 0x41, 0xf7, 0x5b, 0xc1, 0x83, 0xf5, + 0x50, 0x05, 0x27 }; static const unsigned char pkt584[] = { -0x42, 0x22, 0x00, -0x66, 0x2b, 0xc8, 0x46, 0x0c, -0x5b, 0xd3, 0x45, 0xfd, 0x5a, 0xd3, 0x45, 0xfb, -0x5a, 0xd3, 0x45, 0xf9, 0x5a, 0x41, 0x2e, 0xa1, -0xdf, 0x9f, 0x28, 0x41, 0x2e, 0xa1, 0xbf, 0x02, -0x2e, 0xb0, 0x81, 0x05, 0x27 + 0x42, 0x22, 0x00, + 0x66, 0x2b, 0xc8, 0x46, 0x0c, + 0x5b, 0xd3, 0x45, 0xfd, 0x5a, 0xd3, 0x45, 0xfb, + 0x5a, 0xd3, 0x45, 0xf9, 0x5a, 0x41, 0x2e, 0xa1, + 0xdf, 0x9f, 0x28, 0x41, 0x2e, 0xa1, 0xbf, 0x02, + 0x2e, 0xb0, 0x81, 0x05, 0x27 }; static const unsigned char pkt588[] = { -0x42, 0x0e, 0x00, -0x76, 0x2b, 0x00, 0x19, 0xe9, -0x2f, 0xe3, 0x55, 0xdf, 0x2d, 0xe9, 0x2f, 0xd0, -0x50 + 0x42, 0x0e, 0x00, + 0x76, 0x2b, 0x00, 0x19, 0xe9, + 0x2f, 0xe3, 0x55, 0xdf, 0x2d, 0xe9, 0x2f, 0xd0, + 0x50 }; static const unsigned char pkt592[] = { -0x42, 0x0e, 0x00, -0x7c, 0x2b, 0x00, 0x19, 0xe9, -0x2f, 0xb5, 0x55, 0xdf, 0x2d, 0xe9, 0x2f, 0xa2, -0x50 + 0x42, 0x0e, 0x00, + 0x7c, 0x2b, 0x00, 0x19, 0xe9, + 0x2f, 0xb5, 0x55, 0xdf, 0x2d, 0xe9, 0x2f, 0xa2, + 0x50 }; static const unsigned char pkt596[] = { -0x42, 0x0e, 0x00, -0x82, 0x2b, 0xbf, 0x03, 0xe7, -0x2f, 0xb2, 0x53, 0xec, 0xcf, 0x01, 0x2e, 0x2d, -0x73 + 0x42, 0x0e, 0x00, + 0x82, 0x2b, 0xbf, 0x03, 0xe7, + 0x2f, 0xb2, 0x53, 0xec, 0xcf, 0x01, 0x2e, 0x2d, + 0x73 }; static const unsigned char pkt600[] = { -0x42, 0x50, 0x00, -0x88, 0x2b, 0x07, 0x3d, 0x02, -0x5b, 0x6c, 0x86, 0xc2, 0x23, 0xd3, 0x3c, 0x02, -0x44, 0xd7, 0x2f, 0x08, 0x5a, 0x02, 0x45, 0xd7, -0x2f, 0x69, 0x5b, 0x58, 0x23, 0x3c, 0x26, 0x02, -0x55, 0x02, 0x2e, 0x43, 0x83, 0x01, 0x50, 0x02, -0x2e, 0x92, 0x83, 0x07, 0x45, 0xea, 0x5a, 0x41, -0x2e, 0x53, 0xdf, 0xc1, 0x2e, 0x79, 0xdf, 0xff, -0x96, 0xdf, 0x96, 0x41, 0x2e, 0x55, 0xdf, 0xc1, -0x2e, 0x78, 0xdf, 0x9d, 0x01, 0x5d, 0x01, 0xff, -0x22, 0x00, 0x54, 0xff, 0xef, 0x2e, 0xaf, 0xd7, -0x2f, 0x4d, 0x50 + 0x42, 0x50, 0x00, + 0x88, 0x2b, 0x07, 0x3d, 0x02, + 0x5b, 0x6c, 0x86, 0xc2, 0x23, 0xd3, 0x3c, 0x02, + 0x44, 0xd7, 0x2f, 0x08, 0x5a, 0x02, 0x45, 0xd7, + 0x2f, 0x69, 0x5b, 0x58, 0x23, 0x3c, 0x26, 0x02, + 0x55, 0x02, 0x2e, 0x43, 0x83, 0x01, 0x50, 0x02, + 0x2e, 0x92, 0x83, 0x07, 0x45, 0xea, 0x5a, 0x41, + 0x2e, 0x53, 0xdf, 0xc1, 0x2e, 0x79, 0xdf, 0xff, + 0x96, 0xdf, 0x96, 0x41, 0x2e, 0x55, 0xdf, 0xc1, + 0x2e, 0x78, 0xdf, 0x9d, 0x01, 0x5d, 0x01, 0xff, + 0x22, 0x00, 0x54, 0xff, 0xef, 0x2e, 0xaf, 0xd7, + 0x2f, 0x4d, 0x50 }; static const unsigned char pkt604[] = { -0x67, 0x05, 0x00, 0x00, 0x02, 0x2e, 0x00, 0x70, -0x67, 0x05, 0x00, 0x01, 0x02, 0x2e, 0xb8, 0x71, -0x67, 0x05, 0x00, 0x02, 0x02, 0x2e, 0x35, 0x72, -0x67, 0x05, 0x00, 0x08, 0x02, 0x2e, 0xbb, 0x72, -0x67, 0x05, 0x00, 0x07, 0x02, 0x2e, 0x3b, 0x73, -0x67, 0x05, 0x00, 0x0d, 0x02, 0x2e, 0x38, 0x74, -0x67, 0x05, 0x00, 0x0b, 0x02, 0x2e, 0x85, 0x74, -0x67, 0x05, 0x00, 0x0e, 0x02, 0x2e, 0x61, 0x75, -0x67, 0x05, 0x00, 0x05, 0x02, 0x2e, 0xa6, 0x75, -0x67, 0x05, 0x00, 0x0c, 0x02, 0x2e, 0x89, 0x78, -0x67, 0x05, 0x00, 0x09, 0x02, 0x2e, 0xd7, 0x79, -0x5a, 0x05, 0x00, 0x00, 0x6b, 0x01, 0x4f, 0x2b, -0x5a, 0x05, 0x00, 0x01, 0x82, 0x09, 0x5b, 0x2b, -0x5a, 0x05, 0x00, 0x02, 0x78, 0x09, 0x66, 0x2b, -0x5a, 0x05, 0x00, 0x03, 0x4c, 0x15, 0x76, 0x2b, -0x5a, 0x05, 0x00, 0x04, 0x24, 0x15, 0x7c, 0x2b, -0x5a, 0x05, 0x00, 0x05, 0x50, 0x13, 0x82, 0x2b, -0x5a, 0x05, 0x00, 0x06, 0xe1, 0x02, 0x88, 0x2b, -0x0d, -0x42, 0x04, 0x00, 0x88, 0x2b, 0x07, 0x3d + 0x67, 0x05, 0x00, 0x00, 0x02, 0x2e, 0x00, 0x70, + 0x67, 0x05, 0x00, 0x01, 0x02, 0x2e, 0xb8, 0x71, + 0x67, 0x05, 0x00, 0x02, 0x02, 0x2e, 0x35, 0x72, + 0x67, 0x05, 0x00, 0x08, 0x02, 0x2e, 0xbb, 0x72, + 0x67, 0x05, 0x00, 0x07, 0x02, 0x2e, 0x3b, 0x73, + 0x67, 0x05, 0x00, 0x0d, 0x02, 0x2e, 0x38, 0x74, + 0x67, 0x05, 0x00, 0x0b, 0x02, 0x2e, 0x85, 0x74, + 0x67, 0x05, 0x00, 0x0e, 0x02, 0x2e, 0x61, 0x75, + 0x67, 0x05, 0x00, 0x05, 0x02, 0x2e, 0xa6, 0x75, + 0x67, 0x05, 0x00, 0x0c, 0x02, 0x2e, 0x89, 0x78, + 0x67, 0x05, 0x00, 0x09, 0x02, 0x2e, 0xd7, 0x79, + 0x5a, 0x05, 0x00, 0x00, 0x6b, 0x01, 0x4f, 0x2b, + 0x5a, 0x05, 0x00, 0x01, 0x82, 0x09, 0x5b, 0x2b, + 0x5a, 0x05, 0x00, 0x02, 0x78, 0x09, 0x66, 0x2b, + 0x5a, 0x05, 0x00, 0x03, 0x4c, 0x15, 0x76, 0x2b, + 0x5a, 0x05, 0x00, 0x04, 0x24, 0x15, 0x7c, 0x2b, + 0x5a, 0x05, 0x00, 0x05, 0x50, 0x13, 0x82, 0x2b, + 0x5a, 0x05, 0x00, 0x06, 0xe1, 0x02, 0x88, 0x2b, + 0x0d, + 0x42, 0x04, 0x00, 0x88, 0x2b, 0x07, 0x3d }; struct aesX660_cmd aes1660_init_2[] = { - { .cmd = pkt433, .len = sizeof(pkt433) }, - { .cmd = pkt440, .len = sizeof(pkt440) }, - { .cmd = pkt444, .len = sizeof(pkt444) }, - { .cmd = pkt448, .len = sizeof(pkt448) }, - { .cmd = pkt452, .len = sizeof(pkt452) }, - { .cmd = pkt456, .len = sizeof(pkt456) }, - { .cmd = pkt460, .len = sizeof(pkt460) }, - { .cmd = pkt464, .len = sizeof(pkt464) }, - { .cmd = pkt468, .len = sizeof(pkt468) }, - { .cmd = pkt472, .len = sizeof(pkt472) }, - { .cmd = pkt476, .len = sizeof(pkt476) }, - { .cmd = pkt480, .len = sizeof(pkt480) }, - { .cmd = pkt484, .len = sizeof(pkt484) }, - { .cmd = pkt488, .len = sizeof(pkt488) }, - { .cmd = pkt492, .len = sizeof(pkt492) }, - { .cmd = pkt496, .len = sizeof(pkt496) }, - { .cmd = pkt500, .len = sizeof(pkt500) }, - { .cmd = pkt504, .len = sizeof(pkt504) }, - { .cmd = pkt508, .len = sizeof(pkt508) }, - { .cmd = pkt512, .len = sizeof(pkt512) }, - { .cmd = pkt516, .len = sizeof(pkt516) }, - { .cmd = pkt520, .len = sizeof(pkt520) }, - { .cmd = pkt524, .len = sizeof(pkt524) }, - { .cmd = pkt528, .len = sizeof(pkt528) }, - { .cmd = pkt532, .len = sizeof(pkt532) }, - { .cmd = pkt536, .len = sizeof(pkt536) }, - { .cmd = pkt540, .len = sizeof(pkt540) }, - { .cmd = pkt544, .len = sizeof(pkt544) }, - { .cmd = pkt548, .len = sizeof(pkt548) }, - { .cmd = pkt552, .len = sizeof(pkt552) }, - { .cmd = pkt556, .len = sizeof(pkt556) }, - { .cmd = pkt560, .len = sizeof(pkt560) }, - { .cmd = pkt564, .len = sizeof(pkt564) }, - { .cmd = pkt568, .len = sizeof(pkt568) }, - { .cmd = pkt572, .len = sizeof(pkt572) }, - { .cmd = pkt576, .len = sizeof(pkt576) }, - { .cmd = pkt580, .len = sizeof(pkt580) }, - { .cmd = pkt584, .len = sizeof(pkt584) }, - { .cmd = pkt588, .len = sizeof(pkt588) }, - { .cmd = pkt592, .len = sizeof(pkt592) }, - { .cmd = pkt596, .len = sizeof(pkt596) }, - { .cmd = pkt600, .len = sizeof(pkt600) }, - { .cmd = pkt604, .len = sizeof(pkt604) }, + { .cmd = pkt433, .len = sizeof (pkt433) }, + { .cmd = pkt440, .len = sizeof (pkt440) }, + { .cmd = pkt444, .len = sizeof (pkt444) }, + { .cmd = pkt448, .len = sizeof (pkt448) }, + { .cmd = pkt452, .len = sizeof (pkt452) }, + { .cmd = pkt456, .len = sizeof (pkt456) }, + { .cmd = pkt460, .len = sizeof (pkt460) }, + { .cmd = pkt464, .len = sizeof (pkt464) }, + { .cmd = pkt468, .len = sizeof (pkt468) }, + { .cmd = pkt472, .len = sizeof (pkt472) }, + { .cmd = pkt476, .len = sizeof (pkt476) }, + { .cmd = pkt480, .len = sizeof (pkt480) }, + { .cmd = pkt484, .len = sizeof (pkt484) }, + { .cmd = pkt488, .len = sizeof (pkt488) }, + { .cmd = pkt492, .len = sizeof (pkt492) }, + { .cmd = pkt496, .len = sizeof (pkt496) }, + { .cmd = pkt500, .len = sizeof (pkt500) }, + { .cmd = pkt504, .len = sizeof (pkt504) }, + { .cmd = pkt508, .len = sizeof (pkt508) }, + { .cmd = pkt512, .len = sizeof (pkt512) }, + { .cmd = pkt516, .len = sizeof (pkt516) }, + { .cmd = pkt520, .len = sizeof (pkt520) }, + { .cmd = pkt524, .len = sizeof (pkt524) }, + { .cmd = pkt528, .len = sizeof (pkt528) }, + { .cmd = pkt532, .len = sizeof (pkt532) }, + { .cmd = pkt536, .len = sizeof (pkt536) }, + { .cmd = pkt540, .len = sizeof (pkt540) }, + { .cmd = pkt544, .len = sizeof (pkt544) }, + { .cmd = pkt548, .len = sizeof (pkt548) }, + { .cmd = pkt552, .len = sizeof (pkt552) }, + { .cmd = pkt556, .len = sizeof (pkt556) }, + { .cmd = pkt560, .len = sizeof (pkt560) }, + { .cmd = pkt564, .len = sizeof (pkt564) }, + { .cmd = pkt568, .len = sizeof (pkt568) }, + { .cmd = pkt572, .len = sizeof (pkt572) }, + { .cmd = pkt576, .len = sizeof (pkt576) }, + { .cmd = pkt580, .len = sizeof (pkt580) }, + { .cmd = pkt584, .len = sizeof (pkt584) }, + { .cmd = pkt588, .len = sizeof (pkt588) }, + { .cmd = pkt592, .len = sizeof (pkt592) }, + { .cmd = pkt596, .len = sizeof (pkt596) }, + { .cmd = pkt600, .len = sizeof (pkt600) }, + { .cmd = pkt604, .len = sizeof (pkt604) }, }; /* INIT2 is over, 0x07 cmd returns * { 0x07, 0x05, 0x00, 0x8f, 0x16, 0x25, 0x01, 0x63 } @@ -1979,12 +1979,12 @@ struct aesX660_cmd aes1660_init_2[] = { /* This command sequence starts imaging */ static const unsigned char aes1660_start_imaging_cmd[] = { -0x13, -0x20, -0x4c, 0x01, 0x00, 0x00, -0x4b, 0x04, 0x00, 0x78, 0x56, 0x34, 0x12, -0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0x7f, 0x00, 0x00, 0x14, -0x49, 0x03, 0x00, 0x20, 0x00, 0xc8 + 0x13, + 0x20, + 0x4c, 0x01, 0x00, 0x00, + 0x4b, 0x04, 0x00, 0x78, 0x56, 0x34, 0x12, + 0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0x7f, 0x00, 0x00, 0x14, + 0x49, 0x03, 0x00, 0x20, 0x00, 0xc8 }; #endif diff --git a/libfprint/drivers/aes2501.c b/libfprint/drivers/aes2501.c index c321b8c5..d073bae8 100644 --- a/libfprint/drivers/aes2501.c +++ b/libfprint/drivers/aes2501.c @@ -27,19 +27,19 @@ #include "aeslib.h" #include "aes2501.h" -static void start_capture(FpImageDevice *dev); -static void complete_deactivation(FpImageDevice *dev); +static void start_capture (FpImageDevice *dev); +static void complete_deactivation (FpImageDevice *dev); /* FIXME these need checking */ -#define EP_IN (1 | FPI_USB_ENDPOINT_IN) -#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) #define BULK_TIMEOUT 4000 -#define FINGER_DETECTION_LEN 20 -#define READ_REGS_LEN 126 -#define READ_REGS_RESP_LEN 159 -#define STRIP_CAPTURE_LEN 1705 +#define FINGER_DETECTION_LEN 20 +#define READ_REGS_LEN 126 +#define READ_REGS_RESP_LEN 159 +#define STRIP_CAPTURE_LEN 1705 /* * The AES2501 is an imaging device using a swipe-type sensor. It samples @@ -53,318 +53,345 @@ static void complete_deactivation(FpImageDevice *dev); * images returned from this driver vary in height. */ -#define FRAME_WIDTH 192 -#define FRAME_HEIGHT 16 -#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT) -#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2)) +#define FRAME_WIDTH 192 +#define FRAME_HEIGHT 16 +#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT) +#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2)) /* maximum number of frames to read during a scan */ /* FIXME reduce substantially */ -#define MAX_FRAMES 150 +#define MAX_FRAMES 150 /****** GENERAL FUNCTIONS ******/ -struct _FpiDeviceAes2501 { - FpImageDevice parent; +struct _FpiDeviceAes2501 +{ + FpImageDevice parent; - guint8 read_regs_retry_count; - GSList *strips; - size_t strips_len; - gboolean deactivating; - int no_finger_cnt; + guint8 read_regs_retry_count; + GSList *strips; + size_t strips_len; + gboolean deactivating; + int no_finger_cnt; }; -G_DECLARE_FINAL_TYPE(FpiDeviceAes2501, fpi_device_aes2501, FPI, DEVICE_AES2501, - FpImageDevice); -G_DEFINE_TYPE(FpiDeviceAes2501, fpi_device_aes2501, FP_TYPE_IMAGE_DEVICE); +G_DECLARE_FINAL_TYPE (FpiDeviceAes2501, fpi_device_aes2501, FPI, DEVICE_AES2501, + FpImageDevice); +G_DEFINE_TYPE (FpiDeviceAes2501, fpi_device_aes2501, FP_TYPE_IMAGE_DEVICE); static struct fpi_frame_asmbl_ctx assembling_ctx = { - .frame_width = FRAME_WIDTH, - .frame_height = FRAME_HEIGHT, - .image_width = IMAGE_WIDTH, - .get_pixel = aes_get_pixel, + .frame_width = FRAME_WIDTH, + .frame_height = FRAME_HEIGHT, + .image_width = IMAGE_WIDTH, + .get_pixel = aes_get_pixel, }; -typedef void (*aes2501_read_regs_cb)(FpImageDevice *dev, GError *error, - unsigned char *regs, void *user_data); +typedef void (*aes2501_read_regs_cb)(FpImageDevice *dev, + GError *error, + unsigned char *regs, + void *user_data); -struct aes2501_read_regs { - FpImageDevice *dev; - aes2501_read_regs_cb callback; - struct aes_regwrite *regwrite; - void *user_data; +struct aes2501_read_regs +{ + FpImageDevice *dev; + aes2501_read_regs_cb callback; + struct aes_regwrite *regwrite; + void *user_data; }; -static void read_regs_data_cb(FpiUsbTransfer *transfer, FpDevice *dev, - gpointer user_data, GError *error) +static void +read_regs_data_cb (FpiUsbTransfer *transfer, FpDevice *dev, + gpointer user_data, GError *error) { - struct aes2501_read_regs *rdata = user_data; + struct aes2501_read_regs *rdata = user_data; - rdata->callback(rdata->dev, error, transfer->buffer, rdata->user_data); - g_free(rdata); + rdata->callback (rdata->dev, error, transfer->buffer, rdata->user_data); + g_free (rdata); } -static void read_regs_rq_cb(FpImageDevice *dev, GError *error, void *user_data) +static void +read_regs_rq_cb (FpImageDevice *dev, GError *error, void *user_data) { - struct aes2501_read_regs *rdata = user_data; - FpiUsbTransfer *transfer; + struct aes2501_read_regs *rdata = user_data; + FpiUsbTransfer *transfer; - g_free(rdata->regwrite); - if (error) { - rdata->callback(dev, error, NULL, rdata->user_data); - g_free (rdata); - return; - } + g_free (rdata->regwrite); + if (error) + { + rdata->callback (dev, error, NULL, rdata->user_data); + g_free (rdata); + return; + } - transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); - transfer->short_is_error = TRUE; - fpi_usb_transfer_fill_bulk(transfer, EP_IN, READ_REGS_LEN); - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - read_regs_data_cb, rdata); - fpi_usb_transfer_unref(transfer); + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk (transfer, EP_IN, READ_REGS_LEN); + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + read_regs_data_cb, rdata); + fpi_usb_transfer_unref (transfer); } -static void read_regs(FpImageDevice *dev, aes2501_read_regs_cb callback, - void *user_data) +static void +read_regs (FpImageDevice *dev, aes2501_read_regs_cb callback, + void *user_data) { - /* FIXME: regwrite is dynamic because of asynchronity. is this really - * required? */ - struct aes_regwrite *regwrite = g_malloc(sizeof(*regwrite)); - struct aes2501_read_regs *rdata = g_malloc(sizeof(*rdata)); + /* FIXME: regwrite is dynamic because of asynchronity. is this really + * required? */ + struct aes_regwrite *regwrite = g_malloc (sizeof (*regwrite)); + struct aes2501_read_regs *rdata = g_malloc (sizeof (*rdata)); - G_DEBUG_HERE(); - regwrite->reg = AES2501_REG_CTRL2; - regwrite->value = AES2501_CTRL2_READ_REGS; - rdata->dev = dev; - rdata->callback = callback; - rdata->user_data = user_data; - rdata->regwrite = regwrite; + G_DEBUG_HERE (); + regwrite->reg = AES2501_REG_CTRL2; + regwrite->value = AES2501_CTRL2_READ_REGS; + rdata->dev = dev; + rdata->callback = callback; + rdata->user_data = user_data; + rdata->regwrite = regwrite; - aes_write_regv(dev, (const struct aes_regwrite *) regwrite, 1, - read_regs_rq_cb, rdata); + aes_write_regv (dev, (const struct aes_regwrite *) regwrite, 1, + read_regs_rq_cb, rdata); } /* Read the value of a specific register from a register dump */ -static int regval_from_dump(unsigned char *data, guint8 target) +static int +regval_from_dump (unsigned char *data, guint8 target) { - if (*data != FIRST_AES2501_REG) { - fp_err("not a register dump"); - return -1; - } + if (*data != FIRST_AES2501_REG) + { + fp_err ("not a register dump"); + return -1; + } - if (!(FIRST_AES2501_REG <= target && target <= LAST_AES2501_REG)) { - fp_err("out of range"); - return -1; - } + if (!(FIRST_AES2501_REG <= target && target <= LAST_AES2501_REG)) + { + fp_err ("out of range"); + return -1; + } - target -= FIRST_AES2501_REG; - target *= 2; - return data[target + 1]; + target -= FIRST_AES2501_REG; + target *= 2; + return data[target + 1]; } -static void generic_write_regv_cb(FpImageDevice *dev, GError *error, - void *user_data) +static void +generic_write_regv_cb (FpImageDevice *dev, GError *error, + void *user_data) { - FpiSsm *ssm = user_data; - if (!error) - fpi_ssm_next_state(ssm); - else - fpi_ssm_mark_failed(ssm, error); + FpiSsm *ssm = user_data; + + if (!error) + fpi_ssm_next_state (ssm); + else + fpi_ssm_mark_failed (ssm, error); } /* check that read succeeded but ignore all data */ -static void generic_ignore_data_cb(FpiUsbTransfer *transfer, FpDevice *dev, - gpointer user_data, GError *error) +static void +generic_ignore_data_cb (FpiUsbTransfer *transfer, FpDevice *dev, + gpointer user_data, GError *error) { - FpiSsm *ssm = transfer->ssm; - if (error) - fpi_ssm_mark_failed(ssm, error); - else - fpi_ssm_next_state(ssm); + FpiSsm *ssm = transfer->ssm; + + if (error) + fpi_ssm_mark_failed (ssm, error); + else + fpi_ssm_next_state (ssm); } /* read the specified number of bytes from the IN endpoint but throw them * away, then increment the SSM */ -static void generic_read_ignore_data(FpiSsm *ssm, FpDevice *dev, - size_t bytes) +static void +generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev, + size_t bytes) { - FpiUsbTransfer *transfer; + FpiUsbTransfer *transfer; - transfer = fpi_usb_transfer_new(dev); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_fill_bulk(transfer, EP_IN, bytes); - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - generic_ignore_data_cb, NULL); - fpi_usb_transfer_unref(transfer); + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk (transfer, EP_IN, bytes); + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + generic_ignore_data_cb, NULL); + fpi_usb_transfer_unref (transfer); } /****** IMAGE PROCESSING ******/ -static int sum_histogram_values(unsigned char *data, guint8 threshold) +static int +sum_histogram_values (unsigned char *data, guint8 threshold) { - int r = 0; - int i; - guint16 *histogram = (guint16 *)(data + 1); + int r = 0; + int i; + guint16 *histogram = (guint16 *) (data + 1); - if (*data != 0xde) - return -1; + if (*data != 0xde) + return -1; - if (threshold > 0x0f) - return -1; + if (threshold > 0x0f) + return -1; - /* FIXME endianness */ - for (i = threshold; i < 16; i++) - r += histogram[i]; - - return r; + /* FIXME endianness */ + for (i = threshold; i < 16; i++) + r += histogram[i]; + + return r; } /****** FINGER PRESENCE DETECTION ******/ static const struct aes_regwrite finger_det_reqs[] = { - { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, - { AES2501_REG_EXCITCTRL, 0x40 }, - { AES2501_REG_DETCTRL, - AES2501_DETCTRL_DRATE_CONTINUOUS | AES2501_DETCTRL_SDELAY_31_MS }, - { AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US }, - { AES2501_REG_MEASDRV, AES2501_MEASDRV_MDRIVE_0_325 | AES2501_MEASDRV_MEASURE_SQUARE }, - { AES2501_REG_MEASFREQ, AES2501_MEASFREQ_2M }, - { AES2501_REG_DEMODPHASE1, DEMODPHASE_NONE }, - { AES2501_REG_DEMODPHASE2, DEMODPHASE_NONE }, - { AES2501_REG_CHANGAIN, - AES2501_CHANGAIN_STAGE2_4X | AES2501_CHANGAIN_STAGE1_16X }, - { AES2501_REG_ADREFHI, 0x44 }, - { AES2501_REG_ADREFLO, 0x34 }, - { AES2501_REG_STRTCOL, 0x16 }, - { AES2501_REG_ENDCOL, 0x16 }, - { AES2501_REG_DATFMT, AES2501_DATFMT_BIN_IMG | 0x08 }, - { AES2501_REG_TREG1, 0x70 }, - { 0xa2, 0x02 }, - { 0xa7, 0x00 }, - { AES2501_REG_TREGC, AES2501_TREGC_ENABLE }, - { AES2501_REG_TREGD, 0x1a }, - { 0, 0 }, - { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, - { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT }, - { AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE }, + { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, + { AES2501_REG_EXCITCTRL, 0x40 }, + { AES2501_REG_DETCTRL, + AES2501_DETCTRL_DRATE_CONTINUOUS | AES2501_DETCTRL_SDELAY_31_MS }, + { AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US }, + { AES2501_REG_MEASDRV, AES2501_MEASDRV_MDRIVE_0_325 | AES2501_MEASDRV_MEASURE_SQUARE }, + { AES2501_REG_MEASFREQ, AES2501_MEASFREQ_2M }, + { AES2501_REG_DEMODPHASE1, DEMODPHASE_NONE }, + { AES2501_REG_DEMODPHASE2, DEMODPHASE_NONE }, + { AES2501_REG_CHANGAIN, + AES2501_CHANGAIN_STAGE2_4X | AES2501_CHANGAIN_STAGE1_16X }, + { AES2501_REG_ADREFHI, 0x44 }, + { AES2501_REG_ADREFLO, 0x34 }, + { AES2501_REG_STRTCOL, 0x16 }, + { AES2501_REG_ENDCOL, 0x16 }, + { AES2501_REG_DATFMT, AES2501_DATFMT_BIN_IMG | 0x08 }, + { AES2501_REG_TREG1, 0x70 }, + { 0xa2, 0x02 }, + { 0xa7, 0x00 }, + { AES2501_REG_TREGC, AES2501_TREGC_ENABLE }, + { AES2501_REG_TREGD, 0x1a }, + { 0, 0 }, + { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, + { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT }, + { AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE }, }; -static void start_finger_detection(FpImageDevice *dev); +static void start_finger_detection (FpImageDevice *dev); -static void finger_det_data_cb(FpiUsbTransfer *transfer, FpDevice *_dev, - gpointer user_data, GError *error) +static void +finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *_dev, + gpointer user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE(_dev); - unsigned char *data = transfer->buffer; - int i; - int sum = 0; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); + unsigned char *data = transfer->buffer; + int i; + int sum = 0; - if (error) { - fpi_image_device_session_error(dev, error); - return; - } + if (error) + { + fpi_image_device_session_error (dev, error); + return; + } - /* examine histogram to determine finger presence */ - for (i = 1; i < 9; i++) - sum += (data[i] & 0xf) + (data[i] >> 4); - if (sum > 20) { - /* finger present, start capturing */ - fpi_image_device_report_finger_status(dev, TRUE); - start_capture(dev); - } else { - /* no finger, poll for a new histogram */ - start_finger_detection(dev); - } + /* examine histogram to determine finger presence */ + for (i = 1; i < 9; i++) + sum += (data[i] & 0xf) + (data[i] >> 4); + if (sum > 20) + { + /* finger present, start capturing */ + fpi_image_device_report_finger_status (dev, TRUE); + start_capture (dev); + } + else + { + /* no finger, poll for a new histogram */ + start_finger_detection (dev); + } } -static void finger_det_reqs_cb(FpImageDevice *dev, GError *error, - void *user_data) +static void +finger_det_reqs_cb (FpImageDevice *dev, GError *error, + void *user_data) { - FpiUsbTransfer *transfer; + FpiUsbTransfer *transfer; - if (error) { - fpi_image_device_session_error (dev, error); - return; - } + if (error) + { + fpi_image_device_session_error (dev, error); + return; + } - transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); - transfer->short_is_error = TRUE; - fpi_usb_transfer_fill_bulk(transfer, EP_IN, FINGER_DETECTION_LEN); - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - finger_det_data_cb, NULL); - fpi_usb_transfer_unref(transfer); + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk (transfer, EP_IN, FINGER_DETECTION_LEN); + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + finger_det_data_cb, NULL); + fpi_usb_transfer_unref (transfer); } -static void start_finger_detection(FpImageDevice *dev) +static void +start_finger_detection (FpImageDevice *dev) { - FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(dev); - G_DEBUG_HERE(); + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev); - if (self->deactivating) { - complete_deactivation(dev); - return; - } + G_DEBUG_HERE (); - aes_write_regv(dev, finger_det_reqs, G_N_ELEMENTS(finger_det_reqs), - finger_det_reqs_cb, NULL); + if (self->deactivating) + { + complete_deactivation (dev); + return; + } + + aes_write_regv (dev, finger_det_reqs, G_N_ELEMENTS (finger_det_reqs), + finger_det_reqs_cb, NULL); } /****** CAPTURE ******/ static const struct aes_regwrite capture_reqs_1[] = { - { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, - { 0, 0 }, - { AES2501_REG_EXCITCTRL, 0x40 }, - { AES2501_REG_DETCTRL, - AES2501_DETCTRL_SDELAY_31_MS | AES2501_DETCTRL_DRATE_CONTINUOUS }, - { AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US }, - { AES2501_REG_DEMODPHASE2, 0x7c }, - { AES2501_REG_MEASDRV, - AES2501_MEASDRV_MEASURE_SQUARE | AES2501_MEASDRV_MDRIVE_0_325 }, - { AES2501_REG_DEMODPHASE1, 0x24 }, - { AES2501_REG_CHWORD1, 0x00 }, - { AES2501_REG_CHWORD2, 0x6c }, - { AES2501_REG_CHWORD3, 0x09 }, - { AES2501_REG_CHWORD4, 0x54 }, - { AES2501_REG_CHWORD5, 0x78 }, - { 0xa2, 0x02 }, - { 0xa7, 0x00 }, - { 0xb6, 0x26 }, - { 0xb7, 0x1a }, - { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, - { AES2501_REG_IMAGCTRL, - AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE | - AES2501_IMAGCTRL_IMG_DATA_DISABLE }, - { AES2501_REG_STRTCOL, 0x10 }, - { AES2501_REG_ENDCOL, 0x1f }, - { AES2501_REG_CHANGAIN, - AES2501_CHANGAIN_STAGE1_2X | AES2501_CHANGAIN_STAGE2_2X }, - { AES2501_REG_ADREFHI, 0x70 }, - { AES2501_REG_ADREFLO, 0x20 }, - { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT }, - { AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE }, + { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, + { 0, 0 }, + { AES2501_REG_EXCITCTRL, 0x40 }, + { AES2501_REG_DETCTRL, + AES2501_DETCTRL_SDELAY_31_MS | AES2501_DETCTRL_DRATE_CONTINUOUS }, + { AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US }, + { AES2501_REG_DEMODPHASE2, 0x7c }, + { AES2501_REG_MEASDRV, + AES2501_MEASDRV_MEASURE_SQUARE | AES2501_MEASDRV_MDRIVE_0_325 }, + { AES2501_REG_DEMODPHASE1, 0x24 }, + { AES2501_REG_CHWORD1, 0x00 }, + { AES2501_REG_CHWORD2, 0x6c }, + { AES2501_REG_CHWORD3, 0x09 }, + { AES2501_REG_CHWORD4, 0x54 }, + { AES2501_REG_CHWORD5, 0x78 }, + { 0xa2, 0x02 }, + { 0xa7, 0x00 }, + { 0xb6, 0x26 }, + { 0xb7, 0x1a }, + { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, + { AES2501_REG_IMAGCTRL, + AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE | + AES2501_IMAGCTRL_IMG_DATA_DISABLE }, + { AES2501_REG_STRTCOL, 0x10 }, + { AES2501_REG_ENDCOL, 0x1f }, + { AES2501_REG_CHANGAIN, + AES2501_CHANGAIN_STAGE1_2X | AES2501_CHANGAIN_STAGE2_2X }, + { AES2501_REG_ADREFHI, 0x70 }, + { AES2501_REG_ADREFLO, 0x20 }, + { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT }, + { AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE }, }; static const struct aes_regwrite capture_reqs_2[] = { - { AES2501_REG_IMAGCTRL, - AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE | - AES2501_IMAGCTRL_IMG_DATA_DISABLE }, - { AES2501_REG_STRTCOL, 0x10 }, - { AES2501_REG_ENDCOL, 0x1f }, - { AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE1_16X }, - { AES2501_REG_ADREFHI, 0x70 }, - { AES2501_REG_ADREFLO, 0x20 }, - { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT }, + { AES2501_REG_IMAGCTRL, + AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE | + AES2501_IMAGCTRL_IMG_DATA_DISABLE }, + { AES2501_REG_STRTCOL, 0x10 }, + { AES2501_REG_ENDCOL, 0x1f }, + { AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE1_16X }, + { AES2501_REG_ADREFHI, 0x70 }, + { AES2501_REG_ADREFLO, 0x20 }, + { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT }, }; static struct aes_regwrite strip_scan_reqs[] = { - { AES2501_REG_IMAGCTRL, - AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE }, - { AES2501_REG_STRTCOL, 0x00 }, - { AES2501_REG_ENDCOL, 0x2f }, - { AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE1_16X }, - { AES2501_REG_ADREFHI, AES2501_ADREFHI_MAX_VALUE }, - { AES2501_REG_ADREFLO, 0x20 }, - { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT }, + { AES2501_REG_IMAGCTRL, + AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE }, + { AES2501_REG_STRTCOL, 0x00 }, + { AES2501_REG_ENDCOL, 0x2f }, + { AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE1_16X }, + { AES2501_REG_ADREFHI, AES2501_ADREFHI_MAX_VALUE }, + { AES2501_REG_ADREFLO, 0x20 }, + { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT }, }; /* capture SM movement: @@ -374,448 +401,502 @@ static struct aes_regwrite strip_scan_reqs[] = { * report lack of finger presence, and move to finger detection */ enum capture_states { - CAPTURE_WRITE_REQS_1, - CAPTURE_READ_DATA_1, - CAPTURE_WRITE_REQS_2, - CAPTURE_READ_DATA_2, - CAPTURE_REQUEST_STRIP, - CAPTURE_READ_STRIP, - CAPTURE_NUM_STATES, + CAPTURE_WRITE_REQS_1, + CAPTURE_READ_DATA_1, + CAPTURE_WRITE_REQS_2, + CAPTURE_READ_DATA_2, + CAPTURE_REQUEST_STRIP, + CAPTURE_READ_STRIP, + CAPTURE_NUM_STATES, }; -static void capture_read_strip_cb(FpiUsbTransfer *transfer, FpDevice *_dev, - gpointer user_data, GError *error) +static void +capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *_dev, + gpointer user_data, GError *error) { - FpiSsm *ssm = transfer->ssm; - unsigned char *stripdata; - FpImageDevice *dev = FP_IMAGE_DEVICE(_dev); - FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(_dev); - unsigned char *data = transfer->buffer; - int sum; - int threshold; + FpiSsm *ssm = transfer->ssm; + unsigned char *stripdata; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (_dev); + unsigned char *data = transfer->buffer; + int sum; + int threshold; - if (error) { - fpi_ssm_mark_failed(ssm, error); - return; - } + if (error) + { + fpi_ssm_mark_failed (ssm, error); + return; + } - threshold = regval_from_dump(data + 1 + 192*8 + 1 + 16*2 + 1 + 8, - AES2501_REG_DATFMT); - if (threshold < 0) { - fpi_ssm_mark_failed(ssm, - fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - return; - } + threshold = regval_from_dump (data + 1 + 192 * 8 + 1 + 16 * 2 + 1 + 8, + AES2501_REG_DATFMT); + if (threshold < 0) + { + fpi_ssm_mark_failed (ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + return; + } - sum = sum_histogram_values(data + 1 + 192*8, threshold & 0x0f); - if (sum < 0) { - fpi_ssm_mark_failed(ssm, - fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - return; - } - fp_dbg("sum=%d", sum); + sum = sum_histogram_values (data + 1 + 192 * 8, threshold & 0x0f); + if (sum < 0) + { + fpi_ssm_mark_failed (ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + return; + } + fp_dbg ("sum=%d", sum); - if (sum < AES2501_SUM_LOW_THRESH) { - strip_scan_reqs[4].value -= 0x8; - if (strip_scan_reqs[4].value < AES2501_ADREFHI_MIN_VALUE) - strip_scan_reqs[4].value = AES2501_ADREFHI_MIN_VALUE; - } else if (sum > AES2501_SUM_HIGH_THRESH) { - strip_scan_reqs[4].value += 0x8; - if (strip_scan_reqs[4].value > AES2501_ADREFHI_MAX_VALUE) - strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE; - } - fp_dbg("ADREFHI is %.2x", strip_scan_reqs[4].value); + if (sum < AES2501_SUM_LOW_THRESH) + { + strip_scan_reqs[4].value -= 0x8; + if (strip_scan_reqs[4].value < AES2501_ADREFHI_MIN_VALUE) + strip_scan_reqs[4].value = AES2501_ADREFHI_MIN_VALUE; + } + else if (sum > AES2501_SUM_HIGH_THRESH) + { + strip_scan_reqs[4].value += 0x8; + if (strip_scan_reqs[4].value > AES2501_ADREFHI_MAX_VALUE) + strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE; + } + fp_dbg ("ADREFHI is %.2x", strip_scan_reqs[4].value); - /* Sum is 0, maybe finger was removed? Wait for 3 empty frames - * to ensure - */ - if (sum == 0) { - self->no_finger_cnt++; - if (self->no_finger_cnt == 3) { - FpImage *img; + /* Sum is 0, maybe finger was removed? Wait for 3 empty frames + * to ensure + */ + if (sum == 0) + { + self->no_finger_cnt++; + if (self->no_finger_cnt == 3) + { + FpImage *img; - self->strips = g_slist_reverse(self->strips); - fpi_do_movement_estimation(&assembling_ctx, self->strips); - img = fpi_assemble_frames(&assembling_ctx, - self->strips); - g_slist_free_full(self->strips, g_free); - self->strips = NULL; - self->strips_len = 0; - fpi_image_device_image_captured(dev, img); - fpi_image_device_report_finger_status(dev, FALSE); - /* marking machine complete will re-trigger finger detection loop */ - fpi_ssm_mark_completed(ssm); - } else { - fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP); - } - } else { - /* obtain next strip */ - /* FIXME: would preallocating strip buffers be a decent optimization? */ - struct fpi_frame *stripe = g_malloc(FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof(struct fpi_frame)); - stripe->delta_x = 0; - stripe->delta_y = 0; - stripdata = stripe->data; - memcpy(stripdata, data + 1, 192*8); - self->no_finger_cnt = 0; - self->strips = g_slist_prepend(self->strips, stripe); - self->strips_len++; + self->strips = g_slist_reverse (self->strips); + fpi_do_movement_estimation (&assembling_ctx, self->strips); + img = fpi_assemble_frames (&assembling_ctx, + self->strips); + g_slist_free_full (self->strips, g_free); + self->strips = NULL; + self->strips_len = 0; + fpi_image_device_image_captured (dev, img); + fpi_image_device_report_finger_status (dev, FALSE); + /* marking machine complete will re-trigger finger detection loop */ + fpi_ssm_mark_completed (ssm); + } + else + { + fpi_ssm_jump_to_state (ssm, CAPTURE_REQUEST_STRIP); + } + } + else + { + /* obtain next strip */ + /* FIXME: would preallocating strip buffers be a decent optimization? */ + struct fpi_frame *stripe = g_malloc (FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof (struct fpi_frame)); + stripe->delta_x = 0; + stripe->delta_y = 0; + stripdata = stripe->data; + memcpy (stripdata, data + 1, 192 * 8); + self->no_finger_cnt = 0; + self->strips = g_slist_prepend (self->strips, stripe); + self->strips_len++; - fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP); - } + fpi_ssm_jump_to_state (ssm, CAPTURE_REQUEST_STRIP); + } } -static void capture_run_state(FpiSsm *ssm, FpDevice *device, void *user_data) +static void +capture_run_state (FpiSsm *ssm, FpDevice *device, void *user_data) { - FpImageDevice *dev = user_data; - FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(device); + FpImageDevice *dev = user_data; + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (device); - switch (fpi_ssm_get_cur_state(ssm)) { - case CAPTURE_WRITE_REQS_1: - aes_write_regv(dev, capture_reqs_1, G_N_ELEMENTS(capture_reqs_1), - generic_write_regv_cb, ssm); - break; - case CAPTURE_READ_DATA_1: - generic_read_ignore_data(ssm, device, READ_REGS_RESP_LEN); - break; - case CAPTURE_WRITE_REQS_2: - aes_write_regv(dev, capture_reqs_2, G_N_ELEMENTS(capture_reqs_2), - generic_write_regv_cb, ssm); - break; - case CAPTURE_READ_DATA_2: - generic_read_ignore_data(ssm, device, READ_REGS_RESP_LEN); - break; - case CAPTURE_REQUEST_STRIP: - if (self->deactivating) - fpi_ssm_mark_completed(ssm); - else - aes_write_regv(dev, strip_scan_reqs, G_N_ELEMENTS(strip_scan_reqs), - generic_write_regv_cb, ssm); - break; - case CAPTURE_READ_STRIP: { - FpiUsbTransfer *transfer; + switch (fpi_ssm_get_cur_state (ssm)) + { + case CAPTURE_WRITE_REQS_1: + aes_write_regv (dev, capture_reqs_1, G_N_ELEMENTS (capture_reqs_1), + generic_write_regv_cb, ssm); + break; - transfer = fpi_usb_transfer_new(device); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_fill_bulk(transfer, EP_IN, STRIP_CAPTURE_LEN); - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - capture_read_strip_cb, NULL); - fpi_usb_transfer_unref(transfer); - break; - } - }; + case CAPTURE_READ_DATA_1: + generic_read_ignore_data (ssm, device, READ_REGS_RESP_LEN); + break; + + case CAPTURE_WRITE_REQS_2: + aes_write_regv (dev, capture_reqs_2, G_N_ELEMENTS (capture_reqs_2), + generic_write_regv_cb, ssm); + break; + + case CAPTURE_READ_DATA_2: + generic_read_ignore_data (ssm, device, READ_REGS_RESP_LEN); + break; + + case CAPTURE_REQUEST_STRIP: + if (self->deactivating) + fpi_ssm_mark_completed (ssm); + else + aes_write_regv (dev, strip_scan_reqs, G_N_ELEMENTS (strip_scan_reqs), + generic_write_regv_cb, ssm); + break; + + case CAPTURE_READ_STRIP: { + FpiUsbTransfer *transfer; + + transfer = fpi_usb_transfer_new (device); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk (transfer, EP_IN, STRIP_CAPTURE_LEN); + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + capture_read_strip_cb, NULL); + fpi_usb_transfer_unref (transfer); + break; + } + } + ; } -static void capture_sm_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +static void +capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - FpImageDevice *dev = user_data; - FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(_dev); + FpImageDevice *dev = user_data; + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (_dev); - G_DEBUG_HERE(); + G_DEBUG_HERE (); - if (self->deactivating) { - complete_deactivation(dev); - g_clear_pointer (&error, g_error_free); - } else if (error) { - fpi_image_device_session_error(dev, error); - } else { - start_finger_detection(dev); - } - fpi_ssm_free(ssm); + if (self->deactivating) + { + complete_deactivation (dev); + g_clear_pointer (&error, g_error_free); + } + else if (error) + { + fpi_image_device_session_error (dev, error); + } + else + { + start_finger_detection (dev); + } + fpi_ssm_free (ssm); } -static void start_capture(FpImageDevice *dev) +static void +start_capture (FpImageDevice *dev) { - FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(dev); - FpiSsm *ssm; + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev); + FpiSsm *ssm; - if (self->deactivating) { - complete_deactivation(dev); - return; - } + if (self->deactivating) + { + complete_deactivation (dev); + return; + } - self->no_finger_cnt = 0; - /* Reset gain */ - strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE; - ssm = fpi_ssm_new(FP_DEVICE(dev), capture_run_state, - CAPTURE_NUM_STATES, dev); - G_DEBUG_HERE(); - fpi_ssm_start(ssm, capture_sm_complete); + self->no_finger_cnt = 0; + /* Reset gain */ + strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE; + ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, + CAPTURE_NUM_STATES, dev); + G_DEBUG_HERE (); + fpi_ssm_start (ssm, capture_sm_complete); } /****** INITIALIZATION/DEINITIALIZATION ******/ static const struct aes_regwrite init_1[] = { - { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, - { 0, 0 }, - { 0xb0, 0x27 }, /* Reserved? */ - { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, - { AES2501_REG_EXCITCTRL, 0x40 }, - { 0xff, 0x00 }, /* Reserved? */ - { 0xff, 0x00 }, /* Reserved? */ - { 0xff, 0x00 }, /* Reserved? */ - { 0xff, 0x00 }, /* Reserved? */ - { 0xff, 0x00 }, /* Reserved? */ - { 0xff, 0x00 }, /* Reserved? */ - { 0xff, 0x00 }, /* Reserved? */ - { 0xff, 0x00 }, /* Reserved? */ - { 0xff, 0x00 }, /* Reserved? */ - { 0xff, 0x00 }, /* Reserved? */ - { 0xff, 0x00 }, /* Reserved? */ - { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, - { AES2501_REG_EXCITCTRL, 0x40 }, - { AES2501_REG_DETCTRL, - AES2501_DETCTRL_DRATE_CONTINUOUS | AES2501_DETCTRL_SDELAY_31_MS }, - { AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US }, - { AES2501_REG_MEASDRV, - AES2501_MEASDRV_MDRIVE_0_325 | AES2501_MEASDRV_MEASURE_SQUARE }, - { AES2501_REG_MEASFREQ, AES2501_MEASFREQ_2M }, - { AES2501_REG_DEMODPHASE1, DEMODPHASE_NONE }, - { AES2501_REG_DEMODPHASE2, DEMODPHASE_NONE }, - { AES2501_REG_CHANGAIN, - AES2501_CHANGAIN_STAGE2_4X | AES2501_CHANGAIN_STAGE1_16X }, - { AES2501_REG_ADREFHI, 0x44 }, - { AES2501_REG_ADREFLO, 0x34 }, - { AES2501_REG_STRTCOL, 0x16 }, - { AES2501_REG_ENDCOL, 0x16 }, - { AES2501_REG_DATFMT, AES2501_DATFMT_BIN_IMG | 0x08 }, - { AES2501_REG_TREG1, 0x70 }, - { 0xa2, 0x02 }, - { 0xa7, 0x00 }, - { AES2501_REG_TREGC, AES2501_TREGC_ENABLE }, - { AES2501_REG_TREGD, 0x1a }, - { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, - { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT }, - { AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE }, + { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, + { 0, 0 }, + { 0xb0, 0x27 }, /* Reserved? */ + { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, + { AES2501_REG_EXCITCTRL, 0x40 }, + { 0xff, 0x00 }, /* Reserved? */ + { 0xff, 0x00 }, /* Reserved? */ + { 0xff, 0x00 }, /* Reserved? */ + { 0xff, 0x00 }, /* Reserved? */ + { 0xff, 0x00 }, /* Reserved? */ + { 0xff, 0x00 }, /* Reserved? */ + { 0xff, 0x00 }, /* Reserved? */ + { 0xff, 0x00 }, /* Reserved? */ + { 0xff, 0x00 }, /* Reserved? */ + { 0xff, 0x00 }, /* Reserved? */ + { 0xff, 0x00 }, /* Reserved? */ + { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, + { AES2501_REG_EXCITCTRL, 0x40 }, + { AES2501_REG_DETCTRL, + AES2501_DETCTRL_DRATE_CONTINUOUS | AES2501_DETCTRL_SDELAY_31_MS }, + { AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US }, + { AES2501_REG_MEASDRV, + AES2501_MEASDRV_MDRIVE_0_325 | AES2501_MEASDRV_MEASURE_SQUARE }, + { AES2501_REG_MEASFREQ, AES2501_MEASFREQ_2M }, + { AES2501_REG_DEMODPHASE1, DEMODPHASE_NONE }, + { AES2501_REG_DEMODPHASE2, DEMODPHASE_NONE }, + { AES2501_REG_CHANGAIN, + AES2501_CHANGAIN_STAGE2_4X | AES2501_CHANGAIN_STAGE1_16X }, + { AES2501_REG_ADREFHI, 0x44 }, + { AES2501_REG_ADREFLO, 0x34 }, + { AES2501_REG_STRTCOL, 0x16 }, + { AES2501_REG_ENDCOL, 0x16 }, + { AES2501_REG_DATFMT, AES2501_DATFMT_BIN_IMG | 0x08 }, + { AES2501_REG_TREG1, 0x70 }, + { 0xa2, 0x02 }, + { 0xa7, 0x00 }, + { AES2501_REG_TREGC, AES2501_TREGC_ENABLE }, + { AES2501_REG_TREGD, 0x1a }, + { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, + { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT }, + { AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE }, }; static const struct aes_regwrite init_2[] = { - { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, - { AES2501_REG_EXCITCTRL, 0x40 }, - { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, - { AES2501_REG_AUTOCALOFFSET, 0x41 }, - { AES2501_REG_EXCITCTRL, 0x42 }, - { AES2501_REG_DETCTRL, 0x53 }, - { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, + { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, + { AES2501_REG_EXCITCTRL, 0x40 }, + { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, + { AES2501_REG_AUTOCALOFFSET, 0x41 }, + { AES2501_REG_EXCITCTRL, 0x42 }, + { AES2501_REG_DETCTRL, 0x53 }, + { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, }; static const struct aes_regwrite init_3[] = { - { 0xff, 0x00 }, - { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, - { AES2501_REG_AUTOCALOFFSET, 0x41 }, - { AES2501_REG_EXCITCTRL, 0x42 }, - { AES2501_REG_DETCTRL, 0x53 }, - { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, + { 0xff, 0x00 }, + { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, + { AES2501_REG_AUTOCALOFFSET, 0x41 }, + { AES2501_REG_EXCITCTRL, 0x42 }, + { AES2501_REG_DETCTRL, 0x53 }, + { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, }; static const struct aes_regwrite init_4[] = { - { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, - { AES2501_REG_EXCITCTRL, 0x40 }, - { 0xb0, 0x27 }, - { AES2501_REG_ENDROW, 0x0a }, - { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, - { AES2501_REG_DETCTRL, 0x45 }, - { AES2501_REG_AUTOCALOFFSET, 0x41 }, + { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, + { AES2501_REG_EXCITCTRL, 0x40 }, + { 0xb0, 0x27 }, + { AES2501_REG_ENDROW, 0x0a }, + { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE }, + { AES2501_REG_DETCTRL, 0x45 }, + { AES2501_REG_AUTOCALOFFSET, 0x41 }, }; static const struct aes_regwrite init_5[] = { - { 0xb0, 0x27 }, - { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, - { AES2501_REG_EXCITCTRL, 0x40 }, - { 0xff, 0x00 }, - { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, - { AES2501_REG_EXCITCTRL, 0x40 }, - { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, - { AES2501_REG_EXCITCTRL, 0x40 }, - { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, - { AES2501_REG_EXCITCTRL, 0x40 }, - { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, - { AES2501_REG_EXCITCTRL, 0x40 }, - { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, - { AES2501_REG_EXCITCTRL, 0x40 }, - { AES2501_REG_CTRL1, AES2501_CTRL1_SCAN_RESET }, - { AES2501_REG_CTRL1, AES2501_CTRL1_SCAN_RESET }, + { 0xb0, 0x27 }, + { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, + { AES2501_REG_EXCITCTRL, 0x40 }, + { 0xff, 0x00 }, + { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, + { AES2501_REG_EXCITCTRL, 0x40 }, + { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, + { AES2501_REG_EXCITCTRL, 0x40 }, + { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, + { AES2501_REG_EXCITCTRL, 0x40 }, + { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, + { AES2501_REG_EXCITCTRL, 0x40 }, + { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET }, + { AES2501_REG_EXCITCTRL, 0x40 }, + { AES2501_REG_CTRL1, AES2501_CTRL1_SCAN_RESET }, + { AES2501_REG_CTRL1, AES2501_CTRL1_SCAN_RESET }, }; enum activate_states { - WRITE_INIT_1, - READ_DATA_1, - WRITE_INIT_2, - READ_REGS, - WRITE_INIT_3, - WRITE_INIT_4, - WRITE_INIT_5, - ACTIVATE_NUM_STATES, + WRITE_INIT_1, + READ_DATA_1, + WRITE_INIT_2, + READ_REGS, + WRITE_INIT_3, + WRITE_INIT_4, + WRITE_INIT_5, + ACTIVATE_NUM_STATES, }; -void activate_read_regs_cb(FpImageDevice *dev, GError *error, - unsigned char *regs, void *user_data) +void +activate_read_regs_cb (FpImageDevice *dev, GError *error, + unsigned char *regs, void *user_data) { - FpiSsm *ssm = user_data; - FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(dev); + FpiSsm *ssm = user_data; + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev); - if (error) { - fpi_ssm_mark_failed(ssm, error); - } else { - fp_dbg("reg 0xaf = %x", regs[0x5f]); - if (regs[0x5f] != 0x6b || ++self->read_regs_retry_count == 13) - fpi_ssm_jump_to_state(ssm, WRITE_INIT_4); - else - fpi_ssm_next_state(ssm); - } + if (error) + { + fpi_ssm_mark_failed (ssm, error); + } + else + { + fp_dbg ("reg 0xaf = %x", regs[0x5f]); + if (regs[0x5f] != 0x6b || ++self->read_regs_retry_count == 13) + fpi_ssm_jump_to_state (ssm, WRITE_INIT_4); + else + fpi_ssm_next_state (ssm); + } } -static void activate_init3_cb(FpImageDevice *dev, GError *error, - void *user_data) +static void +activate_init3_cb (FpImageDevice *dev, GError *error, + void *user_data) { - FpiSsm *ssm = user_data; - if (!error) - fpi_ssm_jump_to_state(ssm, READ_REGS); - else - fpi_ssm_mark_failed(ssm, error); + FpiSsm *ssm = user_data; + + if (!error) + fpi_ssm_jump_to_state (ssm, READ_REGS); + else + fpi_ssm_mark_failed (ssm, error); } -static void activate_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +activate_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = user_data; - /* This state machine isn't as linear as it may appear. After doing init1 - * and init2 register configuration writes, we have to poll a register - * waiting for a specific value. READ_REGS checks the register value, and - * if we're ready to move on, we jump to init4. Otherwise, we write init3 - * and then jump back to READ_REGS. In a synchronous model: + /* This state machine isn't as linear as it may appear. After doing init1 + * and init2 register configuration writes, we have to poll a register + * waiting for a specific value. READ_REGS checks the register value, and + * if we're ready to move on, we jump to init4. Otherwise, we write init3 + * and then jump back to READ_REGS. In a synchronous model: - [...] - aes_write_regv(init_2); - read_regs(into buffer); - i = 0; - while (buffer[0x5f] == 0x6b) { - aes_write_regv(init_3); - read_regs(into buffer); - if (++i == 13) - break; - } - aes_write_regv(init_4); - */ + [...] + aes_write_regv(init_2); + read_regs(into buffer); + i = 0; + while (buffer[0x5f] == 0x6b) { + aes_write_regv(init_3); + read_regs(into buffer); + if (++i == 13) + break; + } + aes_write_regv(init_4); + */ - switch (fpi_ssm_get_cur_state(ssm)) { - case WRITE_INIT_1: - aes_write_regv(dev, init_1, G_N_ELEMENTS(init_1), - generic_write_regv_cb, ssm); - break; - case READ_DATA_1: - fp_dbg("read data 1"); - generic_read_ignore_data(ssm, _dev, FINGER_DETECTION_LEN); - break; - case WRITE_INIT_2: - aes_write_regv(dev, init_2, G_N_ELEMENTS(init_2), - generic_write_regv_cb, ssm); - break; - case READ_REGS: - read_regs(dev, activate_read_regs_cb, ssm); - break; - case WRITE_INIT_3: - aes_write_regv(dev, init_3, G_N_ELEMENTS(init_3), - activate_init3_cb, ssm); - break; - case WRITE_INIT_4: - aes_write_regv(dev, init_4, G_N_ELEMENTS(init_4), - generic_write_regv_cb, ssm); - break; - case WRITE_INIT_5: - aes_write_regv(dev, init_5, G_N_ELEMENTS(init_5), - generic_write_regv_cb, ssm); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case WRITE_INIT_1: + aes_write_regv (dev, init_1, G_N_ELEMENTS (init_1), + generic_write_regv_cb, ssm); + break; + + case READ_DATA_1: + fp_dbg ("read data 1"); + generic_read_ignore_data (ssm, _dev, FINGER_DETECTION_LEN); + break; + + case WRITE_INIT_2: + aes_write_regv (dev, init_2, G_N_ELEMENTS (init_2), + generic_write_regv_cb, ssm); + break; + + case READ_REGS: + read_regs (dev, activate_read_regs_cb, ssm); + break; + + case WRITE_INIT_3: + aes_write_regv (dev, init_3, G_N_ELEMENTS (init_3), + activate_init3_cb, ssm); + break; + + case WRITE_INIT_4: + aes_write_regv (dev, init_4, G_N_ELEMENTS (init_4), + generic_write_regv_cb, ssm); + break; + + case WRITE_INIT_5: + aes_write_regv (dev, init_5, G_N_ELEMENTS (init_5), + generic_write_regv_cb, ssm); + break; + } } -static void activate_sm_complete(FpiSsm *ssm, FpDevice *dev, - void *user_data, GError *error) +static void +activate_sm_complete (FpiSsm *ssm, FpDevice *dev, + void *user_data, GError *error) { - fpi_image_device_activate_complete(FP_IMAGE_DEVICE (dev), error); + fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error); - if (!error) - start_finger_detection(FP_IMAGE_DEVICE (dev)); - fpi_ssm_free(ssm); + if (!error) + start_finger_detection (FP_IMAGE_DEVICE (dev)); + fpi_ssm_free (ssm); } -static void dev_activate(FpImageDevice *dev) +static void +dev_activate (FpImageDevice *dev) { - FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(dev); - FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); - self->read_regs_retry_count = 0; - fpi_ssm_start(ssm, activate_sm_complete); + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev); + FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); + + self->read_regs_retry_count = 0; + fpi_ssm_start (ssm, activate_sm_complete); } -static void dev_deactivate(FpImageDevice *dev) +static void +dev_deactivate (FpImageDevice *dev) { - FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(dev); - /* FIXME: audit cancellation points, probably need more, specifically - * in error handling paths? */ - self->deactivating = TRUE; + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev); + + /* FIXME: audit cancellation points, probably need more, specifically + * in error handling paths? */ + self->deactivating = TRUE; } -static void complete_deactivation(FpImageDevice *dev) +static void +complete_deactivation (FpImageDevice *dev) { - FpiDeviceAes2501 *self = FPI_DEVICE_AES2501(dev); - G_DEBUG_HERE(); + FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev); - /* FIXME: if we're in the middle of a scan, we should cancel the scan. - * maybe we can do this with a master reset, unconditionally? */ + G_DEBUG_HERE (); - self->deactivating = FALSE; - g_slist_free(self->strips); - self->strips = NULL; - self->strips_len = 0; - fpi_image_device_deactivate_complete(dev, NULL); + /* FIXME: if we're in the middle of a scan, we should cancel the scan. + * maybe we can do this with a master reset, unconditionally? */ + + self->deactivating = FALSE; + g_slist_free (self->strips); + self->strips = NULL; + self->strips_len = 0; + fpi_image_device_deactivate_complete (dev, NULL); } -static void dev_init(FpImageDevice *dev) +static void +dev_init (FpImageDevice *dev) { - GError *error = NULL; - /* FIXME check endpoints */ + GError *error = NULL; - g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error); - fpi_image_device_open_complete(dev, error); + /* FIXME check endpoints */ + + g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error); + fpi_image_device_open_complete (dev, error); } -static void dev_deinit(FpImageDevice *dev) +static void +dev_deinit (FpImageDevice *dev) { - GError *error = NULL; + GError *error = NULL; - g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), - 0, 0, &error); - fpi_image_device_close_complete(dev, error); + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), + 0, 0, &error); + fpi_image_device_close_complete (dev, error); } -static const FpIdEntry id_table [ ] = { - { .vid = 0x08ff, .pid = 0x2500, - }, /* AES2500 */ - { .vid = 0x08ff, .pid = 0x2580, - }, /* AES2501 */ - { .vid = 0, .pid = 0, .driver_data = 0 }, +static const FpIdEntry id_table[] = { + { .vid = 0x08ff, .pid = 0x2500, },/* AES2500 */ + { .vid = 0x08ff, .pid = 0x2580, },/* AES2501 */ + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -static void fpi_device_aes2501_init(FpiDeviceAes2501 *self) { +static void +fpi_device_aes2501_init (FpiDeviceAes2501 *self) +{ } -static void fpi_device_aes2501_class_init(FpiDeviceAes2501Class *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); +static void +fpi_device_aes2501_class_init (FpiDeviceAes2501Class *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); - dev_class->id = "aes2501"; - dev_class->full_name = "AuthenTec AES2501"; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->id_table = id_table; - dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + dev_class->id = "aes2501"; + dev_class->full_name = "AuthenTec AES2501"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - img_class->img_open = dev_init; - img_class->img_close = dev_deinit; - img_class->activate = dev_activate; - img_class->deactivate = dev_deactivate; + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; - img_class->img_width = IMAGE_WIDTH; - img_class->img_height = -1; + img_class->img_width = IMAGE_WIDTH; + img_class->img_height = -1; } - diff --git a/libfprint/drivers/aes2501.h b/libfprint/drivers/aes2501.h index 19adcc90..dc802ca8 100644 --- a/libfprint/drivers/aes2501.h +++ b/libfprint/drivers/aes2501.h @@ -23,149 +23,149 @@ #define __AES2501_H enum aes2501_regs { - AES2501_REG_CTRL1 = 0x80, - AES2501_REG_CTRL2 = 0x81, - AES2501_REG_EXCITCTRL = 0x82, /* excitation control */ - AES2501_REG_DETCTRL = 0x83, /* detect control */ - AES2501_REG_COLSCAN = 0x88, /* column scan rate register */ - AES2501_REG_MEASDRV = 0x89, /* measure drive */ - AES2501_REG_MEASFREQ = 0x8a, /* measure frequency */ - AES2501_REG_DEMODPHASE1 = 0x8d, - AES2501_REG_DEMODPHASE2 = 0x8c, - AES2501_REG_CHANGAIN = 0x8e, /* channel gain */ - AES2501_REG_ADREFHI = 0x91, /* A/D reference high */ - AES2501_REG_ADREFLO = 0x92, /* A/D reference low */ - AES2501_REG_STRTROW = 0x93, /* start row */ - AES2501_REG_ENDROW = 0x94, /* end row */ - AES2501_REG_STRTCOL = 0x95, /* start column */ - AES2501_REG_ENDCOL = 0x96, /* end column */ - AES2501_REG_DATFMT = 0x97, /* data format */ - AES2501_REG_IMAGCTRL = 0x98, /* image data */ - AES2501_REG_STAT = 0x9a, - AES2501_REG_CHWORD1 = 0x9b, /* challenge word 1 */ - AES2501_REG_CHWORD2 = 0x9c, - AES2501_REG_CHWORD3 = 0x9d, - AES2501_REG_CHWORD4 = 0x9e, - AES2501_REG_CHWORD5 = 0x9f, - AES2501_REG_TREG1 = 0xa1, /* test register 1 */ - AES2501_REG_AUTOCALOFFSET = 0xa8, - AES2501_REG_TREGC = 0xac, - AES2501_REG_TREGD = 0xad, - AES2501_REG_LPONT = 0xb4, /* low power oscillator on time */ + AES2501_REG_CTRL1 = 0x80, + AES2501_REG_CTRL2 = 0x81, + AES2501_REG_EXCITCTRL = 0x82, /* excitation control */ + AES2501_REG_DETCTRL = 0x83, /* detect control */ + AES2501_REG_COLSCAN = 0x88, /* column scan rate register */ + AES2501_REG_MEASDRV = 0x89, /* measure drive */ + AES2501_REG_MEASFREQ = 0x8a, /* measure frequency */ + AES2501_REG_DEMODPHASE1 = 0x8d, + AES2501_REG_DEMODPHASE2 = 0x8c, + AES2501_REG_CHANGAIN = 0x8e, /* channel gain */ + AES2501_REG_ADREFHI = 0x91, /* A/D reference high */ + AES2501_REG_ADREFLO = 0x92, /* A/D reference low */ + AES2501_REG_STRTROW = 0x93, /* start row */ + AES2501_REG_ENDROW = 0x94, /* end row */ + AES2501_REG_STRTCOL = 0x95, /* start column */ + AES2501_REG_ENDCOL = 0x96, /* end column */ + AES2501_REG_DATFMT = 0x97, /* data format */ + AES2501_REG_IMAGCTRL = 0x98, /* image data */ + AES2501_REG_STAT = 0x9a, + AES2501_REG_CHWORD1 = 0x9b, /* challenge word 1 */ + AES2501_REG_CHWORD2 = 0x9c, + AES2501_REG_CHWORD3 = 0x9d, + AES2501_REG_CHWORD4 = 0x9e, + AES2501_REG_CHWORD5 = 0x9f, + AES2501_REG_TREG1 = 0xa1, /* test register 1 */ + AES2501_REG_AUTOCALOFFSET = 0xa8, + AES2501_REG_TREGC = 0xac, + AES2501_REG_TREGD = 0xad, + AES2501_REG_LPONT = 0xb4, /* low power oscillator on time */ }; -#define FIRST_AES2501_REG AES2501_REG_CTRL1 -#define LAST_AES2501_REG AES2501_REG_CHWORD5 +#define FIRST_AES2501_REG AES2501_REG_CTRL1 +#define LAST_AES2501_REG AES2501_REG_CHWORD5 -#define AES2501_CTRL1_MASTER_RESET (1<<0) -#define AES2501_CTRL1_SCAN_RESET (1<<1) /* stop + restart scan sequencer */ +#define AES2501_CTRL1_MASTER_RESET (1 << 0) +#define AES2501_CTRL1_SCAN_RESET (1 << 1) /* stop + restart scan sequencer */ /* 1 = continuously updated, 0 = updated prior to starting a scan */ -#define AES2501_CTRL1_REG_UPDATE (1<<2) +#define AES2501_CTRL1_REG_UPDATE (1 << 2) /* 1 = continuous scans, 0 = single scans */ -#define AES2501_CTRL2_CONTINUOUS 0x01 -#define AES2501_CTRL2_READ_REGS 0x02 /* dump registers */ -#define AES2501_CTRL2_SET_ONE_SHOT 0x04 -#define AES2501_CTRL2_CLR_ONE_SHOT 0x08 -#define AES2501_CTRL2_READ_ID 0x10 +#define AES2501_CTRL2_CONTINUOUS 0x01 +#define AES2501_CTRL2_READ_REGS 0x02 /* dump registers */ +#define AES2501_CTRL2_SET_ONE_SHOT 0x04 +#define AES2501_CTRL2_CLR_ONE_SHOT 0x08 +#define AES2501_CTRL2_READ_ID 0x10 enum aes2501_detection_rate { - /* rate of detection cycles: */ - AES2501_DETCTRL_DRATE_CONTINUOUS = 0x00, /* continuously */ - AES2501_DETCTRL_DRATE_16_MS = 0x01, /* every 16.62ms */ - AES2501_DETCTRL_DRATE_31_MS = 0x02, /* every 31.24ms */ - AES2501_DETCTRL_DRATE_62_MS = 0x03, /* every 62.50ms */ - AES2501_DETCTRL_DRATE_125_MS = 0x04, /* every 125.0ms */ - AES2501_DETCTRL_DRATE_250_MS = 0x05, /* every 250.0ms */ - AES2501_DETCTRL_DRATE_500_MS = 0x06, /* every 500.0ms */ - AES2501_DETCTRL_DRATE_1_S = 0x07, /* every 1s */ + /* rate of detection cycles: */ + AES2501_DETCTRL_DRATE_CONTINUOUS = 0x00, /* continuously */ + AES2501_DETCTRL_DRATE_16_MS = 0x01, /* every 16.62ms */ + AES2501_DETCTRL_DRATE_31_MS = 0x02, /* every 31.24ms */ + AES2501_DETCTRL_DRATE_62_MS = 0x03, /* every 62.50ms */ + AES2501_DETCTRL_DRATE_125_MS = 0x04, /* every 125.0ms */ + AES2501_DETCTRL_DRATE_250_MS = 0x05, /* every 250.0ms */ + AES2501_DETCTRL_DRATE_500_MS = 0x06, /* every 500.0ms */ + AES2501_DETCTRL_DRATE_1_S = 0x07, /* every 1s */ }; enum aes2501_settling_delay { - AES2501_DETCTRL_SDELAY_31_MS = 0x00, /* 31.25ms */ - AES2501_DETCTRL_SSDELAY_62_MS = 0x10, /* 62.5ms */ - AES2501_DETCTRL_SSDELAY_125_MS = 0x20, /* 125ms */ - AES2501_DETCTRL_SSDELAY_250_MS = 0x30 /* 250ms */ + AES2501_DETCTRL_SDELAY_31_MS = 0x00, /* 31.25ms */ + AES2501_DETCTRL_SSDELAY_62_MS = 0x10, /* 62.5ms */ + AES2501_DETCTRL_SSDELAY_125_MS = 0x20, /* 125ms */ + AES2501_DETCTRL_SSDELAY_250_MS = 0x30 /* 250ms */ }; enum aes2501_col_scan_rate { - AES2501_COLSCAN_SRATE_32_US = 0x00, /* 32us */ - AES2501_COLSCAN_SRATE_64_US = 0x01, /* 64us */ - AES2501_COLSCAN_SRATE_128_US = 0x02, /* 128us */ - AES2501_COLSCAN_SRATE_256_US = 0x03, /* 256us */ - AES2501_COLSCAN_SRATE_512_US = 0x04, /* 512us */ - AES2501_COLSCAN_SRATE_1024_US = 0x05, /* 1024us */ - AES2501_COLSCAN_SRATE_2048_US = 0x06, /* 2048us */ + AES2501_COLSCAN_SRATE_32_US = 0x00, /* 32us */ + AES2501_COLSCAN_SRATE_64_US = 0x01, /* 64us */ + AES2501_COLSCAN_SRATE_128_US = 0x02, /* 128us */ + AES2501_COLSCAN_SRATE_256_US = 0x03, /* 256us */ + AES2501_COLSCAN_SRATE_512_US = 0x04, /* 512us */ + AES2501_COLSCAN_SRATE_1024_US = 0x05, /* 1024us */ + AES2501_COLSCAN_SRATE_2048_US = 0x06, /* 2048us */ }; enum aes2501_mesure_drive { - AES2501_MEASDRV_MDRIVE_0_325 = 0x00, /* 0.325 Vpp */ - AES2501_MEASDRV_MDRIVE_0_65 = 0x01, /* 0.65 Vpp */ - AES2501_MEASDRV_MDRIVE_1_3 = 0x02, /* 1.3 Vpp */ - AES2501_MEASDRV_MDRIVE_2_6 = 0x03 /* 2.6 Vpp */ + AES2501_MEASDRV_MDRIVE_0_325 = 0x00, /* 0.325 Vpp */ + AES2501_MEASDRV_MDRIVE_0_65 = 0x01, /* 0.65 Vpp */ + AES2501_MEASDRV_MDRIVE_1_3 = 0x02, /* 1.3 Vpp */ + AES2501_MEASDRV_MDRIVE_2_6 = 0x03 /* 2.6 Vpp */ }; /* Select (1=square | 0=sine) wave drive during measure */ -#define AES2501_MEASDRV_SQUARE 0x20 +#define AES2501_MEASDRV_SQUARE 0x20 /* 0 = use measure drive setting, 1 = when sine wave is selected */ -#define AES2501_MEASDRV_MEASURE_SQUARE 0x10 +#define AES2501_MEASDRV_MEASURE_SQUARE 0x10 enum aes2501_measure_freq { - AES2501_MEASFREQ_125K = 0x01, /* 125 kHz */ - AES2501_MEASFREQ_250K = 0x02, /* 250 kHz */ - AES2501_MEASFREQ_500K = 0x03, /* 500 kHz */ - AES2501_MEASFREQ_1M = 0x04, /* 1 MHz */ - AES2501_MEASFREQ_2M = 0x05 /* 2 MHz */ + AES2501_MEASFREQ_125K = 0x01, /* 125 kHz */ + AES2501_MEASFREQ_250K = 0x02, /* 250 kHz */ + AES2501_MEASFREQ_500K = 0x03, /* 500 kHz */ + AES2501_MEASFREQ_1M = 0x04, /* 1 MHz */ + AES2501_MEASFREQ_2M = 0x05 /* 2 MHz */ }; -#define DEMODPHASE_NONE 0x00 -#define DEMODPHASE_180_00 0x40 /* 180 degrees */ -#define DEMODPHASE_2_81 0x01 /* 2.8125 degrees */ +#define DEMODPHASE_NONE 0x00 +#define DEMODPHASE_180_00 0x40 /* 180 degrees */ +#define DEMODPHASE_2_81 0x01 /* 2.8125 degrees */ #define AES2501_REG_DEMODPHASE1 0x8d -#define DEMODPHASE_1_40 0x40 /* 1.40625 degrees */ -#define DEMODPHASE_0_02 0x01 /* 0.02197256 degrees */ +#define DEMODPHASE_1_40 0x40 /* 1.40625 degrees */ +#define DEMODPHASE_0_02 0x01 /* 0.02197256 degrees */ enum aes2501_sensor_gain1 { - AES2501_CHANGAIN_STAGE1_2X = 0x00, /* 2x */ - AES2501_CHANGAIN_STAGE1_4X = 0x01, /* 4x */ - AES2501_CHANGAIN_STAGE1_8X = 0x02, /* 8x */ - AES2501_CHANGAIN_STAGE1_16X = 0x03 /* 16x */ + AES2501_CHANGAIN_STAGE1_2X = 0x00, /* 2x */ + AES2501_CHANGAIN_STAGE1_4X = 0x01, /* 4x */ + AES2501_CHANGAIN_STAGE1_8X = 0x02, /* 8x */ + AES2501_CHANGAIN_STAGE1_16X = 0x03 /* 16x */ }; enum aes2501_sensor_gain2 { - AES2501_CHANGAIN_STAGE2_2X = 0x00, /* 2x */ - AES2501_CHANGAIN_STAGE2_4X = 0x10, /* 4x */ - AES2501_CHANGAIN_STAGE2_8X = 0x20, /* 8x */ - AES2501_CHANGAIN_STAGE2_16X = 0x30 /* 16x */ + AES2501_CHANGAIN_STAGE2_2X = 0x00, /* 2x */ + AES2501_CHANGAIN_STAGE2_4X = 0x10, /* 4x */ + AES2501_CHANGAIN_STAGE2_8X = 0x20, /* 8x */ + AES2501_CHANGAIN_STAGE2_16X = 0x30 /* 16x */ }; -#define AES2501_DATFMT_EIGHT 0x40 /* 1 = 8-bit data, 0 = 4-bit data */ -#define AES2501_DATFMT_LOW_RES 0x20 -#define AES2501_DATFMT_BIN_IMG 0x10 +#define AES2501_DATFMT_EIGHT 0x40 /* 1 = 8-bit data, 0 = 4-bit data */ +#define AES2501_DATFMT_LOW_RES 0x20 +#define AES2501_DATFMT_BIN_IMG 0x10 /* don't send image or authentication messages when imaging */ -#define AES2501_IMAGCTRL_IMG_DATA_DISABLE 0x01 +#define AES2501_IMAGCTRL_IMG_DATA_DISABLE 0x01 /* send histogram when imaging */ -#define AES2501_IMAGCTRL_HISTO_DATA_ENABLE 0x02 +#define AES2501_IMAGCTRL_HISTO_DATA_ENABLE 0x02 /* send histogram at end of each row rather than each scan */ -#define AES2501_IMAGCTRL_HISTO_EACH_ROW 0x04 +#define AES2501_IMAGCTRL_HISTO_EACH_ROW 0x04 /* send full image array rather than 64x64 center */ -#define AES2501_IMAGCTRL_HISTO_FULL_ARRAY 0x08 +#define AES2501_IMAGCTRL_HISTO_FULL_ARRAY 0x08 /* return registers before data (rather than after) */ -#define AES2501_IMAGCTRL_REG_FIRST 0x10 +#define AES2501_IMAGCTRL_REG_FIRST 0x10 /* return test registers with register dump */ -#define AES2501_IMAGCTRL_TST_REG_ENABLE 0x20 +#define AES2501_IMAGCTRL_TST_REG_ENABLE 0x20 -#define AES2501_CHWORD1_IS_FINGER 0x01 /* If set, finger is present */ +#define AES2501_CHWORD1_IS_FINGER 0x01 /* If set, finger is present */ /* Enable the reading of the register in TREGD */ -#define AES2501_TREGC_ENABLE 0x01 +#define AES2501_TREGC_ENABLE 0x01 -#define AES2501_LPONT_MIN_VALUE 0x00 /* 0 ms */ -#define AES2501_LPONT_MAX_VALUE 0x1f /* About 16 ms */ +#define AES2501_LPONT_MIN_VALUE 0x00 /* 0 ms */ +#define AES2501_LPONT_MAX_VALUE 0x1f /* About 16 ms */ #define AES2501_ADREFHI_MIN_VALUE 0x28 #define AES2501_ADREFHI_MAX_VALUE 0x58 @@ -173,4 +173,4 @@ enum aes2501_sensor_gain2 { #define AES2501_SUM_HIGH_THRESH 1000 #define AES2501_SUM_LOW_THRESH 700 -#endif /* __AES2501_H */ +#endif /* __AES2501_H */ diff --git a/libfprint/drivers/aes2550.c b/libfprint/drivers/aes2550.c index b8fce056..80e54e87 100644 --- a/libfprint/drivers/aes2550.c +++ b/libfprint/drivers/aes2550.c @@ -27,11 +27,11 @@ #include "aes2550.h" #include "aeslib.h" -static void start_capture(FpImageDevice *dev); -static void complete_deactivation(FpImageDevice *dev); +static void start_capture (FpImageDevice *dev); +static void complete_deactivation (FpImageDevice *dev); -#define EP_IN (1 | FPI_USB_ENDPOINT_IN) -#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) #define BULK_TIMEOUT 4000 /* @@ -46,528 +46,583 @@ static void complete_deactivation(FpImageDevice *dev); * images returned from this driver vary in height. */ -#define FRAME_WIDTH 192 -#define FRAME_HEIGHT 8 -#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT) -#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2)) +#define FRAME_WIDTH 192 +#define FRAME_HEIGHT 8 +#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT) +#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2)) -struct _FpiDeviceAes2550 { - FpImageDevice parent; +struct _FpiDeviceAes2550 +{ + FpImageDevice parent; - GSList *strips; - size_t strips_len; - gboolean deactivating; - int heartbeat_cnt; + GSList *strips; + size_t strips_len; + gboolean deactivating; + int heartbeat_cnt; }; -G_DECLARE_FINAL_TYPE(FpiDeviceAes2550, fpi_device_aes2550, FPI, DEVICE_AES2550, - FpImageDevice); -G_DEFINE_TYPE(FpiDeviceAes2550, fpi_device_aes2550, FP_TYPE_IMAGE_DEVICE); +G_DECLARE_FINAL_TYPE (FpiDeviceAes2550, fpi_device_aes2550, FPI, DEVICE_AES2550, + FpImageDevice); +G_DEFINE_TYPE (FpiDeviceAes2550, fpi_device_aes2550, FP_TYPE_IMAGE_DEVICE); static struct fpi_frame_asmbl_ctx assembling_ctx = { - .frame_width = FRAME_WIDTH, - .frame_height = FRAME_HEIGHT, - .image_width = IMAGE_WIDTH, - .get_pixel = aes_get_pixel, + .frame_width = FRAME_WIDTH, + .frame_height = FRAME_HEIGHT, + .image_width = IMAGE_WIDTH, + .get_pixel = aes_get_pixel, }; /****** FINGER PRESENCE DETECTION ******/ static unsigned char finger_det_reqs[] = { - 0x80, AES2550_REG80_MASTER_RESET, - 0x95, (8 << AES2550_REG95_COL_SCANNED_OFS) | (1 << AES2550_REG95_EPIX_AVG_OFS), - 0xad, 0x00, - 0xbd, (0 << AES2550_REGBD_LPO_IN_15_8_OFS), - 0xbe, (0 << AES2550_REGBE_LPO_IN_7_0_OFS), - 0xcf, AES2550_REGCF_INTERFERENCE_CHK_EN, - AES2550_CMD_HEARTBEAT, 0x00, 0x01, 0x00, /* Heart beat off */ - AES2550_CMD_RUN_FD, + 0x80, AES2550_REG80_MASTER_RESET, + 0x95, (8 << AES2550_REG95_COL_SCANNED_OFS) | (1 << AES2550_REG95_EPIX_AVG_OFS), + 0xad, 0x00, + 0xbd, (0 << AES2550_REGBD_LPO_IN_15_8_OFS), + 0xbe, (0 << AES2550_REGBE_LPO_IN_7_0_OFS), + 0xcf, AES2550_REGCF_INTERFERENCE_CHK_EN, + AES2550_CMD_HEARTBEAT, 0x00, 0x01, 0x00, /* Heart beat off */ + AES2550_CMD_RUN_FD, }; -static void start_finger_detection(FpImageDevice *dev); +static void start_finger_detection (FpImageDevice *dev); -static void finger_det_data_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE(device); - unsigned char *data = transfer->buffer; + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + unsigned char *data = transfer->buffer; - if (error) { - fpi_image_device_session_error(FP_IMAGE_DEVICE(device), error); - return; - } + if (error) + { + fpi_image_device_session_error (FP_IMAGE_DEVICE (device), error); + return; + } - fp_dbg("transfer completed, len: %.4x, data: %.2x %.2x", - (gint)transfer->actual_length, (int)data[0], (int)data[1]); + fp_dbg ("transfer completed, len: %.4x, data: %.2x %.2x", + (gint) transfer->actual_length, (int) data[0], (int) data[1]); - /* Check if we got 2 bytes, reg address 0x83 and its value */ - if ((transfer->actual_length >= 2) && (data[0] == 0x83) && (data[1] & AES2550_REG83_FINGER_PRESENT)) { - /* finger present, start capturing */ - fpi_image_device_report_finger_status(dev, TRUE); - start_capture(dev); - } else { - /* no finger, poll for a new histogram */ - start_finger_detection(dev); - } + /* Check if we got 2 bytes, reg address 0x83 and its value */ + if ((transfer->actual_length >= 2) && (data[0] == 0x83) && (data[1] & AES2550_REG83_FINGER_PRESENT)) + { + /* finger present, start capturing */ + fpi_image_device_report_finger_status (dev, TRUE); + start_capture (dev); + } + else + { + /* no finger, poll for a new histogram */ + start_finger_detection (dev); + } } -static void finger_det_reqs_cb(FpiUsbTransfer *t, FpDevice *device, - gpointer user_data, GError *error) +static void +finger_det_reqs_cb (FpiUsbTransfer *t, FpDevice *device, + gpointer user_data, GError *error) { - FpiUsbTransfer *transfer; - FpImageDevice *dev = user_data; + FpiUsbTransfer *transfer; + FpImageDevice *dev = user_data; - if (error) { - fpi_image_device_session_error(dev, error); - return; - } + if (error) + { + fpi_image_device_session_error (dev, error); + return; + } - transfer = fpi_usb_transfer_new (device); - /* 2 bytes of result */ - fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE); - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - finger_det_data_cb, NULL); - fpi_usb_transfer_unref(transfer); + transfer = fpi_usb_transfer_new (device); + /* 2 bytes of result */ + fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE); + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + finger_det_data_cb, NULL); + fpi_usb_transfer_unref (transfer); } -static void start_finger_detection(FpImageDevice *dev) +static void +start_finger_detection (FpImageDevice *dev) { - FpiDeviceAes2550 *self = FPI_DEVICE_AES2550(dev); - FpiUsbTransfer *transfer; - G_DEBUG_HERE(); + FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev); + FpiUsbTransfer *transfer; - if (self->deactivating) { - complete_deactivation(dev); - return; - } + G_DEBUG_HERE (); - transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); - transfer->short_is_error = TRUE; - fpi_usb_transfer_fill_bulk_full(transfer, EP_OUT, finger_det_reqs, - sizeof(finger_det_reqs), NULL); - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - finger_det_reqs_cb, NULL); - fpi_usb_transfer_unref(transfer); + if (self->deactivating) + { + complete_deactivation (dev); + return; + } + + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, finger_det_reqs, + sizeof (finger_det_reqs), NULL); + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + finger_det_reqs_cb, NULL); + fpi_usb_transfer_unref (transfer); } /****** CAPTURE ******/ static unsigned char capture_reqs[] = { - 0x80, AES2550_REG80_MASTER_RESET, - 0x80, (1 << AES2550_REG80_SENSOR_MODE_OFS) | (AES2550_REG80_HGC_ENABLE), - 0x85, AES2550_REG85_FLUSH_PER_FRAME, - 0x8f, AES2550_REG8F_AUTH_DISABLE | AES2550_REG8F_EHISTO_DISABLE, - 0xbf, AES2550_REGBF_RSR_DIR_UPDOWN_MOTION | AES2550_REGBF_RSR_LEVEL_SUPER_RSR, - 0xcf, (3 << AES2550_REGCF_INTERFERENCE_AVG_OFFS) | AES2550_REGCF_INTERFERENCE_AVG_EN, - 0xdc, (1 << AES2550_REGDC_BP_NUM_REF_SWEEP_OFS), - AES2550_CMD_HEARTBEAT, 0x00, 0x01, 0x03, /* Heart beat cmd, 3 * 16 cycles without sending image */ - AES2550_CMD_GET_ENROLL_IMG, + 0x80, AES2550_REG80_MASTER_RESET, + 0x80, (1 << AES2550_REG80_SENSOR_MODE_OFS) | (AES2550_REG80_HGC_ENABLE), + 0x85, AES2550_REG85_FLUSH_PER_FRAME, + 0x8f, AES2550_REG8F_AUTH_DISABLE | AES2550_REG8F_EHISTO_DISABLE, + 0xbf, AES2550_REGBF_RSR_DIR_UPDOWN_MOTION | AES2550_REGBF_RSR_LEVEL_SUPER_RSR, + 0xcf, (3 << AES2550_REGCF_INTERFERENCE_AVG_OFFS) | AES2550_REGCF_INTERFERENCE_AVG_EN, + 0xdc, (1 << AES2550_REGDC_BP_NUM_REF_SWEEP_OFS), + AES2550_CMD_HEARTBEAT, 0x00, 0x01, 0x03, /* Heart beat cmd, 3 * 16 cycles without sending image */ + AES2550_CMD_GET_ENROLL_IMG, }; static unsigned char capture_set_idle_reqs[] = { - 0x80, AES2550_REG80_MASTER_RESET, - AES2550_CMD_HEARTBEAT, 0x00, 0x01, 0x00, /* Heart beat off */ - AES2550_CMD_SET_IDLE_MODE, + 0x80, AES2550_REG80_MASTER_RESET, + AES2550_CMD_HEARTBEAT, 0x00, 0x01, 0x00, /* Heart beat off */ + AES2550_CMD_SET_IDLE_MODE, }; enum capture_states { - CAPTURE_WRITE_REQS, - CAPTURE_READ_DATA, - CAPTURE_SET_IDLE, - CAPTURE_NUM_STATES, + CAPTURE_WRITE_REQS, + CAPTURE_READ_DATA, + CAPTURE_SET_IDLE, + CAPTURE_NUM_STATES, }; /* Returns number of processed bytes */ -static gboolean process_strip_data(FpiSsm *ssm, FpImageDevice *dev, - unsigned char *data) +static gboolean +process_strip_data (FpiSsm *ssm, FpImageDevice *dev, + unsigned char *data) { - unsigned char *stripdata; - FpiDeviceAes2550 *self = FPI_DEVICE_AES2550(dev); - struct fpi_frame *stripe; - int len; + unsigned char *stripdata; + FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev); + struct fpi_frame *stripe; + int len; - if (data[0] != AES2550_EDATA_MAGIC) { - fp_dbg("Bogus magic: %.2x\n", (int)(data[0])); - return FALSE; - } - len = data[1] * 256 + data[2]; - if (len != (AES2550_STRIP_SIZE - 3)) { - fp_dbg("Bogus frame len: %.4x\n", len); - } - stripe = g_malloc0(FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof(struct fpi_frame)); /* 4 bits per pixel */ - stripe->delta_x = (int8_t)data[6]; - stripe->delta_y = -(int8_t)data[7]; - stripdata = stripe->data; - memcpy(stripdata, data + 33, FRAME_WIDTH * FRAME_HEIGHT / 2); - self->strips = g_slist_prepend(self->strips, stripe); - self->strips_len++; + if (data[0] != AES2550_EDATA_MAGIC) + { + fp_dbg ("Bogus magic: %.2x\n", (int) (data[0])); + return FALSE; + } + len = data[1] * 256 + data[2]; + if (len != (AES2550_STRIP_SIZE - 3)) + fp_dbg ("Bogus frame len: %.4x\n", len); + stripe = g_malloc0 (FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof (struct fpi_frame)); /* 4 bits per pixel */ + stripe->delta_x = (int8_t) data[6]; + stripe->delta_y = -(int8_t) data[7]; + stripdata = stripe->data; + memcpy (stripdata, data + 33, FRAME_WIDTH * FRAME_HEIGHT / 2); + self->strips = g_slist_prepend (self->strips, stripe); + self->strips_len++; - fp_dbg("deltas: %dx%d", stripe->delta_x, stripe->delta_y); + fp_dbg ("deltas: %dx%d", stripe->delta_x, stripe->delta_y); - return TRUE; + return TRUE; } -static void capture_reqs_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +capture_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - if (!error) { - fpi_ssm_next_state(transfer->ssm); - } else { - fpi_ssm_mark_failed(transfer->ssm, error); - } + if (!error) + fpi_ssm_next_state (transfer->ssm); + else + fpi_ssm_mark_failed (transfer->ssm, error); } -static void capture_set_idle_reqs_cb(FpiUsbTransfer *transfer, - FpDevice *device, gpointer user_data, - GError *error) +static void +capture_set_idle_reqs_cb (FpiUsbTransfer *transfer, + FpDevice *device, gpointer user_data, + GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE(device); - FpiDeviceAes2550 *self = FPI_DEVICE_AES2550(dev); + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev); - if (!error && self->strips_len) { - FpImage *img; + if (!error && self->strips_len) + { + FpImage *img; - self->strips = g_slist_reverse(self->strips); - img = fpi_assemble_frames(&assembling_ctx, self->strips); - g_slist_free_full(self->strips, g_free); - self->strips = NULL; - self->strips_len = 0; - fpi_image_device_image_captured(dev, img); - fpi_image_device_report_finger_status(dev, FALSE); - /* marking machine complete will re-trigger finger detection loop */ - fpi_ssm_mark_completed(transfer->ssm); - } else { - if (error) - fpi_ssm_mark_failed(transfer->ssm, error); - else - fpi_ssm_mark_failed(transfer->ssm, - fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - } + self->strips = g_slist_reverse (self->strips); + img = fpi_assemble_frames (&assembling_ctx, self->strips); + g_slist_free_full (self->strips, g_free); + self->strips = NULL; + self->strips_len = 0; + fpi_image_device_image_captured (dev, img); + fpi_image_device_report_finger_status (dev, FALSE); + /* marking machine complete will re-trigger finger detection loop */ + fpi_ssm_mark_completed (transfer->ssm); + } + else + { + if (error) + fpi_ssm_mark_failed (transfer->ssm, error); + else + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + } } -static void capture_read_data_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE(device); - FpiDeviceAes2550 *self = FPI_DEVICE_AES2550(dev); - unsigned char *data = transfer->buffer; + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev); + unsigned char *data = transfer->buffer; - if (error) { - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } + if (error) + { + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } - fp_dbg("request completed, len: %.4x", (gint)transfer->actual_length); - if (transfer->actual_length >= 2) - fp_dbg("data: %.2x %.2x", (int)data[0], (int)data[1]); + fp_dbg ("request completed, len: %.4x", (gint) transfer->actual_length); + if (transfer->actual_length >= 2) + fp_dbg ("data: %.2x %.2x", (int) data[0], (int) data[1]); - switch (transfer->actual_length) { - case AES2550_STRIP_SIZE: - if (!process_strip_data(transfer->ssm, dev, data)) { - fp_dbg("Processing strip data failed"); - fpi_ssm_mark_failed(transfer->ssm, - fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - return; - } - self->heartbeat_cnt = 0; - fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_READ_DATA); - break; - case AES2550_HEARTBEAT_SIZE: - if (data[0] == AES2550_HEARTBEAT_MAGIC) { - /* No data for a long time => finger was removed or there's no movement */ - self->heartbeat_cnt++; - if (self->heartbeat_cnt == 3) { - /* Got 3 heartbeat message, that's enough to consider that finger was removed, - * assemble image and submit it to the library */ - fp_dbg("Got 3 heartbeats => finger removed"); - fpi_ssm_next_state(transfer->ssm); - } else { - fpi_ssm_jump_to_state(transfer->ssm, - CAPTURE_READ_DATA); - } - } - break; - default: - fp_dbg("Short frame %d, skip", - (gint)transfer->actual_length); - fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_READ_DATA); - break; - } + switch (transfer->actual_length) + { + case AES2550_STRIP_SIZE: + if (!process_strip_data (transfer->ssm, dev, data)) + { + fp_dbg ("Processing strip data failed"); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + return; + } + self->heartbeat_cnt = 0; + fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA); + break; + + case AES2550_HEARTBEAT_SIZE: + if (data[0] == AES2550_HEARTBEAT_MAGIC) + { + /* No data for a long time => finger was removed or there's no movement */ + self->heartbeat_cnt++; + if (self->heartbeat_cnt == 3) + { + /* Got 3 heartbeat message, that's enough to consider that finger was removed, + * assemble image and submit it to the library */ + fp_dbg ("Got 3 heartbeats => finger removed"); + fpi_ssm_next_state (transfer->ssm); + } + else + { + fpi_ssm_jump_to_state (transfer->ssm, + CAPTURE_READ_DATA); + } + } + break; + + default: + fp_dbg ("Short frame %d, skip", + (gint) transfer->actual_length); + fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA); + break; + } } -static void capture_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) +static void +capture_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) { - switch (fpi_ssm_get_cur_state(ssm)) { - case CAPTURE_WRITE_REQS: - { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); + switch (fpi_ssm_get_cur_state (ssm)) + { + case CAPTURE_WRITE_REQS: + { + FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev); - fpi_usb_transfer_fill_bulk_full(transfer, EP_OUT, capture_reqs, - sizeof(capture_reqs), NULL); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - capture_reqs_cb, NULL); - fpi_usb_transfer_unref(transfer); - } - break; - case CAPTURE_READ_DATA: - { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); + fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, capture_reqs, + sizeof (capture_reqs), NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + capture_reqs_cb, NULL); + fpi_usb_transfer_unref (transfer); + } + break; - fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE); - transfer->ssm = ssm; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - capture_read_data_cb, NULL); - fpi_usb_transfer_unref(transfer); - } - break; - case CAPTURE_SET_IDLE: - { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); + case CAPTURE_READ_DATA: + { + FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev); - fpi_usb_transfer_fill_bulk_full(transfer, EP_OUT, - capture_set_idle_reqs, - sizeof(capture_set_idle_reqs), - NULL); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - capture_set_idle_reqs_cb, NULL); - fpi_usb_transfer_unref(transfer); - } - break; - }; + fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE); + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + capture_read_data_cb, NULL); + fpi_usb_transfer_unref (transfer); + } + break; + + case CAPTURE_SET_IDLE: + { + FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev); + + fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, + capture_set_idle_reqs, + sizeof (capture_set_idle_reqs), + NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + capture_set_idle_reqs_cb, NULL); + fpi_usb_transfer_unref (transfer); + } + break; + } + ; } -static void capture_sm_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +static void +capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - FpImageDevice *dev = user_data; - FpiDeviceAes2550 *self = FPI_DEVICE_AES2550(_dev); + FpImageDevice *dev = user_data; + FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (_dev); - fp_dbg("Capture completed"); + fp_dbg ("Capture completed"); - if (self->deactivating) { - complete_deactivation(dev); - g_clear_pointer (&error, g_error_free); - } else if (error) { - fpi_image_device_session_error(dev, error); - } else { - start_finger_detection(dev); - } - fpi_ssm_free(ssm); + if (self->deactivating) + { + complete_deactivation (dev); + g_clear_pointer (&error, g_error_free); + } + else if (error) + { + fpi_image_device_session_error (dev, error); + } + else + { + start_finger_detection (dev); + } + fpi_ssm_free (ssm); } -static void start_capture(FpImageDevice *dev) +static void +start_capture (FpImageDevice *dev) { - FpiDeviceAes2550 *self = FPI_DEVICE_AES2550(dev); - FpiSsm *ssm; + FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev); + FpiSsm *ssm; - if (self->deactivating) { - complete_deactivation(dev); - return; - } + if (self->deactivating) + { + complete_deactivation (dev); + return; + } - self->heartbeat_cnt = 0; - ssm = fpi_ssm_new(FP_DEVICE(dev), capture_run_state, - CAPTURE_NUM_STATES, dev); - G_DEBUG_HERE(); - fpi_ssm_start(ssm, capture_sm_complete); + self->heartbeat_cnt = 0; + ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, + CAPTURE_NUM_STATES, dev); + G_DEBUG_HERE (); + fpi_ssm_start (ssm, capture_sm_complete); } /****** INITIALIZATION/DEINITIALIZATION ******/ static unsigned char init_reqs[] = { - 0x80, AES2550_REG80_MASTER_RESET, /* Master reset */ - 0x80, (1 << AES2550_REG80_SENSOR_MODE_OFS) | (AES2550_REG80_FORCE_FINGER_PRESENT), - 0x85, AES2550_REG85_FLUSH_PER_FRAME, - 0xa8, AES2550_REGA8_DIG_BIT_EN, - 0x81, AES2550_REG81_NSHOT, + 0x80, AES2550_REG80_MASTER_RESET, /* Master reset */ + 0x80, (1 << AES2550_REG80_SENSOR_MODE_OFS) | (AES2550_REG80_FORCE_FINGER_PRESENT), + 0x85, AES2550_REG85_FLUSH_PER_FRAME, + 0xa8, AES2550_REGA8_DIG_BIT_EN, + 0x81, AES2550_REG81_NSHOT, }; static unsigned char calibrate_reqs[] = { - 0x80, AES2550_REG80_MASTER_RESET, /* Master reset */ - AES2550_CMD_CALIBRATE, - AES2550_CMD_READ_CALIBRATION_DATA, + 0x80, AES2550_REG80_MASTER_RESET, /* Master reset */ + AES2550_CMD_CALIBRATE, + AES2550_CMD_READ_CALIBRATION_DATA, }; enum activate_states { - WRITE_INIT, - READ_DATA, - CALIBRATE, - READ_CALIB_TABLE, - ACTIVATE_NUM_STATES, + WRITE_INIT, + READ_DATA, + CALIBRATE, + READ_CALIB_TABLE, + ACTIVATE_NUM_STATES, }; -static void init_reqs_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +init_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - if (!error) { - fpi_ssm_next_state(transfer->ssm); - } else { - fpi_ssm_mark_failed(transfer->ssm, error); - } + if (!error) + fpi_ssm_next_state (transfer->ssm); + else + fpi_ssm_mark_failed (transfer->ssm, error); } -static void init_read_data_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +init_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - if (!error) { - fpi_ssm_next_state(transfer->ssm); - } else { - fpi_ssm_mark_failed(transfer->ssm, error); - } + if (!error) + fpi_ssm_next_state (transfer->ssm); + else + fpi_ssm_mark_failed (transfer->ssm, error); } /* TODO: use calibration table, datasheet is rather terse on that * need more info for implementation */ -static void calibrate_read_data_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +calibrate_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - if (!error) { - fpi_ssm_next_state(transfer->ssm); - } else { - fpi_ssm_mark_failed(transfer->ssm, error); - } + if (!error) + fpi_ssm_next_state (transfer->ssm); + else + fpi_ssm_mark_failed (transfer->ssm, error); } -static void activate_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) +static void +activate_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) { - switch (fpi_ssm_get_cur_state(ssm)) { - case WRITE_INIT: - { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); + switch (fpi_ssm_get_cur_state (ssm)) + { + case WRITE_INIT: + { + FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev); - fpi_usb_transfer_fill_bulk_full(transfer, EP_OUT, init_reqs, - sizeof(init_reqs), NULL); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - init_reqs_cb, NULL); - fpi_usb_transfer_unref(transfer); - } - break; - case READ_DATA: - { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); + fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, init_reqs, + sizeof (init_reqs), NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + init_reqs_cb, NULL); + fpi_usb_transfer_unref (transfer); + } + break; - fpi_usb_transfer_fill_bulk(transfer, EP_IN, AES2550_EP_IN_BUF_SIZE); - transfer->ssm = ssm; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - init_read_data_cb, NULL); - fpi_usb_transfer_unref(transfer); - } - break; - case CALIBRATE: - { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); + case READ_DATA: + { + FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev); - fpi_usb_transfer_fill_bulk_full(transfer, EP_OUT, - calibrate_reqs, - sizeof(calibrate_reqs), NULL); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - init_reqs_cb, NULL); - fpi_usb_transfer_unref(transfer); - } - break; - case READ_CALIB_TABLE: - { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); + fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE); + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + init_read_data_cb, NULL); + fpi_usb_transfer_unref (transfer); + } + break; - fpi_usb_transfer_fill_bulk(transfer, EP_IN, AES2550_EP_IN_BUF_SIZE); - transfer->ssm = ssm; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - calibrate_read_data_cb, NULL); - fpi_usb_transfer_unref(transfer); - } - break; - } + case CALIBRATE: + { + FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev); + + fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, + calibrate_reqs, + sizeof (calibrate_reqs), NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + init_reqs_cb, NULL); + fpi_usb_transfer_unref (transfer); + } + break; + + case READ_CALIB_TABLE: + { + FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev); + + fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE); + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + calibrate_read_data_cb, NULL); + fpi_usb_transfer_unref (transfer); + } + break; + } } -static void activate_sm_complete(FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +static void +activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = user_data; - fpi_image_device_activate_complete(dev, error); + fpi_image_device_activate_complete (dev, error); - if (!error) - start_finger_detection(dev); - fpi_ssm_free(ssm); + if (!error) + start_finger_detection (dev); + fpi_ssm_free (ssm); } -static void dev_activate(FpImageDevice *dev) +static void +dev_activate (FpImageDevice *dev) { - FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); - fpi_ssm_start(ssm, activate_sm_complete); + FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); + + fpi_ssm_start (ssm, activate_sm_complete); } -static void dev_deactivate(FpImageDevice *dev) +static void +dev_deactivate (FpImageDevice *dev) { - FpiDeviceAes2550 *self = FPI_DEVICE_AES2550(dev); + FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev); - self->deactivating = TRUE; + self->deactivating = TRUE; } -static void complete_deactivation(FpImageDevice *dev) +static void +complete_deactivation (FpImageDevice *dev) { - FpiDeviceAes2550 *self = FPI_DEVICE_AES2550(dev); - G_DEBUG_HERE(); + FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev); - self->deactivating = FALSE; - g_slist_free(self->strips); - self->strips = NULL; - self->strips_len = 0; - fpi_image_device_deactivate_complete(dev, NULL); + G_DEBUG_HERE (); + + self->deactivating = FALSE; + g_slist_free (self->strips); + self->strips = NULL; + self->strips_len = 0; + fpi_image_device_deactivate_complete (dev, NULL); } -static void dev_init(FpImageDevice *dev) +static void +dev_init (FpImageDevice *dev) { - GError *error = NULL; - /* TODO check that device has endpoints we're using */ + GError *error = NULL; - g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error); + /* TODO check that device has endpoints we're using */ - fpi_image_device_open_complete(dev, error); + g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error); + + fpi_image_device_open_complete (dev, error); } -static void dev_deinit(FpImageDevice *dev) +static void +dev_deinit (FpImageDevice *dev) { - GError *error = NULL; + GError *error = NULL; - g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), - 0, 0, &error); - fpi_image_device_close_complete(dev, error); + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), + 0, 0, &error); + fpi_image_device_close_complete (dev, error); } -static const FpIdEntry id_table [ ] = { - { .vid = 0x08ff, .pid = 0x2550, - }, /* AES2550 */ - { .vid = 0x08ff, .pid = 0x2810, - }, /* AES2810 */ - { .vid = 0, .pid = 0, .driver_data = 0 }, +static const FpIdEntry id_table[] = { + { .vid = 0x08ff, .pid = 0x2550, },/* AES2550 */ + { .vid = 0x08ff, .pid = 0x2810, },/* AES2810 */ + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -static void fpi_device_aes2550_init(FpiDeviceAes2550 *self) { +static void +fpi_device_aes2550_init (FpiDeviceAes2550 *self) +{ } -static void fpi_device_aes2550_class_init(FpiDeviceAes2550Class *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); +static void +fpi_device_aes2550_class_init (FpiDeviceAes2550Class *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); - dev_class->id = "aes2550"; - dev_class->full_name = "AuthenTec AES2550/AES2810"; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->id_table = id_table; - dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + dev_class->id = "aes2550"; + dev_class->full_name = "AuthenTec AES2550/AES2810"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - img_class->img_open = dev_init; - img_class->img_close = dev_deinit; - img_class->activate = dev_activate; - img_class->deactivate = dev_deactivate; + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; - img_class->img_width = FRAME_WIDTH + FRAME_WIDTH / 2; - img_class->img_height = -1; + img_class->img_width = FRAME_WIDTH + FRAME_WIDTH / 2; + img_class->img_height = -1; } diff --git a/libfprint/drivers/aes2550.h b/libfprint/drivers/aes2550.h index cd1e22d3..8e4ca173 100644 --- a/libfprint/drivers/aes2550.h +++ b/libfprint/drivers/aes2550.h @@ -22,93 +22,93 @@ /* Registers bits */ -#define AES2550_REG80_MASTER_RESET (1 << 0) -#define AES2550_REG80_FORCE_FINGER_PRESENT (1 << 1) -#define AES2550_REG80_LPO_START (1 << 2) -#define AES2550_REG80_HGC_ENABLE (1 << 3) -#define AES2550_REG80_SENSOR_MODE_OFS (4) -#define AES2550_REG80_AUTO_RESTART_FD (1 << 6) -#define AES2550_REG80_EXT_REG_ENABLE (1 << 7) +#define AES2550_REG80_MASTER_RESET (1 << 0) +#define AES2550_REG80_FORCE_FINGER_PRESENT (1 << 1) +#define AES2550_REG80_LPO_START (1 << 2) +#define AES2550_REG80_HGC_ENABLE (1 << 3) +#define AES2550_REG80_SENSOR_MODE_OFS (4) +#define AES2550_REG80_AUTO_RESTART_FD (1 << 6) +#define AES2550_REG80_EXT_REG_ENABLE (1 << 7) -#define AES2550_REG81_CONT_SCAN (1 << 0) -#define AES2550_REG81_READ_REG (1 << 1) -#define AES2550_REG81_NSHOT (1 << 2) -#define AES2550_REG81_RUN_FD (1 << 3) -#define AES2550_REG81_READ_ID (1 << 4) -#define AES2550_REG81_RUN_CAL (1 << 5) -#define AES2550_REG81_RUN_TIMER (1 << 6) -#define AES2550_REG81_RUN_BIST (1 << 7) +#define AES2550_REG81_CONT_SCAN (1 << 0) +#define AES2550_REG81_READ_REG (1 << 1) +#define AES2550_REG81_NSHOT (1 << 2) +#define AES2550_REG81_RUN_FD (1 << 3) +#define AES2550_REG81_READ_ID (1 << 4) +#define AES2550_REG81_RUN_CAL (1 << 5) +#define AES2550_REG81_RUN_TIMER (1 << 6) +#define AES2550_REG81_RUN_BIST (1 << 7) -#define AES2550_REG83_FINGER_PRESENT (1 << 7) +#define AES2550_REG83_FINGER_PRESENT (1 << 7) -#define AES2550_REG85_FLUSH_PER_FRAME (1 << 7) +#define AES2550_REG85_FLUSH_PER_FRAME (1 << 7) -#define AES2550_REG8F_EDATA_DISABLE (1 << 1) -#define AES2550_REG8F_AUTH_DISABLE (1 << 2) -#define AES2550_REG8F_EHISTO_DISABLE (1 << 3) -#define AES2550_REG8F_HISTO64 (1 << 4) -#define AES2550_REG8F_SINGLE_REG_ENABLE (1 << 6) +#define AES2550_REG8F_EDATA_DISABLE (1 << 1) +#define AES2550_REG8F_AUTH_DISABLE (1 << 2) +#define AES2550_REG8F_EHISTO_DISABLE (1 << 3) +#define AES2550_REG8F_HISTO64 (1 << 4) +#define AES2550_REG8F_SINGLE_REG_ENABLE (1 << 6) -#define AES2550_REG95_COL_SCANNED_OFS (0) -#define AES2550_REG95_EPIX_AVG_OFS (4) +#define AES2550_REG95_COL_SCANNED_OFS (0) +#define AES2550_REG95_EPIX_AVG_OFS (4) -#define AES2550_REGA8_DIG_BIT_DATA_OFS (0) -#define AES2550_REGA8_DIG_BIT_EN (1 << 4) -#define AES2550_REGA8_FIXED_BIT_DATA (1 << 5) -#define AES2550_REGA8_INVERT_BIT_DATA (1 << 6) +#define AES2550_REGA8_DIG_BIT_DATA_OFS (0) +#define AES2550_REGA8_DIG_BIT_EN (1 << 4) +#define AES2550_REGA8_FIXED_BIT_DATA (1 << 5) +#define AES2550_REGA8_INVERT_BIT_DATA (1 << 6) -#define AES2550_REGAD_LPFD_AVG_OFS (0) -#define AES2550_REGAD_DETECT_FGROFF (1 << 4) -#define AES2550_REGAD_ADVRANGE_2V (1 << 6) +#define AES2550_REGAD_LPFD_AVG_OFS (0) +#define AES2550_REGAD_DETECT_FGROFF (1 << 4) +#define AES2550_REGAD_ADVRANGE_2V (1 << 6) -#define AES2550_REGB1_ATE_CONT_IMAGE (1 << 1) -#define AES2550_REGB1_ANALOG_RESET (1 << 2) -#define AES2550_REGB1_ANALOG_PD (1 << 3) -#define AES2550_REGB1_TEST_EMBD_WORD (1 << 4) -#define AES2550_REGB1_ORIG_EMBD_WORD (1 << 5) -#define AES2550_REGB1_RESET_UHSM (1 << 6) -#define AES2550_REGB1_RESET_SENSOR (1 << 7) +#define AES2550_REGB1_ATE_CONT_IMAGE (1 << 1) +#define AES2550_REGB1_ANALOG_RESET (1 << 2) +#define AES2550_REGB1_ANALOG_PD (1 << 3) +#define AES2550_REGB1_TEST_EMBD_WORD (1 << 4) +#define AES2550_REGB1_ORIG_EMBD_WORD (1 << 5) +#define AES2550_REGB1_RESET_UHSM (1 << 6) +#define AES2550_REGB1_RESET_SENSOR (1 << 7) -#define AES2550_REGBD_LPO_IN_15_8_OFS (0) -#define AES2550_REGBE_LPO_IN_7_0_OFS (0) +#define AES2550_REGBD_LPO_IN_15_8_OFS (0) +#define AES2550_REGBE_LPO_IN_7_0_OFS (0) -#define AES2550_REGBF_RSR_LEVEL_DISABLED (0 << 0) -#define AES2550_REGBF_RSR_LEVEL_LEADING_RSR (1 << 0) -#define AES2550_REGBF_RSR_LEVEL_SIMPLE_RSR (2 << 0) -#define AES2550_REGBF_RSR_LEVEL_SUPER_RSR (3 << 0) -#define AES2550_REGBF_RSR_DIR_DOWN_MOTION (0 << 2) -#define AES2550_REGBF_RSR_DIR_UP_MOTION (1 << 2) -#define AES2550_REGBF_RSR_DIR_UPDOWN_MOTION (2 << 2) -#define AES2550_REGBF_NOISE_FLOOR_MODE (1 << 4) -#define AES2550_REGBF_QUADRATURE_MODE (1 << 5) +#define AES2550_REGBF_RSR_LEVEL_DISABLED (0 << 0) +#define AES2550_REGBF_RSR_LEVEL_LEADING_RSR (1 << 0) +#define AES2550_REGBF_RSR_LEVEL_SIMPLE_RSR (2 << 0) +#define AES2550_REGBF_RSR_LEVEL_SUPER_RSR (3 << 0) +#define AES2550_REGBF_RSR_DIR_DOWN_MOTION (0 << 2) +#define AES2550_REGBF_RSR_DIR_UP_MOTION (1 << 2) +#define AES2550_REGBF_RSR_DIR_UPDOWN_MOTION (2 << 2) +#define AES2550_REGBF_NOISE_FLOOR_MODE (1 << 4) +#define AES2550_REGBF_QUADRATURE_MODE (1 << 5) -#define AES2550_REGCF_INTERFERENCE_CHK_EN (1 << 0) -#define AES2550_REGCF_INTERFERENCE_AVG_EN (1 << 1) -#define AES2550_REGCF_INTERFERENCE_AVG_OFFS (4) +#define AES2550_REGCF_INTERFERENCE_CHK_EN (1 << 0) +#define AES2550_REGCF_INTERFERENCE_AVG_EN (1 << 1) +#define AES2550_REGCF_INTERFERENCE_AVG_OFFS (4) -#define AES2550_REGDC_BP_NUM_REF_SWEEP_OFS (0) -#define AES2550_REGDC_DEBUG_CTRL2_OFS (3) +#define AES2550_REGDC_BP_NUM_REF_SWEEP_OFS (0) +#define AES2550_REGDC_DEBUG_CTRL2_OFS (3) -#define AES2550_REGDD_DEBUG_CTRL1_OFS (0) +#define AES2550_REGDD_DEBUG_CTRL1_OFS (0) /* Commands */ enum aes2550_cmds { - AES2550_CMD_SET_IDLE_MODE = 0x00, - AES2550_CMD_RUN_FD = 0x01, - AES2550_CMD_GET_ENROLL_IMG = 0x02, - AES2550_CMD_CALIBRATE = 0x06, - AES2550_CMD_READ_CALIBRATION_DATA = 0x10, - AES2550_CMD_HEARTBEAT = 0x70, + AES2550_CMD_SET_IDLE_MODE = 0x00, + AES2550_CMD_RUN_FD = 0x01, + AES2550_CMD_GET_ENROLL_IMG = 0x02, + AES2550_CMD_CALIBRATE = 0x06, + AES2550_CMD_READ_CALIBRATION_DATA = 0x10, + AES2550_CMD_HEARTBEAT = 0x70, }; /* Messages */ -#define AES2550_STRIP_SIZE (0x31e + 3) -#define AES2550_HEARTBEAT_SIZE (4 + 3) -#define AES2550_EDATA_MAGIC 0xe0 -#define AES2550_HEARTBEAT_MAGIC 0xdb +#define AES2550_STRIP_SIZE (0x31e + 3) +#define AES2550_HEARTBEAT_SIZE (4 + 3) +#define AES2550_EDATA_MAGIC 0xe0 +#define AES2550_HEARTBEAT_MAGIC 0xdb -#define AES2550_EP_IN_BUF_SIZE 8192 +#define AES2550_EP_IN_BUF_SIZE 8192 #endif diff --git a/libfprint/drivers/aes2660.c b/libfprint/drivers/aes2660.c index 3b054644..fb5aa7e1 100644 --- a/libfprint/drivers/aes2660.c +++ b/libfprint/drivers/aes2660.c @@ -25,68 +25,73 @@ #include "aes2660.h" #define FRAME_WIDTH 192 -#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2)) +#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2)) -struct _FpiDeviceAes2660 { - FpiDeviceAesX660 parent; +struct _FpiDeviceAes2660 +{ + FpiDeviceAesX660 parent; }; -G_DECLARE_FINAL_TYPE(FpiDeviceAes2660, fpi_device_aes2660, FPI, - DEVICE_AES2660, FpiDeviceAesX660); -G_DEFINE_TYPE(FpiDeviceAes2660, fpi_device_aes2660, FPI_TYPE_DEVICE_AES_X660); +G_DECLARE_FINAL_TYPE (FpiDeviceAes2660, fpi_device_aes2660, FPI, + DEVICE_AES2660, FpiDeviceAesX660); +G_DEFINE_TYPE (FpiDeviceAes2660, fpi_device_aes2660, FPI_TYPE_DEVICE_AES_X660); static struct fpi_frame_asmbl_ctx assembling_ctx = { - .frame_width = FRAME_WIDTH, - .frame_height = AESX660_FRAME_HEIGHT, - .image_width = IMAGE_WIDTH, - .get_pixel = aes_get_pixel, + .frame_width = FRAME_WIDTH, + .frame_height = AESX660_FRAME_HEIGHT, + .image_width = IMAGE_WIDTH, + .get_pixel = aes_get_pixel, }; -static const FpIdEntry id_table [ ] = { - { .vid = 0x08ff, .pid = 0x2660, }, - { .vid = 0x08ff, .pid = 0x2680, }, - { .vid = 0x08ff, .pid = 0x2681, }, - { .vid = 0x08ff, .pid = 0x2682, }, - { .vid = 0x08ff, .pid = 0x2683, }, - { .vid = 0x08ff, .pid = 0x2684, }, - { .vid = 0x08ff, .pid = 0x2685, }, - { .vid = 0x08ff, .pid = 0x2686, }, - { .vid = 0x08ff, .pid = 0x2687, }, - { .vid = 0x08ff, .pid = 0x2688, }, - { .vid = 0x08ff, .pid = 0x2689, }, - { .vid = 0x08ff, .pid = 0x268a, }, - { .vid = 0x08ff, .pid = 0x268b, }, - { .vid = 0x08ff, .pid = 0x268c, }, - { .vid = 0x08ff, .pid = 0x268d, }, - { .vid = 0x08ff, .pid = 0x268e, }, - { .vid = 0x08ff, .pid = 0x268f, }, - { .vid = 0x08ff, .pid = 0x2691, }, - { .vid = 0, .pid = 0, .driver_data = 0 }, +static const FpIdEntry id_table[] = { + { .vid = 0x08ff, .pid = 0x2660, }, + { .vid = 0x08ff, .pid = 0x2680, }, + { .vid = 0x08ff, .pid = 0x2681, }, + { .vid = 0x08ff, .pid = 0x2682, }, + { .vid = 0x08ff, .pid = 0x2683, }, + { .vid = 0x08ff, .pid = 0x2684, }, + { .vid = 0x08ff, .pid = 0x2685, }, + { .vid = 0x08ff, .pid = 0x2686, }, + { .vid = 0x08ff, .pid = 0x2687, }, + { .vid = 0x08ff, .pid = 0x2688, }, + { .vid = 0x08ff, .pid = 0x2689, }, + { .vid = 0x08ff, .pid = 0x268a, }, + { .vid = 0x08ff, .pid = 0x268b, }, + { .vid = 0x08ff, .pid = 0x268c, }, + { .vid = 0x08ff, .pid = 0x268d, }, + { .vid = 0x08ff, .pid = 0x268e, }, + { .vid = 0x08ff, .pid = 0x268f, }, + { .vid = 0x08ff, .pid = 0x2691, }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -static void fpi_device_aes2660_init(FpiDeviceAes2660 *self) { +static void +fpi_device_aes2660_init (FpiDeviceAes2660 *self) +{ } -static void fpi_device_aes2660_class_init(FpiDeviceAes2660Class *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); - FpiDeviceAesX660Class *aes_class = FPI_DEVICE_AES_X660_CLASS (klass); +static void +fpi_device_aes2660_class_init (FpiDeviceAes2660Class *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); + FpiDeviceAesX660Class *aes_class = FPI_DEVICE_AES_X660_CLASS (klass); - dev_class->id = "aes2660"; - dev_class->full_name = "AuthenTec AES2660"; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->id_table = id_table; - dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + dev_class->id = "aes2660"; + dev_class->full_name = "AuthenTec AES2660"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - img_class->bz3_threshold = 20; + img_class->bz3_threshold = 20; - img_class->img_width = FRAME_WIDTH + FRAME_WIDTH / 2; - img_class->img_height = -1; + img_class->img_width = FRAME_WIDTH + FRAME_WIDTH / 2; + img_class->img_height = -1; - aes_class->init_seqs[0] = aes2660_init_1; - aes_class->init_seqs_len[0] = G_N_ELEMENTS(aes2660_init_1); - aes_class->init_seqs[1] = aes2660_init_2; - aes_class->init_seqs_len[1] = G_N_ELEMENTS(aes2660_init_2); - aes_class->start_imaging_cmd = (unsigned char *)aes2660_start_imaging_cmd; - aes_class->start_imaging_cmd_len = sizeof(aes2660_start_imaging_cmd); - aes_class->assembling_ctx = &assembling_ctx; + aes_class->init_seqs[0] = aes2660_init_1; + aes_class->init_seqs_len[0] = G_N_ELEMENTS (aes2660_init_1); + aes_class->init_seqs[1] = aes2660_init_2; + aes_class->init_seqs_len[1] = G_N_ELEMENTS (aes2660_init_2); + aes_class->start_imaging_cmd = (unsigned char *) aes2660_start_imaging_cmd; + aes_class->start_imaging_cmd_len = sizeof (aes2660_start_imaging_cmd); + aes_class->assembling_ctx = &assembling_ctx; } diff --git a/libfprint/drivers/aes2660.h b/libfprint/drivers/aes2660.h index c85bb0a3..d59f4be2 100644 --- a/libfprint/drivers/aes2660.h +++ b/libfprint/drivers/aes2660.h @@ -29,1936 +29,1936 @@ /* INIT1 */ static const unsigned char pkt13[] = { -0x44, 0x02, 0x00, 0x04, 0x00, -0x0d, -0x23, -0x42, 0xca, 0x00, -0x00, 0x20, 0x7f, /* .#B... . */ -0x97, 0x37, 0xcf, 0xdf, 0x96, 0x26, 0xcf, 0xdf, /* .7...&.. */ -0x96, 0xff, 0x96, 0x9f, 0x22, 0x6d, 0x2e, 0x6a, /* ...."m.j */ -0xbf, 0x62, 0x23, 0x23, 0x83, 0xdd, 0x97, 0x26, /* .b##...& */ -0xaf, 0xdd, 0x97, 0x37, 0xaf, 0xa9, 0xcf, 0x70, /* ...7...p */ -0x18, 0xa9, 0xaf, 0x02, 0xef, 0x5d, 0xaf, 0xc5, /* .....].. */ -0xef, 0x2f, 0xff, 0xff, 0x96, 0xdf, 0x96, 0x69, /* ./.....i */ -0xef, 0x20, 0xff, 0xff, 0x96, 0xdf, 0x96, 0x1a, /* . ...... */ -0x27, 0x0b, 0xef, 0x06, 0xaf, 0xf1, 0x81, 0x3a, /* '......: */ -0xff, 0x3f, 0x1d, 0xc1, 0x2e, 0xa3, 0xbf, 0xc2, /* .?...... */ -0x2e, 0x00, 0xdf, 0xff, 0x2d, 0x02, 0x5a, 0xbf, /* ....-.Z. */ -0x22, 0xc1, 0x2e, 0xa3, 0xbf, 0x3c, 0x23, 0x57, /* "....<#W */ -0x23, 0x02, 0x2e, 0x30, 0x80, 0x05, 0x27, 0x12, /* #..0..'. */ -0xef, 0x99, 0xaf, 0x10, 0xef, 0x9b, 0xaf, 0x10, /* ........ */ -0xef, 0x55, 0xaf, 0x3d, 0x23, 0x30, 0xef, 0x20, /* .U.=#0. */ -0xff, 0x1a, 0x27, 0x05, 0xef, 0x27, 0xff, 0x06, /* ..'..'.. */ -0x27, 0x05, 0x27, 0x3f, 0x80, 0x2b, 0x0d, 0x05, /* '.'?.+.. */ -0x27, 0xe5, 0x31, 0x05, 0x81, 0xe5, 0x39, 0x05, /* '.1...9. */ -0x27, 0xc8, 0x46, 0x0e, 0x5b, 0xd3, 0x45, 0xfd, /* '.F.[.E. */ -0x5a, 0x0f, 0x27, 0xd3, 0x45, 0xfa, 0x5a, 0x0f, /* Z.'.E.Z. */ -0x27, 0xd3, 0x45, 0xf7, 0x5a, 0x41, 0x2e, 0xa1, /* '.E.ZA.. */ -0xdf, 0x9f, 0x28, 0x41, 0x2e, 0xa1, 0xbf, 0x02, /* ..(A.... */ -0x2e, 0x57, 0x80, 0x05, 0x27, 0x9f, 0x22, 0xbf, /* .W..'.". */ -0x22, 0x1f, 0x20, 0xfd, 0x53, 0x3f, 0x20, 0x14, /* ". .S? . */ -0x1f, 0xfa, 0x55, 0x05, 0x27, 0x10, 0xef, 0xd0, /* ..U.'... */ -0x81, 0x65, 0xaf, 0x10, 0xef, 0xd0, 0x81 /* .e..... */ + 0x44, 0x02, 0x00, 0x04, 0x00, + 0x0d, + 0x23, + 0x42, 0xca, 0x00, + 0x00, 0x20, 0x7f, /* .#B... . */ + 0x97, 0x37, 0xcf, 0xdf, 0x96, 0x26, 0xcf, 0xdf, /* .7...&.. */ + 0x96, 0xff, 0x96, 0x9f, 0x22, 0x6d, 0x2e, 0x6a, /* ...."m.j */ + 0xbf, 0x62, 0x23, 0x23, 0x83, 0xdd, 0x97, 0x26, /* .b##...& */ + 0xaf, 0xdd, 0x97, 0x37, 0xaf, 0xa9, 0xcf, 0x70, /* ...7...p */ + 0x18, 0xa9, 0xaf, 0x02, 0xef, 0x5d, 0xaf, 0xc5, /* .....].. */ + 0xef, 0x2f, 0xff, 0xff, 0x96, 0xdf, 0x96, 0x69, /* ./.....i */ + 0xef, 0x20, 0xff, 0xff, 0x96, 0xdf, 0x96, 0x1a, /* . ...... */ + 0x27, 0x0b, 0xef, 0x06, 0xaf, 0xf1, 0x81, 0x3a, /* '......: */ + 0xff, 0x3f, 0x1d, 0xc1, 0x2e, 0xa3, 0xbf, 0xc2, /* .?...... */ + 0x2e, 0x00, 0xdf, 0xff, 0x2d, 0x02, 0x5a, 0xbf, /* ....-.Z. */ + 0x22, 0xc1, 0x2e, 0xa3, 0xbf, 0x3c, 0x23, 0x57, /* "....<#W */ + 0x23, 0x02, 0x2e, 0x30, 0x80, 0x05, 0x27, 0x12, /* #..0..'. */ + 0xef, 0x99, 0xaf, 0x10, 0xef, 0x9b, 0xaf, 0x10, /* ........ */ + 0xef, 0x55, 0xaf, 0x3d, 0x23, 0x30, 0xef, 0x20, /* .U.=#0. */ + 0xff, 0x1a, 0x27, 0x05, 0xef, 0x27, 0xff, 0x06, /* ..'..'.. */ + 0x27, 0x05, 0x27, 0x3f, 0x80, 0x2b, 0x0d, 0x05, /* '.'?.+.. */ + 0x27, 0xe5, 0x31, 0x05, 0x81, 0xe5, 0x39, 0x05, /* '.1...9. */ + 0x27, 0xc8, 0x46, 0x0e, 0x5b, 0xd3, 0x45, 0xfd, /* '.F.[.E. */ + 0x5a, 0x0f, 0x27, 0xd3, 0x45, 0xfa, 0x5a, 0x0f, /* Z.'.E.Z. */ + 0x27, 0xd3, 0x45, 0xf7, 0x5a, 0x41, 0x2e, 0xa1, /* '.E.ZA.. */ + 0xdf, 0x9f, 0x28, 0x41, 0x2e, 0xa1, 0xbf, 0x02, /* ..(A.... */ + 0x2e, 0x57, 0x80, 0x05, 0x27, 0x9f, 0x22, 0xbf, /* .W..'.". */ + 0x22, 0x1f, 0x20, 0xfd, 0x53, 0x3f, 0x20, 0x14, /* ". .S? . */ + 0x1f, 0xfa, 0x55, 0x05, 0x27, 0x10, 0xef, 0xd0, /* ..U.'... */ + 0x81, 0x65, 0xaf, 0x10, 0xef, 0xd0, 0x81 /* .e..... */ }; static const unsigned char pkt15[] = { -0x42, 0x48, 0x00, -0x64, 0x20, 0x9c, 0xaf, 0x10, /* BH.d ... */ -0xef, 0xd0, 0x81, 0x9a, 0xaf, 0x05, 0x27, 0x11, /* ......'. */ -0x00, 0x51, 0x87, 0x91, 0x81, 0xd1, 0x6c, 0xd2, /* .Q....l. */ -0x75, 0xe2, 0x80, 0xf2, 0x80, 0xf0, 0x57, 0xf4, /* u.....W. */ -0x7b, 0xf8, 0x7e, 0xfc, 0x8b, 0x10, 0xcf, 0x7c, /* {.~....| */ -0xff, 0x3f, 0x00, 0x20, 0xff, 0x00, 0x13, 0x1a, /* .?. .... */ -0x27, 0x07, 0x27, 0x05, 0x27, 0x01, 0x00, 0x11, /* '.'.'... */ -0x00, 0x21, 0x00, 0x31, 0x00, 0x31, 0x01, 0x32, /* .!.1.1.2 */ -0x01, 0x33, 0x01, 0x33, 0x03, 0x43, 0x03, 0x53, /* .3.3.C.S */ -0x03, 0x63, 0x03 /* .c. */ + 0x42, 0x48, 0x00, + 0x64, 0x20, 0x9c, 0xaf, 0x10, /* BH.d ... */ + 0xef, 0xd0, 0x81, 0x9a, 0xaf, 0x05, 0x27, 0x11, /* ......'. */ + 0x00, 0x51, 0x87, 0x91, 0x81, 0xd1, 0x6c, 0xd2, /* .Q....l. */ + 0x75, 0xe2, 0x80, 0xf2, 0x80, 0xf0, 0x57, 0xf4, /* u.....W. */ + 0x7b, 0xf8, 0x7e, 0xfc, 0x8b, 0x10, 0xcf, 0x7c, /* {.~....| */ + 0xff, 0x3f, 0x00, 0x20, 0xff, 0x00, 0x13, 0x1a, /* .?. .... */ + 0x27, 0x07, 0x27, 0x05, 0x27, 0x01, 0x00, 0x11, /* '.'.'... */ + 0x00, 0x21, 0x00, 0x31, 0x00, 0x31, 0x01, 0x32, /* .!.1.1.2 */ + 0x01, 0x33, 0x01, 0x33, 0x03, 0x43, 0x03, 0x53, /* .3.3.C.S */ + 0x03, 0x63, 0x03 /* .c. */ }; static const unsigned char pkt17[] = { -0x42, 0xca, 0x00, -0x87, 0x20, 0x51, 0x85, 0x44, /* B... Q.D */ -0x1e, 0x03, 0x55, 0xc8, 0x46, 0x01, 0x5b, 0xe4, /* ..U.F.[. */ -0x2f, 0xc9, 0x50, 0x49, 0x1e, 0x16, 0x55, 0xe4, /* /.PI..U. */ -0x2f, 0xc5, 0x50, 0x02, 0xef, 0x02, 0x2e, 0x62, /* /.P....b */ -0x82, 0xfe, 0xcf, 0x08, 0xaf, 0xfe, 0xcf, 0x09, /* ........ */ -0xaf, 0xfe, 0xcf, 0x0b, 0xaf, 0x55, 0x81, 0x02, /* .....U.. */ -0xcf, 0x0f, 0x1c, 0x40, 0x18, 0x08, 0x42, 0x00, /* ...@..B. */ -0x5b, 0x20, 0x18, 0x3d, 0x23, 0x02, 0xaf, 0x10, /* [ .=#... */ -0xef, 0x55, 0xaf, 0x05, 0x27, 0x4a, 0x1e, 0x01, /* .U..'J.. */ -0x55, 0xe4, 0x2f, 0xac, 0x50, 0x4e, 0x1e, 0x01, /* U./.PN.. */ -0x55, 0x00, 0x2e, 0x0d, 0x7b, 0x4f, 0x1e, 0x01, /* U...{O.. */ -0x55, 0x02, 0x2e, 0xbd, 0x71, 0x51, 0x1e, 0x1a, /* U...qQ.. */ -0x55, 0xf9, 0xcf, 0x67, 0xaf, 0xcf, 0x1c, 0xf9, /* U..g.... */ -0xaf, 0xff, 0x86, 0xbf, 0x22, 0x09, 0xbf, 0xfe, /* ...."... */ -0xdf, 0x00, 0x2e, 0xd7, 0x8b, 0x01, 0xef, 0x3b, /* .......; */ -0xaf, 0x01, 0x2e, 0x63, 0x84, 0x3b, 0x80, 0x3b, /* ...c.;.; */ -0xcf, 0x1f, 0x99, 0x01, 0x2e, 0x07, 0x85, 0x00, /* ........ */ -0x2e, 0xa7, 0x8a, 0xbf, 0x22, 0xc1, 0x2e, 0x49, /* ...."..I */ -0xbf, 0x67, 0xcf, 0xf9, 0xaf, 0x05, 0x27, 0x54, /* .g....'T */ -0x1e, 0x32, 0x55, 0x04, 0xef, 0x20, 0x80, 0xe4, /* .2U.. .. */ -0x2f, 0x81, 0x5a, 0x23, 0x81, 0xfe, 0xcf, 0xfe, /* /.Z#.... */ -0xdf, 0xff, 0x96, 0xdf, 0x96, 0xfe, 0xcf, 0xfe, /* ........ */ -0xdf, 0xff, 0x96, 0xdf, 0x96, 0xdf, 0x22, 0x01, /* ......". */ -0x55, 0xff, 0x22, 0x06, 0x54, 0xc1, 0x97, 0x83, /* U.".T... */ -0x03, 0x0e, 0x52, 0x02, 0x5e, 0xc0, 0x97, 0x82, /* ..R.^... */ -0x03, 0x0a, 0x52, 0xc2, 0x97 /* ..R.. */ + 0x42, 0xca, 0x00, + 0x87, 0x20, 0x51, 0x85, 0x44, /* B... Q.D */ + 0x1e, 0x03, 0x55, 0xc8, 0x46, 0x01, 0x5b, 0xe4, /* ..U.F.[. */ + 0x2f, 0xc9, 0x50, 0x49, 0x1e, 0x16, 0x55, 0xe4, /* /.PI..U. */ + 0x2f, 0xc5, 0x50, 0x02, 0xef, 0x02, 0x2e, 0x62, /* /.P....b */ + 0x82, 0xfe, 0xcf, 0x08, 0xaf, 0xfe, 0xcf, 0x09, /* ........ */ + 0xaf, 0xfe, 0xcf, 0x0b, 0xaf, 0x55, 0x81, 0x02, /* .....U.. */ + 0xcf, 0x0f, 0x1c, 0x40, 0x18, 0x08, 0x42, 0x00, /* ...@..B. */ + 0x5b, 0x20, 0x18, 0x3d, 0x23, 0x02, 0xaf, 0x10, /* [ .=#... */ + 0xef, 0x55, 0xaf, 0x05, 0x27, 0x4a, 0x1e, 0x01, /* .U..'J.. */ + 0x55, 0xe4, 0x2f, 0xac, 0x50, 0x4e, 0x1e, 0x01, /* U./.PN.. */ + 0x55, 0x00, 0x2e, 0x0d, 0x7b, 0x4f, 0x1e, 0x01, /* U...{O.. */ + 0x55, 0x02, 0x2e, 0xbd, 0x71, 0x51, 0x1e, 0x1a, /* U...qQ.. */ + 0x55, 0xf9, 0xcf, 0x67, 0xaf, 0xcf, 0x1c, 0xf9, /* U..g.... */ + 0xaf, 0xff, 0x86, 0xbf, 0x22, 0x09, 0xbf, 0xfe, /* ...."... */ + 0xdf, 0x00, 0x2e, 0xd7, 0x8b, 0x01, 0xef, 0x3b, /* .......; */ + 0xaf, 0x01, 0x2e, 0x63, 0x84, 0x3b, 0x80, 0x3b, /* ...c.;.; */ + 0xcf, 0x1f, 0x99, 0x01, 0x2e, 0x07, 0x85, 0x00, /* ........ */ + 0x2e, 0xa7, 0x8a, 0xbf, 0x22, 0xc1, 0x2e, 0x49, /* ...."..I */ + 0xbf, 0x67, 0xcf, 0xf9, 0xaf, 0x05, 0x27, 0x54, /* .g....'T */ + 0x1e, 0x32, 0x55, 0x04, 0xef, 0x20, 0x80, 0xe4, /* .2U.. .. */ + 0x2f, 0x81, 0x5a, 0x23, 0x81, 0xfe, 0xcf, 0xfe, /* /.Z#.... */ + 0xdf, 0xff, 0x96, 0xdf, 0x96, 0xfe, 0xcf, 0xfe, /* ........ */ + 0xdf, 0xff, 0x96, 0xdf, 0x96, 0xdf, 0x22, 0x01, /* ......". */ + 0x55, 0xff, 0x22, 0x06, 0x54, 0xc1, 0x97, 0x83, /* U.".T... */ + 0x03, 0x0e, 0x52, 0x02, 0x5e, 0xc0, 0x97, 0x82, /* ..R.^... */ + 0x03, 0x0a, 0x52, 0xc2, 0x97 /* ..R.. */ }; static const unsigned char pkt19[] = { -0x42, 0xca, 0x00, -0xeb, 0x20, 0xc3, 0x9f, 0xcd, /* B... ... */ -0x80, 0x07, 0x80, 0x00, 0xef, 0xff, 0xaf, 0x00, /* ........ */ -0x2e, 0xa7, 0x8a, 0x04, 0x0c, 0x29, 0x81, 0x05, /* .....).. */ -0x27, 0xc0, 0x97, 0xc1, 0x9f, 0xcd, 0x80, 0x07, /* '....... */ -0x80, 0x01, 0xef, 0xff, 0xaf, 0x00, 0x2e, 0xa9, /* ........ */ -0x8a, 0xc2, 0x97, 0xc3, 0x9f, 0x80, 0x01, 0x41, /* .......A */ -0x01, 0x9f, 0x90, 0xff, 0x90, 0x02, 0x2e, 0xe3, /* ........ */ -0x70, 0x55, 0x1e, 0x16, 0x55, 0x54, 0x85, 0xe4, /* pU..UT.. */ -0x2f, 0x4d, 0x5b, 0x07, 0xef, 0x20, 0x80, 0xe4, /* /M[.. .. */ -0x2f, 0x49, 0x5a, 0xfe, 0xcf, 0x0a, 0xaf, 0xfe, /* /IZ..... */ -0xcf, 0xfe, 0xcf, 0x41, 0x2e, 0x44, 0xbf, 0xfe, /* ...A.D.. */ -0xcf, 0x41, 0x2e, 0x45, 0xbf, 0xfe, 0xcf, 0x52, /* .A.E...R */ -0xaf, 0xfe, 0xcf, 0x53, 0xaf, 0xfe, 0xcf, 0x5a, /* ...S...Z */ -0xaf, 0x05, 0x27, 0x58, 0x1e, 0x0d, 0x55, 0x02, /* ..'X..U. */ -0x44, 0x01, 0x5a, 0x00, 0x2e, 0x54, 0x79, 0xfe, /* D.Z..Ty. */ -0xcf, 0x75, 0xaf, 0xfe, 0xdf, 0x76, 0xbf, 0x41, /* .u...v.A */ -0x2e, 0xa4, 0xdf, 0xdf, 0x29, 0x41, 0x2e, 0xa4, /* ....)A.. */ -0xbf, 0x05, 0x27, 0x59, 0x1e, 0x03, 0x55, 0xfe, /* ..'Y..U. */ -0xcf, 0x10, 0xaf, 0x01, 0x2e, 0x94, 0x76, 0x63, /* ......vc */ -0x1e, 0x1a, 0x55, 0x54, 0x85, 0xe4, 0x2f, 0x1e, /* ..UT../. */ -0x5b, 0x0c, 0xef, 0x20, 0x80, 0xe4, 0x2f, 0x1a, /* [.. ../. */ -0x5a, 0xf0, 0xef, 0x00, 0xff, 0x19, 0x27, 0x08, /* Z.....'. */ -0xef, 0x06, 0xaf, 0xfe, 0xcf, 0x5f, 0x9f, 0x06, /* ....._.. */ -0x25, 0xfb, 0x55, 0xfe, 0xcf, 0xfe, 0xcf, 0x41, /* %.U....A */ -0x2e, 0x40, 0xbf, 0xfe, 0xcf, 0x41, 0x2e, 0x41, /* .@...A.A */ -0xbf, 0xfe, 0xcf, 0x41, 0x2e /* ...A. */ + 0x42, 0xca, 0x00, + 0xeb, 0x20, 0xc3, 0x9f, 0xcd, /* B... ... */ + 0x80, 0x07, 0x80, 0x00, 0xef, 0xff, 0xaf, 0x00, /* ........ */ + 0x2e, 0xa7, 0x8a, 0x04, 0x0c, 0x29, 0x81, 0x05, /* .....).. */ + 0x27, 0xc0, 0x97, 0xc1, 0x9f, 0xcd, 0x80, 0x07, /* '....... */ + 0x80, 0x01, 0xef, 0xff, 0xaf, 0x00, 0x2e, 0xa9, /* ........ */ + 0x8a, 0xc2, 0x97, 0xc3, 0x9f, 0x80, 0x01, 0x41, /* .......A */ + 0x01, 0x9f, 0x90, 0xff, 0x90, 0x02, 0x2e, 0xe3, /* ........ */ + 0x70, 0x55, 0x1e, 0x16, 0x55, 0x54, 0x85, 0xe4, /* pU..UT.. */ + 0x2f, 0x4d, 0x5b, 0x07, 0xef, 0x20, 0x80, 0xe4, /* /M[.. .. */ + 0x2f, 0x49, 0x5a, 0xfe, 0xcf, 0x0a, 0xaf, 0xfe, /* /IZ..... */ + 0xcf, 0xfe, 0xcf, 0x41, 0x2e, 0x44, 0xbf, 0xfe, /* ...A.D.. */ + 0xcf, 0x41, 0x2e, 0x45, 0xbf, 0xfe, 0xcf, 0x52, /* .A.E...R */ + 0xaf, 0xfe, 0xcf, 0x53, 0xaf, 0xfe, 0xcf, 0x5a, /* ...S...Z */ + 0xaf, 0x05, 0x27, 0x58, 0x1e, 0x0d, 0x55, 0x02, /* ..'X..U. */ + 0x44, 0x01, 0x5a, 0x00, 0x2e, 0x54, 0x79, 0xfe, /* D.Z..Ty. */ + 0xcf, 0x75, 0xaf, 0xfe, 0xdf, 0x76, 0xbf, 0x41, /* .u...v.A */ + 0x2e, 0xa4, 0xdf, 0xdf, 0x29, 0x41, 0x2e, 0xa4, /* ....)A.. */ + 0xbf, 0x05, 0x27, 0x59, 0x1e, 0x03, 0x55, 0xfe, /* ..'Y..U. */ + 0xcf, 0x10, 0xaf, 0x01, 0x2e, 0x94, 0x76, 0x63, /* ......vc */ + 0x1e, 0x1a, 0x55, 0x54, 0x85, 0xe4, 0x2f, 0x1e, /* ..UT../. */ + 0x5b, 0x0c, 0xef, 0x20, 0x80, 0xe4, 0x2f, 0x1a, /* [.. ../. */ + 0x5a, 0xf0, 0xef, 0x00, 0xff, 0x19, 0x27, 0x08, /* Z.....'. */ + 0xef, 0x06, 0xaf, 0xfe, 0xcf, 0x5f, 0x9f, 0x06, /* ....._.. */ + 0x25, 0xfb, 0x55, 0xfe, 0xcf, 0xfe, 0xcf, 0x41, /* %.U....A */ + 0x2e, 0x40, 0xbf, 0xfe, 0xcf, 0x41, 0x2e, 0x41, /* .@...A.A */ + 0xbf, 0xfe, 0xcf, 0x41, 0x2e /* ...A. */ }; static const unsigned char pkt21[] = { -0x42, 0xca, 0x00, -0x4f, 0x21, 0x42, 0xbf, 0x05, /* B..O!B.. */ -0x27, 0x64, 0x1e, 0x31, 0x55, 0xb0, 0xef, 0x00, /* 'd.1U... */ -0xff, 0x19, 0x27, 0x0b, 0xef, 0x06, 0xaf, 0xfe, /* ..'..... */ -0xcf, 0x5f, 0x9f, 0x06, 0x25, 0xfb, 0x55, 0xfe, /* ._..%.U. */ -0xcf, 0x56, 0xaf, 0xfe, 0xcf, 0xae, 0xdf, 0x1f, /* .V...... */ -0x1c, 0xe0, 0x1d, 0x5f, 0x02, 0xae, 0xbf, 0xfe, /* ..._.... */ -0xcf, 0x41, 0x2e, 0x54, 0xbf, 0xfe, 0xcf, 0x41, /* .A.T...A */ -0x2e, 0x77, 0xbf, 0xfe, 0xcf, 0x41, 0x2e, 0x55, /* .w...A.U */ -0xbf, 0xfe, 0xcf, 0x41, 0x2e, 0x78, 0xbf, 0xfe, /* ...A.x.. */ -0xcf, 0xbb, 0xaf, 0xfe, 0xcf, 0xbc, 0xaf, 0xfe, /* ........ */ -0xcf, 0xbd, 0xaf, 0xfe, 0xcf, 0xbe, 0xaf, 0xfe, /* ........ */ -0xcf, 0x83, 0xaf, 0xfe, 0xcf, 0x84, 0xaf, 0xfe, /* ........ */ -0xcf, 0x81, 0xaf, 0xfe, 0xcf, 0x82, 0xaf, 0xfe, /* ........ */ -0xcf, 0x24, 0xaf, 0xfe, 0xcf, 0x02, 0x33, 0x05, /* .$....3. */ -0x27, 0x66, 0x1e, 0x0b, 0x55, 0xc5, 0xef, 0x2f, /* 'f..U../ */ -0xff, 0x1a, 0x27, 0x0b, 0xef, 0x06, 0xaf, 0xfe, /* ..'..... */ -0xcf, 0xfe, 0xdf, 0x06, 0x27, 0x01, 0x0e, 0x06, /* ....'... */ -0x25, 0xf9, 0x55, 0x05, 0x27, 0x73, 0x1e, 0x02, /* %.U.'s.. */ -0x55, 0x02, 0x2e, 0x5a, 0x88, 0x05, 0x27, 0x7d, /* U..Z..'} */ -0x1e, 0x0c, 0x55, 0x02, 0x2e, 0xb7, 0x81, 0xe3, /* ..U..... */ -0x2f, 0xb9, 0x5a, 0xfe, 0xcf, 0xfe, 0xdf, 0x1b, /* /.Z..... */ -0x27, 0xfe, 0xcf, 0x36, 0x03, 0xfe, 0xdf, 0x3f, /* '..6...? */ -0x02, 0x9f, 0x9d, 0x05, 0x27, 0x7e, 0x1e, 0x0c, /* ....'~.. */ -0x55, 0x02, 0x2e, 0xb7, 0x81, 0xe3, 0x2f, 0xaa, /* U...../. */ -0x5a, 0xfe, 0xcf, 0xfe, 0xdf, 0x1b, 0x27, 0x07, /* Z.....'. */ -0x80, 0xf6, 0x97, 0xff, 0xaf /* ..... */ + 0x42, 0xca, 0x00, + 0x4f, 0x21, 0x42, 0xbf, 0x05, /* B..O!B.. */ + 0x27, 0x64, 0x1e, 0x31, 0x55, 0xb0, 0xef, 0x00, /* 'd.1U... */ + 0xff, 0x19, 0x27, 0x0b, 0xef, 0x06, 0xaf, 0xfe, /* ..'..... */ + 0xcf, 0x5f, 0x9f, 0x06, 0x25, 0xfb, 0x55, 0xfe, /* ._..%.U. */ + 0xcf, 0x56, 0xaf, 0xfe, 0xcf, 0xae, 0xdf, 0x1f, /* .V...... */ + 0x1c, 0xe0, 0x1d, 0x5f, 0x02, 0xae, 0xbf, 0xfe, /* ..._.... */ + 0xcf, 0x41, 0x2e, 0x54, 0xbf, 0xfe, 0xcf, 0x41, /* .A.T...A */ + 0x2e, 0x77, 0xbf, 0xfe, 0xcf, 0x41, 0x2e, 0x55, /* .w...A.U */ + 0xbf, 0xfe, 0xcf, 0x41, 0x2e, 0x78, 0xbf, 0xfe, /* ...A.x.. */ + 0xcf, 0xbb, 0xaf, 0xfe, 0xcf, 0xbc, 0xaf, 0xfe, /* ........ */ + 0xcf, 0xbd, 0xaf, 0xfe, 0xcf, 0xbe, 0xaf, 0xfe, /* ........ */ + 0xcf, 0x83, 0xaf, 0xfe, 0xcf, 0x84, 0xaf, 0xfe, /* ........ */ + 0xcf, 0x81, 0xaf, 0xfe, 0xcf, 0x82, 0xaf, 0xfe, /* ........ */ + 0xcf, 0x24, 0xaf, 0xfe, 0xcf, 0x02, 0x33, 0x05, /* .$....3. */ + 0x27, 0x66, 0x1e, 0x0b, 0x55, 0xc5, 0xef, 0x2f, /* 'f..U../ */ + 0xff, 0x1a, 0x27, 0x0b, 0xef, 0x06, 0xaf, 0xfe, /* ..'..... */ + 0xcf, 0xfe, 0xdf, 0x06, 0x27, 0x01, 0x0e, 0x06, /* ....'... */ + 0x25, 0xf9, 0x55, 0x05, 0x27, 0x73, 0x1e, 0x02, /* %.U.'s.. */ + 0x55, 0x02, 0x2e, 0x5a, 0x88, 0x05, 0x27, 0x7d, /* U..Z..'} */ + 0x1e, 0x0c, 0x55, 0x02, 0x2e, 0xb7, 0x81, 0xe3, /* ..U..... */ + 0x2f, 0xb9, 0x5a, 0xfe, 0xcf, 0xfe, 0xdf, 0x1b, /* /.Z..... */ + 0x27, 0xfe, 0xcf, 0x36, 0x03, 0xfe, 0xdf, 0x3f, /* '..6...? */ + 0x02, 0x9f, 0x9d, 0x05, 0x27, 0x7e, 0x1e, 0x0c, /* ....'~.. */ + 0x55, 0x02, 0x2e, 0xb7, 0x81, 0xe3, 0x2f, 0xaa, /* U...../. */ + 0x5a, 0xfe, 0xcf, 0xfe, 0xdf, 0x1b, 0x27, 0x07, /* Z.....'. */ + 0x80, 0xf6, 0x97, 0xff, 0xaf /* ..... */ }; static const unsigned char pkt23[] = { -0x42, 0xca, 0x00, -0xb3, 0x21, 0x00, 0x2e, 0xa7, /* B...!... */ -0x8a, 0x05, 0x27, 0x61, 0x74, 0xff, 0x96, 0xc6, /* ..'at... */ -0x2e, 0x01, 0xdf, 0x3f, 0x2c, 0xdd, 0x9f, 0x05, /* ...?,... */ -0x27, 0x01, 0xef, 0x20, 0x80, 0xe3, 0x2f, 0x96, /* '.. ../. */ -0x5a, 0xfe, 0xcf, 0xdf, 0x22, 0xe9, 0x2f, 0xf0, /* Z..."./. */ -0x54, 0x01, 0xff, 0x85, 0xef, 0xff, 0x96, 0xdf, /* T....... */ -0x96, 0x34, 0xff, 0x8d, 0xef, 0x19, 0x27, 0x03, /* .4....'. */ -0xcf, 0x7f, 0x1c, 0x5f, 0x9f, 0xdd, 0x97, 0x5f, /* ..._..._ */ -0x9f, 0xdd, 0x97, 0x5f, 0x9f, 0x05, 0xef, 0x06, /* ..._.... */ -0xaf, 0x9f, 0x22, 0x5f, 0x9f, 0x06, 0x25, 0xfc, /* .."_..%. */ -0x55, 0x5f, 0x9f, 0x06, 0x25, 0xfc, 0x55, 0x20, /* U_..%.U */ -0xef, 0x08, 0xaf, 0x09, 0x23, 0x01, 0x2e, 0x06, /* ....#... */ -0x82, 0x51, 0x81, 0x03, 0xef, 0xfc, 0xaf, 0x84, /* .Q...... */ -0xef, 0xaa, 0xaf, 0x08, 0xef, 0xe3, 0xaf, 0x9f, /* ........ */ -0x22, 0xe2, 0xaf, 0x21, 0xef, 0x41, 0x2e, 0x47, /* "..!.A.G */ -0xbf, 0x27, 0xef, 0xf4, 0xaf, 0x2d, 0xff, 0xa7, /* .'...-.. */ -0xef, 0xe1, 0xbf, 0xe0, 0xaf, 0x08, 0xef, 0x10, /* ........ */ -0xaf, 0x01, 0x2e, 0x94, 0x86, 0xed, 0x80, 0x01, /* ........ */ -0x2e, 0x18, 0x87, 0x01, 0x2e, 0x1a, 0x87, 0x9b, /* ........ */ -0x22, 0x9b, 0x22, 0x34, 0xff, 0x95, 0xef, 0x19, /* "."4.... */ -0x27, 0x2d, 0xff, 0xa7, 0xef, 0x1a, 0x27, 0xc0, /* '-....'. */ -0xef, 0x06, 0xaf, 0xdc, 0x97, 0x5f, 0x9f, 0x06, /* ....._.. */ -0xdf, 0xc0, 0x1f, 0x03, 0x54, 0xdf, 0x22, 0x01, /* ....T.". */ -0x54, 0x00, 0x2e, 0xb9, 0x8b, 0x06, 0x25, 0xf4, /* T.....%. */ -0x55, 0x34, 0xff, 0x91, 0xef, 0x19, 0x27, 0xdd, /* U4....'. */ -0x97, 0xdd, 0x9f, 0x5f, 0x9f /* ..._. */ + 0x42, 0xca, 0x00, + 0xb3, 0x21, 0x00, 0x2e, 0xa7, /* B...!... */ + 0x8a, 0x05, 0x27, 0x61, 0x74, 0xff, 0x96, 0xc6, /* ..'at... */ + 0x2e, 0x01, 0xdf, 0x3f, 0x2c, 0xdd, 0x9f, 0x05, /* ...?,... */ + 0x27, 0x01, 0xef, 0x20, 0x80, 0xe3, 0x2f, 0x96, /* '.. ../. */ + 0x5a, 0xfe, 0xcf, 0xdf, 0x22, 0xe9, 0x2f, 0xf0, /* Z..."./. */ + 0x54, 0x01, 0xff, 0x85, 0xef, 0xff, 0x96, 0xdf, /* T....... */ + 0x96, 0x34, 0xff, 0x8d, 0xef, 0x19, 0x27, 0x03, /* .4....'. */ + 0xcf, 0x7f, 0x1c, 0x5f, 0x9f, 0xdd, 0x97, 0x5f, /* ..._..._ */ + 0x9f, 0xdd, 0x97, 0x5f, 0x9f, 0x05, 0xef, 0x06, /* ..._.... */ + 0xaf, 0x9f, 0x22, 0x5f, 0x9f, 0x06, 0x25, 0xfc, /* .."_..%. */ + 0x55, 0x5f, 0x9f, 0x06, 0x25, 0xfc, 0x55, 0x20, /* U_..%.U */ + 0xef, 0x08, 0xaf, 0x09, 0x23, 0x01, 0x2e, 0x06, /* ....#... */ + 0x82, 0x51, 0x81, 0x03, 0xef, 0xfc, 0xaf, 0x84, /* .Q...... */ + 0xef, 0xaa, 0xaf, 0x08, 0xef, 0xe3, 0xaf, 0x9f, /* ........ */ + 0x22, 0xe2, 0xaf, 0x21, 0xef, 0x41, 0x2e, 0x47, /* "..!.A.G */ + 0xbf, 0x27, 0xef, 0xf4, 0xaf, 0x2d, 0xff, 0xa7, /* .'...-.. */ + 0xef, 0xe1, 0xbf, 0xe0, 0xaf, 0x08, 0xef, 0x10, /* ........ */ + 0xaf, 0x01, 0x2e, 0x94, 0x86, 0xed, 0x80, 0x01, /* ........ */ + 0x2e, 0x18, 0x87, 0x01, 0x2e, 0x1a, 0x87, 0x9b, /* ........ */ + 0x22, 0x9b, 0x22, 0x34, 0xff, 0x95, 0xef, 0x19, /* "."4.... */ + 0x27, 0x2d, 0xff, 0xa7, 0xef, 0x1a, 0x27, 0xc0, /* '-....'. */ + 0xef, 0x06, 0xaf, 0xdc, 0x97, 0x5f, 0x9f, 0x06, /* ....._.. */ + 0xdf, 0xc0, 0x1f, 0x03, 0x54, 0xdf, 0x22, 0x01, /* ....T.". */ + 0x54, 0x00, 0x2e, 0xb9, 0x8b, 0x06, 0x25, 0xf4, /* T.....%. */ + 0x55, 0x34, 0xff, 0x91, 0xef, 0x19, 0x27, 0xdd, /* U4....'. */ + 0x97, 0xdd, 0x9f, 0x5f, 0x9f /* ..._. */ }; static const unsigned char pkt25[] = { -0x42, 0xb2, 0x00, -0x17, 0x22, 0x7f, 0x9f, 0xfd, /* B..."... */ -0x0d, 0xdf, 0x22, 0x01, 0x55, 0xff, 0x22, 0x01, /* ..".U.". */ -0x54, 0x01, 0xef, 0x1f, 0x98, 0x2f, 0xef, 0x41, /* T..../.A */ -0x2e, 0x47, 0xbf, 0x11, 0xef, 0xf4, 0xaf, 0x2d, /* .G.....- */ -0xff, 0xa7, 0xef, 0xe1, 0xbf, 0xe0, 0xaf, 0x01, /* ........ */ -0x2e, 0x18, 0x87, 0x01, 0x2e, 0x1a, 0x87, 0x9b, /* ........ */ -0x22, 0x9b, 0x22, 0x35, 0xff, 0x55, 0xef, 0x19, /* "."5.U.. */ -0x27, 0x2d, 0xff, 0xa7, 0xef, 0x1a, 0x27, 0xc0, /* '-....'. */ -0xef, 0x06, 0xaf, 0xdc, 0x97, 0xff, 0x1a, 0x5f, /* ......._ */ -0x9f, 0x06, 0xdf, 0xc0, 0x1f, 0x03, 0x54, 0xdf, /* ......T. */ -0x22, 0x01, 0x54, 0x00, 0x2e, 0xb9, 0x8b, 0x06, /* ".T..... */ -0x25, 0xf3, 0x55, 0x34, 0xff, 0x93, 0xef, 0x19, /* %.U4.... */ -0x27, 0xdd, 0x97, 0xdd, 0x9f, 0x5f, 0x9f, 0x7f, /* '...._.. */ -0x9f, 0xfb, 0x0d, 0xdf, 0x22, 0x01, 0x54, 0x01, /* ....".T. */ -0xef, 0x1f, 0x98, 0xff, 0x22, 0x01, 0x54, 0x01, /* ....".T. */ -0xef, 0x1f, 0x98, 0x34, 0xff, 0x8d, 0xef, 0x19, /* ...4.... */ -0x27, 0x01, 0x2e, 0x0c, 0x85, 0x00, 0x2e, 0xa7, /* '....... */ -0x8a, 0x55, 0x81, 0x02, 0xef, 0xfc, 0xaf, 0x88, /* .U...... */ -0xef, 0xaa, 0xaf, 0x00, 0xef, 0x41, 0x2e, 0x47, /* .....A.G */ -0xbf, 0x05, 0x27, 0xf9, 0x35, 0xc1, 0x2e, 0x4e, /* ..'.5..N */ -0xdf, 0x0f, 0x1d, 0x09, 0x27, 0x5f, 0x02, 0xc1, /* ....'_.. */ -0x2e, 0x4e, 0xbf, 0x05, 0x27, 0x9f, 0x22, 0x02, /* .N..'.". */ -0x2e, 0xa6, 0x85, 0x05, 0x27 /* ....' */ + 0x42, 0xb2, 0x00, + 0x17, 0x22, 0x7f, 0x9f, 0xfd, /* B..."... */ + 0x0d, 0xdf, 0x22, 0x01, 0x55, 0xff, 0x22, 0x01, /* ..".U.". */ + 0x54, 0x01, 0xef, 0x1f, 0x98, 0x2f, 0xef, 0x41, /* T..../.A */ + 0x2e, 0x47, 0xbf, 0x11, 0xef, 0xf4, 0xaf, 0x2d, /* .G.....- */ + 0xff, 0xa7, 0xef, 0xe1, 0xbf, 0xe0, 0xaf, 0x01, /* ........ */ + 0x2e, 0x18, 0x87, 0x01, 0x2e, 0x1a, 0x87, 0x9b, /* ........ */ + 0x22, 0x9b, 0x22, 0x35, 0xff, 0x55, 0xef, 0x19, /* "."5.U.. */ + 0x27, 0x2d, 0xff, 0xa7, 0xef, 0x1a, 0x27, 0xc0, /* '-....'. */ + 0xef, 0x06, 0xaf, 0xdc, 0x97, 0xff, 0x1a, 0x5f, /* ......._ */ + 0x9f, 0x06, 0xdf, 0xc0, 0x1f, 0x03, 0x54, 0xdf, /* ......T. */ + 0x22, 0x01, 0x54, 0x00, 0x2e, 0xb9, 0x8b, 0x06, /* ".T..... */ + 0x25, 0xf3, 0x55, 0x34, 0xff, 0x93, 0xef, 0x19, /* %.U4.... */ + 0x27, 0xdd, 0x97, 0xdd, 0x9f, 0x5f, 0x9f, 0x7f, /* '...._.. */ + 0x9f, 0xfb, 0x0d, 0xdf, 0x22, 0x01, 0x54, 0x01, /* ....".T. */ + 0xef, 0x1f, 0x98, 0xff, 0x22, 0x01, 0x54, 0x01, /* ....".T. */ + 0xef, 0x1f, 0x98, 0x34, 0xff, 0x8d, 0xef, 0x19, /* ...4.... */ + 0x27, 0x01, 0x2e, 0x0c, 0x85, 0x00, 0x2e, 0xa7, /* '....... */ + 0x8a, 0x55, 0x81, 0x02, 0xef, 0xfc, 0xaf, 0x88, /* .U...... */ + 0xef, 0xaa, 0xaf, 0x00, 0xef, 0x41, 0x2e, 0x47, /* .....A.G */ + 0xbf, 0x05, 0x27, 0xf9, 0x35, 0xc1, 0x2e, 0x4e, /* ..'.5..N */ + 0xdf, 0x0f, 0x1d, 0x09, 0x27, 0x5f, 0x02, 0xc1, /* ....'_.. */ + 0x2e, 0x4e, 0xbf, 0x05, 0x27, 0x9f, 0x22, 0x02, /* .N..'.". */ + 0x2e, 0xa6, 0x85, 0x05, 0x27 /* ....' */ }; static const unsigned char pkt27[] = { -0x42, 0xca, 0x00, -0x6f, 0x22, 0x51, 0x85, 0x01, /* B..o"Q.. */ -0x1e, 0x38, 0x55, 0x26, 0x40, 0x12, 0x5b, 0x26, /* .8U&@.[& */ -0x42, 0x2e, 0x5a, 0x26, 0x41, 0x0e, 0x5a, 0x26, /* B.Z&A.Z& */ -0xcf, 0x40, 0x1a, 0x26, 0xaf, 0x9f, 0x2d, 0x27, /* .@.&..-' */ -0x5a, 0x07, 0x80, 0x01, 0xef, 0xff, 0xaf, 0x26, /* Z......& */ -0x43, 0x01, 0x5b, 0x74, 0x25, 0x00, 0x55, 0x26, /* C.[t%.U& */ -0x32, 0x00, 0x2e, 0xa7, 0x7a, 0x02, 0x2e, 0xc0, /* 2...z... */ -0x85, 0x26, 0x40, 0x08, 0x5b, 0x41, 0x2e, 0x52, /* .&@.[A.R */ -0xdf, 0xdf, 0x2d, 0x04, 0x5b, 0x26, 0x43, 0x01, /* ..-.[&C. */ -0x5b, 0x74, 0x25, 0x00, 0x55, 0x26, 0x32, 0x41, /* [t%.U&2A */ -0x2e, 0x53, 0xdf, 0xc1, 0x2e, 0x79, 0xdf, 0xff, /* .S...y.. */ -0x96, 0xdf, 0x96, 0x41, 0x2e, 0x55, 0xdf, 0xc1, /* ...A.U.. */ -0x2e, 0x78, 0xdf, 0x9d, 0x01, 0x5d, 0x01, 0xff, /* .x...].. */ -0x22, 0x00, 0x54, 0xff, 0xef, 0x2e, 0xaf, 0x05, /* ".T..... */ -0x27, 0x07, 0x80, 0x9f, 0x22, 0xff, 0xaf, 0x00, /* '..."... */ -0x2e, 0xa7, 0x8a, 0x05, 0x27, 0x03, 0x1e, 0x3f, /* ....'..? */ -0x55, 0x02, 0x2e, 0xad, 0x85, 0xa1, 0xcf, 0xfe, /* U....... */ -0x1c, 0xa1, 0xaf, 0xed, 0x80, 0x31, 0x81, 0x02, /* .....1.. */ -0x2e, 0x51, 0x83, 0xff, 0x96, 0xdf, 0x96, 0xa1, /* .Q...... */ -0xcf, 0x01, 0x18, 0xa1, 0xaf, 0xed, 0x80, 0x64, /* .......d */ -0xef, 0xbf, 0x22, 0xa9, 0x80, 0x31, 0x81, 0x02, /* .."..1.. */ -0x2e, 0x51, 0x83, 0xff, 0x96, 0xdf, 0x96, 0x9b, /* .Q...... */ -0x22, 0x14, 0x1e, 0x03, 0x53, 0xff, 0x22, 0x01, /* "...S.". */ -0x55, 0x00, 0x20, 0x0a, 0x50, 0xc3, 0x97, 0xc4, /* U. .P... */ -0x9f, 0x81, 0x01, 0x42, 0x01, 0x03, 0x52, 0xfa, /* ...B..R. */ -0x1e, 0x03, 0x53, 0xff, 0x22 /* ..S." */ + 0x42, 0xca, 0x00, + 0x6f, 0x22, 0x51, 0x85, 0x01, /* B..o"Q.. */ + 0x1e, 0x38, 0x55, 0x26, 0x40, 0x12, 0x5b, 0x26, /* .8U&@.[& */ + 0x42, 0x2e, 0x5a, 0x26, 0x41, 0x0e, 0x5a, 0x26, /* B.Z&A.Z& */ + 0xcf, 0x40, 0x1a, 0x26, 0xaf, 0x9f, 0x2d, 0x27, /* .@.&..-' */ + 0x5a, 0x07, 0x80, 0x01, 0xef, 0xff, 0xaf, 0x26, /* Z......& */ + 0x43, 0x01, 0x5b, 0x74, 0x25, 0x00, 0x55, 0x26, /* C.[t%.U& */ + 0x32, 0x00, 0x2e, 0xa7, 0x7a, 0x02, 0x2e, 0xc0, /* 2...z... */ + 0x85, 0x26, 0x40, 0x08, 0x5b, 0x41, 0x2e, 0x52, /* .&@.[A.R */ + 0xdf, 0xdf, 0x2d, 0x04, 0x5b, 0x26, 0x43, 0x01, /* ..-.[&C. */ + 0x5b, 0x74, 0x25, 0x00, 0x55, 0x26, 0x32, 0x41, /* [t%.U&2A */ + 0x2e, 0x53, 0xdf, 0xc1, 0x2e, 0x79, 0xdf, 0xff, /* .S...y.. */ + 0x96, 0xdf, 0x96, 0x41, 0x2e, 0x55, 0xdf, 0xc1, /* ...A.U.. */ + 0x2e, 0x78, 0xdf, 0x9d, 0x01, 0x5d, 0x01, 0xff, /* .x...].. */ + 0x22, 0x00, 0x54, 0xff, 0xef, 0x2e, 0xaf, 0x05, /* ".T..... */ + 0x27, 0x07, 0x80, 0x9f, 0x22, 0xff, 0xaf, 0x00, /* '..."... */ + 0x2e, 0xa7, 0x8a, 0x05, 0x27, 0x03, 0x1e, 0x3f, /* ....'..? */ + 0x55, 0x02, 0x2e, 0xad, 0x85, 0xa1, 0xcf, 0xfe, /* U....... */ + 0x1c, 0xa1, 0xaf, 0xed, 0x80, 0x31, 0x81, 0x02, /* .....1.. */ + 0x2e, 0x51, 0x83, 0xff, 0x96, 0xdf, 0x96, 0xa1, /* .Q...... */ + 0xcf, 0x01, 0x18, 0xa1, 0xaf, 0xed, 0x80, 0x64, /* .......d */ + 0xef, 0xbf, 0x22, 0xa9, 0x80, 0x31, 0x81, 0x02, /* .."..1.. */ + 0x2e, 0x51, 0x83, 0xff, 0x96, 0xdf, 0x96, 0x9b, /* .Q...... */ + 0x22, 0x14, 0x1e, 0x03, 0x53, 0xff, 0x22, 0x01, /* "...S.". */ + 0x55, 0x00, 0x20, 0x0a, 0x50, 0xc3, 0x97, 0xc4, /* U. .P... */ + 0x9f, 0x81, 0x01, 0x42, 0x01, 0x03, 0x52, 0xfa, /* ...B..R. */ + 0x1e, 0x03, 0x53, 0xff, 0x22 /* ..S." */ }; static const unsigned char pkt29[] = { -0x42, 0xca, 0x00, -0xd3, 0x22, 0x01, 0x55, 0x00, /* B...".U. */ -0x20, 0xf2, 0x50, 0x00, 0x2e, 0xd8, 0x8d, 0x03, /* .P..... */ -0xcf, 0x7f, 0x1c, 0xff, 0xaf, 0x05, 0xef, 0xff, /* ........ */ -0xaf, 0x00, 0xef, 0xff, 0xaf, 0xdd, 0x97, 0xff, /* ........ */ -0xaf, 0xc2, 0x97, 0xff, 0xaf, 0xc3, 0x97, 0xff, /* ........ */ -0xaf, 0xc0, 0x97, 0xff, 0xaf, 0xc1, 0x97, 0xff, /* ........ */ -0xaf, 0x04, 0x0c, 0x00, 0x2e, 0xa7, 0x8a, 0x05, /* ........ */ -0x27, 0x06, 0x1e, 0x01, 0x55, 0x0f, 0x27, 0x0f, /* '...U.'. */ -0x27, 0x0a, 0x1e, 0x08, 0x55, 0x02, 0x2e, 0xf6, /* '...U... */ -0x82, 0xa8, 0x77, 0x3b, 0x30, 0x07, 0x35, 0xff, /* ..w;0.5. */ -0xff, 0xc2, 0xbf, 0x0d, 0x27, 0x0c, 0x27, 0x0d, /* ....'.'. */ -0x1e, 0x02, 0x55, 0x54, 0x85, 0xf5, 0x5b, 0xbd, /* ..UT..[. */ -0x77, 0x12, 0x1e, 0x07, 0x55, 0xdc, 0xef, 0x05, /* w...U... */ -0xff, 0x1a, 0x27, 0x56, 0xdf, 0x3f, 0x20, 0x59, /* ..'V.? Y */ -0x80, 0x3c, 0xaf, 0x05, 0x27, 0x13, 0x1e, 0x01, /* .<..'... */ -0x55, 0x3c, 0x23, 0x05, 0x27, 0x1f, 0x1e, 0x06, /* U<#.'... */ -0x55, 0x37, 0x35, 0x08, 0xef, 0x40, 0x2e, 0xf0, /* U75..@.. */ -0xbf, 0x40, 0x2e, 0xf6, 0xbf, 0x05, 0x27, 0x20, /* .@....' */ -0x1e, 0x06, 0x55, 0x37, 0x3d, 0x16, 0xef, 0x40, /* ..U7=..@ */ -0x2e, 0xf0, 0xbf, 0x40, 0x2e, 0xf6, 0xbf, 0x05, /* ...@.... */ -0x27, 0x2e, 0x1e, 0x0c, 0x55, 0x02, 0x2e, 0x57, /* '...U..W */ -0x80, 0x41, 0x2e, 0xa1, 0xdf, 0xdf, 0x2a, 0x41, /* .A....*A */ -0x2e, 0xa1, 0xbf, 0x02, 0x2e, 0x57, 0x80, 0x9b, /* .....W.. */ -0x22, 0xdf, 0x2f, 0xd3, 0x50, 0x05, 0x27, 0x2f, /* "./.P.'/ */ -0x1e, 0x0c, 0x55, 0x02, 0x2e, 0x57, 0x80, 0x41, /* ..U..W.A */ -0x2e, 0xa1, 0xdf, 0xdf, 0x2a /* ....* */ + 0x42, 0xca, 0x00, + 0xd3, 0x22, 0x01, 0x55, 0x00, /* B...".U. */ + 0x20, 0xf2, 0x50, 0x00, 0x2e, 0xd8, 0x8d, 0x03, /* .P..... */ + 0xcf, 0x7f, 0x1c, 0xff, 0xaf, 0x05, 0xef, 0xff, /* ........ */ + 0xaf, 0x00, 0xef, 0xff, 0xaf, 0xdd, 0x97, 0xff, /* ........ */ + 0xaf, 0xc2, 0x97, 0xff, 0xaf, 0xc3, 0x97, 0xff, /* ........ */ + 0xaf, 0xc0, 0x97, 0xff, 0xaf, 0xc1, 0x97, 0xff, /* ........ */ + 0xaf, 0x04, 0x0c, 0x00, 0x2e, 0xa7, 0x8a, 0x05, /* ........ */ + 0x27, 0x06, 0x1e, 0x01, 0x55, 0x0f, 0x27, 0x0f, /* '...U.'. */ + 0x27, 0x0a, 0x1e, 0x08, 0x55, 0x02, 0x2e, 0xf6, /* '...U... */ + 0x82, 0xa8, 0x77, 0x3b, 0x30, 0x07, 0x35, 0xff, /* ..w;0.5. */ + 0xff, 0xc2, 0xbf, 0x0d, 0x27, 0x0c, 0x27, 0x0d, /* ....'.'. */ + 0x1e, 0x02, 0x55, 0x54, 0x85, 0xf5, 0x5b, 0xbd, /* ..UT..[. */ + 0x77, 0x12, 0x1e, 0x07, 0x55, 0xdc, 0xef, 0x05, /* w...U... */ + 0xff, 0x1a, 0x27, 0x56, 0xdf, 0x3f, 0x20, 0x59, /* ..'V.? Y */ + 0x80, 0x3c, 0xaf, 0x05, 0x27, 0x13, 0x1e, 0x01, /* .<..'... */ + 0x55, 0x3c, 0x23, 0x05, 0x27, 0x1f, 0x1e, 0x06, /* U<#.'... */ + 0x55, 0x37, 0x35, 0x08, 0xef, 0x40, 0x2e, 0xf0, /* U75..@.. */ + 0xbf, 0x40, 0x2e, 0xf6, 0xbf, 0x05, 0x27, 0x20, /* .@....' */ + 0x1e, 0x06, 0x55, 0x37, 0x3d, 0x16, 0xef, 0x40, /* ..U7=..@ */ + 0x2e, 0xf0, 0xbf, 0x40, 0x2e, 0xf6, 0xbf, 0x05, /* ...@.... */ + 0x27, 0x2e, 0x1e, 0x0c, 0x55, 0x02, 0x2e, 0x57, /* '...U..W */ + 0x80, 0x41, 0x2e, 0xa1, 0xdf, 0xdf, 0x2a, 0x41, /* .A....*A */ + 0x2e, 0xa1, 0xbf, 0x02, 0x2e, 0x57, 0x80, 0x9b, /* .....W.. */ + 0x22, 0xdf, 0x2f, 0xd3, 0x50, 0x05, 0x27, 0x2f, /* "./.P.'/ */ + 0x1e, 0x0c, 0x55, 0x02, 0x2e, 0x57, 0x80, 0x41, /* ..U..W.A */ + 0x2e, 0xa1, 0xdf, 0xdf, 0x2a /* ....* */ }; static const unsigned char pkt31[] = { -0x42, 0x88, 0x00, -0x37, 0x23, 0x41, 0x2e, 0xa1, /* B..7#A.. */ -0xbf, 0x02, 0x2e, 0x57, 0x80, 0x08, 0x18, 0x41, /* ...W...A */ -0x2e, 0xa1, 0xbf, 0x05, 0x27, 0x30, 0x1e, 0x0e, /* ....'0.. */ -0x55, 0x7e, 0xef, 0xff, 0xaf, 0x02, 0xef, 0xff, /* U~...... */ -0xaf, 0x00, 0xef, 0xff, 0xaf, 0xff, 0xef, 0x1f, /* ........ */ -0xff, 0x1a, 0x27, 0x07, 0x27, 0xff, 0xaf, 0xff, /* ..'.'... */ -0xbf, 0x00, 0x2e, 0xa7, 0x8a, 0x05, 0x27, 0xf7, /* ......'. */ -0x74, 0xc9, 0xcf, 0xf3, 0x1c, 0x04, 0x18, 0xc9, /* t....... */ -0xaf, 0x23, 0x81, 0x10, 0xff, 0xff, 0xef, 0xc1, /* .#...... */ -0x2e, 0x7c, 0xbf, 0x41, 0x2e, 0x7b, 0xbf, 0x02, /* .|.A.{.. */ -0xef, 0x41, 0x2e, 0x7a, 0xbf, 0xc9, 0x31, 0x18, /* .A.z..1. */ -0xef, 0xc0, 0xaf, 0x04, 0x27, 0x41, 0x2e, 0x7a, /* ....'A.z */ -0xdf, 0xdf, 0x2d, 0x08, 0x5b, 0x01, 0xef, 0x41, /* ..-.[..A */ -0x2e, 0x7a, 0xbf, 0xc0, 0x23, 0x18, 0xef, 0xc1, /* .z..#... */ -0xaf, 0xcb, 0xcf, 0xcc, 0xdf, 0x05, 0x27, 0xc9, /* ......'. */ -0x30, 0x01, 0xef, 0x41, 0x2e, 0x7a, 0xbf, 0xc0, /* 0..A.z.. */ -0x23, 0x18, 0xef, 0xc1, 0xaf, 0x9f, 0x22, 0xbf, /* #.....". */ -0x22, 0x05, 0x27 /* ".' */ + 0x42, 0x88, 0x00, + 0x37, 0x23, 0x41, 0x2e, 0xa1, /* B..7#A.. */ + 0xbf, 0x02, 0x2e, 0x57, 0x80, 0x08, 0x18, 0x41, /* ...W...A */ + 0x2e, 0xa1, 0xbf, 0x05, 0x27, 0x30, 0x1e, 0x0e, /* ....'0.. */ + 0x55, 0x7e, 0xef, 0xff, 0xaf, 0x02, 0xef, 0xff, /* U~...... */ + 0xaf, 0x00, 0xef, 0xff, 0xaf, 0xff, 0xef, 0x1f, /* ........ */ + 0xff, 0x1a, 0x27, 0x07, 0x27, 0xff, 0xaf, 0xff, /* ..'.'... */ + 0xbf, 0x00, 0x2e, 0xa7, 0x8a, 0x05, 0x27, 0xf7, /* ......'. */ + 0x74, 0xc9, 0xcf, 0xf3, 0x1c, 0x04, 0x18, 0xc9, /* t....... */ + 0xaf, 0x23, 0x81, 0x10, 0xff, 0xff, 0xef, 0xc1, /* .#...... */ + 0x2e, 0x7c, 0xbf, 0x41, 0x2e, 0x7b, 0xbf, 0x02, /* .|.A.{.. */ + 0xef, 0x41, 0x2e, 0x7a, 0xbf, 0xc9, 0x31, 0x18, /* .A.z..1. */ + 0xef, 0xc0, 0xaf, 0x04, 0x27, 0x41, 0x2e, 0x7a, /* ....'A.z */ + 0xdf, 0xdf, 0x2d, 0x08, 0x5b, 0x01, 0xef, 0x41, /* ..-.[..A */ + 0x2e, 0x7a, 0xbf, 0xc0, 0x23, 0x18, 0xef, 0xc1, /* .z..#... */ + 0xaf, 0xcb, 0xcf, 0xcc, 0xdf, 0x05, 0x27, 0xc9, /* ......'. */ + 0x30, 0x01, 0xef, 0x41, 0x2e, 0x7a, 0xbf, 0xc0, /* 0..A.z.. */ + 0x23, 0x18, 0xef, 0xc1, 0xaf, 0x9f, 0x22, 0xbf, /* #.....". */ + 0x22, 0x05, 0x27 /* ".' */ }; static const unsigned char pkt33[] = { -0x42, 0xca, 0x00, -0x7a, 0x23, 0x9b, 0x22, 0xff, /* B..z#.". */ -0x86, 0x02, 0x2e, 0x96, 0x83, 0xc2, 0x85, 0x00, /* ........ */ -0xef, 0x41, 0x2e, 0x76, 0xbf, 0x56, 0x87, 0x02, /* .A.v.V.. */ -0x2e, 0xed, 0x83, 0x78, 0x86, 0x02, 0x33, 0x07, /* ...x..3. */ -0x80, 0xdd, 0x97, 0xff, 0xaf, 0x00, 0x2e, 0xa7, /* ........ */ -0x8a, 0x05, 0x27, 0x6c, 0xcf, 0x6d, 0xdf, 0xbf, /* ..'l.m.. */ -0x01, 0x6c, 0xaf, 0x6d, 0x26, 0x00, 0x2e, 0x2c, /* .l.m&.., */ -0x55, 0x00, 0x2e, 0x47, 0x50, 0x9f, 0x22, 0x6b, /* U..GP."k */ -0xaf, 0x62, 0xaf, 0x6d, 0x2e, 0x6a, 0xbf, 0x01, /* .b.m.j.. */ -0x2e, 0x3f, 0x84, 0x00, 0xef, 0x41, 0x2e, 0x44, /* .?...A.D */ -0xbf, 0xbf, 0xef, 0x41, 0x2e, 0x45, 0xbf, 0x80, /* ...A.E.. */ -0xef, 0x0a, 0xaf, 0x01, 0x2e, 0x06, 0x82, 0x80, /* ........ */ -0x82, 0x84, 0x82, 0x6b, 0xcf, 0x10, 0xaf, 0x01, /* ...k.... */ -0x2e, 0x94, 0x86, 0x40, 0xef, 0x6d, 0xaf, 0x80, /* ...@.m.. */ -0xef, 0x6c, 0xaf, 0x01, 0x2e, 0xf9, 0x81, 0xed, /* .l...... */ -0x80, 0x01, 0x2e, 0x18, 0x87, 0x01, 0x2e, 0x1a, /* ........ */ -0x87, 0x07, 0x87, 0xff, 0x2f, 0xd1, 0x5a, 0x6c, /* ..../.Zl */ -0xcf, 0x6d, 0xdf, 0x3f, 0x00, 0x6c, 0xaf, 0x6d, /* .m.?.l.m */ -0x26, 0x03, 0x54, 0x6d, 0xdf, 0x0c, 0x82, 0x6d, /* &.Tm...m */ -0xbf, 0xeb, 0x50, 0x6b, 0xcf, 0x08, 0x1e, 0x11, /* ..Pk.... */ -0x5f, 0x6c, 0x24, 0x02, 0x53, 0xff, 0xef, 0x6c, /* _l$.S..l */ -0xaf, 0x10, 0x50, 0x6c, 0x24, 0x02, 0x53, 0xff, /* ..Pl$.S. */ -0xef, 0x6c, 0xaf, 0x0b, 0x50, 0x6b, 0xcf, 0x0a, /* .l..Pk.. */ -0x1e, 0x08, 0x55, 0x6c, 0x24, 0x02, 0x53, 0xff, /* ..Ul$.S. */ -0xef, 0x6c, 0xaf, 0x03, 0x50, 0x6c, 0x24, 0x01, /* .l..Pl$. */ -0x53, 0xff, 0xef, 0x6c, 0xaf /* S..l. */ + 0x42, 0xca, 0x00, + 0x7a, 0x23, 0x9b, 0x22, 0xff, /* B..z#.". */ + 0x86, 0x02, 0x2e, 0x96, 0x83, 0xc2, 0x85, 0x00, /* ........ */ + 0xef, 0x41, 0x2e, 0x76, 0xbf, 0x56, 0x87, 0x02, /* .A.v.V.. */ + 0x2e, 0xed, 0x83, 0x78, 0x86, 0x02, 0x33, 0x07, /* ...x..3. */ + 0x80, 0xdd, 0x97, 0xff, 0xaf, 0x00, 0x2e, 0xa7, /* ........ */ + 0x8a, 0x05, 0x27, 0x6c, 0xcf, 0x6d, 0xdf, 0xbf, /* ..'l.m.. */ + 0x01, 0x6c, 0xaf, 0x6d, 0x26, 0x00, 0x2e, 0x2c, /* .l.m&.., */ + 0x55, 0x00, 0x2e, 0x47, 0x50, 0x9f, 0x22, 0x6b, /* U..GP."k */ + 0xaf, 0x62, 0xaf, 0x6d, 0x2e, 0x6a, 0xbf, 0x01, /* .b.m.j.. */ + 0x2e, 0x3f, 0x84, 0x00, 0xef, 0x41, 0x2e, 0x44, /* .?...A.D */ + 0xbf, 0xbf, 0xef, 0x41, 0x2e, 0x45, 0xbf, 0x80, /* ...A.E.. */ + 0xef, 0x0a, 0xaf, 0x01, 0x2e, 0x06, 0x82, 0x80, /* ........ */ + 0x82, 0x84, 0x82, 0x6b, 0xcf, 0x10, 0xaf, 0x01, /* ...k.... */ + 0x2e, 0x94, 0x86, 0x40, 0xef, 0x6d, 0xaf, 0x80, /* ...@.m.. */ + 0xef, 0x6c, 0xaf, 0x01, 0x2e, 0xf9, 0x81, 0xed, /* .l...... */ + 0x80, 0x01, 0x2e, 0x18, 0x87, 0x01, 0x2e, 0x1a, /* ........ */ + 0x87, 0x07, 0x87, 0xff, 0x2f, 0xd1, 0x5a, 0x6c, /* ..../.Zl */ + 0xcf, 0x6d, 0xdf, 0x3f, 0x00, 0x6c, 0xaf, 0x6d, /* .m.?.l.m */ + 0x26, 0x03, 0x54, 0x6d, 0xdf, 0x0c, 0x82, 0x6d, /* &.Tm...m */ + 0xbf, 0xeb, 0x50, 0x6b, 0xcf, 0x08, 0x1e, 0x11, /* ..Pk.... */ + 0x5f, 0x6c, 0x24, 0x02, 0x53, 0xff, 0xef, 0x6c, /* _l$.S..l */ + 0xaf, 0x10, 0x50, 0x6c, 0x24, 0x02, 0x53, 0xff, /* ..Pl$.S. */ + 0xef, 0x6c, 0xaf, 0x0b, 0x50, 0x6b, 0xcf, 0x0a, /* .l..Pk.. */ + 0x1e, 0x08, 0x55, 0x6c, 0x24, 0x02, 0x53, 0xff, /* ..Ul$.S. */ + 0xef, 0x6c, 0xaf, 0x03, 0x50, 0x6c, 0x24, 0x01, /* .l..Pl$. */ + 0x53, 0xff, 0xef, 0x6c, 0xaf /* S..l. */ }; static const unsigned char pkt35[] = { -0x42, 0xca, 0x00, -0xde, 0x23, 0x6b, 0xcf, 0xdf, /* B...#k.. */ -0x96, 0xb0, 0xef, 0x00, 0xff, 0x1d, 0x00, 0x00, /* ........ */ -0x13, 0x1b, 0x27, 0x6c, 0xcf, 0x9f, 0x9d, 0x6b, /* ..'l...k */ -0xcf, 0x1f, 0x20, 0x6b, 0xaf, 0x0a, 0x1e, 0xbc, /* .. k.... */ -0x5f, 0x05, 0x27, 0x01, 0x2e, 0x3f, 0x84, 0x55, /* _.'..?.U */ -0x82, 0x01, 0x2e, 0x06, 0x82, 0x73, 0x23, 0x0a, /* .....s#. */ -0xef, 0x10, 0xaf, 0x01, 0x2e, 0x94, 0x86, 0x80, /* ........ */ -0xef, 0x01, 0x2e, 0xf9, 0x81, 0xed, 0x80, 0x08, /* ........ */ -0xef, 0x06, 0xaf, 0x01, 0x2e, 0x18, 0x87, 0x01, /* ........ */ -0x2e, 0x1a, 0x87, 0x06, 0x25, 0xf9, 0x55, 0x02, /* ....%.U. */ -0x2e, 0x52, 0x84, 0x4e, 0x23, 0x40, 0xcf, 0xe0, /* .R.N#@.. */ -0xaf, 0x41, 0xdf, 0xe1, 0xbf, 0x41, 0x2e, 0x4e, /* .A...A.N */ -0xdf, 0xf7, 0x1c, 0x41, 0x2e, 0x4e, 0xbf, 0x01, /* ...A.N.. */ -0x2e, 0x18, 0x87, 0x01, 0x2e, 0x1a, 0x87, 0x45, /* .......E */ -0x82, 0x4e, 0x24, 0x4e, 0xcf, 0x20, 0x1e, 0x03, /* .N$N. .. */ -0x55, 0x01, 0xef, 0x1f, 0x90, 0x02, 0x2e, 0x87, /* U....... */ -0x73, 0x40, 0x2e, 0x8f, 0xdf, 0xdf, 0x22, 0xe5, /* s@....". */ -0x55, 0x4e, 0x86, 0x4e, 0x23, 0x4e, 0xcf, 0x52, /* UN.N#N.R */ -0x86, 0x59, 0x86, 0x3f, 0x9f, 0x4e, 0xcf, 0x52, /* .Y.?.N.R */ -0x86, 0x5f, 0x86, 0x1f, 0x9f, 0x4e, 0x24, 0x4e, /* ._...N$N */ -0xcf, 0x04, 0x1e, 0xf3, 0x55, 0xf8, 0x0f, 0x08, /* ....U... */ -0xef, 0x06, 0xaf, 0xf6, 0x97, 0xbc, 0x03, 0x01, /* ........ */ -0x5f, 0xff, 0x0f, 0xfc, 0x97, 0x06, 0x25, 0xf9, /* _.....%. */ -0x55, 0xf8, 0x0f, 0x08, 0xff, 0x06, 0xbf, 0xf6, /* U....... */ -0x9f, 0xdf, 0x01, 0xa1, 0x27, 0x7f, 0x21, 0x3f, /* ....'.!? */ -0x9f, 0x06, 0x25, 0xf8, 0x55 /* ..%.U */ + 0x42, 0xca, 0x00, + 0xde, 0x23, 0x6b, 0xcf, 0xdf, /* B...#k.. */ + 0x96, 0xb0, 0xef, 0x00, 0xff, 0x1d, 0x00, 0x00, /* ........ */ + 0x13, 0x1b, 0x27, 0x6c, 0xcf, 0x9f, 0x9d, 0x6b, /* ..'l...k */ + 0xcf, 0x1f, 0x20, 0x6b, 0xaf, 0x0a, 0x1e, 0xbc, /* .. k.... */ + 0x5f, 0x05, 0x27, 0x01, 0x2e, 0x3f, 0x84, 0x55, /* _.'..?.U */ + 0x82, 0x01, 0x2e, 0x06, 0x82, 0x73, 0x23, 0x0a, /* .....s#. */ + 0xef, 0x10, 0xaf, 0x01, 0x2e, 0x94, 0x86, 0x80, /* ........ */ + 0xef, 0x01, 0x2e, 0xf9, 0x81, 0xed, 0x80, 0x08, /* ........ */ + 0xef, 0x06, 0xaf, 0x01, 0x2e, 0x18, 0x87, 0x01, /* ........ */ + 0x2e, 0x1a, 0x87, 0x06, 0x25, 0xf9, 0x55, 0x02, /* ....%.U. */ + 0x2e, 0x52, 0x84, 0x4e, 0x23, 0x40, 0xcf, 0xe0, /* .R.N#@.. */ + 0xaf, 0x41, 0xdf, 0xe1, 0xbf, 0x41, 0x2e, 0x4e, /* .A...A.N */ + 0xdf, 0xf7, 0x1c, 0x41, 0x2e, 0x4e, 0xbf, 0x01, /* ...A.N.. */ + 0x2e, 0x18, 0x87, 0x01, 0x2e, 0x1a, 0x87, 0x45, /* .......E */ + 0x82, 0x4e, 0x24, 0x4e, 0xcf, 0x20, 0x1e, 0x03, /* .N$N. .. */ + 0x55, 0x01, 0xef, 0x1f, 0x90, 0x02, 0x2e, 0x87, /* U....... */ + 0x73, 0x40, 0x2e, 0x8f, 0xdf, 0xdf, 0x22, 0xe5, /* s@....". */ + 0x55, 0x4e, 0x86, 0x4e, 0x23, 0x4e, 0xcf, 0x52, /* UN.N#N.R */ + 0x86, 0x59, 0x86, 0x3f, 0x9f, 0x4e, 0xcf, 0x52, /* .Y.?.N.R */ + 0x86, 0x5f, 0x86, 0x1f, 0x9f, 0x4e, 0x24, 0x4e, /* ._...N$N */ + 0xcf, 0x04, 0x1e, 0xf3, 0x55, 0xf8, 0x0f, 0x08, /* ....U... */ + 0xef, 0x06, 0xaf, 0xf6, 0x97, 0xbc, 0x03, 0x01, /* ........ */ + 0x5f, 0xff, 0x0f, 0xfc, 0x97, 0x06, 0x25, 0xf9, /* _.....%. */ + 0x55, 0xf8, 0x0f, 0x08, 0xff, 0x06, 0xbf, 0xf6, /* U....... */ + 0x9f, 0xdf, 0x01, 0xa1, 0x27, 0x7f, 0x21, 0x3f, /* ....'.!? */ + 0x9f, 0x06, 0x25, 0xf8, 0x55 /* ..%.U */ }; static const unsigned char pkt37[] = { -0x42, 0xb2, 0x00, -0x42, 0x24, 0xf8, 0x0f, 0x04, /* B..B$... */ -0xef, 0x06, 0xaf, 0xbb, 0xef, 0x00, 0xff, 0x1a, /* ........ */ -0x27, 0xfc, 0x9f, 0xfc, 0x97, 0x09, 0x27, 0x5f, /* '.....'_ */ -0x02, 0x3f, 0x97, 0x06, 0x25, 0xf8, 0x55, 0x81, /* .?..%.U. */ -0xcf, 0x24, 0xaf, 0x05, 0x27, 0x0a, 0xef, 0x73, /* .$..'..s */ -0x43, 0x02, 0x5b, 0x73, 0xcf, 0x09, 0x27, 0x0f, /* C.[s..'. */ -0x1c, 0x81, 0xaf, 0x73, 0xcf, 0x09, 0x27, 0x30, /* ...s..'0 */ -0x1c, 0xfc, 0xdf, 0xcf, 0x1d, 0x5f, 0x02, 0xfc, /* ....._.. */ -0xbf, 0x81, 0xcf, 0x10, 0xaf, 0x01, 0x2e, 0x94, /* ........ */ -0x86, 0x80, 0x82, 0x01, 0x2e, 0x34, 0x81, 0x40, /* .....4.@ */ -0xef, 0x6b, 0xaf, 0x80, 0xef, 0x82, 0xaf, 0x01, /* .k...... */ -0x2e, 0xf9, 0x81, 0xed, 0x80, 0x01, 0x2e, 0x18, /* ........ */ -0x87, 0x01, 0x2e, 0x1a, 0x87, 0x16, 0x82, 0x01, /* ........ */ -0x2e, 0x2f, 0x89, 0x0a, 0x5b, 0x73, 0x43, 0x19, /* ./..[sC. */ -0x5a, 0x81, 0xcf, 0x5e, 0xdf, 0xbf, 0x03, 0x15, /* Z..^.... */ -0x5f, 0x5f, 0x20, 0x81, 0xaf, 0xdf, 0x22, 0x11, /* __ ...". */ -0x54, 0xde, 0x50, 0x40, 0x2e, 0x8f, 0xdf, 0x1f, /* T.P@.... */ -0x2c, 0x00, 0x2e, 0x0c, 0x5a, 0x5f, 0x2c, 0x09, /* ,...Z_,. */ -0x5b, 0x82, 0xcf, 0x6b, 0xdf, 0x3f, 0x00, 0x82, /* [..k.?.. */ -0xaf, 0x6b, 0x26, 0xe7, 0x54, 0x6b, 0xdf, 0x0c, /* .k&.Tk.. */ -0x82, 0x6b, 0xbf, 0xd8, 0x50, 0x05, 0x27, 0x82, /* .k..P.'. */ -0xcf, 0x6b, 0xdf, 0xbf, 0x01, 0x82, 0xaf, 0x6b, /* .k.....k */ -0x26, 0xf4, 0x55, 0xdb, 0x50 /* &.U.P */ + 0x42, 0xb2, 0x00, + 0x42, 0x24, 0xf8, 0x0f, 0x04, /* B..B$... */ + 0xef, 0x06, 0xaf, 0xbb, 0xef, 0x00, 0xff, 0x1a, /* ........ */ + 0x27, 0xfc, 0x9f, 0xfc, 0x97, 0x09, 0x27, 0x5f, /* '.....'_ */ + 0x02, 0x3f, 0x97, 0x06, 0x25, 0xf8, 0x55, 0x81, /* .?..%.U. */ + 0xcf, 0x24, 0xaf, 0x05, 0x27, 0x0a, 0xef, 0x73, /* .$..'..s */ + 0x43, 0x02, 0x5b, 0x73, 0xcf, 0x09, 0x27, 0x0f, /* C.[s..'. */ + 0x1c, 0x81, 0xaf, 0x73, 0xcf, 0x09, 0x27, 0x30, /* ...s..'0 */ + 0x1c, 0xfc, 0xdf, 0xcf, 0x1d, 0x5f, 0x02, 0xfc, /* ....._.. */ + 0xbf, 0x81, 0xcf, 0x10, 0xaf, 0x01, 0x2e, 0x94, /* ........ */ + 0x86, 0x80, 0x82, 0x01, 0x2e, 0x34, 0x81, 0x40, /* .....4.@ */ + 0xef, 0x6b, 0xaf, 0x80, 0xef, 0x82, 0xaf, 0x01, /* .k...... */ + 0x2e, 0xf9, 0x81, 0xed, 0x80, 0x01, 0x2e, 0x18, /* ........ */ + 0x87, 0x01, 0x2e, 0x1a, 0x87, 0x16, 0x82, 0x01, /* ........ */ + 0x2e, 0x2f, 0x89, 0x0a, 0x5b, 0x73, 0x43, 0x19, /* ./..[sC. */ + 0x5a, 0x81, 0xcf, 0x5e, 0xdf, 0xbf, 0x03, 0x15, /* Z..^.... */ + 0x5f, 0x5f, 0x20, 0x81, 0xaf, 0xdf, 0x22, 0x11, /* __ ...". */ + 0x54, 0xde, 0x50, 0x40, 0x2e, 0x8f, 0xdf, 0x1f, /* T.P@.... */ + 0x2c, 0x00, 0x2e, 0x0c, 0x5a, 0x5f, 0x2c, 0x09, /* ,...Z_,. */ + 0x5b, 0x82, 0xcf, 0x6b, 0xdf, 0x3f, 0x00, 0x82, /* [..k.?.. */ + 0xaf, 0x6b, 0x26, 0xe7, 0x54, 0x6b, 0xdf, 0x0c, /* .k&.Tk.. */ + 0x82, 0x6b, 0xbf, 0xd8, 0x50, 0x05, 0x27, 0x82, /* .k..P.'. */ + 0xcf, 0x6b, 0xdf, 0xbf, 0x01, 0x82, 0xaf, 0x6b, /* .k.....k */ + 0x26, 0xf4, 0x55, 0xdb, 0x50 /* &.U.P */ }; static const unsigned char pkt39[] = { -0x42, 0xca, 0x00, -0x9a, 0x24, 0xfa, 0xcf, 0xdf, /* B...$... */ -0x96, 0x37, 0xcf, 0xdf, 0x96, 0x08, 0xcf, 0xdf, /* .7...... */ -0x96, 0x3d, 0xcf, 0xdf, 0x96, 0x77, 0xcf, 0xdf, /* .=...w.. */ -0x96, 0x01, 0x2e, 0x08, 0x82, 0xdd, 0x97, 0x77, /* .......w */ -0xaf, 0xdd, 0x97, 0x3d, 0xaf, 0xdd, 0x97, 0x08, /* ...=.... */ -0xaf, 0xdd, 0x97, 0x37, 0xaf, 0xdd, 0x97, 0xfa, /* ...7.... */ -0xaf, 0x9f, 0x22, 0x6d, 0x2e, 0x6d, 0xbf, 0xfb, /* .."m.m.. */ -0x39, 0x08, 0x45, 0x00, 0x5a, 0xfb, 0x31, 0x0a, /* 9.E.Z.1. */ -0x42, 0x00, 0x5b, 0xa2, 0x39, 0x02, 0xcf, 0x5c, /* B.[.9..\ */ -0xaf, 0xe1, 0xef, 0x95, 0xaf, 0x9f, 0x22, 0x61, /* ......"a */ -0xaf, 0x62, 0xaf, 0x69, 0xaf, 0x6a, 0xaf, 0x16, /* .b.i.j.. */ -0xaf, 0x96, 0xaf, 0x29, 0xaf, 0x28, 0xaf, 0xc1, /* ...).(.. */ -0x2e, 0x49, 0xdf, 0x3f, 0x2d, 0x03, 0x5b, 0xa0, /* .I.?-.[. */ -0xcf, 0x8f, 0x1c, 0x20, 0x18, 0xa0, 0xaf, 0xa1, /* ... .... */ -0xcf, 0xdf, 0x1c, 0xa1, 0xaf, 0xed, 0x80, 0x02, /* ........ */ -0x47, 0x06, 0x5a, 0x0a, 0x41, 0x04, 0x5a, 0x0a, /* G.Z.A.Z. */ -0xdf, 0x30, 0x1d, 0x30, 0x1f, 0x00, 0x54, 0x01, /* .0.0..T. */ -0xef, 0x44, 0xaf, 0x09, 0xef, 0x60, 0xaf, 0xa7, /* .D...`.. */ -0xef, 0x40, 0xaf, 0x2d, 0xef, 0x41, 0xaf, 0x0a, /* .@.-.A.. */ -0x40, 0x06, 0x5a, 0x10, 0xcf, 0x27, 0xaf, 0xe2, /* @.Z..'.. */ -0x23, 0x6e, 0x23, 0x08, 0xef, 0xe3, 0xaf, 0x6f, /* #n#....o */ -0xaf, 0xe2, 0x23, 0x08, 0xef, 0xe3, 0xaf, 0x79, /* ..#....y */ -0x82, 0x4d, 0xaf, 0xdf, 0x96, 0x64, 0xdf, 0x8b, /* .M...d.. */ -0x82, 0x93, 0xbf, 0xdd, 0x97, 0x77, 0xff, 0x8b, /* .....w.. */ -0x82, 0x94, 0xbf, 0x9e, 0x23, 0xe4, 0x23, 0x9f, /* ....#.#. */ -0x22, 0x6d, 0x2e, 0x6b, 0xbf /* "m.k. */ + 0x42, 0xca, 0x00, + 0x9a, 0x24, 0xfa, 0xcf, 0xdf, /* B...$... */ + 0x96, 0x37, 0xcf, 0xdf, 0x96, 0x08, 0xcf, 0xdf, /* .7...... */ + 0x96, 0x3d, 0xcf, 0xdf, 0x96, 0x77, 0xcf, 0xdf, /* .=...w.. */ + 0x96, 0x01, 0x2e, 0x08, 0x82, 0xdd, 0x97, 0x77, /* .......w */ + 0xaf, 0xdd, 0x97, 0x3d, 0xaf, 0xdd, 0x97, 0x08, /* ...=.... */ + 0xaf, 0xdd, 0x97, 0x37, 0xaf, 0xdd, 0x97, 0xfa, /* ...7.... */ + 0xaf, 0x9f, 0x22, 0x6d, 0x2e, 0x6d, 0xbf, 0xfb, /* .."m.m.. */ + 0x39, 0x08, 0x45, 0x00, 0x5a, 0xfb, 0x31, 0x0a, /* 9.E.Z.1. */ + 0x42, 0x00, 0x5b, 0xa2, 0x39, 0x02, 0xcf, 0x5c, /* B.[.9..\ */ + 0xaf, 0xe1, 0xef, 0x95, 0xaf, 0x9f, 0x22, 0x61, /* ......"a */ + 0xaf, 0x62, 0xaf, 0x69, 0xaf, 0x6a, 0xaf, 0x16, /* .b.i.j.. */ + 0xaf, 0x96, 0xaf, 0x29, 0xaf, 0x28, 0xaf, 0xc1, /* ...).(.. */ + 0x2e, 0x49, 0xdf, 0x3f, 0x2d, 0x03, 0x5b, 0xa0, /* .I.?-.[. */ + 0xcf, 0x8f, 0x1c, 0x20, 0x18, 0xa0, 0xaf, 0xa1, /* ... .... */ + 0xcf, 0xdf, 0x1c, 0xa1, 0xaf, 0xed, 0x80, 0x02, /* ........ */ + 0x47, 0x06, 0x5a, 0x0a, 0x41, 0x04, 0x5a, 0x0a, /* G.Z.A.Z. */ + 0xdf, 0x30, 0x1d, 0x30, 0x1f, 0x00, 0x54, 0x01, /* .0.0..T. */ + 0xef, 0x44, 0xaf, 0x09, 0xef, 0x60, 0xaf, 0xa7, /* .D...`.. */ + 0xef, 0x40, 0xaf, 0x2d, 0xef, 0x41, 0xaf, 0x0a, /* .@.-.A.. */ + 0x40, 0x06, 0x5a, 0x10, 0xcf, 0x27, 0xaf, 0xe2, /* @.Z..'.. */ + 0x23, 0x6e, 0x23, 0x08, 0xef, 0xe3, 0xaf, 0x6f, /* #n#....o */ + 0xaf, 0xe2, 0x23, 0x08, 0xef, 0xe3, 0xaf, 0x79, /* ..#....y */ + 0x82, 0x4d, 0xaf, 0xdf, 0x96, 0x64, 0xdf, 0x8b, /* .M...d.. */ + 0x82, 0x93, 0xbf, 0xdd, 0x97, 0x77, 0xff, 0x8b, /* .....w.. */ + 0x82, 0x94, 0xbf, 0x9e, 0x23, 0xe4, 0x23, 0x9f, /* ....#.#. */ + 0x22, 0x6d, 0x2e, 0x6b, 0xbf /* "m.k. */ }; static const unsigned char pkt41[] = { -0x42, 0x12, 0x00, -0xfe, 0x24, 0x6d, 0x2e, 0x6a, /* B...$m.j */ -0xbf, 0x6d, 0x2e, 0x6c, 0xbf, 0xa5, 0xcf, 0xf3, /* .m.l.... */ -0x1c, 0xa5, 0xaf, 0x05, 0x27 /* ....' */ + 0x42, 0x12, 0x00, + 0xfe, 0x24, 0x6d, 0x2e, 0x6a, /* B...$m.j */ + 0xbf, 0x6d, 0x2e, 0x6c, 0xbf, 0xa5, 0xcf, 0xf3, /* .m.l.... */ + 0x1c, 0xa5, 0xaf, 0x05, 0x27 /* ....' */ }; static const unsigned char pkt43[] = { -0x42, 0xca, 0x00, -0x06, 0x25, 0xfe, 0xcf, 0x58, /* B...%..X */ -0xaf, 0xfe, 0xcf, 0xfe, 0xdf, 0x02, 0x2e, 0x9d, /* ........ */ -0x85, 0xfe, 0xcf, 0x3c, 0xaf, 0x07, 0x3d, 0x58, /* ...<..=X */ -0x40, 0x4e, 0x5a, 0x3c, 0x26, 0x4c, 0x55, 0x37, /* @NZ<&LU7 */ -0x45, 0x4a, 0x5a, 0x02, 0x2e, 0x1b, 0x86, 0x47, /* EJZ....G */ -0x5a, 0x02, 0x2e, 0xad, 0x85, 0x00, 0x2e, 0xb9, /* Z....... */ -0x8d, 0xfe, 0xef, 0x16, 0x80, 0x02, 0xcf, 0xdf, /* ........ */ -0x96, 0x61, 0xef, 0xc0, 0xaf, 0x04, 0x27, 0xc1, /* .a....'. */ -0x46, 0x04, 0x5b, 0xc0, 0x3e, 0x40, 0xef, 0xc1, /* F.[.>@.. */ -0xaf, 0x01, 0x2e, 0x8d, 0x8b, 0xd0, 0x41, 0x07, /* ......A. */ -0x5b, 0x02, 0x2e, 0x5d, 0x85, 0xf2, 0x5b, 0xae, /* [..]..[. */ -0x87, 0xdd, 0x97, 0x1f, 0x2d, 0x06, 0x5b, 0x03, /* ....-.[. */ -0x50, 0x01, 0x0c, 0x02, 0xcf, 0xc0, 0x1c, 0x01, /* P....... */ -0x55, 0x02, 0x2e, 0x40, 0x85, 0xc0, 0x23, 0x20, /* U..@..# */ -0xef, 0xc1, 0xaf, 0x00, 0x2e, 0xd8, 0x8d, 0x05, /* ........ */ -0x27, 0x9b, 0x22, 0x37, 0x45, 0x05, 0x5a, 0x41, /* '."7E.ZA */ -0x2e, 0x52, 0xdf, 0xdf, 0x2d, 0x04, 0x5b, 0x00, /* .R..-.[. */ -0x28, 0x02, 0x50, 0x3b, 0x43, 0x00, 0x5b, 0x00, /* (.P;C.[. */ -0x28, 0xd3, 0xdf, 0xc6, 0x2e, 0x15, 0xbf, 0xd3, /* (....... */ -0x3c, 0x40, 0xef, 0x09, 0x80, 0xdd, 0x97, 0xff, /* <@...... */ -0xaf, 0x00, 0x2e, 0xa7, 0x8a, 0xc6, 0x2e, 0x15, /* ........ */ -0xdf, 0x10, 0x1d, 0xd3, 0xcf, 0x3f, 0x02, 0xd3, /* .....?.. */ -0xaf, 0x05, 0x27, 0xed, 0x83, 0x07, 0x45, 0x05, /* ..'...E. */ -0x27, 0x3d, 0x23, 0x07, 0x3d, 0x02, 0xcf, 0xdf, /* '=#.=... */ -0x96, 0x02, 0x2e, 0xad, 0x85, 0x02, 0x2e, 0x96, /* ........ */ -0x85, 0xfe, 0xef, 0x16, 0x80 /* ..... */ + 0x42, 0xca, 0x00, + 0x06, 0x25, 0xfe, 0xcf, 0x58, /* B...%..X */ + 0xaf, 0xfe, 0xcf, 0xfe, 0xdf, 0x02, 0x2e, 0x9d, /* ........ */ + 0x85, 0xfe, 0xcf, 0x3c, 0xaf, 0x07, 0x3d, 0x58, /* ...<..=X */ + 0x40, 0x4e, 0x5a, 0x3c, 0x26, 0x4c, 0x55, 0x37, /* @NZ<&LU7 */ + 0x45, 0x4a, 0x5a, 0x02, 0x2e, 0x1b, 0x86, 0x47, /* EJZ....G */ + 0x5a, 0x02, 0x2e, 0xad, 0x85, 0x00, 0x2e, 0xb9, /* Z....... */ + 0x8d, 0xfe, 0xef, 0x16, 0x80, 0x02, 0xcf, 0xdf, /* ........ */ + 0x96, 0x61, 0xef, 0xc0, 0xaf, 0x04, 0x27, 0xc1, /* .a....'. */ + 0x46, 0x04, 0x5b, 0xc0, 0x3e, 0x40, 0xef, 0xc1, /* F.[.>@.. */ + 0xaf, 0x01, 0x2e, 0x8d, 0x8b, 0xd0, 0x41, 0x07, /* ......A. */ + 0x5b, 0x02, 0x2e, 0x5d, 0x85, 0xf2, 0x5b, 0xae, /* [..]..[. */ + 0x87, 0xdd, 0x97, 0x1f, 0x2d, 0x06, 0x5b, 0x03, /* ....-.[. */ + 0x50, 0x01, 0x0c, 0x02, 0xcf, 0xc0, 0x1c, 0x01, /* P....... */ + 0x55, 0x02, 0x2e, 0x40, 0x85, 0xc0, 0x23, 0x20, /* U..@..# */ + 0xef, 0xc1, 0xaf, 0x00, 0x2e, 0xd8, 0x8d, 0x05, /* ........ */ + 0x27, 0x9b, 0x22, 0x37, 0x45, 0x05, 0x5a, 0x41, /* '."7E.ZA */ + 0x2e, 0x52, 0xdf, 0xdf, 0x2d, 0x04, 0x5b, 0x00, /* .R..-.[. */ + 0x28, 0x02, 0x50, 0x3b, 0x43, 0x00, 0x5b, 0x00, /* (.P;C.[. */ + 0x28, 0xd3, 0xdf, 0xc6, 0x2e, 0x15, 0xbf, 0xd3, /* (....... */ + 0x3c, 0x40, 0xef, 0x09, 0x80, 0xdd, 0x97, 0xff, /* <@...... */ + 0xaf, 0x00, 0x2e, 0xa7, 0x8a, 0xc6, 0x2e, 0x15, /* ........ */ + 0xdf, 0x10, 0x1d, 0xd3, 0xcf, 0x3f, 0x02, 0xd3, /* .....?.. */ + 0xaf, 0x05, 0x27, 0xed, 0x83, 0x07, 0x45, 0x05, /* ..'...E. */ + 0x27, 0x3d, 0x23, 0x07, 0x3d, 0x02, 0xcf, 0xdf, /* '=#.=... */ + 0x96, 0x02, 0x2e, 0xad, 0x85, 0x02, 0x2e, 0x96, /* ........ */ + 0x85, 0xfe, 0xef, 0x16, 0x80 /* ..... */ }; static const unsigned char pkt45[] = { -0x42, 0xca, 0x00, -0x6a, 0x25, 0x05, 0xef, 0xc0, /* B..j%... */ -0xaf, 0x04, 0x27, 0xd0, 0x41, 0x03, 0x5b, 0x02, /* ..'.A.[. */ -0x2e, 0x5d, 0x85, 0xf9, 0x5b, 0xbb, 0x50, 0x27, /* .]..[.P' */ -0x82, 0x04, 0xef, 0xc1, 0xaf, 0x9b, 0x22, 0x02, /* ......". */ -0x2e, 0xd1, 0x85, 0xdd, 0x97, 0xdf, 0x22, 0x02, /* ......". */ -0x55, 0x58, 0x40, 0x02, 0x5a, 0x0b, 0x50, 0x58, /* UX@.Z.PX */ -0x40, 0x09, 0x5a, 0xdd, 0x97, 0x1f, 0x2d, 0xb3, /* @.Z...-. */ -0x5a, 0x02, 0x2e, 0x1c, 0x86, 0xb2, 0x5b, 0x9b, /* Z.....[. */ -0x22, 0x02, 0x2e, 0x4c, 0x85, 0xae, 0x50, 0x02, /* "..L..P. */ -0x2e, 0x1c, 0x86, 0xd5, 0x5b, 0x02, 0x2e, 0x40, /* ....[..@ */ -0x85, 0x58, 0x41, 0x02, 0x5b, 0x01, 0x0c, 0x02, /* .XA.[... */ -0x2e, 0x3a, 0x75, 0xcd, 0x50, 0x41, 0x2e, 0x52, /* .:u.PA.R */ -0xdf, 0xed, 0x1c, 0x04, 0x18, 0x41, 0x2e, 0x52, /* .....A.R */ -0xbf, 0x05, 0x27, 0x1a, 0x27, 0x56, 0xdf, 0x59, /* ..'.'V.Y */ -0x80, 0xdf, 0x22, 0x00, 0x54, 0x01, 0x16, 0x3f, /* ..".T..? */ -0x1e, 0x00, 0x5f, 0x3f, 0xef, 0x1f, 0x22, 0x1f, /* .._?..". */ -0x22, 0xaf, 0xdf, 0x03, 0x1d, 0x5f, 0x02, 0xaf, /* "...._.. */ -0xbf, 0x05, 0x27, 0x00, 0x2e, 0xa1, 0x8d, 0xae, /* ..'..... */ -0xdf, 0xe0, 0x19, 0xae, 0xbf, 0x57, 0x40, 0x00, /* .....W@. */ -0x5b, 0xa1, 0x32, 0x57, 0x43, 0x00, 0x5b, 0xae, /* [.2WC.[. */ -0x3f, 0xed, 0x80, 0x05, 0x27, 0x41, 0x2e, 0x52, /* ?...'A.R */ -0xdf, 0x03, 0x18, 0x41, 0x2e, 0x52, 0xbf, 0x05, /* ...A.R.. */ -0x27, 0xd3, 0xdf, 0xff, 0x96, 0x9b, 0x22, 0x02, /* '.....". */ -0x2e, 0xd1, 0x85, 0xd3, 0x3c, 0x07, 0x80, 0xdd, /* ....<... */ -0x97, 0xff, 0xaf, 0x00, 0x2e, 0xa7, 0x8a, 0xdd, /* ........ */ -0x9f, 0x10, 0x1d, 0xd3, 0xcf /* ..... */ + 0x42, 0xca, 0x00, + 0x6a, 0x25, 0x05, 0xef, 0xc0, /* B..j%... */ + 0xaf, 0x04, 0x27, 0xd0, 0x41, 0x03, 0x5b, 0x02, /* ..'.A.[. */ + 0x2e, 0x5d, 0x85, 0xf9, 0x5b, 0xbb, 0x50, 0x27, /* .]..[.P' */ + 0x82, 0x04, 0xef, 0xc1, 0xaf, 0x9b, 0x22, 0x02, /* ......". */ + 0x2e, 0xd1, 0x85, 0xdd, 0x97, 0xdf, 0x22, 0x02, /* ......". */ + 0x55, 0x58, 0x40, 0x02, 0x5a, 0x0b, 0x50, 0x58, /* UX@.Z.PX */ + 0x40, 0x09, 0x5a, 0xdd, 0x97, 0x1f, 0x2d, 0xb3, /* @.Z...-. */ + 0x5a, 0x02, 0x2e, 0x1c, 0x86, 0xb2, 0x5b, 0x9b, /* Z.....[. */ + 0x22, 0x02, 0x2e, 0x4c, 0x85, 0xae, 0x50, 0x02, /* "..L..P. */ + 0x2e, 0x1c, 0x86, 0xd5, 0x5b, 0x02, 0x2e, 0x40, /* ....[..@ */ + 0x85, 0x58, 0x41, 0x02, 0x5b, 0x01, 0x0c, 0x02, /* .XA.[... */ + 0x2e, 0x3a, 0x75, 0xcd, 0x50, 0x41, 0x2e, 0x52, /* .:u.PA.R */ + 0xdf, 0xed, 0x1c, 0x04, 0x18, 0x41, 0x2e, 0x52, /* .....A.R */ + 0xbf, 0x05, 0x27, 0x1a, 0x27, 0x56, 0xdf, 0x59, /* ..'.'V.Y */ + 0x80, 0xdf, 0x22, 0x00, 0x54, 0x01, 0x16, 0x3f, /* ..".T..? */ + 0x1e, 0x00, 0x5f, 0x3f, 0xef, 0x1f, 0x22, 0x1f, /* .._?..". */ + 0x22, 0xaf, 0xdf, 0x03, 0x1d, 0x5f, 0x02, 0xaf, /* "...._.. */ + 0xbf, 0x05, 0x27, 0x00, 0x2e, 0xa1, 0x8d, 0xae, /* ..'..... */ + 0xdf, 0xe0, 0x19, 0xae, 0xbf, 0x57, 0x40, 0x00, /* .....W@. */ + 0x5b, 0xa1, 0x32, 0x57, 0x43, 0x00, 0x5b, 0xae, /* [.2WC.[. */ + 0x3f, 0xed, 0x80, 0x05, 0x27, 0x41, 0x2e, 0x52, /* ?...'A.R */ + 0xdf, 0x03, 0x18, 0x41, 0x2e, 0x52, 0xbf, 0x05, /* ...A.R.. */ + 0x27, 0xd3, 0xdf, 0xff, 0x96, 0x9b, 0x22, 0x02, /* '.....". */ + 0x2e, 0xd1, 0x85, 0xd3, 0x3c, 0x07, 0x80, 0xdd, /* ....<... */ + 0x97, 0xff, 0xaf, 0x00, 0x2e, 0xa7, 0x8a, 0xdd, /* ........ */ + 0x9f, 0x10, 0x1d, 0xd3, 0xcf /* ..... */ }; static const unsigned char pkt47[] = { -0x42, 0xb4, 0x00, -0xce, 0x25, 0x3f, 0x02, 0xd3, /* B...%?.. */ -0xaf, 0x05, 0x27, 0x37, 0x45, 0x10, 0x5a, 0x02, /* ..'7E.Z. */ -0x2e, 0x1b, 0x86, 0x0d, 0x5a, 0x02, 0x2e, 0xad, /* ....Z... */ -0x85, 0x00, 0x2e, 0xbf, 0x8d, 0x00, 0x2e, 0xd3, /* ........ */ -0x8d, 0x41, 0x2e, 0x52, 0xdf, 0xdf, 0x2d, 0x00, /* .A.R..-. */ -0x5b, 0x00, 0x28, 0x00, 0x2e, 0xd8, 0x8d, 0x05, /* [.(..... */ -0x27, 0xf9, 0xcf, 0xdf, 0x96, 0xf9, 0x3d, 0x01, /* '.....=. */ -0x2e, 0x06, 0x82, 0x2d, 0xff, 0xa7, 0xef, 0xe1, /* ...-.... */ -0xbf, 0xe0, 0xaf, 0x09, 0xef, 0x10, 0xaf, 0x01, /* ........ */ -0x2e, 0x94, 0x86, 0xed, 0x80, 0x01, 0x2e, 0x18, /* ........ */ -0x87, 0x01, 0x2e, 0x1a, 0x87, 0x00, 0x2e, 0x16, /* ........ */ -0x82, 0x5b, 0x82, 0x00, 0x2e, 0x2d, 0x82, 0x26, /* .[...-.& */ -0x37, 0x00, 0x5a, 0x0c, 0x50, 0xff, 0x96, 0xdf, /* 7.Z.P... */ -0x96, 0x79, 0xcf, 0x7a, 0xdf, 0xff, 0x96, 0xdf, /* .y.z.... */ -0x96, 0xc2, 0x97, 0xc3, 0x9f, 0x9d, 0x01, 0x5d, /* .......] */ -0x01, 0x07, 0x53, 0xdd, 0x97, 0xdd, 0x9f, 0x79, /* ..S....y */ -0xaf, 0x7a, 0xbf, 0x3b, 0x3b, 0xdd, 0x97, 0xf9, /* .z.;;... */ -0xaf, 0x05, 0x27, 0xff, 0x22, 0x01, 0x55, 0x32, /* ..'.".U2 */ -0x1e, 0xf3, 0x5f, 0x02, 0x0c, 0x02, 0x2e, 0x0e, /* .._..... */ -0x86, 0x3b, 0x33, 0x00, 0x28, 0x05, 0x27, 0x0d, /* .;3.(.'. */ -0x27, 0x3c, 0x26, 0x07, 0x54, 0x3c, 0xcf, 0x3d, /* '<&.T<.= */ -0xdf, 0x3f, 0x20, 0x3d, 0xbf, 0xdf, 0x03, 0x01, /* .? =.... */ -0x52, 0x3d, 0x23, 0x0c, 0x27, 0x0d, 0x27 /* R=#.'.' */ + 0x42, 0xb4, 0x00, + 0xce, 0x25, 0x3f, 0x02, 0xd3, /* B...%?.. */ + 0xaf, 0x05, 0x27, 0x37, 0x45, 0x10, 0x5a, 0x02, /* ..'7E.Z. */ + 0x2e, 0x1b, 0x86, 0x0d, 0x5a, 0x02, 0x2e, 0xad, /* ....Z... */ + 0x85, 0x00, 0x2e, 0xbf, 0x8d, 0x00, 0x2e, 0xd3, /* ........ */ + 0x8d, 0x41, 0x2e, 0x52, 0xdf, 0xdf, 0x2d, 0x00, /* .A.R..-. */ + 0x5b, 0x00, 0x28, 0x00, 0x2e, 0xd8, 0x8d, 0x05, /* [.(..... */ + 0x27, 0xf9, 0xcf, 0xdf, 0x96, 0xf9, 0x3d, 0x01, /* '.....=. */ + 0x2e, 0x06, 0x82, 0x2d, 0xff, 0xa7, 0xef, 0xe1, /* ...-.... */ + 0xbf, 0xe0, 0xaf, 0x09, 0xef, 0x10, 0xaf, 0x01, /* ........ */ + 0x2e, 0x94, 0x86, 0xed, 0x80, 0x01, 0x2e, 0x18, /* ........ */ + 0x87, 0x01, 0x2e, 0x1a, 0x87, 0x00, 0x2e, 0x16, /* ........ */ + 0x82, 0x5b, 0x82, 0x00, 0x2e, 0x2d, 0x82, 0x26, /* .[...-.& */ + 0x37, 0x00, 0x5a, 0x0c, 0x50, 0xff, 0x96, 0xdf, /* 7.Z.P... */ + 0x96, 0x79, 0xcf, 0x7a, 0xdf, 0xff, 0x96, 0xdf, /* .y.z.... */ + 0x96, 0xc2, 0x97, 0xc3, 0x9f, 0x9d, 0x01, 0x5d, /* .......] */ + 0x01, 0x07, 0x53, 0xdd, 0x97, 0xdd, 0x9f, 0x79, /* ..S....y */ + 0xaf, 0x7a, 0xbf, 0x3b, 0x3b, 0xdd, 0x97, 0xf9, /* .z.;;... */ + 0xaf, 0x05, 0x27, 0xff, 0x22, 0x01, 0x55, 0x32, /* ..'.".U2 */ + 0x1e, 0xf3, 0x5f, 0x02, 0x0c, 0x02, 0x2e, 0x0e, /* .._..... */ + 0x86, 0x3b, 0x33, 0x00, 0x28, 0x05, 0x27, 0x0d, /* .;3.(.'. */ + 0x27, 0x3c, 0x26, 0x07, 0x54, 0x3c, 0xcf, 0x3d, /* '<&.T<.= */ + 0xdf, 0x3f, 0x20, 0x3d, 0xbf, 0xdf, 0x03, 0x01, /* .? =.... */ + 0x52, 0x3d, 0x23, 0x0c, 0x27, 0x0d, 0x27 /* R=#.'.' */ }; static const unsigned char pkt49[] = { -0x42, 0x1a, 0x00, -0x27, 0x26, 0x09, 0x43, 0x04, /* B..'&.C. */ -0x5b, 0x00, 0xef, 0xf8, 0xaf, 0x32, 0xef, 0xfa, /* [....2.. */ -0xaf, 0x03, 0x50, 0x01, 0xef, 0xf8, 0xaf, 0x42, /* ..P....B */ -0xef, 0xfa, 0xaf, 0x05, 0x27 /* ....' */ + 0x42, 0x1a, 0x00, + 0x27, 0x26, 0x09, 0x43, 0x04, /* B..'&.C. */ + 0x5b, 0x00, 0xef, 0xf8, 0xaf, 0x32, 0xef, 0xfa, /* [....2.. */ + 0xaf, 0x03, 0x50, 0x01, 0xef, 0xf8, 0xaf, 0x42, /* ..P....B */ + 0xef, 0xfa, 0xaf, 0x05, 0x27 /* ....' */ }; static const unsigned char pkt51[] = { -0x42, 0x26, 0x00, -0x33, 0x26, 0xd3, 0x45, 0xfd, /* B&.3&.E. */ -0x5a, 0x0f, 0x27, 0xd3, 0x45, 0xfa, 0x5a, 0x0f, /* Z.'.E.Z. */ -0x27, 0xd3, 0x45, 0xf7, 0x5a, 0x0f, 0x27, 0x41, /* '.E.Z.'A */ -0x2e, 0xa1, 0xdf, 0x9f, 0x28, 0x41, 0x2e, 0xa1, /* ....(A.. */ -0xbf, 0x02, 0x2e, 0x57, 0x80, 0x00, 0x2e, 0xcb, /* ...W.... */ -0x7a /* z */ + 0x42, 0x26, 0x00, + 0x33, 0x26, 0xd3, 0x45, 0xfd, /* B&.3&.E. */ + 0x5a, 0x0f, 0x27, 0xd3, 0x45, 0xfa, 0x5a, 0x0f, /* Z.'.E.Z. */ + 0x27, 0xd3, 0x45, 0xf7, 0x5a, 0x0f, 0x27, 0x41, /* '.E.Z.'A */ + 0x2e, 0xa1, 0xdf, 0x9f, 0x28, 0x41, 0x2e, 0xa1, /* ....(A.. */ + 0xbf, 0x02, 0x2e, 0x57, 0x80, 0x00, 0x2e, 0xcb, /* ...W.... */ + 0x7a /* z */ }; static const unsigned char pkt53[] = { -0x42, 0x4e, 0x00, -0x45, 0x26, 0x07, 0x3d, 0x02, /* BN.E&.=. */ -0x5b, 0xae, 0x87, 0xc2, 0x23, 0xd3, 0x3c, 0x02, /* [...#.<. */ -0x44, 0xdc, 0x2f, 0x43, 0x5a, 0x02, 0x45, 0xdc, /* D./CZ.E. */ -0x2f, 0xa4, 0x5b, 0x58, 0x23, 0x3c, 0x26, 0x02, /* /.[X#<&. */ -0x55, 0x02, 0x2e, 0x0e, 0x85, 0x00, 0x50, 0x09, /* U.....P. */ -0x8f, 0x07, 0x45, 0xeb, 0x5a, 0x41, 0x2e, 0x53, /* ..E.ZA.S */ -0xdf, 0xc1, 0x2e, 0x79, 0xdf, 0xff, 0x96, 0xdf, /* ...y.... */ -0x96, 0x41, 0x2e, 0x55, 0xdf, 0xc1, 0x2e, 0x78, /* .A.U...x */ -0xdf, 0x9d, 0x01, 0x5d, 0x01, 0xff, 0x22, 0x00, /* ...]..". */ -0x54, 0xff, 0xef, 0x2e, 0xaf, 0xdc, 0x2f, 0x89, /* T...../. */ -0x50 /* P */ + 0x42, 0x4e, 0x00, + 0x45, 0x26, 0x07, 0x3d, 0x02, /* BN.E&.=. */ + 0x5b, 0xae, 0x87, 0xc2, 0x23, 0xd3, 0x3c, 0x02, /* [...#.<. */ + 0x44, 0xdc, 0x2f, 0x43, 0x5a, 0x02, 0x45, 0xdc, /* D./CZ.E. */ + 0x2f, 0xa4, 0x5b, 0x58, 0x23, 0x3c, 0x26, 0x02, /* /.[X#<&. */ + 0x55, 0x02, 0x2e, 0x0e, 0x85, 0x00, 0x50, 0x09, /* U.....P. */ + 0x8f, 0x07, 0x45, 0xeb, 0x5a, 0x41, 0x2e, 0x53, /* ..E.ZA.S */ + 0xdf, 0xc1, 0x2e, 0x79, 0xdf, 0xff, 0x96, 0xdf, /* ...y.... */ + 0x96, 0x41, 0x2e, 0x55, 0xdf, 0xc1, 0x2e, 0x78, /* .A.U...x */ + 0xdf, 0x9d, 0x01, 0x5d, 0x01, 0xff, 0x22, 0x00, /* ...]..". */ + 0x54, 0xff, 0xef, 0x2e, 0xaf, 0xdc, 0x2f, 0x89, /* T...../. */ + 0x50 /* P */ }; static const unsigned char pkt55[] = { -0x42, 0x86, 0x00, -0x6b, 0x26, 0xa5, 0xcf, 0xed, /* B..k&... */ -0x2e, 0x6a, 0xdf, 0xf3, 0x1c, 0x3f, 0x02, 0xa5, /* .j...?.. */ -0xaf, 0x4a, 0xcf, 0xdf, 0x96, 0x10, 0xcf, 0x5f, /* .J....._ */ -0xdf, 0xbf, 0x03, 0x02, 0x5f, 0x5f, 0xcf, 0x10, /* ....__.. */ -0xaf, 0x04, 0x50, 0x5e, 0xdf, 0xbf, 0x03, 0x01, /* ..P^.... */ -0x53, 0x5e, 0xcf, 0x10, 0xaf, 0x01, 0x2e, 0x40, /* S^.....@ */ -0x88, 0x01, 0x2e, 0xe1, 0x86, 0xdd, 0x97, 0x0a, /* ........ */ -0x40, 0x18, 0x5a, 0x62, 0xcf, 0xdf, 0x22, 0x22, /* @.Zb.."" */ -0x54, 0xed, 0x2e, 0x6a, 0xdf, 0x10, 0xef, 0x00, /* T..j.... */ -0x1f, 0x06, 0x54, 0x0c, 0xef, 0x04, 0x1f, 0x03, /* ..T..... */ -0x54, 0x0b, 0xef, 0x08, 0x1f, 0x00, 0x54, 0x05, /* T.....T. */ -0xef, 0x62, 0xdf, 0x76, 0x80, 0x12, 0x82, 0x12, /* .b.v.... */ -0x82, 0x80, 0x10, 0x01, 0x13, 0x4a, 0xcf, 0x3f, /* .....J.? */ -0x00, 0x00, 0x53, 0xff, 0xef, 0x4a, 0xdf, 0xed, /* ..S..J.. */ -0x2e, 0x6e, 0xbf, 0x4a, 0xaf, 0x6d, 0x2e, 0x6f, /* .n.J.m.o */ -0xbf, 0xdf, 0x96, 0xbf, 0x01, 0x6d, 0x2e, 0x6d, /* .....m.m */ -0xbf, 0xdd, 0x97, 0x01, 0x2e, 0xf9, 0x81, 0x05, /* ........ */ -0x27 /* ' */ + 0x42, 0x86, 0x00, + 0x6b, 0x26, 0xa5, 0xcf, 0xed, /* B..k&... */ + 0x2e, 0x6a, 0xdf, 0xf3, 0x1c, 0x3f, 0x02, 0xa5, /* .j...?.. */ + 0xaf, 0x4a, 0xcf, 0xdf, 0x96, 0x10, 0xcf, 0x5f, /* .J....._ */ + 0xdf, 0xbf, 0x03, 0x02, 0x5f, 0x5f, 0xcf, 0x10, /* ....__.. */ + 0xaf, 0x04, 0x50, 0x5e, 0xdf, 0xbf, 0x03, 0x01, /* ..P^.... */ + 0x53, 0x5e, 0xcf, 0x10, 0xaf, 0x01, 0x2e, 0x40, /* S^.....@ */ + 0x88, 0x01, 0x2e, 0xe1, 0x86, 0xdd, 0x97, 0x0a, /* ........ */ + 0x40, 0x18, 0x5a, 0x62, 0xcf, 0xdf, 0x22, 0x22, /* @.Zb.."" */ + 0x54, 0xed, 0x2e, 0x6a, 0xdf, 0x10, 0xef, 0x00, /* T..j.... */ + 0x1f, 0x06, 0x54, 0x0c, 0xef, 0x04, 0x1f, 0x03, /* ..T..... */ + 0x54, 0x0b, 0xef, 0x08, 0x1f, 0x00, 0x54, 0x05, /* T.....T. */ + 0xef, 0x62, 0xdf, 0x76, 0x80, 0x12, 0x82, 0x12, /* .b.v.... */ + 0x82, 0x80, 0x10, 0x01, 0x13, 0x4a, 0xcf, 0x3f, /* .....J.? */ + 0x00, 0x00, 0x53, 0xff, 0xef, 0x4a, 0xdf, 0xed, /* ..S..J.. */ + 0x2e, 0x6e, 0xbf, 0x4a, 0xaf, 0x6d, 0x2e, 0x6f, /* .n.J.m.o */ + 0xbf, 0xdf, 0x96, 0xbf, 0x01, 0x6d, 0x2e, 0x6d, /* .....m.m */ + 0xbf, 0xdd, 0x97, 0x01, 0x2e, 0xf9, 0x81, 0x05, /* ........ */ + 0x27 /* ' */ }; static const unsigned char pkt57[] = { -0x42, 0x16, 0x00, -0xad, 0x26, 0xd3, 0x45, 0x02, /* B...&.E. */ -0x5a, 0xd3, 0x45, 0x00, 0x5a, 0x05, 0x27, 0xd0, /* Z.E.Z.'. */ -0x41, 0xf8, 0x5b, 0xed, 0x83, 0xf6, 0x50, 0x05, /* A.[...P. */ -0x27 /* ' */ + 0x42, 0x16, 0x00, + 0xad, 0x26, 0xd3, 0x45, 0x02, /* B...&.E. */ + 0x5a, 0xd3, 0x45, 0x00, 0x5a, 0x05, 0x27, 0xd0, /* Z.E.Z.'. */ + 0x41, 0xf8, 0x5b, 0xed, 0x83, 0xf6, 0x50, 0x05, /* A.[...P. */ + 0x27 /* ' */ }; static const unsigned char pkt59[] = { -0x42, 0xca, 0x00, -0xb7, 0x26, 0xfd, 0x0c, 0x00, /* B...&... */ -0x2e, 0x3f, 0x8a, 0x39, 0x84, 0x05, 0xcf, 0xdf, /* .?.9.... */ -0x22, 0x00, 0x2e, 0xb4, 0x55, 0x04, 0xcf, 0x14, /* "...U... */ -0x1e, 0x00, 0x2e, 0xb0, 0x55, 0x00, 0x2e, 0xf5, /* ....U... */ -0x89, 0xbb, 0xef, 0x1f, 0x90, 0x91, 0xff, 0x7f, /* ........ */ -0x90, 0x14, 0xef, 0x00, 0x2e, 0x31, 0x8a, 0x14, /* .....1.. */ -0xef, 0x00, 0x2e, 0x39, 0x8a, 0x33, 0xef, 0x1f, /* ...9.3.. */ -0x90, 0x71, 0xff, 0x7f, 0x90, 0x18, 0xef, 0x00, /* .q...... */ -0x2e, 0x31, 0x8a, 0x00, 0x2e, 0xf5, 0x89, 0x40, /* .1.....@ */ -0xef, 0xfc, 0x9f, 0x5f, 0x20, 0xfc, 0x55, 0x01, /* ..._ .U. */ -0x2e, 0x67, 0x8d, 0x01, 0x2e, 0xfe, 0x8c, 0x00, /* .g...... */ -0x2e, 0xf5, 0x89, 0x02, 0x2e, 0x7a, 0x87, 0x0a, /* .....z.. */ -0xef, 0x00, 0x2e, 0x01, 0x8a, 0x02, 0x2e, 0x7a, /* .......z */ -0x87, 0x00, 0xff, 0x80, 0xef, 0x19, 0x27, 0x0a, /* ......'. */ -0xef, 0xdc, 0x9f, 0x7f, 0x9f, 0x5f, 0x20, 0xfb, /* ....._ . */ -0x55, 0x39, 0x84, 0x02, 0x2e, 0x7a, 0x87, 0x0a, /* U9...z.. */ -0xef, 0x00, 0x2e, 0x01, 0x8a, 0x02, 0x2e, 0x7a, /* .......z */ -0x87, 0x0a, 0xef, 0xdc, 0x9f, 0x7f, 0x9f, 0x5f, /* ......._ */ -0x20, 0xfb, 0x55, 0x02, 0x2e, 0x76, 0x87, 0x02, /* .U..v.. */ -0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ -0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ -0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ -0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ -0x2e, 0x44, 0x88, 0x9d, 0xef, 0x1f, 0x90, 0xda, /* .D...... */ -0xff, 0x7f, 0x90, 0x0f, 0xef, 0x00, 0x2e, 0x31, /* .......1 */ -0x8a, 0x80, 0xef, 0x1f, 0x9f /* ..... */ + 0x42, 0xca, 0x00, + 0xb7, 0x26, 0xfd, 0x0c, 0x00, /* B...&... */ + 0x2e, 0x3f, 0x8a, 0x39, 0x84, 0x05, 0xcf, 0xdf, /* .?.9.... */ + 0x22, 0x00, 0x2e, 0xb4, 0x55, 0x04, 0xcf, 0x14, /* "...U... */ + 0x1e, 0x00, 0x2e, 0xb0, 0x55, 0x00, 0x2e, 0xf5, /* ....U... */ + 0x89, 0xbb, 0xef, 0x1f, 0x90, 0x91, 0xff, 0x7f, /* ........ */ + 0x90, 0x14, 0xef, 0x00, 0x2e, 0x31, 0x8a, 0x14, /* .....1.. */ + 0xef, 0x00, 0x2e, 0x39, 0x8a, 0x33, 0xef, 0x1f, /* ...9.3.. */ + 0x90, 0x71, 0xff, 0x7f, 0x90, 0x18, 0xef, 0x00, /* .q...... */ + 0x2e, 0x31, 0x8a, 0x00, 0x2e, 0xf5, 0x89, 0x40, /* .1.....@ */ + 0xef, 0xfc, 0x9f, 0x5f, 0x20, 0xfc, 0x55, 0x01, /* ..._ .U. */ + 0x2e, 0x67, 0x8d, 0x01, 0x2e, 0xfe, 0x8c, 0x00, /* .g...... */ + 0x2e, 0xf5, 0x89, 0x02, 0x2e, 0x7a, 0x87, 0x0a, /* .....z.. */ + 0xef, 0x00, 0x2e, 0x01, 0x8a, 0x02, 0x2e, 0x7a, /* .......z */ + 0x87, 0x00, 0xff, 0x80, 0xef, 0x19, 0x27, 0x0a, /* ......'. */ + 0xef, 0xdc, 0x9f, 0x7f, 0x9f, 0x5f, 0x20, 0xfb, /* ....._ . */ + 0x55, 0x39, 0x84, 0x02, 0x2e, 0x7a, 0x87, 0x0a, /* U9...z.. */ + 0xef, 0x00, 0x2e, 0x01, 0x8a, 0x02, 0x2e, 0x7a, /* .......z */ + 0x87, 0x0a, 0xef, 0xdc, 0x9f, 0x7f, 0x9f, 0x5f, /* ......._ */ + 0x20, 0xfb, 0x55, 0x02, 0x2e, 0x76, 0x87, 0x02, /* .U..v.. */ + 0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ + 0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ + 0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ + 0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ + 0x2e, 0x44, 0x88, 0x9d, 0xef, 0x1f, 0x90, 0xda, /* .D...... */ + 0xff, 0x7f, 0x90, 0x0f, 0xef, 0x00, 0x2e, 0x31, /* .......1 */ + 0x8a, 0x80, 0xef, 0x1f, 0x9f /* ..... */ }; static const unsigned char pkt61[] = { -0x42, 0xca, 0x00, -0x1b, 0x27, 0x9f, 0x22, 0x1f, /* B...'.". */ -0x9f, 0x1f, 0x9f, 0x1f, 0x9f, 0x1f, 0x9f, 0x1f, /* ........ */ -0x9f, 0x1f, 0x9f, 0x03, 0xef, 0x1f, 0x9f, 0xb8, /* ........ */ -0xef, 0x1f, 0x9f, 0x00, 0x2e, 0xf5, 0x89, 0x40, /* .......@ */ -0xef, 0xfc, 0x9f, 0x5f, 0x20, 0xfc, 0x55, 0x01, /* ..._ .U. */ -0x2e, 0xfe, 0x8c, 0x00, 0x2e, 0xff, 0x89, 0x02, /* ........ */ -0x2e, 0xb3, 0x87, 0x02, 0x2e, 0x44, 0x88, 0x02, /* .....D.. */ -0x2e, 0x3f, 0x88, 0x02, 0x2e, 0x44, 0x88, 0x02, /* .?...D.. */ -0x2e, 0x3f, 0x88, 0x02, 0x2e, 0x44, 0x88, 0x02, /* .?...D.. */ -0x2e, 0x3f, 0x88, 0x02, 0x2e, 0x44, 0x88, 0x02, /* .?...D.. */ -0x2e, 0x3f, 0x88, 0x02, 0x2e, 0x44, 0x88, 0x02, /* .?...D.. */ -0x2e, 0xb3, 0x87, 0x14, 0xef, 0xfc, 0x9f, 0x5f, /* ......._ */ -0x20, 0xfc, 0x55, 0x01, 0xff, 0xab, 0xef, 0x19, /* .U..... */ -0x27, 0x02, 0x2e, 0xb3, 0x87, 0x11, 0xff, 0xbf, /* '....... */ -0x90, 0x51, 0xff, 0xc2, 0x97, 0xdf, 0x01, 0x7f, /* .Q...... */ -0x98, 0xfc, 0x9f, 0xbf, 0x98, 0x24, 0x28, 0xc2, /* .....$(. */ -0x9f, 0x7f, 0x20, 0xbf, 0x90, 0xf4, 0x55, 0x24, /* .. ...U$ */ -0x2a, 0x02, 0x2e, 0x7e, 0x87, 0x72, 0xef, 0xff, /* *..~.r.. */ -0xaf, 0x14, 0xef, 0xff, 0xaf, 0x00, 0xef, 0xff, /* ........ */ -0xaf, 0x00, 0xff, 0x80, 0xef, 0x19, 0x27, 0x14, /* ......'. */ -0xff, 0xfd, 0x97, 0xff, 0xaf, 0x7f, 0x20, 0xfb, /* ...... . */ -0x55, 0x00, 0x2e, 0xa9, 0x8a, 0x03, 0x0c, 0xd0, /* U....... */ -0xef, 0x07, 0xff, 0xa9, 0x80, 0x05, 0x27, 0x58, /* ......'X */ -0x85, 0x05, 0x27, 0x40, 0xef, 0x2d, 0xff, 0x1a, /* ..'@.-.. */ -0x27, 0x05, 0x27, 0x02, 0xef, 0x06, 0xff, 0x1a, /* '.'..... */ -0x27, 0x05, 0x27, 0x01, 0xff /* '.'.. */ + 0x42, 0xca, 0x00, + 0x1b, 0x27, 0x9f, 0x22, 0x1f, /* B...'.". */ + 0x9f, 0x1f, 0x9f, 0x1f, 0x9f, 0x1f, 0x9f, 0x1f, /* ........ */ + 0x9f, 0x1f, 0x9f, 0x03, 0xef, 0x1f, 0x9f, 0xb8, /* ........ */ + 0xef, 0x1f, 0x9f, 0x00, 0x2e, 0xf5, 0x89, 0x40, /* .......@ */ + 0xef, 0xfc, 0x9f, 0x5f, 0x20, 0xfc, 0x55, 0x01, /* ..._ .U. */ + 0x2e, 0xfe, 0x8c, 0x00, 0x2e, 0xff, 0x89, 0x02, /* ........ */ + 0x2e, 0xb3, 0x87, 0x02, 0x2e, 0x44, 0x88, 0x02, /* .....D.. */ + 0x2e, 0x3f, 0x88, 0x02, 0x2e, 0x44, 0x88, 0x02, /* .?...D.. */ + 0x2e, 0x3f, 0x88, 0x02, 0x2e, 0x44, 0x88, 0x02, /* .?...D.. */ + 0x2e, 0x3f, 0x88, 0x02, 0x2e, 0x44, 0x88, 0x02, /* .?...D.. */ + 0x2e, 0x3f, 0x88, 0x02, 0x2e, 0x44, 0x88, 0x02, /* .?...D.. */ + 0x2e, 0xb3, 0x87, 0x14, 0xef, 0xfc, 0x9f, 0x5f, /* ......._ */ + 0x20, 0xfc, 0x55, 0x01, 0xff, 0xab, 0xef, 0x19, /* .U..... */ + 0x27, 0x02, 0x2e, 0xb3, 0x87, 0x11, 0xff, 0xbf, /* '....... */ + 0x90, 0x51, 0xff, 0xc2, 0x97, 0xdf, 0x01, 0x7f, /* .Q...... */ + 0x98, 0xfc, 0x9f, 0xbf, 0x98, 0x24, 0x28, 0xc2, /* .....$(. */ + 0x9f, 0x7f, 0x20, 0xbf, 0x90, 0xf4, 0x55, 0x24, /* .. ...U$ */ + 0x2a, 0x02, 0x2e, 0x7e, 0x87, 0x72, 0xef, 0xff, /* *..~.r.. */ + 0xaf, 0x14, 0xef, 0xff, 0xaf, 0x00, 0xef, 0xff, /* ........ */ + 0xaf, 0x00, 0xff, 0x80, 0xef, 0x19, 0x27, 0x14, /* ......'. */ + 0xff, 0xfd, 0x97, 0xff, 0xaf, 0x7f, 0x20, 0xfb, /* ...... . */ + 0x55, 0x00, 0x2e, 0xa9, 0x8a, 0x03, 0x0c, 0xd0, /* U....... */ + 0xef, 0x07, 0xff, 0xa9, 0x80, 0x05, 0x27, 0x58, /* ......'X */ + 0x85, 0x05, 0x27, 0x40, 0xef, 0x2d, 0xff, 0x1a, /* ..'@.-.. */ + 0x27, 0x05, 0x27, 0x02, 0xef, 0x06, 0xff, 0x1a, /* '.'..... */ + 0x27, 0x05, 0x27, 0x01, 0xff /* '.'.. */ }; static const unsigned char pkt63[] = { -0x42, 0x72, 0x00, -0x7f, 0x27, 0xab, 0xef, 0x19, /* Br..'... */ -0x27, 0x08, 0xef, 0x1f, 0x98, 0xe4, 0x29, 0x00, /* '.....). */ -0xff, 0xff, 0x96, 0x20, 0xff, 0xff, 0x96, 0x00, /* ... .... */ -0xff, 0xff, 0x96, 0x40, 0xff, 0xff, 0x96, 0x00, /* ...@.... */ -0xff, 0xff, 0x96, 0x60, 0xff, 0xff, 0x96, 0x00, /* ...`.... */ -0xff, 0xff, 0x96, 0x00, 0xff, 0xff, 0x96, 0x01, /* ........ */ -0xff, 0xff, 0x96, 0x20, 0xff, 0xff, 0x96, 0x00, /* ... .... */ -0xff, 0xff, 0x96, 0x02, 0xff, 0xff, 0x96, 0x02, /* ........ */ -0xff, 0xff, 0x96, 0x82, 0xff, 0xff, 0x96, 0x02, /* ........ */ -0xff, 0xff, 0x96, 0x02, 0x2e, 0xaa, 0x87, 0x46, /* .......F */ -0x2e, 0x01, 0xdf, 0x9f, 0x28, 0x46, 0x2e, 0x01, /* ....(F.. */ -0xbf, 0x05, 0x27, 0x0f, 0xef, 0x5f, 0x98, 0xdd, /* ..'.._.. */ -0x9f, 0xbf, 0x98, 0x24, 0x28, 0x5f, 0x20, 0xf9, /* ...$(_ . */ -0x55, 0x24, 0x2a, 0x05, 0x27, 0x7f, 0xef, 0x2d, /* U$*.'..- */ -0xff, 0x1b, 0x27, 0x05, 0x27 /* ..'.' */ + 0x42, 0x72, 0x00, + 0x7f, 0x27, 0xab, 0xef, 0x19, /* Br..'... */ + 0x27, 0x08, 0xef, 0x1f, 0x98, 0xe4, 0x29, 0x00, /* '.....). */ + 0xff, 0xff, 0x96, 0x20, 0xff, 0xff, 0x96, 0x00, /* ... .... */ + 0xff, 0xff, 0x96, 0x40, 0xff, 0xff, 0x96, 0x00, /* ...@.... */ + 0xff, 0xff, 0x96, 0x60, 0xff, 0xff, 0x96, 0x00, /* ...`.... */ + 0xff, 0xff, 0x96, 0x00, 0xff, 0xff, 0x96, 0x01, /* ........ */ + 0xff, 0xff, 0x96, 0x20, 0xff, 0xff, 0x96, 0x00, /* ... .... */ + 0xff, 0xff, 0x96, 0x02, 0xff, 0xff, 0x96, 0x02, /* ........ */ + 0xff, 0xff, 0x96, 0x82, 0xff, 0xff, 0x96, 0x02, /* ........ */ + 0xff, 0xff, 0x96, 0x02, 0x2e, 0xaa, 0x87, 0x46, /* .......F */ + 0x2e, 0x01, 0xdf, 0x9f, 0x28, 0x46, 0x2e, 0x01, /* ....(F.. */ + 0xbf, 0x05, 0x27, 0x0f, 0xef, 0x5f, 0x98, 0xdd, /* ..'.._.. */ + 0x9f, 0xbf, 0x98, 0x24, 0x28, 0x5f, 0x20, 0xf9, /* ...$(_ . */ + 0x55, 0x24, 0x2a, 0x05, 0x27, 0x7f, 0xef, 0x2d, /* U$*.'..- */ + 0xff, 0x1b, 0x27, 0x05, 0x27 /* ..'.' */ }; static const unsigned char pkt65[] = { -0x42, 0xca, 0x00, -0xb7, 0x27, 0x00, 0x2e, 0x3f, /* B...'..? */ -0x8a, 0x23, 0x81, 0x02, 0x2e, 0x4d, 0x88, 0x05, /* .#...M.. */ -0xcf, 0xdf, 0x22, 0x35, 0x55, 0x04, 0xcf, 0x2a, /* .."5U..* */ -0x1e, 0x32, 0x55, 0xfe, 0xdf, 0xfe, 0xcf, 0x00, /* .2U..... */ -0x1f, 0x1d, 0x55, 0x00, 0x1e, 0x0e, 0x54, 0xc6, /* ..U...T. */ -0x2e, 0x00, 0xdf, 0x3f, 0x20, 0xbf, 0x03, 0x16, /* ...? ... */ -0x55, 0xc6, 0x2e, 0x01, 0xdf, 0x3f, 0x2c, 0x12, /* U....?,. */ -0x5b, 0x46, 0x2e, 0x00, 0xbf, 0x00, 0x2e, 0x25, /* [F.....% */ -0x8a, 0x02, 0x2e, 0xe1, 0x77, 0x00, 0xef, 0x46, /* ....w..F */ -0x2e, 0x00, 0xbf, 0x46, 0x2e, 0x01, 0xdf, 0x1f, /* ...F.... */ -0x28, 0x46, 0x2e, 0x01, 0xbf, 0x00, 0x2e, 0x06, /* (F...... */ -0x8a, 0x02, 0x2e, 0xf7, 0x87, 0x05, 0x27, 0x46, /* ......'F */ -0x2e, 0x01, 0xdf, 0x1f, 0x2a, 0x46, 0x2e, 0x01, /* ....*F.. */ -0xbf, 0x41, 0x2e, 0xb6, 0xdf, 0x01, 0xff, 0xab, /* .A...... */ -0xef, 0x19, 0x27, 0x42, 0xff, 0x7f, 0x98, 0x9f, /* ..'B.... */ -0x98, 0x24, 0x28, 0x56, 0x85, 0x24, 0x2a, 0x05, /* .$(V.$*. */ -0x27, 0x58, 0x85, 0x05, 0x27, 0xfd, 0x0c, 0x00, /* 'X..'... */ -0x2e, 0xf5, 0x89, 0x14, 0xef, 0x00, 0x2e, 0x39, /* .......9 */ -0x8a, 0x02, 0x2e, 0x3b, 0x88, 0x02, 0x2e, 0x44, /* ...;...D */ -0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, 0x2e, 0x44, /* ...?...D */ -0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, 0x2e, 0x44, /* ...?...D */ -0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, 0x2e, 0x44, /* ...?...D */ -0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, 0x2e, 0x44, /* ...?...D */ -0x88, 0x46, 0x2e, 0x00, 0xdf, 0x1f, 0x9f, 0xe2, /* .F...... */ -0xef, 0x1f, 0x90, 0xe0, 0xff, 0x7f, 0x90, 0x0e, /* ........ */ -0xef, 0x00, 0x2e, 0x31, 0x8a /* ...1. */ + 0x42, 0xca, 0x00, + 0xb7, 0x27, 0x00, 0x2e, 0x3f, /* B...'..? */ + 0x8a, 0x23, 0x81, 0x02, 0x2e, 0x4d, 0x88, 0x05, /* .#...M.. */ + 0xcf, 0xdf, 0x22, 0x35, 0x55, 0x04, 0xcf, 0x2a, /* .."5U..* */ + 0x1e, 0x32, 0x55, 0xfe, 0xdf, 0xfe, 0xcf, 0x00, /* .2U..... */ + 0x1f, 0x1d, 0x55, 0x00, 0x1e, 0x0e, 0x54, 0xc6, /* ..U...T. */ + 0x2e, 0x00, 0xdf, 0x3f, 0x20, 0xbf, 0x03, 0x16, /* ...? ... */ + 0x55, 0xc6, 0x2e, 0x01, 0xdf, 0x3f, 0x2c, 0x12, /* U....?,. */ + 0x5b, 0x46, 0x2e, 0x00, 0xbf, 0x00, 0x2e, 0x25, /* [F.....% */ + 0x8a, 0x02, 0x2e, 0xe1, 0x77, 0x00, 0xef, 0x46, /* ....w..F */ + 0x2e, 0x00, 0xbf, 0x46, 0x2e, 0x01, 0xdf, 0x1f, /* ...F.... */ + 0x28, 0x46, 0x2e, 0x01, 0xbf, 0x00, 0x2e, 0x06, /* (F...... */ + 0x8a, 0x02, 0x2e, 0xf7, 0x87, 0x05, 0x27, 0x46, /* ......'F */ + 0x2e, 0x01, 0xdf, 0x1f, 0x2a, 0x46, 0x2e, 0x01, /* ....*F.. */ + 0xbf, 0x41, 0x2e, 0xb6, 0xdf, 0x01, 0xff, 0xab, /* .A...... */ + 0xef, 0x19, 0x27, 0x42, 0xff, 0x7f, 0x98, 0x9f, /* ..'B.... */ + 0x98, 0x24, 0x28, 0x56, 0x85, 0x24, 0x2a, 0x05, /* .$(V.$*. */ + 0x27, 0x58, 0x85, 0x05, 0x27, 0xfd, 0x0c, 0x00, /* 'X..'... */ + 0x2e, 0xf5, 0x89, 0x14, 0xef, 0x00, 0x2e, 0x39, /* .......9 */ + 0x8a, 0x02, 0x2e, 0x3b, 0x88, 0x02, 0x2e, 0x44, /* ...;...D */ + 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, 0x2e, 0x44, /* ...?...D */ + 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, 0x2e, 0x44, /* ...?...D */ + 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, 0x2e, 0x44, /* ...?...D */ + 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, 0x2e, 0x44, /* ...?...D */ + 0x88, 0x46, 0x2e, 0x00, 0xdf, 0x1f, 0x9f, 0xe2, /* .F...... */ + 0xef, 0x1f, 0x90, 0xe0, 0xff, 0x7f, 0x90, 0x0e, /* ........ */ + 0xef, 0x00, 0x2e, 0x31, 0x8a /* ...1. */ }; static const unsigned char pkt67[] = { -0x42, 0xca, 0x00, -0x1b, 0x28, 0x80, 0xef, 0x1f, /* B...(... */ -0x9f, 0x9f, 0x22, 0x1f, 0x9f, 0x1f, 0x9f, 0x1f, /* .."..... */ -0x9f, 0x1f, 0x9f, 0x1f, 0x9f, 0x1f, 0x9f, 0x01, /* ........ */ -0xef, 0x1f, 0x9f, 0xb8, 0xef, 0x1f, 0x9f, 0x00, /* ........ */ -0x2e, 0xf5, 0x89, 0x40, 0xef, 0xfc, 0x9f, 0x5f, /* ...@..._ */ -0x20, 0xfc, 0x55, 0x03, 0x0c, 0x01, 0x2e, 0x67, /* .U....g */ -0x8d, 0x01, 0x2e, 0xfe, 0x8c, 0x00, 0x2e, 0xff, /* ........ */ -0x89, 0x00, 0x2e, 0xfb, 0x89, 0x14, 0xef, 0x00, /* ........ */ -0x2e, 0x01, 0x8a, 0x05, 0x27, 0x40, 0xef, 0x2d, /* ....'@.- */ -0xff, 0x1a, 0x27, 0x05, 0x27, 0x16, 0x27, 0x04, /* ..'.'.'. */ -0x10, 0x00, 0x13, 0x1a, 0x27, 0x05, 0x27, 0xd9, /* ....'.'. */ -0x9f, 0x3f, 0x9f, 0xd8, 0x9f, 0x3f, 0x9f, 0xd7, /* .?...?.. */ -0x9f, 0x3f, 0x9f, 0xd6, 0x9f, 0x3f, 0x9f, 0x05, /* .?...?.. */ -0x27, 0x7f, 0xef, 0x2d, 0xff, 0x46, 0x2e, 0x1d, /* '..-.F.. */ -0xbf, 0xc6, 0x2e, 0x1c, 0xbf, 0x93, 0xef, 0x2d, /* .......- */ -0xff, 0x46, 0x2e, 0x1f, 0xbf, 0xc6, 0x2e, 0x1e, /* .F...... */ -0xbf, 0x05, 0x27, 0x00, 0x2e, 0x3f, 0x8a, 0x23, /* ..'..?.# */ -0x81, 0x02, 0x2e, 0x4d, 0x88, 0x02, 0x2e, 0x60, /* ...M...` */ -0x89, 0x08, 0xef, 0xfe, 0xdf, 0x3f, 0x9f, 0x5f, /* .....?._ */ -0x20, 0xfb, 0x55, 0x28, 0xef, 0xfe, 0xdf, 0x5f, /* .U(..._ */ -0x20, 0xfc, 0x55, 0x00, 0x2e, 0xf5, 0x89, 0xfe, /* .U..... */ -0xdf, 0x00, 0x2e, 0xf5, 0x89, 0x14, 0xff, 0xfe, /* ........ */ -0xcf, 0x1f, 0x9f, 0x7f, 0x20, 0xfb, 0x55, 0x23, /* .... .U# */ -0xff, 0xfe, 0xcf, 0x7f, 0x20, 0xfc, 0x55, 0x02, /* .... .U. */ -0x2e, 0x64, 0x89, 0x00, 0x2e, 0xf5, 0x89, 0x14, /* .d...... */ -0xff, 0xfc, 0x97, 0x1f, 0x97 /* ..... */ + 0x42, 0xca, 0x00, + 0x1b, 0x28, 0x80, 0xef, 0x1f, /* B...(... */ + 0x9f, 0x9f, 0x22, 0x1f, 0x9f, 0x1f, 0x9f, 0x1f, /* .."..... */ + 0x9f, 0x1f, 0x9f, 0x1f, 0x9f, 0x1f, 0x9f, 0x01, /* ........ */ + 0xef, 0x1f, 0x9f, 0xb8, 0xef, 0x1f, 0x9f, 0x00, /* ........ */ + 0x2e, 0xf5, 0x89, 0x40, 0xef, 0xfc, 0x9f, 0x5f, /* ...@..._ */ + 0x20, 0xfc, 0x55, 0x03, 0x0c, 0x01, 0x2e, 0x67, /* .U....g */ + 0x8d, 0x01, 0x2e, 0xfe, 0x8c, 0x00, 0x2e, 0xff, /* ........ */ + 0x89, 0x00, 0x2e, 0xfb, 0x89, 0x14, 0xef, 0x00, /* ........ */ + 0x2e, 0x01, 0x8a, 0x05, 0x27, 0x40, 0xef, 0x2d, /* ....'@.- */ + 0xff, 0x1a, 0x27, 0x05, 0x27, 0x16, 0x27, 0x04, /* ..'.'.'. */ + 0x10, 0x00, 0x13, 0x1a, 0x27, 0x05, 0x27, 0xd9, /* ....'.'. */ + 0x9f, 0x3f, 0x9f, 0xd8, 0x9f, 0x3f, 0x9f, 0xd7, /* .?...?.. */ + 0x9f, 0x3f, 0x9f, 0xd6, 0x9f, 0x3f, 0x9f, 0x05, /* .?...?.. */ + 0x27, 0x7f, 0xef, 0x2d, 0xff, 0x46, 0x2e, 0x1d, /* '..-.F.. */ + 0xbf, 0xc6, 0x2e, 0x1c, 0xbf, 0x93, 0xef, 0x2d, /* .......- */ + 0xff, 0x46, 0x2e, 0x1f, 0xbf, 0xc6, 0x2e, 0x1e, /* .F...... */ + 0xbf, 0x05, 0x27, 0x00, 0x2e, 0x3f, 0x8a, 0x23, /* ..'..?.# */ + 0x81, 0x02, 0x2e, 0x4d, 0x88, 0x02, 0x2e, 0x60, /* ...M...` */ + 0x89, 0x08, 0xef, 0xfe, 0xdf, 0x3f, 0x9f, 0x5f, /* .....?._ */ + 0x20, 0xfb, 0x55, 0x28, 0xef, 0xfe, 0xdf, 0x5f, /* .U(..._ */ + 0x20, 0xfc, 0x55, 0x00, 0x2e, 0xf5, 0x89, 0xfe, /* .U..... */ + 0xdf, 0x00, 0x2e, 0xf5, 0x89, 0x14, 0xff, 0xfe, /* ........ */ + 0xcf, 0x1f, 0x9f, 0x7f, 0x20, 0xfb, 0x55, 0x23, /* .... .U# */ + 0xff, 0xfe, 0xcf, 0x7f, 0x20, 0xfc, 0x55, 0x02, /* .... .U. */ + 0x2e, 0x64, 0x89, 0x00, 0x2e, 0xf5, 0x89, 0x14, /* .d...... */ + 0xff, 0xfc, 0x97, 0x1f, 0x97 /* ..... */ }; static const unsigned char pkt69[] = { -0x42, 0xca, 0x00, -0x7f, 0x28, 0x7f, 0x20, 0xfb, /* B...(. . */ -0x55, 0x2c, 0xef, 0xbf, 0x22, 0x3f, 0x9f, 0x5f, /* U,.."?._ */ -0x20, 0xfc, 0x55, 0x00, 0x2e, 0xf5, 0x89, 0x40, /* .U....@ */ -0xef, 0xf6, 0x9f, 0x36, 0x1b, 0x3f, 0x9f, 0x5f, /* ...6.?._ */ -0x20, 0xfa, 0x55, 0x01, 0x2e, 0x67, 0x8d, 0x01, /* .U..g.. */ -0x2e, 0xfe, 0x8c, 0x00, 0x2e, 0xf5, 0x89, 0x02, /* ........ */ -0x2e, 0x5c, 0x89, 0xdc, 0x9f, 0x3f, 0x9f, 0xdc, /* .\...?.. */ -0x9f, 0x3f, 0x9f, 0xdc, 0x9f, 0x3f, 0x9f, 0xdc, /* .?...?.. */ -0x9f, 0x3f, 0x9f, 0xdc, 0x9f, 0x3f, 0x9f, 0xdc, /* .?...?.. */ -0x9f, 0x3f, 0x9f, 0xdc, 0x9f, 0x3f, 0x9f, 0xdc, /* .?...?.. */ -0x9f, 0x3f, 0x9f, 0x80, 0xff, 0x3f, 0x9f, 0x2f, /* .?...?./ */ -0xef, 0xbf, 0x22, 0x3f, 0x9f, 0x5f, 0x20, 0xfc, /* .."?._ . */ -0x55, 0x3f, 0x9f, 0x3f, 0x9f, 0x3f, 0x9f, 0x3f, /* U?.?.?.? */ -0x9f, 0x3f, 0x9f, 0x3f, 0x9f, 0x02, 0xff, 0x3f, /* .?.?...? */ -0x9f, 0x40, 0xff, 0x3f, 0x9f, 0x00, 0x2e, 0xf5, /* .@.?.... */ -0x89, 0x40, 0xef, 0xfc, 0x9f, 0x5f, 0x20, 0xfc, /* .@..._ . */ -0x55, 0x01, 0x2e, 0xfe, 0x8c, 0x00, 0x2e, 0xff, /* U....... */ -0x89, 0x00, 0x2e, 0xf5, 0x89, 0x14, 0xef, 0x00, /* ........ */ -0x2e, 0x01, 0x8a, 0x46, 0x2e, 0x18, 0xdf, 0xc6, /* ...F.... */ -0x2e, 0x17, 0xdf, 0x1a, 0x27, 0x02, 0x2e, 0x68, /* ....'..h */ -0x89, 0x14, 0xef, 0xfc, 0x9f, 0x5c, 0x1b, 0x3f, /* .....\.? */ -0x97, 0x5f, 0x20, 0xfa, 0x55, 0x2c, 0xef, 0x5c, /* ._ .U,.\ */ -0xff, 0x3f, 0x97, 0x5f, 0x20, 0xfc, 0x55, 0x00, /* .?._ .U. */ -0x2e, 0xff, 0x89, 0x02, 0x2e, 0x68, 0x89, 0x02, /* .....h.. */ -0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ -0x2e, 0x44, 0x88, 0x02, 0x2e /* .D... */ + 0x42, 0xca, 0x00, + 0x7f, 0x28, 0x7f, 0x20, 0xfb, /* B...(. . */ + 0x55, 0x2c, 0xef, 0xbf, 0x22, 0x3f, 0x9f, 0x5f, /* U,.."?._ */ + 0x20, 0xfc, 0x55, 0x00, 0x2e, 0xf5, 0x89, 0x40, /* .U....@ */ + 0xef, 0xf6, 0x9f, 0x36, 0x1b, 0x3f, 0x9f, 0x5f, /* ...6.?._ */ + 0x20, 0xfa, 0x55, 0x01, 0x2e, 0x67, 0x8d, 0x01, /* .U..g.. */ + 0x2e, 0xfe, 0x8c, 0x00, 0x2e, 0xf5, 0x89, 0x02, /* ........ */ + 0x2e, 0x5c, 0x89, 0xdc, 0x9f, 0x3f, 0x9f, 0xdc, /* .\...?.. */ + 0x9f, 0x3f, 0x9f, 0xdc, 0x9f, 0x3f, 0x9f, 0xdc, /* .?...?.. */ + 0x9f, 0x3f, 0x9f, 0xdc, 0x9f, 0x3f, 0x9f, 0xdc, /* .?...?.. */ + 0x9f, 0x3f, 0x9f, 0xdc, 0x9f, 0x3f, 0x9f, 0xdc, /* .?...?.. */ + 0x9f, 0x3f, 0x9f, 0x80, 0xff, 0x3f, 0x9f, 0x2f, /* .?...?./ */ + 0xef, 0xbf, 0x22, 0x3f, 0x9f, 0x5f, 0x20, 0xfc, /* .."?._ . */ + 0x55, 0x3f, 0x9f, 0x3f, 0x9f, 0x3f, 0x9f, 0x3f, /* U?.?.?.? */ + 0x9f, 0x3f, 0x9f, 0x3f, 0x9f, 0x02, 0xff, 0x3f, /* .?.?...? */ + 0x9f, 0x40, 0xff, 0x3f, 0x9f, 0x00, 0x2e, 0xf5, /* .@.?.... */ + 0x89, 0x40, 0xef, 0xfc, 0x9f, 0x5f, 0x20, 0xfc, /* .@..._ . */ + 0x55, 0x01, 0x2e, 0xfe, 0x8c, 0x00, 0x2e, 0xff, /* U....... */ + 0x89, 0x00, 0x2e, 0xf5, 0x89, 0x14, 0xef, 0x00, /* ........ */ + 0x2e, 0x01, 0x8a, 0x46, 0x2e, 0x18, 0xdf, 0xc6, /* ...F.... */ + 0x2e, 0x17, 0xdf, 0x1a, 0x27, 0x02, 0x2e, 0x68, /* ....'..h */ + 0x89, 0x14, 0xef, 0xfc, 0x9f, 0x5c, 0x1b, 0x3f, /* .....\.? */ + 0x97, 0x5f, 0x20, 0xfa, 0x55, 0x2c, 0xef, 0x5c, /* ._ .U,.\ */ + 0xff, 0x3f, 0x97, 0x5f, 0x20, 0xfc, 0x55, 0x00, /* .?._ .U. */ + 0x2e, 0xff, 0x89, 0x02, 0x2e, 0x68, 0x89, 0x02, /* .....h.. */ + 0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ + 0x2e, 0x44, 0x88, 0x02, 0x2e /* .D... */ }; static const unsigned char pkt71[] = { -0x42, 0xca, 0x00, -0xe3, 0x28, 0x3f, 0x88, 0x02, /* B...(?.. */ -0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ -0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ -0x2e, 0x44, 0x88, 0x00, 0x2e, 0xf5, 0x89, 0x40, /* .D.....@ */ -0xef, 0xfc, 0x9f, 0x5f, 0x20, 0xfc, 0x55, 0x01, /* ..._ .U. */ -0x2e, 0x67, 0x8d, 0x01, 0x2e, 0xfe, 0x8c, 0x46, /* .g.....F */ -0x2e, 0x18, 0xdf, 0xc6, 0x2e, 0x17, 0xdf, 0x1a, /* ........ */ -0x27, 0x02, 0x2e, 0x68, 0x89, 0x14, 0xef, 0xfc, /* '..h.... */ -0x9f, 0x3f, 0x97, 0x5f, 0x20, 0xfb, 0x55, 0x80, /* .?._ .U. */ -0xff, 0x3f, 0x97, 0x23, 0xef, 0xbf, 0x22, 0x3f, /* .?.#.."? */ -0x97, 0x5f, 0x20, 0xfc, 0x55, 0x3f, 0x97, 0x3f, /* ._ .U?.? */ -0x97, 0x3f, 0x97, 0x3f, 0x97, 0x3f, 0x97, 0x3f, /* .?.?.?.? */ -0x97, 0x02, 0xff, 0x3f, 0x97, 0xa0, 0xff, 0x3f, /* ...?...? */ -0x97, 0x00, 0x2e, 0xf5, 0x89, 0x40, 0xef, 0xfc, /* .....@.. */ -0x9f, 0x5f, 0x20, 0xfc, 0x55, 0x01, 0x2e, 0xfe, /* ._ .U... */ -0x8c, 0x00, 0x2e, 0xff, 0x89, 0x00, 0x2e, 0xf5, /* ........ */ -0x89, 0x14, 0xef, 0x00, 0x2e, 0x01, 0x8a, 0x00, /* ........ */ -0x2e, 0xff, 0x89, 0x02, 0x2e, 0x68, 0x89, 0x02, /* .....h.. */ -0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ -0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ -0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ -0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ -0x2e, 0x44, 0x88, 0x17, 0x27, 0x5f, 0x20, 0x1b, /* .D..'_ . */ -0x27, 0xf6, 0x97, 0x0f, 0x1c, 0x54, 0x10, 0x2d, /* '....T.- */ -0xff, 0x1b, 0x27, 0x73, 0xef, 0xff, 0xaf, 0x84, /* ..'s.... */ -0xef, 0xff, 0xaf, 0x00, 0xef /* ..... */ + 0x42, 0xca, 0x00, + 0xe3, 0x28, 0x3f, 0x88, 0x02, /* B...(?.. */ + 0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ + 0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ + 0x2e, 0x44, 0x88, 0x00, 0x2e, 0xf5, 0x89, 0x40, /* .D.....@ */ + 0xef, 0xfc, 0x9f, 0x5f, 0x20, 0xfc, 0x55, 0x01, /* ..._ .U. */ + 0x2e, 0x67, 0x8d, 0x01, 0x2e, 0xfe, 0x8c, 0x46, /* .g.....F */ + 0x2e, 0x18, 0xdf, 0xc6, 0x2e, 0x17, 0xdf, 0x1a, /* ........ */ + 0x27, 0x02, 0x2e, 0x68, 0x89, 0x14, 0xef, 0xfc, /* '..h.... */ + 0x9f, 0x3f, 0x97, 0x5f, 0x20, 0xfb, 0x55, 0x80, /* .?._ .U. */ + 0xff, 0x3f, 0x97, 0x23, 0xef, 0xbf, 0x22, 0x3f, /* .?.#.."? */ + 0x97, 0x5f, 0x20, 0xfc, 0x55, 0x3f, 0x97, 0x3f, /* ._ .U?.? */ + 0x97, 0x3f, 0x97, 0x3f, 0x97, 0x3f, 0x97, 0x3f, /* .?.?.?.? */ + 0x97, 0x02, 0xff, 0x3f, 0x97, 0xa0, 0xff, 0x3f, /* ...?...? */ + 0x97, 0x00, 0x2e, 0xf5, 0x89, 0x40, 0xef, 0xfc, /* .....@.. */ + 0x9f, 0x5f, 0x20, 0xfc, 0x55, 0x01, 0x2e, 0xfe, /* ._ .U... */ + 0x8c, 0x00, 0x2e, 0xff, 0x89, 0x00, 0x2e, 0xf5, /* ........ */ + 0x89, 0x14, 0xef, 0x00, 0x2e, 0x01, 0x8a, 0x00, /* ........ */ + 0x2e, 0xff, 0x89, 0x02, 0x2e, 0x68, 0x89, 0x02, /* .....h.. */ + 0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ + 0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ + 0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ + 0x2e, 0x44, 0x88, 0x02, 0x2e, 0x3f, 0x88, 0x02, /* .D...?.. */ + 0x2e, 0x44, 0x88, 0x17, 0x27, 0x5f, 0x20, 0x1b, /* .D..'_ . */ + 0x27, 0xf6, 0x97, 0x0f, 0x1c, 0x54, 0x10, 0x2d, /* '....T.- */ + 0xff, 0x1b, 0x27, 0x73, 0xef, 0xff, 0xaf, 0x84, /* ..'s.... */ + 0xef, 0xff, 0xaf, 0x00, 0xef /* ..... */ }; static const unsigned char pkt73[] = { -0x42, 0x4c, 0x00, -0x47, 0x29, 0xff, 0xaf, 0xfc, /* BL.G)... */ -0x97, 0xff, 0xaf, 0xfc, 0x97, 0xff, 0xaf, 0xfc, /* ........ */ -0x97, 0xff, 0xaf, 0xfc, 0x97, 0xff, 0xaf, 0x80, /* ........ */ -0xef, 0xfe, 0xdf, 0xff, 0xbf, 0x5f, 0x20, 0xfb, /* ....._ . */ -0x55, 0x10, 0xef, 0xfe, 0xdf, 0x5f, 0x20, 0xfc, /* U...._ . */ -0x55, 0x00, 0x2e, 0xa9, 0x8a, 0x05, 0x27, 0x69, /* U.....'i */ -0xef, 0x2d, 0xff, 0x1a, 0x27, 0x05, 0x27, 0x69, /* .-..'.'i */ -0xef, 0x2d, 0xff, 0x1b, 0x27, 0x05, 0x27, 0x54, /* .-..'.'T */ -0xef, 0x2d, 0xff, 0x1a, 0x27, 0x05, 0x27, 0x54, /* .-..'.'T */ -0xef, 0x2d, 0xff, 0x1b, 0x27, 0x05, 0x27 /* .-..'.' */ + 0x42, 0x4c, 0x00, + 0x47, 0x29, 0xff, 0xaf, 0xfc, /* BL.G)... */ + 0x97, 0xff, 0xaf, 0xfc, 0x97, 0xff, 0xaf, 0xfc, /* ........ */ + 0x97, 0xff, 0xaf, 0xfc, 0x97, 0xff, 0xaf, 0x80, /* ........ */ + 0xef, 0xfe, 0xdf, 0xff, 0xbf, 0x5f, 0x20, 0xfb, /* ....._ . */ + 0x55, 0x10, 0xef, 0xfe, 0xdf, 0x5f, 0x20, 0xfc, /* U...._ . */ + 0x55, 0x00, 0x2e, 0xa9, 0x8a, 0x05, 0x27, 0x69, /* U.....'i */ + 0xef, 0x2d, 0xff, 0x1a, 0x27, 0x05, 0x27, 0x69, /* .-..'.'i */ + 0xef, 0x2d, 0xff, 0x1b, 0x27, 0x05, 0x27, 0x54, /* .-..'.'T */ + 0xef, 0x2d, 0xff, 0x1a, 0x27, 0x05, 0x27, 0x54, /* .-..'.'T */ + 0xef, 0x2d, 0xff, 0x1b, 0x27, 0x05, 0x27 /* .-..'.' */ }; static const unsigned char pkt75[] = { -0x67, 0x05, 0x00, 0x00, 0x02, 0x2e, 0x00, 0x70, /* g......p */ -0x67, 0x05, 0x00, 0x02, 0x02, 0x2e, 0x87, 0x70, /* g......p */ -0x67, 0x05, 0x00, 0x01, 0x02, 0x2e, 0x6f, 0x72, /* g.....or */ -0x67, 0x05, 0x00, 0x03, 0x02, 0x2e, 0x7a, 0x73, /* g.....zs */ -0x67, 0x05, 0x00, 0x08, 0x02, 0x2e, 0x9a, 0x74, /* g......t */ -0x67, 0x05, 0x00, 0x07, 0x02, 0x2e, 0x06, 0x75, /* g......u */ -0x5a, 0x05, 0x00, 0x00, 0x55, 0x01, 0x27, 0x26, /* Z...U.'& */ -0x5a, 0x05, 0x00, 0x01, 0xc4, 0x0a, 0x33, 0x26, /* Z.....3& */ -0x5a, 0x05, 0x00, 0x02, 0xd9, 0x02, 0x45, 0x26, /* Z.....E& */ -0x5a, 0x05, 0x00, 0x03, 0x94, 0x16, 0x6b, 0x26, /* Z.....k& */ -0x5a, 0x05, 0x00, 0x04, 0xcc, 0x0a, 0xad, 0x26, /* Z......& */ -0x5a, 0x05, 0x00, 0x05, 0x3e, 0x0a, 0xb7, 0x26, /* Z...>..& */ -0x5a, 0x05, 0x00, 0x06, 0xf4, 0x09, 0xb7, 0x27, /* Z......' */ -0x0d, -0x42, 0x04, 0x00, -0x47, 0x29, 0xff, 0xaf /* .B..G).. */ + 0x67, 0x05, 0x00, 0x00, 0x02, 0x2e, 0x00, 0x70, /* g......p */ + 0x67, 0x05, 0x00, 0x02, 0x02, 0x2e, 0x87, 0x70, /* g......p */ + 0x67, 0x05, 0x00, 0x01, 0x02, 0x2e, 0x6f, 0x72, /* g.....or */ + 0x67, 0x05, 0x00, 0x03, 0x02, 0x2e, 0x7a, 0x73, /* g.....zs */ + 0x67, 0x05, 0x00, 0x08, 0x02, 0x2e, 0x9a, 0x74, /* g......t */ + 0x67, 0x05, 0x00, 0x07, 0x02, 0x2e, 0x06, 0x75, /* g......u */ + 0x5a, 0x05, 0x00, 0x00, 0x55, 0x01, 0x27, 0x26, /* Z...U.'& */ + 0x5a, 0x05, 0x00, 0x01, 0xc4, 0x0a, 0x33, 0x26, /* Z.....3& */ + 0x5a, 0x05, 0x00, 0x02, 0xd9, 0x02, 0x45, 0x26, /* Z.....E& */ + 0x5a, 0x05, 0x00, 0x03, 0x94, 0x16, 0x6b, 0x26, /* Z.....k& */ + 0x5a, 0x05, 0x00, 0x04, 0xcc, 0x0a, 0xad, 0x26, /* Z......& */ + 0x5a, 0x05, 0x00, 0x05, 0x3e, 0x0a, 0xb7, 0x26, /* Z...>..& */ + 0x5a, 0x05, 0x00, 0x06, 0xf4, 0x09, 0xb7, 0x27, /* Z......' */ + 0x0d, + 0x42, 0x04, 0x00, + 0x47, 0x29, 0xff, 0xaf /* .B..G).. */ }; /* INIT1 is over, 0x07 cmd returns * { 0x07, 0x05, 0x00, 0x91, 0x26, 0x21, 0x00, 0x3a } */ struct aesX660_cmd aes2660_init_1[] = { - { .cmd = pkt13, .len = sizeof(pkt13) }, - { .cmd = pkt15, .len = sizeof(pkt15) }, - { .cmd = pkt17, .len = sizeof(pkt17) }, - { .cmd = pkt19, .len = sizeof(pkt19) }, - { .cmd = pkt21, .len = sizeof(pkt21) }, - { .cmd = pkt23, .len = sizeof(pkt23) }, - { .cmd = pkt25, .len = sizeof(pkt25) }, - { .cmd = pkt27, .len = sizeof(pkt27) }, - { .cmd = pkt29, .len = sizeof(pkt29) }, - { .cmd = pkt31, .len = sizeof(pkt31) }, - { .cmd = pkt33, .len = sizeof(pkt33) }, - { .cmd = pkt35, .len = sizeof(pkt35) }, - { .cmd = pkt37, .len = sizeof(pkt37) }, - { .cmd = pkt39, .len = sizeof(pkt39) }, - { .cmd = pkt41, .len = sizeof(pkt41) }, - { .cmd = pkt43, .len = sizeof(pkt43) }, - { .cmd = pkt45, .len = sizeof(pkt45) }, - { .cmd = pkt47, .len = sizeof(pkt47) }, - { .cmd = pkt49, .len = sizeof(pkt49) }, - { .cmd = pkt51, .len = sizeof(pkt51) }, - { .cmd = pkt53, .len = sizeof(pkt53) }, - { .cmd = pkt55, .len = sizeof(pkt55) }, - { .cmd = pkt57, .len = sizeof(pkt57) }, - { .cmd = pkt59, .len = sizeof(pkt59) }, - { .cmd = pkt61, .len = sizeof(pkt61) }, - { .cmd = pkt63, .len = sizeof(pkt63) }, - { .cmd = pkt65, .len = sizeof(pkt65) }, - { .cmd = pkt67, .len = sizeof(pkt67) }, - { .cmd = pkt69, .len = sizeof(pkt69) }, - { .cmd = pkt71, .len = sizeof(pkt71) }, - { .cmd = pkt73, .len = sizeof(pkt73) }, - { .cmd = pkt75, .len = sizeof(pkt75) }, + { .cmd = pkt13, .len = sizeof (pkt13) }, + { .cmd = pkt15, .len = sizeof (pkt15) }, + { .cmd = pkt17, .len = sizeof (pkt17) }, + { .cmd = pkt19, .len = sizeof (pkt19) }, + { .cmd = pkt21, .len = sizeof (pkt21) }, + { .cmd = pkt23, .len = sizeof (pkt23) }, + { .cmd = pkt25, .len = sizeof (pkt25) }, + { .cmd = pkt27, .len = sizeof (pkt27) }, + { .cmd = pkt29, .len = sizeof (pkt29) }, + { .cmd = pkt31, .len = sizeof (pkt31) }, + { .cmd = pkt33, .len = sizeof (pkt33) }, + { .cmd = pkt35, .len = sizeof (pkt35) }, + { .cmd = pkt37, .len = sizeof (pkt37) }, + { .cmd = pkt39, .len = sizeof (pkt39) }, + { .cmd = pkt41, .len = sizeof (pkt41) }, + { .cmd = pkt43, .len = sizeof (pkt43) }, + { .cmd = pkt45, .len = sizeof (pkt45) }, + { .cmd = pkt47, .len = sizeof (pkt47) }, + { .cmd = pkt49, .len = sizeof (pkt49) }, + { .cmd = pkt51, .len = sizeof (pkt51) }, + { .cmd = pkt53, .len = sizeof (pkt53) }, + { .cmd = pkt55, .len = sizeof (pkt55) }, + { .cmd = pkt57, .len = sizeof (pkt57) }, + { .cmd = pkt59, .len = sizeof (pkt59) }, + { .cmd = pkt61, .len = sizeof (pkt61) }, + { .cmd = pkt63, .len = sizeof (pkt63) }, + { .cmd = pkt65, .len = sizeof (pkt65) }, + { .cmd = pkt67, .len = sizeof (pkt67) }, + { .cmd = pkt69, .len = sizeof (pkt69) }, + { .cmd = pkt71, .len = sizeof (pkt71) }, + { .cmd = pkt73, .len = sizeof (pkt73) }, + { .cmd = pkt75, .len = sizeof (pkt75) }, }; /* Second init sequence * INIT2 */ static const unsigned char pkt187[] = { -0x0d, -0x23, -0x42, 0xca, 0x00, -0x00, 0x20, 0x7f, /* .#B... . */ -0x97, 0x37, 0xcf, 0xdf, 0x96, 0x26, 0xcf, 0xdf, /* .7...&.. */ -0x96, 0xff, 0x96, 0x9f, 0x22, 0x6d, 0x2e, 0x6a, /* ...."m.j */ -0xbf, 0x62, 0x23, 0x23, 0x83, 0xdd, 0x97, 0x26, /* .b##...& */ -0xaf, 0xdd, 0x97, 0x37, 0xaf, 0xa9, 0xcf, 0x70, /* ...7...p */ -0x18, 0xa9, 0xaf, 0x02, 0xef, 0x5d, 0xaf, 0xc5, /* .....].. */ -0xef, 0x2f, 0xff, 0xff, 0x96, 0xdf, 0x96, 0x6a, /* ./.....j */ -0xef, 0x20, 0xff, 0xff, 0x96, 0xdf, 0x96, 0x1a, /* . ...... */ -0x27, 0x0b, 0xef, 0x06, 0xaf, 0xf1, 0x81, 0x3a, /* '......: */ -0xff, 0x3f, 0x1d, 0x40, 0x19, 0xc1, 0x2e, 0xa3, /* .?.@.... */ -0xbf, 0xc2, 0x2e, 0x00, 0xdf, 0xff, 0x2d, 0x02, /* ......-. */ -0x5a, 0xbf, 0x22, 0xc1, 0x2e, 0xa3, 0xbf, 0x3c, /* Z."....< */ -0x23, 0x57, 0x23, 0x02, 0x2e, 0x31, 0x80, 0x05, /* #W#..1.. */ -0x27, 0x12, 0xef, 0x99, 0xaf, 0x10, 0xef, 0x9b, /* '....... */ -0xaf, 0x10, 0xef, 0x55, 0xaf, 0x3d, 0x23, 0x31, /* ...U.=#1 */ -0xef, 0x20, 0xff, 0x1a, 0x27, 0x05, 0xef, 0x27, /* . ..'..' */ -0xff, 0x06, 0x27, 0x05, 0x27, 0x3f, 0x80, 0x2b, /* ..'.'?.+ */ -0x0d, 0x05, 0x27, 0xe5, 0x31, 0x05, 0x81, 0xe5, /* ..'.1... */ -0x39, 0x05, 0x27, 0xc8, 0x46, 0x0e, 0x5b, 0xd3, /* 9.'.F.[. */ -0x45, 0xfd, 0x5a, 0x0f, 0x27, 0xd3, 0x45, 0xfa, /* E.Z.'.E. */ -0x5a, 0x0f, 0x27, 0xd3, 0x45, 0xf7, 0x5a, 0x41, /* Z.'.E.ZA */ -0x2e, 0xa1, 0xdf, 0x9f, 0x28, 0x41, 0x2e, 0xa1, /* ....(A.. */ -0xbf, 0x02, 0x2e, 0x58, 0x80, 0x05, 0x27, 0x9f, /* ...X..'. */ -0x22, 0xbf, 0x22, 0x1f, 0x20, 0xfd, 0x53, 0x3f, /* ".". .S? */ -0x20, 0x14, 0x1f, 0xfa, 0x55, 0x05, 0x27, 0x10, /* ...U.'. */ -0xef, 0xd0, 0x81, 0x65, 0xaf, 0x10, 0xef /* ...e... */ + 0x0d, + 0x23, + 0x42, 0xca, 0x00, + 0x00, 0x20, 0x7f, /* .#B... . */ + 0x97, 0x37, 0xcf, 0xdf, 0x96, 0x26, 0xcf, 0xdf, /* .7...&.. */ + 0x96, 0xff, 0x96, 0x9f, 0x22, 0x6d, 0x2e, 0x6a, /* ...."m.j */ + 0xbf, 0x62, 0x23, 0x23, 0x83, 0xdd, 0x97, 0x26, /* .b##...& */ + 0xaf, 0xdd, 0x97, 0x37, 0xaf, 0xa9, 0xcf, 0x70, /* ...7...p */ + 0x18, 0xa9, 0xaf, 0x02, 0xef, 0x5d, 0xaf, 0xc5, /* .....].. */ + 0xef, 0x2f, 0xff, 0xff, 0x96, 0xdf, 0x96, 0x6a, /* ./.....j */ + 0xef, 0x20, 0xff, 0xff, 0x96, 0xdf, 0x96, 0x1a, /* . ...... */ + 0x27, 0x0b, 0xef, 0x06, 0xaf, 0xf1, 0x81, 0x3a, /* '......: */ + 0xff, 0x3f, 0x1d, 0x40, 0x19, 0xc1, 0x2e, 0xa3, /* .?.@.... */ + 0xbf, 0xc2, 0x2e, 0x00, 0xdf, 0xff, 0x2d, 0x02, /* ......-. */ + 0x5a, 0xbf, 0x22, 0xc1, 0x2e, 0xa3, 0xbf, 0x3c, /* Z."....< */ + 0x23, 0x57, 0x23, 0x02, 0x2e, 0x31, 0x80, 0x05, /* #W#..1.. */ + 0x27, 0x12, 0xef, 0x99, 0xaf, 0x10, 0xef, 0x9b, /* '....... */ + 0xaf, 0x10, 0xef, 0x55, 0xaf, 0x3d, 0x23, 0x31, /* ...U.=#1 */ + 0xef, 0x20, 0xff, 0x1a, 0x27, 0x05, 0xef, 0x27, /* . ..'..' */ + 0xff, 0x06, 0x27, 0x05, 0x27, 0x3f, 0x80, 0x2b, /* ..'.'?.+ */ + 0x0d, 0x05, 0x27, 0xe5, 0x31, 0x05, 0x81, 0xe5, /* ..'.1... */ + 0x39, 0x05, 0x27, 0xc8, 0x46, 0x0e, 0x5b, 0xd3, /* 9.'.F.[. */ + 0x45, 0xfd, 0x5a, 0x0f, 0x27, 0xd3, 0x45, 0xfa, /* E.Z.'.E. */ + 0x5a, 0x0f, 0x27, 0xd3, 0x45, 0xf7, 0x5a, 0x41, /* Z.'.E.ZA */ + 0x2e, 0xa1, 0xdf, 0x9f, 0x28, 0x41, 0x2e, 0xa1, /* ....(A.. */ + 0xbf, 0x02, 0x2e, 0x58, 0x80, 0x05, 0x27, 0x9f, /* ...X..'. */ + 0x22, 0xbf, 0x22, 0x1f, 0x20, 0xfd, 0x53, 0x3f, /* ".". .S? */ + 0x20, 0x14, 0x1f, 0xfa, 0x55, 0x05, 0x27, 0x10, /* ...U.'. */ + 0xef, 0xd0, 0x81, 0x65, 0xaf, 0x10, 0xef /* ...e... */ }; static const unsigned char pkt189[] = { -0x42, 0x4a, 0x00, -0x64, 0x20, 0xd0, 0x81, 0x9c, /* BJ.d ... */ -0xaf, 0x10, 0xef, 0xd0, 0x81, 0x9a, 0xaf, 0x05, /* ........ */ -0x27, 0x11, 0x00, 0x51, 0x87, 0x91, 0x81, 0xd1, /* '..Q.... */ -0x6c, 0xd2, 0x75, 0xe2, 0x80, 0xf2, 0x80, 0xf0, /* l.u..... */ -0x57, 0xf4, 0x7b, 0xf8, 0x7e, 0xfc, 0x8b, 0x10, /* W.{.~... */ -0xcf, 0x7d, 0xff, 0x3f, 0x00, 0x20, 0xff, 0x00, /* .}.?. .. */ -0x13, 0x1a, 0x27, 0x07, 0x27, 0x05, 0x27, 0x01, /* ..'.'.'. */ -0x00, 0x11, 0x00, 0x21, 0x00, 0x31, 0x00, 0x31, /* ...!.1.1 */ -0x01, 0x32, 0x01, 0x33, 0x01, 0x33, 0x03, 0x43, /* .2.3.3.C */ -0x03, 0x53, 0x03, 0x63, 0x03 /* .S.c. */ + 0x42, 0x4a, 0x00, + 0x64, 0x20, 0xd0, 0x81, 0x9c, /* BJ.d ... */ + 0xaf, 0x10, 0xef, 0xd0, 0x81, 0x9a, 0xaf, 0x05, /* ........ */ + 0x27, 0x11, 0x00, 0x51, 0x87, 0x91, 0x81, 0xd1, /* '..Q.... */ + 0x6c, 0xd2, 0x75, 0xe2, 0x80, 0xf2, 0x80, 0xf0, /* l.u..... */ + 0x57, 0xf4, 0x7b, 0xf8, 0x7e, 0xfc, 0x8b, 0x10, /* W.{.~... */ + 0xcf, 0x7d, 0xff, 0x3f, 0x00, 0x20, 0xff, 0x00, /* .}.?. .. */ + 0x13, 0x1a, 0x27, 0x07, 0x27, 0x05, 0x27, 0x01, /* ..'.'.'. */ + 0x00, 0x11, 0x00, 0x21, 0x00, 0x31, 0x00, 0x31, /* ...!.1.1 */ + 0x01, 0x32, 0x01, 0x33, 0x01, 0x33, 0x03, 0x43, /* .2.3.3.C */ + 0x03, 0x53, 0x03, 0x63, 0x03 /* .S.c. */ }; static const unsigned char pkt191[] = { -0x42, 0xca, 0x00, -0x88, 0x20, 0x51, 0x85, 0x44, /* B... Q.D */ -0x1e, 0x03, 0x55, 0xc8, 0x46, 0x01, 0x5b, 0xe4, /* ..U.F.[. */ -0x2f, 0xc8, 0x50, 0x49, 0x1e, 0x16, 0x55, 0x37, /* /.PI..U7 */ -0x39, 0x0f, 0x27, 0x02, 0xef, 0x02, 0x2e, 0x2f, /* 9.'..../ */ -0x81, 0xfe, 0xcf, 0x08, 0xaf, 0xfe, 0xcf, 0x09, /* ........ */ -0xaf, 0xfe, 0xcf, 0x0b, 0xaf, 0x55, 0x81, 0x02, /* .....U.. */ -0xcf, 0x0f, 0x1c, 0x40, 0x18, 0x08, 0x42, 0x00, /* ...@..B. */ -0x5b, 0x20, 0x18, 0x3d, 0x23, 0x02, 0xaf, 0x10, /* [ .=#... */ -0xef, 0x55, 0xaf, 0x05, 0x27, 0x4a, 0x1e, 0x01, /* .U..'J.. */ -0x55, 0xe4, 0x2f, 0xab, 0x50, 0x4e, 0x1e, 0x01, /* U./.PN.. */ -0x55, 0x00, 0x2e, 0x0d, 0x7b, 0x55, 0x1e, 0x16, /* U...{U.. */ -0x55, 0x54, 0x85, 0xe4, 0x2f, 0xa2, 0x5b, 0x07, /* UT../.[. */ -0xef, 0x20, 0x80, 0xe4, 0x2f, 0x9e, 0x5a, 0xfe, /* . ../.Z. */ -0xcf, 0x0a, 0xaf, 0xfe, 0xcf, 0xfe, 0xcf, 0x41, /* .......A */ -0x2e, 0x44, 0xbf, 0xfe, 0xcf, 0x41, 0x2e, 0x45, /* .D...A.E */ -0xbf, 0xfe, 0xcf, 0x52, 0xaf, 0xfe, 0xcf, 0x53, /* ...R...S */ -0xaf, 0xfe, 0xcf, 0x5a, 0xaf, 0x05, 0x27, 0x58, /* ...Z..'X */ -0x1e, 0x0d, 0x55, 0x02, 0x44, 0x01, 0x5a, 0x00, /* ..U.D.Z. */ -0x2e, 0x54, 0x79, 0xfe, 0xcf, 0x75, 0xaf, 0xfe, /* .Ty..u.. */ -0xdf, 0x76, 0xbf, 0x41, 0x2e, 0xa4, 0xdf, 0xdf, /* .v.A.... */ -0x29, 0x41, 0x2e, 0xa4, 0xbf, 0x05, 0x27, 0x59, /* )A....'Y */ -0x1e, 0x03, 0x55, 0xfe, 0xcf, 0x10, 0xaf, 0x01, /* ..U..... */ -0x2e, 0x94, 0x76, 0x63, 0x1e, 0x1a, 0x55, 0x54, /* ..vc..UT */ -0x85, 0xe4, 0x2f, 0x73, 0x5b, 0x0c, 0xef, 0x20, /* ../s[.. */ -0x80, 0xe4, 0x2f, 0x6f, 0x5a, 0xf0, 0xef, 0x00, /* ../oZ... */ -0xff, 0x19, 0x27, 0x08, 0xef /* ..'.. */ + 0x42, 0xca, 0x00, + 0x88, 0x20, 0x51, 0x85, 0x44, /* B... Q.D */ + 0x1e, 0x03, 0x55, 0xc8, 0x46, 0x01, 0x5b, 0xe4, /* ..U.F.[. */ + 0x2f, 0xc8, 0x50, 0x49, 0x1e, 0x16, 0x55, 0x37, /* /.PI..U7 */ + 0x39, 0x0f, 0x27, 0x02, 0xef, 0x02, 0x2e, 0x2f, /* 9.'..../ */ + 0x81, 0xfe, 0xcf, 0x08, 0xaf, 0xfe, 0xcf, 0x09, /* ........ */ + 0xaf, 0xfe, 0xcf, 0x0b, 0xaf, 0x55, 0x81, 0x02, /* .....U.. */ + 0xcf, 0x0f, 0x1c, 0x40, 0x18, 0x08, 0x42, 0x00, /* ...@..B. */ + 0x5b, 0x20, 0x18, 0x3d, 0x23, 0x02, 0xaf, 0x10, /* [ .=#... */ + 0xef, 0x55, 0xaf, 0x05, 0x27, 0x4a, 0x1e, 0x01, /* .U..'J.. */ + 0x55, 0xe4, 0x2f, 0xab, 0x50, 0x4e, 0x1e, 0x01, /* U./.PN.. */ + 0x55, 0x00, 0x2e, 0x0d, 0x7b, 0x55, 0x1e, 0x16, /* U...{U.. */ + 0x55, 0x54, 0x85, 0xe4, 0x2f, 0xa2, 0x5b, 0x07, /* UT../.[. */ + 0xef, 0x20, 0x80, 0xe4, 0x2f, 0x9e, 0x5a, 0xfe, /* . ../.Z. */ + 0xcf, 0x0a, 0xaf, 0xfe, 0xcf, 0xfe, 0xcf, 0x41, /* .......A */ + 0x2e, 0x44, 0xbf, 0xfe, 0xcf, 0x41, 0x2e, 0x45, /* .D...A.E */ + 0xbf, 0xfe, 0xcf, 0x52, 0xaf, 0xfe, 0xcf, 0x53, /* ...R...S */ + 0xaf, 0xfe, 0xcf, 0x5a, 0xaf, 0x05, 0x27, 0x58, /* ...Z..'X */ + 0x1e, 0x0d, 0x55, 0x02, 0x44, 0x01, 0x5a, 0x00, /* ..U.D.Z. */ + 0x2e, 0x54, 0x79, 0xfe, 0xcf, 0x75, 0xaf, 0xfe, /* .Ty..u.. */ + 0xdf, 0x76, 0xbf, 0x41, 0x2e, 0xa4, 0xdf, 0xdf, /* .v.A.... */ + 0x29, 0x41, 0x2e, 0xa4, 0xbf, 0x05, 0x27, 0x59, /* )A....'Y */ + 0x1e, 0x03, 0x55, 0xfe, 0xcf, 0x10, 0xaf, 0x01, /* ..U..... */ + 0x2e, 0x94, 0x76, 0x63, 0x1e, 0x1a, 0x55, 0x54, /* ..vc..UT */ + 0x85, 0xe4, 0x2f, 0x73, 0x5b, 0x0c, 0xef, 0x20, /* ../s[.. */ + 0x80, 0xe4, 0x2f, 0x6f, 0x5a, 0xf0, 0xef, 0x00, /* ../oZ... */ + 0xff, 0x19, 0x27, 0x08, 0xef /* ..'.. */ }; static const unsigned char pkt193[] = { -0x42, 0xa2, 0x00, -0xec, 0x20, 0x06, 0xaf, 0xfe, /* B... ... */ -0xcf, 0x5f, 0x9f, 0x06, 0x25, 0xfb, 0x55, 0xfe, /* ._..%.U. */ -0xcf, 0xfe, 0xcf, 0x41, 0x2e, 0x40, 0xbf, 0xfe, /* ...A.@.. */ -0xcf, 0x41, 0x2e, 0x41, 0xbf, 0xfe, 0xcf, 0x41, /* .A.A...A */ -0x2e, 0x42, 0xbf, 0x05, 0x27, 0x66, 0x1e, 0x0b, /* .B..'f.. */ -0x55, 0xc5, 0xef, 0x2f, 0xff, 0x1a, 0x27, 0x0b, /* U../..'. */ -0xef, 0x06, 0xaf, 0xfe, 0xcf, 0xfe, 0xdf, 0x06, /* ........ */ -0x27, 0x01, 0x0e, 0x06, 0x25, 0xf9, 0x55, 0x05, /* '...%.U. */ -0x27, 0x7d, 0x1e, 0x0c, 0x55, 0x02, 0x2e, 0x29, /* '}..U..) */ -0x81, 0xe4, 0x2f, 0x47, 0x5a, 0xfe, 0xcf, 0xfe, /* ../GZ... */ -0xdf, 0x1b, 0x27, 0xfe, 0xcf, 0x36, 0x03, 0xfe, /* ..'..6.. */ -0xdf, 0x3f, 0x02, 0x9f, 0x9d, 0x05, 0x27, 0x7e, /* .?....'~ */ -0x1e, 0x0c, 0x55, 0x02, 0x2e, 0x29, 0x81, 0xe4, /* ..U..).. */ -0x2f, 0x38, 0x5a, 0xfe, 0xcf, 0xfe, 0xdf, 0x1b, /* /8Z..... */ -0x27, 0x07, 0x80, 0xf6, 0x97, 0xff, 0xaf, 0x00, /* '....... */ -0x2e, 0xa7, 0x8a, 0x05, 0x27, 0x61, 0x74, 0xff, /* ....'at. */ -0x96, 0xc6, 0x2e, 0x01, 0xdf, 0x3f, 0x2c, 0xdd, /* .....?,. */ -0x9f, 0x05, 0x27, 0xf9, 0x35, 0xc1, 0x2e, 0x4e, /* ..'.5..N */ -0xdf, 0x0f, 0x1d, 0x09, 0x27, 0x5f, 0x02, 0xc1, /* ....'_.. */ -0x2e, 0x4e, 0xbf, 0x05, 0x27, 0x9f, 0x22, 0x02, /* .N..'.". */ -0x2e, 0xe7, 0x8c, 0x05, 0x27 /* ....' */ + 0x42, 0xa2, 0x00, + 0xec, 0x20, 0x06, 0xaf, 0xfe, /* B... ... */ + 0xcf, 0x5f, 0x9f, 0x06, 0x25, 0xfb, 0x55, 0xfe, /* ._..%.U. */ + 0xcf, 0xfe, 0xcf, 0x41, 0x2e, 0x40, 0xbf, 0xfe, /* ...A.@.. */ + 0xcf, 0x41, 0x2e, 0x41, 0xbf, 0xfe, 0xcf, 0x41, /* .A.A...A */ + 0x2e, 0x42, 0xbf, 0x05, 0x27, 0x66, 0x1e, 0x0b, /* .B..'f.. */ + 0x55, 0xc5, 0xef, 0x2f, 0xff, 0x1a, 0x27, 0x0b, /* U../..'. */ + 0xef, 0x06, 0xaf, 0xfe, 0xcf, 0xfe, 0xdf, 0x06, /* ........ */ + 0x27, 0x01, 0x0e, 0x06, 0x25, 0xf9, 0x55, 0x05, /* '...%.U. */ + 0x27, 0x7d, 0x1e, 0x0c, 0x55, 0x02, 0x2e, 0x29, /* '}..U..) */ + 0x81, 0xe4, 0x2f, 0x47, 0x5a, 0xfe, 0xcf, 0xfe, /* ../GZ... */ + 0xdf, 0x1b, 0x27, 0xfe, 0xcf, 0x36, 0x03, 0xfe, /* ..'..6.. */ + 0xdf, 0x3f, 0x02, 0x9f, 0x9d, 0x05, 0x27, 0x7e, /* .?....'~ */ + 0x1e, 0x0c, 0x55, 0x02, 0x2e, 0x29, 0x81, 0xe4, /* ..U..).. */ + 0x2f, 0x38, 0x5a, 0xfe, 0xcf, 0xfe, 0xdf, 0x1b, /* /8Z..... */ + 0x27, 0x07, 0x80, 0xf6, 0x97, 0xff, 0xaf, 0x00, /* '....... */ + 0x2e, 0xa7, 0x8a, 0x05, 0x27, 0x61, 0x74, 0xff, /* ....'at. */ + 0x96, 0xc6, 0x2e, 0x01, 0xdf, 0x3f, 0x2c, 0xdd, /* .....?,. */ + 0x9f, 0x05, 0x27, 0xf9, 0x35, 0xc1, 0x2e, 0x4e, /* ..'.5..N */ + 0xdf, 0x0f, 0x1d, 0x09, 0x27, 0x5f, 0x02, 0xc1, /* ....'_.. */ + 0x2e, 0x4e, 0xbf, 0x05, 0x27, 0x9f, 0x22, 0x02, /* .N..'.". */ + 0x2e, 0xe7, 0x8c, 0x05, 0x27 /* ....' */ }; static const unsigned char pkt195[] = { -0x42, 0xca, 0x00, -0x3c, 0x21, 0x51, 0x85, 0x01, /* B...Z. */ -0x27, 0x2d, 0x82, 0x40, 0x82, 0x12, 0x82, 0x12, /* '-.@.... */ -0x82, 0x9d, 0xbf, 0xff, 0x97, 0x08, 0x10, 0x09, /* ........ */ -0x27, 0x0f, 0x1c, 0x5c, 0x46, 0x03, 0x5b, 0x02, /* '..\F.[. */ -0x1e, 0x04, 0x53, 0x02, 0xef, 0x02, 0x50, 0x03, /* ..S...P. */ -0x1e, 0x00, 0x53, 0x03, 0xef, 0x69, 0xaf, 0x3f, /* ..S..i.? */ -0x80, 0x1b, 0x0d, 0xe1, 0x97, 0x0f, 0x1c, 0x69, /* .......i */ -0xdf, 0xdf, 0x01, 0x00, 0x53, 0x00, 0xff, 0xe0, /* ....S... */ -0x97, 0x76, 0x80, 0x04, 0x10, 0x07, 0x82, 0x0f, /* .v...... */ -0x1e, 0x00, 0x5f, 0x0f, 0xef, 0x6a, 0xaf, 0xc1, /* .._..j.. */ -0x2e, 0x47, 0xdf, 0xf0, 0x1d, 0x5f, 0x02, 0xc1, /* .G..._.. */ -0x2e, 0x47, 0xbf, 0x10, 0x0d, 0x05, 0x27, 0x01, /* .G....'. */ -0x2e, 0x1a, 0x87, 0xf7, 0xef, 0x16, 0x80, 0x52, /* .......R */ -0x80, 0x16, 0x82, 0x02, 0x2e, 0xb7, 0x85, 0x55, /* .......U */ -0x82, 0x02, 0x2e, 0x60, 0x80, 0x01, 0x2e, 0x84, /* ...`.... */ -0x83, 0x26, 0x40, 0x00, 0x5b, 0x3b, 0x33, 0x5c, /* .&@.[;3\ */ -0x47, 0x09, 0x5b, 0x6c, 0x38, 0x3b, 0x43, 0x00, /* G.[l8;C. */ -0x5b, 0x6c, 0x30, 0x41, 0x2e, 0x71, 0xdf, 0xc1, /* [l0A.q.. */ -0x2e, 0x72, 0xdf, 0xbf, 0x03, 0x01, 0x55, 0x01, /* .r....U. */ -0x2e, 0x98, 0x83, 0x01, 0x2e, 0x63, 0x84, 0x01, /* .....c.. */ -0x2e, 0x71, 0x87, 0x05, 0x27, 0x3b, 0x40, 0x01, /* .q..';@. */ -0x5b, 0x02, 0xef, 0x0c, 0xaf, 0x05, 0x27, 0x52, /* [.....'R */ -0xcf, 0xcb, 0xaf, 0x53, 0xdf /* ...S. */ + 0x42, 0xca, 0x00, + 0xc6, 0x26, 0x02, 0x2e, 0x22, /* B...&.." */ + 0x87, 0x09, 0x46, 0x02, 0x5b, 0x2d, 0x82, 0x90, /* ..F.[-.. */ + 0xaf, 0x91, 0xbf, 0x01, 0x2e, 0xbd, 0x84, 0x02, /* ........ */ + 0x2e, 0x14, 0x85, 0x0c, 0x3e, 0xe8, 0x5a, 0x05, /* ....>.Z. */ + 0x27, 0x2d, 0x82, 0x40, 0x82, 0x12, 0x82, 0x12, /* '-.@.... */ + 0x82, 0x9d, 0xbf, 0xff, 0x97, 0x08, 0x10, 0x09, /* ........ */ + 0x27, 0x0f, 0x1c, 0x5c, 0x46, 0x03, 0x5b, 0x02, /* '..\F.[. */ + 0x1e, 0x04, 0x53, 0x02, 0xef, 0x02, 0x50, 0x03, /* ..S...P. */ + 0x1e, 0x00, 0x53, 0x03, 0xef, 0x69, 0xaf, 0x3f, /* ..S..i.? */ + 0x80, 0x1b, 0x0d, 0xe1, 0x97, 0x0f, 0x1c, 0x69, /* .......i */ + 0xdf, 0xdf, 0x01, 0x00, 0x53, 0x00, 0xff, 0xe0, /* ....S... */ + 0x97, 0x76, 0x80, 0x04, 0x10, 0x07, 0x82, 0x0f, /* .v...... */ + 0x1e, 0x00, 0x5f, 0x0f, 0xef, 0x6a, 0xaf, 0xc1, /* .._..j.. */ + 0x2e, 0x47, 0xdf, 0xf0, 0x1d, 0x5f, 0x02, 0xc1, /* .G..._.. */ + 0x2e, 0x47, 0xbf, 0x10, 0x0d, 0x05, 0x27, 0x01, /* .G....'. */ + 0x2e, 0x1a, 0x87, 0xf7, 0xef, 0x16, 0x80, 0x52, /* .......R */ + 0x80, 0x16, 0x82, 0x02, 0x2e, 0xb7, 0x85, 0x55, /* .......U */ + 0x82, 0x02, 0x2e, 0x60, 0x80, 0x01, 0x2e, 0x84, /* ...`.... */ + 0x83, 0x26, 0x40, 0x00, 0x5b, 0x3b, 0x33, 0x5c, /* .&@.[;3\ */ + 0x47, 0x09, 0x5b, 0x6c, 0x38, 0x3b, 0x43, 0x00, /* G.[l8;C. */ + 0x5b, 0x6c, 0x30, 0x41, 0x2e, 0x71, 0xdf, 0xc1, /* [l0A.q.. */ + 0x2e, 0x72, 0xdf, 0xbf, 0x03, 0x01, 0x55, 0x01, /* .r....U. */ + 0x2e, 0x98, 0x83, 0x01, 0x2e, 0x63, 0x84, 0x01, /* .....c.. */ + 0x2e, 0x71, 0x87, 0x05, 0x27, 0x3b, 0x40, 0x01, /* .q..';@. */ + 0x5b, 0x02, 0xef, 0x0c, 0xaf, 0x05, 0x27, 0x52, /* [.....'R */ + 0xcf, 0xcb, 0xaf, 0x53, 0xdf /* ...S. */ }; static const unsigned char pkt229[] = { -0x42, 0xca, 0x00, -0x2a, 0x27, 0xcc, 0xbf, 0xdf, /* B..*'... */ -0x22, 0x01, 0x55, 0xff, 0x22, 0x01, 0x54, 0x0e, /* ".U.".T. */ -0xef, 0xc9, 0xaf, 0x05, 0x27, 0x0e, 0xcf, 0x6e, /* ....'..n */ -0x1c, 0x49, 0xdf, 0x10, 0x1d, 0x3f, 0x02, 0x49, /* .I...?.I */ -0xaf, 0x0d, 0x44, 0x06, 0x5a, 0x0a, 0x41, 0x03, /* ..D.Z.A. */ -0x5b, 0x49, 0x43, 0x02, 0x5a, 0x48, 0x26, 0x00, /* [IC.ZH&. */ -0x55, 0x49, 0x30, 0x9f, 0x2c, 0x05, 0x5a, 0xdf, /* UI0.,.Z. */ -0x2c, 0x4d, 0x5a, 0x0e, 0x41, 0x16, 0x5b, 0x0c, /* ,MZ.A.[. */ -0x46, 0x14, 0x5a, 0x9f, 0x22, 0x1c, 0xaf, 0x21, /* F.Z."..! */ -0xaf, 0x02, 0x2e, 0xb4, 0x87, 0x03, 0x5a, 0x9f, /* ......Z. */ -0x2c, 0x05, 0x5a, 0x9f, 0x22, 0x04, 0x50, 0x9f, /* ,.Z.".P. */ -0x22, 0x0e, 0x3e, 0x0e, 0x3d, 0x00, 0x5b, 0x5f, /* ".>.=.[_ */ -0xef, 0x1d, 0xaf, 0x49, 0xcf, 0x87, 0x1c, 0x01, /* ...I.... */ -0x18, 0x49, 0xaf, 0x34, 0x50, 0x20, 0x26, 0x08, /* .I.4P &. */ -0x55, 0x1f, 0xcf, 0x48, 0xdf, 0xff, 0x2d, 0x00, /* U..H..-. */ -0x5b, 0xff, 0x21, 0x3f, 0x00, 0x00, 0x53, 0xff, /* [.!?..S. */ -0xef, 0x1f, 0xaf, 0x47, 0xdf, 0x1c, 0xcf, 0x3f, /* ...G...? */ -0x00, 0x1c, 0xaf, 0x1d, 0xcf, 0x48, 0xdf, 0x3f, /* .....H.? */ -0x00, 0x1d, 0xaf, 0xff, 0x22, 0x1f, 0x54, 0xff, /* ....".T. */ -0x2d, 0x03, 0x5b, 0xff, 0x1e, 0x19, 0x5b, 0x60, /* -.[...[` */ -0x10, 0x02, 0x50, 0x60, 0x1e, 0x0a, 0x52, 0x60, /* ..P`..R` */ -0x16, 0x1d, 0xaf, 0x49, 0x30, 0x49, 0x3c, 0x12, /* ...I0I<. */ -0x5b, 0x21, 0xcf, 0x47, 0xdf, 0x3f, 0x00, 0x1c, /* [!.G.?.. */ -0xaf, 0x21, 0x23, 0x0c, 0x50, 0x59, 0x1e, 0x0a, /* .!#.PY.. */ -0x52, 0x49, 0x34, 0x01, 0x5a, 0x21, 0x23, 0x06, /* RI4.Z!#. */ -0x50, 0x21, 0xcf, 0x47, 0xdf /* P!.G. */ + 0x42, 0xca, 0x00, + 0x2a, 0x27, 0xcc, 0xbf, 0xdf, /* B..*'... */ + 0x22, 0x01, 0x55, 0xff, 0x22, 0x01, 0x54, 0x0e, /* ".U.".T. */ + 0xef, 0xc9, 0xaf, 0x05, 0x27, 0x0e, 0xcf, 0x6e, /* ....'..n */ + 0x1c, 0x49, 0xdf, 0x10, 0x1d, 0x3f, 0x02, 0x49, /* .I...?.I */ + 0xaf, 0x0d, 0x44, 0x06, 0x5a, 0x0a, 0x41, 0x03, /* ..D.Z.A. */ + 0x5b, 0x49, 0x43, 0x02, 0x5a, 0x48, 0x26, 0x00, /* [IC.ZH&. */ + 0x55, 0x49, 0x30, 0x9f, 0x2c, 0x05, 0x5a, 0xdf, /* UI0.,.Z. */ + 0x2c, 0x4d, 0x5a, 0x0e, 0x41, 0x16, 0x5b, 0x0c, /* ,MZ.A.[. */ + 0x46, 0x14, 0x5a, 0x9f, 0x22, 0x1c, 0xaf, 0x21, /* F.Z."..! */ + 0xaf, 0x02, 0x2e, 0xb4, 0x87, 0x03, 0x5a, 0x9f, /* ......Z. */ + 0x2c, 0x05, 0x5a, 0x9f, 0x22, 0x04, 0x50, 0x9f, /* ,.Z.".P. */ + 0x22, 0x0e, 0x3e, 0x0e, 0x3d, 0x00, 0x5b, 0x5f, /* ".>.=.[_ */ + 0xef, 0x1d, 0xaf, 0x49, 0xcf, 0x87, 0x1c, 0x01, /* ...I.... */ + 0x18, 0x49, 0xaf, 0x34, 0x50, 0x20, 0x26, 0x08, /* .I.4P &. */ + 0x55, 0x1f, 0xcf, 0x48, 0xdf, 0xff, 0x2d, 0x00, /* U..H..-. */ + 0x5b, 0xff, 0x21, 0x3f, 0x00, 0x00, 0x53, 0xff, /* [.!?..S. */ + 0xef, 0x1f, 0xaf, 0x47, 0xdf, 0x1c, 0xcf, 0x3f, /* ...G...? */ + 0x00, 0x1c, 0xaf, 0x1d, 0xcf, 0x48, 0xdf, 0x3f, /* .....H.? */ + 0x00, 0x1d, 0xaf, 0xff, 0x22, 0x1f, 0x54, 0xff, /* ....".T. */ + 0x2d, 0x03, 0x5b, 0xff, 0x1e, 0x19, 0x5b, 0x60, /* -.[...[` */ + 0x10, 0x02, 0x50, 0x60, 0x1e, 0x0a, 0x52, 0x60, /* ..P`..R` */ + 0x16, 0x1d, 0xaf, 0x49, 0x30, 0x49, 0x3c, 0x12, /* ...I0I<. */ + 0x5b, 0x21, 0xcf, 0x47, 0xdf, 0x3f, 0x00, 0x1c, /* [!.G.?.. */ + 0xaf, 0x21, 0x23, 0x0c, 0x50, 0x59, 0x1e, 0x0a, /* .!#.PY.. */ + 0x52, 0x49, 0x34, 0x01, 0x5a, 0x21, 0x23, 0x06, /* RI4.Z!#. */ + 0x50, 0x21, 0xcf, 0x47, 0xdf /* P!.G. */ }; static const unsigned char pkt231[] = { -0x42, 0xca, 0x00, -0x8e, 0x27, 0x3f, 0x00, 0x21, /* B...'?.! */ -0xaf, 0x01, 0x50, 0x06, 0x1e, 0xf4, 0x5f, 0x05, /* ..P..._. */ -0x27, 0x1e, 0x23, 0x0d, 0xcf, 0x06, 0x1c, 0x1a, /* '.#..... */ -0x54, 0x48, 0xcf, 0xdf, 0x2d, 0x00, 0x5b, 0xdf, /* TH..-.[. */ -0x21, 0x09, 0x27, 0x1f, 0x22, 0xbf, 0x22, 0x1a, /* !.'.".". */ -0x27, 0xc0, 0x2e, 0x96, 0xdf, 0x7f, 0x1f, 0x02, /* '....... */ -0x54, 0x3f, 0x20, 0xc0, 0x2e, 0x96, 0xbf, 0x59, /* T? ....Y */ -0x80, 0x40, 0x2e, 0x97, 0xbf, 0xc0, 0x2e, 0x95, /* .@...... */ -0xdf, 0x76, 0x80, 0x1e, 0xbf, 0x0c, 0x42, 0x02, /* .v....B. */ -0x5b, 0x9f, 0x22, 0x40, 0x2e, 0x96, 0xbf, 0x05, /* [."@.... */ -0x27, 0x0d, 0xcf, 0x06, 0x1c, 0x06, 0x1e, 0x00, /* '....... */ -0x54, 0x0d, 0x27, 0x0c, 0x27, 0x09, 0x46, 0x0d, /* T.'.'.F. */ -0x5b, 0x02, 0x2e, 0x38, 0x86, 0x07, 0x52, 0x0f, /* [..8..R. */ -0xcf, 0x01, 0x16, 0x02, 0x53, 0x02, 0x2e, 0xfe, /* ....S... */ -0x87, 0x04, 0x50, 0xf4, 0xaf, 0x02, 0x50, 0xf2, /* ..P...P. */ -0xcf, 0x02, 0x10, 0x0f, 0xaf, 0x05, 0x27, 0x5a, /* ......'Z */ -0xcf, 0xdf, 0x22, 0x10, 0x54, 0x3e, 0xdf, 0x3f, /* ..".T>.? */ -0x20, 0x3f, 0x1f, 0x0a, 0x52, 0xbf, 0x22, 0x3e, /* ?..R."> */ -0xbf, 0x3d, 0xdf, 0x3f, 0x20, 0xdf, 0x03, 0x02, /* .=.? ... */ -0x52, 0xbf, 0x22, 0x3d, 0xbf, 0x0c, 0x27, 0x3d, /* R."=..'= */ -0xbf, 0x0d, 0x27, 0x3e, 0xbf, 0x0d, 0x27, 0x0d, /* ..'>..'. */ -0x27, 0xbf, 0x22, 0x3e, 0xbf, 0x3d, 0xbf, 0x05, /* '.">.=.. */ -0x27, 0x0f, 0x1c, 0x69, 0xdf, 0xdf, 0x01, 0x00, /* '..i.... */ -0x53, 0x00, 0xff, 0x05, 0x27, 0x2d, 0x82, 0x40, /* S...'-.@ */ -0x82, 0x12, 0x82, 0x12, 0x82, 0x9d, 0xbf, 0xff, /* ........ */ -0x97, 0x08, 0x10, 0x09, 0x27 /* ....' */ + 0x42, 0xca, 0x00, + 0x8e, 0x27, 0x3f, 0x00, 0x21, /* B...'?.! */ + 0xaf, 0x01, 0x50, 0x06, 0x1e, 0xf4, 0x5f, 0x05, /* ..P..._. */ + 0x27, 0x1e, 0x23, 0x0d, 0xcf, 0x06, 0x1c, 0x1a, /* '.#..... */ + 0x54, 0x48, 0xcf, 0xdf, 0x2d, 0x00, 0x5b, 0xdf, /* TH..-.[. */ + 0x21, 0x09, 0x27, 0x1f, 0x22, 0xbf, 0x22, 0x1a, /* !.'.".". */ + 0x27, 0xc0, 0x2e, 0x96, 0xdf, 0x7f, 0x1f, 0x02, /* '....... */ + 0x54, 0x3f, 0x20, 0xc0, 0x2e, 0x96, 0xbf, 0x59, /* T? ....Y */ + 0x80, 0x40, 0x2e, 0x97, 0xbf, 0xc0, 0x2e, 0x95, /* .@...... */ + 0xdf, 0x76, 0x80, 0x1e, 0xbf, 0x0c, 0x42, 0x02, /* .v....B. */ + 0x5b, 0x9f, 0x22, 0x40, 0x2e, 0x96, 0xbf, 0x05, /* [."@.... */ + 0x27, 0x0d, 0xcf, 0x06, 0x1c, 0x06, 0x1e, 0x00, /* '....... */ + 0x54, 0x0d, 0x27, 0x0c, 0x27, 0x09, 0x46, 0x0d, /* T.'.'.F. */ + 0x5b, 0x02, 0x2e, 0x38, 0x86, 0x07, 0x52, 0x0f, /* [..8..R. */ + 0xcf, 0x01, 0x16, 0x02, 0x53, 0x02, 0x2e, 0xfe, /* ....S... */ + 0x87, 0x04, 0x50, 0xf4, 0xaf, 0x02, 0x50, 0xf2, /* ..P...P. */ + 0xcf, 0x02, 0x10, 0x0f, 0xaf, 0x05, 0x27, 0x5a, /* ......'Z */ + 0xcf, 0xdf, 0x22, 0x10, 0x54, 0x3e, 0xdf, 0x3f, /* ..".T>.? */ + 0x20, 0x3f, 0x1f, 0x0a, 0x52, 0xbf, 0x22, 0x3e, /* ?..R."> */ + 0xbf, 0x3d, 0xdf, 0x3f, 0x20, 0xdf, 0x03, 0x02, /* .=.? ... */ + 0x52, 0xbf, 0x22, 0x3d, 0xbf, 0x0c, 0x27, 0x3d, /* R."=..'= */ + 0xbf, 0x0d, 0x27, 0x3e, 0xbf, 0x0d, 0x27, 0x0d, /* ..'>..'. */ + 0x27, 0xbf, 0x22, 0x3e, 0xbf, 0x3d, 0xbf, 0x05, /* '.">.=.. */ + 0x27, 0x0f, 0x1c, 0x69, 0xdf, 0xdf, 0x01, 0x00, /* '..i.... */ + 0x53, 0x00, 0xff, 0x05, 0x27, 0x2d, 0x82, 0x40, /* S...'-.@ */ + 0x82, 0x12, 0x82, 0x12, 0x82, 0x9d, 0xbf, 0xff, /* ........ */ + 0x97, 0x08, 0x10, 0x09, 0x27 /* ....' */ }; static const unsigned char pkt233[] = { -0x42, 0x24, 0x00, -0xf2, 0x27, 0x0f, 0x1c, 0x5c, /* B$..'..\ */ -0x46, 0x03, 0x5b, 0x02, 0x1e, 0x04, 0x53, 0x02, /* F.[...S. */ -0xef, 0x02, 0x50, 0x03, 0x1e, 0x00, 0x53, 0x03, /* ..P...S. */ -0xef, 0x69, 0xaf, 0x05, 0x27, 0x14, 0xef, 0xf4, /* .i..'... */ -0xaf, 0x00, 0xef, 0xf5, 0xaf, 0x05, 0x27 /* ......' */ + 0x42, 0x24, 0x00, + 0xf2, 0x27, 0x0f, 0x1c, 0x5c, /* B$..'..\ */ + 0x46, 0x03, 0x5b, 0x02, 0x1e, 0x04, 0x53, 0x02, /* F.[...S. */ + 0xef, 0x02, 0x50, 0x03, 0x1e, 0x00, 0x53, 0x03, /* ..P...S. */ + 0xef, 0x69, 0xaf, 0x05, 0x27, 0x14, 0xef, 0xf4, /* .i..'... */ + 0xaf, 0x00, 0xef, 0xf5, 0xaf, 0x05, 0x27 /* ......' */ }; static const unsigned char pkt235[] = { -0x42, 0xca, 0x00, -0x03, 0x28, 0x0c, 0x42, 0x00, /* B...(.B. */ -0x5b, 0x18, 0x23, 0x00, 0xef, 0x0c, 0xaf, 0x0e, /* [.#..... */ -0xcf, 0xe0, 0x1c, 0x0e, 0xaf, 0x0a, 0x40, 0x02, /* ......@. */ -0x5a, 0x3b, 0x46, 0x00, 0x5a, 0x05, 0x27, 0x37, /* Z;F.Z.'7 */ -0x43, 0xfc, 0x5b, 0x08, 0xef, 0x0c, 0xaf, 0x0d, /* C.[..... */ -0x40, 0x0a, 0x5a, 0xee, 0xcf, 0x64, 0x1e, 0x01, /* @.Z..d.. */ -0x5e, 0x0c, 0x3b, 0x05, 0x27, 0x0d, 0x30, 0x0c, /* ^.;.'.0. */ -0x35, 0xbf, 0x22, 0xc0, 0x2e, 0x96, 0xbf, 0x05, /* 5."..... */ -0x27, 0x0e, 0x45, 0x02, 0x5b, 0x02, 0x2e, 0x30, /* '.E.[..0 */ -0x88, 0x01, 0x50, 0x02, 0x2e, 0x3a, 0x88, 0x0d, /* ..P..:.. */ -0x41, 0x24, 0x5a, 0x0d, 0x42, 0x14, 0x5a, 0x02, /* A$Z.B.Z. */ -0x2e, 0x2f, 0x79, 0x02, 0x2e, 0x8f, 0x88, 0x19, /* ./y..... */ -0xcf, 0xfe, 0x1e, 0x03, 0x5c, 0x0e, 0x3d, 0x0d, /* ....\.=. */ -0x39, 0x0d, 0x3b, 0x0c, 0x27, 0x0d, 0x27, 0x02, /* 9.;.'.'. */ -0x2e, 0xae, 0x88, 0x19, 0xcf, 0x02, 0x1e, 0xf9, /* ........ */ -0x5a, 0x0e, 0x3e, 0x0d, 0x3a, 0x0d, 0x33, 0x0c, /* Z.>.:.3. */ -0x27, 0xe4, 0x37, 0x02, 0x2e, 0x8b, 0x89, 0xe4, /* '.7..... */ -0x3f, 0x02, 0x2e, 0x80, 0x89, 0x0d, 0x45, 0x61, /* ?.....Ea */ -0x5b, 0x18, 0xcf, 0xdf, 0x22, 0x6b, 0x54, 0x0d, /* [..."kT. */ -0x3b, 0x02, 0x2e, 0xab, 0x78, 0x02, 0x2e, 0x8b, /* ;...x... */ -0x89, 0x02, 0x2e, 0x80, 0x89, 0x0d, 0x42, 0x07, /* ......B. */ -0x5a, 0x0d, 0x45, 0x53, 0x5b, 0x18, 0xcf, 0xdf, /* Z.ES[... */ -0x22, 0x5d, 0x54, 0x0d, 0x33, 0x02, 0x2e, 0xab, /* "]T.3... */ -0x78, 0x15, 0xcf, 0x1a, 0xaf, 0xe4, 0x37, 0x02, /* x.....7. */ -0x2e, 0x8b, 0x89, 0x15, 0xcf, 0x1b, 0xaf, 0xe4, /* ........ */ -0x3f, 0x0d, 0xcf, 0x60, 0x1c /* ?..`. */ + 0x42, 0xca, 0x00, + 0x03, 0x28, 0x0c, 0x42, 0x00, /* B...(.B. */ + 0x5b, 0x18, 0x23, 0x00, 0xef, 0x0c, 0xaf, 0x0e, /* [.#..... */ + 0xcf, 0xe0, 0x1c, 0x0e, 0xaf, 0x0a, 0x40, 0x02, /* ......@. */ + 0x5a, 0x3b, 0x46, 0x00, 0x5a, 0x05, 0x27, 0x37, /* Z;F.Z.'7 */ + 0x43, 0xfc, 0x5b, 0x08, 0xef, 0x0c, 0xaf, 0x0d, /* C.[..... */ + 0x40, 0x0a, 0x5a, 0xee, 0xcf, 0x64, 0x1e, 0x01, /* @.Z..d.. */ + 0x5e, 0x0c, 0x3b, 0x05, 0x27, 0x0d, 0x30, 0x0c, /* ^.;.'.0. */ + 0x35, 0xbf, 0x22, 0xc0, 0x2e, 0x96, 0xbf, 0x05, /* 5."..... */ + 0x27, 0x0e, 0x45, 0x02, 0x5b, 0x02, 0x2e, 0x30, /* '.E.[..0 */ + 0x88, 0x01, 0x50, 0x02, 0x2e, 0x3a, 0x88, 0x0d, /* ..P..:.. */ + 0x41, 0x24, 0x5a, 0x0d, 0x42, 0x14, 0x5a, 0x02, /* A$Z.B.Z. */ + 0x2e, 0x2f, 0x79, 0x02, 0x2e, 0x8f, 0x88, 0x19, /* ./y..... */ + 0xcf, 0xfe, 0x1e, 0x03, 0x5c, 0x0e, 0x3d, 0x0d, /* ....\.=. */ + 0x39, 0x0d, 0x3b, 0x0c, 0x27, 0x0d, 0x27, 0x02, /* 9.;.'.'. */ + 0x2e, 0xae, 0x88, 0x19, 0xcf, 0x02, 0x1e, 0xf9, /* ........ */ + 0x5a, 0x0e, 0x3e, 0x0d, 0x3a, 0x0d, 0x33, 0x0c, /* Z.>.:.3. */ + 0x27, 0xe4, 0x37, 0x02, 0x2e, 0x8b, 0x89, 0xe4, /* '.7..... */ + 0x3f, 0x02, 0x2e, 0x80, 0x89, 0x0d, 0x45, 0x61, /* ?.....Ea */ + 0x5b, 0x18, 0xcf, 0xdf, 0x22, 0x6b, 0x54, 0x0d, /* [..."kT. */ + 0x3b, 0x02, 0x2e, 0xab, 0x78, 0x02, 0x2e, 0x8b, /* ;...x... */ + 0x89, 0x02, 0x2e, 0x80, 0x89, 0x0d, 0x42, 0x07, /* ......B. */ + 0x5a, 0x0d, 0x45, 0x53, 0x5b, 0x18, 0xcf, 0xdf, /* Z.ES[... */ + 0x22, 0x5d, 0x54, 0x0d, 0x33, 0x02, 0x2e, 0xab, /* "]T.3... */ + 0x78, 0x15, 0xcf, 0x1a, 0xaf, 0xe4, 0x37, 0x02, /* x.....7. */ + 0x2e, 0x8b, 0x89, 0x15, 0xcf, 0x1b, 0xaf, 0xe4, /* ........ */ + 0x3f, 0x0d, 0xcf, 0x60, 0x1c /* ?..`. */ }; static const unsigned char pkt237[] = { -0x42, 0xca, 0x00, -0x67, 0x28, 0xdf, 0x22, 0x01, /* B..g(.". */ -0x55, 0x02, 0x2e, 0xdf, 0x78, 0x16, 0xcf, 0x13, /* U...x... */ -0xdf, 0x2a, 0x1e, 0x00, 0x2e, 0x04, 0x5f, 0x2a, /* .*...._* */ -0x1f, 0x00, 0x2e, 0x01, 0x5f, 0x02, 0x2e, 0xdf, /* ...._... */ -0x78, 0xbf, 0x03, 0x40, 0x54, 0x20, 0x52, 0x02, /* x..@T R. */ -0x2e, 0x80, 0x89, 0x9f, 0x22, 0x1a, 0xaf, 0x18, /* ...."... */ -0xcf, 0x12, 0xdf, 0xbf, 0x03, 0x00, 0x53, 0x29, /* ......S) */ -0x50, 0x02, 0x2e, 0x8f, 0x88, 0x02, 0x2e, 0x74, /* P......t */ -0x89, 0x9f, 0x22, 0x1b, 0xaf, 0x02, 0x2e, 0x2e, /* .."..... */ -0x88, 0x02, 0x2e, 0xab, 0x78, 0x0e, 0xcf, 0x9f, /* ....x... */ -0x1c, 0x0e, 0xaf, 0x05, 0x27, 0x0e, 0xcf, 0x5f, /* ....'.._ */ -0x2d, 0x05, 0x5a, 0x9f, 0x2b, 0x5f, 0x29, 0x0e, /* -.Z.+_). */ -0xaf, 0x5f, 0xff, 0x1d, 0xbf, 0x1c, 0x23, 0x05, /* ._....#. */ -0x27, 0x9f, 0x22, 0x1b, 0xaf, 0x18, 0xcf, 0xdf, /* '."..... */ -0x22, 0x0c, 0x54, 0x18, 0xcf, 0x12, 0xdf, 0xbf, /* ".T..... */ -0x03, 0x00, 0x53, 0x07, 0x50, 0x02, 0x2e, 0xae, /* ..S.P... */ -0x88, 0x02, 0x2e, 0x7a, 0x89, 0x9f, 0x22, 0x1a, /* ...z..". */ -0xaf, 0x02, 0x2e, 0x38, 0x88, 0x02, 0x2e, 0xbc, /* ...8.... */ -0x88, 0x05, 0x27, 0x0e, 0xcf, 0x9f, 0x2d, 0x05, /* ..'...-. */ -0x5a, 0x9f, 0x29, 0x5f, 0x2b, 0x0e, 0xaf, 0x00, /* Z.)_+... */ -0xff, 0x1d, 0xbf, 0x1c, 0x23, 0x05, 0x27, 0x02, /* ....#.'. */ -0x2e, 0x64, 0x89, 0x02, 0x2e, 0xc4, 0x78, 0x0d, /* .d....x. */ -0x45, 0x20, 0x5b, 0x02, 0x2e, 0x64, 0x89, 0x18, /* E [..d.. */ -0xcf, 0x12, 0xdf, 0xbf, 0x03, 0x6a, 0x53, 0x0d, /* .....jS. */ -0x44, 0x02, 0x5b, 0x0c, 0x35, 0x02, 0x2e, 0xd6, /* D.[.5... */ -0x78, 0x17, 0xcf, 0xdf, 0x22 /* x..." */ + 0x42, 0xca, 0x00, + 0x67, 0x28, 0xdf, 0x22, 0x01, /* B..g(.". */ + 0x55, 0x02, 0x2e, 0xdf, 0x78, 0x16, 0xcf, 0x13, /* U...x... */ + 0xdf, 0x2a, 0x1e, 0x00, 0x2e, 0x04, 0x5f, 0x2a, /* .*...._* */ + 0x1f, 0x00, 0x2e, 0x01, 0x5f, 0x02, 0x2e, 0xdf, /* ...._... */ + 0x78, 0xbf, 0x03, 0x40, 0x54, 0x20, 0x52, 0x02, /* x..@T R. */ + 0x2e, 0x80, 0x89, 0x9f, 0x22, 0x1a, 0xaf, 0x18, /* ...."... */ + 0xcf, 0x12, 0xdf, 0xbf, 0x03, 0x00, 0x53, 0x29, /* ......S) */ + 0x50, 0x02, 0x2e, 0x8f, 0x88, 0x02, 0x2e, 0x74, /* P......t */ + 0x89, 0x9f, 0x22, 0x1b, 0xaf, 0x02, 0x2e, 0x2e, /* .."..... */ + 0x88, 0x02, 0x2e, 0xab, 0x78, 0x0e, 0xcf, 0x9f, /* ....x... */ + 0x1c, 0x0e, 0xaf, 0x05, 0x27, 0x0e, 0xcf, 0x5f, /* ....'.._ */ + 0x2d, 0x05, 0x5a, 0x9f, 0x2b, 0x5f, 0x29, 0x0e, /* -.Z.+_). */ + 0xaf, 0x5f, 0xff, 0x1d, 0xbf, 0x1c, 0x23, 0x05, /* ._....#. */ + 0x27, 0x9f, 0x22, 0x1b, 0xaf, 0x18, 0xcf, 0xdf, /* '."..... */ + 0x22, 0x0c, 0x54, 0x18, 0xcf, 0x12, 0xdf, 0xbf, /* ".T..... */ + 0x03, 0x00, 0x53, 0x07, 0x50, 0x02, 0x2e, 0xae, /* ..S.P... */ + 0x88, 0x02, 0x2e, 0x7a, 0x89, 0x9f, 0x22, 0x1a, /* ...z..". */ + 0xaf, 0x02, 0x2e, 0x38, 0x88, 0x02, 0x2e, 0xbc, /* ...8.... */ + 0x88, 0x05, 0x27, 0x0e, 0xcf, 0x9f, 0x2d, 0x05, /* ..'...-. */ + 0x5a, 0x9f, 0x29, 0x5f, 0x2b, 0x0e, 0xaf, 0x00, /* Z.)_+... */ + 0xff, 0x1d, 0xbf, 0x1c, 0x23, 0x05, 0x27, 0x02, /* ....#.'. */ + 0x2e, 0x64, 0x89, 0x02, 0x2e, 0xc4, 0x78, 0x0d, /* .d....x. */ + 0x45, 0x20, 0x5b, 0x02, 0x2e, 0x64, 0x89, 0x18, /* E [..d.. */ + 0xcf, 0x12, 0xdf, 0xbf, 0x03, 0x6a, 0x53, 0x0d, /* .....jS. */ + 0x44, 0x02, 0x5b, 0x0c, 0x35, 0x02, 0x2e, 0xd6, /* D.[.5... */ + 0x78, 0x17, 0xcf, 0xdf, 0x22 /* x..." */ }; static const unsigned char pkt239[] = { -0x42, 0xca, 0x00, -0xcb, 0x28, 0x09, 0x55, 0x18, /* B...(.U. */ -0xcf, 0xdf, 0x22, 0x06, 0x55, 0x02, 0x2e, 0xdc, /* ..".U... */ -0x88, 0x0e, 0x3b, 0x0c, 0xdf, 0x24, 0x19, 0x0c, /* ..;..$.. */ -0xbf, 0x05, 0x27, 0x11, 0xcf, 0xff, 0x1e, 0x01, /* ..'..... */ -0x54, 0x1f, 0x20, 0x11, 0xaf, 0x05, 0x27, 0x1a, /* T. ...'. */ -0x23, 0x1b, 0x23, 0x05, 0x27, 0x02, 0x2e, 0xdc, /* #.#.'... */ -0x88, 0x02, 0x2e, 0xf2, 0x88, 0x02, 0x2e, 0x64, /* .......d */ -0x89, 0x02, 0x2e, 0xb4, 0x87, 0x37, 0x5a, 0x0a, /* .....7Z. */ -0xcf, 0xc0, 0x1c, 0xc0, 0x1e, 0x0e, 0x55, 0x9f, /* ......U. */ -0x22, 0x1f, 0xaf, 0x20, 0xaf, 0x19, 0xaf, 0x02, /* ".. .... */ -0x2e, 0x0f, 0x79, 0x0e, 0xcf, 0x05, 0x18, 0x0e, /* ..y..... */ -0xaf, 0x9f, 0x22, 0x47, 0xaf, 0x48, 0xaf, 0x17, /* .."G.H.. */ -0xaf, 0x18, 0xaf, 0x05, 0x27, 0x20, 0xcf, 0xdf, /* ....' .. */ -0x22, 0x06, 0x54, 0x05, 0x1e, 0x1b, 0x55, 0x1f, /* ".T...U. */ -0xdf, 0x80, 0x1f, 0x18, 0x5e, 0x02, 0x2e, 0x08, /* ....^... */ -0x79, 0x1f, 0xdf, 0x10, 0x1f, 0x13, 0x5e, 0x9f, /* y.....^. */ -0x22, 0x20, 0xaf, 0x1f, 0xaf, 0x0a, 0xcf, 0xc0, /* " ...... */ -0x1c, 0x80, 0x1e, 0x0a, 0x55, 0x0d, 0x41, 0x01, /* ....U.A. */ -0x5a, 0x0e, 0x35, 0x00, 0x50, 0x0e, 0x36, 0x0d, /* Z.5.P.6. */ -0xcf, 0x06, 0x18, 0x0d, 0xaf, 0x0e, 0x31, 0x9f, /* ......1. */ -0x22, 0x19, 0xaf, 0x02, 0x2e, 0x20, 0x79, 0x1f, /* ".... y. */ -0x20, 0x06, 0x1e, 0x00, 0x5e, 0x20, 0xaf, 0x0d, /* ...^ .. */ -0x47, 0x0c, 0x5b, 0x51, 0xef, 0x0c, 0xaf, 0x0e, /* G.[Q.... */ -0xcf, 0xfa, 0x1c, 0x0e, 0xaf, 0x20, 0xcf, 0xdf, /* ..... .. */ -0x22, 0x03, 0x54, 0x06, 0x1e, 0x01, 0x54, 0x5f, /* ".T...T_ */ -0x20, 0x20, 0xaf, 0x05, 0x27 /* ..' */ + 0x42, 0xca, 0x00, + 0xcb, 0x28, 0x09, 0x55, 0x18, /* B...(.U. */ + 0xcf, 0xdf, 0x22, 0x06, 0x55, 0x02, 0x2e, 0xdc, /* ..".U... */ + 0x88, 0x0e, 0x3b, 0x0c, 0xdf, 0x24, 0x19, 0x0c, /* ..;..$.. */ + 0xbf, 0x05, 0x27, 0x11, 0xcf, 0xff, 0x1e, 0x01, /* ..'..... */ + 0x54, 0x1f, 0x20, 0x11, 0xaf, 0x05, 0x27, 0x1a, /* T. ...'. */ + 0x23, 0x1b, 0x23, 0x05, 0x27, 0x02, 0x2e, 0xdc, /* #.#.'... */ + 0x88, 0x02, 0x2e, 0xf2, 0x88, 0x02, 0x2e, 0x64, /* .......d */ + 0x89, 0x02, 0x2e, 0xb4, 0x87, 0x37, 0x5a, 0x0a, /* .....7Z. */ + 0xcf, 0xc0, 0x1c, 0xc0, 0x1e, 0x0e, 0x55, 0x9f, /* ......U. */ + 0x22, 0x1f, 0xaf, 0x20, 0xaf, 0x19, 0xaf, 0x02, /* ".. .... */ + 0x2e, 0x0f, 0x79, 0x0e, 0xcf, 0x05, 0x18, 0x0e, /* ..y..... */ + 0xaf, 0x9f, 0x22, 0x47, 0xaf, 0x48, 0xaf, 0x17, /* .."G.H.. */ + 0xaf, 0x18, 0xaf, 0x05, 0x27, 0x20, 0xcf, 0xdf, /* ....' .. */ + 0x22, 0x06, 0x54, 0x05, 0x1e, 0x1b, 0x55, 0x1f, /* ".T...U. */ + 0xdf, 0x80, 0x1f, 0x18, 0x5e, 0x02, 0x2e, 0x08, /* ....^... */ + 0x79, 0x1f, 0xdf, 0x10, 0x1f, 0x13, 0x5e, 0x9f, /* y.....^. */ + 0x22, 0x20, 0xaf, 0x1f, 0xaf, 0x0a, 0xcf, 0xc0, /* " ...... */ + 0x1c, 0x80, 0x1e, 0x0a, 0x55, 0x0d, 0x41, 0x01, /* ....U.A. */ + 0x5a, 0x0e, 0x35, 0x00, 0x50, 0x0e, 0x36, 0x0d, /* Z.5.P.6. */ + 0xcf, 0x06, 0x18, 0x0d, 0xaf, 0x0e, 0x31, 0x9f, /* ......1. */ + 0x22, 0x19, 0xaf, 0x02, 0x2e, 0x20, 0x79, 0x1f, /* ".... y. */ + 0x20, 0x06, 0x1e, 0x00, 0x5e, 0x20, 0xaf, 0x0d, /* ...^ .. */ + 0x47, 0x0c, 0x5b, 0x51, 0xef, 0x0c, 0xaf, 0x0e, /* G.[Q.... */ + 0xcf, 0xfa, 0x1c, 0x0e, 0xaf, 0x20, 0xcf, 0xdf, /* ..... .. */ + 0x22, 0x03, 0x54, 0x06, 0x1e, 0x01, 0x54, 0x5f, /* ".T...T_ */ + 0x20, 0x20, 0xaf, 0x05, 0x27 /* ..' */ }; static const unsigned char pkt241[] = { -0x42, 0xca, 0x00, -0x2f, 0x29, 0x0d, 0x44, 0x0b, /* B../).D. */ -0x5a, 0x0d, 0xcf, 0x06, 0x1c, 0x08, 0x54, 0x0c, /* Z.....T. */ -0x30, 0x48, 0xcf, 0xdf, 0x2d, 0x02, 0x5a, 0x9f, /* 0H..-.Z. */ -0x22, 0x1d, 0xaf, 0x01, 0x50, 0x5f, 0xef, 0x1d, /* "...P_.. */ -0xaf, 0x0c, 0x31, 0x0d, 0x45, 0x13, 0x5b, 0x0a, /* ..1.E.[. */ -0xcf, 0x30, 0x1c, 0x0e, 0x55, 0x0d, 0xcf, 0x06, /* .0..U... */ -0x1c, 0x06, 0x1e, 0x0d, 0x54, 0x11, 0xcf, 0x07, /* ....T... */ -0x1e, 0x03, 0x53, 0x03, 0xef, 0x12, 0xaf, 0x02, /* ..S..... */ -0x2e, 0x54, 0x79, 0x05, 0xef, 0x12, 0xaf, 0x02, /* .Ty..... */ -0x2e, 0x54, 0x79, 0x01, 0xef, 0x12, 0xaf, 0x18, /* .Ty..... */ -0x23, 0x9f, 0x22, 0x11, 0xaf, 0x0d, 0xcf, 0x1f, /* #."..... */ -0x1c, 0x0d, 0xaf, 0x0c, 0xdf, 0x24, 0x19, 0x0c, /* .....$.. */ -0xbf, 0x0a, 0xdf, 0x30, 0x1d, 0x20, 0x1f, 0x01, /* ...0. .. */ -0x55, 0xf9, 0x1c, 0x0d, 0xaf, 0x05, 0x27, 0x17, /* U.....'. */ -0xdf, 0xff, 0x21, 0x47, 0xbf, 0x18, 0xdf, 0x02, /* ..!G.... */ -0x2e, 0xb4, 0x87, 0x03, 0x5b, 0x0e, 0x46, 0x04, /* ....[.F. */ -0x5a, 0x02, 0x2e, 0x71, 0x79, 0x0d, 0x43, 0x00, /* Z..qy.C. */ -0x5a, 0xff, 0x21, 0x48, 0xbf, 0x05, 0x27, 0x19, /* Z.!H..'. */ -0xcf, 0x80, 0x1e, 0x01, 0x54, 0x5f, 0x20, 0x19, /* ....T_ . */ -0xaf, 0x05, 0x27, 0x19, 0xcf, 0x7f, 0x1e, 0x01, /* ..'..... */ -0x54, 0x1f, 0x20, 0x19, 0xaf, 0x05, 0x27, 0x13, /* T. ...'. */ -0xcf, 0x16, 0xaf, 0x15, 0xcf, 0x18, 0xaf, 0x14, /* ........ */ -0xcf, 0x17, 0xaf, 0x0d, 0x3d, 0x0d, 0x46, 0x00, /* ....=.F. */ -0x5b, 0x0d, 0x35, 0x05, 0x27, 0x14, 0x23, 0x15, /* [.5.'.#. */ -0x23, 0xff, 0xef, 0x13, 0xaf, 0x02, 0x2e, 0x98, /* #....... */ -0x89, 0x0d, 0x3e, 0x13, 0xcf /* ..>.. */ + 0x42, 0xca, 0x00, + 0x2f, 0x29, 0x0d, 0x44, 0x0b, /* B../).D. */ + 0x5a, 0x0d, 0xcf, 0x06, 0x1c, 0x08, 0x54, 0x0c, /* Z.....T. */ + 0x30, 0x48, 0xcf, 0xdf, 0x2d, 0x02, 0x5a, 0x9f, /* 0H..-.Z. */ + 0x22, 0x1d, 0xaf, 0x01, 0x50, 0x5f, 0xef, 0x1d, /* "...P_.. */ + 0xaf, 0x0c, 0x31, 0x0d, 0x45, 0x13, 0x5b, 0x0a, /* ..1.E.[. */ + 0xcf, 0x30, 0x1c, 0x0e, 0x55, 0x0d, 0xcf, 0x06, /* .0..U... */ + 0x1c, 0x06, 0x1e, 0x0d, 0x54, 0x11, 0xcf, 0x07, /* ....T... */ + 0x1e, 0x03, 0x53, 0x03, 0xef, 0x12, 0xaf, 0x02, /* ..S..... */ + 0x2e, 0x54, 0x79, 0x05, 0xef, 0x12, 0xaf, 0x02, /* .Ty..... */ + 0x2e, 0x54, 0x79, 0x01, 0xef, 0x12, 0xaf, 0x18, /* .Ty..... */ + 0x23, 0x9f, 0x22, 0x11, 0xaf, 0x0d, 0xcf, 0x1f, /* #."..... */ + 0x1c, 0x0d, 0xaf, 0x0c, 0xdf, 0x24, 0x19, 0x0c, /* .....$.. */ + 0xbf, 0x0a, 0xdf, 0x30, 0x1d, 0x20, 0x1f, 0x01, /* ...0. .. */ + 0x55, 0xf9, 0x1c, 0x0d, 0xaf, 0x05, 0x27, 0x17, /* U.....'. */ + 0xdf, 0xff, 0x21, 0x47, 0xbf, 0x18, 0xdf, 0x02, /* ..!G.... */ + 0x2e, 0xb4, 0x87, 0x03, 0x5b, 0x0e, 0x46, 0x04, /* ....[.F. */ + 0x5a, 0x02, 0x2e, 0x71, 0x79, 0x0d, 0x43, 0x00, /* Z..qy.C. */ + 0x5a, 0xff, 0x21, 0x48, 0xbf, 0x05, 0x27, 0x19, /* Z.!H..'. */ + 0xcf, 0x80, 0x1e, 0x01, 0x54, 0x5f, 0x20, 0x19, /* ....T_ . */ + 0xaf, 0x05, 0x27, 0x19, 0xcf, 0x7f, 0x1e, 0x01, /* ..'..... */ + 0x54, 0x1f, 0x20, 0x19, 0xaf, 0x05, 0x27, 0x13, /* T. ...'. */ + 0xcf, 0x16, 0xaf, 0x15, 0xcf, 0x18, 0xaf, 0x14, /* ........ */ + 0xcf, 0x17, 0xaf, 0x0d, 0x3d, 0x0d, 0x46, 0x00, /* ....=.F. */ + 0x5b, 0x0d, 0x35, 0x05, 0x27, 0x14, 0x23, 0x15, /* [.5.'.#. */ + 0x23, 0xff, 0xef, 0x13, 0xaf, 0x02, 0x2e, 0x98, /* #....... */ + 0x89, 0x0d, 0x3e, 0x13, 0xcf /* ..>.. */ }; static const unsigned char pkt243[] = { -0x42, 0xc0, 0x00, -0x93, 0x29, 0x46, 0xff, 0xbf, /* B...)F.. */ -0x03, 0x00, 0x53, 0x0d, 0x36, 0x05, 0x27, 0x0d, /* ..S.6.'. */ -0xcf, 0x06, 0x1c, 0x06, 0x1e, 0x07, 0x55, 0xe4, /* ......U. */ -0x47, 0x02, 0x5a, 0x1a, 0xcf, 0x02, 0x2e, 0xa5, /* G.Z..... */ -0x79, 0x1b, 0xcf, 0x02, 0x2e, 0xa5, 0x79, 0x18, /* y.....y. */ -0xcf, 0x00, 0x1e, 0x04, 0x55, 0x5d, 0xef, 0x1b, /* ....U].. */ -0xff, 0x02, 0x2e, 0xc0, 0x79, 0x18, 0xcf, 0x01, /* ....y... */ -0x1e, 0x03, 0x55, 0x5e, 0xef, 0x1b, 0xff, 0x02, /* ..U^.... */ -0x2e, 0xc0, 0x79, 0x02, 0x1e, 0x03, 0x55, 0x61, /* ..y...Ua */ -0xef, 0x1b, 0xff, 0x02, 0x2e, 0xc0, 0x79, 0x03, /* ......y. */ -0x1e, 0x03, 0x55, 0x66, 0xef, 0x1b, 0xff, 0x02, /* ..Uf.... */ -0x2e, 0xc0, 0x79, 0x6d, 0xef, 0x1b, 0xff, 0x1a, /* ..ym.... */ -0x27, 0x07, 0x27, 0xe6, 0xaf, 0xe9, 0xbf, 0x7e, /* '.'....~ */ -0x81, 0xec, 0xcf, 0x13, 0xdf, 0xbf, 0x03, 0x19, /* ........ */ -0x54, 0x0a, 0x5e, 0x13, 0xaf, 0xe9, 0xcf, 0x0f, /* T.^..... */ -0x1c, 0x15, 0xaf, 0xe9, 0xcf, 0x09, 0x27, 0x0f, /* ......'. */ -0x1c, 0xdf, 0x2c, 0x00, 0x5b, 0xf0, 0x18, 0x14, /* ..,.[... */ -0xaf, 0x01, 0x0e, 0x07, 0x27, 0x88, 0x1f, 0xe8, /* ....'... */ -0x55, 0x0d, 0x3e, 0x13, 0xcf, 0x46, 0x1e, 0x04, /* U.>..F.. */ -0x53, 0x0d, 0x36, 0x13, 0xcf, 0x46, 0x1e, 0x00, /* S.6..F.. */ -0x5e, 0x0d, 0x36, 0x05, 0x27, 0xe9, 0xcf, 0x09, /* ^.6.'... */ -0x27, 0xdf, 0x2c, 0x00, 0x5b, 0xdf, 0x21, 0x0f, /* '.,.[.!. */ -0x1c, 0x14, 0xdf, 0xff, 0x2d, 0x00, 0x5b, 0xff, /* ....-.[. */ -0x21, 0xbf, 0x03, 0xe5, 0x53, 0xec, 0xcf, 0x02, /* !...S... */ -0x2e, 0xca, 0x79 /* ..y */ + 0x42, 0xc0, 0x00, + 0x93, 0x29, 0x46, 0xff, 0xbf, /* B...)F.. */ + 0x03, 0x00, 0x53, 0x0d, 0x36, 0x05, 0x27, 0x0d, /* ..S.6.'. */ + 0xcf, 0x06, 0x1c, 0x06, 0x1e, 0x07, 0x55, 0xe4, /* ......U. */ + 0x47, 0x02, 0x5a, 0x1a, 0xcf, 0x02, 0x2e, 0xa5, /* G.Z..... */ + 0x79, 0x1b, 0xcf, 0x02, 0x2e, 0xa5, 0x79, 0x18, /* y.....y. */ + 0xcf, 0x00, 0x1e, 0x04, 0x55, 0x5d, 0xef, 0x1b, /* ....U].. */ + 0xff, 0x02, 0x2e, 0xc0, 0x79, 0x18, 0xcf, 0x01, /* ....y... */ + 0x1e, 0x03, 0x55, 0x5e, 0xef, 0x1b, 0xff, 0x02, /* ..U^.... */ + 0x2e, 0xc0, 0x79, 0x02, 0x1e, 0x03, 0x55, 0x61, /* ..y...Ua */ + 0xef, 0x1b, 0xff, 0x02, 0x2e, 0xc0, 0x79, 0x03, /* ......y. */ + 0x1e, 0x03, 0x55, 0x66, 0xef, 0x1b, 0xff, 0x02, /* ..Uf.... */ + 0x2e, 0xc0, 0x79, 0x6d, 0xef, 0x1b, 0xff, 0x1a, /* ..ym.... */ + 0x27, 0x07, 0x27, 0xe6, 0xaf, 0xe9, 0xbf, 0x7e, /* '.'....~ */ + 0x81, 0xec, 0xcf, 0x13, 0xdf, 0xbf, 0x03, 0x19, /* ........ */ + 0x54, 0x0a, 0x5e, 0x13, 0xaf, 0xe9, 0xcf, 0x0f, /* T.^..... */ + 0x1c, 0x15, 0xaf, 0xe9, 0xcf, 0x09, 0x27, 0x0f, /* ......'. */ + 0x1c, 0xdf, 0x2c, 0x00, 0x5b, 0xf0, 0x18, 0x14, /* ..,.[... */ + 0xaf, 0x01, 0x0e, 0x07, 0x27, 0x88, 0x1f, 0xe8, /* ....'... */ + 0x55, 0x0d, 0x3e, 0x13, 0xcf, 0x46, 0x1e, 0x04, /* U.>..F.. */ + 0x53, 0x0d, 0x36, 0x13, 0xcf, 0x46, 0x1e, 0x00, /* S.6..F.. */ + 0x5e, 0x0d, 0x36, 0x05, 0x27, 0xe9, 0xcf, 0x09, /* ^.6.'... */ + 0x27, 0xdf, 0x2c, 0x00, 0x5b, 0xdf, 0x21, 0x0f, /* '.,.[.!. */ + 0x1c, 0x14, 0xdf, 0xff, 0x2d, 0x00, 0x5b, 0xff, /* ....-.[. */ + 0x21, 0xbf, 0x03, 0xe5, 0x53, 0xec, 0xcf, 0x02, /* !...S... */ + 0x2e, 0xca, 0x79 /* ..y */ }; static const unsigned char pkt245[] = { -0x42, 0x66, 0x00, -0x00, 0x2c, 0x01, 0x2e, 0x65, /* Bf..,..e */ -0x84, 0x08, 0x44, 0x2c, 0x5a, 0xff, 0x0d, 0x48, /* ..D,Z..H */ -0xef, 0x5f, 0x9a, 0x2a, 0xaf, 0x02, 0x2e, 0x75, /* ._.*...u */ -0x80, 0xdf, 0x96, 0x26, 0x40, 0x07, 0x5b, 0xa0, /* ...&@.[. */ -0xcf, 0x30, 0x1c, 0x04, 0x54, 0x20, 0x1e, 0x01, /* .0..T .. */ -0x55, 0x31, 0xff, 0x01, 0x50, 0x00, 0xff, 0x30, /* U1..P..0 */ -0x19, 0xbf, 0x9a, 0x2b, 0xbf, 0xa9, 0xcf, 0x70, /* ...+...p */ -0x1c, 0xa5, 0xdf, 0x0c, 0x1d, 0xff, 0x20, 0xff, /* ...... . */ -0x20, 0x5f, 0x02, 0xff, 0x9a, 0x2c, 0xbf, 0xdd, /* _...,.. */ -0x97, 0x1f, 0x9b, 0x2d, 0xaf, 0x29, 0xcf, 0x09, /* ...-.).. */ -0x27, 0x28, 0xdf, 0x3f, 0x02, 0x9f, 0x9c, 0x6a, /* '(.?...j */ -0xcf, 0x09, 0x27, 0x69, 0xdf, 0x3f, 0x02, 0xdf, /* ..'i.?.. */ -0x9c, 0x6d, 0x2e, 0x6d, 0xdf, 0x1f, 0x9d, 0x05, /* .m.m.... */ -0x27 /* ' */ + 0x42, 0x66, 0x00, + 0x00, 0x2c, 0x01, 0x2e, 0x65, /* Bf..,..e */ + 0x84, 0x08, 0x44, 0x2c, 0x5a, 0xff, 0x0d, 0x48, /* ..D,Z..H */ + 0xef, 0x5f, 0x9a, 0x2a, 0xaf, 0x02, 0x2e, 0x75, /* ._.*...u */ + 0x80, 0xdf, 0x96, 0x26, 0x40, 0x07, 0x5b, 0xa0, /* ...&@.[. */ + 0xcf, 0x30, 0x1c, 0x04, 0x54, 0x20, 0x1e, 0x01, /* .0..T .. */ + 0x55, 0x31, 0xff, 0x01, 0x50, 0x00, 0xff, 0x30, /* U1..P..0 */ + 0x19, 0xbf, 0x9a, 0x2b, 0xbf, 0xa9, 0xcf, 0x70, /* ...+...p */ + 0x1c, 0xa5, 0xdf, 0x0c, 0x1d, 0xff, 0x20, 0xff, /* ...... . */ + 0x20, 0x5f, 0x02, 0xff, 0x9a, 0x2c, 0xbf, 0xdd, /* _...,.. */ + 0x97, 0x1f, 0x9b, 0x2d, 0xaf, 0x29, 0xcf, 0x09, /* ...-.).. */ + 0x27, 0x28, 0xdf, 0x3f, 0x02, 0x9f, 0x9c, 0x6a, /* '(.?...j */ + 0xcf, 0x09, 0x27, 0x69, 0xdf, 0x3f, 0x02, 0xdf, /* ..'i.?.. */ + 0x9c, 0x6d, 0x2e, 0x6d, 0xdf, 0x1f, 0x9d, 0x05, /* .m.m.... */ + 0x27 /* ' */ }; static const unsigned char pkt247[] = { -0x42, 0x2c, 0x00, -0x32, 0x2c, 0x08, 0x44, 0x11, /* B,.2,.D. */ -0x5a, 0x3f, 0x80, 0x28, 0x0d, 0xe2, 0x97, 0xdf, /* Z?.(.... */ -0x96, 0xe1, 0x97, 0xdf, 0x96, 0x01, 0x2e, 0xbf, /* ........ */ -0x84, 0xfd, 0x0d, 0x29, 0xcf, 0x09, 0x27, 0x28, /* ...)..'( */ -0xdf, 0x3f, 0x02, 0x5f, 0x9f, 0xdd, 0x97, 0x5f, /* .?._..._ */ -0x9f, 0xdd, 0x97, 0x5f, 0x9f, 0x05, 0x27 /* ..._..' */ + 0x42, 0x2c, 0x00, + 0x32, 0x2c, 0x08, 0x44, 0x11, /* B,.2,.D. */ + 0x5a, 0x3f, 0x80, 0x28, 0x0d, 0xe2, 0x97, 0xdf, /* Z?.(.... */ + 0x96, 0xe1, 0x97, 0xdf, 0x96, 0x01, 0x2e, 0xbf, /* ........ */ + 0x84, 0xfd, 0x0d, 0x29, 0xcf, 0x09, 0x27, 0x28, /* ...)..'( */ + 0xdf, 0x3f, 0x02, 0x5f, 0x9f, 0xdd, 0x97, 0x5f, /* .?._..._ */ + 0x9f, 0xdd, 0x97, 0x5f, 0x9f, 0x05, 0x27 /* ..._..' */ }; static const unsigned char pkt249[] = { -0x42, 0xca, 0x00, -0x47, 0x2c, 0xfe, 0xcf, 0x58, /* B..G,..X */ -0xaf, 0xfe, 0xcf, 0xfe, 0xdf, 0x02, 0x2e, 0xde, /* ........ */ -0x8c, 0xfe, 0xcf, 0x3c, 0xaf, 0x07, 0x3d, 0x58, /* ...<..=X */ -0x40, 0x4e, 0x5a, 0x3c, 0x26, 0x4c, 0x55, 0x37, /* @NZ<&LU7 */ -0x45, 0x4a, 0x5a, 0x02, 0x2e, 0x5c, 0x8d, 0x47, /* EJZ..\.G */ -0x5a, 0x02, 0x2e, 0xee, 0x8c, 0x00, 0x2e, 0xb9, /* Z....... */ -0x8d, 0xfe, 0xef, 0x16, 0x80, 0x02, 0xcf, 0xdf, /* ........ */ -0x96, 0x61, 0xef, 0xc0, 0xaf, 0x04, 0x27, 0xc1, /* .a....'. */ -0x46, 0x04, 0x5b, 0xc0, 0x3e, 0x40, 0xef, 0xc1, /* F.[.>@.. */ -0xaf, 0x01, 0x2e, 0x8d, 0x8b, 0xd0, 0x41, 0x07, /* ......A. */ -0x5b, 0x02, 0x2e, 0x9e, 0x8c, 0xf2, 0x5b, 0xae, /* [.....[. */ -0x87, 0xdd, 0x97, 0x1f, 0x2d, 0x06, 0x5b, 0x03, /* ....-.[. */ -0x50, 0x01, 0x0c, 0x02, 0xcf, 0xc0, 0x1c, 0x01, /* P....... */ -0x55, 0x02, 0x2e, 0x81, 0x8c, 0xc0, 0x23, 0x20, /* U.....# */ -0xef, 0xc1, 0xaf, 0x00, 0x2e, 0xd8, 0x8d, 0x05, /* ........ */ -0x27, 0x9b, 0x22, 0x37, 0x45, 0x05, 0x5a, 0x41, /* '."7E.ZA */ -0x2e, 0x52, 0xdf, 0xdf, 0x2d, 0x04, 0x5b, 0x00, /* .R..-.[. */ -0x28, 0x02, 0x50, 0x3b, 0x43, 0x00, 0x5b, 0x00, /* (.P;C.[. */ -0x28, 0xd3, 0xdf, 0xc6, 0x2e, 0x15, 0xbf, 0xd3, /* (....... */ -0x3c, 0x40, 0xef, 0x09, 0x80, 0xdd, 0x97, 0xff, /* <@...... */ -0xaf, 0x00, 0x2e, 0xa7, 0x8a, 0xc6, 0x2e, 0x15, /* ........ */ -0xdf, 0x10, 0x1d, 0xd3, 0xcf, 0x3f, 0x02, 0xd3, /* .....?.. */ -0xaf, 0x05, 0x27, 0xed, 0x83, 0x07, 0x45, 0x05, /* ..'...E. */ -0x27, 0x3d, 0x23, 0x07, 0x3d, 0x02, 0xcf, 0xdf, /* '=#.=... */ -0x96, 0x02, 0x2e, 0xee, 0x8c, 0x02, 0x2e, 0xd7, /* ........ */ -0x8c, 0xfe, 0xef, 0x16, 0x80 /* ..... */ + 0x42, 0xca, 0x00, + 0x47, 0x2c, 0xfe, 0xcf, 0x58, /* B..G,..X */ + 0xaf, 0xfe, 0xcf, 0xfe, 0xdf, 0x02, 0x2e, 0xde, /* ........ */ + 0x8c, 0xfe, 0xcf, 0x3c, 0xaf, 0x07, 0x3d, 0x58, /* ...<..=X */ + 0x40, 0x4e, 0x5a, 0x3c, 0x26, 0x4c, 0x55, 0x37, /* @NZ<&LU7 */ + 0x45, 0x4a, 0x5a, 0x02, 0x2e, 0x5c, 0x8d, 0x47, /* EJZ..\.G */ + 0x5a, 0x02, 0x2e, 0xee, 0x8c, 0x00, 0x2e, 0xb9, /* Z....... */ + 0x8d, 0xfe, 0xef, 0x16, 0x80, 0x02, 0xcf, 0xdf, /* ........ */ + 0x96, 0x61, 0xef, 0xc0, 0xaf, 0x04, 0x27, 0xc1, /* .a....'. */ + 0x46, 0x04, 0x5b, 0xc0, 0x3e, 0x40, 0xef, 0xc1, /* F.[.>@.. */ + 0xaf, 0x01, 0x2e, 0x8d, 0x8b, 0xd0, 0x41, 0x07, /* ......A. */ + 0x5b, 0x02, 0x2e, 0x9e, 0x8c, 0xf2, 0x5b, 0xae, /* [.....[. */ + 0x87, 0xdd, 0x97, 0x1f, 0x2d, 0x06, 0x5b, 0x03, /* ....-.[. */ + 0x50, 0x01, 0x0c, 0x02, 0xcf, 0xc0, 0x1c, 0x01, /* P....... */ + 0x55, 0x02, 0x2e, 0x81, 0x8c, 0xc0, 0x23, 0x20, /* U.....# */ + 0xef, 0xc1, 0xaf, 0x00, 0x2e, 0xd8, 0x8d, 0x05, /* ........ */ + 0x27, 0x9b, 0x22, 0x37, 0x45, 0x05, 0x5a, 0x41, /* '."7E.ZA */ + 0x2e, 0x52, 0xdf, 0xdf, 0x2d, 0x04, 0x5b, 0x00, /* .R..-.[. */ + 0x28, 0x02, 0x50, 0x3b, 0x43, 0x00, 0x5b, 0x00, /* (.P;C.[. */ + 0x28, 0xd3, 0xdf, 0xc6, 0x2e, 0x15, 0xbf, 0xd3, /* (....... */ + 0x3c, 0x40, 0xef, 0x09, 0x80, 0xdd, 0x97, 0xff, /* <@...... */ + 0xaf, 0x00, 0x2e, 0xa7, 0x8a, 0xc6, 0x2e, 0x15, /* ........ */ + 0xdf, 0x10, 0x1d, 0xd3, 0xcf, 0x3f, 0x02, 0xd3, /* .....?.. */ + 0xaf, 0x05, 0x27, 0xed, 0x83, 0x07, 0x45, 0x05, /* ..'...E. */ + 0x27, 0x3d, 0x23, 0x07, 0x3d, 0x02, 0xcf, 0xdf, /* '=#.=... */ + 0x96, 0x02, 0x2e, 0xee, 0x8c, 0x02, 0x2e, 0xd7, /* ........ */ + 0x8c, 0xfe, 0xef, 0x16, 0x80 /* ..... */ }; static const unsigned char pkt251[] = { -0x42, 0xca, 0x00, -0xab, 0x2c, 0x05, 0xef, 0xc0, /* B...,... */ -0xaf, 0x04, 0x27, 0xd0, 0x41, 0x03, 0x5b, 0x02, /* ..'.A.[. */ -0x2e, 0x9e, 0x8c, 0xf9, 0x5b, 0xbb, 0x50, 0x27, /* ....[.P' */ -0x82, 0x04, 0xef, 0xc1, 0xaf, 0x9b, 0x22, 0x02, /* ......". */ -0x2e, 0x12, 0x8d, 0xdd, 0x97, 0xdf, 0x22, 0x02, /* ......". */ -0x55, 0x58, 0x40, 0x02, 0x5a, 0x0b, 0x50, 0x58, /* UX@.Z.PX */ -0x40, 0x09, 0x5a, 0xdd, 0x97, 0x1f, 0x2d, 0xb3, /* @.Z...-. */ -0x5a, 0x02, 0x2e, 0x5d, 0x8d, 0xb2, 0x5b, 0x9b, /* Z..]..[. */ -0x22, 0x02, 0x2e, 0x8d, 0x8c, 0xae, 0x50, 0x02, /* ".....P. */ -0x2e, 0x5d, 0x8d, 0xd5, 0x5b, 0x02, 0x2e, 0x81, /* .]..[... */ -0x8c, 0x58, 0x41, 0x02, 0x5b, 0x01, 0x0c, 0x02, /* .XA.[... */ -0x2e, 0x7b, 0x7c, 0xcd, 0x50, 0x41, 0x2e, 0x52, /* .{|.PA.R */ -0xdf, 0xed, 0x1c, 0x04, 0x18, 0x41, 0x2e, 0x52, /* .....A.R */ -0xbf, 0x05, 0x27, 0x1a, 0x27, 0x56, 0xdf, 0x59, /* ..'.'V.Y */ -0x80, 0xdf, 0x22, 0x00, 0x54, 0x01, 0x16, 0x3f, /* ..".T..? */ -0x1e, 0x00, 0x5f, 0x3f, 0xef, 0x1f, 0x22, 0x1f, /* .._?..". */ -0x22, 0xaf, 0xdf, 0x03, 0x1d, 0x5f, 0x02, 0xaf, /* "...._.. */ -0xbf, 0x05, 0x27, 0x00, 0x2e, 0xa1, 0x8d, 0xae, /* ..'..... */ -0xdf, 0xe0, 0x19, 0xae, 0xbf, 0x57, 0x40, 0x00, /* .....W@. */ -0x5b, 0xa1, 0x32, 0x57, 0x43, 0x00, 0x5b, 0xae, /* [.2WC.[. */ -0x3f, 0xed, 0x80, 0x05, 0x27, 0x41, 0x2e, 0x52, /* ?...'A.R */ -0xdf, 0x03, 0x18, 0x41, 0x2e, 0x52, 0xbf, 0x05, /* ...A.R.. */ -0x27, 0xd3, 0xdf, 0xff, 0x96, 0x9b, 0x22, 0x02, /* '.....". */ -0x2e, 0x12, 0x8d, 0xd3, 0x3c, 0x07, 0x80, 0xdd, /* ....<... */ -0x97, 0xff, 0xaf, 0x00, 0x2e, 0xa7, 0x8a, 0xdd, /* ........ */ -0x9f, 0x10, 0x1d, 0xd3, 0xcf /* ..... */ + 0x42, 0xca, 0x00, + 0xab, 0x2c, 0x05, 0xef, 0xc0, /* B...,... */ + 0xaf, 0x04, 0x27, 0xd0, 0x41, 0x03, 0x5b, 0x02, /* ..'.A.[. */ + 0x2e, 0x9e, 0x8c, 0xf9, 0x5b, 0xbb, 0x50, 0x27, /* ....[.P' */ + 0x82, 0x04, 0xef, 0xc1, 0xaf, 0x9b, 0x22, 0x02, /* ......". */ + 0x2e, 0x12, 0x8d, 0xdd, 0x97, 0xdf, 0x22, 0x02, /* ......". */ + 0x55, 0x58, 0x40, 0x02, 0x5a, 0x0b, 0x50, 0x58, /* UX@.Z.PX */ + 0x40, 0x09, 0x5a, 0xdd, 0x97, 0x1f, 0x2d, 0xb3, /* @.Z...-. */ + 0x5a, 0x02, 0x2e, 0x5d, 0x8d, 0xb2, 0x5b, 0x9b, /* Z..]..[. */ + 0x22, 0x02, 0x2e, 0x8d, 0x8c, 0xae, 0x50, 0x02, /* ".....P. */ + 0x2e, 0x5d, 0x8d, 0xd5, 0x5b, 0x02, 0x2e, 0x81, /* .]..[... */ + 0x8c, 0x58, 0x41, 0x02, 0x5b, 0x01, 0x0c, 0x02, /* .XA.[... */ + 0x2e, 0x7b, 0x7c, 0xcd, 0x50, 0x41, 0x2e, 0x52, /* .{|.PA.R */ + 0xdf, 0xed, 0x1c, 0x04, 0x18, 0x41, 0x2e, 0x52, /* .....A.R */ + 0xbf, 0x05, 0x27, 0x1a, 0x27, 0x56, 0xdf, 0x59, /* ..'.'V.Y */ + 0x80, 0xdf, 0x22, 0x00, 0x54, 0x01, 0x16, 0x3f, /* ..".T..? */ + 0x1e, 0x00, 0x5f, 0x3f, 0xef, 0x1f, 0x22, 0x1f, /* .._?..". */ + 0x22, 0xaf, 0xdf, 0x03, 0x1d, 0x5f, 0x02, 0xaf, /* "...._.. */ + 0xbf, 0x05, 0x27, 0x00, 0x2e, 0xa1, 0x8d, 0xae, /* ..'..... */ + 0xdf, 0xe0, 0x19, 0xae, 0xbf, 0x57, 0x40, 0x00, /* .....W@. */ + 0x5b, 0xa1, 0x32, 0x57, 0x43, 0x00, 0x5b, 0xae, /* [.2WC.[. */ + 0x3f, 0xed, 0x80, 0x05, 0x27, 0x41, 0x2e, 0x52, /* ?...'A.R */ + 0xdf, 0x03, 0x18, 0x41, 0x2e, 0x52, 0xbf, 0x05, /* ...A.R.. */ + 0x27, 0xd3, 0xdf, 0xff, 0x96, 0x9b, 0x22, 0x02, /* '.....". */ + 0x2e, 0x12, 0x8d, 0xd3, 0x3c, 0x07, 0x80, 0xdd, /* ....<... */ + 0x97, 0xff, 0xaf, 0x00, 0x2e, 0xa7, 0x8a, 0xdd, /* ........ */ + 0x9f, 0x10, 0x1d, 0xd3, 0xcf /* ..... */ }; static const unsigned char pkt253[] = { -0x42, 0xb4, 0x00, -0x0f, 0x2d, 0x3f, 0x02, 0xd3, /* B...-?.. */ -0xaf, 0x05, 0x27, 0x37, 0x45, 0x10, 0x5a, 0x02, /* ..'7E.Z. */ -0x2e, 0x5c, 0x8d, 0x0d, 0x5a, 0x02, 0x2e, 0xee, /* .\..Z... */ -0x8c, 0x00, 0x2e, 0xbf, 0x8d, 0x00, 0x2e, 0xd3, /* ........ */ -0x8d, 0x41, 0x2e, 0x52, 0xdf, 0xdf, 0x2d, 0x00, /* .A.R..-. */ -0x5b, 0x00, 0x28, 0x00, 0x2e, 0xd8, 0x8d, 0x05, /* [.(..... */ -0x27, 0xf9, 0xcf, 0xdf, 0x96, 0xf9, 0x3d, 0x01, /* '.....=. */ -0x2e, 0x06, 0x82, 0x2d, 0xff, 0xa7, 0xef, 0xe1, /* ...-.... */ -0xbf, 0xe0, 0xaf, 0x09, 0xef, 0x10, 0xaf, 0x01, /* ........ */ -0x2e, 0x94, 0x86, 0xed, 0x80, 0x01, 0x2e, 0x18, /* ........ */ -0x87, 0x01, 0x2e, 0x1a, 0x87, 0x00, 0x2e, 0x16, /* ........ */ -0x82, 0x5b, 0x82, 0x00, 0x2e, 0x2d, 0x82, 0x26, /* .[...-.& */ -0x37, 0x00, 0x5a, 0x0c, 0x50, 0xff, 0x96, 0xdf, /* 7.Z.P... */ -0x96, 0x79, 0xcf, 0x7a, 0xdf, 0xff, 0x96, 0xdf, /* .y.z.... */ -0x96, 0xc2, 0x97, 0xc3, 0x9f, 0x9d, 0x01, 0x5d, /* .......] */ -0x01, 0x07, 0x53, 0xdd, 0x97, 0xdd, 0x9f, 0x79, /* ..S....y */ -0xaf, 0x7a, 0xbf, 0x3b, 0x3b, 0xdd, 0x97, 0xf9, /* .z.;;... */ -0xaf, 0x05, 0x27, 0xff, 0x22, 0x01, 0x55, 0x32, /* ..'.".U2 */ -0x1e, 0xf3, 0x5f, 0x02, 0x0c, 0x02, 0x2e, 0x4f, /* .._....O */ -0x8d, 0x3b, 0x33, 0x00, 0x28, 0x05, 0x27, 0x0d, /* .;3.(.'. */ -0x27, 0x3c, 0x26, 0x07, 0x54, 0x3c, 0xcf, 0x3d, /* '<&.T<.= */ -0xdf, 0x3f, 0x20, 0x3d, 0xbf, 0xdf, 0x03, 0x01, /* .? =.... */ -0x52, 0x3d, 0x23, 0x0c, 0x27, 0x0d, 0x27 /* R=#.'.' */ + 0x42, 0xb4, 0x00, + 0x0f, 0x2d, 0x3f, 0x02, 0xd3, /* B...-?.. */ + 0xaf, 0x05, 0x27, 0x37, 0x45, 0x10, 0x5a, 0x02, /* ..'7E.Z. */ + 0x2e, 0x5c, 0x8d, 0x0d, 0x5a, 0x02, 0x2e, 0xee, /* .\..Z... */ + 0x8c, 0x00, 0x2e, 0xbf, 0x8d, 0x00, 0x2e, 0xd3, /* ........ */ + 0x8d, 0x41, 0x2e, 0x52, 0xdf, 0xdf, 0x2d, 0x00, /* .A.R..-. */ + 0x5b, 0x00, 0x28, 0x00, 0x2e, 0xd8, 0x8d, 0x05, /* [.(..... */ + 0x27, 0xf9, 0xcf, 0xdf, 0x96, 0xf9, 0x3d, 0x01, /* '.....=. */ + 0x2e, 0x06, 0x82, 0x2d, 0xff, 0xa7, 0xef, 0xe1, /* ...-.... */ + 0xbf, 0xe0, 0xaf, 0x09, 0xef, 0x10, 0xaf, 0x01, /* ........ */ + 0x2e, 0x94, 0x86, 0xed, 0x80, 0x01, 0x2e, 0x18, /* ........ */ + 0x87, 0x01, 0x2e, 0x1a, 0x87, 0x00, 0x2e, 0x16, /* ........ */ + 0x82, 0x5b, 0x82, 0x00, 0x2e, 0x2d, 0x82, 0x26, /* .[...-.& */ + 0x37, 0x00, 0x5a, 0x0c, 0x50, 0xff, 0x96, 0xdf, /* 7.Z.P... */ + 0x96, 0x79, 0xcf, 0x7a, 0xdf, 0xff, 0x96, 0xdf, /* .y.z.... */ + 0x96, 0xc2, 0x97, 0xc3, 0x9f, 0x9d, 0x01, 0x5d, /* .......] */ + 0x01, 0x07, 0x53, 0xdd, 0x97, 0xdd, 0x9f, 0x79, /* ..S....y */ + 0xaf, 0x7a, 0xbf, 0x3b, 0x3b, 0xdd, 0x97, 0xf9, /* .z.;;... */ + 0xaf, 0x05, 0x27, 0xff, 0x22, 0x01, 0x55, 0x32, /* ..'.".U2 */ + 0x1e, 0xf3, 0x5f, 0x02, 0x0c, 0x02, 0x2e, 0x4f, /* .._....O */ + 0x8d, 0x3b, 0x33, 0x00, 0x28, 0x05, 0x27, 0x0d, /* .;3.(.'. */ + 0x27, 0x3c, 0x26, 0x07, 0x54, 0x3c, 0xcf, 0x3d, /* '<&.T<.= */ + 0xdf, 0x3f, 0x20, 0x3d, 0xbf, 0xdf, 0x03, 0x01, /* .? =.... */ + 0x52, 0x3d, 0x23, 0x0c, 0x27, 0x0d, 0x27 /* R=#.'.' */ }; static const unsigned char pkt255[] = { -0x42, 0x1a, 0x00, -0x68, 0x2d, 0x09, 0x43, 0x04, /* B..h-.C. */ -0x5b, 0x00, 0xef, 0xf8, 0xaf, 0x32, 0xef, 0xfa, /* [....2.. */ -0xaf, 0x03, 0x50, 0x01, 0xef, 0xf8, 0xaf, 0x42, /* ..P....B */ -0xef, 0xfa, 0xaf, 0x05, 0x27 /* ....' */ + 0x42, 0x1a, 0x00, + 0x68, 0x2d, 0x09, 0x43, 0x04, /* B..h-.C. */ + 0x5b, 0x00, 0xef, 0xf8, 0xaf, 0x32, 0xef, 0xfa, /* [....2.. */ + 0xaf, 0x03, 0x50, 0x01, 0xef, 0xf8, 0xaf, 0x42, /* ..P....B */ + 0xef, 0xfa, 0xaf, 0x05, 0x27 /* ....' */ }; static const unsigned char pkt257[] = { -0x42, 0x26, 0x00, -0x74, 0x2d, 0xd3, 0x45, 0xfd, /* B&.t-.E. */ -0x5a, 0x0f, 0x27, 0xd3, 0x45, 0xfa, 0x5a, 0x0f, /* Z.'.E.Z. */ -0x27, 0xd3, 0x45, 0xf7, 0x5a, 0x0f, 0x27, 0x41, /* '.E.Z.'A */ -0x2e, 0xa1, 0xdf, 0x9f, 0x28, 0x41, 0x2e, 0xa1, /* ....(A.. */ -0xbf, 0x02, 0x2e, 0x58, 0x80, 0x00, 0x2e, 0xcb, /* ...X.... */ -0x7a /* z */ + 0x42, 0x26, 0x00, + 0x74, 0x2d, 0xd3, 0x45, 0xfd, /* B&.t-.E. */ + 0x5a, 0x0f, 0x27, 0xd3, 0x45, 0xfa, 0x5a, 0x0f, /* Z.'.E.Z. */ + 0x27, 0xd3, 0x45, 0xf7, 0x5a, 0x0f, 0x27, 0x41, /* '.E.Z.'A */ + 0x2e, 0xa1, 0xdf, 0x9f, 0x28, 0x41, 0x2e, 0xa1, /* ....(A.. */ + 0xbf, 0x02, 0x2e, 0x58, 0x80, 0x00, 0x2e, 0xcb, /* ...X.... */ + 0x7a /* z */ }; static const unsigned char pkt259[] = { -0x42, 0x16, 0x00, -0x86, 0x2d, 0xd3, 0x45, 0x02, /* B...-.E. */ -0x5a, 0xd3, 0x45, 0x00, 0x5a, 0x05, 0x27, 0xd0, /* Z.E.Z.'. */ -0x41, 0xf8, 0x5b, 0xed, 0x83, 0xf6, 0x50, 0x05, /* A.[...P. */ -0x27 /* ' */ + 0x42, 0x16, 0x00, + 0x86, 0x2d, 0xd3, 0x45, 0x02, /* B...-.E. */ + 0x5a, 0xd3, 0x45, 0x00, 0x5a, 0x05, 0x27, 0xd0, /* Z.E.Z.'. */ + 0x41, 0xf8, 0x5b, 0xed, 0x83, 0xf6, 0x50, 0x05, /* A.[...P. */ + 0x27 /* ' */ }; static const unsigned char pkt261[] = { -0x42, 0x4e, 0x00, -0x90, 0x2d, 0x07, 0x3d, 0x02, /* BN..-.=. */ -0x5b, 0xae, 0x87, 0xc2, 0x23, 0xd3, 0x3c, 0x02, /* [...#.<. */ -0x44, 0xd4, 0x2f, 0xf8, 0x5a, 0x02, 0x45, 0xd5, /* D./.Z.E. */ -0x2f, 0x59, 0x5b, 0x58, 0x23, 0x3c, 0x26, 0x02, /* /Y[X#<&. */ -0x55, 0x02, 0x2e, 0x4f, 0x8c, 0x00, 0x50, 0xff, /* U..O..P. */ -0x8e, 0x07, 0x45, 0xeb, 0x5a, 0x41, 0x2e, 0x53, /* ..E.ZA.S */ -0xdf, 0xc1, 0x2e, 0x79, 0xdf, 0xff, 0x96, 0xdf, /* ...y.... */ -0x96, 0x41, 0x2e, 0x55, 0xdf, 0xc1, 0x2e, 0x78, /* .A.U...x */ -0xdf, 0x9d, 0x01, 0x5d, 0x01, 0xff, 0x22, 0x00, /* ...]..". */ -0x54, 0xff, 0xef, 0x2e, 0xaf, 0xd5, 0x2f, 0x3e, /* T...../> */ -0x50 /* P */ + 0x42, 0x4e, 0x00, + 0x90, 0x2d, 0x07, 0x3d, 0x02, /* BN..-.=. */ + 0x5b, 0xae, 0x87, 0xc2, 0x23, 0xd3, 0x3c, 0x02, /* [...#.<. */ + 0x44, 0xd4, 0x2f, 0xf8, 0x5a, 0x02, 0x45, 0xd5, /* D./.Z.E. */ + 0x2f, 0x59, 0x5b, 0x58, 0x23, 0x3c, 0x26, 0x02, /* /Y[X#<&. */ + 0x55, 0x02, 0x2e, 0x4f, 0x8c, 0x00, 0x50, 0xff, /* U..O..P. */ + 0x8e, 0x07, 0x45, 0xeb, 0x5a, 0x41, 0x2e, 0x53, /* ..E.ZA.S */ + 0xdf, 0xc1, 0x2e, 0x79, 0xdf, 0xff, 0x96, 0xdf, /* ...y.... */ + 0x96, 0x41, 0x2e, 0x55, 0xdf, 0xc1, 0x2e, 0x78, /* .A.U...x */ + 0xdf, 0x9d, 0x01, 0x5d, 0x01, 0xff, 0x22, 0x00, /* ...]..". */ + 0x54, 0xff, 0xef, 0x2e, 0xaf, 0xd5, 0x2f, 0x3e, /* T...../> */ + 0x50 /* P */ }; static const unsigned char pkt263[] = { -0x42, 0xca, 0x00, -0xb6, 0x2d, 0xfa, 0xcf, 0xdf, /* B...-... */ -0x96, 0x37, 0xcf, 0xdf, 0x96, 0x08, 0xcf, 0xdf, /* .7...... */ -0x96, 0x3d, 0xcf, 0xdf, 0x96, 0x77, 0xcf, 0xdf, /* .=...w.. */ -0x96, 0x26, 0xcf, 0xdf, 0x96, 0x26, 0x23, 0x01, /* .&...&#. */ -0x2e, 0x08, 0x82, 0xdd, 0x97, 0x26, 0xaf, 0xdd, /* .....&.. */ -0x97, 0x77, 0xaf, 0xdd, 0x97, 0x3d, 0xaf, 0xdd, /* .w...=.. */ -0x97, 0x08, 0xaf, 0xdd, 0x97, 0x37, 0xaf, 0xdd, /* .....7.. */ -0x97, 0xfa, 0xaf, 0x9f, 0x22, 0x6d, 0x2e, 0x6d, /* ...."m.m */ -0xbf, 0x26, 0x40, 0x3a, 0x5b, 0x73, 0x43, 0x08, /* .&@:[sC. */ -0x5b, 0x73, 0xcf, 0x09, 0x27, 0x0f, 0x1c, 0x10, /* [s..'... */ -0xaf, 0x82, 0xcf, 0x01, 0x2e, 0xf9, 0x81, 0xed, /* ........ */ -0x80, 0x05, 0x50, 0x81, 0xcf, 0x10, 0xaf, 0x82, /* ..P..... */ -0xcf, 0x01, 0x2e, 0xf9, 0x81, 0xed, 0x80, 0xc8, /* ........ */ -0xef, 0x0f, 0xaf, 0x08, 0x31, 0x31, 0xef, 0x0a, /* ....11.. */ -0xaf, 0x9f, 0x22, 0x0d, 0xaf, 0x81, 0xcf, 0x10, /* .."..... */ -0xaf, 0x01, 0x2e, 0x94, 0x86, 0x82, 0xcf, 0x04, /* ........ */ -0x16, 0x01, 0x2e, 0xf9, 0x81, 0xed, 0x80, 0x10, /* ........ */ -0xcf, 0xb0, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x00, /* ...?.... */ -0x13, 0x1a, 0x27, 0xd6, 0x97, 0x82, 0xdf, 0xbf, /* ..'..... */ -0x01, 0x6d, 0x2e, 0x6d, 0xbf, 0x74, 0xcf, 0x02, /* .m.m.t.. */ -0x1e, 0x04, 0x55, 0xa0, 0xcf, 0xcf, 0x1c, 0x10, /* ..U..... */ -0x18, 0xa0, 0xaf, 0x05, 0x50, 0x01, 0x1e, 0x04, /* ....P... */ -0x55, 0xa0, 0xcf, 0xcf, 0x1c, 0x20, 0x18, 0xa0, /* U.... .. */ -0xaf, 0xed, 0x80, 0xfb, 0x39, 0x08, 0x45, 0x00, /* ....9.E. */ -0x5a, 0xfb, 0x31, 0x0a, 0x42, 0x00, 0x5b, 0xa2, /* Z.1.B.[. */ -0x39, 0x02, 0xcf, 0x5c, 0xaf /* 9..\. */ + 0x42, 0xca, 0x00, + 0xb6, 0x2d, 0xfa, 0xcf, 0xdf, /* B...-... */ + 0x96, 0x37, 0xcf, 0xdf, 0x96, 0x08, 0xcf, 0xdf, /* .7...... */ + 0x96, 0x3d, 0xcf, 0xdf, 0x96, 0x77, 0xcf, 0xdf, /* .=...w.. */ + 0x96, 0x26, 0xcf, 0xdf, 0x96, 0x26, 0x23, 0x01, /* .&...&#. */ + 0x2e, 0x08, 0x82, 0xdd, 0x97, 0x26, 0xaf, 0xdd, /* .....&.. */ + 0x97, 0x77, 0xaf, 0xdd, 0x97, 0x3d, 0xaf, 0xdd, /* .w...=.. */ + 0x97, 0x08, 0xaf, 0xdd, 0x97, 0x37, 0xaf, 0xdd, /* .....7.. */ + 0x97, 0xfa, 0xaf, 0x9f, 0x22, 0x6d, 0x2e, 0x6d, /* ...."m.m */ + 0xbf, 0x26, 0x40, 0x3a, 0x5b, 0x73, 0x43, 0x08, /* .&@:[sC. */ + 0x5b, 0x73, 0xcf, 0x09, 0x27, 0x0f, 0x1c, 0x10, /* [s..'... */ + 0xaf, 0x82, 0xcf, 0x01, 0x2e, 0xf9, 0x81, 0xed, /* ........ */ + 0x80, 0x05, 0x50, 0x81, 0xcf, 0x10, 0xaf, 0x82, /* ..P..... */ + 0xcf, 0x01, 0x2e, 0xf9, 0x81, 0xed, 0x80, 0xc8, /* ........ */ + 0xef, 0x0f, 0xaf, 0x08, 0x31, 0x31, 0xef, 0x0a, /* ....11.. */ + 0xaf, 0x9f, 0x22, 0x0d, 0xaf, 0x81, 0xcf, 0x10, /* .."..... */ + 0xaf, 0x01, 0x2e, 0x94, 0x86, 0x82, 0xcf, 0x04, /* ........ */ + 0x16, 0x01, 0x2e, 0xf9, 0x81, 0xed, 0x80, 0x10, /* ........ */ + 0xcf, 0xb0, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x00, /* ...?.... */ + 0x13, 0x1a, 0x27, 0xd6, 0x97, 0x82, 0xdf, 0xbf, /* ..'..... */ + 0x01, 0x6d, 0x2e, 0x6d, 0xbf, 0x74, 0xcf, 0x02, /* .m.m.t.. */ + 0x1e, 0x04, 0x55, 0xa0, 0xcf, 0xcf, 0x1c, 0x10, /* ..U..... */ + 0x18, 0xa0, 0xaf, 0x05, 0x50, 0x01, 0x1e, 0x04, /* ....P... */ + 0x55, 0xa0, 0xcf, 0xcf, 0x1c, 0x20, 0x18, 0xa0, /* U.... .. */ + 0xaf, 0xed, 0x80, 0xfb, 0x39, 0x08, 0x45, 0x00, /* ....9.E. */ + 0x5a, 0xfb, 0x31, 0x0a, 0x42, 0x00, 0x5b, 0xa2, /* Z.1.B.[. */ + 0x39, 0x02, 0xcf, 0x5c, 0xaf /* 9..\. */ }; static const unsigned char pkt265[] = { -0x42, 0x96, 0x00, -0x1a, 0x2e, 0xe1, 0xef, 0x95, /* B....... */ -0xaf, 0x9f, 0x22, 0x61, 0xaf, 0x62, 0xaf, 0x69, /* .."a.b.i */ -0xaf, 0x6a, 0xaf, 0x16, 0xaf, 0x96, 0xaf, 0x29, /* .j.....) */ -0xaf, 0x28, 0xaf, 0xc1, 0x2e, 0x49, 0xdf, 0x3f, /* .(...I.? */ -0x2d, 0x03, 0x5b, 0xa0, 0xcf, 0x8f, 0x1c, 0x20, /* -.[.... */ -0x18, 0xa0, 0xaf, 0xa1, 0xcf, 0xdf, 0x1c, 0xa1, /* ........ */ -0xaf, 0xed, 0x80, 0x02, 0x47, 0x06, 0x5a, 0x0a, /* ....G.Z. */ -0x41, 0x04, 0x5a, 0x0a, 0xdf, 0x30, 0x1d, 0x30, /* A.Z..0.0 */ -0x1f, 0x00, 0x54, 0x01, 0xef, 0x44, 0xaf, 0x09, /* ..T..D.. */ -0xef, 0x60, 0xaf, 0xa7, 0xef, 0x40, 0xaf, 0x2d, /* .`...@.- */ -0xef, 0x41, 0xaf, 0x0a, 0x40, 0x06, 0x5a, 0x10, /* .A..@.Z. */ -0xcf, 0x27, 0xaf, 0xe2, 0x23, 0x6e, 0x23, 0x08, /* .'..#n#. */ -0xef, 0xe3, 0xaf, 0x6f, 0xaf, 0xe2, 0x23, 0x08, /* ...o..#. */ -0xef, 0xe3, 0xaf, 0x79, 0x82, 0x4d, 0xaf, 0xdf, /* ...y.M.. */ -0x96, 0x64, 0xdf, 0x8b, 0x82, 0x93, 0xbf, 0xdd, /* .d...... */ -0x97, 0x77, 0xff, 0x8b, 0x82, 0x94, 0xbf, 0x9e, /* .w...... */ -0x23, 0xe4, 0x23, 0x9f, 0x22, 0x6d, 0x2e, 0x6b, /* #.#."m.k */ -0xbf, 0x6d, 0x2e, 0x6a, 0xbf, 0x6d, 0x2e, 0x6c, /* .m.j.m.l */ -0xbf, 0xa5, 0xcf, 0xf3, 0x1c, 0xa5, 0xaf, 0x05, /* ........ */ -0x27 /* ' */ + 0x42, 0x96, 0x00, + 0x1a, 0x2e, 0xe1, 0xef, 0x95, /* B....... */ + 0xaf, 0x9f, 0x22, 0x61, 0xaf, 0x62, 0xaf, 0x69, /* .."a.b.i */ + 0xaf, 0x6a, 0xaf, 0x16, 0xaf, 0x96, 0xaf, 0x29, /* .j.....) */ + 0xaf, 0x28, 0xaf, 0xc1, 0x2e, 0x49, 0xdf, 0x3f, /* .(...I.? */ + 0x2d, 0x03, 0x5b, 0xa0, 0xcf, 0x8f, 0x1c, 0x20, /* -.[.... */ + 0x18, 0xa0, 0xaf, 0xa1, 0xcf, 0xdf, 0x1c, 0xa1, /* ........ */ + 0xaf, 0xed, 0x80, 0x02, 0x47, 0x06, 0x5a, 0x0a, /* ....G.Z. */ + 0x41, 0x04, 0x5a, 0x0a, 0xdf, 0x30, 0x1d, 0x30, /* A.Z..0.0 */ + 0x1f, 0x00, 0x54, 0x01, 0xef, 0x44, 0xaf, 0x09, /* ..T..D.. */ + 0xef, 0x60, 0xaf, 0xa7, 0xef, 0x40, 0xaf, 0x2d, /* .`...@.- */ + 0xef, 0x41, 0xaf, 0x0a, 0x40, 0x06, 0x5a, 0x10, /* .A..@.Z. */ + 0xcf, 0x27, 0xaf, 0xe2, 0x23, 0x6e, 0x23, 0x08, /* .'..#n#. */ + 0xef, 0xe3, 0xaf, 0x6f, 0xaf, 0xe2, 0x23, 0x08, /* ...o..#. */ + 0xef, 0xe3, 0xaf, 0x79, 0x82, 0x4d, 0xaf, 0xdf, /* ...y.M.. */ + 0x96, 0x64, 0xdf, 0x8b, 0x82, 0x93, 0xbf, 0xdd, /* .d...... */ + 0x97, 0x77, 0xff, 0x8b, 0x82, 0x94, 0xbf, 0x9e, /* .w...... */ + 0x23, 0xe4, 0x23, 0x9f, 0x22, 0x6d, 0x2e, 0x6b, /* #.#."m.k */ + 0xbf, 0x6d, 0x2e, 0x6a, 0xbf, 0x6d, 0x2e, 0x6c, /* .m.j.m.l */ + 0xbf, 0xa5, 0xcf, 0xf3, 0x1c, 0xa5, 0xaf, 0x05, /* ........ */ + 0x27 /* ' */ }; static const unsigned char pkt267[] = { -0x42, 0x2c, 0x00, -0x64, 0x2e, 0xf9, 0x32, 0xf9, /* B,.d..2. */ -0x3a, 0xaf, 0xef, 0x00, 0xff, 0x1b, 0x27, 0xf6, /* :.....'. */ -0x97, 0xcf, 0xaf, 0x0f, 0xef, 0x06, 0xaf, 0xce, /* ........ */ -0x30, 0x0f, 0x27, 0x0f, 0x27, 0xfa, 0x97, 0xcf, /* 0.'.'... */ -0xaf, 0xce, 0x32, 0x06, 0x25, 0xf8, 0x55, 0xce, /* ..2.%.U. */ -0x43, 0xfd, 0x5b, 0xce, 0x31, 0x05, 0x27 /* C.[.1.' */ + 0x42, 0x2c, 0x00, + 0x64, 0x2e, 0xf9, 0x32, 0xf9, /* B,.d..2. */ + 0x3a, 0xaf, 0xef, 0x00, 0xff, 0x1b, 0x27, 0xf6, /* :.....'. */ + 0x97, 0xcf, 0xaf, 0x0f, 0xef, 0x06, 0xaf, 0xce, /* ........ */ + 0x30, 0x0f, 0x27, 0x0f, 0x27, 0xfa, 0x97, 0xcf, /* 0.'.'... */ + 0xaf, 0xce, 0x32, 0x06, 0x25, 0xf8, 0x55, 0xce, /* ..2.%.U. */ + 0x43, 0xfd, 0x5b, 0xce, 0x31, 0x05, 0x27 /* C.[.1.' */ }; static const unsigned char pkt269[] = { -0x42, 0x26, 0x00, -0x79, 0x2e, 0xbf, 0x22, 0xff, /* B&.y..". */ -0xef, 0x1b, 0x27, 0xdd, 0x97, 0xdd, 0x9f, 0x06, /* ..'..... */ -0xaf, 0x4e, 0xbf, 0xff, 0x22, 0x04, 0x54, 0xbd, /* .N..".T. */ -0x9d, 0x06, 0x25, 0xfc, 0x53, 0x4e, 0x25, 0xfa, /* ..%.SN%. */ -0x55, 0xbd, 0x9d, 0x06, 0x25, 0xfc, 0x55, 0x05, /* U...%.U. */ -0x27 /* ' */ + 0x42, 0x26, 0x00, + 0x79, 0x2e, 0xbf, 0x22, 0xff, /* B&.y..". */ + 0xef, 0x1b, 0x27, 0xdd, 0x97, 0xdd, 0x9f, 0x06, /* ..'..... */ + 0xaf, 0x4e, 0xbf, 0xff, 0x22, 0x04, 0x54, 0xbd, /* .N..".T. */ + 0x9d, 0x06, 0x25, 0xfc, 0x53, 0x4e, 0x25, 0xfa, /* ..%.SN%. */ + 0x55, 0xbd, 0x9d, 0x06, 0x25, 0xfc, 0x55, 0x05, /* U...%.U. */ + 0x27 /* ' */ }; static const unsigned char pkt271[] = { -0x42, 0x3c, 0x00, -0x8b, 0x2e, 0xbf, 0x22, 0xff, /* B<....". */ -0xef, 0x1b, 0x27, 0xdc, 0x99, 0x28, 0x28, 0x28, /* ..'..((( */ -0x2a, 0x68, 0x2c, 0xfd, 0x5b, 0xa9, 0x9d, 0x6a, /* *h,.[..j */ -0x28, 0x06, 0x25, 0xf6, 0x53, 0x4e, 0x25, 0xf4, /* (.%.SN%. */ -0x55, 0xdc, 0x99, 0x28, 0x28, 0x28, 0x2a, 0x68, /* U..(((*h */ -0x2c, 0xfd, 0x5b, 0xa9, 0x9d, 0x6a, 0x28, 0x06, /* ,.[..j(. */ -0x25, 0xf6, 0x55, 0x01, 0x2e, 0xe4, 0x85, 0xbf, /* %.U..... */ -0x22, 0xbf, 0x99, 0x7f, 0x99, 0x05, 0x27 /* ".....' */ + 0x42, 0x3c, 0x00, + 0x8b, 0x2e, 0xbf, 0x22, 0xff, /* B<....". */ + 0xef, 0x1b, 0x27, 0xdc, 0x99, 0x28, 0x28, 0x28, /* ..'..((( */ + 0x2a, 0x68, 0x2c, 0xfd, 0x5b, 0xa9, 0x9d, 0x6a, /* *h,.[..j */ + 0x28, 0x06, 0x25, 0xf6, 0x53, 0x4e, 0x25, 0xf4, /* (.%.SN%. */ + 0x55, 0xdc, 0x99, 0x28, 0x28, 0x28, 0x2a, 0x68, /* U..(((*h */ + 0x2c, 0xfd, 0x5b, 0xa9, 0x9d, 0x6a, 0x28, 0x06, /* ,.[..j(. */ + 0x25, 0xf6, 0x55, 0x01, 0x2e, 0xe4, 0x85, 0xbf, /* %.U..... */ + 0x22, 0xbf, 0x99, 0x7f, 0x99, 0x05, 0x27 /* ".....' */ }; static const unsigned char pkt273[] = { -0x67, 0x05, 0x00, 0x00, 0x02, 0x2e, 0x00, 0x70, /* g......p */ -0x67, 0x05, 0x00, 0x02, 0x02, 0x2e, 0x88, 0x70, /* g......p */ -0x67, 0x05, 0x00, 0x01, 0x02, 0x2e, 0x3c, 0x71, /* g.....id = "aes3500"; - dev_class->full_name = "AuthenTec AES3500"; - dev_class->id_table = id_table; + dev_class->id = "aes3500"; + dev_class->full_name = "AuthenTec AES3500"; + dev_class->id_table = id_table; - img_class->img_height = FRAME_WIDTH * ENLARGE_FACTOR; - img_class->img_width = FRAME_WIDTH * ENLARGE_FACTOR; + img_class->img_height = FRAME_WIDTH * ENLARGE_FACTOR; + img_class->img_width = FRAME_WIDTH * ENLARGE_FACTOR; - aes_class->data_buflen = DATA_BUFLEN; - aes_class->frame_width = FRAME_WIDTH; - aes_class->frame_size = FRAME_SIZE; - aes_class->frame_number = FRAME_NUMBER; - aes_class->enlarge_factor = ENLARGE_FACTOR; - aes_class->init_reqs = init_reqs; - aes_class->init_reqs_len = G_N_ELEMENTS(init_reqs); + aes_class->data_buflen = DATA_BUFLEN; + aes_class->frame_width = FRAME_WIDTH; + aes_class->frame_size = FRAME_SIZE; + aes_class->frame_number = FRAME_NUMBER; + aes_class->enlarge_factor = ENLARGE_FACTOR; + aes_class->init_reqs = init_reqs; + aes_class->init_reqs_len = G_N_ELEMENTS (init_reqs); } diff --git a/libfprint/drivers/aes3k.c b/libfprint/drivers/aes3k.c index 9c120bd8..f73ac026 100644 --- a/libfprint/drivers/aes3k.c +++ b/libfprint/drivers/aes3k.c @@ -40,169 +40,188 @@ #include "aeslib.h" #include "aes3k.h" -typedef struct { - FpiUsbTransfer *img_trf; - gboolean deactivating; +typedef struct +{ + FpiUsbTransfer *img_trf; + gboolean deactivating; } FpiDeviceAes3kPrivate; -#define CTRL_TIMEOUT 1000 -#define EP_IN (1 | FPI_USB_ENDPOINT_IN) -#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) +#define CTRL_TIMEOUT 1000 +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) -static void do_capture(FpImageDevice *dev); +static void do_capture (FpImageDevice *dev); -G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(FpiDeviceAes3k, fpi_device_aes3k, FP_TYPE_IMAGE_DEVICE); +G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (FpiDeviceAes3k, fpi_device_aes3k, FP_TYPE_IMAGE_DEVICE); -static void aes3k_assemble_image(unsigned char *input, size_t width, size_t height, - unsigned char *output) +static void +aes3k_assemble_image (unsigned char *input, size_t width, size_t height, + unsigned char *output) { - size_t row, column; + size_t row, column; - for (column = 0; column < width; column++) { - for (row = 0; row < height; row += 2) { - output[width * row + column] = (*input & 0x0f) * 17; - output[width * (row + 1) + column] = ((*input & 0xf0) >> 4) * 17; - input++; - } - } + for (column = 0; column < width; column++) + { + for (row = 0; row < height; row += 2) + { + output[width * row + column] = (*input & 0x0f) * 17; + output[width * (row + 1) + column] = ((*input & 0xf0) >> 4) * 17; + input++; + } + } } -static void img_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +img_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE (device); - FpiDeviceAes3k *self = FPI_DEVICE_AES3K (device); - FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self); - FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self); - unsigned char *ptr = transfer->buffer; - FpImage *tmp; - FpImage *img; - int i; + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpiDeviceAes3k *self = FPI_DEVICE_AES3K (device); + FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self); + FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self); + unsigned char *ptr = transfer->buffer; + FpImage *tmp; + FpImage *img; + int i; - priv->img_trf = NULL; + priv->img_trf = NULL; - if (error) { - if (g_error_matches (error, - G_IO_ERROR, - G_IO_ERROR_CANCELLED)) { - /* Deactivation was completed. */ - g_error_free (error); - if (priv->deactivating) - fpi_image_device_deactivate_complete(dev, NULL); - return; - } + if (error) + { + if (g_error_matches (error, + G_IO_ERROR, + G_IO_ERROR_CANCELLED)) + { + /* Deactivation was completed. */ + g_error_free (error); + if (priv->deactivating) + fpi_image_device_deactivate_complete (dev, NULL); + return; + } - fpi_image_device_session_error (dev, error); - } + fpi_image_device_session_error (dev, error); + } - fpi_image_device_report_finger_status(dev, TRUE); + fpi_image_device_report_finger_status (dev, TRUE); - tmp = fp_image_new(cls->frame_width, cls->frame_width); - tmp->width = cls->frame_width; - tmp->height = cls->frame_width; - tmp->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED; - for (i = 0; i < cls->frame_number; i++) { - fp_dbg("frame header byte %02x", *ptr); - ptr++; - aes3k_assemble_image(ptr, cls->frame_width, AES3K_FRAME_HEIGHT, tmp->data + (i * cls->frame_width * AES3K_FRAME_HEIGHT)); - ptr += cls->frame_size; - } + tmp = fp_image_new (cls->frame_width, cls->frame_width); + tmp->width = cls->frame_width; + tmp->height = cls->frame_width; + tmp->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED; + for (i = 0; i < cls->frame_number; i++) + { + fp_dbg ("frame header byte %02x", *ptr); + ptr++; + aes3k_assemble_image (ptr, cls->frame_width, AES3K_FRAME_HEIGHT, tmp->data + (i * cls->frame_width * AES3K_FRAME_HEIGHT)); + ptr += cls->frame_size; + } - /* FIXME: this is an ugly hack to make the image big enough for NBIS - * to process reliably */ - img = fpi_image_resize(tmp, cls->enlarge_factor, cls->enlarge_factor); - g_object_unref (tmp); - fpi_image_device_image_captured(dev, img); + /* FIXME: this is an ugly hack to make the image big enough for NBIS + * to process reliably */ + img = fpi_image_resize (tmp, cls->enlarge_factor, cls->enlarge_factor); + g_object_unref (tmp); + fpi_image_device_image_captured (dev, img); - /* FIXME: rather than assuming finger has gone, we should poll regs until - * it really has, then restart the capture */ - fpi_image_device_report_finger_status(dev, FALSE); + /* FIXME: rather than assuming finger has gone, we should poll regs until + * it really has, then restart the capture */ + fpi_image_device_report_finger_status (dev, FALSE); - do_capture(dev); + do_capture (dev); } -static void do_capture(FpImageDevice *dev) +static void +do_capture (FpImageDevice *dev) { - FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev); - FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self); - FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self); + FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev); + FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self); + FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self); - priv->img_trf = fpi_usb_transfer_new (FP_DEVICE (dev)); - fpi_usb_transfer_fill_bulk(priv->img_trf, EP_IN, cls->data_buflen); - priv->img_trf->short_is_error = TRUE; - fpi_usb_transfer_submit(priv->img_trf, 0, - fpi_device_get_cancellable (FP_DEVICE (dev)), - img_cb, NULL); - fpi_usb_transfer_unref(priv->img_trf); + priv->img_trf = fpi_usb_transfer_new (FP_DEVICE (dev)); + fpi_usb_transfer_fill_bulk (priv->img_trf, EP_IN, cls->data_buflen); + priv->img_trf->short_is_error = TRUE; + fpi_usb_transfer_submit (priv->img_trf, 0, + fpi_device_get_cancellable (FP_DEVICE (dev)), + img_cb, NULL); + fpi_usb_transfer_unref (priv->img_trf); } -static void init_reqs_cb(FpImageDevice *dev, GError *result, void *user_data) +static void +init_reqs_cb (FpImageDevice *dev, GError *result, void *user_data) { - fpi_image_device_activate_complete (dev, result); - if (!result) - do_capture(dev); + fpi_image_device_activate_complete (dev, result); + if (!result) + do_capture (dev); } -static void aes3k_dev_activate(FpImageDevice *dev) +static void +aes3k_dev_activate (FpImageDevice *dev) { - FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev); - FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self); - FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self); + FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev); + FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self); + FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self); - priv->deactivating = FALSE; - aes_write_regv(dev, cls->init_reqs, cls->init_reqs_len, init_reqs_cb, NULL); + priv->deactivating = FALSE; + aes_write_regv (dev, cls->init_reqs, cls->init_reqs_len, init_reqs_cb, NULL); } -static void aes3k_dev_deactivate(FpImageDevice *dev) +static void +aes3k_dev_deactivate (FpImageDevice *dev) { - FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev); - FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self); + FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev); + FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self); - priv->deactivating = TRUE; - if (priv->img_trf) - return; - fpi_image_device_deactivate_complete(dev, NULL); + priv->deactivating = TRUE; + if (priv->img_trf) + return; + fpi_image_device_deactivate_complete (dev, NULL); } -static void fpi_device_aes3k_init(FpiDeviceAes3k *self) { -} - -static void aes3k_dev_init(FpImageDevice *dev) +static void +fpi_device_aes3k_init (FpiDeviceAes3k *self) { - GError *error = NULL; - - if (!g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error)) { - fpi_image_device_open_complete(dev, error); - return; - } - - fpi_image_device_open_complete(dev, NULL); } -static void aes3k_dev_deinit(FpImageDevice *dev) +static void +aes3k_dev_init (FpImageDevice *dev) { - GError *error = NULL; + GError *error = NULL; - g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), - 0, 0, &error); - fpi_image_device_close_complete(dev, error); + if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error)) + { + fpi_image_device_open_complete (dev, error); + return; + } + + fpi_image_device_open_complete (dev, NULL); +} + +static void +aes3k_dev_deinit (FpImageDevice *dev) +{ + GError *error = NULL; + + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), + 0, 0, &error); + fpi_image_device_close_complete (dev, error); } -static void fpi_device_aes3k_class_init(FpiDeviceAes3kClass *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); +static void +fpi_device_aes3k_class_init (FpiDeviceAes3kClass *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->scan_type = FP_SCAN_TYPE_PRESS; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->scan_type = FP_SCAN_TYPE_PRESS; - img_class->img_open = aes3k_dev_init; - img_class->img_close = aes3k_dev_deinit; - img_class->activate = aes3k_dev_activate; - img_class->deactivate = aes3k_dev_deactivate; + img_class->img_open = aes3k_dev_init; + img_class->img_close = aes3k_dev_deinit; + img_class->activate = aes3k_dev_activate; + img_class->deactivate = aes3k_dev_deactivate; - /* Extremely low due to low image quality. */ - img_class->bz3_threshold = 9; + /* Extremely low due to low image quality. */ + img_class->bz3_threshold = 9; - /* Everything else is set by the subclasses. */ + /* Everything else is set by the subclasses. */ } diff --git a/libfprint/drivers/aes3k.h b/libfprint/drivers/aes3k.h index ac491b7a..539f4e11 100644 --- a/libfprint/drivers/aes3k.h +++ b/libfprint/drivers/aes3k.h @@ -38,22 +38,23 @@ #include "fpi-image-device.h" #include "aeslib.h" -#define AES3K_FRAME_HEIGHT 16 +#define AES3K_FRAME_HEIGHT 16 -G_DECLARE_DERIVABLE_TYPE(FpiDeviceAes3k, fpi_device_aes3k, FPI, - DEVICE_AES3K, FpImageDevice) +G_DECLARE_DERIVABLE_TYPE (FpiDeviceAes3k, fpi_device_aes3k, FPI, + DEVICE_AES3K, FpImageDevice) #define FPI_TYPE_DEVICE_AES3K (fpi_device_aes3k_get_type ()) -struct _FpiDeviceAes3kClass { - FpImageDeviceClass parent; +struct _FpiDeviceAes3kClass +{ + FpImageDeviceClass parent; - gsize frame_width; /* image size = frame_width x frame_width */ - gsize frame_size; /* 4 bits/pixel: frame_width x AES3K_FRAME_HEIGHT / 2 */ - gsize frame_number; /* number of frames */ - gsize enlarge_factor; + gsize frame_width; /* image size = frame_width x frame_width */ + gsize frame_size; /* 4 bits/pixel: frame_width x AES3K_FRAME_HEIGHT / 2 */ + gsize frame_number; /* number of frames */ + gsize enlarge_factor; - gsize data_buflen; /* buffer length of usb bulk transfer */ - struct aes_regwrite *init_reqs; /* initial values sent to device */ - gsize init_reqs_len; + gsize data_buflen; /* buffer length of usb bulk transfer */ + struct aes_regwrite *init_reqs; /* initial values sent to device */ + gsize init_reqs_len; }; diff --git a/libfprint/drivers/aes4000.c b/libfprint/drivers/aes4000.c index 02984891..0a801f6b 100644 --- a/libfprint/drivers/aes4000.c +++ b/libfprint/drivers/aes4000.c @@ -28,123 +28,128 @@ #include "aes3k.h" -#define DATA_BUFLEN 0x1259 +#define DATA_BUFLEN 0x1259 /* image size = FRAME_WIDTH x FRAME_WIDTH */ -#define FRAME_WIDTH 96 -#define FRAME_SIZE (FRAME_WIDTH * AES3K_FRAME_HEIGHT / 2) -#define FRAME_NUMBER (FRAME_WIDTH / AES3K_FRAME_HEIGHT) -#define ENLARGE_FACTOR 3 +#define FRAME_WIDTH 96 +#define FRAME_SIZE (FRAME_WIDTH * AES3K_FRAME_HEIGHT / 2) +#define FRAME_NUMBER (FRAME_WIDTH / AES3K_FRAME_HEIGHT) +#define ENLARGE_FACTOR 3 static struct aes_regwrite init_reqs[] = { - /* master reset */ - { 0x80, 0x01 }, - { 0, 0 }, - { 0x80, 0x00 }, - { 0, 0 }, + /* master reset */ + { 0x80, 0x01 }, + { 0, 0 }, + { 0x80, 0x00 }, + { 0, 0 }, - { 0x81, 0x00 }, - { 0x80, 0x00 }, - { 0, 0 }, + { 0x81, 0x00 }, + { 0x80, 0x00 }, + { 0, 0 }, - /* scan reset */ - { 0x80, 0x02 }, - { 0, 0 }, - { 0x80, 0x00 }, - { 0, 0 }, + /* scan reset */ + { 0x80, 0x02 }, + { 0, 0 }, + { 0x80, 0x00 }, + { 0, 0 }, - /* disable register buffering */ - { 0x80, 0x04 }, - { 0, 0 }, - { 0x80, 0x00 }, - { 0, 0 }, + /* disable register buffering */ + { 0x80, 0x04 }, + { 0, 0 }, + { 0x80, 0x00 }, + { 0, 0 }, - { 0x81, 0x00 }, - { 0, 0 }, - /* windows driver reads registers now (81 02) */ - { 0x80, 0x00 }, - { 0x81, 0x00 }, + { 0x81, 0x00 }, + { 0, 0 }, + /* windows driver reads registers now (81 02) */ + { 0x80, 0x00 }, + { 0x81, 0x00 }, - /* set excitation bias current: 2mhz drive ring frequency, - * 4V drive ring voltage, 16.5mA excitation bias */ - { 0x82, 0x04 }, + /* set excitation bias current: 2mhz drive ring frequency, + * 4V drive ring voltage, 16.5mA excitation bias */ + { 0x82, 0x04 }, - /* continuously sample drive ring for finger detection, - * 62.50ms debounce delay */ - { 0x83, 0x13 }, + /* continuously sample drive ring for finger detection, + * 62.50ms debounce delay */ + { 0x83, 0x13 }, - { 0x84, 0x07 }, /* set calibration resistance to 12 kiloohms */ - { 0x85, 0x3d }, /* set calibration capacitance */ - { 0x86, 0x03 }, /* detect drive voltage */ - { 0x87, 0x01 }, /* set detection frequency to 125khz */ - { 0x88, 0x02 }, /* set column scan period */ - { 0x89, 0x02 }, /* set measure drive */ - { 0x8a, 0x33 }, /* set measure frequency and sense amplifier bias */ - { 0x8b, 0x33 }, /* set matrix pattern */ - { 0x8c, 0x0f }, /* set demodulation phase 1 */ - { 0x8d, 0x04 }, /* set demodulation phase 2 */ - { 0x8e, 0x23 }, /* set sensor gain */ - { 0x8f, 0x07 }, /* set image parameters */ - { 0x90, 0x00 }, /* carrier offset null */ - { 0x91, 0x1c }, /* set A/D reference high */ - { 0x92, 0x08 }, /* set A/D reference low */ - { 0x93, 0x00 }, /* set start row to 0 */ - { 0x94, 0x05 }, /* set end row to 5 */ - { 0x95, 0x00 }, /* set start column to 0 */ - { 0x96, 0x18 }, /* set end column to 24*4=96 */ - { 0x97, 0x04 }, /* data format and thresholds */ - { 0x98, 0x28 }, /* image data control */ - { 0x99, 0x00 }, /* disable general purpose outputs */ - { 0x9a, 0x0b }, /* set initial scan state */ - { 0x9b, 0x00 }, /* clear challenge word bits */ - { 0x9c, 0x00 }, /* clear challenge word bits */ - { 0x9d, 0x09 }, /* set some challenge word bits */ - { 0x9e, 0x53 }, /* clear challenge word bits */ - { 0x9f, 0x6b }, /* set some challenge word bits */ - { 0, 0 }, + { 0x84, 0x07 }, /* set calibration resistance to 12 kiloohms */ + { 0x85, 0x3d }, /* set calibration capacitance */ + { 0x86, 0x03 }, /* detect drive voltage */ + { 0x87, 0x01 }, /* set detection frequency to 125khz */ + { 0x88, 0x02 }, /* set column scan period */ + { 0x89, 0x02 }, /* set measure drive */ + { 0x8a, 0x33 }, /* set measure frequency and sense amplifier bias */ + { 0x8b, 0x33 }, /* set matrix pattern */ + { 0x8c, 0x0f }, /* set demodulation phase 1 */ + { 0x8d, 0x04 }, /* set demodulation phase 2 */ + { 0x8e, 0x23 }, /* set sensor gain */ + { 0x8f, 0x07 }, /* set image parameters */ + { 0x90, 0x00 }, /* carrier offset null */ + { 0x91, 0x1c }, /* set A/D reference high */ + { 0x92, 0x08 }, /* set A/D reference low */ + { 0x93, 0x00 }, /* set start row to 0 */ + { 0x94, 0x05 }, /* set end row to 5 */ + { 0x95, 0x00 }, /* set start column to 0 */ + { 0x96, 0x18 }, /* set end column to 24*4=96 */ + { 0x97, 0x04 }, /* data format and thresholds */ + { 0x98, 0x28 }, /* image data control */ + { 0x99, 0x00 }, /* disable general purpose outputs */ + { 0x9a, 0x0b }, /* set initial scan state */ + { 0x9b, 0x00 }, /* clear challenge word bits */ + { 0x9c, 0x00 }, /* clear challenge word bits */ + { 0x9d, 0x09 }, /* set some challenge word bits */ + { 0x9e, 0x53 }, /* clear challenge word bits */ + { 0x9f, 0x6b }, /* set some challenge word bits */ + { 0, 0 }, - { 0x80, 0x00 }, - { 0x81, 0x00 }, - { 0, 0 }, - { 0x81, 0x04 }, - { 0, 0 }, - { 0x81, 0x00 }, + { 0x80, 0x00 }, + { 0x81, 0x00 }, + { 0, 0 }, + { 0x81, 0x04 }, + { 0, 0 }, + { 0x81, 0x00 }, }; -struct _FpiDeviceAes4000 { - FpiDeviceAes3k parent; +struct _FpiDeviceAes4000 +{ + FpiDeviceAes3k parent; }; -G_DECLARE_FINAL_TYPE(FpiDeviceAes4000, fpi_device_aes4000, FPI, - DEVICE_AES4000, FpiDeviceAes3k); -G_DEFINE_TYPE(FpiDeviceAes4000, fpi_device_aes4000, FPI_TYPE_DEVICE_AES3K); +G_DECLARE_FINAL_TYPE (FpiDeviceAes4000, fpi_device_aes4000, FPI, + DEVICE_AES4000, FpiDeviceAes3k); +G_DEFINE_TYPE (FpiDeviceAes4000, fpi_device_aes4000, FPI_TYPE_DEVICE_AES3K); -static const FpIdEntry id_table [ ] = { - { .pid = 0x08ff, .vid = 0x5501 }, - { .vid = 0, .pid = 0, .driver_data = 0 }, +static const FpIdEntry id_table[] = { + { .pid = 0x08ff, .vid = 0x5501 }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -static void fpi_device_aes4000_init(FpiDeviceAes4000 *self) { +static void +fpi_device_aes4000_init (FpiDeviceAes4000 *self) +{ } -static void fpi_device_aes4000_class_init(FpiDeviceAes4000Class *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); - FpiDeviceAes3kClass *aes_class = FPI_DEVICE_AES3K_CLASS (klass); +static void +fpi_device_aes4000_class_init (FpiDeviceAes4000Class *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); + FpiDeviceAes3kClass *aes_class = FPI_DEVICE_AES3K_CLASS (klass); - dev_class->id = "aes4000"; - dev_class->full_name = "AuthenTec AES4000"; - dev_class->id_table = id_table; + dev_class->id = "aes4000"; + dev_class->full_name = "AuthenTec AES4000"; + dev_class->id_table = id_table; - img_class->img_height = FRAME_WIDTH * ENLARGE_FACTOR; - img_class->img_width = FRAME_WIDTH * ENLARGE_FACTOR; + img_class->img_height = FRAME_WIDTH * ENLARGE_FACTOR; + img_class->img_width = FRAME_WIDTH * ENLARGE_FACTOR; - aes_class->data_buflen = DATA_BUFLEN; - aes_class->frame_width = FRAME_WIDTH; - aes_class->frame_size = FRAME_SIZE; - aes_class->frame_number = FRAME_NUMBER; - aes_class->enlarge_factor = ENLARGE_FACTOR; - aes_class->init_reqs = init_reqs; - aes_class->init_reqs_len = G_N_ELEMENTS(init_reqs); + aes_class->data_buflen = DATA_BUFLEN; + aes_class->frame_width = FRAME_WIDTH; + aes_class->frame_size = FRAME_SIZE; + aes_class->frame_number = FRAME_NUMBER; + aes_class->enlarge_factor = ENLARGE_FACTOR; + aes_class->init_reqs = init_reqs; + aes_class->init_reqs_len = G_N_ELEMENTS (init_reqs); } diff --git a/libfprint/drivers/aeslib.c b/libfprint/drivers/aeslib.c index 0e5557ea..8f92d876 100644 --- a/libfprint/drivers/aeslib.c +++ b/libfprint/drivers/aeslib.c @@ -28,131 +28,145 @@ #include "fpi-assembling.h" #include "aeslib.h" -#define MAX_REGWRITES_PER_REQUEST 16 +#define MAX_REGWRITES_PER_REQUEST 16 -#define BULK_TIMEOUT 4000 -#define EP_IN (1 | FPI_USB_ENDPOINT_IN) -#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) +#define BULK_TIMEOUT 4000 +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) -struct write_regv_data { - unsigned int num_regs; - const struct aes_regwrite *regs; - unsigned int offset; - aes_write_regv_cb callback; - void *user_data; +struct write_regv_data +{ + unsigned int num_regs; + const struct aes_regwrite *regs; + unsigned int offset; + aes_write_regv_cb callback; + void *user_data; }; -static void continue_write_regv(FpImageDevice *dev, struct write_regv_data *wdata); +static void continue_write_regv (FpImageDevice *dev, + struct write_regv_data *wdata); /* libusb bulk callback for regv write completion transfer. continues the * transaction */ -static void write_regv_trf_complete(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +write_regv_trf_complete (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - struct write_regv_data *wdata = user_data; + struct write_regv_data *wdata = user_data; - if (error) { - wdata->callback(FP_IMAGE_DEVICE (device), error, wdata->user_data); - g_free(wdata); - } else { - continue_write_regv(FP_IMAGE_DEVICE (device), wdata); - } + if (error) + { + wdata->callback (FP_IMAGE_DEVICE (device), error, wdata->user_data); + g_free (wdata); + } + else + { + continue_write_regv (FP_IMAGE_DEVICE (device), wdata); + } } /* write from wdata->offset to upper_bound (inclusive) of wdata->regs */ -static void do_write_regv(FpImageDevice *dev, struct write_regv_data *wdata, int upper_bound) +static void +do_write_regv (FpImageDevice *dev, struct write_regv_data *wdata, int upper_bound) { - unsigned int offset = wdata->offset; - unsigned int num = upper_bound - offset + 1; - size_t alloc_size = num * 2; - unsigned int i; - size_t data_offset = 0; - FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE (dev)); + unsigned int offset = wdata->offset; + unsigned int num = upper_bound - offset + 1; + size_t alloc_size = num * 2; + unsigned int i; + size_t data_offset = 0; + FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); - fpi_usb_transfer_fill_bulk (transfer, EP_OUT, alloc_size); + fpi_usb_transfer_fill_bulk (transfer, EP_OUT, alloc_size); - for (i = offset; i < offset + num; i++) { - const struct aes_regwrite *regwrite = &wdata->regs[i]; - transfer->buffer[data_offset++] = regwrite->reg; - transfer->buffer[data_offset++] = regwrite->value; - } + for (i = offset; i < offset + num; i++) + { + const struct aes_regwrite *regwrite = &wdata->regs[i]; + transfer->buffer[data_offset++] = regwrite->reg; + transfer->buffer[data_offset++] = regwrite->value; + } - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - write_regv_trf_complete, wdata); - fpi_usb_transfer_unref (transfer); + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + write_regv_trf_complete, wdata); + fpi_usb_transfer_unref (transfer); } /* write the next batch of registers to be written, or if there are no more, * indicate completion to the caller */ -static void continue_write_regv(FpImageDevice *dev, struct write_regv_data *wdata) +static void +continue_write_regv (FpImageDevice *dev, struct write_regv_data *wdata) { - unsigned int offset = wdata->offset; - unsigned int regs_remaining; - unsigned int limit; - unsigned int upper_bound; - int i; + unsigned int offset = wdata->offset; + unsigned int regs_remaining; + unsigned int limit; + unsigned int upper_bound; + int i; - /* skip all zeros and ensure there is still work to do */ - while (TRUE) { - if (offset >= wdata->num_regs) { - fp_dbg("all registers written"); - wdata->callback(dev, 0, wdata->user_data); - g_free(wdata); - return; - } - if (wdata->regs[offset].reg) - break; - offset++; - } + /* skip all zeros and ensure there is still work to do */ + while (TRUE) + { + if (offset >= wdata->num_regs) + { + fp_dbg ("all registers written"); + wdata->callback (dev, 0, wdata->user_data); + g_free (wdata); + return; + } + if (wdata->regs[offset].reg) + break; + offset++; + } - wdata->offset = offset; - regs_remaining = wdata->num_regs - offset; - limit = MIN(regs_remaining, MAX_REGWRITES_PER_REQUEST); - upper_bound = offset + limit - 1; + wdata->offset = offset; + regs_remaining = wdata->num_regs - offset; + limit = MIN (regs_remaining, MAX_REGWRITES_PER_REQUEST); + upper_bound = offset + limit - 1; - /* determine if we can write the entire of the regs at once, or if there - * is a zero dividing things up */ - for (i = offset; i <= upper_bound; i++) - if (!wdata->regs[i].reg) { - upper_bound = i - 1; - break; - } + /* determine if we can write the entire of the regs at once, or if there + * is a zero dividing things up */ + for (i = offset; i <= upper_bound; i++) + if (!wdata->regs[i].reg) + { + upper_bound = i - 1; + break; + } - do_write_regv(dev, wdata, upper_bound); + do_write_regv (dev, wdata, upper_bound); - wdata->offset = upper_bound + 1; + wdata->offset = upper_bound + 1; } /* write a load of registers to the device, combining multiple writes in a * single URB up to a limit. insert writes to non-existent register 0 to force * specific groups of writes to be separated by different URBs. */ -void aes_write_regv(FpImageDevice *dev, const struct aes_regwrite *regs, - unsigned int num_regs, aes_write_regv_cb callback, - void *user_data) +void +aes_write_regv (FpImageDevice *dev, const struct aes_regwrite *regs, + unsigned int num_regs, aes_write_regv_cb callback, + void *user_data) { - struct write_regv_data *wdata; + struct write_regv_data *wdata; - fp_dbg("write %d regs", num_regs); - wdata = g_malloc(sizeof(*wdata)); - wdata->num_regs = num_regs; - wdata->regs = regs; - wdata->offset = 0; - wdata->callback = callback; - wdata->user_data = user_data; - continue_write_regv(dev, wdata); + fp_dbg ("write %d regs", num_regs); + wdata = g_malloc (sizeof (*wdata)); + wdata->num_regs = num_regs; + wdata->regs = regs; + wdata->offset = 0; + wdata->callback = callback; + wdata->user_data = user_data; + continue_write_regv (dev, wdata); } -unsigned char aes_get_pixel(struct fpi_frame_asmbl_ctx *ctx, - struct fpi_frame *frame, - unsigned int x, - unsigned int y) +unsigned char +aes_get_pixel (struct fpi_frame_asmbl_ctx *ctx, + struct fpi_frame *frame, + unsigned int x, + unsigned int y) { - unsigned char ret; + unsigned char ret; - ret = frame->data[x * (ctx->frame_height >> 1) + (y >> 1)]; - ret = y % 2 ? ret >> 4 : ret & 0xf; - ret *= 17; + ret = frame->data[x * (ctx->frame_height >> 1) + (y >> 1)]; + ret = y % 2 ? ret >> 4 : ret & 0xf; + ret *= 17; - return ret; + return ret; } diff --git a/libfprint/drivers/aeslib.h b/libfprint/drivers/aeslib.h index 2a45e993..389b3e56 100644 --- a/libfprint/drivers/aeslib.h +++ b/libfprint/drivers/aeslib.h @@ -22,25 +22,28 @@ #include -struct aes_regwrite { - unsigned char reg; - unsigned char value; +struct aes_regwrite +{ + unsigned char reg; + unsigned char value; }; struct fpi_frame; struct fpi_frame_asmbl_ctx; -typedef void (*aes_write_regv_cb)(FpImageDevice *dev, GError *error, - void *user_data); +typedef void (*aes_write_regv_cb)(FpImageDevice *dev, + GError *error, + void *user_data); -void aes_write_regv(FpImageDevice *dev, const struct aes_regwrite *regs, - unsigned int num_regs, aes_write_regv_cb callback, - void *user_data); +void aes_write_regv (FpImageDevice *dev, + const struct aes_regwrite *regs, + unsigned int num_regs, + aes_write_regv_cb callback, + void *user_data); -unsigned char aes_get_pixel(struct fpi_frame_asmbl_ctx *ctx, - struct fpi_frame *frame, - unsigned int x, - unsigned int y); +unsigned char aes_get_pixel (struct fpi_frame_asmbl_ctx *ctx, + struct fpi_frame *frame, + unsigned int x, + unsigned int y); #endif - diff --git a/libfprint/drivers/aesx660.c b/libfprint/drivers/aesx660.c index b0cc4029..385b1f6a 100644 --- a/libfprint/drivers/aesx660.c +++ b/libfprint/drivers/aesx660.c @@ -27,659 +27,736 @@ #include "aeslib.h" #include "aesx660.h" -typedef struct { - GByteArray *stripe_packet; - GSList *strips; - size_t strips_len; - gboolean deactivating; - struct aesX660_cmd *init_seq; - size_t init_seq_len; - unsigned int init_cmd_idx; - unsigned int init_seq_idx; +typedef struct +{ + GByteArray *stripe_packet; + GSList *strips; + size_t strips_len; + gboolean deactivating; + struct aesX660_cmd *init_seq; + size_t init_seq_len; + unsigned int init_cmd_idx; + unsigned int init_seq_idx; } FpiDeviceAesX660Private; -G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(FpiDeviceAesX660, fpi_device_aes_x660, FP_TYPE_IMAGE_DEVICE); +G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (FpiDeviceAesX660, fpi_device_aes_x660, FP_TYPE_IMAGE_DEVICE); -static void start_capture(FpImageDevice *dev); -static void complete_deactivation(FpImageDevice *dev); +static void start_capture (FpImageDevice *dev); +static void complete_deactivation (FpImageDevice *dev); -#define EP_IN (1 | FPI_USB_ENDPOINT_IN) -#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) -#define BULK_TIMEOUT 4000 -#define FRAME_HEIGHT AESX660_FRAME_HEIGHT +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) +#define BULK_TIMEOUT 4000 +#define FRAME_HEIGHT AESX660_FRAME_HEIGHT -#define ID_LEN 8 -#define INIT_LEN 4 -#define CALIBRATE_DATA_LEN 4 -#define FINGER_DET_DATA_LEN 4 +#define ID_LEN 8 +#define INIT_LEN 4 +#define CALIBRATE_DATA_LEN 4 +#define FINGER_DET_DATA_LEN 4 static void -aesX660_send_cmd_timeout(FpiSsm *ssm, - FpDevice *_dev, - const unsigned char *cmd, - size_t cmd_len, - FpiUsbTransferCallback callback, - int timeout) +aesX660_send_cmd_timeout (FpiSsm *ssm, + FpDevice *_dev, + const unsigned char *cmd, + size_t cmd_len, + FpiUsbTransferCallback callback, + int timeout) { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(_dev); + FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev); - fpi_usb_transfer_fill_bulk_full(transfer, EP_OUT, (unsigned char *)cmd, - cmd_len, NULL); - transfer->ssm = ssm; - fpi_usb_transfer_submit(transfer, timeout, NULL, callback, NULL); - fpi_usb_transfer_unref(transfer); + fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, (unsigned char *) cmd, + cmd_len, NULL); + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, timeout, NULL, callback, NULL); + fpi_usb_transfer_unref (transfer); } static void -aesX660_send_cmd(FpiSsm *ssm, - FpDevice *dev, - const unsigned char *cmd, - size_t cmd_len, - FpiUsbTransferCallback callback) +aesX660_send_cmd (FpiSsm *ssm, + FpDevice *dev, + const unsigned char *cmd, + size_t cmd_len, + FpiUsbTransferCallback callback) { - return aesX660_send_cmd_timeout(ssm, dev, cmd, cmd_len, callback, BULK_TIMEOUT); + return aesX660_send_cmd_timeout (ssm, dev, cmd, cmd_len, callback, BULK_TIMEOUT); } static void -aesX660_read_response(FpiSsm *ssm, - FpDevice *_dev, - gboolean short_is_error, - gboolean cancellable, - size_t buf_len, - FpiUsbTransferCallback callback) +aesX660_read_response (FpiSsm *ssm, + FpDevice *_dev, + gboolean short_is_error, + gboolean cancellable, + size_t buf_len, + FpiUsbTransferCallback callback) { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(_dev); - unsigned char *data; - GCancellable *cancel = NULL; + FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev); + unsigned char *data; + GCancellable *cancel = NULL; - if (cancellable) - cancel = fpi_device_get_cancellable (_dev); - data = g_malloc(buf_len); - fpi_usb_transfer_fill_bulk_full(transfer, EP_IN, data, buf_len, NULL); - transfer->ssm = ssm; - transfer->short_is_error = short_is_error; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, cancel, callback, NULL); - fpi_usb_transfer_unref(transfer); + if (cancellable) + cancel = fpi_device_get_cancellable (_dev); + data = g_malloc (buf_len); + fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, data, buf_len, NULL); + transfer->ssm = ssm; + transfer->short_is_error = short_is_error; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, cancel, callback, NULL); + fpi_usb_transfer_unref (transfer); } -static void aesX660_send_cmd_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +aesX660_send_cmd_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - if (!error) { - fpi_ssm_next_state(transfer->ssm); - } else { - fpi_ssm_mark_failed(transfer->ssm, error); - } + if (!error) + fpi_ssm_next_state (transfer->ssm); + else + fpi_ssm_mark_failed (transfer->ssm, error); } -static void aesX660_read_calibrate_data_cb(FpiUsbTransfer *transfer, - FpDevice *device, - gpointer user_data, GError *error) +static void +aesX660_read_calibrate_data_cb (FpiUsbTransfer *transfer, + FpDevice *device, + gpointer user_data, GError *error) { - unsigned char *data = transfer->buffer; + unsigned char *data = transfer->buffer; - if (error) { - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } - /* Calibrate response was read correctly? */ - if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_CALIBRATE_RESPONSE) { - fp_dbg("Bogus calibrate response: %.2x\n", data[0]); - fpi_ssm_mark_failed(transfer->ssm, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Bogus calibrate response")); - return; - } + if (error) + { + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } + /* Calibrate response was read correctly? */ + if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_CALIBRATE_RESPONSE) + { + fp_dbg ("Bogus calibrate response: %.2x\n", data[0]); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Bogus calibrate response")); + return; + } - fpi_ssm_next_state(transfer->ssm); + fpi_ssm_next_state (transfer->ssm); } /****** FINGER PRESENCE DETECTION ******/ enum finger_det_states { - FINGER_DET_SEND_LED_CMD, - FINGER_DET_SEND_FD_CMD, - FINGER_DET_READ_FD_DATA, - FINGER_DET_SET_IDLE, - FINGER_DET_NUM_STATES, + FINGER_DET_SEND_LED_CMD, + FINGER_DET_SEND_FD_CMD, + FINGER_DET_READ_FD_DATA, + FINGER_DET_SET_IDLE, + FINGER_DET_NUM_STATES, }; -static void finger_det_read_fd_data_cb(FpiUsbTransfer *transfer, - FpDevice *device, gpointer user_data, - GError *error) +static void +finger_det_read_fd_data_cb (FpiUsbTransfer *transfer, + FpDevice *device, gpointer user_data, + GError *error) { - FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); - FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); - unsigned char *data = transfer->buffer; + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + unsigned char *data = transfer->buffer; - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - fpi_ssm_next_state(transfer->ssm); - return; - } + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + fpi_ssm_next_state (transfer->ssm); + return; + } - if (error) { - fp_dbg("Failed to read FD data\n"); - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } + if (error) + { + fp_dbg ("Failed to read FD data\n"); + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } - if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_FINGER_DET_RESPONSE) { - fp_dbg("Bogus FD response: %.2x\n", data[0]); - fpi_ssm_mark_failed(transfer->ssm, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Bogus FD response")); - return; - } + if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_FINGER_DET_RESPONSE) + { + fp_dbg ("Bogus FD response: %.2x\n", data[0]); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Bogus FD response")); + return; + } - if (data[AESX660_FINGER_PRESENT_OFFSET] == AESX660_FINGER_PRESENT || priv->deactivating) { - /* Finger present or we're deactivating... */ - fpi_ssm_next_state(transfer->ssm); - } else { - fp_dbg("Wait for finger returned %.2x as result\n", - data[AESX660_FINGER_PRESENT_OFFSET]); - fpi_ssm_jump_to_state(transfer->ssm, FINGER_DET_SEND_FD_CMD); - } + if (data[AESX660_FINGER_PRESENT_OFFSET] == AESX660_FINGER_PRESENT || priv->deactivating) + { + /* Finger present or we're deactivating... */ + fpi_ssm_next_state (transfer->ssm); + } + else + { + fp_dbg ("Wait for finger returned %.2x as result\n", + data[AESX660_FINGER_PRESENT_OFFSET]); + fpi_ssm_jump_to_state (transfer->ssm, FINGER_DET_SEND_FD_CMD); + } } -static void finger_det_set_idle_cmd_cb(FpiUsbTransfer *transfer, - FpDevice *device, gpointer user_data, - GError *error) +static void +finger_det_set_idle_cmd_cb (FpiUsbTransfer *transfer, + FpDevice *device, gpointer user_data, + GError *error) { - if (!error) { - fpi_ssm_mark_completed(transfer->ssm); - } else { - fpi_ssm_mark_failed(transfer->ssm, error); - } + if (!error) + fpi_ssm_mark_completed (transfer->ssm); + else + fpi_ssm_mark_failed (transfer->ssm, error); } -static void finger_det_sm_complete(FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +static void +finger_det_sm_complete (FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); - FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (_dev); - FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (_dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); - fp_dbg("Finger detection completed"); - fpi_image_device_report_finger_status(dev, TRUE); - fpi_ssm_free(ssm); + fp_dbg ("Finger detection completed"); + fpi_image_device_report_finger_status (dev, TRUE); + fpi_ssm_free (ssm); - if (priv->deactivating) { - complete_deactivation(dev); - if (error) - g_error_free (error); - } else if (error) { - fpi_image_device_session_error(dev, error); - } else { - fpi_image_device_report_finger_status(dev, TRUE); - start_capture(dev); - } + if (priv->deactivating) + { + complete_deactivation (dev); + if (error) + g_error_free (error); + } + else if (error) + { + fpi_image_device_session_error (dev, error); + } + else + { + fpi_image_device_report_finger_status (dev, TRUE); + start_capture (dev); + } } -static void finger_det_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) +static void +finger_det_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) { - switch (fpi_ssm_get_cur_state(ssm)) { - case FINGER_DET_SEND_LED_CMD: - aesX660_send_cmd(ssm, dev, led_blink_cmd, sizeof(led_blink_cmd), - aesX660_send_cmd_cb); - break; - case FINGER_DET_SEND_FD_CMD: - aesX660_send_cmd_timeout(ssm, dev, wait_for_finger_cmd, sizeof(wait_for_finger_cmd), - aesX660_send_cmd_cb, 0); - break; - case FINGER_DET_READ_FD_DATA: - aesX660_read_response(ssm, dev, TRUE, TRUE, FINGER_DET_DATA_LEN, finger_det_read_fd_data_cb); - break; - case FINGER_DET_SET_IDLE: - aesX660_send_cmd(ssm, dev, set_idle_cmd, sizeof(set_idle_cmd), - finger_det_set_idle_cmd_cb); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case FINGER_DET_SEND_LED_CMD: + aesX660_send_cmd (ssm, dev, led_blink_cmd, sizeof (led_blink_cmd), + aesX660_send_cmd_cb); + break; + + case FINGER_DET_SEND_FD_CMD: + aesX660_send_cmd_timeout (ssm, dev, wait_for_finger_cmd, sizeof (wait_for_finger_cmd), + aesX660_send_cmd_cb, 0); + break; + + case FINGER_DET_READ_FD_DATA: + aesX660_read_response (ssm, dev, TRUE, TRUE, FINGER_DET_DATA_LEN, finger_det_read_fd_data_cb); + break; + + case FINGER_DET_SET_IDLE: + aesX660_send_cmd (ssm, dev, set_idle_cmd, sizeof (set_idle_cmd), + finger_det_set_idle_cmd_cb); + break; + } } -static void start_finger_detection(FpImageDevice *dev) +static void +start_finger_detection (FpImageDevice *dev) { - FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); - FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); - FpiSsm *ssm; + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + FpiSsm *ssm; - if (priv->deactivating) { - complete_deactivation(dev); - return; - } + if (priv->deactivating) + { + complete_deactivation (dev); + return; + } - ssm = fpi_ssm_new(FP_DEVICE(dev), finger_det_run_state, - FINGER_DET_NUM_STATES, dev); - fpi_ssm_start(ssm, finger_det_sm_complete); + ssm = fpi_ssm_new (FP_DEVICE (dev), finger_det_run_state, + FINGER_DET_NUM_STATES, dev); + fpi_ssm_start (ssm, finger_det_sm_complete); } /****** CAPTURE ******/ enum capture_states { - CAPTURE_SEND_LED_CMD, - CAPTURE_SEND_CAPTURE_CMD, - CAPTURE_READ_STRIPE_DATA, - CAPTURE_SET_IDLE, - CAPTURE_NUM_STATES, + CAPTURE_SEND_LED_CMD, + CAPTURE_SEND_CAPTURE_CMD, + CAPTURE_READ_STRIPE_DATA, + CAPTURE_SET_IDLE, + CAPTURE_NUM_STATES, }; /* Returns number of processed bytes */ -static int process_stripe_data(FpiSsm *ssm, FpiDeviceAesX660 *self, - unsigned char *data, gsize length) +static int +process_stripe_data (FpiSsm *ssm, FpiDeviceAesX660 *self, + unsigned char *data, gsize length) { - FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); - FpiDeviceAesX660Class *cls = FPI_DEVICE_AES_X660_GET_CLASS (self); - struct fpi_frame *stripe; - unsigned char *stripdata; + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + FpiDeviceAesX660Class *cls = FPI_DEVICE_AES_X660_GET_CLASS (self); + struct fpi_frame *stripe; + unsigned char *stripdata; - if (length < AESX660_IMAGE_OFFSET + cls->assembling_ctx->frame_width * FRAME_HEIGHT / 2) { - fp_warn ("Received stripe data is too short, got %zi expected %i bytes!", - length, - AESX660_IMAGE_OFFSET + cls->assembling_ctx->frame_width * FRAME_HEIGHT / 2); - return 0; - } + if (length < AESX660_IMAGE_OFFSET + cls->assembling_ctx->frame_width * FRAME_HEIGHT / 2) + { + fp_warn ("Received stripe data is too short, got %zi expected %i bytes!", + length, + AESX660_IMAGE_OFFSET + cls->assembling_ctx->frame_width * FRAME_HEIGHT / 2); + return 0; + } - stripe = g_malloc(cls->assembling_ctx->frame_width * FRAME_HEIGHT / 2 + sizeof(struct fpi_frame)); /* 4 bpp */ - stripdata = stripe->data; + stripe = g_malloc (cls->assembling_ctx->frame_width * FRAME_HEIGHT / 2 + sizeof (struct fpi_frame)); /* 4 bpp */ + stripdata = stripe->data; - fp_dbg("Processing frame %.2x %.2x", data[AESX660_IMAGE_OK_OFFSET], - data[AESX660_LAST_FRAME_OFFSET]); + fp_dbg ("Processing frame %.2x %.2x", data[AESX660_IMAGE_OK_OFFSET], + data[AESX660_LAST_FRAME_OFFSET]); - stripe->delta_x = (int8_t)data[AESX660_FRAME_DELTA_X_OFFSET]; - stripe->delta_y = -(int8_t)data[AESX660_FRAME_DELTA_Y_OFFSET]; - fp_dbg("Offset to previous frame: %d %d", stripe->delta_x, stripe->delta_y); + stripe->delta_x = (int8_t) data[AESX660_FRAME_DELTA_X_OFFSET]; + stripe->delta_y = -(int8_t) data[AESX660_FRAME_DELTA_Y_OFFSET]; + fp_dbg ("Offset to previous frame: %d %d", stripe->delta_x, stripe->delta_y); - if (data[AESX660_IMAGE_OK_OFFSET] == AESX660_IMAGE_OK) { - memcpy(stripdata, data + AESX660_IMAGE_OFFSET, cls->assembling_ctx->frame_width * FRAME_HEIGHT / 2); + if (data[AESX660_IMAGE_OK_OFFSET] == AESX660_IMAGE_OK) + { + memcpy (stripdata, data + AESX660_IMAGE_OFFSET, cls->assembling_ctx->frame_width * FRAME_HEIGHT / 2); - priv->strips = g_slist_prepend(priv->strips, stripe); - priv->strips_len++; - return (data[AESX660_LAST_FRAME_OFFSET] & AESX660_LAST_FRAME_BIT); - } + priv->strips = g_slist_prepend (priv->strips, stripe); + priv->strips_len++; + return data[AESX660_LAST_FRAME_OFFSET] & AESX660_LAST_FRAME_BIT; + } - g_free(stripe); - return 0; + g_free (stripe); + return 0; } -static void capture_set_idle_cmd_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +capture_set_idle_cmd_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE (device); - FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); - FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); - FpiDeviceAesX660Class *cls = FPI_DEVICE_AES_X660_GET_CLASS (self); + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + FpiDeviceAesX660Class *cls = FPI_DEVICE_AES_X660_GET_CLASS (self); - if (!error) { - FpImage *img; + if (!error) + { + FpImage *img; - priv->strips = g_slist_reverse(priv->strips); - img = fpi_assemble_frames(cls->assembling_ctx, priv->strips); - g_slist_foreach(priv->strips, (GFunc) g_free, NULL); - g_slist_free(priv->strips); - priv->strips = NULL; - priv->strips_len = 0; - fpi_image_device_image_captured(dev, img); - fpi_image_device_report_finger_status(dev, FALSE); - fpi_ssm_mark_completed(transfer->ssm); - } else { - fpi_ssm_mark_failed(transfer->ssm, error); - } + priv->strips = g_slist_reverse (priv->strips); + img = fpi_assemble_frames (cls->assembling_ctx, priv->strips); + g_slist_foreach (priv->strips, (GFunc) g_free, NULL); + g_slist_free (priv->strips); + priv->strips = NULL; + priv->strips_len = 0; + fpi_image_device_image_captured (dev, img); + fpi_image_device_report_finger_status (dev, FALSE); + fpi_ssm_mark_completed (transfer->ssm); + } + else + { + fpi_ssm_mark_failed (transfer->ssm, error); + } } -static void capture_read_stripe_data_cb(FpiUsbTransfer *transfer, - FpDevice *device, gpointer user_data, - GError *error) +static void +capture_read_stripe_data_cb (FpiUsbTransfer *transfer, + FpDevice *device, gpointer user_data, + GError *error) { - FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); - FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); - unsigned char *data = transfer->buffer; - int finger_missing = 0; - size_t actual_length = transfer->actual_length; + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + unsigned char *data = transfer->buffer; + int finger_missing = 0; + size_t actual_length = transfer->actual_length; - if (error) { - g_byte_array_set_size (priv->stripe_packet, 0); - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } + if (error) + { + g_byte_array_set_size (priv->stripe_packet, 0); + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } - fp_dbg("Got %lu bytes of data", actual_length); - while (actual_length) { - gssize payload_length; - gssize still_needed_len; - gssize copy_len; + fp_dbg ("Got %lu bytes of data", actual_length); + while (actual_length) + { + gssize payload_length; + gssize still_needed_len; + gssize copy_len; - still_needed_len = MAX (0, AESX660_HEADER_SIZE - (gssize) priv->stripe_packet->len); - copy_len = MIN (actual_length, still_needed_len); - g_byte_array_append (priv->stripe_packet, data, copy_len); - data += copy_len; - actual_length -= copy_len; + still_needed_len = MAX (0, AESX660_HEADER_SIZE - (gssize) priv->stripe_packet->len); + copy_len = MIN (actual_length, still_needed_len); + g_byte_array_append (priv->stripe_packet, data, copy_len); + data += copy_len; + actual_length -= copy_len; - /* Do we have a full header? */ - if (priv->stripe_packet->len < AESX660_HEADER_SIZE) - break; + /* Do we have a full header? */ + if (priv->stripe_packet->len < AESX660_HEADER_SIZE) + break; - payload_length = priv->stripe_packet->data[AESX660_RESPONSE_SIZE_LSB_OFFSET] + - (priv->stripe_packet->data[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8); - fp_dbg("Got frame, type %.2x payload of size %.4lx", - priv->stripe_packet->data[AESX660_RESPONSE_TYPE_OFFSET], - payload_length); + payload_length = priv->stripe_packet->data[AESX660_RESPONSE_SIZE_LSB_OFFSET] + + (priv->stripe_packet->data[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8); + fp_dbg ("Got frame, type %.2x payload of size %.4lx", + priv->stripe_packet->data[AESX660_RESPONSE_TYPE_OFFSET], + payload_length); - still_needed_len = MAX (0, AESX660_HEADER_SIZE + payload_length - (gssize) priv->stripe_packet->len); - copy_len = MIN (actual_length, still_needed_len); - g_byte_array_append (priv->stripe_packet, data, copy_len); - data += copy_len; - actual_length -= copy_len; + still_needed_len = MAX (0, AESX660_HEADER_SIZE + payload_length - (gssize) priv->stripe_packet->len); + copy_len = MIN (actual_length, still_needed_len); + g_byte_array_append (priv->stripe_packet, data, copy_len); + data += copy_len; + actual_length -= copy_len; - /* Do we have a full packet including the payload? */ - if (priv->stripe_packet->len < payload_length + AESX660_HEADER_SIZE) - break; + /* Do we have a full packet including the payload? */ + if (priv->stripe_packet->len < payload_length + AESX660_HEADER_SIZE) + break; - finger_missing |= process_stripe_data(transfer->ssm, - self, - priv->stripe_packet->data, - priv->stripe_packet->len); + finger_missing |= process_stripe_data (transfer->ssm, + self, + priv->stripe_packet->data, + priv->stripe_packet->len); - g_byte_array_set_size (priv->stripe_packet, 0); - } + g_byte_array_set_size (priv->stripe_packet, 0); + } - fp_dbg("finger %s\n", finger_missing ? "missing" : "present"); + fp_dbg ("finger %s\n", finger_missing ? "missing" : "present"); - if (finger_missing) { - fpi_ssm_next_state(transfer->ssm); - } else { - fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_READ_STRIPE_DATA); - } + if (finger_missing) + fpi_ssm_next_state (transfer->ssm); + else + fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_STRIPE_DATA); } -static void capture_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +capture_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (_dev); - FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); - FpiDeviceAesX660Class *cls = FPI_DEVICE_AES_X660_GET_CLASS (self); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (_dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + FpiDeviceAesX660Class *cls = FPI_DEVICE_AES_X660_GET_CLASS (self); - switch (fpi_ssm_get_cur_state(ssm)) { - case CAPTURE_SEND_LED_CMD: - aesX660_send_cmd(ssm, _dev, led_solid_cmd, sizeof(led_solid_cmd), - aesX660_send_cmd_cb); - break; - case CAPTURE_SEND_CAPTURE_CMD: - g_byte_array_set_size (priv->stripe_packet, 0); - aesX660_send_cmd(ssm, _dev, cls->start_imaging_cmd, - cls->start_imaging_cmd_len, - aesX660_send_cmd_cb); - break; - case CAPTURE_READ_STRIPE_DATA: - aesX660_read_response(ssm, _dev, FALSE, FALSE, AESX660_BULK_TRANSFER_SIZE, - capture_read_stripe_data_cb); - break; - case CAPTURE_SET_IDLE: - fp_dbg("Got %lu frames\n", priv->strips_len); - aesX660_send_cmd(ssm, _dev, set_idle_cmd, sizeof(set_idle_cmd), - capture_set_idle_cmd_cb); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case CAPTURE_SEND_LED_CMD: + aesX660_send_cmd (ssm, _dev, led_solid_cmd, sizeof (led_solid_cmd), + aesX660_send_cmd_cb); + break; + + case CAPTURE_SEND_CAPTURE_CMD: + g_byte_array_set_size (priv->stripe_packet, 0); + aesX660_send_cmd (ssm, _dev, cls->start_imaging_cmd, + cls->start_imaging_cmd_len, + aesX660_send_cmd_cb); + break; + + case CAPTURE_READ_STRIPE_DATA: + aesX660_read_response (ssm, _dev, FALSE, FALSE, AESX660_BULK_TRANSFER_SIZE, + capture_read_stripe_data_cb); + break; + + case CAPTURE_SET_IDLE: + fp_dbg ("Got %lu frames\n", priv->strips_len); + aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd), + capture_set_idle_cmd_cb); + break; + } } -static void capture_sm_complete(FpiSsm *ssm, FpDevice *device, void *user_data, - GError *error) +static void +capture_sm_complete (FpiSsm *ssm, FpDevice *device, void *user_data, + GError *error) { - FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); - FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); - fp_dbg("Capture completed"); - fpi_ssm_free(ssm); + fp_dbg ("Capture completed"); + fpi_ssm_free (ssm); - if (priv->deactivating) { - complete_deactivation(FP_IMAGE_DEVICE (device)); - if (error) - g_error_free (error); - } else if (error) { - fpi_image_device_session_error (FP_IMAGE_DEVICE (device), error); - } else { - start_finger_detection(FP_IMAGE_DEVICE (device)); - } + if (priv->deactivating) + { + complete_deactivation (FP_IMAGE_DEVICE (device)); + if (error) + g_error_free (error); + } + else if (error) + { + fpi_image_device_session_error (FP_IMAGE_DEVICE (device), error); + } + else + { + start_finger_detection (FP_IMAGE_DEVICE (device)); + } } -static void start_capture(FpImageDevice *dev) +static void +start_capture (FpImageDevice *dev) { - FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); - FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); - FpiSsm *ssm; + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + FpiSsm *ssm; - if (priv->deactivating) { - complete_deactivation(dev); - return; - } + if (priv->deactivating) + { + complete_deactivation (dev); + return; + } - ssm = fpi_ssm_new(FP_DEVICE(dev), capture_run_state, - CAPTURE_NUM_STATES, dev); - G_DEBUG_HERE(); - fpi_ssm_start(ssm, capture_sm_complete); + ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, + CAPTURE_NUM_STATES, dev); + G_DEBUG_HERE (); + fpi_ssm_start (ssm, capture_sm_complete); } /****** INITIALIZATION/DEINITIALIZATION ******/ enum activate_states { - ACTIVATE_SET_IDLE, - ACTIVATE_SEND_READ_ID_CMD, - ACTIVATE_READ_ID, - ACTIVATE_SEND_CALIBRATE_CMD, - ACTIVATE_READ_CALIBRATE_DATA, - ACTIVATE_SEND_INIT_CMD, - ACTIVATE_READ_INIT_RESPONSE, - ACTIVATE_NUM_STATES, + ACTIVATE_SET_IDLE, + ACTIVATE_SEND_READ_ID_CMD, + ACTIVATE_READ_ID, + ACTIVATE_SEND_CALIBRATE_CMD, + ACTIVATE_READ_CALIBRATE_DATA, + ACTIVATE_SEND_INIT_CMD, + ACTIVATE_READ_INIT_RESPONSE, + ACTIVATE_NUM_STATES, }; -static void activate_read_id_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +activate_read_id_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); - FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); - FpiDeviceAesX660Class *cls = FPI_DEVICE_AES_X660_GET_CLASS (self); - unsigned char *data = transfer->buffer; + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + FpiDeviceAesX660Class *cls = FPI_DEVICE_AES_X660_GET_CLASS (self); + unsigned char *data = transfer->buffer; - if (error) { - fp_dbg("read_id cmd failed\n"); - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } - /* ID was read correctly */ - if (data[0] == 0x07) { - fp_dbg("Sensor device id: %.2x%2x, bcdDevice: %.2x.%.2x, init status: %.2x\n", - data[4], data[3], data[5], data[6], data[7]); - } else { - fp_dbg("Bogus read ID response: %.2x\n", data[AESX660_RESPONSE_TYPE_OFFSET]); - fpi_ssm_mark_failed(transfer->ssm, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Bogus read ID response")); - return; - } + if (error) + { + fp_dbg ("read_id cmd failed\n"); + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } + /* ID was read correctly */ + if (data[0] == 0x07) + { + fp_dbg ("Sensor device id: %.2x%2x, bcdDevice: %.2x.%.2x, init status: %.2x\n", + data[4], data[3], data[5], data[6], data[7]); + } + else + { + fp_dbg ("Bogus read ID response: %.2x\n", data[AESX660_RESPONSE_TYPE_OFFSET]); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Bogus read ID response")); + return; + } - switch (priv->init_seq_idx) { - case 0: - priv->init_seq = cls->init_seqs[0]; - priv->init_seq_len = cls->init_seqs_len[0]; - priv->init_seq_idx = 1; - priv->init_cmd_idx = 0; - /* Do calibration only after 1st init sequence */ - fpi_ssm_jump_to_state(transfer->ssm, ACTIVATE_SEND_INIT_CMD); - break; - case 1: - priv->init_seq = cls->init_seqs[1]; - priv->init_seq_len = cls->init_seqs_len[1]; - priv->init_seq_idx = 2; - priv->init_cmd_idx = 0; - fpi_ssm_next_state(transfer->ssm); - break; - default: - fp_dbg("Failed to init device! init status: %.2x\n", data[7]); - fpi_ssm_mark_failed(transfer->ssm, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Failed to init device")); - break; - } + switch (priv->init_seq_idx) + { + case 0: + priv->init_seq = cls->init_seqs[0]; + priv->init_seq_len = cls->init_seqs_len[0]; + priv->init_seq_idx = 1; + priv->init_cmd_idx = 0; + /* Do calibration only after 1st init sequence */ + fpi_ssm_jump_to_state (transfer->ssm, ACTIVATE_SEND_INIT_CMD); + break; + + case 1: + priv->init_seq = cls->init_seqs[1]; + priv->init_seq_len = cls->init_seqs_len[1]; + priv->init_seq_idx = 2; + priv->init_cmd_idx = 0; + fpi_ssm_next_state (transfer->ssm); + break; + + default: + fp_dbg ("Failed to init device! init status: %.2x\n", data[7]); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Failed to init device")); + break; + } } -static void activate_read_init_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +activate_read_init_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); - FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); - unsigned char *data = transfer->buffer; + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + unsigned char *data = transfer->buffer; - fp_dbg("read_init_cb\n"); + fp_dbg ("read_init_cb\n"); - if (error) { - fp_dbg("read_init transfer status: %s, actual_len: %d\n", error->message, - (gint)transfer->actual_length); - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } - /* ID was read correctly */ - if (data[0] != 0x42 || data[3] != 0x01) { - fp_dbg("Bogus read init response: %.2x %.2x\n", data[0], - data[3]); - fpi_ssm_mark_failed(transfer->ssm, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Bogus read init response")); - return; - } - priv->init_cmd_idx++; - if (priv->init_cmd_idx == priv->init_seq_len) { - if (priv->init_seq_idx < 2) - fpi_ssm_jump_to_state(transfer->ssm, - ACTIVATE_SEND_READ_ID_CMD); - else - fpi_ssm_mark_completed(transfer->ssm); - return; - } + if (error) + { + fp_dbg ("read_init transfer status: %s, actual_len: %d\n", error->message, + (gint) transfer->actual_length); + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } + /* ID was read correctly */ + if (data[0] != 0x42 || data[3] != 0x01) + { + fp_dbg ("Bogus read init response: %.2x %.2x\n", data[0], + data[3]); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Bogus read init response")); + return; + } + priv->init_cmd_idx++; + if (priv->init_cmd_idx == priv->init_seq_len) + { + if (priv->init_seq_idx < 2) + fpi_ssm_jump_to_state (transfer->ssm, + ACTIVATE_SEND_READ_ID_CMD); + else + fpi_ssm_mark_completed (transfer->ssm); + return; + } - fpi_ssm_jump_to_state(transfer->ssm, ACTIVATE_SEND_INIT_CMD); + fpi_ssm_jump_to_state (transfer->ssm, ACTIVATE_SEND_INIT_CMD); } -static void activate_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +activate_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (_dev); - FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (_dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); - switch (fpi_ssm_get_cur_state(ssm)) { - case ACTIVATE_SET_IDLE: - priv->init_seq_idx = 0; - fp_dbg("Activate: set idle\n"); - aesX660_send_cmd(ssm, _dev, set_idle_cmd, sizeof(set_idle_cmd), - aesX660_send_cmd_cb); - break; - case ACTIVATE_SEND_READ_ID_CMD: - fp_dbg("Activate: read ID\n"); - aesX660_send_cmd(ssm, _dev, read_id_cmd, sizeof(read_id_cmd), - aesX660_send_cmd_cb); - break; - case ACTIVATE_READ_ID: - aesX660_read_response(ssm, _dev, TRUE, FALSE, ID_LEN, activate_read_id_cb); - break; - case ACTIVATE_SEND_INIT_CMD: - fp_dbg("Activate: send init seq #%d cmd #%d\n", - priv->init_seq_idx, - priv->init_cmd_idx); - aesX660_send_cmd(ssm, _dev, - priv->init_seq[priv->init_cmd_idx].cmd, - priv->init_seq[priv->init_cmd_idx].len, - aesX660_send_cmd_cb); - break; - case ACTIVATE_READ_INIT_RESPONSE: - fp_dbg("Activate: read init response\n"); - aesX660_read_response(ssm, _dev, TRUE, FALSE, INIT_LEN, activate_read_init_cb); - break; - case ACTIVATE_SEND_CALIBRATE_CMD: - aesX660_send_cmd(ssm, _dev, calibrate_cmd, sizeof(calibrate_cmd), - aesX660_send_cmd_cb); - break; - case ACTIVATE_READ_CALIBRATE_DATA: - aesX660_read_response(ssm, _dev, TRUE, FALSE, CALIBRATE_DATA_LEN, aesX660_read_calibrate_data_cb); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case ACTIVATE_SET_IDLE: + priv->init_seq_idx = 0; + fp_dbg ("Activate: set idle\n"); + aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd), + aesX660_send_cmd_cb); + break; + + case ACTIVATE_SEND_READ_ID_CMD: + fp_dbg ("Activate: read ID\n"); + aesX660_send_cmd (ssm, _dev, read_id_cmd, sizeof (read_id_cmd), + aesX660_send_cmd_cb); + break; + + case ACTIVATE_READ_ID: + aesX660_read_response (ssm, _dev, TRUE, FALSE, ID_LEN, activate_read_id_cb); + break; + + case ACTIVATE_SEND_INIT_CMD: + fp_dbg ("Activate: send init seq #%d cmd #%d\n", + priv->init_seq_idx, + priv->init_cmd_idx); + aesX660_send_cmd (ssm, _dev, + priv->init_seq[priv->init_cmd_idx].cmd, + priv->init_seq[priv->init_cmd_idx].len, + aesX660_send_cmd_cb); + break; + + case ACTIVATE_READ_INIT_RESPONSE: + fp_dbg ("Activate: read init response\n"); + aesX660_read_response (ssm, _dev, TRUE, FALSE, INIT_LEN, activate_read_init_cb); + break; + + case ACTIVATE_SEND_CALIBRATE_CMD: + aesX660_send_cmd (ssm, _dev, calibrate_cmd, sizeof (calibrate_cmd), + aesX660_send_cmd_cb); + break; + + case ACTIVATE_READ_CALIBRATE_DATA: + aesX660_read_response (ssm, _dev, TRUE, FALSE, CALIBRATE_DATA_LEN, aesX660_read_calibrate_data_cb); + break; + } } -static void activate_sm_complete(FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +static void +activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - fpi_image_device_activate_complete (FP_IMAGE_DEVICE (_dev), error); - fpi_ssm_free(ssm); + fpi_image_device_activate_complete (FP_IMAGE_DEVICE (_dev), error); + fpi_ssm_free (ssm); - if (!error) - start_finger_detection(FP_IMAGE_DEVICE (_dev)); + if (!error) + start_finger_detection (FP_IMAGE_DEVICE (_dev)); } -static void aesX660_dev_activate(FpImageDevice *dev) +static void +aesX660_dev_activate (FpImageDevice *dev) { - FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); - fpi_ssm_start(ssm, activate_sm_complete); + FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); + + fpi_ssm_start (ssm, activate_sm_complete); } -static void aesX660_dev_deactivate(FpImageDevice *dev) +static void +aesX660_dev_deactivate (FpImageDevice *dev) { - FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); - FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); - priv->deactivating = TRUE; + priv->deactivating = TRUE; } -static void aesX660_dev_init(FpImageDevice *dev) +static void +aesX660_dev_init (FpImageDevice *dev) { - FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); - FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); - GError *error = NULL; + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + GError *error = NULL; - g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error); + g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error); - priv->stripe_packet = g_byte_array_new (); + priv->stripe_packet = g_byte_array_new (); - fpi_image_device_open_complete(dev, error); + fpi_image_device_open_complete (dev, error); } -static void aesX660_dev_deinit(FpImageDevice *dev) +static void +aesX660_dev_deinit (FpImageDevice *dev) { - FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); - FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); - GError *error = NULL; + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + GError *error = NULL; - g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), - 0, 0, &error); + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), + 0, 0, &error); - g_clear_pointer (&priv->stripe_packet, g_byte_array_unref); + g_clear_pointer (&priv->stripe_packet, g_byte_array_unref); - fpi_image_device_close_complete(dev, error); + fpi_image_device_close_complete (dev, error); } -static void complete_deactivation(FpImageDevice *dev) +static void +complete_deactivation (FpImageDevice *dev) { - FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); - FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (dev); + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); - G_DEBUG_HERE(); + G_DEBUG_HERE (); - priv->deactivating = FALSE; - g_slist_free(priv->strips); - priv->strips = NULL; - priv->strips_len = 0; - fpi_image_device_deactivate_complete(dev, NULL); + priv->deactivating = FALSE; + g_slist_free (priv->strips); + priv->strips = NULL; + priv->strips_len = 0; + fpi_image_device_deactivate_complete (dev, NULL); } -static void fpi_device_aes_x660_init(FpiDeviceAesX660 *self) { +static void +fpi_device_aes_x660_init (FpiDeviceAesX660 *self) +{ } -static void fpi_device_aes_x660_class_init(FpiDeviceAesX660Class *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); +static void +fpi_device_aes_x660_class_init (FpiDeviceAesX660Class *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - img_class->img_open = aesX660_dev_init; - img_class->img_close = aesX660_dev_deinit; - img_class->activate = aesX660_dev_activate; - img_class->deactivate = aesX660_dev_deactivate; + img_class->img_open = aesX660_dev_init; + img_class->img_close = aesX660_dev_deinit; + img_class->activate = aesX660_dev_activate; + img_class->deactivate = aesX660_dev_deactivate; - /* Everything else is set by the subclasses. */ + /* Everything else is set by the subclasses. */ } diff --git a/libfprint/drivers/aesx660.h b/libfprint/drivers/aesx660.h index 4d6faf56..baf36719 100644 --- a/libfprint/drivers/aesx660.h +++ b/libfprint/drivers/aesx660.h @@ -42,69 +42,70 @@ #define AESX660_FRAME_HEIGHT 8 -G_DECLARE_DERIVABLE_TYPE(FpiDeviceAesX660, fpi_device_aes_x660, FPI, - DEVICE_AES_X660, FpImageDevice) +G_DECLARE_DERIVABLE_TYPE (FpiDeviceAesX660, fpi_device_aes_x660, FPI, + DEVICE_AES_X660, FpImageDevice) #define FPI_TYPE_DEVICE_AES_X660 (fpi_device_aes_x660_get_type ()) -struct _FpiDeviceAesX660Class { - FpImageDeviceClass parent; +struct _FpiDeviceAesX660Class +{ + FpImageDeviceClass parent; - struct aesX660_cmd *init_seqs[2]; - gsize init_seqs_len[2]; - guint8 *start_imaging_cmd; - gsize start_imaging_cmd_len; + struct aesX660_cmd *init_seqs[2]; + gsize init_seqs_len[2]; + guint8 *start_imaging_cmd; + gsize start_imaging_cmd_len; struct fpi_frame_asmbl_ctx *assembling_ctx; }; -struct aesX660_cmd { +struct aesX660_cmd +{ const guint8 *cmd; - gsize len; + gsize len; }; /* 0x77 cmd seems to control LED, this sequence * makes LED blink */ static const guint8 led_blink_cmd[] = { -0x77, 0x18, 0x00, -0x00, 0x3f, 0x00, 0xff, 0x00, -0x01, 0x01, 0x00, 0x00, 0x00, 0xf3, 0x01, 0x00, -0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xf3, -0x01, 0x00, 0x7f + 0x77, 0x18, 0x00, + 0x00, 0x3f, 0x00, 0xff, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x00, 0xf3, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xf3, + 0x01, 0x00, 0x7f }; /* This sequence makes LED light solid */ static const guint8 led_solid_cmd[] = { -0x77, 0x18, 0x00, 0x00, 0x3f, 0x00, 0xff, 0x00, -0x01, 0x01, 0x00, 0x00, 0x00, 0xe7, 0x03, 0x00, -0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x7f + 0x77, 0x18, 0x00, 0x00, 0x3f, 0x00, 0xff, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x00, 0xe7, 0x03, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f }; static const guint8 wait_for_finger_cmd[] = { -0x20, -0x40, 0x04, 0x00, 0x02, 0x1e, 0x00, 0x32 + 0x20, + 0x40, 0x04, 0x00, 0x02, 0x1e, 0x00, 0x32 }; /* 0x40 cmd response * -static const guint8 pkt1371[] = { -0x40, 0x01, 0x00, 0x01 -}; -*/ + static const guint8 pkt1371[] = { + 0x40, 0x01, 0x00, 0x01 + }; + */ static const guint8 set_idle_cmd[] = { - 0x0d, /* Reset or "set idle"? */ + 0x0d, /* Reset or "set idle"? */ }; static const guint8 read_id_cmd[] = { - 0x44, 0x02, 0x00, 0x08, 0x00, /* Max transfer size is 8 */ - 0x07, /* Read ID? */ + 0x44, 0x02, 0x00, 0x08, 0x00, /* Max transfer size is 8 */ + 0x07, /* Read ID? */ }; static const guint8 calibrate_cmd[] = { - 0x44, 0x02, 0x00, 0x04, 0x00, - 0x06, + 0x44, 0x02, 0x00, 0x04, 0x00, + 0x06, }; - diff --git a/libfprint/drivers/driver_ids.h b/libfprint/drivers/driver_ids.h index 012a3d06..4270842d 100644 --- a/libfprint/drivers/driver_ids.h +++ b/libfprint/drivers/driver_ids.h @@ -21,27 +21,27 @@ #define __DRIVER_IDS enum { - UPEKTS_ID = 1, - URU4000_ID = 2, - AES4000_ID = 3, - AES2501_ID = 4, - UPEKTC_ID = 5, - AES1610_ID = 6, - /* FDU2000_ID = 7, */ - VCOM5S_ID = 8, - UPEKSONLY_ID = 9, - VFS101_ID = 10, - VFS301_ID = 11, - AES2550_ID = 12, - /* UPEKE2_ID = 13 */ - AES1660_ID = 14, - AES2660_ID = 15, - AES3500_ID = 16, - UPEKTC_IMG_ID = 17, - ETES603_ID = 18, - VFS5011_ID = 19, - VFS0050_ID = 20, - ELAN_ID = 21, + UPEKTS_ID = 1, + URU4000_ID = 2, + AES4000_ID = 3, + AES2501_ID = 4, + UPEKTC_ID = 5, + AES1610_ID = 6, + /* FDU2000_ID = 7, */ + VCOM5S_ID = 8, + UPEKSONLY_ID = 9, + VFS101_ID = 10, + VFS301_ID = 11, + AES2550_ID = 12, + /* UPEKE2_ID = 13 */ + AES1660_ID = 14, + AES2660_ID = 15, + AES3500_ID = 16, + UPEKTC_IMG_ID = 17, + ETES603_ID = 18, + VFS5011_ID = 19, + VFS0050_ID = 20, + ELAN_ID = 21, }; #endif diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c index 9771bb50..0010086f 100644 --- a/libfprint/drivers/elan.c +++ b/libfprint/drivers/elan.c @@ -41,120 +41,128 @@ #include "drivers_api.h" #include "elan.h" -unsigned char elan_get_pixel(struct fpi_frame_asmbl_ctx *ctx, - struct fpi_frame *frame, unsigned int x, - unsigned int y) +unsigned char +elan_get_pixel (struct fpi_frame_asmbl_ctx *ctx, + struct fpi_frame *frame, unsigned int x, + unsigned int y) { - return frame->data[x + y * ctx->frame_width]; + return frame->data[x + y * ctx->frame_width]; } static struct fpi_frame_asmbl_ctx assembling_ctx = { - .frame_width = 0, - .frame_height = 0, - .image_width = 0, - .get_pixel = elan_get_pixel, + .frame_width = 0, + .frame_height = 0, + .image_width = 0, + .get_pixel = elan_get_pixel, }; -struct _FpiDeviceElan { - FpImageDevice parent; +struct _FpiDeviceElan +{ + FpImageDevice parent; - /* device config */ - unsigned short dev_type; - unsigned short fw_ver; - void (*process_frame) (unsigned short *raw_frame, GSList ** frames); - /* end device config */ + /* device config */ + unsigned short dev_type; + unsigned short fw_ver; + void (*process_frame) (unsigned short *raw_frame, + GSList ** frames); + /* end device config */ - /* commands */ - const struct elan_cmd *cmd; - int cmd_timeout; - /* end commands */ + /* commands */ + const struct elan_cmd *cmd; + int cmd_timeout; + /* end commands */ - /* state */ - gboolean deactivating; - FpImageDeviceState dev_state; - FpImageDeviceState dev_state_next; - unsigned char *last_read; - unsigned char calib_atts_left; - unsigned char calib_status; - unsigned short *background; - unsigned char frame_width; - unsigned char frame_height; - unsigned char raw_frame_height; - int num_frames; - GSList *frames; - /* end state */ + /* state */ + gboolean deactivating; + FpImageDeviceState dev_state; + FpImageDeviceState dev_state_next; + unsigned char *last_read; + unsigned char calib_atts_left; + unsigned char calib_status; + unsigned short *background; + unsigned char frame_width; + unsigned char frame_height; + unsigned char raw_frame_height; + int num_frames; + GSList *frames; + /* end state */ }; -G_DECLARE_FINAL_TYPE(FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN, - FpImageDevice); -G_DEFINE_TYPE(FpiDeviceElan, fpi_device_elan, FP_TYPE_IMAGE_DEVICE); +G_DECLARE_FINAL_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN, + FpImageDevice); +G_DEFINE_TYPE (FpiDeviceElan, fpi_device_elan, FP_TYPE_IMAGE_DEVICE); -int cmp_short(const void *a, const void *b) +int +cmp_short (const void *a, const void *b) { - return (int)(*(short *)a - *(short *)b); + return (int) (*(short *) a - *(short *) b); } -static void elan_dev_reset_state(FpiDeviceElan *elandev) +static void +elan_dev_reset_state (FpiDeviceElan *elandev) { - G_DEBUG_HERE(); + G_DEBUG_HERE (); - elandev->cmd = NULL; - elandev->cmd_timeout = ELAN_CMD_TIMEOUT; + elandev->cmd = NULL; + elandev->cmd_timeout = ELAN_CMD_TIMEOUT; - elandev->calib_status = 0; + elandev->calib_status = 0; - g_free(elandev->last_read); - elandev->last_read = NULL; + g_free (elandev->last_read); + elandev->last_read = NULL; - g_slist_free_full(elandev->frames, g_free); - elandev->frames = NULL; - elandev->num_frames = 0; + g_slist_free_full (elandev->frames, g_free); + elandev->frames = NULL; + elandev->num_frames = 0; } -static void elan_save_frame(FpiDeviceElan *self, unsigned short *frame) +static void +elan_save_frame (FpiDeviceElan *self, unsigned short *frame) { - G_DEBUG_HERE(); + G_DEBUG_HERE (); - /* so far 3 types of readers by sensor dimensions and orientation have been - * seen in the wild: - * 1. 144x64. Raw images are in portrait orientation while readers themselves - * are placed (e.g. built into a touchpad) in landscape orientation. These - * need to be rotated before assembling. - * 2. 96x96 rotated. Like the first type but square. Likewise, need to be - * rotated before assembling. - * 3. 96x96 normal. Square and need NOT be rotated. So far there's only been - * 1 report of a 0c03 of this type. Hopefully this type can be identified - * by device id (and manufacturers don't just install the readers as they - * please). - * we also discard stripes of 'frame_margin' from bottom and top because - * assembling works bad for tall frames */ + /* so far 3 types of readers by sensor dimensions and orientation have been + * seen in the wild: + * 1. 144x64. Raw images are in portrait orientation while readers themselves + * are placed (e.g. built into a touchpad) in landscape orientation. These + * need to be rotated before assembling. + * 2. 96x96 rotated. Like the first type but square. Likewise, need to be + * rotated before assembling. + * 3. 96x96 normal. Square and need NOT be rotated. So far there's only been + * 1 report of a 0c03 of this type. Hopefully this type can be identified + * by device id (and manufacturers don't just install the readers as they + * please). + * we also discard stripes of 'frame_margin' from bottom and top because + * assembling works bad for tall frames */ - unsigned char frame_width = self->frame_width; - unsigned char frame_height = self->frame_height; - unsigned char raw_height = self->raw_frame_height; - unsigned char frame_margin = (raw_height - self->frame_height) / 2; - int frame_idx, raw_idx; + unsigned char frame_width = self->frame_width; + unsigned char frame_height = self->frame_height; + unsigned char raw_height = self->raw_frame_height; + unsigned char frame_margin = (raw_height - self->frame_height) / 2; + int frame_idx, raw_idx; - for (int y = 0; y < frame_height; y++) - for (int x = 0; x < frame_width; x++) { - if (self->dev_type & ELAN_NOT_ROTATED) - raw_idx = x + (y + frame_margin) * frame_width; - else - raw_idx = frame_margin + y + x * raw_height; - frame_idx = x + y * frame_width; - frame[frame_idx] = - ((unsigned short *) self->last_read)[raw_idx]; - } + for (int y = 0; y < frame_height; y++) + for (int x = 0; x < frame_width; x++) + { + if (self->dev_type & ELAN_NOT_ROTATED) + raw_idx = x + (y + frame_margin) * frame_width; + else + raw_idx = frame_margin + y + x * raw_height; + frame_idx = x + y * frame_width; + frame[frame_idx] = + ((unsigned short *) self->last_read)[raw_idx]; + } } -static void elan_save_background(FpiDeviceElan *elandev) +static void +elan_save_background (FpiDeviceElan *elandev) { - G_DEBUG_HERE(); + G_DEBUG_HERE (); - g_free(elandev->background); - elandev->background = - g_malloc(elandev->frame_width * elandev->frame_height * - sizeof(short)); - elan_save_frame(elandev, elandev->background); + g_free (elandev->background); + elandev->background = + g_malloc (elandev->frame_width * elandev->frame_height * + sizeof (short)); + elan_save_frame (elandev, elandev->background); } /* save a frame as part of the fingerprint image @@ -192,792 +200,904 @@ static void elan_save_background(FpiDeviceElan *elandev) * \ * ======== 0 \___> ======== 0 */ -static int elan_save_img_frame(FpiDeviceElan *elandev) +static int +elan_save_img_frame (FpiDeviceElan *elandev) { - G_DEBUG_HERE(); + G_DEBUG_HERE (); - unsigned int frame_size = elandev->frame_width * elandev->frame_height; - unsigned short *frame = g_malloc(frame_size * sizeof(short)); - elan_save_frame(elandev, frame); - unsigned int sum = 0; + unsigned int frame_size = elandev->frame_width * elandev->frame_height; + unsigned short *frame = g_malloc (frame_size * sizeof (short)); + elan_save_frame (elandev, frame); + unsigned int sum = 0; - for (int i = 0; i < frame_size; i++) { - if (elandev->background[i] > frame[i]) - frame[i] = 0; - else - frame[i] -= elandev->background[i]; - sum += frame[i]; - } + for (int i = 0; i < frame_size; i++) + { + if (elandev->background[i] > frame[i]) + frame[i] = 0; + else + frame[i] -= elandev->background[i]; + sum += frame[i]; + } - if (sum == 0) { - fp_dbg - ("frame darker than background; finger present during calibration?"); - return -1; - } + if (sum == 0) + { + fp_dbg + ("frame darker than background; finger present during calibration?"); + return -1; + } - elandev->frames = g_slist_prepend(elandev->frames, frame); - elandev->num_frames += 1; - return 0; -} - -static void elan_process_frame_linear(unsigned short *raw_frame, - GSList ** frames) -{ - unsigned int frame_size = - assembling_ctx.frame_width * assembling_ctx.frame_height; - struct fpi_frame *frame = - g_malloc(frame_size + sizeof(struct fpi_frame)); - - G_DEBUG_HERE(); - - unsigned short min = 0xffff, max = 0; - for (int i = 0; i < frame_size; i++) { - if (raw_frame[i] < min) - min = raw_frame[i]; - if (raw_frame[i] > max) - max = raw_frame[i]; - } - - g_assert(max != min); - - unsigned short px; - for (int i = 0; i < frame_size; i++) { - px = raw_frame[i]; - px = (px - min) * 0xff / (max - min); - frame->data[i] = (unsigned char)px; - } - - *frames = g_slist_prepend(*frames, frame); -} - -static void elan_process_frame_thirds(unsigned short *raw_frame, - GSList ** frames) -{ - G_DEBUG_HERE(); - - unsigned int frame_size = - assembling_ctx.frame_width * assembling_ctx.frame_height; - struct fpi_frame *frame = - g_malloc(frame_size + sizeof(struct fpi_frame)); - - unsigned short lvl0, lvl1, lvl2, lvl3; - unsigned short *sorted = g_malloc(frame_size * sizeof(short)); - memcpy(sorted, raw_frame, frame_size * sizeof(short)); - qsort(sorted, frame_size, sizeof(short), cmp_short); - lvl0 = sorted[0]; - lvl1 = sorted[frame_size * 3 / 10]; - lvl2 = sorted[frame_size * 65 / 100]; - lvl3 = sorted[frame_size - 1]; - g_free(sorted); - - unsigned short px; - for (int i = 0; i < frame_size; i++) { - px = raw_frame[i]; - if (lvl0 <= px && px < lvl1) - px = (px - lvl0) * 99 / (lvl1 - lvl0); - else if (lvl1 <= px && px < lvl2) - px = 99 + ((px - lvl1) * 56 / (lvl2 - lvl1)); - else // (lvl2 <= px && px <= lvl3) - px = 155 + ((px - lvl2) * 100 / (lvl3 - lvl2)); - frame->data[i] = (unsigned char)px; - } - - *frames = g_slist_prepend(*frames, frame); -} - -static void elan_submit_image(FpImageDevice *dev) -{ - FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); - GSList *raw_frames; - GSList *frames = NULL; - FpImage *img; - - G_DEBUG_HERE(); - - raw_frames = g_slist_nth(self->frames, ELAN_SKIP_LAST_FRAMES); - - assembling_ctx.frame_width = self->frame_width; - assembling_ctx.frame_height = self->frame_height; - assembling_ctx.image_width = self->frame_width * 3 / 2; - g_slist_foreach(raw_frames, (GFunc) self->process_frame, &frames); - fpi_do_movement_estimation(&assembling_ctx, frames); - img = fpi_assemble_frames(&assembling_ctx, frames); - - fpi_image_device_image_captured(dev, img); -} - -static void elan_cmd_done(FpiSsm *ssm) -{ - G_DEBUG_HERE(); - fpi_ssm_next_state(ssm); -} - -static void elan_cmd_cb(FpiUsbTransfer *transfer, FpDevice *dev, - gpointer user_data, GError *error) -{ - FpiSsm *ssm = transfer->ssm; - FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); - - G_DEBUG_HERE(); - - if (error) { - /* XXX: In the cancellation case we used to not - * mark the SSM as failed?! */ - fpi_ssm_mark_failed (transfer->ssm, error); - return; - } - - /* XXX: We used to reset the device in error cases! */ - if (transfer->endpoint & FPI_USB_ENDPOINT_IN) { - /* just finished receiving */ - self->last_read = g_memdup(transfer->buffer, transfer->actual_length); - elan_cmd_done(ssm); - } else { - /* just finished sending */ - G_DEBUG_HERE(); - elan_cmd_read(ssm, dev); - } -} - -static void elan_cmd_read(FpiSsm *ssm, FpDevice *dev) -{ - FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); - FpiUsbTransfer *transfer; - GCancellable *cancellable = NULL; - int response_len = self->cmd->response_len; - - G_DEBUG_HERE(); - - if (self->cmd->response_len == ELAN_CMD_SKIP_READ) { - fp_dbg("skipping read, not expecting anything"); - elan_cmd_done(ssm); - return; - } - - if (self->dev_type == ELAN_0C42) { - /* ELAN_0C42 sends an extra byte in one byte responses */ - if (self->cmd->response_len == 1) - response_len = 2; - } - - if (self->cmd->cmd == get_image_cmd.cmd) - /* raw data has 2-byte "pixels" and the frame is vertical */ - response_len = - self->raw_frame_height * self->frame_width * 2; - - g_clear_pointer(&self->last_read, g_free); - - transfer = fpi_usb_transfer_new (dev); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - - fpi_usb_transfer_fill_bulk (transfer, - self->cmd->response_in, - response_len); - - if (!self->cmd->never_cancel) - cancellable = fpi_device_get_cancellable (dev); - - fpi_usb_transfer_submit (transfer, self->cmd_timeout, cancellable, elan_cmd_cb, NULL); - fpi_usb_transfer_unref (transfer); + elandev->frames = g_slist_prepend (elandev->frames, frame); + elandev->num_frames += 1; + return 0; } static void -elan_run_cmd(FpiSsm *ssm, - FpDevice *dev, - const struct elan_cmd *cmd, - int cmd_timeout) +elan_process_frame_linear (unsigned short *raw_frame, + GSList ** frames) { - FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); - FpiUsbTransfer *transfer; - GCancellable *cancellable = NULL; + unsigned int frame_size = + assembling_ctx.frame_width * assembling_ctx.frame_height; + struct fpi_frame *frame = + g_malloc (frame_size + sizeof (struct fpi_frame)); - self->cmd = cmd; - if (cmd_timeout != -1) - self->cmd_timeout = cmd_timeout; + G_DEBUG_HERE (); - if (cmd->devices != ELAN_ALL_DEV && !(cmd->devices & self->dev_type)) { - fp_dbg("skipping command 0x%x 0x%x for this device (for devices 0x%x but device is 0x%x)", - cmd->cmd[0], cmd->cmd[1], cmd->devices, self->dev_type); - elan_cmd_done(ssm); - return; - } + unsigned short min = 0xffff, max = 0; + for (int i = 0; i < frame_size; i++) + { + if (raw_frame[i] < min) + min = raw_frame[i]; + if (raw_frame[i] > max) + max = raw_frame[i]; + } - transfer = fpi_usb_transfer_new (dev); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; + g_assert (max != min); - fpi_usb_transfer_fill_bulk_full (transfer, - ELAN_EP_CMD_OUT, - (guint8*) cmd->cmd, - ELAN_CMD_LEN, - NULL); + unsigned short px; + for (int i = 0; i < frame_size; i++) + { + px = raw_frame[i]; + px = (px - min) * 0xff / (max - min); + frame->data[i] = (unsigned char) px; + } - if (!self->cmd->never_cancel) - cancellable = fpi_device_get_cancellable (dev); + *frames = g_slist_prepend (*frames, frame); +} - fpi_usb_transfer_submit (transfer, - self->cmd_timeout, - cancellable, - elan_cmd_cb, - NULL); - fpi_usb_transfer_unref (transfer); +static void +elan_process_frame_thirds (unsigned short *raw_frame, + GSList ** frames) +{ + G_DEBUG_HERE (); + + unsigned int frame_size = + assembling_ctx.frame_width * assembling_ctx.frame_height; + struct fpi_frame *frame = + g_malloc (frame_size + sizeof (struct fpi_frame)); + + unsigned short lvl0, lvl1, lvl2, lvl3; + unsigned short *sorted = g_malloc (frame_size * sizeof (short)); + memcpy (sorted, raw_frame, frame_size * sizeof (short)); + qsort (sorted, frame_size, sizeof (short), cmp_short); + lvl0 = sorted[0]; + lvl1 = sorted[frame_size * 3 / 10]; + lvl2 = sorted[frame_size * 65 / 100]; + lvl3 = sorted[frame_size - 1]; + g_free (sorted); + + unsigned short px; + for (int i = 0; i < frame_size; i++) + { + px = raw_frame[i]; + if (lvl0 <= px && px < lvl1) + px = (px - lvl0) * 99 / (lvl1 - lvl0); + else if (lvl1 <= px && px < lvl2) + px = 99 + ((px - lvl1) * 56 / (lvl2 - lvl1)); + else // (lvl2 <= px && px <= lvl3) + px = 155 + ((px - lvl2) * 100 / (lvl3 - lvl2)); + frame->data[i] = (unsigned char) px; + } + + *frames = g_slist_prepend (*frames, frame); +} + +static void +elan_submit_image (FpImageDevice *dev) +{ + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + GSList *raw_frames; + GSList *frames = NULL; + FpImage *img; + + G_DEBUG_HERE (); + + raw_frames = g_slist_nth (self->frames, ELAN_SKIP_LAST_FRAMES); + + assembling_ctx.frame_width = self->frame_width; + assembling_ctx.frame_height = self->frame_height; + assembling_ctx.image_width = self->frame_width * 3 / 2; + g_slist_foreach (raw_frames, (GFunc) self->process_frame, &frames); + fpi_do_movement_estimation (&assembling_ctx, frames); + img = fpi_assemble_frames (&assembling_ctx, frames); + + fpi_image_device_image_captured (dev, img); +} + +static void +elan_cmd_done (FpiSsm *ssm) +{ + G_DEBUG_HERE (); + fpi_ssm_next_state (ssm); +} + +static void +elan_cmd_cb (FpiUsbTransfer *transfer, FpDevice *dev, + gpointer user_data, GError *error) +{ + FpiSsm *ssm = transfer->ssm; + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + + G_DEBUG_HERE (); + + if (error) + { + /* XXX: In the cancellation case we used to not + * mark the SSM as failed?! */ + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } + + /* XXX: We used to reset the device in error cases! */ + if (transfer->endpoint & FPI_USB_ENDPOINT_IN) + { + /* just finished receiving */ + self->last_read = g_memdup (transfer->buffer, transfer->actual_length); + elan_cmd_done (ssm); + } + else + { + /* just finished sending */ + G_DEBUG_HERE (); + elan_cmd_read (ssm, dev); + } +} + +static void +elan_cmd_read (FpiSsm *ssm, FpDevice *dev) +{ + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + FpiUsbTransfer *transfer; + GCancellable *cancellable = NULL; + int response_len = self->cmd->response_len; + + G_DEBUG_HERE (); + + if (self->cmd->response_len == ELAN_CMD_SKIP_READ) + { + fp_dbg ("skipping read, not expecting anything"); + elan_cmd_done (ssm); + return; + } + + if (self->dev_type == ELAN_0C42) + { + /* ELAN_0C42 sends an extra byte in one byte responses */ + if (self->cmd->response_len == 1) + response_len = 2; + } + + if (self->cmd->cmd == get_image_cmd.cmd) + /* raw data has 2-byte "pixels" and the frame is vertical */ + response_len = + self->raw_frame_height * self->frame_width * 2; + + g_clear_pointer (&self->last_read, g_free); + + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + + fpi_usb_transfer_fill_bulk (transfer, + self->cmd->response_in, + response_len); + + if (!self->cmd->never_cancel) + cancellable = fpi_device_get_cancellable (dev); + + fpi_usb_transfer_submit (transfer, self->cmd_timeout, cancellable, elan_cmd_cb, NULL); + fpi_usb_transfer_unref (transfer); +} + +static void +elan_run_cmd (FpiSsm *ssm, + FpDevice *dev, + const struct elan_cmd *cmd, + int cmd_timeout) +{ + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + FpiUsbTransfer *transfer; + GCancellable *cancellable = NULL; + + self->cmd = cmd; + if (cmd_timeout != -1) + self->cmd_timeout = cmd_timeout; + + if (cmd->devices != ELAN_ALL_DEV && !(cmd->devices & self->dev_type)) + { + fp_dbg ("skipping command 0x%x 0x%x for this device (for devices 0x%x but device is 0x%x)", + cmd->cmd[0], cmd->cmd[1], cmd->devices, self->dev_type); + elan_cmd_done (ssm); + return; + } + + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + + fpi_usb_transfer_fill_bulk_full (transfer, + ELAN_EP_CMD_OUT, + (guint8 *) cmd->cmd, + ELAN_CMD_LEN, + NULL); + + if (!self->cmd->never_cancel) + cancellable = fpi_device_get_cancellable (dev); + + fpi_usb_transfer_submit (transfer, + self->cmd_timeout, + cancellable, + elan_cmd_cb, + NULL); + fpi_usb_transfer_unref (transfer); } enum stop_capture_states { - STOP_CAPTURE, - STOP_CAPTURE_NUM_STATES, + STOP_CAPTURE, + STOP_CAPTURE_NUM_STATES, }; -static void stop_capture_run_state(FpiSsm *ssm, FpDevice *dev, - void *user_data) +static void +stop_capture_run_state (FpiSsm *ssm, FpDevice *dev, + void *user_data) { - G_DEBUG_HERE(); + G_DEBUG_HERE (); - switch (fpi_ssm_get_cur_state(ssm)) { - case STOP_CAPTURE: - elan_run_cmd(ssm, dev, &stop_cmd, - ELAN_CMD_TIMEOUT); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case STOP_CAPTURE: + elan_run_cmd (ssm, dev, &stop_cmd, + ELAN_CMD_TIMEOUT); + break; + } } -static void stop_capture_complete(FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +static void +stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - FpImageDevice *dev = user_data; - FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); + FpImageDevice *dev = user_data; + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); - G_DEBUG_HERE(); + G_DEBUG_HERE (); - fpi_ssm_free(ssm); + fpi_ssm_free (ssm); - /* The device is inactive at this point. */ - self->dev_state = FP_IMAGE_DEVICE_STATE_INACTIVE; + /* The device is inactive at this point. */ + self->dev_state = FP_IMAGE_DEVICE_STATE_INACTIVE; - if (self->deactivating) { - /* Simply complete the pending deactivation. */ - self->deactivating = FALSE; - fpi_image_device_deactivate_complete (dev, error); - return; - } + if (self->deactivating) + { + /* Simply complete the pending deactivation. */ + self->deactivating = FALSE; + fpi_image_device_deactivate_complete (dev, error); + return; + } - if (!error) { - fpi_image_device_report_finger_status(dev, FALSE); - } else { - /* NOTE: We cannot get a cancellation error here. */ - fpi_image_device_session_error (dev, error); - } + if (!error) + fpi_image_device_report_finger_status (dev, FALSE); + else + /* NOTE: We cannot get a cancellation error here. */ + fpi_image_device_session_error (dev, error); } -static void elan_stop_capture(FpDevice *dev) +static void +elan_stop_capture (FpDevice *dev) { - FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); - G_DEBUG_HERE(); + G_DEBUG_HERE (); - elan_dev_reset_state(self); + elan_dev_reset_state (self); - FpiSsm *ssm = - fpi_ssm_new(dev, stop_capture_run_state, - STOP_CAPTURE_NUM_STATES, dev); - fpi_ssm_start(ssm, stop_capture_complete); + FpiSsm *ssm = + fpi_ssm_new (dev, stop_capture_run_state, + STOP_CAPTURE_NUM_STATES, dev); + fpi_ssm_start (ssm, stop_capture_complete); } enum capture_states { - CAPTURE_LED_ON, - CAPTURE_WAIT_FINGER, - CAPTURE_READ_DATA, - CAPTURE_CHECK_ENOUGH_FRAMES, - CAPTURE_NUM_STATES, + CAPTURE_LED_ON, + CAPTURE_WAIT_FINGER, + CAPTURE_READ_DATA, + CAPTURE_CHECK_ENOUGH_FRAMES, + CAPTURE_NUM_STATES, }; -static void capture_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) +static void +capture_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) { - FpImageDevice *idev = FP_IMAGE_DEVICE(dev); - FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); - int r; + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + int r; - switch (fpi_ssm_get_cur_state(ssm)) { - case CAPTURE_LED_ON: - elan_run_cmd(ssm, dev, &led_on_cmd, ELAN_CMD_TIMEOUT); - break; - case CAPTURE_WAIT_FINGER: - elan_run_cmd(ssm, dev, &pre_scan_cmd, -1); - break; - case CAPTURE_READ_DATA: - self->dev_state = FP_IMAGE_DEVICE_STATE_CAPTURE; + switch (fpi_ssm_get_cur_state (ssm)) + { + case CAPTURE_LED_ON: + elan_run_cmd (ssm, dev, &led_on_cmd, ELAN_CMD_TIMEOUT); + break; - /* 0x55 - finger present - * 0xff - device not calibrated (probably) */ - if (self->last_read && self->last_read[0] == 0x55) { - fpi_image_device_report_finger_status(idev, TRUE); - elan_run_cmd(ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT); - } else { - fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - } - break; - case CAPTURE_CHECK_ENOUGH_FRAMES: - r = elan_save_img_frame(self); - if (r < 0) - fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); - else if (self->num_frames < ELAN_MAX_FRAMES) { - /* quickly stop if finger is removed */ - self->cmd_timeout = ELAN_FINGER_TIMEOUT; - fpi_ssm_jump_to_state(ssm, CAPTURE_WAIT_FINGER); - } else { - fpi_ssm_next_state(ssm); - } - break; - } + case CAPTURE_WAIT_FINGER: + elan_run_cmd (ssm, dev, &pre_scan_cmd, -1); + break; + + case CAPTURE_READ_DATA: + self->dev_state = FP_IMAGE_DEVICE_STATE_CAPTURE; + + /* 0x55 - finger present + * 0xff - device not calibrated (probably) */ + if (self->last_read && self->last_read[0] == 0x55) + { + fpi_image_device_report_finger_status (idev, TRUE); + elan_run_cmd (ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT); + } + else + { + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + } + break; + + case CAPTURE_CHECK_ENOUGH_FRAMES: + r = elan_save_img_frame (self); + if (r < 0) + { + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + } + else if (self->num_frames < ELAN_MAX_FRAMES) + { + /* quickly stop if finger is removed */ + self->cmd_timeout = ELAN_FINGER_TIMEOUT; + fpi_ssm_jump_to_state (ssm, CAPTURE_WAIT_FINGER); + } + else + { + fpi_ssm_next_state (ssm); + } + break; + } } -static void capture_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +static void +capture_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - FpImageDevice *dev = user_data; - FpiDeviceElan *self = FPI_DEVICE_ELAN(_dev); + FpImageDevice *dev = user_data; + FpiDeviceElan *self = FPI_DEVICE_ELAN (_dev); - G_DEBUG_HERE(); + G_DEBUG_HERE (); - /* XXX: cancellation was specially handled by doing nothing! */ + /* XXX: cancellation was specially handled by doing nothing! */ - /* either max frames captured or timed out waiting for the next frame */ - if (!error || - (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) && - fpi_ssm_get_cur_state(ssm) == CAPTURE_WAIT_FINGER)) { - if (self->num_frames >= ELAN_MIN_FRAMES) - elan_submit_image(dev); - else { - fp_dbg("swipe too short: want >= %d frames, got %d", - ELAN_MIN_FRAMES, self->num_frames); - fpi_image_device_retry_scan(dev, FP_DEVICE_RETRY_TOO_SHORT); - } - g_clear_error (&error); - } else { - fpi_image_device_session_error (dev, error); - } + /* either max frames captured or timed out waiting for the next frame */ + if (!error || + (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) && + fpi_ssm_get_cur_state (ssm) == CAPTURE_WAIT_FINGER)) + { + if (self->num_frames >= ELAN_MIN_FRAMES) + { + elan_submit_image (dev); + } + else + { + fp_dbg ("swipe too short: want >= %d frames, got %d", + ELAN_MIN_FRAMES, self->num_frames); + fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT); + } + g_clear_error (&error); + } + else + { + fpi_image_device_session_error (dev, error); + } - fpi_ssm_free(ssm); + fpi_ssm_free (ssm); } -static void elan_capture(FpDevice *dev) +static void +elan_capture (FpDevice *dev) { - FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); - G_DEBUG_HERE(); + G_DEBUG_HERE (); - elan_dev_reset_state(self); - FpiSsm *ssm = - fpi_ssm_new(dev, capture_run_state, CAPTURE_NUM_STATES, - dev); - fpi_ssm_start(ssm, capture_complete); + elan_dev_reset_state (self); + FpiSsm *ssm = + fpi_ssm_new (dev, capture_run_state, CAPTURE_NUM_STATES, + dev); + fpi_ssm_start (ssm, capture_complete); } /* this function needs to have elandev->background and elandev->last_read to be * the calibration mean */ -static int elan_need_calibration(FpiDeviceElan *elandev) +static int +elan_need_calibration (FpiDeviceElan *elandev) { - G_DEBUG_HERE(); + G_DEBUG_HERE (); - unsigned short calib_mean = - elandev->last_read[0] * 0xff + elandev->last_read[1]; - unsigned int bg_mean = 0, delta; - unsigned int frame_size = elandev->frame_width * elandev->frame_height; + unsigned short calib_mean = + elandev->last_read[0] * 0xff + elandev->last_read[1]; + unsigned int bg_mean = 0, delta; + unsigned int frame_size = elandev->frame_width * elandev->frame_height; - g_assert(frame_size != 0); + g_assert (frame_size != 0); - if (elandev->dev_type == ELAN_0C42) { - if (calib_mean > 5500 || - calib_mean < 2500) { - fp_dbg("Forcing needed recalibration"); - return 1; - } - } + if (elandev->dev_type == ELAN_0C42) + { + if (calib_mean > 5500 || + calib_mean < 2500) + { + fp_dbg ("Forcing needed recalibration"); + return 1; + } + } - for (int i = 0; i < frame_size; i++) - bg_mean += elandev->background[i]; - bg_mean /= frame_size; + for (int i = 0; i < frame_size; i++) + bg_mean += elandev->background[i]; + bg_mean /= frame_size; - delta = - bg_mean > calib_mean ? bg_mean - calib_mean : calib_mean - bg_mean; + delta = + bg_mean > calib_mean ? bg_mean - calib_mean : calib_mean - bg_mean; - fp_dbg("calibration mean: %d, bg mean: %d, delta: %d", calib_mean, - bg_mean, delta); + fp_dbg ("calibration mean: %d, bg mean: %d, delta: %d", calib_mean, + bg_mean, delta); - return delta > ELAN_CALIBRATION_MAX_DELTA ? 1 : 0; + return delta > ELAN_CALIBRATION_MAX_DELTA ? 1 : 0; } enum calibrate_states { - CALIBRATE_GET_BACKGROUND, - CALIBRATE_SAVE_BACKGROUND, - CALIBRATE_GET_MEAN, - CALIBRATE_CHECK_NEEDED, - CALIBRATE_GET_STATUS, - CALIBRATE_CHECK_STATUS, - CALIBRATE_REPEAT_STATUS, - CALIBRATE_NUM_STATES, + CALIBRATE_GET_BACKGROUND, + CALIBRATE_SAVE_BACKGROUND, + CALIBRATE_GET_MEAN, + CALIBRATE_CHECK_NEEDED, + CALIBRATE_GET_STATUS, + CALIBRATE_CHECK_STATUS, + CALIBRATE_REPEAT_STATUS, + CALIBRATE_NUM_STATES, }; -static gboolean elan_supports_calibration(FpiDeviceElan *elandev) +static gboolean +elan_supports_calibration (FpiDeviceElan *elandev) { - if (elandev->dev_type == ELAN_0C42) - return TRUE; + if (elandev->dev_type == ELAN_0C42) + return TRUE; - return elandev->fw_ver >= ELAN_MIN_CALIBRATION_FW; -} - -static void calibrate_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) -{ - FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); - - G_DEBUG_HERE(); - - switch (fpi_ssm_get_cur_state(ssm)) { - case CALIBRATE_GET_BACKGROUND: - elan_run_cmd(ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT); - break; - case CALIBRATE_SAVE_BACKGROUND: - elan_save_background(self); - if (!elan_supports_calibration(self)) { - fp_dbg("FW does not support calibration"); - fpi_ssm_mark_completed(ssm); - } else - fpi_ssm_next_state(ssm); - break; - case CALIBRATE_GET_MEAN: - elan_run_cmd(ssm, dev, &get_calib_mean_cmd, ELAN_CMD_TIMEOUT); - break; - case CALIBRATE_CHECK_NEEDED: - if (elan_need_calibration(self)) { - self->calib_status = 0; - fpi_ssm_next_state(ssm); - } else - fpi_ssm_mark_completed(ssm); - break; - case CALIBRATE_GET_STATUS: - self->calib_atts_left -= 1; - if (self->calib_atts_left) - elan_run_cmd(ssm, dev, &get_calib_status_cmd, - ELAN_CMD_TIMEOUT); - else { - fp_dbg("calibration failed"); - fpi_ssm_mark_failed(ssm, - fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, - "Callibration failed!")); - } - break; - case CALIBRATE_CHECK_STATUS: - /* 0x01 - retry, 0x03 - ok - * It appears that when reading the response soon after 0x4023 the device - * can return 0x03, and only after some time (up to 100 ms) the response - * changes to 0x01. It stays that way for some time and then changes back - * to 0x03. Because of this we don't just expect 0x03, we want to see 0x01 - * first. This is to make sure that a full calibration loop has completed */ - fp_dbg("calibration status: 0x%02x", self->last_read[0]); - if (self->calib_status == 0x01 - && self->last_read[0] == 0x03) { - self->calib_status = 0x03; - fpi_ssm_jump_to_state(ssm, CALIBRATE_GET_BACKGROUND); - } else { - GSource *timeout; - - if (self->calib_status == 0x00 - && self->last_read[0] == 0x01) - self->calib_status = 0x01; - timeout = fpi_device_add_timeout(dev, 50, - fpi_ssm_next_state_timeout_cb, - ssm); - g_source_set_name(timeout, "calibrate_run_state"); - } - break; - case CALIBRATE_REPEAT_STATUS: - fpi_ssm_jump_to_state(ssm, CALIBRATE_GET_STATUS); - break; - } -} - -static void calibrate_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) -{ - FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); - - G_DEBUG_HERE(); - - if (error) { - self->dev_state = FP_IMAGE_DEVICE_STATE_INACTIVE; - fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error); - } else { - self->dev_state = FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON; - elan_capture(dev); - } - - fpi_ssm_free(ssm); -} - -static void elan_calibrate(FpDevice *dev) -{ - FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); - - G_DEBUG_HERE(); - - elan_dev_reset_state(self); - self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS; - - FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(dev), calibrate_run_state, - CALIBRATE_NUM_STATES, dev); - fpi_ssm_start(ssm, calibrate_complete); -} - -enum activate_states { - ACTIVATE_GET_FW_VER, - ACTIVATE_SET_FW_VER, - ACTIVATE_GET_SENSOR_DIM, - ACTIVATE_SET_SENSOR_DIM, - ACTIVATE_CMD_1, - ACTIVATE_NUM_STATES, -}; - -static void activate_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) -{ - FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); - - G_DEBUG_HERE(); - - switch (fpi_ssm_get_cur_state(ssm)) { - case ACTIVATE_GET_FW_VER: - elan_run_cmd(ssm, dev, &get_fw_ver_cmd, ELAN_CMD_TIMEOUT); - break; - case ACTIVATE_SET_FW_VER: - self->fw_ver = - (self->last_read[0] << 8 | self->last_read[1]); - fp_dbg("FW ver 0x%04hx", self->fw_ver); - fpi_ssm_next_state(ssm); - break; - case ACTIVATE_GET_SENSOR_DIM: - elan_run_cmd(ssm, dev, &get_sensor_dim_cmd, ELAN_CMD_TIMEOUT); - break; - case ACTIVATE_SET_SENSOR_DIM: - /* see elan_save_frame for details */ - if (self->dev_type & ELAN_NOT_ROTATED) { - self->frame_width = self->last_read[0]; - self->frame_height = self->raw_frame_height = - self->last_read[2]; - } else { - self->frame_width = self->last_read[2]; - self->frame_height = self->raw_frame_height = - self->last_read[0]; - } - /* Work-around sensors returning the sizes as zero-based index - * rather than the number of pixels. */ - if ((self->frame_width % 2 == 1) && - (self->frame_height % 2 == 1)) { - self->frame_width++; - self->frame_height++; - self->raw_frame_height = self->frame_height; - } - if (self->frame_height > ELAN_MAX_FRAME_HEIGHT) - self->frame_height = ELAN_MAX_FRAME_HEIGHT; - fp_dbg("sensor dimensions, WxH: %dx%d", self->frame_width, - self->raw_frame_height); - fpi_ssm_next_state(ssm); - break; - case ACTIVATE_CMD_1: - /* TODO: find out what this does, if we need it */ - elan_run_cmd(ssm, dev, &activate_cmd_1, ELAN_CMD_TIMEOUT); - break; - } -} - -static void activate_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) -{ - FpImageDevice *idev = FP_IMAGE_DEVICE (dev); - - G_DEBUG_HERE(); - - fpi_image_device_activate_complete (idev, error); - - fpi_ssm_free(ssm); -} - -static void elan_activate(FpImageDevice *dev) -{ - FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); - - G_DEBUG_HERE(); - elan_dev_reset_state(self); - - FpiSsm *ssm = - fpi_ssm_new(FP_DEVICE(dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); - fpi_ssm_start(ssm, activate_complete); -} - -static void dev_init(FpImageDevice *dev) -{ - GError *error = NULL; - FpiDeviceElan *self; - - G_DEBUG_HERE(); - - if (!g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error)) { - fpi_image_device_open_complete(dev, error); - return; - } - - self = FPI_DEVICE_ELAN(dev); - - /* common params */ - self->dev_type = fpi_device_get_driver_data (FP_DEVICE (dev)); - self->background = NULL; - self->process_frame = elan_process_frame_thirds; - - switch (self->dev_type) { - case ELAN_0907: - self->process_frame = elan_process_frame_linear; - break; - } - - fpi_image_device_open_complete(dev, NULL); -} - -static void dev_deinit(FpImageDevice *dev) -{ - GError *error = NULL; - FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); - - G_DEBUG_HERE(); - - elan_dev_reset_state(self); - g_free(self->background); - g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), - 0, 0, &error); - fpi_image_device_close_complete(dev, error); -} - -static void dev_activate(FpImageDevice *dev) -{ - G_DEBUG_HERE(); - elan_activate(dev); -} - -static void elan_change_state(FpImageDevice *idev) -{ - FpDevice *dev = FP_DEVICE(idev); - FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); - FpImageDeviceState next_state = self->dev_state_next; - - if (self->dev_state == next_state) { - fp_dbg("already in %d", next_state); - return; - } else { - fp_dbg("changing to %d", next_state); - } - - switch (next_state) { - break; - case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: - /* activation completed or another enroll stage started */ - elan_calibrate(dev); - break; - case FP_IMAGE_DEVICE_STATE_CAPTURE: - /* not used */ - break; - case FP_IMAGE_DEVICE_STATE_INACTIVE: - case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: - if (self->dev_state != FP_IMAGE_DEVICE_STATE_INACTIVE || - self->dev_state != FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF) - elan_stop_capture(dev); - } + return elandev->fw_ver >= ELAN_MIN_CALIBRATION_FW; } static void -elan_change_state_async(FpDevice *dev, - void *data) +calibrate_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) { - g_message ("state change dev: %p", dev); - elan_change_state(FP_IMAGE_DEVICE(dev)); + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + + G_DEBUG_HERE (); + + switch (fpi_ssm_get_cur_state (ssm)) + { + case CALIBRATE_GET_BACKGROUND: + elan_run_cmd (ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT); + break; + + case CALIBRATE_SAVE_BACKGROUND: + elan_save_background (self); + if (!elan_supports_calibration (self)) + { + fp_dbg ("FW does not support calibration"); + fpi_ssm_mark_completed (ssm); + } + else + { + fpi_ssm_next_state (ssm); + } + break; + + case CALIBRATE_GET_MEAN: + elan_run_cmd (ssm, dev, &get_calib_mean_cmd, ELAN_CMD_TIMEOUT); + break; + + case CALIBRATE_CHECK_NEEDED: + if (elan_need_calibration (self)) + { + self->calib_status = 0; + fpi_ssm_next_state (ssm); + } + else + { + fpi_ssm_mark_completed (ssm); + } + break; + + case CALIBRATE_GET_STATUS: + self->calib_atts_left -= 1; + if (self->calib_atts_left) + { + elan_run_cmd (ssm, dev, &get_calib_status_cmd, + ELAN_CMD_TIMEOUT); + } + else + { + fp_dbg ("calibration failed"); + fpi_ssm_mark_failed (ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Callibration failed!")); + } + break; + + case CALIBRATE_CHECK_STATUS: + /* 0x01 - retry, 0x03 - ok + * It appears that when reading the response soon after 0x4023 the device + * can return 0x03, and only after some time (up to 100 ms) the response + * changes to 0x01. It stays that way for some time and then changes back + * to 0x03. Because of this we don't just expect 0x03, we want to see 0x01 + * first. This is to make sure that a full calibration loop has completed */ + fp_dbg ("calibration status: 0x%02x", self->last_read[0]); + if (self->calib_status == 0x01 && + self->last_read[0] == 0x03) + { + self->calib_status = 0x03; + fpi_ssm_jump_to_state (ssm, CALIBRATE_GET_BACKGROUND); + } + else + { + GSource *timeout; + + if (self->calib_status == 0x00 && + self->last_read[0] == 0x01) + self->calib_status = 0x01; + timeout = fpi_device_add_timeout (dev, 50, + fpi_ssm_next_state_timeout_cb, + ssm); + g_source_set_name (timeout, "calibrate_run_state"); + } + break; + + case CALIBRATE_REPEAT_STATUS: + fpi_ssm_jump_to_state (ssm, CALIBRATE_GET_STATUS); + break; + } } -static void dev_change_state(FpImageDevice *dev, FpImageDeviceState state) +static void +calibrate_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); - GSource *timeout; + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); - G_DEBUG_HERE(); + G_DEBUG_HERE (); - /* Inactive and await finger off are equivalent for the elan driver. */ - if (state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF) - state = FP_IMAGE_DEVICE_STATE_INACTIVE; + if (error) + { + self->dev_state = FP_IMAGE_DEVICE_STATE_INACTIVE; + fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error); + } + else + { + self->dev_state = FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON; + elan_capture (dev); + } - if (self->dev_state_next == state) { - fp_dbg ("change to state %d already queued", state); - } - - switch (state) { - case FP_IMAGE_DEVICE_STATE_INACTIVE: - case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: - case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: { - char *name; - - /* schedule state change instead of calling it directly to allow all actions - * related to the previous state to complete */ - self->dev_state_next = state; - timeout = fpi_device_add_timeout(FP_DEVICE(dev), 10, - elan_change_state_async, - NULL); - - name = g_strdup_printf ("dev_change_state to %d", state); - g_source_set_name(timeout, name); - g_free (name); - - break; - } - case FP_IMAGE_DEVICE_STATE_CAPTURE: - /* TODO MAYBE: split capture ssm into smaller ssms and use this state */ - self->dev_state = state; - self->dev_state_next = state; - break; - default: - g_assert_not_reached(); - } + fpi_ssm_free (ssm); } -static void dev_deactivate(FpImageDevice *dev) +static void +elan_calibrate (FpDevice *dev) { - FpiDeviceElan *self = FPI_DEVICE_ELAN(dev); - G_DEBUG_HERE(); + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); - if (self->dev_state == FP_IMAGE_DEVICE_STATE_INACTIVE) { - /* The device is inactive already, complete the operation immediately. */ - fpi_image_device_deactivate_complete (dev, NULL); - } else { - /* The device is not yet inactive, flag that we are deactivating (and - * need to signal back deactivation) and then ensure we will change - * to the inactive state eventually. */ - self->deactivating = TRUE; - dev_change_state (dev, FP_IMAGE_DEVICE_STATE_INACTIVE); - } + G_DEBUG_HERE (); + + elan_dev_reset_state (self); + self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS; + + FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), calibrate_run_state, + CALIBRATE_NUM_STATES, dev); + fpi_ssm_start (ssm, calibrate_complete); } -static void fpi_device_elan_init(FpiDeviceElan *self) { +enum activate_states { + ACTIVATE_GET_FW_VER, + ACTIVATE_SET_FW_VER, + ACTIVATE_GET_SENSOR_DIM, + ACTIVATE_SET_SENSOR_DIM, + ACTIVATE_CMD_1, + ACTIVATE_NUM_STATES, +}; + +static void +activate_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +{ + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + + G_DEBUG_HERE (); + + switch (fpi_ssm_get_cur_state (ssm)) + { + case ACTIVATE_GET_FW_VER: + elan_run_cmd (ssm, dev, &get_fw_ver_cmd, ELAN_CMD_TIMEOUT); + break; + + case ACTIVATE_SET_FW_VER: + self->fw_ver = + (self->last_read[0] << 8 | self->last_read[1]); + fp_dbg ("FW ver 0x%04hx", self->fw_ver); + fpi_ssm_next_state (ssm); + break; + + case ACTIVATE_GET_SENSOR_DIM: + elan_run_cmd (ssm, dev, &get_sensor_dim_cmd, ELAN_CMD_TIMEOUT); + break; + + case ACTIVATE_SET_SENSOR_DIM: + /* see elan_save_frame for details */ + if (self->dev_type & ELAN_NOT_ROTATED) + { + self->frame_width = self->last_read[0]; + self->frame_height = self->raw_frame_height = + self->last_read[2]; + } + else + { + self->frame_width = self->last_read[2]; + self->frame_height = self->raw_frame_height = + self->last_read[0]; + } + /* Work-around sensors returning the sizes as zero-based index + * rather than the number of pixels. */ + if ((self->frame_width % 2 == 1) && + (self->frame_height % 2 == 1)) + { + self->frame_width++; + self->frame_height++; + self->raw_frame_height = self->frame_height; + } + if (self->frame_height > ELAN_MAX_FRAME_HEIGHT) + self->frame_height = ELAN_MAX_FRAME_HEIGHT; + fp_dbg ("sensor dimensions, WxH: %dx%d", self->frame_width, + self->raw_frame_height); + fpi_ssm_next_state (ssm); + break; + + case ACTIVATE_CMD_1: + /* TODO: find out what this does, if we need it */ + elan_run_cmd (ssm, dev, &activate_cmd_1, ELAN_CMD_TIMEOUT); + break; + } } -static void fpi_device_elan_class_init(FpiDeviceElanClass *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); - dev_class->id = "elan"; - dev_class->full_name = "ElanTech Fingerprint Sensor"; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->id_table = elan_id_table; - dev_class->scan_type = FP_SCAN_TYPE_SWIPE; +static void +activate_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) +{ + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); - img_class->img_open = dev_init; - img_class->img_close = dev_deinit; - img_class->activate = dev_activate; - img_class->deactivate = dev_deactivate; - img_class->change_state = dev_change_state; + G_DEBUG_HERE (); - img_class->bz3_threshold = 24; + fpi_image_device_activate_complete (idev, error); + + fpi_ssm_free (ssm); +} + +static void +elan_activate (FpImageDevice *dev) +{ + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + + G_DEBUG_HERE (); + elan_dev_reset_state (self); + + FpiSsm *ssm = + fpi_ssm_new (FP_DEVICE (dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); + fpi_ssm_start (ssm, activate_complete); +} + +static void +dev_init (FpImageDevice *dev) +{ + GError *error = NULL; + FpiDeviceElan *self; + + G_DEBUG_HERE (); + + if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error)) + { + fpi_image_device_open_complete (dev, error); + return; + } + + self = FPI_DEVICE_ELAN (dev); + + /* common params */ + self->dev_type = fpi_device_get_driver_data (FP_DEVICE (dev)); + self->background = NULL; + self->process_frame = elan_process_frame_thirds; + + switch (self->dev_type) + { + case ELAN_0907: + self->process_frame = elan_process_frame_linear; + break; + } + + fpi_image_device_open_complete (dev, NULL); +} + +static void +dev_deinit (FpImageDevice *dev) +{ + GError *error = NULL; + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + + G_DEBUG_HERE (); + + elan_dev_reset_state (self); + g_free (self->background); + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), + 0, 0, &error); + fpi_image_device_close_complete (dev, error); +} + +static void +dev_activate (FpImageDevice *dev) +{ + G_DEBUG_HERE (); + elan_activate (dev); +} + +static void +elan_change_state (FpImageDevice *idev) +{ + FpDevice *dev = FP_DEVICE (idev); + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + FpImageDeviceState next_state = self->dev_state_next; + + if (self->dev_state == next_state) + { + fp_dbg ("already in %d", next_state); + return; + } + else + { + fp_dbg ("changing to %d", next_state); + } + + switch (next_state) + { + break; + + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: + /* activation completed or another enroll stage started */ + elan_calibrate (dev); + break; + + case FP_IMAGE_DEVICE_STATE_CAPTURE: + /* not used */ + break; + + case FP_IMAGE_DEVICE_STATE_INACTIVE: + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: + if (self->dev_state != FP_IMAGE_DEVICE_STATE_INACTIVE || + self->dev_state != FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF) + elan_stop_capture (dev); + } +} + +static void +elan_change_state_async (FpDevice *dev, + void *data) +{ + g_message ("state change dev: %p", dev); + elan_change_state (FP_IMAGE_DEVICE (dev)); +} + +static void +dev_change_state (FpImageDevice *dev, FpImageDeviceState state) +{ + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + GSource *timeout; + + G_DEBUG_HERE (); + + /* Inactive and await finger off are equivalent for the elan driver. */ + if (state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF) + state = FP_IMAGE_DEVICE_STATE_INACTIVE; + + if (self->dev_state_next == state) + fp_dbg ("change to state %d already queued", state); + + switch (state) + { + case FP_IMAGE_DEVICE_STATE_INACTIVE: + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: { + char *name; + + /* schedule state change instead of calling it directly to allow all actions + * related to the previous state to complete */ + self->dev_state_next = state; + timeout = fpi_device_add_timeout (FP_DEVICE (dev), 10, + elan_change_state_async, + NULL); + + name = g_strdup_printf ("dev_change_state to %d", state); + g_source_set_name (timeout, name); + g_free (name); + + break; + } + + case FP_IMAGE_DEVICE_STATE_CAPTURE: + /* TODO MAYBE: split capture ssm into smaller ssms and use this state */ + self->dev_state = state; + self->dev_state_next = state; + break; + + default: + g_assert_not_reached (); + } +} + +static void +dev_deactivate (FpImageDevice *dev) +{ + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + + G_DEBUG_HERE (); + + if (self->dev_state == FP_IMAGE_DEVICE_STATE_INACTIVE) + { + /* The device is inactive already, complete the operation immediately. */ + fpi_image_device_deactivate_complete (dev, NULL); + } + else + { + /* The device is not yet inactive, flag that we are deactivating (and + * need to signal back deactivation) and then ensure we will change + * to the inactive state eventually. */ + self->deactivating = TRUE; + dev_change_state (dev, FP_IMAGE_DEVICE_STATE_INACTIVE); + } +} + +static void +fpi_device_elan_init (FpiDeviceElan *self) +{ +} +static void +fpi_device_elan_class_init (FpiDeviceElanClass *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); + + dev_class->id = "elan"; + dev_class->full_name = "ElanTech Fingerprint Sensor"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = elan_id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; + img_class->change_state = dev_change_state; + + img_class->bz3_threshold = 24; } diff --git a/libfprint/drivers/elan.h b/libfprint/drivers/elan.h index 059f00ac..169498a6 100644 --- a/libfprint/drivers/elan.h +++ b/libfprint/drivers/elan.h @@ -71,155 +71,158 @@ #define ELAN_CMD_TIMEOUT 10000 #define ELAN_FINGER_TIMEOUT 200 -struct elan_cmd { - unsigned char cmd[ELAN_CMD_LEN]; - int response_len; - int response_in; - unsigned short devices; - gboolean never_cancel; +struct elan_cmd +{ + unsigned char cmd[ELAN_CMD_LEN]; + int response_len; + int response_in; + unsigned short devices; + gboolean never_cancel; }; static const struct elan_cmd get_sensor_dim_cmd = { - .cmd = {0x00, 0x0c}, - .response_len = 0x4, - .response_in = ELAN_EP_CMD_IN, - .devices = ELAN_ALL_DEV, + .cmd = {0x00, 0x0c}, + .response_len = 0x4, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_ALL_DEV, }; static const struct elan_cmd get_fw_ver_cmd = { - .cmd = {0x40, 0x19}, - .response_len = 0x2, - .response_in = ELAN_EP_CMD_IN, - .devices = ELAN_ALL_DEV, + .cmd = {0x40, 0x19}, + .response_len = 0x2, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_ALL_DEV, }; /* unknown, returns 0x0 0x1 on 0907 */ static const struct elan_cmd activate_cmd_1 = { - .cmd = {0x40, 0x2a}, - .response_len = 0x2, - .response_in = ELAN_EP_CMD_IN, - .devices = ELAN_0907, + .cmd = {0x40, 0x2a}, + .response_len = 0x2, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_0907, }; static const struct elan_cmd get_image_cmd = { - .cmd = {0x00, 0x09}, - /* raw frame sizes are calculated from image dimensions reported by the - * device */ - .response_len = -1, - .response_in = ELAN_EP_IMG_IN, - .devices = ELAN_ALL_DEV, + .cmd = {0x00, 0x09}, + /* raw frame sizes are calculated from image dimensions reported by the + * device */ + .response_len = -1, + .response_in = ELAN_EP_IMG_IN, + .devices = ELAN_ALL_DEV, }; static const struct elan_cmd read_sensor_status_cmd = { - .cmd = {0x40, 0x13}, - .response_len = 0x1, - .response_in = ELAN_EP_CMD_IN, - .devices = ELAN_ALL_DEV, + .cmd = {0x40, 0x13}, + .response_len = 0x1, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_ALL_DEV, }; static const struct elan_cmd get_calib_status_cmd = { - .cmd = {0x40, 0x23}, - .response_len = 0x1, - .response_in = ELAN_EP_CMD_IN, - .devices = ELAN_ALL_DEV, + .cmd = {0x40, 0x23}, + .response_len = 0x1, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_ALL_DEV, }; static const struct elan_cmd get_calib_mean_cmd = { - .cmd = {0x40, 0x24}, - .response_len = 0x2, - .response_in = ELAN_EP_CMD_IN, - .devices = ELAN_ALL_DEV, + .cmd = {0x40, 0x24}, + .response_len = 0x2, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_ALL_DEV, }; static const struct elan_cmd led_on_cmd = { - .cmd = {0x40, 0x31}, - .response_len = ELAN_CMD_SKIP_READ, - .response_in = ELAN_EP_CMD_IN, - .devices = ELAN_ALL_DEV, + .cmd = {0x40, 0x31}, + .response_len = ELAN_CMD_SKIP_READ, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_ALL_DEV, }; /* wait for finger * subsequent read will not complete until finger is placed on the reader */ static const struct elan_cmd pre_scan_cmd = { - .cmd = {0x40, 0x3f}, - .response_len = 0x1, - .response_in = ELAN_EP_CMD_IN, - .devices = ELAN_ALL_DEV, + .cmd = {0x40, 0x3f}, + .response_len = 0x1, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_ALL_DEV, }; /* led off, stop waiting for finger */ static const struct elan_cmd stop_cmd = { - .cmd = {0x00, 0x0b}, - .response_len = ELAN_CMD_SKIP_READ, - .response_in = ELAN_EP_CMD_IN, - .devices = ELAN_ALL_DEV, - .never_cancel = TRUE, + .cmd = {0x00, 0x0b}, + .response_len = ELAN_CMD_SKIP_READ, + .response_in = ELAN_EP_CMD_IN, + .devices = ELAN_ALL_DEV, + .never_cancel = TRUE, }; -static const FpIdEntry elan_id_table [ ] = { - {.vid = ELAN_VEND_ID, .pid = 0x0903, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0907, .driver_data = ELAN_0907}, - {.vid = ELAN_VEND_ID, .pid = 0x0c01, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c02, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c03, .driver_data = ELAN_0C03}, - {.vid = ELAN_VEND_ID, .pid = 0x0c04, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c05, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c06, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c07, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c08, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c09, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c0a, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c0b, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c0c, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c0d, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c0e, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c0f, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c10, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c11, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c12, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c13, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c14, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c15, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c16, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c17, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c18, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c19, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c1a, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c1b, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c1c, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c1d, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c1e, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c1f, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c20, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c21, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c22, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c23, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c24, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c25, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c26, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c27, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c28, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c29, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c2a, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c2b, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c2c, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c2d, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c2e, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c2f, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c30, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c31, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c32, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c33, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42}, - {.vid = 0, .pid = 0, .driver_data = 0}, +static const FpIdEntry elan_id_table[] = { + {.vid = ELAN_VEND_ID, .pid = 0x0903, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0907, .driver_data = ELAN_0907}, + {.vid = ELAN_VEND_ID, .pid = 0x0c01, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c02, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c03, .driver_data = ELAN_0C03}, + {.vid = ELAN_VEND_ID, .pid = 0x0c04, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c05, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c06, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c07, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c08, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c09, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0a, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0b, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0c, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0d, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0e, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c0f, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c10, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c11, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c12, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c13, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c14, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c15, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c16, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c17, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c18, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c19, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1a, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1b, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1c, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1d, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1e, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c1f, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c20, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c21, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c22, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c23, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c24, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c25, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c26, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c27, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c28, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c29, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2a, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2b, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2c, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2d, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2e, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c2f, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c30, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c31, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c32, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c33, .driver_data = ELAN_ALL_DEV}, + {.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42}, + {.vid = 0, .pid = 0, .driver_data = 0}, }; -static void elan_cmd_done(FpiSsm *ssm); -static void elan_cmd_read(FpiSsm *ssm, FpDevice *dev); +static void elan_cmd_done (FpiSsm *ssm); +static void elan_cmd_read (FpiSsm *ssm, + FpDevice *dev); -static void elan_calibrate(FpDevice *dev); -static void elan_capture(FpDevice *dev); +static void elan_calibrate (FpDevice *dev); +static void elan_capture (FpDevice *dev); -static void dev_change_state(FpImageDevice *dev, FpImageDeviceState state); +static void dev_change_state (FpImageDevice *dev, + FpImageDeviceState state); #endif diff --git a/libfprint/drivers/etes603.c b/libfprint/drivers/etes603.c index b7592a87..95b077f4 100644 --- a/libfprint/drivers/etes603.c +++ b/libfprint/drivers/etes603.c @@ -39,418 +39,448 @@ #include "driver_ids.h" /* libusb defines */ -#define EP_IN 0x81 -#define EP_OUT 0x02 +#define EP_IN 0x81 +#define EP_OUT 0x02 /* Note that 1000 ms is usually enough but with CMD_READ_FE could be longer * since the sensor is waiting motion. */ -#define BULK_TIMEOUT 1000 +#define BULK_TIMEOUT 1000 /* es603 defines */ -#define FRAME_WIDTH 192 /* pixels per row */ -#define FRAME_HEIGHT 4 /* number of rows */ -#define FRAME_SIZE 384 /* size in bytes (4 bits per pixels) */ -#define FE_WIDTH 256 /* pixels per row for Fly-Estimation */ -#define FE_HEIGHT 500 /* number of rows for Fly-Estimation */ -#define FE_SIZE 64000 /* size in bytes (4 bits per pixels) */ +#define FRAME_WIDTH 192 /* pixels per row */ +#define FRAME_HEIGHT 4 /* number of rows */ +#define FRAME_SIZE 384 /* size in bytes (4 bits per pixels) */ +#define FE_WIDTH 256 /* pixels per row for Fly-Estimation */ +#define FE_HEIGHT 500 /* number of rows for Fly-Estimation */ +#define FE_SIZE 64000 /* size in bytes (4 bits per pixels) */ -#define GAIN_SMALL_INIT 0x23 /* Initial small gain */ -#define VRT_MAX 0x3F /* Maximum value for VRT */ -#define VRB_MAX 0x3A /* Maximum value for VRB */ -#define DTVRT_MAX 0x3A /* Maximum value for DTVRT */ -#define DCOFFSET_MIN 0x00 /* Minimum value for DCoffset */ -#define DCOFFSET_MAX 0x35 /* Maximum value for DCoffset */ +#define GAIN_SMALL_INIT 0x23 /* Initial small gain */ +#define VRT_MAX 0x3F /* Maximum value for VRT */ +#define VRB_MAX 0x3A /* Maximum value for VRB */ +#define DTVRT_MAX 0x3A /* Maximum value for DTVRT */ +#define DCOFFSET_MIN 0x00 /* Minimum value for DCoffset */ +#define DCOFFSET_MAX 0x35 /* Maximum value for DCoffset */ /* es603 commands */ -#define CMD_READ_REG 0x01 -#define CMD_WRITE_REG 0x02 -#define CMD_READ_FRAME 0x03 /* Read the sensor area */ -#define CMD_READ_FE 0x06 /* Read a fingerprint using Fly-Estimation */ -#define CMD_20 0x20 /* ? */ -#define CMD_25 0x25 /* ? */ -#define CMD_60 0x60 /* ? */ +#define CMD_READ_REG 0x01 +#define CMD_WRITE_REG 0x02 +#define CMD_READ_FRAME 0x03 /* Read the sensor area */ +#define CMD_READ_FE 0x06 /* Read a fingerprint using Fly-Estimation */ +#define CMD_20 0x20 /* ? */ +#define CMD_25 0x25 /* ? */ +#define CMD_60 0x60 /* ? */ -#define CMD_OK 0x01 /* Command successfully executed */ +#define CMD_OK 0x01 /* Command successfully executed */ /* es603 registers */ -#define REG_MAX 0x18 /* Maximum number of registers in one message */ -#define REG_MODE_CONTROL 0x02 /* Mode control */ -#define REG_03 0x03 /* Contact register? */ -#define REG_04 0x04 /* ? */ -#define REG_10 0x10 /* MVS FRMBUF control */ -#define REG_1A 0x1A /* ? */ +#define REG_MAX 0x18 /* Maximum number of registers in one message */ +#define REG_MODE_CONTROL 0x02 /* Mode control */ +#define REG_03 0x03 /* Contact register? */ +#define REG_04 0x04 /* ? */ +#define REG_10 0x10 /* MVS FRMBUF control */ +#define REG_1A 0x1A /* ? */ /* BEGIN init sensor */ -#define REG_20 0x20 /* (def: 0x00) */ -#define REG_21 0x21 /* Small gain (def: 0x23) */ -#define REG_22 0x22 /* Normal gain (def: 0x21) */ -#define REG_23 0x23 /* Large gain (def: 0x20) */ -#define REG_24 0x24 /* (def: 0x14) */ -#define REG_25 0x25 /* (def: 0x6A) */ -#define REG_26 0x26 /* VRB again? (def: 0x00) */ -#define REG_27 0x27 /* VRT again? (def: 0x00) */ -#define REG_28 0x28 /* (def: 0x00) */ -#define REG_29 0x29 /* (def: 0xC0) */ -#define REG_2A 0x2A /* (def: 0x50) */ -#define REG_2B 0x2B /* (def: 0x50) */ -#define REG_2C 0x2C /* (def: 0x4D) */ -#define REG_2D 0x2D /* (def: 0x03) */ -#define REG_2E 0x2E /* (def: 0x06) */ -#define REG_2F 0x2F /* (def: 0x06) */ -#define REG_30 0x30 /* (def: 0x10) */ -#define REG_31 0x31 /* (def: 0x02) */ -#define REG_32 0x32 /* (def: 0x14) */ -#define REG_33 0x33 /* (def: 0x34) */ -#define REG_34 0x34 /* (def: 0x01) */ -#define REG_35 0x35 /* (def: 0x08) */ -#define REG_36 0x36 /* (def: 0x03) */ -#define REG_37 0x37 /* (def: 0x21) */ +#define REG_20 0x20 /* (def: 0x00) */ +#define REG_21 0x21 /* Small gain (def: 0x23) */ +#define REG_22 0x22 /* Normal gain (def: 0x21) */ +#define REG_23 0x23 /* Large gain (def: 0x20) */ +#define REG_24 0x24 /* (def: 0x14) */ +#define REG_25 0x25 /* (def: 0x6A) */ +#define REG_26 0x26 /* VRB again? (def: 0x00) */ +#define REG_27 0x27 /* VRT again? (def: 0x00) */ +#define REG_28 0x28 /* (def: 0x00) */ +#define REG_29 0x29 /* (def: 0xC0) */ +#define REG_2A 0x2A /* (def: 0x50) */ +#define REG_2B 0x2B /* (def: 0x50) */ +#define REG_2C 0x2C /* (def: 0x4D) */ +#define REG_2D 0x2D /* (def: 0x03) */ +#define REG_2E 0x2E /* (def: 0x06) */ +#define REG_2F 0x2F /* (def: 0x06) */ +#define REG_30 0x30 /* (def: 0x10) */ +#define REG_31 0x31 /* (def: 0x02) */ +#define REG_32 0x32 /* (def: 0x14) */ +#define REG_33 0x33 /* (def: 0x34) */ +#define REG_34 0x34 /* (def: 0x01) */ +#define REG_35 0x35 /* (def: 0x08) */ +#define REG_36 0x36 /* (def: 0x03) */ +#define REG_37 0x37 /* (def: 0x21) */ /* END init sensor */ -#define REG_ENC1 0x41 /* Encryption 1 */ -#define REG_ENC2 0x42 -#define REG_ENC3 0x43 -#define REG_ENC4 0x44 -#define REG_ENC5 0x45 -#define REG_ENC6 0x46 -#define REG_ENC7 0x47 -#define REG_ENC8 0x48 /* Encryption 8 */ +#define REG_ENC1 0x41 /* Encryption 1 */ +#define REG_ENC2 0x42 +#define REG_ENC3 0x43 +#define REG_ENC4 0x44 +#define REG_ENC5 0x45 +#define REG_ENC6 0x46 +#define REG_ENC7 0x47 +#define REG_ENC8 0x48 /* Encryption 8 */ -#define REG_50 0x50 /* ? For contact detection */ -#define REG_51 0x51 /* ? */ -#define REG_59 0x59 /* ? */ -#define REG_5A 0x5A /* ? */ -#define REG_5B 0x5B /* ? */ +#define REG_50 0x50 /* ? For contact detection */ +#define REG_51 0x51 /* ? */ +#define REG_59 0x59 /* ? */ +#define REG_5A 0x5A /* ? */ +#define REG_5B 0x5B /* ? */ -#define REG_INFO0 0x70 /* Sensor model byte0 */ -#define REG_INFO1 0x71 /* Sensor model byte1 */ -#define REG_INFO2 0x72 /* Sensor model byte2 */ -#define REG_INFO3 0x73 /* Sensor model byte3 */ +#define REG_INFO0 0x70 /* Sensor model byte0 */ +#define REG_INFO1 0x71 /* Sensor model byte1 */ +#define REG_INFO2 0x72 /* Sensor model byte2 */ +#define REG_INFO3 0x73 /* Sensor model byte3 */ -#define REG_GAIN 0xE0 -#define REG_VRT 0xE1 -#define REG_VRB 0xE2 -#define REG_DTVRT 0xE3 /* used for contact detection */ -#define REG_VCO_CONTROL 0xE5 /* 0x13 (IDLE?), 0x14 (REALTIME) */ -#define REG_DCOFFSET 0xE6 +#define REG_GAIN 0xE0 +#define REG_VRT 0xE1 +#define REG_VRB 0xE2 +#define REG_DTVRT 0xE3 /* used for contact detection */ +#define REG_VCO_CONTROL 0xE5 /* 0x13 (IDLE?), 0x14 (REALTIME) */ +#define REG_DCOFFSET 0xE6 -#define REG_F0 0xF0 /* ? init:0x00 close:0x01 */ -#define REG_F2 0xF2 /* ? init:0x00 close:0x4E */ +#define REG_F0 0xF0 /* ? init:0x00 close:0x01 */ +#define REG_F2 0xF2 /* ? init:0x00 close:0x4E */ -#define REG_MODE_SLEEP 0x30 /* Sleep mode */ -#define REG_MODE_CONTACT 0x31 /* Contact mode */ -#define REG_MODE_SENSOR 0x33 /* Sensor mode */ -#define REG_MODE_FP 0x34 /* FingerPrint mode (Fly-Estimation®) */ +#define REG_MODE_SLEEP 0x30 /* Sleep mode */ +#define REG_MODE_CONTACT 0x31 /* Contact mode */ +#define REG_MODE_SENSOR 0x33 /* Sensor mode */ +#define REG_MODE_FP 0x34 /* FingerPrint mode (Fly-Estimation®) */ -#define REG_VCO_IDLE 0x13 -#define REG_VCO_RT 0x14 /* Realtime */ +#define REG_VCO_IDLE 0x13 +#define REG_VCO_RT 0x14 /* Realtime */ /* The size of the message header is 5 plus 1 for the command. */ -#define MSG_HDR_SIZE 6 +#define MSG_HDR_SIZE 6 /* This structure must be packed because it is a the raw message sent. */ -struct egis_msg { - guint8 magic[5]; /* out: 'EGIS' 0x09 / in: 'SIGE' 0x0A */ - guint8 cmd; - union { - struct { - guint8 nb; - guint8 regs[REG_MAX]; - } egis_readreg; - struct { - guint8 regs[REG_MAX]; - } sige_readreg; - struct { - guint8 nb; - struct { - guint8 reg; - guint8 val; - } regs[REG_MAX]; - } egis_writereg; - struct { - guint8 length_factor; - guint8 length; - guint8 use_gvv; - guint8 gain; - guint8 vrt; - guint8 vrb; - } egis_readf; - struct { - guint8 len[2]; - guint8 val[3]; - } egis_readfp; - struct { - guint8 val[5]; - } sige_misc; - guint8 padding[0x40-6]; /* Ensure size of 0x40 */ - }; +struct egis_msg +{ + guint8 magic[5]; /* out: 'EGIS' 0x09 / in: 'SIGE' 0x0A */ + guint8 cmd; + union + { + struct + { + guint8 nb; + guint8 regs[REG_MAX]; + } egis_readreg; + struct + { + guint8 regs[REG_MAX]; + } sige_readreg; + struct + { + guint8 nb; + struct + { + guint8 reg; + guint8 val; + } regs[REG_MAX]; + } egis_writereg; + struct + { + guint8 length_factor; + guint8 length; + guint8 use_gvv; + guint8 gain; + guint8 vrt; + guint8 vrb; + } egis_readf; + struct + { + guint8 len[2]; + guint8 val[3]; + } egis_readfp; + struct + { + guint8 val[5]; + } sige_misc; + guint8 padding[0x40 - 6]; /* Ensure size of 0x40 */ + }; } __attribute__((packed)); /* Structure to keep information between asynchronous functions. */ -struct _FpiDeviceEtes603 { - FpImageDevice parent; +struct _FpiDeviceEtes603 +{ + FpImageDevice parent; - guint8 regs[256]; - struct egis_msg *req; - size_t req_len; - struct egis_msg *ans; - size_t ans_len; + guint8 regs[256]; + struct egis_msg *req; + size_t req_len; + struct egis_msg *ans; + size_t ans_len; - guint8 *fp; - guint16 fp_height; + guint8 *fp; + guint16 fp_height; - guint8 tunedc_min; - guint8 tunedc_max; + guint8 tunedc_min; + guint8 tunedc_max; - /* Device parameters */ - guint8 gain; - guint8 dcoffset; - guint8 vrt; - guint8 vrb; + /* Device parameters */ + guint8 gain; + guint8 dcoffset; + guint8 vrt; + guint8 vrb; - unsigned int is_active; + unsigned int is_active; }; -G_DECLARE_FINAL_TYPE(FpiDeviceEtes603, fpi_device_etes603, FPI, DEVICE_ETES603, - FpImageDevice); -G_DEFINE_TYPE(FpiDeviceEtes603, fpi_device_etes603, FP_TYPE_IMAGE_DEVICE); +G_DECLARE_FINAL_TYPE (FpiDeviceEtes603, fpi_device_etes603, FPI, DEVICE_ETES603, + FpImageDevice); +G_DEFINE_TYPE (FpiDeviceEtes603, fpi_device_etes603, FP_TYPE_IMAGE_DEVICE); -static void m_start_fingerdetect(FpImageDevice *idev); +static void m_start_fingerdetect (FpImageDevice *idev); /* * Prepare the header of the message to be sent to the device. */ -static void msg_header_prepare(struct egis_msg *msg) +static void +msg_header_prepare (struct egis_msg *msg) { - msg->magic[0] = 'E'; - msg->magic[1] = 'G'; - msg->magic[2] = 'I'; - msg->magic[3] = 'S'; - msg->magic[4] = 0x09; + msg->magic[0] = 'E'; + msg->magic[1] = 'G'; + msg->magic[2] = 'I'; + msg->magic[3] = 'S'; + msg->magic[4] = 0x09; } /* * Check that the header of the received message is correct. */ -static int msg_header_check(struct egis_msg *msg) +static int +msg_header_check (struct egis_msg *msg) { - if (msg->magic[0] == 'S' && msg->magic[1] == 'I' - && msg->magic[2] == 'G' && msg->magic[3] == 'E' - && msg->magic[4] == 0x0A) - return 0; - return -1; + if (msg->magic[0] == 'S' && msg->magic[1] == 'I' && + msg->magic[2] == 'G' && msg->magic[3] == 'E' && + msg->magic[4] == 0x0A) + return 0; + return -1; } /* * Prepare message to ask for a frame. */ -static void msg_get_frame(FpiDeviceEtes603 *self, - guint8 use_gvv, guint8 gain, guint8 vrt, - guint8 vrb) +static void +msg_get_frame (FpiDeviceEtes603 *self, + guint8 use_gvv, guint8 gain, guint8 vrt, + guint8 vrb) { - struct egis_msg *msg = self->req; - msg_header_prepare(msg); - msg->cmd = CMD_READ_FRAME; - msg->egis_readf.length_factor = 0x01; - /* length should be 0xC0 */ - msg->egis_readf.length = FRAME_WIDTH; - msg->egis_readf.use_gvv = use_gvv; - /* if use_gvv is set, gain/vrt/vrb are used */ - msg->egis_readf.gain = gain; - msg->egis_readf.vrt = vrt; - msg->egis_readf.vrb = vrb; + struct egis_msg *msg = self->req; - self->req_len = MSG_HDR_SIZE + 6; - self->ans_len = FRAME_SIZE; + msg_header_prepare (msg); + msg->cmd = CMD_READ_FRAME; + msg->egis_readf.length_factor = 0x01; + /* length should be 0xC0 */ + msg->egis_readf.length = FRAME_WIDTH; + msg->egis_readf.use_gvv = use_gvv; + /* if use_gvv is set, gain/vrt/vrb are used */ + msg->egis_readf.gain = gain; + msg->egis_readf.vrt = vrt; + msg->egis_readf.vrb = vrb; + + self->req_len = MSG_HDR_SIZE + 6; + self->ans_len = FRAME_SIZE; } /* * Prepare message to ask for a fingerprint frame. */ -static void msg_get_fp(FpiDeviceEtes603 *self, guint8 len0, guint8 len1, - guint8 v2, guint8 v3, guint8 v4) +static void +msg_get_fp (FpiDeviceEtes603 *self, guint8 len0, guint8 len1, + guint8 v2, guint8 v3, guint8 v4) { - struct egis_msg *msg = self->req; - msg_header_prepare(msg); - msg->cmd = CMD_READ_FE; - /* Unknown values and always same on captured frames. - * 1st 2nd bytes is unsigned short for height, but only on value range - * 0x01 0xF4 (500), 0x02 0x00 (512), 0x02 0xF4 (756) are ok - */ - msg->egis_readfp.len[0] = len0; - msg->egis_readfp.len[1] = len1; - /* 3rd byte : ?? but changes frame size - * 4th byte : 0x00 -> can change width - * 5th byte : motion sensibility? - */ - msg->egis_readfp.val[0] = v2; - msg->egis_readfp.val[1] = v3; - msg->egis_readfp.val[2] = v4; + struct egis_msg *msg = self->req; - self->req_len = MSG_HDR_SIZE + 5; - self->ans_len = FE_SIZE; + msg_header_prepare (msg); + msg->cmd = CMD_READ_FE; + /* Unknown values and always same on captured frames. + * 1st 2nd bytes is unsigned short for height, but only on value range + * 0x01 0xF4 (500), 0x02 0x00 (512), 0x02 0xF4 (756) are ok + */ + msg->egis_readfp.len[0] = len0; + msg->egis_readfp.len[1] = len1; + /* 3rd byte : ?? but changes frame size + * 4th byte : 0x00 -> can change width + * 5th byte : motion sensibility? + */ + msg->egis_readfp.val[0] = v2; + msg->egis_readfp.val[1] = v3; + msg->egis_readfp.val[2] = v4; + + self->req_len = MSG_HDR_SIZE + 5; + self->ans_len = FE_SIZE; } /* * Prepare message to read registers from the sensor. * Variadic argument pattern: int reg, ... */ -static void msg_get_regs(FpiDeviceEtes603 *self, int n_args, ... ) +static void +msg_get_regs (FpiDeviceEtes603 *self, int n_args, ... ) { - struct egis_msg *msg = self->req; - va_list ap; - int i; + struct egis_msg *msg = self->req; + va_list ap; + int i; - g_assert(n_args > 0 && n_args <= REG_MAX); + g_assert (n_args > 0 && n_args <= REG_MAX); - msg_header_prepare(msg); - msg->cmd = CMD_READ_REG; - msg->egis_readreg.nb = n_args; - va_start(ap, n_args); - for (i = 0; i < n_args; i++) { - msg->egis_readreg.regs[i] = va_arg(ap, int); - } - va_end(ap); + msg_header_prepare (msg); + msg->cmd = CMD_READ_REG; + msg->egis_readreg.nb = n_args; + va_start (ap, n_args); + for (i = 0; i < n_args; i++) + msg->egis_readreg.regs[i] = va_arg (ap, int); + va_end (ap); - self->req_len = MSG_HDR_SIZE + 1 + n_args; - self->ans_len = MSG_HDR_SIZE + 1 + n_args; + self->req_len = MSG_HDR_SIZE + 1 + n_args; + self->ans_len = MSG_HDR_SIZE + 1 + n_args; } /* * Parse the result of read register command. */ -static int msg_parse_regs(FpiDeviceEtes603 *dev) +static int +msg_parse_regs (FpiDeviceEtes603 *dev) { - size_t i, n_args; - struct egis_msg *msg_req = dev->req; - struct egis_msg *msg_ans = dev->ans; - n_args = dev->ans_len - MSG_HDR_SIZE; + size_t i, n_args; + struct egis_msg *msg_req = dev->req; + struct egis_msg *msg_ans = dev->ans; - if (msg_header_check(msg_ans)) { - return -1; - } - if (msg_ans->cmd != CMD_OK) { - return -2; - } + n_args = dev->ans_len - MSG_HDR_SIZE; - for (i = 0; i < n_args; i++) { - int reg = msg_req->egis_readreg.regs[i]; - dev->regs[reg] = msg_ans->sige_readreg.regs[i]; - } - return 0; + if (msg_header_check (msg_ans)) + return -1; + if (msg_ans->cmd != CMD_OK) + return -2; + + for (i = 0; i < n_args; i++) + { + int reg = msg_req->egis_readreg.regs[i]; + dev->regs[reg] = msg_ans->sige_readreg.regs[i]; + } + return 0; } /* * Prepare message to write sensor's registers. * Variadic arguments are: int reg, int val, ... */ -static void msg_set_regs(FpiDeviceEtes603 *self, int n_args, ...) +static void +msg_set_regs (FpiDeviceEtes603 *self, int n_args, ...) { - struct egis_msg *msg = self->req; - va_list ap; - int i; + struct egis_msg *msg = self->req; + va_list ap; + int i; - g_assert(n_args != 0 && n_args % 2 == 0 && n_args <= REG_MAX * 2); + g_assert (n_args != 0 && n_args % 2 == 0 && n_args <= REG_MAX * 2); - msg_header_prepare(msg); - msg->cmd = CMD_WRITE_REG; - msg->egis_writereg.nb = n_args / 2; + msg_header_prepare (msg); + msg->cmd = CMD_WRITE_REG; + msg->egis_writereg.nb = n_args / 2; - va_start(ap, n_args); - for (i = 0; i < n_args / 2; i++) { - msg->egis_writereg.regs[i].reg = va_arg(ap, int); - msg->egis_writereg.regs[i].val = va_arg(ap, int); - } - va_end(ap); + va_start (ap, n_args); + for (i = 0; i < n_args / 2; i++) + { + msg->egis_writereg.regs[i].reg = va_arg (ap, int); + msg->egis_writereg.regs[i].val = va_arg (ap, int); + } + va_end (ap); - self->req_len = MSG_HDR_SIZE + 1 + n_args; - self->ans_len = MSG_HDR_SIZE + 1; + self->req_len = MSG_HDR_SIZE + 1 + n_args; + self->ans_len = MSG_HDR_SIZE + 1; } -static int msg_check_ok(FpiDeviceEtes603 *dev) +static int +msg_check_ok (FpiDeviceEtes603 *dev) { - struct egis_msg *msg = dev->ans; - if (msg_header_check(msg)) { - goto err; - } - if (msg->cmd != CMD_OK) { - goto err; - } - return 0; + struct egis_msg *msg = dev->ans; + + if (msg_header_check (msg)) + goto err; + if (msg->cmd != CMD_OK) + goto err; + return 0; err: - return -1; + return -1; } /* * Check the model of the sensor. */ -static int check_info(FpiDeviceEtes603 *dev) +static int +check_info (FpiDeviceEtes603 *dev) { - if (dev->regs[0x70] == 0x4A && dev->regs[0x71] == 0x44 - && dev->regs[0x72] == 0x49 && dev->regs[0x73] == 0x31) - return 0; - fp_err("unknown device parameters (REG_70:%02X REG_71:%02X " - "REG_FIRMWARE:%02X REG_VERSION:%02X)", - dev->regs[0x70], dev->regs[0x71], dev->regs[0x72], - dev->regs[0x73]); - return -1; + if (dev->regs[0x70] == 0x4A && dev->regs[0x71] == 0x44 && + dev->regs[0x72] == 0x49 && dev->regs[0x73] == 0x31) + return 0; + fp_err ("unknown device parameters (REG_70:%02X REG_71:%02X " + "REG_FIRMWARE:%02X REG_VERSION:%02X)", + dev->regs[0x70], dev->regs[0x71], dev->regs[0x72], + dev->regs[0x73]); + return -1; } -static void msg_get_cmd20(FpiDeviceEtes603 *dev) +static void +msg_get_cmd20 (FpiDeviceEtes603 *dev) { - struct egis_msg *msg = dev->req; - msg_header_prepare(msg); - msg->cmd = CMD_20; - dev->req_len = MSG_HDR_SIZE; + struct egis_msg *msg = dev->req; + + msg_header_prepare (msg); + msg->cmd = CMD_20; + dev->req_len = MSG_HDR_SIZE; } -static int msg_check_cmd20(FpiDeviceEtes603 *dev) +static int +msg_check_cmd20 (FpiDeviceEtes603 *dev) { - struct egis_msg *msg = dev->ans; - if (msg_header_check(msg)) { - fp_err("msg_header_check failed"); - return -1; - } - /* status or flashtype/flashinfo or ? */ - if (msg->cmd != 0x05 - || msg->sige_misc.val[0] != 0x00 - || msg->sige_misc.val[1] != 0x00) { - fp_warn("unexpected answer CMD_20 from device(%02X %02X %02X)", - msg->cmd, msg->sige_misc.val[0], msg->sige_misc.val[1]); - } + struct egis_msg *msg = dev->ans; - return 0; + if (msg_header_check (msg)) + { + fp_err ("msg_header_check failed"); + return -1; + } + /* status or flashtype/flashinfo or ? */ + if (msg->cmd != 0x05 || + msg->sige_misc.val[0] != 0x00 || + msg->sige_misc.val[1] != 0x00) + fp_warn ("unexpected answer CMD_20 from device(%02X %02X %02X)", + msg->cmd, msg->sige_misc.val[0], msg->sige_misc.val[1]); + + return 0; } -static void msg_get_cmd25(FpiDeviceEtes603 *dev) +static void +msg_get_cmd25 (FpiDeviceEtes603 *dev) { - struct egis_msg *msg = dev->req; - msg_header_prepare(msg); - msg->cmd = CMD_25; - dev->req_len = MSG_HDR_SIZE; + struct egis_msg *msg = dev->req; + + msg_header_prepare (msg); + msg->cmd = CMD_25; + dev->req_len = MSG_HDR_SIZE; } -static int msg_check_cmd25(FpiDeviceEtes603 *dev) +static int +msg_check_cmd25 (FpiDeviceEtes603 *dev) { - struct egis_msg *msg = dev->ans; - if (msg_header_check(msg)) { - fp_err("msg_header_check failed"); - goto err; - } - if (msg->cmd != CMD_OK) { - fp_err("CMD_OK failed"); - goto err; - } - /* flashtype or status or ? */ - if (msg->sige_misc.val[0] != 0x00) { - fp_warn("unexpected answer for CMD_25 (%02X)", - msg->sige_misc.val[0]); - } - return 0; + struct egis_msg *msg = dev->ans; + + if (msg_header_check (msg)) + { + fp_err ("msg_header_check failed"); + goto err; + } + if (msg->cmd != CMD_OK) + { + fp_err ("CMD_OK failed"); + goto err; + } + /* flashtype or status or ? */ + if (msg->sige_misc.val[0] != 0x00) + fp_warn ("unexpected answer for CMD_25 (%02X)", + msg->sige_misc.val[0]); + return 0; err: - return -1; + return -1; } -static void msg_set_mode_control(FpiDeviceEtes603 *self, guint8 mode) +static void +msg_set_mode_control (FpiDeviceEtes603 *self, guint8 mode) { - msg_set_regs(self, 2, REG_MODE_CONTROL, mode); + msg_set_regs (self, 2, REG_MODE_CONTROL, mode); } @@ -459,1013 +489,1177 @@ static void msg_set_mode_control(FpiDeviceEtes603 *self, guint8 mode) /* * Return the brightness of a 4bpp frame */ -static unsigned int process_get_brightness(guint8 *f, size_t s) +static unsigned int +process_get_brightness (guint8 *f, size_t s) { - unsigned int i, sum = 0; - for (i = 0; i < s; i++) { - sum += f[i] >> 4; - sum += f[i] & 0x0F; - } - return sum; + unsigned int i, sum = 0; + + for (i = 0; i < s; i++) + { + sum += f[i] >> 4; + sum += f[i] & 0x0F; + } + return sum; } /* * Return the histogram of a 4bpp frame */ -static void process_hist(guint8 *f, size_t s, float stat[5]) +static void +process_hist (guint8 *f, size_t s, float stat[5]) { - float hist[16]; - float black_mean, white_mean; - int i; - /* Clean histogram */ - for (i = 0; i < 16; i++) - hist[i] = 0.0; - for (i = 0; i < s; i++) { - hist[f[i] >> 4]++; - hist[f[i] & 0x0F]++; - } - /* histogram average */ - for (i = 0; i < 16; i++) { - hist[i] = hist[i] / (s * 2); - } - /* Average black/white pixels (full black and full white pixels - * are excluded). */ - black_mean = white_mean = 0.0; - for (i = 1; i < 8; i++) - black_mean += hist[i]; - for (i = 8; i < 15; i++) - white_mean += hist[i]; - stat[0] = hist[0]; - stat[1] = black_mean; - stat[2] = black_mean+white_mean; - stat[3] = white_mean; - stat[4] = hist[15]; - fp_dbg("fullb=%6f black=%6f grey=%6f white=%6f fullw=%6f", - hist[0], black_mean, black_mean+white_mean, white_mean, - hist[15]); + float hist[16]; + float black_mean, white_mean; + int i; + + /* Clean histogram */ + for (i = 0; i < 16; i++) + hist[i] = 0.0; + for (i = 0; i < s; i++) + { + hist[f[i] >> 4]++; + hist[f[i] & 0x0F]++; + } + /* histogram average */ + for (i = 0; i < 16; i++) + hist[i] = hist[i] / (s * 2); + /* Average black/white pixels (full black and full white pixels + * are excluded). */ + black_mean = white_mean = 0.0; + for (i = 1; i < 8; i++) + black_mean += hist[i]; + for (i = 8; i < 15; i++) + white_mean += hist[i]; + stat[0] = hist[0]; + stat[1] = black_mean; + stat[2] = black_mean + white_mean; + stat[3] = white_mean; + stat[4] = hist[15]; + fp_dbg ("fullb=%6f black=%6f grey=%6f white=%6f fullw=%6f", + hist[0], black_mean, black_mean + white_mean, white_mean, + hist[15]); } /* * Return true if the frame is almost empty. */ -static int process_frame_empty(guint8 *frame, size_t size) +static int +process_frame_empty (guint8 *frame, size_t size) { - unsigned int sum = process_get_brightness(frame, size); - /* Allow an average of 'threshold' luminosity per pixel */ - if (sum < size) - return 1; - return 0; + unsigned int sum = process_get_brightness (frame, size); + + /* Allow an average of 'threshold' luminosity per pixel */ + if (sum < size) + return 1; + return 0; } /* Transform 4 bits image to 8 bits image */ -static void process_4to8_bpp(guint8 *input, unsigned int input_size, - guint8 *output) +static void +process_4to8_bpp (guint8 *input, unsigned int input_size, + guint8 *output) { - unsigned int i, j = 0; - for (i = 0; i < input_size; i++, j += 2) { - /* 16 gray levels transform to 256 levels using << 4 */ - output[j] = input[i] & 0xF0; - output[j+1] = input[i] << 4; - } + unsigned int i, j = 0; + + for (i = 0; i < input_size; i++, j += 2) + { + /* 16 gray levels transform to 256 levels using << 4 */ + output[j] = input[i] & 0xF0; + output[j + 1] = input[i] << 4; + } } /* * Remove duplicated lines at the end of a fingerprint. */ -static void process_removefpi_end(FpiDeviceEtes603 *dev) +static void +process_removefpi_end (FpiDeviceEtes603 *dev) { - unsigned int i; - /* 2 last lines with Fly-Estimation are the empty pattern. */ - guint8 *pattern = dev->fp + (dev->fp_height - 2) * FE_WIDTH / 2; - for (i = 2; i < dev->fp_height; i+= 2) { - if (memcmp(pattern, pattern - (i * FE_WIDTH / 2), FE_WIDTH)) - break; - } - dev->fp_height -= i; - fp_dbg("Removing %d empty lines from image", i - 2); + unsigned int i; + /* 2 last lines with Fly-Estimation are the empty pattern. */ + guint8 *pattern = dev->fp + (dev->fp_height - 2) * FE_WIDTH / 2; + + for (i = 2; i < dev->fp_height; i += 2) + if (memcmp (pattern, pattern - (i * FE_WIDTH / 2), FE_WIDTH)) + break; + dev->fp_height -= i; + fp_dbg ("Removing %d empty lines from image", i - 2); } -static void reset_param(FpiDeviceEtes603 *dev) +static void +reset_param (FpiDeviceEtes603 *dev) { - dev->dcoffset = 0; - dev->vrt = 0; - dev->vrb = 0; - dev->gain = 0; + dev->dcoffset = 0; + dev->vrt = 0; + dev->vrb = 0; + dev->gain = 0; } /* Asynchronous stuff */ enum { - INIT_CHECK_INFO_REQ, - INIT_CHECK_INFO_ANS, - INIT_CMD20_REQ, - INIT_CMD20_ANS, - INIT_CMD25_REQ, - INIT_CMD25_ANS, - INIT_SENSOR_REQ, - INIT_SENSOR_ANS, - INIT_ENC_REQ, - INIT_ENC_ANS, - INIT_REGS_REQ, - INIT_REGS_ANS, - INIT_NUM_STATES + INIT_CHECK_INFO_REQ, + INIT_CHECK_INFO_ANS, + INIT_CMD20_REQ, + INIT_CMD20_ANS, + INIT_CMD25_REQ, + INIT_CMD25_ANS, + INIT_SENSOR_REQ, + INIT_SENSOR_ANS, + INIT_ENC_REQ, + INIT_ENC_ANS, + INIT_REGS_REQ, + INIT_REGS_ANS, + INIT_NUM_STATES }; enum { - TUNEDC_INIT, - TUNEDC_SET_DCOFFSET_REQ, - TUNEDC_SET_DCOFFSET_ANS, - TUNEDC_GET_FRAME_REQ, - TUNEDC_GET_FRAME_ANS, - TUNEDC_FINAL_SET_REG2122_REQ, - TUNEDC_FINAL_SET_REG2122_ANS, - TUNEDC_FINAL_SET_GAIN_REQ, - TUNEDC_FINAL_SET_GAIN_ANS, - TUNEDC_FINAL_SET_DCOFFSET_REQ, - TUNEDC_FINAL_SET_DCOFFSET_ANS, - TUNEDC_NUM_STATES + TUNEDC_INIT, + TUNEDC_SET_DCOFFSET_REQ, + TUNEDC_SET_DCOFFSET_ANS, + TUNEDC_GET_FRAME_REQ, + TUNEDC_GET_FRAME_ANS, + TUNEDC_FINAL_SET_REG2122_REQ, + TUNEDC_FINAL_SET_REG2122_ANS, + TUNEDC_FINAL_SET_GAIN_REQ, + TUNEDC_FINAL_SET_GAIN_ANS, + TUNEDC_FINAL_SET_DCOFFSET_REQ, + TUNEDC_FINAL_SET_DCOFFSET_ANS, + TUNEDC_NUM_STATES }; enum { - TUNEVRB_INIT, - TUNEVRB_GET_GAIN_REQ, - TUNEVRB_GET_GAIN_ANS, - TUNEVRB_GET_DCOFFSET_REQ, - TUNEVRB_GET_DCOFFSET_ANS, - TUNEVRB_SET_DCOFFSET_REQ, - TUNEVRB_SET_DCOFFSET_ANS, - TUNEVRB_FRAME_REQ, - TUNEVRB_FRAME_ANS, - TUNEVRB_FINAL_SET_DCOFFSET_REQ, - TUNEVRB_FINAL_SET_DCOFFSET_ANS, - TUNEVRB_FINAL_SET_REG2627_REQ, - TUNEVRB_FINAL_SET_REG2627_ANS, - TUNEVRB_FINAL_SET_GAINVRTVRB_REQ, - TUNEVRB_FINAL_SET_GAINVRTVRB_ANS, - TUNEVRB_FINAL_SET_MODE_SLEEP_REQ, - TUNEVRB_FINAL_SET_MODE_SLEEP_ANS, - TUNEVRB_NUM_STATES + TUNEVRB_INIT, + TUNEVRB_GET_GAIN_REQ, + TUNEVRB_GET_GAIN_ANS, + TUNEVRB_GET_DCOFFSET_REQ, + TUNEVRB_GET_DCOFFSET_ANS, + TUNEVRB_SET_DCOFFSET_REQ, + TUNEVRB_SET_DCOFFSET_ANS, + TUNEVRB_FRAME_REQ, + TUNEVRB_FRAME_ANS, + TUNEVRB_FINAL_SET_DCOFFSET_REQ, + TUNEVRB_FINAL_SET_DCOFFSET_ANS, + TUNEVRB_FINAL_SET_REG2627_REQ, + TUNEVRB_FINAL_SET_REG2627_ANS, + TUNEVRB_FINAL_SET_GAINVRTVRB_REQ, + TUNEVRB_FINAL_SET_GAINVRTVRB_ANS, + TUNEVRB_FINAL_SET_MODE_SLEEP_REQ, + TUNEVRB_FINAL_SET_MODE_SLEEP_ANS, + TUNEVRB_NUM_STATES }; enum { - FGR_FPA_INIT_SET_MODE_SLEEP_REQ, - FGR_FPA_INIT_SET_MODE_SLEEP_ANS, - FGR_FPA_INIT_SET_DCOFFSET_REQ, - FGR_FPA_INIT_SET_DCOFFSET_ANS, - FGR_FPA_INIT_SET_GAINVRTVRB_REQ, - FGR_FPA_INIT_SET_GAINVRTVRB_ANS, - FGR_FPA_INIT_SET_VCO_CONTROL_RT_REQ, - FGR_FPA_INIT_SET_VCO_CONTROL_RT_ANS, - FGR_FPA_INIT_SET_REG04_REQ, - FGR_FPA_INIT_SET_REG04_ANS, - FGR_FPA_INIT_SET_MODE_SENSOR_REQ, - FGR_FPA_INIT_SET_MODE_SENSOR_ANS, - FGR_FPA_GET_FRAME_REQ, - FGR_FPA_GET_FRAME_ANS, - FGR_NUM_STATES + FGR_FPA_INIT_SET_MODE_SLEEP_REQ, + FGR_FPA_INIT_SET_MODE_SLEEP_ANS, + FGR_FPA_INIT_SET_DCOFFSET_REQ, + FGR_FPA_INIT_SET_DCOFFSET_ANS, + FGR_FPA_INIT_SET_GAINVRTVRB_REQ, + FGR_FPA_INIT_SET_GAINVRTVRB_ANS, + FGR_FPA_INIT_SET_VCO_CONTROL_RT_REQ, + FGR_FPA_INIT_SET_VCO_CONTROL_RT_ANS, + FGR_FPA_INIT_SET_REG04_REQ, + FGR_FPA_INIT_SET_REG04_ANS, + FGR_FPA_INIT_SET_MODE_SENSOR_REQ, + FGR_FPA_INIT_SET_MODE_SENSOR_ANS, + FGR_FPA_GET_FRAME_REQ, + FGR_FPA_GET_FRAME_ANS, + FGR_NUM_STATES }; enum { - CAP_FP_INIT_SET_REG10_REQ, - CAP_FP_INIT_SET_REG10_ANS, - CAP_FP_INIT_SET_MODE_FP_REQ, - CAP_FP_INIT_SET_MODE_FP_ANS, - CAP_FP_GET_FP_REQ, - CAP_FP_GET_FP_ANS, - CAP_NUM_STATES + CAP_FP_INIT_SET_REG10_REQ, + CAP_FP_INIT_SET_REG10_ANS, + CAP_FP_INIT_SET_MODE_FP_REQ, + CAP_FP_INIT_SET_MODE_FP_ANS, + CAP_FP_GET_FP_REQ, + CAP_FP_GET_FP_ANS, + CAP_NUM_STATES }; enum { - EXIT_SET_REGS_REQ, - EXIT_SET_REGS_ANS, - EXIT_NUM_STATES + EXIT_SET_REGS_REQ, + EXIT_SET_REGS_ANS, + EXIT_NUM_STATES }; -static void async_tx(FpDevice *dev, unsigned int ep, void *cb, - FpiSsm *ssm) +static void +async_tx (FpDevice *dev, unsigned int ep, void *cb, + FpiSsm *ssm) { - FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); - FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); - unsigned char *buffer = NULL; - int length; + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); + FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev); + unsigned char *buffer = NULL; + int length; - if (ep == EP_OUT) { - buffer = (unsigned char *) self->req; - length = self->req_len; - } else if (ep == EP_IN) { - buffer = (unsigned char *) self->ans; - length = self->ans_len; - } else { - g_assert_not_reached (); - } - transfer->ssm = ssm; - fpi_usb_transfer_fill_bulk_full(transfer, ep, buffer, length, NULL); - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, cb, NULL); - fpi_usb_transfer_unref(transfer); + if (ep == EP_OUT) + { + buffer = (unsigned char *) self->req; + length = self->req_len; + } + else if (ep == EP_IN) + { + buffer = (unsigned char *) self->ans; + length = self->ans_len; + } + else + { + g_assert_not_reached (); + } + transfer->ssm = ssm; + fpi_usb_transfer_fill_bulk_full (transfer, ep, buffer, length, NULL); + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, cb, NULL); + fpi_usb_transfer_unref (transfer); } -static void async_tx_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +async_tx_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpImageDevice *idev = FP_IMAGE_DEVICE(device); - FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(idev); + FpImageDevice *idev = FP_IMAGE_DEVICE (device); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (idev); - if (error) { - fp_warn("transfer is not completed (result: %s)", - error->message); - fpi_ssm_mark_failed(transfer->ssm, error); - } else { - unsigned char endpoint = transfer->endpoint; - int actual_length = transfer->actual_length; - int length = transfer->length; + if (error) + { + fp_warn ("transfer is not completed (result: %s)", + error->message); + fpi_ssm_mark_failed (transfer->ssm, error); + } + else + { + unsigned char endpoint = transfer->endpoint; + int actual_length = transfer->actual_length; + int length = transfer->length; - if (endpoint == EP_OUT) { - if (length != actual_length) - fp_warn("length %d != actual_length %d", - length, actual_length); + if (endpoint == EP_OUT) + { + if (length != actual_length) + fp_warn ("length %d != actual_length %d", + length, actual_length); - /* Chained with the answer */ - async_tx(device, EP_IN, async_tx_cb, transfer->ssm); - } else if (endpoint == EP_IN) { - self->ans_len = actual_length; - fpi_ssm_next_state(transfer->ssm); - } - } + /* Chained with the answer */ + async_tx (device, EP_IN, async_tx_cb, transfer->ssm); + } + else if (endpoint == EP_IN) + { + self->ans_len = actual_length; + fpi_ssm_next_state (transfer->ssm); + } + } } -static void m_exit_state(FpiSsm *ssm, FpDevice *dev, void *user_data) +static void +m_exit_state (FpiSsm *ssm, FpDevice *dev, void *user_data) { - FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case EXIT_SET_REGS_REQ: - msg_set_regs(self, 4, REG_VCO_CONTROL, REG_VCO_IDLE, - REG_MODE_CONTROL, REG_MODE_SLEEP); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case EXIT_SET_REGS_ANS: - if (msg_check_ok(self)) - goto err; - fpi_ssm_mark_completed(ssm); - break; - default: - g_assert_not_reached(); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case EXIT_SET_REGS_REQ: + msg_set_regs (self, 4, REG_VCO_CONTROL, REG_VCO_IDLE, + REG_MODE_CONTROL, REG_MODE_SLEEP); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; - return; + case EXIT_SET_REGS_ANS: + if (msg_check_ok (self)) + goto err; + fpi_ssm_mark_completed (ssm); + break; + + default: + g_assert_not_reached (); + break; + } + + return; err: - fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } -static void m_exit_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +static void +m_exit_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - FpImageDevice *idev = FP_IMAGE_DEVICE (dev); + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); - if (error) { - fp_err("Error switching the device to idle state"); - } else { - fp_dbg("The device is now in idle state"); - } - fpi_image_device_deactivate_complete(idev, error); - fpi_ssm_free(ssm); + if (error) + fp_err ("Error switching the device to idle state"); + else + fp_dbg ("The device is now in idle state"); + fpi_image_device_deactivate_complete (idev, error); + fpi_ssm_free (ssm); } -static void m_exit_start(FpImageDevice *idev) +static void +m_exit_start (FpImageDevice *idev) { - FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(idev); - FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(idev), m_exit_state, - EXIT_NUM_STATES, idev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (idev); + FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), m_exit_state, + EXIT_NUM_STATES, idev); - self->is_active = FALSE; - fp_dbg("Switching device to idle mode"); - fpi_ssm_start(ssm, m_exit_complete); + self->is_active = FALSE; + fp_dbg ("Switching device to idle mode"); + fpi_ssm_start (ssm, m_exit_complete); } -static void m_capture_state(FpiSsm *ssm, FpDevice *dev, void *user_data) +static void +m_capture_state (FpiSsm *ssm, FpDevice *dev, void *user_data) { - FpImageDevice *idev = FP_IMAGE_DEVICE (dev); - FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); - if (self->is_active == FALSE) { - fpi_ssm_mark_completed(ssm); - return; - } + if (self->is_active == FALSE) + { + fpi_ssm_mark_completed (ssm); + return; + } - switch (fpi_ssm_get_cur_state(ssm)) { - case CAP_FP_INIT_SET_REG10_REQ: - /* Reset fingerprint */ - fp_dbg("Capturing a fingerprint..."); - memset(self->fp, 0, FE_SIZE * 2); - self->fp_height = 0; - msg_set_regs(self, 2, REG_10, 0x92); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case CAP_FP_INIT_SET_REG10_ANS: - if (msg_check_ok(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case CAP_FP_INIT_SET_MODE_FP_REQ: - msg_set_mode_control(self, REG_MODE_FP); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case CAP_FP_INIT_SET_MODE_FP_ANS: - if (msg_check_ok(self)) - goto err; - fp_dbg("Capturing a 1st frame..."); - fpi_ssm_next_state(ssm); - break; - case CAP_FP_GET_FP_REQ: - msg_get_fp(self, 0x01, 0xF4, 0x02, 0x01, 0x64); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case CAP_FP_GET_FP_ANS: - memcpy(self->fp + self->fp_height * FE_WIDTH / 2, self->ans, - FE_SIZE); - self->fp_height += FE_HEIGHT; - if (self->fp_height <= FE_HEIGHT) { - /* 2 lines are at least removed each time */ - self->fp_height -= 2; - fp_dbg("Capturing a 2nd frame..."); - fpi_ssm_jump_to_state(ssm, CAP_FP_GET_FP_REQ); - } else { - FpImage *img; - unsigned int img_size; - /* Remove empty parts 2 times for the 2 frames */ - process_removefpi_end(self); - process_removefpi_end(self); - img_size = self->fp_height * FE_WIDTH; - img = fp_image_new(FE_WIDTH, self->fp_height); - /* Images received are white on black, so invert it. */ - /* TODO detect sweep direction */ - img->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED; - img->height = self->fp_height; - process_4to8_bpp(self->fp, img_size / 2, img->data); - fp_dbg("Sending the raw fingerprint image (%dx%d)", - img->width, img->height); - fpi_image_device_image_captured(idev, img); - fpi_image_device_report_finger_status(idev, FALSE); - fpi_ssm_mark_completed(ssm); - } - break; - default: - g_assert_not_reached(); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case CAP_FP_INIT_SET_REG10_REQ: + /* Reset fingerprint */ + fp_dbg ("Capturing a fingerprint..."); + memset (self->fp, 0, FE_SIZE * 2); + self->fp_height = 0; + msg_set_regs (self, 2, REG_10, 0x92); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; - return; + case CAP_FP_INIT_SET_REG10_ANS: + if (msg_check_ok (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case CAP_FP_INIT_SET_MODE_FP_REQ: + msg_set_mode_control (self, REG_MODE_FP); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case CAP_FP_INIT_SET_MODE_FP_ANS: + if (msg_check_ok (self)) + goto err; + fp_dbg ("Capturing a 1st frame..."); + fpi_ssm_next_state (ssm); + break; + + case CAP_FP_GET_FP_REQ: + msg_get_fp (self, 0x01, 0xF4, 0x02, 0x01, 0x64); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case CAP_FP_GET_FP_ANS: + memcpy (self->fp + self->fp_height * FE_WIDTH / 2, self->ans, + FE_SIZE); + self->fp_height += FE_HEIGHT; + if (self->fp_height <= FE_HEIGHT) + { + /* 2 lines are at least removed each time */ + self->fp_height -= 2; + fp_dbg ("Capturing a 2nd frame..."); + fpi_ssm_jump_to_state (ssm, CAP_FP_GET_FP_REQ); + } + else + { + FpImage *img; + unsigned int img_size; + /* Remove empty parts 2 times for the 2 frames */ + process_removefpi_end (self); + process_removefpi_end (self); + img_size = self->fp_height * FE_WIDTH; + img = fp_image_new (FE_WIDTH, self->fp_height); + /* Images received are white on black, so invert it. */ + /* TODO detect sweep direction */ + img->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED; + img->height = self->fp_height; + process_4to8_bpp (self->fp, img_size / 2, img->data); + fp_dbg ("Sending the raw fingerprint image (%dx%d)", + img->width, img->height); + fpi_image_device_image_captured (idev, img); + fpi_image_device_report_finger_status (idev, FALSE); + fpi_ssm_mark_completed (ssm); + } + break; + + default: + g_assert_not_reached (); + break; + } + + return; err: - fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } -static void m_capture_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +static void +m_capture_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - FpImageDevice *idev = FP_IMAGE_DEVICE (dev); - FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); - if (error) { - if (self->is_active) { - fp_err("Error while capturing fingerprint " - "(%s)", error->message); - fpi_image_device_session_error (idev, error); - } else { - g_error_free (error); - } - } - fpi_ssm_free(ssm); + if (error) + { + if (self->is_active) + { + fp_err ("Error while capturing fingerprint " + "(%s)", error->message); + fpi_image_device_session_error (idev, error); + } + else + { + g_error_free (error); + } + } + fpi_ssm_free (ssm); - if (self->is_active == TRUE) { - fp_dbg("Device is still active, restarting finger detection"); - m_start_fingerdetect(idev); - } else { - fp_dbg("And it's over."); - m_exit_start(idev); - } + if (self->is_active == TRUE) + { + fp_dbg ("Device is still active, restarting finger detection"); + m_start_fingerdetect (idev); + } + else + { + fp_dbg ("And it's over."); + m_exit_start (idev); + } } -static void m_finger_state(FpiSsm *ssm, FpDevice *dev, void *user_data) +static void +m_finger_state (FpiSsm *ssm, FpDevice *dev, void *user_data) { - FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); - if (self->is_active == FALSE) { - fpi_ssm_mark_completed(ssm); - return; - } + if (self->is_active == FALSE) + { + fpi_ssm_mark_completed (ssm); + return; + } - switch (fpi_ssm_get_cur_state(ssm)) { - case FGR_FPA_INIT_SET_MODE_SLEEP_REQ: - msg_set_mode_control(self, REG_MODE_SLEEP); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case FGR_FPA_INIT_SET_MODE_SLEEP_ANS: - if (msg_check_ok(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case FGR_FPA_INIT_SET_DCOFFSET_REQ: - msg_set_regs(self, 2, REG_DCOFFSET, self->dcoffset); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case FGR_FPA_INIT_SET_DCOFFSET_ANS: - if (msg_check_ok(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case FGR_FPA_INIT_SET_GAINVRTVRB_REQ: - msg_set_regs(self, 6, REG_GAIN, self->gain, REG_VRT, - self->vrt, - REG_VRB, self->vrb); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case FGR_FPA_INIT_SET_GAINVRTVRB_ANS: - if (msg_check_ok(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case FGR_FPA_INIT_SET_VCO_CONTROL_RT_REQ: - msg_set_regs(self, 2, REG_VCO_CONTROL, REG_VCO_RT); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case FGR_FPA_INIT_SET_VCO_CONTROL_RT_ANS: - if (msg_check_ok(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case FGR_FPA_INIT_SET_REG04_REQ: - msg_set_regs(self, 2, REG_04, 0x00); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case FGR_FPA_INIT_SET_REG04_ANS: - if (msg_check_ok(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case FGR_FPA_INIT_SET_MODE_SENSOR_REQ: - msg_set_mode_control(self, REG_MODE_SENSOR); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case FGR_FPA_INIT_SET_MODE_SENSOR_ANS: - if (msg_check_ok(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case FGR_FPA_GET_FRAME_REQ: - msg_get_frame(self, 0x00, 0x00, 0x00, 0x00); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case FGR_FPA_GET_FRAME_ANS: - if (process_frame_empty((guint8 *) self->ans, FRAME_SIZE)) { - fpi_ssm_jump_to_state(ssm, FGR_FPA_GET_FRAME_REQ); - } else { - fpi_image_device_report_finger_status(FP_IMAGE_DEVICE (dev), TRUE); - fpi_ssm_mark_completed(ssm); - } - break; - default: - g_assert_not_reached(); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case FGR_FPA_INIT_SET_MODE_SLEEP_REQ: + msg_set_mode_control (self, REG_MODE_SLEEP); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; - return; + case FGR_FPA_INIT_SET_MODE_SLEEP_ANS: + if (msg_check_ok (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case FGR_FPA_INIT_SET_DCOFFSET_REQ: + msg_set_regs (self, 2, REG_DCOFFSET, self->dcoffset); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case FGR_FPA_INIT_SET_DCOFFSET_ANS: + if (msg_check_ok (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case FGR_FPA_INIT_SET_GAINVRTVRB_REQ: + msg_set_regs (self, 6, REG_GAIN, self->gain, REG_VRT, + self->vrt, + REG_VRB, self->vrb); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case FGR_FPA_INIT_SET_GAINVRTVRB_ANS: + if (msg_check_ok (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case FGR_FPA_INIT_SET_VCO_CONTROL_RT_REQ: + msg_set_regs (self, 2, REG_VCO_CONTROL, REG_VCO_RT); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case FGR_FPA_INIT_SET_VCO_CONTROL_RT_ANS: + if (msg_check_ok (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case FGR_FPA_INIT_SET_REG04_REQ: + msg_set_regs (self, 2, REG_04, 0x00); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case FGR_FPA_INIT_SET_REG04_ANS: + if (msg_check_ok (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case FGR_FPA_INIT_SET_MODE_SENSOR_REQ: + msg_set_mode_control (self, REG_MODE_SENSOR); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case FGR_FPA_INIT_SET_MODE_SENSOR_ANS: + if (msg_check_ok (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case FGR_FPA_GET_FRAME_REQ: + msg_get_frame (self, 0x00, 0x00, 0x00, 0x00); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case FGR_FPA_GET_FRAME_ANS: + if (process_frame_empty ((guint8 *) self->ans, FRAME_SIZE)) + { + fpi_ssm_jump_to_state (ssm, FGR_FPA_GET_FRAME_REQ); + } + else + { + fpi_image_device_report_finger_status (FP_IMAGE_DEVICE (dev), TRUE); + fpi_ssm_mark_completed (ssm); + } + break; + + default: + g_assert_not_reached (); + break; + } + + return; err: - fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } -static void m_finger_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +static void +m_finger_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - FpImageDevice *idev = FP_IMAGE_DEVICE (dev); - FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); - if (!error) { - FpiSsm *ssm_cap; - ssm_cap = fpi_ssm_new(dev, m_capture_state, - CAP_NUM_STATES, NULL); - fpi_ssm_start(ssm_cap, m_capture_complete); - } else { - if (self->is_active) { - fp_err("Error while capturing fingerprint " - "(%s)", error->message); - fpi_image_device_session_error(idev, error); - } else { - m_exit_start(idev); - g_error_free (error); - } - self->is_active = FALSE; - } + if (!error) + { + FpiSsm *ssm_cap; + ssm_cap = fpi_ssm_new (dev, m_capture_state, + CAP_NUM_STATES, NULL); + fpi_ssm_start (ssm_cap, m_capture_complete); + } + else + { + if (self->is_active) + { + fp_err ("Error while capturing fingerprint " + "(%s)", error->message); + fpi_image_device_session_error (idev, error); + } + else + { + m_exit_start (idev); + g_error_free (error); + } + self->is_active = FALSE; + } - fpi_ssm_free(ssm); + fpi_ssm_free (ssm); } -static void m_start_fingerdetect(FpImageDevice *idev) +static void +m_start_fingerdetect (FpImageDevice *idev) { - FpiSsm *ssmf; - ssmf = fpi_ssm_new(FP_DEVICE(idev), m_finger_state, FGR_NUM_STATES, - idev); - fpi_ssm_start(ssmf, m_finger_complete); + FpiSsm *ssmf; + + ssmf = fpi_ssm_new (FP_DEVICE (idev), m_finger_state, FGR_NUM_STATES, + idev); + fpi_ssm_start (ssmf, m_finger_complete); } /* * Tune value of VRT and VRB for contrast and brightness. */ -static void m_tunevrb_state(FpiSsm *ssm, FpDevice *dev, void *user_data) +static void +m_tunevrb_state (FpiSsm *ssm, FpDevice *dev, void *user_data) { - FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); - float hist[5]; + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); + float hist[5]; - if (self->is_active == FALSE) { - fpi_ssm_mark_completed(ssm); - return; - } + if (self->is_active == FALSE) + { + fpi_ssm_mark_completed (ssm); + return; + } - switch (fpi_ssm_get_cur_state(ssm)) { - case TUNEVRB_INIT: - fp_dbg("Tuning of VRT/VRB"); - g_assert(self->dcoffset); - /* VRT(reg E1)=0x0A and VRB(reg E2)=0x10 are starting values */ - self->vrt = 0x0A; - self->vrb = 0x10; - fpi_ssm_next_state(ssm); - break; - case TUNEVRB_GET_GAIN_REQ: - msg_get_regs(self, 1, REG_GAIN); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case TUNEVRB_GET_GAIN_ANS: - if (msg_parse_regs(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case TUNEVRB_GET_DCOFFSET_REQ: - msg_get_regs(self, 1, REG_DCOFFSET); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case TUNEVRB_GET_DCOFFSET_ANS: - if (msg_parse_regs(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case TUNEVRB_SET_DCOFFSET_REQ: - /* Reduce DCoffset by 1 to allow tuning */ - msg_set_regs(self, 2, REG_DCOFFSET, self->dcoffset - 1); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case TUNEVRB_SET_DCOFFSET_ANS: - if (msg_check_ok(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case TUNEVRB_FRAME_REQ: - fp_dbg("Testing VRT=0x%02X VRB=0x%02X", self->vrt, self->vrb); - msg_get_frame(self, 0x01, self->gain, self->vrt, self->vrb); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case TUNEVRB_FRAME_ANS: - process_hist((guint8 *) self->ans, FRAME_SIZE, hist); - /* Note that this tuning could probably be improved */ - if (hist[0] + hist[1] > 0.95) { - if (self->vrt <= 0 || self->vrb <= 0) { - fp_dbg("Image is too dark, reducing DCOffset"); - self->dcoffset--; - fpi_ssm_jump_to_state(ssm, TUNEVRB_INIT); - } else { - self->vrt--; - self->vrb--; - fpi_ssm_jump_to_state(ssm, TUNEVRB_FRAME_REQ); - } - break; - } - if (hist[4] > 0.95) { - fp_dbg("Image is too bright, increasing DCOffset"); - self->dcoffset++; - fpi_ssm_jump_to_state(ssm, TUNEVRB_INIT); - break; - } - if (hist[4] + hist[3] > 0.4) { - if (self->vrt >= 2 * self->vrb - 0x0a) { - self->vrt++; self->vrb++; - } else { - self->vrt++; - } - /* Check maximum for vrt/vrb */ - /* TODO if maximum is reached, leave with an error? */ - if (self->vrt > VRT_MAX) - self->vrt = VRT_MAX; - if (self->vrb > VRB_MAX) - self->vrb = VRB_MAX; - fpi_ssm_jump_to_state(ssm, TUNEVRB_FRAME_REQ); - break; - } - fpi_ssm_next_state(ssm); - break; - case TUNEVRB_FINAL_SET_DCOFFSET_REQ: - fp_dbg("-> VRT=0x%02X VRB=0x%02X", self->vrt, self->vrb); - /* Reset the DCOffset */ - msg_set_regs(self, 2, REG_DCOFFSET, self->dcoffset); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case TUNEVRB_FINAL_SET_DCOFFSET_ANS: - if (msg_check_ok(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case TUNEVRB_FINAL_SET_REG2627_REQ: - /* In traces, REG_26/REG_27 are set. purpose? values? */ - msg_set_regs(self, 4, REG_26, 0x11, REG_27, 0x00); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case TUNEVRB_FINAL_SET_REG2627_ANS: - if (msg_check_ok(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case TUNEVRB_FINAL_SET_GAINVRTVRB_REQ: - /* Set Gain/VRT/VRB values found */ - msg_set_regs(self, 6, REG_GAIN, self->gain, REG_VRT, - self->vrt, - REG_VRB, self->vrb); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case TUNEVRB_FINAL_SET_GAINVRTVRB_ANS: - if (msg_check_ok(self)) - goto err; - /* In traces, Gain/VRT/VRB are read again. */ - fpi_ssm_next_state(ssm); - break; - case TUNEVRB_FINAL_SET_MODE_SLEEP_REQ: - msg_set_mode_control(self, REG_MODE_SLEEP); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case TUNEVRB_FINAL_SET_MODE_SLEEP_ANS: - if (msg_check_ok(self)) - goto err; - fpi_ssm_mark_completed(ssm); - break; - default: - g_assert_not_reached(); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case TUNEVRB_INIT: + fp_dbg ("Tuning of VRT/VRB"); + g_assert (self->dcoffset); + /* VRT(reg E1)=0x0A and VRB(reg E2)=0x10 are starting values */ + self->vrt = 0x0A; + self->vrb = 0x10; + fpi_ssm_next_state (ssm); + break; - return; + case TUNEVRB_GET_GAIN_REQ: + msg_get_regs (self, 1, REG_GAIN); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case TUNEVRB_GET_GAIN_ANS: + if (msg_parse_regs (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case TUNEVRB_GET_DCOFFSET_REQ: + msg_get_regs (self, 1, REG_DCOFFSET); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case TUNEVRB_GET_DCOFFSET_ANS: + if (msg_parse_regs (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case TUNEVRB_SET_DCOFFSET_REQ: + /* Reduce DCoffset by 1 to allow tuning */ + msg_set_regs (self, 2, REG_DCOFFSET, self->dcoffset - 1); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case TUNEVRB_SET_DCOFFSET_ANS: + if (msg_check_ok (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case TUNEVRB_FRAME_REQ: + fp_dbg ("Testing VRT=0x%02X VRB=0x%02X", self->vrt, self->vrb); + msg_get_frame (self, 0x01, self->gain, self->vrt, self->vrb); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case TUNEVRB_FRAME_ANS: + process_hist ((guint8 *) self->ans, FRAME_SIZE, hist); + /* Note that this tuning could probably be improved */ + if (hist[0] + hist[1] > 0.95) + { + if (self->vrt <= 0 || self->vrb <= 0) + { + fp_dbg ("Image is too dark, reducing DCOffset"); + self->dcoffset--; + fpi_ssm_jump_to_state (ssm, TUNEVRB_INIT); + } + else + { + self->vrt--; + self->vrb--; + fpi_ssm_jump_to_state (ssm, TUNEVRB_FRAME_REQ); + } + break; + } + if (hist[4] > 0.95) + { + fp_dbg ("Image is too bright, increasing DCOffset"); + self->dcoffset++; + fpi_ssm_jump_to_state (ssm, TUNEVRB_INIT); + break; + } + if (hist[4] + hist[3] > 0.4) + { + if (self->vrt >= 2 * self->vrb - 0x0a) + { + self->vrt++; + self->vrb++; + } + else + { + self->vrt++; + } + /* Check maximum for vrt/vrb */ + /* TODO if maximum is reached, leave with an error? */ + if (self->vrt > VRT_MAX) + self->vrt = VRT_MAX; + if (self->vrb > VRB_MAX) + self->vrb = VRB_MAX; + fpi_ssm_jump_to_state (ssm, TUNEVRB_FRAME_REQ); + break; + } + fpi_ssm_next_state (ssm); + break; + + case TUNEVRB_FINAL_SET_DCOFFSET_REQ: + fp_dbg ("-> VRT=0x%02X VRB=0x%02X", self->vrt, self->vrb); + /* Reset the DCOffset */ + msg_set_regs (self, 2, REG_DCOFFSET, self->dcoffset); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case TUNEVRB_FINAL_SET_DCOFFSET_ANS: + if (msg_check_ok (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case TUNEVRB_FINAL_SET_REG2627_REQ: + /* In traces, REG_26/REG_27 are set. purpose? values? */ + msg_set_regs (self, 4, REG_26, 0x11, REG_27, 0x00); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case TUNEVRB_FINAL_SET_REG2627_ANS: + if (msg_check_ok (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case TUNEVRB_FINAL_SET_GAINVRTVRB_REQ: + /* Set Gain/VRT/VRB values found */ + msg_set_regs (self, 6, REG_GAIN, self->gain, REG_VRT, + self->vrt, + REG_VRB, self->vrb); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case TUNEVRB_FINAL_SET_GAINVRTVRB_ANS: + if (msg_check_ok (self)) + goto err; + /* In traces, Gain/VRT/VRB are read again. */ + fpi_ssm_next_state (ssm); + break; + + case TUNEVRB_FINAL_SET_MODE_SLEEP_REQ: + msg_set_mode_control (self, REG_MODE_SLEEP); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case TUNEVRB_FINAL_SET_MODE_SLEEP_ANS: + if (msg_check_ok (self)) + goto err; + fpi_ssm_mark_completed (ssm); + break; + + default: + g_assert_not_reached (); + break; + } + + return; err: - fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } -static void m_tunevrb_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +static void +m_tunevrb_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); - FpImageDevice *idev = FP_IMAGE_DEVICE (dev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); - fpi_image_device_activate_complete(idev, error); - if (!error) { - fp_dbg("Tuning is done. Starting finger detection."); - m_start_fingerdetect(idev); - } + fpi_image_device_activate_complete (idev, error); + if (!error) + { + fp_dbg ("Tuning is done. Starting finger detection."); + m_start_fingerdetect (idev); + } - if (!self->is_active) - m_exit_start(idev); + if (!self->is_active) + m_exit_start (idev); - fpi_ssm_free(ssm); + fpi_ssm_free (ssm); } /* * This function tunes the DCoffset value and adjusts the gain value if * required. */ -static void m_tunedc_state(FpiSsm *ssm, FpDevice *dev, void *user_data) +static void +m_tunedc_state (FpiSsm *ssm, FpDevice *dev, void *user_data) { - FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); - if (self->is_active == FALSE) { - fpi_ssm_mark_completed(ssm); - return; - } + if (self->is_active == FALSE) + { + fpi_ssm_mark_completed (ssm); + return; + } - /* TODO To get better results, tuning could be done 3 times as in - * captured traffic to make sure that the value is correct. */ - /* The default gain should work but it may reach a DCOffset limit so in - * this case we decrease the gain. */ - switch (fpi_ssm_get_cur_state(ssm)) { - case TUNEDC_INIT: - /* reg_e0 = 0x23 is sensor normal/small gain */ - self->gain = GAIN_SMALL_INIT; - self->tunedc_min = DCOFFSET_MIN; - self->tunedc_max = DCOFFSET_MAX; - fp_dbg("Tuning DCoffset"); - fpi_ssm_next_state(ssm); - break; - case TUNEDC_SET_DCOFFSET_REQ: - /* Dichotomic search to find at which value the frame becomes - * almost black. */ - self->dcoffset = (self->tunedc_max + self->tunedc_min) / 2; - fp_dbg("Testing DCoffset=0x%02X Gain=0x%02X", self->dcoffset, - self->gain); - msg_set_regs(self, 2, REG_DCOFFSET, self->dcoffset); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case TUNEDC_SET_DCOFFSET_ANS: - if (msg_check_ok(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case TUNEDC_GET_FRAME_REQ: - /* vrt:0x15 vrb:0x10 are constant in all tuning frames. */ - msg_get_frame(self, 0x01, self->gain, 0x15, 0x10); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case TUNEDC_GET_FRAME_ANS: - if (process_frame_empty((guint8 *) self->ans, FRAME_WIDTH)) - self->tunedc_max = self->dcoffset; - else - self->tunedc_min = self->dcoffset; - if (self->tunedc_min + 1 < self->tunedc_max) { - fpi_ssm_jump_to_state(ssm, TUNEDC_SET_DCOFFSET_REQ); - } else if (self->tunedc_max < DCOFFSET_MAX) { - self->dcoffset = self->tunedc_max + 1; - fpi_ssm_next_state(ssm); - } else { - self->gain--; - fpi_ssm_jump_to_state(ssm, TUNEDC_SET_DCOFFSET_REQ); - } - break; - case TUNEDC_FINAL_SET_REG2122_REQ: - fp_dbg("-> DCoffset=0x%02X Gain=0x%02X", self->dcoffset, - self->gain); - /* ??? how reg21 / reg22 are calculated */ - msg_set_regs(self, 4, REG_21, 0x23, REG_22, 0x21); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case TUNEDC_FINAL_SET_REG2122_ANS: - if (msg_check_ok(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case TUNEDC_FINAL_SET_GAIN_REQ: - msg_set_regs(self, 2, REG_GAIN, self->gain); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case TUNEDC_FINAL_SET_GAIN_ANS: - fpi_ssm_next_state(ssm); - break; - case TUNEDC_FINAL_SET_DCOFFSET_REQ: - msg_set_regs(self, 2, REG_DCOFFSET, self->dcoffset); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case TUNEDC_FINAL_SET_DCOFFSET_ANS: - /* In captured traffic, read GAIN, VRT, and VRB registers. */ - if (msg_check_ok(self)) - goto err; - fpi_ssm_mark_completed(ssm); - break; - default: - g_assert_not_reached(); - break; - } + /* TODO To get better results, tuning could be done 3 times as in + * captured traffic to make sure that the value is correct. */ + /* The default gain should work but it may reach a DCOffset limit so in + * this case we decrease the gain. */ + switch (fpi_ssm_get_cur_state (ssm)) + { + case TUNEDC_INIT: + /* reg_e0 = 0x23 is sensor normal/small gain */ + self->gain = GAIN_SMALL_INIT; + self->tunedc_min = DCOFFSET_MIN; + self->tunedc_max = DCOFFSET_MAX; + fp_dbg ("Tuning DCoffset"); + fpi_ssm_next_state (ssm); + break; - return; + case TUNEDC_SET_DCOFFSET_REQ: + /* Dichotomic search to find at which value the frame becomes + * almost black. */ + self->dcoffset = (self->tunedc_max + self->tunedc_min) / 2; + fp_dbg ("Testing DCoffset=0x%02X Gain=0x%02X", self->dcoffset, + self->gain); + msg_set_regs (self, 2, REG_DCOFFSET, self->dcoffset); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case TUNEDC_SET_DCOFFSET_ANS: + if (msg_check_ok (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case TUNEDC_GET_FRAME_REQ: + /* vrt:0x15 vrb:0x10 are constant in all tuning frames. */ + msg_get_frame (self, 0x01, self->gain, 0x15, 0x10); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case TUNEDC_GET_FRAME_ANS: + if (process_frame_empty ((guint8 *) self->ans, FRAME_WIDTH)) + self->tunedc_max = self->dcoffset; + else + self->tunedc_min = self->dcoffset; + if (self->tunedc_min + 1 < self->tunedc_max) + { + fpi_ssm_jump_to_state (ssm, TUNEDC_SET_DCOFFSET_REQ); + } + else if (self->tunedc_max < DCOFFSET_MAX) + { + self->dcoffset = self->tunedc_max + 1; + fpi_ssm_next_state (ssm); + } + else + { + self->gain--; + fpi_ssm_jump_to_state (ssm, TUNEDC_SET_DCOFFSET_REQ); + } + break; + + case TUNEDC_FINAL_SET_REG2122_REQ: + fp_dbg ("-> DCoffset=0x%02X Gain=0x%02X", self->dcoffset, + self->gain); + /* ??? how reg21 / reg22 are calculated */ + msg_set_regs (self, 4, REG_21, 0x23, REG_22, 0x21); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case TUNEDC_FINAL_SET_REG2122_ANS: + if (msg_check_ok (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case TUNEDC_FINAL_SET_GAIN_REQ: + msg_set_regs (self, 2, REG_GAIN, self->gain); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case TUNEDC_FINAL_SET_GAIN_ANS: + fpi_ssm_next_state (ssm); + break; + + case TUNEDC_FINAL_SET_DCOFFSET_REQ: + msg_set_regs (self, 2, REG_DCOFFSET, self->dcoffset); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case TUNEDC_FINAL_SET_DCOFFSET_ANS: + /* In captured traffic, read GAIN, VRT, and VRB registers. */ + if (msg_check_ok (self)) + goto err; + fpi_ssm_mark_completed (ssm); + break; + + default: + g_assert_not_reached (); + break; + } + + return; err: - fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } -static void m_tunedc_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +static void +m_tunedc_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); - FpImageDevice *idev = FP_IMAGE_DEVICE (dev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); - if (!error) { - FpiSsm *ssm_tune; - ssm_tune = fpi_ssm_new(FP_DEVICE(idev), m_tunevrb_state, - TUNEVRB_NUM_STATES, idev); - fpi_ssm_start(ssm_tune, m_tunevrb_complete); - } else { - fp_err("Error while tuning DCOFFSET"); - reset_param(FPI_DEVICE_ETES603 (dev)); - fpi_image_device_session_error(idev, error); - } + if (!error) + { + FpiSsm *ssm_tune; + ssm_tune = fpi_ssm_new (FP_DEVICE (idev), m_tunevrb_state, + TUNEVRB_NUM_STATES, idev); + fpi_ssm_start (ssm_tune, m_tunevrb_complete); + } + else + { + fp_err ("Error while tuning DCOFFSET"); + reset_param (FPI_DEVICE_ETES603 (dev)); + fpi_image_device_session_error (idev, error); + } - if (!self->is_active) - m_exit_start(idev); + if (!self->is_active) + m_exit_start (idev); - fpi_ssm_free(ssm); + fpi_ssm_free (ssm); } -static void m_init_state(FpiSsm *ssm, FpDevice *dev, void *user_data) +static void +m_init_state (FpiSsm *ssm, FpDevice *dev, void *user_data) { - FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(dev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); - if (self->is_active == FALSE) { - fpi_ssm_mark_completed(ssm); - return; - } + if (self->is_active == FALSE) + { + fpi_ssm_mark_completed (ssm); + return; + } - switch (fpi_ssm_get_cur_state(ssm)) { - case INIT_CHECK_INFO_REQ: - msg_get_regs(self, 4, REG_INFO0, REG_INFO1, REG_INFO2, - REG_INFO3); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case INIT_CHECK_INFO_ANS: - if (msg_parse_regs(self)) - goto err; - if (check_info(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case INIT_CMD20_REQ: - msg_get_cmd20(self); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case INIT_CMD20_ANS: - if (msg_check_cmd20(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case INIT_CMD25_REQ: - msg_get_cmd25(self); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case INIT_CMD25_ANS: - if (msg_check_cmd25(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case INIT_SENSOR_REQ: - /* In captured traffic, those are split. */ - msg_set_regs(self, 18, REG_MODE_CONTROL, REG_MODE_SLEEP, - REG_50, 0x0F, REG_GAIN, 0x04, REG_VRT, 0x08, - REG_VRB, 0x0D, REG_VCO_CONTROL, REG_VCO_RT, - REG_DCOFFSET, 0x36, REG_F0, 0x00, REG_F2, 0x00); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case INIT_SENSOR_ANS: - if (msg_check_ok(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case INIT_ENC_REQ: - /* Initialize encryption registers without encryption. */ - /* Set registers from 0x41 to 0x48 (0x8 regs) */ - msg_set_regs(self, 16, REG_ENC1, 0x12, REG_ENC2, 0x34, - REG_ENC3, 0x56, REG_ENC4, 0x78, REG_ENC5, 0x90, - REG_ENC6, 0xAB, REG_ENC7, 0xCD, REG_ENC8, 0xEF); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case INIT_ENC_ANS: - if (msg_check_ok(self)) - goto err; - fpi_ssm_next_state(ssm); - break; - case INIT_REGS_REQ: - /* Set register from 0x20 to 0x37 (0x18 regs) */ - msg_set_regs(self, 48, - REG_20, 0x00, REG_21, 0x23, REG_22, 0x21, REG_23, - 0x20, - REG_24, 0x14, REG_25, 0x6A, REG_26, 0x00, REG_27, - 0x00, - REG_28, 0x00, REG_29, 0xC0, REG_2A, 0x50, REG_2B, - 0x50, - REG_2C, 0x4D, REG_2D, 0x03, REG_2E, 0x06, REG_2F, - 0x06, - REG_30, 0x10, REG_31, 0x02, REG_32, 0x14, REG_33, - 0x34, - REG_34, 0x01, REG_35, 0x08, REG_36, 0x03, REG_37, - 0x21); - async_tx(dev, EP_OUT, async_tx_cb, ssm); - break; - case INIT_REGS_ANS: - if (msg_check_ok(self)) - goto err; - fpi_ssm_mark_completed(ssm); - break; - default: - g_assert_not_reached(); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case INIT_CHECK_INFO_REQ: + msg_get_regs (self, 4, REG_INFO0, REG_INFO1, REG_INFO2, + REG_INFO3); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; - return; + case INIT_CHECK_INFO_ANS: + if (msg_parse_regs (self)) + goto err; + if (check_info (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case INIT_CMD20_REQ: + msg_get_cmd20 (self); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case INIT_CMD20_ANS: + if (msg_check_cmd20 (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case INIT_CMD25_REQ: + msg_get_cmd25 (self); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case INIT_CMD25_ANS: + if (msg_check_cmd25 (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case INIT_SENSOR_REQ: + /* In captured traffic, those are split. */ + msg_set_regs (self, 18, REG_MODE_CONTROL, REG_MODE_SLEEP, + REG_50, 0x0F, REG_GAIN, 0x04, REG_VRT, 0x08, + REG_VRB, 0x0D, REG_VCO_CONTROL, REG_VCO_RT, + REG_DCOFFSET, 0x36, REG_F0, 0x00, REG_F2, 0x00); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case INIT_SENSOR_ANS: + if (msg_check_ok (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case INIT_ENC_REQ: + /* Initialize encryption registers without encryption. */ + /* Set registers from 0x41 to 0x48 (0x8 regs) */ + msg_set_regs (self, 16, REG_ENC1, 0x12, REG_ENC2, 0x34, + REG_ENC3, 0x56, REG_ENC4, 0x78, REG_ENC5, 0x90, + REG_ENC6, 0xAB, REG_ENC7, 0xCD, REG_ENC8, 0xEF); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case INIT_ENC_ANS: + if (msg_check_ok (self)) + goto err; + fpi_ssm_next_state (ssm); + break; + + case INIT_REGS_REQ: + /* Set register from 0x20 to 0x37 (0x18 regs) */ + msg_set_regs (self, 48, + REG_20, 0x00, REG_21, 0x23, REG_22, 0x21, REG_23, + 0x20, + REG_24, 0x14, REG_25, 0x6A, REG_26, 0x00, REG_27, + 0x00, + REG_28, 0x00, REG_29, 0xC0, REG_2A, 0x50, REG_2B, + 0x50, + REG_2C, 0x4D, REG_2D, 0x03, REG_2E, 0x06, REG_2F, + 0x06, + REG_30, 0x10, REG_31, 0x02, REG_32, 0x14, REG_33, + 0x34, + REG_34, 0x01, REG_35, 0x08, REG_36, 0x03, REG_37, + 0x21); + async_tx (dev, EP_OUT, async_tx_cb, ssm); + break; + + case INIT_REGS_ANS: + if (msg_check_ok (self)) + goto err; + fpi_ssm_mark_completed (ssm); + break; + + default: + g_assert_not_reached (); + break; + } + + return; err: - fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } -static void m_init_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +static void +m_init_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - FpImageDevice *idev = FP_IMAGE_DEVICE (dev); - if (!error) { - FpiSsm *ssm_tune; - ssm_tune = fpi_ssm_new(FP_DEVICE(idev), m_tunedc_state, - TUNEDC_NUM_STATES, idev); - fpi_ssm_start(ssm_tune, m_tunedc_complete); - } else { - fp_err("Error initializing the device"); - reset_param(FPI_DEVICE_ETES603 (dev)); - fpi_image_device_session_error (idev, error); - } - fpi_ssm_free(ssm); + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); + + if (!error) + { + FpiSsm *ssm_tune; + ssm_tune = fpi_ssm_new (FP_DEVICE (idev), m_tunedc_state, + TUNEDC_NUM_STATES, idev); + fpi_ssm_start (ssm_tune, m_tunedc_complete); + } + else + { + fp_err ("Error initializing the device"); + reset_param (FPI_DEVICE_ETES603 (dev)); + fpi_image_device_session_error (idev, error); + } + fpi_ssm_free (ssm); } -static void dev_activate(FpImageDevice *idev) +static void +dev_activate (FpImageDevice *idev) { - FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(idev); - FpiSsm *ssm; + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (idev); + FpiSsm *ssm; - g_assert(self); + g_assert (self); - /* Reset info and data */ - self->is_active = TRUE; + /* Reset info and data */ + self->is_active = TRUE; - if (self->dcoffset == 0) { - fp_dbg("Tuning device..."); - ssm = fpi_ssm_new(FP_DEVICE(idev), m_init_state, - INIT_NUM_STATES, idev); - fpi_ssm_start(ssm, m_init_complete); - } else { - fp_dbg("Using previous tuning (DCOFFSET=0x%02X,VRT=0x%02X," - "VRB=0x%02X,GAIN=0x%02X).", self->dcoffset, self->vrt, - self->vrb, self->gain); - fpi_image_device_activate_complete(idev, NULL); - ssm = fpi_ssm_new(FP_DEVICE(idev), m_finger_state, - FGR_NUM_STATES, idev); - fpi_ssm_start(ssm, m_finger_complete); - } + if (self->dcoffset == 0) + { + fp_dbg ("Tuning device..."); + ssm = fpi_ssm_new (FP_DEVICE (idev), m_init_state, + INIT_NUM_STATES, idev); + fpi_ssm_start (ssm, m_init_complete); + } + else + { + fp_dbg ("Using previous tuning (DCOFFSET=0x%02X,VRT=0x%02X," + "VRB=0x%02X,GAIN=0x%02X).", self->dcoffset, self->vrt, + self->vrb, self->gain); + fpi_image_device_activate_complete (idev, NULL); + ssm = fpi_ssm_new (FP_DEVICE (idev), m_finger_state, + FGR_NUM_STATES, idev); + fpi_ssm_start (ssm, m_finger_complete); + } } -static void dev_deactivate(FpImageDevice *idev) +static void +dev_deactivate (FpImageDevice *idev) { - FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(idev); + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (idev); - fp_dbg("deactivating"); + fp_dbg ("deactivating"); - /* this can be called even if still activated. */ - if (self->is_active == TRUE) { - self->is_active = FALSE; - } else { - m_exit_start(idev); - } + /* this can be called even if still activated. */ + if (self->is_active == TRUE) + self->is_active = FALSE; + else + m_exit_start (idev); } -static void dev_open(FpImageDevice *idev) +static void +dev_open (FpImageDevice *idev) { - GError *error = NULL; - FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(idev); + GError *error = NULL; + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (idev); - if (!g_usb_device_claim_interface (fpi_device_get_usb_device(FP_DEVICE(idev)), 0, 0, &error)) { - fpi_image_device_open_complete(idev, error); - return; - } + if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (idev)), 0, 0, &error)) + { + fpi_image_device_open_complete (idev, error); + return; + } - self->req = g_malloc(sizeof(struct egis_msg)); - self->ans = g_malloc(FE_SIZE); - self->fp = g_malloc(FE_SIZE * 4); + self->req = g_malloc (sizeof (struct egis_msg)); + self->ans = g_malloc (FE_SIZE); + self->fp = g_malloc (FE_SIZE * 4); - fpi_image_device_open_complete(idev, NULL); + fpi_image_device_open_complete (idev, NULL); } -static void dev_close(FpImageDevice *idev) +static void +dev_close (FpImageDevice *idev) { - GError *error = NULL; - FpiDeviceEtes603 *self = FPI_DEVICE_ETES603(idev); + GError *error = NULL; + FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (idev); - g_free(self->req); - g_free(self->ans); - g_free(self->fp); + g_free (self->req); + g_free (self->ans); + g_free (self->fp); - g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(idev)), - 0, 0, &error); - fpi_image_device_close_complete(idev, error); + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (idev)), + 0, 0, &error); + fpi_image_device_close_complete (idev, error); } -static const FpIdEntry id_table [ ] = { - /* EgisTec (aka Lightuning) ES603 */ - { .vid = 0x1c7a, .pid = 0x0603, }, - { .vid = 0, .pid = 0, .driver_data = 0 }, +static const FpIdEntry id_table[] = { + /* EgisTec (aka Lightuning) ES603 */ + { .vid = 0x1c7a, .pid = 0x0603, }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -static void fpi_device_etes603_init(FpiDeviceEtes603 *self) { +static void +fpi_device_etes603_init (FpiDeviceEtes603 *self) +{ } -static void fpi_device_etes603_class_init(FpiDeviceEtes603Class *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); +static void +fpi_device_etes603_class_init (FpiDeviceEtes603Class *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); - dev_class->id = "etes603"; - dev_class->full_name = "EgisTec ES603"; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->id_table = id_table; - dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + dev_class->id = "etes603"; + dev_class->full_name = "EgisTec ES603"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - img_class->img_open = dev_open; - img_class->img_close = dev_close; - img_class->activate = dev_activate; - img_class->deactivate = dev_deactivate; + img_class->img_open = dev_open; + img_class->img_close = dev_close; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; - img_class->img_width = 256; - img_class->img_height = -1; + img_class->img_width = 256; + img_class->img_height = -1; } - diff --git a/libfprint/drivers/synaptics/bmkt.h b/libfprint/drivers/synaptics/bmkt.h index de7f875e..67c48f2e 100644 --- a/libfprint/drivers/synaptics/bmkt.h +++ b/libfprint/drivers/synaptics/bmkt.h @@ -21,107 +21,107 @@ #define _BMKT_H_ /**< User ID maximum length allowed */ -#define BMKT_MAX_USER_ID_LEN 100 +#define BMKT_MAX_USER_ID_LEN 100 /**< Software Part Number length */ -#define BMKT_PART_NUM_LEN 10 +#define BMKT_PART_NUM_LEN 10 /**< Software supplier identification length */ -#define BMKT_SUPPLIER_ID_LEN 2 +#define BMKT_SUPPLIER_ID_LEN 2 /**< Maximum namber of templates for storing in internal flash of the fingerprint sensor */ -#define BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH 15 +#define BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH 15 #include #include "bmkt_response.h" /*! -******************************************************************************* -** Type definition for result -*/ + ******************************************************************************* + ** Type definition for result + */ /** No error; Operation successfully completed. */ -#define BMKT_SUCCESS 0 +#define BMKT_SUCCESS 0 /** Fingerprint system not initialized */ -#define BMKT_FP_SYSTEM_NOT_INITIALIZED 101 +#define BMKT_FP_SYSTEM_NOT_INITIALIZED 101 /** Fingerprint system busy performing another operation */ -#define BMKT_FP_SYSTEM_BUSY 102 +#define BMKT_FP_SYSTEM_BUSY 102 /** Operation not allowed */ -#define BMKT_OPERATION_DENIED 103 +#define BMKT_OPERATION_DENIED 103 /** System ran out of memory while performing operation */ -#define BMKT_OUT_OF_MEMORY 104 +#define BMKT_OUT_OF_MEMORY 104 /** Corrupt message, CRC check fail or truncated message */ -#define BMKT_CORRUPT_MESSAGE 110 +#define BMKT_CORRUPT_MESSAGE 110 /** One of the command parameters is outside the range of valid values */ -#define BMKT_INVALID_PARAM 111 +#define BMKT_INVALID_PARAM 111 /** Unrecognized message or message with invalid message ID */ -#define BMKT_UNRECOGNIZED_MESSAGE 112 +#define BMKT_UNRECOGNIZED_MESSAGE 112 /** Operation time out */ -#define BMKT_OP_TIME_OUT 113 +#define BMKT_OP_TIME_OUT 113 /** General error – cause of error cannot be determined */ -#define BMKT_GENERAL_ERROR 114 +#define BMKT_GENERAL_ERROR 114 -#define BMKT_SET_SECURITY_LEVEL_FAIL 120 -#define BMKT_GET_SECURITY_LEVEL_FAIL 121 +#define BMKT_SET_SECURITY_LEVEL_FAIL 120 +#define BMKT_GET_SECURITY_LEVEL_FAIL 121 /** Fingerprint sensor reset while operation was being performed */ -#define BMKT_SENSOR_RESET 201 +#define BMKT_SENSOR_RESET 201 /** Fingerprint sensor malfunctioned */ -#define BMKT_SENSOR_MALFUNCTION 202 +#define BMKT_SENSOR_MALFUNCTION 202 /** Fingerprint sensor cannot be accessed despite repeated attempts */ -#define BMKT_SENSOR_TAMPERED 203 +#define BMKT_SENSOR_TAMPERED 203 /** -* BMKT_SENSOR_NOT_INIT: -* Fingerprint sensor module not initialized yet – not ready for use -* (different from error code 101 which indicates that the entire system -* has not been initialized) -*/ -#define BMKT_SENSOR_NOT_INIT 204 + * BMKT_SENSOR_NOT_INIT: + * Fingerprint sensor module not initialized yet – not ready for use + * (different from error code 101 which indicates that the entire system + * has not been initialized) + */ +#define BMKT_SENSOR_NOT_INIT 204 /** Number of re-pairing operations exceeded limit or re-pairing has been disabled */ -#define BMKT_OWNERSHIP_RESET_MAX_EXCEEDED 205 +#define BMKT_OWNERSHIP_RESET_MAX_EXCEEDED 205 /** -* BMKT_SENSOR_STIMULUS_ERROR: -* There is a finger or debris on the sensor that needs to be removed -* before issuing this command -*/ -#define BMKT_SENSOR_STIMULUS_ERROR 213 + * BMKT_SENSOR_STIMULUS_ERROR: + * There is a finger or debris on the sensor that needs to be removed + * before issuing this command + */ +#define BMKT_SENSOR_STIMULUS_ERROR 213 /** -* BMKT_CORRUPT_TEMPLATE_DATA: -* One of the fingerprint templates stored on flash is corrupt. -* This error code is returned in case of failure in finding a fingerprint match -* during identify or verify operations while also detecting that one or more -* fingerprint templates stored on the flash has become corrupted -*/ -#define BMKT_CORRUPT_TEMPLATE_DATA 300 + * BMKT_CORRUPT_TEMPLATE_DATA: + * One of the fingerprint templates stored on flash is corrupt. + * This error code is returned in case of failure in finding a fingerprint match + * during identify or verify operations while also detecting that one or more + * fingerprint templates stored on the flash has become corrupted + */ +#define BMKT_CORRUPT_TEMPLATE_DATA 300 /** Failed to extract features from fingerprint image acquired by sensor */ -#define BMKT_FEATURE_EXTRACT_FAIL 301 +#define BMKT_FEATURE_EXTRACT_FAIL 301 /** Failed to generate fingerprint template */ -#define BMKT_ENROLL_FAIL 302 +#define BMKT_ENROLL_FAIL 302 /** Specified finger already enrolled for this user */ -#define BMKT_ENROLLMENT_EXISTS 303 +#define BMKT_ENROLLMENT_EXISTS 303 /** Invalid fingerprint image */ -#define BMKT_INVALID_FP_IMAGE 304 +#define BMKT_INVALID_FP_IMAGE 304 /** No matching user fingerprint template found in database */ -#define BMKT_FP_NO_MATCH 404 +#define BMKT_FP_NO_MATCH 404 /** Fingerprint database is full */ -#define BMKT_FP_DATABASE_FULL 501 +#define BMKT_FP_DATABASE_FULL 501 /** Fingerprint database is empty */ -#define BMKT_FP_DATABASE_EMPTY 502 +#define BMKT_FP_DATABASE_EMPTY 502 /** Cannot access fingerprint database */ -#define BMKT_FP_DATABASE_ACCESS_FAIL 503 +#define BMKT_FP_DATABASE_ACCESS_FAIL 503 /** Fingerprint template record does not exist */ -#define BMKT_FP_DATABASE_NO_RECORD_EXISTS 504 +#define BMKT_FP_DATABASE_NO_RECORD_EXISTS 504 /** Failed to read/write system parameters stored on flash */ -#define BMKT_FP_PARAM_ACCESS_FAIL 505 +#define BMKT_FP_PARAM_ACCESS_FAIL 505 /** Fingerprint is a spoof */ -#define BMKT_FP_SPOOF_ALERT 801 +#define BMKT_FP_SPOOF_ALERT 801 /** Anti-spoof module failure */ -#define BMKT_ANTI_SPOOF_MODULE_FAIL 802 +#define BMKT_ANTI_SPOOF_MODULE_FAIL 802 -#define BMKT_CORRUPT_UPDATE_IMAGE 901 -#define BMKT_SYSTEM_UPDATE_FAIL 902 +#define BMKT_CORRUPT_UPDATE_IMAGE 901 +#define BMKT_SYSTEM_UPDATE_FAIL 902 -#define BMKT_EVENT_NOT_SET 1000 -#define BMKT_SENSOR_NOT_READY 1001 -#define BMKT_TIMEOUT 1002 -#define BMKT_SENSOR_RESPONSE_PENDING 1003 +#define BMKT_EVENT_NOT_SET 1000 +#define BMKT_SENSOR_NOT_READY 1001 +#define BMKT_TIMEOUT 1002 +#define BMKT_SENSOR_RESPONSE_PENDING 1003 #ifdef __cplusplus @@ -129,104 +129,100 @@ extern "C" { #endif /** -* bmkt_mode: -* Fingerprint system operational mode values level 1 -*/ -typedef enum bmkt_mode -{ - BMKT_STATE_UNINIT = 0xFF, - BMKT_STATE_IDLE = 0x00, - BMKT_STATE_ENROLL = 0x10, - BMKT_STATE_IDENTIFY = 0x20, - BMKT_STATE_VERIFY = 0x30, - BMKT_STATE_DB_OPS = 0x40, - BMKT_STATE_SYS_TEST = 0x50, - BMKT_STATE_SYS_OPS = 0x60, + * bmkt_mode: + * Fingerprint system operational mode values level 1 + */ +typedef enum bmkt_mode { + BMKT_STATE_UNINIT = 0xFF, + BMKT_STATE_IDLE = 0x00, + BMKT_STATE_ENROLL = 0x10, + BMKT_STATE_IDENTIFY = 0x20, + BMKT_STATE_VERIFY = 0x30, + BMKT_STATE_DB_OPS = 0x40, + BMKT_STATE_SYS_TEST = 0x50, + BMKT_STATE_SYS_OPS = 0x60, } bmkt_mode_t; /** -* bmkt_mode_level2: -* Fingerprint system operational mode values level 2 -*/ -typedef enum bmkt_mode_level2 -{ - BMKT_STATE_L2_IDLE = 0x00, - BMKT_STATE_L2_STARTING = 0x11, - BMKT_STATE_L2_WAITING_FOR_FINGER = 0x12, - BMKT_STATE_L2_CAPTURE_IMAGE = 0x13, - BMKT_STATE_L2_CAPTURE_COMPLETE = 0x14, - BMKT_STATE_L2_EXTRACT_FEATURE = 0x15, - BMKT_STATE_L2_CREATE_TEMPLATE = 0x16, - BMKT_STATE_L2_READING_FROM_FLASH = 0x17, - BMKT_STATE_L2_WRITING_TO_FLASH = 0x18, - BMKT_STATE_L2_FINISHING = 0x19, - BMKT_STATE_L2_CANCELING_OP = 0x20, - BMKT_STATE_L2_MATCHING = 0x21, - BMKT_STATE_L2_TRANSMITTING_RESPONSE = 0x22, - BMKT_STATE_L2_READY_POWER_DOWN = 0xF0, + * bmkt_mode_level2: + * Fingerprint system operational mode values level 2 + */ +typedef enum bmkt_mode_level2 { + BMKT_STATE_L2_IDLE = 0x00, + BMKT_STATE_L2_STARTING = 0x11, + BMKT_STATE_L2_WAITING_FOR_FINGER = 0x12, + BMKT_STATE_L2_CAPTURE_IMAGE = 0x13, + BMKT_STATE_L2_CAPTURE_COMPLETE = 0x14, + BMKT_STATE_L2_EXTRACT_FEATURE = 0x15, + BMKT_STATE_L2_CREATE_TEMPLATE = 0x16, + BMKT_STATE_L2_READING_FROM_FLASH = 0x17, + BMKT_STATE_L2_WRITING_TO_FLASH = 0x18, + BMKT_STATE_L2_FINISHING = 0x19, + BMKT_STATE_L2_CANCELING_OP = 0x20, + BMKT_STATE_L2_MATCHING = 0x21, + BMKT_STATE_L2_TRANSMITTING_RESPONSE = 0x22, + BMKT_STATE_L2_READY_POWER_DOWN = 0xF0, } bmkt_mode_level2_t; /** -* bmkt_transport_type: -* Fingerprint system transport types -*/ -typedef enum bmkt_transport_type -{ - BMKT_TRANSPORT_TYPE_USB = 0, + * bmkt_transport_type: + * Fingerprint system transport types + */ +typedef enum bmkt_transport_type { + BMKT_TRANSPORT_TYPE_USB = 0, } bmkt_transport_type_t; /** -* bmkt_usb_config: -* Structure represcontainingenting USB configuration details -*/ + * bmkt_usb_config: + * Structure represcontainingenting USB configuration details + */ typedef struct bmkt_usb_config { - int product_id; /**< USB device product ID */ + int product_id; /**< USB device product ID */ } bmkt_usb_config_t; /** -* bmkt_transport_config_t: -* Union containing transport configuration details -*/ + * bmkt_transport_config_t: + * Union containing transport configuration details + */ typedef union { - bmkt_usb_config_t usb_config; + bmkt_usb_config_t usb_config; } bmkt_transport_config_t; /** -* bmkt_sensor_desc_t: -* Structure containing fingerprint system description -*/ + * bmkt_sensor_desc_t: + * Structure containing fingerprint system description + */ typedef struct bmkt_sensor_desc { - int product_id; - int flags; + int product_id; + int flags; } bmkt_sensor_desc_t; /** -* bmkt_finger_state_t: -* Finger state representation values. -*/ -typedef enum -{ - BMKT_FINGER_STATE_UNKNOWN = 0, - BMKT_FINGER_STATE_ON_SENSOR, - BMKT_FINGER_STATE_NOT_ON_SENSOR, + * bmkt_finger_state_t: + * Finger state representation values. + */ +typedef enum { + BMKT_FINGER_STATE_UNKNOWN = 0, + BMKT_FINGER_STATE_ON_SENSOR, + BMKT_FINGER_STATE_NOT_ON_SENSOR, } bmkt_finger_state_t; /** -* bmkt_finger_event_t: -* Structure containing finger state -*/ + * bmkt_finger_event_t: + * Structure containing finger state + */ typedef struct bmkt_finger_event { - bmkt_finger_state_t finger_state; + bmkt_finger_state_t finger_state; } bmkt_finger_event_t; typedef struct bmkt_user_id { - uint8_t user_id_len; - uint8_t user_id[BMKT_MAX_USER_ID_LEN]; + uint8_t user_id_len; + uint8_t user_id[BMKT_MAX_USER_ID_LEN]; } bmkt_user_id_t; #ifdef __cplusplus diff --git a/libfprint/drivers/synaptics/bmkt_message.c b/libfprint/drivers/synaptics/bmkt_message.c index 78dec262..59bd62c1 100644 --- a/libfprint/drivers/synaptics/bmkt_message.c +++ b/libfprint/drivers/synaptics/bmkt_message.c @@ -20,395 +20,381 @@ #include "bmkt_response.h" #include "bmkt_message.h" -static uint8_t extract8(const uint8_t *buf, int *offset) +static uint8_t +extract8 (const uint8_t *buf, int *offset) { - uint8_t ret = 0; - int off = 0; - if (offset) - off = *offset; + uint8_t ret = 0; + int off = 0; - ret = *(buf + off); + if (offset) + off = *offset; - if (offset) - *offset += 1; + ret = *(buf + off); - return ret; + if (offset) + *offset += 1; + + return ret; } -static int parse_error_response(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +static int +parse_error_response (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) { - if (msg_resp->payload_len != 2) - { - return BMKT_UNRECOGNIZED_MESSAGE; - } + if (msg_resp->payload_len != 2) + return BMKT_UNRECOGNIZED_MESSAGE; - resp->result = (msg_resp->payload[0] << 8) | msg_resp->payload[1]; + resp->result = (msg_resp->payload[0] << 8) | msg_resp->payload[1]; - return BMKT_SUCCESS; + return BMKT_SUCCESS; } -static int parse_init_ok(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +static int +parse_init_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) { - bmkt_init_resp_t *init_resp = &resp->response.init_resp; + bmkt_init_resp_t *init_resp = &resp->response.init_resp; - if (msg_resp->payload_len != 1) - { - return BMKT_UNRECOGNIZED_MESSAGE; - } + if (msg_resp->payload_len != 1) + return BMKT_UNRECOGNIZED_MESSAGE; - init_resp->finger_presence = extract8(msg_resp->payload, NULL); + init_resp->finger_presence = extract8 (msg_resp->payload, NULL); - return BMKT_SUCCESS; + return BMKT_SUCCESS; } -static int parse_fps_mode_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +static int +parse_fps_mode_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) { - int offset = 0; - bmkt_fps_mode_resp_t *fps_mode_resp = &resp->response.fps_mode_resp; + int offset = 0; + bmkt_fps_mode_resp_t *fps_mode_resp = &resp->response.fps_mode_resp; - if (msg_resp->payload_len != sizeof(bmkt_fps_mode_resp_t)) - { - return BMKT_UNRECOGNIZED_MESSAGE; - } + if (msg_resp->payload_len != sizeof (bmkt_fps_mode_resp_t)) + return BMKT_UNRECOGNIZED_MESSAGE; - fps_mode_resp->mode = extract8(msg_resp->payload, &offset); - fps_mode_resp->level2_mode = extract8(msg_resp->payload, &offset); - fps_mode_resp->cmd_id = extract8(msg_resp->payload, &offset); - fps_mode_resp->finger_presence = extract8(msg_resp->payload, &offset); + fps_mode_resp->mode = extract8 (msg_resp->payload, &offset); + fps_mode_resp->level2_mode = extract8 (msg_resp->payload, &offset); + fps_mode_resp->cmd_id = extract8 (msg_resp->payload, &offset); + fps_mode_resp->finger_presence = extract8 (msg_resp->payload, &offset); - return BMKT_SUCCESS; + return BMKT_SUCCESS; } -static int parse_enroll_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +static int +parse_enroll_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) { - bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp; + bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp; - if (msg_resp->payload_len != 1) - { - return BMKT_UNRECOGNIZED_MESSAGE; - } + if (msg_resp->payload_len != 1) + return BMKT_UNRECOGNIZED_MESSAGE; - enroll_resp->progress = extract8(msg_resp->payload, NULL); + enroll_resp->progress = extract8 (msg_resp->payload, NULL); - return BMKT_SUCCESS; + return BMKT_SUCCESS; } -static int parse_enroll_ok(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +static int +parse_enroll_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) { - bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp; + bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp; - if (msg_resp->payload_len < 1 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 1)) - { - return BMKT_UNRECOGNIZED_MESSAGE; - } + if (msg_resp->payload_len < 1 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 1)) + return BMKT_UNRECOGNIZED_MESSAGE; - enroll_resp->finger_id = msg_resp->payload[0]; - memcpy(enroll_resp->user_id, &msg_resp->payload[1], msg_resp->payload_len - 1); + enroll_resp->finger_id = msg_resp->payload[0]; + memcpy (enroll_resp->user_id, &msg_resp->payload[1], msg_resp->payload_len - 1); - return BMKT_SUCCESS; + return BMKT_SUCCESS; } -static int parse_auth_ok(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +static int +parse_auth_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) { - bmkt_identify_resp_t *id_resp = &resp->response.id_resp; + bmkt_identify_resp_t *id_resp = &resp->response.id_resp; - if (msg_resp->payload_len < 3 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 3)) - { - return BMKT_UNRECOGNIZED_MESSAGE; - } + if (msg_resp->payload_len < 3 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 3)) + return BMKT_UNRECOGNIZED_MESSAGE; - id_resp->match_result = (double)msg_resp->payload[0] + 0.01 * (double)msg_resp->payload[1]; - id_resp->finger_id = msg_resp->payload[2]; - memcpy(id_resp->user_id, &msg_resp->payload[3], msg_resp->payload_len - 3); + id_resp->match_result = (double) msg_resp->payload[0] + 0.01 * (double) msg_resp->payload[1]; + id_resp->finger_id = msg_resp->payload[2]; + memcpy (id_resp->user_id, &msg_resp->payload[3], msg_resp->payload_len - 3); - return BMKT_SUCCESS; + return BMKT_SUCCESS; } -static int parse_security_level_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +static int +parse_security_level_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) { - bmkt_set_sec_level_resp_t *sec_level_resp = &resp->response.sec_level_resp; + bmkt_set_sec_level_resp_t *sec_level_resp = &resp->response.sec_level_resp; - if (msg_resp->payload_len != 1) - { - return BMKT_UNRECOGNIZED_MESSAGE; - } + if (msg_resp->payload_len != 1) + return BMKT_UNRECOGNIZED_MESSAGE; - sec_level_resp->sec_level = extract8(msg_resp->payload, NULL); + sec_level_resp->sec_level = extract8 (msg_resp->payload, NULL); - return BMKT_SUCCESS; + return BMKT_SUCCESS; } -static int parse_del_all_users_progress_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +static int +parse_del_all_users_progress_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) { - bmkt_del_all_users_resp_t *del_all_users_resp = &resp->response.del_all_users_resp; + bmkt_del_all_users_resp_t *del_all_users_resp = &resp->response.del_all_users_resp; - if (msg_resp->payload_len != 1) - { - return BMKT_UNRECOGNIZED_MESSAGE; - } + if (msg_resp->payload_len != 1) + return BMKT_UNRECOGNIZED_MESSAGE; - del_all_users_resp->progress = extract8(msg_resp->payload, NULL); + del_all_users_resp->progress = extract8 (msg_resp->payload, NULL); - return BMKT_SUCCESS; + return BMKT_SUCCESS; } -static int parse_db_cap_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +static int +parse_db_cap_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) { - bmkt_get_db_capacity_resp_t *db_cap_resp = &resp->response.db_cap_resp; - int offset = 0; + bmkt_get_db_capacity_resp_t *db_cap_resp = &resp->response.db_cap_resp; + int offset = 0; - if (msg_resp->payload_len < 2 || msg_resp->payload_len > 4) - { - return BMKT_UNRECOGNIZED_MESSAGE; - } + if (msg_resp->payload_len < 2 || msg_resp->payload_len > 4) + return BMKT_UNRECOGNIZED_MESSAGE; - db_cap_resp->total = extract8(msg_resp->payload, &offset); - db_cap_resp->empty = extract8(msg_resp->payload, &offset); + db_cap_resp->total = extract8 (msg_resp->payload, &offset); + db_cap_resp->empty = extract8 (msg_resp->payload, &offset); - if (msg_resp->payload_len == 4) - { - db_cap_resp->bad_slots = extract8(msg_resp->payload, &offset); - db_cap_resp->corrupt_templates = extract8(msg_resp->payload, &offset); - } + if (msg_resp->payload_len == 4) + { + db_cap_resp->bad_slots = extract8 (msg_resp->payload, &offset); + db_cap_resp->corrupt_templates = extract8 (msg_resp->payload, &offset); + } - return BMKT_SUCCESS; + return BMKT_SUCCESS; } -static int parse_get_enrolled_fingers_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +static int +parse_get_enrolled_fingers_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) { - int offset = 0; - int i = 0; + int offset = 0; + int i = 0; - if (msg_resp->payload_len < 2) - { - return BMKT_UNRECOGNIZED_MESSAGE; - } - /* 2 bytes per finger so calculate the total number of fingers to process*/ - int num_fingers = (msg_resp->payload_len) / 2; + if (msg_resp->payload_len < 2) + return BMKT_UNRECOGNIZED_MESSAGE; + /* 2 bytes per finger so calculate the total number of fingers to process*/ + int num_fingers = (msg_resp->payload_len) / 2; - bmkt_enrolled_fingers_resp_t *get_enrolled_fingers_resp = &resp->response.enrolled_fingers_resp; + bmkt_enrolled_fingers_resp_t *get_enrolled_fingers_resp = &resp->response.enrolled_fingers_resp; - for (i = 0; i < num_fingers; i++) - { - get_enrolled_fingers_resp->fingers[i].finger_id = extract8(msg_resp->payload, &offset); - get_enrolled_fingers_resp->fingers[i].template_status = extract8(msg_resp->payload, &offset); + for (i = 0; i < num_fingers; i++) + { + get_enrolled_fingers_resp->fingers[i].finger_id = extract8 (msg_resp->payload, &offset); + get_enrolled_fingers_resp->fingers[i].template_status = extract8 (msg_resp->payload, &offset); - } - return BMKT_SUCCESS; + } + return BMKT_SUCCESS; } -static int parse_get_enrolled_users_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +static int +parse_get_enrolled_users_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) { - int offset = 0; - int i = 0; + int offset = 0; + int i = 0; - /* the payload is 2 bytes + template data */ - if (msg_resp->payload_len < 2) - { - return BMKT_UNRECOGNIZED_MESSAGE; - } + /* the payload is 2 bytes + template data */ + if (msg_resp->payload_len < 2) + return BMKT_UNRECOGNIZED_MESSAGE; - bmkt_enroll_templates_resp_t *get_enroll_templates_resp = &resp->response.enroll_templates_resp; + bmkt_enroll_templates_resp_t *get_enroll_templates_resp = &resp->response.enroll_templates_resp; - get_enroll_templates_resp->total_query_messages = extract8(msg_resp->payload, &offset); - get_enroll_templates_resp->query_sequence = extract8(msg_resp->payload, &offset); + get_enroll_templates_resp->total_query_messages = extract8 (msg_resp->payload, &offset); + get_enroll_templates_resp->query_sequence = extract8 (msg_resp->payload, &offset); - int n = 0; - for (n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++) - { - if (offset >= msg_resp->payload_len) - break; - get_enroll_templates_resp->templates[n].user_id_len = extract8(msg_resp->payload, &offset) - 2; - if(get_enroll_templates_resp->templates[n].user_id_len > BMKT_MAX_USER_ID_LEN) - { - return BMKT_UNRECOGNIZED_MESSAGE; - } - get_enroll_templates_resp->templates[n].template_status = extract8(msg_resp->payload, &offset); - get_enroll_templates_resp->templates[n].finger_id = extract8(msg_resp->payload, &offset); - for (i = 0; i < get_enroll_templates_resp->templates[n].user_id_len; i++) - { - get_enroll_templates_resp->templates[n].user_id[i] = extract8(msg_resp->payload, &offset); - } - get_enroll_templates_resp->templates[n].user_id[i] = '\0'; - } + int n = 0; + for (n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++) + { + if (offset >= msg_resp->payload_len) + break; + get_enroll_templates_resp->templates[n].user_id_len = extract8 (msg_resp->payload, &offset) - 2; + if(get_enroll_templates_resp->templates[n].user_id_len > BMKT_MAX_USER_ID_LEN) + return BMKT_UNRECOGNIZED_MESSAGE; + get_enroll_templates_resp->templates[n].template_status = extract8 (msg_resp->payload, &offset); + get_enroll_templates_resp->templates[n].finger_id = extract8 (msg_resp->payload, &offset); + for (i = 0; i < get_enroll_templates_resp->templates[n].user_id_len; i++) + get_enroll_templates_resp->templates[n].user_id[i] = extract8 (msg_resp->payload, &offset); + get_enroll_templates_resp->templates[n].user_id[i] = '\0'; + } - return BMKT_SUCCESS; + return BMKT_SUCCESS; } -static int parse_get_version_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +static int +parse_get_version_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) { - bmkt_get_version_resp_t *get_version_resp = &resp->response.get_version_resp; - int offset = 0; + bmkt_get_version_resp_t *get_version_resp = &resp->response.get_version_resp; + int offset = 0; - if (msg_resp->payload_len != 15) - { - return BMKT_UNRECOGNIZED_MESSAGE; - } + if (msg_resp->payload_len != 15) + return BMKT_UNRECOGNIZED_MESSAGE; - memcpy(get_version_resp->part, msg_resp->payload, BMKT_PART_NUM_LEN); - offset += BMKT_PART_NUM_LEN; - get_version_resp->year = extract8(msg_resp->payload, &offset); - get_version_resp->week = extract8(msg_resp->payload, &offset); - get_version_resp->patch = extract8(msg_resp->payload, &offset); - memcpy(get_version_resp->supplier_id, msg_resp->payload + offset, BMKT_SUPPLIER_ID_LEN); + memcpy (get_version_resp->part, msg_resp->payload, BMKT_PART_NUM_LEN); + offset += BMKT_PART_NUM_LEN; + get_version_resp->year = extract8 (msg_resp->payload, &offset); + get_version_resp->week = extract8 (msg_resp->payload, &offset); + get_version_resp->patch = extract8 (msg_resp->payload, &offset); + memcpy (get_version_resp->supplier_id, msg_resp->payload + offset, BMKT_SUPPLIER_ID_LEN); - return BMKT_SUCCESS; + return BMKT_SUCCESS; } -int bmkt_compose_message(uint8_t *cmd, int *cmd_len, uint8_t msg_id, uint8_t seq_num, - uint8_t payload_size, const uint8_t *payload) +int +bmkt_compose_message (uint8_t *cmd, int *cmd_len, uint8_t msg_id, uint8_t seq_num, + uint8_t payload_size, const uint8_t *payload) { - int message_len = BMKT_MESSAGE_HEADER_LEN + payload_size; + int message_len = BMKT_MESSAGE_HEADER_LEN + payload_size; - if (*cmd_len < message_len) - { - return BMKT_OUT_OF_MEMORY; - } + if (*cmd_len < message_len) + return BMKT_OUT_OF_MEMORY; - cmd[BMKT_MESSAGE_HEADER_ID_FIELD] = BMKT_MESSAGE_HEADER_ID; - cmd[BMKT_MESSAGE_SEQ_NUM_FIELD] = seq_num; - cmd[BMKT_MESSAGE_ID_FIELD] = msg_id; - cmd[BMKT_MESSAGE_PAYLOAD_LEN_FIELD] = payload_size; - memcpy(&cmd[BMKT_MESSAGE_PAYLOAD_FIELD], payload, payload_size); + cmd[BMKT_MESSAGE_HEADER_ID_FIELD] = BMKT_MESSAGE_HEADER_ID; + cmd[BMKT_MESSAGE_SEQ_NUM_FIELD] = seq_num; + cmd[BMKT_MESSAGE_ID_FIELD] = msg_id; + cmd[BMKT_MESSAGE_PAYLOAD_LEN_FIELD] = payload_size; + memcpy (&cmd[BMKT_MESSAGE_PAYLOAD_FIELD], payload, payload_size); - *cmd_len = message_len; + *cmd_len = message_len; - return BMKT_SUCCESS; + return BMKT_SUCCESS; } -int bmkt_parse_message_header(uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp) +int +bmkt_parse_message_header (uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp) { - if (resp_buf[BMKT_MESSAGE_HEADER_ID_FIELD] != BMKT_MESSAGE_HEADER_ID) - { - return BMKT_CORRUPT_MESSAGE; - } + if (resp_buf[BMKT_MESSAGE_HEADER_ID_FIELD] != BMKT_MESSAGE_HEADER_ID) + return BMKT_CORRUPT_MESSAGE; - msg_resp->seq_num = resp_buf[BMKT_MESSAGE_SEQ_NUM_FIELD]; - msg_resp->msg_id = resp_buf[BMKT_MESSAGE_ID_FIELD]; - msg_resp->payload_len = resp_buf[BMKT_MESSAGE_PAYLOAD_LEN_FIELD]; - if (msg_resp->payload_len > 0) - { - msg_resp->payload = &resp_buf[BMKT_MESSAGE_PAYLOAD_FIELD]; - } - else - { - msg_resp->payload = NULL; - } + msg_resp->seq_num = resp_buf[BMKT_MESSAGE_SEQ_NUM_FIELD]; + msg_resp->msg_id = resp_buf[BMKT_MESSAGE_ID_FIELD]; + msg_resp->payload_len = resp_buf[BMKT_MESSAGE_PAYLOAD_LEN_FIELD]; + if (msg_resp->payload_len > 0) + msg_resp->payload = &resp_buf[BMKT_MESSAGE_PAYLOAD_FIELD]; + else + msg_resp->payload = NULL; - return BMKT_SUCCESS; + return BMKT_SUCCESS; } -int bmkt_parse_message_payload(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +int +bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) { - int ret = BMKT_SUCCESS; + int ret = BMKT_SUCCESS; - memset(resp, 0, sizeof(bmkt_response_t)); + memset (resp, 0, sizeof (bmkt_response_t)); - resp->response_id = msg_resp->msg_id; + resp->response_id = msg_resp->msg_id; - switch(msg_resp->msg_id) - { - case BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_FAIL: - case BMKT_RSP_SENSOR_MODULE_TEST_FAIL: - case BMKT_RSP_FPS_INIT_FAIL: - case BMKT_RSP_FPS_MODE_FAIL: - case BMKT_RSP_SET_SECURITY_LEVEL_FAIL: - case BMKT_RSP_GET_SECURITY_LEVEL_FAIL: - case BMKT_RSP_CANCEL_OP_FAIL: - case BMKT_RSP_ENROLL_FAIL: - case BMKT_RSP_ID_FAIL: - case BMKT_RSP_VERIFY_FAIL: - case BMKT_RSP_QUERY_FAIL: - case BMKT_RSP_DEL_USER_FP_FAIL: - case BMKT_RSP_DEL_FULL_DB_FAIL: - case BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL: - case BMKT_RSP_POWER_DOWN_FAIL: - case BMKT_RSP_GET_VERSION_FAIL: - case BMKT_RSP_DISABLE_PAIRING_FAIL: - case BMKT_RSP_QUERY_PAIRING_FAIL: - case BMKT_RSP_SENSOR_STATUS_FAIL: - case BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL: - ret = parse_error_response(msg_resp, resp); - resp->complete = 1; - break; + switch(msg_resp->msg_id) + { + case BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_FAIL: + case BMKT_RSP_SENSOR_MODULE_TEST_FAIL: + case BMKT_RSP_FPS_INIT_FAIL: + case BMKT_RSP_FPS_MODE_FAIL: + case BMKT_RSP_SET_SECURITY_LEVEL_FAIL: + case BMKT_RSP_GET_SECURITY_LEVEL_FAIL: + case BMKT_RSP_CANCEL_OP_FAIL: + case BMKT_RSP_ENROLL_FAIL: + case BMKT_RSP_ID_FAIL: + case BMKT_RSP_VERIFY_FAIL: + case BMKT_RSP_QUERY_FAIL: + case BMKT_RSP_DEL_USER_FP_FAIL: + case BMKT_RSP_DEL_FULL_DB_FAIL: + case BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL: + case BMKT_RSP_POWER_DOWN_FAIL: + case BMKT_RSP_GET_VERSION_FAIL: + case BMKT_RSP_DISABLE_PAIRING_FAIL: + case BMKT_RSP_QUERY_PAIRING_FAIL: + case BMKT_RSP_SENSOR_STATUS_FAIL: + case BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL: + ret = parse_error_response (msg_resp, resp); + resp->complete = 1; + break; - case BMKT_RSP_FPS_INIT_OK: - ret = parse_init_ok(msg_resp, resp); - resp->complete = 1; - break; + case BMKT_RSP_FPS_INIT_OK: + ret = parse_init_ok (msg_resp, resp); + resp->complete = 1; + break; - case BMKT_RSP_CANCEL_OP_OK: - case BMKT_RSP_DEL_FULL_DB_OK: - case BMKT_RSP_DEL_USER_FP_OK: - /* responses with a payload of 0 - so the response indicates success */ - resp->result = BMKT_SUCCESS; - resp->complete = 1; - break; + case BMKT_RSP_CANCEL_OP_OK: + case BMKT_RSP_DEL_FULL_DB_OK: + case BMKT_RSP_DEL_USER_FP_OK: + /* responses with a payload of 0 + so the response indicates success */ + resp->result = BMKT_SUCCESS; + resp->complete = 1; + break; - case BMKT_RSP_FPS_MODE_REPORT: - // parse_fps_mode - ret = parse_fps_mode_report(msg_resp, resp); - resp->complete = 1; - break; + case BMKT_RSP_FPS_MODE_REPORT: + // parse_fps_mode + ret = parse_fps_mode_report (msg_resp, resp); + resp->complete = 1; + break; - case BMKT_RSP_GET_SECURITY_LEVEL_REPORT: - case BMKT_RSP_SET_SECURITY_LEVEL_REPORT: - /* parse security level result */ - ret = parse_security_level_report(msg_resp, resp); - resp->complete = 1; - break; + case BMKT_RSP_GET_SECURITY_LEVEL_REPORT: + case BMKT_RSP_SET_SECURITY_LEVEL_REPORT: + /* parse security level result */ + ret = parse_security_level_report (msg_resp, resp); + resp->complete = 1; + break; - case BMKT_RSP_DELETE_PROGRESS: - ret = parse_del_all_users_progress_report(msg_resp, resp); - break; + case BMKT_RSP_DELETE_PROGRESS: + ret = parse_del_all_users_progress_report (msg_resp, resp); + break; - case BMKT_RSP_CAPTURE_COMPLETE: - resp->result = BMKT_SUCCESS; - break; + case BMKT_RSP_CAPTURE_COMPLETE: + resp->result = BMKT_SUCCESS; + break; - case BMKT_RSP_ENROLL_READY: - resp->result = BMKT_SUCCESS; - break; + case BMKT_RSP_ENROLL_READY: + resp->result = BMKT_SUCCESS; + break; - case BMKT_RSP_ENROLL_REPORT: - ret = parse_enroll_report(msg_resp, resp); - break; + case BMKT_RSP_ENROLL_REPORT: + ret = parse_enroll_report (msg_resp, resp); + break; - case BMKT_RSP_ENROLL_OK: - resp->complete = 1; - ret = parse_enroll_ok(msg_resp, resp); - break; + case BMKT_RSP_ENROLL_OK: + resp->complete = 1; + ret = parse_enroll_ok (msg_resp, resp); + break; - case BMKT_RSP_ID_OK: - case BMKT_RSP_VERIFY_OK: - ret = parse_auth_ok(msg_resp, resp); - resp->complete = 1; - break; - case BMKT_RSP_GET_ENROLLED_FINGERS_REPORT: - ret = parse_get_enrolled_fingers_report(msg_resp, resp); - resp->complete = 1; - break; - case BMKT_RSP_DATABASE_CAPACITY_REPORT: - resp->complete = 1; - ret = parse_db_cap_report(msg_resp, resp); - break; - case BMKT_RSP_TEMPLATE_RECORDS_REPORT: - ret = parse_get_enrolled_users_report(msg_resp, resp); - break; - case BMKT_RSP_QUERY_RESPONSE_COMPLETE: - resp->complete = 1; - break; + case BMKT_RSP_ID_OK: + case BMKT_RSP_VERIFY_OK: + ret = parse_auth_ok (msg_resp, resp); + resp->complete = 1; + break; - case BMKT_RSP_VERSION_INFO: - ret = parse_get_version_report(msg_resp, resp); - resp->complete = 1; - break; - case BMKT_RSP_POWER_DOWN_READY: - resp->complete = 1; - break; - } + case BMKT_RSP_GET_ENROLLED_FINGERS_REPORT: + ret = parse_get_enrolled_fingers_report (msg_resp, resp); + resp->complete = 1; + break; - return ret; + case BMKT_RSP_DATABASE_CAPACITY_REPORT: + resp->complete = 1; + ret = parse_db_cap_report (msg_resp, resp); + break; + + case BMKT_RSP_TEMPLATE_RECORDS_REPORT: + ret = parse_get_enrolled_users_report (msg_resp, resp); + break; + + case BMKT_RSP_QUERY_RESPONSE_COMPLETE: + resp->complete = 1; + break; + + case BMKT_RSP_VERSION_INFO: + ret = parse_get_version_report (msg_resp, resp); + resp->complete = 1; + break; + + case BMKT_RSP_POWER_DOWN_READY: + resp->complete = 1; + break; + } + + return ret; } diff --git a/libfprint/drivers/synaptics/bmkt_message.h b/libfprint/drivers/synaptics/bmkt_message.h index 9366771e..d41e3d2f 100644 --- a/libfprint/drivers/synaptics/bmkt_message.h +++ b/libfprint/drivers/synaptics/bmkt_message.h @@ -21,66 +21,73 @@ #define BMKT_MESSAGE_H_ -#define BMKT_MESSAGE_HEADER_ID 0xFE -#define BMKT_MESSAGE_HEADER_LEN (4) -#define BMKT_MESSAGE_CRC32_LEN (4) -#define BMKT_MESSAGE_HEADER_ID_FIELD 0 -#define BMKT_MESSAGE_SEQ_NUM_FIELD 1 -#define BMKT_MESSAGE_ID_FIELD 2 -#define BMKT_MESSAGE_PAYLOAD_LEN_FIELD 3 -#define BMKT_MESSAGE_PAYLOAD_FIELD 4 +#define BMKT_MESSAGE_HEADER_ID 0xFE +#define BMKT_MESSAGE_HEADER_LEN (4) +#define BMKT_MESSAGE_CRC32_LEN (4) +#define BMKT_MESSAGE_HEADER_ID_FIELD 0 +#define BMKT_MESSAGE_SEQ_NUM_FIELD 1 +#define BMKT_MESSAGE_ID_FIELD 2 +#define BMKT_MESSAGE_PAYLOAD_LEN_FIELD 3 +#define BMKT_MESSAGE_PAYLOAD_FIELD 4 // Command messages -#define BMKT_CMD_CONTINUOUS_IMAGE_CAPTURE 0x01 -#define BMKT_CMD_CONTINUOUS_IMAGE_CAPTURE_STOP 0x04 -#define BMKT_CMD_SENSOR_MODULE_TEST 0x06 -#define BMKT_CMD_SENSOR_MODULE_TEST_START 0x08 -#define BMKT_CMD_NEXT_TEST_REPORT_CHUNK 0x0B -#define BMKT_CMD_FPS_INIT 0x11 -#define BMKT_CMD_GET_FPS_MODE 0x21 -#define BMKT_CMD_SET_SECURITY_LEVEL 0x31 -#define BMKT_CMD_GET_SECURITY_LEVEL 0x34 -#define BMKT_CMD_CANCEL_OP 0x41 -#define BMKT_CMD_ENROLL_USER 0x51 -#define BMKT_CMD_ENROLL_PAUSE 0x52 -#define BMKT_CMD_ENROLL_RESUME 0x53 -#define BMKT_CMD_ID_USER 0x61 -#define BMKT_CMD_VERIFY_USER 0x65 -#define BMKT_CMD_GET_TEMPLATE_RECORDS 0x71 -#define BMKT_CMD_GET_NEXT_QUERY_RESPONSE 0x72 -#define BMKT_CMD_GET_ENROLLED_FINGERS 0x73 -#define BMKT_CMD_GET_DATABASE_CAPACITY 0x74 -#define BMKT_CMD_DEL_USER_FP 0x81 -#define BMKT_CMD_DEL_FULL_DB 0x84 -#define BMKT_CMD_REPEAT_LAST_RSP 0x92 -#define BMKT_CMD_POWER_DOWN_NOTIFY 0xA1 -#define BMKT_CMD_GET_VERSION 0xB1 -#define BMKT_CMD_DISABLE_PAIRING 0xC2 -#define BMKT_CMD_QUERY_PAIRING 0xC5 -#define BMKT_CMD_SENSOR_STATUS 0xD1 -#define BMKT_CMD_ID_USER_IN_ORDER 0xE1 -#define BMKT_CMD_ID_NEXT_USER 0xE3 -#define BMKT_CMD_VERIFY_USER_IN_ORDER 0xF1 -#define BMKT_CMD_VERIFY_FINGERS_IN_ORDER 0xF2 -#define BMKT_CMD_GET_FINAL_RESULT 0xE4 +#define BMKT_CMD_CONTINUOUS_IMAGE_CAPTURE 0x01 +#define BMKT_CMD_CONTINUOUS_IMAGE_CAPTURE_STOP 0x04 +#define BMKT_CMD_SENSOR_MODULE_TEST 0x06 +#define BMKT_CMD_SENSOR_MODULE_TEST_START 0x08 +#define BMKT_CMD_NEXT_TEST_REPORT_CHUNK 0x0B +#define BMKT_CMD_FPS_INIT 0x11 +#define BMKT_CMD_GET_FPS_MODE 0x21 +#define BMKT_CMD_SET_SECURITY_LEVEL 0x31 +#define BMKT_CMD_GET_SECURITY_LEVEL 0x34 +#define BMKT_CMD_CANCEL_OP 0x41 +#define BMKT_CMD_ENROLL_USER 0x51 +#define BMKT_CMD_ENROLL_PAUSE 0x52 +#define BMKT_CMD_ENROLL_RESUME 0x53 +#define BMKT_CMD_ID_USER 0x61 +#define BMKT_CMD_VERIFY_USER 0x65 +#define BMKT_CMD_GET_TEMPLATE_RECORDS 0x71 +#define BMKT_CMD_GET_NEXT_QUERY_RESPONSE 0x72 +#define BMKT_CMD_GET_ENROLLED_FINGERS 0x73 +#define BMKT_CMD_GET_DATABASE_CAPACITY 0x74 +#define BMKT_CMD_DEL_USER_FP 0x81 +#define BMKT_CMD_DEL_FULL_DB 0x84 +#define BMKT_CMD_REPEAT_LAST_RSP 0x92 +#define BMKT_CMD_POWER_DOWN_NOTIFY 0xA1 +#define BMKT_CMD_GET_VERSION 0xB1 +#define BMKT_CMD_DISABLE_PAIRING 0xC2 +#define BMKT_CMD_QUERY_PAIRING 0xC5 +#define BMKT_CMD_SENSOR_STATUS 0xD1 +#define BMKT_CMD_ID_USER_IN_ORDER 0xE1 +#define BMKT_CMD_ID_NEXT_USER 0xE3 +#define BMKT_CMD_VERIFY_USER_IN_ORDER 0xF1 +#define BMKT_CMD_VERIFY_FINGERS_IN_ORDER 0xF2 +#define BMKT_CMD_GET_FINAL_RESULT 0xE4 -#define BMKT_EVT_FINGER_REPORT 0x91 +#define BMKT_EVT_FINGER_REPORT 0x91 -#define BMKT_EVT_FINGER_STATE_NOT_ON_SENSOR 0x00 -#define BMKT_EVT_FINGER_STATE_ON_SENSOR 0x01 +#define BMKT_EVT_FINGER_STATE_NOT_ON_SENSOR 0x00 +#define BMKT_EVT_FINGER_STATE_ON_SENSOR 0x01 typedef struct bmkt_msg_resp { - uint8_t msg_id; - uint8_t seq_num; - uint8_t payload_len; - uint8_t *payload; - int result; + uint8_t msg_id; + uint8_t seq_num; + uint8_t payload_len; + uint8_t *payload; + int result; } bmkt_msg_resp_t; -int bmkt_compose_message(uint8_t *cmd, int *cmd_len, uint8_t msg_id, uint8_t seq_num, - uint8_t payload_size, const uint8_t *payload); +int bmkt_compose_message (uint8_t *cmd, + int *cmd_len, + uint8_t msg_id, + uint8_t seq_num, + uint8_t payload_size, + const uint8_t *payload); -int bmkt_parse_message_header(uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp); -int bmkt_parse_message_payload(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp); +int bmkt_parse_message_header (uint8_t *resp_buf, + int resp_len, + bmkt_msg_resp_t *msg_resp); +int bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp, + bmkt_response_t *resp); #endif /* BMKT_MESSAGE_H_ */ diff --git a/libfprint/drivers/synaptics/bmkt_response.h b/libfprint/drivers/synaptics/bmkt_response.h index 874bf972..cfd77033 100644 --- a/libfprint/drivers/synaptics/bmkt_response.h +++ b/libfprint/drivers/synaptics/bmkt_response.h @@ -24,466 +24,466 @@ #include "bmkt.h" /** List of response message IDs */ -#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_FAIL 0x02 -#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_READY 0x03 +#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_FAIL 0x02 +#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_READY 0x03 #define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_STOPPED 0x05 -#define BMKT_RSP_SENSOR_MODULE_TEST_READY 0x07 -#define BMKT_RSP_SENSOR_MODULE_TEST_FAIL 0x09 -#define BMKT_RSP_SENSOR_MODULE_TEST_REPORT 0x0A -#define BMKT_RSP_NEXT_TEST_REPORT_CHUNK 0x0C +#define BMKT_RSP_SENSOR_MODULE_TEST_READY 0x07 +#define BMKT_RSP_SENSOR_MODULE_TEST_FAIL 0x09 +#define BMKT_RSP_SENSOR_MODULE_TEST_REPORT 0x0A +#define BMKT_RSP_NEXT_TEST_REPORT_CHUNK 0x0C /*! \addtogroup init -* Response IDs returned by fingerprint initialization operation -* @{ -*/ + * Response IDs returned by fingerprint initialization operation + * @{ + */ /** Failed to initialize fingerprint sensor module */ -#define BMKT_RSP_FPS_INIT_FAIL 0x12 +#define BMKT_RSP_FPS_INIT_FAIL 0x12 /** Successfully initialized fingerprint sensor module */ -#define BMKT_RSP_FPS_INIT_OK 0x13 +#define BMKT_RSP_FPS_INIT_OK 0x13 /*! @} */ /*! \addtogroup mode -* Response IDs returned by get fingerprint mode operation -* @{ -*/ + * Response IDs returned by get fingerprint mode operation + * @{ + */ /** Failed to get fingerprint sensor module’s current operational mode */ -#define BMKT_RSP_FPS_MODE_FAIL 0x22 +#define BMKT_RSP_FPS_MODE_FAIL 0x22 /** -* BMKT_RSP_FPS_MODE_REPORT: -* Response containing the current operational mode of the fingerprint sensor module -*
Payload data represented in \ref bmkt_fps_mode_resp_t struct -*/ -#define BMKT_RSP_FPS_MODE_REPORT 0x23 + * BMKT_RSP_FPS_MODE_REPORT: + * Response containing the current operational mode of the fingerprint sensor module + *
Payload data represented in \ref bmkt_fps_mode_resp_t struct + */ +#define BMKT_RSP_FPS_MODE_REPORT 0x23 /*! @} */ /*! \addtogroup setseclevel -* Response IDs returned by set security level operation -* @{ -*/ + * Response IDs returned by set security level operation + * @{ + */ /** Failed to set fingerprint sensor module security level */ -#define BMKT_RSP_SET_SECURITY_LEVEL_FAIL 0x32 +#define BMKT_RSP_SET_SECURITY_LEVEL_FAIL 0x32 /** -* BMKT_RSP_SET_SECURITY_LEVEL_REPORT: -* Security level of the fingerprint sensor module was set successfully -*
Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct -*/ -#define BMKT_RSP_SET_SECURITY_LEVEL_REPORT 0x33 + * BMKT_RSP_SET_SECURITY_LEVEL_REPORT: + * Security level of the fingerprint sensor module was set successfully + *
Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct + */ +#define BMKT_RSP_SET_SECURITY_LEVEL_REPORT 0x33 /*! @} */ /*! \addtogroup getseclevel -* Response IDs returned by get security level operation -* @{ -*/ + * Response IDs returned by get security level operation + * @{ + */ /** Failed to get fingerprint sensor module security level */ -#define BMKT_RSP_GET_SECURITY_LEVEL_FAIL 0x35 +#define BMKT_RSP_GET_SECURITY_LEVEL_FAIL 0x35 /** -* BMKT_RSP_GET_SECURITY_LEVEL_REPORT: -* Returns the current security level of the fingerprint sensor module -*
Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct -*/ -#define BMKT_RSP_GET_SECURITY_LEVEL_REPORT 0x36 + * BMKT_RSP_GET_SECURITY_LEVEL_REPORT: + * Returns the current security level of the fingerprint sensor module + *
Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct + */ +#define BMKT_RSP_GET_SECURITY_LEVEL_REPORT 0x36 /*! @} */ /*! \addtogroup cancelop -* Response IDs returned by cancel_operation operation -* @{ -*/ + * Response IDs returned by cancel_operation operation + * @{ + */ /** -* BMKT_RSP_CANCEL_OP_OK: -* Successfully canceled the current operation and returned -* fingerprint sensor module to idle mode -*/ -#define BMKT_RSP_CANCEL_OP_OK 0x42 + * BMKT_RSP_CANCEL_OP_OK: + * Successfully canceled the current operation and returned + * fingerprint sensor module to idle mode + */ +#define BMKT_RSP_CANCEL_OP_OK 0x42 /** Failed to cancel the current operation */ -#define BMKT_RSP_CANCEL_OP_FAIL 0x43 +#define BMKT_RSP_CANCEL_OP_FAIL 0x43 /*! @} */ /*! \addtogroup enrollment -* Response IDs returned by enrollment operation -* @{ -*/ + * Response IDs returned by enrollment operation + * @{ + */ /** -* BMKT_RSP_ENROLL_READY: -* Fingerprint enrollment session has begun and the user can place -* their finger on the sensor -*/ -#define BMKT_RSP_ENROLL_READY 0x54 + * BMKT_RSP_ENROLL_READY: + * Fingerprint enrollment session has begun and the user can place + * their finger on the sensor + */ +#define BMKT_RSP_ENROLL_READY 0x54 /** Progress of the currently on-going fingerprint enrollment session */ -#define BMKT_RSP_ENROLL_REPORT 0x55 +#define BMKT_RSP_ENROLL_REPORT 0x55 /** Enrollment has been paused */ -#define BMKT_RSP_ENROLL_PAUSED 0x56 +#define BMKT_RSP_ENROLL_PAUSED 0x56 /** Enrollment has been resume */ -#define BMKT_RSP_ENROLL_RESUMED 0x57 +#define BMKT_RSP_ENROLL_RESUMED 0x57 /** The current enrollment session has encountered an error */ -#define BMKT_RSP_ENROLL_FAIL 0x58 +#define BMKT_RSP_ENROLL_FAIL 0x58 /** -* BMKT_RSP_ENROLL_OK: -* User has been successfully enrolled into the fingerprint sensor module -*
Contains payload data represented in \ref bmkt_enroll_resp_t struct -*/ -#define BMKT_RSP_ENROLL_OK 0x59 + * BMKT_RSP_ENROLL_OK: + * User has been successfully enrolled into the fingerprint sensor module + *
Contains payload data represented in \ref bmkt_enroll_resp_t struct + */ +#define BMKT_RSP_ENROLL_OK 0x59 /** -* BMKT_RSP_CAPTURE_COMPLETE: -* Fingerprint image capture is complete and it is safe for the user -* to lift their finger off the sensor -*/ -#define BMKT_RSP_CAPTURE_COMPLETE 0x60 + * BMKT_RSP_CAPTURE_COMPLETE: + * Fingerprint image capture is complete and it is safe for the user + * to lift their finger off the sensor + */ +#define BMKT_RSP_CAPTURE_COMPLETE 0x60 /*! @} */ /*! \addtogroup identify -* Response IDs returned by identify operation. -* @{ -*/ + * Response IDs returned by identify operation. + * @{ + */ /* Fingerprint identification session has begun */ -#define BMKT_RSP_ID_READY 0x62 +#define BMKT_RSP_ID_READY 0x62 /* Identification has failed */ -#define BMKT_RSP_ID_FAIL 0x63 +#define BMKT_RSP_ID_FAIL 0x63 /** -* BMKT_RSP_ID_OK: -* User has been successfully identified -*
Contains payload data represented in \ref bmkt_auth_resp struct -*/ -#define BMKT_RSP_ID_OK 0x64 + * BMKT_RSP_ID_OK: + * User has been successfully identified + *
Contains payload data represented in \ref bmkt_auth_resp struct + */ +#define BMKT_RSP_ID_OK 0x64 /*! @} */ /*! \addtogroup verify -* Response IDs returned by identify operation. -* @{ -*/ + * Response IDs returned by identify operation. + * @{ + */ /** Fingerprint verification session has begun */ -#define BMKT_RSP_VERIFY_READY 0x66 +#define BMKT_RSP_VERIFY_READY 0x66 /** Verification has failed */ -#define BMKT_RSP_VERIFY_FAIL 0x67 +#define BMKT_RSP_VERIFY_FAIL 0x67 /** -* BMKT_RSP_VERIFY_OK: -* User’s identity has been successfully verified -*
Contains payload data represented in \ref bmkt_auth_resp struct -*/ -#define BMKT_RSP_VERIFY_OK 0x68 + * BMKT_RSP_VERIFY_OK: + * User’s identity has been successfully verified + *
Contains payload data represented in \ref bmkt_auth_resp struct + */ +#define BMKT_RSP_VERIFY_OK 0x68 /*! @} */ /** -* BMKT_RSP_TEMPLATE_RECORDS_REPORT: -* Response ID returned by get enrolled users templates record operation -*
Returns list of template records containing user IDs and corresponding finger IDs -*
Payload data represented in \ref bmkt_enroll_templates_resp_t struct -*/ -#define BMKT_RSP_TEMPLATE_RECORDS_REPORT 0x75 + * BMKT_RSP_TEMPLATE_RECORDS_REPORT: + * Response ID returned by get enrolled users templates record operation + *
Returns list of template records containing user IDs and corresponding finger IDs + *
Payload data represented in \ref bmkt_enroll_templates_resp_t struct + */ +#define BMKT_RSP_TEMPLATE_RECORDS_REPORT 0x75 /** -* BMKT_RSP_QUERY_RESPONSE_COMPLETE: -* Response ID returned by get next query response operation -*
Complete sequence of messages containing the template records query response has been sent -*/ -#define BMKT_RSP_QUERY_RESPONSE_COMPLETE 0x76 + * BMKT_RSP_QUERY_RESPONSE_COMPLETE: + * Response ID returned by get next query response operation + *
Complete sequence of messages containing the template records query response has been sent + */ +#define BMKT_RSP_QUERY_RESPONSE_COMPLETE 0x76 /** -* BMKT_RSP_GET_ENROLLED_FINGERS_REPORT: -* Response ID returned by get enrolled fingers operation -*
Returns list of IDs of enrolled fingers for a specific user, -* along with template record status corresponding to each enrolled finger -*
Contains payload data represented in \ref bmkt_enrolled_fingers_resp_t struct -*/ -#define BMKT_RSP_GET_ENROLLED_FINGERS_REPORT 0x77 + * BMKT_RSP_GET_ENROLLED_FINGERS_REPORT: + * Response ID returned by get enrolled fingers operation + *
Returns list of IDs of enrolled fingers for a specific user, + * along with template record status corresponding to each enrolled finger + *
Contains payload data represented in \ref bmkt_enrolled_fingers_resp_t struct + */ +#define BMKT_RSP_GET_ENROLLED_FINGERS_REPORT 0x77 /*! \addtogroup dbcapacity -* Response IDs returned by get database capacity operation -* @{ -*/ + * Response IDs returned by get database capacity operation + * @{ + */ /** -* BMKT_RSP_DATABASE_CAPACITY_REPORT: -* Response specifying total capacity of fingerprint template database and -* how much free capacity is remaining along with how many templates are corrupted and -* how many bad (permanently unusable) storage slots are there. -*
Payload data represented in \ref bmkt_get_db_capacity_resp_t struct -*/ -#define BMKT_RSP_DATABASE_CAPACITY_REPORT 0x78 + * BMKT_RSP_DATABASE_CAPACITY_REPORT: + * Response specifying total capacity of fingerprint template database and + * how much free capacity is remaining along with how many templates are corrupted and + * how many bad (permanently unusable) storage slots are there. + *
Payload data represented in \ref bmkt_get_db_capacity_resp_t struct + */ +#define BMKT_RSP_DATABASE_CAPACITY_REPORT 0x78 /** Failed to execute database query */ -#define BMKT_RSP_QUERY_FAIL 0x79 +#define BMKT_RSP_QUERY_FAIL 0x79 /*! @} */ /*! \addtogroup deluser -* Response IDs returned by delete fingerprint of specific user operation -* @{ -*/ + * Response IDs returned by delete fingerprint of specific user operation + * @{ + */ /** Failed to delete a user’s fingerprint template from the database */ -#define BMKT_RSP_DEL_USER_FP_FAIL 0x82 +#define BMKT_RSP_DEL_USER_FP_FAIL 0x82 /** -* BMKT_RSP_DEL_USER_FP_OK: -* Fingerprint template successfully deleted from the database. -* Returns the user ID and finger ID deleted. If value of finger ID is set equal to 0, -* then all fingerprint templates for that user have been deleted from the database -*
Payload data represented in \ref bmkt_del_user_resp_t struct -*/ -#define BMKT_RSP_DEL_USER_FP_OK 0x83 + * BMKT_RSP_DEL_USER_FP_OK: + * Fingerprint template successfully deleted from the database. + * Returns the user ID and finger ID deleted. If value of finger ID is set equal to 0, + * then all fingerprint templates for that user have been deleted from the database + *
Payload data represented in \ref bmkt_del_user_resp_t struct + */ +#define BMKT_RSP_DEL_USER_FP_OK 0x83 /*! @} */ /*! \addtogroup delfulldb -* Response IDs returned by delete entire fingerprint template DB operation -* @{ -*/ + * Response IDs returned by delete entire fingerprint template DB operation + * @{ + */ /** Failed to erase entire fingerprint template database */ -#define BMKT_RSP_DEL_FULL_DB_FAIL 0x85 +#define BMKT_RSP_DEL_FULL_DB_FAIL 0x85 /** Successfully erased entire fingerprint template database */ -#define BMKT_RSP_DEL_FULL_DB_OK 0x86 +#define BMKT_RSP_DEL_FULL_DB_OK 0x86 /** -* BMKT_RSP_DELETE_PROGRESS: -* Notify progress made during the on-going deletion of the full template database -*
Payload data represented in \ref bmkt_del_all_users_resp_t struct -*/ -#define BMKT_RSP_DELETE_PROGRESS 0x87 + * BMKT_RSP_DELETE_PROGRESS: + * Notify progress made during the on-going deletion of the full template database + *
Payload data represented in \ref bmkt_del_all_users_resp_t struct + */ +#define BMKT_RSP_DELETE_PROGRESS 0x87 /*! @} */ /** -* BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL: -* Response ID returned by repeate last response operation -*
Failed to retrieve and re-send last response -*/ -#define BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL 0x93 + * BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL: + * Response ID returned by repeate last response operation + *
Failed to retrieve and re-send last response + */ +#define BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL 0x93 /*! \addtogroup pwrdwn -* Response IDs returned by power down notify operation -* @{ -*/ + * Response IDs returned by power down notify operation + * @{ + */ /** Fingerprint sensor module is ready to be powered down */ -#define BMKT_RSP_POWER_DOWN_READY 0xA2 +#define BMKT_RSP_POWER_DOWN_READY 0xA2 /** Failed to go into power down mode */ -#define BMKT_RSP_POWER_DOWN_FAIL 0xA3 +#define BMKT_RSP_POWER_DOWN_FAIL 0xA3 /*! @} */ /*! \addtogroup versioninfo -* Response IDs returned by get version operation -* @{ -*/ + * Response IDs returned by get version operation + * @{ + */ /** -* BMKT_RSP_VERSION_INFO: -* System version information of the fingerprint sensor module -*
Payload data represented in \ref bmkt_get_version_resp_t struct -*/ -#define BMKT_RSP_VERSION_INFO 0xB2 + * BMKT_RSP_VERSION_INFO: + * System version information of the fingerprint sensor module + *
Payload data represented in \ref bmkt_get_version_resp_t struct + */ +#define BMKT_RSP_VERSION_INFO 0xB2 /* Failed to retrieve and send last response */ -#define BMKT_RSP_GET_VERSION_FAIL 0xB3 +#define BMKT_RSP_GET_VERSION_FAIL 0xB3 /*! @} */ /** -* BMKT_RSP_GENERAL_ERROR: -* Not tied to a specific command-response session. -*
Could be caused by corrupt or truncated command message -*/ -#define BMKT_RSP_GENERAL_ERROR 0xC1 -#define BMKT_RSP_DISABLE_PAIRING_FAIL 0xC3 -#define BMKT_RSP_DISABLE_PAIRING_OK 0xC4 -#define BMKT_RSP_QUERY_PAIRING_FAIL 0xC6 -#define BMKT_RSP_SENSOR_PAIRING_REPORT 0xC7 + * BMKT_RSP_GENERAL_ERROR: + * Not tied to a specific command-response session. + *
Could be caused by corrupt or truncated command message + */ +#define BMKT_RSP_GENERAL_ERROR 0xC1 +#define BMKT_RSP_DISABLE_PAIRING_FAIL 0xC3 +#define BMKT_RSP_DISABLE_PAIRING_OK 0xC4 +#define BMKT_RSP_QUERY_PAIRING_FAIL 0xC6 +#define BMKT_RSP_SENSOR_PAIRING_REPORT 0xC7 /*! \addtogroup versioninfo -* Response IDs returned by get sensor module status operation -* @{ -*/ + * Response IDs returned by get sensor module status operation + * @{ + */ /** -* BMKT_RSP_SENSOR_STATUS_REPORT: -* Response returning the current status of the sensor module -*
Payload data represented in bmkt_XXX struct -*/ -#define BMKT_RSP_SENSOR_STATUS_REPORT 0xD2 + * BMKT_RSP_SENSOR_STATUS_REPORT: + * Response returning the current status of the sensor module + *
Payload data represented in bmkt_XXX struct + */ +#define BMKT_RSP_SENSOR_STATUS_REPORT 0xD2 /** Failed to retrieve sensor status */ -#define BMKT_RSP_SENSOR_STATUS_FAIL 0xD3 +#define BMKT_RSP_SENSOR_STATUS_FAIL 0xD3 /*! @} */ /** -* BMKT_RSP_SEND_NEXT_USER_ID: -* Response ID returned by identify user in order operation -*
Notify to send the next batch of user IDs in the priority list -*/ -#define BMKT_RSP_SEND_NEXT_USER_ID 0xE2 + * BMKT_RSP_SEND_NEXT_USER_ID: + * Response ID returned by identify user in order operation + *
Notify to send the next batch of user IDs in the priority list + */ +#define BMKT_RSP_SEND_NEXT_USER_ID 0xE2 /** -* BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL: -* Response IDs returned by retrieve final result operation -*
Failed to retrieve and re-send cached final result -*/ -#define BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL 0xE5 + * BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL: + * Response IDs returned by retrieve final result operation + *
Failed to retrieve and re-send cached final result + */ +#define BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL 0xE5 /** -* Response payload data structure returned by sensor initialization operation. -*/ + * Response payload data structure returned by sensor initialization operation. + */ typedef struct bmkt_init_resp { - uint8_t finger_presence; /**< Indicates finger existence on the sensor during startup */ + uint8_t finger_presence; /**< Indicates finger existence on the sensor during startup */ } bmkt_init_resp_t; /** -* bmkt_enroll_resp: -* Response payload data structure returned by enrollment operation. -*/ + * bmkt_enroll_resp: + * Response payload data structure returned by enrollment operation. + */ typedef struct bmkt_enroll_resp { - int progress; /**< Shows current progress stutus [0-100] */ - uint8_t finger_id; /**< User's finger id [1-10] */ - uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< User name to be enrolled */ + int progress; /**< Shows current progress stutus [0-100] */ + uint8_t finger_id; /**< User's finger id [1-10] */ + uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< User name to be enrolled */ } bmkt_enroll_resp_t; /** -* bmkt_auth_resp: -* Response payload data structure returned by identify and verify operations. -*/ + * bmkt_auth_resp: + * Response payload data structure returned by identify and verify operations. + */ struct bmkt_auth_resp { - double match_result; /**< match result returned by matcher */ - uint8_t finger_id; /**< Matched templates's finger id */ - uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< Matched template's user id */ + double match_result; /**< match result returned by matcher */ + uint8_t finger_id; /**< Matched templates's finger id */ + uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< Matched template's user id */ }; typedef struct bmkt_auth_resp bmkt_verify_resp_t; /**< Returned by verify */ typedef struct bmkt_auth_resp bmkt_identify_resp_t; /**< Returned by identify */ /** -* bmkt_fps_mode_resp: -* Response payload data structure returned by get fingerprint mode operation. -*/ + * bmkt_fps_mode_resp: + * Response payload data structure returned by get fingerprint mode operation. + */ typedef struct bmkt_fps_mode_resp { - uint8_t mode; /**< One of the Level I bmkt_mode_t values */ - uint8_t level2_mode; /**< One of the Level II bmkt_mode_level2_t values */ - uint8_t cmd_id; /**< Message ID of command being executed when bmkt_get_fps_mode was called */ - uint8_t finger_presence; /**< Finger presence status value finger on sensor 1 / finger not on sensor 0 */ + uint8_t mode; /**< One of the Level I bmkt_mode_t values */ + uint8_t level2_mode; /**< One of the Level II bmkt_mode_level2_t values */ + uint8_t cmd_id; /**< Message ID of command being executed when bmkt_get_fps_mode was called */ + uint8_t finger_presence; /**< Finger presence status value finger on sensor 1 / finger not on sensor 0 */ } bmkt_fps_mode_resp_t; /** -* bmkt_get_version_resp: -* Response payload data structure returned by get version operation. -*/ + * bmkt_get_version_resp: + * Response payload data structure returned by get version operation. + */ typedef struct bmkt_get_version_resp { - uint8_t part[BMKT_PART_NUM_LEN]; /**< Software Part Number */ - uint8_t year; /**< Software Version Year */ - uint8_t week; /**< Software Version Week */ - uint8_t patch; /**< Software Version Patch Level */ - uint8_t supplier_id[BMKT_SUPPLIER_ID_LEN]; /**< Software Supplier Identification */ + uint8_t part[BMKT_PART_NUM_LEN]; /**< Software Part Number */ + uint8_t year; /**< Software Version Year */ + uint8_t week; /**< Software Version Week */ + uint8_t patch; /**< Software Version Patch Level */ + uint8_t supplier_id[BMKT_SUPPLIER_ID_LEN]; /**< Software Supplier Identification */ } bmkt_get_version_resp_t; /** -* bmkt_get_db_capacity_resp: -* Response payload data structure returned by get DB capacity operation. -*/ + * bmkt_get_db_capacity_resp: + * Response payload data structure returned by get DB capacity operation. + */ typedef struct bmkt_get_db_capacity_resp { - uint8_t total; /**< Total Available Capacity: Total number of template records that can be stored */ - uint8_t empty; /**< Free Capacity: Number of template records that can still be stored */ - uint8_t bad_slots; /**< Number of bad template storage slots */ - uint8_t corrupt_templates; /**< Number of corrupt templates */ + uint8_t total; /**< Total Available Capacity: Total number of template records that can be stored */ + uint8_t empty; /**< Free Capacity: Number of template records that can still be stored */ + uint8_t bad_slots; /**< Number of bad template storage slots */ + uint8_t corrupt_templates; /**< Number of corrupt templates */ } bmkt_get_db_capacity_resp_t; /** -* bmkt_sec_level: -* Security level values. -*/ -typedef enum bmkt_sec_level -{ - BMKT_SECURITY_LEVEL_LOW = 0x10, - BMKT_SECURITY_LEVEL_MEDIUM = 0x40, - BMKT_SECURITY_LEVEL_HIGH = 0x60, + * bmkt_sec_level: + * Security level values. + */ +typedef enum bmkt_sec_level { + BMKT_SECURITY_LEVEL_LOW = 0x10, + BMKT_SECURITY_LEVEL_MEDIUM = 0x40, + BMKT_SECURITY_LEVEL_HIGH = 0x60, } bmkt_sec_level_t; /** -* bmkt_set_sec_level_resp: -* Response payload data structure returned by get/set security level operations. -*/ + * bmkt_set_sec_level_resp: + * Response payload data structure returned by get/set security level operations. + */ typedef struct bmkt_set_sec_level_resp { - bmkt_sec_level_t sec_level; /**< One of the bmkt_sec_level_t values */ + bmkt_sec_level_t sec_level; /**< One of the bmkt_sec_level_t values */ } bmkt_set_sec_level_resp_t; /** -* bmkt_del_all_users_resp: -* Response payload data structure returned by delete all enrolled users operation. -*/ + * bmkt_del_all_users_resp: + * Response payload data structure returned by delete all enrolled users operation. + */ typedef struct bmkt_del_all_users_resp { - int progress; /**< Progress indicator as a percentage */ + int progress; /**< Progress indicator as a percentage */ } bmkt_del_all_users_resp_t; /** -* bmkt_del_user_resp: -* Response payload data structure returned by delete enrolled user operation. -*/ + * bmkt_del_user_resp: + * Response payload data structure returned by delete enrolled user operation. + */ typedef struct bmkt_del_user_resp { - int progress; /**< Progress indicator as a percentage */ + int progress; /**< Progress indicator as a percentage */ } bmkt_del_user_resp_t; /** -* bmkt_enroll_template: -* Structure of enrolled users template record data. -*/ + * bmkt_enroll_template: + * Structure of enrolled users template record data. + */ typedef struct bmkt_enroll_template { - uint8_t user_id_len; /**< Length of user_id string */ - uint8_t template_status; /**< Template record status */ - uint8_t finger_id; /**< ID of enrolled finger */ - uint8_t user_id[BMKT_MAX_USER_ID_LEN + 1]; /**< Name of the enrolled user */ + uint8_t user_id_len; /**< Length of user_id string */ + uint8_t template_status; /**< Template record status */ + uint8_t finger_id; /**< ID of enrolled finger */ + uint8_t user_id[BMKT_MAX_USER_ID_LEN + 1]; /**< Name of the enrolled user */ } bmkt_enroll_template_t; /** -* bmkt_enroll_templates_resp: -* Response payload data structure returned by get enrolled user list operation. -*/ + * bmkt_enroll_templates_resp: + * Response payload data structure returned by get enrolled user list operation. + */ typedef struct bmkt_enroll_templates_resp { - uint8_t total_query_messages; /**< Total query response messages */ - uint8_t query_sequence; /**< Query response sequence number */ - bmkt_enroll_template_t templates[BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH]; /**< Enrolled user template records list */ + uint8_t total_query_messages; /**< Total query response messages */ + uint8_t query_sequence; /**< Query response sequence number */ + bmkt_enroll_template_t templates[BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH]; /**< Enrolled user template records list */ } bmkt_enroll_templates_resp_t; /** -* bmkt_enrolled_fingers: -* Structure of template record status corresponding to each enrolled finger. -*/ + * bmkt_enrolled_fingers: + * Structure of template record status corresponding to each enrolled finger. + */ typedef struct bmkt_enrolled_fingers { - uint8_t finger_id; /**< ID of enrolled finger */ - uint8_t template_status; /**< Template record status of finger_id */ + uint8_t finger_id; /**< ID of enrolled finger */ + uint8_t template_status; /**< Template record status of finger_id */ } bmkt_enrolled_fingers_t; /** -* bmkt_enrolled_fingers_resp: -* Response payload data structure returned by get enrolled fingers operation. -*/ + * bmkt_enrolled_fingers_resp: + * Response payload data structure returned by get enrolled fingers operation. + */ typedef struct bmkt_enrolled_fingers_resp { - bmkt_enrolled_fingers_t fingers[10]; /**< List of enroled fingers, max number of supported fingers per user is 10 */ + bmkt_enrolled_fingers_t fingers[10]; /**< List of enroled fingers, max number of supported fingers per user is 10 */ } bmkt_enrolled_fingers_resp_t; /** -* bmkt_response_data_t: -* Union combining all response payload data types. -*/ -typedef union { - bmkt_init_resp_t init_resp; - bmkt_enroll_resp_t enroll_resp; - bmkt_verify_resp_t verify_resp; - bmkt_identify_resp_t id_resp; - bmkt_fps_mode_resp_t fps_mode_resp; - bmkt_get_version_resp_t get_version_resp; - bmkt_get_db_capacity_resp_t db_cap_resp; - bmkt_set_sec_level_resp_t sec_level_resp; - bmkt_del_all_users_resp_t del_all_users_resp; - bmkt_enroll_templates_resp_t enroll_templates_resp; - bmkt_del_user_resp_t del_user_resp; - bmkt_enrolled_fingers_resp_t enrolled_fingers_resp; + * bmkt_response_data_t: + * Union combining all response payload data types. + */ +typedef union +{ + bmkt_init_resp_t init_resp; + bmkt_enroll_resp_t enroll_resp; + bmkt_verify_resp_t verify_resp; + bmkt_identify_resp_t id_resp; + bmkt_fps_mode_resp_t fps_mode_resp; + bmkt_get_version_resp_t get_version_resp; + bmkt_get_db_capacity_resp_t db_cap_resp; + bmkt_set_sec_level_resp_t sec_level_resp; + bmkt_del_all_users_resp_t del_all_users_resp; + bmkt_enroll_templates_resp_t enroll_templates_resp; + bmkt_del_user_resp_t del_user_resp; + bmkt_enrolled_fingers_resp_t enrolled_fingers_resp; } bmkt_response_data_t; /** -* bmkt_response: -* Structure to abstract different response structure types in one API -* to be used in bmkt_resp_cb_t callback function. -*/ + * bmkt_response: + * Structure to abstract different response structure types in one API + * to be used in bmkt_resp_cb_t callback function. + */ typedef struct bmkt_response { - int response_id; /**< Response message ID, one of th BMKT_RSP_XXX */ - int result; /**< Operation execution result code */ - int complete; /**< Operation completion status 1: complete / 0: not completed */ - bmkt_response_data_t response; /**< Operation specific response union */ + int response_id; /**< Response message ID, one of th BMKT_RSP_XXX */ + int result; /**< Operation execution result code */ + int complete; /**< Operation completion status 1: complete / 0: not completed */ + bmkt_response_data_t response; /**< Operation specific response union */ } bmkt_response_t; #endif /* _BMKT_RESPONSE_H_ */ diff --git a/libfprint/drivers/synaptics/sensor.h b/libfprint/drivers/synaptics/sensor.h index b8ebdfb2..922b1dd6 100644 --- a/libfprint/drivers/synaptics/sensor.h +++ b/libfprint/drivers/synaptics/sensor.h @@ -20,61 +20,68 @@ #define _SENSOR_H_ #include "usb_transport.h" -#define BMKT_MAX_PENDING_SESSIONS 2 +#define BMKT_MAX_PENDING_SESSIONS 2 -typedef enum bmkt_sensor_state -{ - BMKT_SENSOR_STATE_UNINIT = 0, - BMKT_SENSOR_STATE_IDLE, - BMKT_SENSOR_STATE_INIT, - BMKT_SENSOR_STATE_EXIT, +typedef enum bmkt_sensor_state { + BMKT_SENSOR_STATE_UNINIT = 0, + BMKT_SENSOR_STATE_IDLE, + BMKT_SENSOR_STATE_INIT, + BMKT_SENSOR_STATE_EXIT, } bmkt_sensor_state_t; typedef struct bmkt_sensor_drv bmkt_sensor_drv_t; typedef struct bmkt_sensor_version { - uint32_t build_time; - uint32_t build_num; - uint8_t version_major; - uint8_t version_minor; - uint8_t target; - uint8_t product; - uint8_t silicon_rev; - uint8_t formal_release; - uint8_t platform; - uint8_t patch; - uint8_t serial_number[6]; - uint16_t security; - uint8_t iface; - uint8_t device_type; + uint32_t build_time; + uint32_t build_num; + uint8_t version_major; + uint8_t version_minor; + uint8_t target; + uint8_t product; + uint8_t silicon_rev; + uint8_t formal_release; + uint8_t platform; + uint8_t patch; + uint8_t serial_number[6]; + uint16_t security; + uint8_t iface; + uint8_t device_type; } bmkt_sensor_version_t; typedef struct bmkt_sensor { - bmkt_usb_transport_t usb_xport; - bmkt_sensor_version_t version; - bmkt_session_ctx_t pending_sessions[BMKT_MAX_PENDING_SESSIONS]; - int empty_session_idx; - int flags; - int seq_num; - bmkt_sensor_state_t sensor_state; - bmkt_event_cb_t finger_event_cb; - void *finger_cb_ctx; - bmkt_general_error_cb_t gen_err_cb; - void *gen_err_cb_ctx; - bmkt_op_state_t op_state; + bmkt_usb_transport_t usb_xport; + bmkt_sensor_version_t version; + bmkt_session_ctx_t pending_sessions[BMKT_MAX_PENDING_SESSIONS]; + int empty_session_idx; + int flags; + int seq_num; + bmkt_sensor_state_t sensor_state; + bmkt_event_cb_t finger_event_cb; + void *finger_cb_ctx; + bmkt_general_error_cb_t gen_err_cb; + void *gen_err_cb_ctx; + bmkt_op_state_t op_state; } bmkt_sensor_t; -int bmkt_sensor_open(bmkt_sensor_t *sensor, - bmkt_general_error_cb_t err_cb, void *err_cb_ctx); -int bmkt_sensor_close(bmkt_sensor_t *sensor); +int bmkt_sensor_open (bmkt_sensor_t *sensor, + bmkt_general_error_cb_t err_cb, + void *err_cb_ctx); +int bmkt_sensor_close (bmkt_sensor_t *sensor); -int bmkt_sensor_init_fps(bmkt_sensor_t *sensor); +int bmkt_sensor_init_fps (bmkt_sensor_t *sensor); -int bmkt_sensor_send_message(bmkt_sensor_t *sensor, uint8_t msg_id, uint8_t payload_size, - uint8_t *payload, bmkt_resp_cb_t resp_cb, void *resp_data); -int bmkt_sensor_handle_response(bmkt_sensor_t *sensor, uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp); +int bmkt_sensor_send_message (bmkt_sensor_t *sensor, + uint8_t msg_id, + uint8_t payload_size, + uint8_t *payload, + bmkt_resp_cb_t resp_cb, + void *resp_data); +int bmkt_sensor_handle_response (bmkt_sensor_t *sensor, + uint8_t *resp_buf, + int resp_len, + bmkt_msg_resp_t *msg_resp); -int bmkt_sensor_send_async_read_command(bmkt_sensor_t *sensor); +int bmkt_sensor_send_async_read_command (bmkt_sensor_t *sensor); #endif /* _SENSOR_H_ */ diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index d5efa2a8..b7a0fce8 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -25,347 +25,386 @@ #include "synaptics.h" #include "bmkt_message.h" -G_DEFINE_TYPE(FpiDeviceSynaptics, fpi_device_synaptics, FP_TYPE_DEVICE) +G_DEFINE_TYPE (FpiDeviceSynaptics, fpi_device_synaptics, FP_TYPE_DEVICE) -static const FpIdEntry id_table [ ] = { - { .vid = SYNAPTICS_VENDOR_ID, .pid = 0xBD, }, +static const FpIdEntry id_table[] = { + { .vid = SYNAPTICS_VENDOR_ID, .pid = 0xBD, }, - { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ + { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ }; static void cmd_recieve_cb (FpiUsbTransfer *transfer, - FpDevice *device, - gpointer user_data, - GError *error) + FpDevice *device, + gpointer user_data, + GError *error) { - FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); - SynCmdMsgCallback callback = user_data; - int res; - bmkt_msg_resp_t msg_resp; - bmkt_response_t resp; + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); + SynCmdMsgCallback callback = user_data; + int res; + bmkt_msg_resp_t msg_resp; + bmkt_response_t resp; - if (error) { - /* NOTE: assumes timeout should never happen for receiving. */ - fpi_ssm_mark_failed (transfer->ssm, error); - return; - } + if (error) + { + /* NOTE: assumes timeout should never happen for receiving. */ + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } - res = bmkt_parse_message_header(&transfer->buffer[SENSOR_FW_REPLY_HEADER_LEN], - transfer->actual_length - SENSOR_FW_REPLY_HEADER_LEN, - &msg_resp); - if (res != BMKT_SUCCESS) { - g_warning ("Corrupted message received"); - fpi_ssm_mark_failed (transfer->ssm, - fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - return; - } + res = bmkt_parse_message_header (&transfer->buffer[SENSOR_FW_REPLY_HEADER_LEN], + transfer->actual_length - SENSOR_FW_REPLY_HEADER_LEN, + &msg_resp); + if (res != BMKT_SUCCESS) + { + g_warning ("Corrupted message received"); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + return; + } - /* Special case events */ - if (msg_resp.msg_id == BMKT_EVT_FINGER_REPORT) { - if (msg_resp.payload_len != 1) { - g_warning ("Corrupted finger report received"); - fpi_ssm_mark_failed (transfer->ssm, - fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - return; - } + /* Special case events */ + if (msg_resp.msg_id == BMKT_EVT_FINGER_REPORT) + { + if (msg_resp.payload_len != 1) + { + g_warning ("Corrupted finger report received"); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + return; + } - if (msg_resp.payload[0] == 0x01) { - self->finger_on_sensor = TRUE; - } else { - self->finger_on_sensor = FALSE; - if (self->cmd_complete_on_removal) { - fpi_ssm_mark_completed (transfer->ssm); - return; - } - } + if (msg_resp.payload[0] == 0x01) + { + self->finger_on_sensor = TRUE; + } + else + { + self->finger_on_sensor = FALSE; + if (self->cmd_complete_on_removal) + { + fpi_ssm_mark_completed (transfer->ssm); + return; + } + } - fp_dbg ("Finger is now %s the sensor", self->finger_on_sensor ? "on" : "off"); + fp_dbg ("Finger is now %s the sensor", self->finger_on_sensor ? "on" : "off"); - /* XXX: Call callback!?! */ - } + /* XXX: Call callback!?! */ + } - res = bmkt_parse_message_payload (&msg_resp, &resp); - if (res != BMKT_SUCCESS) { - g_warning ("Could not parse message payload: %i", res); - fpi_ssm_mark_failed (transfer->ssm, - fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - return; - } + res = bmkt_parse_message_payload (&msg_resp, &resp); + if (res != BMKT_SUCCESS) + { + g_warning ("Could not parse message payload: %i", res); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + return; + } - /* Special cancellation handling */ - if (resp.response_id == BMKT_RSP_CANCEL_OP_OK || resp.response_id == BMKT_RSP_CANCEL_OP_FAIL) { - if (resp.response_id == BMKT_RSP_CANCEL_OP_OK) { - fp_dbg ("Received cancellation success resonse"); - fpi_ssm_mark_failed (transfer->ssm, - g_error_new_literal (G_IO_ERROR, - G_IO_ERROR_CANCELLED, - "Device reported cancellation of operation")); - } else { - fp_dbg ("Cancellation failed, this should not happen"); - fpi_ssm_mark_failed (transfer->ssm, - fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - } - return; - } + /* Special cancellation handling */ + if (resp.response_id == BMKT_RSP_CANCEL_OP_OK || resp.response_id == BMKT_RSP_CANCEL_OP_FAIL) + { + if (resp.response_id == BMKT_RSP_CANCEL_OP_OK) + { + fp_dbg ("Received cancellation success resonse"); + fpi_ssm_mark_failed (transfer->ssm, + g_error_new_literal (G_IO_ERROR, + G_IO_ERROR_CANCELLED, + "Device reported cancellation of operation")); + } + else + { + fp_dbg ("Cancellation failed, this should not happen"); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + } + return; + } - if (msg_resp.seq_num == 0) { - /* XXX: Should we really abort the command on general error? - * The original code did not! */ - if (msg_resp.msg_id == BMKT_RSP_GENERAL_ERROR) { - guint16 err; + if (msg_resp.seq_num == 0) + { + /* XXX: Should we really abort the command on general error? + * The original code did not! */ + if (msg_resp.msg_id == BMKT_RSP_GENERAL_ERROR) + { + guint16 err; - /* XXX: It is weird that this is big endian. */ - err = FP_READ_UINT16_BE(msg_resp.payload); + /* XXX: It is weird that this is big endian. */ + err = FP_READ_UINT16_BE (msg_resp.payload); - fp_warn("Received General Error %d from the sensor", (guint) err); - fpi_ssm_mark_failed (transfer->ssm, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Received general error from device")); - //fpi_ssm_jump_to_state (transfer->ssm, fpi_ssm_get_cur_state (transfer->ssm)); - return; - } else { - fp_dbg ("Received message with 0 sequence number 0x%02x, ignoring!", - msg_resp.msg_id); - fpi_ssm_next_state (transfer->ssm); - return; - } - } + fp_warn ("Received General Error %d from the sensor", (guint) err); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Received general error from device")); + //fpi_ssm_jump_to_state (transfer->ssm, fpi_ssm_get_cur_state (transfer->ssm)); + return; + } + else + { + fp_dbg ("Received message with 0 sequence number 0x%02x, ignoring!", + msg_resp.msg_id); + fpi_ssm_next_state (transfer->ssm); + return; + } + } - /* We should only ever have one command running, and the sequence num needs - * to match. */ - if (msg_resp.seq_num != self->cmd_seq_num) { - fp_warn ("Got unexpected sequence number from device, %d instead of %d", - msg_resp.seq_num, - self->cmd_seq_num); - } + /* We should only ever have one command running, and the sequence num needs + * to match. */ + if (msg_resp.seq_num != self->cmd_seq_num) + { + fp_warn ("Got unexpected sequence number from device, %d instead of %d", + msg_resp.seq_num, + self->cmd_seq_num); + } - if (callback) - callback (self, &resp, NULL); + if (callback) + callback (self, &resp, NULL); - /* Callback may have queued a follow up command, then we need - * to restart the SSM. If not, we'll finish/wait for interrupt - * depending on resp.complete. */ - if (self->cmd_pending_transfer) - fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_SEND_PENDING); - else if (!resp.complete) - fpi_ssm_next_state (transfer->ssm); /* SYNAPTICS_CMD_WAIT_INTERRUPT */ - else - fpi_ssm_mark_completed (transfer->ssm); + /* Callback may have queued a follow up command, then we need + * to restart the SSM. If not, we'll finish/wait for interrupt + * depending on resp.complete. */ + if (self->cmd_pending_transfer) + fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_SEND_PENDING); + else if (!resp.complete) + fpi_ssm_next_state (transfer->ssm); /* SYNAPTICS_CMD_WAIT_INTERRUPT */ + else + fpi_ssm_mark_completed (transfer->ssm); } static void cmd_interrupt_cb (FpiUsbTransfer *transfer, - FpDevice *device, - gpointer user_data, - GError *error) + FpDevice *device, + gpointer user_data, + GError *error) { - g_debug ("interrupt transfer done"); - if (error) { - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - g_error_free (error); - fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_GET_RESP); - return; - } + g_debug ("interrupt transfer done"); + if (error) + { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_error_free (error); + fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_GET_RESP); + return; + } - fpi_ssm_mark_failed (transfer->ssm, error); - return; - } - g_clear_pointer (&error, g_error_free); + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } + g_clear_pointer (&error, g_error_free); - if (transfer->buffer[0] & USB_ASYNC_MESSAGE_PENDING || error) - fpi_ssm_next_state (transfer->ssm); - else - fpi_usb_transfer_submit (transfer, 1000, NULL, cmd_interrupt_cb, NULL); + if (transfer->buffer[0] & USB_ASYNC_MESSAGE_PENDING || error) + fpi_ssm_next_state (transfer->ssm); + else + fpi_usb_transfer_submit (transfer, 1000, NULL, cmd_interrupt_cb, NULL); } static void -synaptics_cmd_run_state(FpiSsm *ssm, - FpDevice *dev, - void *user_data) +synaptics_cmd_run_state (FpiSsm *ssm, + FpDevice *dev, + void *user_data) { - g_autoptr(FpiUsbTransfer) transfer = NULL; - FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev); + g_autoptr(FpiUsbTransfer) transfer = NULL; + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case SYNAPTICS_CMD_SEND_PENDING: - if (self->cmd_pending_transfer) { - self->cmd_pending_transfer->ssm = ssm; - fpi_usb_transfer_submit (self->cmd_pending_transfer, - 1000, - NULL, - fpi_ssm_usb_transfer_cb, - NULL); - g_clear_pointer (&self->cmd_pending_transfer, fpi_usb_transfer_unref); - } else { - fpi_ssm_next_state (ssm); - } - break; + switch (fpi_ssm_get_cur_state (ssm)) + { + case SYNAPTICS_CMD_SEND_PENDING: + if (self->cmd_pending_transfer) + { + self->cmd_pending_transfer->ssm = ssm; + fpi_usb_transfer_submit (self->cmd_pending_transfer, + 1000, + NULL, + fpi_ssm_usb_transfer_cb, + NULL); + g_clear_pointer (&self->cmd_pending_transfer, fpi_usb_transfer_unref); + } + else + { + fpi_ssm_next_state (ssm); + } + break; - case SYNAPTICS_CMD_GET_RESP: - transfer = fpi_usb_transfer_new (dev); - transfer->ssm = ssm; - fpi_usb_transfer_fill_bulk (transfer, USB_EP_REPLY, MAX_TRANSFER_LEN); - fpi_usb_transfer_submit (transfer, - 5000, - NULL, - cmd_recieve_cb, - user_data); + case SYNAPTICS_CMD_GET_RESP: + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + fpi_usb_transfer_fill_bulk (transfer, USB_EP_REPLY, MAX_TRANSFER_LEN); + fpi_usb_transfer_submit (transfer, + 5000, + NULL, + cmd_recieve_cb, + user_data); - break; + break; - case SYNAPTICS_CMD_WAIT_INTERRUPT: - transfer = fpi_usb_transfer_new (dev); - transfer->ssm = ssm; - fpi_usb_transfer_fill_interrupt (transfer, USB_EP_INTERRUPT, USB_INTERRUPT_DATA_SIZE); - fpi_usb_transfer_submit (transfer, - 0, - self->interrupt_cancellable, - cmd_interrupt_cb, - NULL); + case SYNAPTICS_CMD_WAIT_INTERRUPT: + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + fpi_usb_transfer_fill_interrupt (transfer, USB_EP_INTERRUPT, USB_INTERRUPT_DATA_SIZE); + fpi_usb_transfer_submit (transfer, + 0, + self->interrupt_cancellable, + cmd_interrupt_cb, + NULL); - break; + break; - case SYNAPTICS_CMD_SEND_ASYNC: - transfer = fpi_usb_transfer_new (dev); - transfer->ssm = ssm; - fpi_usb_transfer_fill_bulk (transfer, USB_EP_REQUEST, SENSOR_FW_CMD_HEADER_LEN); - transfer->buffer[0] = SENSOR_CMD_ASYNCMSG_READ; - fpi_usb_transfer_submit (transfer, - 1000, - NULL, - fpi_ssm_usb_transfer_cb, - NULL); + case SYNAPTICS_CMD_SEND_ASYNC: + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + fpi_usb_transfer_fill_bulk (transfer, USB_EP_REQUEST, SENSOR_FW_CMD_HEADER_LEN); + transfer->buffer[0] = SENSOR_CMD_ASYNCMSG_READ; + fpi_usb_transfer_submit (transfer, + 1000, + NULL, + fpi_ssm_usb_transfer_cb, + NULL); - break; + break; - case SYNAPTICS_CMD_RESTART: - fpi_ssm_jump_to_state (ssm, SYNAPTICS_CMD_SEND_PENDING); - break; - } + case SYNAPTICS_CMD_RESTART: + fpi_ssm_jump_to_state (ssm, SYNAPTICS_CMD_SEND_PENDING); + break; + } } static void -cmd_ssm_done (FpiSsm *ssm, - FpDevice *dev, - void *user_data, - GError *error) +cmd_ssm_done (FpiSsm *ssm, + FpDevice *dev, + void *user_data, + GError *error) { - FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev); - SynCmdMsgCallback callback = user_data; + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev); + SynCmdMsgCallback callback = user_data; - self->cmd_ssm = NULL; + self->cmd_ssm = NULL; - /* Notify about the SSM failure from here instead. */ - if (error) { - callback (self, NULL, error); - } else if (self->cmd_complete_on_removal) { - callback (self, NULL, self->cmd_complete_error); - self->cmd_complete_error = NULL; - } - self->cmd_complete_on_removal = FALSE; - g_clear_pointer (&self->cmd_complete_error, g_error_free); - fpi_ssm_free (ssm); + /* Notify about the SSM failure from here instead. */ + if (error) + { + callback (self, NULL, error); + } + else if (self->cmd_complete_on_removal) + { + callback (self, NULL, self->cmd_complete_error); + self->cmd_complete_error = NULL; + } + self->cmd_complete_on_removal = FALSE; + g_clear_pointer (&self->cmd_complete_error, g_error_free); + fpi_ssm_free (ssm); } static void cmd_forget_cb (FpiUsbTransfer *transfer, - FpDevice *device, - gpointer user_data, - GError *error) + FpDevice *device, + gpointer user_data, + GError *error) { - if (error) { - g_warning ("Async command sending failed: %s", error->message); - g_error_free (error); - } else { - g_debug ("Async command sent successfully"); - } + if (error) + { + g_warning ("Async command sending failed: %s", error->message); + g_error_free (error); + } + else + { + g_debug ("Async command sent successfully"); + } } static void synaptics_sensor_cmd (FpiDeviceSynaptics *self, - gint seq_num, - guint8 msg_id, - const guint8* payload, - gssize payload_len, - SynCmdMsgCallback callback) + gint seq_num, + guint8 msg_id, + const guint8 * payload, + gssize payload_len, + SynCmdMsgCallback callback) { - g_autoptr(FpiUsbTransfer) transfer = NULL; - guint8 real_seq_num; - gint msg_len; - gint res; + g_autoptr(FpiUsbTransfer) transfer = NULL; + guint8 real_seq_num; + gint msg_len; + gint res; - /* callback may be NULL in two cases: - * - seq_num == -1 - * - a state machine is already running, continued command */ - g_assert (payload || payload_len == 0); + /* callback may be NULL in two cases: + * - seq_num == -1 + * - a state machine is already running, continued command */ + g_assert (payload || payload_len == 0); - /* seq_num of 0 means a normal command, -1 means the current commands - * sequence number should not be udpated (i.e. second async command which - * may only be a cancellation currently). */ - if (seq_num <= 0) { - self->last_seq_num = MAX(1, self->last_seq_num + 1); - real_seq_num = self->last_seq_num; - if (seq_num == 0) - self->cmd_seq_num = self->last_seq_num; - } else { - real_seq_num = seq_num; - self->last_seq_num = real_seq_num; - } - g_debug ("sequence number is %d", real_seq_num); + /* seq_num of 0 means a normal command, -1 means the current commands + * sequence number should not be udpated (i.e. second async command which + * may only be a cancellation currently). */ + if (seq_num <= 0) + { + self->last_seq_num = MAX (1, self->last_seq_num + 1); + real_seq_num = self->last_seq_num; + if (seq_num == 0) + self->cmd_seq_num = self->last_seq_num; + } + else + { + real_seq_num = seq_num; + self->last_seq_num = real_seq_num; + } + g_debug ("sequence number is %d", real_seq_num); - /* We calculate the exact length here (we could also just create a larger - * buffer instead and check the result of bmkt_compose_message. */ - msg_len = BMKT_MESSAGE_HEADER_LEN + payload_len; + /* We calculate the exact length here (we could also just create a larger + * buffer instead and check the result of bmkt_compose_message. */ + msg_len = BMKT_MESSAGE_HEADER_LEN + payload_len; - /* Send out the command */ - transfer = fpi_usb_transfer_new (FP_DEVICE (self)); - transfer->short_is_error = TRUE; - fpi_usb_transfer_fill_bulk (transfer, - USB_EP_REQUEST, - msg_len + SENSOR_FW_CMD_HEADER_LEN); + /* Send out the command */ + transfer = fpi_usb_transfer_new (FP_DEVICE (self)); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk (transfer, + USB_EP_REQUEST, + msg_len + SENSOR_FW_CMD_HEADER_LEN); - /* MIS sensors send ACE commands encapsulated in FW commands*/ - transfer->buffer[0] = SENSOR_CMD_ACE_COMMAND; - res = bmkt_compose_message (&transfer->buffer[1], - &msg_len, msg_id, - real_seq_num, - payload_len, - payload); - g_assert (res == BMKT_SUCCESS); - g_assert (msg_len + SENSOR_FW_CMD_HEADER_LEN == transfer->length); + /* MIS sensors send ACE commands encapsulated in FW commands*/ + transfer->buffer[0] = SENSOR_CMD_ACE_COMMAND; + res = bmkt_compose_message (&transfer->buffer[1], + &msg_len, msg_id, + real_seq_num, + payload_len, + payload); + g_assert (res == BMKT_SUCCESS); + g_assert (msg_len + SENSOR_FW_CMD_HEADER_LEN == transfer->length); - /* Special case for async command sending (should only be used for - * cancellation). */ - if (seq_num == -1) { - g_assert(callback == NULL); + /* Special case for async command sending (should only be used for + * cancellation). */ + if (seq_num == -1) + { + g_assert (callback == NULL); - /* We just send and forget here. */ - fpi_usb_transfer_submit (transfer, 1000, NULL, cmd_forget_cb, NULL); - } else { - /* Command should be send using the state machine. */ - g_assert (self->cmd_pending_transfer == NULL); + /* We just send and forget here. */ + fpi_usb_transfer_submit (transfer, 1000, NULL, cmd_forget_cb, NULL); + } + else + { + /* Command should be send using the state machine. */ + g_assert (self->cmd_pending_transfer == NULL); - self->cmd_pending_transfer = g_steal_pointer (&transfer); + self->cmd_pending_transfer = g_steal_pointer (&transfer); - if (self->cmd_ssm) { - /* Continued command, we already have an SSM with a callback. - * There is nothing to do in this case, the command will be - * sent automatically. */ - g_assert (callback == NULL); - } else { - /* Start of a new command, create the state machine. */ - g_assert (callback != NULL); + if (self->cmd_ssm) + { + /* Continued command, we already have an SSM with a callback. + * There is nothing to do in this case, the command will be + * sent automatically. */ + g_assert (callback == NULL); + } + else + { + /* Start of a new command, create the state machine. */ + g_assert (callback != NULL); - self->cmd_ssm = fpi_ssm_new (FP_DEVICE (self), - synaptics_cmd_run_state, - SYNAPTICS_CMD_NUM_STATES, - callback); + self->cmd_ssm = fpi_ssm_new (FP_DEVICE (self), + synaptics_cmd_run_state, + SYNAPTICS_CMD_NUM_STATES, + callback); - fpi_ssm_start (self->cmd_ssm, cmd_ssm_done); - } - } + fpi_ssm_start (self->cmd_ssm, cmd_ssm_done); + } + } } static gboolean @@ -374,744 +413,798 @@ parse_print_data (GVariant *data, const guint8 **user_id, gssize *user_id_len) { - g_autoptr(GVariant) user_id_var = NULL; + g_autoptr(GVariant) user_id_var = NULL; - g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (finger != NULL, FALSE); - g_return_val_if_fail (user_id != NULL, FALSE); - g_return_val_if_fail (user_id_len != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (finger != NULL, FALSE); + g_return_val_if_fail (user_id != NULL, FALSE); + g_return_val_if_fail (user_id_len != NULL, FALSE); - *user_id = NULL; - *user_id_len = 0; + *user_id = NULL; + *user_id_len = 0; - if (!g_variant_check_format_string (data, "(y@ay)", FALSE)) - return FALSE; + if (!g_variant_check_format_string (data, "(y@ay)", FALSE)) + return FALSE; - g_variant_get(data, - "(y@ay)", - finger, - &user_id_var); + g_variant_get (data, + "(y@ay)", + finger, + &user_id_var); - *user_id = g_variant_get_fixed_array (user_id_var, user_id_len, 1); + *user_id = g_variant_get_fixed_array (user_id_var, user_id_len, 1); - if (*user_id_len == 0 || *user_id_len > BMKT_MAX_USER_ID_LEN) - return FALSE; + if (*user_id_len == 0 || *user_id_len > BMKT_MAX_USER_ID_LEN) + return FALSE; - if (*user_id_len <= 0 || *user_id[0] == ' ') - return FALSE; + if (*user_id_len <= 0 || *user_id[0] == ' ') + return FALSE; - return TRUE; + return TRUE; } static void -list_msg_cb(FpiDeviceSynaptics *self, - bmkt_response_t *resp, - GError *error) +list_msg_cb (FpiDeviceSynaptics *self, + bmkt_response_t *resp, + GError *error) { - bmkt_enroll_templates_resp_t *get_enroll_templates_resp; + bmkt_enroll_templates_resp_t *get_enroll_templates_resp; - if (error) { - g_clear_pointer (&self->list_result, g_ptr_array_free); - fpi_device_list_complete (FP_DEVICE (self), NULL, error); - return; - } + if (error) + { + g_clear_pointer (&self->list_result, g_ptr_array_free); + fpi_device_list_complete (FP_DEVICE (self), NULL, error); + return; + } - get_enroll_templates_resp = &resp->response.enroll_templates_resp; + get_enroll_templates_resp = &resp->response.enroll_templates_resp; - switch (resp->response_id) - { - case BMKT_RSP_QUERY_FAIL: - if (resp->result == BMKT_FP_DATABASE_EMPTY) { - fp_info("Database is empty"); + switch (resp->response_id) + { + case BMKT_RSP_QUERY_FAIL: + if (resp->result == BMKT_FP_DATABASE_EMPTY) + { + fp_info ("Database is empty"); - fpi_device_list_complete (FP_DEVICE (self), - g_steal_pointer (&self->list_result), - NULL); - } else { - fp_info("Failed to query enrolled users: %d", resp->result); - g_clear_pointer (&self->list_result, g_ptr_array_free); - fpi_device_list_complete (FP_DEVICE (self), - NULL, - fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, - "Failed to query enrolled users")); - } - break; - case BMKT_RSP_QUERY_RESPONSE_COMPLETE: - fp_info("Query complete!"); + fpi_device_list_complete (FP_DEVICE (self), + g_steal_pointer (&self->list_result), + NULL); + } + else + { + fp_info ("Failed to query enrolled users: %d", resp->result); + g_clear_pointer (&self->list_result, g_ptr_array_free); + fpi_device_list_complete (FP_DEVICE (self), + NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Failed to query enrolled users")); + } + break; - fpi_device_list_complete (FP_DEVICE (self), - g_steal_pointer (&self->list_result), - NULL); + case BMKT_RSP_QUERY_RESPONSE_COMPLETE: + fp_info ("Query complete!"); - break; - case BMKT_RSP_TEMPLATE_RECORDS_REPORT: + fpi_device_list_complete (FP_DEVICE (self), + g_steal_pointer (&self->list_result), + NULL); - for (int n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++) - { - GVariant *data = NULL; - GVariant *uid = NULL; - FpPrint *print; - gchar *userid; + break; - if (get_enroll_templates_resp->templates[n].user_id_len == 0) - continue; + case BMKT_RSP_TEMPLATE_RECORDS_REPORT: - fp_info("![query %d of %d] template %d: status=0x%x, userId=%s, fingerId=%d", - get_enroll_templates_resp->query_sequence, - get_enroll_templates_resp->total_query_messages, - n, - get_enroll_templates_resp->templates[n].template_status, - get_enroll_templates_resp->templates[n].user_id, - get_enroll_templates_resp->templates[n].finger_id); + for (int n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++) + { + GVariant *data = NULL; + GVariant *uid = NULL; + FpPrint *print; + gchar *userid; - userid = get_enroll_templates_resp->templates[n].user_id; + if (get_enroll_templates_resp->templates[n].user_id_len == 0) + continue; - print = fp_print_new (FP_DEVICE (self)); - uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - get_enroll_templates_resp->templates[n].user_id, - get_enroll_templates_resp->templates[n].user_id_len, - 1); - data = g_variant_new ("(y@ay)", - get_enroll_templates_resp->templates[n].finger_id, - uid); + fp_info ("![query %d of %d] template %d: status=0x%x, userId=%s, fingerId=%d", + get_enroll_templates_resp->query_sequence, + get_enroll_templates_resp->total_query_messages, + n, + get_enroll_templates_resp->templates[n].template_status, + get_enroll_templates_resp->templates[n].user_id, + get_enroll_templates_resp->templates[n].finger_id); - fpi_print_set_type (print, FP_PRINT_RAW); - fpi_print_set_device_stored (print, TRUE); - g_object_set (print, "fp-data", data, NULL); - g_object_set (print, "description", get_enroll_templates_resp->templates[n].user_id, NULL); + userid = get_enroll_templates_resp->templates[n].user_id; - /* The format has 24 bytes at the start and some dashes in the right places */ - if (g_str_has_prefix (userid, "FP1-") && strlen(userid) >= 24 && - userid[12] == '-' && userid[14] == '-' && userid[23] == '-') { - g_autofree gchar *copy = g_strdup(userid); - gint32 date_ymd; - GDate *date = NULL; - gint32 finger; - gchar *username; - /* Try to parse information from the string. */ + print = fp_print_new (FP_DEVICE (self)); + uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + get_enroll_templates_resp->templates[n].user_id, + get_enroll_templates_resp->templates[n].user_id_len, + 1); + data = g_variant_new ("(y@ay)", + get_enroll_templates_resp->templates[n].finger_id, + uid); - copy[12] = '\0'; - date_ymd = g_ascii_strtod (copy + 4, NULL); - if (date_ymd > 0) - date = g_date_new_dmy (date_ymd % 100, - (date_ymd / 100) % 100, - date_ymd / 10000); - else - date = g_date_new (); + fpi_print_set_type (print, FP_PRINT_RAW); + fpi_print_set_device_stored (print, TRUE); + g_object_set (print, "fp-data", data, NULL); + g_object_set (print, "description", get_enroll_templates_resp->templates[n].user_id, NULL); - fp_print_set_enroll_date (print, date); - g_date_free (date); + /* The format has 24 bytes at the start and some dashes in the right places */ + if (g_str_has_prefix (userid, "FP1-") && strlen (userid) >= 24 && + userid[12] == '-' && userid[14] == '-' && userid[23] == '-') + { + g_autofree gchar *copy = g_strdup (userid); + gint32 date_ymd; + GDate *date = NULL; + gint32 finger; + gchar *username; + /* Try to parse information from the string. */ - copy[14] = '\0'; - finger = g_ascii_strtoll (copy + 13, NULL, 16); - fp_print_set_finger (print, finger); + copy[12] = '\0'; + date_ymd = g_ascii_strtod (copy + 4, NULL); + if (date_ymd > 0) + date = g_date_new_dmy (date_ymd % 100, + (date_ymd / 100) % 100, + date_ymd / 10000); + else + date = g_date_new (); - /* We ignore the next chunk, it is just random data. - * Then comes the username; nobody is the default if the metadata - * is unknown */ - username = copy + 24; - if (strlen(username) > 0 && g_strcmp0 (username, "nobody") != 0) - fp_print_set_username (print, username); - } + fp_print_set_enroll_date (print, date); + g_date_free (date); - g_ptr_array_add (self->list_result, g_object_ref_sink (print)); - } + copy[14] = '\0'; + finger = g_ascii_strtoll (copy + 13, NULL, 16); + fp_print_set_finger (print, finger); - synaptics_sensor_cmd (self, - self->cmd_seq_num, - BMKT_CMD_GET_NEXT_QUERY_RESPONSE, - NULL, - 0, - NULL); + /* We ignore the next chunk, it is just random data. + * Then comes the username; nobody is the default if the metadata + * is unknown */ + username = copy + 24; + if (strlen (username) > 0 && g_strcmp0 (username, "nobody") != 0) + fp_print_set_username (print, username); + } - break; - } + g_ptr_array_add (self->list_result, g_object_ref_sink (print)); + } + + synaptics_sensor_cmd (self, + self->cmd_seq_num, + BMKT_CMD_GET_NEXT_QUERY_RESPONSE, + NULL, + 0, + NULL); + + break; + } } static void -list(FpDevice *device) +list (FpDevice *device) { - FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); - G_DEBUG_HERE(); + G_DEBUG_HERE (); - self->list_result = g_ptr_array_new_with_free_func (g_object_unref); - synaptics_sensor_cmd (self, 0, BMKT_CMD_GET_TEMPLATE_RECORDS, NULL, 0, list_msg_cb); + self->list_result = g_ptr_array_new_with_free_func (g_object_unref); + synaptics_sensor_cmd (self, 0, BMKT_CMD_GET_TEMPLATE_RECORDS, NULL, 0, list_msg_cb); } static void -verify_msg_cb(FpiDeviceSynaptics *self, - bmkt_response_t *resp, - GError *error) +verify_msg_cb (FpiDeviceSynaptics *self, + bmkt_response_t *resp, + GError *error) { - FpDevice *device = FP_DEVICE (self); - bmkt_verify_resp_t *verify_resp; + FpDevice *device = FP_DEVICE (self); + bmkt_verify_resp_t *verify_resp; - if (error) { - fpi_device_verify_complete (device, FPI_MATCH_ERROR, NULL, error); - return; - } + if (error) + { + fpi_device_verify_complete (device, FPI_MATCH_ERROR, NULL, error); + return; + } - if (resp == NULL && self->cmd_complete_on_removal) { - fpi_device_verify_complete (device, - GPOINTER_TO_INT (self->cmd_complete_data), - NULL, - error); - return; - } + if (resp == NULL && self->cmd_complete_on_removal) + { + fpi_device_verify_complete (device, + GPOINTER_TO_INT (self->cmd_complete_data), + NULL, + error); + return; + } - verify_resp = &resp->response.verify_resp; + verify_resp = &resp->response.verify_resp; - switch (resp->response_id) - { - case BMKT_RSP_VERIFY_READY: - fp_info("Place Finger on the Sensor!"); - break; + switch (resp->response_id) + { + case BMKT_RSP_VERIFY_READY: + fp_info ("Place Finger on the Sensor!"); + break; - case BMKT_RSP_CAPTURE_COMPLETE: - fp_info("Fingerprint image capture complete!"); - break; + case BMKT_RSP_CAPTURE_COMPLETE: + fp_info ("Fingerprint image capture complete!"); + break; - case BMKT_RSP_VERIFY_FAIL: - if(resp->result == BMKT_SENSOR_STIMULUS_ERROR) { - fp_dbg ("delaying retry error until after finger removal!"); - self->cmd_complete_on_removal = TRUE; - self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_ERROR); - self->cmd_complete_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); - } else if (resp->result == BMKT_FP_NO_MATCH) { - fp_dbg ("delaying match failure until after finger removal!"); - self->cmd_complete_on_removal = TRUE; - self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_FAIL); - self->cmd_complete_error = NULL; - } else if (BMKT_FP_DATABASE_NO_RECORD_EXISTS) { - fp_info("Print is not in database"); - fpi_device_verify_complete (device, - FPI_MATCH_ERROR, - NULL, - fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND)); - } else { - fp_warn("Verify has failed: %d", resp->result); - fpi_device_verify_complete (device, FPI_MATCH_FAIL, NULL, NULL); - } - break; + case BMKT_RSP_VERIFY_FAIL: + if(resp->result == BMKT_SENSOR_STIMULUS_ERROR) + { + fp_dbg ("delaying retry error until after finger removal!"); + self->cmd_complete_on_removal = TRUE; + self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_ERROR); + self->cmd_complete_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); + } + else if (resp->result == BMKT_FP_NO_MATCH) + { + fp_dbg ("delaying match failure until after finger removal!"); + self->cmd_complete_on_removal = TRUE; + self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_FAIL); + self->cmd_complete_error = NULL; + } + else if (BMKT_FP_DATABASE_NO_RECORD_EXISTS) + { + fp_info ("Print is not in database"); + fpi_device_verify_complete (device, + FPI_MATCH_ERROR, + NULL, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND)); + } + else + { + fp_warn ("Verify has failed: %d", resp->result); + fpi_device_verify_complete (device, FPI_MATCH_FAIL, NULL, NULL); + } + break; - case BMKT_RSP_VERIFY_OK: - fp_info("Verify was successful! for user: %s finger: %d score: %f", - verify_resp->user_id, verify_resp->finger_id, verify_resp->match_result); - fpi_device_verify_complete (device, FPI_MATCH_SUCCESS, NULL, NULL); - break; - } + case BMKT_RSP_VERIFY_OK: + fp_info ("Verify was successful! for user: %s finger: %d score: %f", + verify_resp->user_id, verify_resp->finger_id, verify_resp->match_result); + fpi_device_verify_complete (device, FPI_MATCH_SUCCESS, NULL, NULL); + break; + } } static void -verify(FpDevice *device) +verify (FpDevice *device) { - FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); - FpPrint *print = NULL; - g_autoptr(GVariant) data = NULL; - guint8 finger; - const guint8 *user_id; - gsize user_id_len = 0; + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); + FpPrint *print = NULL; - fpi_device_get_verify_data (device, &print); + g_autoptr(GVariant) data = NULL; + guint8 finger; + const guint8 *user_id; + gsize user_id_len = 0; - g_object_get (print, "fp-data", &data, NULL); - g_debug ("data is %p", data); - if (!parse_print_data (data, &finger, &user_id, &user_id_len)) { - fpi_device_verify_complete (device, - FPI_MATCH_ERROR, - NULL, - fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); - return; - } + fpi_device_get_verify_data (device, &print); - G_DEBUG_HERE(); + g_object_get (print, "fp-data", &data, NULL); + g_debug ("data is %p", data); + if (!parse_print_data (data, &finger, &user_id, &user_id_len)) + { + fpi_device_verify_complete (device, + FPI_MATCH_ERROR, + NULL, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); + return; + } - synaptics_sensor_cmd (self, 0, BMKT_CMD_VERIFY_USER, user_id, user_id_len, verify_msg_cb); + G_DEBUG_HERE (); + + synaptics_sensor_cmd (self, 0, BMKT_CMD_VERIFY_USER, user_id, user_id_len, verify_msg_cb); } static void -enroll_msg_cb(FpiDeviceSynaptics *self, - bmkt_response_t *resp, - GError *error) +enroll_msg_cb (FpiDeviceSynaptics *self, + bmkt_response_t *resp, + GError *error) { - FpDevice *device = FP_DEVICE (self); - bmkt_enroll_resp_t *enroll_resp; + FpDevice *device = FP_DEVICE (self); + bmkt_enroll_resp_t *enroll_resp; - if (error) { - fpi_device_enroll_complete (device, NULL, error); - return; - } + if (error) + { + fpi_device_enroll_complete (device, NULL, error); + return; + } - enroll_resp = &resp->response.enroll_resp; + enroll_resp = &resp->response.enroll_resp; - switch (resp->response_id) - { - case BMKT_RSP_ENROLL_READY: - { - self->enroll_stage = 0; - fp_info("Place Finger on the Sensor!"); - break; - } - case BMKT_RSP_CAPTURE_COMPLETE: - { - fp_info("Fingerprint image capture complete!"); - break; - } - case BMKT_RSP_ENROLL_REPORT: - { - gint done_stages; - fp_info("Enrollment is %d %% ", enroll_resp->progress); + switch (resp->response_id) + { + case BMKT_RSP_ENROLL_READY: + { + self->enroll_stage = 0; + fp_info ("Place Finger on the Sensor!"); + break; + } - done_stages = (enroll_resp->progress * ENROLL_SAMPLES + 99) / 100; - if (enroll_resp->progress < 100) - done_stages = MIN(done_stages, ENROLL_SAMPLES - 1); + case BMKT_RSP_CAPTURE_COMPLETE: + { + fp_info ("Fingerprint image capture complete!"); + break; + } - /* Emit a retry error if there has been no discernable - * progress. Some firmware revisions report more required - * touches. */ - if (self->enroll_stage == done_stages) - fpi_device_enroll_progress (device, - done_stages, - NULL, - fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); + case BMKT_RSP_ENROLL_REPORT: + { + gint done_stages; + fp_info ("Enrollment is %d %% ", enroll_resp->progress); - while (self->enroll_stage < done_stages) { - self->enroll_stage += 1; - fpi_device_enroll_progress (device, self->enroll_stage, NULL, NULL); - } - break; - } - case BMKT_RSP_ENROLL_PAUSED: - { - fp_info("Enrollment has been paused!"); - break; - } - case BMKT_RSP_ENROLL_RESUMED: - { - fp_info("Enrollment has been resumed!"); - break; - } - case BMKT_RSP_ENROLL_FAIL: - { - fp_info("Enrollment has failed!: %d", resp->result); - if (resp->result == BMKT_FP_DATABASE_FULL) - fpi_device_enroll_complete (device, - NULL, - fpi_device_error_new (FP_DEVICE_ERROR_DATA_FULL)); - else - fpi_device_enroll_complete (device, - NULL, - fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, - "Enrollment failed")); - break; - } - case BMKT_RSP_ENROLL_OK: - { - FpPrint *print = NULL; + done_stages = (enroll_resp->progress * ENROLL_SAMPLES + 99) / 100; + if (enroll_resp->progress < 100) + done_stages = MIN (done_stages, ENROLL_SAMPLES - 1); - fp_info("Enrollment was successful!"); + /* Emit a retry error if there has been no discernable + * progress. Some firmware revisions report more required + * touches. */ + if (self->enroll_stage == done_stages) + { + fpi_device_enroll_progress (device, + done_stages, + NULL, + fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); + } - fpi_device_get_enroll_data (device, &print); + while (self->enroll_stage < done_stages) + { + self->enroll_stage += 1; + fpi_device_enroll_progress (device, self->enroll_stage, NULL, NULL); + } + break; + } - fpi_device_enroll_complete (device, g_object_ref (print), NULL); - break; - } - } + case BMKT_RSP_ENROLL_PAUSED: + { + fp_info ("Enrollment has been paused!"); + break; + } + + case BMKT_RSP_ENROLL_RESUMED: + { + fp_info ("Enrollment has been resumed!"); + break; + } + + case BMKT_RSP_ENROLL_FAIL: + { + fp_info ("Enrollment has failed!: %d", resp->result); + if (resp->result == BMKT_FP_DATABASE_FULL) + { + fpi_device_enroll_complete (device, + NULL, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_FULL)); + } + else + { + fpi_device_enroll_complete (device, + NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Enrollment failed")); + } + break; + } + + case BMKT_RSP_ENROLL_OK: + { + FpPrint *print = NULL; + + fp_info ("Enrollment was successful!"); + + fpi_device_get_enroll_data (device, &print); + + fpi_device_enroll_complete (device, g_object_ref (print), NULL); + break; + } + } } #define TEMPLATE_ID_SIZE 20 static void -enroll(FpDevice *device) +enroll (FpDevice *device) { - FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); - FpPrint *print = NULL; - GVariant *data = NULL; - GVariant *uid = NULL; - const gchar *username; - guint finger; - g_autofree gchar *user_id; - gssize user_id_len; - g_autofree guint8 *payload = NULL; - const GDate *date; - gint y, m, d; - gint32 rand_id = 0; + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); + FpPrint *print = NULL; + GVariant *data = NULL; + GVariant *uid = NULL; + const gchar *username; + guint finger; + g_autofree gchar *user_id; + gssize user_id_len; + g_autofree guint8 *payload = NULL; + const GDate *date; + gint y, m, d; + gint32 rand_id = 0; - fpi_device_get_enroll_data (device, &print); + fpi_device_get_enroll_data (device, &print); - G_DEBUG_HERE(); + G_DEBUG_HERE (); - date = fp_print_get_enroll_date (print); - if (date && g_date_valid (date)) { - y = date->year; - m = date->month; - d = date->day; - } else { - y = 0; - m = 0; - d = 0; - } + date = fp_print_get_enroll_date (print); + if (date && g_date_valid (date)) + { + y = date->year; + m = date->month; + d = date->day; + } + else + { + y = 0; + m = 0; + d = 0; + } - username = fp_print_get_username (print); - if (!username) - username = "nobody"; + username = fp_print_get_username (print); + if (!username) + username = "nobody"; - if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0) - rand_id = 0; - else - rand_id = g_random_int(); + if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0) + rand_id = 0; + else + rand_id = g_random_int (); - user_id = g_strdup_printf ("FP1-%04d%02d%02d-%X-%08X-%s", - y, m, d, - fp_print_get_finger (print), - rand_id, - username); + user_id = g_strdup_printf ("FP1-%04d%02d%02d-%X-%08X-%s", + y, m, d, + fp_print_get_finger (print), + rand_id, + username); - user_id_len = strlen (user_id); - user_id_len = MIN(BMKT_MAX_USER_ID_LEN, user_id_len); + user_id_len = strlen (user_id); + user_id_len = MIN (BMKT_MAX_USER_ID_LEN, user_id_len); - /* We currently always use finger 1 from the devices piont of view */ - finger = 1; + /* We currently always use finger 1 from the devices piont of view */ + finger = 1; - uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - user_id, - user_id_len, - 1); - data = g_variant_new ("(y@ay)", - finger, - uid); + uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + user_id, + user_id_len, + 1); + data = g_variant_new ("(y@ay)", + finger, + uid); - fpi_print_set_type (print, FP_PRINT_RAW); - fpi_print_set_device_stored (print, TRUE); - g_object_set (print, "fp-data", data, NULL); - g_object_set (print, "description", user_id, NULL); + fpi_print_set_type (print, FP_PRINT_RAW); + fpi_print_set_device_stored (print, TRUE); + g_object_set (print, "fp-data", data, NULL); + g_object_set (print, "description", user_id, NULL); - g_debug("user_id: %s, finger: %d", user_id, finger); + g_debug ("user_id: %s, finger: %d", user_id, finger); - payload = g_malloc0(user_id_len + 2); + payload = g_malloc0 (user_id_len + 2); - /* Backup options are not supported for Prometheus */ - payload[0] = 0; - payload[1] = finger; - memcpy (payload + 2, user_id, user_id_len); + /* Backup options are not supported for Prometheus */ + payload[0] = 0; + payload[1] = finger; + memcpy (payload + 2, user_id, user_id_len); - synaptics_sensor_cmd (self, 0, BMKT_CMD_ENROLL_USER, payload, user_id_len + 2, enroll_msg_cb); + synaptics_sensor_cmd (self, 0, BMKT_CMD_ENROLL_USER, payload, user_id_len + 2, enroll_msg_cb); } static void -delete_msg_cb(FpiDeviceSynaptics *self, - bmkt_response_t *resp, - GError *error) +delete_msg_cb (FpiDeviceSynaptics *self, + bmkt_response_t *resp, + GError *error) { - FpDevice *device = FP_DEVICE (self); - bmkt_del_user_resp_t *del_user_resp; + FpDevice *device = FP_DEVICE (self); + bmkt_del_user_resp_t *del_user_resp; - if (error) { - fpi_device_delete_complete (device, error); - return; - } + if (error) + { + fpi_device_delete_complete (device, error); + return; + } - del_user_resp = &resp->response.del_user_resp; + del_user_resp = &resp->response.del_user_resp; - switch (resp->response_id) - { - case BMKT_RSP_DELETE_PROGRESS: - fp_info("Deleting Enrolled Users is %d%% complete", - del_user_resp->progress); - break; - case BMKT_RSP_DEL_USER_FP_FAIL: - fp_info("Failed to delete enrolled user: %d", resp->result); - if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS) - fpi_device_delete_complete (device, - fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND)); - else - fpi_device_delete_complete (device, - fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); - break; - case BMKT_RSP_DEL_USER_FP_OK: - fp_info("Successfully deleted enrolled user"); - fpi_device_delete_complete (device, NULL); - break; - } + switch (resp->response_id) + { + case BMKT_RSP_DELETE_PROGRESS: + fp_info ("Deleting Enrolled Users is %d%% complete", + del_user_resp->progress); + break; + + case BMKT_RSP_DEL_USER_FP_FAIL: + fp_info ("Failed to delete enrolled user: %d", resp->result); + if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS) + fpi_device_delete_complete (device, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND)); + else + fpi_device_delete_complete (device, + fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + break; + + case BMKT_RSP_DEL_USER_FP_OK: + fp_info ("Successfully deleted enrolled user"); + fpi_device_delete_complete (device, NULL); + break; + } } static void -delete_print(FpDevice *device) +delete_print (FpDevice *device) { - FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); - FpPrint *print = NULL; - g_autoptr(GVariant) data = NULL; - guint8 finger; - const guint8 *user_id; - gsize user_id_len = 0; - g_autofree guint8 *payload = NULL; + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); + FpPrint *print = NULL; - fpi_device_get_delete_data (device, &print); + g_autoptr(GVariant) data = NULL; + guint8 finger; + const guint8 *user_id; + gsize user_id_len = 0; + g_autofree guint8 *payload = NULL; - g_object_get (print, "fp-data", &data, NULL); - g_debug ("data is %p", data); - if (!parse_print_data (data, &finger, &user_id, &user_id_len)) { - fpi_device_delete_complete (device, - fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); - return; - } + fpi_device_get_delete_data (device, &print); - G_DEBUG_HERE(); + g_object_get (print, "fp-data", &data, NULL); + g_debug ("data is %p", data); + if (!parse_print_data (data, &finger, &user_id, &user_id_len)) + { + fpi_device_delete_complete (device, + fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); + return; + } - payload = g_malloc0 (1 + user_id_len); - payload[0] = finger; - memcpy (payload + 1, user_id, user_id_len); + G_DEBUG_HERE (); - synaptics_sensor_cmd (self, 0, BMKT_CMD_DEL_USER_FP, payload, user_id_len + 1, delete_msg_cb); + payload = g_malloc0 (1 + user_id_len); + payload[0] = finger; + memcpy (payload + 1, user_id, user_id_len); + + synaptics_sensor_cmd (self, 0, BMKT_CMD_DEL_USER_FP, payload, user_id_len + 1, delete_msg_cb); } static void -dev_probe(FpDevice *device) +dev_probe (FpDevice *device) { - FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); - GUsbDevice *usb_dev; - FpiUsbTransfer *transfer; - FpiByteReader reader; - GError *error = NULL; - guint16 status; - const guint8 *data; - gboolean read_ok = TRUE; - g_autofree gchar *serial = NULL; + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); + GUsbDevice *usb_dev; + FpiUsbTransfer *transfer; + FpiByteReader reader; + GError *error = NULL; + guint16 status; + const guint8 *data; + gboolean read_ok = TRUE; + g_autofree gchar *serial = NULL; - G_DEBUG_HERE(); + G_DEBUG_HERE (); - /* Claim usb interface */ - usb_dev = fpi_device_get_usb_device(device); - if (!g_usb_device_open (usb_dev, &error)) { - fpi_device_probe_complete (device, NULL, NULL, error); - return; - } + /* Claim usb interface */ + usb_dev = fpi_device_get_usb_device (device); + if (!g_usb_device_open (usb_dev, &error)) + { + fpi_device_probe_complete (device, NULL, NULL, error); + return; + } - if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error)) { - fpi_device_probe_complete (device, NULL, NULL, error); - return; - } + if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error)) + { + fpi_device_probe_complete (device, NULL, NULL, error); + return; + } - if (!g_usb_device_claim_interface (fpi_device_get_usb_device(device), 0, 0, &error)) - goto err_close; + if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error)) + goto err_close; - /* TODO: Do not do this synchronous. */ - transfer = fpi_usb_transfer_new (device); - fpi_usb_transfer_fill_bulk (transfer, USB_EP_REQUEST, SENSOR_FW_CMD_HEADER_LEN); - transfer->short_is_error = TRUE; - transfer->buffer[0] = SENSOR_CMD_GET_VERSION; - if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error)) - goto err_close; - fpi_usb_transfer_unref (transfer); + /* TODO: Do not do this synchronous. */ + transfer = fpi_usb_transfer_new (device); + fpi_usb_transfer_fill_bulk (transfer, USB_EP_REQUEST, SENSOR_FW_CMD_HEADER_LEN); + transfer->short_is_error = TRUE; + transfer->buffer[0] = SENSOR_CMD_GET_VERSION; + if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error)) + goto err_close; + fpi_usb_transfer_unref (transfer); - transfer = fpi_usb_transfer_new (device); - fpi_usb_transfer_fill_bulk (transfer, USB_EP_REPLY, 40); - if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error)) - goto err_close; + transfer = fpi_usb_transfer_new (device); + fpi_usb_transfer_fill_bulk (transfer, USB_EP_REPLY, 40); + if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error)) + goto err_close; - fpi_byte_reader_init (&reader, transfer->buffer, transfer->actual_length); + fpi_byte_reader_init (&reader, transfer->buffer, transfer->actual_length); - if (!fpi_byte_reader_get_uint16_le (&reader, &status)) { - g_warning ("Transfer in response to version query was too short"); - error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); - goto err_close; - } - if (status != 0) { - g_warning ("Device responded with error: %d", status); - error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); - goto err_close; - } + if (!fpi_byte_reader_get_uint16_le (&reader, &status)) + { + g_warning ("Transfer in response to version query was too short"); + error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); + goto err_close; + } + if (status != 0) + { + g_warning ("Device responded with error: %d", status); + error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); + goto err_close; + } - read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_time); - read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_num); - read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.version_major); - read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.version_minor); - read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.target); - read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.product); + read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_time); + read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_num); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.version_major); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.version_minor); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.target); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.product); - read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.silicon_rev); - read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.formal_release); - read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.platform); - read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.patch); - if (fpi_byte_reader_get_data (&reader, sizeof(self->mis_version.serial_number), &data)) - memcpy (self->mis_version.serial_number, data, sizeof(self->mis_version.serial_number)); - else - read_ok = FALSE; - read_ok &= fpi_byte_reader_get_uint16_le (&reader, &self->mis_version.security); - read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.iface); - read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.device_type); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.silicon_rev); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.formal_release); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.platform); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.patch); + if (fpi_byte_reader_get_data (&reader, sizeof (self->mis_version.serial_number), &data)) + memcpy (self->mis_version.serial_number, data, sizeof (self->mis_version.serial_number)); + else + read_ok = FALSE; + read_ok &= fpi_byte_reader_get_uint16_le (&reader, &self->mis_version.security); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.iface); + read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.device_type); - if (!read_ok) { - g_warning ("Transfer in response to verison query was too short"); - error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); - goto err_close; - } + if (!read_ok) + { + g_warning ("Transfer in response to verison query was too short"); + error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); + goto err_close; + } - fp_dbg("Build Time: %d", self->mis_version.build_time); - fp_dbg("Build Num: %d", self->mis_version.build_num); - fp_dbg("Version: %d.%d", self->mis_version.version_major, self->mis_version.version_minor); - fp_dbg("Target: %d", self->mis_version.target); - fp_dbg("Product: %d", self->mis_version.product); + fp_dbg ("Build Time: %d", self->mis_version.build_time); + fp_dbg ("Build Num: %d", self->mis_version.build_num); + fp_dbg ("Version: %d.%d", self->mis_version.version_major, self->mis_version.version_minor); + fp_dbg ("Target: %d", self->mis_version.target); + fp_dbg ("Product: %d", self->mis_version.product); - fpi_usb_transfer_unref (transfer); + fpi_usb_transfer_unref (transfer); - /* We need at least firmware version 10.1, and for 10.1 build 2989158 */ - if (self->mis_version.version_major < 10 || - self->mis_version.version_minor < 1 || - (self->mis_version.version_major == 10 && - self->mis_version.version_minor == 1 && - self->mis_version.build_num < 2989158)) - { - fp_warn ("Firmware version %d.%d with build number %d is unsupported", - self->mis_version.version_major, - self->mis_version.version_minor, - self->mis_version.build_num); + /* We need at least firmware version 10.1, and for 10.1 build 2989158 */ + if (self->mis_version.version_major < 10 || + self->mis_version.version_minor < 1 || + (self->mis_version.version_major == 10 && + self->mis_version.version_minor == 1 && + self->mis_version.build_num < 2989158)) + { + fp_warn ("Firmware version %d.%d with build number %d is unsupported", + self->mis_version.version_major, + self->mis_version.version_minor, + self->mis_version.build_num); - error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, - "Unsupported firmware version"); - goto err_close; - } + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Unsupported firmware version"); + goto err_close; + } - /* This is the same as the serial_number from above, hex encoded and somewhat reordered */ - /* Should we add in more, e.g. the chip revision? */ - if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0) - serial = g_strdup ("emulated-device"); - else - serial = g_usb_device_get_string_descriptor (usb_dev, - g_usb_device_get_serial_number_index (usb_dev), - &error); + /* This is the same as the serial_number from above, hex encoded and somewhat reordered */ + /* Should we add in more, e.g. the chip revision? */ + if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0) + serial = g_strdup ("emulated-device"); + else + serial = g_usb_device_get_string_descriptor (usb_dev, + g_usb_device_get_serial_number_index (usb_dev), + &error); - g_usb_device_close (usb_dev, NULL); + g_usb_device_close (usb_dev, NULL); - fpi_device_probe_complete (device, serial, NULL, error); + fpi_device_probe_complete (device, serial, NULL, error); - return; + return; err_close: - g_usb_device_close (usb_dev, NULL); - fpi_device_probe_complete (device, NULL, NULL, error); + g_usb_device_close (usb_dev, NULL); + fpi_device_probe_complete (device, NULL, NULL, error); } static void -fps_init_msg_cb(FpiDeviceSynaptics *self, - bmkt_response_t *resp, - GError *error) +fps_init_msg_cb (FpiDeviceSynaptics *self, + bmkt_response_t *resp, + GError *error) { - if (error) { - fpi_device_open_complete (FP_DEVICE (self), error); - return; - } + if (error) + { + fpi_device_open_complete (FP_DEVICE (self), error); + return; + } - /* BMKT_OPERATION_DENIED is returned if the sensor is already initialized */ - if (resp->result == BMKT_SUCCESS || resp->result == BMKT_OPERATION_DENIED) { - fpi_device_open_complete (FP_DEVICE (self), NULL); - } else { - g_warning ("Initializing fingerprint sensor failed with %d!", resp->result); - fpi_device_open_complete (FP_DEVICE (self), - fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); - } + /* BMKT_OPERATION_DENIED is returned if the sensor is already initialized */ + if (resp->result == BMKT_SUCCESS || resp->result == BMKT_OPERATION_DENIED) + { + fpi_device_open_complete (FP_DEVICE (self), NULL); + } + else + { + g_warning ("Initializing fingerprint sensor failed with %d!", resp->result); + fpi_device_open_complete (FP_DEVICE (self), + fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + } } static void -fps_deinit_cb(FpiDeviceSynaptics *self, - bmkt_response_t *resp, - GError *error) +fps_deinit_cb (FpiDeviceSynaptics *self, + bmkt_response_t *resp, + GError *error) { - /* Release usb interface */ - g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE (self)), 0, 0, &error); + /* Release usb interface */ + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (self)), 0, 0, &error); - g_clear_object (&self->interrupt_cancellable); + g_clear_object (&self->interrupt_cancellable); - if (!error) { - switch (resp->response_id) { - case BMKT_RSP_POWER_DOWN_READY: - fp_info("Fingerprint sensor ready to be powered down"); - break; - case BMKT_RSP_POWER_DOWN_FAIL: - fp_info("Failed to go to power down mode: %d", resp->result); - error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, - "Power down failed"); + if (!error) + { + switch (resp->response_id) + { + case BMKT_RSP_POWER_DOWN_READY: + fp_info ("Fingerprint sensor ready to be powered down"); + break; - break; - } - } - fpi_device_close_complete(FP_DEVICE (self), error); + case BMKT_RSP_POWER_DOWN_FAIL: + fp_info ("Failed to go to power down mode: %d", resp->result); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Power down failed"); + + break; + } + } + fpi_device_close_complete (FP_DEVICE (self), error); } static void dev_init (FpDevice *device) { - FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); - GError *error = NULL; + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); + GError *error = NULL; - G_DEBUG_HERE(); + G_DEBUG_HERE (); - self->interrupt_cancellable = g_cancellable_new (); + self->interrupt_cancellable = g_cancellable_new (); - if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error)) - goto error; + if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error)) + goto error; - /* Claim usb interface */ - if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error)) - goto error; + /* Claim usb interface */ + if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error)) + goto error; - synaptics_sensor_cmd (self, 0, BMKT_CMD_FPS_INIT, NULL, 0, fps_init_msg_cb); + synaptics_sensor_cmd (self, 0, BMKT_CMD_FPS_INIT, NULL, 0, fps_init_msg_cb); - return; + return; error: - fpi_device_open_complete (FP_DEVICE (self), error); + fpi_device_open_complete (FP_DEVICE (self), error); } static void -dev_exit(FpDevice *device) +dev_exit (FpDevice *device) { - FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); - G_DEBUG_HERE(); + G_DEBUG_HERE (); - synaptics_sensor_cmd (self, 0, BMKT_CMD_POWER_DOWN_NOTIFY, NULL, 0, fps_deinit_cb); + synaptics_sensor_cmd (self, 0, BMKT_CMD_POWER_DOWN_NOTIFY, NULL, 0, fps_deinit_cb); } static void -cancel(FpDevice *dev) +cancel (FpDevice *dev) { - FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS(dev); + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev); - /* We just send out a cancel command and hope for the best. */ - synaptics_sensor_cmd (self, -1, BMKT_CMD_CANCEL_OP, NULL, 0, NULL); + /* We just send out a cancel command and hope for the best. */ + synaptics_sensor_cmd (self, -1, BMKT_CMD_CANCEL_OP, NULL, 0, NULL); - /* Cancel any current interrupt transfer (resulting us to go into - * response reading mode again); then create a new cancellable - * for the next transfers. */ - g_cancellable_cancel (self->interrupt_cancellable); - g_clear_object (&self->interrupt_cancellable); - self->interrupt_cancellable = g_cancellable_new (); + /* Cancel any current interrupt transfer (resulting us to go into + * response reading mode again); then create a new cancellable + * for the next transfers. */ + g_cancellable_cancel (self->interrupt_cancellable); + g_clear_object (&self->interrupt_cancellable); + self->interrupt_cancellable = g_cancellable_new (); } static void -fpi_device_synaptics_init(FpiDeviceSynaptics *self) { +fpi_device_synaptics_init (FpiDeviceSynaptics *self) +{ } static void -fpi_device_synaptics_class_init(FpiDeviceSynapticsClass *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); +fpi_device_synaptics_class_init (FpiDeviceSynapticsClass *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); - dev_class->id = FP_COMPONENT; - dev_class->full_name = SYNAPTICS_DRIVER_FULLNAME; + dev_class->id = FP_COMPONENT; + dev_class->full_name = SYNAPTICS_DRIVER_FULLNAME; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->scan_type = FP_SCAN_TYPE_PRESS; - dev_class->id_table = id_table; - dev_class->nr_enroll_stages = ENROLL_SAMPLES; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->scan_type = FP_SCAN_TYPE_PRESS; + dev_class->id_table = id_table; + dev_class->nr_enroll_stages = ENROLL_SAMPLES; - dev_class->open = dev_init; - dev_class->close = dev_exit; - dev_class->probe = dev_probe; - dev_class->verify = verify; - dev_class->enroll = enroll; - dev_class->delete = delete_print; - dev_class->cancel = cancel; - dev_class->list = list; + dev_class->open = dev_init; + dev_class->close = dev_exit; + dev_class->probe = dev_probe; + dev_class->verify = verify; + dev_class->enroll = enroll; + dev_class->delete = delete_print; + dev_class->cancel = cancel; + dev_class->list = list; } diff --git a/libfprint/drivers/synaptics/synaptics.h b/libfprint/drivers/synaptics/synaptics.h index a0bc0b8e..cce6be9c 100644 --- a/libfprint/drivers/synaptics/synaptics.h +++ b/libfprint/drivers/synaptics/synaptics.h @@ -22,109 +22,109 @@ #include "fpi-device.h" #include "fpi-ssm.h" -#define SYNAPTICS_VENDOR_ID 0x06cb +#define SYNAPTICS_VENDOR_ID 0x06cb -G_DECLARE_FINAL_TYPE(FpiDeviceSynaptics, fpi_device_synaptics, FPI, DEVICE_SYNAPTICS, FpDevice) +G_DECLARE_FINAL_TYPE (FpiDeviceSynaptics, fpi_device_synaptics, FPI, DEVICE_SYNAPTICS, FpDevice) -#define MAX_TRANSFER_LEN 263 + 1 /* SPI Header */ + 2 /* VCSFW header */ +#define MAX_TRANSFER_LEN 263 + 1 /* SPI Header */ + 2 /* VCSFW header */ -#define USB_EP_REQUEST 0x01 -#define USB_EP_REPLY 0x81 -#define USB_EP_FINGERPRINT 0x82 -#define USB_EP_INTERRUPT 0x83 +#define USB_EP_REQUEST 0x01 +#define USB_EP_REPLY 0x81 +#define USB_EP_FINGERPRINT 0x82 +#define USB_EP_INTERRUPT 0x83 -#define USB_ASYNC_MESSAGE_PENDING 0x4 -#define USB_INTERRUPT_DATA_SIZE 7 +#define USB_ASYNC_MESSAGE_PENDING 0x4 +#define USB_INTERRUPT_DATA_SIZE 7 -#define SENSOR_CMD_GET_VERSION 1 -#define SENSOR_CMD_ACE_COMMAND 167 -#define SENSOR_CMD_ASYNCMSG_READ 168 +#define SENSOR_CMD_GET_VERSION 1 +#define SENSOR_CMD_ACE_COMMAND 167 +#define SENSOR_CMD_ASYNCMSG_READ 168 -#define SENSOR_FW_CMD_HEADER_LEN 1 -#define SENSOR_FW_REPLY_HEADER_LEN 2 +#define SENSOR_FW_CMD_HEADER_LEN 1 +#define SENSOR_FW_REPLY_HEADER_LEN 2 /* Number of enroll stages */ -#define ENROLL_SAMPLES 8 +#define ENROLL_SAMPLES 8 -#define SYNAPTICS_DRIVER_FULLNAME "Synaptics Sensors" +#define SYNAPTICS_DRIVER_FULLNAME "Synaptics Sensors" #include "bmkt.h" #include "bmkt_response.h" typedef struct bmkt_sensor_version { - uint32_t build_time; - uint32_t build_num; - uint8_t version_major; - uint8_t version_minor; - uint8_t target; - uint8_t product; - uint8_t silicon_rev; - uint8_t formal_release; - uint8_t platform; - uint8_t patch; - uint8_t serial_number[6]; - uint16_t security; - uint8_t iface; - uint8_t device_type; + uint32_t build_time; + uint32_t build_num; + uint8_t version_major; + uint8_t version_minor; + uint8_t target; + uint8_t product; + uint8_t silicon_rev; + uint8_t formal_release; + uint8_t platform; + uint8_t patch; + uint8_t serial_number[6]; + uint16_t security; + uint8_t iface; + uint8_t device_type; } bmkt_sensor_version_t; struct syna_enroll_resp_data { - int progress; + int progress; }; -typedef enum syna_state -{ - SYNA_STATE_UNINIT = 0, - SYNA_STATE_IDLE , - SYNA_STATE_ENROLL , - SYNA_STATE_IDENTIFY , - SYNA_STATE_IDENTIFY_DELAY_RESULT , - SYNA_STATE_VERIFY , - SYNA_STATE_VERIFY_DELAY_RESULT , - SYNA_STATE_DELETE , +typedef enum syna_state { + SYNA_STATE_UNINIT = 0, + SYNA_STATE_IDLE, + SYNA_STATE_ENROLL, + SYNA_STATE_IDENTIFY, + SYNA_STATE_IDENTIFY_DELAY_RESULT, + SYNA_STATE_VERIFY, + SYNA_STATE_VERIFY_DELAY_RESULT, + SYNA_STATE_DELETE, } syna_state_t; -typedef enum -{ - SYNAPTICS_CMD_SEND_PENDING = 0, - SYNAPTICS_CMD_GET_RESP, - SYNAPTICS_CMD_WAIT_INTERRUPT, - SYNAPTICS_CMD_SEND_ASYNC, - SYNAPTICS_CMD_RESTART, - SYNAPTICS_CMD_NUM_STATES, +typedef enum { + SYNAPTICS_CMD_SEND_PENDING = 0, + SYNAPTICS_CMD_GET_RESP, + SYNAPTICS_CMD_WAIT_INTERRUPT, + SYNAPTICS_CMD_SEND_ASYNC, + SYNAPTICS_CMD_RESTART, + SYNAPTICS_CMD_NUM_STATES, } SynapticsCmdState; -typedef void (*SynCmdMsgCallback) (FpiDeviceSynaptics *self, bmkt_response_t *resp, GError *error); +typedef void (*SynCmdMsgCallback) (FpiDeviceSynaptics *self, + bmkt_response_t *resp, + GError *error); struct _FpiDeviceSynaptics { - FpDevice parent; + FpDevice parent; - guint8 cmd_seq_num; - guint8 last_seq_num; - FpiSsm *cmd_ssm; - FpiUsbTransfer *cmd_pending_transfer; - gboolean cmd_complete_on_removal; - GError *cmd_complete_error; - void *cmd_complete_data; + guint8 cmd_seq_num; + guint8 last_seq_num; + FpiSsm *cmd_ssm; + FpiUsbTransfer *cmd_pending_transfer; + gboolean cmd_complete_on_removal; + GError *cmd_complete_error; + void *cmd_complete_data; - bmkt_sensor_version_t mis_version; + bmkt_sensor_version_t mis_version; - GCancellable *interrupt_cancellable; + GCancellable *interrupt_cancellable; - gint enroll_stage; - gboolean finger_on_sensor; - GPtrArray *list_result; + gint enroll_stage; + gboolean finger_on_sensor; + GPtrArray *list_result; - struct syna_enroll_resp_data enroll_resp_data; - syna_state_t state; + struct syna_enroll_resp_data enroll_resp_data; + syna_state_t state; }; #endif //__synaptics_h__ diff --git a/libfprint/drivers/upek_proto.c b/libfprint/drivers/upek_proto.c index 0ecc4b13..13c4d98a 100644 --- a/libfprint/drivers/upek_proto.c +++ b/libfprint/drivers/upek_proto.c @@ -21,46 +21,47 @@ #include "upek_proto.h" static const uint16_t crc_table[256] = { - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, - 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, - 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, - 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, - 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, - 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, - 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, - 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, - 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, - 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, - 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, - 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, - 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, - 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, - 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, - 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, - 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, - 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, - 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, - 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, - 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, - 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, - 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 }; uint16_t -udf_crc(unsigned char *buffer, size_t size) +udf_crc (unsigned char *buffer, size_t size) { - uint16_t crc = 0; - while (size--) - crc = (uint16_t) ((crc << 8) ^ - crc_table[((crc >> 8) & 0x00ff) ^ *buffer++]); - return crc; + uint16_t crc = 0; + + while (size--) + crc = (uint16_t) ((crc << 8) ^ + crc_table[((crc >> 8) & 0x00ff) ^ *buffer++]); + return crc; } diff --git a/libfprint/drivers/upek_proto.h b/libfprint/drivers/upek_proto.h index 2c3a617d..9459748b 100644 --- a/libfprint/drivers/upek_proto.h +++ b/libfprint/drivers/upek_proto.h @@ -21,4 +21,5 @@ #include #include -uint16_t udf_crc(unsigned char *buffer, size_t size); +uint16_t udf_crc (unsigned char *buffer, + size_t size); diff --git a/libfprint/drivers/upeksonly.c b/libfprint/drivers/upeksonly.c index a9e0f27d..7d206965 100644 --- a/libfprint/drivers/upeksonly.c +++ b/libfprint/drivers/upeksonly.c @@ -28,7 +28,7 @@ #include "drivers_api.h" #include "upeksonly.h" -#define CTRL_TIMEOUT 1000 +#define CTRL_TIMEOUT 1000 #define NUM_BULK_TRANSFERS 24 #define MAX_ROWS 2048 #define MIN_ROWS 64 @@ -39,1372 +39,1540 @@ #define DIFF_THRESHOLD 13 enum { - UPEKSONLY_2016, - UPEKSONLY_1000, - UPEKSONLY_1001, + UPEKSONLY_2016, + UPEKSONLY_1000, + UPEKSONLY_1001, }; enum sonly_kill_transfers_action { - NOT_KILLING = 0, + NOT_KILLING = 0, - /* abort a SSM with an error code */ - ABORT_SSM, + /* abort a SSM with an error code */ + ABORT_SSM, - /* report an image session error */ - IMG_SESSION_ERROR, + /* report an image session error */ + IMG_SESSION_ERROR, - /* iterate a SSM to the next state */ - ITERATE_SSM, + /* iterate a SSM to the next state */ + ITERATE_SSM, - /* call a callback */ - EXEC_CALLBACK, + /* call a callback */ + EXEC_CALLBACK, }; enum sonly_fs { - AWAIT_FINGER, - FINGER_DETECTED, - FINGER_REMOVED, + AWAIT_FINGER, + FINGER_DETECTED, + FINGER_REMOVED, }; -struct _FpiDeviceUpeksonly { - FpImageDevice parent; +struct _FpiDeviceUpeksonly +{ + FpImageDevice parent; - gboolean capturing; - gboolean deactivating; - guint8 read_reg_result; + gboolean capturing; + gboolean deactivating; + guint8 read_reg_result; - int dev_model; - int img_width; + int dev_model; + int img_width; - FpiSsm *loopsm; + FpiSsm *loopsm; - /* Do we really need multiple concurrent transfers? */ - GCancellable *img_cancellable; - GPtrArray *img_transfers; - int num_flying; + /* Do we really need multiple concurrent transfers? */ + GCancellable *img_cancellable; + GPtrArray *img_transfers; + int num_flying; - GSList *rows; - size_t num_rows; - unsigned char *rowbuf; - int rowbuf_offset; + GSList *rows; + size_t num_rows; + unsigned char *rowbuf; + int rowbuf_offset; - int wraparounds; - int num_blank; - int num_nonblank; - enum sonly_fs finger_state; - int last_seqnum; + int wraparounds; + int num_blank; + int num_nonblank; + enum sonly_fs finger_state; + int last_seqnum; - enum sonly_kill_transfers_action killing_transfers; - GError *kill_error; - union { - FpiSsm *kill_ssm; - void (*kill_cb)(FpImageDevice *dev); - }; + enum sonly_kill_transfers_action killing_transfers; + GError *kill_error; + union + { + FpiSsm *kill_ssm; + void (*kill_cb)(FpImageDevice *dev); + }; - struct fpi_line_asmbl_ctx assembling_ctx; + struct fpi_line_asmbl_ctx assembling_ctx; }; -G_DECLARE_FINAL_TYPE(FpiDeviceUpeksonly, fpi_device_upeksonly, FPI, - DEVICE_UPEKSONLY, FpImageDevice); -G_DEFINE_TYPE(FpiDeviceUpeksonly, fpi_device_upeksonly, FP_TYPE_IMAGE_DEVICE); +G_DECLARE_FINAL_TYPE (FpiDeviceUpeksonly, fpi_device_upeksonly, FPI, + DEVICE_UPEKSONLY, FpImageDevice); +G_DEFINE_TYPE (FpiDeviceUpeksonly, fpi_device_upeksonly, FP_TYPE_IMAGE_DEVICE); /* Calculate squared standard deviation of sum of two lines */ -static int upeksonly_get_deviation2(struct fpi_line_asmbl_ctx *ctx, - GSList *line1, GSList *line2) +static int +upeksonly_get_deviation2 (struct fpi_line_asmbl_ctx *ctx, + GSList *line1, GSList *line2) { - unsigned char *buf1 = line1->data, *buf2 = line2->data; - int res = 0, mean = 0, i; + unsigned char *buf1 = line1->data, *buf2 = line2->data; + int res = 0, mean = 0, i; - g_assert (ctx->line_width > 0); + g_assert (ctx->line_width > 0); - for (i = 0; i < ctx->line_width; i+= 2) - mean += (int)buf1[i + 1] + (int)buf2[i]; + for (i = 0; i < ctx->line_width; i += 2) + mean += (int) buf1[i + 1] + (int) buf2[i]; - mean /= (ctx->line_width / 2); + mean /= (ctx->line_width / 2); - for (i = 0; i < ctx->line_width; i+= 2) { - int dev = (int)buf1[i + 1] + (int)buf2[i] - mean; - res += dev*dev; - } + for (i = 0; i < ctx->line_width; i += 2) + { + int dev = (int) buf1[i + 1] + (int) buf2[i] - mean; + res += dev * dev; + } - return res / (ctx->line_width / 2); + return res / (ctx->line_width / 2); } -static unsigned char upeksonly_get_pixel(struct fpi_line_asmbl_ctx *ctx, - GSList *row, - unsigned x) +static unsigned char +upeksonly_get_pixel (struct fpi_line_asmbl_ctx *ctx, + GSList *row, + unsigned x) { - unsigned char *buf; - unsigned offset; + unsigned char *buf; + unsigned offset; - /* The scans from this device are rolled right by two columns */ - if (x < ctx->line_width - 2) - offset = x + 2; - else if ((x > ctx->line_width - 2) && (x < ctx->line_width)) - offset = x - (ctx->line_width - 2); - else - return 0; - /* Each 2nd pixel is shifted 2 pixels down */ - if ((!(x & 1)) && g_slist_next(row) && g_slist_next(g_slist_next(row))) - buf = g_slist_next(g_slist_next(row))->data; - else - buf = row->data; + /* The scans from this device are rolled right by two columns */ + if (x < ctx->line_width - 2) + offset = x + 2; + else if ((x > ctx->line_width - 2) && (x < ctx->line_width)) + offset = x - (ctx->line_width - 2); + else + return 0; + /* Each 2nd pixel is shifted 2 pixels down */ + if ((!(x & 1)) && g_slist_next (row) && g_slist_next (g_slist_next (row))) + buf = g_slist_next (g_slist_next (row))->data; + else + buf = row->data; - return buf[offset]; + return buf[offset]; } /***** IMAGE PROCESSING *****/ -static void free_img_transfers(FpiDeviceUpeksonly *sdev) +static void +free_img_transfers (FpiDeviceUpeksonly *sdev) { - g_cancellable_cancel (sdev->img_cancellable); - g_clear_object (&sdev->img_cancellable); - g_clear_pointer (&sdev->img_transfers, g_ptr_array_unref); + g_cancellable_cancel (sdev->img_cancellable); + g_clear_object (&sdev->img_cancellable); + g_clear_pointer (&sdev->img_transfers, g_ptr_array_unref); } -static void last_transfer_killed(FpImageDevice *dev) +static void +last_transfer_killed (FpImageDevice *dev) { - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); - switch (self->killing_transfers) { - case ABORT_SSM: - fp_dbg("abort ssm error %s", self->kill_error->message); - fpi_ssm_mark_failed(self->kill_ssm, g_steal_pointer (&self->kill_error)); - return; - case ITERATE_SSM: - fp_dbg("iterate ssm"); - fpi_ssm_next_state(self->kill_ssm); - return; - case IMG_SESSION_ERROR: - fp_dbg("session error %s", self->kill_error->message); - fpi_image_device_session_error(dev, g_steal_pointer (&self->kill_error)); - return; - default: - return; - } + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev); + + switch (self->killing_transfers) + { + case ABORT_SSM: + fp_dbg ("abort ssm error %s", self->kill_error->message); + fpi_ssm_mark_failed (self->kill_ssm, g_steal_pointer (&self->kill_error)); + return; + + case ITERATE_SSM: + fp_dbg ("iterate ssm"); + fpi_ssm_next_state (self->kill_ssm); + return; + + case IMG_SESSION_ERROR: + fp_dbg ("session error %s", self->kill_error->message); + fpi_image_device_session_error (dev, g_steal_pointer (&self->kill_error)); + return; + + default: + return; + } } -static void cancel_img_transfers(FpImageDevice *dev) +static void +cancel_img_transfers (FpImageDevice *dev) { - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev); - g_cancellable_cancel (self->img_cancellable); + g_cancellable_cancel (self->img_cancellable); - if (self->num_flying == 0) - last_transfer_killed(dev); + if (self->num_flying == 0) + last_transfer_killed (dev); } -static gboolean is_capturing(FpiDeviceUpeksonly *sdev) +static gboolean +is_capturing (FpiDeviceUpeksonly *sdev) { - return sdev->num_rows < MAX_ROWS && (sdev->finger_state != FINGER_REMOVED); + return sdev->num_rows < MAX_ROWS && (sdev->finger_state != FINGER_REMOVED); } -static void handoff_img(FpImageDevice *dev) +static void +handoff_img (FpImageDevice *dev) { - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); - FpImage *img; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev); + FpImage *img; - GSList *elem = self->rows; + GSList *elem = self->rows; - if (!elem) { - fp_err("no rows?"); - return; - } + if (!elem) + { + fp_err ("no rows?"); + return; + } - self->rows = g_slist_reverse(self->rows); + self->rows = g_slist_reverse (self->rows); - fp_dbg("%lu rows", self->num_rows); - img = fpi_assemble_lines(&self->assembling_ctx, self->rows, self->num_rows); + fp_dbg ("%lu rows", self->num_rows); + img = fpi_assemble_lines (&self->assembling_ctx, self->rows, self->num_rows); - g_slist_free_full(self->rows, g_free); - self->rows = NULL; + g_slist_free_full (self->rows, g_free); + self->rows = NULL; - fpi_image_device_image_captured(dev, img); - fpi_image_device_report_finger_status(dev, FALSE); + fpi_image_device_image_captured (dev, img); + fpi_image_device_report_finger_status (dev, FALSE); - self->killing_transfers = ITERATE_SSM; - self->kill_ssm = self->loopsm; - cancel_img_transfers(dev); + self->killing_transfers = ITERATE_SSM; + self->kill_ssm = self->loopsm; + cancel_img_transfers (dev); } -static void row_complete(FpImageDevice *dev) +static void +row_complete (FpImageDevice *dev) { - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); - self->rowbuf_offset = -1; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev); - if (self->num_rows > 0) { - unsigned char *lastrow = self->rows->data; - int std_sq_dev, mean_sq_diff; + self->rowbuf_offset = -1; - std_sq_dev = fpi_std_sq_dev(self->rowbuf, self->img_width); - mean_sq_diff = fpi_mean_sq_diff_norm(lastrow, self->rowbuf, - self->img_width); + if (self->num_rows > 0) + { + unsigned char *lastrow = self->rows->data; + int std_sq_dev, mean_sq_diff; - switch (self->finger_state) { - case AWAIT_FINGER: - if (self->deactivating) { - self->killing_transfers = ITERATE_SSM; - self->kill_ssm = self->loopsm; - cancel_img_transfers(dev); - } - fp_dbg("std_sq_dev: %d", std_sq_dev); - if (std_sq_dev > BLANK_THRESHOLD) { - self->num_nonblank++; - } else { - self->num_nonblank = 0; - } + std_sq_dev = fpi_std_sq_dev (self->rowbuf, self->img_width); + mean_sq_diff = fpi_mean_sq_diff_norm (lastrow, self->rowbuf, + self->img_width); - if (self->num_nonblank > FINGER_PRESENT_THRESHOLD) { - self->finger_state = FINGER_DETECTED; - fpi_image_device_report_finger_status(dev, - TRUE); - } else { - return; - } - break; - case FINGER_DETECTED: - case FINGER_REMOVED: - default: - break; - } + switch (self->finger_state) + { + case AWAIT_FINGER: + if (self->deactivating) + { + self->killing_transfers = ITERATE_SSM; + self->kill_ssm = self->loopsm; + cancel_img_transfers (dev); + } + fp_dbg ("std_sq_dev: %d", std_sq_dev); + if (std_sq_dev > BLANK_THRESHOLD) + self->num_nonblank++; + else + self->num_nonblank = 0; - if (std_sq_dev > BLANK_THRESHOLD) { - self->num_blank = 0; - } else { - self->num_blank++; - /* Don't consider the scan complete unless there's at least - * MIN_ROWS recorded or very long blank read occurred. - * - * Typical problem spot: one brief touch before starting the - * actual scan. Happens most commonly if scan is started - * from before the first joint resulting in a gap after the initial touch. - */ - if (self->num_blank > FINGER_REMOVED_THRESHOLD) { - self->finger_state = FINGER_REMOVED; - fp_dbg("detected finger removal. Blank rows: %d, Full rows: %lu", - self->num_blank, self->num_rows); - handoff_img(dev); - return; - } - } - fp_dbg("mean_sq_diff: %d, std_sq_dev: %d", mean_sq_diff, std_sq_dev); - fp_dbg("num_blank: %d", self->num_blank); - if (mean_sq_diff < DIFF_THRESHOLD) { - return; - } - } + if (self->num_nonblank > FINGER_PRESENT_THRESHOLD) + { + self->finger_state = FINGER_DETECTED; + fpi_image_device_report_finger_status (dev, + TRUE); + } + else + { + return; + } + break; - switch (self->finger_state) { - case AWAIT_FINGER: - if (!self->num_rows) { - self->rows = g_slist_prepend(self->rows, self->rowbuf); - self->num_rows++; - } else { - return; - } - break; - case FINGER_DETECTED: - case FINGER_REMOVED: - self->rows = g_slist_prepend(self->rows, self->rowbuf); - self->num_rows++; - break; - } - self->rowbuf = NULL; + case FINGER_DETECTED: + case FINGER_REMOVED: + default: + break; + } - if (self->num_rows >= MAX_ROWS) { - fp_dbg("row limit met"); - handoff_img(dev); - } + if (std_sq_dev > BLANK_THRESHOLD) + { + self->num_blank = 0; + } + else + { + self->num_blank++; + /* Don't consider the scan complete unless there's at least + * MIN_ROWS recorded or very long blank read occurred. + * + * Typical problem spot: one brief touch before starting the + * actual scan. Happens most commonly if scan is started + * from before the first joint resulting in a gap after the initial touch. + */ + if (self->num_blank > FINGER_REMOVED_THRESHOLD) + { + self->finger_state = FINGER_REMOVED; + fp_dbg ("detected finger removal. Blank rows: %d, Full rows: %lu", + self->num_blank, self->num_rows); + handoff_img (dev); + return; + } + } + fp_dbg ("mean_sq_diff: %d, std_sq_dev: %d", mean_sq_diff, std_sq_dev); + fp_dbg ("num_blank: %d", self->num_blank); + if (mean_sq_diff < DIFF_THRESHOLD) + return; + } + + switch (self->finger_state) + { + case AWAIT_FINGER: + if (!self->num_rows) + { + self->rows = g_slist_prepend (self->rows, self->rowbuf); + self->num_rows++; + } + else + { + return; + } + break; + + case FINGER_DETECTED: + case FINGER_REMOVED: + self->rows = g_slist_prepend (self->rows, self->rowbuf); + self->num_rows++; + break; + } + self->rowbuf = NULL; + + if (self->num_rows >= MAX_ROWS) + { + fp_dbg ("row limit met"); + handoff_img (dev); + } } /* add data to row buffer */ -static void add_to_rowbuf(FpImageDevice *dev, unsigned char *data, int size) +static void +add_to_rowbuf (FpImageDevice *dev, unsigned char *data, int size) { - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev); - memcpy(self->rowbuf + self->rowbuf_offset, data, size); - self->rowbuf_offset += size; - if (self->rowbuf_offset >= self->img_width) - row_complete(dev); + memcpy (self->rowbuf + self->rowbuf_offset, data, size); + self->rowbuf_offset += size; + if (self->rowbuf_offset >= self->img_width) + row_complete (dev); } -static void start_new_row(FpiDeviceUpeksonly *self, unsigned char *data, - int size) +static void +start_new_row (FpiDeviceUpeksonly *self, unsigned char *data, + int size) { - if (!self->rowbuf) - self->rowbuf = g_malloc(self->img_width); - memcpy(self->rowbuf, data, size); - self->rowbuf_offset = size; + if (!self->rowbuf) + self->rowbuf = g_malloc (self->img_width); + memcpy (self->rowbuf, data, size); + self->rowbuf_offset = size; } /* returns number of bytes left to be copied into rowbuf (capped to 62) * or -1 if we aren't capturing anything */ -static int rowbuf_remaining(FpiDeviceUpeksonly *sdev) +static int +rowbuf_remaining (FpiDeviceUpeksonly *sdev) { - int r; + int r; - if (sdev->rowbuf_offset == -1) - return -1; + if (sdev->rowbuf_offset == -1) + return -1; - r = sdev->img_width - sdev->rowbuf_offset; - if (r > 62) - r = 62; - return r; + r = sdev->img_width - sdev->rowbuf_offset; + if (r > 62) + r = 62; + return r; } -static void handle_packet(FpImageDevice *dev, unsigned char *data) +static void +handle_packet (FpImageDevice *dev, unsigned char *data) { - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); - guint16 seqnum = data[0] << 8 | data[1]; - int abs_base_addr; - int for_rowbuf; - int next_row_addr; - int diff; - unsigned char dummy_data[62]; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev); + guint16 seqnum = data[0] << 8 | data[1]; + int abs_base_addr; + int for_rowbuf; + int next_row_addr; + int diff; + unsigned char dummy_data[62]; - /* Init dummy data to something neutral */ - memset (dummy_data, 204, 62); + /* Init dummy data to something neutral */ + memset (dummy_data, 204, 62); - data += 2; /* skip sequence number */ - if (seqnum != self->last_seqnum + 1) { - if (seqnum != 0 && self->last_seqnum != 16383) { - int missing_data = seqnum - self->last_seqnum; - int i; - fp_warn("lost %d packets of data between %d and %d", missing_data, - self->last_seqnum, seqnum ); + data += 2; /* skip sequence number */ + if (seqnum != self->last_seqnum + 1) + { + if (seqnum != 0 && self->last_seqnum != 16383) + { + int missing_data = seqnum - self->last_seqnum; + int i; + fp_warn ("lost %d packets of data between %d and %d", missing_data, + self->last_seqnum, seqnum ); - /* Minimize distortions for readers that lose a lot of packets */ - for (i =1; i < missing_data; i++) { - abs_base_addr = (self->last_seqnum + 1) * 62; + /* Minimize distortions for readers that lose a lot of packets */ + for (i = 1; i < missing_data; i++) + { + abs_base_addr = (self->last_seqnum + 1) * 62; - /* If possible take the replacement data from last row */ - if (self->num_rows > 1) { - int row_left = self->img_width - self->rowbuf_offset; - unsigned char *last_row = g_slist_nth_data (self->rows, - 0); + /* If possible take the replacement data from last row */ + if (self->num_rows > 1) + { + int row_left = self->img_width - self->rowbuf_offset; + unsigned char *last_row = g_slist_nth_data (self->rows, + 0); - if (row_left >= 62) { - memcpy(dummy_data, - last_row + self->rowbuf_offset, - 62); - } else { - memcpy(dummy_data, - last_row + self->rowbuf_offset, - row_left); - memcpy(dummy_data + row_left, last_row , 62 - row_left); - } - } + if (row_left >= 62) + { + memcpy (dummy_data, + last_row + self->rowbuf_offset, + 62); + } + else + { + memcpy (dummy_data, + last_row + self->rowbuf_offset, + row_left); + memcpy (dummy_data + row_left, last_row, 62 - row_left); + } + } - fp_warn("adding dummy input for %d, i=%d", - self->last_seqnum + i, i); - for_rowbuf = rowbuf_remaining(self); - if (for_rowbuf != -1) { - add_to_rowbuf(dev, dummy_data, for_rowbuf); - /* row boundary */ - if (for_rowbuf < 62) { - start_new_row(self, - dummy_data + for_rowbuf, - 62 - for_rowbuf); - } - } else if (abs_base_addr % self->img_width == 0) { - start_new_row(self, dummy_data, 62); - } else { - /* does the data in the packet reside on a row boundary? - * if so capture it */ - next_row_addr = ((abs_base_addr / self->img_width) + 1) * self->img_width; - diff = next_row_addr - abs_base_addr; - if (diff < 62) - start_new_row(self, - dummy_data + diff, - 62 - diff); - } - self->last_seqnum = self->last_seqnum + 1; - } - } - } - if (seqnum <= self->last_seqnum) { - fp_dbg("detected wraparound"); - self->wraparounds++; - } + fp_warn ("adding dummy input for %d, i=%d", + self->last_seqnum + i, i); + for_rowbuf = rowbuf_remaining (self); + if (for_rowbuf != -1) + { + add_to_rowbuf (dev, dummy_data, for_rowbuf); + /* row boundary */ + if (for_rowbuf < 62) + { + start_new_row (self, + dummy_data + for_rowbuf, + 62 - for_rowbuf); + } + } + else if (abs_base_addr % self->img_width == 0) + { + start_new_row (self, dummy_data, 62); + } + else + { + /* does the data in the packet reside on a row boundary? + * if so capture it */ + next_row_addr = ((abs_base_addr / self->img_width) + 1) * self->img_width; + diff = next_row_addr - abs_base_addr; + if (diff < 62) + start_new_row (self, + dummy_data + diff, + 62 - diff); + } + self->last_seqnum = self->last_seqnum + 1; + } + } + } + if (seqnum <= self->last_seqnum) + { + fp_dbg ("detected wraparound"); + self->wraparounds++; + } - self->last_seqnum = seqnum; - seqnum += self->wraparounds * 16384; - abs_base_addr = seqnum * 62; + self->last_seqnum = seqnum; + seqnum += self->wraparounds * 16384; + abs_base_addr = seqnum * 62; - /* are we already capturing a row? if so append the data to the - * row buffer */ - for_rowbuf = rowbuf_remaining(self); - if (for_rowbuf != -1) { - add_to_rowbuf(dev, data, for_rowbuf); - /*row boundary*/ - if (for_rowbuf < 62) { - start_new_row(self, data + for_rowbuf, - 62 - for_rowbuf); - } - return; - } + /* are we already capturing a row? if so append the data to the + * row buffer */ + for_rowbuf = rowbuf_remaining (self); + if (for_rowbuf != -1) + { + add_to_rowbuf (dev, data, for_rowbuf); + /*row boundary*/ + if (for_rowbuf < 62) + start_new_row (self, data + for_rowbuf, + 62 - for_rowbuf); + return; + } - /* does the packet START on a boundary? if so we want it in full */ - if (abs_base_addr % self->img_width == 0) { - start_new_row(self, data, 62); - return; - } + /* does the packet START on a boundary? if so we want it in full */ + if (abs_base_addr % self->img_width == 0) + { + start_new_row (self, data, 62); + return; + } - /* does the data in the packet reside on a row boundary? - * if so capture it */ - next_row_addr = ((abs_base_addr / self->img_width) + 1) * self->img_width; - diff = next_row_addr - abs_base_addr; - if (diff < 62) - start_new_row(self, data + diff, 62 - diff); + /* does the data in the packet reside on a row boundary? + * if so capture it */ + next_row_addr = ((abs_base_addr / self->img_width) + 1) * self->img_width; + diff = next_row_addr - abs_base_addr; + if (diff < 62) + start_new_row (self, data + diff, 62 - diff); } -static void img_data_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +img_data_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE (device); - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); - int i; + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev); + int i; - self->num_flying--; + self->num_flying--; - if (self->killing_transfers) { - if (self->num_flying == 0) - last_transfer_killed(dev); + if (self->killing_transfers) + { + if (self->num_flying == 0) + last_transfer_killed (dev); - /* don't care about error or success if we're terminating */ - g_clear_error (&error); - return; - } + /* don't care about error or success if we're terminating */ + g_clear_error (&error); + return; + } - if (error) { - fp_warn("bad status %s, terminating session", error->message); - self->killing_transfers = IMG_SESSION_ERROR; + if (error) + { + fp_warn ("bad status %s, terminating session", error->message); + self->killing_transfers = IMG_SESSION_ERROR; - /* This cannot really happen, but just in case. */ - if (!self->kill_error) - self->kill_error = error; - else - g_error_free (error); + /* This cannot really happen, but just in case. */ + if (!self->kill_error) + self->kill_error = error; + else + g_error_free (error); - cancel_img_transfers(dev); - return; - } + cancel_img_transfers (dev); + return; + } - /* there are 64 packets in the transfer buffer - * each packet is 64 bytes in length - * the first 2 bytes are a sequence number - * then there are 62 bytes for image data - */ - for (i = 0; i < 4096; i += 64) { - if (!is_capturing(self)) - return; - handle_packet(dev, transfer->buffer + i); - } + /* there are 64 packets in the transfer buffer + * each packet is 64 bytes in length + * the first 2 bytes are a sequence number + * then there are 62 bytes for image data + */ + for (i = 0; i < 4096; i += 64) + { + if (!is_capturing (self)) + return; + handle_packet (dev, transfer->buffer + i); + } - if (is_capturing(self)) { - fpi_usb_transfer_submit (transfer, - 0, - self->img_cancellable, - img_data_cb, - user_data); - self->num_flying++; - } + if (is_capturing (self)) + { + fpi_usb_transfer_submit (transfer, + 0, + self->img_cancellable, + img_data_cb, + user_data); + self->num_flying++; + } } /***** STATE MACHINE HELPERS *****/ -struct write_regs_data { - FpDevice *dev; - FpiSsm *ssm; - FpiUsbTransfer *transfer; - const struct sonly_regwrite *regs; - size_t num_regs; - size_t regs_written; +struct write_regs_data +{ + FpDevice *dev; + FpiSsm *ssm; + FpiUsbTransfer *transfer; + const struct sonly_regwrite *regs; + size_t num_regs; + size_t regs_written; }; -static void write_regs_finished(struct write_regs_data *wrdata, GError *error) +static void +write_regs_finished (struct write_regs_data *wrdata, GError *error) { - if (!error) - fpi_ssm_next_state(wrdata->ssm); - else - fpi_ssm_mark_failed(wrdata->ssm, error); + if (!error) + fpi_ssm_next_state (wrdata->ssm); + else + fpi_ssm_mark_failed (wrdata->ssm, error); } -static void write_regs_iterate(struct write_regs_data *wrdata); +static void write_regs_iterate (struct write_regs_data *wrdata); -static void write_regs_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +write_regs_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - struct write_regs_data *wrdata = user_data; - if (error) { - write_regs_finished(wrdata, error); - return; - } + struct write_regs_data *wrdata = user_data; - wrdata->regs_written++; - write_regs_iterate(wrdata); -} + if (error) + { + write_regs_finished (wrdata, error); + return; + } -static void write_regs_iterate(struct write_regs_data *wrdata) -{ - FpiUsbTransfer *transfer; - const struct sonly_regwrite *regwrite; - - if (wrdata->regs_written >= wrdata->num_regs) { - write_regs_finished(wrdata, NULL); - return; - } - - regwrite = &wrdata->regs[wrdata->regs_written]; - fp_dbg("set %02x=%02x", regwrite->reg, regwrite->value); - - transfer = fpi_usb_transfer_new(wrdata->dev); - fpi_usb_transfer_fill_control(transfer, - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, - G_USB_DEVICE_REQUEST_TYPE_VENDOR, - G_USB_DEVICE_RECIPIENT_DEVICE, - 0x0c, - 0, - regwrite->reg, - 1); - transfer->short_is_error = TRUE; - transfer->ssm = wrdata->ssm; - fpi_usb_transfer_submit(transfer, CTRL_TIMEOUT, NULL, write_regs_cb, NULL); - fpi_usb_transfer_unref(transfer); - - transfer->buffer[0] = regwrite->value; + wrdata->regs_written++; + write_regs_iterate (wrdata); } static void -sm_write_regs(FpiSsm *ssm, - FpDevice *dev, - const struct sonly_regwrite *regs, - size_t num_regs) +write_regs_iterate (struct write_regs_data *wrdata) { - struct write_regs_data *wrdata = g_malloc(sizeof(*wrdata)); + FpiUsbTransfer *transfer; + const struct sonly_regwrite *regwrite; - wrdata->ssm = ssm; - wrdata->regs = regs; - wrdata->num_regs = num_regs; - wrdata->regs_written = 0; - wrdata->dev = dev; + if (wrdata->regs_written >= wrdata->num_regs) + { + write_regs_finished (wrdata, NULL); + return; + } - write_regs_iterate(wrdata); + regwrite = &wrdata->regs[wrdata->regs_written]; + fp_dbg ("set %02x=%02x", regwrite->reg, regwrite->value); + + transfer = fpi_usb_transfer_new (wrdata->dev); + fpi_usb_transfer_fill_control (transfer, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0x0c, + 0, + regwrite->reg, + 1); + transfer->short_is_error = TRUE; + transfer->ssm = wrdata->ssm; + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, write_regs_cb, NULL); + fpi_usb_transfer_unref (transfer); + + transfer->buffer[0] = regwrite->value; } -static void sm_write_reg_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +sm_write_regs (FpiSsm *ssm, + FpDevice *dev, + const struct sonly_regwrite *regs, + size_t num_regs) { - if (error) - fpi_ssm_mark_failed(transfer->ssm, error); - else - fpi_ssm_next_state(transfer->ssm); + struct write_regs_data *wrdata = g_malloc (sizeof (*wrdata)); + + wrdata->ssm = ssm; + wrdata->regs = regs; + wrdata->num_regs = num_regs; + wrdata->regs_written = 0; + wrdata->dev = dev; + + write_regs_iterate (wrdata); +} + +static void +sm_write_reg_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) +{ + if (error) + fpi_ssm_mark_failed (transfer->ssm, error); + else + fpi_ssm_next_state (transfer->ssm); } static void -sm_write_reg(FpiSsm *ssm, - FpImageDevice *dev, - guint8 reg, - guint8 value) +sm_write_reg (FpiSsm *ssm, + FpImageDevice *dev, + guint8 reg, + guint8 value) { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE (dev)); + FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); - fp_dbg("set %02x=%02x", reg, value); - fpi_usb_transfer_fill_control(transfer, - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, - G_USB_DEVICE_REQUEST_TYPE_VENDOR, - G_USB_DEVICE_RECIPIENT_DEVICE, - 0x0c, - 0, - reg, - 1); - transfer->short_is_error = TRUE; - transfer->ssm = ssm; - fpi_usb_transfer_submit(transfer, CTRL_TIMEOUT, NULL, sm_write_reg_cb, NULL); - fpi_usb_transfer_unref(transfer); + fp_dbg ("set %02x=%02x", reg, value); + fpi_usb_transfer_fill_control (transfer, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0x0c, + 0, + reg, + 1); + transfer->short_is_error = TRUE; + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, sm_write_reg_cb, NULL); + fpi_usb_transfer_unref (transfer); - transfer->buffer[0] = value; -} - -static void sm_read_reg_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) -{ - FpImageDevice *dev = FP_IMAGE_DEVICE(device); - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); - - if (error) { - fpi_ssm_mark_failed(transfer->ssm, error); - } else { - self->read_reg_result = transfer->buffer[0]; - fp_dbg("read reg result = %02x", self->read_reg_result); - fpi_ssm_next_state(transfer->ssm); - } - - g_free(transfer->buffer); + transfer->buffer[0] = value; } static void -sm_read_reg(FpiSsm *ssm, - FpImageDevice *dev, - guint8 reg) +sm_read_reg_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev); - fp_dbg("read reg %02x", reg); - fpi_usb_transfer_fill_control(transfer, - G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, - G_USB_DEVICE_REQUEST_TYPE_VENDOR, - G_USB_DEVICE_RECIPIENT_DEVICE, - 0x0c, - 0, - reg, - 8); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit(transfer, - CTRL_TIMEOUT, - NULL, - sm_read_reg_cb, - NULL); - fpi_usb_transfer_unref(transfer); -} + if (error) + { + fpi_ssm_mark_failed (transfer->ssm, error); + } + else + { + self->read_reg_result = transfer->buffer[0]; + fp_dbg ("read reg result = %02x", self->read_reg_result); + fpi_ssm_next_state (transfer->ssm); + } -static void sm_await_intr_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) -{ - FpImageDevice *dev = FP_IMAGE_DEVICE(device); - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); - - if (error) { - g_free(transfer->buffer); - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } - - fp_dbg("interrupt received: %02x %02x %02x %02x", - transfer->buffer[0], transfer->buffer[1], - transfer->buffer[2], transfer->buffer[3]); - g_free(transfer->buffer); - - self->finger_state = FINGER_DETECTED; - fpi_image_device_report_finger_status(dev, TRUE); - fpi_ssm_next_state(transfer->ssm); + g_free (transfer->buffer); } static void -sm_await_intr(FpiSsm *ssm, - FpImageDevice *dev) +sm_read_reg (FpiSsm *ssm, + FpImageDevice *dev, + guint8 reg) { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); + FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); - G_DEBUG_HERE(); + fp_dbg ("read reg %02x", reg); + fpi_usb_transfer_fill_control (transfer, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0x0c, + 0, + reg, + 8); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, + CTRL_TIMEOUT, + NULL, + sm_read_reg_cb, + NULL); + fpi_usb_transfer_unref (transfer); +} - fpi_usb_transfer_fill_interrupt (transfer, 0x83, 4); - transfer->short_is_error = TRUE; - transfer->ssm = ssm; +static void +sm_await_intr_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) +{ + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev); - /* NOTE: This was changed to be cancellable with the version 2 port! */ - fpi_usb_transfer_submit (transfer, - 0, - fpi_device_get_cancellable (FP_DEVICE (dev)), - sm_await_intr_cb, - NULL); - fpi_usb_transfer_unref (transfer); + if (error) + { + g_free (transfer->buffer); + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } + + fp_dbg ("interrupt received: %02x %02x %02x %02x", + transfer->buffer[0], transfer->buffer[1], + transfer->buffer[2], transfer->buffer[3]); + g_free (transfer->buffer); + + self->finger_state = FINGER_DETECTED; + fpi_image_device_report_finger_status (dev, TRUE); + fpi_ssm_next_state (transfer->ssm); +} + +static void +sm_await_intr (FpiSsm *ssm, + FpImageDevice *dev) +{ + FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + + G_DEBUG_HERE (); + + fpi_usb_transfer_fill_interrupt (transfer, 0x83, 4); + transfer->short_is_error = TRUE; + transfer->ssm = ssm; + + /* NOTE: This was changed to be cancellable with the version 2 port! */ + fpi_usb_transfer_submit (transfer, + 0, + fpi_device_get_cancellable (FP_DEVICE (dev)), + sm_await_intr_cb, + NULL); + fpi_usb_transfer_unref (transfer); } /***** AWAIT FINGER *****/ enum awfsm_2016_states { - AWFSM_2016_WRITEV_1, - AWFSM_2016_READ_01, - AWFSM_2016_WRITE_01, - AWFSM_2016_WRITEV_2, - AWFSM_2016_READ_13, - AWFSM_2016_WRITE_13, - AWFSM_2016_WRITEV_3, - AWFSM_2016_READ_07, - AWFSM_2016_WRITE_07, - AWFSM_2016_WRITEV_4, - AWFSM_2016_NUM_STATES, + AWFSM_2016_WRITEV_1, + AWFSM_2016_READ_01, + AWFSM_2016_WRITE_01, + AWFSM_2016_WRITEV_2, + AWFSM_2016_READ_13, + AWFSM_2016_WRITE_13, + AWFSM_2016_WRITEV_3, + AWFSM_2016_READ_07, + AWFSM_2016_WRITE_07, + AWFSM_2016_WRITEV_4, + AWFSM_2016_NUM_STATES, }; enum awfsm_1000_states { - AWFSM_1000_WRITEV_1, - AWFSM_1000_WRITEV_2, - AWFSM_1000_NUM_STATES, + AWFSM_1000_WRITEV_1, + AWFSM_1000_WRITEV_2, + AWFSM_1000_NUM_STATES, }; -static void awfsm_2016_run_state(FpiSsm *ssm, FpDevice *_dev, - void *user_data) +static void +awfsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - FpImageDevice *dev = user_data; - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case AWFSM_2016_WRITEV_1: - sm_write_regs(ssm, _dev, awfsm_2016_writev_1, G_N_ELEMENTS(awfsm_2016_writev_1)); - break; - case AWFSM_2016_READ_01: - sm_read_reg(ssm, dev, 0x01); - break; - case AWFSM_2016_WRITE_01: - if (self->read_reg_result != 0xc6) - sm_write_reg(ssm, dev, 0x01, 0x46); - else - sm_write_reg(ssm, dev, 0x01, 0xc6); - break; - case AWFSM_2016_WRITEV_2: - sm_write_regs(ssm, _dev, awfsm_2016_writev_2, G_N_ELEMENTS(awfsm_2016_writev_2)); - break; - case AWFSM_2016_READ_13: - sm_read_reg(ssm, dev, 0x13); - break; - case AWFSM_2016_WRITE_13: - if (self->read_reg_result != 0x45) - sm_write_reg(ssm, dev, 0x13, 0x05); - else - sm_write_reg(ssm, dev, 0x13, 0x45); - break; - case AWFSM_2016_WRITEV_3: - sm_write_regs(ssm, _dev, awfsm_2016_writev_3, G_N_ELEMENTS(awfsm_2016_writev_3)); - break; - case AWFSM_2016_READ_07: - sm_read_reg(ssm, dev, 0x07); - break; - case AWFSM_2016_WRITE_07: - if (self->read_reg_result != 0x10 && self->read_reg_result != 0x90) - fp_warn("odd reg7 value %x", self->read_reg_result); - sm_write_reg(ssm, dev, 0x07, self->read_reg_result); - break; - case AWFSM_2016_WRITEV_4: - sm_write_regs(ssm, _dev, awfsm_2016_writev_4, G_N_ELEMENTS(awfsm_2016_writev_4)); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case AWFSM_2016_WRITEV_1: + sm_write_regs (ssm, _dev, awfsm_2016_writev_1, G_N_ELEMENTS (awfsm_2016_writev_1)); + break; + + case AWFSM_2016_READ_01: + sm_read_reg (ssm, dev, 0x01); + break; + + case AWFSM_2016_WRITE_01: + if (self->read_reg_result != 0xc6) + sm_write_reg (ssm, dev, 0x01, 0x46); + else + sm_write_reg (ssm, dev, 0x01, 0xc6); + break; + + case AWFSM_2016_WRITEV_2: + sm_write_regs (ssm, _dev, awfsm_2016_writev_2, G_N_ELEMENTS (awfsm_2016_writev_2)); + break; + + case AWFSM_2016_READ_13: + sm_read_reg (ssm, dev, 0x13); + break; + + case AWFSM_2016_WRITE_13: + if (self->read_reg_result != 0x45) + sm_write_reg (ssm, dev, 0x13, 0x05); + else + sm_write_reg (ssm, dev, 0x13, 0x45); + break; + + case AWFSM_2016_WRITEV_3: + sm_write_regs (ssm, _dev, awfsm_2016_writev_3, G_N_ELEMENTS (awfsm_2016_writev_3)); + break; + + case AWFSM_2016_READ_07: + sm_read_reg (ssm, dev, 0x07); + break; + + case AWFSM_2016_WRITE_07: + if (self->read_reg_result != 0x10 && self->read_reg_result != 0x90) + fp_warn ("odd reg7 value %x", self->read_reg_result); + sm_write_reg (ssm, dev, 0x07, self->read_reg_result); + break; + + case AWFSM_2016_WRITEV_4: + sm_write_regs (ssm, _dev, awfsm_2016_writev_4, G_N_ELEMENTS (awfsm_2016_writev_4)); + break; + } } -static void awfsm_1000_run_state(FpiSsm *ssm, FpDevice *_dev, - void *user_data) +static void +awfsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - switch (fpi_ssm_get_cur_state(ssm)) { - case AWFSM_1000_WRITEV_1: - sm_write_regs(ssm, _dev, awfsm_1000_writev_1, G_N_ELEMENTS(awfsm_1000_writev_1)); - break; - case AWFSM_1000_WRITEV_2: - sm_write_regs(ssm, _dev, awfsm_1000_writev_2, G_N_ELEMENTS(awfsm_1000_writev_2)); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case AWFSM_1000_WRITEV_1: + sm_write_regs (ssm, _dev, awfsm_1000_writev_1, G_N_ELEMENTS (awfsm_1000_writev_1)); + break; + + case AWFSM_1000_WRITEV_2: + sm_write_regs (ssm, _dev, awfsm_1000_writev_2, G_N_ELEMENTS (awfsm_1000_writev_2)); + break; + } } /***** CAPTURE MODE *****/ enum capsm_2016_states { - CAPSM_2016_INIT, - CAPSM_2016_WRITE_15, - CAPSM_2016_WRITE_30, - CAPSM_2016_FIRE_BULK, - CAPSM_2016_WRITEV, - CAPSM_2016_NUM_STATES, + CAPSM_2016_INIT, + CAPSM_2016_WRITE_15, + CAPSM_2016_WRITE_30, + CAPSM_2016_FIRE_BULK, + CAPSM_2016_WRITEV, + CAPSM_2016_NUM_STATES, }; enum capsm_1000_states { - CAPSM_1000_INIT, - CAPSM_1000_FIRE_BULK, - CAPSM_1000_WRITEV, - CAPSM_1000_NUM_STATES, + CAPSM_1000_INIT, + CAPSM_1000_FIRE_BULK, + CAPSM_1000_WRITEV, + CAPSM_1000_NUM_STATES, }; enum capsm_1001_states { - CAPSM_1001_INIT, - CAPSM_1001_FIRE_BULK, - CAPSM_1001_WRITEV_1, - CAPSM_1001_WRITEV_2, - CAPSM_1001_WRITEV_3, - CAPSM_1001_WRITEV_4, - CAPSM_1001_WRITEV_5, - CAPSM_1001_NUM_STATES, + CAPSM_1001_INIT, + CAPSM_1001_FIRE_BULK, + CAPSM_1001_WRITEV_1, + CAPSM_1001_WRITEV_2, + CAPSM_1001_WRITEV_3, + CAPSM_1001_WRITEV_4, + CAPSM_1001_WRITEV_5, + CAPSM_1001_NUM_STATES, }; static void -capsm_fire_bulk(FpiSsm *ssm, - FpDevice *dev) +capsm_fire_bulk (FpiSsm *ssm, + FpDevice *dev) { - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); - int i; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev); + int i; - g_assert (self->capturing == FALSE); + g_assert (self->capturing == FALSE); - g_clear_object (&self->img_cancellable); - self->img_cancellable = g_cancellable_new (); - for (i = 0; i < self->img_transfers->len; i++) { - fpi_usb_transfer_submit(g_ptr_array_index (self->img_transfers, i), - 0, - self->img_cancellable, - img_data_cb, - NULL); - self->num_flying++; - } - self->capturing = TRUE; - fpi_ssm_next_state(ssm); + g_clear_object (&self->img_cancellable); + self->img_cancellable = g_cancellable_new (); + for (i = 0; i < self->img_transfers->len; i++) + { + fpi_usb_transfer_submit (g_ptr_array_index (self->img_transfers, i), + 0, + self->img_cancellable, + img_data_cb, + NULL); + self->num_flying++; + } + self->capturing = TRUE; + fpi_ssm_next_state (ssm); } -static void capsm_2016_run_state(FpiSsm *ssm, FpDevice *_dev, - void *user_data) +static void +capsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - FpImageDevice *dev = user_data; - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case CAPSM_2016_INIT: - self->rowbuf_offset = -1; - self->num_rows = 0; - self->wraparounds = -1; - self->num_blank = 0; - self->num_nonblank = 0; - self->finger_state = FINGER_DETECTED; - self->last_seqnum = 16383; - self->killing_transfers = 0; - fpi_ssm_next_state(ssm); - break; - case CAPSM_2016_WRITE_15: - sm_write_reg(ssm, dev, 0x15, 0x20); - break; - case CAPSM_2016_WRITE_30: - sm_write_reg(ssm, dev, 0x30, 0xe0); - break; - case CAPSM_2016_FIRE_BULK: ; - capsm_fire_bulk (ssm, _dev); - break; - case CAPSM_2016_WRITEV: - sm_write_regs(ssm, _dev, capsm_2016_writev, G_N_ELEMENTS(capsm_2016_writev)); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case CAPSM_2016_INIT: + self->rowbuf_offset = -1; + self->num_rows = 0; + self->wraparounds = -1; + self->num_blank = 0; + self->num_nonblank = 0; + self->finger_state = FINGER_DETECTED; + self->last_seqnum = 16383; + self->killing_transfers = 0; + fpi_ssm_next_state (ssm); + break; + + case CAPSM_2016_WRITE_15: + sm_write_reg (ssm, dev, 0x15, 0x20); + break; + + case CAPSM_2016_WRITE_30: + sm_write_reg (ssm, dev, 0x30, 0xe0); + break; + + case CAPSM_2016_FIRE_BULK:; + capsm_fire_bulk (ssm, _dev); + break; + + case CAPSM_2016_WRITEV: + sm_write_regs (ssm, _dev, capsm_2016_writev, G_N_ELEMENTS (capsm_2016_writev)); + break; + } } -static void capsm_1000_run_state(FpiSsm *ssm, FpDevice *_dev, - void *user_data) +static void +capsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(_dev); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case CAPSM_1000_INIT: - self->rowbuf_offset = -1; - self->num_rows = 0; - self->wraparounds = -1; - self->num_blank = 0; - self->num_nonblank = 0; - self->finger_state = FINGER_DETECTED; - self->last_seqnum = 16383; - self->killing_transfers = 0; - fpi_ssm_next_state(ssm); - break; - case CAPSM_1000_FIRE_BULK: ; - capsm_fire_bulk (ssm, _dev); - break; - case CAPSM_1000_WRITEV: - sm_write_regs(ssm, _dev, capsm_1000_writev, G_N_ELEMENTS(capsm_1000_writev)); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case CAPSM_1000_INIT: + self->rowbuf_offset = -1; + self->num_rows = 0; + self->wraparounds = -1; + self->num_blank = 0; + self->num_nonblank = 0; + self->finger_state = FINGER_DETECTED; + self->last_seqnum = 16383; + self->killing_transfers = 0; + fpi_ssm_next_state (ssm); + break; + + case CAPSM_1000_FIRE_BULK:; + capsm_fire_bulk (ssm, _dev); + break; + + case CAPSM_1000_WRITEV: + sm_write_regs (ssm, _dev, capsm_1000_writev, G_N_ELEMENTS (capsm_1000_writev)); + break; + } } -static void capsm_1001_run_state(FpiSsm *ssm, FpDevice *_dev, - void *user_data) +static void +capsm_1001_run_state (FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(_dev); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case CAPSM_1001_INIT: - self->rowbuf_offset = -1; - self->num_rows = 0; - self->wraparounds = -1; - self->num_blank = 0; - self->num_nonblank = 0; - self->finger_state = AWAIT_FINGER; - self->last_seqnum = 16383; - self->killing_transfers = 0; - fpi_ssm_next_state(ssm); - break; - case CAPSM_1001_FIRE_BULK: ; - capsm_fire_bulk (ssm, _dev); - break; - case CAPSM_1001_WRITEV_1: - sm_write_regs(ssm, _dev, capsm_1001_writev_1, G_N_ELEMENTS(capsm_1001_writev_1)); - break; - case CAPSM_1001_WRITEV_2: - sm_write_regs(ssm, _dev, capsm_1001_writev_2, G_N_ELEMENTS(capsm_1001_writev_2)); - break; - case CAPSM_1001_WRITEV_3: - sm_write_regs(ssm, _dev, capsm_1001_writev_3, G_N_ELEMENTS(capsm_1001_writev_3)); - break; - case CAPSM_1001_WRITEV_4: - sm_write_regs(ssm, _dev, capsm_1001_writev_4, G_N_ELEMENTS(capsm_1001_writev_4)); - break; - case CAPSM_1001_WRITEV_5: - sm_write_regs(ssm, _dev, capsm_1001_writev_5, G_N_ELEMENTS(capsm_1001_writev_5)); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case CAPSM_1001_INIT: + self->rowbuf_offset = -1; + self->num_rows = 0; + self->wraparounds = -1; + self->num_blank = 0; + self->num_nonblank = 0; + self->finger_state = AWAIT_FINGER; + self->last_seqnum = 16383; + self->killing_transfers = 0; + fpi_ssm_next_state (ssm); + break; + + case CAPSM_1001_FIRE_BULK:; + capsm_fire_bulk (ssm, _dev); + break; + + case CAPSM_1001_WRITEV_1: + sm_write_regs (ssm, _dev, capsm_1001_writev_1, G_N_ELEMENTS (capsm_1001_writev_1)); + break; + + case CAPSM_1001_WRITEV_2: + sm_write_regs (ssm, _dev, capsm_1001_writev_2, G_N_ELEMENTS (capsm_1001_writev_2)); + break; + + case CAPSM_1001_WRITEV_3: + sm_write_regs (ssm, _dev, capsm_1001_writev_3, G_N_ELEMENTS (capsm_1001_writev_3)); + break; + + case CAPSM_1001_WRITEV_4: + sm_write_regs (ssm, _dev, capsm_1001_writev_4, G_N_ELEMENTS (capsm_1001_writev_4)); + break; + + case CAPSM_1001_WRITEV_5: + sm_write_regs (ssm, _dev, capsm_1001_writev_5, G_N_ELEMENTS (capsm_1001_writev_5)); + break; + } } /***** DEINITIALIZATION *****/ enum deinitsm_2016_states { - DEINITSM_2016_WRITEV, - DEINITSM_2016_NUM_STATES, + DEINITSM_2016_WRITEV, + DEINITSM_2016_NUM_STATES, }; enum deinitsm_1000_states { - DEINITSM_1000_WRITEV, - DEINITSM_1000_NUM_STATES, + DEINITSM_1000_WRITEV, + DEINITSM_1000_NUM_STATES, }; enum deinitsm_1001_states { - DEINITSM_1001_WRITEV, - DEINITSM_1001_NUM_STATES, + DEINITSM_1001_WRITEV, + DEINITSM_1001_NUM_STATES, }; -static void deinitsm_2016_run_state(FpiSsm *ssm, FpDevice *_dev, - void *user_data) +static void +deinitsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - switch (fpi_ssm_get_cur_state(ssm)) { - case DEINITSM_2016_WRITEV: - sm_write_regs(ssm, _dev, deinitsm_2016_writev, G_N_ELEMENTS(deinitsm_2016_writev)); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case DEINITSM_2016_WRITEV: + sm_write_regs (ssm, _dev, deinitsm_2016_writev, G_N_ELEMENTS (deinitsm_2016_writev)); + break; + } } -static void deinitsm_1000_run_state(FpiSsm *ssm, FpDevice *_dev, - void *user_data) +static void +deinitsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - switch (fpi_ssm_get_cur_state(ssm)) { - case DEINITSM_1000_WRITEV: - sm_write_regs(ssm, _dev, deinitsm_1000_writev, G_N_ELEMENTS(deinitsm_1000_writev)); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case DEINITSM_1000_WRITEV: + sm_write_regs (ssm, _dev, deinitsm_1000_writev, G_N_ELEMENTS (deinitsm_1000_writev)); + break; + } } -static void deinitsm_1001_run_state(FpiSsm *ssm, FpDevice *_dev, - void *user_data) +static void +deinitsm_1001_run_state (FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - switch (fpi_ssm_get_cur_state(ssm)) { - case DEINITSM_1001_WRITEV: - sm_write_regs(ssm, _dev, deinitsm_1001_writev, G_N_ELEMENTS(deinitsm_1001_writev)); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case DEINITSM_1001_WRITEV: + sm_write_regs (ssm, _dev, deinitsm_1001_writev, G_N_ELEMENTS (deinitsm_1001_writev)); + break; + } } /***** INITIALIZATION *****/ enum initsm_2016_states { - INITSM_2016_WRITEV_1, - INITSM_2016_READ_09, - INITSM_2016_WRITE_09, - INITSM_2016_READ_13, - INITSM_2016_WRITE_13, - INITSM_2016_WRITE_04, - INITSM_2016_WRITE_05, - INITSM_2016_NUM_STATES, + INITSM_2016_WRITEV_1, + INITSM_2016_READ_09, + INITSM_2016_WRITE_09, + INITSM_2016_READ_13, + INITSM_2016_WRITE_13, + INITSM_2016_WRITE_04, + INITSM_2016_WRITE_05, + INITSM_2016_NUM_STATES, }; enum initsm_1000_states { - INITSM_1000_WRITEV_1, - INITSM_1000_NUM_STATES, + INITSM_1000_WRITEV_1, + INITSM_1000_NUM_STATES, }; enum initsm_1001_states { - INITSM_1001_WRITEV_1, - INITSM_1001_WRITEV_2, - INITSM_1001_WRITEV_3, - INITSM_1001_WRITEV_4, - INITSM_1001_WRITEV_5, - INITSM_1001_NUM_STATES, + INITSM_1001_WRITEV_1, + INITSM_1001_WRITEV_2, + INITSM_1001_WRITEV_3, + INITSM_1001_WRITEV_4, + INITSM_1001_WRITEV_5, + INITSM_1001_NUM_STATES, }; -static void initsm_2016_run_state(FpiSsm *ssm, FpDevice *_dev, - void *user_data) +static void +initsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - FpImageDevice *dev = user_data; - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case INITSM_2016_WRITEV_1: - sm_write_regs(ssm, _dev, initsm_2016_writev_1, G_N_ELEMENTS(initsm_2016_writev_1)); - break; - case INITSM_2016_READ_09: - sm_read_reg(ssm, dev, 0x09); - break; - case INITSM_2016_WRITE_09: - sm_write_reg(ssm, dev, 0x09, self->read_reg_result & ~0x08); - break; - case INITSM_2016_READ_13: - sm_read_reg(ssm, dev, 0x13); - break; - case INITSM_2016_WRITE_13: - sm_write_reg(ssm, dev, 0x13, self->read_reg_result & ~0x10); - break; - case INITSM_2016_WRITE_04: - sm_write_reg(ssm, dev, 0x04, 0x00); - break; - case INITSM_2016_WRITE_05: - sm_write_reg(ssm, dev, 0x05, 0x00); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case INITSM_2016_WRITEV_1: + sm_write_regs (ssm, _dev, initsm_2016_writev_1, G_N_ELEMENTS (initsm_2016_writev_1)); + break; + + case INITSM_2016_READ_09: + sm_read_reg (ssm, dev, 0x09); + break; + + case INITSM_2016_WRITE_09: + sm_write_reg (ssm, dev, 0x09, self->read_reg_result & ~0x08); + break; + + case INITSM_2016_READ_13: + sm_read_reg (ssm, dev, 0x13); + break; + + case INITSM_2016_WRITE_13: + sm_write_reg (ssm, dev, 0x13, self->read_reg_result & ~0x10); + break; + + case INITSM_2016_WRITE_04: + sm_write_reg (ssm, dev, 0x04, 0x00); + break; + + case INITSM_2016_WRITE_05: + sm_write_reg (ssm, dev, 0x05, 0x00); + break; + } } -static void initsm_1000_run_state(FpiSsm *ssm, FpDevice *_dev, - void *user_data) +static void +initsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - switch (fpi_ssm_get_cur_state(ssm)) { - case INITSM_1000_WRITEV_1: - sm_write_regs(ssm, _dev, initsm_1000_writev_1, G_N_ELEMENTS(initsm_1000_writev_1)); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case INITSM_1000_WRITEV_1: + sm_write_regs (ssm, _dev, initsm_1000_writev_1, G_N_ELEMENTS (initsm_1000_writev_1)); + break; + } } -static void initsm_1001_run_state(FpiSsm *ssm, FpDevice *_dev, - void *user_data) +static void +initsm_1001_run_state (FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - switch (fpi_ssm_get_cur_state(ssm)) { - case INITSM_1001_WRITEV_1: - sm_write_regs(ssm, _dev, initsm_1001_writev_1, G_N_ELEMENTS(initsm_1001_writev_1)); - break; - case INITSM_1001_WRITEV_2: - sm_write_regs(ssm, _dev, initsm_1001_writev_2, G_N_ELEMENTS(initsm_1001_writev_2)); - break; - case INITSM_1001_WRITEV_3: - sm_write_regs(ssm, _dev, initsm_1001_writev_3, G_N_ELEMENTS(initsm_1001_writev_3)); - break; - case INITSM_1001_WRITEV_4: - sm_write_regs(ssm, _dev, initsm_1001_writev_4, G_N_ELEMENTS(initsm_1001_writev_4)); - break; - case INITSM_1001_WRITEV_5: - sm_write_regs(ssm, _dev, initsm_1001_writev_5, G_N_ELEMENTS(initsm_1001_writev_5)); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case INITSM_1001_WRITEV_1: + sm_write_regs (ssm, _dev, initsm_1001_writev_1, G_N_ELEMENTS (initsm_1001_writev_1)); + break; + + case INITSM_1001_WRITEV_2: + sm_write_regs (ssm, _dev, initsm_1001_writev_2, G_N_ELEMENTS (initsm_1001_writev_2)); + break; + + case INITSM_1001_WRITEV_3: + sm_write_regs (ssm, _dev, initsm_1001_writev_3, G_N_ELEMENTS (initsm_1001_writev_3)); + break; + + case INITSM_1001_WRITEV_4: + sm_write_regs (ssm, _dev, initsm_1001_writev_4, G_N_ELEMENTS (initsm_1001_writev_4)); + break; + + case INITSM_1001_WRITEV_5: + sm_write_regs (ssm, _dev, initsm_1001_writev_5, G_N_ELEMENTS (initsm_1001_writev_5)); + break; + } } /***** CAPTURE LOOP *****/ enum loopsm_states { - LOOPSM_RUN_AWFSM, - LOOPSM_AWAIT_FINGER, - LOOPSM_RUN_CAPSM, - LOOPSM_CAPTURE, - LOOPSM_RUN_DEINITSM, - LOOPSM_FINAL, - LOOPSM_NUM_STATES, + LOOPSM_RUN_AWFSM, + LOOPSM_AWAIT_FINGER, + LOOPSM_RUN_CAPSM, + LOOPSM_CAPTURE, + LOOPSM_RUN_DEINITSM, + LOOPSM_FINAL, + LOOPSM_NUM_STATES, }; -static void loopsm_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +loopsm_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - FpImageDevice *dev = user_data; - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); + + switch (fpi_ssm_get_cur_state (ssm)) + { + case LOOPSM_RUN_AWFSM:; + switch (self->dev_model) + { + case UPEKSONLY_1001: + if (self->deactivating) + fpi_ssm_mark_completed (ssm); + else + fpi_ssm_next_state (ssm); + break; + + default: + if (self->deactivating) + { + fpi_ssm_mark_completed (ssm); + } + else + { + FpiSsm *awfsm = NULL; + switch (self->dev_model) + { + case UPEKSONLY_2016: + awfsm = fpi_ssm_new (FP_DEVICE (dev), + awfsm_2016_run_state, + AWFSM_2016_NUM_STATES, + dev); + break; + + case UPEKSONLY_1000: + awfsm = fpi_ssm_new (FP_DEVICE (dev), + awfsm_1000_run_state, + AWFSM_1000_NUM_STATES, + dev); + break; + } + fpi_ssm_start_subsm (ssm, awfsm); + } + break; + } + break; + + case LOOPSM_AWAIT_FINGER: + switch (self->dev_model) + { + case UPEKSONLY_1001: + fpi_ssm_next_state (ssm); + break; + + default: + sm_await_intr (ssm, dev); + break; + } + break; + + case LOOPSM_RUN_CAPSM:; + FpiSsm *capsm = NULL; + switch (self->dev_model) + { + case UPEKSONLY_2016: + capsm = fpi_ssm_new (FP_DEVICE (dev), + capsm_2016_run_state, + CAPSM_2016_NUM_STATES, dev); + break; + + case UPEKSONLY_1000: + capsm = fpi_ssm_new (FP_DEVICE (dev), + capsm_1000_run_state, + CAPSM_1000_NUM_STATES, dev); + break; + + case UPEKSONLY_1001: + capsm = fpi_ssm_new (FP_DEVICE (dev), + capsm_1001_run_state, + CAPSM_1001_NUM_STATES, dev); + break; + } + fpi_ssm_start_subsm (ssm, capsm); + break; + + case LOOPSM_CAPTURE: + break; + + case LOOPSM_RUN_DEINITSM:; + FpiSsm *deinitsm = NULL; + switch (self->dev_model) + { + case UPEKSONLY_2016: + deinitsm = fpi_ssm_new (FP_DEVICE (dev), + deinitsm_2016_run_state, + DEINITSM_2016_NUM_STATES, dev); + break; + + case UPEKSONLY_1000: + deinitsm = fpi_ssm_new (FP_DEVICE (dev), + deinitsm_1000_run_state, + DEINITSM_1000_NUM_STATES, dev); + break; + + case UPEKSONLY_1001: + deinitsm = fpi_ssm_new (FP_DEVICE (dev), + deinitsm_1001_run_state, + DEINITSM_1001_NUM_STATES, dev); + break; + } + self->capturing = FALSE; + fpi_ssm_start_subsm (ssm, deinitsm); + break; + + case LOOPSM_FINAL: + fpi_ssm_jump_to_state (ssm, LOOPSM_RUN_AWFSM); + break; + } - switch (fpi_ssm_get_cur_state(ssm)) { - case LOOPSM_RUN_AWFSM: ; - switch (self->dev_model) { - case UPEKSONLY_1001: - if (self->deactivating) { - fpi_ssm_mark_completed(ssm); - } else { - fpi_ssm_next_state(ssm); - } - break; - default: - if (self->deactivating) { - fpi_ssm_mark_completed(ssm); - } else { - FpiSsm *awfsm = NULL; - switch (self->dev_model) { - case UPEKSONLY_2016: - awfsm = fpi_ssm_new(FP_DEVICE(dev), - awfsm_2016_run_state, - AWFSM_2016_NUM_STATES, - dev); - break; - case UPEKSONLY_1000: - awfsm = fpi_ssm_new(FP_DEVICE(dev), - awfsm_1000_run_state, - AWFSM_1000_NUM_STATES, - dev); - break; - } - fpi_ssm_start_subsm(ssm, awfsm); - } - break; - } - break; - case LOOPSM_AWAIT_FINGER: - switch (self->dev_model) { - case UPEKSONLY_1001: - fpi_ssm_next_state(ssm); - break; - default: - sm_await_intr(ssm, dev); - break; - } - break; - case LOOPSM_RUN_CAPSM: ; - FpiSsm *capsm = NULL; - switch (self->dev_model) { - case UPEKSONLY_2016: - capsm = fpi_ssm_new(FP_DEVICE(dev), - capsm_2016_run_state, - CAPSM_2016_NUM_STATES, dev); - break; - case UPEKSONLY_1000: - capsm = fpi_ssm_new(FP_DEVICE(dev), - capsm_1000_run_state, - CAPSM_1000_NUM_STATES, dev); - break; - case UPEKSONLY_1001: - capsm = fpi_ssm_new(FP_DEVICE(dev), - capsm_1001_run_state, - CAPSM_1001_NUM_STATES, dev); - break; - } - fpi_ssm_start_subsm(ssm, capsm); - break; - case LOOPSM_CAPTURE: - break; - case LOOPSM_RUN_DEINITSM: ; - FpiSsm *deinitsm = NULL; - switch (self->dev_model) { - case UPEKSONLY_2016: - deinitsm = fpi_ssm_new(FP_DEVICE(dev), - deinitsm_2016_run_state, - DEINITSM_2016_NUM_STATES, dev); - break; - case UPEKSONLY_1000: - deinitsm = fpi_ssm_new(FP_DEVICE(dev), - deinitsm_1000_run_state, - DEINITSM_1000_NUM_STATES, dev); - break; - case UPEKSONLY_1001: - deinitsm = fpi_ssm_new(FP_DEVICE(dev), - deinitsm_1001_run_state, - DEINITSM_1001_NUM_STATES, dev); - break; - } - self->capturing = FALSE; - fpi_ssm_start_subsm(ssm, deinitsm); - break; - case LOOPSM_FINAL: - fpi_ssm_jump_to_state(ssm, LOOPSM_RUN_AWFSM); - break; - } - } /***** DRIVER STUFF *****/ -static void deactivate_done(FpImageDevice *dev, GError *error) +static void +deactivate_done (FpImageDevice *dev, GError *error) { - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev); - G_DEBUG_HERE(); - free_img_transfers(self); - g_free(self->rowbuf); - self->rowbuf = NULL; + G_DEBUG_HERE (); + free_img_transfers (self); + g_free (self->rowbuf); + self->rowbuf = NULL; - g_slist_free_full (self->rows, g_free); - self->rows = NULL; + g_slist_free_full (self->rows, g_free); + self->rows = NULL; - fpi_image_device_deactivate_complete(dev, error); + fpi_image_device_deactivate_complete (dev, error); } -static void dev_deactivate(FpImageDevice *dev) +static void +dev_deactivate (FpImageDevice *dev) { - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev); - if (!self->capturing) { - deactivate_done(dev, NULL); - return; - } + if (!self->capturing) + { + deactivate_done (dev, NULL); + return; + } - self->deactivating = TRUE; - self->killing_transfers = ITERATE_SSM; - self->kill_ssm = self->loopsm; - cancel_img_transfers(dev); + self->deactivating = TRUE; + self->killing_transfers = ITERATE_SSM; + self->kill_ssm = self->loopsm; + cancel_img_transfers (dev); } -static void loopsm_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, GError *error) +static void +loopsm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, GError *error) { - FpImageDevice *dev = user_data; - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); - fpi_ssm_free(ssm); + fpi_ssm_free (ssm); - if (self->deactivating) { - deactivate_done(dev, error); - return; - } + if (self->deactivating) + { + deactivate_done (dev, error); + return; + } - if (error) { - fpi_image_device_session_error(dev, error); - return; - } + if (error) + { + fpi_image_device_session_error (dev, error); + return; + } } -static void initsm_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +static void +initsm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - FpImageDevice *dev = user_data; - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); - fpi_ssm_free(ssm); - fpi_image_device_activate_complete(dev, error); - if (error) - return; + fpi_ssm_free (ssm); + fpi_image_device_activate_complete (dev, error); + if (error) + return; - self->loopsm = fpi_ssm_new(FP_DEVICE(dev), loopsm_run_state, - LOOPSM_NUM_STATES, dev); - fpi_ssm_start(self->loopsm, loopsm_complete); + self->loopsm = fpi_ssm_new (FP_DEVICE (dev), loopsm_run_state, + LOOPSM_NUM_STATES, dev); + fpi_ssm_start (self->loopsm, loopsm_complete); } -static void dev_activate(FpImageDevice *dev) +static void +dev_activate (FpImageDevice *dev) { - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY(dev); - FpiSsm *ssm = NULL; - int i; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev); + FpiSsm *ssm = NULL; + int i; - self->deactivating = FALSE; - self->capturing = FALSE; + self->deactivating = FALSE; + self->capturing = FALSE; - self->img_transfers = g_ptr_array_new_full(NUM_BULK_TRANSFERS, (GDestroyNotify) fpi_usb_transfer_unref); - self->num_flying = 0; + self->img_transfers = g_ptr_array_new_full (NUM_BULK_TRANSFERS, (GDestroyNotify) fpi_usb_transfer_unref); + self->num_flying = 0; - for (i = 0; i < self->img_transfers->len; i++) { - FpiUsbTransfer *transfer; + for (i = 0; i < self->img_transfers->len; i++) + { + FpiUsbTransfer *transfer; - transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); - fpi_usb_transfer_fill_bulk (transfer, 0x81, 4096); + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + fpi_usb_transfer_fill_bulk (transfer, 0x81, 4096); - g_ptr_array_add (self->img_transfers, transfer); - } + g_ptr_array_add (self->img_transfers, transfer); + } - switch (self->dev_model) { - case UPEKSONLY_2016: - ssm = fpi_ssm_new(FP_DEVICE(dev), initsm_2016_run_state, - INITSM_2016_NUM_STATES, dev); - break; - case UPEKSONLY_1000: - ssm = fpi_ssm_new(FP_DEVICE(dev), initsm_1000_run_state, - INITSM_1000_NUM_STATES, dev); - break; - case UPEKSONLY_1001: - ssm = fpi_ssm_new(FP_DEVICE(dev), initsm_1001_run_state, - INITSM_1001_NUM_STATES, dev); - break; - } - fpi_ssm_start(ssm, initsm_complete); + switch (self->dev_model) + { + case UPEKSONLY_2016: + ssm = fpi_ssm_new (FP_DEVICE (dev), initsm_2016_run_state, + INITSM_2016_NUM_STATES, dev); + break; + + case UPEKSONLY_1000: + ssm = fpi_ssm_new (FP_DEVICE (dev), initsm_1000_run_state, + INITSM_1000_NUM_STATES, dev); + break; + + case UPEKSONLY_1001: + ssm = fpi_ssm_new (FP_DEVICE (dev), initsm_1001_run_state, + INITSM_1001_NUM_STATES, dev); + break; + } + fpi_ssm_start (ssm, initsm_complete); } -static void dev_init(FpImageDevice *dev); +static void dev_init (FpImageDevice *dev); -static void dev_deinit(FpImageDevice *dev) +static void +dev_deinit (FpImageDevice *dev) { - GError *error = NULL; + GError *error = NULL; - g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), - 0, 0, &error); - fpi_image_device_close_complete(dev, error); + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), + 0, 0, &error); + fpi_image_device_close_complete (dev, error); } -static gint dev_discover(GUsbDevice *usb_device) +static gint +dev_discover (GUsbDevice *usb_device) { - guint16 pid = g_usb_device_get_pid (usb_device); - guint16 bcd = g_usb_device_get_release (usb_device); + guint16 pid = g_usb_device_get_pid (usb_device); + guint16 bcd = g_usb_device_get_release (usb_device); - if (pid == 0x2016) { - if (bcd == 1) /* Revision 1 is what we're interested in */ - return 1; - } - if (pid == 0x1000) { - if (bcd == 0x0033) /* Looking for revision 0.33 */ - return 1; - } + if (pid == 0x2016) + if (bcd == 1) /* Revision 1 is what we're interested in */ + return 1; + if (pid == 0x1000) + if (bcd == 0x0033) /* Looking for revision 0.33 */ + return 1; - if (pid == 0x1001) - return 1; + if (pid == 0x1001) + return 1; - return 0; + return 0; } -static const FpIdEntry id_table [ ] = { - { .vid = 0x147e, .pid = 0x2016, .driver_data = UPEKSONLY_2016 }, - { .vid = 0x147e, .pid = 0x1000, .driver_data = UPEKSONLY_1000 }, - { .vid = 0x147e, .pid = 0x1001, .driver_data = UPEKSONLY_1001 }, - { .vid = 0, .pid = 0, .driver_data = 0 }, +static const FpIdEntry id_table[] = { + { .vid = 0x147e, .pid = 0x2016, .driver_data = UPEKSONLY_2016 }, + { .vid = 0x147e, .pid = 0x1000, .driver_data = UPEKSONLY_1000 }, + { .vid = 0x147e, .pid = 0x1001, .driver_data = UPEKSONLY_1001 }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -static void fpi_device_upeksonly_init(FpiDeviceUpeksonly *self) { -} -static void fpi_device_upeksonly_class_init(FpiDeviceUpeksonlyClass *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); - - dev_class->id = "upeksonly"; - dev_class->full_name = "UPEK TouchStrip Sensor-Only"; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->id_table = id_table; - dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - - dev_class->usb_discover = dev_discover; - - img_class->img_open = dev_init; - img_class->img_close = dev_deinit; - img_class->activate = dev_activate; - img_class->deactivate = dev_deactivate; - - img_class->img_width = -1; - img_class->img_height = -1; -} - -static void dev_init(FpImageDevice *dev) +static void +fpi_device_upeksonly_init (FpiDeviceUpeksonly *self) { - GError *error = NULL; - FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev); +} +static void +fpi_device_upeksonly_class_init (FpiDeviceUpeksonlyClass *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); - if (!g_usb_device_set_configuration (fpi_device_get_usb_device(FP_DEVICE(dev)), 1, &error)) { - fp_err("could not set configuration 1"); - fpi_image_device_open_complete(dev, error); - } + dev_class->id = "upeksonly"; + dev_class->full_name = "UPEK TouchStrip Sensor-Only"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - if (!g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error)) { - fpi_image_device_open_complete(dev, error); - return; - } + dev_class->usb_discover = dev_discover; - self->assembling_ctx.max_height = 1024; - self->assembling_ctx.resolution = 8; - self->assembling_ctx.median_filter_size = 25; - self->assembling_ctx.max_search_offset = 30; - self->assembling_ctx.get_deviation = upeksonly_get_deviation2; - self->assembling_ctx.get_pixel = upeksonly_get_pixel; + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; - self = FPI_DEVICE_UPEKSONLY(dev); - self->dev_model = (int)fpi_device_get_driver_data (FP_DEVICE (dev)); - switch (self->dev_model) { - case UPEKSONLY_1000: - self->img_width = IMG_WIDTH_1000; - self->assembling_ctx.line_width = IMG_WIDTH_1000; - break; - case UPEKSONLY_1001: - self->img_width = IMG_WIDTH_1001; - self->assembling_ctx.line_width = IMG_WIDTH_1001; - - /* The sensor resolution is too low for the normal threshold. */ - fpi_image_device_set_bz3_threshold (dev, 25); - break; - case UPEKSONLY_2016: - self->img_width = IMG_WIDTH_2016; - self->assembling_ctx.line_width = IMG_WIDTH_2016; - break; - default: - g_assert_not_reached (); - } - fpi_image_device_open_complete(dev, NULL); + img_class->img_width = -1; + img_class->img_height = -1; } +static void +dev_init (FpImageDevice *dev) +{ + GError *error = NULL; + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (dev); + if (!g_usb_device_set_configuration (fpi_device_get_usb_device (FP_DEVICE (dev)), 1, &error)) + { + fp_err ("could not set configuration 1"); + fpi_image_device_open_complete (dev, error); + } + + if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error)) + { + fpi_image_device_open_complete (dev, error); + return; + } + + self->assembling_ctx.max_height = 1024; + self->assembling_ctx.resolution = 8; + self->assembling_ctx.median_filter_size = 25; + self->assembling_ctx.max_search_offset = 30; + self->assembling_ctx.get_deviation = upeksonly_get_deviation2; + self->assembling_ctx.get_pixel = upeksonly_get_pixel; + + self = FPI_DEVICE_UPEKSONLY (dev); + self->dev_model = (int) fpi_device_get_driver_data (FP_DEVICE (dev)); + switch (self->dev_model) + { + case UPEKSONLY_1000: + self->img_width = IMG_WIDTH_1000; + self->assembling_ctx.line_width = IMG_WIDTH_1000; + break; + + case UPEKSONLY_1001: + self->img_width = IMG_WIDTH_1001; + self->assembling_ctx.line_width = IMG_WIDTH_1001; + + /* The sensor resolution is too low for the normal threshold. */ + fpi_image_device_set_bz3_threshold (dev, 25); + break; + + case UPEKSONLY_2016: + self->img_width = IMG_WIDTH_2016; + self->assembling_ctx.line_width = IMG_WIDTH_2016; + break; + + default: + g_assert_not_reached (); + } + fpi_image_device_open_complete (dev, NULL); +} diff --git a/libfprint/drivers/upeksonly.h b/libfprint/drivers/upeksonly.h index cd48a320..611afda5 100644 --- a/libfprint/drivers/upeksonly.h +++ b/libfprint/drivers/upeksonly.h @@ -23,297 +23,298 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#define IMG_WIDTH_2016 288 -#define IMG_WIDTH_1000 288 -#define IMG_WIDTH_1001 216 +#define IMG_WIDTH_2016 288 +#define IMG_WIDTH_1000 288 +#define IMG_WIDTH_1001 216 -struct sonly_regwrite { - guint8 reg; - guint8 value; +struct sonly_regwrite +{ + guint8 reg; + guint8 value; }; /***** AWAIT FINGER *****/ static const struct sonly_regwrite awfsm_2016_writev_1[] = { - { 0x0a, 0x00 }, { 0x0a, 0x00 }, { 0x09, 0x20 }, { 0x03, 0x3b }, - { 0x00, 0x67 }, { 0x00, 0x67 }, + { 0x0a, 0x00 }, { 0x0a, 0x00 }, { 0x09, 0x20 }, { 0x03, 0x3b }, + { 0x00, 0x67 }, { 0x00, 0x67 }, }; static const struct sonly_regwrite awfsm_1000_writev_1[] = { - /* Initialize sensor settings */ - { 0x0a, 0x00 }, { 0x09, 0x20 }, { 0x03, 0x37 }, { 0x00, 0x5f }, - { 0x01, 0x6e }, { 0x01, 0xee }, { 0x0c, 0x13 }, { 0x0d, 0x0d }, - { 0x0e, 0x0e }, { 0x0f, 0x0d }, + /* Initialize sensor settings */ + { 0x0a, 0x00 }, { 0x09, 0x20 }, { 0x03, 0x37 }, { 0x00, 0x5f }, + { 0x01, 0x6e }, { 0x01, 0xee }, { 0x0c, 0x13 }, { 0x0d, 0x0d }, + { 0x0e, 0x0e }, { 0x0f, 0x0d }, - { 0x13, 0x05 }, { 0x13, 0x45 }, + { 0x13, 0x05 }, { 0x13, 0x45 }, - /* Initialize finger detection registers (not enabling yet) */ - { 0x30, 0xe0 }, { 0x15, 0x26 }, + /* Initialize finger detection registers (not enabling yet) */ + { 0x30, 0xe0 }, { 0x15, 0x26 }, - { 0x12, 0x01 }, { 0x20, 0x01 }, { 0x07, 0x10 }, - { 0x10, 0x00 }, { 0x11, 0xbf }, + { 0x12, 0x01 }, { 0x20, 0x01 }, { 0x07, 0x10 }, + { 0x10, 0x00 }, { 0x11, 0xbf }, }; static const struct sonly_regwrite awfsm_2016_writev_2[] = { - { 0x01, 0xc6 }, { 0x0c, 0x13 }, { 0x0d, 0x0d }, { 0x0e, 0x0e }, - { 0x0f, 0x0d }, { 0x0b, 0x00 }, + { 0x01, 0xc6 }, { 0x0c, 0x13 }, { 0x0d, 0x0d }, { 0x0e, 0x0e }, + { 0x0f, 0x0d }, { 0x0b, 0x00 }, }; static const struct sonly_regwrite awfsm_1000_writev_2[] = { - /* Enable finger detection */ - { 0x30, 0xe1 }, { 0x15, 0x06 }, { 0x15, 0x86 }, + /* Enable finger detection */ + { 0x30, 0xe1 }, { 0x15, 0x06 }, { 0x15, 0x86 }, }; static const struct sonly_regwrite awfsm_2016_writev_3[] = { - { 0x13, 0x45 }, { 0x30, 0xe0 }, { 0x12, 0x01 }, { 0x20, 0x01 }, - { 0x09, 0x20 }, { 0x0a, 0x00 }, { 0x30, 0xe0 }, { 0x20, 0x01 }, + { 0x13, 0x45 }, { 0x30, 0xe0 }, { 0x12, 0x01 }, { 0x20, 0x01 }, + { 0x09, 0x20 }, { 0x0a, 0x00 }, { 0x30, 0xe0 }, { 0x20, 0x01 }, }; static const struct sonly_regwrite awfsm_2016_writev_4[] = { - { 0x08, 0x00 }, { 0x10, 0x00 }, { 0x12, 0x01 }, { 0x11, 0xbf }, - { 0x12, 0x01 }, { 0x07, 0x10 }, { 0x07, 0x10 }, { 0x04, 0x00 },\ - { 0x05, 0x00 }, { 0x0b, 0x00 }, - - /* enter finger detection mode */ - { 0x15, 0x20 }, { 0x30, 0xe1 }, { 0x15, 0x24 }, { 0x15, 0x04 }, - { 0x15, 0x84 }, + { 0x08, 0x00 }, { 0x10, 0x00 }, { 0x12, 0x01 }, { 0x11, 0xbf }, + { 0x12, 0x01 }, { 0x07, 0x10 }, { 0x07, 0x10 }, { 0x04, 0x00 }, \ + { 0x05, 0x00 }, { 0x0b, 0x00 }, + + /* enter finger detection mode */ + { 0x15, 0x20 }, { 0x30, 0xe1 }, { 0x15, 0x24 }, { 0x15, 0x04 }, + { 0x15, 0x84 }, }; /***** CAPTURE MODE *****/ static const struct sonly_regwrite capsm_2016_writev[] = { - /* enter capture mode */ - { 0x09, 0x28 }, { 0x13, 0x55 }, { 0x0b, 0x80 }, { 0x04, 0x00 }, - { 0x05, 0x00 }, + /* enter capture mode */ + { 0x09, 0x28 }, { 0x13, 0x55 }, { 0x0b, 0x80 }, { 0x04, 0x00 }, + { 0x05, 0x00 }, }; static const struct sonly_regwrite capsm_1000_writev[] = { - { 0x08, 0x80 }, { 0x13, 0x55 }, { 0x0b, 0x80 }, /* Enter capture mode */ + { 0x08, 0x80 }, { 0x13, 0x55 }, { 0x0b, 0x80 }, /* Enter capture mode */ }; static const struct sonly_regwrite capsm_1001_writev_1[] = { - { 0x1a, 0x02 }, - { 0x4a, 0x9d }, - { 0x4e, 0x05 }, + { 0x1a, 0x02 }, + { 0x4a, 0x9d }, + { 0x4e, 0x05 }, }; static const struct sonly_regwrite capsm_1001_writev_2[] = { - { 0x4d, 0xc0 }, { 0x4e, 0x09 }, + { 0x4d, 0xc0 }, { 0x4e, 0x09 }, }; static const struct sonly_regwrite capsm_1001_writev_3[] = { - { 0x4a, 0x9c }, - { 0x1a, 0x00 }, - { 0x0b, 0x00 }, - { 0x04, 0x00 }, - { 0x05, 0x00 }, - { 0x1a, 0x02 }, - { 0x4a, 0x9d }, - { 0x4d, 0x40 }, { 0x4e, 0x09 }, + { 0x4a, 0x9c }, + { 0x1a, 0x00 }, + { 0x0b, 0x00 }, + { 0x04, 0x00 }, + { 0x05, 0x00 }, + { 0x1a, 0x02 }, + { 0x4a, 0x9d }, + { 0x4d, 0x40 }, { 0x4e, 0x09 }, }; static const struct sonly_regwrite capsm_1001_writev_4[] = { - { 0x4a, 0x9c }, - { 0x1a, 0x00 }, - { 0x1a, 0x02 }, - { 0x4a, 0x9d }, - { 0x4e, 0x08 }, + { 0x4a, 0x9c }, + { 0x1a, 0x00 }, + { 0x1a, 0x02 }, + { 0x4a, 0x9d }, + { 0x4e, 0x08 }, }; static const struct sonly_regwrite capsm_1001_writev_5[] = { - { 0x4a, 0x9c }, - { 0x1a, 0x00 }, - { 0x1a, 0x02 }, - { 0x00, 0x5f }, { 0x01, 0xee }, - { 0x03, 0x2c }, - { 0x07, 0x00 }, { 0x08, 0x00 }, { 0x09, 0x29 }, { 0x0a, 0x00 }, { 0x0b, 0x00 }, { 0x0c, 0x13 }, { 0x0d, 0x0d }, { 0x0e, 0x0e }, - { 0x0f, 0x0d }, { 0x10, 0x00 }, { 0x11, 0x8f }, { 0x12, 0x01 }, { 0x13, 0x45 }, - { 0x15, 0x26 }, - { 0x1e, 0x02 }, - { 0x20, 0x01 }, - { 0x25, 0x8f }, - { 0x27, 0x23 }, - { 0x30, 0xe0 }, - { 0x07, 0x10 }, - { 0x09, 0x21 }, - { 0x13, 0x75 }, - { 0x0b, 0x80 }, + { 0x4a, 0x9c }, + { 0x1a, 0x00 }, + { 0x1a, 0x02 }, + { 0x00, 0x5f }, { 0x01, 0xee }, + { 0x03, 0x2c }, + { 0x07, 0x00 }, { 0x08, 0x00 }, { 0x09, 0x29 }, { 0x0a, 0x00 }, { 0x0b, 0x00 }, { 0x0c, 0x13 }, { 0x0d, 0x0d }, { 0x0e, 0x0e }, + { 0x0f, 0x0d }, { 0x10, 0x00 }, { 0x11, 0x8f }, { 0x12, 0x01 }, { 0x13, 0x45 }, + { 0x15, 0x26 }, + { 0x1e, 0x02 }, + { 0x20, 0x01 }, + { 0x25, 0x8f }, + { 0x27, 0x23 }, + { 0x30, 0xe0 }, + { 0x07, 0x10 }, + { 0x09, 0x21 }, + { 0x13, 0x75 }, + { 0x0b, 0x80 }, }; /***** DEINITIALIZATION *****/ static const struct sonly_regwrite deinitsm_2016_writev[] = { - /* reset + enter low power mode */ - { 0x0b, 0x00 }, { 0x09, 0x20 }, { 0x13, 0x45 }, { 0x13, 0x45 }, + /* reset + enter low power mode */ + { 0x0b, 0x00 }, { 0x09, 0x20 }, { 0x13, 0x45 }, { 0x13, 0x45 }, }; static const struct sonly_regwrite deinitsm_1000_writev[] = { - { 0x15, 0x26 }, { 0x30, 0xe0 }, /* Disable finger detection */ + { 0x15, 0x26 }, { 0x30, 0xe0 }, /* Disable finger detection */ - { 0x0b, 0x00 }, { 0x13, 0x45 }, { 0x08, 0x00 }, /* Disable capture mode */ + { 0x0b, 0x00 }, { 0x13, 0x45 }, { 0x08, 0x00 }, /* Disable capture mode */ }; static const struct sonly_regwrite deinitsm_1001_writev[] = { - { 0x0b, 0x00 }, - { 0x13, 0x45 }, - { 0x09, 0x29 }, - { 0x1a, 0x00 }, + { 0x0b, 0x00 }, + { 0x13, 0x45 }, + { 0x09, 0x29 }, + { 0x1a, 0x00 }, }; /***** INITIALIZATION *****/ static const struct sonly_regwrite initsm_2016_writev_1[] = { - { 0x49, 0x00 }, - - /* BSAPI writes different values to register 0x3e each time. I initially - * thought this was some kind of clever authentication, but just blasting - * these sniffed values each time seems to work. */ - { 0x3e, 0x83 }, { 0x3e, 0x4f }, { 0x3e, 0x0f }, { 0x3e, 0xbf }, - { 0x3e, 0x45 }, { 0x3e, 0x35 }, { 0x3e, 0x1c }, { 0x3e, 0xae }, + { 0x49, 0x00 }, - { 0x44, 0x01 }, { 0x43, 0x06 }, { 0x43, 0x05 }, { 0x43, 0x04 }, - { 0x44, 0x00 }, { 0x0b, 0x00 }, + /* BSAPI writes different values to register 0x3e each time. I initially + * thought this was some kind of clever authentication, but just blasting + * these sniffed values each time seems to work. */ + { 0x3e, 0x83 }, { 0x3e, 0x4f }, { 0x3e, 0x0f }, { 0x3e, 0xbf }, + { 0x3e, 0x45 }, { 0x3e, 0x35 }, { 0x3e, 0x1c }, { 0x3e, 0xae }, + + { 0x44, 0x01 }, { 0x43, 0x06 }, { 0x43, 0x05 }, { 0x43, 0x04 }, + { 0x44, 0x00 }, { 0x0b, 0x00 }, }; static const struct sonly_regwrite initsm_1000_writev_1[] = { - { 0x49, 0x00 }, /* Encryption disabled */ + { 0x49, 0x00 }, /* Encryption disabled */ - /* Setting encryption key. Doesn't need to be random since we don't use any - * encryption. */ - { 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f }, - { 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f }, + /* Setting encryption key. Doesn't need to be random since we don't use any + * encryption. */ + { 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f }, + { 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f }, - { 0x04, 0x00 }, { 0x05, 0x00 }, + { 0x04, 0x00 }, { 0x05, 0x00 }, - { 0x0b, 0x00 }, { 0x08, 0x00 }, /* Initialize capture control registers */ + { 0x0b, 0x00 }, { 0x08, 0x00 }, /* Initialize capture control registers */ }; static const struct sonly_regwrite initsm_1001_writev_1[] = { - { 0x4a, 0x9d }, - { 0x4f, 0x06 }, - { 0x4f, 0x05 }, - { 0x4f, 0x04 }, - { 0x4a, 0x9c }, - { 0x3e, 0xa6 }, - { 0x3e, 0x01 }, - { 0x3e, 0x68 }, - { 0x3e, 0xfd }, - { 0x3e, 0x72 }, - { 0x3e, 0xef }, - { 0x3e, 0x5d }, - { 0x3e, 0xc5 }, - { 0x1a, 0x02 }, - { 0x4a, 0x9d }, - { 0x4c, 0x1f }, { 0x4d, 0xb8 }, { 0x4e, 0x00 }, + { 0x4a, 0x9d }, + { 0x4f, 0x06 }, + { 0x4f, 0x05 }, + { 0x4f, 0x04 }, + { 0x4a, 0x9c }, + { 0x3e, 0xa6 }, + { 0x3e, 0x01 }, + { 0x3e, 0x68 }, + { 0x3e, 0xfd }, + { 0x3e, 0x72 }, + { 0x3e, 0xef }, + { 0x3e, 0x5d }, + { 0x3e, 0xc5 }, + { 0x1a, 0x02 }, + { 0x4a, 0x9d }, + { 0x4c, 0x1f }, { 0x4d, 0xb8 }, { 0x4e, 0x00 }, }; static const struct sonly_regwrite initsm_1001_writev_2[] = { - { 0x4c, 0x03 }, { 0x4d, 0xb8 }, { 0x4e, 0x00 }, + { 0x4c, 0x03 }, { 0x4d, 0xb8 }, { 0x4e, 0x00 }, }; static const struct sonly_regwrite initsm_1001_writev_3[] = { - { 0x4a, 0x9c }, - { 0x1a, 0x00 }, - { 0x1a, 0x02 }, - { 0x4a, 0x9d }, - { 0x4c, 0xff }, { 0x4d, 0xc0 }, { 0x4e, 0x00 }, + { 0x4a, 0x9c }, + { 0x1a, 0x00 }, + { 0x1a, 0x02 }, + { 0x4a, 0x9d }, + { 0x4c, 0xff }, { 0x4d, 0xc0 }, { 0x4e, 0x00 }, }; static const struct sonly_regwrite initsm_1001_writev_4[] = { - { 0x4a, 0x9c }, - { 0x1a, 0x00 }, - { 0x09, 0x27 }, - { 0x1a, 0x02 }, - { 0x49, 0x01 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x0a }, - { 0x47, 0x00 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x0a }, - { 0x47, 0x00 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x0a }, - { 0x47, 0x00 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x02 }, - { 0x47, 0x0a }, - { 0x47, 0x00 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x47, 0x04 }, - { 0x49, 0x00 }, - { 0x3e, 0x90 }, - { 0x3e, 0xbd }, - { 0x3e, 0xbf }, - { 0x3e, 0x48 }, - { 0x3e, 0x2a }, - { 0x3e, 0xe3 }, - { 0x3e, 0xd2 }, - { 0x3e, 0x58 }, - { 0x09, 0x2f }, - { 0x1a, 0x00 }, - { 0x1a, 0x02 }, - { 0x4a, 0x9d }, - { 0x4d, 0x40 }, { 0x4e, 0x03 }, + { 0x4a, 0x9c }, + { 0x1a, 0x00 }, + { 0x09, 0x27 }, + { 0x1a, 0x02 }, + { 0x49, 0x01 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x0a }, + { 0x47, 0x00 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x0a }, + { 0x47, 0x00 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x0a }, + { 0x47, 0x00 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x02 }, + { 0x47, 0x0a }, + { 0x47, 0x00 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x47, 0x04 }, + { 0x49, 0x00 }, + { 0x3e, 0x90 }, + { 0x3e, 0xbd }, + { 0x3e, 0xbf }, + { 0x3e, 0x48 }, + { 0x3e, 0x2a }, + { 0x3e, 0xe3 }, + { 0x3e, 0xd2 }, + { 0x3e, 0x58 }, + { 0x09, 0x2f }, + { 0x1a, 0x00 }, + { 0x1a, 0x02 }, + { 0x4a, 0x9d }, + { 0x4d, 0x40 }, { 0x4e, 0x03 }, }; static const struct sonly_regwrite initsm_1001_writev_5[] = { - { 0x4a, 0x9c }, - { 0x1a, 0x00 }, + { 0x4a, 0x9c }, + { 0x1a, 0x00 }, }; diff --git a/libfprint/drivers/upektc.c b/libfprint/drivers/upektc.c index fb4c0f78..54bc9b2d 100644 --- a/libfprint/drivers/upektc.c +++ b/libfprint/drivers/upektc.c @@ -29,412 +29,456 @@ #define UPEKET_EP_OUT (2 | FPI_USB_ENDPOINT_OUT) #define BULK_TIMEOUT 4000 -struct _FpiDeviceUpektc { - FpImageDevice parent; +struct _FpiDeviceUpektc +{ + FpImageDevice parent; - gboolean deactivating; - const struct setup_cmd *setup_commands; - size_t setup_commands_len; - int ep_in; - int ep_out; - int init_idx; - int sum_threshold; + gboolean deactivating; + const struct setup_cmd *setup_commands; + size_t setup_commands_len; + int ep_in; + int ep_out; + int init_idx; + int sum_threshold; }; -G_DECLARE_FINAL_TYPE(FpiDeviceUpektc, fpi_device_upektc, FPI, DEVICE_UPEKTC, - FpImageDevice); -G_DEFINE_TYPE(FpiDeviceUpektc, fpi_device_upektc, FP_TYPE_IMAGE_DEVICE); +G_DECLARE_FINAL_TYPE (FpiDeviceUpektc, fpi_device_upektc, FPI, DEVICE_UPEKTC, + FpImageDevice); +G_DEFINE_TYPE (FpiDeviceUpektc, fpi_device_upektc, FP_TYPE_IMAGE_DEVICE); enum upektc_driver_data { - UPEKTC_2015, - UPEKTC_3001, + UPEKTC_2015, + UPEKTC_3001, }; -static void start_capture(FpImageDevice *dev); -static void complete_deactivation(FpImageDevice *dev, GError *error); -static void start_finger_detection(FpImageDevice *dev); +static void start_capture (FpImageDevice *dev); +static void complete_deactivation (FpImageDevice *dev, + GError *error); +static void start_finger_detection (FpImageDevice *dev); /****** INITIALIZATION/DEINITIALIZATION ******/ enum activate_states { - WRITE_INIT, - READ_DATA, - ACTIVATE_NUM_STATES, + WRITE_INIT, + READ_DATA, + ACTIVATE_NUM_STATES, }; static void -upektc_next_init_cmd(FpiSsm *ssm, - FpImageDevice *dev) +upektc_next_init_cmd (FpiSsm *ssm, + FpImageDevice *dev) { - FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev); - self->init_idx += 1; - if (self->init_idx == self->setup_commands_len) - fpi_ssm_mark_completed(ssm); - else - fpi_ssm_jump_to_state(ssm, WRITE_INIT); + self->init_idx += 1; + if (self->init_idx == self->setup_commands_len) + fpi_ssm_mark_completed (ssm); + else + fpi_ssm_jump_to_state (ssm, WRITE_INIT); } -static void write_init_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +write_init_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE(device); - FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev); - if (!error) { - if (self->setup_commands[self->init_idx].response_len) - fpi_ssm_next_state(transfer->ssm); - else - upektc_next_init_cmd(transfer->ssm, dev); - } else { - fpi_ssm_mark_failed(transfer->ssm, error); - } + if (!error) + { + if (self->setup_commands[self->init_idx].response_len) + fpi_ssm_next_state (transfer->ssm); + else + upektc_next_init_cmd (transfer->ssm, dev); + } + else + { + fpi_ssm_mark_failed (transfer->ssm, error); + } } -static void read_init_data_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +read_init_data_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE(device); + FpImageDevice *dev = FP_IMAGE_DEVICE (device); - if (!error) - upektc_next_init_cmd(transfer->ssm, dev); - else - fpi_ssm_mark_failed(transfer->ssm, error); + if (!error) + upektc_next_init_cmd (transfer->ssm, dev); + else + fpi_ssm_mark_failed (transfer->ssm, error); } -static void activate_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) +static void +activate_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) { - FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case WRITE_INIT: - { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); + switch (fpi_ssm_get_cur_state (ssm)) + { + case WRITE_INIT: + { + FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev); - fpi_usb_transfer_fill_bulk_full(transfer, - self->ep_out, - (unsigned char *) self->setup_commands[self->init_idx].cmd, - UPEKTC_CMD_LEN, - NULL); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - write_init_cb, NULL); - fpi_usb_transfer_unref(transfer); - } - break; - case READ_DATA: - { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); + fpi_usb_transfer_fill_bulk_full (transfer, + self->ep_out, + (unsigned char *) self->setup_commands[self->init_idx].cmd, + UPEKTC_CMD_LEN, + NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + write_init_cb, NULL); + fpi_usb_transfer_unref (transfer); + } + break; - fpi_usb_transfer_fill_bulk (transfer, - self->ep_in, - self->setup_commands[self->init_idx].response_len); - transfer->ssm = ssm; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - read_init_data_cb, NULL); - fpi_usb_transfer_unref(transfer); - } - break; - } + case READ_DATA: + { + FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev); + + fpi_usb_transfer_fill_bulk (transfer, + self->ep_in, + self->setup_commands[self->init_idx].response_len); + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + read_init_data_cb, NULL); + fpi_usb_transfer_unref (transfer); + } + break; + } } -static void activate_sm_complete(FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +static void +activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE(_dev); + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); - fpi_image_device_activate_complete(dev, error); + fpi_image_device_activate_complete (dev, error); - if (!error) - start_finger_detection(dev); - fpi_ssm_free(ssm); + if (!error) + start_finger_detection (dev); + fpi_ssm_free (ssm); } /****** FINGER PRESENCE DETECTION ******/ -static int finger_present(unsigned char *img, size_t len, int sum_threshold) +static int +finger_present (unsigned char *img, size_t len, int sum_threshold) { - int i, sum; + int i, sum; - sum = 0; + sum = 0; - for (i = 0; i < len; i++) { - if (img[i] < 160) { - sum++; - } - } + for (i = 0; i < len; i++) + if (img[i] < 160) + sum++; - fp_dbg("finger_present: sum is %d\n", sum); - return sum < sum_threshold ? 0 : 1; + fp_dbg ("finger_present: sum is %d\n", sum); + return sum < sum_threshold ? 0 : 1; } -static void finger_det_data_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE(device); - FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev); - if (error) { - fp_dbg("data transfer status %s\n", error->message); - fpi_image_device_session_error(dev, error); - return; - } + if (error) + { + fp_dbg ("data transfer status %s\n", error->message); + fpi_image_device_session_error (dev, error); + return; + } - if (finger_present(transfer->buffer, IMAGE_SIZE, self->sum_threshold)) { - /* finger present, start capturing */ - fpi_image_device_report_finger_status(dev, TRUE); - start_capture(dev); - } else { - /* no finger, poll for a new histogram */ - start_finger_detection(dev); - } + if (finger_present (transfer->buffer, IMAGE_SIZE, self->sum_threshold)) + { + /* finger present, start capturing */ + fpi_image_device_report_finger_status (dev, TRUE); + start_capture (dev); + } + else + { + /* no finger, poll for a new histogram */ + start_finger_detection (dev); + } } -static void finger_det_cmd_cb(FpiUsbTransfer *t, FpDevice *device, - gpointer user_data, GError *error) +static void +finger_det_cmd_cb (FpiUsbTransfer *t, FpDevice *device, + gpointer user_data, GError *error) { - FpiUsbTransfer *transfer; - FpImageDevice *dev = FP_IMAGE_DEVICE (device); - FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); + FpiUsbTransfer *transfer; + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev); - if (error) { - fp_dbg("req transfer status %s\n", error->message); - fpi_image_device_session_error(dev, error); - return; - } + if (error) + { + fp_dbg ("req transfer status %s\n", error->message); + fpi_image_device_session_error (dev, error); + return; + } - transfer = fpi_usb_transfer_new (device); - transfer->short_is_error = TRUE; - fpi_usb_transfer_fill_bulk(transfer, self->ep_in, - IMAGE_SIZE); - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - finger_det_data_cb, NULL); - fpi_usb_transfer_unref(transfer); + transfer = fpi_usb_transfer_new (device); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk (transfer, self->ep_in, + IMAGE_SIZE); + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + finger_det_data_cb, NULL); + fpi_usb_transfer_unref (transfer); } -static void start_finger_detection(FpImageDevice *dev) +static void +start_finger_detection (FpImageDevice *dev) { - FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); - FpiUsbTransfer *transfer; - G_DEBUG_HERE(); + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev); + FpiUsbTransfer *transfer; - if (self->deactivating) { - complete_deactivation(dev, NULL); - return; - } + G_DEBUG_HERE (); - transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); - transfer->short_is_error = TRUE; - fpi_usb_transfer_fill_bulk_full(transfer, self->ep_out, - (unsigned char *)scan_cmd, - UPEKTC_CMD_LEN, NULL); - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - finger_det_cmd_cb, NULL); - fpi_usb_transfer_unref(transfer); + if (self->deactivating) + { + complete_deactivation (dev, NULL); + return; + } + + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk_full (transfer, self->ep_out, + (unsigned char *) scan_cmd, + UPEKTC_CMD_LEN, NULL); + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + finger_det_cmd_cb, NULL); + fpi_usb_transfer_unref (transfer); } /****** CAPTURE ******/ enum capture_states { - CAPTURE_WRITE_CMD, - CAPTURE_READ_DATA, - CAPTURE_NUM_STATES, + CAPTURE_WRITE_CMD, + CAPTURE_READ_DATA, + CAPTURE_NUM_STATES, }; -static void capture_cmd_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +capture_cmd_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - if (!error) { - fpi_ssm_next_state(transfer->ssm); - } else { - fpi_ssm_mark_failed(transfer->ssm, error); - } + if (!error) + fpi_ssm_next_state (transfer->ssm); + else + fpi_ssm_mark_failed (transfer->ssm, error); } -static void capture_read_data_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE(device); - FpImage *img; + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpImage *img; - if (error) { - fp_dbg("request is not completed, %s", error->message); - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } + if (error) + { + fp_dbg ("request is not completed, %s", error->message); + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } - img = fp_image_new(IMAGE_WIDTH, IMAGE_HEIGHT); - memcpy(img->data, transfer->buffer, IMAGE_SIZE); - fpi_image_device_image_captured(dev, img); - fpi_image_device_report_finger_status(dev, FALSE); - fpi_ssm_mark_completed(transfer->ssm); + img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT); + memcpy (img->data, transfer->buffer, IMAGE_SIZE); + fpi_image_device_image_captured (dev, img); + fpi_image_device_report_finger_status (dev, FALSE); + fpi_ssm_mark_completed (transfer->ssm); } -static void capture_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +capture_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(_dev); + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (_dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case CAPTURE_WRITE_CMD: - { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(_dev); + switch (fpi_ssm_get_cur_state (ssm)) + { + case CAPTURE_WRITE_CMD: + { + FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev); - fpi_usb_transfer_fill_bulk_full(transfer, self->ep_out, - (unsigned char *)scan_cmd, - UPEKTC_CMD_LEN, NULL); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - capture_cmd_cb, NULL); - fpi_usb_transfer_unref(transfer); - } - break; - case CAPTURE_READ_DATA: - { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(_dev); + fpi_usb_transfer_fill_bulk_full (transfer, self->ep_out, + (unsigned char *) scan_cmd, + UPEKTC_CMD_LEN, NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + capture_cmd_cb, NULL); + fpi_usb_transfer_unref (transfer); + } + break; - fpi_usb_transfer_fill_bulk(transfer, self->ep_in, - IMAGE_SIZE); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - capture_read_data_cb, NULL); - fpi_usb_transfer_unref(transfer); - } - break; - }; + case CAPTURE_READ_DATA: + { + FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev); + + fpi_usb_transfer_fill_bulk (transfer, self->ep_in, + IMAGE_SIZE); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + capture_read_data_cb, NULL); + fpi_usb_transfer_unref (transfer); + } + break; + } + ; } -static void capture_sm_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +static void +capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - FpImageDevice *dev = user_data; - FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (_dev); - fp_dbg("Capture completed"); - if (self->deactivating) - complete_deactivation(dev, error); - else if (error) - fpi_image_device_session_error(dev, error); - else - start_finger_detection(dev); + fp_dbg ("Capture completed"); + if (self->deactivating) + complete_deactivation (dev, error); + else if (error) + fpi_image_device_session_error (dev, error); + else + start_finger_detection (dev); - fpi_ssm_free(ssm); + fpi_ssm_free (ssm); } -static void start_capture(FpImageDevice *dev) +static void +start_capture (FpImageDevice *dev) { - FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); - FpiSsm *ssm; + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev); + FpiSsm *ssm; - if (self->deactivating) { - complete_deactivation(dev, NULL); - return; - } + if (self->deactivating) + { + complete_deactivation (dev, NULL); + return; + } - ssm = fpi_ssm_new(FP_DEVICE(dev), capture_run_state, - CAPTURE_NUM_STATES, dev); - G_DEBUG_HERE(); - fpi_ssm_start(ssm, capture_sm_complete); + ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, + CAPTURE_NUM_STATES, dev); + G_DEBUG_HERE (); + fpi_ssm_start (ssm, capture_sm_complete); } -static void dev_activate(FpImageDevice *dev) +static void +dev_activate (FpImageDevice *dev) { - FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); - FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); - self->init_idx = 0; - fpi_ssm_start(ssm, activate_sm_complete); + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev); + FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); + + self->init_idx = 0; + fpi_ssm_start (ssm, activate_sm_complete); } -static void dev_deactivate(FpImageDevice *dev) +static void +dev_deactivate (FpImageDevice *dev) { - FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev); - self->deactivating = TRUE; + self->deactivating = TRUE; } -static void complete_deactivation(FpImageDevice *dev, GError *error) +static void +complete_deactivation (FpImageDevice *dev, GError *error) { - FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); - G_DEBUG_HERE(); + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev); - self->deactivating = FALSE; - fpi_image_device_deactivate_complete(dev, error); + G_DEBUG_HERE (); + + self->deactivating = FALSE; + fpi_image_device_deactivate_complete (dev, error); } -static void dev_init(FpImageDevice *dev) +static void +dev_init (FpImageDevice *dev) { - GError *error = NULL; - FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC(dev); - guint64 driver_data = fpi_device_get_driver_data (FP_DEVICE (dev)); + GError *error = NULL; + FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev); + guint64 driver_data = fpi_device_get_driver_data (FP_DEVICE (dev)); - /* TODO check that device has endpoints we're using */ + /* TODO check that device has endpoints we're using */ - if (!g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error)) { - fpi_image_device_open_complete(dev, error); - return; - } + if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error)) + { + fpi_image_device_open_complete (dev, error); + return; + } - switch (driver_data) { - case UPEKTC_2015: - self->ep_in = UPEKTC_EP_IN; - self->ep_out = UPEKTC_EP_OUT; - self->setup_commands = upektc_setup_commands; - self->setup_commands_len = G_N_ELEMENTS(upektc_setup_commands); - self->sum_threshold = UPEKTC_SUM_THRESHOLD; - break; - case UPEKTC_3001: - self->ep_in = UPEKET_EP_IN; - self->ep_out = UPEKET_EP_OUT; - self->setup_commands = upeket_setup_commands; - self->setup_commands_len = G_N_ELEMENTS(upeket_setup_commands); - self->sum_threshold = UPEKET_SUM_THRESHOLD; - break; - default: - fp_err("Device variant %lu is not known\n", driver_data); - g_assert_not_reached (); - fpi_image_device_open_complete(dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); - return; - } - fpi_image_device_open_complete(dev, NULL); + switch (driver_data) + { + case UPEKTC_2015: + self->ep_in = UPEKTC_EP_IN; + self->ep_out = UPEKTC_EP_OUT; + self->setup_commands = upektc_setup_commands; + self->setup_commands_len = G_N_ELEMENTS (upektc_setup_commands); + self->sum_threshold = UPEKTC_SUM_THRESHOLD; + break; + + case UPEKTC_3001: + self->ep_in = UPEKET_EP_IN; + self->ep_out = UPEKET_EP_OUT; + self->setup_commands = upeket_setup_commands; + self->setup_commands_len = G_N_ELEMENTS (upeket_setup_commands); + self->sum_threshold = UPEKET_SUM_THRESHOLD; + break; + + default: + fp_err ("Device variant %lu is not known\n", driver_data); + g_assert_not_reached (); + fpi_image_device_open_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + return; + } + fpi_image_device_open_complete (dev, NULL); } -static void dev_deinit(FpImageDevice *dev) +static void +dev_deinit (FpImageDevice *dev) { - GError *error = NULL; + GError *error = NULL; - g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), - 0, 0, &error); - fpi_image_device_close_complete(dev, error); + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), + 0, 0, &error); + fpi_image_device_close_complete (dev, error); } -static const FpIdEntry id_table [ ] = { - { .vid = 0x0483, .pid = 0x2015, .driver_data = UPEKTC_2015 }, - { .vid = 0x147e, .pid = 0x3001, .driver_data = UPEKTC_3001 }, - { .vid = 0, .pid = 0, .driver_data = 0 }, +static const FpIdEntry id_table[] = { + { .vid = 0x0483, .pid = 0x2015, .driver_data = UPEKTC_2015 }, + { .vid = 0x147e, .pid = 0x3001, .driver_data = UPEKTC_3001 }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -static void fpi_device_upektc_init(FpiDeviceUpektc *self) { +static void +fpi_device_upektc_init (FpiDeviceUpektc *self) +{ } -static void fpi_device_upektc_class_init(FpiDeviceUpektcClass *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); +static void +fpi_device_upektc_class_init (FpiDeviceUpektcClass *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); - dev_class->id = "upektc"; - dev_class->full_name = "UPEK TouchChip/Eikon Touch 300"; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->id_table = id_table; - dev_class->scan_type = FP_SCAN_TYPE_PRESS; + dev_class->id = "upektc"; + dev_class->full_name = "UPEK TouchChip/Eikon Touch 300"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_PRESS; - img_class->img_open = dev_init; - img_class->img_close = dev_deinit; - img_class->activate = dev_activate; - img_class->deactivate = dev_deactivate; + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; - img_class->bz3_threshold = 30; + img_class->bz3_threshold = 30; - img_class->img_width = IMAGE_WIDTH; - img_class->img_height = IMAGE_HEIGHT; + img_class->img_width = IMAGE_WIDTH; + img_class->img_height = IMAGE_HEIGHT; } diff --git a/libfprint/drivers/upektc.h b/libfprint/drivers/upektc.h index 143916e3..7ea919aa 100644 --- a/libfprint/drivers/upektc.h +++ b/libfprint/drivers/upektc.h @@ -29,1911 +29,1912 @@ #define UPEKTC_SUM_THRESHOLD 10000 #define UPEKET_SUM_THRESHOLD 5000 -struct setup_cmd { - unsigned char cmd[0x40]; - int response_len; +struct setup_cmd +{ + unsigned char cmd[0x40]; + int response_len; }; static const struct setup_cmd upektc_setup_commands[] = { - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0xfe, 0x00, 0x01, - 0xc0, 0xbd, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0xf0, 0xfd, 0x7f, 0x00, 0x60, 0xfd, 0x7f, - 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0xcc, 0xf8, 0x2f, 0x01, - 0x09, 0x48, 0xe7, 0x77, 0xf0, 0xfa, 0x2f, 0x01, - 0x09, 0x48, 0xe7, 0x77, 0xe0, 0x3a, 0xe6, 0x77 - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xf7, 0x00, 0x00, - 0xc8, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x58, 0xf9, 0x2f, 0x01, - 0xe9, 0x4f, 0x01, 0x10, 0xd8, 0xf8, 0x2f, 0x01, - 0x40, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x02, 0xfe, 0x00, 0x01, 0xc0, 0xbd, 0xf0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0xfd, 0x7f - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0xf7, 0xcd, 0x00, - 0x2c, 0xf9, 0x2f, 0x01, 0x6d, 0x4f, 0x01, 0x10, - 0xac, 0xf8, 0x2f, 0x01, 0x40, 0x00, 0x00, 0x00, - 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0xfe, 0x16, 0x10, 0x03, 0xee, 0x00, 0x37, - 0x01, 0x09, 0x02, 0x0e, 0x03, 0x18, 0x03, 0x1a, - 0x03, 0x20, 0x10, 0x2f, 0x11, 0x3f, 0x12, 0x44, - 0x01, 0x01, 0x07, 0x08, 0x0c, 0x00, 0x6c, 0x6c - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, - 0x02, 0xfe, 0x16, 0x10, 0x03, 0xee, 0x00, 0x37, - 0x01, 0x09, 0x02, 0x0e, 0x03, 0x18, 0x03, 0x1a, - 0x03, 0x20, 0x10, 0x2f, 0x11, 0x3f, 0x12, 0x44, - 0x01, 0x01, 0x07, 0x08, 0x0c, 0x00, 0x6c, 0x6c, - 0x00, 0xf9, 0x2f, 0x01, 0x97, 0x40, 0x01, 0x10, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0x45, 0x03, 0x10, 0x02, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8b, 0x00, 0x00, 0x00, 0x3a, 0x50, 0xf9, 0x2f, - 0x01, 0x18, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x88, 0xf9, 0x2f, - 0x01, 0x91, 0x99, 0x00, 0x10, 0xf8, 0x00, 0x00, - 0x00, 0xbe, 0x99, 0x00, 0x10, 0xa0, 0xa6, 0x04, - 0x10, 0x01, 0x9b, 0x00, 0x10, 0x18, 0x00, 0x00, - 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0x0d, 0xff, 0x36, - 0xdc, 0xf8, 0x2f, 0x01, 0xf1, 0x9d, 0x00, 0x10, - 0xfc, 0xf8, 0x2f, 0x01, 0x9d, 0xf8, 0x2f, 0x01, - 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x9e, 0xbf, 0x85, 0x85, 0x02, 0x05, 0x26, - 0x25, 0x4d, 0x13, 0x10, 0x00, 0x00, 0x00, 0x6c, - 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, - 0x01, 0x01, 0x09, 0x09, 0x0f, 0x00, 0x6c, 0x6c - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x0c, 0x37, 0x6a, 0x3d, - 0x73, 0x3d, 0x71, 0x0e, 0x01, 0x0e, 0x81, 0x3d, - 0x51, 0xf8, 0x2f, 0x01, 0x3a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x9e, 0xbf, 0x85, - 0x85, 0x02, 0x05, 0x26, 0x25, 0x4d, 0x13, 0x10, - 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0xcf, 0x00, - 0x01, 0x00, 0x00, 0x1f, 0x01, 0x01, 0x09, 0x09, - 0x0f, 0x00, 0x6c, 0x6c, 0xf0, 0xf8, 0x2f, 0x01 - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8b, 0x00, 0x01, 0x7c, 0x0a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, - 0x14, 0xf5, 0x2f, 0x01, 0xa0, 0x20, 0x14, 0x00, - 0x40, 0xf8, 0x2f, 0x01, 0x05, 0x90, 0xf6, 0x77, - 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x50, 0xf8, 0x2f, 0x01, 0x40, 0x39, 0xf4, 0x77, - 0xa8, 0x20, 0x14, 0x00, 0x1c, 0xf6, 0x2f, 0x01, - 0x2c, 0x20, 0xf4, 0x77, 0x80, 0x4d, 0xfb, 0x77 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8b, 0x00, 0x03, 0xc8, 0x3a, 0x01, 0x00, 0x00, - 0x1f, 0x01, 0x01, 0x09, 0x09, 0x0f, 0x00, 0x6c, - 0x6c, 0x6c, 0x6c, 0x40, 0x40, 0x40, 0x40, 0x40, - 0x40, 0x40, 0x40, 0x40, 0x40, 0x6c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x60, 0x62, 0x62, 0x62, 0x62, - 0x62, 0x51, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x40, 0xf9, 0x2f, 0x01, 0x4f, 0x9d, 0x00, - 0x10, 0x3a, 0x00, 0x00, 0x00, 0x04, 0xf9, 0x01 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8b, 0x00, 0x04, 0x02, 0x06, 0x0b, 0x07, 0x13, - 0x0e, 0x55, 0x56, 0x01, 0x44, 0xf8, 0x2f, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, - 0xc8, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x07, 0x00, 0x20, 0x00, 0x3a, 0x0e, 0x13, 0x07, - 0x0f, 0x14, 0x07, 0x10, 0x15, 0x07, 0x12, 0x16, - 0x07, 0x13, 0x17, 0x07, 0x14, 0x18, 0x07, 0x15, - 0x18, 0x07, 0x16, 0x19, 0x07, 0x17, 0x1a, 0x07, - 0x19, 0x1b, 0x07, 0x1a, 0x1c, 0x07, 0x1b, 0x1d, - 0x07, 0x1c, 0x1e, 0x07, 0x1d, 0x1f, 0x07, 0x1e, - 0x20, 0x07, 0x1f, 0x21, 0x07, 0x20, 0x22, 0x07, - 0x21, 0x23, 0x07, 0x23, 0x23, 0x07, 0x24, 0x55 - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x07, 0x00, 0x20, 0x3a, 0x26, 0x24, 0x07, 0x25, - 0x25, 0x07, 0x26, 0x25, 0x07, 0x27, 0x26, 0x07, - 0x28, 0x27, 0x07, 0x29, 0x27, 0x07, 0x2a, 0x28, - 0x07, 0x2b, 0x29, 0x07, 0x2d, 0x29, 0x07, 0x2e, - 0x2a, 0x07, 0x2f, 0x2b, 0x07, 0x30, 0x2b, 0x07, - 0x31, 0x2c, 0x07, 0x07, 0x1d, 0x1f, 0x07, 0x1e, - 0x20, 0x07, 0x1f, 0x21, 0x07, 0x20, 0x22, 0x07, - 0x21, 0x23, 0x07, 0x23, 0x23, 0x07, 0x24, 0x55 - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x06, 0x0e, 0x81, 0x0e, - 0x81, 0x09, 0x4d, 0x00, 0x07, 0x00, 0x20, 0x3a, - 0x26, 0x24, 0x07, 0x25, 0x25, 0x07, 0x26, 0x25, - 0x07, 0x27, 0x26, 0x07, 0x28, 0x27, 0x07, 0x29, - 0x27, 0x07, 0x2a, 0x28, 0x07, 0x2b, 0x29, 0x07, - 0x2d, 0x29, 0x07, 0x2e, 0x2a, 0x07, 0x2f, 0x2b, - 0x07, 0x30, 0x2b, 0x07, 0x31, 0x2c, 0x07, 0x07, - 0x1d, 0x1f, 0x07, 0x1e, 0x20, 0x07, 0x1f, 0x21 - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0x0e, 0x85, 0x36, - 0xd8, 0xf8, 0x2f, 0x01, 0xf1, 0x9d, 0x00, 0x10, - 0xf8, 0xf8, 0x2f, 0x01, 0x99, 0xf8, 0x2f, 0x01, - 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x9e, 0xbf, 0x85, 0x85, 0x02, 0x05, 0x26, - 0x25, 0x4d, 0x10, 0x10, 0x00, 0xff, 0x81, 0x6c, - 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, - 0x01, 0x01, 0x09, 0x09, 0x0f, 0x00, 0x6c, 0x6c - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0x0d, 0x00, 0x00, - 0x02, 0x9e, 0xbf, 0x85, 0x85, 0x02, 0x05, 0x26, - 0x25, 0x4d, 0x10, 0x10, 0x00, 0xff, 0x81, 0x6c, - 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, - 0x01, 0x01, 0x09, 0x09, 0x0f, 0x00, 0x6c, 0x6c, - 0xec, 0xf8, 0x2f, 0x01, 0x97, 0x40, 0x01, 0x10, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0x45, 0x03, 0x10, 0x02, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xf7, 0xcf, 0x00, - 0x01, 0x00, 0x00, 0x1f, 0x01, 0x01, 0x09, 0x09, - 0x0f, 0x00, 0x6c, 0x6c, 0x6c, 0x6c, 0x40, 0x40, - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, - 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x62, - 0x62, 0x62, 0x62, 0x62, 0x51, 0x6c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xf7, 0x00, 0x00, - 0x02, 0xf9, 0xbf, 0x85, 0x85, 0x02, 0x05, 0x26, - 0x25, 0x4d, 0x10, 0x10, 0x00, 0xff, 0x81, 0x6c, - 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, - 0x01, 0x01, 0x09, 0x09, 0x0f, 0x00, 0x6c, 0x6c, - 0x6c, 0x6c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, - 0x40, 0x40, 0x40, 0x40, 0x6c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x60, 0x62, 0x62, 0x62, 0x62, 0x62 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0xf7, 0xf4, 0x00, - 0x14, 0xf9, 0x2f, 0x01, 0x6d, 0x4f, 0x01, 0x10, - 0x94, 0xf8, 0x2f, 0x01, 0x40, 0x00, 0x00, 0x00, - 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0xf9, 0xbf, 0x85, 0x85, 0x02, 0x05, 0x26, - 0x25, 0x4d, 0x10, 0x10, 0x00, 0xff, 0x81, 0x6c, - 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, - 0x01, 0x01, 0x09, 0x09, 0x0f, 0x00, 0x6c, 0x6c - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0x20, 0x6c, 0x01, - 0x6d, 0x4f, 0x01, 0x10, 0x94, 0xf8, 0x2f, 0x01, - 0x40, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0xf9, 0xbf, 0x85, - 0x85, 0x02, 0x05, 0x26, 0x25, 0x4d, 0x10, 0x10, - 0x00, 0xff, 0x81, 0x6c, 0x00, 0x00, 0xcf, 0x00, - 0x01, 0x00, 0x00, 0x1f, 0x01, 0x01, 0x09, 0x09, - 0x0f, 0x00, 0x6c, 0x6c, 0xe8, 0xf8, 0x2f, 0x01 - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xf9, 0x81, 0x6c, - 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, - 0x01, 0x01, 0x09, 0x09, 0x0f, 0x00, 0x6c, 0x6c, - 0xe8, 0xf8, 0x2f, 0x01, 0xec, 0xf8, 0x2f, 0x01, - 0x97, 0x40, 0x01, 0x10, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xfa, 0x45, 0x03, 0x10, - 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0xf9, 0x01, 0x00, - 0x1c, 0xf9, 0x2f, 0x01, 0x6d, 0x4f, 0x01, 0x10, - 0x9c, 0xf8, 0x2f, 0x01, 0x40, 0x00, 0x00, 0x00, - 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x6c, 0xbf, 0x85, 0x85, 0x02, 0x05, 0x26, - 0x25, 0x4d, 0x10, 0x10, 0x00, 0xff, 0x81, 0x6c, - 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, - 0x01, 0x01, 0x09, 0x09, 0x0f, 0x00, 0x6c, 0x6c - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x12, 0x1c, 0x0c, 0x1b, - 0x08, 0x1a, 0x07, 0x30, 0x08, 0x09, 0x6d, 0x08, - 0x27, 0x00, 0x9e, 0x00, 0x1e, 0x23, 0x47, 0x01, - 0x40, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x6c, 0xbf, 0x85, - 0x85, 0x02, 0x05, 0x26, 0x25, 0x4d, 0x10, 0x10, - 0x00, 0xff, 0x81, 0x6c, 0x00, 0x00, 0xcf, 0x00, - 0x01, 0x00, 0x00, 0x1f, 0x01, 0x01, 0x09, 0x09 - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0x0d, 0xff, 0x36, - 0xdc, 0xf8, 0x2f, 0x01, 0xf1, 0x9d, 0x00, 0x10, - 0xfc, 0xf8, 0x2f, 0x01, 0x9d, 0xf8, 0x2f, 0x01, - 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x1e, 0x3f, 0x05, 0x05, 0x02, 0x05, 0x26, - 0x27, 0x6d, 0x10, 0x10, 0x00, 0xff, 0x85, 0x6c, - 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, - 0x01, 0x01, 0x07, 0x08, 0x0c, 0x00, 0x6c, 0x6c - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0xcf, - 0x00, 0x01, 0x00, 0x00, 0x1f, 0x01, 0x01, 0x10, - 0xfc, 0xf8, 0x2f, 0x01, 0x9d, 0xf8, 0x2f, 0x01, - 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x1e, 0x3f, 0x05, 0x05, 0x02, 0x05, 0x26, - 0x27, 0x6d, 0x10, 0x10, 0x00, 0xff, 0x85, 0x6c, - 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, - 0x01, 0x01, 0x07, 0x08, 0x0c, 0x00, 0x6c, 0x6c - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x08, 0x0e, 0x85, 0x09, - 0xed, 0x09, 0x6d, 0x09, 0xed, 0x1e, 0x3f, 0x05, - 0x05, 0x02, 0x05, 0x26, 0x27, 0x6d, 0x10, 0x10, - 0x00, 0xff, 0x85, 0x6c, 0x00, 0x00, 0xcf, 0x00, - 0x01, 0x00, 0x00, 0x1f, 0x01, 0x01, 0x07, 0x08, - 0x0c, 0x00, 0x6c, 0x6c, 0xf0, 0xf8, 0x2f, 0x01, - 0x97, 0x40, 0x01, 0x10, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3e, 0xf9, 0x2f, 0x01 - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xf3, 0x6c, 0x6c, - 0xf0, 0xf8, 0x2f, 0x01, 0x97, 0x40, 0x01, 0x10, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3e, 0xf9, 0x2f, 0x01, 0x04, 0xf9, 0x2f, 0x01, - 0x97, 0x40, 0x01, 0x10, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x03, 0x10, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x84, 0x00, 0x00, 0x00, 0x32, 0x02, 0xa3, 0x04, - 0x10, 0x3b, 0xa3, 0x04, 0x10, 0x1a, 0xa3, 0x04, - 0x10, 0xf9, 0xa2, 0x04, 0x10, 0xd8, 0xa2, 0x00, - 0xb9, 0x19, 0xe2, 0x87, 0xba, 0x56, 0x78, 0x72, - 0x68, 0x9e, 0x7a, 0xf4, 0x65, 0x6d, 0xd9, 0xde, - 0xf6, 0x33, 0xa2, 0x04, 0x10, 0x12, 0xa2, 0x04, - 0x10, 0xf1, 0xa1, 0x04, 0x10, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xb4, 0x2d, 0x6c, 0xe9 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x06, 0x1a, 0x07, 0x1b, - 0x08, 0x1c, 0x0c, 0x77, 0x21, 0xac, 0xe5, 0x77, - 0x00, 0x00, 0x00, 0x00, 0xaa, 0x4e, 0x01, 0x10, - 0x3c, 0x01, 0x00, 0x00, 0xc4, 0xf8, 0x2f, 0x01, - 0xdc, 0xf8, 0x2f, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0xb9, 0x19, 0xe2, 0x87, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0xcf, - 0x00, 0x01, 0x00, 0x00, 0x1f, 0x01, 0x01, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0xcc, 0xf8, 0x2f, 0x01, 0x8b, 0x41, 0x01, 0x10, - 0x8c, 0xf8, 0x2f, 0x01, 0x40, 0x00, 0x00, 0x00 - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x04, 0x3d, 0x51, 0x0a, - 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfc, 0xf9, 0x2f, 0x01, 0x31, 0x10, 0x01, 0x10, - 0xd0, 0xf9, 0x2f, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x1a, 0x07, 0x1b, 0x08, 0x1c, 0x0c, 0xc6, 0xf8, - 0x66, 0xbc, 0xc4, 0xbe, 0x0b, 0x25, 0xc5, 0x4c, - 0xf4, 0x03, 0x10, 0x2f, 0x11, 0x3f, 0x12, 0x44 - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0x0a, 0x10, 0x36, - 0x88, 0xf9, 0x2f, 0x01, 0xf1, 0x9d, 0x00, 0x10, - 0xa8, 0xf9, 0x2f, 0x01, 0x49, 0xf9, 0x2f, 0x01, - 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x1e, 0x3f, 0x05, 0x05, 0x02, 0x05, 0x26, - 0x27, 0xed, 0x00, 0x10, 0x00, 0xff, 0x85, 0x6c, - 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, - 0x01, 0x01, 0x07, 0x08, 0x0c, 0x00, 0x6c, 0x6c - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x8b, 0x00, 0x00, 0xbc, 0x3a, 0x40, 0xd3, 0x60, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xd8, 0xf4, 0x2f, 0x01, 0x80, 0x69, 0x67, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0xfd, - 0x7f, 0x00, 0x60, 0xfd, 0x7f, 0x3c, 0x01, 0x00, - 0x00, 0xa0, 0xf5, 0x2f, 0x01, 0x03, 0x01, 0x00, - 0x00, 0x9a, 0x11, 0xf4, 0x77, 0x9f, 0x11, 0xf4, - 0x77, 0x3c, 0x01, 0x00, 0x00, 0xa0, 0xf5, 0x01 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8b, 0x00, 0x00, 0xf6, 0x3a, 0x0b, 0x07, 0xa5, - 0x03, 0x2f, 0x63, 0x97, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8b, 0x00, 0x01, 0x30, 0x3a, 0x0b, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x12, 0xcd, 0xa6, 0x3c, - 0x36, 0xec, 0x6a, 0x73, 0x00, 0x64, 0x75, 0xdf, - 0x2e, 0x13, 0xec, 0xca, 0x3c, 0x03, 0x00, 0x00, - 0x06, 0xa5, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8b, 0x00, 0x01, 0x6a, 0x3a, 0x0b, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8b, 0x00, 0x01, 0xa4, 0x3a, 0x0b, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0xa5, 0x83, 0x1b, 0x8e, 0xac, 0x00, 0x00, - 0x0b, 0xa5, 0x08, 0x08, 0x03, 0x00, 0x00, 0x01, - 0x02, 0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x8d, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8b, 0x00, 0x01, 0xde, 0x3a, 0x0b, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8b, 0x00, 0x02, 0x18, 0x3a, 0x0b, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8b, 0x00, 0x02, 0x52, 0x3a, 0x0b, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8b, 0x00, 0x02, 0x8c, 0x3a, 0x0b, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8b, 0x00, 0x02, 0xc6, 0x2a, 0x0b, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, - 0xc8, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xf1, 0x2f, 0x01, - 0x49, 0xf9, 0x2f, 0x01, 0x3a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x1e, 0x3f, 0x05, - 0x05, 0x02, 0x05, 0x26, 0x27, 0xed, 0x00, 0x10, - 0x00, 0xff, 0x85, 0x6c, 0x00, 0x00, 0xcf, 0x00, - 0x01, 0x00, 0x00, 0x1f, 0x01, 0x01, 0x07, 0x08, - 0x0c, 0x00, 0x6c, 0x6c, 0x9c, 0xf9, 0x2f, 0x01, - 0x97, 0x40, 0x01, 0x10, 0x03, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0xf1, 0x01, 0x00, - 0xb4, 0xf9, 0x2f, 0x01, 0x6d, 0x4f, 0x01, 0x10, - 0x34, 0xf9, 0x2f, 0x01, 0x40, 0x00, 0x00, 0x00, - 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x8b, 0x00, 0x01, 0x10, 0x3a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8b, 0x00, 0x01, 0x4a, 0x2e, 0x0b, 0x06, 0xa5, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, - 0xc8, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xfb, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x88, 0xf9, 0x2f, 0x01, 0x97, 0x40, 0x01, 0x10, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0x45, 0x03, 0x10, 0x02, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0xfb, 0x0f, 0x00, - 0xc4, 0xf9, 0x2f, 0x01, 0x6d, 0x4f, 0x01, 0x10, - 0x44, 0xf9, 0x2f, 0x01, 0x40, 0x00, 0x00, 0x00, - 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }, - .response_len = 0x00 - } + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0xfe, 0x00, 0x01, + 0xc0, 0xbd, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xf0, 0xfd, 0x7f, 0x00, 0x60, 0xfd, 0x7f, + 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0xcc, 0xf8, 0x2f, 0x01, + 0x09, 0x48, 0xe7, 0x77, 0xf0, 0xfa, 0x2f, 0x01, + 0x09, 0x48, 0xe7, 0x77, 0xe0, 0x3a, 0xe6, 0x77 + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xf7, 0x00, 0x00, + 0xc8, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x58, 0xf9, 0x2f, 0x01, + 0xe9, 0x4f, 0x01, 0x10, 0xd8, 0xf8, 0x2f, 0x01, + 0x40, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x02, 0xfe, 0x00, 0x01, 0xc0, 0xbd, 0xf0, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0xfd, 0x7f + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0xf7, 0xcd, 0x00, + 0x2c, 0xf9, 0x2f, 0x01, 0x6d, 0x4f, 0x01, 0x10, + 0xac, 0xf8, 0x2f, 0x01, 0x40, 0x00, 0x00, 0x00, + 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0xfe, 0x16, 0x10, 0x03, 0xee, 0x00, 0x37, + 0x01, 0x09, 0x02, 0x0e, 0x03, 0x18, 0x03, 0x1a, + 0x03, 0x20, 0x10, 0x2f, 0x11, 0x3f, 0x12, 0x44, + 0x01, 0x01, 0x07, 0x08, 0x0c, 0x00, 0x6c, 0x6c + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, + 0x02, 0xfe, 0x16, 0x10, 0x03, 0xee, 0x00, 0x37, + 0x01, 0x09, 0x02, 0x0e, 0x03, 0x18, 0x03, 0x1a, + 0x03, 0x20, 0x10, 0x2f, 0x11, 0x3f, 0x12, 0x44, + 0x01, 0x01, 0x07, 0x08, 0x0c, 0x00, 0x6c, 0x6c, + 0x00, 0xf9, 0x2f, 0x01, 0x97, 0x40, 0x01, 0x10, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfa, 0x45, 0x03, 0x10, 0x02, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8b, 0x00, 0x00, 0x00, 0x3a, 0x50, 0xf9, 0x2f, + 0x01, 0x18, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x88, 0xf9, 0x2f, + 0x01, 0x91, 0x99, 0x00, 0x10, 0xf8, 0x00, 0x00, + 0x00, 0xbe, 0x99, 0x00, 0x10, 0xa0, 0xa6, 0x04, + 0x10, 0x01, 0x9b, 0x00, 0x10, 0x18, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, + 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, + 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0x0d, 0xff, 0x36, + 0xdc, 0xf8, 0x2f, 0x01, 0xf1, 0x9d, 0x00, 0x10, + 0xfc, 0xf8, 0x2f, 0x01, 0x9d, 0xf8, 0x2f, 0x01, + 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x9e, 0xbf, 0x85, 0x85, 0x02, 0x05, 0x26, + 0x25, 0x4d, 0x13, 0x10, 0x00, 0x00, 0x00, 0x6c, + 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, + 0x01, 0x01, 0x09, 0x09, 0x0f, 0x00, 0x6c, 0x6c + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x0c, 0x37, 0x6a, 0x3d, + 0x73, 0x3d, 0x71, 0x0e, 0x01, 0x0e, 0x81, 0x3d, + 0x51, 0xf8, 0x2f, 0x01, 0x3a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x9e, 0xbf, 0x85, + 0x85, 0x02, 0x05, 0x26, 0x25, 0x4d, 0x13, 0x10, + 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0xcf, 0x00, + 0x01, 0x00, 0x00, 0x1f, 0x01, 0x01, 0x09, 0x09, + 0x0f, 0x00, 0x6c, 0x6c, 0xf0, 0xf8, 0x2f, 0x01 + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, + 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8b, 0x00, 0x01, 0x7c, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, + 0x14, 0xf5, 0x2f, 0x01, 0xa0, 0x20, 0x14, 0x00, + 0x40, 0xf8, 0x2f, 0x01, 0x05, 0x90, 0xf6, 0x77, + 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x50, 0xf8, 0x2f, 0x01, 0x40, 0x39, 0xf4, 0x77, + 0xa8, 0x20, 0x14, 0x00, 0x1c, 0xf6, 0x2f, 0x01, + 0x2c, 0x20, 0xf4, 0x77, 0x80, 0x4d, 0xfb, 0x77 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8b, 0x00, 0x03, 0xc8, 0x3a, 0x01, 0x00, 0x00, + 0x1f, 0x01, 0x01, 0x09, 0x09, 0x0f, 0x00, 0x6c, + 0x6c, 0x6c, 0x6c, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x6c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x62, 0x62, 0x62, 0x62, + 0x62, 0x51, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0xf9, 0x2f, 0x01, 0x4f, 0x9d, 0x00, + 0x10, 0x3a, 0x00, 0x00, 0x00, 0x04, 0xf9, 0x01 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8b, 0x00, 0x04, 0x02, 0x06, 0x0b, 0x07, 0x13, + 0x0e, 0x55, 0x56, 0x01, 0x44, 0xf8, 0x2f, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, + 0xc8, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x07, 0x00, 0x20, 0x00, 0x3a, 0x0e, 0x13, 0x07, + 0x0f, 0x14, 0x07, 0x10, 0x15, 0x07, 0x12, 0x16, + 0x07, 0x13, 0x17, 0x07, 0x14, 0x18, 0x07, 0x15, + 0x18, 0x07, 0x16, 0x19, 0x07, 0x17, 0x1a, 0x07, + 0x19, 0x1b, 0x07, 0x1a, 0x1c, 0x07, 0x1b, 0x1d, + 0x07, 0x1c, 0x1e, 0x07, 0x1d, 0x1f, 0x07, 0x1e, + 0x20, 0x07, 0x1f, 0x21, 0x07, 0x20, 0x22, 0x07, + 0x21, 0x23, 0x07, 0x23, 0x23, 0x07, 0x24, 0x55 + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x07, 0x00, 0x20, 0x3a, 0x26, 0x24, 0x07, 0x25, + 0x25, 0x07, 0x26, 0x25, 0x07, 0x27, 0x26, 0x07, + 0x28, 0x27, 0x07, 0x29, 0x27, 0x07, 0x2a, 0x28, + 0x07, 0x2b, 0x29, 0x07, 0x2d, 0x29, 0x07, 0x2e, + 0x2a, 0x07, 0x2f, 0x2b, 0x07, 0x30, 0x2b, 0x07, + 0x31, 0x2c, 0x07, 0x07, 0x1d, 0x1f, 0x07, 0x1e, + 0x20, 0x07, 0x1f, 0x21, 0x07, 0x20, 0x22, 0x07, + 0x21, 0x23, 0x07, 0x23, 0x23, 0x07, 0x24, 0x55 + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x06, 0x0e, 0x81, 0x0e, + 0x81, 0x09, 0x4d, 0x00, 0x07, 0x00, 0x20, 0x3a, + 0x26, 0x24, 0x07, 0x25, 0x25, 0x07, 0x26, 0x25, + 0x07, 0x27, 0x26, 0x07, 0x28, 0x27, 0x07, 0x29, + 0x27, 0x07, 0x2a, 0x28, 0x07, 0x2b, 0x29, 0x07, + 0x2d, 0x29, 0x07, 0x2e, 0x2a, 0x07, 0x2f, 0x2b, + 0x07, 0x30, 0x2b, 0x07, 0x31, 0x2c, 0x07, 0x07, + 0x1d, 0x1f, 0x07, 0x1e, 0x20, 0x07, 0x1f, 0x21 + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, + 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0x0e, 0x85, 0x36, + 0xd8, 0xf8, 0x2f, 0x01, 0xf1, 0x9d, 0x00, 0x10, + 0xf8, 0xf8, 0x2f, 0x01, 0x99, 0xf8, 0x2f, 0x01, + 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x9e, 0xbf, 0x85, 0x85, 0x02, 0x05, 0x26, + 0x25, 0x4d, 0x10, 0x10, 0x00, 0xff, 0x81, 0x6c, + 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, + 0x01, 0x01, 0x09, 0x09, 0x0f, 0x00, 0x6c, 0x6c + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0x0d, 0x00, 0x00, + 0x02, 0x9e, 0xbf, 0x85, 0x85, 0x02, 0x05, 0x26, + 0x25, 0x4d, 0x10, 0x10, 0x00, 0xff, 0x81, 0x6c, + 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, + 0x01, 0x01, 0x09, 0x09, 0x0f, 0x00, 0x6c, 0x6c, + 0xec, 0xf8, 0x2f, 0x01, 0x97, 0x40, 0x01, 0x10, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfa, 0x45, 0x03, 0x10, 0x02, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xf7, 0xcf, 0x00, + 0x01, 0x00, 0x00, 0x1f, 0x01, 0x01, 0x09, 0x09, + 0x0f, 0x00, 0x6c, 0x6c, 0x6c, 0x6c, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x62, + 0x62, 0x62, 0x62, 0x62, 0x51, 0x6c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xf7, 0x00, 0x00, + 0x02, 0xf9, 0xbf, 0x85, 0x85, 0x02, 0x05, 0x26, + 0x25, 0x4d, 0x10, 0x10, 0x00, 0xff, 0x81, 0x6c, + 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, + 0x01, 0x01, 0x09, 0x09, 0x0f, 0x00, 0x6c, 0x6c, + 0x6c, 0x6c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x6c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x62, 0x62, 0x62, 0x62, 0x62 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0xf7, 0xf4, 0x00, + 0x14, 0xf9, 0x2f, 0x01, 0x6d, 0x4f, 0x01, 0x10, + 0x94, 0xf8, 0x2f, 0x01, 0x40, 0x00, 0x00, 0x00, + 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0xf9, 0xbf, 0x85, 0x85, 0x02, 0x05, 0x26, + 0x25, 0x4d, 0x10, 0x10, 0x00, 0xff, 0x81, 0x6c, + 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, + 0x01, 0x01, 0x09, 0x09, 0x0f, 0x00, 0x6c, 0x6c + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0x20, 0x6c, 0x01, + 0x6d, 0x4f, 0x01, 0x10, 0x94, 0xf8, 0x2f, 0x01, + 0x40, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xf9, 0xbf, 0x85, + 0x85, 0x02, 0x05, 0x26, 0x25, 0x4d, 0x10, 0x10, + 0x00, 0xff, 0x81, 0x6c, 0x00, 0x00, 0xcf, 0x00, + 0x01, 0x00, 0x00, 0x1f, 0x01, 0x01, 0x09, 0x09, + 0x0f, 0x00, 0x6c, 0x6c, 0xe8, 0xf8, 0x2f, 0x01 + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xf9, 0x81, 0x6c, + 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, + 0x01, 0x01, 0x09, 0x09, 0x0f, 0x00, 0x6c, 0x6c, + 0xe8, 0xf8, 0x2f, 0x01, 0xec, 0xf8, 0x2f, 0x01, + 0x97, 0x40, 0x01, 0x10, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfa, 0x45, 0x03, 0x10, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0xf9, 0x01, 0x00, + 0x1c, 0xf9, 0x2f, 0x01, 0x6d, 0x4f, 0x01, 0x10, + 0x9c, 0xf8, 0x2f, 0x01, 0x40, 0x00, 0x00, 0x00, + 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x6c, 0xbf, 0x85, 0x85, 0x02, 0x05, 0x26, + 0x25, 0x4d, 0x10, 0x10, 0x00, 0xff, 0x81, 0x6c, + 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, + 0x01, 0x01, 0x09, 0x09, 0x0f, 0x00, 0x6c, 0x6c + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x12, 0x1c, 0x0c, 0x1b, + 0x08, 0x1a, 0x07, 0x30, 0x08, 0x09, 0x6d, 0x08, + 0x27, 0x00, 0x9e, 0x00, 0x1e, 0x23, 0x47, 0x01, + 0x40, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x6c, 0xbf, 0x85, + 0x85, 0x02, 0x05, 0x26, 0x25, 0x4d, 0x10, 0x10, + 0x00, 0xff, 0x81, 0x6c, 0x00, 0x00, 0xcf, 0x00, + 0x01, 0x00, 0x00, 0x1f, 0x01, 0x01, 0x09, 0x09 + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, + 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0x0d, 0xff, 0x36, + 0xdc, 0xf8, 0x2f, 0x01, 0xf1, 0x9d, 0x00, 0x10, + 0xfc, 0xf8, 0x2f, 0x01, 0x9d, 0xf8, 0x2f, 0x01, + 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x1e, 0x3f, 0x05, 0x05, 0x02, 0x05, 0x26, + 0x27, 0x6d, 0x10, 0x10, 0x00, 0xff, 0x85, 0x6c, + 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, + 0x01, 0x01, 0x07, 0x08, 0x0c, 0x00, 0x6c, 0x6c + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0xcf, + 0x00, 0x01, 0x00, 0x00, 0x1f, 0x01, 0x01, 0x10, + 0xfc, 0xf8, 0x2f, 0x01, 0x9d, 0xf8, 0x2f, 0x01, + 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x1e, 0x3f, 0x05, 0x05, 0x02, 0x05, 0x26, + 0x27, 0x6d, 0x10, 0x10, 0x00, 0xff, 0x85, 0x6c, + 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, + 0x01, 0x01, 0x07, 0x08, 0x0c, 0x00, 0x6c, 0x6c + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x08, 0x0e, 0x85, 0x09, + 0xed, 0x09, 0x6d, 0x09, 0xed, 0x1e, 0x3f, 0x05, + 0x05, 0x02, 0x05, 0x26, 0x27, 0x6d, 0x10, 0x10, + 0x00, 0xff, 0x85, 0x6c, 0x00, 0x00, 0xcf, 0x00, + 0x01, 0x00, 0x00, 0x1f, 0x01, 0x01, 0x07, 0x08, + 0x0c, 0x00, 0x6c, 0x6c, 0xf0, 0xf8, 0x2f, 0x01, + 0x97, 0x40, 0x01, 0x10, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3e, 0xf9, 0x2f, 0x01 + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xf3, 0x6c, 0x6c, + 0xf0, 0xf8, 0x2f, 0x01, 0x97, 0x40, 0x01, 0x10, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3e, 0xf9, 0x2f, 0x01, 0x04, 0xf9, 0x2f, 0x01, + 0x97, 0x40, 0x01, 0x10, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x03, 0x10, + 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x84, 0x00, 0x00, 0x00, 0x32, 0x02, 0xa3, 0x04, + 0x10, 0x3b, 0xa3, 0x04, 0x10, 0x1a, 0xa3, 0x04, + 0x10, 0xf9, 0xa2, 0x04, 0x10, 0xd8, 0xa2, 0x00, + 0xb9, 0x19, 0xe2, 0x87, 0xba, 0x56, 0x78, 0x72, + 0x68, 0x9e, 0x7a, 0xf4, 0x65, 0x6d, 0xd9, 0xde, + 0xf6, 0x33, 0xa2, 0x04, 0x10, 0x12, 0xa2, 0x04, + 0x10, 0xf1, 0xa1, 0x04, 0x10, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb4, 0x2d, 0x6c, 0xe9 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x06, 0x1a, 0x07, 0x1b, + 0x08, 0x1c, 0x0c, 0x77, 0x21, 0xac, 0xe5, 0x77, + 0x00, 0x00, 0x00, 0x00, 0xaa, 0x4e, 0x01, 0x10, + 0x3c, 0x01, 0x00, 0x00, 0xc4, 0xf8, 0x2f, 0x01, + 0xdc, 0xf8, 0x2f, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0xb9, 0x19, 0xe2, 0x87, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x08, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0xcf, + 0x00, 0x01, 0x00, 0x00, 0x1f, 0x01, 0x01, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xcc, 0xf8, 0x2f, 0x01, 0x8b, 0x41, 0x01, 0x10, + 0x8c, 0xf8, 0x2f, 0x01, 0x40, 0x00, 0x00, 0x00 + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x04, 0x3d, 0x51, 0x0a, + 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfc, 0xf9, 0x2f, 0x01, 0x31, 0x10, 0x01, 0x10, + 0xd0, 0xf9, 0x2f, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x1a, 0x07, 0x1b, 0x08, 0x1c, 0x0c, 0xc6, 0xf8, + 0x66, 0xbc, 0xc4, 0xbe, 0x0b, 0x25, 0xc5, 0x4c, + 0xf4, 0x03, 0x10, 0x2f, 0x11, 0x3f, 0x12, 0x44 + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, + 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0x0a, 0x10, 0x36, + 0x88, 0xf9, 0x2f, 0x01, 0xf1, 0x9d, 0x00, 0x10, + 0xa8, 0xf9, 0x2f, 0x01, 0x49, 0xf9, 0x2f, 0x01, + 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x1e, 0x3f, 0x05, 0x05, 0x02, 0x05, 0x26, + 0x27, 0xed, 0x00, 0x10, 0x00, 0xff, 0x85, 0x6c, + 0x00, 0x00, 0xcf, 0x00, 0x01, 0x00, 0x00, 0x1f, + 0x01, 0x01, 0x07, 0x08, 0x0c, 0x00, 0x6c, 0x6c + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x8b, 0x00, 0x00, 0xbc, 0x3a, 0x40, 0xd3, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd8, 0xf4, 0x2f, 0x01, 0x80, 0x69, 0x67, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0xfd, + 0x7f, 0x00, 0x60, 0xfd, 0x7f, 0x3c, 0x01, 0x00, + 0x00, 0xa0, 0xf5, 0x2f, 0x01, 0x03, 0x01, 0x00, + 0x00, 0x9a, 0x11, 0xf4, 0x77, 0x9f, 0x11, 0xf4, + 0x77, 0x3c, 0x01, 0x00, 0x00, 0xa0, 0xf5, 0x01 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8b, 0x00, 0x00, 0xf6, 0x3a, 0x0b, 0x07, 0xa5, + 0x03, 0x2f, 0x63, 0x97, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8b, 0x00, 0x01, 0x30, 0x3a, 0x0b, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x12, 0xcd, 0xa6, 0x3c, + 0x36, 0xec, 0x6a, 0x73, 0x00, 0x64, 0x75, 0xdf, + 0x2e, 0x13, 0xec, 0xca, 0x3c, 0x03, 0x00, 0x00, + 0x06, 0xa5, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8b, 0x00, 0x01, 0x6a, 0x3a, 0x0b, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8b, 0x00, 0x01, 0xa4, 0x3a, 0x0b, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0xa5, 0x83, 0x1b, 0x8e, 0xac, 0x00, 0x00, + 0x0b, 0xa5, 0x08, 0x08, 0x03, 0x00, 0x00, 0x01, + 0x02, 0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8d, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8b, 0x00, 0x01, 0xde, 0x3a, 0x0b, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8b, 0x00, 0x02, 0x18, 0x3a, 0x0b, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8b, 0x00, 0x02, 0x52, 0x3a, 0x0b, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8b, 0x00, 0x02, 0x8c, 0x3a, 0x0b, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8b, 0x00, 0x02, 0xc6, 0x2a, 0x0b, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, + 0xc8, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xf1, 0x2f, 0x01, + 0x49, 0xf9, 0x2f, 0x01, 0x3a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x1e, 0x3f, 0x05, + 0x05, 0x02, 0x05, 0x26, 0x27, 0xed, 0x00, 0x10, + 0x00, 0xff, 0x85, 0x6c, 0x00, 0x00, 0xcf, 0x00, + 0x01, 0x00, 0x00, 0x1f, 0x01, 0x01, 0x07, 0x08, + 0x0c, 0x00, 0x6c, 0x6c, 0x9c, 0xf9, 0x2f, 0x01, + 0x97, 0x40, 0x01, 0x10, 0x03, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0xf1, 0x01, 0x00, + 0xb4, 0xf9, 0x2f, 0x01, 0x6d, 0x4f, 0x01, 0x10, + 0x34, 0xf9, 0x2f, 0x01, 0x40, 0x00, 0x00, 0x00, + 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x8b, 0x00, 0x01, 0x10, 0x3a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8b, 0x00, 0x01, 0x4a, 0x2e, 0x0b, 0x06, 0xa5, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, + 0xc8, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xfb, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x88, 0xf9, 0x2f, 0x01, 0x97, 0x40, 0x01, 0x10, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfa, 0x45, 0x03, 0x10, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0xfb, 0x0f, 0x00, + 0xc4, 0xf9, 0x2f, 0x01, 0x6d, 0x4f, 0x01, 0x10, + 0x44, 0xf9, 0x2f, 0x01, 0x40, 0x00, 0x00, 0x00, + 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .response_len = 0x00 + } }; static const struct setup_cmd upeket_setup_commands[] = { - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xF3, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0xfe, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x00, 0x00, 0x00, 0x98, 0xf1, 0x12, 0x00, - 0x03, 0xd4, 0xa9, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x14, 0x20, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x84, 0xf1, 0x12, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x90, 0xf1, 0x12, 0x00, - 0xac, 0x0d, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xf7, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x90, 0xf1, 0x12, 0x00, - 0x92, 0xc5, 0xa9, 0x00, 0x48, 0xf1, 0x12, 0x00, - 0x40, 0x00, 0x00, 0x00, 0xa2, 0xc5, 0xa9, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x02, 0xfe, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x00, 0x00, 0x00, 0x98, 0xf1, 0x12, 0x00, - 0x03, 0xd4, 0xa9, 0x00, 0x64, 0x00, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0xf7, 0xcd, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xf8, 0xa9, 0x00, - 0x28, 0xf1, 0x12, 0x00, 0x40, 0x00, 0x00, 0x00, - 0xbb, 0xc4, 0xa9, 0x00, 0x02, 0xfa, 0x3f, 0x05, - 0x05, 0x02, 0x05, 0x23, 0x27, 0xe5, 0x13, 0x10, - 0x08, 0xff, 0x04, 0x6c, 0xc1, 0x41, 0x1c, 0x4c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x60, 0xf1, 0x12, 0x00, 0x89, 0xae, 0xa9, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8b, 0x00, 0x00, 0x00, 0x3a, 0x8c, 0xf1, 0x12, - 0x00, 0x64, 0xa8, 0xa7, 0x00, 0x84, 0xf1, 0x12, - 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf1, 0x12, - 0x00, 0x51, 0xa6, 0xa7, 0x00, 0xf8, 0x00, 0x00, - 0x00, 0x7e, 0xa6, 0xa7, 0x00, 0x24, 0x5a, 0xac, - 0x00, 0x01, 0xf1, 0x12, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x2f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x7c, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0x0d, 0xff, 0x00, - 0x34, 0xf1, 0x12, 0x00, 0x40, 0x00, 0x00, 0x00, - 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xf1, 0x12, 0x00, 0x57, 0xcc, 0xa9, 0x00, - 0x34, 0xf1, 0x12, 0x00, 0x40, 0x00, 0x00, 0x00, - 0xbd, 0xcc, 0xa9, 0x00, 0x3a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, - 0x34, 0xf1, 0x12, 0x00, 0x3a, 0x00, 0x00, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x0a, 0x37, 0x6a, 0x3d, - 0x73, 0x3d, 0x71, 0x0e, 0x01, 0x0e, 0x81, 0x00, - 0x40, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x12, 0x00, - 0x57, 0xcc, 0xa9, 0x00, 0x34, 0xf1, 0x12, 0x00, - 0x40, 0x00, 0x00, 0x00, 0xbd, 0xcc, 0xa9, 0x00, - 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb8, 0x00, 0x00, 0x00, 0x34, 0xf1, 0x12, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0x3d, 0x51, 0x0e, - 0x01, 0x0e, 0x81, 0x00, 0x40, 0x00, 0x00, 0x00, - 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xf1, 0x12, 0x00, 0x57, 0xcc, 0xa9, 0x00, - 0x34, 0xf1, 0x12, 0x00, 0x40, 0x00, 0x00, 0x00, - 0xbd, 0xcc, 0xa9, 0x00, 0x3a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, - 0x34, 0xf1, 0x12, 0x00, 0x3a, 0x00, 0x00, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x04, 0x78, 0x3A, 0x34, 0x00, 0x00, - 0xC0, 0x00, 0x00, 0x00, 0x00, 0x24, 0x1A, 0x80, - 0x7C, 0x04, 0xF1, 0x12, 0x00, 0x18, 0x00, 0x00, - 0x00, 0x48, 0x00, 0x00, 0x00, 0xCC, 0xEF, 0x12, - 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xB0, 0xEF, 0x12, 0x00, 0x0C, 0x00, 0x0C, - 0x00, 0x84, 0x21, 0x15, 0x00, 0x48, 0x00, 0x00, - 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x04, 0xB2, 0x3A, 0x0B, 0x88, 0x01, - 0xB4, 0x01, 0x20, 0x91, 0x04, 0x07, 0x02, 0x24, - 0x20, 0xE2, 0x15, 0x0D, 0x10, 0x0F, 0x10, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x12, 0x13, 0x13, 0x13, - 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, - 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, - 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, - 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x04, 0xEC, 0x3A, 0x0B, 0x1C, 0x1C, - 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, - 0x1E, 0x1D, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1F, 0x1F, 0x20, - 0x20, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x20, 0x21, - 0x20, 0x21, 0x20, 0x20, 0x20, 0x21, 0x20, 0x21, - 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x21, - 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x22, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x05, 0x26, 0x3A, 0x0B, 0x22, 0x22, - 0x22, 0x21, 0x22, 0x22, 0x22, 0x21, 0x22, 0x22, - 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x21, 0x21, - 0x22, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x21, - 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x20, 0x20, 0x21, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x1F, 0x1F, 0x1F, 0x1F, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x05, 0x60, 0x3A, 0x0B, 0x1F, 0x1F, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, - 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, - 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, - 0x1E, 0x1E, 0x1E, 0x1E, 0x1D, 0x1D, 0x1D, 0x1D, - 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1C, 0x1D, 0x1D, - 0x1D, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, - 0x1B, 0x1B, 0x1C, 0x1C, 0x1B, 0x1B, 0x1B, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x05, 0x9A, 0x3A, 0x0B, 0x1B, 0x1B, - 0x1B, 0x1A, 0x1B, 0x1B, 0x1A, 0x1A, 0x1A, 0x1B, - 0x1B, 0x1B, 0x1B, 0x1A, 0x19, 0x1A, 0x1A, 0x1A, - 0x1A, 0x19, 0x1A, 0x1A, 0x1A, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x18, 0x19, 0x18, 0x18, 0x19, - 0x18, 0x17, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x16, 0x17, 0x16, 0x16, 0x15, - 0x15, 0x16, 0x15, 0x16, 0x15, 0x15, 0x14, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x05, 0xD4, 0x2C, 0x0B, 0x14, 0x15, - 0x14, 0x14, 0x14, 0x13, 0x13, 0x13, 0x12, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x6E, 0x12, 0x00, 0x2B, 0xC5, 0xA9, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x7C, 0xEF, 0x12, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x01, 0x68, 0x0A, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xD0, 0xFD, 0x7F, 0xDC, 0x6D, 0x12, 0x00, - 0x2A, 0x26, 0x80, 0x7C, 0x98, 0x6D, 0x12, 0x00, - 0x00, 0x26, 0x80, 0x7C, 0xB8, 0x00, 0x00, 0x00, - 0x0C, 0x80, 0x01, 0x10, 0x90, 0x3E, 0x94, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x03, 0xB4, 0x3A, 0x1F, 0x1F, 0x1F, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, - 0x1E, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, - 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, - 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1D, 0x1D, 0x1D, - 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1C, 0x1D, - 0x1D, 0x1D, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x03, 0xEE, 0x06, 0x0B, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x85, 0xB7, 0xA9, 0x00, - 0xB8, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00, - 0x18, 0x70, 0x12, 0x00, 0x2B, 0xC5, 0xA9, 0x00, - 0x64, 0x00, 0x00, 0x00, 0xD4, 0xF0, 0x12, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x07, 0x00, 0x20, 0x00, 0x3a, 0x32, 0x2b, 0x07, - 0x2e, 0x29, 0x07, 0x2b, 0x27, 0x07, 0x27, 0x25, - 0x07, 0x23, 0x23, 0x07, 0x20, 0x21, 0x07, 0x1c, - 0x1d, 0x07, 0x19, 0x1a, 0x07, 0x15, 0x17, 0x07, - 0x12, 0x15, 0x07, 0x0e, 0x14, 0x07, 0x12, 0x17, - 0x07, 0x15, 0x19, 0x07, 0x19, 0x1c, 0x07, 0x1c, - 0x1f, 0x07, 0x20, 0x23, 0x07, 0x23, 0x25, 0x07, - 0x27, 0x27, 0x07, 0x2b, 0x29, 0x07, 0x2e, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x07, 0x00, 0x20, 0x3a, 0x26, 0x2b, 0x07, 0x32, - 0x2d, 0x07, 0x32, 0x2f, 0x07, 0x2e, 0x2d, 0x07, - 0x2b, 0x2b, 0x07, 0x27, 0x29, 0x07, 0x23, 0x27, - 0x07, 0x20, 0x25, 0x07, 0x1c, 0x22, 0x07, 0x19, - 0x1e, 0x07, 0x15, 0x1b, 0x07, 0x12, 0x19, 0x07, - 0x0e, 0x16, 0x07, 0x07, 0x19, 0x1c, 0x07, 0x1c, - 0x1f, 0x07, 0x20, 0x23, 0x07, 0x23, 0x25, 0x07, - 0x27, 0x27, 0x07, 0x2b, 0x29, 0x07, 0x2e, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x06, 0x0e, 0x81, 0x0e, - 0x81, 0x09, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x26, 0x00, 0x00, 0x00, 0x07, 0x00, 0x20, 0x3a, - 0x26, 0x2b, 0x07, 0x32, 0x2d, 0x07, 0x32, 0x2f, - 0x07, 0x2e, 0x2d, 0x07, 0x2b, 0x2b, 0x07, 0x27, - 0x29, 0x07, 0x23, 0x27, 0x07, 0x20, 0x25, 0x07, - 0x1c, 0x22, 0x07, 0x19, 0x1e, 0x07, 0x15, 0x1b, - 0x07, 0x12, 0x19, 0x07, 0x0e, 0x16, 0x07, 0x07, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, - 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0x0e, 0x85, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x20, 0x3a, 0x26, 0x2b, 0x07, 0x32, - 0x2d, 0x07, 0x32, 0x2f, 0x07, 0x2e, 0x2d, 0x07, - 0x2b, 0x2b, 0x07, 0x29, 0x07, 0x23, 0x27, 0x07, - 0x20, 0x25, 0x07, 0x1c, 0x22, 0x07, 0x19, 0x1e, - 0x07, 0x15, 0x1b, 0x07, 0x12, 0x19, 0x07, 0x1f, - 0x0e, 0x16, 0x07, 0x07, 0x19, 0x1c, 0x07, 0x1c, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0x0d, 0x62, 0x62, - 0x51, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, - 0x3a, 0x41, 0x0e, 0x2b, 0x00, 0x00, 0x00, 0x00, - 0x78, 0xf1, 0x12, 0x00, 0x1a, 0xaa, 0xa7, 0x1f, - 0x00, 0x3a, 0x09, 0x00, 0x00, 0x00, 0x12, 0x41, - 0x0e, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x4c, 0xf1, 0x12, 0x00, 0x89, 0xae, - 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0x20, 0x6C, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x20, 0x3A, 0x26, 0x2B, 0x07, 0x32, - 0x2D, 0x07, 0x32, 0x2F, 0x07, 0x2E, 0x2D, 0x07, - 0x2B, 0x2B, 0x07, 0x27, 0x29, 0x07, 0x23, 0x27, - 0x07, 0x20, 0x25, 0x07, 0x1C, 0x22, 0x07, 0x19, - 0x1E, 0x07, 0x15, 0x1B, 0x07, 0x12, 0x19, 0x07, - 0x0E, 0x16, 0x07, 0x07, 0x19, 0x1C, 0x07, 0x1C, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xF9, 0x6C, 0x6C, - 0x6C, 0x6C, 0x40, 0x40, 0x2E, 0x6D, 0x64, 0xED, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x4C, 0xF1, 0x12, 0x00, 0x89, 0xAE, 0xA9, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xE8, 0x3D, 0xAC, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x68, 0xF1, 0x12, 0x00, - 0x14, 0xAB, 0xA7, 0x00, 0x03, 0x00, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0xF9, 0x00, 0x00, - 0x26, 0x00, 0x00, 0x00, 0x07, 0x00, 0x20, 0x3A, - 0x26, 0x2B, 0x07, 0x32, 0x2D, 0x07, 0x32, 0x2F, - 0x07, 0x2E, 0x2D, 0x07, 0x2B, 0x2B, 0x07, 0x27, - 0x29, 0x07, 0x23, 0x27, 0x07, 0x20, 0x25, 0x07, - 0x1C, 0x22, 0x07, 0x19, 0x1E, 0x07, 0x15, 0x1B, - 0x07, 0x12, 0x19, 0x07, 0x0E, 0x16, 0x07, 0x07, - 0x19, 0x1C, 0x07, 0x1C, 0xBA, 0xEC, 0x64, 0xED, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x16, 0x1C, 0x13, 0x1B, - 0x0B, 0x1A, 0x0A, 0x30, 0x08, 0x09, 0x6D, 0x08, - 0xA7, 0x00, 0x9E, 0x00, 0x1E, 0x0C, 0x08, 0x1D, - 0x04, 0x23, 0x42, 0x2F, 0x07, 0x2E, 0x2D, 0x07, - 0x2B, 0x2B, 0x07, 0x27, 0x29, 0x07, 0x23, 0x27, - 0x07, 0x20, 0x25, 0x07, 0x1C, 0x22, 0x07, 0x19, - 0x1E, 0x07, 0x15, 0x1B, 0x07, 0x12, 0x19, 0x07, - 0x0E, 0x16, 0x07, 0x07, 0x19, 0x1C, 0x07, 0x1C, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, - 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, - 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0x0D, 0xFF, 0x30, - 0x08, 0x09, 0x6D, 0x08, 0xA7, 0x00, 0x9E, 0x00, - 0x1E, 0x0C, 0x08, 0x1D, 0x04, 0x23, 0x42, 0x2F, - 0x07, 0x2E, 0x2D, 0x07, 0x2B, 0x2B, 0x07, 0x27, - 0x29, 0x07, 0x23, 0x27, 0x07, 0x20, 0x25, 0x07, - 0x1C, 0x22, 0x07, 0x19, 0x1E, 0x07, 0x15, 0x1B, - 0x07, 0x12, 0x19, 0x07, 0x0E, 0x16, 0x07, 0x07, - 0x19, 0x1C, 0x07, 0x1C, 0xBA, 0xEC, 0x64, 0xED, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xF7, 0x64, 0xED, - 0x00, 0x00, 0x00, 0x00, 0x7C, 0xF1, 0x12, 0x00, - 0x1A, 0xAA, 0xA7, 0x00, 0x3A, 0x00, 0x00, 0x00, - 0x2A, 0x6D, 0x64, 0xED, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x50, 0xF1, 0x12, 0x00, - 0x89, 0xAE, 0xA9, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xE8, 0x3D, 0xAC, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xF7, 0xA9, 0x00, - 0x02, 0xFA, 0x3F, 0x05, 0x05, 0xC2, 0x85, 0xA6, - 0xA7, 0x6D, 0x10, 0x10, 0x08, 0xFF, 0x85, 0x6C, - 0x00, 0x00, 0xCF, 0x00, 0x01, 0x00, 0x00, 0x1F, - 0x01, 0x01, 0x0A, 0x0B, 0x13, 0x04, 0x6C, 0x6C, - 0x6C, 0x6C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x6C, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x40, 0x42, 0x42, 0x42, 0x42, 0x42, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0xF7, 0xF3, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x02, 0x0D, 0xFF, 0x30, - 0x08, 0x09, 0x6D, 0x08, 0xA7, 0x00, 0x9E, 0x00, - 0x1E, 0x0C, 0x08, 0x1D, 0x04, 0x23, 0x42, 0x2F, - 0x07, 0x2E, 0x2D, 0x07, 0x2B, 0x2B, 0x07, 0x27, - 0x29, 0x07, 0x23, 0x27, 0x07, 0x20, 0x25, 0x07, - 0x1C, 0x22, 0x07, 0x19, 0x1E, 0x07, 0x15, 0x1B, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xE8, 0x3D, 0xAC, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x5C, 0xF1, 0x12, 0x00, 0x14, 0xAB, 0xA7, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x5C, 0xF1, 0x12, 0x00, - 0x20, 0xAB, 0xA7, 0x00, 0x58, 0xF1, 0x12, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x99, 0xA9, 0xA7, 0x00, - 0xE8, 0x3D, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x8F, 0x2F, - 0x07, 0x2E, 0x2D, 0x07, 0x2B, 0x2B, 0x07, 0x27, - 0x29, 0x07, 0x23, 0x27, 0x07, 0x20, 0x25, 0x07, - 0x1C, 0x22, 0x07, 0x19, 0x1E, 0x07, 0x15, 0x1B, - 0x07, 0x12, 0x19, 0x07, 0x82, 0xEC, 0x64, 0xED, - 0x24, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xEA, 0x3D, 0xAC, 0x00, 0xBD, 0xCC, 0xA9, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x08, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0xCF, - 0x00, 0x01, 0x00, 0x00, 0x1F, 0x01, 0x01, 0x00, - 0x0C, 0xCF, 0xA9, 0x00, 0x74, 0x70, 0x12, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x1C, 0xCF, 0xA9, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x8F, 0x2F, - 0x07, 0x2E, 0x2D, 0x07, 0x2B, 0x2B, 0x07, 0x27, - 0x29, 0x07, 0x23, 0x27, 0x07, 0x20, 0x25, 0x07, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x06, 0x0E, 0x85, 0x09, - 0xED, 0x09, 0x6D, 0x2F, 0x07, 0x2E, 0x2D, 0x07, - 0x2B, 0x2B, 0x07, 0x27, 0x29, 0x07, 0x23, 0x27, - 0x07, 0x20, 0x25, 0x07, 0x1C, 0x22, 0x07, 0x19, - 0x8A, 0xEC, 0x64, 0xED, 0x1C, 0xF1, 0x12, 0x00, - 0xFA, 0xCB, 0xA9, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x72, 0xF1, 0x12, 0x00, - 0xBD, 0xCC, 0xA9, 0x00, 0x0A, 0x00, 0x00, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, - 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, - 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0x09, 0xED, 0x2F, - 0x07, 0x2E, 0x2D, 0x07, 0x2B, 0x2B, 0x07, 0x27, - 0x29, 0x07, 0x23, 0x27, 0x07, 0x20, 0x25, 0x07, - 0x1C, 0x22, 0x07, 0x19, 0x8A, 0xEC, 0x64, 0xED, - 0x1C, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x72, 0xF1, 0x12, 0x00, 0xBD, 0xCC, 0xA9, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0xBD, 0xCC, 0xA9, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xF3, 0x00, 0x00, - 0x8C, 0xF1, 0x12, 0x00, 0x1A, 0xAA, 0xA7, 0x00, - 0x3A, 0x00, 0x00, 0x00, 0x5A, 0x6D, 0x64, 0xED, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x60, 0xF1, 0x12, 0x00, 0x89, 0xAE, 0xA9, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xE8, 0x3D, 0xAC, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7C, 0xF1, 0x12, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x84, 0x00, 0x00, 0x00, 0x32, 0x02, 0xE0, 0xAD, - 0x00, 0xFC, 0xDF, 0xAD, 0x00, 0xDB, 0xDF, 0xAD, - 0x00, 0xBA, 0xDF, 0xAD, 0x00, 0x99, 0xDF, 0x6F, - 0x44, 0xC2, 0xE8, 0x20, 0x65, 0x73, 0x83, 0xAC, - 0xD7, 0x88, 0x6D, 0x59, 0x61, 0xE0, 0x3B, 0x3D, - 0xB7, 0xF4, 0xDE, 0xAD, 0x00, 0xD3, 0xDE, 0xAD, - 0x00, 0xB2, 0xDE, 0xAD, 0x00, 0x91, 0xDE, 0x00, - 0xA6, 0xEC, 0x64, 0xED, 0xA2, 0xEC, 0x64, 0xED, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x06, 0x1A, 0x0A, 0x1B, - 0x0B, 0x1C, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x92, 0xD5, 0x90, 0x7C, 0xBB, 0x9B, 0x80, 0x7C, - 0xB8, 0x00, 0x00, 0x00, 0xAC, 0x70, 0x12, 0x00, - 0x85, 0xB7, 0xA9, 0x00, 0xB8, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x08, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0xCF, - 0x00, 0x01, 0x00, 0x00, 0x1F, 0x01, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00, - 0x4C, 0x70, 0x12, 0x00, 0xEB, 0xC4, 0xA9, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x68, 0x70, 0x12, 0x00, - 0x40, 0x00, 0x00, 0x00, 0xE8, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xB0, 0x70, 0x12, 0x00, - 0x0C, 0xCF, 0xA9, 0x00, 0x68, 0x70, 0x12, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0x0D, 0x00, 0x00, - 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1F, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, - 0xD0, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0xA6, 0xB5, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x94, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x28, 0x6F, 0x44, 0xC2, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x04, 0x78, 0x3A, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xD0, 0xFD, 0x7F, 0x94, 0xF0, 0x12, - 0x00, 0x2A, 0x26, 0x80, 0x7C, 0x50, 0xF0, 0x12, - 0x00, 0x00, 0x26, 0x80, 0x7C, 0x08, 0x00, 0x00, - 0x00, 0x0C, 0x80, 0x01, 0x10, 0x90, 0x3E, 0x94, - 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x00, 0x00, 0x00, 0x80, 0x69, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x04, 0xB2, 0x3A, 0x0B, 0x88, 0x01, - 0xB4, 0x01, 0x20, 0x91, 0x04, 0x07, 0x02, 0x24, - 0x20, 0xE2, 0x15, 0x0D, 0x10, 0x0F, 0x10, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x12, 0x13, 0x13, 0x13, - 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, - 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, - 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, - 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x04, 0xEC, 0x3A, 0x0B, 0x1C, 0x1C, - 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, - 0x1E, 0x1D, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1F, 0x1F, 0x20, - 0x20, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x20, 0x21, - 0x20, 0x21, 0x20, 0x20, 0x20, 0x21, 0x20, 0x21, - 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x21, - 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x22, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x05, 0x26, 0x3A, 0x0B, 0x22, 0x22, - 0x22, 0x21, 0x22, 0x22, 0x22, 0x21, 0x22, 0x22, - 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x21, 0x21, - 0x22, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x21, - 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x20, 0x20, 0x21, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x1F, 0x1F, 0x1F, 0x1F, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x05, 0x60, 0x3A, 0x0B, 0x1F, 0x1F, - 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, - 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, - 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, - 0x1E, 0x1E, 0x1E, 0x1E, 0x1D, 0x1D, 0x1D, 0x1D, - 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1C, 0x1D, 0x1D, - 0x1D, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, - 0x1B, 0x1B, 0x1C, 0x1C, 0x1B, 0x1B, 0x1B, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x05, 0x9A, 0x3A, 0x0B, 0x1B, 0x1B, - 0x1B, 0x1A, 0x1B, 0x1B, 0x1A, 0x1A, 0x1A, 0x1B, - 0x1B, 0x1B, 0x1B, 0x1A, 0x19, 0x1A, 0x1A, 0x1A, - 0x1A, 0x19, 0x1A, 0x1A, 0x1A, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x18, 0x19, 0x18, 0x18, 0x19, - 0x18, 0x17, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x16, 0x17, 0x16, 0x16, 0x15, - 0x15, 0x16, 0x15, 0x16, 0x15, 0x15, 0x14, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x05, 0xD4, 0x2C, 0x0B, 0x14, 0x15, - 0x14, 0x14, 0x14, 0x13, 0x13, 0x13, 0x12, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x6F, 0x12, 0x00, 0x2B, 0xC5, 0xA9, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x2C, 0xF0, 0x12, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xF7, 0x1C, 0x1C, - 0x1B, 0x1B, 0x1C, 0x1C, 0x1B, 0x1B, 0x1B, 0x1B, - 0x1B, 0x1B, 0x1B, 0x1A, 0x1B, 0x1B, 0x1A, 0x1A, - 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, 0x1A, 0x19, 0x1A, - 0x1A, 0x1A, 0x1A, 0x19, 0x1A, 0x1A, 0x1A, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x19, 0x18, - 0x18, 0x19, 0x18, 0x17, 0x18, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x16, 0x17, 0x16, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0xF7, 0xF3, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x04, 0x3D, 0x40, 0x0A, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x52, 0xED, 0x64, 0xED, - 0xD4, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, - 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, - 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0x0A, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x52, 0xED, 0x64, 0xED, 0xD4, 0xF1, 0x12, 0x00, - 0xFA, 0xCB, 0xA9, 0x00, 0x03, 0x00, 0x00, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x8B, 0x00, 0x00, 0xA8, 0x3A, 0x00, 0x00, 0x00, - 0x00, 0xDC, 0x00, 0xEA, 0x00, 0x20, 0xED, 0x12, - 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x00, 0xDC, 0xFD, - 0x7F, 0x20, 0xED, 0x12, 0x00, 0x05, 0x00, 0x00, - 0x00, 0xA0, 0x20, 0x15, 0x00, 0xC8, 0x00, 0x00, - 0x01, 0x43, 0x00, 0x3A, 0x00, 0x5C, 0x00, 0x44, - 0x00, 0x6F, 0x00, 0x63, 0x00, 0x75, 0x00, 0x6D, - 0x00, 0x65, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x00, 0xE2, 0x3A, 0x0B, 0x07, 0xA5, - 0x03, 0x2F, 0x63, 0x97, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x01, 0x1C, 0x3A, 0x0B, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x12, 0x75, 0xB3, 0x05, - 0xE2, 0xBC, 0x74, 0x68, 0xAD, 0xAC, 0x7B, 0xB1, - 0xF8, 0x52, 0xD5, 0x8F, 0xF7, 0x03, 0x00, 0x00, - 0x06, 0xA5, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x01, 0x56, 0x3A, 0x0B, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x01, 0x90, 0x3A, 0x0B, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0xA5, 0x00, 0x22, 0x8E, 0xA3, 0x00, 0x00, - 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x4C, 0xA5, 0xC8, 0xC8, 0x41, 0x50, 0x52, 0x39, - 0x07, 0x01, 0x00, 0x5F, 0x00, 0x00, 0xFF, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x01, 0xCA, 0x3A, 0x0B, 0x01, 0x48, - 0x34, 0x33, 0x00, 0x00, 0x00, 0x00, 0x76, 0x3E, - 0x84, 0x10, 0x2E, 0x48, 0x54, 0x0D, 0x98, 0x4C, - 0x14, 0x12, 0x72, 0x7A, 0x88, 0x0F, 0x9F, 0x84, - 0x98, 0x03, 0x52, 0xA6, 0xA4, 0x0A, 0x6E, 0xA8, - 0x54, 0x0C, 0x13, 0xB6, 0xE8, 0x0A, 0x77, 0xC0, - 0x94, 0x04, 0x73, 0xC6, 0x14, 0x07, 0x80, 0xCA, - 0xA8, 0x08, 0x31, 0xD2, 0x44, 0x09, 0x1E, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x02, 0x04, 0x3A, 0x0B, 0x74, 0x09, - 0x7A, 0xE4, 0x78, 0x17, 0xA5, 0xE4, 0x24, 0x09, - 0x45, 0xE8, 0x68, 0x07, 0xBA, 0xEC, 0xE8, 0x05, - 0xC2, 0xF0, 0x58, 0x16, 0x78, 0xF6, 0x98, 0x15, - 0x7C, 0xFC, 0xB8, 0x19, 0xAD, 0xFC, 0x74, 0x09, - 0x8C, 0x02, 0x39, 0x0D, 0x36, 0x06, 0x99, 0x06, - 0x9B, 0x08, 0x09, 0x0B, 0xA1, 0x0C, 0x25, 0x19, - 0x57, 0x10, 0x29, 0x05, 0x1A, 0x1C, 0x45, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x02, 0x3E, 0x3A, 0x0B, 0x55, 0x1E, - 0x69, 0x16, 0xA4, 0x24, 0xB9, 0x09, 0x1C, 0x44, - 0x55, 0x08, 0x9C, 0x44, 0xC9, 0x0B, 0x9F, 0x4A, - 0xF9, 0x19, 0x4C, 0x4C, 0xF9, 0x13, 0x5E, 0x50, - 0x09, 0x13, 0xB7, 0x6A, 0x09, 0x0A, 0x7C, 0x7A, - 0x75, 0x0F, 0x0E, 0x7E, 0x95, 0x00, 0x81, 0xA6, - 0x99, 0x0E, 0xC0, 0xAE, 0xE5, 0x19, 0xA0, 0xCC, - 0x35, 0x0D, 0x63, 0xE2, 0x85, 0x1F, 0x8E, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x02, 0x78, 0x3A, 0x0B, 0x35, 0x1D, - 0xC1, 0xE8, 0xA9, 0x0C, 0x7A, 0x06, 0xCA, 0x0E, - 0xAD, 0x12, 0xD6, 0x1C, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x02, 0xB2, 0x2A, 0x0B, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x6C, 0x12, 0x00, 0x2B, 0xC5, 0xA9, 0x00, - 0x64, 0x00, 0x00, 0x00, 0xFC, 0xEC, 0x12, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xF1, 0x42, 0x42, - 0x40, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, - 0xCE, 0x6D, 0x64, 0xED, 0x00, 0x00, 0x00, 0x00, - 0x30, 0xF2, 0x12, 0x00, 0x1A, 0xAA, 0xA7, 0x00, - 0x3A, 0x00, 0x00, 0x00, 0xF6, 0x6D, 0x64, 0xED, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0xF2, 0x12, 0x00, 0x89, 0xAE, 0xA9, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0xF1, 0x01, 0x00, - 0x1C, 0xCF, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x02, 0x0A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x8B, 0x00, 0x00, 0xFC, 0x3A, 0x1E, 0xDC, 0x74, - 0x09, 0x7A, 0xE4, 0x78, 0x17, 0xA5, 0xE4, 0x24, - 0x09, 0x45, 0xE8, 0x68, 0x07, 0xBA, 0xEC, 0xE8, - 0x05, 0xC2, 0xF0, 0x58, 0x16, 0x78, 0xF6, 0x98, - 0x15, 0x7C, 0xFC, 0xB8, 0x19, 0xAD, 0xFC, 0x74, - 0x09, 0x8C, 0x02, 0x39, 0x0D, 0x36, 0x06, 0x99, - 0x06, 0x9B, 0x08, 0x09, 0x0B, 0xA1, 0x0C, 0x25, - 0x19, 0x57, 0x10, 0x29, 0x05, 0x1A, 0x1C, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x8B, 0x00, 0x01, 0x36, 0x2E, 0x0B, 0x06, 0xA5, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2B, 0xC5, 0xA9, 0x00, - 0x64, 0x00, 0x00, 0x00, 0xD8, 0xEE, 0x12, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xF0, 0xAC, 0x00, - 0xF0, 0xF1, 0x12, 0x00, 0x6A, 0xB1, 0xA7, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x06, 0xA5, 0x00, 0x01, - 0x00, 0x00, 0x12, 0x00, 0x14, 0xAB, 0xA7, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x0C, 0xF2, 0x12, 0x00, - 0x20, 0xAB, 0xA7, 0x00, 0x08, 0xF2, 0x12, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x99, 0xA9, 0xA7, 0x00, - 0xE8, 0x3D, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x8F, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x52, 0xED, 0x64, 0xED, - 0xD4, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xEA, 0x3D, 0xAC, 0x00, 0xBD, 0xCC, 0xA9, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xF7, 0x12, 0x00, - 0x88, 0xC4, 0xA9, 0x00, 0xD8, 0xF1, 0x12, 0x00, - 0x40, 0x00, 0x00, 0x00, 0xBB, 0xC4, 0xA9, 0x00, - 0x02, 0x00, 0x3F, 0x05, 0x0B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xEA, 0x6D, 0x64, 0xED, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0xF2, 0x12, 0x00, - 0x89, 0xAE, 0xA9, 0x00, 0x03, 0x00, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xF7, 0xA9, 0x00, - 0x02, 0xFA, 0x3F, 0x05, 0x0B, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0xF7, 0xF3, 0x00, - 0x0C, 0xCF, 0xA9, 0x00, 0x24, 0x71, 0x12, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x1C, 0xCF, 0xA9, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x8F, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x01, 0xFB, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF1, 0x12, 0x00, - 0x89, 0xAE, 0xA9, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xE8, 0x3D, 0xAC, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0C, 0xF2, 0x12, 0x00, 0x14, 0xAB, 0xA7, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x0C, 0xF2, 0x12, 0x00, - 0x20, 0xAB, 0xA7, 0x00, 0x08, 0xF2, 0x12, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0xFB, 0x0F, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x8F, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x52, 0xED, 0x64, 0xED, - 0xD4, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, - 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, - 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0x07, 0xA4, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x52, 0xED, 0x64, 0xED, - 0xD4, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x42, 0xED, 0x64, 0xED, - 0xE4, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x08, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0xCF, - 0x00, 0x01, 0x00, 0x00, 0x1F, 0x01, 0x01, 0x00, - 0xEB, 0xC4, 0xA9, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x24, 0x71, 0x12, 0x00, 0x40, 0x00, 0x00, 0x00, - 0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x6C, 0x71, 0x12, 0x00, 0x0C, 0xCF, 0xA9, 0x00, - 0x24, 0x71, 0x12, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x1C, 0xCF, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, - 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, - 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, - 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, - 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x21, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x36, 0xED, 0x64, 0xED, - 0xB0, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0xF2, 0x12, 0x00, 0xBD, 0xCC, 0xA9, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x52, 0xED, 0x64, 0xED, 0xFC, 0xF1, 0x12, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x06, 0xF2, 0x12, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, - 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, - 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, - 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, - 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, - }, - .response_len = 0x40 - }, - { - .cmd = { - 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x36, 0xED, 0x64, 0xED, - 0xB0, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0xF2, 0x12, 0x00, 0xBD, 0xCC, 0xA9, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x52, 0xED, 0x64, 0xED, 0xFC, 0xF1, 0x12, 0x00, - 0x0A, 0x00, 0x00, 0x00, 0x06, 0xF2, 0x12, 0x00, - }, - .response_len = 0x00 - }, - { - .cmd = { - 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, - 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, - 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, - }, - .response_len = 0x40 - }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xF3, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb8, 0x00, 0x00, 0x00, 0x98, 0xf1, 0x12, 0x00, + 0x03, 0xd4, 0xa9, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x14, 0x20, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x84, 0xf1, 0x12, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x90, 0xf1, 0x12, 0x00, + 0xac, 0x0d, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xf7, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x90, 0xf1, 0x12, 0x00, + 0x92, 0xc5, 0xa9, 0x00, 0x48, 0xf1, 0x12, 0x00, + 0x40, 0x00, 0x00, 0x00, 0xa2, 0xc5, 0xa9, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb8, 0x00, 0x00, 0x00, 0x98, 0xf1, 0x12, 0x00, + 0x03, 0xd4, 0xa9, 0x00, 0x64, 0x00, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0xf7, 0xcd, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xf8, 0xa9, 0x00, + 0x28, 0xf1, 0x12, 0x00, 0x40, 0x00, 0x00, 0x00, + 0xbb, 0xc4, 0xa9, 0x00, 0x02, 0xfa, 0x3f, 0x05, + 0x05, 0x02, 0x05, 0x23, 0x27, 0xe5, 0x13, 0x10, + 0x08, 0xff, 0x04, 0x6c, 0xc1, 0x41, 0x1c, 0x4c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0xf1, 0x12, 0x00, 0x89, 0xae, 0xa9, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8b, 0x00, 0x00, 0x00, 0x3a, 0x8c, 0xf1, 0x12, + 0x00, 0x64, 0xa8, 0xa7, 0x00, 0x84, 0xf1, 0x12, + 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf1, 0x12, + 0x00, 0x51, 0xa6, 0xa7, 0x00, 0xf8, 0x00, 0x00, + 0x00, 0x7e, 0xa6, 0xa7, 0x00, 0x24, 0x5a, 0xac, + 0x00, 0x01, 0xf1, 0x12, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x2f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, + 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x7c, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, + 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0x0d, 0xff, 0x00, + 0x34, 0xf1, 0x12, 0x00, 0x40, 0x00, 0x00, 0x00, + 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf1, 0x12, 0x00, 0x57, 0xcc, 0xa9, 0x00, + 0x34, 0xf1, 0x12, 0x00, 0x40, 0x00, 0x00, 0x00, + 0xbd, 0xcc, 0xa9, 0x00, 0x3a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, + 0x34, 0xf1, 0x12, 0x00, 0x3a, 0x00, 0x00, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x0a, 0x37, 0x6a, 0x3d, + 0x73, 0x3d, 0x71, 0x0e, 0x01, 0x0e, 0x81, 0x00, + 0x40, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x12, 0x00, + 0x57, 0xcc, 0xa9, 0x00, 0x34, 0xf1, 0x12, 0x00, + 0x40, 0x00, 0x00, 0x00, 0xbd, 0xcc, 0xa9, 0x00, + 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb8, 0x00, 0x00, 0x00, 0x34, 0xf1, 0x12, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, + 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0x3d, 0x51, 0x0e, + 0x01, 0x0e, 0x81, 0x00, 0x40, 0x00, 0x00, 0x00, + 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf1, 0x12, 0x00, 0x57, 0xcc, 0xa9, 0x00, + 0x34, 0xf1, 0x12, 0x00, 0x40, 0x00, 0x00, 0x00, + 0xbd, 0xcc, 0xa9, 0x00, 0x3a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, + 0x34, 0xf1, 0x12, 0x00, 0x3a, 0x00, 0x00, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, + 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x04, 0x78, 0x3A, 0x34, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0x00, 0x24, 0x1A, 0x80, + 0x7C, 0x04, 0xF1, 0x12, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x00, 0x00, 0xCC, 0xEF, 0x12, + 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xB0, 0xEF, 0x12, 0x00, 0x0C, 0x00, 0x0C, + 0x00, 0x84, 0x21, 0x15, 0x00, 0x48, 0x00, 0x00, + 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x04, 0xB2, 0x3A, 0x0B, 0x88, 0x01, + 0xB4, 0x01, 0x20, 0x91, 0x04, 0x07, 0x02, 0x24, + 0x20, 0xE2, 0x15, 0x0D, 0x10, 0x0F, 0x10, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x12, 0x13, 0x13, 0x13, + 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, + 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, + 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x04, 0xEC, 0x3A, 0x0B, 0x1C, 0x1C, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, + 0x1E, 0x1D, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1F, 0x1F, 0x20, + 0x20, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x20, 0x21, + 0x20, 0x21, 0x20, 0x20, 0x20, 0x21, 0x20, 0x21, + 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x21, + 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x22, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x05, 0x26, 0x3A, 0x0B, 0x22, 0x22, + 0x22, 0x21, 0x22, 0x22, 0x22, 0x21, 0x22, 0x22, + 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x21, 0x21, + 0x22, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x21, + 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x20, 0x20, 0x21, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x1F, 0x1F, 0x1F, 0x1F, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x05, 0x60, 0x3A, 0x0B, 0x1F, 0x1F, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, + 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, + 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, + 0x1E, 0x1E, 0x1E, 0x1E, 0x1D, 0x1D, 0x1D, 0x1D, + 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1C, 0x1D, 0x1D, + 0x1D, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1B, 0x1B, 0x1C, 0x1C, 0x1B, 0x1B, 0x1B, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x05, 0x9A, 0x3A, 0x0B, 0x1B, 0x1B, + 0x1B, 0x1A, 0x1B, 0x1B, 0x1A, 0x1A, 0x1A, 0x1B, + 0x1B, 0x1B, 0x1B, 0x1A, 0x19, 0x1A, 0x1A, 0x1A, + 0x1A, 0x19, 0x1A, 0x1A, 0x1A, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x18, 0x19, 0x18, 0x18, 0x19, + 0x18, 0x17, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x16, 0x17, 0x16, 0x16, 0x15, + 0x15, 0x16, 0x15, 0x16, 0x15, 0x15, 0x14, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x05, 0xD4, 0x2C, 0x0B, 0x14, 0x15, + 0x14, 0x14, 0x14, 0x13, 0x13, 0x13, 0x12, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x6E, 0x12, 0x00, 0x2B, 0xC5, 0xA9, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x7C, 0xEF, 0x12, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x01, 0x68, 0x0A, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xD0, 0xFD, 0x7F, 0xDC, 0x6D, 0x12, 0x00, + 0x2A, 0x26, 0x80, 0x7C, 0x98, 0x6D, 0x12, 0x00, + 0x00, 0x26, 0x80, 0x7C, 0xB8, 0x00, 0x00, 0x00, + 0x0C, 0x80, 0x01, 0x10, 0x90, 0x3E, 0x94, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x03, 0xB4, 0x3A, 0x1F, 0x1F, 0x1F, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, + 0x1E, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, + 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, + 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1D, 0x1D, 0x1D, + 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1C, 0x1D, + 0x1D, 0x1D, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x03, 0xEE, 0x06, 0x0B, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x85, 0xB7, 0xA9, 0x00, + 0xB8, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00, + 0x18, 0x70, 0x12, 0x00, 0x2B, 0xC5, 0xA9, 0x00, + 0x64, 0x00, 0x00, 0x00, 0xD4, 0xF0, 0x12, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x07, 0x00, 0x20, 0x00, 0x3a, 0x32, 0x2b, 0x07, + 0x2e, 0x29, 0x07, 0x2b, 0x27, 0x07, 0x27, 0x25, + 0x07, 0x23, 0x23, 0x07, 0x20, 0x21, 0x07, 0x1c, + 0x1d, 0x07, 0x19, 0x1a, 0x07, 0x15, 0x17, 0x07, + 0x12, 0x15, 0x07, 0x0e, 0x14, 0x07, 0x12, 0x17, + 0x07, 0x15, 0x19, 0x07, 0x19, 0x1c, 0x07, 0x1c, + 0x1f, 0x07, 0x20, 0x23, 0x07, 0x23, 0x25, 0x07, + 0x27, 0x27, 0x07, 0x2b, 0x29, 0x07, 0x2e, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x07, 0x00, 0x20, 0x3a, 0x26, 0x2b, 0x07, 0x32, + 0x2d, 0x07, 0x32, 0x2f, 0x07, 0x2e, 0x2d, 0x07, + 0x2b, 0x2b, 0x07, 0x27, 0x29, 0x07, 0x23, 0x27, + 0x07, 0x20, 0x25, 0x07, 0x1c, 0x22, 0x07, 0x19, + 0x1e, 0x07, 0x15, 0x1b, 0x07, 0x12, 0x19, 0x07, + 0x0e, 0x16, 0x07, 0x07, 0x19, 0x1c, 0x07, 0x1c, + 0x1f, 0x07, 0x20, 0x23, 0x07, 0x23, 0x25, 0x07, + 0x27, 0x27, 0x07, 0x2b, 0x29, 0x07, 0x2e, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x06, 0x0e, 0x81, 0x0e, + 0x81, 0x09, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x07, 0x00, 0x20, 0x3a, + 0x26, 0x2b, 0x07, 0x32, 0x2d, 0x07, 0x32, 0x2f, + 0x07, 0x2e, 0x2d, 0x07, 0x2b, 0x2b, 0x07, 0x27, + 0x29, 0x07, 0x23, 0x27, 0x07, 0x20, 0x25, 0x07, + 0x1c, 0x22, 0x07, 0x19, 0x1e, 0x07, 0x15, 0x1b, + 0x07, 0x12, 0x19, 0x07, 0x0e, 0x16, 0x07, 0x07, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, + 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3d, 0x3f, 0xff, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0x0e, 0x85, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x20, 0x3a, 0x26, 0x2b, 0x07, 0x32, + 0x2d, 0x07, 0x32, 0x2f, 0x07, 0x2e, 0x2d, 0x07, + 0x2b, 0x2b, 0x07, 0x29, 0x07, 0x23, 0x27, 0x07, + 0x20, 0x25, 0x07, 0x1c, 0x22, 0x07, 0x19, 0x1e, + 0x07, 0x15, 0x1b, 0x07, 0x12, 0x19, 0x07, 0x1f, + 0x0e, 0x16, 0x07, 0x07, 0x19, 0x1c, 0x07, 0x1c, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0x0d, 0x62, 0x62, + 0x51, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x3a, 0x41, 0x0e, 0x2b, 0x00, 0x00, 0x00, 0x00, + 0x78, 0xf1, 0x12, 0x00, 0x1a, 0xaa, 0xa7, 0x1f, + 0x00, 0x3a, 0x09, 0x00, 0x00, 0x00, 0x12, 0x41, + 0x0e, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x4c, 0xf1, 0x12, 0x00, 0x89, 0xae, + 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0x20, 0x6C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x20, 0x3A, 0x26, 0x2B, 0x07, 0x32, + 0x2D, 0x07, 0x32, 0x2F, 0x07, 0x2E, 0x2D, 0x07, + 0x2B, 0x2B, 0x07, 0x27, 0x29, 0x07, 0x23, 0x27, + 0x07, 0x20, 0x25, 0x07, 0x1C, 0x22, 0x07, 0x19, + 0x1E, 0x07, 0x15, 0x1B, 0x07, 0x12, 0x19, 0x07, + 0x0E, 0x16, 0x07, 0x07, 0x19, 0x1C, 0x07, 0x1C, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xF9, 0x6C, 0x6C, + 0x6C, 0x6C, 0x40, 0x40, 0x2E, 0x6D, 0x64, 0xED, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4C, 0xF1, 0x12, 0x00, 0x89, 0xAE, 0xA9, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE8, 0x3D, 0xAC, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x68, 0xF1, 0x12, 0x00, + 0x14, 0xAB, 0xA7, 0x00, 0x03, 0x00, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0xF9, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x07, 0x00, 0x20, 0x3A, + 0x26, 0x2B, 0x07, 0x32, 0x2D, 0x07, 0x32, 0x2F, + 0x07, 0x2E, 0x2D, 0x07, 0x2B, 0x2B, 0x07, 0x27, + 0x29, 0x07, 0x23, 0x27, 0x07, 0x20, 0x25, 0x07, + 0x1C, 0x22, 0x07, 0x19, 0x1E, 0x07, 0x15, 0x1B, + 0x07, 0x12, 0x19, 0x07, 0x0E, 0x16, 0x07, 0x07, + 0x19, 0x1C, 0x07, 0x1C, 0xBA, 0xEC, 0x64, 0xED, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x16, 0x1C, 0x13, 0x1B, + 0x0B, 0x1A, 0x0A, 0x30, 0x08, 0x09, 0x6D, 0x08, + 0xA7, 0x00, 0x9E, 0x00, 0x1E, 0x0C, 0x08, 0x1D, + 0x04, 0x23, 0x42, 0x2F, 0x07, 0x2E, 0x2D, 0x07, + 0x2B, 0x2B, 0x07, 0x27, 0x29, 0x07, 0x23, 0x27, + 0x07, 0x20, 0x25, 0x07, 0x1C, 0x22, 0x07, 0x19, + 0x1E, 0x07, 0x15, 0x1B, 0x07, 0x12, 0x19, 0x07, + 0x0E, 0x16, 0x07, 0x07, 0x19, 0x1C, 0x07, 0x1C, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, + 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0x0D, 0xFF, 0x30, + 0x08, 0x09, 0x6D, 0x08, 0xA7, 0x00, 0x9E, 0x00, + 0x1E, 0x0C, 0x08, 0x1D, 0x04, 0x23, 0x42, 0x2F, + 0x07, 0x2E, 0x2D, 0x07, 0x2B, 0x2B, 0x07, 0x27, + 0x29, 0x07, 0x23, 0x27, 0x07, 0x20, 0x25, 0x07, + 0x1C, 0x22, 0x07, 0x19, 0x1E, 0x07, 0x15, 0x1B, + 0x07, 0x12, 0x19, 0x07, 0x0E, 0x16, 0x07, 0x07, + 0x19, 0x1C, 0x07, 0x1C, 0xBA, 0xEC, 0x64, 0xED, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xF7, 0x64, 0xED, + 0x00, 0x00, 0x00, 0x00, 0x7C, 0xF1, 0x12, 0x00, + 0x1A, 0xAA, 0xA7, 0x00, 0x3A, 0x00, 0x00, 0x00, + 0x2A, 0x6D, 0x64, 0xED, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x50, 0xF1, 0x12, 0x00, + 0x89, 0xAE, 0xA9, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xE8, 0x3D, 0xAC, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xF7, 0xA9, 0x00, + 0x02, 0xFA, 0x3F, 0x05, 0x05, 0xC2, 0x85, 0xA6, + 0xA7, 0x6D, 0x10, 0x10, 0x08, 0xFF, 0x85, 0x6C, + 0x00, 0x00, 0xCF, 0x00, 0x01, 0x00, 0x00, 0x1F, + 0x01, 0x01, 0x0A, 0x0B, 0x13, 0x04, 0x6C, 0x6C, + 0x6C, 0x6C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x6C, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x42, 0x42, 0x42, 0x42, 0x42, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0xF7, 0xF3, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x0D, 0xFF, 0x30, + 0x08, 0x09, 0x6D, 0x08, 0xA7, 0x00, 0x9E, 0x00, + 0x1E, 0x0C, 0x08, 0x1D, 0x04, 0x23, 0x42, 0x2F, + 0x07, 0x2E, 0x2D, 0x07, 0x2B, 0x2B, 0x07, 0x27, + 0x29, 0x07, 0x23, 0x27, 0x07, 0x20, 0x25, 0x07, + 0x1C, 0x22, 0x07, 0x19, 0x1E, 0x07, 0x15, 0x1B, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xE8, 0x3D, 0xAC, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5C, 0xF1, 0x12, 0x00, 0x14, 0xAB, 0xA7, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x5C, 0xF1, 0x12, 0x00, + 0x20, 0xAB, 0xA7, 0x00, 0x58, 0xF1, 0x12, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x99, 0xA9, 0xA7, 0x00, + 0xE8, 0x3D, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x8F, 0x2F, + 0x07, 0x2E, 0x2D, 0x07, 0x2B, 0x2B, 0x07, 0x27, + 0x29, 0x07, 0x23, 0x27, 0x07, 0x20, 0x25, 0x07, + 0x1C, 0x22, 0x07, 0x19, 0x1E, 0x07, 0x15, 0x1B, + 0x07, 0x12, 0x19, 0x07, 0x82, 0xEC, 0x64, 0xED, + 0x24, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x3D, 0xAC, 0x00, 0xBD, 0xCC, 0xA9, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x08, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0xCF, + 0x00, 0x01, 0x00, 0x00, 0x1F, 0x01, 0x01, 0x00, + 0x0C, 0xCF, 0xA9, 0x00, 0x74, 0x70, 0x12, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x1C, 0xCF, 0xA9, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x8F, 0x2F, + 0x07, 0x2E, 0x2D, 0x07, 0x2B, 0x2B, 0x07, 0x27, + 0x29, 0x07, 0x23, 0x27, 0x07, 0x20, 0x25, 0x07, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x06, 0x0E, 0x85, 0x09, + 0xED, 0x09, 0x6D, 0x2F, 0x07, 0x2E, 0x2D, 0x07, + 0x2B, 0x2B, 0x07, 0x27, 0x29, 0x07, 0x23, 0x27, + 0x07, 0x20, 0x25, 0x07, 0x1C, 0x22, 0x07, 0x19, + 0x8A, 0xEC, 0x64, 0xED, 0x1C, 0xF1, 0x12, 0x00, + 0xFA, 0xCB, 0xA9, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x72, 0xF1, 0x12, 0x00, + 0xBD, 0xCC, 0xA9, 0x00, 0x0A, 0x00, 0x00, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, + 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0x09, 0xED, 0x2F, + 0x07, 0x2E, 0x2D, 0x07, 0x2B, 0x2B, 0x07, 0x27, + 0x29, 0x07, 0x23, 0x27, 0x07, 0x20, 0x25, 0x07, + 0x1C, 0x22, 0x07, 0x19, 0x8A, 0xEC, 0x64, 0xED, + 0x1C, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x72, 0xF1, 0x12, 0x00, 0xBD, 0xCC, 0xA9, 0x00, + 0x0A, 0x00, 0x00, 0x00, 0xBD, 0xCC, 0xA9, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xF3, 0x00, 0x00, + 0x8C, 0xF1, 0x12, 0x00, 0x1A, 0xAA, 0xA7, 0x00, + 0x3A, 0x00, 0x00, 0x00, 0x5A, 0x6D, 0x64, 0xED, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0xF1, 0x12, 0x00, 0x89, 0xAE, 0xA9, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE8, 0x3D, 0xAC, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7C, 0xF1, 0x12, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x84, 0x00, 0x00, 0x00, 0x32, 0x02, 0xE0, 0xAD, + 0x00, 0xFC, 0xDF, 0xAD, 0x00, 0xDB, 0xDF, 0xAD, + 0x00, 0xBA, 0xDF, 0xAD, 0x00, 0x99, 0xDF, 0x6F, + 0x44, 0xC2, 0xE8, 0x20, 0x65, 0x73, 0x83, 0xAC, + 0xD7, 0x88, 0x6D, 0x59, 0x61, 0xE0, 0x3B, 0x3D, + 0xB7, 0xF4, 0xDE, 0xAD, 0x00, 0xD3, 0xDE, 0xAD, + 0x00, 0xB2, 0xDE, 0xAD, 0x00, 0x91, 0xDE, 0x00, + 0xA6, 0xEC, 0x64, 0xED, 0xA2, 0xEC, 0x64, 0xED, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x06, 0x1A, 0x0A, 0x1B, + 0x0B, 0x1C, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x92, 0xD5, 0x90, 0x7C, 0xBB, 0x9B, 0x80, 0x7C, + 0xB8, 0x00, 0x00, 0x00, 0xAC, 0x70, 0x12, 0x00, + 0x85, 0xB7, 0xA9, 0x00, 0xB8, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x08, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0xCF, + 0x00, 0x01, 0x00, 0x00, 0x1F, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00, + 0x4C, 0x70, 0x12, 0x00, 0xEB, 0xC4, 0xA9, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x68, 0x70, 0x12, 0x00, + 0x40, 0x00, 0x00, 0x00, 0xE8, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xB0, 0x70, 0x12, 0x00, + 0x0C, 0xCF, 0xA9, 0x00, 0x68, 0x70, 0x12, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0x0D, 0x00, 0x00, + 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1F, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, + 0xD0, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xA6, 0xB5, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x94, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x28, 0x6F, 0x44, 0xC2, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x04, 0x78, 0x3A, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xD0, 0xFD, 0x7F, 0x94, 0xF0, 0x12, + 0x00, 0x2A, 0x26, 0x80, 0x7C, 0x50, 0xF0, 0x12, + 0x00, 0x00, 0x26, 0x80, 0x7C, 0x08, 0x00, 0x00, + 0x00, 0x0C, 0x80, 0x01, 0x10, 0x90, 0x3E, 0x94, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x80, 0x69, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x04, 0xB2, 0x3A, 0x0B, 0x88, 0x01, + 0xB4, 0x01, 0x20, 0x91, 0x04, 0x07, 0x02, 0x24, + 0x20, 0xE2, 0x15, 0x0D, 0x10, 0x0F, 0x10, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x12, 0x13, 0x13, 0x13, + 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, + 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, + 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x04, 0xEC, 0x3A, 0x0B, 0x1C, 0x1C, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, + 0x1E, 0x1D, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1F, 0x1F, 0x20, + 0x20, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x20, 0x21, + 0x20, 0x21, 0x20, 0x20, 0x20, 0x21, 0x20, 0x21, + 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x21, + 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x22, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x05, 0x26, 0x3A, 0x0B, 0x22, 0x22, + 0x22, 0x21, 0x22, 0x22, 0x22, 0x21, 0x22, 0x22, + 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x21, 0x21, + 0x22, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x21, + 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x20, 0x20, 0x21, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x1F, 0x1F, 0x1F, 0x1F, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x05, 0x60, 0x3A, 0x0B, 0x1F, 0x1F, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, + 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, + 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, + 0x1E, 0x1E, 0x1E, 0x1E, 0x1D, 0x1D, 0x1D, 0x1D, + 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1C, 0x1D, 0x1D, + 0x1D, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1B, 0x1B, 0x1C, 0x1C, 0x1B, 0x1B, 0x1B, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x05, 0x9A, 0x3A, 0x0B, 0x1B, 0x1B, + 0x1B, 0x1A, 0x1B, 0x1B, 0x1A, 0x1A, 0x1A, 0x1B, + 0x1B, 0x1B, 0x1B, 0x1A, 0x19, 0x1A, 0x1A, 0x1A, + 0x1A, 0x19, 0x1A, 0x1A, 0x1A, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x18, 0x19, 0x18, 0x18, 0x19, + 0x18, 0x17, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x16, 0x17, 0x16, 0x16, 0x15, + 0x15, 0x16, 0x15, 0x16, 0x15, 0x15, 0x14, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x05, 0xD4, 0x2C, 0x0B, 0x14, 0x15, + 0x14, 0x14, 0x14, 0x13, 0x13, 0x13, 0x12, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x6F, 0x12, 0x00, 0x2B, 0xC5, 0xA9, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x2C, 0xF0, 0x12, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xF7, 0x1C, 0x1C, + 0x1B, 0x1B, 0x1C, 0x1C, 0x1B, 0x1B, 0x1B, 0x1B, + 0x1B, 0x1B, 0x1B, 0x1A, 0x1B, 0x1B, 0x1A, 0x1A, + 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, 0x1A, 0x19, 0x1A, + 0x1A, 0x1A, 0x1A, 0x19, 0x1A, 0x1A, 0x1A, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x19, 0x18, + 0x18, 0x19, 0x18, 0x17, 0x18, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x16, 0x17, 0x16, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0xF7, 0xF3, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x04, 0x3D, 0x40, 0x0A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x52, 0xED, 0x64, 0xED, + 0xD4, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, + 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0x0A, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x52, 0xED, 0x64, 0xED, 0xD4, 0xF1, 0x12, 0x00, + 0xFA, 0xCB, 0xA9, 0x00, 0x03, 0x00, 0x00, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x8B, 0x00, 0x00, 0xA8, 0x3A, 0x00, 0x00, 0x00, + 0x00, 0xDC, 0x00, 0xEA, 0x00, 0x20, 0xED, 0x12, + 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x00, 0xDC, 0xFD, + 0x7F, 0x20, 0xED, 0x12, 0x00, 0x05, 0x00, 0x00, + 0x00, 0xA0, 0x20, 0x15, 0x00, 0xC8, 0x00, 0x00, + 0x01, 0x43, 0x00, 0x3A, 0x00, 0x5C, 0x00, 0x44, + 0x00, 0x6F, 0x00, 0x63, 0x00, 0x75, 0x00, 0x6D, + 0x00, 0x65, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x00, 0xE2, 0x3A, 0x0B, 0x07, 0xA5, + 0x03, 0x2F, 0x63, 0x97, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x01, 0x1C, 0x3A, 0x0B, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x12, 0x75, 0xB3, 0x05, + 0xE2, 0xBC, 0x74, 0x68, 0xAD, 0xAC, 0x7B, 0xB1, + 0xF8, 0x52, 0xD5, 0x8F, 0xF7, 0x03, 0x00, 0x00, + 0x06, 0xA5, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x01, 0x56, 0x3A, 0x0B, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x01, 0x90, 0x3A, 0x0B, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0xA5, 0x00, 0x22, 0x8E, 0xA3, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4C, 0xA5, 0xC8, 0xC8, 0x41, 0x50, 0x52, 0x39, + 0x07, 0x01, 0x00, 0x5F, 0x00, 0x00, 0xFF, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x01, 0xCA, 0x3A, 0x0B, 0x01, 0x48, + 0x34, 0x33, 0x00, 0x00, 0x00, 0x00, 0x76, 0x3E, + 0x84, 0x10, 0x2E, 0x48, 0x54, 0x0D, 0x98, 0x4C, + 0x14, 0x12, 0x72, 0x7A, 0x88, 0x0F, 0x9F, 0x84, + 0x98, 0x03, 0x52, 0xA6, 0xA4, 0x0A, 0x6E, 0xA8, + 0x54, 0x0C, 0x13, 0xB6, 0xE8, 0x0A, 0x77, 0xC0, + 0x94, 0x04, 0x73, 0xC6, 0x14, 0x07, 0x80, 0xCA, + 0xA8, 0x08, 0x31, 0xD2, 0x44, 0x09, 0x1E, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x02, 0x04, 0x3A, 0x0B, 0x74, 0x09, + 0x7A, 0xE4, 0x78, 0x17, 0xA5, 0xE4, 0x24, 0x09, + 0x45, 0xE8, 0x68, 0x07, 0xBA, 0xEC, 0xE8, 0x05, + 0xC2, 0xF0, 0x58, 0x16, 0x78, 0xF6, 0x98, 0x15, + 0x7C, 0xFC, 0xB8, 0x19, 0xAD, 0xFC, 0x74, 0x09, + 0x8C, 0x02, 0x39, 0x0D, 0x36, 0x06, 0x99, 0x06, + 0x9B, 0x08, 0x09, 0x0B, 0xA1, 0x0C, 0x25, 0x19, + 0x57, 0x10, 0x29, 0x05, 0x1A, 0x1C, 0x45, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x02, 0x3E, 0x3A, 0x0B, 0x55, 0x1E, + 0x69, 0x16, 0xA4, 0x24, 0xB9, 0x09, 0x1C, 0x44, + 0x55, 0x08, 0x9C, 0x44, 0xC9, 0x0B, 0x9F, 0x4A, + 0xF9, 0x19, 0x4C, 0x4C, 0xF9, 0x13, 0x5E, 0x50, + 0x09, 0x13, 0xB7, 0x6A, 0x09, 0x0A, 0x7C, 0x7A, + 0x75, 0x0F, 0x0E, 0x7E, 0x95, 0x00, 0x81, 0xA6, + 0x99, 0x0E, 0xC0, 0xAE, 0xE5, 0x19, 0xA0, 0xCC, + 0x35, 0x0D, 0x63, 0xE2, 0x85, 0x1F, 0x8E, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x02, 0x78, 0x3A, 0x0B, 0x35, 0x1D, + 0xC1, 0xE8, 0xA9, 0x0C, 0x7A, 0x06, 0xCA, 0x0E, + 0xAD, 0x12, 0xD6, 0x1C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x02, 0xB2, 0x2A, 0x0B, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x6C, 0x12, 0x00, 0x2B, 0xC5, 0xA9, 0x00, + 0x64, 0x00, 0x00, 0x00, 0xFC, 0xEC, 0x12, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xF1, 0x42, 0x42, + 0x40, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0xCE, 0x6D, 0x64, 0xED, 0x00, 0x00, 0x00, 0x00, + 0x30, 0xF2, 0x12, 0x00, 0x1A, 0xAA, 0xA7, 0x00, + 0x3A, 0x00, 0x00, 0x00, 0xF6, 0x6D, 0x64, 0xED, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0xF2, 0x12, 0x00, 0x89, 0xAE, 0xA9, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0xF1, 0x01, 0x00, + 0x1C, 0xCF, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x02, 0x0A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x8B, 0x00, 0x00, 0xFC, 0x3A, 0x1E, 0xDC, 0x74, + 0x09, 0x7A, 0xE4, 0x78, 0x17, 0xA5, 0xE4, 0x24, + 0x09, 0x45, 0xE8, 0x68, 0x07, 0xBA, 0xEC, 0xE8, + 0x05, 0xC2, 0xF0, 0x58, 0x16, 0x78, 0xF6, 0x98, + 0x15, 0x7C, 0xFC, 0xB8, 0x19, 0xAD, 0xFC, 0x74, + 0x09, 0x8C, 0x02, 0x39, 0x0D, 0x36, 0x06, 0x99, + 0x06, 0x9B, 0x08, 0x09, 0x0B, 0xA1, 0x0C, 0x25, + 0x19, 0x57, 0x10, 0x29, 0x05, 0x1A, 0x1C, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x8B, 0x00, 0x01, 0x36, 0x2E, 0x0B, 0x06, 0xA5, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2B, 0xC5, 0xA9, 0x00, + 0x64, 0x00, 0x00, 0x00, 0xD8, 0xEE, 0x12, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xF0, 0xAC, 0x00, + 0xF0, 0xF1, 0x12, 0x00, 0x6A, 0xB1, 0xA7, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x06, 0xA5, 0x00, 0x01, + 0x00, 0x00, 0x12, 0x00, 0x14, 0xAB, 0xA7, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x0C, 0xF2, 0x12, 0x00, + 0x20, 0xAB, 0xA7, 0x00, 0x08, 0xF2, 0x12, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x99, 0xA9, 0xA7, 0x00, + 0xE8, 0x3D, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x8F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x52, 0xED, 0x64, 0xED, + 0xD4, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x3D, 0xAC, 0x00, 0xBD, 0xCC, 0xA9, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xF7, 0x12, 0x00, + 0x88, 0xC4, 0xA9, 0x00, 0xD8, 0xF1, 0x12, 0x00, + 0x40, 0x00, 0x00, 0x00, 0xBB, 0xC4, 0xA9, 0x00, + 0x02, 0x00, 0x3F, 0x05, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x6D, 0x64, 0xED, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xF2, 0x12, 0x00, + 0x89, 0xAE, 0xA9, 0x00, 0x03, 0x00, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xF7, 0xA9, 0x00, + 0x02, 0xFA, 0x3F, 0x05, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0xF7, 0xF3, 0x00, + 0x0C, 0xCF, 0xA9, 0x00, 0x24, 0x71, 0x12, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x1C, 0xCF, 0xA9, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x8F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x01, 0xFB, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF1, 0x12, 0x00, + 0x89, 0xAE, 0xA9, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xE8, 0x3D, 0xAC, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0xF2, 0x12, 0x00, 0x14, 0xAB, 0xA7, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x0C, 0xF2, 0x12, 0x00, + 0x20, 0xAB, 0xA7, 0x00, 0x08, 0xF2, 0x12, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0xFB, 0x0F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x8F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x52, 0xED, 0x64, 0xED, + 0xD4, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, + 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0x07, 0xA4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x52, 0xED, 0x64, 0xED, + 0xD4, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x42, 0xED, 0x64, 0xED, + 0xE4, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x08, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0xCF, + 0x00, 0x01, 0x00, 0x00, 0x1F, 0x01, 0x01, 0x00, + 0xEB, 0xC4, 0xA9, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x24, 0x71, 0x12, 0x00, 0x40, 0x00, 0x00, 0x00, + 0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6C, 0x71, 0x12, 0x00, 0x0C, 0xCF, 0xA9, 0x00, + 0x24, 0x71, 0x12, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x1C, 0xCF, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, + 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, + 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x21, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x36, 0xED, 0x64, 0xED, + 0xB0, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0xF2, 0x12, 0x00, 0xBD, 0xCC, 0xA9, 0x00, + 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x52, 0xED, 0x64, 0xED, 0xFC, 0xF1, 0x12, 0x00, + 0x0A, 0x00, 0x00, 0x00, 0x06, 0xF2, 0x12, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, + 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, + 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, + }, + .response_len = 0x40 + }, + { + .cmd = { + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x36, 0xED, 0x64, 0xED, + 0xB0, 0xF1, 0x12, 0x00, 0xFA, 0xCB, 0xA9, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0xF2, 0x12, 0x00, 0xBD, 0xCC, 0xA9, 0x00, + 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x52, 0xED, 0x64, 0xED, 0xFC, 0xF1, 0x12, 0x00, + 0x0A, 0x00, 0x00, 0x00, 0x06, 0xF2, 0x12, 0x00, + }, + .response_len = 0x00 + }, + { + .cmd = { + 0x82, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x01, 0x02, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, + 0x1C, 0x1D, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, + 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3A, 0x3D, 0x3F, 0xFF, 0x00, + }, + .response_len = 0x40 + }, }; static const unsigned char scan_cmd[0x40] = { - 0x0e, 0x00, 0x03, 0xa8, 0x00, 0xb6, 0xbb, 0xbb, - 0xb8, 0xb7, 0xb8, 0xb5, 0xb8, 0xb9, 0xb8, 0xb9, - 0xbb, 0xbb, 0xbe, 0xbb, 0x4e, 0x16, 0xf4, 0x77, - 0xa8, 0x07, 0x32, 0x00, 0x6a, 0x16, 0xf4, 0x77, - 0x78, 0x24, 0x61, 0x00, 0xc8, 0x00, 0xec, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x3c, 0xf3, 0x2f, 0x01, - 0x05, 0x90, 0xf6, 0x77, 0x84, 0xf5, 0x2f, 0x01, - 0x05, 0x90, 0xf6, 0x00, 0xc8, 0x00, 0xec, 0x00 + 0x0e, 0x00, 0x03, 0xa8, 0x00, 0xb6, 0xbb, 0xbb, + 0xb8, 0xb7, 0xb8, 0xb5, 0xb8, 0xb9, 0xb8, 0xb9, + 0xbb, 0xbb, 0xbe, 0xbb, 0x4e, 0x16, 0xf4, 0x77, + 0xa8, 0x07, 0x32, 0x00, 0x6a, 0x16, 0xf4, 0x77, + 0x78, 0x24, 0x61, 0x00, 0xc8, 0x00, 0xec, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x3c, 0xf3, 0x2f, 0x01, + 0x05, 0x90, 0xf6, 0x77, 0x84, 0xf5, 0x2f, 0x01, + 0x05, 0x90, 0xf6, 0x00, 0xc8, 0x00, 0xec, 0x00 }; #endif diff --git a/libfprint/drivers/upektc_img.c b/libfprint/drivers/upektc_img.c index 33f76848..d3cc636a 100644 --- a/libfprint/drivers/upektc_img.c +++ b/libfprint/drivers/upektc_img.c @@ -23,626 +23,687 @@ #include "upek_proto.h" #include "upektc_img.h" -static void start_capture(FpImageDevice *dev); -static void start_deactivation(FpImageDevice *dev); +static void start_capture (FpImageDevice *dev); +static void start_deactivation (FpImageDevice *dev); -#define EP_IN (1 | FPI_USB_ENDPOINT_IN) -#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) -#define CTRL_TIMEOUT 4000 -#define BULK_TIMEOUT 4000 +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT) +#define CTRL_TIMEOUT 4000 +#define BULK_TIMEOUT 4000 -#define IMAGE_WIDTH 144 -#define IMAGE_HEIGHT 384 -#define IMAGE_SIZE (IMAGE_WIDTH * IMAGE_HEIGHT) +#define IMAGE_WIDTH 144 +#define IMAGE_HEIGHT 384 +#define IMAGE_SIZE (IMAGE_WIDTH * IMAGE_HEIGHT) -#define MAX_CMD_SIZE 64 -#define MAX_RESPONSE_SIZE 2052 -#define SHORT_RESPONSE_SIZE 64 +#define MAX_CMD_SIZE 64 +#define MAX_RESPONSE_SIZE 2052 +#define SHORT_RESPONSE_SIZE 64 -struct _FpiDeviceUpektcImg { - FpImageDevice parent; +struct _FpiDeviceUpektcImg +{ + FpImageDevice parent; - unsigned char cmd[MAX_CMD_SIZE]; - unsigned char response[MAX_RESPONSE_SIZE]; - unsigned char *image_bits; - unsigned char seq; - size_t image_size; - size_t response_rest; - gboolean deactivating; + unsigned char cmd[MAX_CMD_SIZE]; + unsigned char response[MAX_RESPONSE_SIZE]; + unsigned char *image_bits; + unsigned char seq; + size_t image_size; + size_t response_rest; + gboolean deactivating; }; -G_DECLARE_FINAL_TYPE(FpiDeviceUpektcImg, fpi_device_upektc_img, FPI, - DEVICE_UPEKTC_IMG, FpImageDevice); -G_DEFINE_TYPE(FpiDeviceUpektcImg, fpi_device_upektc_img, FP_TYPE_IMAGE_DEVICE); +G_DECLARE_FINAL_TYPE (FpiDeviceUpektcImg, fpi_device_upektc_img, FPI, + DEVICE_UPEKTC_IMG, FpImageDevice); +G_DEFINE_TYPE (FpiDeviceUpektcImg, fpi_device_upektc_img, FP_TYPE_IMAGE_DEVICE); /****** HELPERS ******/ -static void upektc_img_cmd_fix_seq(unsigned char *cmd_buf, unsigned char seq) +static void +upektc_img_cmd_fix_seq (unsigned char *cmd_buf, unsigned char seq) { - uint8_t byte; + uint8_t byte; - byte = cmd_buf[5]; - byte &= 0x0f; - byte |= (seq << 4); - cmd_buf[5] = byte; -} - -static void upektc_img_cmd_update_crc(unsigned char *cmd_buf, size_t size) -{ - /* CRC does not cover Ciao prefix (4 bytes) and CRC location (2 bytes) */ - uint16_t crc = udf_crc(cmd_buf + 4, size - 6); - - cmd_buf[size - 2] = (crc & 0x00ff); - cmd_buf[size - 1] = (crc & 0xff00) >> 8; + byte = cmd_buf[5]; + byte &= 0x0f; + byte |= (seq << 4); + cmd_buf[5] = byte; } static void -upektc_img_submit_req(FpiSsm *ssm, - FpImageDevice *dev, - const unsigned char *buf, - size_t buf_size, - unsigned char seq, - FpiUsbTransferCallback cb) +upektc_img_cmd_update_crc (unsigned char *cmd_buf, size_t size) { - FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); - FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); + /* CRC does not cover Ciao prefix (4 bytes) and CRC location (2 bytes) */ + uint16_t crc = udf_crc (cmd_buf + 4, size - 6); - BUG_ON(buf_size > MAX_CMD_SIZE); - - memcpy(self->cmd, buf, buf_size); - upektc_img_cmd_fix_seq(self->cmd, seq); - upektc_img_cmd_update_crc(self->cmd, buf_size); - - fpi_usb_transfer_fill_bulk_full(transfer, EP_OUT, self->cmd, buf_size, - NULL); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, cb, NULL); - fpi_usb_transfer_unref(transfer); + cmd_buf[size - 2] = (crc & 0x00ff); + cmd_buf[size - 1] = (crc & 0xff00) >> 8; } static void -upektc_img_read_data(FpiSsm *ssm, - FpImageDevice *dev, - size_t buf_size, - size_t buf_offset, - FpiUsbTransferCallback cb) +upektc_img_submit_req (FpiSsm *ssm, + FpImageDevice *dev, + const unsigned char *buf, + size_t buf_size, + unsigned char seq, + FpiUsbTransferCallback cb) { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); - FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); + FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); - BUG_ON(buf_offset + buf_size > MAX_RESPONSE_SIZE); + BUG_ON (buf_size > MAX_CMD_SIZE); - fpi_usb_transfer_fill_bulk_full(transfer, EP_IN, - self->response + buf_offset, buf_size, - NULL); - transfer->ssm = ssm; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, cb, NULL); - fpi_usb_transfer_unref(transfer); + memcpy (self->cmd, buf, buf_size); + upektc_img_cmd_fix_seq (self->cmd, seq); + upektc_img_cmd_update_crc (self->cmd, buf_size); + + fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, self->cmd, buf_size, + NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, cb, NULL); + fpi_usb_transfer_unref (transfer); +} + +static void +upektc_img_read_data (FpiSsm *ssm, + FpImageDevice *dev, + size_t buf_size, + size_t buf_offset, + FpiUsbTransferCallback cb) +{ + FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); + + BUG_ON (buf_offset + buf_size > MAX_RESPONSE_SIZE); + + fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, + self->response + buf_offset, buf_size, + NULL); + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, cb, NULL); + fpi_usb_transfer_unref (transfer); } /****** CAPTURE ******/ enum capture_states { - CAPTURE_INIT_CAPTURE, - CAPTURE_READ_DATA, - CAPTURE_READ_DATA_TERM, - CAPTURE_ACK_00_28, - CAPTURE_ACK_08, - CAPTURE_ACK_FRAME, - CAPTURE_ACK_00_28_TERM, - CAPTURE_NUM_STATES, + CAPTURE_INIT_CAPTURE, + CAPTURE_READ_DATA, + CAPTURE_READ_DATA_TERM, + CAPTURE_ACK_00_28, + CAPTURE_ACK_08, + CAPTURE_ACK_FRAME, + CAPTURE_ACK_00_28_TERM, + CAPTURE_NUM_STATES, }; -static void capture_reqs_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +capture_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - if (error) { - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } - switch (fpi_ssm_get_cur_state(transfer->ssm)) { - case CAPTURE_ACK_00_28_TERM: - fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_READ_DATA_TERM); - break; - default: - fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_READ_DATA); - break; - } + if (error) + { + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } + switch (fpi_ssm_get_cur_state (transfer->ssm)) + { + case CAPTURE_ACK_00_28_TERM: + fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA_TERM); + break; + + default: + fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA); + break; + } } -static int upektc_img_process_image_frame(unsigned char *image_buf, unsigned char *cmd_res) +static int +upektc_img_process_image_frame (unsigned char *image_buf, unsigned char *cmd_res) { - int offset = 8; - int len = ((cmd_res[5] & 0x0f) << 8) | (cmd_res[6]); + int offset = 8; + int len = ((cmd_res[5] & 0x0f) << 8) | (cmd_res[6]); - len -= 1; - if (cmd_res[7] == 0x2c) { - len -= 10; - offset += 10; - } - if (cmd_res[7] == 0x20) { - len -= 4; - } - memcpy(image_buf, cmd_res + offset, len); + len -= 1; + if (cmd_res[7] == 0x2c) + { + len -= 10; + offset += 10; + } + if (cmd_res[7] == 0x20) + len -= 4; + memcpy (image_buf, cmd_res + offset, len); - return len; + return len; } -static void capture_read_data_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE(device); - FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); - unsigned char *data = self->response; - FpImage *img; - size_t response_size; + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); + unsigned char *data = self->response; + FpImage *img; + size_t response_size; - if (error) { - fp_dbg("request is not completed, %s", error->message); - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } + if (error) + { + fp_dbg ("request is not completed, %s", error->message); + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } - if (self->deactivating) { - fp_dbg("Deactivate requested\n"); - fpi_ssm_mark_completed(transfer->ssm); - return; - } + if (self->deactivating) + { + fp_dbg ("Deactivate requested\n"); + fpi_ssm_mark_completed (transfer->ssm); + return; + } - fp_dbg("request completed, len: %.4x", (gint)transfer->actual_length); - if (transfer->actual_length == 0) { - fpi_ssm_jump_to_state(transfer->ssm, - fpi_ssm_get_cur_state(transfer->ssm)); - return; - } + fp_dbg ("request completed, len: %.4x", (gint) transfer->actual_length); + if (transfer->actual_length == 0) + { + fpi_ssm_jump_to_state (transfer->ssm, + fpi_ssm_get_cur_state (transfer->ssm)); + return; + } - if (fpi_ssm_get_cur_state(transfer->ssm) == CAPTURE_READ_DATA_TERM) { - fp_dbg("Terminating SSM\n"); - fpi_ssm_mark_completed(transfer->ssm); - return; - } + if (fpi_ssm_get_cur_state (transfer->ssm) == CAPTURE_READ_DATA_TERM) + { + fp_dbg ("Terminating SSM\n"); + fpi_ssm_mark_completed (transfer->ssm); + return; + } - if (!self->response_rest) { - response_size = ((data[5] & 0x0f) << 8) + data[6]; - response_size += 9; /* 7 bytes for header, 2 for CRC */ - if (response_size > transfer->actual_length) { - fp_dbg("response_size is %lu, actual_length is %d\n", - response_size, (gint)transfer->actual_length); - fp_dbg("Waiting for rest of transfer"); - BUG_ON(self->response_rest); - self->response_rest = response_size - transfer->actual_length; - fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_READ_DATA); - return; - } - } - self->response_rest = 0; + if (!self->response_rest) + { + response_size = ((data[5] & 0x0f) << 8) + data[6]; + response_size += 9; /* 7 bytes for header, 2 for CRC */ + if (response_size > transfer->actual_length) + { + fp_dbg ("response_size is %lu, actual_length is %d\n", + response_size, (gint) transfer->actual_length); + fp_dbg ("Waiting for rest of transfer"); + BUG_ON (self->response_rest); + self->response_rest = response_size - transfer->actual_length; + fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA); + return; + } + } + self->response_rest = 0; - switch (data[4]) { - case 0x00: - switch (data[7]) { - /* No finger */ - case 0x28: - fp_dbg("18th byte is %.2x\n", data[18]); - switch (data[18]) { - case 0x0c: - /* no finger */ - fpi_ssm_jump_to_state(transfer->ssm, - CAPTURE_ACK_00_28); - break; - case 0x00: - /* finger is present! */ - fpi_ssm_jump_to_state(transfer->ssm, - CAPTURE_ACK_00_28); - break; - case 0x1e: - /* short scan */ - fp_err("short scan, aborting\n"); - fpi_image_device_retry_scan(dev, - FP_DEVICE_RETRY_TOO_SHORT); - fpi_image_device_report_finger_status(dev, - FALSE); - fpi_ssm_jump_to_state(transfer->ssm, - CAPTURE_ACK_00_28_TERM); - break; - case 0x1d: - /* too much horisontal movement */ - fp_err("too much horisontal movement, aborting\n"); - fpi_image_device_retry_scan(dev, - FP_DEVICE_RETRY_CENTER_FINGER); - fpi_image_device_report_finger_status(dev, - FALSE); - fpi_ssm_jump_to_state(transfer->ssm, - CAPTURE_ACK_00_28_TERM); - break; - default: - /* some error happened, cancel scan */ - fp_err("something bad happened, stop scan\n"); - fpi_image_device_retry_scan(dev, - FP_DEVICE_RETRY); - fpi_image_device_report_finger_status(dev, - FALSE); - fpi_ssm_jump_to_state(transfer->ssm, - CAPTURE_ACK_00_28_TERM); - break; - } - break; - /* Image frame with additional info */ - case 0x2c: - fpi_image_device_report_finger_status(dev, - TRUE); - /* Plain image frame */ - case 0x24: - self->image_size += - upektc_img_process_image_frame(self->image_bits + self->image_size, - data); - fpi_ssm_jump_to_state(transfer->ssm, - CAPTURE_ACK_FRAME); - break; - /* Last image frame */ - case 0x20: - self->image_size += - upektc_img_process_image_frame(self->image_bits + self->image_size, - data); - BUG_ON(self->image_size != IMAGE_SIZE); - fp_dbg("Image size is %lu\n", - self->image_size); - img = fp_image_new(IMAGE_WIDTH, IMAGE_HEIGHT); - memcpy(img->data, self->image_bits, - IMAGE_SIZE); - fpi_image_device_image_captured(dev, img); - fpi_image_device_report_finger_status(dev, - FALSE); - fpi_ssm_mark_completed(transfer->ssm); - break; - default: - fp_err("Unknown response!\n"); - fpi_ssm_mark_failed(transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); - break; - } - break; - case 0x08: - fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_ACK_08); - break; - default: - fp_err("Not handled response!\n"); - fpi_ssm_mark_failed(transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); - } + switch (data[4]) + { + case 0x00: + switch (data[7]) + { + /* No finger */ + case 0x28: + fp_dbg ("18th byte is %.2x\n", data[18]); + switch (data[18]) + { + case 0x0c: + /* no finger */ + fpi_ssm_jump_to_state (transfer->ssm, + CAPTURE_ACK_00_28); + break; + + case 0x00: + /* finger is present! */ + fpi_ssm_jump_to_state (transfer->ssm, + CAPTURE_ACK_00_28); + break; + + case 0x1e: + /* short scan */ + fp_err ("short scan, aborting\n"); + fpi_image_device_retry_scan (dev, + FP_DEVICE_RETRY_TOO_SHORT); + fpi_image_device_report_finger_status (dev, + FALSE); + fpi_ssm_jump_to_state (transfer->ssm, + CAPTURE_ACK_00_28_TERM); + break; + + case 0x1d: + /* too much horisontal movement */ + fp_err ("too much horisontal movement, aborting\n"); + fpi_image_device_retry_scan (dev, + FP_DEVICE_RETRY_CENTER_FINGER); + fpi_image_device_report_finger_status (dev, + FALSE); + fpi_ssm_jump_to_state (transfer->ssm, + CAPTURE_ACK_00_28_TERM); + break; + + default: + /* some error happened, cancel scan */ + fp_err ("something bad happened, stop scan\n"); + fpi_image_device_retry_scan (dev, + FP_DEVICE_RETRY); + fpi_image_device_report_finger_status (dev, + FALSE); + fpi_ssm_jump_to_state (transfer->ssm, + CAPTURE_ACK_00_28_TERM); + break; + } + break; + + /* Image frame with additional info */ + case 0x2c: + fpi_image_device_report_finger_status (dev, + TRUE); + + /* Plain image frame */ + case 0x24: + self->image_size += + upektc_img_process_image_frame (self->image_bits + self->image_size, + data); + fpi_ssm_jump_to_state (transfer->ssm, + CAPTURE_ACK_FRAME); + break; + + /* Last image frame */ + case 0x20: + self->image_size += + upektc_img_process_image_frame (self->image_bits + self->image_size, + data); + BUG_ON (self->image_size != IMAGE_SIZE); + fp_dbg ("Image size is %lu\n", + self->image_size); + img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT); + memcpy (img->data, self->image_bits, + IMAGE_SIZE); + fpi_image_device_image_captured (dev, img); + fpi_image_device_report_finger_status (dev, + FALSE); + fpi_ssm_mark_completed (transfer->ssm); + break; + + default: + fp_err ("Unknown response!\n"); + fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + break; + } + break; + + case 0x08: + fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_ACK_08); + break; + + default: + fp_err ("Not handled response!\n"); + fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + } } -static void capture_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +capture_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - FpImageDevice *dev = user_data; - FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case CAPTURE_INIT_CAPTURE: - upektc_img_submit_req(ssm, dev, upek2020_init_capture, sizeof(upek2020_init_capture), - self->seq, capture_reqs_cb); - self->seq++; - break; - case CAPTURE_READ_DATA: - case CAPTURE_READ_DATA_TERM: - if (!self->response_rest) - upektc_img_read_data(ssm, dev, SHORT_RESPONSE_SIZE, 0, capture_read_data_cb); - else - upektc_img_read_data(ssm, dev, MAX_RESPONSE_SIZE - SHORT_RESPONSE_SIZE, - SHORT_RESPONSE_SIZE, capture_read_data_cb); - break; - case CAPTURE_ACK_00_28: - case CAPTURE_ACK_00_28_TERM: - upektc_img_submit_req(ssm, dev, upek2020_ack_00_28, sizeof(upek2020_ack_00_28), - self->seq, capture_reqs_cb); - self->seq++; - break; - case CAPTURE_ACK_08: - upektc_img_submit_req(ssm, dev, upek2020_ack_08, sizeof(upek2020_ack_08), - 0, capture_reqs_cb); - break; - case CAPTURE_ACK_FRAME: - upektc_img_submit_req(ssm, dev, upek2020_ack_frame, sizeof(upek2020_ack_frame), - self->seq, capture_reqs_cb); - self->seq++; - break; - }; + switch (fpi_ssm_get_cur_state (ssm)) + { + case CAPTURE_INIT_CAPTURE: + upektc_img_submit_req (ssm, dev, upek2020_init_capture, sizeof (upek2020_init_capture), + self->seq, capture_reqs_cb); + self->seq++; + break; + + case CAPTURE_READ_DATA: + case CAPTURE_READ_DATA_TERM: + if (!self->response_rest) + upektc_img_read_data (ssm, dev, SHORT_RESPONSE_SIZE, 0, capture_read_data_cb); + else + upektc_img_read_data (ssm, dev, MAX_RESPONSE_SIZE - SHORT_RESPONSE_SIZE, + SHORT_RESPONSE_SIZE, capture_read_data_cb); + break; + + case CAPTURE_ACK_00_28: + case CAPTURE_ACK_00_28_TERM: + upektc_img_submit_req (ssm, dev, upek2020_ack_00_28, sizeof (upek2020_ack_00_28), + self->seq, capture_reqs_cb); + self->seq++; + break; + + case CAPTURE_ACK_08: + upektc_img_submit_req (ssm, dev, upek2020_ack_08, sizeof (upek2020_ack_08), + 0, capture_reqs_cb); + break; + + case CAPTURE_ACK_FRAME: + upektc_img_submit_req (ssm, dev, upek2020_ack_frame, sizeof (upek2020_ack_frame), + self->seq, capture_reqs_cb); + self->seq++; + break; + } + ; } -static void capture_sm_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, GError *error_arg) +static void +capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, GError *error_arg) { - FpImageDevice *dev = user_data; - FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(_dev); - g_autoptr(GError) error = error_arg; + FpImageDevice *dev = user_data; + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev); - fpi_ssm_free(ssm); + g_autoptr(GError) error = error_arg; - /* Note: We assume that the error is a cancellation in the deactivation case */ - if (self->deactivating) - start_deactivation(dev); - else if (error) - fpi_image_device_session_error (dev, g_steal_pointer (&error)); - else - start_capture(dev); + fpi_ssm_free (ssm); + + /* Note: We assume that the error is a cancellation in the deactivation case */ + if (self->deactivating) + start_deactivation (dev); + else if (error) + fpi_image_device_session_error (dev, g_steal_pointer (&error)); + else + start_capture (dev); } -static void start_capture(FpImageDevice *dev) +static void +start_capture (FpImageDevice *dev) { - FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); - FpiSsm *ssm; + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); + FpiSsm *ssm; - self->image_size = 0; + self->image_size = 0; - ssm = fpi_ssm_new(FP_DEVICE(dev), capture_run_state, - CAPTURE_NUM_STATES, dev); - fpi_ssm_start(ssm, capture_sm_complete); + ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, + CAPTURE_NUM_STATES, dev); + fpi_ssm_start (ssm, capture_sm_complete); } /****** INITIALIZATION/DEINITIALIZATION ******/ enum deactivate_states { - DEACTIVATE_DEINIT, - DEACTIVATE_READ_DEINIT_DATA, - DEACTIVATE_NUM_STATES, + DEACTIVATE_DEINIT, + DEACTIVATE_READ_DEINIT_DATA, + DEACTIVATE_NUM_STATES, }; -static void deactivate_reqs_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +deactivate_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - if (!error) { - fpi_ssm_jump_to_state(transfer->ssm, CAPTURE_READ_DATA); - } else { - fpi_ssm_mark_failed(transfer->ssm, error); - } + if (!error) + fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA); + else + fpi_ssm_mark_failed (transfer->ssm, error); } /* TODO: process response properly */ -static void deactivate_read_data_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +deactivate_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - if (!error) { - fpi_ssm_mark_completed(transfer->ssm); - } else { - fpi_ssm_mark_failed(transfer->ssm, error); - } + if (!error) + fpi_ssm_mark_completed (transfer->ssm); + else + fpi_ssm_mark_failed (transfer->ssm, error); } -static void deactivate_run_state(FpiSsm *ssm, FpDevice *_dev, - void *user_data) +static void +deactivate_run_state (FpiSsm *ssm, FpDevice *_dev, + void *user_data) { - FpImageDevice *dev = user_data; - FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case DEACTIVATE_DEINIT: - upektc_img_submit_req(ssm, dev, upek2020_deinit, sizeof(upek2020_deinit), - self->seq, deactivate_reqs_cb); - self->seq++; - break; - case DEACTIVATE_READ_DEINIT_DATA: - upektc_img_read_data(ssm, dev, SHORT_RESPONSE_SIZE, 0, deactivate_read_data_cb); - break; - }; + switch (fpi_ssm_get_cur_state (ssm)) + { + case DEACTIVATE_DEINIT: + upektc_img_submit_req (ssm, dev, upek2020_deinit, sizeof (upek2020_deinit), + self->seq, deactivate_reqs_cb); + self->seq++; + break; + + case DEACTIVATE_READ_DEINIT_DATA: + upektc_img_read_data (ssm, dev, SHORT_RESPONSE_SIZE, 0, deactivate_read_data_cb); + break; + } + ; } -static void deactivate_sm_complete(FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +static void +deactivate_sm_complete (FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - FpImageDevice *dev = user_data; - FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev); - fp_dbg("Deactivate completed"); - fpi_ssm_free(ssm); + fp_dbg ("Deactivate completed"); + fpi_ssm_free (ssm); - self->deactivating = FALSE; - fpi_image_device_deactivate_complete(dev, error); + self->deactivating = FALSE; + fpi_image_device_deactivate_complete (dev, error); } -static void start_deactivation(FpImageDevice *dev) +static void +start_deactivation (FpImageDevice *dev) { - FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); - FpiSsm *ssm; + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); + FpiSsm *ssm; - self->image_size = 0; + self->image_size = 0; - ssm = fpi_ssm_new(FP_DEVICE(dev), deactivate_run_state, - DEACTIVATE_NUM_STATES, dev); - fpi_ssm_start(ssm, deactivate_sm_complete); + ssm = fpi_ssm_new (FP_DEVICE (dev), deactivate_run_state, + DEACTIVATE_NUM_STATES, dev); + fpi_ssm_start (ssm, deactivate_sm_complete); } enum activate_states { - ACTIVATE_CONTROL_REQ_1, - ACTIVATE_READ_CTRL_RESP_1, - ACTIVATE_INIT_1, - ACTIVATE_READ_INIT_1_RESP, - ACTIVATE_INIT_2, - ACTIVATE_READ_INIT_2_RESP, - ACTIVATE_CONTROL_REQ_2, - ACTIVATE_READ_CTRL_RESP_2, - ACTIVATE_INIT_3, - ACTIVATE_READ_INIT_3_RESP, - ACTIVATE_INIT_4, - ACTIVATE_READ_INIT_4_RESP, - ACTIVATE_NUM_STATES, + ACTIVATE_CONTROL_REQ_1, + ACTIVATE_READ_CTRL_RESP_1, + ACTIVATE_INIT_1, + ACTIVATE_READ_INIT_1_RESP, + ACTIVATE_INIT_2, + ACTIVATE_READ_INIT_2_RESP, + ACTIVATE_CONTROL_REQ_2, + ACTIVATE_READ_CTRL_RESP_2, + ACTIVATE_INIT_3, + ACTIVATE_READ_INIT_3_RESP, + ACTIVATE_INIT_4, + ACTIVATE_READ_INIT_4_RESP, + ACTIVATE_NUM_STATES, }; -static void init_reqs_ctrl_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +init_reqs_ctrl_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - if (!error) { - fpi_ssm_next_state(transfer->ssm); - } else { - fpi_ssm_mark_failed(transfer->ssm, error); - } + if (!error) + fpi_ssm_next_state (transfer->ssm); + else + fpi_ssm_mark_failed (transfer->ssm, error); } -static void init_reqs_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +init_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - if (!error) { - fpi_ssm_next_state(transfer->ssm); - } else { - fpi_ssm_mark_failed(transfer->ssm, error); - } + if (!error) + fpi_ssm_next_state (transfer->ssm); + else + fpi_ssm_mark_failed (transfer->ssm, error); } /* TODO: process response properly */ -static void init_read_data_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +init_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - if (!error) { - fpi_ssm_next_state(transfer->ssm); - } else { - fpi_ssm_mark_failed(transfer->ssm, error); - } + if (!error) + fpi_ssm_next_state (transfer->ssm); + else + fpi_ssm_mark_failed (transfer->ssm, error); } -static void activate_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) +static void +activate_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) { - FpiUsbTransfer *transfer; - FpImageDevice *idev = user_data; - FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); + FpiUsbTransfer *transfer; + FpImageDevice *idev = user_data; + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case ACTIVATE_CONTROL_REQ_1: - case ACTIVATE_CONTROL_REQ_2: - { - transfer = fpi_usb_transfer_new(dev); + switch (fpi_ssm_get_cur_state (ssm)) + { + case ACTIVATE_CONTROL_REQ_1: + case ACTIVATE_CONTROL_REQ_2: + { + transfer = fpi_usb_transfer_new (dev); - fpi_usb_transfer_fill_control(transfer, - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, - G_USB_DEVICE_REQUEST_TYPE_VENDOR, - G_USB_DEVICE_RECIPIENT_DEVICE, - 0x0c, 0x100, 0x0400, 1); - transfer->buffer[0] = '\0'; - transfer->ssm = ssm; - fpi_usb_transfer_submit(transfer, CTRL_TIMEOUT, NULL, - init_reqs_ctrl_cb, NULL); - fpi_usb_transfer_unref(transfer); - } - break; - case ACTIVATE_INIT_1: - upektc_img_submit_req(ssm, idev, upek2020_init_1, sizeof(upek2020_init_1), - 0, init_reqs_cb); - break; - case ACTIVATE_INIT_2: - upektc_img_submit_req(ssm, idev, upek2020_init_2, sizeof(upek2020_init_2), - 0, init_reqs_cb); - break; - case ACTIVATE_INIT_3: - upektc_img_submit_req(ssm, idev, upek2020_init_3, sizeof(upek2020_init_3), - 0, init_reqs_cb); - break; - case ACTIVATE_INIT_4: - upektc_img_submit_req(ssm, idev, upek2020_init_4, sizeof(upek2020_init_4), - self->seq, init_reqs_cb); - /* Seq should be updated after 4th init */ - self->seq++; - break; - case ACTIVATE_READ_CTRL_RESP_1: - case ACTIVATE_READ_CTRL_RESP_2: - case ACTIVATE_READ_INIT_1_RESP: - case ACTIVATE_READ_INIT_2_RESP: - case ACTIVATE_READ_INIT_3_RESP: - case ACTIVATE_READ_INIT_4_RESP: - upektc_img_read_data(ssm, idev, SHORT_RESPONSE_SIZE, 0, init_read_data_cb); - break; - } + fpi_usb_transfer_fill_control (transfer, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0x0c, 0x100, 0x0400, 1); + transfer->buffer[0] = '\0'; + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, + init_reqs_ctrl_cb, NULL); + fpi_usb_transfer_unref (transfer); + } + break; + + case ACTIVATE_INIT_1: + upektc_img_submit_req (ssm, idev, upek2020_init_1, sizeof (upek2020_init_1), + 0, init_reqs_cb); + break; + + case ACTIVATE_INIT_2: + upektc_img_submit_req (ssm, idev, upek2020_init_2, sizeof (upek2020_init_2), + 0, init_reqs_cb); + break; + + case ACTIVATE_INIT_3: + upektc_img_submit_req (ssm, idev, upek2020_init_3, sizeof (upek2020_init_3), + 0, init_reqs_cb); + break; + + case ACTIVATE_INIT_4: + upektc_img_submit_req (ssm, idev, upek2020_init_4, sizeof (upek2020_init_4), + self->seq, init_reqs_cb); + /* Seq should be updated after 4th init */ + self->seq++; + break; + + case ACTIVATE_READ_CTRL_RESP_1: + case ACTIVATE_READ_CTRL_RESP_2: + case ACTIVATE_READ_INIT_1_RESP: + case ACTIVATE_READ_INIT_2_RESP: + case ACTIVATE_READ_INIT_3_RESP: + case ACTIVATE_READ_INIT_4_RESP: + upektc_img_read_data (ssm, idev, SHORT_RESPONSE_SIZE, 0, init_read_data_cb); + break; + } } -static void activate_sm_complete(FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +static void +activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = user_data; - fpi_ssm_free(ssm); - fpi_image_device_activate_complete(dev, error); + fpi_ssm_free (ssm); + fpi_image_device_activate_complete (dev, error); - if (!error) - start_capture(dev); + if (!error) + start_capture (dev); } -static void dev_activate(FpImageDevice *dev) +static void +dev_activate (FpImageDevice *dev) { - FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); - FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); - self->seq = 0; - fpi_ssm_start(ssm, activate_sm_complete); + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); + FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state, + ACTIVATE_NUM_STATES, dev); + + self->seq = 0; + fpi_ssm_start (ssm, activate_sm_complete); } -static void dev_deactivate(FpImageDevice *dev) +static void +dev_deactivate (FpImageDevice *dev) { - FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); - self->deactivating = TRUE; + self->deactivating = TRUE; } -static void dev_init(FpImageDevice *dev) +static void +dev_init (FpImageDevice *dev) { - FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); - GError *error = NULL; - /* TODO check that device has endpoints we're using */ + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); + GError *error = NULL; - if (!g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error)) { - fpi_image_device_open_complete(dev, error); - return; - } + /* TODO check that device has endpoints we're using */ - self->image_bits = g_malloc0 (IMAGE_SIZE * 2); - fpi_image_device_open_complete(dev, NULL); + if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error)) + { + fpi_image_device_open_complete (dev, error); + return; + } + + self->image_bits = g_malloc0 (IMAGE_SIZE * 2); + fpi_image_device_open_complete (dev, NULL); } -static void dev_deinit(FpImageDevice *dev) +static void +dev_deinit (FpImageDevice *dev) { - FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG(dev); - GError *error = NULL; + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); + GError *error = NULL; - g_clear_pointer (&self->image_bits, g_free); - g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), - 0, 0, &error); - fpi_image_device_close_complete(dev, error); + g_clear_pointer (&self->image_bits, g_free); + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), + 0, 0, &error); + fpi_image_device_close_complete (dev, error); } static int -discover(GUsbDevice *usb_device) +discover (GUsbDevice *usb_device) { - gint16 pid = g_usb_device_get_pid (usb_device); - gint16 bcd = g_usb_device_get_release (usb_device); + gint16 pid = g_usb_device_get_pid (usb_device); + gint16 bcd = g_usb_device_get_release (usb_device); - if (pid == 0x2020 && bcd == 1) - return 100; - if (pid == 0x2016 && bcd == 2) - return 100; + if (pid == 0x2020 && bcd == 1) + return 100; + if (pid == 0x2016 && bcd == 2) + return 100; - return 0; + return 0; } -static const FpIdEntry id_table [ ] = { - { .vid = 0x147e, .pid = 0x2016, - }, - { .vid = 0x147e, .pid = 0x2020, - }, - { .vid = 0, .pid = 0, .driver_data = 0 }, +static const FpIdEntry id_table[] = { + { .vid = 0x147e, .pid = 0x2016, }, + { .vid = 0x147e, .pid = 0x2020, }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -static void fpi_device_upektc_img_init(FpiDeviceUpektcImg *self) { +static void +fpi_device_upektc_img_init (FpiDeviceUpektcImg *self) +{ } -static void fpi_device_upektc_img_class_init(FpiDeviceUpektcImgClass *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); +static void +fpi_device_upektc_img_class_init (FpiDeviceUpektcImgClass *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); - dev_class->id = "upektc_img"; - dev_class->full_name = "Upek TouchChip Fingerprint Coprocessor"; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->id_table = id_table; - dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - dev_class->usb_discover = discover; + dev_class->id = "upektc_img"; + dev_class->full_name = "Upek TouchChip Fingerprint Coprocessor"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + dev_class->usb_discover = discover; - img_class->img_open = dev_init; - img_class->img_close = dev_deinit; - img_class->activate = dev_activate; - img_class->deactivate = dev_deactivate; + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; - img_class->bz3_threshold = 20; + img_class->bz3_threshold = 20; - img_class->img_width = IMAGE_WIDTH; - img_class->img_height = IMAGE_HEIGHT; + img_class->img_width = IMAGE_WIDTH; + img_class->img_height = IMAGE_HEIGHT; } diff --git a/libfprint/drivers/upektc_img.h b/libfprint/drivers/upektc_img.h index 6146557e..9185aa8e 100644 --- a/libfprint/drivers/upektc_img.h +++ b/libfprint/drivers/upektc_img.h @@ -21,124 +21,124 @@ #define __UPEKTC_IMG_H static const unsigned char upek2020_init_1[] = { -'C', 'i', 'a', 'o', -0x04, -0x00, 0x0d, -0x01, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, -0x01, 0x00, 0x00, 0x00, -0xda, 0xc1 + 'C', 'i', 'a', 'o', + 0x04, + 0x00, 0x0d, + 0x01, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0xda, 0xc1 }; static const unsigned char upek2020_init_2[] = { -0x43, 0x69, 0x61, 0x6f, -0x07, -0x00, 0x01, -0x01, -0x3d, 0x72 + 0x43, 0x69, 0x61, 0x6f, + 0x07, + 0x00, 0x01, + 0x01, + 0x3d, 0x72 }; static const unsigned char upek2020_init_3[] = { -'C', 'i', 'a', 'o', -0x04, -0x00, 0x0d, -0x01, 0x00, 0xbc, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, -0x01, 0x00, 0x00, 0x00, -0x55, 0x2f + 'C', 'i', 'a', 'o', + 0x04, + 0x00, 0x0d, + 0x01, 0x00, 0xbc, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x55, 0x2f }; static const unsigned char upek2020_init_4[] = { -'C', 'i', 'a', 'o', -0x00, -0x00, 0x07, -0x28, 0x04, 0x00, 0x00, 0x00, 0x06, 0x04, -0xc0, 0xd6 + 'C', 'i', 'a', 'o', + 0x00, + 0x00, 0x07, + 0x28, 0x04, 0x00, 0x00, 0x00, 0x06, 0x04, + 0xc0, 0xd6 }; static const unsigned char upek2020_deinit[] = { -'C', 'i', 'a', 'o', -0x07, -0x00, 0x01, -0x01, -0x3d, -0x72 + 'C', 'i', 'a', 'o', + 0x07, + 0x00, 0x01, + 0x01, + 0x3d, + 0x72 }; static const unsigned char upek2020_init_capture[] = { -'C', 'i', 'a', 'o', -0x00, -0x00, 0x0e, /* Seq = 7, len = 0x00e */ -0x28, /* CMD = 0x28 */ -0x0b, 0x00, /* Inner len = 0x000b */ -0x00, 0x00, -0x0e, /* SUBCMD = 0x0e */ -0x02, -0xfe, 0xff, 0xff, 0xff, /* timeout = -2 = 0xfffffffe = infinite time */ -0x02, -0x00, /* Wait for acceptable finger */ -0x02, -0x14, 0x9a /* CRC */ + 'C', 'i', 'a', 'o', + 0x00, + 0x00, 0x0e, /* Seq = 7, len = 0x00e */ + 0x28, /* CMD = 0x28 */ + 0x0b, 0x00, /* Inner len = 0x000b */ + 0x00, 0x00, + 0x0e, /* SUBCMD = 0x0e */ + 0x02, + 0xfe, 0xff, 0xff, 0xff, /* timeout = -2 = 0xfffffffe = infinite time */ + 0x02, + 0x00, /* Wait for acceptable finger */ + 0x02, + 0x14, 0x9a /* CRC */ }; #if 0 static const unsigned char finger_status[] = { -'C', 'i', 'a', 'o', -0x00, -0x70, 0x14, /* Seq = 7, len = 0x014 */ -0x28, /* CMD = 0x28 */ -0x11, 0x00, /* Inner len = 0x0011 */ -0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, -0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, -0x26, 0x03, /* CRC */ -0x00, 0x00, 0x00, /* Rest is garbage */ -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 'C', 'i', 'a', 'o', + 0x00, + 0x70, 0x14, /* Seq = 7, len = 0x014 */ + 0x28, /* CMD = 0x28 */ + 0x11, 0x00, /* Inner len = 0x0011 */ + 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + 0x26, 0x03, /* CRC */ + 0x00, 0x00, 0x00, /* Rest is garbage */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #endif static const unsigned char upek2020_ack_00_28[] = { -'C', 'i', 'a', 'o', -0x00, -0x80, 0x08, /* Seq = 8, len = 0x008 */ -0x28, /* CMD = 0x28 */ -0x05, 0x00, /* Inner len = 0x0005 */ -0x00, 0x00, 0x00, 0x30, 0x01, -0x6a, 0xc4 /* CRC */ + 'C', 'i', 'a', 'o', + 0x00, + 0x80, 0x08, /* Seq = 8, len = 0x008 */ + 0x28, /* CMD = 0x28 */ + 0x05, 0x00, /* Inner len = 0x0005 */ + 0x00, 0x00, 0x00, 0x30, 0x01, + 0x6a, 0xc4 /* CRC */ }; #if 0 /* No seq should be tracked here */ static const unsigned char got_finger[] = { -'C', 'i', 'a', 'o', -0x08, -0x00, 0x00, /* Seq = 0, len = 0x000 */ -0xa1, 0xa9, /* CRC */ -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Rest is garbage */ -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 'C', 'i', 'a', 'o', + 0x08, + 0x00, 0x00, /* Seq = 0, len = 0x000 */ + 0xa1, 0xa9, /* CRC */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Rest is garbage */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #endif /* No seq should be put in there */ static const unsigned char upek2020_ack_08[] = { -'C', 'i', 'a', 'o', -0x09, -0x00, 0x00, /* Seq = 0, len = 0x0 */ -0x91, 0x9e /* CRC */ + 'C', 'i', 'a', 'o', + 0x09, + 0x00, 0x00, /* Seq = 0, len = 0x0 */ + 0x91, 0x9e /* CRC */ }; static const unsigned char upek2020_ack_frame[] = { -'C', 'i', 'a', 'o', -0x00, -0x50, 0x01, /* Seq = 5, len = 0x001 */ -0x30, -0xac, 0x5b /* CRC */ + 'C', 'i', 'a', 'o', + 0x00, + 0x50, 0x01, /* Seq = 5, len = 0x001 */ + 0x30, + 0xac, 0x5b /* CRC */ }; #endif diff --git a/libfprint/drivers/upekts.c b/libfprint/drivers/upekts.c index 09160d97..a3a0cad0 100644 --- a/libfprint/drivers/upekts.c +++ b/libfprint/drivers/upekts.c @@ -37,26 +37,27 @@ #define MSG_READ_BUF_SIZE 0x40 #define MAX_DATA_IN_READ_BUF (MSG_READ_BUF_SIZE - 9) -struct _FpiDeviceUpekts { - FpDevice parent; +struct _FpiDeviceUpekts +{ + FpDevice parent; - gboolean enroll_passed; - gint enroll_stage; - gboolean first_verify_iteration; - guint8 seq; /* FIXME: improve/automate seq handling */ + gboolean enroll_passed; + gint enroll_stage; + gboolean first_verify_iteration; + guint8 seq; /* FIXME: improve/automate seq handling */ }; -G_DECLARE_FINAL_TYPE(FpiDeviceUpekts, fpi_device_upekts, FPI, - DEVICE_UPEKTS, FpDevice); -G_DEFINE_TYPE(FpiDeviceUpekts, fpi_device_upekts, FP_TYPE_DEVICE); +G_DECLARE_FINAL_TYPE (FpiDeviceUpekts, fpi_device_upekts, FPI, + DEVICE_UPEKTS, FpDevice); +G_DEFINE_TYPE (FpiDeviceUpekts, fpi_device_upekts, FP_TYPE_DEVICE); /* * MESSAGE FORMAT - * + * * Messages to and from the device have the same format. * * Byte-wise: - * 'C' 'i' 'a' 'o' A B L C1 C2 + * 'C' 'i' 'a' 'o' A B L C1 C2 * * Ciao prefixes all messages. The rightmost 4 bits of B become the uppermost * 4 bits of L, and when combined with the lower 8 bits listed as 'L', L is @@ -69,7 +70,7 @@ G_DEFINE_TYPE(FpiDeviceUpekts, fpi_device_upekts, FP_TYPE_DEVICE); * with B=0 and A incremented. * * When the driver sends a command to the device, A=0 and B is used as a - * sequence counter. It starts at 0, increments by 0x10 on each command, and + * sequence counter. It starts at 0, increments by 0x10 on each command, and * wraps around. * After each command is sent, the device responds with another message * indicating completion of the command including any data that was requested. @@ -78,7 +79,7 @@ G_DEFINE_TYPE(FpiDeviceUpekts, fpi_device_upekts, FP_TYPE_DEVICE); * When the driver is sending commands as above, and when the device is * responding, the seems to follow this structure: * - * 28 L1 L2 0 0 S + * 28 L1 L2 0 0 S * * Where the length of is L-3, and S is some kind of subcommand * code. L1 is the least significant bits of L, L2 is the most significant. In @@ -90,1304 +91,1489 @@ G_DEFINE_TYPE(FpiDeviceUpekts, fpi_device_upekts, FP_TYPE_DEVICE); #define CMD_SEQ_INCREMENT 0x10 -static FpiUsbTransfer *alloc_send_cmd_transfer(FpDevice *dev, - unsigned char seq_a, - unsigned char seq_b, - const unsigned char *data, - guint16 len) +static FpiUsbTransfer * +alloc_send_cmd_transfer (FpDevice *dev, + unsigned char seq_a, + unsigned char seq_b, + const unsigned char *data, + guint16 len) { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); - guint16 crc; - const char *ciao = "Ciao"; + FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev); + guint16 crc; + const char *ciao = "Ciao"; - /* 9 bytes extra for: 4 byte 'Ciao', 1 byte A, 1 byte B | lenHI, - * 1 byte lenLO, 2 byte CRC */ - size_t urblen = len + 9; + /* 9 bytes extra for: 4 byte 'Ciao', 1 byte A, 1 byte B | lenHI, + * 1 byte lenLO, 2 byte CRC */ + size_t urblen = len + 9; - if (!data && len > 0) { - fp_err("len>0 but no data?"); - return NULL; - } + if (!data && len > 0) + { + fp_err ("len>0 but no data?"); + return NULL; + } - fpi_usb_transfer_fill_bulk (transfer, EP_OUT, urblen); + fpi_usb_transfer_fill_bulk (transfer, EP_OUT, urblen); - /* Write header */ - memcpy(transfer->buffer, ciao, strlen(ciao)); - transfer->buffer[4] = seq_a; - transfer->buffer[5] = seq_b | ((len & 0xf00) >> 8); - transfer->buffer[6] = len & 0x00ff; + /* Write header */ + memcpy (transfer->buffer, ciao, strlen (ciao)); + transfer->buffer[4] = seq_a; + transfer->buffer[5] = seq_b | ((len & 0xf00) >> 8); + transfer->buffer[6] = len & 0x00ff; - /* Copy data */ - if (data) - memcpy(transfer->buffer + 7, data, len); + /* Copy data */ + if (data) + memcpy (transfer->buffer + 7, data, len); - /* Append CRC */ - crc = udf_crc(transfer->buffer + 4, urblen - 6); - transfer->buffer[urblen - 2] = crc & 0xff; - transfer->buffer[urblen - 1] = crc >> 8; + /* Append CRC */ + crc = udf_crc (transfer->buffer + 4, urblen - 6); + transfer->buffer[urblen - 2] = crc & 0xff; + transfer->buffer[urblen - 1] = crc >> 8; - return transfer; + return transfer; } -static FpiUsbTransfer *alloc_send_cmd28_transfer(FpDevice *dev, - unsigned char subcmd, - const unsigned char *data, - guint16 innerlen) +static FpiUsbTransfer * +alloc_send_cmd28_transfer (FpDevice *dev, + unsigned char subcmd, + const unsigned char *data, + guint16 innerlen) { - guint16 _innerlen = innerlen; - size_t len = innerlen + 6; - unsigned char *buf = g_malloc0(len); - FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); - guint8 seq = upekdev->seq + CMD_SEQ_INCREMENT; - FpiUsbTransfer *ret; + guint16 _innerlen = innerlen; + size_t len = innerlen + 6; + unsigned char *buf = g_malloc0 (len); + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev); + guint8 seq = upekdev->seq + CMD_SEQ_INCREMENT; + FpiUsbTransfer *ret; - fp_dbg("seq=%02x subcmd=%02x with %d bytes of data", seq, subcmd, innerlen); + fp_dbg ("seq=%02x subcmd=%02x with %d bytes of data", seq, subcmd, innerlen); - _innerlen = innerlen + 3; - buf[0] = 0x28; - buf[1] = _innerlen & 0x00ff; - buf[2] = (_innerlen & 0xff00) >> 8; - buf[5] = subcmd; - memcpy(buf + 6, data, innerlen); + _innerlen = innerlen + 3; + buf[0] = 0x28; + buf[1] = _innerlen & 0x00ff; + buf[2] = (_innerlen & 0xff00) >> 8; + buf[5] = subcmd; + memcpy (buf + 6, data, innerlen); - ret = alloc_send_cmd_transfer(dev, 0, seq, buf, len); - upekdev->seq = seq; + ret = alloc_send_cmd_transfer (dev, 0, seq, buf, len); + upekdev->seq = seq; - g_free(buf); - return ret; + g_free (buf); + return ret; } -static FpiUsbTransfer *alloc_send_cmdresponse_transfer(FpDevice *dev, - unsigned char seq, - const unsigned char *data, - guint8 len) +static FpiUsbTransfer * +alloc_send_cmdresponse_transfer (FpDevice *dev, + unsigned char seq, + const unsigned char *data, + guint8 len) { - fp_dbg("seq=%02x len=%d", seq, len); - return alloc_send_cmd_transfer(dev, seq, 0, data, len); + fp_dbg ("seq=%02x len=%d", seq, len); + return alloc_send_cmd_transfer (dev, seq, 0, data, len); } enum read_msg_type { - READ_MSG_CMD, - READ_MSG_RESPONSE, + READ_MSG_CMD, + READ_MSG_RESPONSE, }; -typedef void (*read_msg_cb_fn)(FpDevice *dev, enum read_msg_type type, - guint8 seq, unsigned char subcmd, - unsigned char *data, size_t data_len, - void *user_data, GError *error); +typedef void (*read_msg_cb_fn)(FpDevice *dev, + enum read_msg_type type, + guint8 seq, + unsigned char subcmd, + unsigned char *data, + size_t data_len, + void *user_data, + GError *error); -struct read_msg_data { - gssize buflen; - guint8 *buffer; - read_msg_cb_fn callback; - void *user_data; -}; - -static void __read_msg_async(FpDevice *dev, struct read_msg_data *udata); - -#define READ_MSG_DATA_CB_ERR(dev, udata, error) (udata)->callback(dev, \ - READ_MSG_CMD, 0, 0, NULL, 0, (udata)->user_data, error) - -static void busy_ack_sent_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +struct read_msg_data { - struct read_msg_data *udata = user_data; + gssize buflen; + guint8 *buffer; + read_msg_cb_fn callback; + void *user_data; +}; - if (error) { - READ_MSG_DATA_CB_ERR(device, udata, error); - g_free(udata->buffer); - g_free(udata); - } else { - __read_msg_async(device, udata); - } +static void __read_msg_async (FpDevice *dev, + struct read_msg_data *udata); + +#define READ_MSG_DATA_CB_ERR(dev, udata, error) (udata)->callback (dev, \ + READ_MSG_CMD, 0, 0, NULL, 0, (udata)->user_data, error) + +static void +busy_ack_sent_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) +{ + struct read_msg_data *udata = user_data; + + if (error) + { + READ_MSG_DATA_CB_ERR (device, udata, error); + g_free (udata->buffer); + g_free (udata); + } + else + { + __read_msg_async (device, udata); + } } -static void busy_ack_retry_read(FpDevice *device, struct read_msg_data *udata) +static void +busy_ack_retry_read (FpDevice *device, struct read_msg_data *udata) { - FpiUsbTransfer *transfer; + FpiUsbTransfer *transfer; - transfer = alloc_send_cmdresponse_transfer(device, 0x09, NULL, 0); - transfer->short_is_error = TRUE; + transfer = alloc_send_cmdresponse_transfer (device, 0x09, NULL, 0); + transfer->short_is_error = TRUE; - fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, busy_ack_sent_cb, udata); - fpi_usb_transfer_unref (transfer); + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, busy_ack_sent_cb, udata); + fpi_usb_transfer_unref (transfer); } /* Returns 0 if message was handled, 1 if it was a device-busy message, and * negative on error. */ -static void __handle_incoming_msg(FpDevice *device, - struct read_msg_data *udata) +static void +__handle_incoming_msg (FpDevice *device, + struct read_msg_data *udata) { - GError *error = NULL; - guint8 *buf = udata->buffer; - guint16 len = ((buf[5] & 0xf) << 8) | buf[6]; - guint16 computed_crc = udf_crc(buf + 4, len + 3); - guint16 msg_crc = (buf[len + 8] << 8) | buf[len + 7]; - unsigned char *retdata = NULL; - unsigned char code_a, code_b; + GError *error = NULL; + guint8 *buf = udata->buffer; + guint16 len = ((buf[5] & 0xf) << 8) | buf[6]; + guint16 computed_crc = udf_crc (buf + 4, len + 3); + guint16 msg_crc = (buf[len + 8] << 8) | buf[len + 7]; + unsigned char *retdata = NULL; + unsigned char code_a, code_b; - if (computed_crc != msg_crc) { - fp_err("CRC failed, got %04x expected %04x", msg_crc, computed_crc); - error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "CRC check on message failed"); - goto err; - } + if (computed_crc != msg_crc) + { + fp_err ("CRC failed, got %04x expected %04x", msg_crc, computed_crc); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "CRC check on message failed"); + goto err; + } - code_a = buf[4]; - code_b = buf[5] & 0xf0; - len = ((buf[5] & 0xf) << 8) | buf[6]; - fp_dbg("A=%02x B=%02x len=%d", code_a, code_b, len); + code_a = buf[4]; + code_b = buf[5] & 0xf0; + len = ((buf[5] & 0xf) << 8) | buf[6]; + fp_dbg ("A=%02x B=%02x len=%d", code_a, code_b, len); - if (code_a && !code_b) { - /* device sends command to driver */ - fp_dbg("cmd %x from device to driver", code_a); + if (code_a && !code_b) + { + /* device sends command to driver */ + fp_dbg ("cmd %x from device to driver", code_a); - if (code_a == 0x08) { - fp_dbg("device busy, send busy-ack"); - busy_ack_retry_read(device, udata); - return; - } + if (code_a == 0x08) + { + fp_dbg ("device busy, send busy-ack"); + busy_ack_retry_read (device, udata); + return; + } - if (len > 0) { - retdata = g_malloc(len); - memcpy(retdata, buf + 7, len); - } - udata->callback(device, READ_MSG_CMD, code_a, 0, retdata, len, - udata->user_data, NULL); - goto done; - } else if (!code_a) { - /* device sends response to a previously executed command */ - unsigned char *innerbuf = buf + 7; - unsigned char _subcmd; - guint16 innerlen; + if (len > 0) + { + retdata = g_malloc (len); + memcpy (retdata, buf + 7, len); + } + udata->callback (device, READ_MSG_CMD, code_a, 0, retdata, len, + udata->user_data, NULL); + goto done; + } + else if (!code_a) + { + /* device sends response to a previously executed command */ + unsigned char *innerbuf = buf + 7; + unsigned char _subcmd; + guint16 innerlen; - if (len < 6) { - fp_warn("cmd response too short (%d)", len); - error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "CMD response too short"); - goto err; - } - if (innerbuf[0] != 0x28) { - fp_warn("cmd response without 28 byte?"); - error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "CMD response without 0x28 byte"); - goto err; - } + if (len < 6) + { + fp_warn ("cmd response too short (%d)", len); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "CMD response too short"); + goto err; + } + if (innerbuf[0] != 0x28) + { + fp_warn ("cmd response without 28 byte?"); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "CMD response without 0x28 byte"); + goto err; + } - /* not really sure what these 2 bytes are. on most people's hardware, - * these bytes are always 0. However, Alon Bar-Lev's hardware gives - * 0xfb 0xff during the READ28_OB initsm stage. so don't error out - * if they are different... */ - if (innerbuf[3] || innerbuf[4]) - fp_dbg("non-zero bytes in cmd response"); + /* not really sure what these 2 bytes are. on most people's hardware, + * these bytes are always 0. However, Alon Bar-Lev's hardware gives + * 0xfb 0xff during the READ28_OB initsm stage. so don't error out + * if they are different... */ + if (innerbuf[3] || innerbuf[4]) + fp_dbg ("non-zero bytes in cmd response"); - innerlen = innerbuf[1] | (innerbuf[2] << 8); - innerlen = innerlen - 3; - _subcmd = innerbuf[5]; - fp_dbg("device responds to subcmd %x with %d bytes", _subcmd, innerlen); - if (innerlen > 0) { - retdata = g_malloc(innerlen); - memcpy(retdata, innerbuf + 6, innerlen); - } - udata->callback(device, READ_MSG_RESPONSE, code_b, _subcmd, - retdata, innerlen, udata->user_data, NULL); - g_free(retdata); - goto done; - } else { - fp_err("don't know how to handle this message"); - error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Message cannot be processed"); - goto err; - } - g_assert_not_reached(); + innerlen = innerbuf[1] | (innerbuf[2] << 8); + innerlen = innerlen - 3; + _subcmd = innerbuf[5]; + fp_dbg ("device responds to subcmd %x with %d bytes", _subcmd, innerlen); + if (innerlen > 0) + { + retdata = g_malloc (innerlen); + memcpy (retdata, innerbuf + 6, innerlen); + } + udata->callback (device, READ_MSG_RESPONSE, code_b, _subcmd, + retdata, innerlen, udata->user_data, NULL); + g_free (retdata); + goto done; + } + else + { + fp_err ("don't know how to handle this message"); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Message cannot be processed"); + goto err; + } + g_assert_not_reached (); err: - READ_MSG_DATA_CB_ERR(device, udata, error); + READ_MSG_DATA_CB_ERR (device, udata, error); done: - g_free(udata->buffer); - g_free(udata); + g_free (udata->buffer); + g_free (udata); } -static void read_msg_extend_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +read_msg_extend_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - struct read_msg_data *udata = user_data; + struct read_msg_data *udata = user_data; - if (error) { - fp_err("extended msg read failed: %s", error->message); - READ_MSG_DATA_CB_ERR(device, udata, error); - g_free(udata->buffer); - g_free(udata); - return; - } + if (error) + { + fp_err ("extended msg read failed: %s", error->message); + READ_MSG_DATA_CB_ERR (device, udata, error); + g_free (udata->buffer); + g_free (udata); + return; + } - __handle_incoming_msg(device, udata); + __handle_incoming_msg (device, udata); } -static void read_msg_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - struct read_msg_data *udata = user_data; - guint16 len; + struct read_msg_data *udata = user_data; + guint16 len; - if (error) { - fp_err("async msg read failed: %s", error->message); - goto err; - } - if (transfer->actual_length < 9) { - fp_err("async msg read too short (%d)", - (gint)transfer->actual_length); - error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Packet from device was too short"); - goto err; - } + if (error) + { + fp_err ("async msg read failed: %s", error->message); + goto err; + } + if (transfer->actual_length < 9) + { + fp_err ("async msg read too short (%d)", + (gint) transfer->actual_length); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Packet from device was too short"); + goto err; + } - if (strncmp(udata->buffer, "Ciao", 4) != 0) { - fp_err("no Ciao for you!!"); - error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Packet from device had incorrect header"); - goto err; - } + if (strncmp (udata->buffer, "Ciao", 4) != 0) + { + fp_err ("no Ciao for you!!"); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Packet from device had incorrect header"); + goto err; + } - len = ((udata->buffer[5] & 0xf) << 8) | udata->buffer[6]; - if (transfer->actual_length != MSG_READ_BUF_SIZE - && (len + 9) > transfer->actual_length) { - /* Check that the length claimed inside the message is in line with - * the amount of data that was transferred over USB. */ - fp_err("msg didn't include enough data, expected=%d recv=%d", - len + 9, (gint)transfer->actual_length); - error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Packet from device didn't include data"); - goto err; - } + len = ((udata->buffer[5] & 0xf) << 8) | udata->buffer[6]; + if (transfer->actual_length != MSG_READ_BUF_SIZE && + (len + 9) > transfer->actual_length) + { + /* Check that the length claimed inside the message is in line with + * the amount of data that was transferred over USB. */ + fp_err ("msg didn't include enough data, expected=%d recv=%d", + len + 9, (gint) transfer->actual_length); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Packet from device didn't include data"); + goto err; + } - /* We use a 64 byte buffer for reading messages. However, sometimes - * messages are longer, in which case we have to do another USB bulk read - * to read the remainder. This is handled below. */ - if (len > MAX_DATA_IN_READ_BUF) { - int needed = len - MAX_DATA_IN_READ_BUF; - FpiUsbTransfer *etransfer = fpi_usb_transfer_new(device); + /* We use a 64 byte buffer for reading messages. However, sometimes + * messages are longer, in which case we have to do another USB bulk read + * to read the remainder. This is handled below. */ + if (len > MAX_DATA_IN_READ_BUF) + { + int needed = len - MAX_DATA_IN_READ_BUF; + FpiUsbTransfer *etransfer = fpi_usb_transfer_new (device); - fp_dbg("didn't fit in buffer, need to extend by %d bytes", needed); - udata->buffer = g_realloc((gpointer) udata->buffer, len); - udata->buflen = len; + fp_dbg ("didn't fit in buffer, need to extend by %d bytes", needed); + udata->buffer = g_realloc ((gpointer) udata->buffer, len); + udata->buflen = len; - fpi_usb_transfer_fill_bulk_full(etransfer, EP_IN, - udata->buffer + MSG_READ_BUF_SIZE, - needed, NULL); - etransfer->short_is_error = TRUE; - fpi_usb_transfer_submit(etransfer, TIMEOUT, - NULL, - read_msg_extend_cb, udata); - fpi_usb_transfer_unref(etransfer); - return; - } + fpi_usb_transfer_fill_bulk_full (etransfer, EP_IN, + udata->buffer + MSG_READ_BUF_SIZE, + needed, NULL); + etransfer->short_is_error = TRUE; + fpi_usb_transfer_submit (etransfer, TIMEOUT, + NULL, + read_msg_extend_cb, udata); + fpi_usb_transfer_unref (etransfer); + return; + } - __handle_incoming_msg(device, udata); + __handle_incoming_msg (device, udata); - return; + return; err: - READ_MSG_DATA_CB_ERR(device, udata, error); - g_free(udata->buffer); - g_free(udata); + READ_MSG_DATA_CB_ERR (device, udata, error); + g_free (udata->buffer); + g_free (udata); } -static void __read_msg_async(FpDevice *device, struct read_msg_data *udata) +static void +__read_msg_async (FpDevice *device, struct read_msg_data *udata) { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(device); + FpiUsbTransfer *transfer = fpi_usb_transfer_new (device); - if (udata->buflen != MSG_READ_BUF_SIZE) { - udata->buffer = g_realloc (udata->buffer, MSG_READ_BUF_SIZE); - udata->buflen = MSG_READ_BUF_SIZE; - } + if (udata->buflen != MSG_READ_BUF_SIZE) + { + udata->buffer = g_realloc (udata->buffer, MSG_READ_BUF_SIZE); + udata->buflen = MSG_READ_BUF_SIZE; + } - fpi_usb_transfer_fill_bulk_full(transfer, EP_IN, udata->buffer, udata->buflen, NULL); - fpi_usb_transfer_submit(transfer, TIMEOUT, NULL, read_msg_cb, udata); - fpi_usb_transfer_unref(transfer); + fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, udata->buffer, udata->buflen, NULL); + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, read_msg_cb, udata); + fpi_usb_transfer_unref (transfer); } -static void read_msg_async(FpDevice *dev, - read_msg_cb_fn callback, - void *user_data) +static void +read_msg_async (FpDevice *dev, + read_msg_cb_fn callback, + void *user_data) { - struct read_msg_data *udata = g_new0(struct read_msg_data, 1); + struct read_msg_data *udata = g_new0 (struct read_msg_data, 1); - udata->buflen = 0; - udata->buffer = NULL; - udata->callback = callback; - udata->user_data = user_data; - __read_msg_async(dev, udata); + udata->buflen = 0; + udata->buffer = NULL; + udata->callback = callback; + udata->user_data = user_data; + __read_msg_async (dev, udata); } static const unsigned char init_resp03[] = { - 0x01, 0x00, 0xe8, 0x03, 0x00, 0x00, 0xff, 0x07 + 0x01, 0x00, 0xe8, 0x03, 0x00, 0x00, 0xff, 0x07 }; static const unsigned char init28_08[] = { - 0x04, 0x83, 0x00, 0x2c, 0x22, 0x23, 0x97, 0xc9, 0xa7, 0x15, 0xa0, 0x8a, - 0xab, 0x3c, 0xd0, 0xbf, 0xdb, 0xf3, 0x92, 0x6f, 0xae, 0x3b, 0x1e, 0x44, - 0xc4 + 0x04, 0x83, 0x00, 0x2c, 0x22, 0x23, 0x97, 0xc9, 0xa7, 0x15, 0xa0, 0x8a, + 0xab, 0x3c, 0xd0, 0xbf, 0xdb, 0xf3, 0x92, 0x6f, 0xae, 0x3b, 0x1e, 0x44, + 0xc4 }; static const unsigned char init28_0c[] = { - 0x04, 0x03, 0x00, 0x00, 0x00 + 0x04, 0x03, 0x00, 0x00, 0x00 }; static const unsigned char init28_0b[] = { - 0x04, 0x03, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, - 0x00, 0x64, 0x00, 0xf4, 0x01, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 + 0x04, 0x03, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0a, + 0x00, 0x64, 0x00, 0xf4, 0x01, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 }; /* device initialisation state machine */ enum initsm_states { - WRITE_CTRL400 = 0, - READ_MSG03, - SEND_RESP03, - READ_MSG05, - SEND28_06, - READ28_06, - SEND28_07, - READ28_07, - SEND28_08, - READ28_08, - SEND28_0C, - READ28_0C, - SEND28_0B, - READ28_0B, - INITSM_NUM_STATES, + WRITE_CTRL400 = 0, + READ_MSG03, + SEND_RESP03, + READ_MSG05, + SEND28_06, + READ28_06, + SEND28_07, + READ28_07, + SEND28_08, + READ28_08, + SEND28_0C, + READ28_0C, + SEND28_0B, + READ28_0B, + INITSM_NUM_STATES, }; static void -initsm_read_msg_response_cb(FpiSsm *ssm, - FpDevice *dev, - enum read_msg_type type, - guint8 seq, - unsigned char expect_subcmd, - unsigned char subcmd, - GError *error) +initsm_read_msg_response_cb (FpiSsm *ssm, + FpDevice *dev, + enum read_msg_type type, + guint8 seq, + unsigned char expect_subcmd, + unsigned char subcmd, + GError *error) { - FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev); - if (error) { - fpi_ssm_mark_failed(ssm, error); - } else if (type != READ_MSG_RESPONSE) { - fp_err("expected response, got %d seq=%x in state %d", type, seq, - fpi_ssm_get_cur_state(ssm)); - fpi_ssm_mark_failed(ssm, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Unexpected message type")); - } else if (seq != upekdev->seq) { - fp_warn("expected response to subcmd 0x%02x, got response to %02x in " - "state %d", expect_subcmd, subcmd, - fpi_ssm_get_cur_state(ssm)); - fpi_ssm_mark_failed(ssm, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Unexpected response subcommand")); - } else if (seq != upekdev->seq) { - fp_err("expected response to cmd seq=%02x, got response to %02x " - "in state %d", upekdev->seq, seq, - fpi_ssm_get_cur_state(ssm)); - fpi_ssm_mark_failed(ssm, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Unexpected sequence number in response")); - } else { - fpi_ssm_next_state(ssm); - } -} - -static void read28_0b_cb(FpDevice *dev, enum read_msg_type type, - guint8 seq, unsigned char subcmd, - unsigned char *data, size_t data_len, - void *user_data, GError *error) -{ - initsm_read_msg_response_cb((FpiSsm *) user_data, dev, type, seq, - 0x0b, subcmd, error); -} - -static void read28_0c_cb(FpDevice *dev, enum read_msg_type type, - guint8 seq, unsigned char subcmd, - unsigned char *data, size_t data_len, - void *user_data, GError *error) -{ - initsm_read_msg_response_cb((FpiSsm *) user_data, dev, type, seq, - 0x0c, subcmd, error); -} - -static void read28_08_cb(FpDevice *dev, enum read_msg_type type, - guint8 seq, unsigned char subcmd, - unsigned char *data, size_t data_len, - void *user_data, GError *error) -{ - initsm_read_msg_response_cb((FpiSsm *) user_data, dev, type, seq, - 0x08, subcmd, error); -} - -static void read28_07_cb(FpDevice *dev, enum read_msg_type type, - guint8 seq, unsigned char subcmd, - unsigned char *data, size_t data_len, - void *user_data, GError *error) -{ - initsm_read_msg_response_cb((FpiSsm *) user_data, dev, type, seq, - 0x07, subcmd, error); -} - -static void read28_06_cb(FpDevice *dev, enum read_msg_type type, - guint8 seq, unsigned char subcmd, - unsigned char *data, size_t data_len, - void *user_data, GError *error) -{ - initsm_read_msg_response_cb((FpiSsm *) user_data, dev, type, seq, - 0x06, subcmd, error); + if (error) + { + fpi_ssm_mark_failed (ssm, error); + } + else if (type != READ_MSG_RESPONSE) + { + fp_err ("expected response, got %d seq=%x in state %d", type, seq, + fpi_ssm_get_cur_state (ssm)); + fpi_ssm_mark_failed (ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Unexpected message type")); + } + else if (seq != upekdev->seq) + { + fp_warn ("expected response to subcmd 0x%02x, got response to %02x in " + "state %d", expect_subcmd, subcmd, + fpi_ssm_get_cur_state (ssm)); + fpi_ssm_mark_failed (ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Unexpected response subcommand")); + } + else if (seq != upekdev->seq) + { + fp_err ("expected response to cmd seq=%02x, got response to %02x " + "in state %d", upekdev->seq, seq, + fpi_ssm_get_cur_state (ssm)); + fpi_ssm_mark_failed (ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Unexpected sequence number in response")); + } + else + { + fpi_ssm_next_state (ssm); + } } static void -initsm_read_msg_cmd_cb(FpiSsm *ssm, - FpDevice *dev, - enum read_msg_type type, - guint8 seq, - guint8 expected_seq, - GError *error) +read28_0b_cb (FpDevice *dev, enum read_msg_type type, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, GError *error) { - FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); - - if (error) { - fpi_ssm_mark_failed(ssm, error); - return; - } else if (type != READ_MSG_CMD) { - fp_err("expected command, got %d seq=%x in state %d", type, seq, - fpi_ssm_get_cur_state(ssm)); - fpi_ssm_mark_failed(ssm, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Expected command but got response")); - return; - } - upekdev->seq = seq; - if (seq != expected_seq) { - fp_err("expected seq=%x, got %x in state %d", expected_seq, seq, - fpi_ssm_get_cur_state(ssm)); - fpi_ssm_mark_failed(ssm, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Got unexpected sequence number")); - return; - } - - fpi_ssm_next_state(ssm); -} - -static void read_msg05_cb(FpDevice *dev, enum read_msg_type type, - guint8 seq, unsigned char subcmd, - unsigned char *data, size_t data_len, - void *user_data, GError *error) -{ - initsm_read_msg_cmd_cb((FpiSsm *) user_data, dev, type, 5, seq, error); -} - -static void read_msg03_cb(FpDevice *dev, enum read_msg_type type, - guint8 seq, unsigned char subcmd, - unsigned char *data, size_t data_len, - void *user_data, GError *error) -{ - initsm_read_msg_cmd_cb((FpiSsm *) user_data, dev, type, 3, seq, error); + initsm_read_msg_response_cb ((FpiSsm *) user_data, dev, type, seq, + 0x0b, subcmd, error); } static void -initsm_read_msg_handler(FpiSsm *ssm, - FpDevice *dev, - read_msg_cb_fn callback) +read28_0c_cb (FpDevice *dev, enum read_msg_type type, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, GError *error) { - read_msg_async(dev, callback, ssm); + initsm_read_msg_response_cb ((FpiSsm *) user_data, dev, type, seq, + 0x0c, subcmd, error); } static void -initsm_send_msg28_handler(FpiSsm *ssm, - FpDevice *dev, - unsigned char subcmd, - const unsigned char *data, - guint16 innerlen) +read28_08_cb (FpDevice *dev, enum read_msg_type type, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, GError *error) { - FpiUsbTransfer *transfer; - - transfer = alloc_send_cmd28_transfer(dev, subcmd, data, innerlen); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); - fpi_usb_transfer_unref (transfer); + initsm_read_msg_response_cb ((FpiSsm *) user_data, dev, type, seq, + 0x08, subcmd, error); } -static void initsm_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) +static void +read28_07_cb (FpDevice *dev, enum read_msg_type type, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, GError *error) { - FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); - FpiUsbTransfer *transfer; - - switch (fpi_ssm_get_cur_state(ssm)) { - case WRITE_CTRL400: ; - transfer = fpi_usb_transfer_new(dev); - fpi_usb_transfer_fill_control(transfer, - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, - G_USB_DEVICE_REQUEST_TYPE_VENDOR, - G_USB_DEVICE_RECIPIENT_DEVICE, - 0x0c, 0x100, 0x0400, 1); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit(transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); - fpi_usb_transfer_unref(transfer); - break; - case READ_MSG03: - initsm_read_msg_handler(ssm, dev, read_msg03_cb); - break; - case SEND_RESP03: ; - transfer = alloc_send_cmd28_transfer(dev, ++upekdev->seq, init_resp03, sizeof(init_resp03)); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); - fpi_usb_transfer_unref (transfer); - break; - case READ_MSG05: - initsm_read_msg_handler(ssm, dev, read_msg05_cb); - break; - case SEND28_06: ; - unsigned char dummy28_06 = 0x04; - upekdev->seq = 0xf0; - initsm_send_msg28_handler(ssm, dev, 0x06, &dummy28_06, 1); - break; - case READ28_06: - initsm_read_msg_handler(ssm, dev, read28_06_cb); - break; - case SEND28_07: ; - unsigned char dummy28_07 = 0x04; - initsm_send_msg28_handler(ssm, dev, 0x07, &dummy28_07, 1); - break; - case READ28_07: - initsm_read_msg_handler(ssm, dev, read28_07_cb); - break; - case SEND28_08: - initsm_send_msg28_handler(ssm, dev, 0x08, init28_08, sizeof(init28_08)); - break; - case READ28_08: - initsm_read_msg_handler(ssm, dev, read28_08_cb); - break; - case SEND28_0C: - initsm_send_msg28_handler(ssm, dev, 0x0c, init28_0c, sizeof(init28_0c)); - break; - case READ28_0C: - initsm_read_msg_handler(ssm, dev, read28_0c_cb); - break; - case SEND28_0B: - initsm_send_msg28_handler(ssm, dev, 0x0b, init28_0b, sizeof(init28_0b)); - break; - case READ28_0B: - initsm_read_msg_handler(ssm, dev, read28_0b_cb); - break; - } + initsm_read_msg_response_cb ((FpiSsm *) user_data, dev, type, seq, + 0x07, subcmd, error); } -static FpiSsm *initsm_new(FpDevice *dev) +static void +read28_06_cb (FpDevice *dev, enum read_msg_type type, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, GError *error) { - return fpi_ssm_new(dev, initsm_run_state, INITSM_NUM_STATES, NULL); + initsm_read_msg_response_cb ((FpiSsm *) user_data, dev, type, seq, + 0x06, subcmd, error); +} + +static void +initsm_read_msg_cmd_cb (FpiSsm *ssm, + FpDevice *dev, + enum read_msg_type type, + guint8 seq, + guint8 expected_seq, + GError *error) +{ + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev); + + if (error) + { + fpi_ssm_mark_failed (ssm, error); + return; + } + else if (type != READ_MSG_CMD) + { + fp_err ("expected command, got %d seq=%x in state %d", type, seq, + fpi_ssm_get_cur_state (ssm)); + fpi_ssm_mark_failed (ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Expected command but got response")); + return; + } + upekdev->seq = seq; + if (seq != expected_seq) + { + fp_err ("expected seq=%x, got %x in state %d", expected_seq, seq, + fpi_ssm_get_cur_state (ssm)); + fpi_ssm_mark_failed (ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Got unexpected sequence number")); + return; + } + + fpi_ssm_next_state (ssm); +} + +static void +read_msg05_cb (FpDevice *dev, enum read_msg_type type, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, GError *error) +{ + initsm_read_msg_cmd_cb ((FpiSsm *) user_data, dev, type, 5, seq, error); +} + +static void +read_msg03_cb (FpDevice *dev, enum read_msg_type type, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, GError *error) +{ + initsm_read_msg_cmd_cb ((FpiSsm *) user_data, dev, type, 3, seq, error); +} + +static void +initsm_read_msg_handler (FpiSsm *ssm, + FpDevice *dev, + read_msg_cb_fn callback) +{ + read_msg_async (dev, callback, ssm); +} + +static void +initsm_send_msg28_handler (FpiSsm *ssm, + FpDevice *dev, + unsigned char subcmd, + const unsigned char *data, + guint16 innerlen) +{ + FpiUsbTransfer *transfer; + + transfer = alloc_send_cmd28_transfer (dev, subcmd, data, innerlen); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); + fpi_usb_transfer_unref (transfer); +} + +static void +initsm_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +{ + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev); + FpiUsbTransfer *transfer; + + switch (fpi_ssm_get_cur_state (ssm)) + { + case WRITE_CTRL400:; + transfer = fpi_usb_transfer_new (dev); + fpi_usb_transfer_fill_control (transfer, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + 0x0c, 0x100, 0x0400, 1); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); + fpi_usb_transfer_unref (transfer); + break; + + case READ_MSG03: + initsm_read_msg_handler (ssm, dev, read_msg03_cb); + break; + + case SEND_RESP03:; + transfer = alloc_send_cmd28_transfer (dev, ++upekdev->seq, init_resp03, sizeof (init_resp03)); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); + fpi_usb_transfer_unref (transfer); + break; + + case READ_MSG05: + initsm_read_msg_handler (ssm, dev, read_msg05_cb); + break; + + case SEND28_06:; + unsigned char dummy28_06 = 0x04; + upekdev->seq = 0xf0; + initsm_send_msg28_handler (ssm, dev, 0x06, &dummy28_06, 1); + break; + + case READ28_06: + initsm_read_msg_handler (ssm, dev, read28_06_cb); + break; + + case SEND28_07:; + unsigned char dummy28_07 = 0x04; + initsm_send_msg28_handler (ssm, dev, 0x07, &dummy28_07, 1); + break; + + case READ28_07: + initsm_read_msg_handler (ssm, dev, read28_07_cb); + break; + + case SEND28_08: + initsm_send_msg28_handler (ssm, dev, 0x08, init28_08, sizeof (init28_08)); + break; + + case READ28_08: + initsm_read_msg_handler (ssm, dev, read28_08_cb); + break; + + case SEND28_0C: + initsm_send_msg28_handler (ssm, dev, 0x0c, init28_0c, sizeof (init28_0c)); + break; + + case READ28_0C: + initsm_read_msg_handler (ssm, dev, read28_0c_cb); + break; + + case SEND28_0B: + initsm_send_msg28_handler (ssm, dev, 0x0b, init28_0b, sizeof (init28_0b)); + break; + + case READ28_0B: + initsm_read_msg_handler (ssm, dev, read28_0b_cb); + break; + } +} + +static FpiSsm * +initsm_new (FpDevice *dev) +{ + return fpi_ssm_new (dev, initsm_run_state, INITSM_NUM_STATES, NULL); } enum deinitsm_states { - SEND_RESP07 = 0, - READ_MSG01, - DEINITSM_NUM_STATES, + SEND_RESP07 = 0, + READ_MSG01, + DEINITSM_NUM_STATES, }; -static void read_msg01_cb(FpDevice *dev, enum read_msg_type type, - guint8 seq, unsigned char subcmd, - unsigned char *data, size_t data_len, - void *user_data, GError *error) +static void +read_msg01_cb (FpDevice *dev, enum read_msg_type type, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, GError *error) { - FpiSsm *ssm = user_data; - FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); + FpiSsm *ssm = user_data; + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev); - if (error) { - fpi_ssm_mark_failed(ssm, error); - return; - } else if (type != READ_MSG_CMD) { - fp_err("expected command, got %d seq=%x", type, seq); - fpi_ssm_mark_failed(ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Expected command but got response")); - return; - } - upekdev->seq = seq; - if (seq != 1) { - fp_err("expected seq=1, got %x", seq); - fpi_ssm_mark_failed(ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Got wrong sequence number")); - return; - } + if (error) + { + fpi_ssm_mark_failed (ssm, error); + return; + } + else if (type != READ_MSG_CMD) + { + fp_err ("expected command, got %d seq=%x", type, seq); + fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Expected command but got response")); + return; + } + upekdev->seq = seq; + if (seq != 1) + { + fp_err ("expected seq=1, got %x", seq); + fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Got wrong sequence number")); + return; + } - fpi_ssm_next_state(ssm); + fpi_ssm_next_state (ssm); } -static void deinitsm_state_handler(FpiSsm *ssm, FpDevice *dev, - void *user_data) +static void +deinitsm_state_handler (FpiSsm *ssm, FpDevice *dev, + void *user_data) { - switch (fpi_ssm_get_cur_state(ssm)) { - case SEND_RESP07: ; - FpiUsbTransfer *transfer; - unsigned char dummy = 0; + switch (fpi_ssm_get_cur_state (ssm)) + { + case SEND_RESP07:; + FpiUsbTransfer *transfer; + unsigned char dummy = 0; - transfer = alloc_send_cmdresponse_transfer(dev, 0x07, &dummy, 1); - transfer->short_is_error = TRUE; - transfer->ssm = ssm; - fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); - fpi_usb_transfer_unref (transfer); - break; - case READ_MSG01: ; - read_msg_async(dev, read_msg01_cb, ssm); - break; - } + transfer = alloc_send_cmdresponse_transfer (dev, 0x07, &dummy, 1); + transfer->short_is_error = TRUE; + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); + fpi_usb_transfer_unref (transfer); + break; + + case READ_MSG01:; + read_msg_async (dev, read_msg01_cb, ssm); + break; + } } -static void initsm_done(FpiSsm *ssm, FpDevice *dev, void *user_data, GError *error) +static void +initsm_done (FpiSsm *ssm, FpDevice *dev, void *user_data, GError *error) { - if (error) - g_usb_device_release_interface (fpi_device_get_usb_device(dev), 0, 0, NULL); + if (error) + g_usb_device_release_interface (fpi_device_get_usb_device (dev), 0, 0, NULL); - fpi_device_open_complete (dev, error); + fpi_device_open_complete (dev, error); } -static FpiSsm *deinitsm_new(FpDevice *dev, void *user_data) +static FpiSsm * +deinitsm_new (FpDevice *dev, void *user_data) { - return fpi_ssm_new(dev, deinitsm_state_handler, DEINITSM_NUM_STATES, user_data); + return fpi_ssm_new (dev, deinitsm_state_handler, DEINITSM_NUM_STATES, user_data); } -static void dev_init(FpDevice *dev) +static void +dev_init (FpDevice *dev) { - FpiSsm *ssm; - GError *error = NULL; - FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev); + FpiSsm *ssm; + GError *error = NULL; + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev); - if (!g_usb_device_claim_interface (fpi_device_get_usb_device(dev), 0, 0, &error)) { - fpi_device_open_complete (dev, error); - return; - } + if (!g_usb_device_claim_interface (fpi_device_get_usb_device (dev), 0, 0, &error)) + { + fpi_device_open_complete (dev, error); + return; + } - upekdev->seq = 0xf0; /* incremented to 0x00 before first cmd */ + upekdev->seq = 0xf0; /* incremented to 0x00 before first cmd */ - ssm = fpi_ssm_new(dev, initsm_run_state, INITSM_NUM_STATES, NULL); - fpi_ssm_start (ssm, initsm_done); + ssm = fpi_ssm_new (dev, initsm_run_state, INITSM_NUM_STATES, NULL); + fpi_ssm_start (ssm, initsm_done); } -static void deinitsm_done(FpiSsm *ssm, FpDevice *dev, void *user_data, GError *error) +static void +deinitsm_done (FpiSsm *ssm, FpDevice *dev, void *user_data, GError *error) { - g_usb_device_release_interface (fpi_device_get_usb_device(dev), 0, 0, NULL); + g_usb_device_release_interface (fpi_device_get_usb_device (dev), 0, 0, NULL); - fpi_device_close_complete (dev, error); + fpi_device_close_complete (dev, error); } -static void dev_exit(FpDevice *dev) +static void +dev_exit (FpDevice *dev) { - FpiSsm *ssm; + FpiSsm *ssm; - ssm = fpi_ssm_new(dev, deinitsm_state_handler, DEINITSM_NUM_STATES, NULL); - fpi_ssm_start (ssm, deinitsm_done); + ssm = fpi_ssm_new (dev, deinitsm_state_handler, DEINITSM_NUM_STATES, NULL); + fpi_ssm_start (ssm, deinitsm_done); } static const unsigned char enroll_init[] = { - 0x02, 0xc0, 0xd4, 0x01, 0x00, 0x04, 0x00, 0x08 + 0x02, 0xc0, 0xd4, 0x01, 0x00, 0x04, 0x00, 0x08 }; static const unsigned char scan_comp[] = { - 0x12, 0xff, 0xff, 0xff, 0xff /* scan completion, prefixes print data */ + 0x12, 0xff, 0xff, 0xff, 0xff /* scan completion, prefixes print data */ }; /* used for enrollment and verification */ static const unsigned char poll_data[] = { 0x30, 0x01 }; enum enroll_start_sm_states { - RUN_INITSM = 0, - ENROLL_INIT, - READ_ENROLL_MSG28, - ENROLL_START_NUM_STATES, + RUN_INITSM = 0, + ENROLL_INIT, + READ_ENROLL_MSG28, + ENROLL_START_NUM_STATES, }; -static void enroll_start_sm_cb_msg28(FpDevice *dev, - enum read_msg_type type, guint8 seq, - unsigned char subcmd, - unsigned char *data, size_t data_len, - void *user_data, - GError *error) +static void +enroll_start_sm_cb_msg28 (FpDevice *dev, + enum read_msg_type type, guint8 seq, + unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, + GError *error) { - FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); - FpiSsm *ssm = user_data; + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev); + FpiSsm *ssm = user_data; - if (error) { - fpi_ssm_mark_failed(ssm, error); - } - if (type != READ_MSG_RESPONSE) { - fp_err("expected response, got %d seq=%x", type, seq); - fpi_ssm_mark_failed(ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Unexpected response type")); - } else if (subcmd != 0) { - fp_warn("expected response to subcmd 0, got response to %02x", - subcmd); - fpi_ssm_mark_failed(ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Got response to wrong subcommand")); - } else if (seq != upekdev->seq) { - fp_err("expected response to cmd seq=%02x, got response to %02x", - upekdev->seq, seq); - fpi_ssm_mark_failed(ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Got response with wrong sequence number")); - } else { - fpi_ssm_next_state(ssm); - } + if (error) + fpi_ssm_mark_failed (ssm, error); + if (type != READ_MSG_RESPONSE) + { + fp_err ("expected response, got %d seq=%x", type, seq); + fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Unexpected response type")); + } + else if (subcmd != 0) + { + fp_warn ("expected response to subcmd 0, got response to %02x", + subcmd); + fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Got response to wrong subcommand")); + } + else if (seq != upekdev->seq) + { + fp_err ("expected response to cmd seq=%02x, got response to %02x", + upekdev->seq, seq); + fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Got response with wrong sequence number")); + } + else + { + fpi_ssm_next_state (ssm); + } } -static void enroll_start_sm_run_state(FpiSsm *ssm, FpDevice *dev, - void *user_data) +static void +enroll_start_sm_run_state (FpiSsm *ssm, FpDevice *dev, + void *user_data) { - switch (fpi_ssm_get_cur_state(ssm)) { - case RUN_INITSM: ; - FpiSsm *initsm = initsm_new(dev); - fpi_ssm_start_subsm(ssm, initsm); - break; - case ENROLL_INIT: ; - FpiUsbTransfer *transfer; - transfer = alloc_send_cmd28_transfer(dev, 0x02, enroll_init, sizeof(enroll_init)); - transfer->short_is_error = TRUE; - transfer->ssm = ssm; + switch (fpi_ssm_get_cur_state (ssm)) + { + case RUN_INITSM:; + FpiSsm *initsm = initsm_new (dev); + fpi_ssm_start_subsm (ssm, initsm); + break; - fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); - fpi_usb_transfer_unref (transfer); - break; - case READ_ENROLL_MSG28: ; - /* FIXME: protocol misunderstanding here. device receives response - * to subcmd 0 after submitting subcmd 2? */ - /* actually this is probably a poll response? does the above cmd - * include a 30 01 poll somewhere? */ - read_msg_async(dev, enroll_start_sm_cb_msg28, ssm); - break; - } + case ENROLL_INIT:; + FpiUsbTransfer *transfer; + transfer = alloc_send_cmd28_transfer (dev, 0x02, enroll_init, sizeof (enroll_init)); + transfer->short_is_error = TRUE; + transfer->ssm = ssm; + + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); + fpi_usb_transfer_unref (transfer); + break; + + case READ_ENROLL_MSG28:; + /* FIXME: protocol misunderstanding here. device receives response + * to subcmd 0 after submitting subcmd 2? */ + /* actually this is probably a poll response? does the above cmd + * include a 30 01 poll somewhere? */ + read_msg_async (dev, enroll_start_sm_cb_msg28, ssm); + break; + } } -typedef struct { - FpPrint *print; - GError *error; +typedef struct +{ + FpPrint *print; + GError *error; } EnrollStopData; -static void enroll_stop_deinit_cb(FpiSsm *ssm, FpDevice *dev, - void *user_data, GError *error) +static void +enroll_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, + void *user_data, GError *error) { - EnrollStopData *data = user_data; + EnrollStopData *data = user_data; - /* don't really care about errors */ - if (error) { - fp_warn ("Error deinitializing: %s", error->message); - g_error_free (error); - } + /* don't really care about errors */ + if (error) + { + fp_warn ("Error deinitializing: %s", error->message); + g_error_free (error); + } - fpi_device_enroll_complete (dev, data->print, data->error); - g_free (data); - fpi_ssm_free(ssm); + fpi_device_enroll_complete (dev, data->print, data->error); + g_free (data); + fpi_ssm_free (ssm); } -static void do_enroll_stop(FpDevice *dev, FpPrint *print, GError *error) +static void +do_enroll_stop (FpDevice *dev, FpPrint *print, GError *error) { - EnrollStopData *data = g_new0(EnrollStopData, 1); - FpiSsm *ssm = deinitsm_new(dev, data); + EnrollStopData *data = g_new0 (EnrollStopData, 1); + FpiSsm *ssm = deinitsm_new (dev, data); - data->print = print; - data->error = error; + data->print = print; + data->error = error; - fpi_ssm_start(ssm, enroll_stop_deinit_cb); + fpi_ssm_start (ssm, enroll_stop_deinit_cb); } -static void enroll_iterate(FpDevice *dev); +static void enroll_iterate (FpDevice *dev); -static void e_handle_resp00(FpDevice *dev, unsigned char *data, - size_t data_len) +static void +e_handle_resp00 (FpDevice *dev, unsigned char *data, + size_t data_len) { - FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); - unsigned char status; + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev); + unsigned char status; - if (data_len != 14) { - fp_err("received 3001 poll response of %lu bytes?", data_len); - do_enroll_stop (dev, NULL, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "received 3001 response with wrong length")); - return; - } + if (data_len != 14) + { + fp_err ("received 3001 poll response of %lu bytes?", data_len); + do_enroll_stop (dev, NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "received 3001 response with wrong length")); + return; + } - status = data[5]; - fp_dbg("poll result = %02x", status); + status = data[5]; + fp_dbg ("poll result = %02x", status); - switch (status) { - case 0x0c: - case 0x0d: - case 0x0e: - case 0x26: - case 0x27: - case 0x2e: - /* if we previously completed a non-last enrollment stage, we'll - * get this code to indicate successful stage completion */ - if (upekdev->enroll_passed) { - upekdev->enroll_passed = FALSE; - upekdev->enroll_stage += 1; + switch (status) + { + case 0x0c: + case 0x0d: + case 0x0e: + case 0x26: + case 0x27: + case 0x2e: + /* if we previously completed a non-last enrollment stage, we'll + * get this code to indicate successful stage completion */ + if (upekdev->enroll_passed) + { + upekdev->enroll_passed = FALSE; + upekdev->enroll_stage += 1; - fpi_device_enroll_progress (dev, upekdev->enroll_stage, NULL, NULL); - } - /* otherwise it just means "no news" so we poll again */ - break; - case 0x1c: /* FIXME what does this one mean? */ - case 0x0b: /* FIXME what does this one mean? */ - case 0x23: /* FIXME what does this one mean? */ - fpi_device_enroll_progress (dev, - upekdev->enroll_stage, - NULL, - fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); - break; - case 0x0f: /* scan taking too long, remove finger and try again */ - fpi_device_enroll_progress (dev, - upekdev->enroll_stage, - NULL, - fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER)); - break; - case 0x1e: /* swipe too short */ - fpi_device_enroll_progress (dev, - upekdev->enroll_stage, - NULL, - fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT)); - break; - case 0x24: /* finger not centered */ - fpi_device_enroll_progress (dev, - upekdev->enroll_stage, - NULL, - fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER)); - break; - case 0x20: - /* finger scanned successfully */ - /* need to look at the next poll result to determine if enrollment is - * complete or not */ - upekdev->enroll_passed = TRUE; - break; - case 0x00: /* enrollment complete */ - /* we can now expect the enrollment data on the next poll, so we - * have nothing to do here */ - break; - default: - do_enroll_stop (dev, - NULL, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Unrecognised scan status code")); - /* Stop iteration. */ - return; - } - enroll_iterate(dev); + fpi_device_enroll_progress (dev, upekdev->enroll_stage, NULL, NULL); + } + /* otherwise it just means "no news" so we poll again */ + break; - /* FIXME: need to extend protocol research to handle the case when - * enrolment fails, e.g. you scan a different finger on each stage */ - /* FIXME: should do proper tracking of when we expect cmd0 results and - * cmd2 results and enforce it */ + case 0x1c: /* FIXME what does this one mean? */ + case 0x0b: /* FIXME what does this one mean? */ + case 0x23: /* FIXME what does this one mean? */ + fpi_device_enroll_progress (dev, + upekdev->enroll_stage, + NULL, + fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); + break; + + case 0x0f: /* scan taking too long, remove finger and try again */ + fpi_device_enroll_progress (dev, + upekdev->enroll_stage, + NULL, + fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER)); + break; + + case 0x1e: /* swipe too short */ + fpi_device_enroll_progress (dev, + upekdev->enroll_stage, + NULL, + fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT)); + break; + + case 0x24: /* finger not centered */ + fpi_device_enroll_progress (dev, + upekdev->enroll_stage, + NULL, + fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER)); + break; + + case 0x20: + /* finger scanned successfully */ + /* need to look at the next poll result to determine if enrollment is + * complete or not */ + upekdev->enroll_passed = TRUE; + break; + + case 0x00: /* enrollment complete */ + /* we can now expect the enrollment data on the next poll, so we + * have nothing to do here */ + break; + + default: + do_enroll_stop (dev, + NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Unrecognised scan status code")); + /* Stop iteration. */ + return; + } + enroll_iterate (dev); + + /* FIXME: need to extend protocol research to handle the case when + * enrolment fails, e.g. you scan a different finger on each stage */ + /* FIXME: should do proper tracking of when we expect cmd0 results and + * cmd2 results and enforce it */ } -static void e_handle_resp02(FpDevice *dev, unsigned char *data, - size_t data_len) +static void +e_handle_resp02 (FpDevice *dev, unsigned char *data, + size_t data_len) { - FpPrint *print = NULL; - GError *error = NULL; + FpPrint *print = NULL; + GError *error = NULL; - if (data_len < sizeof(scan_comp)) { - fp_err("fingerprint data too short (%lu bytes)", data_len); - error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "fingerprint data too short"); - } else if (memcmp(data, scan_comp, sizeof(scan_comp)) != 0) { - fp_err("unrecognised data prefix %x %x %x %x %x", - data[0], data[1], data[2], data[3], data[4]); - error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "fingerprint data has wrong prefix"); - } else { - GVariant *fp_data; - print = fp_print_new (dev); + if (data_len < sizeof (scan_comp)) + { + fp_err ("fingerprint data too short (%lu bytes)", data_len); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "fingerprint data too short"); + } + else if (memcmp (data, scan_comp, sizeof (scan_comp)) != 0) + { + fp_err ("unrecognised data prefix %x %x %x %x %x", + data[0], data[1], data[2], data[3], data[4]); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "fingerprint data has wrong prefix"); + } + else + { + GVariant *fp_data; + print = fp_print_new (dev); - fpi_device_get_enroll_data (dev, &print); + fpi_device_get_enroll_data (dev, &print); - fp_data = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - data + sizeof(scan_comp), - data_len - sizeof(scan_comp), - 1); + fp_data = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + data + sizeof (scan_comp), + data_len - sizeof (scan_comp), + 1); - g_object_set (print, "fp-data", fp_data, NULL); - g_object_ref (print); - } + g_object_set (print, "fp-data", fp_data, NULL); + g_object_ref (print); + } - do_enroll_stop (dev, print, error); + do_enroll_stop (dev, print, error); } -static void enroll_iterate_msg_cb(FpDevice *dev, - enum read_msg_type msgtype, guint8 seq, - unsigned char subcmd, - unsigned char *data, size_t data_len, - void *user_data, - GError *error) +static void +enroll_iterate_msg_cb (FpDevice *dev, + enum read_msg_type msgtype, guint8 seq, + unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, + GError *error) { - if (error) { - do_enroll_stop (dev, NULL, error); - return; - } else if (msgtype != READ_MSG_RESPONSE) { - fp_err("expected response, got %d seq=%x", msgtype, seq); - do_enroll_stop (dev, NULL, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Expected message response, not command")); - return; - } - if (subcmd == 0) { - e_handle_resp00(dev, data, data_len); - } else if (subcmd == 2) { - e_handle_resp02(dev, data, data_len); - } else { - fp_err("unexpected subcmd %d", subcmd); - do_enroll_stop (dev, NULL, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Unexpected subcommand")); - } + if (error) + { + do_enroll_stop (dev, NULL, error); + return; + } + else if (msgtype != READ_MSG_RESPONSE) + { + fp_err ("expected response, got %d seq=%x", msgtype, seq); + do_enroll_stop (dev, NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Expected message response, not command")); + return; + } + if (subcmd == 0) + { + e_handle_resp00 (dev, data, data_len); + } + else if (subcmd == 2) + { + e_handle_resp02 (dev, data, data_len); + } + else + { + fp_err ("unexpected subcmd %d", subcmd); + do_enroll_stop (dev, NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Unexpected subcommand")); + } } -static void enroll_iterate_cmd_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +enroll_iterate_cmd_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - if (error) { - do_enroll_stop(device, NULL, error); - } else { - read_msg_async(device, enroll_iterate_msg_cb, NULL); - } + if (error) + do_enroll_stop (device, NULL, error); + else + read_msg_async (device, enroll_iterate_msg_cb, NULL); } -static void enroll_iterate(FpDevice *dev) +static void +enroll_iterate (FpDevice *dev) { - FpiUsbTransfer *transfer; + FpiUsbTransfer *transfer; - if (fpi_device_action_is_cancelled (dev)) { - do_enroll_stop(dev, NULL, g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled")); - return; - } + if (fpi_device_action_is_cancelled (dev)) + { + do_enroll_stop (dev, NULL, g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled")); + return; + } - transfer = alloc_send_cmd28_transfer(dev, 0x00, - poll_data, sizeof(poll_data)); - transfer->short_is_error = TRUE; + transfer = alloc_send_cmd28_transfer (dev, 0x00, + poll_data, sizeof (poll_data)); + transfer->short_is_error = TRUE; - fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, enroll_iterate_cmd_cb, NULL); - fpi_usb_transfer_unref (transfer); + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, enroll_iterate_cmd_cb, NULL); + fpi_usb_transfer_unref (transfer); } -static void enroll_started(FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +static void +enroll_started (FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - if (error) { - do_enroll_stop (dev, NULL, error); - } else { - enroll_iterate(dev); - } + if (error) + do_enroll_stop (dev, NULL, error); + else + enroll_iterate (dev); - fpi_ssm_free(ssm); + fpi_ssm_free (ssm); } -static void enroll(FpDevice *dev) +static void +enroll (FpDevice *dev) { - FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev); - /* do_init state machine first */ - FpiSsm *ssm = fpi_ssm_new(dev, enroll_start_sm_run_state, - ENROLL_START_NUM_STATES, NULL); + /* do_init state machine first */ + FpiSsm *ssm = fpi_ssm_new (dev, enroll_start_sm_run_state, + ENROLL_START_NUM_STATES, NULL); - upekdev->enroll_passed = FALSE; - upekdev->enroll_stage = 0; - fpi_ssm_start(ssm, enroll_started); + upekdev->enroll_passed = FALSE; + upekdev->enroll_stage = 0; + fpi_ssm_start (ssm, enroll_started); } -typedef struct { - FpiMatchResult res; - GError *error; +typedef struct +{ + FpiMatchResult res; + GError *error; } VerifyStopData; -static void verify_stop_deinit_cb(FpiSsm *ssm, FpDevice *dev, - void *user_data, GError *error) +static void +verify_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, + void *user_data, GError *error) { - VerifyStopData *data = user_data; + VerifyStopData *data = user_data; - if (error) { - fp_warn ("Error deinitializing: %s", error->message); - g_error_free (error); - } + if (error) + { + fp_warn ("Error deinitializing: %s", error->message); + g_error_free (error); + } - fpi_device_verify_complete (dev, data->res, NULL, data->error); - g_free (data); - fpi_ssm_free(ssm); + fpi_device_verify_complete (dev, data->res, NULL, data->error); + g_free (data); + fpi_ssm_free (ssm); } -static void do_verify_stop(FpDevice *dev, FpiMatchResult res, GError *error) +static void +do_verify_stop (FpDevice *dev, FpiMatchResult res, GError *error) { - VerifyStopData *data = g_new0(VerifyStopData, 1); - FpiSsm *ssm = deinitsm_new(dev, data); + VerifyStopData *data = g_new0 (VerifyStopData, 1); + FpiSsm *ssm = deinitsm_new (dev, data); - data->res = res; - data->error = error; + data->res = res; + data->error = error; - fpi_ssm_start(ssm, verify_stop_deinit_cb); + fpi_ssm_start (ssm, verify_stop_deinit_cb); } static const unsigned char verify_hdr[] = { - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xc0, 0xd4, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x00 + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xd4, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00 }; enum { - VERIFY_RUN_INITSM = 0, - VERIFY_INIT, - VERIFY_NUM_STATES, + VERIFY_RUN_INITSM = 0, + VERIFY_INIT, + VERIFY_NUM_STATES, }; -static void verify_start_sm_run_state(FpiSsm *ssm, FpDevice *dev, - void *user_data) +static void +verify_start_sm_run_state (FpiSsm *ssm, FpDevice *dev, + void *user_data) { - FpPrint *print; - g_autoptr(GVariant) fp_data = NULL; - FpiUsbTransfer *transfer; - gsize data_len; - const guint8 *data; - guint8 *msg; - gsize msg_len; + FpPrint *print; - switch (fpi_ssm_get_cur_state(ssm)) { - case VERIFY_RUN_INITSM: ; - FpiSsm *initsm = initsm_new(dev); - fpi_ssm_start_subsm(ssm, initsm); - break; - case VERIFY_INIT: - fpi_device_get_verify_data (dev, &print); - g_object_get (dev, "fp-data", &fp_data, NULL); + g_autoptr(GVariant) fp_data = NULL; + FpiUsbTransfer *transfer; + gsize data_len; + const guint8 *data; + guint8 *msg; + gsize msg_len; - data = g_variant_get_fixed_array (fp_data, &data_len, 1); + switch (fpi_ssm_get_cur_state (ssm)) + { + case VERIFY_RUN_INITSM:; + FpiSsm *initsm = initsm_new (dev); + fpi_ssm_start_subsm (ssm, initsm); + break; - msg_len = sizeof(verify_hdr) + data_len; - msg = g_malloc (msg_len); + case VERIFY_INIT: + fpi_device_get_verify_data (dev, &print); + g_object_get (dev, "fp-data", &fp_data, NULL); - memcpy(msg, verify_hdr, sizeof(verify_hdr)); - memcpy(msg + sizeof(verify_hdr), data, data_len); + data = g_variant_get_fixed_array (fp_data, &data_len, 1); - transfer = alloc_send_cmd28_transfer(dev, 0x03, data, data_len); + msg_len = sizeof (verify_hdr) + data_len; + msg = g_malloc (msg_len); - g_free(msg); + memcpy (msg, verify_hdr, sizeof (verify_hdr)); + memcpy (msg + sizeof (verify_hdr), data, data_len); - transfer->short_is_error = TRUE; - transfer->ssm = ssm; - fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); - fpi_usb_transfer_unref (transfer); + transfer = alloc_send_cmd28_transfer (dev, 0x03, data, data_len); - break; - } + g_free (msg); + + transfer->short_is_error = TRUE; + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, fpi_ssm_usb_transfer_cb, NULL); + fpi_usb_transfer_unref (transfer); + + break; + } } -static void verify_iterate(FpDevice *dev); +static void verify_iterate (FpDevice *dev); -static void v_handle_resp00(FpDevice *dev, unsigned char *data, - size_t data_len) +static void +v_handle_resp00 (FpDevice *dev, unsigned char *data, + size_t data_len) { - unsigned char status; - GError *error = NULL; + unsigned char status; + GError *error = NULL; - if (data_len != 14) { - fp_warn("received 3001 poll response of %lu bytes?", data_len); - error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); - goto out; - } + if (data_len != 14) + { + fp_warn ("received 3001 poll response of %lu bytes?", data_len); + error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); + goto out; + } - status = data[5]; - fp_dbg("poll result = %02x", status); + status = data[5]; + fp_dbg ("poll result = %02x", status); - /* These codes indicate that we're waiting for a finger scan, so poll - * again */ - switch (status) { - case 0x0c: /* no news, poll again */ - break; - case 0x20: - fp_dbg("processing scan for verification"); - break; - case 0x00: - fp_dbg("good image"); - break; - case 0x1c: /* FIXME what does this one mean? */ - case 0x0b: /* FIXME what does this one mean? */ - case 0x23: /* FIXME what does this one mean? */ - error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); - break; - case 0x0f: /* scan taking too long, remove finger and try again */ - error = fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER); - break; - case 0x1e: /* swipe too short */ - error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT); - break; - case 0x24: /* finger not centered */ - error = fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER); - break; - default: - fp_err("unrecognised verify status code %02x", status); - error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); - } + /* These codes indicate that we're waiting for a finger scan, so poll + * again */ + switch (status) + { + case 0x0c: /* no news, poll again */ + break; + + case 0x20: + fp_dbg ("processing scan for verification"); + break; + + case 0x00: + fp_dbg ("good image"); + break; + + case 0x1c: /* FIXME what does this one mean? */ + case 0x0b: /* FIXME what does this one mean? */ + case 0x23: /* FIXME what does this one mean? */ + error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); + break; + + case 0x0f: /* scan taking too long, remove finger and try again */ + error = fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER); + break; + + case 0x1e: /* swipe too short */ + error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT); + break; + + case 0x24: /* finger not centered */ + error = fpi_device_retry_new (FP_DEVICE_RETRY_CENTER_FINGER); + break; + + default: + fp_err ("unrecognised verify status code %02x", status); + error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); + } out: - if (error) - do_verify_stop (dev, FPI_MATCH_ERROR, error); - else - verify_iterate(dev); + if (error) + do_verify_stop (dev, FPI_MATCH_ERROR, error); + else + verify_iterate (dev); } -static void v_handle_resp03(FpDevice *dev, unsigned char *data, - size_t data_len) +static void +v_handle_resp03 (FpDevice *dev, unsigned char *data, + size_t data_len) { - FpiMatchResult r; - GError *error = NULL; + FpiMatchResult r; + GError *error = NULL; - if (data_len < 2) { - fp_warn("verify result abnormally short!"); - r = FPI_MATCH_ERROR; - error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); - } else if (data[0] != 0x12) { - fp_warn("unexpected verify header byte %02x", data[0]); - r = FPI_MATCH_ERROR; - error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); - } else if (data[1] == 0x00) { - r = FPI_MATCH_FAIL; - } else if (data[1] == 0x01) { - r = FPI_MATCH_SUCCESS; - } else { - fp_warn("unrecognised verify result %02x", data[1]); - r = FPI_MATCH_ERROR; - error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); - } - do_verify_stop(dev, r, error); + if (data_len < 2) + { + fp_warn ("verify result abnormally short!"); + r = FPI_MATCH_ERROR; + error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); + } + else if (data[0] != 0x12) + { + fp_warn ("unexpected verify header byte %02x", data[0]); + r = FPI_MATCH_ERROR; + error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); + } + else if (data[1] == 0x00) + { + r = FPI_MATCH_FAIL; + } + else if (data[1] == 0x01) + { + r = FPI_MATCH_SUCCESS; + } + else + { + fp_warn ("unrecognised verify result %02x", data[1]); + r = FPI_MATCH_ERROR; + error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO); + } + do_verify_stop (dev, r, error); } -static void verify_rd2800_cb(FpDevice *dev, enum read_msg_type msgtype, - guint8 seq, unsigned char subcmd, - unsigned char *data, size_t data_len, - void *user_data, - GError *error) +static void +verify_rd2800_cb (FpDevice *dev, enum read_msg_type msgtype, + guint8 seq, unsigned char subcmd, + unsigned char *data, size_t data_len, + void *user_data, + GError *error) { - FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev); - if (error) { - do_verify_stop (dev, FPI_MATCH_ERROR, error); - return; - } + if (error) + { + do_verify_stop (dev, FPI_MATCH_ERROR, error); + return; + } - if (msgtype != READ_MSG_RESPONSE) { - fp_warn("expected response, got %d seq=%x", msgtype, seq); - do_verify_stop (dev, - FPI_MATCH_ERROR, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Expected message response")); - return; - } + if (msgtype != READ_MSG_RESPONSE) + { + fp_warn ("expected response, got %d seq=%x", msgtype, seq); + do_verify_stop (dev, + FPI_MATCH_ERROR, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Expected message response")); + return; + } - if (seq != upekdev->seq) { - fp_warn("expected response to cmd seq=%02x, got response to %02x", - upekdev->seq, seq); - do_verify_stop (dev, - FPI_MATCH_ERROR, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Response hat wrong command sequence")); - return; - } + if (seq != upekdev->seq) + { + fp_warn ("expected response to cmd seq=%02x, got response to %02x", + upekdev->seq, seq); + do_verify_stop (dev, + FPI_MATCH_ERROR, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Response hat wrong command sequence")); + return; + } - if (subcmd == 0) - v_handle_resp00(dev, data, data_len); - else if (subcmd == 3) - v_handle_resp03(dev, data, data_len); - else - do_verify_stop (dev, - FPI_MATCH_ERROR, - fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, - "Response had wrong subcommand type")); + if (subcmd == 0) + { + v_handle_resp00 (dev, data, data_len); + } + else if (subcmd == 3) + { + v_handle_resp03 (dev, data, data_len); + } + else + { + do_verify_stop (dev, + FPI_MATCH_ERROR, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Response had wrong subcommand type")); + } } -static void verify_wr2800_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +verify_wr2800_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - if (error) { - do_verify_stop (device, - FPI_MATCH_ERROR, - error); - } else { - read_msg_async(device, verify_rd2800_cb, NULL); - } + if (error) + { + do_verify_stop (device, + FPI_MATCH_ERROR, + error); + } + else + { + read_msg_async (device, verify_rd2800_cb, NULL); + } } -static void verify_iterate(FpDevice *dev) +static void +verify_iterate (FpDevice *dev) { - FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev); - if (fpi_device_action_is_cancelled (dev)) { - do_verify_stop(dev, FPI_MATCH_ERROR, g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled")); - return; - } + if (fpi_device_action_is_cancelled (dev)) + { + do_verify_stop (dev, FPI_MATCH_ERROR, g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled")); + return; + } - /* FIXME: this doesn't flow well, should the first cmd be moved from - * verify init to here? */ - if (upekdev->first_verify_iteration) { - read_msg_async(dev, verify_rd2800_cb, NULL); - upekdev->first_verify_iteration = FALSE; - } else { - FpiUsbTransfer *transfer = alloc_send_cmd28_transfer(dev, - 0x00, poll_data, sizeof(poll_data)); - transfer->short_is_error = TRUE; + /* FIXME: this doesn't flow well, should the first cmd be moved from + * verify init to here? */ + if (upekdev->first_verify_iteration) + { + read_msg_async (dev, verify_rd2800_cb, NULL); + upekdev->first_verify_iteration = FALSE; + } + else + { + FpiUsbTransfer *transfer = alloc_send_cmd28_transfer (dev, + 0x00, poll_data, sizeof (poll_data)); + transfer->short_is_error = TRUE; - fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, verify_wr2800_cb, NULL); - fpi_usb_transfer_unref (transfer); - } + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, verify_wr2800_cb, NULL); + fpi_usb_transfer_unref (transfer); + } } -static void verify_started(FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +static void +verify_started (FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS(dev); + FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev); - if (error) { - do_verify_stop (dev, FPI_MATCH_ERROR, error); - return; - } + if (error) + { + do_verify_stop (dev, FPI_MATCH_ERROR, error); + return; + } - upekdev->first_verify_iteration = TRUE; - verify_iterate(dev); + upekdev->first_verify_iteration = TRUE; + verify_iterate (dev); - fpi_ssm_free(ssm); + fpi_ssm_free (ssm); } -static void verify(FpDevice *dev) +static void +verify (FpDevice *dev) { - FpiSsm *ssm = fpi_ssm_new(dev, verify_start_sm_run_state, - VERIFY_NUM_STATES, NULL); - fpi_ssm_start(ssm, verify_started); + FpiSsm *ssm = fpi_ssm_new (dev, verify_start_sm_run_state, + VERIFY_NUM_STATES, NULL); + + fpi_ssm_start (ssm, verify_started); } static const FpIdEntry id_table[] = { - { .vid = 0x0483, .pid = 0x2016, }, - { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ + { .vid = 0x0483, .pid = 0x2016, }, + { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */ }; static void -fpi_device_upekts_init(FpiDeviceUpekts *self) { +fpi_device_upekts_init (FpiDeviceUpekts *self) +{ } static void -fpi_device_upekts_class_init(FpiDeviceUpektsClass *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); +fpi_device_upekts_class_init (FpiDeviceUpektsClass *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); - dev_class->id = FP_COMPONENT; - dev_class->full_name = "UPEK TouchStrip"; + dev_class->id = FP_COMPONENT; + dev_class->full_name = "UPEK TouchStrip"; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - dev_class->id_table = id_table; - dev_class->nr_enroll_stages = 3; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + dev_class->id_table = id_table; + dev_class->nr_enroll_stages = 3; - dev_class->open = dev_init; - dev_class->close = dev_exit; - dev_class->verify = verify; - dev_class->enroll = enroll; - /* dev_class->cancel = cancel; */ + dev_class->open = dev_init; + dev_class->close = dev_exit; + dev_class->verify = verify; + dev_class->enroll = enroll; + /* dev_class->cancel = cancel; */ } diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c index 8962b92f..599f5a3c 100644 --- a/libfprint/drivers/uru4000.c +++ b/libfprint/drivers/uru4000.c @@ -25,184 +25,189 @@ #include "drivers_api.h" -#define EP_INTR (1 | FPI_USB_ENDPOINT_IN) -#define EP_DATA (2 | FPI_USB_ENDPOINT_IN) -#define USB_RQ 0x04 -#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | FPI_USB_ENDPOINT_IN) -#define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | FPI_USB_ENDPOINT_OUT) -#define CTRL_TIMEOUT 5000 -#define BULK_TIMEOUT 5000 -#define IRQ_LENGTH 64 -#define CR_LENGTH 16 +#define EP_INTR (1 | FPI_USB_ENDPOINT_IN) +#define EP_DATA (2 | FPI_USB_ENDPOINT_IN) +#define USB_RQ 0x04 +#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | FPI_USB_ENDPOINT_IN) +#define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | FPI_USB_ENDPOINT_OUT) +#define CTRL_TIMEOUT 5000 +#define BULK_TIMEOUT 5000 +#define IRQ_LENGTH 64 +#define CR_LENGTH 16 -#define IMAGE_HEIGHT 290 -#define IMAGE_WIDTH 384 +#define IMAGE_HEIGHT 290 +#define IMAGE_WIDTH 384 -#define ENC_THRESHOLD 5000 +#define ENC_THRESHOLD 5000 enum { - IRQDATA_SCANPWR_ON = 0x56aa, - IRQDATA_FINGER_ON = 0x0101, - IRQDATA_FINGER_OFF = 0x0200, - IRQDATA_DEATH = 0x0800, + IRQDATA_SCANPWR_ON = 0x56aa, + IRQDATA_FINGER_ON = 0x0101, + IRQDATA_FINGER_OFF = 0x0200, + IRQDATA_DEATH = 0x0800, }; enum { - REG_HWSTAT = 0x07, - REG_SCRAMBLE_DATA_INDEX = 0x33, - REG_SCRAMBLE_DATA_KEY = 0x34, - REG_MODE = 0x4e, - REG_DEVICE_INFO = 0xf0, - /* firmware starts at 0x100 */ - REG_RESPONSE = 0x2000, - REG_CHALLENGE = 0x2010, + REG_HWSTAT = 0x07, + REG_SCRAMBLE_DATA_INDEX = 0x33, + REG_SCRAMBLE_DATA_KEY = 0x34, + REG_MODE = 0x4e, + REG_DEVICE_INFO = 0xf0, + /* firmware starts at 0x100 */ + REG_RESPONSE = 0x2000, + REG_CHALLENGE = 0x2010, }; enum { - MODE_INIT = 0x00, - MODE_AWAIT_FINGER_ON = 0x10, - MODE_AWAIT_FINGER_OFF = 0x12, - MODE_CAPTURE = 0x20, - MODE_CAPTURE_AUX = 0x30, - MODE_OFF = 0x70, - MODE_READY = 0x80, + MODE_INIT = 0x00, + MODE_AWAIT_FINGER_ON = 0x10, + MODE_AWAIT_FINGER_OFF = 0x12, + MODE_CAPTURE = 0x20, + MODE_CAPTURE_AUX = 0x30, + MODE_OFF = 0x70, + MODE_READY = 0x80, }; enum { - MS_KBD, - MS_INTELLIMOUSE, - MS_STANDALONE, - MS_STANDALONE_V2, - DP_URU4000, - DP_URU4000B, + MS_KBD, + MS_INTELLIMOUSE, + MS_STANDALONE, + MS_STANDALONE_V2, + DP_URU4000, + DP_URU4000B, }; -static const struct uru4k_dev_profile { - const char *name; - gboolean auth_cr; - gboolean encryption; +static const struct uru4k_dev_profile +{ + const char *name; + gboolean auth_cr; + gboolean encryption; } uru4k_dev_info[] = { - [MS_KBD] = { - .name = "Microsoft Keyboard with Fingerprint Reader", - .auth_cr = FALSE, - }, - [MS_INTELLIMOUSE] = { - .name = "Microsoft Wireless IntelliMouse with Fingerprint Reader", - .auth_cr = FALSE, - }, - [MS_STANDALONE] = { - .name = "Microsoft Fingerprint Reader", - .auth_cr = FALSE, - }, - [MS_STANDALONE_V2] = { - .name = "Microsoft Fingerprint Reader v2", - .auth_cr = TRUE, - }, - [DP_URU4000] = { - .name = "Digital Persona U.are.U 4000", - .auth_cr = FALSE, - }, - [DP_URU4000B] = { - .name = "Digital Persona U.are.U 4000B", - .auth_cr = FALSE, - .encryption = TRUE, - }, + [MS_KBD] = { + .name = "Microsoft Keyboard with Fingerprint Reader", + .auth_cr = FALSE, + }, + [MS_INTELLIMOUSE] = { + .name = "Microsoft Wireless IntelliMouse with Fingerprint Reader", + .auth_cr = FALSE, + }, + [MS_STANDALONE] = { + .name = "Microsoft Fingerprint Reader", + .auth_cr = FALSE, + }, + [MS_STANDALONE_V2] = { + .name = "Microsoft Fingerprint Reader v2", + .auth_cr = TRUE, + }, + [DP_URU4000] = { + .name = "Digital Persona U.are.U 4000", + .auth_cr = FALSE, + }, + [DP_URU4000B] = { + .name = "Digital Persona U.are.U 4000B", + .auth_cr = FALSE, + .encryption = TRUE, + }, }; typedef void (*irq_cb_fn)(FpImageDevice *dev, - GError *error, - uint16_t type, - void *user_data); + GError *error, + uint16_t type, + void *user_data); typedef void (*irqs_stopped_cb_fn)(FpImageDevice *dev); -struct _FpiDeviceUru4000 { - FpImageDevice parent; +struct _FpiDeviceUru4000 +{ + FpImageDevice parent; - const struct uru4k_dev_profile *profile; - uint8_t interface; - FpImageDeviceState activate_state; - unsigned char last_reg_rd[16]; - unsigned char last_hwstat; + const struct uru4k_dev_profile *profile; + uint8_t interface; + FpImageDeviceState activate_state; + unsigned char last_reg_rd[16]; + unsigned char last_hwstat; - GCancellable *irq_cancellable; - FpiUsbTransfer *img_transfer; - void *img_data; - int img_data_actual_length; - uint16_t img_lines_done, img_block; - uint32_t img_enc_seed; + GCancellable *irq_cancellable; + FpiUsbTransfer *img_transfer; + void *img_data; + int img_data_actual_length; + uint16_t img_lines_done, img_block; + uint32_t img_enc_seed; - irq_cb_fn irq_cb; - void *irq_cb_data; - irqs_stopped_cb_fn irqs_stopped_cb; + irq_cb_fn irq_cb; + void *irq_cb_data; + irqs_stopped_cb_fn irqs_stopped_cb; - int rebootpwr_ctr; - int powerup_ctr; - unsigned char powerup_hwstat; + int rebootpwr_ctr; + int powerup_ctr; + unsigned char powerup_hwstat; - int scanpwr_irq_timeouts; - GSource *scanpwr_irq_timeout; + int scanpwr_irq_timeouts; + GSource *scanpwr_irq_timeout; - int fwfixer_offset; - unsigned char fwfixer_value; + int fwfixer_offset; + unsigned char fwfixer_value; - CK_MECHANISM_TYPE cipher; - PK11SlotInfo *slot; - PK11SymKey *symkey; - SECItem *param; + CK_MECHANISM_TYPE cipher; + PK11SlotInfo *slot; + PK11SymKey *symkey; + SECItem *param; }; -G_DECLARE_FINAL_TYPE(FpiDeviceUru4000, fpi_device_uru4000, FPI, DEVICE_URU4000, - FpImageDevice); -G_DEFINE_TYPE(FpiDeviceUru4000, fpi_device_uru4000, FP_TYPE_IMAGE_DEVICE); +G_DECLARE_FINAL_TYPE (FpiDeviceUru4000, fpi_device_uru4000, FPI, DEVICE_URU4000, + FpImageDevice); +G_DEFINE_TYPE (FpiDeviceUru4000, fpi_device_uru4000, FP_TYPE_IMAGE_DEVICE); /* For 2nd generation MS devices */ static const unsigned char crkey[] = { - 0x79, 0xac, 0x91, 0x79, 0x5c, 0xa1, 0x47, 0x8e, - 0x98, 0xe0, 0x0f, 0x3c, 0x59, 0x8f, 0x5f, 0x4b, + 0x79, 0xac, 0x91, 0x79, 0x5c, 0xa1, 0x47, 0x8e, + 0x98, 0xe0, 0x0f, 0x3c, 0x59, 0x8f, 0x5f, 0x4b, }; /***** REGISTER I/O *****/ -static void write_regs(FpImageDevice *dev, uint16_t first_reg, - uint16_t num_regs, unsigned char *values, - FpiUsbTransferCallback callback, - void *user_data) +static void +write_regs (FpImageDevice *dev, uint16_t first_reg, + uint16_t num_regs, unsigned char *values, + FpiUsbTransferCallback callback, + void *user_data) { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); + FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); - transfer->short_is_error = TRUE; - fpi_usb_transfer_fill_control(transfer, - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, - G_USB_DEVICE_REQUEST_TYPE_STANDARD, - G_USB_DEVICE_RECIPIENT_DEVICE, - USB_RQ, first_reg, 0, - num_regs); - memcpy(transfer->buffer, values, num_regs); - fpi_usb_transfer_submit(transfer, CTRL_TIMEOUT, NULL, callback, user_data); - fpi_usb_transfer_unref(transfer); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_control (transfer, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_STANDARD, + G_USB_DEVICE_RECIPIENT_DEVICE, + USB_RQ, first_reg, 0, + num_regs); + memcpy (transfer->buffer, values, num_regs); + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, callback, user_data); + fpi_usb_transfer_unref (transfer); } -static void write_reg(FpImageDevice *dev, uint16_t reg, - unsigned char value, - FpiUsbTransferCallback callback, - void *user_data) +static void +write_reg (FpImageDevice *dev, uint16_t reg, + unsigned char value, + FpiUsbTransferCallback callback, + void *user_data) { - write_regs(dev, reg, 1, &value, callback, user_data); + write_regs (dev, reg, 1, &value, callback, user_data); } -static void read_regs(FpImageDevice *dev, uint16_t first_reg, - uint16_t num_regs, - FpiUsbTransferCallback callback, - void *user_data) +static void +read_regs (FpImageDevice *dev, uint16_t first_reg, + uint16_t num_regs, + FpiUsbTransferCallback callback, + void *user_data) { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); + FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); - fpi_usb_transfer_fill_control(transfer, - G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, - G_USB_DEVICE_REQUEST_TYPE_STANDARD, - G_USB_DEVICE_RECIPIENT_DEVICE, - USB_RQ, first_reg, 0, num_regs); - fpi_usb_transfer_submit(transfer, CTRL_TIMEOUT, NULL, callback, user_data); - fpi_usb_transfer_unref(transfer); + fpi_usb_transfer_fill_control (transfer, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_STANDARD, + G_USB_DEVICE_RECIPIENT_DEVICE, + USB_RQ, first_reg, 0, num_regs); + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, callback, user_data); + fpi_usb_transfer_unref (transfer); } /* @@ -230,45 +235,49 @@ static void read_regs(FpImageDevice *dev, uint16_t first_reg, * an interrupt to the host. Maybe? */ -static void response_cb(FpiUsbTransfer *transfer, FpDevice *dev, void *user_data, GError *error) +static void +response_cb (FpiUsbTransfer *transfer, FpDevice *dev, void *user_data, GError *error) { - /* NOTE: We could use the SSM function instead if we attached the ssm to the transfer! */ - FpiSsm *ssm = user_data; + /* NOTE: We could use the SSM function instead if we attached the ssm to the transfer! */ + FpiSsm *ssm = user_data; - if (!error) - fpi_ssm_next_state(ssm); - else - fpi_ssm_mark_failed(ssm, error); + if (!error) + fpi_ssm_next_state (ssm); + else + fpi_ssm_mark_failed (ssm, error); } -static void challenge_cb(FpiUsbTransfer *transfer, FpDevice *dev, void *user_data, GError *error) +static void +challenge_cb (FpiUsbTransfer *transfer, FpDevice *dev, void *user_data, GError *error) { - FpiSsm *ssm = user_data; - FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); - unsigned char respdata[CR_LENGTH]; - PK11Context *ctx; - int outlen; + FpiSsm *ssm = user_data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); + unsigned char respdata[CR_LENGTH]; + PK11Context *ctx; + int outlen; - if (error) { - fpi_ssm_mark_failed(ssm, error); - return; - } + if (error) + { + fpi_ssm_mark_failed (ssm, error); + return; + } - /* submit response */ - /* produce response from challenge */ - ctx = PK11_CreateContextBySymKey(self->cipher, CKA_ENCRYPT, - self->symkey, self->param); - if (PK11_CipherOp(ctx, respdata, &outlen, CR_LENGTH, transfer->buffer, CR_LENGTH) != SECSuccess - || PK11_Finalize(ctx) != SECSuccess) { - fp_err("Failed to encrypt challenge data"); - error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "Failed to encrypt challenge data"); - } - PK11_DestroyContext(ctx, PR_TRUE); + /* submit response */ + /* produce response from challenge */ + ctx = PK11_CreateContextBySymKey (self->cipher, CKA_ENCRYPT, + self->symkey, self->param); + if (PK11_CipherOp (ctx, respdata, &outlen, CR_LENGTH, transfer->buffer, CR_LENGTH) != SECSuccess || + PK11_Finalize (ctx) != SECSuccess) + { + fp_err ("Failed to encrypt challenge data"); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "Failed to encrypt challenge data"); + } + PK11_DestroyContext (ctx, PR_TRUE); - if (!error) - write_regs(FP_IMAGE_DEVICE (dev), REG_RESPONSE, CR_LENGTH, respdata, response_cb, ssm); - else - fpi_ssm_mark_failed(ssm, error); + if (!error) + write_regs (FP_IMAGE_DEVICE (dev), REG_RESPONSE, CR_LENGTH, respdata, response_cb, ssm); + else + fpi_ssm_mark_failed (ssm, error); } /* @@ -277,476 +286,526 @@ static void challenge_cb(FpiUsbTransfer *transfer, FpDevice *dev, void *user_dat * driver. */ static void -sm_do_challenge_response(FpiSsm *ssm, - FpImageDevice *dev) +sm_do_challenge_response (FpiSsm *ssm, + FpImageDevice *dev) { - G_DEBUG_HERE(); - read_regs(dev, REG_CHALLENGE, CR_LENGTH, challenge_cb, ssm); + G_DEBUG_HERE (); + read_regs (dev, REG_CHALLENGE, CR_LENGTH, challenge_cb, ssm); } /***** INTERRUPT HANDLING *****/ #define IRQ_HANDLER_IS_RUNNING(urudev) ((urudev)->irq_cancellable) -static void start_irq_handler(FpImageDevice *dev); +static void start_irq_handler (FpImageDevice *dev); -static void irq_handler(FpiUsbTransfer *transfer, - FpDevice *dev, - void *user_data, - GError *error) +static void +irq_handler (FpiUsbTransfer *transfer, + FpDevice *dev, + void *user_data, + GError *error) { - FpImageDevice *imgdev = FP_IMAGE_DEVICE (dev); - FpiDeviceUru4000 *urudev = FPI_DEVICE_URU4000 (dev); - unsigned char *data = transfer->buffer; - uint16_t type; + FpImageDevice *imgdev = FP_IMAGE_DEVICE (dev); + FpiDeviceUru4000 *urudev = FPI_DEVICE_URU4000 (dev); + unsigned char *data = transfer->buffer; + uint16_t type; - g_clear_object (&urudev->irq_cancellable); + g_clear_object (&urudev->irq_cancellable); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - fp_dbg("cancelled"); - if (urudev->irqs_stopped_cb) - urudev->irqs_stopped_cb(imgdev); - urudev->irqs_stopped_cb = NULL; - return; - } else if (error) { - if (urudev->irq_cb) { - urudev->irq_cb(imgdev, error, 0, urudev->irq_cb_data); - } else { - fp_dbg("ignoring interrupt error: %s", error->message); - g_clear_error (&error); - } - return; - } + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + fp_dbg ("cancelled"); + if (urudev->irqs_stopped_cb) + urudev->irqs_stopped_cb (imgdev); + urudev->irqs_stopped_cb = NULL; + return; + } + else if (error) + { + if (urudev->irq_cb) + { + urudev->irq_cb (imgdev, error, 0, urudev->irq_cb_data); + } + else + { + fp_dbg ("ignoring interrupt error: %s", error->message); + g_clear_error (&error); + } + return; + } - type = GUINT16_FROM_BE(*((uint16_t *) data)); - fp_dbg("recv irq type %04x", type); + type = GUINT16_FROM_BE (*((uint16_t *) data)); + fp_dbg ("recv irq type %04x", type); - /* The 0800 interrupt seems to indicate imminent failure (0 bytes transfer) - * of the next scan. It still appears on occasion. */ - if (type == IRQDATA_DEATH) - fp_warn("oh no! got the interrupt OF DEATH! expect things to go bad"); + /* The 0800 interrupt seems to indicate imminent failure (0 bytes transfer) + * of the next scan. It still appears on occasion. */ + if (type == IRQDATA_DEATH) + fp_warn ("oh no! got the interrupt OF DEATH! expect things to go bad"); - if (urudev->irq_cb) - urudev->irq_cb(imgdev, NULL, type, urudev->irq_cb_data); - else - fp_dbg("ignoring interrupt"); + if (urudev->irq_cb) + urudev->irq_cb (imgdev, NULL, type, urudev->irq_cb_data); + else + fp_dbg ("ignoring interrupt"); - start_irq_handler(imgdev); + start_irq_handler (imgdev); } -static void start_irq_handler(FpImageDevice *dev) +static void +start_irq_handler (FpImageDevice *dev) { - FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); - FpiUsbTransfer *transfer; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); + FpiUsbTransfer *transfer; - g_assert (self->irq_cancellable == NULL); - self->irq_cancellable = g_cancellable_new (); - transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); - transfer->ssm = NULL; - transfer->short_is_error = TRUE; - fpi_usb_transfer_fill_bulk (transfer, - EP_INTR, - IRQ_LENGTH); - fpi_usb_transfer_submit(transfer, 0, self->irq_cancellable, irq_handler, NULL); - fpi_usb_transfer_unref(transfer); + g_assert (self->irq_cancellable == NULL); + self->irq_cancellable = g_cancellable_new (); + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + transfer->ssm = NULL; + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk (transfer, + EP_INTR, + IRQ_LENGTH); + fpi_usb_transfer_submit (transfer, 0, self->irq_cancellable, irq_handler, NULL); + fpi_usb_transfer_unref (transfer); } -static void stop_irq_handler(FpImageDevice *dev, irqs_stopped_cb_fn cb) +static void +stop_irq_handler (FpImageDevice *dev, irqs_stopped_cb_fn cb) { - FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); - if (self->irq_cancellable) { - g_cancellable_cancel (self->irq_cancellable); - self->irqs_stopped_cb = cb; - } + if (self->irq_cancellable) + { + g_cancellable_cancel (self->irq_cancellable); + self->irqs_stopped_cb = cb; + } } /***** STATE CHANGING *****/ -static void execute_state_change(FpImageDevice *dev); +static void execute_state_change (FpImageDevice *dev); -static void finger_presence_irq_cb(FpImageDevice *dev, - GError *error, - uint16_t type, - void *user_data) +static void +finger_presence_irq_cb (FpImageDevice *dev, + GError *error, + uint16_t type, + void *user_data) { - if (error) - fpi_image_device_session_error(dev, error); - else if (type == IRQDATA_FINGER_ON) - fpi_image_device_report_finger_status(dev, TRUE); - else if (type == IRQDATA_FINGER_OFF) - fpi_image_device_report_finger_status(dev, FALSE); - else - fp_warn("ignoring unexpected interrupt %04x", type); + if (error) + fpi_image_device_session_error (dev, error); + else if (type == IRQDATA_FINGER_ON) + fpi_image_device_report_finger_status (dev, TRUE); + else if (type == IRQDATA_FINGER_OFF) + fpi_image_device_report_finger_status (dev, FALSE); + else + fp_warn ("ignoring unexpected interrupt %04x", type); } -static void change_state_write_reg_cb(FpiUsbTransfer *transfer, - FpDevice *dev, - void *user_data, - GError *error) +static void +change_state_write_reg_cb (FpiUsbTransfer *transfer, + FpDevice *dev, + void *user_data, + GError *error) { - if (error) - fpi_image_device_session_error(FP_IMAGE_DEVICE (dev), error); + if (error) + fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error); } -static void dev_change_state(FpImageDevice *dev, FpImageDeviceState state) +static void +dev_change_state (FpImageDevice *dev, FpImageDeviceState state) { - FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); - switch (state) { - case FP_IMAGE_DEVICE_STATE_INACTIVE: - case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: - case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: - case FP_IMAGE_DEVICE_STATE_CAPTURE: - break; - default: - g_assert_not_reached (); - } + switch (state) + { + case FP_IMAGE_DEVICE_STATE_INACTIVE: + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: + case FP_IMAGE_DEVICE_STATE_CAPTURE: + break; - self->activate_state = state; - if (self->img_transfer != NULL) - return; + default: + g_assert_not_reached (); + } - execute_state_change(dev); + self->activate_state = state; + if (self->img_transfer != NULL) + return; + + execute_state_change (dev); } /***** GENERIC STATE MACHINE HELPER FUNCTIONS *****/ -static void sm_write_reg_cb(FpiUsbTransfer *transfer, - FpDevice *dev, - void *user_data, - GError *error) +static void +sm_write_reg_cb (FpiUsbTransfer *transfer, + FpDevice *dev, + void *user_data, + GError *error) { - FpiSsm *ssm = user_data; + FpiSsm *ssm = user_data; - if (error) - fpi_ssm_mark_failed(ssm, error); - else - fpi_ssm_next_state(ssm); + if (error) + fpi_ssm_mark_failed (ssm, error); + else + fpi_ssm_next_state (ssm); } static void -sm_write_regs(FpiSsm *ssm, - FpImageDevice *dev, - uint16_t first_reg, - uint16_t num_regs, - void *data) +sm_write_regs (FpiSsm *ssm, + FpImageDevice *dev, + uint16_t first_reg, + uint16_t num_regs, + void *data) { - write_regs(dev, first_reg, num_regs, data, sm_write_reg_cb, ssm); + write_regs (dev, first_reg, num_regs, data, sm_write_reg_cb, ssm); } static void -sm_write_reg(FpiSsm *ssm, - FpImageDevice *dev, - uint16_t reg, - unsigned char value) +sm_write_reg (FpiSsm *ssm, + FpImageDevice *dev, + uint16_t reg, + unsigned char value) { - sm_write_regs(ssm, dev, reg, 1, &value); -} - -static void sm_read_reg_cb(FpiUsbTransfer *transfer, - FpDevice *dev, - void *user_data, - GError *error) -{ - FpiSsm *ssm = user_data; - FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); - - if (error) { - fpi_ssm_mark_failed(ssm, error); - } else { - memcpy(self->last_reg_rd, transfer->buffer, transfer->actual_length); - fp_dbg("reg value %x", self->last_reg_rd[0]); - fpi_ssm_next_state(ssm); - } -} - -#define member_size(type, member) sizeof(((type *)0)->member) - -static void -sm_read_regs(FpiSsm *ssm, - FpImageDevice *dev, - uint16_t reg, - uint16_t num_regs) -{ - g_assert (num_regs <= member_size(FpiDeviceUru4000, last_reg_rd)); - - fp_dbg("read %d regs at %x", num_regs, reg); - read_regs(dev, reg, num_regs, sm_read_reg_cb, ssm); + sm_write_regs (ssm, dev, reg, 1, &value); } static void -sm_read_reg(FpiSsm *ssm, - FpImageDevice *dev, - uint16_t reg) +sm_read_reg_cb (FpiUsbTransfer *transfer, + FpDevice *dev, + void *user_data, + GError *error) { - sm_read_regs(ssm, dev, reg, 1); + FpiSsm *ssm = user_data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); + + if (error) + { + fpi_ssm_mark_failed (ssm, error); + } + else + { + memcpy (self->last_reg_rd, transfer->buffer, transfer->actual_length); + fp_dbg ("reg value %x", self->last_reg_rd[0]); + fpi_ssm_next_state (ssm); + } +} + +#define member_size(type, member) sizeof (((type *) 0)->member) + +static void +sm_read_regs (FpiSsm *ssm, + FpImageDevice *dev, + uint16_t reg, + uint16_t num_regs) +{ + g_assert (num_regs <= member_size (FpiDeviceUru4000, last_reg_rd)); + + fp_dbg ("read %d regs at %x", num_regs, reg); + read_regs (dev, reg, num_regs, sm_read_reg_cb, ssm); } static void -sm_set_hwstat(FpiSsm *ssm, - FpImageDevice *dev, - unsigned char value) +sm_read_reg (FpiSsm *ssm, + FpImageDevice *dev, + uint16_t reg) { - fp_dbg("set %02x", value); - sm_write_reg(ssm, dev, REG_HWSTAT, value); + sm_read_regs (ssm, dev, reg, 1); +} + +static void +sm_set_hwstat (FpiSsm *ssm, + FpImageDevice *dev, + unsigned char value) +{ + fp_dbg ("set %02x", value); + sm_write_reg (ssm, dev, REG_HWSTAT, value); } /***** IMAGING LOOP *****/ enum imaging_states { - IMAGING_CAPTURE, - IMAGING_SEND_INDEX, - IMAGING_READ_KEY, - IMAGING_DECODE, - IMAGING_REPORT_IMAGE, - IMAGING_NUM_STATES + IMAGING_CAPTURE, + IMAGING_SEND_INDEX, + IMAGING_READ_KEY, + IMAGING_DECODE, + IMAGING_REPORT_IMAGE, + IMAGING_NUM_STATES }; -struct uru4k_image { - uint8_t unknown_00[4]; - uint16_t num_lines; - uint8_t key_number; - uint8_t unknown_07[9]; - struct { - uint8_t flags; - uint8_t num_lines; - } block_info[15]; - uint8_t unknown_2E[18]; - uint8_t data[IMAGE_HEIGHT][IMAGE_WIDTH]; -}; - -static void image_transfer_cb(FpiUsbTransfer *transfer, FpDevice *dev, - gpointer user_data, GError *error) +struct uru4k_image { - FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); - FpiSsm *ssm = transfer->ssm; + uint8_t unknown_00[4]; + uint16_t num_lines; + uint8_t key_number; + uint8_t unknown_07[9]; + struct + { + uint8_t flags; + uint8_t num_lines; + } block_info[15]; + uint8_t unknown_2E[18]; + uint8_t data[IMAGE_HEIGHT][IMAGE_WIDTH]; +}; - if (error) { - fp_dbg("error"); - fpi_ssm_mark_failed(ssm, error); - } else { - self->img_data = g_memdup(transfer->buffer, sizeof(struct uru4k_image)); - self->img_data_actual_length = transfer->actual_length; - fpi_ssm_next_state(ssm); - } +static void +image_transfer_cb (FpiUsbTransfer *transfer, FpDevice *dev, + gpointer user_data, GError *error) +{ + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); + FpiSsm *ssm = transfer->ssm; + + if (error) + { + fp_dbg ("error"); + fpi_ssm_mark_failed (ssm, error); + } + else + { + self->img_data = g_memdup (transfer->buffer, sizeof (struct uru4k_image)); + self->img_data_actual_length = transfer->actual_length; + fpi_ssm_next_state (ssm); + } } enum { - BLOCKF_CHANGE_KEY = 0x80, - BLOCKF_NO_KEY_UPDATE = 0x04, - BLOCKF_ENCRYPTED = 0x02, - BLOCKF_NOT_PRESENT = 0x01, + BLOCKF_CHANGE_KEY = 0x80, + BLOCKF_NO_KEY_UPDATE = 0x04, + BLOCKF_ENCRYPTED = 0x02, + BLOCKF_NOT_PRESENT = 0x01, }; -static uint32_t update_key(uint32_t key) +static uint32_t +update_key (uint32_t key) { - /* linear feedback shift register - * taps at bit positions 1 3 4 7 11 13 20 23 26 29 32 */ - uint32_t bit = key & 0x9248144d; - bit ^= bit << 16; - bit ^= bit << 8; - bit ^= bit << 4; - bit ^= bit << 2; - bit ^= bit << 1; - return (bit & 0x80000000) | (key >> 1); + /* linear feedback shift register + * taps at bit positions 1 3 4 7 11 13 20 23 26 29 32 */ + uint32_t bit = key & 0x9248144d; + + bit ^= bit << 16; + bit ^= bit << 8; + bit ^= bit << 4; + bit ^= bit << 2; + bit ^= bit << 1; + return (bit & 0x80000000) | (key >> 1); } -static uint32_t do_decode(uint8_t *data, int num_bytes, uint32_t key) +static uint32_t +do_decode (uint8_t *data, int num_bytes, uint32_t key) { - uint8_t xorbyte; - int i; + uint8_t xorbyte; + int i; - for (i = 0; i < num_bytes - 1; i++) { - /* calculate xor byte and update key */ - xorbyte = ((key >> 4) & 1) << 0; - xorbyte |= ((key >> 8) & 1) << 1; - xorbyte |= ((key >> 11) & 1) << 2; - xorbyte |= ((key >> 14) & 1) << 3; - xorbyte |= ((key >> 18) & 1) << 4; - xorbyte |= ((key >> 21) & 1) << 5; - xorbyte |= ((key >> 24) & 1) << 6; - xorbyte |= ((key >> 29) & 1) << 7; - key = update_key(key); + for (i = 0; i < num_bytes - 1; i++) + { + /* calculate xor byte and update key */ + xorbyte = ((key >> 4) & 1) << 0; + xorbyte |= ((key >> 8) & 1) << 1; + xorbyte |= ((key >> 11) & 1) << 2; + xorbyte |= ((key >> 14) & 1) << 3; + xorbyte |= ((key >> 18) & 1) << 4; + xorbyte |= ((key >> 21) & 1) << 5; + xorbyte |= ((key >> 24) & 1) << 6; + xorbyte |= ((key >> 29) & 1) << 7; + key = update_key (key); - /* decrypt data */ - data[i] = data[i+1] ^ xorbyte; - } + /* decrypt data */ + data[i] = data[i + 1] ^ xorbyte; + } - /* the final byte is implicitly zero */ - data[i] = 0; - return update_key(key); + /* the final byte is implicitly zero */ + data[i] = 0; + return update_key (key); } -static int calc_dev2(struct uru4k_image *img) +static int +calc_dev2 (struct uru4k_image *img) { - uint8_t *b[2] = { NULL, NULL }; - int res = 0, mean = 0, i, r, j, idx; + uint8_t *b[2] = { NULL, NULL }; + int res = 0, mean = 0, i, r, j, idx; - for (i = r = idx = 0; i < G_N_ELEMENTS(img->block_info) && idx < 2; i++) { - if (img->block_info[i].flags & BLOCKF_NOT_PRESENT) - continue; - for (j = 0; j < img->block_info[i].num_lines && idx < 2; j++) - b[idx++] = img->data[r++]; - } - if (!b[0] || !b[1]) { - fp_dbg("NULL! %p %p", b[0], b[1]); - return 0; - } - for (i = 0; i < IMAGE_WIDTH; i++) - mean += (int)b[0][i] + (int)b[1][i]; + for (i = r = idx = 0; i < G_N_ELEMENTS (img->block_info) && idx < 2; i++) + { + if (img->block_info[i].flags & BLOCKF_NOT_PRESENT) + continue; + for (j = 0; j < img->block_info[i].num_lines && idx < 2; j++) + b[idx++] = img->data[r++]; + } + if (!b[0] || !b[1]) + { + fp_dbg ("NULL! %p %p", b[0], b[1]); + return 0; + } + for (i = 0; i < IMAGE_WIDTH; i++) + mean += (int) b[0][i] + (int) b[1][i]; - mean /= IMAGE_WIDTH; + mean /= IMAGE_WIDTH; - for (i = 0; i < IMAGE_WIDTH; i++) { - int dev = (int)b[0][i] + (int)b[1][i] - mean; - res += dev * dev; - } + for (i = 0; i < IMAGE_WIDTH; i++) + { + int dev = (int) b[0][i] + (int) b[1][i] - mean; + res += dev * dev; + } - return res / IMAGE_WIDTH; + return res / IMAGE_WIDTH; } -static void imaging_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +imaging_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - FpImageDevice *dev = user_data; - FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(_dev); - struct uru4k_image *img = self->img_data; - FpImage *fpimg; - uint32_t key; - uint8_t flags, num_lines; - int i, r, to, dev2; - unsigned char buf[5]; + FpImageDevice *dev = user_data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (_dev); + struct uru4k_image *img = self->img_data; + FpImage *fpimg; + uint32_t key; + uint8_t flags, num_lines; + int i, r, to, dev2; + unsigned char buf[5]; - switch (fpi_ssm_get_cur_state(ssm)) { - case IMAGING_CAPTURE: - self->img_lines_done = 0; - self->img_block = 0; - fpi_usb_transfer_submit(self->img_transfer, 0, NULL, image_transfer_cb, NULL); + switch (fpi_ssm_get_cur_state (ssm)) + { + case IMAGING_CAPTURE: + self->img_lines_done = 0; + self->img_block = 0; + fpi_usb_transfer_submit (self->img_transfer, 0, NULL, image_transfer_cb, NULL); - break; - case IMAGING_SEND_INDEX: - fp_dbg("hw header lines %d", img->num_lines); + break; - if (img->num_lines >= IMAGE_HEIGHT || - self->img_data_actual_length < img->num_lines * IMAGE_WIDTH + 64) { - fp_err("bad captured image (%d lines) or size mismatch %d < %d", - img->num_lines, - self->img_data_actual_length, - img->num_lines * IMAGE_WIDTH + 64); - fpi_ssm_jump_to_state(ssm, IMAGING_CAPTURE); - return; - } - if (!self->profile->encryption) { - dev2 = calc_dev2(img); - fp_dbg("dev2: %d", dev2); - if (dev2 < ENC_THRESHOLD) { - fpi_ssm_jump_to_state(ssm, IMAGING_REPORT_IMAGE); - return; - } - fp_info("image seems to be encrypted"); - } - buf[0] = img->key_number; - buf[1] = self->img_enc_seed; - buf[2] = self->img_enc_seed >> 8; - buf[3] = self->img_enc_seed >> 16; - buf[4] = self->img_enc_seed >> 24; - sm_write_regs(ssm, dev, REG_SCRAMBLE_DATA_INDEX, 5, buf); - break; - case IMAGING_READ_KEY: - sm_read_regs(ssm, dev, REG_SCRAMBLE_DATA_KEY, 4); - break; - case IMAGING_DECODE: - key = self->last_reg_rd[0]; - key |= self->last_reg_rd[1] << 8; - key |= self->last_reg_rd[2] << 16; - key |= self->last_reg_rd[3] << 24; - key ^= self->img_enc_seed; + case IMAGING_SEND_INDEX: + fp_dbg ("hw header lines %d", img->num_lines); - fp_dbg("encryption id %02x -> key %08x", img->key_number, key); - while (self->img_block < G_N_ELEMENTS(img->block_info) && - self->img_lines_done < img->num_lines) { - flags = img->block_info[self->img_block].flags; - num_lines = img->block_info[self->img_block].num_lines; - if (num_lines == 0) - break; + if (img->num_lines >= IMAGE_HEIGHT || + self->img_data_actual_length < img->num_lines * IMAGE_WIDTH + 64) + { + fp_err ("bad captured image (%d lines) or size mismatch %d < %d", + img->num_lines, + self->img_data_actual_length, + img->num_lines * IMAGE_WIDTH + 64); + fpi_ssm_jump_to_state (ssm, IMAGING_CAPTURE); + return; + } + if (!self->profile->encryption) + { + dev2 = calc_dev2 (img); + fp_dbg ("dev2: %d", dev2); + if (dev2 < ENC_THRESHOLD) + { + fpi_ssm_jump_to_state (ssm, IMAGING_REPORT_IMAGE); + return; + } + fp_info ("image seems to be encrypted"); + } + buf[0] = img->key_number; + buf[1] = self->img_enc_seed; + buf[2] = self->img_enc_seed >> 8; + buf[3] = self->img_enc_seed >> 16; + buf[4] = self->img_enc_seed >> 24; + sm_write_regs (ssm, dev, REG_SCRAMBLE_DATA_INDEX, 5, buf); + break; - fp_dbg("%d %02x %d", self->img_block, flags, - num_lines); - if (flags & BLOCKF_CHANGE_KEY) { - fp_dbg("changing encryption keys.\n"); - img->block_info[self->img_block].flags &= ~BLOCKF_CHANGE_KEY; - img->key_number++; - self->img_enc_seed = rand(); - fpi_ssm_jump_to_state(ssm, IMAGING_SEND_INDEX); - return; - } - switch (flags & (BLOCKF_NO_KEY_UPDATE | BLOCKF_ENCRYPTED)) { - case BLOCKF_ENCRYPTED: - fp_dbg("decoding %d lines", num_lines); - key = do_decode(&img->data[self->img_lines_done][0], - IMAGE_WIDTH*num_lines, key); - break; - case 0: - fp_dbg("skipping %d lines", num_lines); - for (r = 0; r < IMAGE_WIDTH*num_lines; r++) - key = update_key(key); - break; - } - if ((flags & BLOCKF_NOT_PRESENT) == 0) - self->img_lines_done += num_lines; - self->img_block++; - } - fpi_ssm_next_state(ssm); - break; - case IMAGING_REPORT_IMAGE: - fpimg = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT); + case IMAGING_READ_KEY: + sm_read_regs (ssm, dev, REG_SCRAMBLE_DATA_KEY, 4); + break; - to = r = 0; - for (i = 0; i < G_N_ELEMENTS(img->block_info) && r < img->num_lines; i++) { - flags = img->block_info[i].flags; - num_lines = img->block_info[i].num_lines; - if (num_lines == 0) - break; - memcpy(&fpimg->data[to], &img->data[r][0], - num_lines * IMAGE_WIDTH); - if (!(flags & BLOCKF_NOT_PRESENT)) - r += num_lines; - to += num_lines * IMAGE_WIDTH; - } + case IMAGING_DECODE: + key = self->last_reg_rd[0]; + key |= self->last_reg_rd[1] << 8; + key |= self->last_reg_rd[2] << 16; + key |= self->last_reg_rd[3] << 24; + key ^= self->img_enc_seed; - fpimg->flags = FPI_IMAGE_COLORS_INVERTED; - if (!self->profile->encryption) - fpimg->flags |= FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED; - fpi_image_device_image_captured(dev, fpimg); + fp_dbg ("encryption id %02x -> key %08x", img->key_number, key); + while (self->img_block < G_N_ELEMENTS (img->block_info) && + self->img_lines_done < img->num_lines) + { + flags = img->block_info[self->img_block].flags; + num_lines = img->block_info[self->img_block].num_lines; + if (num_lines == 0) + break; - if (self->activate_state == FP_IMAGE_DEVICE_STATE_CAPTURE) - fpi_ssm_jump_to_state(ssm, IMAGING_CAPTURE); - else - fpi_ssm_mark_completed(ssm); - break; - } + fp_dbg ("%d %02x %d", self->img_block, flags, + num_lines); + if (flags & BLOCKF_CHANGE_KEY) + { + fp_dbg ("changing encryption keys.\n"); + img->block_info[self->img_block].flags &= ~BLOCKF_CHANGE_KEY; + img->key_number++; + self->img_enc_seed = rand (); + fpi_ssm_jump_to_state (ssm, IMAGING_SEND_INDEX); + return; + } + switch (flags & (BLOCKF_NO_KEY_UPDATE | BLOCKF_ENCRYPTED)) + { + case BLOCKF_ENCRYPTED: + fp_dbg ("decoding %d lines", num_lines); + key = do_decode (&img->data[self->img_lines_done][0], + IMAGE_WIDTH * num_lines, key); + break; + + case 0: + fp_dbg ("skipping %d lines", num_lines); + for (r = 0; r < IMAGE_WIDTH * num_lines; r++) + key = update_key (key); + break; + } + if ((flags & BLOCKF_NOT_PRESENT) == 0) + self->img_lines_done += num_lines; + self->img_block++; + } + fpi_ssm_next_state (ssm); + break; + + case IMAGING_REPORT_IMAGE: + fpimg = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT); + + to = r = 0; + for (i = 0; i < G_N_ELEMENTS (img->block_info) && r < img->num_lines; i++) + { + flags = img->block_info[i].flags; + num_lines = img->block_info[i].num_lines; + if (num_lines == 0) + break; + memcpy (&fpimg->data[to], &img->data[r][0], + num_lines * IMAGE_WIDTH); + if (!(flags & BLOCKF_NOT_PRESENT)) + r += num_lines; + to += num_lines * IMAGE_WIDTH; + } + + fpimg->flags = FPI_IMAGE_COLORS_INVERTED; + if (!self->profile->encryption) + fpimg->flags |= FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED; + fpi_image_device_image_captured (dev, fpimg); + + if (self->activate_state == FP_IMAGE_DEVICE_STATE_CAPTURE) + fpi_ssm_jump_to_state (ssm, IMAGING_CAPTURE); + else + fpi_ssm_mark_completed (ssm); + break; + } } -static void imaging_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +static void +imaging_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); - fpi_ssm_free(ssm); + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); - /* Report error before exiting imaging loop - the error handler - * can request state change, which needs to be postponed to end of - * this function. */ - if (error) - fpi_image_device_session_error(FP_IMAGE_DEVICE (dev), error); + fpi_ssm_free (ssm); - /* Freed by callback or cancellation */ - self->img_transfer = NULL; + /* Report error before exiting imaging loop - the error handler + * can request state change, which needs to be postponed to end of + * this function. */ + if (error) + fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error); - g_free(self->img_data); - self->img_data = NULL; - self->img_data_actual_length = 0; + /* Freed by callback or cancellation */ + self->img_transfer = NULL; - execute_state_change(FP_IMAGE_DEVICE (dev)); + g_free (self->img_data); + self->img_data = NULL; + self->img_data_actual_length = 0; + + execute_state_change (FP_IMAGE_DEVICE (dev)); } /***** INITIALIZATION *****/ @@ -768,54 +827,62 @@ static void imaging_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, * and fails after 100 tries. */ enum rebootpwr_states { - REBOOTPWR_SET_HWSTAT = 0, - REBOOTPWR_GET_HWSTAT, - REBOOTPWR_CHECK_HWSTAT, - REBOOTPWR_PAUSE, - REBOOTPWR_NUM_STATES, + REBOOTPWR_SET_HWSTAT = 0, + REBOOTPWR_GET_HWSTAT, + REBOOTPWR_CHECK_HWSTAT, + REBOOTPWR_PAUSE, + REBOOTPWR_NUM_STATES, }; static void -rebootpwr_pause_cb(FpDevice *dev, - void *data) +rebootpwr_pause_cb (FpDevice *dev, + void *data) { - FpiSsm *ssm = data; - FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); + FpiSsm *ssm = data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); - if (!--self->rebootpwr_ctr) { - fp_err("could not reboot device power"); - fpi_ssm_mark_failed(ssm, - fpi_device_error_new_msg (FP_DEVICE_ERROR, - "Could not reboot device")); - } else { - fpi_ssm_jump_to_state(ssm, REBOOTPWR_GET_HWSTAT); - } + if (!--self->rebootpwr_ctr) + { + fp_err ("could not reboot device power"); + fpi_ssm_mark_failed (ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR, + "Could not reboot device")); + } + else + { + fpi_ssm_jump_to_state (ssm, REBOOTPWR_GET_HWSTAT); + } } -static void rebootpwr_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +rebootpwr_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - FpImageDevice *dev = user_data; - FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (_dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case REBOOTPWR_SET_HWSTAT: - self->rebootpwr_ctr = 100; - sm_set_hwstat(ssm, dev, self->last_hwstat & 0xf); - break; - case REBOOTPWR_GET_HWSTAT: - sm_read_reg(ssm, dev, REG_HWSTAT); - break; - case REBOOTPWR_CHECK_HWSTAT: - self->last_hwstat = self->last_reg_rd[0]; - if (self->last_hwstat & 0x1) - fpi_ssm_mark_completed(ssm); - else - fpi_ssm_next_state(ssm); - break; - case REBOOTPWR_PAUSE: - fpi_device_add_timeout(_dev, 10, rebootpwr_pause_cb, ssm); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case REBOOTPWR_SET_HWSTAT: + self->rebootpwr_ctr = 100; + sm_set_hwstat (ssm, dev, self->last_hwstat & 0xf); + break; + + case REBOOTPWR_GET_HWSTAT: + sm_read_reg (ssm, dev, REG_HWSTAT); + break; + + case REBOOTPWR_CHECK_HWSTAT: + self->last_hwstat = self->last_reg_rd[0]; + if (self->last_hwstat & 0x1) + fpi_ssm_mark_completed (ssm); + else + fpi_ssm_next_state (ssm); + break; + + case REBOOTPWR_PAUSE: + fpi_device_add_timeout (_dev, 10, rebootpwr_pause_cb, ssm); + break; + } } /* After messing with the device firmware in its low-power state, we have to @@ -827,523 +894,587 @@ static void rebootpwr_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) * * This is implemented as the powerup state machine below. Pseudo-code: - status = get_hwstat(); - for (i = 0; i < 100; i++) { - set_hwstat(status & 0xf); - if ((get_hwstat() & 0x80) == 0) - break; + status = get_hwstat(); + for (i = 0; i < 100; i++) { + set_hwstat(status & 0xf); + if ((get_hwstat() & 0x80) == 0) + break; - usleep(10000); - if (need_auth_cr) - auth_cr(); - } + usleep(10000); + if (need_auth_cr) + auth_cr(); + } - if (tmp & 0x80) - error("could not power up device"); + if (tmp & 0x80) + error("could not power up device"); */ enum powerup_states { - POWERUP_INIT = 0, - POWERUP_SET_HWSTAT, - POWERUP_GET_HWSTAT, - POWERUP_CHECK_HWSTAT, - POWERUP_PAUSE, - POWERUP_CHALLENGE_RESPONSE, - POWERUP_CHALLENGE_RESPONSE_SUCCESS, - POWERUP_NUM_STATES, + POWERUP_INIT = 0, + POWERUP_SET_HWSTAT, + POWERUP_GET_HWSTAT, + POWERUP_CHECK_HWSTAT, + POWERUP_PAUSE, + POWERUP_CHALLENGE_RESPONSE, + POWERUP_CHALLENGE_RESPONSE_SUCCESS, + POWERUP_NUM_STATES, }; static void -powerup_pause_cb(FpDevice *dev, - void *data) +powerup_pause_cb (FpDevice *dev, + void *data) { - FpiSsm *ssm = data; - FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); + FpiSsm *ssm = data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); - if (!--self->powerup_ctr) { - fp_err("could not power device up"); - fpi_ssm_mark_failed(ssm, - fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, - "could not power device up")); - } else if (!self->profile->auth_cr) { - fpi_ssm_jump_to_state(ssm, POWERUP_SET_HWSTAT); - } else { - fpi_ssm_next_state(ssm); - } + if (!--self->powerup_ctr) + { + fp_err ("could not power device up"); + fpi_ssm_mark_failed (ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "could not power device up")); + } + else if (!self->profile->auth_cr) + { + fpi_ssm_jump_to_state (ssm, POWERUP_SET_HWSTAT); + } + else + { + fpi_ssm_next_state (ssm); + } } -static void powerup_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +powerup_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - FpImageDevice *dev = user_data; - FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (_dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case POWERUP_INIT: - self->powerup_ctr = 100; - self->powerup_hwstat = self->last_hwstat & 0xf; - fpi_ssm_next_state(ssm); - break; - case POWERUP_SET_HWSTAT: - sm_set_hwstat(ssm, dev, self->powerup_hwstat); - break; - case POWERUP_GET_HWSTAT: - sm_read_reg(ssm, dev, REG_HWSTAT); - break; - case POWERUP_CHECK_HWSTAT: - self->last_hwstat = self->last_reg_rd[0]; - if ((self->last_reg_rd[0] & 0x80) == 0) - fpi_ssm_mark_completed(ssm); - else - fpi_ssm_next_state(ssm); - break; - case POWERUP_PAUSE: - fpi_device_add_timeout(_dev, 10, powerup_pause_cb, ssm); - break; - case POWERUP_CHALLENGE_RESPONSE: - sm_do_challenge_response(ssm, dev); - break; - case POWERUP_CHALLENGE_RESPONSE_SUCCESS: - fpi_ssm_jump_to_state(ssm, POWERUP_SET_HWSTAT); - break; - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case POWERUP_INIT: + self->powerup_ctr = 100; + self->powerup_hwstat = self->last_hwstat & 0xf; + fpi_ssm_next_state (ssm); + break; + + case POWERUP_SET_HWSTAT: + sm_set_hwstat (ssm, dev, self->powerup_hwstat); + break; + + case POWERUP_GET_HWSTAT: + sm_read_reg (ssm, dev, REG_HWSTAT); + break; + + case POWERUP_CHECK_HWSTAT: + self->last_hwstat = self->last_reg_rd[0]; + if ((self->last_reg_rd[0] & 0x80) == 0) + fpi_ssm_mark_completed (ssm); + else + fpi_ssm_next_state (ssm); + break; + + case POWERUP_PAUSE: + fpi_device_add_timeout (_dev, 10, powerup_pause_cb, ssm); + break; + + case POWERUP_CHALLENGE_RESPONSE: + sm_do_challenge_response (ssm, dev); + break; + + case POWERUP_CHALLENGE_RESPONSE_SUCCESS: + fpi_ssm_jump_to_state (ssm, POWERUP_SET_HWSTAT); + break; + } } /* * This is the main initialization state machine. As pseudo-code: - status = get_hwstat(); + status = get_hwstat(); - // correct device power state - if ((status & 0x84) == 0x84) - run_reboot_sm(); + // correct device power state + if ((status & 0x84) == 0x84) + run_reboot_sm(); - // power device down - if ((status & 0x80) == 0) - set_hwstat(status | 0x80); + // power device down + if ((status & 0x80) == 0) + set_hwstat(status | 0x80); - // power device up - run_powerup_sm(); - await_irq(IRQDATA_SCANPWR_ON); + // power device up + run_powerup_sm(); + await_irq(IRQDATA_SCANPWR_ON); */ enum init_states { - INIT_GET_HWSTAT = 0, - INIT_CHECK_HWSTAT_REBOOT, - INIT_REBOOT_POWER, - INIT_CHECK_HWSTAT_POWERDOWN, - INIT_POWERUP, - INIT_AWAIT_SCAN_POWER, - INIT_DONE, - INIT_GET_VERSION, - INIT_REPORT_VERSION, - INIT_NUM_STATES, + INIT_GET_HWSTAT = 0, + INIT_CHECK_HWSTAT_REBOOT, + INIT_REBOOT_POWER, + INIT_CHECK_HWSTAT_POWERDOWN, + INIT_POWERUP, + INIT_AWAIT_SCAN_POWER, + INIT_DONE, + INIT_GET_VERSION, + INIT_REPORT_VERSION, + INIT_NUM_STATES, }; -static void init_scanpwr_irq_cb(FpImageDevice *dev, GError *error, - uint16_t type, void *user_data) +static void +init_scanpwr_irq_cb (FpImageDevice *dev, GError *error, + uint16_t type, void *user_data) { - FpiSsm *ssm = user_data; - FpiDeviceUru4000 *urudev = FPI_DEVICE_URU4000 (dev); + FpiSsm *ssm = user_data; + FpiDeviceUru4000 *urudev = FPI_DEVICE_URU4000 (dev); - if (error) - fpi_ssm_mark_failed(ssm, error); - else if (type != IRQDATA_SCANPWR_ON) - fp_dbg("ignoring interrupt"); - else if (fpi_ssm_get_cur_state(ssm) != INIT_AWAIT_SCAN_POWER) { - fp_dbg("early scanpwr interrupt"); - urudev->scanpwr_irq_timeouts = -1; - } else { - fp_dbg("late scanpwr interrupt"); - fpi_ssm_next_state(ssm); - } + if (error) + { + fpi_ssm_mark_failed (ssm, error); + } + else if (type != IRQDATA_SCANPWR_ON) + { + fp_dbg ("ignoring interrupt"); + } + else if (fpi_ssm_get_cur_state (ssm) != INIT_AWAIT_SCAN_POWER) + { + fp_dbg ("early scanpwr interrupt"); + urudev->scanpwr_irq_timeouts = -1; + } + else + { + fp_dbg ("late scanpwr interrupt"); + fpi_ssm_next_state (ssm); + } } static void -init_scanpwr_timeout(FpDevice *dev, - void *user_data) +init_scanpwr_timeout (FpDevice *dev, + void *user_data) { - FpiSsm *ssm = user_data; - FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); + FpiSsm *ssm = user_data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); - fp_warn("powerup timed out"); - self->irq_cb = NULL; - self->scanpwr_irq_timeout = NULL; + fp_warn ("powerup timed out"); + self->irq_cb = NULL; + self->scanpwr_irq_timeout = NULL; - if (++self->scanpwr_irq_timeouts >= 3) { - fp_err("powerup timed out 3 times, giving up"); - fpi_ssm_mark_failed(ssm, - g_error_new_literal (G_USB_DEVICE_ERROR, - G_USB_DEVICE_ERROR_TIMED_OUT, - "Powerup timed out 3 times, giving up")); - } else { - fpi_ssm_jump_to_state(ssm, INIT_GET_HWSTAT); - } + if (++self->scanpwr_irq_timeouts >= 3) + { + fp_err ("powerup timed out 3 times, giving up"); + fpi_ssm_mark_failed (ssm, + g_error_new_literal (G_USB_DEVICE_ERROR, + G_USB_DEVICE_ERROR_TIMED_OUT, + "Powerup timed out 3 times, giving up")); + } + else + { + fpi_ssm_jump_to_state (ssm, INIT_GET_HWSTAT); + } } -static void init_run_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +init_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - FpImageDevice *dev = user_data; - FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(_dev); + FpImageDevice *dev = user_data; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (_dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case INIT_GET_HWSTAT: - sm_read_reg(ssm, dev, REG_HWSTAT); - break; - case INIT_CHECK_HWSTAT_REBOOT: - self->last_hwstat = self->last_reg_rd[0]; - if ((self->last_hwstat & 0x84) == 0x84) - fpi_ssm_next_state(ssm); - else - fpi_ssm_jump_to_state(ssm, INIT_CHECK_HWSTAT_POWERDOWN); - break; - case INIT_REBOOT_POWER: ; - FpiSsm *rebootsm = fpi_ssm_new(FP_DEVICE(dev), - rebootpwr_run_state, - REBOOTPWR_NUM_STATES, dev); - fpi_ssm_start_subsm(ssm, rebootsm); - break; - case INIT_CHECK_HWSTAT_POWERDOWN: - if ((self->last_hwstat & 0x80) == 0) - sm_set_hwstat(ssm, dev, self->last_hwstat | 0x80); - else - fpi_ssm_next_state(ssm); - break; - case INIT_POWERUP: - if (!IRQ_HANDLER_IS_RUNNING(self)) { - fpi_ssm_mark_failed(ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, - "IRQ handler should be running but is not")); - return; - } - self->irq_cb_data = ssm; - self->irq_cb = init_scanpwr_irq_cb; + switch (fpi_ssm_get_cur_state (ssm)) + { + case INIT_GET_HWSTAT: + sm_read_reg (ssm, dev, REG_HWSTAT); + break; - FpiSsm *powerupsm = fpi_ssm_new(FP_DEVICE(dev), - powerup_run_state, - POWERUP_NUM_STATES, dev); - fpi_ssm_start_subsm(ssm, powerupsm); - break; - case INIT_AWAIT_SCAN_POWER: - if (self->scanpwr_irq_timeouts < 0) { - fpi_ssm_next_state(ssm); - break; - } + case INIT_CHECK_HWSTAT_REBOOT: + self->last_hwstat = self->last_reg_rd[0]; + if ((self->last_hwstat & 0x84) == 0x84) + fpi_ssm_next_state (ssm); + else + fpi_ssm_jump_to_state (ssm, INIT_CHECK_HWSTAT_POWERDOWN); + break; - /* sometimes the 56aa interrupt that we are waiting for never arrives, - * so we include this timeout loop to retry the whole process 3 times - * if we don't get an irq any time soon. */ - self->scanpwr_irq_timeout = fpi_device_add_timeout(_dev, - 300, - init_scanpwr_timeout, - ssm); - break; - case INIT_DONE: - if (self->scanpwr_irq_timeout) { - g_source_destroy (self->scanpwr_irq_timeout); - self->scanpwr_irq_timeout = NULL; - } - self->irq_cb_data = NULL; - self->irq_cb = NULL; - fpi_ssm_next_state(ssm); - break; - case INIT_GET_VERSION: - sm_read_regs(ssm, dev, REG_DEVICE_INFO, 16); - break; - case INIT_REPORT_VERSION: - /* Likely hardware revision, and firmware version. - * Not sure which is which. */ - fp_info("Versions %02x%02x and %02x%02x", - self->last_reg_rd[10], self->last_reg_rd[11], - self->last_reg_rd[4], self->last_reg_rd[5]); - fpi_ssm_mark_completed(ssm); - break; - } + case INIT_REBOOT_POWER:; + FpiSsm *rebootsm = fpi_ssm_new (FP_DEVICE (dev), + rebootpwr_run_state, + REBOOTPWR_NUM_STATES, dev); + fpi_ssm_start_subsm (ssm, rebootsm); + break; + + case INIT_CHECK_HWSTAT_POWERDOWN: + if ((self->last_hwstat & 0x80) == 0) + sm_set_hwstat (ssm, dev, self->last_hwstat | 0x80); + else + fpi_ssm_next_state (ssm); + break; + + case INIT_POWERUP: + if (!IRQ_HANDLER_IS_RUNNING (self)) + { + fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "IRQ handler should be running but is not")); + return; + } + self->irq_cb_data = ssm; + self->irq_cb = init_scanpwr_irq_cb; + + FpiSsm *powerupsm = fpi_ssm_new (FP_DEVICE (dev), + powerup_run_state, + POWERUP_NUM_STATES, dev); + fpi_ssm_start_subsm (ssm, powerupsm); + break; + + case INIT_AWAIT_SCAN_POWER: + if (self->scanpwr_irq_timeouts < 0) + { + fpi_ssm_next_state (ssm); + break; + } + + /* sometimes the 56aa interrupt that we are waiting for never arrives, + * so we include this timeout loop to retry the whole process 3 times + * if we don't get an irq any time soon. */ + self->scanpwr_irq_timeout = fpi_device_add_timeout (_dev, + 300, + init_scanpwr_timeout, + ssm); + break; + + case INIT_DONE: + if (self->scanpwr_irq_timeout) + { + g_source_destroy (self->scanpwr_irq_timeout); + self->scanpwr_irq_timeout = NULL; + } + self->irq_cb_data = NULL; + self->irq_cb = NULL; + fpi_ssm_next_state (ssm); + break; + + case INIT_GET_VERSION: + sm_read_regs (ssm, dev, REG_DEVICE_INFO, 16); + break; + + case INIT_REPORT_VERSION: + /* Likely hardware revision, and firmware version. + * Not sure which is which. */ + fp_info ("Versions %02x%02x and %02x%02x", + self->last_reg_rd[10], self->last_reg_rd[11], + self->last_reg_rd[4], self->last_reg_rd[5]); + fpi_ssm_mark_completed (ssm); + break; + } } -static void activate_initsm_complete(FpiSsm *ssm, FpDevice *dev, - void *user_data, GError *error) +static void +activate_initsm_complete (FpiSsm *ssm, FpDevice *dev, + void *user_data, GError *error) { - fpi_image_device_activate_complete(FP_IMAGE_DEVICE (dev), error); + fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error); } -static void dev_activate(FpImageDevice *dev) +static void +dev_activate (FpImageDevice *dev) { - FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); - FpiSsm *ssm; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); + FpiSsm *ssm; - start_irq_handler(dev); + start_irq_handler (dev); - self->scanpwr_irq_timeouts = 0; - ssm = fpi_ssm_new(FP_DEVICE(dev), init_run_state, INIT_NUM_STATES, NULL); - fpi_ssm_start(ssm, activate_initsm_complete); + self->scanpwr_irq_timeouts = 0; + ssm = fpi_ssm_new (FP_DEVICE (dev), init_run_state, INIT_NUM_STATES, NULL); + fpi_ssm_start (ssm, activate_initsm_complete); } /***** DEINITIALIZATION *****/ -static void deactivate_irqs_stopped(FpImageDevice *dev) +static void +deactivate_irqs_stopped (FpImageDevice *dev) { - fpi_image_device_deactivate_complete(dev, NULL); + fpi_image_device_deactivate_complete (dev, NULL); } -static void deactivate_write_reg_cb(FpiUsbTransfer *transfer, FpDevice *dev, - gpointer user_data, GError *error) +static void +deactivate_write_reg_cb (FpiUsbTransfer *transfer, FpDevice *dev, + gpointer user_data, GError *error) { - stop_irq_handler(FP_IMAGE_DEVICE (dev), deactivate_irqs_stopped); + stop_irq_handler (FP_IMAGE_DEVICE (dev), deactivate_irqs_stopped); } -static void dev_deactivate(FpImageDevice *dev) +static void +dev_deactivate (FpImageDevice *dev) { - dev_change_state(dev, FP_IMAGE_DEVICE_STATE_INACTIVE); + dev_change_state (dev, FP_IMAGE_DEVICE_STATE_INACTIVE); } -static void execute_state_change(FpImageDevice *dev) +static void +execute_state_change (FpImageDevice *dev) { - FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); - FpiSsm *ssm; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); + FpiSsm *ssm; - switch (self->activate_state) { - case FP_IMAGE_DEVICE_STATE_INACTIVE: - fp_dbg("deactivating"); - self->irq_cb = NULL; - self->irq_cb_data = NULL; - write_reg(dev, REG_MODE, MODE_OFF, - deactivate_write_reg_cb, NULL); - break; + switch (self->activate_state) + { + case FP_IMAGE_DEVICE_STATE_INACTIVE: + fp_dbg ("deactivating"); + self->irq_cb = NULL; + self->irq_cb_data = NULL; + write_reg (dev, REG_MODE, MODE_OFF, + deactivate_write_reg_cb, NULL); + break; - case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: - fp_dbg("wait finger on"); - if (!IRQ_HANDLER_IS_RUNNING(self)) { - fpi_image_device_session_error (dev, - fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, - "IRQ handler should be running but is not")); - return; - } - self->irq_cb = finger_presence_irq_cb; - write_reg(dev, REG_MODE, MODE_AWAIT_FINGER_ON, - change_state_write_reg_cb, NULL); - break; + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: + fp_dbg ("wait finger on"); + if (!IRQ_HANDLER_IS_RUNNING (self)) + { + fpi_image_device_session_error (dev, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "IRQ handler should be running but is not")); + return; + } + self->irq_cb = finger_presence_irq_cb; + write_reg (dev, REG_MODE, MODE_AWAIT_FINGER_ON, + change_state_write_reg_cb, NULL); + break; - case FP_IMAGE_DEVICE_STATE_CAPTURE: - fp_dbg("starting capture"); - self->irq_cb = NULL; + case FP_IMAGE_DEVICE_STATE_CAPTURE: + fp_dbg ("starting capture"); + self->irq_cb = NULL; - ssm = fpi_ssm_new(FP_DEVICE(dev), imaging_run_state, - IMAGING_NUM_STATES, dev); - self->img_enc_seed = rand(); - self->img_transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); - self->img_transfer->ssm = ssm; - self->img_transfer->short_is_error = FALSE; - fpi_usb_transfer_fill_bulk(self->img_transfer, - EP_DATA, - sizeof(struct uru4k_image)); + ssm = fpi_ssm_new (FP_DEVICE (dev), imaging_run_state, + IMAGING_NUM_STATES, dev); + self->img_enc_seed = rand (); + self->img_transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + self->img_transfer->ssm = ssm; + self->img_transfer->short_is_error = FALSE; + fpi_usb_transfer_fill_bulk (self->img_transfer, + EP_DATA, + sizeof (struct uru4k_image)); - fpi_ssm_start(ssm, imaging_complete); + fpi_ssm_start (ssm, imaging_complete); - write_reg(dev, REG_MODE, MODE_CAPTURE, - change_state_write_reg_cb, NULL); - break; + write_reg (dev, REG_MODE, MODE_CAPTURE, + change_state_write_reg_cb, NULL); + break; - case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: - fp_dbg("await finger off"); - if (!IRQ_HANDLER_IS_RUNNING(self)) { - fpi_image_device_session_error (dev, - fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, - "IRQ handler should be running but is not")); - return; - } - self->irq_cb = finger_presence_irq_cb; - write_reg(dev, REG_MODE, MODE_AWAIT_FINGER_OFF, - change_state_write_reg_cb, NULL); - break; - } + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: + fp_dbg ("await finger off"); + if (!IRQ_HANDLER_IS_RUNNING (self)) + { + fpi_image_device_session_error (dev, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "IRQ handler should be running but is not")); + return; + } + self->irq_cb = finger_presence_irq_cb; + write_reg (dev, REG_MODE, MODE_AWAIT_FINGER_OFF, + change_state_write_reg_cb, NULL); + break; + } } /***** LIBRARY STUFF *****/ -static void dev_init(FpImageDevice *dev) +static void +dev_init (FpImageDevice *dev) { - GError *error = NULL; - FpiDeviceUru4000 *self; - g_autoptr(GPtrArray) interfaces = NULL; - GUsbInterface *iface = NULL; - guint64 driver_data; - SECStatus rv; - SECItem item; - int i; + GError *error = NULL; + FpiDeviceUru4000 *self; - interfaces = g_usb_device_get_interfaces (fpi_device_get_usb_device(FP_DEVICE(dev)), &error); - if (error) { - fpi_image_device_open_complete (dev, error); - return; - } + g_autoptr(GPtrArray) interfaces = NULL; + GUsbInterface *iface = NULL; + guint64 driver_data; + SECStatus rv; + SECItem item; + int i; - /* Find fingerprint interface; TODO: Move this into probe() */ - for (i = 0; i < interfaces->len; i++) { - GUsbInterface *cur_iface = g_ptr_array_index (interfaces, i); + interfaces = g_usb_device_get_interfaces (fpi_device_get_usb_device (FP_DEVICE (dev)), &error); + if (error) + { + fpi_image_device_open_complete (dev, error); + return; + } - if (g_usb_interface_get_class (cur_iface) == 255 && - g_usb_interface_get_subclass (cur_iface) == 255 && - g_usb_interface_get_protocol (cur_iface) == 255) { - iface = cur_iface; - break; - } - } + /* Find fingerprint interface; TODO: Move this into probe() */ + for (i = 0; i < interfaces->len; i++) + { + GUsbInterface *cur_iface = g_ptr_array_index (interfaces, i); - if (iface == NULL) { - fp_err("could not find interface"); - fpi_image_device_open_complete (dev, - fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, - "Could not find interface")); - return; - } + if (g_usb_interface_get_class (cur_iface) == 255 && + g_usb_interface_get_subclass (cur_iface) == 255 && + g_usb_interface_get_protocol (cur_iface) == 255) + { + iface = cur_iface; + break; + } + } - /* TODO: Find/check endpoints; does not seem easily possible with GUsb unfortunately! */ + if (iface == NULL) + { + fp_err ("could not find interface"); + fpi_image_device_open_complete (dev, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Could not find interface")); + return; + } + + /* TODO: Find/check endpoints; does not seem easily possible with GUsb unfortunately! */ #if 0 - if (iface_desc->bNumEndpoints != 2) { - fp_err("found %d endpoints!?", iface_desc->bNumEndpoints); - r = -ENODEV; - goto out; - } + if (iface_desc->bNumEndpoints != 2) + { + fp_err ("found %d endpoints!?", iface_desc->bNumEndpoints); + r = -ENODEV; + goto out; + } - ep = &iface_desc->endpoint[0]; - if (ep->bEndpointAddress != EP_INTR - || (ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) != - LIBUSB_TRANSFER_TYPE_INTERRUPT) { - fp_err("unrecognised interrupt endpoint"); - r = -ENODEV; - goto out; - } + ep = &iface_desc->endpoint[0]; + if (ep->bEndpointAddress != EP_INTR || + (ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) != + LIBUSB_TRANSFER_TYPE_INTERRUPT) + { + fp_err ("unrecognised interrupt endpoint"); + r = -ENODEV; + goto out; + } - ep = &iface_desc->endpoint[1]; - if (ep->bEndpointAddress != EP_DATA - || (ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) != - LIBUSB_TRANSFER_TYPE_BULK) { - fp_err("unrecognised bulk endpoint"); - r = -ENODEV; - goto out; - } + ep = &iface_desc->endpoint[1]; + if (ep->bEndpointAddress != EP_DATA || + (ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) != + LIBUSB_TRANSFER_TYPE_BULK) + { + fp_err ("unrecognised bulk endpoint"); + r = -ENODEV; + goto out; + } #endif - /* Device looks like a supported reader */ + /* Device looks like a supported reader */ - if (!g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), - g_usb_interface_get_number (iface), 0, &error)) { - fpi_image_device_open_complete(dev, error); - return; - } + if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), + g_usb_interface_get_number (iface), 0, &error)) + { + fpi_image_device_open_complete (dev, error); + return; + } - /* Disable loading p11-kit's user configuration */ - g_setenv ("P11_KIT_NO_USER_CONFIG", "1", TRUE); + /* Disable loading p11-kit's user configuration */ + g_setenv ("P11_KIT_NO_USER_CONFIG", "1", TRUE); - /* Initialise NSS early */ - rv = NSS_NoDB_Init("."); - if (rv != SECSuccess) { - fp_err("could not initialise NSS"); - fpi_image_device_open_complete (dev, - fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, - "Could not initialise NSS")); - return; - } + /* Initialise NSS early */ + rv = NSS_NoDB_Init ("."); + if (rv != SECSuccess) + { + fp_err ("could not initialise NSS"); + fpi_image_device_open_complete (dev, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Could not initialise NSS")); + return; + } - self = FPI_DEVICE_URU4000(dev); + self = FPI_DEVICE_URU4000 (dev); - driver_data = fpi_device_get_driver_data (FP_DEVICE (dev)); - self->profile = &uru4k_dev_info[driver_data]; - self->interface = g_usb_interface_get_number (iface); + driver_data = fpi_device_get_driver_data (FP_DEVICE (dev)); + self->profile = &uru4k_dev_info[driver_data]; + self->interface = g_usb_interface_get_number (iface); - /* Set up encryption */ - self->cipher = CKM_AES_ECB; - self->slot = PK11_GetBestSlot(self->cipher, NULL); - if (self->slot == NULL) { - fp_err("could not get encryption slot"); - fpi_image_device_open_complete (dev, - fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, - "Could not get encryption slot")); - return; - } - item.type = siBuffer; - item.data = (unsigned char*) crkey; - item.len = sizeof(crkey); - self->symkey = PK11_ImportSymKey(self->slot, - self->cipher, - PK11_OriginUnwrap, - CKA_ENCRYPT, - &item, NULL); - if (self->symkey == NULL) { - fp_err("failed to import key into NSS"); - PK11_FreeSlot(self->slot); - self->slot = NULL; - fpi_image_device_open_complete (dev, - fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, - "Failed to import key into NSS")); - return; - } - self->param = PK11_ParamFromIV(self->cipher, NULL); + /* Set up encryption */ + self->cipher = CKM_AES_ECB; + self->slot = PK11_GetBestSlot (self->cipher, NULL); + if (self->slot == NULL) + { + fp_err ("could not get encryption slot"); + fpi_image_device_open_complete (dev, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Could not get encryption slot")); + return; + } + item.type = siBuffer; + item.data = (unsigned char *) crkey; + item.len = sizeof (crkey); + self->symkey = PK11_ImportSymKey (self->slot, + self->cipher, + PK11_OriginUnwrap, + CKA_ENCRYPT, + &item, NULL); + if (self->symkey == NULL) + { + fp_err ("failed to import key into NSS"); + PK11_FreeSlot (self->slot); + self->slot = NULL; + fpi_image_device_open_complete (dev, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, + "Failed to import key into NSS")); + return; + } + self->param = PK11_ParamFromIV (self->cipher, NULL); - fpi_image_device_open_complete(dev, NULL); + fpi_image_device_open_complete (dev, NULL); } -static void dev_deinit(FpImageDevice *dev) +static void +dev_deinit (FpImageDevice *dev) { - GError *error = NULL; - FpiDeviceUru4000 *self = FPI_DEVICE_URU4000(dev); - if (self->symkey) - PK11_FreeSymKey (self->symkey); - if (self->param) - SECITEM_FreeItem(self->param, PR_TRUE); - if (self->slot) - PK11_FreeSlot(self->slot); - g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), - self->interface, 0, &error); - fpi_image_device_close_complete(dev, error); + GError *error = NULL; + FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); + + if (self->symkey) + PK11_FreeSymKey (self->symkey); + if (self->param) + SECITEM_FreeItem (self->param, PR_TRUE); + if (self->slot) + PK11_FreeSlot (self->slot); + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), + self->interface, 0, &error); + fpi_image_device_close_complete (dev, error); } -static const FpIdEntry id_table [ ] = { - /* ms kbd with fp rdr */ - { .vid = 0x045e, .pid = 0x00bb, .driver_data = MS_KBD }, +static const FpIdEntry id_table[] = { + /* ms kbd with fp rdr */ + { .vid = 0x045e, .pid = 0x00bb, .driver_data = MS_KBD }, - /* ms intellimouse with fp rdr */ - { .vid = 0x045e, .pid = 0x00bc, .driver_data = MS_INTELLIMOUSE }, + /* ms intellimouse with fp rdr */ + { .vid = 0x045e, .pid = 0x00bc, .driver_data = MS_INTELLIMOUSE }, - /* ms fp rdr (standalone) */ - { .vid = 0x045e, .pid = 0x00bd, .driver_data = MS_STANDALONE }, + /* ms fp rdr (standalone) */ + { .vid = 0x045e, .pid = 0x00bd, .driver_data = MS_STANDALONE }, - /* ms fp rdr (standalone) v2 */ - { .vid = 0x045e, .pid = 0x00ca, .driver_data = MS_STANDALONE_V2 }, + /* ms fp rdr (standalone) v2 */ + { .vid = 0x045e, .pid = 0x00ca, .driver_data = MS_STANDALONE_V2 }, - /* dp uru4000 (standalone) */ - { .vid = 0x05ba, .pid = 0x0007, .driver_data = DP_URU4000 }, + /* dp uru4000 (standalone) */ + { .vid = 0x05ba, .pid = 0x0007, .driver_data = DP_URU4000 }, - /* dp uru4000 (keyboard) */ - { .vid = 0x05ba, .pid = 0x0008, .driver_data = DP_URU4000 }, + /* dp uru4000 (keyboard) */ + { .vid = 0x05ba, .pid = 0x0008, .driver_data = DP_URU4000 }, - /* dp uru4000b (standalone) */ - { .vid = 0x05ba, .pid = 0x000a, .driver_data = DP_URU4000B }, + /* dp uru4000b (standalone) */ + { .vid = 0x05ba, .pid = 0x000a, .driver_data = DP_URU4000B }, - /* terminating entry */ - { .vid = 0, .pid = 0, .driver_data = 0 }, + /* terminating entry */ + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -static void fpi_device_uru4000_init(FpiDeviceUru4000 *self) { +static void +fpi_device_uru4000_init (FpiDeviceUru4000 *self) +{ } -static void fpi_device_uru4000_class_init(FpiDeviceUru4000Class *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); +static void +fpi_device_uru4000_class_init (FpiDeviceUru4000Class *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); - dev_class->id = "uru4000"; - dev_class->full_name = "Digital Persona U.are.U 4000/4000B/4500"; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->id_table = id_table; - dev_class->scan_type = FP_SCAN_TYPE_PRESS; + dev_class->id = "uru4000"; + dev_class->full_name = "Digital Persona U.are.U 4000/4000B/4500"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_PRESS; - img_class->img_open = dev_init; - img_class->img_close = dev_deinit; - img_class->activate = dev_activate; - img_class->deactivate = dev_deactivate; - img_class->change_state = dev_change_state; + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; + img_class->change_state = dev_change_state; - img_class->img_width = IMAGE_WIDTH; - img_class->img_height = IMAGE_HEIGHT; + img_class->img_width = IMAGE_WIDTH; + img_class->img_height = IMAGE_HEIGHT; } - diff --git a/libfprint/drivers/vcom5s.c b/libfprint/drivers/vcom5s.c index c97c4196..74e7bdbe 100644 --- a/libfprint/drivers/vcom5s.c +++ b/libfprint/drivers/vcom5s.c @@ -28,109 +28,112 @@ * powerdown? does windows do anything special on exit? */ -#define CTRL_TIMEOUT 1000 -#define EP_IN (1 | FPI_USB_ENDPOINT_IN) +#define CTRL_TIMEOUT 1000 +#define EP_IN (1 | FPI_USB_ENDPOINT_IN) -#define IMG_WIDTH 300 -#define IMG_HEIGHT 288 -#define ROWS_PER_RQ 12 -#define NR_REQS (IMG_HEIGHT / ROWS_PER_RQ) -#define RQ_SIZE (IMG_WIDTH * ROWS_PER_RQ) -#define IMG_SIZE (IMG_WIDTH * IMG_HEIGHT) +#define IMG_WIDTH 300 +#define IMG_HEIGHT 288 +#define ROWS_PER_RQ 12 +#define NR_REQS (IMG_HEIGHT / ROWS_PER_RQ) +#define RQ_SIZE (IMG_WIDTH * ROWS_PER_RQ) +#define IMG_SIZE (IMG_WIDTH * IMG_HEIGHT) -struct _FpDeviceVcom5s { - FpImageDevice parent; +struct _FpDeviceVcom5s +{ + FpImageDevice parent; - int capture_iteration; - FpImage *capture_img; - gboolean loop_running; - gboolean deactivating; + int capture_iteration; + FpImage *capture_img; + gboolean loop_running; + gboolean deactivating; }; -G_DECLARE_FINAL_TYPE(FpDeviceVcom5s, fpi_device_vcom5s, FPI, DEVICE_VCOM5S, - FpImageDevice); -G_DEFINE_TYPE(FpDeviceVcom5s, fpi_device_vcom5s, FP_TYPE_IMAGE_DEVICE); +G_DECLARE_FINAL_TYPE (FpDeviceVcom5s, fpi_device_vcom5s, FPI, DEVICE_VCOM5S, + FpImageDevice); +G_DEFINE_TYPE (FpDeviceVcom5s, fpi_device_vcom5s, FP_TYPE_IMAGE_DEVICE); enum v5s_regs { - /* when using gain 0x29: - * a value of 0x00 produces mostly-black image - * 0x09 destroys ridges (too white) - * 0x01 or 0x02 seem good values */ - REG_CONTRAST = 0x02, + /* when using gain 0x29: + * a value of 0x00 produces mostly-black image + * 0x09 destroys ridges (too white) + * 0x01 or 0x02 seem good values */ + REG_CONTRAST = 0x02, - /* when using contrast 0x01: - * a value of 0x00 will produce an all-black image. - * 0x29 produces a good contrast image: ridges quite dark, but some - * light grey noise as background - * 0x46 produces all-white image with grey ridges (not very dark) */ - REG_GAIN = 0x03, + /* when using contrast 0x01: + * a value of 0x00 will produce an all-black image. + * 0x29 produces a good contrast image: ridges quite dark, but some + * light grey noise as background + * 0x46 produces all-white image with grey ridges (not very dark) */ + REG_GAIN = 0x03, }; enum v5s_cmd { - /* scan one row. has parameter, at a guess this is which row to scan? */ - CMD_SCAN_ONE_ROW = 0xc0, + /* scan one row. has parameter, at a guess this is which row to scan? */ + CMD_SCAN_ONE_ROW = 0xc0, - /* scan whole image */ - CMD_SCAN = 0xc1, + /* scan whole image */ + CMD_SCAN = 0xc1, }; /***** REGISTER I/O *****/ -static void sm_write_reg_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +sm_write_reg_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - if (error) - fpi_ssm_mark_failed(transfer->ssm, error); - else - fpi_ssm_next_state(transfer->ssm); + if (error) + fpi_ssm_mark_failed (transfer->ssm, error); + else + fpi_ssm_next_state (transfer->ssm); } static void -sm_write_reg(FpiSsm *ssm, - FpDevice *dev, - unsigned char reg, - unsigned char value) +sm_write_reg (FpiSsm *ssm, + FpDevice *dev, + unsigned char reg, + unsigned char value) { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); + FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev); - fp_dbg("set %02x=%02x", reg, value); - fpi_usb_transfer_fill_control(transfer, - G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, - G_USB_DEVICE_REQUEST_TYPE_VENDOR, - G_USB_DEVICE_RECIPIENT_DEVICE, - reg, value, 0, 0); - transfer->ssm = ssm; - fpi_usb_transfer_submit(transfer, CTRL_TIMEOUT, NULL, sm_write_reg_cb, - NULL); - fpi_usb_transfer_unref(transfer); -} - -static void sm_exec_cmd_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) -{ - if (error) - fpi_ssm_mark_failed(transfer->ssm, error); - else - fpi_ssm_next_state(transfer->ssm); + fp_dbg ("set %02x=%02x", reg, value); + fpi_usb_transfer_fill_control (transfer, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + reg, value, 0, 0); + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, sm_write_reg_cb, + NULL); + fpi_usb_transfer_unref (transfer); } static void -sm_exec_cmd(FpiSsm *ssm, - FpDevice *dev, - unsigned char cmd, - unsigned char param) +sm_exec_cmd_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); + if (error) + fpi_ssm_mark_failed (transfer->ssm, error); + else + fpi_ssm_next_state (transfer->ssm); +} - fp_dbg("cmd %02x param %02x", cmd, param); - fpi_usb_transfer_fill_control(transfer, - G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, - G_USB_DEVICE_REQUEST_TYPE_VENDOR, - G_USB_DEVICE_RECIPIENT_DEVICE, - cmd, param, 0, 0); - transfer->ssm = ssm; - fpi_usb_transfer_submit(transfer, CTRL_TIMEOUT, NULL, sm_exec_cmd_cb, - NULL); - fpi_usb_transfer_unref(transfer); +static void +sm_exec_cmd (FpiSsm *ssm, + FpDevice *dev, + unsigned char cmd, + unsigned char param) +{ + FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev); + + fp_dbg ("cmd %02x param %02x", cmd, param); + fpi_usb_transfer_fill_control (transfer, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + cmd, param, 0, 0); + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, sm_exec_cmd_cb, + NULL); + fpi_usb_transfer_unref (transfer); } /***** FINGER DETECTION *****/ @@ -145,217 +148,246 @@ sm_exec_cmd(FpiSsm *ssm, #define DETBOX_COL_END (DETBOX_COL_START + DETBOX_COLS) #define FINGER_PRESENCE_THRESHOLD 100 -static gboolean finger_is_present(unsigned char *data) +static gboolean +finger_is_present (unsigned char *data) { - int row; - guint16 imgavg = 0; + int row; + guint16 imgavg = 0; - for (row = DETBOX_ROW_START; row < DETBOX_ROW_END; row++) { - unsigned char *rowdata = data + (row * IMG_WIDTH); - guint16 rowavg = 0; - int col; + for (row = DETBOX_ROW_START; row < DETBOX_ROW_END; row++) + { + unsigned char *rowdata = data + (row * IMG_WIDTH); + guint16 rowavg = 0; + int col; - for (col = DETBOX_COL_START; col < DETBOX_COL_END; col++) - rowavg += rowdata[col]; - rowavg /= DETBOX_COLS; - imgavg += rowavg; - } - imgavg /= DETBOX_ROWS; - fp_dbg("img avg %d", imgavg); + for (col = DETBOX_COL_START; col < DETBOX_COL_END; col++) + rowavg += rowdata[col]; + rowavg /= DETBOX_COLS; + imgavg += rowavg; + } + imgavg /= DETBOX_ROWS; + fp_dbg ("img avg %d", imgavg); - return (imgavg <= FINGER_PRESENCE_THRESHOLD); + return imgavg <= FINGER_PRESENCE_THRESHOLD; } /***** IMAGE ACQUISITION *****/ -static void capture_iterate(FpiSsm *ssm, FpDevice *dev); +static void capture_iterate (FpiSsm *ssm, + FpDevice *dev); -static void capture_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +capture_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpImageDevice *imgdev = FP_IMAGE_DEVICE(device); - FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S(device); + FpImageDevice *imgdev = FP_IMAGE_DEVICE (device); + FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (device); - if (error) { - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } + if (error) + { + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } - if (++self->capture_iteration == NR_REQS) { - FpImage *img = self->capture_img; - /* must clear this early, otherwise the call chain takes us into - * loopsm_complete where we would free it, when in fact we are - * supposed to be handing off this image */ - self->capture_img = NULL; + if (++self->capture_iteration == NR_REQS) + { + FpImage *img = self->capture_img; + /* must clear this early, otherwise the call chain takes us into + * loopsm_complete where we would free it, when in fact we are + * supposed to be handing off this image */ + self->capture_img = NULL; - fpi_image_device_report_finger_status(imgdev, - finger_is_present(img->data)); - fpi_image_device_image_captured(imgdev, img); - fpi_ssm_next_state(transfer->ssm); - } else { - capture_iterate(transfer->ssm, device); - } + fpi_image_device_report_finger_status (imgdev, + finger_is_present (img->data)); + fpi_image_device_image_captured (imgdev, img); + fpi_ssm_next_state (transfer->ssm); + } + else + { + capture_iterate (transfer->ssm, device); + } } static void -capture_iterate(FpiSsm *ssm, - FpDevice *dev) +capture_iterate (FpiSsm *ssm, + FpDevice *dev) { - FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S(dev); - int iteration = self->capture_iteration; - FpiUsbTransfer *transfer = fpi_usb_transfer_new(FP_DEVICE(dev)); + FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev); + int iteration = self->capture_iteration; + FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_fill_bulk_full (transfer, - EP_IN, - self->capture_img->data + (RQ_SIZE * iteration), - RQ_SIZE, - NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk_full (transfer, + EP_IN, + self->capture_img->data + (RQ_SIZE * iteration), + RQ_SIZE, + NULL); - fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, capture_cb, NULL); - fpi_usb_transfer_unref (transfer); + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, capture_cb, NULL); + fpi_usb_transfer_unref (transfer); } static void -sm_do_capture(FpiSsm *ssm, - FpDevice *dev) +sm_do_capture (FpiSsm *ssm, + FpDevice *dev) { - FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S(dev); - FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (dev); + FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev); + FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (dev); - G_DEBUG_HERE(); - self->capture_img = fp_image_new (cls->img_width, cls->img_height); - self->capture_iteration = 0; - capture_iterate(ssm, dev); + G_DEBUG_HERE (); + self->capture_img = fp_image_new (cls->img_width, cls->img_height); + self->capture_iteration = 0; + capture_iterate (ssm, dev); } /***** CAPTURE LOOP *****/ enum loop_states { - LOOP_SET_CONTRAST, - LOOP_SET_GAIN, - LOOP_CMD_SCAN, - LOOP_CAPTURE, - LOOP_CAPTURE_DONE, - LOOP_NUM_STATES, + LOOP_SET_CONTRAST, + LOOP_SET_GAIN, + LOOP_CMD_SCAN, + LOOP_CAPTURE, + LOOP_CAPTURE_DONE, + LOOP_NUM_STATES, }; -static void loop_run_state(FpiSsm *ssm, FpDevice *dev, void *user_data) +static void +loop_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) { - FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S(dev); + FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case LOOP_SET_CONTRAST: - sm_write_reg(ssm, dev, REG_CONTRAST, 0x01); - break; - case LOOP_SET_GAIN: - sm_write_reg(ssm, dev, REG_GAIN, 0x29); - break; - case LOOP_CMD_SCAN: - if (self->deactivating) { - fp_dbg("deactivating, marking completed"); - fpi_ssm_mark_completed(ssm); - } else - sm_exec_cmd(ssm, dev, CMD_SCAN, 0x00); - break; - case LOOP_CAPTURE: - sm_do_capture(ssm, dev); - break; - case LOOP_CAPTURE_DONE: - fpi_ssm_jump_to_state(ssm, LOOP_CMD_SCAN); - break; - default: - g_assert_not_reached (); - } + switch (fpi_ssm_get_cur_state (ssm)) + { + case LOOP_SET_CONTRAST: + sm_write_reg (ssm, dev, REG_CONTRAST, 0x01); + break; + + case LOOP_SET_GAIN: + sm_write_reg (ssm, dev, REG_GAIN, 0x29); + break; + + case LOOP_CMD_SCAN: + if (self->deactivating) + { + fp_dbg ("deactivating, marking completed"); + fpi_ssm_mark_completed (ssm); + } + else + { + sm_exec_cmd (ssm, dev, CMD_SCAN, 0x00); + } + break; + + case LOOP_CAPTURE: + sm_do_capture (ssm, dev); + break; + + case LOOP_CAPTURE_DONE: + fpi_ssm_jump_to_state (ssm, LOOP_CMD_SCAN); + break; + + default: + g_assert_not_reached (); + } } -static void loopsm_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +static void +loopsm_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - FpImageDevice *imgdev = FP_IMAGE_DEVICE (dev); - FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S(dev); + FpImageDevice *imgdev = FP_IMAGE_DEVICE (dev); + FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev); - fpi_ssm_free(ssm); - g_object_unref (self->capture_img); - self->capture_img = NULL; - self->loop_running = FALSE; + fpi_ssm_free (ssm); + g_object_unref (self->capture_img); + self->capture_img = NULL; + self->loop_running = FALSE; - if (error && !self->deactivating) - fpi_image_device_session_error(imgdev, error); - else if (error) - g_error_free (error); + if (error && !self->deactivating) + fpi_image_device_session_error (imgdev, error); + else if (error) + g_error_free (error); - if (self->deactivating) - fpi_image_device_deactivate_complete(imgdev, NULL); + if (self->deactivating) + fpi_image_device_deactivate_complete (imgdev, NULL); } -static void dev_activate(FpImageDevice *dev) +static void +dev_activate (FpImageDevice *dev) { - FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S(dev); - FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(dev), loop_run_state, - LOOP_NUM_STATES, dev); - self->deactivating = FALSE; - fpi_ssm_start(ssm, loopsm_complete); - self->loop_running = TRUE; - fpi_image_device_activate_complete(dev, NULL); + FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev); + FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), loop_run_state, + LOOP_NUM_STATES, dev); + + self->deactivating = FALSE; + fpi_ssm_start (ssm, loopsm_complete); + self->loop_running = TRUE; + fpi_image_device_activate_complete (dev, NULL); } -static void dev_deactivate(FpImageDevice *dev) +static void +dev_deactivate (FpImageDevice *dev) { - FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S(dev); - if (self->loop_running) - self->deactivating = TRUE; - else - fpi_image_device_deactivate_complete(dev, NULL); + FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev); + + if (self->loop_running) + self->deactivating = TRUE; + else + fpi_image_device_deactivate_complete (dev, NULL); } -static void dev_init(FpImageDevice *dev) +static void +dev_init (FpImageDevice *dev) { - GError *error = NULL; + GError *error = NULL; - g_usb_device_claim_interface (fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error); + g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error); - fpi_image_device_open_complete(dev, error); + fpi_image_device_open_complete (dev, error); } -static void dev_deinit(FpImageDevice *dev) +static void +dev_deinit (FpImageDevice *dev) { - GError *error = NULL; + GError *error = NULL; - g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), - 0, 0, &error); + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), + 0, 0, &error); - fpi_image_device_close_complete(dev, error); + fpi_image_device_close_complete (dev, error); } -static const FpIdEntry id_table [ ] = { - { .vid = 0x061a, .pid = 0x0110, }, - { .vid = 0, .pid = 0, .driver_data = 0 }, +static const FpIdEntry id_table[] = { + { .vid = 0x061a, .pid = 0x0110, }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -static void fpi_device_vcom5s_init(FpDeviceVcom5s *self) { +static void +fpi_device_vcom5s_init (FpDeviceVcom5s *self) +{ } -static void fpi_device_vcom5s_class_init(FpDeviceVcom5sClass *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); +static void +fpi_device_vcom5s_class_init (FpDeviceVcom5sClass *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); - dev_class->id = "vcom5s"; - dev_class->full_name = "Veridicom 5thSense"; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->id_table = id_table; - dev_class->scan_type = FP_SCAN_TYPE_PRESS; + dev_class->id = "vcom5s"; + dev_class->full_name = "Veridicom 5thSense"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_PRESS; - img_class->img_open = dev_init; - img_class->img_close = dev_deinit; - img_class->activate = dev_activate; - img_class->deactivate = dev_deactivate; + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; - img_class->img_width = IMG_WIDTH; - img_class->img_height = IMG_HEIGHT; + img_class->img_width = IMG_WIDTH; + img_class->img_height = IMG_HEIGHT; } - diff --git a/libfprint/drivers/vfs0050.c b/libfprint/drivers/vfs0050.c index aa47ec44..399be86c 100644 --- a/libfprint/drivers/vfs0050.c +++ b/libfprint/drivers/vfs0050.c @@ -27,703 +27,762 @@ G_DEFINE_TYPE (FpDeviceVfs0050, fpi_device_vfs0050, FP_TYPE_IMAGE_DEVICE) /* USB functions */ /* Callback for async_write */ -static void async_write_callback(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +async_write_callback (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - if (error) { - fp_err("USB write transfer: %s", error->message); - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } + if (error) + { + fp_err ("USB write transfer: %s", error->message); + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } - fpi_ssm_next_state(transfer->ssm); + fpi_ssm_next_state (transfer->ssm); } /* Send data to EP1, the only out endpoint */ static void -async_write(FpiSsm *ssm, - FpDevice *dev, - void *data, - int len) +async_write (FpiSsm *ssm, + FpDevice *dev, + void *data, + int len) { - FpiUsbTransfer *transfer; + FpiUsbTransfer *transfer; - transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); - fpi_usb_transfer_fill_bulk_full(transfer, 0x01, data, len, NULL); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit(transfer, VFS_USB_TIMEOUT, NULL, - async_write_callback, NULL); - fpi_usb_transfer_unref(transfer); + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + fpi_usb_transfer_fill_bulk_full (transfer, 0x01, data, len, NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, VFS_USB_TIMEOUT, NULL, + async_write_callback, NULL); + fpi_usb_transfer_unref (transfer); } /* Callback for async_read */ -static void async_read_callback(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +async_read_callback (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - int ep = transfer->endpoint; + int ep = transfer->endpoint; - if (error) { - fp_err("USB read transfer on endpoint %d: %s", ep - 0x80, - error->message); - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } + if (error) + { + fp_err ("USB read transfer on endpoint %d: %s", ep - 0x80, + error->message); + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } - fpi_ssm_next_state(transfer->ssm); + fpi_ssm_next_state (transfer->ssm); } /* Receive data from the given ep and either discard or fill the given buffer */ static void -async_read(FpiSsm *ssm, - FpDevice *dev, - int ep, - void *data, - int len) +async_read (FpiSsm *ssm, + FpDevice *dev, + int ep, + void *data, + int len) { - FpiUsbTransfer *transfer; - GDestroyNotify free_func = NULL; + FpiUsbTransfer *transfer; + GDestroyNotify free_func = NULL; - ep |= FPI_USB_ENDPOINT_IN; + ep |= FPI_USB_ENDPOINT_IN; - transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; - if (data == NULL) { - data = g_malloc0 (len); - free_func = g_free; - } + if (data == NULL) + { + data = g_malloc0 (len); + free_func = g_free; + } - /* 0x83 is the only interrupt endpoint */ - if (ep == EP3_IN) - fpi_usb_transfer_fill_interrupt_full(transfer, ep, data, len, free_func); - else - fpi_usb_transfer_fill_bulk_full(transfer, ep, data, len, free_func); + /* 0x83 is the only interrupt endpoint */ + if (ep == EP3_IN) + fpi_usb_transfer_fill_interrupt_full (transfer, ep, data, len, free_func); + else + fpi_usb_transfer_fill_bulk_full (transfer, ep, data, len, free_func); - fpi_usb_transfer_submit(transfer, VFS_USB_TIMEOUT, NULL, - async_read_callback, NULL); - fpi_usb_transfer_unref(transfer); + fpi_usb_transfer_submit (transfer, VFS_USB_TIMEOUT, NULL, + async_read_callback, NULL); + fpi_usb_transfer_unref (transfer); } /* Callback for async_abort */ -static void async_abort_callback(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +async_abort_callback (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - int ep = transfer->endpoint; + int ep = transfer->endpoint; - /* In normal case endpoint is empty */ - if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT)) { - g_free (error); - fpi_ssm_next_state(transfer->ssm); - return; - } + /* In normal case endpoint is empty */ + if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT)) + { + g_free (error); + fpi_ssm_next_state (transfer->ssm); + return; + } - if (error) { - fp_err("USB write transfer: %s", error->message); - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } + if (error) + { + fp_err ("USB write transfer: %s", error->message); + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } - /* Don't stop process, only print warning */ - fp_warn("Endpoint %d had extra %zd bytes readable", ep - 0x80, - transfer->actual_length); + /* Don't stop process, only print warning */ + fp_warn ("Endpoint %d had extra %zd bytes readable", ep - 0x80, + transfer->actual_length); - fpi_ssm_jump_to_state(transfer->ssm, - fpi_ssm_get_cur_state(transfer->ssm)); + fpi_ssm_jump_to_state (transfer->ssm, + fpi_ssm_get_cur_state (transfer->ssm)); } /* Receive data from the given ep; continues to the next state once no * more data is available. Otherwise the current state is repeated. */ -static void async_abort(FpDevice *dev, FpiSsm *ssm, int ep) +static void +async_abort (FpDevice *dev, FpiSsm *ssm, int ep) { - FpiUsbTransfer *transfer; + FpiUsbTransfer *transfer; - ep |= FPI_USB_ENDPOINT_IN; + ep |= FPI_USB_ENDPOINT_IN; - transfer = fpi_usb_transfer_new (dev); + transfer = fpi_usb_transfer_new (dev); - /* 0x83 is the only interrupt endpoint */ - if (ep == EP3_IN) - fpi_usb_transfer_fill_interrupt (transfer, ep, VFS_USB_BUFFER_SIZE); - else - fpi_usb_transfer_fill_bulk (transfer, ep, VFS_USB_BUFFER_SIZE); + /* 0x83 is the only interrupt endpoint */ + if (ep == EP3_IN) + fpi_usb_transfer_fill_interrupt (transfer, ep, VFS_USB_BUFFER_SIZE); + else + fpi_usb_transfer_fill_bulk (transfer, ep, VFS_USB_BUFFER_SIZE); - fpi_usb_transfer_submit(transfer, VFS_USB_ABORT_TIMEOUT, NULL, - async_abort_callback, NULL); - fpi_usb_transfer_unref(transfer); + fpi_usb_transfer_submit (transfer, VFS_USB_ABORT_TIMEOUT, NULL, + async_abort_callback, NULL); + fpi_usb_transfer_unref (transfer); } /* Image processing functions */ /* Pixel getter for fpi_assemble_lines */ -static unsigned char vfs0050_get_pixel(struct fpi_line_asmbl_ctx *ctx, - GSList * line, unsigned int x) +static unsigned char +vfs0050_get_pixel (struct fpi_line_asmbl_ctx *ctx, + GSList * line, unsigned int x) { - return ((struct vfs_line *)line->data)->data[x]; + return ((struct vfs_line *) line->data)->data[x]; } /* Deviation getter for fpi_assemble_lines */ -static int vfs0050_get_difference(struct fpi_line_asmbl_ctx *ctx, - GSList * line_list_1, GSList * line_list_2) +static int +vfs0050_get_difference (struct fpi_line_asmbl_ctx *ctx, + GSList * line_list_1, GSList * line_list_2) { - struct vfs_line *line1 = line_list_1->data; - struct vfs_line *line2 = line_list_2->data; - const int shift = (VFS_IMAGE_WIDTH - VFS_NEXT_LINE_WIDTH) / 2 - 1; - int res = 0; - for (int i = 0; i < VFS_NEXT_LINE_WIDTH; ++i) { - int x = - (int)line1->next_line_part[i] - (int)line2->data[shift + i]; - res += x * x; - } - return res; + struct vfs_line *line1 = line_list_1->data; + struct vfs_line *line2 = line_list_2->data; + const int shift = (VFS_IMAGE_WIDTH - VFS_NEXT_LINE_WIDTH) / 2 - 1; + int res = 0; + + for (int i = 0; i < VFS_NEXT_LINE_WIDTH; ++i) + { + int x = + (int) line1->next_line_part[i] - (int) line2->data[shift + i]; + res += x * x; + } + return res; } #define VFS_NOISE_THRESHOLD 40 /* Checks whether line is noise or not using hardware parameters */ -static char is_noise(struct vfs_line *line) +static char +is_noise (struct vfs_line *line) { - int val1 = line->noise_hash_1; - int val2 = line->noise_hash_2; - if (val1 > VFS_NOISE_THRESHOLD - && val1 < 256 - VFS_NOISE_THRESHOLD - && val2 > VFS_NOISE_THRESHOLD && val2 < 256 - VFS_NOISE_THRESHOLD) - return 1; - return 0; + int val1 = line->noise_hash_1; + int val2 = line->noise_hash_2; + + if (val1 > VFS_NOISE_THRESHOLD && + val1 < 256 - VFS_NOISE_THRESHOLD && + val2 > VFS_NOISE_THRESHOLD && val2 < 256 - VFS_NOISE_THRESHOLD) + return 1; + return 0; } /* Parameters for fpi_assemble_lines */ static struct fpi_line_asmbl_ctx assembling_ctx = { - .line_width = VFS_IMAGE_WIDTH, - .max_height = VFS_MAX_HEIGHT, - .resolution = 10, - .median_filter_size = 25, - .max_search_offset = 100, - .get_deviation = vfs0050_get_difference, - .get_pixel = vfs0050_get_pixel, + .line_width = VFS_IMAGE_WIDTH, + .max_height = VFS_MAX_HEIGHT, + .resolution = 10, + .median_filter_size = 25, + .max_search_offset = 100, + .get_deviation = vfs0050_get_difference, + .get_pixel = vfs0050_get_pixel, }; /* Processes image before submitting */ -static FpImage *prepare_image(FpDeviceVfs0050 *vdev) +static FpImage * +prepare_image (FpDeviceVfs0050 *vdev) { - int height = vdev->bytes / VFS_LINE_SIZE; + int height = vdev->bytes / VFS_LINE_SIZE; - /* Noise cleaning. IMHO, it works pretty well - I've not detected cases when it doesn't work or cuts a part of the finger - Noise arises at the end of scan when some water remains on the scanner */ - while (height > 0) { - if (!is_noise(vdev->lines_buffer + height - 1)) - break; - --height; - } - if (height > VFS_MAX_HEIGHT) - height = VFS_MAX_HEIGHT; + /* Noise cleaning. IMHO, it works pretty well + I've not detected cases when it doesn't work or cuts a part of the finger + Noise arises at the end of scan when some water remains on the scanner */ + while (height > 0) + { + if (!is_noise (vdev->lines_buffer + height - 1)) + break; + --height; + } + if (height > VFS_MAX_HEIGHT) + height = VFS_MAX_HEIGHT; - /* If image is not good enough */ - if (height < VFS_IMAGE_WIDTH) - return NULL; + /* If image is not good enough */ + if (height < VFS_IMAGE_WIDTH) + return NULL; - /* Building GSList */ - GSList *lines = NULL; - for (int i = height - 1; i >= 0; --i) - lines = g_slist_prepend(lines, vdev->lines_buffer + i); + /* Building GSList */ + GSList *lines = NULL; + for (int i = height - 1; i >= 0; --i) + lines = g_slist_prepend (lines, vdev->lines_buffer + i); - /* Perform line assembling */ - FpImage *img = fpi_assemble_lines(&assembling_ctx, lines, height); + /* Perform line assembling */ + FpImage *img = fpi_assemble_lines (&assembling_ctx, lines, height); - g_slist_free(lines); - return img; + g_slist_free (lines); + return img; } /* Processes and submits image after fingerprint received */ -static void submit_image(FpDeviceVfs0050 *self) +static void +submit_image (FpDeviceVfs0050 *self) { - FpImageDevice *idev = FP_IMAGE_DEVICE(self); + FpImageDevice *idev = FP_IMAGE_DEVICE (self); - /* We were not asked to submit image actually */ - if (!self->active) - return; + /* We were not asked to submit image actually */ + if (!self->active) + return; - FpImage *img = prepare_image(self); + FpImage *img = prepare_image (self); - if (!img) - fpi_image_device_retry_scan(idev, FP_DEVICE_RETRY_TOO_SHORT); - else - fpi_image_device_image_captured(idev, img); + if (!img) + fpi_image_device_retry_scan (idev, FP_DEVICE_RETRY_TOO_SHORT); + else + fpi_image_device_image_captured (idev, img); - /* Finger not on the scanner */ - fpi_image_device_report_finger_status(idev, FALSE); + /* Finger not on the scanner */ + fpi_image_device_report_finger_status (idev, FALSE); } /* Proto functions */ /* SSM loop for clear_ep2 */ static void -clear_ep2_ssm(FpiSsm *ssm, FpDevice *dev, void *user_data) +clear_ep2_ssm (FpiSsm *ssm, FpDevice *dev, void *user_data) { - char command04 = 0x04; + char command04 = 0x04; - switch (fpi_ssm_get_cur_state(ssm)) { - case SUBSM1_COMMAND_04: - async_write(ssm, dev, &command04, sizeof(command04)); - break; + switch (fpi_ssm_get_cur_state (ssm)) + { + case SUBSM1_COMMAND_04: + async_write (ssm, dev, &command04, sizeof (command04)); + break; - case SUBSM1_RETURN_CODE: - async_read(ssm, dev, 1, NULL, 2); - break; + case SUBSM1_RETURN_CODE: + async_read (ssm, dev, 1, NULL, 2); + break; - case SUBSM1_ABORT_2: - async_abort(dev, ssm, 2); - break; + case SUBSM1_ABORT_2: + async_abort (dev, ssm, 2); + break; - default: - fp_err("Unknown SUBSM1 state"); - fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - } + default: + fp_err ("Unknown SUBSM1 state"); + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + } } /* Send command to clear EP2 */ static void -clear_ep2(FpDevice *dev, - FpiSsm *ssm) +clear_ep2 (FpDevice *dev, + FpiSsm *ssm) { - FpiSsm *subsm = - fpi_ssm_new(dev, clear_ep2_ssm, SUBSM1_STATES, NULL); - fpi_ssm_start_subsm(ssm, subsm); + FpiSsm *subsm = + fpi_ssm_new (dev, clear_ep2_ssm, SUBSM1_STATES, NULL); + + fpi_ssm_start_subsm (ssm, subsm); } -static void send_control_packet_ssm(FpiSsm *ssm, FpDevice *dev, - void *user_data) +static void +send_control_packet_ssm (FpiSsm *ssm, FpDevice *dev, + void *user_data) { - FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050(dev); + FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case SUBSM2_SEND_CONTROL: - async_write(ssm, dev, self->control_packet, - VFS_CONTROL_PACKET_SIZE); - break; + switch (fpi_ssm_get_cur_state (ssm)) + { + case SUBSM2_SEND_CONTROL: + async_write (ssm, dev, self->control_packet, + VFS_CONTROL_PACKET_SIZE); + break; - case SUBSM2_RETURN_CODE: - async_read(ssm, dev, 1, NULL, 2); - break; + case SUBSM2_RETURN_CODE: + async_read (ssm, dev, 1, NULL, 2); + break; - case SUBSM2_SEND_COMMIT: - /* next_receive_* packets could be sent only in pair */ - if (self->control_packet == next_receive_1) { - self->control_packet = next_receive_2; - fpi_ssm_jump_to_state(ssm, SUBSM2_SEND_CONTROL); - break; - } - /* commit_out in Windows differs in each commit, but I send the same each time */ - async_write(ssm, dev, commit_out, sizeof(commit_out)); - break; + case SUBSM2_SEND_COMMIT: + /* next_receive_* packets could be sent only in pair */ + if (self->control_packet == next_receive_1) + { + self->control_packet = next_receive_2; + fpi_ssm_jump_to_state (ssm, SUBSM2_SEND_CONTROL); + break; + } + /* commit_out in Windows differs in each commit, but I send the same each time */ + async_write (ssm, dev, commit_out, sizeof (commit_out)); + break; - case SUBSM2_COMMIT_RESPONSE: - async_read(ssm, dev, 1, NULL, VFS_COMMIT_RESPONSE_SIZE); - break; + case SUBSM2_COMMIT_RESPONSE: + async_read (ssm, dev, 1, NULL, VFS_COMMIT_RESPONSE_SIZE); + break; - case SUBSM2_READ_EMPTY_INTERRUPT: - /* I don't know how to check result, it could be different - * NOTE: I guess this comment relates to the above read. */ - async_read(ssm, dev, 3, self->interrupt, VFS_INTERRUPT_SIZE); - break; + case SUBSM2_READ_EMPTY_INTERRUPT: + /* I don't know how to check result, it could be different + * NOTE: I guess this comment relates to the above read. */ + async_read (ssm, dev, 3, self->interrupt, VFS_INTERRUPT_SIZE); + break; - case SUBSM2_ABORT_3: - /* Check that interrupt is empty */ - if (memcmp - (self->interrupt, empty_interrupt, VFS_INTERRUPT_SIZE)) { - fp_err("Unknown SUBSM2 state"); - fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - break; - } - async_abort(dev, ssm, 3); - break; + case SUBSM2_ABORT_3: + /* Check that interrupt is empty */ + if (memcmp + (self->interrupt, empty_interrupt, VFS_INTERRUPT_SIZE)) + { + fp_err ("Unknown SUBSM2 state"); + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + break; + } + async_abort (dev, ssm, 3); + break; - case SUBSM2_CLEAR_EP2: - /* After turn_on Windows doesn't clear EP2 */ - if (self->control_packet != turn_on) - clear_ep2(dev, ssm); - else - fpi_ssm_next_state(ssm); - break; + case SUBSM2_CLEAR_EP2: + /* After turn_on Windows doesn't clear EP2 */ + if (self->control_packet != turn_on) + clear_ep2 (dev, ssm); + else + fpi_ssm_next_state (ssm); + break; - default: - fp_err("Unknown SUBSM2 state"); - fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - } + default: + fp_err ("Unknown SUBSM2 state"); + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + } } /* Send device state control packet */ static void -send_control_packet(FpiSsm *ssm, - FpDevice *dev) +send_control_packet (FpiSsm *ssm, + FpDevice *dev) { - FpiSsm *subsm = - fpi_ssm_new(dev, send_control_packet_ssm, - SUBSM2_STATES, NULL); - fpi_ssm_start_subsm(ssm, subsm); + FpiSsm *subsm = + fpi_ssm_new (dev, send_control_packet_ssm, + SUBSM2_STATES, NULL); + + fpi_ssm_start_subsm (ssm, subsm); } /* Clears all fprint data */ -static void clear_data(FpDeviceVfs0050 *vdev) +static void +clear_data (FpDeviceVfs0050 *vdev) { - g_free(vdev->lines_buffer); - vdev->lines_buffer = NULL; - vdev->memory = vdev->bytes = 0; + g_free (vdev->lines_buffer); + vdev->lines_buffer = NULL; + vdev->memory = vdev->bytes = 0; } /* After receiving interrupt from EP3 */ -static void interrupt_callback(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +interrupt_callback (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050(device); - char *interrupt = transfer->buffer; + FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (device); + char *interrupt = transfer->buffer; - /* we expect a cancellation error when the device is deactivating - * go into the SSM_CLEAR_EP2 state in that case. */ - if (!self->active && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - g_error_free (error); - fpi_ssm_jump_to_state(transfer->ssm, SSM_CLEAR_EP2); - return; - } + /* we expect a cancellation error when the device is deactivating + * go into the SSM_CLEAR_EP2 state in that case. */ + if (!self->active && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_error_free (error); + fpi_ssm_jump_to_state (transfer->ssm, SSM_CLEAR_EP2); + return; + } - if (error) { - fp_err("USB read interrupt transfer: %s", - error->message); - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } + if (error) + { + fp_err ("USB read interrupt transfer: %s", + error->message); + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } - /* Standard interrupts */ - if (memcmp(interrupt, interrupt1, VFS_INTERRUPT_SIZE) == 0 || - memcmp(interrupt, interrupt2, VFS_INTERRUPT_SIZE) == 0 || - memcmp(interrupt, interrupt3, VFS_INTERRUPT_SIZE) == 0) { - /* Go to the next ssm stage */ - fpi_ssm_next_state(transfer->ssm); - return; - } + /* Standard interrupts */ + if (memcmp (interrupt, interrupt1, VFS_INTERRUPT_SIZE) == 0 || + memcmp (interrupt, interrupt2, VFS_INTERRUPT_SIZE) == 0 || + memcmp (interrupt, interrupt3, VFS_INTERRUPT_SIZE) == 0) + { + /* Go to the next ssm stage */ + fpi_ssm_next_state (transfer->ssm); + return; + } - /* When finger is on the scanner before turn_on */ - if (interrupt[0] == 0x01) { - fp_warn("Finger is already on the scanner"); + /* When finger is on the scanner before turn_on */ + if (interrupt[0] == 0x01) + { + fp_warn ("Finger is already on the scanner"); - /* Go to the next ssm stage */ - fpi_ssm_next_state(transfer->ssm); - return; - } + /* Go to the next ssm stage */ + fpi_ssm_next_state (transfer->ssm); + return; + } - /* Unknown interrupt; abort the session */ - fp_err("Unknown interrupt '%02x:%02x:%02x:%02x:%02x'!", - interrupt[0] & 0xff, interrupt[1] & 0xff, interrupt[2] & 0xff, - interrupt[3] & 0xff, interrupt[4] & 0xff); + /* Unknown interrupt; abort the session */ + fp_err ("Unknown interrupt '%02x:%02x:%02x:%02x:%02x'!", + interrupt[0] & 0xff, interrupt[1] & 0xff, interrupt[2] & 0xff, + interrupt[3] & 0xff, interrupt[4] & 0xff); - /* Abort ssm */ - fpi_ssm_mark_failed(transfer->ssm, - fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + /* Abort ssm */ + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); } -static void receive_callback(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +receive_callback (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050(device); + FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (device); - if (error && !g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT)) { - fp_err("USB read transfer: %s", error->message); + if (error && !g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT)) + { + fp_err ("USB read transfer: %s", error->message); - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } - if (error) - g_error_free (error); + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } + if (error) + g_error_free (error); - /* Check if fingerprint data is over */ - if (transfer->actual_length == 0) { - fpi_ssm_next_state(transfer->ssm); - } else { - self->bytes += transfer->actual_length; + /* Check if fingerprint data is over */ + if (transfer->actual_length == 0) + { + fpi_ssm_next_state (transfer->ssm); + } + else + { + self->bytes += transfer->actual_length; - /* We need more data */ - fpi_ssm_jump_to_state(transfer->ssm, - fpi_ssm_get_cur_state(transfer->ssm)); - } + /* We need more data */ + fpi_ssm_jump_to_state (transfer->ssm, + fpi_ssm_get_cur_state (transfer->ssm)); + } } /* SSM stub to prepare device to another scan after orange light was on */ static void -another_scan(FpDevice *dev, - void *data) +another_scan (FpDevice *dev, + void *data) { - FpiSsm *ssm = data; - fpi_ssm_jump_to_state(ssm, SSM_TURN_ON); + FpiSsm *ssm = data; + + fpi_ssm_jump_to_state (ssm, SSM_TURN_ON); } /* Main SSM loop */ -static void activate_ssm(FpiSsm *ssm, FpDevice *dev, void *user_data) +static void +activate_ssm (FpiSsm *ssm, FpDevice *dev, void *user_data) { - FpImageDevice *idev = FP_IMAGE_DEVICE (dev); - FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050(dev); + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); + FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case SSM_INITIAL_ABORT_1: - async_abort(dev, ssm, 1); - break; + switch (fpi_ssm_get_cur_state (ssm)) + { + case SSM_INITIAL_ABORT_1: + async_abort (dev, ssm, 1); + break; - case SSM_INITIAL_ABORT_2: - async_abort(dev, ssm, 2); - break; + case SSM_INITIAL_ABORT_2: + async_abort (dev, ssm, 2); + break; - case SSM_INITIAL_ABORT_3: - async_abort(dev, ssm, 3); - break; + case SSM_INITIAL_ABORT_3: + async_abort (dev, ssm, 3); + break; - case SSM_CLEAR_EP2: - clear_ep2(dev, ssm); - break; + case SSM_CLEAR_EP2: + clear_ep2 (dev, ssm); + break; - case SSM_TURN_OFF: - /* Set control_packet argument */ - self->control_packet = turn_off; + case SSM_TURN_OFF: + /* Set control_packet argument */ + self->control_packet = turn_off; - send_control_packet(ssm, dev); - break; + send_control_packet (ssm, dev); + break; - case SSM_TURN_ON: - if (!self->active) { - /* The only correct exit */ - fpi_ssm_mark_completed(ssm); + case SSM_TURN_ON: + if (!self->active) + { + /* The only correct exit */ + fpi_ssm_mark_completed (ssm); - if (self->need_report) { - fpi_image_device_deactivate_complete(idev, - NULL); - self->need_report = 0; - } - break; - } - /* Set control_packet argument */ - self->control_packet = turn_on; + if (self->need_report) + { + fpi_image_device_deactivate_complete (idev, + NULL); + self->need_report = 0; + } + break; + } + /* Set control_packet argument */ + self->control_packet = turn_on; - send_control_packet(ssm, dev); - break; + send_control_packet (ssm, dev); + break; - case SSM_ASK_INTERRUPT: { - FpiUsbTransfer *transfer; - /* Activated, light must be blinking now */ + case SSM_ASK_INTERRUPT: { + FpiUsbTransfer *transfer; + /* Activated, light must be blinking now */ - /* If we first time here, report that activate completed */ - if (self->need_report) { - fpi_image_device_activate_complete(idev, NULL); - self->need_report = 0; - } + /* If we first time here, report that activate completed */ + if (self->need_report) + { + fpi_image_device_activate_complete (idev, NULL); + self->need_report = 0; + } - /* Asynchronously enquire an interrupt */ - transfer = fpi_usb_transfer_new (dev); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_fill_interrupt (transfer, 0x83, VFS_INTERRUPT_SIZE); - fpi_usb_transfer_submit (transfer, - 0, - fpi_device_get_cancellable (dev), - interrupt_callback, NULL); - fpi_usb_transfer_unref (transfer); + /* Asynchronously enquire an interrupt */ + transfer = fpi_usb_transfer_new (dev); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_interrupt (transfer, 0x83, VFS_INTERRUPT_SIZE); + fpi_usb_transfer_submit (transfer, + 0, + fpi_device_get_cancellable (dev), + interrupt_callback, NULL); + fpi_usb_transfer_unref (transfer); - /* I've put it here to be sure that data is cleared */ - clear_data(self); + /* I've put it here to be sure that data is cleared */ + clear_data (self); - fpi_ssm_next_state(ssm); - break; - } - case SSM_WAIT_INTERRUPT: - /* TODO: This state is unused at this point. When we - * are in this state, then a user cancellation will - * cause deactivation. In that case, the USB transfer - * is cancelled and the device is set to not be active. - * We then go into SSM_CLEAR_EP2 based on the - * cancellation. */ - break; + fpi_ssm_next_state (ssm); + break; + } - case SSM_RECEIVE_FINGER: { - FpiUsbTransfer *transfer; + case SSM_WAIT_INTERRUPT: + /* TODO: This state is unused at this point. When we + * are in this state, then a user cancellation will + * cause deactivation. In that case, the USB transfer + * is cancelled and the device is set to not be active. + * We then go into SSM_CLEAR_EP2 based on the + * cancellation. */ + break; - if (self->memory == 0) { - /* Initialize fingerprint buffer */ - g_free(self->lines_buffer); - self->memory = VFS_USB_BUFFER_SIZE; - self->lines_buffer = g_malloc(self->memory); - self->bytes = 0; + case SSM_RECEIVE_FINGER: { + FpiUsbTransfer *transfer; - /* Finger is on the scanner */ - fpi_image_device_report_finger_status(idev, TRUE); - } + if (self->memory == 0) + { + /* Initialize fingerprint buffer */ + g_free (self->lines_buffer); + self->memory = VFS_USB_BUFFER_SIZE; + self->lines_buffer = g_malloc (self->memory); + self->bytes = 0; - /* Increase buffer size while it's insufficient */ - while (self->bytes + VFS_USB_BUFFER_SIZE > self->memory) { - self->memory <<= 1; - self->lines_buffer = - (struct vfs_line *)g_realloc(self->lines_buffer, - self->memory); - } + /* Finger is on the scanner */ + fpi_image_device_report_finger_status (idev, TRUE); + } - /* Receive chunk of data */ - transfer = fpi_usb_transfer_new (dev); - fpi_usb_transfer_fill_bulk_full(transfer, 0x82, - (void *)self->lines_buffer + self->bytes, - VFS_USB_BUFFER_SIZE, NULL); - transfer->ssm = ssm; - fpi_usb_transfer_submit(transfer, VFS_USB_TIMEOUT, NULL, - receive_callback, NULL); - fpi_usb_transfer_unref(transfer); - break; - } - case SSM_SUBMIT_IMAGE: - submit_image(self); - clear_data(self); + /* Increase buffer size while it's insufficient */ + while (self->bytes + VFS_USB_BUFFER_SIZE > self->memory) + { + self->memory <<= 1; + self->lines_buffer = + (struct vfs_line *) g_realloc (self->lines_buffer, + self->memory); + } - /* Wait for probable vdev->active changing */ - fpi_device_add_timeout(dev, VFS_SSM_TIMEOUT, - fpi_ssm_next_state_timeout_cb, ssm); - break; + /* Receive chunk of data */ + transfer = fpi_usb_transfer_new (dev); + fpi_usb_transfer_fill_bulk_full (transfer, 0x82, + (void *) self->lines_buffer + self->bytes, + VFS_USB_BUFFER_SIZE, NULL); + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, VFS_USB_TIMEOUT, NULL, + receive_callback, NULL); + fpi_usb_transfer_unref (transfer); + break; + } - case SSM_NEXT_RECEIVE: - if (!self->active) { - /* It's the last scan */ - fpi_ssm_jump_to_state(ssm, SSM_CLEAR_EP2); - break; - } + case SSM_SUBMIT_IMAGE: + submit_image (self); + clear_data (self); - /* Set control_packet argument */ - self->control_packet = next_receive_1; + /* Wait for probable vdev->active changing */ + fpi_device_add_timeout (dev, VFS_SSM_TIMEOUT, + fpi_ssm_next_state_timeout_cb, ssm); + break; - send_control_packet(ssm, dev); - break; + case SSM_NEXT_RECEIVE: + if (!self->active) + { + /* It's the last scan */ + fpi_ssm_jump_to_state (ssm, SSM_CLEAR_EP2); + break; + } - case SSM_WAIT_ANOTHER_SCAN: - /* Orange light is on now */ - fpi_device_add_timeout(dev, VFS_SSM_ORANGE_TIMEOUT, - another_scan, ssm); - break; + /* Set control_packet argument */ + self->control_packet = next_receive_1; - default: - fp_err("Unknown state"); - fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - } + send_control_packet (ssm, dev); + break; + + case SSM_WAIT_ANOTHER_SCAN: + /* Orange light is on now */ + fpi_device_add_timeout (dev, VFS_SSM_ORANGE_TIMEOUT, + another_scan, ssm); + break; + + default: + fp_err ("Unknown state"); + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + } } /* Driver functions */ /* Callback for dev_activate ssm */ -static void dev_activate_callback(FpiSsm *ssm, FpDevice *dev, - void *user_data, GError *error) +static void +dev_activate_callback (FpiSsm *ssm, FpDevice *dev, + void *user_data, GError *error) { - FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050(dev); + FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (dev); - self->ssm_active = 0; + self->ssm_active = 0; - if (error) { - g_warning ("Unhandled device activation error: %s", error->message); - g_error_free (error); - } + if (error) + { + g_warning ("Unhandled device activation error: %s", error->message); + g_error_free (error); + } - fpi_ssm_free(ssm); + fpi_ssm_free (ssm); } /* Activate device */ -static void dev_activate(FpImageDevice *idev) +static void +dev_activate (FpImageDevice *idev) { - FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050(idev); + FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (idev); - /* Initialize flags */ - self->active = 1; - self->need_report = 1; - self->ssm_active = 1; + /* Initialize flags */ + self->active = 1; + self->need_report = 1; + self->ssm_active = 1; - FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(idev), activate_ssm, SSM_STATES, - idev); - fpi_ssm_start(ssm, dev_activate_callback); + FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES, + idev); + fpi_ssm_start (ssm, dev_activate_callback); } /* Deactivate device */ -static void dev_deactivate(FpImageDevice *idev) +static void +dev_deactivate (FpImageDevice *idev) { - FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050(idev); + FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (idev); - if (!self->ssm_active) { - fpi_image_device_deactivate_complete(idev, NULL); - return; - } + if (!self->ssm_active) + { + fpi_image_device_deactivate_complete (idev, NULL); + return; + } - /* Initialize flags */ - self->active = 0; - self->need_report = 1; + /* Initialize flags */ + self->active = 0; + self->need_report = 1; } /* Callback for dev_open ssm */ -static void dev_open_callback(FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +static void +dev_open_callback (FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - /* Notify open complete */ - fpi_image_device_open_complete(FP_IMAGE_DEVICE (dev), error); - fpi_ssm_free(ssm); + /* Notify open complete */ + fpi_image_device_open_complete (FP_IMAGE_DEVICE (dev), error); + fpi_ssm_free (ssm); } /* Open device */ -static void dev_open(FpImageDevice *idev) +static void +dev_open (FpImageDevice *idev) { - GError *error = NULL; + GError *error = NULL; - /* Claim usb interface */ - if (!g_usb_device_claim_interface (fpi_device_get_usb_device(FP_DEVICE(idev)), 0, 0, &error)) { - fpi_image_device_open_complete (idev, error); - return; - } + /* Claim usb interface */ + if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (idev)), 0, 0, &error)) + { + fpi_image_device_open_complete (idev, error); + return; + } - /* Clearing previous device state */ - FpiSsm *ssm = fpi_ssm_new(FP_DEVICE(idev), activate_ssm, SSM_STATES, NULL); - fpi_ssm_start(ssm, dev_open_callback); + /* Clearing previous device state */ + FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES, NULL); + fpi_ssm_start (ssm, dev_open_callback); } /* Close device */ -static void dev_close(FpImageDevice *idev) +static void +dev_close (FpImageDevice *idev) { - GError *error = NULL; - FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050(idev); + GError *error = NULL; + FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (idev); - clear_data(self); + clear_data (self); - /* Release usb interface */ - g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(idev)), - 0, 0, &error); + /* Release usb interface */ + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (idev)), + 0, 0, &error); - /* Notify close complete */ - fpi_image_device_close_complete(idev, error); + /* Notify close complete */ + fpi_image_device_close_complete (idev, error); } /* Usb id table of device */ -static const FpIdEntry id_table [ ] = { - {.vid = 0x138a, .pid = 0x0050, - }, - {.vid = 0, .pid = 0, .driver_data = 0}, +static const FpIdEntry id_table[] = { + {.vid = 0x138a, .pid = 0x0050, }, + {.vid = 0, .pid = 0, .driver_data = 0}, }; -static void fpi_device_vfs0050_init(FpDeviceVfs0050 *self) { +static void +fpi_device_vfs0050_init (FpDeviceVfs0050 *self) +{ } -static void fpi_device_vfs0050_class_init(FpDeviceVfs0050Class *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); +static void +fpi_device_vfs0050_class_init (FpDeviceVfs0050Class *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); - dev_class->id = "vfs0050"; - dev_class->full_name = "Validity VFS0050"; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->id_table = id_table; - dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + dev_class->id = "vfs0050"; + dev_class->full_name = "Validity VFS0050"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - img_class->img_open = dev_open; - img_class->img_close = dev_close; - img_class->activate = dev_activate; - img_class->deactivate = dev_deactivate; + img_class->img_open = dev_open; + img_class->img_close = dev_close; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; - img_class->bz3_threshold = 24; + img_class->bz3_threshold = 24; - img_class->img_width = VFS_IMAGE_WIDTH; - img_class->img_height = -1; + img_class->img_width = VFS_IMAGE_WIDTH; + img_class->img_height = -1; } diff --git a/libfprint/drivers/vfs0050.h b/libfprint/drivers/vfs0050.h index a6b315b3..f4ebb177 100644 --- a/libfprint/drivers/vfs0050.h +++ b/libfprint/drivers/vfs0050.h @@ -51,334 +51,336 @@ #define EP3_IN 0x83 /* Fingerprint horizontal line */ -struct vfs_line { - /* It must be always 0x01 */ - unsigned char _0x01; - /* It must be always 0xfe */ - unsigned char _0xfe; +struct vfs_line +{ + /* It must be always 0x01 */ + unsigned char _0x01; + /* It must be always 0xfe */ + unsigned char _0xfe; - /* line number starting from some number in Little-Endian */ - unsigned short id; + /* line number starting from some number in Little-Endian */ + unsigned short id; - /* Some hashes which are useful to detect noise */ - unsigned char noise_hash_1; - unsigned char noise_hash_2; + /* Some hashes which are useful to detect noise */ + unsigned char noise_hash_1; + unsigned char noise_hash_2; - /* The first byte of _somedata is always 0x00, the second is strange useless cyclic line number */ - unsigned short _somedata; + /* The first byte of _somedata is always 0x00, the second is strange useless cyclic line number */ + unsigned short _somedata; - /* Fingerprint image */ - unsigned char data[VFS_IMAGE_WIDTH]; + /* Fingerprint image */ + unsigned char data[VFS_IMAGE_WIDTH]; - /* Narrow fingerprint part from the center used for variable speed lines assembling */ - unsigned char next_line_part[VFS_NEXT_LINE_WIDTH]; + /* Narrow fingerprint part from the center used for variable speed lines assembling */ + unsigned char next_line_part[VFS_NEXT_LINE_WIDTH]; - /* scan_data is 0xfb except some rare cases, it's skipped */ - unsigned char scan_data[8]; -} __attribute__ ((__packed__)); + /* scan_data is 0xfb except some rare cases, it's skipped */ + unsigned char scan_data[8]; +} __attribute__((__packed__)); /* The main driver structure */ -struct _FpDeviceVfs0050 { - FpImageDevice parent; +struct _FpDeviceVfs0050 +{ + FpImageDevice parent; - /* One if we were asked to read fingerprint, zero otherwise */ - char active; + /* One if we were asked to read fingerprint, zero otherwise */ + char active; - /* Control packet parameter for send_control_packet */ - unsigned char *control_packet; + /* Control packet parameter for send_control_packet */ + unsigned char *control_packet; - /* For dev_deactivate to check whether ssm still running or not */ - char ssm_active; + /* For dev_deactivate to check whether ssm still running or not */ + char ssm_active; - /* Should we call fpi_imgdev_activate_complete or fpi_imgdev_deactivate_complete */ - char need_report; + /* Should we call fpi_imgdev_activate_complete or fpi_imgdev_deactivate_complete */ + char need_report; - /* Received fingerprint raw lines */ - struct vfs_line *lines_buffer; + /* Received fingerprint raw lines */ + struct vfs_line *lines_buffer; - /* Current number of received bytes and current memory used by data */ - int bytes, memory; + /* Current number of received bytes and current memory used by data */ + int bytes, memory; - /* USB buffer for fingerprint */ - char *usb_buffer; + /* USB buffer for fingerprint */ + char *usb_buffer; - /* Received interrupt data */ - unsigned char interrupt[8]; + /* Received interrupt data */ + unsigned char interrupt[8]; }; G_DECLARE_FINAL_TYPE (FpDeviceVfs0050, fpi_device_vfs0050, FPI, DEVICE_VFS0050, FpImageDevice) /* SSM states for clear_ep2 */ enum SUBSM1 { - SUBSM1_COMMAND_04, - SUBSM1_RETURN_CODE, - SUBSM1_ABORT_2, + SUBSM1_COMMAND_04, + SUBSM1_RETURN_CODE, + SUBSM1_ABORT_2, - SUBSM1_STATES, + SUBSM1_STATES, }; /* SSM states for control */ enum SUBSM2 { - SUBSM2_SEND_CONTROL, - SUBSM2_RETURN_CODE, /* If next_receive, send another control packet */ + SUBSM2_SEND_CONTROL, + SUBSM2_RETURN_CODE, /* If next_receive, send another control packet */ - SUBSM2_SEND_COMMIT, - SUBSM2_COMMIT_RESPONSE, - SUBSM2_READ_EMPTY_INTERRUPT, - SUBSM2_ABORT_3, - SUBSM2_CLEAR_EP2, + SUBSM2_SEND_COMMIT, + SUBSM2_COMMIT_RESPONSE, + SUBSM2_READ_EMPTY_INTERRUPT, + SUBSM2_ABORT_3, + SUBSM2_CLEAR_EP2, - SUBSM2_STATES, + SUBSM2_STATES, }; /* SSM states for activate_ssm */ enum SSM_STATE { - SSM_INITIAL_ABORT_1, - SSM_INITIAL_ABORT_2, - SSM_INITIAL_ABORT_3, - SSM_CLEAR_EP2, - SSM_TURN_OFF, + SSM_INITIAL_ABORT_1, + SSM_INITIAL_ABORT_2, + SSM_INITIAL_ABORT_3, + SSM_CLEAR_EP2, + SSM_TURN_OFF, - /* Here the device is turned off; if not active, complete ssm */ - SSM_TURN_ON, + /* Here the device is turned off; if not active, complete ssm */ + SSM_TURN_ON, - SSM_ASK_INTERRUPT, - SSM_WAIT_INTERRUPT, + SSM_ASK_INTERRUPT, + SSM_WAIT_INTERRUPT, - SSM_RECEIVE_FINGER, - SSM_SUBMIT_IMAGE, + SSM_RECEIVE_FINGER, + SSM_SUBMIT_IMAGE, - /* If not active, jump to CLEAR_EP2 */ - SSM_NEXT_RECEIVE, - SSM_WAIT_ANOTHER_SCAN, - /* Jump to TURN_ON */ + /* If not active, jump to CLEAR_EP2 */ + SSM_NEXT_RECEIVE, + SSM_WAIT_ANOTHER_SCAN, + /* Jump to TURN_ON */ - SSM_STATES + SSM_STATES }; /* Blocks of data from USB sniffer */ /* Turns on the light */ static unsigned char turn_on[] = { - 0x39, 0x20, 0xBF, 0x02, 0x00, 0xF4, 0x01, 0x00, 0x00, 0x01, 0xD1, 0x00, - 0x20, 0xD1, 0xD1, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x01, 0x00, - 0x00, 0x01, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xF4, 0x01, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0xF4, 0x01, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, + 0x39, 0x20, 0xBF, 0x02, 0x00, 0xF4, 0x01, 0x00, 0x00, 0x01, 0xD1, 0x00, + 0x20, 0xD1, 0xD1, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xF4, 0x01, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0xF4, 0x01, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, }; /* Power off */ static unsigned char turn_off[] = { - 0x39, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, + 0x39, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, }; /* Turns on orange light */ static unsigned char next_receive_1[] = { - 0x39, 0xB8, 0x0B, 0x00, 0x00, 0xB8, 0x0B, 0x00, 0x00, 0x01, 0xD1, 0x00, - 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0xB8, 0x0B, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, + 0x39, 0xB8, 0x0B, 0x00, 0x00, 0xB8, 0x0B, 0x00, 0x00, 0x01, 0xD1, 0x00, + 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0xB8, 0x0B, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, }; /* Packet directly after next_receive_1 */ static unsigned char next_receive_2[] = { - 0x39, 0xE8, 0x03, 0x00, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x01, 0xD1, 0x00, - 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0xE8, 0x03, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, + 0x39, 0xE8, 0x03, 0x00, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x01, 0xD1, 0x00, + 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0xE8, 0x03, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, }; /* Commit message */ static unsigned char commit_out[] = { - 0x02, 0x94, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x2C, 0x03, 0x00, - 0x30, 0x1B, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x08, 0x00, 0x20, 0x03, 0x00, 0x30, 0x3D, 0x10, 0x00, - 0x00, 0x20, 0x00, 0x08, - 0x00, 0x18, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, - 0x00, 0x24, 0x03, 0x00, - 0x30, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x28, 0x03, 0x00, - 0x30, 0x08, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x08, 0x00, 0x30, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x08, - 0x00, 0x38, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, - 0x00, 0x3C, 0x03, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x44, 0x03, 0x00, - 0x30, 0x14, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x08, 0x00, 0x48, 0x03, 0x00, 0x30, 0x01, 0x04, 0x02, - 0x00, 0x20, 0x00, 0x08, - 0x00, 0x4C, 0x03, 0x00, 0x30, 0x01, 0x0C, 0x02, 0x00, 0x20, 0x00, 0x08, - 0x00, 0x54, 0x03, 0x00, - 0x30, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x5C, 0x03, 0x00, - 0x30, 0x90, 0x01, 0x02, - 0x00, 0x20, 0x00, 0x08, 0x00, 0x60, 0x03, 0x00, 0x30, 0x2C, 0x01, 0x19, - 0x00, 0x20, 0x00, 0x08, - 0x00, 0x64, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, - 0x00, 0x6C, 0x03, 0x00, - 0x30, 0x1E, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x70, 0x03, 0x00, - 0x30, 0x21, 0x80, 0x00, - 0x00, 0x20, 0x00, 0x08, 0x00, 0x78, 0x03, 0x00, 0x30, 0x09, 0x00, 0x02, - 0x00, 0x20, 0x00, 0x08, - 0x00, 0x7C, 0x03, 0x00, 0x30, 0x0B, 0x00, 0x19, 0x00, 0x20, 0x00, 0x08, - 0x00, 0x80, 0x03, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x84, 0x03, 0x00, - 0x30, 0x3A, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x08, 0x00, 0x88, 0x03, 0x00, 0x30, 0x14, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x08, - 0x00, 0x8C, 0x03, 0x00, 0x30, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, - 0x00, 0x90, 0x03, 0x00, - 0x30, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x94, 0x03, 0x00, - 0x30, 0x08, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x08, 0x00, 0x98, 0x03, 0x00, 0x30, 0x00, 0x00, 0xA1, - 0x01, 0x20, 0x00, 0x08, - 0x00, 0x9C, 0x03, 0x00, 0x30, 0x00, 0x00, 0xA1, 0x01, 0x20, 0x00, 0x08, - 0x00, 0xA8, 0x03, 0x00, - 0x30, 0x64, 0x01, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0xAC, 0x03, 0x00, - 0x30, 0x64, 0x01, 0x00, - 0x00, 0x20, 0x00, 0x08, 0x00, 0xB0, 0x03, 0x00, 0x30, 0x00, 0x01, 0x00, - 0x00, 0x20, 0x00, 0x08, - 0x00, 0xB4, 0x03, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x08, - 0x00, 0xB8, 0x03, 0x00, - 0x30, 0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0xBC, 0x03, 0x00, - 0x30, 0x05, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x08, 0x00, 0xC0, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x08, - 0x00, 0x84, 0x03, 0x00, 0x30, 0x3B, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, - 0x00, 0x08, 0x07, 0x00, - 0x30, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x0C, 0x07, 0x00, - 0x30, 0x00, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x08, 0x00, 0x14, 0x07, 0x00, 0x30, 0x20, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x08, - 0x00, 0x1C, 0x07, 0x00, 0x30, 0x1A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, - 0x00, 0x70, 0x0D, 0x00, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x25, 0x00, 0x28, 0x00, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x90, 0x00, 0x00, 0x00, 0x2B, 0xFF, 0x2B, 0xFF, 0x2B, - 0xED, 0x00, 0x00, 0x2B, - 0xFB, 0x00, 0x00, 0x2B, 0xC5, 0x00, 0x00, 0x2B, 0x05, 0x80, 0x70, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x24, 0xD3, 0x2E, 0xC0, 0x2C, 0x3B, 0x08, 0xF0, 0x3B, 0x09, 0x24, - 0xBB, 0x3B, 0x0B, 0x24, - 0xAA, 0x3B, 0x1F, 0xF8, 0x00, 0x3B, 0x3F, 0xF0, 0x00, 0x3B, 0x35, 0xC0, - 0x00, 0x38, 0x80, 0x2C, - 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x38, 0x80, 0x2C, 0x70, 0x00, - 0x00, 0x00, 0x00, 0xC0, - 0x3A, 0x80, 0x2C, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x3B, 0x0A, 0x80, - 0x2E, 0x83, 0x24, 0xDB, - 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x2C, 0x31, 0x83, 0x2C, 0x70, - 0x00, 0x00, 0x00, 0x00, - 0xCB, 0x33, 0x1B, 0x83, 0x2C, 0x70, 0x00, 0x00, 0x00, 0x00, 0xCB, 0x31, - 0x83, 0x2C, 0x70, 0x00, - 0x00, 0x00, 0x00, 0xCB, 0x00, 0x33, 0x1E, 0x83, 0x2E, 0x25, 0xFF, 0xC4, - 0x00, 0x2F, 0x06, 0x84, - 0x2E, 0x00, 0x00, 0x10, 0x20, 0x29, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, - 0x00, 0x23, 0x00, 0x00, - 0x00, 0x21, 0x00, 0x10, 0x00, 0x48, 0x03, 0x00, 0x30, 0xFF, 0xF0, 0xFF, - 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x00, 0x00, 0x21, 0x00, 0x10, 0x00, 0x4C, 0x03, 0x00, - 0x30, 0xFF, 0xF0, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x21, 0x00, 0x10, - 0x00, 0x20, 0x03, 0x00, - 0x30, 0x7F, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x00, - 0x00, 0x20, 0x00, 0x08, - 0x00, 0x24, 0x03, 0x00, 0x30, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, - 0x00, 0x1C, 0x07, 0x00, - 0x30, 0x1A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x10, 0x00, 0x20, 0x03, 0x00, - 0x30, 0xC3, 0xFF, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, - 0x00, 0x80, 0x03, 0x00, - 0x30, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x84, 0x00, 0x31, 0x65, 0x77, - 0x77, 0x77, 0x78, 0x88, - 0x77, 0x77, 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x77, 0x67, - 0x66, 0x66, 0x66, 0x66, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x67, 0x66, 0x66, 0x66, 0x66, - 0x66, 0x77, 0x66, 0x66, - 0x66, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x76, 0x66, 0x56, - 0x66, 0x66, 0x56, 0x55, - 0x65, 0x66, 0x66, 0x66, 0x65, 0x66, 0x66, 0x55, 0x66, 0x66, 0x65, 0x66, - 0x76, 0x76, 0x77, 0x77, - 0x66, 0x66, 0x66, 0x76, 0x67, 0x66, 0x77, 0x67, 0x66, 0x66, 0x66, 0x56, - 0x65, 0x66, 0x65, 0x66, - 0x66, 0x55, 0x55, 0x54, 0x55, 0x65, 0x66, 0x66, 0x66, 0x76, 0x77, 0x87, - 0x88, 0x77, 0x66, 0x66, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x65, 0x66, 0x55, 0x55, 0x65, 0x56, 0x55, - 0x55, 0x55, 0x54, 0x45, - 0x54, 0x55, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, - 0x66, 0x26, 0x00, 0x28, - 0x00, 0xFF, 0x00, 0x0F, 0x00, 0xF0, 0xF0, 0x0F, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x30, 0x01, 0x02, - 0x00, 0x2C, 0x01, 0x28, 0x00, 0x20, 0x80, 0x00, 0x00, 0x0A, 0x00, 0x02, - 0x00, 0x0B, 0x00, 0x19, - 0x00, 0x40, 0x1F, 0x10, 0x27, 0x00, 0x0F, 0x03, 0x00, + 0x02, 0x94, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x2C, 0x03, 0x00, + 0x30, 0x1B, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x08, 0x00, 0x20, 0x03, 0x00, 0x30, 0x3D, 0x10, 0x00, + 0x00, 0x20, 0x00, 0x08, + 0x00, 0x18, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, + 0x00, 0x24, 0x03, 0x00, + 0x30, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x28, 0x03, 0x00, + 0x30, 0x08, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x08, 0x00, 0x30, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x08, + 0x00, 0x38, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, + 0x00, 0x3C, 0x03, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x44, 0x03, 0x00, + 0x30, 0x14, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x08, 0x00, 0x48, 0x03, 0x00, 0x30, 0x01, 0x04, 0x02, + 0x00, 0x20, 0x00, 0x08, + 0x00, 0x4C, 0x03, 0x00, 0x30, 0x01, 0x0C, 0x02, 0x00, 0x20, 0x00, 0x08, + 0x00, 0x54, 0x03, 0x00, + 0x30, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x5C, 0x03, 0x00, + 0x30, 0x90, 0x01, 0x02, + 0x00, 0x20, 0x00, 0x08, 0x00, 0x60, 0x03, 0x00, 0x30, 0x2C, 0x01, 0x19, + 0x00, 0x20, 0x00, 0x08, + 0x00, 0x64, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, + 0x00, 0x6C, 0x03, 0x00, + 0x30, 0x1E, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x70, 0x03, 0x00, + 0x30, 0x21, 0x80, 0x00, + 0x00, 0x20, 0x00, 0x08, 0x00, 0x78, 0x03, 0x00, 0x30, 0x09, 0x00, 0x02, + 0x00, 0x20, 0x00, 0x08, + 0x00, 0x7C, 0x03, 0x00, 0x30, 0x0B, 0x00, 0x19, 0x00, 0x20, 0x00, 0x08, + 0x00, 0x80, 0x03, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x84, 0x03, 0x00, + 0x30, 0x3A, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x08, 0x00, 0x88, 0x03, 0x00, 0x30, 0x14, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x08, + 0x00, 0x8C, 0x03, 0x00, 0x30, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, + 0x00, 0x90, 0x03, 0x00, + 0x30, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x94, 0x03, 0x00, + 0x30, 0x08, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x08, 0x00, 0x98, 0x03, 0x00, 0x30, 0x00, 0x00, 0xA1, + 0x01, 0x20, 0x00, 0x08, + 0x00, 0x9C, 0x03, 0x00, 0x30, 0x00, 0x00, 0xA1, 0x01, 0x20, 0x00, 0x08, + 0x00, 0xA8, 0x03, 0x00, + 0x30, 0x64, 0x01, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0xAC, 0x03, 0x00, + 0x30, 0x64, 0x01, 0x00, + 0x00, 0x20, 0x00, 0x08, 0x00, 0xB0, 0x03, 0x00, 0x30, 0x00, 0x01, 0x00, + 0x00, 0x20, 0x00, 0x08, + 0x00, 0xB4, 0x03, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x08, + 0x00, 0xB8, 0x03, 0x00, + 0x30, 0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0xBC, 0x03, 0x00, + 0x30, 0x05, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x08, 0x00, 0xC0, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x08, + 0x00, 0x84, 0x03, 0x00, 0x30, 0x3B, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, + 0x00, 0x08, 0x07, 0x00, + 0x30, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x0C, 0x07, 0x00, + 0x30, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x08, 0x00, 0x14, 0x07, 0x00, 0x30, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x08, + 0x00, 0x1C, 0x07, 0x00, 0x30, 0x1A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, + 0x00, 0x70, 0x0D, 0x00, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x25, 0x00, 0x28, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x90, 0x00, 0x00, 0x00, 0x2B, 0xFF, 0x2B, 0xFF, 0x2B, + 0xED, 0x00, 0x00, 0x2B, + 0xFB, 0x00, 0x00, 0x2B, 0xC5, 0x00, 0x00, 0x2B, 0x05, 0x80, 0x70, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x24, 0xD3, 0x2E, 0xC0, 0x2C, 0x3B, 0x08, 0xF0, 0x3B, 0x09, 0x24, + 0xBB, 0x3B, 0x0B, 0x24, + 0xAA, 0x3B, 0x1F, 0xF8, 0x00, 0x3B, 0x3F, 0xF0, 0x00, 0x3B, 0x35, 0xC0, + 0x00, 0x38, 0x80, 0x2C, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x38, 0x80, 0x2C, 0x70, 0x00, + 0x00, 0x00, 0x00, 0xC0, + 0x3A, 0x80, 0x2C, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x3B, 0x0A, 0x80, + 0x2E, 0x83, 0x24, 0xDB, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x2C, 0x31, 0x83, 0x2C, 0x70, + 0x00, 0x00, 0x00, 0x00, + 0xCB, 0x33, 0x1B, 0x83, 0x2C, 0x70, 0x00, 0x00, 0x00, 0x00, 0xCB, 0x31, + 0x83, 0x2C, 0x70, 0x00, + 0x00, 0x00, 0x00, 0xCB, 0x00, 0x33, 0x1E, 0x83, 0x2E, 0x25, 0xFF, 0xC4, + 0x00, 0x2F, 0x06, 0x84, + 0x2E, 0x00, 0x00, 0x10, 0x20, 0x29, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x23, 0x00, 0x00, + 0x00, 0x21, 0x00, 0x10, 0x00, 0x48, 0x03, 0x00, 0x30, 0xFF, 0xF0, 0xFF, + 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x21, 0x00, 0x10, 0x00, 0x4C, 0x03, 0x00, + 0x30, 0xFF, 0xF0, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x21, 0x00, 0x10, + 0x00, 0x20, 0x03, 0x00, + 0x30, 0x7F, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x00, + 0x00, 0x20, 0x00, 0x08, + 0x00, 0x24, 0x03, 0x00, 0x30, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, + 0x00, 0x1C, 0x07, 0x00, + 0x30, 0x1A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x10, 0x00, 0x20, 0x03, 0x00, + 0x30, 0xC3, 0xFF, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, + 0x00, 0x80, 0x03, 0x00, + 0x30, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x84, 0x00, 0x31, 0x65, 0x77, + 0x77, 0x77, 0x78, 0x88, + 0x77, 0x77, 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x77, 0x67, + 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x67, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x77, 0x66, 0x66, + 0x66, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x76, 0x66, 0x56, + 0x66, 0x66, 0x56, 0x55, + 0x65, 0x66, 0x66, 0x66, 0x65, 0x66, 0x66, 0x55, 0x66, 0x66, 0x65, 0x66, + 0x76, 0x76, 0x77, 0x77, + 0x66, 0x66, 0x66, 0x76, 0x67, 0x66, 0x77, 0x67, 0x66, 0x66, 0x66, 0x56, + 0x65, 0x66, 0x65, 0x66, + 0x66, 0x55, 0x55, 0x54, 0x55, 0x65, 0x66, 0x66, 0x66, 0x76, 0x77, 0x87, + 0x88, 0x77, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x65, 0x66, 0x55, 0x55, 0x65, 0x56, 0x55, + 0x55, 0x55, 0x54, 0x45, + 0x54, 0x55, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, + 0x66, 0x26, 0x00, 0x28, + 0x00, 0xFF, 0x00, 0x0F, 0x00, 0xF0, 0xF0, 0x0F, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x30, 0x01, 0x02, + 0x00, 0x2C, 0x01, 0x28, 0x00, 0x20, 0x80, 0x00, 0x00, 0x0A, 0x00, 0x02, + 0x00, 0x0B, 0x00, 0x19, + 0x00, 0x40, 0x1F, 0x10, 0x27, 0x00, 0x0F, 0x03, 0x00, }; /* Known interrupts */ static unsigned char empty_interrupt[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, }; static unsigned char interrupt1[] = { - 0x02, 0x00, 0x0E, 0x00, 0xF0, + 0x02, 0x00, 0x0E, 0x00, 0xF0, }; static unsigned char interrupt2[] = { - 0x02, 0x04, 0x0A, 0x00, 0xF0, + 0x02, 0x04, 0x0A, 0x00, 0xF0, }; static unsigned char interrupt3[] = { - 0x02, 0x00, 0x0A, 0x00, 0xF0, + 0x02, 0x00, 0x0A, 0x00, 0xF0, }; diff --git a/libfprint/drivers/vfs101.c b/libfprint/drivers/vfs101.c index 690ec2d5..6abf265e 100644 --- a/libfprint/drivers/vfs101.c +++ b/libfprint/drivers/vfs101.c @@ -22,1330 +22,1368 @@ #include "drivers_api.h" /* Input-Output usb endpoint */ -#define EP_IN(n) (n | FPI_USB_ENDPOINT_IN) -#define EP_OUT(n) (n | FPI_USB_ENDPOINT_OUT) +#define EP_IN(n) (n | FPI_USB_ENDPOINT_IN) +#define EP_OUT(n) (n | FPI_USB_ENDPOINT_OUT) /* Usb bulk timeout */ -#define BULK_TIMEOUT 100 +#define BULK_TIMEOUT 100 /* The device send back the image into block of 16 frames of 292 bytes */ -#define VFS_FRAME_SIZE 292 -#define VFS_BLOCK_SIZE 16 * VFS_FRAME_SIZE +#define VFS_FRAME_SIZE 292 +#define VFS_BLOCK_SIZE 16 * VFS_FRAME_SIZE /* Buffer height */ -#define VFS_BUFFER_HEIGHT 5000 +#define VFS_BUFFER_HEIGHT 5000 /* Buffer size */ -#define VFS_BUFFER_SIZE (VFS_BUFFER_HEIGHT * VFS_FRAME_SIZE) +#define VFS_BUFFER_SIZE (VFS_BUFFER_HEIGHT * VFS_FRAME_SIZE) /* Image width */ -#define VFS_IMG_WIDTH 200 +#define VFS_IMG_WIDTH 200 /* Maximum image height */ -#define VFS_IMG_MAX_HEIGHT 1023 +#define VFS_IMG_MAX_HEIGHT 1023 /* Minimum image height */ -#define VFS_IMG_MIN_HEIGHT 200 +#define VFS_IMG_MIN_HEIGHT 200 /* Scan level threshold */ -#define VFS_IMG_SLT_BEGIN 768 -#define VFS_IMG_SLT_END 64 -#define VFS_IMG_SLT_LINES 4 +#define VFS_IMG_SLT_BEGIN 768 +#define VFS_IMG_SLT_END 64 +#define VFS_IMG_SLT_LINES 4 /* Minimum image level */ -#define VFS_IMG_MIN_IMAGE_LEVEL 144 +#define VFS_IMG_MIN_IMAGE_LEVEL 144 /* Best image contrast */ -#define VFS_IMG_BEST_CONTRAST 128 +#define VFS_IMG_BEST_CONTRAST 128 /* Device parameters address */ -#define VFS_PAR_000E 0x000e -#define VFS_PAR_0011 0x0011 -#define VFS_PAR_THRESHOLD 0x0057 -#define VFS_PAR_STATE_3 0x005e -#define VFS_PAR_STATE_5 0x005f -#define VFS_PAR_INFO_RATE 0x0062 -#define VFS_PAR_0076 0x0076 -#define VFS_PAR_INFO_CONTRAST 0x0077 -#define VFS_PAR_0078 0x0078 +#define VFS_PAR_000E 0x000e +#define VFS_PAR_0011 0x0011 +#define VFS_PAR_THRESHOLD 0x0057 +#define VFS_PAR_STATE_3 0x005e +#define VFS_PAR_STATE_5 0x005f +#define VFS_PAR_INFO_RATE 0x0062 +#define VFS_PAR_0076 0x0076 +#define VFS_PAR_INFO_CONTRAST 0x0077 +#define VFS_PAR_0078 0x0078 /* Device regiones address */ -#define VFS_REG_IMG_EXPOSURE 0xff500e -#define VFS_REG_IMG_CONTRAST 0xff5038 +#define VFS_REG_IMG_EXPOSURE 0xff500e +#define VFS_REG_IMG_CONTRAST 0xff5038 /* Device settings */ -#define VFS_VAL_000E 0x0001 -#define VFS_VAL_0011 0x0008 -#define VFS_VAL_THRESHOLD 0x0096 -#define VFS_VAL_STATE_3 0x0064 -#define VFS_VAL_STATE_5 0x00c8 -#define VFS_VAL_INFO_RATE 0x0001 -#define VFS_VAL_0076 0x0012 -#define VFS_VAL_0078 0x2230 -#define VFS_VAL_IMG_EXPOSURE 0x21c0 +#define VFS_VAL_000E 0x0001 +#define VFS_VAL_0011 0x0008 +#define VFS_VAL_THRESHOLD 0x0096 +#define VFS_VAL_STATE_3 0x0064 +#define VFS_VAL_STATE_5 0x00c8 +#define VFS_VAL_INFO_RATE 0x0001 +#define VFS_VAL_0076 0x0012 +#define VFS_VAL_0078 0x2230 +#define VFS_VAL_IMG_EXPOSURE 0x21c0 /* Structure for Validity device */ -struct _FpDeviceVfs101 { - FpImageDevice parent; +struct _FpDeviceVfs101 +{ + FpImageDevice parent; - /* Action state */ - gboolean active; - gboolean deactivate; + /* Action state */ + gboolean active; + gboolean deactivate; - /* Sequential number */ - unsigned int seqnum; + /* Sequential number */ + unsigned int seqnum; - /* Buffer for input/output */ - unsigned char *buffer; + /* Buffer for input/output */ + unsigned char *buffer; - /* Length of data to send or received */ - unsigned int length; + /* Length of data to send or received */ + unsigned int length; - /* Ignore usb error */ - int ignore_error; + /* Ignore usb error */ + int ignore_error; - /* Loop counter */ - int counter; + /* Loop counter */ + int counter; - /* Image contrast */ - int contrast; + /* Image contrast */ + int contrast; - /* Best contrast */ - int best_contrast; + /* Best contrast */ + int best_contrast; - /* Best contrast level */ - int best_clevel; + /* Best contrast level */ + int best_clevel; - /* Bottom line of image */ - int bottom; + /* Bottom line of image */ + int bottom; - /* Image height */ - int height; + /* Image height */ + int height; }; -G_DECLARE_FINAL_TYPE(FpDeviceVfs101, fpi_device_vfs101, FPI, DEVICE_VFS101, - FpImageDevice); -G_DEFINE_TYPE(FpDeviceVfs101, fpi_device_vfs101, FP_TYPE_IMAGE_DEVICE); +G_DECLARE_FINAL_TYPE (FpDeviceVfs101, fpi_device_vfs101, FPI, DEVICE_VFS101, + FpImageDevice); +G_DEFINE_TYPE (FpDeviceVfs101, fpi_device_vfs101, FP_TYPE_IMAGE_DEVICE); /* Return byte at specified position */ -static inline unsigned char byte(int position, int value) +static inline unsigned char +byte (int position, int value) { - return (value >> (position * 8)) & 0xff; + return (value >> (position * 8)) & 0xff; } /* Return sequential number */ -static inline unsigned short get_seqnum(int h, int l) +static inline unsigned short +get_seqnum (int h, int l) { - return (h<<8) | l; + return (h << 8) | l; } /* Check sequential number */ -static inline int check_seqnum(FpDeviceVfs101 *vdev) +static inline int +check_seqnum (FpDeviceVfs101 *vdev) { - if ((byte(0, vdev->seqnum) == vdev->buffer[0]) && - (byte(1, vdev->seqnum) == vdev->buffer[1])) - return 0; - else - return 1; + if ((byte (0, vdev->seqnum) == vdev->buffer[0]) && + (byte (1, vdev->seqnum) == vdev->buffer[1])) + return 0; + else + return 1; } /* Internal result codes */ -enum -{ - RESULT_RETRY, - RESULT_RETRY_SHORT, - RESULT_RETRY_REMOVE, - RESULT_COUNT, +enum { + RESULT_RETRY, + RESULT_RETRY_SHORT, + RESULT_RETRY_REMOVE, + RESULT_COUNT, }; /* Dump buffer for debug */ #define dump_buffer(buf) \ - fp_dbg("%02x %02x %02x %02x %02x %02x %02x %02x", \ - buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13] \ - ) + fp_dbg ("%02x %02x %02x %02x %02x %02x %02x %02x", \ + buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13] \ + ) /* Callback of asynchronous send */ -static void async_send_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +async_send_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE(device); - FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev); - /* Skip error check if ignore_error is set */ - if (error) { - if (!self->ignore_error) { - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } else { - g_error_free (error); - fp_dbg ("Ignoring send error: %s", error->message); - } - } - /* Reset ignore_error flag */ - self->ignore_error = FALSE; + /* Skip error check if ignore_error is set */ + if (error) + { + if (!self->ignore_error) + { + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } + else + { + g_error_free (error); + fp_dbg ("Ignoring send error: %s", error->message); + } + } + /* Reset ignore_error flag */ + self->ignore_error = FALSE; - /* Dump buffer for debug */ - dump_buffer(self->buffer); + /* Dump buffer for debug */ + dump_buffer (self->buffer); - fpi_ssm_next_state(transfer->ssm); + fpi_ssm_next_state (transfer->ssm); } /* Submit asynchronous send */ static void -async_send(FpiSsm *ssm, - FpImageDevice *dev) +async_send (FpiSsm *ssm, + FpImageDevice *dev) { - FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); - FpiUsbTransfer *transfer; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev); + FpiUsbTransfer *transfer; - transfer = fpi_usb_transfer_new(FP_DEVICE (dev)); + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); - /* Put sequential number into the buffer */ - self->seqnum++; - self->buffer[0] = byte(0, self->seqnum); - self->buffer[1] = byte(1, self->seqnum); + /* Put sequential number into the buffer */ + self->seqnum++; + self->buffer[0] = byte (0, self->seqnum); + self->buffer[1] = byte (1, self->seqnum); - /* Prepare bulk transfer */ - fpi_usb_transfer_fill_bulk_full(transfer, EP_OUT(1), - self->buffer, self->length, NULL); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - async_send_cb, NULL); - fpi_usb_transfer_unref(transfer); + /* Prepare bulk transfer */ + fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT (1), + self->buffer, self->length, NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + async_send_cb, NULL); + fpi_usb_transfer_unref (transfer); } /* Callback of asynchronous recv */ -static void async_recv_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +async_recv_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE(device); - FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev); - /* Skip error check if ignore_error is set */ - if (!self->ignore_error) - { - if (error) - { - /* Transfer not completed, return IO error */ - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } + /* Skip error check if ignore_error is set */ + if (!self->ignore_error) + { + if (error) + { + /* Transfer not completed, return IO error */ + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } - if (check_seqnum(self)) - { - /* Sequential number received mismatch, return protocol error */ - fp_err("seqnum mismatch, got %04x, expected %04x", - get_seqnum(self->buffer[1], self->buffer[0]), - self->seqnum); - fpi_ssm_mark_failed(transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - return; - } - } + if (check_seqnum (self)) + { + /* Sequential number received mismatch, return protocol error */ + fp_err ("seqnum mismatch, got %04x, expected %04x", + get_seqnum (self->buffer[1], self->buffer[0]), + self->seqnum); + fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + return; + } + } - g_clear_pointer (&error, g_error_free); + g_clear_pointer (&error, g_error_free); - /* Reset ignore_error flag */ - self->ignore_error = FALSE; + /* Reset ignore_error flag */ + self->ignore_error = FALSE; - /* Dump buffer for debug */ - dump_buffer(self->buffer); + /* Dump buffer for debug */ + dump_buffer (self->buffer); - /* Set length of received data */ - self->length = transfer->actual_length; + /* Set length of received data */ + self->length = transfer->actual_length; - fpi_ssm_next_state(transfer->ssm); + fpi_ssm_next_state (transfer->ssm); } /* Submit asynchronous recv */ static void -async_recv(FpiSsm *ssm, - FpImageDevice *dev) +async_recv (FpiSsm *ssm, + FpImageDevice *dev) { - FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); - FpiUsbTransfer *transfer; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev); + FpiUsbTransfer *transfer; - /* Allocation of transfer */ - transfer = fpi_usb_transfer_new(FP_DEVICE (dev)); + /* Allocation of transfer */ + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); - /* Prepare bulk transfer */ - fpi_usb_transfer_fill_bulk_full(transfer, EP_IN(1), self->buffer, - 0x0f, NULL); - transfer->ssm = ssm; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - async_recv_cb, NULL); - fpi_usb_transfer_unref(transfer); + /* Prepare bulk transfer */ + fpi_usb_transfer_fill_bulk_full (transfer, EP_IN (1), self->buffer, + 0x0f, NULL); + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + async_recv_cb, NULL); + fpi_usb_transfer_unref (transfer); } -static void async_load(FpiSsm *ssm, FpImageDevice *dev); +static void async_load (FpiSsm *ssm, + FpImageDevice *dev); /* Callback of asynchronous load */ -static void async_load_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +async_load_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE(device); - FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev); - /* Skip error check if ignore_error is set */ - if (!self->ignore_error) - { - if (error) - { - /* Transfer not completed */ - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } + /* Skip error check if ignore_error is set */ + if (!self->ignore_error) + { + if (error) + { + /* Transfer not completed */ + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } - if (transfer->actual_length % VFS_FRAME_SIZE) - { - /* Received incomplete frame, return protocol error */ - fp_err("received incomplete frame"); - fpi_ssm_mark_failed(transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - return; - } - } + if (transfer->actual_length % VFS_FRAME_SIZE) + { + /* Received incomplete frame, return protocol error */ + fp_err ("received incomplete frame"); + fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + return; + } + } - /* Any error has been ignored. */ - g_clear_pointer (&error, g_error_free); + /* Any error has been ignored. */ + g_clear_pointer (&error, g_error_free); - /* Increase image length */ - self->length += transfer->actual_length; + /* Increase image length */ + self->length += transfer->actual_length; - if (transfer->actual_length == VFS_BLOCK_SIZE) - { - if ((VFS_BUFFER_SIZE - self->length) < VFS_BLOCK_SIZE) - { - /* Buffer full, image too large, return no memory error */ - fp_err("buffer full, image too large"); - fpi_ssm_mark_failed(transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - return; - } - else - /* Image load not completed, submit another asynchronous load */ - async_load(transfer->ssm, dev); - } - else - { - /* Reset ignore_error flag */ - self->ignore_error = FALSE; + if (transfer->actual_length == VFS_BLOCK_SIZE) + { + if ((VFS_BUFFER_SIZE - self->length) < VFS_BLOCK_SIZE) + { + /* Buffer full, image too large, return no memory error */ + fp_err ("buffer full, image too large"); + fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + return; + } + else + { + /* Image load not completed, submit another asynchronous load */ + async_load (transfer->ssm, dev); + } + } + else + { + /* Reset ignore_error flag */ + self->ignore_error = FALSE; - /* Image load completed, go to next state */ - self->height = self->length / VFS_FRAME_SIZE; - fp_dbg("image loaded, height = %d", self->height); - fpi_ssm_next_state(transfer->ssm); - } + /* Image load completed, go to next state */ + self->height = self->length / VFS_FRAME_SIZE; + fp_dbg ("image loaded, height = %d", self->height); + fpi_ssm_next_state (transfer->ssm); + } } /* Submit asynchronous load */ static void -async_load(FpiSsm *ssm, - FpImageDevice *dev) +async_load (FpiSsm *ssm, + FpImageDevice *dev) { - FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); - FpiUsbTransfer *transfer; - unsigned char *buffer; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev); + FpiUsbTransfer *transfer; + unsigned char *buffer; - /* Allocation of transfer */ - transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + /* Allocation of transfer */ + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); - /* Append new data into the buffer */ - buffer = self->buffer + self->length; + /* Append new data into the buffer */ + buffer = self->buffer + self->length; - /* Prepare bulk transfer */ - fpi_usb_transfer_fill_bulk_full(transfer, EP_IN(2), buffer, - VFS_BLOCK_SIZE, NULL); - transfer->ssm = ssm; - fpi_usb_transfer_submit(transfer, BULK_TIMEOUT, NULL, - async_load_cb, NULL); - fpi_usb_transfer_unref(transfer); + /* Prepare bulk transfer */ + fpi_usb_transfer_fill_bulk_full (transfer, EP_IN (2), buffer, + VFS_BLOCK_SIZE, NULL); + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + async_load_cb, NULL); + fpi_usb_transfer_unref (transfer); } /* Submit asynchronous sleep */ static void -async_sleep(unsigned int msec, - FpiSsm *ssm, - FpImageDevice *dev) +async_sleep (unsigned int msec, + FpiSsm *ssm, + FpImageDevice *dev) { - fpi_device_add_timeout(FP_DEVICE(dev), msec, - fpi_ssm_next_state_timeout_cb, ssm); + fpi_device_add_timeout (FP_DEVICE (dev), msec, + fpi_ssm_next_state_timeout_cb, ssm); } /* Swap ssm states */ -enum -{ - M_SWAP_SEND, - M_SWAP_RECV, - M_SWAP_NUM_STATES, +enum { + M_SWAP_SEND, + M_SWAP_RECV, + M_SWAP_NUM_STATES, }; /* Exec swap sequential state machine */ -static void m_swap_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +m_swap_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - switch (fpi_ssm_get_cur_state(ssm)) - { - case M_SWAP_SEND: - /* Send data */ - async_send(ssm, user_data); - break; + switch (fpi_ssm_get_cur_state (ssm)) + { + case M_SWAP_SEND: + /* Send data */ + async_send (ssm, user_data); + break; - case M_SWAP_RECV: - /* Recv response */ - async_recv(ssm, user_data); - break; - } + case M_SWAP_RECV: + /* Recv response */ + async_recv (ssm, user_data); + break; + } } /* Start swap sequential state machine */ static void -m_swap(FpiSsm *ssm, - FpImageDevice *dev, - unsigned char *data, - size_t length) +m_swap (FpiSsm *ssm, + FpImageDevice *dev, + unsigned char *data, + size_t length) { - FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); - FpiSsm *subsm; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev); + FpiSsm *subsm; - /* Prepare data for sending */ - memcpy(self->buffer, data, length); - memset(self->buffer + length, 0, 16 - length); - self->length = length; + /* Prepare data for sending */ + memcpy (self->buffer, data, length); + memset (self->buffer + length, 0, 16 - length); + self->length = length; - /* Start swap ssm */ - subsm = fpi_ssm_new(FP_DEVICE(dev), m_swap_state, M_SWAP_NUM_STATES, - dev); - fpi_ssm_start_subsm(ssm, subsm); + /* Start swap ssm */ + subsm = fpi_ssm_new (FP_DEVICE (dev), m_swap_state, M_SWAP_NUM_STATES, + dev); + fpi_ssm_start_subsm (ssm, subsm); } /* Retrieve fingerprint image */ static void -vfs_get_print(FpiSsm *ssm, - FpImageDevice *dev, - unsigned int param, - int type) +vfs_get_print (FpiSsm *ssm, + FpImageDevice *dev, + unsigned int param, + int type) { - unsigned char data[2][0x0e] = { - { 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01 }, - { 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01 } - }; + unsigned char data[2][0x0e] = { + { 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01 } + }; - fp_dbg("param = %04x, type = %d", param, type); + fp_dbg ("param = %04x, type = %d", param, type); - /* Prepare data for sending */ - data[type][6] = byte(0, param); - data[type][7] = byte(1, param); + /* Prepare data for sending */ + data[type][6] = byte (0, param); + data[type][7] = byte (1, param); - /* Run swap sequential state machine */ - m_swap(ssm, dev, data[type], 0x0e); + /* Run swap sequential state machine */ + m_swap (ssm, dev, data[type], 0x0e); } /* Set a parameter value on the device */ static void -vfs_set_param(FpiSsm *ssm, - FpImageDevice *dev, - unsigned int param, - unsigned int value) +vfs_set_param (FpiSsm *ssm, + FpImageDevice *dev, + unsigned int param, + unsigned int value) { - unsigned char data[0x0a] = { 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 }; + unsigned char data[0x0a] = { 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 }; - fp_dbg("param = %04x, value = %04x", param, value); + fp_dbg ("param = %04x, value = %04x", param, value); - /* Prepare data for sending */ - data[6] = byte(0, param); - data[7] = byte(1, param); - data[8] = byte(0, value); - data[9] = byte(1, value); + /* Prepare data for sending */ + data[6] = byte (0, param); + data[7] = byte (1, param); + data[8] = byte (0, value); + data[9] = byte (1, value); - /* Run swap sequential state machine */ - m_swap(ssm, dev, data, 0x0a); + /* Run swap sequential state machine */ + m_swap (ssm, dev, data, 0x0a); } /* Abort previous print */ static void -vfs_abort_print(FpiSsm *ssm, - FpImageDevice *dev) +vfs_abort_print (FpiSsm *ssm, + FpImageDevice *dev) { - unsigned char data[0x06] = { 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00 }; + unsigned char data[0x06] = { 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00 }; - G_DEBUG_HERE(); + G_DEBUG_HERE (); - /* Run swap sequential state machine */ - m_swap (ssm, dev, data, 0x06); + /* Run swap sequential state machine */ + m_swap (ssm, dev, data, 0x06); } /* Poke a value on a region */ static void -vfs_poke(FpiSsm *ssm, - FpImageDevice *dev, - unsigned int addr, - unsigned int value, - unsigned int size) +vfs_poke (FpiSsm *ssm, + FpImageDevice *dev, + unsigned int addr, + unsigned int value, + unsigned int size) { - unsigned char data[0x0f] = { 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + unsigned char data[0x0f] = { 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - fp_dbg("addr = %04x, value = %04x", addr, value); + fp_dbg ("addr = %04x, value = %04x", addr, value); - /* Prepare data for sending */ - data[6] = byte(0, addr); - data[7] = byte(1, addr); - data[8] = byte(2, addr); - data[9] = byte(3, addr); - data[10] = byte(0, value); - data[11] = byte(1, value); - data[12] = byte(2, value); - data[13] = byte(3, value); - data[14] = byte(0, size); + /* Prepare data for sending */ + data[6] = byte (0, addr); + data[7] = byte (1, addr); + data[8] = byte (2, addr); + data[9] = byte (3, addr); + data[10] = byte (0, value); + data[11] = byte (1, value); + data[12] = byte (2, value); + data[13] = byte (3, value); + data[14] = byte (0, size); - /* Run swap sequential state machine */ - m_swap(ssm, dev, data, 0x0f); + /* Run swap sequential state machine */ + m_swap (ssm, dev, data, 0x0f); } /* Get current finger state */ static void -vfs_get_finger_state(FpiSsm *ssm, - FpImageDevice *dev) +vfs_get_finger_state (FpiSsm *ssm, + FpImageDevice *dev) { - unsigned char data[0x06] = { 0x00, 0x00, 0x00, 0x00, 0x16, 0x00 }; + unsigned char data[0x06] = { 0x00, 0x00, 0x00, 0x00, 0x16, 0x00 }; - G_DEBUG_HERE(); + G_DEBUG_HERE (); - /* Run swap sequential state machine */ - m_swap (ssm, dev, data, 0x06); + /* Run swap sequential state machine */ + m_swap (ssm, dev, data, 0x06); } /* Load raw image from reader */ static void -vfs_img_load(FpiSsm *ssm, - FpImageDevice *dev) +vfs_img_load (FpiSsm *ssm, + FpImageDevice *dev) { - FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); + FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev); - G_DEBUG_HERE(); + G_DEBUG_HERE (); - /* Reset buffer length */ - self->length = 0; + /* Reset buffer length */ + self->length = 0; - /* Reset image properties */ - self->bottom = 0; - self->height = -1; + /* Reset image properties */ + self->bottom = 0; + self->height = -1; - /* Asynchronous load */ - async_load(ssm, dev); + /* Asynchronous load */ + async_load (ssm, dev); } -#define offset(x, y) ((x) + ((y) * VFS_FRAME_SIZE)) +#define offset(x, y) ((x) + ((y) * VFS_FRAME_SIZE)) /* Screen image to remove noise and find bottom line and height of image */ -static void img_screen(FpDeviceVfs101 *vdev) +static void +img_screen (FpDeviceVfs101 *vdev) { - int y, x, count, top; - long int level; - int last_line = vdev->height - 1; + int y, x, count, top; + long int level; + int last_line = vdev->height - 1; - fp_dbg("image height before screen = %d", vdev->height); + fp_dbg ("image height before screen = %d", vdev->height); - count = 0; + count = 0; - /* Image returned from sensor can contain many empty lines, - * for remove these lines compare byte 282-283 (scan level information) - * with two different thresholds, one for the begin of finger image and - * one for the end. To increase stability of the code use a counter - * of lines that satisfy the threshold. - */ - for (y = last_line, top = last_line; y >= 0; y--) - { - /* Take image scan level */ - level = vdev->buffer[offset(283, y)] * 256 + - vdev->buffer[offset(282, y)]; + /* Image returned from sensor can contain many empty lines, + * for remove these lines compare byte 282-283 (scan level information) + * with two different thresholds, one for the begin of finger image and + * one for the end. To increase stability of the code use a counter + * of lines that satisfy the threshold. + */ + for (y = last_line, top = last_line; y >= 0; y--) + { + /* Take image scan level */ + level = vdev->buffer[offset (283, y)] * 256 + + vdev->buffer[offset (282, y)]; - fp_dbg("line = %d, scan level = %ld", y, level); + fp_dbg ("line = %d, scan level = %ld", y, level); - if (level >= VFS_IMG_SLT_BEGIN && top == last_line) - { - /* Begin threshold satisfied */ - if (count < VFS_IMG_SLT_LINES) - /* Increase count */ - count++; - else - { - /* Found top fingerprint line */ - top = y + VFS_IMG_SLT_LINES; - count = 0; - } - } - else if ((level < VFS_IMG_SLT_END || level >= 65535) && - top != last_line) - { - /* End threshold satisfied */ - if (count < VFS_IMG_SLT_LINES) - /* Increase count */ - count++; - else - { - /* Found bottom fingerprint line */ - vdev->bottom = y + VFS_IMG_SLT_LINES + 1; - break; - } - } - else - /* Not threshold satisfied, reset count */ - count = 0; - } + if (level >= VFS_IMG_SLT_BEGIN && top == last_line) + { + /* Begin threshold satisfied */ + if (count < VFS_IMG_SLT_LINES) + { + /* Increase count */ + count++; + } + else + { + /* Found top fingerprint line */ + top = y + VFS_IMG_SLT_LINES; + count = 0; + } + } + else if ((level < VFS_IMG_SLT_END || level >= 65535) && + top != last_line) + { + /* End threshold satisfied */ + if (count < VFS_IMG_SLT_LINES) + { + /* Increase count */ + count++; + } + else + { + /* Found bottom fingerprint line */ + vdev->bottom = y + VFS_IMG_SLT_LINES + 1; + break; + } + } + else + { + /* Not threshold satisfied, reset count */ + count = 0; + } + } - vdev->height = top - vdev->bottom + 1; + vdev->height = top - vdev->bottom + 1; - /* Check max height */ - if (vdev->height > VFS_IMG_MAX_HEIGHT) - vdev->height = VFS_IMG_MAX_HEIGHT; + /* Check max height */ + if (vdev->height > VFS_IMG_MAX_HEIGHT) + vdev->height = VFS_IMG_MAX_HEIGHT; - fp_dbg("image height after screen = %d", vdev->height); + fp_dbg ("image height after screen = %d", vdev->height); - /* Scan image and remove noise */ - for (y = vdev->bottom; y <= top; y++) - for (x = 6; x < VFS_IMG_WIDTH + 6; x++) - if (vdev->buffer[offset(x, y)] > VFS_IMG_MIN_IMAGE_LEVEL) - vdev->buffer[offset(x, y)] = 255; + /* Scan image and remove noise */ + for (y = vdev->bottom; y <= top; y++) + for (x = 6; x < VFS_IMG_WIDTH + 6; x++) + if (vdev->buffer[offset (x, y)] > VFS_IMG_MIN_IMAGE_LEVEL) + vdev->buffer[offset (x, y)] = 255; }; /* Copy image from reader buffer and put it into image data */ -static void img_copy(FpDeviceVfs101 *self, FpImage *img) +static void +img_copy (FpDeviceVfs101 *self, FpImage *img) { - unsigned int line; - unsigned char *img_buffer = img->data; - unsigned char *vdev_buffer = self->buffer + (self->bottom * VFS_FRAME_SIZE) + 6; + unsigned int line; + unsigned char *img_buffer = img->data; + unsigned char *vdev_buffer = self->buffer + (self->bottom * VFS_FRAME_SIZE) + 6; - for (line = 0; line < img->height; line++) - { - /* Copy image line from reader buffer to image data */ - memcpy(img_buffer, vdev_buffer, VFS_IMG_WIDTH); + for (line = 0; line < img->height; line++) + { + /* Copy image line from reader buffer to image data */ + memcpy (img_buffer, vdev_buffer, VFS_IMG_WIDTH); - /* Next line of reader buffer */ - vdev_buffer = vdev_buffer + VFS_FRAME_SIZE; + /* Next line of reader buffer */ + vdev_buffer = vdev_buffer + VFS_FRAME_SIZE; - /* Next line of image buffer */ - img_buffer = img_buffer + VFS_IMG_WIDTH; - } + /* Next line of image buffer */ + img_buffer = img_buffer + VFS_IMG_WIDTH; + } } /* Extract fingerpint image from raw data */ static void -img_extract(FpiSsm *ssm, - FpImageDevice *dev) +img_extract (FpiSsm *ssm, + FpImageDevice *dev) { - FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); - FpImage *img; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev); + FpImage *img; - /* Screen image to remove noise and find top and bottom line */ - img_screen(self); + /* Screen image to remove noise and find top and bottom line */ + img_screen (self); - /* Check image height */ - if (self->height < VFS_IMG_MIN_HEIGHT) - { - /* Image too short */ - self->height = 0; - fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT); - return; - } + /* Check image height */ + if (self->height < VFS_IMG_MIN_HEIGHT) + { + /* Image too short */ + self->height = 0; + fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT); + return; + } - /* Create new image */ - img = fp_image_new(self->height, VFS_IMG_WIDTH); - img->width = VFS_IMG_WIDTH; - img->height = self->height; - img->flags = FPI_IMAGE_V_FLIPPED; + /* Create new image */ + img = fp_image_new (self->height, VFS_IMG_WIDTH); + img->width = VFS_IMG_WIDTH; + img->height = self->height; + img->flags = FPI_IMAGE_V_FLIPPED; - /* Copy data into image */ - img_copy(self, img); + /* Copy data into image */ + img_copy (self, img); - /* Notify image captured */ - fpi_image_device_image_captured(dev, img); + /* Notify image captured */ + fpi_image_device_image_captured (dev, img); }; /* Finger states */ -enum -{ - VFS_FINGER_EMPTY, - VFS_FINGER_PRESENT, - VFS_FINGER_UNKNOWN, +enum { + VFS_FINGER_EMPTY, + VFS_FINGER_PRESENT, + VFS_FINGER_UNKNOWN, }; /* Return finger state */ -static inline int vfs_finger_state(FpDeviceVfs101 *vdev) +static inline int +vfs_finger_state (FpDeviceVfs101 *vdev) { - /* Check finger state */ - switch (vdev->buffer[0x0a]) - { - case 0x00: - case 0x01: - /* Finger is empty */ - return VFS_FINGER_EMPTY; - break; + /* Check finger state */ + switch (vdev->buffer[0x0a]) + { + case 0x00: + case 0x01: + /* Finger is empty */ + return VFS_FINGER_EMPTY; + break; - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - /* Finger is present */ - return VFS_FINGER_PRESENT; - break; + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + /* Finger is present */ + return VFS_FINGER_PRESENT; + break; - default: - return VFS_FINGER_UNKNOWN; - } + default: + return VFS_FINGER_UNKNOWN; + } }; /* Check contrast of image */ -static void vfs_check_contrast(FpDeviceVfs101 *vdev) +static void +vfs_check_contrast (FpDeviceVfs101 *vdev) { - int y; - long int count = 0; + int y; + long int count = 0; - /* Check difference from byte 4 to byte 5 for verify contrast of image */ - for (y = 0; y < vdev->height; y++) - count = count + vdev->buffer[offset(5, y)] - vdev->buffer[offset(4, y)]; - count = count / vdev->height; + /* Check difference from byte 4 to byte 5 for verify contrast of image */ + for (y = 0; y < vdev->height; y++) + count = count + vdev->buffer[offset (5, y)] - vdev->buffer[offset (4, y)]; + count = count / vdev->height; - if (count < 16) - { - /* Contrast not valid, retry */ - vdev->contrast++; - return; - } + if (count < 16) + { + /* Contrast not valid, retry */ + vdev->contrast++; + return; + } - fp_dbg("contrast = %d, level = %ld", vdev->contrast, count); + fp_dbg ("contrast = %d, level = %ld", vdev->contrast, count); - if (labs(count - VFS_IMG_BEST_CONTRAST) < abs(vdev->best_clevel - VFS_IMG_BEST_CONTRAST)) - { - /* Better contrast found, use it */ - vdev->best_contrast = vdev->contrast; - vdev->best_clevel = count; - } + if (labs (count - VFS_IMG_BEST_CONTRAST) < abs (vdev->best_clevel - VFS_IMG_BEST_CONTRAST)) + { + /* Better contrast found, use it */ + vdev->best_contrast = vdev->contrast; + vdev->best_clevel = count; + } } /* Loop ssm states */ -enum -{ - /* Step 0 - Scan finger */ - M_LOOP_0_GET_PRINT, - M_LOOP_0_SLEEP, - M_LOOP_0_GET_STATE, - M_LOOP_0_LOAD_IMAGE, - M_LOOP_0_EXTRACT_IMAGE, - M_LOOP_0_CHECK_ACTION, +enum { + /* Step 0 - Scan finger */ + M_LOOP_0_GET_PRINT, + M_LOOP_0_SLEEP, + M_LOOP_0_GET_STATE, + M_LOOP_0_LOAD_IMAGE, + M_LOOP_0_EXTRACT_IMAGE, + M_LOOP_0_CHECK_ACTION, - /* Step 1 - Scan failed */ - M_LOOP_1_GET_STATE, - M_LOOP_1_CHECK_STATE, - M_LOOP_1_GET_PRINT, - M_LOOP_1_LOAD_IMAGE, - M_LOOP_1_LOOP, - M_LOOP_1_SLEEP, + /* Step 1 - Scan failed */ + M_LOOP_1_GET_STATE, + M_LOOP_1_CHECK_STATE, + M_LOOP_1_GET_PRINT, + M_LOOP_1_LOAD_IMAGE, + M_LOOP_1_LOOP, + M_LOOP_1_SLEEP, - /* Step 2 - Abort print */ - M_LOOP_2_ABORT_PRINT, - M_LOOP_2_LOAD_IMAGE, + /* Step 2 - Abort print */ + M_LOOP_2_ABORT_PRINT, + M_LOOP_2_LOAD_IMAGE, - /* Step 3 - Wait aborting */ - M_LOOP_3_GET_PRINT, - M_LOOP_3_LOAD_IMAGE, - M_LOOP_3_CHECK_IMAGE, - M_LOOP_3_LOOP, + /* Step 3 - Wait aborting */ + M_LOOP_3_GET_PRINT, + M_LOOP_3_LOAD_IMAGE, + M_LOOP_3_CHECK_IMAGE, + M_LOOP_3_LOOP, - /* Number of states */ - M_LOOP_NUM_STATES, + /* Number of states */ + M_LOOP_NUM_STATES, }; /* Exec loop sequential state machine */ -static void m_loop_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +m_loop_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - FpImageDevice *dev = user_data; - FpDeviceVfs101 *self = FPI_DEVICE_VFS101(_dev); + FpImageDevice *dev = user_data; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (_dev); - /* Complete if deactivation was requested */ - if (self->deactivate) { - fpi_ssm_mark_completed(ssm); - return; - } + /* Complete if deactivation was requested */ + if (self->deactivate) + { + fpi_ssm_mark_completed (ssm); + return; + } - switch (fpi_ssm_get_cur_state(ssm)) - { - case M_LOOP_0_GET_PRINT: - /* Send get print command to the reader */ - vfs_get_print(ssm, dev, VFS_BUFFER_HEIGHT, 1); - break; + switch (fpi_ssm_get_cur_state (ssm)) + { + case M_LOOP_0_GET_PRINT: + /* Send get print command to the reader */ + vfs_get_print (ssm, dev, VFS_BUFFER_HEIGHT, 1); + break; - case M_LOOP_0_SLEEP: - /* Wait fingerprint scanning */ - async_sleep(50, ssm, dev); - break; + case M_LOOP_0_SLEEP: + /* Wait fingerprint scanning */ + async_sleep (50, ssm, dev); + break; - case M_LOOP_0_GET_STATE: - /* Get finger state */ - vfs_get_finger_state(ssm, dev); - break; + case M_LOOP_0_GET_STATE: + /* Get finger state */ + vfs_get_finger_state (ssm, dev); + break; - case M_LOOP_0_LOAD_IMAGE: - /* Check finger state */ - switch (vfs_finger_state(self)) - { - case VFS_FINGER_EMPTY: - fpi_image_device_report_finger_status(dev, FALSE); + case M_LOOP_0_LOAD_IMAGE: + /* Check finger state */ + switch (vfs_finger_state (self)) + { + case VFS_FINGER_EMPTY: + fpi_image_device_report_finger_status (dev, FALSE); - /* Finger isn't present, loop */ - fpi_ssm_jump_to_state(ssm, M_LOOP_0_SLEEP); - break; + /* Finger isn't present, loop */ + fpi_ssm_jump_to_state (ssm, M_LOOP_0_SLEEP); + break; - case VFS_FINGER_PRESENT: - fpi_image_device_report_finger_status(dev, TRUE); + case VFS_FINGER_PRESENT: + fpi_image_device_report_finger_status (dev, TRUE); - /* Load image from reader */ - self->ignore_error = TRUE; - vfs_img_load(ssm, dev); - break; + /* Load image from reader */ + self->ignore_error = TRUE; + vfs_img_load (ssm, dev); + break; - default: - fpi_image_device_report_finger_status(dev, FALSE); + default: + fpi_image_device_report_finger_status (dev, FALSE); - /* Unknown state */ - fp_err("unknown device state 0x%02x", - self->buffer[0x0a]); - fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - break; - } - break; + /* Unknown state */ + fp_err ("unknown device state 0x%02x", + self->buffer[0x0a]); + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + break; + } + break; - case M_LOOP_0_EXTRACT_IMAGE: - /* Fingerprint is loaded, extract image from raw data */ - img_extract(ssm, dev); + case M_LOOP_0_EXTRACT_IMAGE: + /* Fingerprint is loaded, extract image from raw data */ + img_extract (ssm, dev); - /* Wait handling image */ - async_sleep(10, ssm, dev); - break; + /* Wait handling image */ + async_sleep (10, ssm, dev); + break; - case M_LOOP_0_CHECK_ACTION: - /* Action not completed */ - if (self->height > 0) - /* Continue loop */ - fpi_ssm_jump_to_state(ssm, M_LOOP_2_ABORT_PRINT); - else - /* Error found */ - fpi_ssm_next_state(ssm); - break; + case M_LOOP_0_CHECK_ACTION: + /* Action not completed */ + if (self->height > 0) + /* Continue loop */ + fpi_ssm_jump_to_state (ssm, M_LOOP_2_ABORT_PRINT); + else + /* Error found */ + fpi_ssm_next_state (ssm); + break; - case M_LOOP_1_GET_STATE: - /* Get finger state */ - vfs_get_finger_state(ssm, dev); - break; + case M_LOOP_1_GET_STATE: + /* Get finger state */ + vfs_get_finger_state (ssm, dev); + break; - case M_LOOP_1_CHECK_STATE: - /* Check finger state */ - if (vfs_finger_state(self) == VFS_FINGER_PRESENT) - { - fpi_image_device_report_finger_status(dev, TRUE); - async_sleep(250, ssm, dev); - } - else - { - /* Finger not present */ - fpi_image_device_report_finger_status(dev, FALSE); + case M_LOOP_1_CHECK_STATE: + /* Check finger state */ + if (vfs_finger_state (self) == VFS_FINGER_PRESENT) + { + fpi_image_device_report_finger_status (dev, TRUE); + async_sleep (250, ssm, dev); + } + else + { + /* Finger not present */ + fpi_image_device_report_finger_status (dev, FALSE); - /* Continue */ - fpi_ssm_jump_to_state(ssm, M_LOOP_1_SLEEP); - } - break; + /* Continue */ + fpi_ssm_jump_to_state (ssm, M_LOOP_1_SLEEP); + } + break; - case M_LOOP_1_GET_PRINT: - /* Send get print command to the reader */ - vfs_get_print(ssm, dev, VFS_BUFFER_HEIGHT, 1); - break; + case M_LOOP_1_GET_PRINT: + /* Send get print command to the reader */ + vfs_get_print (ssm, dev, VFS_BUFFER_HEIGHT, 1); + break; - case M_LOOP_1_LOAD_IMAGE: - /* Load image */ - self->ignore_error = TRUE; - vfs_img_load(ssm, dev); - break; + case M_LOOP_1_LOAD_IMAGE: + /* Load image */ + self->ignore_error = TRUE; + vfs_img_load (ssm, dev); + break; - case M_LOOP_1_LOOP: - /* Loop */ - fpi_ssm_jump_to_state(ssm, M_LOOP_1_GET_STATE); - break; + case M_LOOP_1_LOOP: + /* Loop */ + fpi_ssm_jump_to_state (ssm, M_LOOP_1_GET_STATE); + break; - case M_LOOP_1_SLEEP: - /* Wait fingerprint scanning */ - async_sleep(10, ssm, dev); - break; + case M_LOOP_1_SLEEP: + /* Wait fingerprint scanning */ + async_sleep (10, ssm, dev); + break; - case M_LOOP_2_ABORT_PRINT: - /* Abort print command */ - vfs_abort_print(ssm, dev); - break; + case M_LOOP_2_ABORT_PRINT: + /* Abort print command */ + vfs_abort_print (ssm, dev); + break; - case M_LOOP_2_LOAD_IMAGE: - /* Load abort image */ - self->ignore_error = TRUE; - vfs_img_load(ssm, dev); - break; + case M_LOOP_2_LOAD_IMAGE: + /* Load abort image */ + self->ignore_error = TRUE; + vfs_img_load (ssm, dev); + break; - case M_LOOP_3_GET_PRINT: - /* Get empty image */ - vfs_get_print(ssm, dev, 0x000a, 0); - break; + case M_LOOP_3_GET_PRINT: + /* Get empty image */ + vfs_get_print (ssm, dev, 0x000a, 0); + break; - case M_LOOP_3_LOAD_IMAGE: - /* Load abort image */ - self->ignore_error = TRUE; - vfs_img_load(ssm, dev); - break; + case M_LOOP_3_LOAD_IMAGE: + /* Load abort image */ + self->ignore_error = TRUE; + vfs_img_load (ssm, dev); + break; - case M_LOOP_3_CHECK_IMAGE: - if (self->height == 10) - { - /* Image load correctly, jump to step 0 */ - self->counter = 0; - fpi_ssm_jump_to_state(ssm, M_LOOP_0_GET_PRINT); - } - else if (self->counter < 10) - { - /* Wait aborting */ - self->counter++; - async_sleep(100, ssm, dev); - } - else - { - /* reach max loop counter, return protocol error */ - fp_err("waiting abort reach max loop counter"); - fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - } - break; + case M_LOOP_3_CHECK_IMAGE: + if (self->height == 10) + { + /* Image load correctly, jump to step 0 */ + self->counter = 0; + fpi_ssm_jump_to_state (ssm, M_LOOP_0_GET_PRINT); + } + else if (self->counter < 10) + { + /* Wait aborting */ + self->counter++; + async_sleep (100, ssm, dev); + } + else + { + /* reach max loop counter, return protocol error */ + fp_err ("waiting abort reach max loop counter"); + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + } + break; - case M_LOOP_3_LOOP: - /* Loop */ - fpi_ssm_jump_to_state(ssm, M_LOOP_3_GET_PRINT); - break; - } + case M_LOOP_3_LOOP: + /* Loop */ + fpi_ssm_jump_to_state (ssm, M_LOOP_3_GET_PRINT); + break; + } } /* Complete loop sequential state machine */ -static void m_loop_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +static void +m_loop_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev); + FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev); - /* When the loop completes, we have (successfully) deactivated */ - if (self->active) - fpi_image_device_deactivate_complete (FP_IMAGE_DEVICE (dev), - error); + /* When the loop completes, we have (successfully) deactivated */ + if (self->active) + fpi_image_device_deactivate_complete (FP_IMAGE_DEVICE (dev), + error); - self->active = FALSE; + self->active = FALSE; - fpi_ssm_free(ssm); + fpi_ssm_free (ssm); } /* Init ssm states */ -enum -{ - /* Step 0 - Cleanup device buffer */ - M_INIT_0_RECV_DIRTY, - M_INIT_0_ABORT_PRINT, - M_INIT_0_LOAD_IMAGE, +enum { + /* Step 0 - Cleanup device buffer */ + M_INIT_0_RECV_DIRTY, + M_INIT_0_ABORT_PRINT, + M_INIT_0_LOAD_IMAGE, - /* Step 1 - Wait aborting */ - M_INIT_1_GET_PRINT, - M_INIT_1_LOAD_IMAGE, - M_INIT_1_CHECK_IMAGE, - M_INIT_1_LOOP, + /* Step 1 - Wait aborting */ + M_INIT_1_GET_PRINT, + M_INIT_1_LOAD_IMAGE, + M_INIT_1_CHECK_IMAGE, + M_INIT_1_LOOP, - /* Step 2 - Handle unexpected finger presence */ - M_INIT_2_GET_STATE, - M_INIT_2_CHECK_STATE, - M_INIT_2_GET_PRINT, - M_INIT_2_LOAD_IMAGE, - M_INIT_2_LOOP, + /* Step 2 - Handle unexpected finger presence */ + M_INIT_2_GET_STATE, + M_INIT_2_CHECK_STATE, + M_INIT_2_GET_PRINT, + M_INIT_2_LOAD_IMAGE, + M_INIT_2_LOOP, - /* Step 3 - Set parameters */ - M_INIT_3_SET_000E, - M_INIT_3_SET_0011, - M_INIT_3_SET_0076, - M_INIT_3_SET_0078, - M_INIT_3_SET_THRESHOLD, - M_INIT_3_SET_STATE3_COUNT, - M_INIT_3_SET_STATE5_COUNT, - M_INIT_3_SET_INFO_CONTRAST, - M_INIT_3_SET_INFO_RATE, + /* Step 3 - Set parameters */ + M_INIT_3_SET_000E, + M_INIT_3_SET_0011, + M_INIT_3_SET_0076, + M_INIT_3_SET_0078, + M_INIT_3_SET_THRESHOLD, + M_INIT_3_SET_STATE3_COUNT, + M_INIT_3_SET_STATE5_COUNT, + M_INIT_3_SET_INFO_CONTRAST, + M_INIT_3_SET_INFO_RATE, - /* Step 4 - Autocalibrate contrast */ - M_INIT_4_SET_EXPOSURE, - M_INIT_4_SET_CONTRAST, - M_INIT_4_GET_PRINT, - M_INIT_4_LOAD_IMAGE, - M_INIT_4_CHECK_CONTRAST, + /* Step 4 - Autocalibrate contrast */ + M_INIT_4_SET_EXPOSURE, + M_INIT_4_SET_CONTRAST, + M_INIT_4_GET_PRINT, + M_INIT_4_LOAD_IMAGE, + M_INIT_4_CHECK_CONTRAST, - /* Step 5 - Set info line parameters */ - M_INIT_5_SET_EXPOSURE, - M_INIT_5_SET_CONTRAST, - M_INIT_5_SET_INFO_CONTRAST, - M_INIT_5_SET_INFO_RATE, + /* Step 5 - Set info line parameters */ + M_INIT_5_SET_EXPOSURE, + M_INIT_5_SET_CONTRAST, + M_INIT_5_SET_INFO_CONTRAST, + M_INIT_5_SET_INFO_RATE, - /* Number of states */ - M_INIT_NUM_STATES, + /* Number of states */ + M_INIT_NUM_STATES, }; /* Exec init sequential state machine */ -static void m_init_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +m_init_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - FpImageDevice *dev = user_data; - FpDeviceVfs101 *self = FPI_DEVICE_VFS101(_dev); + FpImageDevice *dev = user_data; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (_dev); - /* Mark as cancelled when activation collides with deactivation. */ - if (self->deactivate) { - fpi_ssm_mark_failed (ssm, - g_error_new (G_IO_ERROR, - G_IO_ERROR_CANCELLED, - "Initialisation was cancelled")); - return; - } + /* Mark as cancelled when activation collides with deactivation. */ + if (self->deactivate) + { + fpi_ssm_mark_failed (ssm, + g_error_new (G_IO_ERROR, + G_IO_ERROR_CANCELLED, + "Initialisation was cancelled")); + return; + } - switch (fpi_ssm_get_cur_state(ssm)) - { - case M_INIT_0_RECV_DIRTY: - /* Recv eventually dirty data */ - self->ignore_error = TRUE; - async_recv(ssm, dev); - break; + switch (fpi_ssm_get_cur_state (ssm)) + { + case M_INIT_0_RECV_DIRTY: + /* Recv eventually dirty data */ + self->ignore_error = TRUE; + async_recv (ssm, dev); + break; - case M_INIT_0_ABORT_PRINT: - /* Abort print command */ - vfs_abort_print(ssm, dev); - break; + case M_INIT_0_ABORT_PRINT: + /* Abort print command */ + vfs_abort_print (ssm, dev); + break; - case M_INIT_0_LOAD_IMAGE: - /* Load abort image */ - self->ignore_error = TRUE; - vfs_img_load(ssm, dev); - break; + case M_INIT_0_LOAD_IMAGE: + /* Load abort image */ + self->ignore_error = TRUE; + vfs_img_load (ssm, dev); + break; - case M_INIT_1_GET_PRINT: - /* Get empty image */ - vfs_get_print(ssm, dev, 0x000a, 0); - break; + case M_INIT_1_GET_PRINT: + /* Get empty image */ + vfs_get_print (ssm, dev, 0x000a, 0); + break; - case M_INIT_1_LOAD_IMAGE: - /* Load abort image */ - self->ignore_error = TRUE; - vfs_img_load(ssm, dev); - break; + case M_INIT_1_LOAD_IMAGE: + /* Load abort image */ + self->ignore_error = TRUE; + vfs_img_load (ssm, dev); + break; - case M_INIT_1_CHECK_IMAGE: - if (self->height == 10) - { - /* Image load correctly, jump to step 2 */ - self->counter = 0; - fpi_ssm_jump_to_state(ssm, M_INIT_2_GET_STATE); - } - else if (self->counter < 10) - { - /* Wait aborting */ - self->counter++; - async_sleep(100, ssm, dev); - } - else - { - /* reach max loop counter, return protocol error */ - fp_err("waiting abort reach max loop counter"); - fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); - } - break; + case M_INIT_1_CHECK_IMAGE: + if (self->height == 10) + { + /* Image load correctly, jump to step 2 */ + self->counter = 0; + fpi_ssm_jump_to_state (ssm, M_INIT_2_GET_STATE); + } + else if (self->counter < 10) + { + /* Wait aborting */ + self->counter++; + async_sleep (100, ssm, dev); + } + else + { + /* reach max loop counter, return protocol error */ + fp_err ("waiting abort reach max loop counter"); + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + } + break; - case M_INIT_1_LOOP: - /* Loop */ - fpi_ssm_jump_to_state(ssm, M_INIT_1_GET_PRINT); - break; + case M_INIT_1_LOOP: + /* Loop */ + fpi_ssm_jump_to_state (ssm, M_INIT_1_GET_PRINT); + break; - case M_INIT_2_GET_STATE: - /* Get finger state */ - vfs_get_finger_state(ssm, dev); - break; + case M_INIT_2_GET_STATE: + /* Get finger state */ + vfs_get_finger_state (ssm, dev); + break; - case M_INIT_2_CHECK_STATE: - /* Check finger state */ - if (vfs_finger_state(self) == VFS_FINGER_PRESENT) - { - /* Wait a bit for finger removal; if it doesn't happen, prompt */ - if (self->counter < 2) - { - /* Wait removing finger */ - self->counter++; - async_sleep(250, ssm, dev); - } - else - { - /* The user should remove their finger from the scanner */ - fp_warn("unexpected finger find, remove finger from the scanner"); - fpi_ssm_mark_failed(ssm, fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER)); - } - } - else - { - /* Finger not present */ - if (self->counter == 0) - /* Continue */ - fpi_ssm_jump_to_state(ssm, M_INIT_3_SET_000E); - else - { - /* Finger removed, jump to abort */ - self->counter = 0; - fpi_ssm_jump_to_state(ssm, M_INIT_0_ABORT_PRINT); - } - } - break; + case M_INIT_2_CHECK_STATE: + /* Check finger state */ + if (vfs_finger_state (self) == VFS_FINGER_PRESENT) + { + /* Wait a bit for finger removal; if it doesn't happen, prompt */ + if (self->counter < 2) + { + /* Wait removing finger */ + self->counter++; + async_sleep (250, ssm, dev); + } + else + { + /* The user should remove their finger from the scanner */ + fp_warn ("unexpected finger find, remove finger from the scanner"); + fpi_ssm_mark_failed (ssm, fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER)); + } + } + else + { + /* Finger not present */ + if (self->counter == 0) + { + /* Continue */ + fpi_ssm_jump_to_state (ssm, M_INIT_3_SET_000E); + } + else + { + /* Finger removed, jump to abort */ + self->counter = 0; + fpi_ssm_jump_to_state (ssm, M_INIT_0_ABORT_PRINT); + } + } + break; - case M_INIT_2_GET_PRINT: - /* Send get print command to the reader */ - vfs_get_print(ssm, dev, VFS_BUFFER_HEIGHT, 1); - break; + case M_INIT_2_GET_PRINT: + /* Send get print command to the reader */ + vfs_get_print (ssm, dev, VFS_BUFFER_HEIGHT, 1); + break; - case M_INIT_2_LOAD_IMAGE: - /* Load unexpected image */ - self->ignore_error = TRUE; - vfs_img_load(ssm, dev); - break; + case M_INIT_2_LOAD_IMAGE: + /* Load unexpected image */ + self->ignore_error = TRUE; + vfs_img_load (ssm, dev); + break; - case M_INIT_2_LOOP: - /* Loop */ - fpi_ssm_jump_to_state(ssm, M_INIT_2_GET_STATE); - break; + case M_INIT_2_LOOP: + /* Loop */ + fpi_ssm_jump_to_state (ssm, M_INIT_2_GET_STATE); + break; - case M_INIT_3_SET_000E: - /* Set param 0x000e, required for take image */ - vfs_set_param(ssm, dev, VFS_PAR_000E, VFS_VAL_000E); - break; + case M_INIT_3_SET_000E: + /* Set param 0x000e, required for take image */ + vfs_set_param (ssm, dev, VFS_PAR_000E, VFS_VAL_000E); + break; - case M_INIT_3_SET_0011: - /* Set param 0x0011, required for take image */ - vfs_set_param(ssm, dev, VFS_PAR_0011, VFS_VAL_0011); - break; + case M_INIT_3_SET_0011: + /* Set param 0x0011, required for take image */ + vfs_set_param (ssm, dev, VFS_PAR_0011, VFS_VAL_0011); + break; - case M_INIT_3_SET_0076: - /* Set param 0x0076, required for use info line */ - vfs_set_param(ssm, dev, VFS_PAR_0076, VFS_VAL_0076); - break; + case M_INIT_3_SET_0076: + /* Set param 0x0076, required for use info line */ + vfs_set_param (ssm, dev, VFS_PAR_0076, VFS_VAL_0076); + break; - case M_INIT_3_SET_0078: - /* Set param 0x0078, required for use info line */ - vfs_set_param(ssm, dev, VFS_PAR_0078, VFS_VAL_0078); - break; + case M_INIT_3_SET_0078: + /* Set param 0x0078, required for use info line */ + vfs_set_param (ssm, dev, VFS_PAR_0078, VFS_VAL_0078); + break; - case M_INIT_3_SET_THRESHOLD: - /* Set threshold */ - vfs_set_param(ssm, dev, VFS_PAR_THRESHOLD, VFS_VAL_THRESHOLD); - break; + case M_INIT_3_SET_THRESHOLD: + /* Set threshold */ + vfs_set_param (ssm, dev, VFS_PAR_THRESHOLD, VFS_VAL_THRESHOLD); + break; - case M_INIT_3_SET_STATE3_COUNT: - /* Set state 3 count */ - vfs_set_param(ssm, dev, VFS_PAR_STATE_3, VFS_VAL_STATE_3); - break; + case M_INIT_3_SET_STATE3_COUNT: + /* Set state 3 count */ + vfs_set_param (ssm, dev, VFS_PAR_STATE_3, VFS_VAL_STATE_3); + break; - case M_INIT_3_SET_STATE5_COUNT: - /* Set state 5 count */ - vfs_set_param(ssm, dev, VFS_PAR_STATE_5, VFS_VAL_STATE_5); - break; + case M_INIT_3_SET_STATE5_COUNT: + /* Set state 5 count */ + vfs_set_param (ssm, dev, VFS_PAR_STATE_5, VFS_VAL_STATE_5); + break; - case M_INIT_3_SET_INFO_CONTRAST: - /* Set info line contrast */ - vfs_set_param(ssm, dev, VFS_PAR_INFO_CONTRAST, 10); - break; + case M_INIT_3_SET_INFO_CONTRAST: + /* Set info line contrast */ + vfs_set_param (ssm, dev, VFS_PAR_INFO_CONTRAST, 10); + break; - case M_INIT_3_SET_INFO_RATE: - /* Set info line rate */ - vfs_set_param(ssm, dev, VFS_PAR_INFO_RATE, 32); - break; + case M_INIT_3_SET_INFO_RATE: + /* Set info line rate */ + vfs_set_param (ssm, dev, VFS_PAR_INFO_RATE, 32); + break; - case M_INIT_4_SET_EXPOSURE: - /* Set exposure level of reader */ - vfs_poke(ssm, dev, VFS_REG_IMG_EXPOSURE, 0x4000, 0x02); - self->counter = 1; - break; + case M_INIT_4_SET_EXPOSURE: + /* Set exposure level of reader */ + vfs_poke (ssm, dev, VFS_REG_IMG_EXPOSURE, 0x4000, 0x02); + self->counter = 1; + break; - case M_INIT_4_SET_CONTRAST: - /* Set contrast level of reader */ - vfs_poke(ssm, dev, VFS_REG_IMG_CONTRAST, self->contrast, 0x01); - break; + case M_INIT_4_SET_CONTRAST: + /* Set contrast level of reader */ + vfs_poke (ssm, dev, VFS_REG_IMG_CONTRAST, self->contrast, 0x01); + break; - case M_INIT_4_GET_PRINT: - /* Get empty image */ - vfs_get_print(ssm, dev, 0x000a, 0); - break; + case M_INIT_4_GET_PRINT: + /* Get empty image */ + vfs_get_print (ssm, dev, 0x000a, 0); + break; - case M_INIT_4_LOAD_IMAGE: - /* Load empty image */ - vfs_img_load(ssm, dev); - break; + case M_INIT_4_LOAD_IMAGE: + /* Load empty image */ + vfs_img_load (ssm, dev); + break; - case M_INIT_4_CHECK_CONTRAST: - /* Check contrast */ - vfs_check_contrast(self); + case M_INIT_4_CHECK_CONTRAST: + /* Check contrast */ + vfs_check_contrast (self); - if (self->contrast <= 6 || self->counter >= 12) - { - /* End contrast scan, continue */ - self->contrast = self->best_contrast; - self->counter = 0; - fp_dbg("use contrast value = %d", self->contrast); - fpi_ssm_next_state(ssm); - } - else - { - /* Continue contrast scan, loop */ - self->contrast--; - self->counter++; - fpi_ssm_jump_to_state(ssm, M_INIT_4_SET_CONTRAST); - } - break; + if (self->contrast <= 6 || self->counter >= 12) + { + /* End contrast scan, continue */ + self->contrast = self->best_contrast; + self->counter = 0; + fp_dbg ("use contrast value = %d", self->contrast); + fpi_ssm_next_state (ssm); + } + else + { + /* Continue contrast scan, loop */ + self->contrast--; + self->counter++; + fpi_ssm_jump_to_state (ssm, M_INIT_4_SET_CONTRAST); + } + break; - case M_INIT_5_SET_EXPOSURE: - /* Set exposure level of reader */ - vfs_poke(ssm, dev, VFS_REG_IMG_EXPOSURE, VFS_VAL_IMG_EXPOSURE, 0x02); - break; + case M_INIT_5_SET_EXPOSURE: + /* Set exposure level of reader */ + vfs_poke (ssm, dev, VFS_REG_IMG_EXPOSURE, VFS_VAL_IMG_EXPOSURE, 0x02); + break; - case M_INIT_5_SET_CONTRAST: - /* Set contrast level of reader */ - vfs_poke(ssm, dev, VFS_REG_IMG_CONTRAST, self->contrast, 0x01); - break; + case M_INIT_5_SET_CONTRAST: + /* Set contrast level of reader */ + vfs_poke (ssm, dev, VFS_REG_IMG_CONTRAST, self->contrast, 0x01); + break; - case M_INIT_5_SET_INFO_CONTRAST: - /* Set info line contrast */ - vfs_set_param(ssm, dev, VFS_PAR_INFO_CONTRAST, self->contrast); - break; + case M_INIT_5_SET_INFO_CONTRAST: + /* Set info line contrast */ + vfs_set_param (ssm, dev, VFS_PAR_INFO_CONTRAST, self->contrast); + break; - case M_INIT_5_SET_INFO_RATE: - /* Set info line rate */ - vfs_set_param(ssm, dev, VFS_PAR_INFO_RATE, VFS_VAL_INFO_RATE); - break; - } + case M_INIT_5_SET_INFO_RATE: + /* Set info line rate */ + vfs_set_param (ssm, dev, VFS_PAR_INFO_RATE, VFS_VAL_INFO_RATE); + break; + } } /* Complete init sequential state machine */ -static void m_init_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +static void +m_init_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = user_data; - /* Notify activate complete */ - fpi_image_device_activate_complete(dev, error); + /* Notify activate complete */ + fpi_image_device_activate_complete (dev, error); - if (!error) { - FpiSsm *ssm_loop; + if (!error) + { + FpiSsm *ssm_loop; - /* Start loop ssm */ - ssm_loop = fpi_ssm_new(FP_DEVICE(dev), m_loop_state, - M_LOOP_NUM_STATES, dev); - fpi_ssm_start(ssm_loop, m_loop_complete); - } + /* Start loop ssm */ + ssm_loop = fpi_ssm_new (FP_DEVICE (dev), m_loop_state, + M_LOOP_NUM_STATES, dev); + fpi_ssm_start (ssm_loop, m_loop_complete); + } - /* Free sequential state machine */ - fpi_ssm_free(ssm); + /* Free sequential state machine */ + fpi_ssm_free (ssm); } /* Activate device */ -static void dev_activate(FpImageDevice *dev) +static void +dev_activate (FpImageDevice *dev) { - FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); - FpiSsm *ssm; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev); + FpiSsm *ssm; - /* Check if already active */ - g_assert (!self->active); + /* Check if already active */ + g_assert (!self->active); - /* Set active state */ - self->active = TRUE; - self->deactivate = FALSE; + /* Set active state */ + self->active = TRUE; + self->deactivate = FALSE; - /* Set contrast */ - self->contrast = 15; - self->best_clevel = -1; + /* Set contrast */ + self->contrast = 15; + self->best_clevel = -1; - /* Reset loop counter */ - self->counter = 0; + /* Reset loop counter */ + self->counter = 0; - /* Start init ssm */ - ssm = fpi_ssm_new(FP_DEVICE(dev), m_init_state, M_INIT_NUM_STATES, dev); - fpi_ssm_start(ssm, m_init_complete); + /* Start init ssm */ + ssm = fpi_ssm_new (FP_DEVICE (dev), m_init_state, M_INIT_NUM_STATES, dev); + fpi_ssm_start (ssm, m_init_complete); } /* Deactivate device */ -static void dev_deactivate(FpImageDevice *dev) +static void +dev_deactivate (FpImageDevice *dev) { - FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); + FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev); - /* Device already deactivated, likely due to an error */ - if (!self->active) { - fpi_image_device_deactivate_complete (dev, NULL); - return; - } + /* Device already deactivated, likely due to an error */ + if (!self->active) + { + fpi_image_device_deactivate_complete (dev, NULL); + return; + } - /* Signal deactivation, deactivation will happen from the SSM - * completion handler. */ - self->deactivate = TRUE; + /* Signal deactivation, deactivation will happen from the SSM + * completion handler. */ + self->deactivate = TRUE; } /* Open device */ -static void dev_open(FpImageDevice *dev) +static void +dev_open (FpImageDevice *dev) { - FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); - GError *error = NULL; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev); + GError *error = NULL; - /* Claim usb interface */ - g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error); + /* Claim usb interface */ + g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error); - /* Initialize private structure */ - self->seqnum = -1; - self->buffer = g_malloc0 (VFS_BUFFER_SIZE); + /* Initialize private structure */ + self->seqnum = -1; + self->buffer = g_malloc0 (VFS_BUFFER_SIZE); - /* Notify open complete */ - fpi_image_device_open_complete(dev, error); + /* Notify open complete */ + fpi_image_device_open_complete (dev, error); } /* Close device */ -static void dev_close(FpImageDevice *dev) +static void +dev_close (FpImageDevice *dev) { - FpDeviceVfs101 *self = FPI_DEVICE_VFS101(dev); - GError *error = NULL; + FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev); + GError *error = NULL; - /* Release usb interface */ - g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), - 0, 0, &error); + /* Release usb interface */ + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), + 0, 0, &error); - g_clear_pointer (&self->buffer, g_free); + g_clear_pointer (&self->buffer, g_free); - /* Notify close complete */ - fpi_image_device_close_complete(dev, error); + /* Notify close complete */ + fpi_image_device_close_complete (dev, error); } /* Usb id table of device */ -static const FpIdEntry id_table [ ] = { - { .vid = 0x138a, .pid = 0x0001, }, - { .vid = 0, .pid = 0, .driver_data = 0 }, +static const FpIdEntry id_table[] = { + { .vid = 0x138a, .pid = 0x0001, }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -static void fpi_device_vfs101_init(FpDeviceVfs101 *self) { +static void +fpi_device_vfs101_init (FpDeviceVfs101 *self) +{ } -static void fpi_device_vfs101_class_init(FpDeviceVfs101Class *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); +static void +fpi_device_vfs101_class_init (FpDeviceVfs101Class *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); - dev_class->id = "vfs101"; - dev_class->full_name = "Validity VFS101"; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->id_table = id_table; - dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + dev_class->id = "vfs101"; + dev_class->full_name = "Validity VFS101"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - img_class->img_open = dev_open; - img_class->img_close = dev_close; - img_class->activate = dev_activate; - img_class->deactivate = dev_deactivate; + img_class->img_open = dev_open; + img_class->img_close = dev_close; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; - img_class->bz3_threshold = 24; + img_class->bz3_threshold = 24; - img_class->img_width = VFS_IMG_WIDTH; - img_class->img_height = -1; + img_class->img_width = VFS_IMG_WIDTH; + img_class->img_height = -1; } diff --git a/libfprint/drivers/vfs301.c b/libfprint/drivers/vfs301.c index 2339c2ff..4d3dc30b 100644 --- a/libfprint/drivers/vfs301.c +++ b/libfprint/drivers/vfs301.c @@ -30,249 +30,268 @@ G_DEFINE_TYPE (FpDeviceVfs301, fpi_device_vfs301, FP_TYPE_IMAGE_DEVICE) /* Submit asynchronous sleep */ static void -async_sleep(unsigned int msec, - FpiSsm *ssm, - FpImageDevice *dev) +async_sleep (unsigned int msec, + FpiSsm *ssm, + FpImageDevice *dev) { - /* Add timeout */ - fpi_device_add_timeout(FP_DEVICE(dev), msec, - fpi_ssm_next_state_timeout_cb, ssm); + /* Add timeout */ + fpi_device_add_timeout (FP_DEVICE (dev), msec, + fpi_ssm_next_state_timeout_cb, ssm); } static int -submit_image(FpiSsm *ssm, - FpImageDevice *dev) +submit_image (FpiSsm *ssm, + FpImageDevice *dev) { - FpDeviceVfs301 *self = FPI_DEVICE_VFS301(dev); - int height; - FpImage *img; + FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (dev); + int height; + FpImage *img; #if 0 - /* XXX: This is probably handled by libfprint automagically? */ - if (vdev->scanline_count < 20) { - fpi_ssm_jump_to_state(ssm, M_REQUEST_PRINT); - return 0; - } + /* XXX: This is probably handled by libfprint automagically? */ + if (vdev->scanline_count < 20) + { + fpi_ssm_jump_to_state (ssm, M_REQUEST_PRINT); + return 0; + } #endif - img = fp_image_new(VFS301_FP_OUTPUT_WIDTH, self->scanline_count); - if (img == NULL) - return 0; + img = fp_image_new (VFS301_FP_OUTPUT_WIDTH, self->scanline_count); + if (img == NULL) + return 0; - vfs301_extract_image(self, img->data, &height); + vfs301_extract_image (self, img->data, &height); - /* TODO: how to detect flip? should the resulting image be - * oriented so that it is equal e.g. to a fingerprint on a paper, - * or to the finger when I look at it?) */ - img->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED; + /* TODO: how to detect flip? should the resulting image be + * oriented so that it is equal e.g. to a fingerprint on a paper, + * or to the finger when I look at it?) */ + img->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED; - /* The image buffer is larger at this point, but that does not - * matter. */ - img->width = VFS301_FP_OUTPUT_WIDTH; - img->height = height; + /* The image buffer is larger at this point, but that does not + * matter. */ + img->width = VFS301_FP_OUTPUT_WIDTH; + img->height = height; - fpi_image_device_image_captured(dev, img); + fpi_image_device_image_captured (dev, img); - return 1; + return 1; } /* Loop ssm states */ -enum -{ - /* Step 0 - Scan finger */ - M_REQUEST_PRINT, - M_WAIT_PRINT, - M_CHECK_PRINT, - M_READ_PRINT_START, - M_READ_PRINT_WAIT, - M_READ_PRINT_POLL, - M_SUBMIT_PRINT, +enum { + /* Step 0 - Scan finger */ + M_REQUEST_PRINT, + M_WAIT_PRINT, + M_CHECK_PRINT, + M_READ_PRINT_START, + M_READ_PRINT_WAIT, + M_READ_PRINT_POLL, + M_SUBMIT_PRINT, - /* Number of states */ - M_LOOP_NUM_STATES, + /* Number of states */ + M_LOOP_NUM_STATES, }; /* Exec loop sequential state machine */ -static void m_loop_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +m_loop_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - FpImageDevice *dev = user_data; - FpDeviceVfs301 *self = FPI_DEVICE_VFS301(_dev); + FpImageDevice *dev = user_data; + FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (_dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case M_REQUEST_PRINT: - vfs301_proto_request_fingerprint(self); - fpi_ssm_next_state(ssm); - break; + switch (fpi_ssm_get_cur_state (ssm)) + { + case M_REQUEST_PRINT: + vfs301_proto_request_fingerprint (self); + fpi_ssm_next_state (ssm); + break; - case M_WAIT_PRINT: - /* Wait fingerprint scanning */ - async_sleep(200, ssm, dev); - break; + case M_WAIT_PRINT: + /* Wait fingerprint scanning */ + async_sleep (200, ssm, dev); + break; - case M_CHECK_PRINT: - if (!vfs301_proto_peek_event(self)) - fpi_ssm_jump_to_state(ssm, M_WAIT_PRINT); - else - fpi_ssm_next_state(ssm); - break; + case M_CHECK_PRINT: + if (!vfs301_proto_peek_event (self)) + fpi_ssm_jump_to_state (ssm, M_WAIT_PRINT); + else + fpi_ssm_next_state (ssm); + break; - case M_READ_PRINT_START: - fpi_image_device_report_finger_status(dev, TRUE); - vfs301_proto_process_event_start(self); - fpi_ssm_next_state(ssm); - break; + case M_READ_PRINT_START: + fpi_image_device_report_finger_status (dev, TRUE); + vfs301_proto_process_event_start (self); + fpi_ssm_next_state (ssm); + break; - case M_READ_PRINT_WAIT: - /* Wait fingerprint scanning */ - async_sleep(200, ssm, dev); - break; + case M_READ_PRINT_WAIT: + /* Wait fingerprint scanning */ + async_sleep (200, ssm, dev); + break; - case M_READ_PRINT_POLL: - { - int rv = vfs301_proto_process_event_poll(self); - g_assert(rv != VFS301_FAILURE); - if (rv == VFS301_ONGOING) - fpi_ssm_jump_to_state(ssm, M_READ_PRINT_WAIT); - else - fpi_ssm_next_state(ssm); - } - break; + case M_READ_PRINT_POLL: + { + int rv = vfs301_proto_process_event_poll (self); + g_assert (rv != VFS301_FAILURE); + if (rv == VFS301_ONGOING) + fpi_ssm_jump_to_state (ssm, M_READ_PRINT_WAIT); + else + fpi_ssm_next_state (ssm); + } + break; - case M_SUBMIT_PRINT: - if (submit_image(ssm, dev)) { - fpi_ssm_mark_completed(ssm); - /* NOTE: finger off is expected only after submitting image... */ - fpi_image_device_report_finger_status(dev, FALSE); - } else { - fpi_ssm_jump_to_state(ssm, M_REQUEST_PRINT); - } - break; - default: - g_assert_not_reached (); - } + case M_SUBMIT_PRINT: + if (submit_image (ssm, dev)) + { + fpi_ssm_mark_completed (ssm); + /* NOTE: finger off is expected only after submitting image... */ + fpi_image_device_report_finger_status (dev, FALSE); + } + else + { + fpi_ssm_jump_to_state (ssm, M_REQUEST_PRINT); + } + break; + + default: + g_assert_not_reached (); + } } /* Complete loop sequential state machine */ -static void m_loop_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +static void +m_loop_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - if (error) { - g_warning ("State machine completed with an error: %s", error->message); - g_error_free (error); - } - /* Free sequential state machine */ - fpi_ssm_free(ssm); + if (error) + { + g_warning ("State machine completed with an error: %s", error->message); + g_error_free (error); + } + /* Free sequential state machine */ + fpi_ssm_free (ssm); } /* Exec init sequential state machine */ -static void m_init_state(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +m_init_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - FpDeviceVfs301 *self = FPI_DEVICE_VFS301(_dev); + FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (_dev); - g_assert(fpi_ssm_get_cur_state(ssm) == 0); + g_assert (fpi_ssm_get_cur_state (ssm) == 0); - vfs301_proto_init(self); + vfs301_proto_init (self); - fpi_ssm_mark_completed(ssm); + fpi_ssm_mark_completed (ssm); } /* Complete init sequential state machine */ -static void m_init_complete(FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +static void +m_init_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, + GError *error) { - FpiSsm *ssm_loop; + FpiSsm *ssm_loop; - fpi_image_device_activate_complete(FP_IMAGE_DEVICE (dev), error); - if (!error) { - /* Notify activate complete */ + fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error); + if (!error) + { + /* Notify activate complete */ - /* Start loop ssm */ - ssm_loop = fpi_ssm_new(dev, m_loop_state, - M_LOOP_NUM_STATES, dev); - fpi_ssm_start(ssm_loop, m_loop_complete); - } + /* Start loop ssm */ + ssm_loop = fpi_ssm_new (dev, m_loop_state, + M_LOOP_NUM_STATES, dev); + fpi_ssm_start (ssm_loop, m_loop_complete); + } - /* Free sequential state machine */ - fpi_ssm_free(ssm); + /* Free sequential state machine */ + fpi_ssm_free (ssm); } /* Activate device */ -static void dev_activate(FpImageDevice *dev) +static void +dev_activate (FpImageDevice *dev) { - FpiSsm *ssm; + FpiSsm *ssm; - /* Start init ssm */ - ssm = fpi_ssm_new(FP_DEVICE(dev), m_init_state, 1, dev); - fpi_ssm_start(ssm, m_init_complete); + /* Start init ssm */ + ssm = fpi_ssm_new (FP_DEVICE (dev), m_init_state, 1, dev); + fpi_ssm_start (ssm, m_init_complete); } /* Deactivate device */ -static void dev_deactivate(FpImageDevice *dev) +static void +dev_deactivate (FpImageDevice *dev) { - FpDeviceVfs301 *self; + FpDeviceVfs301 *self; - self = FPI_DEVICE_VFS301(dev); - vfs301_proto_deinit(self); - fpi_image_device_deactivate_complete(dev, NULL); + self = FPI_DEVICE_VFS301 (dev); + vfs301_proto_deinit (self); + fpi_image_device_deactivate_complete (dev, NULL); } -static void dev_open(FpImageDevice *dev) +static void +dev_open (FpImageDevice *dev) { - FpDeviceVfs301 *self = FPI_DEVICE_VFS301(dev); - GError *error = NULL; + FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (dev); + GError *error = NULL; - /* Claim usb interface */ - g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error); + /* Claim usb interface */ + g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error); - /* Initialize private structure */ - self->scanline_count = 0; + /* Initialize private structure */ + self->scanline_count = 0; - /* Notify open complete */ - fpi_image_device_open_complete(dev, error); + /* Notify open complete */ + fpi_image_device_open_complete (dev, error); } -static void dev_close(FpImageDevice *dev) +static void +dev_close (FpImageDevice *dev) { - FpDeviceVfs301 *self = FPI_DEVICE_VFS301(dev); - GError *error = NULL; + FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (dev); + GError *error = NULL; - /* Release private structure */ - g_clear_pointer (&self->scanline_buf, g_free); + /* Release private structure */ + g_clear_pointer (&self->scanline_buf, g_free); - /* Release usb interface */ - g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), - 0, 0, &error); + /* Release usb interface */ + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), + 0, 0, &error); - /* Notify close complete */ - fpi_image_device_close_complete(dev, error); + /* Notify close complete */ + fpi_image_device_close_complete (dev, error); } /* Usb id table of device */ -static const FpIdEntry id_table [ ] = { - { /* vfs301 */ .vid = 0x138a, .pid = 0x0005, }, - { /* vfs300 */ .vid = 0x138a, .pid = 0x0008, }, - { .vid = 0, .pid = 0, .driver_data = 0 }, +static const FpIdEntry id_table[] = { + { /* vfs301 */ .vid = 0x138a, .pid = 0x0005, }, + { /* vfs300 */ .vid = 0x138a, .pid = 0x0008, }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -static void fpi_device_vfs301_init(FpDeviceVfs301 *self) { +static void +fpi_device_vfs301_init (FpDeviceVfs301 *self) +{ } -static void fpi_device_vfs301_class_init(FpDeviceVfs301Class *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); +static void +fpi_device_vfs301_class_init (FpDeviceVfs301Class *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); - dev_class->id = "vfs301"; - dev_class->full_name = "Validity VFS301"; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->id_table = id_table; - dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + dev_class->id = "vfs301"; + dev_class->full_name = "Validity VFS301"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - img_class->img_open = dev_open; - img_class->img_close = dev_close; - img_class->activate = dev_activate; - img_class->deactivate = dev_deactivate; + img_class->img_open = dev_open; + img_class->img_close = dev_close; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; - img_class->bz3_threshold = 24; + img_class->bz3_threshold = 24; - img_class->img_width = VFS301_FP_WIDTH; - img_class->img_height = -1; + img_class->img_width = VFS301_FP_WIDTH; + img_class->img_height = -1; } diff --git a/libfprint/drivers/vfs301.h b/libfprint/drivers/vfs301.h index dfbbc7e9..3ab23f94 100644 --- a/libfprint/drivers/vfs301.h +++ b/libfprint/drivers/vfs301.h @@ -25,113 +25,118 @@ #include "fpi-image-device.h" enum { - VFS301_DEFAULT_WAIT_TIMEOUT = 300, + VFS301_DEFAULT_WAIT_TIMEOUT = 300, - VFS301_SEND_ENDPOINT = 0x01, - VFS301_RECEIVE_ENDPOINT_CTRL = 0x81, - VFS301_RECEIVE_ENDPOINT_DATA = 0x82 + VFS301_SEND_ENDPOINT = 0x01, + VFS301_RECEIVE_ENDPOINT_CTRL = 0x81, + VFS301_RECEIVE_ENDPOINT_DATA = 0x82 }; #define VFS301_FP_RECV_LEN_1 (84032) #define VFS301_FP_RECV_LEN_2 (84096) -struct _FpDeviceVfs301 { - FpImageDevice parent; +struct _FpDeviceVfs301 +{ + FpImageDevice parent; - /* buffer to hold raw scanlines */ - unsigned char *scanline_buf; - int scanline_count; + /* buffer to hold raw scanlines */ + unsigned char *scanline_buf; + int scanline_count; - enum { - VFS301_ONGOING = 0, - VFS301_ENDED = 1, - VFS301_FAILURE = -1 - } recv_progress; - int recv_exp_amt; + enum { + VFS301_ONGOING = 0, + VFS301_ENDED = 1, + VFS301_FAILURE = -1 + } recv_progress; + int recv_exp_amt; }; G_DECLARE_FINAL_TYPE (FpDeviceVfs301, fpi_device_vfs301, FPI, DEVICE_VFS301, FpImageDevice) enum { - /* Width of the scanned data in px */ - VFS301_FP_WIDTH = 200, + /* Width of the scanned data in px */ + VFS301_FP_WIDTH = 200, - /* sizeof(fp_line_t) */ - VFS301_FP_FRAME_SIZE = 288, - /* Width of output line */ + /* sizeof(fp_line_t) */ + VFS301_FP_FRAME_SIZE = 288, + /* Width of output line */ #ifndef OUTPUT_RAW - VFS301_FP_OUTPUT_WIDTH = VFS301_FP_WIDTH, + VFS301_FP_OUTPUT_WIDTH = VFS301_FP_WIDTH, #else - VFS301_FP_OUTPUT_WIDTH = VFS301_FP_FRAME_SIZE, + VFS301_FP_OUTPUT_WIDTH = VFS301_FP_FRAME_SIZE, #endif - VFS301_FP_SUM_LINES = 3, + VFS301_FP_SUM_LINES = 3, #ifdef SCAN_FINISH_DETECTION - /* TODO: The following changes (seen ~60 and ~80) In that - * case we'll need to calibrate this from empty data somehow... */ - VFS301_FP_SUM_MEDIAN = 60, - VFS301_FP_SUM_EMPTY_RANGE = 5, + /* TODO: The following changes (seen ~60 and ~80) In that + * case we'll need to calibrate this from empty data somehow... */ + VFS301_FP_SUM_MEDIAN = 60, + VFS301_FP_SUM_EMPTY_RANGE = 5, #endif - /* Minimum average difference between returned lines */ - VFS301_FP_LINE_DIFF_THRESHOLD = 15, + /* Minimum average difference between returned lines */ + VFS301_FP_LINE_DIFF_THRESHOLD = 15, - /* Maximum waiting time for a single fingerprint frame */ - VFS301_FP_RECV_TIMEOUT = 2000 + /* Maximum waiting time for a single fingerprint frame */ + VFS301_FP_RECV_TIMEOUT = 2000 }; /* Arrays of this structure is returned during the initialization as a response * to the 0x02D0 messages. * It seems to be always the same - what is it for? Some kind of confirmation? */ -typedef struct { - unsigned char sync_0x01; - unsigned char sync_0xfe; +typedef struct +{ + unsigned char sync_0x01; + unsigned char sync_0xfe; - unsigned char counter_lo; - unsigned char counter_hi; /* FIXME ? */ + unsigned char counter_lo; + unsigned char counter_hi; /* FIXME ? */ - unsigned char flags[3]; + unsigned char flags[3]; - unsigned char sync_0x00; + unsigned char sync_0x00; - unsigned char scan[VFS301_FP_WIDTH]; + unsigned char scan[VFS301_FP_WIDTH]; } vfs301_init_line_t; -typedef struct { - unsigned char sync_0x01; - unsigned char sync_0xfe; +typedef struct +{ + unsigned char sync_0x01; + unsigned char sync_0xfe; - unsigned char counter_lo; - unsigned char counter_hi; + unsigned char counter_lo; + unsigned char counter_hi; - unsigned char sync_0x08[2]; /* XXX: always? 0x08 0x08 */ - /* 0x08 | 0x18 - Looks like 0x08 marks good quality lines */ - unsigned char flag_1; - unsigned char sync_0x00; + unsigned char sync_0x08[2]; /* XXX: always? 0x08 0x08 */ + /* 0x08 | 0x18 - Looks like 0x08 marks good quality lines */ + unsigned char flag_1; + unsigned char sync_0x00; - unsigned char scan[VFS301_FP_WIDTH]; + unsigned char scan[VFS301_FP_WIDTH]; - /* A offsetted, stretched, inverted copy of scan... probably could - * serve finger motion speed detection? - * Seems to be subdivided to some 10B + 53B + 1B blocks */ - unsigned char mirror[64]; + /* A offsetted, stretched, inverted copy of scan... probably could + * serve finger motion speed detection? + * Seems to be subdivided to some 10B + 53B + 1B blocks */ + unsigned char mirror[64]; - /* Some kind of sum of the scan, very low contrast */ - unsigned char sum1[2]; - unsigned char sum2[11]; - unsigned char sum3[3]; + /* Some kind of sum of the scan, very low contrast */ + unsigned char sum1[2]; + unsigned char sum2[11]; + unsigned char sum3[3]; } vfs301_line_t; -void vfs301_proto_init(FpDeviceVfs301 *dev); -void vfs301_proto_deinit(FpDeviceVfs301 *dev); +void vfs301_proto_init (FpDeviceVfs301 *dev); +void vfs301_proto_deinit (FpDeviceVfs301 *dev); -void vfs301_proto_request_fingerprint(FpDeviceVfs301 *dev); +void vfs301_proto_request_fingerprint (FpDeviceVfs301 *dev); /** returns 0 if no event is ready, or 1 if there is one... */ -int vfs301_proto_peek_event(FpDeviceVfs301 *dev); -void vfs301_proto_process_event_start(FpDeviceVfs301 *dev); -int vfs301_proto_process_event_poll(FpDeviceVfs301 *dev); +int vfs301_proto_peek_event (FpDeviceVfs301 *dev); +void vfs301_proto_process_event_start (FpDeviceVfs301 *dev); +int vfs301_proto_process_event_poll (FpDeviceVfs301 *dev); -void vfs301_extract_image(FpDeviceVfs301 *vfs, unsigned char *output, int *output_height); +void vfs301_extract_image (FpDeviceVfs301 *vfs, + unsigned char *output, + int *output_height); diff --git a/libfprint/drivers/vfs301_proto.c b/libfprint/drivers/vfs301_proto.c index 17129f15..5d02597f 100644 --- a/libfprint/drivers/vfs301_proto.c +++ b/libfprint/drivers/vfs301_proto.c @@ -41,416 +41,453 @@ /************************** USB STUFF *****************************************/ #ifdef DEBUG -static void usb_print_packet(int dir, GError *error, const guint8 *data, int length) +static void +usb_print_packet (int dir, GError *error, const guint8 *data, int length) { - fprintf(stderr, "%s, error %s, len %d\n", dir ? "send" : "recv", error ? error->message : "-", length); + fprintf (stderr, "%s, error %s, len %d\n", dir ? "send" : "recv", error ? error->message : "-", length); #ifdef PRINT_VERBOSE - int i; + int i; - for (i = 0; i < MIN(length, 128); i++) { - fprintf(stderr, "%.2X ", data[i]); - if (i % 8 == 7) - fprintf(stderr, " "); - if (i % 32 == 31) - fprintf(stderr, "\n"); - } + for (i = 0; i < MIN (length, 128); i++) + { + fprintf (stderr, "%.2X ", data[i]); + if (i % 8 == 7) + fprintf (stderr, " "); + if (i % 32 == 31) + fprintf (stderr, "\n"); + } #endif - fprintf(stderr, "\n"); + fprintf (stderr, "\n"); } #endif -static void usb_recv(FpDeviceVfs301 *dev, guint8 endpoint, int max_bytes, FpiUsbTransfer **out, GError **error) +static void +usb_recv (FpDeviceVfs301 *dev, guint8 endpoint, int max_bytes, FpiUsbTransfer **out, GError **error) { - GError *err = NULL; - g_autoptr(FpiUsbTransfer) transfer = NULL; + GError *err = NULL; - /* XXX: This function swallows any transfer errors, that is obviously - * quite bad (it used to assert on no-error)! */ + g_autoptr(FpiUsbTransfer) transfer = NULL; - transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); - transfer->short_is_error = TRUE; - fpi_usb_transfer_fill_bulk (transfer, endpoint, max_bytes); + /* XXX: This function swallows any transfer errors, that is obviously + * quite bad (it used to assert on no-error)! */ - fpi_usb_transfer_submit_sync (transfer, VFS301_DEFAULT_WAIT_TIMEOUT, &err); + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk (transfer, endpoint, max_bytes); + + fpi_usb_transfer_submit_sync (transfer, VFS301_DEFAULT_WAIT_TIMEOUT, &err); #ifdef DEBUG - usb_print_packet(0, err, transfer->buffer, transfer->actual_length); + usb_print_packet (0, err, transfer->buffer, transfer->actual_length); #endif - if (err) { - if (!error) - g_warning("Unhandled receive error: %s", err->message); - g_propagate_error (error, err); - } + if (err) + { + if (!error) + g_warning ("Unhandled receive error: %s", err->message); + g_propagate_error (error, err); + } - if (out) - *out = g_steal_pointer (&transfer); + if (out) + *out = g_steal_pointer (&transfer); } -static void usb_send(FpDeviceVfs301 *dev, const guint8 *data, gssize length, GError **error) +static void +usb_send (FpDeviceVfs301 *dev, const guint8 *data, gssize length, GError **error) { - GError *err = NULL; - g_autoptr(FpiUsbTransfer) transfer = NULL; + GError *err = NULL; - /* XXX: This function swallows any transfer errors, that is obviously - * quite bad (it used to assert on no-error)! */ + g_autoptr(FpiUsbTransfer) transfer = NULL; - transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); - transfer->short_is_error = TRUE; - fpi_usb_transfer_fill_bulk_full (transfer, VFS301_SEND_ENDPOINT, (guint8*) data, length, g_free); + /* XXX: This function swallows any transfer errors, that is obviously + * quite bad (it used to assert on no-error)! */ - fpi_usb_transfer_submit_sync (transfer, VFS301_DEFAULT_WAIT_TIMEOUT, &err); + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + transfer->short_is_error = TRUE; + fpi_usb_transfer_fill_bulk_full (transfer, VFS301_SEND_ENDPOINT, (guint8 *) data, length, g_free); + + fpi_usb_transfer_submit_sync (transfer, VFS301_DEFAULT_WAIT_TIMEOUT, &err); #ifdef DEBUG - usb_print_packet(1, err, data, length); + usb_print_packet (1, err, data, length); #endif - if (err) { - g_warning ("Error while sending data, continuing anyway: %s", err->message); - g_propagate_error (error, err); - } + if (err) + { + g_warning ("Error while sending data, continuing anyway: %s", err->message); + g_propagate_error (error, err); + } } /************************** OUT MESSAGES GENERATION ***************************/ -static guint8 * vfs301_proto_generate_0B(int subtype, gssize *len) +static guint8 * +vfs301_proto_generate_0B (int subtype, gssize *len) { - guint8 *res = g_malloc0 (39); - guint8 *data = res; + guint8 *res = g_malloc0 (39); + guint8 *data = res; - *data = 0x0B; - *len = 1; - data++; + *data = 0x0B; + *len = 1; + data++; - *len += 38; + *len += 38; - data[20] = subtype; + data[20] = subtype; - switch (subtype) { - case 0x04: - data[34] = 0x9F; - break; - case 0x05: - data[34] = 0xAB; - /* NOTE: There was a len++ here, which could never do anything */ - break; - default: - g_assert_not_reached(); - break; - } + switch (subtype) + { + case 0x04: + data[34] = 0x9F; + break; - return res; + case 0x05: + data[34] = 0xAB; + /* NOTE: There was a len++ here, which could never do anything */ + break; + + default: + g_assert_not_reached (); + break; + } + + return res; } #define HEX_TO_INT(c) \ - (((c) >= '0' && (c) <= '9') ? ((c) - '0') : ((c) - 'A' + 10)) + (((c) >= '0' && (c) <= '9') ? ((c) - '0') : ((c) - 'A' + 10)) -static guint8 * translate_str(const char **srcL, gssize *len) +static guint8 * +translate_str (const char **srcL, gssize *len) { - guint8 *res = NULL; - guint8 *dst; - const char **src_pos; - const char *src; - gssize src_len = 0; + guint8 *res = NULL; + guint8 *dst; + const char **src_pos; + const char *src; + gssize src_len = 0; - for (src_pos = srcL; *src_pos; src_pos++) { - gint tmp; + for (src_pos = srcL; *src_pos; src_pos++) + { + gint tmp; - src = *src_pos; - tmp = strlen(src); - g_assert (tmp % 2 == 0); - src_len += tmp; - } + src = *src_pos; + tmp = strlen (src); + g_assert (tmp % 2 == 0); + src_len += tmp; + } - *len = src_len / 2; - res = g_malloc0 (*len); - dst = res; + *len = src_len / 2; + res = g_malloc0 (*len); + dst = res; - for (src_pos = srcL; *src_pos; src_pos++) { - for (src = *src_pos; *src; src += 2, dst += 1) { - *dst = (guint8) ((HEX_TO_INT (src[0]) << 4) | (HEX_TO_INT (src[1]))); - } - } + for (src_pos = srcL; *src_pos; src_pos++) + for (src = *src_pos; *src; src += 2, dst += 1) + *dst = (guint8) ((HEX_TO_INT (src[0]) << 4) | (HEX_TO_INT (src[1]))); - return res; + return res; } -static guint8 *vfs301_proto_generate(int type, int subtype, gssize *len) +static guint8 * +vfs301_proto_generate (int type, int subtype, gssize *len) { - switch (type) { - case 0x01: - case 0x04: - /* After cmd 0x04 is sent, a data is received on VALIDITY_RECEIVE_ENDPOINT_CTRL. - * If it is 0x0000: - * additional 64B and 224B are read from _DATA, then vfs301_next_scan_FA00 is - * sent, 0000 received from _CTRL, and then continue with wait loop - * If it is 0x1204: - * => reinit? - */ - case 0x17: - case 0x19: - case 0x1A: - { - guint8 *data = g_malloc0 (1); - *data = type; - *len = 1; - return data; - } - break; - case 0x0B: - return vfs301_proto_generate_0B(subtype, len); - break; - case 0x02D0: - { - const char **dataLs[] = { - vfs301_02D0_01, - vfs301_02D0_02, - vfs301_02D0_03, - vfs301_02D0_04, - vfs301_02D0_05, - vfs301_02D0_06, - vfs301_02D0_07, - }; - g_assert((int)subtype <= G_N_ELEMENTS (dataLs)); - return translate_str(dataLs[subtype - 1], len); - } - break; - case 0x0220: - switch (subtype) { - case 1: - return translate_str(vfs301_0220_01, len); - break; - case 2: - return translate_str(vfs301_0220_02, len); - break; - case 3: - return translate_str(vfs301_0220_03, len); - break; - case 0xFA00: - case 0x2C01: - case 0x5E01: { - guint8 *data; - guint8 *field; + switch (type) + { + case 0x01: + case 0x04: + /* After cmd 0x04 is sent, a data is received on VALIDITY_RECEIVE_ENDPOINT_CTRL. + * If it is 0x0000: + * additional 64B and 224B are read from _DATA, then vfs301_next_scan_FA00 is + * sent, 0000 received from _CTRL, and then continue with wait loop + * If it is 0x1204: + * => reinit? + */ + case 0x17: + case 0x19: + case 0x1A: + { + guint8 *data = g_malloc0 (1); + *data = type; + *len = 1; + return data; + } + break; - data = translate_str(vfs301_next_scan_template, len); - field = data + *len - (sizeof(S4_TAIL) - 1) / 2 - 4; + case 0x0B: + return vfs301_proto_generate_0B (subtype, len); + break; - g_assert (field >= data && field < data + *len); - g_assert(field[0] == 0xDE); - g_assert(field[1] == 0xAD); - g_assert(field[2] == 0xDE); - g_assert(field[3] == 0xAD); + case 0x02D0: + { + const char **dataLs[] = { + vfs301_02D0_01, + vfs301_02D0_02, + vfs301_02D0_03, + vfs301_02D0_04, + vfs301_02D0_05, + vfs301_02D0_06, + vfs301_02D0_07, + }; + g_assert ((int) subtype <= G_N_ELEMENTS (dataLs)); + return translate_str (dataLs[subtype - 1], len); + } + break; - field[0] = (guint8)((subtype >> 8) & 0xFF); - field[1] = (guint8)(subtype & 0xFF); - field[2] = field[0]; - field[3] = field[1]; + case 0x0220: + switch (subtype) + { + case 1: + return translate_str (vfs301_0220_01, len); + break; - return data; - break; - } - default: - g_assert_not_reached(); - break; - } - break; - case 0x06: - default: - break; - } + case 2: + return translate_str (vfs301_0220_02, len); + break; - g_assert_not_reached(); - *len = 0; - return NULL; + case 3: + return translate_str (vfs301_0220_03, len); + break; + + case 0xFA00: + case 0x2C01: + case 0x5E01: { + guint8 *data; + guint8 *field; + + data = translate_str (vfs301_next_scan_template, len); + field = data + *len - (sizeof (S4_TAIL) - 1) / 2 - 4; + + g_assert (field >= data && field < data + *len); + g_assert (field[0] == 0xDE); + g_assert (field[1] == 0xAD); + g_assert (field[2] == 0xDE); + g_assert (field[3] == 0xAD); + + field[0] = (guint8) ((subtype >> 8) & 0xFF); + field[1] = (guint8) (subtype & 0xFF); + field[2] = field[0]; + field[3] = field[1]; + + return data; + break; + } + + default: + g_assert_not_reached (); + break; + } + break; + + case 0x06: + default: + break; + } + + g_assert_not_reached (); + *len = 0; + return NULL; } /************************** SCAN IMAGE PROCESSING *****************************/ #ifdef SCAN_FINISH_DETECTION -static int img_is_finished_scan(fp_line_t *lines, int no_lines) +static int +img_is_finished_scan (fp_line_t *lines, int no_lines) { - int i; - int j; - int rv = 1; + int i; + int j; + int rv = 1; - for (i = no_lines - VFS301_FP_SUM_LINES; i < no_lines; i++) { - /* check the line for fingerprint data */ - for (j = 0; j < sizeof(lines[i].sum2); j++) { - if (lines[i].sum2[j] > (VFS301_FP_SUM_MEDIAN + VFS301_FP_SUM_EMPTY_RANGE)) - rv = 0; - } - } + for (i = no_lines - VFS301_FP_SUM_LINES; i < no_lines; i++) + { + /* check the line for fingerprint data */ + for (j = 0; j < sizeof (lines[i].sum2); j++) + if (lines[i].sum2[j] > (VFS301_FP_SUM_MEDIAN + VFS301_FP_SUM_EMPTY_RANGE)) + rv = 0; + } - return rv; + return rv; } #endif -static int scanline_diff(const guint8 *scanlines, int prev, int cur) +static int +scanline_diff (const guint8 *scanlines, int prev, int cur) { - const guint8 *line1 = scanlines + prev * VFS301_FP_OUTPUT_WIDTH; - const guint8 *line2 = scanlines + cur * VFS301_FP_OUTPUT_WIDTH; - int i; - int diff; + const guint8 *line1 = scanlines + prev * VFS301_FP_OUTPUT_WIDTH; + const guint8 *line2 = scanlines + cur * VFS301_FP_OUTPUT_WIDTH; + int i; + int diff; #ifdef OUTPUT_RAW - /* We only need the image, not the surrounding stuff. */ - line1 = ((vfs301_line_t*)line1)->scan; - line2 = ((vfs301_line_t*)line2)->scan; + /* We only need the image, not the surrounding stuff. */ + line1 = ((vfs301_line_t *) line1)->scan; + line2 = ((vfs301_line_t *) line2)->scan; #endif - /* TODO: This doesn't work too well when there are parallel lines in the - * fingerprint. */ - for (diff = 0, i = 0; i < VFS301_FP_WIDTH; i++) { - if (*line1 > *line2) - diff += *line1 - *line2; - else - diff += *line2 - *line1; + /* TODO: This doesn't work too well when there are parallel lines in the + * fingerprint. */ + for (diff = 0, i = 0; i < VFS301_FP_WIDTH; i++) + { + if (*line1 > *line2) + diff += *line1 - *line2; + else + diff += *line2 - *line1; - line1++; - line2++; - } + line1++; + line2++; + } - return ((diff / VFS301_FP_WIDTH) > VFS301_FP_LINE_DIFF_THRESHOLD); + return (diff / VFS301_FP_WIDTH) > VFS301_FP_LINE_DIFF_THRESHOLD; } /** Transform the input data to a normalized fingerprint scan */ -void vfs301_extract_image(FpDeviceVfs301 *vfs, guint8 *output, int *output_height -) +void +vfs301_extract_image (FpDeviceVfs301 *vfs, guint8 *output, int *output_height + ) { - const guint8 *scanlines = vfs->scanline_buf; - int last_line; - int i; + const guint8 *scanlines = vfs->scanline_buf; + int last_line; + int i; - g_assert(vfs->scanline_count >= 1); + g_assert (vfs->scanline_count >= 1); - *output_height = 1; - memcpy(output, scanlines, VFS301_FP_OUTPUT_WIDTH); - last_line = 0; + *output_height = 1; + memcpy (output, scanlines, VFS301_FP_OUTPUT_WIDTH); + last_line = 0; - /* The following algorithm is quite trivial - it just picks lines that - * differ more than VFS301_FP_LINE_DIFF_THRESHOLD. - * TODO: A nicer approach would be to pick those lines and then do some kind - * of bi/tri-linear resampling to get the output (so that we don't get so - * many false edges etc.). - */ - for (i = 1; i < vfs->scanline_count; i++) { - if (scanline_diff(scanlines, last_line, i)) { - memcpy( - output + VFS301_FP_OUTPUT_WIDTH * (*output_height), - scanlines + VFS301_FP_OUTPUT_WIDTH * i, - VFS301_FP_OUTPUT_WIDTH - ); - last_line = i; - (*output_height)++; - } - } + /* The following algorithm is quite trivial - it just picks lines that + * differ more than VFS301_FP_LINE_DIFF_THRESHOLD. + * TODO: A nicer approach would be to pick those lines and then do some kind + * of bi/tri-linear resampling to get the output (so that we don't get so + * many false edges etc.). + */ + for (i = 1; i < vfs->scanline_count; i++) + { + if (scanline_diff (scanlines, last_line, i)) + { + memcpy ( + output + VFS301_FP_OUTPUT_WIDTH * (*output_height), + scanlines + VFS301_FP_OUTPUT_WIDTH * i, + VFS301_FP_OUTPUT_WIDTH + ); + last_line = i; + (*output_height)++; + } + } } -static int img_process_data(int first_block, FpDeviceVfs301 *dev, const guint8 *buf, int len) +static int +img_process_data (int first_block, FpDeviceVfs301 *dev, const guint8 *buf, int len) { - vfs301_line_t *lines = (vfs301_line_t*)buf; - int no_lines = len / sizeof(vfs301_line_t); - int i; - /*int no_nonempty;*/ - guint8 *cur_line; - int last_img_height; + vfs301_line_t *lines = (vfs301_line_t *) buf; + int no_lines = len / sizeof (vfs301_line_t); + int i; + /*int no_nonempty;*/ + guint8 *cur_line; + int last_img_height; + #ifdef SCAN_FINISH_DETECTION - int finished_scan; + int finished_scan; #endif - if (first_block) { - last_img_height = 0; - dev->scanline_count = no_lines; - } else { - last_img_height = dev->scanline_count; - dev->scanline_count += no_lines; - } + if (first_block) + { + last_img_height = 0; + dev->scanline_count = no_lines; + } + else + { + last_img_height = dev->scanline_count; + dev->scanline_count += no_lines; + } - dev->scanline_buf = g_realloc(dev->scanline_buf, dev->scanline_count * VFS301_FP_OUTPUT_WIDTH); + dev->scanline_buf = g_realloc (dev->scanline_buf, dev->scanline_count * VFS301_FP_OUTPUT_WIDTH); - for (cur_line = dev->scanline_buf + last_img_height * VFS301_FP_OUTPUT_WIDTH, i = 0; - i < no_lines; - i++, cur_line += VFS301_FP_OUTPUT_WIDTH - ) { + for (cur_line = dev->scanline_buf + last_img_height * VFS301_FP_OUTPUT_WIDTH, i = 0; + i < no_lines; + i++, cur_line += VFS301_FP_OUTPUT_WIDTH + ) + { #ifndef OUTPUT_RAW - memcpy(cur_line, lines[i].scan, VFS301_FP_OUTPUT_WIDTH); + memcpy (cur_line, lines[i].scan, VFS301_FP_OUTPUT_WIDTH); #else - memcpy(cur_line, &lines[i], VFS301_FP_OUTPUT_WIDTH); + memcpy (cur_line, &lines[i], VFS301_FP_OUTPUT_WIDTH); #endif - } + } #ifdef SCAN_FINISH_DETECTION - finished_scan = img_is_finished_scan(lines, no_lines); + finished_scan = img_is_finished_scan (lines, no_lines); - return !finished_scan; + return !finished_scan; #else /* SCAN_FINISH_DETECTION */ - return 1; /* Just continue until data is coming */ + return 1; /* Just continue until data is coming */ #endif } /************************** PROTOCOL STUFF ************************************/ #define USB_RECV(from, len) \ - usb_recv(dev, from, len, NULL, NULL) + usb_recv (dev, from, len, NULL, NULL) #define USB_SEND(type, subtype) \ - { \ - const guint8 *data; \ - gssize len; \ - data = vfs301_proto_generate(type, subtype, &len); \ - usb_send(dev, data, len, NULL); \ - } + { \ + const guint8 *data; \ + gssize len; \ + data = vfs301_proto_generate (type, subtype, &len); \ + usb_send (dev, data, len, NULL); \ + } -#define RAW_DATA(x) x, sizeof(x) +#define RAW_DATA(x) x, sizeof (x) #define IS_VFS301_FP_SEQ_START(b) ((b[0] == 0x01) && (b[1] == 0xfe)) -static int vfs301_proto_process_data(FpDeviceVfs301 *dev, int first_block, const guint8 *buf, gint len) +static int +vfs301_proto_process_data (FpDeviceVfs301 *dev, int first_block, const guint8 *buf, gint len) { - int i; + int i; - if (first_block) { - g_assert(len >= VFS301_FP_FRAME_SIZE); + if (first_block) + { + g_assert (len >= VFS301_FP_FRAME_SIZE); - /* Skip bytes until start_sequence is found */ - for (i = 0; i < VFS301_FP_FRAME_SIZE; i++, buf++, len--) { - if (IS_VFS301_FP_SEQ_START(buf)) - break; - } - } + /* Skip bytes until start_sequence is found */ + for (i = 0; i < VFS301_FP_FRAME_SIZE; i++, buf++, len--) + if (IS_VFS301_FP_SEQ_START (buf)) + break; + } - return img_process_data(first_block, dev, buf, len); + return img_process_data (first_block, dev, buf, len); } -void vfs301_proto_request_fingerprint(FpDeviceVfs301 *dev) +void +vfs301_proto_request_fingerprint (FpDeviceVfs301 *dev) { - USB_SEND(0x0220, 0xFA00); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 000000000000 */ + USB_SEND (0x0220, 0xFA00); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 000000000000 */ } -int vfs301_proto_peek_event(FpDeviceVfs301 *dev) +int +vfs301_proto_peek_event (FpDeviceVfs301 *dev) { - g_autoptr(GError) error = NULL; - g_autoptr(FpiUsbTransfer) transfer = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(FpiUsbTransfer) transfer = NULL; - const char no_event[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - const char got_event[] = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00}; + const char no_event[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + const char got_event[] = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00}; - USB_SEND(0x17, -1); - usb_recv (dev, VFS301_RECEIVE_ENDPOINT_CTRL, 7, &transfer, &error); + USB_SEND (0x17, -1); + usb_recv (dev, VFS301_RECEIVE_ENDPOINT_CTRL, 7, &transfer, &error); - /* XXX: This is obviously not a sane error handling! */ - g_assert (!error); + /* XXX: This is obviously not a sane error handling! */ + g_assert (!error); - if (memcmp(transfer->buffer, no_event, sizeof(no_event)) == 0) { - return 0; - } else if (memcmp(transfer->buffer, got_event, sizeof(no_event)) == 0) { - return 1; - } else { - g_assert_not_reached(); - } + if (memcmp (transfer->buffer, no_event, sizeof (no_event)) == 0) + return 0; + else if (memcmp (transfer->buffer, got_event, sizeof (no_event)) == 0) + return 1; + else + g_assert_not_reached (); } /* XXX: We sometimes need to receive data on from two endpoints at the same @@ -458,196 +495,207 @@ int vfs301_proto_peek_event(FpDeviceVfs301 *dev) * we will run into timeouts randomly and need to then try again. */ #define PARALLEL_RECEIVE(e1, l1, e2, l2) \ - { \ - g_autoptr(GError) error = NULL;\ - usb_recv(dev, e1, l1, NULL, &error); \ - usb_recv(dev, e2, l2, NULL, NULL); \ - if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT)) \ - usb_recv(dev, e1, l1, NULL, NULL); \ - } + { \ + g_autoptr(GError) error = NULL; \ + usb_recv (dev, e1, l1, NULL, &error); \ + usb_recv (dev, e2, l2, NULL, NULL); \ + if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT)) \ + usb_recv(dev, e1, l1, NULL, NULL); \ + } -static void vfs301_proto_process_event_cb(FpiUsbTransfer *transfer, - FpDevice *device, - gpointer user_data, GError *error) +static void +vfs301_proto_process_event_cb (FpiUsbTransfer *transfer, + FpDevice *device, + gpointer user_data, GError *error) { - FpDeviceVfs301 *dev = user_data; + FpDeviceVfs301 *dev = user_data; - if (error) { - g_warning ("Error receiving data: %s", error->message); - g_error_free (error); - dev->recv_progress = VFS301_FAILURE; - return; - } else if (transfer->actual_length < transfer->length) { - /* TODO: process the data anyway? */ - dev->recv_progress = VFS301_ENDED; - return; - } else { - FpiUsbTransfer *new; - if (!vfs301_proto_process_data(dev, - transfer->length == VFS301_FP_RECV_LEN_1, - transfer->buffer, - transfer->actual_length)) { - dev->recv_progress = VFS301_ENDED; - return; - } + if (error) + { + g_warning ("Error receiving data: %s", error->message); + g_error_free (error); + dev->recv_progress = VFS301_FAILURE; + return; + } + else if (transfer->actual_length < transfer->length) + { + /* TODO: process the data anyway? */ + dev->recv_progress = VFS301_ENDED; + return; + } + else + { + FpiUsbTransfer *new; + if (!vfs301_proto_process_data (dev, + transfer->length == VFS301_FP_RECV_LEN_1, + transfer->buffer, + transfer->actual_length)) + { + dev->recv_progress = VFS301_ENDED; + return; + } - new = fpi_usb_transfer_new (device); + new = fpi_usb_transfer_new (device); - fpi_usb_transfer_fill_bulk(new, VFS301_RECEIVE_ENDPOINT_DATA, VFS301_FP_RECV_LEN_2); - fpi_usb_transfer_submit(new, VFS301_FP_RECV_TIMEOUT, NULL, - vfs301_proto_process_event_cb, NULL); - fpi_usb_transfer_unref (new); - return; - } + fpi_usb_transfer_fill_bulk (new, VFS301_RECEIVE_ENDPOINT_DATA, VFS301_FP_RECV_LEN_2); + fpi_usb_transfer_submit (new, VFS301_FP_RECV_TIMEOUT, NULL, + vfs301_proto_process_event_cb, NULL); + fpi_usb_transfer_unref (new); + return; + } } -void vfs301_proto_process_event_start(FpDeviceVfs301 *dev) +void +vfs301_proto_process_event_start (FpDeviceVfs301 *dev) { - FpiUsbTransfer *transfer; + FpiUsbTransfer *transfer; - /* - * Notes: - * - * seen next_scan order: - * o FA00 - * o FA00 - * o 2C01 - * o FA00 - * o FA00 - * o 2C01 - * o FA00 - * o FA00 - * o 2C01 - * o 5E01 !? - * o FA00 - * o FA00 - * o 2C01 - * o FA00 - * o FA00 - * o 2C01 - */ - USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 64); + /* + * Notes: + * + * seen next_scan order: + * o FA00 + * o FA00 + * o 2C01 + * o FA00 + * o FA00 + * o 2C01 + * o FA00 + * o FA00 + * o 2C01 + * o 5E01 !? + * o FA00 + * o FA00 + * o 2C01 + * o FA00 + * o FA00 + * o 2C01 + */ + USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 64); - /* now read the fingerprint data, while there are some */ - transfer = fpi_usb_transfer_new(FP_DEVICE (dev)); - dev->recv_progress = VFS301_ONGOING; + /* now read the fingerprint data, while there are some */ + transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); + dev->recv_progress = VFS301_ONGOING; - fpi_usb_transfer_fill_bulk (transfer, VFS301_RECEIVE_ENDPOINT_DATA, VFS301_FP_RECV_LEN_1); - fpi_usb_transfer_submit(transfer, VFS301_FP_RECV_TIMEOUT, NULL, - vfs301_proto_process_event_cb, NULL); - fpi_usb_transfer_unref(transfer); + fpi_usb_transfer_fill_bulk (transfer, VFS301_RECEIVE_ENDPOINT_DATA, VFS301_FP_RECV_LEN_1); + fpi_usb_transfer_submit (transfer, VFS301_FP_RECV_TIMEOUT, NULL, + vfs301_proto_process_event_cb, NULL); + fpi_usb_transfer_unref (transfer); } -int vfs301_proto_process_event_poll(FpDeviceVfs301 *dev) +int +vfs301_proto_process_event_poll (FpDeviceVfs301 *dev) { - if (dev->recv_progress != VFS301_ENDED) - return dev->recv_progress; + if (dev->recv_progress != VFS301_ENDED) + return dev->recv_progress; - /* Finish the scan process... */ + /* Finish the scan process... */ - USB_SEND(0x04, -1); - /* the following may come in random order, data may not come at all, don't - * try for too long... */ - PARALLEL_RECEIVE( - VFS301_RECEIVE_ENDPOINT_CTRL, 2, /* 1204 */ - VFS301_RECEIVE_ENDPOINT_DATA, 16384 - ); + USB_SEND (0x04, -1); + /* the following may come in random order, data may not come at all, don't + * try for too long... */ + PARALLEL_RECEIVE ( + VFS301_RECEIVE_ENDPOINT_CTRL, 2, /* 1204 */ + VFS301_RECEIVE_ENDPOINT_DATA, 16384 + ); - USB_SEND(0x0220, 2); - PARALLEL_RECEIVE( - VFS301_RECEIVE_ENDPOINT_DATA, 5760, /* seems to always come */ - VFS301_RECEIVE_ENDPOINT_CTRL, 2 /* 0000 */ - ); + USB_SEND (0x0220, 2); + PARALLEL_RECEIVE ( + VFS301_RECEIVE_ENDPOINT_DATA, 5760, /* seems to always come */ + VFS301_RECEIVE_ENDPOINT_CTRL, 2 /* 0000 */ + ); - return dev->recv_progress; + return dev->recv_progress; } -void vfs301_proto_init(FpDeviceVfs301 *dev) +void +vfs301_proto_init (FpDeviceVfs301 *dev) { - USB_SEND(0x01, -1); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 38); - USB_SEND(0x0B, 0x04); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 6); /* 000000000000 */ - USB_SEND(0x0B, 0x05); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 7); /* 00000000000000 */ - USB_SEND(0x19, -1); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 64); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 4); /* 6BB4D0BC */ - usb_send(dev, RAW_DATA(vfs301_06_1), NULL); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + USB_SEND (0x01, -1); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 38); + USB_SEND (0x0B, 0x04); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 6); /* 000000000000 */ + USB_SEND (0x0B, 0x05); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 7); /* 00000000000000 */ + USB_SEND (0x19, -1); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 64); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 4); /* 6BB4D0BC */ + usb_send (dev, RAW_DATA (vfs301_06_1), NULL); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - USB_SEND(0x01, -1); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 38); - USB_SEND(0x1A, -1); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - usb_send(dev, RAW_DATA(vfs301_06_2), NULL); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - USB_SEND(0x0220, 1); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 256); - USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 32); + USB_SEND (0x01, -1); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 38); + USB_SEND (0x1A, -1); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + usb_send (dev, RAW_DATA (vfs301_06_2), NULL); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + USB_SEND (0x0220, 1); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 256); + USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 32); - USB_SEND(0x1A, -1); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - usb_send(dev, RAW_DATA(vfs301_06_3), NULL); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + USB_SEND (0x1A, -1); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + usb_send (dev, RAW_DATA (vfs301_06_3), NULL); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - USB_SEND(0x01, -1); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 38); - USB_SEND(0x02D0, 1); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 11648); /* 56 * vfs301_init_line_t[] */ - USB_SEND(0x02D0, 2); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 53248); /* 2 * 128 * vfs301_init_line_t[] */ - USB_SEND(0x02D0, 3); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 19968); /* 96 * vfs301_init_line_t[] */ - USB_SEND(0x02D0, 4); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 5824); /* 28 * vfs301_init_line_t[] */ - USB_SEND(0x02D0, 5); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 6656); /* 32 * vfs301_init_line_t[] */ - USB_SEND(0x02D0, 6); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 6656); /* 32 * vfs301_init_line_t[] */ - USB_SEND(0x02D0, 7); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 832); - usb_send(dev, RAW_DATA(vfs301_12), NULL); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + USB_SEND (0x01, -1); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 38); + USB_SEND (0x02D0, 1); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 11648); /* 56 * vfs301_init_line_t[] */ + USB_SEND (0x02D0, 2); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 53248); /* 2 * 128 * vfs301_init_line_t[] */ + USB_SEND (0x02D0, 3); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 19968); /* 96 * vfs301_init_line_t[] */ + USB_SEND (0x02D0, 4); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 5824); /* 28 * vfs301_init_line_t[] */ + USB_SEND (0x02D0, 5); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 6656); /* 32 * vfs301_init_line_t[] */ + USB_SEND (0x02D0, 6); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 6656); /* 32 * vfs301_init_line_t[] */ + USB_SEND (0x02D0, 7); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 832); + usb_send (dev, RAW_DATA (vfs301_12), NULL); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - USB_SEND(0x1A, -1); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - usb_send(dev, RAW_DATA(vfs301_06_2), NULL); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - USB_SEND(0x0220, 2); - PARALLEL_RECEIVE( - VFS301_RECEIVE_ENDPOINT_CTRL, 2, /* 0000 */ - VFS301_RECEIVE_ENDPOINT_DATA, 5760 - ); + USB_SEND (0x1A, -1); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + usb_send (dev, RAW_DATA (vfs301_06_2), NULL); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + USB_SEND (0x0220, 2); + PARALLEL_RECEIVE ( + VFS301_RECEIVE_ENDPOINT_CTRL, 2, /* 0000 */ + VFS301_RECEIVE_ENDPOINT_DATA, 5760 + ); - USB_SEND(0x1A, -1); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - usb_send(dev, RAW_DATA(vfs301_06_1), NULL); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + USB_SEND (0x1A, -1); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + usb_send (dev, RAW_DATA (vfs301_06_1), NULL); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - USB_SEND(0x1A, -1); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - usb_send(dev, RAW_DATA(vfs301_06_4), NULL); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - usb_send(dev, RAW_DATA(vfs301_24), NULL); /* turns on white */ - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + USB_SEND (0x1A, -1); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + usb_send (dev, RAW_DATA (vfs301_06_4), NULL); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ + usb_send (dev, RAW_DATA (vfs301_24), NULL); /* turns on white */ + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ - USB_SEND(0x01, -1); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 38); - USB_SEND(0x0220, 3); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2368); - USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 36); - USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 5760); + USB_SEND (0x01, -1); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 38); + USB_SEND (0x0220, 3); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2368); + USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 36); + USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 5760); } -void vfs301_proto_deinit(FpDeviceVfs301 *dev) +void +vfs301_proto_deinit (FpDeviceVfs301 *dev) { } diff --git a/libfprint/drivers/vfs301_proto_fragments.h b/libfprint/drivers/vfs301_proto_fragments.h index 39441a13..6decbc79 100644 --- a/libfprint/drivers/vfs301_proto_fragments.h +++ b/libfprint/drivers/vfs301_proto_fragments.h @@ -26,1118 +26,1118 @@ * I missed some block start, or split data that should be together. * It's quite challenging, this reverse engineering... :-) */ -#define __01 0x88 /* sometimes also 0x87? depending on what? */ +#define __01 0x88 /* sometimes also 0x87? depending on what? */ static const unsigned char vfs301_06_1[] = { /* 2401 B */ - 0x06, 0x00, 0x00, 0x54, 0x09, 0x00, 0x0F, 0x00, 0x60, - 0xD8, 0x0C, 0x00, 0x60, - 0xD4, 0x0C, 0x00, 0x60, - 0x18, 0x17, 0x00, 0x60, - 0x28, 0x17, 0x00, 0x60, - 0xC8, 0x0D, 0x00, 0x60, - 0x9C, 0x0B, 0x00, 0x60, - 0xD8, 0x16, 0x00, 0x60, - 0xDC, 0x16, 0x00, 0x60, - 0x00, 0x0E, 0x04, 0x30, 0xE0, 0x0C, 0x00, 0x60, - 0x07, 0x09, 0x00, 0x00, 0xFF, 0xF7, 0xFF, 0xFF, 0xCC, 0x08, 0x00, 0x60, - 0x02, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x48, 0x0D, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0xE0, 0x16, 0x00, 0x60, - 0x00, 0x12, 0x04, 0x30, 0xA5, 0xC2, 0x00, 0x00, 0xE4, 0x16, 0x00, 0x60, - 0xF0, 0x16, 0x00, 0x60, - 0x00, 0x0F, 0x04, 0x30, 0xB0, 0x0A, 0x00, 0x60, - 0x58, 0xB3, 0x04, 0x60, - 0x84, 0x05, 0x00, 0x60, - 0xA4, 0xED, 0x04, 0x60, - 0x8C, 0x04, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x60, - 0x40, 0x08, 0x00, 0x00, 0x10, 0x03, 0x02, 0x28, 0x1C, 0x0E, 0x00, 0x60, - 0x30, 0x17, 0x00, 0x60, - 0x70, 0x0E, 0x00, 0x60, + 0x06, 0x00, 0x00, 0x54, 0x09, 0x00, 0x0F, 0x00, 0x60, + 0xD8, 0x0C, 0x00, 0x60, + 0xD4, 0x0C, 0x00, 0x60, + 0x18, 0x17, 0x00, 0x60, + 0x28, 0x17, 0x00, 0x60, + 0xC8, 0x0D, 0x00, 0x60, + 0x9C, 0x0B, 0x00, 0x60, + 0xD8, 0x16, 0x00, 0x60, + 0xDC, 0x16, 0x00, 0x60, + 0x00, 0x0E, 0x04, 0x30, 0xE0, 0x0C, 0x00, 0x60, + 0x07, 0x09, 0x00, 0x00, 0xFF, 0xF7, 0xFF, 0xFF, 0xCC, 0x08, 0x00, 0x60, + 0x02, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x48, 0x0D, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0xE0, 0x16, 0x00, 0x60, + 0x00, 0x12, 0x04, 0x30, 0xA5, 0xC2, 0x00, 0x00, 0xE4, 0x16, 0x00, 0x60, + 0xF0, 0x16, 0x00, 0x60, + 0x00, 0x0F, 0x04, 0x30, 0xB0, 0x0A, 0x00, 0x60, + 0x58, 0xB3, 0x04, 0x60, + 0x84, 0x05, 0x00, 0x60, + 0xA4, 0xED, 0x04, 0x60, + 0x8C, 0x04, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x60, + 0x40, 0x08, 0x00, 0x00, 0x10, 0x03, 0x02, 0x28, 0x1C, 0x0E, 0x00, 0x60, + 0x30, 0x17, 0x00, 0x60, + 0x70, 0x0E, 0x00, 0x60, - 0xFF, 0xFF, 0xFF, 0xBF, 0xFD, 0x0C, 0x00, - 0x60, 0xF8, 0x16, 0x00, 0x60, 0xA8, 0x0B, 0x00, - 0x60, 0x08, 0x17, 0x00, 0x60, 0x18, 0x0D, 0x00, - 0x60, 0x00, 0x9E, 0x00, 0x38, 0xDC, 0x0C, 0x00, - 0x60, 0x04, 0x17, 0x00, 0x60, 0x36, 0x41, 0x00, - 0xE5, 0x59, 0x00, 0xA5, 0x65, 0x00, 0xE5, 0x5C, - 0x00, 0x25, 0x66, 0x00, 0x25, 0x58, 0x00, 0x91, - 0xC0, 0x03, 0xA1, 0xC1, 0x03, 0x0C, 0x08, 0x89, - 0x0A, 0x82, 0x49, 0x00, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x61, 0x00, 0x0C, 0x96, 0x91, 0xC2, - 0x03, 0xB1, 0xC3, 0x03, 0x71, 0xC4, 0x03, 0xD8, - 0x1B, 0x16, 0x84, 0x07, 0xC2, 0x0D, 0x4E, 0xC0, - 0xC0, 0x74, 0xE2, 0xA0, 0x71, 0x47, 0x3E, 0x05, - 0x16, 0xDC, 0x0F, 0x47, 0xBE, 0x02, 0x16, 0x4C, - 0x13, 0xF2, 0xA4, 0x6B, 0x26, 0x1C, 0x6E, 0x82, - 0xCC, 0xFE, 0x16, 0x88, 0x07, 0x16, 0x25, 0x05, - 0xC2, 0x0D, 0x4E, 0x16, 0x2C, 0x08, 0x92, 0xCC, - 0xFE, 0x16, 0x59, 0x08, 0x60, 0xAC, 0xC0, 0x16, - 0xAA, 0x10, 0xC2, 0x2D, 0x10, 0xC2, 0x0C, 0x00, - 0xA2, 0xA4, 0x6D, 0x66, 0x6C, 0x02, 0x06, 0x03, - 0x00, 0xAD, 0x0D, 0x65, 0x3B, 0x00, 0xD1, 0xC3, - 0x03, 0xD8, 0x1D, 0x16, 0xAA, 0x07, 0x0C, 0x9C, - 0xE8, 0x07, 0x62, 0x4D, 0x4E, 0xA2, 0x5E, 0x00, - 0xC0, 0xF0, 0x74, 0x60, 0xFF, 0xC0, 0x16, 0xBF, - 0x0D, 0x0C, 0x38, 0xA1, 0xC5, 0x03, 0x91, 0xC6, - 0x03, 0x99, 0x2A, 0x82, 0x4D, 0x4E, 0x0C, 0x2A, - 0xA5, 0xC6, 0x29, 0x1D, 0xF0, 0x16, 0xCD, 0x13, - 0xE8, 0x07, 0xC2, 0xA4, 0x70, 0xC2, 0x5E, 0x00, - 0xC2, 0x0D, 0x4E, 0x06, 0xDE, 0xFF, 0x16, 0xD3, - 0xF8, 0x0C, 0x9C, 0x88, 0x07, 0x62, 0x4D, 0x4E, - 0xF2, 0x58, 0x00, 0x06, 0xE0, 0xFF, 0xC2, 0x1D, - 0x24, 0x37, 0xBC, 0x34, 0x98, 0x07, 0x62, 0x4D, - 0x4E, 0xF2, 0x59, 0x00, 0x46, 0xDD, 0xFF, 0x00, - 0x00, 0x47, 0xBE, 0x02, 0x86, 0xDD, 0xFF, 0x46, - 0x01, 0x00, 0xA2, 0x1D, 0x24, 0x16, 0x3A, 0xF7, - 0xE8, 0x07, 0xC2, 0xA4, 0x6C, 0xC2, 0x5E, 0x00, - 0x62, 0x4D, 0x4E, 0x0C, 0x9C, 0xC6, 0xD8, 0xFF, - 0x00, 0xC2, 0x0D, 0x4E, 0x06, 0xE2, 0xFF, 0x00, - 0x00, 0x16, 0x83, 0xF4, 0xFD, 0x0C, 0xF9, 0x01, - 0xC7, 0xB3, 0x03, 0x8D, 0x03, 0x89, 0x01, 0xA8, - 0xFD, 0xBD, 0x02, 0xC2, 0x21, 0x00, 0xA5, 0x80, - 0x2D, 0xB1, 0xC3, 0x03, 0xD8, 0x1B, 0xA8, 0x01, - 0xC8, 0xFD, 0xAA, 0xCC, 0xC9, 0xFD, 0xD8, 0x1B, - 0x92, 0x1D, 0x24, 0xE2, 0xA0, 0x71, 0xA0, 0x99, - 0xC0, 0x92, 0x5D, 0x24, 0x46, 0xC5, 0xFF, 0x00, - 0x00, 0xF2, 0xA0, 0x72, 0x8D, 0x03, 0x89, 0x01, - 0x40, 0xFF, 0xC0, 0x37, 0xBF, 0x03, 0x8D, 0x0F, - 0x89, 0x01, 0xBD, 0x02, 0xA2, 0x2D, 0x11, 0xC8, - 0x01, 0x4A, 0xAA, 0xE5, 0x7C, 0x2D, 0xE2, 0xA0, - 0x71, 0xC8, 0x01, 0xB1, 0xC3, 0x03, 0xCA, 0x22, - 0xC0, 0x33, 0xC0, 0xD8, 0x1B, 0xCA, 0x44, 0xC2, - 0x0D, 0x4E, 0x46, 0xB3, 0xFF, 0xA1, 0xC2, 0x03, - 0xE5, 0x70, 0x2D, 0xC6, 0xC9, 0xFF, 0xA2, 0x2D, - 0x11, 0x0C, 0x1E, 0xE2, 0x4D, 0x4E, 0x25, 0x5E, - 0x2D, 0xC1, 0xC3, 0x03, 0xC8, 0x1C, 0xBD, 0x0A, - 0xA2, 0x2C, 0x11, 0xB9, 0xBC, 0x4B, 0xAA, 0x25, - 0x5D, 0x2D, 0xD1, 0xC3, 0x03, 0xD2, 0x2D, 0x01, - 0xA2, 0x6D, 0x0C, 0xA2, 0x2D, 0x11, 0x65, 0x2E, - 0x2D, 0xB1, 0xC3, 0x03, 0xD8, 0x1B, 0x0C, 0x0E, - 0xA8, 0xBD, 0xE2, 0x6D, 0x11, 0xAC, 0xCA, 0xE5, - 0x22, 0x2D, 0xB1, 0xC3, 0x03, 0xF8, 0x1B, 0xA2, - 0x6F, 0x10, 0xD8, 0x1B, 0x92, 0x2D, 0x10, 0x16, - 0xE9, 0x04, 0x0C, 0x2C, 0x99, 0xFD, 0xD8, 0x1B, - 0x0C, 0x2A, 0xA2, 0x4D, 0x4E, 0x88, 0xBD, 0x82, - 0x5D, 0x24, 0xE2, 0xA0, 0x71, 0xC0, 0xC0, 0x74, - 0x46, 0x99, 0xFF, 0x00, 0x00, 0xC2, 0x0D, 0x4E, - 0x86, 0xFB, 0xFF, 0x00, 0x00, 0xAD, 0x09, 0x25, - 0x65, 0x2D, 0xA2, 0xA0, 0x72, 0xE5, 0x1E, 0x2D, - 0xB1, 0xC3, 0x03, 0xD8, 0x1B, 0xA2, 0x6D, 0x11, - 0xCC, 0xEA, 0x0C, 0x9C, 0x62, 0x4D, 0x4E, 0x88, - 0x07, 0xF2, 0xA4, 0x6A, 0xF2, 0x58, 0x00, 0x06, - 0x89, 0xFF, 0xC2, 0x0D, 0x4E, 0x86, 0x87, 0xFF, - 0x00, 0x0C, 0x9C, 0x62, 0x4D, 0x4E, 0xA8, 0x07, - 0x92, 0xA4, 0x6F, 0x92, 0x5A, 0x00, 0x06, 0xEC, - 0xFF, 0x36, 0x41, 0x00, 0x42, 0xC2, 0x20, 0x82, - 0xC2, 0x14, 0x91, 0xC7, 0x03, 0x8B, 0xB2, 0x7C, - 0xF3, 0x39, 0xD2, 0x49, 0x92, 0x49, 0x82, 0x89, - 0x62, 0x89, 0x52, 0x99, 0x42, 0xB9, 0x32, 0xB9, - 0x22, 0xA2, 0xC9, 0xFC, 0xA9, 0x72, 0x1D, 0xF0, - 0x00, 0x36, 0x41, 0x00, 0xA2, 0x22, 0x10, 0x16, - 0x2A, 0x00, 0x25, 0x23, 0x2D, 0xA2, 0x22, 0x11, - 0x8C, 0x1A, 0xA5, 0x22, 0x2D, 0xA8, 0xD2, 0x26, - 0x0A, 0x02, 0xE5, 0x56, 0x21, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x20, 0xA2, 0x20, 0x65, - 0xA5, 0x2A, 0xA1, 0xC3, 0x03, 0xA2, 0x2A, 0x01, - 0xA2, 0xCA, 0x14, 0x65, 0x0E, 0x2D, 0xE5, 0x95, - 0x2A, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x31, 0xC3, 0x03, 0xC8, 0x13, 0x0C, 0x05, 0x92, - 0x0C, 0x4E, 0x41, 0xC8, 0x03, 0x82, 0xC9, 0xFD, - 0x16, 0x68, 0x0B, 0x26, 0x49, 0x14, 0x21, 0xC9, - 0x03, 0x26, 0x59, 0x10, 0xA2, 0xC9, 0xFA, 0x16, - 0xFA, 0x07, 0xB2, 0xC9, 0xF9, 0x16, 0x4B, 0x0D, - 0x26, 0x89, 0x49, 0x1D, 0xF0, 0xA2, 0x2C, 0x10, - 0xE8, 0x12, 0xD8, 0x22, 0xD9, 0x03, 0xE2, 0x62, - 0x02, 0x16, 0x9A, 0x00, 0x25, 0x1C, 0x2D, 0xF8, - 0x13, 0x52, 0x6F, 0x10, 0xC8, 0x13, 0xC0, 0x20, - 0x00, 0xB2, 0xA2, 0x00, 0x81, 0xCA, 0x03, 0x82, - 0x64, 0x83, 0xA8, 0xCC, 0xA9, 0xEC, 0xE5, 0xA5, - 0x24, 0xA8, 0x13, 0x0C, 0x69, 0x92, 0x4A, 0x4E, - 0xA2, 0xA2, 0x00, 0xE5, 0x86, 0x2A, 0xA8, 0x13, - 0x8B, 0xAA, 0xA5, 0x0A, 0x00, 0xC0, 0x20, 0x00, - 0x52, 0x64, 0x80, 0x1D, 0xF0, 0xC0, 0x20, 0x00, - 0xC1, 0xCB, 0x03, 0xB2, 0x24, 0x83, 0xC0, 0x20, - 0x00, 0xC0, 0xBB, 0x10, 0xB2, 0x64, 0x83, 0x65, - 0xD5, 0x2A, 0xA8, 0x13, 0x8B, 0xAA, 0xE5, 0x06, - 0x2D, 0xA1, 0xC2, 0x03, 0x25, 0x56, 0x2D, 0x98, - 0x03, 0x16, 0xE9, 0xF8, 0x99, 0x22, 0x59, 0x03, - 0x1D, 0xF0, 0xA2, 0xCC, 0x20, 0xA5, 0x92, 0x2A, - 0x16, 0xFA, 0xF7, 0x22, 0xA0, 0x07, 0xB2, 0x0A, - 0x2C, 0xC2, 0x23, 0x01, 0x07, 0x6B, 0x02, 0x22, - 0x4C, 0x4E, 0x65, 0xA4, 0x24, 0xA8, 0x13, 0xA2, - 0xCA, 0x20, 0xE5, 0x90, 0x2A, 0x56, 0x5A, 0xFE, - 0x1D, 0xF0, 0x52, 0x63, 0x00, 0xA1, 0xCD, 0x03, - 0xB1, 0xCC, 0x03, 0xB2, 0x62, 0x02, 0x65, 0xB5, - 0x2A, 0xC0, 0x20, 0x00, 0x0C, 0x4C, 0xE1, 0xCE, - 0x03, 0xD2, 0x24, 0x83, 0xC0, 0x20, 0x00, 0xA8, - 0x13, 0xE0, 0xDD, 0x20, 0xD2, 0x64, 0x83, 0xC2, - 0x4A, 0x4E, 0xE5, 0x0C, 0x00, 0xAD, 0x02, 0xA5, - 0x9A, 0x29, 0x1D, 0xF0, 0x00, 0xA1, 0xCF, 0x03, - 0x25, 0x52, 0x2D, 0xC0, 0x20, 0x00, 0xA8, 0x13, - 0xF1, 0xD0, 0x03, 0xF2, 0x64, 0x83, 0x65, 0x1B, - 0x00, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x31, 0xC3, 0x03, 0x82, 0x23, 0x01, 0x71, 0xD1, - 0x03, 0x82, 0x28, 0x0E, 0x62, 0xA0, 0x00, 0x16, - 0x68, 0x05, 0xE5, 0x76, 0x2A, 0x4D, 0x0A, 0x16, - 0x2A, 0x05, 0xA8, 0x13, 0x52, 0x14, 0x15, 0xA8, - 0xEA, 0x57, 0xBA, 0x01, 0x5D, 0x0A, 0xB1, 0xD2, - 0x03, 0xC8, 0x24, 0x0C, 0x0D, 0xF1, 0xD3, 0x03, - 0x50, 0xE0, 0xF4, 0xE2, 0x54, 0x14, 0x52, 0xC4, - 0x10, 0xAD, 0x05, 0xE5, 0x81, 0x21, 0x62, 0x44, - 0x2C, 0xD8, 0x13, 0xC2, 0x14, 0x14, 0xB8, 0xED, - 0xC0, 0xBB, 0xC0, 0xB9, 0xED, 0xCC, 0x8B, 0x79, - 0x34, 0x0C, 0x1D, 0xD2, 0x44, 0x2C, 0xD2, 0x23, - 0x01, 0xAD, 0x05, 0xB8, 0xDD, 0x0C, 0x1C, 0x25, - 0xAD, 0x21, 0xE8, 0x13, 0xE8, 0xEE, 0x56, 0x8E, - 0xFA, 0x1D, 0xF0, 0x00, 0x00, 0xAD, 0x02, 0x65, - 0x72, 0x2A, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, - 0xB2, 0xC2, 0xF0, 0xA2, 0xC3, 0x20, 0xA5, 0x7F, - 0x2A, 0xA2, 0xC3, 0x14, 0xE5, 0xF3, 0x2C, 0x1D, - 0xF0, 0x36, 0x41, 0x00, 0x0C, 0x0A, 0xBD, 0x02, - 0xC1, 0xD4, 0x03, 0x65, 0x9B, 0x21, 0xA9, 0xD2, - 0x26, 0x0A, 0x05, 0x0C, 0x02, 0x1D, 0xF0, 0x00, - 0x00, 0x22, 0xA4, 0x6E, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0xA2, 0xA0, 0x03, 0xB1, - 0xD5, 0x03, 0xE5, 0xEA, 0x2C, 0x92, 0xA0, 0x60, - 0x81, 0xC8, 0x03, 0xB8, 0xB2, 0xA2, 0x22, 0x10, - 0xA9, 0xF2, 0xB2, 0x52, 0x26, 0xB2, 0x52, 0x25, - 0x0C, 0x8B, 0xC0, 0x20, 0x00, 0xF2, 0x28, 0x81, - 0xC0, 0x20, 0x00, 0xE8, 0xF2, 0x90, 0xFF, 0x20, - 0xF2, 0x68, 0x81, 0xE2, 0x0E, 0x00, 0xC0, 0x20, - 0x00, 0xC8, 0xF2, 0xF1, 0xD6, 0x03, 0x1B, 0xCC, - 0xE2, 0x5F, 0x80, 0xD2, 0x12, 0x25, 0xC9, 0xF2, - 0x0B, 0xDD, 0xD2, 0x52, 0x25, 0x80, 0x61, 0x00, - 0x9D, 0x08, 0xA0, 0xE4, 0x03, 0xB0, 0xAA, 0x20, - 0xA0, 0xE4, 0x13, 0x80, 0xE6, 0x13, 0x10, 0x20, - 0x00, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x61, 0x00, - 0xC0, 0x20, 0x00, 0xC1, 0xD6, 0x03, 0xF1, 0xC8, - 0x03, 0xE1, 0xC3, 0x03, 0xA2, 0x2F, 0x82, 0xB8, - 0x1E, 0x17, 0x6A, 0x14, 0x92, 0x1B, 0x26, 0x16, - 0xE9, 0x00, 0x82, 0xC9, 0xFF, 0xC0, 0x20, 0x00, - 0xD2, 0x1C, 0x80, 0xD2, 0x51, 0x00, 0x82, 0x5B, - 0x26, 0x92, 0x1B, 0x25, 0x07, 0xEA, 0x07, 0x8C, - 0xA9, 0x82, 0x0B, 0x4E, 0x26, 0x48, 0x41, 0x8C, - 0x29, 0x1D, 0xF0, 0x00, 0x00, 0x92, 0x1B, 0x26, - 0x56, 0x59, 0xFF, 0xC0, 0x20, 0x00, 0x0C, 0x5D, - 0x92, 0xAF, 0x9F, 0x82, 0x2F, 0x81, 0xC0, 0x20, - 0x00, 0x90, 0x88, 0x10, 0x82, 0x6F, 0x81, 0x7C, - 0x7F, 0xA0, 0x61, 0x00, 0xCD, 0x0A, 0xE0, 0xE4, - 0x03, 0xF0, 0xEE, 0x10, 0xE0, 0xE4, 0x13, 0xA0, - 0xE6, 0x13, 0x10, 0x20, 0x00, 0xD2, 0x4B, 0x4E, - 0xA2, 0xCB, 0x14, 0xE5, 0xE3, 0x2C, 0x1D, 0xF0, - 0x00, 0xD8, 0xFB, 0xD2, 0x0D, 0x00, 0xC0, 0x20, - 0x00, 0xA8, 0xFB, 0xD2, 0x5C, 0x80, 0x1B, 0xAA, - 0xA9, 0xFB, 0xB8, 0x1E, 0x92, 0x1B, 0x25, 0x0B, - 0x99, 0x90, 0x90, 0xF4, 0x92, 0x5B, 0x25, 0x06, - 0xE7, 0xFF, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x92, 0xA0, 0x06, 0xB1, 0xC8, 0x03, 0xC0, 0x20, - 0x00, 0x82, 0x2B, 0x82, 0x0C, 0x0A, 0x17, 0x68, - 0x0B, 0x92, 0xC9, 0xFF, 0xC0, 0x20, 0x00, 0xC2, - 0x2B, 0x80, 0x56, 0x89, 0xFE, 0xC0, 0x20, 0x00, - 0xA2, 0xC2, 0x14, 0x0C, 0x8D, 0xE2, 0xA0, 0x04, - 0xE2, 0x6B, 0x84, 0xD2, 0x42, 0x4E, 0x25, 0xDE, - 0x2C, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x31, 0xD7, 0x03, 0x21, 0xD8, 0x03, 0x22, 0x63, - 0x75, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, - 0xA1, 0xD9, 0x03, 0xB1, 0xDA, 0x03, 0xC1, 0xDB, - 0x03, 0xE5, 0x37, 0x2D, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x16, 0xA5, 0x01, 0x20, - 0x61, 0x00, 0x25, 0xA4, 0xFF, 0x20, 0xE6, 0x13, - 0x10, 0x20, 0x00, 0xA2, 0xA0, 0x00, 0x65, 0x72, - 0x29, 0xA1, 0xDC, 0x03, 0xB1, 0xDD, 0x03, 0xE5, - 0xFF, 0x2C, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, - 0xA1, 0xDE, 0x03, 0xB1, 0xDE, 0x03, 0x65, 0xFC, - 0x20, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, - 0xCD, 0x04, 0x81, 0xDF, 0x03, 0xBD, 0x03, 0x88, - 0x08, 0xAD, 0x02, 0xCC, 0xF8, 0x8C, 0xD3, 0xD1, - 0xC9, 0x03, 0xF1, 0xE0, 0x03, 0x98, 0x1D, 0xE8, - 0x2D, 0xE9, 0x0F, 0x92, 0x6D, 0x02, 0xE5, 0x65, - 0x29, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, - 0xC1, 0xE0, 0x03, 0xAD, 0x02, 0x98, 0x0C, 0x0C, - 0x0B, 0x8C, 0x59, 0x81, 0xC9, 0x03, 0xB9, 0x0C, - 0x99, 0x28, 0xE5, 0x70, 0x29, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0xD1, 0xE2, 0x03, 0x91, - 0xE3, 0x03, 0xB0, 0x82, 0x11, 0xA1, 0xE1, 0x03, - 0xB2, 0xAE, 0xF0, 0xBA, 0xAA, 0xAA, 0xA8, 0x9A, - 0x88, 0xC8, 0x0A, 0xC0, 0x20, 0x00, 0xB8, 0x7C, - 0xC0, 0x20, 0x00, 0xD0, 0xBB, 0x10, 0xB9, 0x7C, - 0x82, 0x08, 0x7F, 0x0C, 0x09, 0x8C, 0x18, 0xE5, - 0x5B, 0x21, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, - 0x21, 0xE4, 0x03, 0x31, 0xE5, 0x03, 0x28, 0x22, - 0x29, 0x03, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, - 0x21, 0xE6, 0x03, 0x88, 0x02, 0x27, 0x98, 0x02, - 0x1D, 0xF0, 0x00, 0x20, 0xA2, 0x20, 0x25, 0x08, - 0x00, 0xAD, 0x02, 0xE5, 0xC5, 0x20, 0x1D, 0xF0, - 0x00, 0x36, 0x41, 0x00, 0x20, 0x61, 0x00, 0xA1, - 0xE6, 0x03, 0xE5, 0xC4, 0x20, 0xA5, 0x0B, 0x24, - 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, 0x1D, 0xF0, - 0x00, 0x36, 0x41, 0x00, 0x41, 0xE7, 0x03, 0x21, - 0xE8, 0x03, 0xC0, 0x20, 0x00, 0x32, 0x22, 0x81, - 0x98, 0x54, 0x88, 0x34, 0x30, 0x99, 0x20, 0x99, - 0x54, 0x87, 0x83, 0x39, 0x0C, 0x1C, 0xB2, 0xA0, - 0x38, 0xA2, 0x24, 0x04, 0xC0, 0x20, 0x00, 0xB0, - 0xAA, 0x10, 0xA2, 0x62, 0x80, 0xC0, 0x20, 0x00, - 0xD2, 0x22, 0x81, 0xD0, 0xE0, 0x04, 0x07, 0xED, - 0xF3, 0xC0, 0x20, 0x00, 0xB1, 0xE9, 0x03, 0x32, - 0x62, 0x81, 0xC0, 0x20, 0x00, 0xB8, 0x0B, 0xA1, - 0xEA, 0x03, 0x1B, 0xBB, 0xB9, 0x4A, 0x4B, 0xAA, - 0xA5, 0xBD, 0x20, 0x1D, 0xF0, 0x00, 0x0C, 0x0C, - 0xC9, 0x34, 0xE5, 0xC4, 0x21, 0xC6, 0xEE, 0xFF, - 0x00, 0x36, 0x41, 0x00, 0x20, 0x61, 0x00, 0x3C, - 0x8A, 0x0C, 0x0B, 0x65, 0x08, 0x24, 0x20, 0xE6, - 0x13, 0x10, 0x20, 0x00, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x1F, 0x00, 0x00, 0x00, 0xD0, 0x0F, 0x02, - 0x60, 0xD8, 0x11, 0x02, 0x60, 0x00, 0x12, 0x02, - 0x60, 0x3C, 0x12, 0x02, 0x60, 0x54, 0x13, 0x02, - 0x60, 0x20, 0x12, 0x02, 0x60, 0xCC, 0x13, 0x02, - 0x60, 0xE0, 0x13, 0x02, 0x60, 0x00, 0x14, 0x02, - 0x60, 0x64, 0x14, 0x02, 0x60, 0x04, 0x15, 0x02, - 0x60, 0xC8, 0x16, 0x00, 0x60, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x16, 0x02, - 0x60, 0x08, 0x17, 0x00, 0x60, 0x08, 0x17, 0x00, - 0x60, 0x04, 0x17, 0x00, 0x60, 0x00, 0x00, 0x00, - 0x00, 0xD0, 0x16, 0x00, 0x60, 0xD4, 0x16, 0x00, - 0x60, 0x2C, 0x17, 0x00, 0x60, 0x50, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x0C, 0x00, - 0x60, 0xD4, 0x0C, 0x00, 0x60, 0x19, 0x30, 0x00, - 0x00, 0x40, 0x17, 0x00, 0x60, 0x10, 0x01, 0x00, - 0x00, 0xB0, 0x0A, 0x00, 0x60, 0x60, 0x15, 0x02, - 0x60, 0x34, 0x0D, 0x00, 0x60, 0x10, 0x03, 0x02, - 0x28, 0x18, 0x00, 0x02, 0x28, 0x14, 0x03, 0x02, - 0x28, 0xBC, 0x08, 0x00, 0x60, 0x94, 0x15, 0x02, - 0x60, 0xBC, 0x15, 0x02, 0x60, 0xA4, 0x05, 0x00, - 0x60, 0xD8, 0x15, 0x02, 0x60, 0xA8, 0x0B, 0x00, - 0x60, 0xF8, 0x16, 0x00, 0x60, 0xAC, 0x06, 0x00, - 0x60, 0x38, 0x16, 0x02, 0x60, 0x50, 0x16, 0x02, - 0x60, 0xD8, 0x56, 0x04, 0x60, 0x36, 0x41, 0x00, - 0x81, 0xCF, 0x05, 0xB1, 0xCD, 0x05, 0xA2, 0xA0, - 0x03, 0x91, 0xCE, 0x05, 0xA2, 0x4B, 0x00, 0x82, - 0x69, 0x00, 0xE5, 0x01, 0x00, 0xA5, 0x08, 0x00, - 0x25, 0x05, 0x00, 0x25, 0x06, 0x00, 0x25, 0x02, - 0x00, 0xA5, 0x06, 0x00, 0xA1, 0xD0, 0x05, 0xB1, - 0xD1, 0x05, 0x25, 0xDC, 0x2C, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x31, 0xD2, 0x05, 0x21, - 0xD3, 0x05, 0x22, 0x63, 0x75, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x91, 0xD4, 0x05, 0x92, - 0x09, 0x47, 0x26, 0x19, 0x04, 0x26, 0x29, 0x0C, - 0x1D, 0xF0, 0xA1, 0xD5, 0x05, 0xB1, 0xD6, 0x05, - 0xE5, 0xD6, 0x20, 0x1D, 0xF0, 0xA1, 0xD5, 0x05, - 0xB1, 0xD7, 0x05, 0x25, 0xD6, 0x20, 0x1D, 0xF0, - 0x00, 0x36, 0x41, 0x00, 0x81, 0xD9, 0x05, 0x31, - 0xD8, 0x05, 0x21, 0xDA, 0x05, 0x29, 0x43, 0x89, - 0x03, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x31, 0xDB, 0x05, 0x21, 0xDC, 0x05, 0x22, 0x63, - 0x13, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x31, 0xDD, 0x05, 0x21, 0xDE, 0x05, 0x48, 0x03, - 0x49, 0x22, 0x29, 0x03, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x91, 0xE0, 0x05, 0x21, - 0xE2, 0x05, 0x31, 0xDF, 0x05, 0x81, 0xE1, 0x05, - 0x89, 0xC3, 0x29, 0xA3, 0x99, 0xB3, 0x1D, 0xF0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x04, 0x00, 0x8C, 0x17, 0x02, - 0x60, + 0xFF, 0xFF, 0xFF, 0xBF, 0xFD, 0x0C, 0x00, + 0x60, 0xF8, 0x16, 0x00, 0x60, 0xA8, 0x0B, 0x00, + 0x60, 0x08, 0x17, 0x00, 0x60, 0x18, 0x0D, 0x00, + 0x60, 0x00, 0x9E, 0x00, 0x38, 0xDC, 0x0C, 0x00, + 0x60, 0x04, 0x17, 0x00, 0x60, 0x36, 0x41, 0x00, + 0xE5, 0x59, 0x00, 0xA5, 0x65, 0x00, 0xE5, 0x5C, + 0x00, 0x25, 0x66, 0x00, 0x25, 0x58, 0x00, 0x91, + 0xC0, 0x03, 0xA1, 0xC1, 0x03, 0x0C, 0x08, 0x89, + 0x0A, 0x82, 0x49, 0x00, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x61, 0x00, 0x0C, 0x96, 0x91, 0xC2, + 0x03, 0xB1, 0xC3, 0x03, 0x71, 0xC4, 0x03, 0xD8, + 0x1B, 0x16, 0x84, 0x07, 0xC2, 0x0D, 0x4E, 0xC0, + 0xC0, 0x74, 0xE2, 0xA0, 0x71, 0x47, 0x3E, 0x05, + 0x16, 0xDC, 0x0F, 0x47, 0xBE, 0x02, 0x16, 0x4C, + 0x13, 0xF2, 0xA4, 0x6B, 0x26, 0x1C, 0x6E, 0x82, + 0xCC, 0xFE, 0x16, 0x88, 0x07, 0x16, 0x25, 0x05, + 0xC2, 0x0D, 0x4E, 0x16, 0x2C, 0x08, 0x92, 0xCC, + 0xFE, 0x16, 0x59, 0x08, 0x60, 0xAC, 0xC0, 0x16, + 0xAA, 0x10, 0xC2, 0x2D, 0x10, 0xC2, 0x0C, 0x00, + 0xA2, 0xA4, 0x6D, 0x66, 0x6C, 0x02, 0x06, 0x03, + 0x00, 0xAD, 0x0D, 0x65, 0x3B, 0x00, 0xD1, 0xC3, + 0x03, 0xD8, 0x1D, 0x16, 0xAA, 0x07, 0x0C, 0x9C, + 0xE8, 0x07, 0x62, 0x4D, 0x4E, 0xA2, 0x5E, 0x00, + 0xC0, 0xF0, 0x74, 0x60, 0xFF, 0xC0, 0x16, 0xBF, + 0x0D, 0x0C, 0x38, 0xA1, 0xC5, 0x03, 0x91, 0xC6, + 0x03, 0x99, 0x2A, 0x82, 0x4D, 0x4E, 0x0C, 0x2A, + 0xA5, 0xC6, 0x29, 0x1D, 0xF0, 0x16, 0xCD, 0x13, + 0xE8, 0x07, 0xC2, 0xA4, 0x70, 0xC2, 0x5E, 0x00, + 0xC2, 0x0D, 0x4E, 0x06, 0xDE, 0xFF, 0x16, 0xD3, + 0xF8, 0x0C, 0x9C, 0x88, 0x07, 0x62, 0x4D, 0x4E, + 0xF2, 0x58, 0x00, 0x06, 0xE0, 0xFF, 0xC2, 0x1D, + 0x24, 0x37, 0xBC, 0x34, 0x98, 0x07, 0x62, 0x4D, + 0x4E, 0xF2, 0x59, 0x00, 0x46, 0xDD, 0xFF, 0x00, + 0x00, 0x47, 0xBE, 0x02, 0x86, 0xDD, 0xFF, 0x46, + 0x01, 0x00, 0xA2, 0x1D, 0x24, 0x16, 0x3A, 0xF7, + 0xE8, 0x07, 0xC2, 0xA4, 0x6C, 0xC2, 0x5E, 0x00, + 0x62, 0x4D, 0x4E, 0x0C, 0x9C, 0xC6, 0xD8, 0xFF, + 0x00, 0xC2, 0x0D, 0x4E, 0x06, 0xE2, 0xFF, 0x00, + 0x00, 0x16, 0x83, 0xF4, 0xFD, 0x0C, 0xF9, 0x01, + 0xC7, 0xB3, 0x03, 0x8D, 0x03, 0x89, 0x01, 0xA8, + 0xFD, 0xBD, 0x02, 0xC2, 0x21, 0x00, 0xA5, 0x80, + 0x2D, 0xB1, 0xC3, 0x03, 0xD8, 0x1B, 0xA8, 0x01, + 0xC8, 0xFD, 0xAA, 0xCC, 0xC9, 0xFD, 0xD8, 0x1B, + 0x92, 0x1D, 0x24, 0xE2, 0xA0, 0x71, 0xA0, 0x99, + 0xC0, 0x92, 0x5D, 0x24, 0x46, 0xC5, 0xFF, 0x00, + 0x00, 0xF2, 0xA0, 0x72, 0x8D, 0x03, 0x89, 0x01, + 0x40, 0xFF, 0xC0, 0x37, 0xBF, 0x03, 0x8D, 0x0F, + 0x89, 0x01, 0xBD, 0x02, 0xA2, 0x2D, 0x11, 0xC8, + 0x01, 0x4A, 0xAA, 0xE5, 0x7C, 0x2D, 0xE2, 0xA0, + 0x71, 0xC8, 0x01, 0xB1, 0xC3, 0x03, 0xCA, 0x22, + 0xC0, 0x33, 0xC0, 0xD8, 0x1B, 0xCA, 0x44, 0xC2, + 0x0D, 0x4E, 0x46, 0xB3, 0xFF, 0xA1, 0xC2, 0x03, + 0xE5, 0x70, 0x2D, 0xC6, 0xC9, 0xFF, 0xA2, 0x2D, + 0x11, 0x0C, 0x1E, 0xE2, 0x4D, 0x4E, 0x25, 0x5E, + 0x2D, 0xC1, 0xC3, 0x03, 0xC8, 0x1C, 0xBD, 0x0A, + 0xA2, 0x2C, 0x11, 0xB9, 0xBC, 0x4B, 0xAA, 0x25, + 0x5D, 0x2D, 0xD1, 0xC3, 0x03, 0xD2, 0x2D, 0x01, + 0xA2, 0x6D, 0x0C, 0xA2, 0x2D, 0x11, 0x65, 0x2E, + 0x2D, 0xB1, 0xC3, 0x03, 0xD8, 0x1B, 0x0C, 0x0E, + 0xA8, 0xBD, 0xE2, 0x6D, 0x11, 0xAC, 0xCA, 0xE5, + 0x22, 0x2D, 0xB1, 0xC3, 0x03, 0xF8, 0x1B, 0xA2, + 0x6F, 0x10, 0xD8, 0x1B, 0x92, 0x2D, 0x10, 0x16, + 0xE9, 0x04, 0x0C, 0x2C, 0x99, 0xFD, 0xD8, 0x1B, + 0x0C, 0x2A, 0xA2, 0x4D, 0x4E, 0x88, 0xBD, 0x82, + 0x5D, 0x24, 0xE2, 0xA0, 0x71, 0xC0, 0xC0, 0x74, + 0x46, 0x99, 0xFF, 0x00, 0x00, 0xC2, 0x0D, 0x4E, + 0x86, 0xFB, 0xFF, 0x00, 0x00, 0xAD, 0x09, 0x25, + 0x65, 0x2D, 0xA2, 0xA0, 0x72, 0xE5, 0x1E, 0x2D, + 0xB1, 0xC3, 0x03, 0xD8, 0x1B, 0xA2, 0x6D, 0x11, + 0xCC, 0xEA, 0x0C, 0x9C, 0x62, 0x4D, 0x4E, 0x88, + 0x07, 0xF2, 0xA4, 0x6A, 0xF2, 0x58, 0x00, 0x06, + 0x89, 0xFF, 0xC2, 0x0D, 0x4E, 0x86, 0x87, 0xFF, + 0x00, 0x0C, 0x9C, 0x62, 0x4D, 0x4E, 0xA8, 0x07, + 0x92, 0xA4, 0x6F, 0x92, 0x5A, 0x00, 0x06, 0xEC, + 0xFF, 0x36, 0x41, 0x00, 0x42, 0xC2, 0x20, 0x82, + 0xC2, 0x14, 0x91, 0xC7, 0x03, 0x8B, 0xB2, 0x7C, + 0xF3, 0x39, 0xD2, 0x49, 0x92, 0x49, 0x82, 0x89, + 0x62, 0x89, 0x52, 0x99, 0x42, 0xB9, 0x32, 0xB9, + 0x22, 0xA2, 0xC9, 0xFC, 0xA9, 0x72, 0x1D, 0xF0, + 0x00, 0x36, 0x41, 0x00, 0xA2, 0x22, 0x10, 0x16, + 0x2A, 0x00, 0x25, 0x23, 0x2D, 0xA2, 0x22, 0x11, + 0x8C, 0x1A, 0xA5, 0x22, 0x2D, 0xA8, 0xD2, 0x26, + 0x0A, 0x02, 0xE5, 0x56, 0x21, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x20, 0xA2, 0x20, 0x65, + 0xA5, 0x2A, 0xA1, 0xC3, 0x03, 0xA2, 0x2A, 0x01, + 0xA2, 0xCA, 0x14, 0x65, 0x0E, 0x2D, 0xE5, 0x95, + 0x2A, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x31, 0xC3, 0x03, 0xC8, 0x13, 0x0C, 0x05, 0x92, + 0x0C, 0x4E, 0x41, 0xC8, 0x03, 0x82, 0xC9, 0xFD, + 0x16, 0x68, 0x0B, 0x26, 0x49, 0x14, 0x21, 0xC9, + 0x03, 0x26, 0x59, 0x10, 0xA2, 0xC9, 0xFA, 0x16, + 0xFA, 0x07, 0xB2, 0xC9, 0xF9, 0x16, 0x4B, 0x0D, + 0x26, 0x89, 0x49, 0x1D, 0xF0, 0xA2, 0x2C, 0x10, + 0xE8, 0x12, 0xD8, 0x22, 0xD9, 0x03, 0xE2, 0x62, + 0x02, 0x16, 0x9A, 0x00, 0x25, 0x1C, 0x2D, 0xF8, + 0x13, 0x52, 0x6F, 0x10, 0xC8, 0x13, 0xC0, 0x20, + 0x00, 0xB2, 0xA2, 0x00, 0x81, 0xCA, 0x03, 0x82, + 0x64, 0x83, 0xA8, 0xCC, 0xA9, 0xEC, 0xE5, 0xA5, + 0x24, 0xA8, 0x13, 0x0C, 0x69, 0x92, 0x4A, 0x4E, + 0xA2, 0xA2, 0x00, 0xE5, 0x86, 0x2A, 0xA8, 0x13, + 0x8B, 0xAA, 0xA5, 0x0A, 0x00, 0xC0, 0x20, 0x00, + 0x52, 0x64, 0x80, 0x1D, 0xF0, 0xC0, 0x20, 0x00, + 0xC1, 0xCB, 0x03, 0xB2, 0x24, 0x83, 0xC0, 0x20, + 0x00, 0xC0, 0xBB, 0x10, 0xB2, 0x64, 0x83, 0x65, + 0xD5, 0x2A, 0xA8, 0x13, 0x8B, 0xAA, 0xE5, 0x06, + 0x2D, 0xA1, 0xC2, 0x03, 0x25, 0x56, 0x2D, 0x98, + 0x03, 0x16, 0xE9, 0xF8, 0x99, 0x22, 0x59, 0x03, + 0x1D, 0xF0, 0xA2, 0xCC, 0x20, 0xA5, 0x92, 0x2A, + 0x16, 0xFA, 0xF7, 0x22, 0xA0, 0x07, 0xB2, 0x0A, + 0x2C, 0xC2, 0x23, 0x01, 0x07, 0x6B, 0x02, 0x22, + 0x4C, 0x4E, 0x65, 0xA4, 0x24, 0xA8, 0x13, 0xA2, + 0xCA, 0x20, 0xE5, 0x90, 0x2A, 0x56, 0x5A, 0xFE, + 0x1D, 0xF0, 0x52, 0x63, 0x00, 0xA1, 0xCD, 0x03, + 0xB1, 0xCC, 0x03, 0xB2, 0x62, 0x02, 0x65, 0xB5, + 0x2A, 0xC0, 0x20, 0x00, 0x0C, 0x4C, 0xE1, 0xCE, + 0x03, 0xD2, 0x24, 0x83, 0xC0, 0x20, 0x00, 0xA8, + 0x13, 0xE0, 0xDD, 0x20, 0xD2, 0x64, 0x83, 0xC2, + 0x4A, 0x4E, 0xE5, 0x0C, 0x00, 0xAD, 0x02, 0xA5, + 0x9A, 0x29, 0x1D, 0xF0, 0x00, 0xA1, 0xCF, 0x03, + 0x25, 0x52, 0x2D, 0xC0, 0x20, 0x00, 0xA8, 0x13, + 0xF1, 0xD0, 0x03, 0xF2, 0x64, 0x83, 0x65, 0x1B, + 0x00, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x31, 0xC3, 0x03, 0x82, 0x23, 0x01, 0x71, 0xD1, + 0x03, 0x82, 0x28, 0x0E, 0x62, 0xA0, 0x00, 0x16, + 0x68, 0x05, 0xE5, 0x76, 0x2A, 0x4D, 0x0A, 0x16, + 0x2A, 0x05, 0xA8, 0x13, 0x52, 0x14, 0x15, 0xA8, + 0xEA, 0x57, 0xBA, 0x01, 0x5D, 0x0A, 0xB1, 0xD2, + 0x03, 0xC8, 0x24, 0x0C, 0x0D, 0xF1, 0xD3, 0x03, + 0x50, 0xE0, 0xF4, 0xE2, 0x54, 0x14, 0x52, 0xC4, + 0x10, 0xAD, 0x05, 0xE5, 0x81, 0x21, 0x62, 0x44, + 0x2C, 0xD8, 0x13, 0xC2, 0x14, 0x14, 0xB8, 0xED, + 0xC0, 0xBB, 0xC0, 0xB9, 0xED, 0xCC, 0x8B, 0x79, + 0x34, 0x0C, 0x1D, 0xD2, 0x44, 0x2C, 0xD2, 0x23, + 0x01, 0xAD, 0x05, 0xB8, 0xDD, 0x0C, 0x1C, 0x25, + 0xAD, 0x21, 0xE8, 0x13, 0xE8, 0xEE, 0x56, 0x8E, + 0xFA, 0x1D, 0xF0, 0x00, 0x00, 0xAD, 0x02, 0x65, + 0x72, 0x2A, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, + 0xB2, 0xC2, 0xF0, 0xA2, 0xC3, 0x20, 0xA5, 0x7F, + 0x2A, 0xA2, 0xC3, 0x14, 0xE5, 0xF3, 0x2C, 0x1D, + 0xF0, 0x36, 0x41, 0x00, 0x0C, 0x0A, 0xBD, 0x02, + 0xC1, 0xD4, 0x03, 0x65, 0x9B, 0x21, 0xA9, 0xD2, + 0x26, 0x0A, 0x05, 0x0C, 0x02, 0x1D, 0xF0, 0x00, + 0x00, 0x22, 0xA4, 0x6E, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0xA2, 0xA0, 0x03, 0xB1, + 0xD5, 0x03, 0xE5, 0xEA, 0x2C, 0x92, 0xA0, 0x60, + 0x81, 0xC8, 0x03, 0xB8, 0xB2, 0xA2, 0x22, 0x10, + 0xA9, 0xF2, 0xB2, 0x52, 0x26, 0xB2, 0x52, 0x25, + 0x0C, 0x8B, 0xC0, 0x20, 0x00, 0xF2, 0x28, 0x81, + 0xC0, 0x20, 0x00, 0xE8, 0xF2, 0x90, 0xFF, 0x20, + 0xF2, 0x68, 0x81, 0xE2, 0x0E, 0x00, 0xC0, 0x20, + 0x00, 0xC8, 0xF2, 0xF1, 0xD6, 0x03, 0x1B, 0xCC, + 0xE2, 0x5F, 0x80, 0xD2, 0x12, 0x25, 0xC9, 0xF2, + 0x0B, 0xDD, 0xD2, 0x52, 0x25, 0x80, 0x61, 0x00, + 0x9D, 0x08, 0xA0, 0xE4, 0x03, 0xB0, 0xAA, 0x20, + 0xA0, 0xE4, 0x13, 0x80, 0xE6, 0x13, 0x10, 0x20, + 0x00, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x61, 0x00, + 0xC0, 0x20, 0x00, 0xC1, 0xD6, 0x03, 0xF1, 0xC8, + 0x03, 0xE1, 0xC3, 0x03, 0xA2, 0x2F, 0x82, 0xB8, + 0x1E, 0x17, 0x6A, 0x14, 0x92, 0x1B, 0x26, 0x16, + 0xE9, 0x00, 0x82, 0xC9, 0xFF, 0xC0, 0x20, 0x00, + 0xD2, 0x1C, 0x80, 0xD2, 0x51, 0x00, 0x82, 0x5B, + 0x26, 0x92, 0x1B, 0x25, 0x07, 0xEA, 0x07, 0x8C, + 0xA9, 0x82, 0x0B, 0x4E, 0x26, 0x48, 0x41, 0x8C, + 0x29, 0x1D, 0xF0, 0x00, 0x00, 0x92, 0x1B, 0x26, + 0x56, 0x59, 0xFF, 0xC0, 0x20, 0x00, 0x0C, 0x5D, + 0x92, 0xAF, 0x9F, 0x82, 0x2F, 0x81, 0xC0, 0x20, + 0x00, 0x90, 0x88, 0x10, 0x82, 0x6F, 0x81, 0x7C, + 0x7F, 0xA0, 0x61, 0x00, 0xCD, 0x0A, 0xE0, 0xE4, + 0x03, 0xF0, 0xEE, 0x10, 0xE0, 0xE4, 0x13, 0xA0, + 0xE6, 0x13, 0x10, 0x20, 0x00, 0xD2, 0x4B, 0x4E, + 0xA2, 0xCB, 0x14, 0xE5, 0xE3, 0x2C, 0x1D, 0xF0, + 0x00, 0xD8, 0xFB, 0xD2, 0x0D, 0x00, 0xC0, 0x20, + 0x00, 0xA8, 0xFB, 0xD2, 0x5C, 0x80, 0x1B, 0xAA, + 0xA9, 0xFB, 0xB8, 0x1E, 0x92, 0x1B, 0x25, 0x0B, + 0x99, 0x90, 0x90, 0xF4, 0x92, 0x5B, 0x25, 0x06, + 0xE7, 0xFF, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x92, 0xA0, 0x06, 0xB1, 0xC8, 0x03, 0xC0, 0x20, + 0x00, 0x82, 0x2B, 0x82, 0x0C, 0x0A, 0x17, 0x68, + 0x0B, 0x92, 0xC9, 0xFF, 0xC0, 0x20, 0x00, 0xC2, + 0x2B, 0x80, 0x56, 0x89, 0xFE, 0xC0, 0x20, 0x00, + 0xA2, 0xC2, 0x14, 0x0C, 0x8D, 0xE2, 0xA0, 0x04, + 0xE2, 0x6B, 0x84, 0xD2, 0x42, 0x4E, 0x25, 0xDE, + 0x2C, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x31, 0xD7, 0x03, 0x21, 0xD8, 0x03, 0x22, 0x63, + 0x75, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, + 0xA1, 0xD9, 0x03, 0xB1, 0xDA, 0x03, 0xC1, 0xDB, + 0x03, 0xE5, 0x37, 0x2D, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x16, 0xA5, 0x01, 0x20, + 0x61, 0x00, 0x25, 0xA4, 0xFF, 0x20, 0xE6, 0x13, + 0x10, 0x20, 0x00, 0xA2, 0xA0, 0x00, 0x65, 0x72, + 0x29, 0xA1, 0xDC, 0x03, 0xB1, 0xDD, 0x03, 0xE5, + 0xFF, 0x2C, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, + 0xA1, 0xDE, 0x03, 0xB1, 0xDE, 0x03, 0x65, 0xFC, + 0x20, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, + 0xCD, 0x04, 0x81, 0xDF, 0x03, 0xBD, 0x03, 0x88, + 0x08, 0xAD, 0x02, 0xCC, 0xF8, 0x8C, 0xD3, 0xD1, + 0xC9, 0x03, 0xF1, 0xE0, 0x03, 0x98, 0x1D, 0xE8, + 0x2D, 0xE9, 0x0F, 0x92, 0x6D, 0x02, 0xE5, 0x65, + 0x29, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, + 0xC1, 0xE0, 0x03, 0xAD, 0x02, 0x98, 0x0C, 0x0C, + 0x0B, 0x8C, 0x59, 0x81, 0xC9, 0x03, 0xB9, 0x0C, + 0x99, 0x28, 0xE5, 0x70, 0x29, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0xD1, 0xE2, 0x03, 0x91, + 0xE3, 0x03, 0xB0, 0x82, 0x11, 0xA1, 0xE1, 0x03, + 0xB2, 0xAE, 0xF0, 0xBA, 0xAA, 0xAA, 0xA8, 0x9A, + 0x88, 0xC8, 0x0A, 0xC0, 0x20, 0x00, 0xB8, 0x7C, + 0xC0, 0x20, 0x00, 0xD0, 0xBB, 0x10, 0xB9, 0x7C, + 0x82, 0x08, 0x7F, 0x0C, 0x09, 0x8C, 0x18, 0xE5, + 0x5B, 0x21, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, + 0x21, 0xE4, 0x03, 0x31, 0xE5, 0x03, 0x28, 0x22, + 0x29, 0x03, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, + 0x21, 0xE6, 0x03, 0x88, 0x02, 0x27, 0x98, 0x02, + 0x1D, 0xF0, 0x00, 0x20, 0xA2, 0x20, 0x25, 0x08, + 0x00, 0xAD, 0x02, 0xE5, 0xC5, 0x20, 0x1D, 0xF0, + 0x00, 0x36, 0x41, 0x00, 0x20, 0x61, 0x00, 0xA1, + 0xE6, 0x03, 0xE5, 0xC4, 0x20, 0xA5, 0x0B, 0x24, + 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, 0x1D, 0xF0, + 0x00, 0x36, 0x41, 0x00, 0x41, 0xE7, 0x03, 0x21, + 0xE8, 0x03, 0xC0, 0x20, 0x00, 0x32, 0x22, 0x81, + 0x98, 0x54, 0x88, 0x34, 0x30, 0x99, 0x20, 0x99, + 0x54, 0x87, 0x83, 0x39, 0x0C, 0x1C, 0xB2, 0xA0, + 0x38, 0xA2, 0x24, 0x04, 0xC0, 0x20, 0x00, 0xB0, + 0xAA, 0x10, 0xA2, 0x62, 0x80, 0xC0, 0x20, 0x00, + 0xD2, 0x22, 0x81, 0xD0, 0xE0, 0x04, 0x07, 0xED, + 0xF3, 0xC0, 0x20, 0x00, 0xB1, 0xE9, 0x03, 0x32, + 0x62, 0x81, 0xC0, 0x20, 0x00, 0xB8, 0x0B, 0xA1, + 0xEA, 0x03, 0x1B, 0xBB, 0xB9, 0x4A, 0x4B, 0xAA, + 0xA5, 0xBD, 0x20, 0x1D, 0xF0, 0x00, 0x0C, 0x0C, + 0xC9, 0x34, 0xE5, 0xC4, 0x21, 0xC6, 0xEE, 0xFF, + 0x00, 0x36, 0x41, 0x00, 0x20, 0x61, 0x00, 0x3C, + 0x8A, 0x0C, 0x0B, 0x65, 0x08, 0x24, 0x20, 0xE6, + 0x13, 0x10, 0x20, 0x00, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x1F, 0x00, 0x00, 0x00, 0xD0, 0x0F, 0x02, + 0x60, 0xD8, 0x11, 0x02, 0x60, 0x00, 0x12, 0x02, + 0x60, 0x3C, 0x12, 0x02, 0x60, 0x54, 0x13, 0x02, + 0x60, 0x20, 0x12, 0x02, 0x60, 0xCC, 0x13, 0x02, + 0x60, 0xE0, 0x13, 0x02, 0x60, 0x00, 0x14, 0x02, + 0x60, 0x64, 0x14, 0x02, 0x60, 0x04, 0x15, 0x02, + 0x60, 0xC8, 0x16, 0x00, 0x60, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x16, 0x02, + 0x60, 0x08, 0x17, 0x00, 0x60, 0x08, 0x17, 0x00, + 0x60, 0x04, 0x17, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x00, 0xD0, 0x16, 0x00, 0x60, 0xD4, 0x16, 0x00, + 0x60, 0x2C, 0x17, 0x00, 0x60, 0x50, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x0C, 0x00, + 0x60, 0xD4, 0x0C, 0x00, 0x60, 0x19, 0x30, 0x00, + 0x00, 0x40, 0x17, 0x00, 0x60, 0x10, 0x01, 0x00, + 0x00, 0xB0, 0x0A, 0x00, 0x60, 0x60, 0x15, 0x02, + 0x60, 0x34, 0x0D, 0x00, 0x60, 0x10, 0x03, 0x02, + 0x28, 0x18, 0x00, 0x02, 0x28, 0x14, 0x03, 0x02, + 0x28, 0xBC, 0x08, 0x00, 0x60, 0x94, 0x15, 0x02, + 0x60, 0xBC, 0x15, 0x02, 0x60, 0xA4, 0x05, 0x00, + 0x60, 0xD8, 0x15, 0x02, 0x60, 0xA8, 0x0B, 0x00, + 0x60, 0xF8, 0x16, 0x00, 0x60, 0xAC, 0x06, 0x00, + 0x60, 0x38, 0x16, 0x02, 0x60, 0x50, 0x16, 0x02, + 0x60, 0xD8, 0x56, 0x04, 0x60, 0x36, 0x41, 0x00, + 0x81, 0xCF, 0x05, 0xB1, 0xCD, 0x05, 0xA2, 0xA0, + 0x03, 0x91, 0xCE, 0x05, 0xA2, 0x4B, 0x00, 0x82, + 0x69, 0x00, 0xE5, 0x01, 0x00, 0xA5, 0x08, 0x00, + 0x25, 0x05, 0x00, 0x25, 0x06, 0x00, 0x25, 0x02, + 0x00, 0xA5, 0x06, 0x00, 0xA1, 0xD0, 0x05, 0xB1, + 0xD1, 0x05, 0x25, 0xDC, 0x2C, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x31, 0xD2, 0x05, 0x21, + 0xD3, 0x05, 0x22, 0x63, 0x75, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x91, 0xD4, 0x05, 0x92, + 0x09, 0x47, 0x26, 0x19, 0x04, 0x26, 0x29, 0x0C, + 0x1D, 0xF0, 0xA1, 0xD5, 0x05, 0xB1, 0xD6, 0x05, + 0xE5, 0xD6, 0x20, 0x1D, 0xF0, 0xA1, 0xD5, 0x05, + 0xB1, 0xD7, 0x05, 0x25, 0xD6, 0x20, 0x1D, 0xF0, + 0x00, 0x36, 0x41, 0x00, 0x81, 0xD9, 0x05, 0x31, + 0xD8, 0x05, 0x21, 0xDA, 0x05, 0x29, 0x43, 0x89, + 0x03, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x31, 0xDB, 0x05, 0x21, 0xDC, 0x05, 0x22, 0x63, + 0x13, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x31, 0xDD, 0x05, 0x21, 0xDE, 0x05, 0x48, 0x03, + 0x49, 0x22, 0x29, 0x03, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x91, 0xE0, 0x05, 0x21, + 0xE2, 0x05, 0x31, 0xDF, 0x05, 0x81, 0xE1, 0x05, + 0x89, 0xC3, 0x29, 0xA3, 0x99, 0xB3, 0x1D, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x04, 0x00, 0x8C, 0x17, 0x02, + 0x60, }; static const unsigned char vfs301_06_2[] = { /* 1905 B */ - 0x06, 0x00, 0x00, 0x64, 0x07, 0x00, 0x0F, 0x00, - 0x60, 0xD8, 0x0C, 0x00, 0x60, 0xD4, 0x0C, 0x00, - 0x60, 0x50, 0x15, 0x00, 0x60, 0x20, 0x0E, 0x00, - 0x60, 0xFC, 0xFF, 0x00, 0x00, 0x30, 0x15, 0x00, - 0x60, 0xB0, 0x0A, 0x00, 0x60, 0x58, 0xB3, 0x04, - 0x60, 0x84, 0x05, 0x00, 0x60, 0xA4, 0xED, 0x04, - 0x60, 0x8C, 0x04, 0x00, 0x00, 0x00, 0x0F, 0x00, - 0x60, 0x60, 0x06, 0x00, 0x00, 0xA0, 0x0A, 0x00, - 0x60, 0xD0, 0x38, 0x04, 0x60, 0xB4, 0x39, 0x04, - 0x60, 0x58, 0xB4, 0x04, 0x60, 0xFC, 0x0C, 0x00, - 0x60, 0x20, 0x15, 0x00, 0x60, 0xC8, 0x0D, 0x00, - 0x60, 0x9C, 0x0B, 0x00, 0x60, 0xFC, 0x14, 0x00, - 0x60, 0xCC, 0x08, 0x00, 0x60, 0x68, 0x0A, 0x00, - 0x60, 0x4C, 0x3F, 0x04, 0x60, 0xC0, 0x0D, 0x00, - 0x60, 0x04, 0x15, 0x00, 0x60, 0x18, 0x0D, 0x00, - 0x60, 0x00, 0x9E, 0x00, 0x38, 0xDC, 0x0C, 0x00, - 0x60, 0x00, 0x15, 0x00, 0x60, 0x36, 0x41, 0x00, - 0x25, 0x37, 0x00, 0x65, 0x3A, 0x00, 0xA5, 0x4C, - 0x00, 0xE5, 0x48, 0x00, 0x65, 0x35, 0x00, 0x91, - 0xC0, 0x03, 0xA1, 0xC1, 0x03, 0x0C, 0x08, 0x89, - 0x0A, 0x82, 0x49, 0x00, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x31, 0xC2, 0x03, 0x38, - 0x03, 0x8C, 0x73, 0x88, 0x23, 0x66, 0x28, 0x03, - 0x0C, 0x39, 0x99, 0x23, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x31, 0xC3, 0x03, 0x0C, - 0x02, 0x22, 0x43, 0x00, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0xBD, 0x02, 0x21, 0xC2, - 0x03, 0x28, 0x02, 0x1C, 0x8C, 0xCB, 0xA2, 0xA5, - 0x8F, 0x2D, 0xD1, 0xC4, 0x03, 0x2C, 0x0B, 0x92, - 0x12, 0x11, 0x0C, 0x1C, 0xDC, 0x79, 0xA2, 0x12, - 0x0F, 0x92, 0x12, 0x0E, 0xA0, 0xA0, 0xE4, 0x90, - 0xAA, 0xC0, 0xA2, 0xCA, 0xC2, 0xA0, 0xA1, 0x21, - 0xAA, 0x99, 0x8B, 0x99, 0x92, 0x52, 0x11, 0xB2, - 0x52, 0x13, 0xC9, 0x22, 0xD0, 0xD9, 0x10, 0xD2, - 0x52, 0x11, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, - 0xD8, 0x22, 0x31, 0xC2, 0x03, 0x0C, 0x1E, 0x38, - 0x03, 0x0C, 0x0C, 0xAD, 0x03, 0xF2, 0x13, 0x13, - 0xB2, 0x13, 0x10, 0xF0, 0xCE, 0x83, 0xDA, 0xBB, - 0x25, 0x17, 0x00, 0x0C, 0x45, 0xA8, 0x23, 0x92, - 0x13, 0x13, 0x0C, 0x04, 0x8C, 0x69, 0x0B, 0x99, - 0x90, 0x90, 0xF4, 0x92, 0x53, 0x13, 0xF6, 0x8A, - 0x2F, 0xB1, 0xC5, 0x03, 0xB0, 0xBA, 0xA0, 0xB8, - 0x0B, 0xA0, 0x0B, 0x00, 0xC8, 0x22, 0xB2, 0x13, - 0x11, 0xAD, 0x03, 0xCA, 0xBB, 0x65, 0x21, 0x00, - 0xD2, 0x13, 0x06, 0xF1, 0xC3, 0x03, 0xD7, 0x3A, - 0x0F, 0x0C, 0x29, 0x92, 0x4F, 0x00, 0xE2, 0x13, - 0x0F, 0xE0, 0xEF, 0x04, 0x16, 0xBE, 0x10, 0x99, - 0x23, 0x0C, 0x14, 0x2D, 0x04, 0x1D, 0xF0, 0x49, - 0x23, 0x0C, 0x24, 0x06, 0xFD, 0xFF, 0xAD, 0x03, - 0xE5, 0x1B, 0x00, 0x82, 0x13, 0x09, 0xB2, 0x13, - 0x08, 0x87, 0x3A, 0x02, 0x06, 0x24, 0x00, 0xC8, - 0x22, 0xB2, 0x13, 0x11, 0xAD, 0x03, 0xCA, 0xBB, - 0x65, 0x1D, 0x00, 0xD2, 0x13, 0x07, 0xD7, 0x3A, - 0x02, 0xC6, 0x36, 0x00, 0xE2, 0x13, 0x14, 0x0B, - 0xEE, 0xE0, 0xE0, 0xF4, 0xE2, 0x53, 0x14, 0x56, - 0xEE, 0x0D, 0x0C, 0x24, 0x0C, 0x7F, 0xF9, 0x23, - 0xC6, 0xED, 0xFF, 0xAD, 0x03, 0xE5, 0x17, 0x00, - 0x82, 0x13, 0x08, 0x87, 0x3A, 0x6A, 0x59, 0x23, - 0x42, 0x53, 0x16, 0x92, 0x13, 0x0A, 0x92, 0x53, - 0x14, 0x0C, 0x04, 0x06, 0xE7, 0xFF, 0xAD, 0x03, - 0x65, 0x16, 0x00, 0xB2, 0x13, 0x08, 0xB7, 0x3A, - 0x29, 0xC2, 0x13, 0x14, 0x0B, 0xCC, 0xC0, 0xC0, - 0xF4, 0xC2, 0x53, 0x14, 0xEC, 0xBC, 0x0C, 0x6D, - 0xE2, 0x13, 0x0B, 0xE2, 0x53, 0x14, 0xD9, 0x23, - 0xC6, 0x07, 0x00, 0xDC, 0xC9, 0x59, 0x23, 0x42, - 0x53, 0x16, 0xF2, 0x13, 0x0A, 0xF2, 0x53, 0x14, - 0xC6, 0x03, 0x00, 0x0C, 0x58, 0x92, 0x13, 0x0D, - 0xA2, 0x13, 0x0C, 0xA2, 0x53, 0x14, 0x92, 0x53, - 0x15, 0x89, 0x23, 0x0C, 0x04, 0x86, 0xD4, 0xFF, - 0xB7, 0x3A, 0x05, 0xC2, 0x13, 0x0B, 0xC2, 0x53, - 0x14, 0x42, 0x53, 0x16, 0x0C, 0x04, 0x46, 0xD0, - 0xFF, 0x92, 0x13, 0x15, 0x66, 0x19, 0x09, 0x0C, - 0x34, 0x0B, 0xD9, 0xD2, 0x53, 0x15, 0x46, 0xCC, - 0xFF, 0xCC, 0x39, 0x0C, 0x14, 0x86, 0x01, 0x00, - 0x0C, 0x04, 0x0B, 0xE9, 0xE2, 0x53, 0x15, 0xC8, - 0x22, 0xB2, 0x13, 0x11, 0xAD, 0x03, 0xCA, 0xBB, - 0x65, 0x11, 0x00, 0xD2, 0x13, 0x07, 0xD7, 0xBA, - 0x10, 0xE2, 0x13, 0x14, 0x0B, 0xEE, 0xE0, 0xE0, - 0xF4, 0xE2, 0x53, 0x14, 0xE0, 0x45, 0x83, 0x06, - 0xC0, 0xFF, 0xF2, 0x13, 0x0D, 0xF2, 0x53, 0x14, - 0xC6, 0xBD, 0xFF, 0x0C, 0x39, 0x86, 0xBB, 0xFF, - 0x82, 0x13, 0x06, 0x87, 0x3A, 0x05, 0x92, 0x13, - 0x0B, 0x92, 0x53, 0x14, 0x0C, 0x04, 0x46, 0xB8, - 0xFF, 0x0C, 0x04, 0x06, 0xB7, 0xFF, 0x00, 0x00, - 0x00, 0x36, 0x61, 0x00, 0xB2, 0xA0, 0x94, 0xA2, - 0xC2, 0x34, 0x92, 0xC2, 0x54, 0x99, 0x01, 0xA9, - 0x11, 0xBC, 0xB4, 0x68, 0x11, 0x5D, 0x09, 0x1C, - 0x04, 0x72, 0x12, 0x12, 0x82, 0xA0, 0x94, 0xC0, - 0x77, 0x11, 0x7A, 0x72, 0x8A, 0x77, 0x82, 0x16, - 0x00, 0xB2, 0x07, 0x00, 0x1B, 0x77, 0xAD, 0x0B, - 0xB0, 0x88, 0xC0, 0x82, 0x56, 0x00, 0x2B, 0x66, - 0x65, 0x96, 0x2D, 0x98, 0x05, 0x0B, 0x44, 0xA0, - 0x99, 0xC0, 0x99, 0x05, 0x4B, 0x55, 0x56, 0xC4, - 0xFD, 0x98, 0x01, 0xA8, 0x11, 0xB2, 0xA0, 0x94, - 0x5D, 0x09, 0x6D, 0x0A, 0x72, 0x12, 0x12, 0x1C, - 0x04, 0xC0, 0x77, 0x11, 0x7A, 0x72, 0xBA, 0x77, - 0xD2, 0x03, 0x01, 0xE2, 0x03, 0x03, 0xC2, 0x03, - 0x02, 0xB2, 0x03, 0x00, 0xEA, 0xCC, 0xDA, 0xBB, - 0xCA, 0xBB, 0xB0, 0xB2, 0x41, 0xAD, 0x0B, 0xB2, - 0x47, 0x00, 0x82, 0x16, 0x00, 0x1B, 0x77, 0xBA, - 0x88, 0x82, 0x56, 0x00, 0x2B, 0x66, 0x65, 0x91, - 0x2D, 0x8B, 0x33, 0xF8, 0x05, 0x0B, 0x44, 0xAA, - 0xFF, 0xF9, 0x05, 0x4B, 0x55, 0x56, 0x74, 0xFC, - 0x82, 0x12, 0x12, 0x1B, 0x88, 0x80, 0x80, 0x44, - 0x82, 0x52, 0x12, 0x1D, 0xF0, 0x36, 0x41, 0x00, - 0x32, 0xC2, 0x34, 0x1C, 0x05, 0x0C, 0x04, 0xB2, - 0x13, 0x00, 0xAD, 0x0B, 0xA5, 0x8E, 0x2D, 0x2B, - 0x33, 0x0B, 0x55, 0xA0, 0x95, 0x41, 0x82, 0x22, - 0x15, 0x4B, 0x22, 0x90, 0x88, 0xC0, 0x80, 0x85, - 0x41, 0x8A, 0x44, 0x56, 0x05, 0xFE, 0x40, 0x24, - 0x41, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x1C, 0x07, 0x0C, 0x06, 0x0C, 0x05, 0xB2, 0xC3, - 0x81, 0x42, 0x03, 0x00, 0xB2, 0x0B, 0x7E, 0xC2, - 0x03, 0x01, 0x47, 0xBB, 0x0C, 0x47, 0xBC, 0x11, - 0x4D, 0x0B, 0xC7, 0xBB, 0x0C, 0x4D, 0x0C, 0xC6, - 0x01, 0x00, 0x47, 0x3C, 0x04, 0xC7, 0xBB, 0x01, - 0x4D, 0x0B, 0xAD, 0x04, 0xBD, 0x04, 0x65, 0x89, - 0x2D, 0xAA, 0x66, 0x5A, 0x54, 0x0B, 0x77, 0x4B, - 0x33, 0xB2, 0xC3, 0x81, 0x56, 0x97, 0xFC, 0xAD, - 0x05, 0xBD, 0x05, 0x25, 0x88, 0x2D, 0xD2, 0x12, - 0x16, 0xA0, 0x94, 0x41, 0x90, 0x96, 0xC0, 0xD0, - 0xCD, 0xF0, 0x90, 0x94, 0x41, 0x90, 0xE3, 0x41, - 0xC0, 0xC3, 0x21, 0xEA, 0xCC, 0xD0, 0x9C, 0x93, - 0x92, 0x52, 0x16, 0x2D, 0x09, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x31, 0xC6, 0x03, 0x21, - 0xC7, 0x03, 0x22, 0x63, 0x75, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0xA1, 0xC8, 0x03, 0xB1, - 0xC9, 0x03, 0xC1, 0xCA, 0x03, 0xA5, 0x5D, 0x2D, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x9C, 0x85, 0x20, 0x61, 0x00, 0xE5, 0xC6, 0xFF, - 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, 0x0C, 0x0A, - 0x65, 0x98, 0x29, 0xA1, 0xCB, 0x03, 0xB1, 0xCC, - 0x03, 0xA5, 0x25, 0x2D, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x0C, 0xBB, 0x31, 0xC6, - 0x03, 0x21, 0xD0, 0x03, 0x81, 0xCF, 0x03, 0x91, - 0xCD, 0x03, 0xA1, 0xCE, 0x03, 0xA9, 0xF9, 0x82, - 0x69, 0x19, 0x22, 0x63, 0x6B, 0xB2, 0x59, 0x1C, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x21, 0xD1, 0x03, 0x88, 0x22, 0x37, 0x68, 0x0E, - 0xA1, 0xD2, 0x03, 0xA5, 0x4D, 0x2D, 0x98, 0x22, - 0x6C, 0x7A, 0xA0, 0x99, 0x10, 0x99, 0x22, 0xE5, - 0x79, 0x22, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, - 0xCD, 0x04, 0xBD, 0x03, 0xAD, 0x02, 0xDD, 0x05, - 0x25, 0x0E, 0x2A, 0xAC, 0x15, 0x81, 0xD3, 0x03, - 0xA1, 0xD4, 0x03, 0x88, 0x08, 0x91, 0xD1, 0x03, - 0x82, 0x08, 0x02, 0x98, 0x29, 0xB6, 0x28, 0x06, - 0x91, 0xD5, 0x03, 0x99, 0x2A, 0x1D, 0xF0, 0x37, - 0x69, 0x05, 0x91, 0xD6, 0x03, 0x86, 0xFC, 0xFF, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0xBD, 0x03, 0xAD, 0x02, 0xCD, 0x04, 0xDD, 0x05, - 0x1C, 0x8E, 0x25, 0x71, 0x22, 0xBC, 0x16, 0x82, - 0x12, 0x1A, 0x5A, 0xA4, 0xEC, 0xA8, 0x1C, 0x79, - 0xA7, 0x39, 0x28, 0x92, 0xA4, 0x21, 0x92, 0x52, - 0x1A, 0x06, 0x05, 0x00, 0xA1, 0xD2, 0x03, 0x25, - 0x42, 0x2D, 0xA8, 0x82, 0xE5, 0xBF, 0xFF, 0xB1, - 0xD1, 0x03, 0xA8, 0x2B, 0x30, 0xAA, 0x20, 0xA9, - 0x2B, 0xA8, 0x82, 0xA5, 0x05, 0x2D, 0x0C, 0x0B, - 0xB9, 0x82, 0x1D, 0xF0, 0x1C, 0x83, 0xA7, 0xB3, - 0xDA, 0x92, 0xA4, 0x22, 0x86, 0xF3, 0xFF, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x8C, 0x36, 0x0C, 0x03, - 0x32, 0x52, 0x1A, 0x1D, 0xF0, 0x36, 0x41, 0x00, - 0xA5, 0xB9, 0xFF, 0xAD, 0x02, 0x81, 0xD6, 0x03, - 0x89, 0x22, 0xE5, 0x8C, 0x29, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x31, 0xD7, 0x03, 0x21, - 0xD8, 0x03, 0x29, 0x13, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x81, 0xD9, 0x03, 0x30, - 0x61, 0x00, 0x88, 0x08, 0x82, 0x08, 0x10, 0x26, - 0x48, 0x07, 0xAD, 0x02, 0xA5, 0x54, 0x28, 0x06, - 0x01, 0x00, 0x0C, 0x0A, 0xE5, 0xED, 0x20, 0x30, - 0xE6, 0x13, 0x10, 0x20, 0x00, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x21, 0xDA, 0x03, 0x88, - 0x02, 0x27, 0x18, 0x09, 0xAD, 0x02, 0xE5, 0x07, - 0x00, 0xAD, 0x02, 0xE5, 0xE2, 0x20, 0x1D, 0xF0, - 0x00, 0x36, 0x41, 0x00, 0x20, 0x61, 0x00, 0xA1, - 0xDA, 0x03, 0xE5, 0xE1, 0x20, 0xA5, 0x28, 0x24, - 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, 0x1D, 0xF0, - 0x00, 0x36, 0x41, 0x00, 0x41, 0xDB, 0x03, 0x21, - 0xDC, 0x03, 0xC0, 0x20, 0x00, 0x32, 0x22, 0x81, - 0x98, 0x54, 0x88, 0x34, 0x30, 0x99, 0x20, 0x99, - 0x54, 0x87, 0x03, 0x06, 0x0C, 0x0A, 0xA9, 0x34, - 0xA5, 0xE5, 0x21, 0x0C, 0x1D, 0x3C, 0x8C, 0xB8, - 0x44, 0xC0, 0x20, 0x00, 0xC0, 0xBB, 0x10, 0xB2, - 0x62, 0x80, 0xC0, 0x20, 0x00, 0xE2, 0x22, 0x81, - 0xE0, 0xF0, 0x04, 0x07, 0xEE, 0xF3, 0xC0, 0x20, - 0x00, 0xB1, 0xDD, 0x03, 0x32, 0x62, 0x81, 0xC0, - 0x20, 0x00, 0xB8, 0x0B, 0xA1, 0xDE, 0x03, 0x1B, - 0xBB, 0xB9, 0x4A, 0x4B, 0xAA, 0x25, 0xDA, 0x20, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x20, 0x61, 0x00, 0x3C, 0x8A, 0x0C, 0x0B, 0xA5, - 0x25, 0x24, 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0xB8, 0x0F, 0x02, - 0x60, 0xC0, 0x0F, 0x02, 0x60, 0x04, 0x14, 0x02, - 0x60, 0xDC, 0x14, 0x02, 0x60, 0x04, 0x15, 0x00, - 0x60, 0x04, 0x15, 0x00, 0x60, 0x00, 0x15, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xF4, 0x14, 0x00, 0x60, 0xF8, 0x14, 0x00, - 0x60, 0x50, 0x15, 0x00, 0x60, 0x94, 0x02, 0x00, - 0x00, 0x78, 0x10, 0x02, 0x60, 0x53, 0x10, 0x02, - 0x60, 0x78, 0x10, 0x02, 0x60, 0x02, 0x11, 0x02, - 0x60, 0xDD, 0x10, 0x02, 0x60, 0xC2, 0x10, 0x02, - 0x60, 0x85, 0x10, 0x02, 0x60, 0x7E, 0x10, 0x02, - 0x60, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x0C, 0x00, - 0x60, 0xD4, 0x0C, 0x00, 0x60, 0x10, 0x30, 0x02, - 0x00, 0x60, 0x15, 0x00, 0x60, 0x00, 0x01, 0x00, - 0x00, 0xB0, 0x0A, 0x00, 0x60, 0x04, 0x13, 0x02, - 0x60, 0xA0, 0x0A, 0x00, 0x60, 0xA4, 0x13, 0x02, - 0x60, 0xF8, 0x13, 0x02, 0x60, 0x6C, 0x13, 0x02, - 0x60, 0x6C, 0x06, 0x00, 0x60, 0x14, 0x10, 0x02, - 0x60, 0xF4, 0x05, 0x00, 0x60, 0x4C, 0x13, 0x02, - 0x60, 0x68, 0x0A, 0x00, 0x60, 0x28, 0x8F, 0x04, - 0x60, 0x48, 0x08, 0x00, 0x60, 0x28, 0x14, 0x02, - 0x60, 0xAC, 0x06, 0x00, 0x60, 0x68, 0x14, 0x02, - 0x60, 0x80, 0x14, 0x02, 0x60, 0xD8, 0x56, 0x04, - 0x60, 0x36, 0x41, 0x00, 0x81, 0x57, 0x05, 0xB1, - 0x55, 0x05, 0x0C, 0x3A, 0x91, 0x56, 0x05, 0xA2, - 0x4B, 0x00, 0x89, 0x09, 0xE5, 0x01, 0x00, 0xE5, - 0x05, 0x00, 0xA5, 0x06, 0x00, 0x65, 0x07, 0x00, - 0x25, 0x02, 0x00, 0xA1, 0x58, 0x05, 0xB1, 0x59, - 0x05, 0x25, 0xFA, 0x2C, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x31, 0x5A, 0x05, 0x21, - 0x5B, 0x05, 0x22, 0x63, 0x75, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x0C, 0x8F, 0xB1, 0x5A, - 0x05, 0xA1, 0x5F, 0x05, 0x91, 0x60, 0x05, 0x81, - 0x61, 0x05, 0x31, 0x62, 0x05, 0x21, 0x63, 0x05, - 0xC1, 0x5E, 0x05, 0xD1, 0x5C, 0x05, 0xE1, 0x5D, - 0x05, 0xE9, 0xFD, 0xC2, 0x6D, 0x19, 0x29, 0x83, - 0x89, 0x39, 0xA2, 0x6B, 0x6B, 0xF2, 0x5D, 0x1C, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x31, 0x64, 0x05, 0x21, 0x65, 0x05, 0x29, 0x13, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x31, 0x66, 0x05, 0x21, 0x67, 0x05, 0x22, 0x63, - 0x19, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x91, 0x69, 0x05, 0x21, 0x6B, 0x05, 0x31, 0x68, - 0x05, 0x81, 0x6A, 0x05, 0x89, 0xC3, 0x29, 0xA3, - 0x99, 0xB3, 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x04, 0x00, 0xB0, 0x15, 0x02, - 0x60, + 0x06, 0x00, 0x00, 0x64, 0x07, 0x00, 0x0F, 0x00, + 0x60, 0xD8, 0x0C, 0x00, 0x60, 0xD4, 0x0C, 0x00, + 0x60, 0x50, 0x15, 0x00, 0x60, 0x20, 0x0E, 0x00, + 0x60, 0xFC, 0xFF, 0x00, 0x00, 0x30, 0x15, 0x00, + 0x60, 0xB0, 0x0A, 0x00, 0x60, 0x58, 0xB3, 0x04, + 0x60, 0x84, 0x05, 0x00, 0x60, 0xA4, 0xED, 0x04, + 0x60, 0x8C, 0x04, 0x00, 0x00, 0x00, 0x0F, 0x00, + 0x60, 0x60, 0x06, 0x00, 0x00, 0xA0, 0x0A, 0x00, + 0x60, 0xD0, 0x38, 0x04, 0x60, 0xB4, 0x39, 0x04, + 0x60, 0x58, 0xB4, 0x04, 0x60, 0xFC, 0x0C, 0x00, + 0x60, 0x20, 0x15, 0x00, 0x60, 0xC8, 0x0D, 0x00, + 0x60, 0x9C, 0x0B, 0x00, 0x60, 0xFC, 0x14, 0x00, + 0x60, 0xCC, 0x08, 0x00, 0x60, 0x68, 0x0A, 0x00, + 0x60, 0x4C, 0x3F, 0x04, 0x60, 0xC0, 0x0D, 0x00, + 0x60, 0x04, 0x15, 0x00, 0x60, 0x18, 0x0D, 0x00, + 0x60, 0x00, 0x9E, 0x00, 0x38, 0xDC, 0x0C, 0x00, + 0x60, 0x00, 0x15, 0x00, 0x60, 0x36, 0x41, 0x00, + 0x25, 0x37, 0x00, 0x65, 0x3A, 0x00, 0xA5, 0x4C, + 0x00, 0xE5, 0x48, 0x00, 0x65, 0x35, 0x00, 0x91, + 0xC0, 0x03, 0xA1, 0xC1, 0x03, 0x0C, 0x08, 0x89, + 0x0A, 0x82, 0x49, 0x00, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x31, 0xC2, 0x03, 0x38, + 0x03, 0x8C, 0x73, 0x88, 0x23, 0x66, 0x28, 0x03, + 0x0C, 0x39, 0x99, 0x23, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x31, 0xC3, 0x03, 0x0C, + 0x02, 0x22, 0x43, 0x00, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0xBD, 0x02, 0x21, 0xC2, + 0x03, 0x28, 0x02, 0x1C, 0x8C, 0xCB, 0xA2, 0xA5, + 0x8F, 0x2D, 0xD1, 0xC4, 0x03, 0x2C, 0x0B, 0x92, + 0x12, 0x11, 0x0C, 0x1C, 0xDC, 0x79, 0xA2, 0x12, + 0x0F, 0x92, 0x12, 0x0E, 0xA0, 0xA0, 0xE4, 0x90, + 0xAA, 0xC0, 0xA2, 0xCA, 0xC2, 0xA0, 0xA1, 0x21, + 0xAA, 0x99, 0x8B, 0x99, 0x92, 0x52, 0x11, 0xB2, + 0x52, 0x13, 0xC9, 0x22, 0xD0, 0xD9, 0x10, 0xD2, + 0x52, 0x11, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, + 0xD8, 0x22, 0x31, 0xC2, 0x03, 0x0C, 0x1E, 0x38, + 0x03, 0x0C, 0x0C, 0xAD, 0x03, 0xF2, 0x13, 0x13, + 0xB2, 0x13, 0x10, 0xF0, 0xCE, 0x83, 0xDA, 0xBB, + 0x25, 0x17, 0x00, 0x0C, 0x45, 0xA8, 0x23, 0x92, + 0x13, 0x13, 0x0C, 0x04, 0x8C, 0x69, 0x0B, 0x99, + 0x90, 0x90, 0xF4, 0x92, 0x53, 0x13, 0xF6, 0x8A, + 0x2F, 0xB1, 0xC5, 0x03, 0xB0, 0xBA, 0xA0, 0xB8, + 0x0B, 0xA0, 0x0B, 0x00, 0xC8, 0x22, 0xB2, 0x13, + 0x11, 0xAD, 0x03, 0xCA, 0xBB, 0x65, 0x21, 0x00, + 0xD2, 0x13, 0x06, 0xF1, 0xC3, 0x03, 0xD7, 0x3A, + 0x0F, 0x0C, 0x29, 0x92, 0x4F, 0x00, 0xE2, 0x13, + 0x0F, 0xE0, 0xEF, 0x04, 0x16, 0xBE, 0x10, 0x99, + 0x23, 0x0C, 0x14, 0x2D, 0x04, 0x1D, 0xF0, 0x49, + 0x23, 0x0C, 0x24, 0x06, 0xFD, 0xFF, 0xAD, 0x03, + 0xE5, 0x1B, 0x00, 0x82, 0x13, 0x09, 0xB2, 0x13, + 0x08, 0x87, 0x3A, 0x02, 0x06, 0x24, 0x00, 0xC8, + 0x22, 0xB2, 0x13, 0x11, 0xAD, 0x03, 0xCA, 0xBB, + 0x65, 0x1D, 0x00, 0xD2, 0x13, 0x07, 0xD7, 0x3A, + 0x02, 0xC6, 0x36, 0x00, 0xE2, 0x13, 0x14, 0x0B, + 0xEE, 0xE0, 0xE0, 0xF4, 0xE2, 0x53, 0x14, 0x56, + 0xEE, 0x0D, 0x0C, 0x24, 0x0C, 0x7F, 0xF9, 0x23, + 0xC6, 0xED, 0xFF, 0xAD, 0x03, 0xE5, 0x17, 0x00, + 0x82, 0x13, 0x08, 0x87, 0x3A, 0x6A, 0x59, 0x23, + 0x42, 0x53, 0x16, 0x92, 0x13, 0x0A, 0x92, 0x53, + 0x14, 0x0C, 0x04, 0x06, 0xE7, 0xFF, 0xAD, 0x03, + 0x65, 0x16, 0x00, 0xB2, 0x13, 0x08, 0xB7, 0x3A, + 0x29, 0xC2, 0x13, 0x14, 0x0B, 0xCC, 0xC0, 0xC0, + 0xF4, 0xC2, 0x53, 0x14, 0xEC, 0xBC, 0x0C, 0x6D, + 0xE2, 0x13, 0x0B, 0xE2, 0x53, 0x14, 0xD9, 0x23, + 0xC6, 0x07, 0x00, 0xDC, 0xC9, 0x59, 0x23, 0x42, + 0x53, 0x16, 0xF2, 0x13, 0x0A, 0xF2, 0x53, 0x14, + 0xC6, 0x03, 0x00, 0x0C, 0x58, 0x92, 0x13, 0x0D, + 0xA2, 0x13, 0x0C, 0xA2, 0x53, 0x14, 0x92, 0x53, + 0x15, 0x89, 0x23, 0x0C, 0x04, 0x86, 0xD4, 0xFF, + 0xB7, 0x3A, 0x05, 0xC2, 0x13, 0x0B, 0xC2, 0x53, + 0x14, 0x42, 0x53, 0x16, 0x0C, 0x04, 0x46, 0xD0, + 0xFF, 0x92, 0x13, 0x15, 0x66, 0x19, 0x09, 0x0C, + 0x34, 0x0B, 0xD9, 0xD2, 0x53, 0x15, 0x46, 0xCC, + 0xFF, 0xCC, 0x39, 0x0C, 0x14, 0x86, 0x01, 0x00, + 0x0C, 0x04, 0x0B, 0xE9, 0xE2, 0x53, 0x15, 0xC8, + 0x22, 0xB2, 0x13, 0x11, 0xAD, 0x03, 0xCA, 0xBB, + 0x65, 0x11, 0x00, 0xD2, 0x13, 0x07, 0xD7, 0xBA, + 0x10, 0xE2, 0x13, 0x14, 0x0B, 0xEE, 0xE0, 0xE0, + 0xF4, 0xE2, 0x53, 0x14, 0xE0, 0x45, 0x83, 0x06, + 0xC0, 0xFF, 0xF2, 0x13, 0x0D, 0xF2, 0x53, 0x14, + 0xC6, 0xBD, 0xFF, 0x0C, 0x39, 0x86, 0xBB, 0xFF, + 0x82, 0x13, 0x06, 0x87, 0x3A, 0x05, 0x92, 0x13, + 0x0B, 0x92, 0x53, 0x14, 0x0C, 0x04, 0x46, 0xB8, + 0xFF, 0x0C, 0x04, 0x06, 0xB7, 0xFF, 0x00, 0x00, + 0x00, 0x36, 0x61, 0x00, 0xB2, 0xA0, 0x94, 0xA2, + 0xC2, 0x34, 0x92, 0xC2, 0x54, 0x99, 0x01, 0xA9, + 0x11, 0xBC, 0xB4, 0x68, 0x11, 0x5D, 0x09, 0x1C, + 0x04, 0x72, 0x12, 0x12, 0x82, 0xA0, 0x94, 0xC0, + 0x77, 0x11, 0x7A, 0x72, 0x8A, 0x77, 0x82, 0x16, + 0x00, 0xB2, 0x07, 0x00, 0x1B, 0x77, 0xAD, 0x0B, + 0xB0, 0x88, 0xC0, 0x82, 0x56, 0x00, 0x2B, 0x66, + 0x65, 0x96, 0x2D, 0x98, 0x05, 0x0B, 0x44, 0xA0, + 0x99, 0xC0, 0x99, 0x05, 0x4B, 0x55, 0x56, 0xC4, + 0xFD, 0x98, 0x01, 0xA8, 0x11, 0xB2, 0xA0, 0x94, + 0x5D, 0x09, 0x6D, 0x0A, 0x72, 0x12, 0x12, 0x1C, + 0x04, 0xC0, 0x77, 0x11, 0x7A, 0x72, 0xBA, 0x77, + 0xD2, 0x03, 0x01, 0xE2, 0x03, 0x03, 0xC2, 0x03, + 0x02, 0xB2, 0x03, 0x00, 0xEA, 0xCC, 0xDA, 0xBB, + 0xCA, 0xBB, 0xB0, 0xB2, 0x41, 0xAD, 0x0B, 0xB2, + 0x47, 0x00, 0x82, 0x16, 0x00, 0x1B, 0x77, 0xBA, + 0x88, 0x82, 0x56, 0x00, 0x2B, 0x66, 0x65, 0x91, + 0x2D, 0x8B, 0x33, 0xF8, 0x05, 0x0B, 0x44, 0xAA, + 0xFF, 0xF9, 0x05, 0x4B, 0x55, 0x56, 0x74, 0xFC, + 0x82, 0x12, 0x12, 0x1B, 0x88, 0x80, 0x80, 0x44, + 0x82, 0x52, 0x12, 0x1D, 0xF0, 0x36, 0x41, 0x00, + 0x32, 0xC2, 0x34, 0x1C, 0x05, 0x0C, 0x04, 0xB2, + 0x13, 0x00, 0xAD, 0x0B, 0xA5, 0x8E, 0x2D, 0x2B, + 0x33, 0x0B, 0x55, 0xA0, 0x95, 0x41, 0x82, 0x22, + 0x15, 0x4B, 0x22, 0x90, 0x88, 0xC0, 0x80, 0x85, + 0x41, 0x8A, 0x44, 0x56, 0x05, 0xFE, 0x40, 0x24, + 0x41, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x1C, 0x07, 0x0C, 0x06, 0x0C, 0x05, 0xB2, 0xC3, + 0x81, 0x42, 0x03, 0x00, 0xB2, 0x0B, 0x7E, 0xC2, + 0x03, 0x01, 0x47, 0xBB, 0x0C, 0x47, 0xBC, 0x11, + 0x4D, 0x0B, 0xC7, 0xBB, 0x0C, 0x4D, 0x0C, 0xC6, + 0x01, 0x00, 0x47, 0x3C, 0x04, 0xC7, 0xBB, 0x01, + 0x4D, 0x0B, 0xAD, 0x04, 0xBD, 0x04, 0x65, 0x89, + 0x2D, 0xAA, 0x66, 0x5A, 0x54, 0x0B, 0x77, 0x4B, + 0x33, 0xB2, 0xC3, 0x81, 0x56, 0x97, 0xFC, 0xAD, + 0x05, 0xBD, 0x05, 0x25, 0x88, 0x2D, 0xD2, 0x12, + 0x16, 0xA0, 0x94, 0x41, 0x90, 0x96, 0xC0, 0xD0, + 0xCD, 0xF0, 0x90, 0x94, 0x41, 0x90, 0xE3, 0x41, + 0xC0, 0xC3, 0x21, 0xEA, 0xCC, 0xD0, 0x9C, 0x93, + 0x92, 0x52, 0x16, 0x2D, 0x09, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x31, 0xC6, 0x03, 0x21, + 0xC7, 0x03, 0x22, 0x63, 0x75, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0xA1, 0xC8, 0x03, 0xB1, + 0xC9, 0x03, 0xC1, 0xCA, 0x03, 0xA5, 0x5D, 0x2D, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x9C, 0x85, 0x20, 0x61, 0x00, 0xE5, 0xC6, 0xFF, + 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, 0x0C, 0x0A, + 0x65, 0x98, 0x29, 0xA1, 0xCB, 0x03, 0xB1, 0xCC, + 0x03, 0xA5, 0x25, 0x2D, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x0C, 0xBB, 0x31, 0xC6, + 0x03, 0x21, 0xD0, 0x03, 0x81, 0xCF, 0x03, 0x91, + 0xCD, 0x03, 0xA1, 0xCE, 0x03, 0xA9, 0xF9, 0x82, + 0x69, 0x19, 0x22, 0x63, 0x6B, 0xB2, 0x59, 0x1C, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x21, 0xD1, 0x03, 0x88, 0x22, 0x37, 0x68, 0x0E, + 0xA1, 0xD2, 0x03, 0xA5, 0x4D, 0x2D, 0x98, 0x22, + 0x6C, 0x7A, 0xA0, 0x99, 0x10, 0x99, 0x22, 0xE5, + 0x79, 0x22, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, + 0xCD, 0x04, 0xBD, 0x03, 0xAD, 0x02, 0xDD, 0x05, + 0x25, 0x0E, 0x2A, 0xAC, 0x15, 0x81, 0xD3, 0x03, + 0xA1, 0xD4, 0x03, 0x88, 0x08, 0x91, 0xD1, 0x03, + 0x82, 0x08, 0x02, 0x98, 0x29, 0xB6, 0x28, 0x06, + 0x91, 0xD5, 0x03, 0x99, 0x2A, 0x1D, 0xF0, 0x37, + 0x69, 0x05, 0x91, 0xD6, 0x03, 0x86, 0xFC, 0xFF, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0xBD, 0x03, 0xAD, 0x02, 0xCD, 0x04, 0xDD, 0x05, + 0x1C, 0x8E, 0x25, 0x71, 0x22, 0xBC, 0x16, 0x82, + 0x12, 0x1A, 0x5A, 0xA4, 0xEC, 0xA8, 0x1C, 0x79, + 0xA7, 0x39, 0x28, 0x92, 0xA4, 0x21, 0x92, 0x52, + 0x1A, 0x06, 0x05, 0x00, 0xA1, 0xD2, 0x03, 0x25, + 0x42, 0x2D, 0xA8, 0x82, 0xE5, 0xBF, 0xFF, 0xB1, + 0xD1, 0x03, 0xA8, 0x2B, 0x30, 0xAA, 0x20, 0xA9, + 0x2B, 0xA8, 0x82, 0xA5, 0x05, 0x2D, 0x0C, 0x0B, + 0xB9, 0x82, 0x1D, 0xF0, 0x1C, 0x83, 0xA7, 0xB3, + 0xDA, 0x92, 0xA4, 0x22, 0x86, 0xF3, 0xFF, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x8C, 0x36, 0x0C, 0x03, + 0x32, 0x52, 0x1A, 0x1D, 0xF0, 0x36, 0x41, 0x00, + 0xA5, 0xB9, 0xFF, 0xAD, 0x02, 0x81, 0xD6, 0x03, + 0x89, 0x22, 0xE5, 0x8C, 0x29, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x31, 0xD7, 0x03, 0x21, + 0xD8, 0x03, 0x29, 0x13, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x81, 0xD9, 0x03, 0x30, + 0x61, 0x00, 0x88, 0x08, 0x82, 0x08, 0x10, 0x26, + 0x48, 0x07, 0xAD, 0x02, 0xA5, 0x54, 0x28, 0x06, + 0x01, 0x00, 0x0C, 0x0A, 0xE5, 0xED, 0x20, 0x30, + 0xE6, 0x13, 0x10, 0x20, 0x00, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x21, 0xDA, 0x03, 0x88, + 0x02, 0x27, 0x18, 0x09, 0xAD, 0x02, 0xE5, 0x07, + 0x00, 0xAD, 0x02, 0xE5, 0xE2, 0x20, 0x1D, 0xF0, + 0x00, 0x36, 0x41, 0x00, 0x20, 0x61, 0x00, 0xA1, + 0xDA, 0x03, 0xE5, 0xE1, 0x20, 0xA5, 0x28, 0x24, + 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, 0x1D, 0xF0, + 0x00, 0x36, 0x41, 0x00, 0x41, 0xDB, 0x03, 0x21, + 0xDC, 0x03, 0xC0, 0x20, 0x00, 0x32, 0x22, 0x81, + 0x98, 0x54, 0x88, 0x34, 0x30, 0x99, 0x20, 0x99, + 0x54, 0x87, 0x03, 0x06, 0x0C, 0x0A, 0xA9, 0x34, + 0xA5, 0xE5, 0x21, 0x0C, 0x1D, 0x3C, 0x8C, 0xB8, + 0x44, 0xC0, 0x20, 0x00, 0xC0, 0xBB, 0x10, 0xB2, + 0x62, 0x80, 0xC0, 0x20, 0x00, 0xE2, 0x22, 0x81, + 0xE0, 0xF0, 0x04, 0x07, 0xEE, 0xF3, 0xC0, 0x20, + 0x00, 0xB1, 0xDD, 0x03, 0x32, 0x62, 0x81, 0xC0, + 0x20, 0x00, 0xB8, 0x0B, 0xA1, 0xDE, 0x03, 0x1B, + 0xBB, 0xB9, 0x4A, 0x4B, 0xAA, 0x25, 0xDA, 0x20, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x20, 0x61, 0x00, 0x3C, 0x8A, 0x0C, 0x0B, 0xA5, + 0x25, 0x24, 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0xB8, 0x0F, 0x02, + 0x60, 0xC0, 0x0F, 0x02, 0x60, 0x04, 0x14, 0x02, + 0x60, 0xDC, 0x14, 0x02, 0x60, 0x04, 0x15, 0x00, + 0x60, 0x04, 0x15, 0x00, 0x60, 0x00, 0x15, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xF4, 0x14, 0x00, 0x60, 0xF8, 0x14, 0x00, + 0x60, 0x50, 0x15, 0x00, 0x60, 0x94, 0x02, 0x00, + 0x00, 0x78, 0x10, 0x02, 0x60, 0x53, 0x10, 0x02, + 0x60, 0x78, 0x10, 0x02, 0x60, 0x02, 0x11, 0x02, + 0x60, 0xDD, 0x10, 0x02, 0x60, 0xC2, 0x10, 0x02, + 0x60, 0x85, 0x10, 0x02, 0x60, 0x7E, 0x10, 0x02, + 0x60, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x0C, 0x00, + 0x60, 0xD4, 0x0C, 0x00, 0x60, 0x10, 0x30, 0x02, + 0x00, 0x60, 0x15, 0x00, 0x60, 0x00, 0x01, 0x00, + 0x00, 0xB0, 0x0A, 0x00, 0x60, 0x04, 0x13, 0x02, + 0x60, 0xA0, 0x0A, 0x00, 0x60, 0xA4, 0x13, 0x02, + 0x60, 0xF8, 0x13, 0x02, 0x60, 0x6C, 0x13, 0x02, + 0x60, 0x6C, 0x06, 0x00, 0x60, 0x14, 0x10, 0x02, + 0x60, 0xF4, 0x05, 0x00, 0x60, 0x4C, 0x13, 0x02, + 0x60, 0x68, 0x0A, 0x00, 0x60, 0x28, 0x8F, 0x04, + 0x60, 0x48, 0x08, 0x00, 0x60, 0x28, 0x14, 0x02, + 0x60, 0xAC, 0x06, 0x00, 0x60, 0x68, 0x14, 0x02, + 0x60, 0x80, 0x14, 0x02, 0x60, 0xD8, 0x56, 0x04, + 0x60, 0x36, 0x41, 0x00, 0x81, 0x57, 0x05, 0xB1, + 0x55, 0x05, 0x0C, 0x3A, 0x91, 0x56, 0x05, 0xA2, + 0x4B, 0x00, 0x89, 0x09, 0xE5, 0x01, 0x00, 0xE5, + 0x05, 0x00, 0xA5, 0x06, 0x00, 0x65, 0x07, 0x00, + 0x25, 0x02, 0x00, 0xA1, 0x58, 0x05, 0xB1, 0x59, + 0x05, 0x25, 0xFA, 0x2C, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x31, 0x5A, 0x05, 0x21, + 0x5B, 0x05, 0x22, 0x63, 0x75, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x0C, 0x8F, 0xB1, 0x5A, + 0x05, 0xA1, 0x5F, 0x05, 0x91, 0x60, 0x05, 0x81, + 0x61, 0x05, 0x31, 0x62, 0x05, 0x21, 0x63, 0x05, + 0xC1, 0x5E, 0x05, 0xD1, 0x5C, 0x05, 0xE1, 0x5D, + 0x05, 0xE9, 0xFD, 0xC2, 0x6D, 0x19, 0x29, 0x83, + 0x89, 0x39, 0xA2, 0x6B, 0x6B, 0xF2, 0x5D, 0x1C, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x31, 0x64, 0x05, 0x21, 0x65, 0x05, 0x29, 0x13, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x31, 0x66, 0x05, 0x21, 0x67, 0x05, 0x22, 0x63, + 0x19, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x91, 0x69, 0x05, 0x21, 0x6B, 0x05, 0x31, 0x68, + 0x05, 0x81, 0x6A, 0x05, 0x89, 0xC3, 0x29, 0xA3, + 0x99, 0xB3, 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x04, 0x00, 0xB0, 0x15, 0x02, + 0x60, }; static const unsigned char vfs301_06_3[] = { /* 785 B */ - 0x06, 0x00, 0x00, 0x04, 0x03, 0x00, 0x0F, 0x00, - 0x60, 0xD8, 0x0C, 0x00, 0x60, 0xD4, 0x0C, 0x00, - 0x60, 0xB0, 0x0A, 0x00, 0x60, 0x58, 0xB3, 0x04, - 0x60, 0x84, 0x05, 0x00, 0x60, 0xA4, 0xED, 0x04, - 0x60, 0x8C, 0x04, 0x00, 0x00, 0xBC, 0x08, 0x00, - 0x60, 0x00, 0x0F, 0x00, 0x60, 0x50, 0x02, 0x00, - 0x00, 0xFC, 0x07, 0x00, 0x60, 0xF4, 0x8B, 0x04, - 0x60, 0xBC, 0x0D, 0x00, 0x60, 0xDC, 0x0C, 0x00, - 0x60, 0xC0, 0x0D, 0x00, 0x60, 0x40, 0x11, 0x00, - 0x60, 0x18, 0x0D, 0x00, 0x60, 0x00, 0x9E, 0x00, - 0x38, 0x3C, 0x11, 0x00, 0x60, 0x36, 0x41, 0x00, - 0xE5, 0x02, 0x00, 0x65, 0x14, 0x00, 0x25, 0x06, - 0x00, 0x25, 0x01, 0x00, 0x91, 0xC0, 0x03, 0xA1, - 0xC1, 0x03, 0x0C, 0x08, 0x89, 0x0A, 0x82, 0x49, - 0x00, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x31, 0xC2, 0x03, 0x21, 0xC3, 0x03, 0x22, 0x63, - 0x75, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, - 0xA1, 0xC4, 0x03, 0xB1, 0xC5, 0x03, 0xC1, 0xC6, - 0x03, 0xE5, 0x94, 0x2D, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x9C, 0xD5, 0x20, 0x61, - 0x00, 0x25, 0xFB, 0xFF, 0x81, 0xC7, 0x03, 0x20, - 0xE6, 0x13, 0x10, 0x20, 0x00, 0x88, 0x28, 0x0C, - 0x0A, 0xE0, 0x08, 0x00, 0xA1, 0xC8, 0x03, 0xB1, - 0xC9, 0x03, 0xA5, 0x5C, 0x2D, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x31, 0xCA, 0x03, 0x21, - 0xCB, 0x03, 0x29, 0xD3, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x41, 0xCC, 0x03, 0x88, - 0x04, 0x22, 0x08, 0xD2, 0x80, 0x22, 0xA0, 0x28, - 0x92, 0xAD, 0x02, 0xE5, 0x73, 0x2D, 0xC0, 0x20, - 0x00, 0x5D, 0x0A, 0x38, 0x0A, 0xA2, 0xC2, 0x10, - 0x25, 0x73, 0x2D, 0x88, 0x04, 0x30, 0x9A, 0x10, - 0x82, 0x28, 0x1D, 0xC0, 0x20, 0x00, 0x90, 0x88, - 0x20, 0x89, 0x05, 0xC0, 0x20, 0x00, 0x38, 0x05, - 0x7C, 0xF5, 0x50, 0x5A, 0x30, 0x30, 0x35, 0x10, - 0xCB, 0xA2, 0xE5, 0x70, 0x2D, 0x37, 0x9A, 0x29, - 0x4B, 0xA2, 0x65, 0x70, 0x2D, 0xB8, 0x04, 0xCD, - 0x0A, 0xA2, 0xC2, 0x14, 0x92, 0x2B, 0x1E, 0xC2, - 0x6B, 0x1D, 0x1B, 0x99, 0x92, 0x6B, 0x1E, 0x25, - 0x6F, 0x2D, 0xB8, 0x04, 0xD2, 0x2B, 0x1E, 0xD7, - 0xBA, 0x16, 0xA2, 0xCB, 0x64, 0x25, 0x2E, 0x2D, - 0x1D, 0xF0, 0x8B, 0xA2, 0xE5, 0x6D, 0x2D, 0xF8, - 0x04, 0x3A, 0xEA, 0xE0, 0xE5, 0x10, 0xE2, 0x6F, - 0x1D, 0x81, 0xCA, 0x03, 0x82, 0x28, 0x12, 0xE0, - 0x08, 0x00, 0xA2, 0xA0, 0x94, 0xC1, 0xCD, 0x03, - 0xB8, 0x04, 0xC0, 0x20, 0x00, 0xC8, 0x0C, 0x92, - 0x1B, 0x5D, 0xAA, 0xAB, 0xCA, 0x99, 0x92, 0x6B, - 0x28, 0xE5, 0x20, 0x21, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x81, 0xCE, 0x03, 0x30, - 0x61, 0x00, 0x88, 0x08, 0x82, 0x08, 0x10, 0x26, - 0x48, 0x07, 0xAD, 0x02, 0x25, 0x90, 0x28, 0x06, - 0x01, 0x00, 0x0C, 0x0A, 0x65, 0x29, 0x21, 0x30, - 0xE6, 0x13, 0x10, 0x20, 0x00, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x21, 0xCF, 0x03, 0x88, - 0x02, 0x27, 0x18, 0x09, 0xAD, 0x02, 0xE5, 0x07, - 0x00, 0xAD, 0x02, 0x65, 0x1E, 0x21, 0x1D, 0xF0, - 0x00, 0x36, 0x41, 0x00, 0x20, 0x61, 0x00, 0xA1, - 0xCF, 0x03, 0x65, 0x1D, 0x21, 0x25, 0x64, 0x24, - 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, 0x1D, 0xF0, - 0x00, 0x36, 0x41, 0x00, 0x41, 0xD0, 0x03, 0x21, - 0xD1, 0x03, 0xC0, 0x20, 0x00, 0x32, 0x22, 0x81, - 0x98, 0x54, 0x88, 0x34, 0x30, 0x99, 0x20, 0x99, - 0x54, 0x87, 0x03, 0x06, 0x0C, 0x0A, 0xA9, 0x34, - 0x25, 0x21, 0x22, 0x0C, 0x1D, 0x3C, 0x8C, 0xB8, - 0x44, 0xC0, 0x20, 0x00, 0xC0, 0xBB, 0x10, 0xB2, - 0x62, 0x80, 0xC0, 0x20, 0x00, 0xE2, 0x22, 0x81, - 0xE0, 0xF0, 0x04, 0x07, 0xEE, 0xF3, 0xC0, 0x20, - 0x00, 0xB1, 0xCD, 0x03, 0x32, 0x62, 0x81, 0xC0, - 0x20, 0x00, 0xB8, 0x0B, 0xA1, 0xD2, 0x03, 0x1B, - 0xBB, 0xB9, 0x4A, 0x4B, 0xAA, 0xA5, 0x15, 0x21, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x20, 0x61, 0x00, 0x3C, 0x8A, 0x0C, 0x0B, 0x25, - 0x61, 0x24, 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x24, 0x11, 0x02, - 0x60, 0x40, 0x11, 0x00, 0x60, 0x40, 0x11, 0x00, - 0x60, 0x3C, 0x11, 0x00, 0x60, 0x00, 0x00, 0x00, - 0x00, 0xD8, 0x0C, 0x00, 0x60, 0xD4, 0x0C, 0x00, - 0x60, 0x12, 0x30, 0x00, 0x00, 0x50, 0x11, 0x00, - 0x60, 0xB0, 0x00, 0x00, 0x00, 0xB0, 0x0A, 0x00, - 0x60, 0x90, 0x0F, 0x02, 0x60, 0xFC, 0x07, 0x00, - 0x60, 0xC8, 0x0F, 0x02, 0x60, 0x48, 0x08, 0x00, - 0x60, 0x70, 0x10, 0x02, 0x60, 0xAC, 0x06, 0x00, - 0x60, 0xB0, 0x10, 0x02, 0x60, 0xC8, 0x10, 0x02, - 0x60, 0xD8, 0x56, 0x04, 0x60, 0x36, 0x41, 0x00, - 0x81, 0x56, 0x04, 0xB1, 0x54, 0x04, 0x0C, 0x1A, - 0x91, 0x55, 0x04, 0xA2, 0x4B, 0x00, 0x89, 0x09, - 0xA5, 0x01, 0x00, 0x65, 0x02, 0x00, 0x25, 0x03, - 0x00, 0xE5, 0x03, 0x00, 0xA1, 0x57, 0x04, 0xB1, - 0x58, 0x04, 0xA5, 0x3C, 0x2D, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x31, 0x59, 0x04, 0x21, - 0x5A, 0x04, 0x22, 0x63, 0x75, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x31, 0x5B, 0x04, 0x21, - 0x5C, 0x04, 0x29, 0xD3, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x31, 0x5D, 0x04, 0x21, - 0x5E, 0x04, 0x22, 0x63, 0x19, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x91, 0x60, 0x04, 0x21, - 0x62, 0x04, 0x31, 0x5F, 0x04, 0x81, 0x61, 0x04, - 0x89, 0xC3, 0x29, 0xA3, 0x99, 0xB3, 0x1D, 0xF0, - 0x00, 0x01, 0x00, 0x04, 0x00, 0x8C, 0x11, 0x02, - 0x60, + 0x06, 0x00, 0x00, 0x04, 0x03, 0x00, 0x0F, 0x00, + 0x60, 0xD8, 0x0C, 0x00, 0x60, 0xD4, 0x0C, 0x00, + 0x60, 0xB0, 0x0A, 0x00, 0x60, 0x58, 0xB3, 0x04, + 0x60, 0x84, 0x05, 0x00, 0x60, 0xA4, 0xED, 0x04, + 0x60, 0x8C, 0x04, 0x00, 0x00, 0xBC, 0x08, 0x00, + 0x60, 0x00, 0x0F, 0x00, 0x60, 0x50, 0x02, 0x00, + 0x00, 0xFC, 0x07, 0x00, 0x60, 0xF4, 0x8B, 0x04, + 0x60, 0xBC, 0x0D, 0x00, 0x60, 0xDC, 0x0C, 0x00, + 0x60, 0xC0, 0x0D, 0x00, 0x60, 0x40, 0x11, 0x00, + 0x60, 0x18, 0x0D, 0x00, 0x60, 0x00, 0x9E, 0x00, + 0x38, 0x3C, 0x11, 0x00, 0x60, 0x36, 0x41, 0x00, + 0xE5, 0x02, 0x00, 0x65, 0x14, 0x00, 0x25, 0x06, + 0x00, 0x25, 0x01, 0x00, 0x91, 0xC0, 0x03, 0xA1, + 0xC1, 0x03, 0x0C, 0x08, 0x89, 0x0A, 0x82, 0x49, + 0x00, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x31, 0xC2, 0x03, 0x21, 0xC3, 0x03, 0x22, 0x63, + 0x75, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, + 0xA1, 0xC4, 0x03, 0xB1, 0xC5, 0x03, 0xC1, 0xC6, + 0x03, 0xE5, 0x94, 0x2D, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x9C, 0xD5, 0x20, 0x61, + 0x00, 0x25, 0xFB, 0xFF, 0x81, 0xC7, 0x03, 0x20, + 0xE6, 0x13, 0x10, 0x20, 0x00, 0x88, 0x28, 0x0C, + 0x0A, 0xE0, 0x08, 0x00, 0xA1, 0xC8, 0x03, 0xB1, + 0xC9, 0x03, 0xA5, 0x5C, 0x2D, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x31, 0xCA, 0x03, 0x21, + 0xCB, 0x03, 0x29, 0xD3, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x41, 0xCC, 0x03, 0x88, + 0x04, 0x22, 0x08, 0xD2, 0x80, 0x22, 0xA0, 0x28, + 0x92, 0xAD, 0x02, 0xE5, 0x73, 0x2D, 0xC0, 0x20, + 0x00, 0x5D, 0x0A, 0x38, 0x0A, 0xA2, 0xC2, 0x10, + 0x25, 0x73, 0x2D, 0x88, 0x04, 0x30, 0x9A, 0x10, + 0x82, 0x28, 0x1D, 0xC0, 0x20, 0x00, 0x90, 0x88, + 0x20, 0x89, 0x05, 0xC0, 0x20, 0x00, 0x38, 0x05, + 0x7C, 0xF5, 0x50, 0x5A, 0x30, 0x30, 0x35, 0x10, + 0xCB, 0xA2, 0xE5, 0x70, 0x2D, 0x37, 0x9A, 0x29, + 0x4B, 0xA2, 0x65, 0x70, 0x2D, 0xB8, 0x04, 0xCD, + 0x0A, 0xA2, 0xC2, 0x14, 0x92, 0x2B, 0x1E, 0xC2, + 0x6B, 0x1D, 0x1B, 0x99, 0x92, 0x6B, 0x1E, 0x25, + 0x6F, 0x2D, 0xB8, 0x04, 0xD2, 0x2B, 0x1E, 0xD7, + 0xBA, 0x16, 0xA2, 0xCB, 0x64, 0x25, 0x2E, 0x2D, + 0x1D, 0xF0, 0x8B, 0xA2, 0xE5, 0x6D, 0x2D, 0xF8, + 0x04, 0x3A, 0xEA, 0xE0, 0xE5, 0x10, 0xE2, 0x6F, + 0x1D, 0x81, 0xCA, 0x03, 0x82, 0x28, 0x12, 0xE0, + 0x08, 0x00, 0xA2, 0xA0, 0x94, 0xC1, 0xCD, 0x03, + 0xB8, 0x04, 0xC0, 0x20, 0x00, 0xC8, 0x0C, 0x92, + 0x1B, 0x5D, 0xAA, 0xAB, 0xCA, 0x99, 0x92, 0x6B, + 0x28, 0xE5, 0x20, 0x21, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x81, 0xCE, 0x03, 0x30, + 0x61, 0x00, 0x88, 0x08, 0x82, 0x08, 0x10, 0x26, + 0x48, 0x07, 0xAD, 0x02, 0x25, 0x90, 0x28, 0x06, + 0x01, 0x00, 0x0C, 0x0A, 0x65, 0x29, 0x21, 0x30, + 0xE6, 0x13, 0x10, 0x20, 0x00, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x21, 0xCF, 0x03, 0x88, + 0x02, 0x27, 0x18, 0x09, 0xAD, 0x02, 0xE5, 0x07, + 0x00, 0xAD, 0x02, 0x65, 0x1E, 0x21, 0x1D, 0xF0, + 0x00, 0x36, 0x41, 0x00, 0x20, 0x61, 0x00, 0xA1, + 0xCF, 0x03, 0x65, 0x1D, 0x21, 0x25, 0x64, 0x24, + 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, 0x1D, 0xF0, + 0x00, 0x36, 0x41, 0x00, 0x41, 0xD0, 0x03, 0x21, + 0xD1, 0x03, 0xC0, 0x20, 0x00, 0x32, 0x22, 0x81, + 0x98, 0x54, 0x88, 0x34, 0x30, 0x99, 0x20, 0x99, + 0x54, 0x87, 0x03, 0x06, 0x0C, 0x0A, 0xA9, 0x34, + 0x25, 0x21, 0x22, 0x0C, 0x1D, 0x3C, 0x8C, 0xB8, + 0x44, 0xC0, 0x20, 0x00, 0xC0, 0xBB, 0x10, 0xB2, + 0x62, 0x80, 0xC0, 0x20, 0x00, 0xE2, 0x22, 0x81, + 0xE0, 0xF0, 0x04, 0x07, 0xEE, 0xF3, 0xC0, 0x20, + 0x00, 0xB1, 0xCD, 0x03, 0x32, 0x62, 0x81, 0xC0, + 0x20, 0x00, 0xB8, 0x0B, 0xA1, 0xD2, 0x03, 0x1B, + 0xBB, 0xB9, 0x4A, 0x4B, 0xAA, 0xA5, 0x15, 0x21, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x20, 0x61, 0x00, 0x3C, 0x8A, 0x0C, 0x0B, 0x25, + 0x61, 0x24, 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x24, 0x11, 0x02, + 0x60, 0x40, 0x11, 0x00, 0x60, 0x40, 0x11, 0x00, + 0x60, 0x3C, 0x11, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x00, 0xD8, 0x0C, 0x00, 0x60, 0xD4, 0x0C, 0x00, + 0x60, 0x12, 0x30, 0x00, 0x00, 0x50, 0x11, 0x00, + 0x60, 0xB0, 0x00, 0x00, 0x00, 0xB0, 0x0A, 0x00, + 0x60, 0x90, 0x0F, 0x02, 0x60, 0xFC, 0x07, 0x00, + 0x60, 0xC8, 0x0F, 0x02, 0x60, 0x48, 0x08, 0x00, + 0x60, 0x70, 0x10, 0x02, 0x60, 0xAC, 0x06, 0x00, + 0x60, 0xB0, 0x10, 0x02, 0x60, 0xC8, 0x10, 0x02, + 0x60, 0xD8, 0x56, 0x04, 0x60, 0x36, 0x41, 0x00, + 0x81, 0x56, 0x04, 0xB1, 0x54, 0x04, 0x0C, 0x1A, + 0x91, 0x55, 0x04, 0xA2, 0x4B, 0x00, 0x89, 0x09, + 0xA5, 0x01, 0x00, 0x65, 0x02, 0x00, 0x25, 0x03, + 0x00, 0xE5, 0x03, 0x00, 0xA1, 0x57, 0x04, 0xB1, + 0x58, 0x04, 0xA5, 0x3C, 0x2D, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x31, 0x59, 0x04, 0x21, + 0x5A, 0x04, 0x22, 0x63, 0x75, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x31, 0x5B, 0x04, 0x21, + 0x5C, 0x04, 0x29, 0xD3, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x31, 0x5D, 0x04, 0x21, + 0x5E, 0x04, 0x22, 0x63, 0x19, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x91, 0x60, 0x04, 0x21, + 0x62, 0x04, 0x31, 0x5F, 0x04, 0x81, 0x61, 0x04, + 0x89, 0xC3, 0x29, 0xA3, 0x99, 0xB3, 0x1D, 0xF0, + 0x00, 0x01, 0x00, 0x04, 0x00, 0x8C, 0x11, 0x02, + 0x60, }; static const unsigned char vfs301_06_4[] = { /* 3057 B */ - 0x06, 0x00, 0x00, 0xE4, 0x0B, 0x00, 0x0F, 0x00, - 0x60, 0xD8, 0x0C, 0x00, 0x60, 0xD4, 0x0C, 0x00, - 0x60, 0xB0, 0x0A, 0x00, 0x60, 0x58, 0xB3, 0x04, - 0x60, 0x84, 0x05, 0x00, 0x60, 0xA4, 0xED, 0x04, - 0x60, 0x8C, 0x04, 0x00, 0x00, 0x00, 0x0F, 0x00, - 0x60, 0xC0, 0x0A, 0x00, 0x00, 0xA0, 0x0A, 0x00, - 0x60, 0xD0, 0x38, 0x04, 0x60, 0xB4, 0x39, 0x04, - 0x60, 0x58, 0xB4, 0x04, 0x60, 0xFC, 0x0C, 0x00, - 0x60, 0x80, 0x19, 0x00, 0x60, 0xC8, 0x0D, 0x00, - 0x60, 0x9C, 0x0B, 0x00, 0x60, 0xF4, 0x18, 0x00, - 0x60, 0xCC, 0x08, 0x00, 0x60, 0xF8, 0x18, 0x00, - 0x60, 0xA8, 0x0B, 0x00, 0x60, 0xE4, 0x06, 0x00, - 0x60, 0x54, 0x11, 0x02, 0x60, 0xAC, 0x06, 0x00, - 0x60, 0x48, 0x11, 0x02, 0x60, 0x04, 0x19, 0x00, - 0x60, 0x80, 0x7F, 0x00, 0x38, 0x80, 0x5F, 0x00, - 0x38, 0x80, 0x3F, 0x00, 0x38, 0xDC, 0x0C, 0x00, - 0x60, 0x1C, 0x19, 0x00, 0x60, 0x2C, 0x19, 0x00, - 0x60, 0x48, 0x19, 0x00, 0x60, 0x00, 0x40, 0x00, - 0x38, 0x00, 0xA0, 0x00, 0x38, 0x68, 0x0A, 0x00, - 0x60, 0x4C, 0x3F, 0x04, 0x60, 0xC0, 0x0D, 0x00, - 0x60, 0x5C, 0x19, 0x00, 0x60, 0x18, 0x0D, 0x00, - 0x60, 0x00, 0x9E, 0x00, 0x38, 0x58, 0x19, 0x00, - 0x60, 0xB0, 0x19, 0x00, 0x60, 0x20, 0x0E, 0x00, - 0x60, 0xFC, 0xFF, 0x00, 0x00, 0x90, 0x19, 0x00, - 0x60, 0x36, 0x41, 0x00, 0x65, 0x03, 0x00, 0x25, - 0x18, 0x00, 0x65, 0x15, 0x00, 0x25, 0x06, 0x00, - 0x25, 0x54, 0x00, 0x65, 0x50, 0x00, 0x25, 0x01, - 0x00, 0x91, 0xC0, 0x03, 0xA1, 0xC1, 0x03, 0x0C, - 0x08, 0x89, 0x0A, 0x82, 0x49, 0x00, 0x1D, 0xF0, - 0x00, 0x36, 0x41, 0x00, 0x31, 0xC2, 0x03, 0x21, - 0xC3, 0x03, 0x22, 0x63, 0x75, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0xA1, 0xC4, 0x03, 0xB1, - 0xC5, 0x03, 0xC1, 0xC6, 0x03, 0xA5, 0x8D, 0x2D, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x9C, 0x85, 0x20, 0x61, 0x00, 0xA5, 0xFA, 0xFF, - 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, 0x0C, 0x0A, - 0x65, 0xC8, 0x29, 0xA1, 0xC7, 0x03, 0xB1, 0xC8, - 0x03, 0xA5, 0x55, 0x2D, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x0C, 0xBB, 0x31, 0xC2, - 0x03, 0x21, 0xCC, 0x03, 0x81, 0xCB, 0x03, 0x91, - 0xC9, 0x03, 0xA1, 0xCA, 0x03, 0xA9, 0xF9, 0x82, - 0x69, 0x19, 0x22, 0x63, 0x6B, 0xB2, 0x59, 0x1C, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x21, 0xCD, 0x03, 0x88, 0x22, 0x37, 0x68, 0x0E, - 0xA1, 0xCE, 0x03, 0xA5, 0x7D, 0x2D, 0x98, 0x22, - 0x6C, 0x7A, 0xA0, 0x99, 0x10, 0x99, 0x22, 0xE5, - 0xA9, 0x22, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, - 0xCD, 0x04, 0xBD, 0x03, 0xAD, 0x02, 0xDD, 0x05, - 0x25, 0x3E, 0x2A, 0xAC, 0x15, 0x81, 0xCF, 0x03, - 0xA1, 0xD0, 0x03, 0x88, 0x08, 0x91, 0xCD, 0x03, - 0x82, 0x08, 0x02, 0x98, 0x29, 0xB6, 0x28, 0x06, - 0x91, 0xD1, 0x03, 0x99, 0x2A, 0x1D, 0xF0, 0x37, - 0x69, 0x05, 0x91, 0xD2, 0x03, 0x86, 0xFC, 0xFF, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0xBD, 0x03, 0xAD, 0x02, 0xCD, 0x04, 0xDD, 0x05, - 0x1C, 0x8E, 0x25, 0xA1, 0x22, 0xBC, 0x16, 0x82, - 0x12, 0x1A, 0x5A, 0xA4, 0xEC, 0xA8, 0x1C, 0x79, - 0xA7, 0x39, 0x28, 0x92, 0xA4, 0x21, 0x92, 0x52, - 0x1A, 0x06, 0x05, 0x00, 0xA1, 0xCE, 0x03, 0x25, - 0x72, 0x2D, 0xA8, 0x82, 0xA5, 0x50, 0x00, 0xB1, - 0xCD, 0x03, 0xA8, 0x2B, 0x30, 0xAA, 0x20, 0xA9, - 0x2B, 0xA8, 0x82, 0xA5, 0x35, 0x2D, 0x0C, 0x0B, - 0xB9, 0x82, 0x1D, 0xF0, 0x1C, 0x83, 0xA7, 0xB3, - 0xDA, 0x92, 0xA4, 0x22, 0x86, 0xF3, 0xFF, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x8C, 0x36, 0x0C, 0x03, - 0x32, 0x52, 0x1A, 0x1D, 0xF0, 0x36, 0x41, 0x00, - 0x65, 0x4A, 0x00, 0xAD, 0x02, 0x81, 0xD2, 0x03, - 0x89, 0x22, 0xE5, 0xBC, 0x29, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x21, 0xD3, 0x03, 0x31, - 0xD4, 0x03, 0x28, 0x22, 0x29, 0x03, 0x1D, 0xF0, - 0x00, 0x36, 0x41, 0x00, 0x21, 0xD8, 0x03, 0x31, - 0xD7, 0x03, 0x91, 0xD5, 0x03, 0x81, 0xD6, 0x03, - 0x89, 0x49, 0x29, 0x03, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x25, 0x18, 0x00, 0x1D, - 0xF0, 0x36, 0x41, 0x00, 0xA5, 0x17, 0x00, 0x65, - 0x20, 0x24, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, - 0xAD, 0x02, 0x65, 0xBE, 0x24, 0x65, 0x16, 0x00, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x61, 0xD9, 0x03, 0xCC, 0xE4, 0xA2, 0xA0, 0x76, - 0x65, 0x22, 0x2D, 0xA9, 0x36, 0xCC, 0x4A, 0xA2, - 0xA4, 0x31, 0x25, 0xB2, 0x29, 0x72, 0xA0, 0x76, - 0xD8, 0x36, 0xA2, 0xA0, 0x75, 0xAC, 0x2D, 0x4A, - 0xB3, 0xB7, 0x37, 0x0E, 0xDA, 0xA4, 0xBD, 0x02, - 0xCD, 0x03, 0x65, 0x74, 0x2D, 0xA2, 0xA0, 0x75, - 0xC6, 0x03, 0x00, 0x47, 0x3A, 0x0C, 0xDA, 0xA4, - 0xBD, 0x02, 0x40, 0xC7, 0xC0, 0x25, 0x73, 0x2D, - 0xA2, 0xA0, 0x75, 0xBC, 0x75, 0xC8, 0x36, 0x4A, - 0xB3, 0xBC, 0x1C, 0xB7, 0x3A, 0x08, 0xA2, 0xA4, - 0x05, 0x25, 0xAE, 0x29, 0x46, 0x07, 0x00, 0xB7, - 0xB7, 0x25, 0xA2, 0xA4, 0x06, 0x65, 0xAD, 0x29, - 0x46, 0x04, 0x00, 0x0C, 0x0A, 0xE5, 0xAC, 0x29, - 0xA8, 0x46, 0xB8, 0x36, 0xC2, 0xA0, 0x76, 0x25, - 0x70, 0x2D, 0xA5, 0x02, 0x00, 0xA8, 0x36, 0xE5, - 0x25, 0x2D, 0x0C, 0x0D, 0xD9, 0x36, 0x1D, 0xF0, - 0xE8, 0x46, 0x8C, 0x1E, 0xA5, 0x0D, 0x00, 0xA2, - 0xA0, 0x76, 0x25, 0x1A, 0x2D, 0xA9, 0x46, 0x56, - 0x0A, 0xFD, 0xA2, 0xA4, 0x31, 0xE5, 0xA9, 0x29, - 0x46, 0xF6, 0xFF, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x21, 0xD9, 0x03, 0x91, 0xDA, 0x03, 0xB1, 0xDB, - 0x03, 0x81, 0xDC, 0x03, 0xC0, 0x20, 0x00, 0xA2, - 0x08, 0x84, 0xC0, 0x20, 0x00, 0xD2, 0x0B, 0x84, - 0xC0, 0x20, 0x00, 0xC2, 0x09, 0x84, 0x80, 0xDD, - 0x11, 0xD0, 0xAA, 0x20, 0x00, 0xCC, 0x11, 0xC0, - 0xAA, 0x20, 0xA9, 0xE2, 0xC0, 0x20, 0x00, 0x82, - 0x08, 0x81, 0xC0, 0x20, 0x00, 0xB2, 0x0B, 0x81, - 0xC0, 0x20, 0x00, 0xA8, 0x42, 0x80, 0xBB, 0x11, - 0x92, 0x09, 0x81, 0xB0, 0x88, 0x20, 0x00, 0x99, - 0x11, 0x90, 0x88, 0x20, 0x89, 0xF2, 0xE5, 0x73, - 0x24, 0x31, 0xDD, 0x03, 0x98, 0x42, 0x0C, 0x0B, - 0xA2, 0x09, 0x70, 0x92, 0x09, 0x71, 0xB2, 0x42, - 0x14, 0x80, 0x99, 0x11, 0xA0, 0x99, 0x20, 0x16, - 0x79, 0x04, 0xC0, 0x20, 0x00, 0xB8, 0x03, 0x9A, - 0xBB, 0x0B, 0xBB, 0xB9, 0x92, 0xA1, 0xDE, 0x03, - 0xA5, 0xFF, 0x20, 0xB8, 0x42, 0xB2, 0x0B, 0x75, - 0x9C, 0x9B, 0xC0, 0x20, 0x00, 0xA1, 0xDF, 0x03, - 0xD8, 0x03, 0xB0, 0xCB, 0x11, 0xB0, 0xCC, 0xC0, - 0xB0, 0xCC, 0xA0, 0xD0, 0xCC, 0xB0, 0x0B, 0xCC, - 0xC9, 0xD2, 0x65, 0xFD, 0x20, 0xA1, 0xE0, 0x03, - 0x0C, 0x1E, 0xE2, 0x62, 0x10, 0xC0, 0x20, 0x00, - 0xD8, 0x03, 0xD2, 0x62, 0x14, 0x25, 0xFC, 0x20, - 0x1D, 0xF0, 0xC0, 0x20, 0x00, 0xB8, 0x03, 0x06, - 0xEE, 0xFF, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x21, 0xD9, 0x03, 0x88, 0x42, 0x16, 0x28, 0x08, - 0xA2, 0xC2, 0x44, 0xE5, 0xFB, 0x20, 0xB8, 0x42, - 0x92, 0x0B, 0x74, 0x26, 0x19, 0x14, 0xA2, 0xC9, - 0xFE, 0x16, 0x9A, 0x07, 0xC2, 0xC9, 0xFD, 0x16, - 0xAC, 0x06, 0xA2, 0xCB, 0x48, 0x25, 0x1A, 0x00, - 0x46, 0x01, 0x00, 0xA2, 0xCB, 0x50, 0xA5, 0x19, - 0x00, 0xA1, 0xDE, 0x03, 0x65, 0xF9, 0x20, 0xA1, - 0xDF, 0x03, 0xE5, 0xF8, 0x20, 0xE1, 0xDA, 0x03, - 0x81, 0xDB, 0x03, 0xA1, 0xDC, 0x03, 0xD8, 0xE2, - 0xC0, 0x20, 0x00, 0xD2, 0x4A, 0x84, 0xC8, 0xE2, - 0xC0, 0x20, 0x00, 0xC0, 0xC8, 0x41, 0xC2, 0x48, - 0x84, 0xB8, 0xE2, 0xC0, 0x20, 0x00, 0xB0, 0xB0, - 0xF5, 0xB2, 0x4E, 0x84, 0x98, 0xF2, 0xC0, 0x20, - 0x00, 0x92, 0x4A, 0x81, 0xF8, 0xF2, 0xC0, 0x20, - 0x00, 0xF0, 0xF8, 0x41, 0xF2, 0x48, 0x81, 0xD8, - 0xF2, 0xC0, 0x20, 0x00, 0xD0, 0xD0, 0xF5, 0xD2, - 0x4E, 0x81, 0xA8, 0x42, 0x25, 0x0F, 0x2D, 0x0C, - 0x0E, 0xE9, 0x42, 0x1D, 0xF0, 0xA2, 0xCB, 0x60, - 0xA5, 0x13, 0x00, 0x86, 0xE6, 0xFF, 0xA2, 0xCB, - 0x58, 0xE5, 0x12, 0x00, 0x46, 0xE4, 0xFF, 0x00, - 0x00, 0x36, 0x41, 0x00, 0xB1, 0xD9, 0x03, 0x0C, - 0x1D, 0x98, 0x4B, 0xA2, 0x0B, 0x14, 0xAC, 0x79, - 0xC1, 0xDD, 0x03, 0xEC, 0x4A, 0xA2, 0x09, 0x72, - 0xE2, 0x09, 0x73, 0xD2, 0x4B, 0x14, 0x80, 0x9E, - 0x11, 0xA0, 0x99, 0x20, 0xBC, 0xD9, 0xC0, 0x20, - 0x00, 0xA8, 0x0C, 0x9A, 0x9A, 0x0B, 0x99, 0x99, - 0x32, 0xD2, 0x6B, 0x10, 0xAD, 0x02, 0xA5, 0xED, - 0x20, 0x1D, 0xF0, 0x66, 0x1A, 0xF2, 0xE2, 0x09, - 0x71, 0xA2, 0x09, 0x70, 0x80, 0x9E, 0x11, 0xA0, - 0x99, 0x20, 0x0C, 0x0E, 0xE2, 0x4B, 0x14, 0x8C, - 0xA9, 0xC0, 0x20, 0x00, 0xA8, 0x0C, 0x9A, 0x9A, - 0x0B, 0x99, 0x46, 0xF4, 0xFF, 0xC0, 0x20, 0x00, - 0x98, 0x0C, 0x46, 0xF2, 0xFF, 0xC0, 0x20, 0x00, - 0x98, 0x0C, 0x46, 0xF0, 0xFF, 0x36, 0x41, 0x00, - 0x31, 0xD9, 0x03, 0xB8, 0x43, 0x92, 0x03, 0x14, - 0x16, 0xFB, 0x09, 0xFC, 0x99, 0x82, 0x0B, 0x71, - 0xA2, 0x0B, 0x70, 0x80, 0x88, 0x11, 0xA0, 0x88, - 0x20, 0xAC, 0xB8, 0xC2, 0x0B, 0x68, 0x92, 0x0B, - 0x6B, 0xA2, 0x0B, 0x6A, 0x80, 0x99, 0x11, 0xA0, - 0x99, 0x20, 0xA2, 0x0B, 0x69, 0x80, 0x99, 0x11, - 0xA0, 0x99, 0x20, 0xA2, 0x23, 0x10, 0x80, 0x99, - 0x11, 0xC0, 0x99, 0x20, 0xA7, 0x09, 0x6D, 0xA2, - 0xCB, 0x50, 0x65, 0x07, 0x00, 0xC6, 0x10, 0x00, - 0x66, 0x19, 0x40, 0xA2, 0x0B, 0x73, 0xC2, 0x0B, - 0x72, 0x80, 0xAA, 0x11, 0xC0, 0xAA, 0x20, 0xBC, - 0x1A, 0xE2, 0x0B, 0x6C, 0xC2, 0x0B, 0x6F, 0xD2, - 0x0B, 0x6E, 0x80, 0xCC, 0x11, 0xD0, 0xCC, 0x20, - 0xD2, 0x0B, 0x6D, 0x80, 0xCC, 0x11, 0xD0, 0xCC, - 0x20, 0xD2, 0x23, 0x10, 0x80, 0xCC, 0x11, 0xE0, - 0xCC, 0x20, 0xD7, 0x0C, 0x08, 0xA2, 0xCB, 0x60, - 0xA5, 0x03, 0x00, 0x46, 0x01, 0x00, 0xA2, 0xCB, - 0x58, 0xE5, 0x02, 0x00, 0xAD, 0x02, 0xD1, 0xDD, - 0x03, 0x82, 0x23, 0x10, 0x0C, 0x1F, 0xF0, 0x88, - 0x11, 0xED, 0x08, 0x80, 0xEF, 0x83, 0xE2, 0x63, - 0x10, 0xC0, 0x20, 0x00, 0xD8, 0x0D, 0xD9, 0x32, - 0xA5, 0xDF, 0x20, 0x1D, 0xF0, 0xA2, 0xCB, 0x48, - 0xA5, 0x00, 0x00, 0x46, 0xF5, 0xFF, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x4B, 0xA2, 0x25, 0x28, - 0x2D, 0x3D, 0x0A, 0xAD, 0x02, 0xA5, 0x27, 0x2D, - 0xB1, 0xE1, 0x03, 0xC1, 0xE2, 0x03, 0xC0, 0x20, - 0x00, 0x82, 0x0B, 0x03, 0xC0, 0x20, 0x00, 0x30, - 0x88, 0x10, 0x30, 0x38, 0x41, 0x80, 0x8A, 0x20, - 0xA0, 0xA8, 0x41, 0x82, 0x4B, 0x03, 0xB2, 0xDB, - 0x20, 0xC7, 0x9B, 0xE1, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0xA5, 0xDF, 0xFF, 0x1D, - 0xF0, 0x36, 0x41, 0x00, 0x31, 0xE3, 0x03, 0x21, - 0xE4, 0x03, 0x29, 0x13, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x81, 0xE5, 0x03, 0x30, - 0x61, 0x00, 0x88, 0x08, 0x82, 0x08, 0x10, 0x26, - 0x48, 0x07, 0xAD, 0x02, 0x25, 0x49, 0x28, 0x06, - 0x01, 0x00, 0x0C, 0x0A, 0x65, 0xE2, 0x20, 0x30, - 0xE6, 0x13, 0x10, 0x20, 0x00, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x21, 0xE6, 0x03, 0x88, - 0x02, 0x27, 0x18, 0x09, 0xAD, 0x02, 0xE5, 0x07, - 0x00, 0xAD, 0x02, 0x65, 0xD7, 0x20, 0x1D, 0xF0, - 0x00, 0x36, 0x41, 0x00, 0x20, 0x61, 0x00, 0xA1, - 0xE6, 0x03, 0x65, 0xD6, 0x20, 0x25, 0x1D, 0x24, - 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, 0x1D, 0xF0, - 0x00, 0x36, 0x41, 0x00, 0x41, 0xE7, 0x03, 0x21, - 0xE8, 0x03, 0xC0, 0x20, 0x00, 0x32, 0x22, 0x81, - 0x98, 0x54, 0x88, 0x34, 0x30, 0x99, 0x20, 0x99, - 0x54, 0x87, 0x03, 0x06, 0x0C, 0x0A, 0xA9, 0x34, - 0x25, 0xDA, 0x21, 0x0C, 0x1D, 0x3C, 0x8C, 0xB8, - 0x44, 0xC0, 0x20, 0x00, 0xC0, 0xBB, 0x10, 0xB2, - 0x62, 0x80, 0xC0, 0x20, 0x00, 0xE2, 0x22, 0x81, - 0xE0, 0xF0, 0x04, 0x07, 0xEE, 0xF3, 0xC0, 0x20, - 0x00, 0xB1, 0xDD, 0x03, 0x32, 0x62, 0x81, 0xC0, - 0x20, 0x00, 0xB8, 0x0B, 0xA1, 0xE9, 0x03, 0x1B, - 0xBB, 0xB9, 0x4A, 0x4B, 0xAA, 0xA5, 0xCE, 0x20, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x20, 0x61, 0x00, 0x3C, 0x8A, 0x0C, 0x0B, 0x25, - 0x1A, 0x24, 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x31, 0xEA, 0x03, 0x38, 0x03, 0x8C, 0x73, 0x88, - 0x23, 0x66, 0x28, 0x03, 0x0C, 0x39, 0x99, 0x23, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x31, 0xEB, 0x03, 0x0C, 0x02, 0x22, 0x43, 0x00, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0xBD, 0x02, 0x21, 0xEA, 0x03, 0x28, 0x02, 0x1C, - 0x8C, 0xCB, 0xA2, 0xE5, 0x2E, 0x2D, 0xD1, 0xEC, - 0x03, 0x2C, 0x0B, 0x92, 0x12, 0x11, 0x0C, 0x1C, - 0xDC, 0x79, 0xA2, 0x12, 0x0F, 0x92, 0x12, 0x0E, - 0xA0, 0xA0, 0xE4, 0x90, 0xAA, 0xC0, 0xA2, 0xCA, - 0xC2, 0xA0, 0xA1, 0x21, 0xAA, 0x99, 0x8B, 0x99, - 0x92, 0x52, 0x11, 0xB2, 0x52, 0x13, 0xC9, 0x22, - 0xD0, 0xD9, 0x10, 0xD2, 0x52, 0x11, 0x1D, 0xF0, - 0x00, 0x36, 0x41, 0x00, 0xD8, 0x22, 0x31, 0xEA, - 0x03, 0x0C, 0x1E, 0x38, 0x03, 0x0C, 0x0C, 0xAD, - 0x03, 0xF2, 0x13, 0x13, 0xB2, 0x13, 0x10, 0xF0, - 0xCE, 0x83, 0xDA, 0xBB, 0x25, 0x17, 0x00, 0x0C, - 0x45, 0xA8, 0x23, 0x92, 0x13, 0x13, 0x0C, 0x04, - 0x8C, 0x69, 0x0B, 0x99, 0x90, 0x90, 0xF4, 0x92, - 0x53, 0x13, 0xF6, 0x8A, 0x2F, 0xB1, 0xED, 0x03, - 0xB0, 0xBA, 0xA0, 0xB8, 0x0B, 0xA0, 0x0B, 0x00, - 0xC8, 0x22, 0xB2, 0x13, 0x11, 0xAD, 0x03, 0xCA, - 0xBB, 0x65, 0x21, 0x00, 0xD2, 0x13, 0x06, 0xF1, - 0xEB, 0x03, 0xD7, 0x3A, 0x0F, 0x0C, 0x29, 0x92, - 0x4F, 0x00, 0xE2, 0x13, 0x0F, 0xE0, 0xEF, 0x04, - 0x16, 0xBE, 0x10, 0x99, 0x23, 0x0C, 0x14, 0x2D, - 0x04, 0x1D, 0xF0, 0x49, 0x23, 0x0C, 0x24, 0x06, - 0xFD, 0xFF, 0xAD, 0x03, 0xE5, 0x1B, 0x00, 0x82, - 0x13, 0x09, 0xB2, 0x13, 0x08, 0x87, 0x3A, 0x02, - 0x06, 0x24, 0x00, 0xC8, 0x22, 0xB2, 0x13, 0x11, - 0xAD, 0x03, 0xCA, 0xBB, 0x65, 0x1D, 0x00, 0xD2, - 0x13, 0x07, 0xD7, 0x3A, 0x02, 0xC6, 0x36, 0x00, - 0xE2, 0x13, 0x14, 0x0B, 0xEE, 0xE0, 0xE0, 0xF4, - 0xE2, 0x53, 0x14, 0x56, 0xEE, 0x0D, 0x0C, 0x24, - 0x0C, 0x7F, 0xF9, 0x23, 0xC6, 0xED, 0xFF, 0xAD, - 0x03, 0xE5, 0x17, 0x00, 0x82, 0x13, 0x08, 0x87, - 0x3A, 0x6A, 0x59, 0x23, 0x42, 0x53, 0x16, 0x92, - 0x13, 0x0A, 0x92, 0x53, 0x14, 0x0C, 0x04, 0x06, - 0xE7, 0xFF, 0xAD, 0x03, 0x65, 0x16, 0x00, 0xB2, - 0x13, 0x08, 0xB7, 0x3A, 0x29, 0xC2, 0x13, 0x14, - 0x0B, 0xCC, 0xC0, 0xC0, 0xF4, 0xC2, 0x53, 0x14, - 0xEC, 0xBC, 0x0C, 0x6D, 0xE2, 0x13, 0x0B, 0xE2, - 0x53, 0x14, 0xD9, 0x23, 0xC6, 0x07, 0x00, 0xDC, - 0xC9, 0x59, 0x23, 0x42, 0x53, 0x16, 0xF2, 0x13, - 0x0A, 0xF2, 0x53, 0x14, 0xC6, 0x03, 0x00, 0x0C, - 0x58, 0x92, 0x13, 0x0D, 0xA2, 0x13, 0x0C, 0xA2, - 0x53, 0x14, 0x92, 0x53, 0x15, 0x89, 0x23, 0x0C, - 0x04, 0x86, 0xD4, 0xFF, 0xB7, 0x3A, 0x05, 0xC2, - 0x13, 0x0B, 0xC2, 0x53, 0x14, 0x42, 0x53, 0x16, - 0x0C, 0x04, 0x46, 0xD0, 0xFF, 0x92, 0x13, 0x15, - 0x66, 0x19, 0x09, 0x0C, 0x34, 0x0B, 0xD9, 0xD2, - 0x53, 0x15, 0x46, 0xCC, 0xFF, 0xCC, 0x39, 0x0C, - 0x14, 0x86, 0x01, 0x00, 0x0C, 0x04, 0x0B, 0xE9, - 0xE2, 0x53, 0x15, 0xC8, 0x22, 0xB2, 0x13, 0x11, - 0xAD, 0x03, 0xCA, 0xBB, 0x65, 0x11, 0x00, 0xD2, - 0x13, 0x07, 0xD7, 0xBA, 0x10, 0xE2, 0x13, 0x14, - 0x0B, 0xEE, 0xE0, 0xE0, 0xF4, 0xE2, 0x53, 0x14, - 0xE0, 0x45, 0x83, 0x06, 0xC0, 0xFF, 0xF2, 0x13, - 0x0D, 0xF2, 0x53, 0x14, 0xC6, 0xBD, 0xFF, 0x0C, - 0x39, 0x86, 0xBB, 0xFF, 0x82, 0x13, 0x06, 0x87, - 0x3A, 0x05, 0x92, 0x13, 0x0B, 0x92, 0x53, 0x14, - 0x0C, 0x04, 0x46, 0xB8, 0xFF, 0x0C, 0x04, 0x06, - 0xB7, 0xFF, 0x00, 0x00, 0x00, 0x36, 0x61, 0x00, - 0xB2, 0xA0, 0x94, 0xA2, 0xC2, 0x34, 0x92, 0xC2, - 0x54, 0x99, 0x01, 0xA9, 0x11, 0xBC, 0xB4, 0x68, - 0x11, 0x5D, 0x09, 0x1C, 0x04, 0x72, 0x12, 0x12, - 0x82, 0xA0, 0x94, 0xC0, 0x77, 0x11, 0x7A, 0x72, - 0x8A, 0x77, 0x82, 0x16, 0x00, 0xB2, 0x07, 0x00, - 0x1B, 0x77, 0xAD, 0x0B, 0xB0, 0x88, 0xC0, 0x82, - 0x56, 0x00, 0x2B, 0x66, 0xA5, 0x35, 0x2D, 0x98, - 0x05, 0x0B, 0x44, 0xA0, 0x99, 0xC0, 0x99, 0x05, - 0x4B, 0x55, 0x56, 0xC4, 0xFD, 0x98, 0x01, 0xA8, - 0x11, 0xB2, 0xA0, 0x94, 0x5D, 0x09, 0x6D, 0x0A, - 0x72, 0x12, 0x12, 0x1C, 0x04, 0xC0, 0x77, 0x11, - 0x7A, 0x72, 0xBA, 0x77, 0xD2, 0x03, 0x01, 0xE2, - 0x03, 0x03, 0xC2, 0x03, 0x02, 0xB2, 0x03, 0x00, - 0xEA, 0xCC, 0xDA, 0xBB, 0xCA, 0xBB, 0xB0, 0xB2, - 0x41, 0xAD, 0x0B, 0xB2, 0x47, 0x00, 0x82, 0x16, - 0x00, 0x1B, 0x77, 0xBA, 0x88, 0x82, 0x56, 0x00, - 0x2B, 0x66, 0xA5, 0x30, 0x2D, 0x8B, 0x33, 0xF8, - 0x05, 0x0B, 0x44, 0xAA, 0xFF, 0xF9, 0x05, 0x4B, - 0x55, 0x56, 0x74, 0xFC, 0x82, 0x12, 0x12, 0x1B, - 0x88, 0x80, 0x80, 0x44, 0x82, 0x52, 0x12, 0x1D, - 0xF0, 0x36, 0x41, 0x00, 0x32, 0xC2, 0x34, 0x1C, - 0x05, 0x0C, 0x04, 0xB2, 0x13, 0x00, 0xAD, 0x0B, - 0xE5, 0x2D, 0x2D, 0x2B, 0x33, 0x0B, 0x55, 0xA0, - 0x95, 0x41, 0x82, 0x22, 0x15, 0x4B, 0x22, 0x90, - 0x88, 0xC0, 0x80, 0x85, 0x41, 0x8A, 0x44, 0x56, - 0x05, 0xFE, 0x40, 0x24, 0x41, 0x1D, 0xF0, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x1C, 0x07, 0x0C, 0x06, - 0x0C, 0x05, 0xB2, 0xC3, 0x81, 0x42, 0x03, 0x00, - 0xB2, 0x0B, 0x7E, 0xC2, 0x03, 0x01, 0x47, 0xBB, - 0x0C, 0x47, 0xBC, 0x11, 0x4D, 0x0B, 0xC7, 0xBB, - 0x0C, 0x4D, 0x0C, 0xC6, 0x01, 0x00, 0x47, 0x3C, - 0x04, 0xC7, 0xBB, 0x01, 0x4D, 0x0B, 0xAD, 0x04, - 0xBD, 0x04, 0xA5, 0x28, 0x2D, 0xAA, 0x66, 0x5A, - 0x54, 0x0B, 0x77, 0x4B, 0x33, 0xB2, 0xC3, 0x81, - 0x56, 0x97, 0xFC, 0xAD, 0x05, 0xBD, 0x05, 0x65, - 0x27, 0x2D, 0xD2, 0x12, 0x16, 0xA0, 0x94, 0x41, - 0x90, 0x96, 0xC0, 0xD0, 0xCD, 0xF0, 0x90, 0x94, - 0x41, 0x90, 0xE3, 0x41, 0xC0, 0xC3, 0x21, 0xEA, - 0xCC, 0xD0, 0x9C, 0x93, 0x92, 0x52, 0x16, 0x2D, - 0x09, 0x1D, 0xF0, 0x00, 0x00, 0x24, 0x00, 0x00, - 0x00, 0x64, 0x11, 0x02, 0x60, 0x04, 0x11, 0x02, - 0x60, 0xEC, 0x18, 0x00, 0x60, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x13, 0x02, - 0x60, 0xC8, 0x14, 0x02, 0x60, 0xD4, 0x13, 0x02, - 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x19, 0x00, - 0x60, 0x1C, 0x19, 0x00, 0x60, 0x04, 0x19, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x19, 0x00, - 0x60, 0x2C, 0x19, 0x00, 0x60, 0x08, 0x19, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x48, 0x19, 0x00, 0x60, 0x48, 0x19, 0x00, - 0x60, 0x0C, 0x19, 0x00, 0x60, 0x00, 0x00, 0x00, - 0x00, 0x94, 0x15, 0x02, 0x60, 0x5C, 0x19, 0x00, - 0x60, 0x5C, 0x19, 0x00, 0x60, 0x58, 0x19, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x00, 0xC4, 0x15, 0x02, - 0x60, 0xCC, 0x15, 0x02, 0x60, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x6C, 0x19, 0x00, 0x60, 0x70, 0x19, 0x00, - 0x60, 0xB0, 0x19, 0x00, 0x60, 0x94, 0x02, 0x00, - 0x00, 0x84, 0x16, 0x02, 0x60, 0x5F, 0x16, 0x02, - 0x60, 0x84, 0x16, 0x02, 0x60, 0x0E, 0x17, 0x02, - 0x60, 0xE9, 0x16, 0x02, 0x60, 0xCE, 0x16, 0x02, - 0x60, 0x91, 0x16, 0x02, 0x60, 0x8A, 0x16, 0x02, - 0x60, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x0C, 0x00, - 0x60, 0xD4, 0x0C, 0x00, 0x60, 0x10, 0xB0, 0x02, - 0x00, 0xC0, 0x19, 0x00, 0x60, 0x20, 0x01, 0x00, - 0x00, 0xB0, 0x0A, 0x00, 0x60, 0x04, 0x10, 0x02, - 0x60, 0xA0, 0x0A, 0x00, 0x60, 0xA4, 0x10, 0x02, - 0x60, 0xF8, 0x10, 0x02, 0x60, 0x6C, 0x10, 0x02, - 0x60, 0x6C, 0x06, 0x00, 0x60, 0x20, 0x16, 0x02, - 0x60, 0xF4, 0x05, 0x00, 0x60, 0x4C, 0x10, 0x02, - 0x60, 0xA8, 0x0B, 0x00, 0x60, 0xF8, 0x18, 0x00, - 0x60, 0x68, 0x0A, 0x00, 0x60, 0x28, 0x8F, 0x04, - 0x60, 0x48, 0x08, 0x00, 0x60, 0xE0, 0x14, 0x02, - 0x60, 0xAC, 0x06, 0x00, 0x60, 0x20, 0x15, 0x02, - 0x60, 0x38, 0x15, 0x02, 0x60, 0xD8, 0x56, 0x04, - 0x60, 0x36, 0x41, 0x00, 0x81, 0x6F, 0x06, 0xB1, - 0x6D, 0x06, 0x0C, 0x6A, 0x91, 0x6E, 0x06, 0xA2, - 0x4B, 0x00, 0x89, 0x09, 0x25, 0x02, 0x00, 0x65, - 0x07, 0x00, 0x25, 0x09, 0x00, 0xE5, 0x07, 0x00, - 0x65, 0x02, 0x00, 0x65, 0x05, 0x00, 0xA5, 0x6E, - 0xFF, 0xA1, 0x70, 0x06, 0xB1, 0x71, 0x06, 0x65, - 0xB3, 0x2C, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, - 0x31, 0x72, 0x06, 0x21, 0x73, 0x06, 0x22, 0x63, - 0x75, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x0C, 0x8F, 0xB1, 0x72, 0x06, 0xA1, 0x77, 0x06, - 0x91, 0x78, 0x06, 0x81, 0x79, 0x06, 0x31, 0x7A, - 0x06, 0x21, 0x7B, 0x06, 0xC1, 0x76, 0x06, 0xD1, - 0x74, 0x06, 0xE1, 0x75, 0x06, 0xE9, 0xFD, 0xC2, - 0x6D, 0x19, 0x29, 0x83, 0x89, 0x39, 0xA2, 0x6B, - 0x6B, 0xF2, 0x5D, 0x1C, 0x1D, 0xF0, 0x00, 0x00, - 0x00, 0x36, 0x41, 0x00, 0x31, 0x7C, 0x06, 0x21, - 0x7D, 0x06, 0x48, 0x03, 0x49, 0x22, 0x29, 0x03, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x31, 0x7E, 0x06, 0x21, 0x7F, 0x06, 0x29, 0x13, - 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x31, 0x80, 0x06, 0x21, 0x81, 0x06, 0x22, 0x63, - 0x19, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, - 0x91, 0x83, 0x06, 0x21, 0x85, 0x06, 0x31, 0x82, - 0x06, 0x81, 0x84, 0x06, 0x89, 0xC3, 0x29, 0xA3, - 0x99, 0xB3, 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x04, 0x00, 0x18, 0x1A, 0x02, - 0x60, + 0x06, 0x00, 0x00, 0xE4, 0x0B, 0x00, 0x0F, 0x00, + 0x60, 0xD8, 0x0C, 0x00, 0x60, 0xD4, 0x0C, 0x00, + 0x60, 0xB0, 0x0A, 0x00, 0x60, 0x58, 0xB3, 0x04, + 0x60, 0x84, 0x05, 0x00, 0x60, 0xA4, 0xED, 0x04, + 0x60, 0x8C, 0x04, 0x00, 0x00, 0x00, 0x0F, 0x00, + 0x60, 0xC0, 0x0A, 0x00, 0x00, 0xA0, 0x0A, 0x00, + 0x60, 0xD0, 0x38, 0x04, 0x60, 0xB4, 0x39, 0x04, + 0x60, 0x58, 0xB4, 0x04, 0x60, 0xFC, 0x0C, 0x00, + 0x60, 0x80, 0x19, 0x00, 0x60, 0xC8, 0x0D, 0x00, + 0x60, 0x9C, 0x0B, 0x00, 0x60, 0xF4, 0x18, 0x00, + 0x60, 0xCC, 0x08, 0x00, 0x60, 0xF8, 0x18, 0x00, + 0x60, 0xA8, 0x0B, 0x00, 0x60, 0xE4, 0x06, 0x00, + 0x60, 0x54, 0x11, 0x02, 0x60, 0xAC, 0x06, 0x00, + 0x60, 0x48, 0x11, 0x02, 0x60, 0x04, 0x19, 0x00, + 0x60, 0x80, 0x7F, 0x00, 0x38, 0x80, 0x5F, 0x00, + 0x38, 0x80, 0x3F, 0x00, 0x38, 0xDC, 0x0C, 0x00, + 0x60, 0x1C, 0x19, 0x00, 0x60, 0x2C, 0x19, 0x00, + 0x60, 0x48, 0x19, 0x00, 0x60, 0x00, 0x40, 0x00, + 0x38, 0x00, 0xA0, 0x00, 0x38, 0x68, 0x0A, 0x00, + 0x60, 0x4C, 0x3F, 0x04, 0x60, 0xC0, 0x0D, 0x00, + 0x60, 0x5C, 0x19, 0x00, 0x60, 0x18, 0x0D, 0x00, + 0x60, 0x00, 0x9E, 0x00, 0x38, 0x58, 0x19, 0x00, + 0x60, 0xB0, 0x19, 0x00, 0x60, 0x20, 0x0E, 0x00, + 0x60, 0xFC, 0xFF, 0x00, 0x00, 0x90, 0x19, 0x00, + 0x60, 0x36, 0x41, 0x00, 0x65, 0x03, 0x00, 0x25, + 0x18, 0x00, 0x65, 0x15, 0x00, 0x25, 0x06, 0x00, + 0x25, 0x54, 0x00, 0x65, 0x50, 0x00, 0x25, 0x01, + 0x00, 0x91, 0xC0, 0x03, 0xA1, 0xC1, 0x03, 0x0C, + 0x08, 0x89, 0x0A, 0x82, 0x49, 0x00, 0x1D, 0xF0, + 0x00, 0x36, 0x41, 0x00, 0x31, 0xC2, 0x03, 0x21, + 0xC3, 0x03, 0x22, 0x63, 0x75, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0xA1, 0xC4, 0x03, 0xB1, + 0xC5, 0x03, 0xC1, 0xC6, 0x03, 0xA5, 0x8D, 0x2D, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x9C, 0x85, 0x20, 0x61, 0x00, 0xA5, 0xFA, 0xFF, + 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, 0x0C, 0x0A, + 0x65, 0xC8, 0x29, 0xA1, 0xC7, 0x03, 0xB1, 0xC8, + 0x03, 0xA5, 0x55, 0x2D, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x0C, 0xBB, 0x31, 0xC2, + 0x03, 0x21, 0xCC, 0x03, 0x81, 0xCB, 0x03, 0x91, + 0xC9, 0x03, 0xA1, 0xCA, 0x03, 0xA9, 0xF9, 0x82, + 0x69, 0x19, 0x22, 0x63, 0x6B, 0xB2, 0x59, 0x1C, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x21, 0xCD, 0x03, 0x88, 0x22, 0x37, 0x68, 0x0E, + 0xA1, 0xCE, 0x03, 0xA5, 0x7D, 0x2D, 0x98, 0x22, + 0x6C, 0x7A, 0xA0, 0x99, 0x10, 0x99, 0x22, 0xE5, + 0xA9, 0x22, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, + 0xCD, 0x04, 0xBD, 0x03, 0xAD, 0x02, 0xDD, 0x05, + 0x25, 0x3E, 0x2A, 0xAC, 0x15, 0x81, 0xCF, 0x03, + 0xA1, 0xD0, 0x03, 0x88, 0x08, 0x91, 0xCD, 0x03, + 0x82, 0x08, 0x02, 0x98, 0x29, 0xB6, 0x28, 0x06, + 0x91, 0xD1, 0x03, 0x99, 0x2A, 0x1D, 0xF0, 0x37, + 0x69, 0x05, 0x91, 0xD2, 0x03, 0x86, 0xFC, 0xFF, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0xBD, 0x03, 0xAD, 0x02, 0xCD, 0x04, 0xDD, 0x05, + 0x1C, 0x8E, 0x25, 0xA1, 0x22, 0xBC, 0x16, 0x82, + 0x12, 0x1A, 0x5A, 0xA4, 0xEC, 0xA8, 0x1C, 0x79, + 0xA7, 0x39, 0x28, 0x92, 0xA4, 0x21, 0x92, 0x52, + 0x1A, 0x06, 0x05, 0x00, 0xA1, 0xCE, 0x03, 0x25, + 0x72, 0x2D, 0xA8, 0x82, 0xA5, 0x50, 0x00, 0xB1, + 0xCD, 0x03, 0xA8, 0x2B, 0x30, 0xAA, 0x20, 0xA9, + 0x2B, 0xA8, 0x82, 0xA5, 0x35, 0x2D, 0x0C, 0x0B, + 0xB9, 0x82, 0x1D, 0xF0, 0x1C, 0x83, 0xA7, 0xB3, + 0xDA, 0x92, 0xA4, 0x22, 0x86, 0xF3, 0xFF, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x8C, 0x36, 0x0C, 0x03, + 0x32, 0x52, 0x1A, 0x1D, 0xF0, 0x36, 0x41, 0x00, + 0x65, 0x4A, 0x00, 0xAD, 0x02, 0x81, 0xD2, 0x03, + 0x89, 0x22, 0xE5, 0xBC, 0x29, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x21, 0xD3, 0x03, 0x31, + 0xD4, 0x03, 0x28, 0x22, 0x29, 0x03, 0x1D, 0xF0, + 0x00, 0x36, 0x41, 0x00, 0x21, 0xD8, 0x03, 0x31, + 0xD7, 0x03, 0x91, 0xD5, 0x03, 0x81, 0xD6, 0x03, + 0x89, 0x49, 0x29, 0x03, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x25, 0x18, 0x00, 0x1D, + 0xF0, 0x36, 0x41, 0x00, 0xA5, 0x17, 0x00, 0x65, + 0x20, 0x24, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, + 0xAD, 0x02, 0x65, 0xBE, 0x24, 0x65, 0x16, 0x00, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x61, 0xD9, 0x03, 0xCC, 0xE4, 0xA2, 0xA0, 0x76, + 0x65, 0x22, 0x2D, 0xA9, 0x36, 0xCC, 0x4A, 0xA2, + 0xA4, 0x31, 0x25, 0xB2, 0x29, 0x72, 0xA0, 0x76, + 0xD8, 0x36, 0xA2, 0xA0, 0x75, 0xAC, 0x2D, 0x4A, + 0xB3, 0xB7, 0x37, 0x0E, 0xDA, 0xA4, 0xBD, 0x02, + 0xCD, 0x03, 0x65, 0x74, 0x2D, 0xA2, 0xA0, 0x75, + 0xC6, 0x03, 0x00, 0x47, 0x3A, 0x0C, 0xDA, 0xA4, + 0xBD, 0x02, 0x40, 0xC7, 0xC0, 0x25, 0x73, 0x2D, + 0xA2, 0xA0, 0x75, 0xBC, 0x75, 0xC8, 0x36, 0x4A, + 0xB3, 0xBC, 0x1C, 0xB7, 0x3A, 0x08, 0xA2, 0xA4, + 0x05, 0x25, 0xAE, 0x29, 0x46, 0x07, 0x00, 0xB7, + 0xB7, 0x25, 0xA2, 0xA4, 0x06, 0x65, 0xAD, 0x29, + 0x46, 0x04, 0x00, 0x0C, 0x0A, 0xE5, 0xAC, 0x29, + 0xA8, 0x46, 0xB8, 0x36, 0xC2, 0xA0, 0x76, 0x25, + 0x70, 0x2D, 0xA5, 0x02, 0x00, 0xA8, 0x36, 0xE5, + 0x25, 0x2D, 0x0C, 0x0D, 0xD9, 0x36, 0x1D, 0xF0, + 0xE8, 0x46, 0x8C, 0x1E, 0xA5, 0x0D, 0x00, 0xA2, + 0xA0, 0x76, 0x25, 0x1A, 0x2D, 0xA9, 0x46, 0x56, + 0x0A, 0xFD, 0xA2, 0xA4, 0x31, 0xE5, 0xA9, 0x29, + 0x46, 0xF6, 0xFF, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x21, 0xD9, 0x03, 0x91, 0xDA, 0x03, 0xB1, 0xDB, + 0x03, 0x81, 0xDC, 0x03, 0xC0, 0x20, 0x00, 0xA2, + 0x08, 0x84, 0xC0, 0x20, 0x00, 0xD2, 0x0B, 0x84, + 0xC0, 0x20, 0x00, 0xC2, 0x09, 0x84, 0x80, 0xDD, + 0x11, 0xD0, 0xAA, 0x20, 0x00, 0xCC, 0x11, 0xC0, + 0xAA, 0x20, 0xA9, 0xE2, 0xC0, 0x20, 0x00, 0x82, + 0x08, 0x81, 0xC0, 0x20, 0x00, 0xB2, 0x0B, 0x81, + 0xC0, 0x20, 0x00, 0xA8, 0x42, 0x80, 0xBB, 0x11, + 0x92, 0x09, 0x81, 0xB0, 0x88, 0x20, 0x00, 0x99, + 0x11, 0x90, 0x88, 0x20, 0x89, 0xF2, 0xE5, 0x73, + 0x24, 0x31, 0xDD, 0x03, 0x98, 0x42, 0x0C, 0x0B, + 0xA2, 0x09, 0x70, 0x92, 0x09, 0x71, 0xB2, 0x42, + 0x14, 0x80, 0x99, 0x11, 0xA0, 0x99, 0x20, 0x16, + 0x79, 0x04, 0xC0, 0x20, 0x00, 0xB8, 0x03, 0x9A, + 0xBB, 0x0B, 0xBB, 0xB9, 0x92, 0xA1, 0xDE, 0x03, + 0xA5, 0xFF, 0x20, 0xB8, 0x42, 0xB2, 0x0B, 0x75, + 0x9C, 0x9B, 0xC0, 0x20, 0x00, 0xA1, 0xDF, 0x03, + 0xD8, 0x03, 0xB0, 0xCB, 0x11, 0xB0, 0xCC, 0xC0, + 0xB0, 0xCC, 0xA0, 0xD0, 0xCC, 0xB0, 0x0B, 0xCC, + 0xC9, 0xD2, 0x65, 0xFD, 0x20, 0xA1, 0xE0, 0x03, + 0x0C, 0x1E, 0xE2, 0x62, 0x10, 0xC0, 0x20, 0x00, + 0xD8, 0x03, 0xD2, 0x62, 0x14, 0x25, 0xFC, 0x20, + 0x1D, 0xF0, 0xC0, 0x20, 0x00, 0xB8, 0x03, 0x06, + 0xEE, 0xFF, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x21, 0xD9, 0x03, 0x88, 0x42, 0x16, 0x28, 0x08, + 0xA2, 0xC2, 0x44, 0xE5, 0xFB, 0x20, 0xB8, 0x42, + 0x92, 0x0B, 0x74, 0x26, 0x19, 0x14, 0xA2, 0xC9, + 0xFE, 0x16, 0x9A, 0x07, 0xC2, 0xC9, 0xFD, 0x16, + 0xAC, 0x06, 0xA2, 0xCB, 0x48, 0x25, 0x1A, 0x00, + 0x46, 0x01, 0x00, 0xA2, 0xCB, 0x50, 0xA5, 0x19, + 0x00, 0xA1, 0xDE, 0x03, 0x65, 0xF9, 0x20, 0xA1, + 0xDF, 0x03, 0xE5, 0xF8, 0x20, 0xE1, 0xDA, 0x03, + 0x81, 0xDB, 0x03, 0xA1, 0xDC, 0x03, 0xD8, 0xE2, + 0xC0, 0x20, 0x00, 0xD2, 0x4A, 0x84, 0xC8, 0xE2, + 0xC0, 0x20, 0x00, 0xC0, 0xC8, 0x41, 0xC2, 0x48, + 0x84, 0xB8, 0xE2, 0xC0, 0x20, 0x00, 0xB0, 0xB0, + 0xF5, 0xB2, 0x4E, 0x84, 0x98, 0xF2, 0xC0, 0x20, + 0x00, 0x92, 0x4A, 0x81, 0xF8, 0xF2, 0xC0, 0x20, + 0x00, 0xF0, 0xF8, 0x41, 0xF2, 0x48, 0x81, 0xD8, + 0xF2, 0xC0, 0x20, 0x00, 0xD0, 0xD0, 0xF5, 0xD2, + 0x4E, 0x81, 0xA8, 0x42, 0x25, 0x0F, 0x2D, 0x0C, + 0x0E, 0xE9, 0x42, 0x1D, 0xF0, 0xA2, 0xCB, 0x60, + 0xA5, 0x13, 0x00, 0x86, 0xE6, 0xFF, 0xA2, 0xCB, + 0x58, 0xE5, 0x12, 0x00, 0x46, 0xE4, 0xFF, 0x00, + 0x00, 0x36, 0x41, 0x00, 0xB1, 0xD9, 0x03, 0x0C, + 0x1D, 0x98, 0x4B, 0xA2, 0x0B, 0x14, 0xAC, 0x79, + 0xC1, 0xDD, 0x03, 0xEC, 0x4A, 0xA2, 0x09, 0x72, + 0xE2, 0x09, 0x73, 0xD2, 0x4B, 0x14, 0x80, 0x9E, + 0x11, 0xA0, 0x99, 0x20, 0xBC, 0xD9, 0xC0, 0x20, + 0x00, 0xA8, 0x0C, 0x9A, 0x9A, 0x0B, 0x99, 0x99, + 0x32, 0xD2, 0x6B, 0x10, 0xAD, 0x02, 0xA5, 0xED, + 0x20, 0x1D, 0xF0, 0x66, 0x1A, 0xF2, 0xE2, 0x09, + 0x71, 0xA2, 0x09, 0x70, 0x80, 0x9E, 0x11, 0xA0, + 0x99, 0x20, 0x0C, 0x0E, 0xE2, 0x4B, 0x14, 0x8C, + 0xA9, 0xC0, 0x20, 0x00, 0xA8, 0x0C, 0x9A, 0x9A, + 0x0B, 0x99, 0x46, 0xF4, 0xFF, 0xC0, 0x20, 0x00, + 0x98, 0x0C, 0x46, 0xF2, 0xFF, 0xC0, 0x20, 0x00, + 0x98, 0x0C, 0x46, 0xF0, 0xFF, 0x36, 0x41, 0x00, + 0x31, 0xD9, 0x03, 0xB8, 0x43, 0x92, 0x03, 0x14, + 0x16, 0xFB, 0x09, 0xFC, 0x99, 0x82, 0x0B, 0x71, + 0xA2, 0x0B, 0x70, 0x80, 0x88, 0x11, 0xA0, 0x88, + 0x20, 0xAC, 0xB8, 0xC2, 0x0B, 0x68, 0x92, 0x0B, + 0x6B, 0xA2, 0x0B, 0x6A, 0x80, 0x99, 0x11, 0xA0, + 0x99, 0x20, 0xA2, 0x0B, 0x69, 0x80, 0x99, 0x11, + 0xA0, 0x99, 0x20, 0xA2, 0x23, 0x10, 0x80, 0x99, + 0x11, 0xC0, 0x99, 0x20, 0xA7, 0x09, 0x6D, 0xA2, + 0xCB, 0x50, 0x65, 0x07, 0x00, 0xC6, 0x10, 0x00, + 0x66, 0x19, 0x40, 0xA2, 0x0B, 0x73, 0xC2, 0x0B, + 0x72, 0x80, 0xAA, 0x11, 0xC0, 0xAA, 0x20, 0xBC, + 0x1A, 0xE2, 0x0B, 0x6C, 0xC2, 0x0B, 0x6F, 0xD2, + 0x0B, 0x6E, 0x80, 0xCC, 0x11, 0xD0, 0xCC, 0x20, + 0xD2, 0x0B, 0x6D, 0x80, 0xCC, 0x11, 0xD0, 0xCC, + 0x20, 0xD2, 0x23, 0x10, 0x80, 0xCC, 0x11, 0xE0, + 0xCC, 0x20, 0xD7, 0x0C, 0x08, 0xA2, 0xCB, 0x60, + 0xA5, 0x03, 0x00, 0x46, 0x01, 0x00, 0xA2, 0xCB, + 0x58, 0xE5, 0x02, 0x00, 0xAD, 0x02, 0xD1, 0xDD, + 0x03, 0x82, 0x23, 0x10, 0x0C, 0x1F, 0xF0, 0x88, + 0x11, 0xED, 0x08, 0x80, 0xEF, 0x83, 0xE2, 0x63, + 0x10, 0xC0, 0x20, 0x00, 0xD8, 0x0D, 0xD9, 0x32, + 0xA5, 0xDF, 0x20, 0x1D, 0xF0, 0xA2, 0xCB, 0x48, + 0xA5, 0x00, 0x00, 0x46, 0xF5, 0xFF, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x4B, 0xA2, 0x25, 0x28, + 0x2D, 0x3D, 0x0A, 0xAD, 0x02, 0xA5, 0x27, 0x2D, + 0xB1, 0xE1, 0x03, 0xC1, 0xE2, 0x03, 0xC0, 0x20, + 0x00, 0x82, 0x0B, 0x03, 0xC0, 0x20, 0x00, 0x30, + 0x88, 0x10, 0x30, 0x38, 0x41, 0x80, 0x8A, 0x20, + 0xA0, 0xA8, 0x41, 0x82, 0x4B, 0x03, 0xB2, 0xDB, + 0x20, 0xC7, 0x9B, 0xE1, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0xA5, 0xDF, 0xFF, 0x1D, + 0xF0, 0x36, 0x41, 0x00, 0x31, 0xE3, 0x03, 0x21, + 0xE4, 0x03, 0x29, 0x13, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x81, 0xE5, 0x03, 0x30, + 0x61, 0x00, 0x88, 0x08, 0x82, 0x08, 0x10, 0x26, + 0x48, 0x07, 0xAD, 0x02, 0x25, 0x49, 0x28, 0x06, + 0x01, 0x00, 0x0C, 0x0A, 0x65, 0xE2, 0x20, 0x30, + 0xE6, 0x13, 0x10, 0x20, 0x00, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x21, 0xE6, 0x03, 0x88, + 0x02, 0x27, 0x18, 0x09, 0xAD, 0x02, 0xE5, 0x07, + 0x00, 0xAD, 0x02, 0x65, 0xD7, 0x20, 0x1D, 0xF0, + 0x00, 0x36, 0x41, 0x00, 0x20, 0x61, 0x00, 0xA1, + 0xE6, 0x03, 0x65, 0xD6, 0x20, 0x25, 0x1D, 0x24, + 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, 0x1D, 0xF0, + 0x00, 0x36, 0x41, 0x00, 0x41, 0xE7, 0x03, 0x21, + 0xE8, 0x03, 0xC0, 0x20, 0x00, 0x32, 0x22, 0x81, + 0x98, 0x54, 0x88, 0x34, 0x30, 0x99, 0x20, 0x99, + 0x54, 0x87, 0x03, 0x06, 0x0C, 0x0A, 0xA9, 0x34, + 0x25, 0xDA, 0x21, 0x0C, 0x1D, 0x3C, 0x8C, 0xB8, + 0x44, 0xC0, 0x20, 0x00, 0xC0, 0xBB, 0x10, 0xB2, + 0x62, 0x80, 0xC0, 0x20, 0x00, 0xE2, 0x22, 0x81, + 0xE0, 0xF0, 0x04, 0x07, 0xEE, 0xF3, 0xC0, 0x20, + 0x00, 0xB1, 0xDD, 0x03, 0x32, 0x62, 0x81, 0xC0, + 0x20, 0x00, 0xB8, 0x0B, 0xA1, 0xE9, 0x03, 0x1B, + 0xBB, 0xB9, 0x4A, 0x4B, 0xAA, 0xA5, 0xCE, 0x20, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x20, 0x61, 0x00, 0x3C, 0x8A, 0x0C, 0x0B, 0x25, + 0x1A, 0x24, 0x20, 0xE6, 0x13, 0x10, 0x20, 0x00, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x31, 0xEA, 0x03, 0x38, 0x03, 0x8C, 0x73, 0x88, + 0x23, 0x66, 0x28, 0x03, 0x0C, 0x39, 0x99, 0x23, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x31, 0xEB, 0x03, 0x0C, 0x02, 0x22, 0x43, 0x00, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0xBD, 0x02, 0x21, 0xEA, 0x03, 0x28, 0x02, 0x1C, + 0x8C, 0xCB, 0xA2, 0xE5, 0x2E, 0x2D, 0xD1, 0xEC, + 0x03, 0x2C, 0x0B, 0x92, 0x12, 0x11, 0x0C, 0x1C, + 0xDC, 0x79, 0xA2, 0x12, 0x0F, 0x92, 0x12, 0x0E, + 0xA0, 0xA0, 0xE4, 0x90, 0xAA, 0xC0, 0xA2, 0xCA, + 0xC2, 0xA0, 0xA1, 0x21, 0xAA, 0x99, 0x8B, 0x99, + 0x92, 0x52, 0x11, 0xB2, 0x52, 0x13, 0xC9, 0x22, + 0xD0, 0xD9, 0x10, 0xD2, 0x52, 0x11, 0x1D, 0xF0, + 0x00, 0x36, 0x41, 0x00, 0xD8, 0x22, 0x31, 0xEA, + 0x03, 0x0C, 0x1E, 0x38, 0x03, 0x0C, 0x0C, 0xAD, + 0x03, 0xF2, 0x13, 0x13, 0xB2, 0x13, 0x10, 0xF0, + 0xCE, 0x83, 0xDA, 0xBB, 0x25, 0x17, 0x00, 0x0C, + 0x45, 0xA8, 0x23, 0x92, 0x13, 0x13, 0x0C, 0x04, + 0x8C, 0x69, 0x0B, 0x99, 0x90, 0x90, 0xF4, 0x92, + 0x53, 0x13, 0xF6, 0x8A, 0x2F, 0xB1, 0xED, 0x03, + 0xB0, 0xBA, 0xA0, 0xB8, 0x0B, 0xA0, 0x0B, 0x00, + 0xC8, 0x22, 0xB2, 0x13, 0x11, 0xAD, 0x03, 0xCA, + 0xBB, 0x65, 0x21, 0x00, 0xD2, 0x13, 0x06, 0xF1, + 0xEB, 0x03, 0xD7, 0x3A, 0x0F, 0x0C, 0x29, 0x92, + 0x4F, 0x00, 0xE2, 0x13, 0x0F, 0xE0, 0xEF, 0x04, + 0x16, 0xBE, 0x10, 0x99, 0x23, 0x0C, 0x14, 0x2D, + 0x04, 0x1D, 0xF0, 0x49, 0x23, 0x0C, 0x24, 0x06, + 0xFD, 0xFF, 0xAD, 0x03, 0xE5, 0x1B, 0x00, 0x82, + 0x13, 0x09, 0xB2, 0x13, 0x08, 0x87, 0x3A, 0x02, + 0x06, 0x24, 0x00, 0xC8, 0x22, 0xB2, 0x13, 0x11, + 0xAD, 0x03, 0xCA, 0xBB, 0x65, 0x1D, 0x00, 0xD2, + 0x13, 0x07, 0xD7, 0x3A, 0x02, 0xC6, 0x36, 0x00, + 0xE2, 0x13, 0x14, 0x0B, 0xEE, 0xE0, 0xE0, 0xF4, + 0xE2, 0x53, 0x14, 0x56, 0xEE, 0x0D, 0x0C, 0x24, + 0x0C, 0x7F, 0xF9, 0x23, 0xC6, 0xED, 0xFF, 0xAD, + 0x03, 0xE5, 0x17, 0x00, 0x82, 0x13, 0x08, 0x87, + 0x3A, 0x6A, 0x59, 0x23, 0x42, 0x53, 0x16, 0x92, + 0x13, 0x0A, 0x92, 0x53, 0x14, 0x0C, 0x04, 0x06, + 0xE7, 0xFF, 0xAD, 0x03, 0x65, 0x16, 0x00, 0xB2, + 0x13, 0x08, 0xB7, 0x3A, 0x29, 0xC2, 0x13, 0x14, + 0x0B, 0xCC, 0xC0, 0xC0, 0xF4, 0xC2, 0x53, 0x14, + 0xEC, 0xBC, 0x0C, 0x6D, 0xE2, 0x13, 0x0B, 0xE2, + 0x53, 0x14, 0xD9, 0x23, 0xC6, 0x07, 0x00, 0xDC, + 0xC9, 0x59, 0x23, 0x42, 0x53, 0x16, 0xF2, 0x13, + 0x0A, 0xF2, 0x53, 0x14, 0xC6, 0x03, 0x00, 0x0C, + 0x58, 0x92, 0x13, 0x0D, 0xA2, 0x13, 0x0C, 0xA2, + 0x53, 0x14, 0x92, 0x53, 0x15, 0x89, 0x23, 0x0C, + 0x04, 0x86, 0xD4, 0xFF, 0xB7, 0x3A, 0x05, 0xC2, + 0x13, 0x0B, 0xC2, 0x53, 0x14, 0x42, 0x53, 0x16, + 0x0C, 0x04, 0x46, 0xD0, 0xFF, 0x92, 0x13, 0x15, + 0x66, 0x19, 0x09, 0x0C, 0x34, 0x0B, 0xD9, 0xD2, + 0x53, 0x15, 0x46, 0xCC, 0xFF, 0xCC, 0x39, 0x0C, + 0x14, 0x86, 0x01, 0x00, 0x0C, 0x04, 0x0B, 0xE9, + 0xE2, 0x53, 0x15, 0xC8, 0x22, 0xB2, 0x13, 0x11, + 0xAD, 0x03, 0xCA, 0xBB, 0x65, 0x11, 0x00, 0xD2, + 0x13, 0x07, 0xD7, 0xBA, 0x10, 0xE2, 0x13, 0x14, + 0x0B, 0xEE, 0xE0, 0xE0, 0xF4, 0xE2, 0x53, 0x14, + 0xE0, 0x45, 0x83, 0x06, 0xC0, 0xFF, 0xF2, 0x13, + 0x0D, 0xF2, 0x53, 0x14, 0xC6, 0xBD, 0xFF, 0x0C, + 0x39, 0x86, 0xBB, 0xFF, 0x82, 0x13, 0x06, 0x87, + 0x3A, 0x05, 0x92, 0x13, 0x0B, 0x92, 0x53, 0x14, + 0x0C, 0x04, 0x46, 0xB8, 0xFF, 0x0C, 0x04, 0x06, + 0xB7, 0xFF, 0x00, 0x00, 0x00, 0x36, 0x61, 0x00, + 0xB2, 0xA0, 0x94, 0xA2, 0xC2, 0x34, 0x92, 0xC2, + 0x54, 0x99, 0x01, 0xA9, 0x11, 0xBC, 0xB4, 0x68, + 0x11, 0x5D, 0x09, 0x1C, 0x04, 0x72, 0x12, 0x12, + 0x82, 0xA0, 0x94, 0xC0, 0x77, 0x11, 0x7A, 0x72, + 0x8A, 0x77, 0x82, 0x16, 0x00, 0xB2, 0x07, 0x00, + 0x1B, 0x77, 0xAD, 0x0B, 0xB0, 0x88, 0xC0, 0x82, + 0x56, 0x00, 0x2B, 0x66, 0xA5, 0x35, 0x2D, 0x98, + 0x05, 0x0B, 0x44, 0xA0, 0x99, 0xC0, 0x99, 0x05, + 0x4B, 0x55, 0x56, 0xC4, 0xFD, 0x98, 0x01, 0xA8, + 0x11, 0xB2, 0xA0, 0x94, 0x5D, 0x09, 0x6D, 0x0A, + 0x72, 0x12, 0x12, 0x1C, 0x04, 0xC0, 0x77, 0x11, + 0x7A, 0x72, 0xBA, 0x77, 0xD2, 0x03, 0x01, 0xE2, + 0x03, 0x03, 0xC2, 0x03, 0x02, 0xB2, 0x03, 0x00, + 0xEA, 0xCC, 0xDA, 0xBB, 0xCA, 0xBB, 0xB0, 0xB2, + 0x41, 0xAD, 0x0B, 0xB2, 0x47, 0x00, 0x82, 0x16, + 0x00, 0x1B, 0x77, 0xBA, 0x88, 0x82, 0x56, 0x00, + 0x2B, 0x66, 0xA5, 0x30, 0x2D, 0x8B, 0x33, 0xF8, + 0x05, 0x0B, 0x44, 0xAA, 0xFF, 0xF9, 0x05, 0x4B, + 0x55, 0x56, 0x74, 0xFC, 0x82, 0x12, 0x12, 0x1B, + 0x88, 0x80, 0x80, 0x44, 0x82, 0x52, 0x12, 0x1D, + 0xF0, 0x36, 0x41, 0x00, 0x32, 0xC2, 0x34, 0x1C, + 0x05, 0x0C, 0x04, 0xB2, 0x13, 0x00, 0xAD, 0x0B, + 0xE5, 0x2D, 0x2D, 0x2B, 0x33, 0x0B, 0x55, 0xA0, + 0x95, 0x41, 0x82, 0x22, 0x15, 0x4B, 0x22, 0x90, + 0x88, 0xC0, 0x80, 0x85, 0x41, 0x8A, 0x44, 0x56, + 0x05, 0xFE, 0x40, 0x24, 0x41, 0x1D, 0xF0, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x1C, 0x07, 0x0C, 0x06, + 0x0C, 0x05, 0xB2, 0xC3, 0x81, 0x42, 0x03, 0x00, + 0xB2, 0x0B, 0x7E, 0xC2, 0x03, 0x01, 0x47, 0xBB, + 0x0C, 0x47, 0xBC, 0x11, 0x4D, 0x0B, 0xC7, 0xBB, + 0x0C, 0x4D, 0x0C, 0xC6, 0x01, 0x00, 0x47, 0x3C, + 0x04, 0xC7, 0xBB, 0x01, 0x4D, 0x0B, 0xAD, 0x04, + 0xBD, 0x04, 0xA5, 0x28, 0x2D, 0xAA, 0x66, 0x5A, + 0x54, 0x0B, 0x77, 0x4B, 0x33, 0xB2, 0xC3, 0x81, + 0x56, 0x97, 0xFC, 0xAD, 0x05, 0xBD, 0x05, 0x65, + 0x27, 0x2D, 0xD2, 0x12, 0x16, 0xA0, 0x94, 0x41, + 0x90, 0x96, 0xC0, 0xD0, 0xCD, 0xF0, 0x90, 0x94, + 0x41, 0x90, 0xE3, 0x41, 0xC0, 0xC3, 0x21, 0xEA, + 0xCC, 0xD0, 0x9C, 0x93, 0x92, 0x52, 0x16, 0x2D, + 0x09, 0x1D, 0xF0, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x00, 0x64, 0x11, 0x02, 0x60, 0x04, 0x11, 0x02, + 0x60, 0xEC, 0x18, 0x00, 0x60, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x13, 0x02, + 0x60, 0xC8, 0x14, 0x02, 0x60, 0xD4, 0x13, 0x02, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x19, 0x00, + 0x60, 0x1C, 0x19, 0x00, 0x60, 0x04, 0x19, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x19, 0x00, + 0x60, 0x2C, 0x19, 0x00, 0x60, 0x08, 0x19, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x48, 0x19, 0x00, 0x60, 0x48, 0x19, 0x00, + 0x60, 0x0C, 0x19, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x94, 0x15, 0x02, 0x60, 0x5C, 0x19, 0x00, + 0x60, 0x5C, 0x19, 0x00, 0x60, 0x58, 0x19, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0xC4, 0x15, 0x02, + 0x60, 0xCC, 0x15, 0x02, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x6C, 0x19, 0x00, 0x60, 0x70, 0x19, 0x00, + 0x60, 0xB0, 0x19, 0x00, 0x60, 0x94, 0x02, 0x00, + 0x00, 0x84, 0x16, 0x02, 0x60, 0x5F, 0x16, 0x02, + 0x60, 0x84, 0x16, 0x02, 0x60, 0x0E, 0x17, 0x02, + 0x60, 0xE9, 0x16, 0x02, 0x60, 0xCE, 0x16, 0x02, + 0x60, 0x91, 0x16, 0x02, 0x60, 0x8A, 0x16, 0x02, + 0x60, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x0C, 0x00, + 0x60, 0xD4, 0x0C, 0x00, 0x60, 0x10, 0xB0, 0x02, + 0x00, 0xC0, 0x19, 0x00, 0x60, 0x20, 0x01, 0x00, + 0x00, 0xB0, 0x0A, 0x00, 0x60, 0x04, 0x10, 0x02, + 0x60, 0xA0, 0x0A, 0x00, 0x60, 0xA4, 0x10, 0x02, + 0x60, 0xF8, 0x10, 0x02, 0x60, 0x6C, 0x10, 0x02, + 0x60, 0x6C, 0x06, 0x00, 0x60, 0x20, 0x16, 0x02, + 0x60, 0xF4, 0x05, 0x00, 0x60, 0x4C, 0x10, 0x02, + 0x60, 0xA8, 0x0B, 0x00, 0x60, 0xF8, 0x18, 0x00, + 0x60, 0x68, 0x0A, 0x00, 0x60, 0x28, 0x8F, 0x04, + 0x60, 0x48, 0x08, 0x00, 0x60, 0xE0, 0x14, 0x02, + 0x60, 0xAC, 0x06, 0x00, 0x60, 0x20, 0x15, 0x02, + 0x60, 0x38, 0x15, 0x02, 0x60, 0xD8, 0x56, 0x04, + 0x60, 0x36, 0x41, 0x00, 0x81, 0x6F, 0x06, 0xB1, + 0x6D, 0x06, 0x0C, 0x6A, 0x91, 0x6E, 0x06, 0xA2, + 0x4B, 0x00, 0x89, 0x09, 0x25, 0x02, 0x00, 0x65, + 0x07, 0x00, 0x25, 0x09, 0x00, 0xE5, 0x07, 0x00, + 0x65, 0x02, 0x00, 0x65, 0x05, 0x00, 0xA5, 0x6E, + 0xFF, 0xA1, 0x70, 0x06, 0xB1, 0x71, 0x06, 0x65, + 0xB3, 0x2C, 0x1D, 0xF0, 0x00, 0x36, 0x41, 0x00, + 0x31, 0x72, 0x06, 0x21, 0x73, 0x06, 0x22, 0x63, + 0x75, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x0C, 0x8F, 0xB1, 0x72, 0x06, 0xA1, 0x77, 0x06, + 0x91, 0x78, 0x06, 0x81, 0x79, 0x06, 0x31, 0x7A, + 0x06, 0x21, 0x7B, 0x06, 0xC1, 0x76, 0x06, 0xD1, + 0x74, 0x06, 0xE1, 0x75, 0x06, 0xE9, 0xFD, 0xC2, + 0x6D, 0x19, 0x29, 0x83, 0x89, 0x39, 0xA2, 0x6B, + 0x6B, 0xF2, 0x5D, 0x1C, 0x1D, 0xF0, 0x00, 0x00, + 0x00, 0x36, 0x41, 0x00, 0x31, 0x7C, 0x06, 0x21, + 0x7D, 0x06, 0x48, 0x03, 0x49, 0x22, 0x29, 0x03, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x31, 0x7E, 0x06, 0x21, 0x7F, 0x06, 0x29, 0x13, + 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x31, 0x80, 0x06, 0x21, 0x81, 0x06, 0x22, 0x63, + 0x19, 0x1D, 0xF0, 0x00, 0x00, 0x36, 0x41, 0x00, + 0x91, 0x83, 0x06, 0x21, 0x85, 0x06, 0x31, 0x82, + 0x06, 0x81, 0x84, 0x06, 0x89, 0xC3, 0x29, 0xA3, + 0x99, 0xB3, 0x1D, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x04, 0x00, 0x18, 0x1A, 0x02, + 0x60, }; static const unsigned char vfs301_12[] = { /* 57 B */ - 0x12, 0x90, 0x02, 0x00, 0x00, 0xFE, 0x03, 0x00, - 0x00, 0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, - 0x00, 0xE3, 0x18, 0xD8, 0x01, 0xE3, 0x18, 0xD8, - 0x01, 0xE3, 0x18, 0xD8, 0x01, 0xE3, 0x18, 0xD8, - 0x01, 0xE3, 0x18, 0xD8, 0x01, 0x20, 0xFA, 0x80, - 0x00, 0x3F, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x03, 0x00, - 0x00, + 0x12, 0x90, 0x02, 0x00, 0x00, 0xFE, 0x03, 0x00, + 0x00, 0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, + 0x00, 0xE3, 0x18, 0xD8, 0x01, 0xE3, 0x18, 0xD8, + 0x01, 0xE3, 0x18, 0xD8, 0x01, 0xE3, 0x18, 0xD8, + 0x01, 0xE3, 0x18, 0xD8, 0x01, 0x20, 0xFA, 0x80, + 0x00, 0x3F, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x03, 0x00, + 0x00, }; static const unsigned char vfs301_24[] = { /* 119 B */ - 0x24, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, - 0x07, 0x00, 0x00, 0x00, - 0xF8, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, - 0x07, 0x00, 0x00, 0x00, - 0xF8, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, - 0x07, 0x00, 0x00, 0x00, - 0xF8, 0xFF, 0xFF, 0xFF, - 0x07, 0x00, 0x00, 0x00, - 0xF8, 0xFF, 0xFF, 0xFF, - 0x07, 0x00, 0x00, 0x00, - 0xF8, 0xFF, 0xFF, 0xFF, - 0x07, 0x00, 0x00, 0x00, - 0xF8, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* or : - * 0x00, 0xF4, 0x01, 0xF4, 0x01, 0x00, 0xB4, */ + 0x24, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x07, 0x00, 0x00, 0x00, + 0xF8, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x07, 0x00, 0x00, 0x00, + 0xF8, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x07, 0x00, 0x00, 0x00, + 0xF8, 0xFF, 0xFF, 0xFF, + 0x07, 0x00, 0x00, 0x00, + 0xF8, 0xFF, 0xFF, 0xFF, + 0x07, 0x00, 0x00, 0x00, + 0xF8, 0xFF, 0xFF, 0xFF, + 0x07, 0x00, 0x00, 0x00, + 0xF8, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* or : + * 0x00, 0xF4, 0x01, 0xF4, 0x01, 0x00, 0xB4, */ }; -#define PACKET(cmd, length, payload)\ - cmd length payload +#define PACKET(cmd, length, payload) \ + cmd length payload /* This could be some kind of poke-command. * a looks like the address; (addr << 2), stored in little endian, * b looks like some flags, value of a seems to imply value of b * c looks like the stored value */ #define S1(a, b, c) \ - PACKET("0300", "0900", a b c "04") + PACKET ("0300", "0900", a b c "04") #define S2(a) \ - PACKET("0500", "0E00", a) + PACKET ("0500", "0E00", a) #define S3(a) \ - PACKET("0A00", "0800", a a) + PACKET ("0A00", "0800", a a) #define S4_TAIL \ - "00008000" "6400F401" "00000000" "0000C780" "24004400" + "00008000" "6400F401" "00000000" "0000C780" "24004400" #define S4(a) \ - PACKET("0800", "1800", a a S4_TAIL) + PACKET ("0800", "1800", a a S4_TAIL) #define Z8() \ - "00000000" + "00000000" #define TERM() \ - PACKET("1500", "0800", "0000000020280000") + PACKET ("1500", "0800", "0000000020280000") /* NOTE: * * Reordering the S1() macros in BLOB1 (and similar) doesn't @@ -1153,1479 +1153,1479 @@ static const unsigned char vfs301_24[] = { /* 119 B */ * input lines? */ #define vfs301_0220_BLOB1 \ - S1("0420", "0430", "00000000"),\ - S1("1820", "0430", "00000000"),\ - S1("2020", "0430", "08008000"),\ - S1("2420", "0430", "0000FF01"),\ - S1("2C20", "0430", "01000000"),\ - S1("4020", "0430", "FF030000"),\ - S1("4420", "0430", "E5030000"),\ - S1("4820", "0430", "EA030000"),\ - S1("4C20", "0430", "EA030000"),\ - S1("5020", "0430", "00000400"),\ - S1("5420", "0430", "01980200"),\ - S1("0021", "0430", "00000000"),\ - S1("0421", "0430", "01000000"),\ - S1("0821", "0430", "02000000"),\ - S1("0C21", "0430", "01000000"),\ - S1("1021", "0430", "01000000"),\ - S1("1421", "0430", "01000000"),\ - S1("1821", "0430", "01000000"),\ - S1("1C21", "0430", "1F000000"),\ - S1("2021", "0430", "08000000"),\ - S1("4021", "0430", "00000000"),\ - S1("4421", "0430", "01000000"),\ - S1("4821", "0430", "02000000"),\ - S1("4C21", "0430", "01000000"),\ - S1("5021", "0430", "01000000"),\ - S1("5421", "0430", "01000000"),\ - S1("5821", "0430", "01000000"),\ - S1("5C21", "0430", "1F000000"),\ - S1("6021", "0430", "08000000"),\ - S1("8021", "0430", "30000000"),\ - S1("8421", "0430", "01000000"),\ - S1("8821", "0430", "01000000"),\ - S1("8C21", "0430", "01000000"),\ - S1("9021", "0430", "00000000"),\ - S1("9421", "0430", "01000000"),\ - S1("9821", "0430", "00000000"),\ - S1("9C21", "0430", "1F000000"),\ - S1("A021", "0430", "04000000"),\ - S1("C021", "0430", "30000000"),\ - S1("C421", "0430", "01000000"),\ - S1("C821", "0430", "01000000"),\ - S1("CC21", "0430", "01000000"),\ - S1("D021", "0430", "01000000"),\ - S1("D421", "0430", "01000000"),\ - S1("D821", "0430", "01000000"),\ - S1("DC21", "0430", "1F000000"),\ - S1("E021", "0430", "03000000"),\ - S1("A020", "0430", "EFE10000"),\ - S1("A420", "0430", "00000000"),\ - S1("A820", "0430", "FE210400"),\ - S1("B020", "0430", "00000000"),\ - S1("C420", "0430", "14000000"),\ - S1("C820", "0430", "00000000"),\ - S1("CC20", "0430", "20000000"),\ - S1("38A0", "0038", "5CA30000"),\ - S1("0000", "0038", "02000000"),\ - S1("0400", "0038", "00080000"),\ - S1("0800", "0038", "00120000"),\ - S1("0C00", "0038", "01030200"),\ - S1("1000", "0038", "01070200"),\ - S1("1400", "0038", "0C0C8A00"),\ - PACKET("0200", "8005", \ - "FFF98720" \ - "1AF88700" \ - "1AF88700" \ - "1AF88700" \ - "1AF88700" \ - "1AF88700" \ - "1AF88700" \ - /* NOTE: The following(?) 200 values specify order of fingerprint columns \ - * in vfs301_line_t::scan. */ \ - "1AF80720" \ - "1BF80720" \ - "1CF80720" \ - "1DF80720" \ - "1EF80720" \ - "1FF80720" \ - "20F80720" \ - "21F80720" \ - "22F80720" \ - "23F80720" \ - "24F80722" \ - "25F80722" \ - "26F80722" \ - "27F80722" \ - "28F80722" \ - "29F80722" \ - "2AF80722" \ - "2BF80722" \ - "2CF80722" \ - "2DF80722" \ - "2EF80722" \ - "2FF80722" \ - "30F80722" \ - "31F80722" \ - "32F80722" \ - "33F80722" \ - "34F80722" \ - "35F80722" \ - "36F80722" \ - "37F80722" \ - "38F80722" \ - "39F80722" \ - "3AF80722" \ - "3BF80722" \ - "3CF80722" \ - "3DF80722" \ - "3EF80722" \ - "3FF80722" \ - "40F80722" \ - "41F80722" \ - "42F80722" \ - "43F80722" \ - "44F80722" \ - "45F80722" \ - "46F80722" \ - "47F80722" \ - "48F80722" \ - "49F80722" \ - "4AF80722" \ - "4BF80722" \ - "4CF80722" \ - "4DF80722" \ - "4EF80722" \ - "4FF80722" \ - "50F80722" \ - "51F80722" \ - "52F80722" \ - "53F80722" \ - "54F80722" \ - "55F80722" \ - "56F80722" \ - "57F80722" \ - "58F80722" \ - "59F80722" \ - "5AF80722" \ - "5BF80722" \ - "5CF80722" \ - "5DF80722" \ - "5EF80722" \ - "5FF80722" \ - "60F80722" \ - "61F80722" \ - "62F80722" \ - "63F80722" \ - "64F80722" \ - "65F80722" \ - "66F80722" \ - "67F80722" \ - "68F80722" \ - "69F80722" \ - "6AF80722" \ - "6BF80722" \ - "6CF80722" \ - "6DF80722" \ - "6EF80722" \ - "6FF80722" \ - "70F80722" \ - "71F80722" \ - "72F80722" \ - "73F80722" \ - "74F80722" \ - "75F80722" \ - "76F80722" \ - "77F80722" \ - "78F80722" \ - "79F80722" \ - "7AF80722" \ - "7BF80722" \ - "7CF80722" \ - "7DF80722" \ - "7EF80722" \ - "7FF80722" \ - "80F80722" \ - "81F80722" \ - "82F80722" \ - "83F80722" \ - "84F80722" \ - "85F80722" \ - "86F80722" \ - "87F80722" \ - "88F80722" \ - "89F80722" \ - "8AF80722" \ - "8BF80722" \ - "8CF80722" \ - "8DF80722" \ - "8EF80722" \ - "8FF80722" \ - "90F80722" \ - "91F80722" \ - "92F80722" \ - "93F80722" \ - "94F80722" \ - "95F80722" \ - "96F80722" \ - "97F80722" \ - "98F80722" \ - "99F80722" \ - "9AF80722" \ - "9BF80722" \ - "9CF80722" \ - "9DF80722" \ - "9EF80722" \ - "9FF80722" \ - "A0F80722" \ - "A1F80722" \ - "A2F80722" \ - "A3F80722" \ - "A4F80722" \ - "A5F80722" \ - "A6F80722" \ - "A7F80722" \ - "A8F80722" \ - "A9F80722" \ - "AAF80722" \ - "ABF80722" \ - "ACF80722" \ - "ADF80722" \ - "AEF80722" \ - "AFF80722" \ - "B0F80722" \ - "B1F80722" \ - "B2F80722" \ - "B3F80722" \ - "B4F80722" \ - "B5F80722" \ - "B6F80722" \ - "B7F80722" \ - "B8F80722" \ - "B9F80722" \ - "BAF80722" \ - "BBF80722" \ - "BCF80722" \ - "BDF80722" \ - "BEF80722" \ - "BFF80722" \ - "C0F80722" \ - "C1F80722" \ - "C2F80722" \ - "C3F80722" \ - "C4F80722" \ - "C5F80722" \ - "C6F80722" \ - "C7F80722" \ - "C8F80722" \ - "C9F80722" \ - "CAF80722" \ - "CBF80722" \ - "CCF80722" \ - "CDF80722" \ - "CEF80722" \ - "CFF80722" \ - "D0F80722" \ - "D1F80722" \ - "D2F80722" \ - "D3F80722" \ - "D4F80722" \ - "D5F80722" \ - "D6F80722" \ - "D7F80722" \ - "D8F80720" \ - "D9F80720" \ - "DAF80720" \ - "DBF80720" \ - "DCF80720" \ - "DDF80720" \ - "DEF80720" \ - "DFF80720" \ - "E0F80720" \ - "E1F80720" \ - \ - "E1F80700" \ - "0BF88700" \ - "0BF88700" \ - "0BF88700" \ - "0BF88700" \ - "0BF88700" \ - /* NOTE: The following(?) 64 values specify order of fingerprint columns \ - * in vfs301_line_t::mirror. \ - * Placing Z8() instead of the value shortens the mirror section. \ - * */ \ - "0BF88700" \ - "0AF80720" \ - "09F80720" \ - "08F80720" \ - "07F80720" \ - "06F80720" \ - "05F80720" \ - "04F80720" \ - "03F80720" \ - "02F80720" \ - "01F80720" \ - "00F80720" \ - "17F90720" \ - "16F90720" \ - "15F90720" \ - "14F90720" \ - "13F90720" \ - "12F90720" \ - "11F90720" \ - "10F90720" \ - "0FF90720" \ - "0EF90720" \ - "0DF90720" \ - "0CF90720" \ - "0BF90720" \ - "0AF90720" \ - "09F90720" \ - "08F90720" \ - "07F90720" \ - "06F90720" \ - "05F90720" \ - "04F90720" \ - "03F90720" \ - "02F90720" \ - "01F90720" \ - "00F90720" \ - "FFF80720" \ - "FEF80720" \ - "FDF80720" \ - "FCF80720" \ - "FBF80720" \ - "FAF80720" \ - "F9F80720" \ - "F8F80720" \ - "F7F80720" \ - "F6F80720" \ - "F5F80720" \ - "F4F80720" \ - "F3F80720" \ - "F2F80720" \ - "F1F80720" \ - "F0F80720" \ - "EFF80720" \ - "EEF80720" \ - "EDF80720" \ - "ECF80720" \ - "EBF80720" \ - "EAF80720" \ - "E9F80720" \ - "E8F80720" \ - "E7F80720" \ - "E6F80720" \ - "E5F80720" \ - "E4F80720" \ - \ - "0BF80720" \ - "0BF80700" \ - \ - "5CF2C700" \ - "5CF2C700" \ - "5CF2C700" \ - "5CF2C700" \ - "5CF2C700" \ - "5CF24700" \ - "5CF24700" \ - "5CF24720" \ - "FFF94700" \ - "FFF94700" \ - "FFF94700" \ - "FFF94700" \ - "FFF94700" \ - "FFF94720" \ - "5CF84700" \ - "5CF84700" \ - "5CF84700" \ - "5CF84700" \ - \ - /* NOTE: The following(?) values specify order of fingerprint columns \ - * in vfs301_line_t::sum*. */ \ - "5CF84700" \ - "5CF84720" \ - "62F84700" \ - "62F84720" \ - "68F84700" \ - "68F84720" \ - "6EF84700" \ - "6EF84720" \ - "74F84700" \ - "74F84720" \ - "7AF84700" \ - "7AF84720" \ - "80F84700" \ - "80F84720" \ - "86F84700" \ - "86F84720" \ - "8CF84700" \ - "8CF84720" \ - "92F84700" \ - "92F84720" \ - "98F84720" \ - "9E844700" \ - "9E844720" \ - "9E844700" \ - \ - "FFF96700" "FFF96700" "FFF96700" "FFF96700" "FFF96720" \ - "0DF86700" "0DF86700" "0DF86700" "0DF86700" "0DF86700" \ - "0DF86720" "0DF86700" \ - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() \ - Z8() Z8() Z8() Z8() Z8() Z8() Z8() \ - ), \ - S3("1003181C"), \ - S1("0020", "0430", "80000000") + S1 ("0420", "0430", "00000000"), \ + S1 ("1820", "0430", "00000000"), \ + S1 ("2020", "0430", "08008000"), \ + S1 ("2420", "0430", "0000FF01"), \ + S1 ("2C20", "0430", "01000000"), \ + S1 ("4020", "0430", "FF030000"), \ + S1 ("4420", "0430", "E5030000"), \ + S1 ("4820", "0430", "EA030000"), \ + S1 ("4C20", "0430", "EA030000"), \ + S1 ("5020", "0430", "00000400"), \ + S1 ("5420", "0430", "01980200"), \ + S1 ("0021", "0430", "00000000"), \ + S1 ("0421", "0430", "01000000"), \ + S1 ("0821", "0430", "02000000"), \ + S1 ("0C21", "0430", "01000000"), \ + S1 ("1021", "0430", "01000000"), \ + S1 ("1421", "0430", "01000000"), \ + S1 ("1821", "0430", "01000000"), \ + S1 ("1C21", "0430", "1F000000"), \ + S1 ("2021", "0430", "08000000"), \ + S1 ("4021", "0430", "00000000"), \ + S1 ("4421", "0430", "01000000"), \ + S1 ("4821", "0430", "02000000"), \ + S1 ("4C21", "0430", "01000000"), \ + S1 ("5021", "0430", "01000000"), \ + S1 ("5421", "0430", "01000000"), \ + S1 ("5821", "0430", "01000000"), \ + S1 ("5C21", "0430", "1F000000"), \ + S1 ("6021", "0430", "08000000"), \ + S1 ("8021", "0430", "30000000"), \ + S1 ("8421", "0430", "01000000"), \ + S1 ("8821", "0430", "01000000"), \ + S1 ("8C21", "0430", "01000000"), \ + S1 ("9021", "0430", "00000000"), \ + S1 ("9421", "0430", "01000000"), \ + S1 ("9821", "0430", "00000000"), \ + S1 ("9C21", "0430", "1F000000"), \ + S1 ("A021", "0430", "04000000"), \ + S1 ("C021", "0430", "30000000"), \ + S1 ("C421", "0430", "01000000"), \ + S1 ("C821", "0430", "01000000"), \ + S1 ("CC21", "0430", "01000000"), \ + S1 ("D021", "0430", "01000000"), \ + S1 ("D421", "0430", "01000000"), \ + S1 ("D821", "0430", "01000000"), \ + S1 ("DC21", "0430", "1F000000"), \ + S1 ("E021", "0430", "03000000"), \ + S1 ("A020", "0430", "EFE10000"), \ + S1 ("A420", "0430", "00000000"), \ + S1 ("A820", "0430", "FE210400"), \ + S1 ("B020", "0430", "00000000"), \ + S1 ("C420", "0430", "14000000"), \ + S1 ("C820", "0430", "00000000"), \ + S1 ("CC20", "0430", "20000000"), \ + S1 ("38A0", "0038", "5CA30000"), \ + S1 ("0000", "0038", "02000000"), \ + S1 ("0400", "0038", "00080000"), \ + S1 ("0800", "0038", "00120000"), \ + S1 ("0C00", "0038", "01030200"), \ + S1 ("1000", "0038", "01070200"), \ + S1 ("1400", "0038", "0C0C8A00"), \ + PACKET ("0200", "8005", \ + "FFF98720" \ + "1AF88700" \ + "1AF88700" \ + "1AF88700" \ + "1AF88700" \ + "1AF88700" \ + "1AF88700" \ + /* NOTE: The following(?) 200 values specify order of fingerprint columns \ + * in vfs301_line_t::scan. */ \ + "1AF80720" \ + "1BF80720" \ + "1CF80720" \ + "1DF80720" \ + "1EF80720" \ + "1FF80720" \ + "20F80720" \ + "21F80720" \ + "22F80720" \ + "23F80720" \ + "24F80722" \ + "25F80722" \ + "26F80722" \ + "27F80722" \ + "28F80722" \ + "29F80722" \ + "2AF80722" \ + "2BF80722" \ + "2CF80722" \ + "2DF80722" \ + "2EF80722" \ + "2FF80722" \ + "30F80722" \ + "31F80722" \ + "32F80722" \ + "33F80722" \ + "34F80722" \ + "35F80722" \ + "36F80722" \ + "37F80722" \ + "38F80722" \ + "39F80722" \ + "3AF80722" \ + "3BF80722" \ + "3CF80722" \ + "3DF80722" \ + "3EF80722" \ + "3FF80722" \ + "40F80722" \ + "41F80722" \ + "42F80722" \ + "43F80722" \ + "44F80722" \ + "45F80722" \ + "46F80722" \ + "47F80722" \ + "48F80722" \ + "49F80722" \ + "4AF80722" \ + "4BF80722" \ + "4CF80722" \ + "4DF80722" \ + "4EF80722" \ + "4FF80722" \ + "50F80722" \ + "51F80722" \ + "52F80722" \ + "53F80722" \ + "54F80722" \ + "55F80722" \ + "56F80722" \ + "57F80722" \ + "58F80722" \ + "59F80722" \ + "5AF80722" \ + "5BF80722" \ + "5CF80722" \ + "5DF80722" \ + "5EF80722" \ + "5FF80722" \ + "60F80722" \ + "61F80722" \ + "62F80722" \ + "63F80722" \ + "64F80722" \ + "65F80722" \ + "66F80722" \ + "67F80722" \ + "68F80722" \ + "69F80722" \ + "6AF80722" \ + "6BF80722" \ + "6CF80722" \ + "6DF80722" \ + "6EF80722" \ + "6FF80722" \ + "70F80722" \ + "71F80722" \ + "72F80722" \ + "73F80722" \ + "74F80722" \ + "75F80722" \ + "76F80722" \ + "77F80722" \ + "78F80722" \ + "79F80722" \ + "7AF80722" \ + "7BF80722" \ + "7CF80722" \ + "7DF80722" \ + "7EF80722" \ + "7FF80722" \ + "80F80722" \ + "81F80722" \ + "82F80722" \ + "83F80722" \ + "84F80722" \ + "85F80722" \ + "86F80722" \ + "87F80722" \ + "88F80722" \ + "89F80722" \ + "8AF80722" \ + "8BF80722" \ + "8CF80722" \ + "8DF80722" \ + "8EF80722" \ + "8FF80722" \ + "90F80722" \ + "91F80722" \ + "92F80722" \ + "93F80722" \ + "94F80722" \ + "95F80722" \ + "96F80722" \ + "97F80722" \ + "98F80722" \ + "99F80722" \ + "9AF80722" \ + "9BF80722" \ + "9CF80722" \ + "9DF80722" \ + "9EF80722" \ + "9FF80722" \ + "A0F80722" \ + "A1F80722" \ + "A2F80722" \ + "A3F80722" \ + "A4F80722" \ + "A5F80722" \ + "A6F80722" \ + "A7F80722" \ + "A8F80722" \ + "A9F80722" \ + "AAF80722" \ + "ABF80722" \ + "ACF80722" \ + "ADF80722" \ + "AEF80722" \ + "AFF80722" \ + "B0F80722" \ + "B1F80722" \ + "B2F80722" \ + "B3F80722" \ + "B4F80722" \ + "B5F80722" \ + "B6F80722" \ + "B7F80722" \ + "B8F80722" \ + "B9F80722" \ + "BAF80722" \ + "BBF80722" \ + "BCF80722" \ + "BDF80722" \ + "BEF80722" \ + "BFF80722" \ + "C0F80722" \ + "C1F80722" \ + "C2F80722" \ + "C3F80722" \ + "C4F80722" \ + "C5F80722" \ + "C6F80722" \ + "C7F80722" \ + "C8F80722" \ + "C9F80722" \ + "CAF80722" \ + "CBF80722" \ + "CCF80722" \ + "CDF80722" \ + "CEF80722" \ + "CFF80722" \ + "D0F80722" \ + "D1F80722" \ + "D2F80722" \ + "D3F80722" \ + "D4F80722" \ + "D5F80722" \ + "D6F80722" \ + "D7F80722" \ + "D8F80720" \ + "D9F80720" \ + "DAF80720" \ + "DBF80720" \ + "DCF80720" \ + "DDF80720" \ + "DEF80720" \ + "DFF80720" \ + "E0F80720" \ + "E1F80720" \ + \ + "E1F80700" \ + "0BF88700" \ + "0BF88700" \ + "0BF88700" \ + "0BF88700" \ + "0BF88700" \ + /* NOTE: The following(?) 64 values specify order of fingerprint columns \ + * in vfs301_line_t::mirror. \ + * Placing Z8() instead of the value shortens the mirror section. \ + * */ \ + "0BF88700" \ + "0AF80720" \ + "09F80720" \ + "08F80720" \ + "07F80720" \ + "06F80720" \ + "05F80720" \ + "04F80720" \ + "03F80720" \ + "02F80720" \ + "01F80720" \ + "00F80720" \ + "17F90720" \ + "16F90720" \ + "15F90720" \ + "14F90720" \ + "13F90720" \ + "12F90720" \ + "11F90720" \ + "10F90720" \ + "0FF90720" \ + "0EF90720" \ + "0DF90720" \ + "0CF90720" \ + "0BF90720" \ + "0AF90720" \ + "09F90720" \ + "08F90720" \ + "07F90720" \ + "06F90720" \ + "05F90720" \ + "04F90720" \ + "03F90720" \ + "02F90720" \ + "01F90720" \ + "00F90720" \ + "FFF80720" \ + "FEF80720" \ + "FDF80720" \ + "FCF80720" \ + "FBF80720" \ + "FAF80720" \ + "F9F80720" \ + "F8F80720" \ + "F7F80720" \ + "F6F80720" \ + "F5F80720" \ + "F4F80720" \ + "F3F80720" \ + "F2F80720" \ + "F1F80720" \ + "F0F80720" \ + "EFF80720" \ + "EEF80720" \ + "EDF80720" \ + "ECF80720" \ + "EBF80720" \ + "EAF80720" \ + "E9F80720" \ + "E8F80720" \ + "E7F80720" \ + "E6F80720" \ + "E5F80720" \ + "E4F80720" \ + \ + "0BF80720" \ + "0BF80700" \ + \ + "5CF2C700" \ + "5CF2C700" \ + "5CF2C700" \ + "5CF2C700" \ + "5CF2C700" \ + "5CF24700" \ + "5CF24700" \ + "5CF24720" \ + "FFF94700" \ + "FFF94700" \ + "FFF94700" \ + "FFF94700" \ + "FFF94700" \ + "FFF94720" \ + "5CF84700" \ + "5CF84700" \ + "5CF84700" \ + "5CF84700" \ + \ + /* NOTE: The following(?) values specify order of fingerprint columns \ + * in vfs301_line_t::sum*. */ \ + "5CF84700" \ + "5CF84720" \ + "62F84700" \ + "62F84720" \ + "68F84700" \ + "68F84720" \ + "6EF84700" \ + "6EF84720" \ + "74F84700" \ + "74F84720" \ + "7AF84700" \ + "7AF84720" \ + "80F84700" \ + "80F84720" \ + "86F84700" \ + "86F84720" \ + "8CF84700" \ + "8CF84720" \ + "92F84700" \ + "92F84720" \ + "98F84720" \ + "9E844700" \ + "9E844720" \ + "9E844700" \ + \ + "FFF96700" "FFF96700" "FFF96700" "FFF96700" "FFF96720" \ + "0DF86700" "0DF86700" "0DF86700" "0DF86700" "0DF86700" \ + "0DF86720" "0DF86700" \ + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ + ), \ + S3 ("1003181C"), \ + S1 ("0020", "0430", "80000000") #define vfs301_0220_BLOB2 \ - S2("0C20FF00FFFF0000000000030000"),\ - S2("1020FF00FFFF0000000000070000"),\ - S1("0421", "0430", "01000000"),\ - S1("0821", "0430", "02000000"),\ - S1("0C21", "0430", "01000000"),\ - S1("1021", "0430", "01000000"),\ - S1("1421", "0430", "01000000"),\ - S1("1821", "0430", "01000000"),\ - S1("4421", "0430", "01000000"),\ - S1("4821", "0430", "02000000"),\ - S1("4C21", "0430", "01000000"),\ - S1("5021", "0430", "01000000"),\ - S1("5421", "0430", "01000000"),\ - S1("5821", "0430", "01000000"),\ - S1("C820", "0430", "07000000"),\ - S2("1420FFFF00FF0000000000008800"),\ - S1("8421", "0430", "01000000"),\ - S1("8821", "0430", "01000000"),\ - S1("8C21", "0430", "01000000"),\ - S1("9021", "0430", "01000000"),\ - S1("9421", "0430", "01000000"),\ - S1("9821", "0430", "01000000"),\ - S1("A021", "0430", "00000000"),\ - S1("2021", "0430", "08000000"),\ - S1("6021", "0430", "08000000") + S2 ("0C20FF00FFFF0000000000030000"), \ + S2 ("1020FF00FFFF0000000000070000"), \ + S1 ("0421", "0430", "01000000"), \ + S1 ("0821", "0430", "02000000"), \ + S1 ("0C21", "0430", "01000000"), \ + S1 ("1021", "0430", "01000000"), \ + S1 ("1421", "0430", "01000000"), \ + S1 ("1821", "0430", "01000000"), \ + S1 ("4421", "0430", "01000000"), \ + S1 ("4821", "0430", "02000000"), \ + S1 ("4C21", "0430", "01000000"), \ + S1 ("5021", "0430", "01000000"), \ + S1 ("5421", "0430", "01000000"), \ + S1 ("5821", "0430", "01000000"), \ + S1 ("C820", "0430", "07000000"), \ + S2 ("1420FFFF00FF0000000000008800"), \ + S1 ("8421", "0430", "01000000"), \ + S1 ("8821", "0430", "01000000"), \ + S1 ("8C21", "0430", "01000000"), \ + S1 ("9021", "0430", "01000000"), \ + S1 ("9421", "0430", "01000000"), \ + S1 ("9821", "0430", "01000000"), \ + S1 ("A021", "0430", "00000000"), \ + S1 ("2021", "0430", "08000000"), \ + S1 ("6021", "0430", "08000000") #define vfs301_02D0_BLOB1 \ - S1("A820", "0430", "FE210000"), \ - S1("B020", "0430", "00000000"), \ - S1("C420", "0430", "14000000"), \ - S1("C820", "0430", "00000000"), \ - S1("CC20", "0430", "20000000"), \ - S1("38A0", "0038", "5CA30000"), \ - S1("0000", "0038", "02000000"), \ - S1("0400", "0038", "00080000"), \ - S1("0800", "0038", "00120000"), \ - S1("0C00", "0038", "01030200"), \ - S1("1000", "0038", "01070200"), \ - S1("1400", "0038", "0C0C8A00") + S1 ("A820", "0430", "FE210000"), \ + S1 ("B020", "0430", "00000000"), \ + S1 ("C420", "0430", "14000000"), \ + S1 ("C820", "0430", "00000000"), \ + S1 ("CC20", "0430", "20000000"), \ + S1 ("38A0", "0038", "5CA30000"), \ + S1 ("0000", "0038", "02000000"), \ + S1 ("0400", "0038", "00080000"), \ + S1 ("0800", "0038", "00120000"), \ + S1 ("0C00", "0038", "01030200"), \ + S1 ("1000", "0038", "01070200"), \ + S1 ("1400", "0038", "0C0C8A00") #define vfs301_02D0_BLOB4 \ - PACKET("1200", "0100", "01"),\ - S2("0C20FF00FFFF0000000000030000"),\ - S2("1020FF00FFFF0000000000070000"),\ - S1("0421", "0430", "01000000"),\ - S1("0821", "0430", "02000000"),\ - S1("0C21", "0430", "01000000"),\ - S1("1021", "0430", "01000000"),\ - S1("1421", "0430", "01000000"),\ - S1("1821", "0430", "01000000"),\ - S1("4421", "0430", "01000000"),\ - S1("4821", "0430", "02000000"),\ - S1("4C21", "0430", "01000000"),\ - S1("5021", "0430", "01000000"),\ - S1("5421", "0430", "01000000"),\ - S1("5821", "0430", "01000000") + PACKET ("1200", "0100", "01"), \ + S2 ("0C20FF00FFFF0000000000030000"), \ + S2 ("1020FF00FFFF0000000000070000"), \ + S1 ("0421", "0430", "01000000"), \ + S1 ("0821", "0430", "02000000"), \ + S1 ("0C21", "0430", "01000000"), \ + S1 ("1021", "0430", "01000000"), \ + S1 ("1421", "0430", "01000000"), \ + S1 ("1821", "0430", "01000000"), \ + S1 ("4421", "0430", "01000000"), \ + S1 ("4821", "0430", "02000000"), \ + S1 ("4C21", "0430", "01000000"), \ + S1 ("5021", "0430", "01000000"), \ + S1 ("5421", "0430", "01000000"), \ + S1 ("5821", "0430", "01000000") /* TODO: looks like that removing this whole packet doesn't cause * any troubles. */ -#define vfs301_02D0_ALIGNED_BLOB\ - PACKET("0200", "8005", \ - "FF830720" "5F820720" "FF830720" \ - "5F820720" "FF830720" "5F820720" "FF830720" \ - "5F820720" "FF830720" "5F820720" "FF8B0720" \ - "608A0720" "FF930720" "61920720" "FF9B0720" \ - "629A0720" "FFA30720" "63A20720" "FFAB0720" \ - "64AA0720" "FFB30720" "65B20720" "FFBB0720" \ - "66BA0720" "FFC30720" "67C20720" "FFCB0720" \ - "68CA0720" "FFD30720" "69D20720" "FFDB0720" \ - "6ADA0720" "FFE30720" "6BE20720" "FFEB0720" \ - "6CEA0720" "FFF30720" "6DF20720" "FFFB0720" \ - "6EFA0720" "FF850720" "6F840720" "FF8D0720" \ - "708C0720" "FF950720" "71940720" "FF9D0720" \ - "729C0720" "FFA50720" "73A40720" "FFAD0720" \ - "74AC0720" "FFB50720" "75B40720" "FFBD0720" \ - "76BC0720" "FFC50720" "77C40720" "FFCD0720" \ - "78CC0720" "FFD50720" "79D40720" "FFDD0720" \ - "7ADC0720" "FFE50720" "7BE40720" "FFED0720" \ - "7CEC0720" "FFF50720" "7DF40720" "FFFD0720" \ - "7EFC0720" "FF870720" "7F860720" "FF8F0720" \ - "808E0720" "FF970720" "81960720" "FF9F0720" \ - "829E0720" "FFA70720" "83A60720" "FFAF0720" \ - "84AE0720" "FFB70720" "85B60720" "FFBF0720" \ - "86BE0720" "FFC70720" "87C60720" "FFCF0720" \ - "88CE0720" "FFD70720" "89D60720" "FFDF0720" \ - "8ADE0720" "FFE70720" "8BE60720" "FFEF0720" \ - "8CEE0720" "FFF70720" "8DF60720" "FFFF0720" \ - "8EFE0720" \ - "FFFF0720" "8EFE0720" "FFF70720" "8DF60720" \ - "FFEF0720" "8CEE0720" "FFE70720" "8BE60720" \ - "FFDF0720" "8ADE0720" "FFD70720" "89D60720" \ - "FFCF0720" "88CE0720" "FFC70720" "87C60720" \ - "FFBF0720" "86BE0720" "FFB70720" "85B60720" \ - "FFAF0720" "84AE0720" "FFA70720" "83A60720" \ - "FF9F0720" "829E0720" "FF970720" "81960720" \ - "FF8F0720" "808E0720" "FF870720" "7F860720" \ - "FFFD0720" "7EFC0720" "FFF50720" "7DF40720" \ - "FFED0720" "7CEC0720" "FFE50720" "7BE40720" \ - "FFDD0720" "7ADC0720" "FFD50720" "79D40720" \ - "FFCD0720" "78CC0720" "FFC50720" "77C40720" \ - "FFBD0720" "76BC0720" "FFB50720" "75B40720" \ - "FFAD0720" "74AC0720" "FFA50720" "73A40720" \ - "FF9D0720" "729C0720" "FF950720" "71940720" \ - "FF8D0720" "708C0720" "FF850720" "6F840720" \ - "FFFB0720" "6EFA0720" "FFF30720" "6DF20720" \ - "FFEB0720" "6CEA0720" "FFE30720" "6BE20720" \ - "FFDB0720" "6ADA0720" "FFD30720" "69D20720" \ - "FFCB0720" "68CA0720" "FFC30720" "67C20720" \ - "FFBB0720" "66BA0720" "FFB30720" "65B20720" \ - "FFAB0720" "64AA0720" "FFA30720" "63A20720" \ - "FF9B0720" "629A0720" "FF930720" "61920720" \ - "FF8B0720" "608A0720" "FF830720" "5F820720" \ - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() \ - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() \ - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() \ - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() \ - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() \ - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() \ - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() \ - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() \ - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() \ - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() \ - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() \ - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() \ - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() \ - ),\ - S3("1003181C"),\ - S1("0020", "0430", "80000000") +#define vfs301_02D0_ALIGNED_BLOB \ + PACKET ("0200", "8005", \ + "FF830720" "5F820720" "FF830720" \ + "5F820720" "FF830720" "5F820720" "FF830720" \ + "5F820720" "FF830720" "5F820720" "FF8B0720" \ + "608A0720" "FF930720" "61920720" "FF9B0720" \ + "629A0720" "FFA30720" "63A20720" "FFAB0720" \ + "64AA0720" "FFB30720" "65B20720" "FFBB0720" \ + "66BA0720" "FFC30720" "67C20720" "FFCB0720" \ + "68CA0720" "FFD30720" "69D20720" "FFDB0720" \ + "6ADA0720" "FFE30720" "6BE20720" "FFEB0720" \ + "6CEA0720" "FFF30720" "6DF20720" "FFFB0720" \ + "6EFA0720" "FF850720" "6F840720" "FF8D0720" \ + "708C0720" "FF950720" "71940720" "FF9D0720" \ + "729C0720" "FFA50720" "73A40720" "FFAD0720" \ + "74AC0720" "FFB50720" "75B40720" "FFBD0720" \ + "76BC0720" "FFC50720" "77C40720" "FFCD0720" \ + "78CC0720" "FFD50720" "79D40720" "FFDD0720" \ + "7ADC0720" "FFE50720" "7BE40720" "FFED0720" \ + "7CEC0720" "FFF50720" "7DF40720" "FFFD0720" \ + "7EFC0720" "FF870720" "7F860720" "FF8F0720" \ + "808E0720" "FF970720" "81960720" "FF9F0720" \ + "829E0720" "FFA70720" "83A60720" "FFAF0720" \ + "84AE0720" "FFB70720" "85B60720" "FFBF0720" \ + "86BE0720" "FFC70720" "87C60720" "FFCF0720" \ + "88CE0720" "FFD70720" "89D60720" "FFDF0720" \ + "8ADE0720" "FFE70720" "8BE60720" "FFEF0720" \ + "8CEE0720" "FFF70720" "8DF60720" "FFFF0720" \ + "8EFE0720" \ + "FFFF0720" "8EFE0720" "FFF70720" "8DF60720" \ + "FFEF0720" "8CEE0720" "FFE70720" "8BE60720" \ + "FFDF0720" "8ADE0720" "FFD70720" "89D60720" \ + "FFCF0720" "88CE0720" "FFC70720" "87C60720" \ + "FFBF0720" "86BE0720" "FFB70720" "85B60720" \ + "FFAF0720" "84AE0720" "FFA70720" "83A60720" \ + "FF9F0720" "829E0720" "FF970720" "81960720" \ + "FF8F0720" "808E0720" "FF870720" "7F860720" \ + "FFFD0720" "7EFC0720" "FFF50720" "7DF40720" \ + "FFED0720" "7CEC0720" "FFE50720" "7BE40720" \ + "FFDD0720" "7ADC0720" "FFD50720" "79D40720" \ + "FFCD0720" "78CC0720" "FFC50720" "77C40720" \ + "FFBD0720" "76BC0720" "FFB50720" "75B40720" \ + "FFAD0720" "74AC0720" "FFA50720" "73A40720" \ + "FF9D0720" "729C0720" "FF950720" "71940720" \ + "FF8D0720" "708C0720" "FF850720" "6F840720" \ + "FFFB0720" "6EFA0720" "FFF30720" "6DF20720" \ + "FFEB0720" "6CEA0720" "FFE30720" "6BE20720" \ + "FFDB0720" "6ADA0720" "FFD30720" "69D20720" \ + "FFCB0720" "68CA0720" "FFC30720" "67C20720" \ + "FFBB0720" "66BA0720" "FFB30720" "65B20720" \ + "FFAB0720" "64AA0720" "FFA30720" "63A20720" \ + "FF9B0720" "629A0720" "FF930720" "61920720" \ + "FF8B0720" "608A0720" "FF830720" "5F820720" \ + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () \ + ), \ + S3 ("1003181C"), \ + S1 ("0020", "0430", "80000000") const char *vfs301_0220_01[] = { - "0220010100", + "0220010100", - /* NOTE: replacing this by vfs301_0220_BLOB1 seems to not cause problems */ - S1("0420", "0430", "00000000"), - S1("1820", "0430", "00000000"), - S1("2020", "0430", "08008000"), - S1("2420", "0430", "0000FF01"), - S1("2C20", "0430", "01000000"), - S1("4020", "0430", "AD010000"), - S1("4420", "0430", "AD010000"), - S1("4820", "0430", "AD010000"), - S1("4C20", "0430", "FF030000"), - S1("5020", "0430", "00005003"), - S1("5420", "0430", "013E0200"), - S1("0021", "0430", "14000000"), - S1("0421", "0430", "01000000"), - S1("0821", "0430", "01000000"), - S1("0C21", "0430", "01000000"), - S1("1021", "0430", "01000000"), - S1("1421", "0430", "01000000"), - S1("1821", "0430", "01000000"), - S1("1C21", "0430", "12000000"), - S1("2021", "0430", "04000000"), - S1("4021", "0430", "00000000"), - S1("4421", "0430", "01000000"), - S1("4821", "0430", "10000000"), - S1("4C21", "0430", "01000000"), - S1("5021", "0430", "01000000"), - S1("5421", "0430", "00000000"), - S1("5821", "0430", "01000000"), - S1("5C21", "0430", "1F000000"), - S1("6021", "0430", "0F000000"), - S1("8021", "0430", "00000000"), - S1("8421", "0430", "01000000"), - S1("8821", "0430", "10000000"), - S1("8C21", "0430", "01000000"), - S1("9021", "0430", "01000000"), - S1("9421", "0430", "00000000"), - S1("9821", "0430", "01000000"), - S1("9C21", "0430", "1F000000"), - S1("A021", "0430", "0F000000"), - S1("C021", "0430", "00000000"), - S1("C421", "0430", "01000000"), - S1("C821", "0430", "10000000"), - S1("CC21", "0430", "01000000"), - S1("D021", "0430", "01000000"), - S1("D421", "0430", "00000000"), - S1("D821", "0430", "01000000"), - S1("DC21", "0430", "1F000000"), - S1("E021", "0430", "0F000000"), - S1("A020", "0430", "EFE10000"), - S1("A420", "0430", "00000000"), - S1("A820", "0430", "FE210000"), - S1("B020", "0430", "00000000"), - S1("C420", "0430", "47000000"), - S1("C820", "0430", "00000000"), - S1("CC20", "0430", "20000000"), - S1("38A0", "0038", "5CA30000"), - S1("0000", "0038", "02000000"), - S1("0400", "0038", "00080000"), - S1("0800", "0038", "00120000"), - S1("0C00", "0038", "01030200"), - S1("1000", "0038", "01070200"), - S1("1400", "0038", "0C0C8A00"), + /* NOTE: replacing this by vfs301_0220_BLOB1 seems to not cause problems */ + S1 ("0420", "0430", "00000000"), + S1 ("1820", "0430", "00000000"), + S1 ("2020", "0430", "08008000"), + S1 ("2420", "0430", "0000FF01"), + S1 ("2C20", "0430", "01000000"), + S1 ("4020", "0430", "AD010000"), + S1 ("4420", "0430", "AD010000"), + S1 ("4820", "0430", "AD010000"), + S1 ("4C20", "0430", "FF030000"), + S1 ("5020", "0430", "00005003"), + S1 ("5420", "0430", "013E0200"), + S1 ("0021", "0430", "14000000"), + S1 ("0421", "0430", "01000000"), + S1 ("0821", "0430", "01000000"), + S1 ("0C21", "0430", "01000000"), + S1 ("1021", "0430", "01000000"), + S1 ("1421", "0430", "01000000"), + S1 ("1821", "0430", "01000000"), + S1 ("1C21", "0430", "12000000"), + S1 ("2021", "0430", "04000000"), + S1 ("4021", "0430", "00000000"), + S1 ("4421", "0430", "01000000"), + S1 ("4821", "0430", "10000000"), + S1 ("4C21", "0430", "01000000"), + S1 ("5021", "0430", "01000000"), + S1 ("5421", "0430", "00000000"), + S1 ("5821", "0430", "01000000"), + S1 ("5C21", "0430", "1F000000"), + S1 ("6021", "0430", "0F000000"), + S1 ("8021", "0430", "00000000"), + S1 ("8421", "0430", "01000000"), + S1 ("8821", "0430", "10000000"), + S1 ("8C21", "0430", "01000000"), + S1 ("9021", "0430", "01000000"), + S1 ("9421", "0430", "00000000"), + S1 ("9821", "0430", "01000000"), + S1 ("9C21", "0430", "1F000000"), + S1 ("A021", "0430", "0F000000"), + S1 ("C021", "0430", "00000000"), + S1 ("C421", "0430", "01000000"), + S1 ("C821", "0430", "10000000"), + S1 ("CC21", "0430", "01000000"), + S1 ("D021", "0430", "01000000"), + S1 ("D421", "0430", "00000000"), + S1 ("D821", "0430", "01000000"), + S1 ("DC21", "0430", "1F000000"), + S1 ("E021", "0430", "0F000000"), + S1 ("A020", "0430", "EFE10000"), + S1 ("A420", "0430", "00000000"), + S1 ("A820", "0430", "FE210000"), + S1 ("B020", "0430", "00000000"), + S1 ("C420", "0430", "47000000"), + S1 ("C820", "0430", "00000000"), + S1 ("CC20", "0430", "20000000"), + S1 ("38A0", "0038", "5CA30000"), + S1 ("0000", "0038", "02000000"), + S1 ("0400", "0038", "00080000"), + S1 ("0800", "0038", "00120000"), + S1 ("0C00", "0038", "01030200"), + S1 ("1000", "0038", "01070200"), + S1 ("1400", "0038", "0C0C8A00"), - /* TODO: looks like that removing this whole packet doesn't cause - * any troubles. */ - PACKET("0200", "8005", - "FFF98720" - "83488420" - "83488420" - "83488420" - "83488420" - "83488420" - "83488420" - "83488420" - "83488420" - "83488420" - "83488420" - "85480420" - "87480420" - "89480420" - "8B480420" - "8D480420" - "8F480420" - "91480420" - "93480420" - "95480420" - "97480420" - "99480420" - "9B480420" - "9D480420" - "9F480420" - "A1480420" - "A3480420" - "A3480400" - "855A0420" - "875A0420" - "895A0420" - "8B5A0420" - "8D5A0420" - "8F5A0420" - "915A0420" - "935A0420" - "955A0420" - "975A0420" - "995A0420" - "9B5A0420" - "9D5A0420" - "9F5A0420" - "A15A0420" - "A35A0420" - "A35A0400" - "856C0420" - "876C0420" - "896C0420" - "8B6C0420" - "8D6C0420" - "8F6C0420" - "916C0420" - "936C0420" - "956C0420" - "976C0420" - "996C0420" - "9B6C0420" - "9D6C0420" - "9F6C0420" - "A16C0420" - "A36C0420" - "A36C0400" - "86480420" - "88480420" - "8A480420" - "8C480420" - "8E480420" - "90480420" - "92480420" - "94480420" - "96480420" - "98480420" - "9A480420" - "9C480420" - "9E480420" - "A0480420" - "A2480420" - "A4480420" - "A4480400" - "865A0420" - "885A0420" - "8A5A0420" - "8C5A0420" - "8E5A0420" - "905A0420" - "925A0420" - "945A0420" - "965A0420" - "985A0420" - "9A5A0420" - "9C5A0420" - "9E5A0420" - "A05A0420" - "A25A0420" - "A45A0420" - "A45A0400" - "866C0420" - "886C0420" - "8A6C0420" - "8C6C0420" - "8E6C0420" - "906C0420" - "926C0420" - "946C0420" - "966C0420" - "986C0420" - "9A6C0420" - "9C6C0420" - "9E6C0420" - "A06C0420" - "A26C0420" - "A46C0420" - "A46C0400" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" "83688420" "83688420" - "83688420" "83688420" - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() - ), - S3("10035109"), - S1("0020", "0430", "80000000"), + /* TODO: looks like that removing this whole packet doesn't cause + * any troubles. */ + PACKET ("0200", "8005", + "FFF98720" + "83488420" + "83488420" + "83488420" + "83488420" + "83488420" + "83488420" + "83488420" + "83488420" + "83488420" + "83488420" + "85480420" + "87480420" + "89480420" + "8B480420" + "8D480420" + "8F480420" + "91480420" + "93480420" + "95480420" + "97480420" + "99480420" + "9B480420" + "9D480420" + "9F480420" + "A1480420" + "A3480420" + "A3480400" + "855A0420" + "875A0420" + "895A0420" + "8B5A0420" + "8D5A0420" + "8F5A0420" + "915A0420" + "935A0420" + "955A0420" + "975A0420" + "995A0420" + "9B5A0420" + "9D5A0420" + "9F5A0420" + "A15A0420" + "A35A0420" + "A35A0400" + "856C0420" + "876C0420" + "896C0420" + "8B6C0420" + "8D6C0420" + "8F6C0420" + "916C0420" + "936C0420" + "956C0420" + "976C0420" + "996C0420" + "9B6C0420" + "9D6C0420" + "9F6C0420" + "A16C0420" + "A36C0420" + "A36C0400" + "86480420" + "88480420" + "8A480420" + "8C480420" + "8E480420" + "90480420" + "92480420" + "94480420" + "96480420" + "98480420" + "9A480420" + "9C480420" + "9E480420" + "A0480420" + "A2480420" + "A4480420" + "A4480400" + "865A0420" + "885A0420" + "8A5A0420" + "8C5A0420" + "8E5A0420" + "905A0420" + "925A0420" + "945A0420" + "965A0420" + "985A0420" + "9A5A0420" + "9C5A0420" + "9E5A0420" + "A05A0420" + "A25A0420" + "A45A0420" + "A45A0400" + "866C0420" + "886C0420" + "8A6C0420" + "8C6C0420" + "8E6C0420" + "906C0420" + "926C0420" + "946C0420" + "966C0420" + "986C0420" + "9A6C0420" + "9C6C0420" + "9E6C0420" + "A06C0420" + "A26C0420" + "A46C0420" + "A46C0400" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" "83688420" "83688420" + "83688420" "83688420" + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () + ), + S3 ("10035109"), + S1 ("0020", "0430", "80000000"), - TERM(), + TERM (), - NULL + NULL }; const char *vfs301_next_scan_template[] = { - PACKET("0220", "0100", "00"), + PACKET ("0220", "0100", "00"), - vfs301_0220_BLOB1, + vfs301_0220_BLOB1, - vfs301_0220_BLOB2, + vfs301_0220_BLOB2, - TERM(), + TERM (), - S4("DEAD"), + S4 ("DEAD"), - NULL + NULL }; const char *vfs301_0220_02[] = { - "0220011400", + "0220011400", - vfs301_0220_BLOB1, + vfs301_0220_BLOB1, - vfs301_0220_BLOB2, + vfs301_0220_BLOB2, - TERM(), + TERM (), - NULL + NULL }; const char *vfs301_0220_03[] = { - "0220011400", + "0220011400", - vfs301_0220_BLOB1, + vfs301_0220_BLOB1, - "17000000", + "17000000", - vfs301_0220_BLOB2, + vfs301_0220_BLOB2, - TERM(), + TERM (), - NULL + NULL }; const char *vfs301_02D0_01[] = { - "02D0003800", + "02D0003800", - S1("0420", "0430", "00000000"), - S1("1820", "0430", "01807800"), - S1("2020", "0430", "08008000"), - S1("2420", "0430", "0000FF01"), - S1("2C20", "0430", "01000000"), - S1("4020", "0430", "FF030000"), - S1("4420", "0430", "E6030000"), - S1("4820", "0430", "E7030000"), - S1("4C20", "0430", "E8030000"), - S1("5020", "0430", "00025802"), - S1("5420", "0430", "00E20100"), - S1("0021", "0430", "00000000"), - S1("0421", "0430", "01000000"), - S1("0821", "0430", "01000000"), - S1("0C21", "0430", "01000000"), - S1("1021", "0430", "01000000"), - S1("1421", "0430", "01000000"), - S1("1821", "0430", "01000000"), - S1("1C21", "0430", "1F000000"), - S1("2021", "0430", "01000000"), - S1("4021", "0430", "00000000"), - S1("4421", "0430", "01000000"), - S1("4821", "0430", "01000000"), - S1("4C21", "0430", "01000000"), - S1("5021", "0430", "01000000"), - S1("5421", "0430", "01000000"), - S1("5821", "0430", "01000000"), - S1("5C21", "0430", "1F000000"), - S1("6021", "0430", "01000000"), - S1("8021", "0430", "00000000"), - S1("8421", "0430", "01000000"), - S1("8821", "0430", "01000000"), - S1("8C21", "0430", "01000000"), - S1("9021", "0430", "01000000"), - S1("9421", "0430", "01000000"), - S1("9821", "0430", "01000000"), - S1("9C21", "0430", "1F000000"), - S1("A021", "0430", "01000000"), - S1("C021", "0430", "00000000"), - S1("C421", "0430", "01000000"), - S1("C821", "0430", "01000000"), - S1("CC21", "0430", "01000000"), - S1("D021", "0430", "01000000"), - S1("D421", "0430", "01000000"), - S1("D821", "0430", "01000000"), - S1("DC21", "0430", "1F000000"), - S1("E021", "0430", "01000000"), - S1("A020", "0430", "EFE10000"), - S1("A420", "0430", "00000000"), - vfs301_02D0_BLOB1, - vfs301_02D0_ALIGNED_BLOB, + S1 ("0420", "0430", "00000000"), + S1 ("1820", "0430", "01807800"), + S1 ("2020", "0430", "08008000"), + S1 ("2420", "0430", "0000FF01"), + S1 ("2C20", "0430", "01000000"), + S1 ("4020", "0430", "FF030000"), + S1 ("4420", "0430", "E6030000"), + S1 ("4820", "0430", "E7030000"), + S1 ("4C20", "0430", "E8030000"), + S1 ("5020", "0430", "00025802"), + S1 ("5420", "0430", "00E20100"), + S1 ("0021", "0430", "00000000"), + S1 ("0421", "0430", "01000000"), + S1 ("0821", "0430", "01000000"), + S1 ("0C21", "0430", "01000000"), + S1 ("1021", "0430", "01000000"), + S1 ("1421", "0430", "01000000"), + S1 ("1821", "0430", "01000000"), + S1 ("1C21", "0430", "1F000000"), + S1 ("2021", "0430", "01000000"), + S1 ("4021", "0430", "00000000"), + S1 ("4421", "0430", "01000000"), + S1 ("4821", "0430", "01000000"), + S1 ("4C21", "0430", "01000000"), + S1 ("5021", "0430", "01000000"), + S1 ("5421", "0430", "01000000"), + S1 ("5821", "0430", "01000000"), + S1 ("5C21", "0430", "1F000000"), + S1 ("6021", "0430", "01000000"), + S1 ("8021", "0430", "00000000"), + S1 ("8421", "0430", "01000000"), + S1 ("8821", "0430", "01000000"), + S1 ("8C21", "0430", "01000000"), + S1 ("9021", "0430", "01000000"), + S1 ("9421", "0430", "01000000"), + S1 ("9821", "0430", "01000000"), + S1 ("9C21", "0430", "1F000000"), + S1 ("A021", "0430", "01000000"), + S1 ("C021", "0430", "00000000"), + S1 ("C421", "0430", "01000000"), + S1 ("C821", "0430", "01000000"), + S1 ("CC21", "0430", "01000000"), + S1 ("D021", "0430", "01000000"), + S1 ("D421", "0430", "01000000"), + S1 ("D821", "0430", "01000000"), + S1 ("DC21", "0430", "1F000000"), + S1 ("E021", "0430", "01000000"), + S1 ("A020", "0430", "EFE10000"), + S1 ("A420", "0430", "00000000"), + vfs301_02D0_BLOB1, + vfs301_02D0_ALIGNED_BLOB, - PACKET("0C00", "0100", "00"), - PACKET("0D00", "E800", - "C0000000080000000200000000000000" - "00000050D52200180000009CCE156100" - "0000002003000000" - "0C00003800080000FF00FFFF" - "0C00003800090000FF00FFFF" - "0C00003800020000FF00FFFF" - "0C00003800030000FF00FFFF" - "0C00003800040000FF00FFFF" - "0C00003800050000FF00FFFF" - "0C00003800060000FF00FFFF" - "0C00003800070000FF00FFFF" - "1000003800040000FF00FFFF" - "1000003800050000FF00FFFF" - "1000003800060000FF00FFFF" - "1000003800070000FF00FFFF" - "1000003800080000FF00FFFF" - "1000003800090000FF00FFFF" - "10000038000A0000FF00FFFF" - "10000038000B0000FF00FFFF"), - PACKET("0E00", "E000", - "000100010101011F010000000000FF01" - "000101010101011F010000000000FF01" - "000102010101011F010000000000FF01" - "000104010101011F010000000000FF01" - "000108010101011F010000000000FF01" - "000110010101011F010000000000FF01" - "000110010201011F010000000000FF01" - "000110010401011F010000000000FF01" - "000110010801011F010000000000FF01" - "000110011001011F010000000000FF01" - "000110011001021F010000000000FF01" - "000110011001041F010000000000FF01" - "000110011001081F010000000000FF01" - "000110011001101F010000000000FF01" - "0F000100021000010001110002000800" ), - PACKET("1200", "0100", "0E"), + PACKET ("0C00", "0100", "00"), + PACKET ("0D00", "E800", + "C0000000080000000200000000000000" + "00000050D52200180000009CCE156100" + "0000002003000000" + "0C00003800080000FF00FFFF" + "0C00003800090000FF00FFFF" + "0C00003800020000FF00FFFF" + "0C00003800030000FF00FFFF" + "0C00003800040000FF00FFFF" + "0C00003800050000FF00FFFF" + "0C00003800060000FF00FFFF" + "0C00003800070000FF00FFFF" + "1000003800040000FF00FFFF" + "1000003800050000FF00FFFF" + "1000003800060000FF00FFFF" + "1000003800070000FF00FFFF" + "1000003800080000FF00FFFF" + "1000003800090000FF00FFFF" + "10000038000A0000FF00FFFF" + "10000038000B0000FF00FFFF"), + PACKET ("0E00", "E000", + "000100010101011F010000000000FF01" + "000101010101011F010000000000FF01" + "000102010101011F010000000000FF01" + "000104010101011F010000000000FF01" + "000108010101011F010000000000FF01" + "000110010101011F010000000000FF01" + "000110010201011F010000000000FF01" + "000110010401011F010000000000FF01" + "000110010801011F010000000000FF01" + "000110011001011F010000000000FF01" + "000110011001021F010000000000FF01" + "000110011001041F010000000000FF01" + "000110011001081F010000000000FF01" + "000110011001101F010000000000FF01" + "0F000100021000010001110002000800" ), + PACKET ("1200", "0100", "0E"), - TERM(), + TERM (), - NULL + NULL }; const char *vfs301_02D0_02[] = { - "02D0000001", + "02D0000001", - S1("0420", "0430", "00000000"), - S1("1820", "0430", "01806300"), - S1("2020", "0430", "08008000"), - S1("2420", "0430", "0000FF01"), - S1("2C20", "0430", "01000000"), - S1("4020", "0430", "FF030000"), - S1("4420", "0430", "E6030000"), - S1("4820", "0430", "E7030000"), - S1("4C20", "0430", "E8030000"), - S1("5020", "0430", "00025802"), - S1("5420", "0430", "008E0100"), - S1("0021", "0430", "00000000"), - S1("0421", "0430", "00000000"), - S1("0821", "0430", "00000000"), - S1("0C21", "0430", "00000000"), - S1("1021", "0430", "00000000"), - S1("1421", "0430", "00000000"), - S1("1821", "0430", "00000000"), - S1("1C21", "0430", "1F000000"), - S1("2021", "0430", "01000000"), - S1("4021", "0430", "00000000"), - S1("4421", "0430", "00000000"), - S1("4821", "0430", "00000000"), - S1("4C21", "0430", "00000000"), - S1("5021", "0430", "00000000"), - S1("5421", "0430", "00000000"), - S1("5821", "0430", "00000000"), - S1("5C21", "0430", "1F000000"), - S1("6021", "0430", "01000000"), - S1("8021", "0430", "00000000"), - S1("8421", "0430", "00000000"), - S1("8821", "0430", "00000000"), - S1("8C21", "0430", "00000000"), - S1("9021", "0430", "00000000"), - S1("9421", "0430", "00000000"), - S1("9821", "0430", "00000000"), - S1("9C21", "0430", "1F000000"), - S1("A021", "0430", "01000000"), - S1("C021", "0430", "00000000"), - S1("C421", "0430", "00000000"), - S1("C821", "0430", "00000000"), - S1("CC21", "0430", "00000000"), - S1("D021", "0430", "00000000"), - S1("D421", "0430", "00000000"), - S1("D821", "0430", "00000000"), - S1("DC21", "0430", "1F000000"), - S1("E021", "0430", "01000000"), - S1("A020", "0430", "EFE10000"), - S1("A420", "0430", "00400000"), - vfs301_02D0_BLOB1, - vfs301_02D0_ALIGNED_BLOB, + S1 ("0420", "0430", "00000000"), + S1 ("1820", "0430", "01806300"), + S1 ("2020", "0430", "08008000"), + S1 ("2420", "0430", "0000FF01"), + S1 ("2C20", "0430", "01000000"), + S1 ("4020", "0430", "FF030000"), + S1 ("4420", "0430", "E6030000"), + S1 ("4820", "0430", "E7030000"), + S1 ("4C20", "0430", "E8030000"), + S1 ("5020", "0430", "00025802"), + S1 ("5420", "0430", "008E0100"), + S1 ("0021", "0430", "00000000"), + S1 ("0421", "0430", "00000000"), + S1 ("0821", "0430", "00000000"), + S1 ("0C21", "0430", "00000000"), + S1 ("1021", "0430", "00000000"), + S1 ("1421", "0430", "00000000"), + S1 ("1821", "0430", "00000000"), + S1 ("1C21", "0430", "1F000000"), + S1 ("2021", "0430", "01000000"), + S1 ("4021", "0430", "00000000"), + S1 ("4421", "0430", "00000000"), + S1 ("4821", "0430", "00000000"), + S1 ("4C21", "0430", "00000000"), + S1 ("5021", "0430", "00000000"), + S1 ("5421", "0430", "00000000"), + S1 ("5821", "0430", "00000000"), + S1 ("5C21", "0430", "1F000000"), + S1 ("6021", "0430", "01000000"), + S1 ("8021", "0430", "00000000"), + S1 ("8421", "0430", "00000000"), + S1 ("8821", "0430", "00000000"), + S1 ("8C21", "0430", "00000000"), + S1 ("9021", "0430", "00000000"), + S1 ("9421", "0430", "00000000"), + S1 ("9821", "0430", "00000000"), + S1 ("9C21", "0430", "1F000000"), + S1 ("A021", "0430", "01000000"), + S1 ("C021", "0430", "00000000"), + S1 ("C421", "0430", "00000000"), + S1 ("C821", "0430", "00000000"), + S1 ("CC21", "0430", "00000000"), + S1 ("D021", "0430", "00000000"), + S1 ("D421", "0430", "00000000"), + S1 ("D821", "0430", "00000000"), + S1 ("DC21", "0430", "1F000000"), + S1 ("E021", "0430", "01000000"), + S1 ("A020", "0430", "EFE10000"), + S1 ("A420", "0430", "00400000"), + vfs301_02D0_BLOB1, + vfs301_02D0_ALIGNED_BLOB, - PACKET("0C00", "0100", "03"), - PACKET("0D00", "2800", "C82004300000000001000000FF00000000FFFFFF01000000C8200430000000000000003001000000"), - PACKET("0E00", "1000", "000101010100011F0800000000000001"), - PACKET("0F00", "0100", "01"), - PACKET("1000", "0100", "01"), - PACKET("1100", "0200", "0001"), - vfs301_02D0_BLOB4, + PACKET ("0C00", "0100", "03"), + PACKET ("0D00", "2800", "C82004300000000001000000FF00000000FFFFFF01000000C8200430000000000000003001000000"), + PACKET ("0E00", "1000", "000101010100011F0800000000000001"), + PACKET ("0F00", "0100", "01"), + PACKET ("1000", "0100", "01"), + PACKET ("1100", "0200", "0001"), + vfs301_02D0_BLOB4, - TERM(), + TERM (), - NULL + NULL }; const char *vfs301_02D0_03[] = { - "02D0006000", + "02D0006000", - S1("0420", "0430", "00000000"), - S1("1820", "0430", "01806300"), - S1("2020", "0430", "08008000"), - S1("2420", "0430", "0000FF01"), - S1("2C20", "0430", "01000000"), - S1("4020", "0430", "FF030000"), - S1("4420", "0430", "E6030000"), - S1("4820", "0430", "E7030000"), - S1("4C20", "0430", "E8030000"), - S1("5020", "0430", "00025802"), - S1("5420", "0430", "008E0100"), - S1("0021", "0430", "00000000"), - S1("0421", "0430", "01000000"), - S1("0821", "0430", "01000000"), - S1("0C21", "0430", "01000000"), - S1("1021", "0430", "01000000"), - S1("1421", "0430", "01000000"), - S1("1821", "0430", "01000000"), - S1("1C21", "0430", "1F000000"), - S1("2021", "0430", "05000000"), - S1("4021", "0430", "00000000"), - S1("4421", "0430", "01000000"), - S1("4821", "0430", "01000000"), - S1("4C21", "0430", "01000000"), - S1("5021", "0430", "01000000"), - S1("5421", "0430", "01000000"), - S1("5821", "0430", "01000000"), - S1("5C21", "0430", "1F000000"), - S1("6021", "0430", "05000000"), - S1("8021", "0430", "00000000"), - S1("8421", "0430", "01000000"), - S1("8821", "0430", "01000000"), - S1("8C21", "0430", "01000000"), - S1("9021", "0430", "01000000"), - S1("9421", "0430", "01000000"), - S1("9821", "0430", "01000000"), - S1("9C21", "0430", "1F000000"), - S1("A021", "0430", "05000000"), - S1("C021", "0430", "00000000"), - S1("C421", "0430", "01000000"), - S1("C821", "0430", "01000000"), - S1("CC21", "0430", "01000000"), - S1("D021", "0430", "01000000"), - S1("D421", "0430", "01000000"), - S1("D821", "0430", "01000000"), - S1("DC21", "0430", "1F000000"), - S1("E021", "0430", "05000000"), - S1("A020", "0430", "EFE10000"), - S1("A420", "0430", "00000000"), - vfs301_02D0_BLOB1, - vfs301_02D0_ALIGNED_BLOB, + S1 ("0420", "0430", "00000000"), + S1 ("1820", "0430", "01806300"), + S1 ("2020", "0430", "08008000"), + S1 ("2420", "0430", "0000FF01"), + S1 ("2C20", "0430", "01000000"), + S1 ("4020", "0430", "FF030000"), + S1 ("4420", "0430", "E6030000"), + S1 ("4820", "0430", "E7030000"), + S1 ("4C20", "0430", "E8030000"), + S1 ("5020", "0430", "00025802"), + S1 ("5420", "0430", "008E0100"), + S1 ("0021", "0430", "00000000"), + S1 ("0421", "0430", "01000000"), + S1 ("0821", "0430", "01000000"), + S1 ("0C21", "0430", "01000000"), + S1 ("1021", "0430", "01000000"), + S1 ("1421", "0430", "01000000"), + S1 ("1821", "0430", "01000000"), + S1 ("1C21", "0430", "1F000000"), + S1 ("2021", "0430", "05000000"), + S1 ("4021", "0430", "00000000"), + S1 ("4421", "0430", "01000000"), + S1 ("4821", "0430", "01000000"), + S1 ("4C21", "0430", "01000000"), + S1 ("5021", "0430", "01000000"), + S1 ("5421", "0430", "01000000"), + S1 ("5821", "0430", "01000000"), + S1 ("5C21", "0430", "1F000000"), + S1 ("6021", "0430", "05000000"), + S1 ("8021", "0430", "00000000"), + S1 ("8421", "0430", "01000000"), + S1 ("8821", "0430", "01000000"), + S1 ("8C21", "0430", "01000000"), + S1 ("9021", "0430", "01000000"), + S1 ("9421", "0430", "01000000"), + S1 ("9821", "0430", "01000000"), + S1 ("9C21", "0430", "1F000000"), + S1 ("A021", "0430", "05000000"), + S1 ("C021", "0430", "00000000"), + S1 ("C421", "0430", "01000000"), + S1 ("C821", "0430", "01000000"), + S1 ("CC21", "0430", "01000000"), + S1 ("D021", "0430", "01000000"), + S1 ("D421", "0430", "01000000"), + S1 ("D821", "0430", "01000000"), + S1 ("DC21", "0430", "1F000000"), + S1 ("E021", "0430", "05000000"), + S1 ("A020", "0430", "EFE10000"), + S1 ("A420", "0430", "00000000"), + vfs301_02D0_BLOB1, + vfs301_02D0_ALIGNED_BLOB, - PACKET("0C00", "0100", "02"), - PACKET("0D00", "2800", "1400003800006E000000010000008F00FFFF00FF01000000000002000000010000000F0002000000"), - PACKET("0E00", "1000", "00000000000000000500000000000001"), - PACKET("0F00", "0100", "01"), - PACKET("1000", "0100", "02") - PACKET("1100", "0200", "6000"), - vfs301_02D0_BLOB4, - S1("C820", "0430", "07000000"), + PACKET ("0C00", "0100", "02"), + PACKET ("0D00", "2800", "1400003800006E000000010000008F00FFFF00FF01000000000002000000010000000F0002000000"), + PACKET ("0E00", "1000", "00000000000000000500000000000001"), + PACKET ("0F00", "0100", "01"), + PACKET ("1000", "0100", "02") + PACKET ("1100", "0200", "6000"), + vfs301_02D0_BLOB4, + S1 ("C820", "0430", "07000000"), - TERM(), + TERM (), - NULL + NULL }; const char *vfs301_02D0_04[] = { - "02D0001C00", + "02D0001C00", - S1("0420", "0430", "00000000"), - S1("1820", "0430", "01806300"), - S1("2020", "0430", "08008000"), - S1("2420", "0430", "0000FF01"), - S1("2C20", "0430", "01000000"), - S1("4020", "0430", "FF030000"), - S1("4420", "0430", "E7030000"), - S1("4820", "0430", "FF030000"), - S1("4C20", "0430", "FF030000"), - S1("5020", "0430", "00025802"), - S1("5420", "0430", "008E0100"), - S1("0021", "0430", "30000000"), - S1("0421", "0430", "01000000"), - S1("0821", "0430", "01000000"), - S1("0C21", "0430", "01000000"), - S1("1021", "0430", "01000000"), - S1("1421", "0430", "01000000"), - S1("1821", "0430", "01000000"), - S1("1C21", "0430", "1F000000"), - S1("2021", "0430", "00000000"), - S1("4021", "0430", "30000000"), - S1("4421", "0430", "01000000"), - S1("4821", "0430", "01000000"), - S1("4C21", "0430", "01000000"), - S1("5021", "0430", "01000000"), - S1("5421", "0430", "01000000"), - S1("5821", "0430", "01000000"), - S1("5C21", "0430", "1F000000"), - S1("6021", "0430", "00000000"), - S1("8021", "0430", "30000000"), - S1("8421", "0430", "01000000"), - S1("8821", "0430", "01000000"), - S1("8C21", "0430", "01000000"), - S1("9021", "0430", "01000000"), - S1("9421", "0430", "01000000"), - S1("9821", "0430", "01000000"), - S1("9C21", "0430", "1F000000"), - S1("A021", "0430", "00000000"), - S1("C021", "0430", "30000000"), - S1("C421", "0430", "01000000"), - S1("C821", "0430", "01000000"), - S1("CC21", "0430", "01000000"), - S1("D021", "0430", "01000000"), - S1("D421", "0430", "01000000"), - S1("D821", "0430", "01000000"), - S1("DC21", "0430", "1F000000"), - S1("E021", "0430", "00000000"), - S1("A020", "0430", "EFE10000"), - S1("A420", "0430", "00000000"), - vfs301_02D0_BLOB1, + S1 ("0420", "0430", "00000000"), + S1 ("1820", "0430", "01806300"), + S1 ("2020", "0430", "08008000"), + S1 ("2420", "0430", "0000FF01"), + S1 ("2C20", "0430", "01000000"), + S1 ("4020", "0430", "FF030000"), + S1 ("4420", "0430", "E7030000"), + S1 ("4820", "0430", "FF030000"), + S1 ("4C20", "0430", "FF030000"), + S1 ("5020", "0430", "00025802"), + S1 ("5420", "0430", "008E0100"), + S1 ("0021", "0430", "30000000"), + S1 ("0421", "0430", "01000000"), + S1 ("0821", "0430", "01000000"), + S1 ("0C21", "0430", "01000000"), + S1 ("1021", "0430", "01000000"), + S1 ("1421", "0430", "01000000"), + S1 ("1821", "0430", "01000000"), + S1 ("1C21", "0430", "1F000000"), + S1 ("2021", "0430", "00000000"), + S1 ("4021", "0430", "30000000"), + S1 ("4421", "0430", "01000000"), + S1 ("4821", "0430", "01000000"), + S1 ("4C21", "0430", "01000000"), + S1 ("5021", "0430", "01000000"), + S1 ("5421", "0430", "01000000"), + S1 ("5821", "0430", "01000000"), + S1 ("5C21", "0430", "1F000000"), + S1 ("6021", "0430", "00000000"), + S1 ("8021", "0430", "30000000"), + S1 ("8421", "0430", "01000000"), + S1 ("8821", "0430", "01000000"), + S1 ("8C21", "0430", "01000000"), + S1 ("9021", "0430", "01000000"), + S1 ("9421", "0430", "01000000"), + S1 ("9821", "0430", "01000000"), + S1 ("9C21", "0430", "1F000000"), + S1 ("A021", "0430", "00000000"), + S1 ("C021", "0430", "30000000"), + S1 ("C421", "0430", "01000000"), + S1 ("C821", "0430", "01000000"), + S1 ("CC21", "0430", "01000000"), + S1 ("D021", "0430", "01000000"), + S1 ("D421", "0430", "01000000"), + S1 ("D821", "0430", "01000000"), + S1 ("DC21", "0430", "1F000000"), + S1 ("E021", "0430", "00000000"), + S1 ("A020", "0430", "EFE10000"), + S1 ("A420", "0430", "00000000"), + vfs301_02D0_BLOB1, - /* TODO: looks like that removing this whole packet doesn't cause - * any troubles. */ - PACKET("0200", "8005", - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - "FFF30720" "80F20720" "FFF30720" "80F20720" - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - ), + /* TODO: looks like that removing this whole packet doesn't cause + * any troubles. */ + PACKET ("0200", "8005", + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + "FFF30720" "80F20720" "FFF30720" "80F20720" + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + ), - S3("1003181C"), - S1("0020", "0430", "80000000"), + S3 ("1003181C"), + S1 ("0020", "0430", "80000000"), - PACKET("0C00", "0100", "00"), - PACKET("0D00", "2800", "A02104300100000001000000010000000100000001000000A0210430000000000031003801000000"), - PACKET("0E00", "E000", - "00010001000100000000000000007E00" - "00010101000100000000000000007E00" - "00010101010100000000000000007E00" - "00010101010101000000000000007E00" - "00010201010101000000000000007E00" - "00010401010101000000000000007E00" - "00010801010101000000000000007E00" - "00011001010101000000000000007E00" - "00011001020101000000000000007E00" - "00011001040101000000000000007E00" - "00011001080101000000000000007E00" - "00011001100102000000000000007E00" - "00011001100104000000000000007E00" - "00011001100108000000000000007E00"), - PACKET("0F00", "0100", "01"), - PACKET("1000", "0100", "02"), - PACKET("1100", "0200", "0200"), - PACKET("1200", "0100", "0E"), - S2("0C20FF00FFFF0000000000030000"), - S2("1020FF00FFFF0000000000070000"), - S1("0421", "0430", "01000000"), - S1("0821", "0430", "02000000"), - S1("0C21", "0430", "01000000"), - S1("1021", "0430", "01000000"), - S1("1421", "0430", "01000000"), - S1("1821", "0430", "01000000"), - S1("4421", "0430", "01000000"), - S1("4821", "0430", "02000000"), - S1("4C21", "0430", "01000000"), - S1("5021", "0430", "01000000"), - S1("5421", "0430", "01000000"), - S1("5821", "0430", "01000000"), - S1("C820", "0430", "07000000"), - S2("1420FFFF00FF0000000000008800"), + PACKET ("0C00", "0100", "00"), + PACKET ("0D00", "2800", "A02104300100000001000000010000000100000001000000A0210430000000000031003801000000"), + PACKET ("0E00", "E000", + "00010001000100000000000000007E00" + "00010101000100000000000000007E00" + "00010101010100000000000000007E00" + "00010101010101000000000000007E00" + "00010201010101000000000000007E00" + "00010401010101000000000000007E00" + "00010801010101000000000000007E00" + "00011001010101000000000000007E00" + "00011001020101000000000000007E00" + "00011001040101000000000000007E00" + "00011001080101000000000000007E00" + "00011001100102000000000000007E00" + "00011001100104000000000000007E00" + "00011001100108000000000000007E00"), + PACKET ("0F00", "0100", "01"), + PACKET ("1000", "0100", "02"), + PACKET ("1100", "0200", "0200"), + PACKET ("1200", "0100", "0E"), + S2 ("0C20FF00FFFF0000000000030000"), + S2 ("1020FF00FFFF0000000000070000"), + S1 ("0421", "0430", "01000000"), + S1 ("0821", "0430", "02000000"), + S1 ("0C21", "0430", "01000000"), + S1 ("1021", "0430", "01000000"), + S1 ("1421", "0430", "01000000"), + S1 ("1821", "0430", "01000000"), + S1 ("4421", "0430", "01000000"), + S1 ("4821", "0430", "02000000"), + S1 ("4C21", "0430", "01000000"), + S1 ("5021", "0430", "01000000"), + S1 ("5421", "0430", "01000000"), + S1 ("5821", "0430", "01000000"), + S1 ("C820", "0430", "07000000"), + S2 ("1420FFFF00FF0000000000008800"), - TERM(), + TERM (), - NULL + NULL }; /* Sorry had to replace BLOB3 (was a fragment!) */ const char *vfs301_02D0_05[] = { - "02D0002000", + "02D0002000", - S1("0420", "0430", "00000000"), - S1("1820", "0430", "01806300"), - S1("2020", "0430", "08008000"), - S1("2420", "0430", "0000FF01"), - S1("2C20", "0430", "01000000"), - S1("4020", "0430", "FF030000"), - S1("4420", "0430", "E7030000"), - S1("4820", "0430", "FF030000"), - S1("4C20", "0430", "FF030000"), - S1("5020", "0430", "00025802"), - S1("5420", "0430", "008E0100"), - S1("0021", "0430", "30000000"), - S1("0421", "0430", "01000000"), - S1("0821", "0430", "01000000"), - S1("0C21", "0430", "01000000"), - S1("1021", "0430", "00000000"), - S1("1421", "0430", "01000000"), - S1("1821", "0430", "00000000"), - S1("1C21", "0430", "1F000000"), - S1("2021", "0430", "04000000"), - S1("4021", "0430", "30000000"), - S1("4421", "0430", "01000000"), - S1("4821", "0430", "01000000"), - S1("4C21", "0430", "01000000"), - S1("5021", "0430", "00000000"), - S1("5421", "0430", "01000000"), - S1("5821", "0430", "00000000"), - S1("5C21", "0430", "1F000000"), - S1("6021", "0430", "04000000"), - S1("8021", "0430", "30000000"), - S1("8421", "0430", "01000000"), - S1("8821", "0430", "01000000"), - S1("8C21", "0430", "01000000"), - S1("9021", "0430", "00000000"), - S1("9421", "0430", "01000000"), - S1("9821", "0430", "00000000"), - S1("9C21", "0430", "1F000000"), - S1("A021", "0430", "04000000"), - S1("C021", "0430", "30000000"), - S1("C421", "0430", "01000000"), - S1("C821", "0430", "01000000"), - S1("CC21", "0430", "01000000"), - S1("D021", "0430", "00000000"), - S1("D421", "0430", "01000000"), - S1("D821", "0430", "00000000"), - S1("DC21", "0430", "1F000000"), - S1("E021", "0430", "04000000"), - S1("A020", "0430", "EFE10000"), - S1("A420", "0430", "00000000"), - vfs301_02D0_BLOB1, + S1 ("0420", "0430", "00000000"), + S1 ("1820", "0430", "01806300"), + S1 ("2020", "0430", "08008000"), + S1 ("2420", "0430", "0000FF01"), + S1 ("2C20", "0430", "01000000"), + S1 ("4020", "0430", "FF030000"), + S1 ("4420", "0430", "E7030000"), + S1 ("4820", "0430", "FF030000"), + S1 ("4C20", "0430", "FF030000"), + S1 ("5020", "0430", "00025802"), + S1 ("5420", "0430", "008E0100"), + S1 ("0021", "0430", "30000000"), + S1 ("0421", "0430", "01000000"), + S1 ("0821", "0430", "01000000"), + S1 ("0C21", "0430", "01000000"), + S1 ("1021", "0430", "00000000"), + S1 ("1421", "0430", "01000000"), + S1 ("1821", "0430", "00000000"), + S1 ("1C21", "0430", "1F000000"), + S1 ("2021", "0430", "04000000"), + S1 ("4021", "0430", "30000000"), + S1 ("4421", "0430", "01000000"), + S1 ("4821", "0430", "01000000"), + S1 ("4C21", "0430", "01000000"), + S1 ("5021", "0430", "00000000"), + S1 ("5421", "0430", "01000000"), + S1 ("5821", "0430", "00000000"), + S1 ("5C21", "0430", "1F000000"), + S1 ("6021", "0430", "04000000"), + S1 ("8021", "0430", "30000000"), + S1 ("8421", "0430", "01000000"), + S1 ("8821", "0430", "01000000"), + S1 ("8C21", "0430", "01000000"), + S1 ("9021", "0430", "00000000"), + S1 ("9421", "0430", "01000000"), + S1 ("9821", "0430", "00000000"), + S1 ("9C21", "0430", "1F000000"), + S1 ("A021", "0430", "04000000"), + S1 ("C021", "0430", "30000000"), + S1 ("C421", "0430", "01000000"), + S1 ("C821", "0430", "01000000"), + S1 ("CC21", "0430", "01000000"), + S1 ("D021", "0430", "00000000"), + S1 ("D421", "0430", "01000000"), + S1 ("D821", "0430", "00000000"), + S1 ("DC21", "0430", "1F000000"), + S1 ("E021", "0430", "04000000"), + S1 ("A020", "0430", "EFE10000"), + S1 ("A420", "0430", "00000000"), + vfs301_02D0_BLOB1, - /* TODO: looks like that removing this whole packet doesn't cause - * any troubles. */ - PACKET("0200", "8005", - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - "FFF34720" "80F24720" "FFF34720" "80F24720" - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() - Z8() Z8() Z8() Z8() Z8() Z8() Z8() Z8() ), + /* TODO: looks like that removing this whole packet doesn't cause + * any troubles. */ + PACKET ("0200", "8005", + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + "FFF34720" "80F24720" "FFF34720" "80F24720" + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () + Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 () Z8 ()), - S3("1003181C"), - S1("0020", "0430", "80000000") + S3 ("1003181C"), + S1 ("0020", "0430", "80000000") - PACKET("0C00", "0100", "01"), - PACKET("0D00", "2800", "A021043000000000010000000F00000000FFFFFF01000000A0210430000000000000003001000000"), - PACKET("0E00", "1000", "00000000000000000000000000000000"), - PACKET("0F00", "0100", "01"), - PACKET("1000", "0100", "02"), - PACKET("1100", "0200", "2000"), - vfs301_02D0_BLOB4, - S1("C820", "0430", "07000000"), - S2("1420FFFF00FF0000000000008800"), - S1("8421", "0430", "01000000"), - S1("8821", "0430", "01000000"), - S1("8C21", "0430", "01000000"), - S1("9021", "0430", "01000000"), - S1("9421", "0430", "01000000"), - S1("9821", "0430", "01000000"), + PACKET ("0C00", "0100", "01"), + PACKET ("0D00", "2800", "A021043000000000010000000F00000000FFFFFF01000000A0210430000000000000003001000000"), + PACKET ("0E00", "1000", "00000000000000000000000000000000"), + PACKET ("0F00", "0100", "01"), + PACKET ("1000", "0100", "02"), + PACKET ("1100", "0200", "2000"), + vfs301_02D0_BLOB4, + S1 ("C820", "0430", "07000000"), + S2 ("1420FFFF00FF0000000000008800"), + S1 ("8421", "0430", "01000000"), + S1 ("8821", "0430", "01000000"), + S1 ("8C21", "0430", "01000000"), + S1 ("9021", "0430", "01000000"), + S1 ("9421", "0430", "01000000"), + S1 ("9821", "0430", "01000000"), - TERM(), + TERM (), - NULL + NULL }; const char *vfs301_02D0_06[] = { - "02D0002000", + "02D0002000", - S1("0420", "0430", "00000000"), - S1("1820", "0430", "01806300"), - S1("2020", "0430", "08008000"), - S1("2420", "0430", "0000FF01"), - S1("2C20", "0430", "01000000"), - S1("4020", "0430", "FF030000"), - S1("4420", "0430", "E6030000"), - S1("4820", "0430", "E7030000"), - S1("4C20", "0430", "E8030000"), - S1("5020", "0430", "00025802"), - S1("5420", "0430", "008E0100"), - S1("0021", "0430", "00000000"), - S1("0421", "0430", "01000000"), - S1("0821", "0430", "01000000"), - S1("0C21", "0430", "01000000"), - S1("1021", "0430", "01000000"), - S1("1421", "0430", "01000000"), - S1("1821", "0430", "01000000"), - S1("1C21", "0430", "1F000000"), - S1("2021", "0430", "08000000"), - S1("4021", "0430", "00000000"), - S1("4421", "0430", "01000000"), - S1("4821", "0430", "01000000"), - S1("4C21", "0430", "01000000"), - S1("5021", "0430", "01000000"), - S1("5421", "0430", "01000000"), - S1("5821", "0430", "01000000"), - S1("5C21", "0430", "1F000000"), - S1("6021", "0430", "08000000"), - S1("8021", "0430", "00000000"), - S1("8421", "0430", "01000000"), - S1("8821", "0430", "01000000"), - S1("8C21", "0430", "01000000"), - S1("9021", "0430", "01000000"), - S1("9421", "0430", "01000000"), - S1("9821", "0430", "01000000"), - S1("9C21", "0430", "1F000000"), - S1("A021", "0430", "08000000"), - S1("C021", "0430", "00000000"), - S1("C421", "0430", "01000000"), - S1("C821", "0430", "01000000"), - S1("CC21", "0430", "01000000"), - S1("D021", "0430", "01000000"), - S1("D421", "0430", "01000000"), - S1("D821", "0430", "01000000"), - S1("DC21", "0430", "1F000000"), - S1("E021", "0430", "08000000"), - S1("A020", "0430", "EFE10000"), - S1("A420", "0430", "00000000"), - vfs301_02D0_BLOB1, - vfs301_02D0_ALIGNED_BLOB, + S1 ("0420", "0430", "00000000"), + S1 ("1820", "0430", "01806300"), + S1 ("2020", "0430", "08008000"), + S1 ("2420", "0430", "0000FF01"), + S1 ("2C20", "0430", "01000000"), + S1 ("4020", "0430", "FF030000"), + S1 ("4420", "0430", "E6030000"), + S1 ("4820", "0430", "E7030000"), + S1 ("4C20", "0430", "E8030000"), + S1 ("5020", "0430", "00025802"), + S1 ("5420", "0430", "008E0100"), + S1 ("0021", "0430", "00000000"), + S1 ("0421", "0430", "01000000"), + S1 ("0821", "0430", "01000000"), + S1 ("0C21", "0430", "01000000"), + S1 ("1021", "0430", "01000000"), + S1 ("1421", "0430", "01000000"), + S1 ("1821", "0430", "01000000"), + S1 ("1C21", "0430", "1F000000"), + S1 ("2021", "0430", "08000000"), + S1 ("4021", "0430", "00000000"), + S1 ("4421", "0430", "01000000"), + S1 ("4821", "0430", "01000000"), + S1 ("4C21", "0430", "01000000"), + S1 ("5021", "0430", "01000000"), + S1 ("5421", "0430", "01000000"), + S1 ("5821", "0430", "01000000"), + S1 ("5C21", "0430", "1F000000"), + S1 ("6021", "0430", "08000000"), + S1 ("8021", "0430", "00000000"), + S1 ("8421", "0430", "01000000"), + S1 ("8821", "0430", "01000000"), + S1 ("8C21", "0430", "01000000"), + S1 ("9021", "0430", "01000000"), + S1 ("9421", "0430", "01000000"), + S1 ("9821", "0430", "01000000"), + S1 ("9C21", "0430", "1F000000"), + S1 ("A021", "0430", "08000000"), + S1 ("C021", "0430", "00000000"), + S1 ("C421", "0430", "01000000"), + S1 ("C821", "0430", "01000000"), + S1 ("CC21", "0430", "01000000"), + S1 ("D021", "0430", "01000000"), + S1 ("D421", "0430", "01000000"), + S1 ("D821", "0430", "01000000"), + S1 ("DC21", "0430", "1F000000"), + S1 ("E021", "0430", "08000000"), + S1 ("A020", "0430", "EFE10000"), + S1 ("A420", "0430", "00000000"), + vfs301_02D0_BLOB1, + vfs301_02D0_ALIGNED_BLOB, - PACKET("0C00", "0100", "01"), - PACKET("0D00", "2800", "2021043000000000010000000F00000000FFFFFF0100000020210430000000000000003001000000"), - PACKET("0E00", "1000", "00000000000000000000000000000001"), - PACKET("0F00", "0100", "01"), - PACKET("1000", "0100", "02"), - PACKET("1100", "0200", "2000"), - vfs301_02D0_BLOB4, - S1("C820", "0430", "07000000"), - S2("1420FFFF00FF0000000000008800"), - S1("8421", "0430", "01000000"), - S1("8821", "0430", "01000000"), - S1("8C21", "0430", "01000000"), - S1("9021", "0430", "01000000"), - S1("9421", "0430", "01000000"), - S1("9821", "0430", "01000000"), - S1("A021", "0430", "00000000"), + PACKET ("0C00", "0100", "01"), + PACKET ("0D00", "2800", "2021043000000000010000000F00000000FFFFFF0100000020210430000000000000003001000000"), + PACKET ("0E00", "1000", "00000000000000000000000000000001"), + PACKET ("0F00", "0100", "01"), + PACKET ("1000", "0100", "02"), + PACKET ("1100", "0200", "2000"), + vfs301_02D0_BLOB4, + S1 ("C820", "0430", "07000000"), + S2 ("1420FFFF00FF0000000000008800"), + S1 ("8421", "0430", "01000000"), + S1 ("8821", "0430", "01000000"), + S1 ("8C21", "0430", "01000000"), + S1 ("9021", "0430", "01000000"), + S1 ("9421", "0430", "01000000"), + S1 ("9821", "0430", "01000000"), + S1 ("A021", "0430", "00000000"), - TERM(), + TERM (), - NULL + NULL }; const char *vfs301_02D0_07[] = { - "02D0000400" - S3("1003181C"), - PACKET("0C00", "0100", "04"), - PACKET("0D00", "2800", "28A0003803000000020000003B000000C0FFFFFF0100000028A00038000000001047004801000000"), - PACKET("1100", "0200", "0400"), - PACKET("1300", "0400", "18000000"), - PACKET("1400", "0400", "1E000000"), + "02D0000400" + S3 ("1003181C"), + PACKET ("0C00", "0100", "04"), + PACKET ("0D00", "2800", "28A0003803000000020000003B000000C0FFFFFF0100000028A00038000000001047004801000000"), + PACKET ("1100", "0200", "0400"), + PACKET ("1300", "0400", "18000000"), + PACKET ("1400", "0400", "1E000000"), - S1("A020", "0430", "EFE10000"), - S1("08A0", "0038", "78000200"), - S1("10A0", "0038", "E3186800"), - S1("14A0", "0038", "E3186800"), - S1("18A0", "0038", "E3186800"), - S1("1CA0", "0038", "E3186800"), - S1("20A0", "0038", "E3186800"), - S1("24A0", "0038", "0CFA8000"), - S1("28A0", "0038", "00000800"), - S1("04A0", "0038", "FFFFFFFF"), + S1 ("A020", "0430", "EFE10000"), + S1 ("08A0", "0038", "78000200"), + S1 ("10A0", "0038", "E3186800"), + S1 ("14A0", "0038", "E3186800"), + S1 ("18A0", "0038", "E3186800"), + S1 ("1CA0", "0038", "E3186800"), + S1 ("20A0", "0038", "E3186800"), + S1 ("24A0", "0038", "0CFA8000"), + S1 ("28A0", "0038", "00000800"), + S1 ("04A0", "0038", "FFFFFFFF"), - vfs301_0220_BLOB2, + vfs301_0220_BLOB2, - TERM(), + TERM (), - NULL + NULL }; diff --git a/libfprint/drivers/vfs5011.c b/libfprint/drivers/vfs5011.c index cb1147b0..301a1d64 100644 --- a/libfprint/drivers/vfs5011.c +++ b/libfprint/drivers/vfs5011.c @@ -26,406 +26,447 @@ /* =================== sync/async USB transfer sequence ==================== */ enum { - ACTION_SEND, - ACTION_RECEIVE, + ACTION_SEND, + ACTION_RECEIVE, }; -struct usb_action { - int type; - const char *name; - int endpoint; - int size; - unsigned char *data; - int correct_reply_size; +struct usb_action +{ + int type; + const char *name; + int endpoint; + int size; + unsigned char *data; + int correct_reply_size; }; #define SEND(ENDPOINT, COMMAND) \ -{ \ - .type = ACTION_SEND, \ - .endpoint = ENDPOINT, \ - .name = #COMMAND, \ - .size = sizeof(COMMAND), \ - .data = COMMAND \ -}, + { \ + .type = ACTION_SEND, \ + .endpoint = ENDPOINT, \ + .name = #COMMAND, \ + .size = sizeof (COMMAND), \ + .data = COMMAND \ + }, #define RECV(ENDPOINT, SIZE) \ -{ \ - .type = ACTION_RECEIVE, \ - .endpoint = ENDPOINT, \ - .size = SIZE, \ - .data = NULL \ -}, + { \ + .type = ACTION_RECEIVE, \ + .endpoint = ENDPOINT, \ + .size = SIZE, \ + .data = NULL \ + }, #define RECV_CHECK(ENDPOINT, SIZE, EXPECTED) \ -{ \ - .type = ACTION_RECEIVE, \ - .endpoint = ENDPOINT, \ - .size = SIZE, \ - .data = EXPECTED, \ - .correct_reply_size = sizeof(EXPECTED) \ -}, + { \ + .type = ACTION_RECEIVE, \ + .endpoint = ENDPOINT, \ + .size = SIZE, \ + .data = EXPECTED, \ + .correct_reply_size = sizeof (EXPECTED) \ + }, -struct usbexchange_data { - int stepcount; - FpImageDevice *device; - struct usb_action *actions; - void *receive_buf; - int timeout; +struct usbexchange_data +{ + int stepcount; + FpImageDevice *device; + struct usb_action *actions; + void *receive_buf; + int timeout; }; -static void start_scan(FpImageDevice *dev); +static void start_scan (FpImageDevice *dev); -static void async_send_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +async_send_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - struct usbexchange_data *data = fpi_ssm_get_user_data(transfer->ssm); - struct usb_action *action; + struct usbexchange_data *data = fpi_ssm_get_user_data (transfer->ssm); + struct usb_action *action; - g_assert(!(fpi_ssm_get_cur_state(transfer->ssm) >= data->stepcount)); + g_assert (!(fpi_ssm_get_cur_state (transfer->ssm) >= data->stepcount)); - action = &data->actions[fpi_ssm_get_cur_state(transfer->ssm)]; - g_assert(!(action->type != ACTION_SEND)); + action = &data->actions[fpi_ssm_get_cur_state (transfer->ssm)]; + g_assert (!(action->type != ACTION_SEND)); - if (error) { - /* Transfer not completed, return IO error */ - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } + if (error) + { + /* Transfer not completed, return IO error */ + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } - /* success */ - fpi_ssm_next_state(transfer->ssm); + /* success */ + fpi_ssm_next_state (transfer->ssm); } -static void async_recv_cb(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +async_recv_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - struct usbexchange_data *data = fpi_ssm_get_user_data(transfer->ssm); - struct usb_action *action; + struct usbexchange_data *data = fpi_ssm_get_user_data (transfer->ssm); + struct usb_action *action; - if (error) { - /* Transfer not completed, return IO error */ - fpi_ssm_mark_failed(transfer->ssm, error); - return; - } + if (error) + { + /* Transfer not completed, return IO error */ + fpi_ssm_mark_failed (transfer->ssm, error); + return; + } - g_assert(!(fpi_ssm_get_cur_state(transfer->ssm) >= data->stepcount)); + g_assert (!(fpi_ssm_get_cur_state (transfer->ssm) >= data->stepcount)); - action = &data->actions[fpi_ssm_get_cur_state(transfer->ssm)]; - g_assert(!(action->type != ACTION_RECEIVE)); + action = &data->actions[fpi_ssm_get_cur_state (transfer->ssm)]; + g_assert (!(action->type != ACTION_RECEIVE)); - if (action->data != NULL) { - if (transfer->actual_length != action->correct_reply_size) { - fp_err("Got %d bytes instead of %d", - (gint)transfer->actual_length, - action->correct_reply_size); - fpi_ssm_mark_failed(transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); - return; - } - if (memcmp(transfer->buffer, action->data, - action->correct_reply_size) != 0) { - fp_dbg("Wrong reply:"); - fpi_ssm_mark_failed(transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); - return; - } - } else - fp_dbg("Got %d bytes out of %d", - (gint)transfer->actual_length, - (gint)transfer->length); + if (action->data != NULL) + { + if (transfer->actual_length != action->correct_reply_size) + { + fp_err ("Got %d bytes instead of %d", + (gint) transfer->actual_length, + action->correct_reply_size); + fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + return; + } + if (memcmp (transfer->buffer, action->data, + action->correct_reply_size) != 0) + { + fp_dbg ("Wrong reply:"); + fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + return; + } + } + else + { + fp_dbg ("Got %d bytes out of %d", + (gint) transfer->actual_length, + (gint) transfer->length); + } - fpi_ssm_next_state(transfer->ssm); + fpi_ssm_next_state (transfer->ssm); } -static void usbexchange_loop(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +usbexchange_loop (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - struct usbexchange_data *data = user_data; - struct usb_action *action = &data->actions[fpi_ssm_get_cur_state(ssm)]; - FpiUsbTransfer *transfer; + struct usbexchange_data *data = user_data; + struct usb_action *action = &data->actions[fpi_ssm_get_cur_state (ssm)]; + FpiUsbTransfer *transfer; - g_assert (fpi_ssm_get_cur_state(ssm) < data->stepcount); + g_assert (fpi_ssm_get_cur_state (ssm) < data->stepcount); - switch (action->type) { - case ACTION_SEND: - fp_dbg("Sending %s", action->name); - transfer = fpi_usb_transfer_new(_dev); - fpi_usb_transfer_fill_bulk_full(transfer, action->endpoint, - action->data, action->size, - NULL); - transfer->ssm = ssm; - transfer->short_is_error = TRUE; - fpi_usb_transfer_submit(transfer, data->timeout, NULL, - async_send_cb, NULL); - fpi_usb_transfer_unref(transfer); - break; + switch (action->type) + { + case ACTION_SEND: + fp_dbg ("Sending %s", action->name); + transfer = fpi_usb_transfer_new (_dev); + fpi_usb_transfer_fill_bulk_full (transfer, action->endpoint, + action->data, action->size, + NULL); + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, data->timeout, NULL, + async_send_cb, NULL); + fpi_usb_transfer_unref (transfer); + break; - case ACTION_RECEIVE: - fp_dbg("Receiving %d bytes", action->size); - transfer = fpi_usb_transfer_new(_dev); - fpi_usb_transfer_fill_bulk_full(transfer, action->endpoint, - data->receive_buf, - action->size, NULL); - transfer->ssm = ssm; - fpi_usb_transfer_submit(transfer, data->timeout, NULL, - async_recv_cb, NULL); - fpi_usb_transfer_unref(transfer); - break; + case ACTION_RECEIVE: + fp_dbg ("Receiving %d bytes", action->size); + transfer = fpi_usb_transfer_new (_dev); + fpi_usb_transfer_fill_bulk_full (transfer, action->endpoint, + data->receive_buf, + action->size, NULL); + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, data->timeout, NULL, + async_recv_cb, NULL); + fpi_usb_transfer_unref (transfer); + break; - default: - fp_err("Bug detected: invalid action %d", action->type); - fpi_ssm_mark_failed(ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); - return; - } + default: + fp_err ("Bug detected: invalid action %d", action->type); + fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + return; + } } -static void usb_exchange_async(FpiSsm *ssm, - struct usbexchange_data *data) +static void +usb_exchange_async (FpiSsm *ssm, + struct usbexchange_data *data) { - FpiSsm *subsm = fpi_ssm_new(FP_DEVICE(data->device), - usbexchange_loop, - data->stepcount, - data); - fpi_ssm_start_subsm(ssm, subsm); + FpiSsm *subsm = fpi_ssm_new (FP_DEVICE (data->device), + usbexchange_loop, + data->stepcount, + data); + + fpi_ssm_start_subsm (ssm, subsm); } /* ====================== utils ======================= */ /* Calculade squared standand deviation of sum of two lines */ -static int vfs5011_get_deviation2(struct fpi_line_asmbl_ctx *ctx, GSList *row1, GSList *row2) +static int +vfs5011_get_deviation2 (struct fpi_line_asmbl_ctx *ctx, GSList *row1, GSList *row2) { - unsigned char *buf1, *buf2; - int res = 0, mean = 0, i; - const int size = 64; + unsigned char *buf1, *buf2; + int res = 0, mean = 0, i; + const int size = 64; - buf1 = row1->data + 56; - buf2 = row2->data + 168; + buf1 = row1->data + 56; + buf2 = row2->data + 168; - for (i = 0; i < size; i++) - mean += (int)buf1[i] + (int)buf2[i]; + for (i = 0; i < size; i++) + mean += (int) buf1[i] + (int) buf2[i]; - mean /= size; + mean /= size; - for (i = 0; i < size; i++) { - int dev = (int)buf1[i] + (int)buf2[i] - mean; - res += dev*dev; - } + for (i = 0; i < size; i++) + { + int dev = (int) buf1[i] + (int) buf2[i] - mean; + res += dev * dev; + } - return res / size; + return res / size; } -static unsigned char vfs5011_get_pixel(struct fpi_line_asmbl_ctx *ctx, - GSList *row, - unsigned x) +static unsigned char +vfs5011_get_pixel (struct fpi_line_asmbl_ctx *ctx, + GSList *row, + unsigned x) { - unsigned char *data = row->data + 8; + unsigned char *data = row->data + 8; - return data[x]; + return data[x]; } /* ====================== main stuff ======================= */ enum { - CAPTURE_LINES = 256, - MAXLINES = 2000, - MAX_CAPTURE_LINES = 100000, + CAPTURE_LINES = 256, + MAXLINES = 2000, + MAX_CAPTURE_LINES = 100000, }; static struct fpi_line_asmbl_ctx assembling_ctx = { - .line_width = VFS5011_IMAGE_WIDTH, - .max_height = MAXLINES, - .resolution = 10, - .median_filter_size = 25, - .max_search_offset = 30, - .get_deviation = vfs5011_get_deviation2, - .get_pixel = vfs5011_get_pixel, + .line_width = VFS5011_IMAGE_WIDTH, + .max_height = MAXLINES, + .resolution = 10, + .median_filter_size = 25, + .max_search_offset = 30, + .get_deviation = vfs5011_get_deviation2, + .get_pixel = vfs5011_get_pixel, }; -struct _FpDeviceVfs5011 { - FpImageDevice parent; - - unsigned char *total_buffer; - unsigned char *capture_buffer; - unsigned char *row_buffer; - unsigned char *lastline; - GSList *rows; - int lines_captured, lines_recorded, empty_lines; - int max_lines_captured, max_lines_recorded; - int lines_total, lines_total_allocated; - gboolean loop_running; - gboolean deactivating; - struct usbexchange_data init_sequence; -}; - -G_DECLARE_FINAL_TYPE(FpDeviceVfs5011, fpi_device_vfs5011, FPI, DEVICE_VFS5011, - FpImageDevice); -G_DEFINE_TYPE(FpDeviceVfs5011, fpi_device_vfs5011, FP_TYPE_IMAGE_DEVICE); - -enum { - DEV_ACTIVATE_REQUEST_FPRINT, - DEV_ACTIVATE_INIT_COMPLETE, - DEV_ACTIVATE_READ_DATA, - DEV_ACTIVATE_DATA_COMPLETE, - DEV_ACTIVATE_PREPARE_NEXT_CAPTURE, - DEV_ACTIVATE_NUM_STATES -}; - -enum { - DEV_OPEN_START, - DEV_OPEN_NUM_STATES -}; - -static void capture_init(FpDeviceVfs5011 *self, int max_captured, - int max_recorded) +struct _FpDeviceVfs5011 { - fp_dbg("capture_init"); - self->lastline = NULL; - self->lines_captured = 0; - self->lines_recorded = 0; - self->empty_lines = 0; - self->lines_total = 0; - self->lines_total_allocated = 0; - self->total_buffer = NULL; - self->max_lines_captured = max_captured; - self->max_lines_recorded = max_recorded; + FpImageDevice parent; + + unsigned char *total_buffer; + unsigned char *capture_buffer; + unsigned char *row_buffer; + unsigned char *lastline; + GSList *rows; + int lines_captured, lines_recorded, empty_lines; + int max_lines_captured, max_lines_recorded; + int lines_total, lines_total_allocated; + gboolean loop_running; + gboolean deactivating; + struct usbexchange_data init_sequence; +}; + +G_DECLARE_FINAL_TYPE (FpDeviceVfs5011, fpi_device_vfs5011, FPI, DEVICE_VFS5011, + FpImageDevice); +G_DEFINE_TYPE (FpDeviceVfs5011, fpi_device_vfs5011, FP_TYPE_IMAGE_DEVICE); + +enum { + DEV_ACTIVATE_REQUEST_FPRINT, + DEV_ACTIVATE_INIT_COMPLETE, + DEV_ACTIVATE_READ_DATA, + DEV_ACTIVATE_DATA_COMPLETE, + DEV_ACTIVATE_PREPARE_NEXT_CAPTURE, + DEV_ACTIVATE_NUM_STATES +}; + +enum { + DEV_OPEN_START, + DEV_OPEN_NUM_STATES +}; + +static void +capture_init (FpDeviceVfs5011 *self, int max_captured, + int max_recorded) +{ + fp_dbg ("capture_init"); + self->lastline = NULL; + self->lines_captured = 0; + self->lines_recorded = 0; + self->empty_lines = 0; + self->lines_total = 0; + self->lines_total_allocated = 0; + self->total_buffer = NULL; + self->max_lines_captured = max_captured; + self->max_lines_recorded = max_recorded; } -static int process_chunk(FpDeviceVfs5011 *self, int transferred) +static int +process_chunk (FpDeviceVfs5011 *self, int transferred) { - enum { - DEVIATION_THRESHOLD = 15*15, - DIFFERENCE_THRESHOLD = 600, - STOP_CHECK_LINES = 50 - }; + enum { + DEVIATION_THRESHOLD = 15 * 15, + DIFFERENCE_THRESHOLD = 600, + STOP_CHECK_LINES = 50 + }; - fp_dbg("process_chunk: got %d bytes", transferred); - int lines_captured = transferred/VFS5011_LINE_SIZE; - int i; + fp_dbg ("process_chunk: got %d bytes", transferred); + int lines_captured = transferred / VFS5011_LINE_SIZE; + int i; - for (i = 0; i < lines_captured; i++) { - unsigned char *linebuf = self->capture_buffer - + i * VFS5011_LINE_SIZE; + for (i = 0; i < lines_captured; i++) + { + unsigned char *linebuf = self->capture_buffer + + i * VFS5011_LINE_SIZE; - if (fpi_std_sq_dev(linebuf + 8, VFS5011_IMAGE_WIDTH) - < DEVIATION_THRESHOLD) { - if (self->lines_captured == 0) - continue; - else - self->empty_lines++; - } else - self->empty_lines = 0; - if (self->empty_lines >= STOP_CHECK_LINES) { - fp_dbg("process_chunk: got %d empty lines, finishing", - self->empty_lines); - return 1; - } + if (fpi_std_sq_dev (linebuf + 8, VFS5011_IMAGE_WIDTH) + < DEVIATION_THRESHOLD) + { + if (self->lines_captured == 0) + continue; + else + self->empty_lines++; + } + else + { + self->empty_lines = 0; + } + if (self->empty_lines >= STOP_CHECK_LINES) + { + fp_dbg ("process_chunk: got %d empty lines, finishing", + self->empty_lines); + return 1; + } - self->lines_captured++; - if (self->lines_captured > self->max_lines_captured) { - fp_dbg("process_chunk: captured %d lines, finishing", - self->lines_captured); - return 1; - } + self->lines_captured++; + if (self->lines_captured > self->max_lines_captured) + { + fp_dbg ("process_chunk: captured %d lines, finishing", + self->lines_captured); + return 1; + } - if ((self->lastline == NULL) - || (fpi_mean_sq_diff_norm(self->lastline + 8, - linebuf + 8, - VFS5011_IMAGE_WIDTH) >= DIFFERENCE_THRESHOLD)) { - self->lastline = g_malloc(VFS5011_LINE_SIZE); - self->rows = g_slist_prepend(self->rows, - self->lastline); - memmove(self->lastline, linebuf, VFS5011_LINE_SIZE); - self->lines_recorded++; - if (self->lines_recorded >= self->max_lines_recorded) { - fp_dbg("process_chunk: recorded %d lines, finishing", - self->lines_recorded); - return 1; - } - } - } - return 0; + if ((self->lastline == NULL) || + (fpi_mean_sq_diff_norm (self->lastline + 8, + linebuf + 8, + VFS5011_IMAGE_WIDTH) >= DIFFERENCE_THRESHOLD)) + { + self->lastline = g_malloc (VFS5011_LINE_SIZE); + self->rows = g_slist_prepend (self->rows, + self->lastline); + memmove (self->lastline, linebuf, VFS5011_LINE_SIZE); + self->lines_recorded++; + if (self->lines_recorded >= self->max_lines_recorded) + { + fp_dbg ("process_chunk: recorded %d lines, finishing", + self->lines_recorded); + return 1; + } + } + } + return 0; } static void -submit_image(FpiSsm *ssm, - FpDeviceVfs5011 *self, - FpImageDevice *dev) +submit_image (FpiSsm *ssm, + FpDeviceVfs5011 *self, + FpImageDevice *dev) { - FpImage *img; + FpImage *img; - if (self->lines_recorded == 0) { - /* == FP_ENROLL_RETRY_TOO_SHORT */ - fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT); - return; - } + if (self->lines_recorded == 0) + { + /* == FP_ENROLL_RETRY_TOO_SHORT */ + fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT); + return; + } - g_assert (self->rows != NULL); + g_assert (self->rows != NULL); - self->rows = g_slist_reverse(self->rows); + self->rows = g_slist_reverse (self->rows); - img = fpi_assemble_lines(&assembling_ctx, self->rows, - self->lines_recorded); + img = fpi_assemble_lines (&assembling_ctx, self->rows, + self->lines_recorded); - g_slist_free_full(self->rows, g_free); - self->rows = NULL; + g_slist_free_full (self->rows, g_free); + self->rows = NULL; - fp_dbg("Image captured, committing"); + fp_dbg ("Image captured, committing"); - fpi_image_device_image_captured(dev, img); + fpi_image_device_image_captured (dev, img); } -static void chunk_capture_callback(FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) +static void +chunk_capture_callback (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) { - FpImageDevice *dev = FP_IMAGE_DEVICE(device); - FpDeviceVfs5011 *self; + FpImageDevice *dev = FP_IMAGE_DEVICE (device); + FpDeviceVfs5011 *self; - self = FPI_DEVICE_VFS5011(dev); + self = FPI_DEVICE_VFS5011 (dev); - if (!error || - g_error_matches(error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT)) { - if (error) - g_error_free(error); + if (!error || + g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT)) + { + if (error) + g_error_free (error); - if (transfer->actual_length > 0) - fpi_image_device_report_finger_status(dev, TRUE); + if (transfer->actual_length > 0) + fpi_image_device_report_finger_status (dev, TRUE); - if (process_chunk(self, transfer->actual_length)) - fpi_ssm_jump_to_state(transfer->ssm, - DEV_ACTIVATE_DATA_COMPLETE); - else - fpi_ssm_jump_to_state(transfer->ssm, - DEV_ACTIVATE_READ_DATA); - } else { - if (!self->deactivating) { - fp_err("Failed to capture data"); - fpi_ssm_mark_failed(transfer->ssm, error); - } else { - g_error_free (error); - fpi_ssm_mark_completed(transfer->ssm); - } - } + if (process_chunk (self, transfer->actual_length)) + fpi_ssm_jump_to_state (transfer->ssm, + DEV_ACTIVATE_DATA_COMPLETE); + else + fpi_ssm_jump_to_state (transfer->ssm, + DEV_ACTIVATE_READ_DATA); + } + else + { + if (!self->deactivating) + { + fp_err ("Failed to capture data"); + fpi_ssm_mark_failed (transfer->ssm, error); + } + else + { + g_error_free (error); + fpi_ssm_mark_completed (transfer->ssm); + } + } } -static void capture_chunk_async(FpDeviceVfs5011 *self, - GUsbDevice *handle, int nline, - int timeout, FpiSsm *ssm) +static void +capture_chunk_async (FpDeviceVfs5011 *self, + GUsbDevice *handle, int nline, + int timeout, FpiSsm *ssm) { - FpiUsbTransfer *transfer; - fp_dbg("capture_chunk_async: capture %d lines, already have %d", - nline, self->lines_recorded); - enum { - DEVIATION_THRESHOLD = 15*15, - DIFFERENCE_THRESHOLD = 600, - STOP_CHECK_LINES = 50 - }; + FpiUsbTransfer *transfer; - transfer = fpi_usb_transfer_new(FP_DEVICE(self)); - fpi_usb_transfer_fill_bulk_full(transfer, - VFS5011_IN_ENDPOINT_DATA, - self->capture_buffer, - nline * VFS5011_LINE_SIZE, NULL); - transfer->ssm = ssm; - fpi_usb_transfer_submit(transfer, timeout, fpi_device_get_cancellable (FP_DEVICE (self)), - chunk_capture_callback, NULL); - fpi_usb_transfer_unref(transfer); + fp_dbg ("capture_chunk_async: capture %d lines, already have %d", + nline, self->lines_recorded); + enum { + DEVIATION_THRESHOLD = 15 * 15, + DIFFERENCE_THRESHOLD = 600, + STOP_CHECK_LINES = 50 + }; + + transfer = fpi_usb_transfer_new (FP_DEVICE (self)); + fpi_usb_transfer_fill_bulk_full (transfer, + VFS5011_IN_ENDPOINT_DATA, + self->capture_buffer, + nline * VFS5011_LINE_SIZE, NULL); + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, timeout, fpi_device_get_cancellable (FP_DEVICE (self)), + chunk_capture_callback, NULL); + fpi_usb_transfer_unref (transfer); } /* @@ -434,425 +475,439 @@ static void capture_chunk_async(FpDeviceVfs5011 *self, * image. */ struct usb_action vfs5011_initialization[] = { - SEND(VFS5011_OUT_ENDPOINT, vfs5011_cmd_01) - RECV(VFS5011_IN_ENDPOINT_CTRL, 64) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_01) + RECV (VFS5011_IN_ENDPOINT_CTRL, 64) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_cmd_19) - RECV(VFS5011_IN_ENDPOINT_CTRL, 64) - RECV(VFS5011_IN_ENDPOINT_CTRL, 64) /* B5C457F9 */ + SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_19) + RECV (VFS5011_IN_ENDPOINT_CTRL, 64) + RECV (VFS5011_IN_ENDPOINT_CTRL, 64) /* B5C457F9 */ - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_00) - RECV(VFS5011_IN_ENDPOINT_CTRL, 64) /* 0000FFFFFFFF */ + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_00) + RECV (VFS5011_IN_ENDPOINT_CTRL, 64) /* 0000FFFFFFFF */ - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_01) - RECV(VFS5011_IN_ENDPOINT_CTRL, 64) /* 0000FFFFFFFFFF */ + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_01) + RECV (VFS5011_IN_ENDPOINT_CTRL, 64) /* 0000FFFFFFFFFF */ - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_02) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_02) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_cmd_01) - RECV(VFS5011_IN_ENDPOINT_CTRL, 64) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_01) + RECV (VFS5011_IN_ENDPOINT_CTRL, 64) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_03) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_03) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_04) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - RECV(VFS5011_IN_ENDPOINT_DATA, 256) - RECV(VFS5011_IN_ENDPOINT_DATA, 64) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_04) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + RECV (VFS5011_IN_ENDPOINT_DATA, 256) + RECV (VFS5011_IN_ENDPOINT_DATA, 64) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_05) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_05) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_cmd_01) - RECV(VFS5011_IN_ENDPOINT_CTRL, 64) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_01) + RECV (VFS5011_IN_ENDPOINT_CTRL, 64) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_06) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - RECV(VFS5011_IN_ENDPOINT_DATA, 17216) - RECV(VFS5011_IN_ENDPOINT_DATA, 32) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_06) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + RECV (VFS5011_IN_ENDPOINT_DATA, 17216) + RECV (VFS5011_IN_ENDPOINT_DATA, 32) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_07) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - RECV(VFS5011_IN_ENDPOINT_DATA, 45056) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_07) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + RECV (VFS5011_IN_ENDPOINT_DATA, 45056) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_08) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - RECV(VFS5011_IN_ENDPOINT_DATA, 16896) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_08) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + RECV (VFS5011_IN_ENDPOINT_DATA, 16896) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_09) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - RECV(VFS5011_IN_ENDPOINT_DATA, 4928) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_09) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + RECV (VFS5011_IN_ENDPOINT_DATA, 4928) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_10) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - RECV(VFS5011_IN_ENDPOINT_DATA, 5632) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_10) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + RECV (VFS5011_IN_ENDPOINT_DATA, 5632) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_11) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - RECV(VFS5011_IN_ENDPOINT_DATA, 5632) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_11) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + RECV (VFS5011_IN_ENDPOINT_DATA, 5632) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_12) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - RECV(VFS5011_IN_ENDPOINT_DATA, 3328) - RECV(VFS5011_IN_ENDPOINT_DATA, 64) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_12) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + RECV (VFS5011_IN_ENDPOINT_DATA, 3328) + RECV (VFS5011_IN_ENDPOINT_DATA, 64) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_13) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_13) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_03) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_03) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_14) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - RECV(VFS5011_IN_ENDPOINT_DATA, 4800) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_14) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + RECV (VFS5011_IN_ENDPOINT_DATA, 4800) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_02) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_02) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_cmd_27) - RECV(VFS5011_IN_ENDPOINT_CTRL, 64) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_27) + RECV (VFS5011_IN_ENDPOINT_CTRL, 64) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_15) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_15) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_16) - RECV(VFS5011_IN_ENDPOINT_CTRL, 2368) - RECV(VFS5011_IN_ENDPOINT_CTRL, 64) - RECV(VFS5011_IN_ENDPOINT_DATA, 4800) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_16) + RECV (VFS5011_IN_ENDPOINT_CTRL, 2368) + RECV (VFS5011_IN_ENDPOINT_CTRL, 64) + RECV (VFS5011_IN_ENDPOINT_DATA, 4800) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_17) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_17) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_init_18) - /* 0000 */ - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_18) + /* 0000 */ + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - /* - * Windows driver does this and it works - * But in this driver this call never returns... - * RECV(VFS5011_IN_ENDPOINT_CTRL2, 8) //00D3054000 - */ + /* + * Windows driver does this and it works + * But in this driver this call never returns... + * RECV(VFS5011_IN_ENDPOINT_CTRL2, 8) //00D3054000 + */ }; /* Initiate recording the image */ struct usb_action vfs5011_initiate_capture[] = { - SEND(VFS5011_OUT_ENDPOINT, vfs5011_cmd_04) - RECV(VFS5011_IN_ENDPOINT_DATA, 64) - RECV(VFS5011_IN_ENDPOINT_DATA, 84032) - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_04) + RECV (VFS5011_IN_ENDPOINT_DATA, 64) + RECV (VFS5011_IN_ENDPOINT_DATA, 84032) + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A) - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A) + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_prepare_00) - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_prepare_00) + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A) - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A) + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_prepare_01) - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_prepare_01) + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_prepare_02) - RECV(VFS5011_IN_ENDPOINT_CTRL, 2368) - RECV(VFS5011_IN_ENDPOINT_CTRL, 64) - RECV(VFS5011_IN_ENDPOINT_DATA, 4800) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_prepare_02) + RECV (VFS5011_IN_ENDPOINT_CTRL, 2368) + RECV (VFS5011_IN_ENDPOINT_CTRL, 64) + RECV (VFS5011_IN_ENDPOINT_DATA, 4800) - SEND(VFS5011_OUT_ENDPOINT, vfs5011_prepare_03) - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) - /* - * Windows driver does this and it works - * But in this driver this call never returns... - * RECV(VFS5011_IN_ENDPOINT_CTRL2, 8); - */ + SEND (VFS5011_OUT_ENDPOINT, vfs5011_prepare_03) + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY) + /* + * Windows driver does this and it works + * But in this driver this call never returns... + * RECV(VFS5011_IN_ENDPOINT_CTRL2, 8); + */ - SEND(VFS5011_OUT_ENDPOINT, vfs5011_prepare_04) - RECV_CHECK(VFS5011_IN_ENDPOINT_CTRL, 2368, VFS5011_NORMAL_CONTROL_REPLY) + SEND (VFS5011_OUT_ENDPOINT, vfs5011_prepare_04) + RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 2368, VFS5011_NORMAL_CONTROL_REPLY) - /* - * Windows driver does this and it works - * But in this driver this call never returns... - * RECV(VFS5011_IN_ENDPOINT_CTRL2, 8); - */ + /* + * Windows driver does this and it works + * But in this driver this call never returns... + * RECV(VFS5011_IN_ENDPOINT_CTRL2, 8); + */ }; /* ====================== lifprint interface ======================= */ -static void activate_loop(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +activate_loop (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - enum {READ_TIMEOUT = 0}; + enum {READ_TIMEOUT = 0}; - FpImageDevice *dev = user_data; - FpDeviceVfs5011 *self; + FpImageDevice *dev = user_data; + FpDeviceVfs5011 *self; - self = FPI_DEVICE_VFS5011(_dev); + self = FPI_DEVICE_VFS5011 (_dev); - fp_dbg("main_loop: state %d", fpi_ssm_get_cur_state(ssm)); + fp_dbg ("main_loop: state %d", fpi_ssm_get_cur_state (ssm)); - if (self->deactivating) { - fp_dbg("deactivating, marking completed"); - fpi_ssm_mark_completed(ssm); - return; - } + if (self->deactivating) + { + fp_dbg ("deactivating, marking completed"); + fpi_ssm_mark_completed (ssm); + return; + } - switch (fpi_ssm_get_cur_state(ssm)) { - case DEV_ACTIVATE_REQUEST_FPRINT: - self->init_sequence.stepcount = - G_N_ELEMENTS(vfs5011_initiate_capture); - self->init_sequence.actions = vfs5011_initiate_capture; - self->init_sequence.device = dev; - if (self->init_sequence.receive_buf == NULL) - self->init_sequence.receive_buf = - g_malloc0(VFS5011_RECEIVE_BUF_SIZE); - self->init_sequence.timeout = 1000; - usb_exchange_async(ssm, &self->init_sequence); - break; + switch (fpi_ssm_get_cur_state (ssm)) + { + case DEV_ACTIVATE_REQUEST_FPRINT: + self->init_sequence.stepcount = + G_N_ELEMENTS (vfs5011_initiate_capture); + self->init_sequence.actions = vfs5011_initiate_capture; + self->init_sequence.device = dev; + if (self->init_sequence.receive_buf == NULL) + self->init_sequence.receive_buf = + g_malloc0 (VFS5011_RECEIVE_BUF_SIZE); + self->init_sequence.timeout = 1000; + usb_exchange_async (ssm, &self->init_sequence); + break; - case DEV_ACTIVATE_INIT_COMPLETE: - if (self->init_sequence.receive_buf != NULL) - g_free(self->init_sequence.receive_buf); - self->init_sequence.receive_buf = NULL; - capture_init(self, MAX_CAPTURE_LINES, MAXLINES); - fpi_image_device_activate_complete(dev, NULL); - fpi_ssm_next_state(ssm); - break; + case DEV_ACTIVATE_INIT_COMPLETE: + if (self->init_sequence.receive_buf != NULL) + g_free (self->init_sequence.receive_buf); + self->init_sequence.receive_buf = NULL; + capture_init (self, MAX_CAPTURE_LINES, MAXLINES); + fpi_image_device_activate_complete (dev, NULL); + fpi_ssm_next_state (ssm); + break; - case DEV_ACTIVATE_READ_DATA: - capture_chunk_async(self, - fpi_device_get_usb_device(FP_DEVICE(dev)), - CAPTURE_LINES, - READ_TIMEOUT, ssm); - break; + case DEV_ACTIVATE_READ_DATA: + capture_chunk_async (self, + fpi_device_get_usb_device (FP_DEVICE (dev)), + CAPTURE_LINES, + READ_TIMEOUT, ssm); + break; - case DEV_ACTIVATE_DATA_COMPLETE: - fpi_device_add_timeout(_dev, 1, - fpi_ssm_next_state_timeout_cb, - ssm); + case DEV_ACTIVATE_DATA_COMPLETE: + fpi_device_add_timeout (_dev, 1, + fpi_ssm_next_state_timeout_cb, + ssm); - break; + break; - case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE: - self->init_sequence.stepcount = - G_N_ELEMENTS(vfs5011_initiate_capture); - self->init_sequence.actions = vfs5011_initiate_capture; - self->init_sequence.device = dev; - if (self->init_sequence.receive_buf == NULL) - self->init_sequence.receive_buf = - g_malloc0(VFS5011_RECEIVE_BUF_SIZE); - self->init_sequence.timeout = VFS5011_DEFAULT_WAIT_TIMEOUT; - usb_exchange_async(ssm, &self->init_sequence); - break; + case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE: + self->init_sequence.stepcount = + G_N_ELEMENTS (vfs5011_initiate_capture); + self->init_sequence.actions = vfs5011_initiate_capture; + self->init_sequence.device = dev; + if (self->init_sequence.receive_buf == NULL) + self->init_sequence.receive_buf = + g_malloc0 (VFS5011_RECEIVE_BUF_SIZE); + self->init_sequence.timeout = VFS5011_DEFAULT_WAIT_TIMEOUT; + usb_exchange_async (ssm, &self->init_sequence); + break; - } + } } -static void activate_loop_complete(FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +static void +activate_loop_complete (FpiSsm *ssm, FpDevice *_dev, + void *user_data, GError *error) { - FpImageDevice *dev = user_data; - FpDeviceVfs5011 *self; + FpImageDevice *dev = user_data; + FpDeviceVfs5011 *self; - self = FPI_DEVICE_VFS5011(_dev); + self = FPI_DEVICE_VFS5011 (_dev); - fp_dbg("finishing"); - if (self->init_sequence.receive_buf != NULL) - g_free(self->init_sequence.receive_buf); - self->init_sequence.receive_buf = NULL; - if (!self->deactivating && !error) { - submit_image(ssm, self, dev); - fpi_image_device_report_finger_status(dev, FALSE); - } - fpi_ssm_free(ssm); + fp_dbg ("finishing"); + if (self->init_sequence.receive_buf != NULL) + g_free (self->init_sequence.receive_buf); + self->init_sequence.receive_buf = NULL; + if (!self->deactivating && !error) + { + submit_image (ssm, self, dev); + fpi_image_device_report_finger_status (dev, FALSE); + } + fpi_ssm_free (ssm); - self->loop_running = FALSE; + self->loop_running = FALSE; - if (self->deactivating) { - fpi_image_device_deactivate_complete(dev, error); - } else if (error) { - fpi_image_device_session_error(dev, error); - } else { - start_scan(dev); - } + if (self->deactivating) + fpi_image_device_deactivate_complete (dev, error); + else if (error) + fpi_image_device_session_error (dev, error); + else + start_scan (dev); } -static void open_loop(FpiSsm *ssm, FpDevice *_dev, void *user_data) +static void +open_loop (FpiSsm *ssm, FpDevice *_dev, void *user_data) { - FpImageDevice *dev = user_data; - FpDeviceVfs5011 *self; + FpImageDevice *dev = user_data; + FpDeviceVfs5011 *self; - self = FPI_DEVICE_VFS5011(_dev); + self = FPI_DEVICE_VFS5011 (_dev); - switch (fpi_ssm_get_cur_state(ssm)) { - case DEV_OPEN_START: - self->init_sequence.stepcount = - G_N_ELEMENTS(vfs5011_initialization); - self->init_sequence.actions = vfs5011_initialization; - self->init_sequence.device = dev; - self->init_sequence.receive_buf = - g_malloc0(VFS5011_RECEIVE_BUF_SIZE); - self->init_sequence.timeout = VFS5011_DEFAULT_WAIT_TIMEOUT; - usb_exchange_async(ssm, &self->init_sequence); - break; - }; + switch (fpi_ssm_get_cur_state (ssm)) + { + case DEV_OPEN_START: + self->init_sequence.stepcount = + G_N_ELEMENTS (vfs5011_initialization); + self->init_sequence.actions = vfs5011_initialization; + self->init_sequence.device = dev; + self->init_sequence.receive_buf = + g_malloc0 (VFS5011_RECEIVE_BUF_SIZE); + self->init_sequence.timeout = VFS5011_DEFAULT_WAIT_TIMEOUT; + usb_exchange_async (ssm, &self->init_sequence); + break; + } + ; } -static void open_loop_complete(FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +static void +open_loop_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, + GError *error) { - FpImageDevice *dev = user_data; - FpDeviceVfs5011 *self; + FpImageDevice *dev = user_data; + FpDeviceVfs5011 *self; - self = FPI_DEVICE_VFS5011(_dev); - g_free(self->init_sequence.receive_buf); - self->init_sequence.receive_buf = NULL; + self = FPI_DEVICE_VFS5011 (_dev); + g_free (self->init_sequence.receive_buf); + self->init_sequence.receive_buf = NULL; - fpi_image_device_open_complete(dev, error); - fpi_ssm_free(ssm); + fpi_image_device_open_complete (dev, error); + fpi_ssm_free (ssm); } -static void dev_open(FpImageDevice *dev) +static void +dev_open (FpImageDevice *dev) { - FpiSsm *ssm; - GError *error = NULL; - FpDeviceVfs5011 *self; + FpiSsm *ssm; + GError *error = NULL; + FpDeviceVfs5011 *self; - self = FPI_DEVICE_VFS5011(dev); - self->capture_buffer = - (unsigned char *)g_malloc0(CAPTURE_LINES * VFS5011_LINE_SIZE); + self = FPI_DEVICE_VFS5011 (dev); + self->capture_buffer = + (unsigned char *) g_malloc0 (CAPTURE_LINES * VFS5011_LINE_SIZE); - if (!g_usb_device_claim_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), 0, 0, &error)) { - fpi_image_device_open_complete(dev, error); - return; - } + if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error)) + { + fpi_image_device_open_complete (dev, error); + return; + } - ssm = fpi_ssm_new(FP_DEVICE(dev), open_loop, DEV_OPEN_NUM_STATES, dev); - fpi_ssm_start(ssm, open_loop_complete); + ssm = fpi_ssm_new (FP_DEVICE (dev), open_loop, DEV_OPEN_NUM_STATES, dev); + fpi_ssm_start (ssm, open_loop_complete); } -static void dev_close(FpImageDevice *dev) +static void +dev_close (FpImageDevice *dev) { - GError *error = NULL; - FpDeviceVfs5011 *self = FPI_DEVICE_VFS5011(dev);; + GError *error = NULL; + FpDeviceVfs5011 *self = FPI_DEVICE_VFS5011 (dev); - g_usb_device_release_interface(fpi_device_get_usb_device(FP_DEVICE(dev)), - 0, 0, &error); + ; - g_free(self->capture_buffer); - g_slist_free_full(self->rows, g_free); + g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), + 0, 0, &error); - fpi_image_device_close_complete(dev, error); + g_free (self->capture_buffer); + g_slist_free_full (self->rows, g_free); + + fpi_image_device_close_complete (dev, error); } -static void start_scan(FpImageDevice *dev) +static void +start_scan (FpImageDevice *dev) { - FpDeviceVfs5011 *self; - FpiSsm *ssm; + FpDeviceVfs5011 *self; + FpiSsm *ssm; - self = FPI_DEVICE_VFS5011(dev); - self->loop_running = TRUE; - fp_dbg("creating ssm"); - ssm = fpi_ssm_new(FP_DEVICE(dev), activate_loop, - DEV_ACTIVATE_NUM_STATES, dev); - fp_dbg("starting ssm"); - fpi_ssm_start(ssm, activate_loop_complete); - fp_dbg("ssm done, getting out"); + self = FPI_DEVICE_VFS5011 (dev); + self->loop_running = TRUE; + fp_dbg ("creating ssm"); + ssm = fpi_ssm_new (FP_DEVICE (dev), activate_loop, + DEV_ACTIVATE_NUM_STATES, dev); + fp_dbg ("starting ssm"); + fpi_ssm_start (ssm, activate_loop_complete); + fp_dbg ("ssm done, getting out"); } -static void dev_activate(FpImageDevice *dev) +static void +dev_activate (FpImageDevice *dev) { - FpDeviceVfs5011 *self; + FpDeviceVfs5011 *self; - self = FPI_DEVICE_VFS5011(dev); - fp_dbg("device initialized"); - self->deactivating = FALSE; + self = FPI_DEVICE_VFS5011 (dev); + fp_dbg ("device initialized"); + self->deactivating = FALSE; - start_scan(dev); + start_scan (dev); } -static void dev_deactivate(FpImageDevice *dev) +static void +dev_deactivate (FpImageDevice *dev) { - FpDeviceVfs5011 *self; + FpDeviceVfs5011 *self; - self = FPI_DEVICE_VFS5011(dev); - if (self->loop_running) { - self->deactivating = TRUE; - } else - fpi_image_device_deactivate_complete(dev, NULL); + self = FPI_DEVICE_VFS5011 (dev); + if (self->loop_running) + self->deactivating = TRUE; + else + fpi_image_device_deactivate_complete (dev, NULL); } -static const FpIdEntry id_table [ ] = { - { /* Validity device from some Toshiba laptops */ .vid = 0x138a, .pid = 0x0010, - }, - { /* vfs5011 */ .vid = 0x138a, .pid = 0x0011, - }, - { /* Validity device from Lenovo Preferred Pro USB Fingerprint Keyboard KUF1256 */ .vid = 0x138a, .pid = 0x0015, - }, - { /* Validity device from Lenovo T440 laptops */ .vid = 0x138a, .pid = 0x0017, - }, - { /* one more Validity device */ .vid = 0x138a, .pid = 0x0018, - }, - { .vid = 0, .pid = 0, .driver_data = 0 }, +static const FpIdEntry id_table[] = { + { /* Validity device from some Toshiba laptops */ .vid = 0x138a, .pid = 0x0010, }, + { /* vfs5011 */ .vid = 0x138a, .pid = 0x0011, }, + { /* Validity device from Lenovo Preferred Pro USB Fingerprint Keyboard KUF1256 */ .vid = 0x138a, .pid = 0x0015, }, + { /* Validity device from Lenovo T440 laptops */ .vid = 0x138a, .pid = 0x0017, }, + { /* one more Validity device */ .vid = 0x138a, .pid = 0x0018, }, + { .vid = 0, .pid = 0, .driver_data = 0 }, }; -static void fpi_device_vfs5011_init(FpDeviceVfs5011 *self) { +static void +fpi_device_vfs5011_init (FpDeviceVfs5011 *self) +{ } -static void fpi_device_vfs5011_class_init(FpDeviceVfs5011Class *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS(klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS(klass); +static void +fpi_device_vfs5011_class_init (FpDeviceVfs5011Class *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); - dev_class->id = "vfs5011"; - dev_class->full_name = "Validity VFS5011"; - dev_class->type = FP_DEVICE_TYPE_USB; - dev_class->id_table = id_table; - dev_class->scan_type = FP_SCAN_TYPE_SWIPE; + dev_class->id = "vfs5011"; + dev_class->full_name = "Validity VFS5011"; + dev_class->type = FP_DEVICE_TYPE_USB; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_SWIPE; - img_class->img_open = dev_open; - img_class->img_close = dev_close; - img_class->activate = dev_activate; - img_class->deactivate = dev_deactivate; + img_class->img_open = dev_open; + img_class->img_close = dev_close; + img_class->activate = dev_activate; + img_class->deactivate = dev_deactivate; - img_class->bz3_threshold = 20; + img_class->bz3_threshold = 20; - img_class->img_width = VFS5011_IMAGE_WIDTH; - img_class->img_height = -1; + img_class->img_width = VFS5011_IMAGE_WIDTH; + img_class->img_height = -1; } - diff --git a/libfprint/drivers/vfs5011_proto.h b/libfprint/drivers/vfs5011_proto.h index 972d0173..f71a10f6 100644 --- a/libfprint/drivers/vfs5011_proto.h +++ b/libfprint/drivers/vfs5011_proto.h @@ -5,6182 +5,6182 @@ #define VFS5011_IMAGE_WIDTH 160 enum { - VFS5011_DEFAULT_WAIT_TIMEOUT = 3000, + VFS5011_DEFAULT_WAIT_TIMEOUT = 3000, - VFS5011_OUT_ENDPOINT = 1 | FPI_USB_ENDPOINT_OUT, - VFS5011_IN_ENDPOINT_CTRL = 1 | FPI_USB_ENDPOINT_IN, - VFS5011_IN_ENDPOINT_DATA = 2 | FPI_USB_ENDPOINT_IN, - VFS5011_IN_ENDPOINT_CTRL2 = 3 | FPI_USB_ENDPOINT_IN, + VFS5011_OUT_ENDPOINT = 1 | FPI_USB_ENDPOINT_OUT, + VFS5011_IN_ENDPOINT_CTRL = 1 | FPI_USB_ENDPOINT_IN, + VFS5011_IN_ENDPOINT_DATA = 2 | FPI_USB_ENDPOINT_IN, + VFS5011_IN_ENDPOINT_CTRL2 = 3 | FPI_USB_ENDPOINT_IN, }; enum { - VFS5011_RECEIVE_BUF_SIZE = 102400 + VFS5011_RECEIVE_BUF_SIZE = 102400 }; static unsigned char VFS5011_NORMAL_CONTROL_REPLY[] = {0x00, 0x00}; static unsigned char vfs5011_cmd_01[] = { /* 1 B */ - 0x01, + 0x01, }; static unsigned char vfs5011_cmd_19[] = { /* 1 B */ - 0x19, + 0x19, }; static unsigned char vfs5011_init_00[] = { /* 39 B */ - 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x9F, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x9F, 0x00, 0x00, 0x00, }; static unsigned char vfs5011_init_01[] = { /* 40 B */ - 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x00, }; static unsigned char vfs5011_init_02[] = { /* 578 B */ - 0x06, 0x9C, 0xF1, 0x9D, 0x71, 0xC3, 0x13, 0xDF, - 0x5F, 0xE4, 0x7A, 0x1F, 0xC7, 0x17, 0x53, 0x9A, - 0x1A, 0xA1, 0xD7, 0xB6, 0x6E, 0xBE, 0xDF, 0x1F, - 0x9F, 0x44, 0x42, 0x22, 0xFA, 0x2A, 0x6A, 0xAB, - 0x2B, 0xF0, 0x56, 0x39, 0xE3, 0x7B, 0x53, 0x9A, - 0x1A, 0xA1, 0xDB, 0xBA, 0x62, 0xB2, 0xE4, 0x65, - 0xE5, 0xDB, 0x68, 0x04, 0x79, 0x98, 0xDE, 0x8F, - 0x23, 0xFB, 0xEC, 0xAD, 0x76, 0xCA, 0xA2, 0xEB, - 0x61, 0x38, 0xC7, 0xAB, 0x6E, 0x2E, 0x78, 0xF9, - 0x79, 0x13, 0x8A, 0xE5, 0x90, 0x22, 0x63, 0x8D, - 0x0E, 0x93, 0x25, 0x49, 0x5A, 0xC8, 0xA3, 0xD8, - 0x7E, 0xAE, 0x12, 0xF6, 0x2C, 0x1C, 0xFC, 0x48, - 0x4F, 0x0E, 0x48, 0x22, 0xFB, 0x4B, 0xCE, 0x7E, - 0xDB, 0x2D, 0x91, 0xE0, 0xC8, 0x78, 0x2E, 0xAF, - 0x2F, 0xD4, 0x03, 0x6F, 0x12, 0x59, 0xC6, 0x26, - 0x40, 0x88, 0x2E, 0x62, 0xBA, 0x06, 0x6C, 0xC9, - 0x7A, 0x84, 0x93, 0xCF, 0x14, 0x15, 0x44, 0x87, - 0xE2, 0x09, 0x97, 0xE6, 0xCE, 0x7E, 0x28, 0xA9, - 0x29, 0x53, 0xD7, 0xB8, 0xD1, 0x53, 0x30, 0x15, - 0x6E, 0x95, 0x3E, 0xA2, 0x7A, 0xCA, 0x9C, 0x1D, - 0x9D, 0xEB, 0x5F, 0x15, 0xEF, 0x48, 0x34, 0xCC, - 0xCB, 0x02, 0xA6, 0xD6, 0xA7, 0x80, 0xF2, 0x3F, - 0x7E, 0x96, 0x23, 0xAE, 0x42, 0xF1, 0x29, 0xF5, - 0xAD, 0x5A, 0x35, 0x57, 0x36, 0xAA, 0xAF, 0x97, - 0xE8, 0x1E, 0xA2, 0xD3, 0xFB, 0x4B, 0x1D, 0x9C, - 0x1C, 0x06, 0x84, 0xEB, 0x9E, 0x2C, 0xD4, 0x18, - 0x94, 0x44, 0x7E, 0x4B, 0x12, 0x91, 0xF2, 0x8B, - 0x07, 0x45, 0xDB, 0x52, 0xBB, 0x2E, 0x53, 0x63, - 0xE3, 0x38, 0xB8, 0x95, 0x4D, 0x9B, 0xCF, 0x07, - 0x05, 0xDD, 0x4C, 0xE2, 0x39, 0xAF, 0xA9, 0x51, - 0xDB, 0xAD, 0x19, 0xC8, 0x13, 0x6E, 0x0A, 0x2F, - 0xEA, 0x12, 0xB9, 0x25, 0x55, 0xB6, 0x64, 0x04, - 0x7F, 0x14, 0x6E, 0x12, 0x08, 0xFB, 0xBD, 0xBD, - 0x1D, 0xC6, 0xE2, 0x84, 0x50, 0x20, 0x60, 0xA0, - 0x90, 0xD2, 0x74, 0x8A, 0x18, 0xA4, 0xD9, 0xE9, - 0x69, 0xB2, 0x1E, 0x73, 0xAB, 0x1B, 0x7B, 0xBB, - 0x3B, 0xE0, 0x42, 0x23, 0xF9, 0x29, 0x49, 0x89, - 0x09, 0xD2, 0x4C, 0x29, 0xF1, 0x21, 0x65, 0xAC, - 0x2C, 0x97, 0x30, 0x6C, 0xB4, 0x04, 0xF4, 0x3D, - 0xBD, 0x06, 0xA0, 0xC6, 0x1E, 0xCE, 0x7E, 0xB3, - 0x33, 0x88, 0x2E, 0x43, 0x9B, 0x2B, 0x37, 0xF0, - 0x70, 0xCB, 0x91, 0xF1, 0x2B, 0xFB, 0x8B, 0x48, - 0xCA, 0x39, 0x97, 0xFB, 0x21, 0xB9, 0xCD, 0x0E, - 0x8C, 0x7F, 0x8D, 0xEC, 0x36, 0xE6, 0xEA, 0x27, - 0xA5, 0x1E, 0x40, 0x2A, 0xF2, 0x22, 0xCA, 0x07, - 0x85, 0x3E, 0xC8, 0xAE, 0x76, 0xA6, 0xF0, 0x71, - 0xF1, 0xAB, 0x6B, 0x04, 0x6D, 0xA9, 0xCA, 0x06, - 0x2C, 0x66, 0xA5, 0xCA, 0xB0, 0x4B, 0x2B, 0x62, - 0xEB, 0xD5, 0x61, 0x0D, 0xF0, 0x46, 0x26, 0xC3, - 0x44, 0x9F, 0x0C, 0x63, 0xBB, 0xAA, 0xBD, 0x7E, - 0xF2, 0x74, 0x00, 0x66, 0x2B, 0x7A, 0x62, 0xA1, - 0x07, 0x80, 0x33, 0x8D, 0x1F, 0xF7, 0x45, 0xCB, - 0x5E, 0x24, 0xEB, 0x84, 0xED, 0x27, 0x44, 0x61, - 0xFF, 0x0C, 0xA7, 0x3B, 0xE3, 0x53, 0x05, 0x84, - 0x04, 0xEE, 0x23, 0x4C, 0xB5, 0x79, 0x1A, 0xF3, - 0xA0, 0x66, 0x20, 0x4C, 0x94, 0x24, 0x72, 0xF3, - 0x73, 0x39, 0xF8, 0x97, 0xDD, 0x64, 0x54, 0xF2, - 0x6B, 0xBA, 0xAD, 0xBC, 0x67, 0x66, 0x78, 0xBB, - 0x5E, 0x6D, 0xFB, 0x8A, 0xA2, 0x74, 0x3D, 0xF5, - 0xD4, 0x72, 0xC7, 0x1A, 0xBD, 0x0E, 0x0B, 0x2C, - 0x8C, 0x4A, 0x0C, 0x60, 0xB8, 0x08, 0x5E, 0xDF, - 0x5F, 0x05, 0x33, 0x5C, 0xB5, 0x7E, 0x1D, 0xFC, - 0xFD, 0x25, 0xBA, 0x95, 0xC4, 0xA7, 0xDA, 0xEA, - 0x6A, 0xB1, 0x31, 0x1C, 0xC4, 0xE5, 0x07, 0xC4, - 0xC5, 0x9D, 0x28, 0xCD, 0x3C, 0xE9, 0x89, 0x49, - 0xD4, 0xFF, 0x7F, 0x52, 0x8A, 0x9B, 0x7F, 0xBC, - 0x8E, 0xF5, 0xCF, 0x0B, 0xD9, 0x49, 0x48, 0x88, - 0x80, 0x71, 0x7D, 0xAB, 0xEF, 0x47, 0x2B, 0xF7, - 0x7B, 0x2D, 0x79, 0x3F, 0xCF, 0xBF, 0xFF, 0x3F, - 0x6D, 0xF8, 0x42, 0xEC, 0x7F, 0xE8, 0xED, 0x42, - 0xE6, 0x1D, 0x4D, 0x32, 0xFA, 0x6A, 0x0A, 0xD7, - 0xA7, 0x7C, 0xCB, 0xA7, 0x7B, 0xCB, 0xBF, 0x71, - 0xF3, 0x48, + 0x06, 0x9C, 0xF1, 0x9D, 0x71, 0xC3, 0x13, 0xDF, + 0x5F, 0xE4, 0x7A, 0x1F, 0xC7, 0x17, 0x53, 0x9A, + 0x1A, 0xA1, 0xD7, 0xB6, 0x6E, 0xBE, 0xDF, 0x1F, + 0x9F, 0x44, 0x42, 0x22, 0xFA, 0x2A, 0x6A, 0xAB, + 0x2B, 0xF0, 0x56, 0x39, 0xE3, 0x7B, 0x53, 0x9A, + 0x1A, 0xA1, 0xDB, 0xBA, 0x62, 0xB2, 0xE4, 0x65, + 0xE5, 0xDB, 0x68, 0x04, 0x79, 0x98, 0xDE, 0x8F, + 0x23, 0xFB, 0xEC, 0xAD, 0x76, 0xCA, 0xA2, 0xEB, + 0x61, 0x38, 0xC7, 0xAB, 0x6E, 0x2E, 0x78, 0xF9, + 0x79, 0x13, 0x8A, 0xE5, 0x90, 0x22, 0x63, 0x8D, + 0x0E, 0x93, 0x25, 0x49, 0x5A, 0xC8, 0xA3, 0xD8, + 0x7E, 0xAE, 0x12, 0xF6, 0x2C, 0x1C, 0xFC, 0x48, + 0x4F, 0x0E, 0x48, 0x22, 0xFB, 0x4B, 0xCE, 0x7E, + 0xDB, 0x2D, 0x91, 0xE0, 0xC8, 0x78, 0x2E, 0xAF, + 0x2F, 0xD4, 0x03, 0x6F, 0x12, 0x59, 0xC6, 0x26, + 0x40, 0x88, 0x2E, 0x62, 0xBA, 0x06, 0x6C, 0xC9, + 0x7A, 0x84, 0x93, 0xCF, 0x14, 0x15, 0x44, 0x87, + 0xE2, 0x09, 0x97, 0xE6, 0xCE, 0x7E, 0x28, 0xA9, + 0x29, 0x53, 0xD7, 0xB8, 0xD1, 0x53, 0x30, 0x15, + 0x6E, 0x95, 0x3E, 0xA2, 0x7A, 0xCA, 0x9C, 0x1D, + 0x9D, 0xEB, 0x5F, 0x15, 0xEF, 0x48, 0x34, 0xCC, + 0xCB, 0x02, 0xA6, 0xD6, 0xA7, 0x80, 0xF2, 0x3F, + 0x7E, 0x96, 0x23, 0xAE, 0x42, 0xF1, 0x29, 0xF5, + 0xAD, 0x5A, 0x35, 0x57, 0x36, 0xAA, 0xAF, 0x97, + 0xE8, 0x1E, 0xA2, 0xD3, 0xFB, 0x4B, 0x1D, 0x9C, + 0x1C, 0x06, 0x84, 0xEB, 0x9E, 0x2C, 0xD4, 0x18, + 0x94, 0x44, 0x7E, 0x4B, 0x12, 0x91, 0xF2, 0x8B, + 0x07, 0x45, 0xDB, 0x52, 0xBB, 0x2E, 0x53, 0x63, + 0xE3, 0x38, 0xB8, 0x95, 0x4D, 0x9B, 0xCF, 0x07, + 0x05, 0xDD, 0x4C, 0xE2, 0x39, 0xAF, 0xA9, 0x51, + 0xDB, 0xAD, 0x19, 0xC8, 0x13, 0x6E, 0x0A, 0x2F, + 0xEA, 0x12, 0xB9, 0x25, 0x55, 0xB6, 0x64, 0x04, + 0x7F, 0x14, 0x6E, 0x12, 0x08, 0xFB, 0xBD, 0xBD, + 0x1D, 0xC6, 0xE2, 0x84, 0x50, 0x20, 0x60, 0xA0, + 0x90, 0xD2, 0x74, 0x8A, 0x18, 0xA4, 0xD9, 0xE9, + 0x69, 0xB2, 0x1E, 0x73, 0xAB, 0x1B, 0x7B, 0xBB, + 0x3B, 0xE0, 0x42, 0x23, 0xF9, 0x29, 0x49, 0x89, + 0x09, 0xD2, 0x4C, 0x29, 0xF1, 0x21, 0x65, 0xAC, + 0x2C, 0x97, 0x30, 0x6C, 0xB4, 0x04, 0xF4, 0x3D, + 0xBD, 0x06, 0xA0, 0xC6, 0x1E, 0xCE, 0x7E, 0xB3, + 0x33, 0x88, 0x2E, 0x43, 0x9B, 0x2B, 0x37, 0xF0, + 0x70, 0xCB, 0x91, 0xF1, 0x2B, 0xFB, 0x8B, 0x48, + 0xCA, 0x39, 0x97, 0xFB, 0x21, 0xB9, 0xCD, 0x0E, + 0x8C, 0x7F, 0x8D, 0xEC, 0x36, 0xE6, 0xEA, 0x27, + 0xA5, 0x1E, 0x40, 0x2A, 0xF2, 0x22, 0xCA, 0x07, + 0x85, 0x3E, 0xC8, 0xAE, 0x76, 0xA6, 0xF0, 0x71, + 0xF1, 0xAB, 0x6B, 0x04, 0x6D, 0xA9, 0xCA, 0x06, + 0x2C, 0x66, 0xA5, 0xCA, 0xB0, 0x4B, 0x2B, 0x62, + 0xEB, 0xD5, 0x61, 0x0D, 0xF0, 0x46, 0x26, 0xC3, + 0x44, 0x9F, 0x0C, 0x63, 0xBB, 0xAA, 0xBD, 0x7E, + 0xF2, 0x74, 0x00, 0x66, 0x2B, 0x7A, 0x62, 0xA1, + 0x07, 0x80, 0x33, 0x8D, 0x1F, 0xF7, 0x45, 0xCB, + 0x5E, 0x24, 0xEB, 0x84, 0xED, 0x27, 0x44, 0x61, + 0xFF, 0x0C, 0xA7, 0x3B, 0xE3, 0x53, 0x05, 0x84, + 0x04, 0xEE, 0x23, 0x4C, 0xB5, 0x79, 0x1A, 0xF3, + 0xA0, 0x66, 0x20, 0x4C, 0x94, 0x24, 0x72, 0xF3, + 0x73, 0x39, 0xF8, 0x97, 0xDD, 0x64, 0x54, 0xF2, + 0x6B, 0xBA, 0xAD, 0xBC, 0x67, 0x66, 0x78, 0xBB, + 0x5E, 0x6D, 0xFB, 0x8A, 0xA2, 0x74, 0x3D, 0xF5, + 0xD4, 0x72, 0xC7, 0x1A, 0xBD, 0x0E, 0x0B, 0x2C, + 0x8C, 0x4A, 0x0C, 0x60, 0xB8, 0x08, 0x5E, 0xDF, + 0x5F, 0x05, 0x33, 0x5C, 0xB5, 0x7E, 0x1D, 0xFC, + 0xFD, 0x25, 0xBA, 0x95, 0xC4, 0xA7, 0xDA, 0xEA, + 0x6A, 0xB1, 0x31, 0x1C, 0xC4, 0xE5, 0x07, 0xC4, + 0xC5, 0x9D, 0x28, 0xCD, 0x3C, 0xE9, 0x89, 0x49, + 0xD4, 0xFF, 0x7F, 0x52, 0x8A, 0x9B, 0x7F, 0xBC, + 0x8E, 0xF5, 0xCF, 0x0B, 0xD9, 0x49, 0x48, 0x88, + 0x80, 0x71, 0x7D, 0xAB, 0xEF, 0x47, 0x2B, 0xF7, + 0x7B, 0x2D, 0x79, 0x3F, 0xCF, 0xBF, 0xFF, 0x3F, + 0x6D, 0xF8, 0x42, 0xEC, 0x7F, 0xE8, 0xED, 0x42, + 0xE6, 0x1D, 0x4D, 0x32, 0xFA, 0x6A, 0x0A, 0xD7, + 0xA7, 0x7C, 0xCB, 0xA7, 0x7B, 0xCB, 0xBF, 0x71, + 0xF3, 0x48, }; static unsigned char vfs5011_cmd_1A[] = { /* 1 B */ - 0x1A, + 0x1A, }; static unsigned char vfs5011_init_03[] = { /* 2354 B */ - 0x06, 0xFE, 0x93, 0xFF, 0x03, 0xBA, 0x6A, 0xA6, - 0x26, 0x9D, 0x03, 0x66, 0xBE, 0x6E, 0x2A, 0xE3, - 0x63, 0xD8, 0xFE, 0x9B, 0x43, 0x93, 0xD7, 0x03, - 0x83, 0x38, 0x8C, 0xE0, 0x38, 0x88, 0x58, 0x94, - 0x14, 0xAF, 0xC9, 0xA2, 0x7A, 0xCA, 0x96, 0x5E, - 0xDE, 0x65, 0x27, 0x36, 0xEA, 0x3A, 0x4E, 0x82, - 0x02, 0xB9, 0x0F, 0x4B, 0x97, 0x17, 0xF7, 0x1A, - 0x9E, 0x75, 0xC3, 0x8F, 0x53, 0xD3, 0x9F, 0x7F, - 0xFB, 0x10, 0xE6, 0xAA, 0x76, 0xF6, 0x72, 0x93, - 0x17, 0xFC, 0x4A, 0x26, 0xFE, 0x76, 0x2A, 0xEA, - 0x6A, 0x89, 0x3F, 0xF3, 0x2B, 0xA3, 0xFF, 0x9F, - 0x1F, 0xFC, 0x4A, 0x06, 0xDE, 0x56, 0x38, 0xD8, - 0x58, 0xBB, 0x0D, 0x21, 0xF9, 0x71, 0x19, 0x99, - 0x19, 0xFA, 0x4C, 0x40, 0x98, 0x10, 0x78, 0xD8, - 0x58, 0xBB, 0x0D, 0xE1, 0x39, 0xB1, 0xD9, 0x99, - 0x19, 0xFA, 0x6C, 0x7E, 0xA2, 0x72, 0xC6, 0x7D, - 0xF9, 0x42, 0xF4, 0x86, 0x5A, 0xDA, 0xD2, 0x06, - 0x86, 0x3D, 0x6F, 0x08, 0xD0, 0x00, 0xD8, 0x10, - 0x90, 0x2B, 0xFD, 0xB7, 0x6B, 0xBB, 0x67, 0xA0, - 0x20, 0x9B, 0x35, 0x36, 0xEA, 0x3A, 0xA2, 0x0C, - 0x88, 0x33, 0x7D, 0x1A, 0xC2, 0x12, 0x2A, 0xFE, - 0x7E, 0xC5, 0x8C, 0x17, 0x30, 0x7F, 0xE0, 0xCF, - 0xB0, 0x94, 0x4E, 0x36, 0xEE, 0x3E, 0x5E, 0x96, - 0x16, 0xCD, 0x9F, 0xE1, 0x3B, 0xEB, 0x8B, 0x5B, - 0xDB, 0x00, 0x8A, 0xF2, 0x2A, 0xFA, 0x0E, 0xC8, - 0x48, 0xF3, 0x6D, 0x12, 0xC8, 0x18, 0x08, 0xDC, - 0x5C, 0xE7, 0x01, 0x79, 0xA1, 0x71, 0x3D, 0xF4, - 0x74, 0xCF, 0x84, 0x17, 0xCF, 0x7F, 0xE0, 0x20, - 0x5F, 0x7B, 0xFB, 0xD6, 0x0E, 0x1B, 0x65, 0xA5, - 0x00, 0xDC, 0x6A, 0xE3, 0x7E, 0xCE, 0x4B, 0xCE, - 0x68, 0x22, 0xB8, 0xD7, 0xAE, 0x33, 0x50, 0x9C, - 0x14, 0x46, 0xFA, 0x14, 0x85, 0x35, 0x48, 0x78, - 0xF8, 0x23, 0xA3, 0x8E, 0x56, 0x77, 0x39, 0xFA, - 0x76, 0xA5, 0x91, 0xB4, 0x34, 0xE1, 0x4D, 0xA8, - 0x35, 0x1E, 0x9E, 0xB3, 0x6B, 0x6A, 0x3A, 0xF9, - 0xD4, 0x0D, 0x9A, 0xD9, 0x02, 0xF4, 0x94, 0x54, - 0x1F, 0xE6, 0x5B, 0x8C, 0x72, 0xC9, 0xA3, 0xEB, - 0x69, 0x32, 0x04, 0x1C, 0x43, 0x69, 0xF9, 0x3F, - 0xBE, 0x65, 0xF6, 0xFE, 0x03, 0x9E, 0xF4, 0x29, - 0x59, 0x82, 0x02, 0x2F, 0xF7, 0x67, 0x66, 0xA6, - 0x03, 0x22, 0x6B, 0x27, 0x19, 0xBA, 0xCA, 0x2A, - 0xAA, 0x7D, 0xC1, 0x08, 0xF6, 0x63, 0xA2, 0x53, - 0xD0, 0xBA, 0x3E, 0x51, 0xAC, 0x38, 0x70, 0xAD, - 0xDD, 0x06, 0x86, 0xAB, 0x73, 0xF2, 0xA1, 0x62, - 0xC3, 0x2C, 0x99, 0xDC, 0x47, 0xEA, 0x7A, 0xBA, - 0x3A, 0xE1, 0x61, 0x4C, 0x94, 0xA6, 0xC4, 0x09, - 0x85, 0x45, 0x73, 0x9F, 0x43, 0xA5, 0xDD, 0x1A, - 0x96, 0x48, 0xF2, 0x98, 0x02, 0xA0, 0xCE, 0x12, - 0x95, 0x74, 0x86, 0x58, 0x44, 0x75, 0x27, 0xE3, - 0x63, 0x0A, 0xB7, 0xA5, 0xBF, 0x0B, 0x6A, 0x9D, - 0xA6, 0x71, 0xF0, 0x20, 0xE9, 0x64, 0x0F, 0x08, - 0x33, 0xE4, 0x6F, 0x0F, 0x11, 0xA0, 0xC0, 0x37, - 0x8B, 0x54, 0x25, 0xF2, 0x2B, 0xA6, 0xCD, 0xA0, - 0x23, 0x45, 0xF0, 0xF9, 0x99, 0x01, 0xCB, 0x6D, - 0xB7, 0x3F, 0x82, 0x99, 0x0A, 0xFE, 0x2C, 0x28, - 0x29, 0xA4, 0x85, 0x15, 0x60, 0xD5, 0x08, 0xCD, - 0x68, 0x04, 0x9A, 0xFA, 0x39, 0x5B, 0x99, 0x35, - 0x15, 0x0A, 0xFD, 0x51, 0x4F, 0x3F, 0x85, 0x97, - 0xE5, 0x23, 0x17, 0xBB, 0xA7, 0x56, 0xF6, 0xB5, - 0x74, 0x5F, 0x06, 0x9A, 0xA2, 0xF1, 0xB0, 0xFA, - 0x94, 0xBF, 0xC7, 0x38, 0x22, 0xCF, 0x2D, 0xEB, - 0x68, 0xB3, 0xC7, 0x09, 0xBD, 0xC7, 0x65, 0x67, - 0xFB, 0x5D, 0xD1, 0x71, 0x6B, 0xD7, 0xB7, 0xA5, - 0x37, 0xE5, 0x7E, 0x19, 0x16, 0x1A, 0x7B, 0xB7, - 0x15, 0xD3, 0x95, 0xF9, 0x21, 0x91, 0xC7, 0x46, - 0xC6, 0xAC, 0x2F, 0x40, 0x20, 0x9B, 0x77, 0xDC, - 0xFE, 0x84, 0x52, 0x94, 0xE7, 0xF2, 0x28, 0xC8, - 0xE5, 0x3C, 0x2F, 0xEF, 0x12, 0xBF, 0x2F, 0xEF, - 0x6F, 0xB4, 0x34, 0x19, 0xC1, 0xD0, 0x86, 0x45, - 0x74, 0x98, 0x2D, 0x8C, 0x56, 0x43, 0x75, 0x90, - 0xA1, 0x43, 0xF6, 0xBA, 0x48, 0x58, 0x99, 0x61, - 0xE2, 0xF4, 0x40, 0x89, 0x04, 0x91, 0x40, 0xBB, - 0x38, 0xC3, 0x4F, 0x83, 0x99, 0xEA, 0x9A, 0xFB, - 0x41, 0x99, 0x23, 0x4D, 0xBC, 0x0F, 0x46, 0x95, - 0x3C, 0xC4, 0x5B, 0x04, 0xF9, 0x1D, 0x58, 0x29, - 0x94, 0x4C, 0xCA, 0x9C, 0xE4, 0x96, 0x35, 0xE5, - 0xC4, 0x23, 0x96, 0xDF, 0x54, 0xC1, 0xAD, 0x64, - 0xD4, 0x35, 0x23, 0x7D, 0x66, 0xC6, 0xBD, 0xE4, - 0x4D, 0x95, 0x68, 0x37, 0x89, 0xA0, 0x36, 0x5B, - 0xD8, 0xB1, 0xA7, 0x6E, 0x9A, 0x66, 0x23, 0x41, - 0xE9, 0x93, 0x1B, 0x74, 0x1D, 0x92, 0xF1, 0xF3, - 0xB0, 0x4F, 0x5C, 0x60, 0x9D, 0x9C, 0xBD, 0x7E, - 0xCE, 0x2F, 0x39, 0xF4, 0x6C, 0xDF, 0x8D, 0x8E, - 0x2A, 0x3C, 0x89, 0xC0, 0x4A, 0xDF, 0x0E, 0x8D, - 0x0E, 0xE5, 0x69, 0xA5, 0xDC, 0x2E, 0x4D, 0x40, - 0xC3, 0xFD, 0x18, 0x51, 0x38, 0xCD, 0xAE, 0x5E, - 0xE4, 0x9F, 0x88, 0xA0, 0x7B, 0x06, 0x65, 0x40, - 0x92, 0x6C, 0x6B, 0x40, 0x9B, 0x1B, 0x41, 0x21, - 0x00, 0x9D, 0x28, 0x89, 0x52, 0xC7, 0xF5, 0x10, - 0xA0, 0x51, 0x47, 0x36, 0x1E, 0xAE, 0xF8, 0x79, - 0xF9, 0x07, 0x94, 0xF8, 0xA1, 0x58, 0x3B, 0x6A, - 0xD9, 0x01, 0x16, 0x32, 0xE9, 0xF0, 0xC9, 0x80, - 0x09, 0xCF, 0x89, 0xE5, 0x3D, 0x8D, 0xDB, 0x5A, - 0xDA, 0x30, 0xB3, 0xDC, 0x08, 0x9F, 0xC7, 0x04, - 0xD5, 0x44, 0xF1, 0x0F, 0xD4, 0x6C, 0x6E, 0x0F, - 0xFF, 0x2F, 0x10, 0x6A, 0xFA, 0x4C, 0xFD, 0x76, - 0xF5, 0x22, 0xFE, 0x9E, 0x41, 0x73, 0xDA, 0xE6, - 0x70, 0xA3, 0x1F, 0x55, 0xD4, 0x6C, 0xA1, 0x63, - 0x06, 0x1C, 0x8C, 0xCD, 0x1F, 0xB2, 0x22, 0x88, - 0x4B, 0x22, 0x87, 0xE0, 0xAA, 0x1E, 0x7E, 0xA8, - 0x13, 0xC3, 0x13, 0x06, 0xCE, 0xBC, 0xC8, 0xF4, - 0x22, 0x55, 0xE9, 0x27, 0xBC, 0x04, 0x46, 0x85, - 0x08, 0xF3, 0x64, 0x0C, 0xC9, 0x89, 0xE5, 0x2E, - 0x2C, 0xF4, 0x4F, 0xE1, 0x1A, 0x77, 0x00, 0xA8, - 0x27, 0x6E, 0xD5, 0xB9, 0x6D, 0xCF, 0xB9, 0x50, - 0xDE, 0x0E, 0x11, 0xDF, 0x4A, 0xFA, 0xDC, 0x1C, - 0x9C, 0x4B, 0xFF, 0x53, 0xAB, 0x1B, 0xD9, 0x0A, - 0x82, 0x9B, 0x48, 0x84, 0xD0, 0x7A, 0xFF, 0xD5, - 0x73, 0xB5, 0xF3, 0xF5, 0x6E, 0x0C, 0x68, 0xA8, - 0x4E, 0x88, 0x02, 0xD6, 0x2C, 0x31, 0x52, 0x77, - 0x13, 0xEE, 0xF8, 0x74, 0xD8, 0x0E, 0x70, 0x91, - 0xA0, 0x37, 0x82, 0x1C, 0xCF, 0x7F, 0x39, 0xD6, - 0x51, 0xF8, 0x05, 0x69, 0xBD, 0x07, 0xC2, 0x68, - 0xCD, 0x1A, 0x94, 0x6A, 0x91, 0xFF, 0x5F, 0xBF, - 0x3F, 0x76, 0xA5, 0x69, 0x33, 0xC0, 0xA8, 0x2E, - 0xAD, 0x76, 0x62, 0x1D, 0xC2, 0xFE, 0xE4, 0x56, - 0x92, 0x49, 0x5D, 0x22, 0xFD, 0xE8, 0x6E, 0x88, - 0x04, 0xCD, 0x66, 0xFA, 0x90, 0x33, 0x5B, 0xF1, - 0x32, 0xFF, 0x82, 0xE9, 0xF3, 0x47, 0x27, 0x25, - 0x69, 0x49, 0xE9, 0xB9, 0x66, 0x34, 0x57, 0x9A, - 0x98, 0x67, 0x50, 0x2B, 0x9D, 0x7D, 0x8F, 0x42, - 0xC2, 0x0F, 0x30, 0x50, 0x84, 0x26, 0x4D, 0x74, - 0x06, 0x90, 0x26, 0xCC, 0x04, 0xB4, 0x56, 0x5F, - 0x26, 0xAB, 0x85, 0x1C, 0x7C, 0xEE, 0x23, 0xE0, - 0x85, 0x83, 0x13, 0xDF, 0x97, 0x53, 0x38, 0x61, - 0xB7, 0x85, 0x39, 0x59, 0x8A, 0x36, 0x1A, 0x38, - 0x9B, 0x9D, 0xF9, 0x37, 0x9B, 0xF1, 0x42, 0x42, - 0xE2, 0x39, 0x2D, 0x52, 0x82, 0xD0, 0xD5, 0xB5, - 0x47, 0xC1, 0x09, 0xA7, 0x3C, 0x84, 0xF2, 0x78, - 0x0A, 0xDD, 0x05, 0x8B, 0x17, 0xA7, 0x65, 0xB6, - 0x3E, 0x00, 0x69, 0x23, 0x7D, 0x08, 0x97, 0x7A, - 0xFD, 0x2A, 0x93, 0x3F, 0xC7, 0x77, 0xB5, 0x66, - 0xEE, 0xB7, 0x64, 0xA8, 0x66, 0x4C, 0xDF, 0x7A, - 0x24, 0xD9, 0x72, 0xEE, 0x3A, 0x88, 0xAE, 0xA6, - 0xD9, 0xBA, 0x2E, 0xEF, 0x34, 0x21, 0x99, 0x7F, - 0x5F, 0x14, 0xD6, 0xDC, 0x1D, 0x8A, 0xE6, 0x2D, - 0x7F, 0x87, 0xEC, 0x42, 0x38, 0xFC, 0x56, 0x55, - 0x15, 0xEE, 0x58, 0xE6, 0x5B, 0x4B, 0x89, 0x5A, - 0xD2, 0x7B, 0x91, 0x83, 0xE7, 0x0D, 0x07, 0x24, - 0xA8, 0x1E, 0x7A, 0x58, 0x80, 0x92, 0xE1, 0x29, - 0x4C, 0x4D, 0xDD, 0x37, 0xE6, 0x56, 0x3A, 0x85, - 0x09, 0x86, 0x72, 0x5D, 0x8D, 0x57, 0x74, 0x46, - 0x82, 0x59, 0x5D, 0x22, 0xF1, 0xDD, 0xF6, 0x84, - 0x50, 0x77, 0xCD, 0x5B, 0x8F, 0xB7, 0x55, 0xD1, - 0x51, 0x6F, 0x01, 0x4B, 0x01, 0xA5, 0x39, 0x6B, - 0x22, 0x08, 0x2C, 0x14, 0x30, 0xA2, 0xC1, 0x0C, - 0xAC, 0x56, 0xE4, 0x95, 0xBD, 0x20, 0x47, 0x01, - 0x5E, 0x7A, 0x6E, 0x16, 0x32, 0x94, 0x2E, 0x06, - 0x8A, 0xD9, 0xED, 0xC5, 0x1D, 0x1B, 0xC1, 0x11, - 0x9D, 0xBC, 0x2F, 0x95, 0x6B, 0xF9, 0x8D, 0xB1, - 0x13, 0x0A, 0x4D, 0x03, 0x8F, 0xC3, 0xA5, 0xF8, - 0x87, 0x39, 0x5A, 0x10, 0xE5, 0x52, 0x74, 0x48, - 0x37, 0xEC, 0x6C, 0x41, 0x99, 0x78, 0x2D, 0xEE, - 0x36, 0xE8, 0x1C, 0xD0, 0xF8, 0x02, 0x27, 0xD5, - 0x51, 0x0A, 0x9A, 0xD5, 0x3C, 0xAA, 0x89, 0x7A, - 0x9B, 0x0A, 0xBF, 0xA2, 0x31, 0x82, 0xEE, 0x86, - 0x20, 0x98, 0x01, 0x0B, 0x50, 0xFE, 0x92, 0x21, - 0x33, 0xCD, 0xA5, 0x09, 0xF1, 0x41, 0xB3, 0x15, - 0x35, 0xDC, 0x2E, 0xC2, 0xA8, 0x1D, 0x70, 0x12, - 0x95, 0x4E, 0x48, 0x95, 0x49, 0x49, 0x81, 0xD2, - 0xF0, 0x6C, 0xDA, 0xAB, 0x83, 0x2E, 0xBE, 0x72, - 0xE1, 0x7C, 0xCA, 0xA6, 0x72, 0xF1, 0xA3, 0x27, - 0x27, 0xE1, 0xA7, 0xC7, 0x4C, 0x3E, 0x7B, 0x65, - 0x25, 0xDE, 0x68, 0xC6, 0x78, 0x68, 0xCE, 0xFD, - 0x82, 0x59, 0xD9, 0xF4, 0x2C, 0xAD, 0x80, 0x43, - 0xE2, 0x77, 0xC2, 0x87, 0x4C, 0xE1, 0x71, 0xB1, - 0x31, 0xEA, 0x6A, 0x47, 0x9F, 0xBE, 0xEB, 0x28, - 0x30, 0xE2, 0xD8, 0x1D, 0x67, 0xFE, 0x43, 0x23, - 0x03, 0xCC, 0x5C, 0x0A, 0xD0, 0x05, 0x22, 0xC3, - 0x5E, 0x75, 0xF5, 0xD8, 0x00, 0x11, 0x21, 0xE2, - 0x43, 0xD1, 0x64, 0x39, 0xD2, 0x61, 0x90, 0x1F, - 0x9C, 0xC6, 0x21, 0x4E, 0x1F, 0x86, 0xCF, 0x0C, - 0x25, 0xA7, 0x0C, 0x90, 0x48, 0xF8, 0xAE, 0x2F, - 0xAF, 0x55, 0xB1, 0xDE, 0x8E, 0x1C, 0xBB, 0x13, - 0x8E, 0xF4, 0x11, 0x7E, 0x43, 0xBE, 0xF6, 0xA7, - 0x73, 0xAB, 0xDC, 0xE5, 0x3E, 0x3F, 0x09, 0xCA, - 0xE2, 0x1B, 0x15, 0x72, 0x6A, 0x70, 0x00, 0x50, - 0x4A, 0x81, 0x87, 0x71, 0x3A, 0x13, 0x51, 0xB4, - 0xFA, 0x04, 0xAF, 0x33, 0xEB, 0x5B, 0x0D, 0x8C, - 0x0C, 0x76, 0x93, 0xFC, 0x41, 0xB6, 0xFE, 0xDF, - 0x08, 0xD0, 0x27, 0x78, 0xA3, 0x22, 0x10, 0xD3, - 0x5F, 0x88, 0xE6, 0xA9, 0x80, 0x66, 0x05, 0x72, - 0x9F, 0x66, 0x6D, 0x0E, 0x1E, 0xAA, 0x03, 0xCC, - 0xE1, 0x38, 0x0F, 0x3B, 0xE0, 0xB0, 0x4D, 0xAD, - 0xB4, 0x4C, 0x73, 0x1B, 0xA6, 0x13, 0x73, 0x02, - 0xDB, 0x03, 0x1D, 0x52, 0x86, 0x34, 0xE4, 0x8E, - 0x2E, 0x5C, 0xC9, 0xB8, 0x90, 0x2C, 0x47, 0x41, - 0x37, 0x13, 0x93, 0xBE, 0x66, 0xCA, 0x62, 0x25, - 0x37, 0xE8, 0x7F, 0x49, 0x92, 0x3F, 0xAF, 0xC2, - 0x40, 0x3E, 0x4E, 0x07, 0xF2, 0x48, 0x35, 0x05, - 0x85, 0x5E, 0xDE, 0xF3, 0x2B, 0xDA, 0xE1, 0x22, - 0x93, 0x14, 0xA1, 0x45, 0xD9, 0xE0, 0x02, 0xFB, - 0x3F, 0xF9, 0xBF, 0xD3, 0x0B, 0xBB, 0xED, 0x6C, - 0xEC, 0x95, 0xE1, 0x9D, 0x60, 0xAB, 0xEB, 0xBA, - 0x61, 0xB9, 0x87, 0x69, 0x38, 0xC1, 0xBC, 0x8C, - 0x0C, 0xD7, 0x57, 0x7A, 0xA2, 0xAF, 0xCD, 0x2C, - 0xF1, 0x29, 0xB7, 0xD9, 0x0D, 0x31, 0xDA, 0xB8, - 0x1D, 0x8C, 0x12, 0xFF, 0x79, 0xCA, 0x38, 0x3A, - 0xAA, 0xE8, 0x0C, 0xF9, 0x63, 0x5A, 0x58, 0x14, - 0x97, 0x75, 0x51, 0x20, 0x08, 0xB8, 0xEE, 0x6F, - 0xEF, 0x05, 0xEE, 0x81, 0x61, 0xD2, 0x00, 0xD3, - 0x4B, 0x9C, 0x36, 0x5D, 0x6E, 0xC4, 0x35, 0xAA, - 0x29, 0x32, 0x2F, 0x63, 0x19, 0xFA, 0x82, 0x82, - 0x22, 0xF9, 0xD7, 0xB2, 0xE8, 0x4B, 0x2D, 0x4F, - 0x0C, 0xC7, 0xEB, 0x0F, 0x5E, 0x9D, 0x18, 0xAB, - 0x0B, 0x62, 0xC7, 0xB3, 0x7C, 0x27, 0x49, 0x31, - 0x22, 0x75, 0x58, 0xBC, 0x6F, 0x72, 0x10, 0x30, - 0xB8, 0x63, 0xF8, 0x9E, 0x5B, 0x1B, 0x77, 0xB5, - 0x28, 0x03, 0x83, 0xAE, 0x76, 0xF7, 0xCA, 0x09, - 0xB1, 0x69, 0x6D, 0x13, 0xDF, 0xA7, 0x64, 0x0C, - 0xAF, 0xBE, 0xB3, 0x66, 0x1D, 0x0A, 0x51, 0xC0, - 0xE0, 0xA0, 0xD6, 0x38, 0xF3, 0x5B, 0xA2, 0xC1, - 0x56, 0xE5, 0x78, 0xD6, 0xA6, 0xE9, 0x68, 0xC8, - 0x4B, 0x68, 0x6D, 0xC1, 0x39, 0x89, 0x3B, 0xE8, - 0x70, 0x1A, 0xE6, 0x89, 0xB1, 0xDC, 0xAC, 0x9E, - 0x75, 0x0E, 0x6A, 0x55, 0x95, 0xE5, 0xA5, 0x65, - 0x47, 0xB7, 0x81, 0x2D, 0xD5, 0x65, 0xC5, 0xAF, - 0x3F, 0x46, 0x9B, 0x77, 0xE9, 0x58, 0x38, 0x5A, - 0x19, 0xD2, 0xC1, 0xC3, 0x3B, 0x4B, 0x0B, 0xCB, - 0xDA, 0x5E, 0xEB, 0x05, 0xCE, 0x78, 0x80, 0x49, - 0x6B, 0x73, 0xD5, 0x23, 0x73, 0x4A, 0x59, 0x7C, - 0x97, 0x6C, 0x52, 0xBD, 0xC8, 0x7A, 0xFA, 0x32, - 0xB2, 0x74, 0x32, 0x5E, 0x86, 0x36, 0x60, 0xE1, - 0x61, 0xF8, 0xE6, 0x75, 0x3C, 0xED, 0x8E, 0xFF, - 0x22, 0xFA, 0x7D, 0x5B, 0x80, 0x88, 0xE3, 0xE1, - 0x7A, 0xB9, 0x03, 0x42, 0x4A, 0x36, 0x76, 0x74, - 0xAF, 0x6C, 0x1A, 0x56, 0x8E, 0x9C, 0xDF, 0xBF, - 0x96, 0xF6, 0x80, 0xCC, 0x14, 0x26, 0x65, 0x05, - 0x45, 0xBE, 0x08, 0xF4, 0xA4, 0x04, 0xF6, 0x97, - 0x17, 0x5C, 0x62, 0x2E, 0x74, 0xA7, 0x67, 0x67, - 0xC7, 0x1C, 0x88, 0xC7, 0x9F, 0xEF, 0xAF, 0x6F, - 0xAF, 0x56, 0xF0, 0xDE, 0xA2, 0x12, 0x32, 0xD0, - 0x70, 0x89, 0x5C, 0xB0, 0x75, 0x35, 0x63, 0xE2, - 0x62, 0xDF, 0x5D, 0x39, 0x63, 0xD0, 0x97, 0x95, - 0x16, 0xEB, 0x3B, 0x6F, 0xBD, 0xA0, 0xC2, 0xBF, - 0x3C, 0x2A, 0x98, 0x51, 0x56, 0xC4, 0xB9, 0x89, - 0xA1, 0x29, 0x2D, 0xE1, 0xC2, 0xC2, 0x6E, 0xBE, - 0xFC, 0x64, 0xF4, 0x58, 0xA0, 0x10, 0xE2, 0x28, - 0xA4, 0xBF, 0x29, 0x45, 0x2D, 0x04, 0x74, 0x26, - 0xEC, 0x3B, 0x90, 0x0C, 0xD4, 0x64, 0x1E, 0xDF, - 0x5F, 0x84, 0x32, 0x5E, 0x86, 0x36, 0xB6, 0x7B, - 0xF9, 0x42, 0xF0, 0x9D, 0x45, 0xF5, 0x95, 0x55, - 0xD5, 0x0E, 0x14, 0x76, 0xAC, 0x7C, 0x00, 0xC0, - 0x48, 0x93, 0x58, 0x30, 0x96, 0x22, 0x7E, 0xAC, - 0x2E, 0x95, 0xBB, 0xC5, 0x1F, 0xCF, 0x03, 0xD1, - 0x53, 0xE8, 0xC2, 0xBD, 0x67, 0xB7, 0xFF, 0x2C, - 0xAE, 0x15, 0xEB, 0x93, 0x4B, 0x9B, 0xB7, 0x63, - 0xE3, 0x58, 0x9E, 0xE6, 0x3E, 0xEE, 0xBA, 0x7A, - 0xFA, 0x21, 0x97, 0xFB, 0x23, 0x93, 0xF3, 0x33, - 0xB3, 0x68, 0xDE, 0xB2, 0x6A, 0xDA, 0x92, 0x5B, - 0xDB, 0x60, 0xF2, 0x97, 0x4F, 0x9F, 0xEF, 0x1F, - 0x9D, 0x46, 0x70, 0x08, 0xD0, 0x00, 0x30, 0xF1, - 0x71, 0xAA, 0xA0, 0xCB, 0x13, 0xC3, 0x0B, 0xC6, - 0x44, 0xFF, 0x35, 0x5E, 0x86, 0x56, 0x8E, 0x43, - 0xC1, 0x7A, 0xF0, 0x94, 0x4C, 0x9C, 0xEC, 0x22, - 0xA0, 0x1B, 0x65, 0x07, 0xDD, 0x0D, 0x05, 0xD1, - 0x51, 0xEA, 0xD0, 0xB3, 0x69, 0xB9, 0xB1, 0x60, - 0xE2, 0x59, 0x57, 0x33, 0xEB, 0x3B, 0x83, 0x52, - 0xD0, 0x6B, 0xD1, 0xAF, 0x75, 0xA5, 0x45, 0x97, - 0x15, 0xAE, 0xF0, 0x9A, 0x42, 0x92, 0x1E, 0xCD, - 0x4F, 0xF4, 0x02, 0x64, 0xBC, 0x6C, 0x3A, 0xBB, - 0x3B, 0x61, 0xC8, 0xA1, 0xC8, 0x65, 0x00, 0xCC, - 0x16, 0x5C, 0xF4, 0x9D, 0xE7, 0x1C, 0x7C, 0x35, - 0xBC, 0x42, 0xF7, 0x9B, 0xA6, 0x15, 0x75, 0x10, - 0x95, 0x4E, 0x9D, 0xF9, 0x21, 0xF4, 0x90, 0x50, - 0xB5, 0x67, 0xD1, 0x58, 0x80, 0x30, 0xF1, 0x11, - 0x94, 0xFE, 0x69, 0x00, 0xFD, 0xF9, 0xBE, 0x63, - 0x13, 0xC8, 0x48, 0x65, 0xBD, 0x3C, 0x7E, 0xBB, - 0x1A, 0xE2, 0x51, 0x14, 0xDF, 0x72, 0xE2, 0x22, - 0xA2, 0x79, 0xF9, 0xD4, 0x0C, 0x8D, 0xC9, 0x0C, - 0xAD, 0x53, 0xE0, 0xA5, 0xAE, 0x03, 0x93, 0x53, - 0xD3, 0x08, 0x88, 0xA5, 0x7D, 0xFC, 0xBA, 0x7F, - 0xDE, 0x22, 0x91, 0xD4, 0x4F, 0xE2, 0x72, 0xB2, - 0x32, 0xE9, 0x69, 0x44, 0x9C, 0x1D, 0x59, 0x9C, - 0x3D, 0xCE, 0x7D, 0x38, 0x73, 0xDE, 0x4E, 0x8E, - 0x0E, 0xD5, 0x55, 0x78, 0xA0, 0x81, 0xC8, 0x0D, - 0x81, 0x52, 0x66, 0x43, 0x9B, 0x4E, 0x2F, 0xEF, - 0xCE, 0x3E, 0x8D, 0x50, 0xAE, 0x1B, 0xBA, 0x50, - 0xD5, 0xC7, 0x7A, 0xBF, 0x3C, 0x91, 0x01, 0xC1, - 0x41, 0x9A, 0x1A, 0x37, 0xEF, 0x6E, 0x22, 0xE7, - 0x46, 0xB0, 0x03, 0x46, 0x8D, 0x20, 0xB0, 0x70, - 0xF0, 0x2B, 0xAB, 0x86, 0x5E, 0x6F, 0x21, 0xE4, - 0x55, 0xAC, 0x1F, 0x52, 0xA5, 0x10, 0x59, 0xBA, - 0xB3, 0x3B, 0x90, 0x0C, 0xD4, 0x64, 0x32, 0xB3, - 0x33, 0x79, 0xFF, 0x96, 0xCF, 0x4E, 0x2B, 0x62, - 0xCB, 0x75, 0xC3, 0xAF, 0x6A, 0x2A, 0x7C, 0xFD, - 0x7D, 0x07, 0x83, 0xEA, 0x80, 0x90, 0x7C, 0x14, - 0x9E, 0x65, 0xB2, 0xDE, 0x8E, 0x14, 0xCE, 0xB4, - 0xA8, 0x6B, 0xD1, 0xA1, 0x75, 0x48, 0xCA, 0x20, - 0x88, 0x93, 0x05, 0x69, 0x63, 0x9D, 0xF1, 0xF3, - 0x38, 0xC4, 0x57, 0x3A, 0xC6, 0x56, 0xD0, 0x03, - 0x93, 0x68, 0xDE, 0xAF, 0x87, 0x37, 0x57, 0x97, - 0x17, 0xCC, 0x7A, 0x16, 0xCE, 0x7E, 0x1E, 0xDE, - 0x5E, 0x85, 0x32, 0x5E, 0x82, 0x32, 0x9E, 0x4A, - 0xC8, 0x73, + 0x06, 0xFE, 0x93, 0xFF, 0x03, 0xBA, 0x6A, 0xA6, + 0x26, 0x9D, 0x03, 0x66, 0xBE, 0x6E, 0x2A, 0xE3, + 0x63, 0xD8, 0xFE, 0x9B, 0x43, 0x93, 0xD7, 0x03, + 0x83, 0x38, 0x8C, 0xE0, 0x38, 0x88, 0x58, 0x94, + 0x14, 0xAF, 0xC9, 0xA2, 0x7A, 0xCA, 0x96, 0x5E, + 0xDE, 0x65, 0x27, 0x36, 0xEA, 0x3A, 0x4E, 0x82, + 0x02, 0xB9, 0x0F, 0x4B, 0x97, 0x17, 0xF7, 0x1A, + 0x9E, 0x75, 0xC3, 0x8F, 0x53, 0xD3, 0x9F, 0x7F, + 0xFB, 0x10, 0xE6, 0xAA, 0x76, 0xF6, 0x72, 0x93, + 0x17, 0xFC, 0x4A, 0x26, 0xFE, 0x76, 0x2A, 0xEA, + 0x6A, 0x89, 0x3F, 0xF3, 0x2B, 0xA3, 0xFF, 0x9F, + 0x1F, 0xFC, 0x4A, 0x06, 0xDE, 0x56, 0x38, 0xD8, + 0x58, 0xBB, 0x0D, 0x21, 0xF9, 0x71, 0x19, 0x99, + 0x19, 0xFA, 0x4C, 0x40, 0x98, 0x10, 0x78, 0xD8, + 0x58, 0xBB, 0x0D, 0xE1, 0x39, 0xB1, 0xD9, 0x99, + 0x19, 0xFA, 0x6C, 0x7E, 0xA2, 0x72, 0xC6, 0x7D, + 0xF9, 0x42, 0xF4, 0x86, 0x5A, 0xDA, 0xD2, 0x06, + 0x86, 0x3D, 0x6F, 0x08, 0xD0, 0x00, 0xD8, 0x10, + 0x90, 0x2B, 0xFD, 0xB7, 0x6B, 0xBB, 0x67, 0xA0, + 0x20, 0x9B, 0x35, 0x36, 0xEA, 0x3A, 0xA2, 0x0C, + 0x88, 0x33, 0x7D, 0x1A, 0xC2, 0x12, 0x2A, 0xFE, + 0x7E, 0xC5, 0x8C, 0x17, 0x30, 0x7F, 0xE0, 0xCF, + 0xB0, 0x94, 0x4E, 0x36, 0xEE, 0x3E, 0x5E, 0x96, + 0x16, 0xCD, 0x9F, 0xE1, 0x3B, 0xEB, 0x8B, 0x5B, + 0xDB, 0x00, 0x8A, 0xF2, 0x2A, 0xFA, 0x0E, 0xC8, + 0x48, 0xF3, 0x6D, 0x12, 0xC8, 0x18, 0x08, 0xDC, + 0x5C, 0xE7, 0x01, 0x79, 0xA1, 0x71, 0x3D, 0xF4, + 0x74, 0xCF, 0x84, 0x17, 0xCF, 0x7F, 0xE0, 0x20, + 0x5F, 0x7B, 0xFB, 0xD6, 0x0E, 0x1B, 0x65, 0xA5, + 0x00, 0xDC, 0x6A, 0xE3, 0x7E, 0xCE, 0x4B, 0xCE, + 0x68, 0x22, 0xB8, 0xD7, 0xAE, 0x33, 0x50, 0x9C, + 0x14, 0x46, 0xFA, 0x14, 0x85, 0x35, 0x48, 0x78, + 0xF8, 0x23, 0xA3, 0x8E, 0x56, 0x77, 0x39, 0xFA, + 0x76, 0xA5, 0x91, 0xB4, 0x34, 0xE1, 0x4D, 0xA8, + 0x35, 0x1E, 0x9E, 0xB3, 0x6B, 0x6A, 0x3A, 0xF9, + 0xD4, 0x0D, 0x9A, 0xD9, 0x02, 0xF4, 0x94, 0x54, + 0x1F, 0xE6, 0x5B, 0x8C, 0x72, 0xC9, 0xA3, 0xEB, + 0x69, 0x32, 0x04, 0x1C, 0x43, 0x69, 0xF9, 0x3F, + 0xBE, 0x65, 0xF6, 0xFE, 0x03, 0x9E, 0xF4, 0x29, + 0x59, 0x82, 0x02, 0x2F, 0xF7, 0x67, 0x66, 0xA6, + 0x03, 0x22, 0x6B, 0x27, 0x19, 0xBA, 0xCA, 0x2A, + 0xAA, 0x7D, 0xC1, 0x08, 0xF6, 0x63, 0xA2, 0x53, + 0xD0, 0xBA, 0x3E, 0x51, 0xAC, 0x38, 0x70, 0xAD, + 0xDD, 0x06, 0x86, 0xAB, 0x73, 0xF2, 0xA1, 0x62, + 0xC3, 0x2C, 0x99, 0xDC, 0x47, 0xEA, 0x7A, 0xBA, + 0x3A, 0xE1, 0x61, 0x4C, 0x94, 0xA6, 0xC4, 0x09, + 0x85, 0x45, 0x73, 0x9F, 0x43, 0xA5, 0xDD, 0x1A, + 0x96, 0x48, 0xF2, 0x98, 0x02, 0xA0, 0xCE, 0x12, + 0x95, 0x74, 0x86, 0x58, 0x44, 0x75, 0x27, 0xE3, + 0x63, 0x0A, 0xB7, 0xA5, 0xBF, 0x0B, 0x6A, 0x9D, + 0xA6, 0x71, 0xF0, 0x20, 0xE9, 0x64, 0x0F, 0x08, + 0x33, 0xE4, 0x6F, 0x0F, 0x11, 0xA0, 0xC0, 0x37, + 0x8B, 0x54, 0x25, 0xF2, 0x2B, 0xA6, 0xCD, 0xA0, + 0x23, 0x45, 0xF0, 0xF9, 0x99, 0x01, 0xCB, 0x6D, + 0xB7, 0x3F, 0x82, 0x99, 0x0A, 0xFE, 0x2C, 0x28, + 0x29, 0xA4, 0x85, 0x15, 0x60, 0xD5, 0x08, 0xCD, + 0x68, 0x04, 0x9A, 0xFA, 0x39, 0x5B, 0x99, 0x35, + 0x15, 0x0A, 0xFD, 0x51, 0x4F, 0x3F, 0x85, 0x97, + 0xE5, 0x23, 0x17, 0xBB, 0xA7, 0x56, 0xF6, 0xB5, + 0x74, 0x5F, 0x06, 0x9A, 0xA2, 0xF1, 0xB0, 0xFA, + 0x94, 0xBF, 0xC7, 0x38, 0x22, 0xCF, 0x2D, 0xEB, + 0x68, 0xB3, 0xC7, 0x09, 0xBD, 0xC7, 0x65, 0x67, + 0xFB, 0x5D, 0xD1, 0x71, 0x6B, 0xD7, 0xB7, 0xA5, + 0x37, 0xE5, 0x7E, 0x19, 0x16, 0x1A, 0x7B, 0xB7, + 0x15, 0xD3, 0x95, 0xF9, 0x21, 0x91, 0xC7, 0x46, + 0xC6, 0xAC, 0x2F, 0x40, 0x20, 0x9B, 0x77, 0xDC, + 0xFE, 0x84, 0x52, 0x94, 0xE7, 0xF2, 0x28, 0xC8, + 0xE5, 0x3C, 0x2F, 0xEF, 0x12, 0xBF, 0x2F, 0xEF, + 0x6F, 0xB4, 0x34, 0x19, 0xC1, 0xD0, 0x86, 0x45, + 0x74, 0x98, 0x2D, 0x8C, 0x56, 0x43, 0x75, 0x90, + 0xA1, 0x43, 0xF6, 0xBA, 0x48, 0x58, 0x99, 0x61, + 0xE2, 0xF4, 0x40, 0x89, 0x04, 0x91, 0x40, 0xBB, + 0x38, 0xC3, 0x4F, 0x83, 0x99, 0xEA, 0x9A, 0xFB, + 0x41, 0x99, 0x23, 0x4D, 0xBC, 0x0F, 0x46, 0x95, + 0x3C, 0xC4, 0x5B, 0x04, 0xF9, 0x1D, 0x58, 0x29, + 0x94, 0x4C, 0xCA, 0x9C, 0xE4, 0x96, 0x35, 0xE5, + 0xC4, 0x23, 0x96, 0xDF, 0x54, 0xC1, 0xAD, 0x64, + 0xD4, 0x35, 0x23, 0x7D, 0x66, 0xC6, 0xBD, 0xE4, + 0x4D, 0x95, 0x68, 0x37, 0x89, 0xA0, 0x36, 0x5B, + 0xD8, 0xB1, 0xA7, 0x6E, 0x9A, 0x66, 0x23, 0x41, + 0xE9, 0x93, 0x1B, 0x74, 0x1D, 0x92, 0xF1, 0xF3, + 0xB0, 0x4F, 0x5C, 0x60, 0x9D, 0x9C, 0xBD, 0x7E, + 0xCE, 0x2F, 0x39, 0xF4, 0x6C, 0xDF, 0x8D, 0x8E, + 0x2A, 0x3C, 0x89, 0xC0, 0x4A, 0xDF, 0x0E, 0x8D, + 0x0E, 0xE5, 0x69, 0xA5, 0xDC, 0x2E, 0x4D, 0x40, + 0xC3, 0xFD, 0x18, 0x51, 0x38, 0xCD, 0xAE, 0x5E, + 0xE4, 0x9F, 0x88, 0xA0, 0x7B, 0x06, 0x65, 0x40, + 0x92, 0x6C, 0x6B, 0x40, 0x9B, 0x1B, 0x41, 0x21, + 0x00, 0x9D, 0x28, 0x89, 0x52, 0xC7, 0xF5, 0x10, + 0xA0, 0x51, 0x47, 0x36, 0x1E, 0xAE, 0xF8, 0x79, + 0xF9, 0x07, 0x94, 0xF8, 0xA1, 0x58, 0x3B, 0x6A, + 0xD9, 0x01, 0x16, 0x32, 0xE9, 0xF0, 0xC9, 0x80, + 0x09, 0xCF, 0x89, 0xE5, 0x3D, 0x8D, 0xDB, 0x5A, + 0xDA, 0x30, 0xB3, 0xDC, 0x08, 0x9F, 0xC7, 0x04, + 0xD5, 0x44, 0xF1, 0x0F, 0xD4, 0x6C, 0x6E, 0x0F, + 0xFF, 0x2F, 0x10, 0x6A, 0xFA, 0x4C, 0xFD, 0x76, + 0xF5, 0x22, 0xFE, 0x9E, 0x41, 0x73, 0xDA, 0xE6, + 0x70, 0xA3, 0x1F, 0x55, 0xD4, 0x6C, 0xA1, 0x63, + 0x06, 0x1C, 0x8C, 0xCD, 0x1F, 0xB2, 0x22, 0x88, + 0x4B, 0x22, 0x87, 0xE0, 0xAA, 0x1E, 0x7E, 0xA8, + 0x13, 0xC3, 0x13, 0x06, 0xCE, 0xBC, 0xC8, 0xF4, + 0x22, 0x55, 0xE9, 0x27, 0xBC, 0x04, 0x46, 0x85, + 0x08, 0xF3, 0x64, 0x0C, 0xC9, 0x89, 0xE5, 0x2E, + 0x2C, 0xF4, 0x4F, 0xE1, 0x1A, 0x77, 0x00, 0xA8, + 0x27, 0x6E, 0xD5, 0xB9, 0x6D, 0xCF, 0xB9, 0x50, + 0xDE, 0x0E, 0x11, 0xDF, 0x4A, 0xFA, 0xDC, 0x1C, + 0x9C, 0x4B, 0xFF, 0x53, 0xAB, 0x1B, 0xD9, 0x0A, + 0x82, 0x9B, 0x48, 0x84, 0xD0, 0x7A, 0xFF, 0xD5, + 0x73, 0xB5, 0xF3, 0xF5, 0x6E, 0x0C, 0x68, 0xA8, + 0x4E, 0x88, 0x02, 0xD6, 0x2C, 0x31, 0x52, 0x77, + 0x13, 0xEE, 0xF8, 0x74, 0xD8, 0x0E, 0x70, 0x91, + 0xA0, 0x37, 0x82, 0x1C, 0xCF, 0x7F, 0x39, 0xD6, + 0x51, 0xF8, 0x05, 0x69, 0xBD, 0x07, 0xC2, 0x68, + 0xCD, 0x1A, 0x94, 0x6A, 0x91, 0xFF, 0x5F, 0xBF, + 0x3F, 0x76, 0xA5, 0x69, 0x33, 0xC0, 0xA8, 0x2E, + 0xAD, 0x76, 0x62, 0x1D, 0xC2, 0xFE, 0xE4, 0x56, + 0x92, 0x49, 0x5D, 0x22, 0xFD, 0xE8, 0x6E, 0x88, + 0x04, 0xCD, 0x66, 0xFA, 0x90, 0x33, 0x5B, 0xF1, + 0x32, 0xFF, 0x82, 0xE9, 0xF3, 0x47, 0x27, 0x25, + 0x69, 0x49, 0xE9, 0xB9, 0x66, 0x34, 0x57, 0x9A, + 0x98, 0x67, 0x50, 0x2B, 0x9D, 0x7D, 0x8F, 0x42, + 0xC2, 0x0F, 0x30, 0x50, 0x84, 0x26, 0x4D, 0x74, + 0x06, 0x90, 0x26, 0xCC, 0x04, 0xB4, 0x56, 0x5F, + 0x26, 0xAB, 0x85, 0x1C, 0x7C, 0xEE, 0x23, 0xE0, + 0x85, 0x83, 0x13, 0xDF, 0x97, 0x53, 0x38, 0x61, + 0xB7, 0x85, 0x39, 0x59, 0x8A, 0x36, 0x1A, 0x38, + 0x9B, 0x9D, 0xF9, 0x37, 0x9B, 0xF1, 0x42, 0x42, + 0xE2, 0x39, 0x2D, 0x52, 0x82, 0xD0, 0xD5, 0xB5, + 0x47, 0xC1, 0x09, 0xA7, 0x3C, 0x84, 0xF2, 0x78, + 0x0A, 0xDD, 0x05, 0x8B, 0x17, 0xA7, 0x65, 0xB6, + 0x3E, 0x00, 0x69, 0x23, 0x7D, 0x08, 0x97, 0x7A, + 0xFD, 0x2A, 0x93, 0x3F, 0xC7, 0x77, 0xB5, 0x66, + 0xEE, 0xB7, 0x64, 0xA8, 0x66, 0x4C, 0xDF, 0x7A, + 0x24, 0xD9, 0x72, 0xEE, 0x3A, 0x88, 0xAE, 0xA6, + 0xD9, 0xBA, 0x2E, 0xEF, 0x34, 0x21, 0x99, 0x7F, + 0x5F, 0x14, 0xD6, 0xDC, 0x1D, 0x8A, 0xE6, 0x2D, + 0x7F, 0x87, 0xEC, 0x42, 0x38, 0xFC, 0x56, 0x55, + 0x15, 0xEE, 0x58, 0xE6, 0x5B, 0x4B, 0x89, 0x5A, + 0xD2, 0x7B, 0x91, 0x83, 0xE7, 0x0D, 0x07, 0x24, + 0xA8, 0x1E, 0x7A, 0x58, 0x80, 0x92, 0xE1, 0x29, + 0x4C, 0x4D, 0xDD, 0x37, 0xE6, 0x56, 0x3A, 0x85, + 0x09, 0x86, 0x72, 0x5D, 0x8D, 0x57, 0x74, 0x46, + 0x82, 0x59, 0x5D, 0x22, 0xF1, 0xDD, 0xF6, 0x84, + 0x50, 0x77, 0xCD, 0x5B, 0x8F, 0xB7, 0x55, 0xD1, + 0x51, 0x6F, 0x01, 0x4B, 0x01, 0xA5, 0x39, 0x6B, + 0x22, 0x08, 0x2C, 0x14, 0x30, 0xA2, 0xC1, 0x0C, + 0xAC, 0x56, 0xE4, 0x95, 0xBD, 0x20, 0x47, 0x01, + 0x5E, 0x7A, 0x6E, 0x16, 0x32, 0x94, 0x2E, 0x06, + 0x8A, 0xD9, 0xED, 0xC5, 0x1D, 0x1B, 0xC1, 0x11, + 0x9D, 0xBC, 0x2F, 0x95, 0x6B, 0xF9, 0x8D, 0xB1, + 0x13, 0x0A, 0x4D, 0x03, 0x8F, 0xC3, 0xA5, 0xF8, + 0x87, 0x39, 0x5A, 0x10, 0xE5, 0x52, 0x74, 0x48, + 0x37, 0xEC, 0x6C, 0x41, 0x99, 0x78, 0x2D, 0xEE, + 0x36, 0xE8, 0x1C, 0xD0, 0xF8, 0x02, 0x27, 0xD5, + 0x51, 0x0A, 0x9A, 0xD5, 0x3C, 0xAA, 0x89, 0x7A, + 0x9B, 0x0A, 0xBF, 0xA2, 0x31, 0x82, 0xEE, 0x86, + 0x20, 0x98, 0x01, 0x0B, 0x50, 0xFE, 0x92, 0x21, + 0x33, 0xCD, 0xA5, 0x09, 0xF1, 0x41, 0xB3, 0x15, + 0x35, 0xDC, 0x2E, 0xC2, 0xA8, 0x1D, 0x70, 0x12, + 0x95, 0x4E, 0x48, 0x95, 0x49, 0x49, 0x81, 0xD2, + 0xF0, 0x6C, 0xDA, 0xAB, 0x83, 0x2E, 0xBE, 0x72, + 0xE1, 0x7C, 0xCA, 0xA6, 0x72, 0xF1, 0xA3, 0x27, + 0x27, 0xE1, 0xA7, 0xC7, 0x4C, 0x3E, 0x7B, 0x65, + 0x25, 0xDE, 0x68, 0xC6, 0x78, 0x68, 0xCE, 0xFD, + 0x82, 0x59, 0xD9, 0xF4, 0x2C, 0xAD, 0x80, 0x43, + 0xE2, 0x77, 0xC2, 0x87, 0x4C, 0xE1, 0x71, 0xB1, + 0x31, 0xEA, 0x6A, 0x47, 0x9F, 0xBE, 0xEB, 0x28, + 0x30, 0xE2, 0xD8, 0x1D, 0x67, 0xFE, 0x43, 0x23, + 0x03, 0xCC, 0x5C, 0x0A, 0xD0, 0x05, 0x22, 0xC3, + 0x5E, 0x75, 0xF5, 0xD8, 0x00, 0x11, 0x21, 0xE2, + 0x43, 0xD1, 0x64, 0x39, 0xD2, 0x61, 0x90, 0x1F, + 0x9C, 0xC6, 0x21, 0x4E, 0x1F, 0x86, 0xCF, 0x0C, + 0x25, 0xA7, 0x0C, 0x90, 0x48, 0xF8, 0xAE, 0x2F, + 0xAF, 0x55, 0xB1, 0xDE, 0x8E, 0x1C, 0xBB, 0x13, + 0x8E, 0xF4, 0x11, 0x7E, 0x43, 0xBE, 0xF6, 0xA7, + 0x73, 0xAB, 0xDC, 0xE5, 0x3E, 0x3F, 0x09, 0xCA, + 0xE2, 0x1B, 0x15, 0x72, 0x6A, 0x70, 0x00, 0x50, + 0x4A, 0x81, 0x87, 0x71, 0x3A, 0x13, 0x51, 0xB4, + 0xFA, 0x04, 0xAF, 0x33, 0xEB, 0x5B, 0x0D, 0x8C, + 0x0C, 0x76, 0x93, 0xFC, 0x41, 0xB6, 0xFE, 0xDF, + 0x08, 0xD0, 0x27, 0x78, 0xA3, 0x22, 0x10, 0xD3, + 0x5F, 0x88, 0xE6, 0xA9, 0x80, 0x66, 0x05, 0x72, + 0x9F, 0x66, 0x6D, 0x0E, 0x1E, 0xAA, 0x03, 0xCC, + 0xE1, 0x38, 0x0F, 0x3B, 0xE0, 0xB0, 0x4D, 0xAD, + 0xB4, 0x4C, 0x73, 0x1B, 0xA6, 0x13, 0x73, 0x02, + 0xDB, 0x03, 0x1D, 0x52, 0x86, 0x34, 0xE4, 0x8E, + 0x2E, 0x5C, 0xC9, 0xB8, 0x90, 0x2C, 0x47, 0x41, + 0x37, 0x13, 0x93, 0xBE, 0x66, 0xCA, 0x62, 0x25, + 0x37, 0xE8, 0x7F, 0x49, 0x92, 0x3F, 0xAF, 0xC2, + 0x40, 0x3E, 0x4E, 0x07, 0xF2, 0x48, 0x35, 0x05, + 0x85, 0x5E, 0xDE, 0xF3, 0x2B, 0xDA, 0xE1, 0x22, + 0x93, 0x14, 0xA1, 0x45, 0xD9, 0xE0, 0x02, 0xFB, + 0x3F, 0xF9, 0xBF, 0xD3, 0x0B, 0xBB, 0xED, 0x6C, + 0xEC, 0x95, 0xE1, 0x9D, 0x60, 0xAB, 0xEB, 0xBA, + 0x61, 0xB9, 0x87, 0x69, 0x38, 0xC1, 0xBC, 0x8C, + 0x0C, 0xD7, 0x57, 0x7A, 0xA2, 0xAF, 0xCD, 0x2C, + 0xF1, 0x29, 0xB7, 0xD9, 0x0D, 0x31, 0xDA, 0xB8, + 0x1D, 0x8C, 0x12, 0xFF, 0x79, 0xCA, 0x38, 0x3A, + 0xAA, 0xE8, 0x0C, 0xF9, 0x63, 0x5A, 0x58, 0x14, + 0x97, 0x75, 0x51, 0x20, 0x08, 0xB8, 0xEE, 0x6F, + 0xEF, 0x05, 0xEE, 0x81, 0x61, 0xD2, 0x00, 0xD3, + 0x4B, 0x9C, 0x36, 0x5D, 0x6E, 0xC4, 0x35, 0xAA, + 0x29, 0x32, 0x2F, 0x63, 0x19, 0xFA, 0x82, 0x82, + 0x22, 0xF9, 0xD7, 0xB2, 0xE8, 0x4B, 0x2D, 0x4F, + 0x0C, 0xC7, 0xEB, 0x0F, 0x5E, 0x9D, 0x18, 0xAB, + 0x0B, 0x62, 0xC7, 0xB3, 0x7C, 0x27, 0x49, 0x31, + 0x22, 0x75, 0x58, 0xBC, 0x6F, 0x72, 0x10, 0x30, + 0xB8, 0x63, 0xF8, 0x9E, 0x5B, 0x1B, 0x77, 0xB5, + 0x28, 0x03, 0x83, 0xAE, 0x76, 0xF7, 0xCA, 0x09, + 0xB1, 0x69, 0x6D, 0x13, 0xDF, 0xA7, 0x64, 0x0C, + 0xAF, 0xBE, 0xB3, 0x66, 0x1D, 0x0A, 0x51, 0xC0, + 0xE0, 0xA0, 0xD6, 0x38, 0xF3, 0x5B, 0xA2, 0xC1, + 0x56, 0xE5, 0x78, 0xD6, 0xA6, 0xE9, 0x68, 0xC8, + 0x4B, 0x68, 0x6D, 0xC1, 0x39, 0x89, 0x3B, 0xE8, + 0x70, 0x1A, 0xE6, 0x89, 0xB1, 0xDC, 0xAC, 0x9E, + 0x75, 0x0E, 0x6A, 0x55, 0x95, 0xE5, 0xA5, 0x65, + 0x47, 0xB7, 0x81, 0x2D, 0xD5, 0x65, 0xC5, 0xAF, + 0x3F, 0x46, 0x9B, 0x77, 0xE9, 0x58, 0x38, 0x5A, + 0x19, 0xD2, 0xC1, 0xC3, 0x3B, 0x4B, 0x0B, 0xCB, + 0xDA, 0x5E, 0xEB, 0x05, 0xCE, 0x78, 0x80, 0x49, + 0x6B, 0x73, 0xD5, 0x23, 0x73, 0x4A, 0x59, 0x7C, + 0x97, 0x6C, 0x52, 0xBD, 0xC8, 0x7A, 0xFA, 0x32, + 0xB2, 0x74, 0x32, 0x5E, 0x86, 0x36, 0x60, 0xE1, + 0x61, 0xF8, 0xE6, 0x75, 0x3C, 0xED, 0x8E, 0xFF, + 0x22, 0xFA, 0x7D, 0x5B, 0x80, 0x88, 0xE3, 0xE1, + 0x7A, 0xB9, 0x03, 0x42, 0x4A, 0x36, 0x76, 0x74, + 0xAF, 0x6C, 0x1A, 0x56, 0x8E, 0x9C, 0xDF, 0xBF, + 0x96, 0xF6, 0x80, 0xCC, 0x14, 0x26, 0x65, 0x05, + 0x45, 0xBE, 0x08, 0xF4, 0xA4, 0x04, 0xF6, 0x97, + 0x17, 0x5C, 0x62, 0x2E, 0x74, 0xA7, 0x67, 0x67, + 0xC7, 0x1C, 0x88, 0xC7, 0x9F, 0xEF, 0xAF, 0x6F, + 0xAF, 0x56, 0xF0, 0xDE, 0xA2, 0x12, 0x32, 0xD0, + 0x70, 0x89, 0x5C, 0xB0, 0x75, 0x35, 0x63, 0xE2, + 0x62, 0xDF, 0x5D, 0x39, 0x63, 0xD0, 0x97, 0x95, + 0x16, 0xEB, 0x3B, 0x6F, 0xBD, 0xA0, 0xC2, 0xBF, + 0x3C, 0x2A, 0x98, 0x51, 0x56, 0xC4, 0xB9, 0x89, + 0xA1, 0x29, 0x2D, 0xE1, 0xC2, 0xC2, 0x6E, 0xBE, + 0xFC, 0x64, 0xF4, 0x58, 0xA0, 0x10, 0xE2, 0x28, + 0xA4, 0xBF, 0x29, 0x45, 0x2D, 0x04, 0x74, 0x26, + 0xEC, 0x3B, 0x90, 0x0C, 0xD4, 0x64, 0x1E, 0xDF, + 0x5F, 0x84, 0x32, 0x5E, 0x86, 0x36, 0xB6, 0x7B, + 0xF9, 0x42, 0xF0, 0x9D, 0x45, 0xF5, 0x95, 0x55, + 0xD5, 0x0E, 0x14, 0x76, 0xAC, 0x7C, 0x00, 0xC0, + 0x48, 0x93, 0x58, 0x30, 0x96, 0x22, 0x7E, 0xAC, + 0x2E, 0x95, 0xBB, 0xC5, 0x1F, 0xCF, 0x03, 0xD1, + 0x53, 0xE8, 0xC2, 0xBD, 0x67, 0xB7, 0xFF, 0x2C, + 0xAE, 0x15, 0xEB, 0x93, 0x4B, 0x9B, 0xB7, 0x63, + 0xE3, 0x58, 0x9E, 0xE6, 0x3E, 0xEE, 0xBA, 0x7A, + 0xFA, 0x21, 0x97, 0xFB, 0x23, 0x93, 0xF3, 0x33, + 0xB3, 0x68, 0xDE, 0xB2, 0x6A, 0xDA, 0x92, 0x5B, + 0xDB, 0x60, 0xF2, 0x97, 0x4F, 0x9F, 0xEF, 0x1F, + 0x9D, 0x46, 0x70, 0x08, 0xD0, 0x00, 0x30, 0xF1, + 0x71, 0xAA, 0xA0, 0xCB, 0x13, 0xC3, 0x0B, 0xC6, + 0x44, 0xFF, 0x35, 0x5E, 0x86, 0x56, 0x8E, 0x43, + 0xC1, 0x7A, 0xF0, 0x94, 0x4C, 0x9C, 0xEC, 0x22, + 0xA0, 0x1B, 0x65, 0x07, 0xDD, 0x0D, 0x05, 0xD1, + 0x51, 0xEA, 0xD0, 0xB3, 0x69, 0xB9, 0xB1, 0x60, + 0xE2, 0x59, 0x57, 0x33, 0xEB, 0x3B, 0x83, 0x52, + 0xD0, 0x6B, 0xD1, 0xAF, 0x75, 0xA5, 0x45, 0x97, + 0x15, 0xAE, 0xF0, 0x9A, 0x42, 0x92, 0x1E, 0xCD, + 0x4F, 0xF4, 0x02, 0x64, 0xBC, 0x6C, 0x3A, 0xBB, + 0x3B, 0x61, 0xC8, 0xA1, 0xC8, 0x65, 0x00, 0xCC, + 0x16, 0x5C, 0xF4, 0x9D, 0xE7, 0x1C, 0x7C, 0x35, + 0xBC, 0x42, 0xF7, 0x9B, 0xA6, 0x15, 0x75, 0x10, + 0x95, 0x4E, 0x9D, 0xF9, 0x21, 0xF4, 0x90, 0x50, + 0xB5, 0x67, 0xD1, 0x58, 0x80, 0x30, 0xF1, 0x11, + 0x94, 0xFE, 0x69, 0x00, 0xFD, 0xF9, 0xBE, 0x63, + 0x13, 0xC8, 0x48, 0x65, 0xBD, 0x3C, 0x7E, 0xBB, + 0x1A, 0xE2, 0x51, 0x14, 0xDF, 0x72, 0xE2, 0x22, + 0xA2, 0x79, 0xF9, 0xD4, 0x0C, 0x8D, 0xC9, 0x0C, + 0xAD, 0x53, 0xE0, 0xA5, 0xAE, 0x03, 0x93, 0x53, + 0xD3, 0x08, 0x88, 0xA5, 0x7D, 0xFC, 0xBA, 0x7F, + 0xDE, 0x22, 0x91, 0xD4, 0x4F, 0xE2, 0x72, 0xB2, + 0x32, 0xE9, 0x69, 0x44, 0x9C, 0x1D, 0x59, 0x9C, + 0x3D, 0xCE, 0x7D, 0x38, 0x73, 0xDE, 0x4E, 0x8E, + 0x0E, 0xD5, 0x55, 0x78, 0xA0, 0x81, 0xC8, 0x0D, + 0x81, 0x52, 0x66, 0x43, 0x9B, 0x4E, 0x2F, 0xEF, + 0xCE, 0x3E, 0x8D, 0x50, 0xAE, 0x1B, 0xBA, 0x50, + 0xD5, 0xC7, 0x7A, 0xBF, 0x3C, 0x91, 0x01, 0xC1, + 0x41, 0x9A, 0x1A, 0x37, 0xEF, 0x6E, 0x22, 0xE7, + 0x46, 0xB0, 0x03, 0x46, 0x8D, 0x20, 0xB0, 0x70, + 0xF0, 0x2B, 0xAB, 0x86, 0x5E, 0x6F, 0x21, 0xE4, + 0x55, 0xAC, 0x1F, 0x52, 0xA5, 0x10, 0x59, 0xBA, + 0xB3, 0x3B, 0x90, 0x0C, 0xD4, 0x64, 0x32, 0xB3, + 0x33, 0x79, 0xFF, 0x96, 0xCF, 0x4E, 0x2B, 0x62, + 0xCB, 0x75, 0xC3, 0xAF, 0x6A, 0x2A, 0x7C, 0xFD, + 0x7D, 0x07, 0x83, 0xEA, 0x80, 0x90, 0x7C, 0x14, + 0x9E, 0x65, 0xB2, 0xDE, 0x8E, 0x14, 0xCE, 0xB4, + 0xA8, 0x6B, 0xD1, 0xA1, 0x75, 0x48, 0xCA, 0x20, + 0x88, 0x93, 0x05, 0x69, 0x63, 0x9D, 0xF1, 0xF3, + 0x38, 0xC4, 0x57, 0x3A, 0xC6, 0x56, 0xD0, 0x03, + 0x93, 0x68, 0xDE, 0xAF, 0x87, 0x37, 0x57, 0x97, + 0x17, 0xCC, 0x7A, 0x16, 0xCE, 0x7E, 0x1E, 0xDE, + 0x5E, 0x85, 0x32, 0x5E, 0x82, 0x32, 0x9E, 0x4A, + 0xC8, 0x73, }; static unsigned char vfs5011_init_04[] = { /* 2221 B */ - 0x02, 0x20, 0x01, 0x01, 0x00, 0x03, 0x00, 0x09, - 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, - 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xAD, 0x01, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, - 0x20, 0x04, 0x30, 0xAD, 0x01, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, - 0xAD, 0x01, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x4C, 0x20, 0x04, 0x30, 0xFF, 0x03, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, - 0x04, 0x30, 0x00, 0x00, 0x50, 0x03, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x54, 0x20, 0x04, 0x30, 0x01, - 0x3E, 0x02, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x00, 0x21, 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x08, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x0C, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x10, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x14, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x1C, 0x21, 0x04, 0x30, 0x12, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x20, 0x21, 0x04, 0x30, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x40, 0x21, 0x04, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x44, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x48, - 0x21, 0x04, 0x30, 0x10, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x4C, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x50, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x21, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x58, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x5C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x60, 0x21, 0x04, - 0x30, 0x0F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x80, 0x21, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x84, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x88, 0x21, 0x04, 0x30, - 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x8C, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x90, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x94, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x98, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x9C, 0x21, 0x04, - 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x0F, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC0, - 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xC4, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xC8, 0x21, 0x04, 0x30, 0x10, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xCC, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xD0, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xD4, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xD8, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xDC, 0x21, 0x04, 0x30, 0x1F, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xE0, - 0x21, 0x04, 0x30, 0x0F, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xA0, 0x20, 0x04, 0x30, - 0xEF, 0xE1, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xA4, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA8, 0x20, - 0x04, 0x30, 0xFE, 0x21, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xC4, 0x20, 0x04, 0x30, 0x47, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, - 0x00, 0x00, 0x38, 0x00, 0x08, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, - 0x00, 0x12, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, - 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, - 0x0C, 0x8A, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, - 0xFF, 0xF9, 0x87, 0x20, 0x83, 0x48, 0x84, 0x20, - 0x83, 0x48, 0x84, 0x20, 0x83, 0x48, 0x84, 0x20, - 0x83, 0x48, 0x84, 0x20, 0x83, 0x48, 0x84, 0x20, - 0x83, 0x48, 0x84, 0x20, 0x83, 0x48, 0x84, 0x20, - 0x83, 0x48, 0x84, 0x20, 0x83, 0x48, 0x84, 0x20, - 0x83, 0x48, 0x84, 0x20, 0x85, 0x48, 0x04, 0x20, - 0x87, 0x48, 0x04, 0x20, 0x89, 0x48, 0x04, 0x20, - 0x8B, 0x48, 0x04, 0x20, 0x8D, 0x48, 0x04, 0x20, - 0x8F, 0x48, 0x04, 0x20, 0x91, 0x48, 0x04, 0x20, - 0x93, 0x48, 0x04, 0x20, 0x95, 0x48, 0x04, 0x20, - 0x97, 0x48, 0x04, 0x20, 0x99, 0x48, 0x04, 0x20, - 0x9B, 0x48, 0x04, 0x20, 0x9D, 0x48, 0x04, 0x20, - 0x9F, 0x48, 0x04, 0x20, 0xA1, 0x48, 0x04, 0x20, - 0xA3, 0x48, 0x04, 0x20, 0xA3, 0x48, 0x04, 0x00, - 0x85, 0x5A, 0x04, 0x20, 0x87, 0x5A, 0x04, 0x20, - 0x89, 0x5A, 0x04, 0x20, 0x8B, 0x5A, 0x04, 0x20, - 0x8D, 0x5A, 0x04, 0x20, 0x8F, 0x5A, 0x04, 0x20, - 0x91, 0x5A, 0x04, 0x20, 0x93, 0x5A, 0x04, 0x20, - 0x95, 0x5A, 0x04, 0x20, 0x97, 0x5A, 0x04, 0x20, - 0x99, 0x5A, 0x04, 0x20, 0x9B, 0x5A, 0x04, 0x20, - 0x9D, 0x5A, 0x04, 0x20, 0x9F, 0x5A, 0x04, 0x20, - 0xA1, 0x5A, 0x04, 0x20, 0xA3, 0x5A, 0x04, 0x20, - 0xA3, 0x5A, 0x04, 0x00, 0x85, 0x6C, 0x04, 0x20, - 0x87, 0x6C, 0x04, 0x20, 0x89, 0x6C, 0x04, 0x20, - 0x8B, 0x6C, 0x04, 0x20, 0x8D, 0x6C, 0x04, 0x20, - 0x8F, 0x6C, 0x04, 0x20, 0x91, 0x6C, 0x04, 0x20, - 0x93, 0x6C, 0x04, 0x20, 0x95, 0x6C, 0x04, 0x20, - 0x97, 0x6C, 0x04, 0x20, 0x99, 0x6C, 0x04, 0x20, - 0x9B, 0x6C, 0x04, 0x20, 0x9D, 0x6C, 0x04, 0x20, - 0x9F, 0x6C, 0x04, 0x20, 0xA1, 0x6C, 0x04, 0x20, - 0xA3, 0x6C, 0x04, 0x20, 0xA3, 0x6C, 0x04, 0x00, - 0x86, 0x48, 0x04, 0x20, 0x88, 0x48, 0x04, 0x20, - 0x8A, 0x48, 0x04, 0x20, 0x8C, 0x48, 0x04, 0x20, - 0x8E, 0x48, 0x04, 0x20, 0x90, 0x48, 0x04, 0x20, - 0x92, 0x48, 0x04, 0x20, 0xF7, 0x48, 0x04, 0x20, - 0xF9, 0x48, 0x04, 0x20, 0xFB, 0x48, 0x04, 0x20, - 0xFD, 0x48, 0x04, 0x20, 0xFF, 0x48, 0x04, 0x20, - 0x01, 0x49, 0x04, 0x20, 0x03, 0x49, 0x04, 0x20, - 0x05, 0x49, 0x04, 0x20, 0x07, 0x49, 0x04, 0x20, - 0x07, 0x49, 0x04, 0x00, 0x86, 0x5A, 0x04, 0x20, - 0x88, 0x5A, 0x04, 0x20, 0x8A, 0x5A, 0x04, 0x20, - 0x8C, 0x5A, 0x04, 0x20, 0x8E, 0x5A, 0x04, 0x20, - 0x90, 0x5A, 0x04, 0x20, 0x92, 0x5A, 0x04, 0x20, - 0xF7, 0x5A, 0x04, 0x20, 0xF9, 0x5A, 0x04, 0x20, - 0xFB, 0x5A, 0x04, 0x20, 0xFD, 0x5A, 0x04, 0x20, - 0xFF, 0x5A, 0x04, 0x20, 0x01, 0x5B, 0x04, 0x20, - 0x03, 0x5B, 0x04, 0x20, 0x05, 0x5B, 0x04, 0x20, - 0x07, 0x5B, 0x04, 0x20, 0x07, 0x5B, 0x04, 0x00, - 0x86, 0x6C, 0x04, 0x20, 0x88, 0x6C, 0x04, 0x20, - 0x8A, 0x6C, 0x04, 0x20, 0x8C, 0x6C, 0x04, 0x20, - 0x8E, 0x6C, 0x04, 0x20, 0x90, 0x6C, 0x04, 0x20, - 0x92, 0x6C, 0x04, 0x20, 0xF7, 0x6C, 0x04, 0x20, - 0xF9, 0x6C, 0x04, 0x20, 0xFB, 0x6C, 0x04, 0x20, - 0xFD, 0x6C, 0x04, 0x20, 0xFF, 0x6C, 0x04, 0x20, - 0x01, 0x6D, 0x04, 0x20, 0x03, 0x6D, 0x04, 0x20, - 0x05, 0x6D, 0x04, 0x20, 0x07, 0x6D, 0x04, 0x20, - 0x07, 0x6D, 0x04, 0x00, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, - 0x83, 0x68, 0x84, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x51, 0x09, - 0x10, 0x03, 0x51, 0x09, 0x03, 0x00, 0x09, 0x00, - 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, - 0x04, 0x15, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x20, 0x28, 0x00, 0x00, + 0x02, 0x20, 0x01, 0x01, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, + 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xAD, 0x01, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, + 0x20, 0x04, 0x30, 0xAD, 0x01, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, + 0xAD, 0x01, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x4C, 0x20, 0x04, 0x30, 0xFF, 0x03, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, + 0x04, 0x30, 0x00, 0x00, 0x50, 0x03, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x54, 0x20, 0x04, 0x30, 0x01, + 0x3E, 0x02, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x00, 0x21, 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x08, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x0C, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x10, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x14, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x1C, 0x21, 0x04, 0x30, 0x12, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x20, 0x21, 0x04, 0x30, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x40, 0x21, 0x04, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x44, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x48, + 0x21, 0x04, 0x30, 0x10, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x4C, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x50, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x21, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x58, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x5C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x60, 0x21, 0x04, + 0x30, 0x0F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x80, 0x21, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x84, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x88, 0x21, 0x04, 0x30, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x8C, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x90, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x94, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x98, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x9C, 0x21, 0x04, + 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x0F, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC0, + 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xC4, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xC8, 0x21, 0x04, 0x30, 0x10, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xCC, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xD0, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xD4, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xD8, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xDC, 0x21, 0x04, 0x30, 0x1F, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xE0, + 0x21, 0x04, 0x30, 0x0F, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xA0, 0x20, 0x04, 0x30, + 0xEF, 0xE1, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xA4, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA8, 0x20, + 0x04, 0x30, 0xFE, 0x21, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xC4, 0x20, 0x04, 0x30, 0x47, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, + 0x00, 0x00, 0x38, 0x00, 0x08, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, + 0x00, 0x12, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, + 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, + 0x0C, 0x8A, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, + 0xFF, 0xF9, 0x87, 0x20, 0x83, 0x48, 0x84, 0x20, + 0x83, 0x48, 0x84, 0x20, 0x83, 0x48, 0x84, 0x20, + 0x83, 0x48, 0x84, 0x20, 0x83, 0x48, 0x84, 0x20, + 0x83, 0x48, 0x84, 0x20, 0x83, 0x48, 0x84, 0x20, + 0x83, 0x48, 0x84, 0x20, 0x83, 0x48, 0x84, 0x20, + 0x83, 0x48, 0x84, 0x20, 0x85, 0x48, 0x04, 0x20, + 0x87, 0x48, 0x04, 0x20, 0x89, 0x48, 0x04, 0x20, + 0x8B, 0x48, 0x04, 0x20, 0x8D, 0x48, 0x04, 0x20, + 0x8F, 0x48, 0x04, 0x20, 0x91, 0x48, 0x04, 0x20, + 0x93, 0x48, 0x04, 0x20, 0x95, 0x48, 0x04, 0x20, + 0x97, 0x48, 0x04, 0x20, 0x99, 0x48, 0x04, 0x20, + 0x9B, 0x48, 0x04, 0x20, 0x9D, 0x48, 0x04, 0x20, + 0x9F, 0x48, 0x04, 0x20, 0xA1, 0x48, 0x04, 0x20, + 0xA3, 0x48, 0x04, 0x20, 0xA3, 0x48, 0x04, 0x00, + 0x85, 0x5A, 0x04, 0x20, 0x87, 0x5A, 0x04, 0x20, + 0x89, 0x5A, 0x04, 0x20, 0x8B, 0x5A, 0x04, 0x20, + 0x8D, 0x5A, 0x04, 0x20, 0x8F, 0x5A, 0x04, 0x20, + 0x91, 0x5A, 0x04, 0x20, 0x93, 0x5A, 0x04, 0x20, + 0x95, 0x5A, 0x04, 0x20, 0x97, 0x5A, 0x04, 0x20, + 0x99, 0x5A, 0x04, 0x20, 0x9B, 0x5A, 0x04, 0x20, + 0x9D, 0x5A, 0x04, 0x20, 0x9F, 0x5A, 0x04, 0x20, + 0xA1, 0x5A, 0x04, 0x20, 0xA3, 0x5A, 0x04, 0x20, + 0xA3, 0x5A, 0x04, 0x00, 0x85, 0x6C, 0x04, 0x20, + 0x87, 0x6C, 0x04, 0x20, 0x89, 0x6C, 0x04, 0x20, + 0x8B, 0x6C, 0x04, 0x20, 0x8D, 0x6C, 0x04, 0x20, + 0x8F, 0x6C, 0x04, 0x20, 0x91, 0x6C, 0x04, 0x20, + 0x93, 0x6C, 0x04, 0x20, 0x95, 0x6C, 0x04, 0x20, + 0x97, 0x6C, 0x04, 0x20, 0x99, 0x6C, 0x04, 0x20, + 0x9B, 0x6C, 0x04, 0x20, 0x9D, 0x6C, 0x04, 0x20, + 0x9F, 0x6C, 0x04, 0x20, 0xA1, 0x6C, 0x04, 0x20, + 0xA3, 0x6C, 0x04, 0x20, 0xA3, 0x6C, 0x04, 0x00, + 0x86, 0x48, 0x04, 0x20, 0x88, 0x48, 0x04, 0x20, + 0x8A, 0x48, 0x04, 0x20, 0x8C, 0x48, 0x04, 0x20, + 0x8E, 0x48, 0x04, 0x20, 0x90, 0x48, 0x04, 0x20, + 0x92, 0x48, 0x04, 0x20, 0xF7, 0x48, 0x04, 0x20, + 0xF9, 0x48, 0x04, 0x20, 0xFB, 0x48, 0x04, 0x20, + 0xFD, 0x48, 0x04, 0x20, 0xFF, 0x48, 0x04, 0x20, + 0x01, 0x49, 0x04, 0x20, 0x03, 0x49, 0x04, 0x20, + 0x05, 0x49, 0x04, 0x20, 0x07, 0x49, 0x04, 0x20, + 0x07, 0x49, 0x04, 0x00, 0x86, 0x5A, 0x04, 0x20, + 0x88, 0x5A, 0x04, 0x20, 0x8A, 0x5A, 0x04, 0x20, + 0x8C, 0x5A, 0x04, 0x20, 0x8E, 0x5A, 0x04, 0x20, + 0x90, 0x5A, 0x04, 0x20, 0x92, 0x5A, 0x04, 0x20, + 0xF7, 0x5A, 0x04, 0x20, 0xF9, 0x5A, 0x04, 0x20, + 0xFB, 0x5A, 0x04, 0x20, 0xFD, 0x5A, 0x04, 0x20, + 0xFF, 0x5A, 0x04, 0x20, 0x01, 0x5B, 0x04, 0x20, + 0x03, 0x5B, 0x04, 0x20, 0x05, 0x5B, 0x04, 0x20, + 0x07, 0x5B, 0x04, 0x20, 0x07, 0x5B, 0x04, 0x00, + 0x86, 0x6C, 0x04, 0x20, 0x88, 0x6C, 0x04, 0x20, + 0x8A, 0x6C, 0x04, 0x20, 0x8C, 0x6C, 0x04, 0x20, + 0x8E, 0x6C, 0x04, 0x20, 0x90, 0x6C, 0x04, 0x20, + 0x92, 0x6C, 0x04, 0x20, 0xF7, 0x6C, 0x04, 0x20, + 0xF9, 0x6C, 0x04, 0x20, 0xFB, 0x6C, 0x04, 0x20, + 0xFD, 0x6C, 0x04, 0x20, 0xFF, 0x6C, 0x04, 0x20, + 0x01, 0x6D, 0x04, 0x20, 0x03, 0x6D, 0x04, 0x20, + 0x05, 0x6D, 0x04, 0x20, 0x07, 0x6D, 0x04, 0x20, + 0x07, 0x6D, 0x04, 0x00, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x83, 0x68, 0x84, 0x20, + 0x83, 0x68, 0x84, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x51, 0x09, + 0x10, 0x03, 0x51, 0x09, 0x03, 0x00, 0x09, 0x00, + 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x04, 0x15, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x28, 0x00, 0x00, }; static unsigned char vfs5011_init_05[] = { /* 2770 B */ - 0x06, 0x6B, 0x06, 0x6A, 0x76, 0xCC, 0x1C, 0xD0, - 0x50, 0xEB, 0x75, 0x10, 0xC8, 0x18, 0x5C, 0x95, - 0x15, 0xAE, 0xA8, 0xC8, 0x10, 0xC0, 0xB0, 0x7A, - 0xFA, 0x21, 0x96, 0xFA, 0x22, 0x92, 0xAE, 0x78, - 0xF8, 0x43, 0x05, 0x6E, 0xB6, 0x66, 0x62, 0xD5, - 0x51, 0xEA, 0xF0, 0xE5, 0x39, 0xE9, 0xA1, 0x19, - 0x9D, 0x26, 0x80, 0xE0, 0x38, 0xE8, 0x1C, 0xCA, - 0x4A, 0xF1, 0xBF, 0xD8, 0x00, 0xD0, 0x34, 0xD9, - 0x5D, 0xB6, 0x00, 0xF2, 0x2A, 0xA2, 0xAA, 0x7C, - 0xFC, 0x47, 0xDD, 0xB8, 0x60, 0xB0, 0xD0, 0xEF, - 0x6F, 0xB4, 0x46, 0x2C, 0xF4, 0x24, 0xBB, 0x7B, - 0x04, 0x20, 0x96, 0xC5, 0x1D, 0xAD, 0x32, 0x32, - 0x4D, 0x69, 0xDF, 0xA0, 0x7A, 0xAA, 0xB6, 0x60, - 0xE0, 0x5B, 0x89, 0xF6, 0x2C, 0xFC, 0x14, 0xC2, - 0x42, 0xF9, 0x23, 0x59, 0x81, 0x51, 0x31, 0xEF, - 0x6B, 0x80, 0x36, 0x52, 0x8A, 0x3A, 0x5A, 0x64, - 0x1B, 0xF7, 0xBD, 0xD4, 0x0C, 0xDC, 0xBC, 0x54, - 0xD0, 0x3B, 0x0D, 0x4C, 0x90, 0x10, 0x70, 0x90, - 0x14, 0xFF, 0x65, 0x29, 0xF5, 0x75, 0x55, 0xB5, - 0x31, 0xDA, 0x88, 0xC5, 0x19, 0x99, 0xF9, 0x39, - 0xB9, 0x5A, 0xD0, 0xBC, 0x64, 0xEC, 0x8C, 0xEC, - 0x6C, 0x8F, 0x05, 0xC9, 0x11, 0x99, 0xF9, 0x19, - 0x99, 0x7A, 0xC2, 0x8E, 0x56, 0xDE, 0xBE, 0x3E, - 0xBE, 0x5D, 0xE3, 0xCF, 0x17, 0x9F, 0xFF, 0x5F, - 0xDF, 0x3C, 0x82, 0x8E, 0x56, 0xDE, 0xBE, 0xFE, - 0x7E, 0x9D, 0x23, 0xCF, 0x17, 0x9F, 0xC9, 0x48, - 0xC8, 0xF6, 0x07, 0x4D, 0x04, 0x98, 0xFB, 0x9A, - 0x37, 0xEF, 0x55, 0x31, 0x60, 0xDA, 0x38, 0xB1, - 0x31, 0xF7, 0xB1, 0xDD, 0x05, 0xB5, 0xE3, 0x62, - 0xE2, 0x19, 0xCE, 0xA2, 0x5F, 0x11, 0x8E, 0x6E, - 0x08, 0xC0, 0x66, 0x2A, 0xF2, 0x4E, 0x24, 0x01, - 0xAA, 0x54, 0x43, 0x01, 0xDA, 0xDB, 0x94, 0x57, - 0xB2, 0x40, 0xDE, 0xAF, 0x87, 0x37, 0x61, 0xE0, - 0x60, 0x16, 0xA2, 0x4F, 0xA7, 0x14, 0x78, 0xB1, - 0x3A, 0x59, 0x78, 0x0C, 0xC5, 0x54, 0x05, 0xC6, - 0x8E, 0x57, 0xEA, 0x3D, 0x25, 0x55, 0x41, 0x46, - 0xDC, 0x0C, 0x71, 0x3F, 0x81, 0x3A, 0xAA, 0x8F, - 0x6B, 0x95, 0x0E, 0x68, 0xAD, 0xED, 0x90, 0xA0, - 0x20, 0xFB, 0x7B, 0x56, 0x8E, 0xAF, 0xFC, 0x3F, - 0x9E, 0x70, 0xC5, 0x98, 0x72, 0xC1, 0x20, 0xD4, - 0x57, 0x05, 0x60, 0x2E, 0x95, 0x35, 0xCC, 0x9F, - 0x02, 0x29, 0xA9, 0x84, 0x5C, 0xDD, 0x8B, 0x48, - 0xDE, 0xA7, 0x17, 0x1E, 0x49, 0xDC, 0x94, 0x57, - 0x75, 0xCC, 0x58, 0x15, 0xFA, 0x49, 0xB5, 0x7F, - 0x77, 0x96, 0xB2, 0xC4, 0x08, 0x3A, 0x72, 0xB2, - 0xA0, 0x29, 0x91, 0x1D, 0xCD, 0x7D, 0x5B, 0x9A, - 0x1A, 0xC1, 0x7B, 0x1D, 0x20, 0x5C, 0x1C, 0x79, - 0x9E, 0x45, 0x42, 0x17, 0xCC, 0xD5, 0x37, 0xFB, - 0x67, 0x34, 0x81, 0x0C, 0xEC, 0x5F, 0xCD, 0x05, - 0x50, 0x87, 0x58, 0xA4, 0x83, 0x03, 0xF2, 0x08, - 0x8B, 0xA2, 0x5C, 0xE5, 0xBC, 0x3E, 0x5D, 0x45, - 0xC6, 0xF5, 0x4D, 0xE3, 0x76, 0x11, 0xD9, 0x1A, - 0x78, 0xFE, 0x1F, 0xC1, 0x73, 0xDF, 0x7F, 0x9F, - 0x1F, 0x4C, 0x22, 0xDC, 0x2D, 0x1D, 0xEF, 0x45, - 0xE6, 0x31, 0x8E, 0x70, 0xC2, 0x50, 0xA2, 0x38, - 0xEE, 0xD5, 0x6B, 0x07, 0xC2, 0x82, 0x4A, 0x89, - 0xAB, 0xBA, 0x54, 0x5D, 0x7C, 0xEB, 0x96, 0xA6, - 0x26, 0xFD, 0x7D, 0x50, 0x88, 0xA9, 0xFE, 0x3D, - 0x3F, 0xED, 0x7F, 0x91, 0x00, 0x95, 0x50, 0xB1, - 0x31, 0x4B, 0xC6, 0xA9, 0xF0, 0x72, 0x11, 0xDD, - 0x74, 0x2D, 0xB3, 0xCD, 0x87, 0x5D, 0x39, 0x19, - 0x91, 0x4A, 0x5E, 0x92, 0xDE, 0xDF, 0x89, 0x4A, - 0x0B, 0xEC, 0x59, 0x8D, 0x5E, 0x2E, 0x6E, 0xAE, - 0xE6, 0x31, 0x15, 0x62, 0xE7, 0xFD, 0x36, 0x3C, - 0x25, 0x6C, 0xB1, 0xF5, 0x08, 0x02, 0x42, 0x9F, - 0xEF, 0x34, 0xB4, 0x99, 0x41, 0xFD, 0x88, 0x09, - 0xBE, 0x66, 0xE7, 0x69, 0x9D, 0x6A, 0xE8, 0x27, - 0x95, 0x4A, 0xDB, 0x95, 0x49, 0xDF, 0x85, 0x67, - 0xC7, 0x3D, 0xAA, 0xE4, 0x78, 0xED, 0x90, 0xA0, - 0x79, 0xE6, 0xC2, 0xAA, 0x57, 0x65, 0x01, 0xE7, - 0x6C, 0x2E, 0x08, 0xF4, 0x58, 0x7A, 0x5E, 0xB9, - 0xA3, 0xF0, 0xC6, 0x2B, 0xD2, 0xE0, 0xC4, 0x21, - 0xBC, 0x97, 0x78, 0x20, 0x4A, 0xFE, 0xB9, 0xDB, - 0x5F, 0xA1, 0xB5, 0x9D, 0x4F, 0xE4, 0x2E, 0x4E, - 0x6E, 0xC1, 0xD5, 0xFD, 0x03, 0x09, 0xC3, 0xA3, - 0x82, 0x78, 0x6C, 0x44, 0xB9, 0x14, 0x84, 0x44, - 0xC4, 0x1F, 0x9F, 0xB2, 0x6A, 0x1A, 0x5A, 0x9A, - 0x16, 0xC4, 0xF3, 0xA2, 0x79, 0xF8, 0xA2, 0x61, - 0xB0, 0x50, 0xE5, 0xFB, 0x00, 0x3A, 0x9A, 0x7A, - 0xFA, 0x69, 0x9A, 0x94, 0x6F, 0x56, 0xB6, 0x01, - 0x91, 0xCA, 0x0B, 0x76, 0x2E, 0xF8, 0x88, 0x88, - 0x28, 0xF3, 0x77, 0x38, 0x61, 0xA1, 0xA7, 0x47, - 0xB6, 0x5B, 0xEE, 0xE2, 0x7E, 0xEE, 0xBE, 0xDF, - 0x5B, 0xE1, 0x6B, 0x04, 0xEC, 0xDD, 0xB9, 0x49, - 0x78, 0xE2, 0xEC, 0x87, 0x49, 0xD1, 0xB9, 0xFB, - 0x50, 0x94, 0x15, 0x71, 0xD5, 0xE4, 0xBA, 0x79, - 0xF5, 0x64, 0x5A, 0xDE, 0x36, 0x35, 0x75, 0x55, - 0xDD, 0x06, 0x78, 0x51, 0xA8, 0x2F, 0x4C, 0x87, - 0x9B, 0x56, 0xB9, 0xDF, 0xB5, 0xC9, 0x57, 0x81, - 0xBA, 0x6B, 0x0F, 0xAF, 0x8A, 0x2C, 0xE1, 0x2D, - 0xBB, 0xDC, 0x6A, 0x20, 0xB4, 0x0C, 0xCE, 0xAE, - 0x2E, 0x50, 0x50, 0x1C, 0x06, 0x93, 0xF7, 0xF7, - 0xE7, 0x48, 0x52, 0x57, 0xA9, 0x50, 0x14, 0x71, - 0xE1, 0x3A, 0x0D, 0x53, 0x88, 0xBA, 0xF2, 0x20, - 0x40, 0x93, 0x25, 0xEB, 0x93, 0xB7, 0x6F, 0xA8, - 0xE8, 0x13, 0xA5, 0x01, 0xDF, 0xFD, 0x86, 0x1B, - 0x31, 0x41, 0x3D, 0xC8, 0x82, 0x59, 0x11, 0x34, - 0x1D, 0xE6, 0x98, 0xB1, 0x65, 0xDE, 0x3E, 0x52, - 0xD3, 0xA8, 0xBA, 0xF6, 0x0B, 0xA8, 0xC8, 0xA5, - 0x26, 0xF1, 0x4C, 0x85, 0x4F, 0xFF, 0x57, 0xD2, - 0x92, 0xD9, 0x1B, 0xEB, 0xAA, 0x3C, 0x15, 0xC2, - 0x5F, 0x74, 0x02, 0x4E, 0x96, 0xEE, 0x88, 0xFA, - 0x61, 0xE7, 0xFC, 0x92, 0x80, 0x8B, 0x52, 0xA0, - 0xC5, 0xB8, 0x2E, 0x5F, 0x77, 0xC7, 0xA7, 0x67, - 0x55, 0x2E, 0x99, 0x27, 0xFD, 0x47, 0x85, 0x47, - 0xEF, 0x34, 0x5F, 0x22, 0x7A, 0x60, 0x11, 0x71, - 0x5D, 0xA6, 0xC0, 0x06, 0xFE, 0x6B, 0x04, 0xC4, - 0xEC, 0xB5, 0x0F, 0x68, 0x15, 0xAB, 0xCB, 0x2E, - 0xE7, 0x3C, 0x86, 0xC1, 0x3C, 0x82, 0xE2, 0x3F, - 0x4F, 0x94, 0x2E, 0x48, 0xF5, 0xE8, 0xA8, 0xA0, - 0x65, 0x38, 0x54, 0xC7, 0x1F, 0xAF, 0x62, 0xA1, - 0x04, 0x36, 0x7F, 0xE1, 0x3B, 0xAD, 0x2F, 0xED, - 0x4A, 0x66, 0x6E, 0x13, 0x43, 0xC1, 0x1D, 0x55, - 0x4D, 0xD4, 0xDE, 0xFB, 0x81, 0x33, 0x59, 0x95, - 0x1E, 0x7C, 0x8F, 0x41, 0xDB, 0x4E, 0xE6, 0x63, - 0x25, 0x2E, 0x67, 0xA6, 0x7D, 0x28, 0xAE, 0x91, - 0xC3, 0x1A, 0x8A, 0x24, 0xFE, 0x69, 0xDE, 0xA2, - 0x33, 0x00, 0x84, 0x44, 0x62, 0x2A, 0x08, 0x64, - 0x5B, 0x02, 0xB6, 0xD0, 0x04, 0xBD, 0x44, 0xC1, - 0xC3, 0x5A, 0xC9, 0x6D, 0xF0, 0xC6, 0x61, 0x5E, - 0xDE, 0x05, 0xBF, 0xD9, 0xE4, 0x4A, 0x2A, 0xBC, - 0x86, 0xA1, 0x1B, 0x6D, 0xD0, 0x7E, 0x1E, 0xD2, - 0x69, 0x7F, 0xC3, 0xA3, 0x31, 0x41, 0x8A, 0xD9, - 0xF0, 0x6E, 0xDE, 0x5C, 0x7B, 0xCB, 0xA7, 0x4D, - 0xE8, 0x2E, 0x98, 0x2C, 0xB1, 0x0D, 0x23, 0x43, - 0x1D, 0x45, 0x2A, 0x03, 0x1D, 0x5F, 0xC0, 0x00, - 0x80, 0x5B, 0xDB, 0xF6, 0x2E, 0x3C, 0xFC, 0x18, - 0x49, 0xAF, 0x1A, 0x97, 0x70, 0xC3, 0x92, 0x65, - 0xE6, 0x1C, 0x90, 0xFF, 0x66, 0xE8, 0x8B, 0x8B, - 0x2B, 0xF0, 0xC4, 0x8C, 0x5A, 0x58, 0x1A, 0x53, - 0x11, 0xC9, 0x57, 0xDB, 0xB8, 0x18, 0xF8, 0xF4, - 0x65, 0x6E, 0x14, 0x68, 0x70, 0x7B, 0x3B, 0x1B, - 0x93, 0x48, 0x3E, 0x72, 0xAA, 0x36, 0xDC, 0x94, - 0xF0, 0xFA, 0x0D, 0x62, 0x08, 0x9A, 0x70, 0x72, - 0xF1, 0x0F, 0x58, 0x74, 0xAF, 0x9F, 0x33, 0xE2, - 0x82, 0x95, 0x33, 0x8F, 0xEC, 0x4C, 0xEC, 0x97, - 0x37, 0x0C, 0xB2, 0xDE, 0x1B, 0x5B, 0x0D, 0x8C, - 0x0C, 0x96, 0x16, 0x79, 0xF0, 0x72, 0x11, 0x09, - 0x8D, 0x27, 0xA6, 0xC9, 0x83, 0x1E, 0x62, 0x62, - 0xC2, 0x19, 0x2D, 0x56, 0x80, 0xF2, 0x8F, 0x19, - 0xB0, 0x62, 0x56, 0xF2, 0xD2, 0xF0, 0xBD, 0x61, - 0xAA, 0xBD, 0xCB, 0x67, 0x4B, 0x39, 0x04, 0x92, - 0x59, 0x1B, 0x3F, 0x3E, 0xFA, 0xCD, 0x81, 0x37, - 0x96, 0x74, 0xC1, 0x48, 0xCC, 0x59, 0x81, 0x45, - 0x67, 0xD7, 0x43, 0xA3, 0xC1, 0xF3, 0xB9, 0x7A, - 0x78, 0x8B, 0x3D, 0xB1, 0x61, 0xD1, 0xF7, 0x36, - 0xB6, 0x6D, 0xD7, 0xB1, 0x8C, 0xA6, 0xE6, 0xAE, - 0x8B, 0xB0, 0x0E, 0x62, 0x57, 0xED, 0x5F, 0xBB, - 0x3B, 0x52, 0xFE, 0x86, 0xFC, 0x21, 0x63, 0x71, - 0xEC, 0x61, 0x65, 0xC2, 0xE2, 0x85, 0x4E, 0x8F, - 0xD2, 0x02, 0x09, 0x67, 0x17, 0x89, 0x39, 0x99, - 0xED, 0xFB, 0x4B, 0xAC, 0xDE, 0x8B, 0x8B, 0x63, - 0xC9, 0x34, 0x3A, 0x52, 0x02, 0xE7, 0x25, 0xCE, - 0x6C, 0x25, 0xB8, 0xC8, 0xD2, 0x79, 0x4F, 0xEF, - 0xF6, 0xED, 0x3B, 0x9B, 0x83, 0xF1, 0xCA, 0x5C, - 0x4E, 0xFE, 0x54, 0xD8, 0x08, 0xB8, 0x00, 0xC4, - 0xE6, 0x2A, 0x92, 0x3C, 0xF9, 0x1F, 0xDD, 0xD7, - 0xAF, 0xD3, 0xC9, 0x2B, 0x75, 0xC5, 0xA5, 0x44, - 0xFD, 0x25, 0x21, 0x8E, 0xA9, 0xEF, 0xA4, 0x30, - 0xA6, 0x91, 0x22, 0xAB, 0x27, 0xB2, 0x1A, 0xDE, - 0xFC, 0x4B, 0xDF, 0x3F, 0x5D, 0x6F, 0x25, 0xE6, - 0xE4, 0x17, 0xA1, 0x2D, 0xFD, 0x4D, 0x6B, 0xAA, - 0x2A, 0xF1, 0x4B, 0x2D, 0x10, 0x32, 0x72, 0x3A, - 0x1F, 0x24, 0x9A, 0xF6, 0xE6, 0x52, 0x8F, 0x4D, - 0x6F, 0xD8, 0x4C, 0x88, 0x7A, 0x08, 0x74, 0xE2, - 0xC0, 0xD1, 0x6F, 0xE6, 0x67, 0xFF, 0x2E, 0xD7, - 0x54, 0x07, 0xE4, 0x20, 0xFC, 0x8E, 0x4E, 0x8E, - 0xCC, 0x4D, 0xAD, 0x73, 0xC1, 0x6D, 0xAF, 0x45, - 0xE7, 0xDC, 0x62, 0x0E, 0x04, 0x90, 0xF0, 0xC0, - 0x60, 0xBB, 0xCF, 0xBE, 0x30, 0x0C, 0xF0, 0x92, - 0x3F, 0xF8, 0xF3, 0x9D, 0x20, 0xC7, 0x8F, 0x9D, - 0x39, 0xE2, 0x32, 0x7D, 0x9B, 0xC9, 0xB4, 0x23, - 0x1F, 0xAA, 0x79, 0x5B, 0xA6, 0xEE, 0x8A, 0xE8, - 0x07, 0xFE, 0xE4, 0x92, 0xC2, 0x48, 0xA0, 0x68, - 0x08, 0xDB, 0x6D, 0x89, 0xF4, 0xA4, 0xCC, 0x0C, - 0x14, 0xCB, 0xF5, 0xCC, 0xB6, 0x6F, 0x2D, 0x0D, - 0x85, 0x5E, 0x40, 0x28, 0x52, 0xF8, 0xCF, 0x59, - 0xA3, 0x85, 0x35, 0x5A, 0x82, 0x32, 0x52, 0x33, - 0xF0, 0x28, 0x2F, 0x01, 0xDA, 0xD3, 0xE4, 0x01, - 0x3D, 0xC1, 0xAF, 0xC7, 0xDD, 0x70, 0x47, 0x0B, - 0x87, 0x41, 0x07, 0xCA, 0x57, 0xE4, 0x55, 0xD1, - 0x52, 0x50, 0x81, 0x08, 0x6A, 0xFD, 0x80, 0xB0, - 0x30, 0xEB, 0x6B, 0x46, 0x9E, 0xEF, 0xB8, 0x7B, - 0x5A, 0xBA, 0x0F, 0xDF, 0xC5, 0xF7, 0x55, 0x6B, - 0xFD, 0x6E, 0xDE, 0xD4, 0x1E, 0x85, 0x5D, 0x97, - 0xF5, 0x22, 0xB0, 0x0E, 0xDD, 0x6A, 0xA8, 0x63, - 0xE5, 0xAC, 0x11, 0x78, 0x70, 0x6A, 0xCA, 0x9D, - 0x37, 0xA5, 0xB1, 0x91, 0x61, 0x33, 0x1F, 0xFA, - 0x58, 0x88, 0x37, 0xA9, 0x7A, 0xC2, 0x50, 0xDC, - 0x7B, 0x82, 0x78, 0x32, 0xE6, 0x44, 0x39, 0x09, - 0x89, 0x52, 0xE8, 0x8E, 0xB3, 0x87, 0xC7, 0x0B, - 0x89, 0x4F, 0x09, 0xDD, 0x0F, 0x6D, 0x01, 0xE9, - 0xCB, 0x1B, 0xAA, 0x44, 0x97, 0x23, 0x99, 0xF3, - 0xD4, 0x27, 0xD7, 0x19, 0x8D, 0x15, 0x57, 0x9C, - 0x15, 0x2C, 0x96, 0xDE, 0xF4, 0x4F, 0x27, 0x15, - 0xD9, 0x25, 0x71, 0x51, 0xAC, 0x3E, 0x12, 0xF4, - 0x78, 0xB1, 0x1A, 0x86, 0x52, 0xE0, 0x9D, 0xAD, - 0x95, 0x44, 0x50, 0x30, 0xC0, 0xA2, 0xC9, 0x0E, - 0x0C, 0xDC, 0x6F, 0xD3, 0xA1, 0xD1, 0x36, 0xDC, - 0x40, 0x39, 0xC3, 0x87, 0x7D, 0xC6, 0xAF, 0x8D, - 0x01, 0xFE, 0xBA, 0xDD, 0x0D, 0x4F, 0x63, 0x84, - 0xE6, 0x71, 0xE2, 0xAC, 0x38, 0xAE, 0xC2, 0x10, - 0x8D, 0xA6, 0x1C, 0x72, 0xB7, 0xF7, 0x9B, 0x59, - 0xC4, 0xEF, 0x6F, 0x42, 0x9A, 0x0B, 0x5D, 0x9E, - 0x9C, 0x65, 0xD3, 0xFE, 0x11, 0xA2, 0x40, 0x98, - 0x4F, 0xA5, 0x21, 0x4E, 0x3A, 0xF2, 0x37, 0xCA, - 0x6F, 0x2C, 0x98, 0x56, 0xE7, 0x75, 0xB9, 0xA3, - 0xAB, 0x4A, 0x74, 0x10, 0x28, 0x90, 0xF0, 0xB8, - 0x9B, 0xA0, 0x1E, 0x72, 0x32, 0x80, 0x62, 0x81, - 0x04, 0x7D, 0xA2, 0xEC, 0xD4, 0x6C, 0x0C, 0x64, - 0xE6, 0x9F, 0x33, 0x08, 0x86, 0x5C, 0xC1, 0xA0, - 0x65, 0xBD, 0xBA, 0x92, 0x49, 0x40, 0x44, 0x21, - 0x0A, 0xF6, 0x5D, 0xC1, 0x19, 0xA9, 0xC9, 0xA8, - 0x6B, 0xB3, 0xC4, 0xEA, 0x31, 0x48, 0x7C, 0x19, - 0x33, 0xCF, 0xA1, 0xCF, 0xC5, 0x68, 0x5F, 0xC9, - 0x34, 0x11, 0xE1, 0x7B, 0x5C, 0xEC, 0xBA, 0x3B, - 0xBB, 0x6C, 0xD0, 0x9D, 0x73, 0xC0, 0xDC, 0xF0, - 0xC8, 0x11, 0x26, 0x74, 0xAF, 0xAD, 0xE6, 0x05, - 0x0D, 0x3E, 0x48, 0x9F, 0x57, 0x07, 0x6F, 0xAF, - 0x87, 0x5E, 0x4A, 0xEC, 0x6C, 0x39, 0xFE, 0x19, - 0x84, 0xAF, 0x2F, 0x02, 0xDA, 0x76, 0xCE, 0x89, - 0x9B, 0x44, 0xD3, 0xF9, 0x22, 0x8F, 0x1F, 0x72, - 0xF0, 0x0E, 0x0E, 0x47, 0xB2, 0x08, 0x75, 0x45, - 0xC5, 0x1E, 0x9E, 0xB3, 0x6B, 0x76, 0x14, 0xB1, - 0x31, 0xEA, 0x50, 0x3E, 0xFB, 0xBB, 0xED, 0x6C, - 0xEC, 0x17, 0x03, 0x4F, 0xB2, 0xE0, 0xA7, 0x56, - 0xED, 0x35, 0x1B, 0x74, 0x0C, 0x34, 0x15, 0x57, - 0x9E, 0x44, 0x50, 0x75, 0xAD, 0x36, 0xF4, 0xD1, - 0xB1, 0x4D, 0x4A, 0x11, 0xCA, 0xF8, 0x9A, 0x5F, - 0x2D, 0xF4, 0x45, 0xFB, 0x21, 0x97, 0x35, 0xF7, - 0x7F, 0x4C, 0xF9, 0x07, 0xDD, 0x69, 0x9B, 0x15, - 0x91, 0xC8, 0x30, 0x59, 0x23, 0xDD, 0xBF, 0xDF, - 0xF7, 0x6D, 0x79, 0x5B, 0x80, 0x92, 0xF0, 0x39, - 0x4B, 0xDE, 0x6F, 0xA1, 0x32, 0xA4, 0x66, 0xE8, - 0x61, 0x78, 0x80, 0xE4, 0xEE, 0x10, 0x76, 0x66, - 0x36, 0x99, 0xEF, 0x43, 0xEF, 0x9D, 0xB6, 0x51, - 0x03, 0x93, 0x0D, 0xCB, 0xCF, 0xAF, 0x1E, 0xFF, - 0xAD, 0x3D, 0xAF, 0xDE, 0xF6, 0x46, 0x10, 0x91, - 0x11, 0x07, 0xB3, 0xD3, 0x06, 0xAD, 0xAE, 0xD3, - 0x55, 0xB9, 0x3B, 0x26, 0xD5, 0x31, 0x61, 0xE5, - 0xA5, 0x65, 0x97, 0xBB, 0xE2, 0x13, 0x74, 0xD0, - 0x56, 0xA6, 0xA3, 0x1D, 0xC7, 0x77, 0x0C, 0x0E, - 0x12, 0xF1, 0xEA, 0x8B, 0x78, 0x73, 0xF1, 0x3D, - 0xBD, 0xB4, 0x0E, 0x63, 0x90, 0xEC, 0x66, 0x0C, - 0x56, 0x27, 0xC6, 0x31, 0x07, 0x6A, 0x00, 0x6D, - 0xE0, 0x86, 0x34, 0x7D, 0xC5, 0x5D, 0xF0, 0x32, - 0x0F, 0xD2, 0x68, 0x09, 0x91, 0xC0, 0xE1, 0x26, - 0xC2, 0x15, 0xB8, 0x16, 0x1C, 0xAE, 0xCE, 0x15, - 0x23, 0x28, 0x44, 0xE8, 0xE0, 0x81, 0x81, 0xDD, - 0xA3, 0x55, 0xEE, 0x10, 0xC4, 0x74, 0x3F, 0x44, - 0x54, 0x15, 0x63, 0x9F, 0xD6, 0x06, 0xFC, 0x1E, - 0x1C, 0xCB, 0x7C, 0x3B, 0x2F, 0x1F, 0xF5, 0xF5, - 0xF5, 0xAF, 0x79, 0x9F, 0x65, 0x82, 0x79, 0x5B, - 0xC6, 0xED, 0x76, 0x17, 0xD2, 0x92, 0xFE, 0x3C, - 0xA1, 0x8A, 0x0A, 0x07, 0xDF, 0xAF, 0xEF, 0x2F, - 0xEE, 0x7C, 0xC9, 0x04, 0x94, 0x27, 0x66, 0xE1, - 0x62, 0xEB, 0xFD, 0x90, 0x1A, 0xC8, 0x29, 0x29, - 0x89, 0x52, 0x76, 0x38, 0x60, 0x10, 0x50, 0x90, - 0xB0, 0xF2, 0x64, 0x9A, 0x20, 0x10, 0xB0, 0x50, - 0xD0, 0x89, 0x1B, 0xF6, 0xEE, 0x7E, 0x1E, 0x8E, - 0x86, 0x7D, 0x49, 0x41, 0x18, 0xCD, 0x8F, 0x6A, - 0xD7, 0x06, 0xA6, 0x80, 0x54, 0x5C, 0x16, 0x6F, - 0xEE, 0x39, 0x84, 0x08, 0xB1, 0x01, 0xB3, 0xD3, - 0x53, 0x59, 0xD8, 0xB7, 0xAF, 0x3F, 0x5F, 0x5D, - 0xFF, 0xA4, 0xD2, 0x9E, 0x46, 0xA6, 0x0A, 0xEA, - 0xB8, 0x7E, 0xC6, 0x68, 0xD2, 0xE2, 0x24, 0xF9, - 0x5C, 0x25, 0x33, 0xA3, 0xB9, 0x28, 0x48, 0x48, - 0xE8, 0x33, 0x77, 0x39, 0x6B, 0x2B, 0xC3, 0x42, - 0x62, 0x46, 0xE0, 0x0B, 0xCC, 0x8C, 0x2C, 0xCC, - 0x4C, 0xDC, 0xD1, 0x3F, 0xC5, 0xF9, 0x1B, 0xB7, - 0x37, 0x2E, 0x54, 0x3C, 0x33, 0xA8, 0x17, 0x86, - 0x4C, 0x94, 0xC2, 0x48, 0x83, 0x23, 0x63, 0xA3, - 0xA1, 0x5F, 0xED, 0x61, 0xB1, 0x01, 0x77, 0xBD, - 0x3A, 0xED, 0x55, 0xF8, 0x1B, 0xA8, 0xB4, 0x9C, - 0x10, 0x81, 0x4B, 0x1E, 0x06, 0x96, 0xF6, 0xE4, - 0x40, 0x1D, 0x6B, 0x27, 0xFF, 0xDF, 0x22, 0xF2, - 0xD2, 0x90, 0x06, 0xF8, 0x44, 0x72, 0xD2, 0x32, - 0xB2, 0x9B, 0x09, 0xE4, 0xFC, 0x6C, 0x0C, 0x4C, - 0x33, 0xF8, 0xBC, 0xB4, 0xED, 0x9D, 0xDD, 0x1D, - 0x4F, 0xF0, 0xC0, 0x6C, 0x94, 0x24, 0x8C, 0x40, - 0x68, 0x90, 0xD4, 0xB4, 0x6C, 0x6E, 0x02, 0xC3, - 0x81, 0x96, 0x22, 0xCE, 0xAD, 0x0C, 0x9C, 0xE7, - 0x47, 0x4E, 0xF4, 0x98, 0x82, 0x3E, 0x5F, 0x7D, - 0x9F, 0xC5, 0xF3, 0x53, 0x9A, 0xFA, 0x56, 0xB6, - 0xD3, 0xE0, 0xA9, 0x4D, 0xA6, 0x3B, 0x51, 0x19, - 0x91, 0xE7, 0x52, 0xDE, 0x0E, 0xBE, 0xC3, 0xF3, - 0x73, 0xA8, 0x12, 0x74, 0x49, 0xAD, 0xED, 0xAB, - 0xE6, 0xC2, 0xFC, 0xD5, 0xED, 0x55, 0x35, 0xE3, - 0x19, 0x3D, 0x4D, 0xC1, 0xE6, 0x56, 0x00, 0x81, - 0x01, 0x7B, 0x86, 0xE9, 0x80, 0x7C, 0x1F, 0x12, - 0x90, 0x2E, 0x70, 0x38, 0x51, 0xAF, 0xCC, 0x2C, - 0x86, 0xFD, 0xEA, 0xCB, 0x10, 0x6D, 0x0F, 0xAA, - 0xCD, 0x32, 0x35, 0x09, 0xD2, 0x42, 0x18, 0x78, - 0x3A, 0x22, 0x84, 0x49, 0xDE, 0x6D, 0x01, 0xC3, - 0x6A, 0xB2, 0x2D, 0x52, 0xA3, 0x30, 0x79, 0x8A, - 0xEF, 0xD1, 0x43, 0x9E, 0x14, 0xA7, 0xF7, 0x0D, - 0x2D, 0x34, 0x41, 0x3D, 0x44, 0xA5, 0xC6, 0xE3, - 0x87, 0x78, 0xC2, 0xA7, 0x4F, 0xC5, 0x05, 0xF7, - 0xB4, 0x7F, 0xE2, 0x17, 0xE6, 0x55, 0x1C, 0xCF, - 0xC4, 0x2C, 0xFC, 0x09, 0x25, 0x38, 0x5B, 0x29, - 0x09, 0x77, 0xED, 0xCD, 0xF0, 0x73, 0x3B, 0x5A, - 0x89, 0x51, 0x56, 0x6E, 0xB5, 0xC7, 0x64, 0x80, - 0x65, 0x5C, 0xCE, 0x13, 0x9D, 0x2E, 0x7E, 0x84, - 0xA4, 0xDE, 0x3D, 0x52, 0xB8, 0xCB, 0x8F, 0x82, - 0x01, 0x3F, 0x6A, 0x22, 0x4B, 0xA3, 0xC0, 0x30, - 0x8A, 0xF1, 0xE6, 0xDD, 0x06, 0x7B, 0x18, 0xBD, - 0xD8, 0x27, 0x20, 0x16, 0xCD, 0x4D, 0x17, 0x77, - 0x56, 0xD4, 0x61, 0xC0, 0x1B, 0x0E, 0x8A, 0x6E, - 0x5F, 0xD8, 0x6D, 0x31, 0xD3, 0xC3, 0x02, 0x99, - 0x1A, 0x0C, 0xB9, 0x70, 0x4B, 0xDF, 0x8F, 0x65, - 0x45, 0x83, 0xC5, 0xA9, 0x71, 0xC1, 0xBB, 0x7A, - 0xFA, 0x21, 0x97, 0xFB, 0x23, 0x93, 0x7F, 0xB2, - 0x30, 0x8B, 0xA9, 0xD3, 0x0B, 0xDB, 0xA6, 0x66, - 0xEC, 0x37, 0x03, 0x6B, 0x30, 0x84, 0x44, 0x97, - 0x15, 0xAE, 0x19, 0x75, 0xAD, 0x1D, 0x01, 0xD7, - 0x57, 0xEC, 0x26, 0x5C, 0x84, 0x54, 0x9C, 0x4A, - 0xCA, 0x71, 0x4F, 0x35, 0xED, 0x3D, 0xD5, 0x03, - 0x83, 0x38, 0x22, 0x58, 0x80, 0x50, 0x30, 0xF0, - 0x70, 0xAB, 0x1D, 0x71, 0xA9, 0x19, 0x79, 0xB9, - 0x39, 0xE2, 0x54, 0x38, 0xE0, 0x50, 0x30, 0xF0, - 0x70, 0xAB, 0x1D, 0x71, 0xA9, 0x19, 0x79, 0xB9, - 0x39, 0xE2, 0x54, 0x38, 0xE0, 0x50, 0x30, 0xF0, - 0x70, 0xAB, 0x1D, 0x71, 0xA9, 0x19, 0x79, 0xB9, - 0x39, 0xE2, 0x7C, 0x19, 0xC1, 0x11, 0x55, 0x9C, - 0x1C, 0xA7, 0x03, 0x5F, 0x87, 0x37, 0x97, 0x41, - 0xC1, 0x7A, 0x7C, 0x10, 0xC8, 0x78, 0x64, 0xA3, - 0x23, 0x98, 0x82, 0xE3, 0x39, 0xE9, 0x79, 0xBE, - 0x3E, 0x85, 0xC3, 0xA2, 0x78, 0xA8, 0xB8, 0x76, - 0xF4, 0x4F, 0xF1, 0x92, 0x48, 0x98, 0x44, 0x83, - 0x03, 0xB8, 0x86, 0xF9, 0x23, 0xF3, 0x3F, 0xEA, - 0x68, 0xD3, 0x53, 0x7E, 0xA6, 0x97, 0x45, 0x80, - 0xB1, 0xDA, 0x69, 0xA7, 0xDF, 0x6C, 0x9D, 0xEC, - 0x69, 0x10, 0xED, 0x81, 0xDB, 0x02, 0x62, 0xC7, - 0x46, 0x9D, 0x0E, 0x60, 0xB8, 0x2D, 0x49, 0x89, - 0xA8, 0xC0, 0x73, 0xAE, 0xC2, 0x77, 0xF2, 0xA3, - 0x04, 0xC2, 0x84, 0xE8, 0x30, 0x80, 0xD6, 0x57, - 0xD7, 0x3D, 0x3E, 0x57, 0xAE, 0xA8, 0xCD, 0x24, - 0x77, 0xB1, 0xF7, 0x9B, 0x43, 0xF3, 0xA5, 0x24, - 0xA4, 0xCE, 0xC0, 0xA9, 0x40, 0x4B, 0x2E, 0xCF, - 0xF3, 0x2D, 0x1A, 0xCC, 0x11, 0x30, 0xE7, 0x22, - 0x03, 0x61, 0xD2, 0x17, 0x16, 0x24, 0x2D, 0xFD, - 0x54, 0xAC, 0xA3, 0x56, 0x93, 0xD3, 0x85, 0x04, - 0x84, 0x6E, 0x6D, 0x04, 0xFD, 0xF0, 0x95, 0x7C, - 0x6F, 0xA9, 0xEF, 0x83, 0x5B, 0xEB, 0x8B, 0x4B, - 0xCB, 0x10, 0xA6, 0xCA, 0x12, 0xA2, 0xC2, 0x02, - 0x82, 0x59, 0xEE, 0x82, 0x5E, 0xEE, 0x76, 0xA0, - 0x22, 0x99, + 0x06, 0x6B, 0x06, 0x6A, 0x76, 0xCC, 0x1C, 0xD0, + 0x50, 0xEB, 0x75, 0x10, 0xC8, 0x18, 0x5C, 0x95, + 0x15, 0xAE, 0xA8, 0xC8, 0x10, 0xC0, 0xB0, 0x7A, + 0xFA, 0x21, 0x96, 0xFA, 0x22, 0x92, 0xAE, 0x78, + 0xF8, 0x43, 0x05, 0x6E, 0xB6, 0x66, 0x62, 0xD5, + 0x51, 0xEA, 0xF0, 0xE5, 0x39, 0xE9, 0xA1, 0x19, + 0x9D, 0x26, 0x80, 0xE0, 0x38, 0xE8, 0x1C, 0xCA, + 0x4A, 0xF1, 0xBF, 0xD8, 0x00, 0xD0, 0x34, 0xD9, + 0x5D, 0xB6, 0x00, 0xF2, 0x2A, 0xA2, 0xAA, 0x7C, + 0xFC, 0x47, 0xDD, 0xB8, 0x60, 0xB0, 0xD0, 0xEF, + 0x6F, 0xB4, 0x46, 0x2C, 0xF4, 0x24, 0xBB, 0x7B, + 0x04, 0x20, 0x96, 0xC5, 0x1D, 0xAD, 0x32, 0x32, + 0x4D, 0x69, 0xDF, 0xA0, 0x7A, 0xAA, 0xB6, 0x60, + 0xE0, 0x5B, 0x89, 0xF6, 0x2C, 0xFC, 0x14, 0xC2, + 0x42, 0xF9, 0x23, 0x59, 0x81, 0x51, 0x31, 0xEF, + 0x6B, 0x80, 0x36, 0x52, 0x8A, 0x3A, 0x5A, 0x64, + 0x1B, 0xF7, 0xBD, 0xD4, 0x0C, 0xDC, 0xBC, 0x54, + 0xD0, 0x3B, 0x0D, 0x4C, 0x90, 0x10, 0x70, 0x90, + 0x14, 0xFF, 0x65, 0x29, 0xF5, 0x75, 0x55, 0xB5, + 0x31, 0xDA, 0x88, 0xC5, 0x19, 0x99, 0xF9, 0x39, + 0xB9, 0x5A, 0xD0, 0xBC, 0x64, 0xEC, 0x8C, 0xEC, + 0x6C, 0x8F, 0x05, 0xC9, 0x11, 0x99, 0xF9, 0x19, + 0x99, 0x7A, 0xC2, 0x8E, 0x56, 0xDE, 0xBE, 0x3E, + 0xBE, 0x5D, 0xE3, 0xCF, 0x17, 0x9F, 0xFF, 0x5F, + 0xDF, 0x3C, 0x82, 0x8E, 0x56, 0xDE, 0xBE, 0xFE, + 0x7E, 0x9D, 0x23, 0xCF, 0x17, 0x9F, 0xC9, 0x48, + 0xC8, 0xF6, 0x07, 0x4D, 0x04, 0x98, 0xFB, 0x9A, + 0x37, 0xEF, 0x55, 0x31, 0x60, 0xDA, 0x38, 0xB1, + 0x31, 0xF7, 0xB1, 0xDD, 0x05, 0xB5, 0xE3, 0x62, + 0xE2, 0x19, 0xCE, 0xA2, 0x5F, 0x11, 0x8E, 0x6E, + 0x08, 0xC0, 0x66, 0x2A, 0xF2, 0x4E, 0x24, 0x01, + 0xAA, 0x54, 0x43, 0x01, 0xDA, 0xDB, 0x94, 0x57, + 0xB2, 0x40, 0xDE, 0xAF, 0x87, 0x37, 0x61, 0xE0, + 0x60, 0x16, 0xA2, 0x4F, 0xA7, 0x14, 0x78, 0xB1, + 0x3A, 0x59, 0x78, 0x0C, 0xC5, 0x54, 0x05, 0xC6, + 0x8E, 0x57, 0xEA, 0x3D, 0x25, 0x55, 0x41, 0x46, + 0xDC, 0x0C, 0x71, 0x3F, 0x81, 0x3A, 0xAA, 0x8F, + 0x6B, 0x95, 0x0E, 0x68, 0xAD, 0xED, 0x90, 0xA0, + 0x20, 0xFB, 0x7B, 0x56, 0x8E, 0xAF, 0xFC, 0x3F, + 0x9E, 0x70, 0xC5, 0x98, 0x72, 0xC1, 0x20, 0xD4, + 0x57, 0x05, 0x60, 0x2E, 0x95, 0x35, 0xCC, 0x9F, + 0x02, 0x29, 0xA9, 0x84, 0x5C, 0xDD, 0x8B, 0x48, + 0xDE, 0xA7, 0x17, 0x1E, 0x49, 0xDC, 0x94, 0x57, + 0x75, 0xCC, 0x58, 0x15, 0xFA, 0x49, 0xB5, 0x7F, + 0x77, 0x96, 0xB2, 0xC4, 0x08, 0x3A, 0x72, 0xB2, + 0xA0, 0x29, 0x91, 0x1D, 0xCD, 0x7D, 0x5B, 0x9A, + 0x1A, 0xC1, 0x7B, 0x1D, 0x20, 0x5C, 0x1C, 0x79, + 0x9E, 0x45, 0x42, 0x17, 0xCC, 0xD5, 0x37, 0xFB, + 0x67, 0x34, 0x81, 0x0C, 0xEC, 0x5F, 0xCD, 0x05, + 0x50, 0x87, 0x58, 0xA4, 0x83, 0x03, 0xF2, 0x08, + 0x8B, 0xA2, 0x5C, 0xE5, 0xBC, 0x3E, 0x5D, 0x45, + 0xC6, 0xF5, 0x4D, 0xE3, 0x76, 0x11, 0xD9, 0x1A, + 0x78, 0xFE, 0x1F, 0xC1, 0x73, 0xDF, 0x7F, 0x9F, + 0x1F, 0x4C, 0x22, 0xDC, 0x2D, 0x1D, 0xEF, 0x45, + 0xE6, 0x31, 0x8E, 0x70, 0xC2, 0x50, 0xA2, 0x38, + 0xEE, 0xD5, 0x6B, 0x07, 0xC2, 0x82, 0x4A, 0x89, + 0xAB, 0xBA, 0x54, 0x5D, 0x7C, 0xEB, 0x96, 0xA6, + 0x26, 0xFD, 0x7D, 0x50, 0x88, 0xA9, 0xFE, 0x3D, + 0x3F, 0xED, 0x7F, 0x91, 0x00, 0x95, 0x50, 0xB1, + 0x31, 0x4B, 0xC6, 0xA9, 0xF0, 0x72, 0x11, 0xDD, + 0x74, 0x2D, 0xB3, 0xCD, 0x87, 0x5D, 0x39, 0x19, + 0x91, 0x4A, 0x5E, 0x92, 0xDE, 0xDF, 0x89, 0x4A, + 0x0B, 0xEC, 0x59, 0x8D, 0x5E, 0x2E, 0x6E, 0xAE, + 0xE6, 0x31, 0x15, 0x62, 0xE7, 0xFD, 0x36, 0x3C, + 0x25, 0x6C, 0xB1, 0xF5, 0x08, 0x02, 0x42, 0x9F, + 0xEF, 0x34, 0xB4, 0x99, 0x41, 0xFD, 0x88, 0x09, + 0xBE, 0x66, 0xE7, 0x69, 0x9D, 0x6A, 0xE8, 0x27, + 0x95, 0x4A, 0xDB, 0x95, 0x49, 0xDF, 0x85, 0x67, + 0xC7, 0x3D, 0xAA, 0xE4, 0x78, 0xED, 0x90, 0xA0, + 0x79, 0xE6, 0xC2, 0xAA, 0x57, 0x65, 0x01, 0xE7, + 0x6C, 0x2E, 0x08, 0xF4, 0x58, 0x7A, 0x5E, 0xB9, + 0xA3, 0xF0, 0xC6, 0x2B, 0xD2, 0xE0, 0xC4, 0x21, + 0xBC, 0x97, 0x78, 0x20, 0x4A, 0xFE, 0xB9, 0xDB, + 0x5F, 0xA1, 0xB5, 0x9D, 0x4F, 0xE4, 0x2E, 0x4E, + 0x6E, 0xC1, 0xD5, 0xFD, 0x03, 0x09, 0xC3, 0xA3, + 0x82, 0x78, 0x6C, 0x44, 0xB9, 0x14, 0x84, 0x44, + 0xC4, 0x1F, 0x9F, 0xB2, 0x6A, 0x1A, 0x5A, 0x9A, + 0x16, 0xC4, 0xF3, 0xA2, 0x79, 0xF8, 0xA2, 0x61, + 0xB0, 0x50, 0xE5, 0xFB, 0x00, 0x3A, 0x9A, 0x7A, + 0xFA, 0x69, 0x9A, 0x94, 0x6F, 0x56, 0xB6, 0x01, + 0x91, 0xCA, 0x0B, 0x76, 0x2E, 0xF8, 0x88, 0x88, + 0x28, 0xF3, 0x77, 0x38, 0x61, 0xA1, 0xA7, 0x47, + 0xB6, 0x5B, 0xEE, 0xE2, 0x7E, 0xEE, 0xBE, 0xDF, + 0x5B, 0xE1, 0x6B, 0x04, 0xEC, 0xDD, 0xB9, 0x49, + 0x78, 0xE2, 0xEC, 0x87, 0x49, 0xD1, 0xB9, 0xFB, + 0x50, 0x94, 0x15, 0x71, 0xD5, 0xE4, 0xBA, 0x79, + 0xF5, 0x64, 0x5A, 0xDE, 0x36, 0x35, 0x75, 0x55, + 0xDD, 0x06, 0x78, 0x51, 0xA8, 0x2F, 0x4C, 0x87, + 0x9B, 0x56, 0xB9, 0xDF, 0xB5, 0xC9, 0x57, 0x81, + 0xBA, 0x6B, 0x0F, 0xAF, 0x8A, 0x2C, 0xE1, 0x2D, + 0xBB, 0xDC, 0x6A, 0x20, 0xB4, 0x0C, 0xCE, 0xAE, + 0x2E, 0x50, 0x50, 0x1C, 0x06, 0x93, 0xF7, 0xF7, + 0xE7, 0x48, 0x52, 0x57, 0xA9, 0x50, 0x14, 0x71, + 0xE1, 0x3A, 0x0D, 0x53, 0x88, 0xBA, 0xF2, 0x20, + 0x40, 0x93, 0x25, 0xEB, 0x93, 0xB7, 0x6F, 0xA8, + 0xE8, 0x13, 0xA5, 0x01, 0xDF, 0xFD, 0x86, 0x1B, + 0x31, 0x41, 0x3D, 0xC8, 0x82, 0x59, 0x11, 0x34, + 0x1D, 0xE6, 0x98, 0xB1, 0x65, 0xDE, 0x3E, 0x52, + 0xD3, 0xA8, 0xBA, 0xF6, 0x0B, 0xA8, 0xC8, 0xA5, + 0x26, 0xF1, 0x4C, 0x85, 0x4F, 0xFF, 0x57, 0xD2, + 0x92, 0xD9, 0x1B, 0xEB, 0xAA, 0x3C, 0x15, 0xC2, + 0x5F, 0x74, 0x02, 0x4E, 0x96, 0xEE, 0x88, 0xFA, + 0x61, 0xE7, 0xFC, 0x92, 0x80, 0x8B, 0x52, 0xA0, + 0xC5, 0xB8, 0x2E, 0x5F, 0x77, 0xC7, 0xA7, 0x67, + 0x55, 0x2E, 0x99, 0x27, 0xFD, 0x47, 0x85, 0x47, + 0xEF, 0x34, 0x5F, 0x22, 0x7A, 0x60, 0x11, 0x71, + 0x5D, 0xA6, 0xC0, 0x06, 0xFE, 0x6B, 0x04, 0xC4, + 0xEC, 0xB5, 0x0F, 0x68, 0x15, 0xAB, 0xCB, 0x2E, + 0xE7, 0x3C, 0x86, 0xC1, 0x3C, 0x82, 0xE2, 0x3F, + 0x4F, 0x94, 0x2E, 0x48, 0xF5, 0xE8, 0xA8, 0xA0, + 0x65, 0x38, 0x54, 0xC7, 0x1F, 0xAF, 0x62, 0xA1, + 0x04, 0x36, 0x7F, 0xE1, 0x3B, 0xAD, 0x2F, 0xED, + 0x4A, 0x66, 0x6E, 0x13, 0x43, 0xC1, 0x1D, 0x55, + 0x4D, 0xD4, 0xDE, 0xFB, 0x81, 0x33, 0x59, 0x95, + 0x1E, 0x7C, 0x8F, 0x41, 0xDB, 0x4E, 0xE6, 0x63, + 0x25, 0x2E, 0x67, 0xA6, 0x7D, 0x28, 0xAE, 0x91, + 0xC3, 0x1A, 0x8A, 0x24, 0xFE, 0x69, 0xDE, 0xA2, + 0x33, 0x00, 0x84, 0x44, 0x62, 0x2A, 0x08, 0x64, + 0x5B, 0x02, 0xB6, 0xD0, 0x04, 0xBD, 0x44, 0xC1, + 0xC3, 0x5A, 0xC9, 0x6D, 0xF0, 0xC6, 0x61, 0x5E, + 0xDE, 0x05, 0xBF, 0xD9, 0xE4, 0x4A, 0x2A, 0xBC, + 0x86, 0xA1, 0x1B, 0x6D, 0xD0, 0x7E, 0x1E, 0xD2, + 0x69, 0x7F, 0xC3, 0xA3, 0x31, 0x41, 0x8A, 0xD9, + 0xF0, 0x6E, 0xDE, 0x5C, 0x7B, 0xCB, 0xA7, 0x4D, + 0xE8, 0x2E, 0x98, 0x2C, 0xB1, 0x0D, 0x23, 0x43, + 0x1D, 0x45, 0x2A, 0x03, 0x1D, 0x5F, 0xC0, 0x00, + 0x80, 0x5B, 0xDB, 0xF6, 0x2E, 0x3C, 0xFC, 0x18, + 0x49, 0xAF, 0x1A, 0x97, 0x70, 0xC3, 0x92, 0x65, + 0xE6, 0x1C, 0x90, 0xFF, 0x66, 0xE8, 0x8B, 0x8B, + 0x2B, 0xF0, 0xC4, 0x8C, 0x5A, 0x58, 0x1A, 0x53, + 0x11, 0xC9, 0x57, 0xDB, 0xB8, 0x18, 0xF8, 0xF4, + 0x65, 0x6E, 0x14, 0x68, 0x70, 0x7B, 0x3B, 0x1B, + 0x93, 0x48, 0x3E, 0x72, 0xAA, 0x36, 0xDC, 0x94, + 0xF0, 0xFA, 0x0D, 0x62, 0x08, 0x9A, 0x70, 0x72, + 0xF1, 0x0F, 0x58, 0x74, 0xAF, 0x9F, 0x33, 0xE2, + 0x82, 0x95, 0x33, 0x8F, 0xEC, 0x4C, 0xEC, 0x97, + 0x37, 0x0C, 0xB2, 0xDE, 0x1B, 0x5B, 0x0D, 0x8C, + 0x0C, 0x96, 0x16, 0x79, 0xF0, 0x72, 0x11, 0x09, + 0x8D, 0x27, 0xA6, 0xC9, 0x83, 0x1E, 0x62, 0x62, + 0xC2, 0x19, 0x2D, 0x56, 0x80, 0xF2, 0x8F, 0x19, + 0xB0, 0x62, 0x56, 0xF2, 0xD2, 0xF0, 0xBD, 0x61, + 0xAA, 0xBD, 0xCB, 0x67, 0x4B, 0x39, 0x04, 0x92, + 0x59, 0x1B, 0x3F, 0x3E, 0xFA, 0xCD, 0x81, 0x37, + 0x96, 0x74, 0xC1, 0x48, 0xCC, 0x59, 0x81, 0x45, + 0x67, 0xD7, 0x43, 0xA3, 0xC1, 0xF3, 0xB9, 0x7A, + 0x78, 0x8B, 0x3D, 0xB1, 0x61, 0xD1, 0xF7, 0x36, + 0xB6, 0x6D, 0xD7, 0xB1, 0x8C, 0xA6, 0xE6, 0xAE, + 0x8B, 0xB0, 0x0E, 0x62, 0x57, 0xED, 0x5F, 0xBB, + 0x3B, 0x52, 0xFE, 0x86, 0xFC, 0x21, 0x63, 0x71, + 0xEC, 0x61, 0x65, 0xC2, 0xE2, 0x85, 0x4E, 0x8F, + 0xD2, 0x02, 0x09, 0x67, 0x17, 0x89, 0x39, 0x99, + 0xED, 0xFB, 0x4B, 0xAC, 0xDE, 0x8B, 0x8B, 0x63, + 0xC9, 0x34, 0x3A, 0x52, 0x02, 0xE7, 0x25, 0xCE, + 0x6C, 0x25, 0xB8, 0xC8, 0xD2, 0x79, 0x4F, 0xEF, + 0xF6, 0xED, 0x3B, 0x9B, 0x83, 0xF1, 0xCA, 0x5C, + 0x4E, 0xFE, 0x54, 0xD8, 0x08, 0xB8, 0x00, 0xC4, + 0xE6, 0x2A, 0x92, 0x3C, 0xF9, 0x1F, 0xDD, 0xD7, + 0xAF, 0xD3, 0xC9, 0x2B, 0x75, 0xC5, 0xA5, 0x44, + 0xFD, 0x25, 0x21, 0x8E, 0xA9, 0xEF, 0xA4, 0x30, + 0xA6, 0x91, 0x22, 0xAB, 0x27, 0xB2, 0x1A, 0xDE, + 0xFC, 0x4B, 0xDF, 0x3F, 0x5D, 0x6F, 0x25, 0xE6, + 0xE4, 0x17, 0xA1, 0x2D, 0xFD, 0x4D, 0x6B, 0xAA, + 0x2A, 0xF1, 0x4B, 0x2D, 0x10, 0x32, 0x72, 0x3A, + 0x1F, 0x24, 0x9A, 0xF6, 0xE6, 0x52, 0x8F, 0x4D, + 0x6F, 0xD8, 0x4C, 0x88, 0x7A, 0x08, 0x74, 0xE2, + 0xC0, 0xD1, 0x6F, 0xE6, 0x67, 0xFF, 0x2E, 0xD7, + 0x54, 0x07, 0xE4, 0x20, 0xFC, 0x8E, 0x4E, 0x8E, + 0xCC, 0x4D, 0xAD, 0x73, 0xC1, 0x6D, 0xAF, 0x45, + 0xE7, 0xDC, 0x62, 0x0E, 0x04, 0x90, 0xF0, 0xC0, + 0x60, 0xBB, 0xCF, 0xBE, 0x30, 0x0C, 0xF0, 0x92, + 0x3F, 0xF8, 0xF3, 0x9D, 0x20, 0xC7, 0x8F, 0x9D, + 0x39, 0xE2, 0x32, 0x7D, 0x9B, 0xC9, 0xB4, 0x23, + 0x1F, 0xAA, 0x79, 0x5B, 0xA6, 0xEE, 0x8A, 0xE8, + 0x07, 0xFE, 0xE4, 0x92, 0xC2, 0x48, 0xA0, 0x68, + 0x08, 0xDB, 0x6D, 0x89, 0xF4, 0xA4, 0xCC, 0x0C, + 0x14, 0xCB, 0xF5, 0xCC, 0xB6, 0x6F, 0x2D, 0x0D, + 0x85, 0x5E, 0x40, 0x28, 0x52, 0xF8, 0xCF, 0x59, + 0xA3, 0x85, 0x35, 0x5A, 0x82, 0x32, 0x52, 0x33, + 0xF0, 0x28, 0x2F, 0x01, 0xDA, 0xD3, 0xE4, 0x01, + 0x3D, 0xC1, 0xAF, 0xC7, 0xDD, 0x70, 0x47, 0x0B, + 0x87, 0x41, 0x07, 0xCA, 0x57, 0xE4, 0x55, 0xD1, + 0x52, 0x50, 0x81, 0x08, 0x6A, 0xFD, 0x80, 0xB0, + 0x30, 0xEB, 0x6B, 0x46, 0x9E, 0xEF, 0xB8, 0x7B, + 0x5A, 0xBA, 0x0F, 0xDF, 0xC5, 0xF7, 0x55, 0x6B, + 0xFD, 0x6E, 0xDE, 0xD4, 0x1E, 0x85, 0x5D, 0x97, + 0xF5, 0x22, 0xB0, 0x0E, 0xDD, 0x6A, 0xA8, 0x63, + 0xE5, 0xAC, 0x11, 0x78, 0x70, 0x6A, 0xCA, 0x9D, + 0x37, 0xA5, 0xB1, 0x91, 0x61, 0x33, 0x1F, 0xFA, + 0x58, 0x88, 0x37, 0xA9, 0x7A, 0xC2, 0x50, 0xDC, + 0x7B, 0x82, 0x78, 0x32, 0xE6, 0x44, 0x39, 0x09, + 0x89, 0x52, 0xE8, 0x8E, 0xB3, 0x87, 0xC7, 0x0B, + 0x89, 0x4F, 0x09, 0xDD, 0x0F, 0x6D, 0x01, 0xE9, + 0xCB, 0x1B, 0xAA, 0x44, 0x97, 0x23, 0x99, 0xF3, + 0xD4, 0x27, 0xD7, 0x19, 0x8D, 0x15, 0x57, 0x9C, + 0x15, 0x2C, 0x96, 0xDE, 0xF4, 0x4F, 0x27, 0x15, + 0xD9, 0x25, 0x71, 0x51, 0xAC, 0x3E, 0x12, 0xF4, + 0x78, 0xB1, 0x1A, 0x86, 0x52, 0xE0, 0x9D, 0xAD, + 0x95, 0x44, 0x50, 0x30, 0xC0, 0xA2, 0xC9, 0x0E, + 0x0C, 0xDC, 0x6F, 0xD3, 0xA1, 0xD1, 0x36, 0xDC, + 0x40, 0x39, 0xC3, 0x87, 0x7D, 0xC6, 0xAF, 0x8D, + 0x01, 0xFE, 0xBA, 0xDD, 0x0D, 0x4F, 0x63, 0x84, + 0xE6, 0x71, 0xE2, 0xAC, 0x38, 0xAE, 0xC2, 0x10, + 0x8D, 0xA6, 0x1C, 0x72, 0xB7, 0xF7, 0x9B, 0x59, + 0xC4, 0xEF, 0x6F, 0x42, 0x9A, 0x0B, 0x5D, 0x9E, + 0x9C, 0x65, 0xD3, 0xFE, 0x11, 0xA2, 0x40, 0x98, + 0x4F, 0xA5, 0x21, 0x4E, 0x3A, 0xF2, 0x37, 0xCA, + 0x6F, 0x2C, 0x98, 0x56, 0xE7, 0x75, 0xB9, 0xA3, + 0xAB, 0x4A, 0x74, 0x10, 0x28, 0x90, 0xF0, 0xB8, + 0x9B, 0xA0, 0x1E, 0x72, 0x32, 0x80, 0x62, 0x81, + 0x04, 0x7D, 0xA2, 0xEC, 0xD4, 0x6C, 0x0C, 0x64, + 0xE6, 0x9F, 0x33, 0x08, 0x86, 0x5C, 0xC1, 0xA0, + 0x65, 0xBD, 0xBA, 0x92, 0x49, 0x40, 0x44, 0x21, + 0x0A, 0xF6, 0x5D, 0xC1, 0x19, 0xA9, 0xC9, 0xA8, + 0x6B, 0xB3, 0xC4, 0xEA, 0x31, 0x48, 0x7C, 0x19, + 0x33, 0xCF, 0xA1, 0xCF, 0xC5, 0x68, 0x5F, 0xC9, + 0x34, 0x11, 0xE1, 0x7B, 0x5C, 0xEC, 0xBA, 0x3B, + 0xBB, 0x6C, 0xD0, 0x9D, 0x73, 0xC0, 0xDC, 0xF0, + 0xC8, 0x11, 0x26, 0x74, 0xAF, 0xAD, 0xE6, 0x05, + 0x0D, 0x3E, 0x48, 0x9F, 0x57, 0x07, 0x6F, 0xAF, + 0x87, 0x5E, 0x4A, 0xEC, 0x6C, 0x39, 0xFE, 0x19, + 0x84, 0xAF, 0x2F, 0x02, 0xDA, 0x76, 0xCE, 0x89, + 0x9B, 0x44, 0xD3, 0xF9, 0x22, 0x8F, 0x1F, 0x72, + 0xF0, 0x0E, 0x0E, 0x47, 0xB2, 0x08, 0x75, 0x45, + 0xC5, 0x1E, 0x9E, 0xB3, 0x6B, 0x76, 0x14, 0xB1, + 0x31, 0xEA, 0x50, 0x3E, 0xFB, 0xBB, 0xED, 0x6C, + 0xEC, 0x17, 0x03, 0x4F, 0xB2, 0xE0, 0xA7, 0x56, + 0xED, 0x35, 0x1B, 0x74, 0x0C, 0x34, 0x15, 0x57, + 0x9E, 0x44, 0x50, 0x75, 0xAD, 0x36, 0xF4, 0xD1, + 0xB1, 0x4D, 0x4A, 0x11, 0xCA, 0xF8, 0x9A, 0x5F, + 0x2D, 0xF4, 0x45, 0xFB, 0x21, 0x97, 0x35, 0xF7, + 0x7F, 0x4C, 0xF9, 0x07, 0xDD, 0x69, 0x9B, 0x15, + 0x91, 0xC8, 0x30, 0x59, 0x23, 0xDD, 0xBF, 0xDF, + 0xF7, 0x6D, 0x79, 0x5B, 0x80, 0x92, 0xF0, 0x39, + 0x4B, 0xDE, 0x6F, 0xA1, 0x32, 0xA4, 0x66, 0xE8, + 0x61, 0x78, 0x80, 0xE4, 0xEE, 0x10, 0x76, 0x66, + 0x36, 0x99, 0xEF, 0x43, 0xEF, 0x9D, 0xB6, 0x51, + 0x03, 0x93, 0x0D, 0xCB, 0xCF, 0xAF, 0x1E, 0xFF, + 0xAD, 0x3D, 0xAF, 0xDE, 0xF6, 0x46, 0x10, 0x91, + 0x11, 0x07, 0xB3, 0xD3, 0x06, 0xAD, 0xAE, 0xD3, + 0x55, 0xB9, 0x3B, 0x26, 0xD5, 0x31, 0x61, 0xE5, + 0xA5, 0x65, 0x97, 0xBB, 0xE2, 0x13, 0x74, 0xD0, + 0x56, 0xA6, 0xA3, 0x1D, 0xC7, 0x77, 0x0C, 0x0E, + 0x12, 0xF1, 0xEA, 0x8B, 0x78, 0x73, 0xF1, 0x3D, + 0xBD, 0xB4, 0x0E, 0x63, 0x90, 0xEC, 0x66, 0x0C, + 0x56, 0x27, 0xC6, 0x31, 0x07, 0x6A, 0x00, 0x6D, + 0xE0, 0x86, 0x34, 0x7D, 0xC5, 0x5D, 0xF0, 0x32, + 0x0F, 0xD2, 0x68, 0x09, 0x91, 0xC0, 0xE1, 0x26, + 0xC2, 0x15, 0xB8, 0x16, 0x1C, 0xAE, 0xCE, 0x15, + 0x23, 0x28, 0x44, 0xE8, 0xE0, 0x81, 0x81, 0xDD, + 0xA3, 0x55, 0xEE, 0x10, 0xC4, 0x74, 0x3F, 0x44, + 0x54, 0x15, 0x63, 0x9F, 0xD6, 0x06, 0xFC, 0x1E, + 0x1C, 0xCB, 0x7C, 0x3B, 0x2F, 0x1F, 0xF5, 0xF5, + 0xF5, 0xAF, 0x79, 0x9F, 0x65, 0x82, 0x79, 0x5B, + 0xC6, 0xED, 0x76, 0x17, 0xD2, 0x92, 0xFE, 0x3C, + 0xA1, 0x8A, 0x0A, 0x07, 0xDF, 0xAF, 0xEF, 0x2F, + 0xEE, 0x7C, 0xC9, 0x04, 0x94, 0x27, 0x66, 0xE1, + 0x62, 0xEB, 0xFD, 0x90, 0x1A, 0xC8, 0x29, 0x29, + 0x89, 0x52, 0x76, 0x38, 0x60, 0x10, 0x50, 0x90, + 0xB0, 0xF2, 0x64, 0x9A, 0x20, 0x10, 0xB0, 0x50, + 0xD0, 0x89, 0x1B, 0xF6, 0xEE, 0x7E, 0x1E, 0x8E, + 0x86, 0x7D, 0x49, 0x41, 0x18, 0xCD, 0x8F, 0x6A, + 0xD7, 0x06, 0xA6, 0x80, 0x54, 0x5C, 0x16, 0x6F, + 0xEE, 0x39, 0x84, 0x08, 0xB1, 0x01, 0xB3, 0xD3, + 0x53, 0x59, 0xD8, 0xB7, 0xAF, 0x3F, 0x5F, 0x5D, + 0xFF, 0xA4, 0xD2, 0x9E, 0x46, 0xA6, 0x0A, 0xEA, + 0xB8, 0x7E, 0xC6, 0x68, 0xD2, 0xE2, 0x24, 0xF9, + 0x5C, 0x25, 0x33, 0xA3, 0xB9, 0x28, 0x48, 0x48, + 0xE8, 0x33, 0x77, 0x39, 0x6B, 0x2B, 0xC3, 0x42, + 0x62, 0x46, 0xE0, 0x0B, 0xCC, 0x8C, 0x2C, 0xCC, + 0x4C, 0xDC, 0xD1, 0x3F, 0xC5, 0xF9, 0x1B, 0xB7, + 0x37, 0x2E, 0x54, 0x3C, 0x33, 0xA8, 0x17, 0x86, + 0x4C, 0x94, 0xC2, 0x48, 0x83, 0x23, 0x63, 0xA3, + 0xA1, 0x5F, 0xED, 0x61, 0xB1, 0x01, 0x77, 0xBD, + 0x3A, 0xED, 0x55, 0xF8, 0x1B, 0xA8, 0xB4, 0x9C, + 0x10, 0x81, 0x4B, 0x1E, 0x06, 0x96, 0xF6, 0xE4, + 0x40, 0x1D, 0x6B, 0x27, 0xFF, 0xDF, 0x22, 0xF2, + 0xD2, 0x90, 0x06, 0xF8, 0x44, 0x72, 0xD2, 0x32, + 0xB2, 0x9B, 0x09, 0xE4, 0xFC, 0x6C, 0x0C, 0x4C, + 0x33, 0xF8, 0xBC, 0xB4, 0xED, 0x9D, 0xDD, 0x1D, + 0x4F, 0xF0, 0xC0, 0x6C, 0x94, 0x24, 0x8C, 0x40, + 0x68, 0x90, 0xD4, 0xB4, 0x6C, 0x6E, 0x02, 0xC3, + 0x81, 0x96, 0x22, 0xCE, 0xAD, 0x0C, 0x9C, 0xE7, + 0x47, 0x4E, 0xF4, 0x98, 0x82, 0x3E, 0x5F, 0x7D, + 0x9F, 0xC5, 0xF3, 0x53, 0x9A, 0xFA, 0x56, 0xB6, + 0xD3, 0xE0, 0xA9, 0x4D, 0xA6, 0x3B, 0x51, 0x19, + 0x91, 0xE7, 0x52, 0xDE, 0x0E, 0xBE, 0xC3, 0xF3, + 0x73, 0xA8, 0x12, 0x74, 0x49, 0xAD, 0xED, 0xAB, + 0xE6, 0xC2, 0xFC, 0xD5, 0xED, 0x55, 0x35, 0xE3, + 0x19, 0x3D, 0x4D, 0xC1, 0xE6, 0x56, 0x00, 0x81, + 0x01, 0x7B, 0x86, 0xE9, 0x80, 0x7C, 0x1F, 0x12, + 0x90, 0x2E, 0x70, 0x38, 0x51, 0xAF, 0xCC, 0x2C, + 0x86, 0xFD, 0xEA, 0xCB, 0x10, 0x6D, 0x0F, 0xAA, + 0xCD, 0x32, 0x35, 0x09, 0xD2, 0x42, 0x18, 0x78, + 0x3A, 0x22, 0x84, 0x49, 0xDE, 0x6D, 0x01, 0xC3, + 0x6A, 0xB2, 0x2D, 0x52, 0xA3, 0x30, 0x79, 0x8A, + 0xEF, 0xD1, 0x43, 0x9E, 0x14, 0xA7, 0xF7, 0x0D, + 0x2D, 0x34, 0x41, 0x3D, 0x44, 0xA5, 0xC6, 0xE3, + 0x87, 0x78, 0xC2, 0xA7, 0x4F, 0xC5, 0x05, 0xF7, + 0xB4, 0x7F, 0xE2, 0x17, 0xE6, 0x55, 0x1C, 0xCF, + 0xC4, 0x2C, 0xFC, 0x09, 0x25, 0x38, 0x5B, 0x29, + 0x09, 0x77, 0xED, 0xCD, 0xF0, 0x73, 0x3B, 0x5A, + 0x89, 0x51, 0x56, 0x6E, 0xB5, 0xC7, 0x64, 0x80, + 0x65, 0x5C, 0xCE, 0x13, 0x9D, 0x2E, 0x7E, 0x84, + 0xA4, 0xDE, 0x3D, 0x52, 0xB8, 0xCB, 0x8F, 0x82, + 0x01, 0x3F, 0x6A, 0x22, 0x4B, 0xA3, 0xC0, 0x30, + 0x8A, 0xF1, 0xE6, 0xDD, 0x06, 0x7B, 0x18, 0xBD, + 0xD8, 0x27, 0x20, 0x16, 0xCD, 0x4D, 0x17, 0x77, + 0x56, 0xD4, 0x61, 0xC0, 0x1B, 0x0E, 0x8A, 0x6E, + 0x5F, 0xD8, 0x6D, 0x31, 0xD3, 0xC3, 0x02, 0x99, + 0x1A, 0x0C, 0xB9, 0x70, 0x4B, 0xDF, 0x8F, 0x65, + 0x45, 0x83, 0xC5, 0xA9, 0x71, 0xC1, 0xBB, 0x7A, + 0xFA, 0x21, 0x97, 0xFB, 0x23, 0x93, 0x7F, 0xB2, + 0x30, 0x8B, 0xA9, 0xD3, 0x0B, 0xDB, 0xA6, 0x66, + 0xEC, 0x37, 0x03, 0x6B, 0x30, 0x84, 0x44, 0x97, + 0x15, 0xAE, 0x19, 0x75, 0xAD, 0x1D, 0x01, 0xD7, + 0x57, 0xEC, 0x26, 0x5C, 0x84, 0x54, 0x9C, 0x4A, + 0xCA, 0x71, 0x4F, 0x35, 0xED, 0x3D, 0xD5, 0x03, + 0x83, 0x38, 0x22, 0x58, 0x80, 0x50, 0x30, 0xF0, + 0x70, 0xAB, 0x1D, 0x71, 0xA9, 0x19, 0x79, 0xB9, + 0x39, 0xE2, 0x54, 0x38, 0xE0, 0x50, 0x30, 0xF0, + 0x70, 0xAB, 0x1D, 0x71, 0xA9, 0x19, 0x79, 0xB9, + 0x39, 0xE2, 0x54, 0x38, 0xE0, 0x50, 0x30, 0xF0, + 0x70, 0xAB, 0x1D, 0x71, 0xA9, 0x19, 0x79, 0xB9, + 0x39, 0xE2, 0x7C, 0x19, 0xC1, 0x11, 0x55, 0x9C, + 0x1C, 0xA7, 0x03, 0x5F, 0x87, 0x37, 0x97, 0x41, + 0xC1, 0x7A, 0x7C, 0x10, 0xC8, 0x78, 0x64, 0xA3, + 0x23, 0x98, 0x82, 0xE3, 0x39, 0xE9, 0x79, 0xBE, + 0x3E, 0x85, 0xC3, 0xA2, 0x78, 0xA8, 0xB8, 0x76, + 0xF4, 0x4F, 0xF1, 0x92, 0x48, 0x98, 0x44, 0x83, + 0x03, 0xB8, 0x86, 0xF9, 0x23, 0xF3, 0x3F, 0xEA, + 0x68, 0xD3, 0x53, 0x7E, 0xA6, 0x97, 0x45, 0x80, + 0xB1, 0xDA, 0x69, 0xA7, 0xDF, 0x6C, 0x9D, 0xEC, + 0x69, 0x10, 0xED, 0x81, 0xDB, 0x02, 0x62, 0xC7, + 0x46, 0x9D, 0x0E, 0x60, 0xB8, 0x2D, 0x49, 0x89, + 0xA8, 0xC0, 0x73, 0xAE, 0xC2, 0x77, 0xF2, 0xA3, + 0x04, 0xC2, 0x84, 0xE8, 0x30, 0x80, 0xD6, 0x57, + 0xD7, 0x3D, 0x3E, 0x57, 0xAE, 0xA8, 0xCD, 0x24, + 0x77, 0xB1, 0xF7, 0x9B, 0x43, 0xF3, 0xA5, 0x24, + 0xA4, 0xCE, 0xC0, 0xA9, 0x40, 0x4B, 0x2E, 0xCF, + 0xF3, 0x2D, 0x1A, 0xCC, 0x11, 0x30, 0xE7, 0x22, + 0x03, 0x61, 0xD2, 0x17, 0x16, 0x24, 0x2D, 0xFD, + 0x54, 0xAC, 0xA3, 0x56, 0x93, 0xD3, 0x85, 0x04, + 0x84, 0x6E, 0x6D, 0x04, 0xFD, 0xF0, 0x95, 0x7C, + 0x6F, 0xA9, 0xEF, 0x83, 0x5B, 0xEB, 0x8B, 0x4B, + 0xCB, 0x10, 0xA6, 0xCA, 0x12, 0xA2, 0xC2, 0x02, + 0x82, 0x59, 0xEE, 0x82, 0x5E, 0xEE, 0x76, 0xA0, + 0x22, 0x99, }; static unsigned char vfs5011_init_06[] = { /* 2855 B */ - 0x02, 0xB0, 0x00, 0x62, 0x00, 0x03, 0x00, 0x09, - 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, - 0x04, 0x30, 0x01, 0x80, 0x64, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, - 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, - 0x20, 0x04, 0x30, 0xE6, 0x03, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, - 0xE7, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x4C, 0x20, 0x04, 0x30, 0xE8, 0x03, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, - 0x04, 0x30, 0x00, 0x92, 0x01, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, - 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x40, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x60, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x90, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xD8, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, - 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, - 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, - 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, - 0x30, 0x00, 0x02, 0xA8, 0x02, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, - 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, - 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, - 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, - 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x8B, 0x07, 0x20, 0x60, 0x8A, 0x07, 0x20, - 0xFF, 0x93, 0x07, 0x20, 0x61, 0x92, 0x07, 0x20, - 0xFF, 0x9B, 0x07, 0x20, 0x62, 0x9A, 0x07, 0x20, - 0xFF, 0xA3, 0x07, 0x20, 0x63, 0xA2, 0x07, 0x20, - 0xFF, 0xAB, 0x07, 0x20, 0x64, 0xAA, 0x07, 0x20, - 0xFF, 0xB3, 0x07, 0x20, 0x65, 0xB2, 0x07, 0x20, - 0xFF, 0xBB, 0x07, 0x20, 0x66, 0xBA, 0x07, 0x20, - 0xFF, 0xC3, 0x07, 0x20, 0x67, 0xC2, 0x07, 0x20, - 0xFF, 0xCB, 0x07, 0x20, 0x68, 0xCA, 0x07, 0x20, - 0xFF, 0xD3, 0x07, 0x20, 0x69, 0xD2, 0x07, 0x20, - 0xFF, 0xDB, 0x07, 0x20, 0x6A, 0xDA, 0x07, 0x20, - 0xFF, 0xE3, 0x07, 0x20, 0x6B, 0xE2, 0x07, 0x20, - 0xFF, 0xEB, 0x07, 0x20, 0x6C, 0xEA, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x6D, 0xF2, 0x07, 0x20, - 0xFF, 0xFB, 0x07, 0x20, 0x6E, 0xFA, 0x07, 0x20, - 0xFF, 0x85, 0x07, 0x20, 0x6F, 0x84, 0x07, 0x20, - 0xFF, 0x8D, 0x07, 0x20, 0x70, 0x8C, 0x07, 0x20, - 0xFF, 0x95, 0x07, 0x20, 0x71, 0x94, 0x07, 0x20, - 0xFF, 0x9D, 0x07, 0x20, 0x72, 0x9C, 0x07, 0x20, - 0xFF, 0xA5, 0x07, 0x20, 0x73, 0xA4, 0x07, 0x20, - 0xFF, 0xAD, 0x07, 0x20, 0x74, 0xAC, 0x07, 0x20, - 0xFF, 0xB5, 0x07, 0x20, 0x75, 0xB4, 0x07, 0x20, - 0xFF, 0xBD, 0x07, 0x20, 0x76, 0xBC, 0x07, 0x20, - 0xFF, 0xC5, 0x07, 0x20, 0x77, 0xC4, 0x07, 0x20, - 0xFF, 0xCD, 0x07, 0x20, 0x78, 0xCC, 0x07, 0x20, - 0xFF, 0xD5, 0x07, 0x20, 0x79, 0xD4, 0x07, 0x20, - 0xFF, 0xDD, 0x07, 0x20, 0x7A, 0xDC, 0x07, 0x20, - 0xFF, 0xE5, 0x07, 0x20, 0x7B, 0xE4, 0x07, 0x20, - 0xFF, 0xED, 0x07, 0x20, 0x7C, 0xEC, 0x07, 0x20, - 0xFF, 0xF5, 0x07, 0x20, 0x7D, 0xF4, 0x07, 0x20, - 0xFF, 0xFD, 0x07, 0x20, 0x7E, 0xFC, 0x07, 0x20, - 0xFF, 0x87, 0x07, 0x20, 0x7F, 0x86, 0x07, 0x20, - 0xFF, 0x8F, 0x07, 0x20, 0x80, 0x8E, 0x07, 0x20, - 0xFF, 0x97, 0x07, 0x20, 0x81, 0x96, 0x07, 0x20, - 0xFF, 0x9F, 0x07, 0x20, 0x82, 0x9E, 0x07, 0x20, - 0xFF, 0xA7, 0x07, 0x20, 0x83, 0xA6, 0x07, 0x20, - 0xFF, 0xAF, 0x07, 0x20, 0x84, 0xAE, 0x07, 0x20, - 0xFF, 0xB7, 0x07, 0x20, 0x85, 0xB6, 0x07, 0x20, - 0xFF, 0xBF, 0x07, 0x20, 0x86, 0xBE, 0x07, 0x20, - 0xFF, 0xC7, 0x07, 0x20, 0x87, 0xC6, 0x07, 0x20, - 0xFF, 0xCF, 0x07, 0x20, 0x88, 0xCE, 0x07, 0x20, - 0xFF, 0xD7, 0x07, 0x20, 0x89, 0xD6, 0x07, 0x20, - 0xFF, 0xDF, 0x07, 0x20, 0x8A, 0xDE, 0x07, 0x20, - 0xFF, 0xE7, 0x07, 0x20, 0x8B, 0xE6, 0x07, 0x20, - 0xFF, 0xEF, 0x07, 0x20, 0x8C, 0xEE, 0x07, 0x20, - 0xFF, 0xF7, 0x07, 0x20, 0x8D, 0xF6, 0x07, 0x20, - 0xFF, 0xFF, 0x07, 0x20, 0x8E, 0xFE, 0x07, 0x20, - 0xFF, 0x83, 0xA7, 0x00, 0x5F, 0x82, 0xA7, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, - 0xFF, 0x83, 0x27, 0x20, 0x5F, 0x82, 0x27, 0x20, - 0xFF, 0x8B, 0x27, 0x20, 0x60, 0x8A, 0x27, 0x20, - 0xFF, 0x93, 0x27, 0x20, 0x61, 0x92, 0x27, 0x20, - 0xFF, 0x9B, 0x27, 0x20, 0x62, 0x9A, 0x27, 0x20, - 0xFF, 0xA3, 0x27, 0x20, 0x63, 0xA2, 0x27, 0x20, - 0xFF, 0xAB, 0x27, 0x20, 0x64, 0xAA, 0x27, 0x20, - 0xFF, 0xB3, 0x27, 0x20, 0x65, 0xB2, 0x27, 0x20, - 0xFF, 0xBB, 0x27, 0x20, 0x66, 0xBA, 0x27, 0x20, - 0xFF, 0xC3, 0x27, 0x20, 0x67, 0xC2, 0x27, 0x20, - 0xFF, 0xCB, 0x27, 0x20, 0x68, 0xCA, 0x27, 0x20, - 0xFF, 0xD3, 0x27, 0x20, 0x69, 0xD2, 0x27, 0x20, - 0xFF, 0xDB, 0x27, 0x20, 0x6A, 0xDA, 0x27, 0x20, - 0xFF, 0xE3, 0x27, 0x20, 0x6B, 0xE2, 0x27, 0x20, - 0xFF, 0xEB, 0x27, 0x20, 0x6C, 0xEA, 0x27, 0x20, - 0xFF, 0xF3, 0x27, 0x20, 0x6D, 0xF2, 0x27, 0x20, - 0xFF, 0xFB, 0x27, 0x20, 0x6E, 0xFA, 0x27, 0x20, - 0xFF, 0x85, 0x27, 0x20, 0x6F, 0x84, 0x27, 0x20, - 0xFF, 0x8D, 0x27, 0x20, 0x70, 0x8C, 0x27, 0x20, - 0xFF, 0x95, 0x27, 0x20, 0x71, 0x94, 0x27, 0x20, - 0xFF, 0x9D, 0x27, 0x20, 0x72, 0x9C, 0x27, 0x20, - 0xFF, 0xA5, 0x27, 0x20, 0x73, 0xA4, 0x27, 0x20, - 0xFF, 0xAD, 0x27, 0x20, 0x74, 0xAC, 0x27, 0x20, - 0xFF, 0xB5, 0x27, 0x20, 0x75, 0xB4, 0x27, 0x20, - 0xFF, 0xBD, 0x27, 0x20, 0x76, 0xBC, 0x27, 0x20, - 0xFF, 0xC5, 0x27, 0x20, 0x77, 0xC4, 0x27, 0x20, - 0xFF, 0xCD, 0x27, 0x20, 0x78, 0xCC, 0x27, 0x20, - 0xFF, 0xD5, 0x27, 0x20, 0x79, 0xD4, 0x27, 0x20, - 0xFF, 0xDD, 0x27, 0x20, 0x7A, 0xDC, 0x27, 0x20, - 0xFF, 0xE5, 0x27, 0x20, 0x7B, 0xE4, 0x27, 0x20, - 0xFF, 0xED, 0x27, 0x20, 0x7C, 0xEC, 0x27, 0x20, - 0xFF, 0xF5, 0x27, 0x20, 0x7D, 0xF4, 0x27, 0x20, - 0xFF, 0xFD, 0x27, 0x20, 0x7E, 0xFC, 0x27, 0x20, - 0xFF, 0x87, 0x27, 0x20, 0x7F, 0x86, 0x27, 0x20, - 0xFF, 0x8F, 0x27, 0x20, 0x80, 0x8E, 0x27, 0x20, - 0xFF, 0x97, 0x27, 0x20, 0x81, 0x96, 0x27, 0x20, - 0xFF, 0x9F, 0x27, 0x20, 0x82, 0x9E, 0x27, 0x20, - 0xFF, 0xA7, 0x27, 0x20, 0x83, 0xA6, 0x27, 0x20, - 0xFF, 0xAF, 0x27, 0x20, 0x84, 0xAE, 0x27, 0x20, - 0xFF, 0xB7, 0x27, 0x20, 0x85, 0xB6, 0x27, 0x20, - 0xFF, 0xBF, 0x27, 0x20, 0x86, 0xBE, 0x27, 0x20, - 0xFF, 0xC7, 0x27, 0x20, 0x87, 0xC6, 0x27, 0x20, - 0xFF, 0xCF, 0x27, 0x20, 0x88, 0xCE, 0x27, 0x20, - 0xFF, 0xD7, 0x27, 0x20, 0x89, 0xD6, 0x27, 0x20, - 0xFF, 0xDF, 0x27, 0x20, 0x8A, 0xDE, 0x27, 0x20, - 0xFF, 0xE7, 0x27, 0x20, 0x8B, 0xE6, 0x27, 0x20, - 0xFF, 0xEF, 0x27, 0x20, 0x8C, 0xEE, 0x27, 0x20, - 0xFF, 0xF7, 0x27, 0x20, 0x8D, 0xF6, 0x27, 0x20, - 0xFF, 0xFF, 0x27, 0x20, 0x8E, 0xFE, 0x27, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, - 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, - 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, - 0x04, 0x0C, 0x00, 0x01, 0x00, 0x00, 0x0D, 0x00, - 0x78, 0x01, 0x50, 0x01, 0x00, 0x00, 0x0E, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x6E, - 0x00, 0x65, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, - 0x00, 0x6E, 0x00, 0x67, 0x00, 0x5C, 0x00, 0x70, - 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x03, 0x00, - 0x00, 0x00, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x07, - 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x0C, 0x00, - 0x00, 0x38, 0x02, 0x07, 0x00, 0x00, 0xFD, 0x00, - 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x08, - 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x0C, 0x00, - 0x00, 0x38, 0x02, 0x08, 0x00, 0x00, 0xFD, 0x00, - 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x02, - 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x0C, 0x00, - 0x00, 0x38, 0x02, 0x02, 0x00, 0x00, 0xFD, 0x00, - 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x03, - 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x0C, 0x00, - 0x00, 0x38, 0x02, 0x03, 0x00, 0x00, 0xFD, 0x00, - 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x04, - 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x0C, 0x00, - 0x00, 0x38, 0x02, 0x04, 0x00, 0x00, 0xFD, 0x00, - 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x05, - 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x0C, 0x00, - 0x00, 0x38, 0x02, 0x05, 0x00, 0x00, 0xFD, 0x00, - 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x06, - 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x0C, 0x00, - 0x00, 0x38, 0x02, 0x06, 0x00, 0x00, 0xFD, 0x00, - 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x38, 0x02, 0x03, - 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x10, 0x00, - 0x00, 0x38, 0x00, 0x04, 0x00, 0x00, 0xFD, 0x00, - 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x38, 0x02, 0x04, - 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x10, 0x00, - 0x00, 0x38, 0x00, 0x05, 0x00, 0x00, 0xFD, 0x00, - 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x38, 0x02, 0x05, - 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x10, 0x00, - 0x00, 0x38, 0x00, 0x06, 0x00, 0x00, 0xFD, 0x00, - 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x38, 0x02, 0x06, - 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x10, 0x00, - 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0xFD, 0x00, - 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x38, 0x02, 0x07, - 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x10, 0x00, - 0x00, 0x38, 0x00, 0x08, 0x00, 0x00, 0xFD, 0x00, - 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x38, 0x02, 0x08, - 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x10, 0x00, - 0x00, 0x38, 0x00, 0x09, 0x00, 0x00, 0xFD, 0x00, - 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x38, 0x02, 0x09, - 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x10, 0x00, - 0x00, 0x38, 0x00, 0x0A, 0x00, 0x00, 0xFD, 0x00, - 0xFF, 0xFF, 0x0E, 0x00, 0xE0, 0x00, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x1F, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, - 0x01, 0x01, 0x00, 0x01, 0x00, 0x1F, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x00, 0x1F, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, - 0x02, 0x01, 0x01, 0x01, 0x00, 0x1F, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x1F, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, - 0x02, 0x01, 0x01, 0x01, 0x01, 0x1F, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, - 0x04, 0x01, 0x01, 0x01, 0x01, 0x1F, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, - 0x04, 0x01, 0x02, 0x01, 0x01, 0x1F, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, - 0x08, 0x01, 0x02, 0x01, 0x01, 0x1F, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, - 0x08, 0x01, 0x04, 0x01, 0x01, 0x1F, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, - 0x10, 0x01, 0x04, 0x01, 0x01, 0x1F, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, - 0x10, 0x01, 0x08, 0x01, 0x01, 0x1F, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, - 0x10, 0x01, 0x08, 0x01, 0x02, 0x1F, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, - 0x10, 0x01, 0x10, 0x01, 0x02, 0x1F, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x0F, 0x00, - 0x01, 0x00, 0x02, 0x10, 0x00, 0x01, 0x00, 0x01, - 0x11, 0x00, 0x02, 0x00, 0x0E, 0x00, 0x12, 0x00, - 0x01, 0x00, 0x0E, 0x15, 0x00, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x20, 0x28, 0x00, 0x00, + 0x02, 0xB0, 0x00, 0x62, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, + 0x04, 0x30, 0x01, 0x80, 0x64, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, + 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, + 0x20, 0x04, 0x30, 0xE6, 0x03, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, + 0xE7, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x4C, 0x20, 0x04, 0x30, 0xE8, 0x03, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, + 0x04, 0x30, 0x00, 0x92, 0x01, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, + 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x40, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x60, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x90, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xD8, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, + 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, + 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, + 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, + 0x30, 0x00, 0x02, 0xA8, 0x02, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, + 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, + 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, + 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, + 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x8B, 0x07, 0x20, 0x60, 0x8A, 0x07, 0x20, + 0xFF, 0x93, 0x07, 0x20, 0x61, 0x92, 0x07, 0x20, + 0xFF, 0x9B, 0x07, 0x20, 0x62, 0x9A, 0x07, 0x20, + 0xFF, 0xA3, 0x07, 0x20, 0x63, 0xA2, 0x07, 0x20, + 0xFF, 0xAB, 0x07, 0x20, 0x64, 0xAA, 0x07, 0x20, + 0xFF, 0xB3, 0x07, 0x20, 0x65, 0xB2, 0x07, 0x20, + 0xFF, 0xBB, 0x07, 0x20, 0x66, 0xBA, 0x07, 0x20, + 0xFF, 0xC3, 0x07, 0x20, 0x67, 0xC2, 0x07, 0x20, + 0xFF, 0xCB, 0x07, 0x20, 0x68, 0xCA, 0x07, 0x20, + 0xFF, 0xD3, 0x07, 0x20, 0x69, 0xD2, 0x07, 0x20, + 0xFF, 0xDB, 0x07, 0x20, 0x6A, 0xDA, 0x07, 0x20, + 0xFF, 0xE3, 0x07, 0x20, 0x6B, 0xE2, 0x07, 0x20, + 0xFF, 0xEB, 0x07, 0x20, 0x6C, 0xEA, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x6D, 0xF2, 0x07, 0x20, + 0xFF, 0xFB, 0x07, 0x20, 0x6E, 0xFA, 0x07, 0x20, + 0xFF, 0x85, 0x07, 0x20, 0x6F, 0x84, 0x07, 0x20, + 0xFF, 0x8D, 0x07, 0x20, 0x70, 0x8C, 0x07, 0x20, + 0xFF, 0x95, 0x07, 0x20, 0x71, 0x94, 0x07, 0x20, + 0xFF, 0x9D, 0x07, 0x20, 0x72, 0x9C, 0x07, 0x20, + 0xFF, 0xA5, 0x07, 0x20, 0x73, 0xA4, 0x07, 0x20, + 0xFF, 0xAD, 0x07, 0x20, 0x74, 0xAC, 0x07, 0x20, + 0xFF, 0xB5, 0x07, 0x20, 0x75, 0xB4, 0x07, 0x20, + 0xFF, 0xBD, 0x07, 0x20, 0x76, 0xBC, 0x07, 0x20, + 0xFF, 0xC5, 0x07, 0x20, 0x77, 0xC4, 0x07, 0x20, + 0xFF, 0xCD, 0x07, 0x20, 0x78, 0xCC, 0x07, 0x20, + 0xFF, 0xD5, 0x07, 0x20, 0x79, 0xD4, 0x07, 0x20, + 0xFF, 0xDD, 0x07, 0x20, 0x7A, 0xDC, 0x07, 0x20, + 0xFF, 0xE5, 0x07, 0x20, 0x7B, 0xE4, 0x07, 0x20, + 0xFF, 0xED, 0x07, 0x20, 0x7C, 0xEC, 0x07, 0x20, + 0xFF, 0xF5, 0x07, 0x20, 0x7D, 0xF4, 0x07, 0x20, + 0xFF, 0xFD, 0x07, 0x20, 0x7E, 0xFC, 0x07, 0x20, + 0xFF, 0x87, 0x07, 0x20, 0x7F, 0x86, 0x07, 0x20, + 0xFF, 0x8F, 0x07, 0x20, 0x80, 0x8E, 0x07, 0x20, + 0xFF, 0x97, 0x07, 0x20, 0x81, 0x96, 0x07, 0x20, + 0xFF, 0x9F, 0x07, 0x20, 0x82, 0x9E, 0x07, 0x20, + 0xFF, 0xA7, 0x07, 0x20, 0x83, 0xA6, 0x07, 0x20, + 0xFF, 0xAF, 0x07, 0x20, 0x84, 0xAE, 0x07, 0x20, + 0xFF, 0xB7, 0x07, 0x20, 0x85, 0xB6, 0x07, 0x20, + 0xFF, 0xBF, 0x07, 0x20, 0x86, 0xBE, 0x07, 0x20, + 0xFF, 0xC7, 0x07, 0x20, 0x87, 0xC6, 0x07, 0x20, + 0xFF, 0xCF, 0x07, 0x20, 0x88, 0xCE, 0x07, 0x20, + 0xFF, 0xD7, 0x07, 0x20, 0x89, 0xD6, 0x07, 0x20, + 0xFF, 0xDF, 0x07, 0x20, 0x8A, 0xDE, 0x07, 0x20, + 0xFF, 0xE7, 0x07, 0x20, 0x8B, 0xE6, 0x07, 0x20, + 0xFF, 0xEF, 0x07, 0x20, 0x8C, 0xEE, 0x07, 0x20, + 0xFF, 0xF7, 0x07, 0x20, 0x8D, 0xF6, 0x07, 0x20, + 0xFF, 0xFF, 0x07, 0x20, 0x8E, 0xFE, 0x07, 0x20, + 0xFF, 0x83, 0xA7, 0x00, 0x5F, 0x82, 0xA7, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x00, 0x5F, 0x82, 0x27, 0x00, + 0xFF, 0x83, 0x27, 0x20, 0x5F, 0x82, 0x27, 0x20, + 0xFF, 0x8B, 0x27, 0x20, 0x60, 0x8A, 0x27, 0x20, + 0xFF, 0x93, 0x27, 0x20, 0x61, 0x92, 0x27, 0x20, + 0xFF, 0x9B, 0x27, 0x20, 0x62, 0x9A, 0x27, 0x20, + 0xFF, 0xA3, 0x27, 0x20, 0x63, 0xA2, 0x27, 0x20, + 0xFF, 0xAB, 0x27, 0x20, 0x64, 0xAA, 0x27, 0x20, + 0xFF, 0xB3, 0x27, 0x20, 0x65, 0xB2, 0x27, 0x20, + 0xFF, 0xBB, 0x27, 0x20, 0x66, 0xBA, 0x27, 0x20, + 0xFF, 0xC3, 0x27, 0x20, 0x67, 0xC2, 0x27, 0x20, + 0xFF, 0xCB, 0x27, 0x20, 0x68, 0xCA, 0x27, 0x20, + 0xFF, 0xD3, 0x27, 0x20, 0x69, 0xD2, 0x27, 0x20, + 0xFF, 0xDB, 0x27, 0x20, 0x6A, 0xDA, 0x27, 0x20, + 0xFF, 0xE3, 0x27, 0x20, 0x6B, 0xE2, 0x27, 0x20, + 0xFF, 0xEB, 0x27, 0x20, 0x6C, 0xEA, 0x27, 0x20, + 0xFF, 0xF3, 0x27, 0x20, 0x6D, 0xF2, 0x27, 0x20, + 0xFF, 0xFB, 0x27, 0x20, 0x6E, 0xFA, 0x27, 0x20, + 0xFF, 0x85, 0x27, 0x20, 0x6F, 0x84, 0x27, 0x20, + 0xFF, 0x8D, 0x27, 0x20, 0x70, 0x8C, 0x27, 0x20, + 0xFF, 0x95, 0x27, 0x20, 0x71, 0x94, 0x27, 0x20, + 0xFF, 0x9D, 0x27, 0x20, 0x72, 0x9C, 0x27, 0x20, + 0xFF, 0xA5, 0x27, 0x20, 0x73, 0xA4, 0x27, 0x20, + 0xFF, 0xAD, 0x27, 0x20, 0x74, 0xAC, 0x27, 0x20, + 0xFF, 0xB5, 0x27, 0x20, 0x75, 0xB4, 0x27, 0x20, + 0xFF, 0xBD, 0x27, 0x20, 0x76, 0xBC, 0x27, 0x20, + 0xFF, 0xC5, 0x27, 0x20, 0x77, 0xC4, 0x27, 0x20, + 0xFF, 0xCD, 0x27, 0x20, 0x78, 0xCC, 0x27, 0x20, + 0xFF, 0xD5, 0x27, 0x20, 0x79, 0xD4, 0x27, 0x20, + 0xFF, 0xDD, 0x27, 0x20, 0x7A, 0xDC, 0x27, 0x20, + 0xFF, 0xE5, 0x27, 0x20, 0x7B, 0xE4, 0x27, 0x20, + 0xFF, 0xED, 0x27, 0x20, 0x7C, 0xEC, 0x27, 0x20, + 0xFF, 0xF5, 0x27, 0x20, 0x7D, 0xF4, 0x27, 0x20, + 0xFF, 0xFD, 0x27, 0x20, 0x7E, 0xFC, 0x27, 0x20, + 0xFF, 0x87, 0x27, 0x20, 0x7F, 0x86, 0x27, 0x20, + 0xFF, 0x8F, 0x27, 0x20, 0x80, 0x8E, 0x27, 0x20, + 0xFF, 0x97, 0x27, 0x20, 0x81, 0x96, 0x27, 0x20, + 0xFF, 0x9F, 0x27, 0x20, 0x82, 0x9E, 0x27, 0x20, + 0xFF, 0xA7, 0x27, 0x20, 0x83, 0xA6, 0x27, 0x20, + 0xFF, 0xAF, 0x27, 0x20, 0x84, 0xAE, 0x27, 0x20, + 0xFF, 0xB7, 0x27, 0x20, 0x85, 0xB6, 0x27, 0x20, + 0xFF, 0xBF, 0x27, 0x20, 0x86, 0xBE, 0x27, 0x20, + 0xFF, 0xC7, 0x27, 0x20, 0x87, 0xC6, 0x27, 0x20, + 0xFF, 0xCF, 0x27, 0x20, 0x88, 0xCE, 0x27, 0x20, + 0xFF, 0xD7, 0x27, 0x20, 0x89, 0xD6, 0x27, 0x20, + 0xFF, 0xDF, 0x27, 0x20, 0x8A, 0xDE, 0x27, 0x20, + 0xFF, 0xE7, 0x27, 0x20, 0x8B, 0xE6, 0x27, 0x20, + 0xFF, 0xEF, 0x27, 0x20, 0x8C, 0xEE, 0x27, 0x20, + 0xFF, 0xF7, 0x27, 0x20, 0x8D, 0xF6, 0x27, 0x20, + 0xFF, 0xFF, 0x27, 0x20, 0x8E, 0xFE, 0x27, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, + 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, + 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x04, 0x0C, 0x00, 0x01, 0x00, 0x00, 0x0D, 0x00, + 0x78, 0x01, 0x50, 0x01, 0x00, 0x00, 0x0E, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x6E, + 0x00, 0x65, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, + 0x00, 0x6E, 0x00, 0x67, 0x00, 0x5C, 0x00, 0x70, + 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x03, 0x00, + 0x00, 0x00, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x07, + 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x0C, 0x00, + 0x00, 0x38, 0x02, 0x07, 0x00, 0x00, 0xFD, 0x00, + 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x08, + 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x0C, 0x00, + 0x00, 0x38, 0x02, 0x08, 0x00, 0x00, 0xFD, 0x00, + 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x02, + 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x0C, 0x00, + 0x00, 0x38, 0x02, 0x02, 0x00, 0x00, 0xFD, 0x00, + 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x03, + 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x0C, 0x00, + 0x00, 0x38, 0x02, 0x03, 0x00, 0x00, 0xFD, 0x00, + 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x04, + 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x0C, 0x00, + 0x00, 0x38, 0x02, 0x04, 0x00, 0x00, 0xFD, 0x00, + 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x05, + 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x0C, 0x00, + 0x00, 0x38, 0x02, 0x05, 0x00, 0x00, 0xFD, 0x00, + 0xFF, 0xFF, 0x0C, 0x00, 0x00, 0x38, 0x00, 0x06, + 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x0C, 0x00, + 0x00, 0x38, 0x02, 0x06, 0x00, 0x00, 0xFD, 0x00, + 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x38, 0x02, 0x03, + 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x10, 0x00, + 0x00, 0x38, 0x00, 0x04, 0x00, 0x00, 0xFD, 0x00, + 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x38, 0x02, 0x04, + 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x10, 0x00, + 0x00, 0x38, 0x00, 0x05, 0x00, 0x00, 0xFD, 0x00, + 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x38, 0x02, 0x05, + 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x10, 0x00, + 0x00, 0x38, 0x00, 0x06, 0x00, 0x00, 0xFD, 0x00, + 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x38, 0x02, 0x06, + 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x10, 0x00, + 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0xFD, 0x00, + 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x38, 0x02, 0x07, + 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x10, 0x00, + 0x00, 0x38, 0x00, 0x08, 0x00, 0x00, 0xFD, 0x00, + 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x38, 0x02, 0x08, + 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x10, 0x00, + 0x00, 0x38, 0x00, 0x09, 0x00, 0x00, 0xFD, 0x00, + 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x38, 0x02, 0x09, + 0x00, 0x00, 0xFD, 0x00, 0xFF, 0xFF, 0x10, 0x00, + 0x00, 0x38, 0x00, 0x0A, 0x00, 0x00, 0xFD, 0x00, + 0xFF, 0xFF, 0x0E, 0x00, 0xE0, 0x00, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, + 0x01, 0x01, 0x00, 0x01, 0x00, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, + 0x02, 0x01, 0x01, 0x01, 0x00, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, + 0x02, 0x01, 0x01, 0x01, 0x01, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, + 0x04, 0x01, 0x01, 0x01, 0x01, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, + 0x04, 0x01, 0x02, 0x01, 0x01, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, + 0x08, 0x01, 0x02, 0x01, 0x01, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, + 0x08, 0x01, 0x04, 0x01, 0x01, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, + 0x10, 0x01, 0x04, 0x01, 0x01, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, + 0x10, 0x01, 0x08, 0x01, 0x01, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, + 0x10, 0x01, 0x08, 0x01, 0x02, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x00, 0x01, + 0x10, 0x01, 0x10, 0x01, 0x02, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x0F, 0x00, + 0x01, 0x00, 0x02, 0x10, 0x00, 0x01, 0x00, 0x01, + 0x11, 0x00, 0x02, 0x00, 0x0E, 0x00, 0x12, 0x00, + 0x01, 0x00, 0x0E, 0x15, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x28, 0x00, 0x00, }; static unsigned char vfs5011_init_07[] = { /* 2503 B */ - 0x02, 0xB0, 0x00, 0x00, 0x01, 0x03, 0x00, 0x09, - 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, - 0x04, 0x30, 0x01, 0x80, 0x4F, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, - 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, - 0x20, 0x04, 0x30, 0xE6, 0x03, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, - 0xE7, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x4C, 0x20, 0x04, 0x30, 0xE8, 0x03, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, - 0x04, 0x30, 0x00, 0x3E, 0x01, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x04, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, - 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x18, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, - 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x40, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, - 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x54, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x60, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, - 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x90, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, - 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xCC, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xD8, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, - 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, - 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, - 0x00, 0x40, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, - 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, - 0x30, 0x00, 0x02, 0xA8, 0x02, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, - 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, - 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, - 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, - 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x8B, 0x07, 0x20, 0x60, 0x8A, 0x07, 0x20, - 0xFF, 0x93, 0x07, 0x20, 0x61, 0x92, 0x07, 0x20, - 0xFF, 0x9B, 0x07, 0x20, 0x62, 0x9A, 0x07, 0x20, - 0xFF, 0xA3, 0x07, 0x20, 0x63, 0xA2, 0x07, 0x20, - 0xFF, 0xAB, 0x07, 0x20, 0x64, 0xAA, 0x07, 0x20, - 0xFF, 0xB3, 0x07, 0x20, 0x65, 0xB2, 0x07, 0x20, - 0xFF, 0xBB, 0x07, 0x20, 0x66, 0xBA, 0x07, 0x20, - 0xFF, 0xC3, 0x07, 0x20, 0x67, 0xC2, 0x07, 0x20, - 0xFF, 0xCB, 0x07, 0x20, 0x68, 0xCA, 0x07, 0x20, - 0xFF, 0xD3, 0x07, 0x20, 0x69, 0xD2, 0x07, 0x20, - 0xFF, 0xDB, 0x07, 0x20, 0x6A, 0xDA, 0x07, 0x20, - 0xFF, 0xE3, 0x07, 0x20, 0x6B, 0xE2, 0x07, 0x20, - 0xFF, 0xEB, 0x07, 0x20, 0x6C, 0xEA, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x6D, 0xF2, 0x07, 0x20, - 0xFF, 0xFB, 0x07, 0x20, 0x6E, 0xFA, 0x07, 0x20, - 0xFF, 0x85, 0x07, 0x20, 0x6F, 0x84, 0x07, 0x20, - 0xFF, 0x8D, 0x07, 0x20, 0x70, 0x8C, 0x07, 0x20, - 0xFF, 0x95, 0x07, 0x20, 0x71, 0x94, 0x07, 0x20, - 0xFF, 0x9D, 0x07, 0x20, 0x72, 0x9C, 0x07, 0x20, - 0xFF, 0xA5, 0x07, 0x20, 0x73, 0xA4, 0x07, 0x20, - 0xFF, 0xAD, 0x07, 0x20, 0x74, 0xAC, 0x07, 0x20, - 0xFF, 0xB5, 0x07, 0x20, 0x75, 0xB4, 0x07, 0x20, - 0xFF, 0xBD, 0x07, 0x20, 0x76, 0xBC, 0x07, 0x20, - 0xFF, 0xC5, 0x07, 0x20, 0x77, 0xC4, 0x07, 0x20, - 0xFF, 0xCD, 0x07, 0x20, 0x78, 0xCC, 0x07, 0x20, - 0xFF, 0xD5, 0x07, 0x20, 0x79, 0xD4, 0x07, 0x20, - 0xFF, 0xDD, 0x07, 0x20, 0x7A, 0xDC, 0x07, 0x20, - 0xFF, 0xE5, 0x07, 0x20, 0x7B, 0xE4, 0x07, 0x20, - 0xFF, 0xED, 0x07, 0x20, 0x7C, 0xEC, 0x07, 0x20, - 0xFF, 0xF5, 0x07, 0x20, 0x7D, 0xF4, 0x07, 0x20, - 0xFF, 0xFD, 0x07, 0x20, 0x7E, 0xFC, 0x07, 0x20, - 0xFF, 0x87, 0x07, 0x20, 0x7F, 0x86, 0x07, 0x20, - 0xFF, 0x8F, 0x07, 0x20, 0x80, 0x8E, 0x07, 0x20, - 0xFF, 0x97, 0x07, 0x20, 0x81, 0x96, 0x07, 0x20, - 0xFF, 0x9F, 0x07, 0x20, 0x82, 0x9E, 0x07, 0x20, - 0xFF, 0xA7, 0x07, 0x20, 0x83, 0xA6, 0x07, 0x20, - 0xFF, 0xAF, 0x07, 0x20, 0x84, 0xAE, 0x07, 0x20, - 0xFF, 0xB7, 0x07, 0x20, 0x85, 0xB6, 0x07, 0x20, - 0xFF, 0xBF, 0x07, 0x20, 0x86, 0xBE, 0x07, 0x20, - 0xFF, 0xC7, 0x07, 0x20, 0x87, 0xC6, 0x07, 0x20, - 0xFF, 0xCF, 0x07, 0x20, 0x88, 0xCE, 0x07, 0x20, - 0xFF, 0xD7, 0x07, 0x20, 0x89, 0xD6, 0x07, 0x20, - 0xFF, 0xDF, 0x07, 0x20, 0x8A, 0xDE, 0x07, 0x20, - 0xFF, 0xE7, 0x07, 0x20, 0x8B, 0xE6, 0x07, 0x20, - 0xFF, 0xEF, 0x07, 0x20, 0x8C, 0xEE, 0x07, 0x20, - 0xFF, 0xF7, 0x07, 0x20, 0x8D, 0xF6, 0x07, 0x20, - 0xFF, 0xFF, 0x07, 0x20, 0x8E, 0xFE, 0x07, 0x20, - 0xFF, 0xFF, 0x07, 0x20, 0x8E, 0xFE, 0x07, 0x20, - 0xFF, 0xF7, 0x07, 0x20, 0x8D, 0xF6, 0x07, 0x20, - 0xFF, 0xEF, 0x07, 0x20, 0x8C, 0xEE, 0x07, 0x20, - 0xFF, 0xE7, 0x07, 0x20, 0x8B, 0xE6, 0x07, 0x20, - 0xFF, 0xDF, 0x07, 0x20, 0x8A, 0xDE, 0x07, 0x20, - 0xFF, 0xD7, 0x07, 0x20, 0x89, 0xD6, 0x07, 0x20, - 0xFF, 0xCF, 0x07, 0x20, 0x88, 0xCE, 0x07, 0x20, - 0xFF, 0xC7, 0x07, 0x20, 0x87, 0xC6, 0x07, 0x20, - 0xFF, 0xBF, 0x07, 0x20, 0x86, 0xBE, 0x07, 0x20, - 0xFF, 0xB7, 0x07, 0x20, 0x85, 0xB6, 0x07, 0x20, - 0xFF, 0xAF, 0x07, 0x20, 0x84, 0xAE, 0x07, 0x20, - 0xFF, 0xA7, 0x07, 0x20, 0x83, 0xA6, 0x07, 0x20, - 0xFF, 0x9F, 0x07, 0x20, 0x82, 0x9E, 0x07, 0x20, - 0xFF, 0x97, 0x07, 0x20, 0x81, 0x96, 0x07, 0x20, - 0xFF, 0x8F, 0x07, 0x20, 0x80, 0x8E, 0x07, 0x20, - 0xFF, 0x87, 0x07, 0x20, 0x7F, 0x86, 0x07, 0x20, - 0xFF, 0xFD, 0x07, 0x20, 0x7E, 0xFC, 0x07, 0x20, - 0xFF, 0xF5, 0x07, 0x20, 0x7D, 0xF4, 0x07, 0x20, - 0xFF, 0xED, 0x07, 0x20, 0x7C, 0xEC, 0x07, 0x20, - 0xFF, 0xE5, 0x07, 0x20, 0x7B, 0xE4, 0x07, 0x20, - 0xFF, 0xDD, 0x07, 0x20, 0x7A, 0xDC, 0x07, 0x20, - 0xFF, 0xD5, 0x07, 0x20, 0x79, 0xD4, 0x07, 0x20, - 0xFF, 0xCD, 0x07, 0x20, 0x78, 0xCC, 0x07, 0x20, - 0xFF, 0xC5, 0x07, 0x20, 0x77, 0xC4, 0x07, 0x20, - 0xFF, 0xBD, 0x07, 0x20, 0x76, 0xBC, 0x07, 0x20, - 0xFF, 0xB5, 0x07, 0x20, 0x75, 0xB4, 0x07, 0x20, - 0xFF, 0xAD, 0x07, 0x20, 0x74, 0xAC, 0x07, 0x20, - 0xFF, 0xA5, 0x07, 0x20, 0x73, 0xA4, 0x07, 0x20, - 0xFF, 0x9D, 0x07, 0x20, 0x72, 0x9C, 0x07, 0x20, - 0xFF, 0x95, 0x07, 0x20, 0x71, 0x94, 0x07, 0x20, - 0xFF, 0x8D, 0x07, 0x20, 0x70, 0x8C, 0x07, 0x20, - 0xFF, 0x85, 0x07, 0x20, 0x6F, 0x84, 0x07, 0x20, - 0xFF, 0xFB, 0x07, 0x20, 0x6E, 0xFA, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x6D, 0xF2, 0x07, 0x20, - 0xFF, 0xEB, 0x07, 0x20, 0x6C, 0xEA, 0x07, 0x20, - 0xFF, 0xE3, 0x07, 0x20, 0x6B, 0xE2, 0x07, 0x20, - 0xFF, 0xDB, 0x07, 0x20, 0x6A, 0xDA, 0x07, 0x20, - 0xFF, 0xD3, 0x07, 0x20, 0x69, 0xD2, 0x07, 0x20, - 0xFF, 0xCB, 0x07, 0x20, 0x68, 0xCA, 0x07, 0x20, - 0xFF, 0xC3, 0x07, 0x20, 0x67, 0xC2, 0x07, 0x20, - 0xFF, 0xBB, 0x07, 0x20, 0x66, 0xBA, 0x07, 0x20, - 0xFF, 0xB3, 0x07, 0x20, 0x65, 0xB2, 0x07, 0x20, - 0xFF, 0xAB, 0x07, 0x20, 0x64, 0xAA, 0x07, 0x20, - 0xFF, 0xA3, 0x07, 0x20, 0x63, 0xA2, 0x07, 0x20, - 0xFF, 0x9B, 0x07, 0x20, 0x62, 0x9A, 0x07, 0x20, - 0xFF, 0x93, 0x07, 0x20, 0x61, 0x92, 0x07, 0x20, - 0xFF, 0x8B, 0x07, 0x20, 0x60, 0x8A, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, - 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, - 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, - 0x04, 0x0C, 0x00, 0x01, 0x00, 0x03, 0x0D, 0x00, - 0x28, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x00, - 0x00, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x1C, 0x02, 0xB0, 0x01, 0x00, - 0x00, 0x00, 0x0E, 0x00, 0x10, 0x00, 0x00, 0x01, - 0x01, 0x01, 0x01, 0x00, 0x01, 0x1F, 0x08, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0F, 0x00, - 0x01, 0x00, 0x01, 0x10, 0x00, 0x01, 0x00, 0x01, - 0x11, 0x00, 0x02, 0x00, 0x00, 0x01, 0x12, 0x00, - 0x01, 0x00, 0x01, 0x05, 0x00, 0x0E, 0x00, 0x0C, - 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x08, 0x00, 0x00, 0x05, 0x00, 0x0E, - 0x00, 0x10, 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, - 0x00, 0x09, 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x08, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x44, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x50, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x15, 0x00, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x20, 0x28, 0x00, 0x00, + 0x02, 0xB0, 0x00, 0x00, 0x01, 0x03, 0x00, 0x09, + 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, + 0x04, 0x30, 0x01, 0x80, 0x4F, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, + 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, + 0x20, 0x04, 0x30, 0xE6, 0x03, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, + 0xE7, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x4C, 0x20, 0x04, 0x30, 0xE8, 0x03, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, + 0x04, 0x30, 0x00, 0x3E, 0x01, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x04, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, + 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x18, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, + 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x40, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, + 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x54, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x60, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, + 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x90, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, + 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xCC, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xD8, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, + 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, + 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, + 0x00, 0x40, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, + 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, + 0x30, 0x00, 0x02, 0xA8, 0x02, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, + 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, + 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, + 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, + 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x8B, 0x07, 0x20, 0x60, 0x8A, 0x07, 0x20, + 0xFF, 0x93, 0x07, 0x20, 0x61, 0x92, 0x07, 0x20, + 0xFF, 0x9B, 0x07, 0x20, 0x62, 0x9A, 0x07, 0x20, + 0xFF, 0xA3, 0x07, 0x20, 0x63, 0xA2, 0x07, 0x20, + 0xFF, 0xAB, 0x07, 0x20, 0x64, 0xAA, 0x07, 0x20, + 0xFF, 0xB3, 0x07, 0x20, 0x65, 0xB2, 0x07, 0x20, + 0xFF, 0xBB, 0x07, 0x20, 0x66, 0xBA, 0x07, 0x20, + 0xFF, 0xC3, 0x07, 0x20, 0x67, 0xC2, 0x07, 0x20, + 0xFF, 0xCB, 0x07, 0x20, 0x68, 0xCA, 0x07, 0x20, + 0xFF, 0xD3, 0x07, 0x20, 0x69, 0xD2, 0x07, 0x20, + 0xFF, 0xDB, 0x07, 0x20, 0x6A, 0xDA, 0x07, 0x20, + 0xFF, 0xE3, 0x07, 0x20, 0x6B, 0xE2, 0x07, 0x20, + 0xFF, 0xEB, 0x07, 0x20, 0x6C, 0xEA, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x6D, 0xF2, 0x07, 0x20, + 0xFF, 0xFB, 0x07, 0x20, 0x6E, 0xFA, 0x07, 0x20, + 0xFF, 0x85, 0x07, 0x20, 0x6F, 0x84, 0x07, 0x20, + 0xFF, 0x8D, 0x07, 0x20, 0x70, 0x8C, 0x07, 0x20, + 0xFF, 0x95, 0x07, 0x20, 0x71, 0x94, 0x07, 0x20, + 0xFF, 0x9D, 0x07, 0x20, 0x72, 0x9C, 0x07, 0x20, + 0xFF, 0xA5, 0x07, 0x20, 0x73, 0xA4, 0x07, 0x20, + 0xFF, 0xAD, 0x07, 0x20, 0x74, 0xAC, 0x07, 0x20, + 0xFF, 0xB5, 0x07, 0x20, 0x75, 0xB4, 0x07, 0x20, + 0xFF, 0xBD, 0x07, 0x20, 0x76, 0xBC, 0x07, 0x20, + 0xFF, 0xC5, 0x07, 0x20, 0x77, 0xC4, 0x07, 0x20, + 0xFF, 0xCD, 0x07, 0x20, 0x78, 0xCC, 0x07, 0x20, + 0xFF, 0xD5, 0x07, 0x20, 0x79, 0xD4, 0x07, 0x20, + 0xFF, 0xDD, 0x07, 0x20, 0x7A, 0xDC, 0x07, 0x20, + 0xFF, 0xE5, 0x07, 0x20, 0x7B, 0xE4, 0x07, 0x20, + 0xFF, 0xED, 0x07, 0x20, 0x7C, 0xEC, 0x07, 0x20, + 0xFF, 0xF5, 0x07, 0x20, 0x7D, 0xF4, 0x07, 0x20, + 0xFF, 0xFD, 0x07, 0x20, 0x7E, 0xFC, 0x07, 0x20, + 0xFF, 0x87, 0x07, 0x20, 0x7F, 0x86, 0x07, 0x20, + 0xFF, 0x8F, 0x07, 0x20, 0x80, 0x8E, 0x07, 0x20, + 0xFF, 0x97, 0x07, 0x20, 0x81, 0x96, 0x07, 0x20, + 0xFF, 0x9F, 0x07, 0x20, 0x82, 0x9E, 0x07, 0x20, + 0xFF, 0xA7, 0x07, 0x20, 0x83, 0xA6, 0x07, 0x20, + 0xFF, 0xAF, 0x07, 0x20, 0x84, 0xAE, 0x07, 0x20, + 0xFF, 0xB7, 0x07, 0x20, 0x85, 0xB6, 0x07, 0x20, + 0xFF, 0xBF, 0x07, 0x20, 0x86, 0xBE, 0x07, 0x20, + 0xFF, 0xC7, 0x07, 0x20, 0x87, 0xC6, 0x07, 0x20, + 0xFF, 0xCF, 0x07, 0x20, 0x88, 0xCE, 0x07, 0x20, + 0xFF, 0xD7, 0x07, 0x20, 0x89, 0xD6, 0x07, 0x20, + 0xFF, 0xDF, 0x07, 0x20, 0x8A, 0xDE, 0x07, 0x20, + 0xFF, 0xE7, 0x07, 0x20, 0x8B, 0xE6, 0x07, 0x20, + 0xFF, 0xEF, 0x07, 0x20, 0x8C, 0xEE, 0x07, 0x20, + 0xFF, 0xF7, 0x07, 0x20, 0x8D, 0xF6, 0x07, 0x20, + 0xFF, 0xFF, 0x07, 0x20, 0x8E, 0xFE, 0x07, 0x20, + 0xFF, 0xFF, 0x07, 0x20, 0x8E, 0xFE, 0x07, 0x20, + 0xFF, 0xF7, 0x07, 0x20, 0x8D, 0xF6, 0x07, 0x20, + 0xFF, 0xEF, 0x07, 0x20, 0x8C, 0xEE, 0x07, 0x20, + 0xFF, 0xE7, 0x07, 0x20, 0x8B, 0xE6, 0x07, 0x20, + 0xFF, 0xDF, 0x07, 0x20, 0x8A, 0xDE, 0x07, 0x20, + 0xFF, 0xD7, 0x07, 0x20, 0x89, 0xD6, 0x07, 0x20, + 0xFF, 0xCF, 0x07, 0x20, 0x88, 0xCE, 0x07, 0x20, + 0xFF, 0xC7, 0x07, 0x20, 0x87, 0xC6, 0x07, 0x20, + 0xFF, 0xBF, 0x07, 0x20, 0x86, 0xBE, 0x07, 0x20, + 0xFF, 0xB7, 0x07, 0x20, 0x85, 0xB6, 0x07, 0x20, + 0xFF, 0xAF, 0x07, 0x20, 0x84, 0xAE, 0x07, 0x20, + 0xFF, 0xA7, 0x07, 0x20, 0x83, 0xA6, 0x07, 0x20, + 0xFF, 0x9F, 0x07, 0x20, 0x82, 0x9E, 0x07, 0x20, + 0xFF, 0x97, 0x07, 0x20, 0x81, 0x96, 0x07, 0x20, + 0xFF, 0x8F, 0x07, 0x20, 0x80, 0x8E, 0x07, 0x20, + 0xFF, 0x87, 0x07, 0x20, 0x7F, 0x86, 0x07, 0x20, + 0xFF, 0xFD, 0x07, 0x20, 0x7E, 0xFC, 0x07, 0x20, + 0xFF, 0xF5, 0x07, 0x20, 0x7D, 0xF4, 0x07, 0x20, + 0xFF, 0xED, 0x07, 0x20, 0x7C, 0xEC, 0x07, 0x20, + 0xFF, 0xE5, 0x07, 0x20, 0x7B, 0xE4, 0x07, 0x20, + 0xFF, 0xDD, 0x07, 0x20, 0x7A, 0xDC, 0x07, 0x20, + 0xFF, 0xD5, 0x07, 0x20, 0x79, 0xD4, 0x07, 0x20, + 0xFF, 0xCD, 0x07, 0x20, 0x78, 0xCC, 0x07, 0x20, + 0xFF, 0xC5, 0x07, 0x20, 0x77, 0xC4, 0x07, 0x20, + 0xFF, 0xBD, 0x07, 0x20, 0x76, 0xBC, 0x07, 0x20, + 0xFF, 0xB5, 0x07, 0x20, 0x75, 0xB4, 0x07, 0x20, + 0xFF, 0xAD, 0x07, 0x20, 0x74, 0xAC, 0x07, 0x20, + 0xFF, 0xA5, 0x07, 0x20, 0x73, 0xA4, 0x07, 0x20, + 0xFF, 0x9D, 0x07, 0x20, 0x72, 0x9C, 0x07, 0x20, + 0xFF, 0x95, 0x07, 0x20, 0x71, 0x94, 0x07, 0x20, + 0xFF, 0x8D, 0x07, 0x20, 0x70, 0x8C, 0x07, 0x20, + 0xFF, 0x85, 0x07, 0x20, 0x6F, 0x84, 0x07, 0x20, + 0xFF, 0xFB, 0x07, 0x20, 0x6E, 0xFA, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x6D, 0xF2, 0x07, 0x20, + 0xFF, 0xEB, 0x07, 0x20, 0x6C, 0xEA, 0x07, 0x20, + 0xFF, 0xE3, 0x07, 0x20, 0x6B, 0xE2, 0x07, 0x20, + 0xFF, 0xDB, 0x07, 0x20, 0x6A, 0xDA, 0x07, 0x20, + 0xFF, 0xD3, 0x07, 0x20, 0x69, 0xD2, 0x07, 0x20, + 0xFF, 0xCB, 0x07, 0x20, 0x68, 0xCA, 0x07, 0x20, + 0xFF, 0xC3, 0x07, 0x20, 0x67, 0xC2, 0x07, 0x20, + 0xFF, 0xBB, 0x07, 0x20, 0x66, 0xBA, 0x07, 0x20, + 0xFF, 0xB3, 0x07, 0x20, 0x65, 0xB2, 0x07, 0x20, + 0xFF, 0xAB, 0x07, 0x20, 0x64, 0xAA, 0x07, 0x20, + 0xFF, 0xA3, 0x07, 0x20, 0x63, 0xA2, 0x07, 0x20, + 0xFF, 0x9B, 0x07, 0x20, 0x62, 0x9A, 0x07, 0x20, + 0xFF, 0x93, 0x07, 0x20, 0x61, 0x92, 0x07, 0x20, + 0xFF, 0x8B, 0x07, 0x20, 0x60, 0x8A, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, + 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, + 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x04, 0x0C, 0x00, 0x01, 0x00, 0x03, 0x0D, 0x00, + 0x28, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x00, + 0x00, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x1C, 0x02, 0xB0, 0x01, 0x00, + 0x00, 0x00, 0x0E, 0x00, 0x10, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x1F, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0F, 0x00, + 0x01, 0x00, 0x01, 0x10, 0x00, 0x01, 0x00, 0x01, + 0x11, 0x00, 0x02, 0x00, 0x00, 0x01, 0x12, 0x00, + 0x01, 0x00, 0x01, 0x05, 0x00, 0x0E, 0x00, 0x0C, + 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x08, 0x00, 0x00, 0x05, 0x00, 0x0E, + 0x00, 0x10, 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, + 0x00, 0x09, 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x08, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x44, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x50, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x15, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x28, 0x00, 0x00, }; static unsigned char vfs5011_init_08[] = { /* 2516 B */ - 0x02, 0xB0, 0x00, 0x60, 0x00, 0x03, 0x00, 0x09, - 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, - 0x04, 0x30, 0x01, 0x80, 0x4F, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, - 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, - 0x20, 0x04, 0x30, 0xE6, 0x03, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, - 0xE7, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x4C, 0x20, 0x04, 0x30, 0xE8, 0x03, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, - 0x04, 0x30, 0x00, 0x3E, 0x01, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, - 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x05, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x40, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x60, 0x21, 0x04, 0x30, 0x05, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x90, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, - 0x30, 0x05, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xD8, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, - 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x05, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, - 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, - 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, - 0x30, 0x00, 0x02, 0xA8, 0x02, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, - 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, - 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, - 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, - 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x8B, 0x07, 0x20, 0x60, 0x8A, 0x07, 0x20, - 0xFF, 0x93, 0x07, 0x20, 0x61, 0x92, 0x07, 0x20, - 0xFF, 0x9B, 0x07, 0x20, 0x62, 0x9A, 0x07, 0x20, - 0xFF, 0xA3, 0x07, 0x20, 0x63, 0xA2, 0x07, 0x20, - 0xFF, 0xAB, 0x07, 0x20, 0x64, 0xAA, 0x07, 0x20, - 0xFF, 0xB3, 0x07, 0x20, 0x65, 0xB2, 0x07, 0x20, - 0xFF, 0xBB, 0x07, 0x20, 0x66, 0xBA, 0x07, 0x20, - 0xFF, 0xC3, 0x07, 0x20, 0x67, 0xC2, 0x07, 0x20, - 0xFF, 0xCB, 0x07, 0x20, 0x68, 0xCA, 0x07, 0x20, - 0xFF, 0xD3, 0x07, 0x20, 0x69, 0xD2, 0x07, 0x20, - 0xFF, 0xDB, 0x07, 0x20, 0x6A, 0xDA, 0x07, 0x20, - 0xFF, 0xE3, 0x07, 0x20, 0x6B, 0xE2, 0x07, 0x20, - 0xFF, 0xEB, 0x07, 0x20, 0x6C, 0xEA, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x6D, 0xF2, 0x07, 0x20, - 0xFF, 0xFB, 0x07, 0x20, 0x6E, 0xFA, 0x07, 0x20, - 0xFF, 0x85, 0x07, 0x20, 0x6F, 0x84, 0x07, 0x20, - 0xFF, 0x8D, 0x07, 0x20, 0x70, 0x8C, 0x07, 0x20, - 0xFF, 0x95, 0x07, 0x20, 0x71, 0x94, 0x07, 0x20, - 0xFF, 0x9D, 0x07, 0x20, 0x72, 0x9C, 0x07, 0x20, - 0xFF, 0xA5, 0x07, 0x20, 0x73, 0xA4, 0x07, 0x20, - 0xFF, 0xAD, 0x07, 0x20, 0x74, 0xAC, 0x07, 0x20, - 0xFF, 0xB5, 0x07, 0x20, 0x75, 0xB4, 0x07, 0x20, - 0xFF, 0xBD, 0x07, 0x20, 0x76, 0xBC, 0x07, 0x20, - 0xFF, 0xC5, 0x07, 0x20, 0x77, 0xC4, 0x07, 0x20, - 0xFF, 0xCD, 0x07, 0x20, 0x78, 0xCC, 0x07, 0x20, - 0xFF, 0xD5, 0x07, 0x20, 0x79, 0xD4, 0x07, 0x20, - 0xFF, 0xDD, 0x07, 0x20, 0x7A, 0xDC, 0x07, 0x20, - 0xFF, 0xE5, 0x07, 0x20, 0x7B, 0xE4, 0x07, 0x20, - 0xFF, 0xED, 0x07, 0x20, 0x7C, 0xEC, 0x07, 0x20, - 0xFF, 0xF5, 0x07, 0x20, 0x7D, 0xF4, 0x07, 0x20, - 0xFF, 0xFD, 0x07, 0x20, 0x7E, 0xFC, 0x07, 0x20, - 0xFF, 0x87, 0x07, 0x20, 0x7F, 0x86, 0x07, 0x20, - 0xFF, 0x8F, 0x07, 0x20, 0x80, 0x8E, 0x07, 0x20, - 0xFF, 0x97, 0x07, 0x20, 0x81, 0x96, 0x07, 0x20, - 0xFF, 0x9F, 0x07, 0x20, 0x82, 0x9E, 0x07, 0x20, - 0xFF, 0xA7, 0x07, 0x20, 0x83, 0xA6, 0x07, 0x20, - 0xFF, 0xAF, 0x07, 0x20, 0x84, 0xAE, 0x07, 0x20, - 0xFF, 0xB7, 0x07, 0x20, 0x85, 0xB6, 0x07, 0x20, - 0xFF, 0xBF, 0x07, 0x20, 0x86, 0xBE, 0x07, 0x20, - 0xFF, 0xC7, 0x07, 0x20, 0x87, 0xC6, 0x07, 0x20, - 0xFF, 0xCF, 0x07, 0x20, 0x88, 0xCE, 0x07, 0x20, - 0xFF, 0xD7, 0x07, 0x20, 0x89, 0xD6, 0x07, 0x20, - 0xFF, 0xDF, 0x07, 0x20, 0x8A, 0xDE, 0x07, 0x20, - 0xFF, 0xE7, 0x07, 0x20, 0x8B, 0xE6, 0x07, 0x20, - 0xFF, 0xEF, 0x07, 0x20, 0x8C, 0xEE, 0x07, 0x20, - 0xFF, 0xF7, 0x07, 0x20, 0x8D, 0xF6, 0x07, 0x20, - 0xFF, 0xFF, 0x07, 0x20, 0x8E, 0xFE, 0x07, 0x20, - 0xFF, 0xFF, 0x07, 0x20, 0x8E, 0xFE, 0x07, 0x20, - 0xFF, 0xF7, 0x07, 0x20, 0x8D, 0xF6, 0x07, 0x20, - 0xFF, 0xEF, 0x07, 0x20, 0x8C, 0xEE, 0x07, 0x20, - 0xFF, 0xE7, 0x07, 0x20, 0x8B, 0xE6, 0x07, 0x20, - 0xFF, 0xDF, 0x07, 0x20, 0x8A, 0xDE, 0x07, 0x20, - 0xFF, 0xD7, 0x07, 0x20, 0x89, 0xD6, 0x07, 0x20, - 0xFF, 0xCF, 0x07, 0x20, 0x88, 0xCE, 0x07, 0x20, - 0xFF, 0xC7, 0x07, 0x20, 0x87, 0xC6, 0x07, 0x20, - 0xFF, 0xBF, 0x07, 0x20, 0x86, 0xBE, 0x07, 0x20, - 0xFF, 0xB7, 0x07, 0x20, 0x85, 0xB6, 0x07, 0x20, - 0xFF, 0xAF, 0x07, 0x20, 0x84, 0xAE, 0x07, 0x20, - 0xFF, 0xA7, 0x07, 0x20, 0x83, 0xA6, 0x07, 0x20, - 0xFF, 0x9F, 0x07, 0x20, 0x82, 0x9E, 0x07, 0x20, - 0xFF, 0x97, 0x07, 0x20, 0x81, 0x96, 0x07, 0x20, - 0xFF, 0x8F, 0x07, 0x20, 0x80, 0x8E, 0x07, 0x20, - 0xFF, 0x87, 0x07, 0x20, 0x7F, 0x86, 0x07, 0x20, - 0xFF, 0xFD, 0x07, 0x20, 0x7E, 0xFC, 0x07, 0x20, - 0xFF, 0xF5, 0x07, 0x20, 0x7D, 0xF4, 0x07, 0x20, - 0xFF, 0xED, 0x07, 0x20, 0x7C, 0xEC, 0x07, 0x20, - 0xFF, 0xE5, 0x07, 0x20, 0x7B, 0xE4, 0x07, 0x20, - 0xFF, 0xDD, 0x07, 0x20, 0x7A, 0xDC, 0x07, 0x20, - 0xFF, 0xD5, 0x07, 0x20, 0x79, 0xD4, 0x07, 0x20, - 0xFF, 0xCD, 0x07, 0x20, 0x78, 0xCC, 0x07, 0x20, - 0xFF, 0xC5, 0x07, 0x20, 0x77, 0xC4, 0x07, 0x20, - 0xFF, 0xBD, 0x07, 0x20, 0x76, 0xBC, 0x07, 0x20, - 0xFF, 0xB5, 0x07, 0x20, 0x75, 0xB4, 0x07, 0x20, - 0xFF, 0xAD, 0x07, 0x20, 0x74, 0xAC, 0x07, 0x20, - 0xFF, 0xA5, 0x07, 0x20, 0x73, 0xA4, 0x07, 0x20, - 0xFF, 0x9D, 0x07, 0x20, 0x72, 0x9C, 0x07, 0x20, - 0xFF, 0x95, 0x07, 0x20, 0x71, 0x94, 0x07, 0x20, - 0xFF, 0x8D, 0x07, 0x20, 0x70, 0x8C, 0x07, 0x20, - 0xFF, 0x85, 0x07, 0x20, 0x6F, 0x84, 0x07, 0x20, - 0xFF, 0xFB, 0x07, 0x20, 0x6E, 0xFA, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x6D, 0xF2, 0x07, 0x20, - 0xFF, 0xEB, 0x07, 0x20, 0x6C, 0xEA, 0x07, 0x20, - 0xFF, 0xE3, 0x07, 0x20, 0x6B, 0xE2, 0x07, 0x20, - 0xFF, 0xDB, 0x07, 0x20, 0x6A, 0xDA, 0x07, 0x20, - 0xFF, 0xD3, 0x07, 0x20, 0x69, 0xD2, 0x07, 0x20, - 0xFF, 0xCB, 0x07, 0x20, 0x68, 0xCA, 0x07, 0x20, - 0xFF, 0xC3, 0x07, 0x20, 0x67, 0xC2, 0x07, 0x20, - 0xFF, 0xBB, 0x07, 0x20, 0x66, 0xBA, 0x07, 0x20, - 0xFF, 0xB3, 0x07, 0x20, 0x65, 0xB2, 0x07, 0x20, - 0xFF, 0xAB, 0x07, 0x20, 0x64, 0xAA, 0x07, 0x20, - 0xFF, 0xA3, 0x07, 0x20, 0x63, 0xA2, 0x07, 0x20, - 0xFF, 0x9B, 0x07, 0x20, 0x62, 0x9A, 0x07, 0x20, - 0xFF, 0x93, 0x07, 0x20, 0x61, 0x92, 0x07, 0x20, - 0xFF, 0x8B, 0x07, 0x20, 0x60, 0x8A, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, - 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, - 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, - 0x04, 0x0C, 0x00, 0x01, 0x00, 0x02, 0x0D, 0x00, - 0x28, 0x00, 0x14, 0x00, 0x00, 0x38, 0x00, 0x00, - 0x6E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x8F, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x02, 0x00, - 0x00, 0x00, 0x0E, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0F, 0x00, - 0x01, 0x00, 0x01, 0x10, 0x00, 0x01, 0x00, 0x02, - 0x11, 0x00, 0x02, 0x00, 0x60, 0x00, 0x12, 0x00, - 0x01, 0x00, 0x01, 0x05, 0x00, 0x0E, 0x00, 0x0C, - 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x08, 0x00, 0x00, 0x05, 0x00, 0x0E, - 0x00, 0x10, 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, - 0x00, 0x09, 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x08, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x44, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x50, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, - 0x20, 0x04, 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, - 0x15, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x28, 0x00, 0x00, + 0x02, 0xB0, 0x00, 0x60, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, + 0x04, 0x30, 0x01, 0x80, 0x4F, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, + 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, + 0x20, 0x04, 0x30, 0xE6, 0x03, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, + 0xE7, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x4C, 0x20, 0x04, 0x30, 0xE8, 0x03, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, + 0x04, 0x30, 0x00, 0x3E, 0x01, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, + 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x05, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x40, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x60, 0x21, 0x04, 0x30, 0x05, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x90, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, + 0x30, 0x05, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xD8, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, + 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x05, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, + 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, + 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, + 0x30, 0x00, 0x02, 0xA8, 0x02, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, + 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, + 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, + 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, + 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x8B, 0x07, 0x20, 0x60, 0x8A, 0x07, 0x20, + 0xFF, 0x93, 0x07, 0x20, 0x61, 0x92, 0x07, 0x20, + 0xFF, 0x9B, 0x07, 0x20, 0x62, 0x9A, 0x07, 0x20, + 0xFF, 0xA3, 0x07, 0x20, 0x63, 0xA2, 0x07, 0x20, + 0xFF, 0xAB, 0x07, 0x20, 0x64, 0xAA, 0x07, 0x20, + 0xFF, 0xB3, 0x07, 0x20, 0x65, 0xB2, 0x07, 0x20, + 0xFF, 0xBB, 0x07, 0x20, 0x66, 0xBA, 0x07, 0x20, + 0xFF, 0xC3, 0x07, 0x20, 0x67, 0xC2, 0x07, 0x20, + 0xFF, 0xCB, 0x07, 0x20, 0x68, 0xCA, 0x07, 0x20, + 0xFF, 0xD3, 0x07, 0x20, 0x69, 0xD2, 0x07, 0x20, + 0xFF, 0xDB, 0x07, 0x20, 0x6A, 0xDA, 0x07, 0x20, + 0xFF, 0xE3, 0x07, 0x20, 0x6B, 0xE2, 0x07, 0x20, + 0xFF, 0xEB, 0x07, 0x20, 0x6C, 0xEA, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x6D, 0xF2, 0x07, 0x20, + 0xFF, 0xFB, 0x07, 0x20, 0x6E, 0xFA, 0x07, 0x20, + 0xFF, 0x85, 0x07, 0x20, 0x6F, 0x84, 0x07, 0x20, + 0xFF, 0x8D, 0x07, 0x20, 0x70, 0x8C, 0x07, 0x20, + 0xFF, 0x95, 0x07, 0x20, 0x71, 0x94, 0x07, 0x20, + 0xFF, 0x9D, 0x07, 0x20, 0x72, 0x9C, 0x07, 0x20, + 0xFF, 0xA5, 0x07, 0x20, 0x73, 0xA4, 0x07, 0x20, + 0xFF, 0xAD, 0x07, 0x20, 0x74, 0xAC, 0x07, 0x20, + 0xFF, 0xB5, 0x07, 0x20, 0x75, 0xB4, 0x07, 0x20, + 0xFF, 0xBD, 0x07, 0x20, 0x76, 0xBC, 0x07, 0x20, + 0xFF, 0xC5, 0x07, 0x20, 0x77, 0xC4, 0x07, 0x20, + 0xFF, 0xCD, 0x07, 0x20, 0x78, 0xCC, 0x07, 0x20, + 0xFF, 0xD5, 0x07, 0x20, 0x79, 0xD4, 0x07, 0x20, + 0xFF, 0xDD, 0x07, 0x20, 0x7A, 0xDC, 0x07, 0x20, + 0xFF, 0xE5, 0x07, 0x20, 0x7B, 0xE4, 0x07, 0x20, + 0xFF, 0xED, 0x07, 0x20, 0x7C, 0xEC, 0x07, 0x20, + 0xFF, 0xF5, 0x07, 0x20, 0x7D, 0xF4, 0x07, 0x20, + 0xFF, 0xFD, 0x07, 0x20, 0x7E, 0xFC, 0x07, 0x20, + 0xFF, 0x87, 0x07, 0x20, 0x7F, 0x86, 0x07, 0x20, + 0xFF, 0x8F, 0x07, 0x20, 0x80, 0x8E, 0x07, 0x20, + 0xFF, 0x97, 0x07, 0x20, 0x81, 0x96, 0x07, 0x20, + 0xFF, 0x9F, 0x07, 0x20, 0x82, 0x9E, 0x07, 0x20, + 0xFF, 0xA7, 0x07, 0x20, 0x83, 0xA6, 0x07, 0x20, + 0xFF, 0xAF, 0x07, 0x20, 0x84, 0xAE, 0x07, 0x20, + 0xFF, 0xB7, 0x07, 0x20, 0x85, 0xB6, 0x07, 0x20, + 0xFF, 0xBF, 0x07, 0x20, 0x86, 0xBE, 0x07, 0x20, + 0xFF, 0xC7, 0x07, 0x20, 0x87, 0xC6, 0x07, 0x20, + 0xFF, 0xCF, 0x07, 0x20, 0x88, 0xCE, 0x07, 0x20, + 0xFF, 0xD7, 0x07, 0x20, 0x89, 0xD6, 0x07, 0x20, + 0xFF, 0xDF, 0x07, 0x20, 0x8A, 0xDE, 0x07, 0x20, + 0xFF, 0xE7, 0x07, 0x20, 0x8B, 0xE6, 0x07, 0x20, + 0xFF, 0xEF, 0x07, 0x20, 0x8C, 0xEE, 0x07, 0x20, + 0xFF, 0xF7, 0x07, 0x20, 0x8D, 0xF6, 0x07, 0x20, + 0xFF, 0xFF, 0x07, 0x20, 0x8E, 0xFE, 0x07, 0x20, + 0xFF, 0xFF, 0x07, 0x20, 0x8E, 0xFE, 0x07, 0x20, + 0xFF, 0xF7, 0x07, 0x20, 0x8D, 0xF6, 0x07, 0x20, + 0xFF, 0xEF, 0x07, 0x20, 0x8C, 0xEE, 0x07, 0x20, + 0xFF, 0xE7, 0x07, 0x20, 0x8B, 0xE6, 0x07, 0x20, + 0xFF, 0xDF, 0x07, 0x20, 0x8A, 0xDE, 0x07, 0x20, + 0xFF, 0xD7, 0x07, 0x20, 0x89, 0xD6, 0x07, 0x20, + 0xFF, 0xCF, 0x07, 0x20, 0x88, 0xCE, 0x07, 0x20, + 0xFF, 0xC7, 0x07, 0x20, 0x87, 0xC6, 0x07, 0x20, + 0xFF, 0xBF, 0x07, 0x20, 0x86, 0xBE, 0x07, 0x20, + 0xFF, 0xB7, 0x07, 0x20, 0x85, 0xB6, 0x07, 0x20, + 0xFF, 0xAF, 0x07, 0x20, 0x84, 0xAE, 0x07, 0x20, + 0xFF, 0xA7, 0x07, 0x20, 0x83, 0xA6, 0x07, 0x20, + 0xFF, 0x9F, 0x07, 0x20, 0x82, 0x9E, 0x07, 0x20, + 0xFF, 0x97, 0x07, 0x20, 0x81, 0x96, 0x07, 0x20, + 0xFF, 0x8F, 0x07, 0x20, 0x80, 0x8E, 0x07, 0x20, + 0xFF, 0x87, 0x07, 0x20, 0x7F, 0x86, 0x07, 0x20, + 0xFF, 0xFD, 0x07, 0x20, 0x7E, 0xFC, 0x07, 0x20, + 0xFF, 0xF5, 0x07, 0x20, 0x7D, 0xF4, 0x07, 0x20, + 0xFF, 0xED, 0x07, 0x20, 0x7C, 0xEC, 0x07, 0x20, + 0xFF, 0xE5, 0x07, 0x20, 0x7B, 0xE4, 0x07, 0x20, + 0xFF, 0xDD, 0x07, 0x20, 0x7A, 0xDC, 0x07, 0x20, + 0xFF, 0xD5, 0x07, 0x20, 0x79, 0xD4, 0x07, 0x20, + 0xFF, 0xCD, 0x07, 0x20, 0x78, 0xCC, 0x07, 0x20, + 0xFF, 0xC5, 0x07, 0x20, 0x77, 0xC4, 0x07, 0x20, + 0xFF, 0xBD, 0x07, 0x20, 0x76, 0xBC, 0x07, 0x20, + 0xFF, 0xB5, 0x07, 0x20, 0x75, 0xB4, 0x07, 0x20, + 0xFF, 0xAD, 0x07, 0x20, 0x74, 0xAC, 0x07, 0x20, + 0xFF, 0xA5, 0x07, 0x20, 0x73, 0xA4, 0x07, 0x20, + 0xFF, 0x9D, 0x07, 0x20, 0x72, 0x9C, 0x07, 0x20, + 0xFF, 0x95, 0x07, 0x20, 0x71, 0x94, 0x07, 0x20, + 0xFF, 0x8D, 0x07, 0x20, 0x70, 0x8C, 0x07, 0x20, + 0xFF, 0x85, 0x07, 0x20, 0x6F, 0x84, 0x07, 0x20, + 0xFF, 0xFB, 0x07, 0x20, 0x6E, 0xFA, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x6D, 0xF2, 0x07, 0x20, + 0xFF, 0xEB, 0x07, 0x20, 0x6C, 0xEA, 0x07, 0x20, + 0xFF, 0xE3, 0x07, 0x20, 0x6B, 0xE2, 0x07, 0x20, + 0xFF, 0xDB, 0x07, 0x20, 0x6A, 0xDA, 0x07, 0x20, + 0xFF, 0xD3, 0x07, 0x20, 0x69, 0xD2, 0x07, 0x20, + 0xFF, 0xCB, 0x07, 0x20, 0x68, 0xCA, 0x07, 0x20, + 0xFF, 0xC3, 0x07, 0x20, 0x67, 0xC2, 0x07, 0x20, + 0xFF, 0xBB, 0x07, 0x20, 0x66, 0xBA, 0x07, 0x20, + 0xFF, 0xB3, 0x07, 0x20, 0x65, 0xB2, 0x07, 0x20, + 0xFF, 0xAB, 0x07, 0x20, 0x64, 0xAA, 0x07, 0x20, + 0xFF, 0xA3, 0x07, 0x20, 0x63, 0xA2, 0x07, 0x20, + 0xFF, 0x9B, 0x07, 0x20, 0x62, 0x9A, 0x07, 0x20, + 0xFF, 0x93, 0x07, 0x20, 0x61, 0x92, 0x07, 0x20, + 0xFF, 0x8B, 0x07, 0x20, 0x60, 0x8A, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, + 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, + 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x04, 0x0C, 0x00, 0x01, 0x00, 0x02, 0x0D, 0x00, + 0x28, 0x00, 0x14, 0x00, 0x00, 0x38, 0x00, 0x00, + 0x6E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x8F, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x0E, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0F, 0x00, + 0x01, 0x00, 0x01, 0x10, 0x00, 0x01, 0x00, 0x02, + 0x11, 0x00, 0x02, 0x00, 0x60, 0x00, 0x12, 0x00, + 0x01, 0x00, 0x01, 0x05, 0x00, 0x0E, 0x00, 0x0C, + 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x08, 0x00, 0x00, 0x05, 0x00, 0x0E, + 0x00, 0x10, 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, + 0x00, 0x09, 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x08, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x44, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x50, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, + 0x20, 0x04, 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, + 0x15, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x28, 0x00, 0x00, }; static unsigned char vfs5011_init_09[] = { /* 2742 B */ - 0x02, 0xB0, 0x00, 0x1C, 0x00, 0x03, 0x00, 0x09, - 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, - 0x04, 0x30, 0x01, 0x80, 0x4F, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, - 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, - 0x20, 0x04, 0x30, 0xE7, 0x03, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, - 0xFF, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x4C, 0x20, 0x04, 0x30, 0xFF, 0x03, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, - 0x04, 0x30, 0x00, 0x3E, 0x01, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x30, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, - 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x40, 0x21, 0x04, 0x30, 0x30, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x60, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, - 0x30, 0x30, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x90, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x30, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xD8, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, - 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, - 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, - 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, - 0x30, 0x00, 0x02, 0xA8, 0x02, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, - 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, - 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, - 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, - 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, - 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, - 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, - 0x04, 0x0C, 0x00, 0x01, 0x00, 0x00, 0x0D, 0x00, - 0x28, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x73, 0x00, 0x00, 0x10, 0x01, 0x00, - 0x00, 0x00, 0x0E, 0x00, 0xE0, 0x00, 0x00, 0x01, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, - 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, - 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, - 0x04, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, - 0x08, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, - 0x10, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, - 0x10, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, - 0x10, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, - 0x10, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, - 0x10, 0x01, 0x10, 0x01, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, - 0x10, 0x01, 0x10, 0x01, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, - 0x10, 0x01, 0x10, 0x01, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x0F, 0x00, - 0x01, 0x00, 0x01, 0x10, 0x00, 0x01, 0x00, 0x02, - 0x11, 0x00, 0x02, 0x00, 0x02, 0x00, 0x12, 0x00, - 0x01, 0x00, 0x0E, 0x05, 0x00, 0x0E, 0x00, 0x0C, - 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x08, 0x00, 0x00, 0x05, 0x00, 0x0E, - 0x00, 0x10, 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, - 0x00, 0x09, 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x08, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x44, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x50, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, - 0x20, 0x04, 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, - 0x05, 0x00, 0x0E, 0x00, 0x14, 0x20, 0xFF, 0xFF, - 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x15, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x20, 0x28, 0x00, 0x00, + 0x02, 0xB0, 0x00, 0x1C, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, + 0x04, 0x30, 0x01, 0x80, 0x4F, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, + 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, + 0x20, 0x04, 0x30, 0xE7, 0x03, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, + 0xFF, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x4C, 0x20, 0x04, 0x30, 0xFF, 0x03, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, + 0x04, 0x30, 0x00, 0x3E, 0x01, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x30, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, + 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x40, 0x21, 0x04, 0x30, 0x30, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x60, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x90, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x30, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xD8, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, + 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, + 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, + 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, + 0x30, 0x00, 0x02, 0xA8, 0x02, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, + 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, + 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, + 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, + 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x80, 0xF2, 0x07, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, + 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, + 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x04, 0x0C, 0x00, 0x01, 0x00, 0x00, 0x0D, 0x00, + 0x28, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x73, 0x00, 0x00, 0x10, 0x01, 0x00, + 0x00, 0x00, 0x0E, 0x00, 0xE0, 0x00, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, + 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, + 0x04, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, + 0x08, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, + 0x10, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, + 0x10, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, + 0x10, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, + 0x10, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, + 0x10, 0x01, 0x10, 0x01, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, + 0x10, 0x01, 0x10, 0x01, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x01, + 0x10, 0x01, 0x10, 0x01, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x0F, 0x00, + 0x01, 0x00, 0x01, 0x10, 0x00, 0x01, 0x00, 0x02, + 0x11, 0x00, 0x02, 0x00, 0x02, 0x00, 0x12, 0x00, + 0x01, 0x00, 0x0E, 0x05, 0x00, 0x0E, 0x00, 0x0C, + 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x08, 0x00, 0x00, 0x05, 0x00, 0x0E, + 0x00, 0x10, 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, + 0x00, 0x09, 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x08, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x44, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x50, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, + 0x20, 0x04, 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, + 0x05, 0x00, 0x0E, 0x00, 0x14, 0x20, 0xFF, 0xFF, + 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x00, 0x15, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x28, 0x00, 0x00, }; static unsigned char vfs5011_init_10[] = { /* 2612 B */ - 0x02, 0xB0, 0x00, 0x20, 0x00, 0x03, 0x00, 0x09, - 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, - 0x04, 0x30, 0x01, 0x80, 0x4F, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, - 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, - 0x20, 0x04, 0x30, 0xE7, 0x03, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, - 0xFF, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x4C, 0x20, 0x04, 0x30, 0xFF, 0x03, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, - 0x04, 0x30, 0x00, 0x3E, 0x01, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x30, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, - 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x18, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, - 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x04, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x40, 0x21, 0x04, 0x30, 0x30, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x60, 0x21, 0x04, 0x30, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, - 0x30, 0x30, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x90, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, - 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x30, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xD8, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, - 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x04, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, - 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, - 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, - 0x30, 0x00, 0x02, 0xA8, 0x02, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, - 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, - 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, - 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, - 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, - 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, - 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, - 0x04, 0x0C, 0x00, 0x01, 0x00, 0x01, 0x0D, 0x00, - 0x28, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x00, - 0x00, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x1C, 0x02, 0xB0, 0x01, 0x00, - 0x00, 0x00, 0x0E, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, - 0x01, 0x00, 0x01, 0x10, 0x00, 0x01, 0x00, 0x02, - 0x11, 0x00, 0x02, 0x00, 0x20, 0x00, 0x12, 0x00, - 0x01, 0x00, 0x01, 0x05, 0x00, 0x0E, 0x00, 0x0C, - 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x08, 0x00, 0x00, 0x05, 0x00, 0x0E, - 0x00, 0x10, 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, - 0x00, 0x09, 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x08, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x44, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x50, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, - 0x20, 0x04, 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, - 0x05, 0x00, 0x0E, 0x00, 0x14, 0x20, 0xFF, 0xFF, - 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x03, 0x00, 0x09, 0x00, 0x84, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x88, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x8C, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x90, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x94, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x98, - 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x15, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x28, 0x00, 0x00, + 0x02, 0xB0, 0x00, 0x20, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, + 0x04, 0x30, 0x01, 0x80, 0x4F, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, + 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, + 0x20, 0x04, 0x30, 0xE7, 0x03, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, + 0xFF, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x4C, 0x20, 0x04, 0x30, 0xFF, 0x03, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, + 0x04, 0x30, 0x00, 0x3E, 0x01, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x30, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, + 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x18, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, + 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x04, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x40, 0x21, 0x04, 0x30, 0x30, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x60, 0x21, 0x04, 0x30, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x90, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, + 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x30, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xD8, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, + 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x04, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, + 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, + 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, + 0x30, 0x00, 0x02, 0xA8, 0x02, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, + 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, + 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, + 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, + 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0xFF, 0xF3, 0x47, 0x20, 0x80, 0xF2, 0x47, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, + 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, + 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x04, 0x0C, 0x00, 0x01, 0x00, 0x01, 0x0D, 0x00, + 0x28, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x00, + 0x00, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x1C, 0x02, 0xB0, 0x01, 0x00, + 0x00, 0x00, 0x0E, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, + 0x01, 0x00, 0x01, 0x10, 0x00, 0x01, 0x00, 0x02, + 0x11, 0x00, 0x02, 0x00, 0x20, 0x00, 0x12, 0x00, + 0x01, 0x00, 0x01, 0x05, 0x00, 0x0E, 0x00, 0x0C, + 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x08, 0x00, 0x00, 0x05, 0x00, 0x0E, + 0x00, 0x10, 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, + 0x00, 0x09, 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x08, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x44, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x50, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, + 0x20, 0x04, 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, + 0x05, 0x00, 0x0E, 0x00, 0x14, 0x20, 0xFF, 0xFF, + 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x00, 0x03, 0x00, 0x09, 0x00, 0x84, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x88, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x8C, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x90, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x94, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x98, + 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x15, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x28, 0x00, 0x00, }; static unsigned char vfs5011_init_11[] = { /* 2625 B */ - 0x02, 0xB0, 0x00, 0x20, 0x00, 0x03, 0x00, 0x09, - 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, - 0x04, 0x30, 0x01, 0x80, 0x4F, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, - 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, - 0x20, 0x04, 0x30, 0xE6, 0x03, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, - 0xE7, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x4C, 0x20, 0x04, 0x30, 0xE8, 0x03, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, - 0x04, 0x30, 0x00, 0x3E, 0x01, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, - 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x08, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x40, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x60, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x90, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, - 0x30, 0x08, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xD8, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, - 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x08, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, - 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, - 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, - 0x30, 0x00, 0x02, 0xA8, 0x02, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, - 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, - 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, - 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, - 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0xFF, 0x8B, 0x07, 0x20, 0x60, 0x8A, 0x07, 0x20, - 0xFF, 0x93, 0x07, 0x20, 0x61, 0x92, 0x07, 0x20, - 0xFF, 0x9B, 0x07, 0x20, 0x62, 0x9A, 0x07, 0x20, - 0xFF, 0xA3, 0x07, 0x20, 0x63, 0xA2, 0x07, 0x20, - 0xFF, 0xAB, 0x07, 0x20, 0x64, 0xAA, 0x07, 0x20, - 0xFF, 0xB3, 0x07, 0x20, 0x65, 0xB2, 0x07, 0x20, - 0xFF, 0xBB, 0x07, 0x20, 0x66, 0xBA, 0x07, 0x20, - 0xFF, 0xC3, 0x07, 0x20, 0x67, 0xC2, 0x07, 0x20, - 0xFF, 0xCB, 0x07, 0x20, 0x68, 0xCA, 0x07, 0x20, - 0xFF, 0xD3, 0x07, 0x20, 0x69, 0xD2, 0x07, 0x20, - 0xFF, 0xDB, 0x07, 0x20, 0x6A, 0xDA, 0x07, 0x20, - 0xFF, 0xE3, 0x07, 0x20, 0x6B, 0xE2, 0x07, 0x20, - 0xFF, 0xEB, 0x07, 0x20, 0x6C, 0xEA, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x6D, 0xF2, 0x07, 0x20, - 0xFF, 0xFB, 0x07, 0x20, 0x6E, 0xFA, 0x07, 0x20, - 0xFF, 0x85, 0x07, 0x20, 0x6F, 0x84, 0x07, 0x20, - 0xFF, 0x8D, 0x07, 0x20, 0x70, 0x8C, 0x07, 0x20, - 0xFF, 0x95, 0x07, 0x20, 0x71, 0x94, 0x07, 0x20, - 0xFF, 0x9D, 0x07, 0x20, 0x72, 0x9C, 0x07, 0x20, - 0xFF, 0xA5, 0x07, 0x20, 0x73, 0xA4, 0x07, 0x20, - 0xFF, 0xAD, 0x07, 0x20, 0x74, 0xAC, 0x07, 0x20, - 0xFF, 0xB5, 0x07, 0x20, 0x75, 0xB4, 0x07, 0x20, - 0xFF, 0xBD, 0x07, 0x20, 0x76, 0xBC, 0x07, 0x20, - 0xFF, 0xC5, 0x07, 0x20, 0x77, 0xC4, 0x07, 0x20, - 0xFF, 0xCD, 0x07, 0x20, 0x78, 0xCC, 0x07, 0x20, - 0xFF, 0xD5, 0x07, 0x20, 0x79, 0xD4, 0x07, 0x20, - 0xFF, 0xDD, 0x07, 0x20, 0x7A, 0xDC, 0x07, 0x20, - 0xFF, 0xE5, 0x07, 0x20, 0x7B, 0xE4, 0x07, 0x20, - 0xFF, 0xED, 0x07, 0x20, 0x7C, 0xEC, 0x07, 0x20, - 0xFF, 0xF5, 0x07, 0x20, 0x7D, 0xF4, 0x07, 0x20, - 0xFF, 0xFD, 0x07, 0x20, 0x7E, 0xFC, 0x07, 0x20, - 0xFF, 0x87, 0x07, 0x20, 0x7F, 0x86, 0x07, 0x20, - 0xFF, 0x8F, 0x07, 0x20, 0x80, 0x8E, 0x07, 0x20, - 0xFF, 0x97, 0x07, 0x20, 0x81, 0x96, 0x07, 0x20, - 0xFF, 0x9F, 0x07, 0x20, 0x82, 0x9E, 0x07, 0x20, - 0xFF, 0xA7, 0x07, 0x20, 0x83, 0xA6, 0x07, 0x20, - 0xFF, 0xAF, 0x07, 0x20, 0x84, 0xAE, 0x07, 0x20, - 0xFF, 0xB7, 0x07, 0x20, 0x85, 0xB6, 0x07, 0x20, - 0xFF, 0xBF, 0x07, 0x20, 0x86, 0xBE, 0x07, 0x20, - 0xFF, 0xC7, 0x07, 0x20, 0x87, 0xC6, 0x07, 0x20, - 0xFF, 0xCF, 0x07, 0x20, 0x88, 0xCE, 0x07, 0x20, - 0xFF, 0xD7, 0x07, 0x20, 0x89, 0xD6, 0x07, 0x20, - 0xFF, 0xDF, 0x07, 0x20, 0x8A, 0xDE, 0x07, 0x20, - 0xFF, 0xE7, 0x07, 0x20, 0x8B, 0xE6, 0x07, 0x20, - 0xFF, 0xEF, 0x07, 0x20, 0x8C, 0xEE, 0x07, 0x20, - 0xFF, 0xF7, 0x07, 0x20, 0x8D, 0xF6, 0x07, 0x20, - 0xFF, 0xFF, 0x07, 0x20, 0x8E, 0xFE, 0x07, 0x20, - 0xFF, 0xFF, 0x07, 0x20, 0x8E, 0xFE, 0x07, 0x20, - 0xFF, 0xF7, 0x07, 0x20, 0x8D, 0xF6, 0x07, 0x20, - 0xFF, 0xEF, 0x07, 0x20, 0x8C, 0xEE, 0x07, 0x20, - 0xFF, 0xE7, 0x07, 0x20, 0x8B, 0xE6, 0x07, 0x20, - 0xFF, 0xDF, 0x07, 0x20, 0x8A, 0xDE, 0x07, 0x20, - 0xFF, 0xD7, 0x07, 0x20, 0x89, 0xD6, 0x07, 0x20, - 0xFF, 0xCF, 0x07, 0x20, 0x88, 0xCE, 0x07, 0x20, - 0xFF, 0xC7, 0x07, 0x20, 0x87, 0xC6, 0x07, 0x20, - 0xFF, 0xBF, 0x07, 0x20, 0x86, 0xBE, 0x07, 0x20, - 0xFF, 0xB7, 0x07, 0x20, 0x85, 0xB6, 0x07, 0x20, - 0xFF, 0xAF, 0x07, 0x20, 0x84, 0xAE, 0x07, 0x20, - 0xFF, 0xA7, 0x07, 0x20, 0x83, 0xA6, 0x07, 0x20, - 0xFF, 0x9F, 0x07, 0x20, 0x82, 0x9E, 0x07, 0x20, - 0xFF, 0x97, 0x07, 0x20, 0x81, 0x96, 0x07, 0x20, - 0xFF, 0x8F, 0x07, 0x20, 0x80, 0x8E, 0x07, 0x20, - 0xFF, 0x87, 0x07, 0x20, 0x7F, 0x86, 0x07, 0x20, - 0xFF, 0xFD, 0x07, 0x20, 0x7E, 0xFC, 0x07, 0x20, - 0xFF, 0xF5, 0x07, 0x20, 0x7D, 0xF4, 0x07, 0x20, - 0xFF, 0xED, 0x07, 0x20, 0x7C, 0xEC, 0x07, 0x20, - 0xFF, 0xE5, 0x07, 0x20, 0x7B, 0xE4, 0x07, 0x20, - 0xFF, 0xDD, 0x07, 0x20, 0x7A, 0xDC, 0x07, 0x20, - 0xFF, 0xD5, 0x07, 0x20, 0x79, 0xD4, 0x07, 0x20, - 0xFF, 0xCD, 0x07, 0x20, 0x78, 0xCC, 0x07, 0x20, - 0xFF, 0xC5, 0x07, 0x20, 0x77, 0xC4, 0x07, 0x20, - 0xFF, 0xBD, 0x07, 0x20, 0x76, 0xBC, 0x07, 0x20, - 0xFF, 0xB5, 0x07, 0x20, 0x75, 0xB4, 0x07, 0x20, - 0xFF, 0xAD, 0x07, 0x20, 0x74, 0xAC, 0x07, 0x20, - 0xFF, 0xA5, 0x07, 0x20, 0x73, 0xA4, 0x07, 0x20, - 0xFF, 0x9D, 0x07, 0x20, 0x72, 0x9C, 0x07, 0x20, - 0xFF, 0x95, 0x07, 0x20, 0x71, 0x94, 0x07, 0x20, - 0xFF, 0x8D, 0x07, 0x20, 0x70, 0x8C, 0x07, 0x20, - 0xFF, 0x85, 0x07, 0x20, 0x6F, 0x84, 0x07, 0x20, - 0xFF, 0xFB, 0x07, 0x20, 0x6E, 0xFA, 0x07, 0x20, - 0xFF, 0xF3, 0x07, 0x20, 0x6D, 0xF2, 0x07, 0x20, - 0xFF, 0xEB, 0x07, 0x20, 0x6C, 0xEA, 0x07, 0x20, - 0xFF, 0xE3, 0x07, 0x20, 0x6B, 0xE2, 0x07, 0x20, - 0xFF, 0xDB, 0x07, 0x20, 0x6A, 0xDA, 0x07, 0x20, - 0xFF, 0xD3, 0x07, 0x20, 0x69, 0xD2, 0x07, 0x20, - 0xFF, 0xCB, 0x07, 0x20, 0x68, 0xCA, 0x07, 0x20, - 0xFF, 0xC3, 0x07, 0x20, 0x67, 0xC2, 0x07, 0x20, - 0xFF, 0xBB, 0x07, 0x20, 0x66, 0xBA, 0x07, 0x20, - 0xFF, 0xB3, 0x07, 0x20, 0x65, 0xB2, 0x07, 0x20, - 0xFF, 0xAB, 0x07, 0x20, 0x64, 0xAA, 0x07, 0x20, - 0xFF, 0xA3, 0x07, 0x20, 0x63, 0xA2, 0x07, 0x20, - 0xFF, 0x9B, 0x07, 0x20, 0x62, 0x9A, 0x07, 0x20, - 0xFF, 0x93, 0x07, 0x20, 0x61, 0x92, 0x07, 0x20, - 0xFF, 0x8B, 0x07, 0x20, 0x60, 0x8A, 0x07, 0x20, - 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, - 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, - 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, - 0x04, 0x0C, 0x00, 0x01, 0x00, 0x01, 0x0D, 0x00, - 0x28, 0x00, 0x20, 0x21, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x00, - 0x00, 0x00, 0x20, 0x21, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x1C, 0x02, 0xB0, 0x01, 0x00, - 0x00, 0x00, 0x0E, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0F, 0x00, - 0x01, 0x00, 0x01, 0x10, 0x00, 0x01, 0x00, 0x02, - 0x11, 0x00, 0x02, 0x00, 0x20, 0x00, 0x12, 0x00, - 0x01, 0x00, 0x01, 0x05, 0x00, 0x0E, 0x00, 0x0C, - 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x08, 0x00, 0x00, 0x05, 0x00, 0x0E, - 0x00, 0x10, 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, - 0x00, 0x09, 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x08, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x44, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x50, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, - 0x20, 0x04, 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, - 0x05, 0x00, 0x0E, 0x00, 0x14, 0x20, 0xFF, 0xFF, - 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x03, 0x00, 0x09, 0x00, 0x84, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x88, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x8C, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x90, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x94, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x98, - 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x15, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x28, 0x00, - 0x00, + 0x02, 0xB0, 0x00, 0x20, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, + 0x04, 0x30, 0x01, 0x80, 0x4F, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, + 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, + 0x20, 0x04, 0x30, 0xE6, 0x03, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, + 0xE7, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x4C, 0x20, 0x04, 0x30, 0xE8, 0x03, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, + 0x04, 0x30, 0x00, 0x3E, 0x01, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, + 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x08, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x40, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x60, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x90, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, + 0x30, 0x08, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xD8, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, + 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x08, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, + 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, + 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, + 0x30, 0x00, 0x02, 0xA8, 0x02, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, + 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, + 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, + 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, + 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0xFF, 0x8B, 0x07, 0x20, 0x60, 0x8A, 0x07, 0x20, + 0xFF, 0x93, 0x07, 0x20, 0x61, 0x92, 0x07, 0x20, + 0xFF, 0x9B, 0x07, 0x20, 0x62, 0x9A, 0x07, 0x20, + 0xFF, 0xA3, 0x07, 0x20, 0x63, 0xA2, 0x07, 0x20, + 0xFF, 0xAB, 0x07, 0x20, 0x64, 0xAA, 0x07, 0x20, + 0xFF, 0xB3, 0x07, 0x20, 0x65, 0xB2, 0x07, 0x20, + 0xFF, 0xBB, 0x07, 0x20, 0x66, 0xBA, 0x07, 0x20, + 0xFF, 0xC3, 0x07, 0x20, 0x67, 0xC2, 0x07, 0x20, + 0xFF, 0xCB, 0x07, 0x20, 0x68, 0xCA, 0x07, 0x20, + 0xFF, 0xD3, 0x07, 0x20, 0x69, 0xD2, 0x07, 0x20, + 0xFF, 0xDB, 0x07, 0x20, 0x6A, 0xDA, 0x07, 0x20, + 0xFF, 0xE3, 0x07, 0x20, 0x6B, 0xE2, 0x07, 0x20, + 0xFF, 0xEB, 0x07, 0x20, 0x6C, 0xEA, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x6D, 0xF2, 0x07, 0x20, + 0xFF, 0xFB, 0x07, 0x20, 0x6E, 0xFA, 0x07, 0x20, + 0xFF, 0x85, 0x07, 0x20, 0x6F, 0x84, 0x07, 0x20, + 0xFF, 0x8D, 0x07, 0x20, 0x70, 0x8C, 0x07, 0x20, + 0xFF, 0x95, 0x07, 0x20, 0x71, 0x94, 0x07, 0x20, + 0xFF, 0x9D, 0x07, 0x20, 0x72, 0x9C, 0x07, 0x20, + 0xFF, 0xA5, 0x07, 0x20, 0x73, 0xA4, 0x07, 0x20, + 0xFF, 0xAD, 0x07, 0x20, 0x74, 0xAC, 0x07, 0x20, + 0xFF, 0xB5, 0x07, 0x20, 0x75, 0xB4, 0x07, 0x20, + 0xFF, 0xBD, 0x07, 0x20, 0x76, 0xBC, 0x07, 0x20, + 0xFF, 0xC5, 0x07, 0x20, 0x77, 0xC4, 0x07, 0x20, + 0xFF, 0xCD, 0x07, 0x20, 0x78, 0xCC, 0x07, 0x20, + 0xFF, 0xD5, 0x07, 0x20, 0x79, 0xD4, 0x07, 0x20, + 0xFF, 0xDD, 0x07, 0x20, 0x7A, 0xDC, 0x07, 0x20, + 0xFF, 0xE5, 0x07, 0x20, 0x7B, 0xE4, 0x07, 0x20, + 0xFF, 0xED, 0x07, 0x20, 0x7C, 0xEC, 0x07, 0x20, + 0xFF, 0xF5, 0x07, 0x20, 0x7D, 0xF4, 0x07, 0x20, + 0xFF, 0xFD, 0x07, 0x20, 0x7E, 0xFC, 0x07, 0x20, + 0xFF, 0x87, 0x07, 0x20, 0x7F, 0x86, 0x07, 0x20, + 0xFF, 0x8F, 0x07, 0x20, 0x80, 0x8E, 0x07, 0x20, + 0xFF, 0x97, 0x07, 0x20, 0x81, 0x96, 0x07, 0x20, + 0xFF, 0x9F, 0x07, 0x20, 0x82, 0x9E, 0x07, 0x20, + 0xFF, 0xA7, 0x07, 0x20, 0x83, 0xA6, 0x07, 0x20, + 0xFF, 0xAF, 0x07, 0x20, 0x84, 0xAE, 0x07, 0x20, + 0xFF, 0xB7, 0x07, 0x20, 0x85, 0xB6, 0x07, 0x20, + 0xFF, 0xBF, 0x07, 0x20, 0x86, 0xBE, 0x07, 0x20, + 0xFF, 0xC7, 0x07, 0x20, 0x87, 0xC6, 0x07, 0x20, + 0xFF, 0xCF, 0x07, 0x20, 0x88, 0xCE, 0x07, 0x20, + 0xFF, 0xD7, 0x07, 0x20, 0x89, 0xD6, 0x07, 0x20, + 0xFF, 0xDF, 0x07, 0x20, 0x8A, 0xDE, 0x07, 0x20, + 0xFF, 0xE7, 0x07, 0x20, 0x8B, 0xE6, 0x07, 0x20, + 0xFF, 0xEF, 0x07, 0x20, 0x8C, 0xEE, 0x07, 0x20, + 0xFF, 0xF7, 0x07, 0x20, 0x8D, 0xF6, 0x07, 0x20, + 0xFF, 0xFF, 0x07, 0x20, 0x8E, 0xFE, 0x07, 0x20, + 0xFF, 0xFF, 0x07, 0x20, 0x8E, 0xFE, 0x07, 0x20, + 0xFF, 0xF7, 0x07, 0x20, 0x8D, 0xF6, 0x07, 0x20, + 0xFF, 0xEF, 0x07, 0x20, 0x8C, 0xEE, 0x07, 0x20, + 0xFF, 0xE7, 0x07, 0x20, 0x8B, 0xE6, 0x07, 0x20, + 0xFF, 0xDF, 0x07, 0x20, 0x8A, 0xDE, 0x07, 0x20, + 0xFF, 0xD7, 0x07, 0x20, 0x89, 0xD6, 0x07, 0x20, + 0xFF, 0xCF, 0x07, 0x20, 0x88, 0xCE, 0x07, 0x20, + 0xFF, 0xC7, 0x07, 0x20, 0x87, 0xC6, 0x07, 0x20, + 0xFF, 0xBF, 0x07, 0x20, 0x86, 0xBE, 0x07, 0x20, + 0xFF, 0xB7, 0x07, 0x20, 0x85, 0xB6, 0x07, 0x20, + 0xFF, 0xAF, 0x07, 0x20, 0x84, 0xAE, 0x07, 0x20, + 0xFF, 0xA7, 0x07, 0x20, 0x83, 0xA6, 0x07, 0x20, + 0xFF, 0x9F, 0x07, 0x20, 0x82, 0x9E, 0x07, 0x20, + 0xFF, 0x97, 0x07, 0x20, 0x81, 0x96, 0x07, 0x20, + 0xFF, 0x8F, 0x07, 0x20, 0x80, 0x8E, 0x07, 0x20, + 0xFF, 0x87, 0x07, 0x20, 0x7F, 0x86, 0x07, 0x20, + 0xFF, 0xFD, 0x07, 0x20, 0x7E, 0xFC, 0x07, 0x20, + 0xFF, 0xF5, 0x07, 0x20, 0x7D, 0xF4, 0x07, 0x20, + 0xFF, 0xED, 0x07, 0x20, 0x7C, 0xEC, 0x07, 0x20, + 0xFF, 0xE5, 0x07, 0x20, 0x7B, 0xE4, 0x07, 0x20, + 0xFF, 0xDD, 0x07, 0x20, 0x7A, 0xDC, 0x07, 0x20, + 0xFF, 0xD5, 0x07, 0x20, 0x79, 0xD4, 0x07, 0x20, + 0xFF, 0xCD, 0x07, 0x20, 0x78, 0xCC, 0x07, 0x20, + 0xFF, 0xC5, 0x07, 0x20, 0x77, 0xC4, 0x07, 0x20, + 0xFF, 0xBD, 0x07, 0x20, 0x76, 0xBC, 0x07, 0x20, + 0xFF, 0xB5, 0x07, 0x20, 0x75, 0xB4, 0x07, 0x20, + 0xFF, 0xAD, 0x07, 0x20, 0x74, 0xAC, 0x07, 0x20, + 0xFF, 0xA5, 0x07, 0x20, 0x73, 0xA4, 0x07, 0x20, + 0xFF, 0x9D, 0x07, 0x20, 0x72, 0x9C, 0x07, 0x20, + 0xFF, 0x95, 0x07, 0x20, 0x71, 0x94, 0x07, 0x20, + 0xFF, 0x8D, 0x07, 0x20, 0x70, 0x8C, 0x07, 0x20, + 0xFF, 0x85, 0x07, 0x20, 0x6F, 0x84, 0x07, 0x20, + 0xFF, 0xFB, 0x07, 0x20, 0x6E, 0xFA, 0x07, 0x20, + 0xFF, 0xF3, 0x07, 0x20, 0x6D, 0xF2, 0x07, 0x20, + 0xFF, 0xEB, 0x07, 0x20, 0x6C, 0xEA, 0x07, 0x20, + 0xFF, 0xE3, 0x07, 0x20, 0x6B, 0xE2, 0x07, 0x20, + 0xFF, 0xDB, 0x07, 0x20, 0x6A, 0xDA, 0x07, 0x20, + 0xFF, 0xD3, 0x07, 0x20, 0x69, 0xD2, 0x07, 0x20, + 0xFF, 0xCB, 0x07, 0x20, 0x68, 0xCA, 0x07, 0x20, + 0xFF, 0xC3, 0x07, 0x20, 0x67, 0xC2, 0x07, 0x20, + 0xFF, 0xBB, 0x07, 0x20, 0x66, 0xBA, 0x07, 0x20, + 0xFF, 0xB3, 0x07, 0x20, 0x65, 0xB2, 0x07, 0x20, + 0xFF, 0xAB, 0x07, 0x20, 0x64, 0xAA, 0x07, 0x20, + 0xFF, 0xA3, 0x07, 0x20, 0x63, 0xA2, 0x07, 0x20, + 0xFF, 0x9B, 0x07, 0x20, 0x62, 0x9A, 0x07, 0x20, + 0xFF, 0x93, 0x07, 0x20, 0x61, 0x92, 0x07, 0x20, + 0xFF, 0x8B, 0x07, 0x20, 0x60, 0x8A, 0x07, 0x20, + 0xFF, 0x83, 0x07, 0x20, 0x5F, 0x82, 0x07, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, + 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, + 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x04, 0x0C, 0x00, 0x01, 0x00, 0x01, 0x0D, 0x00, + 0x28, 0x00, 0x20, 0x21, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x00, + 0x00, 0x00, 0x20, 0x21, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x1C, 0x02, 0xB0, 0x01, 0x00, + 0x00, 0x00, 0x0E, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0F, 0x00, + 0x01, 0x00, 0x01, 0x10, 0x00, 0x01, 0x00, 0x02, + 0x11, 0x00, 0x02, 0x00, 0x20, 0x00, 0x12, 0x00, + 0x01, 0x00, 0x01, 0x05, 0x00, 0x0E, 0x00, 0x0C, + 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x08, 0x00, 0x00, 0x05, 0x00, 0x0E, + 0x00, 0x10, 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, + 0x00, 0x09, 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x08, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x44, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x50, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, + 0x20, 0x04, 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, + 0x05, 0x00, 0x0E, 0x00, 0x14, 0x20, 0xFF, 0xFF, + 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x00, 0x03, 0x00, 0x09, 0x00, 0x84, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x88, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x8C, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x90, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x94, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x98, + 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x15, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x28, 0x00, + 0x00, }; static unsigned char vfs5011_init_12[] = { /* 2666 B */ - 0x02, 0xF0, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x09, - 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, - 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, - 0x20, 0x04, 0x30, 0xE5, 0x03, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, - 0xEA, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x4C, 0x20, 0x04, 0x30, 0x0A, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, - 0x04, 0x30, 0x01, 0xDE, 0x01, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, - 0x30, 0x02, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, - 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x08, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x40, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x60, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, - 0x30, 0x30, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x90, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, - 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x30, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xD8, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, - 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x04, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, - 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, - 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, - 0x30, 0x00, 0x00, 0x74, 0x01, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, - 0x74, 0x01, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, - 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, - 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, - 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, - 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, - 0xFF, 0xF9, 0x87, 0x20, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x07, 0x20, - 0xBA, 0xF8, 0x07, 0x20, 0xB9, 0xF8, 0x07, 0x20, - 0xB8, 0xF8, 0x07, 0x20, 0xB7, 0xF8, 0x07, 0x20, - 0xB6, 0xF8, 0x07, 0x20, 0xB5, 0xF8, 0x07, 0x20, - 0xB4, 0xF8, 0x07, 0x20, 0xB3, 0xF8, 0x07, 0x20, - 0xB2, 0xF8, 0x07, 0x20, 0xB1, 0xF8, 0x07, 0x22, - 0xB0, 0xF8, 0x07, 0x22, 0xAF, 0xF8, 0x07, 0x22, - 0xAE, 0xF8, 0x07, 0x22, 0xAD, 0xF8, 0x07, 0x22, - 0xAC, 0xF8, 0x07, 0x22, 0xAB, 0xF8, 0x07, 0x22, - 0xAA, 0xF8, 0x07, 0x22, 0xA9, 0xF8, 0x07, 0x22, - 0xA8, 0xF8, 0x07, 0x22, 0xA7, 0xF8, 0x07, 0x22, - 0xA6, 0xF8, 0x07, 0x22, 0xA5, 0xF8, 0x07, 0x22, - 0xA4, 0xF8, 0x07, 0x22, 0xA3, 0xF8, 0x07, 0x22, - 0xA2, 0xF8, 0x07, 0x22, 0xA1, 0xF8, 0x07, 0x22, - 0xA0, 0xF8, 0x07, 0x22, 0x9F, 0xF8, 0x07, 0x22, - 0x9E, 0xF8, 0x07, 0x22, 0x9D, 0xF8, 0x07, 0x22, - 0x9C, 0xF8, 0x07, 0x22, 0x9B, 0xF8, 0x07, 0x22, - 0x9A, 0xF8, 0x07, 0x22, 0x99, 0xF8, 0x07, 0x22, - 0x98, 0xF8, 0x07, 0x22, 0x97, 0xF8, 0x07, 0x22, - 0x96, 0xF8, 0x07, 0x22, 0x95, 0xF8, 0x07, 0x22, - 0x94, 0xF8, 0x07, 0x22, 0x93, 0xF8, 0x07, 0x22, - 0x92, 0xF8, 0x07, 0x22, 0x91, 0xF8, 0x07, 0x22, - 0x90, 0xF8, 0x07, 0x22, 0x8F, 0xF8, 0x07, 0x22, - 0x8E, 0xF8, 0x07, 0x22, 0x8D, 0xF8, 0x07, 0x22, - 0x8C, 0xF8, 0x07, 0x22, 0x8B, 0xF8, 0x07, 0x22, - 0x8A, 0xF8, 0x07, 0x22, 0x89, 0xF8, 0x07, 0x22, - 0x88, 0xF8, 0x07, 0x22, 0x87, 0xF8, 0x07, 0x22, - 0x86, 0xF8, 0x07, 0x22, 0x85, 0xF8, 0x07, 0x22, - 0x84, 0xF8, 0x07, 0x22, 0x83, 0xF8, 0x07, 0x22, - 0x82, 0xF8, 0x07, 0x22, 0x81, 0xF8, 0x07, 0x22, - 0x80, 0xF8, 0x07, 0x22, 0x7F, 0xF8, 0x07, 0x22, - 0x7E, 0xF8, 0x07, 0x22, 0x7D, 0xF8, 0x07, 0x22, - 0x7C, 0xF8, 0x07, 0x22, 0x7B, 0xF8, 0x07, 0x22, - 0x7A, 0xF8, 0x07, 0x22, 0x79, 0xF8, 0x07, 0x22, - 0x78, 0xF8, 0x07, 0x22, 0x77, 0xF8, 0x07, 0x22, - 0x76, 0xF8, 0x07, 0x22, 0x75, 0xF8, 0x07, 0x22, - 0x74, 0xF8, 0x07, 0x22, 0x73, 0xF8, 0x07, 0x22, - 0x72, 0xF8, 0x07, 0x22, 0x71, 0xF8, 0x07, 0x22, - 0x70, 0xF8, 0x07, 0x22, 0x6F, 0xF8, 0x07, 0x22, - 0x6E, 0xF8, 0x07, 0x22, 0x6D, 0xF8, 0x07, 0x22, - 0x6C, 0xF8, 0x07, 0x22, 0x6B, 0xF8, 0x07, 0x22, - 0x6A, 0xF8, 0x07, 0x22, 0x69, 0xF8, 0x07, 0x22, - 0x68, 0xF8, 0x07, 0x22, 0x67, 0xF8, 0x07, 0x22, - 0x66, 0xF8, 0x07, 0x22, 0x65, 0xF8, 0x07, 0x22, - 0x64, 0xF8, 0x07, 0x22, 0x63, 0xF8, 0x07, 0x22, - 0x62, 0xF8, 0x07, 0x22, 0x61, 0xF8, 0x07, 0x22, - 0x60, 0xF8, 0x07, 0x22, 0x5F, 0xF8, 0x07, 0x22, - 0x5E, 0xF8, 0x07, 0x22, 0x5D, 0xF8, 0x07, 0x22, - 0x5C, 0xF8, 0x07, 0x22, 0x5B, 0xF8, 0x07, 0x22, - 0x5A, 0xF8, 0x07, 0x22, 0x59, 0xF8, 0x07, 0x22, - 0x58, 0xF8, 0x07, 0x22, 0x57, 0xF8, 0x07, 0x22, - 0x56, 0xF8, 0x07, 0x22, 0x55, 0xF8, 0x07, 0x22, - 0x54, 0xF8, 0x07, 0x22, 0x53, 0xF8, 0x07, 0x22, - 0x52, 0xF8, 0x07, 0x22, 0x51, 0xF8, 0x07, 0x22, - 0x50, 0xF8, 0x07, 0x22, 0x4F, 0xF8, 0x07, 0x22, - 0x4E, 0xF8, 0x07, 0x22, 0x4D, 0xF8, 0x07, 0x22, - 0x4C, 0xF8, 0x07, 0x22, 0x4B, 0xF8, 0x07, 0x22, - 0x4A, 0xF8, 0x07, 0x22, 0x49, 0xF8, 0x07, 0x22, - 0x48, 0xF8, 0x07, 0x22, 0x47, 0xF8, 0x07, 0x22, - 0x46, 0xF8, 0x07, 0x22, 0x45, 0xF8, 0x07, 0x22, - 0x44, 0xF8, 0x07, 0x22, 0x43, 0xF8, 0x07, 0x22, - 0x42, 0xF8, 0x07, 0x22, 0x41, 0xF8, 0x07, 0x22, - 0x40, 0xF8, 0x07, 0x22, 0x3F, 0xF8, 0x07, 0x22, - 0x3E, 0xF8, 0x07, 0x22, 0x3D, 0xF8, 0x07, 0x22, - 0x3C, 0xF8, 0x07, 0x22, 0x3B, 0xF8, 0x07, 0x22, - 0x3A, 0xF8, 0x07, 0x22, 0x39, 0xF8, 0x07, 0x22, - 0x38, 0xF8, 0x07, 0x22, 0x37, 0xF8, 0x07, 0x22, - 0x36, 0xF8, 0x07, 0x22, 0x35, 0xF8, 0x07, 0x22, - 0x34, 0xF8, 0x07, 0x22, 0x33, 0xF8, 0x07, 0x22, - 0x32, 0xF8, 0x07, 0x22, 0x31, 0xF8, 0x07, 0x22, - 0x30, 0xF8, 0x07, 0x22, 0x2F, 0xF8, 0x07, 0x22, - 0x2E, 0xF8, 0x07, 0x22, 0x2D, 0xF8, 0x07, 0x22, - 0x2C, 0xF8, 0x07, 0x22, 0x2B, 0xF8, 0x07, 0x22, - 0x2A, 0xF8, 0x07, 0x22, 0x29, 0xF8, 0x07, 0x22, - 0x28, 0xF8, 0x07, 0x22, 0x27, 0xF8, 0x07, 0x22, - 0x26, 0xF8, 0x07, 0x22, 0x25, 0xF8, 0x07, 0x22, - 0x24, 0xF8, 0x07, 0x22, 0x23, 0xF8, 0x07, 0x20, - 0x22, 0xF8, 0x07, 0x20, 0x21, 0xF8, 0x07, 0x20, - 0x20, 0xF8, 0x07, 0x20, 0x1F, 0xF8, 0x07, 0x20, - 0x1E, 0xF8, 0x07, 0x20, 0x1D, 0xF8, 0x07, 0x20, - 0x1C, 0xF8, 0x07, 0x20, 0x1C, 0xF8, 0x07, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD8, 0xF8, 0x27, 0x20, 0xD9, 0xF8, 0x27, 0x20, - 0xDA, 0xF8, 0x27, 0x20, 0xDB, 0xF8, 0x27, 0x20, - 0xDC, 0xF8, 0x27, 0x20, 0xDD, 0xF8, 0x27, 0x20, - 0xDE, 0xF8, 0x27, 0x20, 0xDF, 0xF8, 0x27, 0x20, - 0xE0, 0xF8, 0x27, 0x20, 0xE1, 0xF8, 0x27, 0x20, - 0xE2, 0xF8, 0x27, 0x20, 0xE3, 0xF8, 0x27, 0x20, - 0xE4, 0xF8, 0x27, 0x20, 0xE5, 0xF8, 0x27, 0x20, - 0xE6, 0xF8, 0x27, 0x20, 0xE7, 0xF8, 0x27, 0x20, - 0xE8, 0xF8, 0x27, 0x20, 0xE9, 0xF8, 0x27, 0x20, - 0xEA, 0xF8, 0x27, 0x20, 0xEB, 0xF8, 0x27, 0x20, - 0xEC, 0xF8, 0x27, 0x20, 0xED, 0xF8, 0x27, 0x20, - 0xEE, 0xF8, 0x27, 0x20, 0xEF, 0xF8, 0x27, 0x20, - 0xF0, 0xF8, 0x27, 0x20, 0xF1, 0xF8, 0x27, 0x20, - 0xF2, 0xF8, 0x27, 0x20, 0xF3, 0xF8, 0x27, 0x20, - 0xF4, 0xF8, 0x27, 0x20, 0xF5, 0xF8, 0x27, 0x20, - 0xF6, 0xF8, 0x27, 0x20, 0xF7, 0xF8, 0x27, 0x20, - 0xF8, 0xF8, 0x27, 0x20, 0xF9, 0xF8, 0x27, 0x20, - 0xFA, 0xF8, 0x27, 0x20, 0xFB, 0xF8, 0x27, 0x20, - 0xFC, 0xF8, 0x27, 0x20, 0xFD, 0xF8, 0x27, 0x20, - 0xFE, 0xF8, 0x27, 0x20, 0xFF, 0xF8, 0x27, 0x20, - 0x00, 0xF9, 0x27, 0x20, 0xD7, 0xF8, 0x27, 0x20, - 0x00, 0xF8, 0x27, 0x20, 0x01, 0xF8, 0x27, 0x20, - 0x02, 0xF8, 0x27, 0x20, 0x03, 0xF8, 0x27, 0x20, - 0x04, 0xF8, 0x27, 0x20, 0x05, 0xF8, 0x27, 0x20, - 0x06, 0xF8, 0x27, 0x20, 0x07, 0xF8, 0x27, 0x20, - 0x08, 0xF8, 0x27, 0x20, 0x09, 0xF8, 0x27, 0x20, - 0x0A, 0xF8, 0x27, 0x20, 0x0B, 0xF8, 0x27, 0x20, - 0x0C, 0xF8, 0x27, 0x20, 0x0D, 0xF8, 0x27, 0x20, - 0x0E, 0xF8, 0x27, 0x20, 0x0F, 0xF8, 0x27, 0x20, - 0x10, 0xF8, 0x27, 0x20, 0x11, 0xF8, 0x27, 0x20, - 0x12, 0xF8, 0x27, 0x20, 0x13, 0xF8, 0x27, 0x20, - 0x14, 0xF8, 0x27, 0x20, 0x15, 0xF8, 0x27, 0x20, - 0x15, 0xF8, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, - 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, - 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, - 0x04, 0x0C, 0x00, 0x01, 0x00, 0x04, 0x11, 0x00, - 0x02, 0x00, 0x0E, 0x00, 0x13, 0x00, 0x04, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x04, 0x00, - 0x1E, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x0A, 0x00, - 0x08, 0x00, 0xA8, 0x00, 0xE6, 0x82, 0xA0, 0x0A, - 0x26, 0x06, 0x07, 0x00, 0x3C, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0x78, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x18, 0xA2, 0x55, 0x03, 0xD3, 0xA2, - 0x5D, 0x00, 0x18, 0xA2, 0x55, 0x03, 0xD3, 0xA2, - 0x5D, 0x00, 0x18, 0xA2, 0x55, 0x03, 0x20, 0x80, - 0x80, 0x00, 0xFF, 0x10, 0x0F, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x03, - 0x00, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x0C, 0x20, - 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x08, 0x00, 0x00, 0x05, 0x00, 0x0E, 0x00, - 0x10, 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x44, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, 0x20, - 0x04, 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x05, - 0x00, 0x0E, 0x00, 0x14, 0x20, 0xFF, 0xFF, 0x00, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, - 0x00, 0x03, 0x00, 0x09, 0x00, 0x84, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x88, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x8C, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x90, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x94, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x98, 0x21, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x20, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x60, 0x21, 0x04, - 0x30, 0x08, 0x00, 0x00, 0x00, 0x04, 0x15, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x28, - 0x00, 0x00, + 0x02, 0xF0, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, + 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, + 0x20, 0x04, 0x30, 0xE5, 0x03, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, + 0xEA, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x4C, 0x20, 0x04, 0x30, 0x0A, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, + 0x04, 0x30, 0x01, 0xDE, 0x01, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, + 0x30, 0x02, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, + 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x08, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x40, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x60, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x90, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, + 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x30, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xD8, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, + 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x04, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, + 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, + 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, + 0x30, 0x00, 0x00, 0x74, 0x01, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, + 0x74, 0x01, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, + 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, + 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, + 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, + 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, + 0xFF, 0xF9, 0x87, 0x20, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x07, 0x20, + 0xBA, 0xF8, 0x07, 0x20, 0xB9, 0xF8, 0x07, 0x20, + 0xB8, 0xF8, 0x07, 0x20, 0xB7, 0xF8, 0x07, 0x20, + 0xB6, 0xF8, 0x07, 0x20, 0xB5, 0xF8, 0x07, 0x20, + 0xB4, 0xF8, 0x07, 0x20, 0xB3, 0xF8, 0x07, 0x20, + 0xB2, 0xF8, 0x07, 0x20, 0xB1, 0xF8, 0x07, 0x22, + 0xB0, 0xF8, 0x07, 0x22, 0xAF, 0xF8, 0x07, 0x22, + 0xAE, 0xF8, 0x07, 0x22, 0xAD, 0xF8, 0x07, 0x22, + 0xAC, 0xF8, 0x07, 0x22, 0xAB, 0xF8, 0x07, 0x22, + 0xAA, 0xF8, 0x07, 0x22, 0xA9, 0xF8, 0x07, 0x22, + 0xA8, 0xF8, 0x07, 0x22, 0xA7, 0xF8, 0x07, 0x22, + 0xA6, 0xF8, 0x07, 0x22, 0xA5, 0xF8, 0x07, 0x22, + 0xA4, 0xF8, 0x07, 0x22, 0xA3, 0xF8, 0x07, 0x22, + 0xA2, 0xF8, 0x07, 0x22, 0xA1, 0xF8, 0x07, 0x22, + 0xA0, 0xF8, 0x07, 0x22, 0x9F, 0xF8, 0x07, 0x22, + 0x9E, 0xF8, 0x07, 0x22, 0x9D, 0xF8, 0x07, 0x22, + 0x9C, 0xF8, 0x07, 0x22, 0x9B, 0xF8, 0x07, 0x22, + 0x9A, 0xF8, 0x07, 0x22, 0x99, 0xF8, 0x07, 0x22, + 0x98, 0xF8, 0x07, 0x22, 0x97, 0xF8, 0x07, 0x22, + 0x96, 0xF8, 0x07, 0x22, 0x95, 0xF8, 0x07, 0x22, + 0x94, 0xF8, 0x07, 0x22, 0x93, 0xF8, 0x07, 0x22, + 0x92, 0xF8, 0x07, 0x22, 0x91, 0xF8, 0x07, 0x22, + 0x90, 0xF8, 0x07, 0x22, 0x8F, 0xF8, 0x07, 0x22, + 0x8E, 0xF8, 0x07, 0x22, 0x8D, 0xF8, 0x07, 0x22, + 0x8C, 0xF8, 0x07, 0x22, 0x8B, 0xF8, 0x07, 0x22, + 0x8A, 0xF8, 0x07, 0x22, 0x89, 0xF8, 0x07, 0x22, + 0x88, 0xF8, 0x07, 0x22, 0x87, 0xF8, 0x07, 0x22, + 0x86, 0xF8, 0x07, 0x22, 0x85, 0xF8, 0x07, 0x22, + 0x84, 0xF8, 0x07, 0x22, 0x83, 0xF8, 0x07, 0x22, + 0x82, 0xF8, 0x07, 0x22, 0x81, 0xF8, 0x07, 0x22, + 0x80, 0xF8, 0x07, 0x22, 0x7F, 0xF8, 0x07, 0x22, + 0x7E, 0xF8, 0x07, 0x22, 0x7D, 0xF8, 0x07, 0x22, + 0x7C, 0xF8, 0x07, 0x22, 0x7B, 0xF8, 0x07, 0x22, + 0x7A, 0xF8, 0x07, 0x22, 0x79, 0xF8, 0x07, 0x22, + 0x78, 0xF8, 0x07, 0x22, 0x77, 0xF8, 0x07, 0x22, + 0x76, 0xF8, 0x07, 0x22, 0x75, 0xF8, 0x07, 0x22, + 0x74, 0xF8, 0x07, 0x22, 0x73, 0xF8, 0x07, 0x22, + 0x72, 0xF8, 0x07, 0x22, 0x71, 0xF8, 0x07, 0x22, + 0x70, 0xF8, 0x07, 0x22, 0x6F, 0xF8, 0x07, 0x22, + 0x6E, 0xF8, 0x07, 0x22, 0x6D, 0xF8, 0x07, 0x22, + 0x6C, 0xF8, 0x07, 0x22, 0x6B, 0xF8, 0x07, 0x22, + 0x6A, 0xF8, 0x07, 0x22, 0x69, 0xF8, 0x07, 0x22, + 0x68, 0xF8, 0x07, 0x22, 0x67, 0xF8, 0x07, 0x22, + 0x66, 0xF8, 0x07, 0x22, 0x65, 0xF8, 0x07, 0x22, + 0x64, 0xF8, 0x07, 0x22, 0x63, 0xF8, 0x07, 0x22, + 0x62, 0xF8, 0x07, 0x22, 0x61, 0xF8, 0x07, 0x22, + 0x60, 0xF8, 0x07, 0x22, 0x5F, 0xF8, 0x07, 0x22, + 0x5E, 0xF8, 0x07, 0x22, 0x5D, 0xF8, 0x07, 0x22, + 0x5C, 0xF8, 0x07, 0x22, 0x5B, 0xF8, 0x07, 0x22, + 0x5A, 0xF8, 0x07, 0x22, 0x59, 0xF8, 0x07, 0x22, + 0x58, 0xF8, 0x07, 0x22, 0x57, 0xF8, 0x07, 0x22, + 0x56, 0xF8, 0x07, 0x22, 0x55, 0xF8, 0x07, 0x22, + 0x54, 0xF8, 0x07, 0x22, 0x53, 0xF8, 0x07, 0x22, + 0x52, 0xF8, 0x07, 0x22, 0x51, 0xF8, 0x07, 0x22, + 0x50, 0xF8, 0x07, 0x22, 0x4F, 0xF8, 0x07, 0x22, + 0x4E, 0xF8, 0x07, 0x22, 0x4D, 0xF8, 0x07, 0x22, + 0x4C, 0xF8, 0x07, 0x22, 0x4B, 0xF8, 0x07, 0x22, + 0x4A, 0xF8, 0x07, 0x22, 0x49, 0xF8, 0x07, 0x22, + 0x48, 0xF8, 0x07, 0x22, 0x47, 0xF8, 0x07, 0x22, + 0x46, 0xF8, 0x07, 0x22, 0x45, 0xF8, 0x07, 0x22, + 0x44, 0xF8, 0x07, 0x22, 0x43, 0xF8, 0x07, 0x22, + 0x42, 0xF8, 0x07, 0x22, 0x41, 0xF8, 0x07, 0x22, + 0x40, 0xF8, 0x07, 0x22, 0x3F, 0xF8, 0x07, 0x22, + 0x3E, 0xF8, 0x07, 0x22, 0x3D, 0xF8, 0x07, 0x22, + 0x3C, 0xF8, 0x07, 0x22, 0x3B, 0xF8, 0x07, 0x22, + 0x3A, 0xF8, 0x07, 0x22, 0x39, 0xF8, 0x07, 0x22, + 0x38, 0xF8, 0x07, 0x22, 0x37, 0xF8, 0x07, 0x22, + 0x36, 0xF8, 0x07, 0x22, 0x35, 0xF8, 0x07, 0x22, + 0x34, 0xF8, 0x07, 0x22, 0x33, 0xF8, 0x07, 0x22, + 0x32, 0xF8, 0x07, 0x22, 0x31, 0xF8, 0x07, 0x22, + 0x30, 0xF8, 0x07, 0x22, 0x2F, 0xF8, 0x07, 0x22, + 0x2E, 0xF8, 0x07, 0x22, 0x2D, 0xF8, 0x07, 0x22, + 0x2C, 0xF8, 0x07, 0x22, 0x2B, 0xF8, 0x07, 0x22, + 0x2A, 0xF8, 0x07, 0x22, 0x29, 0xF8, 0x07, 0x22, + 0x28, 0xF8, 0x07, 0x22, 0x27, 0xF8, 0x07, 0x22, + 0x26, 0xF8, 0x07, 0x22, 0x25, 0xF8, 0x07, 0x22, + 0x24, 0xF8, 0x07, 0x22, 0x23, 0xF8, 0x07, 0x20, + 0x22, 0xF8, 0x07, 0x20, 0x21, 0xF8, 0x07, 0x20, + 0x20, 0xF8, 0x07, 0x20, 0x1F, 0xF8, 0x07, 0x20, + 0x1E, 0xF8, 0x07, 0x20, 0x1D, 0xF8, 0x07, 0x20, + 0x1C, 0xF8, 0x07, 0x20, 0x1C, 0xF8, 0x07, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD8, 0xF8, 0x27, 0x20, 0xD9, 0xF8, 0x27, 0x20, + 0xDA, 0xF8, 0x27, 0x20, 0xDB, 0xF8, 0x27, 0x20, + 0xDC, 0xF8, 0x27, 0x20, 0xDD, 0xF8, 0x27, 0x20, + 0xDE, 0xF8, 0x27, 0x20, 0xDF, 0xF8, 0x27, 0x20, + 0xE0, 0xF8, 0x27, 0x20, 0xE1, 0xF8, 0x27, 0x20, + 0xE2, 0xF8, 0x27, 0x20, 0xE3, 0xF8, 0x27, 0x20, + 0xE4, 0xF8, 0x27, 0x20, 0xE5, 0xF8, 0x27, 0x20, + 0xE6, 0xF8, 0x27, 0x20, 0xE7, 0xF8, 0x27, 0x20, + 0xE8, 0xF8, 0x27, 0x20, 0xE9, 0xF8, 0x27, 0x20, + 0xEA, 0xF8, 0x27, 0x20, 0xEB, 0xF8, 0x27, 0x20, + 0xEC, 0xF8, 0x27, 0x20, 0xED, 0xF8, 0x27, 0x20, + 0xEE, 0xF8, 0x27, 0x20, 0xEF, 0xF8, 0x27, 0x20, + 0xF0, 0xF8, 0x27, 0x20, 0xF1, 0xF8, 0x27, 0x20, + 0xF2, 0xF8, 0x27, 0x20, 0xF3, 0xF8, 0x27, 0x20, + 0xF4, 0xF8, 0x27, 0x20, 0xF5, 0xF8, 0x27, 0x20, + 0xF6, 0xF8, 0x27, 0x20, 0xF7, 0xF8, 0x27, 0x20, + 0xF8, 0xF8, 0x27, 0x20, 0xF9, 0xF8, 0x27, 0x20, + 0xFA, 0xF8, 0x27, 0x20, 0xFB, 0xF8, 0x27, 0x20, + 0xFC, 0xF8, 0x27, 0x20, 0xFD, 0xF8, 0x27, 0x20, + 0xFE, 0xF8, 0x27, 0x20, 0xFF, 0xF8, 0x27, 0x20, + 0x00, 0xF9, 0x27, 0x20, 0xD7, 0xF8, 0x27, 0x20, + 0x00, 0xF8, 0x27, 0x20, 0x01, 0xF8, 0x27, 0x20, + 0x02, 0xF8, 0x27, 0x20, 0x03, 0xF8, 0x27, 0x20, + 0x04, 0xF8, 0x27, 0x20, 0x05, 0xF8, 0x27, 0x20, + 0x06, 0xF8, 0x27, 0x20, 0x07, 0xF8, 0x27, 0x20, + 0x08, 0xF8, 0x27, 0x20, 0x09, 0xF8, 0x27, 0x20, + 0x0A, 0xF8, 0x27, 0x20, 0x0B, 0xF8, 0x27, 0x20, + 0x0C, 0xF8, 0x27, 0x20, 0x0D, 0xF8, 0x27, 0x20, + 0x0E, 0xF8, 0x27, 0x20, 0x0F, 0xF8, 0x27, 0x20, + 0x10, 0xF8, 0x27, 0x20, 0x11, 0xF8, 0x27, 0x20, + 0x12, 0xF8, 0x27, 0x20, 0x13, 0xF8, 0x27, 0x20, + 0x14, 0xF8, 0x27, 0x20, 0x15, 0xF8, 0x27, 0x20, + 0x15, 0xF8, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, + 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, + 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x04, 0x0C, 0x00, 0x01, 0x00, 0x04, 0x11, 0x00, + 0x02, 0x00, 0x0E, 0x00, 0x13, 0x00, 0x04, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x04, 0x00, + 0x1E, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x0A, 0x00, + 0x08, 0x00, 0xA8, 0x00, 0xE6, 0x82, 0xA0, 0x0A, + 0x26, 0x06, 0x07, 0x00, 0x3C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0x78, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0xA2, 0x55, 0x03, 0xD3, 0xA2, + 0x5D, 0x00, 0x18, 0xA2, 0x55, 0x03, 0xD3, 0xA2, + 0x5D, 0x00, 0x18, 0xA2, 0x55, 0x03, 0x20, 0x80, + 0x80, 0x00, 0xFF, 0x10, 0x0F, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x03, + 0x00, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x0C, 0x20, + 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x08, 0x00, 0x00, 0x05, 0x00, 0x0E, 0x00, + 0x10, 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, 0x00, + 0x09, 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x44, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, 0x20, + 0x04, 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x05, + 0x00, 0x0E, 0x00, 0x14, 0x20, 0xFF, 0xFF, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, + 0x00, 0x03, 0x00, 0x09, 0x00, 0x84, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x88, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x8C, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x90, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x94, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x98, 0x21, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x20, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x60, 0x21, 0x04, + 0x30, 0x08, 0x00, 0x00, 0x00, 0x04, 0x15, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x28, + 0x00, 0x00, }; static unsigned char vfs5011_init_13[] = { /* 57 B */ - 0x12, 0x90, 0x02, 0x00, 0x00, 0xFE, 0x03, 0x00, - 0x00, 0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, - 0x00, 0x18, 0xA2, 0x55, 0x03, 0xD3, 0xA2, 0x5D, - 0x00, 0x18, 0xA2, 0x55, 0x03, 0xD3, 0xA2, 0x5D, - 0x00, 0x18, 0xA2, 0x55, 0x03, 0x20, 0xFF, 0x80, - 0x00, 0xFF, 0x04, 0x0F, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x03, 0x00, - 0x00, + 0x12, 0x90, 0x02, 0x00, 0x00, 0xFE, 0x03, 0x00, + 0x00, 0xFF, 0x1F, 0xFF, 0x1F, 0x00, 0x00, 0x00, + 0x00, 0x18, 0xA2, 0x55, 0x03, 0xD3, 0xA2, 0x5D, + 0x00, 0x18, 0xA2, 0x55, 0x03, 0xD3, 0xA2, 0x5D, + 0x00, 0x18, 0xA2, 0x55, 0x03, 0x20, 0xFF, 0x80, + 0x00, 0xFF, 0x04, 0x0F, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x03, 0x00, + 0x00, }; static unsigned char vfs5011_init_14[] = { /* 2561 B */ - 0x02, 0xF0, 0x00, 0x14, 0x00, 0x03, 0x00, 0x09, - 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, - 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, - 0x20, 0x04, 0x30, 0xE5, 0x03, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, - 0xEA, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x4C, 0x20, 0x04, 0x30, 0x0A, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, - 0x04, 0x30, 0x01, 0xDE, 0x01, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, - 0x30, 0x02, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, - 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x08, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x40, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x60, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, - 0x30, 0x30, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x90, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, - 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x30, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xD8, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, - 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x04, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, - 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, - 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, - 0x30, 0x00, 0x00, 0x74, 0x01, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, - 0x74, 0x01, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, - 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, - 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, - 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, - 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, - 0xFF, 0xF9, 0x87, 0x20, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x07, 0x20, - 0xBA, 0xF8, 0x07, 0x20, 0xB9, 0xF8, 0x07, 0x20, - 0xB8, 0xF8, 0x07, 0x20, 0xB7, 0xF8, 0x07, 0x20, - 0xB6, 0xF8, 0x07, 0x20, 0xB5, 0xF8, 0x07, 0x20, - 0xB4, 0xF8, 0x07, 0x20, 0xB3, 0xF8, 0x07, 0x20, - 0xB2, 0xF8, 0x07, 0x20, 0xB1, 0xF8, 0x07, 0x22, - 0xB0, 0xF8, 0x07, 0x22, 0xAF, 0xF8, 0x07, 0x22, - 0xAE, 0xF8, 0x07, 0x22, 0xAD, 0xF8, 0x07, 0x22, - 0xAC, 0xF8, 0x07, 0x22, 0xAB, 0xF8, 0x07, 0x22, - 0xAA, 0xF8, 0x07, 0x22, 0xA9, 0xF8, 0x07, 0x22, - 0xA8, 0xF8, 0x07, 0x22, 0xA7, 0xF8, 0x07, 0x22, - 0xA6, 0xF8, 0x07, 0x22, 0xA5, 0xF8, 0x07, 0x22, - 0xA4, 0xF8, 0x07, 0x22, 0xA3, 0xF8, 0x07, 0x22, - 0xA2, 0xF8, 0x07, 0x22, 0xA1, 0xF8, 0x07, 0x22, - 0xA0, 0xF8, 0x07, 0x22, 0x9F, 0xF8, 0x07, 0x22, - 0x9E, 0xF8, 0x07, 0x22, 0x9D, 0xF8, 0x07, 0x22, - 0x9C, 0xF8, 0x07, 0x22, 0x9B, 0xF8, 0x07, 0x22, - 0x9A, 0xF8, 0x07, 0x22, 0x99, 0xF8, 0x07, 0x22, - 0x98, 0xF8, 0x07, 0x22, 0x97, 0xF8, 0x07, 0x22, - 0x96, 0xF8, 0x07, 0x22, 0x95, 0xF8, 0x07, 0x22, - 0x94, 0xF8, 0x07, 0x22, 0x93, 0xF8, 0x07, 0x22, - 0x92, 0xF8, 0x07, 0x22, 0x91, 0xF8, 0x07, 0x22, - 0x90, 0xF8, 0x07, 0x22, 0x8F, 0xF8, 0x07, 0x22, - 0x8E, 0xF8, 0x07, 0x22, 0x8D, 0xF8, 0x07, 0x22, - 0x8C, 0xF8, 0x07, 0x22, 0x8B, 0xF8, 0x07, 0x22, - 0x8A, 0xF8, 0x07, 0x22, 0x89, 0xF8, 0x07, 0x22, - 0x88, 0xF8, 0x07, 0x22, 0x87, 0xF8, 0x07, 0x22, - 0x86, 0xF8, 0x07, 0x22, 0x85, 0xF8, 0x07, 0x22, - 0x84, 0xF8, 0x07, 0x22, 0x83, 0xF8, 0x07, 0x22, - 0x82, 0xF8, 0x07, 0x22, 0x81, 0xF8, 0x07, 0x22, - 0x80, 0xF8, 0x07, 0x22, 0x7F, 0xF8, 0x07, 0x22, - 0x7E, 0xF8, 0x07, 0x22, 0x7D, 0xF8, 0x07, 0x22, - 0x7C, 0xF8, 0x07, 0x22, 0x7B, 0xF8, 0x07, 0x22, - 0x7A, 0xF8, 0x07, 0x22, 0x79, 0xF8, 0x07, 0x22, - 0x78, 0xF8, 0x07, 0x22, 0x77, 0xF8, 0x07, 0x22, - 0x76, 0xF8, 0x07, 0x22, 0x75, 0xF8, 0x07, 0x22, - 0x74, 0xF8, 0x07, 0x22, 0x73, 0xF8, 0x07, 0x22, - 0x72, 0xF8, 0x07, 0x22, 0x71, 0xF8, 0x07, 0x22, - 0x70, 0xF8, 0x07, 0x22, 0x6F, 0xF8, 0x07, 0x22, - 0x6E, 0xF8, 0x07, 0x22, 0x6D, 0xF8, 0x07, 0x22, - 0x6C, 0xF8, 0x07, 0x22, 0x6B, 0xF8, 0x07, 0x22, - 0x6A, 0xF8, 0x07, 0x22, 0x69, 0xF8, 0x07, 0x22, - 0x68, 0xF8, 0x07, 0x22, 0x67, 0xF8, 0x07, 0x22, - 0x66, 0xF8, 0x07, 0x22, 0x65, 0xF8, 0x07, 0x22, - 0x64, 0xF8, 0x07, 0x22, 0x63, 0xF8, 0x07, 0x22, - 0x62, 0xF8, 0x07, 0x22, 0x61, 0xF8, 0x07, 0x22, - 0x60, 0xF8, 0x07, 0x22, 0x5F, 0xF8, 0x07, 0x22, - 0x5E, 0xF8, 0x07, 0x22, 0x5D, 0xF8, 0x07, 0x22, - 0x5C, 0xF8, 0x07, 0x22, 0x5B, 0xF8, 0x07, 0x22, - 0x5A, 0xF8, 0x07, 0x22, 0x59, 0xF8, 0x07, 0x22, - 0x58, 0xF8, 0x07, 0x22, 0x57, 0xF8, 0x07, 0x22, - 0x56, 0xF8, 0x07, 0x22, 0x55, 0xF8, 0x07, 0x22, - 0x54, 0xF8, 0x07, 0x22, 0x53, 0xF8, 0x07, 0x22, - 0x52, 0xF8, 0x07, 0x22, 0x51, 0xF8, 0x07, 0x22, - 0x50, 0xF8, 0x07, 0x22, 0x4F, 0xF8, 0x07, 0x22, - 0x4E, 0xF8, 0x07, 0x22, 0x4D, 0xF8, 0x07, 0x22, - 0x4C, 0xF8, 0x07, 0x22, 0x4B, 0xF8, 0x07, 0x22, - 0x4A, 0xF8, 0x07, 0x22, 0x49, 0xF8, 0x07, 0x22, - 0x48, 0xF8, 0x07, 0x22, 0x47, 0xF8, 0x07, 0x22, - 0x46, 0xF8, 0x07, 0x22, 0x45, 0xF8, 0x07, 0x22, - 0x44, 0xF8, 0x07, 0x22, 0x43, 0xF8, 0x07, 0x22, - 0x42, 0xF8, 0x07, 0x22, 0x41, 0xF8, 0x07, 0x22, - 0x40, 0xF8, 0x07, 0x22, 0x3F, 0xF8, 0x07, 0x22, - 0x3E, 0xF8, 0x07, 0x22, 0x3D, 0xF8, 0x07, 0x22, - 0x3C, 0xF8, 0x07, 0x22, 0x3B, 0xF8, 0x07, 0x22, - 0x3A, 0xF8, 0x07, 0x22, 0x39, 0xF8, 0x07, 0x22, - 0x38, 0xF8, 0x07, 0x22, 0x37, 0xF8, 0x07, 0x22, - 0x36, 0xF8, 0x07, 0x22, 0x35, 0xF8, 0x07, 0x22, - 0x34, 0xF8, 0x07, 0x22, 0x33, 0xF8, 0x07, 0x22, - 0x32, 0xF8, 0x07, 0x22, 0x31, 0xF8, 0x07, 0x22, - 0x30, 0xF8, 0x07, 0x22, 0x2F, 0xF8, 0x07, 0x22, - 0x2E, 0xF8, 0x07, 0x22, 0x2D, 0xF8, 0x07, 0x22, - 0x2C, 0xF8, 0x07, 0x22, 0x2B, 0xF8, 0x07, 0x22, - 0x2A, 0xF8, 0x07, 0x22, 0x29, 0xF8, 0x07, 0x22, - 0x28, 0xF8, 0x07, 0x22, 0x27, 0xF8, 0x07, 0x22, - 0x26, 0xF8, 0x07, 0x22, 0x25, 0xF8, 0x07, 0x22, - 0x24, 0xF8, 0x07, 0x22, 0x23, 0xF8, 0x07, 0x20, - 0x22, 0xF8, 0x07, 0x20, 0x21, 0xF8, 0x07, 0x20, - 0x20, 0xF8, 0x07, 0x20, 0x1F, 0xF8, 0x07, 0x20, - 0x1E, 0xF8, 0x07, 0x20, 0x1D, 0xF8, 0x07, 0x20, - 0x1C, 0xF8, 0x07, 0x20, 0x1C, 0xF8, 0x07, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD8, 0xF8, 0x27, 0x20, 0xD9, 0xF8, 0x27, 0x20, - 0xDA, 0xF8, 0x27, 0x20, 0xDB, 0xF8, 0x27, 0x20, - 0xDC, 0xF8, 0x27, 0x20, 0xDD, 0xF8, 0x27, 0x20, - 0xDE, 0xF8, 0x27, 0x20, 0xDF, 0xF8, 0x27, 0x20, - 0xE0, 0xF8, 0x27, 0x20, 0xE1, 0xF8, 0x27, 0x20, - 0xE2, 0xF8, 0x27, 0x20, 0xE3, 0xF8, 0x27, 0x20, - 0xE4, 0xF8, 0x27, 0x20, 0xE5, 0xF8, 0x27, 0x20, - 0xE6, 0xF8, 0x27, 0x20, 0xE7, 0xF8, 0x27, 0x20, - 0xE8, 0xF8, 0x27, 0x20, 0xE9, 0xF8, 0x27, 0x20, - 0xEA, 0xF8, 0x27, 0x20, 0xEB, 0xF8, 0x27, 0x20, - 0xEC, 0xF8, 0x27, 0x20, 0xED, 0xF8, 0x27, 0x20, - 0xEE, 0xF8, 0x27, 0x20, 0xEF, 0xF8, 0x27, 0x20, - 0xF0, 0xF8, 0x27, 0x20, 0xF1, 0xF8, 0x27, 0x20, - 0xF2, 0xF8, 0x27, 0x20, 0xF3, 0xF8, 0x27, 0x20, - 0xF4, 0xF8, 0x27, 0x20, 0xF5, 0xF8, 0x27, 0x20, - 0xF6, 0xF8, 0x27, 0x20, 0xF7, 0xF8, 0x27, 0x20, - 0xF8, 0xF8, 0x27, 0x20, 0xF9, 0xF8, 0x27, 0x20, - 0xFA, 0xF8, 0x27, 0x20, 0xFB, 0xF8, 0x27, 0x20, - 0xFC, 0xF8, 0x27, 0x20, 0xFD, 0xF8, 0x27, 0x20, - 0xFE, 0xF8, 0x27, 0x20, 0xFF, 0xF8, 0x27, 0x20, - 0x00, 0xF9, 0x27, 0x20, 0xD7, 0xF8, 0x27, 0x20, - 0x00, 0xF8, 0x27, 0x20, 0x01, 0xF8, 0x27, 0x20, - 0x02, 0xF8, 0x27, 0x20, 0x03, 0xF8, 0x27, 0x20, - 0x04, 0xF8, 0x27, 0x20, 0x05, 0xF8, 0x27, 0x20, - 0x06, 0xF8, 0x27, 0x20, 0x07, 0xF8, 0x27, 0x20, - 0x08, 0xF8, 0x27, 0x20, 0x09, 0xF8, 0x27, 0x20, - 0x0A, 0xF8, 0x27, 0x20, 0x0B, 0xF8, 0x27, 0x20, - 0x0C, 0xF8, 0x27, 0x20, 0x0D, 0xF8, 0x27, 0x20, - 0x0E, 0xF8, 0x27, 0x20, 0x0F, 0xF8, 0x27, 0x20, - 0x10, 0xF8, 0x27, 0x20, 0x11, 0xF8, 0x27, 0x20, - 0x12, 0xF8, 0x27, 0x20, 0x13, 0xF8, 0x27, 0x20, - 0x14, 0xF8, 0x27, 0x20, 0x15, 0xF8, 0x27, 0x20, - 0x15, 0xF8, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, - 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, - 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, - 0x04, 0x05, 0x00, 0x0E, 0x00, 0x0C, 0x20, 0xFD, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x08, 0x00, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x10, - 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, 0x00, 0x09, - 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, - 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, - 0x0E, 0x00, 0x14, 0x20, 0xFF, 0xFF, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00, - 0x03, 0x00, 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x88, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x90, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x94, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x20, - 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x60, 0x21, 0x04, 0x30, - 0x08, 0x00, 0x00, 0x00, 0x04, 0x15, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x28, 0x00, - 0x00, + 0x02, 0xF0, 0x00, 0x14, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, + 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, + 0x20, 0x04, 0x30, 0xE5, 0x03, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, + 0xEA, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x4C, 0x20, 0x04, 0x30, 0x0A, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, + 0x04, 0x30, 0x01, 0xDE, 0x01, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, + 0x30, 0x02, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, + 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x08, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x40, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x60, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x90, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, + 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x30, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xD8, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, + 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x04, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, + 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, + 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, + 0x30, 0x00, 0x00, 0x74, 0x01, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, + 0x74, 0x01, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, + 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, + 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, + 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, + 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, + 0xFF, 0xF9, 0x87, 0x20, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x07, 0x20, + 0xBA, 0xF8, 0x07, 0x20, 0xB9, 0xF8, 0x07, 0x20, + 0xB8, 0xF8, 0x07, 0x20, 0xB7, 0xF8, 0x07, 0x20, + 0xB6, 0xF8, 0x07, 0x20, 0xB5, 0xF8, 0x07, 0x20, + 0xB4, 0xF8, 0x07, 0x20, 0xB3, 0xF8, 0x07, 0x20, + 0xB2, 0xF8, 0x07, 0x20, 0xB1, 0xF8, 0x07, 0x22, + 0xB0, 0xF8, 0x07, 0x22, 0xAF, 0xF8, 0x07, 0x22, + 0xAE, 0xF8, 0x07, 0x22, 0xAD, 0xF8, 0x07, 0x22, + 0xAC, 0xF8, 0x07, 0x22, 0xAB, 0xF8, 0x07, 0x22, + 0xAA, 0xF8, 0x07, 0x22, 0xA9, 0xF8, 0x07, 0x22, + 0xA8, 0xF8, 0x07, 0x22, 0xA7, 0xF8, 0x07, 0x22, + 0xA6, 0xF8, 0x07, 0x22, 0xA5, 0xF8, 0x07, 0x22, + 0xA4, 0xF8, 0x07, 0x22, 0xA3, 0xF8, 0x07, 0x22, + 0xA2, 0xF8, 0x07, 0x22, 0xA1, 0xF8, 0x07, 0x22, + 0xA0, 0xF8, 0x07, 0x22, 0x9F, 0xF8, 0x07, 0x22, + 0x9E, 0xF8, 0x07, 0x22, 0x9D, 0xF8, 0x07, 0x22, + 0x9C, 0xF8, 0x07, 0x22, 0x9B, 0xF8, 0x07, 0x22, + 0x9A, 0xF8, 0x07, 0x22, 0x99, 0xF8, 0x07, 0x22, + 0x98, 0xF8, 0x07, 0x22, 0x97, 0xF8, 0x07, 0x22, + 0x96, 0xF8, 0x07, 0x22, 0x95, 0xF8, 0x07, 0x22, + 0x94, 0xF8, 0x07, 0x22, 0x93, 0xF8, 0x07, 0x22, + 0x92, 0xF8, 0x07, 0x22, 0x91, 0xF8, 0x07, 0x22, + 0x90, 0xF8, 0x07, 0x22, 0x8F, 0xF8, 0x07, 0x22, + 0x8E, 0xF8, 0x07, 0x22, 0x8D, 0xF8, 0x07, 0x22, + 0x8C, 0xF8, 0x07, 0x22, 0x8B, 0xF8, 0x07, 0x22, + 0x8A, 0xF8, 0x07, 0x22, 0x89, 0xF8, 0x07, 0x22, + 0x88, 0xF8, 0x07, 0x22, 0x87, 0xF8, 0x07, 0x22, + 0x86, 0xF8, 0x07, 0x22, 0x85, 0xF8, 0x07, 0x22, + 0x84, 0xF8, 0x07, 0x22, 0x83, 0xF8, 0x07, 0x22, + 0x82, 0xF8, 0x07, 0x22, 0x81, 0xF8, 0x07, 0x22, + 0x80, 0xF8, 0x07, 0x22, 0x7F, 0xF8, 0x07, 0x22, + 0x7E, 0xF8, 0x07, 0x22, 0x7D, 0xF8, 0x07, 0x22, + 0x7C, 0xF8, 0x07, 0x22, 0x7B, 0xF8, 0x07, 0x22, + 0x7A, 0xF8, 0x07, 0x22, 0x79, 0xF8, 0x07, 0x22, + 0x78, 0xF8, 0x07, 0x22, 0x77, 0xF8, 0x07, 0x22, + 0x76, 0xF8, 0x07, 0x22, 0x75, 0xF8, 0x07, 0x22, + 0x74, 0xF8, 0x07, 0x22, 0x73, 0xF8, 0x07, 0x22, + 0x72, 0xF8, 0x07, 0x22, 0x71, 0xF8, 0x07, 0x22, + 0x70, 0xF8, 0x07, 0x22, 0x6F, 0xF8, 0x07, 0x22, + 0x6E, 0xF8, 0x07, 0x22, 0x6D, 0xF8, 0x07, 0x22, + 0x6C, 0xF8, 0x07, 0x22, 0x6B, 0xF8, 0x07, 0x22, + 0x6A, 0xF8, 0x07, 0x22, 0x69, 0xF8, 0x07, 0x22, + 0x68, 0xF8, 0x07, 0x22, 0x67, 0xF8, 0x07, 0x22, + 0x66, 0xF8, 0x07, 0x22, 0x65, 0xF8, 0x07, 0x22, + 0x64, 0xF8, 0x07, 0x22, 0x63, 0xF8, 0x07, 0x22, + 0x62, 0xF8, 0x07, 0x22, 0x61, 0xF8, 0x07, 0x22, + 0x60, 0xF8, 0x07, 0x22, 0x5F, 0xF8, 0x07, 0x22, + 0x5E, 0xF8, 0x07, 0x22, 0x5D, 0xF8, 0x07, 0x22, + 0x5C, 0xF8, 0x07, 0x22, 0x5B, 0xF8, 0x07, 0x22, + 0x5A, 0xF8, 0x07, 0x22, 0x59, 0xF8, 0x07, 0x22, + 0x58, 0xF8, 0x07, 0x22, 0x57, 0xF8, 0x07, 0x22, + 0x56, 0xF8, 0x07, 0x22, 0x55, 0xF8, 0x07, 0x22, + 0x54, 0xF8, 0x07, 0x22, 0x53, 0xF8, 0x07, 0x22, + 0x52, 0xF8, 0x07, 0x22, 0x51, 0xF8, 0x07, 0x22, + 0x50, 0xF8, 0x07, 0x22, 0x4F, 0xF8, 0x07, 0x22, + 0x4E, 0xF8, 0x07, 0x22, 0x4D, 0xF8, 0x07, 0x22, + 0x4C, 0xF8, 0x07, 0x22, 0x4B, 0xF8, 0x07, 0x22, + 0x4A, 0xF8, 0x07, 0x22, 0x49, 0xF8, 0x07, 0x22, + 0x48, 0xF8, 0x07, 0x22, 0x47, 0xF8, 0x07, 0x22, + 0x46, 0xF8, 0x07, 0x22, 0x45, 0xF8, 0x07, 0x22, + 0x44, 0xF8, 0x07, 0x22, 0x43, 0xF8, 0x07, 0x22, + 0x42, 0xF8, 0x07, 0x22, 0x41, 0xF8, 0x07, 0x22, + 0x40, 0xF8, 0x07, 0x22, 0x3F, 0xF8, 0x07, 0x22, + 0x3E, 0xF8, 0x07, 0x22, 0x3D, 0xF8, 0x07, 0x22, + 0x3C, 0xF8, 0x07, 0x22, 0x3B, 0xF8, 0x07, 0x22, + 0x3A, 0xF8, 0x07, 0x22, 0x39, 0xF8, 0x07, 0x22, + 0x38, 0xF8, 0x07, 0x22, 0x37, 0xF8, 0x07, 0x22, + 0x36, 0xF8, 0x07, 0x22, 0x35, 0xF8, 0x07, 0x22, + 0x34, 0xF8, 0x07, 0x22, 0x33, 0xF8, 0x07, 0x22, + 0x32, 0xF8, 0x07, 0x22, 0x31, 0xF8, 0x07, 0x22, + 0x30, 0xF8, 0x07, 0x22, 0x2F, 0xF8, 0x07, 0x22, + 0x2E, 0xF8, 0x07, 0x22, 0x2D, 0xF8, 0x07, 0x22, + 0x2C, 0xF8, 0x07, 0x22, 0x2B, 0xF8, 0x07, 0x22, + 0x2A, 0xF8, 0x07, 0x22, 0x29, 0xF8, 0x07, 0x22, + 0x28, 0xF8, 0x07, 0x22, 0x27, 0xF8, 0x07, 0x22, + 0x26, 0xF8, 0x07, 0x22, 0x25, 0xF8, 0x07, 0x22, + 0x24, 0xF8, 0x07, 0x22, 0x23, 0xF8, 0x07, 0x20, + 0x22, 0xF8, 0x07, 0x20, 0x21, 0xF8, 0x07, 0x20, + 0x20, 0xF8, 0x07, 0x20, 0x1F, 0xF8, 0x07, 0x20, + 0x1E, 0xF8, 0x07, 0x20, 0x1D, 0xF8, 0x07, 0x20, + 0x1C, 0xF8, 0x07, 0x20, 0x1C, 0xF8, 0x07, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD8, 0xF8, 0x27, 0x20, 0xD9, 0xF8, 0x27, 0x20, + 0xDA, 0xF8, 0x27, 0x20, 0xDB, 0xF8, 0x27, 0x20, + 0xDC, 0xF8, 0x27, 0x20, 0xDD, 0xF8, 0x27, 0x20, + 0xDE, 0xF8, 0x27, 0x20, 0xDF, 0xF8, 0x27, 0x20, + 0xE0, 0xF8, 0x27, 0x20, 0xE1, 0xF8, 0x27, 0x20, + 0xE2, 0xF8, 0x27, 0x20, 0xE3, 0xF8, 0x27, 0x20, + 0xE4, 0xF8, 0x27, 0x20, 0xE5, 0xF8, 0x27, 0x20, + 0xE6, 0xF8, 0x27, 0x20, 0xE7, 0xF8, 0x27, 0x20, + 0xE8, 0xF8, 0x27, 0x20, 0xE9, 0xF8, 0x27, 0x20, + 0xEA, 0xF8, 0x27, 0x20, 0xEB, 0xF8, 0x27, 0x20, + 0xEC, 0xF8, 0x27, 0x20, 0xED, 0xF8, 0x27, 0x20, + 0xEE, 0xF8, 0x27, 0x20, 0xEF, 0xF8, 0x27, 0x20, + 0xF0, 0xF8, 0x27, 0x20, 0xF1, 0xF8, 0x27, 0x20, + 0xF2, 0xF8, 0x27, 0x20, 0xF3, 0xF8, 0x27, 0x20, + 0xF4, 0xF8, 0x27, 0x20, 0xF5, 0xF8, 0x27, 0x20, + 0xF6, 0xF8, 0x27, 0x20, 0xF7, 0xF8, 0x27, 0x20, + 0xF8, 0xF8, 0x27, 0x20, 0xF9, 0xF8, 0x27, 0x20, + 0xFA, 0xF8, 0x27, 0x20, 0xFB, 0xF8, 0x27, 0x20, + 0xFC, 0xF8, 0x27, 0x20, 0xFD, 0xF8, 0x27, 0x20, + 0xFE, 0xF8, 0x27, 0x20, 0xFF, 0xF8, 0x27, 0x20, + 0x00, 0xF9, 0x27, 0x20, 0xD7, 0xF8, 0x27, 0x20, + 0x00, 0xF8, 0x27, 0x20, 0x01, 0xF8, 0x27, 0x20, + 0x02, 0xF8, 0x27, 0x20, 0x03, 0xF8, 0x27, 0x20, + 0x04, 0xF8, 0x27, 0x20, 0x05, 0xF8, 0x27, 0x20, + 0x06, 0xF8, 0x27, 0x20, 0x07, 0xF8, 0x27, 0x20, + 0x08, 0xF8, 0x27, 0x20, 0x09, 0xF8, 0x27, 0x20, + 0x0A, 0xF8, 0x27, 0x20, 0x0B, 0xF8, 0x27, 0x20, + 0x0C, 0xF8, 0x27, 0x20, 0x0D, 0xF8, 0x27, 0x20, + 0x0E, 0xF8, 0x27, 0x20, 0x0F, 0xF8, 0x27, 0x20, + 0x10, 0xF8, 0x27, 0x20, 0x11, 0xF8, 0x27, 0x20, + 0x12, 0xF8, 0x27, 0x20, 0x13, 0xF8, 0x27, 0x20, + 0x14, 0xF8, 0x27, 0x20, 0x15, 0xF8, 0x27, 0x20, + 0x15, 0xF8, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, + 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, + 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x04, 0x05, 0x00, 0x0E, 0x00, 0x0C, 0x20, 0xFD, + 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x08, 0x00, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x10, + 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, + 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, + 0x0E, 0x00, 0x14, 0x20, 0xFF, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00, + 0x03, 0x00, 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x88, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x90, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x94, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x20, + 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x60, 0x21, 0x04, 0x30, + 0x08, 0x00, 0x00, 0x00, 0x04, 0x15, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x28, 0x00, + 0x00, }; static unsigned char vfs5011_cmd_27[] = { /* 1 B */ - 0x27, + 0x27, }; static unsigned char vfs5011_init_15[] = { /* 3794 B */ - 0x06, 0x6B, 0x06, 0x6A, 0x76, 0xC8, 0x18, 0xD4, - 0x54, 0xEF, 0x71, 0x14, 0xCC, 0x1C, 0x58, 0x91, - 0x11, 0xAA, 0x80, 0xF4, 0x2C, 0xFC, 0x9F, 0x5F, - 0xDF, 0x04, 0x02, 0x62, 0xBA, 0x6A, 0x5A, 0x97, - 0x17, 0xCC, 0x46, 0x22, 0xFA, 0x2A, 0xBE, 0x03, - 0x87, 0x3C, 0x9E, 0xFE, 0x26, 0xF6, 0x96, 0x7E, - 0xFA, 0x11, 0x27, 0x66, 0xBA, 0x3A, 0x5A, 0xBA, - 0x3E, 0xD5, 0x4F, 0x03, 0xDF, 0x5F, 0x7F, 0x9F, - 0x1B, 0xF0, 0xA2, 0xEF, 0x33, 0xB3, 0xD3, 0x13, - 0x93, 0x70, 0xFA, 0x96, 0x4E, 0xC6, 0xA6, 0xC6, - 0x46, 0xA5, 0x2F, 0xE3, 0x3B, 0xB3, 0xD3, 0x33, - 0xB3, 0x50, 0xE8, 0xA4, 0x7C, 0xF4, 0x94, 0x14, - 0x94, 0x77, 0xC9, 0xE5, 0x3D, 0xB5, 0xD5, 0x75, - 0xF5, 0x16, 0xA8, 0xA4, 0x7C, 0xF4, 0x94, 0xD4, - 0x54, 0xB7, 0x09, 0xE5, 0x3D, 0xB5, 0x2D, 0xF4, - 0x74, 0xCF, 0x29, 0x5C, 0x84, 0x54, 0x14, 0xAA, - 0x2E, 0x95, 0xF7, 0xE0, 0x3C, 0xEC, 0x8C, 0x52, - 0xD6, 0x3D, 0x7B, 0x0E, 0xD6, 0x06, 0x82, 0x49, - 0xC9, 0x72, 0x7C, 0x18, 0xC0, 0x10, 0x10, 0xF6, - 0x72, 0xC9, 0xC3, 0xA8, 0x70, 0xA0, 0xD8, 0x77, - 0xF3, 0x48, 0x06, 0x04, 0xD8, 0x08, 0x90, 0x5B, - 0xDB, 0x60, 0x36, 0x43, 0x9B, 0x4B, 0xD4, 0xE3, - 0x9C, 0xB8, 0xF1, 0x72, 0x55, 0x1A, 0x8E, 0x57, - 0xD7, 0x6C, 0xDA, 0xBE, 0x66, 0xD6, 0xEA, 0x3D, - 0xBF, 0x04, 0xB2, 0xCE, 0x16, 0xA6, 0x06, 0xDE, - 0x5E, 0xE5, 0xB7, 0xC3, 0x1B, 0xCB, 0x47, 0x9F, - 0x1F, 0xA4, 0x3E, 0x5B, 0x83, 0x53, 0x53, 0x8A, - 0x0A, 0xB1, 0x93, 0xF9, 0x21, 0xF1, 0x31, 0xE6, - 0x64, 0xDF, 0x95, 0xE0, 0x38, 0xE8, 0xB4, 0x6D, - 0xED, 0x56, 0x1D, 0x8E, 0x56, 0xE6, 0x79, 0xB9, - 0xC6, 0xE2, 0x62, 0x4F, 0x97, 0x02, 0x40, 0x80, - 0x65, 0xB8, 0x0E, 0x07, 0xC2, 0x72, 0x37, 0xBE, - 0x3E, 0x00, 0xF2, 0xB8, 0xF1, 0x6D, 0x0E, 0x6F, - 0xC2, 0x1A, 0xA0, 0xC4, 0x95, 0x2F, 0xCD, 0x44, - 0xC4, 0x02, 0x44, 0x28, 0xF0, 0x40, 0x16, 0x97, - 0x17, 0x7D, 0xE4, 0x8B, 0xFE, 0x4C, 0x0D, 0xE3, - 0x60, 0xFD, 0x4B, 0x27, 0x34, 0xA6, 0xCD, 0xB6, - 0x10, 0xC0, 0x7C, 0x98, 0x42, 0x72, 0x92, 0x26, - 0x21, 0x60, 0x26, 0x4C, 0x95, 0x25, 0xA0, 0x03, - 0xA6, 0x50, 0xEC, 0x9D, 0xB5, 0x05, 0x53, 0xD2, - 0x52, 0xA9, 0x7E, 0x12, 0x2F, 0x65, 0xFA, 0x1A, - 0x7C, 0xB4, 0x12, 0x5E, 0x86, 0x3A, 0x50, 0xF5, - 0x53, 0xAD, 0xBA, 0xE6, 0x3D, 0x3C, 0x6D, 0xAE, - 0xCB, 0x33, 0xAD, 0xDC, 0xF4, 0x44, 0x12, 0x93, - 0x13, 0xF9, 0x7D, 0x12, 0xEB, 0x68, 0x0B, 0xE2, - 0x21, 0xE7, 0xA1, 0xCD, 0x15, 0xA5, 0xF3, 0x72, - 0xF2, 0xAB, 0x1F, 0x7E, 0xAA, 0x01, 0xE1, 0xA1, - 0x25, 0xA8, 0x06, 0x6D, 0xB9, 0x0C, 0x60, 0xA6, - 0x64, 0xAD, 0x15, 0x65, 0xBA, 0x30, 0x14, 0x66, - 0x22, 0x78, 0xFC, 0x94, 0x4C, 0x4E, 0x25, 0x9B, - 0xD9, 0x06, 0xB1, 0xEA, 0x89, 0x35, 0x62, 0x1E, - 0x8F, 0x69, 0xD4, 0x7F, 0x1C, 0xA0, 0xFD, 0x31, - 0x77, 0xAD, 0x1B, 0x40, 0xA4, 0x10, 0xB7, 0xCC, - 0x4D, 0xAB, 0x16, 0xD7, 0x0C, 0x01, 0x62, 0x87, - 0xBF, 0x4C, 0x50, 0x5A, 0xD8, 0x3B, 0x50, 0xE7, - 0x2C, 0xB3, 0xB7, 0x1F, 0x46, 0xA0, 0x57, 0x6B, - 0x46, 0x98, 0x93, 0xFA, 0xC7, 0xC1, 0x89, 0x45, - 0xDE, 0xD7, 0xC3, 0xC3, 0xBB, 0xCF, 0xEE, 0xEE, - 0xA8, 0xB3, 0xDF, 0x61, 0x4B, 0xE6, 0x04, 0x04, - 0x40, 0xDA, 0xAC, 0x43, 0xDA, 0x9A, 0x15, 0x25, - 0x45, 0x7D, 0xEA, 0x0C, 0x3A, 0x7A, 0xD4, 0x87, - 0xC5, 0x43, 0x77, 0x1D, 0xC6, 0x76, 0xD4, 0xB6, - 0x5A, 0x4B, 0x3F, 0x91, 0x55, 0x98, 0xC2, 0xCE, - 0x8C, 0x5B, 0xED, 0x53, 0x99, 0x20, 0x6D, 0xA6, - 0xF1, 0x96, 0x21, 0x41, 0xBB, 0x16, 0x86, 0x46, - 0xC6, 0x1D, 0x9D, 0xB0, 0x68, 0x69, 0x3D, 0xFE, - 0xC6, 0x16, 0x2C, 0x2B, 0x51, 0x40, 0x40, 0x2A, - 0x01, 0xBF, 0xB3, 0xFF, 0x8A, 0x38, 0x3D, 0x51, - 0xF4, 0x32, 0x74, 0x18, 0xC0, 0x70, 0x26, 0xA7, - 0x27, 0x5D, 0xDE, 0xB1, 0xD8, 0x5E, 0x3D, 0x30, - 0xB2, 0x0C, 0xEC, 0xA5, 0xCC, 0x44, 0x27, 0xC7, - 0x6D, 0x16, 0x01, 0x5A, 0x81, 0xFC, 0x9E, 0x3B, - 0xEE, 0x10, 0x17, 0x41, 0x9A, 0x0A, 0x50, 0x30, - 0x72, 0x6A, 0xCC, 0x01, 0xE0, 0x53, 0x3F, 0xFD, - 0x54, 0x8C, 0x13, 0x6C, 0x9D, 0x0E, 0x47, 0xB4, - 0xD1, 0x59, 0xCA, 0x17, 0xF3, 0x40, 0x10, 0xEA, - 0xCA, 0xD3, 0xA6, 0xDA, 0xA3, 0x28, 0x4B, 0x6E, - 0xBC, 0x42, 0xF8, 0x9D, 0x75, 0xFF, 0x3F, 0xCD, - 0x8E, 0x45, 0xE8, 0x1D, 0xEC, 0x5F, 0x74, 0x87, - 0x61, 0x23, 0x63, 0xA2, 0x79, 0x7B, 0xBB, 0xDE, - 0x72, 0xE5, 0xB6, 0x7B, 0x8B, 0x9A, 0xC7, 0x04, - 0x35, 0xD0, 0x65, 0xCB, 0xD0, 0x44, 0x41, 0xD1, - 0x74, 0x1E, 0xE8, 0x87, 0x6F, 0xE5, 0x25, 0x44, - 0xFB, 0x23, 0xA7, 0x08, 0xF4, 0x89, 0xEA, 0xCF, - 0x1E, 0xE0, 0xE7, 0xC9, 0x12, 0x92, 0xC8, 0xA8, - 0x89, 0x13, 0xA6, 0x07, 0xDC, 0xC9, 0xFA, 0x1F, - 0x2E, 0xB1, 0x04, 0x58, 0xBA, 0xAA, 0x6B, 0xE8, - 0x6B, 0x7D, 0xC8, 0x01, 0x8B, 0x1E, 0xCF, 0x49, - 0xCA, 0x21, 0xAD, 0x61, 0x18, 0xED, 0x8E, 0x83, - 0x00, 0x3E, 0xD9, 0x90, 0x78, 0xE2, 0x22, 0xFF, - 0x8F, 0x54, 0xD4, 0xF9, 0x21, 0x10, 0x37, 0xF4, - 0xFC, 0x2F, 0x15, 0x31, 0x48, 0xB0, 0xD3, 0x36, - 0xC1, 0x32, 0x99, 0x05, 0xDD, 0x6D, 0x3B, 0xBA, - 0x3A, 0x60, 0x91, 0xFE, 0xAE, 0x16, 0xFA, 0x72, - 0x53, 0xC0, 0x75, 0xFC, 0x51, 0xC9, 0x0C, 0x38, - 0x99, 0x5F, 0x19, 0x75, 0xAD, 0x1D, 0x4B, 0xCA, - 0x4A, 0x3C, 0x88, 0x01, 0x40, 0xD2, 0x33, 0xB4, - 0x37, 0x64, 0xDA, 0x3A, 0xAA, 0xBB, 0x93, 0x50, - 0xF5, 0x5A, 0xC4, 0xB5, 0x9D, 0x2D, 0x7B, 0xFA, - 0x7A, 0x84, 0x17, 0x7B, 0x22, 0xD8, 0xBB, 0xEA, - 0x58, 0x80, 0x97, 0xB2, 0x69, 0x70, 0x49, 0x00, - 0x89, 0x4F, 0x09, 0x65, 0xBD, 0x0D, 0x5B, 0xDA, - 0x5A, 0xB0, 0x32, 0x5D, 0x89, 0x1E, 0x46, 0x85, - 0x54, 0xC4, 0x71, 0x8F, 0x54, 0xEC, 0xEE, 0x8F, - 0x7F, 0xAF, 0x90, 0xEA, 0x7A, 0xCC, 0x7D, 0xF1, - 0x72, 0xA5, 0x79, 0x19, 0xC6, 0xF4, 0x5D, 0x61, - 0xF7, 0x24, 0x98, 0xD2, 0x53, 0xEB, 0x26, 0xE4, - 0x01, 0x67, 0xF7, 0xB6, 0x64, 0xC9, 0x59, 0xF3, - 0x30, 0x59, 0xFC, 0x9B, 0xD1, 0x65, 0x05, 0xD3, - 0x68, 0xB8, 0x68, 0x7D, 0xB5, 0xC7, 0xB3, 0x8F, - 0x59, 0x2E, 0x92, 0x5C, 0xC7, 0x7F, 0x3D, 0xFE, - 0x73, 0x88, 0x1F, 0x77, 0xB2, 0xF2, 0x9E, 0x55, - 0x57, 0x8F, 0x34, 0x9A, 0x61, 0x0C, 0x7B, 0xD3, - 0x5C, 0x15, 0xAE, 0xC2, 0x16, 0xB4, 0xC2, 0x2B, - 0xA5, 0x75, 0x6A, 0xA4, 0x31, 0x81, 0xA7, 0x67, - 0xE7, 0x30, 0x84, 0x28, 0xD0, 0x60, 0xA2, 0x71, - 0xF9, 0xE0, 0x33, 0xFF, 0xAB, 0x01, 0x04, 0x22, - 0x84, 0x42, 0x04, 0x02, 0x99, 0xFB, 0x9F, 0x5F, - 0xB9, 0x7F, 0xF5, 0x21, 0xDB, 0xC6, 0xA5, 0x00, - 0x60, 0x9D, 0x8B, 0x07, 0xAB, 0x7D, 0x03, 0xE2, - 0xD3, 0x45, 0xF0, 0x6E, 0xBD, 0x0D, 0x4B, 0xA4, - 0x23, 0x8A, 0x77, 0x1B, 0xCF, 0x75, 0x30, 0x96, - 0x33, 0xE4, 0x6A, 0x94, 0x6F, 0x01, 0xA1, 0x41, - 0xC1, 0x88, 0x5B, 0x97, 0xCD, 0x3E, 0x56, 0xD0, - 0x53, 0x88, 0x9C, 0xE3, 0x3C, 0x00, 0x1A, 0xA8, - 0x6C, 0xB7, 0xA3, 0xDC, 0x03, 0x96, 0x14, 0xF2, - 0x7E, 0xB7, 0x1C, 0x80, 0xEA, 0x49, 0x21, 0x8B, - 0x48, 0x85, 0xF8, 0x93, 0x89, 0x3D, 0x5D, 0x5F, - 0x13, 0x33, 0x93, 0xC3, 0x1C, 0x4E, 0x2D, 0xE0, - 0xE2, 0x1D, 0x2A, 0x51, 0xE7, 0x07, 0xF5, 0x38, - 0xB8, 0x75, 0x4A, 0x2A, 0xFE, 0x5C, 0x37, 0x0E, - 0x7C, 0xEA, 0x5C, 0xB6, 0x7E, 0xCE, 0x2C, 0x25, - 0x5C, 0xD1, 0xFF, 0x66, 0x06, 0x94, 0x59, 0x9A, - 0x7F, 0x7D, 0xED, 0x21, 0x69, 0xAD, 0xC6, 0x9F, - 0x49, 0x7B, 0xC7, 0xA7, 0x74, 0xC8, 0xE4, 0xC6, - 0x65, 0x63, 0x07, 0xC9, 0x65, 0x0F, 0xBC, 0xBC, - 0x1C, 0xC7, 0xD3, 0xAC, 0x7C, 0x2E, 0x2B, 0x4B, - 0xB9, 0x3F, 0xF7, 0x59, 0xC2, 0x7A, 0x0C, 0x86, - 0xF4, 0x23, 0xFB, 0x75, 0xE9, 0x59, 0x9B, 0x48, - 0xC0, 0x7E, 0x13, 0x59, 0x07, 0x72, 0xED, 0x00, - 0x87, 0x50, 0xE9, 0x45, 0xBD, 0x0D, 0xCF, 0x1C, - 0x94, 0xCD, 0x1E, 0xD2, 0x1C, 0x36, 0xA5, 0x80, - 0xD9, 0x24, 0x8F, 0x13, 0xC7, 0x75, 0x53, 0x5B, - 0x24, 0x47, 0xD3, 0x12, 0xC9, 0x5C, 0xE8, 0x0E, - 0x2E, 0x65, 0xA7, 0xAD, 0x6C, 0xFB, 0x97, 0x5C, - 0x0E, 0xF6, 0x9D, 0x33, 0x49, 0x8D, 0x27, 0x24, - 0x64, 0x9F, 0x29, 0x97, 0x2A, 0x3A, 0xF8, 0x2B, - 0xA3, 0x0A, 0xE0, 0xF2, 0x96, 0x7C, 0x76, 0x55, - 0xD9, 0x6F, 0x0B, 0x29, 0xF1, 0xE3, 0x90, 0x58, - 0xBD, 0xB0, 0x20, 0xCA, 0x1B, 0xAB, 0xC7, 0x78, - 0xF4, 0x7B, 0x8F, 0xA0, 0x70, 0xAA, 0x89, 0xBB, - 0x7F, 0xA4, 0xA0, 0xDF, 0x0C, 0x20, 0x0B, 0x79, - 0xAD, 0x8A, 0x30, 0xA6, 0x72, 0x4A, 0xA8, 0x2C, - 0xAC, 0x12, 0x70, 0x3A, 0x70, 0xD4, 0x48, 0x1A, - 0x53, 0x79, 0x5D, 0x65, 0x41, 0xD3, 0xB0, 0x7D, - 0xDD, 0x27, 0x95, 0xE4, 0xCC, 0x51, 0x36, 0x70, - 0x2F, 0x0B, 0x1F, 0x67, 0x43, 0xE5, 0x5F, 0x77, - 0xFB, 0xA8, 0x9C, 0xB4, 0x6C, 0x6A, 0xB0, 0x60, - 0xEC, 0xCD, 0xDE, 0x63, 0x9D, 0x0F, 0x7B, 0x47, - 0xE5, 0xFC, 0xBB, 0xF5, 0x79, 0x35, 0x53, 0x0E, - 0x71, 0x4F, 0x29, 0x63, 0x96, 0x21, 0x07, 0x3B, - 0x44, 0x9F, 0x1F, 0x32, 0xEA, 0x0B, 0x5F, 0x9C, - 0x44, 0x9A, 0x6E, 0xA2, 0x8A, 0x70, 0x55, 0xA7, - 0x23, 0x78, 0xE8, 0xA7, 0x4E, 0xD8, 0xFB, 0x08, - 0xE9, 0x79, 0xCC, 0xD1, 0x45, 0xF6, 0x9A, 0xF2, - 0x54, 0xEC, 0x75, 0x7F, 0x24, 0x8A, 0xE6, 0x55, - 0x47, 0xB9, 0xD1, 0x7D, 0x85, 0x35, 0xC7, 0x61, - 0x41, 0xA8, 0x5A, 0xB6, 0xDC, 0x69, 0x04, 0x66, - 0xE1, 0x3A, 0x3C, 0xE1, 0x3D, 0x3D, 0xF5, 0xA6, - 0x84, 0x18, 0xAE, 0xDF, 0xF7, 0x5A, 0xCA, 0x06, - 0x95, 0x08, 0xBE, 0xD2, 0x06, 0x85, 0xD7, 0x53, - 0x53, 0x95, 0xD3, 0xB3, 0x38, 0x4A, 0x0F, 0x11, - 0x51, 0xAA, 0x1C, 0xB2, 0x0C, 0x1C, 0xBA, 0x89, - 0xF6, 0x2D, 0xAD, 0x80, 0x58, 0xD9, 0xF7, 0x34, - 0x95, 0x01, 0xB4, 0xF1, 0x3A, 0x97, 0x07, 0xC7, - 0x47, 0x9C, 0x1C, 0x31, 0xE9, 0xC8, 0x9C, 0x5F, - 0x47, 0x95, 0xAF, 0x6A, 0x10, 0x89, 0x34, 0x54, - 0x74, 0xBB, 0x2B, 0x7D, 0xA7, 0xF2, 0xD0, 0x31, - 0xAC, 0x87, 0x07, 0x2A, 0xF2, 0xE3, 0xD2, 0x11, - 0xB0, 0x21, 0x94, 0xC9, 0x23, 0x90, 0x61, 0xF1, - 0x72, 0x28, 0xCC, 0xA3, 0xF2, 0x6B, 0x22, 0xE1, - 0xC8, 0x4A, 0xE1, 0x7D, 0xA5, 0x15, 0x43, 0xC2, - 0x42, 0xB8, 0x5D, 0x32, 0x62, 0xF0, 0x57, 0xFF, - 0x62, 0x18, 0xFA, 0x95, 0x28, 0xD1, 0x99, 0xC8, - 0x1D, 0xC5, 0xB2, 0x88, 0x53, 0x52, 0x65, 0xA6, - 0x8E, 0x77, 0x79, 0x1E, 0x06, 0x1C, 0x6C, 0x3C, - 0x26, 0xED, 0xEB, 0x1D, 0x56, 0x7F, 0x3D, 0x58, - 0x11, 0xEF, 0x44, 0xD8, 0x00, 0xB0, 0xE6, 0x67, - 0xE7, 0x9D, 0x7F, 0x10, 0x2D, 0xDF, 0x97, 0xB6, - 0x6E, 0xB6, 0x41, 0x1F, 0xC4, 0x45, 0x76, 0xB5, - 0x39, 0xEE, 0x80, 0xCF, 0xE6, 0x01, 0x62, 0x15, - 0xF8, 0x01, 0x0A, 0x69, 0x79, 0xCD, 0x64, 0xAB, - 0x86, 0x5F, 0x68, 0x5D, 0x86, 0xD6, 0x2B, 0xCB, - 0xD2, 0x2A, 0x15, 0x7D, 0xC0, 0x38, 0x58, 0x29, - 0xF3, 0x2B, 0x35, 0x7A, 0xAE, 0x1C, 0xCC, 0xA6, - 0x06, 0x74, 0xE1, 0x90, 0xB8, 0x04, 0x6F, 0x69, - 0x1F, 0x3B, 0xBB, 0x96, 0x4E, 0xE2, 0x4A, 0x0D, - 0x1F, 0xC0, 0x57, 0x60, 0xBB, 0x16, 0x86, 0xEB, - 0x69, 0x97, 0xE3, 0xAA, 0x5F, 0xE5, 0x98, 0xA8, - 0x28, 0xF3, 0x73, 0x5E, 0x86, 0x47, 0x60, 0xA3, - 0xFF, 0x70, 0x4E, 0x25, 0x71, 0x89, 0x4C, 0x92, - 0x12, 0x8F, 0x38, 0x54, 0x2D, 0xD5, 0xB6, 0x53, - 0xEF, 0x1C, 0x02, 0x69, 0xBD, 0x04, 0xF6, 0x7C, - 0x64, 0x0D, 0x1B, 0x04, 0x96, 0x45, 0xE7, 0x87, - 0x73, 0xCF, 0x45, 0x3A, 0x5F, 0xED, 0x25, 0xE2, - 0xAF, 0x77, 0x8B, 0x4D, 0x37, 0x4D, 0x09, 0x6C, - 0xA9, 0x5A, 0x5E, 0x92, 0x39, 0x4F, 0x2A, 0xEA, - 0x2D, 0xCD, 0x6F, 0xBE, 0x64, 0x7C, 0x1B, 0x19, - 0x39, 0x96, 0x60, 0xC0, 0xD8, 0x22, 0xE8, 0x8A, - 0xC0, 0x3F, 0x6C, 0x43, 0xB3, 0xB1, 0x71, 0xC2, - 0xFE, 0x70, 0xA1, 0xF6, 0x26, 0x34, 0xF0, 0x35, - 0x50, 0x5A, 0xC8, 0xE2, 0x3D, 0x8D, 0x5F, 0x3F, - 0xCB, 0x77, 0x7A, 0x1E, 0x64, 0x70, 0x16, 0x33, - 0x63, 0x9C, 0xAC, 0xC3, 0x1B, 0xA7, 0xCD, 0xD5, - 0x52, 0x85, 0x2F, 0x81, 0x14, 0x3C, 0xB9, 0xB6, - 0x12, 0xEC, 0x5E, 0x32, 0x02, 0xB5, 0x37, 0xF9, - 0xE1, 0xF6, 0x0E, 0xC3, 0x53, 0xE0, 0x25, 0xDD, - 0x75, 0xB3, 0xF5, 0x99, 0x41, 0xF1, 0xA7, 0x26, - 0xA6, 0x4C, 0xBD, 0xD2, 0x32, 0x81, 0xC0, 0x5C, - 0xDF, 0x2D, 0xE8, 0x0F, 0x54, 0x76, 0xD5, 0x01, - 0x18, 0xA0, 0x8F, 0xB0, 0xE1, 0x62, 0x8B, 0x68, - 0xCA, 0xD3, 0x99, 0xDC, 0x47, 0xEA, 0x7A, 0xBA, - 0x3A, 0xE1, 0x61, 0x4C, 0x94, 0xC1, 0xB2, 0x72, - 0xEF, 0xC4, 0x44, 0x69, 0xB1, 0x0D, 0x27, 0x42, - 0xE2, 0x1B, 0x8C, 0xA7, 0x7C, 0x41, 0x2B, 0x73, - 0xF1, 0x26, 0x8A, 0x64, 0xD5, 0x42, 0x87, 0x58, - 0xFA, 0x5D, 0x37, 0x27, 0x11, 0xAD, 0xE5, 0x9D, - 0x1F, 0xC8, 0x69, 0xA7, 0x14, 0x8C, 0x5D, 0xD6, - 0x55, 0x4E, 0xD8, 0xB4, 0xFE, 0x65, 0xAD, 0xAD, - 0x0D, 0xD6, 0x10, 0xE5, 0x1D, 0x3F, 0x34, 0x5C, - 0x1C, 0xE7, 0x51, 0xCF, 0x3C, 0x24, 0x84, 0x64, - 0xE4, 0xBF, 0xF6, 0xBA, 0x90, 0x4B, 0x83, 0x83, - 0x23, 0xF8, 0x9C, 0xDB, 0xA9, 0xD9, 0x99, 0x59, - 0x39, 0x3F, 0x99, 0x27, 0x94, 0x8E, 0x2E, 0xCE, - 0x4E, 0x37, 0xAA, 0x6C, 0x74, 0xE4, 0x84, 0x84, - 0xAE, 0x65, 0x71, 0x76, 0x04, 0x15, 0x28, 0xEB, - 0xCE, 0x00, 0x94, 0xF4, 0x2F, 0x27, 0x45, 0x89, - 0x0F, 0xD8, 0x2B, 0xA7, 0x3C, 0x9D, 0xF1, 0x38, - 0x88, 0xB0, 0xF6, 0x7A, 0x4C, 0xED, 0x3D, 0x0E, - 0x2E, 0x97, 0x4E, 0x08, 0xDC, 0x73, 0xDB, 0x19, - 0x09, 0x7B, 0x3D, 0x4A, 0x0B, 0x2B, 0xDB, 0x6F, - 0x05, 0x12, 0x6E, 0xC8, 0xC2, 0x7E, 0x37, 0x75, - 0xF9, 0x08, 0x0C, 0x6C, 0x91, 0xA1, 0x49, 0x98, - 0xA8, 0xC0, 0x37, 0xE9, 0x7D, 0xE8, 0x58, 0x10, - 0xB0, 0xB3, 0x07, 0xD6, 0x06, 0x36, 0xE9, 0xAA, - 0xC0, 0xC6, 0xC0, 0x54, 0xCD, 0x8F, 0xA3, 0x49, - 0x13, 0x62, 0x56, 0x30, 0xC0, 0xC2, 0xEE, 0x07, - 0x07, 0x58, 0xAF, 0x41, 0xD3, 0x4B, 0x4D, 0xC4, - 0xFE, 0xAD, 0x19, 0xD8, 0x03, 0x39, 0xCA, 0x80, - 0xB4, 0xDD, 0x40, 0x06, 0x54, 0x6A, 0xBA, 0xC1, - 0xB1, 0xD0, 0xEE, 0x00, 0xD0, 0x47, 0xA5, 0x2C, - 0x44, 0x17, 0xA3, 0xC3, 0x10, 0x20, 0x93, 0xC3, - 0xC9, 0xE6, 0xA2, 0xE1, 0x13, 0x29, 0xA7, 0x97, - 0xE8, 0xC3, 0x8F, 0x0D, 0x17, 0xA9, 0xE3, 0xC1, - 0x4F, 0xBD, 0x8B, 0x2B, 0xE2, 0xB2, 0x1E, 0xFE, - 0xBC, 0x3A, 0xE0, 0xE9, 0x20, 0x90, 0xFC, 0x35, - 0xBE, 0x30, 0x3E, 0x50, 0x93, 0x10, 0x40, 0xB0, - 0x44, 0xAF, 0xFA, 0x66, 0x04, 0x70, 0x62, 0xCE, - 0x60, 0x5B, 0xAE, 0xD3, 0x5D, 0x58, 0xCD, 0xAF, - 0xE4, 0x2B, 0x1C, 0x2E, 0xF5, 0xD7, 0x9C, 0x79, - 0x6B, 0xDB, 0x44, 0xE8, 0x10, 0xA0, 0x48, 0x80, - 0x89, 0xD9, 0xCA, 0xF1, 0x09, 0xA4, 0x34, 0xF4, - 0x74, 0xAF, 0x2F, 0x02, 0xDA, 0x4B, 0x6C, 0xAF, - 0x87, 0x5E, 0x4A, 0xEC, 0x20, 0xB5, 0x8D, 0x6D, - 0x45, 0x9C, 0xA1, 0x67, 0x9A, 0xB9, 0xFE, 0x32, - 0xF8, 0xC1, 0xD8, 0x34, 0x3D, 0xC6, 0xA5, 0xA5, - 0x05, 0xDE, 0xAA, 0xEB, 0x87, 0xF7, 0xB7, 0x77, - 0x4F, 0x96, 0xC0, 0x60, 0xA8, 0xDA, 0xD7, 0xA3, - 0x91, 0x61, 0xF0, 0xF9, 0x29, 0xBB, 0x63, 0xA1, - 0x2D, 0xEC, 0xE8, 0xAF, 0x5F, 0x0A, 0x6D, 0x8F, - 0x12, 0x39, 0xB9, 0x94, 0x4C, 0xAD, 0x86, 0x45, - 0x05, 0xFE, 0x48, 0x66, 0x9B, 0x9F, 0x3F, 0xDF, - 0x5F, 0xB4, 0x46, 0x3A, 0xA2, 0x50, 0x10, 0x92, - 0x77, 0x18, 0xB3, 0x2F, 0xF7, 0x47, 0x11, 0x90, - 0x10, 0xC7, 0x72, 0x6C, 0x14, 0xD4, 0xE5, 0x62, - 0xE1, 0x36, 0x96, 0x42, 0x9F, 0x1F, 0xBC, 0x8C, - 0xBC, 0xC4, 0xD2, 0x6C, 0x9E, 0x04, 0xD4, 0xD8, - 0xF8, 0xF3, 0x98, 0x04, 0x06, 0x7A, 0x98, 0x54, - 0xF0, 0xCB, 0x3E, 0x43, 0xFD, 0x55, 0x09, 0x2B, - 0x81, 0x74, 0x10, 0x56, 0xBC, 0x47, 0x94, 0xB3, - 0x3E, 0xF2, 0xE6, 0x86, 0x76, 0xC6, 0xBD, 0x3D, - 0xBD, 0xD0, 0xC7, 0xDB, 0xB8, 0x18, 0xD8, 0xB8, - 0x0C, 0x67, 0x7B, 0x37, 0x4F, 0x5F, 0x4B, 0xCD, - 0x4D, 0x96, 0x2C, 0x4A, 0x20, 0x3F, 0xDF, 0x3A, - 0x43, 0x67, 0x69, 0x00, 0x62, 0x06, 0x94, 0x79, - 0xD7, 0x00, 0xAA, 0x36, 0x01, 0xA0, 0x30, 0x3E, - 0x2D, 0x34, 0xEF, 0xAD, 0x6E, 0xED, 0xBD, 0x4D, - 0xB9, 0x04, 0xF1, 0x3D, 0x6E, 0x75, 0xB0, 0xF5, - 0x52, 0x24, 0x90, 0x7D, 0xFB, 0x48, 0xE8, 0x08, - 0x88, 0xDB, 0x65, 0x80, 0x6A, 0x7F, 0x56, 0xB6, - 0x2B, 0x00, 0x80, 0xAD, 0x75, 0x44, 0x63, 0xA0, - 0x00, 0xB9, 0xFF, 0x1B, 0xCB, 0x70, 0x53, 0x13, - 0xA1, 0xEA, 0xDC, 0xE2, 0x9A, 0x58, 0x1D, 0xF7, - 0xF7, 0x4A, 0x5C, 0x40, 0xEF, 0xAF, 0xB5, 0x53, - 0x85, 0xBA, 0x08, 0x46, 0x9C, 0x0A, 0x28, 0x7B, - 0x8B, 0xD0, 0x44, 0x29, 0xD1, 0x49, 0x18, 0x92, - 0x30, 0xEB, 0x7F, 0x02, 0xFA, 0x6A, 0x3B, 0xD9, - 0x0A, 0xA1, 0x55, 0x1C, 0xEE, 0x1E, 0x3A, 0x0A, - 0xC0, 0x5D, 0xA9, 0xC1, 0x3F, 0x2E, 0x11, 0xD2, - 0xD2, 0x4D, 0xFA, 0xD6, 0x46, 0xC7, 0x01, 0xD5, - 0x59, 0x24, 0x50, 0x2F, 0xEB, 0xA9, 0xD5, 0xED, - 0xEF, 0x67, 0xA1, 0x8B, 0x51, 0xE1, 0x67, 0xB5, - 0x33, 0xE4, 0x50, 0x30, 0xE1, 0xC3, 0xF0, 0x40, - 0x60, 0x19, 0x0F, 0xCB, 0x19, 0x0B, 0x0E, 0xFC, - 0x61, 0x4A, 0xDE, 0xB0, 0x4D, 0x7B, 0xF4, 0xCB, - 0x4B, 0x90, 0x10, 0x3D, 0xE5, 0x59, 0x3B, 0xF7, - 0x72, 0xE8, 0x19, 0x76, 0xA2, 0x51, 0xF9, 0x3D, - 0x7D, 0x74, 0x52, 0xAC, 0x69, 0xB5, 0xC3, 0x5A, - 0xDD, 0x0D, 0x32, 0xDE, 0x86, 0xC2, 0x20, 0xBD, - 0x51, 0xDC, 0xE2, 0x88, 0x90, 0xD2, 0x12, 0x30, - 0x9F, 0x6E, 0x64, 0x16, 0xE8, 0x46, 0x09, 0xEF, - 0x41, 0xB6, 0x66, 0x34, 0xBB, 0x59, 0x56, 0xBC, - 0x1C, 0x55, 0x13, 0xBF, 0xFE, 0xEE, 0x2C, 0xE5, - 0x4F, 0x26, 0x99, 0xDC, 0x84, 0x9E, 0xEF, 0x9F, - 0xB5, 0x4E, 0xF4, 0x93, 0xE9, 0x04, 0x08, 0xE2, - 0xCE, 0x87, 0x38, 0x73, 0x39, 0xC3, 0x4B, 0x26, - 0xA4, 0x5A, 0x1F, 0x8C, 0x12, 0xA9, 0xC9, 0x12, - 0x2C, 0xD7, 0xC3, 0x5F, 0x47, 0x5D, 0x9D, 0xEF, - 0x00, 0xF1, 0xF7, 0x20, 0x08, 0x02, 0xC8, 0xBA, - 0x30, 0xC1, 0x95, 0xF3, 0x02, 0x32, 0xE9, 0x38, - 0x58, 0x38, 0xAE, 0x70, 0xF5, 0x29, 0x63, 0x1F, - 0x3D, 0xEC, 0x7D, 0xB3, 0x20, 0x78, 0xB5, 0x77, - 0xFB, 0x2B, 0x78, 0xFB, 0xDC, 0xA4, 0xC0, 0x2A, - 0x76, 0x3F, 0x84, 0x00, 0x74, 0x0D, 0x66, 0x5F, - 0x2D, 0xBB, 0xE5, 0x41, 0x9D, 0x07, 0xBB, 0x99, - 0x14, 0x27, 0x4D, 0xEF, 0x9A, 0x28, 0x44, 0x9F, - 0x3F, 0x66, 0x20, 0x8C, 0xC6, 0xD6, 0x24, 0xCD, - 0x67, 0x7C, 0x42, 0x8E, 0xC6, 0xEF, 0x7F, 0x25, - 0x2D, 0x74, 0xCA, 0x81, 0xDB, 0x26, 0xAE, 0xCB, - 0xA7, 0x83, 0xFD, 0x95, 0x46, 0xC5, 0xBE, 0x5C, - 0xFC, 0x07, 0xC5, 0xFF, 0x34, 0x70, 0x82, 0x6E, - 0xC7, 0x90, 0xAF, 0xC8, 0x99, 0xAB, 0xA7, 0x4E, - 0x02, 0xC1, 0x92, 0x22, 0x05, 0xA8, 0x38, 0xF8, - 0x78, 0xA3, 0x23, 0x0E, 0xD6, 0x27, 0x27, 0xE4, - 0x55, 0xEF, 0x5A, 0xBE, 0x22, 0x1B, 0xF9, 0x00, - 0xC4, 0x02, 0x44, 0x28, 0xF0, 0x40, 0x16, 0x97, - 0x17, 0x6E, 0x1A, 0x66, 0x1B, 0x98, 0xD8, 0x89, - 0x69, 0xB1, 0x8F, 0x61, 0x30, 0xC9, 0xB4, 0x84, - 0x04, 0xDF, 0x5F, 0x72, 0xAA, 0xA7, 0xC5, 0x24, - 0xC6, 0x1E, 0x80, 0xEE, 0x3A, 0x06, 0xED, 0x8F, - 0xAA, 0x73, 0xED, 0x00, 0xBB, 0x08, 0xFA, 0xF8, - 0x68, 0x2A, 0xCE, 0x3B, 0xA1, 0x98, 0x9A, 0xD6, - 0x55, 0xB7, 0x93, 0xE2, 0xCA, 0x7A, 0x2C, 0xAD, - 0x2D, 0xC7, 0x13, 0x7C, 0x9C, 0x2F, 0xFD, 0x2E, - 0xB6, 0x61, 0xCB, 0xA0, 0x93, 0x39, 0xC8, 0x56, - 0xD5, 0xCE, 0xD3, 0x9F, 0xE5, 0x06, 0x7E, 0x7E, - 0xDE, 0x05, 0x2B, 0x4E, 0x14, 0xB7, 0xD1, 0xB3, - 0xF0, 0x3B, 0x17, 0xF3, 0xA2, 0x61, 0x64, 0x88, - 0x28, 0x41, 0xE4, 0x90, 0x5F, 0x04, 0x6A, 0x12, - 0x01, 0x56, 0x7B, 0x9F, 0x4C, 0x51, 0x33, 0x13, - 0x9B, 0x40, 0xDB, 0xBD, 0x78, 0x38, 0x54, 0x96, - 0x0B, 0x20, 0xA0, 0x8D, 0x55, 0xD4, 0xD6, 0x15, - 0xAD, 0x75, 0x71, 0x0F, 0xC3, 0xBB, 0x78, 0x10, - 0xB3, 0xA2, 0xAF, 0x7A, 0x01, 0x16, 0x4D, 0xDC, - 0xFC, 0xBC, 0xCA, 0x24, 0xEF, 0x47, 0xBE, 0xDD, - 0x4A, 0xF9, 0x64, 0xCA, 0xBA, 0xF5, 0x74, 0xD0, - 0x53, 0x70, 0x75, 0xD9, 0x21, 0x91, 0x23, 0xF0, - 0x68, 0x02, 0xFF, 0x90, 0xA8, 0xC5, 0xB5, 0x87, - 0x6C, 0x17, 0x73, 0x4C, 0x8C, 0xFC, 0xBC, 0x7C, - 0x5E, 0xAE, 0x98, 0x34, 0xCC, 0x7C, 0xDC, 0xB6, - 0x26, 0x5F, 0x82, 0x6E, 0xF0, 0x41, 0x21, 0x43, - 0x00, 0xCB, 0x58, 0x13, 0xEB, 0x9B, 0xDB, 0x1B, - 0x0A, 0x8F, 0x3A, 0xD4, 0x1F, 0xA9, 0x51, 0x98, - 0xBA, 0xA2, 0x04, 0xF2, 0xA2, 0x9B, 0x88, 0x2D, - 0x89, 0x72, 0x4C, 0xA3, 0xD6, 0x64, 0xE4, 0x2C, - 0xAC, 0x6A, 0x2C, 0x40, 0x98, 0x28, 0x7E, 0xFF, - 0x7F, 0xE6, 0xF8, 0x6B, 0x22, 0xF7, 0x94, 0xE5, - 0x07, 0xDF, 0x58, 0x7F, 0xA4, 0xAC, 0xC7, 0xC5, - 0x5E, 0x9D, 0x27, 0x66, 0x6E, 0x12, 0x52, 0x50, - 0x8B, 0x48, 0x3E, 0x72, 0xAA, 0xB8, 0xFB, 0x9B, - 0xB2, 0xD2, 0xA4, 0xE8, 0x30, 0x02, 0x41, 0x21, - 0x61, 0x9A, 0x2C, 0xD0, 0x80, 0x20, 0xD2, 0xB3, - 0x33, 0x78, 0x46, 0x0A, 0x50, 0x83, 0x43, 0x43, - 0xE3, 0x38, 0xAC, 0xE3, 0xBB, 0xCB, 0x8B, 0x4B, - 0x8B, 0x72, 0xD4, 0xFA, 0x86, 0x36, 0x16, 0xF4, - 0x54, 0xAD, 0x78, 0x94, 0x51, 0x11, 0x47, 0xC6, - 0x46, 0xFB, 0x79, 0x1D, 0x47, 0xF4, 0xB3, 0xB1, - 0x32, 0xCF, 0x1F, 0x4B, 0x99, 0x84, 0xE6, 0x9B, - 0x18, 0x0E, 0xBC, 0xF5, 0xB5, 0x27, 0x5A, 0x6A, - 0x42, 0xCA, 0xCE, 0x02, 0x21, 0x21, 0x8D, 0x5D, - 0x1F, 0x87, 0x17, 0xBB, 0x43, 0xF3, 0x01, 0xCB, - 0x47, 0x5C, 0xCA, 0xA6, 0xCE, 0xE7, 0x97, 0xC5, - 0x0F, 0xD8, 0x73, 0xEF, 0x37, 0x87, 0xFD, 0x3C, - 0xBC, 0x67, 0xD1, 0xBD, 0x65, 0xD5, 0x51, 0x9C, - 0x1E, 0xA5, 0x17, 0x7A, 0xA2, 0x12, 0x72, 0xB2, - 0x32, 0xE9, 0xEF, 0x8D, 0x57, 0x87, 0xCD, 0x0F, - 0x8F, 0x54, 0xE2, 0x8E, 0x56, 0xE6, 0x66, 0xB4, - 0x36, 0x8D, 0x27, 0x4B, 0x9B, 0x2B, 0x36, 0xF2, - 0x0C, 0xD3, 0xE1, 0x9F, 0x45, 0x95, 0x81, 0x52, - 0xD0, 0x6B, 0x45, 0x3A, 0xE0, 0x30, 0xF0, 0x23, - 0xA1, 0x1A, 0x74, 0x0C, 0xD6, 0x06, 0x7E, 0xAB, - 0x29, 0x92, 0x14, 0x6E, 0xB4, 0x64, 0x30, 0xE5, - 0x67, 0xDC, 0xD2, 0xAB, 0x71, 0xA1, 0xC1, 0x01, - 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x87, 0x47, - 0xC7, 0x1C, 0x5A, 0xC9, 0xEE, 0xA1, 0xC1, 0x01, - 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x87, 0x47, - 0xC7, 0x1C, 0x5A, 0xC9, 0xEE, 0xA1, 0xC1, 0x01, - 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x87, 0x47, - 0xC7, 0x1C, 0x5A, 0xC9, 0xEE, 0xA1, 0xC1, 0x01, - 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x87, 0x47, - 0xC7, 0x1C, 0x5A, 0xC9, 0xEE, 0xA1, 0xC1, 0x01, - 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x97, 0x40, - 0xC2, 0x79, 0xEB, 0x90, 0x4A, 0x9A, 0xEE, 0x36, - 0xB4, 0x0F, 0x19, 0x62, 0xB8, 0x68, 0x08, 0xC8, - 0x48, 0x93, 0x25, 0x49, 0x91, 0x21, 0x41, 0x81, - 0x01, 0xDA, 0xA0, 0xD4, 0x0C, 0xDC, 0x6C, 0xB4, - 0x34, 0x8F, 0xC1, 0xB4, 0x6C, 0xBC, 0x30, 0xF0, - 0x70, 0xAB, 0x1D, 0x71, 0xA9, 0x19, 0x78, 0xB8, - 0x38, 0xE3, 0x54, 0x38, 0xE1, 0x51, 0x30, 0xF8, - 0x38, 0xE3, 0x54, 0x39, 0xE0, 0x51, 0x70, 0xA0, - 0x24, 0xFD, 0x6A, 0x02, 0xFB, 0x4F, 0x0E, 0x4A, - 0xDA, 0x43, 0xE4, 0x99, 0x50, 0xF1, 0xD8, 0x3A, - 0x9E, 0x67, 0x98, 0xE6, 0x77, 0xD5, 0xFC, 0x6E, - 0xD7, 0x1E, 0xFD, 0x80, 0x0D, 0xAC, 0x99, 0x4C, - 0x99, 0x53, 0x4F, 0x09, 0x7B, 0xE1, 0x2B, 0x41, - 0x6B, 0x9A, 0x79, 0x40, 0xCD, 0x28, 0x1D, 0x88, - 0x5D, 0x53, 0xB0, 0x09, 0x84, 0xE1, 0x2B, 0x01, - 0x2B, 0x1E, 0x02, 0x80, 0xF2, 0xAC, 0x7A, 0x17, - 0x21, 0x17, 0x17, 0x96, 0xF8, 0xA5, 0x73, 0x6E, - 0x35, 0x33, 0x6B, 0xE9, 0xDF, 0x81, 0x3F, 0x84, - 0xEB, 0x8D, 0xE5, 0x72, 0x74, 0x3F, 0xE1, 0xCE, - 0xB5, 0x93, 0xDB, 0x49, 0x6F, 0x21, 0xBF, 0x88, - 0xB7, 0x93, 0xDB, 0x48, 0x6E, 0x21, 0xBE, 0x81, - 0xFE, 0xDA, 0x58, 0x2D, 0xF5, 0x25, 0x7D, 0xA4, - 0x24, 0x9F, 0xD5, 0xA0, 0x78, 0xA8, 0xFC, 0x3C, - 0xBC, 0x67, 0xD1, 0xBD, 0x65, 0xD5, 0xB5, 0x75, - 0xF5, 0x2E, 0x98, 0xF4, 0x2C, 0x9C, 0xFC, 0x3C, - 0xBC, 0x67, 0xF9, 0x9C, 0x44, 0x94, 0xD0, 0x19, - 0x99, 0x22, 0x84, 0x58, 0x82, 0x32, 0x52, 0x88, - 0x08, 0xB3, 0x75, 0x18, 0xC0, 0x70, 0x6C, 0xAB, - 0x2B, 0x90, 0x9A, 0xFB, 0x21, 0xF1, 0xAD, 0x65, - 0xE5, 0x5E, 0xFC, 0x9E, 0x44, 0x94, 0x38, 0xF6, - 0x74, 0xCF, 0xED, 0x87, 0x5F, 0x8F, 0x4B, 0x84, - 0x06, 0xBD, 0x4F, 0x25, 0xFD, 0x2D, 0xC1, 0x0E, - 0x8C, 0x37, 0x71, 0x04, 0xDC, 0x0C, 0xB8, 0x77, - 0xF5, 0x4E, 0x48, 0x35, 0xEF, 0x3F, 0xE7, 0x2F, - 0xAF, 0x14, 0x82, 0xFC, 0x26, 0xF6, 0x2A, 0xED, - 0x6D, 0xD6, 0x34, 0x4A, 0x90, 0x40, 0xE8, 0x3A, - 0xB8, 0x03, 0x5D, 0x37, 0xEF, 0x3F, 0x3B, 0xE3, - 0x61, 0xDA, 0x2C, 0x4A, 0x92, 0x42, 0x14, 0x95, - 0x15, 0x4F, 0x7B, 0x11, 0x78, 0x48, 0x2E, 0xF2, - 0x78, 0x32, 0x05, 0x6F, 0x15, 0xEE, 0x8E, 0xC7, - 0x4E, 0xB0, 0x04, 0x68, 0x55, 0xE1, 0x81, 0xE4, - 0x66, 0xBD, 0xEE, 0x87, 0x5F, 0x0A, 0x62, 0xA2, - 0x07, 0xDF, 0x69, 0xA0, 0x71, 0xC1, 0x00, 0x43, - 0xC5, 0xAF, 0x9D, 0xF7, 0x8A, 0x60, 0x27, 0xFA, - 0x8A, 0x51, 0xD1, 0xFC, 0x24, 0xA5, 0x40, 0x86, - 0x27, 0x7A, 0xCA, 0x8F, 0x84, 0x29, 0xB9, 0x79, - 0xF9, 0x22, 0xA2, 0x8F, 0x57, 0xD6, 0x31, 0xF7, - 0x56, 0x05, 0xB5, 0xF0, 0x6B, 0xC6, 0x56, 0x96, - 0x16, 0xCD, 0x4D, 0x60, 0xB8, 0x39, 0xDC, 0x1A, - 0xBB, 0xE9, 0x59, 0x1C, 0x57, 0xFA, 0x6A, 0xAA, - 0x2A, 0xF1, 0x71, 0x5C, 0x84, 0x15, 0xF8, 0x3E, - 0x8F, 0xD8, 0x68, 0x95, 0xC7, 0x71, 0x90, 0xDB, - 0x5D, 0x0F, 0xF0, 0xB5, 0x6E, 0xC3, 0x53, 0x93, - 0x13, 0xC8, 0x48, 0x65, 0xBD, 0x9C, 0x72, 0xB4, - 0x38, 0xEB, 0xDF, 0xFA, 0x22, 0xF7, 0x96, 0x56, - 0x77, 0x3C, 0x8C, 0x51, 0x0E, 0xB8, 0x19, 0x56, - 0xD0, 0xC2, 0x7F, 0xBA, 0x39, 0x94, 0x04, 0xC4, - 0x44, 0x9F, 0x1F, 0x32, 0xEA, 0x6B, 0x9A, 0x5C, - 0xFD, 0xB4, 0x04, 0x41, 0x8A, 0x27, 0xB7, 0x77, - 0xF7, 0x2C, 0xAC, 0x81, 0x59, 0x68, 0x9C, 0x5A, - 0xEB, 0xA3, 0x13, 0x5E, 0x13, 0xA5, 0xEC, 0x0F, - 0x06, 0x8E, 0x25, 0xB9, 0x61, 0xD1, 0x87, 0x06, - 0x86, 0xCC, 0xEC, 0x86, 0xDF, 0xF8, 0x9E, 0xD7, - 0x7E, 0xC0, 0x76, 0x1A, 0xDF, 0x9F, 0xC9, 0x48, - 0xC8, 0xB2, 0x9C, 0xF6, 0x9C, 0x8C, 0x60, 0x08, - 0x82, 0x79, 0xAE, 0xC2, 0x92, 0x08, 0xD2, 0xA8, - 0xB4, 0x77, 0xCD, 0xBD, 0x69, 0x54, 0xD6, 0x3C, - 0x94, 0x8F, 0x19, 0x75, 0x7F, 0x81, 0xED, 0xEF, - 0x24, 0xD8, 0x4B, 0x80, 0x7B, 0xEB, 0x6D, 0xBE, - 0x2E, 0xD5, 0x63, 0x12, 0x3A, 0x8A, 0xEA, 0x2A, - 0xAA, 0x71, 0xC7, 0xAB, 0x73, 0xC3, 0xA3, 0x63, - 0xE3, 0x38, 0x8F, 0xE3, 0x3F, 0x8F, 0x8B, 0x51, - 0xD3, 0x68, + 0x06, 0x6B, 0x06, 0x6A, 0x76, 0xC8, 0x18, 0xD4, + 0x54, 0xEF, 0x71, 0x14, 0xCC, 0x1C, 0x58, 0x91, + 0x11, 0xAA, 0x80, 0xF4, 0x2C, 0xFC, 0x9F, 0x5F, + 0xDF, 0x04, 0x02, 0x62, 0xBA, 0x6A, 0x5A, 0x97, + 0x17, 0xCC, 0x46, 0x22, 0xFA, 0x2A, 0xBE, 0x03, + 0x87, 0x3C, 0x9E, 0xFE, 0x26, 0xF6, 0x96, 0x7E, + 0xFA, 0x11, 0x27, 0x66, 0xBA, 0x3A, 0x5A, 0xBA, + 0x3E, 0xD5, 0x4F, 0x03, 0xDF, 0x5F, 0x7F, 0x9F, + 0x1B, 0xF0, 0xA2, 0xEF, 0x33, 0xB3, 0xD3, 0x13, + 0x93, 0x70, 0xFA, 0x96, 0x4E, 0xC6, 0xA6, 0xC6, + 0x46, 0xA5, 0x2F, 0xE3, 0x3B, 0xB3, 0xD3, 0x33, + 0xB3, 0x50, 0xE8, 0xA4, 0x7C, 0xF4, 0x94, 0x14, + 0x94, 0x77, 0xC9, 0xE5, 0x3D, 0xB5, 0xD5, 0x75, + 0xF5, 0x16, 0xA8, 0xA4, 0x7C, 0xF4, 0x94, 0xD4, + 0x54, 0xB7, 0x09, 0xE5, 0x3D, 0xB5, 0x2D, 0xF4, + 0x74, 0xCF, 0x29, 0x5C, 0x84, 0x54, 0x14, 0xAA, + 0x2E, 0x95, 0xF7, 0xE0, 0x3C, 0xEC, 0x8C, 0x52, + 0xD6, 0x3D, 0x7B, 0x0E, 0xD6, 0x06, 0x82, 0x49, + 0xC9, 0x72, 0x7C, 0x18, 0xC0, 0x10, 0x10, 0xF6, + 0x72, 0xC9, 0xC3, 0xA8, 0x70, 0xA0, 0xD8, 0x77, + 0xF3, 0x48, 0x06, 0x04, 0xD8, 0x08, 0x90, 0x5B, + 0xDB, 0x60, 0x36, 0x43, 0x9B, 0x4B, 0xD4, 0xE3, + 0x9C, 0xB8, 0xF1, 0x72, 0x55, 0x1A, 0x8E, 0x57, + 0xD7, 0x6C, 0xDA, 0xBE, 0x66, 0xD6, 0xEA, 0x3D, + 0xBF, 0x04, 0xB2, 0xCE, 0x16, 0xA6, 0x06, 0xDE, + 0x5E, 0xE5, 0xB7, 0xC3, 0x1B, 0xCB, 0x47, 0x9F, + 0x1F, 0xA4, 0x3E, 0x5B, 0x83, 0x53, 0x53, 0x8A, + 0x0A, 0xB1, 0x93, 0xF9, 0x21, 0xF1, 0x31, 0xE6, + 0x64, 0xDF, 0x95, 0xE0, 0x38, 0xE8, 0xB4, 0x6D, + 0xED, 0x56, 0x1D, 0x8E, 0x56, 0xE6, 0x79, 0xB9, + 0xC6, 0xE2, 0x62, 0x4F, 0x97, 0x02, 0x40, 0x80, + 0x65, 0xB8, 0x0E, 0x07, 0xC2, 0x72, 0x37, 0xBE, + 0x3E, 0x00, 0xF2, 0xB8, 0xF1, 0x6D, 0x0E, 0x6F, + 0xC2, 0x1A, 0xA0, 0xC4, 0x95, 0x2F, 0xCD, 0x44, + 0xC4, 0x02, 0x44, 0x28, 0xF0, 0x40, 0x16, 0x97, + 0x17, 0x7D, 0xE4, 0x8B, 0xFE, 0x4C, 0x0D, 0xE3, + 0x60, 0xFD, 0x4B, 0x27, 0x34, 0xA6, 0xCD, 0xB6, + 0x10, 0xC0, 0x7C, 0x98, 0x42, 0x72, 0x92, 0x26, + 0x21, 0x60, 0x26, 0x4C, 0x95, 0x25, 0xA0, 0x03, + 0xA6, 0x50, 0xEC, 0x9D, 0xB5, 0x05, 0x53, 0xD2, + 0x52, 0xA9, 0x7E, 0x12, 0x2F, 0x65, 0xFA, 0x1A, + 0x7C, 0xB4, 0x12, 0x5E, 0x86, 0x3A, 0x50, 0xF5, + 0x53, 0xAD, 0xBA, 0xE6, 0x3D, 0x3C, 0x6D, 0xAE, + 0xCB, 0x33, 0xAD, 0xDC, 0xF4, 0x44, 0x12, 0x93, + 0x13, 0xF9, 0x7D, 0x12, 0xEB, 0x68, 0x0B, 0xE2, + 0x21, 0xE7, 0xA1, 0xCD, 0x15, 0xA5, 0xF3, 0x72, + 0xF2, 0xAB, 0x1F, 0x7E, 0xAA, 0x01, 0xE1, 0xA1, + 0x25, 0xA8, 0x06, 0x6D, 0xB9, 0x0C, 0x60, 0xA6, + 0x64, 0xAD, 0x15, 0x65, 0xBA, 0x30, 0x14, 0x66, + 0x22, 0x78, 0xFC, 0x94, 0x4C, 0x4E, 0x25, 0x9B, + 0xD9, 0x06, 0xB1, 0xEA, 0x89, 0x35, 0x62, 0x1E, + 0x8F, 0x69, 0xD4, 0x7F, 0x1C, 0xA0, 0xFD, 0x31, + 0x77, 0xAD, 0x1B, 0x40, 0xA4, 0x10, 0xB7, 0xCC, + 0x4D, 0xAB, 0x16, 0xD7, 0x0C, 0x01, 0x62, 0x87, + 0xBF, 0x4C, 0x50, 0x5A, 0xD8, 0x3B, 0x50, 0xE7, + 0x2C, 0xB3, 0xB7, 0x1F, 0x46, 0xA0, 0x57, 0x6B, + 0x46, 0x98, 0x93, 0xFA, 0xC7, 0xC1, 0x89, 0x45, + 0xDE, 0xD7, 0xC3, 0xC3, 0xBB, 0xCF, 0xEE, 0xEE, + 0xA8, 0xB3, 0xDF, 0x61, 0x4B, 0xE6, 0x04, 0x04, + 0x40, 0xDA, 0xAC, 0x43, 0xDA, 0x9A, 0x15, 0x25, + 0x45, 0x7D, 0xEA, 0x0C, 0x3A, 0x7A, 0xD4, 0x87, + 0xC5, 0x43, 0x77, 0x1D, 0xC6, 0x76, 0xD4, 0xB6, + 0x5A, 0x4B, 0x3F, 0x91, 0x55, 0x98, 0xC2, 0xCE, + 0x8C, 0x5B, 0xED, 0x53, 0x99, 0x20, 0x6D, 0xA6, + 0xF1, 0x96, 0x21, 0x41, 0xBB, 0x16, 0x86, 0x46, + 0xC6, 0x1D, 0x9D, 0xB0, 0x68, 0x69, 0x3D, 0xFE, + 0xC6, 0x16, 0x2C, 0x2B, 0x51, 0x40, 0x40, 0x2A, + 0x01, 0xBF, 0xB3, 0xFF, 0x8A, 0x38, 0x3D, 0x51, + 0xF4, 0x32, 0x74, 0x18, 0xC0, 0x70, 0x26, 0xA7, + 0x27, 0x5D, 0xDE, 0xB1, 0xD8, 0x5E, 0x3D, 0x30, + 0xB2, 0x0C, 0xEC, 0xA5, 0xCC, 0x44, 0x27, 0xC7, + 0x6D, 0x16, 0x01, 0x5A, 0x81, 0xFC, 0x9E, 0x3B, + 0xEE, 0x10, 0x17, 0x41, 0x9A, 0x0A, 0x50, 0x30, + 0x72, 0x6A, 0xCC, 0x01, 0xE0, 0x53, 0x3F, 0xFD, + 0x54, 0x8C, 0x13, 0x6C, 0x9D, 0x0E, 0x47, 0xB4, + 0xD1, 0x59, 0xCA, 0x17, 0xF3, 0x40, 0x10, 0xEA, + 0xCA, 0xD3, 0xA6, 0xDA, 0xA3, 0x28, 0x4B, 0x6E, + 0xBC, 0x42, 0xF8, 0x9D, 0x75, 0xFF, 0x3F, 0xCD, + 0x8E, 0x45, 0xE8, 0x1D, 0xEC, 0x5F, 0x74, 0x87, + 0x61, 0x23, 0x63, 0xA2, 0x79, 0x7B, 0xBB, 0xDE, + 0x72, 0xE5, 0xB6, 0x7B, 0x8B, 0x9A, 0xC7, 0x04, + 0x35, 0xD0, 0x65, 0xCB, 0xD0, 0x44, 0x41, 0xD1, + 0x74, 0x1E, 0xE8, 0x87, 0x6F, 0xE5, 0x25, 0x44, + 0xFB, 0x23, 0xA7, 0x08, 0xF4, 0x89, 0xEA, 0xCF, + 0x1E, 0xE0, 0xE7, 0xC9, 0x12, 0x92, 0xC8, 0xA8, + 0x89, 0x13, 0xA6, 0x07, 0xDC, 0xC9, 0xFA, 0x1F, + 0x2E, 0xB1, 0x04, 0x58, 0xBA, 0xAA, 0x6B, 0xE8, + 0x6B, 0x7D, 0xC8, 0x01, 0x8B, 0x1E, 0xCF, 0x49, + 0xCA, 0x21, 0xAD, 0x61, 0x18, 0xED, 0x8E, 0x83, + 0x00, 0x3E, 0xD9, 0x90, 0x78, 0xE2, 0x22, 0xFF, + 0x8F, 0x54, 0xD4, 0xF9, 0x21, 0x10, 0x37, 0xF4, + 0xFC, 0x2F, 0x15, 0x31, 0x48, 0xB0, 0xD3, 0x36, + 0xC1, 0x32, 0x99, 0x05, 0xDD, 0x6D, 0x3B, 0xBA, + 0x3A, 0x60, 0x91, 0xFE, 0xAE, 0x16, 0xFA, 0x72, + 0x53, 0xC0, 0x75, 0xFC, 0x51, 0xC9, 0x0C, 0x38, + 0x99, 0x5F, 0x19, 0x75, 0xAD, 0x1D, 0x4B, 0xCA, + 0x4A, 0x3C, 0x88, 0x01, 0x40, 0xD2, 0x33, 0xB4, + 0x37, 0x64, 0xDA, 0x3A, 0xAA, 0xBB, 0x93, 0x50, + 0xF5, 0x5A, 0xC4, 0xB5, 0x9D, 0x2D, 0x7B, 0xFA, + 0x7A, 0x84, 0x17, 0x7B, 0x22, 0xD8, 0xBB, 0xEA, + 0x58, 0x80, 0x97, 0xB2, 0x69, 0x70, 0x49, 0x00, + 0x89, 0x4F, 0x09, 0x65, 0xBD, 0x0D, 0x5B, 0xDA, + 0x5A, 0xB0, 0x32, 0x5D, 0x89, 0x1E, 0x46, 0x85, + 0x54, 0xC4, 0x71, 0x8F, 0x54, 0xEC, 0xEE, 0x8F, + 0x7F, 0xAF, 0x90, 0xEA, 0x7A, 0xCC, 0x7D, 0xF1, + 0x72, 0xA5, 0x79, 0x19, 0xC6, 0xF4, 0x5D, 0x61, + 0xF7, 0x24, 0x98, 0xD2, 0x53, 0xEB, 0x26, 0xE4, + 0x01, 0x67, 0xF7, 0xB6, 0x64, 0xC9, 0x59, 0xF3, + 0x30, 0x59, 0xFC, 0x9B, 0xD1, 0x65, 0x05, 0xD3, + 0x68, 0xB8, 0x68, 0x7D, 0xB5, 0xC7, 0xB3, 0x8F, + 0x59, 0x2E, 0x92, 0x5C, 0xC7, 0x7F, 0x3D, 0xFE, + 0x73, 0x88, 0x1F, 0x77, 0xB2, 0xF2, 0x9E, 0x55, + 0x57, 0x8F, 0x34, 0x9A, 0x61, 0x0C, 0x7B, 0xD3, + 0x5C, 0x15, 0xAE, 0xC2, 0x16, 0xB4, 0xC2, 0x2B, + 0xA5, 0x75, 0x6A, 0xA4, 0x31, 0x81, 0xA7, 0x67, + 0xE7, 0x30, 0x84, 0x28, 0xD0, 0x60, 0xA2, 0x71, + 0xF9, 0xE0, 0x33, 0xFF, 0xAB, 0x01, 0x04, 0x22, + 0x84, 0x42, 0x04, 0x02, 0x99, 0xFB, 0x9F, 0x5F, + 0xB9, 0x7F, 0xF5, 0x21, 0xDB, 0xC6, 0xA5, 0x00, + 0x60, 0x9D, 0x8B, 0x07, 0xAB, 0x7D, 0x03, 0xE2, + 0xD3, 0x45, 0xF0, 0x6E, 0xBD, 0x0D, 0x4B, 0xA4, + 0x23, 0x8A, 0x77, 0x1B, 0xCF, 0x75, 0x30, 0x96, + 0x33, 0xE4, 0x6A, 0x94, 0x6F, 0x01, 0xA1, 0x41, + 0xC1, 0x88, 0x5B, 0x97, 0xCD, 0x3E, 0x56, 0xD0, + 0x53, 0x88, 0x9C, 0xE3, 0x3C, 0x00, 0x1A, 0xA8, + 0x6C, 0xB7, 0xA3, 0xDC, 0x03, 0x96, 0x14, 0xF2, + 0x7E, 0xB7, 0x1C, 0x80, 0xEA, 0x49, 0x21, 0x8B, + 0x48, 0x85, 0xF8, 0x93, 0x89, 0x3D, 0x5D, 0x5F, + 0x13, 0x33, 0x93, 0xC3, 0x1C, 0x4E, 0x2D, 0xE0, + 0xE2, 0x1D, 0x2A, 0x51, 0xE7, 0x07, 0xF5, 0x38, + 0xB8, 0x75, 0x4A, 0x2A, 0xFE, 0x5C, 0x37, 0x0E, + 0x7C, 0xEA, 0x5C, 0xB6, 0x7E, 0xCE, 0x2C, 0x25, + 0x5C, 0xD1, 0xFF, 0x66, 0x06, 0x94, 0x59, 0x9A, + 0x7F, 0x7D, 0xED, 0x21, 0x69, 0xAD, 0xC6, 0x9F, + 0x49, 0x7B, 0xC7, 0xA7, 0x74, 0xC8, 0xE4, 0xC6, + 0x65, 0x63, 0x07, 0xC9, 0x65, 0x0F, 0xBC, 0xBC, + 0x1C, 0xC7, 0xD3, 0xAC, 0x7C, 0x2E, 0x2B, 0x4B, + 0xB9, 0x3F, 0xF7, 0x59, 0xC2, 0x7A, 0x0C, 0x86, + 0xF4, 0x23, 0xFB, 0x75, 0xE9, 0x59, 0x9B, 0x48, + 0xC0, 0x7E, 0x13, 0x59, 0x07, 0x72, 0xED, 0x00, + 0x87, 0x50, 0xE9, 0x45, 0xBD, 0x0D, 0xCF, 0x1C, + 0x94, 0xCD, 0x1E, 0xD2, 0x1C, 0x36, 0xA5, 0x80, + 0xD9, 0x24, 0x8F, 0x13, 0xC7, 0x75, 0x53, 0x5B, + 0x24, 0x47, 0xD3, 0x12, 0xC9, 0x5C, 0xE8, 0x0E, + 0x2E, 0x65, 0xA7, 0xAD, 0x6C, 0xFB, 0x97, 0x5C, + 0x0E, 0xF6, 0x9D, 0x33, 0x49, 0x8D, 0x27, 0x24, + 0x64, 0x9F, 0x29, 0x97, 0x2A, 0x3A, 0xF8, 0x2B, + 0xA3, 0x0A, 0xE0, 0xF2, 0x96, 0x7C, 0x76, 0x55, + 0xD9, 0x6F, 0x0B, 0x29, 0xF1, 0xE3, 0x90, 0x58, + 0xBD, 0xB0, 0x20, 0xCA, 0x1B, 0xAB, 0xC7, 0x78, + 0xF4, 0x7B, 0x8F, 0xA0, 0x70, 0xAA, 0x89, 0xBB, + 0x7F, 0xA4, 0xA0, 0xDF, 0x0C, 0x20, 0x0B, 0x79, + 0xAD, 0x8A, 0x30, 0xA6, 0x72, 0x4A, 0xA8, 0x2C, + 0xAC, 0x12, 0x70, 0x3A, 0x70, 0xD4, 0x48, 0x1A, + 0x53, 0x79, 0x5D, 0x65, 0x41, 0xD3, 0xB0, 0x7D, + 0xDD, 0x27, 0x95, 0xE4, 0xCC, 0x51, 0x36, 0x70, + 0x2F, 0x0B, 0x1F, 0x67, 0x43, 0xE5, 0x5F, 0x77, + 0xFB, 0xA8, 0x9C, 0xB4, 0x6C, 0x6A, 0xB0, 0x60, + 0xEC, 0xCD, 0xDE, 0x63, 0x9D, 0x0F, 0x7B, 0x47, + 0xE5, 0xFC, 0xBB, 0xF5, 0x79, 0x35, 0x53, 0x0E, + 0x71, 0x4F, 0x29, 0x63, 0x96, 0x21, 0x07, 0x3B, + 0x44, 0x9F, 0x1F, 0x32, 0xEA, 0x0B, 0x5F, 0x9C, + 0x44, 0x9A, 0x6E, 0xA2, 0x8A, 0x70, 0x55, 0xA7, + 0x23, 0x78, 0xE8, 0xA7, 0x4E, 0xD8, 0xFB, 0x08, + 0xE9, 0x79, 0xCC, 0xD1, 0x45, 0xF6, 0x9A, 0xF2, + 0x54, 0xEC, 0x75, 0x7F, 0x24, 0x8A, 0xE6, 0x55, + 0x47, 0xB9, 0xD1, 0x7D, 0x85, 0x35, 0xC7, 0x61, + 0x41, 0xA8, 0x5A, 0xB6, 0xDC, 0x69, 0x04, 0x66, + 0xE1, 0x3A, 0x3C, 0xE1, 0x3D, 0x3D, 0xF5, 0xA6, + 0x84, 0x18, 0xAE, 0xDF, 0xF7, 0x5A, 0xCA, 0x06, + 0x95, 0x08, 0xBE, 0xD2, 0x06, 0x85, 0xD7, 0x53, + 0x53, 0x95, 0xD3, 0xB3, 0x38, 0x4A, 0x0F, 0x11, + 0x51, 0xAA, 0x1C, 0xB2, 0x0C, 0x1C, 0xBA, 0x89, + 0xF6, 0x2D, 0xAD, 0x80, 0x58, 0xD9, 0xF7, 0x34, + 0x95, 0x01, 0xB4, 0xF1, 0x3A, 0x97, 0x07, 0xC7, + 0x47, 0x9C, 0x1C, 0x31, 0xE9, 0xC8, 0x9C, 0x5F, + 0x47, 0x95, 0xAF, 0x6A, 0x10, 0x89, 0x34, 0x54, + 0x74, 0xBB, 0x2B, 0x7D, 0xA7, 0xF2, 0xD0, 0x31, + 0xAC, 0x87, 0x07, 0x2A, 0xF2, 0xE3, 0xD2, 0x11, + 0xB0, 0x21, 0x94, 0xC9, 0x23, 0x90, 0x61, 0xF1, + 0x72, 0x28, 0xCC, 0xA3, 0xF2, 0x6B, 0x22, 0xE1, + 0xC8, 0x4A, 0xE1, 0x7D, 0xA5, 0x15, 0x43, 0xC2, + 0x42, 0xB8, 0x5D, 0x32, 0x62, 0xF0, 0x57, 0xFF, + 0x62, 0x18, 0xFA, 0x95, 0x28, 0xD1, 0x99, 0xC8, + 0x1D, 0xC5, 0xB2, 0x88, 0x53, 0x52, 0x65, 0xA6, + 0x8E, 0x77, 0x79, 0x1E, 0x06, 0x1C, 0x6C, 0x3C, + 0x26, 0xED, 0xEB, 0x1D, 0x56, 0x7F, 0x3D, 0x58, + 0x11, 0xEF, 0x44, 0xD8, 0x00, 0xB0, 0xE6, 0x67, + 0xE7, 0x9D, 0x7F, 0x10, 0x2D, 0xDF, 0x97, 0xB6, + 0x6E, 0xB6, 0x41, 0x1F, 0xC4, 0x45, 0x76, 0xB5, + 0x39, 0xEE, 0x80, 0xCF, 0xE6, 0x01, 0x62, 0x15, + 0xF8, 0x01, 0x0A, 0x69, 0x79, 0xCD, 0x64, 0xAB, + 0x86, 0x5F, 0x68, 0x5D, 0x86, 0xD6, 0x2B, 0xCB, + 0xD2, 0x2A, 0x15, 0x7D, 0xC0, 0x38, 0x58, 0x29, + 0xF3, 0x2B, 0x35, 0x7A, 0xAE, 0x1C, 0xCC, 0xA6, + 0x06, 0x74, 0xE1, 0x90, 0xB8, 0x04, 0x6F, 0x69, + 0x1F, 0x3B, 0xBB, 0x96, 0x4E, 0xE2, 0x4A, 0x0D, + 0x1F, 0xC0, 0x57, 0x60, 0xBB, 0x16, 0x86, 0xEB, + 0x69, 0x97, 0xE3, 0xAA, 0x5F, 0xE5, 0x98, 0xA8, + 0x28, 0xF3, 0x73, 0x5E, 0x86, 0x47, 0x60, 0xA3, + 0xFF, 0x70, 0x4E, 0x25, 0x71, 0x89, 0x4C, 0x92, + 0x12, 0x8F, 0x38, 0x54, 0x2D, 0xD5, 0xB6, 0x53, + 0xEF, 0x1C, 0x02, 0x69, 0xBD, 0x04, 0xF6, 0x7C, + 0x64, 0x0D, 0x1B, 0x04, 0x96, 0x45, 0xE7, 0x87, + 0x73, 0xCF, 0x45, 0x3A, 0x5F, 0xED, 0x25, 0xE2, + 0xAF, 0x77, 0x8B, 0x4D, 0x37, 0x4D, 0x09, 0x6C, + 0xA9, 0x5A, 0x5E, 0x92, 0x39, 0x4F, 0x2A, 0xEA, + 0x2D, 0xCD, 0x6F, 0xBE, 0x64, 0x7C, 0x1B, 0x19, + 0x39, 0x96, 0x60, 0xC0, 0xD8, 0x22, 0xE8, 0x8A, + 0xC0, 0x3F, 0x6C, 0x43, 0xB3, 0xB1, 0x71, 0xC2, + 0xFE, 0x70, 0xA1, 0xF6, 0x26, 0x34, 0xF0, 0x35, + 0x50, 0x5A, 0xC8, 0xE2, 0x3D, 0x8D, 0x5F, 0x3F, + 0xCB, 0x77, 0x7A, 0x1E, 0x64, 0x70, 0x16, 0x33, + 0x63, 0x9C, 0xAC, 0xC3, 0x1B, 0xA7, 0xCD, 0xD5, + 0x52, 0x85, 0x2F, 0x81, 0x14, 0x3C, 0xB9, 0xB6, + 0x12, 0xEC, 0x5E, 0x32, 0x02, 0xB5, 0x37, 0xF9, + 0xE1, 0xF6, 0x0E, 0xC3, 0x53, 0xE0, 0x25, 0xDD, + 0x75, 0xB3, 0xF5, 0x99, 0x41, 0xF1, 0xA7, 0x26, + 0xA6, 0x4C, 0xBD, 0xD2, 0x32, 0x81, 0xC0, 0x5C, + 0xDF, 0x2D, 0xE8, 0x0F, 0x54, 0x76, 0xD5, 0x01, + 0x18, 0xA0, 0x8F, 0xB0, 0xE1, 0x62, 0x8B, 0x68, + 0xCA, 0xD3, 0x99, 0xDC, 0x47, 0xEA, 0x7A, 0xBA, + 0x3A, 0xE1, 0x61, 0x4C, 0x94, 0xC1, 0xB2, 0x72, + 0xEF, 0xC4, 0x44, 0x69, 0xB1, 0x0D, 0x27, 0x42, + 0xE2, 0x1B, 0x8C, 0xA7, 0x7C, 0x41, 0x2B, 0x73, + 0xF1, 0x26, 0x8A, 0x64, 0xD5, 0x42, 0x87, 0x58, + 0xFA, 0x5D, 0x37, 0x27, 0x11, 0xAD, 0xE5, 0x9D, + 0x1F, 0xC8, 0x69, 0xA7, 0x14, 0x8C, 0x5D, 0xD6, + 0x55, 0x4E, 0xD8, 0xB4, 0xFE, 0x65, 0xAD, 0xAD, + 0x0D, 0xD6, 0x10, 0xE5, 0x1D, 0x3F, 0x34, 0x5C, + 0x1C, 0xE7, 0x51, 0xCF, 0x3C, 0x24, 0x84, 0x64, + 0xE4, 0xBF, 0xF6, 0xBA, 0x90, 0x4B, 0x83, 0x83, + 0x23, 0xF8, 0x9C, 0xDB, 0xA9, 0xD9, 0x99, 0x59, + 0x39, 0x3F, 0x99, 0x27, 0x94, 0x8E, 0x2E, 0xCE, + 0x4E, 0x37, 0xAA, 0x6C, 0x74, 0xE4, 0x84, 0x84, + 0xAE, 0x65, 0x71, 0x76, 0x04, 0x15, 0x28, 0xEB, + 0xCE, 0x00, 0x94, 0xF4, 0x2F, 0x27, 0x45, 0x89, + 0x0F, 0xD8, 0x2B, 0xA7, 0x3C, 0x9D, 0xF1, 0x38, + 0x88, 0xB0, 0xF6, 0x7A, 0x4C, 0xED, 0x3D, 0x0E, + 0x2E, 0x97, 0x4E, 0x08, 0xDC, 0x73, 0xDB, 0x19, + 0x09, 0x7B, 0x3D, 0x4A, 0x0B, 0x2B, 0xDB, 0x6F, + 0x05, 0x12, 0x6E, 0xC8, 0xC2, 0x7E, 0x37, 0x75, + 0xF9, 0x08, 0x0C, 0x6C, 0x91, 0xA1, 0x49, 0x98, + 0xA8, 0xC0, 0x37, 0xE9, 0x7D, 0xE8, 0x58, 0x10, + 0xB0, 0xB3, 0x07, 0xD6, 0x06, 0x36, 0xE9, 0xAA, + 0xC0, 0xC6, 0xC0, 0x54, 0xCD, 0x8F, 0xA3, 0x49, + 0x13, 0x62, 0x56, 0x30, 0xC0, 0xC2, 0xEE, 0x07, + 0x07, 0x58, 0xAF, 0x41, 0xD3, 0x4B, 0x4D, 0xC4, + 0xFE, 0xAD, 0x19, 0xD8, 0x03, 0x39, 0xCA, 0x80, + 0xB4, 0xDD, 0x40, 0x06, 0x54, 0x6A, 0xBA, 0xC1, + 0xB1, 0xD0, 0xEE, 0x00, 0xD0, 0x47, 0xA5, 0x2C, + 0x44, 0x17, 0xA3, 0xC3, 0x10, 0x20, 0x93, 0xC3, + 0xC9, 0xE6, 0xA2, 0xE1, 0x13, 0x29, 0xA7, 0x97, + 0xE8, 0xC3, 0x8F, 0x0D, 0x17, 0xA9, 0xE3, 0xC1, + 0x4F, 0xBD, 0x8B, 0x2B, 0xE2, 0xB2, 0x1E, 0xFE, + 0xBC, 0x3A, 0xE0, 0xE9, 0x20, 0x90, 0xFC, 0x35, + 0xBE, 0x30, 0x3E, 0x50, 0x93, 0x10, 0x40, 0xB0, + 0x44, 0xAF, 0xFA, 0x66, 0x04, 0x70, 0x62, 0xCE, + 0x60, 0x5B, 0xAE, 0xD3, 0x5D, 0x58, 0xCD, 0xAF, + 0xE4, 0x2B, 0x1C, 0x2E, 0xF5, 0xD7, 0x9C, 0x79, + 0x6B, 0xDB, 0x44, 0xE8, 0x10, 0xA0, 0x48, 0x80, + 0x89, 0xD9, 0xCA, 0xF1, 0x09, 0xA4, 0x34, 0xF4, + 0x74, 0xAF, 0x2F, 0x02, 0xDA, 0x4B, 0x6C, 0xAF, + 0x87, 0x5E, 0x4A, 0xEC, 0x20, 0xB5, 0x8D, 0x6D, + 0x45, 0x9C, 0xA1, 0x67, 0x9A, 0xB9, 0xFE, 0x32, + 0xF8, 0xC1, 0xD8, 0x34, 0x3D, 0xC6, 0xA5, 0xA5, + 0x05, 0xDE, 0xAA, 0xEB, 0x87, 0xF7, 0xB7, 0x77, + 0x4F, 0x96, 0xC0, 0x60, 0xA8, 0xDA, 0xD7, 0xA3, + 0x91, 0x61, 0xF0, 0xF9, 0x29, 0xBB, 0x63, 0xA1, + 0x2D, 0xEC, 0xE8, 0xAF, 0x5F, 0x0A, 0x6D, 0x8F, + 0x12, 0x39, 0xB9, 0x94, 0x4C, 0xAD, 0x86, 0x45, + 0x05, 0xFE, 0x48, 0x66, 0x9B, 0x9F, 0x3F, 0xDF, + 0x5F, 0xB4, 0x46, 0x3A, 0xA2, 0x50, 0x10, 0x92, + 0x77, 0x18, 0xB3, 0x2F, 0xF7, 0x47, 0x11, 0x90, + 0x10, 0xC7, 0x72, 0x6C, 0x14, 0xD4, 0xE5, 0x62, + 0xE1, 0x36, 0x96, 0x42, 0x9F, 0x1F, 0xBC, 0x8C, + 0xBC, 0xC4, 0xD2, 0x6C, 0x9E, 0x04, 0xD4, 0xD8, + 0xF8, 0xF3, 0x98, 0x04, 0x06, 0x7A, 0x98, 0x54, + 0xF0, 0xCB, 0x3E, 0x43, 0xFD, 0x55, 0x09, 0x2B, + 0x81, 0x74, 0x10, 0x56, 0xBC, 0x47, 0x94, 0xB3, + 0x3E, 0xF2, 0xE6, 0x86, 0x76, 0xC6, 0xBD, 0x3D, + 0xBD, 0xD0, 0xC7, 0xDB, 0xB8, 0x18, 0xD8, 0xB8, + 0x0C, 0x67, 0x7B, 0x37, 0x4F, 0x5F, 0x4B, 0xCD, + 0x4D, 0x96, 0x2C, 0x4A, 0x20, 0x3F, 0xDF, 0x3A, + 0x43, 0x67, 0x69, 0x00, 0x62, 0x06, 0x94, 0x79, + 0xD7, 0x00, 0xAA, 0x36, 0x01, 0xA0, 0x30, 0x3E, + 0x2D, 0x34, 0xEF, 0xAD, 0x6E, 0xED, 0xBD, 0x4D, + 0xB9, 0x04, 0xF1, 0x3D, 0x6E, 0x75, 0xB0, 0xF5, + 0x52, 0x24, 0x90, 0x7D, 0xFB, 0x48, 0xE8, 0x08, + 0x88, 0xDB, 0x65, 0x80, 0x6A, 0x7F, 0x56, 0xB6, + 0x2B, 0x00, 0x80, 0xAD, 0x75, 0x44, 0x63, 0xA0, + 0x00, 0xB9, 0xFF, 0x1B, 0xCB, 0x70, 0x53, 0x13, + 0xA1, 0xEA, 0xDC, 0xE2, 0x9A, 0x58, 0x1D, 0xF7, + 0xF7, 0x4A, 0x5C, 0x40, 0xEF, 0xAF, 0xB5, 0x53, + 0x85, 0xBA, 0x08, 0x46, 0x9C, 0x0A, 0x28, 0x7B, + 0x8B, 0xD0, 0x44, 0x29, 0xD1, 0x49, 0x18, 0x92, + 0x30, 0xEB, 0x7F, 0x02, 0xFA, 0x6A, 0x3B, 0xD9, + 0x0A, 0xA1, 0x55, 0x1C, 0xEE, 0x1E, 0x3A, 0x0A, + 0xC0, 0x5D, 0xA9, 0xC1, 0x3F, 0x2E, 0x11, 0xD2, + 0xD2, 0x4D, 0xFA, 0xD6, 0x46, 0xC7, 0x01, 0xD5, + 0x59, 0x24, 0x50, 0x2F, 0xEB, 0xA9, 0xD5, 0xED, + 0xEF, 0x67, 0xA1, 0x8B, 0x51, 0xE1, 0x67, 0xB5, + 0x33, 0xE4, 0x50, 0x30, 0xE1, 0xC3, 0xF0, 0x40, + 0x60, 0x19, 0x0F, 0xCB, 0x19, 0x0B, 0x0E, 0xFC, + 0x61, 0x4A, 0xDE, 0xB0, 0x4D, 0x7B, 0xF4, 0xCB, + 0x4B, 0x90, 0x10, 0x3D, 0xE5, 0x59, 0x3B, 0xF7, + 0x72, 0xE8, 0x19, 0x76, 0xA2, 0x51, 0xF9, 0x3D, + 0x7D, 0x74, 0x52, 0xAC, 0x69, 0xB5, 0xC3, 0x5A, + 0xDD, 0x0D, 0x32, 0xDE, 0x86, 0xC2, 0x20, 0xBD, + 0x51, 0xDC, 0xE2, 0x88, 0x90, 0xD2, 0x12, 0x30, + 0x9F, 0x6E, 0x64, 0x16, 0xE8, 0x46, 0x09, 0xEF, + 0x41, 0xB6, 0x66, 0x34, 0xBB, 0x59, 0x56, 0xBC, + 0x1C, 0x55, 0x13, 0xBF, 0xFE, 0xEE, 0x2C, 0xE5, + 0x4F, 0x26, 0x99, 0xDC, 0x84, 0x9E, 0xEF, 0x9F, + 0xB5, 0x4E, 0xF4, 0x93, 0xE9, 0x04, 0x08, 0xE2, + 0xCE, 0x87, 0x38, 0x73, 0x39, 0xC3, 0x4B, 0x26, + 0xA4, 0x5A, 0x1F, 0x8C, 0x12, 0xA9, 0xC9, 0x12, + 0x2C, 0xD7, 0xC3, 0x5F, 0x47, 0x5D, 0x9D, 0xEF, + 0x00, 0xF1, 0xF7, 0x20, 0x08, 0x02, 0xC8, 0xBA, + 0x30, 0xC1, 0x95, 0xF3, 0x02, 0x32, 0xE9, 0x38, + 0x58, 0x38, 0xAE, 0x70, 0xF5, 0x29, 0x63, 0x1F, + 0x3D, 0xEC, 0x7D, 0xB3, 0x20, 0x78, 0xB5, 0x77, + 0xFB, 0x2B, 0x78, 0xFB, 0xDC, 0xA4, 0xC0, 0x2A, + 0x76, 0x3F, 0x84, 0x00, 0x74, 0x0D, 0x66, 0x5F, + 0x2D, 0xBB, 0xE5, 0x41, 0x9D, 0x07, 0xBB, 0x99, + 0x14, 0x27, 0x4D, 0xEF, 0x9A, 0x28, 0x44, 0x9F, + 0x3F, 0x66, 0x20, 0x8C, 0xC6, 0xD6, 0x24, 0xCD, + 0x67, 0x7C, 0x42, 0x8E, 0xC6, 0xEF, 0x7F, 0x25, + 0x2D, 0x74, 0xCA, 0x81, 0xDB, 0x26, 0xAE, 0xCB, + 0xA7, 0x83, 0xFD, 0x95, 0x46, 0xC5, 0xBE, 0x5C, + 0xFC, 0x07, 0xC5, 0xFF, 0x34, 0x70, 0x82, 0x6E, + 0xC7, 0x90, 0xAF, 0xC8, 0x99, 0xAB, 0xA7, 0x4E, + 0x02, 0xC1, 0x92, 0x22, 0x05, 0xA8, 0x38, 0xF8, + 0x78, 0xA3, 0x23, 0x0E, 0xD6, 0x27, 0x27, 0xE4, + 0x55, 0xEF, 0x5A, 0xBE, 0x22, 0x1B, 0xF9, 0x00, + 0xC4, 0x02, 0x44, 0x28, 0xF0, 0x40, 0x16, 0x97, + 0x17, 0x6E, 0x1A, 0x66, 0x1B, 0x98, 0xD8, 0x89, + 0x69, 0xB1, 0x8F, 0x61, 0x30, 0xC9, 0xB4, 0x84, + 0x04, 0xDF, 0x5F, 0x72, 0xAA, 0xA7, 0xC5, 0x24, + 0xC6, 0x1E, 0x80, 0xEE, 0x3A, 0x06, 0xED, 0x8F, + 0xAA, 0x73, 0xED, 0x00, 0xBB, 0x08, 0xFA, 0xF8, + 0x68, 0x2A, 0xCE, 0x3B, 0xA1, 0x98, 0x9A, 0xD6, + 0x55, 0xB7, 0x93, 0xE2, 0xCA, 0x7A, 0x2C, 0xAD, + 0x2D, 0xC7, 0x13, 0x7C, 0x9C, 0x2F, 0xFD, 0x2E, + 0xB6, 0x61, 0xCB, 0xA0, 0x93, 0x39, 0xC8, 0x56, + 0xD5, 0xCE, 0xD3, 0x9F, 0xE5, 0x06, 0x7E, 0x7E, + 0xDE, 0x05, 0x2B, 0x4E, 0x14, 0xB7, 0xD1, 0xB3, + 0xF0, 0x3B, 0x17, 0xF3, 0xA2, 0x61, 0x64, 0x88, + 0x28, 0x41, 0xE4, 0x90, 0x5F, 0x04, 0x6A, 0x12, + 0x01, 0x56, 0x7B, 0x9F, 0x4C, 0x51, 0x33, 0x13, + 0x9B, 0x40, 0xDB, 0xBD, 0x78, 0x38, 0x54, 0x96, + 0x0B, 0x20, 0xA0, 0x8D, 0x55, 0xD4, 0xD6, 0x15, + 0xAD, 0x75, 0x71, 0x0F, 0xC3, 0xBB, 0x78, 0x10, + 0xB3, 0xA2, 0xAF, 0x7A, 0x01, 0x16, 0x4D, 0xDC, + 0xFC, 0xBC, 0xCA, 0x24, 0xEF, 0x47, 0xBE, 0xDD, + 0x4A, 0xF9, 0x64, 0xCA, 0xBA, 0xF5, 0x74, 0xD0, + 0x53, 0x70, 0x75, 0xD9, 0x21, 0x91, 0x23, 0xF0, + 0x68, 0x02, 0xFF, 0x90, 0xA8, 0xC5, 0xB5, 0x87, + 0x6C, 0x17, 0x73, 0x4C, 0x8C, 0xFC, 0xBC, 0x7C, + 0x5E, 0xAE, 0x98, 0x34, 0xCC, 0x7C, 0xDC, 0xB6, + 0x26, 0x5F, 0x82, 0x6E, 0xF0, 0x41, 0x21, 0x43, + 0x00, 0xCB, 0x58, 0x13, 0xEB, 0x9B, 0xDB, 0x1B, + 0x0A, 0x8F, 0x3A, 0xD4, 0x1F, 0xA9, 0x51, 0x98, + 0xBA, 0xA2, 0x04, 0xF2, 0xA2, 0x9B, 0x88, 0x2D, + 0x89, 0x72, 0x4C, 0xA3, 0xD6, 0x64, 0xE4, 0x2C, + 0xAC, 0x6A, 0x2C, 0x40, 0x98, 0x28, 0x7E, 0xFF, + 0x7F, 0xE6, 0xF8, 0x6B, 0x22, 0xF7, 0x94, 0xE5, + 0x07, 0xDF, 0x58, 0x7F, 0xA4, 0xAC, 0xC7, 0xC5, + 0x5E, 0x9D, 0x27, 0x66, 0x6E, 0x12, 0x52, 0x50, + 0x8B, 0x48, 0x3E, 0x72, 0xAA, 0xB8, 0xFB, 0x9B, + 0xB2, 0xD2, 0xA4, 0xE8, 0x30, 0x02, 0x41, 0x21, + 0x61, 0x9A, 0x2C, 0xD0, 0x80, 0x20, 0xD2, 0xB3, + 0x33, 0x78, 0x46, 0x0A, 0x50, 0x83, 0x43, 0x43, + 0xE3, 0x38, 0xAC, 0xE3, 0xBB, 0xCB, 0x8B, 0x4B, + 0x8B, 0x72, 0xD4, 0xFA, 0x86, 0x36, 0x16, 0xF4, + 0x54, 0xAD, 0x78, 0x94, 0x51, 0x11, 0x47, 0xC6, + 0x46, 0xFB, 0x79, 0x1D, 0x47, 0xF4, 0xB3, 0xB1, + 0x32, 0xCF, 0x1F, 0x4B, 0x99, 0x84, 0xE6, 0x9B, + 0x18, 0x0E, 0xBC, 0xF5, 0xB5, 0x27, 0x5A, 0x6A, + 0x42, 0xCA, 0xCE, 0x02, 0x21, 0x21, 0x8D, 0x5D, + 0x1F, 0x87, 0x17, 0xBB, 0x43, 0xF3, 0x01, 0xCB, + 0x47, 0x5C, 0xCA, 0xA6, 0xCE, 0xE7, 0x97, 0xC5, + 0x0F, 0xD8, 0x73, 0xEF, 0x37, 0x87, 0xFD, 0x3C, + 0xBC, 0x67, 0xD1, 0xBD, 0x65, 0xD5, 0x51, 0x9C, + 0x1E, 0xA5, 0x17, 0x7A, 0xA2, 0x12, 0x72, 0xB2, + 0x32, 0xE9, 0xEF, 0x8D, 0x57, 0x87, 0xCD, 0x0F, + 0x8F, 0x54, 0xE2, 0x8E, 0x56, 0xE6, 0x66, 0xB4, + 0x36, 0x8D, 0x27, 0x4B, 0x9B, 0x2B, 0x36, 0xF2, + 0x0C, 0xD3, 0xE1, 0x9F, 0x45, 0x95, 0x81, 0x52, + 0xD0, 0x6B, 0x45, 0x3A, 0xE0, 0x30, 0xF0, 0x23, + 0xA1, 0x1A, 0x74, 0x0C, 0xD6, 0x06, 0x7E, 0xAB, + 0x29, 0x92, 0x14, 0x6E, 0xB4, 0x64, 0x30, 0xE5, + 0x67, 0xDC, 0xD2, 0xAB, 0x71, 0xA1, 0xC1, 0x01, + 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x87, 0x47, + 0xC7, 0x1C, 0x5A, 0xC9, 0xEE, 0xA1, 0xC1, 0x01, + 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x87, 0x47, + 0xC7, 0x1C, 0x5A, 0xC9, 0xEE, 0xA1, 0xC1, 0x01, + 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x87, 0x47, + 0xC7, 0x1C, 0x5A, 0xC9, 0xEE, 0xA1, 0xC1, 0x01, + 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x87, 0x47, + 0xC7, 0x1C, 0x5A, 0xC9, 0xEE, 0xA1, 0xC1, 0x01, + 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x97, 0x40, + 0xC2, 0x79, 0xEB, 0x90, 0x4A, 0x9A, 0xEE, 0x36, + 0xB4, 0x0F, 0x19, 0x62, 0xB8, 0x68, 0x08, 0xC8, + 0x48, 0x93, 0x25, 0x49, 0x91, 0x21, 0x41, 0x81, + 0x01, 0xDA, 0xA0, 0xD4, 0x0C, 0xDC, 0x6C, 0xB4, + 0x34, 0x8F, 0xC1, 0xB4, 0x6C, 0xBC, 0x30, 0xF0, + 0x70, 0xAB, 0x1D, 0x71, 0xA9, 0x19, 0x78, 0xB8, + 0x38, 0xE3, 0x54, 0x38, 0xE1, 0x51, 0x30, 0xF8, + 0x38, 0xE3, 0x54, 0x39, 0xE0, 0x51, 0x70, 0xA0, + 0x24, 0xFD, 0x6A, 0x02, 0xFB, 0x4F, 0x0E, 0x4A, + 0xDA, 0x43, 0xE4, 0x99, 0x50, 0xF1, 0xD8, 0x3A, + 0x9E, 0x67, 0x98, 0xE6, 0x77, 0xD5, 0xFC, 0x6E, + 0xD7, 0x1E, 0xFD, 0x80, 0x0D, 0xAC, 0x99, 0x4C, + 0x99, 0x53, 0x4F, 0x09, 0x7B, 0xE1, 0x2B, 0x41, + 0x6B, 0x9A, 0x79, 0x40, 0xCD, 0x28, 0x1D, 0x88, + 0x5D, 0x53, 0xB0, 0x09, 0x84, 0xE1, 0x2B, 0x01, + 0x2B, 0x1E, 0x02, 0x80, 0xF2, 0xAC, 0x7A, 0x17, + 0x21, 0x17, 0x17, 0x96, 0xF8, 0xA5, 0x73, 0x6E, + 0x35, 0x33, 0x6B, 0xE9, 0xDF, 0x81, 0x3F, 0x84, + 0xEB, 0x8D, 0xE5, 0x72, 0x74, 0x3F, 0xE1, 0xCE, + 0xB5, 0x93, 0xDB, 0x49, 0x6F, 0x21, 0xBF, 0x88, + 0xB7, 0x93, 0xDB, 0x48, 0x6E, 0x21, 0xBE, 0x81, + 0xFE, 0xDA, 0x58, 0x2D, 0xF5, 0x25, 0x7D, 0xA4, + 0x24, 0x9F, 0xD5, 0xA0, 0x78, 0xA8, 0xFC, 0x3C, + 0xBC, 0x67, 0xD1, 0xBD, 0x65, 0xD5, 0xB5, 0x75, + 0xF5, 0x2E, 0x98, 0xF4, 0x2C, 0x9C, 0xFC, 0x3C, + 0xBC, 0x67, 0xF9, 0x9C, 0x44, 0x94, 0xD0, 0x19, + 0x99, 0x22, 0x84, 0x58, 0x82, 0x32, 0x52, 0x88, + 0x08, 0xB3, 0x75, 0x18, 0xC0, 0x70, 0x6C, 0xAB, + 0x2B, 0x90, 0x9A, 0xFB, 0x21, 0xF1, 0xAD, 0x65, + 0xE5, 0x5E, 0xFC, 0x9E, 0x44, 0x94, 0x38, 0xF6, + 0x74, 0xCF, 0xED, 0x87, 0x5F, 0x8F, 0x4B, 0x84, + 0x06, 0xBD, 0x4F, 0x25, 0xFD, 0x2D, 0xC1, 0x0E, + 0x8C, 0x37, 0x71, 0x04, 0xDC, 0x0C, 0xB8, 0x77, + 0xF5, 0x4E, 0x48, 0x35, 0xEF, 0x3F, 0xE7, 0x2F, + 0xAF, 0x14, 0x82, 0xFC, 0x26, 0xF6, 0x2A, 0xED, + 0x6D, 0xD6, 0x34, 0x4A, 0x90, 0x40, 0xE8, 0x3A, + 0xB8, 0x03, 0x5D, 0x37, 0xEF, 0x3F, 0x3B, 0xE3, + 0x61, 0xDA, 0x2C, 0x4A, 0x92, 0x42, 0x14, 0x95, + 0x15, 0x4F, 0x7B, 0x11, 0x78, 0x48, 0x2E, 0xF2, + 0x78, 0x32, 0x05, 0x6F, 0x15, 0xEE, 0x8E, 0xC7, + 0x4E, 0xB0, 0x04, 0x68, 0x55, 0xE1, 0x81, 0xE4, + 0x66, 0xBD, 0xEE, 0x87, 0x5F, 0x0A, 0x62, 0xA2, + 0x07, 0xDF, 0x69, 0xA0, 0x71, 0xC1, 0x00, 0x43, + 0xC5, 0xAF, 0x9D, 0xF7, 0x8A, 0x60, 0x27, 0xFA, + 0x8A, 0x51, 0xD1, 0xFC, 0x24, 0xA5, 0x40, 0x86, + 0x27, 0x7A, 0xCA, 0x8F, 0x84, 0x29, 0xB9, 0x79, + 0xF9, 0x22, 0xA2, 0x8F, 0x57, 0xD6, 0x31, 0xF7, + 0x56, 0x05, 0xB5, 0xF0, 0x6B, 0xC6, 0x56, 0x96, + 0x16, 0xCD, 0x4D, 0x60, 0xB8, 0x39, 0xDC, 0x1A, + 0xBB, 0xE9, 0x59, 0x1C, 0x57, 0xFA, 0x6A, 0xAA, + 0x2A, 0xF1, 0x71, 0x5C, 0x84, 0x15, 0xF8, 0x3E, + 0x8F, 0xD8, 0x68, 0x95, 0xC7, 0x71, 0x90, 0xDB, + 0x5D, 0x0F, 0xF0, 0xB5, 0x6E, 0xC3, 0x53, 0x93, + 0x13, 0xC8, 0x48, 0x65, 0xBD, 0x9C, 0x72, 0xB4, + 0x38, 0xEB, 0xDF, 0xFA, 0x22, 0xF7, 0x96, 0x56, + 0x77, 0x3C, 0x8C, 0x51, 0x0E, 0xB8, 0x19, 0x56, + 0xD0, 0xC2, 0x7F, 0xBA, 0x39, 0x94, 0x04, 0xC4, + 0x44, 0x9F, 0x1F, 0x32, 0xEA, 0x6B, 0x9A, 0x5C, + 0xFD, 0xB4, 0x04, 0x41, 0x8A, 0x27, 0xB7, 0x77, + 0xF7, 0x2C, 0xAC, 0x81, 0x59, 0x68, 0x9C, 0x5A, + 0xEB, 0xA3, 0x13, 0x5E, 0x13, 0xA5, 0xEC, 0x0F, + 0x06, 0x8E, 0x25, 0xB9, 0x61, 0xD1, 0x87, 0x06, + 0x86, 0xCC, 0xEC, 0x86, 0xDF, 0xF8, 0x9E, 0xD7, + 0x7E, 0xC0, 0x76, 0x1A, 0xDF, 0x9F, 0xC9, 0x48, + 0xC8, 0xB2, 0x9C, 0xF6, 0x9C, 0x8C, 0x60, 0x08, + 0x82, 0x79, 0xAE, 0xC2, 0x92, 0x08, 0xD2, 0xA8, + 0xB4, 0x77, 0xCD, 0xBD, 0x69, 0x54, 0xD6, 0x3C, + 0x94, 0x8F, 0x19, 0x75, 0x7F, 0x81, 0xED, 0xEF, + 0x24, 0xD8, 0x4B, 0x80, 0x7B, 0xEB, 0x6D, 0xBE, + 0x2E, 0xD5, 0x63, 0x12, 0x3A, 0x8A, 0xEA, 0x2A, + 0xAA, 0x71, 0xC7, 0xAB, 0x73, 0xC3, 0xA3, 0x63, + 0xE3, 0x38, 0x8F, 0xE3, 0x3F, 0x8F, 0x8B, 0x51, + 0xD3, 0x68, }; static unsigned char vfs5011_init_16[] = { /* 2565 B */ - 0x02, 0xF0, 0x00, 0x14, 0x00, 0x03, 0x00, 0x09, - 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, - 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, - 0x20, 0x04, 0x30, 0xE5, 0x03, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, - 0xEA, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x4C, 0x20, 0x04, 0x30, 0x0A, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, - 0x04, 0x30, 0x01, 0xDE, 0x01, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, - 0x30, 0x02, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, - 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x08, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x40, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x60, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, - 0x30, 0x30, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x90, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, - 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x30, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xD8, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, - 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x04, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, - 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, - 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, - 0x30, 0x00, 0x00, 0x74, 0x01, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, - 0x74, 0x01, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, - 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, - 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, - 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, - 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, - 0xFF, 0xF9, 0x87, 0x20, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x07, 0x20, - 0xBA, 0xF8, 0x07, 0x20, 0xB9, 0xF8, 0x07, 0x20, - 0xB8, 0xF8, 0x07, 0x20, 0xB7, 0xF8, 0x07, 0x20, - 0xB6, 0xF8, 0x07, 0x20, 0xB5, 0xF8, 0x07, 0x20, - 0xB4, 0xF8, 0x07, 0x20, 0xB3, 0xF8, 0x07, 0x20, - 0xB2, 0xF8, 0x07, 0x20, 0xB1, 0xF8, 0x07, 0x22, - 0xB0, 0xF8, 0x07, 0x22, 0xAF, 0xF8, 0x07, 0x22, - 0xAE, 0xF8, 0x07, 0x22, 0xAD, 0xF8, 0x07, 0x22, - 0xAC, 0xF8, 0x07, 0x22, 0xAB, 0xF8, 0x07, 0x22, - 0xAA, 0xF8, 0x07, 0x22, 0xA9, 0xF8, 0x07, 0x22, - 0xA8, 0xF8, 0x07, 0x22, 0xA7, 0xF8, 0x07, 0x22, - 0xA6, 0xF8, 0x07, 0x22, 0xA5, 0xF8, 0x07, 0x22, - 0xA4, 0xF8, 0x07, 0x22, 0xA3, 0xF8, 0x07, 0x22, - 0xA2, 0xF8, 0x07, 0x22, 0xA1, 0xF8, 0x07, 0x22, - 0xA0, 0xF8, 0x07, 0x22, 0x9F, 0xF8, 0x07, 0x22, - 0x9E, 0xF8, 0x07, 0x22, 0x9D, 0xF8, 0x07, 0x22, - 0x9C, 0xF8, 0x07, 0x22, 0x9B, 0xF8, 0x07, 0x22, - 0x9A, 0xF8, 0x07, 0x22, 0x99, 0xF8, 0x07, 0x22, - 0x98, 0xF8, 0x07, 0x22, 0x97, 0xF8, 0x07, 0x22, - 0x96, 0xF8, 0x07, 0x22, 0x95, 0xF8, 0x07, 0x22, - 0x94, 0xF8, 0x07, 0x22, 0x93, 0xF8, 0x07, 0x22, - 0x92, 0xF8, 0x07, 0x22, 0x91, 0xF8, 0x07, 0x22, - 0x90, 0xF8, 0x07, 0x22, 0x8F, 0xF8, 0x07, 0x22, - 0x8E, 0xF8, 0x07, 0x22, 0x8D, 0xF8, 0x07, 0x22, - 0x8C, 0xF8, 0x07, 0x22, 0x8B, 0xF8, 0x07, 0x22, - 0x8A, 0xF8, 0x07, 0x22, 0x89, 0xF8, 0x07, 0x22, - 0x88, 0xF8, 0x07, 0x22, 0x87, 0xF8, 0x07, 0x22, - 0x86, 0xF8, 0x07, 0x22, 0x85, 0xF8, 0x07, 0x22, - 0x84, 0xF8, 0x07, 0x22, 0x83, 0xF8, 0x07, 0x22, - 0x82, 0xF8, 0x07, 0x22, 0x81, 0xF8, 0x07, 0x22, - 0x80, 0xF8, 0x07, 0x22, 0x7F, 0xF8, 0x07, 0x22, - 0x7E, 0xF8, 0x07, 0x22, 0x7D, 0xF8, 0x07, 0x22, - 0x7C, 0xF8, 0x07, 0x22, 0x7B, 0xF8, 0x07, 0x22, - 0x7A, 0xF8, 0x07, 0x22, 0x79, 0xF8, 0x07, 0x22, - 0x78, 0xF8, 0x07, 0x22, 0x77, 0xF8, 0x07, 0x22, - 0x76, 0xF8, 0x07, 0x22, 0x75, 0xF8, 0x07, 0x22, - 0x74, 0xF8, 0x07, 0x22, 0x73, 0xF8, 0x07, 0x22, - 0x72, 0xF8, 0x07, 0x22, 0x71, 0xF8, 0x07, 0x22, - 0x70, 0xF8, 0x07, 0x22, 0x6F, 0xF8, 0x07, 0x22, - 0x6E, 0xF8, 0x07, 0x22, 0x6D, 0xF8, 0x07, 0x22, - 0x6C, 0xF8, 0x07, 0x22, 0x6B, 0xF8, 0x07, 0x22, - 0x6A, 0xF8, 0x07, 0x22, 0x69, 0xF8, 0x07, 0x22, - 0x68, 0xF8, 0x07, 0x22, 0x67, 0xF8, 0x07, 0x22, - 0x66, 0xF8, 0x07, 0x22, 0x65, 0xF8, 0x07, 0x22, - 0x64, 0xF8, 0x07, 0x22, 0x63, 0xF8, 0x07, 0x22, - 0x62, 0xF8, 0x07, 0x22, 0x61, 0xF8, 0x07, 0x22, - 0x60, 0xF8, 0x07, 0x22, 0x5F, 0xF8, 0x07, 0x22, - 0x5E, 0xF8, 0x07, 0x22, 0x5D, 0xF8, 0x07, 0x22, - 0x5C, 0xF8, 0x07, 0x22, 0x5B, 0xF8, 0x07, 0x22, - 0x5A, 0xF8, 0x07, 0x22, 0x59, 0xF8, 0x07, 0x22, - 0x58, 0xF8, 0x07, 0x22, 0x57, 0xF8, 0x07, 0x22, - 0x56, 0xF8, 0x07, 0x22, 0x55, 0xF8, 0x07, 0x22, - 0x54, 0xF8, 0x07, 0x22, 0x53, 0xF8, 0x07, 0x22, - 0x52, 0xF8, 0x07, 0x22, 0x51, 0xF8, 0x07, 0x22, - 0x50, 0xF8, 0x07, 0x22, 0x4F, 0xF8, 0x07, 0x22, - 0x4E, 0xF8, 0x07, 0x22, 0x4D, 0xF8, 0x07, 0x22, - 0x4C, 0xF8, 0x07, 0x22, 0x4B, 0xF8, 0x07, 0x22, - 0x4A, 0xF8, 0x07, 0x22, 0x49, 0xF8, 0x07, 0x22, - 0x48, 0xF8, 0x07, 0x22, 0x47, 0xF8, 0x07, 0x22, - 0x46, 0xF8, 0x07, 0x22, 0x45, 0xF8, 0x07, 0x22, - 0x44, 0xF8, 0x07, 0x22, 0x43, 0xF8, 0x07, 0x22, - 0x42, 0xF8, 0x07, 0x22, 0x41, 0xF8, 0x07, 0x22, - 0x40, 0xF8, 0x07, 0x22, 0x3F, 0xF8, 0x07, 0x22, - 0x3E, 0xF8, 0x07, 0x22, 0x3D, 0xF8, 0x07, 0x22, - 0x3C, 0xF8, 0x07, 0x22, 0x3B, 0xF8, 0x07, 0x22, - 0x3A, 0xF8, 0x07, 0x22, 0x39, 0xF8, 0x07, 0x22, - 0x38, 0xF8, 0x07, 0x22, 0x37, 0xF8, 0x07, 0x22, - 0x36, 0xF8, 0x07, 0x22, 0x35, 0xF8, 0x07, 0x22, - 0x34, 0xF8, 0x07, 0x22, 0x33, 0xF8, 0x07, 0x22, - 0x32, 0xF8, 0x07, 0x22, 0x31, 0xF8, 0x07, 0x22, - 0x30, 0xF8, 0x07, 0x22, 0x2F, 0xF8, 0x07, 0x22, - 0x2E, 0xF8, 0x07, 0x22, 0x2D, 0xF8, 0x07, 0x22, - 0x2C, 0xF8, 0x07, 0x22, 0x2B, 0xF8, 0x07, 0x22, - 0x2A, 0xF8, 0x07, 0x22, 0x29, 0xF8, 0x07, 0x22, - 0x28, 0xF8, 0x07, 0x22, 0x27, 0xF8, 0x07, 0x22, - 0x26, 0xF8, 0x07, 0x22, 0x25, 0xF8, 0x07, 0x22, - 0x24, 0xF8, 0x07, 0x22, 0x23, 0xF8, 0x07, 0x20, - 0x22, 0xF8, 0x07, 0x20, 0x21, 0xF8, 0x07, 0x20, - 0x20, 0xF8, 0x07, 0x20, 0x1F, 0xF8, 0x07, 0x20, - 0x1E, 0xF8, 0x07, 0x20, 0x1D, 0xF8, 0x07, 0x20, - 0x1C, 0xF8, 0x07, 0x20, 0x1C, 0xF8, 0x07, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD8, 0xF8, 0x27, 0x20, 0xD9, 0xF8, 0x27, 0x20, - 0xDA, 0xF8, 0x27, 0x20, 0xDB, 0xF8, 0x27, 0x20, - 0xDC, 0xF8, 0x27, 0x20, 0xDD, 0xF8, 0x27, 0x20, - 0xDE, 0xF8, 0x27, 0x20, 0xDF, 0xF8, 0x27, 0x20, - 0xE0, 0xF8, 0x27, 0x20, 0xE1, 0xF8, 0x27, 0x20, - 0xE2, 0xF8, 0x27, 0x20, 0xE3, 0xF8, 0x27, 0x20, - 0xE4, 0xF8, 0x27, 0x20, 0xE5, 0xF8, 0x27, 0x20, - 0xE6, 0xF8, 0x27, 0x20, 0xE7, 0xF8, 0x27, 0x20, - 0xE8, 0xF8, 0x27, 0x20, 0xE9, 0xF8, 0x27, 0x20, - 0xEA, 0xF8, 0x27, 0x20, 0xEB, 0xF8, 0x27, 0x20, - 0xEC, 0xF8, 0x27, 0x20, 0xED, 0xF8, 0x27, 0x20, - 0xEE, 0xF8, 0x27, 0x20, 0xEF, 0xF8, 0x27, 0x20, - 0xF0, 0xF8, 0x27, 0x20, 0xF1, 0xF8, 0x27, 0x20, - 0xF2, 0xF8, 0x27, 0x20, 0xF3, 0xF8, 0x27, 0x20, - 0xF4, 0xF8, 0x27, 0x20, 0xF5, 0xF8, 0x27, 0x20, - 0xF6, 0xF8, 0x27, 0x20, 0xF7, 0xF8, 0x27, 0x20, - 0xF8, 0xF8, 0x27, 0x20, 0xF9, 0xF8, 0x27, 0x20, - 0xFA, 0xF8, 0x27, 0x20, 0xFB, 0xF8, 0x27, 0x20, - 0xFC, 0xF8, 0x27, 0x20, 0xFD, 0xF8, 0x27, 0x20, - 0xFE, 0xF8, 0x27, 0x20, 0xFF, 0xF8, 0x27, 0x20, - 0x00, 0xF9, 0x27, 0x20, 0xD7, 0xF8, 0x27, 0x20, - 0x00, 0xF8, 0x27, 0x20, 0x01, 0xF8, 0x27, 0x20, - 0x02, 0xF8, 0x27, 0x20, 0x03, 0xF8, 0x27, 0x20, - 0x04, 0xF8, 0x27, 0x20, 0x05, 0xF8, 0x27, 0x20, - 0x06, 0xF8, 0x27, 0x20, 0x07, 0xF8, 0x27, 0x20, - 0x08, 0xF8, 0x27, 0x20, 0x09, 0xF8, 0x27, 0x20, - 0x0A, 0xF8, 0x27, 0x20, 0x0B, 0xF8, 0x27, 0x20, - 0x0C, 0xF8, 0x27, 0x20, 0x0D, 0xF8, 0x27, 0x20, - 0x0E, 0xF8, 0x27, 0x20, 0x0F, 0xF8, 0x27, 0x20, - 0x10, 0xF8, 0x27, 0x20, 0x11, 0xF8, 0x27, 0x20, - 0x12, 0xF8, 0x27, 0x20, 0x13, 0xF8, 0x27, 0x20, - 0x14, 0xF8, 0x27, 0x20, 0x15, 0xF8, 0x27, 0x20, - 0x15, 0xF8, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, - 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, - 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, - 0x04, 0x17, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0E, - 0x00, 0x0C, 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x05, - 0x00, 0x0E, 0x00, 0x10, 0x20, 0xFD, 0x00, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, - 0x00, 0x03, 0x00, 0x09, 0x00, 0x04, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x08, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x0C, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x10, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x14, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xC8, 0x20, 0x04, 0x30, 0x04, 0x00, 0x00, - 0x00, 0x04, 0x05, 0x00, 0x0E, 0x00, 0x14, 0x20, - 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x83, 0x00, 0x03, 0x00, 0x09, 0x00, - 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x90, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x08, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x60, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x15, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x20, 0x28, 0x00, 0x00, + 0x02, 0xF0, 0x00, 0x14, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, + 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, + 0x20, 0x04, 0x30, 0xE5, 0x03, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, + 0xEA, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x4C, 0x20, 0x04, 0x30, 0x0A, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, + 0x04, 0x30, 0x01, 0xDE, 0x01, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, + 0x30, 0x02, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, + 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x08, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x40, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x60, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x90, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, + 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x30, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xD8, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, + 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x04, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, + 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, + 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, + 0x30, 0x00, 0x00, 0x74, 0x01, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, + 0x74, 0x01, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, + 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, + 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, + 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, + 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, + 0xFF, 0xF9, 0x87, 0x20, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x07, 0x20, + 0xBA, 0xF8, 0x07, 0x20, 0xB9, 0xF8, 0x07, 0x20, + 0xB8, 0xF8, 0x07, 0x20, 0xB7, 0xF8, 0x07, 0x20, + 0xB6, 0xF8, 0x07, 0x20, 0xB5, 0xF8, 0x07, 0x20, + 0xB4, 0xF8, 0x07, 0x20, 0xB3, 0xF8, 0x07, 0x20, + 0xB2, 0xF8, 0x07, 0x20, 0xB1, 0xF8, 0x07, 0x22, + 0xB0, 0xF8, 0x07, 0x22, 0xAF, 0xF8, 0x07, 0x22, + 0xAE, 0xF8, 0x07, 0x22, 0xAD, 0xF8, 0x07, 0x22, + 0xAC, 0xF8, 0x07, 0x22, 0xAB, 0xF8, 0x07, 0x22, + 0xAA, 0xF8, 0x07, 0x22, 0xA9, 0xF8, 0x07, 0x22, + 0xA8, 0xF8, 0x07, 0x22, 0xA7, 0xF8, 0x07, 0x22, + 0xA6, 0xF8, 0x07, 0x22, 0xA5, 0xF8, 0x07, 0x22, + 0xA4, 0xF8, 0x07, 0x22, 0xA3, 0xF8, 0x07, 0x22, + 0xA2, 0xF8, 0x07, 0x22, 0xA1, 0xF8, 0x07, 0x22, + 0xA0, 0xF8, 0x07, 0x22, 0x9F, 0xF8, 0x07, 0x22, + 0x9E, 0xF8, 0x07, 0x22, 0x9D, 0xF8, 0x07, 0x22, + 0x9C, 0xF8, 0x07, 0x22, 0x9B, 0xF8, 0x07, 0x22, + 0x9A, 0xF8, 0x07, 0x22, 0x99, 0xF8, 0x07, 0x22, + 0x98, 0xF8, 0x07, 0x22, 0x97, 0xF8, 0x07, 0x22, + 0x96, 0xF8, 0x07, 0x22, 0x95, 0xF8, 0x07, 0x22, + 0x94, 0xF8, 0x07, 0x22, 0x93, 0xF8, 0x07, 0x22, + 0x92, 0xF8, 0x07, 0x22, 0x91, 0xF8, 0x07, 0x22, + 0x90, 0xF8, 0x07, 0x22, 0x8F, 0xF8, 0x07, 0x22, + 0x8E, 0xF8, 0x07, 0x22, 0x8D, 0xF8, 0x07, 0x22, + 0x8C, 0xF8, 0x07, 0x22, 0x8B, 0xF8, 0x07, 0x22, + 0x8A, 0xF8, 0x07, 0x22, 0x89, 0xF8, 0x07, 0x22, + 0x88, 0xF8, 0x07, 0x22, 0x87, 0xF8, 0x07, 0x22, + 0x86, 0xF8, 0x07, 0x22, 0x85, 0xF8, 0x07, 0x22, + 0x84, 0xF8, 0x07, 0x22, 0x83, 0xF8, 0x07, 0x22, + 0x82, 0xF8, 0x07, 0x22, 0x81, 0xF8, 0x07, 0x22, + 0x80, 0xF8, 0x07, 0x22, 0x7F, 0xF8, 0x07, 0x22, + 0x7E, 0xF8, 0x07, 0x22, 0x7D, 0xF8, 0x07, 0x22, + 0x7C, 0xF8, 0x07, 0x22, 0x7B, 0xF8, 0x07, 0x22, + 0x7A, 0xF8, 0x07, 0x22, 0x79, 0xF8, 0x07, 0x22, + 0x78, 0xF8, 0x07, 0x22, 0x77, 0xF8, 0x07, 0x22, + 0x76, 0xF8, 0x07, 0x22, 0x75, 0xF8, 0x07, 0x22, + 0x74, 0xF8, 0x07, 0x22, 0x73, 0xF8, 0x07, 0x22, + 0x72, 0xF8, 0x07, 0x22, 0x71, 0xF8, 0x07, 0x22, + 0x70, 0xF8, 0x07, 0x22, 0x6F, 0xF8, 0x07, 0x22, + 0x6E, 0xF8, 0x07, 0x22, 0x6D, 0xF8, 0x07, 0x22, + 0x6C, 0xF8, 0x07, 0x22, 0x6B, 0xF8, 0x07, 0x22, + 0x6A, 0xF8, 0x07, 0x22, 0x69, 0xF8, 0x07, 0x22, + 0x68, 0xF8, 0x07, 0x22, 0x67, 0xF8, 0x07, 0x22, + 0x66, 0xF8, 0x07, 0x22, 0x65, 0xF8, 0x07, 0x22, + 0x64, 0xF8, 0x07, 0x22, 0x63, 0xF8, 0x07, 0x22, + 0x62, 0xF8, 0x07, 0x22, 0x61, 0xF8, 0x07, 0x22, + 0x60, 0xF8, 0x07, 0x22, 0x5F, 0xF8, 0x07, 0x22, + 0x5E, 0xF8, 0x07, 0x22, 0x5D, 0xF8, 0x07, 0x22, + 0x5C, 0xF8, 0x07, 0x22, 0x5B, 0xF8, 0x07, 0x22, + 0x5A, 0xF8, 0x07, 0x22, 0x59, 0xF8, 0x07, 0x22, + 0x58, 0xF8, 0x07, 0x22, 0x57, 0xF8, 0x07, 0x22, + 0x56, 0xF8, 0x07, 0x22, 0x55, 0xF8, 0x07, 0x22, + 0x54, 0xF8, 0x07, 0x22, 0x53, 0xF8, 0x07, 0x22, + 0x52, 0xF8, 0x07, 0x22, 0x51, 0xF8, 0x07, 0x22, + 0x50, 0xF8, 0x07, 0x22, 0x4F, 0xF8, 0x07, 0x22, + 0x4E, 0xF8, 0x07, 0x22, 0x4D, 0xF8, 0x07, 0x22, + 0x4C, 0xF8, 0x07, 0x22, 0x4B, 0xF8, 0x07, 0x22, + 0x4A, 0xF8, 0x07, 0x22, 0x49, 0xF8, 0x07, 0x22, + 0x48, 0xF8, 0x07, 0x22, 0x47, 0xF8, 0x07, 0x22, + 0x46, 0xF8, 0x07, 0x22, 0x45, 0xF8, 0x07, 0x22, + 0x44, 0xF8, 0x07, 0x22, 0x43, 0xF8, 0x07, 0x22, + 0x42, 0xF8, 0x07, 0x22, 0x41, 0xF8, 0x07, 0x22, + 0x40, 0xF8, 0x07, 0x22, 0x3F, 0xF8, 0x07, 0x22, + 0x3E, 0xF8, 0x07, 0x22, 0x3D, 0xF8, 0x07, 0x22, + 0x3C, 0xF8, 0x07, 0x22, 0x3B, 0xF8, 0x07, 0x22, + 0x3A, 0xF8, 0x07, 0x22, 0x39, 0xF8, 0x07, 0x22, + 0x38, 0xF8, 0x07, 0x22, 0x37, 0xF8, 0x07, 0x22, + 0x36, 0xF8, 0x07, 0x22, 0x35, 0xF8, 0x07, 0x22, + 0x34, 0xF8, 0x07, 0x22, 0x33, 0xF8, 0x07, 0x22, + 0x32, 0xF8, 0x07, 0x22, 0x31, 0xF8, 0x07, 0x22, + 0x30, 0xF8, 0x07, 0x22, 0x2F, 0xF8, 0x07, 0x22, + 0x2E, 0xF8, 0x07, 0x22, 0x2D, 0xF8, 0x07, 0x22, + 0x2C, 0xF8, 0x07, 0x22, 0x2B, 0xF8, 0x07, 0x22, + 0x2A, 0xF8, 0x07, 0x22, 0x29, 0xF8, 0x07, 0x22, + 0x28, 0xF8, 0x07, 0x22, 0x27, 0xF8, 0x07, 0x22, + 0x26, 0xF8, 0x07, 0x22, 0x25, 0xF8, 0x07, 0x22, + 0x24, 0xF8, 0x07, 0x22, 0x23, 0xF8, 0x07, 0x20, + 0x22, 0xF8, 0x07, 0x20, 0x21, 0xF8, 0x07, 0x20, + 0x20, 0xF8, 0x07, 0x20, 0x1F, 0xF8, 0x07, 0x20, + 0x1E, 0xF8, 0x07, 0x20, 0x1D, 0xF8, 0x07, 0x20, + 0x1C, 0xF8, 0x07, 0x20, 0x1C, 0xF8, 0x07, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD8, 0xF8, 0x27, 0x20, 0xD9, 0xF8, 0x27, 0x20, + 0xDA, 0xF8, 0x27, 0x20, 0xDB, 0xF8, 0x27, 0x20, + 0xDC, 0xF8, 0x27, 0x20, 0xDD, 0xF8, 0x27, 0x20, + 0xDE, 0xF8, 0x27, 0x20, 0xDF, 0xF8, 0x27, 0x20, + 0xE0, 0xF8, 0x27, 0x20, 0xE1, 0xF8, 0x27, 0x20, + 0xE2, 0xF8, 0x27, 0x20, 0xE3, 0xF8, 0x27, 0x20, + 0xE4, 0xF8, 0x27, 0x20, 0xE5, 0xF8, 0x27, 0x20, + 0xE6, 0xF8, 0x27, 0x20, 0xE7, 0xF8, 0x27, 0x20, + 0xE8, 0xF8, 0x27, 0x20, 0xE9, 0xF8, 0x27, 0x20, + 0xEA, 0xF8, 0x27, 0x20, 0xEB, 0xF8, 0x27, 0x20, + 0xEC, 0xF8, 0x27, 0x20, 0xED, 0xF8, 0x27, 0x20, + 0xEE, 0xF8, 0x27, 0x20, 0xEF, 0xF8, 0x27, 0x20, + 0xF0, 0xF8, 0x27, 0x20, 0xF1, 0xF8, 0x27, 0x20, + 0xF2, 0xF8, 0x27, 0x20, 0xF3, 0xF8, 0x27, 0x20, + 0xF4, 0xF8, 0x27, 0x20, 0xF5, 0xF8, 0x27, 0x20, + 0xF6, 0xF8, 0x27, 0x20, 0xF7, 0xF8, 0x27, 0x20, + 0xF8, 0xF8, 0x27, 0x20, 0xF9, 0xF8, 0x27, 0x20, + 0xFA, 0xF8, 0x27, 0x20, 0xFB, 0xF8, 0x27, 0x20, + 0xFC, 0xF8, 0x27, 0x20, 0xFD, 0xF8, 0x27, 0x20, + 0xFE, 0xF8, 0x27, 0x20, 0xFF, 0xF8, 0x27, 0x20, + 0x00, 0xF9, 0x27, 0x20, 0xD7, 0xF8, 0x27, 0x20, + 0x00, 0xF8, 0x27, 0x20, 0x01, 0xF8, 0x27, 0x20, + 0x02, 0xF8, 0x27, 0x20, 0x03, 0xF8, 0x27, 0x20, + 0x04, 0xF8, 0x27, 0x20, 0x05, 0xF8, 0x27, 0x20, + 0x06, 0xF8, 0x27, 0x20, 0x07, 0xF8, 0x27, 0x20, + 0x08, 0xF8, 0x27, 0x20, 0x09, 0xF8, 0x27, 0x20, + 0x0A, 0xF8, 0x27, 0x20, 0x0B, 0xF8, 0x27, 0x20, + 0x0C, 0xF8, 0x27, 0x20, 0x0D, 0xF8, 0x27, 0x20, + 0x0E, 0xF8, 0x27, 0x20, 0x0F, 0xF8, 0x27, 0x20, + 0x10, 0xF8, 0x27, 0x20, 0x11, 0xF8, 0x27, 0x20, + 0x12, 0xF8, 0x27, 0x20, 0x13, 0xF8, 0x27, 0x20, + 0x14, 0xF8, 0x27, 0x20, 0x15, 0xF8, 0x27, 0x20, + 0x15, 0xF8, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, + 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, + 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x04, 0x17, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0E, + 0x00, 0x0C, 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x05, + 0x00, 0x0E, 0x00, 0x10, 0x20, 0xFD, 0x00, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x03, 0x00, 0x09, 0x00, 0x04, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x08, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x0C, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x10, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x14, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xC8, 0x20, 0x04, 0x30, 0x04, 0x00, 0x00, + 0x00, 0x04, 0x05, 0x00, 0x0E, 0x00, 0x14, 0x20, + 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x83, 0x00, 0x03, 0x00, 0x09, 0x00, + 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x90, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x08, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x60, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, + 0x04, 0x15, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x28, 0x00, 0x00, }; static unsigned char vfs5011_init_17[] = { /* 117 B */ - 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0x00, 0x00, 0xFF, 0xF4, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0xF4, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x20, 0xBF, 0x02, 0x00, + 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xFF, 0x00, 0x00, 0xFF, 0xF4, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0xF4, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0xBF, 0x02, 0x00, }; static unsigned char vfs5011_init_18[] = { /* 2903 B */ - 0x02, 0xF0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x09, - 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, - 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, - 0x20, 0x04, 0x30, 0xE5, 0x03, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, - 0xEA, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x4C, 0x20, 0x04, 0x30, 0x0A, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, - 0x04, 0x30, 0x01, 0xDE, 0x01, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, - 0x30, 0x02, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, - 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x08, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x40, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x60, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, - 0x30, 0x30, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x90, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, - 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x30, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xD8, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, - 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x04, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, - 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, - 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, - 0x30, 0x00, 0x00, 0x74, 0x01, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, - 0x74, 0x01, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, - 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, - 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, - 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, - 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, - 0xFF, 0xF9, 0x87, 0x20, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x07, 0x20, - 0xBA, 0xF8, 0x07, 0x20, 0xB9, 0xF8, 0x07, 0x20, - 0xB8, 0xF8, 0x07, 0x20, 0xB7, 0xF8, 0x07, 0x20, - 0xB6, 0xF8, 0x07, 0x20, 0xB5, 0xF8, 0x07, 0x20, - 0xB4, 0xF8, 0x07, 0x20, 0xB3, 0xF8, 0x07, 0x20, - 0xB2, 0xF8, 0x07, 0x20, 0xB1, 0xF8, 0x07, 0x22, - 0xB0, 0xF8, 0x07, 0x22, 0xAF, 0xF8, 0x07, 0x22, - 0xAE, 0xF8, 0x07, 0x22, 0xAD, 0xF8, 0x07, 0x22, - 0xAC, 0xF8, 0x07, 0x22, 0xAB, 0xF8, 0x07, 0x22, - 0xAA, 0xF8, 0x07, 0x22, 0xA9, 0xF8, 0x07, 0x22, - 0xA8, 0xF8, 0x07, 0x22, 0xA7, 0xF8, 0x07, 0x22, - 0xA6, 0xF8, 0x07, 0x22, 0xA5, 0xF8, 0x07, 0x22, - 0xA4, 0xF8, 0x07, 0x22, 0xA3, 0xF8, 0x07, 0x22, - 0xA2, 0xF8, 0x07, 0x22, 0xA1, 0xF8, 0x07, 0x22, - 0xA0, 0xF8, 0x07, 0x22, 0x9F, 0xF8, 0x07, 0x22, - 0x9E, 0xF8, 0x07, 0x22, 0x9D, 0xF8, 0x07, 0x22, - 0x9C, 0xF8, 0x07, 0x22, 0x9B, 0xF8, 0x07, 0x22, - 0x9A, 0xF8, 0x07, 0x22, 0x99, 0xF8, 0x07, 0x22, - 0x98, 0xF8, 0x07, 0x22, 0x97, 0xF8, 0x07, 0x22, - 0x96, 0xF8, 0x07, 0x22, 0x95, 0xF8, 0x07, 0x22, - 0x94, 0xF8, 0x07, 0x22, 0x93, 0xF8, 0x07, 0x22, - 0x92, 0xF8, 0x07, 0x22, 0x91, 0xF8, 0x07, 0x22, - 0x90, 0xF8, 0x07, 0x22, 0x8F, 0xF8, 0x07, 0x22, - 0x8E, 0xF8, 0x07, 0x22, 0x8D, 0xF8, 0x07, 0x22, - 0x8C, 0xF8, 0x07, 0x22, 0x8B, 0xF8, 0x07, 0x22, - 0x8A, 0xF8, 0x07, 0x22, 0x89, 0xF8, 0x07, 0x22, - 0x88, 0xF8, 0x07, 0x22, 0x87, 0xF8, 0x07, 0x22, - 0x86, 0xF8, 0x07, 0x22, 0x85, 0xF8, 0x07, 0x22, - 0x84, 0xF8, 0x07, 0x22, 0x83, 0xF8, 0x07, 0x22, - 0x82, 0xF8, 0x07, 0x22, 0x81, 0xF8, 0x07, 0x22, - 0x80, 0xF8, 0x07, 0x22, 0x7F, 0xF8, 0x07, 0x22, - 0x7E, 0xF8, 0x07, 0x22, 0x7D, 0xF8, 0x07, 0x22, - 0x7C, 0xF8, 0x07, 0x22, 0x7B, 0xF8, 0x07, 0x22, - 0x7A, 0xF8, 0x07, 0x22, 0x79, 0xF8, 0x07, 0x22, - 0x78, 0xF8, 0x07, 0x22, 0x77, 0xF8, 0x07, 0x22, - 0x76, 0xF8, 0x07, 0x22, 0x75, 0xF8, 0x07, 0x22, - 0x74, 0xF8, 0x07, 0x22, 0x73, 0xF8, 0x07, 0x22, - 0x72, 0xF8, 0x07, 0x22, 0x71, 0xF8, 0x07, 0x22, - 0x70, 0xF8, 0x07, 0x22, 0x6F, 0xF8, 0x07, 0x22, - 0x6E, 0xF8, 0x07, 0x22, 0x6D, 0xF8, 0x07, 0x22, - 0x6C, 0xF8, 0x07, 0x22, 0x6B, 0xF8, 0x07, 0x22, - 0x6A, 0xF8, 0x07, 0x22, 0x69, 0xF8, 0x07, 0x22, - 0x68, 0xF8, 0x07, 0x22, 0x67, 0xF8, 0x07, 0x22, - 0x66, 0xF8, 0x07, 0x22, 0x65, 0xF8, 0x07, 0x22, - 0x64, 0xF8, 0x07, 0x22, 0x63, 0xF8, 0x07, 0x22, - 0x62, 0xF8, 0x07, 0x22, 0x61, 0xF8, 0x07, 0x22, - 0x60, 0xF8, 0x07, 0x22, 0x5F, 0xF8, 0x07, 0x22, - 0x5E, 0xF8, 0x07, 0x22, 0x5D, 0xF8, 0x07, 0x22, - 0x5C, 0xF8, 0x07, 0x22, 0x5B, 0xF8, 0x07, 0x22, - 0x5A, 0xF8, 0x07, 0x22, 0x59, 0xF8, 0x07, 0x22, - 0x58, 0xF8, 0x07, 0x22, 0x57, 0xF8, 0x07, 0x22, - 0x56, 0xF8, 0x07, 0x22, 0x55, 0xF8, 0x07, 0x22, - 0x54, 0xF8, 0x07, 0x22, 0x53, 0xF8, 0x07, 0x22, - 0x52, 0xF8, 0x07, 0x22, 0x51, 0xF8, 0x07, 0x22, - 0x50, 0xF8, 0x07, 0x22, 0x4F, 0xF8, 0x07, 0x22, - 0x4E, 0xF8, 0x07, 0x22, 0x4D, 0xF8, 0x07, 0x22, - 0x4C, 0xF8, 0x07, 0x22, 0x4B, 0xF8, 0x07, 0x22, - 0x4A, 0xF8, 0x07, 0x22, 0x49, 0xF8, 0x07, 0x22, - 0x48, 0xF8, 0x07, 0x22, 0x47, 0xF8, 0x07, 0x22, - 0x46, 0xF8, 0x07, 0x22, 0x45, 0xF8, 0x07, 0x22, - 0x44, 0xF8, 0x07, 0x22, 0x43, 0xF8, 0x07, 0x22, - 0x42, 0xF8, 0x07, 0x22, 0x41, 0xF8, 0x07, 0x22, - 0x40, 0xF8, 0x07, 0x22, 0x3F, 0xF8, 0x07, 0x22, - 0x3E, 0xF8, 0x07, 0x22, 0x3D, 0xF8, 0x07, 0x22, - 0x3C, 0xF8, 0x07, 0x22, 0x3B, 0xF8, 0x07, 0x22, - 0x3A, 0xF8, 0x07, 0x22, 0x39, 0xF8, 0x07, 0x22, - 0x38, 0xF8, 0x07, 0x22, 0x37, 0xF8, 0x07, 0x22, - 0x36, 0xF8, 0x07, 0x22, 0x35, 0xF8, 0x07, 0x22, - 0x34, 0xF8, 0x07, 0x22, 0x33, 0xF8, 0x07, 0x22, - 0x32, 0xF8, 0x07, 0x22, 0x31, 0xF8, 0x07, 0x22, - 0x30, 0xF8, 0x07, 0x22, 0x2F, 0xF8, 0x07, 0x22, - 0x2E, 0xF8, 0x07, 0x22, 0x2D, 0xF8, 0x07, 0x22, - 0x2C, 0xF8, 0x07, 0x22, 0x2B, 0xF8, 0x07, 0x22, - 0x2A, 0xF8, 0x07, 0x22, 0x29, 0xF8, 0x07, 0x22, - 0x28, 0xF8, 0x07, 0x22, 0x27, 0xF8, 0x07, 0x22, - 0x26, 0xF8, 0x07, 0x22, 0x25, 0xF8, 0x07, 0x22, - 0x24, 0xF8, 0x07, 0x22, 0x23, 0xF8, 0x07, 0x20, - 0x22, 0xF8, 0x07, 0x20, 0x21, 0xF8, 0x07, 0x20, - 0x20, 0xF8, 0x07, 0x20, 0x1F, 0xF8, 0x07, 0x20, - 0x1E, 0xF8, 0x07, 0x20, 0x1D, 0xF8, 0x07, 0x20, - 0x1C, 0xF8, 0x07, 0x20, 0x1C, 0xF8, 0x07, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD8, 0xF8, 0x27, 0x20, 0xD9, 0xF8, 0x27, 0x20, - 0xDA, 0xF8, 0x27, 0x20, 0xDB, 0xF8, 0x27, 0x20, - 0xDC, 0xF8, 0x27, 0x20, 0xDD, 0xF8, 0x27, 0x20, - 0xDE, 0xF8, 0x27, 0x20, 0xDF, 0xF8, 0x27, 0x20, - 0xE0, 0xF8, 0x27, 0x20, 0xE1, 0xF8, 0x27, 0x20, - 0xE2, 0xF8, 0x27, 0x20, 0xE3, 0xF8, 0x27, 0x20, - 0xE4, 0xF8, 0x27, 0x20, 0xE5, 0xF8, 0x27, 0x20, - 0xE6, 0xF8, 0x27, 0x20, 0xE7, 0xF8, 0x27, 0x20, - 0xE8, 0xF8, 0x27, 0x20, 0xE9, 0xF8, 0x27, 0x20, - 0xEA, 0xF8, 0x27, 0x20, 0xEB, 0xF8, 0x27, 0x20, - 0xEC, 0xF8, 0x27, 0x20, 0xED, 0xF8, 0x27, 0x20, - 0xEE, 0xF8, 0x27, 0x20, 0xEF, 0xF8, 0x27, 0x20, - 0xF0, 0xF8, 0x27, 0x20, 0xF1, 0xF8, 0x27, 0x20, - 0xF2, 0xF8, 0x27, 0x20, 0xF3, 0xF8, 0x27, 0x20, - 0xF4, 0xF8, 0x27, 0x20, 0xF5, 0xF8, 0x27, 0x20, - 0xF6, 0xF8, 0x27, 0x20, 0xF7, 0xF8, 0x27, 0x20, - 0xF8, 0xF8, 0x27, 0x20, 0xF9, 0xF8, 0x27, 0x20, - 0xFA, 0xF8, 0x27, 0x20, 0xFB, 0xF8, 0x27, 0x20, - 0xFC, 0xF8, 0x27, 0x20, 0xFD, 0xF8, 0x27, 0x20, - 0xFE, 0xF8, 0x27, 0x20, 0xFF, 0xF8, 0x27, 0x20, - 0x00, 0xF9, 0x27, 0x20, 0xD7, 0xF8, 0x27, 0x20, - 0x00, 0xF8, 0x27, 0x20, 0x01, 0xF8, 0x27, 0x20, - 0x02, 0xF8, 0x27, 0x20, 0x03, 0xF8, 0x27, 0x20, - 0x04, 0xF8, 0x27, 0x20, 0x05, 0xF8, 0x27, 0x20, - 0x06, 0xF8, 0x27, 0x20, 0x07, 0xF8, 0x27, 0x20, - 0x08, 0xF8, 0x27, 0x20, 0x09, 0xF8, 0x27, 0x20, - 0x0A, 0xF8, 0x27, 0x20, 0x0B, 0xF8, 0x27, 0x20, - 0x0C, 0xF8, 0x27, 0x20, 0x0D, 0xF8, 0x27, 0x20, - 0x0E, 0xF8, 0x27, 0x20, 0x0F, 0xF8, 0x27, 0x20, - 0x10, 0xF8, 0x27, 0x20, 0x11, 0xF8, 0x27, 0x20, - 0x12, 0xF8, 0x27, 0x20, 0x13, 0xF8, 0x27, 0x20, - 0x14, 0xF8, 0x27, 0x20, 0x15, 0xF8, 0x27, 0x20, - 0x15, 0xF8, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, - 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, - 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, - 0x04, 0x05, 0x00, 0x0E, 0x00, 0x0C, 0x20, 0xFD, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x08, 0x00, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x10, - 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, 0x00, 0x09, - 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, - 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, - 0x0E, 0x00, 0x14, 0x20, 0xFF, 0xFF, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00, - 0x03, 0x00, 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x88, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x90, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x94, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x20, - 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x60, 0x21, 0x04, 0x30, - 0x08, 0x00, 0x00, 0x00, 0x04, 0x15, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x28, 0x00, - 0x00, 0x18, 0x00, 0x52, 0x01, 0x08, 0x00, 0x05, - 0x00, 0x0A, 0x00, 0xFA, 0x00, 0x1E, 0x00, 0xC8, - 0x00, 0x00, 0x00, 0x9F, 0x00, 0x38, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x03, 0xFF, 0xF9, 0xFD, 0xFE, 0xFE, 0x00, 0xFD, - 0x02, 0x03, 0x02, 0x01, 0x01, 0xFF, 0x03, 0x06, - 0x0C, 0x08, 0x08, 0x0C, 0x06, 0x0A, 0x0B, 0x06, - 0x0B, 0x0A, 0x0C, 0x0A, 0x0A, 0x07, 0x02, 0x05, - 0x07, 0x06, 0x0A, 0x09, 0x09, 0x0C, 0x0C, 0x11, - 0x0B, 0x0D, 0x08, 0x07, 0x09, 0x09, 0x09, 0x08, - 0x06, 0x09, 0xFE, 0xFF, 0xFF, 0x01, 0x06, 0x01, - 0xFD, 0xFB, 0x00, 0x01, 0x04, 0x01, 0x02, 0x05, - 0x04, 0x00, 0x02, 0x02, 0x05, 0x07, 0x05, 0x03, - 0x05, 0x02, 0x0A, 0x06, 0x03, 0x04, 0x00, 0x01, - 0x02, 0x04, 0x01, 0x01, 0xFA, 0xF7, 0xFA, 0xF9, - 0xF6, 0xF7, 0xFD, 0xFE, 0x02, 0xFE, 0xFC, 0xF7, - 0xF9, 0xFB, 0xF7, 0xFB, 0xF5, 0xF8, 0xF8, 0xF9, - 0xEF, 0xEE, 0xF2, 0xEF, 0xF0, 0xED, 0xF2, 0xF7, - 0xF9, 0xFA, 0xF6, 0xF6, 0xF5, 0xF4, 0xF3, 0xEF, - 0xF1, 0xF5, 0xF4, 0xF1, 0xF5, 0xFA, 0xF8, 0xFA, - 0xF9, 0xFA, 0xFE, 0x01, 0x02, 0xFE, 0xFE, 0x03, - 0x01, 0xFC, 0xF9, 0xF7, 0xF6, 0xF4, 0xF9, 0xF7, - 0xF7, 0xF5, 0xF7, 0xFA, 0xFB, 0x00, 0xFC, 0xFD, - 0xFD, 0xF6, 0xF2, 0xF4, 0xED, 0xDC, 0xCE, 0xFF, - 0x05, 0x07, 0x08, 0x0E, 0x0E, 0x0F, 0x0A, 0x0C, - 0x06, 0x05, 0x05, 0xF6, 0xF2, 0xF1, 0xEF, 0xF4, - 0xF6, 0xF4, 0xF5, 0xF6, 0xF7, 0xF5, 0xF8, 0xF8, - 0xF8, 0xF2, 0xF7, 0xF3, 0xF0, 0xF3, 0xF5, 0xFD, - 0xFB, 0xFC, 0xF9, 0xF9, 0xFC, 0xFA, 0xF8, 0xFD, - 0x0B, 0x1C, 0x17, 0x13, 0x14, 0x0F, 0x0D, 0x0C, - 0x0B, 0x0B, 0x0F, 0x0C, 0x0E, 0x10, 0x0E, 0x11, - 0x12, 0x14, 0x1C, 0x1C, 0x20, 0x20, 0x24, 0xF4, - 0xF6, 0xF4, 0xF5, 0xF6, 0xF7, 0xF5, 0xF8, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x02, 0xF0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, + 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, + 0x20, 0x04, 0x30, 0xE5, 0x03, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, + 0xEA, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x4C, 0x20, 0x04, 0x30, 0x0A, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, + 0x04, 0x30, 0x01, 0xDE, 0x01, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, + 0x30, 0x02, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, + 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x08, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x40, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x60, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x90, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, + 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x30, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xD8, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, + 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x04, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, + 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, + 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, + 0x30, 0x00, 0x00, 0x74, 0x01, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, + 0x74, 0x01, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, + 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, + 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, + 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, + 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, + 0xFF, 0xF9, 0x87, 0x20, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x07, 0x20, + 0xBA, 0xF8, 0x07, 0x20, 0xB9, 0xF8, 0x07, 0x20, + 0xB8, 0xF8, 0x07, 0x20, 0xB7, 0xF8, 0x07, 0x20, + 0xB6, 0xF8, 0x07, 0x20, 0xB5, 0xF8, 0x07, 0x20, + 0xB4, 0xF8, 0x07, 0x20, 0xB3, 0xF8, 0x07, 0x20, + 0xB2, 0xF8, 0x07, 0x20, 0xB1, 0xF8, 0x07, 0x22, + 0xB0, 0xF8, 0x07, 0x22, 0xAF, 0xF8, 0x07, 0x22, + 0xAE, 0xF8, 0x07, 0x22, 0xAD, 0xF8, 0x07, 0x22, + 0xAC, 0xF8, 0x07, 0x22, 0xAB, 0xF8, 0x07, 0x22, + 0xAA, 0xF8, 0x07, 0x22, 0xA9, 0xF8, 0x07, 0x22, + 0xA8, 0xF8, 0x07, 0x22, 0xA7, 0xF8, 0x07, 0x22, + 0xA6, 0xF8, 0x07, 0x22, 0xA5, 0xF8, 0x07, 0x22, + 0xA4, 0xF8, 0x07, 0x22, 0xA3, 0xF8, 0x07, 0x22, + 0xA2, 0xF8, 0x07, 0x22, 0xA1, 0xF8, 0x07, 0x22, + 0xA0, 0xF8, 0x07, 0x22, 0x9F, 0xF8, 0x07, 0x22, + 0x9E, 0xF8, 0x07, 0x22, 0x9D, 0xF8, 0x07, 0x22, + 0x9C, 0xF8, 0x07, 0x22, 0x9B, 0xF8, 0x07, 0x22, + 0x9A, 0xF8, 0x07, 0x22, 0x99, 0xF8, 0x07, 0x22, + 0x98, 0xF8, 0x07, 0x22, 0x97, 0xF8, 0x07, 0x22, + 0x96, 0xF8, 0x07, 0x22, 0x95, 0xF8, 0x07, 0x22, + 0x94, 0xF8, 0x07, 0x22, 0x93, 0xF8, 0x07, 0x22, + 0x92, 0xF8, 0x07, 0x22, 0x91, 0xF8, 0x07, 0x22, + 0x90, 0xF8, 0x07, 0x22, 0x8F, 0xF8, 0x07, 0x22, + 0x8E, 0xF8, 0x07, 0x22, 0x8D, 0xF8, 0x07, 0x22, + 0x8C, 0xF8, 0x07, 0x22, 0x8B, 0xF8, 0x07, 0x22, + 0x8A, 0xF8, 0x07, 0x22, 0x89, 0xF8, 0x07, 0x22, + 0x88, 0xF8, 0x07, 0x22, 0x87, 0xF8, 0x07, 0x22, + 0x86, 0xF8, 0x07, 0x22, 0x85, 0xF8, 0x07, 0x22, + 0x84, 0xF8, 0x07, 0x22, 0x83, 0xF8, 0x07, 0x22, + 0x82, 0xF8, 0x07, 0x22, 0x81, 0xF8, 0x07, 0x22, + 0x80, 0xF8, 0x07, 0x22, 0x7F, 0xF8, 0x07, 0x22, + 0x7E, 0xF8, 0x07, 0x22, 0x7D, 0xF8, 0x07, 0x22, + 0x7C, 0xF8, 0x07, 0x22, 0x7B, 0xF8, 0x07, 0x22, + 0x7A, 0xF8, 0x07, 0x22, 0x79, 0xF8, 0x07, 0x22, + 0x78, 0xF8, 0x07, 0x22, 0x77, 0xF8, 0x07, 0x22, + 0x76, 0xF8, 0x07, 0x22, 0x75, 0xF8, 0x07, 0x22, + 0x74, 0xF8, 0x07, 0x22, 0x73, 0xF8, 0x07, 0x22, + 0x72, 0xF8, 0x07, 0x22, 0x71, 0xF8, 0x07, 0x22, + 0x70, 0xF8, 0x07, 0x22, 0x6F, 0xF8, 0x07, 0x22, + 0x6E, 0xF8, 0x07, 0x22, 0x6D, 0xF8, 0x07, 0x22, + 0x6C, 0xF8, 0x07, 0x22, 0x6B, 0xF8, 0x07, 0x22, + 0x6A, 0xF8, 0x07, 0x22, 0x69, 0xF8, 0x07, 0x22, + 0x68, 0xF8, 0x07, 0x22, 0x67, 0xF8, 0x07, 0x22, + 0x66, 0xF8, 0x07, 0x22, 0x65, 0xF8, 0x07, 0x22, + 0x64, 0xF8, 0x07, 0x22, 0x63, 0xF8, 0x07, 0x22, + 0x62, 0xF8, 0x07, 0x22, 0x61, 0xF8, 0x07, 0x22, + 0x60, 0xF8, 0x07, 0x22, 0x5F, 0xF8, 0x07, 0x22, + 0x5E, 0xF8, 0x07, 0x22, 0x5D, 0xF8, 0x07, 0x22, + 0x5C, 0xF8, 0x07, 0x22, 0x5B, 0xF8, 0x07, 0x22, + 0x5A, 0xF8, 0x07, 0x22, 0x59, 0xF8, 0x07, 0x22, + 0x58, 0xF8, 0x07, 0x22, 0x57, 0xF8, 0x07, 0x22, + 0x56, 0xF8, 0x07, 0x22, 0x55, 0xF8, 0x07, 0x22, + 0x54, 0xF8, 0x07, 0x22, 0x53, 0xF8, 0x07, 0x22, + 0x52, 0xF8, 0x07, 0x22, 0x51, 0xF8, 0x07, 0x22, + 0x50, 0xF8, 0x07, 0x22, 0x4F, 0xF8, 0x07, 0x22, + 0x4E, 0xF8, 0x07, 0x22, 0x4D, 0xF8, 0x07, 0x22, + 0x4C, 0xF8, 0x07, 0x22, 0x4B, 0xF8, 0x07, 0x22, + 0x4A, 0xF8, 0x07, 0x22, 0x49, 0xF8, 0x07, 0x22, + 0x48, 0xF8, 0x07, 0x22, 0x47, 0xF8, 0x07, 0x22, + 0x46, 0xF8, 0x07, 0x22, 0x45, 0xF8, 0x07, 0x22, + 0x44, 0xF8, 0x07, 0x22, 0x43, 0xF8, 0x07, 0x22, + 0x42, 0xF8, 0x07, 0x22, 0x41, 0xF8, 0x07, 0x22, + 0x40, 0xF8, 0x07, 0x22, 0x3F, 0xF8, 0x07, 0x22, + 0x3E, 0xF8, 0x07, 0x22, 0x3D, 0xF8, 0x07, 0x22, + 0x3C, 0xF8, 0x07, 0x22, 0x3B, 0xF8, 0x07, 0x22, + 0x3A, 0xF8, 0x07, 0x22, 0x39, 0xF8, 0x07, 0x22, + 0x38, 0xF8, 0x07, 0x22, 0x37, 0xF8, 0x07, 0x22, + 0x36, 0xF8, 0x07, 0x22, 0x35, 0xF8, 0x07, 0x22, + 0x34, 0xF8, 0x07, 0x22, 0x33, 0xF8, 0x07, 0x22, + 0x32, 0xF8, 0x07, 0x22, 0x31, 0xF8, 0x07, 0x22, + 0x30, 0xF8, 0x07, 0x22, 0x2F, 0xF8, 0x07, 0x22, + 0x2E, 0xF8, 0x07, 0x22, 0x2D, 0xF8, 0x07, 0x22, + 0x2C, 0xF8, 0x07, 0x22, 0x2B, 0xF8, 0x07, 0x22, + 0x2A, 0xF8, 0x07, 0x22, 0x29, 0xF8, 0x07, 0x22, + 0x28, 0xF8, 0x07, 0x22, 0x27, 0xF8, 0x07, 0x22, + 0x26, 0xF8, 0x07, 0x22, 0x25, 0xF8, 0x07, 0x22, + 0x24, 0xF8, 0x07, 0x22, 0x23, 0xF8, 0x07, 0x20, + 0x22, 0xF8, 0x07, 0x20, 0x21, 0xF8, 0x07, 0x20, + 0x20, 0xF8, 0x07, 0x20, 0x1F, 0xF8, 0x07, 0x20, + 0x1E, 0xF8, 0x07, 0x20, 0x1D, 0xF8, 0x07, 0x20, + 0x1C, 0xF8, 0x07, 0x20, 0x1C, 0xF8, 0x07, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD8, 0xF8, 0x27, 0x20, 0xD9, 0xF8, 0x27, 0x20, + 0xDA, 0xF8, 0x27, 0x20, 0xDB, 0xF8, 0x27, 0x20, + 0xDC, 0xF8, 0x27, 0x20, 0xDD, 0xF8, 0x27, 0x20, + 0xDE, 0xF8, 0x27, 0x20, 0xDF, 0xF8, 0x27, 0x20, + 0xE0, 0xF8, 0x27, 0x20, 0xE1, 0xF8, 0x27, 0x20, + 0xE2, 0xF8, 0x27, 0x20, 0xE3, 0xF8, 0x27, 0x20, + 0xE4, 0xF8, 0x27, 0x20, 0xE5, 0xF8, 0x27, 0x20, + 0xE6, 0xF8, 0x27, 0x20, 0xE7, 0xF8, 0x27, 0x20, + 0xE8, 0xF8, 0x27, 0x20, 0xE9, 0xF8, 0x27, 0x20, + 0xEA, 0xF8, 0x27, 0x20, 0xEB, 0xF8, 0x27, 0x20, + 0xEC, 0xF8, 0x27, 0x20, 0xED, 0xF8, 0x27, 0x20, + 0xEE, 0xF8, 0x27, 0x20, 0xEF, 0xF8, 0x27, 0x20, + 0xF0, 0xF8, 0x27, 0x20, 0xF1, 0xF8, 0x27, 0x20, + 0xF2, 0xF8, 0x27, 0x20, 0xF3, 0xF8, 0x27, 0x20, + 0xF4, 0xF8, 0x27, 0x20, 0xF5, 0xF8, 0x27, 0x20, + 0xF6, 0xF8, 0x27, 0x20, 0xF7, 0xF8, 0x27, 0x20, + 0xF8, 0xF8, 0x27, 0x20, 0xF9, 0xF8, 0x27, 0x20, + 0xFA, 0xF8, 0x27, 0x20, 0xFB, 0xF8, 0x27, 0x20, + 0xFC, 0xF8, 0x27, 0x20, 0xFD, 0xF8, 0x27, 0x20, + 0xFE, 0xF8, 0x27, 0x20, 0xFF, 0xF8, 0x27, 0x20, + 0x00, 0xF9, 0x27, 0x20, 0xD7, 0xF8, 0x27, 0x20, + 0x00, 0xF8, 0x27, 0x20, 0x01, 0xF8, 0x27, 0x20, + 0x02, 0xF8, 0x27, 0x20, 0x03, 0xF8, 0x27, 0x20, + 0x04, 0xF8, 0x27, 0x20, 0x05, 0xF8, 0x27, 0x20, + 0x06, 0xF8, 0x27, 0x20, 0x07, 0xF8, 0x27, 0x20, + 0x08, 0xF8, 0x27, 0x20, 0x09, 0xF8, 0x27, 0x20, + 0x0A, 0xF8, 0x27, 0x20, 0x0B, 0xF8, 0x27, 0x20, + 0x0C, 0xF8, 0x27, 0x20, 0x0D, 0xF8, 0x27, 0x20, + 0x0E, 0xF8, 0x27, 0x20, 0x0F, 0xF8, 0x27, 0x20, + 0x10, 0xF8, 0x27, 0x20, 0x11, 0xF8, 0x27, 0x20, + 0x12, 0xF8, 0x27, 0x20, 0x13, 0xF8, 0x27, 0x20, + 0x14, 0xF8, 0x27, 0x20, 0x15, 0xF8, 0x27, 0x20, + 0x15, 0xF8, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, + 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, + 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x04, 0x05, 0x00, 0x0E, 0x00, 0x0C, 0x20, 0xFD, + 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x08, 0x00, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x10, + 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x00, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, + 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, + 0x0E, 0x00, 0x14, 0x20, 0xFF, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00, + 0x03, 0x00, 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x88, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x90, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x94, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x20, + 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x60, 0x21, 0x04, 0x30, + 0x08, 0x00, 0x00, 0x00, 0x04, 0x15, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x28, 0x00, + 0x00, 0x18, 0x00, 0x52, 0x01, 0x08, 0x00, 0x05, + 0x00, 0x0A, 0x00, 0xFA, 0x00, 0x1E, 0x00, 0xC8, + 0x00, 0x00, 0x00, 0x9F, 0x00, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x03, 0xFF, 0xF9, 0xFD, 0xFE, 0xFE, 0x00, 0xFD, + 0x02, 0x03, 0x02, 0x01, 0x01, 0xFF, 0x03, 0x06, + 0x0C, 0x08, 0x08, 0x0C, 0x06, 0x0A, 0x0B, 0x06, + 0x0B, 0x0A, 0x0C, 0x0A, 0x0A, 0x07, 0x02, 0x05, + 0x07, 0x06, 0x0A, 0x09, 0x09, 0x0C, 0x0C, 0x11, + 0x0B, 0x0D, 0x08, 0x07, 0x09, 0x09, 0x09, 0x08, + 0x06, 0x09, 0xFE, 0xFF, 0xFF, 0x01, 0x06, 0x01, + 0xFD, 0xFB, 0x00, 0x01, 0x04, 0x01, 0x02, 0x05, + 0x04, 0x00, 0x02, 0x02, 0x05, 0x07, 0x05, 0x03, + 0x05, 0x02, 0x0A, 0x06, 0x03, 0x04, 0x00, 0x01, + 0x02, 0x04, 0x01, 0x01, 0xFA, 0xF7, 0xFA, 0xF9, + 0xF6, 0xF7, 0xFD, 0xFE, 0x02, 0xFE, 0xFC, 0xF7, + 0xF9, 0xFB, 0xF7, 0xFB, 0xF5, 0xF8, 0xF8, 0xF9, + 0xEF, 0xEE, 0xF2, 0xEF, 0xF0, 0xED, 0xF2, 0xF7, + 0xF9, 0xFA, 0xF6, 0xF6, 0xF5, 0xF4, 0xF3, 0xEF, + 0xF1, 0xF5, 0xF4, 0xF1, 0xF5, 0xFA, 0xF8, 0xFA, + 0xF9, 0xFA, 0xFE, 0x01, 0x02, 0xFE, 0xFE, 0x03, + 0x01, 0xFC, 0xF9, 0xF7, 0xF6, 0xF4, 0xF9, 0xF7, + 0xF7, 0xF5, 0xF7, 0xFA, 0xFB, 0x00, 0xFC, 0xFD, + 0xFD, 0xF6, 0xF2, 0xF4, 0xED, 0xDC, 0xCE, 0xFF, + 0x05, 0x07, 0x08, 0x0E, 0x0E, 0x0F, 0x0A, 0x0C, + 0x06, 0x05, 0x05, 0xF6, 0xF2, 0xF1, 0xEF, 0xF4, + 0xF6, 0xF4, 0xF5, 0xF6, 0xF7, 0xF5, 0xF8, 0xF8, + 0xF8, 0xF2, 0xF7, 0xF3, 0xF0, 0xF3, 0xF5, 0xFD, + 0xFB, 0xFC, 0xF9, 0xF9, 0xFC, 0xFA, 0xF8, 0xFD, + 0x0B, 0x1C, 0x17, 0x13, 0x14, 0x0F, 0x0D, 0x0C, + 0x0B, 0x0B, 0x0F, 0x0C, 0x0E, 0x10, 0x0E, 0x11, + 0x12, 0x14, 0x1C, 0x1C, 0x20, 0x20, 0x24, 0xF4, + 0xF6, 0xF4, 0xF5, 0xF6, 0xF7, 0xF5, 0xF8, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, }; static unsigned char vfs5011_cmd_04[] = { /* 1 B */ - 0x04, + 0x04, }; static unsigned char vfs5011_prepare_00[] = { /* 578 B */ - 0x06, 0x9C, 0xF1, 0x9D, 0x71, 0xC3, 0x13, 0xDF, - 0x5F, 0xE4, 0x7A, 0x1F, 0xC7, 0x17, 0x53, 0x9A, - 0x1A, 0xA1, 0xD7, 0xB6, 0x6E, 0xBE, 0xDF, 0x1F, - 0x9F, 0x44, 0x42, 0x22, 0xFA, 0x2A, 0x6A, 0xAB, - 0x2B, 0xF0, 0x56, 0x39, 0xE3, 0x7B, 0x53, 0x9A, - 0x1A, 0xA1, 0xDB, 0xBA, 0x62, 0xB2, 0xE4, 0x65, - 0xE5, 0xDB, 0x68, 0x04, 0x79, 0x98, 0xDE, 0x8F, - 0x23, 0xFB, 0xEC, 0xAD, 0x76, 0xCA, 0xA2, 0xEB, - 0x61, 0x38, 0xC7, 0xAB, 0x6E, 0x2E, 0x78, 0xF9, - 0x79, 0x13, 0x8A, 0xE5, 0x90, 0x22, 0x63, 0x8D, - 0x0E, 0x93, 0x25, 0x49, 0x5A, 0xC8, 0xA3, 0xD8, - 0x7E, 0xAE, 0x12, 0xF6, 0x2C, 0x1C, 0xFC, 0x48, - 0x4F, 0x0E, 0x48, 0x22, 0xFB, 0x4B, 0xCE, 0x7E, - 0xDB, 0x2D, 0x91, 0xE0, 0xC8, 0x78, 0x2E, 0xAF, - 0x2F, 0xD4, 0x03, 0x6F, 0x12, 0x59, 0xC6, 0x26, - 0x40, 0x88, 0x2E, 0x62, 0xBA, 0x06, 0x6C, 0xC9, - 0x7A, 0x84, 0x93, 0xCF, 0x14, 0x15, 0x44, 0x87, - 0xE2, 0x09, 0x97, 0xE6, 0xCE, 0x7E, 0x28, 0xA9, - 0x29, 0x53, 0xD7, 0xB8, 0xD1, 0x53, 0x30, 0x15, - 0x6E, 0x95, 0x3E, 0xA2, 0x7A, 0xCA, 0x9C, 0x1D, - 0x9D, 0xEB, 0x5F, 0x15, 0xEF, 0x48, 0x34, 0xCC, - 0xCB, 0x02, 0xA6, 0xD6, 0xA7, 0x80, 0xF2, 0x3F, - 0x7E, 0x96, 0x23, 0xAE, 0x42, 0xF1, 0x29, 0xF5, - 0xAD, 0x5A, 0x35, 0x57, 0x36, 0xAA, 0xAF, 0x97, - 0xE8, 0x1E, 0xA2, 0xD3, 0xFB, 0x4B, 0x1D, 0x9C, - 0x1C, 0x06, 0x84, 0xEB, 0x9E, 0x2C, 0xD4, 0x18, - 0x94, 0x44, 0x7E, 0x4B, 0x12, 0x91, 0xF2, 0x8B, - 0x07, 0x45, 0xDB, 0x52, 0xBB, 0x2E, 0x53, 0x63, - 0xE3, 0x38, 0xB8, 0x95, 0x4D, 0x9B, 0xCF, 0x07, - 0x05, 0xDD, 0x4C, 0xE2, 0x39, 0xAF, 0xA9, 0x51, - 0xDB, 0xAD, 0x19, 0xC8, 0x13, 0x6E, 0x0A, 0x2F, - 0xEA, 0x12, 0xB9, 0x25, 0x55, 0xB6, 0x64, 0x04, - 0x7F, 0x14, 0x6E, 0x12, 0x08, 0xFB, 0xBD, 0xBD, - 0x1D, 0xC6, 0xE2, 0x84, 0x50, 0x20, 0x60, 0xA0, - 0x90, 0xD2, 0x74, 0x8A, 0x18, 0xA4, 0xD9, 0xE9, - 0x69, 0xB2, 0x1E, 0x73, 0xAB, 0x1B, 0x7B, 0xBB, - 0x3B, 0xE0, 0x42, 0x23, 0xF9, 0x29, 0x49, 0x89, - 0x09, 0xD2, 0x4C, 0x29, 0xF1, 0x21, 0x65, 0xAC, - 0x2C, 0x97, 0x30, 0x6C, 0xB4, 0x04, 0xF4, 0x3D, - 0xBD, 0x06, 0xA0, 0xC6, 0x1E, 0xCE, 0x7E, 0xB3, - 0x33, 0x88, 0x2E, 0x43, 0x9B, 0x2B, 0x37, 0xF0, - 0x70, 0xCB, 0x91, 0xF1, 0x2B, 0xFB, 0x8B, 0x48, - 0xCA, 0x39, 0x97, 0xFB, 0x21, 0xB9, 0xCD, 0x0E, - 0x8C, 0x7F, 0x8D, 0xEC, 0x36, 0xE6, 0xEA, 0x27, - 0xA5, 0x1E, 0x40, 0x2A, 0xF2, 0x22, 0xCA, 0x07, - 0x85, 0x3E, 0xC8, 0xAE, 0x76, 0xA6, 0xF0, 0x71, - 0xF1, 0xAB, 0x6B, 0x04, 0x6D, 0xA9, 0xCA, 0x06, - 0x2C, 0x66, 0xA5, 0xCA, 0xB0, 0x4B, 0x2B, 0x62, - 0xEB, 0xD5, 0x61, 0x0D, 0xF0, 0x46, 0x26, 0xC3, - 0x44, 0x9F, 0x0C, 0x63, 0xBB, 0xAA, 0xBD, 0x7E, - 0xF2, 0x74, 0x00, 0x66, 0x2B, 0x7A, 0x62, 0xA1, - 0x07, 0x80, 0x33, 0x8D, 0x1F, 0xF7, 0x45, 0xCB, - 0x5E, 0x24, 0xEB, 0x84, 0xED, 0x27, 0x44, 0x61, - 0xFF, 0x0C, 0xA7, 0x3B, 0xE3, 0x53, 0x05, 0x84, - 0x04, 0xEE, 0x23, 0x4C, 0xB5, 0x79, 0x1A, 0xF3, - 0xA0, 0x66, 0x20, 0x4C, 0x94, 0x24, 0x72, 0xF3, - 0x73, 0x39, 0xF8, 0x97, 0xDD, 0x64, 0x54, 0xF2, - 0x6B, 0xBA, 0xAD, 0xBC, 0x67, 0x66, 0x78, 0xBB, - 0x5E, 0x6D, 0xFB, 0x8A, 0xA2, 0x74, 0x3D, 0xF5, - 0xD4, 0x72, 0xC7, 0x1A, 0xBD, 0x0E, 0x0B, 0x2C, - 0x8C, 0x4A, 0x0C, 0x60, 0xB8, 0x08, 0x5E, 0xDF, - 0x5F, 0x05, 0x33, 0x5C, 0xB5, 0x7E, 0x1D, 0xFC, - 0xFD, 0x25, 0xBA, 0x95, 0xC4, 0xA7, 0xDA, 0xEA, - 0x6A, 0xB1, 0x31, 0x1C, 0xC4, 0xE5, 0x07, 0xC4, - 0xC5, 0x9D, 0x28, 0xCD, 0x3C, 0xE9, 0x89, 0x49, - 0xD4, 0xFF, 0x7F, 0x52, 0x8A, 0x9B, 0x7F, 0xBC, - 0x8E, 0xF5, 0xCF, 0x0B, 0xD9, 0x49, 0x48, 0x88, - 0x80, 0x71, 0x7D, 0xAB, 0xEF, 0x47, 0x2B, 0xF7, - 0x7B, 0x2D, 0x79, 0x3F, 0xCF, 0xBF, 0xFF, 0x3F, - 0x6D, 0xF8, 0x42, 0xEC, 0x7F, 0xE8, 0xED, 0x42, - 0xE6, 0x1D, 0x4D, 0x32, 0xFA, 0x6A, 0x0A, 0xD7, - 0xA7, 0x7C, 0xCB, 0xA7, 0x7B, 0xCB, 0xBF, 0x71, - 0xF3, 0x48, + 0x06, 0x9C, 0xF1, 0x9D, 0x71, 0xC3, 0x13, 0xDF, + 0x5F, 0xE4, 0x7A, 0x1F, 0xC7, 0x17, 0x53, 0x9A, + 0x1A, 0xA1, 0xD7, 0xB6, 0x6E, 0xBE, 0xDF, 0x1F, + 0x9F, 0x44, 0x42, 0x22, 0xFA, 0x2A, 0x6A, 0xAB, + 0x2B, 0xF0, 0x56, 0x39, 0xE3, 0x7B, 0x53, 0x9A, + 0x1A, 0xA1, 0xDB, 0xBA, 0x62, 0xB2, 0xE4, 0x65, + 0xE5, 0xDB, 0x68, 0x04, 0x79, 0x98, 0xDE, 0x8F, + 0x23, 0xFB, 0xEC, 0xAD, 0x76, 0xCA, 0xA2, 0xEB, + 0x61, 0x38, 0xC7, 0xAB, 0x6E, 0x2E, 0x78, 0xF9, + 0x79, 0x13, 0x8A, 0xE5, 0x90, 0x22, 0x63, 0x8D, + 0x0E, 0x93, 0x25, 0x49, 0x5A, 0xC8, 0xA3, 0xD8, + 0x7E, 0xAE, 0x12, 0xF6, 0x2C, 0x1C, 0xFC, 0x48, + 0x4F, 0x0E, 0x48, 0x22, 0xFB, 0x4B, 0xCE, 0x7E, + 0xDB, 0x2D, 0x91, 0xE0, 0xC8, 0x78, 0x2E, 0xAF, + 0x2F, 0xD4, 0x03, 0x6F, 0x12, 0x59, 0xC6, 0x26, + 0x40, 0x88, 0x2E, 0x62, 0xBA, 0x06, 0x6C, 0xC9, + 0x7A, 0x84, 0x93, 0xCF, 0x14, 0x15, 0x44, 0x87, + 0xE2, 0x09, 0x97, 0xE6, 0xCE, 0x7E, 0x28, 0xA9, + 0x29, 0x53, 0xD7, 0xB8, 0xD1, 0x53, 0x30, 0x15, + 0x6E, 0x95, 0x3E, 0xA2, 0x7A, 0xCA, 0x9C, 0x1D, + 0x9D, 0xEB, 0x5F, 0x15, 0xEF, 0x48, 0x34, 0xCC, + 0xCB, 0x02, 0xA6, 0xD6, 0xA7, 0x80, 0xF2, 0x3F, + 0x7E, 0x96, 0x23, 0xAE, 0x42, 0xF1, 0x29, 0xF5, + 0xAD, 0x5A, 0x35, 0x57, 0x36, 0xAA, 0xAF, 0x97, + 0xE8, 0x1E, 0xA2, 0xD3, 0xFB, 0x4B, 0x1D, 0x9C, + 0x1C, 0x06, 0x84, 0xEB, 0x9E, 0x2C, 0xD4, 0x18, + 0x94, 0x44, 0x7E, 0x4B, 0x12, 0x91, 0xF2, 0x8B, + 0x07, 0x45, 0xDB, 0x52, 0xBB, 0x2E, 0x53, 0x63, + 0xE3, 0x38, 0xB8, 0x95, 0x4D, 0x9B, 0xCF, 0x07, + 0x05, 0xDD, 0x4C, 0xE2, 0x39, 0xAF, 0xA9, 0x51, + 0xDB, 0xAD, 0x19, 0xC8, 0x13, 0x6E, 0x0A, 0x2F, + 0xEA, 0x12, 0xB9, 0x25, 0x55, 0xB6, 0x64, 0x04, + 0x7F, 0x14, 0x6E, 0x12, 0x08, 0xFB, 0xBD, 0xBD, + 0x1D, 0xC6, 0xE2, 0x84, 0x50, 0x20, 0x60, 0xA0, + 0x90, 0xD2, 0x74, 0x8A, 0x18, 0xA4, 0xD9, 0xE9, + 0x69, 0xB2, 0x1E, 0x73, 0xAB, 0x1B, 0x7B, 0xBB, + 0x3B, 0xE0, 0x42, 0x23, 0xF9, 0x29, 0x49, 0x89, + 0x09, 0xD2, 0x4C, 0x29, 0xF1, 0x21, 0x65, 0xAC, + 0x2C, 0x97, 0x30, 0x6C, 0xB4, 0x04, 0xF4, 0x3D, + 0xBD, 0x06, 0xA0, 0xC6, 0x1E, 0xCE, 0x7E, 0xB3, + 0x33, 0x88, 0x2E, 0x43, 0x9B, 0x2B, 0x37, 0xF0, + 0x70, 0xCB, 0x91, 0xF1, 0x2B, 0xFB, 0x8B, 0x48, + 0xCA, 0x39, 0x97, 0xFB, 0x21, 0xB9, 0xCD, 0x0E, + 0x8C, 0x7F, 0x8D, 0xEC, 0x36, 0xE6, 0xEA, 0x27, + 0xA5, 0x1E, 0x40, 0x2A, 0xF2, 0x22, 0xCA, 0x07, + 0x85, 0x3E, 0xC8, 0xAE, 0x76, 0xA6, 0xF0, 0x71, + 0xF1, 0xAB, 0x6B, 0x04, 0x6D, 0xA9, 0xCA, 0x06, + 0x2C, 0x66, 0xA5, 0xCA, 0xB0, 0x4B, 0x2B, 0x62, + 0xEB, 0xD5, 0x61, 0x0D, 0xF0, 0x46, 0x26, 0xC3, + 0x44, 0x9F, 0x0C, 0x63, 0xBB, 0xAA, 0xBD, 0x7E, + 0xF2, 0x74, 0x00, 0x66, 0x2B, 0x7A, 0x62, 0xA1, + 0x07, 0x80, 0x33, 0x8D, 0x1F, 0xF7, 0x45, 0xCB, + 0x5E, 0x24, 0xEB, 0x84, 0xED, 0x27, 0x44, 0x61, + 0xFF, 0x0C, 0xA7, 0x3B, 0xE3, 0x53, 0x05, 0x84, + 0x04, 0xEE, 0x23, 0x4C, 0xB5, 0x79, 0x1A, 0xF3, + 0xA0, 0x66, 0x20, 0x4C, 0x94, 0x24, 0x72, 0xF3, + 0x73, 0x39, 0xF8, 0x97, 0xDD, 0x64, 0x54, 0xF2, + 0x6B, 0xBA, 0xAD, 0xBC, 0x67, 0x66, 0x78, 0xBB, + 0x5E, 0x6D, 0xFB, 0x8A, 0xA2, 0x74, 0x3D, 0xF5, + 0xD4, 0x72, 0xC7, 0x1A, 0xBD, 0x0E, 0x0B, 0x2C, + 0x8C, 0x4A, 0x0C, 0x60, 0xB8, 0x08, 0x5E, 0xDF, + 0x5F, 0x05, 0x33, 0x5C, 0xB5, 0x7E, 0x1D, 0xFC, + 0xFD, 0x25, 0xBA, 0x95, 0xC4, 0xA7, 0xDA, 0xEA, + 0x6A, 0xB1, 0x31, 0x1C, 0xC4, 0xE5, 0x07, 0xC4, + 0xC5, 0x9D, 0x28, 0xCD, 0x3C, 0xE9, 0x89, 0x49, + 0xD4, 0xFF, 0x7F, 0x52, 0x8A, 0x9B, 0x7F, 0xBC, + 0x8E, 0xF5, 0xCF, 0x0B, 0xD9, 0x49, 0x48, 0x88, + 0x80, 0x71, 0x7D, 0xAB, 0xEF, 0x47, 0x2B, 0xF7, + 0x7B, 0x2D, 0x79, 0x3F, 0xCF, 0xBF, 0xFF, 0x3F, + 0x6D, 0xF8, 0x42, 0xEC, 0x7F, 0xE8, 0xED, 0x42, + 0xE6, 0x1D, 0x4D, 0x32, 0xFA, 0x6A, 0x0A, 0xD7, + 0xA7, 0x7C, 0xCB, 0xA7, 0x7B, 0xCB, 0xBF, 0x71, + 0xF3, 0x48, }; static unsigned char vfs5011_prepare_01[] = { /* 3794 B */ - 0x06, 0x6B, 0x06, 0x6A, 0x76, 0xC8, 0x18, 0xD4, - 0x54, 0xEF, 0x71, 0x14, 0xCC, 0x1C, 0x58, 0x91, - 0x11, 0xAA, 0x80, 0xF4, 0x2C, 0xFC, 0x9F, 0x5F, - 0xDF, 0x04, 0x02, 0x62, 0xBA, 0x6A, 0x5A, 0x97, - 0x17, 0xCC, 0x46, 0x22, 0xFA, 0x2A, 0xBE, 0x03, - 0x87, 0x3C, 0x9E, 0xFE, 0x26, 0xF6, 0x96, 0x7E, - 0xFA, 0x11, 0x27, 0x66, 0xBA, 0x3A, 0x5A, 0xBA, - 0x3E, 0xD5, 0x4F, 0x03, 0xDF, 0x5F, 0x7F, 0x9F, - 0x1B, 0xF0, 0xA2, 0xEF, 0x33, 0xB3, 0xD3, 0x13, - 0x93, 0x70, 0xFA, 0x96, 0x4E, 0xC6, 0xA6, 0xC6, - 0x46, 0xA5, 0x2F, 0xE3, 0x3B, 0xB3, 0xD3, 0x33, - 0xB3, 0x50, 0xE8, 0xA4, 0x7C, 0xF4, 0x94, 0x14, - 0x94, 0x77, 0xC9, 0xE5, 0x3D, 0xB5, 0xD5, 0x75, - 0xF5, 0x16, 0xA8, 0xA4, 0x7C, 0xF4, 0x94, 0xD4, - 0x54, 0xB7, 0x09, 0xE5, 0x3D, 0xB5, 0x2D, 0xF4, - 0x74, 0xCF, 0x29, 0x5C, 0x84, 0x54, 0x14, 0xAA, - 0x2E, 0x95, 0xF7, 0xE0, 0x3C, 0xEC, 0x8C, 0x52, - 0xD6, 0x3D, 0x7B, 0x0E, 0xD6, 0x06, 0x82, 0x49, - 0xC9, 0x72, 0x7C, 0x18, 0xC0, 0x10, 0x10, 0xF6, - 0x72, 0xC9, 0xC3, 0xA8, 0x70, 0xA0, 0xD8, 0x77, - 0xF3, 0x48, 0x06, 0x04, 0xD8, 0x08, 0x90, 0x5B, - 0xDB, 0x60, 0x36, 0x43, 0x9B, 0x4B, 0xD4, 0xE3, - 0x9C, 0xB8, 0xF1, 0x72, 0x55, 0x1A, 0x8E, 0x57, - 0xD7, 0x6C, 0xDA, 0xBE, 0x66, 0xD6, 0xEA, 0x3D, - 0xBF, 0x04, 0xB2, 0xCE, 0x16, 0xA6, 0x06, 0xDE, - 0x5E, 0xE5, 0xB7, 0xC3, 0x1B, 0xCB, 0x47, 0x9F, - 0x1F, 0xA4, 0x3E, 0x5B, 0x83, 0x53, 0x53, 0x8A, - 0x0A, 0xB1, 0x93, 0xF9, 0x21, 0xF1, 0x31, 0xE6, - 0x64, 0xDF, 0x95, 0xE0, 0x38, 0xE8, 0xB4, 0x6D, - 0xED, 0x56, 0x1D, 0x8E, 0x56, 0xE6, 0x79, 0xB9, - 0xC6, 0xE2, 0x62, 0x4F, 0x97, 0x02, 0x40, 0x80, - 0x65, 0xB8, 0x0E, 0x07, 0xC2, 0x72, 0x37, 0xBE, - 0x3E, 0x00, 0xF2, 0xB8, 0xF1, 0x6D, 0x0E, 0x6F, - 0xC2, 0x1A, 0xA0, 0xC4, 0x95, 0x2F, 0xCD, 0x44, - 0xC4, 0x02, 0x44, 0x28, 0xF0, 0x40, 0x16, 0x97, - 0x17, 0x7D, 0xE4, 0x8B, 0xFE, 0x4C, 0x0D, 0xE3, - 0x60, 0xFD, 0x4B, 0x27, 0x34, 0xA6, 0xCD, 0xB6, - 0x10, 0xC0, 0x7C, 0x98, 0x42, 0x72, 0x92, 0x26, - 0x21, 0x60, 0x26, 0x4C, 0x95, 0x25, 0xA0, 0x03, - 0xA6, 0x50, 0xEC, 0x9D, 0xB5, 0x05, 0x53, 0xD2, - 0x52, 0xA9, 0x7E, 0x12, 0x2F, 0x65, 0xFA, 0x1A, - 0x7C, 0xB4, 0x12, 0x5E, 0x86, 0x3A, 0x50, 0xF5, - 0x53, 0xAD, 0xBA, 0xE6, 0x3D, 0x3C, 0x6D, 0xAE, - 0xCB, 0x33, 0xAD, 0xDC, 0xF4, 0x44, 0x12, 0x93, - 0x13, 0xF9, 0x7D, 0x12, 0xEB, 0x68, 0x0B, 0xE2, - 0x21, 0xE7, 0xA1, 0xCD, 0x15, 0xA5, 0xF3, 0x72, - 0xF2, 0xAB, 0x1F, 0x7E, 0xAA, 0x01, 0xE1, 0xA1, - 0x25, 0xA8, 0x06, 0x6D, 0xB9, 0x0C, 0x60, 0xA6, - 0x64, 0xAD, 0x15, 0x65, 0xBA, 0x30, 0x14, 0x66, - 0x22, 0x78, 0xFC, 0x94, 0x4C, 0x4E, 0x25, 0x9B, - 0xD9, 0x06, 0xB1, 0xEA, 0x89, 0x35, 0x62, 0x1E, - 0x8F, 0x69, 0xD4, 0x7F, 0x1C, 0xA0, 0xFD, 0x31, - 0x77, 0xAD, 0x1B, 0x40, 0xA4, 0x10, 0xB7, 0xCC, - 0x4D, 0xAB, 0x16, 0xD7, 0x0C, 0x01, 0x62, 0x87, - 0xBF, 0x4C, 0x50, 0x5A, 0xD8, 0x3B, 0x50, 0xE7, - 0x2C, 0xB3, 0xB7, 0x1F, 0x46, 0xA0, 0x57, 0x6B, - 0x46, 0x98, 0x93, 0xFA, 0xC7, 0xC1, 0x89, 0x45, - 0xDE, 0xD7, 0xC3, 0xC3, 0xBB, 0xCF, 0xEE, 0xEE, - 0xA8, 0xB3, 0xDF, 0x61, 0x4B, 0xE6, 0x04, 0x04, - 0x40, 0xDA, 0xAC, 0x43, 0xDA, 0x9A, 0x15, 0x25, - 0x45, 0x7D, 0xEA, 0x0C, 0x3A, 0x7A, 0xD4, 0x87, - 0xC5, 0x43, 0x77, 0x1D, 0xC6, 0x76, 0xD4, 0xB6, - 0x5A, 0x4B, 0x3F, 0x91, 0x55, 0x98, 0xC2, 0xCE, - 0x8C, 0x5B, 0xED, 0x53, 0x99, 0x20, 0x6D, 0xA6, - 0xF1, 0x96, 0x21, 0x41, 0xBB, 0x16, 0x86, 0x46, - 0xC6, 0x1D, 0x9D, 0xB0, 0x68, 0x69, 0x3D, 0xFE, - 0xC6, 0x16, 0x2C, 0x2B, 0x51, 0x40, 0x40, 0x2A, - 0x01, 0xBF, 0xB3, 0xFF, 0x8A, 0x38, 0x3D, 0x51, - 0xF4, 0x32, 0x74, 0x18, 0xC0, 0x70, 0x26, 0xA7, - 0x27, 0x5D, 0xDE, 0xB1, 0xD8, 0x5E, 0x3D, 0x30, - 0xB2, 0x0C, 0xEC, 0xA5, 0xCC, 0x44, 0x27, 0xC7, - 0x6D, 0x16, 0x01, 0x5A, 0x81, 0xFC, 0x9E, 0x3B, - 0xEE, 0x10, 0x17, 0x41, 0x9A, 0x0A, 0x50, 0x30, - 0x72, 0x6A, 0xCC, 0x01, 0xE0, 0x53, 0x3F, 0xFD, - 0x54, 0x8C, 0x13, 0x6C, 0x9D, 0x0E, 0x47, 0xB4, - 0xD1, 0x59, 0xCA, 0x17, 0xF3, 0x40, 0x10, 0xEA, - 0xCA, 0xD3, 0xA6, 0xDA, 0xA3, 0x28, 0x4B, 0x6E, - 0xBC, 0x42, 0xF8, 0x9D, 0x75, 0xFF, 0x3F, 0xCD, - 0x8E, 0x45, 0xE8, 0x1D, 0xEC, 0x5F, 0x74, 0x87, - 0x61, 0x23, 0x63, 0xA2, 0x79, 0x7B, 0xBB, 0xDE, - 0x72, 0xE5, 0xB6, 0x7B, 0x8B, 0x9A, 0xC7, 0x04, - 0x35, 0xD0, 0x65, 0xCB, 0xD0, 0x44, 0x41, 0xD1, - 0x74, 0x1E, 0xE8, 0x87, 0x6F, 0xE5, 0x25, 0x44, - 0xFB, 0x23, 0xA7, 0x08, 0xF4, 0x89, 0xEA, 0xCF, - 0x1E, 0xE0, 0xE7, 0xC9, 0x12, 0x92, 0xC8, 0xA8, - 0x89, 0x13, 0xA6, 0x07, 0xDC, 0xC9, 0xFA, 0x1F, - 0x2E, 0xB1, 0x04, 0x58, 0xBA, 0xAA, 0x6B, 0xE8, - 0x6B, 0x7D, 0xC8, 0x01, 0x8B, 0x1E, 0xCF, 0x49, - 0xCA, 0x21, 0xAD, 0x61, 0x18, 0xED, 0x8E, 0x83, - 0x00, 0x3E, 0xD9, 0x90, 0x78, 0xE2, 0x22, 0xFF, - 0x8F, 0x54, 0xD4, 0xF9, 0x21, 0x10, 0x37, 0xF4, - 0xFC, 0x2F, 0x15, 0x31, 0x48, 0xB0, 0xD3, 0x36, - 0xC1, 0x32, 0x99, 0x05, 0xDD, 0x6D, 0x3B, 0xBA, - 0x3A, 0x60, 0x91, 0xFE, 0xAE, 0x16, 0xFA, 0x72, - 0x53, 0xC0, 0x75, 0xFC, 0x51, 0xC9, 0x0C, 0x38, - 0x99, 0x5F, 0x19, 0x75, 0xAD, 0x1D, 0x4B, 0xCA, - 0x4A, 0x3C, 0x88, 0x01, 0x40, 0xD2, 0x33, 0xB4, - 0x37, 0x64, 0xDA, 0x3A, 0xAA, 0xBB, 0x93, 0x50, - 0xF5, 0x5A, 0xC4, 0xB5, 0x9D, 0x2D, 0x7B, 0xFA, - 0x7A, 0x84, 0x17, 0x7B, 0x22, 0xD8, 0xBB, 0xEA, - 0x58, 0x80, 0x97, 0xB2, 0x69, 0x70, 0x49, 0x00, - 0x89, 0x4F, 0x09, 0x65, 0xBD, 0x0D, 0x5B, 0xDA, - 0x5A, 0xB0, 0x32, 0x5D, 0x89, 0x1E, 0x46, 0x85, - 0x54, 0xC4, 0x71, 0x8F, 0x54, 0xEC, 0xEE, 0x8F, - 0x7F, 0xAF, 0x90, 0xEA, 0x7A, 0xCC, 0x7D, 0xF1, - 0x72, 0xA5, 0x79, 0x19, 0xC6, 0xF4, 0x5D, 0x61, - 0xF7, 0x24, 0x98, 0xD2, 0x53, 0xEB, 0x26, 0xE4, - 0x01, 0x67, 0xF7, 0xB6, 0x64, 0xC9, 0x59, 0xF3, - 0x30, 0x59, 0xFC, 0x9B, 0xD1, 0x65, 0x05, 0xD3, - 0x68, 0xB8, 0x68, 0x7D, 0xB5, 0xC7, 0xB3, 0x8F, - 0x59, 0x2E, 0x92, 0x5C, 0xC7, 0x7F, 0x3D, 0xFE, - 0x73, 0x88, 0x1F, 0x77, 0xB2, 0xF2, 0x9E, 0x55, - 0x57, 0x8F, 0x34, 0x9A, 0x61, 0x0C, 0x7B, 0xD3, - 0x5C, 0x15, 0xAE, 0xC2, 0x16, 0xB4, 0xC2, 0x2B, - 0xA5, 0x75, 0x6A, 0xA4, 0x31, 0x81, 0xA7, 0x67, - 0xE7, 0x30, 0x84, 0x28, 0xD0, 0x60, 0xA2, 0x71, - 0xF9, 0xE0, 0x33, 0xFF, 0xAB, 0x01, 0x04, 0x22, - 0x84, 0x42, 0x04, 0x02, 0x99, 0xFB, 0x9F, 0x5F, - 0xB9, 0x7F, 0xF5, 0x21, 0xDB, 0xC6, 0xA5, 0x00, - 0x60, 0x9D, 0x8B, 0x07, 0xAB, 0x7D, 0x03, 0xE2, - 0xD3, 0x45, 0xF0, 0x6E, 0xBD, 0x0D, 0x4B, 0xA4, - 0x23, 0x8A, 0x77, 0x1B, 0xCF, 0x75, 0x30, 0x96, - 0x33, 0xE4, 0x6A, 0x94, 0x6F, 0x01, 0xA1, 0x41, - 0xC1, 0x88, 0x5B, 0x97, 0xCD, 0x3E, 0x56, 0xD0, - 0x53, 0x88, 0x9C, 0xE3, 0x3C, 0x00, 0x1A, 0xA8, - 0x6C, 0xB7, 0xA3, 0xDC, 0x03, 0x96, 0x14, 0xF2, - 0x7E, 0xB7, 0x1C, 0x80, 0xEA, 0x49, 0x21, 0x8B, - 0x48, 0x85, 0xF8, 0x93, 0x89, 0x3D, 0x5D, 0x5F, - 0x13, 0x33, 0x93, 0xC3, 0x1C, 0x4E, 0x2D, 0xE0, - 0xE2, 0x1D, 0x2A, 0x51, 0xE7, 0x07, 0xF5, 0x38, - 0xB8, 0x75, 0x4A, 0x2A, 0xFE, 0x5C, 0x37, 0x0E, - 0x7C, 0xEA, 0x5C, 0xB6, 0x7E, 0xCE, 0x2C, 0x25, - 0x5C, 0xD1, 0xFF, 0x66, 0x06, 0x94, 0x59, 0x9A, - 0x7F, 0x7D, 0xED, 0x21, 0x69, 0xAD, 0xC6, 0x9F, - 0x49, 0x7B, 0xC7, 0xA7, 0x74, 0xC8, 0xE4, 0xC6, - 0x65, 0x63, 0x07, 0xC9, 0x65, 0x0F, 0xBC, 0xBC, - 0x1C, 0xC7, 0xD3, 0xAC, 0x7C, 0x2E, 0x2B, 0x4B, - 0xB9, 0x3F, 0xF7, 0x59, 0xC2, 0x7A, 0x0C, 0x86, - 0xF4, 0x23, 0xFB, 0x75, 0xE9, 0x59, 0x9B, 0x48, - 0xC0, 0x7E, 0x13, 0x59, 0x07, 0x72, 0xED, 0x00, - 0x87, 0x50, 0xE9, 0x45, 0xBD, 0x0D, 0xCF, 0x1C, - 0x94, 0xCD, 0x1E, 0xD2, 0x1C, 0x36, 0xA5, 0x80, - 0xD9, 0x24, 0x8F, 0x13, 0xC7, 0x75, 0x53, 0x5B, - 0x24, 0x47, 0xD3, 0x12, 0xC9, 0x5C, 0xE8, 0x0E, - 0x2E, 0x65, 0xA7, 0xAD, 0x6C, 0xFB, 0x97, 0x5C, - 0x0E, 0xF6, 0x9D, 0x33, 0x49, 0x8D, 0x27, 0x24, - 0x64, 0x9F, 0x29, 0x97, 0x2A, 0x3A, 0xF8, 0x2B, - 0xA3, 0x0A, 0xE0, 0xF2, 0x96, 0x7C, 0x76, 0x55, - 0xD9, 0x6F, 0x0B, 0x29, 0xF1, 0xE3, 0x90, 0x58, - 0xBD, 0xB0, 0x20, 0xCA, 0x1B, 0xAB, 0xC7, 0x78, - 0xF4, 0x7B, 0x8F, 0xA0, 0x70, 0xAA, 0x89, 0xBB, - 0x7F, 0xA4, 0xA0, 0xDF, 0x0C, 0x20, 0x0B, 0x79, - 0xAD, 0x8A, 0x30, 0xA6, 0x72, 0x4A, 0xA8, 0x2C, - 0xAC, 0x12, 0x70, 0x3A, 0x70, 0xD4, 0x48, 0x1A, - 0x53, 0x79, 0x5D, 0x65, 0x41, 0xD3, 0xB0, 0x7D, - 0xDD, 0x27, 0x95, 0xE4, 0xCC, 0x51, 0x36, 0x70, - 0x2F, 0x0B, 0x1F, 0x67, 0x43, 0xE5, 0x5F, 0x77, - 0xFB, 0xA8, 0x9C, 0xB4, 0x6C, 0x6A, 0xB0, 0x60, - 0xEC, 0xCD, 0xDE, 0x63, 0x9D, 0x0F, 0x7B, 0x47, - 0xE5, 0xFC, 0xBB, 0xF5, 0x79, 0x35, 0x53, 0x0E, - 0x71, 0x4F, 0x29, 0x63, 0x96, 0x21, 0x07, 0x3B, - 0x44, 0x9F, 0x1F, 0x32, 0xEA, 0x0B, 0x5F, 0x9C, - 0x44, 0x9A, 0x6E, 0xA2, 0x8A, 0x70, 0x55, 0xA7, - 0x23, 0x78, 0xE8, 0xA7, 0x4E, 0xD8, 0xFB, 0x08, - 0xE9, 0x79, 0xCC, 0xD1, 0x45, 0xF6, 0x9A, 0xF2, - 0x54, 0xEC, 0x75, 0x7F, 0x24, 0x8A, 0xE6, 0x55, - 0x47, 0xB9, 0xD1, 0x7D, 0x85, 0x35, 0xC7, 0x61, - 0x41, 0xA8, 0x5A, 0xB6, 0xDC, 0x69, 0x04, 0x66, - 0xE1, 0x3A, 0x3C, 0xE1, 0x3D, 0x3D, 0xF5, 0xA6, - 0x84, 0x18, 0xAE, 0xDF, 0xF7, 0x5A, 0xCA, 0x06, - 0x95, 0x08, 0xBE, 0xD2, 0x06, 0x85, 0xD7, 0x53, - 0x53, 0x95, 0xD3, 0xB3, 0x38, 0x4A, 0x0F, 0x11, - 0x51, 0xAA, 0x1C, 0xB2, 0x0C, 0x1C, 0xBA, 0x89, - 0xF6, 0x2D, 0xAD, 0x80, 0x58, 0xD9, 0xF7, 0x34, - 0x95, 0x01, 0xB4, 0xF1, 0x3A, 0x97, 0x07, 0xC7, - 0x47, 0x9C, 0x1C, 0x31, 0xE9, 0xC8, 0x9C, 0x5F, - 0x47, 0x95, 0xAF, 0x6A, 0x10, 0x89, 0x34, 0x54, - 0x74, 0xBB, 0x2B, 0x7D, 0xA7, 0xF2, 0xD0, 0x31, - 0xAC, 0x87, 0x07, 0x2A, 0xF2, 0xE3, 0xD2, 0x11, - 0xB0, 0x21, 0x94, 0xC9, 0x23, 0x90, 0x61, 0xF1, - 0x72, 0x28, 0xCC, 0xA3, 0xF2, 0x6B, 0x22, 0xE1, - 0xC8, 0x4A, 0xE1, 0x7D, 0xA5, 0x15, 0x43, 0xC2, - 0x42, 0xB8, 0x5D, 0x32, 0x62, 0xF0, 0x57, 0xFF, - 0x62, 0x18, 0xFA, 0x95, 0x28, 0xD1, 0x99, 0xC8, - 0x1D, 0xC5, 0xB2, 0x88, 0x53, 0x52, 0x65, 0xA6, - 0x8E, 0x77, 0x79, 0x1E, 0x06, 0x1C, 0x6C, 0x3C, - 0x26, 0xED, 0xEB, 0x1D, 0x56, 0x7F, 0x3D, 0x58, - 0x11, 0xEF, 0x44, 0xD8, 0x00, 0xB0, 0xE6, 0x67, - 0xE7, 0x9D, 0x7F, 0x10, 0x2D, 0xDF, 0x97, 0xB6, - 0x6E, 0xB6, 0x41, 0x1F, 0xC4, 0x45, 0x76, 0xB5, - 0x39, 0xEE, 0x80, 0xCF, 0xE6, 0x01, 0x62, 0x15, - 0xF8, 0x01, 0x0A, 0x69, 0x79, 0xCD, 0x64, 0xAB, - 0x86, 0x5F, 0x68, 0x5D, 0x86, 0xD6, 0x2B, 0xCB, - 0xD2, 0x2A, 0x15, 0x7D, 0xC0, 0x38, 0x58, 0x29, - 0xF3, 0x2B, 0x35, 0x7A, 0xAE, 0x1C, 0xCC, 0xA6, - 0x06, 0x74, 0xE1, 0x90, 0xB8, 0x04, 0x6F, 0x69, - 0x1F, 0x3B, 0xBB, 0x96, 0x4E, 0xE2, 0x4A, 0x0D, - 0x1F, 0xC0, 0x57, 0x60, 0xBB, 0x16, 0x86, 0xEB, - 0x69, 0x97, 0xE3, 0xAA, 0x5F, 0xE5, 0x98, 0xA8, - 0x28, 0xF3, 0x73, 0x5E, 0x86, 0x47, 0x60, 0xA3, - 0xFF, 0x70, 0x4E, 0x25, 0x71, 0x89, 0x4C, 0x92, - 0x12, 0x8F, 0x38, 0x54, 0x2D, 0xD5, 0xB6, 0x53, - 0xEF, 0x1C, 0x02, 0x69, 0xBD, 0x04, 0xF6, 0x7C, - 0x64, 0x0D, 0x1B, 0x04, 0x96, 0x45, 0xE7, 0x87, - 0x73, 0xCF, 0x45, 0x3A, 0x5F, 0xED, 0x25, 0xE2, - 0xAF, 0x77, 0x8B, 0x4D, 0x37, 0x4D, 0x09, 0x6C, - 0xA9, 0x5A, 0x5E, 0x92, 0x39, 0x4F, 0x2A, 0xEA, - 0x2D, 0xCD, 0x6F, 0xBE, 0x64, 0x7C, 0x1B, 0x19, - 0x39, 0x96, 0x60, 0xC0, 0xD8, 0x22, 0xE8, 0x8A, - 0xC0, 0x3F, 0x6C, 0x43, 0xB3, 0xB1, 0x71, 0xC2, - 0xFE, 0x70, 0xA1, 0xF6, 0x26, 0x34, 0xF0, 0x35, - 0x50, 0x5A, 0xC8, 0xE2, 0x3D, 0x8D, 0x5F, 0x3F, - 0xCB, 0x77, 0x7A, 0x1E, 0x64, 0x70, 0x16, 0x33, - 0x63, 0x9C, 0xAC, 0xC3, 0x1B, 0xA7, 0xCD, 0xD5, - 0x52, 0x85, 0x2F, 0x81, 0x14, 0x3C, 0xB9, 0xB6, - 0x12, 0xEC, 0x5E, 0x32, 0x02, 0xB5, 0x37, 0xF9, - 0xE1, 0xF6, 0x0E, 0xC3, 0x53, 0xE0, 0x25, 0xDD, - 0x75, 0xB3, 0xF5, 0x99, 0x41, 0xF1, 0xA7, 0x26, - 0xA6, 0x4C, 0xBD, 0xD2, 0x32, 0x81, 0xC0, 0x5C, - 0xDF, 0x2D, 0xE8, 0x0F, 0x54, 0x76, 0xD5, 0x01, - 0x18, 0xA0, 0x8F, 0xB0, 0xE1, 0x62, 0x8B, 0x68, - 0xCA, 0xD3, 0x99, 0xDC, 0x47, 0xEA, 0x7A, 0xBA, - 0x3A, 0xE1, 0x61, 0x4C, 0x94, 0xC1, 0xB2, 0x72, - 0xEF, 0xC4, 0x44, 0x69, 0xB1, 0x0D, 0x27, 0x42, - 0xE2, 0x1B, 0x8C, 0xA7, 0x7C, 0x41, 0x2B, 0x73, - 0xF1, 0x26, 0x8A, 0x64, 0xD5, 0x42, 0x87, 0x58, - 0xFA, 0x5D, 0x37, 0x27, 0x11, 0xAD, 0xE5, 0x9D, - 0x1F, 0xC8, 0x69, 0xA7, 0x14, 0x8C, 0x5D, 0xD6, - 0x55, 0x4E, 0xD8, 0xB4, 0xFE, 0x65, 0xAD, 0xAD, - 0x0D, 0xD6, 0x10, 0xE5, 0x1D, 0x3F, 0x34, 0x5C, - 0x1C, 0xE7, 0x51, 0xCF, 0x3C, 0x24, 0x84, 0x64, - 0xE4, 0xBF, 0xF6, 0xBA, 0x90, 0x4B, 0x83, 0x83, - 0x23, 0xF8, 0x9C, 0xDB, 0xA9, 0xD9, 0x99, 0x59, - 0x39, 0x3F, 0x99, 0x27, 0x94, 0x8E, 0x2E, 0xCE, - 0x4E, 0x37, 0xAA, 0x6C, 0x74, 0xE4, 0x84, 0x84, - 0xAE, 0x65, 0x71, 0x76, 0x04, 0x15, 0x28, 0xEB, - 0xCE, 0x00, 0x94, 0xF4, 0x2F, 0x27, 0x45, 0x89, - 0x0F, 0xD8, 0x2B, 0xA7, 0x3C, 0x9D, 0xF1, 0x38, - 0x88, 0xB0, 0xF6, 0x7A, 0x4C, 0xED, 0x3D, 0x0E, - 0x2E, 0x97, 0x4E, 0x08, 0xDC, 0x73, 0xDB, 0x19, - 0x09, 0x7B, 0x3D, 0x4A, 0x0B, 0x2B, 0xDB, 0x6F, - 0x05, 0x12, 0x6E, 0xC8, 0xC2, 0x7E, 0x37, 0x75, - 0xF9, 0x08, 0x0C, 0x6C, 0x91, 0xA1, 0x49, 0x98, - 0xA8, 0xC0, 0x37, 0xE9, 0x7D, 0xE8, 0x58, 0x10, - 0xB0, 0xB3, 0x07, 0xD6, 0x06, 0x36, 0xE9, 0xAA, - 0xC0, 0xC6, 0xC0, 0x54, 0xCD, 0x8F, 0xA3, 0x49, - 0x13, 0x62, 0x56, 0x30, 0xC0, 0xC2, 0xEE, 0x07, - 0x07, 0x58, 0xAF, 0x41, 0xD3, 0x4B, 0x4D, 0xC4, - 0xFE, 0xAD, 0x19, 0xD8, 0x03, 0x39, 0xCA, 0x80, - 0xB4, 0xDD, 0x40, 0x06, 0x54, 0x6A, 0xBA, 0xC1, - 0xB1, 0xD0, 0xEE, 0x00, 0xD0, 0x47, 0xA5, 0x2C, - 0x44, 0x17, 0xA3, 0xC3, 0x10, 0x20, 0x93, 0xC3, - 0xC9, 0xE6, 0xA2, 0xE1, 0x13, 0x29, 0xA7, 0x97, - 0xE8, 0xC3, 0x8F, 0x0D, 0x17, 0xA9, 0xE3, 0xC1, - 0x4F, 0xBD, 0x8B, 0x2B, 0xE2, 0xB2, 0x1E, 0xFE, - 0xBC, 0x3A, 0xE0, 0xE9, 0x20, 0x90, 0xFC, 0x35, - 0xBE, 0x30, 0x3E, 0x50, 0x93, 0x10, 0x40, 0xB0, - 0x44, 0xAF, 0xFA, 0x66, 0x04, 0x70, 0x62, 0xCE, - 0x60, 0x5B, 0xAE, 0xD3, 0x5D, 0x58, 0xCD, 0xAF, - 0xE4, 0x2B, 0x1C, 0x2E, 0xF5, 0xD7, 0x9C, 0x79, - 0x6B, 0xDB, 0x44, 0xE8, 0x10, 0xA0, 0x48, 0x80, - 0x89, 0xD9, 0xCA, 0xF1, 0x09, 0xA4, 0x34, 0xF4, - 0x74, 0xAF, 0x2F, 0x02, 0xDA, 0x4B, 0x6C, 0xAF, - 0x87, 0x5E, 0x4A, 0xEC, 0x20, 0xB5, 0x8D, 0x6D, - 0x45, 0x9C, 0xA1, 0x67, 0x9A, 0xB9, 0xFE, 0x32, - 0xF8, 0xC1, 0xD8, 0x34, 0x3D, 0xC6, 0xA5, 0xA5, - 0x05, 0xDE, 0xAA, 0xEB, 0x87, 0xF7, 0xB7, 0x77, - 0x4F, 0x96, 0xC0, 0x60, 0xA8, 0xDA, 0xD7, 0xA3, - 0x91, 0x61, 0xF0, 0xF9, 0x29, 0xBB, 0x63, 0xA1, - 0x2D, 0xEC, 0xE8, 0xAF, 0x5F, 0x0A, 0x6D, 0x8F, - 0x12, 0x39, 0xB9, 0x94, 0x4C, 0xAD, 0x86, 0x45, - 0x05, 0xFE, 0x48, 0x66, 0x9B, 0x9F, 0x3F, 0xDF, - 0x5F, 0xB4, 0x46, 0x3A, 0xA2, 0x50, 0x10, 0x92, - 0x77, 0x18, 0xB3, 0x2F, 0xF7, 0x47, 0x11, 0x90, - 0x10, 0xC7, 0x72, 0x6C, 0x14, 0xD4, 0xE5, 0x62, - 0xE1, 0x36, 0x96, 0x42, 0x9F, 0x1F, 0xBC, 0x8C, - 0xBC, 0xC4, 0xD2, 0x6C, 0x9E, 0x04, 0xD4, 0xD8, - 0xF8, 0xF3, 0x98, 0x04, 0x06, 0x7A, 0x98, 0x54, - 0xF0, 0xCB, 0x3E, 0x43, 0xFD, 0x55, 0x09, 0x2B, - 0x81, 0x74, 0x10, 0x56, 0xBC, 0x47, 0x94, 0xB3, - 0x3E, 0xF2, 0xE6, 0x86, 0x76, 0xC6, 0xBD, 0x3D, - 0xBD, 0xD0, 0xC7, 0xDB, 0xB8, 0x18, 0xD8, 0xB8, - 0x0C, 0x67, 0x7B, 0x37, 0x4F, 0x5F, 0x4B, 0xCD, - 0x4D, 0x96, 0x2C, 0x4A, 0x20, 0x3F, 0xDF, 0x3A, - 0x43, 0x67, 0x69, 0x00, 0x62, 0x06, 0x94, 0x79, - 0xD7, 0x00, 0xAA, 0x36, 0x01, 0xA0, 0x30, 0x3E, - 0x2D, 0x34, 0xEF, 0xAD, 0x6E, 0xED, 0xBD, 0x4D, - 0xB9, 0x04, 0xF1, 0x3D, 0x6E, 0x75, 0xB0, 0xF5, - 0x52, 0x24, 0x90, 0x7D, 0xFB, 0x48, 0xE8, 0x08, - 0x88, 0xDB, 0x65, 0x80, 0x6A, 0x7F, 0x56, 0xB6, - 0x2B, 0x00, 0x80, 0xAD, 0x75, 0x44, 0x63, 0xA0, - 0x00, 0xB9, 0xFF, 0x1B, 0xCB, 0x70, 0x53, 0x13, - 0xA1, 0xEA, 0xDC, 0xE2, 0x9A, 0x58, 0x1D, 0xF7, - 0xF7, 0x4A, 0x5C, 0x40, 0xEF, 0xAF, 0xB5, 0x53, - 0x85, 0xBA, 0x08, 0x46, 0x9C, 0x0A, 0x28, 0x7B, - 0x8B, 0xD0, 0x44, 0x29, 0xD1, 0x49, 0x18, 0x92, - 0x30, 0xEB, 0x7F, 0x02, 0xFA, 0x6A, 0x3B, 0xD9, - 0x0A, 0xA1, 0x55, 0x1C, 0xEE, 0x1E, 0x3A, 0x0A, - 0xC0, 0x5D, 0xA9, 0xC1, 0x3F, 0x2E, 0x11, 0xD2, - 0xD2, 0x4D, 0xFA, 0xD6, 0x46, 0xC7, 0x01, 0xD5, - 0x59, 0x24, 0x50, 0x2F, 0xEB, 0xA9, 0xD5, 0xED, - 0xEF, 0x67, 0xA1, 0x8B, 0x51, 0xE1, 0x67, 0xB5, - 0x33, 0xE4, 0x50, 0x30, 0xE1, 0xC3, 0xF0, 0x40, - 0x60, 0x19, 0x0F, 0xCB, 0x19, 0x0B, 0x0E, 0xFC, - 0x61, 0x4A, 0xDE, 0xB0, 0x4D, 0x7B, 0xF4, 0xCB, - 0x4B, 0x90, 0x10, 0x3D, 0xE5, 0x59, 0x3B, 0xF7, - 0x72, 0xE8, 0x19, 0x76, 0xA2, 0x51, 0xF9, 0x3D, - 0x7D, 0x74, 0x52, 0xAC, 0x69, 0xB5, 0xC3, 0x5A, - 0xDD, 0x0D, 0x32, 0xDE, 0x86, 0xC2, 0x20, 0xBD, - 0x51, 0xDC, 0xE2, 0x88, 0x90, 0xD2, 0x12, 0x30, - 0x9F, 0x6E, 0x64, 0x16, 0xE8, 0x46, 0x09, 0xEF, - 0x41, 0xB6, 0x66, 0x34, 0xBB, 0x59, 0x56, 0xBC, - 0x1C, 0x55, 0x13, 0xBF, 0xFE, 0xEE, 0x2C, 0xE5, - 0x4F, 0x26, 0x99, 0xDC, 0x84, 0x9E, 0xEF, 0x9F, - 0xB5, 0x4E, 0xF4, 0x93, 0xE9, 0x04, 0x08, 0xE2, - 0xCE, 0x87, 0x38, 0x73, 0x39, 0xC3, 0x4B, 0x26, - 0xA4, 0x5A, 0x1F, 0x8C, 0x12, 0xA9, 0xC9, 0x12, - 0x2C, 0xD7, 0xC3, 0x5F, 0x47, 0x5D, 0x9D, 0xEF, - 0x00, 0xF1, 0xF7, 0x20, 0x08, 0x02, 0xC8, 0xBA, - 0x30, 0xC1, 0x95, 0xF3, 0x02, 0x32, 0xE9, 0x38, - 0x58, 0x38, 0xAE, 0x70, 0xF5, 0x29, 0x63, 0x1F, - 0x3D, 0xEC, 0x7D, 0xB3, 0x20, 0x78, 0xB5, 0x77, - 0xFB, 0x2B, 0x78, 0xFB, 0xDC, 0xA4, 0xC0, 0x2A, - 0x76, 0x3F, 0x84, 0x00, 0x74, 0x0D, 0x66, 0x5F, - 0x2D, 0xBB, 0xE5, 0x41, 0x9D, 0x07, 0xBB, 0x99, - 0x14, 0x27, 0x4D, 0xEF, 0x9A, 0x28, 0x44, 0x9F, - 0x3F, 0x66, 0x20, 0x8C, 0xC6, 0xD6, 0x24, 0xCD, - 0x67, 0x7C, 0x42, 0x8E, 0xC6, 0xEF, 0x7F, 0x25, - 0x2D, 0x74, 0xCA, 0x81, 0xDB, 0x26, 0xAE, 0xCB, - 0xA7, 0x83, 0xFD, 0x95, 0x46, 0xC5, 0xBE, 0x5C, - 0xFC, 0x07, 0xC5, 0xFF, 0x34, 0x70, 0x82, 0x6E, - 0xC7, 0x90, 0xAF, 0xC8, 0x99, 0xAB, 0xA7, 0x4E, - 0x02, 0xC1, 0x92, 0x22, 0x05, 0xA8, 0x38, 0xF8, - 0x78, 0xA3, 0x23, 0x0E, 0xD6, 0x27, 0x27, 0xE4, - 0x55, 0xEF, 0x5A, 0xBE, 0x22, 0x1B, 0xF9, 0x00, - 0xC4, 0x02, 0x44, 0x28, 0xF0, 0x40, 0x16, 0x97, - 0x17, 0x6E, 0x1A, 0x66, 0x1B, 0x98, 0xD8, 0x89, - 0x69, 0xB1, 0x8F, 0x61, 0x30, 0xC9, 0xB4, 0x84, - 0x04, 0xDF, 0x5F, 0x72, 0xAA, 0xA7, 0xC5, 0x24, - 0xC6, 0x1E, 0x80, 0xEE, 0x3A, 0x06, 0xED, 0x8F, - 0xAA, 0x73, 0xED, 0x00, 0xBB, 0x08, 0xFA, 0xF8, - 0x68, 0x2A, 0xCE, 0x3B, 0xA1, 0x98, 0x9A, 0xD6, - 0x55, 0xB7, 0x93, 0xE2, 0xCA, 0x7A, 0x2C, 0xAD, - 0x2D, 0xC7, 0x13, 0x7C, 0x9C, 0x2F, 0xFD, 0x2E, - 0xB6, 0x61, 0xCB, 0xA0, 0x93, 0x39, 0xC8, 0x56, - 0xD5, 0xCE, 0xD3, 0x9F, 0xE5, 0x06, 0x7E, 0x7E, - 0xDE, 0x05, 0x2B, 0x4E, 0x14, 0xB7, 0xD1, 0xB3, - 0xF0, 0x3B, 0x17, 0xF3, 0xA2, 0x61, 0x64, 0x88, - 0x28, 0x41, 0xE4, 0x90, 0x5F, 0x04, 0x6A, 0x12, - 0x01, 0x56, 0x7B, 0x9F, 0x4C, 0x51, 0x33, 0x13, - 0x9B, 0x40, 0xDB, 0xBD, 0x78, 0x38, 0x54, 0x96, - 0x0B, 0x20, 0xA0, 0x8D, 0x55, 0xD4, 0xD6, 0x15, - 0xAD, 0x75, 0x71, 0x0F, 0xC3, 0xBB, 0x78, 0x10, - 0xB3, 0xA2, 0xAF, 0x7A, 0x01, 0x16, 0x4D, 0xDC, - 0xFC, 0xBC, 0xCA, 0x24, 0xEF, 0x47, 0xBE, 0xDD, - 0x4A, 0xF9, 0x64, 0xCA, 0xBA, 0xF5, 0x74, 0xD0, - 0x53, 0x70, 0x75, 0xD9, 0x21, 0x91, 0x23, 0xF0, - 0x68, 0x02, 0xFF, 0x90, 0xA8, 0xC5, 0xB5, 0x87, - 0x6C, 0x17, 0x73, 0x4C, 0x8C, 0xFC, 0xBC, 0x7C, - 0x5E, 0xAE, 0x98, 0x34, 0xCC, 0x7C, 0xDC, 0xB6, - 0x26, 0x5F, 0x82, 0x6E, 0xF0, 0x41, 0x21, 0x43, - 0x00, 0xCB, 0x58, 0x13, 0xEB, 0x9B, 0xDB, 0x1B, - 0x0A, 0x8F, 0x3A, 0xD4, 0x1F, 0xA9, 0x51, 0x98, - 0xBA, 0xA2, 0x04, 0xF2, 0xA2, 0x9B, 0x88, 0x2D, - 0x89, 0x72, 0x4C, 0xA3, 0xD6, 0x64, 0xE4, 0x2C, - 0xAC, 0x6A, 0x2C, 0x40, 0x98, 0x28, 0x7E, 0xFF, - 0x7F, 0xE6, 0xF8, 0x6B, 0x22, 0xF7, 0x94, 0xE5, - 0x07, 0xDF, 0x58, 0x7F, 0xA4, 0xAC, 0xC7, 0xC5, - 0x5E, 0x9D, 0x27, 0x66, 0x6E, 0x12, 0x52, 0x50, - 0x8B, 0x48, 0x3E, 0x72, 0xAA, 0xB8, 0xFB, 0x9B, - 0xB2, 0xD2, 0xA4, 0xE8, 0x30, 0x02, 0x41, 0x21, - 0x61, 0x9A, 0x2C, 0xD0, 0x80, 0x20, 0xD2, 0xB3, - 0x33, 0x78, 0x46, 0x0A, 0x50, 0x83, 0x43, 0x43, - 0xE3, 0x38, 0xAC, 0xE3, 0xBB, 0xCB, 0x8B, 0x4B, - 0x8B, 0x72, 0xD4, 0xFA, 0x86, 0x36, 0x16, 0xF4, - 0x54, 0xAD, 0x78, 0x94, 0x51, 0x11, 0x47, 0xC6, - 0x46, 0xFB, 0x79, 0x1D, 0x47, 0xF4, 0xB3, 0xB1, - 0x32, 0xCF, 0x1F, 0x4B, 0x99, 0x84, 0xE6, 0x9B, - 0x18, 0x0E, 0xBC, 0xF5, 0xB5, 0x27, 0x5A, 0x6A, - 0x42, 0xCA, 0xCE, 0x02, 0x21, 0x21, 0x8D, 0x5D, - 0x1F, 0x87, 0x17, 0xBB, 0x43, 0xF3, 0x01, 0xCB, - 0x47, 0x5C, 0xCA, 0xA6, 0xCE, 0xE7, 0x97, 0xC5, - 0x0F, 0xD8, 0x73, 0xEF, 0x37, 0x87, 0xFD, 0x3C, - 0xBC, 0x67, 0xD1, 0xBD, 0x65, 0xD5, 0x51, 0x9C, - 0x1E, 0xA5, 0x17, 0x7A, 0xA2, 0x12, 0x72, 0xB2, - 0x32, 0xE9, 0xEF, 0x8D, 0x57, 0x87, 0xCD, 0x0F, - 0x8F, 0x54, 0xE2, 0x8E, 0x56, 0xE6, 0x66, 0xB4, - 0x36, 0x8D, 0x27, 0x4B, 0x9B, 0x2B, 0x36, 0xF2, - 0x0C, 0xD3, 0xE1, 0x9F, 0x45, 0x95, 0x81, 0x52, - 0xD0, 0x6B, 0x45, 0x3A, 0xE0, 0x30, 0xF0, 0x23, - 0xA1, 0x1A, 0x74, 0x0C, 0xD6, 0x06, 0x7E, 0xAB, - 0x29, 0x92, 0x14, 0x6E, 0xB4, 0x64, 0x30, 0xE5, - 0x67, 0xDC, 0xD2, 0xAB, 0x71, 0xA1, 0xC1, 0x01, - 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x87, 0x47, - 0xC7, 0x1C, 0x5A, 0xC9, 0xEE, 0xA1, 0xC1, 0x01, - 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x87, 0x47, - 0xC7, 0x1C, 0x5A, 0xC9, 0xEE, 0xA1, 0xC1, 0x01, - 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x87, 0x47, - 0xC7, 0x1C, 0x5A, 0xC9, 0xEE, 0xA1, 0xC1, 0x01, - 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x87, 0x47, - 0xC7, 0x1C, 0x5A, 0xC9, 0xEE, 0xA1, 0xC1, 0x01, - 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x97, 0x40, - 0xC2, 0x79, 0xEB, 0x90, 0x4A, 0x9A, 0xEE, 0x36, - 0xB4, 0x0F, 0x19, 0x62, 0xB8, 0x68, 0x08, 0xC8, - 0x48, 0x93, 0x25, 0x49, 0x91, 0x21, 0x41, 0x81, - 0x01, 0xDA, 0xA0, 0xD4, 0x0C, 0xDC, 0x6C, 0xB4, - 0x34, 0x8F, 0xC1, 0xB4, 0x6C, 0xBC, 0x30, 0xF0, - 0x70, 0xAB, 0x1D, 0x71, 0xA9, 0x19, 0x78, 0xB8, - 0x38, 0xE3, 0x54, 0x38, 0xE1, 0x51, 0x30, 0xF8, - 0x38, 0xE3, 0x54, 0x39, 0xE0, 0x51, 0x70, 0xA0, - 0x24, 0xFD, 0x6A, 0x02, 0xFB, 0x4F, 0x0E, 0x4A, - 0xDA, 0x43, 0xE4, 0x99, 0x50, 0xF1, 0xD8, 0x3A, - 0x9E, 0x67, 0x98, 0xE6, 0x77, 0xD5, 0xFC, 0x6E, - 0xD7, 0x1E, 0xFD, 0x80, 0x0D, 0xAC, 0x99, 0x4C, - 0x99, 0x53, 0x4F, 0x09, 0x7B, 0xE1, 0x2B, 0x41, - 0x6B, 0x9A, 0x79, 0x40, 0xCD, 0x28, 0x1D, 0x88, - 0x5D, 0x53, 0xB0, 0x09, 0x84, 0xE1, 0x2B, 0x01, - 0x2B, 0x1E, 0x02, 0x80, 0xF2, 0xAC, 0x7A, 0x17, - 0x21, 0x17, 0x17, 0x96, 0xF8, 0xA5, 0x73, 0x6E, - 0x35, 0x33, 0x6B, 0xE9, 0xDF, 0x81, 0x3F, 0x84, - 0xEB, 0x8D, 0xE5, 0x72, 0x74, 0x3F, 0xE1, 0xCE, - 0xB5, 0x93, 0xDB, 0x49, 0x6F, 0x21, 0xBF, 0x88, - 0xB7, 0x93, 0xDB, 0x48, 0x6E, 0x21, 0xBE, 0x81, - 0xFE, 0xDA, 0x58, 0x2D, 0xF5, 0x25, 0x7D, 0xA4, - 0x24, 0x9F, 0xD5, 0xA0, 0x78, 0xA8, 0xFC, 0x3C, - 0xBC, 0x67, 0xD1, 0xBD, 0x65, 0xD5, 0xB5, 0x75, - 0xF5, 0x2E, 0x98, 0xF4, 0x2C, 0x9C, 0xFC, 0x3C, - 0xBC, 0x67, 0xF9, 0x9C, 0x44, 0x94, 0xD0, 0x19, - 0x99, 0x22, 0x84, 0x58, 0x82, 0x32, 0x52, 0x88, - 0x08, 0xB3, 0x75, 0x18, 0xC0, 0x70, 0x6C, 0xAB, - 0x2B, 0x90, 0x9A, 0xFB, 0x21, 0xF1, 0xAD, 0x65, - 0xE5, 0x5E, 0xFC, 0x9E, 0x44, 0x94, 0x38, 0xF6, - 0x74, 0xCF, 0xED, 0x87, 0x5F, 0x8F, 0x4B, 0x84, - 0x06, 0xBD, 0x4F, 0x25, 0xFD, 0x2D, 0xC1, 0x0E, - 0x8C, 0x37, 0x71, 0x04, 0xDC, 0x0C, 0xB8, 0x77, - 0xF5, 0x4E, 0x48, 0x35, 0xEF, 0x3F, 0xE7, 0x2F, - 0xAF, 0x14, 0x82, 0xFC, 0x26, 0xF6, 0x2A, 0xED, - 0x6D, 0xD6, 0x34, 0x4A, 0x90, 0x40, 0xE8, 0x3A, - 0xB8, 0x03, 0x5D, 0x37, 0xEF, 0x3F, 0x3B, 0xE3, - 0x61, 0xDA, 0x2C, 0x4A, 0x92, 0x42, 0x14, 0x95, - 0x15, 0x4F, 0x7B, 0x11, 0x78, 0x48, 0x2E, 0xF2, - 0x78, 0x32, 0x05, 0x6F, 0x15, 0xEE, 0x8E, 0xC7, - 0x4E, 0xB0, 0x04, 0x68, 0x55, 0xE1, 0x81, 0xE4, - 0x66, 0xBD, 0xEE, 0x87, 0x5F, 0x0A, 0x62, 0xA2, - 0x07, 0xDF, 0x69, 0xA0, 0x71, 0xC1, 0x00, 0x43, - 0xC5, 0xAF, 0x9D, 0xF7, 0x8A, 0x60, 0x27, 0xFA, - 0x8A, 0x51, 0xD1, 0xFC, 0x24, 0xA5, 0x40, 0x86, - 0x27, 0x7A, 0xCA, 0x8F, 0x84, 0x29, 0xB9, 0x79, - 0xF9, 0x22, 0xA2, 0x8F, 0x57, 0xD6, 0x31, 0xF7, - 0x56, 0x05, 0xB5, 0xF0, 0x6B, 0xC6, 0x56, 0x96, - 0x16, 0xCD, 0x4D, 0x60, 0xB8, 0x39, 0xDC, 0x1A, - 0xBB, 0xE9, 0x59, 0x1C, 0x57, 0xFA, 0x6A, 0xAA, - 0x2A, 0xF1, 0x71, 0x5C, 0x84, 0x15, 0xF8, 0x3E, - 0x8F, 0xD8, 0x68, 0x95, 0xC7, 0x71, 0x90, 0xDB, - 0x5D, 0x0F, 0xF0, 0xB5, 0x6E, 0xC3, 0x53, 0x93, - 0x13, 0xC8, 0x48, 0x65, 0xBD, 0x9C, 0x72, 0xB4, - 0x38, 0xEB, 0xDF, 0xFA, 0x22, 0xF7, 0x96, 0x56, - 0x77, 0x3C, 0x8C, 0x51, 0x0E, 0xB8, 0x19, 0x56, - 0xD0, 0xC2, 0x7F, 0xBA, 0x39, 0x94, 0x04, 0xC4, - 0x44, 0x9F, 0x1F, 0x32, 0xEA, 0x6B, 0x9A, 0x5C, - 0xFD, 0xB4, 0x04, 0x41, 0x8A, 0x27, 0xB7, 0x77, - 0xF7, 0x2C, 0xAC, 0x81, 0x59, 0x68, 0x9C, 0x5A, - 0xEB, 0xA3, 0x13, 0x5E, 0x13, 0xA5, 0xEC, 0x0F, - 0x06, 0x8E, 0x25, 0xB9, 0x61, 0xD1, 0x87, 0x06, - 0x86, 0xCC, 0xEC, 0x86, 0xDF, 0xF8, 0x9E, 0xD7, - 0x7E, 0xC0, 0x76, 0x1A, 0xDF, 0x9F, 0xC9, 0x48, - 0xC8, 0xB2, 0x9C, 0xF6, 0x9C, 0x8C, 0x60, 0x08, - 0x82, 0x79, 0xAE, 0xC2, 0x92, 0x08, 0xD2, 0xA8, - 0xB4, 0x77, 0xCD, 0xBD, 0x69, 0x54, 0xD6, 0x3C, - 0x94, 0x8F, 0x19, 0x75, 0x7F, 0x81, 0xED, 0xEF, - 0x24, 0xD8, 0x4B, 0x80, 0x7B, 0xEB, 0x6D, 0xBE, - 0x2E, 0xD5, 0x63, 0x12, 0x3A, 0x8A, 0xEA, 0x2A, - 0xAA, 0x71, 0xC7, 0xAB, 0x73, 0xC3, 0xA3, 0x63, - 0xE3, 0x38, 0x8F, 0xE3, 0x3F, 0x8F, 0x8B, 0x51, - 0xD3, 0x68, + 0x06, 0x6B, 0x06, 0x6A, 0x76, 0xC8, 0x18, 0xD4, + 0x54, 0xEF, 0x71, 0x14, 0xCC, 0x1C, 0x58, 0x91, + 0x11, 0xAA, 0x80, 0xF4, 0x2C, 0xFC, 0x9F, 0x5F, + 0xDF, 0x04, 0x02, 0x62, 0xBA, 0x6A, 0x5A, 0x97, + 0x17, 0xCC, 0x46, 0x22, 0xFA, 0x2A, 0xBE, 0x03, + 0x87, 0x3C, 0x9E, 0xFE, 0x26, 0xF6, 0x96, 0x7E, + 0xFA, 0x11, 0x27, 0x66, 0xBA, 0x3A, 0x5A, 0xBA, + 0x3E, 0xD5, 0x4F, 0x03, 0xDF, 0x5F, 0x7F, 0x9F, + 0x1B, 0xF0, 0xA2, 0xEF, 0x33, 0xB3, 0xD3, 0x13, + 0x93, 0x70, 0xFA, 0x96, 0x4E, 0xC6, 0xA6, 0xC6, + 0x46, 0xA5, 0x2F, 0xE3, 0x3B, 0xB3, 0xD3, 0x33, + 0xB3, 0x50, 0xE8, 0xA4, 0x7C, 0xF4, 0x94, 0x14, + 0x94, 0x77, 0xC9, 0xE5, 0x3D, 0xB5, 0xD5, 0x75, + 0xF5, 0x16, 0xA8, 0xA4, 0x7C, 0xF4, 0x94, 0xD4, + 0x54, 0xB7, 0x09, 0xE5, 0x3D, 0xB5, 0x2D, 0xF4, + 0x74, 0xCF, 0x29, 0x5C, 0x84, 0x54, 0x14, 0xAA, + 0x2E, 0x95, 0xF7, 0xE0, 0x3C, 0xEC, 0x8C, 0x52, + 0xD6, 0x3D, 0x7B, 0x0E, 0xD6, 0x06, 0x82, 0x49, + 0xC9, 0x72, 0x7C, 0x18, 0xC0, 0x10, 0x10, 0xF6, + 0x72, 0xC9, 0xC3, 0xA8, 0x70, 0xA0, 0xD8, 0x77, + 0xF3, 0x48, 0x06, 0x04, 0xD8, 0x08, 0x90, 0x5B, + 0xDB, 0x60, 0x36, 0x43, 0x9B, 0x4B, 0xD4, 0xE3, + 0x9C, 0xB8, 0xF1, 0x72, 0x55, 0x1A, 0x8E, 0x57, + 0xD7, 0x6C, 0xDA, 0xBE, 0x66, 0xD6, 0xEA, 0x3D, + 0xBF, 0x04, 0xB2, 0xCE, 0x16, 0xA6, 0x06, 0xDE, + 0x5E, 0xE5, 0xB7, 0xC3, 0x1B, 0xCB, 0x47, 0x9F, + 0x1F, 0xA4, 0x3E, 0x5B, 0x83, 0x53, 0x53, 0x8A, + 0x0A, 0xB1, 0x93, 0xF9, 0x21, 0xF1, 0x31, 0xE6, + 0x64, 0xDF, 0x95, 0xE0, 0x38, 0xE8, 0xB4, 0x6D, + 0xED, 0x56, 0x1D, 0x8E, 0x56, 0xE6, 0x79, 0xB9, + 0xC6, 0xE2, 0x62, 0x4F, 0x97, 0x02, 0x40, 0x80, + 0x65, 0xB8, 0x0E, 0x07, 0xC2, 0x72, 0x37, 0xBE, + 0x3E, 0x00, 0xF2, 0xB8, 0xF1, 0x6D, 0x0E, 0x6F, + 0xC2, 0x1A, 0xA0, 0xC4, 0x95, 0x2F, 0xCD, 0x44, + 0xC4, 0x02, 0x44, 0x28, 0xF0, 0x40, 0x16, 0x97, + 0x17, 0x7D, 0xE4, 0x8B, 0xFE, 0x4C, 0x0D, 0xE3, + 0x60, 0xFD, 0x4B, 0x27, 0x34, 0xA6, 0xCD, 0xB6, + 0x10, 0xC0, 0x7C, 0x98, 0x42, 0x72, 0x92, 0x26, + 0x21, 0x60, 0x26, 0x4C, 0x95, 0x25, 0xA0, 0x03, + 0xA6, 0x50, 0xEC, 0x9D, 0xB5, 0x05, 0x53, 0xD2, + 0x52, 0xA9, 0x7E, 0x12, 0x2F, 0x65, 0xFA, 0x1A, + 0x7C, 0xB4, 0x12, 0x5E, 0x86, 0x3A, 0x50, 0xF5, + 0x53, 0xAD, 0xBA, 0xE6, 0x3D, 0x3C, 0x6D, 0xAE, + 0xCB, 0x33, 0xAD, 0xDC, 0xF4, 0x44, 0x12, 0x93, + 0x13, 0xF9, 0x7D, 0x12, 0xEB, 0x68, 0x0B, 0xE2, + 0x21, 0xE7, 0xA1, 0xCD, 0x15, 0xA5, 0xF3, 0x72, + 0xF2, 0xAB, 0x1F, 0x7E, 0xAA, 0x01, 0xE1, 0xA1, + 0x25, 0xA8, 0x06, 0x6D, 0xB9, 0x0C, 0x60, 0xA6, + 0x64, 0xAD, 0x15, 0x65, 0xBA, 0x30, 0x14, 0x66, + 0x22, 0x78, 0xFC, 0x94, 0x4C, 0x4E, 0x25, 0x9B, + 0xD9, 0x06, 0xB1, 0xEA, 0x89, 0x35, 0x62, 0x1E, + 0x8F, 0x69, 0xD4, 0x7F, 0x1C, 0xA0, 0xFD, 0x31, + 0x77, 0xAD, 0x1B, 0x40, 0xA4, 0x10, 0xB7, 0xCC, + 0x4D, 0xAB, 0x16, 0xD7, 0x0C, 0x01, 0x62, 0x87, + 0xBF, 0x4C, 0x50, 0x5A, 0xD8, 0x3B, 0x50, 0xE7, + 0x2C, 0xB3, 0xB7, 0x1F, 0x46, 0xA0, 0x57, 0x6B, + 0x46, 0x98, 0x93, 0xFA, 0xC7, 0xC1, 0x89, 0x45, + 0xDE, 0xD7, 0xC3, 0xC3, 0xBB, 0xCF, 0xEE, 0xEE, + 0xA8, 0xB3, 0xDF, 0x61, 0x4B, 0xE6, 0x04, 0x04, + 0x40, 0xDA, 0xAC, 0x43, 0xDA, 0x9A, 0x15, 0x25, + 0x45, 0x7D, 0xEA, 0x0C, 0x3A, 0x7A, 0xD4, 0x87, + 0xC5, 0x43, 0x77, 0x1D, 0xC6, 0x76, 0xD4, 0xB6, + 0x5A, 0x4B, 0x3F, 0x91, 0x55, 0x98, 0xC2, 0xCE, + 0x8C, 0x5B, 0xED, 0x53, 0x99, 0x20, 0x6D, 0xA6, + 0xF1, 0x96, 0x21, 0x41, 0xBB, 0x16, 0x86, 0x46, + 0xC6, 0x1D, 0x9D, 0xB0, 0x68, 0x69, 0x3D, 0xFE, + 0xC6, 0x16, 0x2C, 0x2B, 0x51, 0x40, 0x40, 0x2A, + 0x01, 0xBF, 0xB3, 0xFF, 0x8A, 0x38, 0x3D, 0x51, + 0xF4, 0x32, 0x74, 0x18, 0xC0, 0x70, 0x26, 0xA7, + 0x27, 0x5D, 0xDE, 0xB1, 0xD8, 0x5E, 0x3D, 0x30, + 0xB2, 0x0C, 0xEC, 0xA5, 0xCC, 0x44, 0x27, 0xC7, + 0x6D, 0x16, 0x01, 0x5A, 0x81, 0xFC, 0x9E, 0x3B, + 0xEE, 0x10, 0x17, 0x41, 0x9A, 0x0A, 0x50, 0x30, + 0x72, 0x6A, 0xCC, 0x01, 0xE0, 0x53, 0x3F, 0xFD, + 0x54, 0x8C, 0x13, 0x6C, 0x9D, 0x0E, 0x47, 0xB4, + 0xD1, 0x59, 0xCA, 0x17, 0xF3, 0x40, 0x10, 0xEA, + 0xCA, 0xD3, 0xA6, 0xDA, 0xA3, 0x28, 0x4B, 0x6E, + 0xBC, 0x42, 0xF8, 0x9D, 0x75, 0xFF, 0x3F, 0xCD, + 0x8E, 0x45, 0xE8, 0x1D, 0xEC, 0x5F, 0x74, 0x87, + 0x61, 0x23, 0x63, 0xA2, 0x79, 0x7B, 0xBB, 0xDE, + 0x72, 0xE5, 0xB6, 0x7B, 0x8B, 0x9A, 0xC7, 0x04, + 0x35, 0xD0, 0x65, 0xCB, 0xD0, 0x44, 0x41, 0xD1, + 0x74, 0x1E, 0xE8, 0x87, 0x6F, 0xE5, 0x25, 0x44, + 0xFB, 0x23, 0xA7, 0x08, 0xF4, 0x89, 0xEA, 0xCF, + 0x1E, 0xE0, 0xE7, 0xC9, 0x12, 0x92, 0xC8, 0xA8, + 0x89, 0x13, 0xA6, 0x07, 0xDC, 0xC9, 0xFA, 0x1F, + 0x2E, 0xB1, 0x04, 0x58, 0xBA, 0xAA, 0x6B, 0xE8, + 0x6B, 0x7D, 0xC8, 0x01, 0x8B, 0x1E, 0xCF, 0x49, + 0xCA, 0x21, 0xAD, 0x61, 0x18, 0xED, 0x8E, 0x83, + 0x00, 0x3E, 0xD9, 0x90, 0x78, 0xE2, 0x22, 0xFF, + 0x8F, 0x54, 0xD4, 0xF9, 0x21, 0x10, 0x37, 0xF4, + 0xFC, 0x2F, 0x15, 0x31, 0x48, 0xB0, 0xD3, 0x36, + 0xC1, 0x32, 0x99, 0x05, 0xDD, 0x6D, 0x3B, 0xBA, + 0x3A, 0x60, 0x91, 0xFE, 0xAE, 0x16, 0xFA, 0x72, + 0x53, 0xC0, 0x75, 0xFC, 0x51, 0xC9, 0x0C, 0x38, + 0x99, 0x5F, 0x19, 0x75, 0xAD, 0x1D, 0x4B, 0xCA, + 0x4A, 0x3C, 0x88, 0x01, 0x40, 0xD2, 0x33, 0xB4, + 0x37, 0x64, 0xDA, 0x3A, 0xAA, 0xBB, 0x93, 0x50, + 0xF5, 0x5A, 0xC4, 0xB5, 0x9D, 0x2D, 0x7B, 0xFA, + 0x7A, 0x84, 0x17, 0x7B, 0x22, 0xD8, 0xBB, 0xEA, + 0x58, 0x80, 0x97, 0xB2, 0x69, 0x70, 0x49, 0x00, + 0x89, 0x4F, 0x09, 0x65, 0xBD, 0x0D, 0x5B, 0xDA, + 0x5A, 0xB0, 0x32, 0x5D, 0x89, 0x1E, 0x46, 0x85, + 0x54, 0xC4, 0x71, 0x8F, 0x54, 0xEC, 0xEE, 0x8F, + 0x7F, 0xAF, 0x90, 0xEA, 0x7A, 0xCC, 0x7D, 0xF1, + 0x72, 0xA5, 0x79, 0x19, 0xC6, 0xF4, 0x5D, 0x61, + 0xF7, 0x24, 0x98, 0xD2, 0x53, 0xEB, 0x26, 0xE4, + 0x01, 0x67, 0xF7, 0xB6, 0x64, 0xC9, 0x59, 0xF3, + 0x30, 0x59, 0xFC, 0x9B, 0xD1, 0x65, 0x05, 0xD3, + 0x68, 0xB8, 0x68, 0x7D, 0xB5, 0xC7, 0xB3, 0x8F, + 0x59, 0x2E, 0x92, 0x5C, 0xC7, 0x7F, 0x3D, 0xFE, + 0x73, 0x88, 0x1F, 0x77, 0xB2, 0xF2, 0x9E, 0x55, + 0x57, 0x8F, 0x34, 0x9A, 0x61, 0x0C, 0x7B, 0xD3, + 0x5C, 0x15, 0xAE, 0xC2, 0x16, 0xB4, 0xC2, 0x2B, + 0xA5, 0x75, 0x6A, 0xA4, 0x31, 0x81, 0xA7, 0x67, + 0xE7, 0x30, 0x84, 0x28, 0xD0, 0x60, 0xA2, 0x71, + 0xF9, 0xE0, 0x33, 0xFF, 0xAB, 0x01, 0x04, 0x22, + 0x84, 0x42, 0x04, 0x02, 0x99, 0xFB, 0x9F, 0x5F, + 0xB9, 0x7F, 0xF5, 0x21, 0xDB, 0xC6, 0xA5, 0x00, + 0x60, 0x9D, 0x8B, 0x07, 0xAB, 0x7D, 0x03, 0xE2, + 0xD3, 0x45, 0xF0, 0x6E, 0xBD, 0x0D, 0x4B, 0xA4, + 0x23, 0x8A, 0x77, 0x1B, 0xCF, 0x75, 0x30, 0x96, + 0x33, 0xE4, 0x6A, 0x94, 0x6F, 0x01, 0xA1, 0x41, + 0xC1, 0x88, 0x5B, 0x97, 0xCD, 0x3E, 0x56, 0xD0, + 0x53, 0x88, 0x9C, 0xE3, 0x3C, 0x00, 0x1A, 0xA8, + 0x6C, 0xB7, 0xA3, 0xDC, 0x03, 0x96, 0x14, 0xF2, + 0x7E, 0xB7, 0x1C, 0x80, 0xEA, 0x49, 0x21, 0x8B, + 0x48, 0x85, 0xF8, 0x93, 0x89, 0x3D, 0x5D, 0x5F, + 0x13, 0x33, 0x93, 0xC3, 0x1C, 0x4E, 0x2D, 0xE0, + 0xE2, 0x1D, 0x2A, 0x51, 0xE7, 0x07, 0xF5, 0x38, + 0xB8, 0x75, 0x4A, 0x2A, 0xFE, 0x5C, 0x37, 0x0E, + 0x7C, 0xEA, 0x5C, 0xB6, 0x7E, 0xCE, 0x2C, 0x25, + 0x5C, 0xD1, 0xFF, 0x66, 0x06, 0x94, 0x59, 0x9A, + 0x7F, 0x7D, 0xED, 0x21, 0x69, 0xAD, 0xC6, 0x9F, + 0x49, 0x7B, 0xC7, 0xA7, 0x74, 0xC8, 0xE4, 0xC6, + 0x65, 0x63, 0x07, 0xC9, 0x65, 0x0F, 0xBC, 0xBC, + 0x1C, 0xC7, 0xD3, 0xAC, 0x7C, 0x2E, 0x2B, 0x4B, + 0xB9, 0x3F, 0xF7, 0x59, 0xC2, 0x7A, 0x0C, 0x86, + 0xF4, 0x23, 0xFB, 0x75, 0xE9, 0x59, 0x9B, 0x48, + 0xC0, 0x7E, 0x13, 0x59, 0x07, 0x72, 0xED, 0x00, + 0x87, 0x50, 0xE9, 0x45, 0xBD, 0x0D, 0xCF, 0x1C, + 0x94, 0xCD, 0x1E, 0xD2, 0x1C, 0x36, 0xA5, 0x80, + 0xD9, 0x24, 0x8F, 0x13, 0xC7, 0x75, 0x53, 0x5B, + 0x24, 0x47, 0xD3, 0x12, 0xC9, 0x5C, 0xE8, 0x0E, + 0x2E, 0x65, 0xA7, 0xAD, 0x6C, 0xFB, 0x97, 0x5C, + 0x0E, 0xF6, 0x9D, 0x33, 0x49, 0x8D, 0x27, 0x24, + 0x64, 0x9F, 0x29, 0x97, 0x2A, 0x3A, 0xF8, 0x2B, + 0xA3, 0x0A, 0xE0, 0xF2, 0x96, 0x7C, 0x76, 0x55, + 0xD9, 0x6F, 0x0B, 0x29, 0xF1, 0xE3, 0x90, 0x58, + 0xBD, 0xB0, 0x20, 0xCA, 0x1B, 0xAB, 0xC7, 0x78, + 0xF4, 0x7B, 0x8F, 0xA0, 0x70, 0xAA, 0x89, 0xBB, + 0x7F, 0xA4, 0xA0, 0xDF, 0x0C, 0x20, 0x0B, 0x79, + 0xAD, 0x8A, 0x30, 0xA6, 0x72, 0x4A, 0xA8, 0x2C, + 0xAC, 0x12, 0x70, 0x3A, 0x70, 0xD4, 0x48, 0x1A, + 0x53, 0x79, 0x5D, 0x65, 0x41, 0xD3, 0xB0, 0x7D, + 0xDD, 0x27, 0x95, 0xE4, 0xCC, 0x51, 0x36, 0x70, + 0x2F, 0x0B, 0x1F, 0x67, 0x43, 0xE5, 0x5F, 0x77, + 0xFB, 0xA8, 0x9C, 0xB4, 0x6C, 0x6A, 0xB0, 0x60, + 0xEC, 0xCD, 0xDE, 0x63, 0x9D, 0x0F, 0x7B, 0x47, + 0xE5, 0xFC, 0xBB, 0xF5, 0x79, 0x35, 0x53, 0x0E, + 0x71, 0x4F, 0x29, 0x63, 0x96, 0x21, 0x07, 0x3B, + 0x44, 0x9F, 0x1F, 0x32, 0xEA, 0x0B, 0x5F, 0x9C, + 0x44, 0x9A, 0x6E, 0xA2, 0x8A, 0x70, 0x55, 0xA7, + 0x23, 0x78, 0xE8, 0xA7, 0x4E, 0xD8, 0xFB, 0x08, + 0xE9, 0x79, 0xCC, 0xD1, 0x45, 0xF6, 0x9A, 0xF2, + 0x54, 0xEC, 0x75, 0x7F, 0x24, 0x8A, 0xE6, 0x55, + 0x47, 0xB9, 0xD1, 0x7D, 0x85, 0x35, 0xC7, 0x61, + 0x41, 0xA8, 0x5A, 0xB6, 0xDC, 0x69, 0x04, 0x66, + 0xE1, 0x3A, 0x3C, 0xE1, 0x3D, 0x3D, 0xF5, 0xA6, + 0x84, 0x18, 0xAE, 0xDF, 0xF7, 0x5A, 0xCA, 0x06, + 0x95, 0x08, 0xBE, 0xD2, 0x06, 0x85, 0xD7, 0x53, + 0x53, 0x95, 0xD3, 0xB3, 0x38, 0x4A, 0x0F, 0x11, + 0x51, 0xAA, 0x1C, 0xB2, 0x0C, 0x1C, 0xBA, 0x89, + 0xF6, 0x2D, 0xAD, 0x80, 0x58, 0xD9, 0xF7, 0x34, + 0x95, 0x01, 0xB4, 0xF1, 0x3A, 0x97, 0x07, 0xC7, + 0x47, 0x9C, 0x1C, 0x31, 0xE9, 0xC8, 0x9C, 0x5F, + 0x47, 0x95, 0xAF, 0x6A, 0x10, 0x89, 0x34, 0x54, + 0x74, 0xBB, 0x2B, 0x7D, 0xA7, 0xF2, 0xD0, 0x31, + 0xAC, 0x87, 0x07, 0x2A, 0xF2, 0xE3, 0xD2, 0x11, + 0xB0, 0x21, 0x94, 0xC9, 0x23, 0x90, 0x61, 0xF1, + 0x72, 0x28, 0xCC, 0xA3, 0xF2, 0x6B, 0x22, 0xE1, + 0xC8, 0x4A, 0xE1, 0x7D, 0xA5, 0x15, 0x43, 0xC2, + 0x42, 0xB8, 0x5D, 0x32, 0x62, 0xF0, 0x57, 0xFF, + 0x62, 0x18, 0xFA, 0x95, 0x28, 0xD1, 0x99, 0xC8, + 0x1D, 0xC5, 0xB2, 0x88, 0x53, 0x52, 0x65, 0xA6, + 0x8E, 0x77, 0x79, 0x1E, 0x06, 0x1C, 0x6C, 0x3C, + 0x26, 0xED, 0xEB, 0x1D, 0x56, 0x7F, 0x3D, 0x58, + 0x11, 0xEF, 0x44, 0xD8, 0x00, 0xB0, 0xE6, 0x67, + 0xE7, 0x9D, 0x7F, 0x10, 0x2D, 0xDF, 0x97, 0xB6, + 0x6E, 0xB6, 0x41, 0x1F, 0xC4, 0x45, 0x76, 0xB5, + 0x39, 0xEE, 0x80, 0xCF, 0xE6, 0x01, 0x62, 0x15, + 0xF8, 0x01, 0x0A, 0x69, 0x79, 0xCD, 0x64, 0xAB, + 0x86, 0x5F, 0x68, 0x5D, 0x86, 0xD6, 0x2B, 0xCB, + 0xD2, 0x2A, 0x15, 0x7D, 0xC0, 0x38, 0x58, 0x29, + 0xF3, 0x2B, 0x35, 0x7A, 0xAE, 0x1C, 0xCC, 0xA6, + 0x06, 0x74, 0xE1, 0x90, 0xB8, 0x04, 0x6F, 0x69, + 0x1F, 0x3B, 0xBB, 0x96, 0x4E, 0xE2, 0x4A, 0x0D, + 0x1F, 0xC0, 0x57, 0x60, 0xBB, 0x16, 0x86, 0xEB, + 0x69, 0x97, 0xE3, 0xAA, 0x5F, 0xE5, 0x98, 0xA8, + 0x28, 0xF3, 0x73, 0x5E, 0x86, 0x47, 0x60, 0xA3, + 0xFF, 0x70, 0x4E, 0x25, 0x71, 0x89, 0x4C, 0x92, + 0x12, 0x8F, 0x38, 0x54, 0x2D, 0xD5, 0xB6, 0x53, + 0xEF, 0x1C, 0x02, 0x69, 0xBD, 0x04, 0xF6, 0x7C, + 0x64, 0x0D, 0x1B, 0x04, 0x96, 0x45, 0xE7, 0x87, + 0x73, 0xCF, 0x45, 0x3A, 0x5F, 0xED, 0x25, 0xE2, + 0xAF, 0x77, 0x8B, 0x4D, 0x37, 0x4D, 0x09, 0x6C, + 0xA9, 0x5A, 0x5E, 0x92, 0x39, 0x4F, 0x2A, 0xEA, + 0x2D, 0xCD, 0x6F, 0xBE, 0x64, 0x7C, 0x1B, 0x19, + 0x39, 0x96, 0x60, 0xC0, 0xD8, 0x22, 0xE8, 0x8A, + 0xC0, 0x3F, 0x6C, 0x43, 0xB3, 0xB1, 0x71, 0xC2, + 0xFE, 0x70, 0xA1, 0xF6, 0x26, 0x34, 0xF0, 0x35, + 0x50, 0x5A, 0xC8, 0xE2, 0x3D, 0x8D, 0x5F, 0x3F, + 0xCB, 0x77, 0x7A, 0x1E, 0x64, 0x70, 0x16, 0x33, + 0x63, 0x9C, 0xAC, 0xC3, 0x1B, 0xA7, 0xCD, 0xD5, + 0x52, 0x85, 0x2F, 0x81, 0x14, 0x3C, 0xB9, 0xB6, + 0x12, 0xEC, 0x5E, 0x32, 0x02, 0xB5, 0x37, 0xF9, + 0xE1, 0xF6, 0x0E, 0xC3, 0x53, 0xE0, 0x25, 0xDD, + 0x75, 0xB3, 0xF5, 0x99, 0x41, 0xF1, 0xA7, 0x26, + 0xA6, 0x4C, 0xBD, 0xD2, 0x32, 0x81, 0xC0, 0x5C, + 0xDF, 0x2D, 0xE8, 0x0F, 0x54, 0x76, 0xD5, 0x01, + 0x18, 0xA0, 0x8F, 0xB0, 0xE1, 0x62, 0x8B, 0x68, + 0xCA, 0xD3, 0x99, 0xDC, 0x47, 0xEA, 0x7A, 0xBA, + 0x3A, 0xE1, 0x61, 0x4C, 0x94, 0xC1, 0xB2, 0x72, + 0xEF, 0xC4, 0x44, 0x69, 0xB1, 0x0D, 0x27, 0x42, + 0xE2, 0x1B, 0x8C, 0xA7, 0x7C, 0x41, 0x2B, 0x73, + 0xF1, 0x26, 0x8A, 0x64, 0xD5, 0x42, 0x87, 0x58, + 0xFA, 0x5D, 0x37, 0x27, 0x11, 0xAD, 0xE5, 0x9D, + 0x1F, 0xC8, 0x69, 0xA7, 0x14, 0x8C, 0x5D, 0xD6, + 0x55, 0x4E, 0xD8, 0xB4, 0xFE, 0x65, 0xAD, 0xAD, + 0x0D, 0xD6, 0x10, 0xE5, 0x1D, 0x3F, 0x34, 0x5C, + 0x1C, 0xE7, 0x51, 0xCF, 0x3C, 0x24, 0x84, 0x64, + 0xE4, 0xBF, 0xF6, 0xBA, 0x90, 0x4B, 0x83, 0x83, + 0x23, 0xF8, 0x9C, 0xDB, 0xA9, 0xD9, 0x99, 0x59, + 0x39, 0x3F, 0x99, 0x27, 0x94, 0x8E, 0x2E, 0xCE, + 0x4E, 0x37, 0xAA, 0x6C, 0x74, 0xE4, 0x84, 0x84, + 0xAE, 0x65, 0x71, 0x76, 0x04, 0x15, 0x28, 0xEB, + 0xCE, 0x00, 0x94, 0xF4, 0x2F, 0x27, 0x45, 0x89, + 0x0F, 0xD8, 0x2B, 0xA7, 0x3C, 0x9D, 0xF1, 0x38, + 0x88, 0xB0, 0xF6, 0x7A, 0x4C, 0xED, 0x3D, 0x0E, + 0x2E, 0x97, 0x4E, 0x08, 0xDC, 0x73, 0xDB, 0x19, + 0x09, 0x7B, 0x3D, 0x4A, 0x0B, 0x2B, 0xDB, 0x6F, + 0x05, 0x12, 0x6E, 0xC8, 0xC2, 0x7E, 0x37, 0x75, + 0xF9, 0x08, 0x0C, 0x6C, 0x91, 0xA1, 0x49, 0x98, + 0xA8, 0xC0, 0x37, 0xE9, 0x7D, 0xE8, 0x58, 0x10, + 0xB0, 0xB3, 0x07, 0xD6, 0x06, 0x36, 0xE9, 0xAA, + 0xC0, 0xC6, 0xC0, 0x54, 0xCD, 0x8F, 0xA3, 0x49, + 0x13, 0x62, 0x56, 0x30, 0xC0, 0xC2, 0xEE, 0x07, + 0x07, 0x58, 0xAF, 0x41, 0xD3, 0x4B, 0x4D, 0xC4, + 0xFE, 0xAD, 0x19, 0xD8, 0x03, 0x39, 0xCA, 0x80, + 0xB4, 0xDD, 0x40, 0x06, 0x54, 0x6A, 0xBA, 0xC1, + 0xB1, 0xD0, 0xEE, 0x00, 0xD0, 0x47, 0xA5, 0x2C, + 0x44, 0x17, 0xA3, 0xC3, 0x10, 0x20, 0x93, 0xC3, + 0xC9, 0xE6, 0xA2, 0xE1, 0x13, 0x29, 0xA7, 0x97, + 0xE8, 0xC3, 0x8F, 0x0D, 0x17, 0xA9, 0xE3, 0xC1, + 0x4F, 0xBD, 0x8B, 0x2B, 0xE2, 0xB2, 0x1E, 0xFE, + 0xBC, 0x3A, 0xE0, 0xE9, 0x20, 0x90, 0xFC, 0x35, + 0xBE, 0x30, 0x3E, 0x50, 0x93, 0x10, 0x40, 0xB0, + 0x44, 0xAF, 0xFA, 0x66, 0x04, 0x70, 0x62, 0xCE, + 0x60, 0x5B, 0xAE, 0xD3, 0x5D, 0x58, 0xCD, 0xAF, + 0xE4, 0x2B, 0x1C, 0x2E, 0xF5, 0xD7, 0x9C, 0x79, + 0x6B, 0xDB, 0x44, 0xE8, 0x10, 0xA0, 0x48, 0x80, + 0x89, 0xD9, 0xCA, 0xF1, 0x09, 0xA4, 0x34, 0xF4, + 0x74, 0xAF, 0x2F, 0x02, 0xDA, 0x4B, 0x6C, 0xAF, + 0x87, 0x5E, 0x4A, 0xEC, 0x20, 0xB5, 0x8D, 0x6D, + 0x45, 0x9C, 0xA1, 0x67, 0x9A, 0xB9, 0xFE, 0x32, + 0xF8, 0xC1, 0xD8, 0x34, 0x3D, 0xC6, 0xA5, 0xA5, + 0x05, 0xDE, 0xAA, 0xEB, 0x87, 0xF7, 0xB7, 0x77, + 0x4F, 0x96, 0xC0, 0x60, 0xA8, 0xDA, 0xD7, 0xA3, + 0x91, 0x61, 0xF0, 0xF9, 0x29, 0xBB, 0x63, 0xA1, + 0x2D, 0xEC, 0xE8, 0xAF, 0x5F, 0x0A, 0x6D, 0x8F, + 0x12, 0x39, 0xB9, 0x94, 0x4C, 0xAD, 0x86, 0x45, + 0x05, 0xFE, 0x48, 0x66, 0x9B, 0x9F, 0x3F, 0xDF, + 0x5F, 0xB4, 0x46, 0x3A, 0xA2, 0x50, 0x10, 0x92, + 0x77, 0x18, 0xB3, 0x2F, 0xF7, 0x47, 0x11, 0x90, + 0x10, 0xC7, 0x72, 0x6C, 0x14, 0xD4, 0xE5, 0x62, + 0xE1, 0x36, 0x96, 0x42, 0x9F, 0x1F, 0xBC, 0x8C, + 0xBC, 0xC4, 0xD2, 0x6C, 0x9E, 0x04, 0xD4, 0xD8, + 0xF8, 0xF3, 0x98, 0x04, 0x06, 0x7A, 0x98, 0x54, + 0xF0, 0xCB, 0x3E, 0x43, 0xFD, 0x55, 0x09, 0x2B, + 0x81, 0x74, 0x10, 0x56, 0xBC, 0x47, 0x94, 0xB3, + 0x3E, 0xF2, 0xE6, 0x86, 0x76, 0xC6, 0xBD, 0x3D, + 0xBD, 0xD0, 0xC7, 0xDB, 0xB8, 0x18, 0xD8, 0xB8, + 0x0C, 0x67, 0x7B, 0x37, 0x4F, 0x5F, 0x4B, 0xCD, + 0x4D, 0x96, 0x2C, 0x4A, 0x20, 0x3F, 0xDF, 0x3A, + 0x43, 0x67, 0x69, 0x00, 0x62, 0x06, 0x94, 0x79, + 0xD7, 0x00, 0xAA, 0x36, 0x01, 0xA0, 0x30, 0x3E, + 0x2D, 0x34, 0xEF, 0xAD, 0x6E, 0xED, 0xBD, 0x4D, + 0xB9, 0x04, 0xF1, 0x3D, 0x6E, 0x75, 0xB0, 0xF5, + 0x52, 0x24, 0x90, 0x7D, 0xFB, 0x48, 0xE8, 0x08, + 0x88, 0xDB, 0x65, 0x80, 0x6A, 0x7F, 0x56, 0xB6, + 0x2B, 0x00, 0x80, 0xAD, 0x75, 0x44, 0x63, 0xA0, + 0x00, 0xB9, 0xFF, 0x1B, 0xCB, 0x70, 0x53, 0x13, + 0xA1, 0xEA, 0xDC, 0xE2, 0x9A, 0x58, 0x1D, 0xF7, + 0xF7, 0x4A, 0x5C, 0x40, 0xEF, 0xAF, 0xB5, 0x53, + 0x85, 0xBA, 0x08, 0x46, 0x9C, 0x0A, 0x28, 0x7B, + 0x8B, 0xD0, 0x44, 0x29, 0xD1, 0x49, 0x18, 0x92, + 0x30, 0xEB, 0x7F, 0x02, 0xFA, 0x6A, 0x3B, 0xD9, + 0x0A, 0xA1, 0x55, 0x1C, 0xEE, 0x1E, 0x3A, 0x0A, + 0xC0, 0x5D, 0xA9, 0xC1, 0x3F, 0x2E, 0x11, 0xD2, + 0xD2, 0x4D, 0xFA, 0xD6, 0x46, 0xC7, 0x01, 0xD5, + 0x59, 0x24, 0x50, 0x2F, 0xEB, 0xA9, 0xD5, 0xED, + 0xEF, 0x67, 0xA1, 0x8B, 0x51, 0xE1, 0x67, 0xB5, + 0x33, 0xE4, 0x50, 0x30, 0xE1, 0xC3, 0xF0, 0x40, + 0x60, 0x19, 0x0F, 0xCB, 0x19, 0x0B, 0x0E, 0xFC, + 0x61, 0x4A, 0xDE, 0xB0, 0x4D, 0x7B, 0xF4, 0xCB, + 0x4B, 0x90, 0x10, 0x3D, 0xE5, 0x59, 0x3B, 0xF7, + 0x72, 0xE8, 0x19, 0x76, 0xA2, 0x51, 0xF9, 0x3D, + 0x7D, 0x74, 0x52, 0xAC, 0x69, 0xB5, 0xC3, 0x5A, + 0xDD, 0x0D, 0x32, 0xDE, 0x86, 0xC2, 0x20, 0xBD, + 0x51, 0xDC, 0xE2, 0x88, 0x90, 0xD2, 0x12, 0x30, + 0x9F, 0x6E, 0x64, 0x16, 0xE8, 0x46, 0x09, 0xEF, + 0x41, 0xB6, 0x66, 0x34, 0xBB, 0x59, 0x56, 0xBC, + 0x1C, 0x55, 0x13, 0xBF, 0xFE, 0xEE, 0x2C, 0xE5, + 0x4F, 0x26, 0x99, 0xDC, 0x84, 0x9E, 0xEF, 0x9F, + 0xB5, 0x4E, 0xF4, 0x93, 0xE9, 0x04, 0x08, 0xE2, + 0xCE, 0x87, 0x38, 0x73, 0x39, 0xC3, 0x4B, 0x26, + 0xA4, 0x5A, 0x1F, 0x8C, 0x12, 0xA9, 0xC9, 0x12, + 0x2C, 0xD7, 0xC3, 0x5F, 0x47, 0x5D, 0x9D, 0xEF, + 0x00, 0xF1, 0xF7, 0x20, 0x08, 0x02, 0xC8, 0xBA, + 0x30, 0xC1, 0x95, 0xF3, 0x02, 0x32, 0xE9, 0x38, + 0x58, 0x38, 0xAE, 0x70, 0xF5, 0x29, 0x63, 0x1F, + 0x3D, 0xEC, 0x7D, 0xB3, 0x20, 0x78, 0xB5, 0x77, + 0xFB, 0x2B, 0x78, 0xFB, 0xDC, 0xA4, 0xC0, 0x2A, + 0x76, 0x3F, 0x84, 0x00, 0x74, 0x0D, 0x66, 0x5F, + 0x2D, 0xBB, 0xE5, 0x41, 0x9D, 0x07, 0xBB, 0x99, + 0x14, 0x27, 0x4D, 0xEF, 0x9A, 0x28, 0x44, 0x9F, + 0x3F, 0x66, 0x20, 0x8C, 0xC6, 0xD6, 0x24, 0xCD, + 0x67, 0x7C, 0x42, 0x8E, 0xC6, 0xEF, 0x7F, 0x25, + 0x2D, 0x74, 0xCA, 0x81, 0xDB, 0x26, 0xAE, 0xCB, + 0xA7, 0x83, 0xFD, 0x95, 0x46, 0xC5, 0xBE, 0x5C, + 0xFC, 0x07, 0xC5, 0xFF, 0x34, 0x70, 0x82, 0x6E, + 0xC7, 0x90, 0xAF, 0xC8, 0x99, 0xAB, 0xA7, 0x4E, + 0x02, 0xC1, 0x92, 0x22, 0x05, 0xA8, 0x38, 0xF8, + 0x78, 0xA3, 0x23, 0x0E, 0xD6, 0x27, 0x27, 0xE4, + 0x55, 0xEF, 0x5A, 0xBE, 0x22, 0x1B, 0xF9, 0x00, + 0xC4, 0x02, 0x44, 0x28, 0xF0, 0x40, 0x16, 0x97, + 0x17, 0x6E, 0x1A, 0x66, 0x1B, 0x98, 0xD8, 0x89, + 0x69, 0xB1, 0x8F, 0x61, 0x30, 0xC9, 0xB4, 0x84, + 0x04, 0xDF, 0x5F, 0x72, 0xAA, 0xA7, 0xC5, 0x24, + 0xC6, 0x1E, 0x80, 0xEE, 0x3A, 0x06, 0xED, 0x8F, + 0xAA, 0x73, 0xED, 0x00, 0xBB, 0x08, 0xFA, 0xF8, + 0x68, 0x2A, 0xCE, 0x3B, 0xA1, 0x98, 0x9A, 0xD6, + 0x55, 0xB7, 0x93, 0xE2, 0xCA, 0x7A, 0x2C, 0xAD, + 0x2D, 0xC7, 0x13, 0x7C, 0x9C, 0x2F, 0xFD, 0x2E, + 0xB6, 0x61, 0xCB, 0xA0, 0x93, 0x39, 0xC8, 0x56, + 0xD5, 0xCE, 0xD3, 0x9F, 0xE5, 0x06, 0x7E, 0x7E, + 0xDE, 0x05, 0x2B, 0x4E, 0x14, 0xB7, 0xD1, 0xB3, + 0xF0, 0x3B, 0x17, 0xF3, 0xA2, 0x61, 0x64, 0x88, + 0x28, 0x41, 0xE4, 0x90, 0x5F, 0x04, 0x6A, 0x12, + 0x01, 0x56, 0x7B, 0x9F, 0x4C, 0x51, 0x33, 0x13, + 0x9B, 0x40, 0xDB, 0xBD, 0x78, 0x38, 0x54, 0x96, + 0x0B, 0x20, 0xA0, 0x8D, 0x55, 0xD4, 0xD6, 0x15, + 0xAD, 0x75, 0x71, 0x0F, 0xC3, 0xBB, 0x78, 0x10, + 0xB3, 0xA2, 0xAF, 0x7A, 0x01, 0x16, 0x4D, 0xDC, + 0xFC, 0xBC, 0xCA, 0x24, 0xEF, 0x47, 0xBE, 0xDD, + 0x4A, 0xF9, 0x64, 0xCA, 0xBA, 0xF5, 0x74, 0xD0, + 0x53, 0x70, 0x75, 0xD9, 0x21, 0x91, 0x23, 0xF0, + 0x68, 0x02, 0xFF, 0x90, 0xA8, 0xC5, 0xB5, 0x87, + 0x6C, 0x17, 0x73, 0x4C, 0x8C, 0xFC, 0xBC, 0x7C, + 0x5E, 0xAE, 0x98, 0x34, 0xCC, 0x7C, 0xDC, 0xB6, + 0x26, 0x5F, 0x82, 0x6E, 0xF0, 0x41, 0x21, 0x43, + 0x00, 0xCB, 0x58, 0x13, 0xEB, 0x9B, 0xDB, 0x1B, + 0x0A, 0x8F, 0x3A, 0xD4, 0x1F, 0xA9, 0x51, 0x98, + 0xBA, 0xA2, 0x04, 0xF2, 0xA2, 0x9B, 0x88, 0x2D, + 0x89, 0x72, 0x4C, 0xA3, 0xD6, 0x64, 0xE4, 0x2C, + 0xAC, 0x6A, 0x2C, 0x40, 0x98, 0x28, 0x7E, 0xFF, + 0x7F, 0xE6, 0xF8, 0x6B, 0x22, 0xF7, 0x94, 0xE5, + 0x07, 0xDF, 0x58, 0x7F, 0xA4, 0xAC, 0xC7, 0xC5, + 0x5E, 0x9D, 0x27, 0x66, 0x6E, 0x12, 0x52, 0x50, + 0x8B, 0x48, 0x3E, 0x72, 0xAA, 0xB8, 0xFB, 0x9B, + 0xB2, 0xD2, 0xA4, 0xE8, 0x30, 0x02, 0x41, 0x21, + 0x61, 0x9A, 0x2C, 0xD0, 0x80, 0x20, 0xD2, 0xB3, + 0x33, 0x78, 0x46, 0x0A, 0x50, 0x83, 0x43, 0x43, + 0xE3, 0x38, 0xAC, 0xE3, 0xBB, 0xCB, 0x8B, 0x4B, + 0x8B, 0x72, 0xD4, 0xFA, 0x86, 0x36, 0x16, 0xF4, + 0x54, 0xAD, 0x78, 0x94, 0x51, 0x11, 0x47, 0xC6, + 0x46, 0xFB, 0x79, 0x1D, 0x47, 0xF4, 0xB3, 0xB1, + 0x32, 0xCF, 0x1F, 0x4B, 0x99, 0x84, 0xE6, 0x9B, + 0x18, 0x0E, 0xBC, 0xF5, 0xB5, 0x27, 0x5A, 0x6A, + 0x42, 0xCA, 0xCE, 0x02, 0x21, 0x21, 0x8D, 0x5D, + 0x1F, 0x87, 0x17, 0xBB, 0x43, 0xF3, 0x01, 0xCB, + 0x47, 0x5C, 0xCA, 0xA6, 0xCE, 0xE7, 0x97, 0xC5, + 0x0F, 0xD8, 0x73, 0xEF, 0x37, 0x87, 0xFD, 0x3C, + 0xBC, 0x67, 0xD1, 0xBD, 0x65, 0xD5, 0x51, 0x9C, + 0x1E, 0xA5, 0x17, 0x7A, 0xA2, 0x12, 0x72, 0xB2, + 0x32, 0xE9, 0xEF, 0x8D, 0x57, 0x87, 0xCD, 0x0F, + 0x8F, 0x54, 0xE2, 0x8E, 0x56, 0xE6, 0x66, 0xB4, + 0x36, 0x8D, 0x27, 0x4B, 0x9B, 0x2B, 0x36, 0xF2, + 0x0C, 0xD3, 0xE1, 0x9F, 0x45, 0x95, 0x81, 0x52, + 0xD0, 0x6B, 0x45, 0x3A, 0xE0, 0x30, 0xF0, 0x23, + 0xA1, 0x1A, 0x74, 0x0C, 0xD6, 0x06, 0x7E, 0xAB, + 0x29, 0x92, 0x14, 0x6E, 0xB4, 0x64, 0x30, 0xE5, + 0x67, 0xDC, 0xD2, 0xAB, 0x71, 0xA1, 0xC1, 0x01, + 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x87, 0x47, + 0xC7, 0x1C, 0x5A, 0xC9, 0xEE, 0xA1, 0xC1, 0x01, + 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x87, 0x47, + 0xC7, 0x1C, 0x5A, 0xC9, 0xEE, 0xA1, 0xC1, 0x01, + 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x87, 0x47, + 0xC7, 0x1C, 0x5A, 0xC9, 0xEE, 0xA1, 0xC1, 0x01, + 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x87, 0x47, + 0xC7, 0x1C, 0x5A, 0xC9, 0xEE, 0xA1, 0xC1, 0x01, + 0x81, 0x5A, 0x1C, 0x8F, 0xA8, 0xE7, 0x97, 0x40, + 0xC2, 0x79, 0xEB, 0x90, 0x4A, 0x9A, 0xEE, 0x36, + 0xB4, 0x0F, 0x19, 0x62, 0xB8, 0x68, 0x08, 0xC8, + 0x48, 0x93, 0x25, 0x49, 0x91, 0x21, 0x41, 0x81, + 0x01, 0xDA, 0xA0, 0xD4, 0x0C, 0xDC, 0x6C, 0xB4, + 0x34, 0x8F, 0xC1, 0xB4, 0x6C, 0xBC, 0x30, 0xF0, + 0x70, 0xAB, 0x1D, 0x71, 0xA9, 0x19, 0x78, 0xB8, + 0x38, 0xE3, 0x54, 0x38, 0xE1, 0x51, 0x30, 0xF8, + 0x38, 0xE3, 0x54, 0x39, 0xE0, 0x51, 0x70, 0xA0, + 0x24, 0xFD, 0x6A, 0x02, 0xFB, 0x4F, 0x0E, 0x4A, + 0xDA, 0x43, 0xE4, 0x99, 0x50, 0xF1, 0xD8, 0x3A, + 0x9E, 0x67, 0x98, 0xE6, 0x77, 0xD5, 0xFC, 0x6E, + 0xD7, 0x1E, 0xFD, 0x80, 0x0D, 0xAC, 0x99, 0x4C, + 0x99, 0x53, 0x4F, 0x09, 0x7B, 0xE1, 0x2B, 0x41, + 0x6B, 0x9A, 0x79, 0x40, 0xCD, 0x28, 0x1D, 0x88, + 0x5D, 0x53, 0xB0, 0x09, 0x84, 0xE1, 0x2B, 0x01, + 0x2B, 0x1E, 0x02, 0x80, 0xF2, 0xAC, 0x7A, 0x17, + 0x21, 0x17, 0x17, 0x96, 0xF8, 0xA5, 0x73, 0x6E, + 0x35, 0x33, 0x6B, 0xE9, 0xDF, 0x81, 0x3F, 0x84, + 0xEB, 0x8D, 0xE5, 0x72, 0x74, 0x3F, 0xE1, 0xCE, + 0xB5, 0x93, 0xDB, 0x49, 0x6F, 0x21, 0xBF, 0x88, + 0xB7, 0x93, 0xDB, 0x48, 0x6E, 0x21, 0xBE, 0x81, + 0xFE, 0xDA, 0x58, 0x2D, 0xF5, 0x25, 0x7D, 0xA4, + 0x24, 0x9F, 0xD5, 0xA0, 0x78, 0xA8, 0xFC, 0x3C, + 0xBC, 0x67, 0xD1, 0xBD, 0x65, 0xD5, 0xB5, 0x75, + 0xF5, 0x2E, 0x98, 0xF4, 0x2C, 0x9C, 0xFC, 0x3C, + 0xBC, 0x67, 0xF9, 0x9C, 0x44, 0x94, 0xD0, 0x19, + 0x99, 0x22, 0x84, 0x58, 0x82, 0x32, 0x52, 0x88, + 0x08, 0xB3, 0x75, 0x18, 0xC0, 0x70, 0x6C, 0xAB, + 0x2B, 0x90, 0x9A, 0xFB, 0x21, 0xF1, 0xAD, 0x65, + 0xE5, 0x5E, 0xFC, 0x9E, 0x44, 0x94, 0x38, 0xF6, + 0x74, 0xCF, 0xED, 0x87, 0x5F, 0x8F, 0x4B, 0x84, + 0x06, 0xBD, 0x4F, 0x25, 0xFD, 0x2D, 0xC1, 0x0E, + 0x8C, 0x37, 0x71, 0x04, 0xDC, 0x0C, 0xB8, 0x77, + 0xF5, 0x4E, 0x48, 0x35, 0xEF, 0x3F, 0xE7, 0x2F, + 0xAF, 0x14, 0x82, 0xFC, 0x26, 0xF6, 0x2A, 0xED, + 0x6D, 0xD6, 0x34, 0x4A, 0x90, 0x40, 0xE8, 0x3A, + 0xB8, 0x03, 0x5D, 0x37, 0xEF, 0x3F, 0x3B, 0xE3, + 0x61, 0xDA, 0x2C, 0x4A, 0x92, 0x42, 0x14, 0x95, + 0x15, 0x4F, 0x7B, 0x11, 0x78, 0x48, 0x2E, 0xF2, + 0x78, 0x32, 0x05, 0x6F, 0x15, 0xEE, 0x8E, 0xC7, + 0x4E, 0xB0, 0x04, 0x68, 0x55, 0xE1, 0x81, 0xE4, + 0x66, 0xBD, 0xEE, 0x87, 0x5F, 0x0A, 0x62, 0xA2, + 0x07, 0xDF, 0x69, 0xA0, 0x71, 0xC1, 0x00, 0x43, + 0xC5, 0xAF, 0x9D, 0xF7, 0x8A, 0x60, 0x27, 0xFA, + 0x8A, 0x51, 0xD1, 0xFC, 0x24, 0xA5, 0x40, 0x86, + 0x27, 0x7A, 0xCA, 0x8F, 0x84, 0x29, 0xB9, 0x79, + 0xF9, 0x22, 0xA2, 0x8F, 0x57, 0xD6, 0x31, 0xF7, + 0x56, 0x05, 0xB5, 0xF0, 0x6B, 0xC6, 0x56, 0x96, + 0x16, 0xCD, 0x4D, 0x60, 0xB8, 0x39, 0xDC, 0x1A, + 0xBB, 0xE9, 0x59, 0x1C, 0x57, 0xFA, 0x6A, 0xAA, + 0x2A, 0xF1, 0x71, 0x5C, 0x84, 0x15, 0xF8, 0x3E, + 0x8F, 0xD8, 0x68, 0x95, 0xC7, 0x71, 0x90, 0xDB, + 0x5D, 0x0F, 0xF0, 0xB5, 0x6E, 0xC3, 0x53, 0x93, + 0x13, 0xC8, 0x48, 0x65, 0xBD, 0x9C, 0x72, 0xB4, + 0x38, 0xEB, 0xDF, 0xFA, 0x22, 0xF7, 0x96, 0x56, + 0x77, 0x3C, 0x8C, 0x51, 0x0E, 0xB8, 0x19, 0x56, + 0xD0, 0xC2, 0x7F, 0xBA, 0x39, 0x94, 0x04, 0xC4, + 0x44, 0x9F, 0x1F, 0x32, 0xEA, 0x6B, 0x9A, 0x5C, + 0xFD, 0xB4, 0x04, 0x41, 0x8A, 0x27, 0xB7, 0x77, + 0xF7, 0x2C, 0xAC, 0x81, 0x59, 0x68, 0x9C, 0x5A, + 0xEB, 0xA3, 0x13, 0x5E, 0x13, 0xA5, 0xEC, 0x0F, + 0x06, 0x8E, 0x25, 0xB9, 0x61, 0xD1, 0x87, 0x06, + 0x86, 0xCC, 0xEC, 0x86, 0xDF, 0xF8, 0x9E, 0xD7, + 0x7E, 0xC0, 0x76, 0x1A, 0xDF, 0x9F, 0xC9, 0x48, + 0xC8, 0xB2, 0x9C, 0xF6, 0x9C, 0x8C, 0x60, 0x08, + 0x82, 0x79, 0xAE, 0xC2, 0x92, 0x08, 0xD2, 0xA8, + 0xB4, 0x77, 0xCD, 0xBD, 0x69, 0x54, 0xD6, 0x3C, + 0x94, 0x8F, 0x19, 0x75, 0x7F, 0x81, 0xED, 0xEF, + 0x24, 0xD8, 0x4B, 0x80, 0x7B, 0xEB, 0x6D, 0xBE, + 0x2E, 0xD5, 0x63, 0x12, 0x3A, 0x8A, 0xEA, 0x2A, + 0xAA, 0x71, 0xC7, 0xAB, 0x73, 0xC3, 0xA3, 0x63, + 0xE3, 0x38, 0x8F, 0xE3, 0x3F, 0x8F, 0x8B, 0x51, + 0xD3, 0x68, }; static unsigned char vfs5011_prepare_02[] = { /* 2565 B */ - 0x02, 0xF0, 0x00, 0x14, 0x00, 0x03, 0x00, 0x09, - 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, - 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, - 0x20, 0x04, 0x30, 0xE5, 0x03, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, - 0xEA, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x4C, 0x20, 0x04, 0x30, 0x0A, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, - 0x04, 0x30, 0x01, 0xDE, 0x01, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, - 0x30, 0x02, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, - 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x08, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x40, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x60, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, - 0x30, 0x30, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x90, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, - 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x30, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xD8, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, - 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x04, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, - 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, - 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, - 0x30, 0x00, 0x00, 0x74, 0x01, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, - 0x74, 0x01, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, - 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, - 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, - 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, - 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, - 0xFF, 0xF9, 0x87, 0x20, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x07, 0x20, - 0xBA, 0xF8, 0x07, 0x20, 0xB9, 0xF8, 0x07, 0x20, - 0xB8, 0xF8, 0x07, 0x20, 0xB7, 0xF8, 0x07, 0x20, - 0xB6, 0xF8, 0x07, 0x20, 0xB5, 0xF8, 0x07, 0x20, - 0xB4, 0xF8, 0x07, 0x20, 0xB3, 0xF8, 0x07, 0x20, - 0xB2, 0xF8, 0x07, 0x20, 0xB1, 0xF8, 0x07, 0x22, - 0xB0, 0xF8, 0x07, 0x22, 0xAF, 0xF8, 0x07, 0x22, - 0xAE, 0xF8, 0x07, 0x22, 0xAD, 0xF8, 0x07, 0x22, - 0xAC, 0xF8, 0x07, 0x22, 0xAB, 0xF8, 0x07, 0x22, - 0xAA, 0xF8, 0x07, 0x22, 0xA9, 0xF8, 0x07, 0x22, - 0xA8, 0xF8, 0x07, 0x22, 0xA7, 0xF8, 0x07, 0x22, - 0xA6, 0xF8, 0x07, 0x22, 0xA5, 0xF8, 0x07, 0x22, - 0xA4, 0xF8, 0x07, 0x22, 0xA3, 0xF8, 0x07, 0x22, - 0xA2, 0xF8, 0x07, 0x22, 0xA1, 0xF8, 0x07, 0x22, - 0xA0, 0xF8, 0x07, 0x22, 0x9F, 0xF8, 0x07, 0x22, - 0x9E, 0xF8, 0x07, 0x22, 0x9D, 0xF8, 0x07, 0x22, - 0x9C, 0xF8, 0x07, 0x22, 0x9B, 0xF8, 0x07, 0x22, - 0x9A, 0xF8, 0x07, 0x22, 0x99, 0xF8, 0x07, 0x22, - 0x98, 0xF8, 0x07, 0x22, 0x97, 0xF8, 0x07, 0x22, - 0x96, 0xF8, 0x07, 0x22, 0x95, 0xF8, 0x07, 0x22, - 0x94, 0xF8, 0x07, 0x22, 0x93, 0xF8, 0x07, 0x22, - 0x92, 0xF8, 0x07, 0x22, 0x91, 0xF8, 0x07, 0x22, - 0x90, 0xF8, 0x07, 0x22, 0x8F, 0xF8, 0x07, 0x22, - 0x8E, 0xF8, 0x07, 0x22, 0x8D, 0xF8, 0x07, 0x22, - 0x8C, 0xF8, 0x07, 0x22, 0x8B, 0xF8, 0x07, 0x22, - 0x8A, 0xF8, 0x07, 0x22, 0x89, 0xF8, 0x07, 0x22, - 0x88, 0xF8, 0x07, 0x22, 0x87, 0xF8, 0x07, 0x22, - 0x86, 0xF8, 0x07, 0x22, 0x85, 0xF8, 0x07, 0x22, - 0x84, 0xF8, 0x07, 0x22, 0x83, 0xF8, 0x07, 0x22, - 0x82, 0xF8, 0x07, 0x22, 0x81, 0xF8, 0x07, 0x22, - 0x80, 0xF8, 0x07, 0x22, 0x7F, 0xF8, 0x07, 0x22, - 0x7E, 0xF8, 0x07, 0x22, 0x7D, 0xF8, 0x07, 0x22, - 0x7C, 0xF8, 0x07, 0x22, 0x7B, 0xF8, 0x07, 0x22, - 0x7A, 0xF8, 0x07, 0x22, 0x79, 0xF8, 0x07, 0x22, - 0x78, 0xF8, 0x07, 0x22, 0x77, 0xF8, 0x07, 0x22, - 0x76, 0xF8, 0x07, 0x22, 0x75, 0xF8, 0x07, 0x22, - 0x74, 0xF8, 0x07, 0x22, 0x73, 0xF8, 0x07, 0x22, - 0x72, 0xF8, 0x07, 0x22, 0x71, 0xF8, 0x07, 0x22, - 0x70, 0xF8, 0x07, 0x22, 0x6F, 0xF8, 0x07, 0x22, - 0x6E, 0xF8, 0x07, 0x22, 0x6D, 0xF8, 0x07, 0x22, - 0x6C, 0xF8, 0x07, 0x22, 0x6B, 0xF8, 0x07, 0x22, - 0x6A, 0xF8, 0x07, 0x22, 0x69, 0xF8, 0x07, 0x22, - 0x68, 0xF8, 0x07, 0x22, 0x67, 0xF8, 0x07, 0x22, - 0x66, 0xF8, 0x07, 0x22, 0x65, 0xF8, 0x07, 0x22, - 0x64, 0xF8, 0x07, 0x22, 0x63, 0xF8, 0x07, 0x22, - 0x62, 0xF8, 0x07, 0x22, 0x61, 0xF8, 0x07, 0x22, - 0x60, 0xF8, 0x07, 0x22, 0x5F, 0xF8, 0x07, 0x22, - 0x5E, 0xF8, 0x07, 0x22, 0x5D, 0xF8, 0x07, 0x22, - 0x5C, 0xF8, 0x07, 0x22, 0x5B, 0xF8, 0x07, 0x22, - 0x5A, 0xF8, 0x07, 0x22, 0x59, 0xF8, 0x07, 0x22, - 0x58, 0xF8, 0x07, 0x22, 0x57, 0xF8, 0x07, 0x22, - 0x56, 0xF8, 0x07, 0x22, 0x55, 0xF8, 0x07, 0x22, - 0x54, 0xF8, 0x07, 0x22, 0x53, 0xF8, 0x07, 0x22, - 0x52, 0xF8, 0x07, 0x22, 0x51, 0xF8, 0x07, 0x22, - 0x50, 0xF8, 0x07, 0x22, 0x4F, 0xF8, 0x07, 0x22, - 0x4E, 0xF8, 0x07, 0x22, 0x4D, 0xF8, 0x07, 0x22, - 0x4C, 0xF8, 0x07, 0x22, 0x4B, 0xF8, 0x07, 0x22, - 0x4A, 0xF8, 0x07, 0x22, 0x49, 0xF8, 0x07, 0x22, - 0x48, 0xF8, 0x07, 0x22, 0x47, 0xF8, 0x07, 0x22, - 0x46, 0xF8, 0x07, 0x22, 0x45, 0xF8, 0x07, 0x22, - 0x44, 0xF8, 0x07, 0x22, 0x43, 0xF8, 0x07, 0x22, - 0x42, 0xF8, 0x07, 0x22, 0x41, 0xF8, 0x07, 0x22, - 0x40, 0xF8, 0x07, 0x22, 0x3F, 0xF8, 0x07, 0x22, - 0x3E, 0xF8, 0x07, 0x22, 0x3D, 0xF8, 0x07, 0x22, - 0x3C, 0xF8, 0x07, 0x22, 0x3B, 0xF8, 0x07, 0x22, - 0x3A, 0xF8, 0x07, 0x22, 0x39, 0xF8, 0x07, 0x22, - 0x38, 0xF8, 0x07, 0x22, 0x37, 0xF8, 0x07, 0x22, - 0x36, 0xF8, 0x07, 0x22, 0x35, 0xF8, 0x07, 0x22, - 0x34, 0xF8, 0x07, 0x22, 0x33, 0xF8, 0x07, 0x22, - 0x32, 0xF8, 0x07, 0x22, 0x31, 0xF8, 0x07, 0x22, - 0x30, 0xF8, 0x07, 0x22, 0x2F, 0xF8, 0x07, 0x22, - 0x2E, 0xF8, 0x07, 0x22, 0x2D, 0xF8, 0x07, 0x22, - 0x2C, 0xF8, 0x07, 0x22, 0x2B, 0xF8, 0x07, 0x22, - 0x2A, 0xF8, 0x07, 0x22, 0x29, 0xF8, 0x07, 0x22, - 0x28, 0xF8, 0x07, 0x22, 0x27, 0xF8, 0x07, 0x22, - 0x26, 0xF8, 0x07, 0x22, 0x25, 0xF8, 0x07, 0x22, - 0x24, 0xF8, 0x07, 0x22, 0x23, 0xF8, 0x07, 0x20, - 0x22, 0xF8, 0x07, 0x20, 0x21, 0xF8, 0x07, 0x20, - 0x20, 0xF8, 0x07, 0x20, 0x1F, 0xF8, 0x07, 0x20, - 0x1E, 0xF8, 0x07, 0x20, 0x1D, 0xF8, 0x07, 0x20, - 0x1C, 0xF8, 0x07, 0x20, 0x1C, 0xF8, 0x07, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD8, 0xF8, 0x27, 0x20, 0xD9, 0xF8, 0x27, 0x20, - 0xDA, 0xF8, 0x27, 0x20, 0xDB, 0xF8, 0x27, 0x20, - 0xDC, 0xF8, 0x27, 0x20, 0xDD, 0xF8, 0x27, 0x20, - 0xDE, 0xF8, 0x27, 0x20, 0xDF, 0xF8, 0x27, 0x20, - 0xE0, 0xF8, 0x27, 0x20, 0xE1, 0xF8, 0x27, 0x20, - 0xE2, 0xF8, 0x27, 0x20, 0xE3, 0xF8, 0x27, 0x20, - 0xE4, 0xF8, 0x27, 0x20, 0xE5, 0xF8, 0x27, 0x20, - 0xE6, 0xF8, 0x27, 0x20, 0xE7, 0xF8, 0x27, 0x20, - 0xE8, 0xF8, 0x27, 0x20, 0xE9, 0xF8, 0x27, 0x20, - 0xEA, 0xF8, 0x27, 0x20, 0xEB, 0xF8, 0x27, 0x20, - 0xEC, 0xF8, 0x27, 0x20, 0xED, 0xF8, 0x27, 0x20, - 0xEE, 0xF8, 0x27, 0x20, 0xEF, 0xF8, 0x27, 0x20, - 0xF0, 0xF8, 0x27, 0x20, 0xF1, 0xF8, 0x27, 0x20, - 0xF2, 0xF8, 0x27, 0x20, 0xF3, 0xF8, 0x27, 0x20, - 0xF4, 0xF8, 0x27, 0x20, 0xF5, 0xF8, 0x27, 0x20, - 0xF6, 0xF8, 0x27, 0x20, 0xF7, 0xF8, 0x27, 0x20, - 0xF8, 0xF8, 0x27, 0x20, 0xF9, 0xF8, 0x27, 0x20, - 0xFA, 0xF8, 0x27, 0x20, 0xFB, 0xF8, 0x27, 0x20, - 0xFC, 0xF8, 0x27, 0x20, 0xFD, 0xF8, 0x27, 0x20, - 0xFE, 0xF8, 0x27, 0x20, 0xFF, 0xF8, 0x27, 0x20, - 0x00, 0xF9, 0x27, 0x20, 0xD7, 0xF8, 0x27, 0x20, - 0x00, 0xF8, 0x27, 0x20, 0x01, 0xF8, 0x27, 0x20, - 0x02, 0xF8, 0x27, 0x20, 0x03, 0xF8, 0x27, 0x20, - 0x04, 0xF8, 0x27, 0x20, 0x05, 0xF8, 0x27, 0x20, - 0x06, 0xF8, 0x27, 0x20, 0x07, 0xF8, 0x27, 0x20, - 0x08, 0xF8, 0x27, 0x20, 0x09, 0xF8, 0x27, 0x20, - 0x0A, 0xF8, 0x27, 0x20, 0x0B, 0xF8, 0x27, 0x20, - 0x0C, 0xF8, 0x27, 0x20, 0x0D, 0xF8, 0x27, 0x20, - 0x0E, 0xF8, 0x27, 0x20, 0x0F, 0xF8, 0x27, 0x20, - 0x10, 0xF8, 0x27, 0x20, 0x11, 0xF8, 0x27, 0x20, - 0x12, 0xF8, 0x27, 0x20, 0x13, 0xF8, 0x27, 0x20, - 0x14, 0xF8, 0x27, 0x20, 0x15, 0xF8, 0x27, 0x20, - 0x15, 0xF8, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, - 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, - 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, - 0x04, 0x17, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0E, - 0x00, 0x0C, 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x05, - 0x00, 0x0E, 0x00, 0x10, 0x20, 0xFD, 0x00, 0xFF, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, - 0x00, 0x03, 0x00, 0x09, 0x00, 0x04, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x08, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x0C, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x10, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x14, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xC8, 0x20, 0x04, 0x30, 0x04, 0x00, 0x00, - 0x00, 0x04, 0x05, 0x00, 0x0E, 0x00, 0x14, 0x20, - 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x84, 0x00, 0x03, 0x00, 0x09, 0x00, - 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x90, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x07, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x60, 0x21, 0x04, 0x30, 0x07, 0x00, 0x00, 0x00, - 0x04, 0x15, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x20, 0x28, 0x00, 0x00, + 0x02, 0xF0, 0x00, 0x14, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, + 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, + 0x20, 0x04, 0x30, 0xE5, 0x03, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, + 0xEA, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x4C, 0x20, 0x04, 0x30, 0x0A, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, + 0x04, 0x30, 0x01, 0xDE, 0x01, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, + 0x30, 0x02, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, + 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x08, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x40, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x60, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x90, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, + 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x30, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xD8, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, + 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x04, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, + 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, + 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, + 0x30, 0x00, 0x00, 0x74, 0x01, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, + 0x74, 0x01, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, + 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, + 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, + 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, + 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, + 0xFF, 0xF9, 0x87, 0x20, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x07, 0x20, + 0xBA, 0xF8, 0x07, 0x20, 0xB9, 0xF8, 0x07, 0x20, + 0xB8, 0xF8, 0x07, 0x20, 0xB7, 0xF8, 0x07, 0x20, + 0xB6, 0xF8, 0x07, 0x20, 0xB5, 0xF8, 0x07, 0x20, + 0xB4, 0xF8, 0x07, 0x20, 0xB3, 0xF8, 0x07, 0x20, + 0xB2, 0xF8, 0x07, 0x20, 0xB1, 0xF8, 0x07, 0x22, + 0xB0, 0xF8, 0x07, 0x22, 0xAF, 0xF8, 0x07, 0x22, + 0xAE, 0xF8, 0x07, 0x22, 0xAD, 0xF8, 0x07, 0x22, + 0xAC, 0xF8, 0x07, 0x22, 0xAB, 0xF8, 0x07, 0x22, + 0xAA, 0xF8, 0x07, 0x22, 0xA9, 0xF8, 0x07, 0x22, + 0xA8, 0xF8, 0x07, 0x22, 0xA7, 0xF8, 0x07, 0x22, + 0xA6, 0xF8, 0x07, 0x22, 0xA5, 0xF8, 0x07, 0x22, + 0xA4, 0xF8, 0x07, 0x22, 0xA3, 0xF8, 0x07, 0x22, + 0xA2, 0xF8, 0x07, 0x22, 0xA1, 0xF8, 0x07, 0x22, + 0xA0, 0xF8, 0x07, 0x22, 0x9F, 0xF8, 0x07, 0x22, + 0x9E, 0xF8, 0x07, 0x22, 0x9D, 0xF8, 0x07, 0x22, + 0x9C, 0xF8, 0x07, 0x22, 0x9B, 0xF8, 0x07, 0x22, + 0x9A, 0xF8, 0x07, 0x22, 0x99, 0xF8, 0x07, 0x22, + 0x98, 0xF8, 0x07, 0x22, 0x97, 0xF8, 0x07, 0x22, + 0x96, 0xF8, 0x07, 0x22, 0x95, 0xF8, 0x07, 0x22, + 0x94, 0xF8, 0x07, 0x22, 0x93, 0xF8, 0x07, 0x22, + 0x92, 0xF8, 0x07, 0x22, 0x91, 0xF8, 0x07, 0x22, + 0x90, 0xF8, 0x07, 0x22, 0x8F, 0xF8, 0x07, 0x22, + 0x8E, 0xF8, 0x07, 0x22, 0x8D, 0xF8, 0x07, 0x22, + 0x8C, 0xF8, 0x07, 0x22, 0x8B, 0xF8, 0x07, 0x22, + 0x8A, 0xF8, 0x07, 0x22, 0x89, 0xF8, 0x07, 0x22, + 0x88, 0xF8, 0x07, 0x22, 0x87, 0xF8, 0x07, 0x22, + 0x86, 0xF8, 0x07, 0x22, 0x85, 0xF8, 0x07, 0x22, + 0x84, 0xF8, 0x07, 0x22, 0x83, 0xF8, 0x07, 0x22, + 0x82, 0xF8, 0x07, 0x22, 0x81, 0xF8, 0x07, 0x22, + 0x80, 0xF8, 0x07, 0x22, 0x7F, 0xF8, 0x07, 0x22, + 0x7E, 0xF8, 0x07, 0x22, 0x7D, 0xF8, 0x07, 0x22, + 0x7C, 0xF8, 0x07, 0x22, 0x7B, 0xF8, 0x07, 0x22, + 0x7A, 0xF8, 0x07, 0x22, 0x79, 0xF8, 0x07, 0x22, + 0x78, 0xF8, 0x07, 0x22, 0x77, 0xF8, 0x07, 0x22, + 0x76, 0xF8, 0x07, 0x22, 0x75, 0xF8, 0x07, 0x22, + 0x74, 0xF8, 0x07, 0x22, 0x73, 0xF8, 0x07, 0x22, + 0x72, 0xF8, 0x07, 0x22, 0x71, 0xF8, 0x07, 0x22, + 0x70, 0xF8, 0x07, 0x22, 0x6F, 0xF8, 0x07, 0x22, + 0x6E, 0xF8, 0x07, 0x22, 0x6D, 0xF8, 0x07, 0x22, + 0x6C, 0xF8, 0x07, 0x22, 0x6B, 0xF8, 0x07, 0x22, + 0x6A, 0xF8, 0x07, 0x22, 0x69, 0xF8, 0x07, 0x22, + 0x68, 0xF8, 0x07, 0x22, 0x67, 0xF8, 0x07, 0x22, + 0x66, 0xF8, 0x07, 0x22, 0x65, 0xF8, 0x07, 0x22, + 0x64, 0xF8, 0x07, 0x22, 0x63, 0xF8, 0x07, 0x22, + 0x62, 0xF8, 0x07, 0x22, 0x61, 0xF8, 0x07, 0x22, + 0x60, 0xF8, 0x07, 0x22, 0x5F, 0xF8, 0x07, 0x22, + 0x5E, 0xF8, 0x07, 0x22, 0x5D, 0xF8, 0x07, 0x22, + 0x5C, 0xF8, 0x07, 0x22, 0x5B, 0xF8, 0x07, 0x22, + 0x5A, 0xF8, 0x07, 0x22, 0x59, 0xF8, 0x07, 0x22, + 0x58, 0xF8, 0x07, 0x22, 0x57, 0xF8, 0x07, 0x22, + 0x56, 0xF8, 0x07, 0x22, 0x55, 0xF8, 0x07, 0x22, + 0x54, 0xF8, 0x07, 0x22, 0x53, 0xF8, 0x07, 0x22, + 0x52, 0xF8, 0x07, 0x22, 0x51, 0xF8, 0x07, 0x22, + 0x50, 0xF8, 0x07, 0x22, 0x4F, 0xF8, 0x07, 0x22, + 0x4E, 0xF8, 0x07, 0x22, 0x4D, 0xF8, 0x07, 0x22, + 0x4C, 0xF8, 0x07, 0x22, 0x4B, 0xF8, 0x07, 0x22, + 0x4A, 0xF8, 0x07, 0x22, 0x49, 0xF8, 0x07, 0x22, + 0x48, 0xF8, 0x07, 0x22, 0x47, 0xF8, 0x07, 0x22, + 0x46, 0xF8, 0x07, 0x22, 0x45, 0xF8, 0x07, 0x22, + 0x44, 0xF8, 0x07, 0x22, 0x43, 0xF8, 0x07, 0x22, + 0x42, 0xF8, 0x07, 0x22, 0x41, 0xF8, 0x07, 0x22, + 0x40, 0xF8, 0x07, 0x22, 0x3F, 0xF8, 0x07, 0x22, + 0x3E, 0xF8, 0x07, 0x22, 0x3D, 0xF8, 0x07, 0x22, + 0x3C, 0xF8, 0x07, 0x22, 0x3B, 0xF8, 0x07, 0x22, + 0x3A, 0xF8, 0x07, 0x22, 0x39, 0xF8, 0x07, 0x22, + 0x38, 0xF8, 0x07, 0x22, 0x37, 0xF8, 0x07, 0x22, + 0x36, 0xF8, 0x07, 0x22, 0x35, 0xF8, 0x07, 0x22, + 0x34, 0xF8, 0x07, 0x22, 0x33, 0xF8, 0x07, 0x22, + 0x32, 0xF8, 0x07, 0x22, 0x31, 0xF8, 0x07, 0x22, + 0x30, 0xF8, 0x07, 0x22, 0x2F, 0xF8, 0x07, 0x22, + 0x2E, 0xF8, 0x07, 0x22, 0x2D, 0xF8, 0x07, 0x22, + 0x2C, 0xF8, 0x07, 0x22, 0x2B, 0xF8, 0x07, 0x22, + 0x2A, 0xF8, 0x07, 0x22, 0x29, 0xF8, 0x07, 0x22, + 0x28, 0xF8, 0x07, 0x22, 0x27, 0xF8, 0x07, 0x22, + 0x26, 0xF8, 0x07, 0x22, 0x25, 0xF8, 0x07, 0x22, + 0x24, 0xF8, 0x07, 0x22, 0x23, 0xF8, 0x07, 0x20, + 0x22, 0xF8, 0x07, 0x20, 0x21, 0xF8, 0x07, 0x20, + 0x20, 0xF8, 0x07, 0x20, 0x1F, 0xF8, 0x07, 0x20, + 0x1E, 0xF8, 0x07, 0x20, 0x1D, 0xF8, 0x07, 0x20, + 0x1C, 0xF8, 0x07, 0x20, 0x1C, 0xF8, 0x07, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD8, 0xF8, 0x27, 0x20, 0xD9, 0xF8, 0x27, 0x20, + 0xDA, 0xF8, 0x27, 0x20, 0xDB, 0xF8, 0x27, 0x20, + 0xDC, 0xF8, 0x27, 0x20, 0xDD, 0xF8, 0x27, 0x20, + 0xDE, 0xF8, 0x27, 0x20, 0xDF, 0xF8, 0x27, 0x20, + 0xE0, 0xF8, 0x27, 0x20, 0xE1, 0xF8, 0x27, 0x20, + 0xE2, 0xF8, 0x27, 0x20, 0xE3, 0xF8, 0x27, 0x20, + 0xE4, 0xF8, 0x27, 0x20, 0xE5, 0xF8, 0x27, 0x20, + 0xE6, 0xF8, 0x27, 0x20, 0xE7, 0xF8, 0x27, 0x20, + 0xE8, 0xF8, 0x27, 0x20, 0xE9, 0xF8, 0x27, 0x20, + 0xEA, 0xF8, 0x27, 0x20, 0xEB, 0xF8, 0x27, 0x20, + 0xEC, 0xF8, 0x27, 0x20, 0xED, 0xF8, 0x27, 0x20, + 0xEE, 0xF8, 0x27, 0x20, 0xEF, 0xF8, 0x27, 0x20, + 0xF0, 0xF8, 0x27, 0x20, 0xF1, 0xF8, 0x27, 0x20, + 0xF2, 0xF8, 0x27, 0x20, 0xF3, 0xF8, 0x27, 0x20, + 0xF4, 0xF8, 0x27, 0x20, 0xF5, 0xF8, 0x27, 0x20, + 0xF6, 0xF8, 0x27, 0x20, 0xF7, 0xF8, 0x27, 0x20, + 0xF8, 0xF8, 0x27, 0x20, 0xF9, 0xF8, 0x27, 0x20, + 0xFA, 0xF8, 0x27, 0x20, 0xFB, 0xF8, 0x27, 0x20, + 0xFC, 0xF8, 0x27, 0x20, 0xFD, 0xF8, 0x27, 0x20, + 0xFE, 0xF8, 0x27, 0x20, 0xFF, 0xF8, 0x27, 0x20, + 0x00, 0xF9, 0x27, 0x20, 0xD7, 0xF8, 0x27, 0x20, + 0x00, 0xF8, 0x27, 0x20, 0x01, 0xF8, 0x27, 0x20, + 0x02, 0xF8, 0x27, 0x20, 0x03, 0xF8, 0x27, 0x20, + 0x04, 0xF8, 0x27, 0x20, 0x05, 0xF8, 0x27, 0x20, + 0x06, 0xF8, 0x27, 0x20, 0x07, 0xF8, 0x27, 0x20, + 0x08, 0xF8, 0x27, 0x20, 0x09, 0xF8, 0x27, 0x20, + 0x0A, 0xF8, 0x27, 0x20, 0x0B, 0xF8, 0x27, 0x20, + 0x0C, 0xF8, 0x27, 0x20, 0x0D, 0xF8, 0x27, 0x20, + 0x0E, 0xF8, 0x27, 0x20, 0x0F, 0xF8, 0x27, 0x20, + 0x10, 0xF8, 0x27, 0x20, 0x11, 0xF8, 0x27, 0x20, + 0x12, 0xF8, 0x27, 0x20, 0x13, 0xF8, 0x27, 0x20, + 0x14, 0xF8, 0x27, 0x20, 0x15, 0xF8, 0x27, 0x20, + 0x15, 0xF8, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, + 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, + 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x04, 0x17, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0E, + 0x00, 0x0C, 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x05, + 0x00, 0x0E, 0x00, 0x10, 0x20, 0xFD, 0x00, 0xFF, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, + 0x00, 0x03, 0x00, 0x09, 0x00, 0x04, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x08, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x0C, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x10, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x14, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xC8, 0x20, 0x04, 0x30, 0x04, 0x00, 0x00, + 0x00, 0x04, 0x05, 0x00, 0x0E, 0x00, 0x14, 0x20, + 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x84, 0x00, 0x03, 0x00, 0x09, 0x00, + 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x90, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x07, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x60, 0x21, 0x04, 0x30, 0x07, 0x00, 0x00, 0x00, + 0x04, 0x15, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x28, 0x00, 0x00, }; static unsigned char vfs5011_prepare_03[] = { /* 117 B */ - 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0xFF, 0x00, 0x00, 0xFF, 0xF4, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0xF4, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x20, 0xBF, 0x02, 0x00, + 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xFF, 0x00, 0x00, 0xFF, 0xF4, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0xF4, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0xBF, 0x02, 0x00, }; static unsigned char vfs5011_prepare_04[] = { /* 2903 B */ - 0x02, 0xF0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x09, - 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, - 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, - 0x20, 0x04, 0x30, 0xE5, 0x03, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, - 0xEA, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x4C, 0x20, 0x04, 0x30, 0x0A, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, - 0x04, 0x30, 0x01, 0xDE, 0x01, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, - 0x30, 0x02, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, - 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x08, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x40, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x60, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, - 0x30, 0x30, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x90, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, - 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x30, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, - 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xD8, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, - 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x04, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, - 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, - 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, - 0x30, 0x00, 0x00, 0x74, 0x01, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, - 0x74, 0x01, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, - 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, - 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, - 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, - 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, - 0xFF, 0xF9, 0x87, 0x20, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, - 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x07, 0x20, - 0xBA, 0xF8, 0x07, 0x20, 0xB9, 0xF8, 0x07, 0x20, - 0xB8, 0xF8, 0x07, 0x20, 0xB7, 0xF8, 0x07, 0x20, - 0xB6, 0xF8, 0x07, 0x20, 0xB5, 0xF8, 0x07, 0x20, - 0xB4, 0xF8, 0x07, 0x20, 0xB3, 0xF8, 0x07, 0x20, - 0xB2, 0xF8, 0x07, 0x20, 0xB1, 0xF8, 0x07, 0x22, - 0xB0, 0xF8, 0x07, 0x22, 0xAF, 0xF8, 0x07, 0x22, - 0xAE, 0xF8, 0x07, 0x22, 0xAD, 0xF8, 0x07, 0x22, - 0xAC, 0xF8, 0x07, 0x22, 0xAB, 0xF8, 0x07, 0x22, - 0xAA, 0xF8, 0x07, 0x22, 0xA9, 0xF8, 0x07, 0x22, - 0xA8, 0xF8, 0x07, 0x22, 0xA7, 0xF8, 0x07, 0x22, - 0xA6, 0xF8, 0x07, 0x22, 0xA5, 0xF8, 0x07, 0x22, - 0xA4, 0xF8, 0x07, 0x22, 0xA3, 0xF8, 0x07, 0x22, - 0xA2, 0xF8, 0x07, 0x22, 0xA1, 0xF8, 0x07, 0x22, - 0xA0, 0xF8, 0x07, 0x22, 0x9F, 0xF8, 0x07, 0x22, - 0x9E, 0xF8, 0x07, 0x22, 0x9D, 0xF8, 0x07, 0x22, - 0x9C, 0xF8, 0x07, 0x22, 0x9B, 0xF8, 0x07, 0x22, - 0x9A, 0xF8, 0x07, 0x22, 0x99, 0xF8, 0x07, 0x22, - 0x98, 0xF8, 0x07, 0x22, 0x97, 0xF8, 0x07, 0x22, - 0x96, 0xF8, 0x07, 0x22, 0x95, 0xF8, 0x07, 0x22, - 0x94, 0xF8, 0x07, 0x22, 0x93, 0xF8, 0x07, 0x22, - 0x92, 0xF8, 0x07, 0x22, 0x91, 0xF8, 0x07, 0x22, - 0x90, 0xF8, 0x07, 0x22, 0x8F, 0xF8, 0x07, 0x22, - 0x8E, 0xF8, 0x07, 0x22, 0x8D, 0xF8, 0x07, 0x22, - 0x8C, 0xF8, 0x07, 0x22, 0x8B, 0xF8, 0x07, 0x22, - 0x8A, 0xF8, 0x07, 0x22, 0x89, 0xF8, 0x07, 0x22, - 0x88, 0xF8, 0x07, 0x22, 0x87, 0xF8, 0x07, 0x22, - 0x86, 0xF8, 0x07, 0x22, 0x85, 0xF8, 0x07, 0x22, - 0x84, 0xF8, 0x07, 0x22, 0x83, 0xF8, 0x07, 0x22, - 0x82, 0xF8, 0x07, 0x22, 0x81, 0xF8, 0x07, 0x22, - 0x80, 0xF8, 0x07, 0x22, 0x7F, 0xF8, 0x07, 0x22, - 0x7E, 0xF8, 0x07, 0x22, 0x7D, 0xF8, 0x07, 0x22, - 0x7C, 0xF8, 0x07, 0x22, 0x7B, 0xF8, 0x07, 0x22, - 0x7A, 0xF8, 0x07, 0x22, 0x79, 0xF8, 0x07, 0x22, - 0x78, 0xF8, 0x07, 0x22, 0x77, 0xF8, 0x07, 0x22, - 0x76, 0xF8, 0x07, 0x22, 0x75, 0xF8, 0x07, 0x22, - 0x74, 0xF8, 0x07, 0x22, 0x73, 0xF8, 0x07, 0x22, - 0x72, 0xF8, 0x07, 0x22, 0x71, 0xF8, 0x07, 0x22, - 0x70, 0xF8, 0x07, 0x22, 0x6F, 0xF8, 0x07, 0x22, - 0x6E, 0xF8, 0x07, 0x22, 0x6D, 0xF8, 0x07, 0x22, - 0x6C, 0xF8, 0x07, 0x22, 0x6B, 0xF8, 0x07, 0x22, - 0x6A, 0xF8, 0x07, 0x22, 0x69, 0xF8, 0x07, 0x22, - 0x68, 0xF8, 0x07, 0x22, 0x67, 0xF8, 0x07, 0x22, - 0x66, 0xF8, 0x07, 0x22, 0x65, 0xF8, 0x07, 0x22, - 0x64, 0xF8, 0x07, 0x22, 0x63, 0xF8, 0x07, 0x22, - 0x62, 0xF8, 0x07, 0x22, 0x61, 0xF8, 0x07, 0x22, - 0x60, 0xF8, 0x07, 0x22, 0x5F, 0xF8, 0x07, 0x22, - 0x5E, 0xF8, 0x07, 0x22, 0x5D, 0xF8, 0x07, 0x22, - 0x5C, 0xF8, 0x07, 0x22, 0x5B, 0xF8, 0x07, 0x22, - 0x5A, 0xF8, 0x07, 0x22, 0x59, 0xF8, 0x07, 0x22, - 0x58, 0xF8, 0x07, 0x22, 0x57, 0xF8, 0x07, 0x22, - 0x56, 0xF8, 0x07, 0x22, 0x55, 0xF8, 0x07, 0x22, - 0x54, 0xF8, 0x07, 0x22, 0x53, 0xF8, 0x07, 0x22, - 0x52, 0xF8, 0x07, 0x22, 0x51, 0xF8, 0x07, 0x22, - 0x50, 0xF8, 0x07, 0x22, 0x4F, 0xF8, 0x07, 0x22, - 0x4E, 0xF8, 0x07, 0x22, 0x4D, 0xF8, 0x07, 0x22, - 0x4C, 0xF8, 0x07, 0x22, 0x4B, 0xF8, 0x07, 0x22, - 0x4A, 0xF8, 0x07, 0x22, 0x49, 0xF8, 0x07, 0x22, - 0x48, 0xF8, 0x07, 0x22, 0x47, 0xF8, 0x07, 0x22, - 0x46, 0xF8, 0x07, 0x22, 0x45, 0xF8, 0x07, 0x22, - 0x44, 0xF8, 0x07, 0x22, 0x43, 0xF8, 0x07, 0x22, - 0x42, 0xF8, 0x07, 0x22, 0x41, 0xF8, 0x07, 0x22, - 0x40, 0xF8, 0x07, 0x22, 0x3F, 0xF8, 0x07, 0x22, - 0x3E, 0xF8, 0x07, 0x22, 0x3D, 0xF8, 0x07, 0x22, - 0x3C, 0xF8, 0x07, 0x22, 0x3B, 0xF8, 0x07, 0x22, - 0x3A, 0xF8, 0x07, 0x22, 0x39, 0xF8, 0x07, 0x22, - 0x38, 0xF8, 0x07, 0x22, 0x37, 0xF8, 0x07, 0x22, - 0x36, 0xF8, 0x07, 0x22, 0x35, 0xF8, 0x07, 0x22, - 0x34, 0xF8, 0x07, 0x22, 0x33, 0xF8, 0x07, 0x22, - 0x32, 0xF8, 0x07, 0x22, 0x31, 0xF8, 0x07, 0x22, - 0x30, 0xF8, 0x07, 0x22, 0x2F, 0xF8, 0x07, 0x22, - 0x2E, 0xF8, 0x07, 0x22, 0x2D, 0xF8, 0x07, 0x22, - 0x2C, 0xF8, 0x07, 0x22, 0x2B, 0xF8, 0x07, 0x22, - 0x2A, 0xF8, 0x07, 0x22, 0x29, 0xF8, 0x07, 0x22, - 0x28, 0xF8, 0x07, 0x22, 0x27, 0xF8, 0x07, 0x22, - 0x26, 0xF8, 0x07, 0x22, 0x25, 0xF8, 0x07, 0x22, - 0x24, 0xF8, 0x07, 0x22, 0x23, 0xF8, 0x07, 0x20, - 0x22, 0xF8, 0x07, 0x20, 0x21, 0xF8, 0x07, 0x20, - 0x20, 0xF8, 0x07, 0x20, 0x1F, 0xF8, 0x07, 0x20, - 0x1E, 0xF8, 0x07, 0x20, 0x1D, 0xF8, 0x07, 0x20, - 0x1C, 0xF8, 0x07, 0x20, 0x1C, 0xF8, 0x07, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, - 0xD8, 0xF8, 0x27, 0x20, 0xD9, 0xF8, 0x27, 0x20, - 0xDA, 0xF8, 0x27, 0x20, 0xDB, 0xF8, 0x27, 0x20, - 0xDC, 0xF8, 0x27, 0x20, 0xDD, 0xF8, 0x27, 0x20, - 0xDE, 0xF8, 0x27, 0x20, 0xDF, 0xF8, 0x27, 0x20, - 0xE0, 0xF8, 0x27, 0x20, 0xE1, 0xF8, 0x27, 0x20, - 0xE2, 0xF8, 0x27, 0x20, 0xE3, 0xF8, 0x27, 0x20, - 0xE4, 0xF8, 0x27, 0x20, 0xE5, 0xF8, 0x27, 0x20, - 0xE6, 0xF8, 0x27, 0x20, 0xE7, 0xF8, 0x27, 0x20, - 0xE8, 0xF8, 0x27, 0x20, 0xE9, 0xF8, 0x27, 0x20, - 0xEA, 0xF8, 0x27, 0x20, 0xEB, 0xF8, 0x27, 0x20, - 0xEC, 0xF8, 0x27, 0x20, 0xED, 0xF8, 0x27, 0x20, - 0xEE, 0xF8, 0x27, 0x20, 0xEF, 0xF8, 0x27, 0x20, - 0xF0, 0xF8, 0x27, 0x20, 0xF1, 0xF8, 0x27, 0x20, - 0xF2, 0xF8, 0x27, 0x20, 0xF3, 0xF8, 0x27, 0x20, - 0xF4, 0xF8, 0x27, 0x20, 0xF5, 0xF8, 0x27, 0x20, - 0xF6, 0xF8, 0x27, 0x20, 0xF7, 0xF8, 0x27, 0x20, - 0xF8, 0xF8, 0x27, 0x20, 0xF9, 0xF8, 0x27, 0x20, - 0xFA, 0xF8, 0x27, 0x20, 0xFB, 0xF8, 0x27, 0x20, - 0xFC, 0xF8, 0x27, 0x20, 0xFD, 0xF8, 0x27, 0x20, - 0xFE, 0xF8, 0x27, 0x20, 0xFF, 0xF8, 0x27, 0x20, - 0x00, 0xF9, 0x27, 0x20, 0xD7, 0xF8, 0x27, 0x20, - 0x00, 0xF8, 0x27, 0x20, 0x01, 0xF8, 0x27, 0x20, - 0x02, 0xF8, 0x27, 0x20, 0x03, 0xF8, 0x27, 0x20, - 0x04, 0xF8, 0x27, 0x20, 0x05, 0xF8, 0x27, 0x20, - 0x06, 0xF8, 0x27, 0x20, 0x07, 0xF8, 0x27, 0x20, - 0x08, 0xF8, 0x27, 0x20, 0x09, 0xF8, 0x27, 0x20, - 0x0A, 0xF8, 0x27, 0x20, 0x0B, 0xF8, 0x27, 0x20, - 0x0C, 0xF8, 0x27, 0x20, 0x0D, 0xF8, 0x27, 0x20, - 0x0E, 0xF8, 0x27, 0x20, 0x0F, 0xF8, 0x27, 0x20, - 0x10, 0xF8, 0x27, 0x20, 0x11, 0xF8, 0x27, 0x20, - 0x12, 0xF8, 0x27, 0x20, 0x13, 0xF8, 0x27, 0x20, - 0x14, 0xF8, 0x27, 0x20, 0x15, 0xF8, 0x27, 0x20, - 0x15, 0xF8, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, - 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, - 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, - 0x04, 0x05, 0x00, 0x0E, 0x00, 0x0C, 0x20, 0xFD, - 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x10, - 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x05, 0x00, 0x00, 0x03, 0x00, 0x09, - 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, - 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, - 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, - 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, - 0x0E, 0x00, 0x14, 0x20, 0xFF, 0xFF, 0x00, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, - 0x03, 0x00, 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, - 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, - 0x00, 0x88, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, - 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, - 0x00, 0x09, 0x00, 0x90, 0x21, 0x04, 0x30, 0x01, - 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, - 0x94, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, - 0x04, 0x03, 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, - 0x09, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x20, - 0x21, 0x04, 0x30, 0x07, 0x00, 0x00, 0x00, 0x04, - 0x03, 0x00, 0x09, 0x00, 0x60, 0x21, 0x04, 0x30, - 0x07, 0x00, 0x00, 0x00, 0x04, 0x15, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x28, 0x00, - 0x00, 0x18, 0x00, 0x52, 0x01, 0x08, 0x00, 0x05, - 0x00, 0x0A, 0x00, 0xFA, 0x00, 0x1E, 0x00, 0xC8, - 0x00, 0x00, 0x00, 0x9F, 0x00, 0x38, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0xFF, 0xFB, 0xF9, 0xFC, 0xFD, 0xFF, 0xFD, 0xFE, - 0x00, 0x01, 0x00, 0x00, 0x03, 0x01, 0x01, 0x02, - 0x06, 0x05, 0x05, 0x06, 0x05, 0x08, 0x0A, 0x06, - 0x09, 0x09, 0x06, 0x08, 0x05, 0x04, 0x03, 0x04, - 0x03, 0x05, 0x07, 0x07, 0x09, 0x05, 0x04, 0x03, - 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0xFF, 0x00, - 0xFF, 0x00, 0xFB, 0xFD, 0xFF, 0xFF, 0x01, 0xFF, - 0xFD, 0xFF, 0x01, 0x02, 0x01, 0xFE, 0xFF, 0x01, - 0xFE, 0xFC, 0x00, 0xFF, 0x01, 0x01, 0x00, 0x00, - 0xFF, 0xFF, 0x04, 0x03, 0x00, 0x01, 0xFE, 0x02, - 0x02, 0x03, 0x03, 0x00, 0xFF, 0xFA, 0xFB, 0xFC, - 0xFF, 0xFF, 0x02, 0xFF, 0x01, 0xFF, 0xFE, 0xFD, - 0xFF, 0xFE, 0xFB, 0xF9, 0xF9, 0xFC, 0xFC, 0xFC, - 0xF5, 0xF3, 0xF8, 0xF5, 0xF5, 0xF5, 0xF9, 0xFB, - 0xFE, 0xFC, 0xFA, 0xF8, 0xFC, 0xF9, 0xF7, 0xF6, - 0xF6, 0xF7, 0xFB, 0xF7, 0xF9, 0xF9, 0xF8, 0xF8, - 0xF1, 0xF6, 0xF9, 0xFC, 0xFE, 0xFC, 0xFE, 0x00, - 0xFB, 0xFE, 0xFC, 0xFC, 0xFC, 0xFB, 0xFD, 0xFB, - 0xFC, 0xFA, 0xFC, 0xFA, 0x01, 0x02, 0xFE, 0xFE, - 0xFC, 0xF7, 0xF4, 0xF4, 0xED, 0xE1, 0xD7, 0x01, - 0x04, 0x03, 0x04, 0x08, 0x0B, 0x09, 0x09, 0x09, - 0x05, 0x06, 0x08, 0x05, 0x03, 0x00, 0x00, 0x01, - 0x00, 0xFF, 0xFF, 0xFE, 0xFD, 0xFD, 0xFC, 0xFF, - 0x02, 0xFD, 0xFB, 0xFC, 0xFA, 0xFC, 0xFD, 0xFF, - 0xFF, 0xFC, 0xFC, 0xFB, 0xFC, 0xFE, 0xFF, 0x00, - 0x01, 0x0B, 0x09, 0x07, 0x06, 0x03, 0x06, 0x08, - 0x07, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0B, 0x0D, - 0x0E, 0x10, 0x15, 0x15, 0x19, 0x1B, 0x20, 0x01, - 0x00, 0xFF, 0xFF, 0xFE, 0xFD, 0xFD, 0xFC, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x02, 0xF0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x04, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x18, 0x20, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x20, 0x04, 0x30, 0x08, + 0x00, 0x80, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x24, 0x20, 0x04, 0x30, 0x00, 0x00, 0xFF, 0x01, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x2C, 0x20, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x40, 0x20, 0x04, 0x30, 0xFF, 0x03, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, + 0x20, 0x04, 0x30, 0xE5, 0x03, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x48, 0x20, 0x04, 0x30, + 0xEA, 0x03, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x4C, 0x20, 0x04, 0x30, 0x0A, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x54, 0x20, + 0x04, 0x30, 0x01, 0xDE, 0x01, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x00, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, 0x04, + 0x30, 0x02, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x1C, 0x21, + 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x20, 0x21, 0x04, 0x30, 0x08, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x40, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x4C, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x58, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x5C, 0x21, 0x04, 0x30, 0x1F, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x60, 0x21, 0x04, 0x30, 0x08, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x80, 0x21, 0x04, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x88, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x90, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x94, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x9C, 0x21, 0x04, 0x30, 0x1F, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, 0x21, 0x04, + 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xC0, 0x21, 0x04, 0x30, 0x30, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xC8, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xCC, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xD0, 0x21, + 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xD4, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xD8, 0x21, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xDC, 0x21, 0x04, + 0x30, 0x1F, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xE0, 0x21, 0x04, 0x30, 0x04, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xA0, + 0x20, 0x04, 0x30, 0xEF, 0xE1, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0xA4, 0x20, 0x04, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0xB0, 0x20, 0x04, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0xC4, 0x20, + 0x04, 0x30, 0x14, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0xCC, 0x20, 0x04, 0x30, 0x20, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x20, 0x04, + 0x30, 0x00, 0x00, 0x74, 0x01, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xA8, 0x20, 0x04, 0x30, 0xFE, 0x21, + 0x74, 0x01, 0x04, 0x03, 0x00, 0x09, 0x00, 0x04, + 0x00, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x08, 0x00, 0x00, 0x38, + 0x00, 0x15, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x0C, 0x00, 0x00, 0x38, 0x01, 0x03, 0x02, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x10, 0x00, + 0x00, 0x38, 0x01, 0x07, 0x02, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x14, 0x00, 0x00, 0x38, 0x0C, + 0x0C, 0x05, 0x00, 0x04, 0x02, 0x00, 0x80, 0x05, + 0xFF, 0xF9, 0x87, 0x20, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x87, 0x00, + 0xBB, 0xF8, 0x87, 0x00, 0xBB, 0xF8, 0x07, 0x20, + 0xBA, 0xF8, 0x07, 0x20, 0xB9, 0xF8, 0x07, 0x20, + 0xB8, 0xF8, 0x07, 0x20, 0xB7, 0xF8, 0x07, 0x20, + 0xB6, 0xF8, 0x07, 0x20, 0xB5, 0xF8, 0x07, 0x20, + 0xB4, 0xF8, 0x07, 0x20, 0xB3, 0xF8, 0x07, 0x20, + 0xB2, 0xF8, 0x07, 0x20, 0xB1, 0xF8, 0x07, 0x22, + 0xB0, 0xF8, 0x07, 0x22, 0xAF, 0xF8, 0x07, 0x22, + 0xAE, 0xF8, 0x07, 0x22, 0xAD, 0xF8, 0x07, 0x22, + 0xAC, 0xF8, 0x07, 0x22, 0xAB, 0xF8, 0x07, 0x22, + 0xAA, 0xF8, 0x07, 0x22, 0xA9, 0xF8, 0x07, 0x22, + 0xA8, 0xF8, 0x07, 0x22, 0xA7, 0xF8, 0x07, 0x22, + 0xA6, 0xF8, 0x07, 0x22, 0xA5, 0xF8, 0x07, 0x22, + 0xA4, 0xF8, 0x07, 0x22, 0xA3, 0xF8, 0x07, 0x22, + 0xA2, 0xF8, 0x07, 0x22, 0xA1, 0xF8, 0x07, 0x22, + 0xA0, 0xF8, 0x07, 0x22, 0x9F, 0xF8, 0x07, 0x22, + 0x9E, 0xF8, 0x07, 0x22, 0x9D, 0xF8, 0x07, 0x22, + 0x9C, 0xF8, 0x07, 0x22, 0x9B, 0xF8, 0x07, 0x22, + 0x9A, 0xF8, 0x07, 0x22, 0x99, 0xF8, 0x07, 0x22, + 0x98, 0xF8, 0x07, 0x22, 0x97, 0xF8, 0x07, 0x22, + 0x96, 0xF8, 0x07, 0x22, 0x95, 0xF8, 0x07, 0x22, + 0x94, 0xF8, 0x07, 0x22, 0x93, 0xF8, 0x07, 0x22, + 0x92, 0xF8, 0x07, 0x22, 0x91, 0xF8, 0x07, 0x22, + 0x90, 0xF8, 0x07, 0x22, 0x8F, 0xF8, 0x07, 0x22, + 0x8E, 0xF8, 0x07, 0x22, 0x8D, 0xF8, 0x07, 0x22, + 0x8C, 0xF8, 0x07, 0x22, 0x8B, 0xF8, 0x07, 0x22, + 0x8A, 0xF8, 0x07, 0x22, 0x89, 0xF8, 0x07, 0x22, + 0x88, 0xF8, 0x07, 0x22, 0x87, 0xF8, 0x07, 0x22, + 0x86, 0xF8, 0x07, 0x22, 0x85, 0xF8, 0x07, 0x22, + 0x84, 0xF8, 0x07, 0x22, 0x83, 0xF8, 0x07, 0x22, + 0x82, 0xF8, 0x07, 0x22, 0x81, 0xF8, 0x07, 0x22, + 0x80, 0xF8, 0x07, 0x22, 0x7F, 0xF8, 0x07, 0x22, + 0x7E, 0xF8, 0x07, 0x22, 0x7D, 0xF8, 0x07, 0x22, + 0x7C, 0xF8, 0x07, 0x22, 0x7B, 0xF8, 0x07, 0x22, + 0x7A, 0xF8, 0x07, 0x22, 0x79, 0xF8, 0x07, 0x22, + 0x78, 0xF8, 0x07, 0x22, 0x77, 0xF8, 0x07, 0x22, + 0x76, 0xF8, 0x07, 0x22, 0x75, 0xF8, 0x07, 0x22, + 0x74, 0xF8, 0x07, 0x22, 0x73, 0xF8, 0x07, 0x22, + 0x72, 0xF8, 0x07, 0x22, 0x71, 0xF8, 0x07, 0x22, + 0x70, 0xF8, 0x07, 0x22, 0x6F, 0xF8, 0x07, 0x22, + 0x6E, 0xF8, 0x07, 0x22, 0x6D, 0xF8, 0x07, 0x22, + 0x6C, 0xF8, 0x07, 0x22, 0x6B, 0xF8, 0x07, 0x22, + 0x6A, 0xF8, 0x07, 0x22, 0x69, 0xF8, 0x07, 0x22, + 0x68, 0xF8, 0x07, 0x22, 0x67, 0xF8, 0x07, 0x22, + 0x66, 0xF8, 0x07, 0x22, 0x65, 0xF8, 0x07, 0x22, + 0x64, 0xF8, 0x07, 0x22, 0x63, 0xF8, 0x07, 0x22, + 0x62, 0xF8, 0x07, 0x22, 0x61, 0xF8, 0x07, 0x22, + 0x60, 0xF8, 0x07, 0x22, 0x5F, 0xF8, 0x07, 0x22, + 0x5E, 0xF8, 0x07, 0x22, 0x5D, 0xF8, 0x07, 0x22, + 0x5C, 0xF8, 0x07, 0x22, 0x5B, 0xF8, 0x07, 0x22, + 0x5A, 0xF8, 0x07, 0x22, 0x59, 0xF8, 0x07, 0x22, + 0x58, 0xF8, 0x07, 0x22, 0x57, 0xF8, 0x07, 0x22, + 0x56, 0xF8, 0x07, 0x22, 0x55, 0xF8, 0x07, 0x22, + 0x54, 0xF8, 0x07, 0x22, 0x53, 0xF8, 0x07, 0x22, + 0x52, 0xF8, 0x07, 0x22, 0x51, 0xF8, 0x07, 0x22, + 0x50, 0xF8, 0x07, 0x22, 0x4F, 0xF8, 0x07, 0x22, + 0x4E, 0xF8, 0x07, 0x22, 0x4D, 0xF8, 0x07, 0x22, + 0x4C, 0xF8, 0x07, 0x22, 0x4B, 0xF8, 0x07, 0x22, + 0x4A, 0xF8, 0x07, 0x22, 0x49, 0xF8, 0x07, 0x22, + 0x48, 0xF8, 0x07, 0x22, 0x47, 0xF8, 0x07, 0x22, + 0x46, 0xF8, 0x07, 0x22, 0x45, 0xF8, 0x07, 0x22, + 0x44, 0xF8, 0x07, 0x22, 0x43, 0xF8, 0x07, 0x22, + 0x42, 0xF8, 0x07, 0x22, 0x41, 0xF8, 0x07, 0x22, + 0x40, 0xF8, 0x07, 0x22, 0x3F, 0xF8, 0x07, 0x22, + 0x3E, 0xF8, 0x07, 0x22, 0x3D, 0xF8, 0x07, 0x22, + 0x3C, 0xF8, 0x07, 0x22, 0x3B, 0xF8, 0x07, 0x22, + 0x3A, 0xF8, 0x07, 0x22, 0x39, 0xF8, 0x07, 0x22, + 0x38, 0xF8, 0x07, 0x22, 0x37, 0xF8, 0x07, 0x22, + 0x36, 0xF8, 0x07, 0x22, 0x35, 0xF8, 0x07, 0x22, + 0x34, 0xF8, 0x07, 0x22, 0x33, 0xF8, 0x07, 0x22, + 0x32, 0xF8, 0x07, 0x22, 0x31, 0xF8, 0x07, 0x22, + 0x30, 0xF8, 0x07, 0x22, 0x2F, 0xF8, 0x07, 0x22, + 0x2E, 0xF8, 0x07, 0x22, 0x2D, 0xF8, 0x07, 0x22, + 0x2C, 0xF8, 0x07, 0x22, 0x2B, 0xF8, 0x07, 0x22, + 0x2A, 0xF8, 0x07, 0x22, 0x29, 0xF8, 0x07, 0x22, + 0x28, 0xF8, 0x07, 0x22, 0x27, 0xF8, 0x07, 0x22, + 0x26, 0xF8, 0x07, 0x22, 0x25, 0xF8, 0x07, 0x22, + 0x24, 0xF8, 0x07, 0x22, 0x23, 0xF8, 0x07, 0x20, + 0x22, 0xF8, 0x07, 0x20, 0x21, 0xF8, 0x07, 0x20, + 0x20, 0xF8, 0x07, 0x20, 0x1F, 0xF8, 0x07, 0x20, + 0x1E, 0xF8, 0x07, 0x20, 0x1D, 0xF8, 0x07, 0x20, + 0x1C, 0xF8, 0x07, 0x20, 0x1C, 0xF8, 0x07, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD7, 0xF8, 0xA7, 0x00, 0xD7, 0xF8, 0xA7, 0x00, + 0xD8, 0xF8, 0x27, 0x20, 0xD9, 0xF8, 0x27, 0x20, + 0xDA, 0xF8, 0x27, 0x20, 0xDB, 0xF8, 0x27, 0x20, + 0xDC, 0xF8, 0x27, 0x20, 0xDD, 0xF8, 0x27, 0x20, + 0xDE, 0xF8, 0x27, 0x20, 0xDF, 0xF8, 0x27, 0x20, + 0xE0, 0xF8, 0x27, 0x20, 0xE1, 0xF8, 0x27, 0x20, + 0xE2, 0xF8, 0x27, 0x20, 0xE3, 0xF8, 0x27, 0x20, + 0xE4, 0xF8, 0x27, 0x20, 0xE5, 0xF8, 0x27, 0x20, + 0xE6, 0xF8, 0x27, 0x20, 0xE7, 0xF8, 0x27, 0x20, + 0xE8, 0xF8, 0x27, 0x20, 0xE9, 0xF8, 0x27, 0x20, + 0xEA, 0xF8, 0x27, 0x20, 0xEB, 0xF8, 0x27, 0x20, + 0xEC, 0xF8, 0x27, 0x20, 0xED, 0xF8, 0x27, 0x20, + 0xEE, 0xF8, 0x27, 0x20, 0xEF, 0xF8, 0x27, 0x20, + 0xF0, 0xF8, 0x27, 0x20, 0xF1, 0xF8, 0x27, 0x20, + 0xF2, 0xF8, 0x27, 0x20, 0xF3, 0xF8, 0x27, 0x20, + 0xF4, 0xF8, 0x27, 0x20, 0xF5, 0xF8, 0x27, 0x20, + 0xF6, 0xF8, 0x27, 0x20, 0xF7, 0xF8, 0x27, 0x20, + 0xF8, 0xF8, 0x27, 0x20, 0xF9, 0xF8, 0x27, 0x20, + 0xFA, 0xF8, 0x27, 0x20, 0xFB, 0xF8, 0x27, 0x20, + 0xFC, 0xF8, 0x27, 0x20, 0xFD, 0xF8, 0x27, 0x20, + 0xFE, 0xF8, 0x27, 0x20, 0xFF, 0xF8, 0x27, 0x20, + 0x00, 0xF9, 0x27, 0x20, 0xD7, 0xF8, 0x27, 0x20, + 0x00, 0xF8, 0x27, 0x20, 0x01, 0xF8, 0x27, 0x20, + 0x02, 0xF8, 0x27, 0x20, 0x03, 0xF8, 0x27, 0x20, + 0x04, 0xF8, 0x27, 0x20, 0x05, 0xF8, 0x27, 0x20, + 0x06, 0xF8, 0x27, 0x20, 0x07, 0xF8, 0x27, 0x20, + 0x08, 0xF8, 0x27, 0x20, 0x09, 0xF8, 0x27, 0x20, + 0x0A, 0xF8, 0x27, 0x20, 0x0B, 0xF8, 0x27, 0x20, + 0x0C, 0xF8, 0x27, 0x20, 0x0D, 0xF8, 0x27, 0x20, + 0x0E, 0xF8, 0x27, 0x20, 0x0F, 0xF8, 0x27, 0x20, + 0x10, 0xF8, 0x27, 0x20, 0x11, 0xF8, 0x27, 0x20, + 0x12, 0xF8, 0x27, 0x20, 0x13, 0xF8, 0x27, 0x20, + 0x14, 0xF8, 0x27, 0x20, 0x15, 0xF8, 0x27, 0x20, + 0x15, 0xF8, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x08, 0x00, 0x10, 0x03, 0x18, 0x1C, + 0x10, 0x03, 0x18, 0x1C, 0x03, 0x00, 0x09, 0x00, + 0x00, 0x20, 0x04, 0x30, 0x80, 0x00, 0x00, 0x00, + 0x04, 0x05, 0x00, 0x0E, 0x00, 0x0C, 0x20, 0xFD, + 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x10, + 0x20, 0xFD, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x05, 0x00, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x04, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x08, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x0C, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x10, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x14, 0x21, 0x04, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0x18, 0x21, 0x04, 0x30, 0x01, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x44, + 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x48, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x4C, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x50, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x54, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x58, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0xC8, 0x20, 0x04, + 0x30, 0x04, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, + 0x0E, 0x00, 0x14, 0x20, 0xFF, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, + 0x03, 0x00, 0x09, 0x00, 0x84, 0x21, 0x04, 0x30, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, + 0x00, 0x88, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x8C, 0x21, + 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x09, 0x00, 0x90, 0x21, 0x04, 0x30, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, + 0x94, 0x21, 0x04, 0x30, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x09, 0x00, 0x98, 0x21, 0x04, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x09, 0x00, 0xA0, 0x21, 0x04, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x09, 0x00, 0x20, + 0x21, 0x04, 0x30, 0x07, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x09, 0x00, 0x60, 0x21, 0x04, 0x30, + 0x07, 0x00, 0x00, 0x00, 0x04, 0x15, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x28, 0x00, + 0x00, 0x18, 0x00, 0x52, 0x01, 0x08, 0x00, 0x05, + 0x00, 0x0A, 0x00, 0xFA, 0x00, 0x1E, 0x00, 0xC8, + 0x00, 0x00, 0x00, 0x9F, 0x00, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xFF, 0xFB, 0xF9, 0xFC, 0xFD, 0xFF, 0xFD, 0xFE, + 0x00, 0x01, 0x00, 0x00, 0x03, 0x01, 0x01, 0x02, + 0x06, 0x05, 0x05, 0x06, 0x05, 0x08, 0x0A, 0x06, + 0x09, 0x09, 0x06, 0x08, 0x05, 0x04, 0x03, 0x04, + 0x03, 0x05, 0x07, 0x07, 0x09, 0x05, 0x04, 0x03, + 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0xFF, 0x00, + 0xFF, 0x00, 0xFB, 0xFD, 0xFF, 0xFF, 0x01, 0xFF, + 0xFD, 0xFF, 0x01, 0x02, 0x01, 0xFE, 0xFF, 0x01, + 0xFE, 0xFC, 0x00, 0xFF, 0x01, 0x01, 0x00, 0x00, + 0xFF, 0xFF, 0x04, 0x03, 0x00, 0x01, 0xFE, 0x02, + 0x02, 0x03, 0x03, 0x00, 0xFF, 0xFA, 0xFB, 0xFC, + 0xFF, 0xFF, 0x02, 0xFF, 0x01, 0xFF, 0xFE, 0xFD, + 0xFF, 0xFE, 0xFB, 0xF9, 0xF9, 0xFC, 0xFC, 0xFC, + 0xF5, 0xF3, 0xF8, 0xF5, 0xF5, 0xF5, 0xF9, 0xFB, + 0xFE, 0xFC, 0xFA, 0xF8, 0xFC, 0xF9, 0xF7, 0xF6, + 0xF6, 0xF7, 0xFB, 0xF7, 0xF9, 0xF9, 0xF8, 0xF8, + 0xF1, 0xF6, 0xF9, 0xFC, 0xFE, 0xFC, 0xFE, 0x00, + 0xFB, 0xFE, 0xFC, 0xFC, 0xFC, 0xFB, 0xFD, 0xFB, + 0xFC, 0xFA, 0xFC, 0xFA, 0x01, 0x02, 0xFE, 0xFE, + 0xFC, 0xF7, 0xF4, 0xF4, 0xED, 0xE1, 0xD7, 0x01, + 0x04, 0x03, 0x04, 0x08, 0x0B, 0x09, 0x09, 0x09, + 0x05, 0x06, 0x08, 0x05, 0x03, 0x00, 0x00, 0x01, + 0x00, 0xFF, 0xFF, 0xFE, 0xFD, 0xFD, 0xFC, 0xFF, + 0x02, 0xFD, 0xFB, 0xFC, 0xFA, 0xFC, 0xFD, 0xFF, + 0xFF, 0xFC, 0xFC, 0xFB, 0xFC, 0xFE, 0xFF, 0x00, + 0x01, 0x0B, 0x09, 0x07, 0x06, 0x03, 0x06, 0x08, + 0x07, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0B, 0x0D, + 0x0E, 0x10, 0x15, 0x15, 0x19, 0x1B, 0x20, 0x01, + 0x00, 0xFF, 0xFF, 0xFE, 0xFD, 0xFD, 0xFC, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, }; #endif diff --git a/libfprint/drivers/virtual-image.c b/libfprint/drivers/virtual-image.c index 17ebb14f..6fdd3dbb 100644 --- a/libfprint/drivers/virtual-image.c +++ b/libfprint/drivers/virtual-image.c @@ -36,60 +36,64 @@ #include #include -struct _FpDeviceVirtualImage { - FpImageDevice parent; +struct _FpDeviceVirtualImage +{ + FpImageDevice parent; - GSocketListener *listener; - GSocketConnection *connection; - GCancellable *cancellable; + GSocketListener *listener; + GSocketConnection *connection; + GCancellable *cancellable; - gint socket_fd; - gint client_fd; + gint socket_fd; + gint client_fd; - FpImage *recv_img; - gint recv_img_hdr[2]; + FpImage *recv_img; + gint recv_img_hdr[2]; }; G_DECLARE_FINAL_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FPI, DEVICE_VIRTUAL_IMAGE, FpImageDevice) G_DEFINE_TYPE (FpDeviceVirtualImage, fpi_device_virtual_image, FP_TYPE_IMAGE_DEVICE) static void start_listen (FpDeviceVirtualImage *dev); -static void recv_image (FpDeviceVirtualImage *dev, GInputStream *stream); +static void recv_image (FpDeviceVirtualImage *dev, + GInputStream *stream); static void recv_image_img_recv_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { - g_autoptr(GError) error = NULL; - FpDeviceVirtualImage *self; - FpImageDevice *device; - gssize bytes; + g_autoptr(GError) error = NULL; + FpDeviceVirtualImage *self; + FpImageDevice *device; + gssize bytes; - bytes = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error); + bytes = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error); - if (bytes <= 0) { - if (bytes < 0) { - g_warning ("Error receiving header for image data: %s", error->message); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - } + if (bytes <= 0) + { + if (bytes < 0) + { + g_warning ("Error receiving header for image data: %s", error->message); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + } - self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); - g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); - self->connection = NULL; - return; - } + self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); + g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); + self->connection = NULL; + return; + } - self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); - device = FP_IMAGE_DEVICE (self); + self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); + device = FP_IMAGE_DEVICE (self); - fpi_image_device_report_finger_status (device, TRUE); - fpi_image_device_image_captured (device, g_steal_pointer (&self->recv_img)); - fpi_image_device_report_finger_status (device, FALSE); + fpi_image_device_report_finger_status (device, TRUE); + fpi_image_device_image_captured (device, g_steal_pointer (&self->recv_img)); + fpi_image_device_report_finger_status (device, FALSE); - /* And, listen for more images from the same client. */ - recv_image(self, G_INPUT_STREAM (source_object)); + /* And, listen for more images from the same client. */ + recv_image (self, G_INPUT_STREAM (source_object)); } static void @@ -97,180 +101,189 @@ recv_image_hdr_recv_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { - g_autoptr(GError) error = NULL; - FpDeviceVirtualImage *self; - gssize bytes; + g_autoptr(GError) error = NULL; + FpDeviceVirtualImage *self; + gssize bytes; - bytes = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error); + bytes = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error); - if (bytes <= 0) { - if (bytes < 0) { - g_warning ("Error receiving header for image data: %s", error->message); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - } + if (bytes <= 0) + { + if (bytes < 0) + { + g_warning ("Error receiving header for image data: %s", error->message); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + } - self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); - g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); - self->connection = NULL; - return; - } + self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); + g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); + self->connection = NULL; + return; + } - self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); - if (self->recv_img_hdr[0] > 5000 || self->recv_img_hdr[1] > 5000) { - g_warning ("Image header suggests an unrealistically large image, disconnecting client."); - g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); - self->connection = NULL; - } + self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); + if (self->recv_img_hdr[0] > 5000 || self->recv_img_hdr[1] > 5000) + { + g_warning ("Image header suggests an unrealistically large image, disconnecting client."); + g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); + self->connection = NULL; + } - if (self->recv_img_hdr[0] < 0 || self->recv_img_hdr[1] < 0) { - switch (self->recv_img_hdr[0]) { - case -1: - /* -1 is a retry error, just pass it through */ - fpi_image_device_retry_scan (FP_IMAGE_DEVICE (self), self->recv_img_hdr[1]); - break; + if (self->recv_img_hdr[0] < 0 || self->recv_img_hdr[1] < 0) + { + switch (self->recv_img_hdr[0]) + { + case -1: + /* -1 is a retry error, just pass it through */ + fpi_image_device_retry_scan (FP_IMAGE_DEVICE (self), self->recv_img_hdr[1]); + break; - case -2: - /* -2 is a fatal error, just pass it through*/ - fpi_image_device_session_error (FP_IMAGE_DEVICE (self), - fpi_device_error_new (self->recv_img_hdr[1])); - break; + case -2: + /* -2 is a fatal error, just pass it through*/ + fpi_image_device_session_error (FP_IMAGE_DEVICE (self), + fpi_device_error_new (self->recv_img_hdr[1])); + break; - default: - /* disconnect client, it didn't play fair */ - g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); - self->connection = NULL; - } + default: + /* disconnect client, it didn't play fair */ + g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); + self->connection = NULL; + } - /* And, listen for more images from the same client. */ - recv_image(self, G_INPUT_STREAM (source_object)); - return; - } + /* And, listen for more images from the same client. */ + recv_image (self, G_INPUT_STREAM (source_object)); + return; + } - self->recv_img = fp_image_new (self->recv_img_hdr[0], self->recv_img_hdr[1]); - g_debug ("image data: %p", self->recv_img->data); - g_input_stream_read_async (G_INPUT_STREAM (source_object), - (guint8*)self->recv_img->data, - self->recv_img->width * self->recv_img->height, - G_PRIORITY_DEFAULT, - self->cancellable, - recv_image_img_recv_cb, - self); + self->recv_img = fp_image_new (self->recv_img_hdr[0], self->recv_img_hdr[1]); + g_debug ("image data: %p", self->recv_img->data); + g_input_stream_read_async (G_INPUT_STREAM (source_object), + (guint8 *) self->recv_img->data, + self->recv_img->width * self->recv_img->height, + G_PRIORITY_DEFAULT, + self->cancellable, + recv_image_img_recv_cb, + self); } static void recv_image (FpDeviceVirtualImage *dev, GInputStream *stream) { - g_input_stream_read_async (stream, - dev->recv_img_hdr, - sizeof(dev->recv_img_hdr), - G_PRIORITY_DEFAULT, - dev->cancellable, - recv_image_hdr_recv_cb, - dev); + g_input_stream_read_async (stream, + dev->recv_img_hdr, + sizeof (dev->recv_img_hdr), + G_PRIORITY_DEFAULT, + dev->cancellable, + recv_image_hdr_recv_cb, + dev); } static void new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { - g_autoptr(GError) error = NULL; - GSocketConnection *connection; - GInputStream *stream; - FpDeviceVirtualImage *dev = user_data; + g_autoptr(GError) error = NULL; + GSocketConnection *connection; + GInputStream *stream; + FpDeviceVirtualImage *dev = user_data; - connection = g_socket_listener_accept_finish (G_SOCKET_LISTENER (source_object), - res, - NULL, - &error); - if (!connection) { - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; + connection = g_socket_listener_accept_finish (G_SOCKET_LISTENER (source_object), + res, + NULL, + &error); + if (!connection) + { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; - g_warning ("Error accepting a new connection: %s", error->message); - start_listen(dev); - } + g_warning ("Error accepting a new connection: %s", error->message); + start_listen (dev); + } - /* Always further connections (but we disconnect them immediately - * if we already have a connection). */ - start_listen(dev); - if (dev->connection) { - g_io_stream_close (G_IO_STREAM (connection), NULL, NULL); - return; - } + /* Always further connections (but we disconnect them immediately + * if we already have a connection). */ + start_listen (dev); + if (dev->connection) + { + g_io_stream_close (G_IO_STREAM (connection), NULL, NULL); + return; + } - dev->connection = connection; - stream = g_io_stream_get_input_stream (G_IO_STREAM (connection)); + dev->connection = connection; + stream = g_io_stream_get_input_stream (G_IO_STREAM (connection)); - recv_image (dev, stream); + recv_image (dev, stream); - fp_dbg("Got a new connection!"); + fp_dbg ("Got a new connection!"); } static void start_listen (FpDeviceVirtualImage *dev) { - g_socket_listener_accept_async (dev->listener, - dev->cancellable, - new_connection_cb, - dev); + g_socket_listener_accept_async (dev->listener, + dev->cancellable, + new_connection_cb, + dev); } static void -dev_init(FpImageDevice *dev) +dev_init (FpImageDevice *dev) { - g_autoptr(GError) error = NULL; - g_autoptr(GSocketListener) listener = NULL; - FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev); - const char *env; - g_autoptr(GSocketAddress) addr = NULL; - G_DEBUG_HERE(); + g_autoptr(GError) error = NULL; + g_autoptr(GSocketListener) listener = NULL; + FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev); + const char *env; + g_autoptr(GSocketAddress) addr = NULL; + G_DEBUG_HERE (); - self->client_fd = -1; + self->client_fd = -1; - env = fpi_device_get_virtual_env (FP_DEVICE (self)); + env = fpi_device_get_virtual_env (FP_DEVICE (self)); - listener = g_socket_listener_new (); - g_socket_listener_set_backlog (listener, 1); + listener = g_socket_listener_new (); + g_socket_listener_set_backlog (listener, 1); - /* Remove any left over socket. */ - g_unlink (env); + /* Remove any left over socket. */ + g_unlink (env); - addr = g_unix_socket_address_new (env); + addr = g_unix_socket_address_new (env); - if (!g_socket_listener_add_address (listener, - addr, - G_SOCKET_TYPE_STREAM, - G_SOCKET_PROTOCOL_DEFAULT, - NULL, - NULL, - &error)) { - g_warning ("Could not listen on unix socket: %s", error->message); + if (!g_socket_listener_add_address (listener, + addr, + G_SOCKET_TYPE_STREAM, + G_SOCKET_PROTOCOL_DEFAULT, + NULL, + NULL, + &error)) + { + g_warning ("Could not listen on unix socket: %s", error->message); - fpi_image_device_open_complete (FP_IMAGE_DEVICE (dev), g_steal_pointer (&error)); + fpi_image_device_open_complete (FP_IMAGE_DEVICE (dev), g_steal_pointer (&error)); - return; - } + return; + } - self->listener = g_steal_pointer (&listener); - self->cancellable = g_cancellable_new (); + self->listener = g_steal_pointer (&listener); + self->cancellable = g_cancellable_new (); - start_listen (self); + start_listen (self); - fpi_image_device_open_complete (dev, NULL); + fpi_image_device_open_complete (dev, NULL); } -static void dev_deinit(FpImageDevice *dev) +static void +dev_deinit (FpImageDevice *dev) { - FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev); + FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev); - G_DEBUG_HERE(); + G_DEBUG_HERE (); - g_cancellable_cancel (self->cancellable); - g_clear_object (&self->cancellable); - g_clear_object (&self->listener); - g_clear_object (&self->connection); + g_cancellable_cancel (self->cancellable); + g_clear_object (&self->cancellable); + g_clear_object (&self->listener); + g_clear_object (&self->connection); - fpi_image_device_close_complete(dev, NULL); + fpi_image_device_close_complete (dev, NULL); } static void @@ -279,22 +292,21 @@ fpi_device_virtual_image_init (FpDeviceVirtualImage *self) } static const FpIdEntry driver_ids[] = { - { .virtual_envvar = "FP_VIRTUAL_IMAGE" }, - { .virtual_envvar = NULL } + { .virtual_envvar = "FP_VIRTUAL_IMAGE" }, + { .virtual_envvar = NULL } }; static void fpi_device_virtual_image_class_init (FpDeviceVirtualImageClass *klass) { - FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); - FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); - dev_class->id = FP_COMPONENT; - dev_class->full_name = "Virtual image device for debugging"; - dev_class->type = FP_DEVICE_TYPE_VIRTUAL; - dev_class->id_table = driver_ids; + dev_class->id = FP_COMPONENT; + dev_class->full_name = "Virtual image device for debugging"; + dev_class->type = FP_DEVICE_TYPE_VIRTUAL; + dev_class->id_table = driver_ids; - img_class->img_open = dev_init; - img_class->img_close = dev_deinit; + img_class->img_open = dev_init; + img_class->img_close = dev_deinit; } - diff --git a/libfprint/fp_internal.h b/libfprint/fp_internal.h index 0f4df4ae..81470893 100644 --- a/libfprint/fp_internal.h +++ b/libfprint/fp_internal.h @@ -26,26 +26,28 @@ #include "fpi-image-device.h" /* fp_minutia structure definition */ -struct fp_minutia { - int x; - int y; - int ex; - int ey; - int direction; - double reliability; - int type; - int appearing; - int feature_id; - int *nbrs; - int *ridge_counts; - int num_nbrs; +struct fp_minutia +{ + int x; + int y; + int ex; + int ey; + int direction; + double reliability; + int type; + int appearing; + int feature_id; + int *nbrs; + int *ridge_counts; + int num_nbrs; }; /* fp_minutiae structure definition */ -struct fp_minutiae { - int alloc; - int num; - struct fp_minutia **list; +struct fp_minutiae +{ + int alloc; + int num; + struct fp_minutia **list; }; diff --git a/libfprint/fprint-list-supported-devices.c b/libfprint/fprint-list-supported-devices.c index 23096ea5..124e9d9e 100644 --- a/libfprint/fprint-list-supported-devices.c +++ b/libfprint/fprint-list-supported-devices.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Red Hat + * Copyright (C) 2009 Red Hat * Copyright (C) 2008 Bastien Nocera * Copyright (C) 2008 Timo Hoenig , * Coypright (C) 2019 Benjamin Berg @@ -28,9 +28,10 @@ GHashTable *printed = NULL; -static GList *insert_drivers (GList *list) +static GList * +insert_drivers (GList *list) { - g_autoptr(GArray) drivers = g_array_new (FALSE, FALSE, sizeof(GType)); + g_autoptr(GArray) drivers = g_array_new (FALSE, FALSE, sizeof (GType)); gint i; fpi_get_driver_types (drivers); @@ -42,10 +43,11 @@ static GList *insert_drivers (GList *list) FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver)); const FpIdEntry *entry; - if (cls->type != FP_DEVICE_TYPE_USB) { - g_type_class_unref (cls); - continue; - } + if (cls->type != FP_DEVICE_TYPE_USB) + { + g_type_class_unref (cls); + continue; + } for (entry = cls->id_table; entry->vid; entry++) { @@ -53,53 +55,55 @@ static GList *insert_drivers (GList *list) key = g_strdup_printf ("%04x:%04x", entry->vid, entry->pid); - if (g_hash_table_lookup (printed, key) != NULL) { - g_free (key); - continue; - } + if (g_hash_table_lookup (printed, key) != NULL) + { + g_free (key); + continue; + } - g_hash_table_insert (printed, key, GINT_TO_POINTER (1)); + g_hash_table_insert (printed, key, GINT_TO_POINTER (1)); - list = g_list_prepend (list, g_strdup_printf ("%s | %s\n", key, cls->full_name)); + list = g_list_prepend (list, g_strdup_printf ("%s | %s\n", key, cls->full_name)); } g_type_class_unref (cls); } - return list; + return list; } -int main (int argc, char **argv) +int +main (int argc, char **argv) { - GList *list, *l; + GList *list, *l; - setlocale (LC_ALL, ""); + setlocale (LC_ALL, ""); - printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - g_print ("%% lifprint — Supported Devices\n"); - g_print ("%% Bastien Nocera, Daniel Drake\n"); - g_print ("%% 2018\n"); - g_print ("\n"); + g_print ("%% lifprint — Supported Devices\n"); + g_print ("%% Bastien Nocera, Daniel Drake\n"); + g_print ("%% 2018\n"); + g_print ("\n"); - g_print ("# Supported Devices\n"); - g_print ("\n"); - g_print ("This is a list of supported devices in libfprint's development version. Those drivers might not all be available in the stable, released version. If in doubt, contact your distribution or systems integrator for details.\n"); - g_print ("\n"); - g_print ("## USB devices\n"); - g_print ("\n"); - g_print ("USB ID | Driver\n"); - g_print ("------------ | ------------\n"); + g_print ("# Supported Devices\n"); + g_print ("\n"); + g_print ("This is a list of supported devices in libfprint's development version. Those drivers might not all be available in the stable, released version. If in doubt, contact your distribution or systems integrator for details.\n"); + g_print ("\n"); + g_print ("## USB devices\n"); + g_print ("\n"); + g_print ("USB ID | Driver\n"); + g_print ("------------ | ------------\n"); - list = NULL; - list = insert_drivers (list); + list = NULL; + list = insert_drivers (list); - list = g_list_sort (list, (GCompareFunc) g_strcmp0); - for (l = list; l != NULL; l = l->next) - g_print ("%s", (char *) l->data); + list = g_list_sort (list, (GCompareFunc) g_strcmp0); + for (l = list; l != NULL; l = l->next) + g_print ("%s", (char *) l->data); - g_list_free_full (list, g_free); - g_hash_table_destroy (printed); + g_list_free_full (list, g_free); + g_hash_table_destroy (printed); - return 0; + return 0; } diff --git a/libfprint/fprint-list-udev-rules.c b/libfprint/fprint-list-udev-rules.c index 76f84867..0c1b0591 100644 --- a/libfprint/fprint-list-udev-rules.c +++ b/libfprint/fprint-list-udev-rules.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Red Hat + * Copyright (C) 2009 Red Hat * Copyright (C) 2008 Bastien Nocera * Copyright (C) 2008 Timo Hoenig , * Coypright (C) 2019 Benjamin Berg @@ -25,100 +25,105 @@ #include "fpi-device.h" static const FpIdEntry whitelist_id_table[] = { - /* Unsupported (for now) Validity Sensors finger print readers */ - { .vid = 0x138a, .pid = 0x0090 }, /* Found on e.g. Lenovo T460s */ - { .vid = 0x138a, .pid = 0x0091 }, - { .vid = 0x138a, .pid = 0x0094 }, - { .vid = 0x138a, .pid = 0x0097 }, /* Found on e.g. Lenovo T470s */ - { .vid = 0 }, + /* Unsupported (for now) Validity Sensors finger print readers */ + { .vid = 0x138a, .pid = 0x0090 }, /* Found on e.g. Lenovo T460s */ + { .vid = 0x138a, .pid = 0x0091 }, + { .vid = 0x138a, .pid = 0x0094 }, + { .vid = 0x138a, .pid = 0x0097 }, /* Found on e.g. Lenovo T470s */ + { .vid = 0 }, }; static const FpIdEntry blacklist_id_table[] = { - { .vid = 0x0483, .pid = 0x2016 }, - /* https://bugs.freedesktop.org/show_bug.cgi?id=66659 */ - { .vid = 0x045e, .pid = 0x00bb }, - { .vid = 0 }, + { .vid = 0x0483, .pid = 0x2016 }, + /* https://bugs.freedesktop.org/show_bug.cgi?id=66659 */ + { .vid = 0x045e, .pid = 0x00bb }, + { .vid = 0 }, }; static const FpDeviceClass whitelist = { - .type = FP_DEVICE_TYPE_USB, - .id_table = whitelist_id_table, - .full_name = "Hardcoded whitelist" + .type = FP_DEVICE_TYPE_USB, + .id_table = whitelist_id_table, + .full_name = "Hardcoded whitelist" }; GHashTable *printed = NULL; -static void print_driver (const FpDeviceClass *cls) +static void +print_driver (const FpDeviceClass *cls) { - const FpIdEntry *entry; - gint num_printed = 0; + const FpIdEntry *entry; + gint num_printed = 0; - if (cls->type != FP_DEVICE_TYPE_USB) - return; + if (cls->type != FP_DEVICE_TYPE_USB) + return; - for (entry = cls->id_table; entry->vid != 0; entry++) { - const FpIdEntry *bl_entry; - char *key; + for (entry = cls->id_table; entry->vid != 0; entry++) + { + const FpIdEntry *bl_entry; + char *key; - for (bl_entry = blacklist_id_table; bl_entry->vid != 0; bl_entry++) { - if (entry->vid == bl_entry->vid && entry->pid == bl_entry->pid) { - break; - } - } - if (bl_entry->vid != 0) - continue; + for (bl_entry = blacklist_id_table; bl_entry->vid != 0; bl_entry++) + if (entry->vid == bl_entry->vid && entry->pid == bl_entry->pid) + break; - key = g_strdup_printf ("%04x:%04x", entry->vid, entry->pid); + if (bl_entry->vid != 0) + continue; - if (g_hash_table_lookup (printed, key) != NULL) { - g_free (key); - continue; - } + key = g_strdup_printf ("%04x:%04x", entry->vid, entry->pid); - g_hash_table_insert (printed, key, GINT_TO_POINTER (1)); + if (g_hash_table_lookup (printed, key) != NULL) + { + g_free (key); + continue; + } - if (num_printed == 0) - g_print ("# %s\n", cls->full_name); + g_hash_table_insert (printed, key, GINT_TO_POINTER (1)); - g_print ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ATTRS{dev}==\"*\", TEST==\"power/control\", ATTR{power/control}=\"auto\"\n", - entry->vid, entry->pid); - g_print ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ENV{LIBFPRINT_DRIVER}=\"%s\"\n", - entry->vid, entry->pid, cls->full_name); - num_printed++; + if (num_printed == 0) + g_print ("# %s\n", cls->full_name); + + g_print ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ATTRS{dev}==\"*\", TEST==\"power/control\", ATTR{power/control}=\"auto\"\n", + entry->vid, entry->pid); + g_print ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ENV{LIBFPRINT_DRIVER}=\"%s\"\n", + entry->vid, entry->pid, cls->full_name); + num_printed++; } - if (num_printed > 0) - g_print ("\n"); + if (num_printed > 0) + g_print ("\n"); } -int main (int argc, char **argv) +int +main (int argc, char **argv) { - g_autoptr(GArray) drivers = g_array_new (FALSE, FALSE, sizeof(GType)); - guint i; + g_autoptr(GArray) drivers = g_array_new (FALSE, FALSE, sizeof (GType)); + guint i; - g_print ("%p\n", drivers); - g_print ("%p\n", fpi_get_driver_types); - fpi_get_driver_types (drivers); + g_print ("%p\n", drivers); + g_print ("%p\n", fpi_get_driver_types); + fpi_get_driver_types (drivers); - printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - for (i = 0; i < drivers->len; i++) { - GType driver = g_array_index (drivers, GType, i); - FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver)); + for (i = 0; i < drivers->len; i++) + { + GType driver = g_array_index (drivers, GType, i); + FpDeviceClass *cls = FP_DEVICE_CLASS (g_type_class_ref (driver)); - if (cls->type != FP_DEVICE_TYPE_USB) { - g_type_class_unref (cls); - continue; - } + if (cls->type != FP_DEVICE_TYPE_USB) + { + g_type_class_unref (cls); + continue; + } - print_driver (cls); + print_driver (cls); - g_type_class_unref (cls); + g_type_class_unref (cls); } - print_driver (&whitelist); + print_driver (&whitelist); - g_hash_table_destroy (printed); + g_hash_table_destroy (printed); - return 0; + return 0; } diff --git a/libfprint/fprint.h b/libfprint/fprint.h index a4729ea9..6db6cfda 100644 --- a/libfprint/fprint.h +++ b/libfprint/fprint.h @@ -22,4 +22,3 @@ #include "fp-context.h" #include "fp-device.h" #include "fp-image.h" - diff --git a/scripts/uncrustify.sh b/scripts/uncrustify.sh index 9a82320f..cb039069 100755 --- a/scripts/uncrustify.sh +++ b/scripts/uncrustify.sh @@ -13,7 +13,7 @@ case "$1" in esac pushd "$SRCROOT" -uncrustify -c "$CFG" $OPTS `git ls-tree --name-only -r HEAD | grep -E '(fp|fpi)-.*\.[ch]$' | grep -v nbis | grep -v fpi-byte | grep -v build/` +uncrustify -c "$CFG" $OPTS `git ls-tree --name-only -r HEAD | grep -E '.*\.[ch]$' | grep -v nbis | grep -v fpi-byte | grep -v build/` RES=$? popd exit $RES \ No newline at end of file From f2b932960ea702e46f1ecae2f9fbd5a563b94839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 20 Nov 2019 13:41:35 +0100 Subject: [PATCH 68/73] lib: Use g_new0 rather than g_malloc0 Port some of the g_malloc0 users to g_new0. --- libfprint/drivers/vfs5011.c | 3 +-- libfprint/fpi-assembling.c | 2 +- libfprint/fpi-ssm.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libfprint/drivers/vfs5011.c b/libfprint/drivers/vfs5011.c index 301a1d64..0bcf8549 100644 --- a/libfprint/drivers/vfs5011.c +++ b/libfprint/drivers/vfs5011.c @@ -806,8 +806,7 @@ dev_open (FpImageDevice *dev) FpDeviceVfs5011 *self; self = FPI_DEVICE_VFS5011 (dev); - self->capture_buffer = - (unsigned char *) g_malloc0 (CAPTURE_LINES * VFS5011_LINE_SIZE); + self->capture_buffer = g_new0 (unsigned char, CAPTURE_LINES * VFS5011_LINE_SIZE); if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error)) { diff --git a/libfprint/fpi-assembling.c b/libfprint/fpi-assembling.c index 634a50f0..75291c09 100644 --- a/libfprint/fpi-assembling.c +++ b/libfprint/fpi-assembling.c @@ -426,7 +426,7 @@ fpi_assemble_lines (struct fpi_line_asmbl_ctx *ctx, GSList *row1, *row2; float y = 0.0; int line_ind = 0; - int *offsets = (int *) g_malloc0 ((num_lines / 2) * sizeof (int)); + int *offsets = g_new0 (int, num_lines / 2); unsigned char *output = g_malloc0 (ctx->line_width * ctx->max_height); FpImage *img; diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c index 2fb25650..c9da3c8d 100644 --- a/libfprint/fpi-ssm.c +++ b/libfprint/fpi-ssm.c @@ -110,7 +110,7 @@ fpi_ssm_new (FpDevice *dev, BUG_ON (nr_states < 1); - machine = g_malloc0 (sizeof (*machine)); + machine = g_new0 (FpiSsm, 1); machine->handler = handler; machine->nr_states = nr_states; machine->dev = dev; From ab804f7f49c61088e972d637a1886dc78544d948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 20 Nov 2019 14:29:46 +0100 Subject: [PATCH 69/73] examples: Make possible to select the finger to enroll/verify Move some common functions to an utilities file. --- examples/enroll.c | 32 ++++++++++---- examples/manage-prints.c | 43 +----------------- examples/meson.build | 2 +- examples/utilities.c | 94 ++++++++++++++++++++++++++++++++++++++++ examples/utilities.h | 27 ++++++++++++ examples/verify.c | 30 +++++++++---- 6 files changed, 169 insertions(+), 59 deletions(-) create mode 100644 examples/utilities.c create mode 100644 examples/utilities.h diff --git a/examples/enroll.c b/examples/enroll.c index 81535f2a..24c13dbc 100644 --- a/examples/enroll.c +++ b/examples/enroll.c @@ -1,6 +1,6 @@ /* * Example fingerprint enrollment program - * Enrolls your right index finger and saves the print to disk + * Enrolls your choosen finger and saves the print to disk * Copyright (C) 2007 Daniel Drake * Copyright (C) 2019 Marco Trevisan * @@ -23,10 +23,12 @@ #include #include "storage.h" +#include "utilities.h" typedef struct _EnrollData { GMainLoop *loop; + FpFinger finger; int ret_value; } EnrollData; @@ -82,7 +84,7 @@ on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data) if (!fp_device_has_storage (dev)) { g_debug ("Device has not storage, saving locally"); - int r = print_data_save (print, FP_FINGER_RIGHT_INDEX); + int r = print_data_save (print, enroll_data->finger); if (r < 0) { g_warning ("Data save failed, code %d", r); @@ -139,11 +141,12 @@ on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data) } printf ("Opened device. It's now time to enroll your finger.\n\n"); - printf ("You will need to successfully scan your finger %d times to " - "complete the process.\n\n", fp_device_get_nr_enroll_stages (dev)); + printf ("You will need to successfully scan your %s finger %d times to " + "complete the process.\n\n", finger_to_string (enroll_data->finger), + fp_device_get_nr_enroll_stages (dev)); printf ("Scan your finger now.\n"); - print_template = print_create_template (dev, FP_FINGER_RIGHT_INDEX); + print_template = print_create_template (dev, enroll_data->finger); fp_device_enroll (dev, print_template, NULL, on_enroll_progress, NULL, NULL, (GAsyncReadyCallback) on_enroll_completed, enroll_data); @@ -156,13 +159,23 @@ main (void) g_autoptr(EnrollData) enroll_data = NULL; GPtrArray *devices; FpDevice *dev; + FpFinger finger; - printf ("This program will enroll your right index finger, " - "unconditionally overwriting any right-index print that was enrolled " - "previously. If you want to continue, press enter, otherwise hit " - "Ctrl+C\n"); + g_print ("This program will enroll the selected finger, unconditionally " + "overwriting any print for the same finger that was enrolled " + "previously. If you want to continue, press enter, otherwise hit " + "Ctrl+C\n"); getchar (); + g_print ("Choose the finger to enroll:\n"); + finger = finger_chooser (); + + if (finger == FP_FINGER_UNKNOWN) + { + g_warning ("Unknown finger selected"); + return EXIT_FAILURE; + } + setenv ("G_MESSAGES_DEBUG", "all", 0); ctx = fp_context_new (); @@ -182,6 +195,7 @@ main (void) } enroll_data = g_new0 (EnrollData, 1); + enroll_data->finger = finger; enroll_data->ret_value = EXIT_FAILURE; enroll_data->loop = g_main_loop_new (NULL, FALSE); diff --git a/examples/manage-prints.c b/examples/manage-prints.c index 16ab54f0..ba724677 100644 --- a/examples/manage-prints.c +++ b/examples/manage-prints.c @@ -21,6 +21,7 @@ #include #include +#include "utilities.h" typedef struct _ListData { @@ -68,46 +69,6 @@ on_device_closed (FpDevice *dev, g_main_loop_quit (list_data->loop); } -const char * -finger_to_string (FpFinger finger) -{ - switch (finger) - { - case FP_FINGER_LEFT_THUMB: - return "left thumb"; - - case FP_FINGER_LEFT_INDEX: - return "left index"; - - case FP_FINGER_LEFT_MIDDLE: - return "left middle"; - - case FP_FINGER_LEFT_RING: - return "left ring"; - - case FP_FINGER_LEFT_LITTLE: - return "left little"; - - case FP_FINGER_RIGHT_THUMB: - return "right thumb"; - - case FP_FINGER_RIGHT_INDEX: - return "right index"; - - case FP_FINGER_RIGHT_MIDDLE: - return "right middle"; - - case FP_FINGER_RIGHT_RING: - return "right ring"; - - case FP_FINGER_RIGHT_LITTLE: - return "right little"; - - default: - return "unknown"; - } -} - typedef struct _DeleteData { ListData *list_data; @@ -218,7 +179,7 @@ on_list_completed (FpDevice *dev, { gint64 idx = 0; - g_print ("Want to delete saved print? [/A/n]\n"); + g_print ("Want to delete saved print? [/A/n]\n> "); if (fgets (buf, 3, stdin)) idx = g_ascii_strtoll (buf, NULL, 10); diff --git a/examples/meson.build b/examples/meson.build index 216a96e1..5cd3d835 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -2,7 +2,7 @@ examples = [ 'enroll', 'verify', 'manage-prints' ] foreach example: examples executable(example, - [example + '.c', 'storage.c'], + [example + '.c', 'storage.c', 'utilities.c'], dependencies: [libfprint_dep, glib_dep], include_directories: [ root_inc, diff --git a/examples/utilities.c b/examples/utilities.c new file mode 100644 index 00000000..bae23892 --- /dev/null +++ b/examples/utilities.c @@ -0,0 +1,94 @@ +/* + * Utilities for example programs + * + * Copyright (C) 2019 Marco Trevisan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "utilities.h" + +const char * +finger_to_string (FpFinger finger) +{ + switch (finger) + { + case FP_FINGER_LEFT_THUMB: + return "left thumb"; + + case FP_FINGER_LEFT_INDEX: + return "left index"; + + case FP_FINGER_LEFT_MIDDLE: + return "left middle"; + + case FP_FINGER_LEFT_RING: + return "left ring"; + + case FP_FINGER_LEFT_LITTLE: + return "left little"; + + case FP_FINGER_RIGHT_THUMB: + return "right thumb"; + + case FP_FINGER_RIGHT_INDEX: + return "right index"; + + case FP_FINGER_RIGHT_MIDDLE: + return "right middle"; + + case FP_FINGER_RIGHT_RING: + return "right ring"; + + case FP_FINGER_RIGHT_LITTLE: + return "right little"; + + default: + return "unknown"; + } +} + +FpFinger +finger_chooser (void) +{ + int i; + const FpFinger all_fingers[] = { + FP_FINGER_LEFT_THUMB, + FP_FINGER_LEFT_INDEX, + FP_FINGER_LEFT_MIDDLE, + FP_FINGER_LEFT_RING, + FP_FINGER_LEFT_LITTLE, + FP_FINGER_RIGHT_THUMB, + FP_FINGER_RIGHT_INDEX, + FP_FINGER_RIGHT_MIDDLE, + FP_FINGER_RIGHT_RING, + FP_FINGER_RIGHT_LITTLE, + }; + + for (i = all_fingers[0]; i <= G_N_ELEMENTS (all_fingers); ++i) + g_print(" [%d] %s\n", (i - all_fingers[0]), finger_to_string (i)); + + g_print ("> "); + if (!scanf ("%d%*c", &i)) + return FP_FINGER_UNKNOWN; + + if (i < 0 || i >= G_N_ELEMENTS (all_fingers)) + return FP_FINGER_UNKNOWN; + + return all_fingers[i]; +} diff --git a/examples/utilities.h b/examples/utilities.h new file mode 100644 index 00000000..ea2871a5 --- /dev/null +++ b/examples/utilities.h @@ -0,0 +1,27 @@ +/* + * Trivial storage driver for example programs + * + * Copyright (C) 2019 Marco Trevisan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __UTILITIES_H +#define __UTILITIES_H + +FpFinger finger_chooser (void); +const char * finger_to_string (FpFinger finger); + +#endif /* __UTILITIES_H */ diff --git a/examples/verify.c b/examples/verify.c index e5432822..82673b19 100644 --- a/examples/verify.c +++ b/examples/verify.c @@ -1,5 +1,5 @@ /* - * Example fingerprint verification program, which verifies the right index + * Example fingerprint verification program, which verifies the * finger which has been previously enrolled to disk. * Copyright (C) 2007 Daniel Drake * Copyright (C) 2019 Marco Trevisan @@ -23,10 +23,12 @@ #include #include "storage.h" +#include "utilities.h" typedef struct _VerifyData { GMainLoop *loop; + FpFinger finger; int ret_value; } VerifyData; @@ -134,7 +136,7 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data) { FpPrint *print = prints->pdata[i]; - if (fp_print_get_finger (print) == FP_FINGER_RIGHT_INDEX && + if (fp_print_get_finger (print) == verify_data->finger && g_strcmp0 (fp_print_get_username (print), g_get_user_name ()) == 0) { if (!verify_print || @@ -146,8 +148,8 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data) if (!verify_print) { - g_warning ("Did you remember to enroll your right index " - "finger first?"); + g_warning ("Did you remember to enroll your %s finger first?", + finger_to_string (verify_data->finger)); g_main_loop_quit (verify_data->loop); return; } @@ -170,6 +172,17 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data) static void start_verification (FpDevice *dev, VerifyData *verify_data) { + g_print ("Choose the finger to verify:\n"); + verify_data->finger = finger_chooser (); + + if (verify_data->finger == FP_FINGER_UNKNOWN) + { + g_warning ("Unknown finger selected"); + verify_data->ret_value = EXIT_FAILURE; + g_main_loop_quit (verify_data->loop); + return; + } + if (fp_device_has_storage (dev)) { g_print ("Creating finger template, using device storage...\n"); @@ -179,16 +192,17 @@ start_verification (FpDevice *dev, VerifyData *verify_data) } else { - g_print ("Loading previously enrolled right index finger data...\n"); + g_print ("Loading previously enrolled %s finger data...\n", + finger_to_string (verify_data->finger)); g_autoptr(FpPrint) verify_print; - verify_print = print_data_load (dev, FP_FINGER_RIGHT_INDEX); + verify_print = print_data_load (dev, verify_data->finger); if (!verify_print) { g_warning ("Failed to load fingerprint data"); - g_warning ("Did you remember to enroll your right index " - "finger first?"); + g_warning ("Did you remember to enroll your %s finger first?", + finger_to_string (verify_data->finger)); g_main_loop_quit (verify_data->loop); return; } From 39e3e2b794028d0480f82220e6697c362de5e17b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 20 Nov 2019 14:36:57 +0100 Subject: [PATCH 70/73] examples: Move discover_device function to utilities While there are various functions which similar usage in all the examples, I'd prefer to keep each example to be self-containing most of the things. However some clearly repeated action can be moved to a single codebase. --- examples/enroll.c | 12 ------------ examples/manage-prints.c | 12 ------------ examples/utilities.c | 17 ++++++++++++++++- examples/utilities.h | 1 + examples/verify.c | 12 ------------ 5 files changed, 17 insertions(+), 37 deletions(-) diff --git a/examples/enroll.c b/examples/enroll.c index 24c13dbc..159ffbc0 100644 --- a/examples/enroll.c +++ b/examples/enroll.c @@ -40,18 +40,6 @@ enroll_data_free (EnrollData *enroll_data) } G_DEFINE_AUTOPTR_CLEANUP_FUNC (EnrollData, enroll_data_free) -FpDevice *discover_device (GPtrArray * devices) -{ - FpDevice *dev; - - if (!devices->len) - return NULL; - - dev = g_ptr_array_index (devices, 0); - printf ("Found device claimed by %s driver\n", fp_device_get_driver (dev)); - return dev; -} - static void on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data) { diff --git a/examples/manage-prints.c b/examples/manage-prints.c index ba724677..b865af75 100644 --- a/examples/manage-prints.c +++ b/examples/manage-prints.c @@ -40,18 +40,6 @@ list_data_free (ListData *list_data) } G_DEFINE_AUTOPTR_CLEANUP_FUNC (ListData, list_data_free) -FpDevice *discover_device (GPtrArray * devices) -{ - FpDevice *dev; - - if (!devices->len) - return NULL; - - dev = g_ptr_array_index (devices, 0); - g_print ("Found device claimed by %s driver\n", fp_device_get_driver (dev)); - return dev; -} - static void on_device_closed (FpDevice *dev, GAsyncResult *res, diff --git a/examples/utilities.c b/examples/utilities.c index bae23892..70f57b25 100644 --- a/examples/utilities.c +++ b/examples/utilities.c @@ -23,6 +23,21 @@ #include "utilities.h" +FpDevice * +discover_device (GPtrArray * devices) +{ + FpDevice *dev; + + if (!devices->len) + return NULL; + + dev = g_ptr_array_index (devices, 0); + g_print ("Found device %s (%s) claimed by %s driver\n", + fp_device_get_device_id (dev), fp_device_get_name (dev), + fp_device_get_driver (dev)); + return dev; +} + const char * finger_to_string (FpFinger finger) { @@ -81,7 +96,7 @@ finger_chooser (void) }; for (i = all_fingers[0]; i <= G_N_ELEMENTS (all_fingers); ++i) - g_print(" [%d] %s\n", (i - all_fingers[0]), finger_to_string (i)); + g_print (" [%d] %s\n", (i - all_fingers[0]), finger_to_string (i)); g_print ("> "); if (!scanf ("%d%*c", &i)) diff --git a/examples/utilities.h b/examples/utilities.h index ea2871a5..7e436acf 100644 --- a/examples/utilities.h +++ b/examples/utilities.h @@ -21,6 +21,7 @@ #ifndef __UTILITIES_H #define __UTILITIES_H +FpDevice * discover_device (GPtrArray *devices); FpFinger finger_chooser (void); const char * finger_to_string (FpFinger finger); diff --git a/examples/verify.c b/examples/verify.c index 82673b19..89a9b2c6 100644 --- a/examples/verify.c +++ b/examples/verify.c @@ -40,18 +40,6 @@ verify_data_free (VerifyData *verify_data) } G_DEFINE_AUTOPTR_CLEANUP_FUNC (VerifyData, verify_data_free) -FpDevice *discover_device (GPtrArray * devices) -{ - FpDevice *dev; - - if (!devices->len) - return NULL; - - dev = g_ptr_array_index (devices, 0); - printf ("Found device claimed by %s driver\n", fp_device_get_driver (dev)); - return dev; -} - static void on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data) { From 1319daba541f6f441f6056265ded570e8e3954e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 20 Nov 2019 14:53:36 +0100 Subject: [PATCH 71/73] examples: allow to select multiple devices Since there might be external USB readers and embedded ones, better to allow easily to select them all in examples. --- examples/utilities.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/examples/utilities.c b/examples/utilities.c index 70f57b25..379ad0ab 100644 --- a/examples/utilities.c +++ b/examples/utilities.c @@ -27,14 +27,40 @@ FpDevice * discover_device (GPtrArray * devices) { FpDevice *dev; + int i; if (!devices->len) return NULL; - dev = g_ptr_array_index (devices, 0); - g_print ("Found device %s (%s) claimed by %s driver\n", + if (devices->len == 1) + { + i = 0; + } + else + { + g_print ("Multiple devices found, choose one\n"); + + for (i = 0; i < devices->len; ++i) + { + dev = g_ptr_array_index (devices, i); + g_print ("[%d] %s (%s) - driver %s\n", i, + fp_device_get_device_id (dev), fp_device_get_name (dev), + fp_device_get_driver (dev)); + } + + g_print ("> "); + if (!scanf ("%d%*c", &i)) + return NULL; + + if (i < 0 || i >= devices->len) + return NULL; + } + + dev = g_ptr_array_index (devices, i); + g_print ("Selected device %s (%s) claimed by %s driver\n", fp_device_get_device_id (dev), fp_device_get_name (dev), fp_device_get_driver (dev)); + return dev; } From 7bc62821ee3e45fa5f1612938fdc3990b4a1e34c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 20 Nov 2019 18:05:46 +0100 Subject: [PATCH 72/73] ssm: Make possible to set data via function Use the same approach of GTask, making possible to set the data from a function. Givent the fact that a SSM has now a device parameter, it's generally not needed to pass an extra data value. In such case make it possible to set it and to define a destroy-notify function to handle its destruction when freeing the SSM. --- doc/libfprint-sections.txt | 3 +- libfprint/drivers/aes1610.c | 22 ++++--- libfprint/drivers/aes2501.c | 20 +++---- libfprint/drivers/aes2550.c | 21 +++---- libfprint/drivers/aesx660.c | 22 +++---- libfprint/drivers/elan.c | 35 +++++------ libfprint/drivers/etes603.c | 49 ++++++---------- libfprint/drivers/synaptics/synaptics.c | 16 ++--- libfprint/drivers/upeksonly.c | 78 ++++++++++--------------- libfprint/drivers/upektc.c | 17 +++--- libfprint/drivers/upektc_img.c | 33 +++++------ libfprint/drivers/upekts.c | 75 ++++++++++++------------ libfprint/drivers/uru4000.c | 30 +++++----- libfprint/drivers/vcom5s.c | 8 +-- libfprint/drivers/vfs0050.c | 24 +++----- libfprint/drivers/vfs101.c | 30 +++++----- libfprint/drivers/vfs301.c | 17 +++--- libfprint/drivers/vfs5011.c | 35 +++++------ libfprint/fpi-ssm.c | 56 ++++++++++++------ libfprint/fpi-ssm.h | 16 +++-- 20 files changed, 277 insertions(+), 330 deletions(-) diff --git a/doc/libfprint-sections.txt b/doc/libfprint-sections.txt index 814ab804..0abe584d 100644 --- a/doc/libfprint-sections.txt +++ b/doc/libfprint-sections.txt @@ -218,7 +218,8 @@ fpi_ssm_next_state fpi_ssm_jump_to_state fpi_ssm_mark_completed fpi_ssm_mark_failed -fpi_ssm_get_user_data +fpi_ssm_set_data +fpi_ssm_get_data fpi_ssm_get_error fpi_ssm_dup_error fpi_ssm_get_cur_state diff --git a/libfprint/drivers/aes1610.c b/libfprint/drivers/aes1610.c index 30443f7f..c9742e9c 100644 --- a/libfprint/drivers/aes1610.c +++ b/libfprint/drivers/aes1610.c @@ -648,9 +648,9 @@ capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *device, } static void -capture_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) +capture_run_state (FpiSsm *ssm, FpDevice *_dev) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (_dev); switch (fpi_ssm_get_cur_state (ssm)) @@ -690,10 +690,9 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) } static void -capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (_dev); G_DEBUG_HERE (); @@ -727,7 +726,7 @@ start_capture (FpImageDevice *dev) } ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, - CAPTURE_NUM_STATES, dev); + CAPTURE_NUM_STATES); G_DEBUG_HERE (); fpi_ssm_start (ssm, capture_sm_complete); } @@ -750,9 +749,9 @@ enum activate_states { }; static void -activate_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) +activate_run_state (FpiSsm *ssm, FpDevice *_dev) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); /* activation on aes1610 seems much more straightforward compared to aes2501 */ /* verify there's anything missing here */ @@ -767,10 +766,9 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) /* jump to finger detection */ static void -activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); fpi_image_device_activate_complete (dev, error); @@ -784,7 +782,7 @@ dev_activate (FpImageDevice *dev) { FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev); FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); + ACTIVATE_NUM_STATES); self->read_regs_retry_count = 0; fpi_ssm_start (ssm, activate_sm_complete); diff --git a/libfprint/drivers/aes2501.c b/libfprint/drivers/aes2501.c index d073bae8..fad0218e 100644 --- a/libfprint/drivers/aes2501.c +++ b/libfprint/drivers/aes2501.c @@ -505,9 +505,9 @@ capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *_dev, } static void -capture_run_state (FpiSsm *ssm, FpDevice *device, void *user_data) +capture_run_state (FpiSsm *ssm, FpDevice *device) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (device); FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (device); switch (fpi_ssm_get_cur_state (ssm)) @@ -555,10 +555,9 @@ capture_run_state (FpiSsm *ssm, FpDevice *device, void *user_data) } static void -capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (_dev); G_DEBUG_HERE (); @@ -595,7 +594,7 @@ start_capture (FpImageDevice *dev) /* Reset gain */ strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE; ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, - CAPTURE_NUM_STATES, dev); + CAPTURE_NUM_STATES); G_DEBUG_HERE (); fpi_ssm_start (ssm, capture_sm_complete); } @@ -739,9 +738,9 @@ activate_init3_cb (FpImageDevice *dev, GError *error, } static void -activate_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) +activate_run_state (FpiSsm *ssm, FpDevice *_dev) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); /* This state machine isn't as linear as it may appear. After doing init1 * and init2 register configuration writes, we have to poll a register @@ -801,8 +800,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) } static void -activate_sm_complete (FpiSsm *ssm, FpDevice *dev, - void *user_data, GError *error) +activate_sm_complete (FpiSsm *ssm, FpDevice *dev, GError *error) { fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error); @@ -816,7 +814,7 @@ dev_activate (FpImageDevice *dev) { FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev); FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); + ACTIVATE_NUM_STATES); self->read_regs_retry_count = 0; fpi_ssm_start (ssm, activate_sm_complete); diff --git a/libfprint/drivers/aes2550.c b/libfprint/drivers/aes2550.c index 80e54e87..2abcf767 100644 --- a/libfprint/drivers/aes2550.c +++ b/libfprint/drivers/aes2550.c @@ -121,7 +121,7 @@ finger_det_reqs_cb (FpiUsbTransfer *t, FpDevice *device, gpointer user_data, GError *error) { FpiUsbTransfer *transfer; - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (device); if (error) { @@ -321,7 +321,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device, } static void -capture_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +capture_run_state (FpiSsm *ssm, FpDevice *dev) { switch (fpi_ssm_get_cur_state (ssm)) { @@ -371,11 +371,10 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) } static void -capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { - FpImageDevice *dev = user_data; FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (_dev); + FpImageDevice *dev = FP_IMAGE_DEVICE (self); fp_dbg ("Capture completed"); @@ -408,8 +407,7 @@ start_capture (FpImageDevice *dev) } self->heartbeat_cnt = 0; - ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, - CAPTURE_NUM_STATES, dev); + ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, CAPTURE_NUM_STATES); G_DEBUG_HERE (); fpi_ssm_start (ssm, capture_sm_complete); } @@ -471,7 +469,7 @@ calibrate_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device, } static void -activate_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +activate_run_state (FpiSsm *ssm, FpDevice *dev) { switch (fpi_ssm_get_cur_state (ssm)) { @@ -531,10 +529,9 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) } static void -activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); fpi_image_device_activate_complete (dev, error); @@ -547,7 +544,7 @@ static void dev_activate (FpImageDevice *dev) { FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); + ACTIVATE_NUM_STATES); fpi_ssm_start (ssm, activate_sm_complete); } diff --git a/libfprint/drivers/aesx660.c b/libfprint/drivers/aesx660.c index 385b1f6a..8540a068 100644 --- a/libfprint/drivers/aesx660.c +++ b/libfprint/drivers/aesx660.c @@ -204,8 +204,7 @@ finger_det_set_idle_cmd_cb (FpiUsbTransfer *transfer, } static void -finger_det_sm_complete (FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +finger_det_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (_dev); @@ -233,7 +232,7 @@ finger_det_sm_complete (FpiSsm *ssm, FpDevice *_dev, } static void -finger_det_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +finger_det_run_state (FpiSsm *ssm, FpDevice *dev) { switch (fpi_ssm_get_cur_state (ssm)) { @@ -272,7 +271,7 @@ start_finger_detection (FpImageDevice *dev) } ssm = fpi_ssm_new (FP_DEVICE (dev), finger_det_run_state, - FINGER_DET_NUM_STATES, dev); + FINGER_DET_NUM_STATES); fpi_ssm_start (ssm, finger_det_sm_complete); } @@ -424,7 +423,7 @@ capture_read_stripe_data_cb (FpiUsbTransfer *transfer, } static void -capture_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) +capture_run_state (FpiSsm *ssm, FpDevice *_dev) { FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (_dev); FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); @@ -458,8 +457,7 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) } static void -capture_sm_complete (FpiSsm *ssm, FpDevice *device, void *user_data, - GError *error) +capture_sm_complete (FpiSsm *ssm, FpDevice *device, GError *error) { FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (device); FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); @@ -496,8 +494,7 @@ start_capture (FpImageDevice *dev) return; } - ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, - CAPTURE_NUM_STATES, dev); + ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, CAPTURE_NUM_STATES); G_DEBUG_HERE (); fpi_ssm_start (ssm, capture_sm_complete); } @@ -615,7 +612,7 @@ activate_read_init_cb (FpiUsbTransfer *transfer, FpDevice *device, } static void -activate_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) +activate_run_state (FpiSsm *ssm, FpDevice *_dev) { FpiDeviceAesX660 *self = FPI_DEVICE_AES_X660 (_dev); FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); @@ -666,8 +663,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) } static void -activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { fpi_image_device_activate_complete (FP_IMAGE_DEVICE (_dev), error); fpi_ssm_free (ssm); @@ -680,7 +676,7 @@ static void aesX660_dev_activate (FpImageDevice *dev) { FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); + ACTIVATE_NUM_STATES); fpi_ssm_start (ssm, activate_sm_complete); } diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c index 0010086f..b417a419 100644 --- a/libfprint/drivers/elan.c +++ b/libfprint/drivers/elan.c @@ -457,8 +457,7 @@ enum stop_capture_states { }; static void -stop_capture_run_state (FpiSsm *ssm, FpDevice *dev, - void *user_data) +stop_capture_run_state (FpiSsm *ssm, FpDevice *dev) { G_DEBUG_HERE (); @@ -472,10 +471,9 @@ stop_capture_run_state (FpiSsm *ssm, FpDevice *dev, } static void -stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); G_DEBUG_HERE (); @@ -510,8 +508,7 @@ elan_stop_capture (FpDevice *dev) elan_dev_reset_state (self); FpiSsm *ssm = - fpi_ssm_new (dev, stop_capture_run_state, - STOP_CAPTURE_NUM_STATES, dev); + fpi_ssm_new (dev, stop_capture_run_state, STOP_CAPTURE_NUM_STATES); fpi_ssm_start (ssm, stop_capture_complete); } @@ -524,7 +521,7 @@ enum capture_states { }; static void -capture_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +capture_run_state (FpiSsm *ssm, FpDevice *dev) { FpImageDevice *idev = FP_IMAGE_DEVICE (dev); FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); @@ -577,10 +574,9 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) } static void -capture_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceElan *self = FPI_DEVICE_ELAN (_dev); G_DEBUG_HERE (); @@ -621,8 +617,7 @@ elan_capture (FpDevice *dev) elan_dev_reset_state (self); FpiSsm *ssm = - fpi_ssm_new (dev, capture_run_state, CAPTURE_NUM_STATES, - dev); + fpi_ssm_new (dev, capture_run_state, CAPTURE_NUM_STATES); fpi_ssm_start (ssm, capture_complete); } @@ -684,7 +679,7 @@ elan_supports_calibration (FpiDeviceElan *elandev) } static void -calibrate_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +calibrate_run_state (FpiSsm *ssm, FpDevice *dev) { FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); @@ -776,8 +771,7 @@ calibrate_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) } static void -calibrate_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +calibrate_complete (FpiSsm *ssm, FpDevice *dev, GError *error) { FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); @@ -808,7 +802,7 @@ elan_calibrate (FpDevice *dev) self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS; FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), calibrate_run_state, - CALIBRATE_NUM_STATES, dev); + CALIBRATE_NUM_STATES); fpi_ssm_start (ssm, calibrate_complete); } @@ -822,7 +816,7 @@ enum activate_states { }; static void -activate_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +activate_run_state (FpiSsm *ssm, FpDevice *dev) { FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); @@ -883,8 +877,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) } static void -activate_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +activate_complete (FpiSsm *ssm, FpDevice *dev, GError *error) { FpImageDevice *idev = FP_IMAGE_DEVICE (dev); @@ -905,7 +898,7 @@ elan_activate (FpImageDevice *dev) FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); + ACTIVATE_NUM_STATES); fpi_ssm_start (ssm, activate_complete); } diff --git a/libfprint/drivers/etes603.c b/libfprint/drivers/etes603.c index 95b077f4..5c990dae 100644 --- a/libfprint/drivers/etes603.c +++ b/libfprint/drivers/etes603.c @@ -751,7 +751,7 @@ async_tx_cb (FpiUsbTransfer *transfer, FpDevice *device, } static void -m_exit_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +m_exit_state (FpiSsm *ssm, FpDevice *dev) { FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); @@ -780,8 +780,7 @@ err: } static void -m_exit_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +m_exit_complete (FpiSsm *ssm, FpDevice *dev, GError *error) { FpImageDevice *idev = FP_IMAGE_DEVICE (dev); @@ -797,8 +796,7 @@ static void m_exit_start (FpImageDevice *idev) { FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (idev); - FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), m_exit_state, - EXIT_NUM_STATES, idev); + FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), m_exit_state, EXIT_NUM_STATES); self->is_active = FALSE; fp_dbg ("Switching device to idle mode"); @@ -806,7 +804,7 @@ m_exit_start (FpImageDevice *idev) } static void -m_capture_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +m_capture_state (FpiSsm *ssm, FpDevice *dev) { FpImageDevice *idev = FP_IMAGE_DEVICE (dev); FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); @@ -895,8 +893,7 @@ err: } static void -m_capture_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +m_capture_complete (FpiSsm *ssm, FpDevice *dev, GError *error) { FpImageDevice *idev = FP_IMAGE_DEVICE (dev); FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); @@ -929,7 +926,7 @@ m_capture_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, } static void -m_finger_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +m_finger_state (FpiSsm *ssm, FpDevice *dev) { FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); @@ -1037,8 +1034,7 @@ err: } static void -m_finger_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +m_finger_complete (FpiSsm *ssm, FpDevice *dev, GError *error) { FpImageDevice *idev = FP_IMAGE_DEVICE (dev); FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); @@ -1046,8 +1042,7 @@ m_finger_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, if (!error) { FpiSsm *ssm_cap; - ssm_cap = fpi_ssm_new (dev, m_capture_state, - CAP_NUM_STATES, NULL); + ssm_cap = fpi_ssm_new (dev, m_capture_state, CAP_NUM_STATES); fpi_ssm_start (ssm_cap, m_capture_complete); } else @@ -1074,8 +1069,7 @@ m_start_fingerdetect (FpImageDevice *idev) { FpiSsm *ssmf; - ssmf = fpi_ssm_new (FP_DEVICE (idev), m_finger_state, FGR_NUM_STATES, - idev); + ssmf = fpi_ssm_new (FP_DEVICE (idev), m_finger_state, FGR_NUM_STATES); fpi_ssm_start (ssmf, m_finger_complete); } @@ -1083,7 +1077,7 @@ m_start_fingerdetect (FpImageDevice *idev) * Tune value of VRT and VRB for contrast and brightness. */ static void -m_tunevrb_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +m_tunevrb_state (FpiSsm *ssm, FpDevice *dev) { FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); float hist[5]; @@ -1256,8 +1250,7 @@ err: } static void -m_tunevrb_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +m_tunevrb_complete (FpiSsm *ssm, FpDevice *dev, GError *error) { FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); FpImageDevice *idev = FP_IMAGE_DEVICE (dev); @@ -1280,7 +1273,7 @@ m_tunevrb_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, * required. */ static void -m_tunedc_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +m_tunedc_state (FpiSsm *ssm, FpDevice *dev) { FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); @@ -1394,8 +1387,7 @@ err: } static void -m_tunedc_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +m_tunedc_complete (FpiSsm *ssm, FpDevice *dev, GError *error) { FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); FpImageDevice *idev = FP_IMAGE_DEVICE (dev); @@ -1404,7 +1396,7 @@ m_tunedc_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, { FpiSsm *ssm_tune; ssm_tune = fpi_ssm_new (FP_DEVICE (idev), m_tunevrb_state, - TUNEVRB_NUM_STATES, idev); + TUNEVRB_NUM_STATES); fpi_ssm_start (ssm_tune, m_tunevrb_complete); } else @@ -1421,7 +1413,7 @@ m_tunedc_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, } static void -m_init_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +m_init_state (FpiSsm *ssm, FpDevice *dev) { FpiDeviceEtes603 *self = FPI_DEVICE_ETES603 (dev); @@ -1534,8 +1526,7 @@ err: } static void -m_init_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +m_init_complete (FpiSsm *ssm, FpDevice *dev, GError *error) { FpImageDevice *idev = FP_IMAGE_DEVICE (dev); @@ -1543,7 +1534,7 @@ m_init_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, { FpiSsm *ssm_tune; ssm_tune = fpi_ssm_new (FP_DEVICE (idev), m_tunedc_state, - TUNEDC_NUM_STATES, idev); + TUNEDC_NUM_STATES); fpi_ssm_start (ssm_tune, m_tunedc_complete); } else @@ -1569,8 +1560,7 @@ dev_activate (FpImageDevice *idev) if (self->dcoffset == 0) { fp_dbg ("Tuning device..."); - ssm = fpi_ssm_new (FP_DEVICE (idev), m_init_state, - INIT_NUM_STATES, idev); + ssm = fpi_ssm_new (FP_DEVICE (idev), m_init_state, INIT_NUM_STATES); fpi_ssm_start (ssm, m_init_complete); } else @@ -1579,8 +1569,7 @@ dev_activate (FpImageDevice *idev) "VRB=0x%02X,GAIN=0x%02X).", self->dcoffset, self->vrt, self->vrb, self->gain); fpi_image_device_activate_complete (idev, NULL); - ssm = fpi_ssm_new (FP_DEVICE (idev), m_finger_state, - FGR_NUM_STATES, idev); + ssm = fpi_ssm_new (FP_DEVICE (idev), m_finger_state, FGR_NUM_STATES); fpi_ssm_start (ssm, m_finger_complete); } } diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index b7a0fce8..b1d73650 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -202,8 +202,7 @@ cmd_interrupt_cb (FpiUsbTransfer *transfer, static void synaptics_cmd_run_state (FpiSsm *ssm, - FpDevice *dev, - void *user_data) + FpDevice *dev) { g_autoptr(FpiUsbTransfer) transfer = NULL; FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev); @@ -235,7 +234,7 @@ synaptics_cmd_run_state (FpiSsm *ssm, 5000, NULL, cmd_recieve_cb, - user_data); + fpi_ssm_get_data (ssm)); break; @@ -271,13 +270,10 @@ synaptics_cmd_run_state (FpiSsm *ssm, } static void -cmd_ssm_done (FpiSsm *ssm, - FpDevice *dev, - void *user_data, - GError *error) +cmd_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) { FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev); - SynCmdMsgCallback callback = user_data; + SynCmdMsgCallback callback = fpi_ssm_get_data (ssm); self->cmd_ssm = NULL; @@ -399,8 +395,8 @@ synaptics_sensor_cmd (FpiDeviceSynaptics *self, self->cmd_ssm = fpi_ssm_new (FP_DEVICE (self), synaptics_cmd_run_state, - SYNAPTICS_CMD_NUM_STATES, - callback); + SYNAPTICS_CMD_NUM_STATES); + fpi_ssm_set_data (self->cmd_ssm, callback, NULL); fpi_ssm_start (self->cmd_ssm, cmd_ssm_done); } diff --git a/libfprint/drivers/upeksonly.c b/libfprint/drivers/upeksonly.c index 7d206965..76ba4e2f 100644 --- a/libfprint/drivers/upeksonly.c +++ b/libfprint/drivers/upeksonly.c @@ -808,10 +808,9 @@ enum awfsm_1000_states { }; static void -awfsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev, - void *user_data) +awfsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); switch (fpi_ssm_get_cur_state (ssm)) @@ -867,8 +866,7 @@ awfsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev, } static void -awfsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev, - void *user_data) +awfsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev) { switch (fpi_ssm_get_cur_state (ssm)) { @@ -936,10 +934,9 @@ capsm_fire_bulk (FpiSsm *ssm, } static void -capsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev, - void *user_data) +capsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); switch (fpi_ssm_get_cur_state (ssm)) @@ -975,8 +972,7 @@ capsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev, } static void -capsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev, - void *user_data) +capsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev) { FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); @@ -1005,8 +1001,7 @@ capsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev, } static void -capsm_1001_run_state (FpiSsm *ssm, FpDevice *_dev, - void *user_data) +capsm_1001_run_state (FpiSsm *ssm, FpDevice *_dev) { FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); @@ -1068,8 +1063,7 @@ enum deinitsm_1001_states { }; static void -deinitsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev, - void *user_data) +deinitsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev) { switch (fpi_ssm_get_cur_state (ssm)) { @@ -1080,8 +1074,7 @@ deinitsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev, } static void -deinitsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev, - void *user_data) +deinitsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev) { switch (fpi_ssm_get_cur_state (ssm)) { @@ -1092,8 +1085,7 @@ deinitsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev, } static void -deinitsm_1001_run_state (FpiSsm *ssm, FpDevice *_dev, - void *user_data) +deinitsm_1001_run_state (FpiSsm *ssm, FpDevice *_dev) { switch (fpi_ssm_get_cur_state (ssm)) { @@ -1131,10 +1123,9 @@ enum initsm_1001_states { }; static void -initsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev, - void *user_data) +initsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); switch (fpi_ssm_get_cur_state (ssm)) @@ -1170,8 +1161,7 @@ initsm_2016_run_state (FpiSsm *ssm, FpDevice *_dev, } static void -initsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev, - void *user_data) +initsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev) { switch (fpi_ssm_get_cur_state (ssm)) { @@ -1182,8 +1172,7 @@ initsm_1000_run_state (FpiSsm *ssm, FpDevice *_dev, } static void -initsm_1001_run_state (FpiSsm *ssm, FpDevice *_dev, - void *user_data) +initsm_1001_run_state (FpiSsm *ssm, FpDevice *_dev) { switch (fpi_ssm_get_cur_state (ssm)) { @@ -1222,9 +1211,9 @@ enum loopsm_states { }; static void -loopsm_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) +loopsm_run_state (FpiSsm *ssm, FpDevice *_dev) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); switch (fpi_ssm_get_cur_state (ssm)) @@ -1252,15 +1241,13 @@ loopsm_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) case UPEKSONLY_2016: awfsm = fpi_ssm_new (FP_DEVICE (dev), awfsm_2016_run_state, - AWFSM_2016_NUM_STATES, - dev); + AWFSM_2016_NUM_STATES); break; case UPEKSONLY_1000: awfsm = fpi_ssm_new (FP_DEVICE (dev), awfsm_1000_run_state, - AWFSM_1000_NUM_STATES, - dev); + AWFSM_1000_NUM_STATES); break; } fpi_ssm_start_subsm (ssm, awfsm); @@ -1289,19 +1276,19 @@ loopsm_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) case UPEKSONLY_2016: capsm = fpi_ssm_new (FP_DEVICE (dev), capsm_2016_run_state, - CAPSM_2016_NUM_STATES, dev); + CAPSM_2016_NUM_STATES); break; case UPEKSONLY_1000: capsm = fpi_ssm_new (FP_DEVICE (dev), capsm_1000_run_state, - CAPSM_1000_NUM_STATES, dev); + CAPSM_1000_NUM_STATES); break; case UPEKSONLY_1001: capsm = fpi_ssm_new (FP_DEVICE (dev), capsm_1001_run_state, - CAPSM_1001_NUM_STATES, dev); + CAPSM_1001_NUM_STATES); break; } fpi_ssm_start_subsm (ssm, capsm); @@ -1317,19 +1304,19 @@ loopsm_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) case UPEKSONLY_2016: deinitsm = fpi_ssm_new (FP_DEVICE (dev), deinitsm_2016_run_state, - DEINITSM_2016_NUM_STATES, dev); + DEINITSM_2016_NUM_STATES); break; case UPEKSONLY_1000: deinitsm = fpi_ssm_new (FP_DEVICE (dev), deinitsm_1000_run_state, - DEINITSM_1000_NUM_STATES, dev); + DEINITSM_1000_NUM_STATES); break; case UPEKSONLY_1001: deinitsm = fpi_ssm_new (FP_DEVICE (dev), deinitsm_1001_run_state, - DEINITSM_1001_NUM_STATES, dev); + DEINITSM_1001_NUM_STATES); break; } self->capturing = FALSE; @@ -1379,9 +1366,9 @@ dev_deactivate (FpImageDevice *dev) } static void -loopsm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, GError *error) +loopsm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); fpi_ssm_free (ssm); @@ -1400,10 +1387,9 @@ loopsm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, GError *error) } static void -initsm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +initsm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); fpi_ssm_free (ssm); @@ -1412,7 +1398,7 @@ initsm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, return; self->loopsm = fpi_ssm_new (FP_DEVICE (dev), loopsm_run_state, - LOOPSM_NUM_STATES, dev); + LOOPSM_NUM_STATES); fpi_ssm_start (self->loopsm, loopsm_complete); } @@ -1443,17 +1429,17 @@ dev_activate (FpImageDevice *dev) { case UPEKSONLY_2016: ssm = fpi_ssm_new (FP_DEVICE (dev), initsm_2016_run_state, - INITSM_2016_NUM_STATES, dev); + INITSM_2016_NUM_STATES); break; case UPEKSONLY_1000: ssm = fpi_ssm_new (FP_DEVICE (dev), initsm_1000_run_state, - INITSM_1000_NUM_STATES, dev); + INITSM_1000_NUM_STATES); break; case UPEKSONLY_1001: ssm = fpi_ssm_new (FP_DEVICE (dev), initsm_1001_run_state, - INITSM_1001_NUM_STATES, dev); + INITSM_1001_NUM_STATES); break; } fpi_ssm_start (ssm, initsm_complete); diff --git a/libfprint/drivers/upektc.c b/libfprint/drivers/upektc.c index 54bc9b2d..ff5b49ba 100644 --- a/libfprint/drivers/upektc.c +++ b/libfprint/drivers/upektc.c @@ -109,7 +109,7 @@ read_init_data_cb (FpiUsbTransfer *transfer, FpDevice *device, } static void -activate_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +activate_run_state (FpiSsm *ssm, FpDevice *dev) { FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev); @@ -149,8 +149,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) } static void -activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); @@ -294,7 +293,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device, } static void -capture_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) +capture_run_state (FpiSsm *ssm, FpDevice *_dev) { FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (_dev); @@ -333,10 +332,9 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) } static void -capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (_dev); fp_dbg ("Capture completed"); @@ -362,8 +360,7 @@ start_capture (FpImageDevice *dev) return; } - ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, - CAPTURE_NUM_STATES, dev); + ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, CAPTURE_NUM_STATES); G_DEBUG_HERE (); fpi_ssm_start (ssm, capture_sm_complete); } @@ -373,7 +370,7 @@ dev_activate (FpImageDevice *dev) { FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev); FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); + ACTIVATE_NUM_STATES); self->init_idx = 0; fpi_ssm_start (ssm, activate_sm_complete); diff --git a/libfprint/drivers/upektc_img.c b/libfprint/drivers/upektc_img.c index d3cc636a..1e06b903 100644 --- a/libfprint/drivers/upektc_img.c +++ b/libfprint/drivers/upektc_img.c @@ -338,9 +338,9 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device, } static void -capture_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) +capture_run_state (FpiSsm *ssm, FpDevice *_dev) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev); switch (fpi_ssm_get_cur_state (ssm)) @@ -382,9 +382,9 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) } static void -capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, GError *error_arg) +capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error_arg) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev); g_autoptr(GError) error = error_arg; @@ -409,7 +409,7 @@ start_capture (FpImageDevice *dev) self->image_size = 0; ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, - CAPTURE_NUM_STATES, dev); + CAPTURE_NUM_STATES); fpi_ssm_start (ssm, capture_sm_complete); } @@ -443,10 +443,9 @@ deactivate_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device, } static void -deactivate_run_state (FpiSsm *ssm, FpDevice *_dev, - void *user_data) +deactivate_run_state (FpiSsm *ssm, FpDevice *_dev) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev); switch (fpi_ssm_get_cur_state (ssm)) @@ -465,10 +464,9 @@ deactivate_run_state (FpiSsm *ssm, FpDevice *_dev, } static void -deactivate_sm_complete (FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +deactivate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev); fp_dbg ("Deactivate completed"); @@ -487,7 +485,7 @@ start_deactivation (FpImageDevice *dev) self->image_size = 0; ssm = fpi_ssm_new (FP_DEVICE (dev), deactivate_run_state, - DEACTIVATE_NUM_STATES, dev); + DEACTIVATE_NUM_STATES); fpi_ssm_start (ssm, deactivate_sm_complete); } @@ -539,10 +537,10 @@ init_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device, } static void -activate_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +activate_run_state (FpiSsm *ssm, FpDevice *dev) { FpiUsbTransfer *transfer; - FpImageDevice *idev = user_data; + FpImageDevice *idev = FP_IMAGE_DEVICE (dev); FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); switch (fpi_ssm_get_cur_state (ssm)) @@ -599,10 +597,9 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) } static void -activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); fpi_ssm_free (ssm); fpi_image_device_activate_complete (dev, error); @@ -616,7 +613,7 @@ dev_activate (FpImageDevice *dev) { FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev); FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state, - ACTIVATE_NUM_STATES, dev); + ACTIVATE_NUM_STATES); self->seq = 0; fpi_ssm_start (ssm, activate_sm_complete); diff --git a/libfprint/drivers/upekts.c b/libfprint/drivers/upekts.c index a3a0cad0..24269077 100644 --- a/libfprint/drivers/upekts.c +++ b/libfprint/drivers/upekts.c @@ -679,7 +679,7 @@ initsm_send_msg28_handler (FpiSsm *ssm, } static void -initsm_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +initsm_run_state (FpiSsm *ssm, FpDevice *dev) { FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev); FpiUsbTransfer *transfer; @@ -763,7 +763,7 @@ initsm_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) static FpiSsm * initsm_new (FpDevice *dev) { - return fpi_ssm_new (dev, initsm_run_state, INITSM_NUM_STATES, NULL); + return fpi_ssm_new (dev, initsm_run_state, INITSM_NUM_STATES); } enum deinitsm_states { @@ -806,8 +806,7 @@ read_msg01_cb (FpDevice *dev, enum read_msg_type type, } static void -deinitsm_state_handler (FpiSsm *ssm, FpDevice *dev, - void *user_data) +deinitsm_state_handler (FpiSsm *ssm, FpDevice *dev) { switch (fpi_ssm_get_cur_state (ssm)) { @@ -829,7 +828,7 @@ deinitsm_state_handler (FpiSsm *ssm, FpDevice *dev, } static void -initsm_done (FpiSsm *ssm, FpDevice *dev, void *user_data, GError *error) +initsm_done (FpiSsm *ssm, FpDevice *dev, GError *error) { if (error) g_usb_device_release_interface (fpi_device_get_usb_device (dev), 0, 0, NULL); @@ -840,7 +839,7 @@ initsm_done (FpiSsm *ssm, FpDevice *dev, void *user_data, GError *error) static FpiSsm * deinitsm_new (FpDevice *dev, void *user_data) { - return fpi_ssm_new (dev, deinitsm_state_handler, DEINITSM_NUM_STATES, user_data); + return fpi_ssm_new (dev, deinitsm_state_handler, DEINITSM_NUM_STATES); } static void @@ -858,12 +857,12 @@ dev_init (FpDevice *dev) upekdev->seq = 0xf0; /* incremented to 0x00 before first cmd */ - ssm = fpi_ssm_new (dev, initsm_run_state, INITSM_NUM_STATES, NULL); + ssm = fpi_ssm_new (dev, initsm_run_state, INITSM_NUM_STATES); fpi_ssm_start (ssm, initsm_done); } static void -deinitsm_done (FpiSsm *ssm, FpDevice *dev, void *user_data, GError *error) +deinitsm_done (FpiSsm *ssm, FpDevice *dev, GError *error) { g_usb_device_release_interface (fpi_device_get_usb_device (dev), 0, 0, NULL); @@ -875,7 +874,7 @@ dev_exit (FpDevice *dev) { FpiSsm *ssm; - ssm = fpi_ssm_new (dev, deinitsm_state_handler, DEINITSM_NUM_STATES, NULL); + ssm = fpi_ssm_new (dev, deinitsm_state_handler, DEINITSM_NUM_STATES); fpi_ssm_start (ssm, deinitsm_done); } @@ -936,8 +935,7 @@ enroll_start_sm_cb_msg28 (FpDevice *dev, } static void -enroll_start_sm_run_state (FpiSsm *ssm, FpDevice *dev, - void *user_data) +enroll_start_sm_run_state (FpiSsm *ssm, FpDevice *dev) { switch (fpi_ssm_get_cur_state (ssm)) { @@ -973,20 +971,23 @@ typedef struct } EnrollStopData; static void -enroll_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, - void *user_data, GError *error) +enroll_stop_data_free (EnrollStopData *data) { - EnrollStopData *data = user_data; + g_clear_object (&data->print); + g_clear_error (&data->error); + g_free (data); +} + +static void +enroll_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, GError *error) +{ + EnrollStopData *data = fpi_ssm_get_data (ssm); /* don't really care about errors */ if (error) - { - fp_warn ("Error deinitializing: %s", error->message); - g_error_free (error); - } + fp_warn ("Error deinitializing: %s", error->message); fpi_device_enroll_complete (dev, data->print, data->error); - g_free (data); fpi_ssm_free (ssm); } @@ -996,10 +997,11 @@ do_enroll_stop (FpDevice *dev, FpPrint *print, GError *error) EnrollStopData *data = g_new0 (EnrollStopData, 1); FpiSsm *ssm = deinitsm_new (dev, data); - data->print = print; + data->print = g_object_ref (print); data->error = error; fpi_ssm_start (ssm, enroll_stop_deinit_cb); + fpi_ssm_set_data (ssm, data, (GDestroyNotify) enroll_stop_data_free); } static void enroll_iterate (FpDevice *dev); @@ -1206,8 +1208,7 @@ enroll_iterate (FpDevice *dev) } static void -enroll_started (FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +enroll_started (FpiSsm *ssm, FpDevice *dev, GError *error) { if (error) do_enroll_stop (dev, NULL, error); @@ -1224,7 +1225,7 @@ enroll (FpDevice *dev) /* do_init state machine first */ FpiSsm *ssm = fpi_ssm_new (dev, enroll_start_sm_run_state, - ENROLL_START_NUM_STATES, NULL); + ENROLL_START_NUM_STATES); upekdev->enroll_passed = FALSE; upekdev->enroll_stage = 0; @@ -1238,19 +1239,21 @@ typedef struct } VerifyStopData; static void -verify_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, - void *user_data, GError *error) +verify_stop_data_free (VerifyStopData *data) { - VerifyStopData *data = user_data; + g_clear_error (&data->error); + g_free (data); +} + +static void +verify_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, GError *error) +{ + VerifyStopData *data = fpi_ssm_get_data (ssm); if (error) - { - fp_warn ("Error deinitializing: %s", error->message); - g_error_free (error); - } + fp_warn ("Error deinitializing: %s", error->message); fpi_device_verify_complete (dev, data->res, NULL, data->error); - g_free (data); fpi_ssm_free (ssm); } @@ -1264,6 +1267,7 @@ do_verify_stop (FpDevice *dev, FpiMatchResult res, GError *error) data->error = error; fpi_ssm_start (ssm, verify_stop_deinit_cb); + fpi_ssm_set_data (ssm, data, (GDestroyNotify) verify_stop_data_free); } static const unsigned char verify_hdr[] = { @@ -1279,8 +1283,7 @@ enum { }; static void -verify_start_sm_run_state (FpiSsm *ssm, FpDevice *dev, - void *user_data) +verify_start_sm_run_state (FpiSsm *ssm, FpDevice *dev) { FpPrint *print; @@ -1522,8 +1525,7 @@ verify_iterate (FpDevice *dev) } static void -verify_started (FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +verify_started (FpiSsm *ssm, FpDevice *dev, GError *error) { FpiDeviceUpekts *upekdev = FPI_DEVICE_UPEKTS (dev); @@ -1542,8 +1544,7 @@ verify_started (FpiSsm *ssm, FpDevice *dev, void *user_data, static void verify (FpDevice *dev) { - FpiSsm *ssm = fpi_ssm_new (dev, verify_start_sm_run_state, - VERIFY_NUM_STATES, NULL); + FpiSsm *ssm = fpi_ssm_new (dev, verify_start_sm_run_state, VERIFY_NUM_STATES); fpi_ssm_start (ssm, verify_started); } diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c index 599f5a3c..f2484119 100644 --- a/libfprint/drivers/uru4000.c +++ b/libfprint/drivers/uru4000.c @@ -650,9 +650,9 @@ calc_dev2 (struct uru4k_image *img) } static void -imaging_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) +imaging_run_state (FpiSsm *ssm, FpDevice *_dev) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (_dev); struct uru4k_image *img = self->img_data; FpImage *fpimg; @@ -785,8 +785,7 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) } static void -imaging_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +imaging_complete (FpiSsm *ssm, FpDevice *dev, GError *error) { FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev); @@ -855,9 +854,9 @@ rebootpwr_pause_cb (FpDevice *dev, } static void -rebootpwr_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) +rebootpwr_run_state (FpiSsm *ssm, FpDevice *_dev) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (_dev); switch (fpi_ssm_get_cur_state (ssm)) @@ -946,9 +945,9 @@ powerup_pause_cb (FpDevice *dev, } static void -powerup_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) +powerup_run_state (FpiSsm *ssm, FpDevice *_dev) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (_dev); switch (fpi_ssm_get_cur_state (ssm)) @@ -1073,9 +1072,9 @@ init_scanpwr_timeout (FpDevice *dev, } static void -init_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) +init_run_state (FpiSsm *ssm, FpDevice *_dev) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (_dev); switch (fpi_ssm_get_cur_state (ssm)) @@ -1095,7 +1094,7 @@ init_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) case INIT_REBOOT_POWER:; FpiSsm *rebootsm = fpi_ssm_new (FP_DEVICE (dev), rebootpwr_run_state, - REBOOTPWR_NUM_STATES, dev); + REBOOTPWR_NUM_STATES); fpi_ssm_start_subsm (ssm, rebootsm); break; @@ -1118,7 +1117,7 @@ init_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) FpiSsm *powerupsm = fpi_ssm_new (FP_DEVICE (dev), powerup_run_state, - POWERUP_NUM_STATES, dev); + POWERUP_NUM_STATES); fpi_ssm_start_subsm (ssm, powerupsm); break; @@ -1165,8 +1164,7 @@ init_run_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) } static void -activate_initsm_complete (FpiSsm *ssm, FpDevice *dev, - void *user_data, GError *error) +activate_initsm_complete (FpiSsm *ssm, FpDevice *dev, GError *error) { fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error); } @@ -1180,7 +1178,7 @@ dev_activate (FpImageDevice *dev) start_irq_handler (dev); self->scanpwr_irq_timeouts = 0; - ssm = fpi_ssm_new (FP_DEVICE (dev), init_run_state, INIT_NUM_STATES, NULL); + ssm = fpi_ssm_new (FP_DEVICE (dev), init_run_state, INIT_NUM_STATES); fpi_ssm_start (ssm, activate_initsm_complete); } @@ -1240,7 +1238,7 @@ execute_state_change (FpImageDevice *dev) self->irq_cb = NULL; ssm = fpi_ssm_new (FP_DEVICE (dev), imaging_run_state, - IMAGING_NUM_STATES, dev); + IMAGING_NUM_STATES); self->img_enc_seed = rand (); self->img_transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); self->img_transfer->ssm = ssm; diff --git a/libfprint/drivers/vcom5s.c b/libfprint/drivers/vcom5s.c index 74e7bdbe..0e102528 100644 --- a/libfprint/drivers/vcom5s.c +++ b/libfprint/drivers/vcom5s.c @@ -256,7 +256,7 @@ enum loop_states { }; static void -loop_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) +loop_run_state (FpiSsm *ssm, FpDevice *dev) { FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev); @@ -296,8 +296,7 @@ loop_run_state (FpiSsm *ssm, FpDevice *dev, void *user_data) } static void -loopsm_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +loopsm_complete (FpiSsm *ssm, FpDevice *dev, GError *error) { FpImageDevice *imgdev = FP_IMAGE_DEVICE (dev); FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev); @@ -320,8 +319,7 @@ static void dev_activate (FpImageDevice *dev) { FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev); - FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), loop_run_state, - LOOP_NUM_STATES, dev); + FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), loop_run_state, LOOP_NUM_STATES); self->deactivating = FALSE; fpi_ssm_start (ssm, loopsm_complete); diff --git a/libfprint/drivers/vfs0050.c b/libfprint/drivers/vfs0050.c index 399be86c..4dc67827 100644 --- a/libfprint/drivers/vfs0050.c +++ b/libfprint/drivers/vfs0050.c @@ -278,7 +278,7 @@ submit_image (FpDeviceVfs0050 *self) /* SSM loop for clear_ep2 */ static void -clear_ep2_ssm (FpiSsm *ssm, FpDevice *dev, void *user_data) +clear_ep2_ssm (FpiSsm *ssm, FpDevice *dev) { char command04 = 0x04; @@ -307,15 +307,13 @@ static void clear_ep2 (FpDevice *dev, FpiSsm *ssm) { - FpiSsm *subsm = - fpi_ssm_new (dev, clear_ep2_ssm, SUBSM1_STATES, NULL); + FpiSsm *subsm = fpi_ssm_new (dev, clear_ep2_ssm, SUBSM1_STATES); fpi_ssm_start_subsm (ssm, subsm); } static void -send_control_packet_ssm (FpiSsm *ssm, FpDevice *dev, - void *user_data) +send_control_packet_ssm (FpiSsm *ssm, FpDevice *dev) { FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (dev); @@ -384,8 +382,7 @@ send_control_packet (FpiSsm *ssm, FpDevice *dev) { FpiSsm *subsm = - fpi_ssm_new (dev, send_control_packet_ssm, - SUBSM2_STATES, NULL); + fpi_ssm_new (dev, send_control_packet_ssm, SUBSM2_STATES); fpi_ssm_start_subsm (ssm, subsm); } @@ -497,7 +494,7 @@ another_scan (FpDevice *dev, /* Main SSM loop */ static void -activate_ssm (FpiSsm *ssm, FpDevice *dev, void *user_data) +activate_ssm (FpiSsm *ssm, FpDevice *dev) { FpImageDevice *idev = FP_IMAGE_DEVICE (dev); FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (dev); @@ -660,8 +657,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev, void *user_data) /* Callback for dev_activate ssm */ static void -dev_activate_callback (FpiSsm *ssm, FpDevice *dev, - void *user_data, GError *error) +dev_activate_callback (FpiSsm *ssm, FpDevice *dev, GError *error) { FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (dev); @@ -687,8 +683,7 @@ dev_activate (FpImageDevice *idev) self->need_report = 1; self->ssm_active = 1; - FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES, - idev); + FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES); fpi_ssm_start (ssm, dev_activate_callback); } @@ -711,8 +706,7 @@ dev_deactivate (FpImageDevice *idev) /* Callback for dev_open ssm */ static void -dev_open_callback (FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +dev_open_callback (FpiSsm *ssm, FpDevice *dev, GError *error) { /* Notify open complete */ fpi_image_device_open_complete (FP_IMAGE_DEVICE (dev), error); @@ -733,7 +727,7 @@ dev_open (FpImageDevice *idev) } /* Clearing previous device state */ - FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES, NULL); + FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES); fpi_ssm_start (ssm, dev_open_callback); } diff --git a/libfprint/drivers/vfs101.c b/libfprint/drivers/vfs101.c index 6abf265e..37e083c7 100644 --- a/libfprint/drivers/vfs101.c +++ b/libfprint/drivers/vfs101.c @@ -391,18 +391,18 @@ enum { /* Exec swap sequential state machine */ static void -m_swap_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) +m_swap_state (FpiSsm *ssm, FpDevice *dev) { switch (fpi_ssm_get_cur_state (ssm)) { case M_SWAP_SEND: /* Send data */ - async_send (ssm, user_data); + async_send (ssm, FP_IMAGE_DEVICE (dev)); break; case M_SWAP_RECV: /* Recv response */ - async_recv (ssm, user_data); + async_recv (ssm, FP_IMAGE_DEVICE (dev)); break; } } @@ -423,8 +423,7 @@ m_swap (FpiSsm *ssm, self->length = length; /* Start swap ssm */ - subsm = fpi_ssm_new (FP_DEVICE (dev), m_swap_state, M_SWAP_NUM_STATES, - dev); + subsm = fpi_ssm_new (FP_DEVICE (dev), m_swap_state, M_SWAP_NUM_STATES); fpi_ssm_start_subsm (ssm, subsm); } @@ -778,9 +777,9 @@ enum { /* Exec loop sequential state machine */ static void -m_loop_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) +m_loop_state (FpiSsm *ssm, FpDevice *_dev) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (_dev); /* Complete if deactivation was requested */ @@ -950,8 +949,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) /* Complete loop sequential state machine */ static void -m_loop_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +m_loop_complete (FpiSsm *ssm, FpDevice *dev, GError *error) { FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev); @@ -1015,9 +1013,9 @@ enum { /* Exec init sequential state machine */ static void -m_init_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) +m_init_state (FpiSsm *ssm, FpDevice *_dev) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (_dev); /* Mark as cancelled when activation collides with deactivation. */ @@ -1253,10 +1251,9 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) /* Complete init sequential state machine */ static void -m_init_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +m_init_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); /* Notify activate complete */ fpi_image_device_activate_complete (dev, error); @@ -1266,8 +1263,7 @@ m_init_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, FpiSsm *ssm_loop; /* Start loop ssm */ - ssm_loop = fpi_ssm_new (FP_DEVICE (dev), m_loop_state, - M_LOOP_NUM_STATES, dev); + ssm_loop = fpi_ssm_new (FP_DEVICE (dev), m_loop_state, M_LOOP_NUM_STATES); fpi_ssm_start (ssm_loop, m_loop_complete); } @@ -1297,7 +1293,7 @@ dev_activate (FpImageDevice *dev) self->counter = 0; /* Start init ssm */ - ssm = fpi_ssm_new (FP_DEVICE (dev), m_init_state, M_INIT_NUM_STATES, dev); + ssm = fpi_ssm_new (FP_DEVICE (dev), m_init_state, M_INIT_NUM_STATES); fpi_ssm_start (ssm, m_init_complete); } diff --git a/libfprint/drivers/vfs301.c b/libfprint/drivers/vfs301.c index 4d3dc30b..8fdac7c7 100644 --- a/libfprint/drivers/vfs301.c +++ b/libfprint/drivers/vfs301.c @@ -94,9 +94,9 @@ enum { /* Exec loop sequential state machine */ static void -m_loop_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) +m_loop_state (FpiSsm *ssm, FpDevice *_dev) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (_dev); switch (fpi_ssm_get_cur_state (ssm)) @@ -160,8 +160,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) /* Complete loop sequential state machine */ static void -m_loop_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +m_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { if (error) { @@ -174,7 +173,7 @@ m_loop_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, /* Exec init sequential state machine */ static void -m_init_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) +m_init_state (FpiSsm *ssm, FpDevice *_dev) { FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (_dev); @@ -187,8 +186,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev, void *user_data) /* Complete init sequential state machine */ static void -m_init_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, - GError *error) +m_init_complete (FpiSsm *ssm, FpDevice *dev, GError *error) { FpiSsm *ssm_loop; @@ -198,8 +196,7 @@ m_init_complete (FpiSsm *ssm, FpDevice *dev, void *user_data, /* Notify activate complete */ /* Start loop ssm */ - ssm_loop = fpi_ssm_new (dev, m_loop_state, - M_LOOP_NUM_STATES, dev); + ssm_loop = fpi_ssm_new (dev, m_loop_state, M_LOOP_NUM_STATES); fpi_ssm_start (ssm_loop, m_loop_complete); } @@ -214,7 +211,7 @@ dev_activate (FpImageDevice *dev) FpiSsm *ssm; /* Start init ssm */ - ssm = fpi_ssm_new (FP_DEVICE (dev), m_init_state, 1, dev); + ssm = fpi_ssm_new (FP_DEVICE (dev), m_init_state, 1); fpi_ssm_start (ssm, m_init_complete); } diff --git a/libfprint/drivers/vfs5011.c b/libfprint/drivers/vfs5011.c index 0bcf8549..9eddca79 100644 --- a/libfprint/drivers/vfs5011.c +++ b/libfprint/drivers/vfs5011.c @@ -81,7 +81,7 @@ static void async_send_cb (FpiUsbTransfer *transfer, FpDevice *device, gpointer user_data, GError *error) { - struct usbexchange_data *data = fpi_ssm_get_user_data (transfer->ssm); + struct usbexchange_data *data = fpi_ssm_get_data (transfer->ssm); struct usb_action *action; g_assert (!(fpi_ssm_get_cur_state (transfer->ssm) >= data->stepcount)); @@ -104,7 +104,7 @@ static void async_recv_cb (FpiUsbTransfer *transfer, FpDevice *device, gpointer user_data, GError *error) { - struct usbexchange_data *data = fpi_ssm_get_user_data (transfer->ssm); + struct usbexchange_data *data = fpi_ssm_get_data (transfer->ssm); struct usb_action *action; if (error) @@ -148,9 +148,9 @@ async_recv_cb (FpiUsbTransfer *transfer, FpDevice *device, } static void -usbexchange_loop (FpiSsm *ssm, FpDevice *_dev, void *user_data) +usbexchange_loop (FpiSsm *ssm, FpDevice *_dev) { - struct usbexchange_data *data = user_data; + struct usbexchange_data *data = fpi_ssm_get_data (ssm); struct usb_action *action = &data->actions[fpi_ssm_get_cur_state (ssm)]; FpiUsbTransfer *transfer; @@ -196,9 +196,9 @@ usb_exchange_async (FpiSsm *ssm, { FpiSsm *subsm = fpi_ssm_new (FP_DEVICE (data->device), usbexchange_loop, - data->stepcount, - data); + data->stepcount); + fpi_ssm_set_data (subsm, data, NULL); fpi_ssm_start_subsm (ssm, subsm); } @@ -658,11 +658,11 @@ struct usb_action vfs5011_initiate_capture[] = { /* ====================== lifprint interface ======================= */ static void -activate_loop (FpiSsm *ssm, FpDevice *_dev, void *user_data) +activate_loop (FpiSsm *ssm, FpDevice *_dev) { enum {READ_TIMEOUT = 0}; - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpDeviceVfs5011 *self; self = FPI_DEVICE_VFS5011 (_dev); @@ -729,10 +729,9 @@ activate_loop (FpiSsm *ssm, FpDevice *_dev, void *user_data) } static void -activate_loop_complete (FpiSsm *ssm, FpDevice *_dev, - void *user_data, GError *error) +activate_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpDeviceVfs5011 *self; self = FPI_DEVICE_VFS5011 (_dev); @@ -760,9 +759,9 @@ activate_loop_complete (FpiSsm *ssm, FpDevice *_dev, static void -open_loop (FpiSsm *ssm, FpDevice *_dev, void *user_data) +open_loop (FpiSsm *ssm, FpDevice *_dev) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpDeviceVfs5011 *self; self = FPI_DEVICE_VFS5011 (_dev); @@ -784,10 +783,9 @@ open_loop (FpiSsm *ssm, FpDevice *_dev, void *user_data) } static void -open_loop_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, - GError *error) +open_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { - FpImageDevice *dev = user_data; + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); FpDeviceVfs5011 *self; self = FPI_DEVICE_VFS5011 (_dev); @@ -814,7 +812,7 @@ dev_open (FpImageDevice *dev) return; } - ssm = fpi_ssm_new (FP_DEVICE (dev), open_loop, DEV_OPEN_NUM_STATES, dev); + ssm = fpi_ssm_new (FP_DEVICE (dev), open_loop, DEV_OPEN_NUM_STATES); fpi_ssm_start (ssm, open_loop_complete); } @@ -844,8 +842,7 @@ start_scan (FpImageDevice *dev) self = FPI_DEVICE_VFS5011 (dev); self->loop_running = TRUE; fp_dbg ("creating ssm"); - ssm = fpi_ssm_new (FP_DEVICE (dev), activate_loop, - DEV_ACTIVATE_NUM_STATES, dev); + ssm = fpi_ssm_new (FP_DEVICE (dev), activate_loop, DEV_ACTIVATE_NUM_STATES); fp_dbg ("starting ssm"); fpi_ssm_start (ssm, activate_loop_complete); fp_dbg ("ssm done, getting out"); diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c index c9da3c8d..6b63e1a1 100644 --- a/libfprint/fpi-ssm.c +++ b/libfprint/fpi-ssm.c @@ -45,7 +45,7 @@ * implicit edges linking one state to every other state. * * To create an #fpi_ssm, you pass a state handler function and the total number of - * states (4 in the above example) to fpi_ssm_new(). Note that the state numbers + * states (4 in the above example) to fpi_ssm_new (). Note that the state numbers * start at zero, making them match the first value in a C enumeration. * * To start a ssm, you pass in a completion callback function to fpi_ssm_start() @@ -79,7 +79,8 @@ struct _FpiSsm { FpDevice *dev; FpiSsm *parentsm; - void *user_data; + gpointer ssm_data; + GDestroyNotify ssm_data_destroy; int nr_states; int cur_state; gboolean completed; @@ -93,7 +94,6 @@ struct _FpiSsm * @dev: a #fp_dev fingerprint device * @handler: the callback function * @nr_states: the number of states - * @user_data: the user data to pass to callbacks * * Allocate a new ssm, with @nr_states states. The @handler callback * will be called after each state transition. @@ -103,8 +103,7 @@ struct _FpiSsm FpiSsm * fpi_ssm_new (FpDevice *dev, FpiSsmHandlerCallback handler, - int nr_states, - void *user_data) + int nr_states) { FpiSsm *machine; @@ -115,23 +114,42 @@ fpi_ssm_new (FpDevice *dev, machine->nr_states = nr_states; machine->dev = dev; machine->completed = TRUE; - machine->user_data = user_data; return machine; } /** - * fpi_ssm_get_user_data: + * fpi_ssm_set_data: + * @machine: an #FpiSsm state machine + * @ssm_data: (nullable): a pointer to machine data + * @ssm_data_destroy: (nullable): #GDestroyNotify for @ssm_data + * + * Sets @machine's data (freeing the existing data, if any). + * + */ +void +fpi_ssm_set_data (FpiSsm *machine, + gpointer ssm_data, + GDestroyNotify ssm_data_destroy) +{ + if (machine->ssm_data_destroy && machine->ssm_data) + machine->ssm_data_destroy (machine->ssm_data); + + machine->ssm_data = ssm_data; + machine->ssm_data_destroy = ssm_data_destroy; +} + +/** + * fpi_ssm_get_data: * @machine: an #FpiSsm state machine * - * Retrieve the pointer to user data set when fpi_ssm_new() - * is called. + * Retrieve the pointer to SSM data set with fpi_ssm_set_ssm_data() * * Returns: a pointer */ void * -fpi_ssm_get_user_data (FpiSsm *machine) +fpi_ssm_get_data (FpiSsm *machine) { - return machine->user_data; + return machine->ssm_data; } /** @@ -147,6 +165,8 @@ fpi_ssm_free (FpiSsm *machine) if (!machine) return; + if (machine->ssm_data_destroy) + g_clear_pointer (&machine->ssm_data, machine->ssm_data_destroy); g_clear_pointer (&machine->error, g_error_free); g_free (machine); } @@ -156,7 +176,7 @@ static void __ssm_call_handler (FpiSsm *machine) { fp_dbg ("%p entering state %d", machine, machine->cur_state); - machine->handler (machine, machine->dev, machine->user_data); + machine->handler (machine, machine->dev); } /** @@ -180,7 +200,7 @@ fpi_ssm_start (FpiSsm *ssm, FpiSsmCompletedCallback callback) } static void -__subsm_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data, GError *error) +__subsm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { FpiSsm *parent = ssm->parentsm; @@ -215,7 +235,7 @@ fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child) * @machine: an #FpiSsm state machine * * Mark a ssm as completed successfully. The callback set when creating - * the state machine with fpi_ssm_new() will be called synchronously. + * the state machine with fpi_ssm_new () will be called synchronously. */ void fpi_ssm_mark_completed (FpiSsm *machine) @@ -230,7 +250,7 @@ fpi_ssm_mark_completed (FpiSsm *machine) { GError *error = machine->error ? g_error_copy (machine->error) : NULL; - machine->callback (machine, machine->dev, machine->user_data, error); + machine->callback (machine, machine->dev, error); } } @@ -349,7 +369,7 @@ fpi_ssm_dup_error (FpiSsm *machine) * for an fpi_timeout_add() callback, when the state change needs * to happen after a timeout. * - * Make sure to pass the #FpiSsm as the `user_data` argument + * Make sure to pass the #FpiSsm as the `ssm_data` argument * for that fpi_timeout_add() call. */ void @@ -366,7 +386,7 @@ fpi_ssm_next_state_timeout_cb (FpDevice *dev, * fpi_ssm_usb_transfer_cb: * @transfer: a #FpiUsbTransfer * @device: a #FpDevice - * @user_data: User data (unused) + * @ssm_data: User data (unused) * @error: The #GError or %NULL * * Can be used in as a #FpiUsbTransfer callback handler to automatically @@ -376,7 +396,7 @@ fpi_ssm_next_state_timeout_cb (FpDevice *dev, */ void fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer, FpDevice *device, - gpointer user_data, GError *error) + gpointer ssm_data, GError *error) { g_return_if_fail (transfer->ssm); diff --git a/libfprint/fpi-ssm.h b/libfprint/fpi-ssm.h index 560452cb..31a33e56 100644 --- a/libfprint/fpi-ssm.h +++ b/libfprint/fpi-ssm.h @@ -38,7 +38,6 @@ typedef struct _FpiSsm FpiSsm; * FpiSsmCompletedCallback: * @ssm: a #FpiSsm state machine * @dev: the #fp_dev fingerprint device - * @user_data: the user data passed to fpi_ssm_new() * @error: The #GError or %NULL on successful completion * * The callback called when a state machine completes successfully, @@ -46,27 +45,23 @@ typedef struct _FpiSsm FpiSsm; */ typedef void (*FpiSsmCompletedCallback)(FpiSsm *ssm, FpDevice *dev, - void *user_data, GError *error); /** * FpiSsmHandlerCallback: * @ssm: a #FpiSsm state machine * @dev: the #fp_dev fingerprint device - * @user_data: the user data passed to fpi_ssm_new() * * The callback called when a state machine transitions from one - * state to the next, as set when calling fpi_ssm_new(). + * state to the next, as set when calling fpi_ssm_new (). */ typedef void (*FpiSsmHandlerCallback)(FpiSsm *ssm, - FpDevice *dev, - void *user_data); + FpDevice *dev); /* for library and drivers */ FpiSsm *fpi_ssm_new (FpDevice *dev, FpiSsmHandlerCallback handler, - int nr_states, - void *user_data); + int nr_states); void fpi_ssm_free (FpiSsm *machine); void fpi_ssm_start (FpiSsm *ssm, FpiSsmCompletedCallback callback); @@ -80,7 +75,10 @@ void fpi_ssm_jump_to_state (FpiSsm *machine, void fpi_ssm_mark_completed (FpiSsm *machine); void fpi_ssm_mark_failed (FpiSsm *machine, GError *error); -void *fpi_ssm_get_user_data (FpiSsm *machine); +void fpi_ssm_set_data (FpiSsm *machine, + gpointer ssm_data, + GDestroyNotify ssm_data_destroy); +gpointer fpi_ssm_get_data (FpiSsm *machine); GError * fpi_ssm_get_error (FpiSsm *machine); GError * fpi_ssm_dup_error (FpiSsm *machine); int fpi_ssm_get_cur_state (FpiSsm *machine); From 81a446db82abf2264ad22ded6719f9c391b912a4 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 20 Nov 2019 14:05:45 +0100 Subject: [PATCH 73/73] Update NEWS for 1.90.0 release --- NEWS | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/NEWS b/NEWS index ba0ccc3d..f3fa3547 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,27 @@ This file lists notable changes in each release. For the full history of all changes, see ChangeLog. +2019-11-20: v1.90.0 release + +This release updates the core of the library to use GLib routines and Gio +style APIs. While the API both for library users remain similar in most +ways, there are some changes and all users will need to be ported. + +A large motivation for the in-depth changes was the requirement to add +new API to support sensors that store the prints on the sensor. This +support is already used by the new synaptics driver, which will support +the current generation of the Prometheus MIS (match-in-sensor) chipset +by Synaptics (USB ID 06cb:00bd). + +The current codebase is considered stable at this point. However, due to +the lack of wider testing it is only released as a 1.90.0 release which +can be considered a beta-release for 2.0. + +With the rewrite, it is now also possible to support devices that are not +connected through USB (e.g. I2C). Another major improvement is that the +library has now a test suite, testing both the library core and allowing +tests of the drivers using umockdev. + 2019-08-08: v1.0 release * Library: - Add guards to the public API and require GLib 2.50

i`~wNb7Fo9Cj@ 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 eEDHpW)Bg+M2xls_(i-Ui0000 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�w!)jfSOyqUV*;bn)cm9my$3Q-%A{u+g`a8p~Lo3*m zm-CuCzzQdR3QhzFYVpR4VC~*-H!v;m2E=~=PK_Y>715KMbA7(~zPA<=Rn5gX4l->( z2}kt-VZ**)nH*qEK*wi@u!1Cyp9HW2W^vf9A$x#Ez|H|N;ic!N>@IMp!m3n-eb;$awQinees zNeU156H~OJ4gj?x9EA15PsV-rXknM*{P4@WU~3`{oEL+>fZC_##{Al7w{=Gq^B4{18?Hs z@rtDw$L3%+$cDwO7~hEcV|DWfHpEI`i1DZ!JJEzL2qat|oBbIqL#gTqzvG4Wn)qs{ zNiw96I>_+G&++~M;ELBowRQDXBR1}O304N^6~BVUA$5CIpwo(&1W1v4_l?gO;XOdY zx8fkI__&jns9da)72+_ z6z$xAWh`WlKq`=C3DrE;`$k@@y@;Hlt3!A3A~-87p~3WmUZYUR7lapgw+wcpaF+qW zhP3Au4Dp~I-!#HwXwBLyF!TlAfS(>>+UD!am0>V5xxqhi&OvsD~4}5fKnL zmi(29L}?Ppy7F`l3Oa_Mu8BR;eO+cA+Ofr0eM}s14*L%JdW=v(T=QHk4r*!=3+|8V zLIvT-7^q+%hn>3Ld?6wM*U;eZ0gS=91kB&!I|0q;GR7+*nW(Pm=!H%g0${BbEWyVc z8E1*#btm`@AnsizDAUC1X7f8RvWJ7yWwI*F0eS|i?T9Kg72}P|z-dD>H@Y~#3the6 zcRkDCzjOs+EK7g~fWuM>b;yLEv}`<(*oc&ldf^^fpOIc@`IoMnQ+#+rmQf#&Ibl+O zb^IgPZ4`(C$Q|gJ#jhx`@V}tsY&=R`u>aXQ z9FA8pTKyzGRGX*s&cLvM_+AE|X2&`vDZ>l5Ye`T&1!cGnR2qk5P_`yf<{0doF8v*l zj|U$MbOZKWJ+b>ey3`xb2job+I$+>qEwC8#EyBQRNDHTtMup+P5#m!zoUa8D!p!S4 zHUx`!2girpNR**-=o}ARa6&)=t`G!^-871pV61`DM{oLV21~-ogD_`+@OG>|uo;e= zO*&wgjQUG<@PVI)V0fLEd2kG1DIjyh?*mbUpz!_?N;P!gw}Xwx0#PQ@t=KyS$RVP?BhpLTth4@}T3AOJ6p@4?>QgVk`)TJ~4ARRX`v*A5k2&paqP;ZQufchxwBVVv9FMs>c0X zNruYqd+G@L@cqRzIYeN+%RU}akPM_G)%j#C5%W0S1ud?egfBkg+xnXSr94s+^(y_lEwyj za}1B-dZu+)T4WKnQRL5F#WaL#*YKkKFk9aiW&(yZkU7$dc4v zxHYN);sTJ3_Xg!kKO!*qG2wzug*!A+Vu+u)TTTe813bCduO60BNwnN(s~7{LH85$i zG_W#)mjRbA+uj2J%gUe_IH7f$skxQgX&?$~li)`p8Dt&4-lcEw>4+7>B;{hL(Rvx) zyH0IBzKwQcJ0P~a=q-Na_Xxqk7(bM$ zDnqRAEA3j8J#00iq+0}Fb>V1y!$g#zp1$W3;6;$M1iVYQh}jn&_E!l<`}bT2<6vz~7A`|~V5t_tq6+zj${+1-X@YYg|Hl%352rT+rdri7 zlg@%r3=K9uxxyOI(~X6l0q?`+a)kKdez7mWGj~AN*g}9embQ5qdxJ53%4;x&W83%w zcCf~EP{?P{1ij_W;Ewk-uu!1LWddnHInerLZ23Egrd78B6)On*X9}5vkp{n5HiTxv zR5J>Y@%?ZQ<1B{u(9J!~wdChfL_x_ChcNL>Fwp6Il<$ONVarx*S`e8;sW{v4|b zurgv^l(P82TAT4f{3L(^!vIRD{5bv!lE~VigMO=!~V4zcPN|S za>+>!=6@kmn6L_k=)agk)o)c?GtLvLH2Q}}N!W{QYWP5bc8&~NzN8iKmSvewSzz!R zpalx9-ON`0rZIYyls60!I}Xu;CQd_IWvaT#$R4~uZ;nhPh2M+dFA&Iea%+<{L@N?* zSRE=l4a^klB&K@_@qzUm2q)-gr!s_F@@H+*ZR*)*4H*8!Gj8`C{|BN6dVoyu)G#VO zqer8Xm{fT1eoeXOC?N5Ia6DZ-x=BCiaZ{sZiIOsln z2b+CdiZ~je(Lf{o27Awku@u-fz-nQJ5~k$mvRE$c8_sGd(J&!?W36bl&u4-%7}|i! zg@eKN*Lf|I9@*s4lZ?Tzwc!74hWh2W?)d^AK^Dk5dsOOe9p$>^PRk@bK=Qls4u%go zD7Gu`u!YHtH%HDHBXe-y9k6p)B~u(VU0`yMpx9TTNA}xuFHl}IFBgo*BhZi9ZWRP} zEEb$77Qv+6V+khG#UkKqEwN4A0P|huXN2w+P!G%Ip2JSSJJLD490-gf{|vS8gJ!bv zYi9QH)vYC+n8*ZKxD9}ScU2eO1knIynkgAIo27)W;io^;E5Aj9{vfgC;J}NA0&gp- zQ!q*Th5}VFlOfKm5YtyofkS{5L7~sX_#52F7Qrt-^8ztlPv^%>j6Vok=y66ggzZe4 z1=JCdGL#OTesJr#4{SljD%O@TyoPb*oU2^yq}&A^GEh3DU>RvL8NUrJ+_99w`{Ly| zA5Iw08M0gxy8~<}P%@nSx{3tK$RSeP47T@npI9_*aOY&UamQ6=l@DWWR~3L_f|}($ zR*XF89GuqRN0S!Oho*Z(Eb%7rU(BB+3tNGBozzc0lT>%U73a~Cpi`7(_ z`7F#*jfUw}1_ZD$|&_6t1v+%6B`C0yFOeVjU z8ez5B*l(QlMMHLAwFc{wmJ{Hu@!S9u^Q?FaEpNl5vRP19!$C`aZ-HXKkfAJ32FX1y zGzWlmVP;Ow8S00~&Ic{!xs5Z!@nbZO267&th#Nga44d(q14ARS3cW>@N4aF!DZ4mG zX+Poi*$wAz1@DkNAbK8n0ZW|%PkcCLpj2fWz!l&e1Em-1_>j2xnZY+)!y6{t{=iti zy}c**|1`062ZI?HDfm5@INzp|{(8$0G7#H0p_?n$GK8X@ z`Yo{*$T(UzT}@2_%u6l7NZqph%EdQBma1LyZ87a^fna%EkrxO17*EdG0?5}8i%}-T zdLlF!S1cN|2;g=SifBl%z%L_Zs1YZI-5nQu3&2L}mc$zT(IcV==)g6zKK?T;Sh2u! zzwR}n(w3nNPON_5K;94OzfAB2I6f)|FiBRjnJ))^fMfOxpjlnQG%+nec5`yF$>3*rNIx4aGB3oKws z!w5?GlKDls+5>(o!oPMKg9NHgu%+4HyW(h*dcUrkWU+9uF^n+7^>FS+sUf)nEMs`E z#kLVw^OOnV2AdTP#*<`y%<$!KnbOrFwwkOT=r#y^Cn!8V%gP=PpztX-C=Z?FEiLH9 z#!Ko^#P8G+03ul1Z86lVtm6|uD`6vsI9n)=b-6_Vn9;|;<}7QPy3IFs5&cQ0C@=un zH~5|{N)Rd_loSF+hP48Te0s~r!r$B6_PAlImOisoqzk))!TgLp;OF9%_)ep+W~Od* z7aEUVNL(#NUl=ZH0?jLjd}@iYb%;dALl+StK*+?&bH!&FpM_~22;Q2xXE=V>znUB| z@VaF$bNywKQJ%jSH;E?6L#UQhniLh&oAXT0JJ#W8zNg^R+iWTyp5(m z;WpB=t+z&-a1dC;t8)%JT0UT57SL7Zfzg?Wk$k2vE4>Dgpx!ustk6@fz=c~sPYCj< z8*}wtFNDopv3zffKY7v%7e=^>NX-E8XEgwZ>6dPW!&sWir-W!NYC3@KvhoYqy%rb> z67sc^yRKL)(`XAYI-(hR)^uLAp46-&f;o7M2ePFcgQ5ChK{*6OAda|?laOZH;j(OF zg*;dv&YIeR%_z@v%SmPY^ZKZ&tVDm8J$PaR*BU3E<5>H{6r)*19!6vfBT~KcLKD~rF{`x++Y{TF6Gj{-*#cJUn0>XhMJov-% z^$aP?)<5Hsk6Z5M)p>>|^PB|tHG+j%H#8D&Z;ys`<@wg>y?TRy;CmJ5+E)!6FA}VbCgARs1~|I^qwb`Os)}+pq$4Tc^Wg;u;p8 z=A;t@dZ6PI5CvFzZUaOBzW0QuBKyhvYk&P&_ga-f}0C!(ygre)$2l*s5m5OUsY&!p0FI7s^4yPY2FdEM(a6^5U_2#l8i&#ei?z11$ z!_f!ybP6IkF+C|y<1i|?#;7U09m~kRV*gCWu%Yi|;e1*xnyKO(^=GZIPF@IP&k@CJ z@cDjVffl)r@Ta$>NaYNjq6&!5^}-+T4^%q`+%LxJPMHLlR)?~emhO+W^&~Li1$8k@ zz-rS1x|FB%kImQ@kfecEdE;SC3Jl>n40d7>%%vVXk6dH_KU47RHQrmh2-Hc&_(4p| z(({Oc0`q7ktbyZbc?y;p4pwrY1yXBoqze_?*iACw7e+IKAGd zoEuyIch(OUAk?xrz}$Cl1I0mU5k!F)TXS0}|AN3x`n=l)y<}PDT38{J1G>-Ff^JST z*cNEPtqbQ=Fl?tiZEGWM{sMc|7S6&-MVlv2M*=5gDs~s^BXYGBEU&&HtU_@>Dfa9d zpTVpXmgieu_7N?%XUXW%WM8@jTy-AS*(nn9w(|g{!6uA?*KD|<>y^%#I~fKn2T+99 zMeYIIc%&yZJ%1B&ai}MYEy+km1Mwe1M0OJ<4~T$yEyHHb!lOH#!o&i%Z^r+l*-XQ$ zNJ#I7Vt77~35oeIlfYokYVjS{urEP~*1Ps`V#xRl_;}~sK^wymIDls%3XiB8SAydz zSp$m;mSC`p>*_!lOK5Q%peEMW@QxAe39PmeFj~<6{)*m118^F2{gAPSX~G==bgXL( zryvfI`hul090G{g(rJ@(R?`kE(-ESzB5oA87Sk}{j;-1_!H<_cHISSddl${_!N0q~ z+3&PkKH8&cZG$bxz%qZ!zN|w*C7a0G5VF@xcT#m~E{=!pFE$BYgC(%e2G@I=}&aAw} z)tn?TmiDtNrsyDTGI<3zDEf=d$fjLk2*z_jW>7W!?l1$jOdDGd$=Lwbp^IBU{_%p} zJY9z?qGi^Lf-sDy{S4x+s1M%LdbOgrC9wEt6TNXoaN}zU967FoTW8 z7%)BUvpEy#LT@-VP7g}g&0&Kot&#;;OAKV{!3_6~mo0JtMGXEsm+}qk{qC?`+7h%k zt>mL7;*>#6gQhLV~@$S5#{wat*Di3BYh6Vul z7XRZ4}E7cynmbpD(P=uL*Kj9)4Byx1}^zjK+Y#SRJq9KF=v7R6wEE0Iq zI5q7U2F%J(?Dw`3zhOB*v`F4S+(HM(3`=g%wQw2^mIUvIF#!{JG6Umf;;zhde?00g z`Y?MD_O~TXkmn8ow&6v-dZ1f|R0hxwJHdhlZVAASXTarwO$zAv-Uey~tGpM;V)?BG zCBgXoyme4GZ=}-lNzNHS3DYyqd`Y@(0nP^2El7lKfCu}Os)DH6d zZYy4JB~lj@;@cN?zk!X7M&To~QC8rpnAVvQ_J;shQaERvF+<^nBrJnVP;ER1m_5e5 z>t&!Rdr-})R_sLjU}KzFGM9lW@vza2`Ilxl1^=&EEIr%+(Fx}F6?fDl ztDS{@HaR%&WI1`mA|BRj-$e@-@b$Lt^)}gv8?xRQta@9}WqcHDgU{?50%Yk0{i~#G z9=jP%KW(w5|GsQ$yDd{;Hw^$9XsF!u3q{<|O!GP}HwwUZa@aWmj5~a{xP#2;ub0`Vc`2 z?r) zyI{7d+L{RN81IW+lT^KyD{I9xk)L+&K$?ONLB=l}5DUel^H!FqMPtJop!40<(AaRs zV!sXvzFRuP534td!H;FTkJRbA`{k+(5i~m+qOnN?R?`U0zTy1l^Xnl-hGs3fLRAM6 z1iZCFvYir$kuE3Jd@!=t^x{Fu`+jE!Q$7QZ3QfR(Mhq^vAfAHZ({%E@$PN0L?0b~8 zUir2ty;+@eDxX0-%}T22?1aJ+aTUjML$@qthe3ZhKj>yW;D4@DnE+z5=_w;EPXohh zm=1@IrvWV)4G=5HYLb2DGyQg=-;rZaz4E`V1-^!YB7=p?-6sJKIQuX|C@A2v>5HuF zf|v0&13YJ0EO0>EU)y6tV-2a<$WQq7Vp{Y$r~BstqTofv11tjvr)vj@lM4qXi76!ivoakM(KWqJsosl(-rHoBtRT zaB7&rY4zoZ>Tx~Al_e+U;8fbF>7KCD6EH(oAU4`fi$HQf*FX=bbYDq_{)jkD&Wwa1 zY7=uO^e_}UIg{~b=W`%q;&g+2jWo$*r@@k*_d8u- z<{|8VySjakQ={=#U_ZxXbfjWE-w*5hSs?NpsEt9hOO&%5@6yZMH|ss>LAb zo5(nd%-P|}Ab--xp|n35YpS`Dj1gaBbG-=q49uLDc*J(zahQi^nj$`bh8DTclAy3w z-U}yesqZ}`S9@&-et{IM6#+@QX57Y^=U_g0ypE^?Sg!ZhW$%nn?cH;?x?!U{mY9?& zfq1%gmN1nZqeUgR^KkZ??cfa-N?F&5^}M3FMVR}B(zrEnhxIGiv8nX5Cs_-?Q-fW8 zApuOaHqW7FHmVzX`U(~@+y<@?Jxmp!vW!MpohID2tm4Jx49m0iN%qD&j0cf6b5Oi(hLh;zr0qMrvuvzVSEN6t6sn5_AISRhK&kOr|f_c$l zHt(4YSEQNuvT8=5?zY53&ayBzulhaX^zYl&1{E|ec#GJ8*UxB&s~xso8;v z0@yeHeFB1vL;+ZE16%9aC8wWVmW8teW5$t}-j(%~$MT0|BZI9#)6fa_$Y8S#s!6DF z8+*VoIJd+sOEY*2|LK~>X(yltyaa<3U@FscHW9x4%K2cS{1ix;APAV+PggxY^tEaz z7^NOf_=yK;=@hHMIxt`{Cw%;=kiUlA?{|itbKt3-kPd(uW{b30`iJBVmIn!1*8E^N zLCdEJX5JRWVO9Wlc8VW6YJ9()9Ht}g^bF8r#O;pI#A({BTBvD}Zh>S(nEd1PCNl#< z>lZ3o9W{9CS-?h8&R%axKf8%^4GU7O4UxE=YBWf{(`niZz;~_$r^Ak1h*h?!>2x11 z93)tN)@-9BfJ^N3o^mc6_5Gf34$F2jnHl!BBO+W*`y!M_*J7y9jMW)#gyCptjDxd)Lx!Ksg9So7pRR!aAkKdf=E)9kjj$ItyGetkS@J8j_;2PT`-Av!Qg zXOZP-FV2qTkg@x@&O8~%B-w7M*#zz*em40JI8tgEOO0WYe?cW4$T60{;)65ePEv)J z>+7mA;b4`RBLQ+mOR-&l1|b!>g5=>w$RW`MkHHIKVr}nwSRLN`H4};#fd^Fk8?cWR zFd16|&Ysvq7rmEL#b7NAYS*4(2MwFj!f{i<2I)=L6Nz<~2R7^yk~ zVpwruLC9{wK4K%H%c&9F37A7yg?e8QC8$$^s?~5H-gmN$_q08{FU;I$*$JnbPlHA_ zdD*N?*(dyiN(Re5F5VdZYtmPEDsp~0hPDU@D+%s|z})ur+mKwL#+!M1%M;5P1kK(KY) zCM3c9P*(sZ6sv0E?L)41(ye(X>%;bYeXtaW*GX7qXC6es-><|NquVv!(*o#>q*q5( z1;;1I5!rS)Wk2z6BpdYHw+`{lg>!6xei04N+UH-H1T6RlYdIV&8^N={16Ox1>r9qo z0TLi0fqRxoA2}hk2_@T-KjnWy1)cNvn!CoTN9Pz}qbm;MPQQN5Ar^*<7$WRg^yg_! zJN9bi1$W7c5tE7%RMf(xE7lk-YT&ZvvDg>(B@4jkbsB+z$S+^OJ^;n>NjS65R<0kI zcw5(9234V(OpOI?fe|FTKCqsC*LCk|_WvHO=~-*O`VVk@Mbn1hEGPq`|+!0 zYI@GP=#!w{j}wJja>LM+zY|?weBWR|HCN;dz*G=1e5LgamWR}ANCQJPLa;`y+w;V3 z89q@lNSO@Q&p+e~NgemhB%OWtf?Br)-$!o!99~uMMT{zttPD?R{ zG$Y)>%5F@w(`K+l!Nye}ygUjJ@m9F@>AQPAL!9gM-5lFqtouU}K`5{R^b7VJ?51zR zDJvPL^IvQLh~vU)Wox&;@99=C7+pJ>W=g>95$5hxy}-sXXHJX^01Y>!@fyzU1eA;YFyY&pWKfC;5$k-~bdnTS-$8~ifbO=*D-{LQa>a)e zj|G6p8e!GT(y`aA@-+ioXu`|MU0J%`)~p!80oCSbtzrkeY`|Bn z7;_}G-r;W7S|UrBtRo#t!blV1OJT8{%SFvcac`?Fx|9s6kr0Gho}XA9;|oB)iuhGpbfZY0#Xe)Uv;eRyN+qW$R3I-!Bl1g9VXXIxlCX-;zGy8%k@w47)m_$)?XrYg>Cvx}C_G-9@a|obSMJY5whf9>!&9YKPt)$1-#49;;t*I{gL-y&+?fTPo{LoiT@`)|XXNVlV* znlmII+$MY{fGbFpZHl(F8us$MPQh3hHp@7}83Yx~f2{1NCJa}$2FYZe!!+=TXUKDL z#GB*YCd*`}BkuXMBW9HLG3sJf6lQBU@{^qbC}zuXostP@D4k|8k|*%_vz?QClH3*rW_nJ-V{b@snNckM_&J8 z-0fO_PDOjSUN&L0qVdOq@7(axdLTOAW3MT;2XU}0?m^YQRxaCG9KqXI30Sp#$Bt$kbQ#vRBu5i0>rZk4)&$p$c^6fFD3+DHW!Nl%aBZZ)dj_oJ z-xy#l-E+*1UG!FcV*T!qgLI7AWRpOw;KjPF%yjI>qqTO7uU%#=FRl{`wBB#GeMa7B z+pzB_ub+ZF>L>l|q;+RxekV8%)mX_&GdtQjM8KSVi}tu9()T>G3(lNPyHsH20~I+l zzMVThEXR#bxmXUQ!2AJWAkBa^b0r+pE0#Kaj`LKuy$%ye#@>3kp0JiBzxI1uQTCh` zf!9W>WIhB!ysa~GkO27f4C(8Jr{M<%d22nxp%bQdIzy&xldPcTUp)$B#TGMmZ*sc1 zqR8)URg=B47OLW*oJpItfsLKP(>fzDK~W9hTRa@>zPA9+0OhZ9`Z3h{YTld`VZ-o^ z!|2v;+*ZDV3TzkDboIO&ZJsNA{PwhLm9rdsB6N+~z^ z=wv?{1TvbBUG_&=InMrIbnwFX;dJJYop~pYV&*_UNU8~=6FxCqwH*_JDYm^A!Ex$u zMXUdWRZ-?=d+Xy=lXE>sKE~kvOt`T}M z1NN3hga!xzR(AmLsa(J88yUv5Z(b0gDD%l-I-32qDZ=>z?2kJxK=7g!v*n3y;) ziBUK}hQnRhejAQZO(e>4Ayg=D?9*d3WeeP8d(NS4*ee*Pk_CR}gE^e|R?8 zjd*JRuvu2!oYK2&!O;-ASaz9gY~u{DXfZb1O*l#?B{~85D;a@2v9sXhf^I}em%8-~ zjwL;P+yG8k58HGa9N1lt)HnwE@R{x(Bi^=o~zH~e71&-H%kqtYq^03XD14BYhso94*S8=5# zd~Z0GXraJGU}kpG0Z9?8_qLr)bul*v)U9X2dqfj6T-4&E@d&?lV(cOupl;+Tn*!_(9A#Te9LGemsU7(NVXm)K9K7zneNQ!^}uDXc|xGh`n2L<)+-r~Bz;DrSg*f%oOK z6~lwwSezp~TIclfpCATDi=W9*ItcBv4~*xnojcL6R{$n+gVl;C%Wr44C>y`A1YzDN zQSF@xvhk;%qHL>tiZS2^ONgMWKjSp7g0`&nOZSlk>sOlR|5c%!?XR-a$1xWmbY1~u z&hpO04RfN}0*=CrkCC4X<+W$ujHSI^_9tS-P3zi5k*rdCPkj|Ic!=?oMzB)te?=BC zCfE(=`nJOCLHsk0*hw4fwq_HY^Ek=e31zIz`yecngkiwij1k;kY-6j0_AgyprfB)H z*_1QV#%7I{>x~O7)=(nH&M|(@G|u4F5A%TLZi}7$gO7Q~3peElX2&TUg9PIMDur&@ z=bjenm;kXO*S^X-$Av2Pi$uBUH-<1?727n!z6isN?$DJNq};S83?&krwk0jsvl7-llB z7MnAw9urBn!1$JG4Ow>X_qh$CVW7{D=>gqyg!w*sQEx{(*Re%R9R}TvDk3_J zo~hk>cS}{u@X`$%B8p=-t_k>l3yU(k^I6i*5ict|&V;C$O|XGD68L>NK?=_2j5`Fc zit%vDj@!x-zugglGmSJ`uME_j)`?sE(7v5dqH)Gj^$Syo4o-BsIYzPofvq$8lGTUk zjwKMMnSPIE@N|C>Cp4oQf#4fSpYfzGcQEJ3$G1`(o`B^taQ9sikmU60Vlh*?)90*- zGZGx9)e8T^g;e8X$teN+l~wtVcNdhAjcH=Zzp$?P{(4MT1MslB2(gB7IVk#;zrykB znak-EY$O_kNT1b$BG)z|&4%q~wJM){P({@eIGn;|cu?ZF8`n zEte@pVDWr> zu2)9UO<68mu%Ojwme+s5e6{Ot<*uIicgnUA?Er`(-{g5Wb)!`~ed<|R>fdfTPGWB2(^EJ0bU z&j#{-*}DP&f|kPO9D-az?5qntx8B7wxCAEC9SmqXY(H?Wr$8W1MTm7U5Sr7p6Zi}7 zCE#gNlwyIJ#VQctHhuUtkmXUmZw)FtWtWbqz>|6(gzZ(;5|dtxn>e^ASqT0*DcO*Y zN#DoOboJuQmnC??MtJL-Y>X-O+z2-T8m)o~x0`&~o30C`-GxOV~WG!#S_YW*2)WJ#k<#s&CV_YLO z>u|$BF_AyZv`w(t@9}!MN%2a#W-}tk87&^=(=MAyt?%Hm-}LqnWX$rFYUBp;?l{vk zQPU7;gqWjoHgQ&19D*;>^xBH=vO@@AJoB2Yt2ejx9^w>?Jp#ULdjOW@Uh}Z3%F$weofEtE- z?3+>nRIG-Nuph#4G$ z!=GDDEOT-e0n(2j#ucDG^^9wWQ{u8e{|H6iwva;3?D2B=*)%&g?FluH$XoYe@h)z{ z!feO6y$%~g0kSdq%XxGTad;hT5SO`fix6K~EkbzZEkdFx5;PTK;H z7n#Z8?`m$kc^EZaa)t~RU|MUgNLc1_&f>8Hgp zJkIW^PTsRknL|pprDy90HDAfP(1!O~O|`v{M#msJBcv}Fe8SF|Z}dh(-u`(TK)+bb z0<2<3teSO<9?{Y+1=V))Xzh|2Ohk~g-o~0y4!+CbPeNsr$M=1h&T}_A{~T-{tn;7V z%~;M9FBwLbzRdz4hD3irrKwLtG3?|FhJluY9+d8{3be(>Sna)fG z>%a|Ps~#L=@|*~Hn2w7%*PfMf z`u>a4g^I~C=XvqL-paR3rU2Nz!2?K$fyri_9266tDSz8eJjCUl@d6f|#?PzMoLlY; zG&>AeJ*A~c8%9?=Ir*@PBo((t3M~H=zM=zu5H*T7mR&-eFR=|Swra5FivS- zXCR?n2~H0&z-+1uj)jwjl$IJ^i_cEQ@3{r+Yo|04N)AYLtQ2Smk5n!&lpP8Ru?dND zosk#JSf1&fOR*+9Fwn#Xt@_SAFwV#-Eu7SmHK>N#FMNsnmOxm2*@`x8r^&T=McaK! zvb;n^7!ptxIkG7oCra`w3$p~knRV=RyG=0K2xX1Z{c~&fEnrczqn(}a>IGEb7jN~m zDeUwdZVM1kcSV6^Kh_BtZjTmBI9u2h0=CL)H<#13TR#Pq)zM!LR{)q=253HfM=QM) zlWU&q0r7?1c0<5b1LbD#Vd|fkWZ*3Aa<0GPENG(bRo0yYJzfVtW6ac{>j{>?P0RB~ zkXJc$8L6`p*6ADz&o~?gVj;XGdfkk%eLW!g1(vZg9*=&NjgR3h0H`P!Uw2r#*BClG z9B=xbY=w>~S}I@jufW)B*cy)b^kyZ5^K!UlABvH|QoR{+mYUs=7U4Zw8I9!Quk@9A82YCDL$U_HvYbkNcU@ABH+gGa+mC%2RG zGtP8*ldA!Mbf(R2aEWoM<+OF#F~%)89@hFeYrbvg-5SE_<%ew>`L#;&aN6Q&dJlkI ztpX9A8&2yoY@i!j@otp}$PKp_d|353Y}I;fv$FUFr+3w~P31bs63x)xo2(}8S3( z#sW*>9r2mxA{XGQ4foOpQ|v|toX2M*xmYazIM^pTDZLM24Ggjx6`2?YZw@k|qi)l!C$&j?* zj=exc>bau5Vm$wg#`QsDb{}01BLAHBYBbpHMn|YuhYdN`)PS4!pf$T>vpc_%8R$dt)f3{mNeI)Vu^Lne9#D2WX`CwLV~&H`cxpZ8o=aN>=4lr{w#QJDV}8?x ztQAW!?bA-q3fLy2>TTu5M!0NXb6z}tT3F@MtQ1MS_ptQJhAoKhbJ=O_tl!Vos*c$l z9ahJI8lOo+2$q%a^0W808UHuacFP>l#~|6mL82Y4bA}kI>75zTo<88I`Ly*oh0B<` zz4o@M|<;a@nq`$<&1%a?6(~HUN%yY*5O25R}>qydh`rEC4M5wQG zZ$M8L;@5L;R)WW`mLvY&?(+`=hTUEkd7e>(j%7_}L}-cHXh+h!G&8T_=QEhDdgRs4 zRlG$wRkWWoogAMmV|OSfvMV3+O|hVLpd2K?7`xLL+#Rd>j`7opsuuWsgopzm2}w zcmhYk`kv`Q{hIb$JD<&w8n%_&c*jzKvWhpvs_8*{u*RN!)MkI6rfi&uo<0-9-Zht^u` z&$3$2XFNRmxw4mMvDj^`aKa%w7|n?<_hpmj?_yO`l1i~5BW#E)vDxVv?1|hR%IyRe z>*t2exr4yHkfP}$k6rLgTJ zhGixg-+u>hLJD^Iwlh}e_TI_5mvaLx%6`BE4zNGz&6ypgT7F|;9VF&0c*yN#@bt`a zJ`)t6pAs=)ZaFozA$ko`IBiGni&txvb>_a<>-IHoQ){0?6hGT~9rWxyv+y$S;jq17 zoo;V1?#aqL5Om(d!msUpSrU~Hdi7d%$9nGTwaVSJLMlUD#yZ<5mCOLKZ~Y$Tf^7~v zh2z1S&V=28OI~)vV$(N0Ec7@`v9oE^;*kvOT)3zhN%Vt4u zaH?R0YBkfooKYI|u150;Z*NhY_v{VF_IZWNvf*)if%&f}@Ql+>0xj<-f%TkQkuLCw zcYg$lIeJk|T6mk;F<^6zxs4Rf6EgpqwNg&Asnh&{_P2z&8?8CCah{=-654Yud_4os zC28Lo!uiN>u(_b_?QC6p!JI_!t$+%eXU|vryvM@Ip2Y}zsTIV)e-iBqcV>nwm zJfgjp5NxLm7jM6XLjVDsVIf?1=<&H{-r{)Yk9nb0Kh-uIi^;yNdRnEs#@W7d*)?5k z^fQhRsFC@Dxz-tA1D$!R6^>$?*h^J+HR&*Lr-X0ktZmyCF#d5H+A|d7wu6h$%rFQ= zgpGj~tpk3Ivn{8!oi-J4u9nocVC%@IV->D!IP?U$i=B%_ppAQ1D{<wAR&zf1B_#BpC^8Ci0)r>I{%pzVp^ubpWJ8 z!p}64-O}ZdO3OMhq)+~OIGx{?$3cPQcyj9Qs0V#L+vBJKPXy1L%Nd6$Isrs@=l8if z7>hLw)OhKuoD+^z>T^QqD5horKj$p?_gpSuJ+#xiF!8obA&|J8;k6_WGvmr+@SI_$~0v)4`M3%i2X*`OI$L$61*ETox0zGtE6# zv*+EMyjN>q)k~=`s`-@9qgFf~TWqIkv8uR)BGVb&9FVi9E&IF8fBx>Z`rJb>>y<4@ z_14$-%r)Ci6BaE4H1H$MiBHhT?m#MUBzUlUW`#G>Wrv?7R?(}1E~Dqds%F!K151h* zkm!I;Ci`{t>h~stLQX2M^xaWH8;H732SZ_@5co@@)TjnHty_?O4lwN#z(5Ut$;nVl(J z{WA&W1t#mqTfInOMH|r5@CsXR>~L)GIQPqgVZ2;q%-2D7@rn9WP=coODr!-f+v%3s z!A}ibQ0**S9VSAsGHZ_hy; zSNdH{`f8)vGP~^D$4d+vPp6aPhF^0BhDyK)w^xdOUhTZmh7UuAdBL}tQZ)FJMcP&m zPkW3m;hp(}Lk}?U$=gHHKIzQmpa=tGvNYkq;rNOPTZyxF=p-H-EEm&-lW)eF?Iv?5 z0kXr3VZhtg=Em$qE3ln?7nYzp89qDYi*KwpfGrym@_lK9o&IWp*7K{!LwUV8Z1-P- zjGoS#E|`inkk06_SgzQwE9E$7XkbPc&eXfsFV=Qc~Vz%ahK;+sg+6QuWhRE4uG#rD6 z(tCvl6aydZ*o%U*CtYzc>K{L~WFVcD5w7M7dbeR@gwtH&$1 z*C#r*bk!hBG^4Eac{dMeQCBFvCkR4;;N9sl0T&U-)3Sap-(&MEdBK3f zU6=56MW>o1uT=tc+8^DAw=~;rA08+DOFwMr#~rnBazw9p{@v{LdbBjFS^pxIe3Sj> z`b?!Gg$bbym^~#S4cn8I=l_+G!=e2 zKMGbCmV(G8w;>83uMhI^kFo}HN(5%kl>?++qxVwWeM(OcdUaEzfP&S)K=(S*P} zJ?Y-mi!7kUd~%+bBVG={=;1W-)>$L2-zz-45IZ>49EC7w+H|bVrayp!36O>1Fv{dj ztQUB&i@;G$<3#-z);X!D=`^Pqmcz*QfPEYHnJ^gaV)L57`=HY0<+vFOInZ!Ue|VMq z%xBQ?YguS?jM$jx%G^_)-$hp0I%=o1dNXCSg9qceYX zoyJk{$D1*V?j9D!hF^B;LXBaWXqq+HND44zo$EUhwuEdV4eoQr5kHpyKY3~U%&9EoC+oLop{OV)Bb5(aK*x=z+EmrSnmkmzB(BgZUh8f{L z7YWC6J3{HUK;UofE4K=6o^~x5VtdX^fZ?zM;bCfLnEo(_cyUG;f8@owgP|-ntTQKo zSw?(%0CEnav7a8_sVJa@i2?FfjpQI8U?)KFTGkK+OD&A+-d=w)UX<9Y@N6KMzj417 zU74&BxyrKP)S2WAaHVTW@&6? z004NLosh9g!%!54zf`GG?4&q|Lk1Uzf{UG8szMMf#8|=VlqM|}b7M$Sif`bX=)-gn z1Yf{6P;mCY(ZRtiUO4<8hjae_-U|&kiA=G)2PQ3ZFX#;~hga^(8%-5}X5ZcV1?eRczc2f+O*R*o{pZi=V_hv576) z-M}QX=*QFEW^J5aoZG%?8;=wE__&OiF(sj-BTdygrpvz6BPZmZf=HS$R&TDEk{eMW zCyztXK&0E$z4mcdZ91EaEX>2IwWMlHCh-0U?IEl` zL+iRGYxVcrYG%6C%s=1w1+e(n%5rB z-shamlUbQrBgy8_WK&J{V9AzY!M^d0Y~R}OPw;;+Y#1;gOEBODWXpoo>TZ%vs>!Ch zSRAScsMxEsI^iFzAw|5U~RPN z2W=SwdQ8YxYu56b!gBWT=IaAIA| zr>WGpg?7pg7Qu|=0RWvw5P<7ixi&dONn7XwFMv(j4*;w z*_FMZAsaM?v4{i!bzcwCcn?6tLQXKJ0ms-mgo-*6&P&A^f^pOjlt5@51eAKOjn)_w zjIndpAxH>>T3d%8#sE0yJphCNV6FEUdv6^CN?S)TqXk@){{8>qfAtO#mN=too{91HbDlPLFMf3WWe|V&zb!6) z@qc~PUS5szfArrF{^Nf^UXN1%zWamez5nTwfDPnQyU8ago1FIg_MM1 zHnX;_F)pe@Jx&HSZ#Y%P`&d8-007=Q4}ka05HP_Q5u8zD`@z_K<9)~gz?f46|M(xJ z(=cDZe)gO7w&@RT9v+R;)Y>38d-wQ#kzW3GeR+9aHBm4>iem4R5dhb(iz14&w)SYj zgm+C<*I{_?@$??T0CeU4Rt*R_7bc5G$$Y4cY7e{Xq4Qo2*?4k%^d!jpVt-k#hjzCb z&88>WB3+Cgr1xk9QGLa;ZsSb;P3 z2N3`OSm_MrG=j)V%yp|7yzf80e}RUd4~w1-dX7#M2H{?fR&i5TGipK z|IbO?Koricgct$LA!=@h!n@c1{;N;2$=NrvvycDJXU}F62=6^$;V=L1zx;&2`RE`2 z(`fvQe_3^j=;V`ozyHT=`SCA$MUe9!JUV>{;j>ShVH{@h@#4epZm%|Xo2{`&nP5%d z_6Q*~8y_tme0cRj$*R0sTet5T9gv7I9MDKmLNH@mm*uVmpz1oU3_*f&8n8TJ3_|an zbIv&k0U(4B2mug+i=nS7W8*LiA>8h(4gyO4&A)zda_@oBLcI4b<5h8UJE;AY)LDcO zM9G9l_ue1PZ{FP9UR?zuipGmDWuk8Y*srV7nDzPDJMVs5cGYfZcUMfLa~`IXuF_IA z^?_cMD-kc=KmL01^!iy_5ps9stcVFm1YtGQ1s9YdY-G2GP&F(DKsCDS_lU@H{rTl5 zAN&`HAc6=D5rNnlM4dK+w-93o08|h`1d(^n000pH-Z^as(^H2T<^ZVLY45zV3IIef zS2aWs0RRyqh+uAd@80fk8e;Fv;H@(OXNl9pVY4L=(g+b*T8XG`z1=jQet8aI zG`;!QS;2RELhgU`{O6xN{qXqiKq)3a{uiHo@o-sGyXISesD@ws?9;1hm2s7n`cj}M(X)^HnsNbtSS$MFrm}*@dTpdkMa{t57(Q^wi)`vE#YC#qaf}Z zgaJ@Jj}Sow0B5!@>a|F$4sy(f(%I*KiK$4UNqQ2^X#|mOAwtA~xBIPx2vP66MHCV5 ztONjaL=kzb1(*+qx1~lDBJaGz?5zg8T?2pwZ`A`LL;wIlx8U!G7<8Hy4aS>iqvdoa2Nrev_0=Go{%h|6@cC~#dG8pbAO4fw)$0pJZns(V-~W%^{l&lB zRwtRZ_ZCk+ym|BNdD+K24zhGSFSegNt%jH{#}GET?i9jK zIv;WG%f8ox=@cgnV;YNyWBmRjYqgH!Fz!2ygUC5K$bk^bDQ5uyJhIvvYtCO@-=*<` z2Ti>{;Oph_@x%B20MlxH`DNF1owdE%mjs7l+eFc1=3QNt<=x7IG(LYB$LT1^&)8vG zRZ<>y-iav8r^kJJ*dx@nmtVzcK0|1Ad36~@lj&$ay_X(EdEcL3XR%W1=d0Jt$BXv~ zFV;z>)%wcl`GX+K7nroA(M^GAkU67TS?|toUSPsRenbUN9)5rQ+&imP*Q~moGggfr z(hwrudB@XWg1PCPvC3%@kU+Qn&J5vHj3IL7t?(1!jCamJ3=sg{BI>QT5Wm$503i1E zt%bZb5gI{c2JgJ}4p9UN!4M%L#sKu&=1#Q`ZJvGdudT^O)6=2+H1DgE9%fAmjp zpLrjN&tHD{PLTfQr-bOP?Em-&(+5BP=dai0FpCzW@nn7d%inRb$c&4_`Qq;K(=P|3 z9fAP#gSLV(GRfn3f7lk*Wf1@rr)icdwK-Isw#N2)u*x|#-hFQJEP_1 zV!MjsjA&V}oyAmjRuhgX!p_RZNX()c0Oi$CMU&YF$tgsbBVvZP_Z*_)+!+8c2f#Zk zt%Mjl?@Vuc%xT0@-2&hp0RF9A7|gu$4gf?T@(uv2FmqbBP9usr#`uqp|KPs@-dj~y zm&K(s$KNh5RRh73KY0A7FaPF~p9jGxd+(cJ`qTdh07^pk`+xMwPriIbNfP|Y_uu>8 zpZ(9Hotu)4Mvn?(dj9rzx(|8hN0tpn#GZ|d2+H~7y!l8F=H6_!|iro7md|LGpJDPOG*(Wm>>v^)yCMNFYC7V zZalhw?`SG`$j8Yz0e)57ZZ|hK=Ly$66D&yLljU-rgfA`*&2Hb-VK7}rA%)g*&Y01~ z{;;*0i!gH5Ii;#n_Kfl1u+^$%+b|s2=z**dG{WOsk;-8Um}g zmvT_bS#Pa0gC4HG+OEn%OX!`o8u;z49Kx6~$}rhpTs`~k-(J6}*3dFR1q*m28<7%T z-|o)at&_Gl1K~t?=N$=XOoDDh156R60SUZS_4;?-(GYWIyd?qVRsjz@BA8zn`Z>rHcij8Q0-i{kL_ ze$ko7lRUxb{{7MP?#j6!EQ-1VAdbV(81Fd)plmjkwuQ7lq)C{kNwVA3UE5b})lrPm zt_hg20ATEV6dWzAi$Y2btt^n;=ElXb1uD-dUq$pgYWIWO`=+zz!k+oN@YX1VjWPM7?!}1eiPXHXnFb zHTaK~|Kxu%Lv>l6msd2P;V=JrQ*3YIEE+%i>BXC_zki0%{Nbxlj6A>k-Va90U;VUf znjZLXe7h_E;>Qp;e|GfvF%LfZc;7x+9GVXwhvDLZI z2reqEF=`rP>TX*@I7^Q6oCiE$N?ot7ckR#&_0XwKK`==ov78>y!yt|G4526*Pm2TR z%X^eq8-_vf=)<8UbTn3d(e!dqWp%fg10$S|XY)l8YE?F~aoat8QQx)uu6gvq@&r3M zXtOV>G7xdHcr;x&>0BIJbA18)c%J0WIIE;FoNrgzIE=Jvo6So0vn9syczQ31o$0!v z?^{OGaTpAJ*Q&PNS6ib+NQfMigwVU8i!wqmHoC3aN)NzwbvE|inlL65LJ`UqV}y7R zk6G9i+w;CAM3%)(UulI+B$=Pnzbo-*L5!~&P1fkhv82SOit}8Z#15b6QF1 zJ%pH04j}+WYo%4!7)>a`TD2|X`CP;T9-VfzR^AV_k%zn8Ey9GdpgHu7(GU)eNQ^w( z?e1iUiSGM-ya2!qvTWBw5zV_TL?RVAjUb|tmAaLsRnD-4MzT~j5pM&a(-ytW2C7En z|9?_?PcZV%nd0i|`Scio^(*hS8ZU$F>PG;)``zNM+y~+6TJS8LFYhkyZrh%-fB1vP z-}=pu|N0Yx^XTgz4E^Ps%Z>LTue(4zeOmR#QT*MHhGDh7-M30w51fy9EUY~{_P(qK zIVfcqnPubn-ifts+xBIrt@98>!h3>4!KnAv?hndzgRuw=y6mkF=rqnlhB0zZ*{kj9 zFwdL*>D8wfF^~Dt_|ZFzkH(wzde;uyYEuU6XdDQmXU9>}wZ(yu{b5%SoJ2to$9=yq z`r-OA%f|EBy)buHD-qPy)kWVPKbS3*s_U|`E+6M}HFyVrQe|Px&@w?NLVa(H5OKmq zmQ$+KFgQ0`1Tg?c13)O_JoJt*Oq6UIgp3*blZRpIozXntVVEJJdZYWUJ|Kiiu|4da zvxd;F(b`%{yBc90iHOjqynU&q)!mK=Gho)Non^7e5q5Scs&hni=L`|mRkw528Hk$O ze(zm4`;Wzj$U7@#NyJ;W0Figz699O&`E2tF!Y~5>05v38m=BdTVcZp8eVSz1^!EDE zW1|-j{_0=d>`x|5H#@of;?rjlhu~=Z-go}&pS4oZSS+W9>eJUDi#RomI9FEZ>%kaz zlBR*S$FtM><)P~sL(n?!12!AYW|T30ce6dz14glkgFqlONNo_bwj0W>QweXCaS5NM z$75ra?j%8+hGLXjD|OrND?yKQ1R1T`H+OY=y39w@S(*Z{+1~9S*cP1j!}0R$eE`xm z6QkYvdDklqVGxW)#uW9gytqv+rmsfhIHN3#A+&ZF`X-2Hi#So|O?P*LP}g*w5OJd9 zX1!TYXK|X3ii1*RsZ^F{qtQ(ERnay|GQmU;ISYVu*06wwl(&_X2qh^Kgr>7FqZ|Nh z`U+w1jqW=D01%#rL+Rz>P0tX;ja4j*Q?#1|H%1i+RNYj-rxP`rigjK zA~72EL#rva?szhreEAB1JnE#j%W;+-N+Bpa9G+hvW!eaqM2rccbyd~P`cU=}pJr){ zkoSyrebH!35Q3a=V%;c$0HG)t<<=gGcOLP6&Os=Gqa{Mumr5P>ge2p5gs?TY*Krvo5L#<= z-#KSgHlsX=EkJ?r@s|E6aYN@@YUzW zX{+>m@5t`AFPyKXpn1AlzgcJ8y7`Dvty@Vj2lwXQJ9j9{#+a(U*+Q@`^JsZ=bgb23 zcXM~QuLb~Oew5E=-fwsN3gb>HBWS=vAvmR4PbLT*4oXYuz4y;wMgfG*aYktz&lc8X zqijSNLUl1e0MK<(7IiPp!Fy#u&j_Q+7<+l648g(nq=PUB8P75)5BotLA4f69))t4& z?od^Yl+&43QuTvWX%fdL4P^#3yB*Tr!VA=K1Oqf}duW<1QsRZ&;gGG44O8QQkm@2t)8d`4&xTHE(s2LJ$3;w%zO z@PPN2h>!=Wzxzr{LX#0;5JBWD091%r^+xuGw?%#H^;YYS2o_mQ1PL&cZMz>m^bR6t zh(Ht~tBAlHB5$3s5_1FzCAYt-R@ovL7gv}>+46nwu0Jievs2k?{piEPTB#%xVOtGK zurU0C|Ll{WJpGE|n7?yBN&oF%DjPEAdeKI}HzL+QP9 zj5CID+iq778r^q{4pJ&YvN2`Wb{zmsP1(`?WX$i@*KONWeM_hanE*g3tqv=Qg2;PY z4g&y$DA_m8TH~E_X6Wi59@=6fhcFHk9*RWw&92&rSPu|6<4m%gzGD^P5RLD%NaU*V zPBzs|F!l}rJpcfJGrIGR_Lx~o1R~ygD!^m=J$_{`43+z_rdad55VVd zIEi^GD4Ar>UX~pIiAaR=t?Zn(qnO~`u57M$7(JLjyni^vF#xO0?S3!}GcrpE;*3$L zdZ~=})@|xR3p!1*7yzZU+1IsV_&7qa83Kk-J9JW;s)w-ZdS#sl%h6(n@pz0-e4rG7 zt6NHY za`^CGp8xt8fWU|B!BN!?8URL)r@QLz&`6B#&*JcU&&km!ARoQU=%L&eW#_;mzkkYw zb4B_3`eN6rkj~QCXq*Kcp+VN2Hk>A5Bsk$XV4)C<5Q4J=dJHDfY!n5Y3O>#A_-Hyv zMvg|>Fw$%1rP`P4eOdN>KXg4Mfk#4rNGXIw0HM*0a&8P`X%;7fdtcYiEtbwQDyXr$ z-DYJ?9B+2JO6#Va&KS=p-g?(G!$1ik)^uG_-mR?yF3uQde0-#azO4^RV&c8g5Fnh6 zjIN4d5F#BV<1oVv6X4Vk#>Y>>k&zJY&g)&XH@Yh~uQAk3Jiq#MeSZI&G`#vXM8IK6 zc(<)@AVj3P^442KOotf>WbunXBZFdLGFd!scZ8k1bNv3(pM=S`e=xMKzZ`}v#RB89 zNyRv2bTI{>thUvz7kHi|(Qa2Z5O#yHi*%ZeN0d5O*L7R9+7g_G<2=hKD-K2JeG=z6 z7Z7R1nBV~98OEVRh%qUr^Z5c30M@q%6~&+cu(p%hZi+@Cc)jEF!2;u65|SnuQ<`Q< zwr$s)U)`?0|HEv&EY_=ivED++1*OYbD3o@tZqn@d%zNj0DU~sdLWnV?b&YP*Tm%@m z%`iAO71_kOzBz2$wm3u)rN(G2rE>s4xR`V1+#ugPM<~s`ud1eVUhEm?Vmgcavb1)+ z0w7K)({jJX7$Itm(yD8R0U^d2k5kG-z=ZdzbGEP4KxjHij}UIl^~-7pAw&Q;tA?(~ zPmDyE3GaxA#@?4VEW)hYmA9DD5TZAKGk!4pfJOj7qugtED14(prq;xG1WoAFPcNgfK=(s?}}R#3=w$N|_{-aRGoFydMSt5Sksu$JpZf-FCyVYLb}03gyW z=9oc9oNsm_X0dkwB#Yb6g0OFz-C;|}e0lWn{Dt7hr{%Womy3Ik+w#@)QBvoX3>jY^`I&Ic>V)YR^b2rg6ZvuIg>+ zLBK}w(KL#xa=R}ZZ85S=&@4X`gkw-u>+Rj<_$Ukyh0En3>)siN7Vif+qRz;Qr!=Aje=Ga&gYiAp+&wSX`O(cY2q0u)bE|b6=ksdo-J`EP z`z`Q`42<%NO1Yx||69>z4_yB*h=xgYe5$L}%%AR5cg7-kfIR1j2o_ zYtN=>+;qma1I3)=F(Xp7{h_vQoGd0uL`c)zZq}u;f}YGm9*Zm{xR*`e%YADdLJ)fI z0Y;QSm_z|*DB=O0GrUqj-B}I%O#3><4_k-56$?+-hMPUpV zgiwm$+wMC6yoa!97)wV{hJZ5w0N|_$F$GRZMmQ6~+9(b}qx-=cj0ky~2CVCPV>mO$ z8ta^+G>R!RTFUh{3X&1VYG^y>81>G3gb~7+aTZV^7$cNmoMh>Q2a|i*(wTa@dUNxl zS!2ust62bianQklcbhC>1OSY?p=dvT zsw~F{G5q-cWa@pAX4!r(6{Br8sH!0UK{UuAcsNKostT=sWe7o7ciRmn0AP#}!9fVo zVOti)MA7sJLWIXl0GhHc>jD6T^&lJXobB7THro3jhN#^Ujwut~nSrP6`t~#3FMba* zXUw29u@0i4+TV7~cz*LjM16zF)rHbWizt2lLaFyYx_u1*Aqc;E76pMgS~T^=Rj(Lj zv?(`-WwLFT|E1#14fimMhL;i8WSaH-ZV}7>Q!-= z&I!d>Dy2E6jB!GQ=zA#vuofZ_3L&duz&K7JBm@9wyvKwK=dAT!>#hkRgoT)mjM=Oh zGsak{w8|!Zt5nxJ7lg?uNLVmB3KN8!GnyhQtPZk#X|&aU-!w+NBRo0kD`#~t^2<-& ze5!}>Bky$QjQ7MiJ?t-JN7>1{zxnGpt%}okAQU{wnP|H}EFb;i&oLebLRXuUWl_ve zU;j)hcGLLHnv2BF1T!Uf&KfkEf&4`*$~Q zuIoM)qXZ#JwAqyP&})iDVIFhloKi)(uarrGDDa*TA-?!Z8fgHam|_S#$ihM09PEzW zde6x;1%R_%8SqdLGRmv!{H{~8bUIz!_kO=x-Q8^Rm=W)d;Y{o6UBDoKFwdqlLeo7$ z&t9&Iefch&AB&(YtbP9S-tp-f#!p`rEhWl4xF_Xir;XNxj7O&r-h6d_Q#8|@5(KS7 zNU6R{((zQu!`^I`r;k7Q^0V{XUJ5au#fg-6+pLE$2oXYP7_`yad!qsH-g{$>Q4(X$ zl{!>q%@`p;NU7G|D@7T`QOuZ>00beWyThR-m)>g?$Al=gSr2`38zzJjs$|^g1Ycy=76-gPbK)1!Rq zY+HA->5z|N;LFN6&b%M`d^}n-MN?ki-mb^FGlXm}t-g7^zFpl!k(QKEE)pZFyH~$E zexkdtex=poES+C{vOh=QH$TN6gg^X~!(Bd$@^;@<`SgQ79ZDz{24@4x$pub;oZ6?Brm_t95hQB?GTE+$vE=X+%z%|~%BYnh2GwC>O2OtX4aF(Zh zl46u5v+3D8Y2r*0r^zT=&QF$k%y1lXN)Un=BjlX60YiXbjGXJ`q1voRnUsVGKAnsw zMk_r@PnVX`O-PnaMn_Xh+Sb~m<5GeS5M!h35mwnhX9BUB!? zrPZ=Od1!T4ZC3k(b&MM2Y_ZB_vR=Ksc!}MUKZz6Fig@y%KfL(3-QHZ1kWr!J=!A-= zKXq<;uP-)N-i;OrJC`N%qc1;YY_`~6y}2GGCriR^RuB?=G;6D>j|J@(qhYuyYMrw* z0sukn1dYSH{i;d%Q3gOWNIPYttZ6Q8t3gm>r?bAhxw%|->U7*mX{2h~wyoN>cRu26 zp!piRICHZ~0jMrcsGL(p$`ukQ$A1S7%jpPaoL1(Jtkv3D zW4pfYcFofl-Y=))aW+P%YccNot|KIh<|B;D`r=N|xsKyBcHX&ODsAoJc)>U8rrj3- zKfPDiz3ipf|wh>-Hr8)8k~cxhu=IH-<4n1n;Et*6p{>F;X-a*T$rovvmU@#&L!T zA%a85SP(`jWm>IoHe1ji-$NKeLNS66qtSSKO{md9u-Or^-vMAuoQib!W_@|PZvXb| z_rehXZBbsU?&hj0%7($p>qoLodXY(iqpzWJZusB30ik0-<`%w;IUB9@}7Vqm;tOW;PGOg;a(B^0w z$Frl&%HACs=feg;!3gnQ>($nnFpT3Mczv-gAr#{DSgGx9y~)xn1)%QM#jYABlU!>6 zID7s@9AjKJ>usJAGDt$4Glp{jl(N?QI5(Ox0K(8Yt->S>tJ*rL)>rwIv9_-}sgh_q zi6U*9&N;1=y}*rrtfVd*2;-n{FYW?fw%_{R=btovz#l&Z;FB*g8YkcU)?xSNHlWMV z$@1By_W+#Dq^`PF0T6Qxi>_7)OMsQjlp(@V#Ts`+jq1Wh6#% z8f1~P01%vrfLp6AMuX}#Mo0N1nPdSEs9<>-aqpC_o4dR7o9kU&RmJX5)Y1Up{nK-( z0Z7s~4Z`u9plQY+0998uT|Y>I0>P-(b$hw?iqbTR1to)QdZ~fuGz{wQZhyWqaxxNp z7>b(FBw?(q4s|~mqs;vit;)`rJUKeztn0U>(OG)5#IUT|4xzh4({mgIK?p%v)ny>O z(@IIk6UpIF@-v?3%9CpKC>~gw1ef7K@ zAbkJB&p&Gi=kFiQm%sS9>gU;HM9Aej;gmc$-4**5qm(1q%2vf}F>-EORVt*55ri+V zUapeG36=FRuH+I!@Ct5S+y!#RL%yK;0D`07)3IfX(uE-xW;C+wHC?JE^*% zmh~`b=MbdW*k%|MMieVkwDXjbS2wS&USAgbqiHr}47f0egHaj>Rl6&!!3ZIOo1P#k z+b)SAfY5twqy_*Z&YV-G9kk4nG&cI~P?koA0i)eecD;(l@@SHFebr*fn6-@VD=BBQ zFuGe6O&STxiQvv6h;iN2t?Fe@nH>6lcOXaz@0?9y2-iDjMw38rYK<}sb7qZqfdGK> zY?P$l43d&OB^V<@IOhT(In-^M#BtZ&u4Eqsj3HPzRqu>bz**BY09b1cMi_OClmVM& z3`b&rBlz|6i;L0d{?`!x*^j#}<>_qoiie;462HUWe=s|Nu-qf~;DfH#lCx~&J%B|) zNE|(We|}c3flK4>|HE>-T{Ds;jDGr6!~s}N58G$g2!-r;aknm7PLq(+T~Q6Gm}lCQ z1A>nhvq@3cGU3xCiwAjE2pY0HI$6fqX7#(55s!i-3fae zqbGtYrPcXW)ef3r01*Tb001zI_&B|{NW*}IJWtYyVBn35LkOlBC%fjb`|am$s2fT+ z&+;rY%9>Vs?|l?-G8uRM-NBl+_dejEz{mq@(?Wtsdoq7nSoErb&`ej3Fc2 za+EHPIT?m-(8~My47jEPHp?mYHV|nN2#gP z?hc}}Z~yk+LdZDf#y|)mXUC_HzVqo%s%kub@{Ps2pZ+qAvXjy5`R4#&G)W*lzu^R< zW{BclscqR$v+Y3|2n9`}K|v7E=|l)+5S(Xmh>+CI3qtXOdl3HO=h_mat+kwSjoX_sv+ik7g7yGj50}+Z@s!csOH%%v_H0e62Zr6i;a6BGe zZr*I9Mlg#ow)S?-Xegqf?IC<~rS-!nCugr;T-`}+Oqw*^4rnlK1N6jg28uZpU9^4NQXrlZT%(>EA97X*TDi=fL#-q#J%cbn^*#gTJLcLR9y zweR@XyF=SWQIt?>?e(28jB%!Q-AI`vM-y$NzFQfC@mo~ZOJe|t(zYwxL1*EhM)}Q~ z>$~ZQF@&xD=%cS*ly!arfNZh|e=9pXp55PGQTD+P0XY9W2m*zkHPyX)L1Tzf555N2J<;Bi}?|*o;y4V|sQOI7d z1|9Q4eLMDUl_2r4s6k0yP8v-;g_MB<rKb zx%>5JSL?d#RV1=FkGzkAqZvZ~9}Dl*TS=B+>&1?}!@Co4yrCzP>0MW4Rag6-dq)r? zNCTON3+YLJO>cq#L4a_bX72RNbWfM*GHIBZWYY7H$Dih#n2ieni>D^2Ij3v^ReTpJPq0$c$rZ~Xy7&j&Ty@wMxz->ToOWXD$9+)(r_h# zx;AtuN3kM%4P0hrUdh0-5k$~1D6Q*?*oI*khHWm^mcGseX*6snNs3B=7!#^0GT=-S zj8dv9gh-N*5Jadf3Dq@254xnBEI8FQ&SdF&iK|Yl-CnJyYh0IAzw0@Srnw}#{dTji z!n9$p6Gax>&}J)BLlDy>HMORHH&f8d-ytoUWyy=r-4;}u+duvzeBnKLs+mpzB+Z(i z)ukjEHZCtutEv^KYNLgex8Dc8WgUK1hCluZSH02rbiO2Px7Tc4UY7)uC;K}O{_r&y zEqi-oGM9mnT6W;X1*WD7r1PnUY@^$N@M0R4LbPmM3sc6k5&=iolwK2)}C>OFR}vDbvBPn9OgAyh2i>Q zd~!ayT}&6VD1!1}WB;k9s0auMAfznG=d0NQfmSzYsWN9p6-G!7f_4+ZD4s27?Ru`G z!U|W|bGJ846lNL{5|m9-5{u|=u~-W(Bn0a^iU>BXAP6H_)-_cragu22_HJDWE(GJU z9Qf^?Z84G+d8w;|VYAC|QLZvVss&ha8+VS3j9VuaG1uK z%(Hm5xC_%#W`zd$kiR3{O!g(Z#3^#34H+5N_g|nol2&%|4JAN}*Ezd6}%e<0-p{Q`P<9i5I zWgM@g$#T5H1QSE$yzQ2?sd|R3LtyI=n3|A~jHx0^5+-3bPo}He@zp0*3+@M_t!~HC zWC=)|S2&3nX|_8ZStRKqG*ru0RVXutNmXi^uFF!I7o`F%%hqaw3C2K@WkS*_E*;%A z17DKjloH2weOXMGNj~TXjmaWR+JT`Mlyfc%f)#~PP89^C|Nq|< z0MtbAy3Wh2%qmGZcEc}=B&S3YoL9K00~Y`V37Xdu_q|3?=1>N}wk$hM7fD5+w6Rf@ zS93x+1)@7(WEo15>lB6S?cU!!RDo?lsHlvtmKC;)!9BBabCjl+XUSqV{%`{i&0qZ{ zU8fxYtoZELZ~u7lNs?MEK`*Zq)NVH0R~PfhGro9* zi+}w_@S)!dF7GO$E4_y6+${{X>DcBfk)*tCI9r3Io0ji%+rRqT z!^6>FbJX%5Kij*vy&*FsS2bZsHWUOIzgr0A*rqKwXQt8VC=l1{q{e=uJp>|8fkasx z3qBaNyLGu(FW02jbxldj>5A5^CW1&VaFhY5*|0RmIM-C$0-&yiU@TfUd{(CgA-cwC zn5|cygAjr>$*QsvL`!s1UF%!^o1F2tk>q zc1FE>tr0Dg5CDkM6o78uZQAYG@#!Tdj%66vQ~1Prcn=qxd(FvM)3zQg?__zfTV+mz zkw;&Ac*B^fj|PtW&7ao^f?GRpU#}7XdfnxGJR|hc-eCJ*|9G+LIlG&2l2;nq?lrtD zU&OtD^DwQ5kaju^H_fLpXWPAACrY9W$&7azGN3HUmswzKblQPqd#>$3l*WW8C~$|p z;n1|w}=DTNZvW+|{)pP{2B#%(AtDJa>CnLrIzyfXhIZO+CxYS`vZZY(S~P zdC~3YI+PjX0?MjlYH2}8h0BUD1dH-^N%7%BOZ#{gCH=OcPD5GPR>Rj6O3Iou74}v`SUj zv;)_3bUn?k=6MlDXVWm5tVngYnunLSi}~F$NiUXFdUJa>dwY^aw&{1=rtJj&u-9v8 z2-j83g$#hG3tZZ+VN^w4axQpXo2I6#h}7$Nv4rx*w&!Sw5JoMl)mBka5<-Y=H+@O0 z6V6+KYblV>0yD0u0OS=W29jk?49#<8nNcAe+q5(t$+#*oAyrCiRZ$@!T)1Yl4J8N+ zHSimrB1;k%o`W%=hH9CVW@SYvRgvq~bza%JWmXlT5>Sz@30_u&Ns^%o5hu$SN{rMtM;~*;Lzpk)Piw&@wFDP~Ux$0q31Y%a`S%T&1Qu z>TsTwd6}21cp5LVRW=MZH%zm}*JpP#4Pk2Qwkb(v6(wPwVJIh+3R{kEo4TnXnNUm} zLsg)(NGpP=p-{S7Uz}Z@MoU%onucZBt!BRyc$}@G@pQVN6_jmzIOuhY{A^s8MJ9w{ zs0ywrg_3R#u($8DoI%> zONK6qyyBv+IR&7^MXf*uamEFql&XmHD5(e+uIajr;)-+5ivq!BtF9`Xm5wE`JZ=u0 zZk;ag#&<>GIMIaR_Fi%|S)SjqY!<;SG&R!at9M2W6D9;bN$p<`PnA(Rmsri(~d+HFOlBu*!5S#0lnjUuVAspX}L zBnin#UL-}{a4n0F>9VLCQ&Y?8a$#vgn#WaTXpDy$p*gm7&#f_Gl2ntL06@8h8m=q> zDR6|))WBC@UU8-%#^S<)_)r*mL^*I4&y6IFlqU2(1}qU4MVaweMzW z)@qto948r)B_T-=#M$j4j4j=<5L{B{zy(Xw8|f;JnRWu;?El8TDDsuj7a(^8VE+E5vb z(yB&K*Ib8@9H&K%b=7Y$dOEeWqJ$hN4W}$jJqUufq9WC48D2WUh2vPZX>UB%3={Dp zOlK+Vf_o#R#&bseuG3kZhs%xod01Dyop4enan|i*;e2N3g6}>&`tf3JYr9*G=HyO+ z`&*1ILjVkYF!=GKYba=Y<93>qRc-65IK#R!>SSeBsYsH3@$;**+qq*zy;_QQCZ$3KsqSJGfAW%@tHx)|bVz#=Q*QKE}`|V+s zWtnGJ_2oEAJDuH!q`DdtigAs%wj67@o`(u_Z79oFm+u|(kK&Ryei7TZMSe))|?Tl zAzhIHtM6Sq001BWNkl-QYX&}NoD&Kp1TY}xO0Cs%~ByWZRgSJ@1bOB51uf3cc*JF zfBxx1S{Ul~rqg(PVyLD*7`{J)GK9LaE+`)co%U?W_&VR|=IMt^72SkQduxdC?Ig#x z4y3%|oQuF&#%Y0IzqNN5hvUgCn#57A!oAJUe(~&gI4!f|3(7#`6&ISKtEwVI z%_PZGEz@-^1BjXepem+e+Ym0pk`Pu=-}1dQmn6sZJXOIsuL$AHbE^syE|6^Mx{g3x z7%Cx9K6qg$RgMs;%OZ`-2r$9(D2Wv%%j%>I8~xq`4V)aoC(f6@=Ir{|@j6@UNts)A zUE;Dml=$&$S#GsWJ6zPYBsE){+}^lWyE)puJjsheuRS<^4}hZFf3movRe`sM5Z=yo zr5}VDY)wrI3E0MFzpT!dY2CJmeMyY( z-cM|G81#cdx81F)%XdG1|Cghxc8#+3tj}NGf9hxl2cs>=34+~woBOu+*>8UN-yc5m zeLy!xqwYq3cdyD$>|SqckP1_H_o3RA`bFm>PaYz@i)0Kr|S z5$I}F6__$fK)K=TNJkP!FmP>45>>50L$@p_W1Ll46}T94E+io|#WHnm71<^i7&n8h zCpwB&MIpV^`no#c9p@P1A6k`BIj2)UYLSc3D)WI%;ok z`F@(5U*6n=(dEL{pC3MX)@%0rP9qIvIG?_L`{sB$$)mfg5APROtIPAZSEos`eK0)e zZW>mrJM0+>kTeZK0M0&Kez-eB^1+uo&o#m8Zm@}$JI z;LTwB&~tcg8@dKS!%MT85~8V=B}+BIgwvWp$azJ9P!U2%=0XOFLds@WhLQ$(z2<7GFv5n!q&!?e^9zM*H$!wJlT4`R@guQxpJ&p=P zd2$d(R})h$>IZv3djHeMD^q>E?>MV<;BIbWe0?jVouR2#cpBbBEt{~1_wKzAY%$9V z!b-e1c=eg4-(CxzCU4&zpXbT#JSv!|Syo6Q@CcbNj<3QbOq1p5hm&{l+;8r`@*0E9 zdoNizzFCA>Fa>!9ZCIMA7nLMQLK2i#RZ$gng*B+_3gWCN2~%Jc`7V(2 zOcFH_yxG!~8fT?onu-v{B`#|jm^zdRm4U87=s5EgV?iTLB~s<#>TVfjxKg0k=xw>a z%p}RSbWJc#?G60lcmE6z^d}F)scu=p@=~zQ(Dv6;P4Dd&>m(W-IIWvwgz|j%K^Cu< z-L`3RcKoR#y=EMa7d37Bjo|f>B+203gZD>wD+L|ye!2#r*BA~zo~vlH`{Ju_ztdGH z2kzsS|MV}bq@w!+-w#6w`#sJkvnb!}Syq(9IpuA8d-V8WXE?k1`kT8|H`v{32cu0= zzkB!YarpdNLk=`1rQYMu*+qoqLB5 zbZNbc3(gVHRKtQwFbrH*k-=m!UkNM;&quP%EfYw%2B6ipEWsA*x(u4SS{95^rYe>p zL{bQ0>8^!fO@O59oM%;(wS5(JnxtN)Dr~og!!qZ*s&y3rO{r_jF$KahRHY~jTvkyQ zxKLi_j2nsqT}RU}rtGiqDP4S2a~om_ZI@jH9Hg6$QagpHz8C8G^E0 zRyh_zL$;wHAvDD{5i-p@&ng9Gg~ZBSmZLPQ2m^u<(`b#Fy$^3V51Jbr4PTZy`NN-) zhDb$l9vSYw^tV|8#o2 z-0N-cogUwE-M!~tb2gsMZ>E#Q~_tCYc-rWD=@BAgrKHSM%X+lYfWqTn#wpPgC+pF3FPU5aT%<`pamgcPk zECV3RDpC~)B}q3nhQ;}8O}T58rD5!C%$B$=@ancEj=%A^-^ZwMUvF=Xq{z@?{6QSgoTQJ{;N+PZ&xk%XD`Orr(+Fec+|=A%UNJ| z+yD5Nx>n$$`^)*&q$EB6)z7cb=hLHOO;J&&@#MJ>-+cT1oAI9yjy zsxPj8_~XU-VsUpfzWC`!l6?B<@_jhzZa(xI+qzaVftLeoBs`s9>J9UApv{)rF8*J=8f%0l*+m02*wr$&-hUq#U4bqIVFe^(1 z7DbfE@@y3}IxWuDF)mfb(xwq%gN|)M>3RtyLKp==MT9CyQ!Nw0MdTQSa^^WDUgwTJ z&t0wG<{~W>2&9^*iX@e|z??(bv9^YBB1x3f+A>C)D!85tP6#etx7S^V*K-6E*yzOo0$`iFdqpmIO%$|T>N=xoX=znmRGNa&d_@?PO|9Q)G-dhIyD+HPD4f9JB;yjC0$Cie(Omq~5$wDne?qf0)OPZE;n-n+V|;&E{eW zfTMT(z5Um39Md(0_{)bBZ}{)tk7Hjy*qB_NjFHS3sV55+0nqV_a+NA@e`hjPVMX_P zl*|@c62tTao}PY+@`|?XpS|jAC5zjO@4n7UOcYes(^QcghNFA7 zs+?TNKnN~Ao%?_GeZzDb?a}Co;FFK~*J%o2Q69Y|KSFuX-#OelOxDx8rpwsr#nsLJ z-tNOj@aNFKJ3+u6C8aj{wm@S))(E#H( z0bqA`5#@M%*Yr0xAiwPGG8*rm@HEoMV$A7yA>v3 zV%z~B%aR1ZXe7%~tSbl-rXt_ZGFh$}XQpmhj84uTJj373*AV(XrG{mxa7W$h8V*u9 zefOQF$r6->SX{5y?e^ZYB97O73zzp^EiP|w0C@QF=2KmJo?)I{d$#X&`bWokZ72`# z>*n|GO=Z}dEW+GSUOf146=C1-tiQaEaA59ko?b8>ms?%iT1F+_Xgl_&Yb2Yh@0R7q zTNQr(%yG_6P9{j+YGiZjPh{R;MmdtX;C#?}xc##yJDa{c z+S=GuL9f$pS_WrHHe24@Dbj3w{u7S8_TyiVc3K@?P3My^&S%SH83en}{NVO7uOOU9 ztCeSNKNcmcSMi7Ia0Tjhw2rP9oGWlN>W@@Kmg1DMPRq9PJj#no2q+VpRfHHC=V`{d zX>dwNl$T}0QIHTonuey@@F2*`tg3KLR0R`VQ58ZPu46{2qt{dtu49{m*OUuY@f(_2 zR+!2_S9ERnU^xSlrWBRuwg+`ql}S|+RW=RV7HpLQAqfNx9e}J5qTQM<38Rcr-=nl9 z6$VmW6JqF^T4K(9&oE3~SCEX5WvW_{4i899uq+#fqGC$(6AIPsyxG>ej`==k5u>wc^ zl}Ro(x82?Gh4hLZ#KVpDa&t< z)@jQL>=!R3>HXVp-%$GE$%`+Cz4d%OySgc`h5~zg*zdU3;lqbtKKpMrp9G!JqyE8g zZ?M-Mb%&#^ZpYRXS(caUcbC`K=kHmBP-ka&Pi258uqNa6as~=j-Q3;WsEaTrj8^N( z;q&3}^1P_ya=G5$RF$Gc5R*Z#yD7K~(j>|_H4We6be_beEH!M$kiaU=3(G)o9kyGF z9HvQSsjiElrrazgu0Tx_JS~cvGF@>k+scYK*OkEcOdu6iR&uH!S!N6q#!Ow)B+eP- zP_~SA4=`DZvnV%^*FezHaltr}4XxGI)F=XgF%<=Ys)lh~+_9T&&()No$aC9jv^Z_{4JD4MN|pim{uKUp@ao@6Qvd1gYldYRsg$T1 z!42PXDLy-H_^aiE7m}DROTx8vgWx2uh~N#^c8WYJ7&A1^FfEC1l{l|5>>8G# zX=SyD!h&+a8POB~OcPhj*wp-%5N?Z+XjPL6lltfm-Z!6rmdxGG-I3`)q-sUl8UZ1M z?b*T2X%bu3tG`=a-JID@b9jDKRhEv>GBPyBlBB9qWJ}xM|8OjXuI}$0p8;vR_w3c> zIj)Djy8d+QTQ5K3?D87Qf#bP1cVYf`f4KAR-9~3?$8x7vlbMDF-84M)G}6?lzeTjL^N$EJK5uPH>c^6=ffc%JJa2?#C}7__%`Z6!(a5=saG2|@)Sq$<;Sr_*ez zaJnjURT*q@lH~=~Rli|qjFvS3zDr1nH3gF>W3}KwqO2k+Y-CADcy^<4dfxW? z!>emTAM7=|Z+>LV)ONRDzb73Y3i;6KwWblCK~emR(CoHGe&Gv za9I)@0MBi;fk-k0C82AsErS9VbzW7Ks;G!DNzzpWB_Rn}2Eeww2H zd|JhmbIXCS%q6KaSk3dIrW>Q{Tgq^~xxv}(#5US3N-pjUwcnA%a{2gi(EH=J3Vd*X zcKiCQsGmO&;^an>e)*N#{7?U&B1^BTpFT0(2|j!E_RZbu+9lj-^9;e#)pe$n*-1FRdYSAYCRgS`4*Tz6wQzri)<*AtL$KlZ#TP15tb zEN(b(=@fBtm=j{+H~9+=ee#$2@nrn z8M3G+>zlg=hn7X_C{y5Q$Mac*Yg~8QyvmH&gy1wT zYGSC8RAC`B#n4=L9U^F$xI(C?&Zf5J`^}Em$|6Q@Blzq7lg~N_jI3`JjnTnA0}gbHO@;piL@Gi_?aupho-Vf)L8{#P^#mT&B4oK$1jRmUS3O%=fEumQb!j*HVxS zR5`ST}f2g%{dpiw5`>6ITKt}=Tlwpjy}GbtRzWQ82NZ3#KCqF z&X$%j=%?{`=30;LPsX#grPby21b|*M2re%J`{}bHKfX+=C-?5X`ltV>p?f<}PNG%* z)l&qouGjgOFSZ{q##iIGdUo*e)t~?V<7Lm^=yP7=q}sp#@{8RU+3K7B^683@N6*~$ zAOH7%`9Ht^=O6y?=Fe|Ge!7_7UVM80dOk^43d+{&sjAwx@2N@@U*C=|$M3qst>;gF z)Aq|SOqSv0`{;c8*}>T)Hd)zWodd{t+hF4xHl zN$u8Z8D^NUYVVnI8?G2sHr zH8E5q7npJl0g#uyj^D_$0#nL`st}Bz3I$i73@`zpCWMwXA(AAxs(OCAxmZ@U0v)?M zX!dmNTzSn&H!#p0)i_gRPzCt(}uUfAgoa zyS?GCzj=86!`I);)+LS$6&jihFsaEhlR=a)e0F+yZRs2PPkuk#t>g7N$%}Gvsl(2` zsu#;DrI@n+Fd`whCvnblDvUHeH_2 z()E*rkA_)4Ump=kjznc|||>u*AGF~iui??3K$s(iT&?;MBG zIEzbJ_@1s1qQX|g^K?x`vZO#&(KUpC$STf(=nTBz=5mn&fPiTjTAVQ^fu$x}v9k2%pB3pk_T5(d_*6x$&du4;g`|JQTCf(e|#S%TzvL?dUtjW=JMiAu^#O1-LsTD zPqNAN;zWVnUEc$g(F%`m=BJ9V1JhC@O3o*+woRl4{W`vw%2b7}znBzdQdD^Fz-bsL zOP8649Cu?YXdGXyV@Nwa$7^`)7NCo@s2i=Im#%LnbMk$n639oPtBuX#=l8PXdB>-&QHUU72Zj^ae zsz?SE(NMpmtLwBP4NC@sNs{1mHEiH@4&YZY!EQUbN0~86<_J zhlzsPP1}i9cT?ZVG8yPvfAjp*G5~0|SBo%FkfzL*g!FrNw-xrC2T!Zw=%c1QdU<}5 z7EO2e-nTy(s$)KQKEIo;9P`WH$><;cBj>w2HC{)(Zs12z5(57Ar?l8;KYFydy}3NT z=rvz`{@efI=@&14+1+GyFc>|uz5ZU%JNT^G-rO2=&o3ZkEDYB(Bp-rt}3{eM3P&EWjI!nmn9{Gp>5nPi#jW^V$?IWqRgvhh)V@x zoRwTqRuTwYOP15TW=O88Bt;OR3g?(HP2t>c2%#!9F*G6aLf6tPt11G3rE6+gwp&q* z>#{QR?R!r1>#yOV@yq{;lTUvtQd%4K)iEWCs%p5poea9oR%^Jpsd2OGwW{p$R0fQx zilzd|Z`{pm5_nmBeFMS9@NQn=tWf2Pv7tg)SF?;UT`jAuY&eEKooh2rGNR)|LN~9k8Y0s@~5-67w>7d9Mifi?%j8-s$7JNC|re;#l_ac z?$A<}%d4w=ZrQ=Gzm-n2yuevvqt2dfxn{JQuhUc&olV=QlF8cCw)grwlc?zd001BW zNkla07|ki?TLi~GYY zS!a|6UT;HF>MBfy@EeX*R)nZXmX|99X)2{9G1OkC+syK;(vWRA4g!qn8iK8EnF1-t zIUY16iL$haN?c2f&UsF{T$-1tpgm4~Z zIc6L|$FxjYR#hmwjwEzFXvy&VAK;6|um9V8@%EqViZjPQIns4fJB=(UOW$t~{NDVU zQdRTX>&fvct}L@ZDsvh12J?AQH{J0huX-)lTZfW_P+hN56%Bea2qPgpcNx~S?N6r5 z#ME|n^W<{eb~iSP^<(c zBphdXfva#5v>*Jc+bP4#o8u23e;V{v#W75cvAc14+uI#JFyLysh*zs>J=ocQOk>X9 zy#;vd(04WI=z1Lj-0mwpOwy8;{n31m>$EhHZ4=BGf`r6HoHZTOZZvRNRF6MH5-D>` zYhBe1O|7b$G~7nj(Pt{8hyIXs;0M26mFLAu>TWR!5BK(7{_}rW#(DYj^X~rLhd=yb5j}tM z^h?1%9`&0qUflcg=-Z(2{I|0FPyg4u_h}YqQQi;sMvkSx&Czf)+M3+1;&rT{_5AK4 zS$M(DgI-&ZIL(XMO|c02?E%ZfI4R%0d-3w{bI4_BxxN~g3kCG{5mThHoGct|cyG8n zy@c}httuY>a(RQKC@;&6(W5WZDaNbBGoOFu+tcaQqV0Ol)hy224MNIVlL@x$8rLlMtA;yUCOIa)+usV8 z)0HG~Zfeb-EC?-0QTx`;R<|oLN=kxc+t5`gYbYuRYkLp^$u>$H7M$R+#&H5=j9o`? zAxdoNtp;OpAqmIUb+^Ij)s z;c`5irkSDO>f#2<8zWVF_p#sJdvyM(-wK*}>RQcamY(0Ku+^r-P=$E#^75pvJ3*)W z?%cOb?QULFI~zdyc)s23^{>ZJE-K5o9tZAtd9eNdB&{Cr9=)wR1NJNM3o&2=1`Mp>^-98OE$vF0pqUYy zq1jD#cXj2eJI8;{=^Q_p2iKeUUHIVJ=|26vcmMG5kKXxm?>4#u<2t4{nWj#6Z|5QM$8(XrI1iWg&d~?%%=PE%%d?vD-k(>io6&SrBo&RM zjjFRw(kzq3qYs^#%&qJ)rlBOc&c+icP3sgT!hb2NNiYuz^=OqOL z=j0t6+g^!^LY3={yGe;?GDtdgl5$;^0k|kBk|H^_qJt9PG$#pxQ)HeEV}z0{&moNB zD7D=zr$|Lq<=3|rS>U#MwT52v?6Rm-vlQdr{#P%^E%Jj;11kwT2U>T1Yp!YynyK|h zR{*nYv)_I2`qx3&Y~1_!+h<8y(Vl$r)vsB))dVO{YW4NX3tRO@=esu|SCqBN)oqCc zuGZYl2_Q>xw6s}D7KRH9_IBcExv8j))@WRmkN{}1E{el#MH@~q9`yI#efG1tCG(&B zBn@AEML>)nKfV6e_m*b2e()&RTtENf%jrsBceVjO-2dn&zw>YOnp)L5kjR46!zCp0 z1Yo1veKE2^tuQ$^XSvIyqyVpbI?e*YTQ5h-?P0x2!wb4w2%lX+wQ)%sZ%gbq&R`fKnLYZ&1 z(!>iGA`a(sKMX<&YZY9qHnv}+1SSB+whs};K_qZA9mj4!5{8CRl8}TV4fbnB8ZBIe zsv1q?g&!3;4JFxi!X(KBM$<@4lO#kqOUAQD4+TC7tsuz(B1wv*C{#kgF#-o+niWM- z@C-wzd7L6t;v|;^H*kD`Y1ILC+&E;YC`9FE?YImhDVLYz$Bm!LJS>9 z65ZR|x&Q4yjb;pe|0HnE&ev8|`{Vz%$bRuxpTG2yPNiNWi4T7N@DsIV?0)m_FTS~X z@#TMBUcC7E=;iwQ`o;CD@#)2vyHA??)kYpVPLg@yX#C;tfI<=4l`MOGdiMrJ$L~&V z(=5rpdwuWZ`~Q_YvTX=gt7O?e5Cm%$Mp?RHs{OrtFKQU>&=Q`Ef*F;Y#-LD z_A1I&3nG8;ey~|OHT|6r=;C^sCwu!G^Xlw+ST{(*4T3b0eF8$Xe?JQ?w?s>aCaS(+GMroSmEDbPCkpxLV2p~ytwB?s&fixL{Bz42Q;Fu`VbdJ|` zUhv)9Df!dwkN@S_FO#^|i5zbX%nz*=<4e;NE{#3I-mbMP6wUczAAZoNk{L}RG`PL|I&^5_n}7`SBq~dqEO4+O>8O`2ol9 zJOH@Na-LTd)556JuQfc|4Kzg*U2hd+F$E=2;VW9BU2FSxmJtL-{cT>DPcg_#hLnXc zE)h*R5eaRFgcOBJ05C=f08M3>Fmxk?iZV>|LJ{LMD;Sz45oTyznVJGaz%)k)0FDjf zFq&;Bz%sQ~;JtqPdQHBg9iGfDYMu7c`gVHfc^oH76t$RO-0EvhXFj>bxY>1Afz@hC zVzqhpwnVxT_(k5`8eV&0r={pG&QuWX9D`}p*=o3xDi3gf-Oiu%zHARJx2 zJ|~Fx?)~sDIuFY{^?&hyfBtN~2Dzd{5eZj|gL{L+M?YyDlBinm?P$Vyx-($di??O@ z{tpLxp(O}cce81&+H5CL5R2?$Rn=)m=3ue0?=DsT|!MYEYiE1RcP0~f9bfl;YfeK$yWy3vHda*{~Z;*f;4pXD;w z-Wgr{F#r%$G?o@PjHh;qAmnI-{KyIYq$n9GOL-2XB&A4_2of(*1&oU_$r0ihj=`9v z5H3-ib!rId+QQ_Ryky9-Z1uHjV2w@k`>lfqxUBC$Vstv6K}eE{mPAEH5R%NWFMe%1 z9M|99Op};pYfYM+jC$?Bo6c3GNT0pZB~@O`R*u5&?`BDot=-*iYjrnc>1OTvra+yV zX+zkkt~XVcV+1~mFlshjFUe{~ckt|U0`knk$!~teF{-@x;N`OD@eZ%f2bkwY^_?_9qv3MVwJiuT@*c6VX6v4$fGKKxLZ9n1Dt^Je|whq^o&`*9Y- zVE03bA6~lQbVldhz2!K|ua`LP_6NshG+X1O(bem?JiqYmc2{plw(GcFqd`L3F_d~Q z@o;%H-s!alo9W#m3yn&%b9wEC2YXuw)}kn6k!5Yy^9iI^vShwtseA9M+;kQu0z(k4 zzp`RqQAl!W<|RkA`_9VpvNFzbi803#L>O~4!Zb+|5CWWJ2(xsS6Cf}AC@ml$2>@ii zQ4u*m!nkfoQV=O(n(?e6)T)z(Dy8YfW+@W-k*>6Mar*T+`DttSSkzH@_wDF5j5Lko zjQVnlagsow=-+$|Aw##izB3#XpwYRzw4GXIy$NDf&hxds-ya;Go-!naC-;|&dZnT& z+UeUQGvqk1eT6r)`KG4Ql;^8*t>(H2bBb>hd*_Z#{ zo6qN0lQ*w_^XBElcX#%iHC))P>)Gq^^&kIt0ts`PjHBf!i>fWxl6cc`*H1pv<;bPT z=P!Qn$Ab^BYsee(`~o=b{lVeQsUnocX7Rlrm4WRRMcruc@_giM?9Ac#tw&_?&FOkv zuhe@t7ZcMEo89GNvZxz+)iD<~ig`wovM9*}w$gMq01x)m8pu%@hDIezOfOA!jex5S z1ikI<@$@`SY0@wZEs6bzr70>+iV^~lb6lPZ3<3Q(NNAF#5CR~{F`_9$SLHHKa|j@e zQ-lea6$r5uNAs+v3IZ+xU}%yAILm2@V--1y7FI<;D2Q9Sp;h$Gj#A@u%5_*+W+LnR*HeJnom!Jc!=>vmWoKU!&d$$9qw8qV z=%Q$5F2?)EJNy3XyMYljia`rCPeOLGojkuNvhuIqSV zlJPXp7db<#S{ANm1T0IEkmM+g(j;Lho=vhWUv0W=nshw?yrjf6rCt-*vMh=c11t$V zAB294afy<=qVziyOml=vOc7ZMA;)F;+D=ndPEvt)JOCVDU@Q7!!%_?lfT7d$YKYO* z6?r7|8}715C!?iZQMdPsEDg`k>(xBxIa&Vlt0aSvqg-dYCLl-7mPJ944CA^<>IOww zH)>7Sl7;X6)HA<56Ic>bMvDAQvUuI z0(J5PBFFXviEi#OU^U&?;kwokNLw4T3`;|m*sE`@NzA&Mr%2$ zDoM67v!K5%GOicdTSu}GTCRU|PoOPlV|LoD9?WO!9rT^?g;#HofnG4vVLd=5JW*yB-zYGSmr3AqBG2R zLBPCJMF2)~j4Mi(JCPyPh$pVKEz${ai{jK@J4j~9*o{i!X&8(`*u@or@X(|dl zN0Kay5W_B~+Rsl*M@E#=7Wu z2$5u2rg=q+qd4K1_0)46AAo*042P?OhJ8yBx; ztIz((nmqfD7q=Y4Q0=x+>FpgpegBWTyGrFJ|NY5(GP%{tvn*Y%La$6!L)X9f?tAYp z=XY;^|9@z1efyh=YFe<=jKh0G`R3FcwFZsWY?SA(ze?T12i^w4vb5}aZSNRnvsD~Q z%;0@88;vM3ODc8O4C7X9Zo0vCuhpMVZMR<4>VbJREyBHH3QU%v```mvo{h^g_xp#j z7styvP3d|ZMiI}`M3x>tW+{|KiNM6M<1Zbaj4bhj9uJNvaYz~MQzl5zbH{zsjcQLHyV=zcF>L^tvVeVIz^R5nyl6U6s5%P48~)G1ditb7_T7g zH`kUG=t8%7JA+u2(~M{DJv@C&5TbB)$I%D@u(xZOMMl7#-t{m@yS1_~y{d*vj%hZM z#Pm42QJ>5J-W`bY-7Q07Ac?4?srNs#mr0yuCr{EaO&tHjA4cwA$G2;BS$pxDAbRqk zdpLZvSv6`~#~06EoTmBV;Qo{M|LorHwvNw!;mp$DSO4+mi?e4GdH9j46{%w@^6lN_ zrOfa4Ei=#aeDqq=w+_cw0*_D{H+t=XIX$~R`>v|1%FSqD<6M<@k6dfKY8nhx>-CTP z#Wy!ZQZ?jCWW{k&8iu0Y+yQJTMKPU`s9sN#H>aA|=p@c`(`(W6X5&RX&if zM3E*lh`zWY`%FV(+0I_(L&$OzWtmwnaFWnzx3+Ju01yRDEsDuT zdbOTRX#r2nSDeeR7*+t4$HryCj~@<_=Zdf64+~biC>8-s4J5qBQ;D(pmDXBs(jb z^f#io_xS1!##yp`w3P%I3mf=uCxf4 zgmJ8@t?kq^-LfE{rZG$sSuVg;T@dnY#~l#1+j=tVWH*^Z-?RgwGK zcXu-1ZU#Y|bZYmWeD_A?>$UO7iU`m!D#qICw!`pdMw1m|xz2KcPYx$jk(I^8Cd~*i zSrKrjzuI_lP1`#eT}@UrRW)oE!dkV=eJ_eQHjYTrboTcbli_r}Y}I!k&aO?f)82b; zdj8cn7$4oAT)w?b^9LtS{y=Je^>6?4zw32R-jj?Z6ou6i<1ikrYns5t!S=n#9?k>~ zph^{$NviO1Y)@*PS~KxSbJx>FmiKKM)~h6Z@B^djuf4!q?>#*D;Q247o4VmUz5RCM z@(PupIQY;WI^NP$_^pApj^bLiX4r0;8M-3QH_oQfNP^oXOP)M&HyE3)zzRZ^jb{v0 zbbu|}cRD*eCn$8>I1^aCDvEjRge)aVvXsYGnCCn#iXJ%mcNhDcO z##x;IHk}Euu4P#mXE^{IEpi-35)g1qMHP932||`cfq+F}`C(}LC8}x&Q6x<%5&&sd zlmhDoG*uLN{_5HbP=321-_d^Z$F-fy=UED2rDdImITcWBqS@KMhR}|NSP?6@Qz|rK| z#h_K2E`wBHI-SvNlG0?YvN9p)bX*7Hyr|cLuv!VjX8W6O8LHQM=Lge^FTOfDeDXtU z`t@&;ba$(@{moaFf6)KIzhZ>TUw-j(KdKmye@|H?ZwH5qC{k-P2g5vQFJAVR||jD*>AM{^~#*z)$1rF$|Oya!BJ!P z_H~?w0aG4*=r3*8bDn%UzunlHvbC24mMd_rj_=;Cs^a$EY7r&fwo$=_RsfD;(}p035E7V1^X@J$ zL|zb98&wj;^XsfI)a%P66FG_;O=)tw!!WBgP0`fGfl99s{WdZ2JJGpu8M$=>0zw zm>1u=A(^#y+MU^5mai5MJ`#9);RFnB^=@uAcCS;d-`uY3UI(B&W2nIiS(tVj9zMzA zI85_KO_UWS3Vgrbl$6Lb?Z8xZqqdnR8G$)gtIQ@=rEI)5=LvYEVDutYZ^cpundGG!7wZfaF&ND300Y*P+6A04bbMfA6l*-XiA!hY)x;} zL_rh@A_xVZVMHNGFvw(Uf?}Xmhx<};^@7>`AtoOFpl0#4RL>ev!1Lp$#P7OW7-YP`0gq%`}HLA zB3-W6Zzj4FCvKFZR%N^rSyimpuJ7^!gTcVDD6(3?IE?c`l@VeYgb1jJ40-sF6JLEP zun)f%yI*~g7YBy`oW1eFdUf!~8UOuXxj{vJ=XBFn1rc#-9u+#Ic|vZRwwbZG)VJ&yC+L!Io&|q?=y51g_$nW zwCnp(p2SfYTY;a{wQe`hqJ$zL%<~|0yrN)e0%8DAtPP#B)A7>N1X+51d9>}imftk0HQ(hqh9=1<;+gx8%@qOeJ<4K+su{g)hTANX zyjMS)#Cf}NH&OV(P85dmUdM9RJ_HXA(j-sI@~6LlbI!2<7{+2Da4fSmV3;(GVw$=g zAMEeFcl&ZNBZ&Ua@@}(i*LUxYE+o-*9=*H$^k@HPkqi7!{=7C| zYOBS~?ZMIU$KJyChvScaT;_|JA5!q(9cP(mwv)IAkISemZ1|2VTL1tc07*naRKJKD z%{cTTkt_24wz&=>k_>!N(Bvp2U>IqN?dAFI;QSVY5*d=J?jGe4L68In3tM0XZsUqv zv$}BtzumTNFQmwuS)<|yc7U<%wHq`g@NvSjt2IJASC(agOP;5xFw(X5cCBYLC>r3` zr{p7L(7k+vG0W~hu@_gj1k_c}2_v5AcT79Ysv6I&RsdI2*9#L>aQq;tX$Z%er@6=T*KZK2RqI=cdwSh6s?|y-G_#ChR9&lFUd}9u zm4xNSw{gZYWiAS8MPO`uF&62;qpR0tnK;#^Z)aH$N}N^=+|#@Drmi=7i|NWKihjS@ z_N*`=36bmc1NVA~P)+acq`|9El0wYTh8jgYLlJ3C5m_1srj1dW`=OTrEb#=fcD+Cm zAoM&{S(-u8(p4qTO+PD(GEKa|^}{$#1rFn)ED=ettSBp5tCK{&Ly?s(FDK#8z9b(h z{nmOVNeDIj!}BE8mEP9nH9=_d@#EDj$&QZ+BJfqITAeI3QQ*ReCfg0y4P%C87}rPT zZokZ@i>zoEH{%jP?0b&Ovk-6$#&NDmmKP+7U^~MNM{(@R!MIiR+?DCYt(xa~0fd@5 zU&e8s6`ALoR)6cwnI?bmCtv@=#;#Y6-n%)CV}X0{;qB>k!O(y4zhu$h{2yn-LI3yu zCjhU0^~-hsOy`t|M0;dh(m)8BdU-p)W%vLs0;ieVv&6F0~bj>9NU(j;;kTRdm4 zL_V?n1BC+Io-hJp1NWqz*nHf+Dv!^;Yk|S)AXw z>wE9Tb`q1s?w;$oApy4bJo|Q(_?6mx?uA8MZ<#X!T28$V@NAJ46yUh^a^-jl54I0I z(+}KOq>WnW#c7nVUwarmwQKT#jO9(c8kSKzt)$0tE#0aNZ9Ahl-S)LYY;U+BE zs$pb@Wl0jYUo#-K1B56TL;%y2z!oJ%Va(7)$uK0ru@qUB7^`|~z)K{F%PcK3lA`Dr zFUXH-omN>81VP|pJY;A^**<>x5+Rn}zrUVfq$+|mpNRs;-OUt{W%68?YxUc4kkBN{ z_)%S})rLcaDvG9^j}+bsY){}AI!ZO!38HMbZ`w3juP)YMde~>#w^NbX>dqE33xM72 zvdB_h>kaG;ggjRiS%$&>@nlHA{`T36IOW*h-sww0Xf*fUfBh^@o3%>q=Edc8O?&rK zQG5Q^FP}Bru46f(FgOBuv!>u?I=l0nG@UI+vm{dFEL*x^qRYF7`^N&mm}P-lefY`Z zCP_SV?~$sm=F@2zwFYT$c@qUPr`2Y6cPoFUaP32?oX^v!)!%KOnzUKx}64V-5T$YYU6H!cpI4|>x!m_?= zhfxG_Nh&fg@)H^>3P6*z_p;q;tgR9R7c(+dz1l`KMtB1w`UZ?Dq4)vOQBetC5kC%4z4Sd^>H>C0EI z{BU@4etvPYS~Eb5G<(^Jeey zBS}~-W%+1}BxYly+3o-^T#^()05Dnl?#W|GF#R}|L`9?tFTT5`8HQH4C|#M2POHgK zb;a=sqS*-30x4qEpy<4yNS2PXI8ro7@LY+~Jjnql3J3{ElL{B-m(w`j?r+yi1b`b9 z`PSBM9U*}gIgTNT5@Ae{G(`}8;sl-#fGE(^#(eW)F**P4;_b%rg86KI=cQx=G&PQc zP}aVCZ3i@&=e}cl0M=9rP8UUiQKd2*k_5xVF~=~>Vq>TTu{H&+s>ex`mZ;kuPRtOZ zG>x;G4j}})yYqRH9q-Q;szef_B}Yrb+X+eBKQh;*W61r%Vk~g&mMC9e`w_-0HCtpE z%d9s%yFD1)0>H5Zux*y@?Q9ml-|2MrCuhSUgoC|G_nXhN;_y(ZzWvg&Wl55re81a0 ze*E}{C-3YYWPYVW!Zb@#hOReAV!9aYHrl)Q2sj_+0ZE2-;QQWsxcdO5zIS^ElWLU! zX^IMpCJB-x2nyCZI*-dN?Hxj5H8iaxtyR0nhihEb*RSl*cF4*6o$R zZ9Iw740BT=2t=M?8V%QVLY~c1QRH}v3`2}*N)ZuaXhZw$GKjGz*6Olcrb$Xuw#~Cg zC*v_qRWwN;iM)W2WmuYkxQ6a@*_4$qoSUP`>{xuM9_s!KCSM6OmDO_N*|oFFeH z&h`jGkvxy1yWR1WrdTG5IHqC*9t6E6N#4y^s?%A_0H8=zF4u-C@S-%CM~TQ~*});p z*(S@1BF5t>MH$9wLBK|P`|;O5i(*;)@Q;4=mr?xS`}Mc4(!AS#@>z99smJc^ zi`7u6-1`xMRE-3#Tb7NcQ6tb~l7y-b!0n~85k)~RlG_O?ti}7kH@PUwwYh&J%W>#> zqM+(!5r(n9^N<&Ymv3)%MsEt@=!T+5P-*1>E&-sB-Xb#JAwi{9=5H=-r>+(GY{9dF zXjE6rDBd0rAPOvZu&d~4w6X{^IFiNj)C+m0-HC%uK;!*mo_9pH|?jIb_}L>yA2q5D2T#A%we+V%!v zg5Y@oAP8d!^MW9D2NY430B{_`Cb1vnMG!NzCIJv7k}$W(ca(ekcSBiZSaX9B$DG`M z_C}-?;nCB(>pK&Iqn*)$p*Y6ST))@eSP;_GbmPPfsVT#SpEflJZWl7Q+ub+_Ytq6d zi6jbRmQm!5$uS5O1wxvN3NMm5S)I=narbCF3qn62006CKSt7LDuynm@*#bA4lqE?D zBFB4fuh-q*%+eGUTPLr-&^1YV@FRN&5CoF+v%f70L*3rp`{?ifx7W{{RT4S&-8l+9 zQ&1!|a2D$*ATUWft{*6(QZbjVM*>uYL7tsYy?`&7rgin2$PxP$a%%dlCy_>`8p5-#v&egdDrox7SV} zQd%|igNOnEd7i{eQfDB@>)FO#*sV%Mj{?*0w@{gD0ZjOsf?Lf=Jf{ zL6M`7p%LQQN(G@Pwq4f^{V0x8iozJ7Gy_1D4CA{y@=)m3MB(6(v)*hL-d>v|m#efW zQLix`M=4M54?^FM4dvcrfpVNAg>b98+&GEKE7H=+O9JfgIu-;pdAH%{ov!P3Y9IdK z^z`K5^2P~w`_pBV?)Dvb;{f=*Psg{j&2De^!SiPvn`RYbzQU#BbvmxwYxnm=ZoR^o zqFhfBF)oYc%FwNiA4t;H@!2;UOXM4!w_mR}Pd*aV^KU2Cp!4wi=f62S^TM)-sJ!n-j2N>yc|FMV6%`!lBl*;)3TH#qplhpJzwyQp*FWRiy(-T$Pz@J@&XE= z@_J|nk#}%{N}_aw%d72Pb8vfFQIn9u2k+jTTJCbVbEGPHJedgm$)nI64f7C{qnYCe z7SE9|iU2AKHyABy+QSd8&s`5^&F#%JNvhgfFT`Q77Wd( zZa?-H1fE$0oX#6n)6R+l0Zc-I$O}a>9YbEa9F2;+u!FozOEWHVqCCELbLaRax?T30 zEL#?n1p$l-O%(;llxVp!?I6wzgo+}~N>n#wA&do!%GgMy2ah|6|n&+t~76_pvs2L1>uq%iZX?qVITwEfAv1ct80FdNw&-Y9_ z$p}&uixNU}L{kWHT;xpV0I=fX+6$}F_C87b4n+YFC0W+3vFzP=X-mB87_Ea70BXwV z%ll6>?Zumy|7=vcJ&O9rzt7WV|I?=gWLQCc|97_s9Lw>(1Ay&Iil|i7ew8Hhv~xg` zW!b1)yr8*9kFz|EM;B$@+ak%E`S9%MlTMFe&M!$y6qnZNS*>X(BDb_SPE#%K^41S@ znSkp}5;p2dc6L!@EDJzgusm698uR63wwylsBnT<;aE-z!^?9&i#kmM<;vl?w=e9Vpar6zou$5Ns$c0(g-kw9>@!F@F5$d!K#slkQf{5ZJYw=VxDMX|I!H z!?~zx6^4pqPSC2`CqeS;b7%eJ#~**>I{)yO!&h4;yL;d6IT`qDV<@I{-+$9R!h~ z*VHug?MfX0)1O{7Iu%vr5H5?|y(}-v@iYmFA}c6zGNPD!A5}EppWMEAWzDMf!);wi zi~0KS#;t`%ioA`Ae}>zc0Vl0ain6h+Z$H!2D*3u&I`7}Xjiv9P@$ z%aaV_G|LJASej)B_*)wY07Fw0glSHaDns_@qwe4!PuC_(=Q+<_%yQJ$AAfH?q$r9! zd{E?<*HxLObp7_?YD$p`@0uG^6goRawpts zs6kM!ofSwenk>-qN$^KO&{Gf8f%k)f?!&4QmwAmL2PJAk{7bL zwRd+diQ6ZkdpDBBtv%NSSdz5L-6caEKG55*el?ls%8&l=y?=4}Y%Sc|DiRsoh+`^iWDP>Z4UyQA*XAOF*L_> zW0sV}IPqKp00gk>Jp2G>n~lh2$>1mp0d~XG-#wU4B|eCVZ1)|WzP@mM0?wz8KFXsk zNwX-eDx#9bei&sC#;M5ZS{PznB8H;KAS4M{D)TgluwKQOVan2vBtA+!k7F6S$g`p> zSz435@V7FUV=>6{yht;GARtMU$cuQ!3J5P(Rgwxrj*inPWm%D_3M7%mBpD}b2jk_$ zPh>I6%VM>GfM>Ky7WbdsB{FCrD+NPniM#OkvWoFSxaj?Ub`g{1usOH zAP^>CP0O?KGRYt`$Ffi}42@>8Vr>>B#wDjRfBDTfQDmCG{wKBa@n?CF77P3I>R`7b3&M-P z9o+BKfA+WMZwUfph0lx4Ds)7#SydGPwC+d$(rCT^!yrZc4)Vedp1*$ncSfgHO*2i+a#jojj@4xV zzWi=E+unhYr69;l(3kk}NM#R@na3JiAH~O^!1^ z;W(*rj00qL649n2F1B@BEQL8jD#+Vmak*2fUvy*_L zDixNuR%=_UVU%WN$w}@C0Lx#Pc^bHGxL9v&JGgjbE$g+dDugA@^TU0HvDO5ss!p(R zY^&Md?h=q7d~5Fk09m#iPhOt=a(=Bg?j73x%j?xls%Dug0dV?tWN+V>B!-@k)z<#I zd)rw)zTuURz7OHeI?>H;s?Cn{#uW2kp5U2lq@nQ0q_V)X`Z(c230PY`Tndh<0gU3q6T(A_+ z>juW_O;!l3ESfe;x0{29q2t*>z)+F<_M9X{-t>~(3Y$91L=nLKUYcY@Rrdml*xli| zEZx~ZTl7p zU607xN8x6(c3fR?*3-Evl0>r=ds&?2?PjI5nR;OyMX@Bfp&dX(kzooDNmzamHtQVg z`(9A1)Vj{n4g9#FNJ<=}*>ECKwPxUuz>4#*)gpoI3jEcuUg1SlI-V|)1S;D-SWY$q zt4Y-g!;~dK1ObE)01R=KV`LZNzx9+*YE%7b|;A4;MKEcUst{O^*0Q!$h)1Jb%|6(U?nauG_|R-jIQgF6(#Y} zyAb9D&BXp-pP?{#_Bq2f+X63e|M06K-|B6*k6KZhMDKpK(=UoRo6hcTb`E>>5?xFY z%Co^izrs>MRF<-eknM1cE|%Dd5Mt=O@H|zU%m66S-BQrI_!tCg%^ z8BNg?Mbh6?VC$k>JO^DXTK&0Lpi+v{Ds7+l5WhFhO*sZ+2JJ354HsHYFN|5 zVCA-TS$cj}*N*PLeq)Cs%fjV~BJ)BKMPX&pBuxU0N>Rk4aspD?#4R4EL|1eLNOHuHAgz9z2vRv=~XX(9~WXldKy}gh3E`4TY zmalvJ_BHL$Km*_mIieYfqCyXP(8K&Wg(CE#P)H#$MjDPt4nVRA(`bKP`Kt7J@_4_` zHhO@5##-Ns^<}R4?B~JbeCL__wWe+Ns#u{>Hww#&Bg11{h5M>tNLD5%U;m-woP9=0 zlCOfJNmcE`ws`SxEV-?goB0o){Z$o)f#=R|jz7$U@89dn{o9vc6yY{#8(W>884_;7 z`13z+5>;63Z1v>Bbl=uVIT`FD4%SGOAnf;!o_ziNVUOdwLz%;f5!1%)<((p6;uA(4Er1>Nv6H`JvT`W9b?CFyOz6Mu6F!@ zv!pO+%qgGnA&jjr53CaEe{6=NJ1$F3XfIqv8zkJsC$&x5rnjwWqW7lTojGBy|% z+5N`SFlviupDpjIrmT5*&~MSnL8m{vxVvhR=XMS*UsD=Kx_bEPU;j%}*~;wI>XK*u zzM@94raG>o=TVYEAYh)?R8f>9)1JK`VVa4;a6Em|CJ>bA^dgVSyg?*CxL|D%?ES;z zJjO^7)2!n#hDn%7f@P{&l>kuJuEPsgw`FPRy-Ab!Nr?=}>o$chQ!4QNk*?K+D$9~- zFdF%&*@VN+KJdJe3H7p4Y7kN~?Mw zVJz@}^pD80D4M1ssal?eQ541*1YNH`)OFnu#HQM9uC`o>!$cNDe&|BzN0@&8kcb?AyxS!5Le0Qj4%oCo)h*o3jr2sgNAeb5ef><p6xl$&}W0u;qDyw;WaBIK!-K zLfW=ztD-@e;1(f5%dD(L0f6lqwEzr9f>7oNA>8w_;{JB~a6E&sX|IAMe{xV)Y{aDu^Jbf`9rrEb&GJ5nRDO%j3laEJ-tM&ck zo8RMxka^%bykL(EQ`a}!G8vs{8pfAblpH;uj^k{m=iiWY(g5wNb6a>C$lLEC>SrkdJS|^dNyN+d0#`BtD>6Wg@7^f)! zs@ft#@^Tw824S9;IU$UprbQ5PkfSWCMM0GgCZ;9uL;KZFKmG4<+hYGglw~amG46L> zyh@|hMiy036#YFWWgF$eIxoT`$p}^?Ox95l5C$P3>up*!ZQJIBB3im4*Dc2bfLcRU z4Mi-FEXNrK8N&n-NfLz$F(!x{M`?=+6vknIF$e9g>v+y!3ZbehiYzLc^v5_u$9;^7 zN)Qw+&oP1U_?c;VgKqC)eEP&PlKkr3PyTAu)0Gm1(RjGn-8_8veWzbHNw&Iu@=H~z zs=N6={l}MorYeuyfBuiEDT<4^KX<$&`}XSnw}SNiJkGxPW^*$*nNIWS+jrmo&v^@v@Y|!Dxzc=&Ttn7 zN#xeM$xxC-uF2orSehh0`2-~##rW{T>)qe%wzK25DoV&^CzI3fzg@*NACCIdVy{Yu ze)^GVKHNO4K-f8u_#$ZAwU_|LafDD-)E;DT=CboFJg4YD8Y( zJDwzQoGe2qh>_01a3C9yWxsp)Qo0U_wJo66Ve}DU+q$aD4R`g z9tB?D1|3CS?y{PP9qa3>sP1ZKN4G0X4|8$MyPq-!!~#;A1izE|&n9`rSPT@;pk%MG0aM1M>iLpOcN0L}n5MnIwRh#6JBnhbHc!VfTVnHaYs;n#2Vq912 z=Za2>m;nIc@iU%}B7Z~47k?p$Nw9neIm3zL_g~FlJDy{0=DMXw zd3FC*u`Zq&Dxr*NPIt6eU*2ZP^rP|du=n)D@=&Q6emM8<-Y5p8Vf3&6eDxcv!*g|; z7LxS*^x{Ai(#*3h!!rbKx9E0zt}J2#z^k8#q9`P(J9fK8rEC5&*e2m*GVaC6k6#h& zxr(ewVY0quwAWK*2&3%HAHvP3s|bW5TqBO_56+GZB`Vf&QsjBt3Or>&ae4o6jgiyU zl%k2#20y;!xs7S}BvXX=?2JrlhHUhw8dO#aT zH;w*qw`1(pCq;}<*D-YgKKtNt8RU?iody9RvuPZcm7%S7bwh|E>soIh2wCdd2Z!sW zES{dPm!3B~ym^N)V}3jv5mGfL$J@;=8M+X1psIMTsSl3h;PPG(yxwwE*JmHx-Q=|? zmC0gJH$tuG*RTD=F|zdhIjNIW08c)e-(5Wz;-`P}_{04@ssuLs=*KS~mxo9FLxA(_ zC;yEEBR@?Iv450qn+7sfnLckqe~+5uGtH`EStf1&(DGh?-E#;&|F}u!%OI1%$A9s| zZy;bmAv{MIZgB-z zi_#pErp35HWy2W9mGw5nZJc{HLRAAn+4MVx*&+xfiBUyE&6{i9<17xLEV|ifqR1ak z`v<`?OCXoWhV!rgB#Ejznx@giQdb5YMfviFyvpl8{WlyB;p3xc4ZMTnufC?t)MRnK z>33Yu?cU#a99?~wXVuXGqcFaC#jzu~xKt*S5n{JUSjz3kcj(|UjVs4Eb6M)Ny_ z_tA@&O+qmT<9yI-YDRfx8OIlS!gFCpv8rIa-c_~dn6|2idqe9V(dx~$ENZeSbw^EE zR=cDOo_}5@fI^lQ_lthVw!)-t5lM^L=wRFwSvBbzdKgli=Zf@4VeCHjQ(K!3)11<# z4x_`vlcUE))n>KG>&n?-SrH=e5b#{nR1MDofC(eBV?_z}e#l5$JKp#2`D1D74tfwi z?21+qKK?ihqkVszgiRCs%k8M&>Go&Ada+^5wG1N;RjFr7{M)w#ZT3k4Xvckc%xXd` z{mr~A`)*wXp`pq0;|fB@ykEL{uM;F39Q6QL?o5@D<&K9O*!Vox?^2qT4RY<}j)(o; z-CUD7C<g+s=>MHQ(8<8Vu>zActZT4a0S`3N8$x{JOk0(!VU;BwB z9$z>Xqdb?zE$Xx^x{`qL@-uRwWK#dN2wiKLeoWnkJ=&>gWh1 zWl_7PDDWI6f5hxX-QpH!6{V|1Q>rS)Rns&acv$nV%%8nFc~&G%HLyOsc=>0+;+t>t zcprZ7LYDnqoOC-p|9H1gAQ*NrF3Nr8nMr!J>Dv&dr7q8o{Y_r$^3mb#B5OuY+phKy zxOS3giYi~PhmK<}c3u1YNtv&FQ`OWK%_fSn-OCbcHld~0XgpYK1%B9n|KORrmgOxT z4)5>lW;%VCH%%73yO(%HS@@cK{;bIe8Bdn05$=|U9lOj|o3emJQ8||7Rimp;N0O?%uEQ(}Y~$!9&g%jbkrxG? z2dt>ecAN76y+A_0tm9aEUiw*$2|b#)o@o$VH4tJNm5vHw)s!t{Rl&iNr*WXGh5`Yl zX-=rfZxccZsgNwXmMoZBTAOMb%z>Z3jmaLQ71u?yu1DVzjOws7FKtQyxgUWwPu=DQSgE&e)IP4 z{}0E*7@=SNuckfdwRpcKttbZj)$RWN>8Cuu+P?e!N1w`)B(2_Sma0B3fBY|uo}Q}8 z+t>g6|ESjK^QyU9%)jd&4*IHeca!g*{QP8`m%DqrGw66$Rj+SnPXVy?Am#<#;<>CU z3fwAERaYoVtK77!#!vRUxv|7&;Fu{%6c}H z-0o(LT7lEGrp~JdnM!9s+o~+8?H=IK)Ur^?s3g#)I}$lnO46*- zWY3etx{`Q81tWU^eZI)$GQ&eS9Vl0ZX=-5?FDF+CZ1fKJK+rl`_Dntm+L#QhN zsIth{jU;GF-C)8PrH&oO>mW){TQvM9&a02U{D&Yj70c-KHV?8mIY`s#$?dhk^}Sx_ z$)}sgG;7IpY}$8smfq>TyQcTU^8;N~nTTkxv9v}O?)8{{Y4@jpAL7a{U`+bnN_|-?OZ5!8>)zvaiIF9F{ z+~C{x{Y{JeUbs!-C~orZFxciLqsJd;+HOg3w`lua$x6@cO+nK(d3O5T=sdo@o$KPk1z<^7RR9_G;;}+eH0X=Ssq85GPgT zI%Q62i#0`-D9-DqVyJCflosn)<)6H82dQ7zwu!N2alF$lmVS=XDV$k|+tCJ|%fYDK7|| z$oB`DjM`n2C4#7_O^c8y@Em2s(O_h1l4$o0Rg-nC=Tz0reM@AyDE7%b@%Puuw2pI0 z)+Iyjd8z^cW0qB;Fm0MJZ(0D-7$Hg_Y+6E8)zn%H}hNY>?$GViItmL@aLC+5MrhPCxoRpa)3j!u-nnj(iq4oMr zVGo9btoZuZvNk;y_|<%SODWG+m8hQnVmJz;hf7gCdD-hcI|~C!o_?+Cd zy?q~TM(3jmCJ(oHG91{trZD#5&ptReG>!{G+h$Bt_Nl+^b``0`abj7czAo>xyLnaF zwqxpYi|1E)WLg{qpeVPC{iZG%lLSJ8h_QoX%W^G&uMy9gmT8)*qniq*6*4s2;2;C5 zJt7D**6)}qriM!BKHThO`S9RmCh}3*bzR4G9a9qPCM)wwl_B&aN*&FR4Xr?&tE1X6 z#@_jpPyRZMqXfbt8=g^usVpTaM)Rv}s7S6kIhPbfP+O#grgd3xoUZ8d;SXP+?ObRp#6-J;Wb za`^cN!|A~V#&7S6tlI;iLAojM2pP^#{+;VJRd4#mU%h)irJI#Cfl5Yr_*n~Z3M3$n|>k*=B2xobBD2f7KRJz&gcWjx*JR_qd|UjdpAC^yON~JgxvdY-ru}KND@VXG6*GE)oioHvdF=@MJ=J2K+qCX z$?IJ-ntXU+YmDvUtZXp=2m#P>o?XOgnl%jvML`r4$<{GptU^352`y=H)Nn0cEw?ep zwP^Fcstj#1aeME6^Pm2AS)|mq+9r+wh%%0gHoyKySD($cn}_gZxY@p5HSH%a>*D)w zR(r;pRuDv?!NI;MMgH0O?RT~lXN>*gZy;=1S>$<9Y{{%6$)XTv09an%mc;oIp`@%D z+-fpori<{}fBU=fcZ1 z9OM-ydFG8?KFzCt`rFQw(z?F+@%qcr6NFS10LI4WtCgnw=l@Cf`u)86)t5j1T9Ai5 zTMKtZAV|7u>c^)C&vwz@eYs0+epFPRFG@*dOjV=wgF~JZq=N$hFnPRp`{R)&70r)V z(Y~n}8+MAu_ff5BsO`Bm`r)hj)zR5_&|rbb#1Cxe^y2hL;80uUsCoK=P(@NDN$7Q- zy?A;$=qO@V%K~bD`_*n|o6DfVwm#~veXnCX!x14Jw`~y;1l!I_Sp*G6x>#hU(d#mqtknp=&SJsP#-j%i7iZ zy?3wU%r%32;8^Cv+EyJ4Rhxa9o;|s}Qspe~_kZ|i6FK_9!Q(P6JJxuTL=a9VjQW0q z`W->Y%i{x{FLDUG9!03__xqE}OG7#SV80Uh@$t z%6Lu^#+?@Xaa8DHi&|8cd4UOInAA;PwwRD{e=^lHj!FW?0yj^%mbPSU9gJk{_I+Lv zf~su4Uk51w<4JE&SBy0+V}}=I+2R(fdezK&)2XiZOv})W<-Tr@j&!NtQ#DLFcH2e~ zYU6_7q5>c(mN#XcGy4>B=? z0KB`I-#2ZXtsV_q5C~m792^Wgjuoe6*6ViM&ws&~Y9uK_b!GSVVVeHo_W+oxz(W|X zyC-$M4d;)+8~{o?RbkyzHf`HrOr^Bu+ zr3C=G-n5h@2(@KiSF$Wi9IR1EI9F7qv)S3RAHTeQ)D=QxEe*l|!eQs+Mel%802)MT zU9_#Cx>lB?6$ib3Ro94+V27}w^u~^^8vqDAW2luR2wfxeb#=XmaPP-Dwv9+`1i2=HPN2 z`W;u3Whp8j=1p}l1%QK9efhqrr!!e>3BtJLc+E6)p0BDrM+gAJ@@$T4T19@CbKG=b zX>q zYrAGw=5o?=Axy(>UMH2R498YKi{nHROcSHk?VI;SJ?NZ2y?z%awsmxLb;rTH;)NCq ze7CdnWnnzvcu6daBv!<-Hgs8*1XD*1&j*FT0iekjM~c`Y02&--5UMiIrHN^9P?MVm zLQLuwLQNF~(iY`5z^$U{GK9PUKvNsu>}WdcOox-{juE!^~4nZCcr^i!EHLXrp6p}=eH09aR`NjE#EQP7RrL?M6n<{rZm`GBvvpmau zef|C#)z3ebgtXY+4`-g!bCYQNgyVMG&1!e|;m;3;Ng0QypB@}+ch{@SZ&ahI_WPUH zs~@`KvR38I*6t0*wqBvdqbNZTrAfY-%L)JjpOvaM8XNjHSgs_c>q%l(E>@yQC}X-5 zrX26~XOq5z@HUJ>Sv@{96~&>FQdXJuGXKrvy)@J%>_FU4?Nf%Y&X{@LbjG zgPku*vy-!9TTjcf>3h39WuhnwEf#nP3Bjaks;bNzL?{G2*R(|yCRK&8B8#HLa~l7% zKZWq>5)nmckT+bsy}sT=lv0`o+s!-_ILn%xmlb14N=Q;FV$;Sx$GPV5le*!#(S%@1 z5vnRhWbELuu6Zsi3^Ok|NT^{5JRw=#wx(*St|7??C*}PjN!M9e+%Hz!96_+SlO+U5`C@K(uHzV@%nN0+iBN?a#&%m#7KJc- z`>kem`-)swlB}s!ZF`QRD6-1)L7dfPscG}oI;_j%=e@2Z`Fl~mc>d&w=Qj(hdpI5U zl8_f&ud46vufOUI!nkcOzvsn&{~u1rixn@PeMG6J-#(a~!6-_ z$}~C6){BGFqlqeQqwAY2?v4i|S;9o%DP^oP?Dqt|s%2rHhLL4YryZN;Y9xtCyj@ai z8?q>i<1uPENQj~gx|6ZMw-|tZ^sst+we+_k!W`!srp^Fr^ODf2P7rrw4bK@1l8)K2 zEThb>-fSXDRaur5-83x)0EDUx097vQI3hHuDSLP*s-mJ4wJo8vDQl$bvW#gt)&2qvubbxA=#D^rq(*XGaaf=)+$g&v-bWllIfUHgrPXe%m6;B6OeMu3K#D zgzV#oxuPgCrH@Mp6~$Bm$P?W(4N-s~&-?ve|6roa51Y%YJT`65l%=fL?PGs5@ob(; z%gr|SWo0tzI*c_Y|}OTZIP9YY0Gj_rd8~twrD7-uvIf7j+ z%m^`Do)b9JT;2SUPDM%Gwpf;V{?q5WdVC=WggX5=)g;~UmxM|}y61UAnO|4cGOkNi zPfCBIn@PD@9-N56)mqV?zCifv-|CiYi2{T#zc`u7BII;S64R0pRmFtkTLeH^O49N4 z;sk)suCDP`S9tR z|I}2|@pg?HZ-}vNEG{+o;?)PIZF}=oTMfsubidTi(UdX5T4L%iUSx$N5~?WESykti zq=+Jf`}E;flxHW3B=C!E+X7%Yv!Nu+_iumTxXHMzvl^4DOG!3OTW4&(d-pbty8}tw zCw>qFyR~kef8aU*Sehd5gY8xn`+Y+X6H#oMw|9$GfAHbObck9^Y778naT=r?HymiP zB66H2F~C8_ilVN{x~dz*^MU{X?*bJ^nWOXkPyfyA`Qi5@%bUu0Y z(_j6)Dg)ryS*D93H|Sh0ZSCcUQE7d%(D&z=N6#a&0& zAJ&qPRkP7{T{Nm7%Rjs`HP2(Tu8$`#f7(`p!07mBx6(D!k_AQ7bxQ9SJooA+kJqo~ z&rW?`<_Xf&ELCL=7Fov&cDukco__-2>RwYm`-^a~-u1gqfAg5;!TRW_zeKI)bO(12 zbvmBK;V$~<)4DM2^XG%JqgM>k#0UTYAOJ~3K~y+$`hqCPumAP>D&Clyr1_7V`Tkx} z6?M1H{j<+KPgNPc_!G;Xzn?#_ymz#{e|Jqu$Mq&({Y%+&+`*CA{r1a#@B9}y z*N(1;7oXn0&8nvdk~BSS@*p-eUFZ2QYH_$fJXSau2 z7!`TlptNZ;HOm|98USbt&)qzp9qCHPRKy1HuqAn^$qfoKQ!7eIyx#GBexMJ#MKvDU zp4qwj4mDZb;Mo9zt2F?gZW*24>$kGlVp;T~rsa9Y8YBs`*>c%pU6~#J;f*Gp9pN@j zXMIsfGg}wALGRu5KGP&!3nN4dbTZj)Q9JA!roY!!uOllvAHwtJ!=vSmBpp7ZC{4WH zep{Bh4nP!1!l0W(egyI1At0tXoK~6Z8CDV-{ghNw{6{whKjo1`Rg+1ABn>4>oWGnkOG`#-~RTaU(VkZMV`r$ z(|`ZEDh@9o{D;52x*eGAWOJRSf#2<&ewr=;F!cUOwocNjbgjwr<&XQINonm4rKTux z+wF@WO^Uj%HHqLjrPMNbK1r&kW9xcZuC|24c^b=7oHwm3GFDWwcz7sr4O)k|)-{1g z$WM!^DZP%NmSt47#FX+(5CALds=`fE7y02SWLZ`=fN>B)(uk5Q$s%f_BF<>5$dcIU zvQ`#GecO^nj6EyMcOd|lsmYAh?W8vtFoIiMV+?}#TdpL_Fo>$gv^tZ_j}k?a1Xus) zC*u(S9bFU@C6BYZ#iG!lw4%(`?TM>slIR*<2Q|9ldBelr$Tc0yopevauqd*ChY#OJnBao zCA)C5E7B<0`(++w_cxo{%eVjX&9DD&$Q_IonY6=W%C0WUtkdDR?apvbvuQ&gBUR@4 z!Gy7<_1B7CRk!o^Zz0!|b>$B1F(pkiK6rA$@jQ=l82f9h4`CSp>VH#AQN(06WHc1q~Yk51=!!oj@WZ534# zf@~iIdjJe|7vA0VhLfRVGS=^QI+8%BDm!M??qfla<*vh6R;DQc9lOCvb-51q-M(w_ z5YyY`HUwbM@7R>(Wt{AS`|GlFOht@~v?!|iGKm3@WnI;zqFL_aWaH4-B(FDN)-*-3TV^H4C7VC|UuCu3ukRKQbyK7~ALkHCN{bobd0DZH56(_s$dYZI zypkmd$H$hw+*O4vGnSX`*z5Vx>T+;q>UZ1ydN486xxc&u0D!tSyr)k+TUP(_fBfv# zaOw<>&qY2jx0jTM%7X(Yj50KoBwwzXWB*~RmY&A~WTwO)sVNnTdHt{^;w z*Q+EnEeI(Cfaf)Z;~?}L&nTMfYf&5wO|?Rg>mcfOhqj|(dcO+y9q*{`sCko=X(kAx z;i#vpl%>_x!*T=Rpwo8@6_ZtPx456Lwmf%sIO{RCkE1+}Ij++&T|ty2RgHrd_qqTq zqD_*Nl;%a4v={)!1Rekegct$P^*X)%_V51ZclQ!+sH487y?xzcQ*GMgnQkr?hRk!0 z!a-5+WdYBU0AAR>et5pdAfp1!jbrZrcGcm!YE{T@M zK}iq<02qT1!lsD!X<5{S>_f&jD_yUUVQ_p>7)oy#2lLHe|AZHlLQ^CyOvCh9gE0V_ zdG^6#lN8ZPlv;fE{>d-L2bc3OP&G}JgsQY0VX@ie;n~L!DmpJhn1-l+`t!OZ7yzU1 z^>5xm_~d52 z2Ea9=ti`kOXpEZ2#WtlCDJh%6e!uILHK8J3BNYl_8m?D$gNeY`jb#da&*<2wZ82lI zs%up(inCE!{or$s)UnT=b;oDV_aOj;3cRlCX4RB6rI>hK)Fhc}^jt#niZKWt)_E-o zwsUp23Bz2G>t+)x;?Yrq7_+pdHWXRZWeAHpuTg6{PY)<78d>#Rj^lV)&g=DdJ&)sU z`tI)bby3^}VJV0$t{Oj3R83lM+<~E{W$5!lQoZ|*w3NZ)u1;x-Y}++7V|eUXQNFshhi)Ho_UPaY!iU=`Va(tC4zq{l3 zreSQk0Kjr|9f0}0J2q`WD3h~KPEL~a^;d26;xmlf_VH5IO|z=+@BHh*p=l<`_EvW# zNfOVV3HJxi0Trqh{CAlyeh z-*H6#-PLN@aV8#R+uYx28fCW5!MND_Rb`n2uWL2fkE5urCCPJpwkR-=)oF&Bww1)g zuA{3W2jl!<9!8>|$+ivwp)K0`i*1-zH6fCiq;bxGB6nQJbZkG4Q$^h|u9sPD>Ss^lxFszXg#!6`gCx0bOT<{G+w}lY<^F_H z1|$);u4QYgf|{n~A!SWPh$L7l!C|xwl6@G9ye!FzDDseljA6_{Ss<9_vWieyG1M@X zb=PWe5FDIMy!$0%r-zuNyMqG=S9kr1>ry&<`QgR$Q&E;R$|zmmmW9BlIi>xvsb9S> zVz1M+0RX^X{`kAcZ)BZPj8WB_xSpnB#8_UI+1NB~gQbCMm#2OZDzCWq65 z!Qkw(KQ}Z~O^zwMxrN;I{rk7^DhwB!_df{I#mUBRYR3cMZW~ALz_$G;*c5r3JwB}8 z2m3ggUqXm6$AxP~aVts5PLM`}!DzK80#T+^Rja&vXxfv*(Sgx(M-LBG!3%>^j*r6Y zA1BXU&+CdJC8wXcjwCFWbv`~Z^`#%o8AI)E`|=mE{OxzaveO&(uGU4;?K{psUM&eR zG+QU6%uYX;95A+6JD#THWnQh;!JaY*IZoAd^}x%Ueb_X%HZVm&5MTVnwrt(j<0>mn zTaskiF&&e#Bu7YA73E-ZdNS%;rsL{bi_=U|RK>M)xusQGqHT(C+vdg2_d|?1u5B&D zws~%7UyLmk0Mz<{C0ptuSnPYQLnwS(Qm&9DCR^<9m0MNW}koi|9<m0wlz6t3;;>7ZCN_JNVYrw z7yq^1k@Xfs2sy?8$YY*sP~u~plG%I1$@aBuSz;K5 zb?2PU-Y4gCbLhSuCno?LfFMChluIV796!L1{v^M-%B7OZMcc4wV!*)+W~MP6Zr_|v zK0D_e{h;+9Ynmj(4$I;c%c_hwioorl0`6o4 zdHK94_|ea&r#~TxRIBj}4nc3<<$0%n^r$A3B}D|m{k7|68HRWJgR$q%*I~TYS4tGm zRi54Le0EZ!hf)~fc$DaNtKMw^z|KB`%$8o1WO+f8Noskz%aL{A!{cFN*vkqGf}3FA zWoc2WZjE{REKkS#_di^on;u6zf7%$V?=Bwpdad@`cV-~bFOO~0at`-D{Wput>C`kZ zw1{7w0f4}O`Ne&j^AwGFjvrJN1j-f+w`!xYrr{_}v;6%OM+p=~EEj{5R1$Rq0*?+w zK~wXBBI4Ng(saE2aHBhD5k<0I#tgfdrS9&>&PJW}wjk*A9SCe~&u0QV*pip3J?S01 zoL+2HfgA4m)@p+yd;6}Ts?Elie_tiGnT4$ZPht4zQGMvhVet4XJBsPv}YLy&(2BfYPJ1D{nSwxT+!nYjRvQmHdgS*#?9{bO~&LV5G(M7hs9qDC> zqX(blj_rsdPG~BIcDhBnlo4?EQI$Jp6yqq%uI0Rdz)m*`JTJ+@aPKfnH*!%xV4ho^ z9b#~^UKb22&Y`l#H|kY^K)MA16vZ$U#*iplm2rsS6ipF0mZpy91$Qg7io)&~fyxX+ zv)l^uB1mDNC`kf_>LSZLEGnQZ7g}4|Ik-H>up);cjuLp11i`Xw)=U?Hq*@rMdYG~( z6l4tHgkH4MJv!X~WhE~f{IDx;ZtnAfAwd8`2oy!ia;{%4Wpz1o<1ke%KS=T@iDH~6D*%W? zv4y}7Ny1gMwC5g}^@%yPYpPzaD;)<>BjcXi?2;5A*eBJ2^wC8Vb z>dm5bJ$=z0HESH5#+<~`vg# z!vMq5#M9(O7~Wi+|Ij_iGEKdF1;G%cSU2}q-)IJ-bMP z@gWSareeD(L6D^mcH3eQ8;g3s*CVhbh2a_}us8-m?V%vhWM1H892I4d$foJ!g_~$@ zmW_4rNU^rI+EGn!%f-J|}1V{KQ}4J}JqUaTXC6RfSWN;A(-LI@Uwet*;* zHd?hh6Qy==w@^*filQXzwYG3V6RSwYBiBA@1AM3MyV$A&X(?QXd)hMqk7;Bk;b zMO7Dgsv{krGzS>fI$T~y2?Aj-Lq^`+JKKK#vONiW5NPn@0gC$(2$;s%zbZBe76p!5 zAqFQo3}-opKp@ALrQ&*FSrsLP<0yh;X<7McmWLsMQWyj=w3m`NL&0!a2{ZuYX_^Co z)EXTCK$rjk!!`v3!Enpdtt12h5L}+?a#^mIFuHr(?hy23D@->^Z=0tz=l+tDPIN3mF(8D>@W zS}h)iY}>aPhNURHs*zaua_6I`%WDMR?12%%Q(5ZyImG#OO%aQr`HQF&@~9I z(@+J(Nw0lyq;1~6GG>?mX9+(l zO5Z0CCjkM5j#D#GoiqVK5)D%~Fx?=I)2fQXxNs89UF%+A1cvXp0>RJ>Lr^TikPyVw zPy_%xJ5P%;$<>){`B5C>RGlC8K+p}s*t1Yf5@9%U12+m8vA6Slf6zlP2&yp<6bB#} zWttVbj=QneD*zB`d3k-oOAJjBfy36yYO$WagAsxM^S_`(cU+d&_ZNTc?t$R><*R>X zM4FjT<+~)9JPx9bnPp`$7(<{RDzo9ic9&ylCQo3PCdxAQ@-&W@o6W3y+-yj!p&=Lq znf~Iw-m9wn_43CCkplou)VOZFUu$y>4u(x! zPKYx23H#fxVaU)HtEEdYOyZ3U0G+e^hN6AM8xe zJRht^JAvtYKsDM4tc{M8TSu;<8C6~r11pI+_UUgE%QY}Wmir^en6Hz}_4oG!*L2f@ zr;?ZO``VHJk*CvT!^%ta1XSSe$|poD99Syp~NZ39CZv6lr$^rtKzB z#fj@K7p`Sl5QL!uPZLs&;{<^s(lky*zTJkQ*EbA~V{rmPJO_e~$I*F?C_G(aDM^CDaBxRjF+9xF!NsnGtw@ zOYA_I*g#;CkIc>T@`fn-2kP8$3}yRC8JT(%Be~Qym4{X8jt@iA^=Ps&0^&S`peinM z*G*EE=!_H34=_+_`Ih6uX}zth3lIhM+j1pax_JdBv4g(l)_-Y z$Fip7ggn`3!?5oKap;BK-U$Ll0Sx6i1jc@r(45%A@x;%vs)}OA$wC-0wce0s%REgt zhUHhK8=|lqz@Y0xpeWTl%`Sn!0LwBg1aY_@!qD-fR$Eo_{P@Uo4<2KPV=p(|R;zV2 zgFkCc#&_>^6UVm4TaW+nPqs&3zy9|Wd3GVPM@O~h=_@zjX#^IkWs5`2Rd znxi686oDCzlgKc`^k5eR-rp6;XiHf+!DIpfjz^KL-gKI0k3UhSmd{|VK^A3Mz4LIT zSscj-i@D=V0>i&QQ>|{3<$RZAdCAcsaK47~s&d>kqtW%;^Kq=V4OARi6pueQ*PPgLeYG0_fcRiRNFduq}WBao1a{%G|I87J+Arr33xfXgI?h;XXIoV^CJf?e zr)?_lZy=DP%Q8s-0EP|@7IWR{J`BnNMKqnnYXZs4?u}rp-`h3TMbVwyypJNDeOPR58HViv*};?Z^V{Y2 zkm9f3%UZjE5%<^k4;;Du$@1*s*0NcO71d>{P143KFy3Bm==HPBIe5u_R#` z-SVSxpQaT(O5?QG=9twcFPs2FbPtxmzF;}qW3hSp7YKHo&prdHx8K>W?SJ~I)cxUK z6uVvf=u;4UduD_+a(h%{@6Pg4WDgGCo>div3oJ#hHf7mq0zjHlq-p`c*3i;)quuWA zg|;*tzA$InL-(kI7}o)SGHY~{b)2FQO&b=0PWJT`j-rt5I6eU( zNE)-ucppf>a{oYR&TePga*K5H=dNo+Mf3`2Aj< zRuzG_dXZy$XbAxzU^{_5In1M~z%gGTsOg>IUfzfl1Z#@tY(L?|BBGehCNn3GSjKl5 zZuI=%WOW^fU^zNo-=!&9QEV0!Im>~-!(Eym9!I{q$#WL}=-(=LrbVFR-6FZ0Ri!B4 zm}z-Ie}F*KSr{{9qYGu8UzQkJYY1WzDq0*cEXR8ehDCm>2Lmi+yD*T%K!xMH#PUVz z`)-iuI9#MKj8kAmVhEJye!MYc&9vi$AzU{I2%KZvlE@Yr0?}kyq6kA`XjKsy&yxfM z`9YjzspXXkQ|0A;JCDPbaT2hXQBrq^vk6$IjVy%C3D zh-0Q5CoJXImopkg;WAHSsfJ>=Gn!~LY1%Mos@_^nHK)Pj*!7hkwHx!f?UiLw?j1-? zjwJ}G3*>3o8?;ABczthqC(l5@cPwjq|Lm*CEHj{L)*Ia<@_i_i`nC4_3aFB}zvo-4 zxv99D?t!yjEe)+!6NEIjj8?DSB`}hy4`a*oaCmY;Adca8MyEb`BHsf5L-)2jlhvIcMiI;O_tN0{A>~y$_YC=a*%pO_02RBd#08t`~R+ z#MLkiEO7*aWOX)^=SA$=G>gCtB?$zAA|M#2KxsIt9R@&&VF-ew?FP@0ILFikf&c*w zWf!sS{c6TV|>TG6=8oS4ad^?3996LIGbLz)9(rfKKiM-_|$?JTa(3D|g2o8@& zc?N;?hP+(KNOk%)i9|_TyuReAx|k%k(`4!bfxnv}(71!+%XL|{8e1o)e{sULL{hp= z5ZjOBg&Pb<%k{$OiUjG{G*J^#BuxT;FtIfRCJCvnDFiMxlE5%2Osv~_Rkhn$0#rN; zR5V!@jy0VhKEnw^_Pr#isx*@Lb`PiYjb@nc(+}EXFdYu1PXAHt7@D%KHyYbz)abNF z%^ehrT}=&qAQ2kh|Cppj^!)2QoKB0VHAq5zQ)^0XS6!~Q_F5BdX4pJ3JPB3Z2;G`U zq6Cg%d_9lWDh6&n3eC_rZ4wolo@P6$oyYY$j2KE$@+{3DQ0PODyl!W=pD3coG9Z5amUdhmqqtE>KZqnwDi*=6Rl1 zRar(6#}atI+wWm8fr$b^z_6+p1qf)mZ8OZn8tx!}`@#MTU;FX( zQ?tC$NMpyV^6?G~HaidyM=)HKmhJ1cx}jXn!eIZH!Y!L)8^bItGaQBT-og4tSrbHi zSGiv;9d9%iI(ht;KZbUdaE;B~?&f;VqmFrgl{)=hsC<|z zGqEPrblFrpgIZIbKCH27?`9$dcKT!f>+4>OB<3U=)f|%PA6?MlcxmoH!{<995mX2on1oFK4fv&!4` zMy%>-{J;5k zufBQxQ{LaH!Iojw>uyI^8I(yso@Ibc;Gr$_g*w6uPp?5H+5nmP-g4Zr|QS3CEyF5LOk>UoX6<-<<4iR$i2(`$xV> z5ir;puV(^Fk`#S@2}60>?Oohvd5xZ~i*kFU$`B|?Q6Q^s(3Ai`(J*wplf@euNB5su zvTP8r)RNbJ)a#aoWdoH|*HsM5QrE3FyAu@LY*;$a%ABQk9!1{W1CaN(If*1V_Tg3% zmv`rPfy3fBS*5zc(Y*t)FO&(1TBw*J~}YcAuBgY*FUpZ2*{0UH8$)Bzk>ALfbECdh?K^j={2mh?EG#vaL~j zf}?RDYmv8g)Eo%R`MGDM5lI1n*zELC(6ltmHj6Zgah$|OUaXZ_Sy4ESWr-qtZkog~ zih>|7Fid|k+HJOYw#ja(P;ot%hMnNw-~Z-#_5!!S3*I zdZ~L+`s|r!q^aXgcGNWpL~*A-pXOzp?Cq@rMx`v`P z0Yz1Xp?9BFY3K;TVL#`E# zJX{y$)?Q;Jch6hR>Hr#pBX`{;9;UC%DhSIaP!guSE2$l6SAS&AeETVn6scPpL3%ksl7 ze*V*~vegjSum9ol_2s%ob=w@jmXmDMJDZAhk^srsEknT2-off7&rF*k@0a6VcbIsW z3WMw){qYqJmF4cCG6$>U9kF?RX}Tb||LEI4TM+<|00?S!7^8q;VQ`eTMA>qpy`k-B z_WqusSb-Cf;BZv0pPlsvX;f8#-RNuUG#MR}n5X;R{FU%dPU*Qs(xS*>B<_zM`kdb?OQ8`5xdHNP)Q3`Q|i)-}xt&BITY z*RBHq3<*QyLo9=#LC>90`-H{W!wZqai+I7+l1oC8l z%`lI?D*ZfRNiS4wf$?15%u}&NF@p)ups-M5NF2>l9J4~tXDP!uUssuIrFpO3X%snu z_FMIOqvJWRPj9bTG7MWy2=W6jWEq-P^zpdXczpr?dRPQ+Uqz7@IzhMo>8}re^~eAH z&wo}Oj@sHD9L(SU_`0mR(x;!}-7y(aBDL%Q4Hx3?69!n>XM+zMEnA<`rYJ-^*?ZA~u=46)3$JQ&b|vBL447y3fi z=CdR=>}LJ$R(E)!*1W&bZ5HJuLkUAklzQ51b^GWmoQdsLGxX|hwxK>4rmb^yb7HMj z-E&Z=-iiF#1}y7ht$BUHGNCtlJpOq4>dhI2_a=dDs4$G98#zh0_b1Q5WHu|K_OK>e za+>zX!^g34H^YJLlPWpC1OvwoLYinzcmd1|3j}C_ueT>P!Ltkl%+he{+2knprq{}y zw$imm9Yf=!D6-76p@Oe(9R`+ZF=VrDJJY4Cma(p&2*a}i#Z(1`a&(RBHEOKmc@Y8u zz@R~(EG-BuBXA&Sm{op$Ta-06OJ{N%IW7P+>zc7rVc52pO9X(&$kV5q5=1245}$wa z{6D0@;=QVs)yeUf|072J%YXDE6mHb|lZW$%b&DI1wol&v`Cg&1gKbWDxB~!z)6FEW zapOIC6@)deStp45hrHO?MX}Wy1l!H?8xU+aSYFwX7)@;Lko0n10VLiY7#fD2d;x?- zh9XJYZX#fjW3a?)c3$p`OuHyQ{4DXph{T%>o*)nyo^0JeBpFA6fTF<=O%dc`-IDmm z&8hDXw&dw*Bh?sYtq%L16D3vF>?D2|iNekceW4iyy#1lKd3&}sZ0s5LNhq(>S${Y2 zve*weroA0naUhCf>-evLbTv&gr0VYq98ji-GKKTWv+w>TjH)2d>h(^K=G2Yhi2$cS zSijWnXY+S=Q=a+!AGn5opQLcrnjqlvAqeVqit#KQM=?#eEefUBA`4vIDPj^ATHQl; zBg?WPZ?J0ef)PUV^3rx-2u0gHiey*}-6+est@bAE5laAtrsqWk&}3C=RvJaVscn|i zg=*kv6xSOx?Kl#DxXlo07DSe(o1Rw|acnrAZw5UH1oQmS;itdp^$1LsmpX<>JOFs% zjS26PU;WkjTLApsKYaS{!Rq{EY4~8scU-+pr{pELD-As3?NK-6ud^HHGakRf%>ww<(r{et0<3;#!psnfBrVhs_KJ} zIq~lLPODKQzH?}--d_{g@m_oQ!w(2dVD;wvD-@P$y{+3z2*lBYC(~QYYlvIN@^rDH zNwKzBcU$egW6stna=6PLC$MW&NwS4Z zc08^(*cw6cQjwki6oqduijpDAilNE^fprh=p&YWiyZ_-I{*OO>7lnqG7aaZZ=SN?j z{o&?a7-q%Jj- zZ<4euGB5Off7qkw#VXIm8jRQ$j!w3BKD_?RgA9U$766>x2Jx_c{m!!6oqzs+ti{%e zBgX;BSgYH!A`rXpe*gB5By{(ecRv6T$;Mt5@BYeL-@LkeXtzN?RUl~RIQCtKrmE8O zz>2RqX1g`o4;|m{3_{m(6IX1kmbxRcQdeDQhCsI`+RAjwVC#hCuiqw#WA{dZqZ^u< z28~`-=&~2Y>0l`Ktd**-O)&oL|Ds&0n`Yg%KlnRwKxHUsJCZbf#C zN0ELui_|CbAG% zlqj6$c`0#4!O|d@=NJk>Q544yGsn8PxW6-%*wgf?YKVRaf{N{h68H3(Cd1E#ULAow zeYJvN5X=gR`|z`)Uz+oO`p>F?z!>ty@3h$;{*>iSVbt3_Q5V;DPBf?w$Csy7SrqN2 z>p@ko*=*n5EOi*|8;%XED_l!Hw%ZgduSlXjROVIH8L>5O9Yp=%yR))-{-JN8FvoXy<~LbB*{0~wHLUFe4EHU= zI(i-$p&vx8Mq?am0#D#Yw*MK9VgQD2*8Q#BPeL_IuOCR@;7j#33JuF%5BCS#(@WEs z&KY#;BN(2Y0)Vx$R>LQ;wp#0!t&jJ{hnxE_`tYwoD0i|Xut{R?GpxG4L=oRfgL)SM zU8e#-5QzJ`tz95rO(`NtRtsy|-f9k^VzmSS(^;%pa{GiP8MZTwJEmvK9Gfx zY?fJ+=+08J4O7)s-vt1%UXySVfpN6me)8e&0R|;8$3h?okT?vXh*aw~Adsd$`c3Qw zeobQNPJ92@(f|A-M_b-TU3u^js}W%oL}eMp$9uo}pDE$}?_YhhQK~9ThV3u@@y+jl zK5y_=0E0)*u7AFr0RTswJX_5cN}aE&W_vMDbBgGVudjmS=wS5t^hW|q69kc@;l8by z&cR6@tv6*xQ;Ve+_1h22D6Xo7p5#v+&1Yp*7s^~Q2=wR(EV8`Y3xkE+ln^M(dM%c} zfAIb1AKc$B%}HC`#IflP`lgnqj=gnQ#DPE9#<2AqhQ!WhhM`iUjBT&ZNlnWr@+V)T zMH<2&!)qJeX3^%*+$=T%PBMe-z{0WdQ%~6}?&poV*a85cG&S3y@%B!UOmB)ZOTg&x z3n0OfI1Y`SkKpXxDFDpoJS23Ry)wNyS7lM??PqS5sHUs7y2mfCP79~KLl9uGUdeL; zV(Um&WQyr|HGb!Ls|n>8{IE2aP+A|h+rFh4K@60e2Mlg+;gBo`F^-n`>Vf5?PFW0h zwzrc2$Er$dasmcYnC^f;QI-`96@}@#z8^d+G&S-U>wb@BDHf*)vOADk96Q;1^6_vi z*1DtKmQYJVZMk0EFMLPStK#Z%y2uL376Wf5k|r-|3d>^3+EkBIxD&vLvt?*BjkjW_ejQq`+HgG_kjrgtG;SiM&vM^D50a zrmBLV)ispqnuTpk)-ePIuNQvWt6wgGs$0)9mXK>?-K#xNdZVp^s(|T&IW;{B(My`y?s~v9DVgI_S20svJb)-tLq8 z%RC$PSsn!LZV9~KFN!Q1?k4_57TC@p4cs72ya-1m-Va!EJaU{G+Z&;vAHdM|9!rr_ zdrZ?X003#cF-YX(liU|1skgo(h(>2|XZtABY^;ZBsZat?u;=%i(0?SyrQo;ema*7)T`J%CcE`QZsVG&~i!Cvi#uS z3CqrBm)Flf-TyGwF0S6ZF6`|W44e2xp2YqA{;_tKWgxh^Z+9VJalcV4uivW=Z(rXo z{Ybal(*CFRDhPlaL23;Ki6Ru<`ABTVW*V_H!)6f(Hadx)=TVZxp6<&`?eHV{&hcEo zNHA1vwEN9A&*iZnrdb#%nl5Ki7?cH6X?MyUjMUqMtyZ_)6eyOY@HBIyyoAA`1VP(b z>rvu`80rUAm84$ag>K*kjt4`YZ+Uh^VKk9ub&e%IeD={-G+gEgT$fT09%7HTb`Ei3 zb$|I=i${~k@4vaYsH(EsAJg=7P7(lc^78)bd@8ah z&q45qA8||)tLpO1@EDSz6*bK%bhENOfu-oxT6bZvtT=Kwtg>Fa-B&hI((jAS$SsQx zf4lvh69>^KJ8?}}6S(oyo7We2U?R0WGfAXIYoaY27X!AQ4EKzO`3BC0 z`@R)LVy!o{O(35<0V2bI)9!AqvAGN5ZilPwf1NobnWeGUI~IiHt>pw!T{!x6W~mzj zGt|lc=m-v%GLCeb1lb&(y}rJQ?H7O3-Ffq;*`nX=KPy87KoQH_EOC7M6B3AW#xJ9S8`cBw1{-#4)Zf9_|u1_Se%i;w6fKK$0MF zj_kK_l*9-9not)+-f@%63c|#XlMIG%v@E?CgJFoFpsFQ_H3&F7dh$^cUZ0*_Tb>tK z&MOrj<6nO{JidQ_eiKF{5vN}01lz-Q|J|$8voLle7^-tGK2v9Z{xL~mh`?Taw3<(4 z9I1=jkN)zb;!WCL{D;lW=>>&DAda2gW3a?S(CxA+BmZt)RV*2W3xy>gAJv6^|HW@{ zusd#THKZ&Y?2evt%)!g8&&%9eBZJoYn*$U3gzSHjRqKnLE=g6T0eH=nXU-J z-q(ett|sF+FlYV4(ROSRLA+ePFFu3Jz^QN<7WLK?tHq z7#{A2&T3`oqiw03_{)XBU_|1?K^P6UZAH^nbN>)UZg1Q5$&1B#RRN{Y7=Nr@y+31V zd$skUc00W(%PQrB=1#q~xRI5`3@Hx2OdVxauVwK^|FE@%=F|Jdg2VSem6$ZxEJ}a; zxW?+rdJ0vIq1XTt&vQNBF_#QCdMfgfsXIxEz*&T0?V(gh0T|43%R9XZYzzhg5NwW) zKRfxd(MX)Y=jgIhYzW|J!%Y&+GJOyrao?ZLF(gTfOx*-d;BrE9z=*>e3jYt_1K5PVpgz8t|Vhyrvyib2p0Sn~NNTgO8C^xK;|99`RP z{HvFvF^WyE6g^3Uq|WW{A&9NRAWOHq?|!ztvVuSg`sruc!{HiR6s7|JX~r@OHOksT zzk$H**2}-ekv!?{;>_KT-~V0`fBvH>1F>&v4+#9j|M`dimoBUF{2fq@c5VG`H5uUe zY)KI{0S2Rpq~g$V+ug-tGzq=-WO3_w99?glT2b&k49l`+?jNq^sy>-1+QpwS}PY#@kQ z7P(9S03ZNKL_t(zd>2P>jAB$(;M5HSd0tJtyD!R*er>G>+q2v46J_do9MjucPHm4w zdC9YI6b2QwS>JwaZi;O8n6B9y$L@}_xu)V+v!`z~BXIU#D)$7QL`X$(p{?jN!U)>R zwAb<{zk;hIaGb#wMO|MC?EY8sRavBQtO~s{UO#x=W_JAP)`z|tdba5stnlow-~VZ* z7;fx*_1`nZ^?MqJK@99Y1|yo#R0IY}oQmD$CJZ^6uixL;-g545db^K*%Tea$ei6mK zm-_Y2&I^IdLh!$4&xqqjM^Xze>$Nm3ia61%An?rFOW!1EzTV!gHCn=;SEk)o6qXeV z2T2fBB>>oAS-L?OgMj68RG3tiVudjP6eS1%mFsCX#}F8fd!8Sn$l5Hc7e`3x>X%JR0Wy_uOFgTcT9G$64~yQk&dhV~-v zO%Zz6&(Wiv6c@K4DQ>lnBzWYKz+f=0eRX-4-g~F->mS6ydV6>x3w}_mr}5pSQmAyV ze+WZYW%7oaFI2mRWST(MKUmx;nqd`lY~l9G4P^Pt|1^6WM>yK*_RkZ0wMyIvKXJtE zf^Xuuyk>ICv9Fx}&F}x4>n90Ibe~YHv9V26@%7$=T6H~&VhT5B?c>8o^31fdD0U7$ z$B;k#ZoVX8uEBS6m?X+Fg)^jSVQ8hYx=WpdpPCCO)=b4pqu8?*rf~e}c0`dV62-c% zZ6TnwJ3P-k1achP1p&jhT_A-r$5`KCSo?$^3GCp5Jc$AXR?5*t7zYtc06-XnK$c~I zQCKLP|Ab`prRSCkp*4U1@}FA6yB}X(BS1d4k>j+SCrQVl$T;S!rP_A7 z+?EQ%2b;-KsByV`9J=1{xKy$Y+xqaAP&&Wos*UX434mPcY6kXS|g{32d;NkOHBQzb?aGVeXfYkG3Wj)*8gK2Y5UHcA- z6wB2{rOI=4o+22MA?tj<#}!DF#0!N=NjDL=$QJ0wk5{W+tx_aV7^?B7&kmke>scx; zmrKt_5kWRQ(SrxXiz65)mqPd3U$57aQO?<3Ie&OKI3x2f|N9@_!cdms$kBeabNTys z7eQ2{8|6;NF>c2c!H`crT95AUNlbGv`0Oc)%3B!Te>!=sDQl@(cGT~Ff4gW`RBZo#-nHC7baGG*8Q?=Y2Rpi(6G~GEOsp%;8`VXavVWv)N zUt8&B937pPnyb6%DzYB`!jVmVu_%{zKZ>;bTY20*%xqQO|A3;Ux$jeCu2es?HnO#M+xuYr_I4J=hX3UF;KSMbw>LGeT=~;)9T!9P zjxplYvam#;G*RTehqj{Ye2rmu4hwwj%Q67CzU>zCodZpvh+KhWT!SKE zfMmtxddrt#P!d&buv;kWf^0zU!N=Biv6zbmh$-NB;6}c_96p_1t~YqrJ6?>oxAj3T ze|;g#fTzrdPi$!;sCwvR?9Ra@SBmVRBD6gl?sF4Xc#K`W~R=dq}*a?*Hm>c3?kbD z6I0b?isC!%o#RK%7E2N+40?g%yN>HeaT14tp$md2$kJrtShgW=SM$Zf(9_tn=hMMn zsYIZ)rY`wjr)!zZnY0ns>s1tTyd+UXvr3?GLJ@UdR^dac!-0ThA_$PU0f`?!Jo|9( zQ+@gE|1B$i*lUW~;o$h${PyKdnQ2xO^I#uA-(6%Gj)36qL7{s6Y9-@Hv;6Gy+wcGV z`yzv5IC^#M201zlF?>3ymXoAXoz0W9lso&>*d|e@-+m~LJe$eqE2AG2S+nX~|B-N? zrh6Y^MB`x|WwBNRQKL(pc|E?Wwp1yMk`#hK zfa86~bBi2`843hpD8&j(No!OIYQ0R;!EXC(eZ7@)W zNc#58YE{m2)mN_=Z1BWdshX~>mi2n?tkv*zMT1hlRX>4~%|w!+u)wz-7mA@ep01}P zF!(64rx$^TWBVUBJE^@EG+S5nbrQA?Aqb<`B8wTapil&XVF-rNCANs8X`Cg3V%fe4 zCOE~gT&Y=4LjZsvQJxEdnTBy#taDwyn=ddl3M5e!$4Q(-aTs}l<9mT0TD})(rtM~F zoVbDGY^B?ctC@Nf77CJ}YLes!G@Z*uk?rCbSMBfRm?D=%mhA^g@@5O~k#KBTwgY6Y zAI0^`r~j$_)R8WJ^Xk3r1#y<{_m3W97+=P5qlc20zxO>1%JHKgE^ZRPQs1t0>ta*JdIw3=+*endWoIa?9V=hZmHR1; zGmNS+RJ}G`VnCsEa~t`4=bm|e%hJQgjyzk{`C4Dwj8>_&|0MILV-#+-P&^AXWv#R- z^}YF(ZbD#Ymz$Tb727qw_?0-)lu~*3DI7>52q0N=@93LmCsf80Ltu!`V>FH3^>TGh zfSqUUqarRWr}xsuYNRSbU`oy1>OrYOCK#ZaQ(?P}l;wrBLD1ggR^OLwC(BmL)m>ue z`C=niW_RHI(yn(Jv8)?20eYUJ9rW}*D%LeV+Ab!2Z}-?Q1- z&kNkmtFe-pC(pQ=vJ#ZVyvBDrsXG_XpAgt~`+rVv{MUMQQQwPMOpwz&7aMiYXH zO`2Yf$BRH?DTePn&5ZSYy>%Vav0WI9j6g5mqq>h&Q$A8Xo%EYo2 zL$hKp^CK6AnNp=uD8ZTQ+K#1(^TjRSV2eAC87wei7={4=hPT^yche;p6w7QeSKK+R zwJX&e0|QB%CJ=}rERCUA7KU!%hX5d&MFvI61(E=O<=nLL3E9<2>)EAh^8K z4G=7q7>Xif73Pr#?J$BM7-Hy0Uxx0xZ+&xgwH5%N!F~13(_aMkAO96d7uz6i^G`nt z+}peHBuR@*wZc^${o>m65V%|W<^Sqx|IdH5eZE*KTgK&>A*wY|ijspp8k?;65}W_- zN5_5if}~vCv|^uc8xl?C3p)=2BaWM$-4|Rl4MLyanZM(!%k_LxtCMJNI2#WRms1=@ z;O<~K1%b}Ktuf4cjv)2U>{?d(yP@A4$XggrA{cJ=%N1K&%?_V5+p{}O*n65eKVIV5 z*_Ylb3{+|7s8pHXDN2bfwvez&-!4F7_!tPY5CUE6(NDn;%Q(Jun%JJh=IY0_eiqC} z+qJO3q4pVrd!`|8?#p$qAE<^JhK?fKz$sgX6A~?!Bw02al`LD1F|hTp*y39hB&{=m zz-USmr4?W?#i${O+?!Vu>nyzv*3Y+f1&hY$S{&A)D>yGD#U;UXb{`e}0!uVw8i@&-3!|hAc z1c2S0T1VQ9Hz&J;qve>T+P&>6j$xqM+AQK^dHd|=(~FJBQn`XEvMdC#c_1s5%JqD$ z)R*q490XQd*RP`}P8y9U2>itwid!Aamamk6ch2^n?>;Y)k)ddsCaJ!$y@1oo5KQ-uHWQMNR5zeW-->LC?VTTg*6nBZRz#4w zfM$1Z9TiOT)$ZeJ1N7rCiVx; z%NqjEG0om)X<6OjVoKum{${Fc^)}0HH?f;9`F0ZLOZn=05cN>Lj)41H+My*+~QioSdd{5^h))~jV%`|xw^ji?mI{2>s+U`!&1`5 zRQWbta%9K!JU9Xp1hr+&7_IMT`T_@W5+xcZIZBw(6wkqM6k3WSmOG`+(bH1iRunx= zXfh60H~K0I*~;)48RuvU735Mumd7J)NuuR$^Wf-1@eTwilBQkLRsvgF)rX~8quK6p zc^plXEOUL!Ng~IyT+g-4Fj_A*D@~9$p^u`0ABOu6s<8zDwpDieyH9Su``x!Q0R$Ys z$hPV)KSd?8Qo?+{R$VfbQ(bS+)3=MwW*KPRlfhYkSiio?SC~qEtjjU`DneB zB+sli(*&dQ^G6*!vYo0fv02v%uxwS$MJPa!{zLC_0SOS2sxM=TctaZES1qAUrbX-@Ag&9#KJ zszML|C@KWCTBbGKMhSuXQI-yO4$q4v2%u=ow5_QKb3mJT^Sk?TnwB{jLJ?iHopycy z;pFYhS8+mMNs6Oi{H!&+e!bXKN>MbDjyvU2=-y9)2m(2_)16;ys^vm};}#35#&M2; zfFM{bppfHweywI(rc7NH0d5H ztHp{Xcg`(I7TWt1xtt_Xt-bfc7i8I!4nNHmGvj882DNVI5fQ(=Ad!>LN{!U9^sP)` zkA6xZ;_Ce$f$;2$?w&NiyRn55pRXX$o0pL>{BUqe#GWlmI9RMT&x(9#ib9;=nCm*4 zyOn2qpA}kAkOff`$BsI^xcqlG-utYzi^eDtN0RD=y5rfYu5AL7DdmcTv%SZqlC3Tl zv$?W0x4xnaK#CGsl*U0|S%R=$tKw=JIhMxcF|yJw6n4*ggFFsIx?_5}Yk5)V_bat=XG!l&SxhGFE>$oE!+;{LgMgdabmh()yN%)fYe_}J`fha?3k1Qp zThClU-H=$C1V-;cfiuL}xY=!<)!L4@TzXomN*CV!AW4W<-O2L|sY^+e_#_Qu)tv$< zZ!Ra61B0e2uGbftfA$yE7M4c-?Pw)hj%N@cH{d#46Gsv^2oSiyO5%EXdp&tw$Tv^O zLhNM`Uu`zPOqN!2dAprK$>4FmrjvxSY)Gs7$gwn%!YL-#Y}blSjzWAt zN=U3$DzJVKMg+c5WFw4%I7y3aui^Wq(`|n6S$i0Ijwy+vA_$VK+qRnl1@=aOsU!~= z76cI(hV33c{ps+uz+Jz-8-`GIYFa11Ug3R2t^=hJy*oRv1dk65M+M6t4odtCykxOog#Z`v3h&$1z=F%NIXrt zC%!csJ8Br(j_;yS6l5t)<#|U_lu{7{m-E2vox#BLJ_<5#_(Gk`R)ScjD?M?v5FC>N z`_DsdGhg2p3x!sZ;~Vq4#k|!y`sMKH{MCBwimj8~=j-?PlfWP;98Tixih!!aozG|l zLpQVa-SVnj>pyQcDDTGm@nx^?Y#ZauWRMzX2`1SN&vz!2hpFTMG z==^<1YxXKeZ?@4kibb9%`@1bb3UnnZuG=^bG^37@|^=FGbg<`&?YLQo} z;Fu+mL>j>vn@`*z4D8`UPqWqaD%AOI|5JhzZ)rM(ju9znmLKLcsELpm%C^N?(X_hVXwFbjDR+1b%c=7k%s*r;+6mh&P zixU_Q!#E)@FOUsEoQ$WV-Mw~yc!m>E2xNg9hx#^2=sd|l5J5t)tw|e2HT2aaj-rUA zS#qVYRF*{vO921?Y*e_59X2rZ^S>;Yk3aEEasK9q=`2k#1ckr+{J~fM@_$}jdp-g? zezo}c!QgaxGo3nal60ycekm{Sev}l7&@I_|cq~i0MWRsx#HDf^CUFp&TD^_Iq7;T1 zz?GYOi;-roS9uaA9ScFr4YvCJ+Y(>tv2|@WyX0C_fhg!pO~45VKnYC{rFx^jqi-kk zN_qEucB2}#3Psxbd|`WO;Cn#oy99w@E8+M7PORo}-01oC{Rjqj&MbK{Z#KDxw7R|~ zk-^E`wc~E?dj}X4c$0;r4Nq}Y67E+;X!xRi1O>}U>gIU}&K0H?vY2|lUaZAl6y9B; z5k}&06iCYMajE4fX$%4=M9>KK_BVH9+nUTECv^jZt#yxcuw$5ZnoU;nW_oq=Jq7^j z={J1Wl{YKh(hN+fbBaU@*tx7zi+QmbreCqDVQv*@T{}-(3mo*xStSuD5I7b&ToVavr#* zHo7-V2ns^e84O@>wY^?(?EVgrIbNPIY{OAq_&oR1uYUGlAh=M!`X4|1(Xrx$BrGS# zJa~xVZ-4)O1cG7gc%Qv^^pUu_yBLj^3W0Q+dq;1-`}bF&ubMc@mk)=tnW&;j7?*Rl zC$ERctC^@4SgxAq0-GR;1z|Hdi5(d5yzTnQm$n-Ezx&5ln_=I6KYN>5rH;15i0}U~ z)Ot_ee!E`YT%sA9&tg^my=vz?nJ2-ez~V46I?_u}e17)s(?zSVJzwb<(L0dOO0}C zab+9ol+G2}p1fT-7EKe>;is)#N1WVRs$~xLOU2ev_d}LR-7uJqTshB`csRmPS-YD! zf-Q+7I^R0&>{W`k8iouNgfKk0PaN^aRnGsX-T-vLRM9PKxe#WX+p8Z)j4oXM+xagK zA6B_aIf;r~mZZsCTCHSRTKQ_NU)_;rKmH3Ch@;u1ysmXBja;r!=4#D03|4D7s@uj9 z1o3AE10Wg8WSvTSX^ zpH_eRD@S?v>&2z8alM(~`Y60R`1G$J;9vj0xzOfq&ka9$*4UX}&*!r(h2scG92^^} zC^DqsK;TzDLlMU^%rs>v9F5`}4Z{RpZNe#n;CQu%W6PPM8CHRgBSQy(Vt(&2LCP!B zEU+lP7$bjLgs^Hrq#ugTS|wQl6%>h#>fe zB*amc(G=gX)Eq}qi%A+)+r9%qTrEvz3ovQ#7W1nahB0jap**khnusA;ie-v!8Z_G6 zD>0HdnQ=_H4QJz<+(L^(1x*HLf|omgI|xA$d-Y$yIQMVxVk2U$613 zbJjU&?UraL!twj@^_?$4ara4eub6-MVZA|Nf$#aU>{`Bs0yv#3<#Ms784T?QzHhrp zu${~&6)wwqPn$>0VekCuU$d|yBnbpYv2B@>Ay}&K-Mm}RBuUd`VLjihg-z(1nqfd- z5X8||+$tMA3_uWpvn)vg5QbQ0E!jRxLXe~-X|ELoyZz&{GM_|A%oTR`d~de3J+4q> z>(xB7Rp7H+r}p-Lj3=Tbsw76BIqK7&G>40;`>Qm;Q9<{@vmu+meC@fmJ5xC3@p-3@ zQ!l^2-hdf_HY$c93ZmkLPJqJgCV``95Zq62*s>f~Ra}*8=#uUA=Qj-i03ZNKL_t(I zJ`fd3VGxC`#}aILaq9;-(m4vP)<9Tw4>0oPmFt*B;5GZI2m(>iJ3`RFk;Sv06nIxM zwS$iw*)bKZz_#~vNm6(|3{aHgT_<1KE^wSJjjmm%*~M`~N1)zGY&s5{^v``|vBVK5 z>m8@jW@&4M^8RC6Sc{S3#8eaMFEfZC%H-5HMdj_`0?`eKop|JOqfm$G_M) zq+$qE^uwkw;yuNks#nu_jveh5Pt41gpagmHqvy;h@9uI}!hp1t_R+4D|wxW`ou znPGj`(n-2f$x>0UT@YyUon9EEX_~%Y!Elg|EIW*nl*Cblp&x%p7v z%`9_^r8EWsKiEC&>?giq5LkipE#C!zat$Y3)3F$qWZ!%zD6Wsf?EypUn&X~42eRpP zv0SbfJHoANAt1?`il$@8?juw3T$bT#aTIu(M&My!s9BsPL69Y#15H>gnw?tDHO3}7KZUomn{Tu`mUsV*bQX_Fi+-j*?sWlq5ez(+wR=ZFEV$0MGbx|(m8lmp0f;7Ds z7WGE^ynU2sz+knVtxN&%5oG7%oyYe2&0B4gr%T-&n_oUL47SqY?t+8niSnlw}gRgc@i3~&HP|{TyMV6u{0nYN~&2N=;V}PJsvwPAz z=4%v=Ap~w%is?sL79}W5pmCa~Q3QnnAW8s$CHZo>kfV2Z%f(_2L(5zkMs`}hvevh%GUJ$sy`01&v_`C^%- zY37IB_KQDrjW^%kPm^@K1%R_d-xpO~n~MeJU|6XDz_;<(j4`6UKBGD(w6j?;u7a5Oq6EE`>dKK_P<36QT;>uJ*3 zM=}`1F}AF%2r6<*Z5UjQ47s_-4?<~s`%b;X;3U#S+qI;`+Ii7?eDpDy%Ijht z$4zr9Tau}K_gax05ljLH1br*;6vMJ1Pn@oO>tgna{~fn z@^OIT#YSy63vb@E_xO%)FYaP{@S!Jrw!EzMi}@@oH-R*;=SzkFK>)#HK9c8|;#onQ(=%%hAQSW^EMvye4TB#2Rz|fZx;tU=pj;3B-74gAG z`P%&TO3+PJp^(EbcOEbq3Mr~<8G^RypLd?})t%$eG>qkXek*SwC{5R*ym2><$a2;F zMuTr?qO7<+OLYd09>t5TA_$A+y&`#j7-d=D34*GO?j|?B5n963kU^kzRID|I4EgZW zz2inJuofH3@{B;Ww#wX+G*m8MacZlxdRV>g|K)T!YC0fG)|>YCc~` zvgP`|7u<|h*>+9ab`dDgGSrtpAqipY_~m?#(X55qDlwF#=IK)2^OIC{;WD(#pFMx} z7bNQ2-@nw%{aw@0?LqtG2?WXO^=!5xF)uLvvthCP!%NMI6CB+?z%WS)d=M<=dp#1* zvis@Pcs^ZUhelxeF5f~^Ri_A!t95V+f|5YoT22xxD*_8$l7gTjpRbf^uF*Sf?NbFu zMPQmMc5u?z!bp}@4-(%Hxn}(YMQ&evR=!wlSn~ZScKT=Uzw;E5f#Fi#G-TPfaolw+ ztIPqJW%3Oin=cCN-iNU*ZZM?Tw-r&L;LdL3Ch>gM>8GJ2c!8ynSbM)#0mId%+h_8= zrRhjo=4q~2RA(d(08p0C^9O7JgH2i04Rg7Mt;8mBoevtj?M{)gG*Q72mQ9m5F%1~F zd%3>cdDeN_J&9zN+&kNO+Gt=|;6h-lWf*aiBp`^PrfqvPq1%FCn%m82x)FrU^m6o8 zSx_`ig|2Jic<837=Nsx`e0Q^&DVy2l`gVD>y*E@t^F0)03%2Qbn(U~zZ>M*o`{mkk zH8aZ~2tynn1SvetKp>1*YHz3BsUw_ZgkIv7|Yy4umT;FXx z|G_B&i=rs|f$h^oo>r~E8{J{h;R~)I&G?F@trzzOM|wM|7^(k|%NG8lgoM&F%Dk;6_2Ei_`r_ft^O&&ioC{$ctQAT2SQmts`}Z@>Uba zx0UMsIE=Wm<1qAAsqrYLX-7{;S`&3;_#h46{OH?HenFv@ilSWe>7OqzJRb+ozOEGW z#LdXis@3jUj(z`bJ>kmva*m!(=NJ0);PbunKnXlH=cqTokKFw)pum(NFpOwYUM?=> zoB9D$DYX(?6(KN}!!Qh0jSBbfa4kM@oS zdpO7yXo{tPB#grt1ToYNR%#OaUKU-wS==vYaR`E86emgIc)A_O2%M$5F64{Qd zI<_n*8U!W@ikK#jQzVJ!Saei`yK1c6Rm*0&gyD69AF~21yJ6!kEuJ zd6*`;p;=*Yv4X+l;l%WI!K2X-b|D7fM@UIMM>Gz}UTD}J&rl>97eTzY@y~zcF zk`!C~@jC=Awp2j06^ zSGQpphPHFRVThdpffktxrz)nU+XyTgFw`!WiYoy=q79?Kh+EssG6JLUXP=BOM)yI0 zBI9M2ogQ$7!}C1No26_x2vn~e?G5)x5`l_^ zexIS{OGB!6Ruf5O84Lq}jf4QFAM=eQ^4-zP5-*MKUT#M~1cBF=aoF9Xa<-hNf=uI$ z!Tl`=LZD~S3|rYwu3ta=DhnJ#T9xZOANlWZv81sBW|9#26m|MR9J2Yy$5050oSmae zJ&kfTB#VRQE(|a4Et9VeKQ`*u zMCN>BIf|kvfwkQ%X7goat>-tdTv1y&swK!%bs75zj^IhiR{Bqwe4%piaieqk+1Xda z<2)I8VThx7wpQ&93v3pZi^oS*&i9H%nnd6z4k7@+P#i@N&reej3_=8EXb5EJMq{ww z+2v{oBCT)UOsB$jwYr-wl_bqF&1vy1e(wM$gsowFzGendlCl&-@cBXx0NyWQIy-Bg zo?~bnQe>}}#t1YX>vobJ98|fZllK0LU#%|Q|7o<~3nXDVYt0Q1$O}*Q%9Y;nX6pM7 z4vrsG8z{hoS_rT7U2h6o30|=LiC4w-m{gENLy|X)wugt~Q?G8Q=BwFuWa0tHFM`fyS<_ zN(4ecCHCmq$)8tuG00Q5!r~51*b=u_C>L`qvE5phvXy6{U8pus8vBhMX{xDL_m{WY z60p_D<-g>4rh=0Fk4uHj;)-DyC%*58VHCwEoTi$&TxznT8?w0GF1PdT{p}Bb{O9Rg z>F)LKOKdJ9`AMBs+oDH6Kj_Xan+1+oni)@jparJ7s z1ZEJ}thd`FQRXVOIHD*JFtzn;yHrF$Sj$;PU<3hyC1$r6q3;gFEQo|7ty@d65O_N)CQa+J4!+=vhefU0Tx zjZ%T`wi=bw4@>pRAak4bD2&7L?aggq&{P`RI$MAtmVp4nB*{h}BS>PkT+5#R-M_&> z>nIJlnl7Sva~B3K-eVb)FI29s3T$I2%rGoVC!?od&o38i4DIf>&VXz?woQsI_XB-4 z3Ic)*ea#HLQn@h@*Y_JVE|gq5%RGvaTzMASwSJ@R+p9TA(hNZo6iVis1iBjOR^pp093}IG2H!VVmbDO8V&aDO z_D-Fr;qJ3y5s5rUvxN2hemYG|d1}iTR_ga3?L02AjV6#VbdHImt)f|~Z3l*}8k+7n zo^QLlk!6+xfmy0(njudoZzq?V8*6E7Gyy>g+LDaT>MFEAP#7)VIdU2=Zn6Z$37Ttk z4yv78X>igWbPp?Sl0XpGR%F|jl;u`XG{bWI5CCdrf&j8OX6gQJwMoLJ7W%8zTA^^7 zG;Glt)^Ie8-2jHe2m}ld9+F@GTo<}WFaEYv0zqLGNBzCWU;O0n7|K#Fz8_s)zcKA3 z0YC&A_GuhNzWj@7ha|P_X7c*mySvR6%$93OColwBj<*X8D^;sK*RV{QcHQwULvu}W zxmGY3Lyw;}&q8Z)`|ceMm+NfVmVGx%(qu3kJ}xvULS8TC^~UnH-Wlv7ur7f~v5Di6 zH@ksierI;ESSJyJXl9;0`zVbUW0u6wTplMee7hz|3|-F~-QA}z|FykW;_u$yjJus$ z$JT5oayrMYp(D!zigb<{ia;jwIA9p2Sgv94-JNL)OHYEcT(z=`CzE_J#mWyVq0vKvr%8tZBrFD{jFo=+nPI{Axw_vo|3kN8rN ztZ{sy->ei!6abPG1Q8g4Rl^MxOVVHvhD|#NHN!A0b-S2OrH!lU{JMf9{^AoM=OP1dwA6B4NrHE z>Mfjo~4a zuCYaBv)+4a8AY%u$5p!C;!EsUI4) z?sz_sqG+0GmTHAjk_C|$1Ywl;q3)Qr>zc+!SW1c-c(P_XI2y&aPoO{sfqAM{Zt#s- zcc**UJhYYR<;AOucdM!Af?&HA1a~vj-D#X2@?{JgP5qF@VaSh64+6F}%*GwE(*5pV zQyYve>Ee6G+HQ5-)B&JWE|t=l#MAW2vu1DS+1($apvZ^bdLjz5Z5oR@0zqIH5qJ>F zW*p^M4E2K~#^A<2jtVQj3S^QRIyO&I>_2u?VQZ)qgy-`PUq3VhkIwWa)G?QpKLb*gC0JA@YU|a z&Ov0wf#(Am2)dS{EVj!vmdaCgzPL*K`GvC4w@FCQRIymA58EfL08sa798Iep$8 z5&%nAt0W#pKt^I97{@3I!(QM7Ab=uHUSj-n)PxiCcFC=y0q5GHVl0Xn#{Q$)ee->LmysYsL|HfUY z@_NiwhmYadHEC)zmM09w5BXN=5O|tsCJqr0PS?%=AI*SxErp(A3Uhr4#yE}OB+K`j zRgTJ$#d5h>Xt6bhFY>*EN}=D2z3~Rf;zV=7csjGx`CQvx-3DIZY0~BZ@X5hrOA5SF83Jbu8c9P4M#1sOuylELb^SdO6>1lM z)Fjtc*2VJstF2mKJgd?={Hl7K#{cjCA#SRTENq`19L;YulOd%=^ZzI5K6*9D5(7P- zh!fsNeBR#gdXqOzWo2b$m+PwT>S;EcO-Lhh0D|BQMh22r610(a+UPe3kT%+BA!r5y zMS=oNJ9d}rs?17vz5Bci@7;;eg1_Sh-e*UxdFJsuu}`yEg5i5lpZr2>t}n8r+u3_6 zsH>0gqlOo}W`^%0iFR`0$3LkL&#aLSBB~M zVU*@>z)&?cM}AnApd`u3G>x)swTzt5sdcsMCWeX#v#dTE%d+}tYS>tU-Qs-hfu zr(d-;)S5Y`>GeEX?|SOXtEYYe)3TCI0~^M_KS{}keji|ZGcuh-Xi zr?#<+DnO}QemFP7U^=C7925wY7+S3TK$GA3 zv*vbtAW0B_((?r2@P{mCFENlNkaGOK#soF~_QPtr>gPvbiCNAlH}O zo&6sy&Z8)gHtzG{>*p}rctn$n(R99?xns4C6>m;7iJ|jU(dv6ROnrMPO0&uBum}^= zxDhJHKk0NIez3nU&}ke-VVq>T?Rs%+yGz}*J$E{#V3y2B=8PsHb9tUPjI{AVZL7Z1 zJ#04*-Z}nc_o0N-7(y6U6mH;phR4%MczZFKdX_mEz0qg4=jQn8t#6)Rgy#A-)JJcP zkukjb{^m5c7-n|v8KIj-dE#5EyXnnhe0OzoGn>w)SCgd!%AQ6MX--pB4Ppoh{Pw0I zwz_fj>gAg^qotpy0s+IMELj?2I7YxIaU+B>L_nGp*o6Z>ZT|7UZyYv`up%^rrE&A^ ze;B`+-7OcE6ZozdL{S29fx|EiqX=1~NrFgXo^K4An_5+o_U@Ni7}8`#CJEawvNFqJ zg4li_(gYrOg*!VXNU0$xJinYy#zYo*&27)PyNx4;k*jho_rs7ReRJbcZD;cdS)RQa z-3hSF8(TYDG;w#G#mk9)PEpPMSHBs~2mQs=U3B(qo5sk}Sq>7m9)%lSUXZi`1>WeE zWqLcqtJ%%geWg0O=2)@P?3}$abVcaiSA~l=46*$zcPVJw=eJyW_;FK_B^->WAQ5V1i+V1h*{k?}M zUQ@353 z1mJqMGLv{XN110_pUrOEi8)@~Tz&oGcOXG&957t}-u9z-qix%ZXd+Bd z5yTwhco2_MiVQ+f#)%h_q{t`f+KiGY36daAQiKpHN|MM>l98}gZ?^;vVn_E0s2dPI z`e^UHJeuD`L7sPdG&7kljUdLbATCRaBq0Hl6rrkyV>qA)Q~<0f%Hm=H54oMeYKk(1 zl9(W98i1m}FaYWr2GT4_R0-l6n-pxdAf{Cevn(ZE;1}!B)LO4*v&%}oIzU;TfMWL% zEPZ#mvK@hI^c$OHmPFOo^=0fOwxo3*G%Bj5)V}*24U39Q001BWNklckH*{a;MVbkH z9B*w&>UwV52yxtlA9psFcLaX#$FsM(;k!HcD!tR^lba8Ik$a9k9Z5|8K1xnsSaYSa z^+@27&{&**0YUeEZ!^^IMy?SqCvQbfY-s&xnMOFiSWZ@1YTCB#TgG^DHo4Si-Tlb% z*9B5qt$SKeu5KQv{N8cBZY?1u@m@%ihCMaHF!UlHWtKT#MgG;|D$L%y(LMK2<<07SH)M~F|?$-{jFMm^2gC? zqmP3uBXE)`5JGv<*wh+ZM-aG{KB5^(j)KHdYXoN7Siy2EH5_hi*84>g2CH$iSKlh4 z#Z=KY-$w~amgw!tY>0&ipUJYnLMRFYPaivz#?H=%-AxknOhtsaDB#%AxE#(`X^dl& zi_yjC+?p0ipgS{^HjgMu>uc?bw10H`{#M^N{Se1gF;2snCc|)Uq^TP+6oxHkqmwt! zz4h=kT;nAqYJ=X9TI(G)Is#Fx)YQ!#mLRZ-+^lIzqt*7761gKX_igXJP)F> zq)1d?fFgNzVZ(jy7k??$cvWuI`qj1|j<1^ihoA2~I{Xx*6wAtiHM_YxSq$$kK#`}m z4S*MBDF7q^aR4-BVFY2GgL1I1-vu_W96sqD*o*ZQMK$iNP8im)G3?!sK>6~kB4GH) z^$dnVXff^W_Kq&TpHEQ=@uz>$JK(9)*Fo^~r}HzK<0Xh)ovub4xAVj9;|Cw-_UTKA z2hPp+8~YSZ(|Hz#4Ab5cmC$7ctyiMuogj_x9KF32dDo{;e}SRl^;*X=Nn@$$&Am@Z zQc*9@V&~vvh9!Wl`%AGxF?mu^v2ri$7j=v*p9rwQrnyFR6CWX+HUk}jf3|N-f#A+?f!9Rr_t-( zqsUsX-m5mWidNAo744nRaF9l7ZR1E$Ax2VncR_$*X*wKEXC%>VBr!#lAWC_rQPI?P zFYx9DD1&&mb{sz}%ketRNg~ZMlp|1HSnz;je1={R&%TPC!0sKFX>-R}R5ur=r{A2u zETY%nMxkjruBs>%0BEw^dFTCVwbdDq8Z{il@hrpfUR##++2rox92R+U^+K(UF7Tpt zZ|8&F(O~z@*B57jjpM#MxxmZrK1t3eMbY1F-)D-&ILoFJ5jOUv`q8^oar({hsxxRD zsO=(PSpXPD*|2W=@4oz}>k&g@Sdpc%)+C8Mn~qhD6$ldL-kRb%`=M0YfjpDubiX2k&hj z<5|5Ex)>HXvAe#kZ4)#~D_acP?LGbA*-twC^|&T+v?3-+90%drlz7K7jnEI>^~4+p zYk!5~jh)_ot<%}q?00)d_u0brih`q2kt3RHR@}ggvRv1%#<=sqV23;JCjDC%wvmD2GCPxsbiJA())Pe)*-TQIy z`rG-kRwc;A^?Z1Dx}KKN=a;^jrvOhNLlovOI;b(z$)(ngB^P zhR-9E7g@E3($UG~3zmE5r_Hv#^sW2vRojcp#*SPy$G2DRqOl=YB_#>XwXBLYn$II+ z5qjYY;@h7e{+xtbO;jeA=cl(9&fVRM*bY|CqChw#=-N(ad;39eu=md4V?{KUD?1GG zEJ;C`rk>}!jy@l*N2^TNur`R0+@n!a7=qh%ataT2cPv+LBL7*G!0 ztu$xXuAcj4-n_>WT4i##m?eg}U^omL-{whu;IA=!^S$i{d+)vcXV-PD$j3mV6Nf10 zWnLnPG|oant#+|OUs#LvWVHxGQEcvL16j!v-?H`jxC~o|dml4}Yfw}cOEr`(CRvyT zlM?{U)$7ZXvuI9d-k4PwiDbM5RnP|va;N4_hs^S zG&cMwj0|^adx7gOb>BCP`E)T3%`8|CuU>dM2FfB&7@^Xw588YE1BDq3cJ^h403->a zDoaWn+};KOR>a=jMHGagZbBHRs7UiTEkRkbWVcU{H8V!!ThOgm=Rz;uwl_gNg_M#Ajv{`_aRD92-Sx#?s9eMUED5pZoCR zJfR4VAt{>0@#dh}t+n$+R_gVg`&im+)?0!IAf0+OU!LAmQqXR+?CU@5n&^}4EZD6>7sLkPziI*X?g3!9V3;fNa#&%@gTw7Cnp*0zC`lh;Btt4&|+fJ75J}UCikG%blsvD_y z`D%H`@tm9|voS>qA_2p|UqPVuq^drqXiZv_eB=Ebpqszh3(a)$Nuve4GFb=W| zS_|l zq-l_10DvfEC;+0w@zWSXzPntl*P*+fPw%X`v-Hi>4=kFiZ>nuc+1TB=-x-8<5?N-N zF*HRbaTrb)Y3ld_7bO5>d07ffyGoL2JRaRH2pko5ta2oQ5KZD(hDewf6>+0S5S2=$ z+TKRl<;iSCLNAOHJ5a^`#%fJqB9DqB1E4BvvhQIS1_%OxqFAiHnZqA!Vb zr9u!{;yAK=H!2HJ^gPE?L3Z0e~O@Sj|?+C-PB#CL7;<9LTb#-UX zDO{<`>fr~ioyfL~B=*h8iCRDUynPgzG`AW?M)#e@;qr7oB}%o~I_@3Ud+k16)>_B! zw(EgoS|oh)ZMZHIvCh|6mE||KA(D9tQ$<-K2^@D^l8nME6=h>OIjME`ezAR8`GO42}8#% z3V?yqv{u&2C2@e&G*D6`OG|vC*6M_TWlwY?6lqje1%}G<94R76P^2VOq#UKGZu!A{ zVK3)nNlFujNmEqBso~yDSSrod4oxN*M{{gNn=V+Irn78qdw!HGeR#wl?5}QTS9t=; z(do@up7_RcL{hAH^v5cCoPX&owRZPjeWSL^$#_}h7_jG|LsK-7 zrdfi6N=v9}gG!q$ZGAB}3{@ei`Vj%0#q?ILG!OGwP-W3tj^Dtdy31GVhwa1N&nla8 zRb&IpG>X!9Z%&PCdziWfY92MW_CMTzc=Z0({oeN8ldXgHpf%8H819jl$6<#if^V!;1E|<&6+%StIb*I;}QRv}CmhdXWI&K`7!1r9sw?a$Q`VTgL(0u?4YhhbK5CpIkHJT$x z6iwz?HXSEc;>XtbW$Hx6_z&KC^I4}Si|hGtG+SNWB}NhPGR0MP6UUeo$TibQu6DMo zb($`axiH2>T-%YGD8NcZA;`<;46N^CMPxI={O##)cK#WG@^GD2C*uJcTgmXn*ei_6(* zs6$8#oW`moJvci0Z1+jOztQXUYc)-#U>HFR6%!*)Y0?iBG0#0e%QLjF=6VvLf+iuX zs**U^X*9PtJH2{Ot`H=SI|d|@Xmn>7wjU>H4slIt)@cfqjat3l-h>2(8EZ?Qt=*6% z;}jKfmgPJPaa0h{@MSJaNP?zliYDuIiZpDFR^{PrZrYK+r~*Y)#-6?SWfZNA zqVS_m{gXclozv&1*Q!X75C>puC-5k`vt8-W&MTejmT~vD|EK9fSe6IdJNF;|+31_+ z|LEA2svzUIpw>4@HgdlB8we??(%Ab!=dm}x`^K29XRa$rKlv{iInV>+>%YKvW&d4)LKfL5gD1{^CZxV{OW6p$+PoU4AbncW(Zvmovkj?bXxN3mM7|+<2=IM7x`3*HQZ6lg0dW7-el`?N!Aj3sV3XvMObH zk`=|30Ut<@-fiq=L0R-4sG_RTWV7SDMbW60B}vjmS(Asi;?P1aWZm@X73EuG6F_rpa)O102k*CU=Xw)F$bBPgU;WyODi* zlX?-k8FuvAxaH;Mu_!KY zmzUcgRJQT5d#^|wW3@8Y)8Y8iofQd|C*JKB+ncTR3psDa~~6m4$D#cD5c*&t+wEpJfSH6lGbKC|5*9iDSoS z>53Lbx)DdZ9vIdF6k3aA1g^~Eq(mgialDvB2q6T@vhcmt;_g}&PQN;Rp4qLvt*5>H zRvU!#Ws%2$ZGdcfcJifbY(0AVqmTcrf5;1oPY}=k9S+*P-JQMr{e8S7F~gkAhEvCj zB6D3N^}bR+{Hdm30ggw0XhZzjzY+P^wM^4C?fLTV`rhN}puSmVfdc?20zC^VgQK6f z4~sCc-SzyWv7^*Vv^Wve{s$D-d%XRmv_sbqFaW^h_U)IcJ-J@K)mpp%s(tV9c>nR< zQE$7dXk1kr47LZ=ie(8r0BP2$eDKk|Clcq_ce9Zmg=rE-agyZ=GtF2k@Xgh1oQ6>V z!Rq$r_4L}FdwLoHs({jVgYZm;ZDO}Y!10|kAD#rRS~n-JzS}$AcobT^M8El=aqz_zm}^nA}UMV?nEHuma!&8_+tL0$a1(r+It-Hm6J&fs|e z5d#uGN%LZ5dv0QRMz}1?dbiS?-M%?7X5EeI_STb%h9#ijSyf@_#N(9R&j$Cy)%-5< zSq>5;14>40?yGHp?762GXgR`>)L5M)E&$cR(Z`*(ED93DC3(Fpi^+(=gZa&ua-%GT zYJu8^ho7`I+Ixe?&8?&Njz1afx0`zp_CC@2G{v)<8~sKSE-Z@RSkq-FR1_$Vvn)q> zW?E%#EIl_(1K&1R^Whmv7t`feSZGkKg_Qp@9ccO0A&)}7KCY<=Ve)zB44X= zEI~kAkfkaw3z}N5HMHvBzB#*_QAAbMZQZX)IZ87eqbXGu*=}pFAxQ;FvjVO38ysnGrCLCvh<^){Wv1YC?d(7lh;FniUVUo(Un$f4`qzVY4!wV_F_Hx z;;Wk4Zs(b--ChwylC(R!@05i;AtDU?F}^a* zAi}V+#4#K%OWWre2ql4G;y6ySEJ|=(q|%tAYdy6SIr_LjQk4-R_vX#ng%?6R&TzacB`Ha$vZe`=W3AS@tq1`4krPIl z#Ly%{LDH+msUOu82yGAIK}-^=n51zUrzQBODfU<0Po8BdhE-dOk*-6?vJ7LIMNz8{ z4g~Gwt2i3$;}GSOYe6bYLB`?58wjJQKfrO@%(5VmBvGm~n>(ybGGddfdUIzAz}43T zWiItq7#dDhVHk$N@%e)1_K!dO_s#^8%ky9U$1DfH@i2^MRb{#mc^r$=JdabJZ8dzK zBsaG8g;LqL*MB#%8^`X%o{V3geGlP$xpsc`lb`;N^Y0gDi`##(Gt@@wKx&nR(7^E9 z-%ZcdW@C@yDc-nomuZxzDAzje`(hiV#uca4?w$Yb-3wM++|8#P2Y_j+YJZ2Mm4-P( z`C??62w_+dO?6Gc@gU~tb|Z?yxL&1cnkh?^r>SX`WwTLhXUX>C?qhdWAgPrn>q{JB zc;qZ^0f0oFoxG$dj!RSBj1!UoAjxnH!*b-u0z;8WiV8O>%BBKwC#c92$+3z`k~ri= zwMlcKW3K@alsui@#&NBo)Lb+0C^`yOD^07^m$POk4%aKs2S5_j)C(-HB0*@n7{*XV z;e-+!#3T_W>!2kKT49vs1mroxw)`X)=&u&o|8VcW_@C2Y^5*4NS*B^SHXZc_ch^P1 z^RCMiqZC8bXpP3fr77i{j|$$N#mzQu@l~?XL(LCvLvFJ6$d~ZlyDHoJ5J?35*p= z3`0`npy&H(DvI@{Wi-2acJN{IUgCwOIU1dGc02c-S^s_GDlq03cjvav^W8zMul2M+ z8r*(8zsYm0(b%f(Bpv`+Y>v~26-kCu_kQNjDFMS5FG(&mPk&RO+356|BB}~Ow7YNL z-n;kc^VQAhJkNZerYTyKFV2?6(XJp4hkob=n&d}bRFz}_0Gei5hTVJIf1G%E!boMA z1^~ofo~(xqpT>dHJ>WGQ2By1CLL3sLG1r&NRhF+D0tW!c8rsPi$2MvbPm+fZBOk-6 zU6jRv?<5gHdQKeM4um|1P@XdkMIjVL2lpGBiyJ|q`PW}~UcEt(W#PFrV;ZI%rzAm< zIg)tGP4lu8SO{4f!m=bu2$O{4TsKOVR)!c-6Tco}f296*{|$yw?AtH5?*njq!i%CB zx(F3$GID*6iIZ-p+GP07A<81RK(3x8dDh-h+OPhJAdO{FBuSDG1cYHo5Y3h#Gd#oN zu(kz2o+N?VEl}c6)PBL;^Xp{xPXnTw2i?>3}p5*E6tK|&GA-uW^ zlTIzqy^tm;5`cQm^ZEnZ+_~S{%hNp3HUcB|MsMfi&;M%wPbOatzqJ-|5Cy&$$NTpg ze)|Wt!|PxD;qNSy;}}+udIybtich@Z^Na5lZE(LV^0c;9*`|cDu!s81)pzS^8iZ08| zN5*(^Rcq&2S$dZ5iE^6g>mZC03?qr6h>|1&AVu5l-bUa7P!yvH&xt~o5rk<`l;ht0++qU5bew1e=a;-AGdy|HO!tky!9}n(rf96dpoy3m<2oZ|oAoRl=K|GDq zIP~U2yqI6Ehx)`E+q2aj%L`SS*?3Uxk<9adP-|K2F4e9zj4W?TOF~WVVr6Bsxpn+m ztKU0l)w<0e{bhf1cGYV31|$SvzG7+13Z2XEzxl1Vij3#KnO>De97|$qgR-(&+rSEY z9r!r@?ep8qbS(R28U1ouc;c4hDinMXq*yHKgfB9wP%!hZcRaI=DG>e+|ww`Vt z?|mlK@NDa-TGN`mTHWUBD4`{(lep$J#aFi6+2SONX%-T^LQ=K%=3`bMV0RB?v%BxV znT(4(^!1hRO~z3W$9cY7l_(4mf_NO>Tuw$PvX+-`N7s09bFv(@2KDyNQEzASsk`VM zxA*f1!yO%^tMPP_C+nqa>+7YSC!QNb6qV;uC3*tC_JziQQOtU!Q*=i-v9p8^=(hjg^+-Lh7`{)Ob zuG9!B4$8tcD=kOo< z;Q#!;r={8VtnzpN+t+W}TEElkHMi=!jGV`3zb5Ijpjgkuu!A3}o6r9*eaZ@No@?6E zpRMnz{j;y$|JQjEIT+S^FEnT|k7I{bXRoq&@GP>t)x}rVdhc=Mg>DpJ*m6z~7*>`f ziD9;#=c>9|JO19*d{NOPISfR}P(k^9001BWNklW;*TJWbnfoJ`EN3ULgp zX}0TyJR^&a_w^9_&+0$2cy&374gaJ2dU>LQIAduP9K&7#1t)q>*yfW&MjOBBTmmKg+sK+|REx( zqxIbjh_@R_5+@i|mOQ6wB-!W}h~_+#lMa7e zRX#v@)&+`D<}mbC`eqqq?z^r5;!y$=ckiax{grw%#dO_2jEqk5B z5Rw!p&PN>I*+zMuu|iqC{(7ayX}`_$vW9X1vXtd%PN}2ZGY@~b_a|TdubUsRn%E)O z*ebI13CShi`1$;rVmK-CY&{CHOjZN0(m?rQ`jdYv)cut;v6sG`r8LWl1v>bl*i3`S z!im-8FaIBg`S6c7-fO<&&tLsVl*8(jd>q82| zBikB>4$VvT(QBHGgV~*7Bx#(42}j4N9mW~N0f4wbx2wAC$4xCx2$<$HNmJeK&I6$m zxhO+< zhPW5jRDvkWD9-aRK3x(5BR6qKGLY~rls7i6Ua=f6YV9nsmrAW4K%%$L2-ckA2{KDP zhZ70}q3;s}&tq7Yp8o+M$Bu)}0mJ(?K_-EIm#4MOPak9vhFABTv2k0V=F#l6)R0qpxM@Ln#@k$eTd;CTiZ@UUr!@Qj85mLt4j=5yUhm_ zU;iQu-Sy^A7T<+>_u()9kIj1@{XyRZa3R$i|04$aTA}Ac{lf~FD zX1d4$z%fw_uCq*07)DZYJoF9S^J%JDRVv?po1_><5D3LdS;h&(UEd0}+i?=7Q7ns% zN}5^jznqAIWDyfyboTr8qQ6s?Y2rB~bvryf2>r!PS&pt*780wasBFC}R5u=>%%07z z@{HkXZP(0mPOuHfCJ5a~(r>>A9GbQDT8H8&HcKM6x`PvezCNq&Ngb4O)j(G__&QgE z)b%f?CtFWjk5HO=llK^Wl&6;nlAS#B0rCc_Rz_Me3I&EBQvAmLo_K zbZ09GkN;@(vMl7jJNeW9sq+KpcJnim4_C_e?CUJt`E-3g_<~|~KSY@`heR3?l-vRU z!^=Y5)Ndm9<*!LHiNg?~G{rDMNRljLn41ef*xFhyJe#7!pe*$nN%^j6hLP_kahl>d zK_KM1j=$M=T>#3`@pHsb01!~*1h%SamE~f-W~lwcEQL^QEJrM#rBTSxQ8YdSU_5lZ zG)wa^rU;J3uq?CO92LcMCh(%DRq9Ou(qz4WIL{VES)wA#Ax;oclI9SXM3%7}FLb;x zNl{q}Op=wLC{am_ob%Hl_TSw== zEzrh8du~ht2*-}gGDT6ZTDIq;iDg2fd{G~;;^Y(nMofH9PeW}$F#ZC7)miin4ml+- z;~zl9Pb3xSVX^g|N)E94lZRy>u$Y*$CVXu`oEufBF6RTULIwT|16+X+!F&8?n=QiWBxNtC4&blm&)IX0TqqdGSv# zPatHdvdj?xMImq;7so5Jrp5`5C$S&!d|9s6aUzQl+HO(E;$luw5axLhWO)>4`S~?P za*P-F@oxX%Apm(=6p+wbLd99G$9dM>hlH#9mcAzKD9SR1$+G1fQ4&yK(=0LqaLp+P?y*Til@%i-Z`ZWc$o;AU+&1Z}Nkf3D& zMW(4NDOy`V*hiwRu(t% zK@x!4Vej4T50C$>^HAw%J2cP9+NRVd=n@qfO7d9S5?TaJi$#j#YF|*zi8Bw~z!J0~ zn_X!Qp>g-m=U*lso(oN9IQ{~ZkX)Xv&(^26UpwPS$FPfkjLou;yNpaAJRvYqK)DnA zi`boIvh4a0rzlCZY&Xc#r5;28=VU|1Aq zX`YiL%aUZ07}nZFg)DF^MWH;&cutgD2SNe|fFhC%$DDAho#k;_0*KcnnmjiNh~;@% z#$iz^63^#Ztr|tLTojWDj!k= z_5iRhA*E~;Ia?tZMg<@;Vw(~$oM31<^&(Sfw%)~Xf?YgcToBZ9R2Kb*t%EGlZx~sq z?Y$4c@LQqb&ARtq5E*-X`n-L`ug?_L1;~a zN~22eW2!)&u5|;mEU#W*Sf#~Dp&K}HXc}wd!2ymVgb+nZDlg%X;q6te*Vv0)l#O3r zJO?06DJo5(h~tW4xsoL^iDHBZm}FK^mKkEG9A$_iAkI*o2Fq%Sm^GT7Td4&eLKMYu z5C(x^qJpNj+g{M=upB~*+0tCBqljh0h#(+jXmbW}nm8HJL`CEn!@+R^(m4E}`s^vs zCCQ@?I-AvIk*hUcfW&e^(~7({^1LV>g257VHg1s8t&y;bM-Va*y#J0Ei|4X>DUQ3R{Fu+yS)m!y`_T`?t&fR8)LsB!8NRgsMfU=y}h6E>e z;P@dA36cjt<~Ib$56Eu_5Fjz~5G#-sNfafSA~{@U=FZ%?`+oMNPw!pbRh0+-i|^^v z9J|M;QCoe7Q5q~~WzpTSnj7z%b#Gc`6uzvU6V->%S7{lpkeMS zR<;m4yd!nZO{U3od4p8|NKLQGCNJXw5aA$?CG_S`Gz$P4JFUs7-QN7s@WuQN6w`~y z5611i>Wbra@9~tgcm73VZ*keboD7d&Ek__v=WFj~e*59WpAfA`tE;PTJDtYf)t6q! ztUDdIyYY7KfnA57d;gukU47u%J8!hs_uk)q&$f2HyYXc0@!dglix;vsI=yxzr4I&gb)gmQO2?y!DTd@L&&&iRZN@6I82C&AT3_a;a^n$?mv0m zEF^9gVwEPEmH6@E{AHF&(qP1xNoe6mb$2-1*_cc#9_MLVuN&5UIvBnA){p*!e{=j# zy$8Yg*&o^~vij_+RujS`fw0lCtHiFZB8e4NL$$`o;pFt$Y+9|gRyQ6uA4tmLVszvW z6}`2iyRvSt$V4_sBb^E^8wf8>@4iYFvbOTXY^zQY7qO%wEI35r9oEY1?32Msb!F`x znLva!Mj-+qnbD}eFZlHzWqtL%%ijef-O(L)wf;bLX&Chxl?ecXr}OIW{ABR_>`PUj z_FL<#Z{5D|$DQpgS`4G*#v4cyytcuLENt#^CU`u(d46@2XT*?|?mf<&rfS^2JbRTS zlJxQ4_=BUb!m!bL^idYpHsjgJ=YyNh>c-oNpU3SzQjwHocJM0+Z@nYyN55ar&d)rz z-psQoOjBJ4AkWj37P2fvl41-&Uih&Pb;l$^0N^;p0D$u}sn#bWLWs%AvgDjI0FZ>x zbTacb1>^bB&{tO!_2e|m3#MR279yj0A!7)L=0^!tu`E>`#wDa{IRzleWcRkivbViGL5ICQn{x(00<5xZ%eNjRfM1aTqTn1 zGzI5Oa4dU`WGO_vygt;3gipS3YOQTa)~&rKZbxu`aPm#1!OAoo--V%Jtna91kvWyY z5RSshtIyk)WpQY69XK$K~jAQ>WF7BMeq7~F(+ywq&F#`DEEjk`N$z09#e8& z!KbPYfhcJhjl*#s(trkvAsd1Tj%3a8wyNFM{l-J5tEdvjs;tcJ7GqXShflxl-@-Cj z`qS&zcSpBpvw`IhZ*r+>MLxRWeB(jA87>C5(I^R>nq#+Cn)in1#MF&EiQ_yi<1C(y zZ*D`MhQ#oP*C(1XA9}UP5CF~wgCJ03S`;M!5XM=_gmA5`^{QLYZo9W$Z9ou3tTe1} zIhquCStLnWW?7akmvNkCX_}^4mS$O|$f{!7x()yUX)>K^8s`vT3;|;RDwuIqHuNmd zsU#s}5(F6ofN@R1SVGr6&L~YvYS)nDwu>watLp%$hHh&EA-oO%G;3^F&5M^?k0v*= zviU&p%h#^A^PPjweBX7~cLl#ZS@?{7`-{e^B!B+%2j63bS?}y|R_z&;XfYqDnqhQy zicB$_wbtXomqtT2$`k;Ei-bnJlnv6rI?Ib#Hjqq1hyW;J!4XDsnJKp5jPgRTGGjRa z{^i*p`ey*tS33K>Hw{m>TMucZT17g3S>1m7FL}w!cslEkPGqgVNppneLw{nr5)Nj| zInCGi_I|YXq2P=r6NqG^{iKK`l{Byx4I!e@a?DD%L9Edj!puc99iIu0&&=Y^US3ir8(e+NHSHNe*wrTg{V{@$>NkR%N41%M@V%invS!7pzRn6aY!Vnqp{%TX&m= z=dHFLHSZHIU5t;chT#1d#BIK%n5y0Tpx(`wi+<;UNmHBBukjiP=$ ztZthf&0`eF**uwOF4mFcZYrizcWb@3dT-U-&Pwk=ZGH9KWb8D(jwC8w)wuZf>0rx95@{p#E22+$k=jbORR5wcxbnNMUHV@;2vBn7}WB_xEV zw(2V@hFO*fA(Ult0->fr$T%$!l(8h`G|44o5=Fil&SL-@uIDb7^QD3nnX%bY2u+dk z(HJMCqFIg*$1i4sMsNQkvmxuO&|QDvPqKJ1<{W+9`_9@s2z$L`8H`J6RVpi-J@`N& z3K^ZOzrXpzum1b(aec*ZH6HxzKiBsc=cHzJRhvenR=KA+G-9s1vZ=?I&bawZ2 zc0ps^6Fd)RHxOZkrrGlLpEQ@zJgDwgcNb@*ChOBv2o+M_t?d`F)y@N%%rDYq9`RD} zd^tOE*OO^H(LBYHRIGyqsTmEdVcpwg6aa{v4T#b?FYDW?JvkDh;?){kZ)?`kXQxMs z(rmfzqmRy><|*ffLCiGitwlkj+uBrhMbU`q;v2?fdFjitB=x%e!S(p@{bpBDRCV`l zuT$SPDkq=MuLq}hmtJ*nSFc2ISt^QdYDQT^fvjAf#EB4-X}yM!NmRvggy39Jyqe(z zv&GynRE=}S6h%>@s3>c0Q9vj}$x4Qx5Py8mM8yDL?DuB{tC+48L~)wZx?>rf=UjTf z{`h<0T$18QCz?^;xczo<%V>223QgO5*K*U~;-Cm${OaXzgTeaS#1*`@-g;<4uZk_qP7L0;EVIi zFXnf;<*urh-M#tx?l@Uk)ymrC=Xp@u5sXoUWnD4tp0{SzovytCQ92XcsH?WwtnaFZ z(VV?bXGOxxWEu{Mrx=1MW;}$bx-T0vAa&9JKy_w^jYnpiW%Y+>T7 zj{PZwj;ra!ENGfY5<*EDrw}rxD5fEyoYIo9owYQ{3ItulB7$QS#EU4VS%E-KX>q%h zs$jndp{yp+=EL?bR&QTUZUK+Ri@sU8{QA*Pt39_my-s5+C(-q*#hu|a_mbK0aC+L< zS^Ysga@M21Z0I$XM*|va9?Pti;99YkSAf$HN;EwBM{hOrYx|NqJp_Um!Oi%Uf1Aut ze^Uf^2g4(}G(6Sre{=YGGItv3^2^`O?i9)Nj0U5PT_D0iGDi|tN_z3^v)=?~$%r_U zlkufL9iAzYw>CR@^RHok`VGdn2Vei5#dKk}j5;q_E-6|?FxlXRx1BHZ<*R>q{cBlb zxx0S;Nis3&{?)7hr>H;(ZZ?BkMkfcVjWtG>mu9DkWh3eb*VWzevt&Z5q>f~S-Sy5} z)it|Y-EBW?t#x)c-`jpqF}z;7(9G(_R4{A?LPKehMC2>b$21l5XAm`bk~=$EKg@xs(I6e zj9cwIZ*+BYcvaAqjbL$lApr=JaItV4Syq%Zbu6MsNu$gU8CFIIx{EbQnV%<%ER?m)4~xdb`&oZbvY~Z+SBZ9`4~L1r903qbhS&W|2sa*B&GXL;&+XDf&1t@AG|O~xmMsKtzmxm! z1_1doxKbSeinvH*qF80haw{mbXo z&dtk*Kdx>EgR7@sed4%6NK%&G-lh3y{K1c-1ptZ;VY2L>_is%TW7}ora#5D8W}}m* zrd4Yj?)n(Zh750A-<*Rvn?qxF~Zf%bZ)5E1zguAu^joWveEGW8j{GEumYkb50K*%WEc^Y} z!4zY+)?BsfSPcg8G+spWESz2iV;YW6XgIx;@ZHh%YnVrON576Hsek;`b|&YOGl+B> zYXD?RBrW@j;jQJt^s>_PR-7*6*9VNQeNU1hPi9{~9iCX$)(47mbBK^rWfZGGD2B7< zZklbZ5Vx_}eN^k#+ACX+|JBaNB1o62ocUxv{cGKK$?5Waczd1a|)V2nvR<*V@dObW8SvHr6+0KK*pCA4M zEJ#&#Xpk+CB&kJA>Z*&RBIc!HNNSN7O-bfO=erQN>q);_U)gQ%)0oEdYevV{agsd_z1c!)5 z2v_b!!?hpi)iUMf;!Gjy56sH#;ql98sT&t3LNI1oAN)*rZ(dA)F&R1T_q{ToU$Zh8 zaK;L|)qD5-zsnYR;9t*&{THk1=7;~*diAN-L{hXo{Os(TR|nk=aaZ0hl4RO{Ho1~j zh>)BwgWKt;;MGlt=4a`m$P{AKutwuNG-{Q5m2F-ktk>TDH;nR9CPm7Mcp-#aGwh9R zMeBX1zNK1ce;D3v?5ylB`t#x4b)1@dr#l&&W}1%g{Am;dpcBrbX!V|iH4{l#sjd;n zA3+$*^HkMo9{30e!ODWBah6%OQz`P}qoTA;2sy`CG2-yzIL~vc$hAt6M2Qf(mS#~J zrb5UPLPSwzRmo{q#JMH|zyp%HPrHvJ%QoGlGe)DSk-NmhL56>hl_|>st)w`qX zrC)2bH>1V)t}L1>-CZFPKbYkSlBUDS#5But=V9b`x07Y1d-ly}AjF&R$*OLbbo(Pl ztfw!i) zql3ZWtlwDM{C>8~BT1fKR8|Gg0^)VPqgPq3*Rln|MU3?#9=)Kk)oQ-EI6L@1PP4i> zJ%g~wip;1S|8YKf_70~=W%MA7{|%f_Y(*lVjHTWYZ%9Ilq9)D5d7*Aa~{mCO8?Yr z+HHuOy5O;2>D79bRnCNHY&7>8CyPE-N*c^{vi?xkXd2F}YGW-~>UL*)d^sKV`?H~{ zl{Ag|C(FgcuU3Bj^KRRAC24Zq*{Lr9=zXuY4M33;S#xK05zmJgijJg$#?kr9vOKR+^_E#f>cF=G6muK-FJ*EI+^k20U)yo|&C zS>R)Ne&uxRR_YrrD@vM2%OR3z(tiPf(uWAj~qcAV%OzczT`1ty73rpBRmukD~F}S2Po%wo%_*|8BZKc-ikA zWwAd)$f$T#yR!MDu{XbfFwf#ynfn6(I1l{EnQEmzqv6D91AwrkOpl!vNs$eRT90!- zU&^G+u-F^pt08|a*IMfZ@$Wm4+TAsRf zgU<$e##kH%K0>e0JxfzU6l}#4KnPVn9kpx-9kVDIGjs@p*fz$Cqv@KnQo9%h`DP7E zip)9V5FQWHa?OqDG^yyioKTGXtYH?+Gi1q+ZKB|+H(ONPoEC*a;zUy=Da{y@WeF7} zLaHLm)47Zpw~X=3B$|3PROONlmP;Cz``#>#ic(b7lDk^LEG?n7Hi}j~EJ1*Aqk48T z2vjMgyG^1E<}L}dI7bj8P1aQfb3u#YvTBaQoH=UM)Re=4hI6*!T>A|J!gl5LUBi+j zLt|V*7h^*yxo4=dL1w1fOcl(zf-zz| zFDU~+LMomnZPQRM7dq}$f+VK8JWqwlnJI^b1Q%38sw6>KLV$^qV zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3^w(&RXZ__hD{|N5@~_>cbxC5Lw9Qrpv?=jK=LxyP5^wEOq#_up{m z^Y6cYg+KrPm!DtXUw<9>QR2Vp_s3`ddDqL&%Rk;w^PiuOfBpGY=b!7eKNkvrU--neiPrKiHvTKV+9oIehLl1oT{e>J>c*7U=`R@#qTg-9C%70^=F`b{aRAZ0x zY)bZ@@WpzuKPxr%YO-^QAIHD%C7jRgejXpz_~aFMWei*_@Q#1^=lb^_{J;M5FBkeg z%{+v&n7_5+zG6JzO`>|i;|+<3tE9=}VB68>RZ z>Fjg5%f(Cc{qvVl*PjcpM0|GPWCjtE7@kDNm`Tm0sQ_J^3lm z^VCP2dTXk=mip9MTkZ92spVGM(`sw2x3|ZhfU$D*r`O(k@9)cpzWL=^FRy?3!H6S` zJj!@R9c}dSPRwWKS>`kAY_rdI#g!HiaII(6)mC5c4jWV2d6)g{y4&vi{jjw!efcZj z^VP3?{d@o3wLiQ1uerFBD7HZ6U zg}q9hyK&p#Z~X=@YW1z(dnNweO78F7=GW@TbEj`}lVHIKX5|rFcMg+q_~f>Tkr=ao z+xoM5%^&w!ufk8>`K=P?m-}GZL)ffD?O@std5!m};p^quYpyxVGwwlTfAT#Wn_6ai z23v8(ua>)qmAOYyw3O60`*FwdaD~i{?A+3WRlLD_2e{|`t;kla_vt|HJz^N?8mZj7 zHqkZBx=V>~;rDCj5o5vA$`=cU?|r5A-p|w0yvBUn^Q6uizwIk8Zw~L;Db6?V zz4QAlDaamt?oLnVr?}Kg&&sV~VzZ5kN!9C%?-L(Zx8%9@GY89o3B2Duc6r^KI3ZFo zH~fUf>@l-uH4%!|^XB@@-d28ZNJJ&ju}LMIPwifned0d(+`Zah=i@!&XcL3UZ=HN- z;Z7nKV}G9q1~uo^@_a@MA1>Fil28^-5i#(0@Hzrr-+a75x!h%RSBa0qdFpy|ym^K_ zORMF2!UhlG&4#fM&v+JAi&3RK#*@ZqcX>gPj|F()JS+)@K?LUJZa*aCFGTkEYTR7L zMunk<|BM$K;(@}7_vkG1$NQRV1r;0L4%o*66#y@+mEWgW*FzNfCQp@17lW&HOg|k;H#Pr9A zL4pmu#jq>ynJ(1qVbAAf!58~DM!25+?iU^eWIbC4B(bq^E&y+WXdz=|D`Dc# z0HcX~X(T*2u!4C*WUo=d5%zQST}GAMq*_>j#m(?wD-B#@Veau}tsvx0Z-om(jJV3} zGCj|Dui1IhyKPD6&68;^;{(IXUhjMp?iPV576{v~;?k=}rpX^3miF!)$js|n^T~Y@ zISBWC+oZNe!ew_CfWj!#4`2z z&G>>j_35S7Od#P(H_it+t`F$HSo{aSE^U7S;3fcFqhy#|7#nmv5V)g{^tE>`;>n&k zsRSY`CF-i}#VOnd?uu80r^fQm_7aYQpwLTNqfb~lNZlYYxptQr{GE7Rtovb8=0|MV z`1a5rJ1Z0)p8do6uK2KaU^+XeJbHAJ=X(eRlNeAiyyt_1J~#KopS)1Q(Y}SxeZXA( z@SA6GN8s9GS@#1M0wp)w`+>4+m6322qCsSdS;6M^;vJcAd+u!NB%mW_Sga5l)m!aOG)y%Br4?t84ruDx|Utjg~F8DGNF z?swhq0OLRG0pET5>SglrorjD7A~(^>jD*T3EljRrRQ-BS#Kv0TAaH>)z+|wHKu}pZ z5c%E*CkH?PF$9Nkf~R6&OON4Wh(>SRm&i!q1ZFng2A~XaD+q`)F zlX(Fvm)eus2I~p7`R*08`gq*{jMkTK`(tQ!A@I`-TtO}_s2OBaTO-U?F&U4HL4d-8zX%_|SetxG4Tc;e+7_H$od9W$=2*L!^7Y2TqEJ-9RU`8f?WQd zXJ6kF+e$bd@o1YK;J2XqXnqp#7XY9a#KO>zS3O*yj7Crej&8XJE)8+KfW8M#4B*a* zC$nNa<#vM`L1vq1*zFahu*4M`4=Z+7oCEK9nk0cw$=6d^P2AyFL8+ikdAdc1()?$JvtWjI&C82f@ux`w7rm=8Hf(r5P&43{!WxuT9 z){;NA6U^1}iPMvySh3lUNCXp{?iy5Qwz6P!KyQphot-_n5g7Jm5c>diel)ZxMef<-9AO#&k>5+)1=xz38NZ@P52 zEa0)gkck#JSdKZH_PZB`4iX~Q8We5q0)-2@PzAuzjrhYAxCPY7J0aiwZbSz}ZiE>0 z1fl1RP&6#2N2CBwz{d^fEUU|#_F;jO&FMFq7M#m|ZdWf5=LvEcdtt{1Z|?-fuM<9t z^#AUrHn=gcQcA_bejwSr7xZ|IVJyTN)=Ui)f~Ew>D$l37VntpevjMYX6q{Qn=;55$ z)QLZ<8Z54X|3NNMWF419^bvZ1bmR^C2IPQo)lFnb6JHXs;2S_L$OHo5q~$izG6R|x zl3$2M&x@}N1mb|MqcAnS1{+@pRG%Hz%m=C;_hH>1!R-4^B;)$wIw_!8Z}1<}T{o)x zgYk7R=VN<$HTTcj6N}3nurV$Rmktdr#=U8njbP9ABMK&v6meeoCi>KezX7E+*w0V# z2hL3BwRDld5@GfL3OpbIap-RzCbVns$6qYPtv3q5#JnHxg8k;jV&sWn;qNi4v??M3 zjR_KM)(u%VLMM)2Xg0R!GkzQvgj9)ZxYY1!;*slt9Gv2sTDO^hmW1;upcJ}Z8;j$b zcm`fFcU`)F*Z%h%zc|>I24LTC0Obh;2G?Wn@e9@;gn&tLC5Rms@mxK}1pUBg*mvlF z`94V-SP0d50(+mnh#{(Mv>Kw*CLS0uU>gZ)%}2%es+~Vz)$BP60)5SzKA0x!MNot? zm-19%2A3S5T&mb9p8eveQpuuJZJ7Kuz@qgL*K)*SJLLH5I#nhtLeG&X05WVReK2{* zGg0XU9-wb;UL8Z>;X-fUwLiH)u1Y$*1&jI&H}Ja`kDqu1($Hv_pqWSW!jnHJK)tyj z&N0R*u+MQ5OAFb;p7egH?EQ904RmMY z_Xsys9y>>jW?dg3a9!Nx*Ix_(Qoe{GjZknai%^^Jg9V`qX1MS{#RrCKg5+z!JUrNA zsK8dWeCapohlgJwV4WNQw3q;WS4c{l5fqRINg;9VZ6raLbi+rA(5{Re#vp_C3*#l) z1U-8IpK!Ot9UuhoxcB7#xN2q5pmIae6o`4KyJK!dsh4on^v2OmC=m3*o1U@_DIiOG zUgO+X9|be)5*^t#QW(=nC`kwuB#(zjLtTT%HvIy`Vz@-5N^D{4Y9XM($IzUBCF_m@ z>D4Sg`Yqw}7)dAtK!E@Zcs4f)TdaxB!E;!qYz13EPsOa&rKAN+1r9U)_kBPcog52?RoYFknnEV(;ip&;{MU zrb&ul@+%1ua21h`=n7#r@|r0DV8QFRj}xcQ`3qoxK71OC5nsEnO0;D0efB0_VZj%U z(ui}=VYYen)Kh`(5)&8UfDd{SfF6LBfe+qO`H?QP8~{&fQ~GxERp$7yb+j7l<>`%R z0IsI4R=nZG@Z)fI^gs_Ng3d}}oZ(`5Wg_r*%ruyMsR)C56H9YsC#xp_sbdQn`BTfj z@d3C*XYrQM%M!CW_l0r>TMSP<2S5h;$}JkNVRV8h!YWj_DYkIr?WZIJauqb_oP;*);yh`-O4pfQS^x4zU40?w52Io8yrIn^f5DHj)~fPz+;%xgsBs+9`vi znVsqbXj4rNg&~|p%3k3|SotwtAisNvVzLfJ@*KDeDs8C)FbTbv&4=+my}(9r$IYhj z+MnRyO(YCNCZ-6>h@%W*(SvCm#+;^X&$Z+*YB5QilSEYUMhTdpa)yr zL~E@5u4q;83fKi9p7pkRk7&?+>eWn&gT~Wzem?O8+Bt+)&-Aj%9u#IhiKoyPIE)nn z$rbQJ0~J%0fY4=%egxBT3duc*R}o4M`^1_FHS9xyym;V6067+W=k zp4j#n%@b#CJEhxj8~D`=M9e%ZsFx6XFlQoj(`WJx2wW;SUI2$Pk(uR4TqvSD;(MTP zBya=LR9P3^bS&joV(~v*79ENe0JSf%g($WGhREAA5m-N(1CnhThFlU~11hnLR zPR|SRmO$2^a;uxMuveEH@A2m1~>YT@sFywb|hciBqU4$x_qPPO^VP(l9 zQ%Jx`$-RmhZXvM&Ml2#N3*r$+eJ7?4s*ftVL4gY)#JuIU&;WgjFsV>N#LQ@>PIfm< zh4Nr0ZY~5rCt`l+10V^{CK@k@18`s>`b9Ewbyz(_DlQ^EtTxLPYSMDrLR4b*^-{Bs zieW)ou=`4kIoV*PF^io_sLfpl{2;Gz$^=^@R6^>{v99_9!8b0@UYmvjo6Q4SGhD;u z?EQ=Jp0I$QYr`eY%b2~bK86KLU_e1Vi}qIx&%+K4OhA2BHkL|wndZX?3@EP+%QM}5 za)IVo#YKT9J)mz11EJRTbuu3aF}w-dJ5PoT2#{0Z*~F*aEn(_dfCpd0oETIkWel7B zFuq}E;l7MEo}MdxQ9#oh0?N!K!+LK%U!K}pIJpa$J-~$_Z6!E(Rg$MLM9gb|Wjz`E z;41+nN56K$|GU=0WiviJWj-vaRtN>a*{`~!5gb}r7-v)KjgS?j_MW4WPX!xSj8YRk~N%v-h6fqfGLgjax& z*uciDw!4}H-}Izm4&X0bFOPvkde(%PBA~PMhF)`ycr4tr!mK@TBicb6!UuwU=3$b@ zk}??U5RTIv);jQML0_AHH)4%)B(NydMMbl+2R}ihMYOF8_~7qyRH>@ z6SoIY)D0O=d_KQJQNq4V;={ABCN3E&9QxD+KGEZ{tx$l9)sB<^{Bes(v|wwLF{~)7 zz|BM~fDcEOLQk;|gmWRnCZ7;tYlJjR&Pp*{! zwgKG?+kJ>2_~G)%%!7kko)1th;le(NRWMi6E8kH}1i*R3bHNkf1>aYcGXsN&0exIN zkgExXjv@XI_>iLJih`Mn;t6GEQ#R}VMIe}P4K!hSaTzLMpULCBd6I!x3agc&u*4s3 zjo7~*fTn{Eo?3mz9u!ZR#CvXm8#NhF{dfstL_*^2ykcpPtr?SQfFJGDS$%W#_2V(k z-%c18mN{>aRqW}flnCL$9f~Y06eAHfXM)uxEZIyQQrlCkVqSsE@s#%`Jo5v>QGfU}K#wKo zN<^GuXr1Q&Og!9|Cz12@YO;Y5&>}8rwG0)8*5uosmqQ=!Lk(buW|Gj_FsA?{VWxo6 zl`Q>9#H1Pst~Fp7`$X75JSEJV%Q9tQ-2i$gA+K3I8O~7_;7WlZg#;TZW|vuog|89z zQO|j^FJL=N$nu_`+?PN=5r*X_CW(LB@vwU>pYpJX z2fU3H5G6na@`H-6ghOrtm6?ceY=0px!}?p_!D|rrq{P-#m<0ePXTRAD=nb}P=m9Rd zk#joc;TcLD6OH%v5ojO*NF^k|_)N@$j`#@d2=ui~1np5HTL%pWefMZc(%3PkS&+Uh zc{biJ&v{W@!z>d2#Y&^6jF>P>1#BS33AGUtoJKj(n;#(xxD7-M%SSxM`SE^ZOgaZc zK~|TQv5>0!vqqpUZkQ#&!Z6Tg`4Q`Zp031%_c?ZHx^dU*Zb+W!c@`RbpHs+U3gq*s zH%W?i-uK9-aCaVBj8q^FdU+)r7e#t)SnUz;--i%EkFC5h3YO+(54j}Z6z47cp2XSh z#@*ko)-&%dxUiaB{(5fE0mceuv8GsV_1M#LNw_H{bkdf~vw$NzB1*QKh0I1}z#m3q zDy3clf}z&!<=rMMwsrzj1Ot#cEF{F}xsi=X!x&1FOd%N8Io*NpU^M7+@CeT~ZxUZ3 zHyE$r0KtylhV`O?_WCTWtw2q;tmRc4KWHn92Ak=76=TCi?$*o#m=vghrWhN}!Ev_a z4)3hsI2S{IS}@}&P9Zejo;)huOrfyYP)tuB--I{gksZEg>6kQ+yM*h4vKZ)#j^i1u z;>CAM#@?zWCGBlF@+)6Fqe4tQ$&K^u_%2++EUZZ|R40_nM6#RC2H`-jN+el$i5RVY z5rH2MSip!!sOzU#1r#Q9!GiCupZ1agqXIz{li)go6~Mv4^BoM0H+-FV*scuo1pJ71 z`1Sp?lSDK}i!S6ys8dre5dA`0x8zyP8f zG|o}Mh6+{Vwz5~+yy279iNb^7_bBCaXpq-MbVD;j(|eB3KDBYVog;VPfj$22mOKsw zQ!saQ1@xMbPxJ=_2hkt=!7uyuHnaf>{CQajcqcm_@LGb8X%DE7E9ePM)$w71J;?zq zNh9h(9`PO1SQj#ghy!zIFNilh0D$NsFlV!PHV2r}i#)F$NxYcnh9+Qma24qI`+05y zLxvukg+&_=!{$0v6kjp_cXRh<5<5I+Z1@A3{44hfuw*rI$bx!tb^&0QN$Z z1=6fKfhRoHI_25%$9P+r)HQKatI6ujY@HumQ5e9(XW9AsdJ8HfD49pvK6^4PkS#ff zL4a!jM>(ZkY%hNO7NwQB76Qstv!FNoRgrKZZw&V{6Fm!$V|@i022WOgLr_dT%xG$y z7;5ZY1iO=VEnvEd6+B`g+asLUQVK}1X|pF2ZtthRmP{gTpcA)sunCY&^63Q678=ay z<5BSwKRWsx-}G3^n$6D&A%OR(xtIdt@AC8r`Ppbu4^SJ78=?g-vMdi<06f}B$er^8 zQ0!C5w8sLC;emz;5>zXDyG?Ta#1I$*l^7SO3aZ%0V7)1z1g}~ED_&9pJD$d_oQU|*$0 zcpU-WUX@u85m=xlVMa0Trv28)gcxjwC5L=Kct6WI3B_F@LU?_y7H$(Lm}s-$cMj!D zw6HeFi2=uCBsQx#tUiIdJ#zK@V7Kq^u!e}ruBjGG$d+klJ~WFAD>@IKgL@E$x2o&; zAQ1pVMhErm(O|b!4_Wvc0JnwS;4D|aBf?>d2`oA0$*U|{_ber9Z|EmkV`B@5I;EI2 zyH$TK0MYopk~%t=V0@4@hX+hIdj_i^#!$#w&?Mo4kOkA_Uy?&$Y0wz!EiI0_*qjCc zSuao|ySFd3z>Mf}&NVE89lH~93Xfa!iIZ%MDdK7x+IKwnC4WVhgYQ`3Yb6oPt-(Z^ zd-mXAR$f$SB~}gmPw_le_8@%4a`+KWG0b&hghk}wXR@Bo6Pr%xZ`(3n3rtTTOqy`6 z@Jly%q`_s>J#6qP;LF!jY#?at!MefrF}ATlVPuenRe){EO`>dRxyc3IM}(|7g~U&G}C5wuz!#FXVwy> z(5!Ytby{!pm?nTBmxZ>8dO+|V*^Ap?G|E-#Kp|H4^@GMQH0-iyd4tStKE+d`eu`p% zOfcj1)B*5^fw0Ycg0vqSz3TNV-N;)Qm8q{@5kthLhP0}3M5IC;=EM3<9Gm90g>WmutQg?yg3 z=|p+l(qjz&5bU%s;7Cd4qjq( z+)+9ejW7s;C;(@fsrM?ssizJaJbqqnsK8OO2h}$YB>4w)5UTU@EbhIE1%-mtlh~*L%nU|BB)Z4xW|A5g38$P#psxJ_xS`KP2OIc^0Pkz*0x^&ck;3BTM0*Bt}?c&UVc<;LiZW!nn-5t3>a!EK#s z0bo929S+K8Wgu;;mOznW!POI>9vN24J-21n8^h$uPhHsjUe&qv^60aU-#&^{n;V)n zL_huED!djk+N^OAs$#)@FzsB>%^&RX?N1UjKI`zL>*x-%3@lJHOb$X9q3TnM077zYa?GcAoM34N2tx?+pmSUhIKzEOr%(%J zgfYQyc0$Nl45NBU-HbI42|K7KHwZ=FR-Ge!ftU$gT^>9bm977`i%X7MlAR{!G~n?V z3kgYVc(Faqg3trukU;FI>A;a6b^q`XW$NwtpsDGqZ1hZR2V>96E^#|k+y{D5Vd*q* z@esumA{;1M>3uE0#i|tZUBqxgw9P&q-gyGgwiJkRgq_@otZmg7qy){(2Ek6*JaY-z z%qU`^ZlStc!m4K0vI)>gMdQ*}`ls)t3|U8i!gVbOwPbaf`t@)sJ^dOMldcI*C-&fn zQ_;Na6!EwV)(=%hC>9&h4D{6o4leg)J1}t9q#b%LvQTf_zL`P~=A{(zvy7(0X4!OJ z%7$<2`I4cMFupzi_Xw0Ajh|&#^Y9~2J?)r-F-LT4LmW&3BvQL;?nILPn8vdUVn=%! zi0Xt-=n>#)x(jubfn|Fc0M}1(^SP_mfIum_^}WB^awz16Z?s}XilsoGT%@VK`8Yu8 zLKT*Nq`A4E5miBtVFXN z!rzOqMh!3Q<2v;?EGi_7&9>Y)|5f*h_9rGe94fPjair>5wdZ>_#oCPmIS~8->nE^MYUgU^UWRTJ`0XZOIUXR! z2RVVu{opECo@}V`SoeLy+GvsSLMMX<(5gTDkVthH?+bPesb3pk`K!+Olfb`7rfFi1 z2ZQ_p^u-DU+n|Vj5J}^Bwx1}q;Cfk)fbv3WF7@2WkRfP?oR&y!Mz)k}wSK=mkY0^| z#Ty`T-6p{~hm9-T`^PoFGNW8Q;{86w5cjZj8rMJBh-o>&byD!eayS8cZ~TanS!)lb zQEecxJ>riIG`9tXuQjF(KF1>^dPOV6uq}Ywq_$OqXYlD`M$sw7> z>aBiGO9o^wETIb82JwH1Yp`!=D?$Qbiv5EIyx2scZA#j!W=`q^(S4Oo6S~G(V+$dxS-e7JEXDlXBB!@`aYfL*)>XFqg>V#e$tAlp}XI&4p!?`zosi=8te;Q?;&N(>PXYOq9n zf1U$kxooiO`**}^Y{Nwe9A~9^tf~3i>c1?32h_`T$%9pw$37krtYdt)HVb7Qm8o6f0tsT>;dv0Mu!@ z1wFVWQTM)3vqmo{hNbx>d1#uRCdIazMVyj##;@$#963(8AG;YT3u zv`-P>v0>zcs5HR&`$W)ofcC(fzJ?a+JAMQLtV5=AZ`>SkZ`WsH_YH5)c0xy+R#=#g zrEtIYD~58jr387lpZjTT+@{`PUdW17WI(Y^(Uy5l4Yh&3H3ps+z$06WA03&&o# z8s=lc#s#UnJ>_LZ>Mtf^z3{YH%-mX%Ze;|#rb>Fg*S3UZ5g264j$3g593l`P3nV$2;Ll#+O6q2XJS2boqZtXGC|b1RMxaj`=?Rr=8Td6frIZv83G^;Q%~HxlF9 z=)H3+j#AFn9V8`)g4=k_b-#=9gzX?EhXXsJ`KRZa_JW+sgUvSen$pCj?Fz80wQ|v9XUH!Io3yQoRg2Hnb=J>w zWvp(c^qSfq8)67k%PbjMBLUTgkZYmu^P;3qz(u$q5T4i4+WuaM8_Q5vuLbR7Qz=|3 zg;OCopmq;$MKR;!fdycF!7fWVpHp6y-&pMPfz}uYEVTlzs}To~LC^Vpu(2Gk!>NyW-v?!>!;5w7`56vd9Z&d)n~m_hhxs1KIA6cp5DF>j(>;;$mr8 zm28J}IVtrQ7t9`gd$!D$rpijNPgPl1$1RpURv9gKjD4Kem&NNwJz*t$iur@=(ExNK zd60nn=9sj_uB1mA?o)0ZIyg%BQ2uRtWur5MEHR#y=-R6%4LIAAejiy?T- zVvkN@Cm(*ti~7m^nefG4ROpve1q_|C>#sr2hmCgC-pOd!q~)^am$v2H9W+ew2 zD-RY~lxR09OJKuMvLFho7G8@pY>> zIXP7Wwhk%!Y-vUtocx}4aN89-^68aFUh#n6WoMx)6I0GNJAa!qHsj$T9UgV!Bya>*~eJpKh&Ky|@DEIO^$w>OZ!*KM-pb_E~r9TT$T;h9t4>Zb!x zGF*&+h`(}mOPiy|GBv=Uhke;!G^U@BwY%lN--sUq)r>0ygV4Wj3sMMc*MC0u^h=rV!94LfH61&!PYRscRam7&2q}` z998J)HS;O;omPp!0^wxU4!vxNLN2IH27Bka?#?3}&nR>Z7s zij|u)Lyx`LH}ae;WIboSkl^)P+ZM`&u}axD+Q38mYK&3!5S`YvDG|$tKu;C7odVe| zv>^mHdtT567jT1a>z^67xvf>LL{$P$DlACCG0O*8mF&V6Y`R6U){!iv6Z!^h!2Uwp zg}_FritSeRg4Iy_S34Ss2W$|qsFU2zH^2j|l;%1HcF)p!2**I>+4f`HUfHK*gW>4W zR770Xg5M6|*)PJ;BG!N#HH0fPD>z&Pb%J@PC}x*nBTqA+N9&NXx!`S`BF_E6Q%-?~ zWYVU*lPm$>WhQ{*H_TIM<{2`2jyiw~HXW`=Fgk@VLo{~U6D0XlfpVvo@tI)D`oPKV zoT7xtD(nk_!lSImxd3?0^E+X|ZtAc45gN6%j_0+*mR)})F&456AbfZ6$e+94&t)Rr zGWG{_GJ9M$_gH|I{k}3%mg~lGH_9>D`9oak-TLB}`>|P@hihE@f^p#Wz-cwlvbsUT zmPkYiOYoV&!=-J0Z2MGvfsNf{cEeh%xj~u)n9g+?QKfjFrB1f-E%=me<<{pBcr4&L zB^8A=~da_4l-f%^GZcV*>YPv}V7 zPX{8&%=5gIJgM81Xi6$r=dhhGbS8wo9`++Vz!Zp+${2@|5e z^uWjG7!HCuF%dapo915Z2N%dlxs3_&*&yWZgh$jR@(m8+c@05&j_%M0@VKfU9niBJ zTx43uX>$$=2%v4V+^k51$91Z2Uf7bekzR`#S;$jfDi^R#uDAGDV%bjnD0k6b)ufaZ zS6XFm%h|6J1I;davYy5pgQxorr}}k3ompNPAv?-DQO2Uiv)lTdjUoWDNeg2IA>jkq zr_Go^GGWIt9$?`n1UVqc*2hy$X@caAv9sjyb?5+C4|Li}fMs4^K7n#N6~fv@^9w{4 zo2C>l8HRy&A~ZTR0Kg+e+uU?|5CrfzESh?t$F^5^5?}>*jL$<#5QwE21@VDIJ*q-oXa}TgPlhw9|(K(={ z{we-~k=z*jaG1h-#7VR(&1gi(OmJjbw-3vdLoEpE4v^x8 zxd<4Obg*1jc3ZCov=w7P9Tm6noCBajQNk+>YdI{U$f-P=-`P3P0gx>2p{-ZhWk8vO z#d#+IM$%lbp>;D5Rp~@nikac+<$u=Fz580yt^$76A5SE+OYOV zePj8k4X;+wL$@p(=+5+mCN7cLQ#(hc*}|KL{cJaQ^myO|S4HonVF|E3rB0rB(mAMJ3J$tk}xCX33Q95o*9M8vjR0vew*0-Y#h@ejF zfxdvpo~K0*3DwEKh;>(%ft6>1^g$nkq;T_W&r+YA!%6$ztoJazaKD~F4@==Z-iy`; zIJZVtVrS%nfUDSTVCu>fiN@Wlh2*Eb+ooxR-D6u-97L3aDwS7`+^zO;7C~=&Z)-pi ze2pj=)zCIv<2u#DcgK#MDqvfdQKHZS$u8X89szC$R%@AXmwLdxO!k_-d@!=da$v`> z@#xqw8_-U50bbH%&p8m8@o$IL;bqr+ZGg5KgXc(Sh;M<@znK8(mbiEOgHwMhkck5? zYgKV#+dWUo4$6nCU(F;aP6X>ve_%`2zGV4JoLhcw{^E(2qS@tX5#fj@NZuRkw!ror ziucp)X69;nENeyzMth(0WVwzP+UJOZpT(Mg;0+qGU(FVY`%Rw+R{JEV0xa z@w7^0TIj(e_VBLHat&)y!|fb_oAszxn}O}e2Ff=sn^m03aHheWpmBc@!V4zG{S_0d z%?P}m1!kuZ=1s_&$1vY;YTHl*`%)njYHY)Xh*u}OZOEes=E0FsHa|Z<9%8d(aMa@J z%Pwt#h=yg3EdwM#+ZQ zQv>F{ANH#5Q zy87}|wLoL_n;AWUw4M{tx15%T&(@JylH%$51aPaN^Gq?ijppp5#Z~cY`*5R)R4%a>hHnU1>~ROoV$$^R|02{a2*xDlFe54i`hqUVp}+b+fQCOo&18~ zCR-*ykJlaSXdfmrAGy^oA`O0af*T%<`Mjsjk1f4HN;H`B$?W~&InUInY*X*BNn==P ziE3#qXS)bp`E{T*LcZ%QPm56XC!dlJLiCsx>^jZ{pZ@ZlZ8joyn_kh~hKWC+iJJPB#E&?>J@*Z?nN6!W*$)stlIEl4gc zaPAtoMG4t7*Ddu$pEnCiEM9v>sm4MZiTRhh-^Qcd&Rh;W+M10yaL#)L%ffe67J1IM zfy-%4LQZGO?8X}5v!`qU?>7MRLi>0ooMVC;?bI9PQ$a&iJU9F~Bgga3qGv#@&7kZ( z<98ZZ!sWo+fQCbxc%^C7WF4!Sp%iQwaWbc@GyMi6=s}N1ekIGop7wfVzE7(#^8K}q z*nCHFJ^>N4oyrlLwoz*XJI1bvUlm9X9_C{9P_4|;AsO?+Y4Iv{*2z7;ad7YlHpE7H z$P`?l5{44N-sb8v!^9exqSc^fBif1UHZ!B=?9?{u=3xe*ZVnl+*IZG-=d`icNDwvN zoJ?n07=`illj;K!Ez;4N?MvlD;NF(ibW4-u(}cfPoFz&e;JtT~WtymE112{oMLHQX zOq4saz!rXL?l@X>MVLvZxt?ME>oI-P55hV#>lvP2I#0lHCT~{bBHKc^&VZ+Tv6MiX z`fEFkXdrFYVCM}5;EAAikSu~G7$N6G`bChiA(J|N2 z>6@j40G>o)n_-*EwyylapqKOhunk1xg`hoK0(YLuLp2r8P!Tu4)nTy&2KU8W_`B@` z07?(de*sQ5Q}V7}yDjAjuTv}QIl6p^0y9L@69}E#$uB%PMDWS4ZFS3I;pgNJ?Wy|U z_pM(JYw5O^1YK-6`mG{r9m;}Rdbkc4SBFw0tQkV8^EU7=J1!65eoF55dpVwQDk`ip zOyxMq7AUNc@9C#EAh$M9fXZAJSM;pe`N2timoqQxk5sj&arKaiNFc=LxX+qnfEI_N z!vS7cPj;9q!taF|Z@Wgk^&*YAEch%ABC14#N47}hBrct`O11=?X+(WO{%qKCLNlri z-#_&VlMOM;?3fS&7sl!?vgt^hZ&kh6v6^w;PJv*ZEL^q*1l`cRJ4@eBk;>yq&>a0ur0F_tm)1TZtdVZctr`5}{PJTK(z7;2+^j5gvmcbQg=tsMPcsA%z#F6>+ zS&-B{v7DyQis$6csdGN0C&Lfn3Mq=Dlc(7hb_ff*EJv~$7pmNY>w_N~ydfv##(K+d}_v zN^htArDyhL@Tu93cm`tKr)54J^Bmn7ujjDrz1|VkcenG9;FbK9BSe#Q4nF=m4GvSZ z{5<&m6vSaq6_XY9_j36CDaO0^rH1v?ac$=m)at?Z?N};27(nIrw#}I1c4WY6aFK3 zSr5!jQoe?xELd+7Y4Q7T>%{8tkXBIEb;^t|)u%qYUG}2$cb;B3wZ3~x&~}S5E!AP= zn{%OWyJ4Dy_5d-EW-iIE5d;=a~? zAez4!1;I8!#n+o4>>dU8`KL&%*yQ7+C~wVTKpQ5{semP1Y;Cd_Bg+q2<9LRyvoCYU z%Pxyf;Bm@Dw3Jt*GKRw+O+VvQp6{BYI76BVc(%<;HuWa+5SB!Q%Q;E+vX;pN>T+I> zqsn1E;qE$sE&vpF1V z`}GMKf{Cd3ob?%#lW~U~RpW(Zhm>4B5-EW<(Q#$oIFCsRNHI$*$3FAv^>Q~1&;5pjw` z{;o58r*J<&K|$A}Fe)GToysb!{ZCgu)Gfc#b0tDGgxW7u9Bv2nYJ=DFYx}l1#q+%y z0?)=0`c((dIlpewmecyUoCDJwSn7C9sa`)-aAMaLS|x@^E@qA$i>E zU|cAY2`X;Xv1AvZU?H9fzKY9jbG?ooN<8v&y2U&kDl+-B4QRL7P9;eK(H!D?Mr0AP zAIHg;;=s!rso;D(WX}5(EVSRwk(ajXZ^adno#YK8xPHH%h?E%kW|!ae0t?Nk7s_%83@JKL30Ac zNyxuS>&J%i==WxTd|*z-`uj zikWP_?u5!Wn<)mEuKJ)ut3w8=qwm?Nti2b7NldG1qTfKUen-c!E{ClVVEsNGM~2Q~u6AB$*j|hv zp;gH6Ibx361|{5s+krkgGXc5bsXumL_U0{TLv6aumLT1^U+2gXg>5%x|CLdL_YTa1 zj(Q6E$SVE5EVjsbvd&jUgFGJZ?+lQhWp7un_6pg4V?K4BgYRN-8+I0*&bS;KcEg#9 znby;NX@&1N)zNO`<35zEVXQB~g*a61QicOxvSi8aFxLGSno&XSg3HY65 z2xXi$2Y?N+;$hl>uQLPBL4l~e=(%?=ORD+;e$%fo{q;LU&=n zy!W;tVOj|CI^ET(54F=iJ=|xKl%pS^su1|)X%MUzrQ{f(efgb8eya&`N3Ho-aJrso z)AE@!4s1YDl^!_r2E(E`*fGrRyx-#lPR(Xq)oI>NzukUukQx|T=TRQ9wl~|r33T^>ZbeRnk@-G4o9%YsHlO28+-}|{U+`z_o=l;hRobjmsw%XIq!ilFG z`SAO;0kPCCPw>ne5QHeQttiPmIhqa1>iCE4MDsKHUvRd@$Eqd?5>Z^QNeG#425+drVL0Bas2%`5MJ^J78!T-UW zGcyn7oVn-onYs6M-}imDEAAr)(GB?UNs!B>MBbEd{m}LH*LPjASm85_xKKqJL4SOS z-c9yE!|)<&ka=t3JKRNC?s+JgVPx}*MWW0?EtV^V3G>yH=1_cL(zk67Q}_Ony3e-5 zeK%*;pcu(`u;i=m$O^(;z03!~5})ssv<*0?EwL-J|FTN_F&DHIRcDwwP5J%1-Q?eC zkqC?5Y8w0+Ppq^^iZrBS)OTE}a+wJMy4NYSDeeNNSa%R?KQaGQTd7gLwsUY``j-*I zE><}7heSB5TTS%z8_nwb0&`Ax|D8^ke=?42LDO^?Trsfp225JLXrFn1`00R_=`(+% z$iH+@?ohV`Nxh@b#Kzwb`&TiKCO_NtVv{2xm%PZ!&r$*-3f{d+Rh2>sj;A_?!Cyc& z`vQ+XL}-ni_Kk5RG|**{rJU>DKECzR!bj3Z3v@M05U9 zGA`DVP}{b!E6^GDQBGq61E<7gd!rdCA0-3MCCN-$uo@M+v{ZaMiehQw zDz0ZKb69|G#&#`0|FRDah)gVYtbZX4qRL%%-%x?w)s5vNi{2tnco%={Fgm>bIYC^( zpw+>upybOy0m1m4E7l*oc0=EE1(g^HR(XHXyi{9!!k01w67(-F52B{f?veTFePpf| zHNr&E&O%mV`s~BV&nseOpOYYx;r6^!EGO}Z`zJ!u)Y%7;uXij(QZ>H&1h}a4ohD*q z7_Q_#T1GM;Yz3aMg*s0aUl_C8RcJ!wf0O5Q=sNI9g22V#pV~y(QaITDZPA-{etH~O z61b@s(_QT-AotU=__#xma+H*%GflQY`rZ5)xN&^F=KY#GGxePGE?G*@_nwzD>i|pi)r%<@*{aDj%V)ACmgIq)Ay-W z2e06nPj||~6Ls6DdddLoFkOu$k%v~#Ww+A0m&Bc&QDDLYC~&@RPgsuWz)nSj7EQO4 zpB%cR=V&D~TA0yGHr+Scp{?92AI6iu_t-%(*KxURS<}~K&2^?<>EmL6%^Gy@t5G0S zx;%RvyZbQu*#NQdT9YZEdd@B6$iaF7IVdhUg@b7PcMw}cMePN6`gnHlG}prybdTY= z;|u0bR^fat!+B!<-S1w^+r`Yy7?`;bpl&4sze2VqBqqnHf3^%&AKqoe)gKGm*xDbc zmi}d3##KsP(6_A}Sp73pJC=B+ z4&8g(;avCJ`cJKR3P|s%z??ce2f@$E;rr!J@voAm?{YStI#h{xtR3u(3Xn4{wSK{+RQO(2mDuRb1s^@-QJ5hI+;e= zFF475;cRiXnZKl8O)>H=`TNp;H!>Wy{zK?SvhFmU|I^=l8mC*JiqCFID$0tEteS=w& z;}1G-bC0vU0%ex(zoGc=S{66P+m(EWzQK+bKH{qDV&QMNiM>Jh5^344uhZ7DGo z`}7`p2<#FiecPbo*h1 z%;tq`yUuW_`1=h-!?#W%K6mbpW|2Ke$Tr!(elK_6z~=q7l6c4Zs9vpLU+-1grj>c0 z@YJ(j6`#ztf{7cV$}4LwlyOA#tqsdVJ4HoJ6-CAWcU`&lTES)~euj5x(nqvumm#+c zrK1$d86!huvyE^tu;9119h(@wCk*ZuuaPm%^I7X%9$-?_b}3DlleUqL4nY&?OO8nQ z>zmoTR8rB1&n(8GNz(#Hy?`et4y2KfLxhek?8i7?*o-D6!;9 ztHOwr=s&oJC2{pOu};-_|A#u1XFu$BoEl4P?l+mw(NCsl+8@@g_m0k5J7P_+)2;Tb z33TWG8qn#Yym^H@YGcr1LhCOc{^gv|*O?-^&Q%#ntZ%sZ6BI`j3a5W9JL>qhB9#x) z`w4u1%$DsAKiyp5Ph52!pJl}g4s_w_3hfbmf3JZ%Tov+)TTOfp$EVZw)=gsr@^k;l zzQky%wl=Ov-Z?~`4q`}-QK+8p`xaAXNjDG zid^hbMePFsfD@qd@`bj~ly zhHD$w!+U4KM;y4DOL->c9)V~GX-`WDX5I+)J^US<7N*I`iv|htzC=TaT;%xBkQV~V zL!vcRx%^pT$^fRcBr#>ul5M(`)S~Au@>!wFRtq~bEbwf z&>B5&_LJfx2J5aI1rBu=)qOmK6}B3?K9n!G>E^icz9CsSCm;RPz-~7CF2*i?WI0Nt zIH>c>^0Fvz%d+iCCa{wzDWTXB0OXlbh+2l-^gkNr%Zw z5uxHdd`)q!^!?>(bw%7~>jkm1@guRgDb4?29spoZkMh0XrZ~1ARjd4y!;NocyzmtHKBsO_myr1JfwM z_bw?wp~2laf^- zjY;kUqOSm*wB+sdS_su1`gRjQDJ9`@+osdxN>ToJuQ@^0RE+O;Y(EMMdE6a8OY9O3 z0`MV_A4J*%SP~A~rC0L%Axct&2sf$eGJ57q^IoJ#*#u^cm9K!tYty`R0&1KiqDuuZ zLnu41mGP4%&$o0xl$IgpM6CbhK}VP3;z|n+36e(u!0nhSEd715w>V$EdIxpTZK#7p z@uq;#IJpum06f$uG`ks5vtU%c`a<%Gh?CrAZN$F^m+1<~GZ)eNE1F3bvcJ%RMiOxJ z;=Xr3W)_)7AO-m8KVp*H`=a^!t3kd&yU$<%>?l4PWqoY2@Y|6hQ2A<%@SXHPrzc9$x>KG%b@S#PRE2t$e_Fx;UWN%F z<#9KiNy|<`ltQqvSwhyZ1{0oT#~2vh=HS18%H=cq?Z4>0-EfmiQ)NB4`UoMy?OL(2PnRW2nV&*^PsNUxoA;JbVSLX)L)$p_JX&>$otsYErV#{Mf{!h=VU zOe!mHmI#9u;Y%k5xWqvKs_Flrzu)DFlbB($xcm^I+0Rg5ZhAUcI5#HRueQ~}=?}uT zkI;Z1vt5(zzmpo`=mNH8#wYu zIT%{AOnIoj(gT-CW#FD+S!$kBUfx z|Gob12O3ALt-1bais7YuB%Rk$1Pl>bang^tR$$Hp@)S;C;mYYENB}%1EDLUSk4x$m zO}nH*JlAyJ5R^>H3*x&LIE01_hS&4%%?;S#O`5D<*{Wk)KY$rgn54tQ$lV&I4$C&<@yzfFotO3weBQb8oyK{@* z_W_-&!1hM~01AM_#AV@CME@nxD!+a$G;NHJlk)=roYy{R<~4La^b_|tbcTD4x-`fV zNwDG#&KK6>#A|Aj>mm1WhMfZZf=yTv+9ph+u>NL}yKc%4Al+0|dGU;s$pGVmfhj4H@h66(9hvF8Xh0Mpjy8c<64t z=n`OwH)6@6`DAzXzQSJsT=fZk=SZ5lob8}5{E(6p^CR750|AG=!EM?byQzWAgJu~Z@*1pw)VFXtakD^9-Qc1a=xzC zGku3nbcdT>9P|bo?wH)*W&{3ZACjuJ>bovDe&QY0NUwPm$q{MV>g6>6R%YV#omkVP zc)~knD;md_$p(6r4%Fqs8pQ+Bo32YpU$b+v01yQk?8DA82xxK;b3$6L?*ND^1lvro zCRn++%TqzM9(e-O0n7Aw@!5=UP4QJrJ{u1$$JFcn9Wf9@yU&_M7;4&;3{xMu)61*i z(m@N)r~r)D1BptD4d`M(fMgW;mRcX`%vD-G=$D^=fgvAKfr(DWcgwL4p&9QA0TjJ^ zPu@>kT)2GQ$2t~8!G+KyEtNu%UaC^P;n|vQ)Flj0Z?Bh zxn_O&ANGvgVKjnw+)4QHJH@;h17CHkE3Zevjq8iPy<3%~(697R(jQHAYh^P0IAUokr2fBsnkW4|IO9TmYJK8G$q%f>F%|-r>U1A;gE1wG>Gatlcl54ioJp;ssmB9 zj240MzH&~(Y##64Us-ZxZy;sTI0T2`JXD!01%@}~$mlKZ1@_?_oxq#yLmXL-M}&99 z_I0g_w#<8`VkXrY-y!5eO5rZ*BWWCKetn|fDHh%l9Z}FpZQa-N<2B^7TVp_l@p!m< zS6hW8W)GB3)2ohq2Ak{+puxOA(FoU=q41C&eq9YX)&bOyBA;aLJS5RFTbCF#i<{91 zkX}a5CotFQLhxbscYyZ3EWOasLO2hn86gd}MN0W~%Dpa<2)%nb>~7bqk!{teoaQx} zp~{J-bNQQ7)2oBn;E#r5ISIy6M<>pNxt4&7Soz7o{rl{~bHNR?<&I2983GxNdZ|Tmmf&>V7i@a3xJ5Z#2Z{voo+XKNP;xdVl?~9wOmW?_225x{ zn7kCWbQ$t{C9*Q>_sXts2>FN}*3@|Q zW%da^8(*ZoiQUHL*TX>B$r;;8JPPV*B?}k}idhUy|C5&r?b3S0+O97%Z9e7Fy4FLK z2)fAW6!+#ynsvIrK)MUWp{Ma4%Mz1E7BOsRXERo;2 zsZ&;B%RZYMM)*#e23$dbxp=FcL`@OrR_W@5#W(f>k7%UJ2r5hSy^gcDjI|0&(F5xAC>v`u?m>QGl(Npi8=oq zYp1@{i8t#wGQCWo=R(mcGts`Ra@%_~HUL-t_vkw5F|;wMpaU}jSQYc`Fk9UD?Q2@U zLmqOl&fL3fu!A6#!eWVDznL&vj}Q|I8{Rn4=}Q;sc&WbBH`q&K{h|S51^DDniF79e za7yMukNI_=$>u|%n##WFMyW`+I)oUgv@ZKC1PoY#PWL@Qt)fI$peZ%zjyf3_Ei4@r zLSNwRu8z6jC6k(lG;~FlzkNK3xH|jWG6~L1K1J8D3L#}%IfRS8*$#AhU%IYu8B83< z5R$aMp?);35$7?{!f8W52!QsJFZSRVIetD`ZtV%cRY!)s(&VovbnPd)rSv-o-Z$sh zakxj7%O$zu*MAj<=7NmpcfI_ZTWKHJ^t7FwI|nyAom@=h7X3SV6K%A5wva`S3OZJT zaI|IjB+<;3pB!`GFUN%EuFmJ!63koV0V2ldy@aNTlBS9Gpr#s^nbM#mO zM+_gG8r#zeNof$2FPqGoNRCYi&iuW8s!~){?YMqX_+pYKVpqQRA-|MN*yjpuhmu@+ z4GL>F>%e4lNKJpEOhibuQ@Un%hObMp$)0K4)#06xop>YwWfJHGZSj{H5Y>&VFE`}N za5=fybFa!Alaubx{Msx?@SgK1u`XiO-!WZ(W)p(-2|SFgriM<3-{k|&-Pi}clpa86 zDZQkIawf5L@|r?u0L7Re$SSV3p{S(l=|#``qzVtAF9C16rZHez4cxy$;R^@FgZf1~P(QFD3rPo!!dCusv&EW@kou*clXlE&a>_+oN$}S;MB^9U zZDgN%WbC$dbqgt92|?~C2-rA_M9-oL-(U6_^~FRtmKf=xh62&!9wlXKFae>|`3DMk zy#Liv&^ky3Qq+7geDj03hm<32Z!YkvS<2bTbj3(A#RTEKI|Q9;{XLtx@>7jalon9m z9C&ulcy;Kb?%K+Bty`JZ%$S??rn=?qALCAzh?Wv*iuRRU71RW>qTvyliafY~a!DFe zHMq!swDby5Eh{oW`0#hXppkNTh@1ZT%8s(GsE^H{nEks@Rp%^6NDZ#uhzQF*F>R&( zpKCu}>8%uIg~4l<_f0yDE@cNB-5I$r9g8_~ik zJJt{ac`!NyI3=_MsK5*x_gM>s0ATRS=_Gvi9h5nkBIL(lc0E)n*ce12oy@&*oORF0z44nCdzcoS zt~FG&9I#PLmbVk64_^>mvHP!vzK$hq=`z|`rMN?9(>XrOpdq8>#%4Jk(o~Tnh zWYf&~>-|&V)|)tHqLvQJD>pg1{4Au1G80!`VU?6MWsWO)miM9W?$oDC402!kls|nv}f&N{v_wNW6Vg_ zq)fkCf3#aagl0EW1jvO3({(%{$*U=Q8q_FTn7$}W`M|2a+DY!exKaUOU+KXDoVFvM zO_d=PKw$_%WRy%}7BY_%=te+kSrlEYLF`LbF&|u=!yl4{e74K*A1X50@hsP~rmS)@ zwGOJO+A9~gLWy`yye@j!(@~!KX<|v%?Xw`4OHS=LR?B`zOG`E8K#Eh(9$Z<9?;D+p{6hPrTQ+G=fj|t`zmD_+ci2x?|3BLjB$OuF?(I^Ohpan(~Du(Wb{c}bMaRLQKt5#$YR{r50j z<2uUaQCVS(U5LZgT6)+0BO*I4}gfh2sZ{V#?<&?GC}bMSPUt19rRMd6xrjqJKb? z6To>mK5c=##tLtQGUL^8lU~1AI+VAFD8hYgb4N@)5DwH=Wad&+wSxn*<46De>iOb0 zl=k7>UP&VW=4n`|-IXFWyG%K6jGp!9u=oJyq3@I>H-$r(f)5U>Z*CcA2oo?x2Lh~f z5D)eVmgXsB71D{*49+Ym_S#+8@4m9XzjUn>Q{$1wG#oi0KNkcG|AD~=drPYku38;w zahroCvNU_tYt^6Z*Y28?2Ob?t$H`wbR{S|Qao~`f*YqV(f?+b;exE^(E-%Wcg%$HH?W?G#>@ zVne%71f*L&qO|e01VI<%3iGa!ezbR9C8FyG-^&E`Xo1hW)0+D1JVz@UD8DW@8SgZr zkkw)C5ubO|YWG+F?H|2<-8|F6dGv4Jtyp`4ER$+!jo+priZ(>79{|3Gn{hP#Whg^b zv8S{`mA4c3qsF{u`JL8lQ8L7zKO7hCM8;+{XwgD2Ti#fVDxe2aIdw(A^{IT%y2zTo zkTQ6Kbfe@Vc45#`hpy6ZdoT}MpQvwa0e||{&g{Bz7h=F}+}e+XECX*gcIEuUSG2`K z47H6b-Lbt)kS7p+{grP@V**9Lq;rHxZw}_x?s0`&qxY|$HZ32;fTYy$?pND^m8OCH zD@zwu<>eFAErHi&__X7bW1md&%J8K7d7k(-yRY7+yTR&39BXS0nxJkfZT8@T)0VSc z)7F~_vvWeQ3WSSIJcP}yA*Q1oe6Dg|+uKY(e&lKW;Lcg|Zr?x=C&nDkOBb)WYJ*R0`v-(6>%ZS_t_0!R1L<3*DQ#`B9IwlwBxP}B+#;MeeWUbtLALG@?ZYHYV zlO#$`0dA>>f*Pl)ozgwr;XpHN(90o6&ucmuu1P4bsBrxWpL=9HF(-RrA{EdEd zhtGCI4iZA022Wsw;fuCMtEaN-A%cOQjQZ^TwPHRS*crqB0wo9Sm$oI;lWQ+zq%11R zeV;w|d?keQx>@ZO_BJH~M5WrvKe*1cYxH`a(x=8j)Zn%Bxu9q{-QsPPp~3+ojZ*Wc z#%qCril6?|lSBY5p>n=8t4$%%uRHb=yW6rRLy=6=I<;P_ZU@&*ens@MdEd6Ym{&!W z5b&=S@uG$4$%b(2q=TdxEHNOD$z2~F;{}1*gbcv>Fn4vN3`3S^)=FHzGh39osf&`M zq#2Rl{T`6eH7Wfbgj$H5j@@!q3~^$zVU?6}Nbc^w{AKE0p+?J45NeZ&1co8Rlq1u@ z&y-N2DW1*84DASl?J5$!&(75YvOCe6`Y+#m+=tNujnb~uhNMz{d?e&<5`hG4i_uIZ zGp_&;iM%DqbFQK*HT=}v>Yw8xtVVCxIF>Hyr?g$i?=Bhu*Xy%d)6&#W3qF28v$~l- zJErhBP2i9xKdca!d8`&pnUh#m&MG4%!`H6}2N-Rpmai;c=Lgb0SZJXjxD}hH6!8A> z`pRP@L1;9!h3JX6kdg9o!T#-)DfIQ#QgAk{V3RlSMQlr31By|asIb^PdYJaud)GNr zrpMh+M#RgIH>pBDRMOTieK2l3cnJ%Q;||TsXwqtG*>qgxR6h8 zfmQsTX?O4;Nh7$JJ4BMV#CGuPVUd1Q0dC5%ZV@>KC>d=$yngz$Jk9x}9z{9Rdnd%J zZjuKr+5?jdKrpvA`np(qCg)2A?qzFEr}-&OUO4CGGzT?LZhM6Nwbxj;4u*a;1XLjv zUhAOgGDm-wC@^&v-zoiSU+@$vRFah8rbvNMV!hG{R(+ZO;%x=Ic(Vy)^a`NRXJ5}o z9qjJM8W_Kpz%eKJSYK3#6b2yJ@(IzJQv&Ev4exb}T=c~NbifsD_z`C830)1GmJ0#I z3%wc1+VFd-^JWa=UNp5{pfLj7D@wYb=H7-lTz90z`T0)ost#@J&qxf^BE4m1gt}x4 zOL0ut5w+UhZ|c@x?)Hp5Dk)QJm=t`@hoLiw$u1rmIHoW|SAR>)k&b@qZOn zVJT^plgmJte9xeF{W;fcmX!%poT#5n3B4j51#FxGt?c;hQ!m+J(+<;XFz`196pZPb zd{%HSlmc^Fc{BYPue3v)-gy-Yj`Ed^d+@rC39@=wC5$^$QfB zT|=09RQrsiSxNGszFGH{aJp1{UQI)X$SNw)2Bh1gm8PF5i;gk8cUZ6fkh~uIGTl6; zb|i|@6yuvV_OHE=D2Z%)E}za!2ifupjO}xAV`y*2(l$L}5SI(67lhOHzodk`i2$bo zx!5Y}$EBMG;Pun?I+gG|#P|?!Z1<=?Yah#kJ{rtsD-h^HZQ`-to%8k?o*;ZEKlcwMlmTxbYBV^I3_t zY9kJRJoH>m5npwhrE$cC76&O@DewqtIaM`@F>lxp#&7R9g6vOPNH|je25b z-v07CQ3&uOfbgMzhY^@Nmz!Hz$=V-A$Pk5xTi#}o+!gjhv|nrMQN_|;)~k#5w6qio z>q+=H_JyP{9tmk@)jYH&3dv1BPhp#_-?KpcaqGBs(l|i{se%ulnZ@02-)Jt`i%=cY zc2vjkykBF&kz3ekX?w;b?1h#f>|x>b2D%8+$iB@~H`G^-lC@lJI}aw>yyZ*{ ze|D!Bxb}KSnlPe6`gVD`7waWKEJMRyWd=R&d>-C}?hWa|*cYXax6}eSMC6uJyz{hY ztZLa;XyqqpNDgybBEpZaHY^c;kL~?czpt=$)<~!2SESo|y9*z0j7(MEP;k}F228ag zT9@fBx0Oc@p7k!P_F!B9BL`C&$4?X>%Ni!veewm5?jXv(6LIRJ;6p?Ucs{2h3^d?GUZjI<(gk?=%RE(qFlb4l zcph3&bX3A^sG*_?Y`fb$#01&WQI9;0j6_Zit~y=8o}TqwAN;=-pzoAscyINEUEb4E zBcClqFv1mI@_thbr#IVrbM5oUw=R#KvjHmtnG~8yX1-cfqr^yN%{<`3xc1$L-L5T` zvGZ=qppzbS$7-P-MBzn)Wq+Z$piPh7v^B2|-hMn(ugMOQ-Am{gK$Si^w=UP?^$$zb z)~RjNn4Ltzsq-vh4HdfOtXyHay`Ncyf)BISr;bn5DFlEbIjc#kZywn=JT5xErtY`T zO$Kkp8H+r%&P3uKl~s-J&V#J6V7TZ>5Egt(%(BvelGE2B)LUxJV^6A&s#+DlQ}GI~ ziReikt0Iyjku^I<@hK=$C|c@7qv+9Iw&m4G zd6@uzU)?d;dpHNU#oIY^-qD`M$l55h~@@#{%JmDGjT=zH26VdtBj<~A0M!*pcx!(?<7aM#!d30Yany1R*B*_w#&rND3u1s$6mB6Y(fY|_1+;2h-=8&9v}TPt zv02FBD`$A)_&arAMv=bw0zzcAIAouoF+~NNy+zV|Fthh-zES^yXa2MX?em%q@5OTf z1nyEV4bE(treZ=ffFmsTVcYpzW37{=#mn?47;p*emX8LZ@}=kiJ-|z`oO6rdkVQ2L zO(eRN9?eCQhD9m}bdMhXhKe7LzT>w^>k}09OC#w-6W{_f+K=neR}1@pMG~OhBGhoM zhlN!|Nk~W;N09V$;pY}(@JEm=gBYe3;r}#^71_xFDCu&0RIw-ux7lmAn~>6a^RT4M zv^tk&h)1Bvc&4>Sx+GyQvdl6j!}ckRTyIRV4Kb-@;GBVWVt03Qzp)Z*JC&5OHbzc*Vc8YE-g9Z`FfYrmiD*S6-%da3kQEiyRk^Y zaLr23K%J{uV$PTPl$bGxemA!WP1N?b;1Vh|iTfZO@N0_+c>me??vLECHP{$5J6AyK z*xEVGIyO-p%2ly>t0ZaeJsiEYLUeMLv)cm<$s?|Qix06PL{d{8XwV$m#{Kj(lw#8Q z>OVGH{4SzMxX7g1sYO%^fVy^r0J9Syo7S5a?S;!@PX2`Mvj#z?w8cOO8WasGGJ1!O29H`&G8*+8NMdMS z^$eFRbxiKW{lpSU@3Hkj6L^YFg{%F8&@eKyL`el?0rNwZOINDv` z%>`=QMFS4(oA9idoW3R8Gh)Zq9X@!TU(;Z?ez~9HS`rbRfn@p2=54atbGY*I`}t~j zTJ!Lqqut>!y%d~f5ep)}-u?7Xwz)?<7%_g~hi@9qdY3wc7S$})Gs@!PcUDywJ!e8; zQYspINJBJb^vdbONamB?TS}T#jEt?ui^-I{t)4j5a8~{N)h_&{052e?QTu;`26IQO@2 zt8yr0lPX%Y^%70dn3)6WmEf1Zl`V9Bjb#{RD>!!dfQ}N&vvi6msPJB0O9$)#5o^n8 z@z!5sz0u|U%}iLAO1pOQ*Ar&Q9`qE%HaN(5kLg zd(A@wS^BzworqW@woWw$7!4mE45|yhX|_@>)rU9^G)jFPhq?S`j^Av?#`&H)PCvRj zTAO|V^E8H|m)g&E?&_1}iUW!i*S7uY+nzsAw^6R29;8}=&a}Od_Sw^-3~KzYTRBEP zYO8wUegNRT6DG3I^0WDqCY%U<4Y`D-UXBtzZu!@+&A42y?q}^EEZhmf893LULP;>r zLThfEr0p`WM#^~2D($Y9!2?ib0NO&N*1L(EQ`;7S{QK1JO$r+u3?s?Pcl4-Xw0B;o zXtR7!hF?3qw7v$~@;tz3b!>ITram{O$^WgN_#5R(pNuNQq7Zt1s3@g(_-t7+eww99zd<*FlzVT^dlVi_`-1t*_iVZwV zaT=F`P?uP-`!~OSQoeKdO`Tx~vZCX6#RR3Qb7 zE2x9=Xjd2HmiSV4{Qj!Hr|aL(boWDzZ`6lR&BL_uIhxKo*|0vKmdd|`;vhzJt`?vj zMSS2r89HEknDTasH6_#E zB@qK)Opn#7@mxft!t^lFhHxZz1>F2UMoH>XDxj$3qNZ=!o99uEr1=xw#^0mV7VWe2}KAHA*VG34?d1lYzkLx?LL z_tZXI^Jrw+_1W=lBFXz@d0ur@ESxD-lwWAA<6?I)TS^oY5R}6Y!<}zRAw-pQc6POl zl)3P%LWd1gPEM!7JF>?^#GKmBL;#OKD7(f`uXF;2YZ(EDr!8);{8onT{K*yV`K|9z zX@k)U?d2`*md%CoTGkmzak-r=1~C;DRtSo6FJG-RG?q&dEFIxYC6yevfKQ$tS4RN5o%0%~Mg`dg=f4=s2lr@@|fA(h|0w75Wfg#a9j(f7` zY3;un6*C3=<(Q+!BbUBI8DT`E!S~y)^mQ@fT#v;)OPE@3PFAvJVsA@A!1>Z)Z}4&O za)n2;iL?9Dh@WOILMW>;oL=rP2j}78F^asdu7!qaCodSg2Gfl56d$U~>NBZ(|72u| z>dhp7*5JZ#Pc-O5VjZNON&(K%7I=1cRWjIwDdT9eVtAwk%c{hsot^zX(yV3{Zk$@i zgh~ZL1N8d&)}K^^);JC1w;r?~y_7D8_e5PT>D{ci?JFMeu0=s$C<_YBd!rSZ92~({ z&GJ-25lI#pdn(Ohx+NXrj?{b z?D?oz-=l`<;hle%#(4cUIMISVk9Is%GRuqKLr45`p#H&r*H4Rgq!7mJI$sX z9AU}!_-d(UsUWVSla=z^J^9$(%iqSEzd-CYvs1_E))plIg z;P2{2p@;@qnWi{J| z2Ly2J3}#v1>{ho1s($xUeT|>R$FL{geh7DZ=hW74_$#ZvQ7v_#+VEEzzH_#Qo@I@j zlA8qnzXtnNC7V+qa6ALROq}dhX(H3wHac62g536Hx~^{SIyMF?96{n=p?2HMYl11AJl%stmc%^x;m#&A!JmB( zw{EPYGxT2@OHJEXPIWa~(c53ZD?u~%NPnlYfJ zQ8Cy3zO`Wv{GJe3p#+t%oTK+4;N76PwM^Dm2ABgZYHAO!v9ZuaGY9d!Ft5GgO%U~Q z=xxk3ozcE;Wi5BrCX0VH{A4nvxIWOw{nA^`JJ2ALJ63Sm9yk+X5E7CDLefb5oEv=| zmV}C6c~Y7w_)2TQGBfLRc9A$C3)mzl*;9Y-=9wm_6{q;n24Q4&E6+s6iN%% z`1O-0DDwEflkPSe>EtkAIOrH#PP1b2S7gz%ITE;# z=brix@V&J?DBH)^i$C@p5|Bo9+33|{=MZ&n*^ml@_DeF;9# zNyICFVRMlp@LCnmx79HQIEl`G-Tb2jb9~?zuf+eH-|G{Fh{6~N0WJEjRUY?9G~btt z4HgqhSRIyRnK^R4{KV~5RK{|G4lm@v{jzZAoHLg9o5lE}@ckXf2^?2{!5c5?5XLl( zZjzTKNv1V#V_jq=zV*^`^Tc_Cyxkf&{qOHy$KSn;cZ+u#Ie4}OJ4>X=U{-v z4ljod*9u+Y#eiD{x-XW=kgpfW0tqb}wbmsORW3sYm4)r3fP&}pLjZxN264ir@*aJ^ zGMBnGoQ-y`J_%jD^Ag3Y59to3N^NpM;V@&m|6GsMP(PYM0 zpw2Gm!KD_liia|*+VeGaD)v<+yYzF~V=j+)GQpQ`C3ZenV~#?LOJj?v6$>;Hl0v<+ zkv-%zt<}GL7Re^#MI=#n&-ev143p9M19!6&J%4OA#3jA&4{-QG{;`bk^Dt?7(XDf9 z$^afWx!2Fl@g~&@%t9B@rMbhk%~}~KPkm?7-O+k9b}j!7Ag_2OOuJQY8@l&wjkAz4 zuS*LvSiN;MSdYBzVKxWvOyQmx7B}vxmeB)}!^gWsGVV299N2}sVoh2yf(N*Pv5_b9 zN(<7>%7t^IKLmvLk>zo}I+@&_UAFC!6NfOLaB_EmNX$g{(}QCI?qyo`eP@z)p*BMR z!-2^Hjuah4E>+LW#Y{9cR4gh+V#H8mA6Lx6!H2$j50)@z=`S-F$Ngtntm2lz*$R#@ zeAF43`;Ru@Q+wvY2Pw0t{o_}{LCRshb8`Wc^#g~Ymawa(tDu!XKK}`W*$qZiRibo< zplji3T+&>Cw@YLMM({m`hYL~RG2Xp-TQObuS}?QmF8P1)oB5BXho(3~e;5=L{IXpI z&3b}iufIE~zBZQbg<6my?a4wg;#rrjm@cw|+2S4K%JUP$1NmhyJsu)~d`DGi{5S71RQ$G1jC zR7Pq(D=FZ%3CMSraZi~FpE~|m*~7q&*AHOLSWqO{-LpO-2=v{%lg!&WL^m)X7 z-2sJfpDO;;Lqk-07YY>mW=$2M4ewo86l9GRVm5Q5NaocV!8F?lpAW59oe=j6@My=Z z=#MMDWiXb>7#7MZ*rN%nGouWt0~Yztoh)innQA@De(9R2{D#Q`UpLO8HC}+O5hy1_ z-r-t}?Y?ILym}4X`iVlqdTm@=TOI5zNM8v!_pH_W>QKX694hxa`#dH3gf9QQei@O; z5lPM+rM@NuSoYw(Xx;PfB&!GozIpjUTHmV0cKzJI!>zrzx^3+S9Rb!tG*h8~`_x>3 z!as6CAJ@CysuW~DW)~HW`C&<);N$S5$1yv;lJ>!IvEGoAvr^>kw17cZRuxR(S9R1mhlmTZ`v8PhT_xburwH%Us&yJ2B z>;dCyN0j{M)eI$%MPAY#CT}cUU!`@q9J`%aUk=!JJGTPb?-nyM<`S;Es_PRr1foVk z$6zmAk7F)o3*x+_uyupsyPX1Yy+bU|Jxnmdx8ifbRi#=_UDc5TmgLr+Z+A7M%SO^m zUpz(tI0s6Aba30-_F??x_e_y^-#64^DtHBt^nWAmv?l?)T&N$mP)j-#;I;Db+eYC8 zsX4NagGcOSAinNm!8k6I=CBkw7aXM9 zwH%FHOK<{s4Qvv`X0`A}Whf;v%y!9$s%PG$A1AiDYC3nR@7I?!xEB$j)W;kft#O&h zaQ`LXwG!BkFa3KDWz_c`f;PXQ@R$)skbM4nB2cFSulaa&Og8G}9@#*3f(mt>WLES0 z&}hkS>im5psxYS9=dF>S%0;OaVM_!0fP9R|2z&wSj#60eHIeYpFs^$Trc+93LCPa?}-u;grr95fXX$UNMA27*&&eEy1_H)wBvnE#h@iR#UQUEIb zNV0Q7n=rU@WL{r|BW%U$0bailIKGnJyU6_E!LkZK&=hQ(s8F|E_qJ<{)~W)~U!S5! zqv;)0Yz@Ck@*T#$-+eW(l{uqJ-4cCZK6v>s@5`RAMi~d`!h0bfol38QU#DNFL-*