From d47ffe884290210e99aca09963dd7b00498e1ee4 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Jul 28 2020 09:11:07 +0000 Subject: import libfprint-1.90.0-4.el8 --- diff --git a/SOURCES/0001-tests-Add-missing-NULL-terminator-to-g_object_new.patch b/SOURCES/0001-tests-Add-missing-NULL-terminator-to-g_object_new.patch new file mode 100644 index 0000000..8c636fb --- /dev/null +++ b/SOURCES/0001-tests-Add-missing-NULL-terminator-to-g_object_new.patch @@ -0,0 +1,30 @@ +From 1dbd421bd6cc3db07ed6a8482346755fcbeae9ef Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 20 Jan 2020 13:30:33 +0100 +Subject: [PATCH] tests: Add missing NULL terminator to g_object_new + +The g_object_new call had a NULL argument for a property. This meant +that the compiler could not warn about the lack of NULL termination for +the argument list. + +Add the missing NULL termination. +--- + tests/test-fpi-device.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c +index 3d1e81c..7dcff20 100644 +--- a/tests/test-fpi-device.c ++++ b/tests/test-fpi-device.c +@@ -240,7 +240,7 @@ test_driver_get_usb_device (void) + g_autoptr(FpDevice) device = NULL; + + dev_class->type = FP_DEVICE_TYPE_USB; +- device = g_object_new (FPI_TYPE_DEVICE_FAKE, "fpi-usb-device", NULL); ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, "fpi-usb-device", NULL, NULL); + g_assert_null (fpi_device_get_usb_device (device)); + + g_clear_object (&device); +-- +2.24.1 + diff --git a/SOURCES/0001-udev-rules-Remove-debug-spew-from-udev-rules.patch b/SOURCES/0001-udev-rules-Remove-debug-spew-from-udev-rules.patch index 54a831f..134863f 100644 --- a/SOURCES/0001-udev-rules-Remove-debug-spew-from-udev-rules.patch +++ b/SOURCES/0001-udev-rules-Remove-debug-spew-from-udev-rules.patch @@ -1,7 +1,7 @@ From 7a4dd9640668a258383e8e14ce5ae230d33927e0 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Fri, 22 Nov 2019 17:07:56 +0100 -Subject: [PATCH] udev-rules: Remove debug spew from udev rules +Subject: [PATCH 001/181] udev-rules: Remove debug spew from udev rules Some debug output was ending up inside the udev rules. Remove it again. --- @@ -22,5 +22,5 @@ index 0c1b059..c0a3337 100644 printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); -- -2.23.0 +2.24.1 diff --git a/SOURCES/0002-Fix-missing-initialization.patch b/SOURCES/0002-Fix-missing-initialization.patch deleted file mode 100644 index 87ea899..0000000 --- a/SOURCES/0002-Fix-missing-initialization.patch +++ /dev/null @@ -1,29 +0,0 @@ -From ce2478c89f21811029097c6bc06455ca69d42214 Mon Sep 17 00:00:00 2001 -From: Benjamin Berg -Date: Fri, 22 Nov 2019 17:31:29 +0100 -Subject: [PATCH 2/2] Fix missing initialization - -Seems like the compiler on ppc64 will sometimes report this as a missing -initialization. Technically this is not true, as the variable will -always be initialized before the scope is left. But, lets make the -compiler happy about this. ---- - examples/verify.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/examples/verify.c b/examples/verify.c -index 89a9b2c..4e1c988 100644 ---- a/examples/verify.c -+++ b/examples/verify.c -@@ -182,7 +182,7 @@ start_verification (FpDevice *dev, VerifyData *verify_data) - { - g_print ("Loading previously enrolled %s finger data...\n", - finger_to_string (verify_data->finger)); -- g_autoptr(FpPrint) verify_print; -+ g_autoptr(FpPrint) verify_print = NULL; - - verify_print = print_data_load (dev, verify_data->finger); - --- -2.23.0 - diff --git a/SOURCES/0002-elan-Fix-potential-leak-of-dark-frame.patch b/SOURCES/0002-elan-Fix-potential-leak-of-dark-frame.patch new file mode 100644 index 0000000..344432a --- /dev/null +++ b/SOURCES/0002-elan-Fix-potential-leak-of-dark-frame.patch @@ -0,0 +1,25 @@ +From 8b28133beee5122c2a26c361cf2f2095888be2c2 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 25 Nov 2019 18:34:16 +0100 +Subject: [PATCH 002/181] elan: Fix potential leak of dark frame + +Dark frames would be leaked, add an explicit free to avoid this. +--- + libfprint/drivers/elan.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c +index b417a41..6e9107e 100644 +--- a/libfprint/drivers/elan.c ++++ b/libfprint/drivers/elan.c +@@ -223,6 +223,7 @@ elan_save_img_frame (FpiDeviceElan *elandev) + { + fp_dbg + ("frame darker than background; finger present during calibration?"); ++ g_free (frame); + return -1; + } + +-- +2.24.1 + diff --git a/SOURCES/0003-elan-Fix-switch-in-change_state.patch b/SOURCES/0003-elan-Fix-switch-in-change_state.patch new file mode 100644 index 0000000..f5f546f --- /dev/null +++ b/SOURCES/0003-elan-Fix-switch-in-change_state.patch @@ -0,0 +1,39 @@ +From b16245ad588bf7467a3580726184f48af328414d Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 25 Nov 2019 18:34:55 +0100 +Subject: [PATCH 003/181] elan: Fix switch in change_state + +The switch in change_state had a useless break and a useless if clause. +Remove both. +--- + libfprint/drivers/elan.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c +index 6e9107e..961366e 100644 +--- a/libfprint/drivers/elan.c ++++ b/libfprint/drivers/elan.c +@@ -975,8 +975,6 @@ elan_change_state (FpImageDevice *idev) + + switch (next_state) + { +- break; +- + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: + /* activation completed or another enroll stage started */ + elan_calibrate (dev); +@@ -988,9 +986,8 @@ elan_change_state (FpImageDevice *idev) + + 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); ++ elan_stop_capture (dev); ++ break; + } + } + +-- +2.24.1 + diff --git a/SOURCES/0004-synaptics-Correctly-unref-pointer-array.patch b/SOURCES/0004-synaptics-Correctly-unref-pointer-array.patch new file mode 100644 index 0000000..2d8b5cb --- /dev/null +++ b/SOURCES/0004-synaptics-Correctly-unref-pointer-array.patch @@ -0,0 +1,36 @@ +From ada5d488fa769b4818a17a7042b8aa94ceea1519 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 25 Nov 2019 18:35:50 +0100 +Subject: [PATCH 004/181] synaptics: Correctly unref pointer array + +The pointer arrays were unref'ed using g_ptr_array_free rather than +g_ptr_array_unref from g_clear_pointer. Switch to the correct function. +--- + libfprint/drivers/synaptics/synaptics.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c +index b1d7365..4bac934 100644 +--- a/libfprint/drivers/synaptics/synaptics.c ++++ b/libfprint/drivers/synaptics/synaptics.c +@@ -447,7 +447,7 @@ list_msg_cb (FpiDeviceSynaptics *self, + + if (error) + { +- g_clear_pointer (&self->list_result, g_ptr_array_free); ++ g_clear_pointer (&self->list_result, g_ptr_array_unref); + fpi_device_list_complete (FP_DEVICE (self), NULL, error); + return; + } +@@ -468,7 +468,7 @@ list_msg_cb (FpiDeviceSynaptics *self, + else + { + fp_info ("Failed to query enrolled users: %d", resp->result); +- g_clear_pointer (&self->list_result, g_ptr_array_free); ++ g_clear_pointer (&self->list_result, g_ptr_array_unref); + fpi_device_list_complete (FP_DEVICE (self), + NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, +-- +2.24.1 + diff --git a/SOURCES/0005-synaptics-Add-an-explicit-assert-on-the-response.patch b/SOURCES/0005-synaptics-Add-an-explicit-assert-on-the-response.patch new file mode 100644 index 0000000..ee06f6d --- /dev/null +++ b/SOURCES/0005-synaptics-Add-an-explicit-assert-on-the-response.patch @@ -0,0 +1,27 @@ +From 8ba6f4dad2d9c04217153f32c11ac69967ddec00 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 25 Nov 2019 18:37:12 +0100 +Subject: [PATCH 005/181] synaptics: Add an explicit assert on the response + +The response must be non-NULL in the function. Add an explicit assert to +appease to static code analysis tools. +--- + libfprint/drivers/synaptics/synaptics.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c +index 4bac934..8eba852 100644 +--- a/libfprint/drivers/synaptics/synaptics.c ++++ b/libfprint/drivers/synaptics/synaptics.c +@@ -604,6 +604,8 @@ verify_msg_cb (FpiDeviceSynaptics *self, + return; + } + ++ g_assert (resp != NULL); ++ + verify_resp = &resp->response.verify_resp; + + switch (resp->response_id) +-- +2.24.1 + diff --git a/SOURCES/0006-upeksonly-Add-default-clauses-to-switch-statements.patch b/SOURCES/0006-upeksonly-Add-default-clauses-to-switch-statements.patch new file mode 100644 index 0000000..c2baa0d --- /dev/null +++ b/SOURCES/0006-upeksonly-Add-default-clauses-to-switch-statements.patch @@ -0,0 +1,58 @@ +From 2f0824ab8843ddb8bb46f000f802e641a9252d6d Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 25 Nov 2019 18:38:32 +0100 +Subject: [PATCH 006/181] upeksonly: Add default clauses to switch statements + +This effectively only annotates the code to make it clear that variables +set in the switch are always initialized. +--- + libfprint/drivers/upeksonly.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/libfprint/drivers/upeksonly.c b/libfprint/drivers/upeksonly.c +index 76ba4e2..ec81375 100644 +--- a/libfprint/drivers/upeksonly.c ++++ b/libfprint/drivers/upeksonly.c +@@ -1249,6 +1249,9 @@ loopsm_run_state (FpiSsm *ssm, FpDevice *_dev) + awfsm_1000_run_state, + AWFSM_1000_NUM_STATES); + break; ++ ++ default: ++ g_assert_not_reached (); + } + fpi_ssm_start_subsm (ssm, awfsm); + } +@@ -1290,6 +1293,9 @@ loopsm_run_state (FpiSsm *ssm, FpDevice *_dev) + capsm_1001_run_state, + CAPSM_1001_NUM_STATES); + break; ++ ++ default: ++ g_assert_not_reached (); + } + fpi_ssm_start_subsm (ssm, capsm); + break; +@@ -1318,6 +1324,9 @@ loopsm_run_state (FpiSsm *ssm, FpDevice *_dev) + deinitsm_1001_run_state, + DEINITSM_1001_NUM_STATES); + break; ++ ++ default: ++ g_assert_not_reached (); + } + self->capturing = FALSE; + fpi_ssm_start_subsm (ssm, deinitsm); +@@ -1441,6 +1450,9 @@ dev_activate (FpImageDevice *dev) + ssm = fpi_ssm_new (FP_DEVICE (dev), initsm_1001_run_state, + INITSM_1001_NUM_STATES); + break; ++ ++ default: ++ g_assert_not_reached (); + } + fpi_ssm_start (ssm, initsm_complete); + } +-- +2.24.1 + diff --git a/SOURCES/0007-image-device-Remove-unused-fpi_device_get_current_ac.patch b/SOURCES/0007-image-device-Remove-unused-fpi_device_get_current_ac.patch new file mode 100644 index 0000000..d607019 --- /dev/null +++ b/SOURCES/0007-image-device-Remove-unused-fpi_device_get_current_ac.patch @@ -0,0 +1,28 @@ +From 25bc89a4f57a3d414134ac5e66d28b377b3b1914 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 25 Nov 2019 18:40:21 +0100 +Subject: [PATCH 007/181] image-device: Remove unused + fpi_device_get_current_action call + +There is a later call in the function which is sufficient. Simply remove +the first call. +--- + libfprint/fp-image-device.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/libfprint/fp-image-device.c b/libfprint/fp-image-device.c +index 8524e06..65cca16 100644 +--- a/libfprint/fp-image-device.c ++++ b/libfprint/fp-image-device.c +@@ -493,8 +493,6 @@ fpi_image_device_report_finger_status (FpImageDevice *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 +-- +2.24.1 + diff --git a/SOURCES/0008-print-Free-temporary-col-variable.patch b/SOURCES/0008-print-Free-temporary-col-variable.patch new file mode 100644 index 0000000..6736140 --- /dev/null +++ b/SOURCES/0008-print-Free-temporary-col-variable.patch @@ -0,0 +1,25 @@ +From 14a41bdd485d484146a0a102d142239c2cb8a245 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 25 Nov 2019 18:40:59 +0100 +Subject: [PATCH 008/181] print: Free temporary col variable + +The variable was leaked during serialization. Free it. +--- + libfprint/fp-print.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c +index 644370d..592be14 100644 +--- a/libfprint/fp-print.c ++++ b/libfprint/fp-print.c +@@ -921,6 +921,7 @@ fp_print_serialize (FpPrint *print, + xyt->nrows, + sizeof (col[0]))); + g_variant_builder_close (&nested); ++ g_free (col); + } + + g_variant_builder_close (&nested); +-- +2.24.1 + diff --git a/SOURCES/0009-print-Ensure-xyt-struct-is-not-leaked-during-deseria.patch b/SOURCES/0009-print-Ensure-xyt-struct-is-not-leaked-during-deseria.patch new file mode 100644 index 0000000..56f9086 --- /dev/null +++ b/SOURCES/0009-print-Ensure-xyt-struct-is-not-leaked-during-deseria.patch @@ -0,0 +1,37 @@ +From 9b48864c5b41111e1c6f40c1623b0f2393c3cc58 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 25 Nov 2019 18:41:44 +0100 +Subject: [PATCH 009/181] print: Ensure xyt struct is not leaked during + deserialization + +In the unlikely event of an error, the variable may have been leaked. +Fix this by using g_autoptr combined with a g_steal_pointer. +--- + libfprint/fp-print.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c +index 592be14..1a6a70f 100644 +--- a/libfprint/fp-print.c ++++ b/libfprint/fp-print.c +@@ -1047,7 +1047,7 @@ fp_print_deserialize (const guchar *data, + 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); ++ g_autofree 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; +@@ -1078,7 +1078,7 @@ fp_print_deserialize (const guchar *data, + memcpy (xyt->ycol, ycol, sizeof (xcol[0]) * xlen); + memcpy (xyt->thetacol, thetacol, sizeof (xcol[0]) * xlen); + +- g_ptr_array_add (result->prints, xyt); ++ g_ptr_array_add (result->prints, g_steal_pointer (&xyt)); + } + } + else if (type == FP_PRINT_RAW) +-- +2.24.1 + diff --git a/SOURCES/0010-verify-Ensure-we-set-set-the-autoptr-value-to-NULL-a.patch b/SOURCES/0010-verify-Ensure-we-set-set-the-autoptr-value-to-NULL-a.patch new file mode 100644 index 0000000..e0ed5a0 --- /dev/null +++ b/SOURCES/0010-verify-Ensure-we-set-set-the-autoptr-value-to-NULL-a.patch @@ -0,0 +1,26 @@ +From 76dd4066f328ed76794e834b797abcd588650736 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 22 Nov 2019 17:31:50 +0100 +Subject: [PATCH 010/181] verify: Ensure we set set the autoptr value to NULL + at definition + +--- + examples/verify.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/examples/verify.c b/examples/verify.c +index 89a9b2c..4e1c988 100644 +--- a/examples/verify.c ++++ b/examples/verify.c +@@ -182,7 +182,7 @@ start_verification (FpDevice *dev, VerifyData *verify_data) + { + g_print ("Loading previously enrolled %s finger data...\n", + finger_to_string (verify_data->finger)); +- g_autoptr(FpPrint) verify_print; ++ g_autoptr(FpPrint) verify_print = NULL; + + verify_print = print_data_load (dev, verify_data->finger); + +-- +2.24.1 + diff --git a/SOURCES/0011-fpi-ssm-fp-device-Add-missing-copyright.patch b/SOURCES/0011-fpi-ssm-fp-device-Add-missing-copyright.patch new file mode 100644 index 0000000..7cdcf8a --- /dev/null +++ b/SOURCES/0011-fpi-ssm-fp-device-Add-missing-copyright.patch @@ -0,0 +1,50 @@ +From d8efa336e5f82b15d467163c5c5cdcec4ed51b28 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 21 Nov 2019 20:25:36 +0100 +Subject: [PATCH 011/181] fpi-ssm, fp-device: Add missing copyright + +--- + libfprint/fp-device.c | 1 + + libfprint/fpi-ssm.c | 1 + + libfprint/fpi-ssm.h | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c +index f9ccb3c..480d5cf 100644 +--- a/libfprint/fp-device.c ++++ b/libfprint/fp-device.c +@@ -1,6 +1,7 @@ + /* + * FpDevice - A fingerprint reader device + * 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 +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index 6b63e1a..f00af81 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -2,6 +2,7 @@ + * Functions to assist with asynchronous driver <---> library communications + * Copyright (C) 2007-2008 Daniel Drake + * 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 +diff --git a/libfprint/fpi-ssm.h b/libfprint/fpi-ssm.h +index 31a33e5..8d45162 100644 +--- a/libfprint/fpi-ssm.h ++++ b/libfprint/fpi-ssm.h +@@ -2,6 +2,7 @@ + * Copyright (C) 2007-2008 Daniel Drake + * Copyright (C) 2018 Bastien Nocera + * 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 +-- +2.24.1 + diff --git a/SOURCES/0012-meson-Use-multiline-array-for-default-dirvers-listin.patch b/SOURCES/0012-meson-Use-multiline-array-for-default-dirvers-listin.patch new file mode 100644 index 0000000..ab60963 --- /dev/null +++ b/SOURCES/0012-meson-Use-multiline-array-for-default-dirvers-listin.patch @@ -0,0 +1,48 @@ +From dd7d1baeceba8b2c8964b367797103f24a19adc6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 21 Nov 2019 20:24:29 +0100 +Subject: [PATCH 012/181] meson: Use multiline-array for default dirvers + listing + +It will make reviews and diffs nicer to handle when adding new drivers. +--- + meson.build | 23 ++++++++++++++++++++++- + 1 file changed, 22 insertions(+), 1 deletion(-) + +diff --git a/meson.build b/meson.build +index 8d06d45..a499a38 100644 +--- a/meson.build ++++ b/meson.build +@@ -51,7 +51,28 @@ mathlib_dep = cc.find_library('m', required: false) + # Drivers + drivers = get_option('drivers').split(',') + virtual_drivers = [ 'virtual_image' ] +-default_drivers = [ 'upektc_img', 'vfs5011', 'aes3500', 'aes4000', 'aes1610', 'aes1660', 'aes2660', 'aes2501', 'aes2550', 'vfs101', 'vfs301', 'vfs0050', 'etes603', 'vcom5s', 'synaptics', 'elan', 'uru4000', 'upektc', 'upeksonly', 'upekts' ] ++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 + +-- +2.24.1 + diff --git a/SOURCES/0013-meson-Use-preferred-syntax-everywhere.patch b/SOURCES/0013-meson-Use-preferred-syntax-everywhere.patch new file mode 100644 index 0000000..f72bdde --- /dev/null +++ b/SOURCES/0013-meson-Use-preferred-syntax-everywhere.patch @@ -0,0 +1,384 @@ +From 099fa9f005d22aa6d9c7ee79b9a11a088499994c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 21 Nov 2019 20:37:17 +0100 +Subject: [PATCH 013/181] meson: Use preferred syntax everywhere + +Meson files are normally using 4-spaces to indent and functions use first +parameter on the same line while others at next indentation level, not +following the parenthesis indentation. + +So adapt libfprint to follow the meson standard. +--- + demo/meson.build | 27 +++++++------ + doc/meson.build | 48 +++++++++++------------ + doc/xml/meson.build | 4 +- + examples/meson.build | 24 ++++++------ + libfprint/meson.build | 89 +++++++++++++++++++++---------------------- + meson.build | 31 ++++++++------- + tests/meson.build | 9 ++--- + 7 files changed, 116 insertions(+), 116 deletions(-) + +diff --git a/demo/meson.build b/demo/meson.build +index ceca56d..bf7a7ee 100644 +--- a/demo/meson.build ++++ b/demo/meson.build +@@ -1,21 +1,24 @@ +-gtk_test_resources = gnome.compile_resources('gtk-test-resources', 'gtk-libfprint-test.gresource.xml', +- source_dir : '.', +- c_name : 'gtk_test') ++gtk_test_resources = gnome.compile_resources('gtk-test-resources', ++ 'gtk-libfprint-test.gresource.xml', ++ source_dir : '.', ++ c_name : 'gtk_test') + + prefix = get_option('prefix') + bindir = join_paths(prefix, get_option('bindir')) + datadir = join_paths(prefix, get_option('datadir')) + + executable('gtk-libfprint-test', +- [ 'gtk-libfprint-test.c', gtk_test_resources ], +- dependencies: [ libfprint_dep, gtk_dep ], +- include_directories: [ +- root_inc, +- ], +- c_args: [ common_cflags, +- '-DPACKAGE_VERSION="' + meson.project_version() + '"' ], +- install: true, +- install_dir: bindir) ++ [ 'gtk-libfprint-test.c', gtk_test_resources ], ++ dependencies: [ libfprint_dep, gtk_dep ], ++ include_directories: [ ++ root_inc, ++ ], ++ c_args: [ ++ common_cflags, ++ '-DPACKAGE_VERSION="' + meson.project_version() + '"' ++ ], ++ install: true, ++ install_dir: bindir) + + appdata = 'org.freedesktop.libfprint.Demo.appdata.xml' + install_data(appdata, +diff --git a/doc/meson.build b/doc/meson.build +index 5418667..407413a 100644 +--- a/doc/meson.build ++++ b/doc/meson.build +@@ -1,14 +1,14 @@ + subdir('xml') + + private_headers = [ +- 'config.h', +- 'nbis-helpers.h', +- 'fprint.h', +- 'fp_internal.h', ++ 'config.h', ++ 'nbis-helpers.h', ++ 'fprint.h', ++ 'fp_internal.h', + +- # Subdirectories to ignore +- 'drivers', +- 'nbis', ++ # Subdirectories to ignore ++ 'drivers', ++ 'nbis', + ] + + html_images = [ +@@ -25,20 +25,20 @@ glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html') + docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html') + + gnome.gtkdoc('libfprint', +- main_xml: 'libfprint-docs.xml', +- src_dir: join_paths(meson.source_root(), 'libfprint'), +- dependencies: libfprint_dep, +- content_files: content_files, +- expand_content_files: expand_content_files, +- scan_args: [ +- #'--rebuild-sections', +- '--ignore-decorators=API_EXPORTED', +- '--ignore-headers=' + ' '.join(private_headers), +- ], +- fixxref_args: [ +- '--html-dir=@0@'.format(docpath), +- '--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')), +- '--extra-dir=@0@'.format(join_paths(glib_docpath, 'gobject')), +- ], +- html_assets: html_images, +- install: true) ++ main_xml: 'libfprint-docs.xml', ++ src_dir: join_paths(meson.source_root(), 'libfprint'), ++ dependencies: libfprint_dep, ++ content_files: content_files, ++ expand_content_files: expand_content_files, ++ scan_args: [ ++ #'--rebuild-sections', ++ '--ignore-decorators=API_EXPORTED', ++ '--ignore-headers=' + ' '.join(private_headers), ++ ], ++ fixxref_args: [ ++ '--html-dir=@0@'.format(docpath), ++ '--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')), ++ '--extra-dir=@0@'.format(join_paths(glib_docpath, 'gobject')), ++ ], ++ html_assets: html_images, ++ install: true) +diff --git a/doc/xml/meson.build b/doc/xml/meson.build +index e35f7ee..2ca1100 100644 +--- a/doc/xml/meson.build ++++ b/doc/xml/meson.build +@@ -7,4 +7,6 @@ ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version()) + ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/') + ent_conf.set('PACKAGE_VERSION', meson.project_version()) + ent_conf.set('PACKAGE_API_VERSION', '1.0') +-configure_file(input: 'gtkdocentities.ent.in', output: 'gtkdocentities.ent', configuration: ent_conf) ++configure_file(input: 'gtkdocentities.ent.in', ++ output: 'gtkdocentities.ent', ++ configuration: ent_conf) +diff --git a/examples/meson.build b/examples/meson.build +index 5cd3d83..ff03ac6 100644 +--- a/examples/meson.build ++++ b/examples/meson.build +@@ -2,18 +2,18 @@ + examples = [ 'enroll', 'verify', 'manage-prints' ] + foreach example: examples + executable(example, +- [example + '.c', 'storage.c', 'utilities.c'], +- dependencies: [libfprint_dep, glib_dep], +- include_directories: [ +- root_inc, +- ], +- c_args: common_cflags) ++ [ example + '.c', 'storage.c', 'utilities.c' ], ++ 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) ++ 'cpp-test.cpp', ++ dependencies: libfprint_dep, ++ include_directories: [ ++ root_inc, ++ ], ++ c_args: common_cflags) +diff --git a/libfprint/meson.build b/libfprint/meson.build +index af2fe84..f77965a 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -162,73 +162,73 @@ endif + other_sources = [] + + fp_enums = gnome.mkenums_simple('fp-enums', +- sources: libfprint_public_headers, +- install_header : true) ++ sources: libfprint_public_headers, ++ install_header : true) + fp_enums_h = fp_enums[1] + + fpi_enums = gnome.mkenums_simple('fpi-enums', +- sources: libfprint_private_headers, +- install_header : true) ++ sources: libfprint_private_headers, ++ install_header : true) + fpi_enums_h = fpi_enums[1] + + drivers_sources += configure_file(input: 'empty_file', +- output: 'fp-drivers.c', +- capture: true, +- command: [ +- 'echo', +- drivers_type_list + '\n\n' + drivers_type_func +- ]) ++ 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 + fp_enums + fpi_enums + +- drivers_sources + nbis_sources + other_sources, +- soversion: soversion, +- version: libversion, +- c_args: common_cflags + drivers_cflags, +- include_directories: [ +- root_inc, +- include_directories('nbis/include'), +- ], +- link_args : vflag, +- link_depends : mapfile, +- dependencies: deps, +- install: true) ++ libfprint_sources + fp_enums + fpi_enums + ++ drivers_sources + nbis_sources + other_sources, ++ soversion: soversion, ++ version: libversion, ++ c_args: common_cflags + drivers_cflags, ++ include_directories: [ ++ 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, gusb_dep, gio_dep]) ++ sources: [ fp_enums_h ], ++ include_directories: root_inc, ++ dependencies: [ glib_dep, gusb_dep, gio_dep ]) + + install_headers(['fprint.h'] + libfprint_public_headers, subdir: 'libfprint') + + udev_rules = executable('fprint-list-udev-rules', +- 'fprint-list-udev-rules.c', +- include_directories: [ +- root_inc, +- ], +- dependencies: [ deps, libfprint_dep ], +- install: false) ++ 'fprint-list-udev-rules.c', ++ include_directories: [ ++ root_inc, ++ ], ++ dependencies: [ deps, libfprint_dep ], ++ install: false) + + if get_option('udev_rules') + custom_target('udev-rules', +- output: '60-fprint-autosuspend.rules', +- capture: true, +- command: [ udev_rules ], +- install: true, +- install_dir: udev_rules_dir) ++ output: '60-fprint-autosuspend.rules', ++ capture: true, ++ command: [ udev_rules ], ++ install: true, ++ install_dir: udev_rules_dir) + endif + + supported_devices = executable('fprint-list-supported-devices', +- 'fprint-list-supported-devices.c', +- include_directories: [ +- root_inc, +- ], +- dependencies: [ deps, libfprint_dep ], +- install: false) ++ 'fprint-list-supported-devices.c', ++ include_directories: [ ++ root_inc, ++ ], ++ dependencies: [ deps, libfprint_dep ], ++ install: false) + + + if get_option('introspection') +@@ -256,8 +256,7 @@ if get_option('introspection') + 'GObject-2.0', + 'GUsb-1.0', + ], +- install : true +- ) ++ install : true) + libfprint_gir = libfprint_girtarget[0] + libfprint_typelib = libfprint_girtarget[1] + endif +diff --git a/meson.build b/meson.build +index a499a38..158a2a0 100644 +--- a/meson.build ++++ b/meson.build +@@ -1,12 +1,12 @@ + project('libfprint', [ 'c', 'cpp' ], +- version: '1.90.0', +- license: 'LGPLv2.1+', +- default_options: [ +- 'buildtype=debugoptimized', +- 'warning_level=1', +- 'c_std=c99', +- ], +- meson_version: '>= 0.46.0') ++ version: '1.90.0', ++ license: 'LGPLv2.1+', ++ default_options: [ ++ 'buildtype=debugoptimized', ++ 'warning_level=1', ++ 'c_std=c99', ++ ], ++ meson_version: '>= 0.46.0') + + gnome = import('gnome') + +@@ -160,11 +160,10 @@ endif + + pkgconfig = import('pkgconfig') + pkgconfig.generate( +- name: 'libfprint', +- description: 'Generic C API for fingerprint reader access', +- version: meson.project_version(), +- libraries: libfprint, +- subdirs: 'libfprint', +- filebase: 'libfprint2', +- install_dir: join_paths(get_option('libdir'), 'pkgconfig'), +-) ++ name: 'libfprint', ++ description: 'Generic C API for fingerprint reader access', ++ version: meson.project_version(), ++ libraries: libfprint, ++ subdirs: 'libfprint', ++ filebase: 'libfprint2', ++ install_dir: join_paths(get_option('libdir'), 'pkgconfig')) +diff --git a/tests/meson.build b/tests/meson.build +index d02b05a..7987692 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -16,8 +16,7 @@ envs.set('NO_AT_BRIDGE', '1') + + if get_option('introspection') + if 'virtual_image' in drivers +- test( +- 'virtual-image', ++ test('virtual-image', + find_program('virtual-image.py'), + args: '--verbose', + env: envs, +@@ -26,8 +25,7 @@ if get_option('introspection') + endif + + if 'vfs5011' in drivers +- test( +- 'vfs5011', ++ test('vfs5011', + find_program('umockdev-test.py'), + args: join_paths(meson.current_source_dir(), 'vfs5011'), + env: envs, +@@ -37,8 +35,7 @@ if get_option('introspection') + endif + + if 'synaptics' in drivers +- test( +- 'synaptics', ++ test('synaptics', + find_program('umockdev-test.py'), + args: join_paths(meson.current_source_dir(), 'synaptics'), + env: envs, +-- +2.24.1 + diff --git a/SOURCES/0014-meson-Avoid-repeating-the-needed-glib-version-multip.patch b/SOURCES/0014-meson-Avoid-repeating-the-needed-glib-version-multip.patch new file mode 100644 index 0000000..cb0d55f --- /dev/null +++ b/SOURCES/0014-meson-Avoid-repeating-the-needed-glib-version-multip.patch @@ -0,0 +1,54 @@ +From ceb62d7617a01de49d8e1580f14359972cd545d8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 22 Nov 2019 14:09:51 +0100 +Subject: [PATCH 014/181] meson: Avoid repeating the needed glib version + multiple times + +Just define once and modify its syntax when needed. +Use a more verbose definition for the min/max version (instead of just +join the split version) so that in case we may depend on a specifc glib +micro release during development. +--- + meson.build | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/meson.build b/meson.build +index 158a2a0..cf277f5 100644 +--- a/meson.build ++++ b/meson.build +@@ -18,7 +18,10 @@ libfprint_conf = configuration_data() + cc = meson.get_compiler('c') + cpp = meson.get_compiler('cpp') + host_system = host_machine.system() ++glib_min_version = '2.50' + ++glib_version_def = 'GLIB_VERSION_@0@_@1@'.format( ++ glib_min_version.split('.')[0], glib_min_version.split('.')[1]) + common_cflags = cc.get_supported_arguments([ + '-fgnu89-inline', + '-std=gnu99', +@@ -30,8 +33,8 @@ common_cflags = cc.get_supported_arguments([ + '-Werror-implicit-function-declaration', + '-Wno-pointer-sign', + '-Wshadow', +- '-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_50', +- '-DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_50', ++ '-DGLIB_VERSION_MIN_REQUIRED=' + glib_version_def, ++ '-DGLIB_VERSION_MAX_ALLOWED=' + glib_version_def, + ]) + + # maintaining compatibility with the previous libtool versioning +@@ -43,8 +46,8 @@ revision = 0 + 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') ++glib_dep = dependency('glib-2.0', version: '>=' + glib_min_version) ++gio_dep = dependency('gio-unix-2.0', version: '>=' + glib_min_version) + gusb_dep = dependency('gusb', version: '>= 0.3.0') + mathlib_dep = cc.find_library('m', required: false) + +-- +2.24.1 + diff --git a/SOURCES/0015-image-device-Use-g_clear_handle_id-for-timeouts.patch b/SOURCES/0015-image-device-Use-g_clear_handle_id-for-timeouts.patch new file mode 100644 index 0000000..0bbdecb --- /dev/null +++ b/SOURCES/0015-image-device-Use-g_clear_handle_id-for-timeouts.patch @@ -0,0 +1,58 @@ +From 8b270141f32411a02dffa1833564a8dafe6c1fd3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 22 Nov 2019 13:06:08 +0100 +Subject: [PATCH 015/181] image-device: Use g_clear_handle_id for timeouts + +As per this depend on glib 2.56: it has been released almost 2 years ago, +I suppose we're fine with that. +--- + libfprint/fp-image-device.c | 12 ++---------- + meson.build | 2 +- + 2 files changed, 3 insertions(+), 11 deletions(-) + +diff --git a/libfprint/fp-image-device.c b/libfprint/fp-image-device.c +index 65cca16..44de578 100644 +--- a/libfprint/fp-image-device.c ++++ b/libfprint/fp-image-device.c +@@ -80,11 +80,7 @@ fp_image_device_change_state (FpImageDevice *self, FpImageDeviceState state) + + /* 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; +- } ++ g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove); + + fp_dbg ("Image device internal state change from %d to %d\n", priv->state, state); + +@@ -110,11 +106,7 @@ fp_image_device_activate (FpImageDevice *self) + + /* 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; +- } ++ g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove); + + fp_dbg ("Activating image device\n"); + cls->activate (self); +diff --git a/meson.build b/meson.build +index cf277f5..ef352ba 100644 +--- a/meson.build ++++ b/meson.build +@@ -18,7 +18,7 @@ libfprint_conf = configuration_data() + cc = meson.get_compiler('c') + cpp = meson.get_compiler('cpp') + host_system = host_machine.system() +-glib_min_version = '2.50' ++glib_min_version = '2.56' + + glib_version_def = 'GLIB_VERSION_@0@_@1@'.format( + glib_min_version.split('.')[0], glib_min_version.split('.')[1]) +-- +2.24.1 + diff --git a/SOURCES/0016-fp-print-Use-g_date_copy.patch b/SOURCES/0016-fp-print-Use-g_date_copy.patch new file mode 100644 index 0000000..71c4779 --- /dev/null +++ b/SOURCES/0016-fp-print-Use-g_date_copy.patch @@ -0,0 +1,32 @@ +From 201b5a9614afdc39f6cef08072834d59ab63ff65 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 22 Nov 2019 14:19:10 +0100 +Subject: [PATCH 016/181] fp-print: Use g_date_copy + +As per previous commit we depend on glib 2.56, we can use this utility +function as well. +--- + libfprint/fp-print.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c +index 1a6a70f..39c5c0a 100644 +--- a/libfprint/fp-print.c ++++ b/libfprint/fp-print.c +@@ -534,11 +534,8 @@ fp_print_set_enroll_date (FpPrint *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; +- } ++ print->enroll_date = g_date_copy (enroll_date); ++ + g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_ENROLL_DATE]); + } + +-- +2.24.1 + diff --git a/SOURCES/0017-fp-image-device-Clear-the-pending-activation-timeout.patch b/SOURCES/0017-fp-image-device-Clear-the-pending-activation-timeout.patch new file mode 100644 index 0000000..53dff5e --- /dev/null +++ b/SOURCES/0017-fp-image-device-Clear-the-pending-activation-timeout.patch @@ -0,0 +1,25 @@ +From 60ad1ab9e3e5ecc1fe7bf390a2cec2e662dfd567 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 22 Nov 2019 13:08:33 +0100 +Subject: [PATCH 017/181] fp-image-device: Clear the pending activation timeout + on finalize + +--- + libfprint/fp-image-device.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libfprint/fp-image-device.c b/libfprint/fp-image-device.c +index 44de578..9aa9e1f 100644 +--- a/libfprint/fp-image-device.c ++++ b/libfprint/fp-image-device.c +@@ -278,6 +278,7 @@ fp_image_device_finalize (GObject *object) + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + + g_assert (priv->active == FALSE); ++ g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove); + + G_OBJECT_CLASS (fp_image_device_parent_class)->finalize (object); + } +-- +2.24.1 + diff --git a/SOURCES/0018-fp-image-device-Reactivate-in-idle-on-deactivation-c.patch b/SOURCES/0018-fp-image-device-Reactivate-in-idle-on-deactivation-c.patch new file mode 100644 index 0000000..0228007 --- /dev/null +++ b/SOURCES/0018-fp-image-device-Reactivate-in-idle-on-deactivation-c.patch @@ -0,0 +1,34 @@ +From ea4da08af014343bffa6254d78514c2f3076575b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 22 Nov 2019 13:19:03 +0100 +Subject: [PATCH 018/181] fp-image-device: Reactivate in idle on deactivation + completed + +This is the same logic we apply to fp-device by default: any completed +action should trigger the subsequent one when it is finished. +So in case we want reactivate after a deactivation, let's do it in an idle, +after removing the current pending timeout. +--- + libfprint/fp-image-device.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/libfprint/fp-image-device.c b/libfprint/fp-image-device.c +index 9aa9e1f..84b1bb0 100644 +--- a/libfprint/fp-image-device.c ++++ b/libfprint/fp-image-device.c +@@ -732,7 +732,11 @@ fpi_image_device_deactivate_complete (FpImageDevice *self, GError *error) + + /* We might be waiting to be able to activate again. */ + if (priv->pending_activation_timeout_id) +- fp_image_device_activate (self); ++ { ++ g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove); ++ priv->pending_activation_timeout_id = ++ g_idle_add ((GSourceFunc) fp_image_device_activate, self); ++ } + } + + /** +-- +2.24.1 + diff --git a/SOURCES/0019-fp-image-device-Add-private-fp-image-device-state-pr.patch b/SOURCES/0019-fp-image-device-Add-private-fp-image-device-state-pr.patch new file mode 100644 index 0000000..1931f10 --- /dev/null +++ b/SOURCES/0019-fp-image-device-Add-private-fp-image-device-state-pr.patch @@ -0,0 +1,132 @@ +From be367988ae4fc4d91d5cad7c9f7d47f67a878540 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 22 Nov 2019 13:51:16 +0100 +Subject: [PATCH 019/181] fp-image-device: Add private "fp-image-device-state" + property + +In this way drivers may get this without having to keep a copy of it +--- + libfprint/fp-image-device.c | 44 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 44 insertions(+) + +diff --git a/libfprint/fp-image-device.c b/libfprint/fp-image-device.c +index 84b1bb0..3565b90 100644 +--- a/libfprint/fp-image-device.c ++++ b/libfprint/fp-image-device.c +@@ -21,6 +21,7 @@ + #include "fpi-log.h" + + #include "fpi-image-device.h" ++#include "fpi-enums.h" + #include "fpi-print.h" + #include "fpi-image.h" + +@@ -60,6 +61,13 @@ typedef struct + + G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (FpImageDevice, fp_image_device, FP_TYPE_DEVICE) + ++enum { ++ PROP_0, ++ PROP_FPI_STATE, ++ N_PROPS ++}; ++ ++static GParamSpec *properties[N_PROPS]; + + /*******************************************************/ + +@@ -85,6 +93,7 @@ fp_image_device_change_state (FpImageDevice *self, FpImageDeviceState state) + fp_dbg ("Image device internal state change from %d to %d\n", priv->state, state); + + priv->state = state; ++ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]); + + /* change_state is the only callback which is optional and does not + * have a default implementation. */ +@@ -103,6 +112,7 @@ fp_image_device_activate (FpImageDevice *self) + /* 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; ++ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]); + + /* We might have been waiting for deactivation to finish before + * starting the next operation. */ +@@ -127,6 +137,7 @@ fp_image_device_deactivate (FpDevice *device) + return; + } + priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE; ++ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]); + + fp_dbg ("Deactivating image device\n"); + cls->deactivate (self); +@@ -295,6 +306,26 @@ fp_image_device_default_deactivate (FpImageDevice *self) + fpi_image_device_deactivate_complete (self, NULL); + } + ++static void ++fp_image_device_get_property (GObject *object, ++ guint prop_id, ++ GValue *value, ++ GParamSpec *pspec) ++{ ++ FpImageDevice *self = FP_IMAGE_DEVICE (object); ++ FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); ++ ++ switch (prop_id) ++ { ++ case PROP_FPI_STATE: ++ g_value_set_enum (value, priv->state); ++ break; ++ ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ } ++} ++ + static void + fp_image_device_class_init (FpImageDeviceClass *klass) + { +@@ -302,6 +333,7 @@ fp_image_device_class_init (FpImageDeviceClass *klass) + FpDeviceClass *fp_device_class = FP_DEVICE_CLASS (klass); + + object_class->finalize = fp_image_device_finalize; ++ object_class->get_property = fp_image_device_get_property; + + fp_device_class->open = fp_image_device_open; + fp_device_class->close = fp_image_device_close; +@@ -315,6 +347,16 @@ fp_image_device_class_init (FpImageDeviceClass *klass) + /* Default implementations */ + klass->activate = fp_image_device_default_activate; + klass->deactivate = fp_image_device_default_deactivate; ++ ++ properties[PROP_FPI_STATE] = ++ g_param_spec_enum ("fp-image-device-state", ++ "Image Device State", ++ "Private: The state of the image device", ++ FP_TYPE_IMAGE_DEVICE_STATE, ++ FP_IMAGE_DEVICE_STATE_INACTIVE, ++ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); ++ ++ g_object_class_install_properties (object_class, N_PROPS, properties); + } + + static void +@@ -760,6 +802,7 @@ fpi_image_device_open_complete (FpImageDevice *self, GError *error) + g_debug ("Image device open completed"); + + priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE; ++ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]); + + fpi_device_open_complete (FP_DEVICE (self), error); + } +@@ -785,6 +828,7 @@ fpi_image_device_close_complete (FpImageDevice *self, GError *error) + g_return_if_fail (action == FP_DEVICE_ACTION_CLOSE); + + priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE; ++ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]); + + fpi_device_close_complete (FP_DEVICE (self), error); + } +-- +2.24.1 + diff --git a/SOURCES/0020-fp-image-device-Use-a-GObject-signal-to-notify-image.patch b/SOURCES/0020-fp-image-device-Use-a-GObject-signal-to-notify-image.patch new file mode 100644 index 0000000..f460c4d --- /dev/null +++ b/SOURCES/0020-fp-image-device-Use-a-GObject-signal-to-notify-image.patch @@ -0,0 +1,70 @@ +From cca6d3b04b74558e12df3aa43761faaa574c5ff9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 22 Nov 2019 14:50:48 +0100 +Subject: [PATCH 020/181] fp-image-device: Use a GObject signal to notify image + state changed + +This is more GObject-friendly and we have the automatic call of the vfunc if +one is set. +--- + libfprint/fp-image-device.c | 23 +++++++++++++++++------ + 1 file changed, 17 insertions(+), 6 deletions(-) + +diff --git a/libfprint/fp-image-device.c b/libfprint/fp-image-device.c +index 3565b90..692727b 100644 +--- a/libfprint/fp-image-device.c ++++ b/libfprint/fp-image-device.c +@@ -69,6 +69,14 @@ enum { + + static GParamSpec *properties[N_PROPS]; + ++enum { ++ FPI_STATE_CHANGED, ++ ++ LAST_SIGNAL ++}; ++ ++static guint signals[LAST_SIGNAL] = { 0 }; ++ + /*******************************************************/ + + /* TODO: +@@ -81,7 +89,6 @@ 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); +@@ -94,11 +101,7 @@ fp_image_device_change_state (FpImageDevice *self, FpImageDeviceState state) + + priv->state = state; + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_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); ++ g_signal_emit (self, signals[FPI_STATE_CHANGED], 0, priv->state); + } + + static void +@@ -356,6 +359,14 @@ fp_image_device_class_init (FpImageDeviceClass *klass) + FP_IMAGE_DEVICE_STATE_INACTIVE, + G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); + ++ signals[FPI_STATE_CHANGED] = ++ g_signal_new ("fp-image-device-state-changed", ++ G_TYPE_FROM_CLASS (object_class), ++ G_SIGNAL_RUN_FIRST, ++ G_STRUCT_OFFSET (FpImageDeviceClass, change_state), ++ NULL, NULL, NULL, ++ G_TYPE_NONE, 1, FP_TYPE_IMAGE_DEVICE_STATE); ++ + g_object_class_install_properties (object_class, N_PROPS, properties); + } + +-- +2.24.1 + diff --git a/SOURCES/0021-fpi-ssm-Remove-any-reference-to-fpi_timeout_add.patch b/SOURCES/0021-fpi-ssm-Remove-any-reference-to-fpi_timeout_add.patch new file mode 100644 index 0000000..afa4fe6 --- /dev/null +++ b/SOURCES/0021-fpi-ssm-Remove-any-reference-to-fpi_timeout_add.patch @@ -0,0 +1,32 @@ +From 0a08a248966b3ecc9c30c0654ed1326f64a8b0cc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 22 Nov 2019 16:27:18 +0100 +Subject: [PATCH 021/181] fpi-ssm: Remove any reference to fpi_timeout_add() + +This doesn't exist anymore, while fpi_device_add_timeout does exists. +--- + libfprint/fpi-ssm.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index f00af81..1569be8 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -367,11 +367,11 @@ fpi_ssm_dup_error (FpiSsm *machine) + * @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. ++ * for an fpi_device_add_timeout() callback, when the state ++ * change needs to happen after a timeout. + * + * Make sure to pass the #FpiSsm as the `ssm_data` argument +- * for that fpi_timeout_add() call. ++ * for that fpi_device_add_timeout() call. + */ + void + fpi_ssm_next_state_timeout_cb (FpDevice *dev, +-- +2.24.1 + diff --git a/SOURCES/0022-fpi-log-Set-fp_error-as-equal-to-g_critical.patch b/SOURCES/0022-fpi-log-Set-fp_error-as-equal-to-g_critical.patch new file mode 100644 index 0000000..88dbb20 --- /dev/null +++ b/SOURCES/0022-fpi-log-Set-fp_error-as-equal-to-g_critical.patch @@ -0,0 +1,30 @@ +From 15d218a112728c9ded518f55a985223861f79cda Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 22 Nov 2019 17:56:24 +0100 +Subject: [PATCH 022/181] fpi-log: Set fp_error as equal to g_critical + +--- + libfprint/fpi-log.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libfprint/fpi-log.h b/libfprint/fpi-log.h +index 1c3d5ad..8f2f6a1 100644 +--- a/libfprint/fpi-log.h ++++ b/libfprint/fpi-log.h +@@ -68,11 +68,11 @@ + /** + * fp_err: + * +- * Same as g_warning(). In the future, this might be changed to a ++ * Same as g_critical(). In the future, this might be changed to a + * g_assert() instead, so bear this in mind when adding those calls + * to your driver. + */ +-#define fp_err g_warning ++#define fp_err g_critical + + /** + * BUG_ON: +-- +2.24.1 + diff --git a/SOURCES/0023-fp-device-Support-variadic-arguments-to-error-functi.patch b/SOURCES/0023-fp-device-Support-variadic-arguments-to-error-functi.patch new file mode 100644 index 0000000..11ec97e --- /dev/null +++ b/SOURCES/0023-fp-device-Support-variadic-arguments-to-error-functi.patch @@ -0,0 +1,80 @@ +From 555fa2dc485b455faa730406faf57acd4d954197 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 25 Nov 2019 21:22:47 +0100 +Subject: [PATCH 023/181] fp-device: Support variadic arguments to error + functions + +Make possible to generate a formatted message when creating an error from +a device, without having save it first. +--- + libfprint/fp-device.c | 26 ++++++++++++++++++++++---- + libfprint/fpi-device.h | 6 ++++-- + 2 files changed, 26 insertions(+), 6 deletions(-) + +diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c +index 480d5cf..13f1b5a 100644 +--- a/libfprint/fp-device.c ++++ b/libfprint/fp-device.c +@@ -243,9 +243,18 @@ fpi_device_error_new (FpDeviceError error) + * and similar calls. + */ + GError * +-fpi_device_retry_new_msg (FpDeviceRetry error, const gchar *msg) ++fpi_device_retry_new_msg (FpDeviceRetry device_error, ++ const gchar *msg, ++ ...) + { +- return g_error_new_literal (FP_DEVICE_RETRY, error, msg); ++ GError *error; ++ va_list args; ++ ++ va_start (args, msg); ++ error = g_error_new_valist (FP_DEVICE_RETRY, device_error, msg, args); ++ va_end (args); ++ ++ return error; + } + + /** +@@ -257,9 +266,18 @@ fpi_device_retry_new_msg (FpDeviceRetry error, const gchar *msg) + * and similar calls. + */ + GError * +-fpi_device_error_new_msg (FpDeviceError error, const gchar *msg) ++fpi_device_error_new_msg (FpDeviceError device_error, ++ const gchar *msg, ++ ...) + { +- return g_error_new_literal (FP_DEVICE_ERROR, error, msg); ++ GError *error; ++ va_list args; ++ ++ va_start (args, msg); ++ error = g_error_new_valist (FP_DEVICE_ERROR, device_error, msg, args); ++ va_end (args); ++ ++ return error; + } + + static gboolean +diff --git a/libfprint/fpi-device.h b/libfprint/fpi-device.h +index a206798..d83a5a3 100644 +--- a/libfprint/fpi-device.h ++++ b/libfprint/fpi-device.h +@@ -181,9 +181,11 @@ 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); ++ const gchar *msg, ++ ...) G_GNUC_PRINTF (2, 3); + GError * fpi_device_error_new_msg (FpDeviceError error, +- const gchar *msg); ++ const gchar *msg, ++ ...) G_GNUC_PRINTF (2, 3); + + guint64 fpi_device_get_driver_data (FpDevice *device); + +-- +2.24.1 + diff --git a/SOURCES/0024-drivers-Use-clearer-messages-using-parameters.patch b/SOURCES/0024-drivers-Use-clearer-messages-using-parameters.patch new file mode 100644 index 0000000..da2eda1 --- /dev/null +++ b/SOURCES/0024-drivers-Use-clearer-messages-using-parameters.patch @@ -0,0 +1,158 @@ +From d830d88463dc9ecdb1943662910692fd4cb7bdf3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 25 Nov 2019 21:23:31 +0100 +Subject: [PATCH 024/181] drivers: Use clearer messages using parameters + +--- + libfprint/drivers/aesx660.c | 16 +++++++++++----- + libfprint/drivers/synaptics/synaptics.c | 17 ++++++++++++----- + libfprint/drivers/upekts.c | 8 +++++--- + 3 files changed, 28 insertions(+), 13 deletions(-) + +diff --git a/libfprint/drivers/aesx660.c b/libfprint/drivers/aesx660.c +index 8540a06..8ad4c63 100644 +--- a/libfprint/drivers/aesx660.c ++++ b/libfprint/drivers/aesx660.c +@@ -131,7 +131,9 @@ aesX660_read_calibrate_data_cb (FpiUsbTransfer *transfer, + 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")); ++ "Bogus calibrate " ++ "response: %.2x", ++ data[0])); + return; + } + +@@ -175,7 +177,8 @@ finger_det_read_fd_data_cb (FpiUsbTransfer *transfer, + 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")); ++ "Bogus FD response %.2x", ++ data[0])); + return; + } + +@@ -538,7 +541,8 @@ activate_read_id_cb (FpiUsbTransfer *transfer, FpDevice *device, + 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")); ++ "Bogus read ID response %.2x", ++ data[AESX660_RESPONSE_TYPE_OFFSET])); + return; + } + +@@ -565,7 +569,8 @@ activate_read_id_cb (FpiUsbTransfer *transfer, FpDevice *device, + 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")); ++ "Failed to init device %.2x", ++ data[7])); + break; + } + } +@@ -594,7 +599,8 @@ activate_read_init_cb (FpiUsbTransfer *transfer, FpDevice *device, + data[3]); + fpi_ssm_mark_failed (transfer->ssm, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, +- "Bogus read init response")); ++ "Bogus read init response: " ++ "%.2x %.2x", data[0], data[3])); + return; + } + priv->init_cmd_idx++; +diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c +index 8eba852..f6faf11 100644 +--- a/libfprint/drivers/synaptics/synaptics.c ++++ b/libfprint/drivers/synaptics/synaptics.c +@@ -137,7 +137,8 @@ cmd_recieve_cb (FpiUsbTransfer *transfer, + 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")); ++ "Received general error %u from device", ++ (guint) err)); + //fpi_ssm_jump_to_state (transfer->ssm, fpi_ssm_get_cur_state (transfer->ssm)); + return; + } +@@ -472,7 +473,8 @@ list_msg_cb (FpiDeviceSynaptics *self, + fpi_device_list_complete (FP_DEVICE (self), + NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, +- "Failed to query enrolled users")); ++ "Failed to query enrolled users: %d", ++ resp->result)); + } + break; + +@@ -770,7 +772,8 @@ enroll_msg_cb (FpiDeviceSynaptics *self, + fpi_device_enroll_complete (device, + NULL, + fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, +- "Enrollment failed")); ++ "Enrollment failed (%d)", ++ resp->result)); + } + break; + } +@@ -1052,7 +1055,11 @@ dev_probe (FpDevice *device) + self->mis_version.build_num); + + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, +- "Unsupported firmware version"); ++ "Unsupported firmware version " ++ "(%d.%d with build number %d)", ++ self->mis_version.version_major, ++ self->mis_version.version_minor, ++ self->mis_version.build_num); + goto err_close; + } + +@@ -1120,7 +1127,7 @@ fps_deinit_cb (FpiDeviceSynaptics *self, + 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"); ++ "Power down failed: %d", resp->result); + + break; + } +diff --git a/libfprint/drivers/upekts.c b/libfprint/drivers/upekts.c +index 2426907..b3481aa 100644 +--- a/libfprint/drivers/upekts.c ++++ b/libfprint/drivers/upekts.c +@@ -288,7 +288,7 @@ __handle_incoming_msg (FpDevice *device, + { + fp_warn ("cmd response too short (%d)", len); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, +- "CMD response too short"); ++ "CMD response too short (%d)", len); + goto err; + } + if (innerbuf[0] != 0x28) +@@ -371,7 +371,8 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device, + 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"); ++ "Packet from device was too short (%lu)", ++ transfer->actual_length); + goto err; + } + +@@ -798,7 +799,8 @@ read_msg01_cb (FpDevice *dev, enum read_msg_type type, + { + 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")); ++ "Got wrong sequence number (%x)", ++ seq)); + return; + } + +-- +2.24.1 + diff --git a/SOURCES/0025-synaptics-Use-GDate-getters-to-retrieve-the-DMY-valu.patch b/SOURCES/0025-synaptics-Use-GDate-getters-to-retrieve-the-DMY-valu.patch new file mode 100644 index 0000000..ac53316 --- /dev/null +++ b/SOURCES/0025-synaptics-Use-GDate-getters-to-retrieve-the-DMY-valu.patch @@ -0,0 +1,40 @@ +From af26f2e307abde413d3f876c16eee93f5f9413fe Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 27 Nov 2019 16:50:54 +0100 +Subject: [PATCH 025/181] synaptics: Use GDate getters to retrieve the DMY + values + +As per commit 201b5a961 we use g_date_copy() to copy the date, however the +GLib implementation is done assuming that the GDate getters are always used +as the copy function doesn't preserve the original format of the date +(whether is using julian days or dmy), and the synaptics driver access to +the dmy values directly, without using the getter that would recompute the +proper values. +Causing a read error of unset values. + +So, to avoid this, just use the g_date_get_* getters to retrieve the day +month and year for for defining the print enroll id. +--- + libfprint/drivers/synaptics/synaptics.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c +index f6faf11..9ecc682 100644 +--- a/libfprint/drivers/synaptics/synaptics.c ++++ b/libfprint/drivers/synaptics/synaptics.c +@@ -817,9 +817,9 @@ enroll (FpDevice *device) + date = fp_print_get_enroll_date (print); + if (date && g_date_valid (date)) + { +- y = date->year; +- m = date->month; +- d = date->day; ++ y = g_date_get_year (date); ++ m = g_date_get_month (date); ++ d = g_date_get_day (date); + } + else + { +-- +2.24.1 + diff --git a/SOURCES/0026-synaptics-Initialize-user_id-autoptr-to-NULL.patch b/SOURCES/0026-synaptics-Initialize-user_id-autoptr-to-NULL.patch new file mode 100644 index 0000000..98b2e6b --- /dev/null +++ b/SOURCES/0026-synaptics-Initialize-user_id-autoptr-to-NULL.patch @@ -0,0 +1,25 @@ +From e39685ce0ce539763aa555442eb5f168e0ebd07d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 27 Nov 2019 16:59:23 +0100 +Subject: [PATCH 026/181] synaptics: Initialize user_id autoptr to NULL + +--- + libfprint/drivers/synaptics/synaptics.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c +index 9ecc682..a2286b2 100644 +--- a/libfprint/drivers/synaptics/synaptics.c ++++ b/libfprint/drivers/synaptics/synaptics.c +@@ -803,7 +803,7 @@ enroll (FpDevice *device) + GVariant *uid = NULL; + const gchar *username; + guint finger; +- g_autofree gchar *user_id; ++ g_autofree gchar *user_id = NULL; + gssize user_id_len; + g_autofree guint8 *payload = NULL; + const GDate *date; +-- +2.24.1 + diff --git a/SOURCES/0027-examples-Handle-the-cases-where-the-print-date-is-no.patch b/SOURCES/0027-examples-Handle-the-cases-where-the-print-date-is-no.patch new file mode 100644 index 0000000..779141e --- /dev/null +++ b/SOURCES/0027-examples-Handle-the-cases-where-the-print-date-is-no.patch @@ -0,0 +1,66 @@ +From 4c0a89257c713587bf570298a9cefdb6f5f0e302 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 27 Nov 2019 19:14:35 +0100 +Subject: [PATCH 027/181] examples: Handle the cases where the print date is + not set + +--- + examples/manage-prints.c | 17 +++++++++++------ + examples/verify.c | 11 ++++++++--- + 2 files changed, 19 insertions(+), 9 deletions(-) + +diff --git a/examples/manage-prints.c b/examples/manage-prints.c +index b865af7..7bbbc5e 100644 +--- a/examples/manage-prints.c ++++ b/examples/manage-prints.c +@@ -153,14 +153,19 @@ on_list_completed (FpDevice *dev, + for (i = 0; i < prints->len; ++i) + { + FpPrint * print = prints->pdata[i]; ++ const GDate *date = fp_print_get_enroll_date (print); + +- 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, ++ g_print ("[%d] Print of %s finger for username %s", i + 1, + finger_to_string (fp_print_get_finger (print)), +- fp_print_get_username (print), buf, +- fp_print_get_description (print)); ++ fp_print_get_username (print)); ++ ++ if (date) ++ { ++ g_date_strftime (buf, G_N_ELEMENTS (buf), "%Y-%m-%d\0", date); ++ g_print (", enrolled on %s", buf); ++ } ++ ++ g_print (". Description: %s\n", fp_print_get_description (print)); + } + + if (prints->len) +diff --git a/examples/verify.c b/examples/verify.c +index 4e1c988..1249dce 100644 +--- a/examples/verify.c ++++ b/examples/verify.c +@@ -127,9 +127,14 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data) + if (fp_print_get_finger (print) == verify_data->finger && + 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)) ++ const GDate *verify_print_date = NULL; ++ const GDate *print_date = fp_print_get_enroll_date (print); ++ ++ if (verify_print) ++ verify_print_date = fp_print_get_enroll_date (verify_print); ++ ++ if (!verify_print || !print_date || !verify_print_date || ++ g_date_compare (print_date, verify_print_date) >= 0) + verify_print = print; + } + } +-- +2.24.1 + diff --git a/SOURCES/0028-fpi-ssm-Take-ownership-of-the-SSM-when-completing-it.patch b/SOURCES/0028-fpi-ssm-Take-ownership-of-the-SSM-when-completing-it.patch new file mode 100644 index 0000000..6d9bb44 --- /dev/null +++ b/SOURCES/0028-fpi-ssm-Take-ownership-of-the-SSM-when-completing-it.patch @@ -0,0 +1,509 @@ +From 70d7ad5047544c5b66a280c1e6a2da1dcc3eb5f8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 26 Nov 2019 16:18:14 +0100 +Subject: [PATCH 028/181] fpi-ssm: Take ownership of the SSM when completing it + +When a machine is completed, we automatically free it since we can't +consider it valid anymore since this point. + +Update the drivers not to free the SSM on completion callback anymore. +--- + libfprint/drivers/aes1610.c | 2 -- + libfprint/drivers/aes2501.c | 2 -- + libfprint/drivers/aes2550.c | 2 -- + libfprint/drivers/aesx660.c | 3 --- + libfprint/drivers/elan.c | 4 ---- + libfprint/drivers/etes603.c | 6 ------ + libfprint/drivers/synaptics/synaptics.c | 1 - + libfprint/drivers/upeksonly.c | 2 -- + libfprint/drivers/upektc.c | 2 -- + libfprint/drivers/upektc_img.c | 3 --- + libfprint/drivers/upekts.c | 4 ---- + libfprint/drivers/uru4000.c | 1 - + libfprint/drivers/vcom5s.c | 1 - + libfprint/drivers/vfs0050.c | 2 -- + libfprint/drivers/vfs101.c | 2 -- + libfprint/drivers/vfs301.c | 2 -- + libfprint/drivers/vfs5011.c | 2 -- + libfprint/fpi-ssm.c | 15 +++++++++++---- + 18 files changed, 11 insertions(+), 45 deletions(-) + +diff --git a/libfprint/drivers/aes1610.c b/libfprint/drivers/aes1610.c +index c9742e9..0326565 100644 +--- a/libfprint/drivers/aes1610.c ++++ b/libfprint/drivers/aes1610.c +@@ -710,7 +710,6 @@ capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + { + start_finger_detection (dev); + } +- fpi_ssm_free (ssm); + } + + static void +@@ -774,7 +773,6 @@ activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + + if (!error) + start_finger_detection (dev); +- fpi_ssm_free (ssm); + } + + static void +diff --git a/libfprint/drivers/aes2501.c b/libfprint/drivers/aes2501.c +index fad0218..1b59c56 100644 +--- a/libfprint/drivers/aes2501.c ++++ b/libfprint/drivers/aes2501.c +@@ -575,7 +575,6 @@ capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + { + start_finger_detection (dev); + } +- fpi_ssm_free (ssm); + } + + static void +@@ -806,7 +805,6 @@ activate_sm_complete (FpiSsm *ssm, FpDevice *dev, GError *error) + + if (!error) + start_finger_detection (FP_IMAGE_DEVICE (dev)); +- fpi_ssm_free (ssm); + } + + static void +diff --git a/libfprint/drivers/aes2550.c b/libfprint/drivers/aes2550.c +index 2abcf76..b95b053 100644 +--- a/libfprint/drivers/aes2550.c ++++ b/libfprint/drivers/aes2550.c +@@ -391,7 +391,6 @@ capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + { + start_finger_detection (dev); + } +- fpi_ssm_free (ssm); + } + + static void +@@ -537,7 +536,6 @@ activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + + if (!error) + start_finger_detection (dev); +- fpi_ssm_free (ssm); + } + + static void +diff --git a/libfprint/drivers/aesx660.c b/libfprint/drivers/aesx660.c +index 8ad4c63..3f13252 100644 +--- a/libfprint/drivers/aesx660.c ++++ b/libfprint/drivers/aesx660.c +@@ -215,7 +215,6 @@ finger_det_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + + fp_dbg ("Finger detection completed"); + fpi_image_device_report_finger_status (dev, TRUE); +- fpi_ssm_free (ssm); + + if (priv->deactivating) + { +@@ -466,7 +465,6 @@ capture_sm_complete (FpiSsm *ssm, FpDevice *device, GError *error) + FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self); + + fp_dbg ("Capture completed"); +- fpi_ssm_free (ssm); + + if (priv->deactivating) + { +@@ -672,7 +670,6 @@ static void + activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + { + fpi_image_device_activate_complete (FP_IMAGE_DEVICE (_dev), error); +- fpi_ssm_free (ssm); + + if (!error) + start_finger_detection (FP_IMAGE_DEVICE (_dev)); +diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c +index 961366e..5e80be5 100644 +--- a/libfprint/drivers/elan.c ++++ b/libfprint/drivers/elan.c +@@ -479,7 +479,6 @@ stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + + G_DEBUG_HERE (); + +- fpi_ssm_free (ssm); + + /* The device is inactive at this point. */ + self->dev_state = FP_IMAGE_DEVICE_STATE_INACTIVE; +@@ -606,7 +605,6 @@ capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + fpi_image_device_session_error (dev, error); + } + +- fpi_ssm_free (ssm); + } + + static void +@@ -789,7 +787,6 @@ calibrate_complete (FpiSsm *ssm, FpDevice *dev, GError *error) + elan_capture (dev); + } + +- fpi_ssm_free (ssm); + } + + static void +@@ -886,7 +883,6 @@ activate_complete (FpiSsm *ssm, FpDevice *dev, GError *error) + + fpi_image_device_activate_complete (idev, error); + +- fpi_ssm_free (ssm); + } + + static void +diff --git a/libfprint/drivers/etes603.c b/libfprint/drivers/etes603.c +index 5c990da..55f0139 100644 +--- a/libfprint/drivers/etes603.c ++++ b/libfprint/drivers/etes603.c +@@ -789,7 +789,6 @@ m_exit_complete (FpiSsm *ssm, FpDevice *dev, GError *error) + else + fp_dbg ("The device is now in idle state"); + fpi_image_device_deactivate_complete (idev, error); +- fpi_ssm_free (ssm); + } + + static void +@@ -911,7 +910,6 @@ m_capture_complete (FpiSsm *ssm, FpDevice *dev, GError *error) + g_error_free (error); + } + } +- fpi_ssm_free (ssm); + + if (self->is_active == TRUE) + { +@@ -1061,7 +1059,6 @@ m_finger_complete (FpiSsm *ssm, FpDevice *dev, GError *error) + self->is_active = FALSE; + } + +- fpi_ssm_free (ssm); + } + + static void +@@ -1265,7 +1262,6 @@ m_tunevrb_complete (FpiSsm *ssm, FpDevice *dev, GError *error) + if (!self->is_active) + m_exit_start (idev); + +- fpi_ssm_free (ssm); + } + + /* +@@ -1409,7 +1405,6 @@ m_tunedc_complete (FpiSsm *ssm, FpDevice *dev, GError *error) + if (!self->is_active) + m_exit_start (idev); + +- fpi_ssm_free (ssm); + } + + static void +@@ -1543,7 +1538,6 @@ m_init_complete (FpiSsm *ssm, FpDevice *dev, GError *error) + reset_param (FPI_DEVICE_ETES603 (dev)); + fpi_image_device_session_error (idev, error); + } +- fpi_ssm_free (ssm); + } + + static void +diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c +index a2286b2..4932d01 100644 +--- a/libfprint/drivers/synaptics/synaptics.c ++++ b/libfprint/drivers/synaptics/synaptics.c +@@ -290,7 +290,6 @@ cmd_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) + } + self->cmd_complete_on_removal = FALSE; + g_clear_pointer (&self->cmd_complete_error, g_error_free); +- fpi_ssm_free (ssm); + } + + static void +diff --git a/libfprint/drivers/upeksonly.c b/libfprint/drivers/upeksonly.c +index ec81375..e1cd7e5 100644 +--- a/libfprint/drivers/upeksonly.c ++++ b/libfprint/drivers/upeksonly.c +@@ -1380,7 +1380,6 @@ loopsm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); + +- fpi_ssm_free (ssm); + + if (self->deactivating) + { +@@ -1401,7 +1400,6 @@ initsm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); + FpiDeviceUpeksonly *self = FPI_DEVICE_UPEKSONLY (_dev); + +- fpi_ssm_free (ssm); + fpi_image_device_activate_complete (dev, error); + if (error) + return; +diff --git a/libfprint/drivers/upektc.c b/libfprint/drivers/upektc.c +index ff5b49b..e1254ce 100644 +--- a/libfprint/drivers/upektc.c ++++ b/libfprint/drivers/upektc.c +@@ -157,7 +157,6 @@ activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + + if (!error) + start_finger_detection (dev); +- fpi_ssm_free (ssm); + } + + +@@ -345,7 +344,6 @@ capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + else + start_finger_detection (dev); + +- fpi_ssm_free (ssm); + } + + static void +diff --git a/libfprint/drivers/upektc_img.c b/libfprint/drivers/upektc_img.c +index 1e06b90..28a709f 100644 +--- a/libfprint/drivers/upektc_img.c ++++ b/libfprint/drivers/upektc_img.c +@@ -389,7 +389,6 @@ capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error_arg) + + g_autoptr(GError) error = error_arg; + +- fpi_ssm_free (ssm); + + /* Note: We assume that the error is a cancellation in the deactivation case */ + if (self->deactivating) +@@ -470,7 +469,6 @@ deactivate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev); + + fp_dbg ("Deactivate completed"); +- fpi_ssm_free (ssm); + + self->deactivating = FALSE; + fpi_image_device_deactivate_complete (dev, error); +@@ -601,7 +599,6 @@ activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + { + FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); + +- fpi_ssm_free (ssm); + fpi_image_device_activate_complete (dev, error); + + if (!error) +diff --git a/libfprint/drivers/upekts.c b/libfprint/drivers/upekts.c +index b3481aa..4bc6556 100644 +--- a/libfprint/drivers/upekts.c ++++ b/libfprint/drivers/upekts.c +@@ -990,7 +990,6 @@ enroll_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, GError *error) + fp_warn ("Error deinitializing: %s", error->message); + + fpi_device_enroll_complete (dev, data->print, data->error); +- fpi_ssm_free (ssm); + } + + static void +@@ -1217,7 +1216,6 @@ enroll_started (FpiSsm *ssm, FpDevice *dev, GError *error) + else + enroll_iterate (dev); + +- fpi_ssm_free (ssm); + } + + static void +@@ -1256,7 +1254,6 @@ verify_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, GError *error) + fp_warn ("Error deinitializing: %s", error->message); + + fpi_device_verify_complete (dev, data->res, NULL, data->error); +- fpi_ssm_free (ssm); + } + + static void +@@ -1540,7 +1537,6 @@ verify_started (FpiSsm *ssm, FpDevice *dev, GError *error) + upekdev->first_verify_iteration = TRUE; + verify_iterate (dev); + +- fpi_ssm_free (ssm); + } + + static void +diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c +index f248411..89328d0 100644 +--- a/libfprint/drivers/uru4000.c ++++ b/libfprint/drivers/uru4000.c +@@ -789,7 +789,6 @@ imaging_complete (FpiSsm *ssm, FpDevice *dev, GError *error) + { + 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 +diff --git a/libfprint/drivers/vcom5s.c b/libfprint/drivers/vcom5s.c +index 0e10252..edd2dd4 100644 +--- a/libfprint/drivers/vcom5s.c ++++ b/libfprint/drivers/vcom5s.c +@@ -301,7 +301,6 @@ loopsm_complete (FpiSsm *ssm, FpDevice *dev, GError *error) + 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; +diff --git a/libfprint/drivers/vfs0050.c b/libfprint/drivers/vfs0050.c +index 4dc6782..1be272b 100644 +--- a/libfprint/drivers/vfs0050.c ++++ b/libfprint/drivers/vfs0050.c +@@ -669,7 +669,6 @@ dev_activate_callback (FpiSsm *ssm, FpDevice *dev, GError *error) + g_error_free (error); + } + +- fpi_ssm_free (ssm); + } + + /* Activate device */ +@@ -710,7 +709,6 @@ dev_open_callback (FpiSsm *ssm, FpDevice *dev, GError *error) + { + /* Notify open complete */ + fpi_image_device_open_complete (FP_IMAGE_DEVICE (dev), error); +- fpi_ssm_free (ssm); + } + + /* Open device */ +diff --git a/libfprint/drivers/vfs101.c b/libfprint/drivers/vfs101.c +index 37e083c..9ca1b0a 100644 +--- a/libfprint/drivers/vfs101.c ++++ b/libfprint/drivers/vfs101.c +@@ -960,7 +960,6 @@ m_loop_complete (FpiSsm *ssm, FpDevice *dev, GError *error) + + self->active = FALSE; + +- fpi_ssm_free (ssm); + } + + /* Init ssm states */ +@@ -1268,7 +1267,6 @@ m_init_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + } + + /* Free sequential state machine */ +- fpi_ssm_free (ssm); + } + + /* Activate device */ +diff --git a/libfprint/drivers/vfs301.c b/libfprint/drivers/vfs301.c +index 8fdac7c..7219792 100644 +--- a/libfprint/drivers/vfs301.c ++++ b/libfprint/drivers/vfs301.c +@@ -168,7 +168,6 @@ m_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + g_error_free (error); + } + /* Free sequential state machine */ +- fpi_ssm_free (ssm); + } + + /* Exec init sequential state machine */ +@@ -201,7 +200,6 @@ m_init_complete (FpiSsm *ssm, FpDevice *dev, GError *error) + } + + /* Free sequential state machine */ +- fpi_ssm_free (ssm); + } + + /* Activate device */ +diff --git a/libfprint/drivers/vfs5011.c b/libfprint/drivers/vfs5011.c +index 9eddca7..007e486 100644 +--- a/libfprint/drivers/vfs5011.c ++++ b/libfprint/drivers/vfs5011.c +@@ -745,7 +745,6 @@ activate_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + submit_image (ssm, self, dev); + fpi_image_device_report_finger_status (dev, FALSE); + } +- fpi_ssm_free (ssm); + + self->loop_running = FALSE; + +@@ -793,7 +792,6 @@ open_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + self->init_sequence.receive_buf = NULL; + + fpi_image_device_open_complete (dev, error); +- fpi_ssm_free (ssm); + } + + static void +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index 1569be8..a614860 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -51,6 +51,7 @@ + * + * To start a ssm, you pass in a completion callback function to fpi_ssm_start() + * which gets called when the ssm completes (both on error and on failure). ++ * Starting a ssm also takes ownership of it. + * + * To iterate to the next state, call fpi_ssm_next_state(). It is legal to + * attempt to iterate beyond the final state - this is equivalent to marking +@@ -58,6 +59,7 @@ + * + * To mark successful completion of a SSM, either iterate beyond the final + * state or call fpi_ssm_mark_completed() from any state. ++ * This will also invalidate the machine, freeing it. + * + * To mark failed completion of a SSM, call fpi_ssm_mark_failed() from any + * state. You must pass a non-zero error code. +@@ -125,7 +127,6 @@ fpi_ssm_new (FpDevice *dev, + * @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, +@@ -182,12 +183,16 @@ __ssm_call_handler (FpiSsm *machine) + + /** + * fpi_ssm_start: +- * @ssm: an #FpiSsm state machine ++ * @ssm: (transfer full): 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. ++ * ++ * Note that @ssm will be stolen when this function is called. ++ * So that all associated data will be free'ed automatically, after the ++ * @callback is ran. + */ + void + fpi_ssm_start (FpiSsm *ssm, FpiSsmCompletedCallback callback) +@@ -210,7 +215,6 @@ __subsm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + fpi_ssm_mark_failed (parent, error); + else + fpi_ssm_next_state (parent); +- fpi_ssm_free (ssm); + } + + /** +@@ -253,6 +257,7 @@ fpi_ssm_mark_completed (FpiSsm *machine) + + machine->callback (machine, machine->dev, error); + } ++ fpi_ssm_free (machine); + } + + /** +@@ -260,7 +265,7 @@ fpi_ssm_mark_completed (FpiSsm *machine) + * @machine: an #FpiSsm state machine + * @error: a #GError + * +- * Mark a state machine as failed with @error as the error code. ++ * Mark a state machine as failed with @error as the error code, completing it. + */ + void + fpi_ssm_mark_failed (FpiSsm *machine, GError *error) +@@ -305,6 +310,8 @@ fpi_ssm_next_state (FpiSsm *machine) + * @state: the state to jump to + * + * Jump to the @state state, bypassing intermediary states. ++ * If @state is the last state, the machine won't be completed unless ++ * fpi_ssm_mark_completed() isn't explicitly called. + */ + void + fpi_ssm_jump_to_state (FpiSsm *machine, int state) +-- +2.24.1 + diff --git a/SOURCES/0029-fpi-usb-transfer-Take-ownership-of-the-transfer-when.patch b/SOURCES/0029-fpi-usb-transfer-Take-ownership-of-the-transfer-when.patch new file mode 100644 index 0000000..7cd156f --- /dev/null +++ b/SOURCES/0029-fpi-usb-transfer-Take-ownership-of-the-transfer-when.patch @@ -0,0 +1,759 @@ +From b789fda58d5ddf9bc8b6f2830e6fc93d222e6c34 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 26 Nov 2019 21:23:42 +0100 +Subject: [PATCH 029/181] fpi-usb-transfer: Take ownership of the transfer when + submitting it + +When a transfer is completed, we automatically unref it since we can't +consider it valid anymore since this point. + +Update the drivers not to free the transfer after submitting anymore. +--- + libfprint/drivers/aes1610.c | 3 --- + libfprint/drivers/aes2501.c | 4 ---- + libfprint/drivers/aes2550.c | 9 --------- + libfprint/drivers/aes3k.c | 1 - + libfprint/drivers/aeslib.c | 1 - + libfprint/drivers/aesx660.c | 2 -- + libfprint/drivers/elan.c | 2 -- + libfprint/drivers/etes603.c | 1 - + libfprint/drivers/synaptics/synaptics.c | 8 +++----- + libfprint/drivers/upeksonly.c | 5 ----- + libfprint/drivers/upektc.c | 6 ------ + libfprint/drivers/upektc_img.c | 3 --- + libfprint/drivers/upekts.c | 11 ----------- + libfprint/drivers/uru4000.c | 3 --- + libfprint/drivers/vcom5s.c | 3 --- + libfprint/drivers/vfs0050.c | 5 ----- + libfprint/drivers/vfs101.c | 3 --- + libfprint/drivers/vfs301_proto.c | 10 +++------- + libfprint/drivers/vfs5011.c | 3 --- + libfprint/fpi-usb-transfer.c | 14 ++++---------- + 20 files changed, 10 insertions(+), 87 deletions(-) + +diff --git a/libfprint/drivers/aes1610.c b/libfprint/drivers/aes1610.c +index 0326565..4261b05 100644 +--- a/libfprint/drivers/aes1610.c ++++ b/libfprint/drivers/aes1610.c +@@ -155,7 +155,6 @@ generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev, + 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 ******/ +@@ -238,7 +237,6 @@ finger_det_reqs_cb (FpImageDevice *dev, GError *error, + 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 +@@ -683,7 +681,6 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev) + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + capture_read_strip_cb, NULL); +- fpi_usb_transfer_unref (transfer); + break; + } + ; +diff --git a/libfprint/drivers/aes2501.c b/libfprint/drivers/aes2501.c +index 1b59c56..e18b4fe 100644 +--- a/libfprint/drivers/aes2501.c ++++ b/libfprint/drivers/aes2501.c +@@ -126,7 +126,6 @@ read_regs_rq_cb (FpImageDevice *dev, GError *error, void *user_data) + 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 +@@ -210,7 +209,6 @@ generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev, + 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 ******/ +@@ -315,7 +313,6 @@ finger_det_reqs_cb (FpImageDevice *dev, GError *error, + 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 +@@ -547,7 +544,6 @@ capture_run_state (FpiSsm *ssm, FpDevice *device) + 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; + } + } +diff --git a/libfprint/drivers/aes2550.c b/libfprint/drivers/aes2550.c +index b95b053..f3f51d6 100644 +--- a/libfprint/drivers/aes2550.c ++++ b/libfprint/drivers/aes2550.c +@@ -134,7 +134,6 @@ finger_det_reqs_cb (FpiUsbTransfer *t, FpDevice *device, + 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 +@@ -157,7 +156,6 @@ start_finger_detection (FpImageDevice *dev) + sizeof (finger_det_reqs), NULL); + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + finger_det_reqs_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + + /****** CAPTURE ******/ +@@ -335,7 +333,6 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev) + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + capture_reqs_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + break; + +@@ -347,7 +344,6 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev) + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + capture_read_data_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + break; + +@@ -363,7 +359,6 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev) + 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; + } +@@ -482,7 +477,6 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev) + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + init_reqs_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + break; + +@@ -494,7 +488,6 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev) + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + init_read_data_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + break; + +@@ -509,7 +502,6 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev) + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + init_reqs_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + break; + +@@ -521,7 +513,6 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev) + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + calibrate_read_data_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + break; + } +diff --git a/libfprint/drivers/aes3k.c b/libfprint/drivers/aes3k.c +index f73ac02..da3b6a3 100644 +--- a/libfprint/drivers/aes3k.c ++++ b/libfprint/drivers/aes3k.c +@@ -142,7 +142,6 @@ do_capture (FpImageDevice *dev) + 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 +diff --git a/libfprint/drivers/aeslib.c b/libfprint/drivers/aeslib.c +index 8f92d87..4839c62 100644 +--- a/libfprint/drivers/aeslib.c ++++ b/libfprint/drivers/aeslib.c +@@ -88,7 +88,6 @@ do_write_regv (FpImageDevice *dev, struct write_regv_data *wdata, int upper_boun + 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, +diff --git a/libfprint/drivers/aesx660.c b/libfprint/drivers/aesx660.c +index 3f13252..b4d8603 100644 +--- a/libfprint/drivers/aesx660.c ++++ b/libfprint/drivers/aesx660.c +@@ -68,7 +68,6 @@ aesX660_send_cmd_timeout (FpiSsm *ssm, + cmd_len, NULL); + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, timeout, NULL, callback, NULL); +- fpi_usb_transfer_unref (transfer); + } + + static void +@@ -100,7 +99,6 @@ aesX660_read_response (FpiSsm *ssm, + 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 +diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c +index 5e80be5..e2767dd 100644 +--- a/libfprint/drivers/elan.c ++++ b/libfprint/drivers/elan.c +@@ -406,7 +406,6 @@ elan_cmd_read (FpiSsm *ssm, FpDevice *dev) + 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 +@@ -449,7 +448,6 @@ elan_run_cmd (FpiSsm *ssm, + cancellable, + elan_cmd_cb, + NULL); +- fpi_usb_transfer_unref (transfer); + } + + enum stop_capture_states { +diff --git a/libfprint/drivers/etes603.c b/libfprint/drivers/etes603.c +index 55f0139..5cd7f0b 100644 +--- a/libfprint/drivers/etes603.c ++++ b/libfprint/drivers/etes603.c +@@ -710,7 +710,6 @@ async_tx (FpDevice *dev, unsigned int ep, void *cb, + 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); + } + + +diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c +index 4932d01..ccaf60e 100644 +--- a/libfprint/drivers/synaptics/synaptics.c ++++ b/libfprint/drivers/synaptics/synaptics.c +@@ -205,7 +205,7 @@ static void + synaptics_cmd_run_state (FpiSsm *ssm, + FpDevice *dev) + { +- g_autoptr(FpiUsbTransfer) transfer = NULL; ++ FpiUsbTransfer *transfer; + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev); + + switch (fpi_ssm_get_cur_state (ssm)) +@@ -219,7 +219,7 @@ synaptics_cmd_run_state (FpiSsm *ssm, + NULL, + fpi_ssm_usb_transfer_cb, + NULL); +- g_clear_pointer (&self->cmd_pending_transfer, fpi_usb_transfer_unref); ++ self->cmd_pending_transfer = NULL; + } + else + { +@@ -317,7 +317,7 @@ synaptics_sensor_cmd (FpiDeviceSynaptics *self, + gssize payload_len, + SynCmdMsgCallback callback) + { +- g_autoptr(FpiUsbTransfer) transfer = NULL; ++ FpiUsbTransfer *transfer; + guint8 real_seq_num; + gint msg_len; + gint res; +@@ -984,7 +984,6 @@ dev_probe (FpDevice *device) + 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); +@@ -1039,7 +1038,6 @@ dev_probe (FpDevice *device) + 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 || +diff --git a/libfprint/drivers/upeksonly.c b/libfprint/drivers/upeksonly.c +index e1cd7e5..f477b83 100644 +--- a/libfprint/drivers/upeksonly.c ++++ b/libfprint/drivers/upeksonly.c +@@ -635,7 +635,6 @@ write_regs_iterate (struct write_regs_data *wrdata) + 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; + } +@@ -688,7 +687,6 @@ sm_write_reg (FpiSsm *ssm, + 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; + } +@@ -737,7 +735,6 @@ sm_read_reg (FpiSsm *ssm, + NULL, + sm_read_reg_cb, + NULL); +- fpi_usb_transfer_unref (transfer); + } + + static void +@@ -782,7 +779,6 @@ sm_await_intr (FpiSsm *ssm, + fpi_device_get_cancellable (FP_DEVICE (dev)), + sm_await_intr_cb, + NULL); +- fpi_usb_transfer_unref (transfer); + } + + /***** AWAIT FINGER *****/ +@@ -1419,7 +1415,6 @@ dev_activate (FpImageDevice *dev) + 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; + + for (i = 0; i < self->img_transfers->len; i++) +diff --git a/libfprint/drivers/upektc.c b/libfprint/drivers/upektc.c +index e1254ce..92b1930 100644 +--- a/libfprint/drivers/upektc.c ++++ b/libfprint/drivers/upektc.c +@@ -128,7 +128,6 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev) + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + write_init_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + break; + +@@ -142,7 +141,6 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev) + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + read_init_data_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + break; + } +@@ -225,7 +223,6 @@ finger_det_cmd_cb (FpiUsbTransfer *t, FpDevice *device, + IMAGE_SIZE); + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + finger_det_data_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + + static void +@@ -249,7 +246,6 @@ start_finger_detection (FpImageDevice *dev) + UPEKTC_CMD_LEN, NULL); + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + finger_det_cmd_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + + /****** CAPTURE ******/ +@@ -309,7 +305,6 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev) + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + capture_cmd_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + break; + +@@ -323,7 +318,6 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev) + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + capture_read_data_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + break; + } +diff --git a/libfprint/drivers/upektc_img.c b/libfprint/drivers/upektc_img.c +index 28a709f..b9724c1 100644 +--- a/libfprint/drivers/upektc_img.c ++++ b/libfprint/drivers/upektc_img.c +@@ -100,7 +100,6 @@ upektc_img_submit_req (FpiSsm *ssm, + 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 +@@ -120,7 +119,6 @@ upektc_img_read_data (FpiSsm *ssm, + NULL); + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + + /****** CAPTURE ******/ +@@ -557,7 +555,6 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev) + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, + init_reqs_ctrl_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + break; + +diff --git a/libfprint/drivers/upekts.c b/libfprint/drivers/upekts.c +index 4bc6556..05cd9c5 100644 +--- a/libfprint/drivers/upekts.c ++++ b/libfprint/drivers/upekts.c +@@ -226,7 +226,6 @@ busy_ack_retry_read (FpDevice *device, struct read_msg_data *udata) + transfer->short_is_error = TRUE; + + 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 +@@ -416,7 +415,6 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device, + fpi_usb_transfer_submit (etransfer, TIMEOUT, + NULL, + read_msg_extend_cb, udata); +- fpi_usb_transfer_unref (etransfer); + return; + } + +@@ -442,7 +440,6 @@ __read_msg_async (FpDevice *device, struct read_msg_data *udata) + + 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 +@@ -676,7 +673,6 @@ initsm_send_msg28_handler (FpiSsm *ssm, + 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 +@@ -697,7 +693,6 @@ initsm_run_state (FpiSsm *ssm, FpDevice *dev) + 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: +@@ -709,7 +704,6 @@ initsm_run_state (FpiSsm *ssm, FpDevice *dev) + 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: +@@ -820,7 +814,6 @@ deinitsm_state_handler (FpiSsm *ssm, FpDevice *dev) + 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:; +@@ -953,7 +946,6 @@ enroll_start_sm_run_state (FpiSsm *ssm, FpDevice *dev) + 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:; +@@ -1205,7 +1197,6 @@ enroll_iterate (FpDevice *dev) + transfer->short_is_error = TRUE; + + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, enroll_iterate_cmd_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + + static void +@@ -1319,7 +1310,6 @@ verify_start_sm_run_state (FpiSsm *ssm, FpDevice *dev) + 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; + } +@@ -1519,7 +1509,6 @@ verify_iterate (FpDevice *dev) + transfer->short_is_error = TRUE; + + fpi_usb_transfer_submit (transfer, TIMEOUT, NULL, verify_wr2800_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + } + +diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c +index 89328d0..7e28724 100644 +--- a/libfprint/drivers/uru4000.c ++++ b/libfprint/drivers/uru4000.c +@@ -181,7 +181,6 @@ write_regs (FpImageDevice *dev, uint16_t first_reg, + 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 +@@ -207,7 +206,6 @@ read_regs (FpImageDevice *dev, uint16_t first_reg, + 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); + } + + /* +@@ -365,7 +363,6 @@ start_irq_handler (FpImageDevice *dev) + EP_INTR, + IRQ_LENGTH); + fpi_usb_transfer_submit (transfer, 0, self->irq_cancellable, irq_handler, NULL); +- fpi_usb_transfer_unref (transfer); + } + + static void +diff --git a/libfprint/drivers/vcom5s.c b/libfprint/drivers/vcom5s.c +index edd2dd4..1a2b795 100644 +--- a/libfprint/drivers/vcom5s.c ++++ b/libfprint/drivers/vcom5s.c +@@ -103,7 +103,6 @@ sm_write_reg (FpiSsm *ssm, + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, sm_write_reg_cb, + NULL); +- fpi_usb_transfer_unref (transfer); + } + + static void +@@ -133,7 +132,6 @@ sm_exec_cmd (FpiSsm *ssm, + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, sm_exec_cmd_cb, + NULL); +- fpi_usb_transfer_unref (transfer); + } + + /***** FINGER DETECTION *****/ +@@ -227,7 +225,6 @@ capture_iterate (FpiSsm *ssm, + NULL); + + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, capture_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + + +diff --git a/libfprint/drivers/vfs0050.c b/libfprint/drivers/vfs0050.c +index 1be272b..43252c0 100644 +--- a/libfprint/drivers/vfs0050.c ++++ b/libfprint/drivers/vfs0050.c +@@ -56,7 +56,6 @@ async_write (FpiSsm *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 */ +@@ -108,7 +107,6 @@ async_read (FpiSsm *ssm, + + fpi_usb_transfer_submit (transfer, VFS_USB_TIMEOUT, NULL, + async_read_callback, NULL); +- fpi_usb_transfer_unref (transfer); + } + + /* Callback for async_abort */ +@@ -160,7 +158,6 @@ async_abort (FpDevice *dev, FpiSsm *ssm, int ep) + + fpi_usb_transfer_submit (transfer, VFS_USB_ABORT_TIMEOUT, NULL, + async_abort_callback, NULL); +- fpi_usb_transfer_unref (transfer); + } + + /* Image processing functions */ +@@ -564,7 +561,6 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev) + 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); +@@ -614,7 +610,6 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev) + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, VFS_USB_TIMEOUT, NULL, + receive_callback, NULL); +- fpi_usb_transfer_unref (transfer); + break; + } + +diff --git a/libfprint/drivers/vfs101.c b/libfprint/drivers/vfs101.c +index 9ca1b0a..5dedab7 100644 +--- a/libfprint/drivers/vfs101.c ++++ b/libfprint/drivers/vfs101.c +@@ -219,7 +219,6 @@ async_send (FpiSsm *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 */ +@@ -282,7 +281,6 @@ async_recv (FpiSsm *ssm, + 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, +@@ -369,7 +367,6 @@ async_load (FpiSsm *ssm, + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, + async_load_cb, NULL); +- fpi_usb_transfer_unref (transfer); + } + + /* Submit asynchronous sleep */ +diff --git a/libfprint/drivers/vfs301_proto.c b/libfprint/drivers/vfs301_proto.c +index 5d02597..103e890 100644 +--- a/libfprint/drivers/vfs301_proto.c ++++ b/libfprint/drivers/vfs301_proto.c +@@ -67,8 +67,7 @@ static void + usb_recv (FpDeviceVfs301 *dev, guint8 endpoint, int max_bytes, FpiUsbTransfer **out, GError **error) + { + GError *err = NULL; +- +- g_autoptr(FpiUsbTransfer) transfer = NULL; ++ FpiUsbTransfer *transfer; + + /* XXX: This function swallows any transfer errors, that is obviously + * quite bad (it used to assert on no-error)! */ +@@ -98,8 +97,7 @@ static void + usb_send (FpDeviceVfs301 *dev, const guint8 *data, gssize length, GError **error) + { + GError *err = NULL; +- +- g_autoptr(FpiUsbTransfer) transfer = NULL; ++ FpiUsbTransfer *transfer = NULL; + + /* XXX: This function swallows any transfer errors, that is obviously + * quite bad (it used to assert on no-error)! */ +@@ -471,7 +469,7 @@ int + vfs301_proto_peek_event (FpDeviceVfs301 *dev) + { + g_autoptr(GError) error = NULL; +- g_autoptr(FpiUsbTransfer) transfer = NULL; ++ FpiUsbTransfer *transfer; + + const char no_event[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + const char got_event[] = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00}; +@@ -540,7 +538,6 @@ vfs301_proto_process_event_cb (FpiUsbTransfer *transfer, + 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; + } + } +@@ -580,7 +577,6 @@ vfs301_proto_process_event_start (FpDeviceVfs301 *dev) + 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 +diff --git a/libfprint/drivers/vfs5011.c b/libfprint/drivers/vfs5011.c +index 007e486..dbf8276 100644 +--- a/libfprint/drivers/vfs5011.c ++++ b/libfprint/drivers/vfs5011.c +@@ -168,7 +168,6 @@ usbexchange_loop (FpiSsm *ssm, FpDevice *_dev) + 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: +@@ -180,7 +179,6 @@ usbexchange_loop (FpiSsm *ssm, FpDevice *_dev) + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, data->timeout, NULL, + async_recv_cb, NULL); +- fpi_usb_transfer_unref (transfer); + break; + + default: +@@ -466,7 +464,6 @@ capture_chunk_async (FpDeviceVfs5011 *self, + 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); + } + + /* +diff --git a/libfprint/fpi-usb-transfer.c b/libfprint/fpi-usb-transfer.c +index 6b29621..64d706f 100644 +--- a/libfprint/fpi-usb-transfer.c ++++ b/libfprint/fpi-usb-transfer.c +@@ -356,7 +356,7 @@ transfer_finish_cb (GObject *source_object, GAsyncResult *res, gpointer user_dat + + /** + * fpi_usb_transfer_submit: +- * @transfer: The transfer to submit, must have been filled. ++ * @transfer: (transfer full): 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 +@@ -364,10 +364,9 @@ transfer_finish_cb (GObject *source_object, GAsyncResult *res, gpointer user_dat + * + * 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. ++ * Note that #FpiUsbTransfer will be stolen when this function is called. ++ * So that all associated data will be free'ed automatically, after the ++ * callback ran unless fpi_usb_transfer_ref() is explictly called. + */ + void + fpi_usb_transfer_submit (FpiUsbTransfer *transfer, +@@ -385,11 +384,6 @@ fpi_usb_transfer_submit (FpiUsbTransfer *transfer, + 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) +-- +2.24.1 + diff --git a/SOURCES/0030-fpi-ssm-Add-a-usb-transfer-callback-with-data-as-wea.patch b/SOURCES/0030-fpi-ssm-Add-a-usb-transfer-callback-with-data-as-wea.patch new file mode 100644 index 0000000..0ce6873 --- /dev/null +++ b/SOURCES/0030-fpi-ssm-Add-a-usb-transfer-callback-with-data-as-wea.patch @@ -0,0 +1,71 @@ +From 9902e2c4224914dc611eb2326db7322aa57ec2a2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 27 Nov 2019 19:36:24 +0100 +Subject: [PATCH 030/181] fpi-ssm: Add a usb transfer callback with data as + weak pointer + +Allow to pass a double-pointer to be nullified as the transfer data in order +to mark it as NULL when the transfer is done. + +This is useful if we're keeping the transfer around in order to check that +no one is currently running. +--- + libfprint/fpi-ssm.c | 29 +++++++++++++++++++++++++++++ + libfprint/fpi-ssm.h | 6 +++++- + 2 files changed, 34 insertions(+), 1 deletion(-) + +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index a614860..6a02a2c 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -413,3 +413,32 @@ fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer, FpDevice *device, + else + fpi_ssm_next_state (transfer->ssm); + } ++ ++/** ++ * fpi_ssm_usb_transfer_with_weak_pointer_cb: ++ * @transfer: a #FpiUsbTransfer ++ * @device: a #FpDevice ++ * @weak_ptr: A #gpointer pointer to nullify. You can pass a pointer to any ++ * #gpointer to nullify when the callback is completed. I.e a ++ * pointer to the current #FpiUsbTransfer. ++ * @error: The #GError or %NULL ++ * ++ * Can be used in as a #FpiUsbTransfer callback handler to automatically ++ * advance or fail a statemachine on transfer completion. ++ * Passing a #gpointer* as @weak_ptr permits to nullify it once we're done ++ * with the transfer. ++ * ++ * Make sure to set the #FpiSsm on the transfer. ++ */ ++void ++fpi_ssm_usb_transfer_with_weak_pointer_cb (FpiUsbTransfer *transfer, ++ FpDevice *device, gpointer weak_ptr, ++ GError *error) ++{ ++ g_return_if_fail (transfer->ssm); ++ ++ if (weak_ptr) ++ g_nullify_pointer ((gpointer *) weak_ptr); ++ ++ fpi_ssm_usb_transfer_cb (transfer, device, weak_ptr, error); ++} +diff --git a/libfprint/fpi-ssm.h b/libfprint/fpi-ssm.h +index 8d45162..704271d 100644 +--- a/libfprint/fpi-ssm.h ++++ b/libfprint/fpi-ssm.h +@@ -91,5 +91,9 @@ void fpi_ssm_next_state_timeout_cb (FpDevice *dev, + void *data); + void fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer, + FpDevice *device, +- gpointer user_data, ++ gpointer user_date, + GError *error); ++void fpi_ssm_usb_transfer_with_weak_pointer_cb (FpiUsbTransfer *transfer, ++ FpDevice *device, ++ gpointer weak_ptr, ++ GError *error); +-- +2.24.1 + diff --git a/SOURCES/0031-drivers-Use-more-fpi_ssm_usb_transfer_cb-when-possib.patch b/SOURCES/0031-drivers-Use-more-fpi_ssm_usb_transfer_cb-when-possib.patch new file mode 100644 index 0000000..4f891a1 --- /dev/null +++ b/SOURCES/0031-drivers-Use-more-fpi_ssm_usb_transfer_cb-when-possib.patch @@ -0,0 +1,414 @@ +From 99be9c6ef80eb1ca873e4363c404b51acdfb9807 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 27 Nov 2019 20:07:02 +0100 +Subject: [PATCH 031/181] drivers: Use more fpi_ssm_usb_transfer_cb when + possible + +Replace all the transfer callbacks where we just switch to the next state or +fail with fpi_ssm_usb_transfer_cb. +--- + libfprint/drivers/aes1610.c | 14 +---------- + libfprint/drivers/aes2501.c | 15 +----------- + libfprint/drivers/aes2550.c | 43 ++++------------------------------ + libfprint/drivers/aesx660.c | 26 +++++++------------- + libfprint/drivers/upeksonly.c | 14 ++--------- + libfprint/drivers/upektc.c | 12 +--------- + libfprint/drivers/upektc_img.c | 12 +--------- + libfprint/drivers/vcom5s.c | 28 ++++------------------ + 8 files changed, 23 insertions(+), 141 deletions(-) + +diff --git a/libfprint/drivers/aes1610.c b/libfprint/drivers/aes1610.c +index 4261b05..bc39b24 100644 +--- a/libfprint/drivers/aes1610.c ++++ b/libfprint/drivers/aes1610.c +@@ -116,18 +116,6 @@ stub_capture_stop_cb (FpImageDevice *dev, GError *error, + } + } + +- +-/* check that read succeeded but ignore all data */ +-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); +-} +- + static void + generic_write_regv_cb (FpImageDevice *dev, GError *error, + void *user_data) +@@ -154,7 +142,7 @@ generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev, + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, +- generic_ignore_data_cb, NULL); ++ fpi_ssm_usb_transfer_cb, NULL); + } + + /****** FINGER PRESENCE DETECTION ******/ +diff --git a/libfprint/drivers/aes2501.c b/libfprint/drivers/aes2501.c +index e18b4fe..1aa0538 100644 +--- a/libfprint/drivers/aes2501.c ++++ b/libfprint/drivers/aes2501.c +@@ -182,19 +182,6 @@ generic_write_regv_cb (FpImageDevice *dev, GError *error, + 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) +-{ +- 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 +@@ -208,7 +195,7 @@ generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev, + 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_ssm_usb_transfer_cb, NULL); + } + + /****** IMAGE PROCESSING ******/ +diff --git a/libfprint/drivers/aes2550.c b/libfprint/drivers/aes2550.c +index f3f51d6..1ebf933 100644 +--- a/libfprint/drivers/aes2550.c ++++ b/libfprint/drivers/aes2550.c +@@ -216,16 +216,6 @@ process_strip_data (FpiSsm *ssm, FpImageDevice *dev, + return TRUE; + } + +-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); +-} +- + static void + capture_set_idle_reqs_cb (FpiUsbTransfer *transfer, + FpDevice *device, gpointer user_data, +@@ -332,7 +322,7 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev) + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, +- capture_reqs_cb, NULL); ++ fpi_ssm_usb_transfer_cb, NULL); + } + break; + +@@ -430,36 +420,13 @@ enum activate_states { + ACTIVATE_NUM_STATES, + }; + +-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); +-} +- +-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); +-} +- + /* 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) + { +- if (!error) +- fpi_ssm_next_state (transfer->ssm); +- else +- fpi_ssm_mark_failed (transfer->ssm, error); ++ fpi_ssm_usb_transfer_cb (transfer, device, user_data, error); + } + + static void +@@ -476,7 +443,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev) + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, +- init_reqs_cb, NULL); ++ fpi_ssm_usb_transfer_cb, NULL); + } + break; + +@@ -487,7 +454,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *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_ssm_usb_transfer_cb, NULL); + } + break; + +@@ -501,7 +468,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev) + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, +- init_reqs_cb, NULL); ++ fpi_ssm_usb_transfer_cb, NULL); + } + break; + +diff --git a/libfprint/drivers/aesx660.c b/libfprint/drivers/aesx660.c +index b4d8603..0781606 100644 +--- a/libfprint/drivers/aesx660.c ++++ b/libfprint/drivers/aesx660.c +@@ -101,16 +101,6 @@ aesX660_read_response (FpiSsm *ssm, + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, cancel, callback, NULL); + } + +-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); +-} +- + static void + aesX660_read_calibrate_data_cb (FpiUsbTransfer *transfer, + FpDevice *device, +@@ -238,12 +228,12 @@ finger_det_run_state (FpiSsm *ssm, FpDevice *dev) + { + case FINGER_DET_SEND_LED_CMD: + aesX660_send_cmd (ssm, dev, led_blink_cmd, sizeof (led_blink_cmd), +- aesX660_send_cmd_cb); ++ fpi_ssm_usb_transfer_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); ++ fpi_ssm_usb_transfer_cb, 0); + break; + + case FINGER_DET_READ_FD_DATA: +@@ -433,14 +423,14 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev) + { + case CAPTURE_SEND_LED_CMD: + aesX660_send_cmd (ssm, _dev, led_solid_cmd, sizeof (led_solid_cmd), +- aesX660_send_cmd_cb); ++ fpi_ssm_usb_transfer_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); ++ fpi_ssm_usb_transfer_cb); + break; + + case CAPTURE_READ_STRIPE_DATA: +@@ -625,13 +615,13 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev) + 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); ++ fpi_ssm_usb_transfer_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); ++ fpi_ssm_usb_transfer_cb); + break; + + case ACTIVATE_READ_ID: +@@ -645,7 +635,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev) + 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); ++ fpi_ssm_usb_transfer_cb); + break; + + case ACTIVATE_READ_INIT_RESPONSE: +@@ -655,7 +645,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev) + + case ACTIVATE_SEND_CALIBRATE_CMD: + aesX660_send_cmd (ssm, _dev, calibrate_cmd, sizeof (calibrate_cmd), +- aesX660_send_cmd_cb); ++ fpi_ssm_usb_transfer_cb); + break; + + case ACTIVATE_READ_CALIBRATE_DATA: +diff --git a/libfprint/drivers/upeksonly.c b/libfprint/drivers/upeksonly.c +index f477b83..9dd3104 100644 +--- a/libfprint/drivers/upeksonly.c ++++ b/libfprint/drivers/upeksonly.c +@@ -656,17 +656,6 @@ sm_write_regs (FpiSsm *ssm, + 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, +@@ -686,7 +675,8 @@ sm_write_reg (FpiSsm *ssm, + 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_submit (transfer, CTRL_TIMEOUT, NULL, ++ fpi_ssm_usb_transfer_cb, NULL); + + transfer->buffer[0] = value; + } +diff --git a/libfprint/drivers/upektc.c b/libfprint/drivers/upektc.c +index 92b1930..d0c97af 100644 +--- a/libfprint/drivers/upektc.c ++++ b/libfprint/drivers/upektc.c +@@ -256,16 +256,6 @@ enum capture_states { + CAPTURE_NUM_STATES, + }; + +-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); +-} +- + static void + capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) +@@ -304,7 +294,7 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev) + transfer->ssm = ssm; + transfer->short_is_error = TRUE; + fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, +- capture_cmd_cb, NULL); ++ fpi_ssm_usb_transfer_cb, NULL); + } + break; + +diff --git a/libfprint/drivers/upektc_img.c b/libfprint/drivers/upektc_img.c +index b9724c1..d5aaf72 100644 +--- a/libfprint/drivers/upektc_img.c ++++ b/libfprint/drivers/upektc_img.c +@@ -501,16 +501,6 @@ enum activate_states { + ACTIVATE_NUM_STATES, + }; + +-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); +-} +- + static void + init_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) +@@ -554,7 +544,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev) + transfer->buffer[0] = '\0'; + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, +- init_reqs_ctrl_cb, NULL); ++ fpi_ssm_usb_transfer_cb, NULL); + } + break; + +diff --git a/libfprint/drivers/vcom5s.c b/libfprint/drivers/vcom5s.c +index 1a2b795..e1875c3 100644 +--- a/libfprint/drivers/vcom5s.c ++++ b/libfprint/drivers/vcom5s.c +@@ -76,16 +76,6 @@ enum v5s_cmd { + + /***** REGISTER I/O *****/ + +-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, + FpDevice *dev, +@@ -101,18 +91,8 @@ sm_write_reg (FpiSsm *ssm, + 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); +-} +- +-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); ++ fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, ++ fpi_ssm_usb_transfer_cb, NULL); + } + + static void +@@ -130,8 +110,8 @@ sm_exec_cmd (FpiSsm *ssm, + 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_submit (transfer, CTRL_TIMEOUT, NULL, ++ fpi_ssm_usb_transfer_cb, NULL); + } + + /***** FINGER DETECTION *****/ +-- +2.24.1 + diff --git a/SOURCES/0032-fpi-ssm-Make-clearer-that-data-is-unused-in-fpi_ssm_.patch b/SOURCES/0032-fpi-ssm-Make-clearer-that-data-is-unused-in-fpi_ssm_.patch new file mode 100644 index 0000000..6d03d44 --- /dev/null +++ b/SOURCES/0032-fpi-ssm-Make-clearer-that-data-is-unused-in-fpi_ssm_.patch @@ -0,0 +1,49 @@ +From 9615d13f9783503da7060ec95be1ba70aba40f5f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 27 Nov 2019 20:19:54 +0100 +Subject: [PATCH 032/181] fpi-ssm: Make clearer that data is unused in + fpi_ssm_usb_transfer_cb + +--- + libfprint/fpi-ssm.c | 4 ++-- + libfprint/fpi-ssm.h | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index 6a02a2c..5367e32 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -394,7 +394,7 @@ fpi_ssm_next_state_timeout_cb (FpDevice *dev, + * fpi_ssm_usb_transfer_cb: + * @transfer: a #FpiUsbTransfer + * @device: a #FpDevice +- * @ssm_data: User data (unused) ++ * @unused_data: User data (unused) + * @error: The #GError or %NULL + * + * Can be used in as a #FpiUsbTransfer callback handler to automatically +@@ -404,7 +404,7 @@ fpi_ssm_next_state_timeout_cb (FpDevice *dev, + */ + void + fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer, FpDevice *device, +- gpointer ssm_data, GError *error) ++ gpointer unused_data, GError *error) + { + g_return_if_fail (transfer->ssm); + +diff --git a/libfprint/fpi-ssm.h b/libfprint/fpi-ssm.h +index 704271d..57e7d10 100644 +--- a/libfprint/fpi-ssm.h ++++ b/libfprint/fpi-ssm.h +@@ -91,7 +91,7 @@ void fpi_ssm_next_state_timeout_cb (FpDevice *dev, + void *data); + void fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer, + FpDevice *device, +- gpointer user_date, ++ gpointer unused_data, + GError *error); + void fpi_ssm_usb_transfer_with_weak_pointer_cb (FpiUsbTransfer *transfer, + FpDevice *device, +-- +2.24.1 + diff --git a/SOURCES/0033-umockdev-test-Make-possible-to-use-a-wrapper-to-run-.patch b/SOURCES/0033-umockdev-test-Make-possible-to-use-a-wrapper-to-run-.patch new file mode 100644 index 0000000..baa838e --- /dev/null +++ b/SOURCES/0033-umockdev-test-Make-possible-to-use-a-wrapper-to-run-.patch @@ -0,0 +1,68 @@ +From 2803498d804fedc6de37ceb52f5f28072ace247a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 26 Nov 2019 18:39:09 +0100 +Subject: [PATCH 033/181] umockdev-test: Make possible to use a wrapper to run + tests + +Support LIBFPRINT_TEST_WRAPPER env variable to run tests with a wrapper. +--- + tests/umockdev-test.py | 31 ++++++++++++++----------------- + 1 file changed, 14 insertions(+), 17 deletions(-) + +diff --git a/tests/umockdev-test.py b/tests/umockdev-test.py +index f1387d6..d91fcb9 100755 +--- a/tests/umockdev-test.py ++++ b/tests/umockdev-test.py +@@ -50,18 +50,23 @@ def cmp_pngs(png_a, png_b): + 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") ++def get_umockdev_runner(ioctl_basename): ++ ioctl = os.path.join(ddir, "{}.ioctl".format(ioctl_basename)) + 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")]) ++ umockdev = ['umockdev-run', '-d', device, ++ '-i', "%s=%s" % (dev, ioctl), ++ '--'] ++ wrapper = os.getenv('LIBFPRINT_TEST_WRAPPER') ++ return umockdev + (wrapper.split(' ') if wrapper else []) + [sys.executable] ++ ++def capture(): ++ subprocess.check_call(get_umockdev_runner("capture") + ++ ['%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")): +@@ -69,16 +74,8 @@ def capture(): + 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")]) ++ subprocess.check_call(get_umockdev_runner("custom") + ++ ['%s' % os.path.join(ddir, "custom.py")]) + + try: + if os.path.exists(os.path.join(ddir, "capture.ioctl")): +-- +2.24.1 + diff --git a/SOURCES/0034-virtual-image-Re-run-the-test-using-the-defined-wrap.patch b/SOURCES/0034-virtual-image-Re-run-the-test-using-the-defined-wrap.patch new file mode 100644 index 0000000..012c0c7 --- /dev/null +++ b/SOURCES/0034-virtual-image-Re-run-the-test-using-the-defined-wrap.patch @@ -0,0 +1,48 @@ +From 68c3cf97c87d331843ff7899652c31943b58c6d3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 26 Nov 2019 19:37:55 +0100 +Subject: [PATCH 034/181] virtual-image: Re-run the test using the defined + wrapper if any + +In case a LIBFPRINT_TEST_WRAPPER is defined, execute again the script using +the same python processor but using the passed wrapper command. +--- + tests/virtual-image.py | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/tests/virtual-image.py b/tests/virtual-image.py +index a9fe8f5..363219a 100755 +--- a/tests/virtual-image.py ++++ b/tests/virtual-image.py +@@ -10,11 +10,20 @@ import sys + import unittest + import socket + import struct ++import subprocess + import shutil + import glob + import cairo + import tempfile + ++# Re-run the test with the passed wrapper if set ++wrapper = os.getenv('LIBFPRINT_TEST_WRAPPER') ++if wrapper: ++ wrap_cmd = wrapper.split(' ') + [sys.executable, os.path.abspath(__file__)] + \ ++ sys.argv[1:] ++ os.unsetenv('LIBFPRINT_TEST_WRAPPER') ++ sys.exit(subprocess.check_call(wrap_cmd)) ++ + class Connection: + + def __init__(self, addr): +@@ -274,7 +283,6 @@ class VirtualImage(unittest.TestCase): + ctx.iteration(True) + assert(not self._verify_match) + +- + # avoid writing to stderr + unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2)) + +-- +2.24.1 + diff --git a/SOURCES/0035-tests-Add-gdb-setup-to-run-tests-using-gdb.patch b/SOURCES/0035-tests-Add-gdb-setup-to-run-tests-using-gdb.patch new file mode 100644 index 0000000..2a8edee --- /dev/null +++ b/SOURCES/0035-tests-Add-gdb-setup-to-run-tests-using-gdb.patch @@ -0,0 +1,32 @@ +From 923fc9e108a352a1fa4cad98a361cf4cdc233d25 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 26 Nov 2019 18:45:31 +0100 +Subject: [PATCH 035/181] tests: Add 'gdb' setup to run tests using gdb + +When using --setup=gdb the tests will be running using gdb, however this +as per meson limitation allows only running a test when using verbose mode. +--- + tests/meson.build | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/tests/meson.build b/tests/meson.build +index 7987692..1645028 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -44,3 +44,13 @@ if get_option('introspection') + ) + endif + endif ++ ++gdb = find_program('gdb', required: false) ++if gdb.found() ++ add_test_setup('gdb', ++ timeout_multiplier: 1000, ++ env: [ ++ 'LIBFPRINT_TEST_WRAPPER=@0@ --args'.format( ++ gdb.path()) ++ ]) ++endif +-- +2.24.1 + diff --git a/SOURCES/0036-tests-Add-setup-mode-to-run-tests-using-valgrind.patch b/SOURCES/0036-tests-Add-setup-mode-to-run-tests-using-valgrind.patch new file mode 100644 index 0000000..771b726 --- /dev/null +++ b/SOURCES/0036-tests-Add-setup-mode-to-run-tests-using-valgrind.patch @@ -0,0 +1,101 @@ +From 47cb10a9c1e15b2782f1efd4b7d27bd0481324b6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 26 Nov 2019 18:50:18 +0100 +Subject: [PATCH 036/181] tests: Add setup mode to run tests using valgrind + +In such case we need to ignore the python errors, so including a suppression +file when using --setup=valgrind. +--- + tests/meson.build | 16 +++++++++++ + tests/valgrind-python.supp | 55 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 71 insertions(+) + create mode 100644 tests/valgrind-python.supp + +diff --git a/tests/meson.build b/tests/meson.build +index 1645028..0fe8096 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -54,3 +54,19 @@ if gdb.found() + gdb.path()) + ]) + endif ++ ++valgrind = find_program('valgrind', required: false) ++if valgrind.found() ++ glib_share = glib_dep.get_pkgconfig_variable('prefix') / 'share' / glib_dep.name() ++ glib_suppressions = glib_share + '/valgrind/glib.supp' ++ python_suppressions = '@0@/@1@'.format(meson.source_root(), ++ files('valgrind-python.supp')[0]) ++ add_test_setup('valgrind', ++ timeout_multiplier: 10, ++ env: [ ++ 'G_SLICE=always-malloc', ++ ('LIBFPRINT_TEST_WRAPPER=@0@ --tool=memcheck --leak-check=full ' + ++ '--suppressions=@1@ --suppressions=@2@').format( ++ valgrind.path(), glib_suppressions, python_suppressions) ++ ]) ++endif +diff --git a/tests/valgrind-python.supp b/tests/valgrind-python.supp +new file mode 100644 +index 0000000..395e801 +--- /dev/null ++++ b/tests/valgrind-python.supp +@@ -0,0 +1,55 @@ ++{ ++ ignore_py_cond ++ Memcheck:Cond ++ ... ++ fun:Py* ++} ++ ++{ ++ ignore__py_cond ++ Memcheck:Cond ++ ... ++ fun:_Py* ++} ++ ++{ ++ ignore_py_value8 ++ Memcheck:Value8 ++ ... ++ fun:Py* ++} ++ ++{ ++ ignore__py_value8 ++ Memcheck:Value8 ++ ... ++ fun:_Py* ++} ++ ++{ ++ ignore_py_addr4 ++ Memcheck:Addr4 ++ ... ++ fun:Py* ++} ++ ++{ ++ ignore__py_addr4 ++ Memcheck:Addr4 ++ ... ++ fun:_Py* ++} ++ ++{ ++ ignore_py_leaks ++ Memcheck:Leak ++ ... ++ fun:Py* ++} ++ ++{ ++ ignore__py_leaks ++ Memcheck:Leak ++ ... ++ fun:_Py* ++} +-- +2.24.1 + diff --git a/SOURCES/0037-fp-device-Unref-the-usb-device-on-finalize.patch b/SOURCES/0037-fp-device-Unref-the-usb-device-on-finalize.patch new file mode 100644 index 0000000..14d1124 --- /dev/null +++ b/SOURCES/0037-fp-device-Unref-the-usb-device-on-finalize.patch @@ -0,0 +1,28 @@ +From 36f45003414530868e93c220ea474a3e7e602ca7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 26 Nov 2019 19:07:26 +0100 +Subject: [PATCH 037/181] fp-device: Unref the usb device on finalize + +Each device adds a ref to the underlying usb device, but it doesn't remove +the reference on finalization. + +So clear the object to fix the leak +--- + libfprint/fp-device.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c +index 13f1b5a..b2190bd 100644 +--- a/libfprint/fp-device.c ++++ b/libfprint/fp-device.c +@@ -382,6 +382,7 @@ fp_device_finalize (GObject *object) + + g_clear_pointer (&priv->device_id, g_free); + g_clear_pointer (&priv->device_name, g_free); ++ g_clear_object (&priv->usb_device); + + G_OBJECT_CLASS (fp_device_parent_class)->finalize (object); + } +-- +2.24.1 + diff --git a/SOURCES/0038-fp-context-Run-dispose-on-the-usb-context-to-deal-wi.patch b/SOURCES/0038-fp-context-Run-dispose-on-the-usb-context-to-deal-wi.patch new file mode 100644 index 0000000..33248e5 --- /dev/null +++ b/SOURCES/0038-fp-context-Run-dispose-on-the-usb-context-to-deal-wi.patch @@ -0,0 +1,28 @@ +From e2419698d6c87a5d5a822acf4d5891a464f68317 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 26 Nov 2019 19:16:07 +0100 +Subject: [PATCH 038/181] fp-context: Run dispose on the usb context to deal + with circular refs + +Ensure that we dispose the USB context before unreffing it, so that it will +release any reference it has and destroy the internal libusb context. +--- + libfprint/fp-context.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/libfprint/fp-context.c b/libfprint/fp-context.c +index 74dda51..eed7847 100644 +--- a/libfprint/fp-context.c ++++ b/libfprint/fp-context.c +@@ -186,6 +186,8 @@ fp_context_finalize (GObject *object) + g_cancellable_cancel (priv->cancellable); + g_clear_object (&priv->cancellable); + g_clear_pointer (&priv->drivers, g_array_unref); ++ ++ g_object_run_dispose (G_OBJECT (priv->usb_ctx)); + g_clear_object (&priv->usb_ctx); + + G_OBJECT_CLASS (fp_context_parent_class)->finalize (object); +-- +2.24.1 + diff --git a/SOURCES/0039-fp-print-Unref-the-prints-on-finalize.patch b/SOURCES/0039-fp-print-Unref-the-prints-on-finalize.patch new file mode 100644 index 0000000..063d63e --- /dev/null +++ b/SOURCES/0039-fp-print-Unref-the-prints-on-finalize.patch @@ -0,0 +1,24 @@ +From 39f9257773aef96b5be544795c07ff9b355de08f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 26 Nov 2019 20:33:56 +0100 +Subject: [PATCH 039/181] fp-print: Unref the prints on finalize + +--- + libfprint/fp-print.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c +index 39c5c0a..776fc71 100644 +--- a/libfprint/fp-print.c ++++ b/libfprint/fp-print.c +@@ -101,6 +101,7 @@ fp_print_finalize (GObject *object) + 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_clear_pointer (&self->prints, g_ptr_array_unref); + + G_OBJECT_CLASS (fp_print_parent_class)->finalize (object); + } +-- +2.24.1 + diff --git a/SOURCES/0040-fp-print-Assert-the-prints-aren-t-set-when-initializ.patch b/SOURCES/0040-fp-print-Assert-the-prints-aren-t-set-when-initializ.patch new file mode 100644 index 0000000..f469ec0 --- /dev/null +++ b/SOURCES/0040-fp-print-Assert-the-prints-aren-t-set-when-initializ.patch @@ -0,0 +1,29 @@ +From 13dba87820f10d606e70541514195c3cd029c7c1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 27 Nov 2019 19:25:34 +0100 +Subject: [PATCH 040/181] fp-print: Assert the prints aren't set when + initialized + +--- + libfprint/fp-print.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c +index 776fc71..ff7927a 100644 +--- a/libfprint/fp-print.c ++++ b/libfprint/fp-print.c +@@ -580,7 +580,10 @@ fpi_print_set_type (FpPrint *print, + + print->type = type; + if (print->type == FP_PRINT_NBIS) +- print->prints = g_ptr_array_new_with_free_func (g_free); ++ { ++ g_assert_null (print->prints); ++ print->prints = g_ptr_array_new_with_free_func (g_free); ++ } + g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_FPI_TYPE]); + } + +-- +2.24.1 + diff --git a/SOURCES/0041-fp-print-Unref-print-data-and-get-static-strings-whe.patch b/SOURCES/0041-fp-print-Unref-print-data-and-get-static-strings-whe.patch new file mode 100644 index 0000000..4bf695c --- /dev/null +++ b/SOURCES/0041-fp-print-Unref-print-data-and-get-static-strings-whe.patch @@ -0,0 +1,42 @@ +From ba337ffcf3312d23884fd153c3f244350ced1b34 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 26 Nov 2019 20:35:39 +0100 +Subject: [PATCH 041/181] fp-print: Unref print data and get static strings + when deserializing + +--- + libfprint/fp-print.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c +index ff7927a..7777db2 100644 +--- a/libfprint/fp-print.c ++++ b/libfprint/fp-print.c +@@ -978,6 +978,7 @@ fp_print_deserialize (const guchar *data, + g_autoptr(FpPrint) result = NULL; + g_autoptr(GVariant) raw_value = NULL; + g_autoptr(GVariant) value = NULL; ++ g_autoptr(GVariant) print_data = NULL; + guchar *aligned_data = NULL; + GDate *date = NULL; + guint8 finger_int8; +@@ -989,7 +990,6 @@ fp_print_deserialize (const guchar *data, + const gchar *driver; + const gchar *device_id; + gboolean device_stored; +- GVariant *print_data; + + g_assert (data); + g_assert (length > 3); +@@ -1020,7 +1020,7 @@ fp_print_deserialize (const guchar *data, + value = g_variant_get_normal_form (raw_value); + + g_variant_get (value, +- "(issbymsmsi@a{sv}v)", ++ "(i&s&sbymsmsi@a{sv}v)", + &type, + &driver, + &device_id, +-- +2.24.1 + diff --git a/SOURCES/0042-virtual-image-Also-unref-the-object-when-closing-a-t.patch b/SOURCES/0042-virtual-image-Also-unref-the-object-when-closing-a-t.patch new file mode 100644 index 0000000..45690a6 --- /dev/null +++ b/SOURCES/0042-virtual-image-Also-unref-the-object-when-closing-a-t.patch @@ -0,0 +1,63 @@ +From 74b297a9a50e19c97a71bc6e317bc8e4bdf2a0a7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 26 Nov 2019 20:36:44 +0100 +Subject: [PATCH 042/181] virtual-image: Also unref the object when closing a + the stream + +While a stream is closed when completely unreffed, the other way around +isn't true, so always unref the object. +--- + libfprint/drivers/virtual-image.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/libfprint/drivers/virtual-image.c b/libfprint/drivers/virtual-image.c +index 6fdd3db..612863d 100644 +--- a/libfprint/drivers/virtual-image.c ++++ b/libfprint/drivers/virtual-image.c +@@ -81,7 +81,7 @@ recv_image_img_recv_cb (GObject *source_object, + + self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); + g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); +- self->connection = NULL; ++ g_clear_object (&self->connection); + return; + } + +@@ -118,7 +118,7 @@ recv_image_hdr_recv_cb (GObject *source_object, + + self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); + g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); +- self->connection = NULL; ++ g_clear_object (&self->connection); + return; + } + +@@ -127,7 +127,7 @@ recv_image_hdr_recv_cb (GObject *source_object, + { + 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; ++ g_clear_object (&self->connection); + } + + if (self->recv_img_hdr[0] < 0 || self->recv_img_hdr[1] < 0) +@@ -148,7 +148,7 @@ recv_image_hdr_recv_cb (GObject *source_object, + default: + /* disconnect client, it didn't play fair */ + g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL); +- self->connection = NULL; ++ g_clear_object (&self->connection); + } + + /* And, listen for more images from the same client. */ +@@ -206,6 +206,7 @@ new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data + if (dev->connection) + { + g_io_stream_close (G_IO_STREAM (connection), NULL, NULL); ++ g_object_unref (connection); + return; + } + +-- +2.24.1 + diff --git a/SOURCES/0043-fp-device-Use-an-autopointer-and-steal-the-print-whe.patch b/SOURCES/0043-fp-device-Use-an-autopointer-and-steal-the-print-whe.patch new file mode 100644 index 0000000..8430cbd --- /dev/null +++ b/SOURCES/0043-fp-device-Use-an-autopointer-and-steal-the-print-whe.patch @@ -0,0 +1,57 @@ +From b7a62c3e2558abb69a8cad0983e30daf511f00d0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 26 Nov 2019 20:38:16 +0100 +Subject: [PATCH 043/181] fp-device: Use an autopointer and steal the print + when passed + +Make it clearer that we're stealing the print when passing it away, instead +of just doing this silently. +--- + libfprint/fp-image-device.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/libfprint/fp-image-device.c b/libfprint/fp-image-device.c +index 692727b..e45b6a9 100644 +--- a/libfprint/fp-image-device.c ++++ b/libfprint/fp-image-device.c +@@ -389,8 +389,8 @@ static void + fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, gpointer user_data) + { + g_autoptr(FpImage) image = FP_IMAGE (source_object); ++ g_autoptr(FpPrint) print = NULL; + GError *error = NULL; +- FpPrint *print = NULL; + FpDevice *device = FP_DEVICE (user_data); + FpImageDevicePrivate *priv; + FpDeviceAction action; +@@ -443,7 +443,8 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g + priv->enroll_stage += 1; + } + +- fpi_device_enroll_progress (device, priv->enroll_stage, print, error); ++ fpi_device_enroll_progress (device, priv->enroll_stage, ++ g_steal_pointer (&print), error); + + if (priv->enroll_stage == IMG_ENROLL_STAGES) + { +@@ -462,7 +463,7 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g + else + result = FPI_MATCH_ERROR; + +- fpi_device_verify_complete (device, result, print, error); ++ fpi_device_verify_complete (device, result, g_steal_pointer (&print), error); + fp_image_device_deactivate (device); + } + else if (action == FP_DEVICE_ACTION_IDENTIFY) +@@ -483,7 +484,7 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g + } + } + +- fpi_device_identify_complete (device, result, print, error); ++ fpi_device_identify_complete (device, result, g_steal_pointer (&print), error); + fp_image_device_deactivate (device); + } + else +-- +2.24.1 + diff --git a/SOURCES/0044-fp-device-Unref-the-print-once-we-ve-notified-the-pr.patch b/SOURCES/0044-fp-device-Unref-the-print-once-we-ve-notified-the-pr.patch new file mode 100644 index 0000000..0556497 --- /dev/null +++ b/SOURCES/0044-fp-device-Unref-the-print-once-we-ve-notified-the-pr.patch @@ -0,0 +1,48 @@ +From 364dd9f3de7f027723bceaa68584cceb66b6d15d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 26 Nov 2019 20:43:33 +0100 +Subject: [PATCH 044/181] fp-device: Unref the print once we've notified the + progress + +When we notify the enroll progress with a print, this needs to be unreffed +once we're done, but this only was happening in case of error. + +Since it's not up to the callback function to free it, let's do it at the +end of the function. + +As per this, clarify the docs for FpEnrollProgress marking it as transfer +none. +--- + libfprint/fp-device.c | 2 ++ + libfprint/fp-device.h | 2 +- + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c +index b2190bd..c9d1b89 100644 +--- a/libfprint/fp-device.c ++++ b/libfprint/fp-device.c +@@ -2344,6 +2344,8 @@ fpi_device_enroll_progress (FpDevice *device, + } + if (error) + g_error_free (error); ++ ++ g_clear_object (&print); + } + + +diff --git a/libfprint/fp-device.h b/libfprint/fp-device.h +index 821514d..4785064 100644 +--- a/libfprint/fp-device.h ++++ b/libfprint/fp-device.h +@@ -113,7 +113,7 @@ GQuark fp_device_error_quark (void); + * FpEnrollProgress: + * @device: a #FpDevice + * @completed_stages: Number of completed stages +- * @print: (nullable): The last scaned print ++ * @print: (nullable) (transfer none): The last scaned print + * @user_data: (nullable): User provided data + * @error: (nullable) (transfer none): #GError or %NULL + * +-- +2.24.1 + diff --git a/SOURCES/0045-fp-device-Mark-user-data-in-FpEnrollProgress-as-tran.patch b/SOURCES/0045-fp-device-Mark-user-data-in-FpEnrollProgress-as-tran.patch new file mode 100644 index 0000000..55ac6fa --- /dev/null +++ b/SOURCES/0045-fp-device-Mark-user-data-in-FpEnrollProgress-as-tran.patch @@ -0,0 +1,28 @@ +From 2036734844f806e2781ce4bd1a5d355cc6d2b0ba Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 27 Nov 2019 21:39:53 +0100 +Subject: [PATCH 045/181] fp-device: Mark user data in FpEnrollProgress as + transfer none + +The data has its own DestroyNotify set, so while no generic DestroyNotify +exists for generic data, let's make it clear. +--- + libfprint/fp-device.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libfprint/fp-device.h b/libfprint/fp-device.h +index 4785064..a15fc30 100644 +--- a/libfprint/fp-device.h ++++ b/libfprint/fp-device.h +@@ -114,7 +114,7 @@ GQuark fp_device_error_quark (void); + * @device: a #FpDevice + * @completed_stages: Number of completed stages + * @print: (nullable) (transfer none): The last scaned print +- * @user_data: (nullable): User provided data ++ * @user_data: (nullable) (transfer none): User provided data + * @error: (nullable) (transfer none): #GError or %NULL + * + * The passed error is guaranteed to be of type %FP_DEVICE_RETRY if set. +-- +2.24.1 + diff --git a/SOURCES/0046-fp-device-Use-g_clear_error-instead-of-check-free.patch b/SOURCES/0046-fp-device-Use-g_clear_error-instead-of-check-free.patch new file mode 100644 index 0000000..6c50860 --- /dev/null +++ b/SOURCES/0046-fp-device-Use-g_clear_error-instead-of-check-free.patch @@ -0,0 +1,27 @@ +From 25bfa5a0681d6b7eb88a98b229fc309465257358 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 26 Nov 2019 20:44:15 +0100 +Subject: [PATCH 046/181] fp-device: Use g_clear_error instead of check + free + +--- + libfprint/fp-device.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c +index c9d1b89..0a1f8de 100644 +--- a/libfprint/fp-device.c ++++ b/libfprint/fp-device.c +@@ -2342,9 +2342,8 @@ fpi_device_enroll_progress (FpDevice *device, + data->enroll_progress_data, + error); + } +- if (error) +- g_error_free (error); + ++ g_clear_error (&error); + g_clear_object (&print); + } + +-- +2.24.1 + diff --git a/SOURCES/0047-tests-Use-a-loop-for-generating-drivers-tests-and-us.patch b/SOURCES/0047-tests-Use-a-loop-for-generating-drivers-tests-and-us.patch new file mode 100644 index 0000000..1d67996 --- /dev/null +++ b/SOURCES/0047-tests-Use-a-loop-for-generating-drivers-tests-and-us.patch @@ -0,0 +1,53 @@ +From e164796705693d0fae8d21ffbc24fbb4ba1a3fed Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 26 Nov 2019 20:59:09 +0100 +Subject: [PATCH 047/181] tests: Use a loop for generating drivers tests and + use suites + +So we can just run drivers tests with --suite=drivers +--- + tests/meson.build | 22 +++++++++------------- + 1 file changed, 9 insertions(+), 13 deletions(-) + +diff --git a/tests/meson.build b/tests/meson.build +index 0fe8096..d6196be 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -24,25 +24,21 @@ if get_option('introspection') + ) + 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 ++ drivers_tests = [ ++ 'vfs5011', ++ 'synaptics', ++ ] + +- if 'synaptics' in drivers +- test('synaptics', ++ foreach driver_test: drivers_tests ++ test(driver_test, + find_program('umockdev-test.py'), +- args: join_paths(meson.current_source_dir(), 'synaptics'), ++ args: join_paths(meson.current_source_dir(), driver_test), + env: envs, ++ suite: ['drivers'], + timeout: 10, + depends: libfprint_typelib, + ) +- endif ++ endforeach + endif + + gdb = find_program('gdb', required: false) +-- +2.24.1 + diff --git a/SOURCES/0048-fp-print-Set-the-aligned_data-as-the-data-used-by-th.patch b/SOURCES/0048-fp-print-Set-the-aligned_data-as-the-data-used-by-th.patch new file mode 100644 index 0000000..8276057 --- /dev/null +++ b/SOURCES/0048-fp-print-Set-the-aligned_data-as-the-data-used-by-th.patch @@ -0,0 +1,31 @@ +From 2a335a89a622dcc0428fcd32dbed7841dec5b25f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 28 Nov 2019 21:30:17 +0100 +Subject: [PATCH 048/181] fp-print: Set the aligned_data as the data used by + the cleanup function + +g_variant_new_from_data() allows to destroy some other user_data passed as +parameter that might be different from the aligned_data itself. + +But since in this case they match, pass it to be set as g_free parameter +or it won't be free'd. +--- + libfprint/fp-print.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c +index 7777db2..ddf8747 100644 +--- a/libfprint/fp-print.c ++++ b/libfprint/fp-print.c +@@ -1009,7 +1009,7 @@ fp_print_deserialize (const guchar *data, + 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); ++ FALSE, g_free, aligned_data); + + if (!raw_value) + goto invalid_format; +-- +2.24.1 + diff --git a/SOURCES/0049-tests-Fix-endianness-issue-in-test-suite.patch b/SOURCES/0049-tests-Fix-endianness-issue-in-test-suite.patch new file mode 100644 index 0000000..a1b773a --- /dev/null +++ b/SOURCES/0049-tests-Fix-endianness-issue-in-test-suite.patch @@ -0,0 +1,33 @@ +From a916f33535177a3032822d7b47ab199d6249b989 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Thu, 28 Nov 2019 11:37:33 +0100 +Subject: [PATCH 049/181] tests: Fix endianness issue in test suite + +The test suite needs to compare greyscale images and was picking an +undefined byte in the pixel data on big-endian. Select a byte that works +on any endian instead. + +See: #200 +--- + tests/umockdev-test.py | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/tests/umockdev-test.py b/tests/umockdev-test.py +index d91fcb9..1b556e1 100755 +--- a/tests/umockdev-test.py ++++ b/tests/umockdev-test.py +@@ -48,7 +48,10 @@ def cmp_pngs(png_a, png_b): + + 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]) ++ # RGB24 format is endian dependent, using +1 means we test either ++ # the G or B component, which works on any endian for the greyscale ++ # test. ++ assert(data_a[y * stride + x * 4 + 1] == data_b[y * stride + x * 4 + 1]) + + def get_umockdev_runner(ioctl_basename): + ioctl = os.path.join(ddir, "{}.ioctl".format(ioctl_basename)) +-- +2.24.1 + diff --git a/SOURCES/0050-assembling-Use-fixed-point-for-image-assembly.patch b/SOURCES/0050-assembling-Use-fixed-point-for-image-assembly.patch new file mode 100644 index 0000000..216289f --- /dev/null +++ b/SOURCES/0050-assembling-Use-fixed-point-for-image-assembly.patch @@ -0,0 +1,2557 @@ +From 50378b823676072ebe39afc0095c90df3b0c44af Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Thu, 28 Nov 2019 15:50:20 +0100 +Subject: [PATCH 050/181] assembling: Use fixed point for image assembly + +Using floating point causes architecture dependent results due to +accuracy/rounding differences. It is not hard to switch to fixed point, +and while this does cause quite different rounding errors, the +difference is small. + +Fixes: #200 +--- + libfprint/fpi-assembling.c | 32 +++++++++++++++++++++----------- + tests/vfs5011/capture.png | Bin 65243 -> 65213 bytes + 2 files changed, 21 insertions(+), 11 deletions(-) + +diff --git a/libfprint/fpi-assembling.c b/libfprint/fpi-assembling.c +index 75291c0..fef08f0 100644 +--- a/libfprint/fpi-assembling.c ++++ b/libfprint/fpi-assembling.c +@@ -385,8 +385,10 @@ median_filter (int *data, int size, int filtersize) + + 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) ++ GSList *line1, gint32 y1_f, ++ GSList *line2, gint32 y2_f, ++ unsigned char *output, gint32 yi_f, ++ int size) + { + int i; + unsigned char p1, p2; +@@ -396,10 +398,12 @@ interpolate_lines (struct fpi_line_asmbl_ctx *ctx, + + for (i = 0; i < size; i++) + { ++ gint unscaled; + p1 = ctx->get_pixel (ctx, line1, i); + p2 = ctx->get_pixel (ctx, line2, i); +- output[i] = (float) p1 +- + (yi - y1) / (y2 - y1) * (p2 - p1); ++ ++ unscaled = (yi_f - y1_f) * p2 + (y2_f - yi_f) * p1; ++ output[i] = (unscaled) / (y2_f - y1_f); + } + } + +@@ -424,7 +428,13 @@ fpi_assemble_lines (struct fpi_line_asmbl_ctx *ctx, + /* Number of output lines per distance between two scanners */ + int i; + GSList *row1, *row2; +- float y = 0.0; ++ /* The y coordinate is tracked as a 16.16 fixed point number. All ++ * variables postfixed with _f follow this format here and in ++ * interpolate_lines. ++ * We could also use floating point here, but using fixed point means ++ * we get consistent results across architectures. ++ */ ++ gint32 y_f = 0; + int line_ind = 0; + int *offsets = g_new0 (int, num_lines / 2); + unsigned char *output = g_malloc0 (ctx->line_width * ctx->max_height); +@@ -476,21 +486,21 @@ fpi_assemble_lines (struct fpi_line_asmbl_ctx *ctx, + int offset = offsets[i / 2]; + if (offset > 0) + { +- float ynext = y + (float) ctx->resolution / offset; +- while (line_ind < ynext) ++ gint32 ynext_f = y_f + (ctx->resolution << 16) / offset; ++ while ((line_ind << 16) < ynext_f) + { + if (line_ind > ctx->max_height - 1) + goto out; + interpolate_lines (ctx, +- row1, y, ++ row1, y_f, + g_slist_next (row1), +- ynext, ++ ynext_f, + output + line_ind * ctx->line_width, +- line_ind, ++ line_ind << 16, + ctx->line_width); + line_ind++; + } +- y = ynext; ++ y_f = ynext_f; + } + } + out: +diff --git a/tests/vfs5011/capture.png b/tests/vfs5011/capture.png +index c33f01a7c4c7c83269a3b54935adda862c120cd3..969f9d922cb331b0ee035c621aa2a304ef03b495 100644 +GIT binary patch +literal 65213 +zcmXtA2Q=01|F`FLjgY<5#ZBnOHL`bh2q8Or@4fd7*|KG?tPt0h9YV+s*(+rIpYQLS +z|Lq()9aqoi8SnRNJvT~CMUIGoh5!u>jYvUWS_6E~LqkJX!NUN5i%$s>0pD;;Udl4UGv+L0Ur7Gdr~7wFlkn_l-Ha8M?oG-X5XFO=~pk*=pFC+8a%B&{(nZ_3ZhQ{X>GVcEhK{ +zlz3P;At?7YgPPg$@}Eugcv#)5wIx>Z>r~lfDoS#jpN@T3A*c{vUS +z`f$C{)R}iji4}L+OD!!58T>FwhJ<$_3_cyd)L`UsvhNzG#p(@fniuSNs5Uy3rl#GN +zcp!$0Tc@L2E+4#G^{Z!hjd%vR;Az8~&Sj?@<>h)G%om!>b)yUBn)Z)9=?0P>ztYmW +zOM9xRb?zy0Qp1oC@y^_Xeqgn5!{L(j%3pcP)!@RrBitAZ1Dzq~P?Nl`9^Ry;o^tE3 +zPWP!C%2queF}jL5G8S +z(DypoBGL{ou6zw^1gIb<*>b?U?0(_4DJ|z@Jh-?9Tc*Tn5B-g$ +z?uTq!gIPh`7OVj$Prvre>Ro4=IZevMx4pYZx3;xbnYOii#o0J_X~m{b{Toms%x{L@ +z-u(#nD!xrfc421x))_tX&F7@^nsQ|MRG{AY`mJeZW{EMcNQYG>oL5C*)~$2dfl3xZ +z19mU+Xx_G|6ZOHoYSzXu^}lhpJn!MLXwdCkUbf|@g5k!B1bHYd|M>=(;X5o +zx@Em|gClKuETRk97d<-+2b|1a_d3rR-9?$AaO+VwEMJxVj|AGr;xkJ)0>&TI%XQix +zIly(GKfxFN^oN%LdOR%aaXpaJFEc>_NjE89$-|9%v(xpzyNHW+ivBPe2XxmXVOwLn}8NR{CVEi)nK{Vh=)d} +zWYQ83lA**NBpygS5KJM%jAb;sw`@|En25qz7r88MTY|0(Jq$ILK)YG7Z^pzta2Nh@ +z6!50@#v>qP9wS%3Qst{IfBHJM5jpX<`)@c4O;v|ANJ36wPEr%GloO&oI$XJIkpMjT +zaN}B`=xaHqkZiK!xi8fr4M+Z!IR&t`r7?u^FPF9@P^1<~#X0DpHQHS0=7HbmZE?b5 +zWeeL=%FFZBU?g}(m3ssgojUMd-=K?CMC;Zk_ +z;h->G-=d5XUv)bfM;+l_S1?O>Fb3mIBrS7&dbO7xK=yjCh3CUL>9r>L<}6YFotce! +z$ow<>j%<(0(2gW2CWbfsQ~_M}zGBfwoj0<)tfI5%7%Gcp`3rdU-#V!aeg44kP~2spl*rS7j)s2SXTTxv*(UTItUK-6EJfO +zRskW$SQRtT9=cW9tByMSb6cm_7(t*2u~g354d(h4M^C%V9BO^4?zbUnGpPWOW` +zRk-nG5CQ*RS}!8xwfRmO7g3@PMoN +zLhUHPfk%vE&U!gm*XFqT#vAV0yby(Z7ob;*W#sg{v(CuNUIo*O?PbragEu_fNk&oF +zpsI~{^Jm@m2OlSvXW8AqrHoxYVY{5Ue@h5jSBaIP?AUr8>Y6h4B6!Ux1RMu9;Ew-?8rx7>R01RnTF@;;&rw +z2u`RZ^Sn|0JKqraqjp-czJ+5?P=9btW5SJ*+>*Z+db!QB<_!!Tn-^BCE|guCUk?9P +zxS`~ELe*hbq6Wu%htaI;2s$kv1@4&;e^!bz-i)~ +zyYrMOWBOc$a+KJ4N_5z$$;Fi}iBu>^q@AXSoT^1~=eXEk7A5+n$hR-qH_q0)6^_ST +z>RhsCCSn^kiEuS|C|`e=cy&G}q>^QcD@Tmp>wk(*r@{H4C1TV9EG{T0tsEsEmDpcb +z%s97#Isv+>2txzc&8B;sG8Z@K +zrdVvtUjd8u#L&_LHK{Q|oQWh#TCteyJmlQl&(9CEM!7;#C`YQIOrd%^_rS$r!2R_= +z0^{T4A%GRVJNASQdY!TXEEzJJb698sIMG~Jlke!J=#GxBGVwXOprjK39fJ?%dET2s +zT$iKXbDvn5`IT4&u{Gvowgyf@B8k4qHl{ek|O>6{l6O4FfuY;--?z!kz){8IlTgFlCRb!u;DD2TRUkv +zy?Z`s89McnjjT>*Z)GJ=NQaGVXww<2zG2Ne#CG9pTbm2rs1Dps21_&>OcixITxEXa@$rQQD2N}vS)kdz?o_i3v!Ri6pzcqpc6Nd7M@ +zF|ZZ2ai~x=zb8z^_NsLrdXaiDP0$3y`>^(GRBrEanF*=FgC3BeZ=e*B56Ne3(^Thi +zdu&6}eK=Dw?5r~RsUQc3hYw?9DrPd3*rN-;Vf%Hnx{Bh7y(I!C61hKW5%TWUqDb5p +zDhwG9j?xO@@a72$_1{R_mU2fe0OCW?80W1z&h4I$Sv*^4s+i$a0Y_|n%f;3}oqW*& +z96TlVaAUS)g+L+nf_d9tzkV^$(P4$4`b>DKAhLy|&!zwJ(Ls9}om_wJ^XD1?9Ai=k +z_EN&YqaS$eYgD9ayt=&FQwS7dt~fEgGSD}RO{K+SXnXEt-~HMqGn5Nw>f}@dr~j{@ +zGLv;Y*~d>U_}p?)#Ko61QPPgDrjeynWyVwh(aqbcl)f6S&qMQQGiY0imn{SXC5u|| +z{V@DU=B=n2K}C>wSJOTKgmlpBTYnxZx;R<19#(lXLqlBznavg%d^QAPTKOb>MSlTfeqm*6z3B-oHAIj>&-@{ +zP^?j6RjpkyFd%1Z(Y92gQD)uvt#oGBO(k`+e!I*0=ve}D2F2foglKXB)=fDq^}{Wd +z_sH8!58vzk=HMl8HrfbFpQZ*R3;@~!5WRPYFE@oxyU0NFRu_}}-}Pg_e8#p;v7Ydd +z(?T9>oLDBMHR+9+u#8$^PQ* +z?(4!nfrN6P5*t|xf*`EBuTO@JEMt5t1che!?Bn=5zKluBv%~wl!*g%?EwLPxh5f%q +zJS&wXHi4!e%-!0S3~O+Yz<~rietY|q4qQW%0fGaHbMpeIN*ZM;!<%R<$wNi+wq#N0 +z=|#k4ngnb%ne04S$U*czMASghosk0>=VHC)23z7n6Iidt*ENR5ZMIbfFsjhRrSdnY +zs5qmq=}0XR_lIgY{Or@94+j#9w?X7bw=s2aNrMS4b!3-+9GPDoGzEJ=Rj^767T=3zucgyj>;7;MX!qToEx7@)+&&oUsSLV&C!5AC@A +zv~J8CWk;8p`V3GiL6~8?CuzcfTw&6{`j8pl?m11b03B4fQkq2_PN~olDd(xlVvnS& +zp0OU!eIblQP9W^~GFGCAdIrt-#y^VHXjgze4bH)&<>!U{RY$O-2p}4)*Ntz1NnE)DCE=f3I)5t(p6N?z?B>jL>f=Nj{Qz7@YhdA;M)*=-9b++W(?$ +zIp`@?Dk{onk)ZB3fr$?Lo))>PNb;w|&^gx4u!BL11~OA*IzU1lh8}H83kwUw!^0L0 +z9KiyHHEJ+$hOHZ;lgGDCyH-FW$WbYs;;17?Adiv;1Wbe>;vOSMl9efWy@-GVZwov< +zq$hoRYmNWd6W}s6*h;@Ac-K(yzuP;-VrO@EcW-adBOP%_>^_*IGP=U3!@*QFFYH?) +zf_s3FB3^st8}9*_)cP?{57c0q;DCk&TV>{`L|CUwqwi@&Yhv*+KM=&)_#EoUM0ni@ +z;DXrQaROMzoN}&?m4K*B4Vggyf&vDDFeYvJNbE|5Rc3MmfZx +zSx*9esAkrfMPY!$H8@1Of+A2bNgnhb@E_F7g7)o{*tZd=!B;wsE{SngTX^|$fI=6q +z-;g`)=g0e-cWZ)X*olgN9#8AAK>z>~IrZ<4ea4)9B+z1_Lg&T9yWq}6EfQpviN^9N +zzyv5o_&6b;f20l1ST~x~ZC`*ka&ODO>)z%$4e)5zC^Dv<_E%T~o=l=*@th{ffUhX- +z>|9gM_}0`8;$8gor{zOH9&2qt@3d$T{aCZGzcz#!BwjJ|=iECKke@`AQiYV~%DZ6W +zso;7#`TIk;1{lDe1y%X%3~SYVf!~a9Pr$ft`S8Isf0iDqo&;$m8MMOvt{3v&wPH8GM7-)7~ +zSZiXnVNbBc>%{##8Ex^6V@%UkN<}aUay>-=dyMHbsnTYJfoh5}LTkk_XKifnGeMDo +zDK_Kdz=i(6uVJDnvP96t$%0;li-FTNwF8Ne5~p6q(MnNbpC8n&c+QXj7NW6ieSO_k +zNSX8e=*ZE2m^8&l;-6Yx;5mwBOLI}iqyoUt*{IK*HOj6v29Bs+6~I0Snkr4s +zVhs+41i}Kga13Qn{sE`JZ`m(rs*dWXd^@c&e=amTG*`>2)jO04?I+J(!||Dks-Qf;2B%Awn-c~0?4F<*sgf;f$)mBj9)2SWBsR}o` +zgPucJK~v+SzEf~I7qEQvU-9qSIt9qCr>92;-Y>Dy)3(Gtmo?Ly0lMxHy}n%YLZ4Q4 +zZtibq!Qpznsvle99~Hdl2bfoXZyPBANyUi{Pty}yQdRWhW1G$|U;bQNlL&_ff?qZ@ +zHKkVt^wJ?eRDLBtiWDBlDIXkjEA~7`Cog{R%^!*)0ndQ=Q%7V9aijidAi3SzF;X&8 +zo=s8_)GPqU&(EJLYGnj-DVTaDb|SkMm(A0 +z#sgVDIwEoO@$|d|{6hyG-h6m*JCX2Hkp((-H7Uu!)6 +z9Nd0vD;eLAG$%R$NRUhKoL-A39iIR7@898HXsLo8&_HlFh>u>-{naRQb#Y +zghhjwo14t@k*!m}Qef?X5RY0E>tV8x(i7`rj0fI>V+vZ%D+6k?4#SA!ekgjrS`(R~ +z__Gc6W6$iyg1xHSyNk}PfzZ?qd_3nbT+Hk>%U`~$Geo9A!Xz`4!ihc<$N-VMqr=bF +z*S2{fc_`E}&Rkq#VBHBn2=N_3L-efzNnB1UDFCP^f#^o?3XVvY5z&kt@uXXh0jVms +zI4v~7wPpKDt`d6)%BW)I%h#_sFlOEf1fa_FbaWy653sx0Ky{aB#F)WsQm$p&dtpQ+Yq$GD_`h~?>nw@wzX73(QjksGToh=c!46n +z&!6wtyZ~StzG5{JOrS`d{W7RRTl)M&${PA|T +zxg;i-_DyH}9f>toNbx_h1vCFAFOm|H8`i#|*ju*$tE#0wmd`FHa>`sE(ld +zPiv=!Mzknf3C>^Ku;q|sT*`7%gM9!N(x6J4n3#Bv=n^oZu`L&}X9)uUW1|2&7--dx +zC(ai?IXeRu08vku^j|3hIHgo;kaBtn0Hp)#$E&N%Ug}6XcGD8dU@maj110z|MOv2Z +zll~@k0U-o%=cwMv$;q^*Z~vSN;dA>q1_a#iOg%mli!v{rx&li$_frQB1`3oGBwhIO +zwtE`@dI<>$l|#1tJ+%1(KU)H%1MPGv7vtCeR(0{3hUTlu`<(wt-HsM)%6@A!`NK{z +zbZ#RM58E!v*Kn3F48t^Ob&8$uHLW?VbJIbh5uZl88Mt{WP?jzJ5mfO>O8pP3J5HCimlVD2x7)N +zaGnwdOe0B+cbGqBjs6DzBwLs?O@#kTUb|q@l8p@22k0Q;iDM4{ax`&ZKm%Hf5)wky +z$%Z_u)BB9BgIxiwcfpG)2Nd5HlUk`-rD+zlw;6 +z!0ZD6PA${q1o)jT2bpfs0Jy%fjAx(`570Z`0JgCVq$4J~c&1e*nz#}T4r3KCQJZly +z*5{|=V#~|R*SB}?#&bdIIrmoPm%n6v5i+V=I<@8ubS3UI(}xnAJ*y-TiCl$!3U+lq +zBm4~wSG}6qpKTt8;<8AV3Bkn=R++UnbvjD=ba+ol@K(Nu5h}AMgTVwQX;-)f1a#_E +zb-n6-ovehJwBm|)Q@f?Zj0DH!5m}Ti{~PW!!JpY`WWEUltdh`^4=AI+?X9!36joK< +zKoi-vrQiDg|IT*q?hKwj%^S0V$nuZa4r60uMvHlTD{m%@3Yl73 +zT0UuVs(~WkGGh(4sTwRa9>7OZ^!$5(ifs9xK`R`$JFB=FV^;P2p?9B?@T)S5SMZd`5fe +zM`)~|fK3vLMmiKyF+@qTBn<*QwYm9-MceHAnlq9pNj_96u84@zmWOJk9>}gkL-;G8 +zmI7&K$sU)Y?=*y8chnIH(X>U-bXnoxn(&EqjMDBDMqV~VWX{N3dQ1&rhyXQFL^Ad4x1}a +zecFs2Fg5AawD?cJK@p%-=6pI7x-!I>(8dE>^GfFIn~TIDAL<|n1|~DT5#-+E&#j(pq84i{|NjUkHU0HXRPbsB-U^!IfX0Hc+VA6$3`!Z +zTuxprG(F20IX>ofB+C=d8f9Q)1YUcNa6u;!{R9LAKokr-fhdhmE*f_(~`~U`*Koh3Uj-!(Eq9NiiH2X5j1s5JnyD217)F3C-%Ifv-5s7;P$oT$<>vh`8^2&pu6&%#m;4-aGd3jX~0 +z4H!@juZ|L}oHR<#?aem{#PrZ}4-E8=k_R;{6jsCawMH5_j!1ntCBXfna=>VaBP_@a +zH3`+oG1moR|KSBlDGU$4%*_&4Y5cf|lcvL&3iOaqB13jxmJYxy+dDXvT>}uce1CWG +zHsJO-1d_pe2Cm538cT-K +zT0tJ%GKva2c39RsfUr1uM>=1grxOZM%yVi$#~v1O>%A2haqQVTRVWHA3ABD3vq`Gu +z!GgvdK?HIQ0OkRgE<>pxFbIO~1S|%8d9_|dy4ph^D88(jZLkw&NC1A!^6h~Kz@c5v +zBpl{wwF1(4R+*r>45pWP)CF9k>A|GC<;OW+qT2w#LqeMU@gtxiq|F*D>x;3ntV|xj +z&APrd`>t6sWCIMIpK75ogb=MLznxA(u>i{+^a*-%N7M0qyrMw;LUz7*Nd_DRh)c3l4*9VG@wlvowHux$c4 +za&J#56RRs^$=*YR;S~pGs^W|_MK~3Qe1~DFC-yOQoGfV<8yUW|`bPAB2y4(+e3gz- +zNjs0viHi<8#VE@;qQ|5SDme+$UUiE;$y2X1Sf}`4m3GXSD3bs?sD-CjBF3rFlwsuQ +zhUHdl1}m)cRLWC7_y0cay!j3!Iuz5Dz}N&2BomTYNJeg?*}ZxMY_r*2vHP26cCkfD +zje7gr+jvIcNCSg464G +z_}t%hY{oaNpHUyg@>-IXVZ9o_NdlNYBSzd;5;tT<;}6Cm)6(CzDKw&mDPEF +z3mgX^1bBD+0>;?P>$e@A$1JIe5@-{Bil}JrlG9TcqbvJnsWIg)_K<;HCam@8F^dMk +z{tase##ZUQa9TW67&>1tB&^@dD@YSWs*#k0@v)@xPMU}I7-yyn8s?~M9UN3oT3R0d +z>Ug!(&ur(QLgQPs8Q+}5N4b*A@+tD2n?Xca9yCbk!7t2PA~L8n&$g#%z@1XY-qFz! +zFgw&>Ji*cZa2R&NK!{1`pWmRjo@^4T$vZ7<4-V7D^#esWRS{sm&X$(Qfpt)DfNpWe +z!wDP|%Fh_PgnoW5E-qeP3R%o2nZRB62i7f}<}&He4`f +zdp@5+Fx!CS+F#J6lRjG>L@E+|nkYY-z47L3+dc+1yHHNQpm=$bLDy`aa%ciDktc4! +z25&)tr~%&>UScQ|xJlqE%%g|F=pgbry$AQANnJ}v2WUy9W;hip5rcp`UVgp%XT!;p +z?Nnsn;_7$~`s*S_D6k1ZPz~5+EgyiI&=hJ);DT`<%?=p8Gs~*$(BX4s+Bn%y*6)Yd +zbfRLRHWJ!IY!=r${5@aaR8i_eVzZ`k)qepb-Yv>b7NuA$iJp`V+<9Ug%#GJa-@+t= +zP9DlPE$my@7;vrwf@2#purJwj +zmFSsh`My|92t;UrEp|rjxKi{-!HO&-@KLe3#MlI&^S}@Q7J-Ne+i>U;NvlWnTwp)B +z=8%LN89Lb8gZ{cLL>48!pzdKz3}OzEI0t_>Ha6DQFrq(xuQaCO8J9m-BYCM4Bnq^X +z4#V+!IMVD(`=w(M>nBa)lFQeB0Tlat?RSZvDT1|z_Fg{1-TtAVxRx8m(NAKr8}Vw4 +zb>gOAfe7o;mi-nfsktlw{yG2XJhs*)?ftx9=lJ|Hd0F|s$|=xcYgMKtcD7Jw_s0nV +zz;ld~WyMPS{(jSCKn58vh0e&pILz+%G*xkHYYT{W5W5b;LQdwOl1f)kPrM7sT3eFj0B3&w%e%YW6CCeYGrp+67>GIGC!(SNGXmu#>5bDs +z4T*%#hOcM>Bl}VQk+-L3;8v7uA<(#ikHkWDXr{#XTo)OjQofG-nILu-`6t@1;0yFn +z>MiXa{{Ue3PtsnpFK(QAv8`Xallk6(2p1T7(h}E!uZMOtJdFRvAVK(t8IaZJfO6+e +z0|2e6q5}NLF+1lVv%tLY-%DG@unq}!!jz7-HsBkyzhoi-1`a^vwzcp?B@E_Rl#yvB +z3CKgb3*`W}m1Y`*R2trmBPTM2Kl#_`=o=cYMO=l0;o}D*iu?6pJq~|yR9jF+ri@w~^Jp|; +z>ou^5dhlb$QM~c^**_mcXG9<9QjEJBCL|J>uGKOpVn;#HLnzSf&< +z+NqqR+sjK&7nh!AUWXKvIoR;O~!vj(u3yX=ORZspViAhEdrU5XlcXw?R +z2j%|*ajMWV?o{r0niyHZ>^0NE$v_DfRz>#Y%!;?OOU$9b#?Dchdh?Qn;GNL|KL%O* +z!PfUUMq8U=BXEE&62dyG@LY9YU%qN>U-9?H +zRN>1Y?*Whya0+ocJwkOIHMP}56jv>>&%~)=e!?Auo``y=pdd?=OoLg4$0PGoRqQsj +z?Hv-GXiR<&`5QPc7#TYCE(2Z2_@0Z9-(~iaETGx}T*{uW=4#@TsH(;YxHJ-0aOvHF +zbKL!f)S$>Nk+o0i)#sAr0UpQ)+CStv&{iDP>3w%#OQ>=mlc{3T7Pq>*BI*IfyVx9u +z?+UcAikh!rp5fSvAd>7@T5D?gI#R8~s@pnAHQ;>aHBfH8#ojoIFa%tkge4|)p10Zk +zhTWR^ql?h^r`Su2`XcGxL)DlheBw3~W!3%mq22 +zW&=*ZhZo9WuUXo6-*e(jEl9)vL-m!|`tq4h=~H_j2LsNU9NX +zG0MsHCI!KGsdqfT?Y~G(f4V=7OraMn1#T^{b%p2&IK*)>iY5EV_s~r8sCek0K^DEx +zdOM``Hyrr#ouhgYyQ9nWTdx(M>TM1`{I1)>6Wzx$MFuho^U%YXXgqH+DD^AWC;3#- +zMQPhm_+xSXw{HXPZZg&c4ACzFX&PsDN$*&b26uKi3?6#I4L}n9pr;2DnqV943Z-Xl +z$L+DXB!yx9C!u`5L>ugP!1F{`dG&T~3T$z?4abSoVdJ+yDOk`}2o@HCZPn +zPfts0@Ljhf@b4&N2Az0JN|f_vg4qjjq_*?PeF6fArwf>0kVRPrT=p;;1+P2efYFf7Dm#V;MHWzLJD-*aXdXJC+$n!oNGw)z%fjfSOrA9c&L$ +z>Dv+cKb^FBya1I%au3jBKGM)tOyo&J!{)f54wqoOaBmCC?88gfR{V#RF2{vIR$|$q +zR~2Z=gA251;3j{_2l18=oUS5qV88QcjZRHHcyBfIv|tjZ#f0$m5o~4yIOfr69 +zUS2SZJ^JG8!626F +zT#M6JW!Yye%8$-0_^7>lLCcTM>ouK1JdD8}*|cvitY&i2`nJiZQL^Kz$N<3(l76q1 +zSNj%DS$u(S0Hwjg>MRPF7$cd5hz2L3BE87yDpMZHOy*nBFeiUzc$GX!?W!a(hu(Mm +z8I(4VTk4v2ZZ&g#c=K!rPMW!&)QXQrADhm<9pSZoV;Mx@ +zdLh`@eV=@usVaM{P$G*#qL~Az%&qzs9~coN`ea(h+x;NCuPPWH@-HeSWu|CQ;t^}A +zBJVuuuxSW@jT&X-Aqk1$>-ZoN3C~+=qV6}TYiMY&<>$)84UKYa3dEF$nB1SApBwRX +zsq=Qle5P#%MpE&6STnrH6=}GG^)j3tw%U7mPec-AKUT};{I5lI}vbZq6$e>Vh3d(ma@kX*9E-Z_I5VNDXuK`i{QZqii`Lvlo1o_ +z`CtvniWA1h#L>6B2k9KX39vWl&lBfj2Qh!Vcj7Gwtt3B;8<1@b3BmgQY6v$nF=fgV +z#r$B0tSc-0QNLA{HrH87iv18;(8KTE1^+c;$NV^1;LM;~5xzxaDQ_1YdqVKL-m8a! +zFhWr&(*nSBI2L%1{E&&4h^=*IW?cRQ8S_g+Z|xoGq)F^9gfHBSoNj(*hQiJ5n<(D1 +zPaA4)F*r5qR$3B6#bZGa24M$~WHYRZsDGBD(&>A30$6V=Hoa|%lNuS&GE4SBx=HaY +zuLw}E%gadb46BA|bW#JfQVISb@jQL*^`S&hkW##PKuWJVw1Z+56%kQ$enf40Ml&cY +zj@jV>>cxr)31d2)I0ylJ265Pi{aC54$){;Ak4WR1z-0mnNWVm&ueZ14CGl%<0mf60 +zvNclp3kFr7es8~1VG9``Aw4=V3r&*mMT~lPsFb0pq>}p|7$#i3!vyivQH#kSO->5y>UmrD4ns^G^4CdpDkE0AOhP;d^azM6PiffY?GdqaL; +z@v-O4_I9Mbsuxb=V}n`srilXO4D@2I%LAt!f4lA4EyIPao)~{&n*1=d#D@k>IKa$<}oTwi(*nFARpM2Fh +zLj3RqdDOy<0a^ffv%krH(FWi0!n88m%reoX1$XhOPI#%Le4|)Lc(~V>fy5Ko!M5@g +z0)M6jYqA(LWJd?2DN?OrzBg{x`uPMVOCp%gj343dG-HJMC;$srK59ozO})a%IHO(< +zEmKAncfEk%gaETALhcuvw?~5TI>Z~~dTfAc$%sz=X(WHMs4)&hxbrvIy^jH%9n!z` +z7voMlqszkam5h8{q2)T6_^JT=U9>Y3Nnq_G1*w(b#|hFb(Og~jje4CoCxpi%?xm_& +z7(t4~!Qyfrr9~Px7=iG`U8yJ+a6tCrUct$iE6xb~Gl=-}V7FY&YZq9ck(Nm}KCy7MbOY@OR*{gxh +zveZ~Tt8-tP)#jS2ZdZu|j6ygx`2M25VE2Kn2IA%GRsHi7^^~aZ0lL%C(S&uQya4^h +zzc)XHZ5s9R)tInq-#89~R6Ekq)s>te45WUcXfv#X*~K7m20HTn)yMn!9ak(iR`N{@ +z9N;0i%Vv4wgK>tfMY}OpHQ2r +zsh)Cu?UPi0f*aW@{{zH?6pNWO@rh#tz=eqRs1mD7G||(W8@gbc_umntfCQZoU5|&f +z=Itb*czaX+lPD4IzV(1;AMlIB0`9W&NvUov8d^I#usL5LR~J`^6E9PS&Cjq~=pxCd +z_I*O|hqg|Om~Z_*9`*7U0Z7Z~=Im@jg%igKP7bgyzkz#zpor!1^hUUtM3(F|52_B8 +zY>4-K%NHxUlog6*prsnez2p2+Xe*iY@k-3m6q03}ak+$7_Q`ar7kFtC=d5lEU(&{V +z;#TB`Y=*uYd24BbP)Mx@prA>_MOnbMEczzRjqWgZqVS+>&2Ug=lY$ec;6H!h=5!p0 +zgIyMi%Wxv2+$U@to$c+wE=$>h8JvzZ*%i)zu;*DL7hXN~6#tpRZnf0e))vxHFalz1 +z>gLjg>I4gOEQ@cMNQ@GUtMaoWcQcf5emsccd@}1uV_5SrE^zgiF}?wcf`4J3pDcai%5p$-n><-9ERfxBOT$558LmOV8%qrcLty)Z%!$Q3l;P +z{mIS7;p+l>*vwpdF-O=r6a`UxzvHS$!<-*(>D}K_rUtGZ%Az034w;<*`4O?G_^4`X +zXQCD}Fl@4im*oAN>7bn~7r2cWS#|7L+2Mbi85o2e;&#kDX-O`L8xZy;P^-x<>%cD^ +zoxE&>EQF&kUp<%gH7l-Zq%jD#If6tD=LVC4(2%7)Vau~xlHHYPQud!dqbqd(%{F?5 +z#$p(QAP9(vh)8S8t!m7=IUmp4hPP>GrB+6H!&=CNe;25KXV9DYzH=7y@abio;}V)d +z#sOv;ege)k83wpA(4$;X1-KhKOM1Ac$k?8qr7$c9v`|04(Ya5pJ|Vbn_J+|t1Wusz +zkc^x_cF*eoC~&KScp~}G|oELjhgWVS-e`b>eV?~UCp1} +z1spP)kB-#=FC#Fpe#w4{PRWJQhngTP{fCqxmoA5Rm2 +zg=%!#zS&9^SnJuQdO|Hv(a7HLke01@cYq5|HE%mDnBakw#w3pa{{H>oFT6&6LJ?2c +zO{J+x@-eyqaJ(4J1jHUV;NA1ihb1Lq>Lh3@Xo~Ndf(?`P0__%R^Yhg#TlMdRcA$o7 +zBJUg5jlg~4Y+}L2O=u}r{HpbeN)R&;e;i8IdKm`y)GQ>8w^L^DPFpO?8C|`-L>Nl` +zy(*O=3h_Ah?y&qyE_2-aP|AWY1H@>#2xD>kb|=t37=`kB1uet=7?>I?hsj)O(lBG0nP_X}Y-%n+E* +zLQ@>OzSH67_ls%a8b6if*PeKMqarhM#@a^z)M3OU&tcWJ^lN!}staS`0YO-NeEi@b +zYJ|Lxmyy!BME5g3di>My+WhiM7P~?K*MH5`ct7eKzH>nf$LDA!B +zPoGva6{Zs&3fnBE`yr{IBZL;@v={b2;0u8-8e)_fv0Eu1mZnz)Qj{ZgC1&`~Wu>JA +z(6>0)!O;TOcD!*k~$A(+0zW`xsJtu58N`rVtSSDzXEFVS1s{IvkcIjJ8A +z5=ZM#J%3XJgg%t#*i{{LA3PoN$xImoxS +zw1|ID`Z^qKbFld4a$X|yFay( +zvKf1xPwO#(5Fs~RYthR+Ew%ay;<&)_ok)a5W1Qn*V~K;HH^krQ4(q|46%9xk+V=a3 +z$}K@hyC2bRI%hNn>uu36l)s^aT5lbdnCYGkCE*4uDg4N9Notw+PW&C1b7tt8e?VZT +zuip6oLnMI&=jSuPPHEk&XUOti3=0(Em^vuY%c^#kj +zK1-2$<3YuU5iZXL=&3G-_edF8_sk1GW!!>fWfRaBA{5k5Ol^jym|}sa$tjvnP}2Kd +zoPX1QmjYRf%6K?FNLfzsM;%91nzv@umD(sQnhQxY0dt-60*&pMYu +zY79>k46nV!YT}LAIQ&I(ug2#*!x+}?_j8Yf7&JfpIMC;u2rQyzb1w*&Gm<@L5L2k& +z{205>lC+hy?eOc%L+6vO!R;hGlS+8pXOemp%829%^gUSt{EI<~!zJ6#0;cE;_=F{b +z2jYw7lQ0dgY_RYY$d4?n8YDhj2`#3R^CH!Ydj9SUPO51)k0ehv_vbXb1+#_!a#Fy$ +zIXF1zigQIfvawyTcorDhqB!`_1Y#RrVx>gVZNlR*R;FJm0o&}kk`Unu0ryM8e57C) +zPa;s@8pDB)+hPT45mIXB0@!!gKA*l|ZbPBa7G^_lX@#{(d!Yj+2O7d7N>A3E6lS@{ +z3Ed29-zn+Y(lPA6cQM0_%>8gAYkYjTFEKJ!E#&YOdv| +zJpiBIq1#;W5;bUq7ieUbRn$OU%Z!;0>;Cy~=?yYZ!ZB{TG)x{1ZITw`B0htJg5*5O +zY8Z2O2e?yCUHjV!S5_z<_?-B>FJ)IRu8nz)R?mKkbI}~Av4_@u-u4v91>n}-UnMw3 +z!X~pxuS(SKpY$-0U^n|cs@WuMlphoSGh?exapFPJA>&>E6qZgi7)W7eNmPOPCFpUG +z7%2s`lG0(oh6Rtb3?I81})CMgN^r72`Dn42G9IUaX69n~jb!l-mCGG@ +zbZGMSOea_}>cEX^UiS9^0P!m41$#KURA{%fyVPq=2(g|px53I3Y)OiE`%65Rq(D3; +zG1udykSmQvey{(d=`5qF?7A*YbLj3yy1PNTK}uS>8y-5Ok(5SS8Ug979nesFY(U@eU!xEq6zscUHu7?}- +z-TTIgA#Ex>hTS);KXDcC7UC*dF>w0v5UVE_qoBd0Gts2qEtyihQT8 +z4ZJW=1ZhE4$jS|dYzm6Y&Ub#_-=e^n%Y-QPrVuu`IS-Z0qgqEn^`71r_(F}o30dfR +zz7RGdp)X-jY+uLs`Qa@>hnCk1XZ((7h|262A{A!3l)fwmeZO~DcS=+`%vF(AqrKpDb>M`FJd!V8mE1)I+hx*bBLnE5`4HYd|eL +zm(0iP(aj{G#064t2&k{2Z)LoUDj#FBZ)j6)-zo +zVL@5m0{H%K7dz^33=a+jR9g*89wAG?nb5~uX~k%g@8=2FjiwsWqJHXDt*#m%_2+3H +zy!6dt>$z}0D(ib}*-hn?&f0bq>;&TRqNE|!1$OF@uH +z7_XSZPGqKg(j*jAOy`Frh|L_FnD@<*bPR|NSnf^EYQM(>}Rq9PZ_ +zg7|l8xv*195t6?H(>5tC=yQEP5JQ81{W>@Jy<{05%rQm#7_fwjwYf7c*c}13KH?GB +z89L>Vn7q(%z9>d7vbZHWeRs8?wFmOSAB}-Y#||8LBPKi9V|^D|W+RQNvKmGKRfOB17y? +zXYsLpoz5-vL}KufPYf}a7dr~m1~};OI9!mzko=SdPhVbMK-KD*2@73>>3ZnEH@ndl +z036=o3sl6=j1olU!f;3pqvVw+*^^o|doh3l#-{pbb$5a*#v +zfQ%A)`(kpP=y%>LIS)AwASrL;*l`*merj;J%m{yiPJ!H#x>etrhDwk>+STEuWV+W} +zlc>i7?KfPT?AkHNvY_2kZ{_*nlG9KGdr&OjA;BmiOhRvp0$ACg7)NZ<8R2ea==yU; +zaSv)tJ`UP7{{HjC9TSrPkAbj=6DJ!bx)<3(7L9D7SYF|I?c{&~J_s +zkPDf2?l@L+F)Wg8C}o?VV&no<0KsW#9sI4WCER~2|L3=(!K=YVhD8m0+(w*0k%LtZ +zEAB(CjjYKj>f;c@tqsouH*8ujxcyK4rkMB%a5)8=mjrOmtG@u@LV&a+04*MI!eSj{ +z{D5u1f(sy7Du@(LS~s8$BLDU~IjokHX}H2$e(e6rh|&S+5W)_WcQ_{cRAqLI5)PBh +znXvChERYCrP;?+UDXXC*3s>?l=I-q+ULpOiX7Q9(1L_XM|GG+2gDt->a<8SE5F+eo +zVWTZT+w#!ky+thi0~YhAPl#KklZV0}bz^*ZD;R(R^tXR$!fA4-d`r5H&C5v(E}Qw0 +zE=J8=fnppj+l%W;KeIzzTbpunWX*9JrA}Tp7?fG~|nlrxFE$ +znkzM>2Ql0We7FWhq6ki8Bd_QzcO^|y>CX(31coS3aVI!vojhN}kzK_gJird)4h8*X +z^K$W@2OgY2k5aF7Nn(-)_k_Gn$%eIcu8zvmdub1R}GZ} +z^sQZA_ce^AG;&LKM8fi4C-W7>eqUG}ctz1}Rsh9d?CtibbTe?RLuHuoF_28l?WA}= +zfefG~d9f59)O!SMe4%Dg1peoRsl?s%>6vkxeR|7u7@{3iR&Z3(_NfA-V2h4ze2dJX +zSOB^VPlp{bmF~9G^WvN9%30Z5AN96_cu5iM4Eq2L%WvO&!7@%4xa-jtV|h{KF<0j> +z5TvFtv41E>jraxVKt*rbs{U(4UKav8xgg3;u~Ko;cyBQIBG^onK0)B3Cv##b+k}CS +zy0DOE-7YiD?KQ6eW{#?_Z*{kgQ38ZnfNeY4U=i>boX{|!MF+I3rzj_)xgjfI-V#YQ +z{~i7|{Q)5tkQERe;yG?porqpY70E50Uc;(_!#xYd#TiCN8H(V1j>E{mgb2ZeK?@VQ +zu>YiE^#Q$_3KYt46BtLmi~aSqRg%aP*h?AqoT&-jR>P3!6S6Lx@pv^Dwb8d3C8I2+ +z>Sn;jc>a9ZEhmTQ+^2|yk60rf(}PgqWXxhS>xpKmUmI7-kuyLYbPKqIcY<&505b +zO0lR95=rQ&lo_n@Mr4R_v{;;nS@&Y!*?;=j9YnYTmo5g33$PfI_t80IlMrLZ%1R-X +zZHr>U7wN)kiMDhw1-2BgHGnTAVZ2(l6)gd-Fdr`5g|fLfvCqgg +zF}{U)sA!u*{VC`P*ab3b9_&#lhAAf%uf&x#_JBIKztbJ6P +zC)yZJdzBgy$z{KTF4fPbm346%vtcwZ*bM2#t@2n +zPN0|b>`cD{oWTdGM=HBWw~YF8Pf_rucYz!rD95W8rGz9`Gvw)?#5It_+s}=3qIguj +z=oOZl)@^ubu>ZT&;mg`riSnJ1r*cQzy}9b_Akz(wMi)n=j#b;g_Rf>DkjGa5bilpZ +zAkXvr)5Rq&fe>;%^^)M>NQMqrc%mQ0TSDJ3P_=3}LvJWiByzn?#Bdt96>w$9tJuuP +zu$%$Os3a986VsAf`A|+ictn6v0AU@tgy>;G$&ddr)e{3^(8E*_fsgJb>5CB3e}8>t +z!<7Cr6suk_g+N^v2L37#;=A{PgqvNHpAGwwo!a{&d}ORl$tldP_8MoXw_8MW#swVj +zkGK9@p*0H^Igr@m8L&6^Oa8}m^-bDLM&0GE$00*EqE4YiDsPdhI|P2#Bj?Y0x74}2x?hoM10J&#gyD`UzEl>UaPBag`tWgo`F~`tCH_2OpCuTl52?BIHC4itz +z!2&^n;Z8KXVRV&XHKTzVadL4kcRcs+=jdl^tvYy|G%_bVXW1Me_5vbyZmldhB0Vz$ +z1T$uXomzv3su7sQczM`QP}C^LxZ!DtLtq2MCPIE&z%Xyr{ZZvlsjm!E-$&T-ZxaQO +zAV_$dq;rH2dR!F^YqnVs=?>xvv;+4Zt!l(0GM>0?@;aVN7C6uwjY`I-6TGeldxv>GCP9Lohc|sG1G-MOS7OEvjnGV;!>{RcfQ}z*m13F&OE&M*H +zC*y+*Zvsv<{cwouL0eVn?D6gGEsz;oT%jY16uv_gnoJ3mizEjlje%6AEFd7lABvMG|6>CTk#&GwDM%u(QiR5OmpmWoz^I?j>uwS7W +z1)s!&c&d@NB^42qs6Wr}IOySvARUWjQ*59L0|-?t{}yASw1oMzu+ozFqJ#nzk}HVH +z7-a*jngd@Vq2egcy*+i}H|>fmnR<+Bj(2&=YfQj_1vY$$_e7w0M +zp0^xSAoo_uUbF#R$6VL6t%i6rFV5^0e%OA7$;l^|$U*uuKxSlY%pH*F5;2;aoh|-& +z71~zCEeU4{VMZEO2q`@MZB?J|*vF&tOY3>|>r2Y0g{rD*OHhcnlnTMS$heS&7U9q3 +z)G8E3#yp~uVo>m8!>((;jQ2dVE!|=ph1;0{K4;fegFQu?>Ve5tOfO>TU8$zl7U(O2 +zO`VXoDn3Z@36e{sx^;X!>Y8mB1u+e +zx_s{0(SD2^biulX+7-6W8y%)=OuK9W7f?`yfj`c^oh1;?$V;|fINV(j6ks^B@+CmTTS9Cvj&h^Y?`N;K +zNEa~XG}b$28R(~*z}>emJE+|zT!zU1`S^CqfN+1jYW2%wv?px7EW>vLb$2U9=ptq7$02Zh?cAl +z3}5)JDY*%nuH`^=p@mC^acKRtSZ!`@2016N{U=IT?vm4x-8}!z`ibByt?^~lqQ@z- +zWO}Us1<8YUMnXnCX|%|OmQhhscvl3{mY~hU5fb-}Thhwr?Vl^yP7pf{9>;!^lDoBX +z?jV_rYf#ix8+e9OA9Gx>9szFvCo1ej&H&PKv^&)mOpBp~CJVCb^~uS}#l>e*Ea%r( +zSC6lot{+A{dz>H6!;~>;AVF~AaM(1d`-ubUA8#GlpN*S4hjQsTgWwV)<@eTF|8AFR +z4%LZu@H!*Fv|Wmp+AUUnXfHA#)AoXRz5CB@fh1~E<@qDInE$tiHwGaH9g6k`K{g|h^T5Hu>3jd?+}1O~ +zaAAtlymuVm4^nOy_vxtH$7X^7j}Uj?{$MlkwewAA`p>#?%bSIHrd|O%ztQ0$FIZUE +zbI(=xAxr&eJ^=wp3HC~Vnm|HU!{-lqVS=;YG3m+<$Dx20h1RdWn2xY+^M)c)hS +zj8N2uTS~^+84%|=@XcY$07Sd^xHxt3M0L=DyKsV8lva;* +z^gp(n;XRQ=pNcr{`Ch%CMJ`ePPlv$?wI*;gC +z)=ITFJ|t(~#|S`!_v`qvIyeiWBZmzhB5h#4iumlmTK1Ijs#)i?$KUCS&7a`^0)wT8^D5}(|a`lX +z$glhR!4n2o2-#^S^^%;dtb9iFV1W-&F}ejwC@ +z-@D?02sU^(!1s+nRf~Col>zg*`(V!zBXr)dKuyRWnaMYUTUTgYrj@R~IAfRo?yFd3 +zRn@`2MIuaDtw!8rg8GSi|A^Q2Rl&LM4UDCU3Dl5f1n|86K)mG +zTdC{RsjytGxO2x+o5t!F=Jy1=AC#-iLJG{cvGZbz9pz!#`>N{P?H`q6aHQ#1ZbF`u +z&*Nk~iFpBLK_#;!ImLnR0c2Sgj|}q60B>w5dSZOMMo@C!%pmmCvAC=_|4`orD +z2i@8s36GstNhvw)%a_~B?pHAf#gw3%;&K$F?*vNhp9`e!rcB#KLAWv#6SJ|+(aa3y +z>@KA9xhB9|=08tQ+4RKHpFtDa;9I|FY-*xId-k>R6VDQP;!-z<{`Eb~5M?d7jOiTt +zwJm7-m_wU4IsLFz?GB_e;F3$h_e3u0D}7yL8N>9+0T|poVk*Bi`yNnd90Aic?aR~@ +zX80H1sFLyil>3yM)CN~5cTrJMG}O(n4t>;YLb^+aO;a<}O(53C^18bD5&`xh34xCU +zAVO~BQR&DT&jEqi3WZ}h5qL^JNtTS(;K1+vCaYMSw161hqFoUe7Z>bc6$hot7Q5{a +zyI}fV`Q7v>Vk8L}+57`;f@`v-rY0fm?zLS&AwyFyb$!sAPv%};{6hkk?h%YP*=*%w +za$-7_+WQXm-w8K+dnH0X>P;enL|wog_g)AHGA1Tssf@EI1jxW+oCDYSo@=p&D^Ivt +zj)RJ&X~eb?110D?-Td>C>BIcAn!SW6skvg(uLTsSlwe2_Ac?9fE2mRWA60_%Gcz)} +zmQZ_6^c-l1#3@Uu#A?^hvf*nO3B@Pj8e=%6>tp^kOGAN?G)+@1uB>E5L-@&DDZ~;T +zi; +z;{J|ESrL2@2zG}t;m4pO&obp;RKrTB#JKtT5*Hw-Q!OaI^1j}Tv3Eau;p$TN%jgfI +zsQ14aI`+8vaJR%QsTL=r89KJ`u@a^>Ih(AE4=nvwqfYspUd)iE|8fgkA6Uk48;dn; +zt*j!7Y7PJBTs-|?WVCTGqOb7v6qDQMGeSLurm#tiR$3Kfw!Gd!zK?a) +z+~6R*7f%lf$>0yzy=QoW}Uf~-T*OFFUM%+o9%jOGPv>+4myNZL$EC}zN+ +zUzLxS(|N{+yVK8LE|$Lgs;#XpX@PEV9FoqT-(8!@=Zg(O?NbFKrfE>D;lA9}+Nx9xG+HZa8(V~AqUR5qK}+6c5~)YRA5P6AO4(CmM!C}FCS}t$-zzJ976=FkI#@U+ +zT@)FAVqn9Qd_+2VV@Bx{f=;NA+=@zJum1mD0FM)=a)x*K+^@gRS7RD5iga0KE~nSb +zy8#5jmX$SVv8kb9fR*6%g6+41wgjeYAGE-L)6CQep30@hsAltw10Vq3DJw%TB0WqEsnrQa +z(SMk+qWyItTXVayzkv})J~L@v6@B}*n&y`K91Y%!efd7QVlaIwN7##a^co2Pj#~k( +z5vJ3Gh0veI;iwyFPLWZWm)Et^$eIq<5R@Ua3)ATx2mf +zx)BkM{Kz0m%KexYk?ji20P1+lR37+Oet{J2>*92MS>JYrcEvc$-)cfLpRhKGEDuV@ +z6ztc%LRI}F^7Q`3*n!QOY>oQy;@&YO^JtNUc$Rp7#}d&tsU4SEUH@NaM2FPP%WKl8 +z{EAhzX7TcgsvyFefR&MBM`Lgo92}gUtP|<%=or-|B_%a*P4%QSuPL$EbVXA{jvt?mOs +zcrLy9Pd#O|+7+S1NuGC$Xa<5p>t*$>ihb2N%fM)2opy~UJwwW6 +zOvwvo-rh^iGF{9&(6yj<6jcRKnZAkV4I3><2aSoY%dA;lzMWNlqcgaRcX#e-mR55h +zTnIML$47xNqx~S|<25Pe)P?~`3bJiW4OaX}&94D}9@W`>Y;0_toSfX;G)77C$9m`g +z$Vp}3&FpIl2zC_z&)$gMeC(9zs3OQnoD;fkP@6K<8v&W<|tul@c*@J +zO-!}!v`9D!qzzJj0fCn8?ss~Sm~ch4bSGwXKbqn7A$Q6&#TX$eON$Y2gjd018u`M>uxt +z@9d00*w;F<0YYYtjl7pJ!(}qbPyf(ugO~$=hM6juK~JWM>LKd?c=hu4xvTU|Q)6TJ +z7phV2Np2Alv3~+x2!Y;B9r{W+9#4-27Uav$zs|lIGUxK!SaUnfC?%A1Eku +zO=2_|k-6GS1-%FJmbRg)x_U9WF}=9?V<{p{DS!tdMQK+r9!tNM_L^b(4M?ZL&=Szp +z;YM<_A&=bhJLNtB~{oRp(!A +zdxA%RRRNkcub@3qi1r-|tuNduu3=oXi3Z0!D0{YeWTtP6Vd9Zz3O*0U#TJ7??9W;K +zc1S8=K8 +z#a&D!4#iK%cpklgCD&ihSE`CjZ3Z5!oJyb`C-46@$9Gl2u +zB&`mTb0s}4{r9!aW560|QHZdj&KnsStH}5Ygi#^eV(xYOIhPTG_hEDhCw7#TIt3r8 +z?bNqzt)A{cYCu?%3N7To$4Q-y%7mV^CLgl2vQmdWwGEQgXv?MT)|Qt!8}kNq_4T8t@$@h& +zOB9G#6dRzCgncCWGuny!U11Im4oXT&`a-|w94NVVGP%h!@kQ|^RYc*IoZFMhyZ|^A +z|7@GyZol4dxs=U~jn5zA)d-g)d8>R7b(@l^u?}qf{r>={*V5CL1EX@S{*s!Dx@dXE +zk1^aMTDkebeg|v4rnR8N6|9kw3CEP%6ZtmsEKmFJp*eaG3L@325cDea+L-++j>J2I~^brXWLoO%oe +ztx|e8_z|@Vca`x!w84gCf?;6nC4F-!Fjg1b@D{smP987#`S))DF`_PBvv~VHL6S6j +ztl^JPn$DYD^JCC{ex2kWRQ9ayJFi*Mi=W26uov$Ayv?rm>M&WxV(L=1w@@m^9t;;# +zU?3_`;RDN-iA77On-ujQHW|=lqL~y>*f?ro(84JA?aX|A^+kraTa6C5ZJjt^b5w`j +zsI*Vj)2XwLgybE;N&LQcyoipDZk(ge6hLYK!!uYeeTYVK+$LfsS +zmfk#3o`Vi3pmi!KDeb#0AMUvefiVCb0Ocg~i`ado@gpABgp)KPE)`C@&f}lmgY+(B +zrKf-G3~HteU#4%?|G;FvkC5kp217VJ16~ywPE@A8f;tWp-$(_g_PBQ_7rP(jmNT@z8utOnm;y +z)oG3R$1^_4hv^?%`!H##75Z3?W +zN2k<;u|!(vALHY(I9sk$bkSG9j}R%e2ZbA9QlN3g1IpXFni_GJ|5AUA;W<@aPE8kF +z_g`I4!0`jPT#T$c{|ojjL63#M|C)tan0sE1NPMI|cc_4Z`o;Dm^LfKptXYCiT}Ew) +z|MRc&lM}mqwV-?s)}e7uylhc5@7}*M$p)SP`w7;Qw-A4pV^##_=FXB#DdPJRI&0MX +zD673rzlW|rH)CciZBd`2sOEsV^xYzwO$%1?b2wo*X&Sq=wKY8*ot9>AF)DyI+de*Czk%tPJ!WBL#Tp`R +z<_)i@tGhY;8W=LLLULgv>?qqjwguV}z&B-YZ?BgY7aN;CA1f~gm}vhg{%x(Tt*xo) +z36!D$M&7Z;N-2Y`5C +zC!pBg*t1BpY$~K~19WS!d;N>lrBh((gBKq7liTa-`-w(zhzJQe0*d(uk3B6d2i2Oi +z05=Y_9}2(JwY32NJg=Z&lc>s+keJ_p8<6M%M=FdVUP|qN^w(Vwm3MTE +zGc>vaq}4t#XKu!~dq2gi7oP?Rj2#>t{=~mtzpZ28{%f`Jn@`dE&m-rT7EngM-Uhx* +z&dtp&8VAOqs?i-SGyZAl2ve|kj5+}&i+y+vQdwO~4XlrXd40MW_f&19` +zl{R|xZb>@Ml!X^{8^FiR@}Qf35leM}(>A2-|06P4snb``<8|(t6?6ka!^q_NG}MeG +zmQY%0minBWCYNOYjofnsq3WN6r7p%x-oa=P_;}UZNKQruP)^5>k1cl{ZEewMUWY9e +zk&dRZ#r9wn2+zB>0l(b?0xCUUW5VUfbn;c1b)bymw)6AzmzVW~(o|RI;jjfs)1%7D +z%0Mm@fWywu&!M|{G=MPl1k7^4x$TqgLv4knY;<{k4&n#;Uk-l%CdNN4z81$o;U+L- +z6IR2dlhsfs^2z<0o!#;A?{DzzTZF19ZQ4%B_4`(P^~rL7PpTOlC0MTo9Y)77Pb~%Q +z#7SRfx<9jSuCCU{mugptg69VtITa=DCux@K2=*A#&aSSH;O(EDP81`7ddHh)xvb`9 +zIFaNN=g&A+;GupoVbAJ_GwZy-g>?%;&9ZWGt%c!qNU1{xqp$XM6-L#XXES?1Z#n~} +z)ARHFf4QxXn~w!vYc@QnW;Ul9{uzT}iYOeeJk#EJi5%0XBb#e$x*FSz5GNpnfgdmt +zD{~b6vqPE&X2vHgE_dQsjELpSX(k{{8R+TRHtN5z4Q-XbKv$oAa@dg;TpqR7i{Mz~ +z%+AifqcX6qGW-+7mXFD9<>FGa?2su4vLKohoQnI(d +zzhQIh>~Yw0af}!T2L~@NeEB0WI7IGX_4C2G-8Xm|rkni+gr_TI3-ce*XNMt9TMc-! +zokkee1GwUZUnc(<1J>nK#3jVJynK8{!#k5v`G3zu2;ny5P6AZlF?}35j08TW+j!h| +zd|ntpPlPe#%GpJ_geYIoe8Hd24Y>gPeeZUuDAMp>fU*OIf^2pNZYq8}50~t9H%-^X +zPey8g(w)J&jtbQWeDxGiC;WPN0E^+~UknQfai%{AJwjC77&G)CK?gBW6#mRX^6{Dm +zxy)t8Tp}WWwt8Vh3a1(&un__)qogoo!Q1wwXrfKFS$J~A5a5_MgR;;{O=n8woTowzKr079o#vdReTN_V2j^R>IrYh*|G_$_pCzGCSXl%qIcW2`)Mv2OlQ^vfx +zSQl=n{51loW4#W!+UM%fTj}H?-dB60IIM64(~w;Ai3)6%a=JH(poM2NrM_GKa5efl +zlh!)Vl0R;7sEW*vUJyM>R&Cq0aI)wfZ*FP1Ynkp5&CjQWg|xm8d|~f-mG=o8GUZ|E +zhwh4zn9p4>K1o=-{M&whas7UNmU{D*HXvbGv3vVF*4&eh$?f^1Oy1sO36w~C)cRFHgA0MJNX=&wm@A}WtGY;OqgO;wnFU=(s`SyS}B)P=n +z!bNiib`+~TqH49+&|uDNaeQ`>GqBa1pO=|*!gz^_&EMR(y#VvaX~0J7fAk%abv$$@ +zUG`&<7_t!#SXa0lFQ7D&MzIoh-65|yJ_hxMEo!E&o*vdov48d`xN2m+$K>l*m<5$q +z8HW1)-d1@@V`F1Z4q0^j@v*H3M`qXTG5G(Ev44Myotg{oDq)M`=HcZX^qVo5RyxSf +zFGF6*+9c;Nmi`;W@@t6mKyt#UGCW);N#QU+8U)os;J~!@R*&EK}1eYM}=n? +zPO46vj+gA=M#jF98Wn|`Q-J)36#F%LaOdyyL;s>Y)i(wU +zW_l8ZeyCOo0P?KS$Vsh>j7TF<>d?=OI_%hyXzxSch(Q6Ihq0~kx(9kD-Jd`3?e^@ +z0jIyQzCQV1XEwLz;PUKjO2#Xhk>NgkBeJhbmj#gbD!l4hgoTBlcVgK40(D5N0|Ij5 +zQb^MdTa{Tlfkk@F<91{SYt&a+f};Xz|3E1C +zf*3i=ZLhNek6d0CUw<2es-3^AIBa`k-@(=|MUnPDxf`s;UqD*MF%q@9NRE(-qpUAX +zAO(yJAnx64etcG$4}ag)+Pdv=whqFcqj&^l$q{;K>d=pUpX(1L_ZvDo{=EG4d$q4# +z1lu-X$QpyR$Hy%RO#v)Ngs`taqx%F!`TOBByANZhCA7Anj +zqfx_1Yw-K%JQA=HaO|1x#0v+-2ix9Q0CqQph&N^dN6U(#a;K3_JM){-fIs3QLSKLV +z`D4feNU;EHRJ@Fy7$qC7D|6H9bly~pErQGZ$&@Z|;%W^58jRVO-cvGiVPXzqzlYt$ +zYb`RWZa?jis%L>sWn`X$=NTuLOS3dLH-9~T`?nOF<|0JBWki_oVH#)faWCI7m;F^o +z`*phKa5=wV*Qo8LyuP_M3WQ~M)RxS0J@X#)8SZnSIf!gE%0B| +zQ$yQ<6SgSSO+Q!ZqI{Eu7km7K;CP}e(@Y`GT!p{3rG;>ZYg$Q0F5m0F|G0&O>;_i3 +zk!}$*P5Z0%ib1OY7^0jz0bo4IoYsqDC +zOL}aM4sA^PQM_b(DyrI*iS-|K%CMWNUYrY)!&@8I*R^d63@$WZbfdCqoe9VTXB2gp +zo;Vm}q0{^oDC45X7=7-J5;=7)31erRu3N?}+gnV?=;%GGw-yDoQ0S2*my8@)7r_Sg +z2F%*jEIPtx?tg?)i;GgOs_sw-vrF5#SZ^1QyB`EK=L=vH4jXnVi2sL)C8$CnMZv?M +z)fM|wz7Kp6xnco|T$Shxqw)FQ%!v7*%Y|*T!tic&Jy;OgRO~q_` +zCsb2Od7kuN-1UM>YilCH!Z?1QG=X9A>#h0;uFxkZOdpnddY~j9Kr>*ajdV*oQlkt` +zYJ|P71r@K~=gynSV3T=_tCjH;yuGe|K);slMHN|BjdL5Fo72*zM-q^|yA|PAD!5jK +zgTZIgpix8mg34zxhY7eXHUU}<9C +zFzp*#;93MVe2Z!GD-e4DotQl>0xqhWDCm=@yJBp8wpsrIRZ}~eKg6}l&T*P^?w2ZkTG+Llx1mfU2H$zcp +z?m`9z1^{Q*xBEcL>}5@@rsIGTK0?GJ#qxmiPi +zE|hzhD^km+IgX@Kt?}-m>um<1?C977XC@Bk(B|pA88qr>wpq#IDJvV>O~Sp3jXP*e +zaM%=(a(}2alSMzGVtp@)T1r0w{ee&$n^r@Wjr8RbY;Z5TZ(sV!1!uI@ZR{qXD43a< +z^U-%@$nWHB1n;uc?_`PhCs>g3A>7jX#2AZ12O$8{_cs<)0^l71nxoFFY*+sEL +zPUoaWVUln#fc9U5fP=nG;7s)1$bBSg7_{dfcLq_E%hKtfuR7=~aL;*#ZyUnH+*MLS +zT_GRt{TVm`aKcwf9QauPpY%b;;@|yse*Qi5CJNomf?XKww=L4Zfynip-_`QWy9x&rhhVVriWx4^N(uO~m+1d|>7@z4dJk10ZEn?R#Qu8G +zeu?^?FS&jI6r^6j+yXfM<{7BrN6X+7IN`$A&9lB075(tx!@Zs**)wOX3`)Hn6BqPe +z)Dcq*qFiTP9kt@Ahrv50LhzkefB(+H&c2I6b*p;|ls)u^JC8P+70~O1F3Dco1`Au1 +zF^^{ir?L|K`eyN}rTw!yS2T5C^dVqy)^Bi+ad|%j&rKbaJuAZl5X;ge?SE_|)m$W$ +z$+Ai!Luk9rUQ6;HKxK`Jj-Gj>9%V~3KZ8yn8lqi6Yc&#am+6yx_>YVVgQ67FrTz~r +z#LCVNi;GGKzMUN<2m!y0K+-7M@-B1(Su{ybU@(ldyk~pfR0x;GCoP!D{ +zU;(#+F>dLpbr0g&^=^}j(afa%X6bg%eS +z#<_=}eygcqE?z&Tp$evAL_-RiZjh_g-YpHA$5?*_1R)~QvwRI1q#yRE(x2j5YHeE3 +ziexVB+#`dJ&?R{s0Oj*#C97z6TCt=F@>jpIsi|qGp;e0s$OT~jW$ZE(k4+2gV?#cK +z)2#J!y}^aNyHGWC)ym4sVF*)1*j7~sd2am;3Ec>5sfUi_+SHU9C(&p7@m|H828Y4U +zL@xgveJ&4S@Ix9H)Z2r)H?bkS4wV{A(gbTn)w6z?h6nPhS}fwT0Ui_Q#xU}^ +zcM=dio(zWdo!%7Oa*Ig?u4IQ;hp*T*$3oMd*?1DgCs^K!l#ci5oLyd4T=G_PkWbHA +ze%}hfu>`W5im^LaOJQ;3hb6=n|W0=Qhgx=W@u$l!#{!hiHqnry5u71i|Z7#CR_KhoGj=)!> +z$%fhEj=)H#fgYObNwfi;=W+- +z6ftb~-#LDf14M3->iICmB94mAe(KdM2d +zjz$|NwzmNcA7i@7AcuaYroA-X52fW2WEHS@=;D~!v~8fFQ}H$f@4k2)qpw{LCQ2`` +zPdogG1e*+m6+l@6_-36HO<{deFrXbO1eb1w5cvd9+Fo|Qo%9o{Cad4+f%%mGMm0u7 +zxB9U%cUBkE~>c~H#g(=waq}+3as0|r^c@# +zs9`^@uU*krynBnr@?UuBqc1RvMc~ngy)M@ByQ3hNTxDa^yFdcKq$mM_7pek#TX?E! +zsqN@7(p>RS)lZK%H`wQ~b@S(7th`Sy&}Gif&fMGAlaq1EbGjP7k$-`z{hE_AZPEHy +z_Gdxdv??>w_bXiZ+sm%!&m3=syyoqAW&e^zr>5dLvH9eFs)w68B0b6@D!r>gZC|s +zDEhMTReVJ3ZA>OP7 +zoo=n)`!9zea{e1fSs~&4>bCuHLr^@InJ_T&L}j8%qKbI=(8h=Fhi3GJZ<-Xs)7&Oc?-Tp2PY?4z5p;H1_FjY%TRb}{koB%;y8SMpg +z%3NZ>9JD7uOC~nZ)Z=1IxFeq`Clpg-RpgPSs*1z`V;TAR_!yK=@7vTc;OwZ5B!EMt +z%kKewNy?W&YiF!S3`m$Q`?7^p73wXmJix9s0{ux!j!ZA#s;3*=)7rr}i{tu9vE6+Y +z{y;F_YBKPJd!!xkS($XI2Nb~gq?g_Jw{4@Mo}eS_>DdJ4YgAPM1vKA3oS`ra4jyQj +zU`dsgtY>#6Zr_1!a~*ZZj~Tl%(EI`3o`vT8oL{;H0!2#JiKRRoZ;;>GZz_o2(fhaD +zfL{ZMg_*xCn@Uu$WV~7pH`dnHR##_}09Xg;=`bJIefB_sd1Ax&Xfd?!_LSw^)r)JT +zCwr;{^Z5JTzRDals8CQ)8iK+bVhw~O=sE(P!NbX!2Yp;EjIYa2_!UN3EE581aHHzx +zx;nR0&hmN~xAQ0Iq_CvI~HT3gd(gV6q&+ItspsJS%uXs89=# +zT!bQ7zc~B(Wkpu4o(nxR`%#H;A7E`EQ-wNw>(J)1r91$mKMnHLwseWZ_Q7>xX(@du +z5ym7i@D~laeUMo)v#A{x(+a}?I$2aXci1{aDjoNSWwfA9u{RA +zQgENYM4V+er8jPefzS>pzzz-%Gm^uM+7kK36~Tz5&?U5+c;p>m+uKoRer8V83$QZx +z0fod@v49!IqkG>!Td5pB%Dc5v0bkrc_Yf#P+Rt&zqnW$A`X{$6g|V^r>F1usme|2>Q!y^{JrcD@s8n-3-GXkohBz&+FYqA +z7$UPV4KGxE|8+{8Tj9g<~Ij~M`BOMhj)io+{-95@rr?UkX42AhKlaNoc_McKOW +znMk4aFISr$bki_(=j)lV6{ +zK|^@Y&AeSNZ5nl&`4~a}lU|vY`y`Ey8-&Y!j?nY!wZAG&cgr5ykMa*dX-F?mL`df6 +zC6fLvW>L{nnx8_dD_eH3`{XUg#ku&2l08-Y%9GpCYBBGW=8&p_c!vS=alac(%(-KC +zo+R2rRCe)mOyDrATEQCj?IdrC7ckQQp!e_3HN^tGoDExip5zJcxALKdukXr%Pn0yx +z((0;x(co1+*=#)tDXG@gAkEugL`ik5%l!b*$ch@j^*1$zc3Rx)!T4TPrSA!B8*$ZG +zk66{Vrc8z5>dav&?d9<)6?4!Bp!2K-8AL7?DQ$} +zL2ilLLEKmmcRhU~x}D#&k=_4_a3?(9>QoWbH6$J*n-9Pv=c;p-1BDA@IS$}i8-l|B +z4vkZ={sQCq?RyrRiAhKdfH9-CKxA@T<7Y2RB@y51F?_!w +zKv08*(KI(`?as6&5!e7x0(4?P5192pi7V4owmNH&3 +zE-h;BXxwbpWiflaD`GghlXa4FBd-&(d{nJq2jJLH{etVjtF7MUWg=a$ss9DmQ?XIx +zAYhIJ2dG(r5!W}~AD{i6exFvG3I(8NkAnohWb7Bq<(-{^7Y%+#<+lL$xB2=UI9#P` +zKlB~(SSiaoN`r=B<^GlzuYFT>wa-7Fp&CB_sildvVhG!fN1_~ +z37Y-Q5o#MiN~CUMR=1ZP1`Pr>VCw-l#@awp)O|373s?xX7=Jj0p%{Hx7*6Cz#0=BQ +zSJO2%rkCyh?{EUNa2*fPQobCv3VsF9+5S({zn*}BlrhQh6ez}jZ@<1ucgr6-anQsL +zg8}G!ba`xxZ%g2kp1_n(f9FSJ%wX|gv7Sa5EQy53D-`*uaabi}wRuB?!%<+NduDoJSKX2sEWbUPN&*fMU(X=O1RZ;N~H+yqU +zEj#PL_M@&x6C%M$NU!RYhnU%%Oa5kg14GSkpD~5;wu2pQF +z^}qoP=55p@tb9-TB{P;{F+%-TwQ%;BVQT$DP8R6hO)9d4agXDCG84HGD*V9`w^v92 +z2>&l2KUq#B`9+Fs=itc<)CHiw5+WR(x9;>wXnwWtA8`vA>qW%NU|4YSzu$~d!Pd`N~{X19@^Uex#e$zTS+xx{T}`Y|({lgQO +zhCy$ho|I1GKglk7b{=QyB6A7_&B*L;|r>wmH6#+dV5c^CBVMoLY>n38`fK +z)DEZ8m*{uz8E};+c(YW-;b`P<{_502o2Syw0x$B2D&C^x+c;7-BpH*1>g1x|bFM;% +zD_qjS#SIWDpna;OB2lD`?SrDhqx|;Y;sTScsTFe7ft9QRSOq~|!>o*Vockx=Tp +zOHU2oyG$_Gl{*>)#%-Vpu|5D5AqUS03TT7SP4{{LlPSmz#B#0;Fi5_dZz+m>@9(Hc +zuJr%WbX8GRuHBmM25FG)mJaD|M7q0M8l@YgTe_qrq!Ex5P+C&yP*6$*HtL!FV;t_h +z*|68QzIVR!$xeg%8-CV8K@&3Nzf|W|Y0547rE0hvkuQUW`FZwq{>94nXDa1ceYyi8 +zy={qg*@Nvw?hCGcn&S#Nn=eM=xBj;w0J^}(cs7n}@WGEjuB2@3^dZ|2GL_vgA0M9! +zXyhxphc$^~9}w^hZftN31@P6*TK1{EHfpI>BVIVXkRjD-zQ4!eF^BekhHx_=*&4Mk +zv4NC*^XCUI>OHR0-oZx}g_>z8O7axGVPPP}Z~TVjLV(Qo5e5hOb?}bawy3*a80Q=ZySuwXp?i+$%N$HJeci=lzdb_+UGxHKOwdldUH#+=l+j +zzj0nGdojG5t4hOaaEmcy6;Wmv5x7X?->tG*mQw4eH5M6!J!W)Sd+hggA +z`$f1qUd{1mDM^j(qjVW-zI?>Ma%!S +zVW*CLc$R6Of9B*#hor46E6Dhhl{;gT{qr6AaVc01U4&@8J1zMxjLi=t3*4cU$O30L +zVu^@h_|$I;0+~S{EA`-0XZBB=S2&D$phz7PoTM`*$|$fHqDNaxq;MTJMc{Bdk#Zb2 +zOj+Kz7W_fN033Z!}Ebs#4d)+5Wg276|`9vj`-M +zH8nQgeDI@l3GnMgqT%M9=i%lC`3_0{ZrQK-oorAs$V59s>~+Y_Rwd(z~k4A!j}N@3fPeG~dU2zT7GF#}_#2)IRtWTp(9RUd_fC +zp3x6=_%S^Z%x|Oar57^wA}oHn*!t$p{kkDK>JL`Ouz?5fqVIaY56IVb +z4`AR1IRyo+&XLp5z!whfU3xk}fynrUO85_CB}23G7EGvKANwxhoPJZG{CqZIQ}BVe +zm)9A{L87>~@3=IcEEGKx)F$}KrutVUgvZj)lQJbXUaki50K*<0H0;bSE^4SpU;TQ` +z>1W)ci^Ly3)KWN{XN!yGNq%f;St3th6ENOy#sdIpq^_MSKCR?nL|g%n{zcEl;4u^{ +zLG4ie7gK +z^Cuv^*_FU}8T|u$a}LH@-fGa#lYBB9r6V*VYz&SwWt9hQf(!M`T`*gwWZ=(MZ+KL{ +zByj8b8YfEr6}oBuC&Z)Q^J)%f +z7yVD+NQ&X+?~kn)?8V^(-)Qj6x)y$7A_y5PY_(|f2fuu&+h0@raD-*W;WQiA{}wkZ +zWK8EVHAYyx1|t#G_ZK(%!FxTsJubq3;4CWs`=Wh=*CFOo@}pmZ*kje9$a|rr-uMOx +z!OG({Ltc#k2pw2Oqw#(#>bD#+JfDA&oRYHn<{9*tk62~A(|-A7g8ag;@YlRi`VRdX +zJB~0SwHx1cwJfx!L-(%zd5c|CH2;W_Ag0tPQv_~8fs@G`l>T&`UX@Z>M-A6d`GF7w +z!;)ot=x4z6^#1-n$R8`_07ORS#NMy|fPC*(rQoN25FoV|J{Wsi-v|NQy!B)f1$63` +zt%;`SRd@Hz{lDk;S$ct1766s!SI5LhgQe`HvyXllnb{S<1?m`o3ZgA8fHnJZcUN?@ +zWS@dNG-@+vRE<{dvv4KqtDk9UaHdLM8H(2U+yU +z*5=zQIPAT=(o{vtv~%o*k6~2nVq>-te$_u5!bG{$=x}D)v<6sX+vOm~c3|r{*XeI7 +z>_Yq1o11P-XXRzaNFoqWu8s$4SG6lYp#GeYgR%nGH^7#^Ft@!)bRa5%6a_luBBtKa +zZBcLCWsxn4we_<0eqC~~W0LCJzkmM_kfXxBQ(EkV4W=ujx}`6mAqd@Y6K?d!Xne8v +z{nyTCTh^M>H*oR2UFmrP)p`MIAK6#}xJS71rB@AkS0^u@aOX~0sY9F1!-sIeUH$ZF +zj8~jNCWqum3w9X3jsvbMV58Thx2E19{Cs~Ulc=99_{qi5@eoEO;#|J=mY=5v?aAntS_O8AITr+d^!cZEo;%GlQ!Qx~Dn;UzOdWj!$BW;lvvG9EXTG0;+(2+r;8HTU7sF_e@lGY5 +zfJx$YMkW^~UNzu5PoMsQ5VSRE>cB1pD<(PIgg!wAz6TG8)y13$;1~uqp2kNQ9YAd1 +zRFV-%`8^uGw(B^7!-JnSl@9G3^hYXIVHn4Q&I{d$FWr{KcstANs3hMp_7V;nPxJ|gOoQ#A<@ +zNLoms__Vn>nnqRL?R$t<%bNpeHf0>d1yn~XF3J@!cfOG!A18c2GozSU_kwf`I;{tu +z{iThl3i0fc9rV+LZl1}>1YBZKM@x#QS!7=S38F?{Th#r`k{`5>)hcXHvErq~@2_n7 +z?aEJDBEBfx|80JrDCZpwm?>ewXT$i>gyW){g4>nB796qb$7XtO7cSZvncK*|-(kEk +z_(C~%uEI_1P=KZ7XXv8?29Cm3lE-+$74#Dzx_TT-5arvbvz!V@#RKHHc=zgO(+pNn +ztrq##rG1z_yb6dPpyZ@d9NL_F$Z!n8o%G6@H~&+sYVGP$(JZ|ps`|kRv#ID0XxUmM +zkG{%X)B}VtAi@6pF0o|CR1sb70Sf6=#^I~fGVScYR}0#N?j#K`6s}|OQ)0{0!#*#wS;snOEkneF6GO@=1v+<)7YCIpu^lCzEwrTA!_GEKO%&_1g*cDX+A2imRvp82k8( +zRPgXnQBcS>=Ppc05xIa8{2Mlj0)3;su4aOv*8-^B6B4|Qh?(h?eYgSo2X^E1CyGJh +z<8a~oDi0*_uQ7LUH>@7i{;~X#@g&qjY`{$6*p%m#r%xm*(zsb%zpme= +z0I}pG`0Z0al|vd-mS|J;*s3BX2;df!uZsO#0%h#fX$-!15$g(;>*CiROp$sf#3?5g +z4L@H^PEDeyj0s{@`76`^)7H?q*xpr>>Rzh3$^HdM9cCl|L9)gRn{y?x4%+A>UjWjN +z$Fu4%0TY||2*Za>Hz6vj{lC-GICAR~|jAN^asWO^otl)e?nS!R8OG@z9BRW)Y1cY>Qer6omz&=kXhAO9{ +zF+8v>eQe(}UNJVkUdpm|FXNWWWWu5?aj{t_nRl#q?v)SfaKJJJX%}n_$Er7Pv?5AD +zhok&f&MU=8pCh~LWBYvZ!w$9D3yhU(k{e14fv-C9Efzev0AznzCwg#Q(eq|(vr4dl +zu|Y+{5#Uo$8-k+%b#y_)cV{DLn=(D^MJuI#c5?;m{dD2$b}MX2=Bmlo7g~-sHgd+y +z$^R*@v+%vUx@xC6Qla(fg47z2g$NkY^WBL`QRMwPIcdl+BlMhi*f+UF4`zLj>t6ZG +z2fY8;-XE=YKS=+bcCif!q0+*mU=Uq9^@juu?hcvoW3B&QaZUNrh`&gEgZmYdYXO_` +zaCbkJ(V-Jn4OWH&3F6*U$;|4P0Jd+}596=+4@;RW$-CfJTs}zp^mTMYq`-Ou+8vAl +zL?x%+XWLQdA^gkVDO4mpH5Oy!O@U^BC24l+_7;GQN!=rs_2Q~3W}0||R+O<41k%d) +z{>vouci_B~X<5;QqGF>g4CKu#d~tde9^6p+wB`4vhx}Zxe+5f%qjT$fx39V#{KHRS +zem3d)>X?#=7-*WxyilX@q&n+k!jExDc&A?L+_|oC8!jcMr5I0zU#oPGvOh}H=Yg=VGSF!c#n}Jw4MbL+Bmdri67@qnO1XW>pzS~cGwhBTxUNg_ +z?lCXD(X{R1#CbDOJcDnL+1QQLuFnA%rV`Aq^!MZo4NsCutye6J4cl~ph>6xlKmp`F`2xxeJb?b>7O?#47t!3dQFwG +zQ@i>QyuON`6CZ9?=MBSJL{NcX`jr(U3yZPN-U@)XAX_0%?m+}4OoX7~wwWD$X0;?o +zzgVUFYp1XKw_yvr4IkYjr&ZSrzk$8XUSoaGqd4lRi>vItCEIV^n;yNkfOWF0R{0M% +z0Y&+1{9!U|Q5@X51p=RXRDZADc|QBE5CM{Jf?V@F`Etp1j9n_9LYebxMDgdX%^Wdz +zl+vBRiZ(y{J%z=hY)T7IdKuG?P +zPLe%#XoGJXDak{xjtG@g^^|ycCFq2Ymb7;GP`%Qhie0pTF*VKz{ +zi)P0vV}O~%6FL(b64+m{lDJ7a28pb;3aLz){xHP(PDVPJ}>c_C9VDRCTppyLn!#Mb{47xabvN+riF +zQHfWnoXs`Jxr~Z*W)QGi`qJJk +z@=JYzoSifnu#mTphl{&Pk>EW1cT`CvFXnNgFF1Dm{r!(r)tsG);$)pwN(VsmZ3LQv +z&;22}r~~yC>|foW)3Ld^S%L!KFLWn*{7P;ow>FIfuRSH1|JMS55PST^gsKJK-LQR% +ziG!6@I0q5ZV=OSltUM)DM%jav7EZtEHxQ)!8jIeag!JeV2cULm)pP0BO*us5@PW0 +zRvk-V4&s|uN|&uuwsH6D7*TpQK~k>o9et*HR?-TNn>mEruiAX>G8Av_-zz}S2WI)* +zZ65DH553-{`C^HZyoa<*THU6Htur}iKB7qJ0gadx^}nOcL^XE#9>A9~|NiWYhilA{ +zTrH>9*W~wK24l`NSjxsTh2$%}iqf}7eG>9*B7)030Onj3@?>jr@<1VVX|f`eJ7v<1 +zy`Ikfc5N!Vex?o~*Vxefx61sJIwZQXVLg$<|Vq$KaEPANX_!p0i4Lx!RV#kNX{az^4%$ +zqp$5tFk5kjr&8`;gN))46D%{0EzHEju49++IO+bdX-A#5JLrI6fnBr*5Chqtx(B-XRLs|!q{KSEnj;f(%gWi|dzzY1db +zez|_atto`-kr5OVYSO8UqDRK7pFexztzo{)*e|##BL6F7Q>T(*K}?@-i6l#&K@xNI +zBYwHH9djg$!Dfo&QSat*zo&4a!Nmq`OO_@MB1+4LOKScddu5*Sp9JkFmt=x654fF} +zzjyG`{V~`QAUS?w5|2eO;>Tu(r}e;8a5{d4?9}|8W2$;WQl%vT-r1x4OS0Gvx)H2h +z0|W2>`Fz2w;rO9=JHX@n>okS!mA_Zy1p5E)SA7V?C3O`e^onO*ilxDwvcyta%N=aC*vd*X0PhTrt +zFE5k6cr>B0n+umMU?x7<71#Mb*TujM)46{_Qs^8I1j@0oGfu)`z*@m}%r&UTl{62a +z^=yizIH2vf{t$!U=5_+>5j;DdDjGEx`ul{B-nMRDZmz6|iisUpQw;j|(%AUX$~FwtX&>}S~@%p4;@z|jwfv|#0DMv;nYX6`fGja`h= +z*g3l-o-Qr-a2G}4*<5D+ZCGXhsj#o7*E+krj|az}!n9!i_hD)7)8Sq4s2iY0T%(93 +zprs>u>WRJo@WHnMMF6;?3(tWYwD-bwEI#w+@QTOQ)c!s*I~OX##c*D|=so)*SnulG +zMlaaR$sC%Jno6mOjf?y#N<&7yL!SfA%$F?o1^&H_PYA<{^i7*J$w7$oAGpIIP@GVk +zR&%=dz}f1lyF2%5D*;IdT;kZPQ1ahes5rf(L2pt$&bCg5g9=&!yk{;vF`~6c(qU$>3Wu)XqrDK3e>cx&vN6ot(`+@=Vk}GUyzu@uS%Xm`WxHb;YwnEtIw=M@LQ0lJ +zf}P9_Gkf|dVE2bi&5Vo&+mqarV}koFK)1^J^vM%@JM|}@)Ugxf(JeT#Z6Z?T +zsW~+I?UpYdI{x!a{hB9*_+#B!kWa1W?7R`QBU9HiV? +zuJDL)?)WAR*gOLt7Z(l(=ym#elqmk54t +z6Lh%0fdkchf{Am4{XuZqgq?&&xr3l7R#)zS=ATh^m!F6t?-|lx;}S2nvh=pvea1}( +zN{PcMO-F56a;$5JUzX3&*dVKf@1u7!XLjOdgV}z6A-K-KMC%+M?AWpazyEZ`z$x8G +zVk?n&aJ{cUDN~41}kz0>=+Xp^yx_&3az8qByE8 +zrcS5nmH4DBCENsSy@~^WJ33rG)$Y?6cls+oEu17d{_W&XA3rMNk0456FcM+gEUB%X +z3OsmV>uc2f5iWMR*jB9#)eJS|0VLcYnQp*`^=i%C^65?0D5c)>0;C#@hF}pRd1m6T +z_-{~HbO>*z2Om5oV5zHO&Mi3NM|II*;}g~Zf3A##hGnUBAE*U#D=6Q$;$ZF?|9(Su +z(lMt;CDl5I{J35Y<5Wt-DQqYsB2W&ic7xH}BWW|}FLvOQ{13>y_H +z&7|h`V&5t>b-jxXK`P&fid`Bq2E7Mrz|=Lt0?w|hPx^YsKj)5(zGCbM`n*<_AGR{ +z_726x@}A5Y&EUaAE1S4%g54pcjoj)Q=Qul@ees!hHi*`IGgRl;jJpi_A8=A`o9r(V +z6Ihs;>HKGdvYW_A^SLkR64aE>nL%J|cS2;tG>a?z?zyIx*3SL-dinF?H3)nz_vWUd9E&$ +zQhsAzM^le{qR=8}H6Ei26Jn +zjau?8clf^m1p=~P7A86>2oStBzgzWflE=CaPf#)=)U +z+_Ef6iVSmipDD*dkWF5){@G1P)=tpAfLF1^!KV*~7@@MxU{Ea{is22#r5+7cem^)E +zYgZ`KA*ZAih}c1gse4BIP3lYfdAdZF{VHtU-@Y|H;$nh|_4ntWGWn317J8%JwZ!;6 +zg>t^@rDWdLk1~ZHcegNTUvmM(u5+yVYp$Z?u~UUet*OWJ&^QNthQY&s-hvF8Upt2^i{C#X +z;sEl)zAZjqsAL>~=$#>(Pq7Gz4$mu=T*TP6$fp$*A}&${;kBjNB^hn^|0S&TP%UYj +zF)VEkT^-?d^vL^;mLvk=_TJw5DeTYUCmQS;)>MvFLtrjFPyKHpgDfs#WAfrL;V2^q +z3D(mD!+YdinJnlVx;T9XZe07shcCp=(iWN~n1Trfc1JJl$Um$7Cjp=gjIObE45f$M4hruUoE=ZX|o{}Xr +z_fPSX<&>V)Lvwe@Oc(t9$W>?|(m=l+9|v)>+A`EioA=AxGnDWCy&xnPH!0&LG;HOv +zjZhM&_0WAGD2i3DHh-E9wk9E-ZvHq^n=a}}=pdL&rVrncAg+l4PAJO(?eI;3_z?7%`+E4w&?awke*sd260VpRdpKc@D`)MH_W0>d08wg#)tZ8aKx7neRoqT** +zA05zFPuK*#EAWhgI?xm+)EH|`nO2axpR>Nyho5TRaSguL_(5IWxQsB +zLGLVwFiOiPh8$$a7MHl`k;}(u(K36Ve?cV~Rdz+xo`}^Be?o&pJMv5+()0MPm8k(l +z2(7wy#=l9`(DwF$CI_<{ZLcBq2R<@_LGXK@`2O5fkqzDAn$v)2bpI7y+PC#m$92LHpgKtJ^!~>E&{?ZCK5bCF0l2XXR +zDjitpX~xS=5w^%j;-xwOz#9%|G5~b%^ +zO>s6PdVhu`LRGu?Ry|53qOFx{ePcsVCiZ^Uv%h~pHuC50#&?wYk>MSs{{8k`!HrY@ +z=7ooR_j@yQ_&|#M(fu+cl>9Ge3Ocgm{b|um2AxnJ8$b?@{v|M2KcQqxa{)LZ8h+blRt8VXCh+JuIqnyP;6WMoF5%?YR@ +ze*tF5YNWVoXMQ5~*&^+BC=SzD$dgwn+YscJD&F$Vekd~b2WoTK)Rw(jxyJt;$C4jQ;MaCro(@cSl*qZhu$y2 +zUsfU&^17u(2TF-djaDi+(NwyBr#`+iStVdZ(neUk`Ea>G2(vKmJ)+fn>?fTR%@o?zI;d!KL%#}jQh;F~~;$wZ8Vv{;p4gz$b1;LfO +zne?XtR(Y^YpVhL7vvwcZ-P!hAxizGU`IO|ZJ(u5c+>S8wa4}kmM-PU*%OCkm80m_9 +z{f3drM(LDmRT!CA*lMr@I?~^OV1e5Yjy<+WLFX?&f_3fQNHLS*>l@oVMR`oR5s4l4 +zHqQqK?OAf76ry;-2Jz({|~bB;HH~SFlF`K +zeR$`*U0hRA6Jg#U_iXLkR=(U1$;Bu|OH)($J~6fL;_q4F{N=S(ku5>>OtckH7ZDH; +z09`WD;&N3EQg+NE%17v0GSzSG9SI`;gJ74VRhN!-16>DE3L2#)cHbQ^he)0Lv$%u~ +zfWlD`GwaM4)wI?Vwt_pvj*QZ~tsGA00Jc3ySK*Q^Kuh~Tx3s-&eeyh#cZ?1`zJpbT +z;e!K~qb5OE(GtyD17F}gPTMI1gV->UWAfw}wtuIeVITQtW9L$lhB=Df`G|*PYXkRw +zC&-lnr3|)zwITc&(s^-ioggo-*=w<6hXxf%P{4pG2C3O_=Nk~hkOVh15XfeT@u-q8 +zZl>eAQi=RFD=VdV*x8mWCpYT)%F5u_UXX{z9xpD-rfavEa9I7+fldf>=tj1mQz@Km +zsyIj;b$9Si#SSqB3NHkkzf3jSFsrpb)id#mOA1ef-9E_cyV3&fyZGe#Ugo|K-_+1D +zouf}{q!h)L=Y{LePhzQHSAGE0bM}#6cT_qhIps`Jl&RPL$vf1BIj0x^IqIfVozAYUcib`yZrI*)1m}{Rf +z+7OQCeR+bJ)pFrIi$y#*KR*YNF+Y)t65s! +zw>2x1?|k+E2$2mPR2OrKnJxHsVl{A0nQd@Qwa>%ak*^p+oNjS;eEf2{{Hs-<(1gG3 +zat|I|Y6}x{++}1)D9k?pUT#fjcrUNtf^%|1q391VIc1SlT}+=MOh`^+dQhZy+zu23i~RqPq`b;HPzL?_9FNv-7aIG->p41%sK8 +zq^P^?gX7|t1Cgyi0IdXybXtuqTaFl_3#K36F3c4ZxxwVJG5PbFCUXIfe+ZmopomE> +zo*)v@V52xCdgs;@>UcA?r(=YS2{(jv;P2V?r9Y=Tz6piPD*eRsEA5npr9UjFB +zbKne76T}O(?E!$dEPbe)W^ZiAOMs>t0I_z;ewJ%Bf?{G~A|m5Yq=!xEXTly0bjx#? +zU+;ok1{|>FV9qkI_ESXNCm1n7LEneG)n6p-Ni4%YDnA(_a-2BxPhwOMw*mCCu2!#QwmQ7iX1NmUKwN%FZ+DJQ#3O2Bw4B;rG~5xyP?Df|Ub;Df4;NLV5+OU`B41CuAr*<6zW8^2Q*T{{Xg-$iN@LFP^dI +zlL!yjdMg+lJzim~yH}XxV#ZiX!qFEVZQmJDHz9q2ZVoZN!S~R#^)YBWU!8A#?sX2y +zuhG%uEb(Zo3}>cg92OE)Qg$M)$N9oR{Ig&=!$w!7HT<3CTCbFe@(ac;vEC!31RZBb +zt=YL`Z^k@?*J->cUi(k`PS$aIfWFcBYHv)66ag~5r*dqnHl;FesA&d%|6B*NW_cIx +za=FvpXf0v%H_+B*ziz9egGDrPzGfC{>i6g2_g61xIMsIzIoDR8X_ttO9+4>N7qiFs +zaV2YZ<$-*_W5bzeqL+;|t`Ml|QaygGx|)hRcA`X=pouY^nilQv{P3=e)g>TfTb{$4 +z?cQLyr+Eh?+9h(4Si_B~H{^fN=M;@}itf=p^o+>G6CJEN3;~sQ +z82yd*PMXGlZQXHBHG&-9E^nOBI5#oF_ZgS6^svU6`|bFs6XHjZIAqM!yUkdxz28(x +zan*Zf^ZZo_rV4gNA5RtTwt5fwZ-a635sK9>j`P&2hTlD8>6o1>6OR*`mWVcpp<+xr +zXh2x>D!su$8B(kA2?`2&uo});qq*(hJ4rVo_fqIZaDd==8qPpj)#nIp_9iDg0l$%3 +zbniEP0fQ`QFW`RYB*=jfDT^<0-aFw;|0cbx)R^@ns^<^^xk$A>hpZ?nbrl`USrmy{ +z%OT>VWDJ?IWzst$qBl5+5$mPO@;oyqyeizDX3iFQV)h|KQl44a +z;35FT9u97Br70;XO%Qj7&><#!hpQtO&a#f}=~OfXM}?DUi4<;#?glzgoG}C`F~*0u +zEn;6dA$A}|R32x@r~g4PeDby99GX!^(NLTPBp7g;pTDbFb&Gs}U_O_Ro)aaE^82}5 +zd>*>rU>n>pnj0I30yB1z`nG=k$Ipk%o^0j)w@ZBXOl9bZE$!28j#mvI&JF#fT?Q$a +z7!C8o2_A-DM8TB_krGuBc#5<(Y)sf&!~ZT(-m?v0Du;v&aYe5I6HHVmHeDX|^JO>T +zlo6anlip3dJ9Q-)^>7-rS>)Q6Z1MKH*l5)lO|CDs(@;*7Ss{3DIMlW%f%q+f10BJZ +zIYu^df((KH0kxfrY(tvrR#IQqhskwGX=zYDM)=X!8bITnjhxaA@)qGKqsaGZXqYo6;q)sQ65^JX5D>^vVUn?kUofb@x90qq7k6)9XPx4+mnikw +zj?)3gSY_6ZF1R^L8GJ+0(a>~o978d56lv3v-cw51$(8wIv?sh|n+=j)0TPRm9Ow4; +zQ@fVRe8eBbCemoJ6Ux{ql0*zydu*cj)cl>F5|F95$@;^8EzL%jlHzcD51XO{0Sa~& +zk}pxTS+=}yy=Xu{8pvm`KAFw@9o-7aAgfwnj#8E3(|@c**3^t0Vuy?b7=itt^f?qW +zm>Zs@@-=@d3s{R%9Lzw^EJGQO%M9gTOH?Mz`s~rk*qj=1L(3wmI)Jbhm@On_Xt`+9 +zwR1@B@cqk|ND&N&AaCy>|3|5eANGI!_vj@_akm-I!c`SMo4Ls=6s@MZ#}X5jUT;Kw +z-v#rTZ*gx)&p#FrN{=4xgw|84Z5}&*jbN>hhnL$gpfedNyje2gB?d1+`V@HHEefdP +zDA9K61ce$6TzPVLjV7#7lF;4`)60v?zNM6Y=H-Qepqj^)t)`!IXEcHVyPxb7YNFg$ +zVHEFapMfa2Tq(ndb3VMgd!A*amw~u|gt>Kyc^_AbPgGJ80-WL_FjJODrFuF9=>A^| +zp!J?v;WbdZ;;T3oB_$;g+U|>VU0Ye(r{_%ePEtYE^O@q&&h2dh5>%J-45j-QP3vBK +z@nBg=$0IDW{VA%)lHLj)Jspt@?f9nlxR<@wwS2tH8lf_76eO7^N~Koc_@yNJK11~l +zhv-T+5*h=FfYI4~FMLTcT(^=BBK-XHK`9zy50)Zdp`tz#|4bUBCvIDrkApOaA)6c7 +zmh`&|flL2@Fa5r?Fb^{Yg>j*3(wHs_`-`Ol4X7fWsNb@TfAqM2fLe69D!~4M&D&SV +zl$na5xSDlU3VpJa(+&?j5hD?^xQP@qCz*D6lq$S|0&{eXBZ#y?3wveK7@J0HhD7LI +zwvzU~UbZ=|Y+&yhVnUj+A4GIff+tgc>tK~Yz4WtBV<(C4_4R8A;0N=B!KlzRksHpq +zoM7QiY@I=V+1s~M%$JU&NtM=NVKhhgJrn9{#0mDIS2-?dTyQlelpY=5zN#SAp4@Gd +zkhz*UZhkAxl{C)0z3Swie0q-iV!8f=)sKRi_S?9VfxH_4TCB +zH9m@7gv}Vp5(F6F6+q~JM1+2f&Q_%|B!ec3XorjYTk+v&3af3Tj;s`J1LF#ZB(BF2 +z__aTMqD525uOdoD1x2#t3cH3+4d~o#KBpWSKhE$bK-1H|UBut*`_)SA8(UHZ3 +zI+=M9fFwXGVtlgL_7D!}|mzOQHztcG(vkS@Oyrdu)_OH`Z~nCH-@ItEF}2yxwl +zq0eR2%haz0zbsiUCQWduD@Ob$YfStlh>fH?Ce<^XV!}=0eGy4(O$|CKQNd5T7idut +z?vF7(*YE^hiT(DMaN^ZIbA1$RUGG}A6kJ3XHG`?nV4nBg?byE}B4 +z5E>}^lyD9YF?gV%tawkh6s)=BWl!N)9FslrV1I408<v)<);H!(Ji8`Vb<(Iu3Y*E)PH7$L*&_d3sx +zoKSMd1{?GplNkQwM^iKszkgIQr@}-8!uLht$Nd_SY@E&5emGC*F7^eyeslDtrfgbgtWiI6?|tn+kaEm+E26fJ{>U*b0N%n2Ve8dFGHENujx_yWvQ`WIZ^unZgLoMgVgb{*0i6stlNLwuY@Anc^+VD#Ufw_fLL8f%zl +z%|e2L92Q4aM`8p!o2}CtSWkz(?Bj#VM3g$`UN(t(1G244@noA7pC|x}PhQXe_ysAv +z3uSza;R=8br&kdFM*D`gDVg-ktDc;fTv^>NvX~i9 +z?o>mk7)RsCyRW51`_uEAm7XyguhXp4#nb9ao0g=n(NNa98*W02Q%b$0+E%&fb6z0r +z1*?2HZ<=I66q2I-0HEOH2#nBF7}BliX%ldovxlUflIc9m&N$f` +zi2-SZaMe=BfIA;~79~_(#=NywQthTa6Ds?w8W3b>R|!m7A*gXmK7iQ)?ep{dk<#F& +zY?8i}rzTu`fTTGk6I+gF5NwW7#s8lypa)112!doh)YOu7cz*;|*+uZzNTlN;Gc1*M +zV##)Ri1tKXE6MjLAwXD#0_z41@rzs;LKmZIzRJgzD5L;|_mDlq?t@XnmdU>^pEIIO +zN2^|;dGI{@6NYA|ykCmU?y9ANxXp6m$B^LQtwhc$qn8S3uFH{T8Z1f-gcg(rWn1iD +zxu3xuIYK7NdxQ7UufeEu}7p{PII7jk) +z3x=4~qD?ZlDDnn==Q^(H^XE;1rpuLvRC6dXRoJ@(hz*IPrwW3(55#iRIzqTJj-I4MjXTIW2w~xg=u4!Wq%*0*AfphP6-D&fZO!sto;;(r$-+uu!AUxB9%2wtr7l{4<8#pT3GnQ +zXdAf@b|xnB#kdX|%E;+?AUGHPTMEb0Fu5Vhcpx1L{RHVMgMaVU-t)%BLu@W^i_hUS +zbq;-a|B8ie2EyQ(FE;B)a!7H5)!Od;kR)&I$gxn{VI0qrZ)%_B|Iv&QL(^9bC|uCB5xm<*#xh(jgMZFz@Dij{UQX>GXFmY)^- +z)pllJzlDVfXB?*AjUx_DS+ug0xVW76HniR~EiL?hDve3fM{lQ2oS-0(Pm=a~xzQ9n +zp5Xs=K+9&~7ndGZPEWQx9!8r;Hllk-?N9Cbb8G8g4|_6mq@P~v!rdVS7b!MRdgmZ7 +z(Qg$VaTNh$dOJi6RZ?yW+=)cX{SdDfoewIHRIe%xPztICtdcV=(cLh|6q1o0tQF*) +zgOtxmw_H{6pajNR_RvRcBu)p7;a2bW+env%)?>k3Hnn`xN8FYNb;~sSyGUwYm+{oY +zpNO5uVsml;1XmCcHKTnFAb}olVxS}$b^z`@6bf1`3c&}r=n8l}PoKUiG2<_sVaWuE +zgld)_Ki^xs>4`1+Jg1!}A3N4aBvChbi*&t$CONo*oAEnD+1Z{|y|n)oZveMVg6;6I +zcfn!3^HZKj{98Rkld2ed5aWJ)daB5dt`(hZtUft~!n-gy{kNiTMA_X56+gZ`kkX7~ +zyt6K@rbfh!R)Dd)00E`!9(XTDeoG`jZNjd5tSw7R|(yP+;-lFzN>F#cM#Y +zT}*d~U`=Er8NNXls`#n5^o~l6^Yze7HG4FN$PNloVkymb$;+|?q%MUjlCH!h7gTJf +z1^N!*<3>%jDa5mN{<^f3qXz~**2-Nv)Z$XJBuYLoHdbY2d>Y^?Rq~KQQ14+UiGV3j +z9ekmKL|Rs9(&%H#HcP*(%s}|&Gq0(_mMFqUgbS+;w-ke=}*~%>?=J<)B$&fq*^ek(kaU%T)Aijr&-)dny~tO7rQcoa22&S +z8YKieF^eHP0hk_s;*c&U8mVE$SA?06GpPt}R``AGGv5MRQJeGzFi(vr<*w +zS5zAJv5h1+)K_|99|&I%0vd9e$cOJgC4+OLpu?=7fOh?TuaQL;`Lt8S#bP$T_?la7*Q +zh@bYipm5FXasBb;Jrtzrg{39b7g=qnqhP2VJiHwGWjle4?%-xz+2prN@ohz0l~m>6 +z)2B~&cX#jJVd+OGFo27feFMi!;#2D42pzkqsv3zkzfS|)9tHBvEG%M|6iw4U!o^d` +z5d5f)fWPExyu-2%LK_LsJ}{5>t(MmOO7^)IqGLeX+}o@E2T8;Fl@V}Swy#ziO*^kK +zRm%0R=6MA4%C6?e(h`Qj!H`Hz&d%k(w>ifGQM5uwLIDa3ARo4NPM2y|d%9z;^R|L1 +zJz(@Pi*Ab%mj+AX7*?LJj-*FX2=j4FXqX=2XYxE^FwL$UD*2Mg+7h+JF0b3kzw9I2 +z$vM;Sa*_Kw|J_wWgz&tlyH?zNziCs0!;Ge^M?zPOoNB6?bAIGFLVomL7PD0 +zVxM%vj(uw_jwslwGjqV*?i?Yfs?2^@+Hhuit-_=%m)bWlz;Y!MYL!z{U!SypP`Zl1 +zbrMlQHsYFP?6^Y1_S5jk-hID^Ep+c(y +zm1qOOg<7rEfkhO0;*QK+Jw<~Gn=PmLC7?C +zFC({<5SOvm8#_BisPUu&&#VFijY1!8(k9nrF%%&S%ieCRtc2%jx~NWA39C+gO-t-L +zq9#eCOub-zo%ZaHomHlRnY)X<_aF3My!D;dXE61Fe|4{N^f6a4un(a89z&8ffoor& +zO1wQIKRz_}ePExFksuQc1FB_Q=fMp$H-C +zS|OAz71pgRp +zZ&jMnDcMx}fQ^D)y$ME4kpJ0*QZ1mC<)TkKXMgQyn2z6e1CTpsVe=U(|7L)_M4DHO +zeFrzRj+wWoqjn+Ao{|2R;@$UENbuA#XAp`F4D^|9N(|pI!-)pk%()~K+Gv(wBCfte +zQ7L=pq6_MKK1cimzawvoxOzn%M%P_4NuX(*U<`I)1b50k+ln#fUmOoD8%alse@c9H +z&jgw#|J1tb`;Ls|JxH_rHv?>=!pBcJ`2>lHQjfSmXCpf9jB;D+>QTU#4YvBfzhUeFaXcMpJn0PK}vVDG5#4G?mD&Gr}9T5m~^ +zbLaGus>zVX*S|WxgB}O|L4SWgfN%k<9i4x%ZjsJBJL6}|Z4fCBB5$TBV|)1g^Us^4 +zjiYnecE#-=_3Ldlp`x2j&{OESXkRltRFOy4$WY=|*hT4f=*30bQJThTL@0qD(p0{= +zlRusBllRZmUBqKA;B;e$Q}y1#p_%}3m}ATL57Z#cZ%4sd-frqmst8d5;u(BnegZA08 +zth7{$hq1#(R!!^cK-(eoSzWeY=riN}0_X|-!^7=nqWk}`zdO&v_*cF-VU0eLT=eug +z=1htV$`^=F;j4vS{iJ1Sk*)jkT$Mm=_$I#3f`O6Qst>pe1JW3_Ro7e351t118IA)n +zEa4-o8b#9&kgb6aUa(urwu@ftLU1c!PM+UAsl)i~w;IwG=@&;|=2UJ5MJeZwDBZ57 +z%C3)yQxBo6BPJ0yLw^O+Wzs#j{`D)Dxcq|QHU0K$CUP#9V1To^ubyP`4LRLuSAj+6 +zJ>JCMU=LRghoQ^d<3jJJTREVxtp#eiM<|1wN%UaTVJ!KL2I6Uq3sdt +zTM@#FN5iK8#&JQ;Qm|nyu_b*zGfPI(<0+~e5o8CmrisGR(ugsBm6IAbV&hjeM@B}z +z7*q6xrOsx3oRc#O)JP8aWLMF3RsWUoEZ*MrDAxCWikpETP1?rvw4ZHr-s9^P7ZY6q +zVq#(-Y-D^sb71XN +zv0<6a5TxR|oPTvypTAx*A1#PwPon*ebPK$(3}`;Pie!sra7~(X4Q!o)sY!FQ`gh^$ +zy3XB2rgWdU?`O2$cryxt4a2~XSgZm|QN?^YRx-Y>zJ8z$(Uc2xz0_Ets7{ti<9EoO{90I`Nemf0gGNox +z$2#@3)*wJ;WeIW_CmSG34DUQUjTh_68{77u@zqC-H9TC8 +zRNyEUL!4On{Jrtn9`L9r$;FuB2{E{U^7Fugj_HI{AX#6~Om{N6q_kwt?D}nEP#gkY +zBk8o_h>u&Yob%O +zE?6+OkWmMQou)4k7?07zbrP>*V+i8yu?#h)ihRfv?g$;RIP1U=U^Mm+LhLdzIyo$~ +zwraFWvft~UTYfYm=ZWgLMb}2e0_~!ChbkYz24h*H)f`H5uXz~zuB=F3VK=^Z|GvzX +zLx5E+v36O>uL2|Y`iEDUfj~7k*-&F>di=*yo{P#d7_AI+P)qr~(>I({V2Y(vWD16_ +zHWvhwUNsYmEq)&doT@h(73rWL3)gbaq7T%#c5M^@m~}jgkL0uZ-}t|wTcsEJTqKd$ +zO+(N6HSkb~k7?ILI#GB+vz;os`Evy?!bZWrKiR2n +zc~#6M36Upo3t$s+gU$fSZfF>HRM0C*y5A~`-3?^A9d#kc&bf^2K?q|Xzal%ZdqKQK +zrS}czKM>6Mr>6Du*nSWWjuxfUJ$Wva;R&Qe6_+tG0nN=#AKVJUY&z|ri3}4VGp#D~ +zhe~O{ivkmmGh7jn_xYk=xiol+cnF%!ilAlGYTfsQMQC&HAe;z)aUty!Y$BkN>$|We +zWTEK#u-*us=e)rCogAmF24{-g-7Q~eh$ABz-<5&I +zEC}7e+8@kopz2JhpVZdKG6tm;fLu*O%i7Wcqu(}bE+kJK{6}Ixq}b{883;veF<~h{ +z007hKn(-AkrH0DNc%uSfzXfWrF@J1t4;)+!*Aik6qsoBQ9XM=2V!)`^o^P_71kO6J +z^njQH5-dQmakaCX2i_h0;F270^f3KU>GZr^=xtb)dGGH>!f&`4gO6!U$8uH#Qn?)` +zgFdV2swB1>bi?Di%Cfs`$+ajfA@HkYM7`SqjV^+}Rkw +z`%Q1`Oup2x0)GGqc@<-hA!p_{cGLuz!`cC*00K6E?ECb|NSTl004dkz(Ey+VphUym +zQ%B4K!v?rCSXQpf8?avBiG)2CaR1KpL;@cP5FsLQdR$D#XIJH6-HRIm!Uc0W=!tYP +z7p>WAA8R=BFbW&8M0Hp-c`=x@*vrc;F^6hF@-|F~#pi(v4@?1a`ibIJnx8Kpg!`)Q +zEmy!~%vKI&+b}5TlkQa93hlQ?QIa2{AJ4%bQAhuxpsfRN5wO#a1~U#f3sesly$^qS +zv$L~<6Xfr2)ljgZNID|jb`_Ma4za*qf!y~t1>V3Tu#|dLVqQ9J1ii@QBr(faQAGu` +zUtnkoHr1@5%>C-x#>)m`ad6_{DM9Nffa+u@Q|YuRkG553fjsKfZza5i& +z>CUAw=b%UDnsf@82i)xROMsn=rdAfwMD9NnNX6&*;oIP8#dblZqGKkU*llQF +z;0Z=mfayhC%Jc)Dg`X>|NpOJ!j2m@D9M{s+$f<2Nx-A4f6;xR*mqx +zZAoE9$D4MB3_MJP6z;F(!_)jtc8dJCy@R$y_-grL) +z2R@+~d){#BXyENtjXA=WMF=eCL@F>h@4%)sH{N;;?|m +zU5>t|kQ%Br4H}vt4?6?pc((`rNz68gYXk)at?zgO{(=J&gLAxh4~8@5oiOl3BgY5< +zS|NVXV{k4PIJ9$2-byTp0wnB{t(<(;+OOq`V4HLD@|#RYt4z&AW-*y(ZrDaR3h-)x +zha<)s3gHT(8^71TsUJrNKR~Z!u~H%r*9ZA61Nc>dP4;MLEGt`WI@)W3cx`XoN^@*D +z24z%GaInd1&C^*qIRKlu`RI{CTvr*Gx4OkTWAX|myhrp?LA!=tioQ44QK7D^4B|Z5 +zc1c~`w>j7U7Y2}#lH%pz@xe#_&$C1_w5z}lf#BoQ(^5A@qhLze+Ci*Gf4OgGC&nIj +zGE6)EH0TyI9v$uh!z-Vr0bD-69oxD?t5rjW=Sp_X;ctYZJOxCTV{js_wLFb9Dl%WA +z;RykkikFkqSD8vMNCXPqjeO=isTmnZKjD@iyS#$hSg&0iq0L@?fRbXrd(IW=T+{uR +zr<{iU!O=;@(_Sta9+ZLDWypbJV`D8X+#ndXeu^xtW%4^1J~I)5@c*L6K(-1T&Vr_dC2ns6W9I+@zmBx?g2}D>nGu@i~NA +zBxwOUDKOjmr*a8Lg9v#y=Gbq)2}uB4k*w*`DtF~WfUAPKYoWq&0~)l8L%2~$TPWq_ij$L&Fia5o +z4HAG5%bcVWLGbw*q=sfYtO~e!$;-3RP%bEuoN^dYMq?7WTVcq<`PBP<&67PnJ@5(u +zS^uvea6RrJdRdSxU^(93uU=kPUasE5Jk82*JGtm47U;x{n= +zgJv*47${~<;KOrzjwL>*7}{S@mIs*+@Qw{jQfM$Tm%|sS39KH&_9G)LZ`=U(_yL$! +z!P$U_HNse@=iN(!*qHfZd~gtO>c2L2d~TB30Iq}?f?eZ*S5xa0k=9+A?~({B_|&t8 +zDnD7DJ=e6;3#mEF82s0I05ZpD?_l$aP}F82x)yHf_w6@GiyeOXg4UEpxQj$UK!@_4 +z^cB((#9LTi022uu2Lhs;6?_|ezTo)kP}tK#mX&d+^AipF6>H`U`%CFfQY@2bcH +z`q;FTy$JNyEH<*{g@V}XeWex4~?YKGUQarj;GN;v?=+(WjV4p`A +z`~DqBK@6+|1~jwf2JoJQpY-^YigVw%f3WiN3&tJss%3s;2>wYkYhhay2C2+@!jPOCtb>K312M +zlOsP|1+%aKjV!=0!fSC;0s)?}(#M|FO9wJ=ZlTP9(jT-HRF5`P;r=wU2k>?OA`fei +z{rnTS%iADV3UvBBg81vR0dl{LGAT@pSFda`>)p%l$9Tv?8Uio$g*MG3z(@XdS8kK6 +z)Pbt8vlEv`_|M7;e0%3W_h}W5*5KgfH>30)bxz%MbBovJ;TeHa+E%V8KD!~pjQ|uJ +zxXu)ulSdFXFqfh1asa!)G@~Q@Hpd`&m&sx>pQ@KK{FbpZd{IYmag$S1PqWdHX9C&` +z?ACG#;#c#a&K7*twT!uYGAT*{jhdBFQ-CO-DEg0Ftr1jf;P`ae%JD_PGAkE97LO=u +z|NRJXb@I6&WCv{tCEgSCP%FkDDj#1l2*`kNZ)iAxl=1uby`&JZ8Q}*n5&!1Nwl*zT +zJYV#O%+SiD3aLZwWquI|J<)UzJ5}dkK`yo3iOntD#k`Uo(R2P{8;c;mMXTVUtel(% +zRn&)qW}=U!Mx~ui>(33}Oxac_lu`6l7)^2DQ&aeo;!a(PCqSa!@l@f9`uyor%g=+S +zO9O@A+lW)ds*|_Y1F;$mtJdMB#P&cL2#*Wm?QxLZ`I@AYL-vN{YAS*55(x398HmBx +zZk@u$iTCjf#o#2_&!qP9G=i%kmjvbl89NklP<2%TX8^R9U0gscA;TA0Jp4SJ=VCL! +zT`l{MDF|Q9VKLR$$Gjn_wk>xs{_6C>`s +z9zXV{0DnZ0xGsqOePKLkG)Yv&W7FQlgG*f#$JNs_Xh$|L>L53Qu;zVC{xqN#)b#8laQJ3C9K?#aP9v<&4-%zYWipCjcRVJMglBuEP;GJg?#s*?1p7TI? +zbF~;C8Q}Q`p9e?(#-UDc&%%(a5&dlpPxwiO?nd?c$X{;uF&jo)iec(%o?VwM#~sm$ +z-V|wrh4F*?0Q6o`IeT`i?#BVxWvNfXm;sJO&r-iC6kwpeFvowm8tlDW;Jpi$iF_A5 +zW}Ow`Yr(fa+_E~_>frYdP?X#__OORu9be?G+z2f{PQ)3dwo<kM +z8e#$<|-%MI~yRiz2^RskA>RFFEe>2@5&VH+8bg3?fPTgqrrB0(ai&FR1!a! +zp($&PF>R#ZFtma4I{JdR#Qpp+N8r=cjXSy3n8ox4Ae1an)eI;UaQAK6U>gpd5hyTF +z9JY$^n4N4&6z6vHGKsgDzk1m9J+YH4N#$sN0~VoguNr8)g!&79G88?S8bnL8K!C5Y +zB>R7vUw-_!bYC{vV8Bn?nXi^MD3KSi5dFa`cWktrwz1Ut;ExkCsd +z&@Jk6=HwM$diH&Ew1btba@ov`a=LlwKJX}tiQ`n48Kq$Xd$yK-Fst-iiGU%2y4sE) +z-@Dq-_uHrSpR!w(cuCd@2%QO2p3h^mJiT4z^y^X9AA`qmftLFq>6DIwY&ut0Wr#MZLAhR-0O)5h_ +z0!>$thG24nZ7Vl@_>1{jR`-ABQA0l1Rh_cal{m5UICS$S?d$Nzq<6EF4>HN_>Twuv +zekk4;n#C7>U{ehSNDW7ObeH&$K2J`WiO$Ktg9C@`}nXykM|W@8!BZ0$^fXKy_)!K +zW7O$hb12N)f@%1yB3!ks!C0xwp>n8C8ys|0ZG!(y|FMP~)jXCiRJ_PY7b?n2V{!2X +z`jcUextpWARW5y&G0i-8tSqF6*y0Dw0K3m(RYOmwIg?|E&dcr}ZOW633ScJ=%O8~0 +zic9S+T_2PQo;;AYyin6S=926gyOFv|`-Zq3FzFHY*vrh9<8H0Z`Oy-$!I!0JOhiZM +z80)2k$EO!A$||%_A`a=o<1E6H+1Pi=FZ(794Gy-3)n#P@A6)g1hnul#vKZAnRx{g_?@^o=1@@8?J>Uv@0%fX-SBpoUh +zTgU1$N4K8Qa}|b$*~sbb4+%0(5}X;@-Ck#_T%%&VL|v0`p)%>|5H-!#M +zZ)EO)v*+#p-TyY@6)8mw%#rm2dv~f^KnW-j5iBo>5 +zn|%Q#R+Mg3LYhscPQA5=xoy4K;&75kRyYCw6zw3EFH{W52pGP415XK@&&!~otJ7^K +zU~8N@1>xL?pf=GqiRA8B%zRO)B0ZD^d<$hXe|)g@`dO}s={KFq+D{|?^(r0*s16vG +zGoL@!yggd$fg@JGzI*3P9BQ) +z3A2N6l9<%4ZNEpESVK_Ik>f8JH)jn +z18YVYu1m7tyb{<?469D^JkCVdrC3b2aoq$-G}D2E{miNZG1dsl(*nxf!zLU +zYSB +zg`PY=+0UC71AC5_>fG}iP+Dr%wOJb{p2&hzm6d}Z7g9qn-(XBwmesY@a6);5uD)Vi +zS06fWOyaAmT*N6WL#b3FKMit`^~UelYU}n3Zu}{nwA0^gul#<+s3PWTh8T+6Gh~TK +ze5JP=gHHPI$~(>d2Hz)-ja%2Mg7n>FugEN|Kx3 +zdxVtx@gMZ4im{$Qz?Ybn9E6WwdE6u~oCP +zg;{o8U1~p0jLapgu+{hm&P2WDmQikXHSnCqen0wBr)&hZ@0_c#AMu%5(N6>VU-X9j +z{!@%(_k5y^4eq7cyjaqY^gGY(p)Zllk(jD!H`u*QCaf)`DSd97Bi8vN6zg^(mzgPY +zrlrtm2^|>3r1nBfAd8)@DfE{^c)7cWIBm&rCe5H;Q3aNmNoo|tMr-2lmz!Zx<_E@= +zYJAK$W-cC<_=*?Bm~@afbGzb9Xj}GJl1i@Ly()8|oz(f56dv>BN5geffiZn7bUpF)Z?e|Twrvh9_j>^D^;c{At!~&aBpJt +zD;eS_V5oX^5swBs2idLiE%YnRB0dfps$(P?Bp&ND9UJ_ClO<2MGMk~nY8 +zr+Uj_X;TGgbD3b^W|JN{#7OaTxQTdTk@@P-f<%{XomWVR8 +ze}Fa+Wq)E%ZGLG>=_QTp_4M(9^>#OQy%REhB~=kSr;Lo&9qdlJORcLsdFp+WSpDsW +z#0wa?m-Fa}r|Eyx4H7(`TPBCoTD%kD>$@F7`H#+m|MQ37XcyfbHNucSe^=pX*D5hL +zW}hJE1O$+g+3T4{|NXBP6_Tad@H9VVd7?)=tZr2YZQuTv6Fa`89ly54)A +zL(XqjrL#%m=cxw7Fk)fl_RexLluJGarDl@T&FJC4hg4|ShYz)XqIu(1R-9@ELGu`9 +z4I~2yi7{$DdREC<)IMiyR1p%fXWWSsXS+Cbqt%}gOFUJgd?>fm_o?gybJWntotx~v +z4pq+`vE|7(@%K|j%YcT_Wy@L&xFO>2OY?h_cUn%pa?KlC?Dp +zagkE&ZiM7?s|fLQZ=>)>^p+fX&Pd(??V!WLoUMo>`7U$0%UxR@C>sCuR8*YV5AC(f +zdC;TFQZ3`r4G%H&&U7*^1N*CWpIyf9Oy^qL@4@29LL0t!q2!yZ&8u;yanYQ_O7z*V +zz)bC{pTmU3TU+TTLbtOmvTjI?A!yH2yxvz*dz#0lxd0naEouKKc-iF%l?i$O1;pK7 +zkZFul4IsA3UU?rELBr9de)qP<9lyu{`g>~(vG+Jp$TPuQOkJrbYj3J)?Zj8A%oesd +zXa0h

31a1yqk>;<(f8MBa3@J9)y(5uC;p9FN=lt%)k~a^C2qWt|#Hv%olM-g7O% +zMS=Mu4BozM;U1y10Q|l8#DPx4;jxAaQYYF#Jn*QgzP=3slbe8}wY=kX2yub9-A#iMpA>`M^#oyEt3>)g`C|^E^AXs1N?tI`M +zTJuk+3$;^<$)>fU43ZQjdnPR_*g5fIize%SlI`?#OQ7t-mW%k4JS-GjVdx +zhUvAU;r+$;@mq}s;@edDlc54ja58GiV6_L+YNLV^T;xg}rQepQDCY~y$3in`Gu2sS +zaFOM=(wKI*WHLPQ6RiCHBlP7_U&+pFB%!PFM_sPV8>Ud#-$8Om*b%fsFX6=nT$Qj% +z8LOIwLCInn;Ws;PwUF3*ty@XZchBzH5cybhqg6RH$R2a7(5F)rrC&lx_L{6v{(L`7 +zLN;i{*Q+l^bb2D5@RD@)1+T?%n2s*#C*5u)$urq25(XbAh2j|+;tW#G``tuLt#y{o +zte)F^gP>R?DYLBkb$%JjiL@aqPOU$^gO0nWzWn0#2Sd`Ur8iea0xyNnytqdq`#$&s#mCd)^BcvU^+A`ouA$g^2s7&oZ( +zA~oFqFU$Rr>^rRcQah{2Qt7UaJ+Lt7o+E##+s;Nu?QK7xIc64lNywhU7^7PMdX#3$ +z@x1)HO)?kj=jIFygE9K-iJYRkPW&IkNjc;G7;oorcS{1sOF;Fxx9o%HyB<`9nO4Lx +zHU3g$!b*DUltBFhyCSw7g@p&&4X-1f8wV`uMZr#<7=o@Dwq}j1iFCi|->jBD;y{cW +z@u>XOD~PViPds4hruuss-_ID!-RD5`;;nT5B#T^GSYUp_>_4F^fl%Sadc8G~Iah7( +z!BAjjUkVE|0Dboda$>PV9C_Eh7)rl>ToSE>y_e2`fw^O%EyMkfH>NW@$I(f3;oGfI +zYkab`>N$-%4Rz^Zr(ZhyPoP7LG%Ln>enrgSbEJTHU3)T*YLX#ElaiTcEXk8#ncZ$9 +zi0D@TaMapAMdcEe>d{g4-y6;o%CQ@fH0gtjT6*m7n*n4UTcBm1awH#v`Yzxtb+!#UY}Rt@xZ? +z!oFf-YCK)FFip+wx8}?BWQe#Ldg*iWU+y;iNoX>X$S^7>5;yc%ltAX=r(WW#jC?6S +z?1lPfT~&8Zq>POdxp+-o?|cpbmK;o=RgojX00~y&DE7(i&frCAqKV4+C|W(b%vK^6 +zt8LvsWUBJc~ek6)BrSKVMB0OM87Qxy3Hp;k3~17>{Ha +jX9Oh6qq?-wmP>o8R-N-hBW>)K2>9q}8)?1PAo~3u+}f#? + +literal 65243 +zcmXtAcRbbK|G%zv?U8Zq%_ZX+>5{z(A%u);k0d)Qd+#kPn~Mti(=T(1Z~Hw;(*q|H;@R%_4;ubEwfW~KTRiF1 +z>MPr`yf4rG(W&(?K(3%#gdu6kqh|N7f0v2LEozucLA!M$_*-9D6FPN6IxJFn+`DV3 +zepbiCq;I(qk@$E)H1F>8n?3*WK2e6GtI&P#&Ti|*a)d`maMzMY$3rYK60_pnIU_aE +zBCI!UTAx$xT37dO$-~5i0_)jnDVmp5v-aTFRqjJ*-_!qIaEBoY7t*W6TfY0Q95H0q +zJiYT~Vb7zZ%c8-*t9W>Qe*di5?8Byael-(ioXGgMJ%5FgkI3W+r)iH4bJC85hTXp& +z9b^PhkB&m(V_ZlS2HmyvdhU^liOBd7E(C)%n3h^-r@(&lE4Bge>%Q^ULn3f7j{7 +zRd=3i!MoQiv6!S_xfi&QNh7hm@zbEavx~r(O>gjUehTU)vsa-{%)f;8J)j$E5zZTT +zTxgfeud6%i3n{Cs8{f<RJ&Zu@}PmAN(_V2=7?D;<` +z_~F!Q-eB7P*oWEJWY%w~{qaJ(BZc|Byz#b$y#RA-QtZkdT;#to#_l%Pf`aO1k5|(7 +zM(#By%icTayM2DJPI=p`7p>{|F+kf|WBSdKhk)XE`)I_5E_#aGt>$Ei-x4ge2R`dAc)jb*{MDEt-DYt2;L5$pwZOgU +zS5*ub;XHO@VPYoJ)advu@<=H30@V!%i1u|BQ~=^I|hG%&@A7f$@Wx^`;CD9M-! +z|1BdVj#8G!U&m6kU_zq08KuX@Y1JH}#P74-T7AFgztAqy#hr^KI=;tBrjSnYgYoe3 +zQB>c&pZ|=M9xnJry8K_is4#ns_oq;MObe#F|KD_^c~Bse>DIp%^mP(pupE1!cyHY1 +zx`91ra1QJzoG5HmW|P%jn&ppbF9+G5i!1BKj^%xyScaq_w>CS*Ln)N?pET^7<$auf +z`x0R7*z8bZ|U)PG~cLpZE+AT@1{@seHajlL8Dk1 +zY6ghLB_2z&Sj|z1z>|q`U8R_zs{C0AAGg-A&1iK)7@nErMTeO%uR{|CMHRZ^(SaXu +zL}+V94N-i%u-6~nwUm16a+yK+AK3EtZ~?~ptS7k?KLYUJLs3V4Etp)#ow%Emkz=Vk +z(J1n&5d1sC7#e|(9MDW#_^Z^lOPUeR8a280*Sjmi-5if<5Mv%4l6qNZiyj^Iv!qW6 +z3`mKhK-W@YD)p5vjNrnqBE_oe+&HNZa3S!UT?0SG7|6tJR-Pf@C%6z$M`!ZnDFKa2 +zoK5rYUuC52d#saEm}6J{yTB1#-rvghv^3+s#H_k$eUgvng!*ork^ZE+^P^;tet|OC +z@!6mPy*kb>s#$T~VjlfRS4C`#?WXOM4eI#eT#EP0i7blA+?Qf~h9BbZ-8Z3kw_A`d +zOFdh5mmc4wW#Nk_io%=*>5VuXgQ2q+nSYWy$KSYP4Oo{4z$MovsT#dDf6~|=}_ay@1uu< +zM#>>Am^jhmV@$OfWxv9u4L98`kK*Y9Mecnp%NWu4a#GH542l3_4yV`$jcCL0^8868 +zbsr7c52`KWxl>g#ryO(Bh+yl+ybZGzDT90p&_O{_f?h>#h8(>rBfNo%!jzUHo}(C& +z8?ombp8IFPSR^_2>z+U8$FjwC!yCQAJPf~%angkpNllib^JvS0?l$*>e~y^A$)YE@ +zT0(^a%lxJuY^5vzzN15pnr6!gTfeMX;ZDsCJUVVrUH*H6Ch1>u1C?^LSVVNBl^a_l +z_XcgrjiDv;?^=3(>MnheLb%RlBCv4XCk)4KY9G}9>tpzJ7@#|yom@0*9|cb5KH(6C +zD7eQO*S>7lvj;~X=lpYfvfP^!(hd>ah0G}ZY;#c#^(56<1hTUWxhD-&|)ciSapo+o_7bk2IkdrK+kty +zSt|sclpagkaK#iXx_f!QOe8Hel{+JTVUImUWT31>06FdDf8}R +zP0?s}UuYM|8ntVF{&DM46gIBQfBb8{)mVr=X~?M7m^;J3q;1LLscbPWwPw{@6XcNYHSg +ze2d3!m@a>(tj-O^I=OW`>hO90419Vta{DmAw0<@~E|$FH<5tDg%Z0s`lggXTX0ObI +z8IsgnO#JPd%?{eY*2So_KL&8fy76}51lUE{V(?>ote?oSV+9JUnUaP$n=y9bxCtk0 +z?uV`8t56OY0T}kR#sFY|moTTqVnL(0+8k$$_sAR1(c+cJ*Og;`U^2UZrpcY*i2`ev +zz*9f#)@i9OUhcQYQ>GJGqTU)?Pw260Q6rt#Oc-3)GYvlek@9%q +z)78Qr!)K+>!p-&(ym6HIHfcNqt~d5pwzW0ppD0AA>NrL!_0GFDse9koRb)?VXd@cohnU?2ludCu)%7Ud^;qt4zKw=;UPv +zS~b&&`0DJcK9(OH)bAhT<<5vD2Gbc{I&hhVjcsPv% +zoQ0qsP=LSQjc*p{^0z;Z!`gl*jsc?y;1?aD7bP<#sJ>RM +z(q^J;IP|Mkv*;1`ky7ccYt}Q3*irMT`3EDuFU+6U+k@%S! +zcLdF&0%;b^ETR7ZXkZ(MmBJvV!sgC|tVGJl8}t&+FUzVSqx3{cd9UO6bMa +zwS$B>IS+dpK6oZvfSiYPA*ggsP0i50ux2yx!YP+ZS7sUdZSvPC6#!Zv66~JJ(k9R) +z4Y^2-Y5H|pVboZ8phEmN-@6s?KPT#<`OV0?90szyaSgjjO +z%M4&!t(KyKe~%)J%uaD3xsDS~lE|dxeSmZ!SO2$LZD_p)$GQ=2S1@Q#$_3CdBwECqVX=>8bPO1_1UR4|Kk>tzF2>2 +zeK_rZ4AjS`0-?j7HM;3-bn4(`eh7+d5Y*ZMoEHw}mPEc5!RjGx0zubv0FDv}#1vU6 +z=M_Ck4T?nYuD}ShZWM5kSQKjPR}ss*n_F%v`tSOz@88e*#a(CXc&lO(!~=;~Zc^MH$4x2m4tvq=TS +zPM4*qnbO<)5Eg&kqMFFN65+8LX4e6nmJmD9t9K1 +zqr*!8GG%~Jn~d#D8(!D1X|-rDQ`Sn><-d`l5lF=Sy4p2IXLGl)FZ9nZrm+`sad9;@ +zHJ~NAwFP)L9ojXoz*_FPcpN;wob&!F{z`wW8e-CmW^=EBRpJ;9@OXj!BQzU +z5v+(J%=P)opt9^ocy?kLTImu;_Y8hkOvP_x8j;t$h{4*Exeh^ZF{glLQ>-7{!|p12 +z^YiX0QB*`ZqRe3X3_iO2BWD6(WuOIICesgOp +znBd1#pMHZz!eIo~-2pTy8k!a0;ObNv0W>;zo0ZZWOx@g%TiQLIBw&Z63u(N-ys9z^ +z{PSymY6|eutWkmo?r;sEoS^H=z)nj*!)D#urd$ANU-djcIg!fOeZSs3yq+**cNkDq +znSBE0D=y@>e^=J1gGByGP|tuH*AVC=MMNLiHgr|^l=ILZ6Na(#`o#gAmTr9)OZ)wd +zkz*@^R{Ak!J_O>zH~x&hQ0Jz3p>3?C@+;#=iRI<|dr( +z6Fgz<2~jASa2nr~&{qKXASy@52O?;qyU!wA5#iRMY_wNCFCP~hA4ZysvU)xsQ9_`PBA^MeYUWETKxwJBch+*7e= +zF0SM0SqalFs!D`h5hT#S2sll(;t5}AuX0ht0(z`5%9(@_E3sIv{G0i|gL-1S#L4m7 +z8;yl9IG`H<@s8n=PdG4678)fNdy +zSCk&Al&zcwY4@%oN)3d^K~?Se%7S*g?iIcTIvizOV)>w5Gr)_aF#$1vO<9Wmk448N +z@Uqo>N*Jg6ECuAAtLwu6%f`8jD}~UEp^b1OiJBQa73fJ*#jC=-cwqv2P}_TAVK}lw +z))uH1-{}oEVcOW+g%mGvNc;Es)cWTvmf`}ba?hVXmdPQ1(J!S3p_x$>AK3H;Z|o~u +zJn8_JSfS)Bs7Lr|$HL=|1#m(DF>;ceoszybG666cR8@vYP%6`nj?{=OW_%wH| +zyxT1FYVPmFafEWtIi;C9YKIDsgCjvLC5+f1K4krcE&#)P$Pw>G{J(yNc528F6lge2 +ze95z~4?`$X3lFJACxX=9Pq(>v?y>q|>)j$yAjsK*Se +zdC6sTxFNs97?Kjy>^d!_3-#)XX70vfZBeYE;HRo^F{hB0^TtB;N&zV#5=sg)Wz{A( +zag%HR^Ly#e6inxjh)Ip=(cg4Fu1bvG_PZBayqxwJ{*eb5{^=cKH$l%c;oJH~O1EBJ +zIkj>z0NxZJXD!SC8p=m`R!Yo=aQp!{A0y=}TR14~9G$~^i4}dyH)U8UWr)FS&l+Xr +z;Lzlzq2%WHzUPnm{))elCTXbusVCc#2jc^;&`{85!4R#V{duNacGOpS+?E1Lmv8LDaQ3pD8ZC=`J +z1TtyIS7-8@i_}4hFKYiv(>Cf6)8HA$EHH+(XYPp>RR +z6@&li`Z=VZ2C=XZ|d% +zjh60338`rq3HzJ>Ob4l8AnqQL3>C#clrm +zTfniArCRn0U@OWv@MI4LZ-Q|*Jw1JV>~m1-T5uKmZ)b;ORpFB+ofxeSM7xv;E%6Aj +zem?{Yd!879dTU;Y=xfNq5AT9oK?}i%H-SxWOy<<+%0Gl7Q=FtI;I@pBh1T-=rC}^yaKLLtQ +z1jT#Dst|TvH0n^gOdJ*QdUwY+2*sM&V0+a~GfcKh+$|g0JLS@kTu&(j>-Gm6-qWDZ +zDnJ^^3UQ571sIK*B0z)KZX9`by%2G-USAf9_ehwiCJ( +zjSl@|&eyE&kx5`kyVLga!O2@3K%e~(6YV9%9D}v>pKE_?WWqj)Bq!Ki!)eQMNgSr| +zW`BGk-__S=(_jj!=oiI#`Mmq&mJh9D-uSJOkC=LZt@3qasmhd&PEP13<0!EGYLu#0 +zytK-l5qi(7!6X=72W8A7ZEPtMmHb +zp(qMru{^mh#X(0|8OTQ!m{ZiW3518M`rqZ~@WC8V>Y0i2?q7C%n~;D!QO1Eu-)y$= +zY{L=A627v8e5o2dr04HmtA=LSsaF`HVR5mH)yZY3D|OL4vL2f<1F&DH=RgKwPqS4I +zfPk9aKYQ4~FvgWGt(opgO&ND1f#7b3r6~Bb&6HWU)8mhd59&=C=f)$z8ahNpE0)u{ +ziw@Sj-PGmBK8!L3rxzYM!*Ru|TkgYKjJ3IqPOpKRfG2_=2{#z=1iQphk5i&a9slBiOYBT(+v|9lPd{ +zsUOil^)+K)GU!?`Y067L3rLk4f+RA5(tNWuU2_k-N#aJeEA0|jPegUrX!JBmUaE5} +z%w8}0W(;}RwH6^CbBbu*cw8K@uWhd5v%e><(uFxXRdbCtKqkS3eBbe1ks^@EQfp#H +zkkhLJ{4(#JtE3vyXM&U`!cuAeOGM|wsm!h +z%j28gF)En#!*I28?C&)!O?!q6px_G&3rik(qYjgkljuxs#TB+PT|DN?@>NfmrWmbm +z-*TA0f38lImb+UUa|Wt#Vy#iDz}ya2p~jt|Qw2MYcVDTI(u>Mda#MXAetR%P#dpR@JGLPIz>WgMtKP@zEns$nLLd7&5<8W@=Ha(#8R +zYqn@Y`e}8{3FGHY63~|2<1?1u4YR~`fj|5*&iF_&M6pIGa#yRy7%x!`wj218S +zLPKIAb%pCc{tLj(b51P;(5Q_0cVh?a1{n7zE)8e!P6%c$HDDevQx5r*R5KUTV?V=JC6r)e2EOiH|1z +z9u=j6;v}bm9cH!jIHze;WWS!@2O!-=%3zMW4xsHSBSApYN}! +zYtZ);LioLe6w;)T_4V~ewFHFX>}d}hzWB-lU3zJc3vySEcoJ&h#!PFUyEfPB;N}1X&x~lyHQjssP6L@~FTGK^Hk{ +zm*)BzF9eaOa{2Dm?%b&tAu}TY-j!Uh<$h*9Nb3xkR)q#I7lXE;4=@ +z3@o66#i?>Wk}d>3Z~$5wFg<{Gqa{`dT__so?ponVXDjV`#}Y!GH8wU*^W~G{0C!YX?RpNEkk5_-uFv*%Jid+?VSxp^W&QtW0VFaU +zl1ie|`!#Hd4iAIC;M0@Z`*_K(N{yRIc2 +zve>nFQULPN$kKSdIU)rn>K8gyrGJ0#?Q;?*9`x2dB{}M2!pw9A;8pxr#JJhn*@D +zj2*kl0 +zKIpCP2PYZ0N-6gSglITa)1m~|Btpf$*yDk32WA?@s2Gp+RC&N4_=DDL>Qy8`tzp{d)j*W$QEB|;Zs^AkrS^_@0H_@3CCz4o>t1xobgsndXi+?p#OFj=ruBY4 +zKF6EmdDe~2=B852B6OtxNmGEFMQm~!jX}^);+5c{4j+PRw%Cjerr)f3e%(J)A9$`) +zmCnWab=Oz6b)K9Cv$^Rg#Z2#YlTcxD!bJ+|T{G$@E9Gt+O3cKJCHiwjJRt#+lpnK+G5CL+YdexaAP +zG!oXzR4G$3r{h_NH%nC}IKZUZd1*-WFMxM_0;-UY^mhlfY#HEzql +zi-H9Z!q$0V5^_o+(|B%Dju9O|Z%ab|CY-SSq_JkM;+G=ZeAuz@EHv~QwBgU6G@@1P +z!q@aklPY5nx!?Ar)enKb9}=RAiK@UZAGbP!T0eyMKSa=hHcu{YlpfTh +ze@F^}J+G;vF{JA(|8sS=oP`S?FqE`yf#xJU#Guo!kw&&(pv}Ng35VD|HPl2?z@-Kl +zS5-OPIoR1f)ud(%tMhgF!AG^tNo0u02Bwy`N;MTW8MlT7)I_ZB^0SN7WvC+V_T(od +zc>y`{RwOi82MI5la5@dT+7J78r&d7lew9%~5fCC*Jp=ldRn@vIUxz6CTN_FORm>b@ +z+i7WSV{`w$vWZG>sZ8;gqlX4AniW$4a;f(}I7nZ6lqejBTkd$%HUzQC{ +zZj2AcPco2Q+1c4G8W^rE4YR#Fg)J21KIMtoeA{dPbA5HuBRQEm?TnIqU#eb7tINis +z)@$A9C<=XXgN@wuZtbHs3&Yyt2`6i3X3l1RDduOF=gp?|n2}FAd|21;-vP!iLy$P9 +z)>_kgl?~Dq^>4=~Cxd^w0}fT0^X3rFsQcH`CmIbfb}%{1ZWzfFz&~z +z8*Ar^Mzk4FZn|jKvScksU0)`!J)-c`2Q|}y0RccP{C2h+mUe@4i^x;wpYV +zT}z?3BSJ(a>ap*L4RgwSr&iE!|08_w-bJ4Db#+xJCMN=Sgs`FiuZqp`(h|TZ(@yc- +zKk6HMgAUgStBFF@+@L{eYTR2}TT(B`_#pmSZxr&zfsfNdBupSS(ASdWUSkUfDTi4% +zF9*O0p5u?=%g~}Gk;%qFgbVlR0BAT3vU0l*v9+F%(hDLfn5h0UaeF!ajmu=b4(ZEu +zcvIIU2=~+#jylk8L25Pp@ob``GrZ}AZhdP-wKjRx&n9|&sHms_w7#N(XKbm7`1u_> +zy@h--K#@WF15Q=Ef8IDB8#k!_^$Xy3q_26uf7HfYC10TF-MP54Be)11eDYuJZFkm< +zelAnLW-9l*h(>o%Y=;T>_(fVMtD|6JVE=OTP?{wqQ$BKSvtYeNx)ngRQ}X+xgB3`SOQNLmHWBh{#I<3o! +z2Y`>j1uH!locQ^U@>sb40QpLZ1Ly`T@~je8)*-0RG{$wv`9qX7NZJ0H^ +zC54E3otw>4yB|E?-{)x?=8#xRxR&I--f)k#1+>Gh +zO-G$UUPF%EIT4>}%tZ<~nSk#VP8e;N79HMHqh^o+d?=121knv_>D9o2RZlQ29V9B_ +z2k$Ut>FO~|mSnjtwEySxl)keodHEW9@oA2zYr^X|Kn^4gNp8=(GmN5oiwR2lfHelR +z28Xjm$>ri4?z?4rR4tKZj;H@QYEfi}HekpB#BC|s;ZtDA$;A1xERZS?uJa^)6zce2 +z+XU7e2tFv2wPIS7BuJu9NQhXbqqPi8+NO7A+-@F*-PHl<8vw>OA8!bgOiRt=*Kb(aZ +zG}GYvtyTE$#r4HLy{06Y8c@Xo;I-eN4OaTZw_BN9UVW9F{*mCOWec>UZ}_kq<#di> +zYEwY20Otv)4jauIGEbjAMX{z0M_scRQIoLhe`tTKBl`8tB}t6Rg9i_Q_vZheCv|we +z@88wFF9a*OvNz9y@}Ck{b{HVcyse7l8sn{@)3gxHn~Fb_Lx_Tg{BB8938Y!Xng27{ +z{Xk?D)>+o06@BhEV^(X4y9yP05Dy3Tgun|WEC?&it8rs;X-xE{dCRyL_2+!y7^&#s8_Jh#>#4Hx}Sz$ +zz +znd)1-UHMM(9+4bRpuht>zPdUf@**n3OJ<|;SBicE8fqroZYEsX64Np~WVokYWrW=C +zCdrrGS1pF;!f&g7^9L0VsX$G6bN~m{^*7HQbT8{78RYpQT_}(QP3lb?{tBM}b>umr +zak3U(HDQp+;3$~U*VjNyG@u3t66`vN{jxHW=K4}5zTY|?TK5u92GPx@Pl*T1+Nfg) +z3F#@B{OA}!9^i>I%ePd}!ENE#Rp6Pdg@%h2S?mpSgbgl97KIZz^ZK*;G|rJl2v=O0 +z2`{wcLecWdl(fxD9yT^Mk|cz`CjM}ifEWoU8!Me*NRM??fbG)DeVqkPP12@t(`RBu>-x`Of7Gk-_e}m8{dZ|-`JOi +z|F&pw(vz+L-_GpJDK%9>?9F8CYY(B#2VGR{q8E37`xBymN&$%DI$Z8l) +z%y6A+WTa5yY*9YE&b6@m%#cR;-T;@qTO}WzYQ{-<2sAhAt5I9j1Vg9UImi}j0@tTG|{@r1Sf+jm(+cS1T(gJ2)6P11%*}La* +z2bAt4(kZ>vnGC*~+N{{BAPf;ULNZa^FdIaXrkTPh4FM0BqEc;Je}z8UzA`CF_!1AR +z^obObotN9ZG1NI3r{E#DZ%+V3>%Ty!@0YWnNk^&!)I!J_C4*8>0O}<2RgX0l5k<*KC&vgD(!s9-|+8$@DcB3y9VSC)^8fi!Y?Ac>~G@{Gial9_;@Pmb!1qBFG +z_4K#wnt^!_m=rJqCZNV_WS9?$b?w?W6A!cH!K~=(z!a!s|hFB8YuChbDUP8c3*xrWqAhnT>FRw!TEJddV8I#n1k^<%Yt5}Lm$lKxk_o5!L=3lB^ +zq3wpMzs`a!%w&|pY5()J(J)w@g#$N;FK&?MyhPbikve4dgxeeLa;*x`nNQBxva%_- +z^)2(<-YWI{)d_@I#+f_!Z$+v+EaqAkG1;8S#JaucGk5(zm%DSNw +zs$|n4`HQ&do;-f7pi~(mrgJm>pOAhqS*-vaKRH!PBDf2p8-d6F_jxtA*I@YJYkRRy +z6@q=5FzR!$cVlJs43)9-dx~WEE2dgxv?u|kyPVzq%edr`3jeqT9^|7i+_(*A>`FQb +zJNXc}Zt?*cl|e*Qp{fLC4el%XXLDAvP}-jWZdUL2&ow2b3%Dc6h`-oNNQPm3{h#w} +zPy+{=PRBn@11(!@WR?3IS`o>P_rV>NH39C^ppoerLB=1_CB31L9*G~O0(hK3TMQL@sTZ$)>uB?09O_%eScvr-+Nae4xMCYdyGON +z7(WM-d5HI6ah5*Q*bW@kODs?HO78d +zagYOv7f@Z(?quf9;uhaf-1GItth;KxhxZV*O!*ai>IB4z_}G~ray6L=i^ +z*qJpF6?8yD1TMr-529HKMnL($>w2mCX@YnGB+Wp+tkdAqE(XMxF!lt{ue1^>K{Ege +zRzVGJ3tldEa-RX6HJ=?9!k&Mp-qqZ+)>uU~l1B0-_2cZh-JuF +zow;QvbpI*6B#M}9hw0k>M77GAn@S7#@#t;=BJF+pG{|0Pi~xEu7@p#AaIVj^LuR%11&y+m5l +z7_?VR%8iCwqz+QE2Dow~q6=zobSXI&zy+W!0(}k@rZe~ELflkeLTW^25&t)%F!nxI +zrEHP4DmDaUj2V)&0_mJjs$C1B-7F)wjo`qKyIoZF)lIq(#7`NLfUf)rpF16#f&4GA +z{>+m}8@(0{+<2uXYnPXD8ComRBI8h6OfF|CXY?T&sI3G#M_zd`JrsH^lp>AN;L>$%E(|68s;8p-D#Xl8t0QAuEr~&UIPlKmDC2Eek6IO6l5Tm +zmm-4f#ic>`l3N?F;PU{=EcR)p`&wx%#Pw;aSg>}c0K!SO_16Gxfnx1_`xZ@J417ae +z$Q$~p?=UJb|NNYTggpYKn5R-3P`A}`#vR?7>wHMA&`70b!VYpwDjaq{!e>@WggIr+ +ziH3RFS%X^HKwyii3?;vhpqfV`IVp(1(yz=!z9!q^ +z^Y(*f@zg*Pb0skbH11RD4n0`@cm1?La?`eD{uj_50A!u~1QQNzonKsD#?KKf^7I(-c^L|_ +z|IvnTS>x%ZcY>oxMx9zKxj^K5D_K>e3eZNNGq`x$N`IN3XUabH?hFYDQL~Mw+8U(R +zo8Je%H_|lw5XAm{Jjyk~v<_2z>Exx6)`@4|o-RMroUgPL<@t6;UOtA!{ww+T;J$_y +zVH+9#$}#TKsXfEPt)sxVG$kL2ebrja>x6s)O-wfbWP#z||NUF%z$y@hjq^wNRwm39 +zT)9n($U0wks|+bg0T@>jc8yzI#ryh!PQkqg^djyU2XNyM=wT@uQAe!FEFa0=&G@nH +zb&O1ZCCM8n{9G-iy?c$t;{T#|jCGJm5aMB_1bB7GE<$AB%5V~->zlq9=ntL(qk}D( +zLCNB^HgUR<4?!Sdc7dgB>yifuYb%s!%G^wJ`VY=hJLTvQ_E0|UM`CZx-dS`&!g*(T +z?tuf35^v9fLk!(z=R}oJK9plv4g>R2B7gbn_fw#{NxXwQ-?fMJG{#C6hHpQpSL@ +z4L0O?68@yKkXFY6AEBlh2|b8YcCtpYgs-SdIVXPxxi!-WZyW$|{__4bkfhfP+XO|? +zRMqzJ8aKX^iA&U}6jlBCF~LFuhkPNW>30mR|&i#RUP@~sd(o6e`TId`ufQ3$3Lw6mfil=G2(AbZ+ng+*=?1FP_dv_Bm@Vg2ah3U;F*%E>cz35V+p*A@J&l2%ky(hKqQ;z +zR5tG(+ht^u^Ge$dc&#H^ej56pBXf26!3V@ViQawRGex0`<-E&l`M)Ut{?3l;-eO^5 +zyR{)*K|Gon48+z)WqYN*Knejs)4l>ONOpSnCbc{@!F@Z5Nb?uAJ=Tw&eD5xEQ+}FG +zAak8bsl81$(WyZEz(6#wc8gkW!w%@A(1~gk_I=X|pcNepdf$lKG$PW1A0c)g6@2mN +zaHXv7OzR;hfTFdIEJoK3?t*&^5SVA;0@DxfhJIt^Z7wr#nR81a-M>puGV|lsI_vaj +z%rm_7uaOB_gmb%o3MFC3KR~V)?~RK28Mv-;5lrVcD7bNxl`&fU;P6P%-@M%fn)r?9$##v`sggcryl|?84Kj~U_hf+o{koVCr2HYb=ad`ji +zku1to5U`|}LW490B;yo)t(+M+9uw7BN-Yk6g_Y=-YBj2%2Z%{BG{Q@Tk +zH-jB)qB8+rV~PsFqfQ*jPZj5ST8rf_;;G;(?t1$+Tu+4*D!?-iy%{%2+e6xhn{`w7 +zg2h7uwI!;rP8-9PWTwNs#{Xg{Fm!cJtxWRHgNoCgzKsTm{uiGH+AJC_C$F}XNqH#Z +z2ILhKoD3nBiRJ0n>xtSs;V}?&Igv9ggMwJ!kgk$gm#Y%epTJM~xG0IT3?J{A9KECQ +z9y%BQtVmpoz1?q}JfMP7nSm2~IAZ3)p)L-yZCc(Zu|??8ZRy_}edda&nuz8N-PdJO +zh3ck4OcvBnZk|G{hQ;+Z{i6c5d_U?}K=jPZHN^ +zQs(jce=g*^+18xpq?tp$Fvgk(AT02vH-vQQ6^GXLANp +z8?}vo@c`GnarM!n0gjC|wSugS~a03OGpEdi< +z!JXT@3(n^``v}8Jac?iHxz6bE^+T8CXJ>5Bv)uYXTxY{E4KUK=o9ps|NTmX$YeT%v +z5KlsCAB}^6I-gGY0k(cJ4UJUWg+JF9U)cXY3jhKpS65fIs%x{evtU~HKZ~_(TI+X` +zDt-65f^xWuk(BU=bYn%qnU27nNW|B7Xy=`Ns**l*xx5ZY%plI01)*A}cpmvu;1Rdu +zPyenq3ksTB?;4-Hn$Tr2}$5>}i@8Ao>*_CZO7{1CllF$VQ!X^h-!6k;AH&XcaVa)r^{Id2tb` +zN7)#OOtV@g*ExKmN?>b{rqn#x^8tp$)yAT+22k~t_UI#O5A +znm{ZHmhn~2J0vvIA?j=F{FHgJ0IwvzaaVCtDSZudkdKdQOgJI9$M2r@dvP+F9sf*4 +zPF3cOU+f_l8Wy86<&w=;I$R{gWw`|SzX>C={3rYVKek5Mmj-0ua;$fnv5-lvvBBZ0 +z`g7X5cXNu|UsW2_BArdm`t@tDekf|X#l!x9!oz?M6N5!RboqS%-+Ib*cY~2lR_^_f +ziY_!q`P$(P*zVXOk?68FAMYtg@dN`&5bOOiNXQ +zlqf#7pSbBvs|RT2P@crWZnjy%4RVyN;IN@}w5i=h{%hsU=g4Gg@*1)|Amq*e7Z?Zm +zk1il+xjpoS9DqE2@;pAKAZJN&=|n<|O;DnF|@D`J_{FZLSlefLSvCoH=fjI;x4?*?Z{*)LinN4CV +zTxI&d>#ZOOr0ps0^51{%F$?a2W;7ehMNnv5uby4(Y~W#eysDC;FsuEpzhv&*!OkcV +zz2a1T#F?OU`+)aApnSkKC-9E-4dr+(J%lIlnn!aqXEJH1Y46jJA?b{#r3zX|O73py +zxcy{6y921~MfL!DM}icOVNDzNIN%Yav0dH#uRQ +zs)~j8SU93GTZ<$_)kQBjfA7Qh|D)-w!=m24E>1~z +zNlTZ2bc1wvNlSN!bazUZfOJZSba!`mH^`+V-{bFj-ueG}XNK>bv-jF-eRiQwdL)PX +z2MN#R#uyQl`tC|Bb70B?`hNJrKl3CDcHfbb|A?@tpsLOE?AAyZY4i>@3W`a?;Bj!@ +zI3}5t$kgwPtUn9Y%iv8PA8FtrNJ~xyVbp6g7AW#_{&~H=#`J`A +zP}rdj$y&FQtQk7|k4);oS_WH*oj*B`b|@>YQPMKuiv;KeBBWv(sUpe6;8q*sDKN|8 +z+kp3%fH*wqDDkR2SW#0ksr2+V1H|Ux+x<<9?kw2J3yY9q)Z*wV({2`xpc6{KKkpdd +z9~c&RpJ!CXlj@0H-jt8@&`W~FhhPlmF#(vuhqy}VymHS576V2#q~FQorp}P?rOyrp +zAT885Kmu;Gc@`rQ!snyk5pl?UXhHuDnGW~v1EJbfOJ!Ym*B4B;6;ojUN?pV_x%&Gs +z8RGnjI{&1L9Q|kBF948%U}AvO!%2g;1Eo2;KP*u`_Iyh=fNxF^7fHfPEEg)& +z;CKwL$UwAutFM}y`-{5z<>jTcA5h=Y$#~c?$*JWnFE=~GOy9w(mh5;k-{FN}MfFSF +zaZOa@O8pMjF)T0n?{tC@UiUNX&i)gcj({nv3a~x*XicEcAxpviX0SzPN<9UsJr`S1 +zBes;&*H`@>=91**&Z~M%t*Ojw3QdyJ{?%=q?cJ%=A4SrInD?lB-A-C5ILNTV2t<;z +z>=f}spnJx*@A>qug{_C+C*>bd+fTq)DWHOS4@Md$5V$SR!V*&#fkqmA7r>Y!B2Jv) +z4L-8Prr(r*xU&zhF~d!)v}tNE7>AU +z!1yT2{F#C7cLuXc$^k+=Mb9m3c8u?i1GgMEoR#5zP`8lR{ROelS?!<@-Vx@rpiOAF +zy>LNVL**%Q8|<}zJwl>Qr|qgm_wwzq3AwTT&?>i2^v5`t>|i}a95K?3lZOX9Wh8~@ +zI7eZ-2FM<&iBiN +z;soB*VgT(EY6&?X6#2(i*!+O%j3IzJT@KT~i^@U&jAgq>yJBN~eOs6ZT?i4wZNiN0 +ze7)5T7)U8#Z^L~Fl5%-P}mn@swFkC5IDlqO$w4iy|8IE3&6 +zhd}1UrINy!c~#X_ZZWPXJ%_4pALD_1*@HkQt%O%hFb74ni%Jy-J84FrK7@kQaG)-2tYo_$|>($=eQ6idWxS3vUCCf_iC8 +z^V+}XP~;1Eko55UEu#!$N2kz%FknURzPxun1H=9%v#hS0>wQ^DoN8=DXyneP3%-dc +zWGSkwL%MF=aOr?rO%qad()&RKzJt=PY~Ke=9nXQ> +za?MBJZxa79es6w&~;3KpGq7{2v{;q%lfMf_rAa0uR!7k^3qoE|3c{fNUW71n)xqRy=WF_{!^@2AbaF= +z%-JJ@?;gXJYaQTX)VaxKCp^cQ##f<+{({~dAr|;7wjvF}Ds{^+Sx!AiU-Nij8li4P +zzk6jaOVZ+E7nArCGcW3RL&IadM#+8Oh1V6)q`QGf9cD&Ow;OD%_}`q88a_^vE)q21 +z%{G`8qMj|<6-be6cLOD +z!(~c?NVc+iCE7St(yeRH_J1%CN0%*?KP4t%Moag?g9A;iOJ80{((5~7&bM|OxEw +zbUWaf*LYRcqyiUDIc7@$JB0H`p%Q>~HIWeCLpK&m;;%!7mbLr7cpk5rBI(F02DROR +z;oY^OJ1gh+1sEafNkmhMN2yvx{p|L=J1m>`_X;Fnl5@1S!snOP8l=gKhpZCN0m`vX +zu^_n4P=j~$YS`;)_YTQ3`^9DSmMnLWDZumpFy4WaRCNaP +z_`MM(u1|Yp9Y;6`{?#EtQ)^*fl5Mk4;fTH5aQXq^8 +z&7}E0s7i}%f{J?6^e^$iD@Lj`HTj5YmfNgb2?BE9iLz{YN8@}utFZ?0SShfs}@aW4FCY82k>=4xS)NYe~qil<)e^ +zw~jr7ttZ((FqioNau5}1AaojjIBd!dh8VKPpZJC+)hscEUqB#t9vm0SRzy&8nM6L9 +zH?Vn+U0&0&H1%wmmAZi=q`VIb%%4RN;Bj9O@M+n&JyLHyEB?*Kj*gIfAui)2BQGWn +z>t|$|vsGbN>N5j)Lk%5b(1sG{Vz8ji(}ztM%x!q~DNd?@Vg4L$3|R1wK1ok*(Slt2 +z_;}0>RUBjxrhhGE>)z8|RdjQXNyIC-*O_-wL}4J~>HH1iRc1Z5oDcS=j19GLq2;y& +z$+m_Bhr%5$b<8z5ory_B(=t&R#RboS4)@)dxd0DcGEV|ZDCcxHIxol{57O8u0CNIN +zRfUQ|H<3PbSv-01ZuO;(Vy1v)e +zNP$IJ+1Ud|EV`t&yEZ5aY3At4%PcJ&`#kFyH77^(x*}aUI}NelBJb^B+uCuGGj%A@b$( +zgjAsUAmv7k6tfhN5fjejfCGNX46@4DwV$RdNqZ8Wgu=(`PqqkhnM;i@crosv44Mh8 +zey=+6AkBg3{k-qn(`GN^t*5{oWy0`Qr1S^zf(a#^jFktk1pJK{mG619l*kquLInnh +zCEo7Z*Lt*UmFTLOsMabBfgwYbY5d~YOMI!-TQ4z(Zozw+pt&iitCJ&M3JHfg +z(KVr-Ktqey{3@dlx}Gu*;Q!Nw-dvKE>r_JJ?24}w>)yNjhq(fKDwr0_koR-oBH3=i +z){$FA5yH>tD%%F_2S9h6MA1c8hr!MCbaJ-a(CZ%L1~&MElkXIC$c8RN@}u)1CZD3?gi_1aH@^pF2oENlJD-$ +zb#OEC10<<1KSl=T!~P;bJvg!`KXqLmm*f|H05H$!{BDIR8IEI~&W@_f~7F3uBMDV{;G101FGf+?tAK{1~ +z#F2Q(92VJ!A|t;)Ae!vYczsJPUCjZ~)BwYPfLrz;Gr}b}NPK}QS=g6i +z7@q3Wo(vwcVt75uZKn$cFoCk+#fyT7IYNU!S-si+E<=nqO4;Z$Xx&&EO09w%m>=N| +z5wUOujB*~`_aX!kb~K3y{n{sZW{NI)#l6ti +z0JN1VQwZ#vo}q(A5mGbgV`o{0nfiy1dNVM*-?jW!_^>5eQ4$8v$&~ZN(KO>G52xEi +z4(fVLzyKt*C+Htg2F4gOz~l;1#Q6bkv{uP1pi?+mS6VDL2m=*9RqBh7dSo7QST88F +zpvWANro=R%&?9Ge!GXtuiB={dhmvC*RG{P{q6z&UwJ9&(htc1FM(7*tzWv`{5G=3J +z6kC%C=w^Z0pGOKx-6)L_=ki#M(9oNHD$njB8vNK|=# +zRVpPGC!!7}IY6KF5-Aa2gw*zJ4V&zIBXHpMi*&ZciJhutsKj3Meb|OOdIDz87tEs= +z!%lZ~`1dNjaoCPYMcaUDq-eyeXAkp*758e+f*lhdJ%QGO!P6XpaLg|N84WfFy?QNb +z7K9PU0e}+$Hb~`K>}6zp?CR^>R>^Kg5y+$RNVin(GD_Fybj6_~Jjw4T6D}Wb?g-^9 +zZ&S;~ZgW0J~adNt2OcC2thH51@1+rL>L_OflbSbWFgSktuID&cF85m*)qkRrv +z&1psW7UGR5KX8#!-o~+NMw)N?22SBuTx$FK6 +z_Ey^NX%>DwJ|1p7_ZFONPP*eD<>ghKvZ2K`;!m>7aQcr|fu#TAFZhoXefZEs9P%Kw +z3DQ)osqpdWMB%op|NYH`$@pUrwAi1M|FvqyB|GE8FRyQ;eH>BPyzn4$z!Lz}L8gB~KniRmCU2K2xy0lRb@ +zVXsh(sOissuSD%drdkF5LY&&4LHeYVc(Y6R`QV4WN-4HGy3~+{vTdOb$u^^L6euAJ +zSV*<5iFVk_cuHK$^!btHI40r}M{Kc77}QQJSXVFaL3CVLa4&{*qr!Q-+k~~bqho`Y +zE6Pz82`jol6^R3_A5UC)D3CVH8G+=S)FEmJL%IJd^+r(ngl2@<7NGX5|IGrz3YBQ9 +zAAwa%#NP-*&uNLA7CYaOFQ_<|2VsxN{OY4p;I9vA{8rTde@EAv>jqsi9+uYMzL!6p +z#D0{mh4yB%=j9G$4yJ%a4}}>nJ7GO3GfKV8j$au2np&@&QJM$2Ev(t&WkMc9(!tB3 +zxzo!~N{C{z;ib?Q3y{LxIgyqrN1igg*(zzWr7QY+dh2Uz;F;!TRcpLL-&X>j!o}0P +z_`Hkhe93B^?8Csg`}cF|QgC$)ghWKh6$N+^-*EXU^$KumkvV6~#mx3Tzdqz^1%RA= +zGS!1|UbFAy#`qz11tM;e`&UfcLV-IuvtxUQi#!Vum&mU13j$GDrsbqC@=r{Rj1?6X +zr5NjE#~NYt#69b?nHjeWzj06LlScq{D*0Q%ueRvw3(Tn?I5abJ^InSaEG4+gii-6@ +zJ>kA>&lIzgu`IGT+`PX%~O&-?pWrk5*YJ0s3%;@|bbwTQOwu{4>nHMvyh1FH0 +zBFvRA()y~Z%Y%b~wniZ!e1g34$CS7~>Jfj2T%uP@@7EM>{tCcnX2O+ay+_3RPYu}d +zi*UW2W}|?K(;y1HBL540@|st2`2v&?CU&t;J&b4rO5{k?_Ya>tE?r~<$mra4z^z$S +z2r`;ux4i1CFX!jyQ&Z^gf`2NDHPiRA-xb5MIOatvk4LF5l{1|G5aBL>wboL=;vut$n&Ccll_1#^gVp01izBr=@wUIuBVk|xq +zatVMK$+O5L+G2zom9t_L=HSd8!d9a7Vjz0=*YSaa?mi*}@J2ZDS1di3xb`1qaN)D| +zJ$${qbO2cq!2^3wBiy-jiX8inrs99x4>-?V$@TPTOUBtOFgtWzu +z;4T|~|4w}y?R-YMDMX$9!+BrHA|zF4z(tSMGX47MoAX|g`mdq-7~<6h#O5Er%ISdt +z3HDX|!aAP!+CGo`lfXW}0P}wG#Yrr(WBclgxrDBakPO2KJ5X;}Wl9x9caAg{vAZ`m +zHx)U_HD_7WfZN?9JXasjpi1;2Q`i&TlA_Ve>^0i?_UiRbNI#d|rW+4cd}P{s<~4C6 +zSQ17?Q4tMQT$ZTLzKxf&qwhwubsZK;AQeRX(fYrr9C(eeH{NIE&38Ojp^@-keM1q1 +zgz1JMYu1I*!?Gky=&GzPXILi`oZW%Rj%aM#x-jt)4arwlEmd18u;i5g$a2f-Ye*60~S1?2OmHFb5zfY#Ak +zO{WYc0$0Wq$kMLq>4>dYk|`pyI6q&A0I57$#g7Tk#x%?MRPAFd?)>eWL|T0Dxc`Jk +zyT18FLt`T~%9E#=m(UOXzpTo}kaxd=b&=MvTD`W`-gLXJT=2>>q{sf#rG30P#tIys +zEq=&#pQ#m37HtH-g_eGeIUND#c)1%uT7a2bT$J1{)Ze){HXH#GyvzzWL<`9K!-l$r +zAM5vt!y)|`#nsmCOUca2+V^`o{i>X!L<>)2pIDtbJHe(iMu8j%@jwb0$*UkpU0xiQ +zhaD~csVrWlwBR;?JXVYJIsQ>HO6kWe66`6nMp1E^CQlOe#*M%`leN9RKA3?n_crZK +z06DK7V%QqmURqy|VNt-(GK}Oejyk!Hp9G-hjA1K_8|1@q#x43J(kGb%T1d;e1R +z;9-;>W03X{e}{Iyvtwjn;IBI~jUDM)%aI&{ANncRpPQR|=P25rV~;@tt-mUhMDx6~D%fFatjJ~AuzI8vjWDl1Xi`ZMq^ +zIP}g19=)&AMMp;j{8d|9TT5mOeam@6WfO*C$hqKlagmS?1wLG*qmH(=B;n|kt?PP| +zE~1rsz~`uzP;IB>2G6mPX704b+2tiTFI1Yj73nP@fl5V|8`+;1)Kf2W*n29ZG@F;1 +zogG>ttQOudL!a|}_|xyMQ`sN_8Sxj0j41a~3>>>&>$!~b_;`NN3S)xZdDebs^pS^8 +z#WrQswD)fYBX1BH%zuaclFlIfO=krFXy8edCG>+&voGwHD2+|#E4mVt{FZvte9fMC +zXu}!_qliEHrf@;ee!ZB%xQ@y$LU%fIFwa +z+(%QEy3fhzUO-Vv6;jJ-J-qF2vF29sPv1ad6L_Up^7FMFf%DIcByjP_j`?!?upu_( +z^D}1e@57!q9G(rp-Ol4M9_JtO!IS`?aXSc^Yatvg%4ET4v#=z-c);I!eYGR^cK% +z_5+|VK(M*oGM{D|+yIP`M7QiGOfvbQ{Jb5@1m{itb#-i~9^P)ZNZWHijRGz^o>1K~ +zOw%zWY3V$F4PWHYBm^|Qr{4NCQ^swyfx7JvtQTUH#=ITe;6sTfgajpT&FC})|z +zDWl-{`B}H`dPRt_WN@Y}=L7&TUb4v`&)mxA$tw!=ZdPz{ak&?a*Vn~=j?=@FD{w=E +zg+l}Lz^q2hid)m%`@ifVhj@W)1D@=Jf;NVHhM;s7YE`sr)%qLC?Ui%!0s3P{29RMicA`~ +zu-CFo78NUTjYYt7`-^6f1`mCVl4FkRzrY%UD~yzflWf9#6+~5ed7DN@Q&Xz0Iq>xZ +z$6uvEE*))wdI`{nWo2az3j);MqfQ@}8GghjUIS@}kJ9r5fB$8mx&0COGN{?J71yj9 +z*b4$ZAY0>b@c2%kA|W&vlho^biBL~09Y+2Qom*q}lK3eJ%;-^wM^AD)gXEMk;$}1?CX_-k>DA6wY4Aw3-q|jw~g-aK=Wqu_LqGwz}QIbd^Yv=UbDOn*?xD6uu(jFj9!QttGN|XjDkgAF2IV&|?=;XTbgZbjB6~%xJdJhaegmdwPDpzPVY< +z5Zo_9RU*B`lkkRssqI8aNVw60tyDhmje$idh|_l!1Jc0s!B1Ww8?1HNLvnvg1@By{_f77Ec4^JZQZi2j?RA_@OKOuWB&lD +zgXn#Gdz8r@g(~<21bN1hxs_mS|Jn0q=-#ETv9a-rmD1zDgM{B*DBvA!C|7~Pe_LBy +zAgE>=8bTpuF~7MIa+2cIY(t2-`aUNW_YioUGS-Brjb=elZf5(}KvT%|j^&7Ch!wo7BN(`|*Rz^&UO=_nMAI)a-zl*xro*E6V +zi}Q0JF9JSuZY~)y+g`*MyJB&`X8J?oUS55rLjOuA}7AoITuz7J$8T?EslxptSqoYJbIA~jL5M&(TdP|5cCkKcMpGdCk3D6Hbr4^RH}nMeD<9STUuF};c7_J +zd3PM5jIu=<)t^`V-FazkZH_WKEe*nPpZ<+;`}5S)u?x2tRP;=)h`64EkI#9vRkRiI +zLkTe2g3H~i4tPt_?gkkRMC%wRIzxU;LAMwhP(VQx3ztde?5wA?CsOsBv{3}aSdZXD +z`03=pQL3j%B!XD}>+bi@jWaUlEsG`Falgyp<&o#q6}79xUc~AvdS=J2kNL7t-HJ-y +zuK9n{rdH{FWUQtuz)3zmJsnb?EdyQ7b&DWBi*&Bi($bRBuOF))6rOg^2EBkG-{9H<;GJyEhWcpL!hZ!okKIt1I8V +zkYH0@4%(j1ro)XgHZ}%55Ow|>QckT0Mo0sfr<0Qk1Focm1n{5aibHBBIj&iE@RuZY2j%x< +zHAp@H>s)0e6AsCc0dYh=GYbpL=g)6v%WSr`hrieDtZ^QuRB}Fr_V&&K<{}?0`0t~I +zI9{j1L~a1n%h%m~2|)Os|2iXA;QnxhhgW_~W;hq_=XPqqu5U9C`DV&1Bs6>M@y9ys +zWB<1iT~U_tz5YMo%NmptPBYa~T={^YXH^i{rKhJy^b>jWo2zSSNSFE-EEC9N@f^?g +z*Vh-XcB1Ovv&U2OVs;vvgqu4`831y{E3?5r`PXw030Eq2XS80T5!k_Xj}n6u$W}~1 +zuRw}}OP}@i@e*8wf6P)oOn&qiwv5Y +zqoShTSS??{m_S<0bQWAQ+P8tO0sslq%x$3;G1ieFWn>Ibq9Z7@nI_U@34w9uVZddM +z1+7bqt!r@{Y1R%1kAANJ-lf5^DUVjZvW{*%ipdf@d~F +z1TvJo7wJnos9=&P3uPSqruR~a0V%|vF6qEyqETKn+}`mlZ#Ia&A(1Wg5yk;TmtMjC +z8x=Vnu4xutx5%H}-Q7!5AUN1xa`X)3jUSWfDxMzTH!!gUj_&>a!i3N{;ggn*4qSev +zQrKW3Bo;&-hOdB2^F1b}v?x&4<7x{sF%;YyYav$1i|e9re1Vz(Jq1fju6fSikn +zK>|)ZViCjlV2NdC-+N6Cj?oE`e>Q% +zxxOt}+D!5lfVZ;K)6+9Ez29Da+Vuyu%GAISs8Y2ESl)Vrz;3PC9VY4T-<7miP>K8p +z6%Fm*^%juHHWhF@13u&L-}iUtt8cfRukU+o0MWq1L(5fh?UbTXn{hc7s$1A`4ci$i +z<4i&99)xKqPT*T_N`vz&>v=^*M*e#Sltzh7koEUowBbac-E8+N-pUmxPcYJk6{33! +z@FOt0OcSmA335JvFIq37uS@@I$uE1Fn)Wx4;NiIgK>g5A_)S|&OJs`MVN-dytzmSb +zbt%*wRcl9wM(f+KNWp%&5{(a1S2@et;vyH|+Yjcg?+{n{sn~;*eT$V=0R?TG1jkbP$cW@lpf}DUTK4dknr2>8`A<)_pJ5 +zC>QX1eFk6=GExTWQ%_d*`{AVftE(&Ucms+QK(F5{L%5gKFpNGX?ACr>S75r9;GJrr +zbvvB5{uY{KE(mS*uVd%awn$L2Y)gLjleYy0jLO-}-rfCu(AwY0&u_>-@V?%}g0&OE +z$hLZspX!z*Eg=tVS&gUMbK;q&Pj>-RIBoh08|F87{@gA%hT-9HZCcYUHXD<^LE`h? +zDv_!uHuR(lm+$ZIgOl^MzFU{lEv)3&o6|8b^K7ql^QA1ImvW;O6!d5JSI0OCeh(Ch70!1V(MOLZUZzSS>$0n0eL2AqRw!kcztRo +z7#~^S6UnrASbPoF*Vb;4^*smJNEgF2Rop~`*1wwht2|;lcBE +z`t=Ry+c-th$}~rmsR^Ya5EdP258c0^!f&`SFm$C~65!BCqGMw*i9#yH@tFIjcZ!XU5lQcR#tVF*)Xa(>Jg^ZFJ_UoV%Wr%`qlTwyP|Lx<)eZF*&}ck?w(-X(g6G3v?wgbsnt8xlp9Tgv7+) +zcuL0&jIw~4WI0qvzzvBX>h6a8bX4Lv@AY6JIiA2aRhuvwR*LEVEQM +z%J{jZ&_42d1pF&NA-t5f7ypzV7MdZWfDbt2dmdb3TMG1KVW9!>r>!P8hiV)@WoDj|%U{zo!FbB)$>L(AvPW~ +z0dG*;PC2nk_4YKb+CC_cypPOOP>SlBjP(Z(0#K%^MyjC-j(4ZMj{mV7F+|LIv&WM +z-5MMh78jSLh7CQkNBd@Ua+SLDxGro_06{@9n_oCygC55@Hn?0OIW#oX%*?DuqZrV} +zgF)t}#%9*V;>(v*{(}GVbwi)PE+bHQ1R*Mp)J2UXz^2qw@ZN!<*FYaT^3TPE-4eJ0 +z5Pp!F`1y6ZUjfh|6>L#s+AHvRgZJ_F()o5jGm{|ANQHdQWG=g!4=AL33ExW^K)N^m +z>V(DlCp(c9OgeGD-Zl2a&9Uk$SiMo!Qau7<@oll~KLCuac_+_!hIy2g9^&hg-hZCgEuCC%d&tH*>mO_{6yu47+N4MkhnxZr4?b1#b +z#xgC(_$P%aU)F)gU(8?1islmWO?31fvPas(F6x$XT#+X$2)F_k7#U(vc?b%Y?sN(b +z{uT6}qk4|X$;tj1s|H?fZmBwAa;zA{n#jGN^%WmuDtB59)LyyQ%r09jdjlusG^``TfSp!V*tI!OanL%nvl@ +z(VrE3=~|EZ1ZRuG%NylDGIAScaRmpkqa%iogveNw%m`Pyf};?;oKFhXPxSZ{zYg7_ +zDA8sZ8qgi$f+ZrLo0$>jVVtCLo3|g}#~M3%e>@TLjEKLbIV(RlIT_X@ccU_`d<5o% +z$jHcef9~XZ+5+aFP>fPT*#J8T+|k#d2I|JYVR$ZPQA4wE9~^?T=Ne`GZ_D==sE2^T +zYy_5`FW!HEQb{zDM+p5p8hD +zBMm;EUvL@+SD^~SD64p+T@7pWCx1G;_~F}Rt_Y=Z6=YP@9isX7pxFEilE3erZ>b^2 +zg~j&ReUN>oa+LnEa#A3io}7SHCOp?jb!CYkM3wv5ZJ^Z35y5?&M8$i!l*urvrZE$p +z=IH9$(9$B4XMI5&bY58=dcHe>`S%$-ful_VS?%ot;u#-D;gK17?A6NE^I*pdwJSIU +z1Z=gEy@fYrGOg{94Mn8pe%!Iu@c=o4pN|jA>!*Mht|?(j$UmW|5b5;zIJXWo0}BiL +z5HuoSbrzn8FUA0$B~P+Z0EwdMsh6o1HP?RU^R=wK_LdFySl8^!9BnEn2!dS`{Efvv +zPde985?qRr8sw7WB(O6<^aDUL&?EpqvjzAmdnnEy9yA5cuMVWWo9q9*3P{PO5#hf2 +z>?9{A`|l^ogCod{LmazQI5m`i^)z5K$BylI4*MD(4VH9moD^51vOXdH_qO8DhafY? +zI4RNZ4yoQ5pr#S$d?ZI*1K2@O`oNeBxX}We$xcgB$F5kT +zHaNH|KyADAr!^tDl`Wo%?~A%tiYc}N^E!}c8+sN*PJ$Y|!;N<-O=HN|}O8UGC>iAPl@5`n?tlI2Dw(OwVO@1a>sJ +zEnBd=$HNI=YNLXM9HJ5g`x6WZx$taa+5~8e0|$Y?Jn<5}u>siBK@ANYU*5nxzaW~N +zh({in$XV~AhPT56imVcJ#9OVMVz37v`|-dOAGy$SGU-Tc8r6+?!^Oz#INiHKXGl3qc{pR +zO}URHy?mrzcje(&3fnc46hO4vyisRX<` +z_%Um_0DOdVfN;|cIz6?qU9T;Rd=GE3)u3)duYoBXr};z4p>=0)d2#K3CDMLcUxN!Kk%5A1=ra8{W{t(EJ~%s*6N7viE5-`gZ3Ym@Mm+J*#?l +z_z%WrSqe07cdPa&>YNF6pzrJh_0JQKm5kFR7LJzzoy8LSUF|&MXF%cxI4O1^OZk}Qa;_5ze?=-E2n}Oz3 +zi>2-yoR`b;?u3j>wOWXQBmc7A?9aQMEHQi5zfWoDvvw>OM6 +zyTeRrRiVrDRaY03f5Iw@I5}egr`umIKlgJep(+G%Q=eK9)6e8!#i;I?)7EpwlaA4d{25G1|1qK|1?Pf**u#}^cO6; +zTao?V@1Lk>G%9+@G2FZX1-5Q*UjyBMs#SicExq*eV|8=5ndbKJF4wIP*ff_ +zhxdw#ik|Ov?vZ>vHh}pRK0D6HGFl5XVz5dEwCrF}S*uRM2WT-%P#a84PX6d*qWt{; +ze!WUn@s*aLAP63@iNO48d{jrkwgau-{?BjdZSTqP@$|j>S2d0jW7nJ>Ncg}yvBle4 +z*ISypyvq6~VRtTBQkGN2r80CM(Y#%mLMIm&7jN%h_q{1f+{#-xQQ~0`vttk}Z>yWH +z67ri0A7^g=-qOhysz88cD2&P=0JD4#d7DGho2c1wBWGJ}-VjW5>B76BBqc~qr%aqD +z@8Xx$3@Ua8w`}Tdup#8?!`q(^aREw}DAmgjpVItMf&23E0-)~$a|l5FVd%+zg!dpu{Gxks1w-J%+XsHfVkMlX7HD9DEC1v;HDG)LHd0wu +zWqk=rDn!lCtgLC1<`;?aycn{6c=|vvaKBN5`s4p!xafsc4QT%EEIAG&oeW)Ii&%!9mX@ +z4%lYM^z@^w1GR>^fxoV5$L+o(zDUI}X9ziQO4|8Y;EN4)_qSY#^!!xc1Qmi7L#egs +zwefc-lAm9azKaZhVM=vlb-e9x0ZJd$>MLq`+oox}seK3eKde&tr2?`7 +zGB~+q%Fjs!`@Sp?O2zMHeIiwKbOuhzd{|{K9ukj%?#AhG4IFcNNEa5bA3%o(6zq6; +zfc;?M;3)jh&%r?`sA96IrUr6Q=|2cNa%S6@WjWfch0Xf1#WNj?P)tqn^?A8oTv!~f +z0<7Vv6}BDIIG}+#b!|^6OKOzh1K!8#Dic6_ +zJ)YG~x_g`|5&_Nozn^c&*LJ?XBo@~)nFXL70*S=-tTkhBDTAX7_-#*4PQX7h@+F+L +zMOukjK;Q-ZimX<~j|r6>0rRo!7kpK1y|&C-=q=+!I#+n=A<1lE-B7*>2L*wqN^{k; +z8W4mX_JMN_oB81V5?bmC3TU7>ft9hg9MnMP11vc_(cbns|DqT5E`#x( +z6poz$@yh2BX=Pe2aa0$xbEOSr*ot968O~%ht6A01A#fP-bL52stWr=_PA&I<=Gqr^ +zJ-pyTy+XOV8I|h+?vwJT#ubjoqWXwmAIZMG^C?szi*=0nceyYR}c;(jtxk +z1l`%M^ZgE+F$rWPI_psAh&5FrtkJ(deI#lG)@A}+WK&ad1MyG>pkXyN4Z*~1n +zar_N|6$rzDY$f4>V-?&Aqz&bX!=eoMbRyG>$49U^WoKeSp+dt8jQhco$(eXK;nsB^ +zrF!u+kv3y9n5(CA)-+^(HgWhl3n&xMamythgCYq(cj68bPTvLwDrD`@A*H +zpz`#yYy>R(qMG~<>~U;m2`Dn#xoD%`X=@9X +zBxhA|pLw%TlS7hjUtf@y_vH9E9n75AtEhf}HQnLzd)t9>RBE%NP^#*DylfMB +zu8U%^IZy);Lvd%aBpGtiWGJAP(@{Amlsa9=a4>!FE%Xv7d +zy2X+uw=|2>0oc;-!BQC^6K=z*mob30*jac|6=+I~w1K(stQ^1cBeA00j@ +zT(`y^-N2RRXTGUu6TyQ>DguG=|eit46cq6^l1@z;Mr +zto}jY0w3?C@N=2HH^Y^B4QrKlcvnIuhp!hcF?8XDgE#-aCme5n=y76a}(dAPdH*Mee{VApzu +z+vxjSvqbvAv4M7t9FsIlZB31%hsUrW3dm4L+&xBv7$Ye2tgK|dP01m5YKP=u%_^+q +zyHi^T1}J?}iT%PI-sFq0^T`jaUegKL!1@fGn*T@S6cmKvtwxtHIbe|=FBezw00izY +zNUXf|SIO@r(kHktC$ad=E;6uiaK%MMK*wZ;==Xx|=$N0Hn(FBhiN@LYKuxtmHM1PA +zURL;or?CPE!}k|i*}`?pNfXI!LS7BpFTlF;j|%a%$N%go`AHx2lZ7glVBjrH5yT02 +z74;}7l#`-hTcly-L95G*pn`lZjbb)lF<2eG7JB0{F70l9#FIub6X1M|({h10A(2nk +zl_Ry^@C-(TmoiVMNiNrUe!xuATTCM^T+HS4IpM#!dAeRVZ6C0Z0dEd725cQV0+A8T +zr=#h7FliPXj>Ppv>k|u<%RZD?cKq~j{fb=iWI!VL`Vm<4Q%u2Z;!*azp5^7?;o

+^#@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 +ze;&a&qdP_Y#;**?^ZDeIfHm-C+a*|5e;Xq|Gs^XwH%|Rbzsimyj7Xi{y_Jim(`)fB +zy%ybb91YVpmTTtc+qcsD>@1jWDvJsWad7N*!5gNuju@z<@_|Me3`>^n{!729DNvn_ +zjj8lnSi<>lU%Yl6P$YL>b)kTxVc|f<0xxWBT*@XS#PV+_ulG!Ybi%LxI0xv$QUO1bI-wy +zP!;w2MeNhpKetda1dCS%(|u+X+bp2I`!FC;jgwLjy0_9T7Q7TWP(=Q{H$ooigBZ}m-kw;3OjoS)bJ_x;q=zU|>3 +zD8F1kXpGe7q<0wqJ^ogFT&tkLwaX0cv0C{&j9j3Gy}T3-*6F|-OG8?J;oU`D@gXm& +zKC^3P>ja^qd|PrE>h?$Yt3}B&Uw~Q;OOJj2DWiiIw0!mDgWjkQ)oIwMG6f0P3K);dIeNIFzj}SQiMg23}6Znw;(Q +zKz=J8L9NOtKTC3E*mDK=(sw~OXYo95W69{vQ5@CejM!9NA31o5^9{oFK<+Is2#zt7 +zix;ZGA|i?MATQDzU~r+IPWxm@m#~8YP;iOrk_Pq;Adn#7AuxV(6-|YrvD~`u4usK1 +z-moW^ncK<%h#elHaRi&{O9kE-ol~>UA`7+7^amrKt`^%uxJL%Oi`oyK-XkMx)Hlh| +z-YXrnlXi&XeBFd-M5M^$nTKazWAppuMBCe@+xo|IS66jAL%LfQAStX*)|Zxqq^19W +zuZVfX->f-h8GM3(O4i`eqa`v%HT$}O;E6(%*@W>T##>fnfS;^musoiVcXwu|R?(f3=LAC0~-=G=3Z +z_v2(g5s>U5nSS5Y07ab7+r6e +zoI6}BJmTR3@OJWGZ1a%H8DJBD)%!hpQkvwm^NN1q=pasG@G`1aYA +zmOepNs{~`|gQrl0qWY4IfC@J`_^SSuQR>@qy7av6GfUD6h<9&u6-G0dL>$ye(Ge$Cqg(ZTuf?B|{)#s}ayV4QpY*aj^`|7y9jJ45M7Bv1>c@?Z=ydsLj3mfngADn%q8PmE&JQd22`7I4XM6?J3ea4D!;2HlNerMb +z9bN!a1WWP=HZ)HHVq*IG?MI+e?$8}>0WBI6o&GgAMMF!=QKcUV0vZ}>YK2a0Ub#bX +zlAJ!{`*3`qD&e8A7$yJM&ktIYMQ68e-xPrcTgQp@Q$bV|Dot#+9cIEqL{63b@3rh@ +zH{h@gwQ4GD)aPhoBSc$0xGzqx!i^h5pYq}Tm*Zxgpr`dHAz6fOWNC3er0h%o7etEC01=Inw|EuBuPSI7>@&ooM^U} +z%N<)7w2|qi9l-Bm3(A_!A4yqi<>2nO!kR{LfjbuLI>PaKnQV!Nl>&mdvu?uQaUuP6 +z8J&}5^u#y~Y3i^qyj)zdsBqO(Tk#_MnY(cAkB<rk!cAYHZcS-_t!@aRuU +z0;A0Xjuclo*Z!5dcBgagKy$>eMb-Go@sDLwV}{x)bdO_)NMy5=xT_RVbvtm?J@97I +zm{B5vj<@$aU7y~=ih|ovQ^Ln3MDyHjL;fC( +z(I)s@p}aY*nUsE2%dlMZ6^u3TXCle4nYt8(ZF>`k+UcjY%ZFeI$08k5X+9r(&H3&t +zxZgji<@w?DY{BU~vT4JOunA`Y;B_HCKxGZuBv^JqhCk$Vtstks5LMsWoOho@gE*C4 +z9lN?fGJuF!Q=AV)K19uTfP39>cnx?%mEM&2p2Q6Hmy?$%!;_#Zt#~%CArz~8G(JYJ +zj}&+!y)dn3YehtmtZOyZ(9PM@#(T$<~fJUp;fO;kTP=cC)jy3l4tU +z&@l5}WsdgmJ*suVAmeho7lo@UE5)qr<>ji>XcFUUS_y5&ONw@3$3L*f2uB9`>#^c2 +z{$C3qG|5k|fZfIVpX^V5jXhE<)M#-9tuwhPoaV2B5^|)NVH~K55`Isg4ih4FL0R%Y +z50b~byR167SQ=~U+aAtI;4%)(Jsrx7tCqpA^q*s$rM(l*D8*>}Gc!&y((YlXcPn?` +zqAswfppWdrsZNqjSlFZ4yfTszszP#l3m)#16~{tce03csfcoX8(Jo0z|R%$ +zZCU;~dkMEKGN-$MiUheiIZ#rqDCl>A5APjHpGA;lM;Z$n +zeEtPK1>OS9p_N0ekaba>7$$!IsC>#g`y8vfV6TWWdj3<)c(cZLEp&`EtP5i?o{uS_ +zByy>$hFrlI9wy%=M5X-3>y0biIzG`Ru~kW)G8D6#5q!mD4V8vah#+7d;li({UNyN= +z{E)tW!UY);Fk5TUwr_zs4u~Ugqv2OOx}O;ijQ&OQcxgPHMS9$fwFGvBuMdBp48lzZT4D^GAICoz6M!fN1uIZj +zb{R}f0j4*V2K8zcBJy@`j8}T4p4Zv6k?$Su6>&IIh52|tf6k@$jI87V4ZixlWaEa# +zne&Q7eV7$?|AM@-DSZ74i~3~q(fI|pJRQ9f?CGaXhcVUvD*cm6J#g|~zHN54G +zJ)*fcuPbpeZoYb3G`hUG`ER2dQ40=eSy{vY5V_=uw~(vz3Y9T@qZ7GPdQX4wVHFqS +ze~ZYsVf@Yw+TdaGU}iaT3W@+&9#M_s>~#X2oG|{JsrQTBID?WOs-s{m;VP$5bD_Ua +zs5jUwr7rR4k(Sn~Ga9tdMU&?%r?^I*Uw(!G0JGvZk;dy2TE>hhIoS@K={q<=+1J9f +z51#t@mD1nQR-y}WIa??7NhKk;kZZQ@hmX#y6`AT`?@y*>pPcSMIq0=*kb}CT=gxds +z@*MzF+dpq_S1Y^;&;!tSvFZs5<$31%zMrsU?!aX-s@8P`^U%K)8yHvIN~fipqW|+? +zZ?n5Rlr##$bwrjkZEwGMa~~i$l)(vCCkrFBYf5r*-W)PYv}sI!M6M;>YC!>k(j176 +zo38kvh~TaJU$3yWCtROEl3P8R;Ia1fDaZ>LBiUnK3fdaNb2%rZQdfO85`WI- +zXx}p +zp0W96jbd3ROaM1phZUi|`SyAIj-u@=Im4E&w;&II=!$kBJCl)|6vlA!U|-*nmlKcs +zE1EpgF!GE%<{}tyOLvMVguhf+goiz@%UTbmZGKFyytZBxX;6!Xv-nEr`qP2W)a9~^ +z(0798@t`u_KiMIWD(9R$dw2KUDiz&L-sYNjD}&J(^&vbXFm?XwQRHj5 +z&3xOK%&04(m +z4o{zEPCc`-La3}-L0=P%_o)%q(4IVN7*BgHq5#PRm_XcjXUF31GqD@_pZXUwM$0vy_{~;%Ne(~-C8m*cM +zb!@GPS?<`^$;l}&aP?y>e)T59#0?pwxj--pAk2yskOVr|RNrk(i8;W7xQ{dG^fL8! +zg!Oc>buF`T9x<1zCs8*Temo@P{?F1rU?$LndpYd*KlO74$aHCuWQiIj50~nlKxmOc +zWnfryUyyv3eQ2@#V5xBTRm1+fq7S@O^Qx`}K)no7F5-*+IzObRec!CH>Fn(MqJe3q +zP`5g=LD?yr{;(`xubmb2o;N|w>|1m*slT+7OCAf&FeU^1Og=kfTOs}H=${EJoZ>U6 +z?r?$t=Vc?wLqitob-ssW8GrKIyBH#S-ZnNC{W5`7b^U?7RDIPVD+`N8-^dG2mS3hl +z%5bNH4jIP{Mx=kRMZL4&?hbY13Yf>>WyiZE*dCL%f$zjjUy3nA@;S%IDgAF?zi3Nf +zue;p1b7mmOTmXO@8Pz^2`COUDoWdeH{AO4f>2HTVNA-lfDE(Fn{;=vMa +z4bf7VhvtxVg3zoLY-DRqRlChADk|LY4t>N~+_%4JRoebXE=JmGn`Q4}d5COUX9z3b +z*w`4%%j0w=-*oi0NWu(`(Og9Z1$UoqQqd)i7SXdLOxa@v5IQ_l2cc2;mmFuGczXGnfwphQ3 +zzrz=vi!)%rO!5!UlmC|BgdHZ&P-Yg&e6K;mc#Hgz+JsDzm5qG_vULeu{kWns{307uaWjlc6ZoGYd*c4f&keOi4po-zM +zp!F#!F?IX?n1TH1!78YViXZ$b;aPGLG&_~K4lTeeRrw7UaETO$QnH=5_q^rIzkE9w +zH}x>W=yA#Pk2-3fpB1&&h8#-h)T0Nto-RWI`f +z^ur&Yt`Gi5VYv=MZ>wXsRI4bI(t?tRA_lo^*+uI#<&_d}(zVZHAi^Vp@u=T+! +zUE<&+8IR8%(c+wWLLH7zGZ&${3EAb&FXW2pgwa-fA=qrc>#9n5MEM8A*#kcKZ;%Q*8IXqe`L(kyz{W(a#f-$mMpCc_o +z)RMO{jO(*Wnkx~PHHtpHDn9Xp5+k$ZBJ>?u)r8f56gQ9mfzu@UYZ-}}f>N^8%}w;m +zbxF63gS2aACjF6h>Q3M|792`!61wGw0}2+bhc9XJqzx$^8F7;J?yyyL*3R8tBf9kV +zrI`?6qnDei80Nf2==fj^*2etqe5}{t-U^IfED1Ec-Hfu^WwDsIhUu-YzTW$Eycvvz +zA|p}%P6^uRz7nDTk#MCrsNC@}VDzCX)2`lhcipfbMl+%tr|}hB8-;y49U);HN!ZyLml? +z`!nQXOd;Gq1k_82#3(bIZPA}Y>K`m?$!lt<$}st1OGdNO@H`7LFq3X{@D~d(`G^!@ +z34slnfxBEo2%hKPmTExJY}0&hv_EK{rr*8p>w-*-t(4vG9E-Oh!Bj0N4NxVFDh(DVzl)prV4+0xL?cW-asgzlXk^x1a% +zQz3X{yC_7?_LuVyxzQJmI=ITlClX%4gl9peHZ-$_Kc|AGr%Qw%^U9ZjWFdCE`lc?T83@i=uE$^Sn;UbT-cAB8e=24rnBPu +zJwR3CU#lwZ^l=RkLB&zJ4rnWyUC_2%h7`!kYTVw}3ae7?0 +zaBpj?k0)}zcMB3Rx3{-{cOSoP2^1{wFZhZg9-PmBFyYa2Ol^@@-uFESh@Y`fn +zcTci+*HOm-@BG!s9dg1FEmH??-AnMcAHKdZ7?9Xl!Z3o=lZ$Ulkb}sQkHKPF9r1MT +zrg5!d?|HW546xKH@u4rr$5r_!{KGHjREgE>Fw{S06bw$3E*yZV7tH8uzhlKmcZcAJ +zW;+E1t97@UY5%rI>cKy>=8&C@L8Q60jX-Wb5+P1X$s6r#OdF5%(|6%%ogS;=hc*?d +zpqi`S0E3?Ee)}PkyVQ +zDsjnJJG%u$i99v7l+_q9FEe1TH0Jb1W*uVg=KDS&Biu7EjmB|tGEb+wRm(XEv=eU1 +zHu}He^yX{fJO5KTukl6FcW6uK-G%tvA?s5&UpRyZqiSebKzi4yKt(Yd&(jhPXM;!nwh)#U9gyr)Su$7(*BZ#U +zz~3vLiiCee26#RR|1?3$6N92Xb`G$g{}o)F`Z|gdv;UPh@DK{JGpoptzkQqkILZd` +zz$PNHUXHGj=;rE&!_2J6xFz;kXp68TQZzYMcM3Ld7p^kqC5H|9H*jasnbjGt&vBmS +z{E2fyY)=VB+bCAT()ZvT=DG^15gKyXB+_27fP0xI!iUOuv#`XR-eYP8icVmQMo%wB~#=6L)^KCCd}h|_{ULWCs_;3=6dKCP +z3!5j~qI1J$luggrFugit=VZE3K9T6JWx&P?OX<7YZ#9r6_s=iCx2N>jG<^@k4cMAD +z3yI>Sn6{0 +z*)|9!w@F?`k8#-%sagDS{L<<jfK@T(XIq{qu1QQa%?ObBYfTIVOycVEcCX81;~E +znm8AU)Xq_K&xc9hTYXD<2U7znmw80s(d@YvXP^%(YwR{Nk2U3I4 +z=O4g@!|goz)}PG?L$8c5X1eWIsZf5Km9;tUJ`GK;x_ZB`uy7+^Kmir;jb4Q66$Aiw +zye3xI6V{fzz$mmq}FSLSr*UTpMb=jt3(loAlFCJ}-2wU0QB +zd>VWtk_6k2O!dV-7}k6d=u-MF=pUO%d~U``_n;`$e$AWKF^5y60iyC#7 +znang|eHFT9J1YB9HC8c=SnJ@vGO;}svgFj)Ap9)trOp`3*`Qu~ug}30zB-lG>U4}H +z#`eDd!v`{o;)KxmJ71Zdo-s}#m8s8k?PnqoLRC6GvIeDXLZo({y$NqeLaUANO1#ea +zO#xZcGiuO8oU7?Xd`pipn>H528pi!u&|`Irt0T^)S|@I6{SDn~Twedvn2DZv!1dn+q*+Pc}+Q@F#PF2H8;rKy{+ +z$NMq+t%9i^z>gdeF2-{t_nDP)42-;Ttoe3^8Cn_|+|1-jDco&yD~Q4Rlqm +zxN%&r^*GKHu*ZJafuO4<8^p5L;LLeb1u94@dK|5rS1AH +zO06z!Ty>SCVwAc-s~jx-49T43DEy3eu_VEBv`QOFPvmqO?hd?)NHM=t+lf^ebG{yx +z6J)%X{mm|aNI{bkd-Sjl!wF4_GI0bLOSp?cUGg8>N6b2vXM91?wrA==i5rMJWBVIkrW_u||O#i@p9et6;H +z;YIu2N2ur)o}eQJbW$W&bD|SGoe%zH!-l?F7)V1@U`tsKa`<~FJ~JY8z8WS +zGGf)M5p5~idyycu_#%RqcN#t(Ri(T8-ihsn)erkN)66nk{_J|4zEE!ix`FDB8uilE +zxi23&!FeM5`QCI1=Rr?KLP4kbHbnS6AdCOV>_1IZ57DG8yB?cwmmYpqPO&$!;~_v( +z^#ig|*~e(LQczl2T0mg%>BE7?^wZDv-ge1zm|xohSmNpF31TYas5w&740!@qLh20A +z-EHX2a_3-7(yzp$n3njB+wmx1A-oLx1en{y|4zi-ym5ikW{M?(^Flz{q;jDN6{#UH +zBGN%eA2j2I`1J81DxF*YiaN*q!O<^!L|OE}l0Qh{AXt&1Mv6TD3F8;t2DFO&)#Yb*i`3bPt(~oDRMvkWd~c~!Ne23} +z5iuv-kquHq&d|+$vg`v%(H`kz&~`MPZfzol`9E1|Jv)$A$1?uR$6yv=>k}#5G*MK~ +zZ{6U`#ZDH*gk7~(*88jU>7rP8Zc99O3Pz^y9tzELyg +zRFl$ntX=thO}aBrh$NxPV4*GFLgmKm{DF# +zO3I$Mv1HUk<$?C)7c+TLRO)g%mXin)wZ^ZAI3 +z_wSUQ{L8F-NK}r!)I0UaqkpGB`8#%2UJ}uLyL+k6Fs0@d`t#>$Vi@rGNYYR}w_)kK +z)e?N5*#CQfKURw{ufahMky0&VQn!a9+M2~dd$GN>l@47^Nk%<1v1%5%s+ujYOrPF&FW>+|we_n2 +zsse=g!~frei59=Obd-%FzF?5qy5 +zuLmfpr%_{N6_<6Abi28gE*>5qSLXIB9`EmmS~8H_KSQb{o7j2@fgi&=r;yQ^(=Ws& +zDr|4&J<0u3Y(h;281dUm#3PijTaJnNWXSmNraH0~comRS~ +z&$d#2BWp(2gt`LycZE1qXS=-n={$BpNI{g**24keti&gx&pYvA2E)*8+w#p!&VmtG +ztQ4I&i0e|BKKF)

k^D=01@YZG;9(CUxV#)YcZg>c_3<@uAH4Eb^F1_^dZJt)$5e +zY!BTUKz)oeb;Y}_dWMQHT2p(_73f4o;t*|^YNLg|L6`kyco_AQrdX2X%bBn8vjiVV +zH7##L=gUdew{~Bfwnb=QUBwGj)}k+PQphCyeO1|jMSn>8RX=ELh9SMI9vJ{LQYB?>=>K_6kONezriVk +zz+_zl>AogswuFpqBv?gXkQC`pru$#|S_tInvXRV+Sl`r6{Z)Cv%uK<{m4Xmla56WG +z90Bq2kQPCnJ!|~m{0>6d?biQm0d~#g?EZy8rB82Nfcow6V=C6rWVN`72bsRbQ}VkP +zmqwA?5M_fJ_@vuBobkKptJ2*i^GA)0G~szSkn8x2nmt`*1$rZ^sKy;VJR0EAmeN?q +zl}C+k;XOrcve(vVrV0!10;lFlFszU`3|2;1&bo=qaAx%B2}7g>%9D7h5HAsssl0mA)_D6i6a7BTDGET&TU} +z*@L4UFnBJ^T`w>r0g_c(y2ye668hgz6LmZk^C>c^QW*=@489jPRH-_0_ +zuq&}hnVphYF@IsJ%vF#!>gb2?E(axRB5_142=S!BRb#>}TDlJhFPKV%MW%RO&TBc5 +z7>{NohAeV5h?C5gk}h{TZ7elmYXp(a>Gq5a{`DGD5Iw)>w_*;6bIT;&%Po&EV|c3^T;4Jlm`7SpGCg4(kUB{qSvsd$FvU#fheVG?{jt_B +z#Lw3kb{Wh&tS@NpXdVbQ!p}OHet1fVErcf_{uOdn9Q%f7Lp(&ZorWaMJW`jmB#hI#7M2h+{hlQp;Zw+0XgVNw4Fkc}eRcAk$ +zS~sm$hEC>Qmx0GE%jH(#saA6x;(hMGkk3Z4IbfKj3~Z0NlpZzI!h~c9nq=)+@1nGA +z^|30$nxcpyqZEA(hk1{310l974DmHm7hEwmCsj3sJ!Cygm82K^wm-K}lT4k>klqtF +z3OffW#`AjX&0USz@kb6s7Ys1qwSTiel%y;k#W5)xPX{r> +z#oL>o8V{0Ax2~$q2+f8b4D?<8x&s@S@^QwH>@A`iyDl&2#1Ty7n8ntW7Fin6qX#Gs6*i-zmMuWxo1@iVqU +zxzlp=EXrT$zMkK+Rbg8};PtZ2CeF*ru{jGRhN8;xMFJky3kc(DqC(}<^D +zluXt6z)O&pVPJ(@8hf- +z{lE{p_z1VWX@`|kO?#XsC0ZOd;~}c5x7LVA%JRz&8H6`{--uh05Et?T@pBDoiiK+w +zQXZsz7^lQNQbvT@Cw~X$N?V*#!j^zg}su%v~YZ +z(w%PK!z41PGX%A(${j{kBkKv%2=V4_qT;x*iXt@Pdv)OV*0&!JrENfrudQAm*rg)nDyL_ +zx|oW0gqpG}*rURx9RxZB(V%?AF`sEgUUPDx_~}3ZSp1ue-JU(mU9EWiQkB5|%hRx= +zetd*z#uxC3F_i$FXSJEO +zH|rJAr%9%UwXUJ7uNJ1(9H+ZyMu+f|7Tk567J#$K^`=|&`uy2B?Q~Nsr5At%T|Pe9 +zIN75vNTF6>04y#;3MwOYr^|*%tqEa+NvBF@4%N`%&OHyB190Kc28a%JrKkpEsv2WX +z=oE=t6}T$+hERq>JaDB4=NXhpdTU?Pr>ZFUdWP#ft~1nMm@OYxv}H{z2DciSPxghk +z%>Zxo+R6(2kKqq@PW`QB`WHs}ye)2+mf0T2q6VUcuMe>jayex=5g*RSdATS`+}gAT +zD^f&aV=1PY(<8jMBl~sCMoBe#`Bp!WHh +zX!T>KvGlhvz#DV2pk~gS4)>8{@CklTA7`qy_|sTk4t*nLhWfgkO?U~_0W32}VSOJz +zW-qR&EpNhRtr0VjfIwtTNV%q6BI+06PCGG5?PS5fFetd0ja3wMyE43b?trRmsD`1% +zrvEgEE~cifZRvG~7)RaE#9>k1m#O)6Nq9YcsLb+stWkwV#Xx)c+x;M9r0-@QpmB4{6E-f^NHrdhDHGcQz{G22^!SvNzg5PCXS!CpNO~$qGJlf_f +zz|JD7dF$l){rFgqeH>5AOa&gpdZy-wpU{vHt4}$}CP4+nPL7W8mgW560XKZ-?QLz= +zEfBAN5eRWPTfa`_Ptf-Z`!1A2Vj1P0DHSD0% +zUh21Gk@&JFoBR2zwzlC#uv8G|7PFmkm9fkOgtnQL0&c)APrpeglMg4O9}_$A0j00@ +zR??UlwCX70Z4=w`2Vt5JJq+{bOcZ|g&@hlua2;<>2r1DqgzzBNz{3Kp+|du}Gvt1z +z;e2?F+Lf&V80FV;Yf`L&=8ZFeUyrYTjo)|fpkqvmAd$ +zVcJSOXLh^0uiDgKTJLxkMpPYLv&69|+8WH>SzQMcBnRO>FTWfEKYkFJ_p@?T&vAjW +zt-Zn%wA4&5@%$AxvY^~t8K1KC7yo&8nThA`^-NTiA{_K+$QdiDSI@E7Fk)$y>vQxk +z>>Q=t37)HT`w#--+AKrDIla*&_EaSPE_8BxH|znS1bff5`q0sc|8EXz#68g?-(L``4(_GRHyveL& +z@%?{Et4O`D@emtw++wpHJa&eP>T?#hX%OnyhJB70x7t#tD6* +zaY9m7R)iRyHJnQ{KGvA~pEYd|mIRTvPW|PI3F6x@AJ=jTom*7+OX4Bd%rcECe9gUS +zk7n5?78#y{cM9`~xv}Z{dke=2qYIxt%Qea8fF-?bt7ErVu +zCw1~uO{D8hcQ!Mjo5f!5uAV9g|d +zoK^DJsAh>Ri>U@3t*f(BCM$9xH!K-KaPZ1~%Xa8=1Pf*USFRw+PR^R11iC1`-7LS*vVTfUZAeW}8u7uqD+31FrnsZTLUY|&+nl!AUnumO6cR5uc +zf{$<~)P#Ia+jN7l2ld)CEdoF|<5_q%#^M*_D4dty#-M(gZ9WiuX^hg>n(cDiY}odL +z?fyOO@Lc6xg3AIG0pZqGU|X5f`nS*gC8MpidE)#f?_vAllA=)1YEcLZ+@dSsy$O~s +zOg7`oorc19;IT7&_;?5HrpC7DvzoCa!t7k=eIBD#a>6Au#!Ig8khef1uKUA`JEk>DS1s^Yb0}pO +zA|mHOg*FPPte)(T%VQcxrn$6D{8ua!V|*VgDoDD}jWBEn!3=pUVu{+ck&hPG?r!W>N1PYN!sqh5T +z))9AIQ3rB<_w6oU!DB>7p>D8hGKN@P@q7@0QOmOMl53&3Ihux^BSqq&zaRec?8wyp +zmH(s1yqRhsKNt8E!z!a$_<;-+dm8O`y3cMsF3uDr8fd)jL)lweB7Gr2KuSb*!iLkU +z9Epy_ +z4PRBX1{87J$yqu4M0-WoO%Eqln7e3v*}3;us1)Y8SEroj0(Za~64mQW-PSBkmh@SI +z<`vEn0C5(LWCS(BZ6$A=-L#4qj25~dV4!4I!ox(I-4Q!(y}v(f`7r8uGzA@RYOPhp +z{9r_2t*J1bGi3@UtMc-4_^j;s10X;@ei+=dpb)d73;lHJTgHN>+OMixf)Sr;Yry?- +z=kyvJ4pvX+$aXKpsPW$D{$IG?slS;a#-sopTCL!*T%N$4v+29*4M+%8VS-&j{ST6c +zb;}AcmN1`rtabK3k|9EE7caNVwb+*5N>E_n*ZKJ2gHkFoW7Kd`kHqRO{1{8`UXl~& +zcX&9tnqwTsAN63n_-8Pk)pt%XVF~9Zjw{R=BQBuDjV3;6VCqe2nBmxRMSc9#@j{XgsZ=cH_{?}Zrzk%VU?$2Q+RD7`|_zzK<+yC?DtswJo3pCHVh_06K?yJ-} +zx7`LwXH^=vo|%+7f51ITSUum}RUorcRaJWI3GQAkghWpLmH=!#E^W30wy66Vq`}zt +zU+k)krNW*ti+mbpQUKcjtlS6(&SaNARq +z+P%Wj+g!!a-jDJ)iX>wU*FHy;czarYw10$m+KOR<#U&^IB9LYSKNN?8ok@M};9s|e +zs3@J}4(piNH9bxg$WZ^MqpJ*vvTLGCt;Eu`bR!_Kq=0m%gh&fZNQ;yTNK1FOgp`Fy +z2qG5T=h$5a(-XoOwt$xaCTi9^@4IzEAh-QSawr|KDlE3nOKzN(plN$hKN{F@o^_BLy= +z?z|rH-!~%SNd^cS4h}=XjF$Ltc=agBVt~PT+wA2eI@Lm?|NEvf^NlR0`dL5OBvwqS +zh^7D<#TjW@^C^mu^d;1YxLGx>Ld84RGX{J5AC0Lmnz@qE_vRWlc+q<7n7pfMdGn@M +ziL{8Hf^fbyAfwC)-3O4W1Y_2%fa!jKGrVVioId(UMZ*{T?S7lIgnW2-mi;7N(au1LoWO{5*8LA0QXYx47{7 +zWtFohABO3V*w!9PZn;#Z3hWjR2#iaytANRo61&%*1$jEd)XToON8#*5s9VY}%kzk% +zQGYb~X9V#gEI$MI_Wh?s7y~nH4sd5(I<|Jb-@}*)2HTa6PfY|$R0MU09mN1Uh6(6; +zl`m|?*Rc&nN6TWg;YkxtOLGXkr$P`>P-^Jn?hcH;zuyu>z~a~COMQWG4bMq{a8R@z +z8buIs3Co|b;L;hkc5xRwWU)#5P8W2L@N;^oPHf>|m%n}Tf;W_n5pSLzm-|5iRn%!z +zX1aYe2Om48W0AZj@j!CaWS-_VO)+tb+TCKW-b3($KMGRlSiC#)B{fzdUCXx#9)zlX +zkU^V`W>maizW?&JzvtI?v}7?jCph8THnSc;R$w#6ERc9UwII1Sv)@SXMK$@*vc9z# +zrh7sB+ZEQrO>f>1;NlS4uFyGFVw~}xtLiW;CDMsiu_>hr=_PtzG=>WSr@d_9i9T3Q +zQ4vQ0$EjimPon?yIH)Mg>2+$RF*BLHKK^F(ZAL}PZ?sW@P7Pzw;I8k^$ +zgb$UKDJ*;)KPBjSKX0}s!;-6z>q>d0JMu)^b1=5hi~3?~9odg=R2V0xI^)zIr^S3bfJ}5pK=I6eA;XAd617i6y4k%86amUH6 +z)EMnsX$Do7_e39Cp2-u2R44{!AbcgNWLpiS)5qQy&T;qfKz$NOWNw@bM-8CxFVkbc +zI@RB~dslo%mu4@pZ4XC#KDPo(OCgfhNBYEIaZN +z`CBWrZCUxmRW>!<@(>PRzEpN}L#LJ@iv!syC#FaCu-cSb1QsdkHpG8Le_Ku!m>-Ap +z&36*A;~*ulDlwZB4cU+#0ob|@a(kC>`AS7@&C1h>aX)Ehf3BGBuHPv^0w1b^ +z!wK+sinHFUzhelj|do6~=Pn +zMUU+0lsSl_RA3^T&baH_XgpEI=mU|JrUf##LeXMPVdZ3 +z>bd>q-z^Gfk9hs1urktNVPo5c77z|Eq-b^+2n~Cf^3eotEh$SgSDuE+MP0reLUGzT +z%Ja1(N;_E4fhDW5f}>FAh-hn%;Ts7)EEl~3|zd})X?_+`j4`Aq=w-tF6~ +z5CPR1;XtaTIi%5sFPWiA)TP?@SX)jvP?^O{FSc$XRAoy +zsYCOx#g3;l9=H7C=AQ9=swEc*fg9|+8LnW8_(23iP(oot{2+pjXM9H-KD7G}9z3fH +zdj}elr#s-kOBILDML+sAYK-(0^fqFq1VR#ddd9m-q#X|rJ*AnEHZf>9aq&ks6605H +zc`E!{eLXW_WMy@_#*zDc(9!;V#86#DMbu%hk@U4|4%`tWfLlOs27KhttDUuFL`fkm +zK{vx}DFUwFY_`@gPaPNDqu=%)Pl2NvduZs5QAd8m~GQ!c+9$La@cI&p&{G6SA1N*v{%CjYp-f@0F@e@rF97Fd>jImlO|H +zKF|QXj&*zU^L`6>YXIxfQL2DCPECSQUQw~ip!4(sd}pMYp;x%{n4UvL>ZyfbHt^fw +zrI(ak-91JJR@p?7XueAR1V;CzUxaCh0Z}LvI1vZN>#|p*3P=2pd{Z?I-po?|7p83B +ziVP!)Gl{!GF;v%J$U&+$h4rQLAc+k(8UB2Icq15lJqPn!UUD3EoswX76Ce;!mR +z{_2m@>~J=PAoFJ?yu7^apdtYF1hiYw+h6bk(>SV93CLhFkPoVzc#!KZlRZ!1NMQF#tJ+7xskIF?K)j +z>#zNgi?c(J#5%q|4hnH~2rQ +zefG5)WnISY(M44!1bCs_z4U<5Zu_@dRzpKxax2yQCw2Yo@58?rn}5zXV<6S%Z^y-7 +zsG@3|+h8Z8c)pzyditI10-{Kq0|J^&U%!8gTVH!^P%2Rj7lk(ACP-{dvC+<(_v<63M50Q6_;|PwjN)50K1R*8K{5I +zaU}HOo)zE@{&#<|HK4wtfP(3}aW>f#2%MAj) +z4Ppz>h6R9?Mzi%nV4IrA(f$_i_M~tQ$>+y+r~r>;=md}P_V#n|y8p(fyw+M+XSp9?5ryMJJ +zB&k$Dnu<7mU`WXM$^I{J-1d;twT(Qb8Pm*g2o1e}@I}y}jyl!Tkf}T%MLq(eSGdx@ +zkP&E20|JhLfGbf@YLevHUNE|+nEPSWQ4IbjmW3itp`||? +zj+g41G~h_!AOh5K3TIeZfTk@T|m +z{^#s7e0$Fugo=Mb%JAqBUhWKYK;KD;^hC+QanL_I%-q~mmbz%W9{XB&pzVSCZmzD+ +zUN#wq`z*FR82fX$=F<#Afv}+dRiaFNp&O +zAt`%mLqgxBRrc@i($4@lCsQ}nl-+#&<@e3 +z5DV%jJGyhdX-@xrY37sXr|Keintj*E8U!WS>Slj~2^AdX`Fgk^;B5q%GxQGc-Ua?e +z1#%-0ta93F$|hc32m#oyY=g_M68r0p4sy0f+xFNFC}~iF!8qKf7r2J?&SS8Nz7Yvq +zDY)$6%6j$b*Eb}etK(2o$Pq02Tt2{ECP)Wh&wKi=HFYK*fBz$}>||zPiIOAWh~^Fm +z3i{_53!!Mr<#$|NH;ONgi!b)76oo`Yn4*>W;aIpv;G6@W6I#<7+rC9_Z^AydxVX5< +zToCNt>dXb^yxRuEiAT=gCH61Ej*Qo88uSOm&KzxkSdf>ewv!t#2 +zCUD9Z2UM+JC3+u7>m8@7A`nM$u?@=T9fBWB8X6jamu1K`uz(#X$R|#*T0Tf`cD#!~mZWdTh&woy~Xd+$lAD +z3S>yu6d3ipa-iV?mRT3}wM`9IIV}naK}s>YAL~$W!4NnsJFp+Yd2Q8~9FZeN#=~ +zokEU}t49uyNC>1zm<@69k($Xo{s5jsAaDkK1bd}^O-6R2@z9^cf7cYSgn`uv*Ct45 +z!9#G+slMUXlC)o`jfIaBmYL2af|5lhAm8mwooZZV1=N5Fb2dCzA4Y1If +zPuCO`L;oJ!F?X2ghF=$cmLmm|6pT!7nz)C94|QH+0^~pZXKD-M2+ic@Y@1X%)-1_ +z6M7-+A$@S=u9X@8?dIUWjsM?lzkPTpJn=9vFh5z4F>2eNd8lgf4+N{gxS<(JjEMZG +z4*{n8L?o|W93~baaOecw_Tk8=fndrzjV_~m8Cz@*g&CSISPVRIH=zfwO2ARYmf+Zi +z`AXYh@jVkqom8>8(X`>MZ{F;~hi)6R-CL%a5_0i(5z2Ck9Ns1Hs)5_>1a2S2vke38 +z&oJ(~xWr1NhCu^Xnrrt7DkktP(61c(dz}=96s`>Zhx>$n2JuD +zjkC~Y;`Ti&@V64k8iG&%=TA4@3}x^9^5S%Gd7^j{)?TWJOHh{z6IoV +zkT?Mzs0dmza9=JSn=1dFtwb2KwbTXenWpBYcE^c?s<<97^-NnOuyEik3V`g1 +zsnFw`(Bme^8Mrv9xqz3C+AQ`N*~7^HBfEm^Aam2Kk7D!n1LRVPoI=4B=;(-fDJ3xc-F?;FPm +z9Wg;lzv_sJ`#%Mg{4>f60gljlM_rwYbG9ZVqm$QNJ0IH2&Gg!({lw +zM+Rpc61P5m{0Kwhi%Dj(OHcAglIu*Bf0Vf*5wl<=`Ym&b1aS-vi?djszZ`3lM$M~N +zsRFle;Ff0tnO&zMB6=FS3rI*p=vaep{`wk7lEJQC@#(mt9Tn_XgA`t3(o;=JRoPTI +zG|insvMX8~;S!nl$O_5-p9<2I4el$IZjlhW4B!xop7O`nHx3#S*RdG(teloW9_vecm +zct_yPg8>2dH+ZD?TORXDxDTk5j&E&wDHJ=GlF798+S`4c!=REyICeg5UYSRq%zL?} +zarG~tGA&^SRts==W2xN1=QJ>}mV2*Vry9++T?<$>uVOgP8=p{JV42;g0Q +z?=XEqE35{zOgF8U>8Z7+z)JB7gQ>+|F1e8*yPF3r@PI18=@J{?y}d2UH7sUA?xkTR +zo2OT|fc(PKMvCZ#PX$T=>>k95x&>t#WVH^w!d`PyKTq8U1rv0rLq-&%fQWW4Z$Yhq +z%t$8Kz+VRkzIT`&BmWkdl7SBi!3qD4RFVAL{CuP#s=w?xJ=Kj>&9Vuz8XNiGlRdbu +zD=0xan57fttoiGJzWR!9$DSwwT}7!fnXe0V)UoZx49^c5na>~$M4?-%sp;0JJnZb@JiC&am_`B9z(^Yp714(-u>blKa@Ybsl!UFGO%MJ3 +za|7g0`a!D?u25$&p+_;HCsm;*XMaL3mb&nAhG`ReLF@gm!qq?z5FstNYXeOgpxrvp +zTqOP(DwzvLJ0N`4?j7#$!=wW5dA;-BO)F#oJN^n +zY{A;4)r8&1dFr^f#CxS$n$l3}vj4RIg(d06{;y8}J7Rob?}7O@EkK}_GA`I%04dUZ +zJWZ#fgwK~3E7{Q4$V(LmWm4|p0qS(NJO@*tR|$+l2}U3z0akUw1)tBqv{RUV@^rCF +zC19~jP(x8Na2r1L&pvEP8XJ_grTt*H4Mh_C$-&AwDh>CA1^+&zia?fF>&A9E|fgp#0&o`b;LxQ(3=^~l3Fd8N1)dJ4Jt*xk)>+wScq9_MP +z$MU8odKO_*M{$lYGWza2Fmb{wfc6HPez>MT)!06|zz|(B?ft`pEZt35!~QTmADqt_ +zz%g$>Klud)g>|NSDus)4bGqDA(5Ng?g?V8J?bvA&)am#@PB&$h*#Er&OIfJt8L`Z> +z(#77+^($fXlAzFYXBEl0KrfCZp%IQr9JLb&0ufIex!Pj=3SgkjH~`vxo0(_o$0u{& +zyqWcYz7BfGfrHc?Oye(~<`N0$RiSr!Dh2!{ELMp>YOgGDVsfTRVe{87hqz7v4!2b4 +z5(s)!H-c|$U9)(Av!JOK!_!qzUdD5kc9Q#^moKmS6l#&=Yw}jtTImaYJJNgL8j{B` +zz+b@*DkGVU!Re_faR~{vcDy^;@uY-AY}Xg*KVGg+1DrzCnAlx_*rlqxj7}&PCz#@l +z9ziTfynm^O)+E*#maA4$z=KiU&`V1iA{!L{j_X&q@pk(iQRWg?NHGh<48kfjpL>=$YHGFWoJW|dQ%5q^a +z-rHocSIIVRA3cYWGUO9t&^h>ZOd?F|B6OG{7U!$1wF$lWI(C3|+fl=8c(rb7V`Xe( +zxQ-IxPkxT9uctXulZ>7-q7}{4gU9Lds*H7&1SN?^4K;A9iP1c}ZmslayZ4PN_`W4L?l?EqvTb{8;j-Hjn9`(hT~71n(q4DO##wp?p{VSGXto@o`5p;YQwU7i9uoYVTQg3tPT6bL~WwG0?vaJ +z4DR(*z0bkQ&0nK8DP&ziQ|Zc5ybX+A_VTo*@wr>bijyw?1hbf$C?hMIZq1_M1jg?s +zxP+>$)YlP4_TC6x_!jps3(B%%wKNBAl%rq^7mQb@{2t`4@sta%B`=VV=%pkW`ZALzZn~-NJE^KAe!-> +zQ}Mn4MFx<3WZ+37D`*c`RZ1>A9`H>fI8C@lmA@z?Ua6dNVEuCQkEic?tgTXY^~7$6)`w&Bl{RE +z!NE8<>OZULx!oh=I3H|YCy8HqmC9_F$M5wvuhI$G>4!K^UC}veajH0^Rf%f2T0N6N +zdXSpEky-j8C0Y?L7zkbz-#8{u&O&0H8?@`0bLXJcdpDN*v6{< +zlJCk_lG0nC{C3?Dh0jFOHu#(|@UH9-E^pg%o;PVSbm?5g>6xN^V_KKbESEJSy0;8B +z{47264D^uSwc0y32xp>AA3A+A_TTdJ)%Hl6&x*ZbmU`jX7;hb^*g^KwSt(7zVNY4$RHcwA74()js8U~kbXh2eZZwb?v +zVF|YkvoXTh`q{8;tcdtwQaHn5wzjP$du*mpZ{7~#Wl2>JhtemqT->^OaEt>R@kU3h +zD`(^a1n=?facDRiinSxwAB1<(@74W+0l2?RbNIR_R(%08BE}$M8Ys!D%~zH=$%^#p +zGI6}gm(~>-X?Xz|`C}CL +z$h%kErJ4I|(*oiT7`K_6U<;Sce94|CCQ(&&29}3?XO+y{HyJ=xj-sQ^-lr1g8wKi8 +zsc0&LhQu?5&Lj>D)I;%W5WI!cm1_#^-<5@;XY#xYuNOga{DCgc>WQE}ZsjVsL39VH +zzuDBoMeStk(6&A!AJIb0dv<^Rk=e;f`-vw8Qq`B-C){0*3{*o)uPFsY+!LZpu!xXa +z<}My9d(MrFwhRmRwk}5{VhuYvBqsq0LLp&6Y;n_0ERTCs)HUi96j +zxrp@QO#D3ZQ +zVT}2r^5eanu<;Xa|5K7?JdV-t+vAt*oQnLAV+e*vzXn*|O+L)Gw6by~dyl9fR~AZ1 +z(jF%?+V(%)*_m{EL-o@U5UzclHXKi$^eS`8uSSeSYJMLW8tfDxP*AZ!ml=6ahVmWg +z=VhNy3*km~Ev#Y(S$)-bSNgWhl2cNk!%8yBuYPjIHRZo^+hx{|il!T*mB_#Fw#Mf{ +zl==HZuX>&nd&^CMs@V|)jz=*55yhvjPLqs1E>TSVbB~xKE4?jd??CjA|0+RRUkH}Jgm&rMEn2YeY5tXnYj$9#dutAL! +z&W?{$R5i|aBKUnAj;>%|^xCKO<6P8ki0ogrwa1=|^wqoE^U1K8j}O=0c^r7R=+^MJ +zw6tJPZ0w~7=hFYQQJ7yA!K`tntuND+EC@51D{G%}r@8K`xK?GPn>V;bd+2nx?P>)X +zO?r3Sct&#vTVj^~81cH5#`OC*y8sRGQUtUHfLFqpm#85|6icGc68%#pp7_0xFDJa` +zHZ@Ivr5^~V+z`lu*;#2G8?5wfO^@U!i9Xw-Wip&QVJU`scZ%$@e(5Gh$S?)!3gpq} +z6sZ1~9{!EPr7ol@d^MGFP--;~9(D$QY`D=j9STKT2J2@qC4ZKQMtfUND>EPz<>bn9 +zj@^+zq;(6(pRo7|5XqG9NfnTGm&}l>ldRxONG^OAVa!cuWVnaYGsu@?$YO703m^1s +za^A1Ifl3UzG=k1MJX6ObS&M$CF??%8gH$7WKu4+NYw~p8;yag&h4U-OK7V^GmB-70 +zsGh#^DSNE<*UTvBIPDjh +z9utC9b^<(o*ZW&pZ;+UBvKMq@2!l!?)dLR87vJ8D|DeQ`rMi}?7Vd%}@91@^@AB@i +z7F`8`r`EH9ED940>d^!`p2X6b-IRhZ)rKpFcf0(U;|;~*CN1vw-0Xoe+;b`vh=d9$ +zoOueZyc2?!)W+ng(X_P+x#filr5 +zsoo+&wA&pJ2lqINQR4EO9F;^0W7*RMy_F-j?9@-vgFL(RD>R?@JtXeHeeFCI7@Qs~ +z5gJTKu<^72l>X8iw69;sy( +zMWa7^Hc{hN2inQJN^$L$Lsj^&`2Jll&satiUw)K~$C(&Z<`xjF&KRVQ#>+!4;mH(JrP+j&SY?L72Qt +z^2aVn4$^C;DhFd<0%tS~|FGzkz$L0o35`5kh-v-*P!jn(Iozllj70bz-7r=~M_6$D +z$NQS~=-$>X7w1~8D&uFdj3tIvXnW{$v3fLkx}x14WTk4YvdGHI8kA$(_Ulwk@F}B4 +zXv0NguWP-rRR6juj^}WzqNyR3fxpcrOT3=~F9%IVu+D)2CJ-eXFOHS#0gF-J%N)ww +zH^Tpo<(jIBT;{T)9*>Dlvf}y<(A9fq2v=J+aQUv)K;5+Xd_UWDUu#jN+yK3A7m`5V +z#jxW4?O@}kmx(C(lmkLO2y@Ck!|jMf3ptJ2bGW3WO(8q27*hr5BIb>^#gYv?I*%le!yhwz3W)mzzRepKF5SaEL++Tjn-4MJIp^eDJp8X0l0 +zHwj@W##h}6`!ou@p-w#Cwl+V3+VxAwUFs0R8O+p5hBvBN5B<4P#sdvOUj^2-s1el& +znw>S~o8iOD?MpJLKaWQ`@3#$PUh8W1lzOc#LdkR2Fpx`(P08lcYs%1pnH7SW{S&Gm +z78uMZ9%J(KUg7m8#;Sj~Gn|r_&`SPtVt4MHlAc}ZM95(b)LPla7z3w`P^in+AtIy> +zbwbjSlQVD0%LbvP2z)?_GBzRX{htP +z-!Jb6pbMjhn*WW7)3(-ZtsQjayx}hOTHRg#%l;1vl=al`dF(3gU;YZ0OM|4)Fm{kx +z%B`XC07y-ci`D+aMT;mVLo3d{%qhrVz{&7-BY5J|^3~YS4v9kTt8Zl6s=jF42_*Ut +zB#uUk33PKj7TpCtIY*amKOuhze?QxToH{+v$)`0IzQN6J-w#S{B!#0S8KTo>nEJCc +ztbo7ddqsz&b9dQ`zrp==o}73z2Vz*c??Rkoj0DVR0{h?GtYM&*OW#cRTC9?_N;X3>JGOu8><udBUM!AATK?sG;M + +-- +2.24.1 + diff --git a/SOURCES/0051-Fix-indentation-issues-using-newer-uncrustify.patch b/SOURCES/0051-Fix-indentation-issues-using-newer-uncrustify.patch new file mode 100644 index 0000000..e7eac38 --- /dev/null +++ b/SOURCES/0051-Fix-indentation-issues-using-newer-uncrustify.patch @@ -0,0 +1,44 @@ +From d1bf2cc0c69210bf8c835399edb3578c4c69c4a6 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 2 Dec 2019 17:02:07 +0100 +Subject: [PATCH 051/181] Fix indentation issues using newer uncrustify + +Seems like the older uncrustify versions did not find these indentation +issues. Fix them. + +Old versions of uncrustify will leave things as is, so this is not a +problem if developers are using an old version of uncrustify. +--- + libfprint/drivers/vfs301_proto.c | 2 +- + libfprint/fpi-print.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libfprint/drivers/vfs301_proto.c b/libfprint/drivers/vfs301_proto.c +index 103e890..84e2318 100644 +--- a/libfprint/drivers/vfs301_proto.c ++++ b/libfprint/drivers/vfs301_proto.c +@@ -498,7 +498,7 @@ vfs301_proto_peek_event (FpDeviceVfs301 *dev) + 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); \ ++ usb_recv (dev, e1, l1, NULL, NULL); \ + } + + static void +diff --git a/libfprint/fpi-print.h b/libfprint/fpi-print.h +index fe07c26..94670a0 100644 +--- a/libfprint/fpi-print.h ++++ b/libfprint/fpi-print.h +@@ -43,7 +43,7 @@ gboolean fpi_print_add_from_image (FpPrint *print, + GError **error); + + FpiMatchResult fpi_print_bz3_match (FpPrint * template, +- FpPrint *print, ++ FpPrint * print, + gint bz3_threshold, + GError **error); + +-- +2.24.1 + diff --git a/SOURCES/0052-virtual-image-Fix-driver-reading-insufficient-data.patch b/SOURCES/0052-virtual-image-Fix-driver-reading-insufficient-data.patch new file mode 100644 index 0000000..b36ae7b --- /dev/null +++ b/SOURCES/0052-virtual-image-Fix-driver-reading-insufficient-data.patch @@ -0,0 +1,99 @@ +From 61851ea1f0a1e23c9f6f05245aa2d4d0303d1a88 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 2 Dec 2019 16:48:04 +0100 +Subject: [PATCH 052/181] virtual-image: Fix driver reading insufficient data + +In rare occasions it could happen that the driver was reading +insufficient data. Fix this by using g_input_stream_read_all_async +which will ensure that incomplete data will not be misinterpreted. + +This fixes rare test failures seen in fprintd. +--- + libfprint/drivers/virtual-image.c | 46 ++++++++++++++++--------------- + 1 file changed, 24 insertions(+), 22 deletions(-) + +diff --git a/libfprint/drivers/virtual-image.c b/libfprint/drivers/virtual-image.c +index 612863d..c271c7a 100644 +--- a/libfprint/drivers/virtual-image.c ++++ b/libfprint/drivers/virtual-image.c +@@ -66,13 +66,14 @@ recv_image_img_recv_cb (GObject *source_object, + g_autoptr(GError) error = NULL; + FpDeviceVirtualImage *self; + FpImageDevice *device; +- gssize bytes; ++ gboolean success; ++ gsize bytes = 0; + +- bytes = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error); ++ success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error); + +- if (bytes <= 0) ++ if (!success || bytes == 0) + { +- if (bytes < 0) ++ if (!success) + { + g_warning ("Error receiving header for image data: %s", error->message); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) +@@ -103,13 +104,14 @@ recv_image_hdr_recv_cb (GObject *source_object, + { + g_autoptr(GError) error = NULL; + FpDeviceVirtualImage *self; +- gssize bytes; ++ gboolean success; ++ gsize bytes; + +- bytes = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error); ++ success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error); + +- if (bytes <= 0) ++ if (!success || bytes == 0) + { +- if (bytes < 0) ++ if (!success) + { + g_warning ("Error receiving header for image data: %s", error->message); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) +@@ -158,25 +160,25 @@ recv_image_hdr_recv_cb (GObject *source_object, + + 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); ++ g_input_stream_read_all_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_all_async (stream, ++ dev->recv_img_hdr, ++ sizeof (dev->recv_img_hdr), ++ G_PRIORITY_DEFAULT, ++ dev->cancellable, ++ recv_image_hdr_recv_cb, ++ dev); + } + + static void +-- +2.24.1 + diff --git a/SOURCES/0053-synaptics-Use-an-autoptr-to-handle-the-FpiUsbTransfe.patch b/SOURCES/0053-synaptics-Use-an-autoptr-to-handle-the-FpiUsbTransfe.patch new file mode 100644 index 0000000..9ea7514 --- /dev/null +++ b/SOURCES/0053-synaptics-Use-an-autoptr-to-handle-the-FpiUsbTransfe.patch @@ -0,0 +1,39 @@ +From b5d9916157d5b215224ba799c1a2b707fd435554 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 28 Nov 2019 20:34:20 +0100 +Subject: [PATCH 053/181] synaptics: Use an autoptr to handle the + FpiUsbTransfer sync transfers + +When using fpi_usb_transfer_submit_sync we still need to unref the transfer +once done with it, so let's use an auto pointer so we free it also on +errors and early returns without having to handle this manually. +--- + libfprint/drivers/synaptics/synaptics.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c +index ccaf60e..284973c 100644 +--- a/libfprint/drivers/synaptics/synaptics.c ++++ b/libfprint/drivers/synaptics/synaptics.c +@@ -950,7 +950,8 @@ dev_probe (FpDevice *device) + { + FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device); + GUsbDevice *usb_dev; +- FpiUsbTransfer *transfer; ++ ++ g_autoptr(FpiUsbTransfer) transfer = NULL; + FpiByteReader reader; + GError *error = NULL; + guint16 status; +@@ -985,7 +986,7 @@ dev_probe (FpDevice *device) + if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error)) + goto err_close; + +- ++ g_clear_pointer (&transfer, fpi_usb_transfer_unref); + 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)) +-- +2.24.1 + diff --git a/SOURCES/0054-synaptics-Close-the-usb-device-if-reset-failed.patch b/SOURCES/0054-synaptics-Close-the-usb-device-if-reset-failed.patch new file mode 100644 index 0000000..c0a3019 --- /dev/null +++ b/SOURCES/0054-synaptics-Close-the-usb-device-if-reset-failed.patch @@ -0,0 +1,30 @@ +From e26a788fd6e4c71cfdbd3c62df4a5ebeba81b31b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 28 Nov 2019 20:35:33 +0100 +Subject: [PATCH 054/181] synaptics: Close the usb device if reset failed + +If reseting the device failed, we still need to close the usb device before +returning. +--- + libfprint/drivers/synaptics/synaptics.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c +index 284973c..1524c45 100644 +--- a/libfprint/drivers/synaptics/synaptics.c ++++ b/libfprint/drivers/synaptics/synaptics.c +@@ -970,10 +970,7 @@ dev_probe (FpDevice *device) + } + + if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error)) +- { +- fpi_device_probe_complete (device, NULL, NULL, error); +- return; +- } ++ goto err_close; + + if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error)) + goto err_close; +-- +2.24.1 + diff --git a/SOURCES/0055-vfs301-Use-a-transfer-autopointer-to-cleanup-it-on-s.patch b/SOURCES/0055-vfs301-Use-a-transfer-autopointer-to-cleanup-it-on-s.patch new file mode 100644 index 0000000..429201e --- /dev/null +++ b/SOURCES/0055-vfs301-Use-a-transfer-autopointer-to-cleanup-it-on-s.patch @@ -0,0 +1,47 @@ +From b82bcc0fc55035d04ac10143a909cc3a20bfcedf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 28 Nov 2019 20:40:32 +0100 +Subject: [PATCH 055/181] vfs301: Use a transfer autopointer to cleanup it on + sync submission + +Partially revert commit a855c0cc7, since the driver uses a sync transfer +and in such case the caller still keeps the ownership. +--- + libfprint/drivers/vfs301_proto.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/libfprint/drivers/vfs301_proto.c b/libfprint/drivers/vfs301_proto.c +index 84e2318..2bf8bbd 100644 +--- a/libfprint/drivers/vfs301_proto.c ++++ b/libfprint/drivers/vfs301_proto.c +@@ -67,7 +67,8 @@ static void + usb_recv (FpDeviceVfs301 *dev, guint8 endpoint, int max_bytes, FpiUsbTransfer **out, GError **error) + { + GError *err = NULL; +- FpiUsbTransfer *transfer; ++ ++ g_autoptr(FpiUsbTransfer) transfer = NULL; + + /* XXX: This function swallows any transfer errors, that is obviously + * quite bad (it used to assert on no-error)! */ +@@ -78,7 +79,6 @@ usb_recv (FpDeviceVfs301 *dev, guint8 endpoint, int max_bytes, FpiUsbTransfer ** + + fpi_usb_transfer_submit_sync (transfer, VFS301_DEFAULT_WAIT_TIMEOUT, &err); + +- + #ifdef DEBUG + usb_print_packet (0, err, transfer->buffer, transfer->actual_length); + #endif +@@ -97,7 +97,8 @@ static void + usb_send (FpDeviceVfs301 *dev, const guint8 *data, gssize length, GError **error) + { + GError *err = NULL; +- FpiUsbTransfer *transfer = 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)! */ +-- +2.24.1 + diff --git a/SOURCES/0056-fpi-ssm-Also-bug-on-negative-state-value.patch b/SOURCES/0056-fpi-ssm-Also-bug-on-negative-state-value.patch new file mode 100644 index 0000000..00a717a --- /dev/null +++ b/SOURCES/0056-fpi-ssm-Also-bug-on-negative-state-value.patch @@ -0,0 +1,26 @@ +From 66b6a2598b599afe874efe15bec4cdcb34f7ee79 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 22 Nov 2019 18:03:08 +0100 +Subject: [PATCH 056/181] fpi-ssm: Also bug-on negative state value + +Being an integer, anything could happen. +--- + libfprint/fpi-ssm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index 5367e32..5299e2d 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -317,7 +317,7 @@ void + fpi_ssm_jump_to_state (FpiSsm *machine, int state) + { + BUG_ON (machine->completed); +- BUG_ON (state >= machine->nr_states); ++ BUG_ON (state < 0 || state >= machine->nr_states); + machine->cur_state = state; + __ssm_call_handler (machine); + } +-- +2.24.1 + diff --git a/SOURCES/0057-fpi-device-Make-possible-to-set-a-DestroyNotify-for-.patch b/SOURCES/0057-fpi-device-Make-possible-to-set-a-DestroyNotify-for-.patch new file mode 100644 index 0000000..a5646fe --- /dev/null +++ b/SOURCES/0057-fpi-device-Make-possible-to-set-a-DestroyNotify-for-.patch @@ -0,0 +1,206 @@ +From 9f9a94d7a0c18dd62794f0172d3a306d2f38c4fd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 22 Nov 2019 17:11:29 +0100 +Subject: [PATCH 057/181] fpi-device: Make possible to set a DestroyNotify for + timeout data + +Since GSource data can be automatically cleaned up on source destruction, we +can mimic this for the devices timeout easily as well. + +Add an extra parameter, and let's use this cocci file to adapt all the +drivers like magic: + + @@ + expression e1, e2, e3, e4; + @@ + fpi_device_add_timeout (e1, e2, e3, e4 + + , NULL + ) +--- + libfprint/drivers/elan.c | 4 ++-- + libfprint/drivers/uru4000.c | 6 +++--- + libfprint/drivers/vfs0050.c | 4 ++-- + libfprint/drivers/vfs101.c | 2 +- + libfprint/drivers/vfs301.c | 2 +- + libfprint/drivers/vfs5011.c | 2 +- + libfprint/fp-device.c | 14 ++++++++------ + libfprint/fpi-device.h | 10 +++++----- + 8 files changed, 23 insertions(+), 21 deletions(-) + +diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c +index e2767dd..f9e8763 100644 +--- a/libfprint/drivers/elan.c ++++ b/libfprint/drivers/elan.c +@@ -756,7 +756,7 @@ calibrate_run_state (FpiSsm *ssm, FpDevice *dev) + self->calib_status = 0x01; + timeout = fpi_device_add_timeout (dev, 50, + fpi_ssm_next_state_timeout_cb, +- ssm); ++ ssm, NULL); + g_source_set_name (timeout, "calibrate_run_state"); + } + break; +@@ -1020,7 +1020,7 @@ dev_change_state (FpImageDevice *dev, FpImageDeviceState state) + self->dev_state_next = state; + timeout = fpi_device_add_timeout (FP_DEVICE (dev), 10, + elan_change_state_async, +- NULL); ++ NULL, NULL); + + name = g_strdup_printf ("dev_change_state to %d", state); + g_source_set_name (timeout, name); +diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c +index 7e28724..1deadd3 100644 +--- a/libfprint/drivers/uru4000.c ++++ b/libfprint/drivers/uru4000.c +@@ -875,7 +875,7 @@ rebootpwr_run_state (FpiSsm *ssm, FpDevice *_dev) + break; + + case REBOOTPWR_PAUSE: +- fpi_device_add_timeout (_dev, 10, rebootpwr_pause_cb, ssm); ++ fpi_device_add_timeout (_dev, 10, rebootpwr_pause_cb, ssm, NULL); + break; + } + } +@@ -971,7 +971,7 @@ powerup_run_state (FpiSsm *ssm, FpDevice *_dev) + break; + + case POWERUP_PAUSE: +- fpi_device_add_timeout (_dev, 10, powerup_pause_cb, ssm); ++ fpi_device_add_timeout (_dev, 10, powerup_pause_cb, ssm, NULL); + break; + + case POWERUP_CHALLENGE_RESPONSE: +@@ -1130,7 +1130,7 @@ init_run_state (FpiSsm *ssm, FpDevice *_dev) + self->scanpwr_irq_timeout = fpi_device_add_timeout (_dev, + 300, + init_scanpwr_timeout, +- ssm); ++ ssm, NULL); + break; + + case INIT_DONE: +diff --git a/libfprint/drivers/vfs0050.c b/libfprint/drivers/vfs0050.c +index 43252c0..6377639 100644 +--- a/libfprint/drivers/vfs0050.c ++++ b/libfprint/drivers/vfs0050.c +@@ -619,7 +619,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev) + + /* Wait for probable vdev->active changing */ + fpi_device_add_timeout (dev, VFS_SSM_TIMEOUT, +- fpi_ssm_next_state_timeout_cb, ssm); ++ fpi_ssm_next_state_timeout_cb, ssm, NULL); + break; + + case SSM_NEXT_RECEIVE: +@@ -639,7 +639,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev) + case SSM_WAIT_ANOTHER_SCAN: + /* Orange light is on now */ + fpi_device_add_timeout (dev, VFS_SSM_ORANGE_TIMEOUT, +- another_scan, ssm); ++ another_scan, ssm, NULL); + break; + + default: +diff --git a/libfprint/drivers/vfs101.c b/libfprint/drivers/vfs101.c +index 5dedab7..0df9b73 100644 +--- a/libfprint/drivers/vfs101.c ++++ b/libfprint/drivers/vfs101.c +@@ -376,7 +376,7 @@ async_sleep (unsigned int msec, + FpImageDevice *dev) + { + fpi_device_add_timeout (FP_DEVICE (dev), msec, +- fpi_ssm_next_state_timeout_cb, ssm); ++ fpi_ssm_next_state_timeout_cb, ssm, NULL); + } + + /* Swap ssm states */ +diff --git a/libfprint/drivers/vfs301.c b/libfprint/drivers/vfs301.c +index 7219792..1d0f066 100644 +--- a/libfprint/drivers/vfs301.c ++++ b/libfprint/drivers/vfs301.c +@@ -36,7 +36,7 @@ async_sleep (unsigned int msec, + { + /* Add timeout */ + fpi_device_add_timeout (FP_DEVICE (dev), msec, +- fpi_ssm_next_state_timeout_cb, ssm); ++ fpi_ssm_next_state_timeout_cb, ssm, NULL); + } + + static int +diff --git a/libfprint/drivers/vfs5011.c b/libfprint/drivers/vfs5011.c +index dbf8276..4fac03c 100644 +--- a/libfprint/drivers/vfs5011.c ++++ b/libfprint/drivers/vfs5011.c +@@ -706,7 +706,7 @@ activate_loop (FpiSsm *ssm, FpDevice *_dev) + case DEV_ACTIVATE_DATA_COMPLETE: + fpi_device_add_timeout (_dev, 1, + fpi_ssm_next_state_timeout_cb, +- ssm); ++ ssm, NULL); + + break; + +diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c +index 0a1f8de..182be51 100644 +--- a/libfprint/fp-device.c ++++ b/libfprint/fp-device.c +@@ -1475,7 +1475,8 @@ fpi_device_set_scan_type (FpDevice *device, + * @device: The #FpDevice + * @interval: The interval in milliseconds + * @func: The #FpTimeoutFunc to call on timeout +- * @user_data: User data to pass to the callback ++ * @user_data: (nullable): User data to pass to the callback ++ * @destroy_notify: (nullable): #GDestroyNotify for @user_data + * + * Register a timeout to run. Drivers should always make sure that timers are + * cancelled when appropriate. +@@ -1483,10 +1484,11 @@ fpi_device_set_scan_type (FpDevice *device, + * Returns: (transfer none): A newly created and attached #GSource + */ + GSource * +-fpi_device_add_timeout (FpDevice *device, +- gint interval, +- FpTimeoutFunc func, +- gpointer user_data) ++fpi_device_add_timeout (FpDevice *device, ++ gint interval, ++ FpTimeoutFunc func, ++ gpointer user_data, ++ GDestroyNotify destroy_notify) + { + FpDevicePrivate *priv = fp_device_get_instance_private (device); + FpDeviceTimeoutSource *source; +@@ -1497,7 +1499,7 @@ fpi_device_add_timeout (FpDevice *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_callback (&source->source, (GSourceFunc) func, user_data, destroy_notify); + g_source_set_ready_time (&source->source, + g_source_get_time (&source->source) + interval * (guint64) 1000); + priv->sources = g_slist_prepend (priv->sources, source); +diff --git a/libfprint/fpi-device.h b/libfprint/fpi-device.h +index d83a5a3..2333ae2 100644 +--- a/libfprint/fpi-device.h ++++ b/libfprint/fpi-device.h +@@ -203,11 +203,11 @@ void fpi_device_get_delete_data (FpDevice *device, + GCancellable *fpi_device_get_cancellable (FpDevice *device); + + +- +-GSource * fpi_device_add_timeout (FpDevice *device, +- gint interval, +- FpTimeoutFunc func, +- gpointer user_data); ++GSource * fpi_device_add_timeout (FpDevice *device, ++ gint interval, ++ FpTimeoutFunc func, ++ gpointer user_data, ++ GDestroyNotify destroy_notify); + + void fpi_device_set_nr_enroll_stages (FpDevice *device, + gint enroll_stages); +-- +2.24.1 + diff --git a/SOURCES/0058-fpi-ssm-Add-possibility-to-jump-to-a-state-or-next-o.patch b/SOURCES/0058-fpi-ssm-Add-possibility-to-jump-to-a-state-or-next-o.patch new file mode 100644 index 0000000..35631cd --- /dev/null +++ b/SOURCES/0058-fpi-ssm-Add-possibility-to-jump-to-a-state-or-next-o.patch @@ -0,0 +1,227 @@ +From d35cadd5fd81067bfc5bf6f5595b98d4227ad190 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 22 Nov 2019 17:19:27 +0100 +Subject: [PATCH 058/181] fpi-ssm: Add possibility to jump to a state (or next + one) with delay + +This allows to have an automatic cleanup of the timeout source when the +the callback is reached and to avoid to do further state changes in the +middle. +--- + doc/libfprint-sections.txt | 3 + + libfprint/fpi-ssm.c | 118 +++++++++++++++++++++++++++++++++++++ + libfprint/fpi-ssm.h | 6 ++ + 3 files changed, 127 insertions(+) + +diff --git a/doc/libfprint-sections.txt b/doc/libfprint-sections.txt +index 0abe584..9fb01bd 100644 +--- a/doc/libfprint-sections.txt ++++ b/doc/libfprint-sections.txt +@@ -215,7 +215,10 @@ fpi_ssm_free + fpi_ssm_start + fpi_ssm_start_subsm + fpi_ssm_next_state ++fpi_ssm_next_state_delayed + fpi_ssm_jump_to_state ++fpi_ssm_jump_to_state_delayed ++fpi_ssm_cancel_delayed_state_change + fpi_ssm_mark_completed + fpi_ssm_mark_failed + fpi_ssm_set_data +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index 5299e2d..38186d2 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -87,6 +87,7 @@ struct _FpiSsm + int nr_states; + int cur_state; + gboolean completed; ++ GSource *timeout; + GError *error; + FpiSsmCompletedCallback callback; + FpiSsmHandlerCallback handler; +@@ -170,6 +171,7 @@ fpi_ssm_free (FpiSsm *machine) + if (machine->ssm_data_destroy) + g_clear_pointer (&machine->ssm_data, machine->ssm_data_destroy); + g_clear_pointer (&machine->error, g_error_free); ++ g_clear_pointer (&machine->timeout, g_source_destroy); + g_free (machine); + } + +@@ -231,7 +233,9 @@ __subsm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + void + fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child) + { ++ BUG_ON (parent->timeout); + child->parentsm = parent; ++ g_clear_pointer (&parent->timeout, g_source_destroy); + fpi_ssm_start (child, __subsm_complete); + } + +@@ -246,7 +250,12 @@ void + fpi_ssm_mark_completed (FpiSsm *machine) + { + BUG_ON (machine->completed); ++ BUG_ON (machine->timeout); ++ BUG_ON (machine->timeout != NULL); ++ ++ g_clear_pointer (&machine->timeout, g_source_destroy); + machine->completed = TRUE; ++ + if (machine->error) + fp_dbg ("%p completed with error: %s", machine, machine->error->message); + else +@@ -297,6 +306,10 @@ fpi_ssm_next_state (FpiSsm *machine) + g_return_if_fail (machine != NULL); + + BUG_ON (machine->completed); ++ BUG_ON (machine->timeout != NULL); ++ ++ g_clear_pointer (&machine->timeout, g_source_destroy); ++ + machine->cur_state++; + if (machine->cur_state == machine->nr_states) + fpi_ssm_mark_completed (machine); +@@ -304,6 +317,56 @@ fpi_ssm_next_state (FpiSsm *machine) + __ssm_call_handler (machine); + } + ++void ++fpi_ssm_cancel_delayed_state_change (FpiSsm *machine) ++{ ++ g_return_if_fail (machine); ++ BUG_ON (machine->completed); ++ BUG_ON (machine->timeout == NULL); ++ ++ g_clear_pointer (&machine->timeout, g_source_destroy); ++} ++ ++static void ++on_device_timeout_next_state (FpDevice *dev, ++ gpointer user_data) ++{ ++ FpiSsm *machine = user_data; ++ ++ machine->timeout = NULL; ++ fpi_ssm_next_state (machine); ++} ++ ++/** ++ * fpi_ssm_next_state_delayed: ++ * @machine: an #FpiSsm state machine ++ * @delay: the milliseconds to wait before switching to the next state ++ * ++ * Iterate to next state of a state machine with a delay of @delay ms. 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_delayed (FpiSsm *machine, ++ int delay) ++{ ++ g_autofree char *source_name = NULL; ++ ++ g_return_if_fail (machine != NULL); ++ BUG_ON (machine->completed); ++ BUG_ON (machine->timeout != NULL); ++ ++ g_clear_pointer (&machine->timeout, g_source_destroy); ++ machine->timeout = fpi_device_add_timeout (machine->dev, delay, ++ on_device_timeout_next_state, ++ machine); ++ ++ source_name = g_strdup_printf ("[%s] ssm %p jump to next state %d", ++ fp_device_get_device_id (machine->dev), ++ machine, machine->cur_state + 1); ++ g_source_set_name (machine->timeout, source_name); ++} ++ + /** + * fpi_ssm_jump_to_state: + * @machine: an #FpiSsm state machine +@@ -318,10 +381,65 @@ fpi_ssm_jump_to_state (FpiSsm *machine, int state) + { + BUG_ON (machine->completed); + BUG_ON (state < 0 || state >= machine->nr_states); ++ BUG_ON (machine->timeout != NULL); ++ ++ g_clear_pointer (&machine->timeout, g_source_destroy); + machine->cur_state = state; + __ssm_call_handler (machine); + } + ++typedef struct ++{ ++ FpiSsm *machine; ++ int next_state; ++} FpiSsmJumpToStateDelayedData; ++ ++static void ++on_device_timeout_jump_to_state (FpDevice *dev, ++ gpointer user_data) ++{ ++ FpiSsmJumpToStateDelayedData *data = user_data; ++ ++ data->machine->timeout = NULL; ++ fpi_ssm_jump_to_state (data->machine, data->next_state); ++} ++ ++/** ++ * fpi_ssm_jump_to_state_delayed: ++ * @machine: an #FpiSsm state machine ++ * @state: the state to jump to ++ * @delay: the milliseconds to wait before switching to @state state ++ * ++ * Jump to the @state state with a delay of @delay milliseconds, bypassing ++ * intermediary states. ++ */ ++void ++fpi_ssm_jump_to_state_delayed (FpiSsm *machine, ++ int state, ++ int delay) ++{ ++ FpiSsmJumpToStateDelayedData *data; ++ g_autofree char *source_name = NULL; ++ ++ g_return_if_fail (machine != NULL); ++ BUG_ON (machine->completed); ++ BUG_ON (machine->timeout != NULL); ++ ++ data = g_new0 (FpiSsmJumpToStateDelayedData, 1); ++ data->machine = machine; ++ data->next_state = state; ++ ++ g_clear_pointer (&machine->timeout, g_source_destroy); ++ machine->timeout = fpi_device_add_timeout_full (machine->dev, delay, ++ on_device_timeout_jump_to_state, ++ data, g_free); ++ ++ source_name = g_strdup_printf ("[%s] ssm %p jump to state %d", ++ fp_device_get_device_id (machine->dev), ++ machine, state); ++ g_source_set_name (machine->timeout, source_name); ++} ++ + /** + * fpi_ssm_get_cur_state: + * @machine: an #FpiSsm state machine +diff --git a/libfprint/fpi-ssm.h b/libfprint/fpi-ssm.h +index 57e7d10..05e6cf0 100644 +--- a/libfprint/fpi-ssm.h ++++ b/libfprint/fpi-ssm.h +@@ -73,6 +73,12 @@ void fpi_ssm_start_subsm (FpiSsm *parent, + void fpi_ssm_next_state (FpiSsm *machine); + void fpi_ssm_jump_to_state (FpiSsm *machine, + int state); ++void fpi_ssm_next_state_delayed (FpiSsm *machine, ++ int delay); ++void fpi_ssm_jump_to_state_delayed (FpiSsm *machine, ++ int state, ++ int delay); ++void fpi_ssm_cancel_delayed_state_change (FpiSsm *machine); + void fpi_ssm_mark_completed (FpiSsm *machine); + void fpi_ssm_mark_failed (FpiSsm *machine, + GError *error); +-- +2.24.1 + diff --git a/SOURCES/0059-drivers-Use-fpi_ssm_next_state_delayed-instead-of-cu.patch b/SOURCES/0059-drivers-Use-fpi_ssm_next_state_delayed-instead-of-cu.patch new file mode 100644 index 0000000..1bda0a2 --- /dev/null +++ b/SOURCES/0059-drivers-Use-fpi_ssm_next_state_delayed-instead-of-cu.patch @@ -0,0 +1,263 @@ +From 4a98d79f9f4dc64d568b31f801f47cbbca3e5711 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 22 Nov 2019 18:22:50 +0100 +Subject: [PATCH 059/181] drivers: Use fpi_ssm_next_state_delayed instead of + custom callbacks + +As per this fpi_ssm_next_state_timeout_cb can be removed +--- + libfprint/drivers/elan.c | 7 +------ + libfprint/drivers/vfs0050.c | 3 +-- + libfprint/drivers/vfs101.c | 24 +++++++----------------- + libfprint/drivers/vfs301.c | 15 ++------------- + libfprint/drivers/vfs5011.c | 5 +---- + libfprint/fpi-ssm.c | 30 ++++-------------------------- + libfprint/fpi-ssm.h | 2 -- + 7 files changed, 16 insertions(+), 70 deletions(-) + +diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c +index f9e8763..f622988 100644 +--- a/libfprint/drivers/elan.c ++++ b/libfprint/drivers/elan.c +@@ -749,15 +749,10 @@ calibrate_run_state (FpiSsm *ssm, FpDevice *dev) + } + 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, NULL); +- g_source_set_name (timeout, "calibrate_run_state"); ++ fpi_ssm_next_state_delayed (ssm, 50); + } + break; + +diff --git a/libfprint/drivers/vfs0050.c b/libfprint/drivers/vfs0050.c +index 6377639..af70db5 100644 +--- a/libfprint/drivers/vfs0050.c ++++ b/libfprint/drivers/vfs0050.c +@@ -618,8 +618,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev) + clear_data (self); + + /* Wait for probable vdev->active changing */ +- fpi_device_add_timeout (dev, VFS_SSM_TIMEOUT, +- fpi_ssm_next_state_timeout_cb, ssm, NULL); ++ fpi_ssm_next_state_delayed (ssm, VFS_SSM_TIMEOUT); + break; + + case SSM_NEXT_RECEIVE: +diff --git a/libfprint/drivers/vfs101.c b/libfprint/drivers/vfs101.c +index 0df9b73..7020726 100644 +--- a/libfprint/drivers/vfs101.c ++++ b/libfprint/drivers/vfs101.c +@@ -369,16 +369,6 @@ async_load (FpiSsm *ssm, + async_load_cb, NULL); + } + +-/* Submit asynchronous sleep */ +-static void +-async_sleep (unsigned int msec, +- FpiSsm *ssm, +- FpImageDevice *dev) +-{ +- fpi_device_add_timeout (FP_DEVICE (dev), msec, +- fpi_ssm_next_state_timeout_cb, ssm, NULL); +-} +- + /* Swap ssm states */ + enum { + M_SWAP_SEND, +@@ -795,7 +785,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev) + + case M_LOOP_0_SLEEP: + /* Wait fingerprint scanning */ +- async_sleep (50, ssm, dev); ++ fpi_ssm_next_state_delayed (ssm, 50); + break; + + case M_LOOP_0_GET_STATE: +@@ -838,7 +828,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev) + img_extract (ssm, dev); + + /* Wait handling image */ +- async_sleep (10, ssm, dev); ++ fpi_ssm_next_state_delayed (ssm, 10); + break; + + case M_LOOP_0_CHECK_ACTION: +@@ -861,7 +851,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev) + if (vfs_finger_state (self) == VFS_FINGER_PRESENT) + { + fpi_image_device_report_finger_status (dev, TRUE); +- async_sleep (250, ssm, dev); ++ fpi_ssm_next_state_delayed (ssm, 250); + } + else + { +@@ -891,7 +881,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev) + + case M_LOOP_1_SLEEP: + /* Wait fingerprint scanning */ +- async_sleep (10, ssm, dev); ++ fpi_ssm_next_state_delayed (ssm, 10); + break; + + case M_LOOP_2_ABORT_PRINT: +@@ -927,7 +917,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev) + { + /* Wait aborting */ + self->counter++; +- async_sleep (100, ssm, dev); ++ fpi_ssm_next_state_delayed (ssm, 100); + } + else + { +@@ -1065,7 +1055,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev) + { + /* Wait aborting */ + self->counter++; +- async_sleep (100, ssm, dev); ++ fpi_ssm_next_state_delayed (ssm, 100); + } + else + { +@@ -1094,7 +1084,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev) + { + /* Wait removing finger */ + self->counter++; +- async_sleep (250, ssm, dev); ++ fpi_ssm_next_state_delayed (ssm, 250); + } + else + { +diff --git a/libfprint/drivers/vfs301.c b/libfprint/drivers/vfs301.c +index 1d0f066..3870879 100644 +--- a/libfprint/drivers/vfs301.c ++++ b/libfprint/drivers/vfs301.c +@@ -28,17 +28,6 @@ G_DEFINE_TYPE (FpDeviceVfs301, fpi_device_vfs301, FP_TYPE_IMAGE_DEVICE) + + /************************** GENERIC STUFF *************************************/ + +-/* Submit asynchronous sleep */ +-static void +-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, NULL); +-} +- + static int + submit_image (FpiSsm *ssm, + FpImageDevice *dev) +@@ -108,7 +97,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev) + + case M_WAIT_PRINT: + /* Wait fingerprint scanning */ +- async_sleep (200, ssm, dev); ++ fpi_ssm_next_state_delayed (ssm, 200); + break; + + case M_CHECK_PRINT: +@@ -126,7 +115,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev) + + case M_READ_PRINT_WAIT: + /* Wait fingerprint scanning */ +- async_sleep (200, ssm, dev); ++ fpi_ssm_next_state_delayed (ssm, 200); + break; + + case M_READ_PRINT_POLL: +diff --git a/libfprint/drivers/vfs5011.c b/libfprint/drivers/vfs5011.c +index 4fac03c..b769e31 100644 +--- a/libfprint/drivers/vfs5011.c ++++ b/libfprint/drivers/vfs5011.c +@@ -704,10 +704,7 @@ activate_loop (FpiSsm *ssm, FpDevice *_dev) + break; + + case DEV_ACTIVATE_DATA_COMPLETE: +- fpi_device_add_timeout (_dev, 1, +- fpi_ssm_next_state_timeout_cb, +- ssm, NULL); +- ++ fpi_ssm_next_state_delayed (ssm, 1); + break; + + case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE: +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index 38186d2..931c8fe 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -359,7 +359,7 @@ fpi_ssm_next_state_delayed (FpiSsm *machine, + g_clear_pointer (&machine->timeout, g_source_destroy); + machine->timeout = fpi_device_add_timeout (machine->dev, delay, + on_device_timeout_next_state, +- machine); ++ machine, NULL); + + source_name = g_strdup_printf ("[%s] ssm %p jump to next state %d", + fp_device_get_device_id (machine->dev), +@@ -430,9 +430,9 @@ fpi_ssm_jump_to_state_delayed (FpiSsm *machine, + data->next_state = state; + + g_clear_pointer (&machine->timeout, g_source_destroy); +- machine->timeout = fpi_device_add_timeout_full (machine->dev, delay, +- on_device_timeout_jump_to_state, +- data, g_free); ++ machine->timeout = fpi_device_add_timeout (machine->dev, delay, ++ on_device_timeout_jump_to_state, ++ data, g_free); + + source_name = g_strdup_printf ("[%s] ssm %p jump to state %d", + fp_device_get_device_id (machine->dev), +@@ -486,28 +486,6 @@ fpi_ssm_dup_error (FpiSsm *machine) + 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_device_add_timeout() callback, when the state +- * change needs to happen after a timeout. +- * +- * Make sure to pass the #FpiSsm as the `ssm_data` argument +- * for that fpi_device_add_timeout() 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 +diff --git a/libfprint/fpi-ssm.h b/libfprint/fpi-ssm.h +index 05e6cf0..b426fff 100644 +--- a/libfprint/fpi-ssm.h ++++ b/libfprint/fpi-ssm.h +@@ -93,8 +93,6 @@ int fpi_ssm_get_cur_state (FpiSsm *machine); + /* 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 unused_data, +-- +2.24.1 + diff --git a/SOURCES/0060-fpi-ssm-Clarify-the-ownership-of-error-in-fpi_ssm_ma.patch b/SOURCES/0060-fpi-ssm-Clarify-the-ownership-of-error-in-fpi_ssm_ma.patch new file mode 100644 index 0000000..908bed8 --- /dev/null +++ b/SOURCES/0060-fpi-ssm-Clarify-the-ownership-of-error-in-fpi_ssm_ma.patch @@ -0,0 +1,35 @@ +From a2ca701133742744edafb09d5ea5245ca1d3b621 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 22 Nov 2019 18:25:59 +0100 +Subject: [PATCH 060/181] fpi-ssm: Clarify the ownership of error in + fpi_ssm_mark_failed + +--- + libfprint/fpi-ssm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index 931c8fe..e2cb48a 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -272,7 +272,7 @@ fpi_ssm_mark_completed (FpiSsm *machine) + /** + * fpi_ssm_mark_failed: + * @machine: an #FpiSsm state machine +- * @error: a #GError ++ * @error: (transfer full): a #GError + * + * Mark a state machine as failed with @error as the error code, completing it. + */ +@@ -288,7 +288,7 @@ fpi_ssm_mark_failed (FpiSsm *machine, GError *error) + } + + fp_dbg ("SSM failed in state %d with error: %s", machine->cur_state, error->message); +- machine->error = error; ++ machine->error = g_steal_pointer (&error); + fpi_ssm_mark_completed (machine); + } + +-- +2.24.1 + diff --git a/SOURCES/0061-drivers-Use-SSM-delayed-actions-when-possible.patch b/SOURCES/0061-drivers-Use-SSM-delayed-actions-when-possible.patch new file mode 100644 index 0000000..4efa926 --- /dev/null +++ b/SOURCES/0061-drivers-Use-SSM-delayed-actions-when-possible.patch @@ -0,0 +1,170 @@ +From 651cc37ee0409af767447f626f6a90db50c016b0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 22 Nov 2019 18:39:02 +0100 +Subject: [PATCH 061/181] drivers: Use SSM delayed actions when possible + +--- + libfprint/drivers/uru4000.c | 72 ++++++++++++++----------------------- + libfprint/drivers/vfs0050.c | 13 +------ + libfprint/fpi-ssm.c | 3 +- + 3 files changed, 29 insertions(+), 59 deletions(-) + +diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c +index 1deadd3..e15f1ca 100644 +--- a/libfprint/drivers/uru4000.c ++++ b/libfprint/drivers/uru4000.c +@@ -829,26 +829,6 @@ enum rebootpwr_states { + REBOOTPWR_NUM_STATES, + }; + +-static void +-rebootpwr_pause_cb (FpDevice *dev, +- void *data) +-{ +- 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); +- } +-} +- + static void + rebootpwr_run_state (FpiSsm *ssm, FpDevice *_dev) + { +@@ -875,7 +855,17 @@ rebootpwr_run_state (FpiSsm *ssm, FpDevice *_dev) + break; + + case REBOOTPWR_PAUSE: +- fpi_device_add_timeout (_dev, 10, rebootpwr_pause_cb, ssm, NULL); ++ 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_delayed (ssm, 10, REBOOTPWR_GET_HWSTAT); ++ } + break; + } + } +@@ -916,30 +906,6 @@ enum powerup_states { + POWERUP_NUM_STATES, + }; + +-static void +-powerup_pause_cb (FpDevice *dev, +- void *data) +-{ +- 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); +- } +-} +- + static void + powerup_run_state (FpiSsm *ssm, FpDevice *_dev) + { +@@ -971,7 +937,21 @@ powerup_run_state (FpiSsm *ssm, FpDevice *_dev) + break; + + case POWERUP_PAUSE: +- fpi_device_add_timeout (_dev, 10, powerup_pause_cb, ssm, NULL); ++ 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_delayed (ssm, POWERUP_SET_HWSTAT, 10); ++ } ++ else ++ { ++ fpi_ssm_next_state_delayed (ssm, 10); ++ } + break; + + case POWERUP_CHALLENGE_RESPONSE: +diff --git a/libfprint/drivers/vfs0050.c b/libfprint/drivers/vfs0050.c +index af70db5..22e9ae9 100644 +--- a/libfprint/drivers/vfs0050.c ++++ b/libfprint/drivers/vfs0050.c +@@ -479,16 +479,6 @@ receive_callback (FpiUsbTransfer *transfer, FpDevice *device, + } + } + +-/* SSM stub to prepare device to another scan after orange light was on */ +-static void +-another_scan (FpDevice *dev, +- void *data) +-{ +- FpiSsm *ssm = data; +- +- fpi_ssm_jump_to_state (ssm, SSM_TURN_ON); +-} +- + /* Main SSM loop */ + static void + activate_ssm (FpiSsm *ssm, FpDevice *dev) +@@ -637,8 +627,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev) + + case SSM_WAIT_ANOTHER_SCAN: + /* Orange light is on now */ +- fpi_device_add_timeout (dev, VFS_SSM_ORANGE_TIMEOUT, +- another_scan, ssm, NULL); ++ fpi_ssm_jump_to_state_delayed (ssm, SSM_TURN_ON, VFS_SSM_ORANGE_TIMEOUT); + break; + + default: +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index e2cb48a..19712ef 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -168,6 +168,8 @@ fpi_ssm_free (FpiSsm *machine) + if (!machine) + return; + ++ BUG_ON (machine->timeout != NULL); ++ + if (machine->ssm_data_destroy) + g_clear_pointer (&machine->ssm_data, machine->ssm_data_destroy); + g_clear_pointer (&machine->error, g_error_free); +@@ -250,7 +252,6 @@ void + fpi_ssm_mark_completed (FpiSsm *machine) + { + BUG_ON (machine->completed); +- BUG_ON (machine->timeout); + BUG_ON (machine->timeout != NULL); + + g_clear_pointer (&machine->timeout, g_source_destroy); +-- +2.24.1 + diff --git a/SOURCES/0062-fpi-ssm-Make-delayed-actions-cancellable.patch b/SOURCES/0062-fpi-ssm-Make-delayed-actions-cancellable.patch new file mode 100644 index 0000000..f8123c2 --- /dev/null +++ b/SOURCES/0062-fpi-ssm-Make-delayed-actions-cancellable.patch @@ -0,0 +1,424 @@ +From 37a007317e5de27eb68a667bace42961c5c73b33 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 28 Nov 2019 19:24:55 +0100 +Subject: [PATCH 062/181] fpi-ssm: Make delayed actions cancellable + +Add a GCancellable parameter to fpi_ssm_nex_state_delayed and +fpi_ssm_jump_to_state_delayed() so that it's possible to cancel an action +from the caller and in case the driver wants to cancel a delayed operation +when a device action has been cancelled. +--- + libfprint/drivers/elan.c | 2 +- + libfprint/drivers/uru4000.c | 6 +- + libfprint/drivers/vfs0050.c | 5 +- + libfprint/drivers/vfs101.c | 14 ++-- + libfprint/drivers/vfs301.c | 4 +- + libfprint/drivers/vfs5011.c | 2 +- + libfprint/fpi-ssm.c | 123 ++++++++++++++++++++++++++++++------ + libfprint/fpi-ssm.h | 12 ++-- + 8 files changed, 127 insertions(+), 41 deletions(-) + +diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c +index f622988..7c7fb26 100644 +--- a/libfprint/drivers/elan.c ++++ b/libfprint/drivers/elan.c +@@ -752,7 +752,7 @@ calibrate_run_state (FpiSsm *ssm, FpDevice *dev) + if (self->calib_status == 0x00 && + self->last_read[0] == 0x01) + self->calib_status = 0x01; +- fpi_ssm_next_state_delayed (ssm, 50); ++ fpi_ssm_next_state_delayed (ssm, 50, NULL); + } + break; + +diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c +index e15f1ca..122544d 100644 +--- a/libfprint/drivers/uru4000.c ++++ b/libfprint/drivers/uru4000.c +@@ -864,7 +864,7 @@ rebootpwr_run_state (FpiSsm *ssm, FpDevice *_dev) + } + else + { +- fpi_ssm_jump_to_state_delayed (ssm, 10, REBOOTPWR_GET_HWSTAT); ++ fpi_ssm_jump_to_state_delayed (ssm, 10, REBOOTPWR_GET_HWSTAT, NULL); + } + break; + } +@@ -946,11 +946,11 @@ powerup_run_state (FpiSsm *ssm, FpDevice *_dev) + } + else if (!self->profile->auth_cr) + { +- fpi_ssm_jump_to_state_delayed (ssm, POWERUP_SET_HWSTAT, 10); ++ fpi_ssm_jump_to_state_delayed (ssm, POWERUP_SET_HWSTAT, 10, NULL); + } + else + { +- fpi_ssm_next_state_delayed (ssm, 10); ++ fpi_ssm_next_state_delayed (ssm, 10, NULL); + } + break; + +diff --git a/libfprint/drivers/vfs0050.c b/libfprint/drivers/vfs0050.c +index 22e9ae9..9b99dc3 100644 +--- a/libfprint/drivers/vfs0050.c ++++ b/libfprint/drivers/vfs0050.c +@@ -608,7 +608,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev) + clear_data (self); + + /* Wait for probable vdev->active changing */ +- fpi_ssm_next_state_delayed (ssm, VFS_SSM_TIMEOUT); ++ fpi_ssm_next_state_delayed (ssm, VFS_SSM_TIMEOUT, NULL); + break; + + case SSM_NEXT_RECEIVE: +@@ -627,7 +627,8 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev) + + case SSM_WAIT_ANOTHER_SCAN: + /* Orange light is on now */ +- fpi_ssm_jump_to_state_delayed (ssm, SSM_TURN_ON, VFS_SSM_ORANGE_TIMEOUT); ++ fpi_ssm_jump_to_state_delayed (ssm, SSM_TURN_ON, VFS_SSM_ORANGE_TIMEOUT, ++ NULL); + break; + + default: +diff --git a/libfprint/drivers/vfs101.c b/libfprint/drivers/vfs101.c +index 7020726..ccce7db 100644 +--- a/libfprint/drivers/vfs101.c ++++ b/libfprint/drivers/vfs101.c +@@ -785,7 +785,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev) + + case M_LOOP_0_SLEEP: + /* Wait fingerprint scanning */ +- fpi_ssm_next_state_delayed (ssm, 50); ++ fpi_ssm_next_state_delayed (ssm, 50, NULL); + break; + + case M_LOOP_0_GET_STATE: +@@ -828,7 +828,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev) + img_extract (ssm, dev); + + /* Wait handling image */ +- fpi_ssm_next_state_delayed (ssm, 10); ++ fpi_ssm_next_state_delayed (ssm, 10, NULL); + break; + + case M_LOOP_0_CHECK_ACTION: +@@ -851,7 +851,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev) + if (vfs_finger_state (self) == VFS_FINGER_PRESENT) + { + fpi_image_device_report_finger_status (dev, TRUE); +- fpi_ssm_next_state_delayed (ssm, 250); ++ fpi_ssm_next_state_delayed (ssm, 250, NULL); + } + else + { +@@ -881,7 +881,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev) + + case M_LOOP_1_SLEEP: + /* Wait fingerprint scanning */ +- fpi_ssm_next_state_delayed (ssm, 10); ++ fpi_ssm_next_state_delayed (ssm, 10, NULL); + break; + + case M_LOOP_2_ABORT_PRINT: +@@ -917,7 +917,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev) + { + /* Wait aborting */ + self->counter++; +- fpi_ssm_next_state_delayed (ssm, 100); ++ fpi_ssm_next_state_delayed (ssm, 100, NULL); + } + else + { +@@ -1055,7 +1055,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev) + { + /* Wait aborting */ + self->counter++; +- fpi_ssm_next_state_delayed (ssm, 100); ++ fpi_ssm_next_state_delayed (ssm, 100, NULL); + } + else + { +@@ -1084,7 +1084,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev) + { + /* Wait removing finger */ + self->counter++; +- fpi_ssm_next_state_delayed (ssm, 250); ++ fpi_ssm_next_state_delayed (ssm, 250, NULL); + } + else + { +diff --git a/libfprint/drivers/vfs301.c b/libfprint/drivers/vfs301.c +index 3870879..f912a36 100644 +--- a/libfprint/drivers/vfs301.c ++++ b/libfprint/drivers/vfs301.c +@@ -97,7 +97,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev) + + case M_WAIT_PRINT: + /* Wait fingerprint scanning */ +- fpi_ssm_next_state_delayed (ssm, 200); ++ fpi_ssm_next_state_delayed (ssm, 200, NULL); + break; + + case M_CHECK_PRINT: +@@ -115,7 +115,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev) + + case M_READ_PRINT_WAIT: + /* Wait fingerprint scanning */ +- fpi_ssm_next_state_delayed (ssm, 200); ++ fpi_ssm_next_state_delayed (ssm, 200, NULL); + break; + + case M_READ_PRINT_POLL: +diff --git a/libfprint/drivers/vfs5011.c b/libfprint/drivers/vfs5011.c +index b769e31..ef318f2 100644 +--- a/libfprint/drivers/vfs5011.c ++++ b/libfprint/drivers/vfs5011.c +@@ -704,7 +704,7 @@ activate_loop (FpiSsm *ssm, FpDevice *_dev) + break; + + case DEV_ACTIVATE_DATA_COMPLETE: +- fpi_ssm_next_state_delayed (ssm, 1); ++ fpi_ssm_next_state_delayed (ssm, 1, NULL); + break; + + case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE: +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index 19712ef..0f54b1d 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -88,6 +88,8 @@ struct _FpiSsm + int cur_state; + gboolean completed; + GSource *timeout; ++ GCancellable *cancellable; ++ gulong cancellable_id; + GError *error; + FpiSsmCompletedCallback callback; + FpiSsmHandlerCallback handler; +@@ -155,6 +157,81 @@ fpi_ssm_get_data (FpiSsm *machine) + return machine->ssm_data; + } + ++static void ++fpi_ssm_clear_delayed_action (FpiSsm *machine) ++{ ++ if (machine->cancellable_id) ++ { ++ g_cancellable_disconnect (machine->cancellable, machine->cancellable_id); ++ machine->cancellable_id = 0; ++ } ++ ++ g_clear_object (&machine->cancellable); ++ g_clear_pointer (&machine->timeout, g_source_destroy); ++} ++ ++typedef struct _CancelledActionIdleData ++{ ++ gulong cancellable_id; ++ GCancellable *cancellable; ++} CancelledActionIdleData; ++ ++static gboolean ++on_delayed_action_cancelled_idle (gpointer user_data) ++{ ++ CancelledActionIdleData *data = user_data; ++ ++ g_cancellable_disconnect (data->cancellable, data->cancellable_id); ++ g_object_unref (data->cancellable); ++ g_free (data); ++ ++ return G_SOURCE_REMOVE; ++} ++ ++static void ++on_delayed_action_cancelled (GCancellable *cancellable, ++ FpiSsm *machine) ++{ ++ CancelledActionIdleData *data; ++ ++ g_clear_pointer (&machine->timeout, g_source_destroy); ++ ++ data = g_new0 (CancelledActionIdleData, 1); ++ data->cancellable = g_steal_pointer (&machine->cancellable); ++ data->cancellable_id = machine->cancellable_id; ++ machine->cancellable_id = 0; ++ ++ g_idle_add_full (G_PRIORITY_HIGH_IDLE, on_delayed_action_cancelled_idle, ++ data, NULL); ++} ++ ++static void ++fpi_ssm_set_delayed_action_timeout (FpiSsm *machine, ++ int delay, ++ FpTimeoutFunc callback, ++ GCancellable *cancellable, ++ gpointer user_data, ++ GDestroyNotify destroy_func) ++{ ++ BUG_ON (machine->completed); ++ BUG_ON (machine->timeout != NULL); ++ ++ fpi_ssm_clear_delayed_action (machine); ++ ++ if (cancellable != NULL) ++ { ++ g_set_object (&machine->cancellable, cancellable); ++ ++ machine->cancellable_id = ++ g_cancellable_connect (machine->cancellable, ++ G_CALLBACK (on_delayed_action_cancelled), ++ machine, NULL); ++ } ++ ++ machine->timeout = fpi_device_add_timeout (machine->dev, delay, callback, ++ user_data, destroy_func); ++} ++ + /** + * fpi_ssm_free: + * @machine: an #FpiSsm state machine +@@ -173,7 +250,7 @@ fpi_ssm_free (FpiSsm *machine) + if (machine->ssm_data_destroy) + g_clear_pointer (&machine->ssm_data, machine->ssm_data_destroy); + g_clear_pointer (&machine->error, g_error_free); +- g_clear_pointer (&machine->timeout, g_source_destroy); ++ fpi_ssm_clear_delayed_action (machine); + g_free (machine); + } + +@@ -254,7 +331,8 @@ fpi_ssm_mark_completed (FpiSsm *machine) + BUG_ON (machine->completed); + BUG_ON (machine->timeout != NULL); + +- g_clear_pointer (&machine->timeout, g_source_destroy); ++ fpi_ssm_clear_delayed_action (machine); ++ + machine->completed = TRUE; + + if (machine->error) +@@ -309,7 +387,7 @@ fpi_ssm_next_state (FpiSsm *machine) + BUG_ON (machine->completed); + BUG_ON (machine->timeout != NULL); + +- g_clear_pointer (&machine->timeout, g_source_destroy); ++ fpi_ssm_clear_delayed_action (machine); + + machine->cur_state++; + if (machine->cur_state == machine->nr_states) +@@ -325,7 +403,7 @@ fpi_ssm_cancel_delayed_state_change (FpiSsm *machine) + BUG_ON (machine->completed); + BUG_ON (machine->timeout == NULL); + +- g_clear_pointer (&machine->timeout, g_source_destroy); ++ fpi_ssm_clear_delayed_action (machine); + } + + static void +@@ -342,25 +420,26 @@ on_device_timeout_next_state (FpDevice *dev, + * fpi_ssm_next_state_delayed: + * @machine: an #FpiSsm state machine + * @delay: the milliseconds to wait before switching to the next state ++ * @cancellable: (nullable): a #GCancellable to cancel the delayed operation + * + * Iterate to next state of a state machine with a delay of @delay ms. If the + * current state is the last state, then the state machine will be marked as + * completed, as if calling fpi_ssm_mark_completed(). ++ * Passing a valid #GCancellable will cause the action to be cancelled when ++ * @cancellable is. + */ + void +-fpi_ssm_next_state_delayed (FpiSsm *machine, +- int delay) ++fpi_ssm_next_state_delayed (FpiSsm *machine, ++ int delay, ++ GCancellable *cancellable) + { + g_autofree char *source_name = NULL; + + g_return_if_fail (machine != NULL); +- BUG_ON (machine->completed); +- BUG_ON (machine->timeout != NULL); + +- g_clear_pointer (&machine->timeout, g_source_destroy); +- machine->timeout = fpi_device_add_timeout (machine->dev, delay, +- on_device_timeout_next_state, +- machine, NULL); ++ fpi_ssm_set_delayed_action_timeout (machine, delay, ++ on_device_timeout_next_state, cancellable, ++ machine, NULL); + + source_name = g_strdup_printf ("[%s] ssm %p jump to next state %d", + fp_device_get_device_id (machine->dev), +@@ -384,7 +463,8 @@ fpi_ssm_jump_to_state (FpiSsm *machine, int state) + BUG_ON (state < 0 || state >= machine->nr_states); + BUG_ON (machine->timeout != NULL); + +- g_clear_pointer (&machine->timeout, g_source_destroy); ++ fpi_ssm_clear_delayed_action (machine); ++ + machine->cur_state = state; + __ssm_call_handler (machine); + } +@@ -410,14 +490,18 @@ on_device_timeout_jump_to_state (FpDevice *dev, + * @machine: an #FpiSsm state machine + * @state: the state to jump to + * @delay: the milliseconds to wait before switching to @state state ++ * @cancellable: (nullable): a #GCancellable to cancel the delayed operation + * + * Jump to the @state state with a delay of @delay milliseconds, bypassing + * intermediary states. ++ * Passing a valid #GCancellable will cause the action to be cancelled when ++ * @cancellable is. + */ + void +-fpi_ssm_jump_to_state_delayed (FpiSsm *machine, +- int state, +- int delay) ++fpi_ssm_jump_to_state_delayed (FpiSsm *machine, ++ int state, ++ int delay, ++ GCancellable *cancellable) + { + FpiSsmJumpToStateDelayedData *data; + g_autofree char *source_name = NULL; +@@ -430,10 +514,9 @@ fpi_ssm_jump_to_state_delayed (FpiSsm *machine, + data->machine = machine; + data->next_state = state; + +- g_clear_pointer (&machine->timeout, g_source_destroy); +- machine->timeout = fpi_device_add_timeout (machine->dev, delay, +- on_device_timeout_jump_to_state, +- data, g_free); ++ fpi_ssm_set_delayed_action_timeout (machine, delay, ++ on_device_timeout_jump_to_state, ++ cancellable, data, g_free); + + source_name = g_strdup_printf ("[%s] ssm %p jump to state %d", + fp_device_get_device_id (machine->dev), +diff --git a/libfprint/fpi-ssm.h b/libfprint/fpi-ssm.h +index b426fff..8dff27d 100644 +--- a/libfprint/fpi-ssm.h ++++ b/libfprint/fpi-ssm.h +@@ -73,11 +73,13 @@ void fpi_ssm_start_subsm (FpiSsm *parent, + void fpi_ssm_next_state (FpiSsm *machine); + void fpi_ssm_jump_to_state (FpiSsm *machine, + int state); +-void fpi_ssm_next_state_delayed (FpiSsm *machine, +- int delay); +-void fpi_ssm_jump_to_state_delayed (FpiSsm *machine, +- int state, +- int delay); ++void fpi_ssm_next_state_delayed (FpiSsm *machine, ++ int delay, ++ GCancellable *cancellable); ++void fpi_ssm_jump_to_state_delayed (FpiSsm *machine, ++ int state, ++ int delay, ++ GCancellable *cancellable); + void fpi_ssm_cancel_delayed_state_change (FpiSsm *machine); + void fpi_ssm_mark_completed (FpiSsm *machine); + void fpi_ssm_mark_failed (FpiSsm *machine, +-- +2.24.1 + diff --git a/SOURCES/0063-fpi-ssm-Bug-on-handler-set-to-a-NULL-function.patch b/SOURCES/0063-fpi-ssm-Bug-on-handler-set-to-a-NULL-function.patch new file mode 100644 index 0000000..ff9d36b --- /dev/null +++ b/SOURCES/0063-fpi-ssm-Bug-on-handler-set-to-a-NULL-function.patch @@ -0,0 +1,26 @@ +From dac6c01df94333686d810a049dedfb32ee8b132b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 28 Nov 2019 20:15:21 +0100 +Subject: [PATCH 063/181] fpi-ssm: Bug on handler set to a NULL function + +We would crash otherwise, while this is quite obvious there was no code +enforcing this. +--- + libfprint/fpi-ssm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index 0f54b1d..4498ce9 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -114,6 +114,7 @@ fpi_ssm_new (FpDevice *dev, + FpiSsm *machine; + + BUG_ON (nr_states < 1); ++ BUG_ON (handler == NULL); + + machine = g_new0 (FpiSsm, 1); + machine->handler = handler; +-- +2.24.1 + diff --git a/SOURCES/0064-fpi-ssm-Mark-a-fpi-ssm-completed-on-delay.patch b/SOURCES/0064-fpi-ssm-Mark-a-fpi-ssm-completed-on-delay.patch new file mode 100644 index 0000000..bdc0242 --- /dev/null +++ b/SOURCES/0064-fpi-ssm-Mark-a-fpi-ssm-completed-on-delay.patch @@ -0,0 +1,78 @@ +From 370137b97f53cec46750d2c984a3861d306bcb9d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 3 Dec 2019 17:22:20 +0100 +Subject: [PATCH 064/181] fpi-ssm: Mark a fpi-ssm completed on delay + +--- + libfprint/fpi-ssm.c | 40 ++++++++++++++++++++++++++++++++++++++++ + libfprint/fpi-ssm.h | 3 +++ + 2 files changed, 43 insertions(+) + +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index 4498ce9..09a31e3 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -349,6 +349,46 @@ fpi_ssm_mark_completed (FpiSsm *machine) + fpi_ssm_free (machine); + } + ++static void ++on_device_timeout_complete (FpDevice *dev, ++ gpointer user_data) ++{ ++ FpiSsm *machine = user_data; ++ ++ machine->timeout = NULL; ++ fpi_ssm_mark_completed (machine); ++} ++ ++/** ++ * fpi_ssm_mark_completed_delayed: ++ * @machine: an #FpiSsm state machine ++ * @delay: the milliseconds to wait before switching to the next state ++ * @cancellable: (nullable): a #GCancellable to cancel the delayed operation ++ * ++ * Mark a ssm as completed successfully with a delay of @delay ms. ++ * The callback set when creating the state machine with fpi_ssm_new () will be ++ * called when the timeout is over. ++ * The request can be cancelled passing a #GCancellable as @cancellable. ++ */ ++void ++fpi_ssm_mark_completed_delayed (FpiSsm *machine, ++ int delay, ++ GCancellable *cancellable) ++{ ++ g_autofree char *source_name = NULL; ++ ++ g_return_if_fail (machine != NULL); ++ ++ fpi_ssm_set_delayed_action_timeout (machine, delay, ++ on_device_timeout_complete, cancellable, ++ machine, NULL); ++ ++ source_name = g_strdup_printf ("[%s] ssm %p complete %d", ++ fp_device_get_device_id (machine->dev), ++ machine, machine->cur_state + 1); ++ g_source_set_name (machine->timeout, source_name); ++} ++ + /** + * fpi_ssm_mark_failed: + * @machine: an #FpiSsm state machine +diff --git a/libfprint/fpi-ssm.h b/libfprint/fpi-ssm.h +index 8dff27d..3ef653e 100644 +--- a/libfprint/fpi-ssm.h ++++ b/libfprint/fpi-ssm.h +@@ -82,6 +82,9 @@ void fpi_ssm_jump_to_state_delayed (FpiSsm *machine, + GCancellable *cancellable); + void fpi_ssm_cancel_delayed_state_change (FpiSsm *machine); + void fpi_ssm_mark_completed (FpiSsm *machine); ++void fpi_ssm_mark_completed_delayed (FpiSsm *machine, ++ int delay, ++ GCancellable *cancellable); + void fpi_ssm_mark_failed (FpiSsm *machine, + GError *error); + void fpi_ssm_set_data (FpiSsm *machine, +-- +2.24.1 + diff --git a/SOURCES/0065-tests-Fix-image-writing-on-big-endian.patch b/SOURCES/0065-tests-Fix-image-writing-on-big-endian.patch new file mode 100644 index 0000000..963b1c2 --- /dev/null +++ b/SOURCES/0065-tests-Fix-image-writing-on-big-endian.patch @@ -0,0 +1,35 @@ +From 1dc9e06987c3787c3e6177fd010e5b0d5eab2ad9 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Wed, 4 Dec 2019 13:21:11 +0100 +Subject: [PATCH 065/181] tests: Fix image writing on big endian + +The code tried to only write the RGB bytes of FORMAT_RGB24, however, the +in-memory layout is different on big-endian which would result in the +wrong bytes being written. + +Fix this by simply also writing the byte we do not care about. +--- + tests/capture.py | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/tests/capture.py b/tests/capture.py +index 2ad9385..a7b7583 100755 +--- a/tests/capture.py ++++ b/tests/capture.py +@@ -36,10 +36,12 @@ c_buf = c_img.get_data() + + for x in range(width): + for y in range(height): ++ # The upper byte is don't care, but the location depends on endianness, ++ # so just set all of them. + 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_buf[y * c_rowstride + x * 4 + 3] = buf[y * width + x] + + c_img.mark_dirty() + c_img.write_to_png(sys.argv[1]) +-- +2.24.1 + diff --git a/SOURCES/0066-fpi-usb-Use-unsigned-length-for-USB-async-transfers.patch b/SOURCES/0066-fpi-usb-Use-unsigned-length-for-USB-async-transfers.patch new file mode 100644 index 0000000..4aed89a --- /dev/null +++ b/SOURCES/0066-fpi-usb-Use-unsigned-length-for-USB-async-transfers.patch @@ -0,0 +1,64 @@ +From 2af78ce8e06f513b96afb639a1406c116b77ecc2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 3 Dec 2019 19:34:58 +0100 +Subject: [PATCH 066/181] fpi-usb: Use unsigned length for USB async transfers + +Properly follow function signature using a temporary gsize variable address +to make the function use the same pointer type and avoid troubles at +deferencing it, while use automatic-casting to switch to signed one if +transfer succeeded. +--- + libfprint/fpi-usb-transfer.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/libfprint/fpi-usb-transfer.c b/libfprint/fpi-usb-transfer.c +index 64d706f..08e75cb 100644 +--- a/libfprint/fpi-usb-transfer.c ++++ b/libfprint/fpi-usb-transfer.c +@@ -454,6 +454,7 @@ fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer, + GError **error) + { + gboolean res; ++ gsize actual_length; + + g_return_val_if_fail (transfer, FALSE); + +@@ -469,7 +470,7 @@ fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer, + transfer->endpoint, + transfer->buffer, + transfer->length, +- &transfer->actual_length, ++ &actual_length, + timeout_ms, + NULL, + error); +@@ -485,7 +486,7 @@ fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer, + transfer->idx, + transfer->buffer, + transfer->length, +- &transfer->actual_length, ++ &actual_length, + timeout_ms, + NULL, + error); +@@ -496,7 +497,7 @@ fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer, + transfer->endpoint, + transfer->buffer, + transfer->length, +- &transfer->actual_length, ++ &actual_length, + timeout_ms, + NULL, + error); +@@ -511,6 +512,8 @@ fpi_usb_transfer_submit_sync (FpiUsbTransfer *transfer, + + if (!res) + transfer->actual_length = -1; ++ else ++ transfer->actual_length = actual_length; + + return res; + } +-- +2.24.1 + diff --git a/SOURCES/0067-drivers-examples-Don-t-use-Wno-pointer-sign-and-fix-.patch b/SOURCES/0067-drivers-examples-Don-t-use-Wno-pointer-sign-and-fix-.patch new file mode 100644 index 0000000..c5da439 --- /dev/null +++ b/SOURCES/0067-drivers-examples-Don-t-use-Wno-pointer-sign-and-fix-.patch @@ -0,0 +1,90 @@ +From 34b61d11546e764b08bc97276b102560fb899959 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 3 Dec 2019 19:36:26 +0100 +Subject: [PATCH 067/181] drivers, examples: Don't use -Wno-pointer-sign and + fix relative errors + +--- + examples/storage.c | 2 +- + libfprint/drivers/synaptics/synaptics.c | 4 ++-- + libfprint/drivers/upekts.c | 2 +- + libfprint/drivers/vfs0050.c | 2 +- + meson.build | 1 - + 5 files changed, 5 insertions(+), 6 deletions(-) + +diff --git a/examples/storage.c b/examples/storage.c +index 932163e..db35854 100644 +--- a/examples/storage.c ++++ b/examples/storage.c +@@ -57,7 +57,7 @@ load_data (void) + GVariantDict *res; + GVariant *var; + g_autofree gchar *contents = NULL; +- gssize length = 0; ++ gsize length = 0; + + if (!g_file_get_contents (STORAGE_FILE, &contents, &length, NULL)) + { +diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c +index 1524c45..247b658 100644 +--- a/libfprint/drivers/synaptics/synaptics.c ++++ b/libfprint/drivers/synaptics/synaptics.c +@@ -407,7 +407,7 @@ static gboolean + parse_print_data (GVariant *data, + guint8 *finger, + const guint8 **user_id, +- gssize *user_id_len) ++ gsize *user_id_len) + { + g_autoptr(GVariant) user_id_var = NULL; + +@@ -506,7 +506,7 @@ 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; ++ userid = (gchar *) 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, +diff --git a/libfprint/drivers/upekts.c b/libfprint/drivers/upekts.c +index 05cd9c5..6ce8136 100644 +--- a/libfprint/drivers/upekts.c ++++ b/libfprint/drivers/upekts.c +@@ -375,7 +375,7 @@ read_msg_cb (FpiUsbTransfer *transfer, FpDevice *device, + goto err; + } + +- if (strncmp (udata->buffer, "Ciao", 4) != 0) ++ if (strncmp ((char *) udata->buffer, "Ciao", 4) != 0) + { + fp_err ("no Ciao for you!!"); + error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, +diff --git a/libfprint/drivers/vfs0050.c b/libfprint/drivers/vfs0050.c +index 9b99dc3..bb6851f 100644 +--- a/libfprint/drivers/vfs0050.c ++++ b/libfprint/drivers/vfs0050.c +@@ -399,7 +399,7 @@ interrupt_callback (FpiUsbTransfer *transfer, FpDevice *device, + gpointer user_data, GError *error) + { + FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (device); +- char *interrupt = transfer->buffer; ++ unsigned char *interrupt = transfer->buffer; + + /* we expect a cancellation error when the device is deactivating + * go into the SSM_CLEAR_EP2 state in that case. */ +diff --git a/meson.build b/meson.build +index ef352ba..54761c4 100644 +--- a/meson.build ++++ b/meson.build +@@ -31,7 +31,6 @@ common_cflags = cc.get_supported_arguments([ + '-Wunused', + '-Wstrict-prototypes', + '-Werror-implicit-function-declaration', +- '-Wno-pointer-sign', + '-Wshadow', + '-DGLIB_VERSION_MIN_REQUIRED=' + glib_version_def, + '-DGLIB_VERSION_MAX_ALLOWED=' + glib_version_def, +-- +2.24.1 + diff --git a/SOURCES/0068-fp-print-Clear-the-data-not-the-description-when-set.patch b/SOURCES/0068-fp-print-Clear-the-data-not-the-description-when-set.patch new file mode 100644 index 0000000..be4e3f1 --- /dev/null +++ b/SOURCES/0068-fp-print-Clear-the-data-not-the-description-when-set.patch @@ -0,0 +1,26 @@ +From d8b15d9c655d329ccb91d0d6b31e6109651a1af6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 3 Dec 2019 19:53:19 +0100 +Subject: [PATCH 068/181] fp-print: Clear the data not the description when + setting the property + +--- + libfprint/fp-print.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c +index ddf8747..e7b119a 100644 +--- a/libfprint/fp-print.c ++++ b/libfprint/fp-print.c +@@ -207,7 +207,7 @@ fp_print_set_property (GObject *object, + break; + + case PROP_FPI_DATA: +- g_clear_pointer (&self->description, g_variant_unref); ++ g_clear_pointer (&self->data, g_variant_unref); + self->data = g_value_dup_variant (value); + break; + +-- +2.24.1 + diff --git a/SOURCES/0069-meson-Use-add_project_arguments-for-common-cflags.patch b/SOURCES/0069-meson-Use-add_project_arguments-for-common-cflags.patch new file mode 100644 index 0000000..7a6871f --- /dev/null +++ b/SOURCES/0069-meson-Use-add_project_arguments-for-common-cflags.patch @@ -0,0 +1,107 @@ +From c23e2719bac6d5b1c832ce06d4bc2358f532eb19 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 12:32:14 +0100 +Subject: [PATCH 069/181] meson: Use add_project_arguments for common cflags + +We were passing around the common cflags and setting them for each library +or executable, but this is just a repetition given we can just use +add_project_arguments for this. +--- + demo/meson.build | 5 +---- + examples/meson.build | 6 ++---- + libfprint/meson.build | 2 +- + meson.build | 13 ++++++++----- + 4 files changed, 12 insertions(+), 14 deletions(-) + +diff --git a/demo/meson.build b/demo/meson.build +index bf7a7ee..279a43c 100644 +--- a/demo/meson.build ++++ b/demo/meson.build +@@ -13,10 +13,7 @@ executable('gtk-libfprint-test', + include_directories: [ + root_inc, + ], +- c_args: [ +- common_cflags, +- '-DPACKAGE_VERSION="' + meson.project_version() + '"' +- ], ++ c_args: '-DPACKAGE_VERSION="' + meson.project_version() + '"', + install: true, + install_dir: bindir) + +diff --git a/examples/meson.build b/examples/meson.build +index ff03ac6..eef8c3f 100644 +--- a/examples/meson.build ++++ b/examples/meson.build +@@ -6,8 +6,7 @@ foreach example: examples + dependencies: [ libfprint_dep, glib_dep ], + include_directories: [ + root_inc, +- ], +- c_args: common_cflags) ++ ]) + endforeach + + executable('cpp-test', +@@ -15,5 +14,4 @@ executable('cpp-test', + dependencies: libfprint_dep, + include_directories: [ + root_inc, +- ], +- c_args: common_cflags) ++ ]) +diff --git a/libfprint/meson.build b/libfprint/meson.build +index f77965a..964744e 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -188,7 +188,7 @@ libfprint = library('fprint', + drivers_sources + nbis_sources + other_sources, + soversion: soversion, + version: libversion, +- c_args: common_cflags + drivers_cflags, ++ c_args: drivers_cflags, + include_directories: [ + root_inc, + include_directories('nbis/include'), +diff --git a/meson.build b/meson.build +index 54761c4..09abc1f 100644 +--- a/meson.build ++++ b/meson.build +@@ -10,9 +10,6 @@ project('libfprint', [ 'c', 'cpp' ], + + gnome = import('gnome') + +-add_project_arguments([ '-D_GNU_SOURCE' ], language: 'c') +-add_project_arguments([ '-DG_LOG_DOMAIN="libfprint"' ], language: 'c') +- + libfprint_conf = configuration_data() + + cc = meson.get_compiler('c') +@@ -23,8 +20,6 @@ glib_min_version = '2.56' + glib_version_def = 'GLIB_VERSION_@0@_@1@'.format( + glib_min_version.split('.')[0], glib_min_version.split('.')[1]) + common_cflags = cc.get_supported_arguments([ +- '-fgnu89-inline', +- '-std=gnu99', + '-Wall', + '-Wtype-limits', + '-Wundef', +@@ -34,7 +29,15 @@ common_cflags = cc.get_supported_arguments([ + '-Wshadow', + '-DGLIB_VERSION_MIN_REQUIRED=' + glib_version_def, + '-DGLIB_VERSION_MAX_ALLOWED=' + glib_version_def, ++ '-D_GNU_SOURCE', ++ '-DG_LOG_DOMAIN="libfprint"', ++]) ++c_cflags = cc.get_supported_arguments([ ++ '-fgnu89-inline', ++ '-std=gnu99', + ]) ++add_project_arguments(common_cflags + c_cflags, language: 'c') ++add_project_arguments(common_cflags, language: 'cpp') + + # maintaining compatibility with the previous libtool versioning + # current = binary - interface +-- +2.24.1 + diff --git a/SOURCES/0070-cpp-test-Fix-indentation.patch b/SOURCES/0070-cpp-test-Fix-indentation.patch new file mode 100644 index 0000000..bd7efbe --- /dev/null +++ b/SOURCES/0070-cpp-test-Fix-indentation.patch @@ -0,0 +1,31 @@ +From a0f18b7200056d3250b0112dcfd46e7d7441606b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 12:32:28 +0100 +Subject: [PATCH 070/181] cpp-test: Fix indentation + +--- + examples/cpp-test.cpp | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/examples/cpp-test.cpp b/examples/cpp-test.cpp +index a0eb2ed..99967e2 100644 +--- a/examples/cpp-test.cpp ++++ b/examples/cpp-test.cpp +@@ -6,10 +6,10 @@ + + int main (int argc, char **argv) + { +- FpContext *ctx; ++ FpContext *ctx; + +- ctx = fp_context_new (); +- g_object_unref (ctx); ++ ctx = fp_context_new (); ++ g_object_unref (ctx); + +- return 0; ++ return 0; + } +-- +2.24.1 + diff --git a/SOURCES/0071-meson-Build-nbis-separately-to-allow-changing-flags.patch b/SOURCES/0071-meson-Build-nbis-separately-to-allow-changing-flags.patch new file mode 100644 index 0000000..6d9b227 --- /dev/null +++ b/SOURCES/0071-meson-Build-nbis-separately-to-allow-changing-flags.patch @@ -0,0 +1,49 @@ +From 051549311b5dd44a9b927b2e165cc539699616b2 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Wed, 4 Dec 2019 11:37:30 +0100 +Subject: [PATCH 071/181] meson: Build nbis separately to allow changing flags + +As nbis is an external source bundle, it does not necessarily make sense +to enable/fix all warnings to the extend we do for our own library code. + +As such, separate the build process into multiple stages. +--- + libfprint/meson.build | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/libfprint/meson.build b/libfprint/meson.build +index 964744e..7742ecc 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -183,9 +183,19 @@ 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 ] ++ ++nbis_lib = static_library('nbis', ++ nbis_sources, ++ include_directories: [ ++ root_inc, ++ include_directories('nbis/include'), ++ ], ++ dependencies: deps, ++ install: false) ++ + libfprint = library('fprint', + libfprint_sources + fp_enums + fpi_enums + +- drivers_sources + nbis_sources + other_sources, ++ drivers_sources + other_sources, + soversion: soversion, + version: libversion, + c_args: drivers_cflags, +@@ -195,6 +205,7 @@ libfprint = library('fprint', + ], + link_args : vflag, + link_depends : mapfile, ++ link_with: nbis_lib, + dependencies: deps, + install: true) + +-- +2.24.1 + diff --git a/SOURCES/0072-meson-Add-the-include-directories-to-deps.patch b/SOURCES/0072-meson-Add-the-include-directories-to-deps.patch new file mode 100644 index 0000000..b1abc80 --- /dev/null +++ b/SOURCES/0072-meson-Add-the-include-directories-to-deps.patch @@ -0,0 +1,71 @@ +From ec5ac320350aa9bc8d0a3ac8df26cb17c53f880b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 12:43:12 +0100 +Subject: [PATCH 072/181] meson: Add the include directories to deps + +So we don't have to repeat them everywhere. +--- + libfprint/meson.build | 23 +++++++---------------- + 1 file changed, 7 insertions(+), 16 deletions(-) + +diff --git a/libfprint/meson.build b/libfprint/meson.build +index 7742ecc..100865d 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -184,12 +184,13 @@ vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfil + + deps = [ mathlib_dep, glib_dep, gusb_dep, nss_dep, imaging_dep, gio_dep ] + +-nbis_lib = static_library('nbis', ++deps += declare_dependency(include_directories: [ ++ root_inc, ++ include_directories('nbis/include'), ++]) ++ ++libnbis = static_library('nbis', + nbis_sources, +- include_directories: [ +- root_inc, +- include_directories('nbis/include'), +- ], + dependencies: deps, + install: false) + +@@ -199,13 +200,9 @@ libfprint = library('fprint', + soversion: soversion, + version: libversion, + c_args: drivers_cflags, +- include_directories: [ +- root_inc, +- include_directories('nbis/include'), +- ], + link_args : vflag, + link_depends : mapfile, +- link_with: nbis_lib, ++ link_with: libnbis, + dependencies: deps, + install: true) + +@@ -218,9 +215,6 @@ install_headers(['fprint.h'] + libfprint_public_headers, subdir: 'libfprint') + + udev_rules = executable('fprint-list-udev-rules', + 'fprint-list-udev-rules.c', +- include_directories: [ +- root_inc, +- ], + dependencies: [ deps, libfprint_dep ], + install: false) + +@@ -235,9 +229,6 @@ endif + + supported_devices = executable('fprint-list-supported-devices', + 'fprint-list-supported-devices.c', +- include_directories: [ +- root_inc, +- ], + dependencies: [ deps, libfprint_dep ], + install: false) + +-- +2.24.1 + diff --git a/SOURCES/0073-nbis-Add-a-global-include-file-with-all-the-definiti.patch b/SOURCES/0073-nbis-Add-a-global-include-file-with-all-the-definiti.patch new file mode 100644 index 0000000..bd207bd --- /dev/null +++ b/SOURCES/0073-nbis-Add-a-global-include-file-with-all-the-definiti.patch @@ -0,0 +1,113 @@ +From 228fda84601a9a9f3ba5b39bbea2302f73c2580c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 13:12:52 +0100 +Subject: [PATCH 073/181] nbis: Add a global include file with all the + definitions ignoring erros + +The nbis headers are full of redundant declarations, we can't fix them all +now, so in the mean time let's use an header using pragma to ignore such +errors. + +Add the error to nbis private include folder that should be used only by +headers of libfprint-nbis. +--- + libfprint/fp-image.c | 2 +- + libfprint/fp-print.c | 3 +-- + libfprint/meson.build | 6 +++++ + libfprint/nbis/libfprint-include/nbis.h | 35 +++++++++++++++++++++++++ + 4 files changed, 43 insertions(+), 3 deletions(-) + create mode 100644 libfprint/nbis/libfprint-include/nbis.h + +diff --git a/libfprint/fp-image.c b/libfprint/fp-image.c +index 4b8b3cd..c66b010 100644 +--- a/libfprint/fp-image.c ++++ b/libfprint/fp-image.c +@@ -20,7 +20,7 @@ + + #include "fpi-image.h" + +-#include "nbis/include/lfs.h" ++#include + + #if HAVE_PIXMAN + #include +diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c +index e7b119a..ed29ec1 100644 +--- a/libfprint/fp-print.c ++++ b/libfprint/fp-print.c +@@ -22,8 +22,7 @@ + #include "fpi-image.h" + #include "fpi-device.h" + +-#include "nbis/include/bozorth.h" +-#include "nbis/include/lfs.h" ++#include + + /** + * SECTION: fp-print +diff --git a/libfprint/meson.build b/libfprint/meson.build +index 100865d..99ebf73 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -187,11 +187,17 @@ deps = [ mathlib_dep, glib_dep, gusb_dep, nss_dep, imaging_dep, gio_dep ] + deps += declare_dependency(include_directories: [ + root_inc, + include_directories('nbis/include'), ++ include_directories('nbis/libfprint-include'), + ]) + + libnbis = static_library('nbis', + nbis_sources, + dependencies: deps, ++ c_args: cc.get_supported_arguments([ ++ '-Wno-error=redundant-decls', ++ '-Wno-redundant-decls', ++ '-Wno-discarded-qualifiers', ++ ]), + install: false) + + libfprint = library('fprint', +diff --git a/libfprint/nbis/libfprint-include/nbis.h b/libfprint/nbis/libfprint-include/nbis.h +new file mode 100644 +index 0000000..e3f667f +--- /dev/null ++++ b/libfprint/nbis/libfprint-include/nbis.h +@@ -0,0 +1,35 @@ ++/* ++ * 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 ++ */ ++ ++#pragma once ++ ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wredundant-decls" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#pragma GCC diagnostic pop +-- +2.24.1 + diff --git a/SOURCES/0074-cleanup-Don-t-make-nbis-depend-on-libfprint-built-so.patch b/SOURCES/0074-cleanup-Don-t-make-nbis-depend-on-libfprint-built-so.patch new file mode 100644 index 0000000..c7c23d2 --- /dev/null +++ b/SOURCES/0074-cleanup-Don-t-make-nbis-depend-on-libfprint-built-so.patch @@ -0,0 +1,213 @@ +From c5e8baac5bfb57c3c96f03c9534cc38002de3cca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 15:08:12 +0100 +Subject: [PATCH 074/181] cleanup: Don't make nbis depend on libfprint + built-sources + +Now that nbis is a static library it should be possible to compile it +without any fprint-built dependency, although since it included fp_internal +there was a compile-time dependency on the fp-enums that can be generated at +later times. + +So: + - Move nbis-helpers to nbis includes (and remove inclusion in fp_internal) + - Move the Minutiae definitions inside a standalone fpi-minutiae header + - Include fpi-minutiae.h in fp_internal.h + - Include nbis-hepers.h and fpi-minutiae.h in nbis' lfs.h + - Adapt missing definitions in libfprint +--- + libfprint/fp-image.c | 1 + + libfprint/fp-print.c | 1 + + libfprint/fp_internal.h | 35 ++------------- + libfprint/fpi-minutiae.h | 45 +++++++++++++++++++ + libfprint/nbis/include/lfs.h | 3 +- + libfprint/nbis/lfs.h.patch | 13 +++--- + .../libfprint-include}/nbis-helpers.h | 0 + 7 files changed, 59 insertions(+), 39 deletions(-) + create mode 100644 libfprint/fpi-minutiae.h + rename libfprint/{ => nbis/libfprint-include}/nbis-helpers.h (100%) + +diff --git a/libfprint/fp-image.c b/libfprint/fp-image.c +index c66b010..16837a8 100644 +--- a/libfprint/fp-image.c ++++ b/libfprint/fp-image.c +@@ -19,6 +19,7 @@ + */ + + #include "fpi-image.h" ++#include "fpi-log.h" + + #include + +diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c +index ed29ec1..f724c77 100644 +--- a/libfprint/fp-print.c ++++ b/libfprint/fp-print.c +@@ -20,6 +20,7 @@ + + #include "fpi-print.h" + #include "fpi-image.h" ++#include "fpi-log.h" + #include "fpi-device.h" + + #include +diff --git a/libfprint/fp_internal.h b/libfprint/fp_internal.h +index 8147089..56ada18 100644 +--- a/libfprint/fp_internal.h ++++ b/libfprint/fp_internal.h +@@ -1,6 +1,6 @@ + /* + * Internal/private definitions for libfprint +- * Copyright (C) 2007-2008 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 +@@ -17,38 +17,9 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef __FPRINT_INTERNAL_H__ +-#define __FPRINT_INTERNAL_H__ ++#pragma once + + #include "fpi-log.h" +-#include "nbis-helpers.h" + #include "fpi-image.h" + #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; +-}; +- +-/* fp_minutiae structure definition */ +-struct fp_minutiae +-{ +- int alloc; +- int num; +- struct fp_minutia **list; +-}; +- +- +-#endif ++#include "fpi-minutiae.h" +diff --git a/libfprint/fpi-minutiae.h b/libfprint/fpi-minutiae.h +new file mode 100644 +index 0000000..24dc761 +--- /dev/null ++++ b/libfprint/fpi-minutiae.h +@@ -0,0 +1,45 @@ ++/* ++ * Internal/private definitions 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 ++ */ ++ ++#pragma once ++ ++/* 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; ++}; ++ ++/* fp_minutiae structure definition */ ++struct fp_minutiae ++{ ++ int alloc; ++ int num; ++ struct fp_minutia **list; ++}; +diff --git a/libfprint/nbis/include/lfs.h b/libfprint/nbis/include/lfs.h +index ae7aee5..f4f38d7 100644 +--- a/libfprint/nbis/include/lfs.h ++++ b/libfprint/nbis/include/lfs.h +@@ -66,7 +66,8 @@ of the software. + + #include + #include +-#include ++#include ++#include + + /*************************************************************************/ + /* OUTPUT FILE EXTENSIONS */ +diff --git a/libfprint/nbis/lfs.h.patch b/libfprint/nbis/lfs.h.patch +index 2be6ebf..3342bc5 100644 +--- a/libfprint/nbis/lfs.h.patch ++++ b/libfprint/nbis/lfs.h.patch +@@ -1,15 +1,16 @@ +---- include/lfs.h 2018-08-24 15:31:54.535579623 +0200 +-+++ include/lfs.h.orig 2018-08-24 15:31:48.781587933 +0200 +-@@ -66,7 +43,7 @@ of the software. ++--- include/lfs.h +++++ include/lfs.h ++@@ -66,7 +66,8 @@ of the software. + + #include + #include + -#include /* Needed by to_type9.c */ +-+#include +++#include +++#include + + /*************************************************************************/ + /* OUTPUT FILE EXTENSIONS */ +-@@ -154,26 +131,8 @@ typedef struct rotgrids{ ++@@ -154,26 +155,8 @@ typedef struct rotgrids{ + #define DISAPPEARING 0 + #define APPEARING 1 + +@@ -38,7 +39,7 @@ + + typedef struct feature_pattern{ + int type; +-@@ -1185,17 +1185,6 @@ extern void bubble_sort_double_inc_2(double *, int *, const int); ++@@ -1203,17 +1186,6 @@ extern void bubble_sort_double_inc_2(double *, int *, const int); + extern void bubble_sort_double_dec_2(double *, int *, const int); + extern void bubble_sort_int_inc(int *, const int); + +diff --git a/libfprint/nbis-helpers.h b/libfprint/nbis/libfprint-include/nbis-helpers.h +similarity index 100% +rename from libfprint/nbis-helpers.h +rename to libfprint/nbis/libfprint-include/nbis-helpers.h +-- +2.24.1 + diff --git a/SOURCES/0075-nbis-log-Don-t-use-old-style-function-declarations.patch b/SOURCES/0075-nbis-log-Don-t-use-old-style-function-declarations.patch new file mode 100644 index 0000000..b78ebad --- /dev/null +++ b/SOURCES/0075-nbis-log-Don-t-use-old-style-function-declarations.patch @@ -0,0 +1,55 @@ +From e0344288b01f66bf4b600468692a1110c8abbe24 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 13:13:14 +0100 +Subject: [PATCH 075/181] nbis/log: Don't use old-style function declarations + +--- + libfprint/nbis/mindtct/log.c | 4 ++-- + libfprint/nbis/update-from-nbis.sh | 6 +++++- + 2 files changed, 7 insertions(+), 3 deletions(-) + +diff --git a/libfprint/nbis/mindtct/log.c b/libfprint/nbis/mindtct/log.c +index b1dcaad..dcd3db7 100644 +--- a/libfprint/nbis/mindtct/log.c ++++ b/libfprint/nbis/mindtct/log.c +@@ -66,7 +66,7 @@ of the software. + + /***************************************************************************/ + /***************************************************************************/ +-int open_logfile() ++int open_logfile(void) + { + #ifdef LOG_REPORT + fprintf(stderr, "ERROR : open_logfile : fopen : %s\n", LOG_FILE); +@@ -91,7 +91,7 @@ void print2log(char *fmt, ...) + + /***************************************************************************/ + /***************************************************************************/ +-int close_logfile() ++int close_logfile(void) + { + #ifdef LOG_REPORT + fprintf(stderr, "ERROR : close_logfile : fclose : %s\n", LOG_FILE); +diff --git a/libfprint/nbis/update-from-nbis.sh b/libfprint/nbis/update-from-nbis.sh +index c8cde80..742c8cb 100755 +--- a/libfprint/nbis/update-from-nbis.sh ++++ b/libfprint/nbis/update-from-nbis.sh +@@ -179,9 +179,13 @@ sed -i 's/[ \t]*$//' `find -name "*.[ch]"` + # Remove usebsd.h + sed -i '/usebsd.h/d' `find -name "*.[ch]"` + ++# Replace functions with empty parameters using (void) ++sed -i 's/^\([[:space:]]*[[:alnum:]_]\+[\*[:space:]]\+'\ ++'[[:alnum:]_]\+[[:space:]]*\)([[:space:]]*)/\1(void)/g' `find -name "*.[ch]"` ++ + # Use GLib memory management + 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 ++patch -p0 < glib-mem-warning.patch +-- +2.24.1 + diff --git a/SOURCES/0076-nbis-Make-the-extern-global-bozworth-y-variable-as-b.patch b/SOURCES/0076-nbis-Make-the-extern-global-bozworth-y-variable-as-b.patch new file mode 100644 index 0000000..72dddea --- /dev/null +++ b/SOURCES/0076-nbis-Make-the-extern-global-bozworth-y-variable-as-b.patch @@ -0,0 +1,237 @@ +From 9c3af4498e7e5898744c4598fe89a5b34e639b92 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 14:22:07 +0100 +Subject: [PATCH 076/181] nbis: Make the extern global bozworth 'y' variable as + bz_y + +Othewise this could create issues with other 'y' variable definitions +shadowing it. + +Add a cocci file that performs the change automatically +--- + libfprint/nbis/bozorth3/bozorth3.c | 34 ++++++++++++++-------------- + libfprint/nbis/bozorth3/bz_gbls.c | 4 ++-- + libfprint/nbis/include/bozorth.h | 2 +- + libfprint/nbis/remove-global-y.cocci | 21 +++++++++++++++++ + libfprint/nbis/update-from-nbis.sh | 3 +++ + 5 files changed, 44 insertions(+), 20 deletions(-) + create mode 100644 libfprint/nbis/remove-global-y.cocci + +diff --git a/libfprint/nbis/bozorth3/bozorth3.c b/libfprint/nbis/bozorth3/bozorth3.c +index 0a8b0ff..e2e668f 100644 +--- a/libfprint/nbis/bozorth3/bozorth3.c ++++ b/libfprint/nbis/bozorth3/bozorth3.c +@@ -896,7 +896,7 @@ for ( k = 0; k < np - 1; k++ ) { + for ( i = 0; i < tot; i++ ) { + + +- int colp_value = colp[ y[i]-1 ][0]; ++ int colp_value = colp[ bz_y[i]-1 ][0]; + if ( colp_value < 0 ) { + kk += colp_value; + n++; +@@ -933,7 +933,7 @@ for ( k = 0; k < np - 1; k++ ) { + + kk = 0; + for ( i = 0; i < tot; i++ ) { +- int diff = colp[ y[i]-1 ][0] - jj; ++ int diff = colp[ bz_y[i]-1 ][0] - jj; + j = SQUARED( diff ); + + +@@ -942,7 +942,7 @@ for ( k = 0; k < np - 1; k++ ) { + if ( j > TXS && j < CTXS ) + kk++; + else +- y[i-kk] = y[i]; ++ bz_y[i-kk] = bz_y[i]; + } /* END FOR i */ + + tot -= kk; /* Adjust the total edge pairs TOT based on # of edge pairs skipped */ +@@ -958,7 +958,7 @@ for ( k = 0; k < np - 1; k++ ) { + + + for ( i = tot-1 ; i >= 0; i-- ) { +- int idx = y[i] - 1; ++ int idx = bz_y[i] - 1; + if ( rk[idx] == 0 ) { + sc[idx] = -1; + } else { +@@ -976,7 +976,7 @@ for ( k = 0; k < np - 1; k++ ) { + int pd = 0; + + for ( i = 0; i < tot; i++ ) { +- int idx = y[i] - 1; ++ int idx = bz_y[i] - 1; + for ( ii = 1; ii < 4; ii++ ) { + + +@@ -1476,7 +1476,7 @@ return match_score; + /* extern int rk[ RK_SIZE ]; */ + /* extern int cp[ CP_SIZE ]; */ + /* extern int rp[ RP_SIZE ]; */ +-/* extern int y[ Y_SIZE ]; */ ++/* extern int bz_y[ Y_SIZE ]; */ + + void bz_sift( + int * ww, /* INPUT and OUTPUT; endpoint groups index; *ww may be bumped by one or by two */ +@@ -1507,7 +1507,7 @@ if ( n == 0 && t == 0 ) { + + + if ( sc[kx-1] != ftt ) { +- y[ (*tot)++ ] = kx; ++ bz_y[ (*tot)++ ] = kx; + rk[kx-1] = sc[kx-1]; + sc[kx-1] = ftt; + } +@@ -1553,7 +1553,7 @@ if ( n == l ) { + qq[*qh] = kz; + zz[kz-1] = (*qh)++; + } +- y[(*tot)++] = kx; ++ bz_y[(*tot)++] = kx; + rk[kx-1] = sc[kx-1]; + sc[kx-1] = ftt; + } +@@ -1697,12 +1697,12 @@ for ( ii = 0; ii < tp; ii++ ) { /* For each index up to the current value of + } + + t = 0; +- y[0] = lim; ++ bz_y[0] = lim; + cp[0] = 1; + b = 0; + n = 1; + do { /* looping until T < 0 ... */ +- if ( y[t] - cp[t] > 1 ) { ++ if (bz_y[t] - cp[t] > 1 ) { + k = sct[cp[t]][t]; + j = ctt[k] + 1; + for ( i = 0; i < j; i++ ) { +@@ -1715,25 +1715,25 @@ for ( ii = 0; ii < tp; ii++ ) { /* For each index up to the current value of + do { + while ( rp[jj] < sct[kk][t] && jj < j ) + jj++; +- while ( rp[jj] > sct[kk][t] && kk < y[t] ) ++ while ( rp[jj] > sct[kk][t] && kk < bz_y[t] ) + kk++; +- while ( rp[jj] == sct[kk][t] && kk < y[t] && jj < j ) { ++ while ( rp[jj] == sct[kk][t] && kk < bz_y[t] && jj < j ) { + sct[k][t+1] = sct[kk][t]; + k++; + kk++; + jj++; + } +- } while ( kk < y[t] && jj < j ); ++ } while ( kk < bz_y[t] && jj < j ); + + t++; + cp[t] = 1; +- y[t] = k; ++ bz_y[t] = k; + b = t; + n = 1; + } else { + int tot = 0; + +- lim = y[t]; ++ lim = bz_y[t]; + for ( i = n-1; i < lim; i++ ) { + tot += ct[ sct[i][t] ]; + } +@@ -1750,7 +1750,7 @@ for ( ii = 0; ii < tp; ii++ ) { /* For each index up to the current value of + + { + int rk_index = b; +- lim = y[t]; ++ lim = bz_y[t]; + for ( i = n-1; i < lim; ) { + rk[ rk_index++ ] = sct[ i++ ][ t ]; + } +@@ -1760,7 +1760,7 @@ for ( ii = 0; ii < tp; ii++ ) { /* For each index up to the current value of + t--; + if ( t >= 0 ) { + ++cp[t]; +- n = y[t]; ++ n = bz_y[t]; + } + } /* END IF */ + +diff --git a/libfprint/nbis/bozorth3/bz_gbls.c b/libfprint/nbis/bozorth3/bz_gbls.c +index dd828dc..ea283d8 100644 +--- a/libfprint/nbis/bozorth3/bz_gbls.c ++++ b/libfprint/nbis/bozorth3/bz_gbls.c +@@ -102,7 +102,7 @@ int yl[ YL_SIZE_1 ][ YL_SIZE_2 ]; + int rf[RF_SIZE_1][RF_SIZE_2]; + int cf[CF_SIZE_1][CF_SIZE_2]; + +- int y[20000]; ++ int bz_y[20000]; + #else + int rq[ RQ_SIZE ] = {}; + int tq[ TQ_SIZE ] = {}; +@@ -122,6 +122,6 @@ int yl[ YL_SIZE_1 ][ YL_SIZE_2 ]; + int rf[RF_SIZE_1][RF_SIZE_2] = {}; + int cf[CF_SIZE_1][CF_SIZE_2] = {}; + +- int y[20000] = {}; ++ int bz_y[20000] = {}; + #endif + +diff --git a/libfprint/nbis/include/bozorth.h b/libfprint/nbis/include/bozorth.h +index 08ec4b1..a705da9 100644 +--- a/libfprint/nbis/include/bozorth.h ++++ b/libfprint/nbis/include/bozorth.h +@@ -245,7 +245,7 @@ extern int cp[ CP_SIZE ]; + extern int rp[ RP_SIZE ]; + extern int rf[RF_SIZE_1][RF_SIZE_2]; + extern int cf[CF_SIZE_1][CF_SIZE_2]; +-extern int y[20000]; ++extern int bz_y[20000]; + + /**************************************************************************/ + /**************************************************************************/ +diff --git a/libfprint/nbis/remove-global-y.cocci b/libfprint/nbis/remove-global-y.cocci +new file mode 100644 +index 0000000..3b740af +--- /dev/null ++++ b/libfprint/nbis/remove-global-y.cocci +@@ -0,0 +1,21 @@ ++@ global_y @ ++identifier y; ++@@ ++int ++- y +++ bz_y ++[20000]; ++ ++@@ ++identifier global_y.y; ++@@ ++- y +++ bz_y ++[...] ++ ++@@ ++@@ ++int ++- y +++ bz_y ++[20000] = {}; +diff --git a/libfprint/nbis/update-from-nbis.sh b/libfprint/nbis/update-from-nbis.sh +index 742c8cb..75e82ba 100755 +--- a/libfprint/nbis/update-from-nbis.sh ++++ b/libfprint/nbis/update-from-nbis.sh +@@ -186,6 +186,9 @@ sed -i 's/^\([[:space:]]*[[:alnum:]_]\+[\*[:space:]]\+'\ + # Use GLib memory management + spatch --sp-file glib-memory.cocci --dir . --in-place + ++# Rename global "y" variable in "bz_y" ++spatch --sp-file remove-global-y.cocci bozorth3/* include/bozorth.h --in-place ++ + # The above leaves an unused variable around, triggering a warning + # remove it. + patch -p0 < glib-mem-warning.patch +-- +2.24.1 + diff --git a/SOURCES/0077-storage-Include-storage-header-so-that-we-have-decla.patch b/SOURCES/0077-storage-Include-storage-header-so-that-we-have-decla.patch new file mode 100644 index 0000000..349495f --- /dev/null +++ b/SOURCES/0077-storage-Include-storage-header-so-that-we-have-decla.patch @@ -0,0 +1,25 @@ +From 15c75f743325a9e73c07fcb35de71c04eb9e9001 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 13:13:40 +0100 +Subject: [PATCH 077/181] storage: Include storage header so that we have + declarations + +--- + examples/storage.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/examples/storage.c b/examples/storage.c +index db35854..6ca6efc 100644 +--- a/examples/storage.c ++++ b/examples/storage.c +@@ -20,6 +20,7 @@ + */ + + #include ++#include "storage.h" + + #include + #include +-- +2.24.1 + diff --git a/SOURCES/0078-fp-device-Remove-unused-timeout-function-and-source-.patch b/SOURCES/0078-fp-device-Remove-unused-timeout-function-and-source-.patch new file mode 100644 index 0000000..f6b2d7c --- /dev/null +++ b/SOURCES/0078-fp-device-Remove-unused-timeout-function-and-source-.patch @@ -0,0 +1,69 @@ +From 1d5ec0b9787f5f3d48fe3a8539c35d23e51745d6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 13:23:26 +0100 +Subject: [PATCH 078/181] fp-device: Remove unused timeout function and source + data + +These were probably added in previous iterations, but they are not uneeded +anymore as the GSource embeds already a callback function. + +So make just this clearer in the dispatch function. +--- + libfprint/fp-device.c | 22 +++++----------------- + 1 file changed, 5 insertions(+), 17 deletions(-) + +diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c +index 182be51..334b998 100644 +--- a/libfprint/fp-device.c ++++ b/libfprint/fp-device.c +@@ -1382,22 +1382,10 @@ fp_device_list_prints_finish (FpDevice *device, + + typedef struct + { +- GSource source; +- FpDevice *device; +- FpTimeoutFunc callback; +- gpointer user_data; ++ GSource source; ++ FpDevice *device; + } 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) + { +@@ -1409,11 +1397,12 @@ timeout_finalize (GSource *source) + } + + static gboolean +-timeout_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) ++timeout_dispatch (GSource *source, GSourceFunc gsource_func, gpointer user_data) + { + FpDeviceTimeoutSource *timeout_source = (FpDeviceTimeoutSource *) source; ++ FpTimeoutFunc callback = (FpTimeoutFunc) gsource_func; + +- ((FpTimeoutFunc) callback)(timeout_source->device, user_data); ++ callback (timeout_source->device, user_data); + + return G_SOURCE_REMOVE; + } +@@ -1496,7 +1485,6 @@ fpi_device_add_timeout (FpDevice *device, + 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, destroy_notify); +-- +2.24.1 + diff --git a/SOURCES/0079-cleanup-Use-static-functions-for-non-declared-method.patch b/SOURCES/0079-cleanup-Use-static-functions-for-non-declared-method.patch new file mode 100644 index 0000000..5a9370a --- /dev/null +++ b/SOURCES/0079-cleanup-Use-static-functions-for-non-declared-method.patch @@ -0,0 +1,77 @@ +From db83641a7cf40fe233606f1f8c3cf269756a7641 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 13:25:27 +0100 +Subject: [PATCH 079/181] cleanup: Use static functions for non-declared + methods + +--- + libfprint/drivers/aes2501.c | 2 +- + libfprint/drivers/elan.c | 4 ++-- + libfprint/fp-device.c | 2 +- + libfprint/fpi-usb-transfer.c | 2 +- + 4 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/libfprint/drivers/aes2501.c b/libfprint/drivers/aes2501.c +index 1aa0538..57b0cca 100644 +--- a/libfprint/drivers/aes2501.c ++++ b/libfprint/drivers/aes2501.c +@@ -686,7 +686,7 @@ enum activate_states { + ACTIVATE_NUM_STATES, + }; + +-void ++static void + activate_read_regs_cb (FpImageDevice *dev, GError *error, + unsigned char *regs, void *user_data) + { +diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c +index 7c7fb26..90a0306 100644 +--- a/libfprint/drivers/elan.c ++++ b/libfprint/drivers/elan.c +@@ -41,7 +41,7 @@ + #include "drivers_api.h" + #include "elan.h" + +-unsigned char ++static unsigned char + elan_get_pixel (struct fpi_frame_asmbl_ctx *ctx, + struct fpi_frame *frame, unsigned int x, + unsigned int y) +@@ -91,7 +91,7 @@ G_DECLARE_FINAL_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN, + FpImageDevice); + G_DEFINE_TYPE (FpiDeviceElan, fpi_device_elan, FP_TYPE_IMAGE_DEVICE); + +-int ++static int + cmp_short (const void *a, const void *b) + { + return (int) (*(short *) a - *(short *) b); +diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c +index 334b998..2f706b3 100644 +--- a/libfprint/fp-device.c ++++ b/libfprint/fp-device.c +@@ -1386,7 +1386,7 @@ typedef struct + FpDevice *device; + } FpDeviceTimeoutSource; + +-void ++static void + timeout_finalize (GSource *source) + { + FpDeviceTimeoutSource *timeout_source = (FpDeviceTimeoutSource *) source; +diff --git a/libfprint/fpi-usb-transfer.c b/libfprint/fpi-usb-transfer.c +index 08e75cb..99fe3d4 100644 +--- a/libfprint/fpi-usb-transfer.c ++++ b/libfprint/fpi-usb-transfer.c +@@ -298,7 +298,7 @@ fpi_usb_transfer_fill_interrupt_full (FpiUsbTransfer *transfer, + transfer->free_buffer = free_func; + } + +-void ++static void + transfer_finish_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) + { + GError *error = NULL; +-- +2.24.1 + diff --git a/SOURCES/0080-gtk-demo-Use-G_DECLARE-to-avoid-missing-declarations.patch b/SOURCES/0080-gtk-demo-Use-G_DECLARE-to-avoid-missing-declarations.patch new file mode 100644 index 0000000..a56acb8 --- /dev/null +++ b/SOURCES/0080-gtk-demo-Use-G_DECLARE-to-avoid-missing-declarations.patch @@ -0,0 +1,53 @@ +From 8f2c0ada0e2e8813f8c7da3fba9c110ec49c614e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 14:04:04 +0100 +Subject: [PATCH 080/181] gtk-demo: Use G_DECLARE to avoid missing declarations + +--- + demo/gtk-libfprint-test.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/demo/gtk-libfprint-test.c b/demo/gtk-libfprint-test.c +index c6dd90e..8026815 100644 +--- a/demo/gtk-libfprint-test.c ++++ b/demo/gtk-libfprint-test.c +@@ -22,9 +22,11 @@ + #include + #include + +-typedef GtkApplication LibfprintDemo; +-typedef GtkApplicationClass LibfprintDemoClass; +- ++struct _LibfprintDemo ++{ ++ GtkApplication parent; ++}; ++G_DECLARE_FINAL_TYPE (LibfprintDemo, libfprint_demo, FP, DEMO, GtkApplication) + G_DEFINE_TYPE (LibfprintDemo, libfprint_demo, GTK_TYPE_APPLICATION) + + typedef enum { +@@ -33,7 +35,7 @@ typedef enum { + IMAGE_DISPLAY_BINARY = 1 << 1 + } ImageDisplayFlags; + +-typedef struct ++struct _LibfprintDemoWindow + { + GtkApplicationWindow parent_instance; + +@@ -52,10 +54,9 @@ typedef struct + + FpImage *img; + ImageDisplayFlags img_flags; +-} LibfprintDemoWindow; +- +-typedef GtkApplicationWindowClass LibfprintDemoWindowClass; ++}; + ++G_DECLARE_FINAL_TYPE (LibfprintDemoWindow, libfprint_demo_window, FP, DEMO_WINDOW, GtkApplicationWindow) + G_DEFINE_TYPE (LibfprintDemoWindow, libfprint_demo_window, GTK_TYPE_APPLICATION_WINDOW) + + typedef enum { +-- +2.24.1 + diff --git a/SOURCES/0081-vfs5011-Cast-gpointer-data-values-to-proper-type-to-.patch b/SOURCES/0081-vfs5011-Cast-gpointer-data-values-to-proper-type-to-.patch new file mode 100644 index 0000000..8a657c2 --- /dev/null +++ b/SOURCES/0081-vfs5011-Cast-gpointer-data-values-to-proper-type-to-.patch @@ -0,0 +1,37 @@ +From ce64d4db86ee179783571eadbdaa9288eeead72b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 14:09:09 +0100 +Subject: [PATCH 081/181] vfs5011: Cast gpointer data values to proper type to + do math operations + +--- + libfprint/drivers/vfs5011.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libfprint/drivers/vfs5011.c b/libfprint/drivers/vfs5011.c +index ef318f2..265495a 100644 +--- a/libfprint/drivers/vfs5011.c ++++ b/libfprint/drivers/vfs5011.c +@@ -210,8 +210,8 @@ vfs5011_get_deviation2 (struct fpi_line_asmbl_ctx *ctx, GSList *row1, GSList *ro + int res = 0, mean = 0, i; + const int size = 64; + +- buf1 = row1->data + 56; +- buf2 = row2->data + 168; ++ buf1 = (unsigned char *) row1->data + 56; ++ buf2 = (unsigned char *) row2->data + 168; + + for (i = 0; i < size; i++) + mean += (int) buf1[i] + (int) buf2[i]; +@@ -232,7 +232,7 @@ vfs5011_get_pixel (struct fpi_line_asmbl_ctx *ctx, + GSList *row, + unsigned x) + { +- unsigned char *data = row->data + 8; ++ unsigned char *data = (unsigned char *) row->data + 8; + + return data[x]; + } +-- +2.24.1 + diff --git a/SOURCES/0082-vfs0050-Use-proper-casting-summing-pointers-first.patch b/SOURCES/0082-vfs0050-Use-proper-casting-summing-pointers-first.patch new file mode 100644 index 0000000..a8b9042 --- /dev/null +++ b/SOURCES/0082-vfs0050-Use-proper-casting-summing-pointers-first.patch @@ -0,0 +1,27 @@ +From 8e9e3f1d8961615e6c12306014dcf8538d7e37de Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 14:22:30 +0100 +Subject: [PATCH 082/181] vfs0050: Use proper casting summing pointers first + +Cast the pointers as what fpi usb transfer expects. +--- + libfprint/drivers/vfs0050.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/libfprint/drivers/vfs0050.c b/libfprint/drivers/vfs0050.c +index bb6851f..b08a865 100644 +--- a/libfprint/drivers/vfs0050.c ++++ b/libfprint/drivers/vfs0050.c +@@ -595,7 +595,8 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev) + /* Receive chunk of data */ + transfer = fpi_usb_transfer_new (dev); + fpi_usb_transfer_fill_bulk_full (transfer, 0x82, +- (void *) self->lines_buffer + self->bytes, ++ (guint8 *) ++ (self->lines_buffer + self->bytes), + VFS_USB_BUFFER_SIZE, NULL); + transfer->ssm = ssm; + fpi_usb_transfer_submit (transfer, VFS_USB_TIMEOUT, NULL, +-- +2.24.1 + diff --git a/SOURCES/0083-meson-Include-fpi-context.h-in-generated-fp-drivers..patch b/SOURCES/0083-meson-Include-fpi-context.h-in-generated-fp-drivers..patch new file mode 100644 index 0000000..6b527e1 --- /dev/null +++ b/SOURCES/0083-meson-Include-fpi-context.h-in-generated-fp-drivers..patch @@ -0,0 +1,25 @@ +From 4b6c3446e9be0ff5d03aa1fe24d79762d93b7ec7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 13:34:14 +0100 +Subject: [PATCH 083/181] meson: Include fpi-context.h in generated + fp-drivers.c + +--- + meson.build | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/meson.build b/meson.build +index 09abc1f..265ce30 100644 +--- a/meson.build ++++ b/meson.build +@@ -118,6 +118,7 @@ endforeach + + # Export the drivers' types to the core code + drivers_type_list = '#include \n' ++drivers_type_list += '#include "fpi-context.h"\n' + drivers_type_func = 'void fpi_get_driver_types(GArray *drivers)\n{\n\tGType t;\n' + foreach driver: drivers + drivers_type_list += 'extern GType (fpi_device_' + driver + '_get_type) (void);\n' +-- +2.24.1 + diff --git a/SOURCES/0084-meson-Move-generated-source-to-fpi-prefix-and-use-mo.patch b/SOURCES/0084-meson-Move-generated-source-to-fpi-prefix-and-use-mo.patch new file mode 100644 index 0000000..6864822 --- /dev/null +++ b/SOURCES/0084-meson-Move-generated-source-to-fpi-prefix-and-use-mo.patch @@ -0,0 +1,67 @@ +From 130466c3c9cceae69b41dfb6c474d4d474722426 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 13:44:08 +0100 +Subject: [PATCH 084/181] meson: Move generated source to fpi- prefix and use + more readable code + +Instead of concatenating strings, use an array of strings and finally join +them using newline. +--- + libfprint/meson.build | 4 ++-- + meson.build | 19 +++++++++++++------ + 2 files changed, 15 insertions(+), 8 deletions(-) + +diff --git a/libfprint/meson.build b/libfprint/meson.build +index 99ebf73..f73aba3 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -172,11 +172,11 @@ fpi_enums = gnome.mkenums_simple('fpi-enums', + fpi_enums_h = fpi_enums[1] + + drivers_sources += configure_file(input: 'empty_file', +- output: 'fp-drivers.c', ++ output: 'fpi-drivers.c', + capture: true, + command: [ + 'echo', +- drivers_type_list + '\n\n' + drivers_type_func ++ '\n'.join(drivers_type_list + [] + drivers_type_func) + ]) + + mapfile = 'libfprint.ver' +diff --git a/meson.build b/meson.build +index 265ce30..65077c5 100644 +--- a/meson.build ++++ b/meson.build +@@ -117,15 +117,22 @@ foreach driver: drivers + endforeach + + # Export the drivers' types to the core code +-drivers_type_list = '#include \n' +-drivers_type_list += '#include "fpi-context.h"\n' +-drivers_type_func = 'void fpi_get_driver_types(GArray *drivers)\n{\n\tGType t;\n' ++drivers_type_list = [] ++drivers_type_func = [] ++drivers_type_list += '#include ' ++drivers_type_list += '#include "fpi-context.h"' ++drivers_type_list += '' ++drivers_type_func += 'void fpi_get_driver_types (GArray *drivers)' ++drivers_type_func += ' {' ++drivers_type_func += ' GType t;' ++drivers_type_func += '' + foreach driver: drivers +- 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' ++ drivers_type_list += 'extern GType (fpi_device_' + driver + '_get_type) (void);' ++ drivers_type_func += ' t = fpi_device_' + driver + '_get_type ();' ++ drivers_type_func += ' g_array_append_val (drivers, t);\n' + endforeach + drivers_type_list += '' +-drivers_type_func += '};' ++drivers_type_func += '}' + + root_inc = include_directories('.') + +-- +2.24.1 + diff --git a/SOURCES/0085-meson-Use-stricter-C-arguments-to-compile-libfprint.patch b/SOURCES/0085-meson-Use-stricter-C-arguments-to-compile-libfprint.patch new file mode 100644 index 0000000..1b506f4 --- /dev/null +++ b/SOURCES/0085-meson-Use-stricter-C-arguments-to-compile-libfprint.patch @@ -0,0 +1,72 @@ +From 59ef7ba5213ea17a451c2d0f2806a5f70181721c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 14:27:33 +0100 +Subject: [PATCH 085/181] meson: Use stricter C arguments to compile libfprint + +These are based on what mutter does, being a quite strict project on c code +quality. +--- + meson.build | 37 +++++++++++++++++++++++++++++++++---- + 1 file changed, 33 insertions(+), 4 deletions(-) + +diff --git a/meson.build b/meson.build +index 65077c5..1561ebf 100644 +--- a/meson.build ++++ b/meson.build +@@ -21,20 +21,49 @@ glib_version_def = 'GLIB_VERSION_@0@_@1@'.format( + glib_min_version.split('.')[0], glib_min_version.split('.')[1]) + common_cflags = cc.get_supported_arguments([ + '-Wall', ++ '-Wcast-align', ++ '-Wformat-nonliteral', ++ '-Wformat-security', ++ '-Wformat=2', ++ '-Wignored-qualifiers', ++ '-Wlogical-op', ++ '-Wmissing-declarations', ++ '-Wmissing-format-attribute', ++ '-Wmissing-include-dirs', ++ '-Wmissing-noreturn', ++ '-Wpointer-arith', ++ '-Wshadow', + '-Wtype-limits', + '-Wundef', + '-Wunused', +- '-Wstrict-prototypes', +- '-Werror-implicit-function-declaration', +- '-Wshadow', ++ '-Werror=address', ++ '-Werror=array-bounds', ++ '-Werror=empty-body', ++ '-Werror=init-self', ++ '-Werror=int-to-pointer-cast', ++ '-Werror=main', ++ '-Werror=missing-braces', ++ '-Werror=nonnull', ++ '-Werror=redundant-decls', ++ '-Werror=return-type', ++ '-Werror=sequence-point', ++ '-Werror=trigraphs', ++ '-Werror=write-strings', ++ '-fno-strict-aliasing', + '-DGLIB_VERSION_MIN_REQUIRED=' + glib_version_def, + '-DGLIB_VERSION_MAX_ALLOWED=' + glib_version_def, + '-D_GNU_SOURCE', + '-DG_LOG_DOMAIN="libfprint"', + ]) + c_cflags = cc.get_supported_arguments([ +- '-fgnu89-inline', + '-std=gnu99', ++ '-Wimplicit-function-declaration', ++ '-Wmissing-prototypes', ++ '-Wnested-externs', ++ '-Wold-style-definition', ++ '-Wstrict-prototypes', ++ '-Werror=implicit', ++ '-Werror=pointer-to-int-cast', + ]) + add_project_arguments(common_cflags + c_cflags, language: 'c') + add_project_arguments(common_cflags, language: 'cpp') +-- +2.24.1 + diff --git a/SOURCES/0086-elan-Fix-internal-state-machine-to-ensure-correct-de.patch b/SOURCES/0086-elan-Fix-internal-state-machine-to-ensure-correct-de.patch new file mode 100644 index 0000000..a835c7d --- /dev/null +++ b/SOURCES/0086-elan-Fix-internal-state-machine-to-ensure-correct-de.patch @@ -0,0 +1,45 @@ +From 2dc4f575b333bee8481cb9707ec6ef293b71e4dd Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Wed, 4 Dec 2019 14:28:08 +0100 +Subject: [PATCH 086/181] elan: Fix internal state machine to ensure correct + deactivation + +During calibration, the internal state was stored as INACTIVE. This is +not true though, the device is actively running state machines. + +Move the state update to the start of the operation, therefore ensuring +we don't deactivate without completing the SSM. + +Note that this will prevent a crash, but the driver still does not +behave quite correctly when such a state change does happen. However, +this is just a safety measure as the state change should not happen in +the first place. + +See: #203 +--- + libfprint/drivers/elan.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c +index 90a0306..9495a48 100644 +--- a/libfprint/drivers/elan.c ++++ b/libfprint/drivers/elan.c +@@ -776,7 +776,6 @@ calibrate_complete (FpiSsm *ssm, FpDevice *dev, GError *error) + } + else + { +- self->dev_state = FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON; + elan_capture (dev); + } + +@@ -966,6 +965,7 @@ elan_change_state (FpImageDevice *idev) + { + case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: + /* activation completed or another enroll stage started */ ++ self->dev_state = FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON; + elan_calibrate (dev); + break; + +-- +2.24.1 + diff --git a/SOURCES/0087-image-device-Prevent-deactivation-when-waiting-for-f.patch b/SOURCES/0087-image-device-Prevent-deactivation-when-waiting-for-f.patch new file mode 100644 index 0000000..96334a6 --- /dev/null +++ b/SOURCES/0087-image-device-Prevent-deactivation-when-waiting-for-f.patch @@ -0,0 +1,103 @@ +From 56126df4a2b5ecee1a9580e8d27f4d3d6f6925cd Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Wed, 4 Dec 2019 15:50:06 +0100 +Subject: [PATCH 087/181] image-device: Prevent deactivation when waiting for + finger + +At the end of enroll, the image device would put the driver into the +AWAIT_FINGER_ON state and then deactivate the device afterwards. Doing +this adds additional complexity to drivers which would need to handle +both cancellation and normal deactivation from that state. + +Only put the device into the AWAIT_FINGER_ON state when we know that +another enroll stage is needed. This avoids the critical state +transition simplifying the driver state machine. + +Fixes: #203 +Fixes: 689aff023253e4ca970c9f76f9e4209188175d3d +--- + libfprint/fp-image-device.c | 31 ++++++++++++++++++++++++++++--- + 1 file changed, 28 insertions(+), 3 deletions(-) + +diff --git a/libfprint/fp-image-device.c b/libfprint/fp-image-device.c +index e45b6a9..26c3cb0 100644 +--- a/libfprint/fp-image-device.c ++++ b/libfprint/fp-image-device.c +@@ -51,6 +51,7 @@ typedef struct + FpImageDeviceState state; + gboolean active; + ++ gboolean enroll_await_on_pending; + gint enroll_stage; + + guint pending_activation_timeout_id; +@@ -256,6 +257,7 @@ fp_image_device_start_capture_action (FpDevice *device) + } + + priv->enroll_stage = 0; ++ priv->enroll_await_on_pending = FALSE; + + /* The device might still be deactivating from a previous call. + * In that situation, try to wait for a bit before reporting back an +@@ -385,6 +387,22 @@ fp_image_device_init (FpImageDevice *self) + + } + ++static void ++fp_image_device_enroll_maybe_await_finger_on (FpImageDevice *self) ++{ ++ FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); ++ ++ if (priv->enroll_await_on_pending) ++ { ++ priv->enroll_await_on_pending = FALSE; ++ fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON); ++ } ++ else ++ { ++ priv->enroll_await_on_pending = TRUE; ++ } ++} ++ + static void + fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, gpointer user_data) + { +@@ -446,11 +464,16 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g + fpi_device_enroll_progress (device, priv->enroll_stage, + g_steal_pointer (&print), error); + ++ /* Start another scan or deactivate. */ + if (priv->enroll_stage == IMG_ENROLL_STAGES) + { + fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL); + fp_image_device_deactivate (device); + } ++ else ++ { ++ fp_image_device_enroll_maybe_await_finger_on (FP_IMAGE_DEVICE (device)); ++ } + } + else if (action == FP_DEVICE_ACTION_VERIFY) + { +@@ -572,13 +595,15 @@ fpi_image_device_report_finger_status (FpImageDevice *self, + * 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). ++ * ++ * The enroll case is special as AWAIT_FINGER_ON should only happen after ++ * minutiae detection to prevent deactivation (without cancellation) ++ * from the AWAIT_FINGER_ON state. + */ + 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); ++ fp_image_device_enroll_maybe_await_finger_on (self); + } + } + +-- +2.24.1 + diff --git a/SOURCES/0088-uru4000-Fix-state-change-from-IRQ-handler.patch b/SOURCES/0088-uru4000-Fix-state-change-from-IRQ-handler.patch new file mode 100644 index 0000000..0e9b77e --- /dev/null +++ b/SOURCES/0088-uru4000-Fix-state-change-from-IRQ-handler.patch @@ -0,0 +1,43 @@ +From b71219b5f80b646ca9655799d33bdcccf67daa66 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Wed, 4 Dec 2019 17:14:35 +0100 +Subject: [PATCH 088/181] uru4000: Fix state change from IRQ handler + +The IRQ handler will re-register itself automatically. However, if this +happens after the callback is called, then the check whether the IRQ +handler is running fails. + +Re-start the IRQ handler before calling the callback. This way the state +changes happening from the callback will see the correct IRQ handler +registration state. + +See: #205 +--- + libfprint/drivers/uru4000.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c +index 122544d..4385f29 100644 +--- a/libfprint/drivers/uru4000.c ++++ b/libfprint/drivers/uru4000.c +@@ -332,6 +332,8 @@ irq_handler (FpiUsbTransfer *transfer, + return; + } + ++ start_irq_handler (imgdev); ++ + type = GUINT16_FROM_BE (*((uint16_t *) data)); + fp_dbg ("recv irq type %04x", type); + +@@ -344,8 +346,6 @@ irq_handler (FpiUsbTransfer *transfer, + urudev->irq_cb (imgdev, NULL, type, urudev->irq_cb_data); + else + fp_dbg ("ignoring interrupt"); +- +- start_irq_handler (imgdev); + } + + static void +-- +2.24.1 + diff --git a/SOURCES/0089-uru4000-Fix-control-transfer-request-type.patch b/SOURCES/0089-uru4000-Fix-control-transfer-request-type.patch new file mode 100644 index 0000000..c34899d --- /dev/null +++ b/SOURCES/0089-uru4000-Fix-control-transfer-request-type.patch @@ -0,0 +1,38 @@ +From 7c15f7083406a40314b818c508359cf1e6a7926d Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Wed, 4 Dec 2019 13:07:10 +0100 +Subject: [PATCH 089/181] uru4000: Fix control transfer request type + +During porting the request type was accidentally changed from VENDOR to +DEVICE. Change the type back to VENDOR. + +See: #205 +--- + libfprint/drivers/uru4000.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c +index 4385f29..5128a12 100644 +--- a/libfprint/drivers/uru4000.c ++++ b/libfprint/drivers/uru4000.c +@@ -175,7 +175,7 @@ write_regs (FpImageDevice *dev, uint16_t first_reg, + 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_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + USB_RQ, first_reg, 0, + num_regs); +@@ -202,7 +202,7 @@ read_regs (FpImageDevice *dev, uint16_t first_reg, + + fpi_usb_transfer_fill_control (transfer, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, +- G_USB_DEVICE_REQUEST_TYPE_STANDARD, ++ G_USB_DEVICE_REQUEST_TYPE_VENDOR, + G_USB_DEVICE_RECIPIENT_DEVICE, + USB_RQ, first_reg, 0, num_regs); + fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, callback, user_data); +-- +2.24.1 + diff --git a/SOURCES/0090-fpi-ssm-Support-named-SSMs-and-use-a-fallback-macro.patch b/SOURCES/0090-fpi-ssm-Support-named-SSMs-and-use-a-fallback-macro.patch new file mode 100644 index 0000000..9bd4a21 --- /dev/null +++ b/SOURCES/0090-fpi-ssm-Support-named-SSMs-and-use-a-fallback-macro.patch @@ -0,0 +1,168 @@ +From 3dcd18da12dfdcd2f0da01c4099dac91c80b16ea Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 20:03:23 +0100 +Subject: [PATCH 090/181] fpi-ssm: Support named SSMs and use a fallback macro + +Add fpi_ssm_new_full() that allows to pass a name to the state-machine +constructor, not to change all the drivers, provide a fpi_ssm_new() macro +that stringifies the nr_parameters value (usually an enum value) as the name +so that we can use it for better debugging. +--- + doc/libfprint-sections.txt | 1 + + libfprint/fpi-ssm.c | 43 +++++++++++++++++++++++++++----------- + libfprint/fpi-ssm.h | 9 +++++--- + 3 files changed, 38 insertions(+), 15 deletions(-) + +diff --git a/doc/libfprint-sections.txt b/doc/libfprint-sections.txt +index 9fb01bd..9e17f8e 100644 +--- a/doc/libfprint-sections.txt ++++ b/doc/libfprint-sections.txt +@@ -211,6 +211,7 @@ fpi_print_bz3_match + FpiSsmCompletedCallback + FpiSsmHandlerCallback + fpi_ssm_new ++fpi_ssm_new_full + fpi_ssm_free + fpi_ssm_start + fpi_ssm_start_subsm +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index 09a31e3..96336e1 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -81,6 +81,7 @@ + struct _FpiSsm + { + FpDevice *dev; ++ const char *name; + FpiSsm *parentsm; + gpointer ssm_data; + GDestroyNotify ssm_data_destroy; +@@ -103,13 +104,29 @@ struct _FpiSsm + * + * Allocate a new ssm, with @nr_states states. The @handler callback + * will be called after each state transition. ++ * This is a macro that calls fpi_ssm_new_full() using the stringified ++ * version of @nr_states, so will work better with named parameters. ++ * ++ * Returns: a new #FpiSsm state machine ++ */ ++ ++/** ++ * fpi_ssm_new_full: ++ * @dev: a #fp_dev fingerprint device ++ * @handler: the callback function ++ * @nr_states: the number of states ++ * @name: the name of the state machine (for debug purposes) ++ * ++ * Allocate a new ssm, with @nr_states states. The @handler callback ++ * will be called after each state transition. + * + * Returns: a new #FpiSsm state machine + */ + FpiSsm * +-fpi_ssm_new (FpDevice *dev, +- FpiSsmHandlerCallback handler, +- int nr_states) ++fpi_ssm_new_full (FpDevice *dev, ++ FpiSsmHandlerCallback handler, ++ int nr_states, ++ const char *name) + { + FpiSsm *machine; + +@@ -120,6 +137,7 @@ fpi_ssm_new (FpDevice *dev, + machine->handler = handler; + machine->nr_states = nr_states; + machine->dev = dev; ++ machine->name = g_strdup (name); + machine->completed = TRUE; + return machine; + } +@@ -251,6 +269,7 @@ fpi_ssm_free (FpiSsm *machine) + if (machine->ssm_data_destroy) + g_clear_pointer (&machine->ssm_data, machine->ssm_data_destroy); + g_clear_pointer (&machine->error, g_error_free); ++ g_clear_pointer (&machine->name, g_free); + fpi_ssm_clear_delayed_action (machine); + g_free (machine); + } +@@ -259,7 +278,7 @@ fpi_ssm_free (FpiSsm *machine) + static void + __ssm_call_handler (FpiSsm *machine) + { +- fp_dbg ("%p entering state %d", machine, machine->cur_state); ++ fp_dbg ("%s entering state %d", machine->name, machine->cur_state); + machine->handler (machine, machine->dev); + } + +@@ -337,9 +356,9 @@ fpi_ssm_mark_completed (FpiSsm *machine) + machine->completed = TRUE; + + if (machine->error) +- fp_dbg ("%p completed with error: %s", machine, machine->error->message); ++ fp_dbg ("%s completed with error: %s", machine->name, machine->error->message); + else +- fp_dbg ("%p completed successfully", machine); ++ fp_dbg ("%s completed successfully", machine->name); + if (machine->callback) + { + GError *error = machine->error ? g_error_copy (machine->error) : NULL; +@@ -383,9 +402,9 @@ fpi_ssm_mark_completed_delayed (FpiSsm *machine, + on_device_timeout_complete, cancellable, + machine, NULL); + +- source_name = g_strdup_printf ("[%s] ssm %p complete %d", ++ source_name = g_strdup_printf ("[%s] ssm %s complete %d", + fp_device_get_device_id (machine->dev), +- machine, machine->cur_state + 1); ++ machine->name, machine->cur_state + 1); + g_source_set_name (machine->timeout, source_name); + } + +@@ -482,9 +501,9 @@ fpi_ssm_next_state_delayed (FpiSsm *machine, + on_device_timeout_next_state, cancellable, + machine, NULL); + +- source_name = g_strdup_printf ("[%s] ssm %p jump to next state %d", ++ source_name = g_strdup_printf ("[%s] ssm %s jump to next state %d", + fp_device_get_device_id (machine->dev), +- machine, machine->cur_state + 1); ++ machine->name, machine->cur_state + 1); + g_source_set_name (machine->timeout, source_name); + } + +@@ -559,9 +578,9 @@ fpi_ssm_jump_to_state_delayed (FpiSsm *machine, + on_device_timeout_jump_to_state, + cancellable, data, g_free); + +- source_name = g_strdup_printf ("[%s] ssm %p jump to state %d", ++ source_name = g_strdup_printf ("[%s] ssm %s jump to state %d", + fp_device_get_device_id (machine->dev), +- machine, state); ++ machine->name, state); + g_source_set_name (machine->timeout, source_name); + } + +diff --git a/libfprint/fpi-ssm.h b/libfprint/fpi-ssm.h +index 3ef653e..d1334b5 100644 +--- a/libfprint/fpi-ssm.h ++++ b/libfprint/fpi-ssm.h +@@ -60,9 +60,12 @@ typedef void (*FpiSsmHandlerCallback)(FpiSsm *ssm, + FpDevice *dev); + + /* for library and drivers */ +-FpiSsm *fpi_ssm_new (FpDevice *dev, +- FpiSsmHandlerCallback handler, +- int nr_states); ++#define fpi_ssm_new(dev, handler, nr_states) \ ++ fpi_ssm_new_full (dev, handler, nr_states, #nr_states) ++FpiSsm *fpi_ssm_new_full (FpDevice *dev, ++ FpiSsmHandlerCallback handler, ++ int nr_states, ++ const char *machine_name); + void fpi_ssm_free (FpiSsm *machine); + void fpi_ssm_start (FpiSsm *ssm, + FpiSsmCompletedCallback callback); +-- +2.24.1 + diff --git a/SOURCES/0091-fpi-ssm-Improve-debugging-of-SSM-using-driver-infos.patch b/SOURCES/0091-fpi-ssm-Improve-debugging-of-SSM-using-driver-infos.patch new file mode 100644 index 0000000..c85e301 --- /dev/null +++ b/SOURCES/0091-fpi-ssm-Improve-debugging-of-SSM-using-driver-infos.patch @@ -0,0 +1,59 @@ +From 49f9cbb5670565c7ddbc78768ff0ec14d99269eb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 20:14:16 +0100 +Subject: [PATCH 091/181] fpi-ssm: Improve debugging of SSM using driver infos + +Always mention the driver that is triggering it +--- + libfprint/fpi-ssm.c | 16 +++++++++++----- + 1 file changed, 11 insertions(+), 5 deletions(-) + +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index 96336e1..8b3e4bd 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -278,7 +278,8 @@ fpi_ssm_free (FpiSsm *machine) + static void + __ssm_call_handler (FpiSsm *machine) + { +- fp_dbg ("%s entering state %d", machine->name, machine->cur_state); ++ fp_dbg ("[%s] %s entering state %d", fp_device_get_driver (machine->dev), ++ machine->name, machine->cur_state); + machine->handler (machine, machine->dev); + } + +@@ -356,9 +357,11 @@ fpi_ssm_mark_completed (FpiSsm *machine) + machine->completed = TRUE; + + if (machine->error) +- fp_dbg ("%s completed with error: %s", machine->name, machine->error->message); ++ fp_dbg ("[%s] %s completed with error: %s", fp_device_get_driver (machine->dev), ++ machine->name, machine->error->message); + else +- fp_dbg ("%s completed successfully", machine->name); ++ fp_dbg ("[%s] %s completed successfully", fp_device_get_driver (machine->dev), ++ machine->name); + if (machine->callback) + { + GError *error = machine->error ? g_error_copy (machine->error) : NULL; +@@ -421,12 +424,15 @@ fpi_ssm_mark_failed (FpiSsm *machine, GError *error) + g_assert (error); + if (machine->error) + { +- fp_warn ("SSM already has an error set, ignoring new error %s", error->message); ++ fp_warn ("[%s] SSM %s already has an error set, ignoring new error %s", ++ fp_device_get_driver (machine->dev), machine->name, error->message); + g_error_free (error); + return; + } + +- fp_dbg ("SSM failed in state %d with error: %s", machine->cur_state, error->message); ++ fp_dbg ("[%s] SSM %s failed in state %d with error: %s", ++ fp_device_get_driver (machine->dev), machine->name, ++ machine->cur_state, error->message); + machine->error = g_steal_pointer (&error); + fpi_ssm_mark_completed (machine); + } +-- +2.24.1 + diff --git a/SOURCES/0092-vfs0051-Use-named-SSMs-for-usb-async-exchanges.patch b/SOURCES/0092-vfs0051-Use-named-SSMs-for-usb-async-exchanges.patch new file mode 100644 index 0000000..7d41a6f --- /dev/null +++ b/SOURCES/0092-vfs0051-Use-named-SSMs-for-usb-async-exchanges.patch @@ -0,0 +1,61 @@ +From 170fca1c03aa1becb5e5dc84fa9c61a3f7cf1a32 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 4 Dec 2019 20:14:49 +0100 +Subject: [PATCH 092/181] vfs0051: Use named SSMs for usb async exchanges + +--- + libfprint/drivers/vfs5011.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/libfprint/drivers/vfs5011.c b/libfprint/drivers/vfs5011.c +index 265495a..4af3207 100644 +--- a/libfprint/drivers/vfs5011.c ++++ b/libfprint/drivers/vfs5011.c +@@ -190,11 +190,13 @@ usbexchange_loop (FpiSsm *ssm, FpDevice *_dev) + + static void + usb_exchange_async (FpiSsm *ssm, +- struct usbexchange_data *data) ++ struct usbexchange_data *data, ++ const char *exchange_name) + { +- FpiSsm *subsm = fpi_ssm_new (FP_DEVICE (data->device), +- usbexchange_loop, +- data->stepcount); ++ FpiSsm *subsm = fpi_ssm_new_full (FP_DEVICE (data->device), ++ usbexchange_loop, ++ data->stepcount, ++ exchange_name); + + fpi_ssm_set_data (subsm, data, NULL); + fpi_ssm_start_subsm (ssm, subsm); +@@ -684,7 +686,7 @@ activate_loop (FpiSsm *ssm, FpDevice *_dev) + self->init_sequence.receive_buf = + g_malloc0 (VFS5011_RECEIVE_BUF_SIZE); + self->init_sequence.timeout = 1000; +- usb_exchange_async (ssm, &self->init_sequence); ++ usb_exchange_async (ssm, &self->init_sequence, "ACTIVATE REQUEST"); + break; + + case DEV_ACTIVATE_INIT_COMPLETE: +@@ -716,7 +718,7 @@ activate_loop (FpiSsm *ssm, FpDevice *_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); ++ usb_exchange_async (ssm, &self->init_sequence, "PREPARE CAPTURE"); + break; + + } +@@ -769,7 +771,7 @@ open_loop (FpiSsm *ssm, FpDevice *_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); ++ usb_exchange_async (ssm, &self->init_sequence, "DEVICE OPEN"); + break; + } + ; +-- +2.24.1 + diff --git a/SOURCES/0093-image-device-Print-warning-for-incorrect-deactivatio.patch b/SOURCES/0093-image-device-Print-warning-for-incorrect-deactivatio.patch new file mode 100644 index 0000000..54e36ee --- /dev/null +++ b/SOURCES/0093-image-device-Print-warning-for-incorrect-deactivatio.patch @@ -0,0 +1,56 @@ +From dfef13a3eb14ded653a0f1226eb5903e0b81b772 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Wed, 4 Dec 2019 19:54:07 +0100 +Subject: [PATCH 093/181] image-device: Print warning for incorrect + deactivation + +Drivers may not handle deactivation properly when they are awaiting a +finger. This should be prevented by the internal FpImageDevice state +machine. +--- + libfprint/fp-image-device.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/libfprint/fp-image-device.c b/libfprint/fp-image-device.c +index 26c3cb0..252f414 100644 +--- a/libfprint/fp-image-device.c ++++ b/libfprint/fp-image-device.c +@@ -50,6 +50,7 @@ typedef struct + { + FpImageDeviceState state; + gboolean active; ++ gboolean cancelling; + + gboolean enroll_await_on_pending; + gint enroll_stage; +@@ -140,6 +141,9 @@ fp_image_device_deactivate (FpDevice *device) + fp_dbg ("Already deactivated, ignoring request."); + return; + } ++ if (!priv->cancelling && priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON) ++ g_warning ("Deactivating image device while waiting for finger, this should not happen."); ++ + priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE; + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]); + +@@ -203,6 +207,7 @@ static void + fp_image_device_cancel_action (FpDevice *device) + { + FpImageDevice *self = FP_IMAGE_DEVICE (device); ++ FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + FpDeviceAction action; + + action = fpi_device_get_current_action (device); +@@ -214,7 +219,9 @@ fp_image_device_cancel_action (FpDevice *device) + action == FP_DEVICE_ACTION_IDENTIFY || + action == FP_DEVICE_ACTION_CAPTURE) + { ++ priv->cancelling = TRUE; + fp_image_device_deactivate (FP_DEVICE (self)); ++ priv->cancelling = FALSE; + + /* XXX: Some nicer way of doing this would be good. */ + fpi_device_action_error (FP_DEVICE (self), +-- +2.24.1 + diff --git a/SOURCES/0094-virtual-image-Only-print-warnings-for-actual-errors.patch b/SOURCES/0094-virtual-image-Only-print-warnings-for-actual-errors.patch new file mode 100644 index 0000000..1f6424f --- /dev/null +++ b/SOURCES/0094-virtual-image-Only-print-warnings-for-actual-errors.patch @@ -0,0 +1,42 @@ +From c064261975a12c68d34da8f52ff11942842a4e61 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Wed, 4 Dec 2019 19:55:25 +0100 +Subject: [PATCH 094/181] virtual-image: Only print warnings for actual errors + +No need to warn for lost connections (if we don't expect more data) or +cancellations. +--- + libfprint/drivers/virtual-image.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/libfprint/drivers/virtual-image.c b/libfprint/drivers/virtual-image.c +index c271c7a..07a631f 100644 +--- a/libfprint/drivers/virtual-image.c ++++ b/libfprint/drivers/virtual-image.c +@@ -75,9 +75,9 @@ recv_image_img_recv_cb (GObject *source_object, + { + if (!success) + { +- g_warning ("Error receiving header for image data: %s", error->message); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; ++ g_warning ("Error receiving header for image data: %s", error->message); + } + + self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); +@@ -113,9 +113,10 @@ recv_image_hdr_recv_cb (GObject *source_object, + { + if (!success) + { +- g_warning ("Error receiving header for image data: %s", error->message); +- if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) ++ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) || ++ g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED)) + return; ++ g_warning ("Error receiving header for image data: %s", error->message); + } + + self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); +-- +2.24.1 + diff --git a/SOURCES/0095-virtual-image-Allow-fine-control-over-the-finger-sta.patch b/SOURCES/0095-virtual-image-Allow-fine-control-over-the-finger-sta.patch new file mode 100644 index 0000000..bbc0899 --- /dev/null +++ b/SOURCES/0095-virtual-image-Allow-fine-control-over-the-finger-sta.patch @@ -0,0 +1,68 @@ +From 57203198c5d777fedd50b4509b765dfa08b73992 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Wed, 4 Dec 2019 19:56:54 +0100 +Subject: [PATCH 095/181] virtual-image: Allow fine control over the finger + state + +Add commands to disable automatic finger reporting for images and to +send a specific finger report. This is useful to test more code paths +inside the image-device code. +--- + libfprint/drivers/virtual-image.c | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +diff --git a/libfprint/drivers/virtual-image.c b/libfprint/drivers/virtual-image.c +index 07a631f..33f322e 100644 +--- a/libfprint/drivers/virtual-image.c ++++ b/libfprint/drivers/virtual-image.c +@@ -47,6 +47,7 @@ struct _FpDeviceVirtualImage + gint socket_fd; + gint client_fd; + ++ gboolean automatic_finger; + FpImage *recv_img; + gint recv_img_hdr[2]; + }; +@@ -89,9 +90,11 @@ recv_image_img_recv_cb (GObject *source_object, + self = FPI_DEVICE_VIRTUAL_IMAGE (user_data); + device = FP_IMAGE_DEVICE (self); + +- fpi_image_device_report_finger_status (device, TRUE); ++ if (self->automatic_finger) ++ 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); ++ if (self->automatic_finger) ++ 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)); +@@ -148,6 +151,17 @@ recv_image_hdr_recv_cb (GObject *source_object, + fpi_device_error_new (self->recv_img_hdr[1])); + break; + ++ case -3: ++ /* -3 sets/clears automatic finger detection for images */ ++ self->automatic_finger = !!self->recv_img_hdr[1]; ++ break; ++ ++ case -4: ++ /* -4 submits a finger detection report */ ++ fpi_image_device_report_finger_status (FP_IMAGE_DEVICE (self), ++ !!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); +@@ -214,6 +228,7 @@ new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data + } + + dev->connection = connection; ++ dev->automatic_finger = TRUE; + stream = g_io_stream_get_input_stream (G_IO_STREAM (connection)); + + recv_image (dev, stream); +-- +2.24.1 + diff --git a/SOURCES/0096-tests-Update-helper-functions-for-new-virtual-image-.patch b/SOURCES/0096-tests-Update-helper-functions-for-new-virtual-image-.patch new file mode 100644 index 0000000..8bd6468 --- /dev/null +++ b/SOURCES/0096-tests-Update-helper-functions-for-new-virtual-image-.patch @@ -0,0 +1,106 @@ +From 77adf957d514715ea23f0810c07253cf3b97156e Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Wed, 4 Dec 2019 19:58:26 +0100 +Subject: [PATCH 096/181] tests: Update helper functions for new virtual-image + features + +This also changes the code to keep the connection open and adds +automatic mainloop iteration to ensure the driver processes the request. +This is important so we will not deadlock when we send multiple +requests. +--- + tests/virtual-image.py | 65 +++++++++++++++++++++++++----------------- + 1 file changed, 39 insertions(+), 26 deletions(-) + +diff --git a/tests/virtual-image.py b/tests/virtual-image.py +index 363219a..86bd86d 100755 +--- a/tests/virtual-image.py ++++ b/tests/virtual-image.py +@@ -24,20 +24,6 @@ if wrapper: + os.unsetenv('LIBFPRINT_TEST_WRAPPER') + sys.exit(subprocess.check_call(wrap_cmd)) + +-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) + +@@ -101,24 +87,51 @@ class VirtualImage(unittest.TestCase): + def setUp(self): + self.dev.open_sync() + ++ self.con = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) ++ self.con.connect(self.sockaddr) ++ + def tearDown(self): ++ self.con.close() ++ del self.con + 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): ++ def send_retry(self, retry_error=1, iterate=True): ++ # The default (1) is too-short ++ self.sendall(struct.pack('ii', -1, retry_error)) ++ while iterate and ctx.pending(): ++ ctx.iteration(False) ++ ++ def send_error(self, device_error=0, iterate=True): ++ # The default (0) is a generic error ++ self.sendall(struct.pack('ii', -1, retry_error)) ++ while iterate and ctx.pending(): ++ ctx.iteration(False) ++ ++ def send_finger_automatic(self, automatic, iterate=True): ++ # Set whether finger on/off is reported around images ++ self.con.sendall(struct.pack('ii', -3, 1 if automatic else 0)) ++ while iterate and ctx.pending(): ++ ctx.iteration(False) ++ ++ def send_finger_report(self, has_finger, iterate=True): ++ # Send finger on/off ++ self.con.sendall(struct.pack('ii', -4, 1 if has_finger else 0)) ++ while iterate and ctx.pending(): ++ ctx.iteration(False) ++ ++ def send_image(self, image, iterate=True): + 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 ++ 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) ++ self.con.sendall(encoded_img) ++ while iterate and ctx.pending(): ++ ctx.iteration(False) + + def test_capture_prevents_close(self): + cancel = Gio.Cancellable() +-- +2.24.1 + diff --git a/SOURCES/0097-tests-Test-finger-removal-after-minutiae-scan-comple.patch b/SOURCES/0097-tests-Test-finger-removal-after-minutiae-scan-comple.patch new file mode 100644 index 0000000..a6a0564 --- /dev/null +++ b/SOURCES/0097-tests-Test-finger-removal-after-minutiae-scan-comple.patch @@ -0,0 +1,34 @@ +From e4c2c0a75a3032b26c5a7b361a0449120bb46529 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Wed, 4 Dec 2019 20:00:49 +0100 +Subject: [PATCH 097/181] tests: Test finger removal after minutiae scan + completion + +--- + tests/virtual-image.py | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/tests/virtual-image.py b/tests/virtual-image.py +index 86bd86d..87c221b 100755 +--- a/tests/virtual-image.py ++++ b/tests/virtual-image.py +@@ -182,10 +182,16 @@ class VirtualImage(unittest.TestCase): + while self._step < 1: + ctx.iteration(True) + ++ # Test the image-device path where the finger is removed after ++ # the minutiae scan is completed. ++ self.send_finger_automatic(False) ++ self.send_finger_report(True) + self.send_image(image) + while self._step < 2: + ctx.iteration(True) ++ self.send_finger_report(False) + ++ self.send_finger_automatic(True) + self.send_image(image) + while self._step < 3: + ctx.iteration(True) +-- +2.24.1 + diff --git a/SOURCES/0098-print-Fix-match-error-propagation.patch b/SOURCES/0098-print-Fix-match-error-propagation.patch new file mode 100644 index 0000000..99943ec --- /dev/null +++ b/SOURCES/0098-print-Fix-match-error-propagation.patch @@ -0,0 +1,40 @@ +From 4d0f8ba66ba170e6e983ff467b79c66707dbe600 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Thu, 5 Dec 2019 10:53:22 +0100 +Subject: [PATCH 098/181] print: Fix match error propagation + +The FPI_MATCH_ERROR constant was set to 0, however it is propagated to +the task completion using g_task_propagate_int. As g_task_propagate_int +will always return -1 on error, we either need to add an explicit -1 +check or we just need to match the semantics. + +Change the constant to -1, also rearange FP_MATCH_SUCCESS so that it +does not end up being 0. +--- + libfprint/fpi-print.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libfprint/fpi-print.h b/libfprint/fpi-print.h +index 94670a0..04500d6 100644 +--- a/libfprint/fpi-print.h ++++ b/libfprint/fpi-print.h +@@ -21,13 +21,13 @@ typedef enum { + /** + * FpiMatchResult: + * @FPI_MATCH_ERROR: An error occured during matching +- * @FPI_MATCH_SUCCESS: The prints matched + * @FPI_MATCH_FAIL: The prints did not match ++ * @FPI_MATCH_SUCCESS: The prints matched + */ + typedef enum { +- FPI_MATCH_ERROR = 0, +- FPI_MATCH_SUCCESS, ++ FPI_MATCH_ERROR = -1, /* -1 for g_task_propagate_int */ + FPI_MATCH_FAIL, ++ FPI_MATCH_SUCCESS, + } FpiMatchResult; + + void fpi_print_add_print (FpPrint *print, +-- +2.24.1 + diff --git a/SOURCES/0099-synaptics-Fix-problem-after-match-is-failed.patch b/SOURCES/0099-synaptics-Fix-problem-after-match-is-failed.patch new file mode 100644 index 0000000..ee24b6a --- /dev/null +++ b/SOURCES/0099-synaptics-Fix-problem-after-match-is-failed.patch @@ -0,0 +1,32 @@ +From 55f1d4b575cd881f61f6e0cc20e468a16ae276f9 Mon Sep 17 00:00:00 2001 +From: Vincent Huang +Date: Mon, 9 Dec 2019 14:12:54 +0800 +Subject: [PATCH 099/181] synaptics: Fix problem after match is failed + +This fixes the the problem that the sensor becomes unresponsive after +pressing the wrong fingerprint. We fix the problem by making sure that +the non-match report is delayed until the finger is removed. With this +we cannot run into the situation that the next match request fails +immediately as the finger is still present. + +Fixes: #208 +--- + libfprint/drivers/synaptics/synaptics.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c +index 247b658..6ed6791 100644 +--- a/libfprint/drivers/synaptics/synaptics.c ++++ b/libfprint/drivers/synaptics/synaptics.c +@@ -168,7 +168,7 @@ cmd_recieve_cb (FpiUsbTransfer *transfer, + * depending on resp.complete. */ + if (self->cmd_pending_transfer) + fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_SEND_PENDING); +- else if (!resp.complete) ++ else if (!resp.complete || self->cmd_complete_on_removal) + fpi_ssm_next_state (transfer->ssm); /* SYNAPTICS_CMD_WAIT_INTERRUPT */ + else + fpi_ssm_mark_completed (transfer->ssm); +-- +2.24.1 + diff --git a/SOURCES/0100-fp-device-Use-different-pointers-for-device-handlers.patch b/SOURCES/0100-fp-device-Use-different-pointers-for-device-handlers.patch new file mode 100644 index 0000000..5905516 --- /dev/null +++ b/SOURCES/0100-fp-device-Use-different-pointers-for-device-handlers.patch @@ -0,0 +1,50 @@ +From 460e58128fdbcc1035dc1368003c1e4692dfa55e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 5 Dec 2019 13:16:11 +0100 +Subject: [PATCH 100/181] fp-device: Use different pointers for device handlers + +A Fp-device use an union to track the handle to the lower-level device, and +the value depends on the object type. + +So in case of using a virtual device, the priv->usb_device location matches +the priv->virtual_env string location, and thus we'd end up unreffing a +string location as it was a GObject, while we'd leak the string. + +To avoid such errors, instead of just checking the device type when we +finalize the device, let's just use different pointers to avoid other +possible clashes. +--- + libfprint/fp-device.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c +index 2f706b3..08023f2 100644 +--- a/libfprint/fp-device.c ++++ b/libfprint/fp-device.c +@@ -50,11 +50,8 @@ typedef struct + { + FpDeviceType type; + +- union +- { +- GUsbDevice *usb_device; +- const gchar *virtual_env; +- }; ++ GUsbDevice *usb_device; ++ const gchar *virtual_env; + + gboolean is_open; + +@@ -382,7 +379,9 @@ fp_device_finalize (GObject *object) + + g_clear_pointer (&priv->device_id, g_free); + g_clear_pointer (&priv->device_name, g_free); ++ + g_clear_object (&priv->usb_device); ++ g_clear_pointer (&priv->virtual_env, g_free); + + G_OBJECT_CLASS (fp_device_parent_class)->finalize (object); + } +-- +2.24.1 + diff --git a/SOURCES/0101-docs-Don-t-ignore-the-deprecated-API_EXPORTED-defini.patch b/SOURCES/0101-docs-Don-t-ignore-the-deprecated-API_EXPORTED-defini.patch new file mode 100644 index 0000000..f1c1234 --- /dev/null +++ b/SOURCES/0101-docs-Don-t-ignore-the-deprecated-API_EXPORTED-defini.patch @@ -0,0 +1,25 @@ +From 7e5d85de2a8c2055330ff8613bdc914ac5dc9cce Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 5 Dec 2019 14:23:11 +0100 +Subject: [PATCH 101/181] docs: Don't ignore the deprecated API_EXPORTED + definition + +--- + doc/meson.build | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/doc/meson.build b/doc/meson.build +index 407413a..bed320d 100644 +--- a/doc/meson.build ++++ b/doc/meson.build +@@ -32,7 +32,6 @@ gnome.gtkdoc('libfprint', + expand_content_files: expand_content_files, + scan_args: [ + #'--rebuild-sections', +- '--ignore-decorators=API_EXPORTED', + '--ignore-headers=' + ' '.join(private_headers), + ], + fixxref_args: [ +-- +2.24.1 + diff --git a/SOURCES/0102-tests-meson-Set-the-typelib-env-var-only-if-we-have-.patch b/SOURCES/0102-tests-meson-Set-the-typelib-env-var-only-if-we-have-.patch new file mode 100644 index 0000000..e39dbc3 --- /dev/null +++ b/SOURCES/0102-tests-meson-Set-the-typelib-env-var-only-if-we-have-.patch @@ -0,0 +1,34 @@ +From 5be8080ced85d14d7d8905827a8d2af40fcddd8d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 5 Dec 2019 14:39:45 +0100 +Subject: [PATCH 102/181] tests/meson: Set the typelib env var only if we have + introspection + +--- + tests/meson.build | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tests/meson.build b/tests/meson.build +index d6196be..6e56cb3 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -5,7 +5,6 @@ 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 +@@ -15,6 +14,8 @@ envs.set('FP_DEVICE_EMULATION', '1') + envs.set('NO_AT_BRIDGE', '1') + + if get_option('introspection') ++ envs.prepend('GI_TYPELIB_PATH', join_paths(meson.build_root(), 'libfprint')) ++ + if 'virtual_image' in drivers + test('virtual-image', + find_program('virtual-image.py'), +-- +2.24.1 + diff --git a/SOURCES/0103-fp-device-Add-a-open-property-and-method-to-check-it.patch b/SOURCES/0103-fp-device-Add-a-open-property-and-method-to-check-it.patch new file mode 100644 index 0000000..b4369e2 --- /dev/null +++ b/SOURCES/0103-fp-device-Add-a-open-property-and-method-to-check-it.patch @@ -0,0 +1,105 @@ +From 5d29acf713a925bc3c97a2359ca5220f50a0c0be Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 5 Dec 2019 15:05:59 +0100 +Subject: [PATCH 103/181] fp-device: Add a "open" property and method to check + its state + +--- + libfprint/fp-device.c | 33 ++++++++++++++++++++++++++++++++- + libfprint/fp-device.h | 1 + + 2 files changed, 33 insertions(+), 1 deletion(-) + +diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c +index 08023f2..91a3aae 100644 +--- a/libfprint/fp-device.c ++++ b/libfprint/fp-device.c +@@ -88,6 +88,7 @@ enum { + PROP_DRIVER, + PROP_DEVICE_ID, + PROP_NAME, ++ PROP_OPEN, + PROP_NR_ENROLL_STAGES, + PROP_SCAN_TYPE, + PROP_FPI_ENVIRON, +@@ -417,6 +418,10 @@ fp_device_get_property (GObject *object, + g_value_set_string (value, priv->device_name); + break; + ++ case PROP_OPEN: ++ g_value_set_boolean (value, priv->is_open); ++ break; ++ + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +@@ -551,6 +556,12 @@ fp_device_class_init (FpDeviceClass *klass) + NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); + ++ properties[PROP_OPEN] = ++ g_param_spec_boolean ("open", ++ "Opened", ++ "Wether the device is open or not", FALSE, ++ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); ++ + properties[PROP_FPI_ENVIRON] = + g_param_spec_string ("fp-environ", + "Virtual Environment", +@@ -628,6 +639,22 @@ fp_device_get_name (FpDevice *device) + return priv->device_name; + } + ++/** ++ * fp_device_is_open: ++ * @device: A #FpDevice ++ * ++ * Returns: Whether the device is open or not ++ */ ++gboolean ++fp_device_is_open (FpDevice *device) ++{ ++ FpDevicePrivate *priv = fp_device_get_instance_private (device); ++ ++ g_return_val_if_fail (FP_IS_DEVICE (device), FALSE); ++ ++ return priv->is_open; ++} ++ + /** + * fp_device_get_scan_type: + * @device: A #FpDevice +@@ -1959,7 +1986,10 @@ fpi_device_open_complete (FpDevice *device, GError *error) + clear_device_cancel_action (device); + + if (!error) +- priv->is_open = TRUE; ++ { ++ priv->is_open = TRUE; ++ g_object_notify_by_pspec (G_OBJECT (device), properties[PROP_OPEN]); ++ } + + if (!error) + fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, +@@ -1988,6 +2018,7 @@ fpi_device_close_complete (FpDevice *device, GError *error) + + clear_device_cancel_action (device); + priv->is_open = FALSE; ++ g_object_notify_by_pspec (G_OBJECT (device), properties[PROP_OPEN]); + + switch (priv->type) + { +diff --git a/libfprint/fp-device.h b/libfprint/fp-device.h +index a15fc30..4f7acac 100644 +--- a/libfprint/fp-device.h ++++ b/libfprint/fp-device.h +@@ -129,6 +129,7 @@ typedef void (*FpEnrollProgress) (FpDevice *device, + 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); ++gboolean fp_device_is_open (FpDevice *device); + FpScanType fp_device_get_scan_type (FpDevice *device); + gint fp_device_get_nr_enroll_stages (FpDevice *device); + +-- +2.24.1 + diff --git a/SOURCES/0104-libfprint-Introduce-libfprint_private-static-library.patch b/SOURCES/0104-libfprint-Introduce-libfprint_private-static-library.patch new file mode 100644 index 0000000..ab1ea31 --- /dev/null +++ b/SOURCES/0104-libfprint-Introduce-libfprint_private-static-library.patch @@ -0,0 +1,51 @@ +From 763492d5c2f5b042a3fa3cb7307e8221cc57e50b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 5 Dec 2019 14:27:33 +0100 +Subject: [PATCH 104/181] libfprint: Introduce libfprint_private static library + +Split the library into a private part with all the symbols that we can use +for unit-test all the fpi functions. +--- + libfprint/meson.build | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/libfprint/meson.build b/libfprint/meson.build +index f73aba3..1e98e2d 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -4,6 +4,9 @@ libfprint_sources = [ + 'fp-image.c', + 'fp-print.c', + 'fp-image-device.c', ++] ++ ++libfprint_private_sources = [ + 'fpi-assembling.c', + 'fpi-ssm.c', + 'fpi-usb-transfer.c', +@@ -200,15 +203,19 @@ libnbis = static_library('nbis', + ]), + install: false) + ++libfprint_private = static_library('fprint-private', ++ sources: libfprint_private_sources + fpi_enums, ++ dependencies: deps, ++ install: false) ++ + libfprint = library('fprint', +- libfprint_sources + fp_enums + fpi_enums + +- drivers_sources + other_sources, ++ sources: libfprint_sources + fp_enums + drivers_sources + other_sources, + soversion: soversion, + version: libversion, + c_args: drivers_cflags, + link_args : vflag, + link_depends : mapfile, +- link_with: libnbis, ++ link_with: [libnbis, libfprint_private], + dependencies: deps, + install: true) + +-- +2.24.1 + diff --git a/SOURCES/0105-fp-device-Move-fpi-code-into-its-own-unit-that-can-b.patch b/SOURCES/0105-fp-device-Move-fpi-code-into-its-own-unit-that-can-b.patch new file mode 100644 index 0000000..db5f63d --- /dev/null +++ b/SOURCES/0105-fp-device-Move-fpi-code-into-its-own-unit-that-can-b.patch @@ -0,0 +1,2529 @@ +From 3b368f67de150199ba2dfb083ab22e7fd2e4204f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 10 Dec 2019 20:24:04 +0100 +Subject: [PATCH 105/181] fp-device: Move fpi code into its own unit that can + be compiled a part + +In order to be able to test the private device code (used by drivers) we +need to have that split a part in a different .c file so that we can compile +it alone and link with it both the shared library and the test executables. + +Redefine fp_device_get_instance_private for private usage, not to move +the private struct as part of FpDevice. +--- + libfprint/fp-device-private.h | 65 ++ + libfprint/fp-device.c | 1186 +-------------------------------- + libfprint/fpi-device.c | 1177 ++++++++++++++++++++++++++++++++ + libfprint/meson.build | 1 + + 4 files changed, 1245 insertions(+), 1184 deletions(-) + create mode 100644 libfprint/fp-device-private.h + create mode 100644 libfprint/fpi-device.c + +diff --git a/libfprint/fp-device-private.h b/libfprint/fp-device-private.h +new file mode 100644 +index 0000000..65fb1cb +--- /dev/null ++++ b/libfprint/fp-device-private.h +@@ -0,0 +1,65 @@ ++/* ++ * FpDevice - A fingerprint reader device ++ * 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 ++ * 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" ++ ++typedef struct ++{ ++ FpDeviceType type; ++ ++ 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; ++ GSource *current_task_idle_return_source; ++ ++ /* State for tasks */ ++ gboolean wait_for_finger; ++} FpDevicePrivate; ++ ++ ++typedef struct ++{ ++ FpPrint *print; ++ ++ FpEnrollProgress enroll_progress_cb; ++ gpointer enroll_progress_data; ++ GDestroyNotify enroll_progress_destroy; ++} FpEnrollData; ++ ++void enroll_data_free (FpEnrollData *enroll_data); +diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c +index 91a3aae..c49e5a9 100644 +--- a/libfprint/fp-device.c ++++ b/libfprint/fp-device.c +@@ -21,17 +21,7 @@ + #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. +- */ ++#include "fp-device-private.h" + + /** + * SECTION: fpi-device +@@ -46,36 +36,6 @@ + * Also see the public #FpDevice routines. + */ + +-typedef struct +-{ +- FpDeviceType type; +- +- 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; +- GSource *current_task_idle_return_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, +@@ -99,27 +59,6 @@ enum { + + 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: + * +@@ -134,150 +73,6 @@ G_DEFINE_QUARK (fp - device - retry - quark, fp_device_retry) + **/ + 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 device_error, +- const gchar *msg, +- ...) +-{ +- GError *error; +- va_list args; +- +- va_start (args, msg); +- error = g_error_new_valist (FP_DEVICE_RETRY, device_error, msg, args); +- va_end (args); +- +- return error; +-} +- +-/** +- * 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 device_error, +- const gchar *msg, +- ...) +-{ +- GError *error; +- va_list args; +- +- va_start (args, msg); +- error = g_error_new_valist (FP_DEVICE_ERROR, device_error, msg, args); +- va_end (args); +- +- return error; +-} +- + static gboolean + fp_device_cancel_in_idle_cb (gpointer user_data) + { +@@ -330,21 +125,6 @@ maybe_cancel_on_cancelled (FpDevice *device, + NULL); + } + +-static void +-clear_device_cancel_action (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) +- { +- g_cancellable_disconnect (g_task_get_cancellable (priv->current_task), +- priv->current_cancellable_id); +- priv->current_cancellable_id = 0; +- } +-} +- + static void + fp_device_constructed (GObject *object) + { +@@ -976,7 +756,7 @@ fp_device_enroll (FpDevice *device, + 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); ++ g_task_set_task_data (priv->current_task, data, (GDestroyNotify) enroll_data_free); + + FP_DEVICE_GET_CLASS (device)->enroll (device); + } +@@ -1406,968 +1186,6 @@ fp_device_list_prints_finish (FpDevice *device, + return g_task_propagate_pointer (G_TASK (result), error); + } + +-typedef struct +-{ +- GSource source; +- FpDevice *device; +-} FpDeviceTimeoutSource; +- +-static 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 gsource_func, gpointer user_data) +-{ +- FpDeviceTimeoutSource *timeout_source = (FpDeviceTimeoutSource *) source; +- FpTimeoutFunc callback = (FpTimeoutFunc) gsource_func; +- +- 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: (nullable): User data to pass to the callback +- * @destroy_notify: (nullable): #GDestroyNotify for @user_data +- * +- * 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, +- GDestroyNotify destroy_notify) +-{ +- FpDevicePrivate *priv = fp_device_get_instance_private (device); +- FpDeviceTimeoutSource *source; +- +- source = (FpDeviceTimeoutSource *) g_source_new (&timeout_funcs, +- sizeof (FpDeviceTimeoutSource)); +- source->device = device; +- +- g_source_attach (&source->source, NULL); +- g_source_set_callback (&source->source, (GSourceFunc) func, user_data, destroy_notify); +- 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; +- } +-} +- +-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 +- * @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_return_if_fail (FP_IS_DEVICE (device)); +- g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_PROBE); +- +- g_debug ("Device reported probe completion"); +- +- clear_device_cancel_action (device); +- +- 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]); +- } +- fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, +- GUINT_TO_POINTER (TRUE)); +- } +- else +- { +- fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, 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_return_if_fail (FP_IS_DEVICE (device)); +- g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_OPEN); +- +- g_debug ("Device reported open completion"); +- +- clear_device_cancel_action (device); +- +- if (!error) +- { +- priv->is_open = TRUE; +- g_object_notify_by_pspec (G_OBJECT (device), properties[PROP_OPEN]); +- } +- +- if (!error) +- fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, +- GUINT_TO_POINTER (TRUE)); +- else +- fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, 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) +-{ +- 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"); +- +- clear_device_cancel_action (device); +- priv->is_open = FALSE; +- g_object_notify_by_pspec (G_OBJECT (device), properties[PROP_OPEN]); +- +- switch (priv->type) +- { +- case FP_DEVICE_TYPE_USB: +- if (!g_usb_device_close (priv->usb_device, &nested_error)) +- { +- if (error == NULL) +- error = nested_error; +- fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); +- return; +- } +- break; +- +- case FP_DEVICE_TYPE_VIRTUAL: +- break; +- +- default: +- g_assert_not_reached (); +- fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, +- fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); +- return; +- } +- +- if (!error) +- fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, +- GUINT_TO_POINTER (TRUE)); +- else +- fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, 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_return_if_fail (FP_IS_DEVICE (device)); +- g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_ENROLL); +- +- g_debug ("Device reported enroll completion"); +- +- clear_device_cancel_action (device); +- +- if (!error) +- { +- if (FP_IS_PRINT (print)) +- { +- 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!"); +- 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 +- { +- 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!"); +- 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_return_if_fail (FP_IS_DEVICE (device)); +- g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_VERIFY); +- +- g_debug ("Device reported verify completion"); +- +- clear_device_cancel_action (device); +- +- g_object_set_data_full (G_OBJECT (priv->current_task), +- "print", +- print, +- g_object_unref); +- +- if (!error) +- { +- if (result != FPI_MATCH_ERROR) +- { +- 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!"); +- 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 +- { +- 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!"); +- 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_return_if_fail (FP_IS_DEVICE (device)); +- g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_IDENTIFY); +- +- g_debug ("Device reported identify completion"); +- +- clear_device_cancel_action (device); +- +- g_object_set_data_full (G_OBJECT (priv->current_task), +- "print", +- print, +- g_object_unref); +- g_object_set_data_full (G_OBJECT (priv->current_task), +- "match", +- match, +- g_object_unref); +- if (!error) +- { +- fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, +- GUINT_TO_POINTER (TRUE)); +- } +- else +- { +- 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!"); +- 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_return_if_fail (FP_IS_DEVICE (device)); +- g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_CAPTURE); +- +- g_debug ("Device reported capture completion"); +- +- clear_device_cancel_action (device); +- +- if (!error) +- { +- if (image) +- { +- 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!"); +- 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 +- { +- 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!"); +- 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_return_if_fail (FP_IS_DEVICE (device)); +- g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_DELETE); +- +- g_debug ("Device reported deletion completion"); +- +- clear_device_cancel_action (device); +- +- if (!error) +- fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, +- GUINT_TO_POINTER (TRUE)); +- else +- fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, 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) +-{ +- 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"); +- +- clear_device_cancel_action (device); +- +- 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) +- fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_PTR_ARRAY, prints); +- else +- fp_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, 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); +- } +- +- g_clear_error (&error); +- g_clear_object (&print); +-} +- +- + static void + async_result_ready (GObject *source_object, GAsyncResult *res, gpointer user_data) + { +diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c +new file mode 100644 +index 0000000..3eee062 +--- /dev/null ++++ b/libfprint/fpi-device.c +@@ -0,0 +1,1177 @@ ++/* ++ * FpDevice - A fingerprint reader device - Private APIs ++ * 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 ++ * 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 "fp-device-private.h" ++ ++/** ++ * 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. ++ */ ++ ++/* Manually redefine what G_DEFINE_* macro does */ ++static inline gpointer ++fp_device_get_instance_private (FpDevice *self) ++{ ++ FpDeviceClass *dev_class = g_type_class_peek_static (FP_TYPE_DEVICE); ++ ++ return G_STRUCT_MEMBER_P (self, ++ g_type_class_get_instance_private_offset (dev_class)); ++} ++ ++/** ++ * 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 with printf-style formatting ++ * @...: args for @msg ++ * ++ * Create a new retry error code for use with fpi_device_verify_complete() ++ * and similar calls. ++ */ ++GError * ++fpi_device_retry_new_msg (FpDeviceRetry device_error, ++ const gchar *msg, ++ ...) ++{ ++ GError *error; ++ va_list args; ++ ++ va_start (args, msg); ++ error = g_error_new_valist (FP_DEVICE_RETRY, device_error, msg, args); ++ va_end (args); ++ ++ return error; ++} ++ ++/** ++ * fpi_device_error_new_msg: ++ * @error: The #FpDeviceRetry error value describing the issue ++ * @msg: Custom message to use with printf-style formatting ++ * @...: args for @msg ++ * ++ * Create a new error code for use with fpi_device_verify_complete() ++ * and similar calls. ++ */ ++GError * ++fpi_device_error_new_msg (FpDeviceError device_error, ++ const gchar *msg, ++ ...) ++{ ++ GError *error; ++ va_list args; ++ ++ va_start (args, msg); ++ error = g_error_new_valist (FP_DEVICE_ERROR, device_error, msg, args); ++ va_end (args); ++ ++ return error; ++} ++ ++/** ++ * 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 (G_OBJECT (device), "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 (G_OBJECT (device), "scan-type"); ++} ++ ++typedef struct ++{ ++ GSource source; ++ FpDevice *device; ++} FpDeviceTimeoutSource; ++ ++static 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 gsource_func, gpointer user_data) ++{ ++ FpDeviceTimeoutSource *timeout_source = (FpDeviceTimeoutSource *) source; ++ FpTimeoutFunc callback = (FpTimeoutFunc) gsource_func; ++ ++ callback (timeout_source->device, user_data); ++ ++ return G_SOURCE_REMOVE; ++} ++ ++static GSourceFuncs timeout_funcs = { ++ NULL, /* prepare */ ++ NULL, /* check */ ++ timeout_dispatch, ++ timeout_finalize, ++ NULL, NULL ++}; ++ ++/** ++ * fpi_device_add_timeout: ++ * @device: The #FpDevice ++ * @interval: The interval in milliseconds ++ * @func: The #FpTimeoutFunc to call on timeout ++ * @user_data: (nullable): User data to pass to the callback ++ * @destroy_notify: (nullable): #GDestroyNotify for @user_data ++ * ++ * 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, ++ GDestroyNotify destroy_notify) ++{ ++ FpDevicePrivate *priv = fp_device_get_instance_private (device); ++ FpDeviceTimeoutSource *source; ++ ++ source = (FpDeviceTimeoutSource *) g_source_new (&timeout_funcs, ++ sizeof (FpDeviceTimeoutSource)); ++ source->device = device; ++ ++ g_source_attach (&source->source, NULL); ++ g_source_set_callback (&source->source, (GSourceFunc) func, user_data, destroy_notify); ++ 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; ++} ++ ++void ++enroll_data_free (FpEnrollData *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); ++} ++ ++/** ++ * 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; ++ } ++} ++ ++static void ++clear_device_cancel_action (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) ++ { ++ g_cancellable_disconnect (g_task_get_cancellable (priv->current_task), ++ priv->current_cancellable_id); ++ priv->current_cancellable_id = 0; ++ } ++} ++ ++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 ++fpi_device_task_return_data_free (FpDeviceTaskReturnData *data) ++{ ++ g_object_unref (data->device); ++ g_free (data); ++} ++ ++static void ++fpi_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) fpi_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 ++ * @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_return_if_fail (FP_IS_DEVICE (device)); ++ g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_PROBE); ++ ++ g_debug ("Device reported probe completion"); ++ ++ clear_device_cancel_action (device); ++ ++ if (!error) ++ { ++ if (device_id) ++ { ++ g_clear_pointer (&priv->device_id, g_free); ++ priv->device_id = g_strdup (device_id); ++ g_object_notify (G_OBJECT (device), "device-id"); ++ } ++ if (device_name) ++ { ++ g_clear_pointer (&priv->device_name, g_free); ++ priv->device_name = g_strdup (device_name); ++ g_object_notify (G_OBJECT (device), "name"); ++ } ++ fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, ++ GUINT_TO_POINTER (TRUE)); ++ } ++ else ++ { ++ fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, 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_return_if_fail (FP_IS_DEVICE (device)); ++ g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_OPEN); ++ ++ g_debug ("Device reported open completion"); ++ ++ clear_device_cancel_action (device); ++ ++ if (!error) ++ { ++ priv->is_open = TRUE; ++ g_object_notify (G_OBJECT (device), "open"); ++ } ++ ++ if (!error) ++ fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, ++ GUINT_TO_POINTER (TRUE)); ++ else ++ fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, 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) ++{ ++ 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"); ++ ++ clear_device_cancel_action (device); ++ priv->is_open = FALSE; ++ g_object_notify (G_OBJECT (device), "open"); ++ ++ switch (priv->type) ++ { ++ case FP_DEVICE_TYPE_USB: ++ if (!g_usb_device_close (priv->usb_device, &nested_error)) ++ { ++ if (error == NULL) ++ error = nested_error; ++ fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); ++ return; ++ } ++ break; ++ ++ case FP_DEVICE_TYPE_VIRTUAL: ++ break; ++ ++ default: ++ g_assert_not_reached (); ++ fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, ++ fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); ++ return; ++ } ++ ++ if (!error) ++ fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, ++ GUINT_TO_POINTER (TRUE)); ++ else ++ fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, 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_return_if_fail (FP_IS_DEVICE (device)); ++ g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_ENROLL); ++ ++ g_debug ("Device reported enroll completion"); ++ ++ clear_device_cancel_action (device); ++ ++ if (!error) ++ { ++ if (FP_IS_PRINT (print)) ++ { ++ fpi_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!"); ++ error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, ++ "Driver failed to provide print data!"); ++ fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); ++ } ++ } ++ else ++ { ++ fpi_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!"); ++ 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_return_if_fail (FP_IS_DEVICE (device)); ++ g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_VERIFY); ++ ++ g_debug ("Device reported verify completion"); ++ ++ clear_device_cancel_action (device); ++ ++ g_object_set_data_full (G_OBJECT (priv->current_task), ++ "print", ++ print, ++ g_object_unref); ++ ++ if (!error) ++ { ++ if (result != FPI_MATCH_ERROR) ++ { ++ fpi_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!"); ++ error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, ++ "Driver failed to provide an error!"); ++ fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); ++ } ++ } ++ else ++ { ++ fpi_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!"); ++ 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_return_if_fail (FP_IS_DEVICE (device)); ++ g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_IDENTIFY); ++ ++ g_debug ("Device reported identify completion"); ++ ++ clear_device_cancel_action (device); ++ ++ g_object_set_data_full (G_OBJECT (priv->current_task), ++ "print", ++ print, ++ g_object_unref); ++ g_object_set_data_full (G_OBJECT (priv->current_task), ++ "match", ++ match, ++ g_object_unref); ++ if (!error) ++ { ++ fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, ++ GUINT_TO_POINTER (TRUE)); ++ } ++ else ++ { ++ fpi_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!"); ++ 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_return_if_fail (FP_IS_DEVICE (device)); ++ g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_CAPTURE); ++ ++ g_debug ("Device reported capture completion"); ++ ++ clear_device_cancel_action (device); ++ ++ if (!error) ++ { ++ if (image) ++ { ++ fpi_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!"); ++ error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, ++ "Driver failed to provide an error!"); ++ fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); ++ } ++ } ++ else ++ { ++ fpi_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!"); ++ 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_return_if_fail (FP_IS_DEVICE (device)); ++ g_return_if_fail (priv->current_action == FP_DEVICE_ACTION_DELETE); ++ ++ g_debug ("Device reported deletion completion"); ++ ++ clear_device_cancel_action (device); ++ ++ if (!error) ++ fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, ++ GUINT_TO_POINTER (TRUE)); ++ else ++ fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, 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) ++{ ++ 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"); ++ ++ clear_device_cancel_action (device); ++ ++ 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) ++ fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_PTR_ARRAY, prints); ++ else ++ fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, 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); ++ } ++ ++ g_clear_error (&error); ++ g_clear_object (&print); ++} +diff --git a/libfprint/meson.build b/libfprint/meson.build +index 1e98e2d..4a34cbd 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -8,6 +8,7 @@ libfprint_sources = [ + + libfprint_private_sources = [ + 'fpi-assembling.c', ++ 'fpi-device.c', + 'fpi-ssm.c', + 'fpi-usb-transfer.c', + 'fpi-byte-reader.c', +-- +2.24.1 + diff --git a/SOURCES/0106-fp-image-device-Move-fpi-code-into-its-own-unit-that.patch b/SOURCES/0106-fp-image-device-Move-fpi-code-into-its-own-unit-that.patch new file mode 100644 index 0000000..c8857c5 --- /dev/null +++ b/SOURCES/0106-fp-image-device-Move-fpi-code-into-its-own-unit-that.patch @@ -0,0 +1,1324 @@ +From 1de79db6506bb388423d518a8bd1d243ee06b631 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 11 Dec 2019 13:40:47 +0100 +Subject: [PATCH 106/181] fp-image-device: Move fpi code into its own unit that + can be compiled a part + +In order to be able to test the private device code (used by drivers) we +need to have that split a part in a different .c file so that we can compile +it alone and link with it both the shared library and the test executables. + +Redefine fp_image_device_get_instance_private for private usage, not to move +the private struct as part of FpDevice. +--- + libfprint/fp-image-device-private.h | 43 ++ + libfprint/fp-image-device.c | 585 +-------------------------- + libfprint/fpi-image-device.c | 595 ++++++++++++++++++++++++++++ + libfprint/meson.build | 1 + + 4 files changed, 643 insertions(+), 581 deletions(-) + create mode 100644 libfprint/fp-image-device-private.h + create mode 100644 libfprint/fpi-image-device.c + +diff --git a/libfprint/fp-image-device-private.h b/libfprint/fp-image-device-private.h +new file mode 100644 +index 0000000..01454fd +--- /dev/null ++++ b/libfprint/fp-image-device-private.h +@@ -0,0 +1,43 @@ ++/* ++ * 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-image-device.h" ++ ++#define IMG_ENROLL_STAGES 5 ++ ++typedef struct ++{ ++ FpImageDeviceState state; ++ gboolean active; ++ gboolean cancelling; ++ ++ gboolean enroll_await_on_pending; ++ gint enroll_stage; ++ ++ guint pending_activation_timeout_id; ++ gboolean pending_activation_timeout_waiting_finger_off; ++ ++ gint bz3_threshold; ++} FpImageDevicePrivate; ++ ++ ++void fpi_image_device_activate (FpImageDevice *image_device); ++void fpi_image_device_deactivate (FpImageDevice *image_device); +diff --git a/libfprint/fp-image-device.c b/libfprint/fp-image-device.c +index 252f414..24d324d 100644 +--- a/libfprint/fp-image-device.c ++++ b/libfprint/fp-image-device.c +@@ -20,14 +20,9 @@ + #define FP_COMPONENT "image_device" + #include "fpi-log.h" + +-#include "fpi-image-device.h" +-#include "fpi-enums.h" +-#include "fpi-print.h" +-#include "fpi-image.h" ++#include "fp-image-device-private.h" + +-#define MIN_ACCEPTABLE_MINUTIAE 10 + #define BOZORTH3_DEFAULT_THRESHOLD 40 +-#define IMG_ENROLL_STAGES 5 + + /** + * SECTION: fp-image-device +@@ -37,30 +32,6 @@ + * 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; +- gboolean cancelling; +- +- gboolean enroll_await_on_pending; +- 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) + + enum { +@@ -87,70 +58,6 @@ static guint signals[LAST_SIGNAL] = { 0 }; + + /* Static helper functions */ + +-static void +-fp_image_device_change_state (FpImageDevice *self, FpImageDeviceState state) +-{ +- FpImageDevicePrivate *priv = fp_image_device_get_instance_private (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. */ +- g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove); +- +- fp_dbg ("Image device internal state change from %d to %d\n", priv->state, state); +- +- priv->state = state; +- g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]); +- g_signal_emit (self, signals[FPI_STATE_CHANGED], 0, priv->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; +- g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]); +- +- /* We might have been waiting for deactivation to finish before +- * starting the next operation. */ +- g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove); +- +- 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; +- } +- if (!priv->cancelling && priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON) +- g_warning ("Deactivating image device while waiting for finger, this should not happen."); +- +- priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE; +- g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]); +- +- fp_dbg ("Deactivating image device\n"); +- cls->deactivate (self); +-} +- + static gboolean + pending_activation_timeout (gpointer user_data) + { +@@ -200,7 +107,7 @@ fp_image_device_close (FpDevice *device) + if (!priv->active) + cls->img_close (self); + else if (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE) +- fp_image_device_deactivate (device); ++ fpi_image_device_deactivate (self); + } + + static void +@@ -220,7 +127,7 @@ fp_image_device_cancel_action (FpDevice *device) + action == FP_DEVICE_ACTION_CAPTURE) + { + priv->cancelling = TRUE; +- fp_image_device_deactivate (FP_DEVICE (self)); ++ fpi_image_device_deactivate (self); + priv->cancelling = FALSE; + + /* XXX: Some nicer way of doing this would be good. */ +@@ -288,7 +195,7 @@ fp_image_device_start_capture_action (FpDevice *device) + + /* And activate the device; we rely on fpi_image_device_activate_complete() + * to be called when done (or immediately). */ +- fp_image_device_activate (self); ++ fpi_image_device_activate (self); + } + + +@@ -391,488 +298,4 @@ fp_image_device_init (FpImageDevice *self) + priv->bz3_threshold = BOZORTH3_DEFAULT_THRESHOLD; + if (cls->bz3_threshold > 0) + priv->bz3_threshold = cls->bz3_threshold; +- +-} +- +-static void +-fp_image_device_enroll_maybe_await_finger_on (FpImageDevice *self) +-{ +- FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); +- +- if (priv->enroll_await_on_pending) +- { +- priv->enroll_await_on_pending = FALSE; +- fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON); +- } +- else +- { +- priv->enroll_await_on_pending = TRUE; +- } +-} +- +-static void +-fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, gpointer user_data) +-{ +- g_autoptr(FpImage) image = FP_IMAGE (source_object); +- g_autoptr(FpPrint) print = NULL; +- GError *error = 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, +- g_steal_pointer (&print), error); +- +- /* Start another scan or deactivate. */ +- if (priv->enroll_stage == IMG_ENROLL_STAGES) +- { +- fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL); +- fp_image_device_deactivate (device); +- } +- else +- { +- fp_image_device_enroll_maybe_await_finger_on (FP_IMAGE_DEVICE (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, g_steal_pointer (&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, g_steal_pointer (&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; +- +- 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. +- * +- * The enroll case is special as AWAIT_FINGER_ON should only happen after +- * minutiae detection to prevent deactivation (without cancellation) +- * from the AWAIT_FINGER_ON state. +- */ +- if (action != FP_DEVICE_ACTION_ENROLL) +- fp_image_device_deactivate (device); +- else +- fp_image_device_enroll_maybe_await_finger_on (self); +- } +-} +- +-/** +- * 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) +- { +- g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove); +- priv->pending_activation_timeout_id = +- g_idle_add ((GSourceFunc) 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; +- g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]); +- +- 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; +- g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FPI_STATE]); +- +- fpi_device_close_complete (FP_DEVICE (self), error); + } +diff --git a/libfprint/fpi-image-device.c b/libfprint/fpi-image-device.c +new file mode 100644 +index 0000000..6e5802e +--- /dev/null ++++ b/libfprint/fpi-image-device.c +@@ -0,0 +1,595 @@ ++/* ++ * FpImageDevice - An image based fingerprint reader device - Private APIs ++ * 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 "fp-image-device-private.h" ++#include "fp-image-device.h" ++ ++/** ++ * SECTION: fpi-image ++ * @title: Internal FpImage ++ * @short_description: Internal image handling routines ++ * ++ * Internal image handling routines. Also see the public FpImage routines. ++ */ ++ ++/* Manually redefine what G_DEFINE_* macro does */ ++static inline gpointer ++fp_image_device_get_instance_private (FpImageDevice *self) ++{ ++ FpImageDeviceClass *img_class = g_type_class_peek_static (FP_TYPE_IMAGE_DEVICE); ++ ++ return G_STRUCT_MEMBER_P (self, ++ g_type_class_get_instance_private_offset (img_class)); ++} ++ ++/* Private shared functions */ ++ ++void ++fpi_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; ++ g_object_notify (G_OBJECT (self), "fp-image-device-state"); ++ ++ /* We might have been waiting for deactivation to finish before ++ * starting the next operation. */ ++ g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove); ++ ++ fp_dbg ("Activating image device\n"); ++ cls->activate (self); ++} ++ ++void ++fpi_image_device_deactivate (FpImageDevice *self) ++{ ++ FpDevice *device = FP_DEVICE (self); ++ 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; ++ } ++ if (!priv->cancelling && priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON) ++ g_warning ("Deactivating image device while waiting for finger, this should not happen."); ++ ++ priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE; ++ g_object_notify (G_OBJECT (self), "fp-image-device-state"); ++ ++ fp_dbg ("Deactivating image device\n"); ++ cls->deactivate (self); ++} ++ ++/* Static helper functions */ ++ ++static void ++fp_image_device_change_state (FpImageDevice *self, FpImageDeviceState state) ++{ ++ FpImageDevicePrivate *priv = fp_image_device_get_instance_private (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. */ ++ g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove); ++ ++ fp_dbg ("Image device internal state change from %d to %d\n", priv->state, state); ++ ++ priv->state = state; ++ g_object_notify (G_OBJECT (self), "fp-image-device-state"); ++ g_signal_emit_by_name (self, "fp-image-device-state-changed", priv->state); ++} ++ ++static void ++fp_image_device_enroll_maybe_await_finger_on (FpImageDevice *self) ++{ ++ FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); ++ ++ if (priv->enroll_await_on_pending) ++ { ++ priv->enroll_await_on_pending = FALSE; ++ fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON); ++ } ++ else ++ { ++ priv->enroll_await_on_pending = TRUE; ++ } ++} ++ ++static void ++fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, gpointer user_data) ++{ ++ g_autoptr(FpImage) image = FP_IMAGE (source_object); ++ g_autoptr(FpPrint) print = NULL; ++ GError *error = NULL; ++ FpImageDevice *self = FP_IMAGE_DEVICE (user_data); ++ FpDevice *device = FP_DEVICE (self); ++ 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)); ++ fpi_image_device_deactivate (self); ++ 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); ++ fpi_image_device_deactivate (self); ++ 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, ++ g_steal_pointer (&print), error); ++ ++ /* Start another scan or deactivate. */ ++ if (priv->enroll_stage == IMG_ENROLL_STAGES) ++ { ++ fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL); ++ fpi_image_device_deactivate (self); ++ } ++ else ++ { ++ fp_image_device_enroll_maybe_await_finger_on (FP_IMAGE_DEVICE (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, g_steal_pointer (&print), error); ++ fpi_image_device_deactivate (self); ++ } ++ 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, g_steal_pointer (&print), error); ++ fpi_image_device_deactivate (self); ++ } ++ 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; ++ ++ 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. ++ * ++ * The enroll case is special as AWAIT_FINGER_ON should only happen after ++ * minutiae detection to prevent deactivation (without cancellation) ++ * from the AWAIT_FINGER_ON state. ++ */ ++ if (action != FP_DEVICE_ACTION_ENROLL) ++ fpi_image_device_deactivate (self); ++ else ++ fp_image_device_enroll_maybe_await_finger_on (self); ++ } ++} ++ ++/** ++ * 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)"); ++ fpi_image_device_deactivate (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!"); ++ ++ fpi_image_device_deactivate (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) ++ { ++ g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove); ++ priv->pending_activation_timeout_id = ++ g_idle_add ((GSourceFunc) fpi_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; ++ g_object_notify (G_OBJECT (self), "fp-image-device-state"); ++ ++ 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; ++ g_object_notify (G_OBJECT (self), "fp-image-device-state"); ++ ++ fpi_device_close_complete (FP_DEVICE (self), error); ++} +diff --git a/libfprint/meson.build b/libfprint/meson.build +index 4a34cbd..9eb4849 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -9,6 +9,7 @@ libfprint_sources = [ + libfprint_private_sources = [ + 'fpi-assembling.c', + 'fpi-device.c', ++ 'fpi-image-device.c', + 'fpi-ssm.c', + 'fpi-usb-transfer.c', + 'fpi-byte-reader.c', +-- +2.24.1 + diff --git a/SOURCES/0107-fp-image-fp-print-Move-private-methods-to-own-code-u.patch b/SOURCES/0107-fp-image-fp-print-Move-private-methods-to-own-code-u.patch new file mode 100644 index 0000000..852cc2c --- /dev/null +++ b/SOURCES/0107-fp-image-fp-print-Move-private-methods-to-own-code-u.patch @@ -0,0 +1,933 @@ +From 0063288d48791b181d794615e5694f9d3c8c1007 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 11 Dec 2019 19:55:47 +0100 +Subject: [PATCH 107/181] fp-image, fp-print: Move private methods to own code + units + +--- + libfprint/fp-image.c | 128 +----------------- + libfprint/fp-print-private.h | 46 +++++++ + libfprint/fp-print.c | 247 +--------------------------------- + libfprint/fpi-image.c | 150 +++++++++++++++++++++ + libfprint/fpi-print.c | 249 +++++++++++++++++++++++++++++++++++ + libfprint/meson.build | 2 + + 6 files changed, 452 insertions(+), 370 deletions(-) + create mode 100644 libfprint/fp-print-private.h + create mode 100644 libfprint/fpi-image.c + create mode 100644 libfprint/fpi-print.c + +diff --git a/libfprint/fp-image.c b/libfprint/fp-image.c +index 16837a8..ac70d68 100644 +--- a/libfprint/fp-image.c ++++ b/libfprint/fp-image.c +@@ -18,15 +18,13 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + ++#define FP_COMPONENT "image" ++ + #include "fpi-image.h" + #include "fpi-log.h" + + #include + +-#if HAVE_PIXMAN +-#include +-#endif +- + /** + * SECTION: fp-image + * @title: FpImage +@@ -36,15 +34,6 @@ + * 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 { +@@ -479,78 +468,6 @@ fp_image_detect_minutiae_finish (FpImage *self, + 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 +@@ -568,44 +485,3 @@ fp_minutia_get_coords (FpMinutia *min, gint *x, gint *y) + 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-print-private.h b/libfprint/fp-print-private.h +new file mode 100644 +index 0000000..f5822b3 +--- /dev/null ++++ b/libfprint/fp-print-private.h +@@ -0,0 +1,46 @@ ++/* ++ * 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 ++ ++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; ++}; +diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c +index f724c77..30fdf1a 100644 +--- a/libfprint/fp-print.c ++++ b/libfprint/fp-print.c +@@ -18,12 +18,10 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#include "fpi-print.h" +-#include "fpi-image.h" +-#include "fpi-log.h" +-#include "fpi-device.h" ++#define FP_COMPONENT "print" + +-#include ++#include "fp-print-private.h" ++#include "fpi-log.h" + + /** + * SECTION: fp-print +@@ -42,28 +40,6 @@ + * #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 { +@@ -540,223 +516,6 @@ fp_print_set_enroll_date (FpPrint *print, + 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) +- { +- g_assert_null (print->prints); +- 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 +diff --git a/libfprint/fpi-image.c b/libfprint/fpi-image.c +new file mode 100644 +index 0000000..8344037 +--- /dev/null ++++ b/libfprint/fpi-image.c +@@ -0,0 +1,150 @@ ++/* ++ * FPrint Image - Private APIs ++ * 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 ++ */ ++ ++#define FP_COMPONENT "image" ++ ++#include "fpi-image.h" ++#include "fpi-log.h" ++ ++#include ++ ++#if HAVE_PIXMAN ++#include ++#endif ++ ++/** ++ * SECTION: fpi-image ++ * @title: Internal FpImage ++ * @short_description: Internal image handling routines ++ * ++ * Internal image handling routines. Also see the public FpImage routines. ++ */ ++ ++/** ++ * 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; ++} ++ ++#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/fpi-print.c b/libfprint/fpi-print.c +new file mode 100644 +index 0000000..a407dd9 +--- /dev/null ++++ b/libfprint/fpi-print.c +@@ -0,0 +1,249 @@ ++/* ++ * FPrint Print handling - Private APIs ++ * 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 ++ */ ++ ++#define FP_COMPONENT "print" ++#include "fpi-log.h" ++ ++#include "fp-print-private.h" ++#include "fpi-device.h" ++ ++/** ++ * SECTION: fpi-print ++ * @title: Internal FpPrint ++ * @short_description: Internal fingerprint handling routines ++ * ++ * Interaction with prints and their storage. See also the public ++ * #FpPrint routines. ++ */ ++ ++/** ++ * 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) ++ { ++ g_assert_null (print->prints); ++ print->prints = g_ptr_array_new_with_free_func (g_free); ++ } ++ g_object_notify (G_OBJECT (print), "fp-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 (G_OBJECT (print), "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 (G_OBJECT (print), "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; ++} +diff --git a/libfprint/meson.build b/libfprint/meson.build +index 9eb4849..8cb8609 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -9,7 +9,9 @@ libfprint_sources = [ + libfprint_private_sources = [ + 'fpi-assembling.c', + 'fpi-device.c', ++ 'fpi-image.c', + 'fpi-image-device.c', ++ 'fpi-print.c', + 'fpi-ssm.c', + 'fpi-usb-transfer.c', + 'fpi-byte-reader.c', +-- +2.24.1 + diff --git a/SOURCES/0108-meson-Use-files-to-track-the-map-file-presence.patch b/SOURCES/0108-meson-Use-files-to-track-the-map-file-presence.patch new file mode 100644 index 0000000..8aa1f07 --- /dev/null +++ b/SOURCES/0108-meson-Use-files-to-track-the-map-file-presence.patch @@ -0,0 +1,36 @@ +From 348c1febc17a4d9c7ef13dd3f7ffc396dcac44f4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 5 Dec 2019 14:28:05 +0100 +Subject: [PATCH 108/181] meson: Use files to track the map file presence + +--- + libfprint/meson.build | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libfprint/meson.build b/libfprint/meson.build +index 8cb8609..d3d0fd6 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -186,9 +186,6 @@ drivers_sources += configure_file(input: 'empty_file', + '\n'.join(drivers_type_list + [] + 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 ] + + deps += declare_dependency(include_directories: [ +@@ -212,6 +209,9 @@ libfprint_private = static_library('fprint-private', + dependencies: deps, + install: false) + ++mapfile = files('libfprint.ver') ++vflag = '-Wl,--version-script,@0@/@1@'.format(meson.source_root(), mapfile[0]) ++ + libfprint = library('fprint', + sources: libfprint_sources + fp_enums + drivers_sources + other_sources, + soversion: soversion, +-- +2.24.1 + diff --git a/SOURCES/0109-meson-Rely-on-libfprint-dependency-to-get-root_inclu.patch b/SOURCES/0109-meson-Rely-on-libfprint-dependency-to-get-root_inclu.patch new file mode 100644 index 0000000..129c390 --- /dev/null +++ b/SOURCES/0109-meson-Rely-on-libfprint-dependency-to-get-root_inclu.patch @@ -0,0 +1,50 @@ +From 733e4256a107440218e2fb79cd6c7eade2565293 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 12 Dec 2019 14:52:23 +0100 +Subject: [PATCH 109/181] meson: Rely on libfprint dependency to get + root_include + +No need to redefine it in all our tools +--- + demo/meson.build | 3 --- + examples/meson.build | 8 ++------ + 2 files changed, 2 insertions(+), 9 deletions(-) + +diff --git a/demo/meson.build b/demo/meson.build +index 279a43c..20f8962 100644 +--- a/demo/meson.build ++++ b/demo/meson.build +@@ -10,9 +10,6 @@ datadir = join_paths(prefix, get_option('datadir')) + executable('gtk-libfprint-test', + [ 'gtk-libfprint-test.c', gtk_test_resources ], + dependencies: [ libfprint_dep, gtk_dep ], +- include_directories: [ +- root_inc, +- ], + c_args: '-DPACKAGE_VERSION="' + meson.project_version() + '"', + install: true, + install_dir: bindir) +diff --git a/examples/meson.build b/examples/meson.build +index eef8c3f..7b313d0 100644 +--- a/examples/meson.build ++++ b/examples/meson.build +@@ -4,14 +4,10 @@ foreach example: examples + executable(example, + [ example + '.c', 'storage.c', 'utilities.c' ], + dependencies: [ libfprint_dep, glib_dep ], +- include_directories: [ +- root_inc, +- ]) ++ ) + endforeach + + executable('cpp-test', + 'cpp-test.cpp', + dependencies: libfprint_dep, +- include_directories: [ +- root_inc, +- ]) ++) +-- +2.24.1 + diff --git a/SOURCES/0110-fprint-Move-drivers-to-private-internal-library.patch b/SOURCES/0110-fprint-Move-drivers-to-private-internal-library.patch new file mode 100644 index 0000000..fd02db2 --- /dev/null +++ b/SOURCES/0110-fprint-Move-drivers-to-private-internal-library.patch @@ -0,0 +1,91 @@ +From f159a65f302abd333c89081b41f10387b85652f8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 11 Dec 2019 20:21:01 +0100 +Subject: [PATCH 110/181] fprint: Move drivers to private internal library + +This allows us to finally remove fpi_get_driver_types from the exported list +of symbols. +--- + libfprint/libfprint.ver | 3 --- + libfprint/meson.build | 25 ++++++++++++++++++++----- + 2 files changed, 20 insertions(+), 8 deletions(-) + +diff --git a/libfprint/libfprint.ver b/libfprint/libfprint.ver +index 7b484f6..d99a456 100644 +--- a/libfprint/libfprint.ver ++++ b/libfprint/libfprint.ver +@@ -1,9 +1,6 @@ + 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 d3d0fd6..06668b3 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -207,19 +207,26 @@ libnbis = static_library('nbis', + libfprint_private = static_library('fprint-private', + sources: libfprint_private_sources + fpi_enums, + dependencies: deps, ++ link_with: libnbis, ++ install: false) ++ ++libfprint_drivers = static_library('fprint-drivers', ++ sources: drivers_sources + [ fp_enums_h ], ++ c_args: drivers_cflags, ++ dependencies: deps, ++ link_with: libfprint_private, + install: false) + + mapfile = files('libfprint.ver') + vflag = '-Wl,--version-script,@0@/@1@'.format(meson.source_root(), mapfile[0]) + + libfprint = library('fprint', +- sources: libfprint_sources + fp_enums + drivers_sources + other_sources, ++ sources: libfprint_sources + fp_enums + other_sources, + soversion: soversion, + version: libversion, +- c_args: drivers_cflags, + link_args : vflag, + link_depends : mapfile, +- link_with: [libnbis, libfprint_private], ++ link_with: [libfprint_private, libfprint_drivers], + dependencies: deps, + install: true) + +@@ -230,9 +237,16 @@ libfprint_dep = declare_dependency(link_with: libfprint, + + install_headers(['fprint.h'] + libfprint_public_headers, subdir: 'libfprint') + ++libfprint_private_dep = declare_dependency( ++ include_directories: include_directories('.'), ++ link_with: libfprint_private, ++ dependencies: [ deps, libfprint_dep ] ++) ++ + udev_rules = executable('fprint-list-udev-rules', + 'fprint-list-udev-rules.c', +- dependencies: [ deps, libfprint_dep ], ++ dependencies: libfprint_private_dep, ++ link_with: libfprint_drivers, + install: false) + + if get_option('udev_rules') +@@ -246,7 +260,8 @@ endif + + supported_devices = executable('fprint-list-supported-devices', + 'fprint-list-supported-devices.c', +- dependencies: [ deps, libfprint_dep ], ++ dependencies: libfprint_private_dep, ++ link_with: libfprint_drivers, + install: false) + + +-- +2.24.1 + diff --git a/SOURCES/0111-meson-Fix-syntax-in-the-auto-generated-fpi-drivers-f.patch b/SOURCES/0111-meson-Fix-syntax-in-the-auto-generated-fpi-drivers-f.patch new file mode 100644 index 0000000..9e05e0c --- /dev/null +++ b/SOURCES/0111-meson-Fix-syntax-in-the-auto-generated-fpi-drivers-f.patch @@ -0,0 +1,41 @@ +From b9fc5906eca7208c40b24050775c8ee76c9f7ffc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Sat, 14 Dec 2019 16:45:11 +0100 +Subject: [PATCH 111/181] meson: Fix syntax in the auto-generated fpi-drivers + file + +Better to be nice everywhere :) +--- + meson.build | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/meson.build b/meson.build +index 1561ebf..b7ba901 100644 +--- a/meson.build ++++ b/meson.build +@@ -152,13 +152,18 @@ drivers_type_list += '#include ' + drivers_type_list += '#include "fpi-context.h"' + drivers_type_list += '' + drivers_type_func += 'void fpi_get_driver_types (GArray *drivers)' +-drivers_type_func += ' {' +-drivers_type_func += ' GType t;' ++drivers_type_func += '{' ++drivers_type_func += ' GType t;' + drivers_type_func += '' ++idx = 0 + foreach driver: drivers + drivers_type_list += 'extern GType (fpi_device_' + driver + '_get_type) (void);' +- drivers_type_func += ' t = fpi_device_' + driver + '_get_type ();' +- drivers_type_func += ' g_array_append_val (drivers, t);\n' ++ drivers_type_func += ' t = fpi_device_' + driver + '_get_type ();' ++ drivers_type_func += ' g_array_append_val (drivers, t);' ++ if idx != drivers.length() - 1 ++ drivers_type_func += '' ++ idx += 1 ++ endif + endforeach + drivers_type_list += '' + drivers_type_func += '}' +-- +2.24.1 + diff --git a/SOURCES/0112-fpi-context-Make-fpi_get_driver_types-to-return-an-a.patch b/SOURCES/0112-fpi-context-Make-fpi_get_driver_types-to-return-an-a.patch new file mode 100644 index 0000000..77f1d53 --- /dev/null +++ b/SOURCES/0112-fpi-context-Make-fpi_get_driver_types-to-return-an-a.patch @@ -0,0 +1,116 @@ +From 9fb75e8f9fa024bfc389bd7b76d7e217e607328f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Sat, 14 Dec 2019 16:56:15 +0100 +Subject: [PATCH 112/181] fpi-context: Make fpi_get_driver_types to return an + array + +No need to create one all the times and the fill it with what we need. +--- + libfprint/fp-context.c | 3 +-- + libfprint/fpi-context.h | 5 +++-- + libfprint/fprint-list-supported-devices.c | 4 +--- + libfprint/fprint-list-udev-rules.c | 4 +--- + meson.build | 11 +++++------ + 5 files changed, 11 insertions(+), 16 deletions(-) + +diff --git a/libfprint/fp-context.c b/libfprint/fp-context.c +index eed7847..3e47f03 100644 +--- a/libfprint/fp-context.c ++++ b/libfprint/fp-context.c +@@ -243,8 +243,7 @@ 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->drivers = fpi_get_driver_types (); + + priv->devices = g_ptr_array_new_with_free_func (g_object_unref); + +diff --git a/libfprint/fpi-context.h b/libfprint/fpi-context.h +index c5a1075..48fecb4 100644 +--- a/libfprint/fpi-context.h ++++ b/libfprint/fpi-context.h +@@ -23,11 +23,12 @@ + + /** + * 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 ++ * Returns: (element-type GType) (transfer container): a #GArray filled with ++ * all driver types + */ +-void fpi_get_driver_types (GArray *drivers); ++GArray *fpi_get_driver_types (void); +diff --git a/libfprint/fprint-list-supported-devices.c b/libfprint/fprint-list-supported-devices.c +index 124e9d9..55da252 100644 +--- a/libfprint/fprint-list-supported-devices.c ++++ b/libfprint/fprint-list-supported-devices.c +@@ -31,11 +31,9 @@ GHashTable *printed = NULL; + static GList * + insert_drivers (GList *list) + { +- g_autoptr(GArray) drivers = g_array_new (FALSE, FALSE, sizeof (GType)); ++ g_autoptr(GArray) drivers = fpi_get_driver_types (); + gint i; + +- fpi_get_driver_types (drivers); +- + /* Find the best driver to handle this USB device. */ + for (i = 0; i < drivers->len; i++) + { +diff --git a/libfprint/fprint-list-udev-rules.c b/libfprint/fprint-list-udev-rules.c +index c0a3337..335c37b 100644 +--- a/libfprint/fprint-list-udev-rules.c ++++ b/libfprint/fprint-list-udev-rules.c +@@ -96,11 +96,9 @@ print_driver (const FpDeviceClass *cls) + int + main (int argc, char **argv) + { +- g_autoptr(GArray) drivers = g_array_new (FALSE, FALSE, sizeof (GType)); ++ g_autoptr(GArray) drivers = fpi_get_driver_types (); + guint i; + +- fpi_get_driver_types (drivers); +- + printed = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + for (i = 0; i < drivers->len; i++) +diff --git a/meson.build b/meson.build +index b7ba901..3f72118 100644 +--- a/meson.build ++++ b/meson.build +@@ -151,21 +151,20 @@ drivers_type_func = [] + drivers_type_list += '#include ' + drivers_type_list += '#include "fpi-context.h"' + drivers_type_list += '' +-drivers_type_func += 'void fpi_get_driver_types (GArray *drivers)' ++drivers_type_func += 'GArray *' ++drivers_type_func += 'fpi_get_driver_types (void)' + drivers_type_func += '{' ++drivers_type_func += ' GArray *drivers = g_array_new (TRUE, FALSE, sizeof (GType));' + drivers_type_func += ' GType t;' + drivers_type_func += '' +-idx = 0 + foreach driver: drivers + drivers_type_list += 'extern GType (fpi_device_' + driver + '_get_type) (void);' + drivers_type_func += ' t = fpi_device_' + driver + '_get_type ();' + drivers_type_func += ' g_array_append_val (drivers, t);' +- if idx != drivers.length() - 1 +- drivers_type_func += '' +- idx += 1 +- endif ++ drivers_type_func += '' + endforeach + drivers_type_list += '' ++drivers_type_func += ' return drivers;' + drivers_type_func += '}' + + root_inc = include_directories('.') +-- +2.24.1 + diff --git a/SOURCES/0113-fp-context-Use-an-env-to-define-a-whitelist-of-drive.patch b/SOURCES/0113-fp-context-Use-an-env-to-define-a-whitelist-of-drive.patch new file mode 100644 index 0000000..0564822 --- /dev/null +++ b/SOURCES/0113-fp-context-Use-an-env-to-define-a-whitelist-of-drive.patch @@ -0,0 +1,111 @@ +From 61e3951e442b6ff8b6ab7ba651e028e61df3aa41 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 13 Dec 2019 20:34:08 +0100 +Subject: [PATCH 113/181] fp-context: Use an env to define a whitelist of + drivers to enable + +This avoids that we pick unwanted drivers when running the tests in a +machine that has some supported device attached. +--- + libfprint/fp-context.c | 45 ++++++++++++++++++++++++++++++++++++++++++ + tests/meson.build | 8 +++++++- + 2 files changed, 52 insertions(+), 1 deletion(-) + +diff --git a/libfprint/fp-context.c b/libfprint/fp-context.c +index 3e47f03..6764241 100644 +--- a/libfprint/fp-context.c ++++ b/libfprint/fp-context.c +@@ -57,6 +57,35 @@ enum { + }; + static guint signals[LAST_SIGNAL] = { 0 }; + ++static const char * ++get_drivers_whitelist_env (void) ++{ ++ return g_getenv ("FP_DRIVERS_WHITELIST"); ++} ++ ++static gboolean ++is_driver_allowed (const gchar *driver) ++{ ++ g_auto(GStrv) whitelisted_drivers = NULL; ++ const char *fp_drivers_whitelist_env; ++ int i; ++ ++ g_return_val_if_fail (driver, TRUE); ++ ++ fp_drivers_whitelist_env = get_drivers_whitelist_env (); ++ ++ if (!fp_drivers_whitelist_env) ++ return TRUE; ++ ++ whitelisted_drivers = g_strsplit (fp_drivers_whitelist_env, ":", -1); ++ ++ for (i = 0; whitelisted_drivers[i]; ++i) ++ if (g_strcmp0 (driver, whitelisted_drivers[i]) == 0) ++ return TRUE; ++ ++ return FALSE; ++} ++ + static void + async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) + { +@@ -242,9 +271,25 @@ fp_context_init (FpContext *self) + { + g_autoptr(GError) error = NULL; + FpContextPrivate *priv = fp_context_get_instance_private (self); ++ guint i; + + priv->drivers = fpi_get_driver_types (); + ++ if (get_drivers_whitelist_env ()) ++ { ++ for (i = 0; i < priv->drivers->len;) ++ { ++ GType driver = g_array_index (priv->drivers, GType, i); ++ g_autoptr(GTypeClass) type_class = g_type_class_ref (driver); ++ FpDeviceClass *cls = FP_DEVICE_CLASS (type_class); ++ ++ if (!is_driver_allowed (cls->id)) ++ g_array_remove_index (priv->drivers, i); ++ else ++ ++i; ++ } ++ } ++ + priv->devices = g_ptr_array_new_with_free_func (g_object_unref); + + priv->cancellable = g_cancellable_new (); +diff --git a/tests/meson.build b/tests/meson.build +index 6e56cb3..082ce86 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -11,6 +11,9 @@ envs.prepend('LD_LIBRARY_PATH', join_paths(meson.build_root(), 'libfprint')) + # random numbers rather than proper ones) + envs.set('FP_DEVICE_EMULATION', '1') + ++# Set a colon-separated list of native drivers we enable in tests ++envs.set('FP_DRIVERS_WHITELIST', 'virtual_image') ++ + envs.set('NO_AT_BRIDGE', '1') + + if get_option('introspection') +@@ -31,10 +34,13 @@ if get_option('introspection') + ] + + foreach driver_test: drivers_tests ++ driver_envs = envs ++ driver_envs.set('FP_DRIVERS_WHITELIST', driver_test) ++ + test(driver_test, + find_program('umockdev-test.py'), + args: join_paths(meson.current_source_dir(), driver_test), +- env: envs, ++ env: driver_envs, + suite: ['drivers'], + timeout: 10, + depends: libfprint_typelib, +-- +2.24.1 + diff --git a/SOURCES/0114-fp-context-tools-Use-auto-ptr-to-handle-GTypeClass-o.patch b/SOURCES/0114-fp-context-tools-Use-auto-ptr-to-handle-GTypeClass-o.patch new file mode 100644 index 0000000..3448370 --- /dev/null +++ b/SOURCES/0114-fp-context-tools-Use-auto-ptr-to-handle-GTypeClass-o.patch @@ -0,0 +1,123 @@ +From 7eb6eba6730f0636f39b5b248b8351bbfc6e6143 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 13 Dec 2019 20:40:41 +0100 +Subject: [PATCH 114/181] fp-context, tools: Use auto-ptr to handle GTypeClass + ownership + +This also fixes a small leak we might have if reffing a type that was not a +virtual one. +--- + libfprint/fp-context.c | 15 +++++---------- + libfprint/fprint-list-supported-devices.c | 10 +++------- + libfprint/fprint-list-udev-rules.c | 10 +++------- + 3 files changed, 11 insertions(+), 24 deletions(-) + +diff --git a/libfprint/fp-context.c b/libfprint/fp-context.c +index 6764241..f64968d 100644 +--- a/libfprint/fp-context.c ++++ b/libfprint/fp-context.c +@@ -131,14 +131,12 @@ usb_device_added_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx) + 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)); ++ g_autoptr(GTypeClass) type_class = g_type_class_ref (driver); ++ FpDeviceClass *cls = FP_DEVICE_CLASS (type_class); + const FpIdEntry *entry; + + if (cls->type != FP_DEVICE_TYPE_USB) +- { +- g_type_class_unref (cls); +- continue; +- } ++ continue; + + for (entry = cls->id_table; entry->pid; entry++) + { +@@ -158,8 +156,6 @@ usb_device_added_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx) + found_driver = driver; + found_entry = entry; + } +- +- g_type_class_unref (cls); + } + + if (found_driver == G_TYPE_NONE) +@@ -355,7 +351,8 @@ fp_context_enumerate (FpContext *context) + 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)); ++ g_autoptr(GTypeClass) type_class = g_type_class_ref (driver); ++ FpDeviceClass *cls = FP_DEVICE_CLASS (type_class); + const FpIdEntry *entry; + + if (cls->type != FP_DEVICE_TYPE_VIRTUAL) +@@ -381,8 +378,6 @@ fp_context_enumerate (FpContext *context) + NULL); + g_debug ("created"); + } +- +- g_type_class_unref (cls); + } + + while (priv->pending_devices) +diff --git a/libfprint/fprint-list-supported-devices.c b/libfprint/fprint-list-supported-devices.c +index 55da252..cb2803f 100644 +--- a/libfprint/fprint-list-supported-devices.c ++++ b/libfprint/fprint-list-supported-devices.c +@@ -38,14 +38,12 @@ insert_drivers (GList *list) + 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)); ++ g_autoptr(GTypeClass) type_class = g_type_class_ref (driver); ++ FpDeviceClass *cls = FP_DEVICE_CLASS (type_class); + const FpIdEntry *entry; + + if (cls->type != FP_DEVICE_TYPE_USB) +- { +- g_type_class_unref (cls); +- continue; +- } ++ continue; + + for (entry = cls->id_table; entry->vid; entry++) + { +@@ -63,8 +61,6 @@ insert_drivers (GList *list) + + list = g_list_prepend (list, g_strdup_printf ("%s | %s\n", key, cls->full_name)); + } +- +- g_type_class_unref (cls); + } + + return list; +diff --git a/libfprint/fprint-list-udev-rules.c b/libfprint/fprint-list-udev-rules.c +index 335c37b..ac50797 100644 +--- a/libfprint/fprint-list-udev-rules.c ++++ b/libfprint/fprint-list-udev-rules.c +@@ -104,17 +104,13 @@ main (int argc, char **argv) + 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)); ++ g_autoptr(GTypeClass) type_class = g_type_class_ref (driver); ++ FpDeviceClass *cls = FP_DEVICE_CLASS (type_class); + + if (cls->type != FP_DEVICE_TYPE_USB) +- { +- g_type_class_unref (cls); +- continue; +- } ++ continue; + + print_driver (cls); +- +- g_type_class_unref (cls); + } + + print_driver (&whitelist); +-- +2.24.1 + diff --git a/SOURCES/0115-tests-Add-basic-unit-tests-for-fp-context.patch b/SOURCES/0115-tests-Add-basic-unit-tests-for-fp-context.patch new file mode 100644 index 0000000..c7e0586 --- /dev/null +++ b/SOURCES/0115-tests-Add-basic-unit-tests-for-fp-context.patch @@ -0,0 +1,298 @@ +From a4f2cc60e4676f8aaef221d14e94cd0250c5d591 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 5 Dec 2019 14:38:41 +0100 +Subject: [PATCH 115/181] tests: Add basic unit tests for fp-context + +Link the tests with the private library using an utils library that will +be useful to share other tests functions +--- + meson.build | 5 +- + tests/meson.build | 26 ++++++++++ + tests/test-fp-context.c | 106 ++++++++++++++++++++++++++++++++++++++++ + tests/test-runner.sh | 3 ++ + tests/test-utils.c | 66 +++++++++++++++++++++++++ + tests/test-utils.h | 23 +++++++++ + 6 files changed, 225 insertions(+), 4 deletions(-) + create mode 100644 tests/test-fp-context.c + create mode 100755 tests/test-runner.sh + create mode 100644 tests/test-utils.c + create mode 100644 tests/test-utils.h + +diff --git a/meson.build b/meson.build +index 3f72118..8ea4a8b 100644 +--- a/meson.build ++++ b/meson.build +@@ -199,10 +199,7 @@ if get_option('gtk-examples') + subdir('demo') + endif + +-# The tests require introspeciton support to run +-if get_option('introspection') +- subdir('tests') +-endif ++subdir('tests') + + pkgconfig = import('pkgconfig') + pkgconfig.generate( +diff --git a/tests/meson.build b/tests/meson.build +index 082ce86..307d9a1 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -48,6 +48,32 @@ if get_option('introspection') + endforeach + endif + ++if 'virtual_image' in drivers ++ test_utils = static_library('fprint-test-utils', ++ sources: ['test-utils.c'], ++ dependencies: libfprint_private_dep, ++ install: false) ++ ++ unit_tests = [ ++ 'fp-context', ++ ] ++ ++ foreach test_name: unit_tests ++ basename = 'test-' + test_name ++ test_exe = executable(basename, ++ sources: basename + '.c', ++ dependencies: libfprint_private_dep, ++ c_args: common_cflags, ++ link_with: test_utils) ++ test(test_name, ++ find_program('test-runner.sh'), ++ suite: ['unit-tests'], ++ args: [test_exe], ++ env: envs, ++ ) ++ endforeach ++endif ++ + gdb = find_program('gdb', required: false) + if gdb.found() + add_test_setup('gdb', +diff --git a/tests/test-fp-context.c b/tests/test-fp-context.c +new file mode 100644 +index 0000000..01516b9 +--- /dev/null ++++ b/tests/test-fp-context.c +@@ -0,0 +1,106 @@ ++/* ++ * FpContext Unit tests ++ * 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 "test-utils.h" ++ ++static void ++test_context_new (void) ++{ ++ g_autoptr(FpContext) context = fp_context_new (); ++ g_assert_true (FP_CONTEXT (context)); ++} ++ ++static void ++test_context_has_no_devices (void) ++{ ++ g_autoptr(FpContext) context = NULL; ++ GPtrArray *devices; ++ ++ context = fp_context_new (); ++ devices = fp_context_get_devices (context); ++ ++ g_assert_nonnull (devices); ++ g_assert_cmpuint (devices->len, ==, 0); ++} ++ ++static void ++test_context_has_virtual_device (void) ++{ ++ g_autoptr(FpContext) context = NULL; ++ FpDevice *virtual_device = NULL; ++ GPtrArray *devices; ++ unsigned int i; ++ ++ fpt_setup_virtual_device_environment (); ++ ++ context = fp_context_new (); ++ devices = fp_context_get_devices (context); ++ ++ g_assert_nonnull (devices); ++ g_assert_cmpuint (devices->len, ==, 1); ++ ++ for (i = 0; i < devices->len; ++i) ++ { ++ FpDevice *device = devices->pdata[i]; ++ ++ if (g_strcmp0 (fp_device_get_driver (device), "virtual_image") == 0) ++ { ++ virtual_device = device; ++ break; ++ } ++ } ++ ++ g_assert_true (FP_IS_DEVICE (virtual_device)); ++ ++ fpt_teardown_virtual_device_environment (); ++} ++ ++static void ++test_context_enumerates_new_devices (void) ++{ ++ g_autoptr(FpContext) context = NULL; ++ GPtrArray *devices; ++ ++ context = fp_context_new (); ++ ++ fpt_setup_virtual_device_environment (); ++ ++ fp_context_enumerate (context); ++ devices = fp_context_get_devices (context); ++ ++ g_assert_nonnull (devices); ++ g_assert_cmpuint (devices->len, ==, 1); ++ ++ fpt_teardown_virtual_device_environment (); ++} ++ ++int ++main (int argc, char *argv[]) ++{ ++ g_test_init (&argc, &argv, NULL); ++ ++ g_test_add_func ("/context/new", test_context_new); ++ g_test_add_func ("/context/no-devices", test_context_has_no_devices); ++ g_test_add_func ("/context/has-virtual-device", test_context_has_virtual_device); ++ g_test_add_func ("/context/enumerates-new-devices", test_context_enumerates_new_devices); ++ ++ return g_test_run (); ++} +diff --git a/tests/test-runner.sh b/tests/test-runner.sh +new file mode 100755 +index 0000000..18b038b +--- /dev/null ++++ b/tests/test-runner.sh +@@ -0,0 +1,3 @@ ++#!/bin/bash ++ ++exec $LIBFPRINT_TEST_WRAPPER $@ +diff --git a/tests/test-utils.c b/tests/test-utils.c +new file mode 100644 +index 0000000..f789058 +--- /dev/null ++++ b/tests/test-utils.c +@@ -0,0 +1,66 @@ ++/* ++ * Unit tests for libfprint ++ * 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 "test-utils.h" ++ ++void ++fpt_teardown_virtual_device_environment (void) ++{ ++ const char *path = g_getenv ("FP_VIRTUAL_IMAGE"); ++ ++ if (path) ++ { ++ g_autofree char *temp_dir = g_path_get_dirname (path); ++ ++ g_unsetenv ("FP_VIRTUAL_IMAGE"); ++ g_unlink (path); ++ g_rmdir (temp_dir); ++ } ++} ++ ++static void ++on_signal_event (int sig) ++{ ++ fpt_teardown_virtual_device_environment (); ++} ++ ++void ++fpt_setup_virtual_device_environment (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autofree char *temp_dir = NULL; ++ g_autofree char *temp_path = NULL; ++ ++ g_assert_null (g_getenv ("FP_VIRTUAL_IMAGE")); ++ ++ temp_dir = g_dir_make_tmp ("libfprint-XXXXXX", &error); ++ g_assert_no_error (error); ++ ++ temp_path = g_build_filename (temp_dir, "virtual-image.socket", NULL); ++ g_setenv ("FP_VIRTUAL_IMAGE", temp_path, TRUE); ++ ++ signal (SIGKILL, on_signal_event); ++ signal (SIGABRT, on_signal_event); ++ signal (SIGSEGV, on_signal_event); ++ signal (SIGTERM, on_signal_event); ++ signal (SIGQUIT, on_signal_event); ++ signal (SIGPIPE, on_signal_event); ++} +diff --git a/tests/test-utils.h b/tests/test-utils.h +new file mode 100644 +index 0000000..369da78 +--- /dev/null ++++ b/tests/test-utils.h +@@ -0,0 +1,23 @@ ++/* ++ * Unit tests for libfprint ++ * 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 ++ ++void fpt_setup_virtual_device_environment (void); ++void fpt_teardown_virtual_device_environment (void); +-- +2.24.1 + diff --git a/SOURCES/0116-tests-Add-fp-device-basic-unit-tests.patch b/SOURCES/0116-tests-Add-fp-device-basic-unit-tests.patch new file mode 100644 index 0000000..752a5b3 --- /dev/null +++ b/SOURCES/0116-tests-Add-fp-device-basic-unit-tests.patch @@ -0,0 +1,373 @@ +From 02b041eb6d6b5bd125993fc68b2cd275052fe8aa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 5 Dec 2019 17:05:21 +0100 +Subject: [PATCH 116/181] tests: Add fp-device basic unit tests + +Use the virtual image device as base for now, while the new setup allows +to create easily fake device drivers without including the driver in +libfprint itself and test all the fpi_device functionalities. +--- + tests/meson.build | 1 + + tests/test-fp-device.c | 238 +++++++++++++++++++++++++++++++++++++++++ + tests/test-utils.c | 61 +++++++++++ + tests/test-utils.h | 14 +++ + 4 files changed, 314 insertions(+) + create mode 100644 tests/test-fp-device.c + +diff --git a/tests/meson.build b/tests/meson.build +index 307d9a1..1ef6e34 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -56,6 +56,7 @@ if 'virtual_image' in drivers + + unit_tests = [ + 'fp-context', ++ 'fp-device', + ] + + foreach test_name: unit_tests +diff --git a/tests/test-fp-device.c b/tests/test-fp-device.c +new file mode 100644 +index 0000000..a279b46 +--- /dev/null ++++ b/tests/test-fp-device.c +@@ -0,0 +1,238 @@ ++/* ++ * FpDevice Unit tests ++ * 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 "test-utils.h" ++ ++static void ++on_device_opened (FpDevice *dev, GAsyncResult *res, FptContext *tctx) ++{ ++ g_autoptr(GError) error = NULL; ++ ++ g_assert_true (fp_device_open_finish (dev, res, &error)); ++ g_assert_no_error (error); ++ g_assert_true (fp_device_is_open (tctx->device)); ++ ++ tctx->user_data = GUINT_TO_POINTER (TRUE); ++} ++ ++static void ++test_device_open_async (void) ++{ ++ g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); ++ ++ fp_device_open (tctx->device, NULL, (GAsyncReadyCallback) on_device_opened, tctx); ++ ++ while (!GPOINTER_TO_UINT (tctx->user_data)) ++ g_main_context_iteration (NULL, TRUE); ++} ++ ++static void ++on_device_closed (FpDevice *dev, GAsyncResult *res, FptContext *tctx) ++{ ++ g_autoptr(GError) error = NULL; ++ ++ g_assert_true (fp_device_close_finish (dev, res, &error)); ++ g_assert_no_error (error); ++ g_assert_false (fp_device_is_open (tctx->device)); ++ ++ tctx->user_data = GUINT_TO_POINTER (TRUE); ++} ++ ++static void ++test_device_close_async (void) ++{ ++ g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); ++ ++ fp_device_open (tctx->device, NULL, (GAsyncReadyCallback) on_device_opened, tctx); ++ while (!tctx->user_data) ++ g_main_context_iteration (NULL, TRUE); ++ ++ tctx->user_data = GUINT_TO_POINTER (FALSE); ++ fp_device_close (tctx->device, NULL, (GAsyncReadyCallback) on_device_closed, tctx); ++ ++ while (!GPOINTER_TO_UINT (tctx->user_data)) ++ g_main_context_iteration (NULL, TRUE); ++} ++ ++static void ++test_device_open_sync (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); ++ ++ fp_device_open_sync (tctx->device, NULL, &error); ++ g_assert_no_error (error); ++ g_assert_true (fp_device_is_open (tctx->device)); ++ ++ fp_device_open_sync (tctx->device, NULL, &error); ++ g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_ALREADY_OPEN); ++} ++ ++static void ++on_open_notify (FpDevice *rdev, GParamSpec *spec, FptContext *tctx) ++{ ++ g_assert_cmpstr (spec->name, ==, "open"); ++ tctx->user_data = GUINT_TO_POINTER (TRUE); ++} ++ ++static void ++test_device_open_sync_notify (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); ++ ++ g_signal_connect (tctx->device, "notify::open", G_CALLBACK (on_open_notify), tctx); ++ fp_device_open_sync (tctx->device, NULL, &error); ++ g_assert_no_error (error); ++ g_assert_true (GPOINTER_TO_INT (tctx->user_data)); ++} ++ ++static void ++test_device_close_sync (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); ++ ++ fp_device_open_sync (tctx->device, NULL, NULL); ++ fp_device_close_sync (tctx->device, NULL, &error); ++ g_assert_no_error (error); ++ g_assert_false (fp_device_is_open (tctx->device)); ++ ++ fp_device_close_sync (tctx->device, NULL, &error); ++ g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_OPEN); ++} ++ ++static void ++on_close_notify (FpDevice *rdev, GParamSpec *spec, FptContext *tctx) ++{ ++ g_assert_cmpstr (spec->name, ==, "open"); ++ tctx->user_data = GUINT_TO_POINTER (TRUE); ++} ++ ++static void ++test_device_close_sync_notify (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); ++ ++ fp_device_open_sync (tctx->device, NULL, NULL); ++ ++ g_signal_connect (tctx->device, "notify::open", G_CALLBACK (on_close_notify), tctx); ++ fp_device_close_sync (tctx->device, NULL, &error); ++ g_assert_no_error (error); ++ g_assert_true (GPOINTER_TO_INT (tctx->user_data)); ++} ++ ++static void ++test_device_get_driver (void) ++{ ++ g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); ++ ++ fp_device_open_sync (tctx->device, NULL, NULL); ++ g_assert_cmpstr (fp_device_get_driver (tctx->device), ==, "virtual_image"); ++} ++ ++static void ++test_device_get_device_id (void) ++{ ++ g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); ++ ++ fp_device_open_sync (tctx->device, NULL, NULL); ++ g_assert_cmpstr (fp_device_get_device_id (tctx->device), ==, "0"); ++} ++ ++static void ++test_device_get_name (void) ++{ ++ g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); ++ ++ fp_device_open_sync (tctx->device, NULL, NULL); ++ g_assert_cmpstr (fp_device_get_name (tctx->device), ==, ++ "Virtual image device for debugging"); ++} ++ ++static void ++test_device_get_scan_type (void) ++{ ++ g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); ++ ++ fp_device_open_sync (tctx->device, NULL, NULL); ++ g_assert_cmpint (fp_device_get_scan_type (tctx->device), ==, FP_SCAN_TYPE_SWIPE); ++} ++ ++static void ++test_device_get_nr_enroll_stages (void) ++{ ++ g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); ++ ++ fp_device_open_sync (tctx->device, NULL, NULL); ++ g_assert_cmpuint (fp_device_get_nr_enroll_stages (tctx->device), ==, 5); ++} ++ ++static void ++test_device_supports_identify (void) ++{ ++ g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); ++ ++ fp_device_open_sync (tctx->device, NULL, NULL); ++ g_assert_true (fp_device_supports_identify (tctx->device)); ++} ++ ++static void ++test_device_supports_capture (void) ++{ ++ g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); ++ ++ fp_device_open_sync (tctx->device, NULL, NULL); ++ g_assert_true (fp_device_supports_capture (tctx->device)); ++} ++ ++static void ++test_device_has_storage (void) ++{ ++ g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); ++ ++ fp_device_open_sync (tctx->device, NULL, NULL); ++ g_assert_false (fp_device_has_storage (tctx->device)); ++} ++ ++int ++main (int argc, char *argv[]) ++{ ++ g_test_init (&argc, &argv, NULL); ++ ++ g_test_add_func ("/device/async/open", test_device_open_async); ++ g_test_add_func ("/device/async/close", test_device_close_async); ++ g_test_add_func ("/device/sync/open", test_device_open_sync); ++ g_test_add_func ("/device/sync/open/notify", test_device_open_sync_notify); ++ g_test_add_func ("/device/sync/close", test_device_close_sync); ++ g_test_add_func ("/device/sync/close/notify", test_device_close_sync_notify); ++ g_test_add_func ("/device/sync/get_driver", test_device_get_driver); ++ g_test_add_func ("/device/sync/get_device_id", test_device_get_device_id); ++ g_test_add_func ("/device/sync/get_name", test_device_get_name); ++ g_test_add_func ("/device/sync/get_scan_type", test_device_get_scan_type); ++ g_test_add_func ("/device/sync/get_nr_enroll_stages", test_device_get_nr_enroll_stages); ++ g_test_add_func ("/device/sync/supports_identify", test_device_supports_identify); ++ g_test_add_func ("/device/sync/supports_capture", test_device_supports_capture); ++ g_test_add_func ("/device/sync/has_storage", test_device_has_storage); ++ ++ return g_test_run (); ++} +diff --git a/tests/test-utils.c b/tests/test-utils.c +index f789058..834a90e 100644 +--- a/tests/test-utils.c ++++ b/tests/test-utils.c +@@ -17,6 +17,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + ++#include + #include + + #include "test-utils.h" +@@ -64,3 +65,63 @@ fpt_setup_virtual_device_environment (void) + signal (SIGQUIT, on_signal_event); + signal (SIGPIPE, on_signal_event); + } ++ ++FptContext * ++fpt_context_new (void) ++{ ++ FptContext *tctx; ++ ++ tctx = g_new0 (FptContext, 1); ++ tctx->fp_context = fp_context_new (); ++ ++ return tctx; ++} ++ ++FptContext * ++fpt_context_new_with_virtual_imgdev (void) ++{ ++ FptContext *tctx; ++ GPtrArray *devices; ++ unsigned int i; ++ ++ fpt_setup_virtual_device_environment (); ++ ++ tctx = fpt_context_new (); ++ devices = fp_context_get_devices (tctx->fp_context); ++ ++ g_assert_nonnull (devices); ++ g_assert_cmpuint (devices->len, ==, 1); ++ ++ for (i = 0; i < devices->len; ++i) ++ { ++ FpDevice *device = devices->pdata[i]; ++ ++ if (g_strcmp0 (fp_device_get_driver (device), "virtual_image") == 0) ++ { ++ tctx->device = device; ++ break; ++ } ++ } ++ ++ g_assert_true (FP_IS_DEVICE (tctx->device)); ++ g_object_add_weak_pointer (G_OBJECT (tctx->device), (gpointer) & tctx->device); ++ ++ return tctx; ++} ++ ++void ++fpt_context_free (FptContext *tctx) ++{ ++ if (tctx->device && fp_device_is_open (tctx->device)) ++ { ++ g_autoptr(GError) error = NULL; ++ ++ fp_device_close_sync (tctx->device, NULL, &error); ++ g_assert_no_error (error); ++ } ++ ++ g_clear_object (&tctx->fp_context); ++ g_free (tctx); ++ ++ fpt_teardown_virtual_device_environment (); ++} +diff --git a/tests/test-utils.h b/tests/test-utils.h +index 369da78..4bc1e69 100644 +--- a/tests/test-utils.h ++++ b/tests/test-utils.h +@@ -21,3 +21,17 @@ + + void fpt_setup_virtual_device_environment (void); + void fpt_teardown_virtual_device_environment (void); ++ ++typedef struct _FptContext ++{ ++ FpContext *fp_context; ++ FpDevice *device; ++ gpointer user_data; ++} FptContext; ++ ++FptContext * fpt_context_new (void); ++FptContext * fpt_context_new_with_virtual_imgdev (void); ++ ++void fpt_context_free (FptContext *test_context); ++ ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (FptContext, fpt_context_free) +-- +2.24.1 + diff --git a/SOURCES/0117-fp-device-Call-identify-device-class-method-on-ident.patch b/SOURCES/0117-fp-device-Call-identify-device-class-method-on-ident.patch new file mode 100644 index 0000000..e68905f --- /dev/null +++ b/SOURCES/0117-fp-device-Call-identify-device-class-method-on-ident.patch @@ -0,0 +1,30 @@ +From 63d7df4e804a7642b6fd407e37e2187d1e3e197d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 6 Dec 2019 17:18:26 +0100 +Subject: [PATCH 117/181] fp-device: Call identify device class method on + identification + +Identify on device was broken because we were calling verify device method +on devices instead of the right one. + +Thank you unit tests! :) +--- + libfprint/fp-device.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c +index c49e5a9..3ac3a1c 100644 +--- a/libfprint/fp-device.c ++++ b/libfprint/fp-device.c +@@ -923,7 +923,7 @@ fp_device_identify (FpDevice *device, + g_ptr_array_ref (prints), + (GDestroyNotify) g_ptr_array_unref); + +- FP_DEVICE_GET_CLASS (device)->verify (device); ++ FP_DEVICE_GET_CLASS (device)->identify (device); + } + + /** +-- +2.24.1 + diff --git a/SOURCES/0118-fpi-device-Clarify-ownership-of-parameters-for-progr.patch b/SOURCES/0118-fpi-device-Clarify-ownership-of-parameters-for-progr.patch new file mode 100644 index 0000000..7480a83 --- /dev/null +++ b/SOURCES/0118-fpi-device-Clarify-ownership-of-parameters-for-progr.patch @@ -0,0 +1,28 @@ +From 38d784fd8000faaf9b0087ca3f033e8adaaaace5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 11 Dec 2019 18:53:36 +0100 +Subject: [PATCH 118/181] fpi-device: Clarify ownership of parameters for + progress call + +--- + libfprint/fpi-device.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c +index 3eee062..5fc6b76 100644 +--- a/libfprint/fpi-device.c ++++ b/libfprint/fpi-device.c +@@ -1134,8 +1134,8 @@ fpi_device_list_complete (FpDevice *device, + * 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 ++ * @print: (transfer full): The #FpPrint for the newly completed stage or %NULL on failure ++ * @error: (transfer full): 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(). +-- +2.24.1 + diff --git a/SOURCES/0119-test-device-fake-Add-fake-test-driver-to-verify-fpi-.patch b/SOURCES/0119-test-device-fake-Add-fake-test-driver-to-verify-fpi-.patch new file mode 100644 index 0000000..7b670f5 --- /dev/null +++ b/SOURCES/0119-test-device-fake-Add-fake-test-driver-to-verify-fpi-.patch @@ -0,0 +1,293 @@ +From abbd2950fdc3c3eee479a5bbecbe009df7cf87ce Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 6 Dec 2019 17:20:52 +0100 +Subject: [PATCH 119/181] test-device-fake: Add fake test driver to verify fpi + functions + +--- + tests/meson.build | 5 +- + tests/test-device-fake.c | 205 +++++++++++++++++++++++++++++++++++++++ + tests/test-device-fake.h | 43 ++++++++ + 3 files changed, 252 insertions(+), 1 deletion(-) + create mode 100644 tests/test-device-fake.c + create mode 100644 tests/test-device-fake.h + +diff --git a/tests/meson.build b/tests/meson.build +index 1ef6e34..e37991d 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -50,7 +50,10 @@ endif + + if 'virtual_image' in drivers + test_utils = static_library('fprint-test-utils', +- sources: ['test-utils.c'], ++ sources: [ ++ 'test-utils.c', ++ 'test-device-fake.c', ++ ], + dependencies: libfprint_private_dep, + install: false) + +diff --git a/tests/test-device-fake.c b/tests/test-device-fake.c +new file mode 100644 +index 0000000..e3b6f38 +--- /dev/null ++++ b/tests/test-device-fake.c +@@ -0,0 +1,205 @@ ++/* ++ * Virtual driver for device debugging ++ * ++ * 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 ++ */ ++ ++#define FP_COMPONENT "fake_test_dev" ++ ++#include "test-device-fake.h" ++ ++G_DEFINE_TYPE (FpiDeviceFake, fpi_device_fake, FP_TYPE_DEVICE) ++ ++static const FpIdEntry driver_ids[] = { ++ { .virtual_envvar = "FP_VIRTUAL_FAKE_DEVICE" }, ++ { .virtual_envvar = NULL } ++}; ++ ++static void ++fpi_device_fake_probe (FpDevice *device) ++{ ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_PROBE); ++ ++ fake_dev->last_called_function = fpi_device_fake_probe; ++ fpi_device_probe_complete (device, dev_class->id, dev_class->full_name, ++ fake_dev->ret_error); ++} ++ ++static void ++fpi_device_fake_open (FpDevice *device) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_OPEN); ++ ++ fake_dev->last_called_function = fpi_device_fake_open; ++ fpi_device_open_complete (device, fake_dev->ret_error); ++} ++ ++static void ++fpi_device_fake_close (FpDevice *device) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_CLOSE); ++ ++ fake_dev->last_called_function = fpi_device_fake_close; ++ fpi_device_close_complete (device, fake_dev->ret_error); ++} ++ ++static void ++fpi_device_fake_enroll (FpDevice *device) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ FpPrint *print = fake_dev->ret_print; ++ ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_ENROLL); ++ fpi_device_get_enroll_data (device, (FpPrint **) &fake_dev->action_data); ++ ++ if (!print && !fake_dev->ret_error) ++ fpi_device_get_enroll_data (device, &print); ++ ++ fake_dev->last_called_function = fpi_device_fake_enroll; ++ fpi_device_enroll_complete (device, print, fake_dev->ret_error); ++} ++ ++static void ++fpi_device_fake_verify (FpDevice *device) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ FpPrint *print = fake_dev->ret_print; ++ ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_VERIFY); ++ fpi_device_get_verify_data (device, (FpPrint **) &fake_dev->action_data); ++ ++ if (!print && !fake_dev->ret_error) ++ fpi_device_get_verify_data (device, &print); ++ ++ fake_dev->last_called_function = fpi_device_fake_verify; ++ fpi_device_verify_complete (device, fake_dev->ret_result, print, ++ fake_dev->ret_error); ++} ++ ++static void ++fpi_device_fake_identify (FpDevice *device) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ FpPrint *match = fake_dev->ret_match; ++ ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_IDENTIFY); ++ fpi_device_get_identify_data (device, (GPtrArray **) &fake_dev->action_data); ++ ++ if (!match && !fake_dev->ret_error) ++ { ++ GPtrArray *prints; ++ unsigned int i; ++ ++ fpi_device_get_identify_data (device, &prints); ++ ++ for (i = 0; prints && i < prints->len; ++i) ++ { ++ FpPrint *print = g_ptr_array_index (prints, i); ++ ++ if (g_strcmp0 (fp_print_get_description (print), "fake-verified") == 0) ++ { ++ match = print; ++ break; ++ } ++ } ++ } ++ ++ fake_dev->last_called_function = fpi_device_fake_identify; ++ fpi_device_identify_complete (device, match, fake_dev->ret_print, ++ fake_dev->ret_error); ++} ++ ++static void ++fpi_device_fake_capture (FpDevice *device) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_CAPTURE); ++ fpi_device_get_capture_data (device, (gboolean *) &fake_dev->action_data); ++ ++ fake_dev->last_called_function = fpi_device_fake_capture; ++ fpi_device_capture_complete (device, fake_dev->ret_image, fake_dev->ret_error); ++} ++ ++static void ++fpi_device_fake_list (FpDevice *device) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_LIST); ++ ++ fake_dev->last_called_function = fpi_device_fake_list; ++ fpi_device_list_complete (device, fake_dev->ret_list, fake_dev->ret_error); ++} ++ ++static void ++fpi_device_fake_delete (FpDevice *device) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_DELETE); ++ fpi_device_get_delete_data (device, (gpointer) & fake_dev->action_data); ++ ++ fake_dev->last_called_function = fpi_device_fake_delete; ++ fpi_device_delete_complete (device, fake_dev->ret_error); ++} ++ ++static void ++fpi_device_fake_cancel (FpDevice *device) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ g_assert_cmpuint (fpi_device_get_current_action (device), !=, FP_DEVICE_ACTION_NONE); ++ ++ fake_dev->last_called_function = fpi_device_fake_cancel; ++} ++ ++static void ++fpi_device_fake_init (FpiDeviceFake *self) ++{ ++} ++ ++static void ++fpi_device_fake_class_init (FpiDeviceFakeClass *klass) ++{ ++ FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); ++ ++ dev_class->id = FP_COMPONENT; ++ dev_class->full_name = "Virtual device for debugging"; ++ dev_class->type = FP_DEVICE_TYPE_VIRTUAL; ++ dev_class->id_table = driver_ids; ++ dev_class->nr_enroll_stages = 5; ++ dev_class->scan_type = FP_SCAN_TYPE_PRESS; ++ ++ dev_class->probe = fpi_device_fake_probe; ++ dev_class->open = fpi_device_fake_open; ++ dev_class->close = fpi_device_fake_close; ++ dev_class->enroll = fpi_device_fake_enroll; ++ dev_class->verify = fpi_device_fake_verify; ++ dev_class->identify = fpi_device_fake_identify; ++ dev_class->capture = fpi_device_fake_capture; ++ dev_class->list = fpi_device_fake_list; ++ dev_class->delete = fpi_device_fake_delete; ++ dev_class->cancel = fpi_device_fake_cancel; ++} +diff --git a/tests/test-device-fake.h b/tests/test-device-fake.h +new file mode 100644 +index 0000000..e8a0919 +--- /dev/null ++++ b/tests/test-device-fake.h +@@ -0,0 +1,43 @@ ++/* ++ * Virtual driver for device debugging ++ * ++ * 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 ++ */ ++ ++#pragma once ++ ++#include "fpi-device.h" ++ ++#define FPI_TYPE_DEVICE_FAKE (fpi_device_fake_get_type ()) ++G_DECLARE_FINAL_TYPE (FpiDeviceFake, fpi_device_fake, FPI, DEVICE_FAKE, FpDevice) ++ ++struct _FpiDeviceFake ++{ ++ FpDevice parent; ++ ++ gpointer last_called_function; ++ ++ GError *ret_error; ++ FpPrint *ret_print; ++ FpPrint *ret_match; ++ FpiMatchResult ret_result; ++ FpImage *ret_image; ++ GPtrArray *ret_list; ++ ++ gpointer action_data; ++ gpointer user_data; ++}; +-- +2.24.1 + diff --git a/SOURCES/0120-tests-meson-Support-unit-tests-non-depending-on-virt.patch b/SOURCES/0120-tests-meson-Support-unit-tests-non-depending-on-virt.patch new file mode 100644 index 0000000..d291b3b --- /dev/null +++ b/SOURCES/0120-tests-meson-Support-unit-tests-non-depending-on-virt.patch @@ -0,0 +1,85 @@ +From 67441cfe751c0b59febf1ed2b0895cf1d5561ff1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 11 Dec 2019 21:09:02 +0100 +Subject: [PATCH 120/181] tests/meson: Support unit-tests non depending on + virtual driver + +Since tests depending on the fake device don't depend on virtual-image +driver anymore, let's change the way we organize the things, by putting +everything in the test lib, but enabling unit-tests depending on what they +depend on. +--- + tests/meson.build | 51 +++++++++++++++++++++++++---------------------- + 1 file changed, 27 insertions(+), 24 deletions(-) + +diff --git a/tests/meson.build b/tests/meson.build +index e37991d..7482a66 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -48,36 +48,39 @@ if get_option('introspection') + endforeach + endif + +-if 'virtual_image' in drivers +- test_utils = static_library('fprint-test-utils', +- sources: [ +- 'test-utils.c', +- 'test-device-fake.c', +- ], +- dependencies: libfprint_private_dep, +- install: false) ++test_utils = static_library('fprint-test-utils', ++ sources: [ ++ 'test-utils.c', ++ 'test-device-fake.c', ++ ], ++ dependencies: libfprint_private_dep, ++ install: false) ++ ++unit_tests = [] + +- unit_tests = [ ++if 'virtual_image' in drivers ++ unit_tests += [ + 'fp-context', + 'fp-device', + ] +- +- foreach test_name: unit_tests +- basename = 'test-' + test_name +- test_exe = executable(basename, +- sources: basename + '.c', +- dependencies: libfprint_private_dep, +- c_args: common_cflags, +- link_with: test_utils) +- test(test_name, +- find_program('test-runner.sh'), +- suite: ['unit-tests'], +- args: [test_exe], +- env: envs, +- ) +- endforeach + endif + ++foreach test_name: unit_tests ++ basename = 'test-' + test_name ++ test_exe = executable(basename, ++ sources: basename + '.c', ++ dependencies: libfprint_private_dep, ++ c_args: common_cflags, ++ link_with: test_utils, ++ ) ++ test(test_name, ++ find_program('test-runner.sh'), ++ suite: ['unit-tests'], ++ args: [test_exe], ++ env: envs, ++ ) ++endforeach ++ + gdb = find_program('gdb', required: false) + if gdb.found() + add_test_setup('gdb', +-- +2.24.1 + diff --git a/SOURCES/0121-tests-Add-fpi-device-tests.patch b/SOURCES/0121-tests-Add-fpi-device-tests.patch new file mode 100644 index 0000000..b965aa9 --- /dev/null +++ b/SOURCES/0121-tests-Add-fpi-device-tests.patch @@ -0,0 +1,1448 @@ +From 3acb616fdb4309ed0144c37a5b26960f6026f9f1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 6 Dec 2019 17:21:38 +0100 +Subject: [PATCH 121/181] tests: Add fpi device tests + +Verify drivers operations simulating a fake driver to check that the lib +interaction is correct. +--- + tests/meson.build | 4 +- + tests/test-fpi-device.c | 1411 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 1414 insertions(+), 1 deletion(-) + create mode 100644 tests/test-fpi-device.c + +diff --git a/tests/meson.build b/tests/meson.build +index 7482a66..d082908 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -56,7 +56,9 @@ test_utils = static_library('fprint-test-utils', + dependencies: libfprint_private_dep, + install: false) + +-unit_tests = [] ++unit_tests = [ ++ 'fpi-device', ++] + + if 'virtual_image' in drivers + unit_tests += [ +diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c +new file mode 100644 +index 0000000..165fc7f +--- /dev/null ++++ b/tests/test-fpi-device.c +@@ -0,0 +1,1411 @@ ++/* ++ * 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 ++ ++#define FP_COMPONENT "device" ++ ++#include "fpi-device.h" ++#include "fpi-log.h" ++#include "test-device-fake.h" ++ ++/* Utility functions */ ++ ++typedef FpDevice FpAutoCloseDevice; ++ ++static FpAutoCloseDevice * ++auto_close_fake_device_new (void) ++{ ++ FpAutoCloseDevice *device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ ++ g_assert_true (fp_device_open_sync (device, NULL, NULL)); ++ ++ return device; ++} ++ ++static void ++auto_close_fake_device_free (FpAutoCloseDevice *device) ++{ ++ if (fp_device_is_open (device)) ++ g_assert_true (fp_device_close_sync (device, NULL, NULL)); ++ ++ g_object_unref (device); ++} ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpAutoCloseDevice, auto_close_fake_device_free) ++ ++typedef FpDeviceClass FpAutoResetClass; ++static FpAutoResetClass default_fake_dev_class = {0}; ++ ++static FpAutoResetClass * ++auto_reset_device_class (void) ++{ ++ g_autoptr(GTypeClass) type_class = NULL; ++ FpDeviceClass *dev_class = g_type_class_peek_static (FPI_TYPE_DEVICE_FAKE); ++ ++ if (!dev_class) ++ { ++ type_class = g_type_class_ref (FPI_TYPE_DEVICE_FAKE); ++ dev_class = (FpDeviceClass *) type_class; ++ g_assert_nonnull (dev_class); ++ } ++ ++ default_fake_dev_class = *dev_class; ++ ++ return dev_class; ++} ++ ++static void ++auto_reset_device_class_cleanup (FpAutoResetClass *dev_class) ++{ ++ *dev_class = default_fake_dev_class; ++ ++ g_assert_cmpint (memcmp (dev_class, &default_fake_dev_class, ++ sizeof (FpAutoResetClass)), ==, 0); ++} ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpAutoResetClass, auto_reset_device_class_cleanup) ++ ++static void ++on_device_notify (FpDevice *device, GParamSpec *spec, gpointer user_data) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ fake_dev->last_called_function = on_device_notify; ++ fake_dev->user_data = g_param_spec_ref (spec); ++} ++ ++static void ++test_driver_action_error_vfunc (FpDevice *device) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ fake_dev->last_called_function = test_driver_action_error_vfunc; ++ ++ fpi_device_action_error (device, fake_dev->user_data); ++} ++ ++/* Tests */ ++ ++static void ++test_driver_get_driver (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpDevice) device = NULL; ++ ++ dev_class->id = "test-fpi-device-driver"; ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ ++ g_assert_cmpstr (fp_device_get_driver (device), ==, "test-fpi-device-driver"); ++} ++ ++static void ++test_driver_get_device_id (void) ++{ ++ g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ ++ g_assert_cmpstr (fp_device_get_device_id (device), ==, "0"); ++} ++ ++static void ++test_driver_get_name (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpDevice) device = NULL; ++ ++ dev_class->full_name = "Test Device Full Name!"; ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ ++ g_assert_cmpstr (fp_device_get_name (device), ==, "Test Device Full Name!"); ++} ++ ++static void ++test_driver_is_open (void) ++{ ++ g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ ++ g_assert_false (fp_device_is_open (device)); ++ fp_device_open_sync (device, NULL, NULL); ++ g_assert_true (fp_device_is_open (device)); ++ fp_device_close_sync (FP_DEVICE (device), NULL, NULL); ++ g_assert_false (fp_device_is_open (device)); ++} ++ ++static void ++test_driver_get_scan_type_press (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpDevice) device = NULL; ++ ++ dev_class->scan_type = FP_SCAN_TYPE_PRESS; ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ g_assert_cmpuint (fp_device_get_scan_type (device), ==, FP_SCAN_TYPE_PRESS); ++} ++ ++static void ++test_driver_get_scan_type_swipe (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpDevice) device = NULL; ++ ++ dev_class->scan_type = FP_SCAN_TYPE_SWIPE; ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ g_assert_cmpuint (fp_device_get_scan_type (device), ==, FP_SCAN_TYPE_SWIPE); ++} ++ ++static void ++test_driver_set_scan_type_press (void) ++{ ++ g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ g_autoptr(GParamSpec) pspec = NULL; ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ g_signal_connect (device, "notify::scan-type", G_CALLBACK (on_device_notify), NULL); ++ ++ fpi_device_set_scan_type (device, FP_SCAN_TYPE_PRESS); ++ g_assert_cmpuint (fp_device_get_scan_type (device), ==, FP_SCAN_TYPE_PRESS); ++ g_assert (fake_dev->last_called_function == on_device_notify); ++ ++ pspec = g_steal_pointer (&fake_dev->user_data); ++ g_assert_cmpstr (pspec->name, ==, "scan-type"); ++} ++ ++static void ++test_driver_set_scan_type_swipe (void) ++{ ++ g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ g_autoptr(GParamSpec) pspec = NULL; ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ g_signal_connect (device, "notify::scan-type", G_CALLBACK (on_device_notify), NULL); ++ ++ fpi_device_set_scan_type (device, FP_SCAN_TYPE_SWIPE); ++ g_assert_cmpuint (fp_device_get_scan_type (device), ==, FP_SCAN_TYPE_SWIPE); ++ g_assert (fake_dev->last_called_function == on_device_notify); ++ ++ pspec = g_steal_pointer (&fake_dev->user_data); ++ g_assert_cmpstr (pspec->name, ==, "scan-type"); ++} ++ ++static void ++test_driver_get_nr_enroll_stages (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpDevice) device = NULL; ++ int expected_stages = g_random_int_range (G_MININT32, G_MAXINT32); ++ ++ dev_class->nr_enroll_stages = expected_stages; ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ ++ g_assert_cmpint (fp_device_get_nr_enroll_stages (device), ==, expected_stages); ++} ++ ++static void ++test_driver_set_nr_enroll_stages (void) ++{ ++ g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ g_autoptr(GParamSpec) pspec = NULL; ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ int expected_stages = g_random_int_range (G_MININT32, G_MAXINT32); ++ ++ g_signal_connect (device, "notify::nr-enroll-stages", G_CALLBACK (on_device_notify), NULL); ++ fpi_device_set_nr_enroll_stages (device, expected_stages); ++ ++ g_assert_cmpint (fp_device_get_nr_enroll_stages (device), ==, expected_stages); ++ g_assert (fake_dev->last_called_function == on_device_notify); ++ ++ pspec = g_steal_pointer (&fake_dev->user_data); ++ g_assert_cmpstr (pspec->name, ==, "nr-enroll-stages"); ++} ++ ++static void ++test_driver_get_usb_device (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpDevice) device = NULL; ++ ++ dev_class->type = FP_DEVICE_TYPE_USB; ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, "fp-usb-device", NULL); ++ g_assert_null (fpi_device_get_usb_device (device)); ++ ++ g_clear_object (&device); ++ dev_class->type = FP_DEVICE_TYPE_VIRTUAL; ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*assertion*type*FP_DEVICE_TYPE_USB*failed*"); ++ g_assert_null (fpi_device_get_usb_device (device)); ++ g_test_assert_expected_messages (); ++} ++ ++static void ++test_driver_get_virtual_env (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpDevice) device = NULL; ++ ++ dev_class->type = FP_DEVICE_TYPE_VIRTUAL; ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, "fp-environ", "TEST_VIRTUAL_ENV_GETTER", NULL); ++ g_assert_cmpstr (fpi_device_get_virtual_env (device), ==, "TEST_VIRTUAL_ENV_GETTER"); ++ ++ g_clear_object (&device); ++ dev_class->type = FP_DEVICE_TYPE_USB; ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*assertion*type*FP_DEVICE_TYPE_VIRTUAL*failed*"); ++ g_assert_null (fpi_device_get_virtual_env (device)); ++ g_test_assert_expected_messages (); ++} ++ ++static void ++test_driver_get_driver_data (void) ++{ ++ g_autoptr(FpDevice) device = NULL; ++ guint64 driver_data; ++ ++ driver_data = g_random_int (); ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, "fp-driver-data", driver_data, NULL); ++ g_assert_cmpuint (fpi_device_get_driver_data (device), ==, driver_data); ++} ++ ++static void ++on_driver_probe_async (GObject *initable, GAsyncResult *res, gpointer user_data) ++{ ++ g_autoptr(GError) error = NULL; ++ FpDevice **out_device = user_data; ++ FpDevice *device; ++ FpDeviceClass *dev_class; ++ FpiDeviceFake *fake_dev; ++ ++ device = FP_DEVICE (g_async_initable_new_finish (G_ASYNC_INITABLE (initable), res, &error)); ++ dev_class = FP_DEVICE_GET_CLASS (device); ++ fake_dev = FPI_DEVICE_FAKE (device); ++ ++ g_assert (fake_dev->last_called_function == dev_class->probe); ++ g_assert_no_error (error); ++ ++ g_assert_false (fp_device_is_open (device)); ++ ++ *out_device = device; ++} ++ ++static void ++test_driver_probe (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpDevice) device = NULL; ++ ++ dev_class->id = "Probed device ID"; ++ dev_class->full_name = "Probed device name"; ++ g_async_initable_new_async (FPI_TYPE_DEVICE_FAKE, G_PRIORITY_DEFAULT, NULL, ++ on_driver_probe_async, &device, NULL); ++ ++ while (!FP_IS_DEVICE (device)) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_false (fp_device_is_open (device)); ++ g_assert_cmpstr (fp_device_get_device_id (device), ==, "Probed device ID"); ++ g_assert_cmpstr (fp_device_get_name (device), ==, "Probed device name"); ++} ++ ++static void ++test_driver_open (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ g_assert (fake_dev->last_called_function != dev_class->probe); ++ ++ fp_device_open_sync (device, NULL, &error); ++ g_assert (fake_dev->last_called_function == dev_class->open); ++ g_assert_no_error (error); ++ g_assert_true (fp_device_is_open (device)); ++ ++ fp_device_close_sync (FP_DEVICE (device), NULL, &error); ++ g_assert_no_error (error); ++} ++ ++static void ++test_driver_open_error (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); ++ fp_device_open_sync (device, NULL, &error); ++ g_assert (fake_dev->last_called_function == dev_class->open); ++ g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); ++ g_assert_false (fp_device_is_open (device)); ++ g_assert (error == g_steal_pointer (&fake_dev->ret_error)); ++} ++ ++static void ++test_driver_close (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ fp_device_close_sync (device, NULL, &error); ++ g_assert (fake_dev->last_called_function == dev_class->close); ++ ++ g_assert_no_error (error); ++ g_assert_false (fp_device_is_open (device)); ++} ++ ++static void ++test_driver_close_error (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); ++ fp_device_close_sync (device, NULL, &error); ++ ++ g_assert (fake_dev->last_called_function == dev_class->close); ++ g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); ++ g_assert (error == g_steal_pointer (&fake_dev->ret_error)); ++} ++ ++static void ++test_driver_enroll (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ FpPrint *template_print = fp_print_new (device); ++ FpPrint *out_print = NULL; ++ ++ out_print = ++ fp_device_enroll_sync (device, template_print, NULL, NULL, NULL, &error); ++ ++ g_assert (fake_dev->last_called_function == dev_class->enroll); ++ g_assert (fake_dev->action_data == template_print); ++ ++ g_assert_no_error (error); ++ g_assert (out_print == template_print); ++} ++ ++static void ++test_driver_enroll_error (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ FpPrint *template_print = fp_print_new (device); ++ FpPrint *out_print = NULL; ++ ++ fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); ++ out_print = ++ fp_device_enroll_sync (device, template_print, NULL, NULL, NULL, &error); ++ ++ g_assert (fake_dev->last_called_function == dev_class->enroll); ++ g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); ++ g_assert (error == g_steal_pointer (&fake_dev->ret_error)); ++ g_assert_null (out_print); ++} ++ ++typedef struct ++{ ++ gint completed_stages; ++ FpPrint *print; ++ GError *error; ++} ExpectedEnrollData; ++ ++static void ++test_driver_enroll_progress_callback (FpDevice *device, ++ gint completed_stages, ++ FpPrint *print, ++ gpointer user_data, ++ GError *error) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ExpectedEnrollData *expected_data = user_data; ++ ++ g_assert_cmpint (expected_data->completed_stages, ==, completed_stages); ++ g_assert (expected_data->print == print); ++ g_assert_true (print == NULL || FP_IS_PRINT (print)); ++ g_assert (expected_data->error == error); ++ ++ fake_dev->last_called_function = test_driver_enroll_progress_callback; ++} ++ ++static void ++test_driver_enroll_progress_vfunc (FpDevice *device) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ExpectedEnrollData *expected_data = fake_dev->user_data; ++ ++ g_autoptr(GError) error = NULL; ++ ++ expected_data->completed_stages = ++ g_random_int_range (fp_device_get_nr_enroll_stages (device), G_MAXINT32); ++ expected_data->print = fp_print_new (device); ++ expected_data->error = NULL; ++ ++ g_object_add_weak_pointer (G_OBJECT (expected_data->print), ++ (gpointer) & expected_data->print); ++ ++ fpi_device_enroll_progress (device, expected_data->completed_stages, ++ expected_data->print, expected_data->error); ++ g_assert (fake_dev->last_called_function == test_driver_enroll_progress_callback); ++ g_assert_null (expected_data->print); ++ ++ ++ expected_data->completed_stages = ++ g_random_int_range (fp_device_get_nr_enroll_stages (device), G_MAXINT32); ++ expected_data->print = NULL; ++ expected_data->error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT); ++ ++ fpi_device_enroll_progress (device, expected_data->completed_stages, ++ expected_data->print, expected_data->error); ++ g_assert (fake_dev->last_called_function == test_driver_enroll_progress_callback); ++ ++ ++ expected_data->completed_stages = ++ g_random_int_range (fp_device_get_nr_enroll_stages (device), G_MAXINT32); ++ expected_data->print = fp_print_new (device); ++ expected_data->error = NULL; ++ ++ error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*assertion*error*FP_DEVICE_RETRY*failed"); ++ fpi_device_enroll_progress (device, expected_data->completed_stages, ++ expected_data->print, error); ++ g_assert (fake_dev->last_called_function == test_driver_enroll_progress_callback); ++ g_clear_object (&expected_data->print); ++ g_test_assert_expected_messages (); ++ ++ expected_data->completed_stages = ++ g_random_int_range (fp_device_get_nr_enroll_stages (device), G_MAXINT32); ++ expected_data->print = NULL; ++ expected_data->error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, ++ "*Driver passed an error and also provided a print*"); ++ fpi_device_enroll_progress (device, expected_data->completed_stages, ++ fp_print_new (device), expected_data->error); ++ g_assert (fake_dev->last_called_function == test_driver_enroll_progress_callback); ++ g_test_assert_expected_messages (); ++ ++ default_fake_dev_class.enroll (device); ++ fake_dev->last_called_function = test_driver_enroll_progress_vfunc; ++} ++ ++static void ++test_driver_enroll_progress (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpAutoCloseDevice) device = NULL; ++ ExpectedEnrollData expected_enroll_data = {0}; ++ FpiDeviceFake *fake_dev; ++ ++ dev_class->nr_enroll_stages = g_random_int_range (10, G_MAXINT32); ++ dev_class->enroll = test_driver_enroll_progress_vfunc; ++ device = auto_close_fake_device_new (); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*assertion*current_action*FP_DEVICE_ACTION_ENROLL*failed"); ++ fpi_device_enroll_progress (device, 0, NULL, NULL); ++ g_test_assert_expected_messages (); ++ ++ fake_dev = FPI_DEVICE_FAKE (device); ++ fake_dev->user_data = &expected_enroll_data; ++ ++ fp_device_enroll_sync (device, fp_print_new (device), NULL, ++ test_driver_enroll_progress_callback, &expected_enroll_data, NULL); ++ ++ g_assert (fake_dev->last_called_function == test_driver_enroll_progress_vfunc); ++} ++ ++static void ++test_driver_verify (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ g_autoptr(FpPrint) enrolled_print = fp_print_new (device); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ FpPrint *out_print = NULL; ++ gboolean match; ++ ++ fake_dev->ret_result = FPI_MATCH_SUCCESS; ++ fp_device_verify_sync (device, enrolled_print, NULL, &match, &out_print, &error); ++ ++ g_assert (fake_dev->last_called_function == dev_class->verify); ++ g_assert (fake_dev->action_data == enrolled_print); ++ g_assert_no_error (error); ++ ++ g_assert (out_print == enrolled_print); ++ g_assert_true (match); ++} ++ ++static void ++test_driver_verify_fail (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ g_autoptr(FpPrint) enrolled_print = fp_print_new (device); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ FpPrint *out_print = NULL; ++ gboolean match; ++ ++ fake_dev->ret_result = FPI_MATCH_FAIL; ++ fp_device_verify_sync (device, enrolled_print, NULL, &match, &out_print, &error); ++ ++ g_assert (fake_dev->last_called_function == dev_class->verify); ++ g_assert_no_error (error); ++ ++ g_assert (out_print == enrolled_print); ++ g_assert_false (match); ++} ++ ++static void ++test_driver_verify_error (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ g_autoptr(FpPrint) enrolled_print = fp_print_new (device); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ FpPrint *out_print = NULL; ++ gboolean match; ++ ++ fake_dev->ret_result = FPI_MATCH_ERROR; ++ fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); ++ fp_device_verify_sync (device, enrolled_print, NULL, &match, &out_print, &error); ++ ++ g_assert (fake_dev->last_called_function == dev_class->verify); ++ g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); ++ g_assert (error == g_steal_pointer (&fake_dev->ret_error)); ++ g_assert_false (match); ++} ++ ++static void ++fake_device_stub_identify (FpDevice *device) ++{ ++} ++ ++static void ++test_driver_supports_identify (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpDevice) device = NULL; ++ ++ dev_class->identify = fake_device_stub_identify; ++ ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ g_assert_true (fp_device_supports_identify (device)); ++} ++ ++static void ++test_driver_do_not_support_identify (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpDevice) device = NULL; ++ ++ dev_class->identify = NULL; ++ ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ g_assert_false (fp_device_supports_identify (device)); ++} ++ ++static void ++test_driver_identify (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpPrint) print = NULL; ++ g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ FpPrint *matched_print; ++ FpPrint *expected_matched; ++ unsigned int i; ++ ++ for (i = 0; i < 500; ++i) ++ g_ptr_array_add (prints, fp_print_new (device)); ++ ++ expected_matched = g_ptr_array_index (prints, g_random_int_range (0, 499)); ++ fp_print_set_description (expected_matched, "fake-verified"); ++ ++ g_assert_true (fp_device_supports_identify (device)); ++ ++ fake_dev->ret_print = fp_print_new (device); ++ fp_device_identify_sync (device, prints, NULL, &matched_print, &print, &error); ++ ++ g_assert (fake_dev->last_called_function == dev_class->identify); ++ g_assert (fake_dev->action_data == prints); ++ g_assert_no_error (error); ++ ++ g_assert (print != NULL && print == fake_dev->ret_print); ++ g_assert (expected_matched == matched_print); ++} ++ ++static void ++test_driver_identify_fail (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpPrint) print = NULL; ++ g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ FpPrint *matched_print; ++ unsigned int i; ++ ++ for (i = 0; i < 500; ++i) ++ g_ptr_array_add (prints, fp_print_new (device)); ++ ++ g_assert_true (fp_device_supports_identify (device)); ++ ++ fake_dev->ret_print = fp_print_new (device); ++ fp_device_identify_sync (device, prints, NULL, &matched_print, &print, &error); ++ ++ g_assert (fake_dev->last_called_function == dev_class->identify); ++ g_assert_no_error (error); ++ ++ g_assert (print != NULL && print == fake_dev->ret_print); ++ g_assert_null (matched_print); ++} ++ ++static void ++test_driver_identify_error (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpPrint) print = NULL; ++ g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ FpPrint *matched_print; ++ FpPrint *expected_matched; ++ unsigned int i; ++ ++ for (i = 0; i < 500; ++i) ++ g_ptr_array_add (prints, fp_print_new (device)); ++ ++ expected_matched = g_ptr_array_index (prints, g_random_int_range (0, 499)); ++ fp_print_set_description (expected_matched, "fake-verified"); ++ ++ g_assert_true (fp_device_supports_identify (device)); ++ ++ fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); ++ fp_device_identify_sync (device, prints, NULL, &matched_print, &print, &error); ++ ++ g_assert (fake_dev->last_called_function == dev_class->identify); ++ g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); ++ g_assert (error == g_steal_pointer (&fake_dev->ret_error)); ++ g_assert_null (matched_print); ++ g_assert_null (print); ++} ++ ++static void ++fake_device_stub_capture (FpDevice *device) ++{ ++} ++ ++static void ++test_driver_supports_capture (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpDevice) device = NULL; ++ ++ dev_class->capture = fake_device_stub_capture; ++ ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ g_assert_true (fp_device_supports_capture (device)); ++} ++ ++static void ++test_driver_do_not_support_capture (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpDevice) device = NULL; ++ ++ dev_class->capture = NULL; ++ ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ g_assert_false (fp_device_supports_capture (device)); ++} ++ ++static void ++test_driver_capture (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpImage) image = NULL; ++ g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ gboolean wait_for_finger = TRUE; ++ ++ fake_dev->ret_image = fp_image_new (500, 500); ++ image = fp_device_capture_sync (device, wait_for_finger, NULL, &error); ++ g_assert (fake_dev->last_called_function == dev_class->capture); ++ g_assert_true (GPOINTER_TO_UINT (fake_dev->action_data)); ++ g_assert_no_error (error); ++ ++ g_assert (image == fake_dev->ret_image); ++} ++ ++static void ++test_driver_capture_error (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpImage) image = NULL; ++ g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ gboolean wait_for_finger = TRUE; ++ ++ fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); ++ image = fp_device_capture_sync (device, wait_for_finger, NULL, &error); ++ g_assert (fake_dev->last_called_function == dev_class->capture); ++ g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); ++ g_assert (error == g_steal_pointer (&fake_dev->ret_error)); ++ ++ g_assert_null (image); ++} ++ ++static void ++fake_device_stub_list (FpDevice *device) ++{ ++} ++ ++static void ++test_driver_has_storage (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpDevice) device = NULL; ++ ++ dev_class->list = fake_device_stub_list; ++ ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ g_assert_true (fp_device_has_storage (device)); ++} ++ ++static void ++test_driver_has_not_storage (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpDevice) device = NULL; ++ ++ dev_class->list = NULL; ++ ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ g_assert_false (fp_device_has_storage (device)); ++} ++ ++static void ++test_driver_list (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); ++ unsigned int i; ++ ++ for (i = 0; i < 500; ++i) ++ g_ptr_array_add (prints, fp_print_new (device)); ++ ++ fake_dev->ret_list = g_steal_pointer (&prints); ++ prints = fp_device_list_prints_sync (device, NULL, &error); ++ ++ g_assert (fake_dev->last_called_function == dev_class->list); ++ g_assert_no_error (error); ++ ++ g_assert (prints == fake_dev->ret_list); ++} ++ ++static void ++test_driver_list_error (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ g_autoptr(GPtrArray) prints = NULL; ++ ++ fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); ++ prints = fp_device_list_prints_sync (device, NULL, &error); ++ ++ g_assert (fake_dev->last_called_function == dev_class->list); ++ g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); ++ g_assert (error == g_steal_pointer (&fake_dev->ret_error)); ++ ++ g_assert_null (prints); ++} ++ ++static void ++test_driver_delete (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ g_autoptr(FpPrint) enrolled_print = fp_print_new (device); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ gboolean ret; ++ ++ ret = fp_device_delete_print_sync (device, enrolled_print, NULL, &error); ++ g_assert (fake_dev->last_called_function == dev_class->delete); ++ g_assert (fake_dev->action_data == enrolled_print); ++ g_assert_no_error (error); ++ g_assert_true (ret); ++} ++ ++static void ++test_driver_delete_error (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ g_autoptr(FpPrint) enrolled_print = fp_print_new (device); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ gboolean ret; ++ ++ fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); ++ ret = fp_device_delete_print_sync (device, enrolled_print, NULL, &error); ++ g_assert (fake_dev->last_called_function == dev_class->delete); ++ g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); ++ g_assert (error == g_steal_pointer (&fake_dev->ret_error)); ++ ++ g_assert_false (ret); ++} ++ ++static gboolean ++fake_device_delete_wait_for_cancel_timeout (gpointer data) ++{ ++ FpDevice *device = data; ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ ++ g_assert (fake_dev->last_called_function == dev_class->cancel); ++ default_fake_dev_class.delete (device); ++ ++ g_assert (fake_dev->last_called_function == default_fake_dev_class.delete); ++ fake_dev->last_called_function = fake_device_delete_wait_for_cancel_timeout; ++ ++ return G_SOURCE_REMOVE; ++} ++ ++static void ++fake_device_delete_wait_for_cancel (FpDevice *device) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ fake_dev->last_called_function = fake_device_delete_wait_for_cancel; ++ ++ g_timeout_add (100, fake_device_delete_wait_for_cancel_timeout, device); ++} ++ ++static void ++on_driver_cancel_delete (GObject *obj, GAsyncResult *res, gpointer user_data) ++{ ++ g_autoptr(GError) error = NULL; ++ FpDevice *device = FP_DEVICE (obj); ++ gboolean *completed = user_data; ++ ++ fp_device_delete_print_finish (device, res, &error); ++ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); ++ ++ *completed = TRUE; ++} ++ ++static void ++test_driver_cancel (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpAutoCloseDevice) device = NULL; ++ g_autoptr(GCancellable) cancellable = NULL; ++ g_autoptr(FpPrint) enrolled_print = NULL; ++ gboolean completed = FALSE; ++ FpiDeviceFake *fake_dev; ++ ++ dev_class->delete = fake_device_delete_wait_for_cancel; ++ ++ device = auto_close_fake_device_new (); ++ fake_dev = FPI_DEVICE_FAKE (device); ++ cancellable = g_cancellable_new (); ++ enrolled_print = fp_print_new (device); ++ ++ fp_device_delete_print (device, enrolled_print, cancellable, ++ on_driver_cancel_delete, &completed); ++ g_cancellable_cancel (cancellable); ++ ++ while (!completed) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert (fake_dev->last_called_function == fake_device_delete_wait_for_cancel_timeout); ++} ++ ++static void ++test_driver_cancel_fail (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ g_autoptr(GCancellable) cancellable = g_cancellable_new (); ++ g_autoptr(FpPrint) enrolled_print = fp_print_new (device); ++ FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ fp_device_delete_print_sync (device, enrolled_print, cancellable, &error); ++ g_assert (fake_dev->last_called_function == dev_class->delete); ++ g_cancellable_cancel (cancellable); ++ ++ while (g_main_context_iteration (NULL, FALSE)) ++ ; ++ ++ g_assert (fake_dev->last_called_function == dev_class->delete); ++ g_assert_no_error (error); ++} ++ ++static void ++test_driver_current_action (void) ++{ ++ g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ ++ g_assert_cmpint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_NONE); ++} ++ ++static void ++test_driver_current_action_open_vfunc (FpDevice *device) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_OPEN); ++ fake_dev->last_called_function = test_driver_current_action_open_vfunc; ++ ++ fpi_device_open_complete (device, NULL); ++} ++ ++static void ++test_driver_current_action_open (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpAutoCloseDevice) device = NULL; ++ FpiDeviceFake *fake_dev; ++ ++ dev_class->open = test_driver_current_action_open_vfunc; ++ device = auto_close_fake_device_new (); ++ fake_dev = FPI_DEVICE_FAKE (device); ++ g_assert (fake_dev->last_called_function == test_driver_current_action_open_vfunc); ++ ++ g_assert_cmpint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_NONE); ++} ++ ++static void ++test_driver_action_get_cancellable_open_vfunc (FpDevice *device) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_OPEN); ++ fake_dev->last_called_function = test_driver_action_get_cancellable_open_vfunc; ++ ++ g_assert_true (G_IS_CANCELLABLE (fpi_device_get_cancellable (device))); ++ ++ fpi_device_open_complete (device, NULL); ++} ++ ++static void ++test_driver_action_get_cancellable_open (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpAutoCloseDevice) device = NULL; ++ g_autoptr(GCancellable) cancellable = NULL; ++ FpiDeviceFake *fake_dev; ++ ++ dev_class->open = test_driver_action_get_cancellable_open_vfunc; ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ fake_dev = FPI_DEVICE_FAKE (device); ++ ++ cancellable = g_cancellable_new (); ++ fp_device_open_sync (device, cancellable, NULL); ++ ++ g_assert (fake_dev->last_called_function == test_driver_action_get_cancellable_open_vfunc); ++} ++ ++static void ++test_driver_action_get_cancellable_open_fail_vfunc (FpDevice *device) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_OPEN); ++ fake_dev->last_called_function = test_driver_action_get_cancellable_open_fail_vfunc; ++ ++ g_assert_false (G_IS_CANCELLABLE (fpi_device_get_cancellable (device))); ++ ++ fpi_device_open_complete (device, NULL); ++} ++ ++static void ++test_driver_action_get_cancellable_open_fail (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpAutoCloseDevice) device = NULL; ++ FpiDeviceFake *fake_dev; ++ ++ dev_class->open = test_driver_action_get_cancellable_open_fail_vfunc; ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ fake_dev = FPI_DEVICE_FAKE (device); ++ ++ g_assert_true (fp_device_open_sync (device, NULL, NULL)); ++ ++ g_assert (fake_dev->last_called_function == test_driver_action_get_cancellable_open_fail_vfunc); ++} ++ ++static void ++test_driver_action_get_cancellable_error (void) ++{ ++ g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*assertion*current_action*FP_DEVICE_ACTION_NONE*failed"); ++ g_assert_null (fpi_device_get_cancellable (device)); ++ g_test_assert_expected_messages (); ++} ++ ++static void ++test_driver_action_is_cancelled_open_vfunc (FpDevice *device) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_OPEN); ++ fake_dev->last_called_function = test_driver_action_is_cancelled_open_vfunc; ++ ++ g_assert_true (G_IS_CANCELLABLE (fpi_device_get_cancellable (device))); ++ g_assert_false (fpi_device_action_is_cancelled (device)); ++ ++ g_cancellable_cancel (fpi_device_get_cancellable (device)); ++ g_assert_true (fpi_device_action_is_cancelled (device)); ++ ++ fpi_device_open_complete (device, NULL); ++} ++ ++static void ++test_driver_action_is_cancelled_open (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpAutoCloseDevice) device = NULL; ++ g_autoptr(GCancellable) cancellable = NULL; ++ g_autoptr(GError) error = NULL; ++ FpiDeviceFake *fake_dev; ++ ++ dev_class->open = test_driver_action_is_cancelled_open_vfunc; ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ fake_dev = FPI_DEVICE_FAKE (device); ++ ++ cancellable = g_cancellable_new (); ++ g_assert_false (fp_device_open_sync (device, cancellable, &error)); ++ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); ++ ++ g_assert (fake_dev->last_called_function == test_driver_action_is_cancelled_open_vfunc); ++} ++ ++static void ++test_driver_action_is_cancelled_error (void) ++{ ++ g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*assertion*current_action*FP_DEVICE_ACTION_NONE*failed"); ++ g_assert_true (fpi_device_action_is_cancelled (device)); ++ g_test_assert_expected_messages (); ++} ++ ++static void ++test_driver_complete_actions_errors (void) ++{ ++ g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*assertion*current_action*failed"); ++ fpi_device_probe_complete (device, NULL, NULL, NULL); ++ g_test_assert_expected_messages (); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*assertion*current_action*failed"); ++ fpi_device_open_complete (device, NULL); ++ g_test_assert_expected_messages (); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*assertion*current_action*failed"); ++ fpi_device_close_complete (device, NULL); ++ g_test_assert_expected_messages (); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*assertion*current_action*failed"); ++ fpi_device_enroll_complete (device, NULL, NULL); ++ g_test_assert_expected_messages (); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*assertion*current_action*failed"); ++ fpi_device_verify_complete (device, FPI_MATCH_FAIL, NULL, NULL); ++ g_test_assert_expected_messages (); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*assertion*current_action*failed"); ++ fpi_device_identify_complete (device, NULL, NULL, NULL); ++ g_test_assert_expected_messages (); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*assertion*current_action*failed"); ++ fpi_device_capture_complete (device, NULL, NULL); ++ g_test_assert_expected_messages (); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*assertion*current_action*failed"); ++ fpi_device_delete_complete (device, NULL); ++ g_test_assert_expected_messages (); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*assertion*current_action*failed"); ++ fpi_device_list_complete (device, NULL, NULL); ++ g_test_assert_expected_messages (); ++} ++ ++static void ++test_driver_action_error_error (void) ++{ ++ g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*assertion*current_action*FP_DEVICE_ACTION_NONE*failed"); ++ fpi_device_action_error (device, NULL); ++ g_test_assert_expected_messages (); ++} ++ ++static void ++test_driver_action_error_open (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpAutoCloseDevice) device = NULL; ++ g_autoptr(GError) error = NULL; ++ FpiDeviceFake *fake_dev; ++ ++ dev_class->open = test_driver_action_error_vfunc; ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ fake_dev = FPI_DEVICE_FAKE (device); ++ fake_dev->user_data = fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID); ++ ++ g_assert_false (fp_device_open_sync (device, NULL, &error)); ++ g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_INVALID); ++ ++ g_assert (fake_dev->last_called_function == test_driver_action_error_vfunc); ++} ++ ++static void ++test_driver_action_error_fallback_open (void) ++{ ++ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); ++ g_autoptr(FpAutoCloseDevice) device = NULL; ++ g_autoptr(GError) error = NULL; ++ FpiDeviceFake *fake_dev; ++ ++ dev_class->open = test_driver_action_error_vfunc; ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ fake_dev = FPI_DEVICE_FAKE (device); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, ++ "*Device failed to pass an error to generic action " ++ "error function*"); ++ ++ g_assert_false (fp_device_open_sync (device, NULL, &error)); ++ g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); ++ ++ g_assert (fake_dev->last_called_function == test_driver_action_error_vfunc); ++ g_test_assert_expected_messages (); ++} ++ ++static void ++test_driver_add_timeout_func (FpDevice *device, gpointer user_data) ++{ ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ ++ fake_dev->last_called_function = test_driver_add_timeout_func; ++} ++ ++static void ++test_driver_add_timeout (void) ++{ ++ g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ FpDevice *data_check = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ ++ g_object_add_weak_pointer (G_OBJECT (data_check), (gpointer) & data_check); ++ fpi_device_add_timeout (device, 50, test_driver_add_timeout_func, ++ data_check, g_object_unref); ++ ++ g_assert_nonnull (data_check); ++ ++ while (FP_IS_DEVICE (data_check)) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_null (data_check); ++ g_assert (fake_dev->last_called_function == test_driver_add_timeout_func); ++} ++ ++static gboolean ++test_driver_add_timeout_cancelled_timeout (gpointer data) ++{ ++ GSource *source = data; ++ ++ g_source_destroy (source); ++ ++ return G_SOURCE_REMOVE; ++} ++ ++static void ++test_driver_add_timeout_cancelled (void) ++{ ++ g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); ++ FpDevice *data_check = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ GSource *source; ++ ++ g_object_add_weak_pointer (G_OBJECT (data_check), (gpointer) & data_check); ++ source = fpi_device_add_timeout (device, 2000, test_driver_add_timeout_func, ++ data_check, g_object_unref); ++ ++ g_timeout_add (20, test_driver_add_timeout_cancelled_timeout, source); ++ g_assert_nonnull (data_check); ++ ++ while (FP_IS_DEVICE (data_check)) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_null (data_check); ++ g_assert_null (fake_dev->last_called_function); ++} ++ ++static void ++test_driver_error_types (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(GEnumClass) errors_enum = g_type_class_ref (FP_TYPE_DEVICE_ERROR); ++ int i; ++ ++ for (i = 0; g_enum_get_value (errors_enum, i); ++i) ++ { ++ error = fpi_device_error_new (i); ++ g_assert_error (error, FP_DEVICE_ERROR, i); ++ g_clear_error (&error); ++ } ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "*Unsupported error*"); ++ error = fpi_device_error_new (i + 1); ++ g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); ++ g_test_assert_expected_messages (); ++} ++ ++static void ++test_driver_retry_error_types (void) ++{ ++ g_autoptr(GError) error = NULL; ++ g_autoptr(GEnumClass) errors_enum = g_type_class_ref (FP_TYPE_DEVICE_RETRY); ++ int i; ++ ++ for (i = 0; g_enum_get_value (errors_enum, i); ++i) ++ { ++ error = fpi_device_retry_new (i); ++ g_assert_error (error, FP_DEVICE_RETRY, i); ++ g_clear_error (&error); ++ } ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "*Unsupported error*"); ++ error = fpi_device_retry_new (i + 1); ++ g_assert_error (error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL); ++ g_test_assert_expected_messages (); ++} ++ ++int ++main (int argc, char *argv[]) ++{ ++ g_test_init (&argc, &argv, NULL); ++ ++ g_test_add_func ("/driver/get_driver", test_driver_get_driver); ++ g_test_add_func ("/driver/get_device_id", test_driver_get_device_id); ++ g_test_add_func ("/driver/get_name", test_driver_get_name); ++ g_test_add_func ("/driver/is_open", test_driver_is_open); ++ g_test_add_func ("/driver/get_scan_type/press", test_driver_get_scan_type_press); ++ g_test_add_func ("/driver/get_scan_type/swipe", test_driver_get_scan_type_swipe); ++ g_test_add_func ("/driver/set_scan_type/press", test_driver_set_scan_type_press); ++ g_test_add_func ("/driver/set_scan_type/swipe", test_driver_set_scan_type_swipe); ++ g_test_add_func ("/driver/get_nr_enroll_stages", test_driver_get_nr_enroll_stages); ++ g_test_add_func ("/driver/set_nr_enroll_stages", test_driver_set_nr_enroll_stages); ++ g_test_add_func ("/driver/supports_identify", test_driver_supports_identify); ++ g_test_add_func ("/driver/supports_capture", test_driver_supports_capture); ++ g_test_add_func ("/driver/has_storage", test_driver_has_storage); ++ g_test_add_func ("/driver/do_not_support_identify", test_driver_do_not_support_identify); ++ g_test_add_func ("/driver/do_not_support_capture", test_driver_do_not_support_capture); ++ g_test_add_func ("/driver/has_not_storage", test_driver_has_not_storage); ++ g_test_add_func ("/driver/get_usb_device", test_driver_get_usb_device); ++ g_test_add_func ("/driver/get_virtual_env", test_driver_get_virtual_env); ++ g_test_add_func ("/driver/get_driver_data", test_driver_get_driver_data); ++ ++ g_test_add_func ("/driver/probe", test_driver_probe); ++ g_test_add_func ("/driver/open", test_driver_open); ++ g_test_add_func ("/driver/open/error", test_driver_open_error); ++ g_test_add_func ("/driver/close", test_driver_close); ++ g_test_add_func ("/driver/close/error", test_driver_close_error); ++ g_test_add_func ("/driver/enroll", test_driver_enroll); ++ g_test_add_func ("/driver/enroll/error", test_driver_enroll_error); ++ g_test_add_func ("/driver/enroll/progress", test_driver_enroll_progress); ++ g_test_add_func ("/driver/verify", test_driver_verify); ++ g_test_add_func ("/driver/verify/fail", test_driver_verify_fail); ++ g_test_add_func ("/driver/verify/error", test_driver_verify_error); ++ g_test_add_func ("/driver/identify", test_driver_identify); ++ g_test_add_func ("/driver/identify/fail", test_driver_identify_fail); ++ g_test_add_func ("/driver/identify/error", test_driver_identify_error); ++ g_test_add_func ("/driver/capture", test_driver_capture); ++ g_test_add_func ("/driver/capture/error", test_driver_capture_error); ++ g_test_add_func ("/driver/list", test_driver_list); ++ g_test_add_func ("/driver/list/error", test_driver_list_error); ++ g_test_add_func ("/driver/delete", test_driver_delete); ++ g_test_add_func ("/driver/delete/error", test_driver_delete_error); ++ g_test_add_func ("/driver/cancel", test_driver_cancel); ++ g_test_add_func ("/driver/cancel/fail", test_driver_cancel_fail); ++ ++ g_test_add_func ("/driver/get_current_action", test_driver_current_action); ++ g_test_add_func ("/driver/get_current_action/open", test_driver_current_action_open); ++ g_test_add_func ("/driver/get_cancellable/error", test_driver_action_get_cancellable_error); ++ g_test_add_func ("/driver/get_cancellable/open", test_driver_action_get_cancellable_open); ++ g_test_add_func ("/driver/get_cancellable/open/fail", test_driver_action_get_cancellable_open_fail); ++ g_test_add_func ("/driver/action_is_cancelled/open", test_driver_action_is_cancelled_open); ++ g_test_add_func ("/driver/action_is_cancelled/error", test_driver_action_is_cancelled_error); ++ g_test_add_func ("/driver/complete_action/all/error", test_driver_complete_actions_errors); ++ g_test_add_func ("/driver/action_error/error", test_driver_action_error_error); ++ g_test_add_func ("/driver/action_error/open", test_driver_action_error_open); ++ g_test_add_func ("/driver/action_error/fail/open", test_driver_action_error_fallback_open); ++ ++ g_test_add_func ("/driver/timeout", test_driver_add_timeout); ++ g_test_add_func ("/driver/timeout/cancelled", test_driver_add_timeout_cancelled); ++ ++ g_test_add_func ("/driver/error_types", test_driver_error_types); ++ g_test_add_func ("/driver/retry_error_types", test_driver_retry_error_types); ++ ++ return g_test_run (); ++} +-- +2.24.1 + diff --git a/SOURCES/0122-fpi-ssm-Use-same-argument-names-of-header-file.patch b/SOURCES/0122-fpi-ssm-Use-same-argument-names-of-header-file.patch new file mode 100644 index 0000000..8196840 --- /dev/null +++ b/SOURCES/0122-fpi-ssm-Use-same-argument-names-of-header-file.patch @@ -0,0 +1,44 @@ +From 3aea44e308637bfc8d32c751f9d50aa34e0f9229 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 11 Dec 2019 20:07:59 +0100 +Subject: [PATCH 122/181] fpi-ssm: Use same argument names of header file + +So we can mute a Gtk-doc parser warning +--- + libfprint/fpi-ssm.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index 8b3e4bd..0f3e6fb 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -115,7 +115,7 @@ struct _FpiSsm + * @dev: a #fp_dev fingerprint device + * @handler: the callback function + * @nr_states: the number of states +- * @name: the name of the state machine (for debug purposes) ++ * @machine_name: the name of the state machine (for debug purposes) + * + * Allocate a new ssm, with @nr_states states. The @handler callback + * will be called after each state transition. +@@ -126,7 +126,7 @@ FpiSsm * + fpi_ssm_new_full (FpDevice *dev, + FpiSsmHandlerCallback handler, + int nr_states, +- const char *name) ++ const char *machine_name) + { + FpiSsm *machine; + +@@ -137,7 +137,7 @@ fpi_ssm_new_full (FpDevice *dev, + machine->handler = handler; + machine->nr_states = nr_states; + machine->dev = dev; +- machine->name = g_strdup (name); ++ machine->name = g_strdup (machine_name); + machine->completed = TRUE; + return machine; + } +-- +2.24.1 + diff --git a/SOURCES/0123-fpi-ssm-Define-autoptr-cleanup-function.patch b/SOURCES/0123-fpi-ssm-Define-autoptr-cleanup-function.patch new file mode 100644 index 0000000..37ac17c --- /dev/null +++ b/SOURCES/0123-fpi-ssm-Define-autoptr-cleanup-function.patch @@ -0,0 +1,22 @@ +From ea9e12ccb39578e0acd28d125c9ae4a7969890ad Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 11 Dec 2019 20:57:15 +0100 +Subject: [PATCH 123/181] fpi-ssm: Define autoptr cleanup function + +--- + libfprint/fpi-ssm.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/libfprint/fpi-ssm.h b/libfprint/fpi-ssm.h +index d1334b5..956e355 100644 +--- a/libfprint/fpi-ssm.h ++++ b/libfprint/fpi-ssm.h +@@ -109,3 +109,5 @@ void fpi_ssm_usb_transfer_with_weak_pointer_cb (FpiUsbTransfer *transfer, + FpDevice *device, + gpointer weak_ptr, + GError *error); ++ ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiSsm, fpi_ssm_free) +-- +2.24.1 + diff --git a/SOURCES/0124-fpi-ssm-Bug-on-wrong-state-passed-to-jump_to_state_d.patch b/SOURCES/0124-fpi-ssm-Bug-on-wrong-state-passed-to-jump_to_state_d.patch new file mode 100644 index 0000000..512f982 --- /dev/null +++ b/SOURCES/0124-fpi-ssm-Bug-on-wrong-state-passed-to-jump_to_state_d.patch @@ -0,0 +1,29 @@ +From ed6eb8050d85d70920c2536a153fa4eddc5e9fe2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 12 Dec 2019 14:54:26 +0100 +Subject: [PATCH 124/181] fpi-ssm: Bug on wrong state passed to + jump_to_state_delayed + +While remove the checks that are already part of the common function +fpi_ssm_set_delayed_action_timeout(). +--- + libfprint/fpi-ssm.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index 0f3e6fb..d672064 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -573,8 +573,7 @@ fpi_ssm_jump_to_state_delayed (FpiSsm *machine, + g_autofree char *source_name = NULL; + + g_return_if_fail (machine != NULL); +- BUG_ON (machine->completed); +- BUG_ON (machine->timeout != NULL); ++ BUG_ON (state < 0 || state >= machine->nr_states); + + data = g_new0 (FpiSsmJumpToStateDelayedData, 1); + data->machine = machine; +-- +2.24.1 + diff --git a/SOURCES/0125-fpi-ssm-Add-debug-message-when-a-delayed-state-chang.patch b/SOURCES/0125-fpi-ssm-Add-debug-message-when-a-delayed-state-chang.patch new file mode 100644 index 0000000..491af73 --- /dev/null +++ b/SOURCES/0125-fpi-ssm-Add-debug-message-when-a-delayed-state-chang.patch @@ -0,0 +1,37 @@ +From 94bc978bc16f04480921ea9222051ae2f0f30318 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 12 Dec 2019 15:49:35 +0100 +Subject: [PATCH 125/181] fpi-ssm: Add debug message when a delayed state + change is cancelled + +--- + libfprint/fpi-ssm.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index d672064..6e56e44 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -213,6 +213,9 @@ on_delayed_action_cancelled (GCancellable *cancellable, + { + CancelledActionIdleData *data; + ++ fp_dbg ("[%s] %s cancelled delayed state change", ++ fp_device_get_driver (machine->dev), machine->name); ++ + g_clear_pointer (&machine->timeout, g_source_destroy); + + data = g_new0 (CancelledActionIdleData, 1); +@@ -469,6 +472,9 @@ fpi_ssm_cancel_delayed_state_change (FpiSsm *machine) + BUG_ON (machine->completed); + BUG_ON (machine->timeout == NULL); + ++ fp_dbg ("[%s] %s cancelled delayed state change", ++ fp_device_get_driver (machine->dev), machine->name); ++ + fpi_ssm_clear_delayed_action (machine); + } + +-- +2.24.1 + diff --git a/SOURCES/0126-fpi-ssm-Make-clear-that-the-completed-callback-owns-.patch b/SOURCES/0126-fpi-ssm-Make-clear-that-the-completed-callback-owns-.patch new file mode 100644 index 0000000..4bd8fea --- /dev/null +++ b/SOURCES/0126-fpi-ssm-Make-clear-that-the-completed-callback-owns-.patch @@ -0,0 +1,26 @@ +From 740ba3265766f32bfa37c78e8c638a469b65071c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 12 Dec 2019 16:06:37 +0100 +Subject: [PATCH 126/181] fpi-ssm: Make clear that the completed callback owns + the error + +--- + libfprint/fpi-ssm.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libfprint/fpi-ssm.h b/libfprint/fpi-ssm.h +index 956e355..fe64946 100644 +--- a/libfprint/fpi-ssm.h ++++ b/libfprint/fpi-ssm.h +@@ -39,7 +39,7 @@ typedef struct _FpiSsm FpiSsm; + * FpiSsmCompletedCallback: + * @ssm: a #FpiSsm state machine + * @dev: the #fp_dev fingerprint device +- * @error: The #GError or %NULL on successful completion ++ * @error: (transfer full): The #GError or %NULL on successful completion + * + * The callback called when a state machine completes successfully, + * as set when calling fpi_ssm_start(). +-- +2.24.1 + diff --git a/SOURCES/0127-fpi-ssm-Clear-delayed-actions-for-parent-and-child-o.patch b/SOURCES/0127-fpi-ssm-Clear-delayed-actions-for-parent-and-child-o.patch new file mode 100644 index 0000000..f53b1b7 --- /dev/null +++ b/SOURCES/0127-fpi-ssm-Clear-delayed-actions-for-parent-and-child-o.patch @@ -0,0 +1,34 @@ +From f8f4344d47c7d112be87c5840c59156f0fdebbe8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 12 Dec 2019 18:41:26 +0100 +Subject: [PATCH 127/181] fpi-ssm: Clear delayed actions for parent and child + on subssm start + +While timeout was already cleared for parent, we didn't properly delete the +cancellable. + +Although we'd warn anyways when starting the SSM, is still better to clear +any delayed action also for the sub-SSM +--- + libfprint/fpi-ssm.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c +index 6e56e44..3cc39a7 100644 +--- a/libfprint/fpi-ssm.c ++++ b/libfprint/fpi-ssm.c +@@ -338,7 +338,10 @@ fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child) + { + BUG_ON (parent->timeout); + child->parentsm = parent; +- g_clear_pointer (&parent->timeout, g_source_destroy); ++ ++ fpi_ssm_clear_delayed_action (parent); ++ fpi_ssm_clear_delayed_action (child); ++ + fpi_ssm_start (child, __subsm_complete); + } + +-- +2.24.1 + diff --git a/SOURCES/0128-tests-Add-unit-tests-for-fpi-ssm.patch b/SOURCES/0128-tests-Add-unit-tests-for-fpi-ssm.patch new file mode 100644 index 0000000..b0ce190 --- /dev/null +++ b/SOURCES/0128-tests-Add-unit-tests-for-fpi-ssm.patch @@ -0,0 +1,1430 @@ +From 2e8981f0f549d59665ca93dfa5a8a38a7defb7e5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 12 Dec 2019 18:42:46 +0100 +Subject: [PATCH 128/181] tests: Add unit tests for fpi-ssm + +Verify that the state machine actions are done as we expected, being the +main tool for drivers, better to check that is done as we expect. +--- + tests/meson.build | 1 + + tests/test-fpi-ssm.c | 1396 ++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 1397 insertions(+) + create mode 100644 tests/test-fpi-ssm.c + +diff --git a/tests/meson.build b/tests/meson.build +index d082908..b4022a4 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -58,6 +58,7 @@ test_utils = static_library('fprint-test-utils', + + unit_tests = [ + 'fpi-device', ++ 'fpi-ssm', + ] + + if 'virtual_image' in drivers +diff --git a/tests/test-fpi-ssm.c b/tests/test-fpi-ssm.c +new file mode 100644 +index 0000000..a3bd9da +--- /dev/null ++++ b/tests/test-fpi-ssm.c +@@ -0,0 +1,1396 @@ ++/* ++ * FpiSsm Unit tests ++ * 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 "fp-device.h" ++#define FP_COMPONENT "SSM" ++ ++#include "drivers_api.h" ++#include "test-device-fake.h" ++#include "fpi-log.h" ++ ++/* Utility functions and shared data */ ++ ++static FpDevice *fake_device = NULL; ++ ++typedef struct ++{ ++ volatile int ref_count; ++ int handler_state; ++ GSList *handlers_chain; ++ gboolean completed; ++ GError *error; ++ gboolean ssm_destroyed; ++ gboolean expected_last_state; ++} FpiSsmTestData; ++ ++static FpiSsmTestData * ++fpi_ssm_test_data_new (void) ++{ ++ FpiSsmTestData *data = g_new0 (FpiSsmTestData, 1); ++ ++ data->ref_count = 1; ++ data->handler_state = -1; ++ ++ return data; ++} ++ ++static FpiSsmTestData * ++fpi_ssm_test_data_ref (FpiSsmTestData *data) ++{ ++ g_atomic_int_inc (&data->ref_count); ++ return data; ++} ++ ++static void ++fpi_ssm_test_data_unref (FpiSsmTestData *data) ++{ ++ if (g_atomic_int_dec_and_test (&data->ref_count)) ++ { ++ g_clear_error (&data->error); ++ g_slist_free (data->handlers_chain); ++ g_free (data); ++ } ++} ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiSsmTestData, fpi_ssm_test_data_unref) ++ ++static void ++fpi_ssm_test_data_unref_by_ssm (FpiSsmTestData *data) ++{ ++ data->ssm_destroyed = TRUE; ++ ++ fpi_ssm_test_data_unref (data); ++} ++ ++enum { ++ FPI_TEST_SSM_STATE_0, ++ FPI_TEST_SSM_STATE_1, ++ FPI_TEST_SSM_STATE_2, ++ FPI_TEST_SSM_STATE_3, ++ FPI_TEST_SSM_STATE_NUM ++}; ++ ++static void ++test_ssm_handler (FpiSsm *ssm, ++ FpDevice *dev) ++{ ++ FpiSsmTestData *data; ++ ++ g_assert (dev == fake_device); ++ g_assert_true (FP_IS_DEVICE (dev)); ++ ++ data = fpi_ssm_get_data (ssm); ++ data->handler_state = fpi_ssm_get_cur_state (ssm); ++ data->handlers_chain = g_slist_append (data->handlers_chain, ++ GINT_TO_POINTER (fpi_ssm_get_cur_state (ssm))); ++} ++ ++static void ++test_ssm_completed_callback (FpiSsm *ssm, ++ FpDevice *dev, ++ GError *error) ++{ ++ FpiSsmTestData *data; ++ ++ g_assert (dev == fake_device); ++ g_assert_true (FP_IS_DEVICE (dev)); ++ ++ data = fpi_ssm_get_data (ssm); ++ data->completed = TRUE; ++ data->handlers_chain = g_slist_append (data->handlers_chain, ++ GINT_TO_POINTER (fpi_ssm_get_cur_state (ssm))); ++ g_clear_error (&data->error); ++ data->error = error; ++ ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, data->expected_last_state); ++} ++ ++static FpiSsm * ++ssm_test_new_full (int nr_states, const char *name) ++{ ++ FpiSsm *ssm; ++ FpiSsmTestData *data; ++ ++ ssm = fpi_ssm_new_full (fake_device, test_ssm_handler, nr_states, name); ++ data = fpi_ssm_test_data_new (); ++ data->expected_last_state = nr_states; ++ fpi_ssm_set_data (ssm, data, (GDestroyNotify) fpi_ssm_test_data_unref_by_ssm); ++ ++ return ssm; ++} ++ ++static FpiSsm * ++ssm_test_new (void) ++{ ++ return ssm_test_new_full (FPI_TEST_SSM_STATE_NUM, "FPI_TEST_SSM"); ++} ++ ++static gboolean ++test_ssm_cancel_delayed_action_delayed (gpointer data) ++{ ++ FpiSsm *ssm = data; ++ ++ fpi_ssm_cancel_delayed_state_change (ssm); ++ ++ return G_SOURCE_REMOVE; ++} ++ ++static gboolean ++test_ssm_cancel_cancellable_delayed (gpointer data) ++{ ++ g_cancellable_cancel (G_CANCELLABLE (data)); ++ ++ return G_SOURCE_REMOVE; ++} ++ ++/* Tests */ ++ ++static void ++test_ssm_new (void) ++{ ++ FpiSsm *ssm; ++ ++ ssm = fpi_ssm_new (fake_device, test_ssm_handler, FPI_TEST_SSM_STATE_NUM); ++ ++ g_assert_null (fpi_ssm_get_data (ssm)); ++ g_assert_no_error (fpi_ssm_get_error (ssm)); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ ++ fpi_ssm_free (ssm); ++} ++ ++static void ++test_ssm_new_full (void) ++{ ++ FpiSsm *ssm; ++ ++ ssm = fpi_ssm_new_full (fake_device, test_ssm_handler, ++ FPI_TEST_SSM_STATE_NUM, "Test SSM Name"); ++ ++ g_assert_null (fpi_ssm_get_data (ssm)); ++ g_assert_no_error (fpi_ssm_get_error (ssm)); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ ++ fpi_ssm_free (ssm); ++} ++ ++static void ++test_ssm_new_no_handler (void) ++{ ++ g_autoptr(FpiSsm) ssm = NULL; ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*BUG:*handler*"); ++ ssm = fpi_ssm_new (fake_device, NULL, FPI_TEST_SSM_STATE_NUM); ++ g_test_assert_expected_messages (); ++} ++ ++static void ++test_ssm_new_wrong_states (void) ++{ ++ g_autoptr(FpiSsm) ssm = NULL; ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, ++ "*BUG:*nr_states*"); ++ ssm = fpi_ssm_new (fake_device, test_ssm_handler, -1); ++ g_test_assert_expected_messages (); ++} ++ ++static void ++test_ssm_set_data (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ GObject *object = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ ++ g_object_add_weak_pointer (object, (gpointer) & object); ++ ++ fpi_ssm_set_data (ssm, object, g_object_unref); ++ g_assert (fpi_ssm_get_data (ssm) == object); ++ ++ fpi_ssm_set_data (ssm, (gpointer) 0xdeadbeef, NULL); ++ g_assert (fpi_ssm_get_data (ssm) == (gpointer) 0xdeadbeef); ++ g_assert_null (object); ++} ++ ++static void ++test_ssm_set_data_cleanup (void) ++{ ++ FpiSsm *ssm = ssm_test_new (); ++ GObject *object = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ ++ g_object_add_weak_pointer (object, (gpointer) & object); ++ ++ fpi_ssm_set_data (ssm, object, g_object_unref); ++ g_assert (fpi_ssm_get_data (ssm) == object); ++ ++ fpi_ssm_free (ssm); ++ g_assert_null (object); ++} ++ ++static void ++test_ssm_start (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ ++ g_assert_null (data->handlers_chain); ++ ++ fpi_ssm_start (ssm, NULL); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ g_assert_no_error (data->error); ++ g_assert_false (data->ssm_destroyed); ++} ++ ++static void ++test_ssm_start_single (void) ++{ ++ g_autoptr(FpiSsmTestData) data = NULL; ++ FpiSsm *ssm; ++ ++ ssm = ssm_test_new_full (1, "FPI_TEST_SSM_SINGLE_STATE"); ++ data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm)); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, 0); ++ g_assert_cmpint (data->handler_state, ==, 0); ++ ++ fpi_ssm_next_state (ssm); ++ g_assert_cmpint (data->handler_state, ==, 0); ++ ++ g_assert_true (data->completed); ++ g_assert_no_error (data->error); ++ g_assert_true (data->ssm_destroyed); ++} ++ ++static void ++test_ssm_next (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm)); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_next_state (ssm); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_next_not_started (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*"); ++ fpi_ssm_next_state (ssm); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_next_with_delayed (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ gpointer timeout_tracker = GUINT_TO_POINTER (TRUE); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_next_state_delayed (ssm, 10, NULL); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*"); ++ fpi_ssm_next_state (ssm); ++ g_test_assert_expected_messages (); ++ ++ g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker); ++ while (timeout_tracker) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_next_complete (void) ++{ ++ FpiSsm *ssm = ssm_test_new (); ++ ++ g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm)); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_next_state (ssm); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ fpi_ssm_next_state (ssm); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 3); ++ ++ fpi_ssm_next_state (ssm); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_3); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_3); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 4); ++ ++ fpi_ssm_next_state (ssm); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_3); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 5); ++ ++ g_assert_true (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_jump_to_state (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_jump_to_state (ssm, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ fpi_ssm_jump_to_state (ssm, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 3); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_jump_to_state_not_started (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*"); ++ fpi_ssm_jump_to_state (ssm, FPI_TEST_SSM_STATE_2); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_jump_to_state_with_delayed (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ gpointer timeout_tracker = GUINT_TO_POINTER (TRUE); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_2, 10, NULL); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*"); ++ fpi_ssm_jump_to_state (ssm, FPI_TEST_SSM_STATE_2); ++ g_test_assert_expected_messages (); ++ ++ g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker); ++ while (timeout_tracker) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_jump_to_state_last (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_jump_to_state (ssm, FPI_TEST_SSM_STATE_3); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_3); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_3); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_jump_to_state_wrong (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*nr_states*"); ++ fpi_ssm_jump_to_state (ssm, FPI_TEST_SSM_STATE_NUM + 10); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_NUM + 10); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_NUM + 10); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*state*"); ++ fpi_ssm_jump_to_state (ssm, FPI_TEST_SSM_STATE_0 - 10); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0 - 10); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0 - 10); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 3); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_mark_completed (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm)); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ data->expected_last_state = FPI_TEST_SSM_STATE_0; ++ fpi_ssm_mark_completed (g_steal_pointer (&ssm)); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ g_assert_true (data->completed); ++ g_assert_no_error (data->error); ++ g_assert_true (data->ssm_destroyed); ++} ++ ++static void ++test_ssm_mark_completed_not_started (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm)); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*"); ++ fpi_ssm_mark_completed (g_steal_pointer (&ssm)); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, -1); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 0); ++ g_assert_true (data->ssm_destroyed); ++} ++ ++static void ++test_ssm_mark_completed_with_delayed (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm)); ++ gpointer timeout_tracker = GUINT_TO_POINTER (TRUE); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ data->expected_last_state = FPI_TEST_SSM_STATE_0; ++ fpi_ssm_mark_completed_delayed (ssm, 10, NULL); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*"); ++ fpi_ssm_mark_completed (g_steal_pointer (&ssm)); ++ g_test_assert_expected_messages (); ++ ++ g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker); ++ while (timeout_tracker) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ g_assert_true (data->ssm_destroyed); ++} ++ ++static void ++test_ssm_mark_failed (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm)); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ data->expected_last_state = FPI_TEST_SSM_STATE_0; ++ fpi_ssm_mark_failed (g_steal_pointer (&ssm), ++ fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ g_assert_true (data->completed); ++ g_assert_error (data->error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_PROTO); ++ g_assert_true (data->ssm_destroyed); ++} ++ ++static void ++test_ssm_mark_failed_not_started (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm)); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*"); ++ fpi_ssm_mark_failed (g_steal_pointer (&ssm), ++ fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, -1); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 0); ++ g_assert_true (data->ssm_destroyed); ++} ++ ++static void ++test_ssm_mark_failed_with_delayed (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm)); ++ gpointer timeout_tracker = GUINT_TO_POINTER (TRUE); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_mark_completed_delayed (ssm, 10, NULL); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*"); ++ data->expected_last_state = FPI_TEST_SSM_STATE_0; ++ fpi_ssm_mark_failed (g_steal_pointer (&ssm), ++ fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); ++ g_test_assert_expected_messages (); ++ ++ g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker); ++ while (timeout_tracker) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ g_assert_true (data->completed); ++ g_assert_error (data->error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_PROTO); ++ g_assert_true (data->ssm_destroyed); ++} ++ ++static void ++test_ssm_delayed_next (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_next_state_delayed (ssm, 10, NULL); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ while (data->handler_state == FPI_TEST_SSM_STATE_0) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_delayed_next_cancel (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ gpointer timeout_tracker = GUINT_TO_POINTER (TRUE); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_next_state_delayed (ssm, 10, NULL); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_idle_add_full (G_PRIORITY_HIGH, test_ssm_cancel_delayed_action_delayed, ssm, NULL); ++ g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker); ++ ++ while (timeout_tracker) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_delayed_next_cancellable (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ g_autoptr(GCancellable) cancellable = g_cancellable_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_next_state_delayed (ssm, 10, cancellable); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_idle_add_full (G_PRIORITY_HIGH, test_ssm_cancel_cancellable_delayed, cancellable, NULL); ++ ++ while (!g_cancellable_is_cancelled (cancellable)) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*"); ++ fpi_ssm_cancel_delayed_state_change (ssm); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_delayed_next_not_started (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*"); ++ fpi_ssm_next_state_delayed (ssm, 10, NULL); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, -1); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 0); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*"); ++ while (data->handler_state == -1) ++ g_main_context_iteration (NULL, TRUE); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_delayed_next_complete (void) ++{ ++ FpiSsm *ssm = ssm_test_new (); ++ ++ g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm)); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_next_state_delayed (ssm, 10, NULL); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ while (data->handler_state == FPI_TEST_SSM_STATE_0) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ fpi_ssm_next_state_delayed (ssm, 10, NULL); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ while (data->handler_state == FPI_TEST_SSM_STATE_1) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 3); ++ ++ fpi_ssm_next_state_delayed (ssm, 10, NULL); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 3); ++ ++ while (data->handler_state == FPI_TEST_SSM_STATE_2) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_3); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_3); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 4); ++ ++ fpi_ssm_next_state_delayed (ssm, 10, NULL); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_3); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_3); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 4); ++ ++ while (!data->completed) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_3); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 5); ++ ++ g_assert_true (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_delayed_jump_to_state (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_2, 10, NULL); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ while (data->handler_state == FPI_TEST_SSM_STATE_0) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_1, 10, NULL); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ while (data->handler_state == FPI_TEST_SSM_STATE_2) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 3); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_delayed_jump_to_state_cancel (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ gpointer timeout_tracker = GUINT_TO_POINTER (TRUE); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_2, 10, NULL); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_idle_add_full (G_PRIORITY_HIGH, test_ssm_cancel_delayed_action_delayed, ssm, NULL); ++ g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker); ++ ++ while (timeout_tracker) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_delayed_jump_to_state_cancellable (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ g_autoptr(GCancellable) cancellable = g_cancellable_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_2, 10, cancellable); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_idle_add_full (G_PRIORITY_HIGH, test_ssm_cancel_cancellable_delayed, cancellable, NULL); ++ ++ while (!g_cancellable_is_cancelled (cancellable)) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*"); ++ fpi_ssm_cancel_delayed_state_change (ssm); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_delayed_jump_to_state_not_started (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*"); ++ fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_2, 10, NULL); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, -1); ++ g_assert_null (data->handlers_chain); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*"); ++ while (data->handler_state == -1) ++ g_main_context_iteration (NULL, TRUE); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_delayed_jump_to_state_last (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_3, 10, NULL); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ while (data->handler_state == FPI_TEST_SSM_STATE_0) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_3); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_3); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_delayed_jump_to_state_wrong (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*nr_states*"); ++ fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_NUM + 10, 10, NULL); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*nr_states*"); ++ while (g_slist_length (data->handlers_chain) == 1) ++ g_main_context_iteration (NULL, TRUE); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_NUM + 10); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_NUM + 10); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*state*"); ++ fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_0 - 10, 10, NULL); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_NUM + 10); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_NUM + 10); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*state*"); ++ while (g_slist_length (data->handlers_chain) == 2) ++ g_main_context_iteration (NULL, TRUE); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0 - 10); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0 - 10); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 3); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_delayed_mark_completed (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm)); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ data->expected_last_state = FPI_TEST_SSM_STATE_0; ++ fpi_ssm_mark_completed_delayed (g_steal_pointer (&ssm), 10, NULL); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ while (g_slist_length (data->handlers_chain) == 1) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ g_assert_true (data->completed); ++ g_assert_no_error (data->error); ++ g_assert_true (data->ssm_destroyed); ++} ++ ++static void ++test_ssm_delayed_mark_completed_not_started (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm)); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*"); ++ fpi_ssm_mark_completed_delayed (ssm, 10, NULL); ++ g_test_assert_expected_messages (); ++ ++ g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &ssm); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*"); ++ while (ssm != NULL) ++ g_main_context_iteration (NULL, TRUE); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, -1); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 0); ++ g_assert_true (data->ssm_destroyed); ++} ++ ++static void ++test_ssm_delayed_mark_completed_cancel (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ gpointer timeout_tracker = GUINT_TO_POINTER (TRUE); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_mark_completed_delayed (ssm, 10, NULL); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_idle_add_full (G_PRIORITY_HIGH, test_ssm_cancel_delayed_action_delayed, ssm, NULL); ++ g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker); ++ ++ while (timeout_tracker) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++ g_assert_false (data->ssm_destroyed); ++} ++ ++static void ++test_ssm_delayed_mark_completed_cancellable (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ g_autoptr(GCancellable) cancellable = g_cancellable_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_mark_completed_delayed (ssm, 10, cancellable); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_idle_add_full (G_PRIORITY_HIGH, test_ssm_cancel_cancellable_delayed, cancellable, NULL); ++ ++ while (!g_cancellable_is_cancelled (cancellable)) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*"); ++ fpi_ssm_cancel_delayed_state_change (ssm); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_assert_false (data->completed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_delayed_cancel_error (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*"); ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*"); ++ fpi_ssm_cancel_delayed_state_change (ssm); ++ g_test_assert_expected_messages (); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*"); ++ fpi_ssm_cancel_delayed_state_change (ssm); ++ g_test_assert_expected_messages (); ++} ++ ++static void ++test_ssm_subssm_start (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ g_autoptr(FpiSsm) subssm = ++ ssm_test_new_full (FPI_TEST_SSM_STATE_NUM, "FPI_TEST_SUB_SSM"); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ g_autoptr(FpiSsmTestData) subdata = ++ fpi_ssm_test_data_ref (fpi_ssm_get_data (subssm)); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_start_subsm (ssm, subssm); ++ g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (subssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 1); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_next_state (subssm); ++ ++ g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 2); ++ g_assert_no_error (subdata->error); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ subdata->expected_last_state = FPI_TEST_SSM_STATE_1; ++ fpi_ssm_mark_completed (g_steal_pointer (&subssm)); ++ ++ g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 2); ++ g_assert_true (subdata->ssm_destroyed); ++ g_assert_no_error (subdata->error); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ g_assert_false (data->completed); ++ g_assert_false (data->ssm_destroyed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_subssm_mark_failed (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ g_autoptr(FpiSsm) subssm = ++ ssm_test_new_full (FPI_TEST_SSM_STATE_NUM, "FPI_TEST_SUB_SSM"); ++ g_autoptr(FpiSsmTestData) data = ++ fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm)); ++ g_autoptr(FpiSsmTestData) subdata = ++ fpi_ssm_test_data_ref (fpi_ssm_get_data (subssm)); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_start_subsm (g_steal_pointer (&ssm), subssm); ++ g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (subssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 1); ++ ++ data->expected_last_state = FPI_TEST_SSM_STATE_0; ++ subdata->expected_last_state = FPI_TEST_SSM_STATE_0; ++ fpi_ssm_mark_failed (g_steal_pointer (&subssm), ++ fpi_device_error_new (FP_DEVICE_ERROR_BUSY)); ++ ++ g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 1); ++ g_assert_true (subdata->ssm_destroyed); ++ g_assert_no_error (subdata->error); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ g_assert_true (data->completed); ++ g_assert_true (data->ssm_destroyed); ++ g_assert_error (data->error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_BUSY); ++} ++ ++static void ++test_ssm_subssm_start_with_started (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ g_autoptr(FpiSsm) subssm = ++ ssm_test_new_full (FPI_TEST_SSM_STATE_NUM, "FPI_TEST_SUB_SSM"); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ g_autoptr(FpiSsmTestData) subdata = ++ fpi_ssm_test_data_ref (fpi_ssm_get_data (subssm)); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_start (subssm, test_ssm_completed_callback); ++ g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 1); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*"); ++ fpi_ssm_start_subsm (ssm, subssm); ++ g_test_assert_expected_messages (); ++ ++ g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (subssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 2); ++ ++ subdata->expected_last_state = FPI_TEST_SSM_STATE_0; ++ fpi_ssm_mark_completed (g_steal_pointer (&subssm)); ++ ++ g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 2); ++ g_assert_true (subdata->ssm_destroyed); ++ g_assert_no_error (subdata->error); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ g_assert_false (data->completed); ++ g_assert_false (data->ssm_destroyed); ++ g_assert_no_error (data->error); ++} ++ ++static void ++test_ssm_subssm_start_with_delayed (void) ++{ ++ g_autoptr(FpiSsm) ssm = ssm_test_new (); ++ g_autoptr(FpiSsm) subssm = ++ ssm_test_new_full (FPI_TEST_SSM_STATE_NUM, "FPI_TEST_SUB_SSM"); ++ FpiSsmTestData *data = fpi_ssm_get_data (ssm); ++ g_autoptr(FpiSsmTestData) subdata = ++ fpi_ssm_test_data_ref (fpi_ssm_get_data (subssm)); ++ gpointer timeout_tracker = GUINT_TO_POINTER (TRUE); ++ ++ fpi_ssm_start (ssm, test_ssm_completed_callback); ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); ++ ++ fpi_ssm_next_state_delayed (ssm, 10, NULL); ++ ++ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*"); ++ fpi_ssm_start_subsm (ssm, subssm); ++ g_test_assert_expected_messages (); ++ ++ g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker); ++ while (timeout_tracker) ++ g_main_context_iteration (NULL, TRUE); ++ ++ g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpint (fpi_ssm_get_cur_state (subssm), ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 1); ++ ++ subdata->expected_last_state = FPI_TEST_SSM_STATE_0; ++ fpi_ssm_mark_completed (g_steal_pointer (&subssm)); ++ ++ g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_0); ++ g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 1); ++ g_assert_true (subdata->ssm_destroyed); ++ g_assert_no_error (subdata->error); ++ ++ g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1); ++ g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2); ++ ++ g_assert_false (data->completed); ++ g_assert_false (data->ssm_destroyed); ++ g_assert_no_error (data->error); ++} ++ ++int ++main (int argc, char *argv[]) ++{ ++ g_autoptr(FpDevice) device = NULL; ++ ++ g_test_init (&argc, &argv, NULL); ++ ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); ++ fake_device = device; ++ g_object_add_weak_pointer (G_OBJECT (device), (gpointer) & fake_device); ++ ++ g_test_add_func ("/ssm/new", test_ssm_new); ++ g_test_add_func ("/ssm/new/full", test_ssm_new_full); ++ g_test_add_func ("/ssm/new/no_handler", test_ssm_new_no_handler); ++ g_test_add_func ("/ssm/new/wrong_states", test_ssm_new_wrong_states); ++ g_test_add_func ("/ssm/set_data", test_ssm_set_data); ++ g_test_add_func ("/ssm/set_data/cleanup", test_ssm_set_data_cleanup); ++ g_test_add_func ("/ssm/start", test_ssm_start); ++ g_test_add_func ("/ssm/start/single", test_ssm_start_single); ++ g_test_add_func ("/ssm/next", test_ssm_next); ++ g_test_add_func ("/ssm/next/complete", test_ssm_next_complete); ++ g_test_add_func ("/ssm/next/not_started", test_ssm_next_not_started); ++ g_test_add_func ("/ssm/next/with_delayed", test_ssm_next_with_delayed); ++ g_test_add_func ("/ssm/jump_to_state", test_ssm_jump_to_state); ++ g_test_add_func ("/ssm/jump_to_state/not_started", test_ssm_jump_to_state_not_started); ++ g_test_add_func ("/ssm/jump_to_state/with_delayed", test_ssm_jump_to_state_with_delayed); ++ g_test_add_func ("/ssm/jump_to_state/last", test_ssm_jump_to_state_last); ++ g_test_add_func ("/ssm/jump_to_state/wrong", test_ssm_jump_to_state_wrong); ++ g_test_add_func ("/ssm/mark_completed", test_ssm_mark_completed); ++ g_test_add_func ("/ssm/mark_completed/not_started", test_ssm_mark_completed_not_started); ++ g_test_add_func ("/ssm/mark_completed/with_delayed", test_ssm_mark_completed_with_delayed); ++ g_test_add_func ("/ssm/mark_failed", test_ssm_mark_failed); ++ g_test_add_func ("/ssm/mark_failed/not_started", test_ssm_mark_failed_not_started); ++ g_test_add_func ("/ssm/mark_failed/with_delayed", test_ssm_mark_failed_with_delayed); ++ g_test_add_func ("/ssm/delayed/next", test_ssm_delayed_next); ++ g_test_add_func ("/ssm/delayed/next/cancel", test_ssm_delayed_next_cancel); ++ g_test_add_func ("/ssm/delayed/next/cancellable", test_ssm_delayed_next_cancellable); ++ g_test_add_func ("/ssm/delayed/next/not_started", test_ssm_delayed_next_not_started); ++ g_test_add_func ("/ssm/delayed/next/complete", test_ssm_delayed_next_complete); ++ g_test_add_func ("/ssm/delayed/jump_to_state", test_ssm_delayed_jump_to_state); ++ g_test_add_func ("/ssm/delayed/jump_to_state/cancel", test_ssm_delayed_jump_to_state_cancel); ++ g_test_add_func ("/ssm/delayed/jump_to_state/cancellable", test_ssm_delayed_jump_to_state_cancellable); ++ g_test_add_func ("/ssm/delayed/jump_to_state/not_started", test_ssm_delayed_jump_to_state_not_started); ++ g_test_add_func ("/ssm/delayed/jump_to_state/last", test_ssm_delayed_jump_to_state_last); ++ g_test_add_func ("/ssm/delayed/jump_to_state/wrong", test_ssm_delayed_jump_to_state_wrong); ++ g_test_add_func ("/ssm/delayed/mark_completed", test_ssm_delayed_mark_completed); ++ g_test_add_func ("/ssm/delayed/mark_completed/cancel", test_ssm_delayed_mark_completed_cancel); ++ g_test_add_func ("/ssm/delayed/mark_completed/cancellable", test_ssm_delayed_mark_completed_cancellable); ++ g_test_add_func ("/ssm/delayed/mark_completed/not_started", test_ssm_delayed_mark_completed_not_started); ++ g_test_add_func ("/ssm/delayed/cancel/error", test_ssm_delayed_cancel_error); ++ g_test_add_func ("/ssm/subssm/start", test_ssm_subssm_start); ++ g_test_add_func ("/ssm/subssm/start/with_started", test_ssm_subssm_start_with_started); ++ g_test_add_func ("/ssm/subssm/start/with_delayed", test_ssm_subssm_start_with_delayed); ++ g_test_add_func ("/ssm/subssm/mark_failed", test_ssm_subssm_mark_failed); ++ ++ return g_test_run (); ++} +-- +2.24.1 + diff --git a/SOURCES/0129-meson-Split-single-line-dependencies-to-reduce-the-d.patch b/SOURCES/0129-meson-Split-single-line-dependencies-to-reduce-the-d.patch new file mode 100644 index 0000000..d7a20b7 --- /dev/null +++ b/SOURCES/0129-meson-Split-single-line-dependencies-to-reduce-the-d.patch @@ -0,0 +1,76 @@ +From ff490a0222987dcb5a618d7ea73743289ba56ec1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 13 Dec 2019 19:33:12 +0100 +Subject: [PATCH 129/181] meson: Split single-line dependencies to reduce the + diff on changes + +Make it more readable and in case we add something else, it's easier to track +--- + demo/meson.build | 5 ++++- + examples/meson.build | 5 ++++- + libfprint/meson.build | 11 +++++++++-- + 3 files changed, 17 insertions(+), 4 deletions(-) + +diff --git a/demo/meson.build b/demo/meson.build +index 20f8962..68d865f 100644 +--- a/demo/meson.build ++++ b/demo/meson.build +@@ -9,7 +9,10 @@ datadir = join_paths(prefix, get_option('datadir')) + + executable('gtk-libfprint-test', + [ 'gtk-libfprint-test.c', gtk_test_resources ], +- dependencies: [ libfprint_dep, gtk_dep ], ++ dependencies: [ ++ gtk_dep, ++ libfprint_dep, ++ ], + c_args: '-DPACKAGE_VERSION="' + meson.project_version() + '"', + install: true, + install_dir: bindir) +diff --git a/examples/meson.build b/examples/meson.build +index 7b313d0..90a1178 100644 +--- a/examples/meson.build ++++ b/examples/meson.build +@@ -3,7 +3,10 @@ examples = [ 'enroll', 'verify', 'manage-prints' ] + foreach example: examples + executable(example, + [ example + '.c', 'storage.c', 'utilities.c' ], +- dependencies: [ libfprint_dep, glib_dep ], ++ dependencies: [ ++ libfprint_dep, ++ glib_dep, ++ ], + ) + endforeach + +diff --git a/libfprint/meson.build b/libfprint/meson.build +index 06668b3..61fd506 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -233,14 +233,21 @@ libfprint = library('fprint', + libfprint_dep = declare_dependency(link_with: libfprint, + sources: [ fp_enums_h ], + include_directories: root_inc, +- dependencies: [ glib_dep, gusb_dep, gio_dep ]) ++ dependencies: [ ++ gio_dep, ++ glib_dep, ++ gusb_dep, ++ ]) + + install_headers(['fprint.h'] + libfprint_public_headers, subdir: 'libfprint') + + libfprint_private_dep = declare_dependency( + include_directories: include_directories('.'), + link_with: libfprint_private, +- dependencies: [ deps, libfprint_dep ] ++ dependencies: [ ++ deps, ++ libfprint_dep, ++ ] + ) + + udev_rules = executable('fprint-list-udev-rules', +-- +2.24.1 + diff --git a/SOURCES/0130-driver_ids.h-Remove-the-legacy-ID-file.patch b/SOURCES/0130-driver_ids.h-Remove-the-legacy-ID-file.patch new file mode 100644 index 0000000..3109a54 --- /dev/null +++ b/SOURCES/0130-driver_ids.h-Remove-the-legacy-ID-file.patch @@ -0,0 +1,81 @@ +From d52dd93759b6e888e7286008fb7d82a6020aebad Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Fri, 13 Dec 2019 21:31:43 +0100 +Subject: [PATCH 130/181] driver_ids.h: Remove the legacy ID file + +This is not used anymore by drivers as they all use GType's, so remove it +and any (dead) reference to it. +--- + libfprint/drivers/driver_ids.h | 47 ---------------------------------- + libfprint/drivers/etes603.c | 1 - + 2 files changed, 48 deletions(-) + delete mode 100644 libfprint/drivers/driver_ids.h + +diff --git a/libfprint/drivers/driver_ids.h b/libfprint/drivers/driver_ids.h +deleted file mode 100644 +index 4270842..0000000 +--- a/libfprint/drivers/driver_ids.h ++++ /dev/null +@@ -1,47 +0,0 @@ +-/* +- * Driver IDs +- * Copyright (C) 2012 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 +- */ +- +-#ifndef __DRIVER_IDS +-#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, +-}; +- +-#endif +diff --git a/libfprint/drivers/etes603.c b/libfprint/drivers/etes603.c +index 5cd7f0b..f798f5b 100644 +--- a/libfprint/drivers/etes603.c ++++ b/libfprint/drivers/etes603.c +@@ -36,7 +36,6 @@ + #define FP_COMPONENT "etes603" + + #include "drivers_api.h" +-#include "driver_ids.h" + + /* libusb defines */ + #define EP_IN 0x81 +-- +2.24.1 + diff --git a/SOURCES/0131-synaptics-Use-local-variable-rather-than-re-fetching.patch b/SOURCES/0131-synaptics-Use-local-variable-rather-than-re-fetching.patch new file mode 100644 index 0000000..706a0dc --- /dev/null +++ b/SOURCES/0131-synaptics-Use-local-variable-rather-than-re-fetching.patch @@ -0,0 +1,30 @@ +From a5db936b44fbfbb9e38a156f05f0b53d7125dad4 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Thu, 5 Dec 2019 15:48:57 +0100 +Subject: [PATCH 131/181] synaptics: Use local variable rather than re-fetching + usb device + +--- + libfprint/drivers/synaptics/synaptics.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c +index 6ed6791..97d9d21 100644 +--- a/libfprint/drivers/synaptics/synaptics.c ++++ b/libfprint/drivers/synaptics/synaptics.c +@@ -969,10 +969,10 @@ dev_probe (FpDevice *device) + return; + } + +- if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error)) ++ if (!g_usb_device_reset (usb_dev, &error)) + goto err_close; + +- if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error)) ++ if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error)) + goto err_close; + + /* TODO: Do not do this synchronous. */ +-- +2.24.1 + diff --git a/SOURCES/0132-tests-Ensure-objects-are-free-ed-at-the-end-of-tests.patch b/SOURCES/0132-tests-Ensure-objects-are-free-ed-at-the-end-of-tests.patch new file mode 100644 index 0000000..27a56cc --- /dev/null +++ b/SOURCES/0132-tests-Ensure-objects-are-free-ed-at-the-end-of-tests.patch @@ -0,0 +1,69 @@ +From 46f83b800ceb31696ebe69246c9cb5c2b243f866 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Thu, 5 Dec 2019 15:49:43 +0100 +Subject: [PATCH 132/181] tests: Ensure objects are free'ed at the end of tests + +The objects may not be garbage collected otherwise. +--- + tests/capture.py | 4 ++++ + tests/synaptics/custom.py | 4 ++++ + tests/virtual-image.py | 2 ++ + 3 files changed, 10 insertions(+) + +diff --git a/tests/capture.py b/tests/capture.py +index a7b7583..88ed81f 100755 +--- a/tests/capture.py ++++ b/tests/capture.py +@@ -17,6 +17,7 @@ c.enumerate() + devices = c.get_devices() + + d = devices[0] ++del devices + + d.open_sync() + +@@ -24,6 +25,9 @@ img = d.capture_sync(True) + + d.close_sync() + ++del d ++del c ++ + width = img.get_width() + height = img.get_height() + +diff --git a/tests/synaptics/custom.py b/tests/synaptics/custom.py +index 6016799..b0f1c54 100755 +--- a/tests/synaptics/custom.py ++++ b/tests/synaptics/custom.py +@@ -11,6 +11,7 @@ c.enumerate() + devices = c.get_devices() + + d = devices[0] ++del devices + + assert d.get_driver() == "synaptics" + +@@ -40,3 +41,6 @@ print("deleting") + d.delete_print_sync(p) + print("delete done") + d.close_sync() ++ ++del d ++del c +diff --git a/tests/virtual-image.py b/tests/virtual-image.py +index 87c221b..11ec8ae 100755 +--- a/tests/virtual-image.py ++++ b/tests/virtual-image.py +@@ -83,6 +83,8 @@ class VirtualImage(unittest.TestCase): + @classmethod + def tearDownClass(cls): + shutil.rmtree(cls.tmpdir) ++ del cls.dev ++ del cls.ctx + + def setUp(self): + self.dev.open_sync() +-- +2.24.1 + diff --git a/SOURCES/0133-examples-Fix-double-device-closing-in-manage-prints.patch b/SOURCES/0133-examples-Fix-double-device-closing-in-manage-prints.patch new file mode 100644 index 0000000..160cfc1 --- /dev/null +++ b/SOURCES/0133-examples-Fix-double-device-closing-in-manage-prints.patch @@ -0,0 +1,30 @@ +From 4025c8ce6a4eba38e2e61eda342c17ea8beb9064 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Thu, 5 Dec 2019 17:28:47 +0100 +Subject: [PATCH 133/181] examples: Fix double device closing in manage-prints + +The manage-prints command would close the device twice when the user +hits an invalid number or 'n' and no prints need to be deleted. + +Simply remove the erroneous call to fix the issue. +--- + examples/manage-prints.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/examples/manage-prints.c b/examples/manage-prints.c +index 7bbbc5e..d64b5fa 100644 +--- a/examples/manage-prints.c ++++ b/examples/manage-prints.c +@@ -197,9 +197,6 @@ on_list_completed (FpDevice *dev, + list_data->ret_value = EXIT_SUCCESS; + else + g_warning ("Invalid finger selected"); +- +- fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, +- list_data); + } + } + +-- +2.24.1 + diff --git a/SOURCES/0134-elan-Do-not-leak-converted-frames.patch b/SOURCES/0134-elan-Do-not-leak-converted-frames.patch new file mode 100644 index 0000000..1e3f280 --- /dev/null +++ b/SOURCES/0134-elan-Do-not-leak-converted-frames.patch @@ -0,0 +1,29 @@ +From 13b89d8d01b9c0eaa83663d66f0955263966cd6c Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Fri, 6 Dec 2019 16:30:34 +0100 +Subject: [PATCH 134/181] elan: Do not leak converted frames + +The elan driver converts frames into a different format. These frames +are only needed to assemable the image and should be free'ed afterwards. + +Fixes: #213 +--- + libfprint/drivers/elan.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c +index 9495a48..415aaef 100644 +--- a/libfprint/drivers/elan.c ++++ b/libfprint/drivers/elan.c +@@ -321,6 +321,8 @@ elan_submit_image (FpImageDevice *dev) + fpi_do_movement_estimation (&assembling_ctx, frames); + img = fpi_assemble_frames (&assembling_ctx, frames); + ++ g_slist_free_full (frames, g_free); ++ + fpi_image_device_image_captured (dev, img); + } + +-- +2.24.1 + diff --git a/SOURCES/0135-meson-Add-missing-dependency-on-fp-enum.h-for-privat.patch b/SOURCES/0135-meson-Add-missing-dependency-on-fp-enum.h-for-privat.patch new file mode 100644 index 0000000..4f05b8c --- /dev/null +++ b/SOURCES/0135-meson-Add-missing-dependency-on-fp-enum.h-for-privat.patch @@ -0,0 +1,29 @@ +From e0c50ecb84490fdc37e1501be018a332f27166d8 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 16 Dec 2019 11:36:28 +0100 +Subject: [PATCH 135/181] meson: Add missing dependency on fp-enum.h for + private library + +The private library needs to indirectly include fp-enum.h. This +dependency was not listed anyway, resulting in a race condition during +the build process. +--- + libfprint/meson.build | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libfprint/meson.build b/libfprint/meson.build +index 61fd506..74908f4 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -205,7 +205,7 @@ libnbis = static_library('nbis', + install: false) + + libfprint_private = static_library('fprint-private', +- sources: libfprint_private_sources + fpi_enums, ++ sources: libfprint_private_sources + fpi_enums + [ fp_enums_h ], + dependencies: deps, + link_with: libnbis, + install: false) +-- +2.24.1 + diff --git a/SOURCES/0136-tests-Fix-stack-corruption-in-FpiSsm-test.patch b/SOURCES/0136-tests-Fix-stack-corruption-in-FpiSsm-test.patch new file mode 100644 index 0000000..5545bdc --- /dev/null +++ b/SOURCES/0136-tests-Fix-stack-corruption-in-FpiSsm-test.patch @@ -0,0 +1,114 @@ +From a19d2d71acee72ce21cf2722c909c10973e9e963 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Tue, 17 Dec 2019 14:23:54 +0100 +Subject: [PATCH 136/181] tests: Fix stack corruption in FpiSsm test + +Using a function with a void return value for a g_timeout_add is not a +good idea after all. +--- + tests/test-fpi-ssm.c | 26 +++++++++++++++++--------- + 1 file changed, 17 insertions(+), 9 deletions(-) + +diff --git a/tests/test-fpi-ssm.c b/tests/test-fpi-ssm.c +index a3bd9da..07e28c0 100644 +--- a/tests/test-fpi-ssm.c ++++ b/tests/test-fpi-ssm.c +@@ -39,6 +39,14 @@ typedef struct + gboolean expected_last_state; + } FpiSsmTestData; + ++static gboolean ++fpi_ssm_test_nullify_pointer (gpointer * nullify_location) ++{ ++ *nullify_location = NULL; ++ ++ return G_SOURCE_REMOVE; ++} ++ + static FpiSsmTestData * + fpi_ssm_test_data_new (void) + { +@@ -334,7 +342,7 @@ test_ssm_next_with_delayed (void) + fpi_ssm_next_state (ssm); + g_test_assert_expected_messages (); + +- g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker); ++ g_timeout_add (100, G_SOURCE_FUNC (fpi_ssm_test_nullify_pointer), &timeout_tracker); + while (timeout_tracker) + g_main_context_iteration (NULL, TRUE); + +@@ -442,7 +450,7 @@ test_ssm_jump_to_state_with_delayed (void) + fpi_ssm_jump_to_state (ssm, FPI_TEST_SSM_STATE_2); + g_test_assert_expected_messages (); + +- g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker); ++ g_timeout_add (100, G_SOURCE_FUNC (fpi_ssm_test_nullify_pointer), &timeout_tracker); + while (timeout_tracker) + g_main_context_iteration (NULL, TRUE); + +@@ -559,7 +567,7 @@ test_ssm_mark_completed_with_delayed (void) + fpi_ssm_mark_completed (g_steal_pointer (&ssm)); + g_test_assert_expected_messages (); + +- g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker); ++ g_timeout_add (100, G_SOURCE_FUNC (fpi_ssm_test_nullify_pointer), &timeout_tracker); + while (timeout_tracker) + g_main_context_iteration (NULL, TRUE); + +@@ -623,7 +631,7 @@ test_ssm_mark_failed_with_delayed (void) + fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + g_test_assert_expected_messages (); + +- g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker); ++ g_timeout_add (100, G_SOURCE_FUNC (fpi_ssm_test_nullify_pointer), &timeout_tracker); + while (timeout_tracker) + g_main_context_iteration (NULL, TRUE); + +@@ -680,7 +688,7 @@ test_ssm_delayed_next_cancel (void) + g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); + + g_idle_add_full (G_PRIORITY_HIGH, test_ssm_cancel_delayed_action_delayed, ssm, NULL); +- g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker); ++ g_timeout_add (100, G_SOURCE_FUNC (fpi_ssm_test_nullify_pointer), &timeout_tracker); + + while (timeout_tracker) + g_main_context_iteration (NULL, TRUE); +@@ -875,7 +883,7 @@ test_ssm_delayed_jump_to_state_cancel (void) + g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); + + g_idle_add_full (G_PRIORITY_HIGH, test_ssm_cancel_delayed_action_delayed, ssm, NULL); +- g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker); ++ g_timeout_add (100, G_SOURCE_FUNC (fpi_ssm_test_nullify_pointer), &timeout_tracker); + + while (timeout_tracker) + g_main_context_iteration (NULL, TRUE); +@@ -1058,7 +1066,7 @@ test_ssm_delayed_mark_completed_not_started (void) + fpi_ssm_mark_completed_delayed (ssm, 10, NULL); + g_test_assert_expected_messages (); + +- g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &ssm); ++ g_timeout_add (100, G_SOURCE_FUNC (fpi_ssm_test_nullify_pointer), &ssm); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*"); + while (ssm != NULL) +@@ -1088,7 +1096,7 @@ test_ssm_delayed_mark_completed_cancel (void) + g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1); + + g_idle_add_full (G_PRIORITY_HIGH, test_ssm_cancel_delayed_action_delayed, ssm, NULL); +- g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker); ++ g_timeout_add (100, G_SOURCE_FUNC (fpi_ssm_test_nullify_pointer), &timeout_tracker); + + while (timeout_tracker) + g_main_context_iteration (NULL, TRUE); +@@ -1312,7 +1320,7 @@ test_ssm_subssm_start_with_delayed (void) + fpi_ssm_start_subsm (ssm, subssm); + g_test_assert_expected_messages (); + +- g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker); ++ g_timeout_add (100, G_SOURCE_FUNC (fpi_ssm_test_nullify_pointer), &timeout_tracker); + while (timeout_tracker) + g_main_context_iteration (NULL, TRUE); + +-- +2.24.1 + diff --git a/SOURCES/0137-fpi-ssm-fpi-usb-transfer-Use-fwd-declarations-to-avo.patch b/SOURCES/0137-fpi-ssm-fpi-usb-transfer-Use-fwd-declarations-to-avo.patch new file mode 100644 index 0000000..96de9e6 --- /dev/null +++ b/SOURCES/0137-fpi-ssm-fpi-usb-transfer-Use-fwd-declarations-to-avo.patch @@ -0,0 +1,52 @@ +From 61ad30dc8b3c1a86728808f8e978dd05f834cdcc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 16 Dec 2019 19:44:17 +0100 +Subject: [PATCH 137/181] fpi-ssm, fpi-usb-transfer: Use fwd-declarations to + avoid headers dependencies + +Don't make headers inclusions dependent on each others, given that FpiSsm +depends on FpiUsbTransfer and vice-versa, so fix the dependency cycle by +using forwarded declarations. +--- + libfprint/fpi-ssm.h | 3 ++- + libfprint/fpi-usb-transfer.h | 3 +-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libfprint/fpi-ssm.h b/libfprint/fpi-ssm.h +index fe64946..0e18ab6 100644 +--- a/libfprint/fpi-ssm.h ++++ b/libfprint/fpi-ssm.h +@@ -22,7 +22,6 @@ + #pragma once + + #include "fp-device.h" +-#include "fpi-usb-transfer.h" + + /* async drv <--> lib comms */ + +@@ -101,6 +100,8 @@ int fpi_ssm_get_cur_state (FpiSsm *machine); + /* Callbacks to be used by the driver instead of implementing their own + * logic. + */ ++typedef struct _FpiUsbTransfer FpiUsbTransfer; ++ + void fpi_ssm_usb_transfer_cb (FpiUsbTransfer *transfer, + FpDevice *device, + gpointer unused_data, +diff --git a/libfprint/fpi-usb-transfer.h b/libfprint/fpi-usb-transfer.h +index 5b8fe9c..09d22e8 100644 +--- a/libfprint/fpi-usb-transfer.h ++++ b/libfprint/fpi-usb-transfer.h +@@ -30,8 +30,7 @@ G_BEGIN_DECLS + #define FPI_USB_ENDPOINT_OUT 0x00 + + typedef struct _FpiUsbTransfer FpiUsbTransfer; +- +-#include "fpi-ssm.h" ++typedef struct _FpiSsm FpiSsm; + + typedef void (*FpiUsbTransferCallback)(FpiUsbTransfer *transfer, + FpDevice *dev, +-- +2.24.1 + diff --git a/SOURCES/0138-meson-Parse-all-private-headers.patch b/SOURCES/0138-meson-Parse-all-private-headers.patch new file mode 100644 index 0000000..f41e677 --- /dev/null +++ b/SOURCES/0138-meson-Parse-all-private-headers.patch @@ -0,0 +1,59 @@ +From 06a58d71dcef5265d37539128b2beef006599706 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 16 Dec 2019 18:07:30 +0100 +Subject: [PATCH 138/181] meson: Parse all private headers + +So we don't have to list each one in case we add new enums. +Also, as per previous commit we can reorder them alphabetically. +--- + libfprint/meson.build | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +diff --git a/libfprint/meson.build b/libfprint/meson.build +index 74908f4..781ea81 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -8,14 +8,14 @@ libfprint_sources = [ + + libfprint_private_sources = [ + 'fpi-assembling.c', ++ 'fpi-byte-reader.c', ++ 'fpi-byte-writer.c', + 'fpi-device.c', +- 'fpi-image.c', + 'fpi-image-device.c', ++ 'fpi-image.c', + 'fpi-print.c', + 'fpi-ssm.c', + 'fpi-usb-transfer.c', +- 'fpi-byte-reader.c', +- 'fpi-byte-writer.c', + ] + + libfprint_public_headers = [ +@@ -27,13 +27,18 @@ libfprint_public_headers = [ + + libfprint_private_headers = [ + 'fpi-assembling.h', ++ 'fpi-byte-reader.h', ++ 'fpi-byte-utils.h', ++ 'fpi-byte-writer.h', ++ 'fpi-context.h', + 'fpi-device.h', +- 'fpi-image.h', + 'fpi-image-device.h', ++ 'fpi-image.h', ++ 'fpi-log.h', ++ 'fpi-minutiae.h', + 'fpi-print.h', +- 'fpi-byte-reader.h', +- 'fpi-byte-writer.h', +- 'fpi-byte-utils.h', ++ 'fpi-usb-transfer.h', ++ 'fpi-ssm.h', + ] + + nbis_sources = [ +-- +2.24.1 + diff --git a/SOURCES/0139-meson-List-deps-in-multiple-lines-to-have-better-dif.patch b/SOURCES/0139-meson-List-deps-in-multiple-lines-to-have-better-dif.patch new file mode 100644 index 0000000..c53e385 --- /dev/null +++ b/SOURCES/0139-meson-List-deps-in-multiple-lines-to-have-better-dif.patch @@ -0,0 +1,33 @@ +From 42b6ce90764b2d9fd18072b8307c2bd200ab54b6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 16 Dec 2019 18:46:07 +0100 +Subject: [PATCH 139/181] meson: List deps in multiple lines, to have better + diffs on changes + +--- + libfprint/meson.build | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/libfprint/meson.build b/libfprint/meson.build +index 781ea81..a693f80 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -191,7 +191,14 @@ drivers_sources += configure_file(input: 'empty_file', + '\n'.join(drivers_type_list + [] + drivers_type_func) + ]) + +-deps = [ mathlib_dep, glib_dep, gusb_dep, nss_dep, imaging_dep, gio_dep ] ++deps = [ ++ gio_dep, ++ glib_dep, ++ gusb_dep, ++ imaging_dep, ++ mathlib_dep, ++ nss_dep, ++] + + deps += declare_dependency(include_directories: [ + root_inc, +-- +2.24.1 + diff --git a/SOURCES/0140-meson-No-need-to-redefine-default-pkgconfig-install-.patch b/SOURCES/0140-meson-No-need-to-redefine-default-pkgconfig-install-.patch new file mode 100644 index 0000000..5b5570f --- /dev/null +++ b/SOURCES/0140-meson-No-need-to-redefine-default-pkgconfig-install-.patch @@ -0,0 +1,24 @@ +From b80ab222218642010e5afb0d5617412a80303e3e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 16 Dec 2019 18:52:46 +0100 +Subject: [PATCH 140/181] meson: No need to redefine default pkgconfig install + dir + +This value would be the default anyways +--- + meson.build | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/meson.build b/meson.build +index 8ea4a8b..1d101a7 100644 +--- a/meson.build ++++ b/meson.build +@@ -209,4 +209,4 @@ pkgconfig.generate( + libraries: libfprint, + subdirs: 'libfprint', + filebase: 'libfprint2', +- install_dir: join_paths(get_option('libdir'), 'pkgconfig')) ++) +-- +2.24.1 + diff --git a/SOURCES/0141-meson-Don-t-install-fpi-enums.patch b/SOURCES/0141-meson-Don-t-install-fpi-enums.patch new file mode 100644 index 0000000..5eca98d --- /dev/null +++ b/SOURCES/0141-meson-Don-t-install-fpi-enums.patch @@ -0,0 +1,25 @@ +From 060f804790dfd8dd678d64edf9d9cf2d1c0c2345 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 16 Dec 2019 19:00:36 +0100 +Subject: [PATCH 141/181] meson: Don't install fpi-enums + +--- + libfprint/meson.build | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libfprint/meson.build b/libfprint/meson.build +index a693f80..23ab60a 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -180,7 +180,7 @@ fp_enums_h = fp_enums[1] + + fpi_enums = gnome.mkenums_simple('fpi-enums', + sources: libfprint_private_headers, +- install_header : true) ++ install_header : false) + fpi_enums_h = fpi_enums[1] + + drivers_sources += configure_file(input: 'empty_file', +-- +2.24.1 + diff --git a/SOURCES/0142-meson-Use-more-meson-s-project_name.patch b/SOURCES/0142-meson-Use-more-meson-s-project_name.patch new file mode 100644 index 0000000..45dbac7 --- /dev/null +++ b/SOURCES/0142-meson-Use-more-meson-s-project_name.patch @@ -0,0 +1,79 @@ +From 73b62b67c55639f4184f2c2de228b68f21093768 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 16 Dec 2019 19:02:00 +0100 +Subject: [PATCH 142/181] meson: Use more meson's project_name() + +Not that libfprint is long to write, but in case we'll ever change the +basename, we do it once. +--- + doc/meson.build | 2 +- + doc/xml/meson.build | 6 +++--- + libfprint/meson.build | 4 +++- + meson.build | 6 +++--- + 4 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/doc/meson.build b/doc/meson.build +index bed320d..2c7a384 100644 +--- a/doc/meson.build ++++ b/doc/meson.build +@@ -24,7 +24,7 @@ glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix') + glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html') + docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html') + +-gnome.gtkdoc('libfprint', ++gnome.gtkdoc(meson.project_name(), + main_xml: 'libfprint-docs.xml', + src_dir: join_paths(meson.source_root(), 'libfprint'), + dependencies: libfprint_dep, +diff --git a/doc/xml/meson.build b/doc/xml/meson.build +index 2ca1100..5e56bb4 100644 +--- a/doc/xml/meson.build ++++ b/doc/xml/meson.build +@@ -1,8 +1,8 @@ + ent_conf = configuration_data() +-ent_conf.set('PACKAGE', 'libfprint') ++ent_conf.set('PACKAGE', meson.project_name()) + ent_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.freedesktop.org/libfprint/libfprint/issues') +-ent_conf.set('PACKAGE_NAME', 'libfprint') +-ent_conf.set('PACKAGE_STRING', 'libfprint') ++ent_conf.set('PACKAGE_NAME', meson.project_name()) ++ent_conf.set('PACKAGE_STRING', meson.project_name()) + ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version()) + ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/') + ent_conf.set('PACKAGE_VERSION', meson.project_version()) +diff --git a/libfprint/meson.build b/libfprint/meson.build +index 23ab60a..210e45c 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -251,7 +251,9 @@ libfprint_dep = declare_dependency(link_with: libfprint, + gusb_dep, + ]) + +-install_headers(['fprint.h'] + libfprint_public_headers, subdir: 'libfprint') ++install_headers(['fprint.h'] + libfprint_public_headers, ++ subdir: meson.project_name() ++) + + libfprint_private_dep = declare_dependency( + include_directories: include_directories('.'), +diff --git a/meson.build b/meson.build +index 1d101a7..29bdff5 100644 +--- a/meson.build ++++ b/meson.build +@@ -203,10 +203,10 @@ subdir('tests') + + pkgconfig = import('pkgconfig') + pkgconfig.generate( +- name: 'libfprint', ++ name: meson.project_name(), + description: 'Generic C API for fingerprint reader access', + version: meson.project_version(), + libraries: libfprint, +- subdirs: 'libfprint', +- filebase: 'libfprint2', ++ subdirs: meson.project_name(), ++ filebase: meson.project_name() + '2', + ) +-- +2.24.1 + diff --git a/SOURCES/0143-meson-Use-soversion-everywhere.patch b/SOURCES/0143-meson-Use-soversion-everywhere.patch new file mode 100644 index 0000000..5134632 --- /dev/null +++ b/SOURCES/0143-meson-Use-soversion-everywhere.patch @@ -0,0 +1,39 @@ +From 1fb15d4dc57bab6a34bfe6de0c9717809a9e4dfd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 16 Dec 2019 19:05:35 +0100 +Subject: [PATCH 143/181] meson: Use soversion everywhere + +Don't repeat the 2 version number hard-coding it, so we can easily track +updates +--- + 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 210e45c..8132a1b 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -293,7 +293,7 @@ if get_option('introspection') + libfprint_public_headers, + libfprint_sources, + ], +- nsversion : '2.0', ++ nsversion : '@0@.0'.format(soversion), + namespace : 'FPrint', + symbol_prefix : 'fp_', + identifier_prefix : 'Fp', +diff --git a/meson.build b/meson.build +index 29bdff5..afd98db 100644 +--- a/meson.build ++++ b/meson.build +@@ -208,5 +208,5 @@ pkgconfig.generate( + version: meson.project_version(), + libraries: libfprint, + subdirs: meson.project_name(), +- filebase: meson.project_name() + '2', ++ filebase: meson.project_name() + '@0@'.format(soversion), + ) +-- +2.24.1 + diff --git a/SOURCES/0144-meson-Add-fp-image-device-to-public-headers.patch b/SOURCES/0144-meson-Add-fp-image-device-to-public-headers.patch new file mode 100644 index 0000000..6ed56d5 --- /dev/null +++ b/SOURCES/0144-meson-Add-fp-image-device-to-public-headers.patch @@ -0,0 +1,24 @@ +From 610095fca55204813a1168fd871034aba817cd5e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 17 Dec 2019 05:14:54 +0100 +Subject: [PATCH 144/181] meson: Add fp-image-device to public headers + +--- + libfprint/meson.build | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libfprint/meson.build b/libfprint/meson.build +index 8132a1b..382fe76 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -21,6 +21,7 @@ libfprint_private_sources = [ + libfprint_public_headers = [ + 'fp-context.h', + 'fp-device.h', ++ 'fp-image-device.h', + 'fp-image.h', + 'fp-print.h', + ] +-- +2.24.1 + diff --git a/SOURCES/0145-cleanup-Remove-fp_internal.h-and-update-drivers_api..patch b/SOURCES/0145-cleanup-Remove-fp_internal.h-and-update-drivers_api..patch new file mode 100644 index 0000000..caff136 --- /dev/null +++ b/SOURCES/0145-cleanup-Remove-fp_internal.h-and-update-drivers_api..patch @@ -0,0 +1,128 @@ +From 106cfd6615bedebdfab573bea6f0a8df5e02c499 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 16 Dec 2019 20:37:15 +0100 +Subject: [PATCH 145/181] cleanup: Remove fp_internal.h and update + drivers_api.h + +Remove the uneeded internal API, as we can now include each header directly +if needed, while move the assembling stuff to the drivers API. +--- + doc/meson.build | 1 - + libfprint/drivers/aeslib.c | 4 +--- + libfprint/drivers_api.h | 12 ++++++------ + libfprint/fp_internal.h | 25 ------------------------- + libfprint/fpi-assembling.c | 3 ++- + 5 files changed, 9 insertions(+), 36 deletions(-) + delete mode 100644 libfprint/fp_internal.h + +diff --git a/doc/meson.build b/doc/meson.build +index 2c7a384..e138ea2 100644 +--- a/doc/meson.build ++++ b/doc/meson.build +@@ -4,7 +4,6 @@ private_headers = [ + 'config.h', + 'nbis-helpers.h', + 'fprint.h', +- 'fp_internal.h', + + # Subdirectories to ignore + 'drivers', +diff --git a/libfprint/drivers/aeslib.c b/libfprint/drivers/aeslib.c +index 4839c62..de56c6b 100644 +--- a/libfprint/drivers/aeslib.c ++++ b/libfprint/drivers/aeslib.c +@@ -19,13 +19,11 @@ + + #define FP_COMPONENT "aeslib" + +-#include "fp_internal.h" ++#include "drivers_api.h" + + #include + #include + +-#include "fpi-usb-transfer.h" +-#include "fpi-assembling.h" + #include "aeslib.h" + + #define MAX_REGWRITES_PER_REQUEST 16 +diff --git a/libfprint/drivers_api.h b/libfprint/drivers_api.h +index bb401cd..e8ed900 100644 +--- a/libfprint/drivers_api.h ++++ b/libfprint/drivers_api.h +@@ -2,6 +2,7 @@ + * Driver API definitions + * Copyright (C) 2007-2008 Daniel Drake + * Copyright (C) 2018 Bastien Nocera ++ * 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 +@@ -21,14 +22,13 @@ + #ifndef __DRIVERS_API_H__ + #define __DRIVERS_API_H__ + +-#include +- +-#include "fp_internal.h" +- ++#include "fpi-assembling.h" ++#include "fpi-device.h" ++#include "fpi-image-device.h" ++#include "fpi-image.h" + #include "fpi-log.h" ++#include "fpi-print.h" + #include "fpi-usb-transfer.h" + #include "fpi-ssm.h" +-#include "fpi-assembling.h" +-#include "fpi-image-device.h" + + #endif +diff --git a/libfprint/fp_internal.h b/libfprint/fp_internal.h +deleted file mode 100644 +index 56ada18..0000000 +--- a/libfprint/fp_internal.h ++++ /dev/null +@@ -1,25 +0,0 @@ +-/* +- * Internal/private definitions for libfprint +- * 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 +- */ +- +-#pragma once +- +-#include "fpi-log.h" +-#include "fpi-image.h" +-#include "fpi-image-device.h" +-#include "fpi-minutiae.h" +diff --git a/libfprint/fpi-assembling.c b/libfprint/fpi-assembling.c +index fef08f0..2b55ee3 100644 +--- a/libfprint/fpi-assembling.c ++++ b/libfprint/fpi-assembling.c +@@ -21,7 +21,8 @@ + + #define FP_COMPONENT "assembling" + +-#include "fp_internal.h" ++#include "fpi-log.h" ++#include "fpi-image.h" + + #include + +-- +2.24.1 + diff --git a/SOURCES/0146-cleanup-Use-pragma-once-everywhere.patch b/SOURCES/0146-cleanup-Use-pragma-once-everywhere.patch new file mode 100644 index 0000000..557f9e2 --- /dev/null +++ b/SOURCES/0146-cleanup-Use-pragma-once-everywhere.patch @@ -0,0 +1,470 @@ +From 4a734ad13b63eaa7cdf8205b141be16f36057dce Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 16 Dec 2019 20:50:04 +0100 +Subject: [PATCH 146/181] cleanup: Use #pragma once everywhere + +Remove legacy header guards, and use compiler newer features. +--- + examples/storage.h | 6 +----- + examples/utilities.h | 5 +---- + libfprint/drivers/aes1660.h | 5 +---- + libfprint/drivers/aes2501.h | 5 +---- + libfprint/drivers/aes2550.h | 5 +---- + libfprint/drivers/aes2660.h | 5 +---- + libfprint/drivers/aeslib.h | 5 +---- + libfprint/drivers/elan.h | 5 +---- + libfprint/drivers/synaptics/bmkt.h | 5 +---- + libfprint/drivers/synaptics/bmkt_message.h | 6 +----- + libfprint/drivers/synaptics/bmkt_response.h | 6 +----- + libfprint/drivers/synaptics/sensor.h | 4 +--- + libfprint/drivers/synaptics/synaptics.h | 5 +---- + libfprint/drivers/upektc.h | 5 +---- + libfprint/drivers/upektc_img.h | 5 +---- + libfprint/drivers/vfs5011_proto.h | 5 +---- + libfprint/drivers_api.h | 5 +---- + libfprint/fpi-assembling.h | 5 +---- + libfprint/fpi-byte-reader.h | 5 +---- + libfprint/fpi-byte-utils.h | 5 +---- + libfprint/fpi-byte-writer.h | 5 +---- + libfprint/fpi-log.h | 5 +---- + 22 files changed, 22 insertions(+), 90 deletions(-) + +diff --git a/examples/storage.h b/examples/storage.h +index bcbd009..6c6c220 100644 +--- a/examples/storage.h ++++ b/examples/storage.h +@@ -18,9 +18,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef __STORAGE_H +-#define __STORAGE_H +- ++#pragma once + + int print_data_save (FpPrint *print, + FpFinger finger); +@@ -30,5 +28,3 @@ FpPrint * print_create_template (FpDevice *dev, + FpFinger finger); + gboolean print_image_save (FpPrint *print, + const char *path); +- +-#endif /* __STORAGE_H */ +diff --git a/examples/utilities.h b/examples/utilities.h +index 7e436ac..7efad29 100644 +--- a/examples/utilities.h ++++ b/examples/utilities.h +@@ -18,11 +18,8 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef __UTILITIES_H +-#define __UTILITIES_H ++#pragma once + + FpDevice * discover_device (GPtrArray *devices); + FpFinger finger_chooser (void); + const char * finger_to_string (FpFinger finger); +- +-#endif /* __UTILITIES_H */ +diff --git a/libfprint/drivers/aes1660.h b/libfprint/drivers/aes1660.h +index 55a94e2..18e4e0c 100644 +--- a/libfprint/drivers/aes1660.h ++++ b/libfprint/drivers/aes1660.h +@@ -18,8 +18,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef __AES1660_H +-#define __AES1660_H ++#pragma once + + #define AES1660_FRAME_SIZE 0x244 + +@@ -1986,5 +1985,3 @@ static const unsigned char aes1660_start_imaging_cmd[] = { + 0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0x7f, 0x00, 0x00, 0x14, + 0x49, 0x03, 0x00, 0x20, 0x00, 0xc8 + }; +- +-#endif +diff --git a/libfprint/drivers/aes2501.h b/libfprint/drivers/aes2501.h +index dc802ca..171a672 100644 +--- a/libfprint/drivers/aes2501.h ++++ b/libfprint/drivers/aes2501.h +@@ -19,8 +19,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef __AES2501_H +-#define __AES2501_H ++#pragma once + + enum aes2501_regs { + AES2501_REG_CTRL1 = 0x80, +@@ -172,5 +171,3 @@ enum aes2501_sensor_gain2 { + + #define AES2501_SUM_HIGH_THRESH 1000 + #define AES2501_SUM_LOW_THRESH 700 +- +-#endif /* __AES2501_H */ +diff --git a/libfprint/drivers/aes2550.h b/libfprint/drivers/aes2550.h +index 8e4ca17..5f38660 100644 +--- a/libfprint/drivers/aes2550.h ++++ b/libfprint/drivers/aes2550.h +@@ -17,8 +17,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef __AES2550_H +-#define __AES2550_H ++#pragma once + + /* Registers bits */ + +@@ -110,5 +109,3 @@ enum aes2550_cmds { + #define AES2550_HEARTBEAT_MAGIC 0xdb + + #define AES2550_EP_IN_BUF_SIZE 8192 +- +-#endif +diff --git a/libfprint/drivers/aes2660.h b/libfprint/drivers/aes2660.h +index d59f4be..5427c80 100644 +--- a/libfprint/drivers/aes2660.h ++++ b/libfprint/drivers/aes2660.h +@@ -17,8 +17,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef __AES2660_H +-#define __AES2660_H ++#pragma once + + #define AES2660_FRAME_SIZE 0x354 + +@@ -1960,5 +1959,3 @@ static const unsigned char aes2660_start_imaging_cmd[] = { + 0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0xbf, 0x00, 0x00, 0x18, + 0x49, 0x03, 0x00, 0x20, 0x08, 0xc8 + }; +- +-#endif +diff --git a/libfprint/drivers/aeslib.h b/libfprint/drivers/aeslib.h +index 389b3e5..d3ea370 100644 +--- a/libfprint/drivers/aeslib.h ++++ b/libfprint/drivers/aeslib.h +@@ -17,8 +17,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef __AESLIB_H__ +-#define __AESLIB_H__ ++#pragma once + + #include + +@@ -45,5 +44,3 @@ 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/elan.h b/libfprint/drivers/elan.h +index 169498a..1fdd820 100644 +--- a/libfprint/drivers/elan.h ++++ b/libfprint/drivers/elan.h +@@ -18,8 +18,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef __ELAN_H +-#define __ELAN_H ++#pragma once + + #include + +@@ -224,5 +223,3 @@ static void elan_capture (FpDevice *dev); + + static void dev_change_state (FpImageDevice *dev, + FpImageDeviceState state); +- +-#endif +diff --git a/libfprint/drivers/synaptics/bmkt.h b/libfprint/drivers/synaptics/bmkt.h +index 67c48f2..1af6d29 100644 +--- a/libfprint/drivers/synaptics/bmkt.h ++++ b/libfprint/drivers/synaptics/bmkt.h +@@ -17,8 +17,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef _BMKT_H_ +-#define _BMKT_H_ ++#pragma once + + /**< User ID maximum length allowed */ + #define BMKT_MAX_USER_ID_LEN 100 +@@ -228,5 +227,3 @@ typedef struct bmkt_user_id + #ifdef __cplusplus + } + #endif +- +-#endif /* _BMKT_H_ */ +diff --git a/libfprint/drivers/synaptics/bmkt_message.h b/libfprint/drivers/synaptics/bmkt_message.h +index d41e3d2..98d38e4 100644 +--- a/libfprint/drivers/synaptics/bmkt_message.h ++++ b/libfprint/drivers/synaptics/bmkt_message.h +@@ -16,10 +16,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +- +-#ifndef BMKT_MESSAGE_H_ +-#define BMKT_MESSAGE_H_ +- ++#pragma once + + #define BMKT_MESSAGE_HEADER_ID 0xFE + #define BMKT_MESSAGE_HEADER_LEN (4) +@@ -90,4 +87,3 @@ int bmkt_parse_message_header (uint8_t *resp_buf, + 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 cfd7703..f13ed94 100644 +--- a/libfprint/drivers/synaptics/bmkt_response.h ++++ b/libfprint/drivers/synaptics/bmkt_response.h +@@ -17,9 +17,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +- +-#ifndef _BMKT_RESPONSE_H_ +-#define _BMKT_RESPONSE_H_ ++#pragma once + + #include "bmkt.h" + +@@ -485,5 +483,3 @@ typedef struct bmkt_response + 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 922b1dd..32134fe 100644 +--- a/libfprint/drivers/synaptics/sensor.h ++++ b/libfprint/drivers/synaptics/sensor.h +@@ -16,8 +16,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef _SENSOR_H_ +-#define _SENSOR_H_ ++#pragma once + + #include "usb_transport.h" + #define BMKT_MAX_PENDING_SESSIONS 2 +@@ -84,4 +83,3 @@ int bmkt_sensor_handle_response (bmkt_sensor_t *sensor, + 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.h b/libfprint/drivers/synaptics/synaptics.h +index cce6be9..37eb362 100644 +--- a/libfprint/drivers/synaptics/synaptics.h ++++ b/libfprint/drivers/synaptics/synaptics.h +@@ -16,8 +16,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef __synaptics_h__ +-#define __synaptics_h__ ++#pragma once + + #include "fpi-device.h" + #include "fpi-ssm.h" +@@ -126,5 +125,3 @@ struct _FpiDeviceSynaptics + struct syna_enroll_resp_data enroll_resp_data; + syna_state_t state; + }; +- +-#endif //__synaptics_h__ +diff --git a/libfprint/drivers/upektc.h b/libfprint/drivers/upektc.h +index 7ea919a..a1f9a23 100644 +--- a/libfprint/drivers/upektc.h ++++ b/libfprint/drivers/upektc.h +@@ -19,8 +19,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef __UPEKTC_H +-#define __UPEKTC_H ++#pragma once + + #define UPEKTC_CMD_LEN 0x40 + #define IMAGE_WIDTH 208 +@@ -1936,5 +1935,3 @@ static const unsigned char scan_cmd[0x40] = { + 0x05, 0x90, 0xf6, 0x77, 0x84, 0xf5, 0x2f, 0x01, + 0x05, 0x90, 0xf6, 0x00, 0xc8, 0x00, 0xec, 0x00 + }; +- +-#endif +diff --git a/libfprint/drivers/upektc_img.h b/libfprint/drivers/upektc_img.h +index 9185aa8..3052b65 100644 +--- a/libfprint/drivers/upektc_img.h ++++ b/libfprint/drivers/upektc_img.h +@@ -17,8 +17,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef __UPEKTC_IMG_H +-#define __UPEKTC_IMG_H ++#pragma once + + static const unsigned char upek2020_init_1[] = { + 'C', 'i', 'a', 'o', +@@ -140,5 +139,3 @@ static const unsigned char upek2020_ack_frame[] = { + 0x30, + 0xac, 0x5b /* CRC */ + }; +- +-#endif +diff --git a/libfprint/drivers/vfs5011_proto.h b/libfprint/drivers/vfs5011_proto.h +index f71a10f..5b2f8f4 100644 +--- a/libfprint/drivers/vfs5011_proto.h ++++ b/libfprint/drivers/vfs5011_proto.h +@@ -1,5 +1,4 @@ +-#ifndef __VFS5011_PROTO_H +-#define __VFS5011_PROTO_H ++#pragma once + + #define VFS5011_LINE_SIZE 240 + #define VFS5011_IMAGE_WIDTH 160 +@@ -6182,5 +6181,3 @@ static unsigned char vfs5011_prepare_04[] = { /* 2903 B */ + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + }; +- +-#endif +diff --git a/libfprint/drivers_api.h b/libfprint/drivers_api.h +index e8ed900..7476ba7 100644 +--- a/libfprint/drivers_api.h ++++ b/libfprint/drivers_api.h +@@ -19,8 +19,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef __DRIVERS_API_H__ +-#define __DRIVERS_API_H__ ++#pragma once + + #include "fpi-assembling.h" + #include "fpi-device.h" +@@ -30,5 +29,3 @@ + #include "fpi-print.h" + #include "fpi-usb-transfer.h" + #include "fpi-ssm.h" +- +-#endif +diff --git a/libfprint/fpi-assembling.h b/libfprint/fpi-assembling.h +index 77e3c55..295e315 100644 +--- a/libfprint/fpi-assembling.h ++++ b/libfprint/fpi-assembling.h +@@ -17,8 +17,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef __FPI_ASSEMBLING_H__ +-#define __FPI_ASSEMBLING_H__ ++#pragma once + + #include + +@@ -116,5 +115,3 @@ struct fpi_line_asmbl_ctx + FpImage *fpi_assemble_lines (struct fpi_line_asmbl_ctx *ctx, + GSList *lines, + size_t num_lines); +- +-#endif +diff --git a/libfprint/fpi-byte-reader.h b/libfprint/fpi-byte-reader.h +index 0a661c6..4a14ec8 100644 +--- a/libfprint/fpi-byte-reader.h ++++ b/libfprint/fpi-byte-reader.h +@@ -19,8 +19,7 @@ + * Boston, MA 02110-1301, USA. + */ + +-#ifndef __FPI_BYTE_READER_H__ +-#define __FPI_BYTE_READER_H__ ++#pragma once + + #include + #include "fpi-byte-utils.h" +@@ -676,5 +675,3 @@ fpi_byte_reader_skip_inline (FpiByteReader * reader, guint 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 +index 8a99121..52acb20 100644 +--- a/libfprint/fpi-byte-utils.h ++++ b/libfprint/fpi-byte-utils.h +@@ -21,9 +21,7 @@ + * Boston, MA 02110-1301, USA. + */ + +- +-#ifndef __FP_UTILS_H__ +-#define __FP_UTILS_H__ ++#pragma once + + #include + +@@ -485,4 +483,3 @@ FP_WRITE_DOUBLE_BE(guint8 *data, gdouble num) + G_END_DECLS + + #endif /* __GTK_DOC_IGNORE__ */ +-#endif /* __FP_UTILS_H__ */ +diff --git a/libfprint/fpi-byte-writer.h b/libfprint/fpi-byte-writer.h +index b15a9a1..ccdaf0b 100644 +--- a/libfprint/fpi-byte-writer.h ++++ b/libfprint/fpi-byte-writer.h +@@ -18,8 +18,7 @@ + * Boston, MA 02110-1301, USA. + */ + +-#ifndef __FPI_BYTE_WRITER_H__ +-#define __FPI_BYTE_WRITER_H__ ++#pragma once + + #include "fpi-byte-reader.h" + #include +@@ -409,5 +408,3 @@ fpi_byte_writer_fill_inline (FpiByteWriter * writer, guint8 value, guint size) + #endif + + G_END_DECLS +- +-#endif /* __FPI_BYTE_WRITER_H__ */ +diff --git a/libfprint/fpi-log.h b/libfprint/fpi-log.h +index 8f2f6a1..da61204 100644 +--- a/libfprint/fpi-log.h ++++ b/libfprint/fpi-log.h +@@ -17,8 +17,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-#ifndef __FPI_LOG_H__ +-#define __FPI_LOG_H__ ++#pragma once + + /** + * SECTION:fpi-log +@@ -94,5 +93,3 @@ + * Same as BUG_ON() but is always true. + */ + #define BUG() BUG_ON (1) +- +-#endif +-- +2.24.1 + diff --git a/SOURCES/0147-cleanup-Use-FPI-prefix-for-all-the-internal-enum-typ.patch b/SOURCES/0147-cleanup-Use-FPI-prefix-for-all-the-internal-enum-typ.patch new file mode 100644 index 0000000..612de60 --- /dev/null +++ b/SOURCES/0147-cleanup-Use-FPI-prefix-for-all-the-internal-enum-typ.patch @@ -0,0 +1,1745 @@ +From 44152f201b938100ea12a1eb049e6fcfafc7aea0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 16 Dec 2019 22:45:00 +0100 +Subject: [PATCH 147/181] cleanup: Use FPI prefix for all the internal enum + types + +--- + doc/libfprint-sections.txt | 6 +- + doc/libfprint-sections.txt-new-manual | 4 +- + libfprint/drivers/elan.c | 60 +++++++------- + libfprint/drivers/elan.h | 4 +- + libfprint/drivers/synaptics/synaptics.c | 4 +- + libfprint/drivers/uru4000.c | 24 +++--- + libfprint/fp-device-private.h | 2 +- + libfprint/fp-device.c | 26 +++--- + libfprint/fp-image-device-private.h | 16 ++-- + libfprint/fp-image-device.c | 30 +++---- + libfprint/fp-print-private.h | 2 +- + libfprint/fp-print.c | 28 +++---- + libfprint/fpi-device.c | 66 +++++++-------- + libfprint/fpi-device.h | 46 +++++------ + libfprint/fpi-image-device.c | 104 ++++++++++++------------ + libfprint/fpi-image-device.h | 24 +++--- + libfprint/fpi-print.c | 24 +++--- + libfprint/fpi-print.h | 20 ++--- + tests/test-device-fake.c | 20 ++--- + tests/test-fpi-device.c | 20 ++--- + 20 files changed, 264 insertions(+), 266 deletions(-) + +diff --git a/doc/libfprint-sections.txt b/doc/libfprint-sections.txt +index 9e17f8e..30a4e9b 100644 +--- a/doc/libfprint-sections.txt ++++ b/doc/libfprint-sections.txt +@@ -129,7 +129,7 @@ fpi_get_driver_types + fpi-device + FpDeviceClass + FpTimeoutFunc +-FpDeviceAction ++FpiDeviceAction + FpIdEntry + fpi_device_get_usb_device + fpi_device_get_virtual_env +@@ -173,7 +173,7 @@ fpi_image_resize +

+ fpi-image-device + FpImageDevice +-FpImageDeviceState ++FpiImageDeviceState + FpImageDeviceClass + fpi_image_device_session_error + fpi_image_device_open_complete +@@ -197,7 +197,7 @@ BUG + +
+ fpi-print +-FpPrintType ++FpiPrintType + FpiMatchResult + fpi_print_add_print + fpi_print_set_type +diff --git a/doc/libfprint-sections.txt-new-manual b/doc/libfprint-sections.txt-new-manual +index 857425b..da850db 100644 +--- a/doc/libfprint-sections.txt-new-manual ++++ b/doc/libfprint-sections.txt-new-manual +@@ -90,7 +90,7 @@ fp_image_get_width + Base class for image devices + FpImageDevice + FpImageDeviceClass +-FpImageDeviceState ++FpiImageDeviceState +
+ +
+@@ -114,5 +114,3 @@ FpUsbTransferCallback + FP_USB_ENDPOINT_IN + FP_USB_ENDPOINT_OUT +
+- +- +diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c +index 415aaef..233e4a8 100644 +--- a/libfprint/drivers/elan.c ++++ b/libfprint/drivers/elan.c +@@ -73,18 +73,18 @@ struct _FpiDeviceElan + /* 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; ++ gboolean deactivating; ++ FpiImageDeviceState dev_state; ++ FpiImageDeviceState 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, +@@ -481,7 +481,7 @@ stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + + + /* The device is inactive at this point. */ +- self->dev_state = FP_IMAGE_DEVICE_STATE_INACTIVE; ++ self->dev_state = FPI_IMAGE_DEVICE_STATE_INACTIVE; + + if (self->deactivating) + { +@@ -538,7 +538,7 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev) + break; + + case CAPTURE_READ_DATA: +- self->dev_state = FP_IMAGE_DEVICE_STATE_CAPTURE; ++ self->dev_state = FPI_IMAGE_DEVICE_STATE_CAPTURE; + + /* 0x55 - finger present + * 0xff - device not calibrated (probably) */ +@@ -773,7 +773,7 @@ calibrate_complete (FpiSsm *ssm, FpDevice *dev, GError *error) + + if (error) + { +- self->dev_state = FP_IMAGE_DEVICE_STATE_INACTIVE; ++ self->dev_state = FPI_IMAGE_DEVICE_STATE_INACTIVE; + fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error); + } + else +@@ -951,7 +951,7 @@ elan_change_state (FpImageDevice *idev) + { + FpDevice *dev = FP_DEVICE (idev); + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); +- FpImageDeviceState next_state = self->dev_state_next; ++ FpiImageDeviceState next_state = self->dev_state_next; + + if (self->dev_state == next_state) + { +@@ -965,18 +965,18 @@ elan_change_state (FpImageDevice *idev) + + switch (next_state) + { +- case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: ++ case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: + /* activation completed or another enroll stage started */ +- self->dev_state = FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON; ++ self->dev_state = FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON; + elan_calibrate (dev); + break; + +- case FP_IMAGE_DEVICE_STATE_CAPTURE: ++ case FPI_IMAGE_DEVICE_STATE_CAPTURE: + /* not used */ + break; + +- case FP_IMAGE_DEVICE_STATE_INACTIVE: +- case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: ++ case FPI_IMAGE_DEVICE_STATE_INACTIVE: ++ case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: + elan_stop_capture (dev); + break; + } +@@ -991,7 +991,7 @@ elan_change_state_async (FpDevice *dev, + } + + static void +-dev_change_state (FpImageDevice *dev, FpImageDeviceState state) ++dev_change_state (FpImageDevice *dev, FpiImageDeviceState state) + { + FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + GSource *timeout; +@@ -999,17 +999,17 @@ dev_change_state (FpImageDevice *dev, FpImageDeviceState state) + 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 (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF) ++ state = FPI_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: { ++ case FPI_IMAGE_DEVICE_STATE_INACTIVE: ++ case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: ++ case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: { + char *name; + + /* schedule state change instead of calling it directly to allow all actions +@@ -1026,7 +1026,7 @@ dev_change_state (FpImageDevice *dev, FpImageDeviceState state) + break; + } + +- case FP_IMAGE_DEVICE_STATE_CAPTURE: ++ case FPI_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; +@@ -1044,7 +1044,7 @@ dev_deactivate (FpImageDevice *dev) + + G_DEBUG_HERE (); + +- if (self->dev_state == FP_IMAGE_DEVICE_STATE_INACTIVE) ++ if (self->dev_state == FPI_IMAGE_DEVICE_STATE_INACTIVE) + { + /* The device is inactive already, complete the operation immediately. */ + fpi_image_device_deactivate_complete (dev, NULL); +@@ -1055,7 +1055,7 @@ dev_deactivate (FpImageDevice *dev) + * 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); ++ dev_change_state (dev, FPI_IMAGE_DEVICE_STATE_INACTIVE); + } + } + +diff --git a/libfprint/drivers/elan.h b/libfprint/drivers/elan.h +index 1fdd820..2b1c089 100644 +--- a/libfprint/drivers/elan.h ++++ b/libfprint/drivers/elan.h +@@ -221,5 +221,5 @@ static void elan_cmd_read (FpiSsm *ssm, + 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, ++ FpiImageDeviceState state); +diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c +index 97d9d21..af4a2fd 100644 +--- a/libfprint/drivers/synaptics/synaptics.c ++++ b/libfprint/drivers/synaptics/synaptics.c +@@ -517,7 +517,7 @@ list_msg_cb (FpiDeviceSynaptics *self, + get_enroll_templates_resp->templates[n].finger_id, + uid); + +- fpi_print_set_type (print, FP_PRINT_RAW); ++ fpi_print_set_type (print, FPI_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); +@@ -856,7 +856,7 @@ enroll (FpDevice *device) + finger, + uid); + +- fpi_print_set_type (print, FP_PRINT_RAW); ++ fpi_print_set_type (print, FPI_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); +diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c +index 5128a12..b86c6c8 100644 +--- a/libfprint/drivers/uru4000.c ++++ b/libfprint/drivers/uru4000.c +@@ -122,7 +122,7 @@ struct _FpiDeviceUru4000 + + const struct uru4k_dev_profile *profile; + uint8_t interface; +- FpImageDeviceState activate_state; ++ FpiImageDeviceState activate_state; + unsigned char last_reg_rd[16]; + unsigned char last_hwstat; + +@@ -408,16 +408,16 @@ change_state_write_reg_cb (FpiUsbTransfer *transfer, + } + + static void +-dev_change_state (FpImageDevice *dev, FpImageDeviceState state) ++dev_change_state (FpImageDevice *dev, FpiImageDeviceState state) + { + 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: ++ case FPI_IMAGE_DEVICE_STATE_INACTIVE: ++ case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: ++ case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: ++ case FPI_IMAGE_DEVICE_STATE_CAPTURE: + break; + + default: +@@ -773,7 +773,7 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev) + 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) ++ if (self->activate_state == FPI_IMAGE_DEVICE_STATE_CAPTURE) + fpi_ssm_jump_to_state (ssm, IMAGING_CAPTURE); + else + fpi_ssm_mark_completed (ssm); +@@ -1176,7 +1176,7 @@ deactivate_write_reg_cb (FpiUsbTransfer *transfer, FpDevice *dev, + static void + dev_deactivate (FpImageDevice *dev) + { +- dev_change_state (dev, FP_IMAGE_DEVICE_STATE_INACTIVE); ++ dev_change_state (dev, FPI_IMAGE_DEVICE_STATE_INACTIVE); + } + + static void +@@ -1187,7 +1187,7 @@ execute_state_change (FpImageDevice *dev) + + switch (self->activate_state) + { +- case FP_IMAGE_DEVICE_STATE_INACTIVE: ++ case FPI_IMAGE_DEVICE_STATE_INACTIVE: + fp_dbg ("deactivating"); + self->irq_cb = NULL; + self->irq_cb_data = NULL; +@@ -1195,7 +1195,7 @@ execute_state_change (FpImageDevice *dev) + deactivate_write_reg_cb, NULL); + break; + +- case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: ++ case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: + fp_dbg ("wait finger on"); + if (!IRQ_HANDLER_IS_RUNNING (self)) + { +@@ -1209,7 +1209,7 @@ execute_state_change (FpImageDevice *dev) + change_state_write_reg_cb, NULL); + break; + +- case FP_IMAGE_DEVICE_STATE_CAPTURE: ++ case FPI_IMAGE_DEVICE_STATE_CAPTURE: + fp_dbg ("starting capture"); + self->irq_cb = NULL; + +@@ -1229,7 +1229,7 @@ execute_state_change (FpImageDevice *dev) + change_state_write_reg_cb, NULL); + break; + +- case FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: ++ case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: + fp_dbg ("await finger off"); + if (!IRQ_HANDLER_IS_RUNNING (self)) + { +diff --git a/libfprint/fp-device-private.h b/libfprint/fp-device-private.h +index 65fb1cb..1a350fe 100644 +--- a/libfprint/fp-device-private.h ++++ b/libfprint/fp-device-private.h +@@ -41,7 +41,7 @@ typedef struct + GSList *sources; + + /* We always make sure that only one task is run at a time. */ +- FpDeviceAction current_action; ++ FpiDeviceAction current_action; + GTask *current_task; + GAsyncReadyCallback current_user_cb; + gulong current_cancellable_id; +diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c +index 3ac3a1c..8041a86 100644 +--- a/libfprint/fp-device.c ++++ b/libfprint/fp-device.c +@@ -81,7 +81,7 @@ fp_device_cancel_in_idle_cb (gpointer user_data) + FpDevicePrivate *priv = fp_device_get_instance_private (self); + + g_assert (cls->cancel); +- g_assert (priv->current_action != FP_DEVICE_ACTION_NONE); ++ g_assert (priv->current_action != FPI_DEVICE_ACTION_NONE); + + g_debug ("Idle cancelling on ongoing operation!"); + +@@ -148,7 +148,7 @@ 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_action == FPI_DEVICE_ACTION_NONE); + g_assert (priv->current_task == NULL); + if (priv->is_open) + g_warning ("User destroyed open device! Not cleaning up properly!"); +@@ -268,7 +268,7 @@ fp_device_async_initable_init_async (GAsyncInitable *initable, + return; + } + +- priv->current_action = FP_DEVICE_ACTION_PROBE; ++ priv->current_action = FPI_DEVICE_ACTION_PROBE; + priv->current_task = g_steal_pointer (&task); + maybe_cancel_on_cancelled (self, cancellable); + +@@ -584,7 +584,7 @@ fp_device_open (FpDevice *device, + return; + } + +- priv->current_action = FP_DEVICE_ACTION_OPEN; ++ priv->current_action = FPI_DEVICE_ACTION_OPEN; + priv->current_task = g_steal_pointer (&task); + maybe_cancel_on_cancelled (device, cancellable); + +@@ -648,7 +648,7 @@ fp_device_close (FpDevice *device, + return; + } + +- priv->current_action = FP_DEVICE_ACTION_CLOSE; ++ priv->current_action = FPI_DEVICE_ACTION_CLOSE; + priv->current_task = g_steal_pointer (&task); + maybe_cancel_on_cancelled (device, cancellable); + +@@ -709,7 +709,7 @@ fp_device_enroll (FpDevice *device, + g_autoptr(GTask) task = NULL; + FpDevicePrivate *priv = fp_device_get_instance_private (device); + FpEnrollData *data; +- FpPrintType print_type; ++ FpiPrintType print_type; + + task = g_task_new (device, cancellable, callback, user_data); + if (g_task_return_error_if_cancelled (task)) +@@ -738,7 +738,7 @@ fp_device_enroll (FpDevice *device, + } + + g_object_get (template_print, "fp-type", &print_type, NULL); +- if (print_type != FP_PRINT_UNDEFINED) ++ if (print_type != FPI_PRINT_UNDEFINED) + { + g_warning ("Passed print template must be newly created and blank!"); + g_task_return_error (task, +@@ -746,7 +746,7 @@ fp_device_enroll (FpDevice *device, + return; + } + +- priv->current_action = FP_DEVICE_ACTION_ENROLL; ++ priv->current_action = FPI_DEVICE_ACTION_ENROLL; + priv->current_task = g_steal_pointer (&task); + maybe_cancel_on_cancelled (device, cancellable); + +@@ -822,7 +822,7 @@ fp_device_verify (FpDevice *device, + return; + } + +- priv->current_action = FP_DEVICE_ACTION_VERIFY; ++ priv->current_action = FPI_DEVICE_ACTION_VERIFY; + priv->current_task = g_steal_pointer (&task); + maybe_cancel_on_cancelled (device, cancellable); + +@@ -915,7 +915,7 @@ fp_device_identify (FpDevice *device, + return; + } + +- priv->current_action = FP_DEVICE_ACTION_IDENTIFY; ++ priv->current_action = FPI_DEVICE_ACTION_IDENTIFY; + priv->current_task = g_steal_pointer (&task); + maybe_cancel_on_cancelled (device, cancellable); + +@@ -1008,7 +1008,7 @@ fp_device_capture (FpDevice *device, + return; + } + +- priv->current_action = FP_DEVICE_ACTION_CAPTURE; ++ priv->current_action = FPI_DEVICE_ACTION_CAPTURE; + priv->current_task = g_steal_pointer (&task); + maybe_cancel_on_cancelled (device, cancellable); + +@@ -1089,7 +1089,7 @@ fp_device_delete_print (FpDevice *device, + return; + } + +- priv->current_action = FP_DEVICE_ACTION_DELETE; ++ priv->current_action = FPI_DEVICE_ACTION_DELETE; + priv->current_task = g_steal_pointer (&task); + maybe_cancel_on_cancelled (device, cancellable); + +@@ -1159,7 +1159,7 @@ fp_device_list_prints (FpDevice *device, + return; + } + +- priv->current_action = FP_DEVICE_ACTION_LIST; ++ priv->current_action = FPI_DEVICE_ACTION_LIST; + priv->current_task = g_steal_pointer (&task); + maybe_cancel_on_cancelled (device, cancellable); + +diff --git a/libfprint/fp-image-device-private.h b/libfprint/fp-image-device-private.h +index 01454fd..07a0347 100644 +--- a/libfprint/fp-image-device-private.h ++++ b/libfprint/fp-image-device-private.h +@@ -25,17 +25,17 @@ + + typedef struct + { +- FpImageDeviceState state; +- gboolean active; +- gboolean cancelling; ++ FpiImageDeviceState state; ++ gboolean active; ++ gboolean cancelling; + +- gboolean enroll_await_on_pending; +- gint enroll_stage; ++ gboolean enroll_await_on_pending; ++ gint enroll_stage; + +- guint pending_activation_timeout_id; +- gboolean pending_activation_timeout_waiting_finger_off; ++ guint pending_activation_timeout_id; ++ gboolean pending_activation_timeout_waiting_finger_off; + +- gint bz3_threshold; ++ gint bz3_threshold; + } FpImageDevicePrivate; + + +diff --git a/libfprint/fp-image-device.c b/libfprint/fp-image-device.c +index 24d324d..9e6c375 100644 +--- a/libfprint/fp-image-device.c ++++ b/libfprint/fp-image-device.c +@@ -106,7 +106,7 @@ fp_image_device_close (FpDevice *device) + + if (!priv->active) + cls->img_close (self); +- else if (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE) ++ else if (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE) + fpi_image_device_deactivate (self); + } + +@@ -115,16 +115,16 @@ fp_image_device_cancel_action (FpDevice *device) + { + FpImageDevice *self = FP_IMAGE_DEVICE (device); + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); +- FpDeviceAction action; ++ FpiDeviceAction 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) ++ if (action == FPI_DEVICE_ACTION_ENROLL || ++ action == FPI_DEVICE_ACTION_VERIFY || ++ action == FPI_DEVICE_ACTION_IDENTIFY || ++ action == FPI_DEVICE_ACTION_CAPTURE) + { + priv->cancelling = TRUE; + fpi_image_device_deactivate (self); +@@ -143,14 +143,14 @@ 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; ++ FpiDeviceAction 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) ++ if (action == FPI_DEVICE_ACTION_CAPTURE) + { + gboolean wait_for_finger; + +@@ -162,12 +162,12 @@ fp_image_device_start_capture_action (FpDevice *device) + return; + } + } +- else if (action == FP_DEVICE_ACTION_ENROLL) ++ else if (action == FPI_DEVICE_ACTION_ENROLL) + { + FpPrint *enroll_print = NULL; + + fpi_device_get_enroll_data (device, &enroll_print); +- fpi_print_set_type (enroll_print, FP_PRINT_NBIS); ++ fpi_print_set_type (enroll_print, FPI_PRINT_NBIS); + } + + priv->enroll_stage = 0; +@@ -178,14 +178,14 @@ fp_image_device_start_capture_action (FpDevice *device) + * error (which will usually say that the user should remove the + * finger). + */ +- if (priv->state != FP_IMAGE_DEVICE_STATE_INACTIVE || priv->active) ++ if (priv->state != FPI_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) ++ if (priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF) + priv->pending_activation_timeout_waiting_finger_off = TRUE; + else + priv->pending_activation_timeout_waiting_finger_off = FALSE; +@@ -271,8 +271,8 @@ fp_image_device_class_init (FpImageDeviceClass *klass) + g_param_spec_enum ("fp-image-device-state", + "Image Device State", + "Private: The state of the image device", +- FP_TYPE_IMAGE_DEVICE_STATE, +- FP_IMAGE_DEVICE_STATE_INACTIVE, ++ FPI_TYPE_IMAGE_DEVICE_STATE, ++ FPI_IMAGE_DEVICE_STATE_INACTIVE, + G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); + + signals[FPI_STATE_CHANGED] = +@@ -281,7 +281,7 @@ fp_image_device_class_init (FpImageDeviceClass *klass) + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (FpImageDeviceClass, change_state), + NULL, NULL, NULL, +- G_TYPE_NONE, 1, FP_TYPE_IMAGE_DEVICE_STATE); ++ G_TYPE_NONE, 1, FPI_TYPE_IMAGE_DEVICE_STATE); + + g_object_class_install_properties (object_class, N_PROPS, properties); + } +diff --git a/libfprint/fp-print-private.h b/libfprint/fp-print-private.h +index f5822b3..6d44700 100644 +--- a/libfprint/fp-print-private.h ++++ b/libfprint/fp-print-private.h +@@ -27,7 +27,7 @@ struct _FpPrint + { + GInitiallyUnowned parent_instance; + +- FpPrintType type; ++ FpiPrintType type; + + gchar *driver; + gchar *device_id; +diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c +index 30fdf1a..dd45b95 100644 +--- a/libfprint/fp-print.c ++++ b/libfprint/fp-print.c +@@ -272,8 +272,8 @@ fp_print_class_init (FpPrintClass *klass) + g_param_spec_enum ("fp-type", + "Type", + "Private: The type of the print data", +- FP_TYPE_PRINT_TYPE, +- FP_PRINT_RAW, ++ FPI_TYPE_PRINT_TYPE, ++ FPI_PRINT_RAW, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + + properties[PROP_FPI_DATA] = +@@ -555,8 +555,8 @@ 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); ++ g_return_val_if_fail (self->type != FPI_PRINT_UNDEFINED, FALSE); ++ g_return_val_if_fail (other->type != FPI_PRINT_UNDEFINED, FALSE); + + if (self->type != other->type) + return FALSE; +@@ -567,11 +567,11 @@ fp_print_equal (FpPrint *self, FpPrint *other) + if (g_strcmp0 (self->device_id, other->device_id)) + return FALSE; + +- if (self->type == FP_PRINT_RAW) ++ if (self->type == FPI_PRINT_RAW) + { + return g_variant_equal (self->data, other->data); + } +- else if (self->type == FP_PRINT_NBIS) ++ else if (self->type == FPI_PRINT_NBIS) + { + gint i; + +@@ -595,7 +595,7 @@ fp_print_equal (FpPrint *self, FpPrint *other) + } + } + +-#define FP_PRINT_VARIANT_TYPE G_VARIANT_TYPE ("(issbymsmsia{sv}v)") ++#define FPI_PRINT_VARIANT_TYPE G_VARIANT_TYPE ("(issbymsmsia{sv}v)") + + G_STATIC_ASSERT (sizeof (((struct xyt_struct *) NULL)->xcol[0]) == 4); + +@@ -618,7 +618,7 @@ fp_print_serialize (FpPrint *print, + GError **error) + { + g_autoptr(GVariant) result = NULL; +- GVariantBuilder builder = G_VARIANT_BUILDER_INIT (FP_PRINT_VARIANT_TYPE); ++ GVariantBuilder builder = G_VARIANT_BUILDER_INIT (FPI_PRINT_VARIANT_TYPE); + gsize len; + + g_assert (data); +@@ -643,7 +643,7 @@ fp_print_serialize (FpPrint *print, + g_variant_builder_close (&builder); + + /* Insert NBIS print data for type NBIS, otherwise the GVariant directly */ +- if (print->type == FP_PRINT_NBIS) ++ if (print->type == FPI_PRINT_NBIS) + { + GVariantBuilder nested = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("(a(aiaiai))")); + gint i; +@@ -745,7 +745,7 @@ fp_print_deserialize (const guchar *data, + g_autofree gchar *username = NULL; + g_autofree gchar *description = NULL; + gint julian_date; +- FpPrintType type; ++ FpiPrintType type; + const gchar *driver; + const gchar *device_id; + gboolean device_stored; +@@ -766,7 +766,7 @@ fp_print_deserialize (const guchar *data, + * 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, ++ raw_value = g_variant_new_from_data (FPI_PRINT_VARIANT_TYPE, + aligned_data, length - 3, + FALSE, g_free, aligned_data); + +@@ -794,7 +794,7 @@ fp_print_deserialize (const guchar *data, + finger = finger_int8; + + /* Assume data is valid at this point if the values are somewhat sane. */ +- if (type == FP_PRINT_NBIS) ++ if (type == FPI_PRINT_NBIS) + { + g_autoptr(GVariant) prints = g_variant_get_child_value (print_data, 0); + gint i; +@@ -804,7 +804,7 @@ fp_print_deserialize (const guchar *data, + "device-id", device_id, + "device-stored", device_stored, + NULL); +- fpi_print_set_type (result, FP_PRINT_NBIS); ++ fpi_print_set_type (result, FPI_PRINT_NBIS); + for (i = 0; i < g_variant_n_children (prints); i++) + { + g_autofree struct xyt_struct *xyt = g_new0 (struct xyt_struct, 1); +@@ -841,7 +841,7 @@ fp_print_deserialize (const guchar *data, + g_ptr_array_add (result->prints, g_steal_pointer (&xyt)); + } + } +- else if (type == FP_PRINT_RAW) ++ else if (type == FPI_PRINT_RAW) + { + g_autoptr(GVariant) fp_data = g_variant_get_child_value (print_data, 0); + +diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c +index 5fc6b76..51dbee1 100644 +--- a/libfprint/fpi-device.c ++++ b/libfprint/fpi-device.c +@@ -350,21 +350,21 @@ fpi_device_get_virtual_env (FpDevice *device) + * fpi_device_get_current_action: + * @device: The #FpDevice + * +- * Get the currently ongoing action or %FP_DEVICE_ACTION_NONE if there ++ * Get the currently ongoing action or %FPI_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 ++ * Returns: The ongoing #FpiDeviceAction + */ +-FpDeviceAction ++FpiDeviceAction + 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); ++ g_return_val_if_fail (FP_IS_DEVICE (device), FPI_DEVICE_ACTION_NONE); + + return priv->current_action; + } +@@ -387,7 +387,7 @@ fpi_device_action_is_cancelled (FpDevice *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); ++ g_return_val_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE, TRUE); + + cancellable = g_task_get_cancellable (priv->current_task); + +@@ -435,7 +435,7 @@ fpi_device_get_enroll_data (FpDevice *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 (priv->current_action == FPI_DEVICE_ACTION_ENROLL); + + data = g_task_get_task_data (priv->current_task); + g_assert (data); +@@ -458,7 +458,7 @@ fpi_device_get_capture_data (FpDevice *device, + 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); ++ g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_CAPTURE); + + if (wait_for_finger) + *wait_for_finger = priv->wait_for_finger; +@@ -478,7 +478,7 @@ fpi_device_get_verify_data (FpDevice *device, + 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); ++ g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY); + + if (print) + *print = g_task_get_task_data (priv->current_task); +@@ -498,7 +498,7 @@ fpi_device_get_identify_data (FpDevice *device, + 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); ++ g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY); + + if (prints) + *prints = g_task_get_task_data (priv->current_task); +@@ -518,7 +518,7 @@ fpi_device_get_delete_data (FpDevice *device, + 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); ++ g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_DELETE); + + if (print) + *print = g_task_get_task_data (priv->current_task); +@@ -542,7 +542,7 @@ 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); ++ g_return_val_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE, NULL); + + return g_task_get_cancellable (priv->current_task); + } +@@ -564,7 +564,7 @@ fpi_device_action_error (FpDevice *device, + 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); ++ g_return_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE); + + if (error != NULL) + { +@@ -579,44 +579,44 @@ fpi_device_action_error (FpDevice *device, + + switch (priv->current_action) + { +- case FP_DEVICE_ACTION_PROBE: ++ case FPI_DEVICE_ACTION_PROBE: + fpi_device_probe_complete (device, NULL, NULL, error); + break; + +- case FP_DEVICE_ACTION_OPEN: ++ case FPI_DEVICE_ACTION_OPEN: + fpi_device_open_complete (device, error); + break; + +- case FP_DEVICE_ACTION_CLOSE: ++ case FPI_DEVICE_ACTION_CLOSE: + fpi_device_close_complete (device, error); + break; + +- case FP_DEVICE_ACTION_ENROLL: ++ case FPI_DEVICE_ACTION_ENROLL: + fpi_device_enroll_complete (device, NULL, error); + break; + +- case FP_DEVICE_ACTION_VERIFY: ++ case FPI_DEVICE_ACTION_VERIFY: + fpi_device_verify_complete (device, FPI_MATCH_ERROR, NULL, error); + break; + +- case FP_DEVICE_ACTION_IDENTIFY: ++ case FPI_DEVICE_ACTION_IDENTIFY: + fpi_device_identify_complete (device, NULL, NULL, error); + break; + +- case FP_DEVICE_ACTION_CAPTURE: ++ case FPI_DEVICE_ACTION_CAPTURE: + fpi_device_capture_complete (device, NULL, error); + break; + +- case FP_DEVICE_ACTION_DELETE: ++ case FPI_DEVICE_ACTION_DELETE: + fpi_device_delete_complete (device, error); + break; + +- case FP_DEVICE_ACTION_LIST: ++ case FPI_DEVICE_ACTION_LIST: + fpi_device_list_complete (device, NULL, error); + break; + + default: +- case FP_DEVICE_ACTION_NONE: ++ case FPI_DEVICE_ACTION_NONE: + g_return_if_reached (); + break; + } +@@ -663,7 +663,7 @@ fp_device_task_return_in_idle_cb (gpointer user_data) + 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_action = FPI_DEVICE_ACTION_NONE; + priv->current_task_idle_return_source = NULL; + + switch (data->type) +@@ -746,7 +746,7 @@ fpi_device_probe_complete (FpDevice *device, + 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_PROBE); ++ g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_PROBE); + + g_debug ("Device reported probe completion"); + +@@ -788,7 +788,7 @@ fpi_device_open_complete (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_OPEN); ++ g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_OPEN); + + g_debug ("Device reported open completion"); + +@@ -821,7 +821,7 @@ fpi_device_close_complete (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_CLOSE); ++ g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_CLOSE); + + g_debug ("Device reported close completion"); + +@@ -873,7 +873,7 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, 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_ENROLL); ++ g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_ENROLL); + + g_debug ("Device reported enroll completion"); + +@@ -923,7 +923,7 @@ fpi_device_verify_complete (FpDevice *device, + 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); ++ g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY); + + g_debug ("Device reported verify completion"); + +@@ -980,7 +980,7 @@ fpi_device_identify_complete (FpDevice *device, + 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); ++ g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY); + + g_debug ("Device reported identify completion"); + +@@ -1027,7 +1027,7 @@ fpi_device_capture_complete (FpDevice *device, + 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); ++ g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_CAPTURE); + + g_debug ("Device reported capture completion"); + +@@ -1072,7 +1072,7 @@ fpi_device_delete_complete (FpDevice *device, + 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); ++ g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_DELETE); + + g_debug ("Device reported deletion completion"); + +@@ -1106,7 +1106,7 @@ fpi_device_list_complete (FpDevice *device, + 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_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_LIST); + + g_debug ("Device reported listing completion"); + +@@ -1150,7 +1150,7 @@ fpi_device_enroll_progress (FpDevice *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 (priv->current_action == FPI_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); +diff --git a/libfprint/fpi-device.h b/libfprint/fpi-device.h +index 2333ae2..3d66ee5 100644 +--- a/libfprint/fpi-device.h ++++ b/libfprint/fpi-device.h +@@ -142,39 +142,39 @@ 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. ++ * FpiDeviceAction: ++ * @FPI_DEVICE_ACTION_NONE: No action is active. ++ * @FPI_DEVICE_ACTION_PROBE: Probe device for support and information. ++ * @FPI_DEVICE_ACTION_OPEN: Device is currently being opened. ++ * @FPI_DEVICE_ACTION_CLOSE: Device is currently being closed. ++ * @FPI_DEVICE_ACTION_ENROLL: Device is currently enrolling. ++ * @FPI_DEVICE_ACTION_VERIFY: Device is currently verifying. ++ * @FPI_DEVICE_ACTION_IDENTIFY: Device is currently identifying. ++ * @FPI_DEVICE_ACTION_CAPTURE: Device is currently capturing an image. ++ * @FPI_DEVICE_ACTION_LIST: Device stored prints are being queried. ++ * @FPI_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; ++ FPI_DEVICE_ACTION_NONE = 0, ++ FPI_DEVICE_ACTION_PROBE, ++ FPI_DEVICE_ACTION_OPEN, ++ FPI_DEVICE_ACTION_CLOSE, ++ FPI_DEVICE_ACTION_ENROLL, ++ FPI_DEVICE_ACTION_VERIFY, ++ FPI_DEVICE_ACTION_IDENTIFY, ++ FPI_DEVICE_ACTION_CAPTURE, ++ FPI_DEVICE_ACTION_LIST, ++ FPI_DEVICE_ACTION_DELETE, ++} FpiDeviceAction; + + 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); ++FpiDeviceAction fpi_device_get_current_action (FpDevice *device); + gboolean fpi_device_action_is_cancelled (FpDevice *device); + + GError * fpi_device_retry_new (FpDeviceRetry error); +diff --git a/libfprint/fpi-image-device.c b/libfprint/fpi-image-device.c +index 6e5802e..e03d60c 100644 +--- a/libfprint/fpi-image-device.c ++++ b/libfprint/fpi-image-device.c +@@ -54,7 +54,7 @@ fpi_image_device_activate (FpImageDevice *self) + + /* 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; ++ priv->state = FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON; + g_object_notify (G_OBJECT (self), "fp-image-device-state"); + + /* We might have been waiting for deactivation to finish before +@@ -79,10 +79,10 @@ fpi_image_device_deactivate (FpImageDevice *self) + fp_dbg ("Already deactivated, ignoring request."); + return; + } +- if (!priv->cancelling && priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON) ++ if (!priv->cancelling && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON) + g_warning ("Deactivating image device while waiting for finger, this should not happen."); + +- priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE; ++ priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE; + g_object_notify (G_OBJECT (self), "fp-image-device-state"); + + fp_dbg ("Deactivating image device\n"); +@@ -92,12 +92,12 @@ fpi_image_device_deactivate (FpImageDevice *self) + /* Static helper functions */ + + static void +-fp_image_device_change_state (FpImageDevice *self, FpImageDeviceState state) ++fp_image_device_change_state (FpImageDevice *self, FpiImageDeviceState state) + { + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); + + /* Cannot change to inactive using this function. */ +- g_assert (state != FP_IMAGE_DEVICE_STATE_INACTIVE); ++ g_assert (state != FPI_IMAGE_DEVICE_STATE_INACTIVE); + + /* We might have been waiting for the finger to go OFF to start the + * next operation. */ +@@ -118,7 +118,7 @@ fp_image_device_enroll_maybe_await_finger_on (FpImageDevice *self) + if (priv->enroll_await_on_pending) + { + priv->enroll_await_on_pending = FALSE; +- fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON); ++ fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON); + } + else + { +@@ -135,7 +135,7 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g + FpImageDevice *self = FP_IMAGE_DEVICE (user_data); + FpDevice *device = FP_DEVICE (self); + FpImageDevicePrivate *priv; +- FpDeviceAction action; ++ FpiDeviceAction action; + + /* Note: We rely on the device to not disappear during an operation. */ + +@@ -159,7 +159,7 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g + priv = fp_image_device_get_instance_private (FP_IMAGE_DEVICE (device)); + action = fpi_device_get_current_action (device); + +- if (action == FP_DEVICE_ACTION_CAPTURE) ++ if (action == FPI_DEVICE_ACTION_CAPTURE) + { + fpi_device_capture_complete (device, g_steal_pointer (&image), error); + fpi_image_device_deactivate (self); +@@ -169,12 +169,12 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g + if (!error) + { + print = fp_print_new (device); +- fpi_print_set_type (print, FP_PRINT_NBIS); ++ fpi_print_set_type (print, FPI_PRINT_NBIS); + if (!fpi_print_add_from_image (print, image, &error)) + g_clear_object (&print); + } + +- if (action == FP_DEVICE_ACTION_ENROLL) ++ if (action == FPI_DEVICE_ACTION_ENROLL) + { + FpPrint *enroll_print; + fpi_device_get_enroll_data (device, &enroll_print); +@@ -199,7 +199,7 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g + fp_image_device_enroll_maybe_await_finger_on (FP_IMAGE_DEVICE (device)); + } + } +- else if (action == FP_DEVICE_ACTION_VERIFY) ++ else if (action == FPI_DEVICE_ACTION_VERIFY) + { + FpPrint *template; + FpiMatchResult result; +@@ -213,7 +213,7 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g + fpi_device_verify_complete (device, result, g_steal_pointer (&print), error); + fpi_image_device_deactivate (self); + } +- else if (action == FP_DEVICE_ACTION_IDENTIFY) ++ else if (action == FPI_DEVICE_ACTION_IDENTIFY) + { + gint i; + GPtrArray *templates; +@@ -285,9 +285,9 @@ fpi_image_device_report_finger_status (FpImageDevice *self, + { + FpDevice *device = FP_DEVICE (self); + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); +- FpDeviceAction action; ++ FpiDeviceAction action; + +- if (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE) ++ if (priv->state == FPI_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 +@@ -300,16 +300,16 @@ fpi_image_device_report_finger_status (FpImageDevice *self, + + action = fpi_device_get_current_action (device); + +- g_assert (action != FP_DEVICE_ACTION_OPEN); +- g_assert (action != FP_DEVICE_ACTION_CLOSE); ++ g_assert (action != FPI_DEVICE_ACTION_OPEN); ++ g_assert (action != FPI_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) ++ if (present && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON) + { +- fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_CAPTURE); ++ fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_CAPTURE); + } +- else if (!present && priv->state == FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF) ++ else if (!present && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF) + { + /* We need to deactivate or continue to await finger */ + +@@ -324,7 +324,7 @@ fpi_image_device_report_finger_status (FpImageDevice *self, + * minutiae detection to prevent deactivation (without cancellation) + * from the AWAIT_FINGER_ON state. + */ +- if (action != FP_DEVICE_ACTION_ENROLL) ++ if (action != FPI_DEVICE_ACTION_ENROLL) + fpi_image_device_deactivate (self); + else + fp_image_device_enroll_maybe_await_finger_on (self); +@@ -349,18 +349,18 @@ void + fpi_image_device_image_captured (FpImageDevice *self, FpImage *image) + { + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); +- FpDeviceAction action; ++ FpiDeviceAction 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); ++ g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_CAPTURE); ++ g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL || ++ action == FPI_DEVICE_ACTION_VERIFY || ++ action == FPI_DEVICE_ACTION_IDENTIFY || ++ action == FPI_DEVICE_ACTION_CAPTURE); + +- fp_image_device_change_state (self, FP_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF); ++ fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF); + + g_debug ("Image device captured an image"); + +@@ -385,22 +385,22 @@ void + fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry) + { + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); +- FpDeviceAction action; ++ FpiDeviceAction 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); ++ g_return_if_fail (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE); ++ g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL || ++ action == FPI_DEVICE_ACTION_VERIFY || ++ action == FPI_DEVICE_ACTION_IDENTIFY || ++ action == FPI_DEVICE_ACTION_CAPTURE); + + error = fpi_device_retry_new (retry); + +- if (action == FP_DEVICE_ACTION_ENROLL) ++ if (action == FPI_DEVICE_ACTION_ENROLL) + { + g_debug ("Reporting retry during enroll"); + fpi_device_enroll_progress (FP_DEVICE (self), priv->enroll_stage, NULL, error); +@@ -438,17 +438,17 @@ fpi_image_device_session_error (FpImageDevice *self, GError *error) + + if (!priv->active) + { +- FpDeviceAction action = fpi_device_get_current_action (FP_DEVICE (self)); ++ FpiDeviceAction 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) ++ if (action != FPI_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) ++ else if (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE) + { + g_warning ("Driver reported session error; translating to deactivation failure."); + fpi_image_device_deactivate_complete (self, error); +@@ -473,15 +473,15 @@ void + fpi_image_device_activate_complete (FpImageDevice *self, GError *error) + { + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); +- FpDeviceAction action; ++ FpiDeviceAction 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); ++ g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL || ++ action == FPI_DEVICE_ACTION_VERIFY || ++ action == FPI_DEVICE_ACTION_IDENTIFY || ++ action == FPI_DEVICE_ACTION_CAPTURE); + + if (error) + { +@@ -496,7 +496,7 @@ fpi_image_device_activate_complete (FpImageDevice *self, GError *error) + + /* 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); ++ fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON); + } + + /** +@@ -511,10 +511,10 @@ 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; ++ FpiDeviceAction action; + + g_return_if_fail (priv->active == TRUE); +- g_return_if_fail (priv->state == FP_IMAGE_DEVICE_STATE_INACTIVE); ++ g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE); + + g_debug ("Image device deactivation completed"); + +@@ -527,7 +527,7 @@ fpi_image_device_deactivate_complete (FpImageDevice *self, GError *error) + + /* 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) ++ if (action == FPI_DEVICE_ACTION_CLOSE) + { + cls->img_close (self); + return; +@@ -553,16 +553,16 @@ void + fpi_image_device_open_complete (FpImageDevice *self, GError *error) + { + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); +- FpDeviceAction action; ++ FpiDeviceAction 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_return_if_fail (action == FPI_DEVICE_ACTION_OPEN); + + g_debug ("Image device open completed"); + +- priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE; ++ priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE; + g_object_notify (G_OBJECT (self), "fp-image-device-state"); + + fpi_device_open_complete (FP_DEVICE (self), error); +@@ -579,16 +579,16 @@ void + fpi_image_device_close_complete (FpImageDevice *self, GError *error) + { + FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); +- FpDeviceAction action; ++ FpiDeviceAction 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); ++ g_return_if_fail (action == FPI_DEVICE_ACTION_CLOSE); + +- priv->state = FP_IMAGE_DEVICE_STATE_INACTIVE; ++ priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE; + g_object_notify (G_OBJECT (self), "fp-image-device-state"); + + fpi_device_close_complete (FP_DEVICE (self), error); +diff --git a/libfprint/fpi-image-device.h b/libfprint/fpi-image-device.h +index 06d1a64..155390d 100644 +--- a/libfprint/fpi-image-device.h ++++ b/libfprint/fpi-image-device.h +@@ -23,11 +23,11 @@ + #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 ++ * FpiImageDeviceState: ++ * @FPI_IMAGE_DEVICE_STATE_INACTIVE: inactive ++ * @FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped ++ * @FPI_IMAGE_DEVICE_STATE_CAPTURE: capturing an image ++ * @FPI_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. +@@ -37,11 +37,11 @@ + * 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; ++ FPI_IMAGE_DEVICE_STATE_INACTIVE, ++ FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON, ++ FPI_IMAGE_DEVICE_STATE_CAPTURE, ++ FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF, ++} FpiImageDeviceState; + + /** + * FpImageDeviceClass: +@@ -90,8 +90,8 @@ struct _FpImageDeviceClass + void (*img_open) (FpImageDevice *dev); + void (*img_close) (FpImageDevice *dev); + void (*activate) (FpImageDevice *dev); +- void (*change_state) (FpImageDevice *dev, +- FpImageDeviceState state); ++ void (*change_state) (FpImageDevice *dev, ++ FpiImageDeviceState state); + void (*deactivate) (FpImageDevice *dev); + }; + +diff --git a/libfprint/fpi-print.c b/libfprint/fpi-print.c +index a407dd9..7a5e1e2 100644 +--- a/libfprint/fpi-print.c ++++ b/libfprint/fpi-print.c +@@ -38,15 +38,15 @@ + * @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 ++ * Appends the single #FPI_PRINT_NBIS print from @add to the collection of ++ * prints in @print. Both print objects need to be of type #FPI_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_return_if_fail (print->type == FPI_PRINT_NBIS); ++ g_return_if_fail (add->type == FPI_PRINT_NBIS); + + g_assert (add->prints->len == 1); + g_ptr_array_add (print->prints, g_memdup (add->prints->pdata[0], sizeof (struct xyt_struct))); +@@ -62,15 +62,15 @@ fpi_print_add_print (FpPrint *print, FpPrint *add) + * print passed during enrollment. + */ + void +-fpi_print_set_type (FpPrint *print, +- FpPrintType type) ++fpi_print_set_type (FpPrint *print, ++ FpiPrintType type) + { + g_return_if_fail (FP_IS_PRINT (print)); + /* We only allow setting this once! */ +- g_return_if_fail (print->type == FP_PRINT_UNDEFINED); ++ g_return_if_fail (print->type == FPI_PRINT_UNDEFINED); + + print->type = type; +- if (print->type == FP_PRINT_NBIS) ++ if (print->type == FPI_PRINT_NBIS) + { + g_assert_null (print->prints); + print->prints = g_ptr_array_new_with_free_func (g_free); +@@ -143,7 +143,7 @@ minutiae_to_xyt (struct fp_minutiae *minutiae, + * @error: Return location for error + * + * Extracts the minutiae from the given image and adds it to @print of +- * type #FP_PRINT_NBIS. ++ * type #FPI_PRINT_NBIS. + * + * The @image will be kept so that API users can get retrieve it e.g. + * for debugging purposes. +@@ -159,7 +159,7 @@ fpi_print_add_from_image (FpPrint *print, + struct fp_minutiae _minutiae; + struct xyt_struct *xyt; + +- if (print->type != FP_PRINT_NBIS || !image) ++ if (print->type != FPI_PRINT_NBIS || !image) + { + g_set_error (error, + G_IO_ERROR, +@@ -203,7 +203,7 @@ fpi_print_add_from_image (FpPrint *print, + * 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 ++ * Both @template and @print need to be of type #FPI_PRINT_NBIS for this to + * work. + * + * Returns: Whether the prints match, @error will be set if #FPI_MATCH_ERROR is returned +@@ -216,7 +216,7 @@ fpi_print_bz3_match (FpPrint *template, FpPrint *print, gint bz3_threshold, GErr + gint i; + + /* XXX: Use a different error type? */ +- if (template->type != FP_PRINT_NBIS || print->type != FP_PRINT_NBIS) ++ if (template->type != FPI_PRINT_NBIS || print->type != FPI_PRINT_NBIS) + { + *error = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, + "It is only possible to match NBIS type print data"); +diff --git a/libfprint/fpi-print.h b/libfprint/fpi-print.h +index 04500d6..c969f12 100644 +--- a/libfprint/fpi-print.h ++++ b/libfprint/fpi-print.h +@@ -7,16 +7,16 @@ + 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 ++ * FpiPrintType: ++ * @FPI_PRINT_UNDEFINED: Undefined type, this happens prior to enrollment ++ * @FPI_PRINT_RAW: A raw print where the data is directly compared ++ * @FPI_PRINT_NBIS: NBIS minutiae comparison + */ + typedef enum { +- FP_PRINT_UNDEFINED = 0, +- FP_PRINT_RAW, +- FP_PRINT_NBIS, +-} FpPrintType; ++ FPI_PRINT_UNDEFINED = 0, ++ FPI_PRINT_RAW, ++ FPI_PRINT_NBIS, ++} FpiPrintType; + + /** + * FpiMatchResult: +@@ -33,8 +33,8 @@ typedef enum { + void fpi_print_add_print (FpPrint *print, + FpPrint *add); + +-void fpi_print_set_type (FpPrint *print, +- FpPrintType type); ++void fpi_print_set_type (FpPrint *print, ++ FpiPrintType type); + void fpi_print_set_device_stored (FpPrint *print, + gboolean device_stored); + +diff --git a/tests/test-device-fake.c b/tests/test-device-fake.c +index e3b6f38..096d140 100644 +--- a/tests/test-device-fake.c ++++ b/tests/test-device-fake.c +@@ -35,7 +35,7 @@ fpi_device_fake_probe (FpDevice *device) + FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + +- g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_PROBE); ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_PROBE); + + fake_dev->last_called_function = fpi_device_fake_probe; + fpi_device_probe_complete (device, dev_class->id, dev_class->full_name, +@@ -47,7 +47,7 @@ fpi_device_fake_open (FpDevice *device) + { + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + +- g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_OPEN); ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_OPEN); + + fake_dev->last_called_function = fpi_device_fake_open; + fpi_device_open_complete (device, fake_dev->ret_error); +@@ -58,7 +58,7 @@ fpi_device_fake_close (FpDevice *device) + { + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + +- g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_CLOSE); ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_CLOSE); + + fake_dev->last_called_function = fpi_device_fake_close; + fpi_device_close_complete (device, fake_dev->ret_error); +@@ -70,7 +70,7 @@ fpi_device_fake_enroll (FpDevice *device) + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + FpPrint *print = fake_dev->ret_print; + +- g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_ENROLL); ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_ENROLL); + fpi_device_get_enroll_data (device, (FpPrint **) &fake_dev->action_data); + + if (!print && !fake_dev->ret_error) +@@ -86,7 +86,7 @@ fpi_device_fake_verify (FpDevice *device) + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + FpPrint *print = fake_dev->ret_print; + +- g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_VERIFY); ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_VERIFY); + fpi_device_get_verify_data (device, (FpPrint **) &fake_dev->action_data); + + if (!print && !fake_dev->ret_error) +@@ -103,7 +103,7 @@ fpi_device_fake_identify (FpDevice *device) + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + FpPrint *match = fake_dev->ret_match; + +- g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_IDENTIFY); ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_IDENTIFY); + fpi_device_get_identify_data (device, (GPtrArray **) &fake_dev->action_data); + + if (!match && !fake_dev->ret_error) +@@ -135,7 +135,7 @@ fpi_device_fake_capture (FpDevice *device) + { + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + +- g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_CAPTURE); ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_CAPTURE); + fpi_device_get_capture_data (device, (gboolean *) &fake_dev->action_data); + + fake_dev->last_called_function = fpi_device_fake_capture; +@@ -147,7 +147,7 @@ fpi_device_fake_list (FpDevice *device) + { + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + +- g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_LIST); ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_LIST); + + fake_dev->last_called_function = fpi_device_fake_list; + fpi_device_list_complete (device, fake_dev->ret_list, fake_dev->ret_error); +@@ -158,7 +158,7 @@ fpi_device_fake_delete (FpDevice *device) + { + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + +- g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_DELETE); ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_DELETE); + fpi_device_get_delete_data (device, (gpointer) & fake_dev->action_data); + + fake_dev->last_called_function = fpi_device_fake_delete; +@@ -170,7 +170,7 @@ fpi_device_fake_cancel (FpDevice *device) + { + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + +- g_assert_cmpuint (fpi_device_get_current_action (device), !=, FP_DEVICE_ACTION_NONE); ++ g_assert_cmpuint (fpi_device_get_current_action (device), !=, FPI_DEVICE_ACTION_NONE); + + fake_dev->last_called_function = fpi_device_fake_cancel; + } +diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c +index 165fc7f..b269ec4 100644 +--- a/tests/test-fpi-device.c ++++ b/tests/test-fpi-device.c +@@ -528,7 +528,7 @@ test_driver_enroll_progress (void) + device = auto_close_fake_device_new (); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, +- "*assertion*current_action*FP_DEVICE_ACTION_ENROLL*failed"); ++ "*assertion*current_action*FPI_DEVICE_ACTION_ENROLL*failed"); + fpi_device_enroll_progress (device, 0, NULL, NULL); + g_test_assert_expected_messages (); + +@@ -989,7 +989,7 @@ test_driver_current_action (void) + { + g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + +- g_assert_cmpint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_NONE); ++ g_assert_cmpint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_NONE); + } + + static void +@@ -997,7 +997,7 @@ test_driver_current_action_open_vfunc (FpDevice *device) + { + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + +- g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_OPEN); ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_OPEN); + fake_dev->last_called_function = test_driver_current_action_open_vfunc; + + fpi_device_open_complete (device, NULL); +@@ -1015,7 +1015,7 @@ test_driver_current_action_open (void) + fake_dev = FPI_DEVICE_FAKE (device); + g_assert (fake_dev->last_called_function == test_driver_current_action_open_vfunc); + +- g_assert_cmpint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_NONE); ++ g_assert_cmpint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_NONE); + } + + static void +@@ -1023,7 +1023,7 @@ test_driver_action_get_cancellable_open_vfunc (FpDevice *device) + { + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + +- g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_OPEN); ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_OPEN); + fake_dev->last_called_function = test_driver_action_get_cancellable_open_vfunc; + + g_assert_true (G_IS_CANCELLABLE (fpi_device_get_cancellable (device))); +@@ -1054,7 +1054,7 @@ test_driver_action_get_cancellable_open_fail_vfunc (FpDevice *device) + { + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + +- g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_OPEN); ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_OPEN); + fake_dev->last_called_function = test_driver_action_get_cancellable_open_fail_vfunc; + + g_assert_false (G_IS_CANCELLABLE (fpi_device_get_cancellable (device))); +@@ -1084,7 +1084,7 @@ test_driver_action_get_cancellable_error (void) + g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, +- "*assertion*current_action*FP_DEVICE_ACTION_NONE*failed"); ++ "*assertion*current_action*FPI_DEVICE_ACTION_NONE*failed"); + g_assert_null (fpi_device_get_cancellable (device)); + g_test_assert_expected_messages (); + } +@@ -1094,7 +1094,7 @@ test_driver_action_is_cancelled_open_vfunc (FpDevice *device) + { + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + +- g_assert_cmpuint (fpi_device_get_current_action (device), ==, FP_DEVICE_ACTION_OPEN); ++ g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_OPEN); + fake_dev->last_called_function = test_driver_action_is_cancelled_open_vfunc; + + g_assert_true (G_IS_CANCELLABLE (fpi_device_get_cancellable (device))); +@@ -1132,7 +1132,7 @@ test_driver_action_is_cancelled_error (void) + g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, +- "*assertion*current_action*FP_DEVICE_ACTION_NONE*failed"); ++ "*assertion*current_action*FPI_DEVICE_ACTION_NONE*failed"); + g_assert_true (fpi_device_action_is_cancelled (device)); + g_test_assert_expected_messages (); + } +@@ -1194,7 +1194,7 @@ test_driver_action_error_error (void) + g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, +- "*assertion*current_action*FP_DEVICE_ACTION_NONE*failed"); ++ "*assertion*current_action*FPI_DEVICE_ACTION_NONE*failed"); + fpi_device_action_error (device, NULL); + g_test_assert_expected_messages (); + } +-- +2.24.1 + diff --git a/SOURCES/0148-tests-Add-a-reference-to-the-enrolled-print-before-r.patch b/SOURCES/0148-tests-Add-a-reference-to-the-enrolled-print-before-r.patch new file mode 100644 index 0000000..7bcca1f --- /dev/null +++ b/SOURCES/0148-tests-Add-a-reference-to-the-enrolled-print-before-r.patch @@ -0,0 +1,64 @@ +From 006cef0a5f97c22c2860d419c8d48fd8c849b58b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 17 Dec 2019 03:28:12 +0100 +Subject: [PATCH 148/181] tests: Add a reference to the enrolled print before + returning it + +--- + tests/test-device-fake.c | 4 +++- + tests/test-fpi-device.c | 8 +++++--- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/tests/test-device-fake.c b/tests/test-device-fake.c +index 096d140..eaa1fa6 100644 +--- a/tests/test-device-fake.c ++++ b/tests/test-device-fake.c +@@ -77,7 +77,9 @@ fpi_device_fake_enroll (FpDevice *device) + fpi_device_get_enroll_data (device, &print); + + fake_dev->last_called_function = fpi_device_fake_enroll; +- fpi_device_enroll_complete (device, print, fake_dev->ret_error); ++ fpi_device_enroll_complete (device, ++ print ? g_object_ref (print) : NULL, ++ fake_dev->ret_error); + } + + static void +diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c +index b269ec4..398407a 100644 +--- a/tests/test-fpi-device.c ++++ b/tests/test-fpi-device.c +@@ -393,9 +393,9 @@ test_driver_enroll (void) + { + g_autoptr(GError) error = NULL; + g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); ++ g_autoptr(FpPrint) template_print = fp_print_new (device); + FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); +- FpPrint *template_print = fp_print_new (device); + FpPrint *out_print = NULL; + + out_print = +@@ -520,6 +520,7 @@ test_driver_enroll_progress (void) + { + g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); + g_autoptr(FpAutoCloseDevice) device = NULL; ++ g_autoptr(FpPrint) enrolled_print = NULL; + ExpectedEnrollData expected_enroll_data = {0}; + FpiDeviceFake *fake_dev; + +@@ -535,8 +536,9 @@ test_driver_enroll_progress (void) + fake_dev = FPI_DEVICE_FAKE (device); + fake_dev->user_data = &expected_enroll_data; + +- fp_device_enroll_sync (device, fp_print_new (device), NULL, +- test_driver_enroll_progress_callback, &expected_enroll_data, NULL); ++ enrolled_print = fp_device_enroll_sync (device, fp_print_new (device), NULL, ++ test_driver_enroll_progress_callback, ++ &expected_enroll_data, NULL); + + g_assert (fake_dev->last_called_function == test_driver_enroll_progress_vfunc); + } +-- +2.24.1 + diff --git a/SOURCES/0149-meson-Define-enum-dependency-and-ensure-we-generate-.patch b/SOURCES/0149-meson-Define-enum-dependency-and-ensure-we-generate-.patch new file mode 100644 index 0000000..73cf2ca --- /dev/null +++ b/SOURCES/0149-meson-Define-enum-dependency-and-ensure-we-generate-.patch @@ -0,0 +1,81 @@ +From ea3af999b3da79725b51411dc757919a23755f7e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 17 Dec 2019 07:02:16 +0100 +Subject: [PATCH 149/181] meson: Define enum dependency and ensure we generate + them before using + +Avoid setting the headers as sources everywhere, but instead use a dependency +to manage the headers creation in time +--- + libfprint/meson.build | 20 ++++++++++++++++---- + 1 file changed, 16 insertions(+), 4 deletions(-) + +diff --git a/libfprint/meson.build b/libfprint/meson.build +index 382fe76..d812cd9 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -184,6 +184,10 @@ fpi_enums = gnome.mkenums_simple('fpi-enums', + install_header : false) + fpi_enums_h = fpi_enums[1] + ++enums_dep = declare_dependency( ++ sources: [ fp_enums_h, fpi_enums_h ] ++) ++ + drivers_sources += configure_file(input: 'empty_file', + output: 'fpi-drivers.c', + capture: true, +@@ -193,6 +197,7 @@ drivers_sources += configure_file(input: 'empty_file', + ]) + + deps = [ ++ enums_dep, + gio_dep, + glib_dep, + gusb_dep, +@@ -218,13 +223,16 @@ libnbis = static_library('nbis', + install: false) + + libfprint_private = static_library('fprint-private', +- sources: libfprint_private_sources + fpi_enums + [ fp_enums_h ], ++ sources: [ ++ fpi_enums, ++ libfprint_private_sources, ++ ], + dependencies: deps, + link_with: libnbis, + install: false) + + libfprint_drivers = static_library('fprint-drivers', +- sources: drivers_sources + [ fp_enums_h ], ++ sources: drivers_sources, + c_args: drivers_cflags, + dependencies: deps, + link_with: libfprint_private, +@@ -234,7 +242,11 @@ mapfile = files('libfprint.ver') + vflag = '-Wl,--version-script,@0@/@1@'.format(meson.source_root(), mapfile[0]) + + libfprint = library('fprint', +- sources: libfprint_sources + fp_enums + other_sources, ++ sources: [ ++ fp_enums, ++ libfprint_sources, ++ other_sources, ++ ], + soversion: soversion, + version: libversion, + link_args : vflag, +@@ -244,9 +256,9 @@ libfprint = library('fprint', + install: true) + + libfprint_dep = declare_dependency(link_with: libfprint, +- sources: [ fp_enums_h ], + include_directories: root_inc, + dependencies: [ ++ enums_dep, + gio_dep, + glib_dep, + gusb_dep, +-- +2.24.1 + diff --git a/SOURCES/0150-meson-Fix-syntax-for-fpi_enums-generation-call.patch b/SOURCES/0150-meson-Fix-syntax-for-fpi_enums-generation-call.patch new file mode 100644 index 0000000..20f9801 --- /dev/null +++ b/SOURCES/0150-meson-Fix-syntax-for-fpi_enums-generation-call.patch @@ -0,0 +1,26 @@ +From 1dbc80528e416e7f7475b17cd9410af57273cf09 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 16 Dec 2019 19:00:36 +0100 +Subject: [PATCH 150/181] meson: Fix syntax for fpi_enums generation call + +--- + libfprint/meson.build | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/libfprint/meson.build b/libfprint/meson.build +index d812cd9..c4984e2 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -181,7 +181,8 @@ fp_enums_h = fp_enums[1] + + fpi_enums = gnome.mkenums_simple('fpi-enums', + sources: libfprint_private_headers, +- install_header : false) ++ install_header: false, ++) + fpi_enums_h = fpi_enums[1] + + enums_dep = declare_dependency( +-- +2.24.1 + diff --git a/SOURCES/0151-libfprint-Make-sure-we-install-fp-enums.h-in-the-rig.patch b/SOURCES/0151-libfprint-Make-sure-we-install-fp-enums.h-in-the-rig.patch new file mode 100644 index 0000000..63d543e --- /dev/null +++ b/SOURCES/0151-libfprint-Make-sure-we-install-fp-enums.h-in-the-rig.patch @@ -0,0 +1,30 @@ +From f3d202ff1c9e3f07a9b9526f17eb1d4e13b6f96b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 17 Dec 2019 15:39:24 +0100 +Subject: [PATCH 151/181] libfprint: Make sure we install fp-enums.h in the + right folder + +Since we were not explictly setting the install_dir, it was endind up in +$PREFIX/include by default, while we use our project name as subfolder. +--- + libfprint/meson.build | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/libfprint/meson.build b/libfprint/meson.build +index c4984e2..50df8a0 100644 +--- a/libfprint/meson.build ++++ b/libfprint/meson.build +@@ -176,7 +176,9 @@ other_sources = [] + + fp_enums = gnome.mkenums_simple('fp-enums', + sources: libfprint_public_headers, +- install_header : true) ++ install_header: true, ++ install_dir: get_option('includedir') / meson.project_name(), ++) + fp_enums_h = fp_enums[1] + + fpi_enums = gnome.mkenums_simple('fpi-enums', +-- +2.24.1 + diff --git a/SOURCES/0152-meson-Bump-dependency-on-0.49.0.patch b/SOURCES/0152-meson-Bump-dependency-on-0.49.0.patch new file mode 100644 index 0000000..60cd06c --- /dev/null +++ b/SOURCES/0152-meson-Bump-dependency-on-0.49.0.patch @@ -0,0 +1,30 @@ +From 28930f4b4016a992596b40abe31a8aeb315e4cd5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 17 Dec 2019 20:44:37 +0100 +Subject: [PATCH 152/181] meson: Bump dependency on 0.49.0 + +We're using some new features, and we may use more in future so better to +bump the version to the minimum required than look back given we're still +unstable. + +Fixes #204 +--- + meson.build | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/meson.build b/meson.build +index afd98db..c42cf2d 100644 +--- a/meson.build ++++ b/meson.build +@@ -6,7 +6,7 @@ project('libfprint', [ 'c', 'cpp' ], + 'warning_level=1', + 'c_std=c99', + ], +- meson_version: '>= 0.46.0') ++ meson_version: '>= 0.49.0') + + gnome = import('gnome') + +-- +2.24.1 + diff --git a/SOURCES/0153-Prefix-internal-properties-signals-with-fpi-and-anno.patch b/SOURCES/0153-Prefix-internal-properties-signals-with-fpi-and-anno.patch new file mode 100644 index 0000000..d2a8f79 --- /dev/null +++ b/SOURCES/0153-Prefix-internal-properties-signals-with-fpi-and-anno.patch @@ -0,0 +1,359 @@ +From 56edf22163089dba9314e4dd48449829a1110b40 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Wed, 18 Dec 2019 12:03:42 +0100 +Subject: [PATCH 153/181] Prefix internal properties/signals with fpi- and + annotate them + +We prefixed them with fp- which is not as obvious as fpi-. Also, +explicitly mark them as private and to be skipped in the GObject +Introspection annotatinos. + +Warning: FPrint: (Signal)fp-image-device-state-changed: argument object: Unresolved type: 'FpiImageDeviceState' +--- + libfprint/drivers/synaptics/synaptics.c | 8 +++---- + libfprint/drivers/upekts.c | 4 ++-- + libfprint/fp-context.c | 8 +++---- + libfprint/fp-device.c | 29 +++++++++++++++++++++---- + libfprint/fp-image-device.c | 20 +++++++++++++++-- + libfprint/fp-print.c | 22 +++++++++++++++---- + libfprint/fpi-image-device.c | 12 +++++----- + libfprint/fpi-print.c | 2 +- + tests/test-fpi-device.c | 6 ++--- + 9 files changed, 81 insertions(+), 30 deletions(-) + +diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c +index af4a2fd..2aac75e 100644 +--- a/libfprint/drivers/synaptics/synaptics.c ++++ b/libfprint/drivers/synaptics/synaptics.c +@@ -519,7 +519,7 @@ list_msg_cb (FpiDeviceSynaptics *self, + + fpi_print_set_type (print, FPI_PRINT_RAW); + fpi_print_set_device_stored (print, TRUE); +- g_object_set (print, "fp-data", data, NULL); ++ g_object_set (print, "fpi-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 */ +@@ -670,7 +670,7 @@ verify (FpDevice *device) + + fpi_device_get_verify_data (device, &print); + +- g_object_get (print, "fp-data", &data, NULL); ++ g_object_get (print, "fpi-data", &data, NULL); + g_debug ("data is %p", data); + if (!parse_print_data (data, &finger, &user_id, &user_id_len)) + { +@@ -858,7 +858,7 @@ enroll (FpDevice *device) + + fpi_print_set_type (print, FPI_PRINT_RAW); + fpi_print_set_device_stored (print, TRUE); +- g_object_set (print, "fp-data", data, NULL); ++ g_object_set (print, "fpi-data", data, NULL); + g_object_set (print, "description", user_id, NULL); + + g_debug ("user_id: %s, finger: %d", user_id, finger); +@@ -927,7 +927,7 @@ delete_print (FpDevice *device) + + fpi_device_get_delete_data (device, &print); + +- g_object_get (print, "fp-data", &data, NULL); ++ g_object_get (print, "fpi-data", &data, NULL); + g_debug ("data is %p", data); + if (!parse_print_data (data, &finger, &user_id, &user_id_len)) + { +diff --git a/libfprint/drivers/upekts.c b/libfprint/drivers/upekts.c +index 6ce8136..16534d3 100644 +--- a/libfprint/drivers/upekts.c ++++ b/libfprint/drivers/upekts.c +@@ -1126,7 +1126,7 @@ e_handle_resp02 (FpDevice *dev, unsigned char *data, + data_len - sizeof (scan_comp), + 1); + +- g_object_set (print, "fp-data", fp_data, NULL); ++ g_object_set (print, "fpi-data", fp_data, NULL); + g_object_ref (print); + } + +@@ -1293,7 +1293,7 @@ verify_start_sm_run_state (FpiSsm *ssm, FpDevice *dev) + + case VERIFY_INIT: + fpi_device_get_verify_data (dev, &print); +- g_object_get (dev, "fp-data", &fp_data, NULL); ++ g_object_get (dev, "fpi-data", &fp_data, NULL); + + data = g_variant_get_fixed_array (fp_data, &data_len, 1); + +diff --git a/libfprint/fp-context.c b/libfprint/fp-context.c +index f64968d..0e7c17f 100644 +--- a/libfprint/fp-context.c ++++ b/libfprint/fp-context.c +@@ -170,8 +170,8 @@ usb_device_added_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx) + priv->cancellable, + async_device_init_done_cb, + self, +- "fp-usb-device", device, +- "fp-driver-data", found_entry->driver_data, ++ "fpi-usb-device", device, ++ "fpi-driver-data", found_entry->driver_data, + NULL); + } + +@@ -373,8 +373,8 @@ fp_context_enumerate (FpContext *context) + priv->cancellable, + async_device_init_done_cb, + context, +- "fp-environ", val, +- "fp-driver-data", entry->driver_data, ++ "fpi-environ", val, ++ "fpi-driver-data", entry->driver_data, + NULL); + g_debug ("created"); + } +diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c +index 8041a86..116f9f8 100644 +--- a/libfprint/fp-device.c ++++ b/libfprint/fp-device.c +@@ -342,22 +342,43 @@ fp_device_class_init (FpDeviceClass *klass) + "Wether the device is open or not", FALSE, + G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); + ++ /** ++ * FpDevice::fpi-environ: (skip) ++ * ++ * This property is only for internal purposes. ++ * ++ * Stability: private ++ */ + properties[PROP_FPI_ENVIRON] = +- g_param_spec_string ("fp-environ", ++ g_param_spec_string ("fpi-environ", + "Virtual Environment", + "Private: The environment variable for the virtual device", + NULL, + G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); + ++ /** ++ * FpDevice::fpi-usb-device: (skip) ++ * ++ * This property is only for internal purposes. ++ * ++ * Stability: private ++ */ + properties[PROP_FPI_USB_DEVICE] = +- g_param_spec_object ("fp-usb-device", ++ g_param_spec_object ("fpi-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); + ++ /** ++ * FpDevice::fpi-driver-data: (skip) ++ * ++ * This property is only for internal purposes. ++ * ++ * Stability: private ++ */ + properties[PROP_FPI_DRIVER_DATA] = +- g_param_spec_uint64 ("fp-driver-data", ++ g_param_spec_uint64 ("fpi-driver-data", + "Driver Data", + "Private: The driver data from the ID table entry", + 0, +@@ -737,7 +758,7 @@ fp_device_enroll (FpDevice *device, + return; + } + +- g_object_get (template_print, "fp-type", &print_type, NULL); ++ g_object_get (template_print, "fpi-type", &print_type, NULL); + if (print_type != FPI_PRINT_UNDEFINED) + { + g_warning ("Passed print template must be newly created and blank!"); +diff --git a/libfprint/fp-image-device.c b/libfprint/fp-image-device.c +index 9e6c375..20e181e 100644 +--- a/libfprint/fp-image-device.c ++++ b/libfprint/fp-image-device.c +@@ -267,16 +267,32 @@ fp_image_device_class_init (FpImageDeviceClass *klass) + klass->activate = fp_image_device_default_activate; + klass->deactivate = fp_image_device_default_deactivate; + ++ /** ++ * FpImageDevice::fpi-image-device-state: (skip) ++ * ++ * This property is only for internal purposes. ++ * ++ * Stability: private ++ */ + properties[PROP_FPI_STATE] = +- g_param_spec_enum ("fp-image-device-state", ++ g_param_spec_enum ("fpi-image-device-state", + "Image Device State", + "Private: The state of the image device", + FPI_TYPE_IMAGE_DEVICE_STATE, + FPI_IMAGE_DEVICE_STATE_INACTIVE, + G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); + ++ /** ++ * FpImageDevice::fpi-image-device-state-changed: (skip) ++ * @image_device: A #FpImageDevice ++ * @new_state: The new state of the device ++ * ++ * This signal is only for internal purposes. ++ * ++ * Stability: private ++ */ + signals[FPI_STATE_CHANGED] = +- g_signal_new ("fp-image-device-state-changed", ++ g_signal_new ("fpi-image-device-state-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (FpImageDeviceClass, change_state), +diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c +index dd45b95..34139ce 100644 +--- a/libfprint/fp-print.c ++++ b/libfprint/fp-print.c +@@ -268,16 +268,30 @@ fp_print_class_init (FpPrintClass *klass) + G_TYPE_DATE, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); + ++ /** ++ * FpPrint::fpi-type: (skip) ++ * ++ * This property is only for internal purposes. ++ * ++ * Stability: private ++ */ + properties[PROP_FPI_TYPE] = +- g_param_spec_enum ("fp-type", ++ g_param_spec_enum ("fpi-type", + "Type", + "Private: The type of the print data", + FPI_TYPE_PRINT_TYPE, + FPI_PRINT_RAW, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + ++ /** ++ * FpPrint::fpi-data: (skip) ++ * ++ * This property is only for internal purposes. ++ * ++ * Stability: private ++ */ + properties[PROP_FPI_DATA] = +- g_param_spec_variant ("fp-data", ++ g_param_spec_variant ("fpi-data", + "Raw Data", + "The raw data for internal use only", + G_VARIANT_TYPE_ANY, +@@ -846,11 +860,11 @@ fp_print_deserialize (const guchar *data, + g_autoptr(GVariant) fp_data = g_variant_get_child_value (print_data, 0); + + result = g_object_new (FP_TYPE_PRINT, +- "fp-type", type, ++ "fpi-type", type, + "driver", driver, + "device-id", device_id, + "device-stored", device_stored, +- "fp-data", fp_data, ++ "fpi-data", fp_data, + NULL); + } + else +diff --git a/libfprint/fpi-image-device.c b/libfprint/fpi-image-device.c +index e03d60c..975e3a1 100644 +--- a/libfprint/fpi-image-device.c ++++ b/libfprint/fpi-image-device.c +@@ -55,7 +55,7 @@ fpi_image_device_activate (FpImageDevice *self) + /* We don't have a neutral ACTIVE state, but we always will + * go into WAIT_FINGER_ON afterwards. */ + priv->state = FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON; +- g_object_notify (G_OBJECT (self), "fp-image-device-state"); ++ g_object_notify (G_OBJECT (self), "fpi-image-device-state"); + + /* We might have been waiting for deactivation to finish before + * starting the next operation. */ +@@ -83,7 +83,7 @@ fpi_image_device_deactivate (FpImageDevice *self) + g_warning ("Deactivating image device while waiting for finger, this should not happen."); + + priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE; +- g_object_notify (G_OBJECT (self), "fp-image-device-state"); ++ g_object_notify (G_OBJECT (self), "fpi-image-device-state"); + + fp_dbg ("Deactivating image device\n"); + cls->deactivate (self); +@@ -106,8 +106,8 @@ fp_image_device_change_state (FpImageDevice *self, FpiImageDeviceState state) + fp_dbg ("Image device internal state change from %d to %d\n", priv->state, state); + + priv->state = state; +- g_object_notify (G_OBJECT (self), "fp-image-device-state"); +- g_signal_emit_by_name (self, "fp-image-device-state-changed", priv->state); ++ g_object_notify (G_OBJECT (self), "fpi-image-device-state"); ++ g_signal_emit_by_name (self, "fpi-image-device-state-changed", priv->state); + } + + static void +@@ -563,7 +563,7 @@ fpi_image_device_open_complete (FpImageDevice *self, GError *error) + g_debug ("Image device open completed"); + + priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE; +- g_object_notify (G_OBJECT (self), "fp-image-device-state"); ++ g_object_notify (G_OBJECT (self), "fpi-image-device-state"); + + fpi_device_open_complete (FP_DEVICE (self), error); + } +@@ -589,7 +589,7 @@ fpi_image_device_close_complete (FpImageDevice *self, GError *error) + g_return_if_fail (action == FPI_DEVICE_ACTION_CLOSE); + + priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE; +- g_object_notify (G_OBJECT (self), "fp-image-device-state"); ++ g_object_notify (G_OBJECT (self), "fpi-image-device-state"); + + fpi_device_close_complete (FP_DEVICE (self), error); + } +diff --git a/libfprint/fpi-print.c b/libfprint/fpi-print.c +index 7a5e1e2..4e3ed03 100644 +--- a/libfprint/fpi-print.c ++++ b/libfprint/fpi-print.c +@@ -75,7 +75,7 @@ fpi_print_set_type (FpPrint *print, + g_assert_null (print->prints); + print->prints = g_ptr_array_new_with_free_func (g_free); + } +- g_object_notify (G_OBJECT (print), "fp-type"); ++ g_object_notify (G_OBJECT (print), "fpi-type"); + } + + /** +diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c +index 398407a..3fa800c 100644 +--- a/tests/test-fpi-device.c ++++ b/tests/test-fpi-device.c +@@ -240,7 +240,7 @@ test_driver_get_usb_device (void) + g_autoptr(FpDevice) device = NULL; + + dev_class->type = FP_DEVICE_TYPE_USB; +- device = g_object_new (FPI_TYPE_DEVICE_FAKE, "fp-usb-device", NULL); ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, "fpi-usb-device", NULL); + g_assert_null (fpi_device_get_usb_device (device)); + + g_clear_object (&device); +@@ -259,7 +259,7 @@ test_driver_get_virtual_env (void) + g_autoptr(FpDevice) device = NULL; + + dev_class->type = FP_DEVICE_TYPE_VIRTUAL; +- device = g_object_new (FPI_TYPE_DEVICE_FAKE, "fp-environ", "TEST_VIRTUAL_ENV_GETTER", NULL); ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, "fpi-environ", "TEST_VIRTUAL_ENV_GETTER", NULL); + g_assert_cmpstr (fpi_device_get_virtual_env (device), ==, "TEST_VIRTUAL_ENV_GETTER"); + + g_clear_object (&device); +@@ -278,7 +278,7 @@ test_driver_get_driver_data (void) + guint64 driver_data; + + driver_data = g_random_int (); +- device = g_object_new (FPI_TYPE_DEVICE_FAKE, "fp-driver-data", driver_data, NULL); ++ device = g_object_new (FPI_TYPE_DEVICE_FAKE, "fpi-driver-data", driver_data, NULL); + g_assert_cmpuint (fpi_device_get_driver_data (device), ==, driver_data); + } + +-- +2.24.1 + diff --git a/SOURCES/0154-fp-print-Add-aliases-for-First-and-Last-finger-in-ou.patch b/SOURCES/0154-fp-print-Add-aliases-for-First-and-Last-finger-in-ou.patch new file mode 100644 index 0000000..fc845b2 --- /dev/null +++ b/SOURCES/0154-fp-print-Add-aliases-for-First-and-Last-finger-in-ou.patch @@ -0,0 +1,42 @@ +From 6d99612cd0144b7a39451f840a77257d2113ba8f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 17 Dec 2019 18:15:12 +0100 +Subject: [PATCH 154/181] fp-print: Add aliases for First and Last finger in + our order + +We might want to iterate through the supported fingers values, to do that we +were hardcoding FP_FINGER_LEFT_THUMB and FP_FINGER_RIGHT_LITTLE as first and +last fingers. + +Not that we'd ever get more fingers (unless some weird radiation would do +the job), but it's logically nicer to read than random hardcoded values. +--- + libfprint/fp-print.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/libfprint/fp-print.h b/libfprint/fp-print.h +index fcb9532..94034ce 100644 +--- a/libfprint/fp-print.h ++++ b/libfprint/fp-print.h +@@ -43,6 +43,8 @@ G_DECLARE_FINAL_TYPE (FpPrint, fp_print, FP, PRINT, GInitiallyUnowned) + * @FP_FINGER_RIGHT_MIDDLE: Right middle finger + * @FP_FINGER_RIGHT_RING: Right ring finger + * @FP_FINGER_RIGHT_LITTLE: Right little finger ++ * @FP_FINGER_FIRST: The first finger in the fp-print order ++ * @FP_FINGER_LAST: The last finger in the fp-print order + */ + typedef enum { + FP_FINGER_UNKNOWN = 0, +@@ -56,6 +58,9 @@ typedef enum { + FP_FINGER_RIGHT_MIDDLE, + FP_FINGER_RIGHT_RING, + FP_FINGER_RIGHT_LITTLE, ++ ++ FP_FINGER_FIRST = FP_FINGER_LEFT_THUMB, ++ FP_FINGER_LAST = FP_FINGER_RIGHT_LITTLE, + } FpFinger; + + FpPrint *fp_print_new (FpDevice *device); +-- +2.24.1 + diff --git a/SOURCES/0155-examples-Iterate-through-fingers-via-first-last-refs.patch b/SOURCES/0155-examples-Iterate-through-fingers-via-first-last-refs.patch new file mode 100644 index 0000000..2840980 --- /dev/null +++ b/SOURCES/0155-examples-Iterate-through-fingers-via-first-last-refs.patch @@ -0,0 +1,54 @@ +From b14c87acb78f458ed27c80ef2a18d829bc982565 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 17 Dec 2019 18:15:37 +0100 +Subject: [PATCH 155/181] examples: Iterate through fingers via first/last refs + +--- + examples/utilities.c | 26 ++++++++------------------ + 1 file changed, 8 insertions(+), 18 deletions(-) + +diff --git a/examples/utilities.c b/examples/utilities.c +index 379ad0a..eb18600 100644 +--- a/examples/utilities.c ++++ b/examples/utilities.c +@@ -107,29 +107,19 @@ finger_to_string (FpFinger finger) + 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)); ++ int i = FP_FINGER_UNKNOWN; ++ ++ for (i = FP_FINGER_FIRST; i <= FP_FINGER_LAST; ++i) ++ g_print (" [%d] %s\n", (i - FP_FINGER_FIRST), finger_to_string (i)); + + g_print ("> "); + if (!scanf ("%d%*c", &i)) + return FP_FINGER_UNKNOWN; + +- if (i < 0 || i >= G_N_ELEMENTS (all_fingers)) ++ i += FP_FINGER_FIRST; ++ ++ if (i < FP_FINGER_FIRST || i > FP_FINGER_LAST) + return FP_FINGER_UNKNOWN; + +- return all_fingers[i]; ++ return i; + } +-- +2.24.1 + diff --git a/SOURCES/0156-fp-print-Add-FP_FINGER_IS_VALID.patch b/SOURCES/0156-fp-print-Add-FP_FINGER_IS_VALID.patch new file mode 100644 index 0000000..20fe0cc --- /dev/null +++ b/SOURCES/0156-fp-print-Add-FP_FINGER_IS_VALID.patch @@ -0,0 +1,28 @@ +From 24ce1c7cf833a0c1518fa7e70e210db35f201ac8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 19 Dec 2019 14:20:00 +0100 +Subject: [PATCH 156/181] fp-print: Add FP_FINGER_IS_VALID + +This is coming directly from fprintd, but being something generic is better +to have it insinde libfprint itself. +--- + libfprint/fp-print.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/libfprint/fp-print.h b/libfprint/fp-print.h +index 94034ce..3408e73 100644 +--- a/libfprint/fp-print.h ++++ b/libfprint/fp-print.h +@@ -28,6 +28,9 @@ G_BEGIN_DECLS + #define FP_TYPE_PRINT (fp_print_get_type ()) + G_DECLARE_FINAL_TYPE (FpPrint, fp_print, FP, PRINT, GInitiallyUnowned) + ++#define FP_FINGER_IS_VALID(finger) \ ++ ((finger) >= FP_FINGER_FIRST && (finger) <= FP_FINGER_LAST) ++ + #include "fp-device.h" + + /** +-- +2.24.1 + diff --git a/SOURCES/0157-fpi-assembling-Accept-error-of-zero.patch b/SOURCES/0157-fpi-assembling-Accept-error-of-zero.patch new file mode 100644 index 0000000..2601bb4 --- /dev/null +++ b/SOURCES/0157-fpi-assembling-Accept-error-of-zero.patch @@ -0,0 +1,38 @@ +From 09f55e077d69eee3be745be740363151b7b10c8d Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Fri, 6 Dec 2019 18:54:49 +0100 +Subject: [PATCH 157/181] fpi-assembling: Accept error of zero + +Rather than discarding a zero error, check that the constraints are +sane. This way a perfect match is possible. +--- + libfprint/fpi-assembling.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libfprint/fpi-assembling.c b/libfprint/fpi-assembling.c +index 2b55ee3..a809a2d 100644 +--- a/libfprint/fpi-assembling.c ++++ b/libfprint/fpi-assembling.c +@@ -52,6 +52,9 @@ calc_error (struct fpi_frame_asmbl_ctx *ctx, + width = ctx->frame_width - (dx > 0 ? dx : -dx); + height = ctx->frame_height - dy; + ++ if (height == 0 || width == 0) ++ return INT_MAX; ++ + y1 = 0; + y2 = dy; + i = 0; +@@ -86,9 +89,6 @@ calc_error (struct fpi_frame_asmbl_ctx *ctx, + err *= (ctx->frame_height * ctx->frame_width); + err /= (height * width); + +- if (err == 0) +- return INT_MAX; +- + return err; + } + +-- +2.24.1 + diff --git a/SOURCES/0158-fpi-assembling-Fix-offsets-to-be-relative-to-the-pre.patch b/SOURCES/0158-fpi-assembling-Fix-offsets-to-be-relative-to-the-pre.patch new file mode 100644 index 0000000..9af713b --- /dev/null +++ b/SOURCES/0158-fpi-assembling-Fix-offsets-to-be-relative-to-the-pre.patch @@ -0,0 +1,114 @@ +From 9b0c2e8bad87100f042144bc251b60b64f646c99 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Fri, 6 Dec 2019 18:55:52 +0100 +Subject: [PATCH 158/181] fpi-assembling: Fix offsets to be relative to the + previous frame + +The offset stored for a frame was not always relative to the previous +frame. This was the case for reverse movement, but for forwrad movement +the offset was the one to the next frame. + +Make the offset handling consistent and alwasy store the offset to the +previous frame. Also update the frame assembling code to add the offset +before blitting the frame (i.e. making it relative to the previous frame +there too). + +Note that fpi_assemble_lines already made the assumption that this was +the case as it forced the offset for the first frame to be zero. As +such, the code was inconsistent. + +This could affect the AES drivers slightly as they use hardware reported +values which might not adhere to these assumptions. +--- + libfprint/fpi-assembling.c | 34 +++++++++++++++++----------------- + 1 file changed, 17 insertions(+), 17 deletions(-) + +diff --git a/libfprint/fpi-assembling.c b/libfprint/fpi-assembling.c +index a809a2d..6d34679 100644 +--- a/libfprint/fpi-assembling.c ++++ b/libfprint/fpi-assembling.c +@@ -99,6 +99,8 @@ static void + find_overlap (struct fpi_frame_asmbl_ctx *ctx, + struct fpi_frame *first_frame, + struct fpi_frame *second_frame, ++ int *dx_out, ++ int *dy_out, + unsigned int *min_error) + { + int dx, dy; +@@ -120,8 +122,8 @@ find_overlap (struct fpi_frame_asmbl_ctx *ctx, + if (err < *min_error) + { + *min_error = err; +- second_frame->delta_x = -dx; +- second_frame->delta_y = dy; ++ *dx_out = -dx; ++ *dy_out = dy; + } + } + } +@@ -133,7 +135,7 @@ do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx, + { + GSList *l; + GTimer *timer; +- guint num_frames = 0; ++ guint num_frames = 1; + struct fpi_frame *prev_stripe; + unsigned int min_error; + /* Max error is width * height * 255, for AES2501 which has the largest +@@ -143,20 +145,27 @@ do_movement_estimation (struct fpi_frame_asmbl_ctx *ctx, + unsigned long long total_error = 0; + + timer = g_timer_new (); ++ ++ /* Skip the first frame */ + prev_stripe = stripes->data; +- for (l = stripes; l != NULL; l = l->next, num_frames++) ++ ++ for (l = stripes->next; l != NULL; l = l->next, num_frames++) + { + struct fpi_frame *cur_stripe = l->data; + + if (reverse) + { +- find_overlap (ctx, prev_stripe, cur_stripe, &min_error); ++ find_overlap (ctx, prev_stripe, cur_stripe, ++ &cur_stripe->delta_x, &cur_stripe->delta_y, ++ &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); ++ find_overlap (ctx, cur_stripe, prev_stripe, ++ &cur_stripe->delta_x, &cur_stripe->delta_y, ++ &min_error); + } + total_error += min_error; + +@@ -328,19 +337,10 @@ fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx, + { + fpi_frame = l->data; + +- if(reverse) +- { +- y += fpi_frame->delta_y; +- x += fpi_frame->delta_x; +- } ++ y += fpi_frame->delta_y; ++ x += fpi_frame->delta_x; + + aes_blit_stripe (ctx, img, fpi_frame, x, y); +- +- if(!reverse) +- { +- y += fpi_frame->delta_y; +- x += fpi_frame->delta_x; +- } + } + + return img; +-- +2.24.1 + diff --git a/SOURCES/0159-tests-Set-MESON_SOURCE_ROOT-to-source-root-not-build.patch b/SOURCES/0159-tests-Set-MESON_SOURCE_ROOT-to-source-root-not-build.patch new file mode 100644 index 0000000..1263283 --- /dev/null +++ b/SOURCES/0159-tests-Set-MESON_SOURCE_ROOT-to-source-root-not-build.patch @@ -0,0 +1,26 @@ +From 339aee40ef38c60602c838fa41d278ce5897a9e7 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 9 Dec 2019 11:51:12 +0100 +Subject: [PATCH 159/181] tests: Set MESON_SOURCE_ROOT to source root not build + root + +--- + tests/meson.build | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/meson.build b/tests/meson.build +index b4022a4..8ab3791 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -4,7 +4,7 @@ envs.set('G_DEBUG', 'fatal-warnings') + envs.set('G_MESSAGES_DEBUG', 'all') + + # Setup paths +-envs.set('MESON_SOURCE_ROOT', meson.build_root()) ++envs.set('MESON_SOURCE_ROOT', meson.source_root()) + 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 +-- +2.24.1 + diff --git a/SOURCES/0160-tests-Add-some-frame-assembly-unit-tests.patch b/SOURCES/0160-tests-Add-some-frame-assembly-unit-tests.patch new file mode 100644 index 0000000..d66e87a --- /dev/null +++ b/SOURCES/0160-tests-Add-some-frame-assembly-unit-tests.patch @@ -0,0 +1,226 @@ +From 7f3216fa9c25a4de000d334411d4ca63aa58dee5 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 9 Dec 2019 11:52:05 +0100 +Subject: [PATCH 160/181] tests: Add some frame assembly unit tests + +--- + meson.build | 3 + + tests/meson.build | 35 +++++++++- + tests/test-fpi-assembling.c | 135 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 171 insertions(+), 2 deletions(-) + create mode 100644 tests/test-fpi-assembling.c + +diff --git a/meson.build b/meson.build +index c42cf2d..96700f6 100644 +--- a/meson.build ++++ b/meson.build +@@ -82,6 +82,9 @@ gio_dep = dependency('gio-unix-2.0', version: '>=' + glib_min_version) + gusb_dep = dependency('gusb', version: '>= 0.3.0') + mathlib_dep = cc.find_library('m', required: false) + ++# The following dependencies are only used for tests ++cairo_dep = dependency('cairo', required: false) ++ + # Drivers + drivers = get_option('drivers').split(',') + virtual_drivers = [ 'virtual_image' ] +diff --git a/tests/meson.build b/tests/meson.build +index 8ab3791..29ff6af 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -59,6 +59,7 @@ test_utils = static_library('fprint-test-utils', + unit_tests = [ + 'fpi-device', + 'fpi-ssm', ++ 'fpi-assembling', + ] + + if 'virtual_image' in drivers +@@ -68,11 +69,41 @@ if 'virtual_image' in drivers + ] + endif + ++unit_tests_deps = { 'fpi-assembling' : [cairo_dep] } ++ ++test_config = configuration_data() ++test_config.set_quoted('SOURCE_ROOT', meson.source_root()) ++test_config_h = configure_file(output: 'test-config.h', configuration: test_config) ++ + foreach test_name: unit_tests ++ if unit_tests_deps.has_key(test_name) ++ missing_deps = false ++ foreach dep: unit_tests_deps[test_name] ++ if not dep.found() ++ missing_deps = true ++ break ++ endif ++ endforeach ++ ++ if missing_deps ++ # Create a dummy test that always skips instead ++ warning('Test @0@ cannot be compiled due to missing dependencies'.format(test_name)) ++ test(test_name, ++ find_program('sh'), ++ suite: ['unit-tests'], ++ args: ['-c', 'exit 77'], ++ ) ++ continue ++ endif ++ extra_deps = unit_tests_deps[test_name] ++ else ++ extra_deps = [] ++ endif ++ + basename = 'test-' + test_name + test_exe = executable(basename, +- sources: basename + '.c', +- dependencies: libfprint_private_dep, ++ sources: [basename + '.c', test_config_h], ++ dependencies: [ libfprint_private_dep ] + extra_deps, + c_args: common_cflags, + link_with: test_utils, + ) +diff --git a/tests/test-fpi-assembling.c b/tests/test-fpi-assembling.c +new file mode 100644 +index 0000000..c5b1bca +--- /dev/null ++++ b/tests/test-fpi-assembling.c +@@ -0,0 +1,135 @@ ++/* ++ * Example fingerprint device prints listing and deletion ++ * Enrolls your right index finger and saves the print to disk ++ * 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 ++#include ++#include "fpi-assembling.h" ++#include "fpi-image.h" ++#include "test-config.h" ++ ++typedef struct ++{ ++ struct fpi_frame frame; ++ cairo_surface_t *surf; ++ guchar *data; ++ guint stride; ++ guint width; ++ guint height; ++ guint x; ++ guint y; ++} cairo_frame; ++ ++static unsigned char ++cairo_get_pixel (struct fpi_frame_asmbl_ctx *ctx, ++ struct fpi_frame *frame, ++ unsigned int x, ++ unsigned int y) ++{ ++ cairo_frame *c_frame = (void *) frame; /* Indirect cast to avoid alignment warning. */ ++ ++ x = x + c_frame->x; ++ y = y + c_frame->y; ++ ++ g_assert (x < c_frame->width); ++ g_assert (y < c_frame->height); ++ ++ return c_frame->data[x * 4 + y * c_frame->stride + 1]; ++} ++ ++static void ++test_frame_assembling (void) ++{ ++ g_autofree char *path = NULL; ++ cairo_surface_t *img = NULL; ++ int width, height, stride, offset; ++ int test_height; ++ guchar *data; ++ struct fpi_frame_asmbl_ctx ctx = { 0, }; ++ ++ g_autoptr(FpImage) fp_img = NULL; ++ GSList *frames = NULL; ++ ++ g_assert_false (SOURCE_ROOT == NULL); ++ path = g_build_path (G_DIR_SEPARATOR_S, SOURCE_ROOT, "tests", "vfs5011", "capture.png", NULL); ++ ++ img = cairo_image_surface_create_from_png (path); ++ data = cairo_image_surface_get_data (img); ++ width = cairo_image_surface_get_width (img); ++ height = cairo_image_surface_get_height (img); ++ stride = cairo_image_surface_get_stride (img); ++ g_assert_cmpint (cairo_image_surface_get_format (img), ==, CAIRO_FORMAT_RGB24); ++ ++ ctx.get_pixel = cairo_get_pixel; ++ ctx.frame_width = width; ++ ctx.frame_height = 20; ++ ctx.image_width = width; ++ ++ offset = 10; ++ test_height = height - (height - ctx.frame_height) % offset; ++ ++ /* for now, fixed offset */ ++ for (int y = 0; y + ctx.frame_height < height; y += offset) ++ { ++ cairo_frame *frame = g_new0 (cairo_frame, 1); ++ ++ frame->surf = img; ++ frame->width = width; ++ frame->height = height; ++ frame->stride = stride; ++ frame->data = data; ++ frame->x = 0; ++ frame->y = y; ++ //frame->y = test_height - ctx.frame_height - y; ++ ++ frames = g_slist_append (frames, frame); ++ } ++ //offset = -offset; ++ ++ fpi_do_movement_estimation (&ctx, frames); ++ for (GSList *l = frames->next; l != NULL; l = l->next) ++ { ++ cairo_frame * frame = l->data; ++ ++ g_assert_cmpint (frame->frame.delta_x, ==, 0); ++ g_assert_cmpint (frame->frame.delta_y, ==, offset); ++ } ++ ++ fp_img = fpi_assemble_frames (&ctx, frames); ++ g_assert_cmpint (fp_img->height, ==, test_height); ++ ++ /* The FpImage and cairo surface need to be identical in the test area */ ++ for (int y = 0; y < test_height; y++) ++ for (int x = 0; x < width; x++) ++ g_assert_cmpint (data[x * 4 + y * stride + 1], ==, fp_img->data[x + y * width]); ++ ++ g_slist_free_full (frames, g_free); ++ cairo_surface_destroy (img); ++ g_assert (1); ++} ++ ++int ++main (int argc, char *argv[]) ++{ ++ g_test_init (&argc, &argv, NULL); ++ ++ g_test_add_func ("/assembling/frames", test_frame_assembling); ++ ++ return g_test_run (); ++} +-- +2.24.1 + diff --git a/SOURCES/0161-examples-Fix-possible-use-after-free-in-storage-code.patch b/SOURCES/0161-examples-Fix-possible-use-after-free-in-storage-code.patch new file mode 100644 index 0000000..17911fc --- /dev/null +++ b/SOURCES/0161-examples-Fix-possible-use-after-free-in-storage-code.patch @@ -0,0 +1,41 @@ +From 8bfb572b5847e271fac49b24c9ceb1a5ea3bdf5d Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Thu, 2 Jan 2020 18:38:19 +0100 +Subject: [PATCH 161/181] examples: Fix possible use-after-free in storage code + +The variant may need the buffer, so we should only free the buffer +together with the variant. +--- + examples/storage.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/examples/storage.c b/examples/storage.c +index 6ca6efc..bb69305 100644 +--- a/examples/storage.c ++++ b/examples/storage.c +@@ -57,7 +57,7 @@ load_data (void) + { + GVariantDict *res; + GVariant *var; +- g_autofree gchar *contents = NULL; ++ gchar *contents = NULL; + gsize length = 0; + + if (!g_file_get_contents (STORAGE_FILE, &contents, &length, NULL)) +@@ -66,7 +66,12 @@ load_data (void) + 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, ++ g_free, ++ contents); + + res = g_variant_dict_new (var); + g_variant_unref (var); +-- +2.24.1 + diff --git a/SOURCES/0162-examples-Do-not-free-data-returned-by-g_variant_get_.patch b/SOURCES/0162-examples-Do-not-free-data-returned-by-g_variant_get_.patch new file mode 100644 index 0000000..078b9fa --- /dev/null +++ b/SOURCES/0162-examples-Do-not-free-data-returned-by-g_variant_get_.patch @@ -0,0 +1,36 @@ +From 245725eada9f2a89a4b38b7151bf9e2c29622749 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Thu, 2 Jan 2020 18:39:57 +0100 +Subject: [PATCH 162/181] examples: Do not free data returned by + g_variant_get_fixed_array + +This data is owned by the variant, so do not free it. +--- + examples/storage.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/examples/storage.c b/examples/storage.c +index bb69305..14a6432 100644 +--- a/examples/storage.c ++++ b/examples/storage.c +@@ -134,7 +134,7 @@ print_data_load (FpDevice *dev, FpFinger finger) + + g_autoptr(GVariant) val = NULL; + g_autoptr(GVariantDict) dict = NULL; +- g_autofree guchar *stored_data = NULL; ++ const guchar *stored_data = NULL; + gsize stored_len; + + dict = load_data (); +@@ -145,7 +145,7 @@ print_data_load (FpDevice *dev, FpFinger finger) + FpPrint *print; + g_autoptr(GError) error = NULL; + +- stored_data = (guchar *) g_variant_get_fixed_array (val, &stored_len, 1); ++ stored_data = (const guchar *) g_variant_get_fixed_array (val, &stored_len, 1); + print = fp_print_deserialize (stored_data, stored_len, &error); + + if (error) +-- +2.24.1 + diff --git a/SOURCES/0163-storage-Do-not-free-image-data-owned-by-FpPrint.patch b/SOURCES/0163-storage-Do-not-free-image-data-owned-by-FpPrint.patch new file mode 100644 index 0000000..dbd13e5 --- /dev/null +++ b/SOURCES/0163-storage-Do-not-free-image-data-owned-by-FpPrint.patch @@ -0,0 +1,27 @@ +From 7de7368d545c007abf8c3dfc3fb5a78e64d5b31e Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Thu, 2 Jan 2020 18:42:18 +0100 +Subject: [PATCH 163/181] storage: Do not free image data owned by FpPrint + +The data returned by fp_print_get_image is owned by the FpPrint and +should not be free'ed. +--- + examples/storage.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/examples/storage.c b/examples/storage.c +index 14a6432..0ab4946 100644 +--- a/examples/storage.c ++++ b/examples/storage.c +@@ -218,7 +218,7 @@ save_image_to_pgm (FpImage *img, const char *path) + gboolean + print_image_save (FpPrint *print, const char *path) + { +- g_autoptr(FpImage) img = NULL; ++ FpImage *img = NULL; + + g_return_val_if_fail (FP_IS_PRINT (print), FALSE); + g_return_val_if_fail (path != NULL, FALSE); +-- +2.24.1 + diff --git a/SOURCES/0164-examples-Save-image-even-on-match-failure.patch b/SOURCES/0164-examples-Save-image-even-on-match-failure.patch new file mode 100644 index 0000000..b83a382 --- /dev/null +++ b/SOURCES/0164-examples-Save-image-even-on-match-failure.patch @@ -0,0 +1,37 @@ +From 88bfd55a66e59acef870e36554179746397a3f43 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Thu, 2 Jan 2020 18:43:16 +0100 +Subject: [PATCH 164/181] examples: Save image even on match failure + +Move the image saving out, so that it is always done when an image is +available. This allows viewing the image that corresponds to a match +failure. +--- + examples/verify.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/examples/verify.c b/examples/verify.c +index 1249dce..83d74ec 100644 +--- a/examples/verify.c ++++ b/examples/verify.c +@@ -75,13 +75,13 @@ on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data) + return; + } + ++ if (print && fp_device_supports_capture (dev) && ++ print_image_save (print, "verify.pgm")) ++ g_print ("Print image saved as verify.pgm\n"); ++ + 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"); +- + verify_data->ret_value = EXIT_SUCCESS; + } + else +-- +2.24.1 + diff --git a/SOURCES/0165-examples-Continue-verification-when-return-is-presse.patch b/SOURCES/0165-examples-Continue-verification-when-return-is-presse.patch new file mode 100644 index 0000000..c63f80d --- /dev/null +++ b/SOURCES/0165-examples-Continue-verification-when-return-is-presse.patch @@ -0,0 +1,27 @@ +From aa7808214af31a69b24e55661ae9743642a075f4 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Thu, 2 Jan 2020 18:43:59 +0100 +Subject: [PATCH 165/181] examples: Continue verification when return is + pressed + +The message says [Y/n], but will not do Y by default. Fix this. +--- + examples/verify.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/examples/verify.c b/examples/verify.c +index 83d74ec..d85ce4e 100644 +--- a/examples/verify.c ++++ b/examples/verify.c +@@ -92,7 +92,7 @@ on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data) + + g_print ("Verify again? [Y/n]? "); + if (fgets (buffer, sizeof (buffer), stdin) && +- (buffer[0] == 'Y' || buffer[0] == 'y')) ++ (buffer[0] == 'Y' || buffer[0] == 'y' || buffer[0] == '\n')) + { + start_verification (dev, verify_data); + return; +-- +2.24.1 + diff --git a/SOURCES/0166-examples-Do-not-re-prompt-the-finger-when-repeating-.patch b/SOURCES/0166-examples-Do-not-re-prompt-the-finger-when-repeating-.patch new file mode 100644 index 0000000..02eb2e7 --- /dev/null +++ b/SOURCES/0166-examples-Do-not-re-prompt-the-finger-when-repeating-.patch @@ -0,0 +1,33 @@ +From 355debe411605f1afbd030fe8a14818138ac8479 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Thu, 2 Jan 2020 18:44:34 +0100 +Subject: [PATCH 166/181] examples: Do not re-prompt the finger when repeating + verification + +Let's assume the user will want to re-scan the same finger rather than +being prompted again to change it. +--- + examples/verify.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/examples/verify.c b/examples/verify.c +index d85ce4e..7fcc64c 100644 +--- a/examples/verify.c ++++ b/examples/verify.c +@@ -165,8 +165,11 @@ 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_print ("Choose the finger to verify:\n"); ++ verify_data->finger = finger_chooser (); ++ } + + if (verify_data->finger == FP_FINGER_UNKNOWN) + { +-- +2.24.1 + diff --git a/SOURCES/0167-image-device-Fix-reading-default-values-from-the-cla.patch b/SOURCES/0167-image-device-Fix-reading-default-values-from-the-cla.patch new file mode 100644 index 0000000..2f0a5e8 --- /dev/null +++ b/SOURCES/0167-image-device-Fix-reading-default-values-from-the-cla.patch @@ -0,0 +1,69 @@ +From e4f3385a7745f9467cbbe80ca8a2d411dbb1bd77 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Thu, 2 Jan 2020 18:46:00 +0100 +Subject: [PATCH 167/181] image-device: Fix reading default values from the + class + +We cannot copy information from the class in the _init routine, instead, +this needs to be done in _constructed. Move the relevant code into a new +_constructed function to fix importing the bz3_threshold override from +drivers. + +Fixes: #206 +--- + libfprint/fp-image-device.c | 27 ++++++++++++++++++--------- + 1 file changed, 18 insertions(+), 9 deletions(-) + +diff --git a/libfprint/fp-image-device.c b/libfprint/fp-image-device.c +index 20e181e..c4de7bb 100644 +--- a/libfprint/fp-image-device.c ++++ b/libfprint/fp-image-device.c +@@ -245,6 +245,23 @@ fp_image_device_get_property (GObject *object, + } + } + ++static void ++fp_image_device_constructed (GObject *obj) ++{ ++ FpImageDevice *self = FP_IMAGE_DEVICE (obj); ++ 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; ++ ++ G_OBJECT_CLASS (fp_image_device_parent_class)->constructed (obj); ++} ++ + static void + fp_image_device_class_init (FpImageDeviceClass *klass) + { +@@ -253,6 +270,7 @@ fp_image_device_class_init (FpImageDeviceClass *klass) + + object_class->finalize = fp_image_device_finalize; + object_class->get_property = fp_image_device_get_property; ++ object_class->constructed = fp_image_device_constructed; + + fp_device_class->open = fp_image_device_open; + fp_device_class->close = fp_image_device_close; +@@ -305,13 +323,4 @@ fp_image_device_class_init (FpImageDeviceClass *klass) + 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; + } +-- +2.24.1 + diff --git a/SOURCES/0168-image-device-Fix-enroll-continuation-after-retry-err.patch b/SOURCES/0168-image-device-Fix-enroll-continuation-after-retry-err.patch new file mode 100644 index 0000000..4a2be28 --- /dev/null +++ b/SOURCES/0168-image-device-Fix-enroll-continuation-after-retry-err.patch @@ -0,0 +1,32 @@ +From 82e0ec9b9adc3638c7161177398d52deba3a58e5 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Thu, 2 Jan 2020 18:50:01 +0100 +Subject: [PATCH 168/181] image-device: Fix enroll continuation after retry + error + +Continuing an enroll was broken in case of a retry error. Explicitly add +code to wait for the finger to go OFF after a retry error, and ensure +that the enroll will continue once that has happened. +--- + libfprint/fpi-image-device.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/libfprint/fpi-image-device.c b/libfprint/fpi-image-device.c +index 975e3a1..efdbb53 100644 +--- a/libfprint/fpi-image-device.c ++++ b/libfprint/fpi-image-device.c +@@ -404,6 +404,11 @@ fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry) + { + g_debug ("Reporting retry during enroll"); + fpi_device_enroll_progress (FP_DEVICE (self), priv->enroll_stage, NULL, error); ++ ++ /* Wait for finger removal and re-touch. ++ * TODO: Do we need to check that the finger is already off? */ ++ priv->enroll_await_on_pending = TRUE; ++ fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF); + } + else + { +-- +2.24.1 + diff --git a/SOURCES/0169-elan-Add-umockdev-based-test.patch b/SOURCES/0169-elan-Add-umockdev-based-test.patch new file mode 100644 index 0000000..6ea0dfd --- /dev/null +++ b/SOURCES/0169-elan-Add-umockdev-based-test.patch @@ -0,0 +1,1390 @@ +From f5febd6951be72b8470832d63175ab3cd81545fb Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Fri, 3 Jan 2020 15:20:23 +0100 +Subject: [PATCH 169/181] elan: Add umockdev based test + +Unfortunately, the timeout handling cannot be simulated properly. This +also adds a workaround in the driver to not consider it a protocol error +if this happens. +--- + libfprint/drivers/elan.c | 6 +- + tests/elan/capture.ioctl | 90 +++++++++ + tests/elan/capture.ioctl-recording | 47 +++++ + tests/elan/capture.png | Bin 0 -> 47670 bytes + tests/elan/device | 284 +++++++++++++++++++++++++++++ + tests/meson.build | 1 + + 6 files changed, 427 insertions(+), 1 deletion(-) + create mode 100644 tests/elan/capture.ioctl + create mode 100644 tests/elan/capture.ioctl-recording + create mode 100644 tests/elan/capture.png + create mode 100644 tests/elan/device + +diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c +index 233e4a8..1c2a7a3 100644 +--- a/libfprint/drivers/elan.c ++++ b/libfprint/drivers/elan.c +@@ -549,7 +549,11 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev) + } + else + { +- fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); ++ /* XXX: The timeout is emulated incorrectly, resulting in a zero byte read. */ ++ if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0) ++ fpi_ssm_mark_completed (ssm); ++ else ++ fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO)); + } + break; + +diff --git a/tests/elan/capture.ioctl b/tests/elan/capture.ioctl +new file mode 100644 +index 0000000..bb76bfd +--- /dev/null ++++ b/tests/elan/capture.ioctl +@@ -0,0 +1,90 @@ ++@DEV /dev/bus/usb/001/094 ++USBDEVFS_GET_CAPABILITIES 0 FD000000 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 4019 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2 2 0 0140 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 000C ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 4 4 0 40009000 ++ ++# Callibration starts by grabbing the background once ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 0009 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 771E7618FD18BB16711785165415F3156116D7150B15BD14DB144A142D160014DC133616D0148213471539148716D31470159D14EE154B15C71415158316E114A413F614D913A112DE12CE140414E414D313F215F9136F14C3142D147E130215A9151F15E7140713FC144414A0132616A313E716A01514154514F017B1182C2410227A19FD16D0189D18DF16F916A417C9171A16FF16FE152F15E615A8154B1542144615D314DC14FB143816BE16CB170215C1162915301693153E168716F7141F158116101590151414DB161F14C714BD16E8155F14DF14F214381723164D153C156415DF1597145A164B1674157D154315D9165A170017BB17F117531AC02391215D1ABD1971186417E4160B175A187616F918371821188216FF157F1660166A162B174C16131515151617421607162317631747164D165416F11221169B162A162F172E166E163815EB15B814EF144B15D01591140816F61585133916BA1504161B16921544146A1633167E1636151D15B3157F1875166117C7173E1B0C255E227B1D841AA6172F186717A3187117AD16BB16BD162A16B216D2158C17B91471160D161E16CA17B915DC153115B5166A165E1783160317AE15DD148813ED15B216FB168617EC14E114C01583141514D5153F160B168E16BD1595158816E2164C1726168616D31577159F14B714C71526163616D8169D1897169A18941A8A242323BD1B5518911782171C187D17CC17E7175017EC16151701166E15231748166815D3160016E815FE15C71520187F14C4155218A515B81254168515BF14031575161D1782163614E11560154214BA16E414FD165E159B150816761674152115E0166A162E17091578164B15FF1596153116F915D2169915D61602195319232318213D1B8418B719DF16CB18E1160C177218A81792172318F115FC158416F016D4166016F8155817CB15B81562163A17FA14BB16A21541157D15C6151F1525165F16EC16F815471409176914F3151415BE152F166B162E1681151516B315FE15F4163F17C21552165B16981607169E16A7159E1642186017D0169719BB1ADC230A21F2188F18061841177C17561855170B17281857177416DD160A1691174117A8176B16FC16FD15A317A317001657167C143315B815F415FD15641501170017DE153816CC152515D7145E15FF149C14671680173D156715D1157616AF141516D816F91446167D152816E7159D15211625178A15CD16FA15A8179D18FD1819249D21A61A10196C199F17F015AE1685172A173D181F16C016C717C7187C16811698172117561706186F17E915ED16CD18D4159C15371690159116011727168415D7159C166D1614156C15DF1620178E14E61779161215B614AB153814F716DB151E16C41500164616F4165016FF15E2169B1644165A16A5154818E318AF1A0D251920BB1A7A19D5172B18DC166E159D1765187717FA16B6166F160016C4164E15DF15CF163E172D171D17EB15431462173315BD16A314AF149014CE168E153515AC15C3162416AD15C614AD14A41417159D160C150C16441458182016AF15CD15291640152C17FE161D18EC15EA1414167A17E1154C160D168116D3180A1914256C22D8186217591751176516771718179018DD1624185C17CB152417D716301603171C16F316B216A216A616E2143C16AE14CB17D816F714E916BF14E9149915AF151517C915F41565145416EA15AD14381657160E166415391536164C15C4154919791650153E174A176C17A417841612178B17D2163317A8160619D519A626D220271C6619FA17A518EF164D172917A3170018E918F2176D179315E91653171A17B91600172117EA147C164815EC1680148314FB14E914F01519153C149214A9160216EB15FD154014E714F7155F14CB1577148A154E15921646164C1650174E171216EB15001773179E15A2142917A716181662166B15B117B318B4199B266721191AFC17041A3C17AF15A216101605182B187F17BC16E1150C160F162017781686162116CE183216A917E014471515158915FC15981580144214BF158D149B1499157D146715B8147214F41576155016D2144F1689166C16B8156115BB16CF16DD16D5170D16181826170516A31704177B160F167516A3161D17061B5A25A122271CA018FC176717C2160B171816BC170E176F1632186E16C91706171D188017E0167C15D217301605169C140B1887165816ED154315A91574165B15DE15BB143A169216F31403140016C0171E16F414AB16821539169017891794157117FB157516C61498158F16941630163D17821624168418A016A3178E18671B62237621411BDF18DF185E19B6165117F717A7184718B816BE160B163516C417AF151E173A179716A0165F16E1151516FC163117251772151B154F174115C314E013A2160616D9154B15BD15B01533177C15E7175F182E16BF158C15D216CC1669179417C5141F161315D916D31446146116E116CF17A21716171918B418A31A0F26E1206D1A9819EE17471953179E18C516271968160B184A18D1151A163A164517B2152818AE18801670150315221653175517D215D9143116BF1594146C150715F81663165216C815A3150E155E15191641167B1753179715E2159C1608157815E615E9166816D015471746167F15801688174E164218B615011769189419C3235D22681B8E185217C21782181A183C18A2169B173D181F177A152F178E173D18A616D817C516BB1658186818B115681630153416A416D915BC15DC154F15021507162D15AE153D1555140218081633166E18DA1435151815CA1551156F15EA151317EC149716E2159C175F18A9157017BC167E17CF17321896170A189E1A13249E20AA1B1A1AD8199617C6178A179717F6167B17F6180A183E177E1740179417A717CC166417B316DB173A16D8168D17A7162A177F1605152A169E162B16741620166617BB174016CA14F81390151D164B16F5155F1530163F185916B915FC1698168815CB1676156F16F21512162D1438182F17CD1760187F18EB18541B4525A121F21AE519EF162818AE18D117C817F3177C18E117E117641781170116981699165D176218AE1649166D17E61604175B157C1775173416AC165715B5166A16C2171117DB156E15CD1684169415BE146D1601186716C8144718E1151F150A15BE1715153516CA1446175B156618A3176318AE17C0169B17851850181C1AE926F61F571C2B1897182E181418C9188B175817DC16B5184916A216DC16F817A016D1163619EB164B19BE17B815771763187B15F0165816C516F81586150C176D1621172417CB16321490170F16B616031420178615EF15691502153B14ED145815DF15C716A6178D14CB16E5150E15CD1467160D16DC15F715CA184F18AD1A1C25C322131A6E17A817251777172317B8172D1613163E17AA176917651557185618B0174015E7174D18FF151016B9155816421743163B14B614AD18F81504173115DF16CD174E1637168F1596158A148E15AD15F2158E14E3148C16DE1465153F169C1747165E1683168A178514FB143E17F415FD154116EE1507171E19EF199B242122361BE719C718F0172718A71633178317FA176B19A6175F169F169C16F417F916DB197F17CA16B21639183017D8169617F61535169B15F7152F17D31652180B18C918A917441764150A154917A514E916C8164E165416C014FC169F15D9159A162515CF15DB159B1797168C168019CC16AA16811887151118B118BB198E244D21441A3D1AAD171117A717C01759175618EC17FD151F182B171A1885165B1786183A16BD18F9166F174D179417FC16C0155D16F4133215AF16D61508182C17E617DA1892171317A41612164715F4154017CA16D014BA15B9150016C7146715A9156816221543164717E6159E16A6155D150F17B715BE170918D017EB194B24D220CE190118BC18A6187B18E517131769187717351810188217F8154718C2163117C116FD16E11402158B15EE15E115121560154114A715A215B014F31601170616FE161317AF16B7157D18D216FF14901700176F162615DD15B615BF15941678166216E617E2159617341806172E16091640150B16C116F816AD17E618F8242F21A1190819851860183D168F175A18DC161216CA1606185A15B816E5189B16F616E0176F16DD161D162F167417BA17AC166C1544147716DA15F7144D162F168216A317C315B71383172F173A173517D317A616C8174016E716BD158E154217B514D6150516BF1510177D15AF166B175217AA157F16AC16FF171C17611A22251A220C1ABA171618A2189E170E172317D7183317E5181618EF16BB16D11557164716951615176619491679155E17FF16F315E2150B164115B014C9154A154F1608162B17FB16C916B216E815EC1730165C16C41697172F17601791156E15E6153B172C15E914F3157415F51599154B18C0177316F01670177C19EC191A1936244A21D21912180C196217AD17E9178A177617FE15FA163D172516C2163017FA160D18881501178316D816F4179415A81601168816AA16FD149116E815021744162917AE1601177116E51446164C16171517179716501574142F17BC14CB145B1600154B1572150414F316B21569160518DC17A215C1157A15A51775175B1AB1242222261B4018531792185418DC170818BB17ED16F317D017131620171617211709181D1897157417C216ED15DD15B0177616181647177C156B1657162E17B515241728175C1872155C171216BB16CF161F166D17051637156015761641155417A015BC140416E7156D1692156316EB16B7165916F5167417BF1627188119A724D221241C9F17D918CB17DF171E18C6182618EF169B18D816DF193D1797176F17D2168D17011759179C167916A9163B170417DF158514E1153615DB153416E9169A171218AA17C0151B178E15DE16F7155C16101620155415F914B41583148F150C177E15A3149C165C1643164E16F2155D163715E41639172C181718461B9A2510227D1AA0190B19E417A016B317D617B518B1173216B317E216AF18511731186518D416A217B016AA16FA16CD167E16BD15D516A4147414CE152F1615151717E31717185A180216491612166614F815D316DF15BA151E15A9165F14EF15BF16D71585152B14411632167416B616D817641674176F178D1608176319CA19A8241D23921B87160A17CF16C5187D17DA17DE180C178219B217D7177D168B172C18D418D2172418AB19B3164617F5155C189315F2154A162A158415A2150716CB162F1714179B17F61646169C16DF15A61654171D173718FD14C516E3153A1661160A172317E5167B160617771747165D1678153F16F817C41675175419CC1966258521C619FE17E2165E18C516D6163818651746191616A817FC159116CC15A1143D16A416971717175615FB1446171A17ED159D158416F8132D161D168D160316D815BD165D16E215B3154814EC155F15D6150D18C8144E155D16BE164215E1151F156C176B168F14FE17EC17CA1845179315DE1442168E16BA180619A21909245921111C46181319011946167916FF15E518D419591A92184716F516E218FB18C1161C175717AF179714A915391595147F157A1610164F159716031542174716A5182A178F174F1480152816E81511142D16CC162B15C3158616BE16D71675155016541605152F16A816E81570163916B21548171216EA1692165C19591A4224DF21251A1A18AB17E21799179018D9177717AE185D1890171318E0177D17D317BB170616A517781618161B164F1582145515AC167816E21698167C16331511171417F917E716BC1535148417DB15D415DB16961778162816A8167E16E916161553161F160816C515561873179D16D5158F169916DA1776168E17D61883198F24F7214A1B5D18AB189B176D18C21650173118B817E41648171F178C17F5174A172C16621705160216C1162615B7165215FD14E815A916F7138316DA169F15D815EB17E017FE152E1490163814B315C2146A17C6178B14131653169815E3154B150E15EB15021772174E17ED148714F01440175B1784155616FF177918EF18B3240122481AA417C8186D19E8167A188E16FF188117B3175A178B1820174A181D173917831746174117621974178A16BB1758161816011832152D1522168416F416DC16CD1854167F14FE15FB15DD157E140D171017CF154B167B159816BB170915C416DE15681566153D161417E01589160016F9164E183517EE174C194F198D243020A4191C199F17B518E71796176F16E01625172618FA18EF172D171B173217C4188B1762160718CA16E5162018581772158316D417FE1453159D16B0157F16F31515169217D51336149F17E516741491150D18651765159216A017CE163317CE15E215F316041831188316BC13E81578166017C217A8169917F1182B197E25F221161A56193819D718AE1620166E173B176918371995177E17D415EC16871785180B19DC170E19A317C91677169D18B7164B160219DA162D164C17E215F3160C163D17D7156E13D113D916E11585156C179217D8163E16F6162E153616E415A01831151E173418D216F31523161C172517C617EC180118F318E518D4199C24EA21E81A8018EB17F9180D18B018E9187C1835186C181016EA145F183117A4167B189917541794171D18A91448167017AF16B215DD162F1614160B16E3156717AE169216DF15FD13ED148E140816EA1434171416CD173C16B11535167C166B158716CF16FC156D154B179615EB163E175617F215B8186E17EA170219911AA62559223A1A421837185418701767172D17DB19C3160017921715171217E517561754198217A91681172D16E9164C18F815D8178E161115A416CE148215CD168F16DB162D17FE16E413BC14DF14B814B7159F164E153616C91528161715CA150E17D41639160D16CD15A715051642166E175116DD1582170B152318DD18271BE923EA217A1AE418D717BB1613178E1738171B172C177318D7179D16CB154216A816AA168E17A516A0166318AB162517581885163E16B415D2153C153715AE162916DA167C16EC154715C315AE153715B31457168E168A15CE14F4162F156915A3153516DD1670176C16E61641152516DC163B17BB16111820175B1808191E1B4A25AA213C1C2319A119581966181218E9174419DE17ED158C1588168617A7172117B7189A17DA145A18411656178C17B7164716A1169F1467153C176014361665162C165F15C2156515F014B5155814BE15E616A91644161F151515EB1485166917EF154D16C416B6167717E0169C160E171D16EC150E161D16F116E617F41B56258322411A2817CA18FC165917BD175618D417F6167517D81694155515FD16E71634175E1793172917A717DB16C9173918F2178615DA14A2147A155E15D2140C16D7148F1566172214EB140D1632167B15B915DB1661171E177217BC159015AE15851791161E15BB1527171016F916BF160F16B6156017EB15F417B519351B2B232623691BA8190518401AEE15CD174C184917BB1674169316881571159517071770172017AA178B169816A81635169A172517CD15BA154F16AD150C150B166615F114F6142117F715B4151D15A615B415E41679169A17551561161416E8153F151D16631629156E155816E016BC16C31669161917EA17D9187D180517951A4F247D21D11AA3188B184E18B118AA16D11779177C1731179916AE15CC1697153C16A415C9178A174F1631147B164217CA179815C118621782145117B314D214DE163416FF15DB153E14A514D1142117A91592167016F5154C153816291525159316E5146414CD151015E415B615A2153D167B16941692176916DD1563179D1A992419226E1B1A195A184E191B1918161516C118BA1698167316A7141F155C17AC16FF15B2177616A016DC174F170518D1178A16B115D2155E166C16E7150F163C15FC142F1600168C13C0153B1667158C16BB15D3170C162117D9141216351531151E164916901631164C177314C7156916D115B5160E1872172418FD176319B62377218E1A13185E188718991753170718C117271892169116E316A517A41760161B1642179217C718DF16FC16FA17541743180F17031638165F1641137516F814F21519166816A91529152E14F41672153F15D41695154A164017AE1403175D160E16CA152A16B514D01790163815DE166116CD160919B1178718B21A511A57245321981B4419BD17E3189F1821186B177A17CB15A916A4157A15DC167117C416F316FC18DF154417C216991598161F18F7169316EE156E171817861548166A16611673143816F2151015FF14C31675141D15A51465164B169314B1165E16E0153C1401173414D415B31678151C15DF172C166C15191807171418DF18481A3C25E021A81A5819C11832177B186616F01669178E1730161B17F81617170917B016AF17E2162517D317A616FA155018A917391686165A166A163D16471755164715A6159414651661156115BE15C614F214CF14901678158D152C166015F6159A163F162D1732162915F615BF15B8165D16671583164D179217BF176618261A4C256F22021CE11846181F183D185917D915A216D0168B18D11676160616FA162415A517F714C716851670156E17AE1745193118381653149D15B616B414CA1528154315EC145B173B15F015ED1467157C146D15E61669158515941617165915A41654165B14D01596147E165216AC153717EF163916D315A7167D18BE18681B39242521F41BAF187A184319B117561593164D18581711178A172A16BE16BF16E4177C15F9158E165218BB177D16041727167617C717B2166016FC1429142616E1150917CE160417B016BC1590154115F6151915DE16541672142B16C516AD15E4140314681729154516F315F515CA156216C7168017FF162D160D18C317D4192A25FE214E1BAE1997171F182D18A4199F18CC17F816B117561750178016271777152417CD19A317F618B3156017C0160918961415155716FE14161519169B16B4154E154E164F162A1684153D14AE15F415931739166916B516AF16C817B51572167C16FC171B163615431618161C16FD166B16AC15E016D816FE19C5163E1A2B237E22A41C511AA1188917B3189418FA17E8185F18C118811620160817E2166316A315A616C2166419AA1639166017941769140B17831505163217981441160116DF164D18041632158114E715081567155B166E17FA152E159215E715C81578150316E7167716A3143618D11622163116211650165D1656158816621871195524D921E81ABA1B7C18DC187E181C1813172019CD199318131867189A16E017E416A5164A184B16DE1869188016F2166F1537163F1405171116C616F2148316F61569162618731747166F1682152D16E615B315F41533140B16891765164D15BC153B151D16BB152F164C15AA156917C7163815621518186E1603180518A319F4269B234A1A0F19DD178A18EB177217FE1853182D1797182417A515C415A716E618D61647189518A218AF159B16C416D0168F15F0155715CF1547154D158C1672166818E917E916CB151A1501161C15F0142516D915D81475168C1554160A14FD14461660146A144B1662173C15EB16A3183B16D514911727166318F0184C1AF6240B226A1B31185A193B1A0319FD172E18D016AB17EA1868195B15F2164316D4168016331649177A179818FD15A91716174A153816B61885152116CA164016541682177117BD161B1716163C157C159314101607172316DC15AB152D17561505164B1709153A151116D1166C168D1583160E164E16471966178A1890198219C0222023861B9E1A4C1950174C198A1779186519C9177018661816188D155916E5149617EA16E3163C19A617AE180817C217F3159116EB159A17771640172D18F11638172F1981161918ED166A161B14781598153F166F145E150D157416B31623166C167816C217B714B817A0161F153117E516C316291A201892177A19041B6924DD20771ADA184A191A178317481712192417B215D5174B15DB16DB158D16F3158E1780162C162B179C18361561172C16C2172A17151623153515B0151617461791169918DC17BB172017A415CA1776151515B1166D15E814EE15391654169516F415741567163A16AD15E21558174617CC143A14801886167218F817FE19FE234722FA18A8184418A418D416ED189F17EC1779188D17D215231611164017DC1539171017931681179E166716A2156A169D162016381791167115EF14EE152D167017481828185817911672156317AF1579178617351721155817DE156716171726178D171818561568173B162817CB169E15A017CD189718991A7218411A9C24CE2059198E181E186617FF17FD17B218A8181F1828182617ED1795153717DB16C216FC16AF171218211775163217BF161916FF15D317FA154A17D0155B177F166E16CF17EC18CD16EB16B517F1160F16F316BF16FC157116BE15FC15A416EE157D163717C717DB15CB170017CD170118AB158B18D917DE168F18D417A21A082779216F19301AB318A118B01804186C184019C31724189E16AC161F17C5173B164417E917E8176B18C0169E163C169517AD19C517EC15781479166C17B016F917EA16B518751795171217B617AD17DD16131783158817411610174E1669151217A71666154D170215B51785164014ED177B174B17FF160D172E173219AB1B4B267221511A2B191019EE1863190C17DD18BA183818F018BE1785179115F315A118AC18FC18EF186D18841770187C174718721792160817E5165F15751824169315D6168318D0170517F9162317B1161B165116D616C61540179F158515F316B7163217E915771565158D17A2168416DE1603174A17701783155E17BA19DF1B3C263520B31AEA171A181C170A17A51720185F19F5178B18A1169D176317D917851560175817D5171F18AE166C188117C41663162417A61547153D157C16971679169E177A175B1835182F16FA15F417DD153A1615169C161C17B217E11516156F158C177617B71749158316E215AD167817C01623173A18F91754186E17901A84241D211C1BBC1A17174917D517A01744175518DC1858194B188217D81828175518F01647178E16D41831169C18A11632175216D417C315EA14FE158F164416FE169916861690191E169B16AF160B18B6159C177817B215A115D418C01570156C1698177A17A3160917C7161D17BF17C5171D174E15BF1AF916B617B91A081BA324CB229E19F4186B172518071A0A18DC17F1181C18A61943195818FD170D185315E3175118B01719164318B217701567177017DF158417C9157F150B157D16B116FB16C4170017B0169F1520160918C515A8166A17A1164D1651174D172315D71646166F17F8150016EC1739166A16FB19EC16BE1547189D177D17391AE31884253A22A61B77178917D318C0177218D417DE186219E8173A1849174417AD170C187B17C9170F18A7186C17A5181A180116C41546177E166016F316FD15C015A316D1173417CC15A6145F164C170B160C176218AC164E17491696176E159C1515165B1794140F16F6172B186116901583176F17D41812176E1737173219961A5C252821421B9B187D194A1791187B195B18F51718161E1ABC169A18E316B51724162818C117AB187317BF169B168E15AA177F1670165C17AE1562168816C914701674174C17E4148714E0176B167C15CA144A16A316A9164C162C16FA156D166F15C81744161416EA1566166116F214CD171316D5166F17C9178417B017581AEF24821FBF1A3D18E41793198018A616E018C51666178A17141655182617A718961785174618971781180C178816F51797171616F815D0159E162116A615E715C8162317001762172716B5149616411618146714B4175E145D164C181718A81739175E156F15831604159418A0169B1686173C173017411719170D17C119361B6A256F20881AEE19F819D5184E180F17EE185E174F17F317F8189616BA17DC170E186418D717A1168B18061835164318EF15201643179E177715C615F916DF158D1574170E17DD154A15AA1522169816B316BD16AE16B3167416DE15D115BC16CE14551532176D16F71543165E15B6183617BE167F17BA18BC168916C218421BCD239D21741A3419E317441846191618DD1716180F170B17D7150A17F417FF179D1808179D17FC16F41879186D17EB162118DF15E715C315C915BB1620164216DF1484175D170F153B162D160E15C4166115DD166A181E164D1788167D148416C4158B1617172D150717FE15FD17A816CA166E178817A1165117CF1866187F19D0239A20CF1AD6186C173E18C818FF17531640182717D0174118F116AA17851913169216A618AF163116E6165F163E17321714176B1610178E15A0163217BD167317F817F9178A17521422161A172A179715E11725176216B414D1171B1611153E17051789167F1709176B176416DE167E18141763188E178817CD17A718331AAC236E20F4193719C11816177E176C171918FB185F18D8161519491611177519A11794181817EB16A8165A16E716BA16EC169F166E16F0169F1595175216EE154E15BB176716BA166C14CE153716EE166716B81790160D16DD14B917BE1576165817C516641625176D166D175216DC176B17C11681178516A817FE161018011AFA24BC236E1B75193119A5185518A116D717461980183E17F418EC16AB17FC17551935184018FA179516B017AB16A11719181117EB1683163717D716CB164714BF153418DF16E817A7141B161017C31666169E167A17BF1416162015D417FC1525162A181F16111873173E1667163A1691174018A017BD172718E618BE17E11AFB2636229A1A331887177E185B18E3186D18D7178617B418D3176A17A215FB1636198B17AE1649186B181E169915BE14DD16AD151417BE1669160F1714158315A117FE16681735174D1507172716B415CA15941778167B170F16C516B3157516731607178F165116E9168E167916BF16B218F3161B1708186217FC184C189B1ADC26E9216A1B6317CF180D185D177E193A185818E5178C17BD1722168F17931714183218A218DB17EC179215F81898162F17B5159817E7151F16F7168016FA14D41511169E15FA163F15A1151D17C416FB154316A3174218D916E716DF161817CB173D18C816DE163B172F184616CA162217A017E917F81792160C185C183D1AAF266D226D1BDD19E619B3186C17F7173417C518F4178A19BF17B417C418FE162F193C192918CB1795187A1605168F1814197616B715BE14EE1553164B14A9162416F51639175218F0151B162F174E16AD153E16BC166816D614CF1750174A16BD1726173218F116AD15191905178F18FC161016631839198C170318CC18811AF6243621AE1A17193B18D119ED17AD15A41689185718BF1806178217B617A3187018751878181E1824190F16E916D616E01796148C16E01527150A17801568167716CE160217EE16AB165315B3158A17151668156C17CA15C015A2171E189C18CC167C173C167D171D1632186C17FE16DA17D9159817D41938176D171E19451BED24F520641B82185B18F718D3173917AB188E185E18F0177C17D5160117A51684184517A718FD17DB1673177E1823183B16A416FA157C16AD16F115BA16EC14CF16E718B516EC17ED1543157715C61634168717F9177C1669184018DF16E6182519DB1873174E17881846186C17B116DF185E1743172717E518F0176C18C21AD024A8217E1AC6180F188C17D717D217DC161819031883184617E8160F1897180E1919192618A6189917701776170F17F0161F1675171D184616A5165915C51712174B18FC170B1751151315631631168014CD1733175E173418E7175A18841749181D173A18B5196C168D183A18F6151F18FF15FF1783179315E9161D19651A08252020811A751816185917BA1708183317CB16D218E4164817D61706186A1771170418FE161C174F173717AB18511772176617C3187817B814A716031641167614E9158E17EB171C165C15AA17E2149716B41705186A1522161618CC177E17A517E9176B188C151417ED16ED17C71664177E16E9179E175A17C418CB18EE19592482216B1A171A14188D18D31826174519241999180B1880175F180D18C51684193A158E1760183A187E17F315A7173A173E156D16E0159816F916EF155D178516E8163117A7163A162D167F15D315691622174718AD164B17C517EF181B19A117C816F6168616C4167B187417FD17B518751767177517A217BA18F8189E1ABB259321191B2C187E182B186D17D417EF18061817197B180118461663175716061A3018C5179817E4164616B415AB155E184F142A176E1629161F178517381561162D178317F41628179116AE1657178316CA16C917EC16D2178618CE161218471719162317D115041792173116CD17C716F21514182F1801169817A617911BF024BE22F01B3E18AD17BE17E81741174E181F19EF18DF180E19BB18C616BC17F0171817CB17FC1714189517D9169117C716C4171F1740164217DA1869164E1518173F17F5154F155615FE15E6153317CE15CD179917CD1759160E18E4176116CE175F17C4160517C5171017E71644171818CD175C17E1181D18F5181419B31BB626B321D31BE019BA1757173F187D16EF167C171518061863189E17EF167D18221703182C18C018B217EF17CD15CA154C16F4142216A616AC15A118A6161B17501589161F16FA16A815271533151F174516D4168917B3164C14B21A0B175D170717C61685189C1765161E176D16291764179416D517D6170718D7178418A31A9C2429212A1BC417221836189518451895168717E5179617A5170717FF162017B5175216481827177D18D71810161E16DB15201692161417E11518187217F2176117F11645179B1767169F15B8147E1744156415DF163915CF169A169C17FE16E0160617D5170A179F16EE16F11638175D1796161918BC176F16C5176D18661ABC24D822A4191E19D41819189F17CB166F18DB1607198018B3171817CD174818EE17C317CB164A187A18461859164017EA16021871161E17C3153D18901693161017D0173C1827162E177216EB16BF164A17AF188816E2168515F9177A178F16E617CD16AC17631625171418F715AA179D175A180D189217F615E8187F18A21A1526D420FC1A14181717DC16F9166E1603179917FF1633189A148A17311792166A18981756177D16A1181A167215901713171617731687167017B316FA1502170817B91644176A160D158B16B315F7162C16AE16C316DF1603155819D7164D192519781763173A16BC15A317FE16F5166217D716DF16F019E116A0161217C6198B23EA228A1B2019AE177B181A199017E619671832180F18DE16BA168517F9164B199F180117C8175417F0160D17E31622179916F7179A161318A9176417471731178D17A317C41795150514FD17F018F715EB16E31823186117A917731614174A178918BD1745177E1816187E178917FE1890179F165E17EA162317E819331BB924E520581B8F176B1852183019FB177718AA17FB172B19C617FA1784163C1874171918371740186E176B178D161318AF17AF16B417E81469161316B2150617BC165B159116CB16021724176D178316151674178E176F151116E616C4169617FF1659182816C417B517F3169A178A1619179E18B617531725167A185A19101AEF259722021B6618E017A619A1187218AD170C191918B61811196C180F18C1172F188716B1184B1794180518F415A5182216F715E9165516A616B9168917CB157915E916EB17271710177D160D1829191C15AC17D21621170D183118DE159B1771165218E9160318D216B01839180A176C17011847185F18D8175D185019801B83257022A61B0E18BB179D1776185C18531835191419341898179717DF17FD1691173D175C1616176D17D0161516B716D315A4159C17F5145915B516F3164915A4158816AF16C316E015DE15C11582166116E8168717EB18E415D7169B172B16C617BB1794177518E314DD1655180E17F317E316B1171C18D11668185B1974198C25F5226A1C4C187A178318DE17D6164E185B19C817EB18C0185A17931681188117C91547189F179116F8160B17C217901771156B170517FC15A818581632161317B81797177C176014D7157B159E151115AE17EF1780171B171118DA15D1172F181D1778178717401822198415C516F617FA171E1707172B18DB18AA179C1A1526CA23A31B7719D717EF18D918E418A118BA169D174716CA174D154816A9174F1703170518DB15DF16C515FF14DC141516E315D115DA15D6167416BD1761174715581736174A153F1384166815C5157C162716201957161D15AF157715A8180A1861171B166D159616D8185317C9175D18A4189F17B217E3161E170B17A4182824B622431B201B52187818DC1624184719AB17E0160C1883172316B215BA151417A2171118E7168317A5161116B4162418CC1571164D15071607175115D8160217A7169115391613167316C715691536173815D31854162E14AF1679153A15BB147C1565168A18C016AD186018A618901706173D170417EA16D7188E198A1BA925A922DF1A8218D318A6174C1751185B185518601702162E17A4161C16331635173F17F9161918B5163817D3159B17F2164E16A2150116A7150716D815141661171B1672163316281383165E1409164915F4149C163E15DA15C215FE15DD16F714D015F216CD17C01730174317FF1662170B16171774176A1686179A18231A22238E22E419D617301727180E1727196B175118B91882171717E115EC15E0179717B616FB17E616C1173416AB16FB18EB17F515BF154C15FC163D1641154116B116B916A71566154E145316EC148616AA156E155C165515AA159E174215F21672167D178A166D17D315C918D816B416C818FA17E2162917AA17DF16C1182D1BE422E321A31B69190A19DF185817AA1939177A198C186C15771635181D17C516B21753172C187C178D178A171617DE17AE18EC16CE16EB161B17D9158216C2153F16D616CB16A5168414A3173317C0158C1407180318E6164F164F16EC151918961740185417C5166D1804187716C516FD16AE17C4186F187916FF169A175119122479219D1B1F195C170518BE167F163E174F16D81634170C176617AA16AB172C18EB16D3157218A216F71719177718711779154817BB13A315AF164B173615C4160C176E1838175C1301163D14261848142816A117661610150517E3177B1786173B169417EF18B01648193518301870179A18A1156017A517B3176A197019D4248121281CB2189918AB179D162C166718811848176218DB18BE16D1164218DF17DE150C1767171418E416FA151F162016F3167618A6161416CF17021805171117A216191742161214FE140116C816F9155B16F016B115531748160F151917BC162819A9163B176A17811765174618F317FD146317421750169417EC18521B0624B220761B4F1874185C185C18F9159318B0186F17B91698177117E5160F176018A61656174B17601954174F169A182117FA179D170217DD1617160F17D9163F17F615DA166E16331688150316DC1637177116701631164416EC159A156015B6152218081724164E18CC173A17ED16741604171617AE164B16C9160F18AF19EB22A624D51ABF17E917FB18EB16D4171F171417251AF01769174C164A15BE17F8163016BF1848161D185B17EA16EF16F81727177E17E5161A149B16791643166417C01645158114E0150C153A16A216281671167817D116CE15AB17A6151F16B5164017281652167D150A18DF16D816D5172A164F178116DC1454172F1793181D24EB228A1C59186C189516E31712179C175F186F1849194E17AC162A189D17551843176118D417BD1708164317A0180D171D17A71880164015C51751156617FA14B21651151E15701654144B15FE153415C315FC15F6154116DF1669160B1634177918BC17AB166B16B817AB17E0170A18E51548172F16F71517173718011B8F2418222D1ADC181B163817E117DE16A917AE1674175C175B17231724175518DC1825176A187F17E717AC17A616CB161917A9192217131653157D15201661166515DD1514166D169714B613EE161B1553145416D6175A167417B41610178A184518E91686162617E01766167D16B415A017E916B81521169516A815B818581B5F24AA21DF1A5E186B19B6194A1993177219B018E218AF1669179817AF163A1862186A17841671171F18D915CB160B169B17DF156D17C315101554169316961521180F17E71433163315751485169716C814AB1793184716C71425162716F616C4161E186117531647163C16971686162817EE1745175E17DC1674178717EE1895244A22CF1AE218321A1018721A271955184619AF19E118CB17E41772156517121742179F17D817AD172C184D163718FF168B16B7179D152917241705170916AD156817E717CE15AB157C157C164215C814731834169C1785155417FE187917D916E8185B18F218BA168A178017B2175919EE1700185A17FA154C18F7187619C7246922621C1A1A4A170B18B916AC1973185B17FB172F18281726156117B1173718AC17F716A3175D188417AF1769179417FC179617BF16DA1790176716D51680160C183618FD1640159D1517177B16D5159E17E1179816B915BF16551778176615ED17EC170916E4152B17CB17AA157C1763169917C816421607184E18351AFE24F321B81BDA194B196F1821180F181A17BF17B7183717C3178017D5166E16C816FD152018F817FB164B162F16AE1AED17401506158E16D21545172C175E16BC1707178216BB16B1140715541513168F150818BF16A4163217F516CA150B17C516F7166817B9174F14E016C0156F1642188916771743179C16F6164918561A15238023BE1C2A1AF319281903181E1982178B197819D7178E187A173418F0173117F3167E1666186617A218991745178F16341735173A16521881178E169316E3172417C9174917B514C4163616C715E116ED175E1872165A16AB153B16011644181618811775174E178E161A16F315A61784174C161916A8163517AB17E519C0247B22D21B1C19E8197318CA17781844198E18FA16721785172E17B31858184C16B3165E163F1AA518CA16C7160F17A117DC168716C6177E17D914631571150816EE166A17A815F014FB14B717D715C516F8178517AB1682168616EF16081974186C17D1162E1816178718E4161C17CC1675166E177417D316DF15C618291A892538217F1BD81867167E1806197418AF18C818C118A2172418EE168516FA175C18DE16E7170B193F18851792197C170F194E183817D916E616AC15BF1564155216021891160C1694150E14E0155D1676163B185D180B1739161417C5159E17A1177317BE178F160E1684173C191917AE1606165118CA167715A2178317391B7225C121911A2C18E917F217D617D118721708184F182C17E4161E172F170E1849189F162D168E189618C018D118811787168416CD1779176616EC168515D41526157416FE15BC15EC1432155216E116841594163318C3178E169317EF1577168316C017B916F8162A1568174C17C41653174A165B186218DC167917F2185D1BDF24D6225E1B541993175919FB177117FA184A175E1860173417BA16A615B215A1161117381846197F198F175D1732195617EC151A16B8167A15BD16821585153517A416DB152D15ED13DD152E156D15F514EE15B91719163416E1150516C716F61590165B169916E5151617B3164218DC17EE167517F117D815621749196619A8243B221C1A641951177A17A7176917BC176C18A718BC1617167F15B41608174E162A172D183C175C180D175A17BB17E3153117641682157815FA15E716FD151816C3165B15E214E9140115C5148714DC151016E1175616BD151817B7167D154516EA152B17E117EB150517F616CE162A179D17BB161917ED179717C6184F1A34257422791B001A63184A180B172C17F816D318C2179817811760168615FE157E175417D417B3166718BA16B016E6188417A416C4176A1555154917991522150E158A16DB15D413B01445146616A113FC15AA179416E516D51517183017F915EB16AA15411619176316DE17A2172D15FC164418FD15D917BF16E11774194D1BCE247F20D61ABB170C1989184A1603175017C417EF171D1861162116FB14FD14DA16C9162D17DF17B617E0162D1713170F18DB16E21517166D16C71791177F168F163A17CE163A153714311548168915E9134A18E4186117E815F1176816A71537174818DE1657177116A617061655165617871734179A17DF16E7174318B61AA2240421061A2519A1167D18A2164618D6183A17CD1723187C173416B415F416AC168A1691160F1A941790177D1517178617901661157516F81698163D1581147616DF165115561423165515AC142617BA156A194C173F1798160D17E4164B1641161916A116A818F2163B18BA16C816D715AF17E1181B1AB9180818E4174E1BEF2431213919E6167E184B174217C215091988170B1857182119AB164916BF1854188D167817FD152E19AB178214EC170A1898178D166D15D6158D16B5156514EA156814EC14F514E5131B1444162D156715AC17EB159D16FC17C917B515FF143C17A7167B171B179E167417AD1565163C18DE158F172D18001658177C18E61B5D25AC218D198A1928175A1889173617AB181018A516621768177D182F174918F818C01665172917D7186D18D916CF16EA1523154E173A16D115A0150816B7149614F51556170A1534158915DC124F17E71513182F174A1604164B16C8158C1568163D174B164618EC1679180B161B170716D117FF16F21828176E18AE19A51A96254F209C1AE2171818D8151718D716FF15A817D7176918E1169D16FB17DB1635169F174B17371805188B162E172C178F166E1626175816E815C7150514401553147A144F1599144F142B15A114B7141C161918B4186517C9168916F81696160E186B1804164815D9153918511792171E1774173A17F817E0162C178818321B432687212F1AC918EB16A416C2165517C318AB17931615181917B9178E158416CC169A158E1884186A183F1705186916D818AA17E816F115EA16C516FF1553161B16C1150716BB149E157A140317B6169E179D166A188117C4163F1719160417B817C3178B160117BF17BA18E6160C177B17D917ED16281783178B183819AB196725CA20BE199A17C6172C1754171617CA1678188516A616E9169916BD167B175C18B6173917A41611170217F416531887160916F015A0153E15251613161A1511150815301306146013DB16BA14F5167216EF1652180516A2152916A817871647182F1747161716111762165E15211848184217D616B616CC16DC174518231BC925B4218D1AC019CD161F16111728175117EA1722177417BB18D716AC15F01722187A170517DA1700164917F815A9168917431762176318B115F815FB15FD133E15F6139A1319150E141D164715DB153E1583164E16BC15B5170919BE16F416CB17C8189D18E21500172418FE165E16BB16FD154316E8164816F817C118301B4925C62279195B18D5178517AE176F1793165C177217B3168017DA160E16E8161417C016FB169D17C916EB16B8164A16561768167A164F15CC16F0158615E8156F148E144E133415A71595167216DB15A116801727166516D018BE16CC16F116B715A1188B180618FD1638176A17051744189616611648184F180618DE19231AC1254720311AF1188117C916D7175015D3161D1757170B18CA163D1851175B1803175617B617EA17F41663175A1685178119B0158116291615175E157F15AF1538146214BE1427145A1427167C164C16A915EF1702169416F71508177915961548180917C717F116A316AA17B517001787172417B51512171C1454170718051A6425F7203F1B26177F1809173817A11746168B189E15061671177018A11743177618E6152B17B417461865166016FE16B518CE161316BA14E4153D16B515B41374145C1465150E149314C4140516E216BD1529166B17651656163917F714F115A7150318FD146115151546160F157017B315B01895151516D317201762180F1AE523DB20BC1B2B188F175317B0170D177E178A188C1766172F176E1812150316701669176E182716C918B7164216641767165716D314A315A013C317E814541759150616E51409154E141D17E81566168616EC15B415A0169415A217FB14A9164816AF17B0167617ED16A11890154817691709172316F716CA17A21985196D1A9A25CD22BB1B5A180B18301815198C16A417AC1854189818B217D016F117FF177F170D18C6185D1727198D162A16D91647186B16EE1615154414F81519161715871692168613D014D91586148E176A17E614C8179F1782160E144917BA165D188B162A17FF167217281616189E178A166516B018ED16DC1735160F18331736193A249A214B1AC318A317C7166E17A31822184E19B118F417621874180C17B5189217F417B017FC1766177716E3174318EC179D1680176E1642151B165717C0168B153916F214041620154216D116AC16B715A815781647162615001694168C17C3166316B7173417EB1545160B16A815CB1729178E172E1898162E18DB18A71A55262020DF185618CA17CE1628180F168D176019541825183217D517EE162F17D11732173517A71866182F16FA15CC161217E81587178B157C176F165B1445174D1512157315E2168F14CE166116AC1451163916D216E015921651170417451630153916B4164E1606159816AE156A16CC160D167A1633185D1648184B18451A19248521EF190D170419AF18FC17C6173E185D19C6164817E618EB16BC177817A71799189117D7176C184D17F8164618D8177C155817BE16E2151716A816ED16A3167F16BB15B314E0151E1612166B16D416AD1755178B16D7152F1627176C15DC168D16F4159A154F16E516F616D01641198E1604175B171417FA176E18101B3825C620E51AF0199117251860184917D2160A18C1188E17DD18D916A91792175C19B317DF173419A517401823173418B9166516DE171A16F616ED165C154215D0140C167114DF15821519156C155D162C16481784162215721739171216591670160C1879160B17C217DE17D016B616A6165B1736182716D1176318531820191626B722DC1BB118C517DC17C8176C173B17D71706187816B61621167D1604180515E71688171C17DF179418C6174117E915EC16D1174418D8151417F5143916CE1641167915E9159F13221681152415DD145217751786165C160416E71506165C178717C517F3169A163A1869163117C5188116D7163F17F3158B16161A6D1ACB26CC20B51A6418DF179B17201893160E198415EA16FC161E177616B917CF172C160016CC178016FD17151663160417AD16E4155E1762172216BE17B0164A172C168C16D7155115E513F015F515AC15A815AB15B217CE1602169E157116A416BC167417F416C716BA15E4175515C416581619166F175817D216C518BE188C1AE824FF20B518F41745195217A5170C17A6178F177216AC18CD1776169D179D179F1712186B16F01701198B17E3154617EB173615AF163A16E115F31526154C16BA141216F5151417B7142D157F155216461536163818B015A415771793168A1741175F1522150A164A166A173C17CA15E7162E17AF1533163C162316C6174A19FC2278217F1B2318301842190517EC173317311887184E1745176B1853175416AB18E418BE1823188218DE1670156617BF1741168515D816BB173515A716C8159A14CF17131767150614FD17AC15C216FB1416172317F115C01537176C15841869152D18551717175C15F61651169C163A189F16151523164616C21751187C1AA7252F23261B5F18E617C61943175218F416BB17E0170518CB16EE16F515C716B2163A17B91724165617B4165116B9164418F6175416F515581373160115E616FD15D4158F153C16CB15E913371811160215F8158416531409178F16F4158015B41686160616F216AD142317C4164B163016A81673161B1712176517EF178719CB258821B11AE6191D175717ED16B0174517A018B217231721175D16341823188515C41746176B175518B917531624179316D4160217C9142B14C117AB163A16271531166B178E159514CD1394164014FF157D167916BD13DA151D176216E5169914BF17751786160E173A162A16BD158B1704161F1648168D144118CB18FD1A4124B7207E1A41190F181417C217B51851183518D5168117F9179C165D163C17151832175C165A1643179B177816D515A1166417E2154A14C51538141F179D150716CA158B1552164C1423148B15F214D914B915C514F014F514F015C916B815F517C3161D1501165E178917C814C6153316B215F514BE16F415C1172A19351A6723A821ED1B58187C17F3168816D91823184018F5162518DF15B21692160917E416951771165217491776182515F216B619721883170E1667154716DA159E1700187316D915C916D813AB15DA153715D4154516F916B5178715B817B916E9159C150818DC1638157A155C175717AE159316D71495160B183417D517CD19B51BDC240422A41AB519B0176118BC17741760172618F116A6174D160017C2153F16D2151C15A01632166216EE14D9141B165617F416B81597141A161B1613168716CF16BC168616AB159E1455163316FF15FF155A154716EA144C16EA165716EB14141653168F155B16A8162B170F152415FB153B1705157716B6159616BB16B21AAE257221A919661843189517BF1600176F1858160517AB1672168D161B15A915A116BE167015AA17AE17B9161115131781163E16DD16131732162A16771513151317E416B417D81429151A140317F9144A159715F715DC14911539173C15F21554160D1641162A168616551687169217851495151A169216271717185B19001BE823B121701A4C1717182E18D7167E17B917E317CC18881831167D165416B6161F173C17CC172917BF1658171C158717D2142D175517A41441175E152416A6153D17A3161C163F162416771451174116D91529188E17DA137B1708165516A116081892165D14C917611605153E165115A715D7158616BC17E3159E18B118851B7A243E21891AEA17EE16FB171B18421731199117FD1690168516F0140915B516D2172816BF16F618E2152A17B1160017F1151417F117EC1504161E15D6151D156D16DE15D8136916D0147114BA1606168B148817F11502167B14B51791157F186216FB15B9151116DF14D816FD136C16AA166117C9154616F316011861163D19D8243922351B9317FF1871185D18BD17D6192819C31799172C18E71695153617A61787182018F517DD151418BC169F1791163F161E184F168E146B166818F915BC152015CC13DA162A152F14F816CA15E014AA17DB178B153916B315E9147D15D41521170516B115C014C7162D1645166517C616AC176316E4155117D619BD1AF1269422061B7619AE167319A719FF17A7187619B718C419081851178316DF1767161717C31894170516D616C6158917CC16991641185017ED15E416CC14671546157014A414A1138E157D15DD14A2154E176517851695162814B1136C150A15D9162116A416C815DE1442168C15DC153C17CD15F01871176F153A161D19BF1A9F24 ++# Then we get the mean once ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 4024 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2 2 0 2106 ++# And query the status until the device reports callibration ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 4023 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 01 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 4023 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 01 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 4023 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 01 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 4023 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 01 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 4023 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 01 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 4023 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 03 ++# Then the background is fetched a second time, and we get the mean one more time ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 0009 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 F327E021F221D31F8520F31FE21E3F1FC01F4D1F951E0F1E021E421DD41E9F1DA01CC71E681E971C4C1ED41D741FD91D901EF81DDF1EBC1E4A1E061E0A208B1EF61CBA1DEA1C2D1BE31B891D071D981D261DBC1E6B1D121D9D1D251D741CD71DCB1E7B1E801E301CDE1D6F1D551CC11E171DA31F051F801EAD1DD8202F22752DEC2A2023E11F6A217321A11F0E208020AE208D1EAA1FE61EF01DC71E231EF71D0A1D671D031E951DC11DE61E521F4520D11D9F1F251E111F2D1EDA1EE41F8B1DF71DBF1EFE1DA21EB31C091FD11C1C1DA91FAD1EFE1C251DAD1D8B1FFF1EBE1D0B1E361E031F7C1D9F1EED1E321E741E241EA41F4920D01F7320CC203223A92CF72A6824F422CB21BC2013204520A521601F3922CD215521E91F1E1F8D1FAB1F6B1FEC1F4F1F451E4F1E3120A81F321F3D20A920A31F981FCC1F7A1CB61ED71F891F8B20861FB31F9E1E571F191ED51D761E441F1E1EC11E5D1FE51CCD1E131F611F8E1FE71EDB1D7B1F911FB01F4C1EA61E321F8F21B41FE92045217D24CF2EAA2B19277E23DF203F21BA20EE217B20FC1F8D1FBA1F821FCF1FF41EA9200D1E651F421F5A1F3521881E041F361E1F20C61F70208B1F3520AB1EFA1D9D1C711E4520941F8B203F1EE51DE51E741DEB1C9D1E521F291FA51FE51E7E1EB71FF51FC2202F1F5C1FC91EBC1ECE1DD41D561EF81E3F1F4E20C021D11FAF217C23BD2DAF2B752534216F2085201B213B2043209A2045200020B21F181F5D1E2F20AF1F1C1E981FEE1EFF1EDE1EB91E0D21981D2E1E8021D71E8D1BC41E8D1ED61DFD1D8B1F2220321F671D2E1E5C1E741D2A1F121EBA1FFE1D7B1EFA1ED91F5D1E0B1EB01FAB1F8020151E591F481ECC1E8D1E321FCF1EC81FB31EF21FEC217E22562CF629C6248A21B422C31F9C210620BC1F242152209020F720921E341F581F7D1F521F3B1FA61E2120CC1E791EB81F3820EC1D671F911E3F1E301E761EBC1DE81E321FBA1FD11EF11C1C1F4B1D4E1EF91DA61EC61E0D1F2A1F5D1EEE1E781E091FCB1F0B20791E3E1F2B1F551F0F1F2F1F511E9B1F5B216620F61FBA22B723AB2CE129F922AB2115216A202F206E2143200220442133204D1FD31FF41E9B205220E820551FBE1F2A1FCB209620F71E3B1F671D4F1DE21E1A1F431FAC1E4720E21FFA1E9A1FCC1EE91DB51DB01DC91D911D0D1F9820A71E721ECE1E6C1F641EEA1EDF1F281E731FA61E431F151F6D1E0A1F5620B61EFC1FDB1E11216F21ED21152D502A4A2471214322C320C61E651F832077200021E11E981F9F208F21741F4D1FB620FF1F8420C4204B20CF1EC71F6821A41E5A1EE11EA31E501FBC1FFC1E951EDA1E5C1F6E1F361E0A1EC61F6020241D8220871F111E701D9B1EE51C381FD21E181FF01E291F201FE41F621FE91EC51F881F621F671FFA1E70218221E623F42DBB2861231E22ED202221CB1F711EB7209021B520FF1F531F371F111F0420431ECB1E022076204D201B20C11E361DC01F261E7E1F0A1E141D681D0A1F6E1E371EC31EAC1F2E1FD21ED61D7A1DD31CE61D341F281E021F771D7E20451FD91EE61E3B1FF81D5320E01F1A21051F1D1E4D1F5820EA1E651F1E1F821FCA21FE21E62D972BB82255203F209320A61F2B203C209521052020219820E31EFB1F4B20631FF81F041FEE1FC61F9D1FD91FE91D5A1FD51D6C20F81FD41DF71FCC1DB81D8C1EA21E2520B51E111FA81DE41EC71E951DF41E841F1F1FD91E571E711F2A1EFE1EF621491F531E9E2079201D206A20AA1F4620B62053202C20881FE9212E23E92FFD29BC251122C1204E21C21F2C202020AD20A120042279202020591EC61FE61FDB1F511FB71F2F20B01D471F4A1EDD1F3B1D4B1D891DDC1D971E961D3D1DC41C331F7B1E8F1ED41E091D141D831E1B1D571E741DDE1D3D1E961F3D1F2E1FFE1FD21FC31EA41EB61F8420821E911DAB1FA31FE71E171F2B1E73207E2175226F2F132B5C2473211C2352200C1FF31FAC1FA1217621A62055202B1F991F671F38205F1F701F9F1F17223F1FBB20F21D5C1E971E771E061FA11E731D211D481EB31D7A1DAA1EC91D0E1E101E851D971EB51EA81F2E1E341FA31FC21FF61E661EA71F112021203E21401F65214720701FBF202820951F611FC61FE61F2C204124DB2EFF2BE22518224421712026202420E21EF62034209D1F7021A41FF92067207B214620D61FAF1E5D20611F741F041E0C21931F9B1F191F481EEE1ED71F351E511F181E531FC71F131EF51CA11EBB203B1F6B1EED1F921E011FB1209C20F01EC020551F721FF01D9A1E821FBC1F371F63206E1F421FB621B71F9D20AE219A24982C732ADD2495219C2111223A1F0C20AE2079210E21491F6F1FC81EDD1E5920771E0D2006208C1F961F2D1F911EEB1E8D1F2A20F21F5A1E071EFB1FE31D931D851CC31EDB1E871E931D6E1E921E3620971EA020E8201E1FDF1E4D1E881FDE1F49206F20921D8B1ED61DF31FB01DDA1CB91E951FA82090200C20C52070215D23A72EF22926246E22F6207B229F20C621CD1F4B22B51F41217421191F741F671F3F20EE1E7F21C821A11FA71E3D1E041F56209320021F0D1E641FE81EFC1D011E231EFB1F461F481FD81EAD1E1C1EB91E9D1F531F7F205220DD1ED61E931F121E7F1EE41EE31FA41FCC1E6720851FDA1E6B1F80208A1F4E21C31E29206721DB22BA2CB52BD525EE21C02056210F2217217621E71F6821F02195208C1E4A203721A021D71F59215020CC1F8721B421531FE31F491E7F1F13205E1FDA1EFA1EBB1E691E431FB61EF31E491E9A1DCD20821FE81F9C21F31D641E671E491F5A1E9B1E291F4E20121E02205C1F0B21C4211D1FB120B51F9E205D21A9212F21A321B8237F2DB92950250523AF229620C520AA20B42002209D202A2258216B2071208720A420B2205420AA20DF1F4721A11F6520D620E01F9620C81F031E871FC91F601F9F1F711FD920D9205D1F421E1F1DFA1D661F7E1F751FCE1E2E1F5821B21FD91E5620D81FB81EDA1F791E901F531F721FC11DC3208820FE20AD21C5211822D524942E2F2B86247122C71FEF20C321B620F220BD2009218C20C4206F207320E41EA21F571F5A209321711F5E1F5420971FC31F5E1E572005206A1F851F711ED11F4E1FDB20F11F061F3A1EC91F6D1F5A1ED51DDB1ED420311F7A1D0721DE1E201EEE1D7620F71D351F7A1DE91F3E1E5421AD203721AA20EB1F5B206321802155237D2F2529FA25F920AC218A214D210A22962085206220C021611F9F1F25203821D01F5120B7226F2075226521371F9A208121C31E5320891FD11F371FB01E2620F81FA2202F204920FB1DC31F1D1FF81F651DBD1F961EB21EAA1E0E1E8C1DD31D6C1E1E1F42202521F91DAE1FCB1E731E2F1E3E1F8C1F2B1F471F2A228D2112249B2EBB2B0A24C8209E202720B720162070203C1F5C1F1520A6209120761E43215E210B213E1ECD206F21401FBA1E9B1E6D1F3120371F511DA01C2A21011F6020731EA21F9B20491F381F741E661E5C1D501ED91EAF1ECB1D6B1D361F921D501E9E1FB720781F5E1FB51F4C207B1D871D3820191FE01E731FE91E02202222ED226D2D362B1025D522E121242146219B1F58209E204A215922C9209F1F8B1F1D20F3200C20CF22C620C61FDF1F76214D20F01FCB202D1F491FBF1E191F64202520752144210122AD204E20A81E211E5E20BA1DD71F0020BB1F551F1A1EBA1FF11E341FFF1F6D1ECB1E0C1FBC20B11F921FEE22A31FF61FAD21B01E0821CE216B22BD2D702A4024702310216320D820C920E6207F217E21331F7A21CE2062210120AD209E215F1FE1210B20CC206820B7204620131F821F781D0E1EF91F5D1F3F2162206F213222C820732016204C1F921E361F72202220361EE01EC31E7E1F311E831E0C1FE81F701E531F68204A1FC11FE31E451E4A20371FE9208221592127239A2D232AF0234821E721EE21F6214A2177209921F32082218D21A7203D1FB6213920AF20192025203A1E701EF91E461F4A1F2F1E7F1E751D671E121F0E1E14208020531F7E206B20C91FBB1EB12148205C1ED7203620971F391E061FD91ECC1EF41F821FCA1F3921381FD520A9218B20BD1F6D1F561E691FE51FE61FC620F321C22DE82AF7235822D1219D21E31FFC20A72164207A1F8A209821BA1E4D204D22762099207D21F61F3B20BB1FD11FD72043211D20CB1E6D1D721F971F4A1EEC1FD91F312006213B1F481D5F20AC20C020C72062213A20612103204620361F9F1ED9203B1E301F931F011F2920B21E1E2017210821211FCA1F27205921AF20AA23A42E1B2BE92307211D21A021EE20F91F6820D2213A2042221E21A41F621FF41E7B1F961F711F1D205622651F5D1E6B201C205D1F5D1F161FC71EF11D781E391E5C1F321F2920CE1FED1FF91F581F0B213D1F671FD41F9A2059208D209D1E7E1ED21E70203D1E221ED31E791EBD1EDC1EBC21BB205B1F1920A020C122F2226122512D8A2A3B248B21A122562148216C211B210921B01F8820BB20941F7320D0207E207621271F5B2013200F207721051F1A206F1FDE1F3620531E04205E1F5120E61FD4203520E820FF1F501EB71F00209B1EA5203220121F2D1E47204F1E031E0C20861EC81E451FB01D1720081FF71F36217A212F1F501F431F3A21FF20C123032E622BB92452215B209A217121E9202B21D2200A203421E7202B1F43200520DD1FE1205421F31EB920BD1FF91EFE1E9E20811F2B1F6F20631E141F6A1F7120DD1E342030202721E81EA6200E1FA21FFF1FC91E3820161F7B1E391EB31F3F1E4D206A1E0E1EEF1E931E9F1FB31E881F15208B1F8D1FEA1F5E207F1F9721B022A42D702B2D26FE201E2268217221762164227B21672009222E2034233E20BB20DE20E61F032151209220FA1F02200F2085201420EB1ED01D791EB31E191F9C1F6F2020214621E620031F7A20321F27201B1F9F1F651F811EEE1E3C1E2A1FFB1D871EE820D21E341E7D1F7D1F621FD21F461F761FCF1E8B208B20802162213624032FB22BB3242C2375224C2111202A214221D0210B21B71F3C218A200322D120B321D9217B20502124208D208820FA1F951F081F0A20DE1D911DB91E991F981E8D200F216821CC21401FCE1F751F011ECA1E57205C1F6F1FB51E2C20F21DC41E4A208F1FF91E881D601FA41FEC1F44205F21CC1F1521F520EE1FEE200D236023FE2D0C2CEC24C91F1A20F61FFF21A020C020FA21482069227920DB20C31F80205821CA2106214521D122A61FB620101F69219D1E021FED1E081EAB1EAF1EE61E1420342094206C2020206D1FBA1FBC1E741FB720EE1F0F21FF1D941F231F721FA51F0D200020C11FD21FDF1FB320901F471FB71E551FF02029205A207922C6228D2EDF2AE92311214820B72123200D204621B8209122891FE320731FC21FF61EE31D721FDE1FEE2079209B1E101EB4202D20F41EF21EA21F4D1DE61E8A1F851F3E1FFC1E0620C21F0A1FAD1E781D6D1EB31E0E1F4F21EC1DAA1EB71F0420701EE11E551E6820E61FB31DFF20862199217D20F21E1F1E511F7E1F12222E229D22502DB72A3E2666216E227A22861F0620931F4822EF22C1230A22991F7720542266224C2076209220BB20DF1DE41E891E0B1E781E15203E1FB61EC61F691E0B20581FF221C220EA20C11D171E921F151F9E1DC31E6D201F1EEE1E0D20961F3920FA1E971F7A1F3A1EB31F0220621FF31FB31F0D1FB5205A1F1520E91FF3228F23A52D232B08248321AE203021CC20D721E220CA202922AD21A5205421BE2013211521DA201C1F0621671FBF1E3F1F971E761D031E9C1F7F1F27208A1F821F431EE31F1B2073214420C51E0C1DBA1FE31ECD1EEA1F7020A41F1C1F9B1FBF1FE21F151E371F2C1F1A1F3E1F99218E20B11FE71EE41FA71FD620781FD7200522E322032E6D2B5125BB215C22E020ED2109209420D32124214220CA20A62028216421D520971F2321CB1F991F4720C41E0F20A61E771E5E1FEB1F881D5C1F7B20F11E4C1F63214221761FD61D2F1FCD1D911E841EC7201721291EF31EC51F0D1F2F1F5E1EB61E611F3A20CC20D520A21E391E001E4A20A820FD1EAD1FC12106225B22772E5B2B7E240521F121C82262207821EB1F26221C21EF20CE20CD2189209B2170205B20872065202E2067228D20991F1621AA1F8D1F16217E1E711E751FB71F7A206D20E221401F7A1DDC1E491F021FB41DDA1F2A200A1FBE1FA31EB21FDA20121EC51FE81E6C1E991E401F8A20441FCF1F1C1F3B2085218E20B62095227722D92D48294E238E22EB2028220C21A920AE1F1A201F2086215F2238219D2052208F200622C820C11F92210920F61F4121B120C71ED91F6121821EB21E801FA31EB31F1F1F751FA520F21C4B1C21209A20B31D311E8221D820AF1E1620DC201F2092203B1F311F0F20CA216721CF1F421D3F1E881F8D20D3202320A32026229A220C2FF92AF52358224222E021FD1FDB1EFA1F3E2087218722C7206C20D91EC11FB32096211C229A20FA21BF209C1F3C1F5E21DB1F561F4F223620191F1920DC1ED31F141F1D20061F731C301CCE1E981E9E1E51208F201820281FD11FF01D931F241F9B211E1E312059210820E41E201F2A207720D520C921D6203822A921D522AB2D752B1125132294212B2275211A22312243229D21FF217F1F771EBE2186200F20D821C520DB20F920B821031E781FFB20C11F101F6720A41F771F6C1F681FFB2029200020901F941DBE1DDE1D5E1F821ECF209F1F85216D1F1C1FEF1FA61F241FFC1F15207E1F161FDC20381F9F20D9201E21501F2F22D62029214C22DF23492F782B3B24B421A4215421C1209B209B206E232D206C20B5205420732080217E209622BE20F01F8620951F69209D21471FF420C21F541EB11F0D1EB31E6720D31F4E208F205F20431D8A1D351EB41DEE1E2F204D1E321F2B1F941F6C1E2F1F59206320691F141FCD1EB31E2A1FA01F8F20991F461F1B215F1E2D2126226E245E2D712B6A242E2267213F2037209B20AB20B120AC20B0215A210D20DA1E961F3D2009202E212A20D21F5B21FA1F2A206221B61F851F231F181F8E1EAD1EF51F131FE71F9A1F5E1FA71EC71E0D1F731E141E9B1FD11FF81E1F1E18207C1EF41EE81E8F1F06209020C91F0820B51E3E1F2C20D020042078218A20CB21C5224524832E202B062637225123A922D8218E216321D6221321601FED1EA81F002122218B2009220B21341EAA21B01F99202321D31FDE1F0F20101E9F1E81200B1E1C1FAE1F841FB01EFD1EAD1E421E381FA91D941E4B2019208E1F521E1F1E1C1E871FC8204C1F2E203F201D20DF203820F61F35205E1F151F781F7A1F53200C213225842E992B3424852033222E20CC20BE206121372154207C203420F11ED81E1E2035208A206B20B52045200B213820BC201D21D020E11E271EB71D951ECC1EEA1D1F1FD91DAD1E6920441DCF1D521F7D1FE31E0F1F20209720A020D1203C1FEC1EF11EE220941F3F1E941E6B20681FED1FE71F501F1C1FC220431F372126235C249D2C0A2CE224CC2213218D239D1EED20D7215820B91FA21F711FA91E6F1E2F20E61F4D2030200C21DD1F9E1F8F1F2F1F05214C201F1FB31E6C1FC81E3B1E9D1E7F1E261ED21DCC1FF41EB11E5E1EF91ECE1EFB1F111FAC20C51E3B1F0A1FD91E1D1ED11E7F1F281EF31D5A1FFD1FD71FD01F5F1F1620C120DD217621FF1F9C23672DE12AA5249B21AC213621A821E31FD720442093203B20561F7E1ED61F6B1E021F6C1EDF207B20901F6E1DBA1E5520C820701ECF212820931D1D20FD1DB31D9C1FF81E351FD31ED51C921DC21DBC1F851E6D1F731F0B1F931E341F8B1E731E8D1F0C1E6C1D1A1E191E9A1ED31EBE1E8A1FB41F8C1F1A218D1F9F1EA3208623912D3D2B30253522792194227C226F1F501FF62155201220CE1F2A1E661E9720DD1F3F1F2721721FD51F4221DB2028211421FD1F1A1F0F1F0D20A71F491F551FA51E461E801F381F321D8D1EB11FE71E0B20181F28216C1F8720FE1DF81E8F1E831E6A1F681F1C20BF1FBD20FB1D2F1EA61F041FD81F05217B204E21162170221C2DF42A5D2449215721A1218F206520FC2019216821A21FC91FE51FA0209E20AC1F4F1F6C20A2201922E01F582016218520A321FF1F4F1F221F8E1F5B1C1B1F111E0A1F311FAB1F931EF21D511D6B1FB41EAB1EF51F901E471F8B20E41DA71FB11F021F061F621FBF1DBE207B1F6A1E11204C1F0A2031222A21B821EC23B3237B2DF42A9925582230213222DA21C921CD201821B41F4220011F1C1F7320F120512058207C22651FC6208820571F1320662190200E20AB1FC8205C203C1FC71F3720DD1F271E171F541FC01EAB1E2E20E51D361E451ED71F1220151EFD1F0520601FE61D801FC11D9C1EEE1FF61EBE1E2021C31F1E1F99217920C5210222D023202F252BD8246222CB216620CC21B31F2F20F8209C20731F6720CF1F7820392042201421E31F8720E420C31F371FA221EF20711FB51FC41FF91F971F9720BF1F801E8B1EC01D3A1F621EBC1E211F0F1E901D761EBE1F151F8E1E321F781EF71EDC1F3F1F19201D1F491E561F021FD01FCD1FB21EC21F872099201521C8215123882EB72B8E251422822142217A21A4200D1FE81F4420C2212720451F501F2720861E9F200C1E2E20B21FBE1E65207F208E228321A11FF91D541ED51F931D871EA81E981EF01D8A20B21EF61ED81D411EC61D291E1A20541EE01EED1F501F761ECF1F531F6D1D4E1EFD1D531F521F1E1F5E2064205F1F091FBD1F9121132270248B2DB72A8D25FA21C4217022E420891E941F9F217720F41FBF20671FB11FF71FEC20A61EC31ED51F6221FE20D81FED1F291F99200821C71F591F151E441D551EE71E442004201D20BC1FA71EBB1E351EE81E471E5B20A31F711DDC1EF21FCC1EF21DE81C0920191E281F061F6D1FD61E3A1FC61F9C2031203A1F4F21C9200F23292EE22AFE242B22702000219A20632226213221671F672029203B20231FA31F7A1E3020C5223A208821C11E30207C1FB920AC1D411DDC1EF31D091EF81E271F821EC11D3D1F2D1F881E591E0E1D801D791E4820EB1E321F751FDF1F9820881E801F4C1F9520D51E3E1E2F1FB01EE31E2B203E1F701ECE1F8A1F7C22A91F0123422CCE2BA026C023FD21CF2021220D225521B522A721E0210E2005205B204E20A91F3C1F2A206A20B422FC1FB91FE420FE20EE1D1E208E1E6C1FB620091E951F2E1F3A209421801FC41EF01DC41EAC1E751EBE1FC8207B1F9A1E1A1F691F631F261F851F7A207520111EA0216A20921F981FA41F1D20C11FEC1E3A20D521FA22B82D082BE7246724A121072245211921E21F6B22F422C22122219C21F51FB920F41FE51F5421391FD0215821901F03209C1E331F3C1D8F1FD51EFE1F121E761FFC1E9F1F0F219E207B1FD21F641E521F361FE71EEB1E4D1D741EAF20291F4F1ED71E761EFF1EE01E1C1F581EB41E7E20D51F241E851E2B21B81F0F21C020C722D42FE02C28243F223721D521F520A7208F22C52164209F215D20CD1EE21EA21F3D220D205721C1210222E91EBA1F59201E20D81E571F911E131F601EA61EB11F8E1FCE2171212D20371F8B1E401F901E1B1E761F051F0A1EAD1FE21E6D1F301DD31DA81FBB1D841DC41EB420E61E5F200E22A71F7D1EDD207C1FA1214A226523152E482B76257921932236239F22682173211D20F420132278223B1EBD1F371FFD1FB61F741F75203020D021991F062125204E1E6A1F1D22811E701F1F205D1F8A1FCE20A720BF1F52204B1FA11EC91EA71D141F19200E1F1D1FC01E0620701E141F5B20B41E9A1E181F5820A31FBD1EA71F591FBB1F6922A120EC21A822CB223C2C442C5225462342229120C222E520B621B52239217F218D215E21AE1E5E1F651EA120AA1FC31F3522EC206921D41FCE20371FC01F151FBB20781F56202021E71F58200422AF1FC7200320591FA71DB61DB41E6D1F871DFD1D6B1E691F8C1FA41FA81F821F8F20D91DB320D21F301E7A20D31F132043234A21AC20B7220524612DAE2A38259322D8221C214321A720CE22D0205F1F0122E11EB520C21FA7206E1F13213320DD1F86208922E91E242136206B21F420E21FA51EDD1E5F1F2221CF201E20692206215F21F420851F6F210D1F031F9320181FC31EF31FF91FB61FD41F9C1F9F1F4220E01FDF1FDA1F4521DD20371E931D56213720D3218221CF23CE2D422BEE22FA214F21022227201922FD20602175218220E71EB31F301F7120591F7B204920ED1FBF20D31F721F581EAE1F11205B1F3320861FA31E111E071F8A1FBC207F214C217720DE1F8C1E9020241FC62098208320701E5420211FA81F3E20DA1FA5204521341E6B205D1F2D20C91FFF1EC5201C227321BB238D211723DF2DFB298A23A821102167200E21F820B421EC215F215521FC1FF7209E1E6420941FCE1FE01F802034211C20101F3720BD1F401F301F1621FE1E1C20951E5F20901FEE1E9F20DA21A71F1720C020FA1FD11EF61FB61FE51E761F061F361FCD1F101FA11F26206A20F31EA320CC1F8F20C720B71EA4216F200720A1211721C7234F306B2A86231B23C821F92130226C21C4211822272170218A1F04205A203821901F612094211121C3213420EC1F511FAA20CF221F21391FC41D501F3520921F352119200D22992085205E2033211C211C203420CD1ECE20771F0120C91FC91E0820D51FDB1E8B20321ECC208F1F7C1D9920C120AA20E31FD51F5F204F221225D92FEA2A342453224922182226224F20FE2118226521EC21F7209820A41E211FBE21AA21D521EF2158215B208E21962092217120B31F7820CF1F2A1E5821551F021FCE1F6C2103215220022039208E1F011F681FF91FD21E8620E81EF41E622004207B20CE1E671EB31EB220FD1F961F961F5620B920BA20BF1E9520AC220925922F9729A8240E21A2217B204C20262186210C2336218C213120BE2076201C21EF1EC520A6202C21A3211420CA210E212520BC1F1B20B41E9F1E6C1E931FC61FE31FA920CB20BD216B21871F741F2B21EE1E861F231F0E205B20F920061F851E941E3C20E720E2207F1EFF1F841F9F1F8F200A20472071210E21AC21A620E423F32D462AE6241924F01F69202B210E2132202C2118225222A721C220B121FF1F6821372075209C1FE221641F41210220D9208A1F2421BE1E2D1E2E1FD41F9A1FF11F6F1FD01FAC22941FCD1F0D202521091F92202B20DE1E0E1F0C22A81E741EAB1F0C21C920AB1FFC1F4420B320B720CE208220391EFB235320EC20C0232C24182EC22B7F230622A7203D2159231521D720FA212F2179226C224F21F0200D21431ECF209321C220F81E76219E20CA1ECF20A320E21E7D20D41E641E001EA71FCF1F4220E420BD1FDD1FCB1E511F1821081FC91FB820F91F511F5B20B520491E06204E1F9720C81E0E1F4421451F6A1FCF22A31FD81E5621B620382047230922BD2E342B9125B820EF20DD21D020F221F5201E223D2205213B214B208220DD20642149205321252181213420DC212C213B1F7C1EA220951F421FB61F3A1F051FD91F1B217E20151FB81DF11E8F20471F35209921A71F8F20551FE520A61EDB1E481F87200E1EC01E35218921DB1FEC1EB320BD2001226D205120DE1F4022B523762E2B2A4D25F021AA22C0209E21A622B721BA215C1F77231020022289202821A81F8921FE2031220521AF1FED1FBF1EFA201A20D71FCC20EE1EC91F901F2E1E4B1F7720A220541EEA1DD120E51FCA1E511E2E1F9F1F2E208E1F791F791FE71F101FE420CB1F881F441FCB1F9B1F981EED206B1F4820BB2017211721592188234D2E5E28D62359210E21FC229521B91F0622E51F39209C203C1F44217F20BD21A2207C205A21B420B221E21F7E1F1B21C120EF1E1F1FF31EBA1F4C1FEF1EFF1EAF1FC61F212093206A1FF41D1E1F171F101DF71C4120531DA91E8A216221D4205220891E6B1E7F1F201E47218B1FC11FA3207920422084203E206720CE220124422EE3297B24C122B122E2218B211E20E2219720DC1F2B21C5217A1FBB201A211F218C210521BA1F0C22C0201E1F7C21FD1E231F8820C9207E1EEE1E0020F91EA21EB620EE1FDF1E431ED61E721F9A1FE51FE41FEC1FC91FB11FF71E991ED21FB41D6C1E3C206E1F1D1F351F661EA621492024209C20B221801F861FBD21BF23C52CB82A512462229520B7215B222221E6203C218F206820061F4B2013212E217D211520E720E21FFF21C021CA204B207921C91EDE1ED31E041F68208A1F7D1F301E9C203520691E7F1F5F1F4E1EC71F6A1E3A20D9215C1F9220781F841D591FA91E641FFB1F641EDB1F041F3521CE1FF51FBB20BF20CE1F522019228E21AA22282D8F297824CB216C203E2106221A218E1F912177201C2163215320D92088224F1FA41FC721A41F4F1F2120711F502066201220921F0420C41EE51F0220C01FAF200E21FA209220441DAA1E40202820CC1EF6207620BA1FD11D5820821F6B1E6E202520CF1FB920E91FAF203B1FF21FCB212B207821C9207120B420B5219323D32C6229DD231F2251215120C92013200C21A5217721FD1F7322881FD71F3422C92021224020B31FB41F8F1F2A20A91FEC1FBE1F651FF21FB91EA420091FFB1E921E8C204E1FD81F3E1D721E4D1F0920581FCF209A1F5A1FDD1D7220941EAA1F7220D21F611F2520501F6C207E1F0C219B201220CB20BB1F5E2039200D2106231B2ECB2CEF2418220F225B214921791FC320492246212F20E121A41F5520E120592220212A21F2208A1F4620541F8220E8200220CF1F9A1F3E20FC1F711F241D031ED520B31FC820921DCA1EFD1F781F4D1FA91F7820381D641EDE1DBC20BB1E271FCE20B71EDE2017202C1F201FDA1E1820362183207820BE201C22AA203523972F382B252423213E206621E1202D211A21E82059208E2157201F205E1EC21FD0213A208A1F48216021131F461EAA1DB71FF11EF01F511F141FC51FF81D771E7F20B11F1D20F81F2B1EFF1F1D1FA01EA31E9720531F3920491F0320541E5E1F791FAD1FAB1FFA1EB61F761F611FC01F7B21D11FEA1F15214520CB2144217523E62FC22A19252E20C821E9208B2093225A211121FE20B920E120871FAA20872036215F218D21CE20F720901EE121CB1F7E20AA1E84201F1FF51EC31FBE1F061EED1E141FDE1EE71F651E641E6720A91FE81E2A1FA220272113201E20FB1F432000219C211520062013202521761FE51F4020E920CA201E218E1F0D21A6214C23D62FD12B65254B231923D821E1209B21542032229121EF223E21E220482229208A22862265210A21C321A81F711FF0215022FA1F0E1F151EBC1E8C1F931D661F9C1F692046208F21681F6A1F8C20E41F371F5B1F0E209B1F471EEE20C320B31F0F218D20F82187200B1F74222620D1217020201FC621E622ED208E211222A5235D2EB82A942488229C212B233B21D01E28200722A62147226920F4207F213322C621CF210B228B215B22791F2A207E204A21F91D761F291F741E9220C71EA41F951F0C209D2006202720C11E201FD820671F7E1EF920191F2A1FD4206021E0217220B320B41FAF205A1F84216121392015213A1F622122238520D420AA22B7249A2E1C2AE32440214821E62115215C20A02152216D21FC209620CF1F3720EF1F92217B20B921D320CC1F5D207121EE20681F751F011FBD1F511FE41ECD1FE51D631FAC21D81F6621EF1E3B1E811EC81F5C1F8820C820771F40210521971F30221A22BB21A4202D20742152215220C71FC32158206B204E20E121DC2081214524B22DB82A12248F21F9208420C2204A201320C82100215621FC1F9E1F012183210A221922FE206D216A204120B520E81FDE1F411F7220DC20BD1E221F341E7120ED1FE520D320DD1F281ED21D531F131F591D2B20FF1F0720D520E5202C218020FD20CA1FFB206D220A1F6C217621211FB320DA1EA9207520081EBB1FF4210823CD2DAE29A12499217621C220B7204421B6202720CC2166205120F1205821E4200921232149202621F220AC20EC213121EB2076205522AC20C11DE01F3E1F5B1FF11DF71EDA207721631F671EC720691EED1F1D215921A21E02206D213421DB2027215A210B22F31EAF2043205B212520AB200C2067213C2125213F224F227623792DBA2A3F247A23FD208A21E32164208022A5229B2149219B209B215421EC1FA122DA1EF320C5215A216020591FA32096206F1E8C1FDA1EC01F17206D1FC220AF1FE31F4820CE1F611F601F551EEB1EA71F8A207821CC1F8C202E21F3213C229E20DE1FF11F761F07207A216D205521A2217E20402080202E21A9213422C223732EB12A90244C21522140213420EF20DD2110210F228221D3202F1FE21F5C1FFE224721D820452041201D1FA71EAF1E6D218A1D901F391F071FE91F8B207E1E441FEA1F53201D203C20861F681F3320791FC51FBB20D31FD02055212820E3207020011F0420D91EEB1F6420E31E0421B71FB51EC72014210D1F88205B204C24F92DD32BCE2554218D20EE20C3200E206521C621C521D821D1215521C01FBF20E22018208420182195207B20A81F5A207C1FDB20FB1F591F4A209021211F021ED41FF01FF81E1F1EB41DF31E101F2620C51ED2205D20C620581FF820DE20A11FF2204B20941F851FA4202B2002202120FA20D420A320EC21F420FB21FE21DC24612F0C2B3E25D0220E21B9204321A91F4E20872001212E212821DE2000207D212A201E2152218F21F220EE200A1FD31EB91FC31D1D1FB61FD51EB221AA1F3020321E8E1FF21E1A207A1EF71D5B1E3220041F0420B5201D207B1D3A231E207B200A206A1F6A21A620331F23209A1F4A206420771FF520B120182185209821DD23252EBC2AF624D520B321CA21DA217921C51FE3202C21FF20CD203E20392085203E21E81F8C219820E6213322931F7E1F501F2D1FDB1F7E20761FB221D020DA211A216A20D020C920F01FF91E141E9920B21EE41E6120991E34205B2018215A205B2087201E2187207A20422051208020F820E01F7B21E120D51F0B215122C223EA2D212C5223352213221521BC20D61F83215F200D228821F4202B202A218021AB20E520F81F3321A6216721B21F4B20CB1F5D215A1F1D20091F8B21971F7E1FF71FB0204221421F6020531F1820F91F72200F22861F2B20DA1E7721A5200220E220BB1FDD20631F862037212A1FCB20DF20D7216E2170203B1F23225A21D5236A2F2C2ABA2456216320DC1F0A20A51F33200521F41F5921E41DBC209820D51F7F21CA208120531F5D216A1F041F7120E31F1020C91F941FC720C61F601F6D206320BB1F4820BD1F4E1EA41FFB1EF41F051FD41F5520FB1F101EA622502052222722C1208B20281FC31ECC204F2049207220502063201D23E41FC91F2D202023C02CAB2B16253622B1201621CF21DE1F6722FF20F620D720DA1F671F2C20072032225D21B01F6B20CF1FAB1FDF1F991FF11F2E1FCF20921FF3204D20F71FE01FC71F44201B2090204E1EE21C0F2098218E1EB51FAD210D217B205C20551FBA1F4420BF219E2076206921FF204A20512026224B206D1F5120C91F2420A022D123442D9D29EC24942081212521D62114218A219520082123228E20FA20491F16215D20142137207C21CD2075206C1FF820D420D31F1021201E4D1F351FD91EF81F751F721EA81FA81FC31FE31F5820761F471F48208220351E501FEA1FA31F692036205321391FE3208F20E01FC6207C1F18208721CC205A204A1F5E215322D322BD2EBB2B9F24B5217421DC22DB21DF21E5205622842117225222A7212021E5206121F71FC8219F20802120214F1FF1217A1F7A1FFC1FAD1FDB1FB71F5520081F121F1220E020AE2052200E201F215422541EFB2002205720812190214B1FA020841FA621762039211F209C21572150208B205221642158213421A8215A22A2249B2E9D2B8D257C21A920E4206B217521AB2134221A223C217220522008212B207E205A20781F6F206520D81FF51EDE1F191F041F9220C61D9C1ED91F1620831EAC1E9A1F8D1F0F20DF1EE11EF71E751FA31FE81F80201B22F01EEB1F8E20041FA6201421B2208D21FF1D811F2A2125204821CF1F11216F21C51F7E21F8210023652E3B2C40264A2153207721C8200D20AE217522CA205222BE214E20811FA221E420E81E2121D420AC1FEE1F3320AF20AF20861E49201520221FA521911F091FDA1F67206B208D207B1DE21EFC1D7E1E181E9920D520AE2013200B21071FDB203B2108208E2099200E211B22851EF11FD92024211B20F91F32211622B420DC23172FE52C94257D226321F62138225522DE213420BD20941F1B21C61EDC1F5A216C209D203821131F2C20201F331E181E151F5E1F241F0E1F2F20CB1F54217A20E11E99203620561EDF1C381FBB1EA11ED01F851F4422D11F8A1EE91EF71ED5215621B920821F8E1ED41F242289200821BD2195210D21F020AC2091202F20F221512D802BF02449246F214D2125203D214922B120E11F01219B20281F741E9E1E5220BC201D2119209E20F51F1B1FCB1F3121051FA01F7A1E161F1A207D1EF21F6D20A01F751EC81E171FAF1F941E471E57204B1E0622481F571D021F761E481EDF1D341E6D1FC021D41FF621B421A421C42048205120D91F4520BD21A022A024D32E032CF024E8215222D920D720532196217D217B20631F9220E91F941FC01F872097209720652150209720851FB8206320F11FCC1E2D1FE21E721F371F961FC7200F1F6F1F7E1F581C4D1FAB1DBF1EA21E221E8A1F801E581F531F691F56206E1E011F6C20572117215D2098208520DF20581FB520C620BD1FB820012248238E2C9B2B6A23E22061206421342046224B200821502197203920691F101FFA20DF20E71FE5201E20FD203E1FDE1F2A220B211D1FBB1E9E1E4620621FF91D791FEA1FF11F6D1ED11E8B1DF41EB41D741FBA1E9C1E861FA51EA31EBE20591EFC1FA41F4620D91F8B20FC1E96210520F41FF221E720FB1F7A20D020B71FFA21FB23F52BD62AA4257A222E2283225B20BE222F20BE22A521921ECB1F76217B201420F22046206B21F020C320B4202F20AE20DD21EE1FA11F06200620F81E9C1FD31E521FC21F0E20721F731D67203220121FAE1DF2204321F31FAD1F901FFA1E3421D82051217B20601F7B21F420941F0820182092206721C121E91F372069204722262D712A852510224720F720A71FB81F4320981F03202520E71F6020DB1F83201F211E20D21E4C21811F1B21352054213D20731E3A20EC1C331EBA1F8B20551E7B1FEB1F6F21E91F8F1C691E481D7120581D931E5220611FEF1DB51FD32079206720321FDF20DA21831F482222210821AE209A216B1E1E20AD20DE2085224022962DA52AD425C0214421BB208E1F2B1F21214B2137207821CE21991FEC1F4121A620B01E29203020F220C51F131FF01EF71E1B2066219D1F311FDB20E9202D2037208F1FA91F7E1F131D6F1D2E1FC11FCF1E3C1FDE1FB51E3620411F051E1120BE1FEF21781F7E2037204C200C203921D620DF1D0420E71F761FC5209C21EE23042D6A2A1126C2213422F421B521B21F34223C22F72008203121F720A820F0208A213720D120B3203523FC202320D221EB20C3210D2192208820AC1F8C205920B020781F89205C20BD1F1B1F871F5B20E120C01FB41F651FCA1FA41F0E1FED1E0B1FC0217B20B51F622129219B2061204A208A20E2208220DC1F302083210A23712C3E2ED7244F21832166220A2010213E206F20B0236A21F220981FBE1E04212A20C31F1F22FF1F8621E620792051203721C820F920AA20BD1D601FA41F541FB7201420E61E171EF91E6F1EC81FB81F481FA71FC2201F20461F0A214A1F7A1F1D20BB20DE1FB41FCD1E6721842031202321CF1FC020D91F501EEA20CE202522BE2D252C76265821B721DB1F3E215320F6208D216D218D22CC20E51F5721BE20442127205121DE20C6203B1FA120B7216B207520A421B71FB61EF3207D1EBB207A1EEF1FAC1E731EB81FB71D581E4B1F8A1E161F7B1F001F571F2C20C01F411F80208221DD20FD1FF11FD120FB20192138210D1F7B203B1F591FB0208C21CB23012E682B3724F4216C1F5A2020213F2011212520F920B220E1207B205A209A21132231209021ED2029210521352037205B2092224420541FD21E861E671FB71F331F6A1F461FB41FC91DBB1C7F1F431E791D111F2121361F72203B20FC1F9B218A21DD1FE91F7A200521AD1F1620611FC4204B201F1F8D1FB21F9D1EFE21C924AA2DAF2A0D25B32190220C239F22D520E822F621D321F81FAD20B020C81F9121B5215920F71F10210C21EE1ED31F5E1FCA20221FC920EE1E5B1EC21FEC1FE31E2A2162204F1E8B1F791E811D281F19204F1EA720FC218A1F341E951F431F3B200D208421BB20851FAB1F871F35201820712034217B20D620CF1FA0209F203222402E582B9724D4217B238F21652328227E212D22FE223B22C620CE20D81E4E202C206A204B20DA20CF202221601F50213A20FC1FD520061F702005205C202E1F8F1EA120DE20981EF81EA91EBF1F661EB41D0321201F5C20B11E3220DA216E20F41FBC211821FE21D71FF2207420DB2072220B2128214220371F85212D226D22D62DC92B84266723CF2050210220F8229B215520F8205D21AB206E1E7920E620842157200820C620AC21A9204821D720CE20FC20A5204E203B21E120461FAA1F9A1F3E217E21C61F711EDA1E2520AF1FE01E9520F420B11FE81EF51FE1209720871E2521F720F71E151F5D205921FB1EBC209C1FB9202920411F1D2157214F23892E332BDE257D23D222AE219421AB216C20FD20EC21E8204821F7202420F51F3720921F922166213820841F6D1FEC239521AD1E611EF41F881FA9206D20BD1F3821902029202020281E1F1E721E741FD41E5B213820CA1F86205A204D1F7120FF1F7F20A420E820BE1D7D1F2E1FD01F9B21B91F04218320C81F8B20B821A523A12CD12CD926AE23262324220A212022D7200823912206211C227A207B2152217B20F31F851FB421C620EB2188206D209D1F5920CE20831F4F219C20EE1FFA1F4221622053218F20F11DB41F691F481F0420BC21B5219C1F6D1F371F881F321F8F213D21CA20E720A020A41F281F8A1F1721C320CE1F741FF31F97204221EE22012E9C2B78253C2224239421FB2071212F229F21E61F512050200420C2216321491F8F1F5D1F2A234E21F21FAE1F0D20F820E71F851F99208620EE1D2C1E6E1EF21E45208C20C51E391E2B1EA9203F1FED1F0D218B20BC1F8E1FCE1FF81F392290214520B61F122101209021F01F5920A41F681F6720612022200B1FD4212723782E4D2A6025ED21C71FA4211B229D2121224A224922332160213C20FE1F2321A4210E2057215722B521DC20E12296204E2265217D2032205320551FE51EDF1EAC1F4C210720731FCF1E751D2D1ED91FC91FAE2152216B20C01F3020F51E30211B21D4201021FE1FB61FD020792245200220A31F92210E20B21E3921BD209224FC2EDA2AB8245E2130210721EA2023228E204B214B210A200A2063206C205B213F210B20B51FEE210122C9210D22C220C71FAE1F29219120B81F3520C71E2B1F4D1E751F541F081FDC1D0E1E801FFC1FD01EEE1F8C21C52000201F210C1F491F9A1F1321AF1FD31F271E5120B020FE1F5220E51FAB21772185209320E5214D24082E1B2C4B259E22B020A0221A2182203D226720B52143205E20EE1FE51E071FE81F582092217122BA22902063208E229C201B1F8D1FAF1FCD1ECE1FB61E091F6920A71FF11E771E531D431E4F1E951ECE1D251FF920421F421F351F6B1FF81FCE1EB21F951FEB1F2F1FF61FDB1F812125212E205A20C020071F8C207E229322D42DDB2BE023B522B420A120E620B020ED20B021C9210A20A01FD41E06202720461F9620C321932092215020A0204D21441F6220951FEC1ED31E201F1D20251F9E1F27205F1EEF1D491E0E1E4E1EE51D7E1E9C1F2321C91F191F4D20BE1FEF1E841F171F4E20CF209B1FB7200F20032063200B2134204C2007219D20F721C823EB2ECF2B27251A234D21BC2143206420DA1F0422E820B320D8208A1F9B1E521FD5203E20D720BE1F722122201920F621B120CC1F1E218D1E571E1420C41E631EA91DD01F2D1F0F1DDD1C451D841ECB1C5B1EDC20B71F2B20EF1E07214C202C1FE81F011F5F1F40205F1FE0208720B01E4A20F720FA1E472104201A2192225124DB2DDB29BD24EB20DB21BD21611FD21F95203921C9204921AE1F791F141EC21DFD1FD91F65208720C420B51F1B2018202D21F11F0D1FF01E571FBA20A4208F1F7E1F5520F41F701EB31DB31D391F8B1E3B1DF0200A224C20231FBF20B11FA71E5B201B21F31F4520731F7E20321FB41F2420E2205A208920232005217521D823152E742AF9231522CB1F8621082072212B229F20472132218E20B21FF21E7E20CD1F2820EC1F8023E120DC20D01E3E20DB20D71F011FE11F0420C11FA81EE01D231F2C20A11EE11DE21E8D1EE61D3E20F11EC222AB204320E31F32203420721FB61F611FDB1FFC2151205821C01F5B201B1F0A2117226A23C9215721432183247A2EC92A36237D20C621B820C820351F6322F120B921BA216B223220CC1F1D22C3210B20F9209C1F9722FA20191E2621BA2141212920E71E321F06203A1FC11D0A1FEA1DD61D661E3C1D161DC41E781E851E0D21811FD41F3C211E21631F3D1E79200A20EA2092203D20C620431FA01FA321451FAF20A821911FAE200F226F257F2EE12A55239A2257207B21AE2014209521F520CD1FC8208720D8218020492104229E1F8E202C20FC218321DD1F1C20FF1E2B1E2620711FFC1E041F0C1FD31D1F1D1C1E4820C61DCB1D7E1ED51BCE1F1E1F96210720681FEA1E7F1FF11EC31EDE1F6C208C1F2521961FC6211E1F1C201C1F7020FB1F1E2242205521A422E523FD2EBD29A72481215221271F83213B20861F95203E21C3211C202A202D214920A31F0F21BC2076216621C51F65208320FA1FD81FBF20741F211F081F681DBF1DDE1D321DE61DC01D661DF41DF41DDB1DF91E6B210822B7200020D81F452031202D21C6217C1FA71E471FEF21C920DE208620AE208A204A216820BE20F6216B24B02F1E2BF2230F22ED1FCF1FE91F6B20DD21F920791FF7203920CF207F1E321FB21FAA1EC1215C2157213F202721D21F0A2291201220AB1EF61FC91F1B1F871F031FDD1E911E981D611E241DA11FC91F6420691F6B214820BD1F7B20F11EFE1FF520C020B81FDD1FD220AE21E11F20207520ED20C51F47208D20972147229F22472EB729FE233C21CA20572036205F20D01F6021881FE11FF21F9F1FD71FC220EE21B82057204A204820152013206021A61F111FF91EEB1E771E491F281F631E471E521EDF1BB71C001C181F8C1D1320A81F22206F212A1FE11E911F1D216E1F0D21A720921F4E1FF81F801FAB1E35214D218A200F20F51F032015215521DF23F82ED82A5E24F0221E20661F7B2073206720CF208720C220D5211120281F3721242170204420F820701F6820411FB81F022175204D204F21E41E491FC71E091DE11D041D021CBB1D511DC61E921E081F671E591F931FFE1E0D2165220B20F61FF920DB21EA21071F6B203D213A208E1F35206B1F6F1F5420CB1F3D21F1217824B52EF92B6F235821F3209720C8208020CA1FAA20A320AF1F87203F20451FC21FE51FFB1FF71FD620C61F0520D91FA41F9D20301F531F361EF21FAE1E861EA81E701D641D211CA51DE91E811FA81F071FD31F85201F1F3F1FB3210B20B51FF51F4E1F9321822107210B2042205A20C51F24214F1FD21F202173211A210B235F23BA2E87292B248022E02065203121B41E05209F204C202C21ED1FC6216C20A5214320D320D0205221DE1F8A208A1FB520D922CC1E4C208F1F6320241EC11E1D1F611D031D281D6B1D471DF81ED11FC11FBA1E4321B91FD51F431F05204B1EE41EC3216020E12028209E1F0121D6201E209D205420BF1E9820921DA91F2F215D23D22EE1295D25612097217D20D520F020881F2522091F441FC9209721FE208920D8214B1F2320B620AF21731F741F2E20BD21FF1F611F381E281F861FB71E1A1D041DF51C3F1E2A1D671DD81D081F2A20121FB21FB820C31F6E1FAC20761EFC1EBE1E8821F81DAA1E581E7A1F331E66202C1FB721DD1E4B1F17211A20AE210F23192DF12969255F2176204520B720532048207C21642025203F207A211A1E051FA21F9B205D21F01EAD21DC1F321FFE1F1A1F321FEF1DCE1EA11CFE1FD11DFB1F701EDB1E2E1E2C1E5E1DA31FE01E361F8F1FD41ED21EA41F931E9320D31D9A1F1C1FD02007206D20DD1F8221D31E63201C20C91F2A1FFE1FD220C0228B22B423D62ECF2B64250F212C214A21C721D61FE7206E210B21EA21BB20E81FD420ED2096200B21D0216520D921B01F271FED1F4621AD1FCB1F771EB41D7C1E601F1D1EA51F811FDE1C441D7C1E7C1DFA1FBA200D1EB720F720711F3E1D3620D61F8521C01F4C20E81F9D203B1F2721DB20DC1F0F1F2121BE1F1721651F332184207E227E2DE22A99240E22CC2019208520E5210021C522B221AB205D21ED215720E021A8200321B4203921CB20B31FE7205B210621D01FBE20B61FA31E4B1F9C20AF1F8C1E201F691EDD1E491E3E1F2420ED1FCB1EB91E0420AB1F3A1E0D1FA91FC420DB1F931FCA2063200E1F9D1F5D1FC31EE1205520DB202C21A11F61210D22B423722F7B29BE22CC21EB202E206621201FCC204222382178218720A02012206420012142205820D3216721221F491F31204420B51E7E208C1E51206D1FB11DE71F941E331EDC1E0020591D2A1FCA1F251E2C1F591F1820F41E0920B520E41F761F6D1E841FB01FC11F6F1E9F1F1E1F8C1F1320411FD61F76218E1F712158216723742D802AB4235D202D22C42104219C207521972201200920C7212020DF208620FC20CC21E420EF209E218E2014208D21EB20B31EF81FB61FFB1E041FC51FD91FCD1F7D1FF71ED81D8A1E141F041FC41F0020E5206820CA1F111F8A1F2A207E1E0D20CE1F3C1FDB1E571FC21F6F2010207F22E31F522089203320F5207E213924682ED8297924F8227520F42010210020C81FED209821C720AB21A21FAA204B205E22A920DB20FE219520402111206121741F811FED20DF1E4620E61F051E561EA11D9F1E401D371E5C1E381E2F1E6F1F2E1F08204A1F201E1120BA1F321F551F9F1FF620B21FEF1F9820CA20781FA11F701F36201821F31EB020332124212622F42EDE2BAF251222A520E1209520D120702025214321A81FE31F351F8A1F56216B1EA91F712069203321E62106216620BA1E1320F7200B21CD1E4B20581E691FD71F521F5E1E291FB41C891E9E1E341E1B1E1720D620B71FAF1F5B1F6F1F271F5C20572081201C2019206521A71F35201922A91FCC1F7F20FA1EA21FEE228823D32F3E2AA924C521D020CB205D21B01F2022C21E23204C206120B21F26212E21271F261FF020C01F12214D1F641F3720CF1FFF1E4F209920741FCF20DF1F6820C71F931FC91E681E621D611E4F1FF51EB81EC91ECD2020202C1FFC1E6E1F871FE51F8620E81FF61F301F1921881EC71F7C1F4C1FBC205E20A21FB421D921D823612E672AA1223021AF22E32025214920FA20E520A91FEF215F21A41F1621FE20DE201722BE1F6F211E22D320481FD7203321B01EF51F731F6D1F4A1F511EB41F411E3F1FA81F9520101E611E121FBA1F901E851FA021311F0B1FE6203020F320E320D51E9D1E631FD01FB420C020E61E5320A320261FD51F911F9E1F1521D322672CFC2A6D253E217E21E2220C200421B1205321EA21A8208D20D8218A209D1FF3214422F52166215C222E20A21E68201021991F051F30208520401E8E1F641F071E8A203720251F6D1D7920F51E4C203F1E88206D200C1F221FE520AB1ED121B21E4F2103210B20DB1E2D20D31F1D207621F31F381E861FB41F3C21A121ED23202F862CCB249F21282102234A204C2141200721DA20F920E41F1E20E31E881FF81F6120C1204C1F8720E81F651FAB1F82210B21821FF91E8A1CF31E331E1620051F301F831E8F1FF31E301DF8205A1FEE1D021FC41FAD1DA31F861F6E1F9B1EBB1F8B1F091FEC1FA31D2420E31FC31F421F8E1F831F3B201F2060201C21BE22052FDD2AB02428233D203620302026218F201022AB2084200B20B71F49219621AF1ECA206B20A420AA21C220AE1F7820A11FAF1F5220EE1D081D1E20A31F2C1F841E5D1FCC20B71EC61DEF1C0D1F891D7A1E791FA91F1E1D251E4A209D1F1D20CC1D4A206E20AA1F28208B1F651F371F13211E1F471FC81FC21D3F21FE214024532DA92AAF24B722512191203A214622E321972148201F219E214120DF1F84202C21A320DD1FC51FE0202521DD1FB61F0220C1205B1F0D1E0B1F861D3120F21E941FFC1E081FEE1F151E561D991E7B1E411E721F5A1E7D1E551E431F5420051F4C212F20431E491FD7200B211F1E181FD41F3D1F541E3A207D1F5521B422D723172D8A2A6A251B21A120FB1FAD1FED2102214521E71F0D21C01E991F411FFC1FDD1FBD20AD1FA92080204121581EAD1F91227F21AD206D1F501E5C1FE11EFE2023214C1F351FEA1F251D1D1EBC1E601E141F461F3420C320CB1EB1208E1F7F1FC71E0521DD1FB21E661E6D203F20D21EC01F5A1E7F1F36212D20BC20BE22AE24E02DEC2A86247C22BA20522103211D2050200821C81FF5200A1F1D20FC1E6F1F271F701EAB1F561F981F0D1EA81DD41E6B204820C41EB51D251F0D1F181FB91FE61F3E20E61F6A1E9B1D2C1F351FE41EAA1E411E2F1FD41D871F0220311F001E2E1F631F9B1E211F0C205D20541EFB1DC21E6720FC1D8C1FAE1E831FB81F9723BE2E882A8123DB21BF212921292048209C219B1FA8206020F41FB21F421EE51E2420E51F0A1F05210D210320361E90200F20B01F2B206E207D1F8B1FE91E3C1E55206620EE20061E881E841DBE1F551EAC1EBC1E3A1FE91DDD1E9920631E4E1F831F801FB21F671F651FC01F5520EB20B61D421E6D1F1F20F32086210523F423252D902A1524522034213421D31FD720BC20C120F7215221201F961F6A1F282079206B20CE203520D51F69202F1E9E20F21DD21F4720D11DCB1F511EF51ECB1EB820DC1FF11E811F891F571D9D1F661FB61E3D216D20E41CA41FBB1E0E1F421F13218B1F741D78208C1F351E491F661EBA1EED1EFC1F6020CE1EB321E021AA249D2DB12AD0244F219D2057212B21CC208E2221216120D11FA11F711E611E18209621D71F53207A225E1FA220D91F9F20731FA620A121691F801F021F761FA11E0320A71F681D471F3D1EE21D7A1F6A1F221EA120801F631F231E6920EA1EFC21A01F461F4A1F5E1F691E8120891D771F0E20C020F01EED1F7B207821F01FAF22682ED82BDC2411215322B321B121F520FC227C22FF20DC2078212E20981E9A20D620DD21A1215421191F2821EE1FBF200120A71F8321A21FD61D3C1F9B21481FD31E601E181DFC1E291E861D571F081F591EB520EC20DC1E861FB41EE51D921E061F8E20F21EFF1EC21DB71F351F981F8D204F20DA20681F081F3C2030234F244C30EA2BD524D122E21F9F22D8224A21D2217F22EB2113237C216120C51F4B219C1F61204A22EB20161F0C20041F95204A207F1F8B21BC20581F30206A1EC01EB51EC31D8F1D951C0C1EE71E341E9F1E6120A520991FDA1F3D1D7F1CFC1D461E26203E1F9E1F1E1FF61D551FA51E471F8A201F1F2822C920C51E4E1F75222724152E ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 4024 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2 2 0 20B3 ++# DONE callibrating ++ ++# First turn on LED ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 4031 ++# The capture loop does 1. report finger (403F) 2. get image (0009) ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 403F ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 0009 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 042817222D2226209D202A20071F4A1FBC1F031F561EC31DDD1D7F1D211F861DBF1CAE1E6B1EA01C5A1EB81D891FD81DD01E2C1E011FDE1E4E1E1E1E0420BB1E141DEB1D3D1D531BFA1B911D091DC41D421DB41E501D621DF81D5C1D411CA81DBE1EA11EB91E2E1CDA1D411D7B1C021F211DCA1F1F1FCA1E0F1EBE205322902DDD2A3A23DA1F7F218521A61F4F20B820BF20AD1EDB1F021F0A1EE11E891E1E1E6D1DD01DC41D7F1DF91D201F681F5D20FA1D921F1C1E271FA71E2E1F9A1F231E031E051FFD1DB21ED41C1F1F561D7F1D5B1F911E6A1D521DDD1DFA1F1B1FFB1D4F1EAD1E281F181E071F381F6A1EAB1E801EE31FCA20CE1FB320BC20B3230B2D932AF7238D228D216B20AA1F6F2034211D1FF52154213321EB1FC81E691F681F001FCA1F271F0C1EE01DB81FFD1EFA1EF61F7420521F2B1F691F631C4D1E931F2B1F1620181F251F3D1ECB1E951D601D321E161FAF1D7C1E051F7B1CBD1EEE1E0B1FD11E981E7E1D241F061F311FD41DF41DAE1E3F214C1F8120BF201B24342EE52B7A2799232C219F21D220D721BA202C20DA1FB41FB01F1D20FE1ECE204C1E891F991F841F2521E91E351F711E1820F61FBF20DA1F5120CF1E2A1EA51C8B1E3020BF1F9420461E051EFE1EB21D371D7E1E541F461FAE1F0D1FCF1ED21F1020F420741F8B1F991E8A1E2B1EEE1D301E221F8E1F3020AD214420AB218523DF2D082CA3256621B5207B201F219C20C020202152201E200B205B1FB51E4520E91F911E03200F1F531F2F1F261F8421BD1D5E1E6B21F31EE81BEA1E881E521E3D1EE81F8C20A81F701D841ECE1EE01D2F1F0D1E67203D1EE71E331FDE1F701E801EE91FC01F8D20941E791F9E1E5C1FFA1E621F321FFD1FCB1E502022229422A72C3A2A5525EA21EC22F61F152243207B20EA21B120F3205D21361F8A1FC41F2E20FF1F911F0C1FCE20F41E141F1D205C208D1EBE1FEA1EA01E6C1EFB1E711E8E1F7B1F13200B1F571D7B1FB11DF31E4D1E161F3A1F841F921F941E371FAC1E861F1F206520021FBF1F771FFA1F6C1FB51FA91EDB1F87216F20F71FF0222424C42C7F2A3823072278219A2096209C21B82028207821AC20911F1C204A1FC020A8202321981F3F20801F4721DA20631F8F1FD41DD21D191F291F7F1FEC1E8620D71FF11EED1F511F691E0D1E421E281EF51D3D1FC920B01E971E851FC41F971E091F4520861ED61F0D1F5B1F541F041F3E1F6120D31E4920371F3C21FD21ED21752DBF2AB324052289229520E41EEF1FC5209C201F21301FAF1FDD20D621D61FAE1F03217320DC204B217420ED1EE61F8B21FF1EF31E621FC71EB61F4220761FD91E061F641FC81F681E821E03205620AF1DA2209E1F551EAA1DB11E9C1D5F1FE81EBF1F691F5A1F7D1F1F20AF1FEC1EFA1FBD1FB51F711F0F1F8721D0210F242A2E7029932484221B215F21C21F811EA820AA21CC2045209C1FA01F051F21205B1EC11E4720902071203920061F661DEF1F541E1920D21D1F1DFD1D971FB81E7C1E2E1FF01F761FE11E1F1EE41D161D321E9F1FA11E3A1FB91DE0204D1FE11E361F951F731E8A2047202721891F251EC31F7F20111F6F1F7C1FFB1FEC21F421592EC82B822291208720E7207A1F9120FB1FD721022062216D20CF1EEA1F1920961F3920301F2B20DE1FEF1FF01F4C1E8D1FD61D772021207A1E31202B1EE11DD71E121F5520131F5D1FB21DFE1EDF1E701D141FC21F551FD31E761EB71F901EEF1E5F22951F6C1E42205A206F20A020681F1C20D72047207920A91F2B224623F32FF0291926AC2288209821FC1FB9203B20CC20D8202B22CF208720C61EE81F0F204520F51F05204620131E801F921E2F20AD1D911DD71DB41DF61E281EB01D781D871FFC1EEB1E301F731D401DE51E721DCC1EC81D441E8B1EFC1F3D1F411F7B2027203E1FFC1EF11FD520E81E1F1EDE1FAE1F381F991F821E8720CD216E22D52F672B8524AA213623C520421F2E20D81FA6215421C0208820931F901F681F6420D61FF41F7B1F13224A1FDA20361EBF1EBA1EC61E291FCC1EC71D581DD71E0C1E681D2C1F011E5F1E5D1ED61D0D1FEC1ECC1F761EA11FBE1FE51F381FE71E37204C2045207F217A1F9021A120651F13213A20C71F8C1FE91FEB1F94209024B12E1F2C1F263E224221C22032206120951FF42091209B1FA1219D1F29218620A621D620EE1FDC1EC520E21FAD1F5D1E2521B81FEB1F3F1FB71EC41EB21F951E521F1A1E911F0920671E4A1DD01EFB20521F841E4220F51E571F1B21B620DE1EFB20B91FCD1F241EB61EF51F941F901F7C20F31F9A1FA6210720E020FE21ED249D2CEE2A592529222F228522D41F74205C212F22862106200920761F431F2F21171F8D207D20E31FEC1F9E1F281F581F24204C204D20E11E921EC220551E171E441D5E1F521F431F1D1EFB1EEF1EAC20321F31216221F41F361F0F1F26201820CA205721301E081F621E6C201D1E5E1D261F3C203B21232173209821ED21D923802F182A5D24AD22DA20802296200522E31F9E22C71F1D219C21FC1E821F391F3C20F71E85211522C31FE11E701E401F93206C20191F3D1E861F611FD11D311E391EDC1F641F6D1F2F1FAD1E401EB81E9B1FA41F9F20B920A91E071F8B1F321EC51E331F1D200720551F9F20D01FEC1EE31FC220B61F5721151F4420A421C922402D852B9425BB218D203F21A32132217621EE1F4721D22162209D1E8D201721C321FD1F44213A20D81F6421CE21551FC51F561EAD1F3220221FDA1EC71E801E311E621F7D1E3E1F471EA61DF2206B1FA91F8C211B1E551E4E1E561FEC1ED71E751F5D20741E0A20621FF820AB211D1FE020CD1FF9203021B321D12097210324492D5E2966251223C422AA207220D5208F2015205020F921302170207B20482096209C202120A320F51F4321651F4A206C20D21F9820CD1F0B1E661FE21F7E1F851F4E1FBE20CE20591FE81DDD1C291E8C1F971F181F941E4C1F7B217E1FD41E2220F41FCB1EC81FD01EAB1F1D1F8A1FAB1D80206D20FB209421AE21FC2180241B2E0C2BB424C82275206C21FE21192104212E217D21F0200D21EB20CF20191FEC1FCE1FBE20A1211220DC1FA92015204C20AD1EC42070209D1FF31FE51E27208F1F73213620231F8B1E2B20C11F1E1F0D1E481F2721B81FEC1D2E21241F711E6F1E2421821E971FDD1D5820F11EAE211321AC21F9202B20E420A1219A217223E12F90296B26A821F721F62185215622ED20AB204F20DA219D1F68206C205C210520AB201323A920FC22B821C11F6B210422E91EA32031207420EA1F1B1FC62064202121AD20C420171EAB20CB1F8020A81D4020181F2A1FE91E781E0B1E411E121F971F7B209A21451EB020481FE31E911E0620B61F6B1FC51F352207224924C52ED82B07240921F120A82005216E201F21751FC81F7B20EE20C520F51E7A217D213721E51E22216221A91F9A1FFC1EB31F9A20E61FAE1D201DC6211B1FAF20EE1E762032210620C71F2E1FE41EE51DB01E681F6A1F1A1EE11DC51F321E1E1F0E2064213E20182048204A21331E2A1EAC20971F6E1FCB1F2F1FB02088227823D62D4A2B0225EF2202228B213E2112209320F82064218522FA200A20CA1F232047214820502326216B202820EA21B5209F203721851FF51F1B1F961FBD20B2201D22F1216922F320D520031FEC1E0021211E2D2066201F20F91F411E6620431F9F1F6B204E1F741F921F63218C2058205E232F209E2068225A1FC2216D222523382EA32A4124AF230921832047212921D420BC219C218F1F7321E12093217620F8207921A91F81222D20D0209D2000216A204D1FD11F9D1D951E5F209A1F8521AA20BE217C226B2106216C20D11F091FA51FE1205B20701E111F9E1FC91F9E1E1D1FBA1F6020FC1E12200A21E01FA4208C1F1B1F29218F1F8221CD21AD219023AD2D9A2A4C24FA2178228A220F22D32131212B22AC214B22132298210920662215218A219B20C920FB1E3F1FCF1FD41F22200C1F711F6E1E471FDA1FEC1EB8207221FF1F60211921E620D21FAB22ED20031FAC21DE208920581F1820E21FAE1FF820212100212D226620F2211E235721D4205720801F5820F420EF20DE219F22972E3A2B1B24CA2238223422352049213322F820F71FC220D021681FC920FF22EE201721132252200F215C207D208F21C821CA20441F231E1F207B20031FD720BF202F212922ED1F2F1E1121A52178218221F421F820D721FC2029212420B21FA921621F30209520F41F6A21D21F1521AE21B6210820B020D3203C2272210724032F7B2B782477219D2125227E219D20F2209A22E720F822A021842054209F1F1F2056204F20F62009231E20991F2D21E0201420F01FC91F2B1FE41E651FFF1E672021203521DD20D120D1201920E12151204220C02076210121B9219D1F741FFD1FE0215A1F291F3320861FCD1F1420C2220322DB207A2165216F23D423EB22D72D1F2BED24FE210E237321B92125227A21D72150203E21982171203B21862132215622F71F3221A320F320F021EF1FA8202F20B3201D21551F1E2171207F210221AD219421FD215821781F01212221BC1F8B211A210B20351FAA21591F401F2A21FC1F51206F20AD1E502181209E21A222A42268205A2053203522C8218E24AF2E8E2B1225BC21F5204E22E221A421DA219221A620DB21CA21D41FEC20C520EE200A22ED215E1F44214F200020BC1F822191203A206921BA1F60209A20C6214D204C214421B9222F201E22682029215D21582082212E20701FC21F0221CE1FEA216320B61FF820732003213A203A2195215C21EA203E218D21F02044227B23952ED92BD1267B21922219223C226322DB2242225421A922412127245821AB219821D1202B2255218D21D220A5201A2186213D216820321F02201D20AE20A020962172225C225222D3205222FB20E421912019218D20B01F3E20601FCB201320B820E322E2203F20A7217F217D21A52173214C217A200B221E22DC2291222825DB2F332C33253624C0231C220521F021162227233D224D201D224221DB227C21A52282226A215B220C21132159211821D120BC20A3219C1FE91E33201E2145200A22E12243237B231B21A521C721AE1F3920C421B12009213A20EA21CB1F4721D1221322BF210320A421A921F32137228B23CA21E922DB22912170226B248124DD2E032DF725F5203521F3202C23BA21F521222325214E23A321A321A4207C217222DE221E228222CA23FE20BC21AA201F234A20F020F820F01FB1202920D120D121422287221623AF22C821EE21BF206D21B022EE210823F01FCF218521FC21B72246231023AA221722AC2272235A2262228921E12166234222A12261247424D92FBF2BF4247122D32106238F216F2193221D22D623D120F221CF202D217720451FE920B021A422BE2106200220AC221B2259215721552232202221E62144220F222E22E1220423F1219A210920EF207D21EC212324A3201021F321F022AB214722F521B5232223DC203524E424B9258A245622572190227E22C424AC24E524B32E172BFB26A6227D234A23B020AC207E2027231724BC243123D9208521CB23B123A021FF2147229C227F1F6A201A201F20EC207C22F821F7203F229F20CF226A227E25122403247720B5201D2228229A2049227B2313219E2135226A224A23BA2189226A224521182300245623F423CC232323F323BF226F23F8227625A325EE2EDC2B2525B0220D22B822F521E4223F22CF2148231E232F22BF2217224A22BC221D2335212423AA211F218B21102172204A21D622CF22B1227822842227224F24EA24F32596248E2265207023FB22E323D624E92460232B229A227B221A231C2180221E2230220D234826ED259924FE2340241024152574234224DE24F924662FBB2CCB263C239223692284238E21E12125238322072238223F22F422402326232622D92393224222142388216D2326221D22EF2273238F2094221624B423F12468272D27F024832255232A22A1239E242D27632614223722A422BA211D228721712163220224C5258126A524F423C923E025E425CB23E72360253E25B5240C30242C562515220A23BC234721B222112130231A2274225E22812305224723B2222423A023F022DD220025BE23C122C62393224A22E4237121DA21C7233625EB263327CF28122572222923152495252325CA26A025FC226F222821E62123235820F5218621F221B2230226082756258D25BA24012580251824CF23CE241924A22EBD2ABA240A24B0229B23C5229522A7214122C2222D2489241C23C722B622102377259F244F23CD244D236B23C12419241922C122B62433225823C2259C26A92805287C27A927AD22DB21CB2615292D28DE2780280126BA22ED226F2347221D231C226722E624CD271929C1273424FF2412255F2525254E23B823632459245A303D2C69250C24FC2355235C213621F122AB22F62321257423BA220F215E227A2392241F25F1235725842311237C22AC24E9224722B2252124ED246C281B28492AD8295F29DD25AA219321FF251F288A29FB2A0E292A26322333238320B02160211524AB214F2533289C275D26A325D4253125AC2410253E232024672338241F2FA42C9E262F247523C0239D238E2451252625D5242A2590221021F923862282224D24AA23B2236023F2233421DC22C224892394222D24B624D326EE28582AAB2C622B64293E26FA217D228324C2285E29C42B1429AF2865242F2256228F211121D2220B241E2578265A28C325E425132586242E226B24AF22C522902354259730A52DEE2684242E243B248024092580253E28BA24B724D9249D232523EA232E235925D023A922D32314236E24D326E524CB266125B6234D261C278929432C542C0B2C312A7B27422296220B25F3264529182BF728B227022545234D218321FC2214245B25CF2634279D269C25CD24BC243A235822A523BC206823B5241A279830A22E08280B26D624CE23E3248726ED267926EE25BD2676252D23E1212E227F22A92204244E232B2467260D260128282A9528B626D9254F279C28282A902C9C2BD42BEF28A925E723A9240926A226D8266B28D628CA268C2365246B217521B921C123C4250D2895272E274F24D3238824E124BC23FC24932309253E261729B233CD2E822A8D276027CC266E27F827BF2739285D2623241D230F23D823982329230B25F124072399272327BA28492ADF2AFF291928D5247A26EA2A232A832BC82B592A2C27B4243D24E924582621257025F92692266425B222AD219120F7214F234F2327253A263B2670263C25AB246425CA249B24FF23572356242226EB2AD03472311E2A7226D22607250127BD2736286727052609263625F422D2214C23E3232F25EC26D628082A9C2B4C2B502CE02CE72A8B269C245A255C28DB29EC29772A97273326D526312425257726B726A925ED25F726A626962511255222AA21ED2115252F25FA248925F626E925FE265227F82669261527CD244927C629792B013351321A2B2C295426BC282B25C62778280227F02693261126D923B0228E2400254E272729F12BE92B772B612BC12A002C4529C025DC23F725DD2656273C2848276D2542243C269425D6251B259C2684276B298129722AD2262D258C23DC220A2228247C268D263C2797288F28F628252A0E2A482939287328D128FB26CA29F4327F30F9290827F72597260C2832266327102801292D29732767244924472382254227E12AFB2BA42A4628B7282E2A722BC1261E27A3244D227925CE24AD242126042573240724CC22CE239025A8281529D12A092CF12A1D298A276A2428236224B1232425A9278828F9283C29B629D32A8D2A40289B27E825AC2501266A288431672F032985268F253C27E027BC257026B629AF2924296C271723B0223B264627BC27DE2910291128AC288328D4290D2AF226B5237D22F0224C2371230B242A23A122D0239F233C22E924A7271229DF2B842B932D422BC32A422623257123E722442480260529052AB22B2A299529A02ADC27D3254A268F251426FB24B2257E2F0F2EFF276E257226932705270327CB28582AD52BBA29C3279025D3252C27E827222867289F27AF28A826D427BE29032AB528B9248C22EB226E23E1204B24C723A124A124D924C82458267627092B7E2B502B222C9F29D628472792238224FB23D72349255B27DC26732AF62AE529C929AA26AA242326D8243025C026F225A12F462D4729AC274627382937299F29252AB42BF32A2C2AAF263124B825B727C028DB28692982253F260C2769273B293B2AF6260424DD223F248F24A8247D268327F3267B2441259926B527E129082D092BCB2A64291829132789231A2587241223D621ED237623342544270927282667278524A2225224692314246B24A4259130FE2D8C28DF285F2A082A802AE4282B2A832CF02BF928A126932441257326CF277B283D26C725A1267F260928112BAA2995257923BB23D623B8245E273428D12733272D25F525EC25D627F729942A152AD729B3297F262624ED23FC22D9226423A422BC23ED22592200240224BB24B023E12100220023CE221923C72392253A306D2ECC2A962AA02BFF2A3D2BB02AEC295F2BC02A392A1926BF23F62325263525B2270C24AC2597258C256E29A62AC12A652769239221EF2255256125CA274B28A427CB253827112539266E265427AD26B5262A27E423242394230E2310225623E522D120DD21382169234E2377225023C222B5214D21F321FA2306256D277030742ED52B622B4B2C0C2D902B5F29582B062D2E2A60272625872327248525912702265626592637286028BB2789278B255025F224DA2365241524CE24F5267F27DD27872643265A256024EC249D24F824BF230925A42336210B234024F7228E226721AB24CE22E323A0231F2346225D228F225B23BC23C5224A252825B227A6321F30632CB12C002C8D2C4E2C222EAA2C602B26285426A4243824E02397262727C229DF2CBA29452A4F2650261C251A2566210D2123238B2258231C25C1250B2540243125162587241F244B2238229A229124F12282234C242A25F42660251B2638259626BD24B7235C244C23A2225623BC22CE22B6244D256D282F260F2A13330132292FB72D272C092BE02BC82B512A6C2A5F28BB262224252431264528AF29B62A672B302A582BF1268C24E124792412210B235F226623F424EE22B724C324692660283C266F25E223C82350221622AD232225CB2401258D26322867282127F9250026D1253623CD25EA239F22EF22DE23D225E026C7261D28322A282C7635E531102D472D89297E298F28A227022675273C27F925D125A926632623296B2A912AA12BBD285329F5277E24DD23E2219422D12025233423A82417236825BA25C0276C2AE62AF2284027B32388237423B0238B2530255127862AF7297128B42612250E250124DE2332227E22212435241A24FF25E72A322AD12A2D2AF62B74370934532CB92A7D2865275A2685252927E425E7241D27E1264A25AA2522277D2994271E289127FE269423DF23CC23C5238D229F239D23B22421244425D326E227D12B1B2DEC2B0D2A552743253B238223B0262628FC27B729F5282E280C25F62464261D24942240235C2464221D24072737266B264D2A4129F9299D29762A8833F3324C2EF62A392BFD2A7D29BB27C0268525AC27292AA82B9626B326E1245B2589245D2450252F25C8260F241326DD2514247A2509295B265E27C22791276A28232BA92C622CC52BF327882469240725A928292BA02A1E29492742273D2525260028D725AA248B24DA249724D6233E254A258726992919283F2787271B275A2FE332962D9D2C262B8F289929A227652792282F28F829FE2A4F2986242B24E1225F2535253D25CA27D6266D288F27CA2815270427C226BC299129DD298B29BE287B2AD22D182BD22AA127DF24A8234D2632298C2A6F289F266E251D26D7264F270928C026F526F523C926DC25762312253924BE245628D725BE24A326B6270430F92F5F2B6B2A522A352884277226DA274F26F22526296426E6266B2525260D25FA26DA26D4260028102B6629472C0D2B7C2BA729F6287D281D296A2888284C28D728B52BF32A5D2921279D24FF274328E229AA2CBF298627A926EB26112872298629CC27B6265726CC263C262126CD242222C0214326B12524273126DA272A31D72EEE26A3267D26EA2660242C26CB245D25D326C2268C2558263D26B527F625122789273D271D29322AA52B2F2B172C042B1B29C928CE28F7271D26B1254225B726F9279E27D325172451232527DF27432B422C1E2BAE270E27DF25C0278529002AE829862AD42717286725B8248B2311230026B3282B29632B2929FC298733D92CE72614268425BC24D32480245F252726B026B8277127532971286E290B2852262A2664277E29562BBB2B742D622C042B5A298D29972726285F25D2256924CE2387258B26E023A024EF25BF2641274A29962AAA29602899255325C52613271B288A29082BFF28872898251E258F258324C22834291F2A202CF62AE32C6D37DF2D33287B28C826D1258C2551243825D226B6265128C227CA28D029A62A2727E42506266326CC285529CD2A2D2B482C592D8029CF2517231124E72490237E24802335257224E12477259627AA28B5287729A228BF2A9B28342601252F241A26EF2673274F290D276327F92493223926BF275029C12A722B622B4C2CDD2DAF36C52FBF2A542963280827C526472451261A2782273A29F7288329262768266927FC25F2251526D2269D270E2AFE29812A4F287E259224FB23C521C424BD220922D722B524F024B625AE276829592AD029222A022B2E2AD8299B25CA23D424192585267F26A9260F268127D1257D256C262F292D2B9E2B4B28FB28982A852CE635CE2F6F2CF729AF29532889261B2774279A293A299C2A4F29532914281D2757243725B2245B25FB25892510288427112673246E24892269227922B123BC2372236A24AE2489268F287F295B2B542DCD2AEB2AF729EB297A28A82667236C226123AB2639288F285A268E2728266E26D228422ABC2B7F2B052A2C298C27202A5A345F307E2DFF2D422ABF2AF32AF52900285F28EB29682CCA2B9E29242927265C27A1256E25FA23A62598234C26A824DC2436232324DB21DA218623B324A724D124E82303240E28DF261329152AC12B2229A929C628EE25D0249626672246229724B92773299129002A5029F727CE274F29202BB028102C832756275F2AB92BD334DA32932CCB2DAB2C712D0C2F1E2C722A9C2A612A782C492CE8299B286B28CF26AD294D299A2665236B252125FD227D245D24C4226D2402241E25622522278B26CD260A2786268E2722276827D228D326CA2643273826A025C72504251F2380258327262B0C2B702AF12ABF2748273B2C412B94292E2BC2298D29D52C362BDF364C31E32D8C2B7E2CA22D372C2A2D962B6F2BCF2AF3281D288226C6269C28A82AB92ADE295A27A725DC2352250F255C23CD22EB24C12484268A286D28FA27D2282229A528FC2637251826C626B624A925D626A9257527932676271724D02336257B283C28CD296C2C9D2A9627FF26952AD42B372D132B302B1B2B642DF32DC036D62E012CB62A162C032A862B2E2D1B2CD32AB726B2281B250F270A2616288F276829D227E6269D2467238F23FE22422516243924ED269727762A102BCF283929C12AEE2A9D27E624BF261D256B23F722BC246F2667278F279A261325E62471240228AD28BB297529862776266B26572AEE29782A502B282C902C0C2CE92CD834722CCE2961280A28492A2A2A40290C2BDF274426A325FB23A7263126392862270E27D2264525162639243224C9263C26AB241E25D026162AAE2BCB2A252AC52AA52A022A7A299326A323A424CF24092312248F28EB252226822766268C259F25472539276E29E32782284C2645274829EF287328C728372AEB2B552DFB2BDA33292E5E29FF28CC292F2A1A2A81289028C92566243B257026C924FC2535269E26DA264126DC24352704278A2585287926ED266128202AA529A92A742ABB28EF26A028BD2764251024582434252A269B270329B7298328DC254B24C623F12428233D2487270D27672682256D242F2806271226F6268D29FE295D2A492B942A03316930402A262AAA29442B292CB029FD277F26DB24452573243526B826B2267B2772268B275F27342A222B072AC929122C612A432A4A2AB42A702BA029BE287626F0287C28B0255D261D26A3251928F227B92A4B2CB42709278925AD23BB25DC24C22498254D24BC25C1243C276626B4265727DF27F727232A512CA6299F288E30CC2E792A7A293429252A052B6F28AE244B265125ED260E28E026AB26C9277D24D6259329472A8F2A342B30294929732AE62B602B6D2B8229612ACB2A492A8E2AE22AB42A342A61265926FF27CD28A627632997283526F023E52695265825CE2550246D2357242C241226C1258D27F9292E297029072904291F284927CA271C30B72EEE29952AF42A8A29142980267426F327BB285D28092B9328F7269327812564271128532A882BF62A78292C288C28A3293D2A8D2A1829DA2A532AF729B128A72A832A5A2BA627352724275227F22511274F25BF248F230827CC257A256C25EE2306238D23FA23DD2668273C2AB82A49295728E12510264625A6251027DD31B830332A652AD02BA32AB8282E25BF26202A4F2BB32A402C58291A282E268B263126AD28722A4C2A7F2A27287B274F287F27F5268A26D22703288F27F324CD255529D2298C2BC226C12501268424F1239A235A245022ED239123FF25AE231C234224ED21142424255326F327DC28262A272AA8276C25F724722623253528CA33292F372A442947291C294D27D227FD28E129A02A282CBE2A4129AA25422521273726AC26D829932A86271825FA23A625B32420253324CC24A8252D248B2435278127E6282B28EA241A255723B6229E227624BC23BD25EB244B257B236124EE23952318237A23B225CA27B629F12A642CB0282126DF25032522278827742A3736CB2E482A762767282027B026B229D429592A1C2A8C295C29FD26C2269126AF27E3285D2A722921288A249B27E9247A24CC229824212397230925ED24AD2304257526DC253B2610239D222B245223DB22F723802603284B272D27812682260527E126B4243625A127862AE42AC22B2C2B79296F270E2655240427CE28852B9337D62F382A2D29E7286D287F28192A5429532A7F29862A5928F226C0277126562ADF2BB32A5C293A29B726D72494267D26AD23392353228123C2246623A32578252826B825062670234D234E24C3232A24EA25B027A928AA27762AAA2A1229A72912284B27E12574269C2B2C2BAD2C282A1727F5263227FA252F28B129992C9135F82E4F291728F6263A2A262BD3291A2A3C2BE62A872ABB270A26DE2529288329662AD329EE286029962755270B26E5251E235F252926B825DE2799264627D725602587255D2571254A24EC249926AC26A027692B9A2AC72A782C222DD32C0A2ACE28F0257626F0251A290E2A3A2ADC297226A926FB28A127E528192B7E2D3835A52EF42945273327092A432C092CF92CB92C132CB72A3728FC241F254E25D4275E26AA27292787277F29D92BEB29BF2640261627ED285729D6287C29B726C2254A27F92560282727022629264228FC28752B2F2DFC2BE42DB22DC82BBA2C1A2BF02833260225D4262B28C328BB28E9290528A3271D29DB2BFD2A7F2ABF2BDC336F2F94289D260E276C292C2C962CB32BC32DF32B162B5827C2246626292733282328D926DC277F288B2A042CB52A2E294D287B2A7E2CB22A062A8727AD272D263027782845295A2871270329F3290D29D42BB82B722C4A2D392D352D3F2A9F2837257025EB26A4249B287E2AFA28152A3C28662A0D2CE429572A872AF7298633832DB128562605286B29C02B912CF22BF02AED2B42282326FA25BE27E8288B298829A82741277428F929712D592C352BC62AE22C592B2E288127C325A5250224C6250C29972A75293D29542C2329D029A32AAA2AB3289229E42C282C182A4D2866261A263A235B26EE28842BE12ABB2A9F2AF82CE22C102CF82B1D2A7B29DF32252E48281D288127B0293B2C0B2BD52C972B35295027D7258D27F928E5293A2D16285B284A28832821298329372B4B2AB2274D283F27E3260E261825C2265F26ED26A72794275828572964295328D62693266D27022610285229592B5A2B9028C125FD24FA243227EE2A772BE12B622CFA2B4A2C152CB12B742B212A512A0134AE2F9E2A7128C028332A412B402C7B2C9E29F428A92768272E271F2ABA2AEE2DA22A5A29792804296C296E29B528BC296A25252743265A254126B427D026E527C727D427F62781294F2A172AC4299827B7254726C4250D270928A1272229FF28B32636272D265128F8291F29422AF529EB291A2D222DA42A3E2C0B2AE02BB3337831212C7F28A82723294D2A3D2ABE2914295B27C1279629FB2A052A2E2B9A29D4278527BC284B2A822B982A54295E26F62506251624412532282528DF27A62959297B270726FD258927C52738286625AF26FF25BA25A824BB267D2726279B28C1272B278F27BA28272837275F26882766284029642C5C2CBD2C982BBF2B7E3490309D2B2A2ADE288429412B8D28D1261126D526F228702B0F2C2A2BFD2BA029072AB929EE2A202C272D1B2A8C2757258D22432309243024DE287929982BA729C9296C29EF298F2711267A2632288F267126A22649260024932A75296B2A4929F027CC28DB28BD276B27F125E92541261E265F282929082B172B232BB92A72324B2F672A8F27C628892AD92BCA2943268E2666284B2A7C2C762B5D2B882B5C2B0629042AC4295A2C3B2D8E297827BC24B123B523B924A024B528182ACD2B452B212BD02B0A2C5429E7260E253627AA25C825A327CF255228F629A52CCC2B552A9A28D72792263F26D225F925892627275527FB2866283828F7295A2ACD290E32853034281D28A929C82A612A6A271D2720260A2A182C7A2BDA29972ACF2BDE2A8F291527D1278C29F92A7A283527C32429255D239F24BB24E8285128B2287F29522B662CA229082925264D255A250227642A3F290B290C28FB2A022C462B622BB628CF261924DE24C62521250D284D296A2B4C2B7629842758299E2708286A32092F3C2A5D298229D129C72810260326E327B1285E2A2C2771283A28F427F7299A28252616250A288426ED25A9266A2580253125FC2568282F294229A72ADE2ABE29E82942289224B22448246B268A27BF29FD2AB52990275C2BBD2A032E692D272A0C28F323A323A026CC274229FD2A552B9F2BCB2D86297A28EE262E2875305030BD2AA12A582A722A7729A3266729322AC42B172BA428BF26EE26C92678297228A425072612265D267E265E268726352641287327232A6F2B6A2B8F2A7F29E5285D273227BC23FF213B267F293C292B2B3D2DC42A9F29812A362AC62B162C6B2CC8281926B826C527F128F929082CF12A322B772CB02BAC2A3B2C922B2A33692EC42AF8279A28D227CE2753270729DF2AC22CD32DA02AC329AE27D52805285B286027B427FD260227672665288228E32790293D28B928672819283B285E27E825CE26FB2508269F260C280029762AB32C602C25294E29A22A452B2A2CAF2B542CED27B8264B26D92662291D29BC28DC2A6C2C8B2C952B122DEC2C1C2CCA358E309F299027D826222834278828E129712D1F2D4D2D3D2D8F2C922B612AA02A4029522B5129E5291D293627B02AC429C229962A4E2A912994283A28AA26C126C3278328B327CD2746289A2A0E2DDB29882C732B402B722CB62C162A8B2A00290B2A1A283C2758252D283729E4285D287329B22BA22C192CA22B902BE42C9A35F72FAB29B825B7244A251A274529692BFD2C862CE52B652B4D2BC32B192A662ABC2A9A2ACC2A372A5A295C291C2BE22A562A132C4F2839275B2725285F27AB285F29E4282729AF2831292D295C2918290D299A29702BF8285829B629EF26CE270628532725281C24C225DB27692775282F27C8282F2AF6287C292D2AF22A7C35532F2129AB2478235525AB260B28D22A3C2CF829912BB32B462A7829462ACA285E27A12A9A2AC8284A29222A7C2B422B7A28F82801282026E0280A2809282D29E7299828D628E7269528342792266425A42782275027612649273325D42623270327DA271128AD27FB277D246126E8276A28A4272727EB27BF28C2273E2BD535F02F4228D925BE24D4269728F52A312C332AEB2AEE29E52BB829392AC929EF276C279228E725EA261226B2257A255026D3254225DE2421267E269D2887283626562765260E25AF248127CE26AE26B8278627A029492607247424BF24BC281229372A0A2ACF286D285A29A0278928952ADC2BC12A982911288C277A277029E3333D2F6529542901274027A827CA2AB42DFC2BC52B3B2DE12C102BB629C127D5269B26FE262E25CF254925AB242C2575263624F724E823C724D726A025BB261F261525FA2368254A2661272A270628F22A4B29532B70273E235A254C26D0277928C1293E2C792E572B7A2B4E2A442BF62B532C202CF72A7629052AD729702B9A3472307A2A6728ED2713277F28922B312D502D242C302BB72BEF295C282C26D72518258A24B625E624372501246A25FA2408256D2446250925222687256B251A263A243B25FD2508232E272D2753297A2AAC29AF29C926A12534263D289E2AA42A5E2B3B2DCE2D942CDD2979284628472AD92A312CDE2B4A29192894274928D5303131962A2D28FC25C12667278B2B7D2B052CD82B512AED28C22571240C2670257524EB2598253127D22569260D28F8269425CC26DF26B628EE264424F724F4258E26FA25B8261A2584276127D129632A5129692970265E255C274C26F428CA298C2C372C6F2CC529022A6D26D5254A29F02952298F29CA289226D527EC29E8313C31B82CE229552876271A26192A5629482B0A2AF3250F26F92683256F25CE269A2684288B28B229D12ADA29A829D629C1281329AD2AEB2A11282D261F25D2269028D5296D2A49277A287928CB27A6263C2929290F279525D22502269A28F728E52A5B2B902A6A2BC228B624A92434255326452814296327DA273928FD2971346430972CB029A926D22528254626BC27EC265827C2271E27382765268227FF28C2286A27102A7A29EE2BE62A4B2B5B284F2546280C26B5279527DE26AD248E27D229BD2C782BD526F2265D254C28F8241326C1270C27A025BE27212901292129BD270C29482AA9277C28DE256425F524FD263C259F28FD29462BA12C6A2BC1340731FA2CAD29A428E826B82577265229D42A182AA12B122CA0293629442A052B2929A9280C2842291E294228952680258F26AA28AE27CB260C2793264A261C28F728862A2B2A2F2709262928BA282C276327BB283D280F2A672AF0285E2A502AF32B56280E276C263A268F244725FD2419237427FA2818294D2AE22A5D2B9032D730082DBB2A6F2B792A932A3D29DC2BB32C482B5D2B9D2C012C0B2BFE2A7B2B6F2944290C298B2B092A3A2897282B277F28C8285D28D7263F25662654272C29DB284729F028172859287F294F2B842B372AFC2A082B892B252B9B2A932A4E2A1A2C522A6B28C4284F27882562243424C22591278D282D28FA27C5276A28973031330A2BEC29972B362CBA29742ACC29FA2A922E862C8E2CA02AA728F62805283B27302A9929582C4C2BAF29CE27CF275128EA28DD273E240926D52623287E2A8A2AE22763254F26D526EE287329BE28BB28792AF22A152AAA2BC8293B2AF12A132BCE29312AEF287429C5277C25C625D2244A27F32749275A290829A628FD320930A62B4729D82A2329E129B329DA2A502CDE2C812E5B2CA12A4B2A2A28C727C527422A1E2C312C0A2A432AEC290F2891275A295E277126792972283F2A44293D2B4A29D527AE28C4264627C8270C268C269D2798287A29202BD12A5E2A482B0F2C072CC42BC22BF02B6B2AD4281F274D255428F528092AD42BF92B042DFE34792E5B28F22738268627E128EA28662B3A2BAA2CB22CAE2C602A3E28B4278F280228E42ACA2BEF2BE92A1E2955272726F528BF273827E5273428F328BB284E284429ED291B2940275126E428B126082478257728A628CE2A592B6F2BD62C772CBC2A462B962C9C2CD9296829E4260B27C526AC27F629D92B212A232D5A2EE1341E2D482843262B288129FA2AAE2AA12DC62C9A2CCC2A142BD829CC26FE26B2270D28CA28EC29292AC226E5258324BE252D24B226C3262A270A28A427F6255728F327EF2561267B258D250527D726E42376263C2884263A260128EE271529E128972AC52A292A18293B2790268B258C2515279A28E92AB02B262C542BC92AB634542E6C284427A72956299D2B9C2BEF2A9E2B252C352BBD290E29F6255B266B26C8272929B529FC27F4267324E425D424AC24B4261F26B8282228942795250425F526372777245F2433250126D0230023F0259B24F425032519276C280327DE262A29EE29942BA92853273126C0251427C226CB28F7297D2AA42C532C982B3C35352FDE2A602A41298C2A1B29822A1E2977276D27C72755271E26FC28CB2878284C281F29872906297E2742277B266226F72696272A287B2ABD2A2D284427CC26EA2734275025FE23BD24C325AD24E3232626AF26DB2556250426312673268D243328CF295D2940287E2798276224DE25E224AB276D298729E92AE22AEB2C1336D62E392B952B9B2C9C2CEE2B432A9E27B826722743265128F729D42A2629552898278F2A0C2BF429DF28A4278B2BF228D425BE266629FC2A5B2C922B7C2A6A2BB52987271B266824182580253A2690258128F827F927D2282D28E92612284228F128642A902BC6274C284C275527F327AC253627C7287C29C029E22AD92C5234AB306E2C742C6E2D412D912C042C3429352A7029D2273129B72A7F2CBD2A67287C27D9272B2B9D2BC22C572ADA28B02698270E298229622DC92CFA2BCA2B992CF02A6D29AB27B524AD27B928AF285E295C2B102C092AF7288C28B0292B2A622C6F2BDA2ABD2ADB2ABA2A3D2A6E292E295C27622585269128B329312A0E2B9E340A30442CF12B842D9C2C402C832C9E2CF62AAA28DB27A3289A290B2C7E2A4626D725FD26882C752C712A2E29E927D12786262827322AEA2B212A502A6D2A242ACC295F28162536252627442BA12AC02A7F2B9E2A002910280329172BB52D162C542A8C294B2C752B932DC92BA32B87286B25E525FB2633294729382BC52A5534D22E1E2C242B37298A2A812BB62B052C8F2BAB2A23291F2A002A5729F1284D273C2502285B2B4F2C362B412C9D295C2A38291A286A285B2AE22A552AFF283F285528F82592253D26DF26A4284A2A282A452B452A8A28FA2680283A28B629FF294E2ADB2BB82B7B2B7D2D092FCA2B53297B2695272227A627332B572A782BB133782F3E2A9828C1279826BA260128E4267F276C278626C22684278327412713266C244C250F2AEB2B302CA42CA62A87281627CB285D2AA32A632BD4289427B025DB259724DE24A52584278129832AF328D828062A5728E8258C27F5254526972660295B2A922B392A772CCD2CEC2B8A2A8D27EA270B286A28FA29312B3F2BB732C62F232A4D28D3245026AF2449241426DF24C4254A2563252725032460237E23EE23D5257528162AC529E52ADE2C77298A26F1260F297B29A22A7528F126A3277B2570247524E724FC27B728BF281728A7280A29D2255A2413248C2485255E25DD27942877298C296D2A3D2B292DA92B1D29B727C8266F250B284A2A8B29A832302F5028262777240D2444242B24EE24C125C825312406247823B0246F246C230724ED25B6258B2748279C283829C226C726E526AD27AE287229492B8A29292852268024CD24F5260E288D283728792821291F2A702769246025F724FC249B27DD28C42A372B3029A529962AAF2BE82B422BB728D826D8266727D329542B1C34242E7228C126C024B224C52359246A24D8268225572549254C24A723E323E7244D24EB248F24DD261A269026B1285E27C026C927DE2557263D295129DC28B026AB26DD25D2243D260B27622839263828DD2A6729AD28E125F526C5260A27012AE62A3A2B362BF928E529BB2B732AFC2B0C2CB8277827F1252328582BA62D6C34142CA9270C24C1257125A52307253D2644277C26E326EB24AE243723AA227A247C24A6254427DC27B1269B2643272729D927AB252525C2253A2862296C2987280728EB27CE278A27B1278A282F2857276D2BC12C602A2928222869272F28A62BC52DF32B5D2BBE29E52A712A842B352CB32A6328E826AC265829472BC62D7335BB2C28279726CC2439270A26B927CC28DC272628E92737278725C323AA244524A625D726F12B2C2A3A295926EC27B02922291D2611262D2682262A267C268F27F6277A27F427292A442AD528512A2B2A8B2DEF2A8A2AB029BF29622AF22AEC2B982B7B2B6D2CA32AC62C902B422C972AC12A2C2A762B112B6F2B942B8B2E46369A2D612702262D299F299D290E28102BAA2A522BCD2AC22AD226492451268826142653292D29AD2BB0282824D8279C29592A2F2836264026B926ED25E3243C264D259A269D28A6282C289A2932299128172AA92970296C2A4A2A8429D329472C352B6F2B9829A729D82A6E2A652B222CC2279527D4298E296D2A142BD72D0836D52D97270A295A29192C242B9C2A522CF22B592A1C2A3C282F27DB24F92559276226EB28F028C02914286725242673260027932927298F28E226D725FF2384232D25F22744263527B028EA25E1287527502A502A5A29A727BF2667278528DB29622AA928052AB6296D2C422A432B5A288A278D26912A7C2AA32BA02BF82BFC35702C5E285027B32999296C2BCD298D28AE29322AAD29402665244F259B24A224AE26C227582879275F256A254626EA268128972AAE2A8B292929F225F8249024D52386244824F1230C255925BA251E27692A082CFA297827CC257F27CA28262AAD2AFB2776279229EE2C1A2CB02A35282D26AE265729A52A9C2BFC2B6A2D2537DA2DF82752276C27A5284A28F32744299428B8252526A924A424CB22492412251B244B27F02610279D25A526B725AD29032B572BC929632A992AE129AA29D52806273F26262405247F237D260028ED29082A342BB228F3259B265F26E828492A6C2A5829C22A8D2C7B2EDB2B182A3928D626F026C429702CA22DC32D9E2C6136E02C7927A025CF26BA27B7275A2701260E272824A4239823562385245426F22734277A264E255D25C324E424DC26CB26ED278A287D27A026B927BF28E228CE2825287B24FF223D21B7254E25B928DC29892AD32A7D262824E924FE27C5284C2BE82B582AB52AD52BA42B112A5A2AC428D8261D28C629FA2B3C2D7A2C7C2D2C36892D8F27AF26CE245B252F2798261B266E25FF23D12331252A24E824B228E529D629A7288E2788247F244323C52479274928AC28F628D125D825B926F525F1266B267E242825662488265227C528CD28682917289D258F26852797260529652B842D262D132AA82BDE2C9A2AF427C626382633286B2A952BFE2C4F2C512CEF335D2E6326352565254126C727DE26A724AF24D823A4221F24C7244525D7274B29892A9E2AA529C126F8242B249224C52657268A27FF251E277A253325C325AA245925AA246626CF272429002A7629432A902A0D28B126F2275425CB25AA273E29592D1B2DA82CA72BBA2B7F2A41284D2845271029432C902DAB2CE52C592AE933A12BD9264925AC24CB257B27872464241224082492248F236926E02553288128702A8B2B172B7E28FB26E7242726FF28DA250E28DA276728EC255C252F25B32350242A267A268A26D9284C2AC929A127B2284A264426902585259F235B25202A292B522C972BD62ABF2B5E2AA5282428F3281528CA29F127FA28CA29192A9D33532C1628DC231A265526CE26FB25D1233625CB228A234E25BA26232623268A287D27E529AF2BB62B90286026FB260429DD289D2833280F2986295227D423722339241B27CF2593250A27A0289228EC250D264C272F267D25C925D62208244C25192AF628702917291429DE26FE282028442A522785261328C927F0289B295432B42CD628A3256225FA257D26F8244B249F254B25D3250126482778247025E5254D2799291929282CAA29E8270A28492737289E27A1288227A22AE827B62790254B263326E2259D2476274B27FE264126AC254126BA27A82508266E22EC23B6240C286429452B862A9A2B6428EB29432AE828D3259F25242616298B2A642B4535EE2E6D2986263D261E2729272324F1246226FE264528612736268D27EA277D276A273E289927DE29D32763264B2749283C27DD277A267426E227A628192640273D27A6249024A625F924ED27C127A524FF270429BA271B2411251724A325A224EF26EE28492B482A922B712B472AA628542842250926FB24AB27B027242A79341C2D87276326AB250D250F25C425012583278927182785279427022638287F266226D325242675258024D5255F265A263D254B2608252D24C12506282A27E125A8267C260527D125A026F926632622256125CB268D265124EB23A623132506251D2684295F2B9E29252AC4299F281C2911279F255226832521288329712B89358F2B7525232517252224352501232225832707272C279D257225FF24432517264A25C224FE254325A3229E22D2236824BB2344255523DF24A22439234D262425662519271729822678270427B9241C258D256B26DD242A2558254B2439244524172687275E2865278F283928AB280C2851250E25B326CE2557285528AE2918334D2C0126CD22DB24D024F6232F246C251F2792247A24F225F323D6249C24022542267B25F7245A2588236B23C024EE24F8224B2596248423092476258226CC264E279B274B2737282A2814273426832533269825F22449249E24F824592434262426B125C325C9261E287F29492A052BC1269A254326B02664283529AB2BC0341C2B2D2636259C226723A623FC223023B6242A252424C72404230024DD233326AE24732570267B24A224122345247023D623FB255424BE25B325FA240126CE25E0268525F726BF26F225D02402250C24B72434244523F4258225EB231F2450250B276325042681279028BE27012864269925F825DB24C427DC29492B732BBA36F12CE0267123AA2274227622FD22B2228323BA238F22DE22152268228224FE2196239124D324462569252B24D0236122E0239A251327CC251F275C25D6260C271D26F8247C25D122D423C523A8228222BE24D0259E25C725C1243E24232490252C267F2618261E26DF27F725EE251227BF231624D12520263828472CF62C8D37412BBA25A022222245223C23AE215E2418218B22EE225823F42258246124F3221F2370256924F525CF236B23E32308248123DF25B7267B260E283E269E26D325CC25B2240824E42204247D242D245224B124E326C0275A277B25D5255C26A326B42702277C26A4246E264423F4235A23A822902497257E26F529E12AB32CFE35C62A6623B621B223F4215922EC218722EE22ED214A24C22388222024012442248E25B823D7252E272D252D238224682511231C25BA25CE2590259B23DC245423F4247C25C3269324EB243A25362611251626C5280227A82742292029792A9D2AAA281C27E8265C2517253A24F3214C23AF2380224C2431251B268D28DD292333622B0B262A225F22F523D221BC229C22A5236C2430237723A1245523B9223725E3253B264D26B327E6240A23BE24C1253B248A24B226B227AE24FA24EC23F7225E26EE2634266B243B275E25E825A8246127102705261B273429CF27A52B11296C2B712B0D2AA7266525AC236723C02462238522D3246B26C928BE29432C8B36E72C742520223B22DF237F21EF22D3211623D0228A2342229C2280217722FB22D123CB245A241D26CA248723B72371259B256524E324AF22AB24B02206243C23AD231824E7245F241822BE2571244423B9244B25592301253B253C25EB248A260F279627C82925279D262825D9231823932322245B2649287229252B3E2C9F368F2B8B25F72365215F214B21AE220722C02379229322D222D721C423D92388210B24792457252E269625E82310244C236A236D2483222F22442527240023F02104236324322257214B20B32245215023CA24762484211122E5232223212488220926D227B028FA298228E625B424E1255F23E223EC257225D929362BC92CAA33652BA2259623A822CE217822BD2366232423F821EC2287239122182210233224F4230E237E23A624AF24792309235123C12363223C21AE2248213E23B2212B22FA21E721AD22D3200420B42110226922A5237322D321AB212B22E72208221E252E25B0241527362950299125CC24AB24B923D822FD24282521273728B928D530012B5E26ED21342194203920E322AB211822C0205F225B2030213B21C421C721B122FC21DD223923CD23E420292212259F239022A121B0209B21BD20BD2223237921DE205D22161F0F205C2168215822032394238C231B21BE22C121A8216B21BA24F223222392237425D524FF22A223CE21FB22BE2484239C23802507270430962B6F258A238D214C22F4214F213B215C2240210222BF209C2199206021C8204C20CA2180210E22A0202C200E218D221322C820AE1FD620FE201021A3210A22F221DF21A2200520CB21FC2148222E22C9219E22C920E021332246213320A8216122DA21B622B622A7234E2179212D22D0232F2154228521C921BD219A2528304B2B102434224A22C021A620CC20B7225B2090212B21D520C720CA1F73208D2170219220D522FB2217222A206122C6213F21D421BB21142140211E20FE1F2422E8218922E51F4E20841F45228021B021E3211E2291209C20072231200E213121632196217B219D21AA214C225C239D20172128226922E7221D2333244E25522E9A2BD1244421FA214422F6203322CF21C1212A238F222020F2208B209421D6210B2296227222C921D4225C20D622BE1FA3211A22791F50211120D1209C204C221922172141217721F71F492286221922F123FA22801F0222D12035217321BA2287211D1F30229D21EE1F8621DB208A21B9216722FC22F2209723F1236D264B2F302B4C250422E7202F22E421E02062237E21F320F220CE20401F741F3321E022F420B721C723BD206522A921D621D320D22190223C20B720CA1F9520E71F7221EB20A51EE720F81FB51F0B2203229C20A0228B212021A51F33222E203A23D1209A206720AB20E61F06224E1F1221332230233321DD2167225E2306228A24FF2F072C2D255D21D0221D2218224D215B23B722B9219F21FC21C820981F6A219921FA22B022B82299208C223921E721DB209E2058227E20F61E7020AD2286203B207A1F771E62206B1FF71E8C2148214F20A022B9224720B920FC1F3A1F911F4320802130202C20381F2B212C217921BB226522C42262214721E0229325772682321B2CEB243B23752009239523F321D0224823A522C023012235219F202A2290203D210D233B225C209C21592074211021E420A5228C2183201E212D1FDA1FEC1FD61EF51E421EB61F9B20CE1FBA2075223B221E212C216E1E211D2F1F961F25217420F4205520661FF520A6201B21B0222E211524BA220221CD213B25E8268330 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 403F ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 0009 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 F227FD21CD211F2083200420111F211FCD1F3C1FBD1E401EE31D511DE91EA81DA11CBA1E711E841C791EEB1D9A1FD51DC21E161E061FF81E8E1E2F1EA91F491E231DFF1D151D5D1BC61B891D0C1DA31D2B1DB11E751D351DED1D391D561C9E1DF01E9F1EB61E761CFB1D491D711C181F1B1DCE1F301FDF1E9A1DDA206222822D492BB72353205222DE212C2087203121FD20101FFF1F261F591E391FB21EAB1EA31D0A1E481EB51D381E1D1FFC1FC320801E1D20A81EA41FE51EAA1F1E20231E521EB01F8A1EB61E321D841F931D891D6D1F071FF81D891D341E1520901F641E721EC51E3C1F0B1E641F451F6B1E911E601E2F20C720192001215121A323392DDF2A5624E522DA2162203020A42095217E1F3E22DA21C6211020561F9D1FF61FA61F24204A1F7E1E4F1E6420A81F4F1FC020B920BC1F971FCE1F8B1C841E02208E1F7F209B1FFA1F7E1E231F0F1EEF1D8B1E7E1F0F1ED31E661FDF1C0B1F2B1F6F1F9A1F231FA11D5D1F731F971F3A1EAD1E1E1F9B21B81FAC20FC20B8247B2EE12BA02702248C2185210D2137220B21502008202920B21F6C20BD1F1E21751EC21FA71FA71F7821E81E451FA21E2A20EC1FCC200F208820211F5D1ED91C9C1E0F201520BF20391E0F1E491F1D1E561DA91ED91F811FF61F6B1F171F06201A20F5208B1FAC1F181FDC1EEF1DF51D921E4C1FE71FBD2002225920C221E123F12D0B2C81259621D820A4202321A1202521D9204E2049205D205A1FBF1E5020E21F951EE01F481F1A1F341F421F8C21F51D591E8F21041FD41BBD1E9D1E201E531ED81F8D20BB1FAA1D671EAE1E8A1D4C1F2A1E1F20931EBF1E3B1F12207A1E841E0020FF1F9F20931EB51FAE1E661F121F4D1F401F3F20DE1EF31FF9219B229D2CF0292F25112227234B202D2232203E20A021B2201521AE21511FA71FBD1F25202320B81F381FDE200A1FD11E352099205C1EF01FE61ED71EB71E1B1F931E9A1FBC1F07203B1F861DE31FBA1DD61E6F1E4B1F491F891FA01F091F471FD11E591F582082201B1FC21F9F1FDC1F421FB91FF11ED01FDA21CD207120FB222A24152D392A9C22CB2110218F207320C7215720FF1F4D215820A41F0520101FAB208E20FA20B61F1A204A1FF220C0203C1F5F1F861DBE1DF01E261F751F1D1F8020B51FF31E901FF91E661EF31DF11D421EAA1D281FF220901E741E5C1F741F2F1E261FF81F501ECC1FF61E191F171FD31E021F3F20931E3920061FC8207E21F221982D092BCC24F521A722FC20311FCF1FD12089208A21701F062029213522062019204D217220D1202F21D620871F1620E5216F1FF31E6C1FD51EB21F4820D51FBD1E531FBD1FCF1F8B1EBB1E6F209B20C81DC320B01F9A1EF81D9E1E8D1D741F301FB61F601F741F7A1F4420DD1FDD1EBE1FF01FA41FB11F2F1FAC2138223924F62DA329BF24C5226621AE21F61FE61E0621D3211821AF20E51F9A1F811F4D20AD1ED11E77209520D420BD20461F091E4620AF1E08205C1EBF1DD21D651FE51E7E1E7C1F1020A41F3A1F5C1ED41D491D441ECF1F741E861FC41DE9208C1FFF1E061F631FA31E992060209A21A01F551E871F7B20341F9D1F501F242005224F226D2E7C2B9F225A206720A7204D1F99205420E3211E2065218220EC1E15201420A41F3120461F4820E71FE41F2220001E571FE51D4A20F41F1E1E2720091EE21DBC1EE51E3320AF1E171F971D2B1FE21E9A1D001FC41F121FAE1E681EB41F6D1ECC1E4722781F511E4B202E203F20BC20E21F5320D020FB1F3920B21F4822E0223530142A2B26ED22832105224720F320BA2033215C21C0226321BD20101F4A207420A820022079209E204D1EEC1FB61E7F20051EA01D1D1E6F1E411F7B1EC91D851DB71F2B1FFB1E491FDB1D881D4D1FC11DD61EF61D6A1EE71E1A20921FA21F9E208820491F221F2C200721661F281E4A200F207D1FC71FB61E10213022E7221F30272BAF240122AA23F0209D1F4E201320FC21D321F1209F20941FE41FD31FC3202620062003207722C41F1821651E091FCA1EAC1E631F341FF71D971DD91E301ED81DFF1E561EC11E561EFC1D321FFE1EE41FAF1E7E1F2B201C203E1FE91E47205A2071207A218C1FC421EA20DC1F4821A4200920CA1FC41F2B208320BC24092FAA2B0926E2213021D0201C204420321F1C219620B71F5721AF1F522153205F21C920F31FC71EBB20831F2B1F481E1921FF1FC11F071F371ECD1E8C1F821E391F0D1E341FDC1F181EE41C601EF5202E1F5D1EE01FCE1EEE1EF920C020E31E0921611F931FFC1DDA1EC51F9B1FA71FCA208A1F4D1F9B213620FD20A8213A24BA2CE02A93254B226D22ED223520992046213B22B9213A200620B81FBF1F1521451FA920C620EE1F1520A21F4E1F981F1020B02084208D1E781EBB20871EEB1DBF1C661FAE1F561F541E071F2A1F9A20071F33215521C21F311F091F1C202F20082152214A1EC41E751E9D206A1EB41D2A1F7F207C215C21A920B821052226247C2F4A2A7624F6228621F422FC2028224A209122AB1F6521F5218F1FB01F8C1F5B200D1FEC2128220820301F961E5C1F9F20D220221F4E1E961F711F0C1E611E4C1E1B208D1FA61F331FD41E9B1EDF1ED81FCE1F90200521C81E591F3D20BF1E391F891F83204D20441FF9200B202B1F24202821F41F8F21661F46200222F122362D6E2B9A25BE21FD206121F5217121E22130206F21D3218C20BE1EA02041219E21072070217C200920A621F821631FDB1F691E7C1FD91F361FFD1E481FC61E441E2E1FBD1E391F8E1E7B1DE920691FB41F7021121E8C1EAA1E941FC51EF91E6A1F59208E1E80207F1F4A21FD214D1FF1202F2004218921FB210D21BE21F623772DBE299525A6233C23A820FB20FE203C219120C72074228721B720E4208820FB20F32022208B2032206D21D21F8A203B21F71FC02031203A1ED11F24207E1F991FB01FF5200621AC1F171E491DA71EE31FE01FB91FFA1ECB1F01221420411F6E207F20721F8820611F1320062017205C1EDD20F7205E2103222C2269220925F32E692B4E259123D52077218E227B217D2163210422662181211A21EE20811F43202B201E210A2250201D20F12090207A20481F2921BB20132055200E1F4F200720A721A720661F0C1FA420F21F3C1F971EEF1F90214820A21EEB21A41F421FF11ECA213D1F65209C1E2F21B91F9D228F218C22B221BA207F21642275223524C430F929F226EC215E225B2228222E237C215B213421622211206F20CA20DF2187203A213423D1204C23C5211A206E212522621F2121552088202520821F2321AA206D2148210E21A81EF4204120FB202B1EA620EC1FC11F541FDF1E9D1EE31EB61F43209F216C22411F4A214920C71F641FE02082207220A7207223B1221A255B2F432C7C247A2175211A214221C7205B21C71FE21FF8203821F120501FDF21D821AA21D11E54211622D91FB91F6C1FE51FE920F71FE51D9E1D0022831FFC20401FBF20A8216C204820A91F701F541E7F1F9A1FA81F6B1E6A1E6020C81E381FB1202C225621912002210822361FE81E82218E207120D0205420B421632324247F2E322BEF24FE221A22A8215321E11F8420D02081218122D720A11FC41F582019216220F12207210F203F206C21BB202E20CA20861FD61F291F781FD1208920462244225E224C21F020551FC51E2121401E1B207620E81FC81F701EBF20CC1F74201421951F3D2085202122FE20A920D823C82050210B23F21F4722ED228523812ED62A8524D7236A21C7203E213C214521DE21E421AE1F9F210321E4216120F620C4219F1F8F229A200721E1206521B0205E1F0C20F01D9F1E5120881FE12125212022F622E7215821E4201F20541FC21F2821DE20FA1EA81FFB1F5D20741F172070204121142030214B2200217F21372023205322E3209222CE2281222C24022E9F2A4724F721612254225122C42128216D22B1213122E7219D2136205322F8204D21B32013210D1F551FE31F34201E20511FA01FAE1E651F2520501F4421CC218120FB21F2213A213F2033238A21971F25222B21C520481F722059209B20A221D8210E224C237D211223A9239022FD217F21D520B7212B220422EC225823272F462B812437238D226D226920DF21AB222221062030213022D51F15213223112155212722BF206121B120B920FE2162221F21C21FBB1EB32001219B1F6C215D21EB21CC222B212D1F192244224822EF218C2260219F228221BA213521D520C7223E207A21A72146216E22FE2070227C23C423CA2196228B22E123CE227225CD2FC82BD024B721F2219922B7211E21F620E622252121231222B520C5200120AF20A520CB203B21AF236B20DD1FA5214121A1208B20B2200E20E71F7A20382059211A21522210221B22B8211F21C9222A212021662148222B225C22B820A2206A21DF22C620AB2046219A203D21BB21C0243F24FC22612399233F2551250E24AE2E532B1E255622B82337222F22A422FB213522CC20A321F821EC2096216722F421C2226E20AF215621B821B92252206121E820B921D521CC208222A9217F22D3217F225F22EB225C2200219D226B22CD20C122D621CE203A20D722C620B220B922CD2132229B22AE201B235622E1232326B9255523DF22CE22F6234923D325492F632CAE256922A5210823A522632267221E226021B72265227020BB217B21B821A2221F23622000223821BD2035204A22442157217C22E520F4211722FB22FE2033228A229D23FC21DF238222B922C322392121223D21B1200221DA221422B4242E23E422D02306238323E922C024D225C424BC239E2389234122A92389243D2F3D2C102752228C239322C022DE22B023AF2200227F23BE218624BB21632257226D218B22B92119224C2159217E2123222022C02176203C2182212D220E22C3223E239E23C4235522F823BF228223A921DF214D218F2032213F210223C12242245F279D258B244825A924512450251725BB24EA221D2462231424A1235A26B030B82C45261625B6241D23F7211B232D23FD23F6227221032335222E247F22722386232722E022EA21F5213422B021B921B4211423402112212222A5227D212B23C923BB249825BF23F82394238221B221A222BC211A22AE21D32327220D252C2849285628E825DB25FF242225D42597279125A4252025EC231F24612650269630952DAE26F82178226C227F243023D22227241A22112472229C226A216E2236235923B7223723762467211C22522113243222FA22E8222622C222402265222E239C2383243C25EB24172407243B22D2228D235F233E2432214B2309242826A2287A2A572A0A298C26D02527260826BC26EE258F255E26DF24B9254D27E82696312C2C592541230123DE23A0225C227223802288243F2193220821FB210521D61F67213722662386220021B520A423FD2378231D24DC2456223C2349233A237C2330244A25EF244424592397214F22A4227823E5253422902205249625DE250828C027F828E6260E249A27C928D52AF02A0F2970265C26702628297329A9282D31382CF7278323D7249D24EC218B216121CA239B247125F023622128227224B524852227239323F023E220D7211D229122292439264425D4230A243722D2242A25B0288C27A726F6227A22CB23C72306233C25F126A9232124842448251027962606271D2641240326D827B428202A602B602A862A6028712880288A2A0B2AC331042D0A26C82333237723D522A423B9228122D123D623E1227B2341236A231E249224F0221225F0239A2248234B23C923602510273D26BB255D244224D623F626E728DB29F8277724CA21D024B524AD26E828FE2880267A248A24D924C6254E244125592410240226D02AF42B3D2B8F2A0F2BC729F22A9829AE2A2D2AA92825312A2DA1278224B5245123F623FE219B22D123B923AD223023422303245924C3243E243B262D25EE246925EC23DC268826D0261E27AC26DA222A24EA25C0253828632BD52BA9288124DB2481230626E127CA2AAB2A9225F2235324D923EA2369231F239A238D258A28D42A932A012AA9290B2CEE2BBA29B329862A55291F2701313F2DA92664233324162547229023DB216924B023FE23A32393246523D924E0242F2642275727F526DD289927BD276C29E4272A26E3268A233D23C125F027B52A192C9A2DFA28F924D024A7257E27F827322A9629E6251324CB2266238424C32176230A2388235026A9293C2C2A2BB82B132B9E2B692B002990278927E4251430E32A6525B7240F231E242B23F1222322CC22C9232025B8259B24BD23CF232925EB27BF27F32655282B26982640285D279924CF24E3252D2351243D275B28FD2A662B172B982AD02491226427282A77297229B72AED273F236A23EC23192377233F22DA2252251929682CD02B07299329362AF5296128962506259C2501258C30E32C3926C8249124212408229B218E23842425263527C52575246922E62345253A2781280A279F27F2250C25B8240C261F2425235526BD24E0256329572A992C872B912B40280E232B22A026DF28652A052C632ACB272F24C12322214722D121D82423225026FA29202BA92AB529632AAF2876271327C8241B251C24DD24732F732D7C278424EF236B2404246E25982681273F2773271225EA2269256723C923E3252B25F524D024E024D0217423F924FA231D2357241A251E2782293B2B0B2DDA2B222A4927CF220423842472282A29A02B8B2930292925E122CD2200223521D4227B241026AF27B92AE4285728492713263F2329255723EE22A6237025F0300B2F302886253625E3241225772602289C2BD12814286027AA258524BC241D243126E324E6239224CC23EC241E277B257F27A1250924D5267F27322A942C3E2C412CF62A1A28BB22C8220325BC269729D72BA32917293B264924F2210F2285238A24CF25EE27BD28D128F7275D26B425BC23DB221A24FC20DC23F3245A27B530652FA4287F2654253C24C7256328EA29712A7429462944280C2596228E229122F8222824C2237024C7264B261528402A6129AE27A325FB269A28B229292C032B6A2B2829E9251C245924B625622607278D28E3287F2710247D24C2211521E921B5230D2663287528E127A324ED2330247B247423B02448239724FF25AE2873331730C22BD8280928BC27BD28EE2A8C2BFC2BA3292C27D0249324EC2431249D239A251B25A3232D28BE27A4299B2B742B012B1829AD25E326372B3C2AA12BF62BB42AEC275525862468252727A3254026D12776278326F423782264217122A3236B23F3255E2720272827B125FC247C25DF24462402248623C0248226722B3E352232522BB927CE27CF251D287E29F62A1D2A722881270C274B24CE22CD2399232025FE2632292B2B752C242C342DB72DDD2BAF27322569256A28742A782AD62A61283B260A272D24B925C126E62604264A2637271D2716265125B622E2219722D825F8258625082673271626B826AA273E275A260A270F258927FA291B2C743346338F2CEA2908278729A9261629B4292229412819286627FF247A23E1246C253D27ED280E2C482C522CE52B742BED2C682AD8266E2425265C27EC27B428F82753267F247A269B25FB254425902690279A29CC29AB2A2127C12526246723A322F0241A27E027242857297829C829E82A152AD329C528A828A9292C28B82AB7337C31162B20288226BA261C28F2264728E9289F29112AD4289525E324572383251E27202B1E2C3F2B8728FC28052BE42BF8271C284D25E02224261E25E624D3267A2590244F24BC22C5237225E3284F29462BD72B0C2BB72990286A25FA23A4246324C8254A28E828CB291F2A6E2A9B2BEE2AE12802288A262E260227E4289A320431562A79271E26CB278C289026BA26B12A9E2A562A2629372547234C269B277B28B02AC6297E29032AF329762BBD2B8A28BD243223D3230D242B24F524D62356236324EC238722A7259228E7296D2C272C752E0A2C172C27286D268A240C246F259F27092A6E2B352C6F29082A942BDA281027F4269A260827E22545265030C62E14286B2522269A2736276427FC28552A312C652A9A281A261526EE26AF279628E92850284F298A272128372AF92AD229E5251923BF2282232F216324E523AA249F24A324DA248726FE271E2BA02BD42BBF2C6C2A0D2A4B2936255425D124C2240D2676280228812B402B432AB22ACC2779259A265425862537274726DD2F532DC6287F2687262E2935294E293729DC2AA92A542AFB26FA234A2500274B287B281B2930253726E22640277329BA2ABC275324C322D32346244324A8267527FC2671240A2568269727A129022D8F2ABD2AA029E62936285F245625C6248A23CE2138249E235925B7274027B926DB27D3247D2260244C23BD230C247E2559302D2E5D286F28F6290B2A302B3829772A8D2CCA2C1E2A162807259325A226362818296E27732648278927E728B72C492B04278F24E3234B243725F1277F28992821283226EB26D426BB28C02AE02AC52AC02AD52AB027662527251D240724602476234624E4234D23DF24F7241626EE24F8220F2374236E23CC235E24F125F230492E332AB729F62A662B842BE02A142A882B512BAC2AAD260324C823F2251F25F1279E2410262726F3269E2A8D2B302CA7284924F421552365260F26F12895294D294227FB27002627273227532864273C273D2890249023EF23AA23A622362495238721DB224822072403242123DE234823E321B7212D225B247025DD27BF301A2E0F2BFF2A922C212DBD2B9029B62B312DE52A3128C8257A23F3238825F4276226EB266E27DF28A029D629BD2959270A268A255F24EC24C924B2250628A3281229A827A126462655257D256F252626BB24C9257D24EC215023B02414248D237D228E2545247825372562242623D9225323202410245023A825F62598282433622FE22B912C962BA22C752C472EE52CAC2B9F28A326E22454241924C6261B27F429BC2DA42A4B2B73279C2711262C26F42155219023DA22D223B42586260526BA2486252F25FD246924B5229B226323E1246D23F8233E246125C92735267B27C926F6277A260326E4251B247F23D32331238023AD2565264F299B27402B80334731882E422D0D2CEC2A382CCE2B932AD82AB0289B26FA23FE23E625C927082A222BF42B2D2BFB2C112887253B25E124172173239E225F236A25642323255D25AE26AD28A626FC257524E823A1223722A523592539255725E926B528D528582869276A27772719256727A22462235B2332245926A5278027E0282C2BC22C9D358F31552D9E2D2E2A212A6429C728B926C427032868260C263827FF26F829822B7C2B552C9C29F02A3D298A258F246C2246233C211924C423992515240126CB2628283E2B8F2BBB29B928DF241B24AD235124EB25DD25FC271A2BF72A6829D3288C26B226CF2548259123EA22A5240C2512256627712BF52AB92B512B8C2CF137EC33D62C492BD228DE278326C9257F27FE2527255C2722275326E3260F28502ADC281329C328D027EC234B2448243524B323AC249D249D254B250E26C027CE281C2C652D072CA42A2A2894257D237523CC2686285728E129A7295E291926AF25A627D8251E24FE23402537232A25AB2722278D273C2BBB29BF2A892A162B3834C832622E102B7F2BE42A3C299727C226FE243827C8292A2C71277927AC25E6253E25F124A8259625FB269C24C526A0268F25B4264F2A11286B28002965280A29C12BC22C482C3B2CC6281325B1240E25FA28BD2BAD2A85292B289327102610274929F627FC25FA24BF254425A324E7250B261027E1295928F827FB276027A32F8933572EB62DF42B5B29F02A7428D52705298E28712AA82B222A0626EB24502329260A264D26D628F1276B299529802B4F29282960281E2B3B2BF72A9D2A9529A32B692ED52BF82B9528D02547246E26E629A12BFF284A27EE25F0265E27F728B1293D297D288024412873279E24E8254E259D2509291D27C6257427112882306E30BE2BAD2AD42A11296B28B12612283226CE2542298F2601276A2559266B25B227D027AE27DB289F2BE129142DB62B242C292A44295F29FD299F29DC297429B629652C902B392A8F27B7241928A128712AD72CF729EF2734270B277E28442A0B2A2A28532744279B272E27C6264325AC2220221B273D26DF27DD2642284231682FFE27942774275128902531273825F22549272F277225CD261D274B28E7263828E828C7282C2A2B2B342C962BBB2C9D2BFD29752A762AB9292A28F1268A26FB2744290C29122701252D24BB27A328502CF82C4A2C11283C2810279128C82AFE2A8F2A2F2B57285B29DD2676253E24F12354278B291C2BE42C712A532B2534842DA4271D27E726F025A4253D25AC257E2632276728E127B0294F299B2ADF2870272B275528272AD72B0E2C6C2D192DA42B2A2AB32A9228F928F926EB261E2592241C2632278B240A256C2667277B287C2A5F2B0E2A2229DB264F26E227FA27BA282A2ADA2BE2291E2AE726E0256C261425EF29412BB02B412DB02B872DF237832E0829B8291D287026C925A5243725EA266A27EC28E3274229EB2A602B952789269126C7260629FF29EE2BE52BE52C542E4A2AA1267D23AE2439250224D424CC23C325B524B724DC2537289C298D2A2D2BB829EC2BFA28C026B025B524D52673272C28752A2D2834284F25EF22E2266928132A7D2B022CC82BDD2CF12D01377130CD2BE02AC529312892266E246A2675276428142AB629082AD127DD26DA274E26E22573266C279928742B802BF72BCE291727F22411242322C424D7223B22FF22CE24A124F7253928EA291D2B952AB02A8D2B6D2A482A142607240425A8257D2795272327EC2604281926E3255027F229022CB82BEA284829442BC82CD635FE30D12D2F2B792AC62812276A27D3270F2A3E2ABF2BEA29062AAC287627A02477251925DA25F6263C27352A0A2A2A28B42517250B238D22C7220624ED23092475249E24C6262929522A992BD02D272B622B052BE92A4D299E276223EA224324A0274329092AF1272E288826A6269729FD2ADB2BE62B372A8E2944289D2AAF344031372E422FF52A2B2BB42B972A0329C029B12B432D5D2C492AD12954272F28DD2673261D25162773257328CB267E2678247125D222E922192528260926EB25BE24552539299628572AC42BC52C452A302B102AD8273A26DF2778238923C5252129BD2AED2A1A2B1C2A21291229BF2AFD2BE129A92D5128DB27502B8F2C9835F932EB2CE22DE12CB42DAD2F4D2CD12A2A2BB02AFF2CCA2C542AA528B7288627E42AC52ADF2720246A2634263724F1254E257F235C2524251B26C1267928D0276F2749271C2761286728E228E529E1271D27D12709279126EF26B225EC239A268E28C42B962BE12A812B44281528E42C882B362A752B002A162A692DB62B0837F931C92ED12B052D142EB72C842DDA2B1C2C742B7429D828532732272829F82BB42B1A2B9028B126B524A926AD267024FD23D525C8258627E029BB2A1B2A582AF72AFF299128CE265D27D427CB2528267C2782269F2861282F295C25EC248826BC29B729B02AC82C4B2B1E289827262B9D2CC72D802BE92B922BD82D7F2E2437632F2D2C862BB72C9B2AEF2B862DAC2C452B25271B29AE257927C726EC28E528DC2A7C298E28B8253824AB2436249D266E2567253728FB28C02BEC2BD729BD2AF92B182C862844262F283D26212467238F2510277F287828A6271626D325C42579298F2A4C2B272A51284A273527F02A3E2A132BB92BD32C0F2D3B2C6B2DC8350A2DF929DE282528A62A962A8E29FE2B83288926DB257A2428270C27EC280F289627A72711268A26262573259B274427AC25AF25AB277D2A0C2CF82A192A062BA82BDA2A212A4C278624DD258125CF23B024E3285126B5267D285B27AF260F27C2266228322A54282F29DF26DA2776292A29A12868294D2B122CCC2D952C47349E2E9A29C229A42ABE2AC92A7829DE290327C524E6255827B92572261A277127B027C626B12550280D28C6261E2A5428E7270629F82A0B2ACD2AE12A36295A2887292829FC26F12421251B26212763289229852A6B292627D4248624C6256324C1252D29BD2856271D260625FE28BB27B6264727182A7F2A142BA82B512B3931C730952A822A1E2A982B952C4C2A33286D26FA243B25D224F526FE26BA26CA27D826EF27F2273B2B3C2CA52A972AB52CCF2A102A612AA72A552BDC29172904273629D728BE26EA268A263F26C0289D28702B8A2C2F28B4278F26ED24E926DE25B9254826C62442263025C327D1267127CF275428DF28892A702C562A5C29AE31C82FD12AD829EC29732BBF2B6E29C2259F26CD254D27AE28EC2765277028D5243826802AF72A672BDE2B98293F2A912B3F2C592BD82B182A0F2B572BDA2A662B402B632BEE2AD1264B27E728F6290929AB2A9129802738259C2893280E2721274B253124F7249D249A26B22681280C2BC529AF2A292A0A2A5A296B285928FF304E2F7B2A292B9B2B592AA729BD27DA2695286B29B9298A2CA929B6282728F5250F28C3282C2B552C692B242A1029D629FD2A022BF02AD529062CFD2A4F2A4A297D2B4D2BC22B572809286A288528FE26AB271026C1254C25DD285D275C27D826CC248B2325249824B22775285A2B5C2BF329AB29C2271327E5254F26F327E032D131272B342B7F2C8B2B6F299D26CA27FF2A532C942B282DCE2A522949278D2742278129EF2BF82A7C2B392944290B2AC529A628BE27EE282729E7280326C226512AFE2ADC2CEF2739270D27D625F024C624AD25B523D025842598270B259E245D25F62218253A2640274F29682A8A2B6A2B0129DA26EC2531278926BE29A235CF2F872AED29362AFA2970281F286D29032B502BA22C8D2B352AC026F0258D27E2268127582A4B2BFC27EF2522255926F524BD25F7245D2571268C241E2518287228482A252A8626EF25F5232B232C23652517252327AA26852674245225DE249924AA235324912695284A2AE82B1C2DE3291F289726C425CF273129F72BFE36BB2F432B7528432902283E276D2ABF2A182BC72A822A6C2A2D28D1273827B1289229922B6E2AA529652685287E257B259E236C25142407248925E1256D243F26B427F726122714245123DF247F244924C725A028982A4E2A48297428CE272528B4279A2557267328672BB02B542CDA2BD12AA728E526362576284E2A492D28381C316D2B5E2A4F2A6D2984293D2BF929362B772A4F2B5F291A28AA287B27642BF32C882B372A6D2AF527FD2559272F277524372445235E24F0259424DA26B42698270427EF2649242F246B25E824DD2526286E2A502B222AB62CE62B8B2A722B72294C29A527E927ED2C322CC02D702B002828286728452784295A2CFA2D9C36962F2D2A94288C27B32AA72BC4298F2AF12B682BC12BB02881268826C4283A2A0D2B582A5E29D62AA9281B28E426A626AC230A26D4265D268828CC274428D126452636262D2673263B25DF25BF27F927D4285D2C7F2BC12B252DCC2DD22D2E2B092A9A271A279E260C2A3F2B2B2B122B1E278727C2293029692AD32C712EF935782FAF2A7D2730276D2AAD2C4F2C1E2D042DC92CC42BEA2890256725C9258F28D926082892274628122A582C3B2A2F27CA26CA278729712AB429862A9C276A26CE2756262F2982283A274127AE288129A02C8C2D332C012E9F2DEC2B672DC72B0D2A55279F257827E128E4294E2A6C2BE328BF28112AEA2C872B2B2BAA2C7034FE2F22297327B827CC29842CC52C2D2C522E942CCD2BD4274B25C426F227C928B82893278D2806295A2B9B2C0A2BB229E2282A2B0D2DFB2A8D2A7828C128EA26E42748295D2AD4282128022ACD2A2529132C542CCE2CE32D852D932DE12A7129B52644265F275B259D29BC2B9B29952A5D28DD2ABC2C572A8A2A012B652ACD33D72D1B2937274128F2292C2CB32C552C622BFB2B902824268826EF273F297A2A492A9828BF271029CA2AA02DA42C752B082B6D2D1E2CA6280F2847264426CA24E026AE29A52B74298D29792CD229C42AEF2AF32A70291A2B9D2D072D3B2B54299227C3260C2449276A29A62C532BF32AE12A3C2D562DB32CA22CD12A0C2A6133242EDD28A128BD276C2A932C422B442D2F2C4629A727412616288729C02A0D2EB128D72804291B29DA290C2AA02B922A7628F6282C289B27CF26BB25AA276827EF276828012865289329DA29EE28D92719270128D926B428A52A2A2DDC2C3E2AF5274D26D125BD27B12BE12B0B2C742C232CA12C502C3A2CD52B992A882A8134412F902ADA28EB28F629422B992C922C9C29AE286D276027C126052AB02AF82DE22A7C29D8285629B829802995285B298B258527A5267425A1264B28942741286F283A28F8275929702A8B2A2B2AB1270B26B82637266D27BF288B286E2A552B1029B928FF26B7286C2A4F290F2AF729CE29902C132DB82A2C2C362AD62B9B337931B92C47298128A3297A2B732A7F2A6F29ED272328222A962B892A8B2B402A8328A728FE29A82B252C272BFB29FF26EC265226D7242526F9281F298529002B3E2A50289826C6266328D9280C2A03283628E026DE26A025B627AE28D328292BF02A002A0A2ABE2ACB299828FD260A285129602A482DE42C6B2D1E2C532CD334C430FC2B892A2329EB29DE2B1729592736265A274C29E12B322CAF2B412C3C2AD42AA52ADF2B542C662DA92A1428EC25E122CC23A2249024F329F82A7D2C3A2ACF2A592A082B5128052771278C29AD28802731282227F3245B2B6C2AEB2B412B012ACC2BC12A5B296829102755265B267726EF288429AF2B892BC62B542BF632A32FC02AA227B4286A2AAF2B042A8F26DC266E286D2A502C702B712B8E2BDE2B9A29612A302AE72CC82D1F2A6028D7242A24F6231525082531291D2B7B2C6D2BA42B2B2C4C2CE1299527AD25CA273126B0266B28C22605294D2A022D9F2C4F2BF829F629C1284F27CF2637269C2697275A27F72838290129082B072B682AF432F430C22879281E2A332BE82AE0276F278926742A842C832B7C2A042B182C892B382A092880289E2A302CAA295D29A226F7255024BE259725B9299B29092A082BE32BBA2C692AB7296127132604264D27EF2AA0290A2A8C28C62B972C802BCB2B9729BF284325872574267A253C28A7296D2C642B7129F0270D2AC128A0283C336F2FAC2AC7293B2A962AAB29EE26B12635288729892BC3271C29DB281329A62A1829B126FA255A29B6281F286C280927DA269F2646278F29652A4A2A532B6A2B8B2ABD2A1529792525259A244D274128792A452B362AEB27DA2B742B802E232E162B15294A25CF231E279728E229992BB12B392C812E212A35296E281A2964319630E72A142BDD2AD72AC529D52663298C2AB32B5E2B9A287F2657272227A029DB28F3253F26BB2675279F27AD272628C127BE299B29ED2BC32B982BD82AF7296F29D4284227EF232322502669298929712B722D092B4E29482A552ABB2B6D2CF42C3F29BA26F926FC278329982A3B2CF92AEC2A562CAE2B282BD72C2E2C6833DF2E442BF928E22948291E290D28AE298E2B102DB32DE22A452A4D286D291D29F6280A287128D827A0272F27BF29242B1B2AA12B8C29862A95292E292E291D289626FF2630264826CE2669284529FC2A242DAF2C8729F529632B9A2B872C0F2C3E2DC228A02706276F27092AB12971294B2B632CAD2CB02B862D342D992C54362331672A6E288C278B284F27BB28162AD42D3F2DA52D6B2DC92CD62B242B442B9929FB2BE3295A2AD329B4280C2CE72A8F2A352BE92A492A342926299327352774285B29CC284828C928CE2A432D022ADC2CBC2B9F2B6F2C182D7D2A5C2BCB29B82B7129E72882262929692A7C295129082AC92B002D792C152C3A2C5B2D12369830202A69260525C4259E27B629612CF42CAA2C152CBD2BC72B2C2C5D2AFE2A2E2BDF2A2F2BBA2A4E2AFD29262C752B0E2B792CAC28B9270028A428D727FC28032A8729A729BE29812AEE290A2A262AFB29862A242C3929B4290B2AD7272D280A2929299F298025C3268F28E927D428D2279329232B53294D2AFE2A2D2B0636E32FAD29962599239E25F62694283C2B7A2C5A2AB82BD82B982ADE29E22A66295428562B222BA329A32A142B0E2CC72B6629752A87296F27D5297E29F929C62A382A9229FE29652823291328E726B4252E2823289527DD26F72785255227B927952712299F29CF28012956252927B1289E29C628FE27832811298728C62B9236153095280D262D25EE264629342CC92C742A452B352A512C262A872A2F2A6B28F127352923277B27BC26AA262C26E0267B261F26C92516277E27E5293A2AC527BF27F726E1257625482852279F27A9287528982A1C279A242D2583255229792AE02AAF2ADD29AF29BC2A90281E296D2BAC2C792BC02AEE28AF289728162AD734582F86299C29582742276628922BF42DFC2BEA2B452DB62C862B9A29B22765272E27B6265A25DF257B2505258725AE260D24F0241624662595279A269A27D526552552249125912604286A271A285A2B242ACE2C62281724D425BF261E28CC28442AF92B4A2E842BC52B8F2AC02B722C812C882CB62B7A2AEB2ACA2A1B2C1235BF30F82A0429A3286E2716293F2C512D4E2D6D2CD92AC32B672AE228D226F12554259D24D325F72493251D24A025E72430257E2481259925FD2612261A269A26E424A9256426C023B02781278229922A8F2AFF2A9228CC261427C028AE2BAB2A8D2B3B2DB12DE42CAF2A56294E29E82B842B9F2C712C0A2A40295628A5283831B131342B2429102733272C286F2C0C2CA52C5D2CD02A75290F2723258626CD251B257D26E32593277226B8264A28502722263A275C27AA29EC285C252F26E1268827D3268827022616280528502ABE2A602AA72A312869269E284D27BB29012BE12C8E2CF52C9B2A592B9227D726672A162B2D2A862AA9297E273D28782A67324C31252D912AE028F8276E266B2AD029F12B5C2A752645263B27D625A225FD261927DC283E29532A052B202AFB29252A10297929FB2A722BA528FF26C225A727A4294F2BE32AC82758298529E628CC27502AA42AF9278E269B268D265529DB29F12BF32B362B7E2CA2298C26A22517266227E628912994287F28BB28662ABC34A030A22CEA29E026F9251E258826A12751275727C02724277227DD26F82750292E2909284E2AC829282C032B212B7228BA25992861267927D227D126EC243628652A692DD62B0A2700273E253E284325942651284A270F260D286B293B292C291A28D6299F2B0229E7297027E42536253A27C025FA28B62A782BA42C4F2BF334C631872D5F2A99291928A1262D27262ACD2BB52A062C182D622A572A172C202CD929072A9D29DB2A562A5B29BB27F9253E276829CD285827BD27432729272129912ABF2BFE2A23283B272529E2296C286028C929F029DE2B422BE329D42BF12A9A2C02298128C1274327CE2553261D268024DA289E2A602A7A2BC12B592C46333031C62D692B072C472B4F2B032A142D5E2D162CCD2BF72CCA2CCA2B9A2B682C8E2A212A3A2AE22CF92ACF283B2957285329392AB6295C2835263F272428302A422AE62A092A0E29F4284E2AEC2BF72BC12A492BAC2B0B2CAB2B0B2BEB2AF22ABD2CC72A0D29FF299D28FC26AF259A253B271A29432AF629C929AD295A2AC231CA33BD2B872A0E2CD92C742A572BC02A872BFB2EDC2CE82C1C2B5029692AA129F328A62B162AD72CB82B182ACC28E7280829352A4029D125C626CE27FE28B12BF62AD528C72616276427A129FB2AF229532AEF2BC62BC72A572CA12ADF2A8F2BE42BB42A0D2BBA296A2B7729A42741278D261B29012AE5282D2AFF298C2AAC349330092C9229972BAB29942A052A232BAB2C0C2DA02E9C2CBF2AD12AA828A628A828142B432C7D2CA12AEE2A512A73287D28EF295E289426D329F028B82AC529B22B692959280829BF271A286D28A5263927C12877297D2A8B2B092BCC2A802BBF2C312CF22B8F2C922CF32BA42A3329FD268F29BE2AF92A132C8B2CAE2D7B35A32EB9281B28CF26C4274A29C129D42B592BB02CFE2CBF2CAE2A6528A627BC28AB28A92B072C212C602BA0290828AA267E296228C6274C28B5288D294329E2281F2A632A8F29142858270E2A602843259826DC296C2A3F2CFF2B262C802D4C2D142BFF2B242D092DF32ADC2ACF28AD282E280A29B82A2E2C8C2A5A2D7B2E1B35DE2D11294727C428DA297A2B4D2B022E692D732D502B922B892A5527A6276128C4287229162B992A4B278726EA2402267B2476279A278927E1287028CC26F828EC28A626492768267B2678281428FD2445273729382875275A29E629EF2A4C2ACC2BA42BED2AFE290C2986285E270F27B828F729B42CD72BAE2C902B8B2B7C35D52E4B292A287A2A9429642C9F2B492B4D2CD32CD02B982AC429AB26F326AC26772898294B2A9628622758253B262D252C254827E026F3287828F327CC257725B2274927392572251E264027E224AD23ED26782526272F26F127D9292829F5279C29132B892CDE2984296A28F62643283C28612AD52B0C2B212DF52C122C983525304B2C742B6B2AD42B172ADA2BD629A4288C2855285D289B27232A1C2A162A592ACD2A7D2A3C2A99281B28A6279D27FC27A12861290D2CA82B5329C62855284F290B29CE2647258D266327F825CE24FA262728252789266027A6274B27C5256B29662BA72A572A912AAF2A6827F627D326C029D12B6A2B6A2C522CFE2DED368B2F1A2CA82C442D212D452CB92AF327F226A227DA26F128C82A782B352A8629F628B92B382B3A2A88291629CE2C0C2AF6264F277B2A642BA02CD32BBA2A372CBC2A6228EB26A9255726AC26E8261C26E12813295A29F0298829F427D0286F294B2AEF2BE92C1829CC299229092A8E2A9327B128672A272B5C2B4C2C9A2DD4348C31AF2D9F2D462E032E172D882C8329E52AE229C228572A792B402DAB2B5729212949298B2C1B2C352D3F2BF629C3285828E429EE2A092E292DAE2C4E2C772DA42B8F2AD428E0253C294F2A522A302B562CF72CDB2A5E2A312A1C2BE82A442D112D782C832CFD2BC62B712B102B1C2BC128EA262828582A142CDD2BC62C8C35AB306E2DAA2C2E2EE22C562CDD2CDE2C742B1F291229322A382B092DEF2AD32660267A270F2DC92CF32A85290429D0288C27C927952A282C3D2A962A902AF12A662A19290D26ED251128CE2B182B362B062C472BA229A0296E2A032C5C2EEC2C342C4D2B712D722CFB2D282C662C052A402722277228382A762A9B2C092C1935A92FD32C8F2B8229342B0D2C352C962C882CD12BAB2AC22B4D2B8B2A492A7828DB25A828082CB02C3E2BE72C0B2A9A2A84290A2953290F2BE82A762A962965294629E826D425852654276F290A2B7F2AD52BDD2ADF28DD275B297929362B242B4F2BCB2C402C1E2C7C2D2A2F1A2C502AA62758282A28B328142CFB2AA62C4434A430EE2BC929D0284C275527E72801287728152913289C28B929EC294E29132708255E26252BDC2CBA2C112D362BEA287C270629C62A132BD22B4F2959285326462614256D2553260428D529352B3629092A3C2B2829A7265A2800272227A627332A302B5D2C702A302D132D642C6D2BDA2839298629E729462B4C2C1F2C47337A31182C262A29277027F02597252E27F5256227BB26D827792726262125E82417254627FA298B2C132B052CD52D202AAA274E28712AC82AAD2BA929D628D728EA268E255525F425B828FC296A2AA829922A3F2BB027CF2521258625D826F5268329602A422BD52AF12B482C022EEF2CCF2AFA299629812774299E2CEF2AAB33E62F99292B29D7259F24AC24CE24AE25C3261E277F250C25EA241A26902551240E256C2626265228FE2723290E2A5D27532792275B280F29342A8A2B212AFD28FB26CC247E256527A5286D29D7286129C229FE2ADC27F624C5258D25B7253D288529862B612B8229EE29142BF32B192C422CEF290A28942720286D2A212C7E34F62EF329E428FF25C7258324F9256526B2285D270C27E1264A26DC25F42512265D25D1257525C027F02674278229C72878276528F6265B27462A692AC829B12768278C26C625F6268827CB28FD2602298F2B542AE5294C27BA278D270128142BA72B3E2CF52BA229A42AE52BAF2A762CDB2CD3288428DE264729972C692E4C35F92C092916260827E72625251427782845290A2929299E273627F62591249E25AF25F4264E28BB287A2784271228142A2E29C0260A26BD264629082BC02A9229602975296E290929D928AA29A829F828A52CC72D4C2B1D299529FB288729B02C382E692C2F2C662A7B2B0E2B202C952CBD2B60299128BE27662A6F2C4F2E16365D2DC128192886264428632717294B2A092A252A632AED292F287A25BA2538258626FA27EB2CCE2A87298926FF27E8296B2908271B264026CB26E1260327EC276828A7274D28F629532AE928C12A472AD62D582BE92A5C2A7F2A8B2A3E2BE32BC52B892B7E2C132BCF2C9C2B7A2CB72A312B9A2AB52B7F2BD62B012C9C2E73361F2F6F294529D32BAA2B312B4629682C862B902C472C2A2C4B28AF253027582745277C2AA92AA52C6E2934256828792A472B2529BD26CE2637277B268425A526B1250B273529F728E3287C2AE2294629342BB929792AAF2B222B2C2A272A9E2CCE2BD22B5D2A292AB42B4A2BDB2BCB2C52287228092B752A8D2BC42B932E4536DA2F8D29DC2B6A2B3F2D442C372B9A2C902C592B472B75292329182680261C284427112AEC2A692B2629BF26F6267627D727D229CC29FF283527F2258524E42360256B28F226BA27E92853264A2970283F2AC62AFE294C284D27CE27FB287E2AB82A5F296F2A542ADF2CF92AD12B45299B28AD27802B332B1F2C302C952C1D36152FDC2AE329E52B8C2A6C2C852A8C29CE2B9F2BEB2AA927AE253626E3253E261E28F6285D2AAA2929271727862759289229D92BB12A152A8D29B42694254A2569240825B7248524EA2508263B268927522AB42C972A33288A2633287F29BA2B572BDC284028F129CA2DF62CFF2B4629D427AF27632A902B702CCE2C152EA3379D30002AEE298729C92A7F2A112A742B802ADB2762275B254C2566230125E025062533281028F227F126CD27F926A52AF22BAE2B162A602AD52A542A662A88298528992669246C24D123FC266828362AAA2AEA2B3E29FA2607273227E1297F2BDF2AFF29862B032D672E2B2C152B33292028FE27AD2AAB2CE32D332EC32CB0362330A22914288F288C29662AF2299A28AB2857257224762425245A2562270E297828552785265326C325B2253F280A282C2977299B28AC265E287829F329FE299E29E025B823E121D525AF259129CA2A2A2B232B1C27DC24AC25EE28B429AE2C032C402B912B8B2CF82BC12A7E2BA82943287028652A2E2C532DB62CF62D8636C430E52955290B276D273929D02812283A27D724B024D025ED242226C029AC2BF42A8D296629422671250224B72578285E290E2A122A00276E269227C726DB27DF262225E925E424C726F327FC281B29152A9E296527DA27432833274C295E2CF32DFA2D082B312C3C2D7B2BC928B327DE2608294C2BEC2B502DD22C012D513409315828B726D3264528172A0C2A86279A25BF244B23A9245F257226E328892A872B252BF82ADF27DC25B62413259927E927BF28122705286B2619267F265425D92563253A2769289F298A2ACA29D72A442B142937289A2910276D2696289029F82D872D202D232C332C082BF228D128EF278329DC2CA32D3D2D922DE12A26345A2EDD28A1273826EF27A22A3B2860262525D0247B25B0240127DF26F42871298B2B662C1E2CAD298028CB25D526612A1A289829FE290D2BF627A226EF253F243D25E7261227002782296D2BFB293F289B29F42702283D271027C3243626162BC42BD62C082C3C2B9D2CFE2A48296C290D2A6129362BCC28DD29162BBE2A0F34462FBC2AA726C6272328EF297729D425B52616241C25D226E82760272C275329F728DB2A302CDE2C882960288727162ADF29C0296A29642AF82AF528242560244125B4275B261826AB27AB29F8294B27DB260F28CD2732271E279A23F6243626E62AAB296A2AB729292A3328A0294329732B59286B27EA28AE28272AF92A39338030932C9C29E028842869290C283526052799279128E2289729F6266427B527D328DA2A662A5C2DE42A5529EC29D92800290428252937288B2B4E29A529AC2696270B27BD2659255628A128EF28C1276D26A427FF289D2775273823A7244F25F3285D2A312C1F2BCC2BAF28DF2A7B2BC1295A273F2647270F2AF42B512CB8351233B52D7D2A4F2AD12AC62A08278D266128EF296A2CFB2A66299B2A6B2B912AE129392A1D29AD2AAE28B32750286A292328F3279426A5268B284B29B827F82744289A25E3241F26DD255629F229E3251D29DB2A202A6E264326C1245626762577271A29522B522AC22B9E2BD92AAB29282AB726FD26E325EB280629122BB334B231152D872C642B4C2A8C296C294028562BD52C4B2C192C192BF0296A2C2C2B472A8E289227902664254727EA27D027C2269027EC25262502275B2985290D282228B227DF27F0261C28A72971299A27BC278C295F29C32680253825A726A3268B27E02A0B2CC02A062B922AF429BB2B20296E27FA27A827DB2A5D2CE22C27363630EC2AA72BE12A23295A29C226C328F02C8E2C4A2C612A3F291E288B28372AA5298C283B28B426B123EE23A125BF2639266E27DB24752699256C244A2771267C26C927A1293B284429F029AE279727EC272C2992270828C3275F26BB26A8264328FA285D2A6A29632A1F2A002B2E2B5928E32612296A28C32AEA2A8D2BB9331C30B32A5A280C2971285227F627272A722D5B2A4D29062A5F273F2724273B28F829CD29322991271B25C7248C261927A12672289F273A257225DA264727A327D52716282A286429652A212A472931281829A428E2276327EC26F1260527C229EC29D0283F288229AB2A6B2C842C472E89299528C228CC29062B602B522D9C35CD2DAF295029BD258B25222612266D27912859292D28C727A825A82691260C29642808298B2A5528E1268F2426264325A4264229F627EF27B8275F26232773266827FB256127A5274B279B2665266C258B26FC258325582841278525AE269828772A35293C29DE2A202C5E2BB52B2C2A072965282227142A3B2C2D2C352CFC36A42E592931263324222424241425A525A926AB2624257E254825E8256227A724B3264728FB285E297428DE2538255E240926162896297F283929812761282728B3265625EB256D23C824642472234D238825C32638275E27E1255925DB251928F928DC29152ADE29BA2BC829BE295D2A602639262328E328BF2A702EA12D92373C2DCC27AB24A7236123A624ED230027E22394258A2628277527D32883285E26712668299529D82A88276325962521268725F6270A292329662A59280B284A27822628255D248123CC2430250F254D2546250A28BB28E2270B265A261F27B2273329CA296429C627B9281A251C26D724282429269C273D29952C4E2C662D0E36F22D562653242625B62399241B2557265427D726BB2A702BC529832A142A2629B52952299C2BEF2CFE2983264C27A62844263F28D8282A298128F1256426762598269727BD285626AD2651275A2832273028562AEA28B8282B2A842A642B8E2B8E2936298928F02677267B25B823BB2464256224942628288528342AD52B0234BF2E65298F25EB237C25A523C825BA2656281D2A1C2B3B2B712B0029E6260129EE295B2BAB2B322DEC29E72675278628182816287A2AEC2BB1284A275C259624D028A829C429F027D1295F28A4284727E429AA2A97287928F629F0284A2CD5299F2C232C132B8F274D265F244324F7259024D7239D268B28692A412B1C2DDA36B2307529D625462420262224412665262F28B1285E2AD629B4295227A8262427A228802A0F2B422CD82AC0286F270E299629BA29AE2A8128E8285726C5266025712609273C285F27DD24482822271F275C295F2A3C271E27FD26CA26C726BD280B299B29B02B63283028BF26A225D9243825F725D428A32AE72B9D2C6A2D5037E12E27292C27972331237523D1242025972795263E275F28892885297029F126102A9D2B1C2CDD2CD62BE3292A2935271227AD28D9271A289D2ABF28CB25F423EE247F269E2493237F221625DE246E28592A362BE7263525E92532257E263825F328AA2A6B2B492C642AE628BB273F284C25ED255628C627182C062D6E2E2E35CD2D212896252B245C2313242B25612594258824CA25B027F0276028A82833298A29F1288B2888299B2A792995280B27F3260026A325D52748264F272D243A24BF23832382247A220022DC246726E727232A8329682865259224E624B124902842299B28212A4E2C152CBA28C52773274426F924822784279229E82A312BEA32B42C5628DC2308232022B921F8233523CA238C225A24C2222C255E26F926CE26A527BF2604271B27F627CA243F26B428F126E42513250A25DC25DA238B257A25BC2345234F245621FA227B2522278429042B542BDB2AAB26F425CE2327244025382905280D261826B0277D27E125BF2672248B25DD26B725842534278328E1301E2D10278A258423712496238922B12271238C22C323B922A9248A24ED2570255224E625E925CA2656258F24102562266125A423B3228D24D52485240625B525DE2513256E2382221E2566277529CC2A8A2A3D2BC528AD27D225F623D922F02403261825E224FF248425A7236E24F9254D285C25C625B22368230C23B626DB30312C6625DF235C242A24F3225222CD23AC21B42288228522F422AF22D6237C25C7246124C9271129BE283D267527F425D324C0249424C7230024AC234824CB261F263026B5220B2360230B288F283C29EF29A82AEA2875274D26BA223823A023C92315246F2336238923CA24A7265625F0264127E325FE24A824F225212701307C2CE925AB221F24B12456239D2327233523732407240422DF225223BF2493250F26022750284B29552BA52847297325BE25F224BB21D623C022A424CB25EF27472614249E23F5239B2313286B29F728312B3A2BAF278D28DF253A246523BD246F231F21302402231122112421247026C227D527C8269423FF25A926AF297432362C892652232123B024BD245023FA24262375227C22A4224C21552245259527BD26C027302B372A1D2C5E2AA6290627C0256C25C0220D23C82226253225B526322502222D2398225F23322782286D263728312754277925F826FB23BC2510232023A622E722E8215B243C22FA24A927BE290028F9252E26C6272A27DD290E35F72C72268F2267244D24AC248A230A251E24B822C32287236422CB2169252227DB286729082B202A812CED294829D325E723B6248D223F218523D22618259F2487238F2119236E22B72268263227E825FA26CA267824A524BE23A322A02229235B241B2306232B225A24D724B32606294E29DE282726CC258F284C2C342DBC37CB2C1C26B0244B223B25A625E82319248D24262403254423E922BA221F2593247D261E299D297F29D42AD0281C287025AF239B249F2316238C24042357239123BF22B02295215A23FF245D25CB26D228C327D0242A249B216F206722CB225725D9249E2551257E246226B92679283B2AD828CC2909289E265429492D2B2ECA35 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 403F ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 0009 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 4F282D223122112002210A201C1FC41FCF1F541FCE1E2A1E3B1E8D1D3A1FDF1DCE1CE51E6F1EA11C7C1EC51DC91F521ED71E221E501F3A1F781E8E1E3F20AA1E4B1D0C1E251DAA1B221CC51D461DAA1D431DC61E8B1D8B1D1D1E2B1DE61CF71D3D1FAF1EA21E831C2A1E931DA01CF11E571DE61F4A1F001F541ECB208522B22D4D2B892337205122B8211E20BD2018214621E91E59207D1F841E301FD11E851EB31D5E1E2A1E381E4A1E6B1FBB1F0621661E0A20AF1EA61FE01E361F0520651E7E1E821F701E341F7C1DB11FA41DD31DA21FDC1ED11D9A1D501E3920541F571E971EAA1E371F3D1E861F781FD41E021F9D1E2120F620592017210321C123612D362B8124EC22062290206B209220AA21C11F7D22AE21AE21D31F601F931FE71FCB1F70205D1F3A1E4F1E4A20AF1F2B1F7420BB20AA1F8C1FD31FBE1CDF1E1420C31F7020951FDC1F931E1A1F431E0E1EAA1E541F111E901E341F061DF41E441F561F671FD81E981D601F8D1FAD1F971E8C1E1A1F1122BF1FB5202121A624AA2E9E2B6427EA23FF209F21F920E92196203E201A20D61F771F6B20791FD120591EA81F8D1FA41F7121DD1E471F631E112002200D21F21F73201F1FDA1DCD1CBC1E1620AC1F1021651E231E371F111E601D7E1E771F581FCA1F061FEC1EC91F0320E2208D1FA01F031F1E1F211ED41D831E2C1F751F8320CE214420CA21CD23ED2D882CC725D321D520F520AF210F211E2140219E20AF208420A71F3B1F94200020041F5920791F6C1FAD1FC41FC621221EA51E04227D1F491C571F081FAD1E691E4D20E8203120F91DB91EFA1E0A1EBB1F9D1EC120D41E2B1F961F3220F31EDF1E49201E20AC20E71E1220C11E5E1F801F9B1F9F1F6320491F522096224E23B72C5B2A802543220823632025225B208920E521C3205F21A9212E1FF41F21209120B020DA1F891F3521AF1F261F5820B020B91E2720311FF51ED21E411F991EBB1FD41F2D20891F871D0820F71D221FAB1E201FAC1FDB1FFE1FE41ED71F281F7D1F9420A720691FDE1F991FFF1F681FEC1F0D1FDC1FC221D720B3204E234124F62CA42A57231522A421ED20C6201522F620A020B7210721CB1F3620AD1F10211721812125208020D81F7D215221AC1F1D205D1E1E1EBE1FC91FBF1F2F1FB42063206A1FFF1F751FC71E321E551E961E221EA91F29211B1F041FA81FEC1FCB1E581F9020B91E2620451F981FA01F451F671FCD202A1F8B20871F4521F8219322A12D9C2AAF240622B32215212E1FE41F8E208320F020F61E27204F210622E81FC61FF2206920E7205921ED20331F2920CA21EA1EB81E6A1FC01EBA1F3E205B1FB71E151F9B1FD61F951E861E3D2067208B1DE320971F741EB91D821E531D741F011F561F271F4E1F8E1F3B20711FDD1EF41FA91F5C1F721FF51E9321E021EB23462E57297B24CA2265217E210920E31ED320B22101215820DF1F9F1F571FAD20B31EFE1EA220D1209420AF20151FBE1D3E209C1E1C20361E891DA01D8D1FE51EAB1E671FD81F531F2A1F4E1EED1D791D281EBD1F951E841FEC1DE5206C1FF01E3C1F981F911E7C207B205621511F201EA31FA220241FC11F481F0C202C225222542E0D2C0623BB20B9200421B91FE8206F20132272207A21D820111F8120A4202420D320B41FB8204120262081205C1E8C1F8B1EB4206A20891E9220891E621EF81E1C1F9C206F1FB81FD61D6E1F201FE61D851F23206E1F281FC01EB81FB11E761FB222AF1FE41E9220A420672004215B20602006215F208620CE1F762275230530622A9626A92282210D228F200921E72035216B21AC227821F9204B1F5D20BA209920412080208E20331EED1FAD1E8E20F81DFA1D2E1E4C1E461F9A1EE81DA71DEF1F1D1F331FAF1FDE1DBD1D401FA81DEC1E021E8C1EBB1E1D20BE1FD01FCA206820611F571F5B201A21531F371E3520FA1F781FC01FA11ECE203A223223E52F832BB024C6217A23D8209A1F842053200322C7215821D020B11FC81F751F6920C91F0020CD1F7922B91F42217B1EDF1EF01E121F8B1FF11E1B1E931DEE1E331ECC1D561F0A1E841E851EF71D261FE71EEA1F9C1EB01FF61F26207E1FEF1E7B2061209D209221691FBF21B520DB1F4821C5200020D21F2620EC1F6120B024D02E412C4D266922CD21C1205720BE20681F3321C1200E208221DE1F6B21B020CF21D4203220F21E59218C1FC91F6C1E85210E20C81F971F7A1EDF1EE31F181F851F7A1E6C1F1220BF1E421DBE1E2821971FA31E4F20CD1E361F2F21D220311F0121AC1FDC1F631EE71ED01FE51FE61FDD20C11FEB1FD42148200621F3217F249D2C1F2B422593226422BF223620C320B9211622BF2144204E208E1F891F7621551FC620CF200F203720CF1F2A1F8C1F5C20C520B720EB1E771E8A208B1E211E1C1D651F8F1F5D1F541EE91E1F1FAA200D1F7221B421C21F8F1F1F1F4A205B20D6202421601E3E1FCD1E9A20841ED31D381F632081216821AB20A1212D22FE23312F6B2AB72423238921EB222C2119225F201B237320BD211422AA1F0520C51FE4205F1FDF21B322EA1FDF1ECA1ED31FC420FE20771F871E811F931FA61E821EAF1E3E20BA1FCA1F721F0F1FC51EFE1E5020B31F0D210721191F961FFB1FBD1E1E1F531F7A206620B31FDB20F21F681F4A2039212320E221521F7720582272233D2DDA2BD5252422C9204C212222B421CE21FA1F8F211522C220D61ED520622114221020822199202220F321FC21411FF51F731EE21F3A204E1F121F5E1F9E1E9F1E151F831E5F1FBF1EE01D3E21A21FDE1F8C216E1E8C1E8D1E7F1FDB1E201F541F7820C41E9D20901F4D210022251F2021522030217921E9215D21002224246A2DF129CF25D0236D2326214C217621B3218A201421A9229E21D7200921FA20382118218620D2205420C6211520C220A820192011215620601ECA1F3220671F9B1FB91FEC20FC208B1F551EB41D851EAA1FBF1F5D1F0F1FA31F0E220F20191FAF207D208F1F9B20601F3A20F41F0020491E5D21262168215222832289222F251D2FAC2B31255923C420E5219F229A215C21B6210F22AB219221482152219C1F6C203D20082126224620282014217120AA201F1F2E21E6202A204620011FC220F61F7F21A020C31F031FAC207520651F731EEB1FAF2137205D1EF321A31F0D1F221FC4210F1F8820E31E2821B71F7C22CB21C222A621042169219A2293227C24D630E929F2262D22AE228B224F220823082246210C218622F71FA020C020ED215720F1200523D4203C231222EC1F90216322401FDA207020AF20F21F401FBC208A203521F320B320761EFC203220CB20541EB620A81FA71FA51FF51E511E881EE81F60209E217E22231F3F2158200920781FFD20CE205D2082204923CD222425842FCB2CB82418220C22772104222321FE217220612059212B22A021A91F5522952214226A1FC02134223620F81FB31F5A20152177203C1E0E1E3D220F207321281F1421D421AD20B8202A203620E01EB61F54201220021FD71EBA203D1F15200F21772262216621B4219922981F8B1F3822FA20AB2055210F2141221C24A124482FA42B6125A0238D22092212225620012151219221F8226921212036209820B321842057234E21782087200022D820AA20452100200A203F1FEF1FE820DE2069224F22B122AE215521931F591F8B21A21EAB20B82047202E20D71EC220EC1FAD2095211420B2200721E022A621B42198248621B5217B239020332304245C24292FD92A6824D9236D21E42066214D2119211C22DF21751F8E210D21F121A1201C21F621D11F12227320412128213421CA20751FED1F3A1EB81E5720A31FCB211C216E220623CD214621D8203E208A1F37203C21DA20C81E721FDC1F8220251F0C20CE20C92193209E21DD228D210522112180204E222B214A23C12382233225AF2EE22AD924CC219E22BE22802220226C219422C3216B224622BF2152203B22E4204721C0203D210D1F581FC61F5A204F20A81F731FC31E9D1FFE1FE81E3A21E321D320FE21E021AC219F20A523A021F81F41224921EB20AA1F92208020D1204C223C222522F1237022AB23982420235C223D2247219F22AF2365234524C4243230542B96247B236322AC227F20062258225D217F2025210122A51F702145233C2157211A228D207421CE20D120C52120223321D01FC81E8920D920D41F5A21B321E021F1226321611F1F226D22C2228922F522F4211D238B21D32115210321D422A120D2213B2212226923A921BF22A123F323CE22E223FB23512534246826DB30A42B8424D121E72182225121D220B820DF22E720B8228821B92062209D1F572060209620262185232D20A91F5C210E211D202D202820D71F751F24200320602120215022D121C0219C21562134236821422155211922092260228F206D20FE20E022F6209E207B214E217721D9217A249024F523BA24E624D826B52649251D2F1E2BB22440228823E32106229E221C22152297203D217C219A209821E321C221C7222D20C22148216021862254204521822034216A2105201322CA21D1224722C52241229D221A2285209C22CC221E21E5226322CD20CE1FA7229E208220A6229B214A228B22CB2058236922E9235F260C2761257425A2240126D124AC2666300A2CD1255D22B5210F230D238D226A2234227621A6228222ED20FD21C3212022032334237D204C226E21A4204C201A22E320E2205022EB202422B622E723EA214223B122A523BA211724E4227F23D5232E22D02275218120DA209922B52161243423352364246A24BB240923D024F626AC27D12719273C264C2411254025B62FFD2B072703227B2319230F232623D223F8222022C423EB21AF241822A3229322A421A922E0212522782180215E21D821C221FC20242066210622D22239238123B623E62380236E2248245F239B24F322D022D0210E212021DF2096220922B9236527382605267F27A82690257625D7266528A726B226482592258224DF26DF30E42C0C263C25C624C22362223923BE2375249123A3214A239E223A24A922E823DF235F221423DB21FA211D22ED215D213C21C0228D21B5212723F523D122152482249C246425A42332256F25F7220A23BD2315223A22812170238C21FC23EE2637284529BD28B2299D289526E92504284A27CA2780267A2451243B268326B530B62D29276622CF22C4224125FC23FF23DA24AB22C92439232723DF218F22BB23D823EA22302394247B215B222A218A237521C522D62387234924AA23D423722406248724DE25F125FA25EE2568241E244D24B0230A25FA21CD23C52349259427342A272C9C2B3E2AE82808278025DA25F925DE2664276A255725FF26B427BE32DB2CCC25D5236123CB24D223C423FB2498238525FD2124235D2122222B213E20702112223723BD22102182202F23F622E422FD23EB258D2456253625A32409240424CC25DC264326C225AB23B22335235623FD25E622C3234C242D25C024102750285F2B9D2AC026EF276A27EF28C428F927462777273B263F28D628A9299E335E2C2628EE23C225F42505236523A222C4244325DA25F2239A219C22D324B324552202234923DF232B21BE217F213D21062353263E278226C42602242425A2246E28592868293F26BB24552536241F227E2439277C2536266626D325C8267D26A4289E284C261326EF25852659285F29F729B42B162950288A27E92A2F2C2534EC2C65268224C624F12475245225D12317230E24F02345232B2462238523EF2300248E220325B923052314238E226E225124AA2792287628C4260C256623DF256E289C2B4E2B8C283F249A25DD23AE248A27022AEA295728D2260E26A92665252327D02565244924C227FA280F2A6B2A4F2BDD2A012B1B29FD29822B142BCF33C52DA828E7256B260C250D262C232C23FD235523E422BC23D0234F24A4242324A1239C25BD241525A72596235925F22442264428D828662595256C2582248B261F2B6B2D952B5028D3269B239C23F0242B2A702CCB289927B226FC24CB2482245A242D24A42489257527F927B328B7287F2BF52BE429372A6B2B282B842921336F2D3627442486255A26A623532440221624FF2221242A248725F523B9244024F7245526C526B326C928D2269D25E327AB2781276B288324952381248125F128C22A762E5D2B2F287F263C25FE244825012AF92B92290A2871244C2437258822CC23A9225C2283236926BE29B02AA72BE82A3D2CAB2C062BD729F6292928A230E32B8C2603269C24952549248D235A220F232E244C26B627422655256F24FC243E274627B726D728932602262F272E27C2250D26B52656239D234E25CA26FB299E2B682C2B2DAD275524962669274B2793296F2D472BE1267625422531245524DA2268224E24FF268229022BB2294D2B662C142D052C1829E12711271B267531AC2D1B274C26F8254625132315227D2331248D2601290D287427E224EF2424252B260128922771283326952433246C26C524DB237F260E24682420271228362BDD2B022DC62A552655234F2519267428032C9B2C402A152790252322042336228F24792163249827B1286E2ACC2B8F2C052C1E2B632AAC275126F8244F25932F822E2D290427D425E625F62431251C265927D0284D2AC5280D27502984264F24DF251A25AE257E257E259B2156232E254E247223A924DF2321255C27DB291B2D782CFF2BDA29E4258A230C235B261E28C92BCF2ACA2BD927E6244324EE228621B7225A232F2461262A2A6E2AA12BAF2AC8294A262227B924CC231C249825B1304C30E7299A2847272226CF2432256126602BCF2AFF2AC92AF9290F297B278B24D925B724872321242123FF23EE259F2429275F263524AC2547250A28702B1A2C782CFB2B472AFF24AE222423EE246C28DC2A2D2A562AED280E279523A02240237A23BA23C825D5275229102A4A2959287325BA235124F720BC2340248D26B02F3831692B1F2AB128722506255F26B628D52ADB2B6C2C3E2B7328C8257B246923F622032444239A23D5253425DA263C290329F22819272C26E426B528072B0A2BC22BAA2AA128B7241424DA24922528273329F9299729FF27802780231622AF211223B6249E27EC28F629F827F02586252925C323DA241A231B248C25F427A132CE31F02D7B2B632B32290F288028F72AF92D322C5D29E3273A276027E9256A247925BE24B5225F27D626C428242AA12A522B562BD32759264B2934292B2B6C2CF52BA329C927F7249824BB267C267727B128872861287B26D12401234A2370246823562557275128DF280727AF257725AD241A24F22352234D24F325B22A3E35EC322E2D732AE32AAB264E263528612A722B032AAF29BC285D261625D424AC23FC238B257C27E728E62A512BB92BB82C412CC6292B2756247F268728CE28352A1429A0274527502363248326FA26CC25C925F626862706272626602386228C2209252B257F256E26BA27B725E6254326BE259C25B4268F248526BF29BA2B19330C34402EF72C43290E2A0225CE27A929A2294329F328F828692744254D2536241A2595269C29152BC72B132B522AF22B7E2B0229D4252525DB241C26B727A7270D263824942549247824332455250226D82741284F29B0260026B524F9239D22BA231D26ED265027BE282328AE27632852288F283328D427B8274527652A013396325B2D1C2B26297627512783268D28EF28102AE22A8C2AAB281E27B423F923C82453295F2B732B1329D728BD29172BAB29AD2B7E27C222DD24C42362245A2630255B249A23C4218022B5232E2797279029702B9D2AA529BE290C27F0246C25D8231D259F27A528702974292A29192A602B092A5D29D526CA252A27F828E5318832DA2CBB29412702278A270D26A6266C2A8E2A1D2B062BE4271725A7251D252626EB29D929F329962A59299429AE2A382AB227592491231523E522EA2308236A229A23562369218E236A268627C32A5A2BA22DED2BFF2BB2284B273B252324BC243626DA28062A402CEF281C290B2B752A1829B3279F257C26AD25F625A42F6431972A3B270826E7261027A927ED281B2AAE2C6F2BD12AE228BB26BD25732546273D29CA292B2A362783277829D92AD82B34281C24E422FC22FF1F592350236924D9247024C323B0243E26372AD02A442B0E2DD12AEE2A3A2A9925CD25252523242D2590279027572B0F2B4D2AE52B352AB6274527D2249825F0261926842FFC2F552A6C27952542289329DA2AD929092BE42A252C8229F426AE25B8258526D927572A46277F26A72643262A29D92B692A66272124F8230C247923A925702770271B25772591256226CE28C22B3C2AF52AD42A812BA629F625C825FD24B123F7215A24A2237625062887277627FD296928CD2427259F230E247824AA25B030DB2E7728A026B5275628152B6B2ACA2A0F2CA82CF72A642A61276F25E824DA2517286D271427592769265C277E2B322C252963266A24B123FF239E26E1274B28C6285B2733272F26CB27FD29C32A972A162BD12B7C2921275425AB23DE232E246B23B22403241F23D324F82449260C26F723BE23B8230523D623802435261331532E8C2815260328F429162C472B9229D32A402B7D2CAC28F52469232E2496233027F224A7267C26BD259229502B172D0A2A0726E221AA22ED24CC24E8272529012A6528ED288A264027582747281828CF288329C726CC2421246B2381221E24872379219F2235225B24A924BB23CF24A5236A22D0216622AA24B9254428F430CC2C03297A27B829AC2CBD2B8F29392B262D832BCC2918283B2496237C24A826EC2581273F28A129202A482AD02ABA28AD27FC25E6230324B823E424A12767299C2A9F293228DD26C82533266A26F3261B26102740251B2219239D24B32385237522922528242326AF254525E723382344236A242324D3237826FD2651294B34A72D0D296729D529E02B872CB12D9D2CF82B89299228DB25A72450230C250226F7292B2E942B2B2CC328B028EC26B62638226321F6226A221323B5259E2661265025C225A72583252225E92305244424B42598239E2329241B255327172653270027E927592698262B2718259423E9230723F822BB25D926702AEC28D02BD533412F542C2A2C342C182B162CBF2B472BCA2B88293028CF243024BA2547273229AC2A642C1F2C172E6929A2278926A325C7215423F922CA23F0251B247825C025CB26FC286C272A276F265426C424212315247F256C257225F326E0285A295E2993288B2823280F268B280126F02393235924862637288B281F2AB72C162DFC356C2F8A2B592E4F2B912A38297428AB265D2833289826F225F3269E267529ED2A432BA82CE329772BCB29A426EF24B62211236F216F2488243526C12456265C26D227E82AD62BC62A922AA3278C25E12318247B258625F527D52AAF2A7D29D128E126EF26D4259325E5234C23B924D124D2242827BF2B352B122C5A2B632CF4372732022C792C8F2AAA2919283B26B1272926A824FC26E12696269527E3289D2ABE28C3286328FD273A24C0249424A424BD23F6246C25FD26AF26D7266B28C128A22B402D932CA72B8729F3277824A423502610283D28812AE229B0298226B3255C277D25512494246A2528230325F22743278E27CC2AF529212BE32A412B593400312B2E712CDA2C572C472A86284E2758258526D628742B8028482987275B267225F4247925BB252F27AF24FE26F3264526D427BD2A1729002AF32A142A142AF92BF32CC52C1B2D442A2827FF24B4245E283A2B3F2B522AF6283328F325BF26FE2881270B264C2524269E254F25562628268227332AA22830287928D32712309D32182E202ECD2CF929472BC7288928B5281D2772292D2CB72B2427A72529248B26252642260B2931287D299929C72B8B2AB42A6A29782B8D2B5A2CC72B142A882B732E422C0A2DE02941277B2492269129FB2B7329A0281A274527912769289A2973292E295425A6287328DE252C27B7252326A7296928CB260D28E8286531982F772BA52A402BEF288328BC278A28DC25CD24E828D726E0273E269E269F253127792766273B28682A2C292D2C5D2C3E2D3B2BAE2909292B2A092BD32AE829232A1E2D142CC12A53284925FE273928522AE72C9B2AB928D8273E2721289429AC2918285D273427CC27FF27A327CC255023F2222E28A327DE28F927D3282E322C2FA9279327AA27D128E72635288C25B725F0263927B0259526DE2657287C27DE27F12721277428D228372A352B982C4E2CE42A8C2A132AEC2947299B286727D9272C29F3283A2701250F24A227B4281D2C0D2D102C70281F28B2263628102A5A2A9F29432A132864294B27992573247B24E527D42A332C002ECE2A4A2B18348C2D0428C3270D287F27582737261A2688266327BF28402895298F28892A3B2A86287F26DE263A28A529402B452DD42C122C102BEE2BE52898290328C227ED25F7243B262B277124A4250A27F4276529E52B032C5E2A7D2963277F26B627902709283729F92A97292F2A2927EE258B26E4258E2A7E2C362C902D262CAC2D1D38832E76295B2BDA2ABA296028B225F3255F271E28732A0E2A5F2ABA2A3D2C79291628A2262526CA278128442AC22BAE2D2D2FB32BE72740244725CE25F324A4253124C325EC2463257B262D29472BF82B922C532A6E2CED2959283E261F2515276627D727602A46287D28DA255B236A279129242C662C7A2C262C092D332E05378F2FBD2B502CAA2B342AEF282D25A5261B28A229132C422B6C2A2F28EE272E29A4276B260426B4265F28632B312C172DA02ADD27BB2584244F224C25FF227122FA22E924152511263F28732AD82B522BA72B1D2CBA2A032B0D27F0246B25D025412779278727D52624288E26172659270C2A432C8A2C50293A2A9E2BFA2C3D36402F5D2DDE2BCA2BB8297F28DE2700286B2AF62A9E2CBF2A3C2B6F29D02848255F26D325FC25EC266127442B8E2BF3297627B8252F23C722D5223D24262421249224D124DA26E128DC29F02BDC2D472BC02BF12A1E2B202AE4287E2476238C241128A529CF2AFB276C28B526E7266F292B2B442C942CF22AFF29BB28112BC434EE2F7B2D8E2F842B8A2B662BBE2ACE28D6297E2BAF2C592CA72A3F2A8427D227E0266527E5253027C12501290D28CA2715259225A12275227424D925922581255124C3248928DF275B2ABC2BB22CFA29EF2A0F2A3928BA269628CB23B623EB25AD29982BEE2A252B392A0A296F28192ABA2B9D29A02DB42893289B2BC82C4F3503326E2C2E2EDF2C292EB02FC12CAB2BD12BEA2A8D2C592C922A23296B28EC26F42A492C4729AD25E826C026812514270826C8235C2515252D26C9261F282D275327D52789270F29EB29302AD72A042862276428E127E227CA27E026E3247D274129922C7F2B282B5E2B3F28AB27CB2CCD2BB32A402C792A6D2A392E692C01378230952D6D2B032D1A2E0E2C0A2D3C2C912CF22B4C2939286D26C0263B28C02A7C2BE62BCE29F22733250F2702278B257424D7255C252E27C1295D2A8C2968294E2AC629C9286827842890281326702689276526CA28D5287F2974263525DD262D2AF629242B8C2CDE2AC2271127B82A262CAF2D3D2B9F2B9F2BE22D382EE836A82ECB2B232BB52C942AA92BFB2CB42C612CAF28552A04263E27822676286E288B2AFC29D5290F27D2247625DC2521282526A825A4273F28E02AA62B6829FB29512BF02B5F299927B5281027C724BC2345250F27B0282229822859265D26F825D929BF2AF62A2A2A6E2815271127D82A412AB92A5A2B762CE02C302C8C2DE5351A2DE72992283B28A22A2D2A2A29972CBF299328DB266E245E273B271029B728C628632878260E274326BF267529C629102725268127762A012C912AF429802A8B2B402BEC2A322858258A26C925C8239324F62897265327A7288A27E526AF27FA26C028522A7A28E028EB262328032AAC29DE281329CB2A1B2CCC2D162D4F34DA2FBA2A442AD12AF52A5F2B052AC72BF428B1267A26BB2760260428F9271628452886272A262229CA29E428F52B9B2946292A2A8F2B102ACD2A5F2B48294828052AFA295528FD25E325CE26BD276528AA29202BF429CD279A253125AC26382552266B29FD288527A3269425D9293129B7270A285A2AE72A2C2B032CC12B9131E2316D2BB02A442A8C2BFE2CCE2B4E2A7B28CF25E825D32505285D285D27CA27AB26B5271728AA2BE22CB02BE22AEA2CB12A492ADC29822A8D2BFE294B297F27CB29E429EC27742700273726C0282728CE2AB52C5D28B22789267525B527F52680269926A3240B263E2510288427CD273D28B4280729762AA22C872A2F29B4317630892B94292629A02AE22B502A2F275F272226E32783299529BF295B291225CA255A29FD293A2BD72B002A442AF82A282C632B5E2B8929D42A0E2B8F2A342B5A2BB12B5E2B69276C276629632AB228E22940293627E124F728022964286A28AD2536242125CE241E270C27F228452B362AE62A2C2A162A262933288528D430D62FB42AB42A5D2BA62A822A81286A27BA288B29192A272DB02A2E2ACD29B5269327CF275E2A552C672B552A8229772A1B2BD42ADA2A6C29E62BDF2A802A86295A2B432BDE2BA82852282628B528F626CF271326D7255B254E295A28D62795275B258F236F24B424F9272F292F2CFC2B312AA2296127782720264126F927DE32EF31F12AF42A7D2CD62B852A08275E273D2ADE2B562B252DC12ADB2935286E2795268F28082B362B9A2B4E29EA29A52A272A3129C927B828FD280D29642690260F2AE72ABA2CE12726272527C725C1248824CD251E2484261D2628286425CB247D250B23412599269D27B029082BA02BA42B1529DC2634266F278726D229DE352730A42A2B2ADE2A522B3129F7286D29AE2A632BCC2CFB2B662A84279926E2274C27E227C52A8E2B99280C27E6257627022666263D257725D4261A25B0254828AA28BC2A4F2AD6260F264D24AC234E230D26C6256828E627C3274325BE253025F2244C249424002746291F2B152CB02DD02ACA285F2708265D285829B32C4D372A30B12BF728402A0F297427042AB22A182B942AB42A7E2A5D28C32717276928D929852BF32A512A30272529F026412676235A2518242724BC254426F9248C262228AD274527E7236F23A62448241724CC25AF286B2BAC2A99298D2852286E28DF277C257526B628072C7D2BFE2BFD2B0A2B8928BB2633259128C52AB62DF7376E32B72C442BE02A912988297C2B022B632C682B302C412A3A298829D027702B772DE22BA32A072B3F2929287528DB271025CC2446245425A72691250828DC27C228F027AD271D25DD2428265C252A266C28ED2AD22B9C2AFB2C6E2C212B192CF329FB2963282128382D8D2C062EE02BAE286028C02845289D2AC02C3D2EBA360B31582B5B29CE27AC29682AC329092B712C512C442C6A29A727E6266F28DC29F62A852A7029C32A4E2980290C28FD269823AE266D27D626E12858282B298527562676262F26D6269A2531269D27E727D528C92C682B5D2B4A2DCA2DB82D812B2E2A6227E9269326CA29862B4A2B632B65279827092A9529EF2A2E2D712ECB3524307A2BF327E9267329A52B532C432D972DEC2C2D2C472926267E25ED256D2857274528CD270128522AE32C392BA827FC26D127EE29EF2AFD29BC2AEE27C426082886267429C628C5271F27CE288029B02C942D162CF22DD92D4F2C0C2DE32BF2295A279B255B27F828A029822AB82B30299F281E2A092DB12B732BE32C8E34BF301A2A1F284C274229542C0F2D382C572E0D2D202C7A28C42522278528BA294D2AFE28F5281629712BE82C992BFB290A29D72A1A2D4A2BE22A99288628252739286F29702A5129E228262ADE2A5E29382C132CBC2CC82DC52D732DCC2A7E29CD26622680276D25A329112CF5290C2BE328202B5D2C7A2A0D2B3E2BBA2A4A348F2E7529EC276528D5297B2C222DB32CBB2B662CD628BC26FC268428F929EA2B722B6529E2286D29552BD42DD32C9E2B962B6C2D392C2429E8280A27B226A0257D27B22A442C272A002AC62CB029DB2A392B7F2B9F295F2BD02D712D8F2BDA297F282B275D24AF27142A5F2D952B552B402B892D9D2DF82C242D7A2B892A8033122F0D2921297E28CA2A332D112CD22DB92C082A45287A263828E929402BAD2E9129782A472A0A2AAC2A752AD72B662A96285E2900296328FA263F2607290E297629A7291C297B29982A5C2AB229E228AD2775286927B9290E2CA02D8A2DE82A9828A22621267228FB2B182C742CBD2CC02CC42CE52C722C782C342B5B2BE734262FDC2A5C29FC29EE2A4A2B372CE22CDD294029D52772273D27192ACE2AFC2DF32AC1290A296E29D4291B2A0E29D829EF256B27A526C525C726A0284F286B29B12981294C292A2A202BE62A7C2A0D282B26B22637269F2729294229A12B982B42292629A7277729252B6829A32A0B2A392A1B2D5E2DDF2A352C3F2ACA2B04349B312C2D822ABA29AA2A932B5C2BCD2AE729A128B228862A562C452B542CD22A14293029282AE82B7F2C962B7A2AC927C3277E267625E826EC29BA2A2C2A192C542B4729A4271027AE28E129522BB428EA280828C427982668286C29772AB82CDA2BDA2AAA2A7E2B7F2A3F291128D028E129822BC42D452DBC2DB02CCA2C1835A630602C9F2AD4280F294F2B5629BD277B2636274329B92B512CAC2BAF2C6C2AEA2A902A802B672C682D1A2BA72863263E231424CC241925792A862B5E2C482AEF2A812A472B93284B272328D3291229C6284F29F527A5250A2CAF2AFD2BAD2BD02A732C862BDE29BB29D4277826A226A126F828012A042C942BA72B8A2B533310306B2B24288B28792A252C7D2A08271127A828902A9B2CD62B882B412C6C2C162A0A2B0A2AB12C2A2E4C2B58296426932436247225AD252F2A2B2CE92C3E2CC42BB82CC12C0F2AFB27D025422859260A27E9285F278129402B122DD82CBF2BD52AF32A442931283527C126EC26BF27E42745298A298629752B4C2BBF2A09334031E0289628ED29C72AB62A402875274926392A312CC22B292AF92A052C752B902A0C287228A92A9C2C6C2A0D2A442784267824AE250F26502A252A992A022BFD2BFD2CC92A032A0D27002617269B275C2B212A482A27298D2C6A2CB82B192CF0294229EB25BF257226AF25A528E329432C512B9E2915283F2A2E2940299C333730CE2A7A29112ADC2A0F2A8A27E62652283E29ED2B1C2853294B29AB29D92BB6292A283E26092AED29B229262AC8286F275F27F0272B2A592B0D2BE92B1C2C312B5C2BA2299E26B725DE241F27D128CB2AB32B9D2A2E28922C0A2CB12E522E9B2B39296F255C2468279328112AAF2BCD2B962CA32E1C2A59297D284F29223246311F2B782A432A172B272AFC2669295D2A1A2C1E2C5C29A827CA27CC27712ACD296B27DC267127C0281F29C228E22888281F2A012A3C2C102C012C2E2B802A022A95296B282E248922B426422AB829F12BE12D582BE629C72AAA2A052CBB2C632D8D29472745274A28B529062B462C1D2B4F2B922C262CB22B072DBE2CE433712FFF2A3028532929291329B0279C29232B802D5C2E172C412B2229E42A4A2ACA2A812987292A2924298328CA2AEA2BBD2A402C052AD42AD3298E29BD2958299D278B279D267B262227B228FD29852B512DC22C7D293C2ACB2B672C102D972CCD2D3A2987282B270928862AE929F129FF2BAF2CE82CF42BA52D802DB62C9436A031522A23280527FC275427BF28E129872D132D722DD02D642D892C852BFF2B872A8C2C6D2A142B372A6E29062D262B872A642B142B932A202957293228BB271E29DA291329AE28E7281D2B5D2DE429D52CC92B682BDD2C0B2D762A832B3A2A302CA2297229262725295F2AD32965299A2AEE2BE22CA32C3D2CE92B592D36367031CB2ABE26F824452526278729F12B282DFC2CDF2BAF2BFC2B462CDE2A472B762B4D2BA12B542BE32A602A4B2CB92BDE2A9F2C4B29B9288B285D2900298F29AB2A7F2A2E2A1B2A9F2AFE292C2A192A462A052B402C84299D2AA42A4F282F29D829B329792AE32516272029DC28CA29BF28EB297D2BD229F72A452B812B1D36E130A52A19263B24BF25FD26EE28DA2B3D2D172BCC2C482C6F2B982A562BCF29FE28DB2B8E2B0A2A692BB82B8B2C342C7929172B672AEF28372B002A842A222BF42A1E2AB02AE228EC2932292128B926D3282729C828E827B4287B263B28AC28C428102A942A112A4A2A5726ED277429262A242931299729832A8F29C52C173795301D29BD264425AC268F28C62BE72CDA2ABC2BC62AA12C582A4E2BE92AB0283428A12915279E27FE26D02655264427DA269D261D269C273328A32AF42A242839286A276C26DC25B428442800285A295A295A2B7027AF244B25B325E329F22A882BD22A3C2A862A242B1D29D2294C2CF42C802BBB2A7D291C29F928AB2A0535402FBA29FC29072799262F27842AAE2DD32BCF2B3A2D902CFA2AF42994285C270127D0260125AA254B252C25492575267D24752545246025D2273827DA27102781257E24CB259F2648287A274028802B492ADC2C282833245626F8265B28C628FF29BF2B592E402B422CD82AA32B522CB52C772C662B8D2A242B022B422CFB34F630AF2B862905292C274B288A2BA02DC72DA02C902BFF2B9E2A4929D8279C26D42563253D262A25FB25E6240F2656259725232551268326D5276027A72620276A256F26CB263A244A283528202AE92A042B772BFA289727A7278E29822CE62AFF2B582DF22D4A2D022BBE29812A652C752B022DE22CA82AA629F828A429AF319031CC2BAD29B727F4263327C12B442CE22C8E2CDC2A7F299727D32520277C26BF25E1265B26FE27DD268327D5289727C626EB2759285A2A712980268526762780289F27CC277A2696288528162B442BF82AF02A662826275A294028392A6F2B112D9E2C122DE92AEB2B2D286727D12AC32BC82AD62A4A2A1528BA280B2BCF323D31662D212B0329B027FC25F129DA29412CA62A36265C26932759267026FA271F288F290B2AC32A6F2B532A0A2A1B2ADA2868292A2B972B17292F27BE25EA27B329422B002BF42764297329AC288827412A6D2AEE27C8269826C5265B29312AEE2BEC2B702B992C5A2ACF269E2572267E271129F5296A2866288728442A8D34FC30692D102BAA277626E9243226BA27AC273F283228212898280B281529CB2A2F2ADD28D32AC0290A2C7A2B7D2B95289E25A4286326C62722284F27F42419289D2AA42DDE2B3B273F27CD2570287F2578262D285027FF253D286929642919295D28B829F02B7929DE2A26287D26AB25DA27C8255429FA2A7B2BE92CC42BC2346331DD2D242B4C2A6E28F925AB260C2AF62B892A0F2CD02CA52A742AC62B2A2C322A432AB529C82A062A21298B270926C7261B292F282727BE273F270527A628C029A12BBA2ABF27C9267128C6285F27262834296B29942B8C2A8129422B6E2A612CE6287D2815287D270B264A26F3250E24D028A42A4D2A302B672BFA2BE332D730952DC02B642C802BD12A0629532C6E2D312C9F2BD22CA72CCB2BA42BB52C4A2BFD2A742A352D2E2B3029062A922881292A2A3A2AD02822261127FB27212A612AE32AFC29DC28DE280C2AB62BE52BF92A502B9C2BE22BA82B092BF02AD22AD02CC52A7E297B2AF5282827BC25E5258B278429572A082A75295229C929A5311E33002BA729C52BE72C1F2A572BF22A8E2BBE2ED02CE72C192B2329212AD929EF29A42C802A002D422C452AF3282429C629C82AB1292F26CC26B427AF28622B102B76282926DA2672276329842A99293B2ADF2BB42BE52A4B2C172AE82A732BD22BC12A102BD129932B9329E6277927972659291E2AE228742A1C2A682AA334E72F392B7328EC29B229FA2A8C2AD62BD62C752DCE2E852C0B2BDB2ABD285A29BC292A2CBF2CA72CAE2A1E2BDB2ADA28EC28AE2AE028EA27192AA628C72AE329862B80290228F428B227D92796281C271D27B7286B29562A6B2B512B992AD92BE02C8A2C292C402CD32C1E2CBD2AA4296B27B329812A212B612C672CDC2D9E352C2EC727CA267C2566272929D129282C7B2BB32CD92CC52C0B2BE92872289029D129BD2C452C292C9C2BBF292928B726AF2935298E285728AB2830296D29E928CA29A12AC32916285A272A2A0328ED246E26C2291A2A442C022C3F2C8B2D352D922BD22BFF2C322DEF2AEC2A20293329F2285529CC2AEB2BAC2A582D2E2EF134472D3E282A26EC2732294A2A062A062DE92C242D302B1D2CF82A2228CC275628F528282A8A2BB62A8227A12642255726E3241D28EF272728F8288B28AA265A294C292C2753279726C2269928562808256627FD28252871277929D929132BB62A172CA22BF72A132A4D29DC28752761271529722A9C2CF82B7A2CCD2B5A2B3435A02E83284727BE29B028152B332A302A512B042C0B2C362BE32A86274127B9265E282B2AB02A1F2946288225DF2674258A2595274627BE29CF29DC28DD257725D2270D2835257E254D262F27B124BE23CA264B25E826B1253B28CE29D328C6271C2A412BBE2CD929C829C1288827C62812283C2AFF2B2E2B532DCD2C152C7635692F0E2BF32AB829272B9629292B30291D278D274A2865287927F929CF2998295B29252AE82AAC2AE92873282328AF27D427C0284B29532C012C7E29EC280A2876291829D32647259F263D27B8259D24E426CE27D9264826FE263B27F02609267629912BF92A6C2AAA2AF42ABE275B28E026EB29CF2B252B662CDB2BDE2DA736A32EB32AB22B982CAE2CB62C262BD427AF2673275626EA277329052BB4298F285627D02AD02BAF2A032AA329B02D3E2A332736272F2A6F2BDF2CE12BCA2A2B2CF22A8D28A326B0258C269C26E0262E26F9282E294029DE29B4296028F4287729C62A392C2F2D6F29762A462A7E2AE22ACD27C4285A2A582B6B2B4B2CA22D7C348C30792CB22CDB2D5B2DD22CFC2C432A6D2BD329CF2778283C29FF2B312B432876276B28F22B0E2C5D2D732B3E2AD528A828E929DA2AF82DF92C282C102C002D702B9E2A9628F9251B29412AC929BE2AE82BA32C8A2AFA29362A632B4A2B4D2E5D2E3B2D972CE92BB92B562B092B332BF42805276328272A082CEB2B772C8335AF2F292C392CE52D192C802BC52C1F2DBC2B4829B6287B282529F42B012B2127FD259127292D092DC72A1A2AF129B92948288728142B852C4A2AA02AA02A772A812A34291926E7250228112C2E2BEB2A9A2B752AE428B1280A2A2D2C232F902E462D862CB82D832C0A2E2F2C522C422A732731276A28612AC52AD02C112C0D35C32E2C2C652B6B294E2AA32A632B502CA62C262C922AEF2A182AFD298B2AAA2824269828F42B2B2D462BD32C4C2A472BDE2959297B29072B342BA22ADE29A429F8294C273926EF2663278129062B542AFA2A002A7828422713293D29E22B292CAA2C912DC22C1B2C7D2D5A2F732C902A2328E428B12852296D2C292BBE2C82349A2F3B2B4C2AA5291228CD2609285527F8279B28172855284C29E9298A29ED27ED24D125E72AE42C4E2D952DBA2B68290D286D29472B452B042CD529D028AC26A7263225552538264728E129442B5129DD29BD2AA9284D26C727FA26A1276D288D2B0A2CAC2C732A1A2D412DA72CC02B0429B729842A502A722B1F2C582C81337930A72B482B3428E327BB251D25EB269025E32653267827BC278B2658252525B424A9262629F42B722B5C2C072E592A8227A0279629852A652B31294C28972894262825D524752585285F29E2293029F6295A2A0127322555241B2594260C27CC290B2B4E2B102A752B3C2C2D2EAF2CA32A3C2A652968274F298A2C782AAA33082FF7287A295F275C25F4240C250B263D276227F0253B25DF249E263626CE24DE242A260C267D286728DE29D52ACA270427C2268E27C928412AAA2B272A05297327C52424253427EC2793286F28E7284729982AD527E2247A253425A2258228112A382CD82B6C29702AC82A242C132C282C092AA128C5275928852A342C8B34352E4A291C29432775260C25CC25E426DD290329FC27F6260C26D8259E26302731261D267B25A427E4268F279D29F1284627BA27F825E4264D2A4E2AFF29F3275E279326902586261527892831270329B82BA52A302A902792276527B827C32AA92BE62BBC2BD029B52AF52BBD2AA72CDB2C152927293F277829762C3E2E5935412C6428B12500270227112543265D28E1296A2A272A90277C263925A9242F26C1253F271D289E27BF26D4267C27AE299B28F7256E253D26D028802A092BA7299A291A29B8284A28E827CF289328DA27232CBA2DF32AF7281D29F9277328CB2B182E4B2CD32B672A892B1D2BDC2BD52C972B46298728AB276E2A832C422E0836E32C1128AE279C26402932283329142BA82AAF2B762B582AC828CF25412665253B26DB27932C7E2A2329B6255527112A002A67271B261E2671266126D7265728AC28D3274A28502AA92A3829032BF02A772EA12B122BFD29032A0A2AEC2A112CE12BCE2B172D0B2BFB2C092CB52C3C2B752BE92A522CD62B262C5D2CC62EC736922D1C273526092AEB2A112BFB28442B152BB02CD12CDF2CB0295027A027E6263A261B292C29332C52298724FB263729962A2529A326CC25622698255F242726E02415263128DF271528E229F029C629012CEB29DF297D2A3F2A9029B9298F2CD62B902B2B2A412AC42BD82AB02BE52C4C288628FC2A542A6F2BB22B562E5936F42D6F272D2865288D2B3F2B152A712B552BC02A762B532A652AD4275827E427D025D727DB28022B63298E263A264526232795294329F6275B26CC25EF231F23A024FF266A25AB2679282126EB292729572B4D2A0C29E72675268727FC28722AD82A8B29072B382A262D092BFC2BE3282D28C2275D2B662B262C4E2CA22C11362F2DCA288D2668286028C02A4C29B327FB28312AD82A3628FD250127A5269426A0276527B92884284C2660269B26442791280A2BCF29CF285228C225332551245B23EA23B2239F232625D02517265927122AEB2BAD294227E8251A288429102C952BC1281528492ADF2D002D192C6F29BC27FD27912AD22B4A2CE32C2F2E84376E2E82288826C725BE27A6283D282A297028DD25EC265D258625A023D1255127882595270D270527C925BF26CC258C29912A222B5E2919293529632961295E28AB26B325CE23B023E622D925CF27B629C329C72A4328AD253E26B6269329252BDD2AC5293D2BBB2C592E272CD02A1F29CF27A627142A8F2CB62D1B2EA92CD136362E3D28222500260E273A28EF27C8268F279124FB23DE23A5230E2537286E2A032A0228EC256D259E24AB24CA262027F428612951284E260127282872287028B427CF24772329217F24DD23DD27F8285C2AA82A5B265B249024B727F128EE2BBE2BE52A142B0B2CB12B712A3B2B6D290E2839285F2A182C332D7D2C972DFC35C32F7E298228B0240925E527A228FC27FB261B25852487251124BC244829702B702B3F2A3629A42571259623AC249E272B297B2A142B56276826CD260F2627272A2778259C26A72476258125EE26DB27EC299629A42722279927D32627292A2C522EEB2DEC2A1F2C6F2DC12B2F290F28D8266129052C142C642D382DF22C91345231F428A0267D25E325F327C9282B276C26F324592314240A24422478264C28AF290E2BDB2A2B280B267324E923A3258A26882872276628A0269F25E9253325A12579256B271E281328B527EA266328C029E12866275E28AD2509260C283E29372D6B2DD92C192C662C8D2BF5281D290C287829052D112E6F2D192E7A2B6B34362F362A54286E256F25852772263527372616254B25F22348266F25D626652684285A2A0E2C312A72297926FE253828F424BC276E28F9293428CE261D26D9233E24B9262627172789288E29132975266F2898260C270826342608246725D52A5A2C0E2D0B2C962BA32C712BA729012AB0296529D12AE428EA2A142C762B9534E82F582CD02761279A25DC26D427EA25EC26782332248326BE274C26D2254227C6250428B229E42B0B2AC4283427142845265D26E72619294A2A1E29482504247D24E6263726E225E526CF283D29E42635265B277F264726DE269323B5245E263F2B0F2AB92AD429512A6828CC29E628EA2AFC2755275E292F2AD22BC42B6C331630A12D052B3829A2275427D2268C26DA26462649277228C529EA25E8256026742727288826202ABC299A29DC29232709262C25E326B726052B1E29D029B826A126842690263725DE274828BE28AD273726CE267F283B27C0275823E524922573291A2BB22C6D2B1E2C0C291B2B012B3F299D265F265627782A7D2CC52C103680312F2D252BBA2A492A772AA627DD26AF273028442A262B542A262A6A2934295229C128A4263C287A26D12612282529D42690262F2542256F27D02895271F28E327682560253C2674254A29EB29AF26B628DA294A2A492776274C253B261D2583279729632C112B682CA92B022B002A532A1B27C9265D253A289028DD2AF134EC2E482A482A3B2A9C29A4292E2AF3273129612A202B0D2CDE2B15297F2975286A28AA274227C9258F2421268D27B5273A27E12792252F246325B927AC2787265227A726CD27C62674270F293D2952272727EC286629BE2757262E25C025E62489252E29B92A712ACD2A402A7529E52AD2283D27DD2635269828C7295B2C2436E82CA027D0270428E62747293027E327E22A492B4D2CA02A282AF7278A265A271827EF26C028D3273124B923D4241D26AD26DB284B2686262F25392310262525ED24B92668287B269B2832297F27DD27FD27C4297D29E8296B291627F6244624F025062797287B282B2A492A822A542BD328F72635285E278D29B1295E2BF833352D6A27E424D8266227732692260828BA2AC2294829AF29DE267626AE250A26DF26E6265F27F6270026B5246925B525E3241B28DF27E525F8244625842550259725862569253F271B2820280228AF27882842280D289C27ED277726942441262A26B7255C26F927D629F02BF22BC72D9229DE2885283729A529632A942CF734FD2B8427B3262624BB24F024772421258C276D2832278327A024372511254427CB258E265C28292774277A259E25E0235C24192730268E27C326A024C1241524F924412389245A254D252E259325142501268425FD2426286E272625C52480258F27DF259D265D28B4296F2A292B052A1029EA28AE27642AF12BE02BED2BAF36282E9428DD247D23A323A6230E246E24DC2530268924C2242124E22479267A231C252526A826A328F9296A28672548232F24A825D826A8254C272425512634278226DD24D224A5220D2404248E2354230625C725C225D92626262225D8245826D7261D2749267A26462990281D29412A272712266E280029D42AA42E982D2238E52C9427A924A0230223B623762283256E222724CE2462252225DA26AE26E4246F245A2678256F289627FC26A7258B24312364250F267D259427772668264B26D626C52501258E23A924A3256425FC24B1243726F825E725102593256726E726A027D2263426B024C9265524A525B12445249B25F5268A288F2B402C4B2DDD351E2DEC25C2247B250323232308230B24FF243A248527EC27F1263E2891276626F926272585277029A22972285C276F26802389252726B7261827B42505261124EA258C27BC287026F726C2278328D2266C2772280E258925662847283C2AAF2AF1281D28822744263526622561239D249D2430239825DA26E2275129542BDC33672DAB282925102539255222B123D8232025D2267C261A280F2A4C29BE2692270D278227CE27712965298F284C281F27E424C8246B27BA29D328E8273625F22231262127D6268F25B428D4261B282E261828D7275A2544256427B226492B5529212BF22A7B2A69282F27E6244924892515247A228B241726B4286229462C3C36562EC1271925B8249425B0229B23DF22762414251E26CC256C27D526CF26C825602509268225C92730282828202817286326AD24A72526257928BC2607266723FC220E23B1249524CA222826B3243224F7255B26B623B424DD24B4243A2557272227F626B4286227BA2826274225BD23B4232623A224C925F6266B28182AFD35A52C342743267D2312236D2225239522A324EB23BD239B24F7241828F42898258826C325A226F7279327CE268027342626254E25CA23552411298F289B25F822CF22C123CD214B216220F1229621B823892558267223AC23C924AB23A0243E235B2634275C2731295E290C297C274F271E247523CA237B22C126E627552A3033C02BB226B424CE234923A1230C24B223BB23DC2270238424FF23B224F926D9277726BC24F2243F2642267925562521256025D1239622B42416256327CE24D1236A221722CB22E320182091212122A3220625CC24C72434248C23B4236B2280253B25D523DC25192816299E2695267C26C72440230A2405230C25A526CA276330F52B4B271923D1221222BC21C623A72238236621EF2231212622CC2299244125D525FA23C824D424E4250D235E24D826902556242B239322C324FE249726E32527231022D622DA1FCC205B21AE216A23DE245A26412733249325722370223022FB242924B22217233A25C7257F24852594237D248525192451240E26C32713304C2C13264124BF229B2346239322BE222023C821B2224C217A228321AF22DD22E422ED233F23F9238F229422B8239D24C323782256219D2275232A247525B9252D25DD23ED21A820A7214422C3225823B3239825BC243A26782579233D2118229322EF21A722D622E323C921F7220A243526D723A124A22386231B23BA26FE30F02BE72414235B23332351228122F32390211A22F621282163216E207121682352238B22C0243525532418233A253B24652376233D23B1229022B522462335260626EE25CB2154210E20AE22D72191224523A9240124E324F925FF22BB226322EC2146221F22FB21352207235F244B223124E6259C257A259325D92603286C30C52B3425AC217722F62246226F232A23CF2297234E23E7204221F6209822F722F323C9243A24E023DF240023AC259A22A823B4237D206122E9201422AA22CE25E52592247523622218203C225E2273222125CE24D8212325A424E4234423E7231622AC1FC42298211E20952106216322BA239E2582269A2363265227682A6C33D02BBA25A022CA21DB222E236722D1241B23FF2158212A21F41F0C20132297231423312450266E23232592240C2552230D2419249C217321CC20E9216821AA23D2234222842378218A20602248225521D123D222DD221B223E25912358253222BD2131215D217D209422CF1FCE215E23DA241224DA249C25E6268726192A43356A2CCB25022224239B227223DA22AF24362486224822BC224221CD1F7622B92246246424D824F2226B2531242025AB239922D6238B21B41F39216D237621D521D6217E213E23FF2165202F22B521FB20B8231A24C62132223A22D22141220D22C32282212221FE1FC12191214A22FB23BF23AD24C42374232C269E2ADB2C3637812CB32543243221FC23CE243D23EC239C249C23C1249D22D721D720AB224C215B22AB24A223A222B62324238424D723232323248C22E82018225120FC205A2175204F2144219822D8226421C621A423BF23F922EC220420301F4221B821502374228222CE21EE207722C52145220124F622B0252C24CB22952441291D2CCC34 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 403F ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 0009 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 B027FC21BF21B01F6920CF1FD41E0F1F9F1F191F561EA41DB81D211D161FAE1D881CA21E411E151C1D1EB81D911FDF1D991EC51DFC1ECD1E401EBC1DAB1F491E231DBC1D101DFC1ABD1B751D111D5B1DEC1C7B1E461DE51CEA1D101D401C6B1DD61E541E311EDB1B9A1DFB1C381CB51EFF1C741FDC1E5F1E8B1D5620F221EC2C072B7023202003229021DA1F2A20B220FC20171F1120341F3F1EC11EA61E591E8A1DC21D4B1EC01D2A1E651FA11FB820481ECB1F621E241FB91E631FD31FDF1D171E021F551ED01E2C1D641F4C1D511DA91FFA1E641D5B1D2A1E0020051F2E1E2C1E8C1E271FE51D201F6F1F8B1EB81E531EF41FBF203820E820312187232F2D1B2B6B24DF22B021A8200A207C208721D71F6622D42153210F201F1FA91FA71F9B1F0720641F2D1E671E3E20911F731F7920B7209F1FB51FFE1F821CD31E4120C21FD620721FB51F561E6A1F0D1EF41D9F1E401FFE1DDD1E541FA31CFE1E1D1F6A1F7B1F021FB51D461F9D1FA71F761E961EED1EC121EE1FD120FA20B624892E9F2B4527B123FD207D212F211722E92025200220D61FD01F45206B1FDA20811EC41FBE1F601F3621E41E831F711E2620D31FEE20BA1F4220DA1E2A1ED21CA91E3920EA1FCD206A1E291E041F0A1E661D891EAE1F4A1FEA1F2F1F211FF31F5C200F21811FB41F2B1FC01E011EAD1D9C1E6D1FAE1F7620CD214420E321A723C92D6D2C0126C5210F21ED20B72122210D2145217520742079207D1F201FA120DB1FF81E0220A01F991FA31F581F9921FE1DB41EC921241F411C571FDB1E631E7C1E0520AC20C91FD61D111FD81ECF1DB21F9B1E8020CC1EDE1E9D1F2020BC1EDE1E01202520E420BC1EB61F071F9D1F6E1FAB1F721F4320161FC32085221E23A82C162A622526221423FC1FE5217620A520B521B8204721A821591FA41FF11F4C205520C51F5D1FD4206F1FF81E5B2096208F1EEF1F2F1F081FAB1EE61EB61EA01FA31F0F204E1F6C1DE21FE11DCE1E6A1E291F6A1FD21FCA1FEC1E531F1B1F471F8A20BA20041F841FB51F2D20D71FFD1FCE1EE11FC321D22074202D23DF233E2D732A18231822BB211921F8202D22052182209921CD2003203020B31F0D210721682118202D20BA1F6A214E21C51F21200B1E801E7D1FB81FD11F8B1FE4202E20851F0F20711FEE1E6C1E741E741E251E991F2621F91E261F9A1FD91FB21E231F9820BC1EF81F0F1FA91F441F1B1F9F1FE820181F9D207E1F422114223A229E2DEB2AF1246E22F2225521461F302015211021B721B31F72203F21632242201C205C21B8202021C9212221931F6D2011227A1F681FB01F211F1520E320D41F061FB11F26201620CC1EF31E6D20C3200B1E64210120A71E2E1E0C1FDB1DAE1F661F9C1F871FA81FB21F7020CD1F5D1F1F201320EA1FAF1F5C1F10222D223B24822E6029AD2407238F2194212A203F1F51212A223B21982001200C20C51FB820D51E461FBB201621F120C420581FF81D8620E11E5A205C1E9F1D101EEB1F571FFA1E9B1F6620CC1F5F1F8F1EE11DA41D2F1EDB1FDC1E961FE81D1F21D21F2B1F691FDE1FD81EC52091206521961F891EC71FBD20811FF41FC31F0B20482288228C2E832C8B2359211521592163204921FE209D22CF2010225F21C11FC2200D21A220E0203F20242170206020BA20DF1E6220D71E5821DE20E91E0821A91E771E981FB11FD920A31F2020661E9F1F961F781EC61F9620CC1F8F1F291FE31FFC1EA81F06233620201F3C213421042134215020D120BA21EE203F216720A222D4239830D22AEC263223B321F921E4205D215321AE219C213D23CE214221D21FC6202C214421A220DF203621C51E8B206B1F1F215A1E3D1EA11EA31E8A1F211F641EE71D6920C01FBB1F2220441E311EAF1F4E1E3C1F7C1EF51E181F87203F20EA1F0A21AD20881F6A1FC32071218C1F6A1E8420A020EC1F5720221F4121BF22462351302E2BB924B9215623D920911FD92028200522F7212921C320961FB71F0A201C2141208A2053209422E41F7721CD1ED01EEF1E0B1F951F711F021EA61DDE1E441E101E241F0D1E751E551E151E271F3B1FF61F911EA01FD31F2A206A1FD61E2D20552081209621831FA2210721CF1F4B21B82010208C1FF01FDE1FA620B824FF2E4E2C97266722C0210421D22008212720B821D2201A20F8215C20AE212B213C223C2178206D1F5F21C51F1620A71EAC210B204720A61FE31E651F16201B1F901F4E1EDE1F3120871E651D2A1F3A21871F9C1E4C201F1F821F2F21F020481F2B21911FDE1F5E1EDC1E18201A20BC1FC220E61FA91F1D2252202D211322CB24AC2CE82A1C253E225C22DB222820E520A3213B2293216C204320A91FEE1F6421871F1121DF2019204520FC1F711F6E1F4C20B3208220DE1EA11EB9207B1EFE1DD31C401F4F1F2B1F4B1EDC1ED11E8D20EE1E59217821901F4A1FEB1EF51F2D20EF201921111EDC1E701E8220101EA01D551F2B204D216C210821B12126222924692F922ADC247323B3210F236921B3228420F6223120CF213722E21F2A200A202321B11F1E22C52219202C1FB91E9C1FCE20D820701F4F1ECC1F7C1F421E9F1EB61E2B20C01FDE1F721FFB1EC61E2B1F0F20E31FF920CB203A1F4C1F2720C01ECE1E6B1F11204020791F1021F61F5F1F2120402156200922921FA9203F229123572D1F2C44265322C821142203231D227F22DD2015226E2230219D1FAC21E3219722BE2043221C21662010227022F41F4D20FA1E06205F20A81F6C1F7A1F2B1FA81EA91FF31E771FEA1E031E7E21C91FFD1FE021AC1EEF1E051FA81F411F6C1FF81FE720AA1EA920E61F90215D22991F9221C520AB211C229A22AA21AA2274241D2E202ADD25FC239B2393218E219321A221EC202421FC2209224A215C2106218F216221B520F9207E20D221E11F8B20402169200A212F205E1EEE1F7920F01FCA1FBC1FFC203E21B01F6B1E9D1DAF1EED1FF31FC81F581F262014226020781F6F2039205E1FA0204F1F282017204620781EA72151210122A422E222E522A925362FE82B9E25FD2334214F222423DF2127222F227222FE212522BA21EC215120C220F52067216A220E217F2032219320C220561F482102216A2066206B1FE4204E20E421DF20CC1FFE1EC6206820A61FF71E32201122B520FB1E3E2218205D1F3A1FA721201F7420B61E1521E71FD122402249236C22BD21692221235523F5241731242A52276C22E922E9229B224C23DA21B9211221FD226F200421F8204922AE206B21642336212F231C220D20692131225D1FE02028205220F21F5E1F0E2199201A21F720DC20771EDC206020C320521EBE20F01F2F20BA1F0D1F9C1EDA1E5A1FDB1F36210122221F26216320F91FEC1F7B215A211B214021FC2360239625EA2FAD2C1B2519223222D72138229621E0215B2065207D213122D621BE1FA622A12225228F1FF82166222C20F31FD51F0A2005215420371EA01D6022B91F5D21781FC620E02179205E20C21FE91FD51EBC1F502065206E1F281F0421561FC21FCB2000229D20A42055216622971FEB1F8F22D821CA214B22D121DF2284241225352FD92BE425EC2314235E223D22CE203221A6212B224623D3214F205A20A920C42191205E2384214620562020223421AA204C21BB1F3820BD1FF31F082135217C223022862222214F21A41F281FC2211F1F7E2176216021FE205A1F2A21E51F70200021741FDD1F7A20BD22B92125227F25A922CB22B924AD21FC235A24D3243A2F8C2B20259D243D22AD21F321F021FB21D72298227D206222E821BD220F2196216C22542005232021BF216721EE215E21F41F8E209D1E2B1F152187209422A921C82226234122CC219E2142219B2040218422242289203C21FA202D21D61F42208F20332129202821DA22D521D72213220122E123AD228724D1242B2485256C2F672BEF24702269232723FD228422A221D8221B22CA229722F2216F20F6227321A021E7206B21731FB91F4C209D207120EE1F0220181FBF1F8620861F4E21FE21A520FB21E221C221FA202C24DF2270218023CA224E221921D2218A2130210122C6219E2120239721692395246323EE22C422F521D8226B234023AF2389243D30852BC8243823AD228B22A720A9218D2233212F2030214322981F422137233B2157213622F1209B21D320FF20062278229421FE1FD81E9A200921DB1F3D2144218A21A7221321A51FE4227123C223A223F7239E220D24BA2214234D22CF2171238F2000217B214521D3229F21D122EC23F42327220623042329241E2338260D31092C96247121F2216F22D42105216C213F23CE21A92355221A210B214120E020B12041219A21F1230D218D204F221C222A21E020B22053208D1F0620B11F0521012139222F2240231D23CC228824C7227E2297226A237923A4249A22BF2278228D23B5209E206A216821C521F7214825D82492233424472403264C26FC25F9307D2B0E257B228023F1216622C0228222E22294218A22892270212322D7222E222F23D420772213228C22A8239A2182221A2234222222782020222C211A228721B222C2220524F023F8227C2433243422072456235222F3218125AE232623912423226E21CD2137203C2398227A244C26082773257325E12402263C259028C032772C04268C22A721EC220423F42227233A23AA221D2408247022752332232523BE230224B321A223C6224822EA21E7232122B721F0229F205E21A52180220921EB22AF23F6252B246B26C924F6249C24A22225247823FA236025D326F3247625A1225321302252228523D4223025092702285F281829EE28DA26DD26CE27A832572C4C2705226723CB222723BD23D524682499237C25F4237427ED243F25152502248124D3235324F92221232123B2231123C9216120DD20C8206121BF21C8224224CC25AB262F251D2792250126D523F123D3232824DC25622645279924912380242322BE217C23BC233F241126C127072ACA2A192C292BEF29F3272729B4330F2DD725962438242123202293233E248325E524C223BF25A025B9277526132721261824CB2476231A232623A0225222C721B8227220CB1F1821052233218F239B25BD274229F727FA271027D623CC234A252E25AB26F426C728A92553253225D0239A233D22E12358247B25BF264E2A842B5D2D7A2C212A9E28BE283928EA31912D992673217F21BA217424842301246725D623DC266225192677254A268E26F9253124EE237C25F021EE227021DA2313216E21FA212B21B52179214122DB23A8253E28312ABB2AF3281727B924A52490267E275C290A27AB2745261D25C52409259E250B26A325BB2540267826EA270B29632AC62BCE282A27A9270A28A233652C4825B6221A22ED230A2377233225E5242D2785248B264225BB2589245A22B022C022CD232823A2211821762325230B2253229423AC21DA22512392233724F9256829642BA12A80287B244224902457268B2AD7271927C2264226102443240C25AC28A228EA25312857285C29052A352901285E27FB25F42767287429DC33002C9B27182339249B241C2213236723AC263B28122A6729BA26342636270A26FE2230232523D12305210422CA2171217E228624702424244025612320254925EB29192BFC2BBB285E26D625EC24D8234227732A4F2976285427CD258D25C524972788298929EE29E828FD262D2771273627CE274C258E258A257B29F12BD734812C1B25CB226A224223AA23BE254C259725C027962802280D285726FA2411248E23E12145241F23DF221F233F227421CF229C25992614276A26FC258124D6263C29A32B902AE22724244425782429264629582C2E2B7B2986281126FB25D724AE28ED29C32A8E292B2A3228E9254C25CB25F02488252E246C260C29032BD434902CBE263823D523EA22CB248423D82482268326E0255E26BE259225D024B92351224B247A23C923D724E62284240923CC230326C127E625F62679279425D826062A652AD8277924CE24D32294249526FE2A292DE429092AEF28042647256526A028DF2A972B722A63283324E822A722AC249624AD22102439276829CF2AE435922CD5258B22B3230E250023A424CE2350268825AE255E2511263D2497249323082408250226C92692287726D024B425F3241B263E2976271826F225C3259A26EB2610289B249922D6239F244926F726B72AE02C7C2B242B08289426BE27BC267C2A712BE629CB27BC255D2557238223B52271238A24DA241B27772A062CA635882A6E24E32369222024E623E4238723AC249125C92638277A252B2482237E2323269D26E726BD2943285B274427602590237D259027E32482247B244223A924F92329247B255921F620042691283528EE29EC2DD32C78294D28292767262A29622A692B262B6F2A9428BC242D21B82123220A232924A324F226832AEA2BB1361F2C4F252124322454247C23B42309260C27DE28302A60280F2653230F2418250E27062ACD2A252CD62A9F296C27A0264F24E6230F27A6246223272491225824F123502548247E219C2115266728BF29162DD82CEB2B1E29B327B5235B253627C52BC229752B1C2B69285A25D423B1234123E723E625BE26CD297A2BD12B28355E2C9B2627245424B62581268A28272AB72BAE2BB72B44289F24A526E3247F253429DE2AC72B4E2B032B6427BD26DA25B92398220424A5238F2343233924E326F226AA27F8263C243C24DB25B529CC2AE62CA82B912CE828B52519253C2545260C29D52AA72AA729842AE626682575240B24D322A026BD27D8293E2CCB2C7A35022D7C2668246125472605271B2883291A2EB12A9B2ABF297827C5257226C0262B2B8C2B6A2A5F2A5C2876275227C4233224C4228F21272387222524ED26E3276C29072BF52A93262825EC268028622A2E2C622A492AEE27A925CB231225FB27E928CA289B28A7282C28CE26B9244724EB22DC22DB250125AD29442B832B7F32EC2D96272126362644268827FF28732A272C2C2CA62C432B0528F82428250D272F296D2BC429C228E0286926C425E1256723D022DE22F123022516262629AF29D62BDE2B032BBE283227C0279F28E429232CB62BAB29242652268324A225D426A827722723289D27B5270625E42339247C242524CC264827E8283029EA292E332A2EC22ABC286C29442AE42A782B592C7B2E902D602BE42974283427B0263227552AA22A11272529B927A327C22670247F23CC23DD22E424B3287C277C29772BAC2B0E2B732ADC278225B32693260529042BC52ABF2871254E24A7248A26C9270926F226FB2617279C276F263625D724E32331242625482679277427A02A4E33B42FE2290828A829B328B429922BF22C432D922C722C3E2B7527662479251526A3274D28D028A7283B2906293F288D26C92426236124AA25E7270729CE28BA290529372AF92A62259F23BA246526B4261E2714272127EC25BD259A24BD24E12461277327B926AE27F32878272A273D262025A32460270927092AA22BB22B5A326B302D2B672B0C2AC12C9028312B452D652C5B2C722BD529C626D523F82564261D285828BE290D2AD62A322A38288B2628251A25582602298529302972287D27F6272B286E299A260624E722E323CA241E2632252C2666235B243824EC24AE25CC277329092A762A872B122B692AC0297627E2262328D92AC92B192ABB2C7834A12E222A9829272A7A2A0D2B99294E2BDF2B222CD32A13287224CA241024E1253D26E528B629F729092809288C272926E1239328E1282227652811265525AA27EC27DA28F027B02306229F218723E32202246B24362480234D24FB233B25B4286028AE28DA29B82A2C2BBB2A8C294D29FC277C26CA273F27E1270F2A0D2D39352D2FF42A1F2A0A2A002BD92A0B280528992B1B2B4429B8261C2351238A269A271D275E2974297E2A332C6D2ACC287326E624BE253E274628BC269825C2259125BA26B4289027EA2237228C22102212249F2467272F26B1267C2318257C26C828E22AA42B632CB32B392C4328EA26EE268F25C025D826F52651297F2A542B6B34F12FB92B5C2A502A322A91289E278D282E29602ADD2777251F258C26272851287728B2297E2B5A2DC92A052A98289C25B1268126062716270B269E223B250126B5283429532866243C220F21B5234A24B7255B284A2758276027DE24D228AA2A892B6C2B902BE929CE2BF7280B26E32529250F25FB26B6258B27562A8D2A6F338431872E992CA22AE12AA029952812277E27B9255E2579231F24D626A629E42ADF2AD82C352A1A2C172B1B28E525E825FA24E2251E2643277A264125A8267228AD29F528BD274C25B822D3229525CB241B275828422A192AD4261628EB28AA297F29D12BCF29D229252AFF261D24F1254C248523C425A724AC256426A8274332B0324D2EDC2D572DB32A262A23275F267F26B725C6238824202562281A2A9F2B012C762BFA2BC72C7C2ADE2706272C25DA2327256F26E926D426B8275B27D227FC28C72741271024E92238245B24C825ED279C2A622A97291129FB263F278828E428DA2A322A4E28BB261F25252553245E238E24B0258925B8255726AC27FB313B33512F8E2DE32C922B342A4C27D123F9232F247225B7249E252F28AD2AAD299C2CB329C22BD32A192860273E257E264526B4258D252027B928BA26802764278127F225B7262523FA22A7223124CF24D4263D29EC27F12632271E262225BF261D271325B8251F24C824322455237825EB256F250025682597274828272A59324732BE2E1D2DCC2C642C5629DA2460247925662414243E2614273A293E2B972C612AE62AFF2A942B70293126D2240A24972651298B2A412BBF29E6280E2956285027DA25E1240524DC226E23DA236F25C7258E270C27AA24FC2537274526DC25DE233F26DE2380241E24D72472250027AB28222AEF29E127E3280229422AEE334D324B2D112CBC29E729CA280F28AC25D924A32370255E27E629062AAC2ACC288929852CA929372A3B26A6253B25F42669256527852AA22AD029FB2A412AD127DC24C824D92349233E237D22D3237925962729262127F027E828852A3E29F9285427E9265A24EE231A2607274028482AF42A582A932A60294F2BF9277E29A2317A31232D342B5429BC270B27ED252D24552527250F2775279328E32964297627C925ED25C5252528B4248B24FD2652286C2619293D2940292F2A3127FC26A02541251826AB233F236223F3243C258B2539278F287628712895297C2AEF294928D8269B256025A824B129842A932AAA2A722A282A9F2842261327E32771270A319C31CB2CCF2D4B2AE729C32791250E235325F426D127CD29A22CC72ABC2AA928C3266827122516270B278A266428D9279528CB2553273A26CD26722451255824D924BC26AC269026C3275A279928BD289E281829CF275A29BF2C872B252AD128B22573257E251A2821295B2AE42B9D2AF927A9261229F22719298C276F2744335B341A2DD92C7D2A532931268C246A2548248B243F28A229722AA22AF12AE42B8D28CB287E28A4273925AD275F29E829B2272626CE242925662417251026BA256D284729C929C529D628502994297E299A2ADE2996287A2A4C2BED2BF9284927C8265B245B253B297B2C5F2AEF2A2B2BD127BF25C3288028E8292729A72869323E32AE2D992AA52A91290C27B02495242F23342591289C2BEE28612A67293A29A528732746276426842806276629FC2889257125FF271E25F326B8270E274827AE29512B4B2BE62B092A9228EA28D028EE29AF2A13295229422ACB2B4D299827CB2692254D27362A4E2CDE2AA528EF27C32679273A2BB32A222A812955288730D6319B2BB32AE8289A25D2265C242F2523264C25C9275F29822A5D272127E725CF2880270826DC270D27B328BA276B288A260227A426A72845286929272A5A29792BC12E372C1C2DF52AC92906284428B829602AC0275D2769289A29E72853267B2582260D2AF429AF2DEC2B2929E529F9284329B62D732B5529D629832BE933962ECC28D826CD26BD24E52480240626BE23FD22602682241F267E251F27AB26B927122680240E2576270D25062865272129182A64298F27702662260B284129102BD52EC32D512DCD2B3929B02AAE298929822A1D283526052719270F262925D724A925A6281F2A0B2B082BAA2B71297D26A025992AA0295F2A4229EE2A07342A2E5226CB25DD250427CC249F265F24B8243E250825E3230F25E2258927482626263525CE2324256325AE2604278E282629152AF02A4E28EB24AA2321251527002B932DB22D742C092B4E288D281027752829282627B9239B2502247E247E256A26AF28302BFE29BA2B602A822ADB2883266E28082AF129282CBF2AC22BEB33392DB4277E27DD27ED2787287827BD268F26CB253626EA254928802747290A28092612255E25872649271D28F5292E2A9429CD29FD2A5A270926E823A225D326C628E52B2F2E4D2B792AA2292327F2248C25BC24F523F423482399235B256826BA28FB2A342D9E2BCA2CA42B752C892B5527DE286127242799297C2A4F2CBB36BF2D4129352BC82BF92B9B2B9329712803277625F5256025E8270A2AA42BCB286B271C275A26B927DC271F29FB28472AAA2C3F2A5C27F7231E24DC2455247127A428B72B082B042A05288B2672256524AE24A722D12445237723D823772499289B2AD12AF62CDB2AF62CAD2B4D298A2A732800263B250A2663272D2A762C9635B12FA62B0D2DE52D1B2DEE2C512A462A29287F26342752277B29EB29F92A1A2DEA2B1D2BB02AFF29022AF92B622B782CDF2A1B296C2774266E2452270B257A25FA27B82A592A5D28DC25E6243E24AB23F224A6257E24A825C82324245A279429202C652B402B302BE52C6E2BA52A4229C127F325F925F724B028822BAF2D6636EF2EED2C512CDA2CB92BFA2A102BB629B128E725EA267E26DE29D02B292D992BC22C402C2A2C902B5D291C2B332BBA2A6C293C283826B2262A27F727AF26E125AA269027D8286A284F253424FE25CE24AB26B72696278B27C52793250F260B28802B702C132C30298029342888281629612740265E27BD283A2B302BD02D88357F2E262CB82D792A472B582B082AF326CC25B325752620275028902B022CD22D122C552C222B7D2CCA28062AAA28E4274426A42717262B273529EB2999274E25FF23E7247F2857254625E7247226DD25ED289D29D9287A27F7293A27B826FD28F72ADB2A43286027D126FF26952885291E298E25F9292A28D829FA2DA92D4335D72FF8284929D128D029162CC8289C267E26162544271A28A128052A732C232ADE2CCA2CCA2B782A362CD42A44270C27B5269B25652855289428B8275F279225AC259326D326BD26492586250828F8277A2ADE2C6B2B662A102B442B5C297C2A9429252AF326792551276A261B28C32CB62A5E28DC286B28F528BF2C5C2BA336252E1A2982252F26D827AE26252790250E26F426F226CB276A272428F828A42A0F2AE92A052B4B2C392B612B4529A8250D25DD27A6274F28A228D9266525AC25A6264F2747270E264E2679274727092A912D3B2CB42CA62A732C702A632A0C2A462ABC26E8258F27A828D0270B28B22AAC2AE32A1D28EE27FF27ED2A372D7536E02CDB286026B62736268A2719285526EC25F424E02A6529F52B67292629CB277729A8297A2B082B8429A128B124AE26C2269B27A228A0262D27592631249B25DD27552954281F276E29B82893276928562AAB2BFC2AC029032A3D2A752AA9280729D9271827AE263D2889293729932A0528E326352781284629052A952CAA35552C83290928AC27C42ABD2AB0279C274F25A527E529812ABC2CEB2A0D2BCB29532A9B2B352BD12BA9289E25412682261026E12646265626C225F624792572273929342A492B9B2934284129A2294B28EB27A22A4E270927352AEA2A032A062936262C268527C426332B942AC72AF0290F281827F0276928AA28FC2AD22BD234E42E972B942B022C3A2C262C3E290E2944277B28642B062E422B842B652A3E2A692B642B302A8F2B1729622568271A268E272D291729B5244F24EA258626D1275C2BAE2BBA29DC2819297C2A1E2B562BEB2A622A102A9729192959283F29F926EE267C2807289828732953294C2BD728AF27BE287C2B3D2AF52896284D29CE309F302D2CA42B392A852BD22C7A2A992863286C298F2B002BD32B7E2B7A2ABC2A042A382BD229422ACF2830277227FD294D2982292728802544254825CE26AF271A2CDF2B05298928B6285C28522A7729EA2A5A2C322AC32B312AF7277829FA299929102A4C289A29DA2801293827F426F427B729492ADE2A982AB3272826A92FC12F502BC22928290D2B092C982983264629A72A0A2DEC2C592BBC2ACA2B9F287529462C622939279E26D6266F296C2B992BD72A432A142611259525FD26012AA92C9F2C7A2B40272528182A772A3C28CB29642AE0291C284829CD28B528822BF82ADD291A2A7928B9272D259525402805284E2A172A5029F2278F260427162F082FE329EE29C62AA22A7F2A81281928442A992CA12B872D64299028352A1F2A052C422ACB28CE2680266B28D129702B1E2B832AC6296A267A267425B626B627D32A442A462A6127B427122801284226092851277B27C92525282D271C29F32A052A0B28A3262825EA25BC240327C9279F285A29EF275727FF25DC25A42612311931BC293829812ACA2BE22A7B2730287B2BE82CF52BD82CBE299629222A1B2C072B852A2A29B92617283B282F2A952BAE2ACF29A6281C27BC269E275226C327BE2A8429932AAC265226E926E4252D2514258A2658247E258F2541299B28232815288624AE255A250024D52464267B298C2B432A0E29D627762876262628EF32982E33289B26E727BA293529BD2827297F2AC02BF82C8D2BC32ADC288829D22B3729582740282029F428112813279328E6276828B126282697278F27A628CB2A542A3B2ACA291827C426C8244E248D24692664253F27BA26FF27D3261728C526EA25B3243624C6241B259B26FC28562C552B232B2B2B0D2A632B362A932AD934A52E7D29E2268A29DC29522874290F2AAE2B382C702B7D2B8D2A162C8F2BF72AD8296F296829A32AA629382D8A2A122BEE284B291626B525B9271E293D2834282928EF27112A9928C22568262F269E26AC27F2281F2A4B2A3B2AE3287327DB27D727B126322727279B288928D02A8E2C572D202D202D3B2B9D2C372C3D2C1436D1306E2A542A182CFB2A8B28F5271628562B242CD22C802B132CCA2D8C2B672CA02AD2282E29072C302BEA2A5A2D0A2EC32A27289124B7245E2633255F27602715282D29322C702ADF28D82714270828BA292C2BB12A67296D2B8629E526DA274428952A052A6328192BD22ADA2DC02CF52B6E2ED62E0C2DF62C3C2C302C61340F30EE296A293329942AAB27C6240A27862A042CA22C7A2B182CA92C1A2D332B3829E328D5291A2D072B7A2BD02B942C43282827FA24D923EF261B26072706275E272829BF2A8C2B9229CC2837296A290D2AC32CE9297029EA29FE28B92849280B2A6C2A782B82293D2C702C0B2C202D072BF32CA42E0C2C692B1A2B662BF23206300B2BA027CD266F2774261D260B29542B9D2C8B2C472C6F2B912BCD291E2A79272E283729622AD12B172D952C402A262956264025CB254E271D2997272C28EA29F328512BF02AFC29B729A42A772A7E2C992CFA29AB2A5B2985271D2A592CBB2C522B232BF12C232D622C2F2BE12C7D2B1F2C822CD62DF22AF129972A6732A9307C292D27C4252D2633278D27B0275F2BB32C032EE62CC22B2A2C972ACD291A2955281D2AEC2AE32B162C422B402AE12713273D27E1264629D4293C2C3F2BE82A1A2AF429BA29CB29092B812AE5282B2B0A2B0E2A522943298A2AD82AFD2B762A952BD32D7F2B7B2D762CC42859295F287E2A292C382A452B332C202B6833B72E1029E825BA25C5265328F329F629AF29922CAE2B9A2CE42B122BEB2803285A280228C928E329762B072D492B8629F6270C287627D9268729332A572AF427752718296C2A442AA6291C2B70270929672A492AC426FA26292AD72BBA2B452BD32ABC2BFE292F2CB82B4C2B762810277626CC28D2292A2BF62C9E2C1A2C1734A82F4D28F92605260828D52AB32A062DC82CB62B672C252C1E2C092AD127842A4328B429232B1B2B4F2BCF29322A0D28D824BE267927A7295D2BDE296B2A1829B9285F29512A252B792A3C28E5265D27162887289226D728792B452E3F2EF92B6C2A552AF829612BF92C9A2A1D2AF3297928D4273C287B29822BE22CC62D8036F52E8228C124CA253827242888296D2B1A2B962C5F2C382B3E2872278526A72B122B332A61298F2941297F28C726C1271424ED279D29C02ACB2B5A2B752892281F29B42ACD2BBF2C442BD129AF281F26CD25E2263627EB291B2D582CDD2C2F2CB52A322B9729A52AA52BA7292B2B6D2957287D29712AB528D82AC92BC62EF8350830C929C525F7240E26BA272C280A2A342CD02C1F2C7D2BA02934270729082A4B292A29AC29B52A452B082A0129BB26EB27D529FB2A352C772D3D2B7B293F2BAC2A04291329322A1F2BC029A228FC243326E325EC270E297A2CB62CFB2A862C572CB12BC02ACB2A162ADF29E929122BC32A5F2A402C602CB52D1E2E402FC8370D30692A13280F2548259A27B2278329002B242C962BFE296C2870274A2A0D2BF42A1D2AE02A552B0B2C07298026712614262B294E2B7A2AE82C612B7B2CDE2998295528B3291B2A6F2A81292129EA258425D426C8274527EC2D9A2B782B222B862BA72DEC2B2E294528E1264A286F293F2AF02B362CD02C7F2C692D952E1436E230912B7527FB25512627271F29E629E12BA12CBC2AD72855273B28392AED2B81291A2AEF29842CA42C5228A02642263628C7298E2B4A29AD2A4E2B752C282BBC28EA27D828ED29492AD228B429C5260526F6273D276A2ACC2B362C5C2B472B562B502C4F2A2B287E26F026EC28062BA32B322CA62AF629502C002DDB2DC235F032E12AE6290F282D255F256D261A2AE02A512CA12A812807279429112C3B2B822ACE285B2AF12B0E2B3B279B26D926F329712A952A972702291C287B28AD281028CF276026B428DB281A296B2859297C2B7229C02A362AC72CB02B1D2AFF2A9B29162A64271626C3267D261E2A322CDA2CC82B9929F427342B7E2B642D51372531792CF428172668241F24B5248427A2290E2A2F2A7D26BD29312B202BA22C992A9A29E7285C2A81274B25DC26D727E9293B2BB32AB12A2929F92743299829BE287A287D275926A9275227D7283729FF29F22A602B9A293F2D9C2A7D2CCD2B94291B292D26DB245227B7288F2AC72C0F2C512BDE2C3229BF29FC2A002D6B341B32CC2B5229E8267326A4264C2565296A2AA02B912B762AA22AE32BDC2B8E2D422C5A291A29DE2766265226EF26F728292A622C5A2B872CD32B6A2B432B122B892B5F2B0A2BEE27A3257629CC2C592A6A2B542D7B2C202BBF2A5F297429E9298E2BE029BE2808291B2A132B372C722E902C6C2BC52B072B802B842D752DF234CF2E962A0E27F92644271928762642271E28792A342DCC2BD72BEB292E2CB42B332C772976282B262425F0241828062A782AB82BF928C829502A5D2A1D2B942ABB29632B1F2BE52A672A3D2B6E2B302B582C382C9029A32923294C29552A762A7B2C6329542A892AE62A4C2CF12A242B6D2CAB2B402B4D2A562C542C052B3C357930B2292D283628E12A0B2A9E28342655282D29FF2A6D2C6E2C1E2CC32B7B2CDB29252AAE26FF2515250C2408292B2964293C2AF629822ABB2AA32B3E290B280B292D2BA12BA82A2D2A0C2CCF2DED29502C312BDC2A2B2BD32AED28832A212ADA2B112AF42AAB2A712DD02CEA2A872A002BB72AB32A3A2A5B2AA22A3A2BA5337130ED2A2629F629D22BBF2BEB2995284F2805299129462A692BA72CBD2BD82B012A9C27B4253025D7248924D5273629572A472C55290C2A232CFF2BAC29C7280F29CC291C2A3B287D2724286029F029492AC32A902B4B280029982A462AE12BD72A6B29742A4828C22ACD2C5B2B112C8D2A7C2BA62AFE27AA28E528C5288233CD30E62B4329322A6C2C752B3328EF27F228C9279D29342AA029452A902C812A5C27DA27E2269825BF2524269328492B822A5C2C732CD92B742EF02B3E2BD52A072A5F299F28F6232A257125CF2508258727882784274427172950281E2B632BC1283827E8276329512C0B29182A542C1A2D0A2C4E2B562A7C291628902ADB357831852A372AD52A1F2D6F2CC22A7E29EF2739290C28F0277F252D2733296C28CF27682814271928D2258B24E025AF292D2B3F2B5C2BA92C102CF72CFF2A5D28AF283E27462421227F2460249E246B2549253F285A26C0250F27EC27B52AFE291A280426A5252E28452B282BA82CBC2D272E922D8B2C562A00295728E729C534B22F362AD32B5B2B782CE82A582A382AEA286A29422A4928E324DF248125B3273D287929392AD62A6E28F5256D27042B212BF92B592AE929542A19281628AB273326E524BB25B2258E26DE25D525EC26B3243629E3274426E228A82830277C2573258F27B82AD029132C562C6E2DF92CB52CA62C902B3C2A9D2A1A2B4E2D5536D62FEB298829922C262C022C532BC529E529A729892890276B250325BD2631290F2A3B2A6A2CD82A78298C264E273F28AE29EE29AC290228D527B526F8264228C326B22736280E257B288D2799288B274B2628287E28E429072B992AFD29C8269A26EF292A2C7A2C642B2F2B222B2B2C0C2B042CCE2B2229FB287A29AB2A0733DE2F02295528EA29E32B3D2BAB2CFB284C2811294028BB268724B3246A282F2A7A2ACD2BCB2AEC2BF0284A2734282E285427432884272C2931286B26C127AD283E290329292993274B2971295D2BF9297428CC2767279028262B1C29F428352731287E29042CB92AEA2C232A7B29AA2B072B1D2A0B2A69299427DE28F32A0932EE2F0C2C602B6F2CCE2CC82AB42C7E28AE28E62739242725C42669262727462A342B522CB02BB62BEC2ADB28A827CD2899282129D029392A9F29DF2A2D2A532AC32A942B092B2128D929C42A462A8528B8297729F327C927BA280F280A298227CB28EC29F12A702D482C362A0C2AE4292F2AF52AAA2A0D2911295529452A5E34AF30402D272C472B182C0A2A9E29E5277F257925922560269A271128CB28BE294B2A612A4B2D032B022CC92A2F2BEE29A9282D2B9F2879294F2BF12CF12AD02BCF2B8B2DD52B1827D4276927EC2A85270B275828E1272227AF295C2A7D28B0278127E92ACB2D3A2B3B2DB22B4F2C092C2B2D50298F2AC32B822CDB2D8F2CC93550319E2DD62A722B0B2B03290D2774277026AF243D269A2818286B296A2B632A2B289929A02ABD2AA9290E2A002A7429BA2A222D6E2BF92AE02C612D982CE72B312AD32AAA2A28284927D129892B072962288C283E28502AF2299927C2279327372BC82A162C2D2B7F2AAF29582BE92B4129442B122B9C2A492C362DF62DC0340831622D362ABB2AE42A2E2B72285A28DE260B25AB24A927D0299C2BEC2B862CF129B5291B29252AFF28E7280B2C0C2B1D2CEC2BE62B552CE52BFE2C382C7C2BEF28ED286929392AAA2A5D2B6D2C962C2A2AD728D7280C2A422AE4281F289D28D42B502CD82BF02C3F2B472A602AF72A712B8E2AE529FB29402B232CF12CE83305358D2CF8281429442BC82A752B182997263028F625B627D4287429922CE22BE72A1A2C80272227B62679278F28F829172AA72B8F2B7C29502BF72BAB2B7D2B8728F0254D26C328E729BD2BD62B082BA62A212AF8287428C52AD529712A662BB62BAA2A512B6E2A772C9C2ADF2A612C8D2A802AD728FC26522A922BCD2BA1350934BB2E92298629E7289D2B772B272B992908280B28B8276329BA2C4F2C0C2DFE2B312C83297527F2243A270929AB287E292B2C0C2B672AD02CC32AD42CB428E32744250526E9293E2912299B29A52841283A27392617275229AF2ADA2AC72B4B2CEE2A142A142BCC2BCB2A542B762C602A8F2A362898272D29C82AC42DE1355232012CA82936260C27D429D12A282B6928C9265026E4274B29D42AB52C612D6B2B5E2CD9292728F0261F27AC27A328742B132A7029D12887288229642A57290E28532657266F26DC268829FD275B256126912770253F276728CA29B12C532CA029592869281A2A4F295E284127452A9F2A3928B0265E267E25EE28DA2B01345631AD2C442991281129092AD12A0C2DA92AD528D225D127F029F0291A2BEA2ABA2A672A642ACA282126A32727287B2ABD291D2A4127B1255227C727A027022B852AF326B22637261827D72803299526752897295B271B25AF27AD28882A4A2BE52B042A04290F29A128C9275E27F128872A1D29702745265A27C9279528ED329231312CB729052AAB27922AB02B532BC52A672ADE29BA2AC92B9E285128C127F028982A7E2ADD284828EA27672BEC2B8E2B4F2B81272227642699268426BF279F2A6E2B2528FE266E28042AEA2898271D2B2A2A912A3728E129732D022DAA2C2E2EB22C722DFA2A362B84294329042C5C2B742AAB28F826F529B92B542BBD340431442DD82A96271B272F27442B592A4528C127B628512AC829F82A372AF1298229AE29132A71298928FE29E72BA12CD62C2C2C2A2AED298928C225AD26ED274C2B7F2C9D290B27A627752AEC2A8A2ACB2CAD2CA62A1729E7292E2C162D7B2B2A2E842D8D2B472BCC2B952A9C27302A1C2B0B2CC82AF7294C2C5D2CC02D6136512FD42ADD290A29BE27EB287C29C727DD261E289D28742B842CBD2BA52A382A75290D2C912AFF274D26D127682ED22C59295029D52A012A5E2A9229412899292C2B6A2B002A5B26CD25BF27312AB92A852C922A052A642AA3297229E72B792C532D4D2D972D042AB92AD6286E28672BE92B9A2D182D0B2C292C212DB42DF13417305E2AD3280B280228A628B929DC276D28AE284529232CBF2B232DCC2CF02BC12B332BC12BCE28BA28B328082A592A102A6E2ACB29F32C8E2B9A2A012A102BF22A592CC52AE3256D2686272D29662B602C772B1C29422858276F282B29682DFD2D6A2D452D792C702AB028EB27102B212DBB2C812C2B2C092CD62B2B2CBB35FA2FD1297D27A227EC2629273B283F28AE265F26B828422A5B2A732CB92C082BA82B692BDF2D652ADE27DA27BE299C2A13287F267D28E028C9261F27AE276F28022A702BF12831268B248C272C288C2A412C2F2B4A2A68295C28D928602C042DC82C4B2C482D6E2B8E2BAA283B2812291C2B1E2DDA2C862BD529F62B5E2BE234B92FAA2A6D27EA23452694272327F626FA26EF27FF28F82A192A8129712BCB2CC22B2B2D3E2D7A2AAC28E62AD52A272CC9290A275A2518267F25A525D2256B271E2AF42909291E26DA22F123DB262029492C552C882B272A7529E9278B2A852C622CBB2C0D2B1D2A672A3B2A7B2702289E29892DEA2B662A672C382B1B2D6C34C730762B6128642658253A257426B1245D25A1260328A029CF2AB12A982BF52BB32A7A2A032C742A142977294D2A6A2AE4287D27DC255E25DE268E25F825802503277B27EB2633254024C824F925CE251F28292BB42BDB29B42997276028272A322DCB2B4C2C43295F2ACF28C326D127FD28B02CBC2D6F2C3C2CD02C732DFA330832122DDF2B9828D92754252824752504245226EF27272A0D2BF2292D293F297E29CD2AA02B642A32278426132A412AF927FB257B2578251B28B62771273328CE266F2685264225FC257925D824432457263729942809281627B826AF270028042A5D2BDF2BE22AAF2AAA28FC28C329C62A752B552C962A122C412DC12BD034DA30C42BB32CFC291328A9252B24752357240D25F72523289F28012A7D29C6276927C4284E277627C7245D25DF264426BD27FD25B024BE25F627EE299429F928B027F025D625F825A8256F25FB243326C0266B281627B426C8285E287826BF26D4265729782BF72A402BA0299428C729142CE82AAE2A872BC32BD02CAF2CC83532309A2C0A2D3A2B9E2AAD270A253C23F52424247125DB27BF289D28A628FA281528ED2754267A275425DA24C32788279328492917276526EE28BE289328422735288027D924A623E123992587256C280B2B4E2938288F26032A452BCF28BB27CA25DD26FC288529C62B352B1E281C2A272DAB2A202CCB2A9E2CB62DE22D78352A2E122B032AB92BCC2AD327BB268625A32402247D256C25B026E5265627B529EB29402AA829392817266026D426EF282D298E29152A3E2A2F2B3A2BDD2AD02A342B4D2AD4275C24AF239F25BA267B27002C3B2DAC2963277729002A6F29A9295A29F6271228E8276D29A3287428502A622C612C6F2CC42BA62C7F2CE92D9335152FE02AB32B2529F0290C28EF282728FF244424A3241A256B2500263D29972A262B282A732C7C28ED276026BE274228CE276028602A552B782A2529B6281C2A312B9629EF261A26CC24DB233227A127022D6A2B8C29A4277427CB289329E329C9289928542A6D286D288C26F726A326252AEC2CD82E792D532C712B702DC0359630812BD32A162C042A962941288D290127E5257825D026BA2521274B2B132D7E2B262B02287D290429DC26B729BE29DA284C2854285229282A2B29F62788299C28C626CC25FB23F3231B266D250D26AA29BB2942295829BC286D27AB27F92AE02A692BA92A8829D3284E265426432810266928B22ADB29F82A722BAA2D03367331702C572D892A5E2B292AFC299F2A29283D244924B4241427F127942A402D682A0B2A37288828CE28D328A929E4271B2575270228C12872280D28A326A4260E27B227402412243B269724BB2729268F281228A127FC26772783272828432A722B4F2ADD2BC72A782CFC28C828252745277326A628D527282A512C122DC9364330542D4A2B0F2BDD27F6297A2AA6287727EE2593259A239B24D027B8287829CF2A5F29A528CA272F27B8294E2BA7291D283227CE260E28D4280226832600260D24B923A122DF22B2251C273C27262787287228172735262A27DC28E429FB2C5D2D6E293C281C29C02C462CEA2BDC2AB7290228FE26A4269E282F2B452E57374E31EE2B402A3B277B26C8275629C32A3E28182494249D2311241F2305265628702750298528D1270328CF2AA82A7F2C83293527F9243527A82837282E28DE26E024AB230522952362249428F0290D2BF028D928C32647251D26D625F8285E2B682B29294628C428652BEC2A5B2BE82B372BA428E426EE26CE28AC2AD32B1F36A12F882ADB27092654264127492835279127472497232A23EB222C239325AC285A292D29AE272B274A27F428CC2B712A51288C253124512407277F28BE27FF259F240021EE20392002252525BA28C729A22A512B7127E324A0248D26ED267B2A992BA8296A28AD271E27D526DC29E32B9D2B842A1929ED274928C1284A2B1C36422FAE29BF28F424C824E326402778276B27F82538259A255E237722002587266027922820294127B12720270E29E42AEB292A281F279224AD269128ED26EA25622360210D239C223E246D240A26542794298D2A7F29062A95294B2653260D29AD2BC62CE5296B2ADB2AE5285027F928F0293A2B4C2B2C2A472B052BF22B9234D32E4327FB254C25AE25DE27B128C4277C28BA2753251E2547243023A323FC23F924A8260F292F2891270B272F27362904290128DA24D525CE2569271228FC246123062280241026F02589254E25DB269C28EC28E629862C7629B227322686253F29C72A102CA92B962B202A83286229DC29BD2AE12B9A2BAF2BF52C402B4934D32B4F27EF25B624B025CF281D28F629122B332A4E290A26BB26C1258D267824BA24C725E12738285829DD273B28A12A7E28CA29342940284125D826EA27F524772340247A2582265D2720279F26F4255E28DE267D2840297B2A2E28A32633281B2779283829842A9D2CBB2BDE297F29EA297B29382A4C26B128BB2ABD2B6F34B62C2E28F0231B2647267F287A2A422B052E652AAF28CE274D2805289827B7274324FA24A026222A6E2A592ADD29002B2D2ABE2AF129072A7C299D2831267525A024EE26A2279528A628852810298B287A288F283E2765278429EE274E2858272F29E2255326A227172A112A672BB628DC2A5D295C29212AFB29FF2B3B2CA933B02C3E282C2537254C268B28F429582C902D2C2C012A452800299C260528F726CB26F426EE244329D929A82AA92B512902297628A929C2288D2B3B294A2AC2273127B1279A29C629D52BF929FC29BA2A202A1B293528F0255F27E92464272628042A7928A4271F279A29CB282B2B492B7F2A142AF72AE72A4B2CAC2CF42C1536A32ED527EC23C9240A276A2A702A732CE02C3F2B252A0328E0262E29092A44298128962738255F27BD269C280A2AAE2A1628A3284B28E927FC286D29BA27102828289126E127B929A628C029272AB727922A3A2B2F292F252A2632251B279626A028DC28BA282A2692278A27A0270E28342AA229DE2BD829D62AED297A2B8E34F82CCF26A0247724EF254529B82CD02B842C0B2AEC279D27A3284F28402AE128FD2743275826D124AC240F28A1296629C5269227BD2758272128D82891275D26F4274628242982280F290929D427D2262827612875281F2782265E259825BD241726892862299527C12640251F2525284528D028F729CB299D2BD12B6C2C29360D2C55256C247524EB251F2A622A222CB02C63297D282A27C928A329582A402AB328B0274D28A92663235924B0266727D4259F266F25F32759275F240D2646250E262928BF292427B627302747250D27AA27D728C0270329A229A9285125F0226124B3250D27C42605282226A526AB273027A227FE284F28FE290E2A222B2C337C2DC52656236825FF26FE286C2BE42C7C2C2028BC26E0289A28692B472CB82B372BF8298D29A128D42500256927AE28F726FE27EA268C258725C6257E2551254426BE2637266326662632264B271728C529082AD128D427DF28302A9327D62580241E2474245026BE27C1283428A12A48299229852880279B27B027BB290B333E2D27288D26AB23A125322818298429F72936290C279E276A27A82AAC2BDF2CA7294129122A9B28F827D625C9268826FC27412AAC28C227252670234D23DF221425F024E22567255F250B260428AC28082ABB29C227AF29082B5C2AB7296727922687247E25F2262228FD276028B3278728172A0E28AB275C271027D2276133E02FE02940260A24DA2471262F28A627B227DF26ED2425255B258B27412A5727E326B926D626A628D92913293527DF24C326B929002C3E29BE2877241A24EF240126F6261B284F251627F52716282028B329342B112AFB29192A7B2A3D2AEE29E1273B26B0258D267A2956295E2A152BA827C327ED28D527EF27072BCF2B7736022EAF281F25CD23A023DA255725F2276524DC25AA250C25C4244127F627BC257D242F26E024CE27CF276028E6278926CC242227282978298F2A0628BC255A243D253126A327B826D4271029FE285D28E0266828D927EC272428A529032B7A2A9C293827F525FB25CF291A29732AD428F825CC262227E427F02AC22BF62C9D354F2E0C275725E425FE23FE241025EE257926F525652848268F241626D5269D261527932469263028EB275F27F6282F29C2250A265926A8271729A52798267023E9234825232894261C27FE2745294828FF274229862632279D2ADB2BEB2C3D2C55291E27DA25EA256F28932A9D2A782BA2294E259E24512535262A28A4299A32C22EDC2968260D25EA25FB23A625B725A327112938289926AC266925B224172751276227E7261F281926CB25302813291B286E26F626F3271527FD2893270824792533257C24D0239C2726267B27E726F729462A96273527712A2F2AC72DFF296E2C112B1C290526462725288B2A742DC129F1254424B5239A25DF253528933222306029B42619251926BE230726FE25F527AC28C22958277425942319247624322577267D25A926492682263E28642A172B1929A6270224C8252326DE27822543245B230724202445222F2600252725C72746292227B42743284229EC2872290A296428F828A325E726ED2651285329292AF227BC255424F523AB241326BA31D92E57297028C724C3238F23D6255F2602291429F9295429F625E025B5250723B82537265027CB27862735271F296D29C229402A8E27C22409276926E52534250E268E269523292253211023E921AF23F8257227EB254126BC27AD27ED282A2732294829D32789273F265925E6259A29A22978285E2690221325AB257727C12FCE2DEC2815279C25D9239B246D268D273528CE27D529F02A2B272C2463244E2531252E2524263827CD277827802774280C2990273425DE256B247F26DB24FE257426D426A52603236A212A22092234227223D4236725E025D925EB268926782AD72AD7281928EB2792275A247924202668278A27DA2782252726F32600278D2FF12CE92848251D24BB224F2273257526B4274F268E289426FA2512246D2332236D24C7244C26E926082852258826992905296B2758258B24AD25A2252027392748263227C0284A24CB22D021AF21A0224C23602439261B25EE2673258E25BA263D2BC02AAA28B3262C271226A623B6240C24E7265C29C428722768270228D72FD82C6827F1250B247D24D6230A24F925F2273A26C4271427AC270525E123B62245229D248B25132783254625DD25E6267A263B2561243626242717275E27672654264A270D287C26DD25BC23FD22D0224F227F232323DC25BF27DE2642252A278229842A082B182A2D29362559233F23FB244823442631279E271D2608283631F62BD1257824BB240A24B922FB232C27922675274427C927A5288F26BF246E24D823A2236B273329222912274F28372747261227D92799271428CC279E261227F125BC27B726C52754256425BE22A022A8224F230A2377254529A628D728BB2860299E2A432B932A1229332740262B2218228523FF241327E928BF2AE72A7D31A52B722556223D235C236922D723492503279328F8274926D727E8273C2778256C241E2535269D2766290B28E9296627D727372889255728052792277E277527B6255F258A27BF28B926382793249522AC24DC2313219925192703295429CF2ADC298F28712BC62A1228A126A523E322412227235D243423CC260928262BE832C82B2326F2223C2242236D232923D026CE268826FF255826BB25B92685284528F1241625E327EB253E286028B6296C291B2A1F2AC8273B279D26A727842612277F25D723B527882889285129342760231D24D322E422A7222427BE26BB293A28A127B028C029F0299E2BEA26482581248224292345240F25DC258C2499272D33332CDD25E22154230D234523F422132651271F27D926D226BC258925CD2899289B27522646265C24D0265D2666288428C428B3298B275724A825F4273F26B725F3235F233C273D282228CD29992838250A254824C821E32224235F23EB233D24ED256C25832672269428A52730261B254C249825CD246624CC24692777284F34782CA125042448211D2483245223C42458272C281B297027E125D925322806275926CA277A261E25B425D124C826A827F128C42A3129422632263024DA249E2413235D232024A12719290728FD2739282E26C12356234B20E91F3B22E6225324BA233B24E42374239D25292532257F25DA23CF27DD2700268C25D5271829AD32 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 403F ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 0009 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 80287422CB22862028217020691FE31F3120B41F0F1FC71E6E1EE41DEC1F721E4C1D7A1F081F151DC21E621E6520951E691F871EA71F811FD71E871EA2202D1FB01D871E7B1DD31B561C541EA81D301E7D1D351F061EC41DAD1ED71D231D4C1E911F381F0A1FE31C781E121EF61C891FAA1D2520911F371F7A1E6121F422D82DC22B09246520C1227522A820D5205821A421941FB120D81FF11E991F721F541F441ED71EC51E991E9F1EE71F5F206121321FBD202A1F69203D1F27207120991EC01E0420F51E771FBF1DF91FF41DE91D27204E1F421E211EBB1E9C20EF1FDD1E731F751FF41F871ED61F2720341F801FFE1EA5203D21F4207421B3214724BA2D1D2BD024512345222521BE20102115222E20BF2239220C227C20C61F2B2026201820EE20D81F981EE51EA4201020D81FED2047212F2004204B20C61C221F8520FD1FC620DD1F2820A41E6E1F751E4B1EDF1EBB1F4A1E0F1FEF1F4F1D691FC01FD01FED1F611F431E0C200C200F20BD1EDF1E961F2D2238201B215521D4248D2EE02B16283124772141227921AD2258219520552076200920E820EE1F9521C41E1720FF1F0720D1214A1F901FC41E96208220172121202121561F6E1E531D491FAF209E201D21CC1E881E4A1F331EE71DA61EC81F971F2620A11FA21F1E20CA205D21FC1F69209E1FE71E751E481EE21ED31FF41FFB2039227720E921E2232A2E9D2CF225E2212E214421E421DE20A421BD21C820D820DF200420351F06214820F21E8520A71FC21FC81F971FE821701E341F1A22691F7D1C431F2E1FBF1EA81E5420EE203C20181EC61E0E1FFD1DD01FB71ED520DB1E331F921F22201F1FE41E9E20592030212B1F2D20EB1EAB1F5C1FEE1FA21F7E20881F8D202F22F822B52C832ABD2579227B2381209222C420B22032226021A621422203200920852099207720F51FA71F3A21661F511FBB202C21FB1E46208A1F551F441F5B1F151FD41F2620C220B91F0A1E4420351E741FF61E8B1F701F2420F01F501F0B20AF1FB11FC92021218F1F0520E61F5E20BD1F1D201E1F482002221C21C62031233624682DCF2A7F23862251225C21782140223E21E220462265214D20992030207B214B21AD215A206F20F31FAB215121D31F5120561E7B1ED91FE01F11208B1F4B219F20CF1F8220C31F261FDB1EB01ECF1E7F1E0B205C214C1F391FCE1F5520191FE41FF5202B1F5320901FCF1FD81F691F981F03217E1FC120861F5F214A225622CF2DAA2BB12547230224032257201821D621C7218A22B020392151224D231021EE201922DD21DA211922DC2147204F210E232D20B21F5920E81FEB204A21922013208A20FE200D21901FE21F7A219F21C81EEF21E520831FE91ECA1FA21E93205620CA2070208320912020215F2011209D20A8203F20B0201C207822B8221425FD2E252AAC25E7238C22B5220121971FDF2100231B222B21B120F02083202C217C1FEB1F2121592181213A21DC1F5D1E5621891FCE200B1F651EA11E47209F1F671F2B2027214C20E91F591FF11E741E011F7C20681F6220AB1ED5218C20E81F35206B20251F7A210121FA21EB1FCA1E3D207821212089203020C020CD221023BC2EAD2CE8231322C0210122D820A5217821E9221D21AF22F62174207B217A211121A521CF1F2121F12000210D212B1F7D20261F98211021361F0821251F141F1D20EE1FAD2124204C20F71E65204020EC1E3020DB2008209A1F7B1FA220531F38204E2369207D1F24211B21142168217E201E21B3214A215D21A820512336249330E92A0427C523B42235239F21A8219C2115221422CF2376225122822048217F217921C22016215121101FA120A81F2B21B01EA71E141F411F35206F1FB81E9A1ECE208620A920EC20271FD61E5C20A91ED51FBA1E531F681FE52067205C207C2131211B20D81FCE203B21AA1FC61E1821E8206420B120B11FED214E23E32355302D2CE0251723A2243122CC207B216A212923A9231A23A02262215621952126222621FD20D0205823D6206F22E31F61203920362092200620241FE11E4A20BB1F381FC320062074208F20971F9C2080202421901FB420F120BF205520BA1F7E21AB219921B322AB20C522D621C9209B22CB2155214021D72102226222DF250030052D6F2784237522DC213A219E21D620AA2264229D21B923C52122235B22222314221B21D11F1822F720EC20F31FE0226B2123218120A11FDF1F14213F201921DE1F822145228620571FD420BC22B020C81F3A21CC1F37202922F0211120EE21C220CC20FA1EE01FAC20D1205D20952144216421F1232A22FF2287232426CF2DB72B4B26392369239F23E3209B21762289239F23692247229B214E21D122C5202B22DC21E2204E21E220972034212C223E2226225E20F41F2C221620C81FF81E382186218B213320D020F9203B22562021226E22AF20782005204B214E210422C822601F5620CC1F6421901FBA1ED02015226C23872325231D244124B6257030682BCC256424F122FF233C229723CD218B248122012472249E21DD21B2217722EF201023BA2368218C20BC20FF211023FD22B02155209D21F6202620D52040211E231A22FE212F21CB204F2051205F210E2133223F2279201B21CC217520132123210A22F421E7206D229921FD200D226923BD222025C822CB2307257525B52EE42C6F27BF23CC223023CA23102378235E222C24E82454234C21BB227123E523ED210D23DE21CC21B1238F247122CB225421C322B8228A215021A321B0219D2133229521A421EE20D41F2E2381217D2131230D209020E020F4218D21AE21E021EE22CE20762267213023822463222F24E623F5240E263F2748262D26FB26402FC62BCB27F72598250023E522012357230F23EB230226AA24A12369231F233A23E722EA217A22DF21B8239822D723B4247C231C24CC2279200F220B23D722572322233A24BE230B22B420A31F68206421BB217F217C21F5224F253E232B223423DD2279218A2254215B2215236C24AB23A6266B26C8270C29A628B2271A28DF30D92DC52729267023B124E9245A23CE239D24F7253726F225BA243D24AF22F7223A22C822C9233D225B225F24B224EE24D6224E24C0236F22D92246226624C9232B25E4236D22A821B7230A2396216D20A5210224402317228825FF22C2216221DA23B42183223121AB23A6226E27A728072A7D297228D028B728E226AD26E331B42C4E2A862637267725CD240725CC23C72407267628C3253725DB2464258023A5233425F42268250C25152499269F271A24CE2442230A23B422E6228D256F259225C924BD244622A32490237E234620B422422236237A232823C8218321EF21CD22142430251322EC23E422FF2368252D2840284E27D2261528D22595262E304D2F3328EE25DC25DA245A240D2316244D23052586270F281A27CF234F26A325D0246321CE23C324A6239824BD251026912600258A215220BF2467239C2691258E26AC269425F925C824EB23BC21D221632224232E2373232F259F228C2264230D25322412246B24ED24C921512241267F262527EC262B253B25BA255C25522F962E49298A2876277D2590248E22F9221E24C2258228E3269725CD244D24F824B1233C26CB23D4236525CF274527D026D3263B246D23D2213522C82496260C298029B0296C28C8271A258323E8244A21672383241D255125C223D424C2223923FE23B522DA22AF2227246E2385238B277125A9251F27D5228B2452248824622F162EAE284829B32778257E247F237D23CC24DD25C824EA262426922656258B258725D6228D25B524C12678272F280F27A1241E243A213C210023872366270E286829422AD428C62766269424392295221A24EF243D2433252E25FC24E6221123DF226623AA217C227123042354240F24AF233D25242329247B231E23E224332F852EA3291A29A629C62844265224D92320269026A0271A278726802533287426FB252024382410234E24DE258A268125C02326237721A6216E22D622A42694281F270F285A279026E5249C26C723D821C2242F253D25A324102582248D230D248923582340247B22912473264D26122660257523562337239E22142336243730AF2F9D2A152B422AF8289B24A824412516250826E0273328212576262529E326C82571252E237A24772429257C26B126ED2410235821A1220A231F236C26BF27EC277928712662242926F2240624852364240324DA25C0240B255E235E22B8230C21BD2113222222802422246926BF27F82626247923F322D123E622EA25CD30CE30722B0F2A372A392ABA276624FA23F226D526732AA82994264E257D24CE246A24AD2356242727D324CD24CE26832698257C25AE246D239822DF23F22420270E275B28C028B52839272F249A243F22D622992385245824AB243822C021E121432302211B21BB220024D925BA2643297E28B425E4242524A425B625602568305D2FCE2AD929FE2AE1284A27C62598242E253825D527F127B6257125E524E923E4247D2268246E250127B5286926D4272C274327E9269D244C26392692272A272328F127852842270F24D023EF22D2203323C822CD214021F2237221282118235E2177212222BD21F825A0262E2829295328EC24CE23EC224024EA238327D331F42FB12A5029C5274E281827182548247424E0247A274127AC24E724B72324231524A02471235C271C28FF27B127E12911298D2744271E25E726C5276A28212695263626E826A7233C24BF21FE215D2299212723C3222322B0223B24DC226C2497211C21B6226D23C2254B2674273E271626EB24AA2447246B23BF253A2762322C30612B392727289A26E12541259E254525992533286126F5280126F6243E24EF228E24E125F728FB29C72A8D2A8C2A98291827DA23B824D3251C279826F025592502255824E4219922E620F7217A219C22E12220230F240E24242553242E243F25892201226A240C26BF26E426D32504260F25172665255126CB26A92A91354631532A5329332827260924542488246B26F126F2269A28C327F4289426DF2534252A24B22673285C2A6E2BF429D828C92605268F22D9219223E3245A2315241424FC23172443217B215221C61F0121A223E12338253E2571274C257926972677242123FE21AA24F7258F269E26D627B7266D28F927CB25AB250029742AFC3452327C2B6726E2259125F2269624CA2437279227AC2B4E2B552B4F298B28CE26A0251D25EF26F42AD429ED2A0E2944290625C02375223E2168220922DB21A8228522AC22D72272224C217021E5206422AE24D92505282726CA28C72849282027F8256025CF254B26B027BF28C127B6272C27E3276C289325C125E427DF28B533A931082BE728AB27622832262D259E262C277C2B202B482DB52B8F2BD8288824E0239224AD26902726276A2621284326D823F8224423AF20D32136229D22AC229B2267239223952244229B20782197225B24AC280F277928742A762B7B288626BF248027A1274B269A2A782C372D1C2CF329C027B7260025B8260D27902752317B31732D5129BD2A7D2AEB2660253C241A282B2B622E3B2D082B5C2B962BFF28A42442243E2566263D24E1249123F021CB21AE22B321FB201C22BC207223DF22282650258F25A622D82266238D2245215324772802288B29BD2AF4299D282325C0250D2792278B29952A552A8A2B582B8A29BE28002538246923F025A9261E303831B92A8E2986298C292A28D526EA246925DF27F228E428182ABE292B28B92522245D22AF24CE2390239523BD2247210C214322FD2102225422B3224622802498257527B7269D254223BB240B23802326266D29CB2A7A2ACF29F0274E26A5237F250F273A28C028F9290C2AB029B12838270225DC24F92215242C25C9256F30BF30732BA229572BDC29F428A32402242C25EE2516267927DC278A27A326C02480223824F4227E23B6243323DC2438239722B022B72256205F226A246124972559288F282027C22547267A236E23A2232128782AA0295F2AA329AC268A2423240B255E272529A7299B290E272C252E249825A6249022572359259D26E9265F320031262B8C29C72B1B2C63270C26792376251A25B7266227AA283926E725C9234C23A3230E24E42475272F26AF253F276225DF237F24B8215422D224C12657281228272944269C2484250725B8240D249827F329512A9A2A2528352688261A247327EE27CD27F226DD262127C5244424D122AA230F2510255526A328EC280B33AF2F042B0F2CD52A492B31283E2584237C2459259627BB28692788252A249D231B258F248B24A227C1261A275728FB271A268F25932568225823F9257827FC296E290528BB27F522FD21AA259A266A257927D82ADA2A272836272027C6262328E727AF28762A102BA5295E26222232227F23ED2443264726CB276D29BE290D352031BD2B5B2C1D2C7D2A732682233024862495266F28222703262523DE23C4236224AE25422638294129AF285927AB29A9283426782711240C242627C3271F2A042ADE29B1265B22F520FF2376253427E529BB29D427E0246F25AF232E269427302B8C28D129502AD5266323A422E22373242226B7281A29102B562A1F2AA333BB31132DDF2B882B9F2A2F284F26EA2511269526F027D82549245B272B25E12362257C2551270B29162B1A28BE28962A512AFF273F261A24D824E226D4288E2BC12AA32A9D282A24CF22B122C0254627072A7E2886275F249023072570264627BF297E2ADA28572601262F23E523A624CB25BB25E62A9E2BD62B9E2BB32B46354F321B2C2A2B302B9F294E27F1248724832707250126DE260C2786270728DE25D8261A260B27E029D72A652B102CF929552C2F293A253D25F8239F26A8293E2A8F2ACE2A132ADE2407238823C424EC27332AFD2745262E24A923EC2211253C286C29E028C426CE24702302235C230425D624D62569294729E12BFA2C072DDA334531E82A362A5B2911275425A4244F24D724FC24AD26662742275F276A274C262D258526AA27D629402DD32A102B342CBC2AA82835253D24242440256B28B8275529C729A32868257C240625DF25D627442A902AAE27C223FD238122B623852555270B274526D92468246522AB2269247B25CD259C286829F12BA82CAD2D7835F52F7E2BF928402910283A264D2541256027C826B62542267728CB2A282BA6287F27AF269D25692B852BDB2B262B4B2A232A24291B24042354256923BF254A276B284428A9278B252A24EC2524267528B92ACA2AFD27E523A32271224D2451261725C4251F25D7246425FF238E23F92338243825F1267F28F029472B7A2EC035A630C1296B2759283E251B257125E026E3275128B029BC2A002A732A652B53297F27572694276C29DB2B462B542BC32AFE29D326E723472273236C248F2488260F269B27932809243F241D27EA28C828D328BD28B12768260A26CE24D9249A24512699256D245125C02694248D24822416259826282A3E2A922CB12D982DEE3393301E2A5529302799284223D3251F28872891294A2AE02A212A332ADF2BEF290628972599267E268627A027E6264C270D266324C8229623CA23A3248226C7269C260626EC26D224E624EF250E28F8271B285126A12620244C258F26472763257F251D26EB25A626F0279126F4247B25B026C829B52C972DD82CC42A742DC734B42ED828C5266126D1251C268024C72661289B29672A412AA329112B2B29E827DF24D725D7245E24D82245245A25AF25D122EB252324CD219725C325D9264D29C6286B2724254E226022F5233B273E26442640251C2428248D26882714285A2856250E25D2260A28A728D126D324E12526284D2A1F2D092B3E2A5C2B152D29358B2F4629A8267E2500261726ED238E245B286E274C272028BC27A428592A8328D0241F25A823CC246126CC256C26E2257F2447231B236024D72482269C27BF26B925EB254B2427212B22C12391236A253224F9252624D125922510293F2961288D2705278D287429412B8626EF24DC268127BF29912CC72B622CF82B742C62344930AC29992651255225CA248325F6262B277127BE25AC26DD28C72AC32A8927B824FF240B26B428F5268927FC27B827E428DA262725EA24802598224525B3246C25CC243D243B229D2188211824BA235B23A4241223D6241428C4274F2A042B8229EB2844294F28562A6628BF250228A528B429432D562C702D2E2FC42D5535A230DA2BC527C1247D2518261527D52715287A254E252D245825DA2719285B2618254527B325B928832924289827C429992A522A61283627002635248B24712547256F2374231E2342223B2331265824D523B5226C2457258525CD29832BCD2AFE280D2AF3288F284328DF25DB25C229AD2982289D2AAD2B382DA92D7E2D0D3635324F2BF22871267C24DE260E27A6294E2BF029C926E1251125D82571250B259C255F253328D82A882AD728102AC22AA82AEA2A93292027C22436257B2491247F253F25332666245E2481251D268526C9257025F7234125252868297D2B1A2C482B592CEB2ADD283327FC25B027F8284C2853280629802AA62CF12C0A2DEB348032602C3D28E525A9255927FC286E29D72AEA2A062BC0272025252467246522EA24A123852724298028DC294C29D22B482C552A9D2644246B246B2212247325AA270128B329E926D6252B25BF265626B525BB25EF23E4258D29862AFF29002CAE2B6B29CC2949275F26EB251A275F2ADF2AC028ED261A28082BFA2B4A2CC23207314E2C7428B1266727D027EB27422AA92C722B1A2B552A2B27E724E523B6249322C9243C27362A372BD82920295B28452AEB2AB927D624A62250222524FA26FF29C72BAC2BCE29E226D925FE25AF26D124D5252925C624B728F52A9D2A892A9D291A2C2E290128A025CE257527C829832B172B86297B27FD282528812839322A31AF2B5E2957266F275829D12C142D2A2C852A2C2CBE2B512A9C26CB240A2349251929AF28542BE829652B552AE92A7427BE2584255E2313233A253C26CE261A28852A5A2B082A0828AE2496244D25BB26A42440257C27D629DE2C902A8D2BD22B152D8829E1267825C925F227C32AB02BAB2A442A34290F2A6126F32784308731DC2CE02907282A270C2A222C9B2B792CBB2B712CCD2A5C2990270B259A238B2378253E27F92BDA2ADC2A292B372A4026812623242724092672240726C6264229CF2C112BF4292C2725259F237023D624FD2589253526E0272129DB28F628CF29042A0E288E2348267125DB262E29F52A6D2BDD299E2752267B26F726973142311A2BD42AEF276229232B412B4029352B472C3C2C302C2E2B0727C0254C24422435279226A12A2C2C812AB129BE267925902259241D24392689253B275726F827C82B882C842AFB28F5244024562432256E265F25EE26EC29A929B328932809282E27FA24402492229523CA265E284728F628E12A0A28C62642258E26F733AE322129AA277B261129292AB729DB2A342936286D2A322AA427B4246D247C26E8241A289C297B2B82289128B8274526A62347236A22EE2384254E27A0280728552A5D2C4E2B53297726B02440232D2426276528A32798286E276C28482731284E29242647233D23DD241B237725B428A227BD26A928D3251A26DA25F2263F31E12F93291E269927B5294F2B112A4629B9266A277229D22A7D257B254F244A25BA25C52681293E2B942C23298D29572749237D236326F2232627A129882A042A2D2BA42BEB2AEA29AE26B523D32369244C28E32A472A0C29342774285C28F9299C2BC927BD249B24D2254125F3242C268025A025B92776254D2548261526B42FFA2FC7285827D6266A26EB290E29C528FA2899272629A2294628512467258F25492899273928972B282B352CA62A862A8826C22472230626D627DD2A9F2CBF2A2F2B652D402A2F2ACA26512411233F251228BD298C28072717261A27EF28ED29BF2AA8287027F324B028C4282927DB27F525B925AE285A2624257A278E293E33622DC927F425EF27C7272729DB281F2A0028C8265C2ACA274227D125C5276928272A9A28C12676278429F127CD2AA62A0F2A8B2776241A245E260B29732B172B792A912C312BA229D426332410270D27E9286A2B7E2914288C2755276B28A22948291027E326BD273329A52A452BBD2857253D249A289B279228C028002BB9347F2D44251925F626EA29B229192BDA2860289B29202A2A27D8257925FF271D285E290328A625252654258A26F126F32822281D25E924E124952507270B294C29642A602C852BC8289225A423A82617287E2B252CAD2BCB284529D427442875296E284F27FD27EB26012BAA2AF7299327D425D028B52B2F2C182D922A102C5F34DA2B9225E2240926E727C329722A1929B628BA28E32885265E260E24CF2625278E27BE268D26EC260026A925F826B0266D254C248A250024DD264928322B1F2BAB2A882C562DAD2859263526CE267E286E2B5E2C5A2B2F2BED29CD295A2A9F28A4261D26B127E127582BFD2A3E2A4329A726D22AEE2B862B4D2CEE29392B1B36312CB825132603261D282429F427482783277A26B5261E24F723BA247F26FB253527E327CD27EA2816284E27D325852608286E25512341225E25A52895290E2CCA2A1D2DE52B9229A026DE251A279C28042B5F2A002D0E2B052B422AA6284B278725202423276E27752BA92AB427F028F028C929722AA52A0D29F328A82A6E34D02CC72693252627A328592986272F274C2771267E26C324B62431235E258229AD2A052B002B0A2B2F2B0D2C8029332888256C24FC24D924C123F9277127CB27E3284A2B852A3D285A259E24C0249B25D22790295629342B392965288427FB2551258124102655286D2BB22B032B6E2AA22AC42AD22A89274427C028DB2A72353A2CD6272C25BB27AA28AC28AC28062858297E28A427AB24F724B925CD271C28302B7A2BDA2B5A2C692B382DA62AA827EE24D4251A25062531244A25DD266128382AE32A572A5028FC2301234125F023BC257C26DB271629B029DA268824AD238325FC262E294429CC2B772B032CE12CA12B1D2BFD2A60299F28D427022B2335F22C3228E828B727132AE52AD329592846290C2B432A9A27542585271828832BB92B172C212BF22C212A432C33297227E724862790268025182573250727A829742AF329FD2A4C25B723E922812489235B266227CC263827B02A7E2730250125F9256027C628F72A1E2C462C992C322D792CD228C72B4B2781274B2B812C0A35FE2E3527C527D428A82BB52D562AE929C62BD42BD82BBD295628B8281F2B4E2A072D392D072C0D2AEC2B9C2AD626F52595250725A5271726C424EC23132707296D2A942A59276A2463220723FB2464243C27C429482A4E2A592B5F2B4428CD2665258B275B283B2A002D432B8C2BF72E722BB028882853272328AB2B032A2835812E55297E27A829CF2CA62B362B5029F32AD42BAC297928E027C8293D2C102DDA2B192C992B1D2C412A8C2AE22732245C232626D5259525A6259624AB25D42730292328DC24A7225723172467239025FD28BB29702B462A4E2C702ACC293028DC260825D027B92BFE2C412BDE2A602C222BCC2A80278D278328BB2BE82B9334402D84290E29492CF02B232D5E2CA329BF288126B9290827D629DE2A262C572AEE2B202B852C4F2B5329B7271724BC253C251A26C1276A25B625E124F623C525ED265D26F0234123DF253024E6220E2323265129F42AE4298F293A2A712AA52741271126BA2783286329632ADE297A2C9D294728F3266828832A9D2BD92C0C35AF2B852948294D2B4E2E772CAD29042A1A268B258F25E924CC28FB294A2CD7295629292AF82A3C2C572990264C2650266226DD27A528AA282F27E02468245825A1250D265A278A265324FD244D24C3225324EA29E52854291D2B432B2E2B94296C255624CE263A26232AD929862B832C852A3328B126F227132A0E2ED02DBF354E2D94299C2B342D5F2C292B7929F92994266424852511275126FB2868299628BE28F828D8288E2B9F291026DA2760269B28782B352DEC293529D527F324B323C126A527BC27E127CA271C271A26FF25C527002A492BD62AAF2960299D2A1727CA249025612525263727F827F52CFE2B642AB02853284327FA28B42B572DA333BF2EE429562BC52AD92A702BE02AAC293E282925E324AA243527C72844282328BF262B282B28682ABA290828B127802A202AE12ADE2A642B162BDF27FA24B023F7272D29AB29542B142BD02819286A253928D92B442B982CF72AE128EF295E28C525372580234526F826ED2A5E2B9B2BEE296C281D26C527D92A672B8B2B0634F02DEA296C29F6283D294B2AB02AD428432896257826F9277128052AE32BC2271027E9298C28AD26EC26F42658295E2B052C522BD22B402A522A4F284F25C925C127CE29A12B8E29322BF22BDE29C42632282C29162AB828BD2AAD2A2E2ACC2AAA27A02435253925B728012A5D2BE62B7A2885270E279728CC29DF2BFD2C6734802D0529C72882280127A3282229C32905290827E425F0297B29232B642DED2A0B2C2C2AD328D0266826DF2794292E2B9A2B3E2B492BD5294D2AE12645245F230C26A9261C295228332952293529A526AD275127D7275426F628C228822A912BAB281D2564248C24382849298A2B5A2911277726E3269A29962A8C2B682C1936D0308029E727C1273A28102A9D298B2985298E2773265F2ADA2AFB2B012D082E8D2C972BBA29D126EF27E0285F2B6F2CAC2BE72B742BF82B502AC427D3223523A426B526ED29392818283428EC261E262E269528ED25872666259A29682AD72A132B1A266D250725A72558275E274827FF26B1260428442AFF2CB92A2A2D96372A3062294C271326B928252A122CBD292D287F26F328542A152B5629F52A5C2D4C2B3B295A290C29EE27C428CC28382A042A9F2B342B342BFB2A1427B8246B268226F927A1286527EE279D25BA2439255828A9287F2AA7286027A826A029FC2A362AF426FD234924882430257B25F926BF242A263C29812A6C2CEF2B182D80377430A52A7626F727CE28C42A352EA12B2A2AFE288429442B522AC52AE929802A5A2A972940282D288C27A32CAE2BDE2BF9298E2B6129AC29F7299B286524C924562661271C29AC275726C526D825DA259D27722A532C282A0829BA279329482BEC2A1E27AE242E248A253C24BD24D6248D25E226A7283028692AAE2A802BF4355031202B2C29F3288929122B072DB52BE12B9A2A582CD12B0E2C222C9A284029DF28E626DF26E928E2285D29742CCA2D082BBB29EB26D825542683238824BF24E026ED28F22A2329D927322731260A267227E2285529A927F32832284127EB28C6273E273824992272262F250827B225C524FF27092A192AE52A262A442A1333352F0E2973265726B229E92A2A2AAB2B6D2CED2A3E2BAD2AA52B192B5B2AC728E32636263D264328B9269B27E6272B294627C527C325A423812490222A23C4236F2502281429E9285826AD25FD2617264E26B729C72829283D294429D729192929282B259424F122E4252E277A27CF28B32641299F2CE72A102B172B3C2BD932052FA5295326C625C6270029702AB62CBD2CE72BE92A1B2BE72A9B2A5928E22795258826AB267D26F026AA273427E32564266026C6253024A02210233521582310276927602AF2283C262C256526FF26CB29052CB02ACA2B252B012A952CEE2CDA2B05280D253A2674271429652A652D642B1F2BF02BF82D712CAF2BFB2BB733BE2FD528F425E6240526AD276528B428432BF32A082C542ABE29DD292529C12796265726A227B026F425E325BB251B26EC25E02781273E245D23D021A123A7234726702848290328CC252C267D25BE243829AA2AF82AA22A922A192C132C8F2C382A63292C28882402288F2AA42AED2CF8293C2B3E2B80292B2A4A2B2B2B9234842E272986269C26292730289528D727CA27412AA6292129AD28A7273C26A0253E2650269927A227D1260E28FA27F22866299A2B45297825F324782372231222932455292B2C482ADF289828B924C8265829B02B0C291C282F2A7D2CB82C552CF62A732912250D265727202AD42A3A2BB9291A2B002B3D2AFA2A382AFB2ADD34BC2E56285D28EE27152AEC2B7629FD29D129442A3A2A0C293C28232735256927BA238227BC298F29B427E1250F29342A382968297D272127F726A12546261525FE2514288429052B4A2A8A286726ED250F27C129D828C1286B2AA72D0C2E7D2BF528F826E8250027182A3E2AE72AB62ACC29242A882A4B29B32871288E2AC1358D2EEC28F9267F299F2BC12AB229E4289927CA29A42BD72A54281A289D26A82943289B2720289B27AD257326A628312C7728B3289A274D278D28D129A2271D2743271828AD2810298D289F28AE28352690259B26A7267A28552AF12AE72B252A03271F275C265D288C297529482B4E292F28DA2A392C2B2862270F27CF2B36355530422A8E286B290C2B672A1F280427C3276429152C6F2D702C3E2A372BF42984270E279D2742279C268327222AC32A122CE72947282D295B2C1D2BE128B529922A8A28B825BC24A225D426AF288926782678253D2601269F29E62A6429BF282A272027E428AD2A512A422AFE2A022C662BBF2B8F2D4A2BDA29A729212D0B37CF2F982A4B2A3A2A4B2A8A2935260225C725BC27D8291A2CE52BF72A362CB62AE3292F2814276426E527C4268D27E628B127FB279A289628CA2C812B022BA128DD29152AFE295626C1246D25A6280728C026CE258424A523F92AFE2837284F26E6255029E62A802A1E2A6429B72ADB2B212B8D2C2F2CAE2BA928C627B12A0435672E7429EC26812876295328D926B624A526A3277828012A962A032BF42AC72AF32727277F257B2727290C28B727DA26ED264E2749293D29852BE12AD52AE029522A0E2BBC2A142809265925F328D927CB251625C0227C255F26DF27492654251D26FE28822A2A2B4F2AD829A22A0E2CA02A522B4A2A5328AE27892745293B34D82F3627E2264128B627E2266525EB27A727262AB32AA8297129D92AF42B602A902820257A26492894298C2823295C287D28A9260A281C27CB28F726FC263928292AEF2B192930290E29D2290C2A052AE529BF25EA244B241A277026B724F22529268829882AE82BC62B2129BF2A942BE32B222A9C2711254727CE263F29D4340E2E1929E6262E262126DC2583259E27482A0E2BD62B8B27FE292E2BD92A852B69284C261026A9291A2941288729142A772A99298528AC270D2616256727A128F22878290829CC27AF29A42AA32B9429A227FA25B525212596290A27DC277927FA26002A282BC32AFD2B792AD029972A252AD0284C29212620263927AC29843224303C2A8B2912283E275527F225912AF82BF22B122B34295A29F52A9B2A1E2BBD28002696272B29F229012A5E29772AEA2A142CEA281628532649265327142875289127F2277527B327532BB52CAD27292672276C27BE289429D227E7258425F2275A29832BA02DC52CE32ACC29462B3129B9267B26B62634289D2BD32CC533932E072B5A29922A342998284B27C929D52B6F2B612B4C29BF299E29E12B5229C62799264829272B972BE7296B2AD92A302BBC2C45289D267F251F268728BC28812663269C266F28522A072CF829C4279B264726AE259F28DA2A3D2ABB28C125FF27D927A22BC52CAA2BD62B022A4D29012A29289226E826F82A332D8D2C003617304B2AF529472BB52B6C28F5273329752C642BE4298A29A329282A7B2AB9297126D4270228462B752C2929822A4C288528252A09299C278326DF28CC28A628072829274C264E27EA28382BA12B7225EA25B625BD273A2BFA2C0A2A7E294B261627DB273D2BDA2BC32D952CE12A032B772ABF28592749289F2A982C022E6235E02FED2A7729362A232938281528C929632CAC2B3429912762278428F1277727ED257D256F277E296B2A46294D28D1267927D829CB26E6259D27A229292AD829D3281A2680259925FF265F27D42634255B24B525762997298C2B362CFD28F727D5265A27BB2AB7299A2BA62CE22BF22C6C2A662966282D27CE2AF12CB92CF7357330C52BCF298129DC28B126EA250429DE2BFF29282A71294C28012744280626B8238126652749280A2A772A2D2AFA281126A5272C277626EE2AC32A092BA72B4E2A0028F325532364266F26F524DB22C924CD25CD271D29812BD5297F2BA229B8264E266F280D2B922D4D2AD32BE12C882C852994273C28D02A142BEB2DC9365132C22BD12A7429E72842272A2779285528EB2998286E28AD2591266C27712511254E268C25B82830297729F127982680253425DE259C284F2AC92C4A2CA42A082B1028B8234722C4250A269D242724BD23DF2718274627E0275F27A62ABA2988277B24BD248A28AF2C7E2C292D142E762D2F2B01292927982881294D2BDF34C531F12B8B2C5D2A202910263526F4277128A629AB2B4729EA26B025C325B126E326C9263F26F3285C2A0B2B842AAF2940257E257625B927812A0E2AD42B442CE82A17289B259D249D252325E423F924FA227E28D92738272728F926DC261F2659246A243A278D26422B9C2D282EF12C392C362BE5280E277A29F82BCC2DA9352932542B1B2AFB2BDB2976272F268226AA28A929BF29BA29D027D9263D2868294A2915283E28FF27512A8A2A622A73274F259524682627278B28F628C1296E2BF929A3297127BE217C24DC22AE23F422142328264727D62871284E28C8293228022652254025FF258527C229802BD72B8E2A2F2B9E2925271028AF2ACC2CB033BE318E2A042AD02AB22ABB279527D0253328CF2ACE2AFF2879260127032B502C122B802B31297C29B8288429D02A06286B2410256D2638298128CA26D6277828D2289627392602236C235322F123FE2283233C26CC268727D628D326252AAB2A1B2ADB26FB244E2307270527DD28792BC52BC52ABE295A287926BB294F2D8B33A3300B2D022C942CA42B9327B627B625FF299E2B2228BC26DA270428DD297A2CD12B642CB62ABD2948294428332787269E248A251528532956281C28E42667275D28FA2802287E23C324D22332222E21032510278F27BF27F5264226002AA52B582BE5274B24BF253525D3249E260C28BC293C2B282A6026762516265628AE320030372D962C2D2BCE2A732766259B2664284B2AD32ACB287D273028DE2ADE2C632BE729C32B2A29B129C9270827F724692380269F25C628542A082B8928A1290F2BBF2C742AB824A223B1217B245421E4223F26B227542732280529722A322CBD2AB329CC2895242E2765261E289828BF2A1D283428CF26F0254D270A271132712EDE2BAA2A302B92298726B324C227272A0C2B802C492BB427C227562B1B2C3429B0297129CF29FF275925722465247E25C0272D28AA29332C3C2C202B622B562BFC2BAC2A7A267D23DA2380243623E023952571260229A627E12554298C2BF82DAC2998286726CB267226C828F229A328192A232A6C277F26CD2612293832FC2C4F2A8A29F029CB2864273B24B227F629512BC12ABA2AE928FE27A929EC2B252A232AEA29502B48289C2559272627B6284428AC28E229562AA82B572B012C3A2B542C972B262AF12624259425FC25D7244125F2263428ED26692593266728232CA82B62298329A7282128C2285A2A042C172C512B9C29512805277B28CB3173306A287926CF2742289525AC256125B927612CEB2BF52A2A288E25AB288429922A242D802A0C2B332810265126D3288629F6293029122733298429CF291A2CC72BAE2AB129172A0C288826072638254C25D8263C288D27BA27B62424256C27D829832A8C2A3F28F828C2273C28A72AC42A802B912ABE282B2958276C27ED32722E692928265E279A26E027F8255326DF27C129992CD829AA27D427F92612293D2A2E2D662C262B9927D2268B2894289C29282BE328B527F2297F2876299C28E82A192AE829C42AE8276726DE257F24AE24BA251227C12735278B247723C125E9280C2A332ABC293F29A7284B28102965277928C2275328BE28F627F6283832762DDF26B625C024BB27EB280E27E625A125EB276929BE299527F425E2268A287328462BEB2B6A2B9429F62719270328E92A9F290E29AF28FF282A29442838279C28D3288B28ED265C260E2934266F231C24D02666266528C7262F25042682260B263C27D4287929E627FD27CE26F027A0260F255F2504271D2608287929CB311E2D3527E3247627322A5D2B07280528C126C227A027E028A9274125512601272C274128272A072B35289527172770289B25C727C327012856295E295927AC28D72790255E2646259C25E027D52710248E25D6265B256B25F226E925D2252F25A6260D27D226D62678263328B9284A283D27062565253F25D12687265327A731592E7327B524B327D927B32B602A2028212779282C29B3291F295E254E267326D127DA28E529722A312BC229432B73299F276E273527522ABA2AE0295B271126302748274924F623672492264A2528242B26652436262526F829282CEF28A8269D2706281F2AA52816281B286E295A2B67282A263324A823B8274529FC298B33CD2FE4297227AC24D926A927FD2A18291226AC269628C8295C28C228C1280C2A672A90299729D02AE52A2E2CE42BF22AA22922283927852ACA2B97297428D226F5274F27E724452305242D267C26E22596262C260D257D26332AC92BF92A5127C927D327E126A42747285C28A526A6291C28D6268424EC23D9265529502C483573302A2A09289726DA269928512AB3288427E7272528512B872CDF2AE729A12A022AA32AD1281A27D527F728692E6C2B22278F24C3258B260529B629DC28A329092996273A267F238623EF2498272727FD271425C0244D2717298629832AC429D128B427A22785252E2738268527AA2AE929232944269C246A25F228362CD4332533322CD628C62645267E27822A3F2AEC2A8D295429372CE82BDA2C8A2BE12AEF29EB27932736264A284D282E282827D726062609243327F8261E279627C9297E2A002B08296A249725B1263928DA29EA29BD27932446254426A5273B27292A712AF028A927B1260326232645278C2ADB2BEB29D726F024B2251C27192AA8348432A82C7B286A27FA2598262929932B032AAA27E527E5294D2BD52CBE2BED280D28F2259F28E0266E26FF266D27332743256124B025C1254F24C025C826E0271F2A752BA1284F25952449287E28072AB829FD26C7245B25D5269D27B129CC2AA52AA8290E2AF82727284326FC275329AE2A642B09298F26FE244F281B2A6E355631B52CF428D42571260527BD284B2B792B9629B128642A1E2BFB29792A562AF12724272B28362801294D2C572AD32AD6282C26C6240F25AB251C27D9271F29D72BD72AC12978272524A325BA284B29412AD72761258726BF287127022970290E2B742C462AE928C8288E29812740284129232C35294D265D286A28CE2B4B359731D22B6F299928D926F425E827C628FF2917298127B828282A622A932A232AF0278E257028022AEB2B6D2D2C2C7C2AE4282B28412682240226B62600296F29E32AC12A0F2AD92765253E263828C627592733278526D9266F2ABE29D72866288E2A232B842BEA28D129762943279F27B627FF291F2A1A285F28122A562C86344F32C42C712BCF29882A9127EA25DD28AA2858295328A9290D2BF22952295D295E282E28FC29CD2C932B382C522EBF2B20298327EF25FA231125D525E827182B702BE72AC8295B27FC25F524A4250A266E269B26042585277F29112B5D2A372891282B29302A3C2AE92A7B2A3C2BD5292028DE27ED279F2587272D2A632A15341032D82B142C842A6E2992272326FD260C29B8294C286B289F28CF29F6297D28D2271D299229A72CE62B212C662C49298129DF272725A223FA239B2534277B29C82AF328642738267424A3237323A324712542267925FB266A2A0B2B4F299A2886286D2A3F2B522AA72B8A2B2A2B8F2A472A812852274E27E226AE287A2AF634A431572C4E2B102AD9297E27A12555258628F8272A283829042938273626082765260128B9285A2C832B5B2B342C88295C280629CD2661240A254423AF242826152934286524272374229523CD215223C5255C24862536265B2A3E2B5C29CE29B029BB2A3F2B292AFB2BCB2C6E2A2E2B912BAA28CE289A265527B929AE2C4035E52E832AA4275A28D327EA24D624E4240126AE261A2883270D289C25E9239824D82450262329452B832BEB2A8929B22927280B287B284B273B2624257224A3259A272A2791245A227A220D24F1222E214824EE251E25C8254829A728F02641283B2AAD2A762ACC28D2297E2A402B9E2B4A2B6E2939288F25A9263028AC2B8C35962F072A80291D27E4274825DC25D3250824B3259127A728AC287B27AB2695247524B124B42A432BE52BA32982296F2974284928072AB329FA260D23472252246C2693257F23AE231D238B22F124302340260D249A24C3260E29FD284827B8260F274028382A14292B2A232A692BB62A2F2C662B5B2ABC276C2643272E2CFE35D130942A3F29002B6429AA27DE233326272448250927712AED2A452A782AA8276A247725F6259A2B392C9D28C029162AD429052AA1298C290E28E124BF228E24E224AF25A6253623A022B72455248D23C9242123682441280C2ACD281C26ED27BF2779299B294728EE273527F628582C162A202AB829C225672588276F2C193612313B2B6F2C0F2B142C9429AF26D9257424A722DE243C27E42A3A2BFD2A8C2942257925CF258A29EF2A8129AE28DC25E124F6275828672832276B253C23E9237F266A2999279C250C26072461279125E625ED23D9238A25BD274F276826A9275F293429612A6128B128882673282F281D2A9F29872A81278B26802768292335D42F7E2C072C022D772AA72B5628AF24D5247024402539250827892970292028752738269026FF26E726DE273A27CF256625F326092798278C279124DE234A253A2612284228B126D726E32650272C273C2771266C2567261B28AF284028222A392CEB29ED285728AB2A662AEC2A9A2ABB2AD229632ADD284A270427672907359730942BFD2B9F2A302A2D295A28BA270B25E62249247824CF254024DF2589267325412739262A2686250A27942582275B26F826A6268628CB28D02677267E27E928C929B6296A293B277A288F29342A03274026CF2433261729D4285B29B829AB29C1280629C42A1B2D702BB92B2F2C892B5A29FC2897298F293D28E9264632642E6D2991289628EF271B2758266025E225C6224A2397244825CF252E2777285A2749260C258F24A924E224932616254F25EB262028CF272C28B026E025122784281A27D72731269B2886262E291629EC27D0268923832473278D2A4E29A5291E28A7251D26EC277D28A1288E2B0D2C232A2228AB266827A4284627C727F031FD2EF328C228EB26B326CC271B2708270226ED24C6254928202808285C2A242B242A10291D28E2242725DB231125D7264528D629892C4A29B1286C261D256E27B527BA26B6281D2883293F299329CE28FB27982533242E27402A882ADE2964290529802886252E27F8284128A6273B28EA26E025CA2529268928D728C029B832DD2E222762263C274228B529E029B4274E26C52490249F2787291C2A092B692B882A2A2A732AE927B72546240A2408279C27B6281D27F527F425AB248325D525E8269D25422773289529612A332A572A8B29ED2566245E27CA271A29E5286726D72717282A28B8272C28CF27F1262E280026F22441262827C128792B7D2A9133D52C27288F274D27E128DF2A7428F0274B2614256C268727C32B0C2C342D6E2B0F2BB92AA02BB929002880247225EA28C5261C29FD273E2752243A24DD24EB24C825B425EF246E259E271C298E292D29442A2F26AA24F4246A286B28472873294F287228B128B128832AD72AA0290D29A2277024AA25D923F327C52A1C2CC4342C2E452AB1260B29F129D12B1E2BF6277827592347240828702BBC2B3C2B432CFD287F29C92A082C29283825CA242327DC267F2782269126F8253024B2223124A7250C271A25C224562518278828BC278827DC26C024CF24C1288F282E29BB2720295026E9261E27B1294129042B8E28D428C524FD2414283329952B392C3A34622F192BF62884297D2B8C2CD32A14299927272506258027092BCB2858282E28B328FC29C729D32C2429FC254A2525245525A324182602257727BC230326EC25FB27E527DC27D9257627E22613282028BE263C25B024B223E327C527D1296228F627B0267727DB27A52A7A29CF2BF02A9128532509264428F92B8B2C5F2C173626318A2B23293E2AA72CAF2D3F2A64297B273625F5250127E628A52A772AFE287F28B529712AF62C60298D26192511260C25D625C1243D25ED26AF25D12377267D28C1263027F12771267129C62A8F28D6294928652488219825FE27ED2A7D286126422541266726AA29782B152B6C29D029F326C52740275F29FF2886290934FB2F202AF329B029422ACF2BD82C78294D28B925F524AA27432A672A112B36287627A128212BEF2BEC297829CB27AD25D8242E26132564251B27C6279725AD24632707289928C527DC28922AA12BA12A9B2927284125A122F12332264F294E28A425C425D825EE2577287429C129D42A8A28AD2724292B29962A932A0D2BAF35382EF927E12708280628702A182924284A27BA24DF24B72543289A28B427FE268026F227562B412CF628F726FA251C257823D22457231426E626C8248A25BE236424D7268B28FC2579280C2A8E299A2A3D2A5529F02491235324E6245E26682539257524AA241225B227CD27BF274E274E25DF25D828B5281A2B1A2AA12A4B33762FE4286C26D4283129D229F82AEA29702878237E235E26DE26242963283827DF278C289B292B2B6729A0285729372885246B2595244324A52545276826EC241F251026E5257E27FE28222A5F2BA02A432BB429782637231A2321246224682695256024782433268027B727D5261D28F524AE253F27B128DF29FB2A612C1F35CC2E772AE0294D27C32711290129382832265A25A02373253E250E288D27FB28B927D1284B2A1F2916294128232A392905286C271E24CB245B25FA243A256223A823B2220025C02601280429042A3329B92841271524C4248C239422AF23F124D426B9240F2669286F2968272326B224652549265725D2271629F929B62AE0357B312A2C06293027FE26A0272729812872269224BD224623BE23FD2560289B25BD279829A92ABD2A872ABB29552AE029262B872ACA288D249025EC245B272A271925612359247223332735296129FF27DD27A2271D26E4240523C8223E23DA255C265C26C6263F28F82A8F282B2702287E252E262027E3254427502BE32B6C36AC2F852B5E2811264726A1273A27B9291025A523F0220A2312231B2676273E271628D02AA62AC82BEE28D927A128C129ED29562BD9291A264B26C6251E282328B1261324DD223322E624C2276828A82766264A2870274B25DD2227236123E4243A267F25BD25ED267A2A7E27E226B625C225C72701284327A428D328922A5C34712F52290228E127AA251327052804297D279623B0249C23BC2265259E2762294C2B2A2A722C0E2D782AC32741281F299A2795297729C426E6244B24EB265F27142820269A25BE224C239A25782794263627752AAE283E26FF25FC23B524FB24C6237523E3247726D828C728AB26C927A528022716280C286127C627E728E3314F2F4C2B27286526802738266029222A4229FC26DA230B23A324AD24EB25082B262C822B5A2B092DAA29092742270A2831271B28D0295429DC24012573253026DF296D29F02546227E251724DA252E257928362ABE299728C326FD22CB25FD22CA256925302515254528B82864296E2ABD28C326AB2877295B2B512A552B3335D62F4B29E026A1254027BD2525297029FC282526782464229B22AC22D1259D287529B8298E28B9292A295927AD261028412814289228CE24B4249F221C253725902676265A26B824F12174255B240E243C269828282766282526EA236222D9237F23CC22732465231C288729B8299628B527762777290F2BFF2AE32AF32A4B35512DD0271F27F9233E240525CA27C52878297B26EF23EE2243221A250C270127392AA0292029922966292F279E26BF25A526582828273725F7255C247A23372393245A266824FB22A4218C230F22BB2376258F2666257426FD268324F62346215C2398237323632510273C2873274428AE25A726A9286727082AC12ACC2B3633702C09273725412490230F2532279328542844252224B2235322AE227125B6288F2965288626DE26E6268C25CC2426250A26BC253D25142629230224B722A6235C236C2377245822A2215423DA23E2234D2472234F24232563250B259E2297244A23F520A82278254228CF26A826D925AF240D2540283828192A122B852A9832152C6327182395221B22AD229F250426D12624241D24C5207821CF219C2371259C270527EF26AA25EC259122F123EB263626FF2575256C247024B722EF2413260C240523F723AB20D321ED222724EF25CD2500256325B32357265F24B72251216C23CF21F5206D223E27F628DF26122697238F258128FF28AF29512B8A2B6433992C5A26E42468230D24492422243F25C0266924572478213E226F21F32281231B244D26C6250F25F7223E2263233B256225F6247D2436262B251724FB244826A0264F255523AF212423B32369252727D42642262B237B24A725CF247922A922712277217E22152470272727ED26E9267927BB2404279227E3288628032BF734072CF6246723CB237823D5225823BE252824C32452231C22A82182208C216D232C249E2329265626FE249722D624A824EB242126032755262B256A23A423282715289C276E239622F420A123BF235526F52719270424A323B225152445247623232208222422DF23212686287A29672622262527A127DD279028E829F92A6232352CAA252B226D230024ED228D24CC2470257F261725C821D6218621C4226D230624F224CD24BF243125EE22632522239D259B2620245F260424A0237223E72621283827A625EC236721B923AF24F925742AF8299E2477251E256F263B264C2640237D206923AA2366249B2782276F2717275A282529C026FD277727D9295932882BDF25A222E62179237E237223D5255324282420231E222F20662033222924DB22DC23DD25BF22A62419249D24F723F7251C274A251725BC23AA23B2227625A22606256E25B72287211C2301248024CD28C027DC2516230826BB258229DD251D231B22FC21D32137254B24EA2712292E2904283B28BE274327922496267C316E2CAF25292290232123BC239423AD2575253524FD238323B2210620A4221A237524BE24F7249522AC248823B02412246B2468278A253623B42302259E221A232524ED23C6245F22D020B422FD22C6237128D328F624C7233723B223F9245624E123C82190210321E223F62428279B294929E52901295827B52687276427EC329C2C6425BC2324212824E4249F235A245E250325F3259C2303223121E022CE21E7227A2592244B23EC23C8223024F3233724EC266326682416249421AA213E2216224D2367223922F421F420B421CF249326A526C125B02171209E223E237824CD225E227C21E72025239523E325CA299729F22BB82A772873268727A627AE30 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 403F ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 0009 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 D32817234C233221D021412156204120D020F81F561F291F3D1FB91E7C20151FC91DC31F7D1FA31D2A1FA91E5520DD1E371FAC1EC11FF61F631F4F1FFF20A81FDC1DDE1E481E401C131DF71EA61E131F801EF81F9D1E4E1E2D1F831ED21D321F42201C209D1F911D0F1F791E4B1D1220081E02212620C41FD41EF3213723262E6E2CC324922191233823B121C521332248223D209A21A320CF1F8D203720B01F1E1F2B1F131FED1E251F47209C20DE213F1F3221B31FC1200A20F92062218E1F8F1FB720C91F3F20FD1E56217D1F6D1F6A2196200B1FFA1E931FD621C620E21F39202D20DA20681F43208320C21FE61FAB1F6C21FA21A9217F227F22BC24092E3E2CD625A02498237522D7212D223D23D2207E23E922152352217220B7201B21B82041216F20201F0D1F352165205B207E21FF21D220112170213D1E7620E6215B21F2212121B02191208F212E20E81F4F20DF20721FAF204221C91ED220112195210F217520211FA1209920F420B21F32207B207023612161225D229A25A12FE92C3D293B26F9224F23DD22B12311221121DC2002219F205E21A920CC21761FA42091206020F321921FEA1F151FF22001212022AD21702207212420CB1E77203422CF21942240205B204521FE1F541F3D202D2110218F211D2106211C224222DC22472134211220D51F541F3F1FD91FDF207F2121225423A1211E23B3246F2EDB2DD727B8239722D0222C233E22492227224D212C2150211F20C71F6121E820841FEF20242029200A2028205122D31EFF1F7C232F21861E9B2148213120502012227F22DD211420E0208120BB1F33210320DF215E20CE20D321CA22692117216722B7216722FA1FE9200120C420762034214921C2219B208B211923B923432D362C632774244A254822AE23A12187218822B5210E22A5227120BA20DF203A215321D5203920F0215920E11F24210A2245203D22B921AA21C721CF215721F221DF215222AC212B20D121F11FB9204B2004218C2134228222BF21BD22EC2113221A23C322D6201721062161214221D9210021F221A423CD22CB21172457252E2EC62CEF25B124FF23F0226E225F23F421A821AF22242228217021D9207B225522CF227621E021F2200523D1226021F92174200E218F22CF22E122F1215E239922DD215722B921E8209520BE202620D11FF12103248D22C8224E23BD235122EC2281234F210B223B2130218421A821072289230A229C23CE210E23CE236024842F692D6827AE242A25E822C92034210D22B0217922BB202F219E22D3235C217A219522F921A222FE228722052137229424B7212722A9223A22CE22EC22D72120219C212B226E22FD20F820D8228122E31FBC234223B62276225723A9212A23C422EF227022B5219621782243224F22A1237F2371232F232D22B1241B241A269130552B0A27A1242023E7221E21C01FBA21B32202226321EC201D21E320CC21D11F8F20CD212F225A223B22F7203F20F0221122C823D221D1207020BF218720A920B42191220A22A421D1201320661F8D206D220622AB230022E724ED22292230228322F720A3228C22DE2383221322F72323258723CB23F9222823F6242125DB30992D9D246322F4212222F120D7217A21D9224521B1222E2294209E2105229B2138225021372205225C2237233B2264242823AA256F247F211F238C20692084212F22D623E822382340213A22F721B720B0221524DB234123DE226423EC21A5228A255822E720CF2289239524BF2573258F2564265D25A6246923CE251827C533642B8B2716248022F0228D21E521762112223C228F2388227B229120F7214C224122C7216522CF226D21FF23DA231B26A4231A235B2289217E21E020D52060216B2424247F24A424EF2118214A22192103235923EB23F523D724E0236B2379243F23E0217121A522872402241824D4263126E72431249E22A0248D260E2867343D2CB625CB2280240E22B320B2210A211D235823EB22CB226821E821F32143238B226E225922B225A82377267E247025D8242524B9230422BC20AD200C238A2322240826C324DC2479231122F4227A232226352679276027E32609250724B724BE2357233124E6226A26CC270A2886299428E1252024F323752473260E2BBC348D2C0C273A237722F921A621E921D9209A2276221422582487227124E823FF241724122385212E2423242225CE245A277A256C240B238821DC21AF231E24B626F5254E276227B12461228922CD244224002680293C29C528E7286E271E25D8251023A5227D21DF2249266B286529C72A57286D256B262E24D9258A28DA2BD932B32B652694231F24DC240B2264225E231E24242452231024E523D023FC25F2236C25912409239723102475241525D525D925F3248822A12143245623B624F624C7279F279A26A524B123CE225D2425241329412B822A1829DD269626F1259B252625B2211C231D244F284F273B278A283628992760258724122746296F2C5D366D2B32261925C12310254E23C82497223425F622AB252027D824A625E1250727C024D025BE251623D62250237924F525FF25F9233E2246234E23AF232E25EC253928122857277B254523F6214322572405267228AA285626D425F7252B24A1231A235224D3250927E629652A81298F2961293026C8253023B725A429FF2BA834702DE027A224AF23F7248525A724942430233325FD2648277D266E285A29672A65278E2615249123C425B326AB24B2256E24EE248A24E022D7222224BD246E25692785272327A924F521A9242E237B2444276524F72448252B26BD257F25CF24AE240A239A262D28C82A052C54282628212676259B2482252926DF28CA2B8D342F2B7827162644265824CC2499245424E323E92458285E29D829802AA52A442A7B28EE247A24202471269A253B2792284927C1269A2493211923B224C2255F27AF28522AE529E425D6219E20A5222F251C26AB259A244D2699299F28E226EC254E247523D62551268827FB26EE2505230C253D242524B7255F2741295F2CA734132D1C274426F123BC25C12660253F25232690274F291C2B7D2BF82BD3295E29DF266D25B925F2246C261729AD295D2A9B27CD26BC242523C1233124A727DE28962B9D2A0F281F2436248523D7232025FC2668285426E324A629312848254523ED24BB22A8249F231E2674245027B725DF257B24AB2322259227F528972ACF353E2C062ABB2601271B277527DE275026BE26AB28332C6E2BAE2BAB2B412CF028482780275C250729FC290A2A2D2CF32B6D274A260724EA23FC2369253429162BA82BFF2A852971245024AC2367250F25A828312797259D2466246123ED22212363230F25C926192451267525E424952407250B24D523C82470287128502A6C349A2F8929A02821280D27FA26DE250C27E72649290F2C442D712C032A942C852A252820247D272F293B29F629F429602989281D25C721202164261F26C7299729A12A322B9C286D254D23F4220A238B2525279F26F0238E22E323DC216F22CC2304266C260A27B1274229A42612261328FB258B2513260B26792750290D2A443458301A2C2C2CBA2AD7283D270A253E267C280D2B272E522C592AA429F5281728B825762963294E29BF29672B252AC72885276A241624B523272597277928242A472A382A992733255E2203228825DA2301262A26DC2453230D21A7224C22C3236B26BF264C288C289F2A3D2A5629232B9327A027422AC527F428CC2865285A32B830BB2CFB2D132B2D294228CE26772681289F296029202B8D295629D7265B26B0277227242CE82A0A2BD929122AB028A62523251923E124A727332779282527D127B927EA2565249E23C323F9237025982601264D2345234322A32234223A246627F629FD29582A452BAD2910297F262025FB276327B6287C27EC25DD266C303830732C832B792C0A2C7A2AB52863265A278B276E28A5277C269624DD264A267228EB291C2CA629A3284F276527F026FE24BA240D24DA269F28F0264527AC262325C325B424B6237223AE275E276C26AF2800289426BF23A723F922FD231D27EB29F02B1F2D272A432B0F2BD3276025AF246024712561254D244524DC240630C52FE52AD02BE02B662C19295A288F278A258A242A250F2620238C249B27DE27FA29BB2C1F2B902AD62882271628ED2705267424E92488285F29FE26C0262426FB253C26832379219225D127FE29142BDF2B8F2A4A2A00277C245E23CE234F284828F129332A11291F2811256624DD248824CC22622340230324EF2295251630482F9F296929EE2A332C372A9F27F0254027A925402721259A236124BE251F29C22A572B302BD52B9B27A8250327CF25C124FB24E826F8279A27F32636255526A025BF25D224E9248B266E28562B0C2B612B9C2BAA2A8E272E25BB22B6230A26892942284326D725F923AE2206224B244E23F921A3221D231325C425B5245C2F872EA52980290E2C702A7829EF27D0262727FD254A265925DB23BF259028E12A922D9D2ABE2A2C290328C527C8245A25A72440267E286F28D429B0287C28F627D9278A26E325A12571251929C32AD8293A2C042B44281F24C2244922CE220926B725602511254122BD232822AC2297238923DA214822CA228024E824C2279C312A30942B162A4529072A2F29D92763272F27AC26F3268E2566235E2567272729CA2AB92A7F27A5270326DF24032451258824BE25D7283C27EE276F27E92804280628AC269426E823DA267C26CF27002914289028D325E1220A226E235D224C25FA23AF223E23732270224521C7218A224F22AC224924FA245B25642776280033B030E32D392ADB2AB7298B29EB2834281C27A3258C260624B8268F24A826A427C426C32742267A2690250F256424942453259C266D264D27F92670273B28BC281E28CB2607252723F924AA24E9262B26D026812571234F2239216322E521AF22F5244A23BB227B23392378221A222D2247239023F62589265128D228E62B7A35DD31342D1A2DCA2B502A1229B92876275627A025C523CD24D82354263026F62759289F26DC26E525DE257C253624A123B6242228A727C226C2271E290429122A23298E2657253123612464257E2447254926F9233A239A2136235C2137233625C024F524D5230025DA233B2321230825EB24EA27C4288B27E327642A562B56342633112E022AC82960293A2C292A94287D276D24E225352482245D243226A5272E2843275C271829DE255A25762389256D241D27E7286A28E0285F29FE297E29F426D224C8247124472493253D255B254925D92337247C21B8230F24A6254E26D726572769273E266F255E2422233224BB254F28FA2A64294A28D1286E28EC32FD31242C8E2A3229812A802A9E2A682AA4270B2727239524B7233F250025EF235225C4250B27E626A6244623CD24BC242B25C327772A4729832A2A2B5C2A1828FF24942492247F241B253424B724B1235B23FF2439218322B5240027D52632277D2625294429ED25EC2621269E26A8265A27AE28992A4B2ABF2A6C290C286F306131D32D4129092AEA2A70299D2AF928CB28E1275327AB255524202692281F288C250826932654271A24F8232923D62278253A29802A9E2A482B52293B2A1E272D271425C625F423DD2440261925842254232D24E321AF2359264128BD29B628EE283B299E286E28D9265024F024B2267B286F2BD02AAD2A2C2982291029D1301D30D6290F28DB26A12898293B2CC32A46288F267825D8246D2621279127D126BC26E8244F27DC26B1257924E4238D230126B029F02AC92B222B462A1927E3259E2455254325A2245A236D269A25532593256C253624972487276229772B1F299C292E2A122AB6280D28F725C3258727F229B02AFD2B722ACB2A73292B280631DB2FC92A502888286B28512BCD2A4F2ADE28E6259B24F3255327402995296228B7254D2704268D26022754246E261626E8277529262AD6278D28E728D22554248125402517240023E024FD23CE25FA258827832615237B25B528D0291D2BCF2995299E2A172BF129A72703244C24B0260E2A402BFC29D02AE02A0D29F026D131C2301F2B43297C2ABC2C192B502C282926293A26B426DC27EE2A392BA72BDA29A3280427572616263428B2260927E0290B2A8A29D52906271B26A7264825B4240E247426312439235225EA268F2746267E274B26BD24F5269E28212B2D2DA229162B3B2A5929E8264A253A2528256227DF2786293D2C3C2BFE296E29B427B83145308B2C092DF62BC32D822C2B2B4D288026E1263829B12C0C2D6D2CED2B2D2B172B98289525B5261C2503264E29AC2A53293529B529A026C025B425C42363243F24BF25DB27C5243F25152A992BB128D6261528552796266D2A322D612CE42BEA29C4291F2AE328DD269D24F1226025772742294D2B5A2A20296328352808347F32C12D092EBC2DB62DB42A992826276E26F928DD2C092DC62C2D2BF62BFF2BCE2BA62A39278E263C254A2508264929BA28BA27D72908287A265826D2235E251D26B828D32804272D27A52A592B912A712A46283926C026B8292929B429B328022AF72673272D275D2423243C2555272C282829C82AC22970290D2834292E345A32B82D922C4A2CE32C102BFC29D128FF27A529612DD22BBB2A632D552BDB2A7B2C4B2913276125C925EE22A02591278B26C225BC265926F425AB24F723B526DD27D229922A22298529BC29FB2AF229D3295C263C2610258225E0261726062547254B25E523C2221025562454274529592AAB28EF29F8273E262727242ADA353C32972C712B182C882B3E2A6129B527A129FB28E42A302D3D2CCD2BF72B752B1A2DA92937265225A8249626E228EB26E727082661248F258E235C23ED24C72560288729792A062819285C293829E728EA27F223E423F0239624A2235C243A25D8241B2446230B2306243E269928682AC62A8B2943293B24B225F8267F299E32B6317E2BC82A192AD829422A6729882769261327482A612C652AD828A6284029E12822285A25A12400279A27F529572B3A289B25CB23C523812290229524C724A326D526AD26D926D128B7294429222796252E244923E022C5252024F823AE2453256B257D25A6244F26D32598271029FD294028F8268A24E424EF254C28D731D1316A2D752AB72B0B2CB12BEE29C9276027F326F4261928DF28CF296A2A8D29442A28283623612624267B29482C942BEB29E3273F239822A3241A227C244B262F26C924A924A8255B279429E227BD25C825EE245A256D254926BC250527032953286628A927E7269427C826A7264D279D266025F7230E23B9237B240F2948325332B02B1E29F82A87293A29002837272B263C26A528062AAC29E728C929872960282627E8254D2547275629BC2C9A2DA72B4127E8231422F622802481258A278E25232557267A2318254B271427C7246A241E265728862ABA2BAD28DA27E928452C052BB72838275D270625E2254D26F0254B25F225CE239A250728BF29A6327F320D2CBA2BD72A782DE4277028A627DA255E261A28512A672AF0294B2BA72992283B26E425FF240C266628232AD92CDE2A52272224F42300242D251E28F428AD27B7256F26A5249624EF232424DD236325B626772AF4296F2AC9285428BD28C62A342B2E286225832509258C25372787278128592810285127E226462B5E3478303D2B442BC02C282D292D222ABB290328AA278C29B22BC62A2A2B4C28DF26382513277526BE25D924A527B42A772CE1281E294326CD2273261B27E628852B0D2B102A1B28A2230123EF222F245E238625F1278D298F2A982AE4282828BE2A3B2A612822261824482441249625F928EF2A6F2BA32B5828ED256128292C8235E42FB42A032B492CFC2DC12D992A4D29D9298A270F2801294127E825F3266E256D24EA26AD2690270C291B29BC2A452B78280025D4232C25C626C8283C2A8D291329122A59290825B92364234622722422258D295F29EC2A53284028E127C7286D29132806263D2481259C23C92595297C2A7B2BAD2B3D29C728C3283C2A9E333A2F6D296C29AB2B2C2D982C1B2C132C6F2A7F297627B4268E268126D7255524EF241B28832AB72C9929AC29372B6E2AC729EB26C524FC258E28C72667297B28F3284C2AE82AE5273924AB2183239323312541282528A329872BFB273029572A9F28FB2535256923F826AB268D26C229182B852B032D5C2AB129E32A572AF632872E012B3C2AB42A202C732CC22CF82BF62AEA270F263B244F237A240225DC246D26DF2A852A6C2B632A2E29352A672B9E28F225C025FD28312ADF294D2AE729012A7729142ABE28E92446235824EC229824E6257829292B2D29E9292629DA276A259F2517236C248B2789267C26762A732B012BB62CE429822816273C28473291300A2C122C972B98297B2A0F2984299A2A60291B26E124C52394247424AF25D8277F28302A7C2B3B2A942AC42CF92A67276026DC278129592A702A2429D1272F286428802943277C2484236F220D23C224B4273728FD285629E127562676267A25B125A3251126F2273F2703281029D729A72BD52B53291E270E265D27A332ED32882F5F2DF12B0D2ABF29A828622787280128C92702259B23F023E7258A25432998270429ED281229F22B942B802BC628A22666268F285C29D2262126B42604280C2835293026AC24E922862334246F263D2945286128A7286D2624242E2572243323B4254927A92971299D28672A592C682B7B298827C82630273D2A253495327E2F362DF92B2F2B4E29E82608285C2A4B29F2263D258523A824B82626292A288E284829782B772C1C2B8E29822609265027F927E628C5265D24E5242126FC2739286527C82509245C241325AA261C28982A3A2AC927A127F3267024AD22BD211526CB26DA29052B1C2A7729012B152CEB2B4529B4255C26BC26EB29E0354B33CD2E9A2DCC2ABF2AE12AC32C512B4B2A9E2789263E25D125FB25E5278B27362A262E602B782D8E2ABB2ABC274E2618239E23BE26DA2604260B260426FF253D268C273626752592252725CC253B27362A132A622A9B2A9C2A7E2A80265925B324E627FF28A42A0F2CD52ABC2A2A2C3E2B3729CE2781254A28ED26502B51348933782FED2CCF2A162AFA2B8C2BB8298329FE270A271C257B262B29AC2A7B2AC529482B4A2BC92D7129332721269525E3228E26242720287A280825A326DB2735297F2A6527E3256F2672286527302644278A28DC2747289629352A2528DA24AE249727F429082AB52D592B4D2ABB2A392AE9288125F22302267429B32B2A35AE31252CDC2CF229F22A4D2A7028BF2554278727B92625270E2A262BC62CA62B8E2AE72B7829B32A90283824FD23F022E024E424C8284628CA2762256C270D288028F52876270E27A5282E28B5278B253D24CA240424ED26902ACE29EB2651248223BD25E727D729E7292E29852AF52A5D28D025922699245F275929222CD93793321A2AA6297529CC2A1929E0263E2782263F265E281328A628932A0E2C122DC3294B2A062AB628D823702375234B24222597274928CF277A258C259827152835290E2808268426D226A427AA25DA230B2589240A24D6268D26342790239A22892441245326AE29312CEB29D42BEA2D3B2ABE2669263E250F29212C302E5F36A130612B5A29262C992D4F2B47281927E9253728532AC22BA228D32AF1295629F5279126F1261A265E26132323240F248D2392262F2A5B2637259925ED257E25FE259325FC24A4261C2678254F252424F825A5270126B7251325922544235A232B25152567279529752B912A842A022C192AE927EF27C4268029472DFC2C9A34E9316B2C4C2D8C2DD32B942C1429A628E2297729BB2A442BEA2A20285B274E261929CE2871289429942701260624A725692525273626B926F024C4259526B524C124A2263625B727B92798272F2578252528742919287026A124CC24D6244B24FC2496255F28DA266C2A3C2A5229B22BFB299D274528C326E3278C2BEB2D5E359730E22CEF2CC62D9D2B732B472AFF2B1F290F287B2A6827CE27B52651285228CC2AC32AFE29EC29F129B824EE25D4255429D2293A287C25C9246825D4269E259B24B026F7264C29D62A542A9D2BC4298F2AAE2C8C2AFE279826D5253A26A726E9254E25BC26CC2734281F297D2B632A82267922AD25D42488277228922A63340F327E2BA32B232BD92B4A2AB42C952A022A442A3129E9256325EE25C628A029E52A782A9B29792AFF2760255A246927AC29D5298A296A2733262A26772609255C25CE26F0274D29C22A382A292C602A602C742C722B4C27F226A625882749294028A026BB2715264C2AE32A942A0D283924B62463258C259B284B27E028D0321631FC2B202B2B2A832A112C342C612BEB29A7286E27BE25A126B32586292F2B902A372AFB2AFB2A3728822578273429592A2B2ADA2A392864295429F0287A261B2503281D2BE72A242C8A2C712B422A312B642A89285026EF240E267B2898289727E226AD27FE27802BCB2BE62A7328752355256624AF24D5271A28882AD33687310B2CD42C8A2B732C572D1F2C4F2A062964264B267F24A8252A28132B4B2BBD2B0C2C892BD92A892758268F27A12B2E2F9C2C1129F0261429E22A2229B728EA27892B452CCD2C6E2C672CEF2B222BE62A0D28E9270425F724BF2539261B28FB263025792751271C2BE7293B26D3267325EF247624D325B427CF2A212E49370432842D032DD12C0C2DBE2D622BF72A6228B9254226CB257027892717298F2CAB2C802CFB2BD929D92736285429D52CBC2C212BF0291B298427422A8E274D262F29CE2CC52CF52B9F2BFF2A822A1E2ABA29522887243125D923BC24FA26AF265326E9246C25A026CE2842272E2644263A26CE258125FF233127132B9B2E1037E2300B2EAD2B1D2C792BC22BA32C292BF129AA263126E425EB28502A4D2B81292C2B062BC32A1B291126B6281B2AA02B342B142BD6279025D5240026C9259C261A2A2C2CDE2CC22B57295E29D42BA9298F28B925112573251128DA26CD262626CE26B8264E2794252826722561267A288F277326D926F626A62889292C2D653515318A2DB52DFF290D2C632D012DB92A0C297F277327D628FD29192CB929EC2A042ABA2ACE283928A52552296D2AD62BFE29F92AED26CF23E8238D24D2247826DE273F29F82B97277C27DB28522B3429922890268D246226872BE629E829D1297629B0275525F8253B2651270729D6295429C925CD2939274A29CE2D392ECB352932412BCD2AE629B82CD62FB02DCF2B1D2AC327C728C52A942CA22B622AA627A22A612CD429F526F228D32A122A2F2B782A0029F1283A256223C522F5243D26CF277728F8264C260A260828562A5128252788274C27F728B92B982CCC2A742B962801278424E224E9284229BB2A682EA72A2D2890282028B829902E872CF236CD31412D3F29122A312D7D2D262EBF2B5D2A63292728E129FE2A482A6E29032AE92A442C7A2ABC296F291C2CF62BD828E2270F2A03293226E3245924B625D3271829ED283426A524CC2611291328A8279128CB273B2AF52ADB2CA42ACD2A852AC429FE242A241628A72A5D2B382B6E2DCE2C0A2D7E29DB289629092D1C2EAE36FB31DA2D412B542C4F2B922D1D2EC02B632914261A2A2929322BAC281A2896275D2BB82BB32B47291A28AE285F275A294A290B2A932A7B266825B9250026E028D82AE92AD0275B268929F028AA260A252D27B8296F2B1C2BE12AAF2A132B7229632957260A2522265F282D2A152B7D2D262CD12B0D2A3A2909297A2A7C2C2F354D30E42D522B9C2A162D352CA5295D2A9826B6265C286528D929ED272228C8271329F52A34295D2996275A268028E228D0271628B7261B260025A125D727F129AD2BE52BF72B532AE627472741267A240B26D82AE6289829982CAE2C9F2BDA29F525F6239024FB23D0287728572A5F2C9D2B3D2A0629F3264527372A8D2B0334B531FA2D2D2DB92CA22BC82A52280A28B92510264729D22CB72955297A286428FD29A22A6F285729A628DB25FE28F427CA280F294228C12469252E281D297729412C5B2C742BB4297628CD26F726E728A92A562B192B582B1C2BD02A722BE527FC258F2642254425C3266727AF2BB32A2A29B428FD28F7264A27482A6F2BF3313832492DFB2C032B1B2BF32A2C28B225D425C22597278E287729B3291029E92A952A6D2BB329EF2A8C29F0272E28362BFB2905299D26C0258027B1288D29CE28B62A3E2B74299B29C2273C25F0279928212BE62CCF29932BD12A2C29072BEC29A9282B27AA25DA278927412A9929BE2830272127BE26D328742B8A2B932A6E32AD309F2C5F2B332AF02AC22ACF271524BE2551256D27722989295F29FA2A4F29D72A7C2DA52AD8289F278E265C29B42B522C0F2B502AC9270229722AA12A9A2A062ABC293A29DD2434259127A929DC29672CAF2BA42AC928832AC129A929992AE9285C2769286F29EA2A9E299229D5298527BB288729112BCD2B292C922B54325130172BBB2A7E2A0E2AEF2999272D26C6265727CE275A2B2C29B2289F2A832A972C202B6C2A932896263827EA28992B822C7A2CC82B3829F62AD02AE32A0C29FC287E26E5251E23BB24C1267D29372A062C262B1F2BD4284529B0261827982793261926A6274F299A2B5E2A112B5829F1271C296B29B62AB82A152B3D2B30345E326A2AD4281A29D629982A4C270926822732282B29EC2C662A96298129322B222BC42A91296226E6252C2680292A2C712C152C082BDD2AF62A482BD5283828512900277826BC22E72459279A279D27E8271D29E9261B27AB245626EA232A241F25DF234D27FC285929FE28022833286629152AC32A9D2BA92C872AE22BA735A0305729FD267F27BF29A82AF329E927AD26C927A42BB42C0B2BA327CF27302A382A81290329162705245424C0254B295B2AF92B092B762A0E2B7529192A132B0528F1253B25ED238326E325F624C524A2260F26FF26CC251525C7221E2392225623AF23CC24C22723290129E5272C295528BC29512C932BD42CE92A102C4B363F30D82AD327C329962A342A7E2BAB285B2718292B2BAC2C4A2AA129D7289E29C72BB22BA6280C263D23AA27D626A5282428F02A642AAB2A042B182A732789264B25DD239D25DE247F25CE267825F624A625BE27EB2860272326C9240E2483242A258424B82616298E2BC729CD28832730290D2B2E2D272BEB2B282A902BE536C531832C172CF12B8D2A4D29D7284926AB278E28F42BE72B2C2A052AAC270A2AB92B1C2A3F28272779250F266D29932A48285327B626B227C227CE24E32522253625F42463275D265126C326D8250826C827652942291A2733288F26582406256B241627BA27CD28D62CC82A442B5E286F260C2A5C2DDA2BD92ABA293B2B27352831252C3D2B90290E2AEA27CE24122616282729992BC82AFB2937298D2985299A2905291C2886284F277C29C12A622A092698261B27CF26F7277D25B2254E2577254F26C727A928892643265F28CB283B29392CD429C828F528AF2880287D263126F725AD287B29B12C592CAC2A8C290326CE27232B252A9729A02A3B2D5D3691300F2CD8283127D126D925B02577281C2A8C2B9E2BAE2A4F292F292929C62A7228E927F5268927C529A72CBC2BDC270C26C7257B2781280A283A281A260327DC28DB26E028F4270E2689251A28CE296E2CD52CE529D12A9F2A212A492CCC2BB62AE828C0286A2ACA2BC22AD529EF2AA5278C268E268C289C27FC28A32CCF358E31E12A0A296C26872593250126E2277F2C8B2C2A2CD8297129442BD92C002D312BDF28B128AA293F2B3D2BDB287926C5243E277E29CE29A62A3D290C2BE02AC32A27297327312576241E26E327C327612B7F2B842A8C2A5F2B262D902CDC2CF42A192C572C56280929F428AB27D12956276126B025A323B4255A298E2B3C352230232CB72A8C292D27D42504271729552B482DB829C8280729CB2A782C442CC12AFF272628FD29FF2AFB2AF927C125AD255B281029A228DA2A5E2AB72A192972288B287E270425A124BA274C263E29402BE12B08296E29752C372DF82C0E2C7A2C7F2DCB29FE29F527EB27D9279329EA280C287C26BD25B727B129262BC133AA30082C6D2D8B2AE22847272E26322AE92CD02B0E2A4E2873283829CD29B32CF42641278A288E2955293E263226D92537241B266B26E928152AF929822B3A2A0229E32605250725C3254C2612275727852868295D29312B7A2C422D912C662A152A5D2B732AD5295D2A512811290B2B2F2A4328D4255D2507279628BF29C1334230FF2C2E2C122C88290D27722630299B2A6A2C6A2B3D2A082886282E28512BF828402728275B28A627FA256725F628462636282C28D4275D29452B7329D929D3280B2704264227E42790287E29A328982760280B297C2A662B6B29B5295C291629302BC1295C2A122BC829B42BAE2AA028F227BF26552444268E269029B4321E31612DDF2BA22B8D29A2279C258B27ED29392C092D162D112CBA29972A262906274727F927742875283A2788271A28FB2A9A2B202A322AF92BD52A7929152A542841250B25792640287F28D12909294F2A0A2ABE29E427E32719278D262C29E2298B29A529CD2A652B792C7D2C0A2CFA29DC279D272627BA289228BE29CC33D430B92CFE2C692BE32948282B24B424E226F229682C3E2C5D2B292A392B5B293B299C29F329BF2827285825DF25F828C728402A8B2AF3282C2C782B5D2BD8273B261D266B288B28CD28FF27C229592A702BF92B69291C25EA282D26AE270D289927572977298E29AC2B202C2D2CD42AD527822798274D296729482944294231D930502C6429402A632A8228E2252F246B266629292BFE2A092A902ACA2A1C2A5528382AA32A1C2B3E290D260427FE28672A972A272ABA28982B832C342C7C2991278A28F42A952B862AF927CF29832A342BEC2B3B283327B52611287B28F3275827BC27A5278E29A62BD82B572B2829C326892786287E29522CA72B922A4F321033DA2AB329E828C72766264E24692585249B28832A6F2AF0295C2B9B2B8729FC287E29632C8E2B5C29A226AE28222AE32BBF28A1271226372A6F2AAE298D289B27E1294A2AF52BD62AD0293629CF2AF42DDD2A41292E264E2847295329AA299627D5260226EB28622B502A342AB827C526272761284F29522DD62B7B2B6734A731D02C3529DA273027E526D6245324B42461252B29FC27472BB62BFF29A52AA529812ACB2AA22B7627DF254B29B72AAA2A6B28AA26D527CD27D027BE288B27A426802850291C29D42991289E285D29E22A022BFE28A625B02A152BB22D982CC328D226BB255127BD2A872A0F289F25DE2442268F2BDA2A982B592B3C2C8332F832212DFE2AAD29F22A622BA4277E274025E025E6271729F62AF92B602A4B2B952ACE29A42A96286B26CA2665281B2A5F291C29112787283628B127062711266C268D274829C727A3261E29632A41284029902BB2297229B42ABF2AA62B152B542A60276A26DB28D7292029F3269526C324F5240B28AA29442B8F2D1A2DCB334B30272CB028CC298E2B512C9329CB27A3243825FB27F428492B172BF52B3E2A332ABE29132ABE27E7256D257728E7294229422986258C26C72529255E25C324E9232F26EA278C29AF2A612A6628B3269F27D8275826AD28B32AB42B592CD62A312AE02589261927DF27F427032566241126D126ED27FC27122AD52B4D2BC2343E313C2A8B28BA28212CD22B1F2A312711263E252726B228D72A7F2CE12B2C2BAD28312AE428F127F32506243E288C2745285B281E27B2264326E0268B24D6234025F32698281E2A452B362C572BAC251727E926FA271D2BE92CD32A7A2C902AA52A762778263C267F2941291526DB2456263028192AD12A292A432AD82B49347C30B32A9628E5289B2A6D2BD829FA278C263F26FA25B82683286F2B392BD72AB3296829E3295A287E25ED233A25AE268528712A32274B2660276928C7269C269B267F263C283A29642AE5295428C925FF2574274D2A7B29402B322C722A112C1E2B0529CF277D246B27D4286B26D6262F26FC285F2B0C2AE72AFC2AF42AC2345031FB2B85293E2A092CE82A0A281027F1266425EC2605278C27D528602BFD29EE279D2A132BE027DE259824F8252D28AD27F1296F299527222ADF29302AA42A532A2B2917295727012982273A259123DD268E2858294D29332A30288729AA2AF329ED28D926D4263B28E6248225DE259127552899296A2A852A1129FE2B3D36BB32242C1E2C252C482D0B2C572A3528B925DA26AD250A2701258B27C829FD29812A152C94294F29CC25B52364246827C828E8286F27CD277728742B2C2C822AC22B3F2A74276E25F22723268424F424E625CC2A6E29EA2717273C268329162AD5299E27A32425253F27C525FC25B026FE27ED28162ACC281C28D727D6291F355D31222CE92D5E2CF32BAA2957299A29522809280F2996271C253F25B826CD29B82BA52CB62AB1291C279625AC278A2B642AB9292027CA265729D229702BF42BDB2A38298F2846271B2765246223A1254B25FB2A062A652706281A27D0260427B427CC272C28B02490261126562694259A26AA2865292329E929F82A782D73360832592B4C2AD62B1F2A99294B2AD92A2C2B182A54297929AE262B25C125F2289D2ACE2B352C3729B0278C26FE291D2C0E2CB2296128C1260D29372A552BA32B97290C2A5F29FD24EF256923202449245A25F8281B2AE22A652A462A842BF529CC2A662BEE29C827CE250C26E62536269D257E28DE29E328F328D72AE82C8534BA31502ACF289A270C2877271C2B372BBF2B7F2BF82A0C2AF426EA2365269F27A8286C2AFF28732824263D27992B6B2D6E2B632A04286328E928BC283A2A0C2A2D290E27A226C5244425E8231626852527261529B829832A002C8929A52BC02BE72C942BFA2951261F28ED26A5260D287A27422754284B28D926A029562DD133C731F32D9D2B4A2A2F299727E92B302B122D2B2BF9277F28A028BD25C624C126DB272A29F427B8263F26D326BE296C2DE02B2B2BA629F1280828042A112A9F29C0294F297B273224A226B92600272F26FF284B2A9C2A4F2A392A2F2AB82CC42C3E2D352CC129032A0D291228092825278D27C929142ADA26D525FA25DD287933FB31AD2E562C182919280027C228512A6329DA281428DA285B286A25DD2401268D26C025BB2894261C2737262729552AC329142B1726B82582274B297B28452A822BDF2B6228DA22C9240725B829D1279A27372926290628EB280A2BA72B772C522B4F2C722C0929772A1D2A3E2A57285529CA2727284726112515268326BC311A329A2E212B9629EA275F2681270C2A8B2A62281C29C22A6E28E625E7254225952468272A29462A71273325BD25572777291E2BE427A6250D2771285A29892B4A2B662BBD280B2431240427F4282C28F128C2299329A32A2C291F27112A8E2BBB2DD02A8A2B2F2BFA29BE28BD28C0279825AB28D62704252525B125A5276D301E31D62D432A6929192810282027FB29312A2928F4263C2801285226E8247E25BB248427C929CA2CFA28B125B727B627452AC429C72767258A244F2638272629CD29A72A7129DD274726CA26DA27A9283929232A552A592A1E2979270427DB27FA29012A302A7E2CEC2AAF283E263026F526D2275A27DA2557255125B0264F2FDA33C52BE228AD279928A1271D2AF0299829C42BEF2851280C27AB245C25F2236F246E284928652A20297526A1258C275828AD28C526242355244925E3254E282C288B27B4263C27EA267D2798264E268028EE2AD02A6129FF29FB2638260A273C270F26DB26052773293F28D1250A268A25A22729286526A727CF25F025AA309F317D2D242A1E2ABC28602A6B2B5D2C192CFC2AD32BBB292B291D296426A525922464271B299F2A3B282B277D27BB2612282B2A652894256B27CC25572875269B28F5275C28EA2923283027D4263E25D52616299D296029C928A3266D252426D626C82529253426FB271F28F126C126FE248D27822871290C2A2A299A2950328830E22B2B2CB829232B8B2C862BDF2C782BBC2A262A242B262B252A0729A427C224A3263928612ACF2AFC271F26AC261A2BD02A352A79283F27D2281929C1272B27E2273029B8288A274929F426C823E9258629DE29F02A2D29D8277728FE270A259B249C258027702732284026B126CA25A2254C28F0298B29592B0A2CD132A02FB42C482C312E842ED52D982B462E6B2D342C5C29EA2A2F2C0C2BC12A82286825222518288C2A9729D6280F2687270428722BB52AAD296D2AE72A9E291E2AE22716257927A027F426F62774271B24C926E228FA275F26E627FF27E2285F28A928F226A62545270E296A2AE3289C26A1265926732840293D2A0B2ABC2A2634AC2F832AC12AB12D852C062EFC2BF32B482DA92CBC2B622BA82C702A962AC42745252825F7264129C52BEC28892823277528462B8D2AC42BCC2AC02A842811268926A6262125BD25CE25932673244223EC25232541271A266628DE2AF62AFA2A902B6E296B29A0281E2BA82BC529F52817269626CB262E263C286A29892A9C341530932CDF2B892A012C582A192C192BF62AAC2B6E2B652B292A452CAE2BF4291F278525B3268F29312B502B3F29FB28852AEC2B792B6D2CCE2AA7286A270F264827A0273A27EE25D5250A261D254524F025BC26CA260D2794283D2A7B2BF229802B052ADC264527AF2AFC2B67277C26B624B0263E278226F0278E286C2BB135AB303A2D1F2DE42C602CB72BB32AD629612BB72C3F2B512C3D2C762B6A2AA52916275E2704278627EB285229782C7C29D9278028C729FC282829582862264027F5268B27CA285B27B4262826A9256D24A0269D255327FD29302B572ACD2B7D2B0A2B202A63290826F528C928B82775273E258A271029282996289E294E2CDE3306333C2F2C2EFB2DD22C7F2B842B7A2A832DA92D742B5C2B6E2AA32BB32BEA29082977263927D126E029432AEA28DC267C28212AE829312B5F2914285A267627D6270D2A182BE228D329E128E3260A2678260027BE26B1287729E62A0C2B182D382CA32AF328FD273A281A28862684264E2643270029CB2984291B29442A19356832472F8B2DB32E712C9D2A302B452C6C2CBD2A6E2AE129B929A92B942BA92992291A287B293D28262759280E28362810283D29522BF82A17287C26D72579260529B02A532A552999287C2A5128DB265526662598251128D529AF2B8F2D812C2B2B42292C292227F228BF27CA2651257725A628BE2A562B02290A2AC62A1835DB30882E022D0F2B3F2CCB2B9F2B362D892D0D2C1D2AD42ABC2A7D2A592BC92B752A9F2AFA291628F626F62ACA29C62AA42A4D2AB5299E29F827DB2655260928F12A452BF32AA529FC26DA26A62709272F2700265125F4258C289628582A4F2A7E29A328DB25A82470268C2810261C253B25DC29E52AC4297B2BD029382DEE352B31BB2CBD2BD72BFA2A232BB12CCD2BAE2B6C2A9128D8270F299129432A112AA6287827C628B127732747295D290B28B82776291329A02671268424CE256027E329F32A442AE8270C26422711280B27E526E42637258624E726AC26CC2680260F272525CB2478222F2577259224AB240F25E328C72A432AE929FA2A562D23350A32CD2DA92C552A562CB92BED2B7D2DDF2A222A05289627DB279226D925B326CE269D27FE27A02768256E268629AA280727D22786271A251825642398244628E029D82A322935261B267D268927CA27F8277E27FC23A423E62337252C26BA24F8244D2456247D235624E0235225F8243C25E62762297827AC27A6293D2A7E340D319D2C272DEC2AC32A262B2E2C792C592CC32AE0271127AE26EB278227522639277327F225F8258024F4244D2680255A28C2285F270925162452240A24CC268F29BA29EB281127CA2594265A2714298F299529FF25E1230B257225BD2448257B2429254725732442252B245C230E2449269C27F5285929D1274E286D2951341D31212E3B2E7E2CA62C562B132C9B2B502D762A7029562A202AC4288128102A8029D8287C25B225D423732318267926F827992AE728DA25C725492326234224E928B829ED274F2694254C278A261829292CC629EE27CE241427F126FD264A2869264A2636279F265527962563221724A726F126112A8D285B288829832BF333942F412DA12B112DBB2C062B292CB52C172D802B922B322A992AE5284A284E2A002B792A2029FA263424FA23E223E125D52613280829E32842281E26B22481254C2841291328D72560258926D3266B26172BCD2C5C29F626672816284F28B32A682B75291F2AB229BC291D26362469243E260B284629022876289B296C2CC234B52F262C342CA529FC2BCB2ABE2C892D902B782B762B482B192A40295D2B152B7A2B5F2A382DB62835269B22452350247824442565270528D7268A248A22F323D4258A2595241E2557248C236A269B26892B752A2A29AC2755285D29CD2A062BFF298829F92BFE2A6A2B922705251123572656292D2C452A9829B2298E2C36356E30A22B832A502BE9295C2A57298A2C862A122B6B2B272D862AD729A12C792CB92A062B6528EF29C427D221F323B4244025E1243B2464256E26E4247922272321223123F823FD225E22712441257926F329222991281029112AD52985295F2CF22A2C2BE429622AB42A1B271125E4258424D627D12A1B29D028FA28862BF233C930082C162DBD29E12951290A2A672B0C2A892846292B2A7B2BEA29832A9F2BC7284928C4274329F2279624FD23282387237A260B26F0259B259725502316223B236125D42340242F2562239D28ED28852B762AC6288327B5286029542AE72B252C232AC22B902A342CED27792611243026EC27BF2B2B2A1D2A5F29EF28C332BD2E522CBB2A3A2A04272329A829252957290529C429D427F1269C278B2652266E288B282429EF2905276C2501253725D92615299C28E327A5273B25F224E3233C22F622DE2235233325C2266F279F280A2B982B1E2975283F29B82A172BE42C522D8F2AA8296B2A6A2C7A29D02775255426FF272B2A362908282E27C9281433062FAE2A0A2BBA283527E927D329DD2BEA291C27F027B4265C26D7231C25A226C126FD2ADB2B672BC228CB2684246B286529D52A3D2AE72AAD2A60298429622866251D24B6225F244E25ED284B29F6299828C62850279027B0294F29FC290E2B5E2B822A492B1B2CC02C892932272B26FA267928112A612A7729F9282928FF321A2E5A2A0B2AD02A632908292E2AEE29022A4527CC260E27F0257725D726CD28012A9F2BD82A5B2A532865257F264F266E28BA29992AFC29462AB0291B294B2827262522A0213A21B226BB2683286827A726A827F124C325FC27CA29722837293929D128DE28602A352AEE27A327DE2653274D29E42A652AC72916291C2B59355C2F552B1C2D812AEA28FE28042AF22A922A072A6F2A6B2B4E28DF2531286829BD2ABA2BC72BCB282D274024E1248627A029062B912CEB29C529F9282E27302844269622BA223F22A2240C260C27432688262D257B245627332A8F290C291A29C229DE29A027F7284C2A2F283D25C6242D258028BC2A862ADB2ACA2A292CE0340930782A992B292BE6299729DF29F029512BC92B062BDD2A8B29D8272B28A629052BD72BB62BE1283726A32460241F2715282529EF270929F82744275128EF27DF266923D62278232C25D825C125AC2758285425A124C327D2276629692AA628DD29142A1E2ABE29DE29BB28B525C225D4246027FC2AF72B142A8A2A022A4E34A42DF42A462CC72A6529BE282B266E28892A442C082D0B2BDF2BBE29962B362B362C2E2C5A2CC8284B26B02344255C299B274129132801286C256D2661287D27CD26032592229121AD230E256325B5257229D52604251625F5276828FD28B62BCE2AFE2A6D2A3A2AA82B192A3127F724DD244B2528291727FF26BA26872731322E2EF92BAD29632B15291A281B27F9264C2B3A2A202BF02BF02BDF2AB72A832CE62AFD2BCA2B342A1D260B24B8241D289428572872260B26D4261327D926BE276327FE267F237B220E2389247C257425D827D6283B264925072889271629D4281D2B2629072A3D2A592BC128B427EA23DC252C24DE26A329FC27DB262E276730A82DF62AA42907292B279526B725D126A629CA2A842BEC2A0E2B622739288128182AD42C022A332AB3252D238624FB245827EA2692265023EF260A264D2A2A2A002AB72717266523B5249C23A524F2250A2755274C26622454274626BC285D28262AF72A832CF42B1F2D202927284B25FC23BC235C266F285129082853271732932FA42A4C2872271A2712279E247026D128EB299A2BD22ABC28A82896299229512A2D2CB82A4B2A4A250823F2231926BA267028E925162417254D27522730294E29E925AA251F26FE235A257E253F23F927F528A026F222B825AB26CD296229802AFF2A312CAB2A0F2CB52AAA2756246925C7231026C0256D2713255B262B315A2E8629CE282A273A2537252C2681255F286C292A2A042B0F2AFA2733296B287F285729422A03285C242A243C24FE24622512289A26C9247525E527A0279626B626E22590270627C1262F26682474231D2423263226C6238523BB24EF26D327D428292B7D2B0B294128D02645258225D923C923FB246124EA26CE265E27FD32E42DC129312A0929AD2721273124EB25DC282F297F2A492A962ADB28D1276628A32725288C2A402971246A220323CB23FB235627F2256127E3260926A32826271B261D272B29EE27CB282628AD2451240C2423269226E126042682240A249B24FC27C829E22A5C282C271B2634269E25142346230025DB248127E0267A276131162FE02AD629E22B3B2B2729AD276E27D529DC28AA280E2B142A4A2AD028A7272C28A1288A295629E42591239C244A244B23A42675271927E4272F2A632BC12AC429A0283327662876297A292E28C325EF2568267527452789267B259B2354259B263A28D3288C282E2863285B287B298B255D2405253D26C727C5272929E332642D902AD82B012A3C2A7F294927F225FB277F29242AC52B772A5A2A64287728EF26BB283E2B4F29782713245B24A4222C232B26B026F628DD29D6281B296C282B28E6259726E12632270B28FF2738269D250F2554256329A229962633247B246F2673267A28F3284929FD282A2900283E26F625712333268727FA268226B032D62FD32BE8297B290B299E277C2632267327FD274C272729CC297029E728AB243426AB28302A3B2B71292726E2233522AD235626FC28AA28B62911282929A02AC729A52701279724EE263B28CD27EF25FF252A2650264C28E128F1279025CB25BD25FE254F262A279C29F229FC2A782BA326BD244125E4230E253228972743339F2E2B2B842ACF29C028A027B124F8261824B325BD26CB27B428182AA228FA2473255529252A592B6427552482230523AF220326A028C128E9298E281B298F29F1290E28FC25A524A52681282328A026A724A5256F25FB25B52665273727C825E72541255B255725EB281028B829A628F925C025F7247F245326C7253227D130592EED287E29822BD629DE28EA256D2513251D24DE26D42669261E28E5260C2677272727DD2A882CE828902447241E24C32139258C27F3289C287E264D27ED26F427982700282C251326D927CF2841261B25F9252223E4237D264D266E278A263524C2238724E624E6263528BB27D0286827AE23BC235923F822562460259D2E372E802AB6287429E12B4E29EB285826A425F625E1242025F326E3259B24C52652276728C7290D2C4D28E92309242624F0221B24ED27A82A6B2998283C26D724952761277725AE2356276B263B285325B225AC24BC227F23462564231D27FC23C02664260E267424C525AF252127372960279C23E1236D237024642412261F318A2FE5297D28FA275E2AA229C72AD7271826E6243125E623DE24D8239C24C72499257E2600270529C1277224562373242524FE230726BD25E4282C2764272925982452245D25C4246323B327A526EF24A3246224852264249524E6231B231A246C24BC241A275E258A26562522258F252A26C3249324E3238223A5230525FB303C2EB229012A5727B426A827BA298429F228602580244E24EB23C125C22592236B269B26CE276529C228B124BF235622D02284240E240B259329D82913288525782522269924E6239A2350266825C8254B2519254F234E25D4260B25CD2441222525192635279329D5284326C2245B2601259224092475212D24442468267A2F1B2DD2280B28BD26B625E4266129A52A6329B125C824FF2480233A23B5240A263B2680254E266928892863252E2395225723B9229A2227254325362834273E27FC25FF24EA254A246424BD2685266A25FE24C2232325B126C827F2264E24B3258A247F234B26F8295D2BE226AF24B124052532240225F422E623C024CD25512F512D752952268F256B245624A3273B2869281F25E5241422A02252227523E523DD258D25D9263628C2293E25E02370251124BB2376238123602583250F28D528D92689258F26C2237B253226EF2533260B252A25FF261E27412A80281B254C232025562412246E26D4293E295F25F124622498264427AB24B0230925C8260330762D3D2815274C25A0251025BC2472260628B32519257722F422B621CE223523552373259E25A22700275825A8239123B9220722E0215024E324DA24F72577260D27E726A9255A257F276327C726DE25C12337243023FB267D299228B024F723A323CD22DE2484277F29F1261F242C24182728260527652418231822172632317E2C952656254B25A0244D238723CD259224A525FB231D22A2219920592171230F243C243327CF28E928BA2579250923DB21B222E9234A240C25AD2433241126C3251427FE243826DF25F127FC253E25D8230A2308223A2422282A262725F523E1225223452464261828A32769268B2220241E27C3279D26E724EB24FE25EB2ED52C6B272624F724B9244323E5233F24222598265A252222E121D421C0220C24BA24502646272328C5299E260726E321F822592385216D2462247B267426842769263F25FD25F5262826D628F827A4257A26CB240A210D25FF25D5269525B9257F233621DC24E1253E26ED261C24E423F3246327692813250726F9240B27C02FE12CB927A724CB237224FE23362384254224CB235D23D4221021E9208322432493233825B028282771291B28AC25E92256233F2478229523D3236F261C27E1287427F823542510250E26E7281E28A7248A25D9239A23AA22C426602616286B245323DB22452383233327E2244325362500269A2593265B268D257B22C9242E30962D6627C523B3240F241924372361251B251124C323F92347228020B822DF227A241925ED2545259C288D2660250623692236246C22F4204723DF26912679279226BA24CA257124F324A2279D266D2462251425932271230A244B25C8251A24CB2328223A22032203252326DE258525A824DA25F0248D23AC236C253F26DA31602DF326682592221C252725792334242625582461250E249A226721B32297214322EC245824C723E925A124B624EF22DF21FE232423F52141235122582446258C240925C0236C2490253C253925E025192550236D2322215521CD24192557253A238022FA2187212F2434251E26422656234726F82484223A228D243426A62F ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 403F ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 0009 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 65289F229522A12011216920A51FF11F5D20DF1F431FB11E8D1E271EC71F311E1B1D631F2E1F2B1D741F251FD920721FEF1F101F38200720751F681F1E21A01F831EBE1E1D1E5E1CD01CA81EF41D691EEB1D7A1F141EC31DDC1E201EA41DDC1E5E2032202420AA1D4A1FD51EB11DB220D51EA0211C21AB20981F21223E23442EBF2BE623B8205A22522286203621CF218921CA1F11214620281FE01F661F191F8D1EB21EE61ED91E491F0A2199215D22E01FA721E01FE520D21F9820E520441F501F8520591F1E20681E68206B1E721E6120B71F791E771E141F3721A720D71F2D20742077212520612156213B20B52092200E221F23A3220723DF22D824F12D642BDD245B231E220221B2203721EB212E20FB2276226E227B20F01F532071201E20D6203A203E1FA91FE621472117211B22632243210421EF205A1D9F1F22218E206321612093202A1FFD1FF71EBC1E2A1FE41FAA1EA61F3A20E51D3420BB205421D0215321502097215921BC215E20E72045210024B9218B228F22A225782F3D2CF0278D24E6214622EA21FC22AC212A2140210C21AD205E213920CA213F1FC220B92099208E228520222180207022FB21D222A12109226D20401FF81D901F2E210321DA21791F551F3720141F621E991FD020842023218920A520EF217222B323E022E22222227E218620332038210A222922C822EA2318226D23F724F92EEF2C34267122C321AE212F220322F6213D22E321AF21D021A5204E20AF21C320841F30217920B7200A217321D7235720D820D023BF20591D2020B51F361F451FCE207E21CA20881E3A1FBE1FBC1E8520A11F7621A51F3720E920B02117212A21CE22E022BC2364212922FA206A2149218B218E210422B120C3219323D723EA2D522B272616232124BB213123CF21BD21F9220B22742201239020F520A1219821AF21E42085206A2231215121CE22EB2298208E2164200E209F1FF11F791FB520B92022217320F01E2721391F8020F21F5F20732040217421CD20E921A5214C2255237123FE2109228A212B224021AC21FB201D221D24C722F8218B24B625BA2E762B73247D233323C0226A2286238E22202202237C22CE21FF216B2186228022D8223A21E62149215D2361233022FC21E11FF71F922055209220F41F83210B214F200B21AE202020A41FBE1FE21F801F00219C229320FE20D5212323FD21CC22AB23BF21C9221E21962131214D21A0211F23AD21C42269211C23C3231B24BB2F442C60260C24ED2497237021ED21DD22B822502391219222552362240022E621D622E52182224723F4225B216722E023FA206820D5200E20FF205521AE2003209F204321492144201420DD2145225C1FEF227821C020F2204F22BA21592413241C24C7224A2201226D2258224F2281236723782350235E222C2429244C267730202BCB26E524AC233A2495222221F32208244E23862229224C22CD21BD22F42003211C2250226122A5223121A71FFB21FD1F5221BF1FC01E171FD120CB1F1220B42077214921C2201720B81F681F7120D021F1209822F3212B268A25F324BE246C242A22BF23DB223024E622B522E724E825A8249624BA230823C1240825E730DC2D5125A9237F23AD23AE228023BA22E8237C227924A723C821E022D822E72185223F21492286219121FF21D11F2821941FF0217021AA1F9B21B31F541F6420862060222621A32144200D22F8218320DD21F8224123DA23112519263425332567277223932162231C246B25F22615275327D227AB26C225A523AE25B8268933462CDF2803268224152532234A23062380230724DF25B32425242022B822A2224B226B21EB2107227D1F1D21EC1F8B21611F1D1F7C1FA31F59201920621F221FDE21BD214122A22240215921BD222E21C521062154220224D3268626A62558262225FA223B22442327257525E225D028B3286227BA263124E9248A254A26D3337E2D6B27D9249C26B823222295222C228E24F624E5248D24382396223F22C3229C21542106214F238B20D621701FC01F50205F20BE208520911F051F5F202C203C2022221422D122F922E322E2237523CF23D021D62261248825FD2418245125BF24E1232E24B82279269A27D627022A3129BE27FC25CD24702318232D270632522FB829C9264E258724CD23482326228324B424EF24022798244B25AA234524FC226A216D2032228120B520B41FDE22EC212322B2211821B521B022502119223121F92388251D2467234E250E28482565233424992220238C2508262A24452667240F24B621A0221525C72663277628E3275C27652801253224892450273B2F752EB2293627AD26E926A023E9231C244E2500266825AC25AB2496236924AF21B422232243214D21DA207820D4202A22C6224923F321C021D1239721EC20EE1F09238C24DE25DA250B2788270F291D275C27DA2580232923A5237325E425A126B426D6220B235F22EE24F0231E2481262B28B029E1286B25EE24F324B3262332FB2E9D29C2282C262127D02495253423BB25A623F325AD26F223A723D4222723B52001232023EC20F91FE51FF920DF226023122295218F23612330222C223222D924B125BF277B2827280A286B2860281F267E258224D2236A25E926B2255D26422669253024C522F224CB24DB25D427DC29F128E9285F24EF23C12412263C3065308E2BA1280B260D269F268F255B2544235D248225BB24D122D623C623DE234221B222902110218E222523022103224621E622B5236B238F23D5233A23EE22B424D6252128C0286228892B222ACF288B27A522D2221524BB26A1276A286128C427DA230224AE22BF24332767269529B9291A2AF8284A274D2468242F27E830272EFF2AE02905296F2678263A269825F223D12365258D24BA238723D02283222E2248219321F7204622E72012225D233823FD24E8244023C6245C259A24E8246A26E729492C5D2BFC29AD2834289E27E1251424B723CD251B2A422ACB29552A62283F24DA232622BE238825C1270727642A622AD629162899252E25E1271A32D82E65290A281E25A6262F289D273527BC25FC2468241B249D2351236021AF214C21D621B9220B21FF202A2242223E2355237A261A278F26DA254624B8259D259B28332AEC2A872A0B2C4F2B6929C5265125A326B9254125E1296329492870275628AC23AA237121C724C524D129972A342B982AA52899269225B1244E26E032CF2C532A4E26682604279427FA287027832512244A258322B222A0229123CF213C22A42416226024EA226921B423B3255D25F428FC28BD2828270C25FC251526A8279A29832B28299C2ACE2981292A25E8253F25B226552714271426652685265F26F2251326DC22A2258925E525C0253E27DC2620267824C725AA24322785315B2F7128532591259925772615262126C123E322A123BD23502378211B2414248323A2200A23442356215921CC215324D62751295628CD26042A2F27C5265224672638282728382828270E26FA2339247525EB26572775270B291F27FA26C0270B280B26FA2410264F288B2521251C27A625502501255123EE23AF258026E830C82F392A4829FA2799266E2643242D241924FE233F25D523CE22B5220C230E248A22AD2495229F21AF2168230223742453273E285329CF2801290429C9277B270B27AC276526B22626243C231A2517236026BB28C229702AFB273928B5261A274827942412252E26A5295B29F4271B29D4256B254A2671229624A025D6260D321B310F2C5D2C422918280827BD25BB242625B324F222A6251825CD252F245C247E24FB2160245A22602246227D23E6233624CE26BA250C27AA293329C6295F27D8263627D22540257524A02341236325B428292AAF296929A52830275125EE25CB25DA25A2244627EA2932299D28C1259F24642632241D251D25CA25F92820338031C72C8B2B402B652AF1285F266E2410259B244626EE265B26B124EC267F246D241823F422A6206020D920702139226B22142418243A26FA27C626BE27E126AF248125972543255D2302267725F4259A2A0F2C442BF328BB2754269C255626C425912581277A27EB2A5D2CD629E22741264F25852527250725EA262E291C354E31322C2E2CC72AC42909265225912517240824D72510279B24F225E6273D25E6240E25A3229922B9219F21FB22CE23EC23B3237D2386260827792526261D2548256A26FB24C7228C246E24EC255028DB2A4F2BD82B53294E283326312525264823E92372253F27112A33290429EF28FC2818276C26B72549268026452A0B354030722A0A29C2282E28062604240A2451261625D6270527EA25EB253A25C025892586241C2486250122D620C3222D2372233B255A26C426AF2582255A2430256E24DC25BA25F824F5230D23A925BD25E527AA28F9281A28C627452549242E2416253F235D245E278C27B227A2269B295E2AB1287F27C225EF26CB27442709324A2E84287326F627CD250E2504255524442589249F251726AE254727CC27B2275628172514255123AF22DB23A721C6239B24D426852889271B2880261D27DC2513263A25F925BC242C2258231624982335273F277C2544245026052413230E249F2259237E2503265E2931282C285A2A692B4428D325BE23CC246F24712772317A2E412821256024DE25AF256725B825FB25872589268C26B2251028792864283D29E7286924D524E12200224322E82498255F27032A2A2992288827EC27EB251D262425C9251C238824C322C5233125FC24DD26B625C124B824B4258523F824CC22F6228B25D6272E2950280229382A9E2AE5286626AB243123B3240F26F230512E6F295C25E52573252126002773287428C92774285C26F0296729902AC12A88297329B02627253523CE222A239B245C26A027D6276C286C270227EC26C727C227CE2620250323F92370222924FA2397258625EA246625B724B825CB232B239F24582385249A281F2A932ABE2AE22AB82A47288B26D5241E253A25452855328B2F98286127A82665268426D4287A29B22B982B57297829D228F02A942A8B2B722B47299628F624D723A02300239B23D6244E281E2832272027E226FC254D2803297328F7262923CD223B232322EC23FF256D25A025122546261824DF24F8249323A123ED231D28042A782B962B222DB22AD3299B278F242525B12713281832AB309E29102504259E25A029632A182B622DDF2BF82D512BB32AE129962A302B8D2B912A91294A29A324E8234E22FA24922312261528EF26F0258D253C26A8275228DD278C267724E22231237423F824EE26F225D6264D24752624260126E724A2240125B4266628792A312C4E2BE42A0B2925279E26E1245825D8271828CB327D2F9A28C525DA25AE284228DF28D92B8B2CA32E482BAD2B4B29E1294A29CF271F292E2AD72ACB27AC23B3218C2312230123532428267A245E25D02564262D27D32706283A26B423A22296219623CD24BE259D270324B1248A269C277E259C24812383269627C026E22A842CE22C282B2528D6245524FF2374265527C62722314A2F752AFD26AC28EA293928E5272E285B2C972EAE2EA52B55285D283A2BBE2CB32B162CE42A4C29B4237F225A2106212022A9248B254E258C261825AE27DB274D2B422A8E281323A022C824F6252625E226F0274F25FF25F92689275B27EB24BF250B27892727298E299D28E328BE282D27D12626242D24F723EB26E1277431942E9B271126AF26AC287B288828E3275928FB29062A84285C280C2814285129052BF129C02AFF26A3237222202161208521A624262638281A28F0272B277E29822A922A5627CC2397228E26372783288829592A61281D26F5257B255C257723F825832719283B28AB29D62878273F2638269F241325A6232425AE2654279931732EB128E62674286C2847296B260A263927C32650262F2723287C290A2A9329A8286429CC276D255224B421EC226A212322C124DA273427F929C02B4B2A842AF92B0E2A99267F23DD257326AC283629002CB92B9D27B926F325462494234F238224E526FD288A29EE28D125FC24A62421268E258F23FD2426288028B828E133062ED22748260629962AE827A927C925E4270426C426B527AC2AEC2A662B072A562908290F2765251C26AB2380227E234323F7243829AD29862AB32B962BAD2B112A222A002619240D275629E52A64295E2B372B5929E4286826202521257E2207255325AC251A269D265E2751267726E124EC24C326D4278B297B2C772B2735BD2C5528E429922A8B2BE12906299E27DD275327E82786290B2B1A2B2F2B0B2B172C232A212790269C230723E423262361228424B22875289129DB2A4F2AC02AC0289F26F5265123FD24A52A2E2C4F295129412C8B2B0F292E28B8269A24F6248324EC248B26B2277E27F3259823B42405257F2590268E27FB297D2CDA2B7936CB2E8B29A52BC82CE02BE5286227DC29E92AF02A612A8F2869287228A42A7C2CCA2C862C6429442821251B23EF21D923B422C123BE2887287F28C629CB288D293029F3281526B42277235B28E0280429542AB22A1D2A0D29222803244C241B249C2740256D27BA278B252E241E242525E524FE24E0264A27AB29032AC52A9634B72FB02A692A462BBB2B372AF92A7F2C372D6D2B4629DE2574256D2A402BE12B6F2DAC2B282A40282D26792155224623A72240239D26AA27D42724273A27B7292B2A0E29F82579224723CE249C27C226FB28AF2744297C279D254F251324EF2373266428CB276B26C726CC2312244B243424F622B0263826C7266627CE2875334430B92ABB2A042C252B1C2AC92A9D2BD92E492A1D28ED26A6275C297B2C712C2D2E5A2CA12AF629FD260825D12436225A246A244C25B2283F277526CC279D2857290029ED265C2268223424A6253C2739283926EB263D26C125CA23AC23C7256F27C9288C29B328A52629252C241B245E239E23BC26B624F126DE267628E4305B2F5F2AB02B6D2B592AAE2A9B2B472C2E2C492A6D29412812272D285A296E2A962A2A2C452B602AEB29182634248824FD22122485255727AE27AD264028E5278A28F326182574236523332576266B27D3287D2863276325B926E3233C23F723FB25C228962A5C2A7829B625E123FF23F8247925BD286C287B289C271228C931562E582B612B222D1D2CA72B4F2CAA2C572D2A2A83264A258227232BD02B3F2AAA2BF12BEB287A2BA1286F26FF24FD222E2389243B245D26EA28AF2551273229A12902285026A524D323AA254A26B2286B2ACF2A6729B926E324BA238C24F125D1253E286C2A5D2B7F2A5A27B72487245624FA252C28E3284C297928932ACA32AF2ED4286C27712A1928E727E428392AFC296E273C260827B127DA28CA2A652A4D2AE62A5A2BD62A0F2A31274C25122544244123E524B825232612264526AA297729F629D02A1F269C240C262928E428C428A2282628DB26B726D524DA247125ED27D727B027AB2855295526DA24C72428258827122B902A2E2CA32C182CE3314B2F3229AD287D27D4298C25D9264E27B025A324C0245B26EE27DF287D2AAF2A6F2A0F2A3B2B5B2A0F297126EF233424A8234C236324BA26D525FA24852645285829132ACE2BBE299C273E2513269626B9271626C8268823CC2466251027A52605277927DD2665270F280A26D92473258A26BA29982C1C2DCE2BD9299A2C0F34CF2EBB29E6288028C127D0279E255A265E25F5245125F4263F28AF2AD329482A37299E2A7E2AE9294727F4256F25A424E321B9258725792338262124FD2482286C29DE2AEC2AE2284B27AC255326E6245C25F324F723A9233825DE250028852905282A26F2266427F0267525A5245C262228F429502C3F2A79285E29862C693547304F2CA02B022B272BC12A7B27F4253827A8240C25A02660277228A62BA22B062A9C2BC329FD29F82AD228C726D924D72210220823CF2440259125D8265B261D26C4279A283B2712287C273725102598239C25EB23ED24322310263227E02734288F286429B42971297824D724BB278C287D29BF2A562A542A2C2AE72B43344430852C312CFD2CDF2C802B902ACC2A7B28172761257D269328662AA52B902A582A5D2B392BAC2BCF28D627E7269224972434232923D3240027662507281227BD26B82630279F26DA264125ED25BB23F222172425236424562696244727CC270528AA28AC291828AE283F2634258C287C29FF29422B5929C0294F2C102C8634902F262D5A2CC02B122D1D2DFD2C502B152AA826CF25052649279D2870297529A029162B5327112767260825E724AF245323FC228B230C273029FC29B82B152BE5287125AB255726352690262A27232390224122D1240F266A25D727832741276A265A294E2815279A269E24BD245229FF29F42712280F271E28BC288E2AC23427303A2B532BF12AB229302CD82A632BF229B9273525CA2690277C287827E9276628B62661263826C424BB2384252C240822802232248326E4287D2B602BE5297E28CC252B278A26EB26412756253523CF2278248B24A92533272C27C5276A28F028CC2A5D290526AF2409248B25D026A326DB26B126302692269627E6282233F931CB2C172A20290529A32A832B7A29E427F425C726F8258F262927F92791262D292B26A3269025FC2335252A2490253F248822462222251029E728CC29E228DB27CD26AF292A2870277D259F24E5223A233026B42542277A285428A1275F29612A1028CA261A2467247324822420277927332668258425232874299A2B13335431242D582A072A6D2A74290C28812852289E25E92446269B26EC279128222AFE28022917294F293D278824DD237D228F23482492246326472761273D28A02723281B281A2858272A2537248B23CF2374233027AD288827FC281B2975279A266725C4275924F0230323A1237B2460269E270228852678259428F528692A25349031962CEC2B312A7C2AB32A8A2CBD2AB7283E25EF2569278129E629922A6E298F2BA42E782B852B8326182655248F241721F2209E239424F125DE27B9276726DF254B278E262D25DA2388222D234B2422273C27EA29CC2B6B2BF32AA6271C273926F026D42342225623BB235825C9276C2754266E268C26622A8C28FC29E431D730B92DCD2C272CC12AD02BAA2B5929BD2839269A26BC26B228FB2AAA2B052A1429922942291D2BED2667255F26AB258E21EB2287222B243A27F924DB25EB25992792299D27B424EA22992309240B25D726D32876294629912835278325AF24F024B424D423E0207D248D23342400264E269F25AB24DB23C42557274927D830BE30FB2C5C2F9C2CA42CA02B462A442782272327A526F527022BA62BE82C942A7A28C428AE26BC284A2867273F28B3253224C7200323CC235A267725D826C82654286E2BC42A30282E26A024FD251B272F27E2278C269027DE28ED265725A6256A258B25D62324230022EA226125AD255624CA23E0252024722507255326B5327E330B2D282DCD2BA02B532A2429A529DB26922473265E26BB263D283F29AB2A1D271A27C3271128AF25D927492982285724E922BB210423D1231825A2278128F12B7B2CD52A1C29D5269F26CD256726FC271F27CC25642759263F27F4258526F827D7250424DD23F524AB236025FA2729256B2363250424D025D2253B260C309F32F02E622C672D9F2D732C2F2BA22A7D27DF26D42738295D264828D62698260725DF2468266B276F290E28CE294129CD24F823FC25022327252E27AB289329B82B222B1F2A202BD129AC2837273026D227E527F92547261C27A929DC287028252A3A29EC279326562621268826EF27BD2606268B281927952789275B260A2FAA32412E3B2E082DD02A5C2D632B822BDE2AA9282D29CF2ABC2A7527FE25CA235A25B5247B25F52874288128BD2780283D25A6242323ED2427254128C12AA42A5A2AA62B4C298C2B8A2AF5281825F124C62577253E235F2488266B29712A8529B329C429412A0F26D127F327A12799298028EE26772AFB29C628912881288130FF30A42DA82DB12D6A2B352CC22B9A2C5129D127112B0C29432AF028E0276825AF2568258326D6289E2A3A275F290C29C72878260F24F4225A24C526572A152B572A9B2BDB2A9B2B9A2A7F279D2798243F248925F723D524EF27C329B62AE9299B2939290529142708277B28982B382BA52738259A29DE293D2BBA284828A931E731AD2BFB2C6B2C092D5F2A4D2CB629A229292B6E2BAA2985296228F3279D25062643265127A22A8F2A85296028A5297629AF262025AE2391239C2400280D299F2AA72B702BA82A9C29C42626266123D924E624AD25E624F2283129D629B52A2A2A322A9629AC2573278E28A52AE72AAB281629B62A502BB82CBF28C428AF3252306C2C472D2C2D4D2C092C4D2AD229EA29662A592B8429D1291227E327AA268A26262763296A2C5C2BE029582A8C2AA32954276126952301251C25B128592AF62A3D2C212DA32A282BAD2A87270524752461244E25AD27482820295B2A312ADC290E2914287525F8274E29152C712C3D295F2A9E287227A62810276D294F36CA2F0B2C6A2ECA2DD62CB52BB7286927D827C6275C28AD26142748277E28D426D4278A297E2B212D2B2B1F2AA4280629212B0E28B7237E217D23EE2586271D2B162BEA2CF32B332CFC2B1D2CE5298D26F9248723AA275D28EB28A528A52753297429F726E426E324CF288229D728AE2A642A7B28C82546252B25D7266A29B9340230FF2BEA2CBF2CEE2B232A4026332609260C26A727EE26C927C4265A27D02AB42B212C952CC72C662BA72BEC28FD2743265524DF232723CC21EE25D12526276728042AD02AC52B3F2C642B2829AF254A248F257026A8298228D1263F28A128592930273825BF2575297F2A4B2A61292C2973287926DF22542479263629B933622EB12B8D2ABD2B152A2C281826B1253E277F260028D7264A29F42A122C312A3C2B042B802BF32B2F2A452B7B294E27CD24C42470222222352295245726D127DA28BE28342A552C2C2B052BA62BEF26FC24F5249B27AC29EF2A762726267A27232A0A2A2329CE26AD29822AB5292B2A1F29F22881287326E925142576281F32FD2EB52ABA2B32299F29AE283D2675245F26BE28812AA32A4A2A642CA12AB82B79297F29D528372A15287C2902290F29A726352699224D210C238C254827152973289027602AE828AF29982A722A70260726D725CE25A026C8292F262E255E27AB29B829AF27BA2786287A29522936293C2972273C2BF7254C257228BC298333E531322950280A279528F2291D2704267028112A7A2DCF2C1F2B742A4D2AC626F9272A293B2A8D29582B882A5129762B6B2AB1265A25F4225723B8246028F329462BC72A8E280F28BA2759284829312669252E277E271A27212759267724762619277928C925F7256528C426ED264F2AF128CF27A7282E26B8258929932997354F32652C6A2772265527D32565261E264229452C412C062CD629DC28F1277B2789265628492ADB2CDE2A532CD72B712A1229D128EC255724D724CE25D1273B2A132CD52A4A2867257D26C827C9257425B7261C26CC284C286C28DB2479246625D6276C254E25A827B6270126AA25CC280529F929A027FA25A8253C290D2CCF359231532D992A3D2A3B26DB25D626CB26B4281128E62C4C2A772B9A298E29FA268627E727A82ABB2AAB29772ADB29B32B8029EC277C268B239224BC2550260C29112B5B2BED2771256C27CA25E3234A227B23572578274528C12771268526DC25CC280F2857278326F025F8250D26EE295C291729F1274F2792276628152B41352E2F9B2C042BB52995295F26CB23E7268126AD28C3290729692BF12A052CF029682809285827C028DA276928152BB12B2B29C427D525F92424246424EF264F29682A282A2C2A4F2872259D25DC23E620C7201825A9236726FA28942807287A28F7277428E328BE26C42895269028682BE52B0F2B93296E282D28C22BF22C0D35172F942BE02B212B86280026D423D8266A270D29772BCD2C642A402B282B0D2B562AAF2806260528CD272227602A9629372A1E2BD72909251F2406265B2793275D29E7283327FA257D2637261625E9238A238E249C25CF26B7261726C02659252327A929F228532744263B25462AD52BF92B792C9D2C7C292529A92B3E2D7F33FF2F4B2BE82AAE2811287328B12600278229132B3A2CF62AB52B6D2B702B552C652A5F299B268B2850297F28E427D0296A2962290728AC258F2509263128D827BB294E28E5241E26DD26A3251E2640237B24F626DD2692290729AA25462656263927BC27F82596269524062751274F2A782C9D2C492BE92ACA2B422B762CA934E92FCE2B102ABB28AE290F2B752916273329262A232C572CFC2A1B2BFA2CA62A8F2AD72A7427F9260D291C28FA276D27E327AB2726275924032538265D28A32ABF2AB828BA26FC238B264B2881276724AA253A267427A627762A7B280426C927EF279527B3279E25942570246C26602A562B262D1F2C8B2B882A6F2BCE2C30340230432BEA2A5C2B3D2B202CD22A882A9D2A852A69292D2BF327EA270E2BAB2BA32CCA2996289028D329A52A842939289C261026512528232E2516250F2703287F296D2795268324E4262D28C028B426D526FA25EB275228A42A40280027E3271F2816289F2747258E256824D426DA279028592A6E2A232B542A7A2ACA2B423560314B2A2A297D2AF42B0D2DC22AA52ABC2ABF290D289D28EC254626A927542AD42A682AA8299D28522AB12A8E2A6A29EE269824B0231424B32333246B232F26C129E628982945268E26322805287226382520260925D127292740286F25B02530289C263E283B26382468245E251B273928FD276E282C29482A4D287229A934512F0329F926A927122AAF2B242DD32B5D2A8E294B2A0F2911274F245926E429D3296529802A062B65298A28E0268C27E625162675246D23E323A5224924D92868296C2AD029F5262427CA25AB254825DC26C825B32790272828C625ED253526BE26962699259825A425B7263428472A5C28E026A32776270929FB27D328AA33C72FF12A25270628E827A328BF2B0B2BA02A8B2ABE2AE82A6128F8278A27B729BB2BFD2BBD2A532B2529972BC9287428D4268C28EF25DB248E246924F2232E27F12864282228EC244F245D251225DB24FC25ED28152AA4299D292429C4282F29EA29F227692640265F285D28FC29D72A9D291B2842270C26C228BF28C5297135FA30102C592A792960299F29D02A6229D32ACE2A252DE02B3F2B2D2BA728BF2B8A2DC92B672B9E2CB12A7829CE2A4E2B8E2962294027BD25ED244122612559278129BB29982941265F24C424DF23342420279C29112AE027E6284A292929322B7F2A652A4E276725412A262A072C5C294326F426CA2764279929172BB82BCB340E30FB2B682AC928CA2AA82BEA29482A6E2BEE2B532D562B682B1E2A6B2A402B852CC62C222C372DE9294A293D285B295B28452A5C2AEF27B8267A24B5255027E128DF29732967281E255D244925C7240F26702A96293028E727CF284D2A5B2A642B4029D7274026A029D92AF828D7274124B725E32796269A28D32A272D1B35FF2FDC2C292A4C29402A082C562C562CC32BCF2B3C2C352B502902285B26DD283129B32B3D2C222BD42A282AED289727AD29C92A602BED29FF27EC260A25E926282A7A29902BBE29DD275B2515259824BD27E829BC29512AEB28C42636290F2B7C2B19290D272A281D296629D22716289925802503261228CB2742293B2C6C34BB31FE2B932AC9281028812AC62B652A9E2BD72AE42BD32943285427C7268127D128072A0F2D192CEB2A35298C27A727D728AB2B672C99290729AA27AE29F028C3285329712A9229F528BD272925D8229C26FC273529542AF529E1295D287328342715288C2847254A281629242790279725C727F1274B26CD261F293A2A8434DE30CD2C512A2729DE277B29AF2B2D2A63286F297528FC27BA27FE26C12599259526FB27082BC42C7B2BE92AEC2824299D2A1E2D8C2A79275328A3285D2981279526F227AB29F6296329DB294225D524CE2588279726D7282E2B2C2B1B2A0E297C2805284D24C72599267328792761276C269829712BD62AC32A042A752AFF337332282DB82C13296B29A22BD72ADC2B322AF528B0287129C52AE5290727F0278524EC28842C332DA02BA628F7289F29D629182B0D296728712886289B2A372ADE290429EF276728EC28D827CE25AD24CE247F26D0268729DF2BBE2CCE2B112AAE28DF2760269926BE28D127F8275428A3271529FA2A882B0E2BA02AE32B3536C8320D2EA32AB529F029E229932A862A9B28E528A929552B962A552BA428E3295628F828562B4A2CE0291D28E126122A86281A2AB229F727B82736289B269A28D729F32A092A2A293F28C0278727FF24DC231D2589254A285D2A7D29DA29B1290428ED27752644286829602793271226ED25002A082CD22889284927872B6F35A033E72E2E2B40299728D728612828291C2AEB29CC2A392D9B2DCE2B142C5B29D2271F29D62B202D1E2BC8289E270A277129432ADC2838287328C225E5246728BE2AF52A512955272B261826C326462403256C2432259B2505298C291629CA2A2F2A9328B327B129092B1E2AAD28BC27A528C329C02C862AB529DD28B22A2C362A33182F212D9229022833280427AD289929EB2A6E2B822CF72C6B2CE62CC4298F29152A6A2C2B2C452BA4277D2529263B252727FE27452614285E25AE26B526182A942B722C4329C62699256727C32598240D2521240223792AC729612B122B102A7D2A76291F29B92AED29CF288F273528392B222B9729A52744273429263330324C2E532A4D292928A02790281129FD2BDF2C9F2BDE2AA22A152BF32AE82988273C289728B42A972AD7268125BB254D271028BB28B5267C273A26A127D0287D2A5B2CE42C852A8A286A2622291F27C024A124E121AA2453264A290F2B432B5E2A872A152943296E293C28FB261C27E7276E2A4A2A7B27D92668274828CE315B33D22B852A01291626D825C126922A5F2B622DA42B59292D2828293F2A0D296F2729260628E4298129B1263027DB27662AC929A529DC265C276D254F267428212A5F2CEF29042A78285D28D9282F29F7287D2408249E223D2696276B28EA2AAA2AAD2A5A284728A328E2252F261D2676289929B128762605286B263728ED3228315E2C1A29F4257F2421259C26F829272C492B0F2B1326EE2753289D28442A12293727EC26292A3128A826992876297C2B922A9A2881271C26E1258528F729132AF429AE28412580267E262028AA27DC263D25EA23BE2178260C268B2AE32C572B9F2A2128C62681280A273025F9247D255127362B7E28B9260D26A92749309332082D552A8B275426F9265D27E42C2E2D1A2D8B2B8C29C428B0296D2AA42CBC2ACC276E2717282E28E728122A6A2BD22A872B4E288A279D267927A629AE2BE72B762A6D29A825D9231D28252A5327A82653276A258224E324852407278429A42C882AAF29A72AA72AAD284B26CF2639259825412822291329082A342ABC3289302A2D8C295629A8275B27E527A12A792CCA2C9E2DA62B7B2BE8293C2CCB2A8F2A2B28CA27FF2694273228442B722C732B302BC525ED24BB241F26CA29952B4D2A782A962866272028342981294E285427EB25FF22F423D4241525112782287B2B31296529C929E629B929C726B72431268726CB270728B029332A60290F342A33B52DBE2B0D2B762A7F28E028582A0B2E332DE02C942CE62B342BAD2AD62A80285029A3279927B6278827612C5E2BC82A922AD827A32530255227FA2745295D2B272C5B2A58298529602CBB2D6B283E283826E3256227DF271C25A326FD264D2A382A6B2B772ADA2CE92AE427AF258A260E28A529122ABB298A296B2BB334F4324A2E2C2B182AA228DB273E29D92BFC2D352DFA2A5D29E8289928B0278D271A28A427AA27D3264826B426DC29D82A862A322B1626BC247F25E12638279928322A8A2A512A73280E283329CF2ABE295B280C27D928E3260528C7272025F6261C282429912B4A29A82A192BF62729279B264029752B0D2A6F2A9F29CB29FA3454338A2E852AAA28C42768273528C42B792E182CDF2BD629B227A4268728D327E726AC2AD52A732811278927ED29BD2B59297F29F72759253328A827E128C72AA12B4C2B792A2F26EC26232706271A261B2819299F29C929182B5628FF27CB26A925522705290D2BB82C312838275127CB28F629F82B602C8D2B5728FA29A5354A33F42C8E2A5E28A627C2274229B02B612B802BD5287128FA2597278C293A294B2AA12C142A3B2A22273325DF250728D02771261D253A261A27162A522B5529F72A492A3F288025492715267A25742681277E2BE22988285F28D3273329F026242574246325B627302A8C284727ED277C296A2B902CA12B882A3128E22717336B32652DB22C012994274A255727022A782AB4290A2AAD28692775283D291E2B302C492DB42BCD2B54293327CE27602A4D285127E524AE2574282E28C529772AB028242730296A2A6D2AC7273425FA269C26EA2BDC29F926C8276F275F26CA23AD22DD23C527F42616294328B627CF26E1271C2AE02BAF2B942C5C2BAE2BC034E6327D2D382BD12A0528D425032707287629E028992788282D2845293C2BA52C9B2C7B2C842DB42BBF2AC228E929AE2A912A5A2847264E26C628E129C92AD72A2928AB277F290428B3298F27EB250F254E261F296728B227032785272E288C242D232F2418267E27C327C0271427CF26F125A228872A6D2AEA2A612AEF29FE31C9319D2B7A2A0A29E8271C25D2276727A229842BC62A002A1C280D28BD2B882CBD2BD42CCF2B4D2C9A29252AED2C5A2C8F2A752991275228DA280B29CA2A9E2AAD286526EC2794277D28D225DF257D245A253C276A26292665274C254327A2250125A123BE24942421299E28DF27C528CA267D260E28A92823271928C4286E2FB2302C2D872B8B2A21290626D9288028482CBF2C30294D29FA299D29722AC12C122C692D982CCF2B832A282ACC2BA82D7F2B842A6B292E292D29572BCF2A402A87289A2714284E2744297F279F243F2332271D28B0263126A9257625BE278C26C725152453236526FC2766289C28782756261927D627AD2678269B252D2610306330982CB32A502819278A257D26E328B8298F2A1C2B3B2A14291A28F3294B2CE12BD82A482D5F2A892A3C29362B782B4829082A33265126AF286D2A25291929C727DE27D126312445262724B226AC23F525AC28912711257426802725279D26C82361243625A9234328ED28E42912284227AB23F6252F2706277A276526C430E631F72DF32A7E2A7B281B267827562B182D362B772C652C3429DB289A2A7D2BE529B82B832B302B4A287326AF2722296E2A622B7128F2260129FB29772AA0294D2708269825EA241B2692275C287A27AC286A2ACD294A2A97286026BF281728C0286624432431243C2604284D2AB0293D25EF25E12564267628DF28C929F2310132C02E152C082C452AF429FF28FB2CA42DBA2BD72A9B2B122B862AB52A0D2B6D29592AC92AA02B5B284926A929FD2AB72C012B22299E27012665279B27CD27382583250C260927AD289F29792B432C6C2BC02B3E2BA02A76299028AB28CF28FD296E27422487252B26D5275529F2294A28492679266C273029D82A672BC4328E35142EDA2B8F2BF12A0628EE29432BAE2B1E2E302B032BFE297D29632B242AF628D72A7929AE29F5278B269B27962A782B132B2129702411256325AE25E526FE240523B82272256327B429982BE92A122BB92B4E2BF1298E2A5E2859293B2BB52ABD27FF24492328264B27C528902A6D2833279326B926AF2AA12B372BBB343D335A2F142CC02B262891281129C22B642D412C6D2C172AD729982B842B832C292BD42C912B7F2A2F286328ED29FF29D22A992BF7272D255A27EC2435277024E02413231223AD25B824CF261E292C29E228FE28F428CB29D6290B2974290F2CFD2C102AFA262D25B9251A275D297B2BAB28FB274026AD27812A7E2CCB2D5B3565305F2B572B4B289C277C287D28082B7A2BD52B4C2B222BA32AF52AC52C8B2DB92BDF2C002C252B792A422A682A682A822CF328D726FF25762629282D288B26FC24EF236624A42397235427D02644265F27512977284D2A302A452AA22C3C2D452BC82980289926BE249A2598267C2A8D2A7927B726F7272D28DB2BC32D4434A92F4D2B3B2A752BE52A4A2ACA293C2DE82C332D442B7E2BAB2BF92AF12CD82C6E2B022BDE2B0A2BC228FF29382A3E2B04297E297527C1264F29072B472ADE2ACD2750232625AC25CE2671285429D5272D29662AA728A52751298429C22A1D2BA62CF92A7C285426FC2477259D2662298A2B16291528B627FC29842A392A07347531E22B6C2A712B7A281B2AAC2AC62ACF2BA22CF52B6E2A612AE6281D2AE2295B29112AFE2AC42A612BDC29152C952AB0293E2A692725299B2AD22BC729D227E226EA2534254E27D228772A6E29EF27AB299E280C299D28D52A532C4F2A052AF22B152B562B5E281127E82545262B2AF42A8C29F9270627EB2AED2B812AD833BD32D92E4F2C3F281B27E425E529EE2A4A2A102BA72A4D295E26FA277B28F72872289D283F2A5C2CF72B972C322CDE2BEC2BA32AAC28E329EA2B8A2A1A2A0F28402777261A2605276729EA2B552B6229502ABC2A9629AC298D2AC62975290128572ABA2AE528232846283E2728247427C3271D29D22719279B2A482B352C0C352B327A2E162DC62A5128D726652859295C2C4F2D812B722BEC29FE27C6268D279E27CA2A312CE32B762B732BC62F232DD029AB28EE2702274E2ACB2BEA297F291127CC24002640269528A429142B7529072B202A9F2AAB2B312A4628A32830290F2AB92A032B3E28D927B42552259127BF2776290E290428EC28462AC22BC832E032EF2E6D2D032C8329862779287329F92D642EA12CC42CD6297029A528A728E529752A852C7F2BB72D622CB82B482B9E2BE52A6928D729D12A202B492A58296926A725E82595259229A02AF9291E2A6F2B6B2C642AFA296028C5268026AE29392A92295329D328B6278725C2245326BA27E5275A2754276F289D283429973261317B2DDB2B8A2C0B2A0B2841275829832B6F2BBE2B892A5B2860284828A327A429292A5B2DD82BDE2AB82ACB2A862BA72AD829862A1D2A5F28CB2860288D265B25BF24E32366257B27C42A67294C29BC2A762B672AA6296F28EA26DA28FB287C275B26B4278E269F276325222551246824F4266E276E27092759298029B73222303B2C5D2A3629E12A352AE42817290D2B822C292B792AEE273826F0279529B629A52B532C892BF22A8F2CB629732B6A2B8C2AEE295D2AD8296F297F28C226A22656248E24AE25F226A128DE29E029DB2B612C862B532A8D29B9260B289E285D284B28C726B225AE26B827DB2409249623CD26EF253326E4291F2A8F2B6933AF30642A8F289828BC29072A80298727EF284C2BB82A7729422851278729432B282AFF29F22BB62BA12B702BB3285E26F826C228E829B229302A6A28A2274E2580244723AC23832438271B2A9A2B8229702AD22C562C2C2B122B1128CD27AF28232A38290229DB26C4278726AA241A24E52236252A2630276929DA2B512C3433A331B82A092918286E2B622A57280128D527072BEB2B822B98295828B528882A962B652CE72C182DC42AB229962A8C27B52501273C28ED271F2947285B276B27242564234323C6230B277928D32828281D29822CF42A252BCC295029AE29DC28A929DC29A62AB529122A5A28822795259B23AA23B32450241D28312BBD2A8D338131BA290629802739293F2A99280D275628262A582BC02A5129B42A822B0B2BF72BEF2C522B712CD22AA82A9E29E626E8271128C12764275B28C229952997285A265D230623E424F22638283C27B927DE28AA2B402B7C2A6C2BE829B2284029A529692B312C3B2BE82B4E2A6F284A26EE2428239A231B252A263E28E52959347431292B9429B0288D2A6C2A422920275C28FC27092A342B0C29A728282A7E2C9A2B3A2B212AED2BF32AF32A8B2B7C29022A6E2BB628FF26A1282E283528A3263B261F243B2208248326BB281026B92667296729812AF0283A2ADA297729B52A6729322A762B442A422BC92A6527C1261026AC22A3248523A1255D27F2285032C52F7B2A06275028F329062AC5297B282F27E5268C285A27AC266026E027A12A802A272A022A752A1D2A842AA929AA2A652A262A7E298428C2289429D6291429C327F4245C23BB2394262029C5278224F127E829542985273328B926D7265728CF28B9274D284C270E2850268E2690266E251D2455245024E72581266028FB319530DF299C2814260E2A192B3E2CCF2A6F27922617279F269525DA253F295E2A7A2A87297E2C272A882A10288F28B4295F2AD929462A3C29742833281228B528FF27352467225E247726D326B3288D269829252941293D289B27C3263C26CF25192589252A28DB263A281A2700285426C9267F269F2786276E2854281F2B813437313D29E82612291D2AB82B7A2A1A2C5F285827D826B4276B252726172AAA2BE9297E2ABA28562B582A7726A5286F2AA42B362A14280727F32764289427E32751253A23F4224F227B239A26D0260F261A282D28D1282029F62777250724B025DB24FB251426A1269528F5273629C82A03267B25B32660269C29812B412EE73518318A29022A4129C82B1C2CF42B052CF5282E25AF25C92563279E27E929FB2BF428C228B328382B5F2B6E286E270427782796298728EC26042779270A26BC24F524A625ED21A1229824E823EF28EE27482976294229AF2756269025BF2436256F2567241427D026422A8029852AB927B62612258727B727B32A112D3B2D4136A42FF62AE128F029142A572D932B8C2996288C268F2639256E269629932A212A982AE029412A402B532AEF295729DA283D29CC2906286D27E427D6253F252624AB227122C721D7210B24AD26B32716286929032B9E2A40298A283128DC27A9283828A7251C253627D72A122B1F2A2828E12511256226B3271D2A2D2C852DDA362830F02912290B289129EF2A302B272BCA28132586252725D026BA269529BC2A20294D2A4E2AD72ADE2AA92B71294B2B772976284B26FF2752293B29022873252A2490233522B52289234228D2299C2A2928FB284529C829E52AB8297D2A372A092961272828EC298B2CBA2AD72941280726232455259127E12A592CBC2A0B354B2FC529D727D6277029C82A852A0329DA28B125CA24B424262538270E2AED2CD12BCA297F284E28E2280A2ACE2B32296227C925772529268C284329AD271426262584211821032025250F261B290A291D286F28B126E227582A9A2C1B2BAE2BE529262940299E2A082B372A152B0029E1254324C8240E27502A382B832C0835F72F0C2B8D2AA6272F279A29802A8B2AA329BE272D26EA26152586253F29102C272BDB29A329D0270F28C5277D29342B55297827BC270D26EC27DE28F326D1261925E0212922DF216B24F6252E275026B126C8259925BF28C92BB92BFF2BEB2B592B652B4929262B9B2CBB2BBC290E287324FC23D9248126172A452C962C4734D02F5229D629F828FE277A292F2B022A3D292E28C82554264525A4244F268F286029B929FE290328FA261C27C8277129C2276825CC23F6252426FE26AD278726FC248021E42198225F246225D6254F262426162481248A27A527D628B6294C285A29E329212A2C291B2A002B70292728032456236F2541271929852B4E2AEC33162D2F29032A142AE829C62A3629312AA429DD281129A8265A27C92578278D27B429862A7F2A1628DB26CD25A127932AA8263626C3243425EB237B250D278D255E24A22247214221B6239225B625E524A626F1236224A524B22635268C27DA29DF287F281928AE278429DF2AD7292628D0247F22BA237922C0266A29EF29A633122DBF290428EC2A4F2B4C2B242B66299D2A99270F27AF279227C6257325EC27D22668281228E5271825C924D525A628AD273226A0231B2379242824B9234624452311231F216121A223FC25A72607253325832510245F248B268E251B27D9264729202663261526E4274A273529FA2545264122C1229D254126C9286C29A331652CF828242716299A2ACC2A682988287828C8277327AC26CA266E2238236A24E326CD28AF2518274B24A123212570253B2729250E2463219F24E92298264E256A243722F1218F212A26C426B827202767250C246F249723BD261F258B273E27CE287F27C4274B27F128F9268728D52680247E22F92295248F27852806299833E92DF827B1252228842ADE2B4E28792711280728B7280B27C324FC24EA2436255427392921281128A024AE2381243527F6268E27712428221023F1245225712737262721D2209A229A2342287E2928279B284D27F7245222D3259A26BC28D827A128B2273A27A325D627372866277525CA252C232124AA222E253325CA272232432C832659256926A1277228F028292732280D2843274B273726E5238425212520279628AE29DC28D22509267926A526BD26D927C1254323FC2398264C27FD261C26F322B32235226924B12607286627B42644263725A623AA240726EA27B227D0276128C226D1249025BB2648270228D0242224EF239022A324382628290135EA2A0E257D2480258A2652289425A6262C285C279827CE252F2502242424752552260228C22AD32AEA26B9242725D725982568278E24212547242A23DF26BE2607256F23A42344217B24CB25ED24282625261826F123CE24872571259D2595255B27D92667251124C525A4267728D327B324A5231224452289245125CF280033A02C112668233E266F2769278427472784284E266F268A272A256D2599241325C326F9273829802A0529C92660273927A5254C27A0259B2397233625B8263E271E260024D321C122AE24D725E326F226542711266424732311240A251F243526C22699257E24A5240D265E283F29492BDD26C924EA2356233D24D425E7290D354B2B7626B4253F24CE266727232656255F26502716267C26D5233624C3233126DD24682688289E275E287626F0263125BA2518270F241D24BD236922B42309249824DA21FD2107229C220124A525F7258D262F259822F6239723AA223923F7232E26842483242E25E525D3259927E9261226352500223023B7238E24EC260F346D2D74275C248A24B2262027432740266326B526BC244624C222F2228624CF21CF230F258525FB26E127D826F825B224F825A126C725B722982353221B244F25CD24D422A8221B207E225B23B82343245A26C126FA240224B9229622E322DC235F248524FE23B723A2250225EC26F0287725EC2367237D214E228426092802352A2CA626FC239A24C3256B277E25AE27AE230E25C1242324D822D723D023582291229F24C2235D25FA232124DD241D25802495252325D6226624A5238A24892492242F23F921B720D52109237D2336247724C726FB25E5234C226422CC22F922F82364236B23C6221025D82288250D2510243F241B2342226E24A024EF278D32CC2B29242E235B256E247A25D6241C25F02485239A2518245C22682328231D234324752243245E252024E922692479253E23372453233F220E228F216F233122652329237723CB206221A622BD23C1223C249826F8230024DE243723BE237823F821482165223C237D24E22479236925412571220A224C21782170236E25882F622CD0262723D723822561237B24172494240825BF2369235824A722EB215E247524992424240425F122C6219F239E245F23EA2254234F231D2196226B224D212C242323C221DF1F8923FD219F23FF2130248D245923D723CA24FB218D244E21DA23B7233D230822CB239423722427266424AA21F6216E210323BC2341268C31352E98266423632369250923B82456234324DC233124CE22E022AE214A22882290227C2328227A23E52274220C2388247E2404235622561F7F21EE20D4222E2231226F21FE21B721212005247F2277219E2230238F2118240D24FA22B32165226322D0211B23E320D423D723CA23BB234A243B2322234122A822A623382580312C2C2A268724F52114227222D52375233C2571230F23AC22E6216B237323C520312361221F23E0232E233D22C3223D2286225B237220651F2822B821B821EB20B721ED22C220E41F2E1FD421422098215122872230207521CC239C22E522322083227D222E22FA228E22AE22F222E8248623DD225F22B01FDE22B2235D260B2FBA2B4426C323D2220D2256235924542482240B239E2341245F22FD21A02298234923C221022201237123272238229922662309221920F820B91F2222E620CF219821322123220520A61F48213F21C220F72131213D2193212D221623E021DB233222AC20D42156231A24C421CC229A23722331224B237A215A239324DE25252F892B9126F6217921B62009213A23A6227223F921F0225F200A210B21A521212110221121202236221523ED1F322122243C237F221521B51FBE2024204A22CA22DA202D2083215A1ED01F9D20762001214321C221B6229D20FA229B21392166206E222021C51F43205E22EB22EB211E237A21AF22AB231A2219221D242126592F0E2CC725B323BD21B9226322A5212F226123DB2183220E21EE217F20FE20D02009208721FA204B21AA1FA41FC3200D22D021B8207D1F6D20DD209B2070219A21C321DA203F20491FD22044213E21AD2066205221C21F89210A226E212020F62032216F202B21C921902267203921EB21BE232E21D921D620732168213B25D72F5A2B6D244E22842202228F20F3203023D820E0217E213C21F120771FEE1F5121D520FA1F0B221F223C21671FCB215C21F5207E21E821E320C320AF1F9E1FBA218521F1215A1F831FF41E2F2101204F207620A120AF1F4320F221D01F21212F21B020EF20CA20F7205821FA212D2363201E21EA21F6215F2292224E246A251B2EB42B1125912108224D221C21FA2102223B226123F322A120C12086203B21D7217C2113226621FE20E621831FD321411F9E21D921631F51219A1F3D20F51FF821FB2045207420C1200A1FA02150219B20D4224522F51E6D21BE2040215D2170222521EA1EF1212721A91F0C217720632159213722B722A5201C23FB220A26F32EAB2BA3257622912166227122A721DE2341228E2142211F21EF1FE11F6A215F22002165218C23D22002221D217B216620E921D622AE20DE200C20D220C31F4321A5206B1E7820511F121F39219321EB1F24225F211C21B71F2422C42080233221FE20F0208920B11FFA21EC1EB1203822C9222C21892123221C238A21EE23682F012CA6257621C122F5211C22B7219B233723CA21F3215C225C21961F9C219C21AE2218223422F11FCF21A2206C2161206A202522A2200F1FFA1FE9212E201720061FD41DEF1F111F641E5C201420821FBD213A22FB1F8420F81F8D1FD71F6C204F212720E21FBF1E9B203A20C5202922F8219522E1200C207921E323CF24AE30B32CCD258423E320DA230C24A222F022E5231A2377247022A3213221A322D52071215D23032243205D214020B1214B21F1201D23DF2183205621CF1FBD1FEA1FC91EC11EDA1D491F3820A01F4620F22149226F215D211B1F0F1EB41F0120C52128212821A0207A1FAF202D20D92077224B21F5239B224B209620AF238A25D92E ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 403F ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 0009 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 AF287B22C522FE20BF213B2130207C20F8200020991FF01E1F1F561E4B20591E711DC51F501F311D041FC81E6720CF1EA41FA61ED11FD41F441F191F0F21731F431ED81E331E5D1CFD1C8B1E2A1EBC1E091EA21F6C1E0B1E091FB61E591EFE1F55211D21E320B81E0620571FF51D1D20601EA520FD1FB91FA71EDC2119233A2EC82BF923E6202B2309235521EE21542252223720A2217020841F3F20CC1F831FBE1E081F0B1FB31EF71E4620AB20D721361FFB204D1F5C20BF1F3F20EC202B1F6F1F5120751F5A20931EBF20951EB41EE2202F200B1F881E331FDA21ED20BD2054217221E421692099213221F41FA41F881F3421DC214F214C2243229F24962DB92B982525244B232522B821792295233D21D4232923D6224221B120F420F120DE20D021A720861F9F1F5821AB20BA20BD2132221421EC2066210E1E24206B212321072244216A210220CA202D20871F4F20FC20881F3C20FD20D11E3A2125228D228E22A72113203F211D21F520861F761FFB1FB622FE20CE21A222AB258C2F862C5D28DB245E220F23E222E8237E220A2259218C21AD200922D12069221E205C21FB20C9206A2223206620AE1FAE219C217D2285210222CA201720AA1E53201422A02173229F1FC21F3521D31F5D1F5B202321072153210A21042151221623ED236622752235216B20A51FF21EB41F3120A920A221B92262213C23E824D82E2F2DB926C822652279226023B322C122F822F621EA21D121FC20832016227C217520DD210721B72090208720DB224E1F34206123EE20271E3221062178206D20FF216F22BA217C1F9720F720FD1FBF2177205422662084203A21352271217B21E7227A22E522452018213B206F201C2094205B20292177209D2180233D249B2D292B45265B23BC2457225724BF2295228823752292224D238E205E210D2254225C228C21A02036227D2043203721CF210220A02144212D216721D7212C213D222322FA216D21AF1F5C223F2088214F2192218F21DC21C621F520BE21F620E321BE22B322D2200D21EE207721ED200F2173207B210E2362221422B8247C25602E852B5024AC239223262331236B2454238D2265233E228921DD215A21CE2207235323B22109226521C1223E22FB20A521D21F8920EF219C22B3224122DE232523CE212E22D921712149219C21A321D920452294233B211A219921D921AF201721522259205B21E12000211521B520C2204222CC206322672172234924A224562FCB2BD825B023D0249923F7219F223F23FE223D23EC20A7218D22F923ED2106222423842216232F238722D120C2216F233021B7217E22D72109236C2394229A21C421522297220222C622F4231A24D020BC234C22AD20E51FA3205A1F1D219B201421BA20E4202821D5215321B420BC216A21AF21EE211922F32464251E279E30A02A3826D8243124A72451232F220D24A524602344229D21BD21F121D32232218D21122367231C230B237221E11F5F222821A2231D2263211D2253238322A12133222D238C23CC2394230323FC21442227234921FF211D20D5224021A420E9206B219620B3227722C9230822EF200F22152313223823C8231025ED2619273032182D672410233A23BB23C022E0233A2350243D22882390223C21A7221723AF224A2354226D23D2227E22F022772005223B215F240F246D228B248C22DA21E7210522ED23772331252C2432253A2401227B228B22952182200D20CB20E21F9B2034249321C12048236F2365235E238622D922E72322248A25FD258728EE287E34792B8B27C324AB2398242F23B6232F234F230B237424F3222223F52131239F23BE2324231F247224E621F3224E212923A3219D226623872327240123C92128211B239522D223CA2590243024D724F02146225920472038207121A420C32046228222D521F42157232E24E222B12179230323A322F523E9246128BC29982A7A36852C2B26DF23062689236F227C231223722429245B2331239722432382236C24D3232B249A24922752240F25D021B622FC2392259726DF25B523A7226C236422A22117239F221C24D0246C24BD247023212306214A2199215221DA208D201A2295225423C924EF22672538252D248F258D24582439253F27772832290A2D3E36802DC5272D24F223F223BD23142438237B24BC23AC22CC24B823C0255F2532264E25CA242F24D3269124CE23CF218825A5256D27CC272A264325A8252A24C524C3227323AB23BA224A22F0239125F922342120227A208F206D224622C420B022EF21C222BB21DC223524E72444250526AC24FF24AD2827295D2BA42C4C2E1034382C512768246D257826A024632509260D26302528238623DC23D324B42655249F25C825B225F725112550230723C9238A257627DA261D267127C924B82489235825212462236F227D233123D023FA216B235A234621942052206521D4218E222024C8215123B823D425C8231E23D824E2251228A9298D2BDC2CF72CBD2D1237972BA826E425542571271626BD27EA240A276F235A2457250424AA259E25B925B4237426B627A5251024F3229C22CB23E324C2247524AC252C25822487259526DC27D124B723B02288228D2177212222AA219F221E2268207820F820FC1F0D217D228D24632628269F27E9250B25B025D9261627E42AA52AC52B7D2C4C2CB834352E372935277126B0275728F626D8269024FB241B251C244E23B426DA27BC27C5246026B125B125BD263C26D6224A23A8228A2428254E2483247E251B2607274D274F2459230122042143241E2216229C234E202A207920E5208420F6202422F7246F2529291D29252A3C2A5126AD26EF253E288C2ADD2CD62BC02B8E2C0334122D602A082B432B4E28B52641263C26DC247C2491256D247D2497253C265126AC25A62440250A25D0256123FA238C247D24A9253425DD228A249F25D3258C26B925AF2562246C2224211C20FF20E121012281219D2070217D2365211D216F233D250527382A0E2A4D2AD328F926C1231E26D7267C283C2AA52A902A5D2BC2339C2F5B2AF12A5E2881277927F82594268B263226E62462245024F92419243725E324852595266424C5237224DA239E243424E926DC26EB25DF259A24DC25E124EC2522247922B421A5235A234B2201216B22EE234E22EE1F5F236021C420C32120263826612988286A2ABA28CE2994288F274626B8259D267727EE26AB270D33002EB42B38287328882787266027B6265A263925C1251023E623D92476263F25C225EB27B325A727AE254F23FD24312772265E298F280B28F12683255226C4247A24D223DC23DE21802419247E2491218A23F521E62122216B20731F01209721B62395265829672759290A29D9276825A125BB24482446247326CE25802768312D30F22851268826122615264126352797257224AA24F1247C25B924BE286428F92771250828B2279224C8231224FC2510291A2A19282F26B5290B2780265423C62397243E24BA2480248324D22244234E23A0222B218B20F8212020E7208E22C324C6249625EE26E8287126B9258B27ED244A24DC244C24122512260D26C830C22EAF28692710270C278727E126EC27C0276226D3265125CE25D327D128DB297C29BD2C192A0D28FA258A26BD258A26AC2850289E2835270627E6265B25D7252E25D625B2252D26D1241D2413261E2398242124182341222A2000220221D1210423EA2260248F25BA271E278E268728132537251D2734243D26C52590251731B62DA927FE270827AE275F29C92A342B3F2A0628E5239B26E527C32A1D2B622BEB2BF1296F2C0129F9275026A72699269125BD26C42476259226BF24CC2569247025DA267F26B5265B26C425DD246C2582268125C322CA22E2211B22DF20CE212A234A2583250627282843269D26F7242724CD25E624D5262826F4244126CE30942DD527BD260229332B0B2DCF2C772B7A2A9E2790269626C7276928692B842A422BF72AE72AF127A025872599252925042451244E23FF2350249F2235248624DC23852513264926F5251629C927BF252828FD2646254223B1222622EB21AB232E25CD26B1297029552A462A2B2857262325F323C9244125BC24C2241225D7305F2E822880289B29E02BB72AE12B1F2BCB274424C1246626A8257628862B0E2ABC2A932BA6291229A6262E260F27CA260E254323302205243424AE223C24AC247D252927EE242023EE266D2863293B2A7D2AD3282328DE24DD2397225A222F256B2430272729EF29902A9D27802717280E274524E5249C24C7256824E9268C31162F2C29D7270629032A2F2ADD280A273F27A024CC268926D626FC27D427D828A7287528B3271929F5253425CF2695255C24CE232023EF22AA229F230C24DD257A26E927E3264E2686262927472A812964293729CF277525A8240B22FD210C23FC26F426F2277329D3280927792627297028C2250D25BC248326C3268D257630752F0B2AB5282929E127B327C12765268F251124B325FB265F273D29702AD82AFE2A17279726EF25E426A6288826F0268A2532259424E32244251C26462864288329E42AC82AA82814264A28BC295528D829A829E52669237224AA215921F82347243927502901284A2877262B273629B6294E272F25AD23A7243C2471279E31A830C82A802829263027E3263F26782543255F255C2844297628C329F72AE32A9D2A4E29D5258727F627D628CB28C229E52744257A25A823AD255E27A6296B29942B132C2C2DB529C72A7929072A172A9228CD28432786244D2362236E2106249F233A25E5276027F6266D25BF261D2887287C2791262A25682316253D267631C92F662B2C279B276E26822650268126DA25A4268F2A072B5A2E372BAD2BB52BA3290429D927F628322A7A2B352BDC2AAF286A254423B3240426DB279B28262A882C5E2D8D2C1E2A952A2329CE293529AC297529BF2794255923E7222721D121EF242824CE246526FA259F255D26592770284F27A32772256E25362590285D3392303D2A662A432AE62827261C268C25B526E427EC28202CA32BA22C762A6C2B7E2AF028C229A82A802BB22B692A1A296826D7258B233F24B526BC27EA265229DE2BED2C162C5D2893277927532600283A2AEE29DE28A4251A254921E021D722C62287236223A525C42533262427BB29DD29E72AE3281C25DE2460278B2827336B32712C4F29E8295429302ADE2636250827FA26F32B1E2CC82B20297A28A928FC28A5284D2A332E4E2B4A2BF528642947252E24B22417258826F825BD252E27E82751281A28E2261C2685260F261B28972A612A582A2D257C24D4228422C422C92316258726472756281A29BB2839294429C628DC27B425F825B328F529E6350D32482CC12B8C2BE42BA4282B262B26C2254A296E287F2AFC28C8275B25882327256827BD2AFB2BFD295928B328EE262324EF235E25782445261F269325E724FE24F7251526162629261C250E26E726BA27252A18266D24C82353234521092284228626E5276827322B8C2C322DB82B2A29B826C925BC250E29D02A602C5A354331C52EEF2B5A2DEA2B1A27052576249827E928D72A9B2904272326C827B127A0261E28312AB02BF927AF26DE24152349234C25FD2536261C27D3241D26E62492272026EA262C259E264828A1279B25EC26CF277D24F823BD2314233E23D021D523B825D426102AC52B2E2B7C2B632AC5280028872502277828D72CE92DE1354A31E92B802BBA2AAB296B279D26D1253B261028B227632645266D25EF25B32643286427C8296C28EE255E253624892247233C261A28D628962775260925E126DB260D273A262726E92537294628B5272028DE27FE244023E72219226522D020E32233245D264B28822B5D2B0E2A47297C289F2609276B266629692C712C27352631E52C962B872B36286B273E257A26A028BB28A8274F2786261327D32761283728972916285026DB26AB256527062500253327D32934280528E227CD266A28D82911293326F424E6273E27812862283A2AF1290C25B523352389216E2108219B210D241C27E1288229EC270B270027D72872284125CA25F428732A4A2B8F353831722BA329ED293729CD25DC273D27A62AD52A0A2B822AD12AA228DD286C28FA28A928182799269729122A812994296E278927CF2ABE28C9264A279728912A622A1A2A0C262B24DA26B628722903294D2ABC29C826F3248622D022392377201C23E823422587260A27D12709276A28EA279627152799258B262D29992983330A30FC2A932A28281828FA27A9298F2AA92B062C2F2D772D3F2B8729FC289728782AA729E4270B2941283829F02A5C296527DE28052B6328A9276A28B5285E2A8829C427922706241F25372A302CBD29372AD42C152BF7269A25EC24A923D62374231C25AD285E2A9E2A8D2878256F2722281C287726CD242A26AA2885296D354D31732A2C294B2795273A289229E12B7A2B032CCB2CBB2AF828002665270729D82A9B2BD929632AEF283C271526C827FD2680281A2CFF296529872A312A7C2B1E297527602583230E25E428E928CB280C2B222CF62A40285D269422ED225A22B22512242D286D2A5629BD278127382906291F283827B0256A275B287D2A95347B30CD292827DD251328252A812D1C2D102CF52A1A2B5A282F25E528CE28FC29002D812B832A012AFD298625F024092632268D27932924292D2955292A2A8B2B45294127A4250D250327372747286927B72AE92A132C84287A25AC241523482217241526D326D02694283427DF296C2B552B0D2894286126AF2622295A2C7536A82F5F286B251126E927DF295F2C912BE72D272A452AB7290529D528052B322C5C2E822BB429C02A9529C32878275024FE264127C926A827C3251227B42826283427C0262D279C254527352820273828C629C029352A992847265323CA22E1230225F6259927012736265F27C529602CB32B982AAB2A1D26CB278929E92CD834DD2EBA27E22589258F265B29F62B6F2C3E2CF82B4B2C832B692904281729522A1B2BEE2AA4295F2A5D2CE7283E270B27FF249125A5256F25AE2474241D26B9244425FF24A426FD275D29082AB2286D279A288329C7299C271727922387228F22CF2329266D28752737271A265228C62ABF2CE02BA92CAE295529CF298A2BB6346C2E47291B264E27C328A42A862CD62C032E7E2B1929EB27B8276328A828AC286F2A0B29D8253B2A1C2A042A5528A2259B2532263E243424032618238423BC23C423C6231E2642281529DD29C4276F27B9288329B229A5272425FC22FD22CD23F222C4243E262426DC26B926C9275329BA29FA29692A51292328C926E929D532C2308628BC24C027B627EF2A5B2CDB2CDF2B3D2A132A9A29A0274526602703276E27B42645272D28A129A0298A29282A7D2A8928DB2692251126C42509248524AE226D2456288B27F5285B2AE22AA4293429232A0A2B6A2A4D29F324A92230223C242E24CE230A250027AE26B0270128F1274C28CD2AC9296B2A692A9329843025316C29F127AC26BB2B4129AC2BF52B542A962945293129D72700276F28CD270427E2259626F22580267F2681262D29F32ABC2AC0291D2A5529EC27FC261125B023A823622700288E2884284E294629132A2729212AAD273626F423CA227F216522AC23EC2391255F28BC286D280A285A268727FA285A2A222A17271C287530982FC82877263F2744297D2BEB29202B792BFD2BB42BFD2AE729032B39294F298727FD27E226F225FC234E25F4262429F128A92C822BD228EC2AD129F028CB27A425FA2522271B264326B326C8282A272C27FA26D4253425AE2546233822E82277217522602592279329782AB0292D29D727B42685286927EF263F274428DE30482F3F290C27D026DB28F82919282E28592CE72BAE2B282BE6283F270F2A162BF329812AFC278B273E296E28A92825291929D02730273429A92AE82A072A3C274C24CA2504277B251426B0261C26DB264D25B12689243225F422D32295219521ED22A2247C272029132CA529BA2994293128CE2785295529F6296E2833271C30D32ED728A026EA273929732880288129742BFB2C9F2A0E2A1129B8281929AA29242AE52A4F2A032C5B2AF82A532B0D2A8C2A6F288F26482745297227F427BC24F5239A247A26F1254A25C524CA26DF253725F7259123F6235724002168227222A222442427270D28112C612B28296829F628BD29822B78299A29272A42287130AB2F092CBE2AD72AEC2C8B2C082C4B2AEF2A222ACE2A8128E5267D27EE28F829202B052C18283429022B8D2A442BBE2B892962287C263328532927295328EA25A3246A23B8253D27AC26E3266229E7273127C7251C2625253A223F23A522D22127212225FB253C28972A8329C42712296C2844278E28B326922699268227B0313531122DCC2C892D8E2CB12DE02A2A2AB02A252B4D2A8F2A4F29512959298E2AD92B152985287F2833283728652A6D2AD928552854284328392874298E27312459235223392728285D289728F027A5270D287528E8256324DA235E224322DA22D9224825C526DD26D127E52641272827182655263B265B25912547269D270E327A32D22E452D462D8E2DA52D232C0B29AA28FA29312DAB2B362A112986297D28482A08279226DB25C02473270228D02A822B3E2A672854286129B5262A25A2238023B5249B293E2ABC2A3229C72734260127E9272025F624E025AC249C228E2337231922C3244625E7267626382674284A28862699247124AB26E227872AEE32A330F82DC42C4D2D3B2EDB2CD729192AB52B342BD22B8E2CC22976285727EA283D27A72659267F27AD26C52574276C28892A372CB12AB8295A2767241F24B623F024772652298C2BDD2AB42986274726FB24A426C725B424E7268027712442228C202424E0236E26D726A7266A27E928FD29242AF02733253A27A527CD29AD34D42FD82B032C6C2B812C872C042E702CE52B122B7A2CDD2BEE291A279F268A259D273A2A20289C285A258B27BE28FF2A3B291928D9280427C325AF25CB241C23CD224D2525276528362893253E24672471263725C225FF26B8288B2936252E24FE22E22440249524BD269927B028132A592AB12850287327892975278D2A9A32802FD22BB22B2D2CFD2B3C2DCE2C092C262D6F2CF92C492A5B28F626F2261327B52616280C29082CA928CC27A32AC42C0429F629D32814283C29DA259125E024FA252328BD2634260A259F24612349234725C426E6255D25DC26FF2641253F2320231624D3246324E2293F2AFD29B62942297429F8287127B62731295D2AF933A72FFF295B2B302A142C472CA42B4829AB2A882B9A2AE9291A2930275429FC29FA29C42BAA2A4F2DE32B9429B32A892AEE2AE427B728F9280B2A9B27452772266A27EA29312AB9273326CE23E623DC237E247C25F1232225192877269924AC23C52273237224B026DD277328BE290A2912270727C52988280C2869271D2928351733A92A19297327AE281929FA2888299D27D325AA27C726CC257227212AA12D522BF22C4D2DB82CE328C628092A532BE4297A295C285F2923290A28DC271228372BEB2B422A802870258C24AE222023EF25CA26DC253727C62669276B246223FC2346228F22F825FE295A298C296C2A4E28AC26B428422634274527C3274A31FC32942D2B29E628CA29E529CE281828AE257F264B28B929BF276B2A692B4B2C382CA42B482B442A992A3028BB2ADB2BAA296D2A422D9C29C8297329AC286729B32B832B432AF729E92710257624E623F426382AE529BC288628D8295628EA25BD257523122497265D291F2A6B29A329B328EC28022BC8286527C5263B26E42E6A346F2E362C2F297026F628DA27FF28112A2E29A629592BCE2BE229C62A9B292A2C1D2BBE29992A3228B3283129922C6F2BF12B862A102BBB28F52728299B29C72A5C2CAF282829B3275026FA23EB24A927012AB3288427CA27BD29C429502709254C24BC25EF2362292F2BC129B62B622AA12A4A2D232ABF2708274B27ED2F5C32652DF52A7D2956276228A6298A2D382BA629032C3329942A8F293B2AB5283B29A228D026B226C9270C25C1298D2BE92DD62C9D2ABC276425DD241727D027A02755290029BA280C2848268B287B27A2281C2BC029412836282928A22720262624642393242525322760296B2B312B4C29F528772CB62A2E2A1627FA265030F332C72A8D2934282E287228E42C3E2DDE2D1D2EB32CD329B6292229F029CF270F27332635257926EA259B26AE27BB2A632CF92A3E2A3A270824CA2234244125E7266F28EF280A29AE28D227BA294E29B92B442C752BD427D127D125662561256D249A24C62585237F27F027DF282F28A1283D2C392E5C2DFB2C0D285927E6307331F12AF3280A27C426CF29D52CDE2DD62DF72C3F2CCD296A2A8D28F3291529E3268225E12550276E270127D128D029BE2A192A842A2326D224952347254325A9254028A72AF9290E2B762B002A3D29E229D629A7286A270226F624732467232223FB2303259424D927E0274D2882289227452C882C922B712BB027EC276433FF31DF2BE32AA128C928502BA62CD72CCD2C3F2B8F2AE027D3276929942BB729F328CD27502778299D29FA286327B728642C8C2B5528EB231024102586258B28E227102A562ABC2A2D2ABD2AC729CB285828A4268F284827BA27F826D4248B245C2374222125D824E4288728DC256228A6283B2A422B5B2B9D29E42849292533C032A12C722A31298E29A02CDC2BB92CBB2BCE2AA32A5C298C29E228F2295C2C632ACF29FA29762BD52B582C74294929FE27B8278A27CC255523CC26082784288929C52AB4290A29062821279A26F9263A28A2284E27B4297929FB282328BF2586243A238A241427ED2A292B022AAB281028812861298827902722285F29CE331A31EE2CE528CA271E279529AC2C9F2CAC2CE6291C2A2829B32A7F2B8F2B9028D12868287529122CAF2B662D522A3C28AB250D26412446237B2311263028CF29FC2AD029C229F62811262D25CA275B270629B8283F29442A532C0D29BB26DB2481257F25F8261427792A422BA52A5B2A8728B2278E28C427FD260725C227B9313731032C1D2B81265E273D2A1E2CBF2A5D2A702A552BF22BD22BBF2C3B2AD32AB429632A002A072C632AD32C572AC829F2262126BB221122DE233126D627F82855281A28A02A2827D625AE259127B326072916294428D328B62B15282E26AF2597255525322552285E2A1E2C432C4C2B3B299525F229EE25CB24E726582745316B329F29422805268C28B62C002C392B0B2B162A942CF82C952CAC2BCA2ADF27A92A232DF12B6129522B172B9928BF29EC28FC248A249F22F222CA23B52679277E282A295B280928FE25F32513279125522635280528E028692A5F2A4A2739267824012520244E263D2AC829C129742CE228892678274025D923022660245C316B31162B68264826E528C3296C2C3D2B612C912C2C2B4F2B6B2A0A2A7C29472A732B4F2D4E2C332B0229FE29D42A0129EE268326022454236E244C25EC26B7284A2A442A982840267127E8279525B12584271226EA270528612A64290729D227B7264D238A240729662B8F29BE2742280F28D629C527CC25A1234F259D264631412F3F2A9F27F627F926F629702CA22BEE2B6A29992C4028D4287B2656274D27452BB92C722D4B2A6928C227F4260B297B27F1255726E6236625DE2632279329CF2B802B4E2882266B29C0289D2502245B257826D926A826CE27DB288E2918286227392530261728E329BF299D26202709265327E127F02687256D24CA269631882DF0296727DE26602A8E2BD229352CEA29AF2A682A5327832783258927D1272B2A322D8C2C692CC929D7281C2AFF28332721273A270027C3250126EB278029672A372A4D2A1629BA27152888267623332460281B2581255A28CE28BD286027F1239B23EC25B526492BE928D5269C269C268B274E283D27AA2509272928D1321D30712B722AFC2A0B2C152DD52B062DD42AC22AA82B952B9A27A9269426A1279E297E2BDC2A182D612B1C29DA2A6A28AD28292BCA2BD8271926DA26892658264B28B2279B26A426C5272628482732276428A3294F2988277A25D824572598227A227124D6249A26E6279126A628D926DA269B287B2ACC286C26B2267C28F3301632522C292B262A842C722E5C2DCA2C472CD22A092BDE29C8298C280C27A8273226E22785279D29502AB228252755291C29DC290B2A34293428702626265C24A026B52590249A264D2787267227ED25F1285E2B5729FE286F26E122C5238422D622B123F5225E261D272429FE27D827282895283728D928FE28FB263E2734312D31BD2C1D2BBB2AE82C5F2E1C2DEB2A522CF62A142CE52CEF2A9F29E1298126EB25F42703263B2561268A25B326352754287929F52A402974289A278827F6274F27C026472628249D26DD284728B7268D29572AF9280326552774255D23B124EC2381233A251426E2284728D728532A94285B28C227D02788278827502846318430352CA72C0B2D0A2C752C6D2B552BBA2BDF2BBA2B5C2E8F2AAA290E2B4429492ACE28C026F9254126E32608265C269C268E27BF286C2795283527B0272027D8289F2664260B25B0278728C82853286D2AF229BC28AB25132873268A26AE2616251124DC24F32518291229032AD1285D264326D4240B264626FF27442AE634A533C32D7E2DF62DCE2D612D632A5F2AB32B882BEE2BDE2D362B2F2BB82B3A2D252C242C902A892790280B28F327B5270127EA273C28EA28A728992834274828262B5729862949275429C02A0C2A6B2AA62A3E2BF12605270E27A42A3A297927F12637243E263D27FF27AA28712771271E274F250A2500269728FE28DE2C3137D231552DB22CEA2CD72D322DDE2C3A2B782A7F2AF52C372C852BF129A52BD42D042CC92AFA2A8C291D28C527EA25CF26DB26A329732AB929F1296428EC28D92BEE2A482AF4286727A92AD62A5E2A452ACD2B6F295C291828BD29162A132B92295F28B5252D25DE26CC275828A728D6291928362634268F255428DC29572D97376E31482E1C2C412E842D1E2C802DC32BA32B412B132BB02A4229BC2AD72B722CA92CB72CFF2A222A28289C2BF928F8270727692B4B2B1F2A382A5B2AFD2898290629F326FE26EF25DD27B12A902B632AE029E329A729AC28E9297C2B4E2C2D2CD62A7E28B2279827E5280C2871291A2B8D2B912944280E25F92784293C2CA8367C32452E772E8F2E7A2C632A9B2A302A9B2C032B2F2BAA28DF279B2959293B2CC82CD52B822B562C532A7B29FC2AAA2A9328B52844281728AB28E5265128102868273926B726FB24362657299A2A832ACB29C928BE262A268B2A762C3B2BC52B392ADF2B6C2A4E28B4295528942A732B842A692BF3293A277027E3280C2BFF343731092D992C432B9E2BB428FA254328F42A5D2A372986268226AE27042A0A2BDE2B522C552CC92DAC2A362AEF28702852250B289D28DC26D92783265927EC265A260726AC2486244B241027A72AEC2A7029ED29F5262C27742A682C552CEC294F2A442AE22B5429902998287728AE2AE729E12ABF2A8C26882593275D2A48345030EA2DF92BDE2AF2296A2839277E29C62A702958275526BB266C28D928992B232BDD2C642CAA2B3B2C3E2CD2291B271C27EB279A285D276F2556262A254B27E629AC27BF261524B3232E268B29AD2A712B752A5B287D2A2F2CD12AC22BEB2A0A2BB42AE82AF62BDA2AFA28AF27B02A3F2AEA29E3270527A72428253528DE31BF30B22C5E2CF12A84298729E3296829462BE6280E2824273D287A2B3A2D9D2DAB2D442D882DD52C9D2CAC2B70290E2811278229112AF326A6259A241428BA29C32BF32A422823242A24602711291A28FE2908296828B0298D2B212C702A8D29FD27CA289E2AF828502B622B662805291F275828152732235E23372541267A31F22E302CB52B802B292A8A2AC72B212BD329D72A3128F927592A282DE92CD42C9E2CD42BB62CEC2C772C432D9B2A1329A428182ABD28DE24EB25302618282D28D2290D2C002B2D277F25D02901296C2AAA2A6529CF25A4267529B02A692963284C27E1279D257C28612A742C862A3B29FF263327B126B4258A254925292673302E30302BAC2C942B8D2C602DB02BEF2D4E2DFD2BB92A6829572BEB2CB62BF82DD528F92A352D9A2DB42C812A612A93289225792620269027502819280E2ADD2A972BE42B322AF22757260227A628322993282B286D255726B9277F29092AC92742252F2597253D283D2C562C932C992BD628402727279626FE250F2554260731F230542B392A652C162D5B2CAA2CDF2D642DDD2DEF2B0F2A8E288E2A6B2B572E3E2B082B922B322C6C2BEB29FF27FC274523002639278B285E2A292BA5289328332A122BE8299B285D260427AB28AB270E279F26372684271529362877282427A32447253E256228EF2A1E2B132DC22A50289929622A72274E266F24052756303F32802C0E2A932B272D2E2D3A2CB32DE02E2A2E762C052B202BFF2A5B2D822C9A2ABE2A0E2CEE2C332CF729A6287B25F8251B2662277E2ACC2C012A6027E127652859272626C8241325C725B12713263A27262783282B28A82A1B2BA4282028A026E42522274D296E2ADE2ABD2A212B432A9E2AD32CB82A36290727EF27AA318C31662C7E2B8C2BD22C4E2DAE2B832CFD2CD92CBC2BB72AE92AB22BA32D2A2C4E2CAA2B772CE32BC02BD3271B25C624BB2273251A281B29672CCB29B328A9253A2760279728F425DD244125072816272F2782283A29A428D92D7C2A7229A4276F266B29B32AE929332AB7282A28C1272127A629E42A592A4527DD25F426EB2FFB30A62CCA294D2B062D212DB92C212BC62C972C882B2C2AD529572BA82CD32CCC2A912B552A072C952B7D273525ED23652436268029822A6D2CE02AF32A8629C329DC2A052BB928F225E1241228A526222737293529702B432B512AD727272647272C2AE82BB12B242AC82852276727332781299F295227E5262D26A42623309233E72BB12BB32B7F2B6F2B162A392B1A2AB42BB72AB6286D275429992B052C852BE029F32A172CB52B632834278725782639264429A4297C2C802A0E2A582A342BA62B5129FD28F1260926492646276A2A232AC62BA12A282C632919268126EA264D2A5B2B1E2C1C2CF628A0287E28282A672BC729012774279625592731329E319C2D622B892A5E2A8C2A5F29E028D7289127B127D9231327E6279928772BDB2B662BD72A682D592B0A2A092AB8275D2657272829BA2B112B2E2ABF2AB52A9529412A1F29572676261B251726F6253728332A072C372A9B2DC6287028BC27FE269E29752AB22A9B2CAC2AC2296B2AF42AAA2BD02D2F28B7258325E12731316E32372D752C932BE32B2F2CC22A8D2C082A9028D6260B2669262428E028792C0A2DAE2B6F2C872C9D2CFB2B342A46287A263329142A142DBF2B462A08296A2857282528E0278325E0246F270D282925E827282C1B2D3D2CC62B3B282F265326AD281129A92AA72C432CD72A5B2A6A2CD72B0E2BFD2A6A28E8262629672AA733562F242C062A7D2BAC2A262B762AAA2B232A1E2954294C288B29B729E52BC32A2C2BE42A1A2CDD2B822BBA29D929EC2788267B297B29412B2F2AE927EC266C263C255D2604269627B02803290A27B725B427A5291A293529B828D526CD26CB26C329BD29A82B662B4B2A182A9328A028A22A272A02290427B9282D2A9C2A3E352031162C662BD62B662C0E2AFF29A72A822C792AE829222B452CF12C132C622B6D285B297429B22BE12A9D277E28A12574250F28CB29B32B992AB829C226D5258727AE28A3287F29A42A4F2CDF2B2D26B227CF27D428B9295A29812505273E27D62A4D2BF92B322AD32B002BA0291F294C295328B927EB27BC29D02B992CB934CE31AC2D0D2C142CA82BD72AFD29912A322C802B142AF0293F2B932C922BE42AF2282D2777285B2A262AD927F7264025B224FC2772262C28EE284F2844268E27CE296F2A082B932A272BE12A7F2AC0280E276428C42A5828442746277226FE29652CC42BAB2B0D27AD28162B562BE42B0329FD27A4277A27B32ADE2B012B9D34EC32DA2E622C112C8A2CD02AD9281729162A4C29002A092A9D29432AB12C192A242777284F295D2A6D2BEC29552966272724632666278E27272A5D282E272D29AF2B922CC02CD7291F2B162AB029DE273029C12A332BAC2AB82A5B2787291D2C272C0A2C412A9429742B8C29DA2B0D2C7C2A8B2750264028892A9329FD2A93340634D52DDB2C442C8A2C532B612A9B2970274627E3256227C225D027D52933293A28A42873272A2A532AE428C4254E25F8247A252527B129552A9C2B6C2A5E28F52A6C2CD02A2A29112B8D2AD129EF290B2A762D252B4A2AE0294028122BDC2C222D4A2BFD283528C52AC42BC82C1B2C3E2AB7278A268126302706276E27D331FE32452DB42D502BEC2AB529102A892AF3271E262427402615254325AA2578279C27FF27E527F029082A8F289E272927B624D9260828062AF82BF629C929A129FB29612AA32B952B032C622A0429BB290A29F62C5A2B1C293829EB27AF27ED28FF29AB2B5D2CD028352AEF2BAD2CEC29BC27E1258325D425C3275728902942338B33B82CBD2A952BB52ACB2B422C382BDD29FB275426CE275E2686251A2663279B273D281E2AE029FD291228C1271C265426292796296E2A6C2B522A6429A7298B28F929792B4828972A81295A293127E826182A452A8B2A1B290F283B296E29972AD02BF92A8E296C285E2849293F296726B7261E277526EB2787289A285330E032962BFE29132ABE2B8D2BD82D8F2A3A2AF32AFC2A772A0C28C625F527C7274928A32A052BD02B23297828DE28D827A226B728D729462C182B86299F291F2948294028B128F827D429BF28D7274326AC26412939298328B028D025B427CD27972989292129F0251528BE262C28C12A222AD0281B29FC29AC293E2BEA2BBD317B31022D792B252C6C2DAE2B902DB429732BEB2BB629CE2AE42A26284C26BD277B28522B4E2C752C8B2B0D2A1E293329B528742ABD2B222C862A262B0C2A7E29C4298D29FF286C26A32928294A26DA239027B229552A13295227A5256527FB266C28A727A725CB264826B72567281F2A7D2B722C492C752A192BCE2A812A56336A31732DE32B002B022D682BB12ADD293929BE2A142CB22B142BDE28F127B927B1278328B42CE82B0B2D0B2BC12AEC2888271C2B1E29BD29DF2AC52BB829E02A2D2BAF2B9029EB25482765259E27DD234D25E928BA298A2812289D2719263B265225F726E6260C24252730273429B02A4B2D112A932B702BC32BD52CB12A09343032D42D272BFC2B8C2C8E2B4E2A4C2B602B9E2A2D2C922C392AC0298D29D1277225DD273E2A722C1E2B6B293C276D26A928E22B012B5D2A102B2D2BB62A042BB42A4E2B132ABA270327E527BE274226FF269D280028032921278B24F8250B2691289E257E259B243C257E25B227E0280527D929342AD22896299B2B5F2C6333CE30122D482A752BDA2BE62B3E29E12AD22BFD2AD129E22AC42A522A3B29BE270225F525A5272B2B312A5828012999275E29FF2A672B042BD929442AE229FF2A332AAB2B6C2BA52A9A29F328C928D0295729DB28EF27F126E2254D25262698265E297E27DF2473250B254D2524262227FB278D28D227A1263F27DD28682A3D320435772C642A182B0C2C8A296B295C280029E82DE02BB82BBD2A002A262BE4278025D3274C26C82803297F2892273A288428132A152BA428A629C72A232AB62B852B012ADC288129CA28DF28012956292E2A192B9F2913284C28D826C628752AA72BE9283E26FB235926492795287D2A9929052AF728E225C327C728012AD9344833872E252B152C8B29072AB2275A273F293A2B902DBB2B272BA12CC12A1C2AD927C728D0281829422701286E282E27EF27B129F32854275529D62702293F274A29DE27F5262828862603272828FA27CE284E2983283128E827CA27A028C82A3B2C092AEB26F1247926ED28CA2A562C692ACE2A7D28C226C82745297C2CDC346632BC2C852CA42A772B2D2B33280428EA276C2A242C722C0E2C102C132D852C8D295A2B772B892B1A2AED279C26C426342AAF29F9289A27BC26FF26B7260F26C526E7261027E72511267B294A298D28D3298D2C6C2A932AEE286328462BD12C5C2A6C28C026712698255128B529ED2CFB2B182AB928E027EC26032BCF2DAD34E3306A2CB02BCF2DDC2EAB2D6A2A6C2B402B2F2CDD2A462C782CA52B552D7B2C872AD629D52B502CD72873271D25C2262226DE29E3290429432995287026D627F226ED24492734279B27072A1B2C652ADE2CD32DD92A4A2858273E27DE29822BDA2BD12858254E243E257D28522A502CF42C222B3E2A6029922A0D2B042B6B340030702A4E2ABD2D9B2CF72E3E2DC72B952B682C9C2C2B2CDB2CE42A652CE72AF9298229E22A9C2BB62BFC274B2787255B266C29E3297C2B812A47298326D6249126DF27882736289528EE29C929AE29E42C492BE72B77287428E2299E2A142BEE2BE228D0261324E4259C27E629392D532BA52A932939296E2BD32B682A1C338630BB2B382B602AAA2C5C2C172F142DFB2A022B552BC72B802A152DD82C232CC12947294D2A0F2C712B0B2B252976278827D528D629542C0B2B07283D2658259F270929A029A4280428B429852ADF29072C402C992A6D29AE292A2A1F2B8829212B782819241A231C25252806286D2A8629082AC929BA29502B672A5D2A0533F330DC2BFE2A882B922CAF2D042E612C4D2CC42B392A3B2CB62C882CE92B1A2B96298F2BD92A5C2A9829B329272E9C29FB251826DE283A29EA29CF28E0252C27562726287E29E527DB268027B828BC273D2ABC29DF29C82AAF2AB429502BAE2A382A4B2810265D22712475268F29482D912AD32A9F2AEE2A4A2BC12B382BFD311C33B82DFE2BA72B602BA92B312D9C2B582D7A2B6729622AA62AA42C762CE32A602A0E2ADC2ABC284929C829522A2228D626BD270928582BCB2A7328CC263D287D28EA297D2A9D272C280528E527F4274B287C28EC265527ED27F52819298D2A152ACC2758257C24D9244526E328CB2B102C562AEC29BC2AB52B462B342BA133FC32172E172CBA2C9A2AFB29172B4A2B422A3128C5273728D828792B712C2E2AB62A072A262CEF28F42669288C295529192752265029562B292905282C275F28302A942BFC2932292E282E2AE7281A28722782268326682731283129202CB52B8B29C22616263624BA262E27EF29882A642A1C2B302BD02B982AF22C282CF7345E31402E872CF12AF72BD32B332BB22A422A332A0D2A4C2BC42AAF2A952C022DC52BF22B122BC7286C27632B992ACE2AC5281127C8279029702AC729B7286729832C5C2BCF2A7B29CF27412840292B288F284128E4272E280329A727EA29322B4C2AA0280825A423ED25082AA82A632A5729552B402A9829602C402B262D34357031232D702CD82C872C4F2CAD2C392A70299D29E2292B2B002CBD2BE62C5D2DAA2B152AD22AD52816285C2A9C2AEB2811272B274D27792759295A28E5270628602A8D2A5529C027632726297F2AB928C627A629C12AA829372A0228A927DF28282AD22792259522B4252028C129EF2A14294229082AA4299A29352A612BB433F432042E742D152CBB2D472CF22BD92C362A432A142A3A2B922B822A722A752BF72BBB2B702B6B2A8C271A28FE2BF62A12280026B32533256127FE255E263D29D52AB92A67287D25DA26D427482802279927E229AF29262A822880273928742887291628D42584231F25F126F42ABD2B1729BA27C0274626B827B728E42709329532D42C022DC12A5E2AB22A552BBD2BCB2B122BAF299B292A29982A6B2BB92AC72B8A2CE329832946274F28C62AAE29CD295B273124E423D224B3258A257727DA297A29042814261D2691262626EA26B427532A752A9A29AA292928EA26272931290229542730240E254B261D2810298B294C2795262F28B227C32715286032F631432D462D272B002B5A2AB42B5B2B602CA12A362B752B342921288229FA2BE22BAD2B0029EF28C727EF28212C862BD9295629B924542355251C2441240A256A287528E325F22465256427D624E12505293129FB293128032958285A274229B3288A275E26F3231E25112671258A2884292B27072916287F289B282229A731E82F4E2C7A2A442CAF2CE92A582C252C442B492A252C8F2A6429242700273D2A202B1F2B062A21298B28452AFC2B032D6A2A84272825D2242D2664266926912769299629B4274325A926C728F3265C249C28142BFC291F28A5283C274F27B028E728EA269F25AF23CC24212496260B29102A6C297F292429F0289827C828CB319730EE2A2A2B152A162D112C872DD32C9229E229712B972B3E2A1828D8286C29FB2A062A222CE3289029DB29FF2B852CE3292927DE25F924F524D72427269128E6294028A725CD26A827B027AB29EC27912ADC298329B6283B2882282528E5268D2543258F2631243D25E9249E277D28982A162BA82B332B702A4A29832B3734A531F32A292A5F2C6D2C9A2CB52AFA2C7229B729D32A9E2D262BA029002BDD2AF0294D2AB327AF29DA2921281C2BDD2B872AF3277C24E623EF242B2538261729C028C82788265125E825CD289228BB27AA2929289A279A281329DA281728AE2858267A261F254324B0244B242B270A2B072907293D29B9279B29582B582ED9359B32422C072D3E2BF62C7B2C062C092C092ADA27D828992AB02C922A9E29192A6C285528D327EE28B5289328B929A7283B2679275925E123AC23FB245F250727F4284C2A3C27B325E0266025FC29F529692BD3288526D7252F274B28A328C82840283526F3265D24C92559246F27872743291C28C92818279829C92CA12DF3362931692D2E2BEB2AF228342BD02A6629CB2979296D2AB1297329BE29572782251C27B7271029A3287B26F0270229C428EA27C5272425B9237623FB218C23482514260627BD255B24D82418250126BE27E0291C2A4F2759256A26B82801297D2A952A2627032474233D2521259E2638273E277B265E267825F3267929F52CE5364432762C312B61283627FA273929A72BDF2AEB28512A7D2A6B2A2127E82534251424F12710298F298528F22838286F2B582A73286A25932538255824C924B525BF267B27DA2684266424D6258726582875273328DB252E2576263A263128A1293E2A75274325E424A82554243A2559267926D1240125B0247D266728F72852340231562C872AFB2957286C27A4283C293A2B9E29372A3C2B952A73299928BA27EF25AE2586269128E528A428442A9429AF28DB26AF250E252F253B241D238B23F5244824E8245B2393257623512593257126A32701244E2319244C260C26592884282D264024B9231523F92201268D2697258224DD23C623182505260229EF333732592D7A2D202A742805280229712A5E2BA42AF02B972D5E2B7A29A1291F286A25A9244A26EC26EB2999298429392A83298228432848252125BE239F2198226F227C229C249A231B24302357230C23FB244A251A246525DD25302445250C27042876277723AD230225C4243525D1259624612450244123E124F5259E288D324432442C382C7C2BDF29C229232AA229522A752A572A272C482BFD281327282508248523FF24E42537282129A828AB281526692506247B25FB23A8225F22CA205521DF20DB22C723CF2329238622B92321258E244224A0251523462337244724ED262D26BE241C23C42331253126C527B32536258C2531259124E82651271D32562F2F2C7F2CE72A232A0A2A1C286E29022A162A992B102B502D402AF7289E2593244324C924342519285928EE28D029222597252B25CC251C23C8228122FF2024215E22B122A5228D23AE236423CC22EF25E52405251824C223782291237B27DB2640260C240D23A0249C25D926F027EF278D251A26C921B823942560272E32882EA32BD828E929A02944292C29B128CD29DB26EB26D9296C2C552A1E2893264523EE2308240026D82501273927B22723255024C723F923412487224F206820C32043236F2391233623FB2332240B23182463264125EC23A22490222B240D250E2895239F22EB216623B6226B26CA25BF288F25BC24D225C824E3254C279D30AC2D3A2A2B2845272A279227452793273C28752622266327132A93272926A7246924E324492245258B2423254926A9242C24EB22CA23C8219D24AC218D239021962285222224CA23B425432400243424BB23272402252C2390242822A12446253E273A257D24042302250E23D9254B260B26B924EF241625602677260E27C4316A2F8929FA267826C726BC275C26A2271328E8260E2734260A27D4285A283A2658251F25AD238C25E223E22331254426562496243A234C22B422E5224D21FD221723012151228224C9239B252A255922B825E0251E245521C7235B23DE25B224C225B8243624A422902410252725CB24DE26F4248D250E237224532376254830092E7B282327B02697250226F327B22760290028B42583263F27B7260D286A254E24E123D4236F236F238225582661251224E024AF234922CA22B5235D2292217A22C6211E231F234E246025B824492348232E24A023ED211622B72264245124EA232025DC23F92190220B238623C425C725BB254325F8223424BF24EF257231862D85273127852761261B270325E0260629972798260D25A52590251A26BB25E7234E23772489241C23F7234825CF246123AA2490223F24F8225B206B224221E1201B228D238E210224522458224923CA23AE2419238023A723BC22B82243229D23A5230423582176221E222F234E244824D024F3259023D424E223BA258C2F852E3E281426EF28A3286E2659252926AA27AA247024B925FC2368253925C3248F244E233723E923AD233724CA25DB2447221324FF22E721722116221022B521B6217321C9207C215E229E22ED221223A1243624F922DF21DE21712298212D23F3227C227E21E2211B22DD22FE22D825BA23382484244824602429244A26E42FD42CEA284629F927662726264E24D023BB24962595240A254B235C242A24FF2571232C231324D4220D2404239624CD228222042424227E2231220620FB1F641FD220A01F6320F220AD2021210122FC21692312231421CD228322562181217F2241246922AE22AD22F022F121A0228522A3237F248F2268246F24F02329247630842E9C29F827B22661260C2510248A232B242424B622EF225A22BD22682480216B22AA2243222C23232472232123E3218222D623AE234E218F223B20052171218621A1204321051FBE203C21C620C7200D23D623882209226A218B218B21EA2216234F239F2224229123F721E3220B255B22F12294238922EA22E325B1259131822C862766250B25EE24F424BB2239259421BF22F722922253228723B52332228121D0225D210E2357219B21312282226221FE22F8226F21FB228B21FC212A21822180203F205F1FD82078212321432168219A2394227E21C0205E21C9210622F8227522E22101213023D2206922BE21A221EC223F23AD22C7248B241826E52FD62B7924AC235525BF23C32398220E23C1226821CC23E7226F21B32216238A224A230821822285233122FC208522552384209B218121BA20F620C21FEA20D41F7B20C3203F227D1FEF1FCF208A213B20742176232221D02089227F2159226022B9204620D020232154223622D0207D22A822D1209C218521C3215E236B24A22D742C21277523C8235325A7226723C0225623F62389227B2272235E22B521C6231E248623AA22AD239F2146205D22E4225C213F2106229D2236207D21D1204F1F4C22BD21AE201B1F3F22B520D021EC1F30224F22E020D22070223C20AA23B32064236922BC216420EA218B210D228623152279206E21EA216423AF23EF2597308B2D812649232B23DF2472225823132208239B2292224521EF21AB2074219321DC212C22022107224221B92084212323CB225021CA205D1E6920A71FA8218B207920FA1F2221AA20CD1E6022EF20C61F842047213F1FE3201621AE20E51F37216B21AC203F21211F6A218F212C213021DE2148213922E2211D22152382244730932C8E260025432264223D22F32268220224D122FC214A226F2139235E236C20C22205222222E1221222E920DF215B218A21DB21B01FD31EAD2148219F20F31FF1200422E21F5B1F4E1E8020161F4C203E211321C81EBE1FB521CE208F211D1FEE2132225D21D3210D21D920DB20BA220D21FC204D21571F87226423B7259E2EDE2B0B26D62315236C223823CB2381233F232622B6226B239D2129212822E422EB21FA204B21D421D121F720B3203321E721F620611F2920061F372112209D207220592003210E1F5C1ED21FC01F6C1FB3207A1F931F631F09203A211820DC227A21BA1FC020EF213E22E11F78200B214F20C11FA72173209622EB23BF24022EDB2BE326A522D3212421D82008239622B4223A21D9224B20F9209C2035211A21BA21ED2083217B2140223A1F71206C23B022BB215C204F1F3220A21FB22145227520751F0221FD1D381F991F351F1D204D201921C821C61FEA218920D11FA11F05229620281F511F41218A21E51FD720341FC12057225B21E3214224A025622EB02C36267C245B221823D522F1210722D122A321A5221B21F821A12050217D20C31F26219B200621771F2E1F3020C621022114204D1FB9208A2067201C2182219321D5201720C91E78206F2060201720CC1FB1200E1FD1205521E6207E1FC820D820E51FB3201E21EA21AE1FE11F47202222AD1F25218620282145215525D92FA82BA8249222C12215224A216421E422C82098214821BC20D2206D1FF01F0621BF20AC1FB721CC21D720091F3A219C205E20F120172173204920681F151F0F21ED206C21EC1E031F191E1220201F1A1FB51F12202B1F7A1F2A215B1F1C203920282068203E20772091200421E821281F831F98200421A9216222B1231125BC2DD12B2F259E211D221F22E6200122E92122221823A02256206520082017213B214F218E21F320A3204C21DC1E50216E1EAA2028217B1EBF20511FF31F9C1F5521A320D91F40200A20231E1E200620261F20229421B61D8D20B41F48202820DC214720151E10216720B81E4320621F0A20BE1F9E208D21C01F7B228F228A25222EC32BF4256E2274212B222B228921CB234D228E210621F7207E1FAF1F6021792296204221462337206F21EF202B213C204B21352240203820891F82204E1FCA2041204A1ED71FDA1EA71E6A205820EE1E32213E202F20D81E5521D61FB8222F20482015204F20421F4C21851E46201C21BC217420DC205D215122AE207123142F8E2CE325D32128239422A822DB211F246A2330220E2273223321761F7E21BA219A224622E921AC1F0A22AF20C521A82040203E224B20D61E1F2029222220DE1F3E1FF31D2420F71E4F1E3520D11FF01E69212022BD1F1B20AA1F261F831FF61F0321BB1FD21FBA1E932006207020D5214421EA21AD201A2091211424A624EB304E2C90257C23A620A123DE235422EE22D1232A23F523852253218120F2216120EF20F3227921DD1F0E2109203E21F6202220002215210620FA20211F361F7D1F861E6E1EC61DDC1E731FF71E731F32215821A020DC20631EF81CF21E491FBB20F91F7020CB1F981EFA1F801F032096213E201C238921A41F10202E23E324C02E ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 403F ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 0009 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 042973239F239D21A9228121E7201321A921FE201A20341F461F141F4F20081F261E29200420F71DB61F301FE320861F3F20A11FE620E52065203820CF213520E41E661F6E1E0A1DC91D9E1FB91E471FCC1E3D20F61E851E4C1F891E271EA11FE820EE200021D41EC2203B200F1F20212C1FCD2175215D2130202E237B244B2FF52BBD2446218D232C23BC218022DB22E522A320C2215F208D1F3E20CC1FCE1FCF1E561F8E1F4F1FB11FD920EC202022961F98214A203F21C8206721C5217E1FAD1FB920AD1F7E20091F07212F1F2C1F56217E20D71EDF1E571F7221A720FA1F6C20F4208B21A22052223322F320EE20B020302259232E23D523AF23DD25D12E2D2CAC25A224C323C6224322B522C823E2213F24502307235B218720FC2023214B21F321322139205B20FA213021CF201922A9220122F3216A22C81E2921F72159211722252189212820422160200020DE2093211620BF200F21A01EE920A0214F226C223F222821D822DF2286225421432141227C25F9237C2468248227C630A22C94287E25202399235923A2245B236922E72193212A2168213A202B22EF1F842169214A214123AA200821BF1FAB219B21DD223722C7226221AB201B1FA620CD217B212C22142022204821F91FA41FFD20C9217D218C21C120D520F321E1220C244D234E23A52253225D21F120432166222923DC24A6269224A625CA26E52F102DAE260223CD22ED22D3231C2370239A2398221F22A3217A201720972169217020262298219F21672152214A23421F302087237D21891E8A21232173200F2083210D224E21701F7C2009213320DB213121DA22E520EE203921E521D120572183236E23BA247F228C2312224D221022D022F7232B268525F725AD26F925F62E742BAA267E23BC2452226F24E6221C232B24CA22E7222D23C5202B21452141226D2214229F218123B7210E21F12167222920DB212F21402140219F21CD209721A321BE21FE20841F05227720CE2194212C22B922E122BC2291210F22AD21D022EB2443259B2327240924D32304230B2396221D253F2983291528E0287928C02F062C9E24AA233C231C235523A024D423572352243A23172255226F21D122DE22BA2374223E238922B323772396217A21BB1F00208121C8212E22AC21622391224621F4219C2156213A217021BC21802126231D253023C922FA220323E521AE23ED258D24F42574247F240F24272315235B24ED237E277927BD28332885264D30AE2CB326DC238D242C23B821162381248D2400255A22F4220B24B2242F222322DE23B823232488247B23DC216822D623B820FE209D2177216F2253236422A721F121FE215222C321A52268249F24AB2129259A24EC23AC2212232E210C23112499264827E426F225BB25DD2422241F24D123A923D6248A251B2843270528CF30992B3E274F257C23E823BC228E2227258A266D259B24B62367238C222F231A21EB21CB23ED23F523B523D521DC1F07223E201E22B920A62039212C239E223722702209235B2201236A2320234622B7224E24EA232C2542236825FE224122CF23382680264A28AE266627A525812460257C258B23BC23EC23E624492628255630322EDF25F42328237323AF228A243A255A27AB25BE263626C8232B246B23F822C523F322E62331231423FB22A220942138205E239C232B22CF240A238E22E122882268236822B6238C2368258524D222AA23D724A12408241D23352383210023CB27352622258E26E52651278A2880276B26C22540245724A8238A25CE25DC316C2DBD29A727D924DA248023DB24BB250427A2273629CC288C279E24332438242724C82332241E24A121B9226521F522F2204221EF2257236A2485234E22E2215223312234229023942355243D250C23A623CA22F3231F249E24472378223D24F124CD24B224AF25E0265426A9262629CE279524AE232A22EE230F25512547313B2EA828212674270E24C7225D2433255228E828D6288928C7263F2583235D24992357241C247D265923E924E021762235233C24D42514255E2341220523332277216422E420A821C2228A2303250C2480240C234024CB240D246722CF216D23792425250326FC237126D626C426CB28D7267B241023D1229B22B0223B269530882F9F2A1A28972627259B244125B3252A28AF271B27E12859266B26B6246E253425E92408243C2682249224272353268D25D925472637255A24CB2451232024CE226A23DC224121B920152315265E24CE22832458235423832412246122B3247D249025FD230A240A255F2545251626BD242A23A424CA226F233E24C726862E2E2EFE299228D8279C2701256B267828B4299C295F277925252405234324992240251226A4252026BC255F25D125352689260726E7242B24B925DE227322D521FB234523612224216522FE22F824DF23EB25E92521244C23CA227423CD239B25CD27C02591265025AA261A24E522C7239B230C248D236C238624E624D9269F31082FF8296F2902283D28802653298F29702C472859273F260B23D622892233241F24F2276F29FA275D26F425FC26A027F326E1249523F3244424FD22A2234324BF251F245823902213236523CE24B425A4259B26AB264624FB2361240A23DE24BF27DC292E2BD729852A2828582592249B2446230B25442383243826C3262630A230162BE127FB256226A3279128462A302996283B27D22404228623352466252125F028D52855285129F52931276E26B3234D24632414240B249024B7242225D2259F230E235922B122B227F8262227142940264126C9250F257B23B5231F254F281F28522AD6299F2A202A84252C259B235A24462596261B26A8260128A330632E562AD4283928BD2646272D28C3285D27A926742750265D2509255D240E256C262C28FF29042A812A0B286E2731274F254B258F246D230E268E2723286C288F272F27752529244A247225CC27F828B629262A1429AD28612912268A2435263E272427EF28E42790275826A324C2213424B92422268F27CC27B8279A292B33A02EAF28082746255227B828AF274327E926A5269026472724278B26FE2356240725E127FA2AC7292529962859269D25572327252725D42567278B27B329262A3C2A2B27C223DF220B266E27F0275327EC285B2B772A0B280729C8251D240824D1264024AE252624D025DD23D7256F245D251325292564263E274E27A22857343D2C102AEA26BE2791286028BF28DB26A82614267A287D2718288D272E27B42428257C281628052B432A95271A27CA264223F124E324C0267027F327C429A4295E2874256824E9212325432620280D26332950293C291328042627240D2443244A24E524F62560226A24462350225C22042425245924A4245A277927042A6B34AC2EC327CB25D5266F27A327A2266B27EA25B4264628472A8F2A6727A82787266625FE227426D22756266625B024372400259E243823732345284A261828BC25AF25792569239F23F6233D2596250527432855289B26C7256426F523D024362584252124AF23CE23C024CB211A225A258224F9249425B1248C25C3274529B833692E5229D4282328C827A327D6257A264E277D281F2B9C2A06294E273F265626A3244A273E256D24FD249C2620259F24AE25AA248725CE240D2555261026E426FE250626632412259724C125B2289026D9285A2888267B259A23ED2517258D25C325892393230323A42458244825B029D227C5279D2995263C279427C9288C33632F632AB52A0F280B265D262C266A26EC27F8281C28C5299A29692969278C276228922539273C2495246C2490257625C824B6259B23BF2306251924B325E7247F251B26E625B726A7279C276B27D028E6292D291A2586243425A32686260E2761265B26DB23FA234C25772457279227F627462A592A212B742A2029EF2A3F342330E02A15294F281E27B526B426F326E528F1288329C329B428F126032A012A722ACE286426FE221622A022BF233C24F823CE24C323172466241D23D8242C256A23BC2461262328B9287D2B952AFA28042B96299E276325BF26AE278228C0298B290C28612782244926A228B028EA2845298A29E52AA12BB42A932AB32A2B354E30ED2A892A8C28A0265D248D26C9282528AD26C62667277F2502287A2B8F2A922ABC2924268B2425239B239425D82650260F2500249D25F72549244D25C7246B2465251F25E825662AC82BF42A752AB22A2029D02883278C28982892286A2A6627602649254C245E264F26202810299E298129312B252B192B0729472A7334E930282B0A2AE128D0276C260626A427592A4A28C0286427A826CB2751289E2954299B27E62516270A24502477275A2852282E28CE275B2795260F27B1257525FE23CD24C0253928022ACE2A5A2B4528FE261127B0276728862AE72915299528FF2862256723FA238E2450269B266A28AA2779273529C429AE2AF8295728BC31692F812A0E2A612B2D28A9262A27E12724288A265F27BB270827A028C029152AEB29252699254125B125D0275827C5299A2A262BAC2A3F29132B072A462986266F25D924882633270E273C297E2844258526882570256626872AEE296C28222892256924C8234F22DF25E1252E279727A12614256A258D255F2704275F298A33FA2E752904282F275228A427202708272B270827B2282729D2279A284C28D527C0275A27B2245427F82606270E28D52A162B732A262B4A29632A2F2A5E29B9255225F8244E26D12456272F26EA25B6250724D525B0257326262886290B28A327AB24EE22C3230724C125AD253426FF2517259024FA24AC257525FB279529A133BC2D0B29292543273D273D27F5266127F926AC265829D728252C6C29802832278925E6262C2715292A2932296429122AFF29BD28F0263228B228AC2805279A259725CA250826A02495253F24FE24BF238824F5247425FE26A0262E2710257F24A5254A23EC229725F1262427B22669259625CA240D26AC251427DB27602B3E35F92D4727D526522731274426A226AE269F27532773263229042A692BDF28CA276927D4267F29422AF22AB92AC42964291E282F287B267F269228F8273E2559252D26F4264228512665267B2579232E24F9254B26D9271D278C27872485250E2748261A25C423C326CF286129C52878281A27E028AB28832687266A29AC2A9E346A2F5A28A523FC242026D42868276B277128B226C629402A9E2BE5297629E1282228E9275329B52CE029782A1129C42A6A28ED27C127D326C3277626772599252F26A827F1285529C1287C281627E326B9270228D129D926B9269F25C02632283829A828A5279E277329F22A1A29C227472722297C2B88286F2607280D29C334AD2EF227CB25C4254F27572607273C2982286E298726BF29422A2B2AC727E724DA25022791286E280B271527FA29652A96299E29DF291827192732267125B9250D272629512A652A462A6528E327C5266C261B2915261626BF26DE26EF25AF27CC27E0288027D325312A7B2B532BAD29C028E828072A8A281928A127A12811337A2E672B41280E295F281425BB251C26F528DB287D2932290E280728CF29482A3D284E2898289E28B7253D27822784279F28062A592930273326822381256626652BBC2BC22B24287827A6283B2776248B257B271D264A27AE2706274227ED2599262226D42468272D291C292029D6287729572B142AD428872504284F2999337E307F2BF52A5B2A87299227DA277B27C526F927282737269127912773284329BC2AB629322B832968286A2820286C27E7275729A4286C273625BF240A24D227AF2A192D112BD928E22532287626CC258127B229472AA929C029C1281A287325A7259A24CC248B26972AA62AA8292829512A632BDD2B4228FC26BF2744294434F230372D552CE52C312A77290027E7271029E527CA2559252725C1265C288F29022AA92BCA298D29012A4F286A29F827D526252726273323E2238724F523E1262D2B7B2C1B2ADB270228D025FF25B6253729412B5329AC297F290B28B1275B26EF244624E32486260B28762625256925B0289629FE275B26FF266C27002912358B30162C952BFF2C6E2CBF289F29EA299F2C8B2A8428D0256826982529287428C5282129BD298429932B9929702802285C26DE25EA267123A52277237B245E279429792D8E2AA628F2289428E727FE257628BB292F2AC72954287C28A92A5228A027A6242623B923BB25D5261325AA2571256F26DF26A325BF2587288629A434EC2DA929AD2B8F2A272B6F29EF29122B552CD62B222A3728BB256C25D625FE26D028D627C926C2285327AE27A3281D272B2572269227E2230423C423AC239C266428EC29482C192848266C29EF29A12631264C29C5296F2789277628FC28252A6928C3259F25D4268327F225DA22EC238124802525252C244A256628722A9136472F7B294A2AB42AE029C2276527A92A762CBD2C722B4B270025B023A52522274928FF28AC27AD286727A4260F262F2884270228CC2ABC2760249524AD23662776284C2AC129AE26DB2402276A26DF252E271627BF262525CE25E7237726412783290E263627B128C327F126E725CF26B22653262D26B224CA26A2271A2A3D354330CE2AC929A829292A4129AB2ABF2C292D012C312AEE25F8229E26C426D627BA2A9B2A6E2AAE299929812563265928B2281329912A84285C25D723BD24782879296A2A1829C826F72519269C27F626C928FA262C2887252A24E424BD24192523267F26C6264428EE2AD3291B2AFD29362A5327EB27AB25C4259327802AE1353B31B52B762BFA2BC22A7329562A972B4D2E002A3D2827268325B0264929B82A582EE02C2D2B772B5A29A1284E29AF28092B8A2B92290629AB24B423D825182704292A2A5A2A79272C27FD277128A829982AB5287D286E276A268E2413259B267826F725132746288029B62AC42AC92B592B482A412A3125E6267A280B2BA233CE30FD2B172C372B822936299029BD2AC92A2629FE27DE26BF254626EB28BB2A1D2C1B2DD52B522BD82BFF2841292C2BBE2AE22A95298C279F246F23FB241825EC26F9267C27E42742293B2AC829EC288529E8298029762867294926D0259526D226C926BF273C2832295F286328922AC82C762B512BFD277627B128522BE5341B307D2C1E2B602C5E2B682AD929452A062B90281725DA24CE26DB29C52BC92BD42D0D2DE529222DA52A8B2AFC2A132A422A0D2A652791258C268C23C724252672262526AD266927EB2789294B283827EE270A28EB282829992825270128302A8529CE29422926290829AE2794273B29372AE82935281C25FE24A3266F2B2634A42F91294328782A872936297228182876275126A62654276927E627E829FB2ADF2B622CF52C552CF62BB62A822BCC2B842A5F27B325CB249525792630263F2825272128AA29BC26EC26A6289F28F426262688278D29AA2B9C2B4F28172704285F2BFA2A16293E2844288426F526BB272028E327AF2741245A25932792290932CD2FEC29C22A042B572EB028122984283126E825C7266328362875276329012A692B3D2C352DE62BBA2A182ACE29E12A162989265125E2269727FF272A29D029272A7429B62AA1287F27722768283A28DB28D427F6297A29AA29022892260F26BA270C29DB2759273928A627BB276F28F027C128ED271627D6251A257E298633462ED629682A6E2C432D302D1A2A9E293028DE2732297A2AB629D629642707288628742BD12BC42AB4277F27A02802299126CF286A273F2545295029A129F12BC62B702BD82901270D260B27FA29A129C729222967284D28F128F4263125EF2589248D24E025FB253A270128DC271D293729392864275A242323A2250E2AC134B72FFD2A892BAD2CE12D882DC9295D2888290E293B2A782BC2292528CB28A327A4269E2862278C2764287D2762284C28F126F32553258A26682758288329CD296429C92A4F2A1127EB267428D428A62A1C298F294D272428F7255B26AB242124D9244725C7265F278729EE271228F6289927C8266E26B3241C25C425E6287C331A30E22A4E2A832B5E2C582BAE2A252AEE292B2BD92A1A2B5E2B112B8229C226F12409264D263327E124BE2568275F2707284326CD24DB2466257523A22735286729602A942A0A2964271D27C6299829A927CF26AC24E5254F27B624752602260E252B2538271627942A2D2A89285E28F3260A260027BC2460250428B428A63292304E2C932A422A142C3D2CD12B1B2AAD2A4D2A4D2B9229C8280A29D5288226EC2506288C242E25D5247324F5267829D028C126DE24C62587258E24AE2690289B29AE28EA281629BF278E276F29C2272926B0240326DE26FF244D278D272F272A25F72639265C28952ABD296B286B29802805266D27D125F625A3264628383397315F2BAF29DF299A29C72BD029E629B82AE12B992A2C2A68289727B0268926B9275F27CF2748272A253F255F29F42A1529A627F02679264B26BC26AE2579259F26E6269928EE2665262C268A2560254425702645266D274D285F276C28BC295F298C29DF280F290B2AD329012ABD29F728F82898288927E427FF27452997332F32162C76287D27EF272729F928BC277A29CC2A5B2C3B29DF261F2666279626F0299128B829EF27E72478275A29512D0C2C1B297C26F726F228D026C6256A24D6244B25762888251F258F2391234823B424C127D7274F29102B712AB129042B012A47277827C5276A2AA62A74298F2A282BD4295D28BB274F2AC32BDB2C32347C30B52B2828C8277329E32882260C28452B642B0F2A0A29C92688272829682B0E2AAE2ABE2A752A92286E27D929B82A5D2BF22A402946291729652830283A26B3257525F6251F264D24AB2365239D241E25A32858298628142A022C452A9B2894259E275026FB28142A812AEC29F629AF2A142BC1296128962A572B0A2C44354330672A4D298A28D4292D2BAE2C7D2B412BA329112AB8282128A928232B922A012C2C2EDA2A922AEA265D28362A682C9428782629271B279728FE2AC72A9827642406251D2594250225E0235924E325BC28912871290F2A9F2A232C4D29F32805274727EF250F27F229332BFF2A572B7E292328BC27CD27932B8C29EC2BEA32C02F182B452A0A2B9D2B692DD02C9E2B392C522BFB2A7F28FB278F2AF42BFC2A242AEB2A6A2AE52B57273A27702A792C9628AC28EC26D827B42AAC295F2A7D2873262F27D725CA26FD26B227532747272E289029B128D626DF26F4266F26BC252F25B025D225EF25CA2B252C8B2BAC2AAF280A277725EA243127EA2811290033B82E8C296A2B412B622DAA2C272C462A722CD42C4B2B112A742A002A282C7E2B552A112C312ADC2B7729772701293229B129CD26AA277527CD296C295F2A9E27B1250A271C28CD28622A3F2ACF2AF829B4288D279525C1262A28DD2525241C24B623AE240025DD268228F729082C812A7D261324EA25652446266026D5275E340632A92922299629C82B422B982AEB2CFD2BAC2A4C2BEA28DC255D26F428292C9D2A2B2CA52C242C472794264428F229E12938295A27892705281529FD29FA27E82717271627D8283029702A95293C283428D026F625AA2837279F261323C522CA2418242F2482265D295A29FB2A672BEF260123EB2495237C2644276A284A32A7318E2CAD285D29FF2A192BC32A942CD42B302C7D2B782AD8245926A0265328AF28EA28D529092A4E2AB8265828F428A22893293F2C83283829C02AE02AF528C127FB266C27212A5F2A0E294D28AB26AC26A0270C276528B628F9289125CC249526BA2627273027BB279D27C327DE288826AE2477266A2542270429A0284A3151339B2DC92B602913272D298029472C3E2E972B102B66291528F224132614255C27D726942611294C279D2716275C291A296D2AD529352B6F2AC12B802CAF2924288828F6265D2AFA2AF029F2264025CA255826B62594276A28CE286127F42595264728C42A8427C3276C267925F72789264E25C9276F266227AB2A1A2C27334732A52DC12BA82AA32798273C29F32D862B7129982ACB268A271C277D288526E926A0251A250A26AB27FD248528EE28372B582B3F2A13292429E129122CDF2A74288428F727582A262CE729622A31271A26A1282B28662857290E29B627FC2646276C28D72AB42A9E28902607275C269F230C2214260726112A862B3F2CF1331D33E82BF92BDB29B3282A263E2A002B032BC22AE128ED25EF262E28E92936282A275026592511267925C826ED275F2A082B1E2A992AF9295E29C3288A29C128C9276E27A627F4289329242987290627BA287729852B9429932A4A28D0271E29A6291E2A3B2CDF29222B56281E27F5244E23E02499264B273E2B0B2BA22BFA333631872BD32AFE28C1253A26872718297A29952801288726F7270E2717299D280A28E42756280F28EA2629276D2A062C732B232A3B2BCA289C2A1C2A1F2B9C28AC256526A728C827BD29CF2AE7281227F527E3289429292A212909283729092A8C2A7B2A972A5829FA2A032AE229E02751234D258D24F424D7273B28C02A7D363430362A862A75288C26FC257525B426D927D226BE278D26572765289229C1285C29C82B992BDA2ACF278C2702290A2C5C2F9A2CFB284F260128DD299A295429932629276A261428FC28162A532A1329A4282A2750292E2880277027CA27FB2A162B7B284B2810263829EC281326542722252B2432241E25FA26DA29E72C7C366D2F812964285B27AC263326DE23C4254A262C276B29152ACC2A6C28D327AE2A492C312D372D4B2BC328BD284E294A2CAB2C2D2B5D2A9F28F625EA28F326882561259B263326E526FA270D28F827D127E1278627672543268D2462256128292AA72BAE2859268A25112894273527FF2506266F254325FC233028CD2B3E2E1037962D8329202737279026F725C725AF25522745273E2A382BB22C992BEB2A6529602B5A2CC52C222C6A288428E72722296329AC2A982888260E2557262427612762279E26D927D72852284D28D52953282E2805276E26F52517263E247925E027492BF32BDF2AC6274128452742275C281D283F284C28822723290F2AE72C3435DD2D4429542A5A28EE284729552707252526A728752BE22C342CF42C052AB62A462A012CCB2B2A2D52282828882597266626C4287E2623259B25B026E9278929CF28B627412AE5283A2A1F2B912BF328A8296A296127BF25732796236024A1269429EC2AE329F12944293A296129822A612BCA282C2CAF277227622A372BC4337D2F5F270128DC28B32A892C8C288026DD27AD27A42A8A2C872C922BB32A26271A2A2C2DFA2C3F2BFD2B99283224B9257126B025BD271A267025AE258F289A29E02A262AE2284B293A2A532B732C8A296A29252AA629FE27BB26D9256623EF2453254E27EA250F2620281926D1266F2BBB2A562A022C752985270C292227BD32AF2FA02AC0271F29F22ADF298D294128F129652BDB29E22ADB2A1A2B4A2A372A8B2A6F2C052D632DDF2A952A3428EB248425EC28F8283A2964292C283C28F029882B4C2A002999289C2A4D2C5E2A7E2A4F2BFB29782BAA29A029E7255524FF245B26D5235524E8264927562528254D281B298E2C5C2B2B2A3B28012976293733CD2F4A2C8C2ADD2B48297429D629652AC72B022A1F2DBF286B2AA2291E2AF228012B822BE12C7C2B5B294A28C8258627B2275C29D82B802A252B302AE427A928AF29242B1929EC28DF2BD62AEB28A92659270F29E72AAA2A48295C27F9263926DD28B0269D254225072612263224812637262D283A29C42925291B28092AFA33542FE62C722B8B2B352CA6297E27332AB42A742C932B5A28D828CF27CE29962ACC2BC52C7D2B1B2C322A8229E929CC286827C828F729842B0F2B412A3B293A299429A12A602C452B0B2A292B6329CD25F82464294B28F429982C772BC32A8F2A4229A6284F27F724FD2850278226E1260827C52757280C2887270B2A1C2C9235E0300E2D832C282C722A172917278729882A562B3F2BAD2AC326E9266E28842AA32CBE2C2C2BBF2CD02B252A432C3728BD26CD281F2BD429622A592B6729DA274529432A042B652AD12A1B2B292A79298628AC289B29A12AE9298629732AC5288D28622AB628812665268B2656298B27ED269D29AE2BFE28E1275B293C2C92337E32322D6B2C3F2AE1299B295D288F28972AEB2AE029F0265626AB26B527082AF92A9F2C762B622DCD2CA22B242B1F2B612766264B28AF29712BBA2AC629652717294C2A1D2AC02B592B53290A2A50288C29A12BA02824296428E325C028AE285029D22926285B284B2799294529B127FA27662A0C2B752AD92A462A2A2B6A34C931C62D362CC02A8D2A172A8129FB28C12B622BE32A81297D278727E429FB27DE281E2CD42A0D2A302A96299F2A6D2AEF283B27A2284229EB2B002C902AC12A412A462BD32B89287D283129DA283C271D2A3A2ACD277D24D7261B269B259D2802290F29102A3D2A3F2B872988298D2A2B28FD29892BE72A9A291F2A552B28338931412D2B2DF32CCD2AF4298D29592B542DCF2C6A2A542B15282329592C062B282C3D2A3A2ABB29D628E2289429312ABD28FD264C28AE28E62B452B702A9628B1299A29952A14287D27A026B526AE267729E228EF26AB2331261225A5262028812886286229592A6D2C782AD92AFB282D277928FE28E7295D2845284929843368346A2DD72C632D112CD92A87280E2A662D562C4D2A372B7429382BD32C8E2D142C4F2B602AE52724280828A82A292C422A9B287B277E29192B402B0C28D12630291329A02BB0286A274A27132620264B27562816240C249223F7274127BD27632A5029A12BDD2BBC2AAC2AFE284628222834285D29292A542A4327B028FC33BD314F2C342B042B9A2B80297829332A852AF7297D2A09292029F628F32AE12C4D2A0C295529A6285B26D026A827282AB7297D295D28EE274729C62735279928E626512815294328E7280B27B82513265C288F260F272425122674262E291F2ADD2A922A262A032BE62AB42A382A912AB227D327A1294D2922290427D627F2336131202D2A2AB52B002A4828C6297B2AFB2A3A2AC6281028D927962A6C2BCA2A342A5E2AC0298A2903277D2922294F2A67290A2BD9286228662985294D274F2735271926B4273127A5270629B728292866285529742959271F2766287C2A2F2DC22CCE2ADF2A1C2B9F2C412B1B2BF42989293F29402908278827DD262C28CC334E31942C282CB42BC129F8277528EB28272C172BF42A9A28D828102C762A782B462A02295C29AA2BE829A528F229B12B642AF7292C2855285529D127C2280D29C4294629542983278A27B8290F2ACF29342A842AE1297A274A286228D528D42B3D2B832BC829F328232DA12BEA2C1C2A43277928FE2845271D28A22875297B33932F832BEE2A9A293F2ABE27E3251929622C0A2CD62A77288D289F29542BC429A0282728BB29052D662A6B2AD229BA2A7828132A922A3A29B52A3529042AE22A4F2BAC2A33291728D326FB28962BD12AE729322C702AA32999293F29B92A342B9C2BB429CE29DD28C12BE22C8D2BE62AE22623278328822649280F2B0F2DFC34052F552CBD2A252A4E29D627F427B32A362C7B2B1C2AC8298729F729EF281829B026B52798286229C82A392C5B2B4E298D29642A7A2BC22ADA29DD292F28202A962D122BB82A2F270126FC27AB2AD32AD22B912C192B8F2C9F2A4A285F2AB82C2F2D882B142AD52A212C102CC72AED2A7D2781254F257A270E287E2A9D2DF434562FE52A0B2B002B1E2AB529A029DB29EC2C6C2B612B272A992A642C7D2C372BDB298B28DF29892A762B582B772AFA29EB29DF2B6E2C5B2A482A0F287B29F92A472C082C192A0827642505288E29D428B12A302BF32B3E2CC02AC4296E29432B632BD12C122DB5285D2A7B2B9D28352872242C25A2245923E726892AD62B9534252E4B2AFA29802B4F2B702B712BA72B752B852D762BA82B972C512DE12C342CBD2A0E29DF29FA2BF92B3D2D852B792B842B992D2E2C3C291B2AC9288A285C2727299C2B3A2C4C2967270329AF27F929982B902B3C29E429F32A9D29DC28B3290D2C732D302A822A9729472A2A29D4276A25DE253D25E32540297D2B332CAE34DA2E2B29F0299229C42B8D2CDC2A472DCE2D3A2DBF2C422CDF2CEA2CAF2BCB2D99285629282B552CC32BDA296E2BDA2ACB28D229012AC32945296A2738288A28DD29FC2ABF2AD229E7280827F22670284329062AF5275128462880282428682733287F29C429BA29352A8729D02A7D2AF127892502250F262328AE2AEF2CE935762F372AA528522A5F2CE12BF72BD32CC32C962EC52D962C7B2A9E2B5C2AFF2D762B342AC329302B032BE32AA02A302C8B272D297F293D289E2711272E25F727282AB72BFD2AB32AE529B729502A7A298C299429F227B9276E2756251B261426E12567285928252A032BBC298E2CDF2AA4281728FB2662247E27DF285E2DC835F0307F2BBC28EA29062C092C0F2B542BD62C732D9E2D0B2D3F2B0429C329CF29B828802880282029DA2AEE2A8A2B2F2AAF2A602A48295929D3285625B92320270429C0283A275926EA26C027552981287B29F12998294427AA26C7250624B72669278327A3286A2AEB2AE72A892B572C642B3F29D0286727F028FA2AF72D9D362031EF2BB12A572A052C682DCC2A622AA12A042C162CA52BB42900286228CB2761291D29EE28A1282E2A472985281629812726293E2AA628A629512625268C242027E626D127A325C325D8265229232892271F292F29C926642ACA26F926E0278B286A2A902AFF2849295529E62A0B2B1B290E299E272727B427EA2A7C2D25358230042C01299C29C12B262DF02C7F2ACB2A6A2B612BB42A9228D2262B27DD287129322B8729E32AF32BDA293D295F28A6289B2A142CC829AC2A0C29B6285A2809286928B2286F2724278727AF2AF328DB266F279B266F29782910291D2856292F2B582C222A6A2873279328A4298D2A8A280A28B32678250E28C92A552DA6353932492A632AAF2A3B2A892AF5292F2B1D29572AF42A012A3928AC274D28D228742AAE2A742BDF2B5A2C822AE42A8029B82A6D2AB02B8B29162B06291F285D2891297C2B07292429B628632A762B392B3D2B61271127A62624292828A426D828DE29CD2B98290A28AF2765268E29962A2D2A5F288225EB23A7272328062B4236A530FD2B132AE8296429B0299E28DE28A728DE271B2969263B2823286128852AC52AB82B3E2B912D242BB12A7B2BF7293E2AE12A7F2B312CFE2A5E2A092BBD2A702A7B2B1F2A0C2898289928632A342A30290A283C267D24DC28AD266228F4281329662AFD28BC2654275027AA288C2ACF294F28D928AE2426248A25B728FA319A31A12B982A3C2A2D2B2B2BEB28DA2A4B2AA12A372A3528C1262D28E828232C9B2B922AB52BC02B322C0F2CA72BEB2A6B29842BA22A0C2D8A2C672C422CAD2B6B2BA92A9A2A6F2829268E29CE2B8B28192832296827D725A9259524FE248B25DB27EF27F2273B281D27ED263C287F2B5A2A2B285B26E524A724D927A1292133A42EB32A2D28B629552A7B2AF52877299329782B742C6B2953282426FE28CF29052BAE29A82ADF2A012B642ACF2B992BEE29872A4128DE29362B792B822C1F2CCF293D2AA329542A952A1C2A72285027B1288828F325A825392582244C25C124B526B724C826D826D4253227DE260D28F0296B29F42678243E26D4272D291335AA30E8290E29FE29FF2B172A1729A927D529382B842B822A8028AC265D274B295E28D9298D28FC28D228EC26442AA7291C292E2831278C28532A642C8A2A462A312BA32B9F2AAD2A372ADB2AD12A89261529E0291C2AF7299528E92468263C25C52621251C266525C227DD27B227F727E7286C287A27112680264E283F2B57352131492B9B285F29342B4B2B2C2A5529462A862BA62A35291327D926ED26B9288E2961297129B928FA26BC253927DF27E4277928DB248426BA28CF29D228082801295529DC29B4288F280128E2276A276928AC2A2B2DF22802280D280727DD284B288A26C7269C239926E22824292A2AE12837286327322522274729252BB1357431112C9928B028212BCD2B0B2AAC2ABF2BCE2A222CCA2A64281927D029AB2AC9294F2C272B4729D428932710282329BE279A288928BE27F7291928802620278427A527E72766254B27CE268226F4254129352B6A2BAD2998297B278A2AE82BA92941285D26682664286F2697296E2B6B2B22298327F7262C281E280C2C8236B431F22A142A012B372D632DEF2C4C2C452A782B2F2A7B2AA6278028502B742BD82BB72CC129D52A6729F6279C2632287428A728B728682A202AD5291528FE24A726C4267025DD24D727BB273D27DC27AE289C2C402A00282427FC26762B572C4E2B21281D257C25C627E3273D2A052D572D7C2BE2299E2713271728F8291B354531D62ABE2BA12BC32C902B4C2CDF2C012B3D2BD62B312AFA27A6277429AE2B662C062D652B902BC22A552AB12A122CE1299A2AC629B82A9D2BCE282D282E27CB255F2529273C283529F728BF27AF281827062C682AA927A92713277B277327BC278C28AE291327A02785272C29692AA52B672B3B299E276328CF29412D77364C32302B0B29812A9B2B002C982CE42BD32B4A2BE129DA2924282327FF288A2B022CBD2B892C5E2B1F2BEA294F2BFC2A2B2B042A5C2A942A8F2BA02A122AEF292827E7266028DF25B92834278327662637262F285B2831285D27EA27F829BC285F28C7290A2B4629C7266A252A267D27922768292729CC26C2268A28702A9833DA32012BF128FB276E29AE2A272D542AFA2AE02B692B612A4627A825F628082A702ACB2BEE2A242CE9298929162B052BE129F5290129E42A172BD629BD2AE22979281E26A7278A273C2936285D281A271C2714289B26FA25752705263C29FC29522BC52A402BC128C7281525E024C52796274A275827CF265A25F627E32AD4327F32292EC82BEB2AB82AA529FB2C7C2AAF2C372C0B294729BC29F227B62684285029282B592BFA2B7C2B89294629432A002A4E2A362A3A2A0F2A6A2B6F2AB82992285127EC276B27E82AEB2A0929CE267C2A622BCA280A267E25AD25C429962BBA2CF82BCA2A172CB129B126EB25D526D427C5280128C925A1254D26FB2798328432EA2EC52CE12959293528BF28192A852AA92BA02B802A592A8A285C276628812890289D2BFD293C2BBA29F8294D28B126EE29C127DE27BB29B52BAC299F2A652AC52A32291F266D286C27EF298427AC28D42AC929D026952644276928712A1A2AE52BF12C462A1E2C89296F296C29302B502700272D261D261928E527D6329532062F432C592BA029D4279527B62A5F2C782BD22C9F2C8D29D128E9288F2847289E2AA32B4F2BEE28A027C326BF25A6277F2A252BE02AEE2BD62BF22A452BA12A2D2ACF28CB25362637284B283C27D928BD2A1A2A8C2A6F286025CA279828D62B442AAB2BA82B782B3C2AA72A6C2A37285A29F627852585250727F8298B33D131522EFE2A192B852A822A5B28122A212B9C2A3B2AB12A74292B287F276D28D1285F2B532C752D742A9B29042BB9285428DF28D52ACC2B452A442A002AD22ACA29992A46296E27CE266427C027152830288329CD2A752BB82AF6283A271627752A822BB22B902DC52C4A2B6F292329282A212B042A56279925F8250D288431F834BA2C9529C229EC2A6B297B2A2C2945289D2A1E2964284E2664248F269526A027EE2BE82AEA2B272B0A2B812AFF29B427B7272D2963281329A7289C27A4294E2A29290727FC26C826A027FD26FF2507276029DA2A0B2BC52C3E2A7229C828BE29B829642B1A2B6E2DF12A0A291A294728E429312A63271D274C256B261D32A532832E3C2AF42A072A3F2C082B372BB12AEA29A02A3F28E0251627CF250927F526322A832BFC2AC7299D2BA72CDB2983284228D927A028C32AFC27C5285D27522ADF2933293C296D27FD2739282D26F82531270B2894298A2B242BD4298D29552A392A2C2A742B6A2C932B702ABE29C0278A28CB27CD272C28232763289F314631DA2BAA2BD828052AEC2BD32A4C2B9E29292A2B2A432A98289F262427F227C9266829C129EB294B2A4C2A502AFF29092BAF27E626E22780287E281A28F3272F299E297B294A273B26082A5529E8262727F9289D270029D729682A3D2B852A8627BA266B28572A3D2A492AB6284929B728C1252C2653275126632860293C310F303F2C122B522C262D322D302BCB2C0C2C562C112B132C0A2B6028B8272B287328AB28B1297E2A0B2832280328BE292928B6275F268527E029872A0229382B3A2BC5283C286326BD264329002BC8284C2AFD2BC228D62543274527B227EC26D12741270627D127AA287D29D029252A512A942795266C264028F727192742316330A52A8D2AE92C232BE92DA32CC12B682C5E2DB12D3C2CF02BB328C5273A2703296D2AAA2BD42AB12A9D28F829372A742993284526F328512AF52A7729AB29B12BC12B6E28762602278929E328AC272B2B8B2A082BB9284529C32A7328932699284829362B7029D02A0E2B832BFE2C7C2A8428F2252D250029B4299E286031C0302C2CFB2AF628F829702A7C2E3F2D752B132CA72CE92BE429F42ABF299029BE29302BBD2BA32CD22AF22ABA2A3F2BE22A1429FD2675284C2AC42AE12AD32A642C242C242A94273F27D4293F2A2729D72A662CE52A0A2AAD2A652A7529132619287529EF29182A282B232C3C2A232C91299B28B72520250E28DE28CC29BD325031662CAC2BAC2B2B2B072CD32CED2B5E2C592DA52CE62C0C2C9C2A20297728DE28792CDB2CCC2BAE2A75297D2E6F2C1C2995264F26C625AC28B62A0E2B9B2C272B4E2AF629AB27D72652288E29D329A52C6E2B1B2B4A2BD02ACD29BC2A56295228F8282F2B5F290B2B552A1E2B0B2D842AAE294C27BF252827182A982B01326933D62D4A2CC52C9B2CE12B9C2CE32A362D492DFE2B492CA02A922A4C29B6274728CA29682C312B8A2B5929AA280829D6297E294D26F6268526DF278729BA2BEA29DC29DA2893250728AD281B29172ACA2B652C98296C2824277E287D28D429A429A929E2290A2AFD294D29A529982B602B65286C257B259D26D828312B1F346B32F92CCB2A242D052D932C6D2C402C0F2B312A142B5D2B4E2A9E2A172990256F262728B92C8D2B17292A2706277D280B29CE28AA280527EE23D6243E270B29262A8B29C5269225D526C02AFC290A2AA52A612A8F29E928172859295C2C0A2B5529C428DD2AD129802A3D29C52A542BB32AD5297B2787255625A9294A2C70352031602CD7298D28B42BC12DEF2C832C792B302BD62A382C872A9B28E3279627BF265529442C542B5429E5297A274A299F2A752ADA294C2856254F251C277A29482B9129DC2763269726A828272A3B2A192B5C2A9D297A29C92AD929792BEC2A51294F296829ED282029DC2AA829012B722A7A2BB227B124F227DD28D62C4A36EB31912BB4285D28E529F32B582D912B552B342BFA29DB29132AA02961290E2922289728192C912C862BB72A36296928EA28AB2A6D2B3329AE276325A5261D28F52999298E28C926C827B529C32B072A0A2AF82A6C2A102A422CDD2A892A8729AD29F4279E286F271F29AE2831287F29B429A62A3C291B27BE27D22ACA2DB6357A33ED2C8A2A9B28392B892C632CEB2DE42BDB2C792BB32A2A29D427B826E42730294C2CFC2DA92E8E2BB82A7C2C982BB32ADA2AE42A94291629F8252B26CB29D22A102AD1288027D1282529C229B229C22AAF2B7D294F2AD22A072B112B0A29F0278B2687278528FB295A29C7297F29E42800293328B725AC27DC2A172C693576328D2BEC2ACC277728712A232CED2BB02C492C4A2A9E28FD25BA26E026322778290E2C122BFE2B362A002A702A5229292BBB2AA929BD28D72730279E25A82751292A28662718287028322807289129492B572C432A18297E2ABC2AD628EE274A2684267327212730299E289626512637272626362657263F2664286C2AE034E7327B2D952B0E299529DF29352B992A3C2C2D2AD329D32820263D24A42543284E29102BF629B92A09290728C6297929422AB42B1629D627A4280C2680245324F527F627F72566266F27A628EB26FA285B2C5F2BB52A9928AF29B629BF288328C2262E26F2266E267A289C2836259B255026D0242C27BE2569265428602A0134C530412D94299D29D028B0269A289329B82A842918293B260E25A1238523A1263328282A462B742A7D28962772272929CD280728D827B427532813274725FD242227A42773266B2552260C283C274C263F2B422DA92A95287F28C326C32524283529C7274D27CE264628FB26CC252F251425DA24FD25B025BB26DB2603292F336230192CD12ABD26D826D325A928162BAE2A822A8E293827012543246C2639268427C628F42CA22A952929274B2848297728E5261527D826E625ED239422812304257124CE232E255325D6240F277926582BF22A8E2A9A29B4283C268C258E26CB2653271229A6282B2A7428C32621240C25DA254A27C426782723279A29553333317D2BF329872A26281627DC261A2C422CD42CE62A132A5726E825A029682AFD28AB299D29592C342AD526BF29CD2B9B2B572AFA277B26A6260A25C42233231722ED22B623D72237238125F924D2247C285A280B2AE22B882A0E27BA243E2738276428DC2712283A29E02711274327A6232F24E524B6237826A7282A2B1034E131E42B982CF929C0296A288A28E12B812CE02AC42AAB289427B1264829452C4B296429F228EB2A1A2A8B28B3288C283328862A6329AF277526D72514235E212822D524DF224E235B2408229325FD2493270628B9281829A128DA2610254526AE278926142866271F2A3928A1277D24DE248123ED247323FD259028BC29D133C530D92C042B9E2A73274E28E627E028B02B142CDB2B2B28F1251C27F4273F29132B482AF529392916277427DD282729C229FD2A972893267A267123EB22C421F520CC218D228F229A234423192352247F260728082821283828E327482667272428E825EB2405266E295029BE27682598248323E023C422E92367269C2992340231A92C972BAE287826A8251C27272A9A2B062AC52A5F284726EC23A925D027AB27C329522978281126EE26F0253129722956293C279A26D5257824F123F22225225E221522612391226F244524C624AB23BA252F252126052792258C254A26FC25C2240025E425A5276826E62555258324F822B622AF22EB2329252826AF312C2F722B742A522AA6286D261826BD26FA29082993282227A525FA2469268928772893278726D925E924AD245126E62464251926A7251825F5243C24002371223122D91F692031204024E9227324C623BE2318251C238D239C24002673240C2657252C24DC236324CC238C238F2665265824E0224022C121DE227C23B0269831902FD52ADA2BCD2918293A28A1267026EA272228E727FE274A25E423302625279B26E925F825BA234F240E23F4236D2588254126D9275425E82487245F22F822D921582094216021A02313244D245F23DF234523C722F42465268E2458242025052635263823FB23D2243424A323C4245523C822DE22BC210623D423A126C230D12F6629F029402A942A182A6C28A2255D2638271D2667261B25A9231024A024BC24ED243525962391233F233123EB242C2428254D246C26FE24602481242723D422D8202F222F235524AB2496242E2550252E23242328256923D723A4238C224D25412518256723B623C4237A232C25F922B422CC2364237422A824E1246130DE2C2029592A362A242A942A1F273126F3251C2610277A25A226D3246725BA24B925C0259425F823FB23A7226624F22669231125462582261E247624CC245A230C23A822FC216321FA2239246824FD231D266D233923D02299231F227222E0247B237A248423C722E523D02310238E23AA23B1215722321F5021B122B1240B30372DC529EE27192A052A7529F02815266B27C623FA2372252D26EF2442246B26092568268126D4262924BA23D923D8256D2402249D23CA24AB25882403231023D322C423B022F52148222F2358249223DE238B249923F4222D242922E1226D2294244D21E5219021CD225521782301229C24C321BD210C23F6215523DA24BD2E1E2DB72834268A271028A1277026E62557266624D723DC231625572184229923A425942712253A278D247323132454229022E821D4225521E424D02240255523F923B522CF22BF21DB23C322EB221C236B224D22DF22F121C2236F21452383227C237022D2226B22FE230521EC22BE229422D8212422AB22EB23DB23B224E42F702F972838251C2608288B289D25AF25C325FB241F25F6231823E723C223F8237C25BF268C25C826F22349239E236824CB22EE229C213B2163225F232522DC23722318213D21A822F421E623C323EF20E823CC231A221A20A022F422E2246E22FF22EF21C3229C218E233523CA2152218E2325220E232D2151226321A823A62EFC2D7D278225472552259A2693278E25A42620259F2340244A243422BF231323EC23562402250D2413235D245824EA2334224E23F1213A214222EF23CC22CF21A0229C210F22D121CB225F23B82270213A21E9219D2187202521EC212D236022A621AE22ED21EB20562113213A205A22042285229F22ED206D22D4227C243630362DE1261A25E5240125F6260B250226DA260D25C024722350238A22A3226123F82234236525DC240F221822D6221923BD212423FE20F32227227D2093229421FE208A21C5227E20C222CF22C2209F21D62179223421D5219522FF2176219520702157218021F81F2721C32034218221E8200F21BA22DC20B02291227024762EAC2D1627DA235825C525BF25E2257D26062790232A238E246A22FD228F227F228F233D237E230424B4226822A023E922CB209E222122D120AD20D4212F221422E121212113200C210F22BF2119220922AF22072225219420042188218820A821302162200E20A720DA201821FD209623FE2046217B215121E0216A221825082F5B2CB32776266B23A324FC24AF249A24CD25DD258424AD246A22DB228D228224B4226C239C241323892333227923CD21C72143234721F6211B2217201220CC1F1221501F6F20E6209B20BC209D21542140227C2105201F229921F620DD204321D222FD206C2117223322CE203821CC20942187222720A8211E22F3210823FF2F5F2E2728AB249023672383236A244E24F824F7242223F82298217621FA22F31FAA21B5225C223723CB23FE225C22EB20AB21FE225F23AB20222227202821C521D420F81FF3209A1ED120BD203D203320AE213C221721FD207A208D2054209821CA21ED218421EC20722299202F2107238920AC203A218E1F6F20C42344245A30EB2C4527122418230B2388238C228A253D2252235C2331231D22FD22B9222321D620B7224821E222FC203D21C2219121A9206A2260220F21B6227A21B921E920CA207F20CD1FBA1E3F20CF20212073208B20352255219720E91F2C208020F420B321F4201321CD1FE0216F1FD120E41FFC1F622145217E20632219220B24A72EAC2C2925AE23D824A92208237D227D23F3238222F724BF23412201239822262230236F21D122EB237A22E420EF21A32227204B21FD20A8200D212E203521831F5B20A820C021671FA81F2C202E21EB1FDE201B232C202B202E221821EB216D21C61F201F4B207920A7217521E41F12216821C51F7020FA1F1E20A621EB224D2C1F2D6D28382407248524C021DA22A522BA2387242A231423F823502216218223B4238323FA22192499211B2088213022BB203C209321ED2101205E219E207A1FB92195211A208D1E9721F21F6C21911FE421EC210D202620B321B01F1D23AB1F8C22D0212921C21F30219A20B1203C22DA201E1F3B203020B2211D222024762F602E65275B249123242529229222A1211223F02295233B226122D020A3216A21C621552216210822A321CC202A21A5224F22B5204720191E6E20B81FB8214B207B201020A62053207B1E2E229420871FAD20F220F51EBF2022219D20B31FC42096201D202321B21E0121EB20BD203A20882061203721EB202F21E9215023A82FDA2C2427ED252123D0222922AC22FD21CE2381226C22BA22AE213B2346236F20AD2222226322492356223321D22126213321C721951FF41EB2213C2100212220EE200922ED1F151F6A1E4020CD1EFB1F0721E0205B1E961F8921CC204E21F91E6B217421D82042218E205C203320E62135206A20B0209A1E0F22A9221E25D52DD82B72265224A2238E2221238323BD22EF22B1213F220A2392210821F821C82219229C200821FE217222F020C920FF20CE218620EF1EF61FF61E2921E01FD320592001200121121F281E6D1F711F9C1F7520201F421F561F29200D21E01F2422C320411F6B20AC211022ED1EBD1F84201E20591FCB20C71FE52104231C24852DCD2B38278A2282229621F320062329229B22DD209022FD1F0021D2205C214A2127224921C021CC216822931FC020FF23B8226E212420801F5B20DD1FE5216622A520D31F4821261E371F8C1F1D1FFC1F71202F219921741F902178200320721FE8218D201D1F7C1F32212621921FA820FB1E2120F421D120352151233A25182EE72BC02526246A22FD22772243219A212022E920EC2184206D210A20BD203520DA1FE1207B20D020381FBB1ED51F8021E120BF1F9C1E11206C205720DF202A214121C020831FB71E1F201720F41FFE1F941F5B20C21E2820EB205820FE1E11207C205F1F6B206D200421F51EFF1ECF1F2421BF1E6520A81F80207420EC23062F732BAB24CF22DC221822F12011219B225A203321C72066207720771FCD1FFE209520C01FC721ED21BE20041F5921C3204A20CC201C211C200A20B91F0D1F2D21DD20BF21FE1E0F1F171E5A200D1F761F9F1FE61F1E1F701F2D213E1F12203320FF1F3520182014200C20C8206221351E301FFC1F64203021B5211C237F248A2DB42B3425A6218E22B6226B213F222122B6212323C522432085204E200B215F21702123227B21F420EF213A1FFC21F21E41218621AF1EF2209F1F3620CB1F9521202176208C205820621E41208320CF1F2422AE212B1EE2202E206A20B22019228B206E1E7C215620F91E61205A1FBB1FEB1FC7208D21A61F5722C7224F25202E9B2BB2254422A4213A2270229021B223B6215221CF209D207A1F701F1F2128229720392140230020DC21AD2044210D20692153221B204520A71F3D203D1FCE200620D01DE41FFD1E8C1E9A203A20091F30215A208D20041F3F21A61FA82245202220DB1F4920ED1E1821FF1DF61F0C21A421C71F83200421402255200323AB2E3F2C8225A421D422A7228622E321842316237F21A021D621B820491F6D2155213C22F521EB21B11FEA21712036213E20E81F1C2214207A1EFD1FF121B81FDC1FE01EC91DAB1FD61EEA1DDC1F911FB21E00218B21891FFE1F2D1FBC1E331FA41F1921B61F6F1F401ED61FCA1FC91F31218D204A21DF1F801FC12064237C246F309E2C6A259123C3207823D5232322C5224923E722DD2317220E217620E2215D20F120BE22A221BF1F2421DF1F07216720F61F5522F120D61FDC20EB1EED1E6B1F2A1E8B1E801DC31E8B1FBC1E6A1F65215E215820B820D11DEF1C991EEE1E8120CC1F5420F71FD31EC31F551F911FF420A41FA7222221761F0520F3227424412E ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 403F ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 0009 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 D228EF2224238421F82154217F20052179218E20B41F551F2A1F9C1E8120051FF91D73202E20431EA31F551F2721601F0020851F76200F20841F501F6321BC1F431ECB1E491E561C0B1D571E1D1E771ED61D941F471E071ED11EEB1D7E1D941E7B1F661F8D1F321DA41E501E481DCF1FC11D66200920C31FC51EB4210C23412E642CD924D621B0238323D3217F22EE221623E52022220B21E31F67203920DE1F8A1FE21F0D20561F0620D92069217A22D11F9B21DC1FAC2027208D205121511FA51F6720CE1F4720AD1ECF20E71EC61EF7202B20161FD11E701F33215E203D1FAC1FAD1F2120091F5620A120751FDD1F521FF720DF2147210F223222EA24402E452CAA255E2478236822FD2182229C23DC212F247D2368238721D820F2201B211D211422F3200620E61FBA210E21CE2014222F22D020B7203421C41DDC1F2E21E420FC21F9202621C41F9320AE1F571F1520C220491FFB1F7D20221E252018209A207320BB1FC41E402043205B201D1F3D1F032071228D20BE211E22BB254D2F1F2D33297E260D233623F722612443234622D721FB217121E2211B213F22EE1F5D21812157213123C42042211920FF21C1219D22AD2128228420AE1F631EBD205822ED21B6222A20DB1FE820941F371F4A205121F620A921BE20612032215E212C22AA201921F21F9E1FF01EE81E791F7120AE206A210C23972116233A25DE2ECC2D8C27732361228A226223AE22F5224723672260225122172163209B2132214D20F02152214F212C2106218423C01F5620B623CD20AC1DA82077203620692045225A229721661F20208D20851F1F21652060221E20D220452166211620D71F3021F62083216C1F9620821F0A20F11F7B20F91FDF20E11F40213F231024AA2D532CFE26DE23A324F621EF2303225B229F23A1220223D1236721C021C421F721D2219A213D215923CF214D2194221123E32092227C21E1208D20E820C920E8210F226C226A21D91F06221C207321AC202F21AA216A218121C6207D21CB20D920EB21B9216E20BB207320C5207A207B20DE1FBD20BD2234229B2163247E25522E732C2325D0233D237D2247227B23AB225E22BC231F233922A522F221F022BC2246239F2161221C22AB2388232F228222D020E0203A220A229D215721D122B522E4217722C6215521F7200C210E217A20F9214223CE209A209321D6216A2009210622002085213C207D204E20C21FEE1F5B21E01F99217A20852273239723D42E292D2F27C624F72430230921EB21D8223223FD235E22022328244B25BA227822732358222823B32394232B2252230D256A224A228C220B22A122DF2229228321802256233E23FB212122B723DD23892091233122D6200620002120200E225621B021AB2192216221E421FC20922051210721A220DE2095205323A323BA25AF2F652CD227DD2568242B243C22E52045239E244B24D1230B234C231023D923EB2180218D22A6220423532363226321B2232B22FF234F224921C5206522A321F22177238424AF23002324226721C2205E217622D720BC21F41F2123C7215D21A221F721B820D02255225D23FA20CA1FEC201E22AB203921FA20A721CD23F023B12FE62E0F2641241F24892318227D22B622C724CB234B252E249222F723362465239223B221A1222F22B122C1231E22742378222C254225CB223E24B2214221E92204248625A223502383212423B22213210422AA224421AF2081206121B9204E21C224DE21AB20A22260226F228F22522177213022B721A4210921D6238B242931E22DEA294A2740250425E122FD221F232E241B2500273A258C2416234224D7245324F1229422B5225D2192236C238B253923522329240D246B24D1224A21662261265526BF25CA24D721922122235B218C228A214E2114216822D021D521342303231322B321B1227F23B32160203622E521DD20DD20D91F4E22B72384240B31912F55291A279B278E249422DE22912207253A267B26D9250824BF2304244C256224DB23CE2211254F22DC247723C6240F254125D4257C2589232F22052384225A2455278925BE24462313225723212367248C2235233E238822932178211823B82330233D248222E7243F24C422DF23AC22712100218921B721492241264F30ED2F3D2B3F28BE25AC2443231723392272244225B625B2274A25C02547259B268C250A243622BE2370222A232523D8275A27CD26CF2592242D2461249922D0233A241628D428D8253B230F2417263C245F2304259323A7237324D92322226324452349238F219822AE23EB238323DC231E226C218B23D221F3223824A2266E2E952E2C2A4728FF26BC267A236023A9232F255B26C626152725263E254F262E24482508252823842253226222DB2375263F28DD27792500249225CC22B92175204224CF261D28992613261E2523261E246626B2261625A5246B23F623C9236624062501222F23AF222325F522DE21E6221B237123F8223E2289233D248B26AE310C2F702AB2294C274F27D924E52570238526DE243228C92AC028AE279B260E272125B72646261B231E22FF21D323F026B528B9273125242615259123FB22B7225D2421255D279A27F9265B2500258E25812571262B276F2528258F2434225D228723E7246325EB24702649259B248B24D4249622B3234C217C22D1243D26F02F8230492C67293F27B726562789267D2677247126D528222A7A29A72AEA2AD62A75281028A925E623E02448250A24A1269926A8273027DE25DD254226162554234B23B22236243B2555255B280226BA2562270324F0246425A325A223B822C1227A24B223822619269427C4274C244E25CD23D5237623E723EE224A2420274030E52E6F2C812B732AA92708288B286028D5268026A729862B002CA62B022B0E2B9E2AC9297628A32574255E238D252928792895282F27362578275E28B92767266A24BC24162501252B259F2469251C2619269E2544251C26C427AF24C822DA236224AF2448278D2638272D2645257322AC24EE23D1235D24A1245325CF286C320A319A2CC42B4A288D28842A6E2BB12BBD2A73298E29A52B802CAF2C292AC92AC02A602B042B2C2768245624D72435270227B828C927EF26EF275727A528432792267324EC220F23CE25E826E02530255026C927CB26B6242427D923F321B1211C252A24FA26CD250C288325CE272826232681248323B623A4246E252B288134FA2EA72E672BC92A302A8F2A302D692CD62BFF296A2AA428BB298D2BC12CCC2A922B082D41297829C426082317255427F125EE27B0260927D626E826562808273226B224D8238121E024A8250127E4249F27E42682266625E02316227421EC214523D425DD283F26FB27582623255C240D257E246123A4227B25D925F928B2335C31252C662B9C2A2529A829552A562CBC2A5A2930287827FC27B527602B532C0E2BB32730281427FB23B6226D2204241D2678261824B023512802262427CE242925462548230623BD222124D023DA252627282780256C24EA241E22B5212323DE244025702620283D2966267F2598270026682594244523BD23FA258E2721328A306D2DA72D5B2C402AEF294C298E2A542B4A2AB629CB265525BE26352856290028D829DE276F2542245625BD23CE23B2256A255426C525DD25CD263A26F2269726E72682251A2532234D23F1265B254C27CD26F525EF24A222CD239E22FD22D023A123C02524278D295529C0282A2B2828E3268E275723DA242B253426E431FA2F3D2C892E0F2C922A152AE729A52AFD2BA32AD826FE26CD260C284527F7271428A62539280826FF25BC245C244424972494267025392628279E250427D6257527A928F727B52671252E25902598263327E825EB2286238D23952312236F2398237C2485242127CD29A129072AEC283527FB27C22549267725A7245E266231B02F5B2B8D2BD02C232CD02A0E2AFA297F2B4B2A9729F927AC269D2549288D26B426FA25A826B1242824A0235B23582353247A266D26C2264C267E241C2603275E26442892282F27E7241E275C26392504271525E2237F2273233B245325CA26EF2597243026BA258D29702C282BA02930283426D6255B256C24592445256F3192301D2BFE2A752A452A99279927E9286C285727FE26E226C4237425FC27AC25FD257227D326AB279226A02579253D259A258726692678270927722512276F274C287E29B6272024AD2503254025D3254C260725B6253E240025F62427262C2956265B2560247E248927FB272629652939286D25AF2528250B26AE2489261731A031E62A88283627BE27D726BD2556260D2827269B27E5255124702464247F25E1253827B628B62B1B29C0262726FD249224E126BF286D2828272327B12695284428C7285127FB2538244823E124B423982439253226D625AA268A2505279D28D92909262D23C2237324E6253E26912828279125DE2539260828E627072629307930502A2728C1276A267A2600270E262F268F24CC24BE24FA23A825E826742780297128602A382B692B512B64265C259724E3268E299129262BFB29A12AC029862A9429FC284B26DA22CC235B232E226725B4255425FB249C2719260027C329EE28F726B224AA219A2462242326432713271A254925A625AB278E2624281B31E82F9A2910273A2611289C281928C3279926DB24722581256124162762285729CE2BDB2BA029D12B9B2A0329D8267226BA243C25B728FC28AC2AC62ADB2A80284E28FF27AC28582506269523B623DA233A23AE259A25F7257326C327AA2676292628EE25E5247D2328242B24B325B726BB26AD264D27002864276428E5278431E72E6F2A842717298329EC2A442BD42BB5292727E626D124A328DC27C729932BDA2AE02B6C2A3D2A1729F828F827622640251024232427279C28DF285E2878277B278927AA26A524612587237D2477230624B623F423EE24F324C92565243D2539279F2441234724D324DC25242772274D280527F2282629722A7F291B2BB433CC2F582AAC2B622CD22B322B4C2C082C432C452AF1269226B2253A29592AE62C022DD92A132B3B2958289327EF26E2250C247424E8220B248C26D2274B266D27A9275B2758274924AD247724C32283241D26AE24A6240B24AD256A2399247A250625642463223824CD25D4271A293D2B862A8B2BF42ABA29692A042CDC2AE4339B31542C6929FC2A762BD02DD72BBD2A622B7A28FD28932654253625B327482ADA2B752ACA29142B87274E278925E62626232A23952369235925DE259326F126B626D626D826892546244B24FB23CB25EA274427BD2743242E255424E0244025EB25CB2534250F2565260F295B2AD02AB129302AEF2B5C2A882AF72BF22A4934AD30082C1A2B522B502D1A2C6E2B232B162973298225D725BA2347240C244F249F265C274D28A327A1264026C0270126F223C3231B25BE23C125B9264C278527502727288727A3258E24A522E9230A25D726D42917279926E526B826592520263726FA27AA26F42384278129BF2CB52BCF29A5282E29AE29FB2BA42BD22A4C33FB2FC52D122B9F2C072D032BD72A2829272A382A7E2AC92708243F2430268327F725372789273A2883260E2805277A24DF23AC255126A8264D28B6260E293729E72BBA2A642A66269A242B252825782481268128B426D5273528AD27DD27F626DB285C294027A8267026E7267829932A032A202BB7299D2AF129A82B002B3733022F022A1F2AF529C92A302B162CDE2AD729EF2A232A062895260D25A82471253726792531287227CF275428E726632481234B25A72620293F2A352A712892291C2BE62BB529D926B623DC25A8254D274329DD296528FA2662276A27B2274D269528EB28F0273D26DB27BE279F285C29E52A522A492BE7290C2B862A70297032282E702947288029D629BC2B062A422B922CE12B912A9B2987272526DB25B7252D258F2771274C284B2A28297829ED25E6235325AE27FB26B829B52BC829F829612C8A2BB52888258C256E237625D826E02A932B4527C7256026C9252D260626DD26E32723286827D3266E25F92622281D2B452B7E29292AE02B1E2BF4286C32502D68279F250A290E2CE32A792C772BC92D452C142C162A49292A26C7261D27CC275C282F29CD2AC82DD92BEE290A29FA256D253229EA28092AE52AE62A632B3B2B5D2C21282F24FA241625D3255126DD29A72B5B2924279624B425D8273E25B226DC25022572241625EA269F272C2A8D2AA72AEF2A902A302B032C93291F32D02B1927CC271329E72CFA2CCC2CA62BC32BA52B162C5D2B5D283C26B2266C28D02B6E2B8A2A702DE12BFA2BE82B6D290126672669293829772A772B432AFE2A112AAC29A5297B242B22D4257727A126E428D62CC82BD72799267D2784273E28412692253A26A226B2262126FC25B228452A922B102BC629032BAE2B522A4B347D2D5227CF27652A2F2D032C3D2B5D2C642B722C432D342AC627582497268D29622C4F2D642B022D362C702BF829AB2A5227F625702ABC2AD72A412B6329642A0129FE285E27922323223E24B6246B266F2A692C242B58281227A9249B267E261E28F2234225DE25B0244E254027F729962BFE2B562C3D2BB82B622A2E2A2933DE2D2C2806270D297A2C842D5E2E4F2E3E2DC62C592DF029D626EA27F6263328262BCF2A4D2A542A152B7128C42880292E27D7259428C829062B262A67297A2A5529FA2826281C2530245E23BF24CE245029442A2D2C07296F262926882697259C253C258C23C5228B243224E1273F2A652C822A232DE12A7E2A1A2AB82AB834212E6927F4254A28052A562BCF2B322CE02E8E2B492C082CB3296F2720279D27DC2A102AB7286F28C8272429FA2A0528EF27FB250926BD299A29FD281C292C2852280F29D429B926AE256125892448252E27F726A028F82793267A245C257826ED257A249D239B22A822DE235926B129A22A5D2A2F2BB0270F296229632BCC33FD2DDD2671258B259125F1262C281B29992A012BD32C152C78289924892472255E266628732747272E29DC281F2A1F2B06285C251B25BA263E2790260D27CE25ED260A27CF270228AF28E0279225E4247A25DC254D2532248E256D23942326245824682451248E230824A3227A245F27C629122A782AF128DB281E291A2B1335622E742993260027B226BF26C6270129A22BDA2ABA293E294928F826C02588251B29022AC4279B2A8729862A992B702AEC28C02699237B2453279724B125A426AC2636266C2774280329482ACC2738262C26402597240E23CF22CB22E124872617257D2564255425B22595240C25B226D6271828D1270C27BA270128C52B5335CF2F51287D247E26BF2406264827BF29ED2BC22AC42A192A85277724FC247D25CF272A2AA32C0E2C252C0B2B8C2B062C7F2A93262024EA221024D624F32450272227A7276E294F270D2887294729CE264E2509251A2592247A253224FB24EC252228F226E62418251326AD24E4243D2656271F28F629D6283329F12ADE2B3533163037292A27DC24FD27D5235D27FE29BD2A95290128F126EF24D8230B2533257627B8296C2CC62BAF2A762973283429BE282E26B1244B24AF23892411276B286B28802791285427FD26D825EA252D256B25DE237A245F22B723EF24832638266527BD276526302565259A244E2484255A260629912A6C2BAF29A627C429663309306A2A56281C2704273B282227FB28B329D6290B28562668257426AB24492589256B2A452C602B6428CD27F7273E284D26092A8C28BB237B25BF24CC268A2ADE2A2A2A8328BF24852489245126F0243325A8245023B5229424932543274029BB275D275928462719266F24B4234A258126A4273A2A0629692618272E2A71348E311B2DC62A61287D28AE29482805273529B927BE26DE262726E82629290728652675294C2A9D2B192C692A082AA029CD286728EA277C279C25102544276A28FA28B229A728FD24A325A126D42542277126A527A924DC249B239826EE2743288628F3285B2A4B2A022AEA243E24D22555256B260228452794271327F22819339632892D572BD8291229EF283F29172963288C28922774286B2AAF2C9C2C522AF7283829E42A052E932B892BDF2BEA2AF02BD42AE82AE82927287D237E26EB27F3294F2B922AEF28C427AB26FB28E7286A28E828F2252B258F26F725122AF22A632979281429AE28132B22297226172890272A27D628E627FD27E129512A52346832002F0E2C29298C285B277D27A526F026B62609293929AA29542CE82C112CEB2A5E2B4028032A912B9C2A5A2B812C642B412BCF2A742B8B29F226C1266F28232A292A142BF22AA029A029C62B9729D2296B287B27CB25B923EB27EC29782A39287228CC266328712AEB280627CB2934299427BB281028BA28BE28A82990347432AA2D962C5F2A4727B7265C24F824D026952822298A2B1F2B0A2C962BF32BDD2BDD2827284F294A2A472AD32C242CA72AC32AB92A352A1129E4275026B1253F282B29782BBD2AA32A322B322AE429EA29542A5E27C02429251826D228C62A3F2AE22A7A29FC28142A35297A285028F127EB287729262A062BB72AF12A293484322B2ED42B172AB8283F27DA25FC23EA25E627632BE22AA22987293D2A0C29982AEE2659276627F2274E2A282A452C662B3629732680262528AE256A2545257427E428212CB92A532B2D2A662A8229D029832A32270525D7257D26C927D62A312BA628C0280328552949294C27FD276C29DB29AA29CF29F92B412CC62CA133F0309B2DCA2BA12B782BA5295D26A426802858288F29072A0F285127D827C52865264525C52589289829E6297529F027F6287729462885279A2615262926FA2553282D2AFA2BC22BC02A462A9629A829C4285229BA27BA2303251B27AE2756286F27382AA028A428E7276E27F82501261D28E32AB92BEA29762BC529A32A07340632522D602C172B032C2E2C142DFD2ABC298B28FB29AF2A2E2A9528E928A4276728D2290F279E28A927AB2A632AD72AEB2732271D298528AC27DE28ED27B825F1250429672AE32AA22A14294D283C28072A8C28FF268926042643287C274329FB28E32965287426EE26E7253A253B26D02655284E2AF12A612C2A289529EF319733352F432D0C2CEC2B352D5D2CBA2AD62A5B2ABF2B122B042B6E2B842B222B9F295E28B826CE292529FF29902BD82A5528A82AE42A562BBA2CBE28BF2712265927AA2AF52ACB2AFA29422AEC286F285D29CF2AB228DA254725A8256326DC2610278627C526FF2347272A26582555259A255A279D275427F227C628842803323333F02D3D2EB92B642DC32C0C2B2428B328C429512B7C2CD22D092CE12CEF2B0C2BE32AB9277029BB2A282A1A2A7F287928EB272D2B662B1D2C2129992859268D262D2A392CAF2BFC2B7A2AB82A012A192A2D2AAD27A526F2262925242412252325CF2565256625802409252627D22636251425FB277C267927B726A1271234ED34292D402C602BF52C4A2C772A322A9427EE257D28AB29342AA62A1B2BE02C4F2AE62AFE29D72903284F29042AA429EC274828542886295029A228972715261A286D29A52A332B942AE82A5F2911296F2A702ADA272C270725AB241522662344262825EF241D264E27F0250D28942ACB281226FE27D426B0285928B428C331BE32442E812B742DE52E452E1B2CE429A0261626B427AD29E927BB298229102AAC29E52849289227642A1E2A6A2C802B5028B427192A4B270F27152747268525C4268E272728CC2975291028CA2700274C298C2A00292F27A1259625642376247327142758277627D1278727AC27732964296F28F02A0C2AA72AED2A12292830ED32362DEA2CC92CBA2C2F2F0B2D342CA62AF8275828B0292F2BF128D729EB29902CDA2A5629E72AF32A502DCD2CA12D142B722A7C289D2802289A284629BE274C270829F3267D28F3275B27642553267128DA29AA2867273427C127F326BD25C6261428C72AFE27BB29C6291529072B822AF129842D232C9D2AA32B972B7532CB30312CFB2A5C2C2B2CCB2D032D6B2DED28EE252E29C427BC29232A7F2B632A462CC02A6029D1281E2B99290B2D672C8E2DAB2BEC281C2794275F28032A8029F2276A280727B527E72704274829E7270128A32A412AF529B02A2C2A5B29852759263C277729B029E6280A29F32ACF2AE4276F25222A792A812B7929B6291432AD32102B402BDA2A092D0A2C6F2EAB2B152AB529D0296229272AC129052B9829892A9F291C28B9279A27C328D029BD2B0B2C572AE829CA289F27A3274D28E9264727AA270528BE272328C7279B29B028F429412BFF2B142A632CC22A052A0429EC262C287E2AA7285329E6275528E0272726C2279E29DE2ACC2C092987287031B4318D2C5C2CB72BA52B032D7C2DC52CF52AA829222B1D2BC92BB928152983289528D1279927832755279428182BC22BF72A8729EA296A289B297C29EF29F327D6255127C5294A29922A2D2BA029FA2782286829602A1B2B8F2AEC2AAC2A7B289B261E2790294A295B2A682804285A285E2535273A262026F827D02672282734DE31E32C952E2F2D6E2D122E922C1A2CB02A1A29262AA62AF82AE329DE2981288829E92A4329B828EC2616282D298F2B552D352A5527CB259F28072BE92A012BC4289B291D2A382B972BFE2BAB2A8B2879280028092BB62ACE2A6D2AFC28EC281A271F257D27912635296727EF2400282427CA252A24F923D824E6267B29503440324E2D7B2DF72DEA2DB12DB22AE82A75298B28C629B22BAE2B71283B273A2A7E2C482D522C3E2AE6273E286C281F2A52298D271027DA270E28762C892B962A2F2A1A2BA22A092BD92BB92B0B2A2C285A28292AD1291B2B6D29E2287C29602933298326F724042571271E2716286D285C28B7264A253A222A241327102A443564309E2D1E2C972C772BAE2A4C2A3B29E428EB268F289E29F72BE52AC329A027C2296C2B2E2C472BA3278127AB265626A625EE25E5248B266B289E2A022C212C9B2C872BE82BA52B172A2B2A812B4428F027CD28D429F92AFD2BCD291029FA28862AC229BA27B923A4255B269628B62AB1292F28E626A425C525CD24DE28E4333A30772D682EB82AA22A2B2A4F287D258E25352638272F282229682A2A289227F326ED27DB272729B52553266724DC24D023602535242B257C28102AC12A292BDC295A2A452DE029282AD929982A1C272028F2284229092A562DC3290E292D29012A2F29CD25A324132524272F291A2A2D294925AD292F26C0253A283128E031ED31792BB92C0C2B562BC92BDB2781259525FA24C9269627B127F327F1274824B1269C27CD270B268B27FA254B231B252325C32333269B263628C327D5281B28D228E129322B102CD92A992ADD2AA927CC27402AA22BBE2B0B2C5D2BAE28DD28BD27B727A92417248926382691271A2B94281E26672860284C28132AF12719338331C12C9029772A812A2E28042726254A25AF259424DE258F2521265B26D626D3254327F327C028C126202753260A247F234F250A25F126BE298129E227AC267B274A285028E328822A042B42284527E7282D29D52BD82A932BE3272C262426B6267F237B23AF2564269525ED259A28EF27322906283929B629112CA52BA4342931382D722ABC2A9227292707271C2569248F221D270825FD276D2674276C262128C4272D297C284F2601262D251A272E256124D625F32504297629FA260726EB269427AE269427892A2F2989261024C32551282F2940291C28A8261F269C243B267524B82321232124AB25162608292628B1284229A32A202B422BA12C2435852FB32C212A872871283426D423F52504234F2486253126A429F429B02B882A822AF62A6B2956292727A9267C296529AB2604259D24BA26E128F7284E28C2279A27FC272729FE272E261C274725F8223023CC277D25E52617299728AB27E026D8249324A524F6226126E8250D28022BDC2BCF2BC42B5C2BF02A752DC22DA0354330D72B752A8429B727EF25642404262E242A2409263D298B29802B7E2C7E2CBB2CAA2BF4283E29BE27B926112BC629482956281227C8243A27D929C329E8271D29452A12299C267A25BE25B2256725B4255C26E1261527B626CB2622286726282785286C262025E82484253C2B602CA02C5A2D5D2ED12B5F2BE62CDC2D8E33C930E02A12292C263C265F271D27EA261627FF24FF24392576288C2A3A2C402D222B402BBD28422925290529EA297F2C9F29ED278125C324CD261D282B29DD270C2A372B3F297528E425D62373259A24EA26AB288D26E52700273D265C29FD29832A332B0F283927C9256829902A162CAC2CEE2C0A2CA02CBE2D9B2C5E2C0A344C2FF929AF279825C9264028F72867280D2AD5274826C32615271A29BE2BCB289728F62988272C260428B328652AB02A442AC128612770244A25FE263C28092AE02AFE2A542A0E26242505268F263526E6294E2A5D296A2744297A29FA29972C072C822B252BF5280529AD28B12ACF2DFC2BEB2C002C782C732CDA2CF82CC833312E07299227F026CB267828B429CE2B1D2C3B2AE1267827BB25DF27682B3E2A122A1427C8253B26C9279E29692AE4296D28832629267C23F8242A24582514262D28CE260E27EC232B247724D925D426512A872A9B2A1329862A1F292B2A2A2C182CC52AF6294128D3286729482C212CE52A402B1F2A5B2BE32AF02A142B4D342131922952287C28F629142C962A272CB62D5F2B2028BF27B9269D291E2CF52C6D2AC8281327412598275C28512AF12AF3289126CA2482245524F82301226A23B426BE255827EC23E124CC25C6255A2629270A29E0262728DB27312A5629042A952CFF29D12AE028D7266228F8292C2C292C642B4C2BEC2B782CB929EA2A01353D2FE328F52640280C2B792C0C2DA82C562CE12A5C2AFF273F27E027A52A722D902A5A280D28FC271F26E5250426AF280428D92792257C24E924C82382244E264C257626D226C225FD273027BC2654269327182696274F27B62860278F284A29092B4D2B3D29D22781269B27EC294C2D1D2B9E2BC32C382CBE2C872AD52A0335892E5629BB26B529C52BE92B722EF62C222D272C4B2AE0282C265E29822BB62C0B2C992A302934291E279A29BE27EA27412746297E262D2540268B2775268F261E2675256B281728A528B62AB12A51295D286C280A29E8288729D529B82A4F2C642D002C282B24297F288B277929502B882CB62C5A2D702BC12C662B402B8A35CA2FC6295E299D2A902B4D2C282D0D2C982D8C2C192DA9295A284E29C529832DA82C3D2A85294A2B492A4F29412A062A7B27B12605254025E32696264729A429D929CD298E2B812A9B2AE12B292BDD2A1E2A952944290C29F02B142CAF2A7C2C442C042EE52BB228272A76293E2CDE2BD82AB92D8D2EC22C202DF82B952B5234552E3029C328EA280E2BE52A012AAC2B662D192D612D052A5A282127FA286A2A7D2BEE296729152BC629152A4229AE285D2469260626FC24EF268127B629052B8A2BB62B8A2B7B2B2A2AA42AFC2B862A1029BA291D283B297C2CE12CBA2CFE2A5F2B1B2B392C4529C729ED29012BF82C832A4E2C9A2E4B2C742C992C3D2CE133BD2E792B492A272B7C2BA72ADE2A972CB32C792C782CEF2A0F287226FE25072918289B2851271D279C286F2A152A322775261527CF2762269925E4276F27D0293C2D882BDA2C732A4C293929852ACD29242A8F298C287F2BBF2C3C2B0F2D902C422CC82B842BA12B452A3B2997290F2DB72B552BBE2B8C2DF82B7C2B362C84330631062C2B2C432CCE2B6C2BC72AF02AF92B282A072BDA296B28B5273228CE29172B7429A0284B27252822284F278F261026D728B6291E27CD25AB255F29912A352C692CA92B9C293F29522ABB2A1A28D52841284429F42BAC2CA52C452BC12B0D2BBC2CD12DF929C62ABF29D127942AE229D92B922BE129402B652C3E2BFF335B30BF2C5E2C0A2D3A2C9D2BDD2BB72B822ACF2A112876275227412764278829702B67297728AC27BD271929E627B126D8261D299E287A25E625252674281C286429E62BBC2CF02A9A2AFF2C0E2A132BA12ADB290928CF29AA2CCE2BBA2AEB2A3F2C512DEB294C2AE6285528CE268428E128392B172CBE2B862CBA2B3E2B8B33C931F32CC62DE12BFC2B152C242B752E182E132C342A39288827DA264F26AC2B9B292B2BB62ABA29E828E5266D27412662244F267C264A27A526B9256D29002BE42BBA2B4C2B2F2B372BCC2A212B032B862AD3291428A629E52BA72CA22B092A9B2A8F2BF12974296C29EF26E32655282129842A472BC82ACA2A902A512BFE3455329E2D752B1B2B6D2A452AD92BF92D4F2D782D4A2C5F2A6227FE257B25D92A802BAB2ABD29BC29FE282D286F2783287C24752788283F28F527AE27A7269029BB2BBB2CF72B812BC12A3C2B182C862A6B2929293C2742280E2A312A4A2A7A298428532A5829F0289B271A255427AE263327222A522BD1279D271D27852BE8343F33702EBF2A95293829502A062BDF2C852DA12CDF2BF12B742ACC265A262B279B2703297F294F2A792B6C2B372C4A2AFE2AB72A7D2AC82B5F2CAD28CA25FF28122B112B202A8829C229E929882B342A062BF628A0279C254F28F828512892296529FC288B289E281B27DB2625284F2A652BF32A312C292A722936298F2BA33624316F2C6B2A0D28CC2630288927CA289E295D2A732955290B28C3252A26B0248D268D278328CB28F32AD02ADE2AC72B7B29352A422AC129192D452A3A29AB264F287C290F2C0E2AEF2859283D2B262B1E2B4B2A9027AB239429EC274D286028402854294628D325B9267327AB29892BFD2A062C1E2B2D2A53283028B12A7A346F30422B9227CB2608279227B627F4255727A827332739267F2509257E24D9241E24E7265C26F928472B4A2A5E2BE62B1F2C4F2BF92A9D299C2C212CE22BD2298B29902A922B6A2A8829BA28332C0A2B962ABD2A0F274D27A5271629F628F1288829722A41283026BB267328952A242C402BF42B9B2AF0283329D729D12B01353B3272296D28D726102694269126B527E525E8275427DD25C0244425E7253925B325FC2502286E28AF28F827702A7C2B352D1A2BD02ACB28842B1A2B8A2A4F2AB52A392CD229422A5929302A4B2BFB2B182D4B29B228CD26242AB82A9A293A2AB929F02AE927CC26B027B4271D2BD82B352C352BF129F627CF29B4294C2C1337B22F9A2A9527BF25DF257C272028E4288E28822786282F245D26FF25B7258A27E326E5272128E3293727F7250328AA280A2AB92AEE296F2AA62A422A252B812A6A2AEB2B032B4D2862281E2864295929F9284328E1261226E82B5D2BD62D092DAB2AC32A542889250427B2273129FB2A1E2A552A4C2DDD282F27B327692A34344530F5292C289E26AC280A2B5D2B9E2ED32CF32B6B2B0229AA27BA272B28FF295129A728562A802A6929EF27F225A1265927C0298F287F295B2AAE2A052A23297129892BB02C8D2957272429252BFA27DB265F285427F827C6299E2AF32BFD2B722DD22BF72A4E2A172861266927582A9129EC28032A1A2ABA288129A82BBA34CE2CD12888253D27DA28FC2B6B2C832DF62C1A2DF92D462BF429BC28A52AF829D1293229D42A3F2B2C2AB827E72664264126412994270D28F02745283D299F284D27CD29F82A9F2B6D2A9529C5276426F826C326FD241D271629962A262CE72B9A2D602BC52CE22AFD276726DF24E92582289928E1282328E928C6282829FC34E52E6C282A261627F229222BB02CAE2C3F2E682D9A2D0C2DE62AF629D42AAB2B22297A2A942AB52BD52AF32789287F25782509281329442AB42A612B7529FA287E29952ADF2A402AF328C328D42873247E263626C327732A292CBF29612B662ADB2C1D2C332DF32AFD2A902863259E259D27EC28F029CD2980290829B629AE33472FD82A4E280528EE28142A712B402CDD2D3D2EFF2C362BA829CB289B28CD2AA82AC129292BC42B342B9B29BE29E92776262028AC26C728452A602BD229452A412B4B2AF129D3277226622618263625612521276F2A172AD62B2C2C002AD22A952BE02BEA2CC328EF285028D125C026C326E829D02B7D2AC02A8C2AEB29DC337C31872DB02AB32AC12B222B132AB82BAB2C122B8D2C312BCE288526EC28AE291529AC2B3E2CF92AEC2B402C8F2CD52B8E28F7285428A927EE2A4329AD28292A8F2BD82AC1297C25132687264E2645241F26CD26CC28672AE32C9D2A3A2C392B4F29C029802ADE2AB52AA525C2254027B128A828372A482CC52CB52AC92CE3351233FC2D502D4E2C5C2D802DA22D852CE0299629D9273A2838250B2666288929982B2E2D3D2ACC2AAE295329BA296A2B372B282A1F28A427562716298A28DC26F52806298126932317260527692704277F25D9274326852700293629EC2B832ABD286A26FD2585270129B2261127D928852AB32A992AD729B22AB22AA22BEB34D930672D652E5D2C722C9F2BF62CB22DA52A44284D274A263525A62512279729E92B212D482B232B7D292529F429662CC929512AF427C9254326D7245726A1262426A925442600264726B525C6253827F123DC2614257624F5261E27B7269B25442547263329832851295F28C42733288429ED2A1B2A80292B2B8C2C082EA836B730342BE42A932C1C2B262B282C702C692B8D2871253026E72583264D289D2AAE2BEC2BE62C632A78296E277D282728F4270B27002764251325852492258527CC259726D226B323DF268F2544265825E923D324CC248F265027CD27C828B4260B27A828DC292B2BD1292B2876276A283C286C2A1C2C632ABB2A7F2BD02C58343230D428A928DD290C2B9429A82B332A7A2A7229CE261726BE2554263929272ACB29AE2AA729262A2D270026E42792278125922551257926A624DD2290245F2654276A2621278B266128A92704296E2763258225D724FD26112AE828D729B729142BA02A992A3928B9299C272B27452ADF2AFC29F72AE02B742A442B932C4533932F8D2BC62A0C2C872C472A4F2C022AE82BE629492592252028982732273328B827F4280F28EA270427F2259B262E28BE26412650267C26A124F22481248A253B27BC288A290B28572B102C872A3528CB28A6270F267D275029EB29282CF12B932CF02B7C2A4E2BF12820265427E828182BB02B4A2B182AF32A0B2AF9295E33D92F582CEA2BDB2A9B2B372AEB2A972BAD2A302A8F28B9260F2826288428AD28E527F327A72AB228DA28FC26E42875295A289C29012664264227962728256327E628232B2C2BF9272A29B2288D2BAE28E52710285D268F26172A882CDF2B552CDE2A782C142D7529952A48285C288229412DFE293E2B472B2F2B5F2C0F2B8E340C2FFB2B602BAC2CE62AF928F827182BC82C9E2ADE2A852AF4272A281D2A0E2AD028612AD02B0B2C892988273127AD28122B172D082BF929FB2AE42AFC28A4280729832A182B7B284E27D52835295728A8273527EB25A3288A297129FA2AA12A002DED294F2A782984282A265427CD2805280F2BB62B422AA02A442B1B2D7F343A2E272BC22A0C2DAA2BA82A7427D029762B3C2B432A212B342A0B2AF12A502CD82A0B2CC72CE52E4E2C6629412B552B5A2D142DA22C252C412BE22B932A122A8828392AAB2BF22A85293E28D32737286C27A5266726CF275629802998284528B4293529AF27752845274526B725C7266929942B812BB42AF8299029002B41337431DA2889278829542B1B28E726F9252727902B402B152B78291A28052A332BB52A8A2D562B8B2D412C212AFA28B9290E2BC12B882BD0287F2A612B012AE4297D284426A52667282227F2266C263E268C276A284E27F026AB29332820277527A627A32616263E256227C225B924E7253F2644293A2A82284C293A288F277032EE2F5F2A5B276F284C272628242651269027A5280A2B2E2A4C29532A002A8B2BD52B532D2B2D572D352B6D2BFD2AF4289F28C72AD9299129132DCB2A212C7A28A428CC2655264728C525782530266C26D8274228B62755289929C729D427632712296E29F8281F29102AFC284D27C426B725F7283329E429CA2A4C2AB52AEF32592F83284227CF256D270A288326FE2645265027D22724280E28CB27DC28732AFF29F22BC82B862C8B2C2A2B9C298D28172A8A28F527E628B229952B6A2B3A2A4B2A112AE528C925E323452621256825FB270F2AC828FB291D2B672B302CE52ADF28DF289E2A402CD12A582AC1278027DE269A279029212B012A572C942CF8329D2F1A2AA328C82AF32C6A2CAE29A02BDF2AAE2AC22733271427DA259C27832717273227E028D429132964292328D4273B254E2799260028B42A2B2CF42A622D602C712A342BCE28D225ED25AE263B26AF2A262CAD281927B3294E2B6D2C1C2B2D2CF52A9A29E0293A2A2F2B442A50290329FD28DC2A732B6E2CAF2BE22A38342F31852A8929082D5B2CE52E482D182CD92C762DC92B4C295A28BF241626BB25E82554267F27A2280D2ACC28F328C02640258B26C825FF28F72AC92B9A2AAB2A9D2CE92C7B2A232A52292B2838259925462A372AF32ABA280F2B382E9A2C582C622D012C942CEE281429A7298A2B342C7E292129AC29FF29372D2D2DC02B3734EC30222C932AE929FB2B312B532E0F2D372B1B2C062C542A6C2765270E279F27B226B2266B28AE2A712B942BE829F5278826EE25A1259B28412A552A272BF32A1C2D0C2D8E2BF129F929C229D3279226232A362CF32A5A2A322B402B902B8D29BA2B9F2B9A294428BF27D528D2273B2A9F281228DE27B028612B9B2B492C8B349B2F0D2B642AE42A9A2B272C0A2DDB2BDA2B332C972BBE2CE32B9C294128B8278C27C429A42A352B1C2BDD2AA82E3A2A2526772410268026DC291E2CCA2B982DA52C472C9E2B92292C2957287727FF26B42ABE2BC82B982C812B02298E29452A622AB129002AB026BF260326EC274E2BEC29E32987287828F329EF2B742C00336430862B262A472AB62A542BA42CDE2B932D722CA62A1E2C612B562BAC2921287D276627E829F52A4B2D6C2C872BD229D92989290D283929EE29A72B582C992DE12C452D2B2CAF2820292C281F27B4273A2A012DBB2B5D2B6A2AC229B228042BE62B1E2B4B2A3B299C27FF253926F3296D2BC329D6281D282A29072A2D2C15351A2F0B2A3428C428E027B7284E2A762CE92BEF293929D928A928322A07295A25DC2415251D291B2954293F2A2D2B2D2BE229CC298B2A1029FE25C8275B29CC2A182C6E2C072A7E28742732291D27A726B728272A4F2BFA2AAA2A782A762BF12A3D2B352B412C762A1A2BED27E126FC265F28312AAA2AC1293328CA29E32B2A368A2D86298B271C25FB2674287729052B642C7E2C0B2AE328DF260C26CE263F266D24B825E726E9268D27642B922A5E2CC02BAF2ACD29E928B926F5266728022A422C1A2BD22A56299727C7274E28F526AB28DB29EE2AA62A922A9D28392914291629D72AF62A5C2A342CD42CAC2805277F277D2B5D2B9B29692B0E2A182D4F364C2FA5290A28982797272F274028EB2796290C2B16293427C8259325E9256825AD233D2322262F272428BB29272A59291C29EA2AFD2A7828FC26E125BD27FB28AD2A812ACA2985284728112AD92A302856277A292E2B4F2B252C7F29A3285027E2279727EF285328772BF32B3D2A8E28C426042AAD2CD22B552BB52B1A2DFA348E31C12ACF29C429BF2B78299128CB29B629EF2A7C294D2824260F248223A723A02358253C27D428E0270F29592C312B8129B129112A07289526F92452260B2A482B1C2AB428502600284A29392A5729FE289F29D128372A1E2BF32AE42A11292628B5264227F2272D2AE52AE12B862A1F28A1277B29E7285829FB2AAB2AAB343631A4299029A5283329042A5B2A272B472C332CA42A2F296A27CE269525CF233124E925F42582281528F629FE2B4F2A6D2B582A7F296428762635262C25EA2644295C289D26B125CD252B27A527F7289229472B422924299C2BAB2B282AEB2AFD29BA296329F228822ADC2A452AE32976298427C02653280F288B28D629AB34B331332B56290728A9283D29C12AA32BB22D222CF82BE62B162AFF2764260E26FA249725CE2546296C29492A602D2A2CE12BC92CFF298529832AD026B9249A24E2272028AD25A5247F247026F4258A28AF2BF62AE52A9629512CF92B252BD32B662A3D2A722A9529192C5C2CDC29BD2A6D2B3228532890265228092A122C17346030932BA9288A286B28EE269329852C202D4E2C222CE429572941270025AF25BA246F25FE26CF28D9282A2AA42BE82C732B812A482AD72AFC2B852A2228B826A9275228A5276F260726D826F726CE266B2BB12DD32B3A2A2A2BEA298929B62BEB2B4C2AF52948294B2BEA2A782BFA2BCD2BAA2A0D296C279228B729C82C23351E308B2AB42AB4285329C9278629E42CEE2B1F2C762B2F2A4628A12534264B254B252225DD2829276E282E27E0290E2C0A2B11290F29E929C1291B2895269D276B27DE25A725A627762748262A28AC27552CBC2B5E2BEF2ABA2A8B29AF285928FF274A28C9291A29422BE82A2A2C842A882CCB2CEC2CFA2964290E2A602DBB3517306229B428372BEF2ADA295428F62BE62B512CCD2B092CA8286D269B27352719266227B12571287E273025E328642B7F2CD62A822878273C28BE268C255C2770262226D125F52449251E28B127CA27F02A452B2A2CA02C6A2CD629FC2798296D2A7B2B3E2A6729832A302A112CD62DD62A2E2C1F2C0D289E27FC289A2D5436D32F3B29972A3E2A9A2C492B592A9C2B4D2B23294429F828B3297827D8267C273F265828D127782831278725202712273028BA2A432949289727B8264B2420249E266129DE26902573263125342A0C2A602C1D2CC82BCC2A9C2ADB290D293D29912AEB2ADA2CD12A752C672A132CB62B132DB02B052D8B293729B9294D2B2A361F2E162A32292E2B5C2A012D2D2B5D2A3F2BBD2A472AD12782266027FA255A25BA272829BD2A3429EC255625DE252B26FA274A2A42292F28C5275225202485239023DF250A279B262826102669274A297A2C7E2DAA2C232B922A5C2A6429822AD52B3B2A002A892A8D2CBA2B912CC32CA12CFD2BC42B9229D62842285E2A8035272F162928293B298B2A732B3D2CD72D602CAD294629B6263B261F240825FF25D8257F2ABB2B1C2B52282227D524E6272F28BF28C727AD288D299228182729259824AF25712617289F260D28F627D3297C2A982CEA2B6B2B2A2B9528DE27CD2808293D29852A092C9E2C9C2A1B2B222C8F2C772B3D2BB02A0F2A48292028B332812DAA27342607283029B32AFD2BF12BDF2CA629A9279B25AB2454251F276A29E7298429F729A52A10295F26E92601269B266827AB27B3271729E6282A275A25A824112349244F2459284926A22711273B28A72ADC29CC29F529402AFC270B29AE29BE292F2A2F2B662A4129AC2B9B2CDD2BEA2A992A0D2ACF29272894289B32BC2D7727E926082527266A29542BC22B6E2BB2291728FA265F245D2412280F2AC92AE4293C2AB528BC2757252D258927E028A829822A6628F62879298C278C26CF24FD231926A425F6262227FE2671254126FF265928372BC12C6529A1288928082AC02B152A932B832C592B9D2A992B912AA02AC02AEB296C2AB329F129EB32832E6726A224E324ED251828BC29DC299029A027C72411255E24172454268328EC28AB28CA28E6272D270726F4241F2778277328B4261F285B27D9277928E1262D26102577273428C02762277E2714287E278325D6261C2BCE2A7E2AC129B127F02840293A2A902A5F2B6F2BCC2A8F2C222BA62AC02BB72BAD2A5C2B9F298A331E2DA627E625AE243E254727AF26AA28C2274A26B2258B234B25C8241B27B62736295D297B2926299B29B327C326F1282826B428C428AE28D3256A264D2731265E26442772274E27DA27B327372757274829DA263E26B226B428BD270928A12A98296F294828FC27072BD42B452BC92B392CC02A5D2B68271A2835293E2A58344D2E6029D4248D250F25EC26FE27F3266D282824EB220D24EE243E24C6249327B626C8283A29712A7B2939290E28AF283627582752279C274A27B325B0239F240D264E28D227FF27DA27BF275727462613281E29A2273426B927F225AB2648279F2A0128B2260D269A28B428522B452A3D2DBD2AAD2ADC2AA228B9287829BC322A2E8729FE25712458248825E425992638270D258F23E2224C24E4206222E42381264629A727ED297D284327C72784268126B0241B269F249B276F24392605252E27512742285E27092955273D261E26ED25A826CB270127A528FD2467267C267C296C2AD72AE228072A0D293B2B6D2B172B242AC52A062A8C2AF1282E2807336830B029BD25A0249E24A225FE23DA2554263025AE24412391228823DB230A24E5255227A5264028A225302527268D2729264F267124CE234724DC2487237325AA263825FC25DE26C125B627D5264B232E269A266F2698258028D427C2287326CC278B295C2B4E29152ABA29DE29662A5E2C9C2ABE2BA7281D2843254B26B030882E8528E22599241623602318252524F425EB244E239D23D7233722CA230B23E32363240A25DF2405249C251426C025F72432266C2452234B24B225CC2480249925A22500274B26D3265927EA251A24412350244F2593258526DA26CA276E26F52544289C286827682774263E269929902A542B272BD428342805271427E2319A2C8F26A025BF2459235F24D8212B2319252124562409232B239322942222238E22D122DB24EE245B23E523BD2508261525ED26E924FC25C12407234B255D24CC24A926E828D9268E28E028B2262726E02459253E2595270928E226A325012453257B25BA256724F925F5244E25A426BB26D3275829B227C027BD258226A62F292D2427E123CE253625FB2366231F240025A7224D233525B523FA237A23EC22E1236F239923C224DF243226EF28222992270C29BE28A7262225D8253A267D26BC26DF26D126C728C629F629792A8429C82801278726252754283B28922568269A25B824EC2310245E240025B8240A2731256426C426F425F8258B2507278830C22B2B271D269F230724C92392225722CC23DA2478243426B324FA24F12342253B2355236F2496234625C525132928294829042B6629C128F226BF230024602442262625EA26FE26C227712885295229C028DE26B52416285E293E293A28082760284F26B7257325EC246923B6237F23B424C425602347250D257124ED241F313C2D6A27AC23DA22E7229C22C02269225D2307249F23FD244F240B24C72443211722A3221122542351244D25BC2627272729062BBE2B3728EE26792392231F25A7250526F0265C241326D0262927AD269A27CF2643258C25C626222898271B284F283B288F2612259A25512318241726B823E7234624C922F922CA25CF2592317C2B17262923802248223223762107243B215B23B424A3257725DA25182567229E212B2357210D23BA21B822E0248E26C7264E296B2A9D28D127E72462248723A0243F25AD2569242F25B42505265B26F2259C2623256F24AE2430267A2765279128B0280628CA254F260623A024A724FF2417268D2537248A25D62451264C30662BF123B22241245422CF222D22FF227123D32217260F260B25F5251525ED232924F2213223C323AA22C7210624FE2571241327842726277C26E223FE239E21F0221A242326A424EE243525A325892482254F273B2433240327FF261128F32774263D260027A426FF26072682247C268E27FB252426E8241B24A1249525A32E072C9E26ED222A237324F421F422DF22E423F32476243D259A26E42489230B259E2445247623FE23F121202131239124F423142403260B27F5249C258E233A21DD239D236D239B222826782453258623FB25B6250724A12429277926282AA527FA28D9276C268324BE253925A4253827832618254A2664267426FD252B276E31862D8626E222FF22AD24042262231E226E2389238D24C523BC246E23AF236823F022CE2251217922DD216A21762285246724A3239C2382213D2442238F24BA22702211222D233423D82191259623882241231E246A229224D3258E26D126182873272726982581229A243424FD231A24AE24E024622623268C25BF250B266831CF2B05268624B421C321F3218D226822D323DF221123A9238E230D254125082263233D223F22E5229022AD2152226122EF22A423D62159211424C2233223FE21CB22BA2302222021732086228220BA21DC220E238320012230257525DC26D9242B2795263125C1240D23A022AD222224D4224D23EB2338226425AC253D27722F6C2BC62581236F222D22D522A7239723BB23AA220823982479233323FE2350241523A1215A214F2280227121AB21A722F123E7225F21A3223321582301225E222622112262237C218220DD21152167208421A5201A2186213B23EA2489241E27C92508247E24BA24A12493215D22DF227D22A0215923B5221425CA256A26F32E602BAC263922D2213C21DD2033239D22D5228F211A23DB202B224122F322512289226521C521A5219D22C21F6C21CF248F248323D222B321D622DB215023F9231A2277211A2336203C217D2165207B214B213922BE221421CA23772390234E23A7252C2499222C22AF2390230422D9226E216A22CC23F9227223AC25DA267E2F212CB02506246022F422AE22EE2128220023F121CD22832175229A211D224721A520C821F720F920B81F9B1FDB2088228822E9211F21CC22A4224E22D6225D2265224222692197202F22FF219D214121A12057210720B321C822D02243221E239923FB2274236B23BF236521D1216622DE233F217A22852155222322222672306F2B662471226B220E223E212721E022B6209C218121132128210720D9200322582110201622BD21E720211FD92179215B216122E122432212223C219C209022E421922207208620951FC02145208820A2202021BF1F55202722E4203B22702245227F22402203229222D0229023CE203E211D229522D4226E23AE24CD25612E4C2BC8242221FA211122ED2011224622E621F5229B223E20BD20AB2033219A21A521E3214521C5207721D11E8721271F40211522AB1FEE217F202521D4207F227221A320DD20E9204C1F6C2164218720FA22F721841E4F21BF206421D621C2232F22AE1F0823E32141205E21DB2050213F211A2208239F20772398232126B72E7A2BD4254E22772144224D229E219B231422682149211421C11FF71FA921DD228621C32193232C20B621E82082217020C621DE223F219721DB207321B52015225421DF1E3321D51FB01FCC21A92149202F2241212521861F3322C0201024D221AD215E21AA219B20B122B11FA121C422612360213822EA226A23C1214824B02F6B2C84258421DF2295226D22E921AC2348230722BC216C221321C31FE0211022DE22A7222B2214202D22C220C421D420B420BF22E020691FDB201B232D21DB20C91F9E1E8620DA1F251F5121D62044207722AB22BB20FF204B20F11F74201C215422DC200321E21FB32137216621AB220E22D3228821D120EA215D244A255E31892CA325C523C220A2230C247C22E322AE2337233E2475227B2108216522DD2083215B23DB2132203D213B20C021FA20DE20B1221122DA20CB21FF1F5E208920881F4C1F651EAC1FAD202520D020B622D922EB21D7214B1FC11DF41FEF1FDF2131217B21012103206B21E4206421BC2284217824DA22C320DA20F223D2251C2F ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 403F ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 0009 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 A42936256425802333245C239422DD222223C321A920C21F7F1F241F6D2142209F1FCA21B221881F3F21F02026226320C6206D2025224D220E2231225524F1227E219F212720F11D3C1E41205E202921D3203322682031209B20BE1FBD1E4E1F59202520E01F081E38200320501FEA210420AF22B121DB207B1F53228B23BC2EA32C1026CA234A26042614246B2437253E25A52214239F213E2043219B21BB212E21BC21AE214421F9216B239C236C248E214823FE2180233723A624A225EF235224AA247323A2225C20A722F720A3216324A223AC214021842171236322B020B62081206021A120AA222D236622AA228B22F2235C247223CD233923BA251A2F072C3F26F125A3251725BC2439256F265D249E26E7243C241E221421F4215C221823F32340233E22442277245F2417248E242624E9225523052567220A25CD26C8266C2786255524D42162225021DB21642336249722DC22082383205A2237224722DF2172213E20DE22A6238F244723FF22A7231226D3235C2436242F27C0309E2CF72889266D2495258F251827C1252525B5243C24F222112377214423FE200A237823C7239E25AE237F24D3232F260425AB240623D9235323F423F92335267A289C285729FF2499225C22B6208F201C233425FA24D024DA23C623DA24D424F524BA22A122092241228A221E233324B42492241225332696240C26F8267030972ED027F02368232D244C253425BD256E26B025A9251C256723312246239722DD218B23F4235324D32402252828E52437259F26C722F71F332349248925A5267E289B297529E02598235D229E207C226822532646258E2597254D2687259A25D026EB243D24B62153233623D7241E25042584245E254124A9251B27BA264B2FC02CB327A124CE24042245245C2340243426B4252326CF2652245924A9231F23EF227422BC220C2564244525492776282E266B260424C42288223924C525072831288228C527E02414254521D121412160226A24A82684272126EB26F02606287628FB26D82314238D224923AE23E124B023EB24FD269E269A263A296A29CB300B2EE426702565245423F0227F24362497246026532693256D26C02590263925B424952259237C2360267C277C271429C2277D27A3271E263325C8243A28CF29BA299929B4281F270E2597237F227721FA22B025EC2518284B29202A2229DE29D02BC42853279223FD227822A422D123AF259E240027A526C929FB2AF32932339D2F9F2965278C263824892108227F233924B8257C242E265E27C2283C266225752592230D247A24CA2489243C27DB2ACE290E2A302A5C28D2263826CF25BE2604288E281F2834264926F726F225C7216C248A230F242C26C62879271D293829FF297D297927E724C82386221C22C323E1243B268327CE271A2B042CBC2CF2337C2E7F2A2D29AC2692253D238A2177230C253025F3256A26B027B02747284E257424DF246F2447246024F0232D24C428C128262BA52946282E26AD257224D824E126F027A2262926C7257E253324DB2357249622D5232D240A29EE28ED2736287129B4283829E426D025BD2253212C23D525A126EA2816298329492B472ABE334131FC2899277D262C269823E923532320255F249F272D295A29932A002A1528122716259E2506256B240C25A024F72763285E2B362BD528412966253623C423CB245E27102683269F251428742742253D25E2248123A0236024DD257725A9268C2B062A1A28AC277B25FA23C023FF22CA2421286D298C2A2229032A172A3B35CB2F592C782AB328AC27E3249424DD230F2429251929B72A882CDF2AFC2A9A29792808275F27EC2767252726F1248E28C2277D2722271127FF273A26BA236C2290241D253526D126512669274B29ED2700272C244C230123C2246524F624AD264827FC26CF2691269625AF220F2158236D248B25E0271F277128242808284933A130202B7E29202BF727F924E5247723CF24A125D42660290C2BD32BDE2A3F2A48287A272E28C72BA1297A2A06269925B82693272828ED271C276C26662617248322FB239A2358255A2667277A29BC295C298925A824E423F92318245624A4268D26B626E127D224E625F7238A222624F323B9240926A926D22543256828E3318731982CB629F6288B271126352532238A24B82312247A28EE28492CB32B902B5F2960286E27CB2AB32AD82966265C27AF25AE26A127DE27A828BC294C28C826C123012477247C236C237B26B4298E28BA2503264F239822B8249525742520285E26D4250C248C249C249D234D223A23C822F422CB268825EF254C264228DC2F5E2FA32AA22854288B28AB25B625CF253126BE252E24D124D6257B27012A0329652950296429902A2A2BFB2978286D261D268226F5266728112B7B29A928E2256326B324D223EB22592434258A2775262928722779244C23E022E424F1265F287128CF24F62585250727C523B62196220F23D9244A26E626F827A027E428D7337E2D1F2862275E26F327BE26552897266F29DF26F82696261E2456253426E027E826282A5A2C142BF82AD2291329FB277F26BE24D8243E286F29AE28E62880284E296B27AE2546257C254D25A22605286328B8281227C5232F2378242A24A025102679274128AB28812AE6281026D324A9246723D62658267D287429F5294933882DAC2879253E25BC265D28C828BD295129582AD329D226F42284246525FD26D1250629A529D32A7A2DAE2DDE293E28A2240C259025952584263A28D9289729462A79282B27A02673266A2ABB29282A5A2C97285E269224AE2392225223AF24E3261B264129D6294C2CEC2C9028B727CF24DC24DB253028DF288229FF2A9533022B7627712662279626C927C3283F2974294B29E5293E27AA240A24712372243D2553268D2898299F2C942A6C2A7A293827B926AC25B5237A25E1263228072A382B782BAE2A06295828A927AE28AB297D2AD22953279C25202686238B2263258D26F72615297428A4294F2ABC29E52529264025C6250828082A4D2B3A2C9534202C6E26B6254324C726E5289228BD284A28FD270427A32545249323E321782235238F258C287F28EB28BD29682860277A259227ED2738276326DE24A226AB275F2ADB29372874269128FD279727C3268C270C290C2704233825532297218622C226E925AB272D26BE28EB27F52A7D293D289A257824CF2542293E2B782BA135B62A3128E523AD25792725282C29F927B726BF25262758243D24A6231A2488228D23A4263626C629F429C827D728522961264628E228512A8929C2264326B925D926092790263123082694258D26DD230A26DC24A6243123CD21AF209F20D0211724ED26B228F625A328B1284928DE265526532431236723DE2765296D2CCC34932D1D264223DB24D525382713272B2748253C254D26B3260C26D223C0256B2584240922E72578277826E826B9274228D4284128F7263F270B2B6A277D263A234C244C25DA237F23232367232B2272233C247824EB22A3221324A8218F212C23DF249725AD26C028972B6F296329662B60286125E623DE22B724D1276329E933C92C13272025D2246725192734264D2675269326D428DB27A0264B264A2575255023E625C1248724A925B92886289E28FC28F9262D2712263A266126B9246C258324982421232223B021922141240322F72465251725132554239B249122742277234323F72532285B2BAD2B262B082EC6298627602647226824A325152793327B2DCB27572782244D241B2603275B275528492873266F29442A0C2B87282D276A268C23EF257B24F2256826C527C7279926B626FF230A2477257324C4259B2404254F25A9232B23F4224D237B2325253B277727F025ED266527AD261A243D234723D52407264829CB2C7B2BC72B882AD229B8296726C1254A2521251B287832722EDD28BE26F726FC252626FB26AC2784290A2ADD2A142B482B102AD62BC8285A27F72486247A221F23B82351240325EF242B25BF234F24B72490239C2534269224BE24D52342237F221126ED25C0256A29CE29EB292D29B22920294F27F3259524EE242A28F1287A2CB22DF22B322BEC2A98296F287926E324C0256A27E8332330C52AE02A0F2976270724E5255328BD28B228DA29732BB129E42BB62D292A4F29AD27E024E7245C2475244D250E26D5255325BA24EC260C27572539274B2770277E278A2494210A24DA24FF26C128AC2AA42A782C4F2BF42BE02A3B293029FB24B72470256B279A2AAA2A462B152C582C942A9A2A7B28FA265B25A32808348731C12BE42A0A2BE02979271325C72520295329292C8B2BE22A822BBA2AA32A9B29E3274326BE27E4249424F7250325942496253927F9274D271C279326412843285D294828C4257824DA23FD268127A4299B2B7B2C962C102D012B4C2ABB294C2A2426EE232225D126CD28D129EC2C512C4E2B5E2B2C2A0B2A7028142610314F31492C472BB02C982A8E292D2814269126A126D328762A062B7A2CA62CD22BDF2B3628B127EC261827222847257E25A024B225B427FC27232A9B29FA29BF29392B452B982BAC286D24B2243625E925C32A2C2C382B492AC22CD42A7E2A0E2C202A89280F262B233E261E27FB29E62CEC2C1A2AD6295128AC27B4253F27BB307C32592C7E2AD7292B2BE22A98293328342693256828302AE02A982C552CB02BD12B2F2BB828132AE329A828E426AC2662247C24B226D926E82836290F2A2D29212B822C6F2D3129D6288125AA24F725D726A12A812B002BEB2ADE2BFD2A1F2DA62AB828F426B224B1247D24B82668281728DE271328262774259625CB25F22FD7313F2DB22883294929442AD72A472AE5277925EF27A428902D5F2CFC2C862CD32A0A2BAB2AFA2B8F2B4C2B242934270025AB23E62290254E27B2283B299C2A3E2C842D2A2DB22A1E2A93263E25FB23B82576273029F32A462AFF2A362A632AE22B86286E25422549249C23A324DF24D325BC246F26AE25DD25F9242C27F5308D31EF2A422A522983288727B0288028A3288D26B7248C279928442C322C972DF42C822AA02B8D2B432CB02B9329C726DE23FB232C222223A1262D299F296E2BB62CA12D262E3B2B912A4528B5234D23772538262529E629FC2BEA282929842A9629C1273624562451230F235D237D2546247925A1258D2494243526EC25FC2FC330BE2AB12651266C26FB2807283727032869254C27CD25882610277729092C6D2C1A2B822BBD2D892AD42A2828E227A3230D230B2341232F266628092AB92B932B522CBB2C0B2C8A2A1F298A26F5240626D626592A7F29732B842A252AD429B8296B28E6251C24BF238023EB2212231023EE2340269625BD25BB264E26E430E12E0B29CD275528C729CB29642963293028FE29942719271B25D725E5250A26452806292A2B1D2B93297D2802294427E424F7239024E72215264F29882BEB2BF82B3B2CC72B112B002B4E2942281E261F2506285D26DD281E2B5D2C732A762A4029D52964273223462512259A25FB24D7230C24F625FD269429242A59290B32262DF129DD27182A502C7C29ED288A278229752B132DE12A0127B2257F27C2279526FF27B22844295D269F26DB25FE24FA2428261C259B23DC25B925FC29EA2A882D662BB22AD427B527C529B529F225E324862520242326F028A82A4B2C5B2AA62A4F295826AB257E24FD22E7223023F423502647260228E427FD2ABD2BDB33322D0527B625E52656294E2A522B282A7729012BCC2B4A2B622AAA278C250025A625F424BC27AE267F26C1267626CD2577260F28412785266F257925CD25E828452A8B2BB729A727B325C029202ABF284B27C92513240424122695277429D728812984298C284527D52720253523FE22F02495261D29D5285F2A182C3E2C2C35322E4B28172584263827C6296D29952A6B2B9B2A0D2A532B9E2A86291F27F324772374256925532612283A27E8288F2745279028C228192569259E2518250627052B022CB1294227BD288B28E729D129D129EC277622E1222624AB24F82541262D275328B529C22A3C299B243B220C22DE25ED271428BE29F32B772C222C6D36132FB0273524792540276226BD29082A602CCD2A5F2B862B602C54291428312597249D24EB24F225BA29B8291729502A7F2896274829D226572573252C25A827DC29B32DE52A96286E292E2B502B0329E9282227C22347232223262573272425EE2657261B269326FB262D26C423DF23F123E7262D2AEF2ADE2A3D2CC52BB235E62D0B28502663249F251E26EB276329042B6B2B4A2CE32C752BCD29F427EE259926EE24DA2338269B252127082985286826E9269D286626CF25B8256A2455269428C42A222DBB280928272CAD2C7D2860266527632580223024F0260D282729E327DF26BE27D528EB28E825D021442278233926332854284629632A7F2A9835EE2F5D290C286426AF2587245B252E29672B222D9B2D732B0C2B1129CC282128A9279D27A725AF269B252D263427B129E5285027252A0729E427B827AE242B268827DF2AC02BC3286A27DA29272AF02890281C27A22419238024AE246828B429A52C43283429EB2AFE28C526E824D12427242C250428E128972A862A592A4D332E30C42ADD286B2723278D264C27C228952A932C162D102AC928022BB329AB283A291A2856273F265F26B7231027362AF929FB28F429EE29D7296428C4257F26AB261129CA2A4C298428BC27282840264D27F9242026C323A8236C269F28D729202B642B092A9329312B8D28CB279B266B255223E3266527D228CE29132B4834FD30922B6F2AC52A2A2A68298728F526962A8429522B112CED2A7B2AEC2ABF29982B212AD2281A28A6255626F028C128A22B2A2B9F29432BE929A729FC285D26F925F027D52A37291828D2263425AE2532267624A42529251125A3248027FA2A762CCE2BD62A302AA02A972A4E2AE028B125E5232526FD245F29592B932C89336231B72C742C882BCB2A662B192B8E29F8275127AF29822BCD29A72820280C28F327C32944294528E5273725B326BB29FF29582A6F2AD82AD72A0F2AD629EC26C125DA2576274E28D8277F269624D92305258C26FB26012645279B244E257927DA297A2B362C162BF02B782A932ABD294D280425802628274F2A942C2B2D03353531C72E932C732D012DA62D782DF32B302B6F28C0250326C427D729EE2A9F2A052C182B0F28C729712725266126EC260329AA2A7A29D0298E2C6829AF2993281826EC249725F7251626B325FA228123D4258827D62899274C2683241525E7261E27A72845291A2AAA2B522BFD2AEF298C27EF246924C225A028142AFF2DFE342E33722D1E2BF42CDE2A652C262D312DD02BB729D328532742267E278A2A882BB62B4B2B6C2B642A462A35283427D52702294229BB29CA298F2A132A9A28B228B8260726BA265123A923C82403258A24E825E628D42AA02BAE2AF2267624FD23E72639276A26FB26EF289F28CC29F2292828D2253C2624251E280A2B372C93321833A12DFC2C542B0A2EB429252CE52C832B252B9D29A227E4249A258729D22AF72A812A612BF129B2291E29A4269A26A32682276A28CC2959291228BC27702707276725D6255F23D6225022C4231125B42751281A2B7129AC2822264E24C7222C245B268826BE269A274B283C29A62A962990289D269F267126AD25EE28DC31F230CA2C8D2CB82CDD2C682D032BFC2BBF2B472CB92BAC29B7268226B22636297D29962BD22BD32A6728862802293D28CB241F29CB29C62729290A2716264E28F7270227F724CF2180211622C22445254A289129212A282A222AC427CF241B257C23D124C52777287F2867280729F62AA62B0E2A03292425DF23F625EF28BD322C30132CD62B672CAD2C9C2C7029C728E12A292A442A9B29722693247927F428E629872C0C2B622B3B2C6B2B342B37294326A6240125DD26C6264826592677257D252E262725B3217A22C6233F24A727F3282C2CEA2AD22B2029EE284D2648249A242B267D28D129DC2BCD283629DB2A852A1F2A302948263A26E826D6285D32522ED729B829622B8F2BC929E92874280C286D288D2793275027BC268926D72694283D2B362CF42C702AFF2A6F2B3C29F427DF24C9237D24B025B1226225DB24C3250C26A7258D237722F22119257F268328242B062A4D2A3B2B1828222828264024E724AF277727392B502B092A822B922A1D2A402A1A2788268529A32AE433BD2D512A7F2A302B972C5C2BEA2902281A275D255E26C925F12560260826A4255E27F32A78286628F92726274928D2289626B624B3236425FD25E525432774282528A7265F27FB259B230D233625D424A626AE275E299C2971274629DC288B26542343255D258427282A912A002A902C362BB329FA2940274E260D2736298534C62E5829022A872C6B2CE32CDB29E1286C283927AF25B6279927F8275926A325662677262627CF274F260D269628F927C125D324A324ED2456267D283A295A29002A8C29AB2A88280B26D124F2226E23E1243C27192747271828382894289D272F261D27FA27F628AE2AD92AC22B842B742AE52A042A2228E626A0278A29C5340730262A09285829312C382D9E2BF7280328F72643285327A5272628C6275024D825032357255525A32410278227D72999293326C222AA23FE26D3267D28DE286F29DD29C02CC529F7275C240323B9210623E82533257A26A728FA280D28D9273B2688248A274A28E22A572B232A3B2BB92A3229E7268825F826B028D22B8E347730102BE5270028012B422C4E2ACC2A782BF32851271D284128CC29402A91292B2513246A25DE270428872749283B28D629DA292627A625CD2505276B290D2AC42A6C2BCA2BB12B5129FA26CF234623EE22CB256026DB25FC28152B5B2A7128F6249F272327EB296F2B1A2BEF2A7E2A6D2AEC29E927002553260127882AAD358C32A02CE7297B2793280B2BBB2E9F2D642C6D292129B628DD29AE2A522CD529FB287E2958270A295427E128A929A42B5C294828C927B624F3248928392AD4293428E0280D2A322B812A8627F324082493254925C1269128762A472D122B702B87296229CA278E28982AFA2A682B3E2C0B2B8B29C928FC258C2725259929F732C632E02E3F2C4629AE279D2A692D7C2D5B2EBA2C9E2B3D292929A32B3B2C822B0829652736264F29B727B2270C2A122CCB29EA2BD32974272227082649290F2A472A9B2B542AB92A002A102A8D27C424DE257327C327F22716290F2B9D2BB12AE529CA2869271B26D92A0F2BB02AED2A632B6F2B0F29BC254D258726D927AB32BF31662DA42EBC2AE229A9294E2BFC2BAD2E102F122D842BA72BEB2A2D2D2B2C362ACC29A7266B285228E3261428EE27A529B2284D2A3E28942616256D28B3294E2A102CF02B442B132CB42AF2297427C9251627C926E028762B4F2B772AC02A8F293228AB25BA263F277828882AD32A022A092ABF2B3B28BC26AA25CF27F7342533492CDF2C852BBC2AF828BD28042D662D612C2B2DF02ACE289D28662AF42DE02A572A8029172A8727EA2708286D28CA27BE280028E127C0255925F627302A9F2D142DC92BB52B0C2BF22B8F294327092703289028E92AC92A142BEE28F2280F2AFA265124EA255A29BB29012B0C2DA42AD629412CEF2992295F28DC284733AD30822CB42A002D122D5C2AE6283B2AA52ADF2B752C342C4127CB28C428762AB12A9D2875273628462BFF29962B782A0228A3289B2BB4276926BE25A526B728AB2B982CED2BBE2CAC2BAC2ADB29AB26B0266829A22A162BD92AB22B93296F2996295F269524FD2468275228F6278D2802284329872DD82BEF2AC32950285030CC316F2CA42C312C0E2AC92A70275228B82A882A172B332B712AFA274129BB296D2BF6284927F0293D2B772DD12BE42CCF2A9B2B952A4C2B6D28E72659279027692A5F2EE82B682D722C692BDE276A2530265F280C283F29D2297E2B4D2B4F2AAB285A26EB255F22E4257C2677259D270327F527722CA72BE329F629C429D931E72F2A2B912A402B7D2954280B2690277026842644296727C0288A288D2ADD2A532CBF297B27CC27442B3F2AF32CB72B322DC22C042CD32AB0295D284F27A2275C29632D772DDE2DFB2C762A8F2ADF26DC25CD2824295529F92A9C2BCC2BAF2B1E2A5D274125AF23CD230525F5265D265E249D231D29FD28F82932282728B230782FEA278A27CA275A286F259126ED2490256027462803284C29BC29932B322B642CCC2A1428F4275328162A2F2A732B732B652B742CC12BA32A5B289B260C264729A82C162DA52C912B16292A2912266027D428EE29EC286C2A6F2A1A2B152CD12A94290228EC22DD249E24B4269A266A257D272829FA291F2C01297C2849318A2C8D26AD258325122567253F252725492519269028BC29A82CDC2A8E2C902BC22BBD2A4229D12890281129BE2AC92A1F2AF229662C772AF02B182977287226CE269F2A3C2DDB2AF32AA92ADF27FF2427265827E1276F28A7273228D129B4292029C3278826862354255B255D28C729BA2701296328B42794295929472A2835E52CBA26EA265B26BD262027B725F3250E26AF254E283E29FA2BDF2CC32DE02B982C7A2C602A38296F28BA29312ADF2A732CF02A6C291729F62AA92BD02819288F277E2B0C2C1F2CCA2AC52A4229C426B0268726C92A502A0B2A102A4F29852A29291D268A26CC232126C0258D25D22AB92B932A0E2A722A882A652CC52D4E361D2D04272A260C277A27C6274C25D926D625712552274B28822A712A222BA32D4E2DB32CCF2A7B2850277F2A5B2B7E2B48299A274A2832290429B72BEE275025A226C62A6F2C112C6F2B602A742998272D26DC277328052BC529022A952B292B462AC52788250A253D270A260B277D29312C782C372C0B2AC12B6E2DF12EBF362E2DE32822266D27D6277F271328DD2792283026D7266E267629852B642C552AF82BD42B322B6529D9267D29AA2BE22B022ADC29E627A2277D283E294D288D265427BF29AC2DB52DE42B402BBE2C72292428EA264129FD2B9A2DEE2A842ABE2A8E2C162C6B2B3F288B28B326D126D929192C162D452EDC2D8D2DE32B772D2435692FD52A2F2B1A287D29BB2A382A132976292529D928DB2774283B2B342B272C4C2AC42A152A6C2A0B260727AF279B2AB02A122C80295E288028D02875273426F1245B27A02C0F2B962B8B2B4B2C98294029AD27E826C728F32C712A702A0B2BB92CCD2C9F2B632B902A6429A3288528602A522A5930E52BFD2B7A2D092C8E33AD326E2BE72A3329442B362ED02B732B962C1A2B212B012A622AD62BED2CC9299B2BD22BE12A962865283F26AA248828752A6D2ACC2B492AA129D4272F27B1255B253F278C280E2A512ACD2A652C99292429472883273729E82B4A2C332AC52A1E2A952C472B592B792C2C296B27EA291529082A4E2DEF2BA42A082CB0284633E032C52ED92A702A4B2C9A2CC12DAF2CF02D582EAA2B662AE429B52B382DF72D702CBA2C622C832CBF296A29E1277A258126FD29E129732A422BBD294E271C26222656264A2638278829CE2BBC2AB52B7C2C292968298729A12C4A2BD12A012AC92A2029732AE72D7F2DFE296F277727CC27EC2AD62A7C2AF4289029C42954339931522E992B382B7729842CBF2E822D7F2D212B4C2E9729FA2AA92AEF2C122CE42DBC2C8C2DA62B3A2AEF28FD2405264E25CD25E6271027D3282029142676257825C025C524F425342AAD2AE1299929A52AD92A7829FD28312A8F2B212BD328CB294329402AE12A1E2AC1281925E72586247F26B727DF27DD26E025B127ED315A2F7A2D152BDE29E12B302CEA2BA72E4F2CD02CD92C172A5A2BD82A112E262DF62C862D7C2C8B2DD02B592A112AD727CB247B2597262328E628862938291428602603261428C8288228722AD32A2E290A29702CF428C128D12B412DAA2C1C2B3328DA272929FE279E2A7A286D26E7251F253125FE25D9257D251D283F296933C12F052CD52BC52A9A291F2A032B9E2D6A2C882CDE2DE52D6B29D3292A2C4E2DB22DD72C842B072E5B2D852BDA2B1B2733262428CD296928D8280B2A4F2A0329E0286A27D3264528BC29562B5B2BA22B0F2C9D2C092C4C2A00297F29942B8729DC283C2A4729F92879291028D829552788242425D6264D25DB250428452AB5324530862B202BA928342881281C29702B8A2D9E2C902C7D2A382A9829062B702D082C122C2D2BB82D712E972CC32A0E2A3027E6270729BC293E2B162A4B2ABA28D729A12868263429792AE5299A2B5B2A402CFA2D7F2BC22B9A28CE252529F029142BDF2A48285A29DB299D2CA32AD82868266D25F424AE26FB29442AE12AA633162FD62B422B3B295B2852281C28CF28FC2CBF2C752DF02C5D2A5E29BD2A6C294A2B632D332B422B822CA92B672B4F291B289E286A2B7A2B7A2C562C042C4F2C8F2B482AAE299227C3293D2C3E2C062B532DD42CBD2BF1289C292328CB272F2B332C162B3B2BAA2AA62C4E2BC82B2E2C2C28B827C02658281D2A7C2C522D6334392FD82B5D2C102BBD28142885277729C42C7D2D6F2CC32D22290D28D528A328052B8F2A042B432C8E2C6D2CBB2A302993270028E92A942BD52D802C1A2CB22AB42BB6281A28D325D8287E2A112C8B2B872D5B2CF92B5929AB2AC928512A012DA62C112B0D2B4F2A4F2C162C692DEB2BBC29B1286B274129F72A6E2C1B2D57360632B52C582C002CC32A792AD328132A162D892C2E2B222CD42893278427BF29D32AAD2BFB2B462B2D2D092C6B2CB62A852839286C294E2C352DD72C352A802ACD2B9128B82869258527C02AAA2B232B692B9A2C6B29B9298C27F72855281B2ACF2D222B1F2C042B512A472B472B472CCE2BB129D4291B2BBF2C422BB72DC037892F892B5E2BFE2AAB2BDD2AB62B402C4E2C132B162B1E2924278E24D32529291D2AF62A8C2C812CD82AD72A4129BA284C278E28A428A129BC2B302AF52A702CAD29DD27EE256F2470276E282129EF28532A8B29E22AF828F7278E254E273829AE2B932B4C2A482AEA29472A432BFE2CE5291C29D529A42AF42BF32A472C3637DB2E552B592A942D7B2C4D2BAB2D412D782D252CCB2928280D25292645267528C82A132D592CF32B7129132D842AC22935271C2961284A2896291F2BE029DD2A93295126D62528244E25A0284A293529A8288629352AA2287B277A263427652AF62C0A2CF82BB22BD92BE229FB293B2AF3292B29D029EE29262C6C2B472CC7362A2F822A062C322E762D752C2E2C652BA72DCC2C732C70287426B8279D26AA2ABA2CDA2B4C2BB72B98298029C62BF02A2B2743265325D825F92628264D29CB2A1E2B11294527AD24BA256828A9289D28C428C927A3263A2551288B275C26AB29AE2BB02D0D2CBE2AFB2D3D2B2B2CF9297D2789286229242A6E2C822CDB2C2C35A62E2C29F829A62BC72EEC2CFB2AE42BF02D832DF72C6D293128E9278829582B942C202C552A792AAA2724286D28592825240E25D42409247926D525A428322A402B182AA92732263C266528912AE429B128D3280A261626FB28B929DC2936295A2B832BC62C352BFC2C562CBD2BDC2BB4289F28C229A9281C2AE52C282E8A353E2F682A5A28DE29162DF62C972C992DDA2DD42D402D1C2BB4284728C828872B802B9F2C602AA0276B26D227F3276E2695256B241625F62484241E268725D728F92B2B2AC029CC26842663285B2A052AF92A502A70289829132BFB29FD2A882A0B2C572C452CAF2C662CD22B902BE52DBD2B942ABB28FD2818292B2BAE2D30350931212AA028AF289C2AC42CAA2CDB2B0D2E6F2DF22D782B2A291F2A2D2C7C2DDE2DB82C092CD928C626FE26C826EC26CB252426CD26752575265A25F7271C28032ABE2ABC284925A725DA28D1298D28E42AFC2A532BDA2B0B2C2B2C0E2A07297C288C2B4A2E2D2BF12C9A2C5C2AC72C732A692BBE292A263E26A929C72B3635E930ED2BD328CB286E2AB62C932DA62C2A2C1F2E8D2CAF2B262A8A2A492B932CD92CED2BDB2B9F2A6D29502A4A2ADD2A0D2A5A2AC328D126D0289128912820276A28CF2A1E2BB9279B26A42A6A29442BEE2C402D9B2AC02B9C2D692D9C2BA32960297A2B212A802C9D2BB52CB22B402C4C2BD22B342AF228F3281129872AA034D731432C562BDA28902A962DEF2CBC2E7A2E972D892D812CAE2BED29FF286E2CC829242C0F2D282C782AB428482AD12BD029A0291E283E29F02ACC2A272CEF2A522BD12B2B2B4E29F727E4275829582B552C872D872BD52C8E2D922EA92D672A43288128CB29192C772DFE2BAD2C4D2D082C5A2B512AF429CE292329C2299A347031D22CDA296F29C1296F2B772DB32E9F2D7C2E092E212D122B5B2A2528FD2AE92A8A2BBF2BA32B842A58294E294C2C0E29E5290F29E928402BB42CE92A922B312C852C532C662B93297829442CC92B4F2CE82C602C502D022EF02CEC2CB72A90273B28A928122BDE2CC62A3B2D892B7B2A452C612BB328BC29D428422ACA323D313C2D3C2A2529AB280A2A312CF72D612EF52DBF2DE42D702DA72AFB29B7273526C527122A0A2CAD2B742A842AE829B92B1A2BD2287E29BE2C732B1A2A0A2C202CBE2A602A94290E2931296C2B3F2B4E2DBC2C812DF92B902D4D2DB82B732C032A4228E228B72B232CD92BDC2BE02CC62C2B2CAB2C102BE92B6B2BA02B35340E30932C702C432A2729592AFE2A6B2CD42CFB2CFD2CB72C652C8A2BFA2A6027AA262F27E328562A8D2C8F2A9C29F72928290E2A2F2A2528342B562B462C522A5F2BF82A2A2C7F2A8129A728772A422B572CB62C002CCD29C62E052BDE2BBB2BE329652A092A982A692CD42B2F2C722CDE2B5F2D4E2C032B0D2A062BA82B2133262F602B6729B52967299729D22A9A2AEA2BC32B782BC02B682BB32B132A55287C2516271227DD29802CAD2A782ACB29D82A212B772AE927182A142C992D1B2DEC2BBA2BE82B682B232AB8272629FB28F629252B1229E229402A3C2A8029EA29E429D0282A28EE28C92AF92B482C712CE02BA82D302C9029D029812A082B5133A9300729E529222A61288427FD272E2B3C2A8D2B2A2BCA2A252B892C382C2629DF270427D028B9291A2B9F293D2BC42AC42C902B332B0E28DE295F2AD22B402C3C2CD42B0F29692A212A4D293828AF28CA2BF729802ADF282B2BEB29F027462813276C27EF25FA27BB2AEC2AEE2CDB2CA02D982DFE2BB029AB2A3029BD2AD335F82E512ACC28F42631262826C3262C29DA2AB829822A8427C82A102C3D2B942BE1292E2A312ACD2CE129F428E829732AA32B5B2B1B2B292BB229092A6F2C402CC02A022ACA2834275D29F228B0287427A02715292A2A6429B32DEF2A902B462ABF288E277A25F525E029CB2B692C242DAB2C9D2C382F792A3C28C02673293E33F92FED29B828C9268F269326D625232AFA2AEC2A7A2AE229A32AFB2B062BFD2B8F2AE129F62B0C2CD52B2F2BA02954290129612AA1296F2BB22AE92A722BCF2A5F2A70289E273A266D269D29842ACC26DA266A29B02A7C2B582C852A5A29132882293A28A22641282E2A2A2CC32CBD2ED52CD22B2A2CB02AF0281929FE29AB33D62DC229EF26BA267F26BE26572557274A28DE29342C742BC82C7A2B8A2CC129DD29462AFB2CA32C642C3B2B992BF22931288F286826C62792274928982AB42A95277F26E025BA26CC27CA288B275D2610277B276A262C29CC2A332A9E29B02745288F25B8263E27B228E22B402C3B2CC62D182D2F2CE729432A7B29EC285434B22F2629972657263C2771258C253825C0275E28CD29BB2B072DBB2C792B402AD9274A2A232B4F2CC92B192AC42C06290E27542653264F2792273029AF2860282028AB27B62602262126C4276A281B247D2607262E27212AC82B9528B827FB244F26CA249C2596243628372A8D2B7E2BEA2BB32B132C3C2B0F2AE5283C291F33602F042A3A278F253D25542570253526A0270E28FC277C28132A4E2CBE2A9929AD28B727E429272B662A2E29102AB829A62819282F2434251C2762280A2829287A28FE279F27BA25DB24FC245B257325DA257A26FC284028072A842A9F26C225E62431242225ED21AF24D2274E28252A2829B229D12AD429F529F428AC27ED31CD2F032BB9275625A825B7246F247326212836273829E729B729C529F62A1C29A2269929682BBE2ACD2A6F2AB42A1E2B3B298C29A7270B2534287D279E28052A7A2A092A612A6526A22546248724C724BA27A227122886286E2AC028482885266A247C24B124DB24F5256723E425BD273228482729286C293F2A62277D27BD3144309B29B82826260F26FA25862656272C2690274A272D2A4D293C2A132B8528C327072A252A482C502A6E2947282C29B429CC29BE27B6260726D828882A322A892BC72A34297D27E527B025172663283329712C2829F1275328D827A629682877265325EB246A26C62747253726E127D228F32818295728BF27FC25FC254E30432E7E284F289225092577230325EA261C265A263928CE281729CE294129BE286628FA29ED2A3F2C082BEB29B32A952BE429D62ADE28BA2689260126A529262C162BEE29FD2A1D2BCD2ABC270726BA290C2AA92D4E2AF5272A299A288C26522439247B26012A8A28C228D126A926602665270329A6296429DF29432946290C326B2E7D27E324F1255B24E0233C25EF25D2263E26B9252C283629942A9B2AB52954287E287C2B062CA92BCB29692B432B7F2B612ACA2AC4289A276E278B29C62C3E2BBE2BB12B8E28392AB42709277E27DE28A72A3F2A162AED29FA29BA29EF253525B62798290D2AE9280427E02565267B26B329882B382AA92AB62A0A2A1C317D2DB1257D230323F523F72256253A24822539261826AB26BF260528902AFA287126FA270C29D82B102A102AE02BF82BBD2AFA2A7B2A652B3F29A5270D2ADE2B6B2C9B2A932A32292E2A0228982798265D28F5297A296B28FD28D72618287126C4268226EC275E27F12923281226AD276B27D1273429862A972A672CDB2C9F31B02C64276F243E245124EF226D254323DD256B258D22BD24892731276C278D273C264227DA275A297C2AE529632A7B2BD82A712BE22B4F2B1429F629432A992B1C2C552C812B5329E42BE42ABB279424C228102A3E294028B526262679286527C22710270428EC2A022BAE29F028AD2769279428F2287928752AE82B092C3834342C922766247F221A23DA213422E622512226230624E123122504256426A226E424C323EB26D02556280828B3291C297327B4291228D9277A28C129DD29C52BC12B4A2DDD2B5628F22997287729B8255A26EB285B285A26822787284C28FC2732261328042B2A2AD52CDA2BBD2B482AD72A46276D275528F42AC42D692C5C35902CC7272024F423F122B5218E21BD235224352362247F259F231E24B52535253E23F423B824F425F5242725A5253F26D327C12903295F288128DE289E296A2B562A782AFC291E2864282A2A792A982762273929D12831296C280C27A429E2291B2B19281329AA2A1A2BE929D22A062B4C28C0292C2995279129CA2C6C2EA7348C2B4A27BC23E5234423592341210324512428237122C22399237C23E523EF2450237423C323ED256D24C923E2265826ED272C28EA279D27F4258A2602278B28D8275C2818281E288C288F29B8293E2981271428CF28B6280D281728F6287629F72AC128A427EE29BD299A286D274D282D2AFA2BFB297728CA28232B982C9533642FDE258C22DE22AB23C521D222042289226E2557232823EF216D219423D822C222CD242F2255243B2400244724EA25C4256326112668231D259124572499268626F92468240726622678287A2838261326E827F2288F287F2904286429222BE32A17285027EF2663289626FA257B270928EA2A3D2A62272929D22AD62B1635362D50279A220C234E21B022F521AE22AE23A223B924C0221D22D02372235C242B234724B423DC23AB223424D625B2240F25F226682567243D26582380247A22A3258C24B0247A26C424EB2678286F264825C925AA26AF28F028F32753289C2A972B2F2922276127CA27F5261F276D27B8262A2AF629CF2845292C2BF32DB535EA2B2D25DA22452047214E2248210D2253217E228C220023742287220424F824462354247223DD23402404240624272424277F25E425CB258125B224E123A4225B236B244F25F423BB238F273027CF25B6250827E52522282B2888277A298F2B8C2999273326BD264F25F2256B25AB27212849282C29F5280427192B692E8135ED2BC5258A2293232024A8232A2257245F23BB23BA21C022F2222F224D24612466230E230C248F24E1225724BD230C258B233226D625A926AD285A27BA242A2670252724042642251C25F126BB2847279328BA28FF25472593275B27BF276428DA29BD285425C22480248625B4262C290D2CC02BC42B722AB92A962A2E2C4A36B12B20255D222124F2212324E8222F223423C3238F235722CE22832097227122B2222623E723A223552415232B25FB23952340256D24C327AC289A28F7253624712605281D276C26252687271027AF26D7287F263327CB25B8281B2BAA293828652969283027D923CC247C25F326CC2A512CC02C232BD429D82B812BD12ADB34512C03273124AD210722C520C923CF2261214722A7222C22E61F632285227C23FF220B23A3237924AE23572441248A24FB24CE244E24F726F42758273D27E025CE27C6290E2A8028C527A528FA288128242930289326FC263B29132B582BB527E92882279424A8231B25DB26AD2537297729332C4A2B632ACE2B5D2BA72B2934D72B4D262E2422239022502266223121DB2153231422D2226622B821B321F2217721B0239D23DE220622EF211B27F524CE218E2142231823D925EE26C82609283B270528B6294D28BB26642628289128ED298E2745269E28E129282A902BC62AC329A42811270E23ED2418263228BC2A7D29442AB92A722AF82A682B812BF731462D0B27E423502398220522D4227E21B42399230B22FD22C0219122BF22F121BB216321BE239222D8238C229C227C22CA221723042284241C24BC2442261A283127542852296D28C928B0278A275B29862A68295A267D267B27AC2827295B2CE62BAC2A3A2966271426CB26D128FF2A302AB52763265D27B4287328F9284632692CF725192302249522BE215622FA2260223A217821AA214821172316231421522102212D257323E821E321812226233422DC213E2359235C214722DC23A925A7265B2755260227CA2793291528A828A529AD28DE25AD25E2261628B22AD72B392BB229512A1E28FD27FF260429EB288127C626DA257725EF2468271328FA31A62AD02535223B202922792231225C22D12286229121F3212D21FC2014229C223021812291230E234A22F2231522A62328230422C6211022A3211622AD222D242F260025782566265326EA264C272E270829D8279625C4243D25A424562766289B284B287226A324EE252D28AB26FE25E024B22624242D22AE246D24E0273431782B0625D821AD21BD21962193223321BC21E821EB20D6203F2178213C223E22DF20A7203823312332235F230F226A216921B122B8227821862273212A222D22D1238C23EF233D24322620280C286F250E263827BA25D92304258A2353248B253C27C125CF25BE22E7245525FA241225EA233B254125D0237323DC2429271730602C7425A52211211E238D21A3207B220A210922FB20F9209920991F881FB8200A2145223423DA23A7217721E6231A223120A92016217520DE21D520512160232523B6225822E621F52469261B265F24C82401265E23032381228C22CF23882329251C255E25B2236A24802402268825EF2353245924612287238D252D2570302B2C8C245D23082125212421392185213D224922AD20FA1FA11F032107216B203421AC228B213723C7218A21832279209F21D3201C2045201C214222972114220323BD21C121EE2144238C247E246C246724B125A92388227B23C42242228D2320241D26CF26E2252226502514258225F1254C246224EC24BA24ED2564271A32142C0626CE23FA213622E0201221AE20BB227621992173213720851F7920CB216221FF21F6208122512135213A23EE21332150222720F51FF021A120892052208D222E22A520B7209121DF230922BC238D250024FA236D222724552389223824E523B825B727532742286127B1245526DF2657242926CC2416260228892A3734FC29C1240121FB21CD21991F0F20AB2043211F2189210920A21F8E1E4A1E65208A203621AA217421AB200A21E820E621C02016202920A620232202221F2152214C22372244216D202C215E23DD2214217E2471253D23CD218F2317227721BA239925A725F6275F28DA282F268025FF25F4258525B02545256326F9267F2AB534A62A17243822D11F95213A20B6214E22A720252178213C21EA1F181F9720932090208620E3234F216321951F2421A4218120B11FC0202A213921B01F0A1FA420D1217020EF1F8321AE212B21F023E922E82587231623B3220D2391222322AA220A231725AB282229E22A4E288C260725D0264427B4283B286A273727052B4D35F12ABE23FA20232235211E21A61FD32253210B22702260239E205B209C224122B12093211C2066232822E11EBC214D220D22C220D11F682030217520071F6720531F09205A20D31FC51F0522F7211322A924E62206237B243A2454224921672354235F25CD25B926F3274726F6256427B524FD25F8265725F7269127872BB8343F2BA323D522D920C1212F21D5203622C721002020210C2164220921E62178228D201621E620D12266228620F420C91F011F072167202720E11F3920F11EA21EDA1FC421991FF71FF920A61ED8222B22B3246823CC227522DB225622D421BC227D23DD226D25B8245327F2246E252F24E62588258A27AD25F72632283E29F7338929B2249321B421621F85217C20601F11217921352282203720A3217720FE1F642140210F22C0210420DF200E2136203D205F21D11FA91FF71F0A1E8B1EC81E211EEB1E071F781E731F8E1FF41F0921A823A7247023A2229822132382220A24EC23B4216C2100239A25E82475242624D5242D25DC2536257C253026CE28B033142B58243D226B201B205220EA202F221B21F51F8421F7200621131FC91F4420581F5A2217222D222E21E3213320AE22A3212D219E1F8E20CD2069208D205420E41FEC1FFC1ED61F101F6B21B321B222EB2102243223F3228A232B228C2253230A230022AD2296231B259D239B232B247B24E523B6242C253C268C265526C9310F2A2324B620D02059203C207620CE1F4D218F1F11208220AC1FE21F9C20D9214221D32045209420462077209421D01F6F1F801F401F321FFF1FCE1F021FFF1E081FFA1C891D561CB71F961E2621F62055210A23EE20E020E2212E23E021272358224E2137211122D5215D212124F3234A23B7228F23992371246C24E6268D31672BE52440235D20881FB9209220E42047212A2148217A228820B11FAF21CE21322109216B21F81FF420E51F7B209B21E92047212A22A11FED1FB01F111ECC1E451EF41CB21E711EE81FB31F5F20F91F1A214621242120231F24302233224C23B623BE23FD2087226E239A220D22EF22EB216B221623D5227D24F7241427CD30B42BA723BA21E8207820CE209C20EC1F9320B3209F1FAD203F20DC1F1A2049203D206D202321422082204B20FC1F0121FE1F0920971E6C20731F271F5D1FF81DCE1DBA1C5F1E8A1F57202C20881FD4209E216820802019236A2185218521DF2019230823BD228221EF213F22EB2132237621BE21A523E623922366255A25AB30C6293824A222DC206A204321031F5420C620DF20B92123200C22DB20C9219820F020F0206A218620E320F91F10213A232E1F69200F205920761EF11EE31F121EB31DE01D9D1D9A1D831F6B206B20A31FF22156208C2076206221CC1F0B20D822B3212122822107214322AC22DE216A221822A0206C22B81FF9218C232A254430B72AAB257E203722F72012213F21F11F60226E1FB31F3E2182224F21DB204E22F41FF4206221FC215F205420CA208B22C920F91F5D1F00205120B21FDD1DC21DD61D571F511E5A1EE21E3D201A21B51FA820E221F820C520F5219F1F95206D20AD22BB1F1820C51F2321C41F5322BD206523CB205B211123CD22E6232525E72E8B2AC425E0210E21D52020219420C520FC211D21ED20BF20D4216B1E881FEB1F3D21F821D11F8622502024200C21FF1FF91F671E8C1F741D7220A21ECB20461F961FC11EE81E351E7420611F5F2085201620F61FF92001200A22301FBB20772017221521C6216C21D4221A20E1211222C221DE20C821892268245A2449255B30562C7925692124217F213322F91F3621EA216F213C2212213220702171211F21CC215222E1208522FE1F7B1F9320D921EE1F76200C1F3B1E251FBF1FF81E6E201E20411DA51D171F521EC6203D219C1EC421AC218120F91D0121D8207E22B62082214421B22146206C221022F7209120C1226321C8221621C722C721B423B72ED32A97241122CE203820AF2025222321A422FA21EC20C221D22170200422AE2036214421B721DC20062052218B210A210E201F212620E31E9F1F30215B20241FC71F6E1E331FBE1EDC1FCE203C209E1FBC1F26202A202C1FF31F4A209821E1208F20C2213D21EF1F9F205520D11FFA217721E6216122DB20722266237F244A3087290F23B021302131209821591FAD20A3226D219821EC200C2187207A205721832097207122BA21851F971F13206020481FB520E41EC420D51F001E67204A1F641E511F9D20CB1D13207D20911EC61F1820AD20841F89206C21BD201E200E1F30207C208C20671F7920D01F4720F2207720A1203D22A520A32298221624152ED02A1524BB204822242267213B21BA21DB22422088206F22A320992127215C21132289212321FD211E21AB20F32144214E1FEF2062206E1F631F4B209D2088200B20991F951E441FE21FE81F64209A209421DF208F20AA1F47200B217F1FE920B320F71FA91F262090202521F7203F23DC203F2176210921ED2185225725692FE72941258C23DB20AE21BA219E201A206521FD210F21222235201621C9200223C6206E21B9221921BE215A20A4210D20CA1F6821651F55207120D71EA71E451E541FD61D071FEC1EE81EFC1EDD1F2920D5202A20AD1E46219920BC1F0220832033228C202F21A321902163209B2082205B213922F11F8B214C223E22F522D72FDB2BD8251A22E220FC20CE20AA20C62016214821A61F05206C1F9D1F4221951EFE1F8E208720432111220021BB203F1F33204D214421591F6420AF1E941F4120DE1FEE1E571F171DF01ECF1E6D1EC01E75202A21242005208C1FD71FD91F9C2015210E21C0205320F5215520DF20662209204D20EB20521F7720C2233E243830372AD624F721F420C520842121207D221F1F9C207A207E20EC1F56211C217E1F221F612107202F21A11FAD1F5B2039200B1FF820B820881F6121F91FA620D31F1B208C1F921E8C1DE61ED01F201F391F351F39218C20EF1F3A1FCF1F1C201E202D21AD2061208F1FCB21181FAB20AA1FB91F1B21EC204A203F224922A024982E5F2A17239A21052322217A21752029212E21F71FC72179213C2036211A2169211922032029219C225E219A1F0A21D621BD1E5120AB1F381F861FA91E0920851E941FEB1FE520601EB11E7A1F2B201E1F2A2021225D1F821F9521A32030211D21951F2B1F322043207E2147219D1FE52057219E1F352023204320CB214423B32CC52A77256D218721B2223E2025210021862122229B20BC20EC2194209A1F35224C2222228B217C223120E71EA2205221A21F261F0620DD20C01EE01F761F291E9B207C20331F871DD3201B1F3B20A31E1521D920151FAA1F3521F31E6E22321FB5214421D620401FAB20F61F902046227920C41ED91F0C206F211922E923712F772C4125BF21862159238720BE217720622108218021FE1FBC20861F45203C20B4201621D61F25217220FD1F3C2096216521DC1F511FF01C481F8A1E63203A1F4C1F1C1F2720941F911D6E21F21FAD1E8A1F2020101EFD1F0F208F1F221F5E202A20831FA020721EA72077202720C01F77206120FA20D7202E218A217623902F1F2B492589230021B920D120BE21102197224F21EF20E320EC1FCF213622581F932104216C21522235214220ED2055209820DD207E1EC81DEE205F202820081FF31F31215E1F601EE31D831F481E1B1F50203420E11DD71EEF200320AD20761E002100215720002102201A20E01F80210220FB1F7A20631ED921B2220B25EB2DD12AF824B722E521D92092215822F621F221B52049211E226020FE1F0321C5214F210E202E203D2175213620ED1F4D201C21D51F1E1E4E1F311E50201A1FD31F9A1F771F92204E1E8C1D0A1FD01EC11EAA1FCB1EDB1EDB1E8C1F9420A71FCD21A920251F202035218921FA1EB71F1120DF1F071FC420CD1FB1213F231B24882D712AB52539219620BB1FBA1FC52139211A21A81F5B21E21E7E1F8A1F0920E51F8920D61F6C20A0205A21431EAB1FA1229721C320051F4D1E5A1FCE1EBB204521581FE11EFF1F461D2E1EFA1E5B1E021F651F1820EA20BE1EE320C61F6E1F121F1F21B21F831E661E4A209420321FFE1F861ED11F3F218220D22029230725182EAE2B6E258823EA213B22AC2114212E21F7210821BD212320CF207E1F7A20C61FFD1E7820FA1F5F20D41E801E951FE620D120941F601EE41FE11FD21FA520C1201E2176208A1F8C1E1D202420F21F6A1F2F1F2820811E3120B5202C20001F38208420D41F65208B207321F81E0A1FD21F4021BA1E2C20F91FB920A720BE24742FE12AC5238121E0213E2129203920E521841F65204820EA1FAC1F5A1EED1E5120CF1FF41E28212B21E71F321EA7202620871F4D207520C91F771FD41EA51E6C200B20E720401E7F1E581DA41F641EAF1ECF1E651F6D1EF21E9F20BA1ED21F921F8B1FD91FED1FD61FCB1F34203521E11DA01EEA1F6320F12081213E237A248F2DE22A092472205B219B213420342103211C21E0219021791FBD1F2B1F2F2042205C20E52066200120AB20511E0821311E3920A620061EEE1FB51E5D1F211F05211B203E1F851F951FAB1DF01F991FDB1E7721D120611DEA1F311FCF1FD41F7521C01F8B1DBF20EF1F6E1EA81F931E241F221F422018211A1FFE214A220E25DD2DAE2AE5249421AF20872186218A200F231E218C202F202820711ECD1E5220D021F81F8A20A1226A1FBF203920C520541FA0209421821F6D1FD51EAC1FA61E23208C1F731D691F7C1E361E1320B41F881E9D20A61FCE1F961EFA20791F3322F11FB51F661FFE1FC01EA120DB1D8E1F742004216F1F2E20AE20872177202023972E0D2CC924A9201422CB21E52118213A235422F920F720872116208D1EF520BE20DF2160215F214D1F4221E91F9D20ED1F7B1FBE21C11FFC1D521F6F212F1F301F601E341D601F451EA81D911F191F6B1EA2202721271FA31FE71E571EF41E691F6E20451FF01EF11DC11F5A1FB31FEC204C20E220901F291FA7202E23112453300F2C2E25F0225F20FB224123CD21322217236D2266230022CE209620B121E91FAC206422F920681FAE20C11F262171202220DF212421A51F72207E1EFF1E241F131E161E111D7C1E361F741E2D1FF720032128206020D91D6E1C4D1EAB1E7C20B11F24208A1F4B1ED41F361FAE1FE4207B1F94224921261FA01FE322C224862E ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 403F ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 0009 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 FB28092311230221A821FB20D51F3A20A020BD1F671FDF1EDC1E251E0220441E711D861F2D1F3D1D1B1F9D1E7620DB1EE31FD81E3C200D20B51F8C1FA6214D20081FB91FC41E1B1DAB1D7C1F591FEB1FB01F7E211A202420C120DA1F391F1D201221CC205620D71D7D1FED1ECB1D5920741E092123202E20F71EA6212523402ED42B6A242921EF22AA22ED208721E021AF21B81FDA201620DF1EB41F791F171F7E1EE11ED71E711EA91E5620CF20F021691F3E21E31F2E219D20B32127227E20B520B5219920FF202D1F6B21C51FF41F7322E62103214321E821C8237B222C2148217C21D32155206721612155206320BD1F5221F321B6215F228F22CA24142EBB2B1F25DB23BE2292210221A1218B22A7200A2371224C22AB20FA1F65205F20602016212520101F511F2D21F720AC20D121452237219D2135220D1F822157231F23FA2397228B227D205F216C20342079219922182296232F248D213A233A23212300234822F22010221622B6213A202820852085239021752204230026BA2FFF2BEB275324D521E3218E21BB227521F320922064202220AE20DF1F61211F1F302057201220F821EB1F5C20B51F8C217A2198226C217922722115212F20782235242424F2240B229A2100229420BD1F27215022FD225D24A524B32497254125D8254D2437245E236C226F217220EB203C21682143227E23EE216A2339251B2FB82C69265722A7218A215A226D21D121EA2147211D213C215A20C01F7521E620911F492191206E209920F42063230120DE204524BA21BE1E4E225D225D22FB22FD240626C9251B23F723BB232622FF2287217723142252230E258F26282692255426E5256426222414252C233D2359225022E9214922F9200E221924A0240E2E062B13268D22DB23D720D32264213021B322AC213A22E0229020BB204521A821CF214D21A9203922E620E5204E22382343218E22EE211022302214233E23BE24A02597264D26132592278225BA252D245A2382234D238923BD23FC250C27D727FA279427E8253126B2255825D523A5235022F8225D243C233822BC24E2257F2EEF2AF723CA2273228C21C921F522082285218E226C224621AA216D21EA22CE225023D8217E22BC213023D022B1215B22AD20302193222A23B5230A24D3250326B025E62620274D27CC27A827472782250D26D4264424A62318240D250F25B126F1270B262D270C2665259E24F6234823F8233B225223B121E7228723F823BB2E632B9425E522E9239D22C7208D217C224C222A2365210822462333242422582299238623F1231B243F23BA2169225024E621D821C422C0224F24912556256F258C26F326AC27DA26F827EA29352BA727B6294E29002785244F24612224240C2512269926C926F525BD2561244A23A6234E23F422852283215B234A237025852FEA2A34267F245D23DF2374223F2185235A24DE236423AF22F122E022D2231D221423BB2432250F25C2240923FC206E23B121112391217621782232258C258626EE279028D6278C2766276E276C276728492AFA29032BC227ED278F241B23AC2323251E2545277B266526F6231622F52212249722D9225422922221241F24DC2F4B2D9C240D2342238D23EA22CA236823EE246E2333258C24BD22E62346244B242325A22402268C2546251D259D2234236B21DC2371239C214E241C237624E026502889299B28832877270F291729F12709299C2A4B2A69283F250524E7218122D926EF24F3239025C3244524FE23102374237C2491238123D822EF24A025E431222C8E289B256B243525AD23A423A323FC236A244826E324A924A2226324F3246D252025DE25982643247425B6236E24582107210721EF20D921FF212A23B52430284C289328BD2977285D275828B625D02602263026BA2506251A23E721F02232230E23EF22CE238A247C229821FD230A248623D423332245245925B4256532942E7A282426D127BA247A23C623232315259E253D25CB24C1232D247624D3255C25B32554265F29C226D627362487235823B822DF22DD21CC20C420E022142458250B28AA27DE280429FD27BB2731266126B6241C259D24BA238B226F213F2288223F234C2442220625F324A724E5268B266426D3258225D2242C257929B633C030832B3E281B2605253E24052487226124AC238623C025652487264A26CE27FC267026D225AB284527822684249B26AA24302417237F219E217822D821FA23FE23F4260829D12821282529802A3A276E247A25662350235C245A2444220C2451228922EB20AB216A231A253126A02885281628A629632754265A27C42ACE32CE2FC82A90281027F126D723EC2332247D24CE23D9224A23A0234825FD27DC262728D52706276A27AA2644258C24C424E124382421222121FD22A1206320F91F4F2316256A26FD26CA28A428B82847258126E8251B2352228122C0236F24D92412255B217B213021ED230B2315241D279028AF29EB283D2638261F2763295434142FDF29D3285E265D272C253326B223BA25C0224524222532236925382778296328A829622A7C274725F023B6232424F6233922F720E6218E214820CF2040214324CD242726232726271C2645250125FE235E24F32376222C2395241524E224EB24D224C92341220724892365244326D627BF267027F32373246B2644276430EB2F602A92273E25E825DB2609261D2646246525C7254024AC22BD25FA27ED29C128B628222774252126F22557226A220D2101225B2288210A216B2142210A22B924B225FF266226B8249E26DB2365239024FB20672113220C24DC242326FE26D52737249224CB22D823D624D422522569255226E0250D26FC2484251D27CF2FE92D1E2A32296B285A268526CE2612271F266126F627F525F824EA24AE2508274C27CF25A4253F240B25E02238239123C0225923DB22F3203B22F522FA22352580279D2AD02B0B2971252522AE215F2262223B22FB21D8232C27B626E5266A2810286D250E2595229922702292229421E024052582256226482648267C28AE31092F6929E7289A25E82617280E2886283F29B7290D2936272025B1242823BD23DD238D244925E82256226023AE22EA229D21ED233A2446236D23052241243926542A3D2B31299326F225A1239E214D20B421EC2358230723B0274426E025E425FF2743248524FF21A723C5217E24E723352572244E24EB2434267D26ED2773332F2D802B7328AF28FD283B29D52ADE2A372B532AE8294726CF24F8236D24C1224A23782505239325162486222A24A2250323C52499249024D423D622EA24B326D629DA2A3429A224F524592320235920B1223522A223E22483253C256E25B42571259226452784238524CB22C0215221FF22D1224A231C24C427C227EF29F133532FA6280A28B229462AED2A3B2A172B1229A9276626D125AE240D225324CA239B23AC2067231324B822F32201233C2494252C2515233D2240261523A624122421277628DF25AA242923B62230216D22DD22B223AC232E25FF2700266A25A925A426D225B0259C258125B221E120BD23D32201232024DA24A327F429572A3933A72E5629C0299F2A2F2B622B3B29EF2760274526AE26252461220B22F721F222F421AB240F2379221523B82546256A253B26B924622569247D24D9242C24E5254426FF265925C52489229022412505237F255726C1267527ED250A276C24F323BE24D8230025ED24D625182419239226EB23A1249927DD25FE293B2B2D2ABB33172FB228BB28E4272E28C4289527412662261D25A3222B246B234A24DE222A23C523192295243923DA24E7253227E326C825F425D423AF241E2641245C25FC2321250D26EA24EF242E257A259925C126A1286428C226F2261D261725CD221C23E5239A257425D6269E274F2517254324BF2418288E275F2AFF2BE12A482BA433592FEE287826D5264A272927342673241B2524248D242824DF2336228A248F238323772233238321F92271257A27C427F926AA26E2243A25852530231624DC239D22C8235724C624C024C3282728E82612295A281827C32499245D23CD22F523FB244B26A1299529002BD52AA02729265C274028F329B82AFF29EF29C329CA33CE30E4297E28F625AA256A234924A524372385223D232324EC21D2233E26F123F7234424BB22AC231824A626242A732CAB2A5D280525D825372524235F23A0229B22C6231B2244212925F2264228482810281526A526D124662461233423E224B6235D261129732AF92B39289326C5267C28E3287C2A302A882AEE28152AE4332D32022B872765252125E923EE22292315256E23B5251A25C6235124702484241624AF233F24B42677240925E3286C2A792A5429512721256A23D722F5216B22DD218E229C22D922A0234E24642799263C26D2252626C92592268F2430248724D426DA26E228972ADA290328E424F2262B27CF27EE29ED2A352C042C672AED33FF30252B1328D7261F24B4239E238B23E2232623AF24A8256B25CD26B227E2266B272424A42517261B262E274F25182864289A283C274524C2246223BB23AB224E23B0222D23AC2260216D23B2241D24EB269C26BC2589254E283C261C25732606252727DA2807288929A6271A26B42663267A252427C0280E2BD62AB62CFB34A431122CDB2876254C2558248523D123D023DA23922646288E276B29CE291D29952895271426DA28D927D425AD24A22687259825F7251F2350230823F7235B227C23F4223E24DE2177231022632393242824B1269A27872816297C29A226E9261D25EB2554284E29752A7C281E274226D22466243426AB273A280E2AD12ACA331832E02DA228192869259724162496245B247424B927BD28C62DDE2B572BEE29F62726286328FA295C2949277D25B0242C24342376213122D9218622C022712349249F24C923FB213223E0211B232622D023EF24032724293A299528E42493245127762687273C2AC02B942A6929BF2634251B23A3245C2514277B27302A23342E333E2DF62B1E2AD426AF238724B2241E26FE25B425FB287329112C022A282AF129DE28F3295929F628AB275325D22358223423D520B4202D22EF22EC21F423E22451250525B822F8220023652141221E24462465264727DF287C255C25922643272228F427152ADD2A2D2B082A7729CE25D2245024B823AD2474279327A1310F331E2D9628BE265B258C26A624EB2461272C267228A82609275126F226C2276528B927CF2740294B26B9258C23FA24882166213A219420802193214A22462336231523E52367239522502338231F24922536259B262B24C5259C24FE2417262D280129802937299D29402A6128E9257023BE22A423A62229232F25C425D2304D31282B472976270227F924EE2411279827432A4227DB268F24CE2416247823282583253A260F2506232B2240244F239E213321F321B31F2B2104227E220C22CA218722D2225C22CD229A22DE24E72599262828A8233423CF236C241D23CC243D250E287C271E25072871281E28CC25B8223621BF21BF2133248124E924702F21305D2CAC28B028A3272924BA24A6253A2A562CFD2B8A28A8246F24552622262824632427242124E920A0215A2160209E201F2248219A20B6213E202F22C8217B2480230124AD2145230E2617272A269127F327E12322235F23CD22C8231023CB244E25FF232125FB241E24F4230B23E321092383214F22F721FE247525832FBA2E9528B7269F2501269C252E275727D128C22A612AFD2738266624D223CA239B2378214E23E7214D21AB21DF2001204520DC21D321F22148212E213A20E421D6229F24AC242E24FF23DE275D276927CC2721278C24B8225F220522962244210C2332231323D322E3240C24BE22EF2195225A22B32377228B23AB24332530301E2EDE28CA256426D525A327E92580272529F6286B27FF2571242224BF232E239821E722B2210B22E0226B214923A42140213822AB22D61F7F2153221A21C421A924B425C725712590270A2628269825662746262922362225222F21292107211321FD21F42289238A2338217C20EB207F2323244E237224E725BE258A255B31462DF9262C24F725D827C226272894262F2818269F253A247E24942238235922262279227A22BB225F253F240B24FE243323672207240D2103211022F1212B23EE233627B626DD263628F72754262B246125CD2495227822EA2097218D22E51FA521FF20C3200021F7214D2350228423A2237E25B82782271B2745271A26A430FE2B1527A526BE257827A127AA27C725EE246024C124EB24A023DB226D22AC2234248C23A0223825C1241D26E727B926112497245C257E22BA226D23AB22A723B8233825B0280E275C27252A7529D424A823942520249D21B222F7222F227C2250217221FA225C24F324B6231C223E248026F428862A7D2AB5296F286826E131192E5028BB274B27AA26A724FD232D242023A7237924B0223222CA203522B9221424142561246D262026512773277528562689259327D724C323BD24502366244824DE25D22576257326AC289C266C24E6241824DB222C21EF21CA1FD420C1204823FA1FB82296246924A224F72507288A29312BD42CCC2BE32AF5276F266030882FC02A19296927D22682256B2514258924B9235B2420220021EA24ED23F2237126F2257F2644274828CE25FF2793290E29CA277A27EF257625FA2422252027DE262027CF268025C82649260E26C423F224AF22CD23D4215421F4218E21EA20F421AD22B822872338272D27A229242CFF2CA02BF92DB42B2A2BCC299329D932BB2F242949278226E2249723EF22882231258E223323D523D9236324C325DF25662968290229C3284626322603282927362A70297C263426C2232024BD250326C8271E29F82859248723192415233F237A231721BA21CE2054213E2018215D22B722B6227623C524C026AE28D529EA2BBA2B8C2B9C2C8229F62B5A2B612B8F31682ED827A7250424652238224622622265229A227324BC24E323B5236B25E0266328B22A842AE828552749245325C9278A272327B125C3247A23BB227E242C24822679275D27DB24BD23F4220F22932132221222D220DD1F0C2229205C200521FC219023C5253F271D2939280228FB28D02A112B7D2CBB2B0D2DA72C922CA433072D98282E2599258A2412245C23452392246C23432277233E2588273928CA28F72B662CB9286B2936258224F224BF247825C2257A236923CA24CF211E23D12467262927922701265024C023F821052247239522DB21CA20D6206420ED217A237B226E246A26F028992B842AB32849276A2724284C29962A162CDA2BC62D59344F2D262685223C2401229822B12276230923732269234F2486249225CE27BC28202A892BC12AAF274F25C1231424902495248522F321EB20F82184226B22D5246725C927292A8626CF2480251C25FF2232227822E22200233B236721FD204A21F9233324D12484279D2AD1297B28012633255326A9294B2A792C192D102CD831302E5627AE2517245F269821E423EF23E6225722002305243624BB25E228E329952B7E2BC02AF9263324A4232D231D247C232122D321F322BE221023E4244D267F2705280B2A4A29A028DD2604267B243E24A622BE2340212422FA213F22DB212B237824F9243F271B2AD82AF728BD26CE244F267C28B52B542CE829B52BDE32E22D24280926BA25A22558251123C9238B23C623D923C423882379266C2666282F29222CFD29812661220F23A92328249421DC2487235821CF24AE2454266C2A542B322B552A0E284A272826E3268C24452463238D22B021D8224922C322BD244C239423242592265E28182815275226892592258C27F2272E281A29D52AFC331E2FBC29D02709264E26F925BE225822442516243B24D2236422F722022766284E29712B1A2848258225AB24A4243124EC22EB215322CA23892439261229F629B329652A362A2327E526C626CB249525012483259423F223C22126236323F4242C2645266826A726D027EF248B25DA255024D5248D2639270D2991291C2BE633C32FD929662789262A26682402247C24042598265025B1243324E3247326D3279429EB2AFF288327F72320241B253E243A253024D323A8248225FF23172819287728AE28E52855270C263E24CB25BF248924EF256A245A24C8242F225325AD276227BA26EE26C624F326B1257E24E925E924CF241D279D26AB28E62B9A2CDE341230372B022866252226452507256C248F25892581261D2401234824F925BC276C29532B0A266C256B24ED22E62346250625C3253226EB275628DF269C27AF279F26532529274A276926CA252827EF246D252025DF26D9252A23C8249F25AC264B264A280D26DA257326DC2440241C27722592248F2603261928212A392C5635BF2F4F2997272A2630246C253A232E243A26A9273626C6256724CD24A22458268E28F026E8259825F0232E2393254425D6245D261228E828D828F92876266E240E24522450273327AB27B5278E267326D026CA274B267F250D25F62399242B26552749299B2956275D26B125CB26DD262F268826AE266E260328C7296E2B8A34E82E4929752685254B25B3253C258C236D250B2788286D26A525D42404258C237C264B238C240C24F722E724FC245B274E27A126D925472739290426DD24C8230224042550296029512A2829ED28932763275B289E258125B8266F262525032654265426712811276B27DA26F72502284D2881264025B025CC28702A622C0A33E62C46288B253D262027EF2519236524792600261526722798260226A82412255322A9226A23522591255424CF2486249526942793274F28EB27B52615266425D425FD265D29772B5A2B302B742AB129CA279A272D261C241A270129DA267E24DD22FE26AF2642281C274C267E25892601270F27E2256D25CB28EB28022ACF33902DC327E426A6251827632744281F26D5259D249B2642286B298A27F2248A2285232126422443260524FF25B225B4260A245F248C26B72635285A2A4A2AF0276325C1265F283E2AC42BFB298C29C828BC28BF255925482629283A2ADE277B263525B32605263726FB27F6262226812652253C24EF249D25F82957283F2A9E32C32D3629AE27EA260E278628BF2708269F26CC251E279C27D028C427DF24D122DD21CE225F2319274E25A5251A27732746244326A525F7265E2AF829792B402A9629C3292828F927A7286729CA28C42690267C26EE24D4235D25732608260225B82412254F2592242E292928DB2527255D240E246A236423F0258F2865293834982D0D2896280627B028FD28D427B924F825C32610272B29022BE027A0254B237C226124C22228262727AF26D9270927FC262B243426B826C429302A2F2C9C2A2A2AF92A7C293828A0289A27E8276B265525D524E522C22315261E258D244425C724FA24FD23D0249C24DC240D260325D5225122A1247223882577266E29E236DD30C228B227BA26E527A3270D269826BB240524FC26C6289128F026EF248925DC228B24312508265224E7260829DC291F290D283426A0278428D529E92B212B732D7E2C0C2A042823266726AD2449244025D2244D23D92447244625C5234025EC2682240023352453266B248025AB2615243A22FA23C7229625BB27302A03359830B32B6E282F28462872276925DE24F722492437278C2A75286128B724CD23652357233925A0255C27F4257929362BCC29F729292C83289829362B8A2AA12A9D2CBB2C222BC82AA1274824CF23B4223724A6251C249C24F924AC269325822660281726CA244C2545263725C123AE24CC23F323F1254224B52551289E291B33A132822CF02A012890243E26BC2383247B256324D0269029D02AD226C824892201258525AD2667292928CF27EE26A0294B2A742B292A792B3E2A942A062B172A032CA72EFE2B4E2CD0281F2512221222AB23A1242E238324DD25C9270828C527AC27C12617272424342762264B24CF251F25DF248B27EB24BB249828CB2BE4344E312D2CB6295D288024F1231C231A25CF22452277266D25ED27D92518266A24212603274A2821292F2AAA25FC267626B5293C2BB32A8929F828DA2738296E2AA62B8C2E8D2D882CB429A325542530235E234625DD24842575289229262AFD283C271F267E262526A5262F2714280F278F241E23852690242526E326D62A36351332DA29EE286626AC2594225C24112379236E24AB244524842573259F262D2558263C27AF276729E1275226D1242D26F0260228042A352A6D289326C727D328642BB62D522DB62BBA28B624F62401232E25AE25E0268F26742A4D2AE3295629B32753289629942750297B29322AF428D0265A27D5277326F927A226122A39352530BF292B285925CF23C5239223F623F523F8239A2459245426DA246B27D9261626F02503274B2884272B2738280D27F825292682293629162AF228FB291B2A502A9C2CD72DF82AEA293028C2242A2397243525CD2667297B2AAB2A9C298B277B27C529D02B1B2AEF2B3D2BBE2B802BCB27CE2881266624CE25702520291336642F4F285B27D22508256F243E236D232B24352324244223A92487261D29B027DB26F42653269F2706278F281A29C729E12A6628212611260429302BD22A582C692BA62D9E2C672C952A7129942752257B25BB24C1290F2BA42B7A2AEB279327D0277D281E2BFF29F32BC4296927B529EF28D326FC243324432474263229CC33922E0328F42568250E258A243622972378233F2371243E243B255325F127F22ABA299228B5275027BA27552A1B2B272CDF299B270627EB278C289B2C5E2B332B352CE22DF82C502C162B06291D2748258D254F27EE274E2B962AB129E329ED2824297A29F729132A592BED280B27212613269925F324CF22A625BA273C292033A42C2F285D243824CD22FF210C231F238E241B23232406236125B227F02ADA29CC293228D2274728EB26D5297A2B0B2BDC295429B32683262928F22A7B2C542C6E2D812D442E612D442A0329BF298E273B27BF267A28DC2A3C2D6B2ABB2967292C2BF12BAC2C492AC52A7A285E26DA25CA242825A2260B271928222718298C31C12CE927E2269522B422D222AE226721D622A9233C244B240425D528FA29502C5B292228B326CE28EF2585289B28982AA92AB42B3C28E62548275529F62A702CA02B282C6A2E042AF929D429032BE628C129A728E6260228272DEB2A9C2A2C2BBF2BBB2B542BF92B332B8F29BF278525D7247923D029EA273628BE2ADA2A8132732EF825BE24D02261230625702215226923F622A424EC247125D927FA2A4229142AC829DB2831273129A8280D275D2A4C2CEB2AB32B84286C26D4254A285F29732B202CB62A252AA6289D28902A4129E129DE29FA271727F5294A2CB02A9D2B722A6C2B2B2AEA2A722B852700259227242589252429BE29152A392D912A1835A42DC327C922B922B123AD223C236822762306240023DF2383246B27322A5E2CCB2970290A29882A4A2A822B802ACF29D22A702DDC2B932A47290327E925C7272C2A0B2BBD296A287B284F296028CE285F2A09290428D2253828E8274929892A732BC0281029BE2B132B4E27572412261B278D2AE62AA12B942BFF2D2E2EA036412C9027D323B9243022292335243123D122D9204D25A9224426B926642AF82A462B0129CF29B22AB82AB12AD528602AEA2A572B8A2CDE29BE294D27F323BE25A228472A66297428052A44289925FE24E4267827EE25C024C624CD2560272427B9299C29E72969291028ED25E3239A264927B02A8B2C522D6E2D202D942E9036292A842654239F228824C5220B217723F82002229722C921232545267C2A842B7C2A132A31298E2A6B2ADA294A2A29290C27E327F4270A293C2878259824E5253828142A4B2C092AD426222604252123A3231427FD225B23C525172632268B26BB25BA26FD272A267028F525D3250E27EF28142BF02CEB2CD32C1E2F312F68365E2B1926AF242F245623D7227F212E23DE21CE21FA224B24E722DF2536285E29782ACE29B228F02AFB2AD228D929042665250427E327D8255626E9262525B3248328FB29C729D8278325F3245825E225452647269D25BA24A3234523A7242123DC24E427DC2660268D2614253328EE26BE27572A272DCC2BD72BEA2D6D2EED33122CEF25232491221323EB239B227822F42232225222862192230C255F26F82742276028D628BF2B012C0B2A6E28712898254D2593255026312860272A268A248C280D291127BF266B25F623C925C0244C27F128F6269527F2252A23BC243125C2264028D62655273E26E027822688264B27E8287A29AB2A772DFF2C102C6F33022BB0256B23B421DF2287237E22D3200723EF21ED22CB2309233324A826CC235A259E285A283629252A6D2830282F28F22729287528E9269E288C2855276C2828292929B728672460251F27E627FC26C7292C2A272A5928AE297D2804266F288529282A702A6E281128A4266A278C288F268B28D6288E2A1B2C582CE32B92329B2A522504242923B9214D22C6218722AD2316236F22B3242F227D235F2662253827C7261528CA28942860280C283729E929BE2A4D2BF5286629E4278727A9277929712862283B261A271228F129352BF92CF12BD22B962AEB2C862AF929CE2A6B2B3A2B972ADB288629C428002AB728E42675275A27462A4E2B7F2B3D2BFA33D02DC4256E235223DA22AA22C720FA21DC235323FC215A248B226E23B7240E27AC2663275C28152740288E27FE28452A8A2AFD2AC52A7D2A9428D12601255427F729DF28922A24283828D229972B172C3C2C0C2DCB29242BA92A5F2D112A7829AA2BB02ADE2B922A7929F629452A462A362981273228742A232DBC2A9B2B3135602C79256C221D2215236B22C222BD227B222122DE238C23AE2309225F24B62647251E252F278F27612641265C2680286928102AFB290D299027C2241126F0292D2A582A042AAF28D129142AB82A632B002DF62A632B372AA22BCB2AE82A34297429282A8B2AD32AE92A6A2B5F2C622D1D29C827282A192C472DB22B812C6D36CD2B2726542115231C22A921BF239C227D224C22D72274235E22E9232624FA245625D52527251726F52494299A28D928D626C52868279A2610262325D423CD2660289C278E281A262926DE28D6290D2A012A512ABA2A5529F929C32AB52AE929EF29EF28ED29AA2AA82C992BAB2C272BE5293D29DD2A242B032D292C592D8E37732C5226EB23E4238222B52117224A211D23A82263240B23CB2311257623CB25A7259C24B424722671261227262ACB2A9627C525A524252550256C22BA24AA267B29502A402AE5263A254427C727E327BA279027D026EB25D429AD2BDB296F2999276629EB29382A0B2E3D2CC52DA52A452730293D2C572C432D6A2DF02D60364D2B1F2548236D22F723F021B21FE2209922B922FB235D2251239923E02470247F249C24FD24D026E5251C288B28B728C2246426A926CA25F926D524A12564277F29FB2A21299926CE23B324582799269725C42737261327CB29F02BF42B7F2813272A27942AF22A262DE92CC42B152B92276D28082C1A2CFC2C1D2E002FA336A12ACC25B2219A217E22D721322161228D226822982268225522B02250222324DC22842447244424B826A729002BB128CF27EC2768292A29E3271B2782246227552B4C2A5E2A2426A3237A2390255526C32777289A27262A772BB72A122C792A7A29F828922A732D632DAD2C5F2BAB2C06290D2864297D2DEE2C272DB42E1836672BD4246522D3215B21A5216721E220E12266223D2330226E229C233A24E4240E2543241925C82463268D286429DE298229D12BA72C1F2A54290627B6276127012A3D2B2029A125B2231225E5259B2528299929092A0B2B822B2B2C0E2B392AD2275C296F2D342B682D862D822BB82C842868285E29F929E82BFC2D9A2D8F36112A2E25A822592281219221F82168211A211523C32175224523F3239D23A123CE2331232E24052593255628DF288D29EF2A4F2DF12BC428BD288F2721270725DF26052A942BB0282A268827B2255E29A92BBB2BE7283D29662CA02C212C9A2AD029D02B702ABF2CD92B272D6D2CA72CA229E429D92A5E2C2B2EC42DB52D1236312BAE24E3238C214322D1224521182344236E22A8227022B6237B2368225B2562219D23D224F624B0241C2424275428992769292529F1283629D127EC275B26ED26F728502A862AF2285326BC261829BE2AC32B9929192BB92CA12E1D2E0E2B8429F32AB22B772C4A2D3B2C962D922DA32A1B29F629DE2CC92DFB2D9B2E6137562B7325432267223B228121E42102237D2276230023D0228C21FB22E621E8252C24E723FC23E82342235D23D9243C290F27FD289828DD27272823280125AF25F2262A29072BAF2B532A1429C92848280929E4294E29382B742DE82C3C2D112B5529672B802B762CC52C0A2BEE2DF82B7029242A612B2E2B062E472DCF2FC336202CE1258B213421A2218621CA2002223723D62229237E231323B0211323FB22482239238023D523D323A323E725F7250E28A427A4263D270D280E25EA22DB240926C226BF27EC279F28E927DB27E3258627482749287628D12B0B2DC22ACE2A902AEE2A682BAC2B6D2A752A5F2B642CF62A5129BD2B0D2D922E792ED02FE4378A2BF9256F2388215821312283201221A32107227D22C22266220B2291237E229B23EC2327245A235924CF227923392508245425B0256424E526902478242523C32538275429C128EE288B285129C32610260127B8272827722EC72BBC2A5A295629712C7F2B2B294729D6289E2AE62B532A562AD32A9F2CBA2CE32DE02E3336EE2AC7256921D621282265223D227320C5213F2248222D22B621D5214022AF22CB218F23D322472475249C225423A0235724B924862502249A25D524DD257B262228A529912A8429F3296A29642AA426EA24D026D926782A672C772C2A2A1F29082A892C0A2B6B2910299329DC2B972CDA2AA42AF62AC52B972DF52D392E7C36652CB02355225C2280210F21A6202722CB20E4229922E92162216B22C22249227E22F0212223AB235C23EF215F236423FB2453235824EA228F25CF233E245B262429BB2B2329242939291E2A4329CF274C28ED25FD27A928262C622B7128B028212A962C812A4E2AB32A022A7B2C542CCB2B4A2A802AC82ADE2D692C1B2EA737E52AFA24D2219D209020C7205E2029219D212D2167220D1F072298213221FB2255225122D92163237221F620E322BA227B2323235E23F6242F2479232F25EF26A827AF28C827A8255127F326AA273D265D263F26492776279C2C0A2A3C2B532B9C2BAF2C112BC729732BD62B242CB32B7329D028F22C342B312BD32ACA2CE9341B2C5E25D422F620AA214822762044230C2201222322B3209D202021E220B7231E238F211F2294219921E221C4216F221322DC23AC227B24702412246F246425B926AF26B926F123AA224D26C227C2245325E8270C283829B92A8D28F9263528F12B4F2C8B2B012CD12BC82BEE2B452CE328DB265E29172B302B5B2C102DF234272A9B255621FF210322BE22AF21F9217C21F5211D23812148228E208122DC217222DC214D234E22802288213023F3224622CB232621AC2293223A22CF234124A023F32494246F24B62476259C245B24CA254B266A259D28FF2913290128D827782B9F2AE22B8A2A232ABB2B522A30291E2902282429162AC42C532C142CA136072CE524CC219F2129232422332267218A220C22AA22372343222D22DD216722B5202823C621FF2267229920C523FA200021F221E621782281226223BD21C2217F239F241B24BA23C223B0259126FE228C256C25B226A6291D2B37272927C1261F2A482AB92A0B29062B6E2BBF2940282527FB26EC285D2AD92B452CEF2D7D36D32B71253E2104215921C721CB21CD217822EA222022532142218F210421BC218321A02072219621432164200B21752086207A22BF1FF52028226A2212217D21C522942222239222322387231A242F24972496254B28CA26C0279D276B25DF2741297F2A4F2BC62750292E2B1329C3273F25A526FF277527E529CA2B3E2C8236252C292661219A203E21E32051207121C522172171225F22AB201D2056223821991FFE21CD21BD202B212E21BC21B6219C1FBA218F21E020B823B0215D21532216232F234F23A1209A22B1222F239D2245250A26D426C326FD2717252F2752289C28392A702BFF2B802C8027BC26E0260A27DC26502793285A29D328E82B7936682D9725F7229C217122E022BE227922802072214C20AF21B01F8A20C22107213E2128220D203D210520731F3A1F6C209420C120A6205F22D2213423CB221F21922353239021372046238B23BA23D6248724A2277525C9241F25EB241029C629462A9F29DC298E2BE92C3C2907282428BE29D02A9C2A072AD8291329D329F933192C81250125F321AA21C520D521B2224721B220F2216E210C20981FB11F2D21F5216622F220CC21F220822069216E224E20D3206720FE20FD21B2200422C6225E229F219422B122502313231623D32562230C2781249B22412472240B26FE261F275D280B2C3C2B932C042A07298B28012A832BD52AA42AC02CE92CCE2DB1355D2C1325E12162222521FB20AC21CD21A821EF20CF1F25215820212007203721E6200C212922102178215D208321DE20C920C71F5D20FC1FF4209C203721A722252102223422201F102212218B224C2218228923C12250236C238C2457271027122722289729C62A992912284D274029362A112CC62B132AAE2BEE2C4B2DD833032C38244D211921DA21FA202B233921DF215C22A7213021432001202C22DE21F92045221F218322B1202D216623342288202D202220E2214B2117207D21FF2177223021A8216920062245218C2218229D22BC23A622C222A42460232B275128B328D826B227CD2604293F2737284D2CA72DF12CCA2C392C122B492DDF2E3B34072BB925C02276227B22A1204623A620F0225422281F4020E821FB20C020BC210D210222A021D3214F21FA20C721B922E0208C20C1200F213C2011217920FD208A210C2214220E20F52292224921382096235E24BE228C22C8222A2305273728CB28CE2656252627B4260C26EC277C2A8C2CC02D962DAC2BDF2B8B2B232CB734942AC925C222B0205B21D61F3F20C22018207E20C0207120DD209D207F21E0219020A71F8B22512001220E2152221421411F67210E1EA71F2021F02122205321EE2161232A22921EC020AC1FAE22961FC120D222FF21DB20DA22AE24752540279426C7260227D223DA26AB269B285129F22BE7284F2A1A2C8F2BBA2C412B78341B2B37265E2203223E21FD1F0420E9214122F920EB2165224720AA20F2219221971FE9205021F2216820F41F0920F41F25219122CF2063200B227C229F212E226121CE217E21121F581F0821DC21D4204C2131220E217F225722D0215D2555276A2A16278C256F24A1240B25942708285F2504289028FE275F29B42AD02BCC328C2AE025F72164225E22D621E71F99227A22592173209F216421E1202B213922882015216B2186235B218320AC2298213722A92152217E216E20D82180212A220821DF2197215921C22004210C2277228A2131213C21CF2101224922AF2306269F29CA2789244D25AD240C25A6254026B826E62641264D261127A82773281E30582E21252321962195226D205121A020EC20C7238F21D720E51FF81E6721D1205020D3225220F6218C21DA20F120C3213421A4217021AC1E6620D6207920F8218E212B20571F4120DD1F0F2138218F2027217722C8210721EC2216229D23BF257D27EC257B24A1227F25622536267E272A26B526B125192456262E26AF26F130382CEF264621BC21A81F4D2183200E21E821CD21AA227B20F31FC3210121EF21B620E3214621EF20931FE3200C22C1201E2171225D20571F8B21581FA521511FF120DF1F681FB7208B1E4A1F6320F11F6620C4207A20F3200B22EB216022FB24C426D425E3238D2357259C26FF274E295D2777274D252A2519269A263328CE308A2B69242E22D71FD62059218620682199202921D8202721CF20CF201A22F822AE2029226C21B121A021D420CF20DF208C23F4205C20BE1F901F2720A020CD1F79207520B020EF1EEF1DDB209A1FC51E6A20A72204215922D62186227C241525BB23D8236024F02423241B260A27652ABC2A432890265D26A6240828482ADD31EE2A3725E02139234223E4223A21682349226E22632018214421842013221422132180205121F421CA1F8020D51F5A21EC1F4D21E81F6C1F4C20CF2007204122AE21841FA820781FDD1EA12058218F1F362285231121CC1F8E21A821AC22CC224124C223BC220B23C02347251D278D29392C402A282939271328A728BC29A733DC2BC4242C22A4238321D0237D22A221A9224123A42204217B212A1FC320AC20E520E5203D210F216321DE1F0622BA2028206121B71FFE2012210C210B20B61F7A210322EC1FA51FCB1F1D21691F171F3122F620F92133202422D4236C2243225724E023A6246E22DC2387243326A729582ADF291228B5250629352BB52B8734162C9F26B52315216E213B2014233022E120B9217B21EF20CF1EF7206821DF210921EE208421072208216721FC2090218B219321EF20172297211F20AA207F20DE2188221921C41FFC1F4E21C8202E206E2289221821CD20092275228822A4204D235B238B215321F4227824122372261B265D278826D425A028D829852C65359D2B1D26D623CA220422182202227C201D216822292199216721A5204320B020D11FD921CA21C0202020D21F95241322441F241F7B20E41F3F213E21762044227221F82007212B1F1D1F961F6420C61F72225E210A210522C221C220452290211E2270227622D71FDD21A3212B23A925BB24D9258B25A625A026E128F42AAE32132DBC26CD236C234A2256217722052174230D237B211522C620E421A121B2207F20082016220B2126222E21FE204620E62036210120082211219320AA2005223C21EA214221A51EAA206220FC1F21215B22CF22A920B1207620DC205F20E322A822672233220E22AA212721E7218D248C248F235C2311242725822635281832902B83252F226F23CD21192188219822A5213E208D20AA205220D321DE21B41FEC1FB51F7123C0214A20152044202D21FA1FFF1F5E212821AB1E9C1EFE1ED61FC5206521521F9D1ECC1E8F210E200D210C22BD217A20E820FB2050217B23B12226225A21C1228521302360219E223C2262224F23AC235723DE22F02500276E319B2AB1253E22F01FB2212E22F721102245226E222021622168203420AB211F2251208521BA22F3211B2182231D21AD2204220D21F520CF20E81F851F441FF81FD5217E202A208A1F171EDA1E7420EB20612257226C21E2207B215B2043227022DF217C224121C3205A2264242C2251222722A024CE22E72140243B24EC271431EF2AA324862191213F210921F621012163215C214A202B20A8207C207821A2211520C01F41221F223B224022ED202D202820932179210120B4200F1F551FF61E15208D1F851F9C1E911E2820D220591F5F207222FB21B120162220203C20BE202F22FD205A21511FE9212322AC21F3218E21C723D323292361230B25E926EC2F792C9D250A233F211623B7210A21A322B120FB211A21EE207020611F561F47209920AA21B0222F233B2120215C235A21C61F0B207F20C91F72206C1F711F1D217F20DF1F3D1FEC1D391F781F4E1F121F0D20EC212620682013203B201121F71F2421DC20202186209B21A121482317231B22D2225223F7218A2378256D253F30132C62242123202110218C2134215321102230228020961F111F19207720D11FC4203F2218215222B820EA209D21E11F87200920751F491FAB1FB920A01F22207F200F1F001F021FC61ECF1E811E7D1F36200F22B72011207321AD20C21FB4201620A121FD21D0209321782189211C22F42214228A224A2346234E24DD258830EA2BC8259D23B6211222BB20B120A0209A220C2160213821E51F3C1F2A207E21022198216020EC21C120B220A3225821C4207E214C1FBF1EC3206B1F1D1F5D1E6120DE1F971DCB1D1B1E971FEF1D6A1F002295205C21FF1F6122972129204A21F41FA620A521BD20EF2117226620B821EE220821822339228823F8248D26882FDF2933252A214022C921951F1C20E0207E211621A021F71F981F541E391E4C200120B520502130214A20AA208720C6215620411FAB1F0F201F214021EC1FC01FD7206020D21EFD1D201EAF1FE61EA91D43219C22E220D31FB5216020F41E08211B229820382175205E2122209A206A21E721B521F5218121B222FC223125182F4F2AFC234C22B41F9E2121204C210222832029210B217020741F9D1E7720DE1F3A200C20B623FB20DF20E31E3920DA20E81FDD1EC71F3B201520EE1E361E0E1F1220D01E001E5B1FD71E3F1E8E20561FD0223621B3204920A3208C2010201D20B51F9D207422D72054229B201A210B200722432364242523EA221E226F25522FCD2A53232B209721C6209620201FC722C52080219721A6226E20C61F2B22EA212020DD205B1FCE223E213B1E00218A2155211820241F431F1F204C1F251E561F1E1E1A1E961EB31D361D0D1F931EC61E6021DE1F4520BF21AD21CE1FB11E37218A209521F22097204421FF1F8F2069220120A621A3228E209221D9220426292F292B7623E222AB20CD21FB209420C3216121EE1FD420FA201822C520BD212122D31FFE20B9208522DD2138209620311F881E8120BB1F4D1F281F2F1F2F1E881D041FC7203E1E6D1EF91EA41C56206E1F1922D4201720A11F2420DA1F871F742007212C203522A620662222200B212E209A215021002311216B229F23CB24512FC629CE248C2193212F1FB121A020B61F2D210F21E9217C20322059218220D51F2F212B219C21792112209F2075202020EA1FC220671F241F5D1F961DEC1D171E8B1D6C1E491E691D3E1E6E1E5F1E771FBC21B822572133200520F6208D20E1217822E61F1C1F102028228421812103217321992105221E216221EA224C252C30012B55242F222620EC1F33209420F621FB20A41F5121B220D220C21E7C1FDA1F041F0622E921B42190207E21DA1F35222A218A206C1F5D2058207F1FB11F801F1E1F211F961EB91EE11D1F202720FE20252023221B2194200B21A11F9A2088214A212C20BD208B218022E920E52020219421DC20162179217522FD22A123712F812A5F249A213321E8208E20D92039201E22162090209E20E11F6520342156224421F220B120C520762063209F211320791FAD1F741FEF1EB91FD51F361F9B1EC91EB41C371D511CB91F3A1E6A204C20AA203422D41F8D1F5820CE2172200E227E2174201420D7206E20991F34224B229C211B210721D2201F223E22A2242330562BEA2484235220D61FAA20C220EE204721012112213D228E20AE1FC7212D22082197205321C81FE120981F2B205121A820CF20DD216A1F971F9E1FD61D841EB11D881C571EEC1D2A1FF71E891FAF1EFA1F6F20AE1F9C218F22C820A12091218522A322C21FA620F42100214820E1203020482013217220F921E5222D252E2FF42BB723CC21DD2076201721CC20D71FD220E0208A1F7A202D208B1F572044200F20F91FFA20E91F3620F21F8B1FAB20531FB71F801EF91F4B1F941E0A1F8E1D881D0C1CE81D3E1FDA1FEB1F1E1F0520DF20A61FA41F2D22282037204220701F2422DB218C218A20FE20EE208220C32111201320C321F7216C21602390236A2FD3294A24D922042170206E21421F5520CD20E220B72150203F2210211B22C6203F212D218F21D1201221B51F352133230D1F6520FB1F8220921E0A1F7D1FDC1D801DC51DE01DAA1D661F2F200F20681F8F21E01F3D20FA1FAE201E1FA71F5E223021A221C1200D20D1219021F4205421EE20BB1F2E211D1E8D200F2222245F2F882AF325C3200F220B21022155210B202422961FDF1F07210C223A2189203822AD1FA9203121122251200C2098205C224620A11F991EA01F0020581F731D6A1D6A1DA41EE71DC71D701E8C1F4B20631F5A2014215120C61FFB20BE1EC61F431FE121C81EEC1E5B1F5120191F3221BF1F6A22871FE41FD4211B2192221724032E6B2ACC258F212F21E5201A21A520F6200422F620C9201521EC21EC1EAB1FF41F33211822F91F78223820B41FF120C11FE31F841E2F1F831DE120951E8320051F5A1F9D1EC21EFE1D1C20471F012040207E1F6E1F6720A51F6A21CC1E28201B20562186204F21A72043228B1F3A214721E6201D20AF207F21BD2391235024CF2F642CF625BC2188219421A7222C209D212822FD212C22262157206F217621422106226222B420B2224720B21F922085213920C920D61E091E391FE21F7C1E3C2045207B1DB81D481F251EB2202A219B1E91217B212620F61DAA208D2047223620EB2056202F21EC1FD42189218F20282032228320F2212B20CC21D22049233D2EFF2A77242822F5201D20F32006221721A72208223721D421E5210B202922AB2044210B216321FB2040206521F9212C21F21F2121CF1FCA1E5A1FE9200620F31E9D1FAE1E4B1FC81EB01F7C204A20401F791F0320B41FCD1E861FF61F31216220EE1F7321F020B61F0C200920521FC721DF201D219A213E20EF21A32244240B30C9290623E4211A218A2097218A1F2121A9227621B9217720E220592053201721BF207B202622D821941F9C1F7A2079204E1FB320251F1521C21FD51D3A20E91E8F1E001F4B20DD1DB41F36203C1E871F801F6A206B1F5220DA206720BF1FBA1EEF1F13203C20ED1E1420631F1920A420A51F4220D721FF1F2722FA210424172ED72A1C2478207822E82167210A21DE210D2346203C203F228B20492100212D21C9211C217221F021B120CF20B3216421F11EAE208820721F951F65203020E51FF81F221F4F1E3D1FCB1FB21F4E2027206A2106212220591FE41F6F209A1FBD201620CF1F381FD31F5D20C0209E20DB224620AC201421C220AE213B220A25F52EB72907256423AF203E216C219320662072210922F820B3210A20D82054208A22A92043215A22D5206A2143207D21971F881F1521491F1920B71F3E1E561E071E041FA11D4D1E6A1E841EC51E901F871F5F20A01F4B1EA2204120741F571F14208B21F41F3E20F6206521B61F4920E61FD4209821731F0721A5218A2180224A2F092CE1250422F920E920B820F420B12055214521002018205E1FF51F55217E1EFD1FCD209C205A2102221821C520531F1E2028214D21481FAF208D1E741FEB1F831FCC1E4A1F431DA41EEE1E671E801E3D20D420E31FC91F8A1F881F361F99207F20412193202420B921F91FAC20792209206120DB20391F2F2099232224F62F8D2A0F25F42134213621E421352098220C1F66208F20A12013208B217021A41F6C1F282106204321AF1FFC1F62202C20491F02210321B41F3C2133209F20FD1F6220641FB61E8C1DFB1E9D1F5A1F891F971F20216720C81F3F1FA01F0920F31FED2039207C20411FB121041F6520AC1FC11F1B2106216C206D2220226A24CF2EA52A14238921052300214A218F2049211821D91F1722632147206721752100210322FD1F94218E221021B41F12218921C21E3020BC1F9B1FB61FD11E02208D1E8D1FD21FCA209E1EC91E951F3120F21E182005229F1F491F50219F207321EF205B1F151FDD1FE11F1F210521701FC820ED20371F1320AD1F122082213823CB2CEC2A34257421BA21D72264202D21AA207C210622A6209A20FB21C5208B1F41225D225A22B921A5222F20F71E68207021C51F321F4820E4200C1F1B203F1F071EE02094201D1F951D8720171F62209F1EB22000212A1F691FE420CD1EE721091F792126215C200A1F312002204820BD215020A61ECF1F22204C21C1210C244D2FC22C4325F72173216223D220E021792080218921FC217F207F209F1F8A206A20D3202821DC1FF42053200C20362006229521FF1F951FE31C6D1F8F1E9F20801FB31F2C1F1B208B1FA71D8521FF1F951EC91F2F20251E30201320D21F2E1F19206C20B41FA5203A1ED02099205720E41F5E2085201721E6202E21CD219723852FD42AF02450238120512040201621AB200422F72099207220BA1F7321AE21CD1E1A216F20EC20B521F720B21F9E20C21FEC1F5120361E441D70201A209E1F8F1EB91F0321991E031E301D321FC21DE41EDB1FE31F6A1D731E5E20E11F4D203B1EE320BB20FC1F9820A91F901F661F4721881F6E1FF61FF31D462133228A245F2DC32AFA24CA229D21D320B721712213220922AC2044211B225520DA1FEA20BA212721E61F1D20EB202C215420D91F2D20F220DE1F3B1E0A1FFD1D4520ED1EE21F761F4A1F2920721E9B1DF81E101F4A1E7A1FA71EA21ED41E441F5120561FA4216F20B51EE21F0F2179218F1E6A1FC61F581F1B1F4820A51FB72126234924432D912AD2250B219A20F11FD41F102204216D21F11F6421D21E931F5B1FF61F0320CD20C11FA820C4205C214E1E9F1F91226621BD20BB1F881E951FD51EAD204021971F0C1F4320231D721EEC1E881E2E1F761F3420DF20DC1ECD20B31F841FFB1E5E21E31F631EBD1E85206820E81ED11F551E9E1F442192200D211223F124072E2F2BB024F422F920A321332191206820862115202E21731F6220031F0920831FC21E0D20811F04204D1E191E0B1FA8201820081F2D1E671F4A1F821F3B20432091202B20C91EF71D861F541F581F051F991E991F271EAD1F7B20BF1F781E701FC31FEC1E551F3120A920581E491E231FDE20621E9D1F671F292006201E24382FDA2AC5239E21AF21342157203120C321B81F8A206020FF1FB31FAB1E041F70201820F41E2C21162129201C1E89205120CF1F54208E20B41F8C1FD11EB41E362037202221681E8E1EBC1DDE1F871EDB1EC81E6E1F521ECA1EAB20921E901FCF1FA81FE21FFB1FA61FDB1F46201721131E921EBF1F1520FE209B21F82263241B2D1C2B8824D42059219921F01F2221422121213022C321511FD51FD51F2C2084206D20E220A8202820CA206A1EFA206C1E1E20BF20D71D1B20AB1E3F1FD21ECF20F01F641FAC1FA41F921DEA1FE51F021FB721E920541D22206B1FBA1FB51F8521D41F8E1D91200A20211E681FD41E401F101FF41F4621331FE2211422BE24F62D102B2125E821FA20D921A221E820EC22E22096206F207220FF1ED71EB320C3211320CD20A8229D1F02211720D220A11FBD20E921B41FF01F381FDD1FDA1E4D20FA1F8B1D641F9B1EE81DD81F0F20841E1B21D81FD31F731EE920441F8322EE1FD81F8A1FCF1FB41EDF20C61DA11FCC2027219E1F29200421FC216320F622C02EE32BE724A62024229E217121E320BF225322D620E220262115207F1EB020832094215B210821FF1E182100207A20DC1F6C1F6C21AB1FC31D031F67212A1FDC1E4B1EFA1CF11E221E491D3A1FD11E5B1E81200721B01E711F861E3B1E871E041F5420121FCB1EA11D8A1FF51E971F9C201720E4206B1FE81E3A20E82217241230252C1125F522502020233E23CA214822192366225C23C521D320F21FA42106208A204F224021721FA320581FF12086201E20E321FC20CB1F78207C1EE81EE81EFE1DF41D0C1D501E251F4D1E0F1F1721FD2007207D20E11DC01CAA1E9E1EB120D51F33205D1F941EAF1F4B1F7D1FE820C91F7A223E21041F591FC5229524832E ++# Note that this results in a zero byte read ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 403F ++ USBDEVFS_REAPURBNDELAY 0 3 131 -2 0 1 0 0 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 000B ++ ++ +diff --git a/tests/elan/capture.ioctl-recording b/tests/elan/capture.ioctl-recording +new file mode 100644 +index 0000000..45c4ca0 +--- /dev/null ++++ b/tests/elan/capture.ioctl-recording +@@ -0,0 +1,47 @@ ++@DEV /dev/bus/usb/001/094 ++USBDEVFS_GET_CAPABILITIES 0 FD000000 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 4019 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2 2 0 0140 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 000C ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 4 4 0 40009000 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 0009 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 771E7618FD18BB16711785165415F3156116D7150B15BD14DB144A142D160014DC133616D0148213471539148716D31470159D14EE154B15C71415158316E114A413F614D913A112DE12CE140414E414D313F215F9136F14C3142D147E130215A9151F15E7140713FC144414A0132616A313E716A01514154514F017B1182C2410227A19FD16D0189D18DF16F916A417C9171A16FF16FE152F15E615A8154B1542144615D314DC14FB143816BE16CB170215C1162915301693153E168716F7141F158116101590151414DB161F14C714BD16E8155F14DF14F214381723164D153C156415DF1597145A164B1674157D154315D9165A170017BB17F117531AC02391215D1ABD1971186417E4160B175A187616F918371821188216FF157F1660166A162B174C16131515151617421607162317631747164D165416F11221169B162A162F172E166E163815EB15B814EF144B15D01591140816F61585133916BA1504161B16921544146A1633167E1636151D15B3157F1875166117C7173E1B0C255E227B1D841AA6172F186717A3187117AD16BB16BD162A16B216D2158C17B91471160D161E16CA17B915DC153115B5166A165E1783160317AE15DD148813ED15B216FB168617EC14E114C01583141514D5153F160B168E16BD1595158816E2164C1726168616D31577159F14B714C71526163616D8169D1897169A18941A8A242323BD1B5518911782171C187D17CC17E7175017EC16151701166E15231748166815D3160016E815FE15C71520187F14C4155218A515B81254168515BF14031575161D1782163614E11560154214BA16E414FD165E159B150816761674152115E0166A162E17091578164B15FF1596153116F915D2169915D61602195319232318213D1B8418B719DF16CB18E1160C177218A81792172318F115FC158416F016D4166016F8155817CB15B81562163A17FA14BB16A21541157D15C6151F1525165F16EC16F815471409176914F3151415BE152F166B162E1681151516B315FE15F4163F17C21552165B16981607169E16A7159E1642186017D0169719BB1ADC230A21F2188F18061841177C17561855170B17281857177416DD160A1691174117A8176B16FC16FD15A317A317001657167C143315B815F415FD15641501170017DE153816CC152515D7145E15FF149C14671680173D156715D1157616AF141516D816F91446167D152816E7159D15211625178A15CD16FA15A8179D18FD1819249D21A61A10196C199F17F015AE1685172A173D181F16C016C717C7187C16811698172117561706186F17E915ED16CD18D4159C15371690159116011727168415D7159C166D1614156C15DF1620178E14E61779161215B614AB153814F716DB151E16C41500164616F4165016FF15E2169B1644165A16A5154818E318AF1A0D251920BB1A7A19D5172B18DC166E159D1765187717FA16B6166F160016C4164E15DF15CF163E172D171D17EB15431462173315BD16A314AF149014CE168E153515AC15C3162416AD15C614AD14A41417159D160C150C16441458182016AF15CD15291640152C17FE161D18EC15EA1414167A17E1154C160D168116D3180A1914256C22D8186217591751176516771718179018DD1624185C17CB152417D716301603171C16F316B216A216A616E2143C16AE14CB17D816F714E916BF14E9149915AF151517C915F41565145416EA15AD14381657160E166415391536164C15C4154919791650153E174A176C17A417841612178B17D2163317A8160619D519A626D220271C6619FA17A518EF164D172917A3170018E918F2176D179315E91653171A17B91600172117EA147C164815EC1680148314FB14E914F01519153C149214A9160216EB15FD154014E714F7155F14CB1577148A154E15921646164C1650174E171216EB15001773179E15A2142917A716181662166B15B117B318B4199B266721191AFC17041A3C17AF15A216101605182B187F17BC16E1150C160F162017781686162116CE183216A917E014471515158915FC15981580144214BF158D149B1499157D146715B8147214F41576155016D2144F1689166C16B8156115BB16CF16DD16D5170D16181826170516A31704177B160F167516A3161D17061B5A25A122271CA018FC176717C2160B171816BC170E176F1632186E16C91706171D188017E0167C15D217301605169C140B1887165816ED154315A91574165B15DE15BB143A169216F31403140016C0171E16F414AB16821539169017891794157117FB157516C61498158F16941630163D17821624168418A016A3178E18671B62237621411BDF18DF185E19B6165117F717A7184718B816BE160B163516C417AF151E173A179716A0165F16E1151516FC163117251772151B154F174115C314E013A2160616D9154B15BD15B01533177C15E7175F182E16BF158C15D216CC1669179417C5141F161315D916D31446146116E116CF17A21716171918B418A31A0F26E1206D1A9819EE17471953179E18C516271968160B184A18D1151A163A164517B2152818AE18801670150315221653175517D215D9143116BF1594146C150715F81663165216C815A3150E155E15191641167B1753179715E2159C1608157815E615E9166816D015471746167F15801688174E164218B615011769189419C3235D22681B8E185217C21782181A183C18A2169B173D181F177A152F178E173D18A616D817C516BB1658186818B115681630153416A416D915BC15DC154F15021507162D15AE153D1555140218081633166E18DA1435151815CA1551156F15EA151317EC149716E2159C175F18A9157017BC167E17CF17321896170A189E1A13249E20AA1B1A1AD8199617C6178A179717F6167B17F6180A183E177E1740179417A717CC166417B316DB173A16D8168D17A7162A177F1605152A169E162B16741620166617BB174016CA14F81390151D164B16F5155F1530163F185916B915FC1698168815CB1676156F16F21512162D1438182F17CD1760187F18EB18541B4525A121F21AE519EF162818AE18D117C817F3177C18E117E117641781170116981699165D176218AE1649166D17E61604175B157C1775173416AC165715B5166A16C2171117DB156E15CD1684169415BE146D1601186716C8144718E1151F150A15BE1715153516CA1446175B156618A3176318AE17C0169B17851850181C1AE926F61F571C2B1897182E181418C9188B175817DC16B5184916A216DC16F817A016D1163619EB164B19BE17B815771763187B15F0165816C516F81586150C176D1621172417CB16321490170F16B616031420178615EF15691502153B14ED145815DF15C716A6178D14CB16E5150E15CD1467160D16DC15F715CA184F18AD1A1C25C322131A6E17A817251777172317B8172D1613163E17AA176917651557185618B0174015E7174D18FF151016B9155816421743163B14B614AD18F81504173115DF16CD174E1637168F1596158A148E15AD15F2158E14E3148C16DE1465153F169C1747165E1683168A178514FB143E17F415FD154116EE1507171E19EF199B242122361BE719C718F0172718A71633178317FA176B19A6175F169F169C16F417F916DB197F17CA16B21639183017D8169617F61535169B15F7152F17D31652180B18C918A917441764150A154917A514E916C8164E165416C014FC169F15D9159A162515CF15DB159B1797168C168019CC16AA16811887151118B118BB198E244D21441A3D1AAD171117A717C01759175618EC17FD151F182B171A1885165B1786183A16BD18F9166F174D179417FC16C0155D16F4133215AF16D61508182C17E617DA1892171317A41612164715F4154017CA16D014BA15B9150016C7146715A9156816221543164717E6159E16A6155D150F17B715BE170918D017EB194B24D220CE190118BC18A6187B18E517131769187717351810188217F8154718C2163117C116FD16E11402158B15EE15E115121560154114A715A215B014F31601170616FE161317AF16B7157D18D216FF14901700176F162615DD15B615BF15941678166216E617E2159617341806172E16091640150B16C116F816AD17E618F8242F21A1190819851860183D168F175A18DC161216CA1606185A15B816E5189B16F616E0176F16DD161D162F167417BA17AC166C1544147716DA15F7144D162F168216A317C315B71383172F173A173517D317A616C8174016E716BD158E154217B514D6150516BF1510177D15AF166B175217AA157F16AC16FF171C17611A22251A220C1ABA171618A2189E170E172317D7183317E5181618EF16BB16D11557164716951615176619491679155E17FF16F315E2150B164115B014C9154A154F1608162B17FB16C916B216E815EC1730165C16C41697172F17601791156E15E6153B172C15E914F3157415F51599154B18C0177316F01670177C19EC191A1936244A21D21912180C196217AD17E9178A177617FE15FA163D172516C2163017FA160D18881501178316D816F4179415A81601168816AA16FD149116E815021744162917AE1601177116E51446164C16171517179716501574142F17BC14CB145B1600154B1572150414F316B21569160518DC17A215C1157A15A51775175B1AB1242222261B4018531792185418DC170818BB17ED16F317D017131620171617211709181D1897157417C216ED15DD15B0177616181647177C156B1657162E17B515241728175C1872155C171216BB16CF161F166D17051637156015761641155417A015BC140416E7156D1692156316EB16B7165916F5167417BF1627188119A724D221241C9F17D918CB17DF171E18C6182618EF169B18D816DF193D1797176F17D2168D17011759179C167916A9163B170417DF158514E1153615DB153416E9169A171218AA17C0151B178E15DE16F7155C16101620155415F914B41583148F150C177E15A3149C165C1643164E16F2155D163715E41639172C181718461B9A2510227D1AA0190B19E417A016B317D617B518B1173216B317E216AF18511731186518D416A217B016AA16FA16CD167E16BD15D516A4147414CE152F1615151717E31717185A180216491612166614F815D316DF15BA151E15A9165F14EF15BF16D71585152B14411632167416B616D817641674176F178D1608176319CA19A8241D23921B87160A17CF16C5187D17DA17DE180C178219B217D7177D168B172C18D418D2172418AB19B3164617F5155C189315F2154A162A158415A2150716CB162F1714179B17F61646169C16DF15A61654171D173718FD14C516E3153A1661160A172317E5167B160617771747165D1678153F16F817C41675175419CC1966258521C619FE17E2165E18C516D6163818651746191616A817FC159116CC15A1143D16A416971717175615FB1446171A17ED159D158416F8132D161D168D160316D815BD165D16E215B3154814EC155F15D6150D18C8144E155D16BE164215E1151F156C176B168F14FE17EC17CA1845179315DE1442168E16BA180619A21909245921111C46181319011946167916FF15E518D419591A92184716F516E218FB18C1161C175717AF179714A915391595147F157A1610164F159716031542174716A5182A178F174F1480152816E81511142D16CC162B15C3158616BE16D71675155016541605152F16A816E81570163916B21548171216EA1692165C19591A4224DF21251A1A18AB17E21799179018D9177717AE185D1890171318E0177D17D317BB170616A517781618161B164F1582145515AC167816E21698167C16331511171417F917E716BC1535148417DB15D415DB16961778162816A8167E16E916161553161F160816C515561873179D16D5158F169916DA1776168E17D61883198F24F7214A1B5D18AB189B176D18C21650173118B817E41648171F178C17F5174A172C16621705160216C1162615B7165215FD14E815A916F7138316DA169F15D815EB17E017FE152E1490163814B315C2146A17C6178B14131653169815E3154B150E15EB15021772174E17ED148714F01440175B1784155616FF177918EF18B3240122481AA417C8186D19E8167A188E16FF188117B3175A178B1820174A181D173917831746174117621974178A16BB1758161816011832152D1522168416F416DC16CD1854167F14FE15FB15DD157E140D171017CF154B167B159816BB170915C416DE15681566153D161417E01589160016F9164E183517EE174C194F198D243020A4191C199F17B518E71796176F16E01625172618FA18EF172D171B173217C4188B1762160718CA16E5162018581772158316D417FE1453159D16B0157F16F31515169217D51336149F17E516741491150D18651765159216A017CE163317CE15E215F316041831188316BC13E81578166017C217A8169917F1182B197E25F221161A56193819D718AE1620166E173B176918371995177E17D415EC16871785180B19DC170E19A317C91677169D18B7164B160219DA162D164C17E215F3160C163D17D7156E13D113D916E11585156C179217D8163E16F6162E153616E415A01831151E173418D216F31523161C172517C617EC180118F318E518D4199C24EA21E81A8018EB17F9180D18B018E9187C1835186C181016EA145F183117A4167B189917541794171D18A91448167017AF16B215DD162F1614160B16E3156717AE169216DF15FD13ED148E140816EA1434171416CD173C16B11535167C166B158716CF16FC156D154B179615EB163E175617F215B8186E17EA170219911AA62559223A1A421837185418701767172D17DB19C3160017921715171217E517561754198217A91681172D16E9164C18F815D8178E161115A416CE148215CD168F16DB162D17FE16E413BC14DF14B814B7159F164E153616C91528161715CA150E17D41639160D16CD15A715051642166E175116DD1582170B152318DD18271BE923EA217A1AE418D717BB1613178E1738171B172C177318D7179D16CB154216A816AA168E17A516A0166318AB162517581885163E16B415D2153C153715AE162916DA167C16EC154715C315AE153715B31457168E168A15CE14F4162F156915A3153516DD1670176C16E61641152516DC163B17BB16111820175B1808191E1B4A25AA213C1C2319A119581966181218E9174419DE17ED158C1588168617A7172117B7189A17DA145A18411656178C17B7164716A1169F1467153C176014361665162C165F15C2156515F014B5155814BE15E616A91644161F151515EB1485166917EF154D16C416B6167717E0169C160E171D16EC150E161D16F116E617F41B56258322411A2817CA18FC165917BD175618D417F6167517D81694155515FD16E71634175E1793172917A717DB16C9173918F2178615DA14A2147A155E15D2140C16D7148F1566172214EB140D1632167B15B915DB1661171E177217BC159015AE15851791161E15BB1527171016F916BF160F16B6156017EB15F417B519351B2B232623691BA8190518401AEE15CD174C184917BB1674169316881571159517071770172017AA178B169816A81635169A172517CD15BA154F16AD150C150B166615F114F6142117F715B4151D15A615B415E41679169A17551561161416E8153F151D16631629156E155816E016BC16C31669161917EA17D9187D180517951A4F247D21D11AA3188B184E18B118AA16D11779177C1731179916AE15CC1697153C16A415C9178A174F1631147B164217CA179815C118621782145117B314D214DE163416FF15DB153E14A514D1142117A91592167016F5154C153816291525159316E5146414CD151015E415B615A2153D167B16941692176916DD1563179D1A992419226E1B1A195A184E191B1918161516C118BA1698167316A7141F155C17AC16FF15B2177616A016DC174F170518D1178A16B115D2155E166C16E7150F163C15FC142F1600168C13C0153B1667158C16BB15D3170C162117D9141216351531151E164916901631164C177314C7156916D115B5160E1872172418FD176319B62377218E1A13185E188718991753170718C117271892169116E316A517A41760161B1642179217C718DF16FC16FA17541743180F17031638165F1641137516F814F21519166816A91529152E14F41672153F15D41695154A164017AE1403175D160E16CA152A16B514D01790163815DE166116CD160919B1178718B21A511A57245321981B4419BD17E3189F1821186B177A17CB15A916A4157A15DC167117C416F316FC18DF154417C216991598161F18F7169316EE156E171817861548166A16611673143816F2151015FF14C31675141D15A51465164B169314B1165E16E0153C1401173414D415B31678151C15DF172C166C15191807171418DF18481A3C25E021A81A5819C11832177B186616F01669178E1730161B17F81617170917B016AF17E2162517D317A616FA155018A917391686165A166A163D16471755164715A6159414651661156115BE15C614F214CF14901678158D152C166015F6159A163F162D1732162915F615BF15B8165D16671583164D179217BF176618261A4C256F22021CE11846181F183D185917D915A216D0168B18D11676160616FA162415A517F714C716851670156E17AE1745193118381653149D15B616B414CA1528154315EC145B173B15F015ED1467157C146D15E61669158515941617165915A41654165B14D01596147E165216AC153717EF163916D315A7167D18BE18681B39242521F41BAF187A184319B117561593164D18581711178A172A16BE16BF16E4177C15F9158E165218BB177D16041727167617C717B2166016FC1429142616E1150917CE160417B016BC1590154115F6151915DE16541672142B16C516AD15E4140314681729154516F315F515CA156216C7168017FF162D160D18C317D4192A25FE214E1BAE1997171F182D18A4199F18CC17F816B117561750178016271777152417CD19A317F618B3156017C0160918961415155716FE14161519169B16B4154E154E164F162A1684153D14AE15F415931739166916B516AF16C817B51572167C16FC171B163615431618161C16FD166B16AC15E016D816FE19C5163E1A2B237E22A41C511AA1188917B3189418FA17E8185F18C118811620160817E2166316A315A616C2166419AA1639166017941769140B17831505163217981441160116DF164D18041632158114E715081567155B166E17FA152E159215E715C81578150316E7167716A3143618D11622163116211650165D1656158816621871195524D921E81ABA1B7C18DC187E181C1813172019CD199318131867189A16E017E416A5164A184B16DE1869188016F2166F1537163F1405171116C616F2148316F61569162618731747166F1682152D16E615B315F41533140B16891765164D15BC153B151D16BB152F164C15AA156917C7163815621518186E1603180518A319F4269B234A1A0F19DD178A18EB177217FE1853182D1797182417A515C415A716E618D61647189518A218AF159B16C416D0168F15F0155715CF1547154D158C1672166818E917E916CB151A1501161C15F0142516D915D81475168C1554160A14FD14461660146A144B1662173C15EB16A3183B16D514911727166318F0184C1AF6240B226A1B31185A193B1A0319FD172E18D016AB17EA1868195B15F2164316D4168016331649177A179818FD15A91716174A153816B61885152116CA164016541682177117BD161B1716163C157C159314101607172316DC15AB152D17561505164B1709153A151116D1166C168D1583160E164E16471966178A1890198219C0222023861B9E1A4C1950174C198A1779186519C9177018661816188D155916E5149617EA16E3163C19A617AE180817C217F3159116EB159A17771640172D18F11638172F1981161918ED166A161B14781598153F166F145E150D157416B31623166C167816C217B714B817A0161F153117E516C316291A201892177A19041B6924DD20771ADA184A191A178317481712192417B215D5174B15DB16DB158D16F3158E1780162C162B179C18361561172C16C2172A17151623153515B0151617461791169918DC17BB172017A415CA1776151515B1166D15E814EE15391654169516F415741567163A16AD15E21558174617CC143A14801886167218F817FE19FE234722FA18A8184418A418D416ED189F17EC1779188D17D215231611164017DC1539171017931681179E166716A2156A169D162016381791167115EF14EE152D167017481828185817911672156317AF1579178617351721155817DE156716171726178D171818561568173B162817CB169E15A017CD189718991A7218411A9C24CE2059198E181E186617FF17FD17B218A8181F1828182617ED1795153717DB16C216FC16AF171218211775163217BF161916FF15D317FA154A17D0155B177F166E16CF17EC18CD16EB16B517F1160F16F316BF16FC157116BE15FC15A416EE157D163717C717DB15CB170017CD170118AB158B18D917DE168F18D417A21A082779216F19301AB318A118B01804186C184019C31724189E16AC161F17C5173B164417E917E8176B18C0169E163C169517AD19C517EC15781479166C17B016F917EA16B518751795171217B617AD17DD16131783158817411610174E1669151217A71666154D170215B51785164014ED177B174B17FF160D172E173219AB1B4B267221511A2B191019EE1863190C17DD18BA183818F018BE1785179115F315A118AC18FC18EF186D18841770187C174718721792160817E5165F15751824169315D6168318D0170517F9162317B1161B165116D616C61540179F158515F316B7163217E915771565158D17A2168416DE1603174A17701783155E17BA19DF1B3C263520B31AEA171A181C170A17A51720185F19F5178B18A1169D176317D917851560175817D5171F18AE166C188117C41663162417A61547153D157C16971679169E177A175B1835182F16FA15F417DD153A1615169C161C17B217E11516156F158C177617B71749158316E215AD167817C01623173A18F91754186E17901A84241D211C1BBC1A17174917D517A01744175518DC1858194B188217D81828175518F01647178E16D41831169C18A11632175216D417C315EA14FE158F164416FE169916861690191E169B16AF160B18B6159C177817B215A115D418C01570156C1698177A17A3160917C7161D17BF17C5171D174E15BF1AF916B617B91A081BA324CB229E19F4186B172518071A0A18DC17F1181C18A61943195818FD170D185315E3175118B01719164318B217701567177017DF158417C9157F150B157D16B116FB16C4170017B0169F1520160918C515A8166A17A1164D1651174D172315D71646166F17F8150016EC1739166A16FB19EC16BE1547189D177D17391AE31884253A22A61B77178917D318C0177218D417DE186219E8173A1849174417AD170C187B17C9170F18A7186C17A5181A180116C41546177E166016F316FD15C015A316D1173417CC15A6145F164C170B160C176218AC164E17491696176E159C1515165B1794140F16F6172B186116901583176F17D41812176E1737173219961A5C252821421B9B187D194A1791187B195B18F51718161E1ABC169A18E316B51724162818C117AB187317BF169B168E15AA177F1670165C17AE1562168816C914701674174C17E4148714E0176B167C15CA144A16A316A9164C162C16FA156D166F15C81744161416EA1566166116F214CD171316D5166F17C9178417B017581AEF24821FBF1A3D18E41793198018A616E018C51666178A17141655182617A718961785174618971781180C178816F51797171616F815D0159E162116A615E715C8162317001762172716B5149616411618146714B4175E145D164C181718A81739175E156F15831604159418A0169B1686173C173017411719170D17C119361B6A256F20881AEE19F819D5184E180F17EE185E174F17F317F8189616BA17DC170E186418D717A1168B18061835164318EF15201643179E177715C615F916DF158D1574170E17DD154A15AA1522169816B316BD16AE16B3167416DE15D115BC16CE14551532176D16F71543165E15B6183617BE167F17BA18BC168916C218421BCD239D21741A3419E317441846191618DD1716180F170B17D7150A17F417FF179D1808179D17FC16F41879186D17EB162118DF15E715C315C915BB1620164216DF1484175D170F153B162D160E15C4166115DD166A181E164D1788167D148416C4158B1617172D150717FE15FD17A816CA166E178817A1165117CF1866187F19D0239A20CF1AD6186C173E18C818FF17531640182717D0174118F116AA17851913169216A618AF163116E6165F163E17321714176B1610178E15A0163217BD167317F817F9178A17521422161A172A179715E11725176216B414D1171B1611153E17051789167F1709176B176416DE167E18141763188E178817CD17A718331AAC236E20F4193719C11816177E176C171918FB185F18D8161519491611177519A11794181817EB16A8165A16E716BA16EC169F166E16F0169F1595175216EE154E15BB176716BA166C14CE153716EE166716B81790160D16DD14B917BE1576165817C516641625176D166D175216DC176B17C11681178516A817FE161018011AFA24BC236E1B75193119A5185518A116D717461980183E17F418EC16AB17FC17551935184018FA179516B017AB16A11719181117EB1683163717D716CB164714BF153418DF16E817A7141B161017C31666169E167A17BF1416162015D417FC1525162A181F16111873173E1667163A1691174018A017BD172718E618BE17E11AFB2636229A1A331887177E185B18E3186D18D7178617B418D3176A17A215FB1636198B17AE1649186B181E169915BE14DD16AD151417BE1669160F1714158315A117FE16681735174D1507172716B415CA15941778167B170F16C516B3157516731607178F165116E9168E167916BF16B218F3161B1708186217FC184C189B1ADC26E9216A1B6317CF180D185D177E193A185818E5178C17BD1722168F17931714183218A218DB17EC179215F81898162F17B5159817E7151F16F7168016FA14D41511169E15FA163F15A1151D17C416FB154316A3174218D916E716DF161817CB173D18C816DE163B172F184616CA162217A017E917F81792160C185C183D1AAF266D226D1BDD19E619B3186C17F7173417C518F4178A19BF17B417C418FE162F193C192918CB1795187A1605168F1814197616B715BE14EE1553164B14A9162416F51639175218F0151B162F174E16AD153E16BC166816D614CF1750174A16BD1726173218F116AD15191905178F18FC161016631839198C170318CC18811AF6243621AE1A17193B18D119ED17AD15A41689185718BF1806178217B617A3187018751878181E1824190F16E916D616E01796148C16E01527150A17801568167716CE160217EE16AB165315B3158A17151668156C17CA15C015A2171E189C18CC167C173C167D171D1632186C17FE16DA17D9159817D41938176D171E19451BED24F520641B82185B18F718D3173917AB188E185E18F0177C17D5160117A51684184517A718FD17DB1673177E1823183B16A416FA157C16AD16F115BA16EC14CF16E718B516EC17ED1543157715C61634168717F9177C1669184018DF16E6182519DB1873174E17881846186C17B116DF185E1743172717E518F0176C18C21AD024A8217E1AC6180F188C17D717D217DC161819031883184617E8160F1897180E1919192618A6189917701776170F17F0161F1675171D184616A5165915C51712174B18FC170B1751151315631631168014CD1733175E173418E7175A18841749181D173A18B5196C168D183A18F6151F18FF15FF1783179315E9161D19651A08252020811A751816185917BA1708183317CB16D218E4164817D61706186A1771170418FE161C174F173717AB18511772176617C3187817B814A716031641167614E9158E17EB171C165C15AA17E2149716B41705186A1522161618CC177E17A517E9176B188C151417ED16ED17C71664177E16E9179E175A17C418CB18EE19592482216B1A171A14188D18D31826174519241999180B1880175F180D18C51684193A158E1760183A187E17F315A7173A173E156D16E0159816F916EF155D178516E8163117A7163A162D167F15D315691622174718AD164B17C517EF181B19A117C816F6168616C4167B187417FD17B518751767177517A217BA18F8189E1ABB259321191B2C187E182B186D17D417EF18061817197B180118461663175716061A3018C5179817E4164616B415AB155E184F142A176E1629161F178517381561162D178317F41628179116AE1657178316CA16C917EC16D2178618CE161218471719162317D115041792173116CD17C716F21514182F1801169817A617911BF024BE22F01B3E18AD17BE17E81741174E181F19EF18DF180E19BB18C616BC17F0171817CB17FC1714189517D9169117C716C4171F1740164217DA1869164E1518173F17F5154F155615FE15E6153317CE15CD179917CD1759160E18E4176116CE175F17C4160517C5171017E71644171818CD175C17E1181D18F5181419B31BB626B321D31BE019BA1757173F187D16EF167C171518061863189E17EF167D18221703182C18C018B217EF17CD15CA154C16F4142216A616AC15A118A6161B17501589161F16FA16A815271533151F174516D4168917B3164C14B21A0B175D170717C61685189C1765161E176D16291764179416D517D6170718D7178418A31A9C2429212A1BC417221836189518451895168717E5179617A5170717FF162017B5175216481827177D18D71810161E16DB15201692161417E11518187217F2176117F11645179B1767169F15B8147E1744156415DF163915CF169A169C17FE16E0160617D5170A179F16EE16F11638175D1796161918BC176F16C5176D18661ABC24D822A4191E19D41819189F17CB166F18DB1607198018B3171817CD174818EE17C317CB164A187A18461859164017EA16021871161E17C3153D18901693161017D0173C1827162E177216EB16BF164A17AF188816E2168515F9177A178F16E617CD16AC17631625171418F715AA179D175A180D189217F615E8187F18A21A1526D420FC1A14181717DC16F9166E1603179917FF1633189A148A17311792166A18981756177D16A1181A167215901713171617731687167017B316FA1502170817B91644176A160D158B16B315F7162C16AE16C316DF1603155819D7164D192519781763173A16BC15A317FE16F5166217D716DF16F019E116A0161217C6198B23EA228A1B2019AE177B181A199017E619671832180F18DE16BA168517F9164B199F180117C8175417F0160D17E31622179916F7179A161318A9176417471731178D17A317C41795150514FD17F018F715EB16E31823186117A917731614174A178918BD1745177E1816187E178917FE1890179F165E17EA162317E819331BB924E520581B8F176B1852183019FB177718AA17FB172B19C617FA1784163C1874171918371740186E176B178D161318AF17AF16B417E81469161316B2150617BC165B159116CB16021724176D178316151674178E176F151116E616C4169617FF1659182816C417B517F3169A178A1619179E18B617531725167A185A19101AEF259722021B6618E017A619A1187218AD170C191918B61811196C180F18C1172F188716B1184B1794180518F415A5182216F715E9165516A616B9168917CB157915E916EB17271710177D160D1829191C15AC17D21621170D183118DE159B1771165218E9160318D216B01839180A176C17011847185F18D8175D185019801B83257022A61B0E18BB179D1776185C18531835191419341898179717DF17FD1691173D175C1616176D17D0161516B716D315A4159C17F5145915B516F3164915A4158816AF16C316E015DE15C11582166116E8168717EB18E415D7169B172B16C617BB1794177518E314DD1655180E17F317E316B1171C18D11668185B1974198C25F5226A1C4C187A178318DE17D6164E185B19C817EB18C0185A17931681188117C91547189F179116F8160B17C217901771156B170517FC15A818581632161317B81797177C176014D7157B159E151115AE17EF1780171B171118DA15D1172F181D1778178717401822198415C516F617FA171E1707172B18DB18AA179C1A1526CA23A31B7719D717EF18D918E418A118BA169D174716CA174D154816A9174F1703170518DB15DF16C515FF14DC141516E315D115DA15D6167416BD1761174715581736174A153F1384166815C5157C162716201957161D15AF157715A8180A1861171B166D159616D8185317C9175D18A4189F17B217E3161E170B17A4182824B622431B201B52187818DC1624184719AB17E0160C1883172316B215BA151417A2171118E7168317A5161116B4162418CC1571164D15071607175115D8160217A7169115391613167316C715691536173815D31854162E14AF1679153A15BB147C1565168A18C016AD186018A618901706173D170417EA16D7188E198A1BA925A922DF1A8218D318A6174C1751185B185518601702162E17A4161C16331635173F17F9161918B5163817D3159B17F2164E16A2150116A7150716D815141661171B1672163316281383165E1409164915F4149C163E15DA15C215FE15DD16F714D015F216CD17C01730174317FF1662170B16171774176A1686179A18231A22238E22E419D617301727180E1727196B175118B91882171717E115EC15E0179717B616FB17E616C1173416AB16FB18EB17F515BF154C15FC163D1641154116B116B916A71566154E145316EC148616AA156E155C165515AA159E174215F21672167D178A166D17D315C918D816B416C818FA17E2162917AA17DF16C1182D1BE422E321A31B69190A19DF185817AA1939177A198C186C15771635181D17C516B21753172C187C178D178A171617DE17AE18EC16CE16EB161B17D9158216C2153F16D616CB16A5168414A3173317C0158C1407180318E6164F164F16EC151918961740185417C5166D1804187716C516FD16AE17C4186F187916FF169A175119122479219D1B1F195C170518BE167F163E174F16D81634170C176617AA16AB172C18EB16D3157218A216F71719177718711779154817BB13A315AF164B173615C4160C176E1838175C1301163D14261848142816A117661610150517E3177B1786173B169417EF18B01648193518301870179A18A1156017A517B3176A197019D4248121281CB2189918AB179D162C166718811848176218DB18BE16D1164218DF17DE150C1767171418E416FA151F162016F3167618A6161416CF17021805171117A216191742161214FE140116C816F9155B16F016B115531748160F151917BC162819A9163B176A17811765174618F317FD146317421750169417EC18521B0624B220761B4F1874185C185C18F9159318B0186F17B91698177117E5160F176018A61656174B17601954174F169A182117FA179D170217DD1617160F17D9163F17F615DA166E16331688150316DC1637177116701631164416EC159A156015B6152218081724164E18CC173A17ED16741604171617AE164B16C9160F18AF19EB22A624D51ABF17E917FB18EB16D4171F171417251AF01769174C164A15BE17F8163016BF1848161D185B17EA16EF16F81727177E17E5161A149B16791643166417C01645158114E0150C153A16A216281671167817D116CE15AB17A6151F16B5164017281652167D150A18DF16D816D5172A164F178116DC1454172F1793181D24EB228A1C59186C189516E31712179C175F186F1849194E17AC162A189D17551843176118D417BD1708164317A0180D171D17A71880164015C51751156617FA14B21651151E15701654144B15FE153415C315FC15F6154116DF1669160B1634177918BC17AB166B16B817AB17E0170A18E51548172F16F71517173718011B8F2418222D1ADC181B163817E117DE16A917AE1674175C175B17231724175518DC1825176A187F17E717AC17A616CB161917A9192217131653157D15201661166515DD1514166D169714B613EE161B1553145416D6175A167417B41610178A184518E91686162617E01766167D16B415A017E916B81521169516A815B818581B5F24AA21DF1A5E186B19B6194A1993177219B018E218AF1669179817AF163A1862186A17841671171F18D915CB160B169B17DF156D17C315101554169316961521180F17E71433163315751485169716C814AB1793184716C71425162716F616C4161E186117531647163C16971686162817EE1745175E17DC1674178717EE1895244A22CF1AE218321A1018721A271955184619AF19E118CB17E41772156517121742179F17D817AD172C184D163718FF168B16B7179D152917241705170916AD156817E717CE15AB157C157C164215C814731834169C1785155417FE187917D916E8185B18F218BA168A178017B2175919EE1700185A17FA154C18F7187619C7246922621C1A1A4A170B18B916AC1973185B17FB172F18281726156117B1173718AC17F716A3175D188417AF1769179417FC179617BF16DA1790176716D51680160C183618FD1640159D1517177B16D5159E17E1179816B915BF16551778176615ED17EC170916E4152B17CB17AA157C1763169917C816421607184E18351AFE24F321B81BDA194B196F1821180F181A17BF17B7183717C3178017D5166E16C816FD152018F817FB164B162F16AE1AED17401506158E16D21545172C175E16BC1707178216BB16B1140715541513168F150818BF16A4163217F516CA150B17C516F7166817B9174F14E016C0156F1642188916771743179C16F6164918561A15238023BE1C2A1AF319281903181E1982178B197819D7178E187A173418F0173117F3167E1666186617A218991745178F16341735173A16521881178E169316E3172417C9174917B514C4163616C715E116ED175E1872165A16AB153B16011644181618811775174E178E161A16F315A61784174C161916A8163517AB17E519C0247B22D21B1C19E8197318CA17781844198E18FA16721785172E17B31858184C16B3165E163F1AA518CA16C7160F17A117DC168716C6177E17D914631571150816EE166A17A815F014FB14B717D715C516F8178517AB1682168616EF16081974186C17D1162E1816178718E4161C17CC1675166E177417D316DF15C618291A892538217F1BD81867167E1806197418AF18C818C118A2172418EE168516FA175C18DE16E7170B193F18851792197C170F194E183817D916E616AC15BF1564155216021891160C1694150E14E0155D1676163B185D180B1739161417C5159E17A1177317BE178F160E1684173C191917AE1606165118CA167715A2178317391B7225C121911A2C18E917F217D617D118721708184F182C17E4161E172F170E1849189F162D168E189618C018D118811787168416CD1779176616EC168515D41526157416FE15BC15EC1432155216E116841594163318C3178E169317EF1577168316C017B916F8162A1568174C17C41653174A165B186218DC167917F2185D1BDF24D6225E1B541993175919FB177117FA184A175E1860173417BA16A615B215A1161117381846197F198F175D1732195617EC151A16B8167A15BD16821585153517A416DB152D15ED13DD152E156D15F514EE15B91719163416E1150516C716F61590165B169916E5151617B3164218DC17EE167517F117D815621749196619A8243B221C1A641951177A17A7176917BC176C18A718BC1617167F15B41608174E162A172D183C175C180D175A17BB17E3153117641682157815FA15E716FD151816C3165B15E214E9140115C5148714DC151016E1175616BD151817B7167D154516EA152B17E117EB150517F616CE162A179D17BB161917ED179717C6184F1A34257422791B001A63184A180B172C17F816D318C2179817811760168615FE157E175417D417B3166718BA16B016E6188417A416C4176A1555154917991522150E158A16DB15D413B01445146616A113FC15AA179416E516D51517183017F915EB16AA15411619176316DE17A2172D15FC164418FD15D917BF16E11774194D1BCE247F20D61ABB170C1989184A1603175017C417EF171D1861162116FB14FD14DA16C9162D17DF17B617E0162D1713170F18DB16E21517166D16C71791177F168F163A17CE163A153714311548168915E9134A18E4186117E815F1176816A71537174818DE1657177116A617061655165617871734179A17DF16E7174318B61AA2240421061A2519A1167D18A2164618D6183A17CD1723187C173416B415F416AC168A1691160F1A941790177D1517178617901661157516F81698163D1581147616DF165115561423165515AC142617BA156A194C173F1798160D17E4164B1641161916A116A818F2163B18BA16C816D715AF17E1181B1AB9180818E4174E1BEF2431213919E6167E184B174217C215091988170B1857182119AB164916BF1854188D167817FD152E19AB178214EC170A1898178D166D15D6158D16B5156514EA156814EC14F514E5131B1444162D156715AC17EB159D16FC17C917B515FF143C17A7167B171B179E167417AD1565163C18DE158F172D18001658177C18E61B5D25AC218D198A1928175A1889173617AB181018A516621768177D182F174918F818C01665172917D7186D18D916CF16EA1523154E173A16D115A0150816B7149614F51556170A1534158915DC124F17E71513182F174A1604164B16C8158C1568163D174B164618EC1679180B161B170716D117FF16F21828176E18AE19A51A96254F209C1AE2171818D8151718D716FF15A817D7176918E1169D16FB17DB1635169F174B17371805188B162E172C178F166E1626175816E815C7150514401553147A144F1599144F142B15A114B7141C161918B4186517C9168916F81696160E186B1804164815D9153918511792171E1774173A17F817E0162C178818321B432687212F1AC918EB16A416C2165517C318AB17931615181917B9178E158416CC169A158E1884186A183F1705186916D818AA17E816F115EA16C516FF1553161B16C1150716BB149E157A140317B6169E179D166A188117C4163F1719160417B817C3178B160117BF17BA18E6160C177B17D917ED16281783178B183819AB196725CA20BE199A17C6172C1754171617CA1678188516A616E9169916BD167B175C18B6173917A41611170217F416531887160916F015A0153E15251613161A1511150815301306146013DB16BA14F5167216EF1652180516A2152916A817871647182F1747161716111762165E15211848184217D616B616CC16DC174518231BC925B4218D1AC019CD161F16111728175117EA1722177417BB18D716AC15F01722187A170517DA1700164917F815A9168917431762176318B115F815FB15FD133E15F6139A1319150E141D164715DB153E1583164E16BC15B5170919BE16F416CB17C8189D18E21500172418FE165E16BB16FD154316E8164816F817C118301B4925C62279195B18D5178517AE176F1793165C177217B3168017DA160E16E8161417C016FB169D17C916EB16B8164A16561768167A164F15CC16F0158615E8156F148E144E133415A71595167216DB15A116801727166516D018BE16CC16F116B715A1188B180618FD1638176A17051744189616611648184F180618DE19231AC1254720311AF1188117C916D7175015D3161D1757170B18CA163D1851175B1803175617B617EA17F41663175A1685178119B0158116291615175E157F15AF1538146214BE1427145A1427167C164C16A915EF1702169416F71508177915961548180917C717F116A316AA17B517001787172417B51512171C1454170718051A6425F7203F1B26177F1809173817A11746168B189E15061671177018A11743177618E6152B17B417461865166016FE16B518CE161316BA14E4153D16B515B41374145C1465150E149314C4140516E216BD1529166B17651656163917F714F115A7150318FD146115151546160F157017B315B01895151516D317201762180F1AE523DB20BC1B2B188F175317B0170D177E178A188C1766172F176E1812150316701669176E182716C918B7164216641767165716D314A315A013C317E814541759150616E51409154E141D17E81566168616EC15B415A0169415A217FB14A9164816AF17B0167617ED16A11890154817691709172316F716CA17A21985196D1A9A25CD22BB1B5A180B18301815198C16A417AC1854189818B217D016F117FF177F170D18C6185D1727198D162A16D91647186B16EE1615154414F81519161715871692168613D014D91586148E176A17E614C8179F1782160E144917BA165D188B162A17FF167217281616189E178A166516B018ED16DC1735160F18331736193A249A214B1AC318A317C7166E17A31822184E19B118F417621874180C17B5189217F417B017FC1766177716E3174318EC179D1680176E1642151B165717C0168B153916F214041620154216D116AC16B715A815781647162615001694168C17C3166316B7173417EB1545160B16A815CB1729178E172E1898162E18DB18A71A55262020DF185618CA17CE1628180F168D176019541825183217D517EE162F17D11732173517A71866182F16FA15CC161217E81587178B157C176F165B1445174D1512157315E2168F14CE166116AC1451163916D216E015921651170417451630153916B4164E1606159816AE156A16CC160D167A1633185D1648184B18451A19248521EF190D170419AF18FC17C6173E185D19C6164817E618EB16BC177817A71799189117D7176C184D17F8164618D8177C155817BE16E2151716A816ED16A3167F16BB15B314E0151E1612166B16D416AD1755178B16D7152F1627176C15DC168D16F4159A154F16E516F616D01641198E1604175B171417FA176E18101B3825C620E51AF0199117251860184917D2160A18C1188E17DD18D916A91792175C19B317DF173419A517401823173418B9166516DE171A16F616ED165C154215D0140C167114DF15821519156C155D162C16481784162215721739171216591670160C1879160B17C217DE17D016B616A6165B1736182716D1176318531820191626B722DC1BB118C517DC17C8176C173B17D71706187816B61621167D1604180515E71688171C17DF179418C6174117E915EC16D1174418D8151417F5143916CE1641167915E9159F13221681152415DD145217751786165C160416E71506165C178717C517F3169A163A1869163117C5188116D7163F17F3158B16161A6D1ACB26CC20B51A6418DF179B17201893160E198415EA16FC161E177616B917CF172C160016CC178016FD17151663160417AD16E4155E1762172216BE17B0164A172C168C16D7155115E513F015F515AC15A815AB15B217CE1602169E157116A416BC167417F416C716BA15E4175515C416581619166F175817D216C518BE188C1AE824FF20B518F41745195217A5170C17A6178F177216AC18CD1776169D179D179F1712186B16F01701198B17E3154617EB173615AF163A16E115F31526154C16BA141216F5151417B7142D157F155216461536163818B015A415771793168A1741175F1522150A164A166A173C17CA15E7162E17AF1533163C162316C6174A19FC2278217F1B2318301842190517EC173317311887184E1745176B1853175416AB18E418BE1823188218DE1670156617BF1741168515D816BB173515A716C8159A14CF17131767150614FD17AC15C216FB1416172317F115C01537176C15841869152D18551717175C15F61651169C163A189F16151523164616C21751187C1AA7252F23261B5F18E617C61943175218F416BB17E0170518CB16EE16F515C716B2163A17B91724165617B4165116B9164418F6175416F515581373160115E616FD15D4158F153C16CB15E913371811160215F8158416531409178F16F4158015B41686160616F216AD142317C4164B163016A81673161B1712176517EF178719CB258821B11AE6191D175717ED16B0174517A018B217231721175D16341823188515C41746176B175518B917531624179316D4160217C9142B14C117AB163A16271531166B178E159514CD1394164014FF157D167916BD13DA151D176216E5169914BF17751786160E173A162A16BD158B1704161F1648168D144118CB18FD1A4124B7207E1A41190F181417C217B51851183518D5168117F9179C165D163C17151832175C165A1643179B177816D515A1166417E2154A14C51538141F179D150716CA158B1552164C1423148B15F214D914B915C514F014F514F015C916B815F517C3161D1501165E178917C814C6153316B215F514BE16F415C1172A19351A6723A821ED1B58187C17F3168816D91823184018F5162518DF15B21692160917E416951771165217491776182515F216B619721883170E1667154716DA159E1700187316D915C916D813AB15DA153715D4154516F916B5178715B817B916E9159C150818DC1638157A155C175717AE159316D71495160B183417D517CD19B51BDC240422A41AB519B0176118BC17741760172618F116A6174D160017C2153F16D2151C15A01632166216EE14D9141B165617F416B81597141A161B1613168716CF16BC168616AB159E1455163316FF15FF155A154716EA144C16EA165716EB14141653168F155B16A8162B170F152415FB153B1705157716B6159616BB16B21AAE257221A919661843189517BF1600176F1858160517AB1672168D161B15A915A116BE167015AA17AE17B9161115131781163E16DD16131732162A16771513151317E416B417D81429151A140317F9144A159715F715DC14911539173C15F21554160D1641162A168616551687169217851495151A169216271717185B19001BE823B121701A4C1717182E18D7167E17B917E317CC18881831167D165416B6161F173C17CC172917BF1658171C158717D2142D175517A41441175E152416A6153D17A3161C163F162416771451174116D91529188E17DA137B1708165516A116081892165D14C917611605153E165115A715D7158616BC17E3159E18B118851B7A243E21891AEA17EE16FB171B18421731199117FD1690168516F0140915B516D2172816BF16F618E2152A17B1160017F1151417F117EC1504161E15D6151D156D16DE15D8136916D0147114BA1606168B148817F11502167B14B51791157F186216FB15B9151116DF14D816FD136C16AA166117C9154616F316011861163D19D8243922351B9317FF1871185D18BD17D6192819C31799172C18E71695153617A61787182018F517DD151418BC169F1791163F161E184F168E146B166818F915BC152015CC13DA162A152F14F816CA15E014AA17DB178B153916B315E9147D15D41521170516B115C014C7162D1645166517C616AC176316E4155117D619BD1AF1269422061B7619AE167319A719FF17A7187619B718C419081851178316DF1767161717C31894170516D616C6158917CC16991641185017ED15E416CC14671546157014A414A1138E157D15DD14A2154E176517851695162814B1136C150A15D9162116A416C815DE1442168C15DC153C17CD15F01871176F153A161D19BF1A9F24 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 F327E021F221D31F8520F31FE21E3F1FC01F4D1F951E0F1E021E421DD41E9F1DA01CC71E681E971C4C1ED41D741FD91D901EF81DDF1EBC1E4A1E061E0A208B1EF61CBA1DEA1C2D1BE31B891D071D981D261DBC1E6B1D121D9D1D251D741CD71DCB1E7B1E801E301CDE1D6F1D551CC11E171DA31F051F801EAD1DD8202F22752DEC2A2023E11F6A217321A11F0E208020AE208D1EAA1FE61EF01DC71E231EF71D0A1D671D031E951DC11DE61E521F4520D11D9F1F251E111F2D1EDA1EE41F8B1DF71DBF1EFE1DA21EB31C091FD11C1C1DA91FAD1EFE1C251DAD1D8B1FFF1EBE1D0B1E361E031F7C1D9F1EED1E321E741E241EA41F4920D01F7320CC203223A92CF72A6824F422CB21BC2013204520A521601F3922CD215521E91F1E1F8D1FAB1F6B1FEC1F4F1F451E4F1E3120A81F321F3D20A920A31F981FCC1F7A1CB61ED71F891F8B20861FB31F9E1E571F191ED51D761E441F1E1EC11E5D1FE51CCD1E131F611F8E1FE71EDB1D7B1F911FB01F4C1EA61E321F8F21B41FE92045217D24CF2EAA2B19277E23DF203F21BA20EE217B20FC1F8D1FBA1F821FCF1FF41EA9200D1E651F421F5A1F3521881E041F361E1F20C61F70208B1F3520AB1EFA1D9D1C711E4520941F8B203F1EE51DE51E741DEB1C9D1E521F291FA51FE51E7E1EB71FF51FC2202F1F5C1FC91EBC1ECE1DD41D561EF81E3F1F4E20C021D11FAF217C23BD2DAF2B752534216F2085201B213B2043209A2045200020B21F181F5D1E2F20AF1F1C1E981FEE1EFF1EDE1EB91E0D21981D2E1E8021D71E8D1BC41E8D1ED61DFD1D8B1F2220321F671D2E1E5C1E741D2A1F121EBA1FFE1D7B1EFA1ED91F5D1E0B1EB01FAB1F8020151E591F481ECC1E8D1E321FCF1EC81FB31EF21FEC217E22562CF629C6248A21B422C31F9C210620BC1F242152209020F720921E341F581F7D1F521F3B1FA61E2120CC1E791EB81F3820EC1D671F911E3F1E301E761EBC1DE81E321FBA1FD11EF11C1C1F4B1D4E1EF91DA61EC61E0D1F2A1F5D1EEE1E781E091FCB1F0B20791E3E1F2B1F551F0F1F2F1F511E9B1F5B216620F61FBA22B723AB2CE129F922AB2115216A202F206E2143200220442133204D1FD31FF41E9B205220E820551FBE1F2A1FCB209620F71E3B1F671D4F1DE21E1A1F431FAC1E4720E21FFA1E9A1FCC1EE91DB51DB01DC91D911D0D1F9820A71E721ECE1E6C1F641EEA1EDF1F281E731FA61E431F151F6D1E0A1F5620B61EFC1FDB1E11216F21ED21152D502A4A2471214322C320C61E651F832077200021E11E981F9F208F21741F4D1FB620FF1F8420C4204B20CF1EC71F6821A41E5A1EE11EA31E501FBC1FFC1E951EDA1E5C1F6E1F361E0A1EC61F6020241D8220871F111E701D9B1EE51C381FD21E181FF01E291F201FE41F621FE91EC51F881F621F671FFA1E70218221E623F42DBB2861231E22ED202221CB1F711EB7209021B520FF1F531F371F111F0420431ECB1E022076204D201B20C11E361DC01F261E7E1F0A1E141D681D0A1F6E1E371EC31EAC1F2E1FD21ED61D7A1DD31CE61D341F281E021F771D7E20451FD91EE61E3B1FF81D5320E01F1A21051F1D1E4D1F5820EA1E651F1E1F821FCA21FE21E62D972BB82255203F209320A61F2B203C209521052020219820E31EFB1F4B20631FF81F041FEE1FC61F9D1FD91FE91D5A1FD51D6C20F81FD41DF71FCC1DB81D8C1EA21E2520B51E111FA81DE41EC71E951DF41E841F1F1FD91E571E711F2A1EFE1EF621491F531E9E2079201D206A20AA1F4620B62053202C20881FE9212E23E92FFD29BC251122C1204E21C21F2C202020AD20A120042279202020591EC61FE61FDB1F511FB71F2F20B01D471F4A1EDD1F3B1D4B1D891DDC1D971E961D3D1DC41C331F7B1E8F1ED41E091D141D831E1B1D571E741DDE1D3D1E961F3D1F2E1FFE1FD21FC31EA41EB61F8420821E911DAB1FA31FE71E171F2B1E73207E2175226F2F132B5C2473211C2352200C1FF31FAC1FA1217621A62055202B1F991F671F38205F1F701F9F1F17223F1FBB20F21D5C1E971E771E061FA11E731D211D481EB31D7A1DAA1EC91D0E1E101E851D971EB51EA81F2E1E341FA31FC21FF61E661EA71F112021203E21401F65214720701FBF202820951F611FC61FE61F2C204124DB2EFF2BE22518224421712026202420E21EF62034209D1F7021A41FF92067207B214620D61FAF1E5D20611F741F041E0C21931F9B1F191F481EEE1ED71F351E511F181E531FC71F131EF51CA11EBB203B1F6B1EED1F921E011FB1209C20F01EC020551F721FF01D9A1E821FBC1F371F63206E1F421FB621B71F9D20AE219A24982C732ADD2495219C2111223A1F0C20AE2079210E21491F6F1FC81EDD1E5920771E0D2006208C1F961F2D1F911EEB1E8D1F2A20F21F5A1E071EFB1FE31D931D851CC31EDB1E871E931D6E1E921E3620971EA020E8201E1FDF1E4D1E881FDE1F49206F20921D8B1ED61DF31FB01DDA1CB91E951FA82090200C20C52070215D23A72EF22926246E22F6207B229F20C621CD1F4B22B51F41217421191F741F671F3F20EE1E7F21C821A11FA71E3D1E041F56209320021F0D1E641FE81EFC1D011E231EFB1F461F481FD81EAD1E1C1EB91E9D1F531F7F205220DD1ED61E931F121E7F1EE41EE31FA41FCC1E6720851FDA1E6B1F80208A1F4E21C31E29206721DB22BA2CB52BD525EE21C02056210F2217217621E71F6821F02195208C1E4A203721A021D71F59215020CC1F8721B421531FE31F491E7F1F13205E1FDA1EFA1EBB1E691E431FB61EF31E491E9A1DCD20821FE81F9C21F31D641E671E491F5A1E9B1E291F4E20121E02205C1F0B21C4211D1FB120B51F9E205D21A9212F21A321B8237F2DB92950250523AF229620C520AA20B42002209D202A2258216B2071208720A420B2205420AA20DF1F4721A11F6520D620E01F9620C81F031E871FC91F601F9F1F711FD920D9205D1F421E1F1DFA1D661F7E1F751FCE1E2E1F5821B21FD91E5620D81FB81EDA1F791E901F531F721FC11DC3208820FE20AD21C5211822D524942E2F2B86247122C71FEF20C321B620F220BD2009218C20C4206F207320E41EA21F571F5A209321711F5E1F5420971FC31F5E1E572005206A1F851F711ED11F4E1FDB20F11F061F3A1EC91F6D1F5A1ED51DDB1ED420311F7A1D0721DE1E201EEE1D7620F71D351F7A1DE91F3E1E5421AD203721AA20EB1F5B206321802155237D2F2529FA25F920AC218A214D210A22962085206220C021611F9F1F25203821D01F5120B7226F2075226521371F9A208121C31E5320891FD11F371FB01E2620F81FA2202F204920FB1DC31F1D1FF81F651DBD1F961EB21EAA1E0E1E8C1DD31D6C1E1E1F42202521F91DAE1FCB1E731E2F1E3E1F8C1F2B1F471F2A228D2112249B2EBB2B0A24C8209E202720B720162070203C1F5C1F1520A6209120761E43215E210B213E1ECD206F21401FBA1E9B1E6D1F3120371F511DA01C2A21011F6020731EA21F9B20491F381F741E661E5C1D501ED91EAF1ECB1D6B1D361F921D501E9E1FB720781F5E1FB51F4C207B1D871D3820191FE01E731FE91E02202222ED226D2D362B1025D522E121242146219B1F58209E204A215922C9209F1F8B1F1D20F3200C20CF22C620C61FDF1F76214D20F01FCB202D1F491FBF1E191F64202520752144210122AD204E20A81E211E5E20BA1DD71F0020BB1F551F1A1EBA1FF11E341FFF1F6D1ECB1E0C1FBC20B11F921FEE22A31FF61FAD21B01E0821CE216B22BD2D702A4024702310216320D820C920E6207F217E21331F7A21CE2062210120AD209E215F1FE1210B20CC206820B7204620131F821F781D0E1EF91F5D1F3F2162206F213222C820732016204C1F921E361F72202220361EE01EC31E7E1F311E831E0C1FE81F701E531F68204A1FC11FE31E451E4A20371FE9208221592127239A2D232AF0234821E721EE21F6214A2177209921F32082218D21A7203D1FB6213920AF20192025203A1E701EF91E461F4A1F2F1E7F1E751D671E121F0E1E14208020531F7E206B20C91FBB1EB12148205C1ED7203620971F391E061FD91ECC1EF41F821FCA1F3921381FD520A9218B20BD1F6D1F561E691FE51FE61FC620F321C22DE82AF7235822D1219D21E31FFC20A72164207A1F8A209821BA1E4D204D22762099207D21F61F3B20BB1FD11FD72043211D20CB1E6D1D721F971F4A1EEC1FD91F312006213B1F481D5F20AC20C020C72062213A20612103204620361F9F1ED9203B1E301F931F011F2920B21E1E2017210821211FCA1F27205921AF20AA23A42E1B2BE92307211D21A021EE20F91F6820D2213A2042221E21A41F621FF41E7B1F961F711F1D205622651F5D1E6B201C205D1F5D1F161FC71EF11D781E391E5C1F321F2920CE1FED1FF91F581F0B213D1F671FD41F9A2059208D209D1E7E1ED21E70203D1E221ED31E791EBD1EDC1EBC21BB205B1F1920A020C122F2226122512D8A2A3B248B21A122562148216C211B210921B01F8820BB20941F7320D0207E207621271F5B2013200F207721051F1A206F1FDE1F3620531E04205E1F5120E61FD4203520E820FF1F501EB71F00209B1EA5203220121F2D1E47204F1E031E0C20861EC81E451FB01D1720081FF71F36217A212F1F501F431F3A21FF20C123032E622BB92452215B209A217121E9202B21D2200A203421E7202B1F43200520DD1FE1205421F31EB920BD1FF91EFE1E9E20811F2B1F6F20631E141F6A1F7120DD1E342030202721E81EA6200E1FA21FFF1FC91E3820161F7B1E391EB31F3F1E4D206A1E0E1EEF1E931E9F1FB31E881F15208B1F8D1FEA1F5E207F1F9721B022A42D702B2D26FE201E2268217221762164227B21672009222E2034233E20BB20DE20E61F032151209220FA1F02200F2085201420EB1ED01D791EB31E191F9C1F6F2020214621E620031F7A20321F27201B1F9F1F651F811EEE1E3C1E2A1FFB1D871EE820D21E341E7D1F7D1F621FD21F461F761FCF1E8B208B20802162213624032FB22BB3242C2375224C2111202A214221D0210B21B71F3C218A200322D120B321D9217B20502124208D208820FA1F951F081F0A20DE1D911DB91E991F981E8D200F216821CC21401FCE1F751F011ECA1E57205C1F6F1FB51E2C20F21DC41E4A208F1FF91E881D601FA41FEC1F44205F21CC1F1521F520EE1FEE200D236023FE2D0C2CEC24C91F1A20F61FFF21A020C020FA21482069227920DB20C31F80205821CA2106214521D122A61FB620101F69219D1E021FED1E081EAB1EAF1EE61E1420342094206C2020206D1FBA1FBC1E741FB720EE1F0F21FF1D941F231F721FA51F0D200020C11FD21FDF1FB320901F471FB71E551FF02029205A207922C6228D2EDF2AE92311214820B72123200D204621B8209122891FE320731FC21FF61EE31D721FDE1FEE2079209B1E101EB4202D20F41EF21EA21F4D1DE61E8A1F851F3E1FFC1E0620C21F0A1FAD1E781D6D1EB31E0E1F4F21EC1DAA1EB71F0420701EE11E551E6820E61FB31DFF20862199217D20F21E1F1E511F7E1F12222E229D22502DB72A3E2666216E227A22861F0620931F4822EF22C1230A22991F7720542266224C2076209220BB20DF1DE41E891E0B1E781E15203E1FB61EC61F691E0B20581FF221C220EA20C11D171E921F151F9E1DC31E6D201F1EEE1E0D20961F3920FA1E971F7A1F3A1EB31F0220621FF31FB31F0D1FB5205A1F1520E91FF3228F23A52D232B08248321AE203021CC20D721E220CA202922AD21A5205421BE2013211521DA201C1F0621671FBF1E3F1F971E761D031E9C1F7F1F27208A1F821F431EE31F1B2073214420C51E0C1DBA1FE31ECD1EEA1F7020A41F1C1F9B1FBF1FE21F151E371F2C1F1A1F3E1F99218E20B11FE71EE41FA71FD620781FD7200522E322032E6D2B5125BB215C22E020ED2109209420D32124214220CA20A62028216421D520971F2321CB1F991F4720C41E0F20A61E771E5E1FEB1F881D5C1F7B20F11E4C1F63214221761FD61D2F1FCD1D911E841EC7201721291EF31EC51F0D1F2F1F5E1EB61E611F3A20CC20D520A21E391E001E4A20A820FD1EAD1FC12106225B22772E5B2B7E240521F121C82262207821EB1F26221C21EF20CE20CD2189209B2170205B20872065202E2067228D20991F1621AA1F8D1F16217E1E711E751FB71F7A206D20E221401F7A1DDC1E491F021FB41DDA1F2A200A1FBE1FA31EB21FDA20121EC51FE81E6C1E991E401F8A20441FCF1F1C1F3B2085218E20B62095227722D92D48294E238E22EB2028220C21A920AE1F1A201F2086215F2238219D2052208F200622C820C11F92210920F61F4121B120C71ED91F6121821EB21E801FA31EB31F1F1F751FA520F21C4B1C21209A20B31D311E8221D820AF1E1620DC201F2092203B1F311F0F20CA216721CF1F421D3F1E881F8D20D3202320A32026229A220C2FF92AF52358224222E021FD1FDB1EFA1F3E2087218722C7206C20D91EC11FB32096211C229A20FA21BF209C1F3C1F5E21DB1F561F4F223620191F1920DC1ED31F141F1D20061F731C301CCE1E981E9E1E51208F201820281FD11FF01D931F241F9B211E1E312059210820E41E201F2A207720D520C921D6203822A921D522AB2D752B1125132294212B2275211A22312243229D21FF217F1F771EBE2186200F20D821C520DB20F920B821031E781FFB20C11F101F6720A41F771F6C1F681FFB2029200020901F941DBE1DDE1D5E1F821ECF209F1F85216D1F1C1FEF1FA61F241FFC1F15207E1F161FDC20381F9F20D9201E21501F2F22D62029214C22DF23492F782B3B24B421A4215421C1209B209B206E232D206C20B5205420732080217E209622BE20F01F8620951F69209D21471FF420C21F541EB11F0D1EB31E6720D31F4E208F205F20431D8A1D351EB41DEE1E2F204D1E321F2B1F941F6C1E2F1F59206320691F141FCD1EB31E2A1FA01F8F20991F461F1B215F1E2D2126226E245E2D712B6A242E2267213F2037209B20AB20B120AC20B0215A210D20DA1E961F3D2009202E212A20D21F5B21FA1F2A206221B61F851F231F181F8E1EAD1EF51F131FE71F9A1F5E1FA71EC71E0D1F731E141E9B1FD11FF81E1F1E18207C1EF41EE81E8F1F06209020C91F0820B51E3E1F2C20D020042078218A20CB21C5224524832E202B062637225123A922D8218E216321D6221321601FED1EA81F002122218B2009220B21341EAA21B01F99202321D31FDE1F0F20101E9F1E81200B1E1C1FAE1F841FB01EFD1EAD1E421E381FA91D941E4B2019208E1F521E1F1E1C1E871FC8204C1F2E203F201D20DF203820F61F35205E1F151F781F7A1F53200C213225842E992B3424852033222E20CC20BE206121372154207C203420F11ED81E1E2035208A206B20B52045200B213820BC201D21D020E11E271EB71D951ECC1EEA1D1F1FD91DAD1E6920441DCF1D521F7D1FE31E0F1F20209720A020D1203C1FEC1EF11EE220941F3F1E941E6B20681FED1FE71F501F1C1FC220431F372126235C249D2C0A2CE224CC2213218D239D1EED20D7215820B91FA21F711FA91E6F1E2F20E61F4D2030200C21DD1F9E1F8F1F2F1F05214C201F1FB31E6C1FC81E3B1E9D1E7F1E261ED21DCC1FF41EB11E5E1EF91ECE1EFB1F111FAC20C51E3B1F0A1FD91E1D1ED11E7F1F281EF31D5A1FFD1FD71FD01F5F1F1620C120DD217621FF1F9C23672DE12AA5249B21AC213621A821E31FD720442093203B20561F7E1ED61F6B1E021F6C1EDF207B20901F6E1DBA1E5520C820701ECF212820931D1D20FD1DB31D9C1FF81E351FD31ED51C921DC21DBC1F851E6D1F731F0B1F931E341F8B1E731E8D1F0C1E6C1D1A1E191E9A1ED31EBE1E8A1FB41F8C1F1A218D1F9F1EA3208623912D3D2B30253522792194227C226F1F501FF62155201220CE1F2A1E661E9720DD1F3F1F2721721FD51F4221DB2028211421FD1F1A1F0F1F0D20A71F491F551FA51E461E801F381F321D8D1EB11FE71E0B20181F28216C1F8720FE1DF81E8F1E831E6A1F681F1C20BF1FBD20FB1D2F1EA61F041FD81F05217B204E21162170221C2DF42A5D2449215721A1218F206520FC2019216821A21FC91FE51FA0209E20AC1F4F1F6C20A2201922E01F582016218520A321FF1F4F1F221F8E1F5B1C1B1F111E0A1F311FAB1F931EF21D511D6B1FB41EAB1EF51F901E471F8B20E41DA71FB11F021F061F621FBF1DBE207B1F6A1E11204C1F0A2031222A21B821EC23B3237B2DF42A9925582230213222DA21C921CD201821B41F4220011F1C1F7320F120512058207C22651FC6208820571F1320662190200E20AB1FC8205C203C1FC71F3720DD1F271E171F541FC01EAB1E2E20E51D361E451ED71F1220151EFD1F0520601FE61D801FC11D9C1EEE1FF61EBE1E2021C31F1E1F99217920C5210222D023202F252BD8246222CB216620CC21B31F2F20F8209C20731F6720CF1F7820392042201421E31F8720E420C31F371FA221EF20711FB51FC41FF91F971F9720BF1F801E8B1EC01D3A1F621EBC1E211F0F1E901D761EBE1F151F8E1E321F781EF71EDC1F3F1F19201D1F491E561F021FD01FCD1FB21EC21F872099201521C8215123882EB72B8E251422822142217A21A4200D1FE81F4420C2212720451F501F2720861E9F200C1E2E20B21FBE1E65207F208E228321A11FF91D541ED51F931D871EA81E981EF01D8A20B21EF61ED81D411EC61D291E1A20541EE01EED1F501F761ECF1F531F6D1D4E1EFD1D531F521F1E1F5E2064205F1F091FBD1F9121132270248B2DB72A8D25FA21C4217022E420891E941F9F217720F41FBF20671FB11FF71FEC20A61EC31ED51F6221FE20D81FED1F291F99200821C71F591F151E441D551EE71E442004201D20BC1FA71EBB1E351EE81E471E5B20A31F711DDC1EF21FCC1EF21DE81C0920191E281F061F6D1FD61E3A1FC61F9C2031203A1F4F21C9200F23292EE22AFE242B22702000219A20632226213221671F672029203B20231FA31F7A1E3020C5223A208821C11E30207C1FB920AC1D411DDC1EF31D091EF81E271F821EC11D3D1F2D1F881E591E0E1D801D791E4820EB1E321F751FDF1F9820881E801F4C1F9520D51E3E1E2F1FB01EE31E2B203E1F701ECE1F8A1F7C22A91F0123422CCE2BA026C023FD21CF2021220D225521B522A721E0210E2005205B204E20A91F3C1F2A206A20B422FC1FB91FE420FE20EE1D1E208E1E6C1FB620091E951F2E1F3A209421801FC41EF01DC41EAC1E751EBE1FC8207B1F9A1E1A1F691F631F261F851F7A207520111EA0216A20921F981FA41F1D20C11FEC1E3A20D521FA22B82D082BE7246724A121072245211921E21F6B22F422C22122219C21F51FB920F41FE51F5421391FD0215821901F03209C1E331F3C1D8F1FD51EFE1F121E761FFC1E9F1F0F219E207B1FD21F641E521F361FE71EEB1E4D1D741EAF20291F4F1ED71E761EFF1EE01E1C1F581EB41E7E20D51F241E851E2B21B81F0F21C020C722D42FE02C28243F223721D521F520A7208F22C52164209F215D20CD1EE21EA21F3D220D205721C1210222E91EBA1F59201E20D81E571F911E131F601EA61EB11F8E1FCE2171212D20371F8B1E401F901E1B1E761F051F0A1EAD1FE21E6D1F301DD31DA81FBB1D841DC41EB420E61E5F200E22A71F7D1EDD207C1FA1214A226523152E482B76257921932236239F22682173211D20F420132278223B1EBD1F371FFD1FB61F741F75203020D021991F062125204E1E6A1F1D22811E701F1F205D1F8A1FCE20A720BF1F52204B1FA11EC91EA71D141F19200E1F1D1FC01E0620701E141F5B20B41E9A1E181F5820A31FBD1EA71F591FBB1F6922A120EC21A822CB223C2C442C5225462342229120C222E520B621B52239217F218D215E21AE1E5E1F651EA120AA1FC31F3522EC206921D41FCE20371FC01F151FBB20781F56202021E71F58200422AF1FC7200320591FA71DB61DB41E6D1F871DFD1D6B1E691F8C1FA41FA81F821F8F20D91DB320D21F301E7A20D31F132043234A21AC20B7220524612DAE2A38259322D8221C214321A720CE22D0205F1F0122E11EB520C21FA7206E1F13213320DD1F86208922E91E242136206B21F420E21FA51EDD1E5F1F2221CF201E20692206215F21F420851F6F210D1F031F9320181FC31EF31FF91FB61FD41F9C1F9F1F4220E01FDF1FDA1F4521DD20371E931D56213720D3218221CF23CE2D422BEE22FA214F21022227201922FD20602175218220E71EB31F301F7120591F7B204920ED1FBF20D31F721F581EAE1F11205B1F3320861FA31E111E071F8A1FBC207F214C217720DE1F8C1E9020241FC62098208320701E5420211FA81F3E20DA1FA5204521341E6B205D1F2D20C91FFF1EC5201C227321BB238D211723DF2DFB298A23A821102167200E21F820B421EC215F215521FC1FF7209E1E6420941FCE1FE01F802034211C20101F3720BD1F401F301F1621FE1E1C20951E5F20901FEE1E9F20DA21A71F1720C020FA1FD11EF61FB61FE51E761F061F361FCD1F101FA11F26206A20F31EA320CC1F8F20C720B71EA4216F200720A1211721C7234F306B2A86231B23C821F92130226C21C4211822272170218A1F04205A203821901F612094211121C3213420EC1F511FAA20CF221F21391FC41D501F3520921F352119200D22992085205E2033211C211C203420CD1ECE20771F0120C91FC91E0820D51FDB1E8B20321ECC208F1F7C1D9920C120AA20E31FD51F5F204F221225D92FEA2A342453224922182226224F20FE2118226521EC21F7209820A41E211FBE21AA21D521EF2158215B208E21962092217120B31F7820CF1F2A1E5821551F021FCE1F6C2103215220022039208E1F011F681FF91FD21E8620E81EF41E622004207B20CE1E671EB31EB220FD1F961F961F5620B920BA20BF1E9520AC220925922F9729A8240E21A2217B204C20262186210C2336218C213120BE2076201C21EF1EC520A6202C21A3211420CA210E212520BC1F1B20B41E9F1E6C1E931FC61FE31FA920CB20BD216B21871F741F2B21EE1E861F231F0E205B20F920061F851E941E3C20E720E2207F1EFF1F841F9F1F8F200A20472071210E21AC21A620E423F32D462AE6241924F01F69202B210E2132202C2118225222A721C220B121FF1F6821372075209C1FE221641F41210220D9208A1F2421BE1E2D1E2E1FD41F9A1FF11F6F1FD01FAC22941FCD1F0D202521091F92202B20DE1E0E1F0C22A81E741EAB1F0C21C920AB1FFC1F4420B320B720CE208220391EFB235320EC20C0232C24182EC22B7F230622A7203D2159231521D720FA212F2179226C224F21F0200D21431ECF209321C220F81E76219E20CA1ECF20A320E21E7D20D41E641E001EA71FCF1F4220E420BD1FDD1FCB1E511F1821081FC91FB820F91F511F5B20B520491E06204E1F9720C81E0E1F4421451F6A1FCF22A31FD81E5621B620382047230922BD2E342B9125B820EF20DD21D020F221F5201E223D2205213B214B208220DD20642149205321252181213420DC212C213B1F7C1EA220951F421FB61F3A1F051FD91F1B217E20151FB81DF11E8F20471F35209921A71F8F20551FE520A61EDB1E481F87200E1EC01E35218921DB1FEC1EB320BD2001226D205120DE1F4022B523762E2B2A4D25F021AA22C0209E21A622B721BA215C1F77231020022289202821A81F8921FE2031220521AF1FED1FBF1EFA201A20D71FCC20EE1EC91F901F2E1E4B1F7720A220541EEA1DD120E51FCA1E511E2E1F9F1F2E208E1F791F791FE71F101FE420CB1F881F441FCB1F9B1F981EED206B1F4820BB2017211721592188234D2E5E28D62359210E21FC229521B91F0622E51F39209C203C1F44217F20BD21A2207C205A21B420B221E21F7E1F1B21C120EF1E1F1FF31EBA1F4C1FEF1EFF1EAF1FC61F212093206A1FF41D1E1F171F101DF71C4120531DA91E8A216221D4205220891E6B1E7F1F201E47218B1FC11FA3207920422084203E206720CE220124422EE3297B24C122B122E2218B211E20E2219720DC1F2B21C5217A1FBB201A211F218C210521BA1F0C22C0201E1F7C21FD1E231F8820C9207E1EEE1E0020F91EA21EB620EE1FDF1E431ED61E721F9A1FE51FE41FEC1FC91FB11FF71E991ED21FB41D6C1E3C206E1F1D1F351F661EA621492024209C20B221801F861FBD21BF23C52CB82A512462229520B7215B222221E6203C218F206820061F4B2013212E217D211520E720E21FFF21C021CA204B207921C91EDE1ED31E041F68208A1F7D1F301E9C203520691E7F1F5F1F4E1EC71F6A1E3A20D9215C1F9220781F841D591FA91E641FFB1F641EDB1F041F3521CE1FF51FBB20BF20CE1F522019228E21AA22282D8F297824CB216C203E2106221A218E1F912177201C2163215320D92088224F1FA41FC721A41F4F1F2120711F502066201220921F0420C41EE51F0220C01FAF200E21FA209220441DAA1E40202820CC1EF6207620BA1FD11D5820821F6B1E6E202520CF1FB920E91FAF203B1FF21FCB212B207821C9207120B420B5219323D32C6229DD231F2251215120C92013200C21A5217721FD1F7322881FD71F3422C92021224020B31FB41F8F1F2A20A91FEC1FBE1F651FF21FB91EA420091FFB1E921E8C204E1FD81F3E1D721E4D1F0920581FCF209A1F5A1FDD1D7220941EAA1F7220D21F611F2520501F6C207E1F0C219B201220CB20BB1F5E2039200D2106231B2ECB2CEF2418220F225B214921791FC320492246212F20E121A41F5520E120592220212A21F2208A1F4620541F8220E8200220CF1F9A1F3E20FC1F711F241D031ED520B31FC820921DCA1EFD1F781F4D1FA91F7820381D641EDE1DBC20BB1E271FCE20B71EDE2017202C1F201FDA1E1820362183207820BE201C22AA203523972F382B252423213E206621E1202D211A21E82059208E2157201F205E1EC21FD0213A208A1F48216021131F461EAA1DB71FF11EF01F511F141FC51FF81D771E7F20B11F1D20F81F2B1EFF1F1D1FA01EA31E9720531F3920491F0320541E5E1F791FAD1FAB1FFA1EB61F761F611FC01F7B21D11FEA1F15214520CB2144217523E62FC22A19252E20C821E9208B2093225A211121FE20B920E120871FAA20872036215F218D21CE20F720901EE121CB1F7E20AA1E84201F1FF51EC31FBE1F061EED1E141FDE1EE71F651E641E6720A91FE81E2A1FA220272113201E20FB1F432000219C211520062013202521761FE51F4020E920CA201E218E1F0D21A6214C23D62FD12B65254B231923D821E1209B21542032229121EF223E21E220482229208A22862265210A21C321A81F711FF0215022FA1F0E1F151EBC1E8C1F931D661F9C1F692046208F21681F6A1F8C20E41F371F5B1F0E209B1F471EEE20C320B31F0F218D20F82187200B1F74222620D1217020201FC621E622ED208E211222A5235D2EB82A942488229C212B233B21D01E28200722A62147226920F4207F213322C621CF210B228B215B22791F2A207E204A21F91D761F291F741E9220C71EA41F951F0C209D2006202720C11E201FD820671F7E1EF920191F2A1FD4206021E0217220B320B41FAF205A1F84216121392015213A1F622122238520D420AA22B7249A2E1C2AE32440214821E62115215C20A02152216D21FC209620CF1F3720EF1F92217B20B921D320CC1F5D207121EE20681F751F011FBD1F511FE41ECD1FE51D631FAC21D81F6621EF1E3B1E811EC81F5C1F8820C820771F40210521971F30221A22BB21A4202D20742152215220C71FC32158206B204E20E121DC2081214524B22DB82A12248F21F9208420C2204A201320C82100215621FC1F9E1F012183210A221922FE206D216A204120B520E81FDE1F411F7220DC20BD1E221F341E7120ED1FE520D320DD1F281ED21D531F131F591D2B20FF1F0720D520E5202C218020FD20CA1FFB206D220A1F6C217621211FB320DA1EA9207520081EBB1FF4210823CD2DAE29A12499217621C220B7204421B6202720CC2166205120F1205821E4200921232149202621F220AC20EC213121EB2076205522AC20C11DE01F3E1F5B1FF11DF71EDA207721631F671EC720691EED1F1D215921A21E02206D213421DB2027215A210B22F31EAF2043205B212520AB200C2067213C2125213F224F227623792DBA2A3F247A23FD208A21E32164208022A5229B2149219B209B215421EC1FA122DA1EF320C5215A216020591FA32096206F1E8C1FDA1EC01F17206D1FC220AF1FE31F4820CE1F611F601F551EEB1EA71F8A207821CC1F8C202E21F3213C229E20DE1FF11F761F07207A216D205521A2217E20402080202E21A9213422C223732EB12A90244C21522140213420EF20DD2110210F228221D3202F1FE21F5C1FFE224721D820452041201D1FA71EAF1E6D218A1D901F391F071FE91F8B207E1E441FEA1F53201D203C20861F681F3320791FC51FBB20D31FD02055212820E3207020011F0420D91EEB1F6420E31E0421B71FB51EC72014210D1F88205B204C24F92DD32BCE2554218D20EE20C3200E206521C621C521D821D1215521C01FBF20E22018208420182195207B20A81F5A207C1FDB20FB1F591F4A209021211F021ED41FF01FF81E1F1EB41DF31E101F2620C51ED2205D20C620581FF820DE20A11FF2204B20941F851FA4202B2002202120FA20D420A320EC21F420FB21FE21DC24612F0C2B3E25D0220E21B9204321A91F4E20872001212E212821DE2000207D212A201E2152218F21F220EE200A1FD31EB91FC31D1D1FB61FD51EB221AA1F3020321E8E1FF21E1A207A1EF71D5B1E3220041F0420B5201D207B1D3A231E207B200A206A1F6A21A620331F23209A1F4A206420771FF520B120182185209821DD23252EBC2AF624D520B321CA21DA217921C51FE3202C21FF20CD203E20392085203E21E81F8C219820E6213322931F7E1F501F2D1FDB1F7E20761FB221D020DA211A216A20D020C920F01FF91E141E9920B21EE41E6120991E34205B2018215A205B2087201E2187207A20422051208020F820E01F7B21E120D51F0B215122C223EA2D212C5223352213221521BC20D61F83215F200D228821F4202B202A218021AB20E520F81F3321A6216721B21F4B20CB1F5D215A1F1D20091F8B21971F7E1FF71FB0204221421F6020531F1820F91F72200F22861F2B20DA1E7721A5200220E220BB1FDD20631F862037212A1FCB20DF20D7216E2170203B1F23225A21D5236A2F2C2ABA2456216320DC1F0A20A51F33200521F41F5921E41DBC209820D51F7F21CA208120531F5D216A1F041F7120E31F1020C91F941FC720C61F601F6D206320BB1F4820BD1F4E1EA41FFB1EF41F051FD41F5520FB1F101EA622502052222722C1208B20281FC31ECC204F2049207220502063201D23E41FC91F2D202023C02CAB2B16253622B1201621CF21DE1F6722FF20F620D720DA1F671F2C20072032225D21B01F6B20CF1FAB1FDF1F991FF11F2E1FCF20921FF3204D20F71FE01FC71F44201B2090204E1EE21C0F2098218E1EB51FAD210D217B205C20551FBA1F4420BF219E2076206921FF204A20512026224B206D1F5120C91F2420A022D123442D9D29EC24942081212521D62114218A219520082123228E20FA20491F16215D20142137207C21CD2075206C1FF820D420D31F1021201E4D1F351FD91EF81F751F721EA81FA81FC31FE31F5820761F471F48208220351E501FEA1FA31F692036205321391FE3208F20E01FC6207C1F18208721CC205A204A1F5E215322D322BD2EBB2B9F24B5217421DC22DB21DF21E5205622842117225222A7212021E5206121F71FC8219F20802120214F1FF1217A1F7A1FFC1FAD1FDB1FB71F5520081F121F1220E020AE2052200E201F215422541EFB2002205720812190214B1FA020841FA621762039211F209C21572150208B205221642158213421A8215A22A2249B2E9D2B8D257C21A920E4206B217521AB2134221A223C217220522008212B207E205A20781F6F206520D81FF51EDE1F191F041F9220C61D9C1ED91F1620831EAC1E9A1F8D1F0F20DF1EE11EF71E751FA31FE81F80201B22F01EEB1F8E20041FA6201421B2208D21FF1D811F2A2125204821CF1F11216F21C51F7E21F8210023652E3B2C40264A2153207721C8200D20AE217522CA205222BE214E20811FA221E420E81E2121D420AC1FEE1F3320AF20AF20861E49201520221FA521911F091FDA1F67206B208D207B1DE21EFC1D7E1E181E9920D520AE2013200B21071FDB203B2108208E2099200E211B22851EF11FD92024211B20F91F32211622B420DC23172FE52C94257D226321F62138225522DE213420BD20941F1B21C61EDC1F5A216C209D203821131F2C20201F331E181E151F5E1F241F0E1F2F20CB1F54217A20E11E99203620561EDF1C381FBB1EA11ED01F851F4422D11F8A1EE91EF71ED5215621B920821F8E1ED41F242289200821BD2195210D21F020AC2091202F20F221512D802BF02449246F214D2125203D214922B120E11F01219B20281F741E9E1E5220BC201D2119209E20F51F1B1FCB1F3121051FA01F7A1E161F1A207D1EF21F6D20A01F751EC81E171FAF1F941E471E57204B1E0622481F571D021F761E481EDF1D341E6D1FC021D41FF621B421A421C42048205120D91F4520BD21A022A024D32E032CF024E8215222D920D720532196217D217B20631F9220E91F941FC01F872097209720652150209720851FB8206320F11FCC1E2D1FE21E721F371F961FC7200F1F6F1F7E1F581C4D1FAB1DBF1EA21E221E8A1F801E581F531F691F56206E1E011F6C20572117215D2098208520DF20581FB520C620BD1FB820012248238E2C9B2B6A23E22061206421342046224B200821502197203920691F101FFA20DF20E71FE5201E20FD203E1FDE1F2A220B211D1FBB1E9E1E4620621FF91D791FEA1FF11F6D1ED11E8B1DF41EB41D741FBA1E9C1E861FA51EA31EBE20591EFC1FA41F4620D91F8B20FC1E96210520F41FF221E720FB1F7A20D020B71FFA21FB23F52BD62AA4257A222E2283225B20BE222F20BE22A521921ECB1F76217B201420F22046206B21F020C320B4202F20AE20DD21EE1FA11F06200620F81E9C1FD31E521FC21F0E20721F731D67203220121FAE1DF2204321F31FAD1F901FFA1E3421D82051217B20601F7B21F420941F0820182092206721C121E91F372069204722262D712A852510224720F720A71FB81F4320981F03202520E71F6020DB1F83201F211E20D21E4C21811F1B21352054213D20731E3A20EC1C331EBA1F8B20551E7B1FEB1F6F21E91F8F1C691E481D7120581D931E5220611FEF1DB51FD32079206720321FDF20DA21831F482222210821AE209A216B1E1E20AD20DE2085224022962DA52AD425C0214421BB208E1F2B1F21214B2137207821CE21991FEC1F4121A620B01E29203020F220C51F131FF01EF71E1B2066219D1F311FDB20E9202D2037208F1FA91F7E1F131D6F1D2E1FC11FCF1E3C1FDE1FB51E3620411F051E1120BE1FEF21781F7E2037204C200C203921D620DF1D0420E71F761FC5209C21EE23042D6A2A1126C2213422F421B521B21F34223C22F72008203121F720A820F0208A213720D120B3203523FC202320D221EB20C3210D2192208820AC1F8C205920B020781F89205C20BD1F1B1F871F5B20E120C01FB41F651FCA1FA41F0E1FED1E0B1FC0217B20B51F622129219B2061204A208A20E2208220DC1F302083210A23712C3E2ED7244F21832166220A2010213E206F20B0236A21F220981FBE1E04212A20C31F1F22FF1F8621E620792051203721C820F920AA20BD1D601FA41F541FB7201420E61E171EF91E6F1EC81FB81F481FA71FC2201F20461F0A214A1F7A1F1D20BB20DE1FB41FCD1E6721842031202321CF1FC020D91F501EEA20CE202522BE2D252C76265821B721DB1F3E215320F6208D216D218D22CC20E51F5721BE20442127205121DE20C6203B1FA120B7216B207520A421B71FB61EF3207D1EBB207A1EEF1FAC1E731EB81FB71D581E4B1F8A1E161F7B1F001F571F2C20C01F411F80208221DD20FD1FF11FD120FB20192138210D1F7B203B1F591FB0208C21CB23012E682B3724F4216C1F5A2020213F2011212520F920B220E1207B205A209A21132231209021ED2029210521352037205B2092224420541FD21E861E671FB71F331F6A1F461FB41FC91DBB1C7F1F431E791D111F2121361F72203B20FC1F9B218A21DD1FE91F7A200521AD1F1620611FC4204B201F1F8D1FB21F9D1EFE21C924AA2DAF2A0D25B32190220C239F22D520E822F621D321F81FAD20B020C81F9121B5215920F71F10210C21EE1ED31F5E1FCA20221FC920EE1E5B1EC21FEC1FE31E2A2162204F1E8B1F791E811D281F19204F1EA720FC218A1F341E951F431F3B200D208421BB20851FAB1F871F35201820712034217B20D620CF1FA0209F203222402E582B9724D4217B238F21652328227E212D22FE223B22C620CE20D81E4E202C206A204B20DA20CF202221601F50213A20FC1FD520061F702005205C202E1F8F1EA120DE20981EF81EA91EBF1F661EB41D0321201F5C20B11E3220DA216E20F41FBC211821FE21D71FF2207420DB2072220B2128214220371F85212D226D22D62DC92B84266723CF2050210220F8229B215520F8205D21AB206E1E7920E620842157200820C620AC21A9204821D720CE20FC20A5204E203B21E120461FAA1F9A1F3E217E21C61F711EDA1E2520AF1FE01E9520F420B11FE81EF51FE1209720871E2521F720F71E151F5D205921FB1EBC209C1FB9202920411F1D2157214F23892E332BDE257D23D222AE219421AB216C20FD20EC21E8204821F7202420F51F3720921F922166213820841F6D1FEC239521AD1E611EF41F881FA9206D20BD1F3821902029202020281E1F1E721E741FD41E5B213820CA1F86205A204D1F7120FF1F7F20A420E820BE1D7D1F2E1FD01F9B21B91F04218320C81F8B20B821A523A12CD12CD926AE23262324220A212022D7200823912206211C227A207B2152217B20F31F851FB421C620EB2188206D209D1F5920CE20831F4F219C20EE1FFA1F4221622053218F20F11DB41F691F481F0420BC21B5219C1F6D1F371F881F321F8F213D21CA20E720A020A41F281F8A1F1721C320CE1F741FF31F97204221EE22012E9C2B78253C2224239421FB2071212F229F21E61F512050200420C2216321491F8F1F5D1F2A234E21F21FAE1F0D20F820E71F851F99208620EE1D2C1E6E1EF21E45208C20C51E391E2B1EA9203F1FED1F0D218B20BC1F8E1FCE1FF81F392290214520B61F122101209021F01F5920A41F681F6720612022200B1FD4212723782E4D2A6025ED21C71FA4211B229D2121224A224922332160213C20FE1F2321A4210E2057215722B521DC20E12296204E2265217D2032205320551FE51EDF1EAC1F4C210720731FCF1E751D2D1ED91FC91FAE2152216B20C01F3020F51E30211B21D4201021FE1FB61FD020792245200220A31F92210E20B21E3921BD209224FC2EDA2AB8245E2130210721EA2023228E204B214B210A200A2063206C205B213F210B20B51FEE210122C9210D22C220C71FAE1F29219120B81F3520C71E2B1F4D1E751F541F081FDC1D0E1E801FFC1FD01EEE1F8C21C52000201F210C1F491F9A1F1321AF1FD31F271E5120B020FE1F5220E51FAB21772185209320E5214D24082E1B2C4B259E22B020A0221A2182203D226720B52143205E20EE1FE51E071FE81F582092217122BA22902063208E229C201B1F8D1FAF1FCD1ECE1FB61E091F6920A71FF11E771E531D431E4F1E951ECE1D251FF920421F421F351F6B1FF81FCE1EB21F951FEB1F2F1FF61FDB1F812125212E205A20C020071F8C207E229322D42DDB2BE023B522B420A120E620B020ED20B021C9210A20A01FD41E06202720461F9620C321932092215020A0204D21441F6220951FEC1ED31E201F1D20251F9E1F27205F1EEF1D491E0E1E4E1EE51D7E1E9C1F2321C91F191F4D20BE1FEF1E841F171F4E20CF209B1FB7200F20032063200B2134204C2007219D20F721C823EB2ECF2B27251A234D21BC2143206420DA1F0422E820B320D8208A1F9B1E521FD5203E20D720BE1F722122201920F621B120CC1F1E218D1E571E1420C41E631EA91DD01F2D1F0F1DDD1C451D841ECB1C5B1EDC20B71F2B20EF1E07214C202C1FE81F011F5F1F40205F1FE0208720B01E4A20F720FA1E472104201A2192225124DB2DDB29BD24EB20DB21BD21611FD21F95203921C9204921AE1F791F141EC21DFD1FD91F65208720C420B51F1B2018202D21F11F0D1FF01E571FBA20A4208F1F7E1F5520F41F701EB31DB31D391F8B1E3B1DF0200A224C20231FBF20B11FA71E5B201B21F31F4520731F7E20321FB41F2420E2205A208920232005217521D823152E742AF9231522CB1F8621082072212B229F20472132218E20B21FF21E7E20CD1F2820EC1F8023E120DC20D01E3E20DB20D71F011FE11F0420C11FA81EE01D231F2C20A11EE11DE21E8D1EE61D3E20F11EC222AB204320E31F32203420721FB61F611FDB1FFC2151205821C01F5B201B1F0A2117226A23C9215721432183247A2EC92A36237D20C621B820C820351F6322F120B921BA216B223220CC1F1D22C3210B20F9209C1F9722FA20191E2621BA2141212920E71E321F06203A1FC11D0A1FEA1DD61D661E3C1D161DC41E781E851E0D21811FD41F3C211E21631F3D1E79200A20EA2092203D20C620431FA01FA321451FAF20A821911FAE200F226F257F2EE12A55239A2257207B21AE2014209521F520CD1FC8208720D8218020492104229E1F8E202C20FC218321DD1F1C20FF1E2B1E2620711FFC1E041F0C1FD31D1F1D1C1E4820C61DCB1D7E1ED51BCE1F1E1F96210720681FEA1E7F1FF11EC31EDE1F6C208C1F2521961FC6211E1F1C201C1F7020FB1F1E2242205521A422E523FD2EBD29A72481215221271F83213B20861F95203E21C3211C202A202D214920A31F0F21BC2076216621C51F65208320FA1FD81FBF20741F211F081F681DBF1DDE1D321DE61DC01D661DF41DF41DDB1DF91E6B210822B7200020D81F452031202D21C6217C1FA71E471FEF21C920DE208620AE208A204A216820BE20F6216B24B02F1E2BF2230F22ED1FCF1FE91F6B20DD21F920791FF7203920CF207F1E321FB21FAA1EC1215C2157213F202721D21F0A2291201220AB1EF61FC91F1B1F871F031FDD1E911E981D611E241DA11FC91F6420691F6B214820BD1F7B20F11EFE1FF520C020B81FDD1FD220AE21E11F20207520ED20C51F47208D20972147229F22472EB729FE233C21CA20572036205F20D01F6021881FE11FF21F9F1FD71FC220EE21B82057204A204820152013206021A61F111FF91EEB1E771E491F281F631E471E521EDF1BB71C001C181F8C1D1320A81F22206F212A1FE11E911F1D216E1F0D21A720921F4E1FF81F801FAB1E35214D218A200F20F51F032015215521DF23F82ED82A5E24F0221E20661F7B2073206720CF208720C220D5211120281F3721242170204420F820701F6820411FB81F022175204D204F21E41E491FC71E091DE11D041D021CBB1D511DC61E921E081F671E591F931FFE1E0D2165220B20F61FF920DB21EA21071F6B203D213A208E1F35206B1F6F1F5420CB1F3D21F1217824B52EF92B6F235821F3209720C8208020CA1FAA20A320AF1F87203F20451FC21FE51FFB1FF71FD620C61F0520D91FA41F9D20301F531F361EF21FAE1E861EA81E701D641D211CA51DE91E811FA81F071FD31F85201F1F3F1FB3210B20B51FF51F4E1F9321822107210B2042205A20C51F24214F1FD21F202173211A210B235F23BA2E87292B248022E02065203121B41E05209F204C202C21ED1FC6216C20A5214320D320D0205221DE1F8A208A1FB520D922CC1E4C208F1F6320241EC11E1D1F611D031D281D6B1D471DF81ED11FC11FBA1E4321B91FD51F431F05204B1EE41EC3216020E12028209E1F0121D6201E209D205420BF1E9820921DA91F2F215D23D22EE1295D25612097217D20D520F020881F2522091F441FC9209721FE208920D8214B1F2320B620AF21731F741F2E20BD21FF1F611F381E281F861FB71E1A1D041DF51C3F1E2A1D671DD81D081F2A20121FB21FB820C31F6E1FAC20761EFC1EBE1E8821F81DAA1E581E7A1F331E66202C1FB721DD1E4B1F17211A20AE210F23192DF12969255F2176204520B720532048207C21642025203F207A211A1E051FA21F9B205D21F01EAD21DC1F321FFE1F1A1F321FEF1DCE1EA11CFE1FD11DFB1F701EDB1E2E1E2C1E5E1DA31FE01E361F8F1FD41ED21EA41F931E9320D31D9A1F1C1FD02007206D20DD1F8221D31E63201C20C91F2A1FFE1FD220C0228B22B423D62ECF2B64250F212C214A21C721D61FE7206E210B21EA21BB20E81FD420ED2096200B21D0216520D921B01F271FED1F4621AD1FCB1F771EB41D7C1E601F1D1EA51F811FDE1C441D7C1E7C1DFA1FBA200D1EB720F720711F3E1D3620D61F8521C01F4C20E81F9D203B1F2721DB20DC1F0F1F2121BE1F1721651F332184207E227E2DE22A99240E22CC2019208520E5210021C522B221AB205D21ED215720E021A8200321B4203921CB20B31FE7205B210621D01FBE20B61FA31E4B1F9C20AF1F8C1E201F691EDD1E491E3E1F2420ED1FCB1EB91E0420AB1F3A1E0D1FA91FC420DB1F931FCA2063200E1F9D1F5D1FC31EE1205520DB202C21A11F61210D22B423722F7B29BE22CC21EB202E206621201FCC204222382178218720A02012206420012142205820D3216721221F491F31204420B51E7E208C1E51206D1FB11DE71F941E331EDC1E0020591D2A1FCA1F251E2C1F591F1820F41E0920B520E41F761F6D1E841FB01FC11F6F1E9F1F1E1F8C1F1320411FD61F76218E1F712158216723742D802AB4235D202D22C42104219C207521972201200920C7212020DF208620FC20CC21E420EF209E218E2014208D21EB20B31EF81FB61FFB1E041FC51FD91FCD1F7D1FF71ED81D8A1E141F041FC41F0020E5206820CA1F111F8A1F2A207E1E0D20CE1F3C1FDB1E571FC21F6F2010207F22E31F522089203320F5207E213924682ED8297924F8227520F42010210020C81FED209821C720AB21A21FAA204B205E22A920DB20FE219520402111206121741F811FED20DF1E4620E61F051E561EA11D9F1E401D371E5C1E381E2F1E6F1F2E1F08204A1F201E1120BA1F321F551F9F1FF620B21FEF1F9820CA20781FA11F701F36201821F31EB020332124212622F42EDE2BAF251222A520E1209520D120702025214321A81FE31F351F8A1F56216B1EA91F712069203321E62106216620BA1E1320F7200B21CD1E4B20581E691FD71F521F5E1E291FB41C891E9E1E341E1B1E1720D620B71FAF1F5B1F6F1F271F5C20572081201C2019206521A71F35201922A91FCC1F7F20FA1EA21FEE228823D32F3E2AA924C521D020CB205D21B01F2022C21E23204C206120B21F26212E21271F261FF020C01F12214D1F641F3720CF1FFF1E4F209920741FCF20DF1F6820C71F931FC91E681E621D611E4F1FF51EB81EC91ECD2020202C1FFC1E6E1F871FE51F8620E81FF61F301F1921881EC71F7C1F4C1FBC205E20A21FB421D921D823612E672AA1223021AF22E32025214920FA20E520A91FEF215F21A41F1621FE20DE201722BE1F6F211E22D320481FD7203321B01EF51F731F6D1F4A1F511EB41F411E3F1FA81F9520101E611E121FBA1F901E851FA021311F0B1FE6203020F320E320D51E9D1E631FD01FB420C020E61E5320A320261FD51F911F9E1F1521D322672CFC2A6D253E217E21E2220C200421B1205321EA21A8208D20D8218A209D1FF3214422F52166215C222E20A21E68201021991F051F30208520401E8E1F641F071E8A203720251F6D1D7920F51E4C203F1E88206D200C1F221FE520AB1ED121B21E4F2103210B20DB1E2D20D31F1D207621F31F381E861FB41F3C21A121ED23202F862CCB249F21282102234A204C2141200721DA20F920E41F1E20E31E881FF81F6120C1204C1F8720E81F651FAB1F82210B21821FF91E8A1CF31E331E1620051F301F831E8F1FF31E301DF8205A1FEE1D021FC41FAD1DA31F861F6E1F9B1EBB1F8B1F091FEC1FA31D2420E31FC31F421F8E1F831F3B201F2060201C21BE22052FDD2AB02428233D203620302026218F201022AB2084200B20B71F49219621AF1ECA206B20A420AA21C220AE1F7820A11FAF1F5220EE1D081D1E20A31F2C1F841E5D1FCC20B71EC61DEF1C0D1F891D7A1E791FA91F1E1D251E4A209D1F1D20CC1D4A206E20AA1F28208B1F651F371F13211E1F471FC81FC21D3F21FE214024532DA92AAF24B722512191203A214622E321972148201F219E214120DF1F84202C21A320DD1FC51FE0202521DD1FB61F0220C1205B1F0D1E0B1F861D3120F21E941FFC1E081FEE1F151E561D991E7B1E411E721F5A1E7D1E551E431F5420051F4C212F20431E491FD7200B211F1E181FD41F3D1F541E3A207D1F5521B422D723172D8A2A6A251B21A120FB1FAD1FED2102214521E71F0D21C01E991F411FFC1FDD1FBD20AD1FA92080204121581EAD1F91227F21AD206D1F501E5C1FE11EFE2023214C1F351FEA1F251D1D1EBC1E601E141F461F3420C320CB1EB1208E1F7F1FC71E0521DD1FB21E661E6D203F20D21EC01F5A1E7F1F36212D20BC20BE22AE24E02DEC2A86247C22BA20522103211D2050200821C81FF5200A1F1D20FC1E6F1F271F701EAB1F561F981F0D1EA81DD41E6B204820C41EB51D251F0D1F181FB91FE61F3E20E61F6A1E9B1D2C1F351FE41EAA1E411E2F1FD41D871F0220311F001E2E1F631F9B1E211F0C205D20541EFB1DC21E6720FC1D8C1FAE1E831FB81F9723BE2E882A8123DB21BF212921292048209C219B1FA8206020F41FB21F421EE51E2420E51F0A1F05210D210320361E90200F20B01F2B206E207D1F8B1FE91E3C1E55206620EE20061E881E841DBE1F551EAC1EBC1E3A1FE91DDD1E9920631E4E1F831F801FB21F671F651FC01F5520EB20B61D421E6D1F1F20F32086210523F423252D902A1524522034213421D31FD720BC20C120F7215221201F961F6A1F282079206B20CE203520D51F69202F1E9E20F21DD21F4720D11DCB1F511EF51ECB1EB820DC1FF11E811F891F571D9D1F661FB61E3D216D20E41CA41FBB1E0E1F421F13218B1F741D78208C1F351E491F661EBA1EED1EFC1F6020CE1EB321E021AA249D2DB12AD0244F219D2057212B21CC208E2221216120D11FA11F711E611E18209621D71F53207A225E1FA220D91F9F20731FA620A121691F801F021F761FA11E0320A71F681D471F3D1EE21D7A1F6A1F221EA120801F631F231E6920EA1EFC21A01F461F4A1F5E1F691E8120891D771F0E20C020F01EED1F7B207821F01FAF22682ED82BDC2411215322B321B121F520FC227C22FF20DC2078212E20981E9A20D620DD21A1215421191F2821EE1FBF200120A71F8321A21FD61D3C1F9B21481FD31E601E181DFC1E291E861D571F081F591EB520EC20DC1E861FB41EE51D921E061F8E20F21EFF1EC21DB71F351F981F8D204F20DA20681F081F3C2030234F244C30EA2BD524D122E21F9F22D8224A21D2217F22EB2113237C216120C51F4B219C1F61204A22EB20161F0C20041F95204A207F1F8B21BC20581F30206A1EC01EB51EC31D8F1D951C0C1EE71E341E9F1E6120A520991FDA1F3D1D7F1CFC1D461E26203E1F9E1F1E1FF61D551FA51E471F8A201F1F2822C920C51E4E1F75222724152E ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 042817222D2226209D202A20071F4A1FBC1F031F561EC31DDD1D7F1D211F861DBF1CAE1E6B1EA01C5A1EB81D891FD81DD01E2C1E011FDE1E4E1E1E1E0420BB1E141DEB1D3D1D531BFA1B911D091DC41D421DB41E501D621DF81D5C1D411CA81DBE1EA11EB91E2E1CDA1D411D7B1C021F211DCA1F1F1FCA1E0F1EBE205322902DDD2A3A23DA1F7F218521A61F4F20B820BF20AD1EDB1F021F0A1EE11E891E1E1E6D1DD01DC41D7F1DF91D201F681F5D20FA1D921F1C1E271FA71E2E1F9A1F231E031E051FFD1DB21ED41C1F1F561D7F1D5B1F911E6A1D521DDD1DFA1F1B1FFB1D4F1EAD1E281F181E071F381F6A1EAB1E801EE31FCA20CE1FB320BC20B3230B2D932AF7238D228D216B20AA1F6F2034211D1FF52154213321EB1FC81E691F681F001FCA1F271F0C1EE01DB81FFD1EFA1EF61F7420521F2B1F691F631C4D1E931F2B1F1620181F251F3D1ECB1E951D601D321E161FAF1D7C1E051F7B1CBD1EEE1E0B1FD11E981E7E1D241F061F311FD41DF41DAE1E3F214C1F8120BF201B24342EE52B7A2799232C219F21D220D721BA202C20DA1FB41FB01F1D20FE1ECE204C1E891F991F841F2521E91E351F711E1820F61FBF20DA1F5120CF1E2A1EA51C8B1E3020BF1F9420461E051EFE1EB21D371D7E1E541F461FAE1F0D1FCF1ED21F1020F420741F8B1F991E8A1E2B1EEE1D301E221F8E1F3020AD214420AB218523DF2D082CA3256621B5207B201F219C20C020202152201E200B205B1FB51E4520E91F911E03200F1F531F2F1F261F8421BD1D5E1E6B21F31EE81BEA1E881E521E3D1EE81F8C20A81F701D841ECE1EE01D2F1F0D1E67203D1EE71E331FDE1F701E801EE91FC01F8D20941E791F9E1E5C1FFA1E621F321FFD1FCB1E502022229422A72C3A2A5525EA21EC22F61F152243207B20EA21B120F3205D21361F8A1FC41F2E20FF1F911F0C1FCE20F41E141F1D205C208D1EBE1FEA1EA01E6C1EFB1E711E8E1F7B1F13200B1F571D7B1FB11DF31E4D1E161F3A1F841F921F941E371FAC1E861F1F206520021FBF1F771FFA1F6C1FB51FA91EDB1F87216F20F71FF0222424C42C7F2A3823072278219A2096209C21B82028207821AC20911F1C204A1FC020A8202321981F3F20801F4721DA20631F8F1FD41DD21D191F291F7F1FEC1E8620D71FF11EED1F511F691E0D1E421E281EF51D3D1FC920B01E971E851FC41F971E091F4520861ED61F0D1F5B1F541F041F3E1F6120D31E4920371F3C21FD21ED21752DBF2AB324052289229520E41EEF1FC5209C201F21301FAF1FDD20D621D61FAE1F03217320DC204B217420ED1EE61F8B21FF1EF31E621FC71EB61F4220761FD91E061F641FC81F681E821E03205620AF1DA2209E1F551EAA1DB11E9C1D5F1FE81EBF1F691F5A1F7D1F1F20AF1FEC1EFA1FBD1FB51F711F0F1F8721D0210F242A2E7029932484221B215F21C21F811EA820AA21CC2045209C1FA01F051F21205B1EC11E4720902071203920061F661DEF1F541E1920D21D1F1DFD1D971FB81E7C1E2E1FF01F761FE11E1F1EE41D161D321E9F1FA11E3A1FB91DE0204D1FE11E361F951F731E8A2047202721891F251EC31F7F20111F6F1F7C1FFB1FEC21F421592EC82B822291208720E7207A1F9120FB1FD721022062216D20CF1EEA1F1920961F3920301F2B20DE1FEF1FF01F4C1E8D1FD61D772021207A1E31202B1EE11DD71E121F5520131F5D1FB21DFE1EDF1E701D141FC21F551FD31E761EB71F901EEF1E5F22951F6C1E42205A206F20A020681F1C20D72047207920A91F2B224623F32FF0291926AC2288209821FC1FB9203B20CC20D8202B22CF208720C61EE81F0F204520F51F05204620131E801F921E2F20AD1D911DD71DB41DF61E281EB01D781D871FFC1EEB1E301F731D401DE51E721DCC1EC81D441E8B1EFC1F3D1F411F7B2027203E1FFC1EF11FD520E81E1F1EDE1FAE1F381F991F821E8720CD216E22D52F672B8524AA213623C520421F2E20D81FA6215421C0208820931F901F681F6420D61FF41F7B1F13224A1FDA20361EBF1EBA1EC61E291FCC1EC71D581DD71E0C1E681D2C1F011E5F1E5D1ED61D0D1FEC1ECC1F761EA11FBE1FE51F381FE71E37204C2045207F217A1F9021A120651F13213A20C71F8C1FE91FEB1F94209024B12E1F2C1F263E224221C22032206120951FF42091209B1FA1219D1F29218620A621D620EE1FDC1EC520E21FAD1F5D1E2521B81FEB1F3F1FB71EC41EB21F951E521F1A1E911F0920671E4A1DD01EFB20521F841E4220F51E571F1B21B620DE1EFB20B91FCD1F241EB61EF51F941F901F7C20F31F9A1FA6210720E020FE21ED249D2CEE2A592529222F228522D41F74205C212F22862106200920761F431F2F21171F8D207D20E31FEC1F9E1F281F581F24204C204D20E11E921EC220551E171E441D5E1F521F431F1D1EFB1EEF1EAC20321F31216221F41F361F0F1F26201820CA205721301E081F621E6C201D1E5E1D261F3C203B21232173209821ED21D923802F182A5D24AD22DA20802296200522E31F9E22C71F1D219C21FC1E821F391F3C20F71E85211522C31FE11E701E401F93206C20191F3D1E861F611FD11D311E391EDC1F641F6D1F2F1FAD1E401EB81E9B1FA41F9F20B920A91E071F8B1F321EC51E331F1D200720551F9F20D01FEC1EE31FC220B61F5721151F4420A421C922402D852B9425BB218D203F21A32132217621EE1F4721D22162209D1E8D201721C321FD1F44213A20D81F6421CE21551FC51F561EAD1F3220221FDA1EC71E801E311E621F7D1E3E1F471EA61DF2206B1FA91F8C211B1E551E4E1E561FEC1ED71E751F5D20741E0A20621FF820AB211D1FE020CD1FF9203021B321D12097210324492D5E2966251223C422AA207220D5208F2015205020F921302170207B20482096209C202120A320F51F4321651F4A206C20D21F9820CD1F0B1E661FE21F7E1F851F4E1FBE20CE20591FE81DDD1C291E8C1F971F181F941E4C1F7B217E1FD41E2220F41FCB1EC81FD01EAB1F1D1F8A1FAB1D80206D20FB209421AE21FC2180241B2E0C2BB424C82275206C21FE21192104212E217D21F0200D21EB20CF20191FEC1FCE1FBE20A1211220DC1FA92015204C20AD1EC42070209D1FF31FE51E27208F1F73213620231F8B1E2B20C11F1E1F0D1E481F2721B81FEC1D2E21241F711E6F1E2421821E971FDD1D5820F11EAE211321AC21F9202B20E420A1219A217223E12F90296B26A821F721F62185215622ED20AB204F20DA219D1F68206C205C210520AB201323A920FC22B821C11F6B210422E91EA32031207420EA1F1B1FC62064202121AD20C420171EAB20CB1F8020A81D4020181F2A1FE91E781E0B1E411E121F971F7B209A21451EB020481FE31E911E0620B61F6B1FC51F352207224924C52ED82B07240921F120A82005216E201F21751FC81F7B20EE20C520F51E7A217D213721E51E22216221A91F9A1FFC1EB31F9A20E61FAE1D201DC6211B1FAF20EE1E762032210620C71F2E1FE41EE51DB01E681F6A1F1A1EE11DC51F321E1E1F0E2064213E20182048204A21331E2A1EAC20971F6E1FCB1F2F1FB02088227823D62D4A2B0225EF2202228B213E2112209320F82064218522FA200A20CA1F232047214820502326216B202820EA21B5209F203721851FF51F1B1F961FBD20B2201D22F1216922F320D520031FEC1E0021211E2D2066201F20F91F411E6620431F9F1F6B204E1F741F921F63218C2058205E232F209E2068225A1FC2216D222523382EA32A4124AF230921832047212921D420BC219C218F1F7321E12093217620F8207921A91F81222D20D0209D2000216A204D1FD11F9D1D951E5F209A1F8521AA20BE217C226B2106216C20D11F091FA51FE1205B20701E111F9E1FC91F9E1E1D1FBA1F6020FC1E12200A21E01FA4208C1F1B1F29218F1F8221CD21AD219023AD2D9A2A4C24FA2178228A220F22D32131212B22AC214B22132298210920662215218A219B20C920FB1E3F1FCF1FD41F22200C1F711F6E1E471FDA1FEC1EB8207221FF1F60211921E620D21FAB22ED20031FAC21DE208920581F1820E21FAE1FF820212100212D226620F2211E235721D4205720801F5820F420EF20DE219F22972E3A2B1B24CA2238223422352049213322F820F71FC220D021681FC920FF22EE201721132252200F215C207D208F21C821CA20441F231E1F207B20031FD720BF202F212922ED1F2F1E1121A52178218221F421F820D721FC2029212420B21FA921621F30209520F41F6A21D21F1521AE21B6210820B020D3203C2272210724032F7B2B782477219D2125227E219D20F2209A22E720F822A021842054209F1F1F2056204F20F62009231E20991F2D21E0201420F01FC91F2B1FE41E651FFF1E672021203521DD20D120D1201920E12151204220C02076210121B9219D1F741FFD1FE0215A1F291F3320861FCD1F1420C2220322DB207A2165216F23D423EB22D72D1F2BED24FE210E237321B92125227A21D72150203E21982171203B21862132215622F71F3221A320F320F021EF1FA8202F20B3201D21551F1E2171207F210221AD219421FD215821781F01212221BC1F8B211A210B20351FAA21591F401F2A21FC1F51206F20AD1E502181209E21A222A42268205A2053203522C8218E24AF2E8E2B1225BC21F5204E22E221A421DA219221A620DB21CA21D41FEC20C520EE200A22ED215E1F44214F200020BC1F822191203A206921BA1F60209A20C6214D204C214421B9222F201E22682029215D21582082212E20701FC21F0221CE1FEA216320B61FF820732003213A203A2195215C21EA203E218D21F02044227B23952ED92BD1267B21922219223C226322DB2242225421A922412127245821AB219821D1202B2255218D21D220A5201A2186213D216820321F02201D20AE20A020962172225C225222D3205222FB20E421912019218D20B01F3E20601FCB201320B820E322E2203F20A7217F217D21A52173214C217A200B221E22DC2291222825DB2F332C33253624C0231C220521F021162227233D224D201D224221DB227C21A52282226A215B220C21132159211821D120BC20A3219C1FE91E33201E2145200A22E12243237B231B21A521C721AE1F3920C421B12009213A20EA21CB1F4721D1221322BF210320A421A921F32137228B23CA21E922DB22912170226B248124DD2E032DF725F5203521F3202C23BA21F521222325214E23A321A321A4207C217222DE221E228222CA23FE20BC21AA201F234A20F020F820F01FB1202920D120D121422287221623AF22C821EE21BF206D21B022EE210823F01FCF218521FC21B72246231023AA221722AC2272235A2262228921E12166234222A12261247424D92FBF2BF4247122D32106238F216F2193221D22D623D120F221CF202D217720451FE920B021A422BE2106200220AC221B2259215721552232202221E62144220F222E22E1220423F1219A210920EF207D21EC212324A3201021F321F022AB214722F521B5232223DC203524E424B9258A245622572190227E22C424AC24E524B32E172BFB26A6227D234A23B020AC207E2027231724BC243123D9208521CB23B123A021FF2147229C227F1F6A201A201F20EC207C22F821F7203F229F20CF226A227E25122403247720B5201D2228229A2049227B2313219E2135226A224A23BA2189226A224521182300245623F423CC232323F323BF226F23F8227625A325EE2EDC2B2525B0220D22B822F521E4223F22CF2148231E232F22BF2217224A22BC221D2335212423AA211F218B21102172204A21D622CF22B1227822842227224F24EA24F32596248E2265207023FB22E323D624E92460232B229A227B221A231C2180221E2230220D234826ED259924FE2340241024152574234224DE24F924662FBB2CCB263C239223692284238E21E12125238322072238223F22F422402326232622D92393224222142388216D2326221D22EF2273238F2094221624B423F12468272D27F024832255232A22A1239E242D27632614223722A422BA211D228721712163220224C5258126A524F423C923E025E425CB23E72360253E25B5240C30242C562515220A23BC234721B222112130231A2274225E22812305224723B2222423A023F022DD220025BE23C122C62393224A22E4237121DA21C7233625EB263327CF28122572222923152495252325CA26A025FC226F222821E62123235820F5218621F221B2230226082756258D25BA24012580251824CF23CE241924A22EBD2ABA240A24B0229B23C5229522A7214122C2222D2489241C23C722B622102377259F244F23CD244D236B23C12419241922C122B62433225823C2259C26A92805287C27A927AD22DB21CB2615292D28DE2780280126BA22ED226F2347221D231C226722E624CD271929C1273424FF2412255F2525254E23B823632459245A303D2C69250C24FC2355235C213621F122AB22F62321257423BA220F215E227A2392241F25F1235725842311237C22AC24E9224722B2252124ED246C281B28492AD8295F29DD25AA219321FF251F288A29FB2A0E292A26322333238320B02160211524AB214F2533289C275D26A325D4253125AC2410253E232024672338241F2FA42C9E262F247523C0239D238E2451252625D5242A2590221021F923862282224D24AA23B2236023F2233421DC22C224892394222D24B624D326EE28582AAB2C622B64293E26FA217D228324C2285E29C42B1429AF2865242F2256228F211121D2220B241E2578265A28C325E425132586242E226B24AF22C522902354259730A52DEE2684242E243B248024092580253E28BA24B724D9249D232523EA232E235925D023A922D32314236E24D326E524CB266125B6234D261C278929432C542C0B2C312A7B27422296220B25F3264529182BF728B227022545234D218321FC2214245B25CF2634279D269C25CD24BC243A235822A523BC206823B5241A279830A22E08280B26D624CE23E3248726ED267926EE25BD2676252D23E1212E227F22A92204244E232B2467260D260128282A9528B626D9254F279C28282A902C9C2BD42BEF28A925E723A9240926A226D8266B28D628CA268C2365246B217521B921C123C4250D2895272E274F24D3238824E124BC23FC24932309253E261729B233CD2E822A8D276027CC266E27F827BF2739285D2623241D230F23D823982329230B25F124072399272327BA28492ADF2AFF291928D5247A26EA2A232A832BC82B592A2C27B4243D24E924582621257025F92692266425B222AD219120F7214F234F2327253A263B2670263C25AB246425CA249B24FF23572356242226EB2AD03472311E2A7226D22607250127BD2736286727052609263625F422D2214C23E3232F25EC26D628082A9C2B4C2B502CE02CE72A8B269C245A255C28DB29EC29772A97273326D526312425257726B726A925ED25F726A626962511255222AA21ED2115252F25FA248925F626E925FE265227F82669261527CD244927C629792B013351321A2B2C295426BC282B25C62778280227F02693261126D923B0228E2400254E272729F12BE92B772B612BC12A002C4529C025DC23F725DD2656273C2848276D2542243C269425D6251B259C2684276B298129722AD2262D258C23DC220A2228247C268D263C2797288F28F628252A0E2A482939287328D128FB26CA29F4327F30F9290827F72597260C2832266327102801292D29732767244924472382254227E12AFB2BA42A4628B7282E2A722BC1261E27A3244D227925CE24AD242126042573240724CC22CE239025A8281529D12A092CF12A1D298A276A2428236224B1232425A9278828F9283C29B629D32A8D2A40289B27E825AC2501266A288431672F032985268F253C27E027BC257026B629AF2924296C271723B0223B264627BC27DE2910291128AC288328D4290D2AF226B5237D22F0224C2371230B242A23A122D0239F233C22E924A7271229DF2B842B932D422BC32A422623257123E722442480260529052AB22B2A299529A02ADC27D3254A268F251426FB24B2257E2F0F2EFF276E257226932705270327CB28582AD52BBA29C3279025D3252C27E827222867289F27AF28A826D427BE29032AB528B9248C22EB226E23E1204B24C723A124A124D924C82458267627092B7E2B502B222C9F29D628472792238224FB23D72349255B27DC26732AF62AE529C929AA26AA242326D8243025C026F225A12F462D4729AC274627382937299F29252AB42BF32A2C2AAF263124B825B727C028DB28692982253F260C2769273B293B2AF6260424DD223F248F24A8247D268327F3267B2441259926B527E129082D092BCB2A64291829132789231A2587241223D621ED237623342544270927282667278524A2225224692314246B24A4259130FE2D8C28DF285F2A082A802AE4282B2A832CF02BF928A126932441257326CF277B283D26C725A1267F260928112BAA2995257923BB23D623B8245E273428D12733272D25F525EC25D627F729942A152AD729B3297F262624ED23FC22D9226423A422BC23ED22592200240224BB24B023E12100220023CE221923C72392253A306D2ECC2A962AA02BFF2A3D2BB02AEC295F2BC02A392A1926BF23F62325263525B2270C24AC2597258C256E29A62AC12A652769239221EF2255256125CA274B28A427CB253827112539266E265427AD26B5262A27E423242394230E2310225623E522D120DD21382169234E2377225023C222B5214D21F321FA2306256D277030742ED52B622B4B2C0C2D902B5F29582B062D2E2A60272625872327248525912702265626592637286028BB2789278B255025F224DA2365241524CE24F5267F27DD27872643265A256024EC249D24F824BF230925A42336210B234024F7228E226721AB24CE22E323A0231F2346225D228F225B23BC23C5224A252825B227A6321F30632CB12C002C8D2C4E2C222EAA2C602B26285426A4243824E02397262727C229DF2CBA29452A4F2650261C251A2566210D2123238B2258231C25C1250B2540243125162587241F244B2238229A229124F12282234C242A25F42660251B2638259626BD24B7235C244C23A2225623BC22CE22B6244D256D282F260F2A13330132292FB72D272C092BE02BC82B512A6C2A5F28BB262224252431264528AF29B62A672B302A582BF1268C24E124792412210B235F226623F424EE22B724C324692660283C266F25E223C82350221622AD232225CB2401258D26322867282127F9250026D1253623CD25EA239F22EF22DE23D225E026C7261D28322A282C7635E531102D472D89297E298F28A227022675273C27F925D125A926632623296B2A912AA12BBD285329F5277E24DD23E2219422D12025233423A82417236825BA25C0276C2AE62AF2284027B32388237423B0238B2530255127862AF7297128B42612250E250124DE2332227E22212435241A24FF25E72A322AD12A2D2AF62B74370934532CB92A7D2865275A2685252927E425E7241D27E1264A25AA2522277D2994271E289127FE269423DF23CC23C5238D229F239D23B22421244425D326E227D12B1B2DEC2B0D2A552743253B238223B0262628FC27B729F5282E280C25F62464261D24942240235C2464221D24072737266B264D2A4129F9299D29762A8833F3324C2EF62A392BFD2A7D29BB27C0268525AC27292AA82B9626B326E1245B2589245D2450252F25C8260F241326DD2514247A2509295B265E27C22791276A28232BA92C622CC52BF327882469240725A928292BA02A1E29492742273D2525260028D725AA248B24DA249724D6233E254A258726992919283F2787271B275A2FE332962D9D2C262B8F289929A227652792282F28F829FE2A4F2986242B24E1225F2535253D25CA27D6266D288F27CA2815270427C226BC299129DD298B29BE287B2AD22D182BD22AA127DF24A8234D2632298C2A6F289F266E251D26D7264F270928C026F526F523C926DC25762312253924BE245628D725BE24A326B6270430F92F5F2B6B2A522A352884277226DA274F26F22526296426E6266B2525260D25FA26DA26D4260028102B6629472C0D2B7C2BA729F6287D281D296A2888284C28D728B52BF32A5D2921279D24FF274328E229AA2CBF298627A926EB26112872298629CC27B6265726CC263C262126CD242222C0214326B12524273126DA272A31D72EEE26A3267D26EA2660242C26CB245D25D326C2268C2558263D26B527F625122789273D271D29322AA52B2F2B172C042B1B29C928CE28F7271D26B1254225B726F9279E27D325172451232527DF27432B422C1E2BAE270E27DF25C0278529002AE829862AD42717286725B8248B2311230026B3282B29632B2929FC298733D92CE72614268425BC24D32480245F252726B026B8277127532971286E290B2852262A2664277E29562BBB2B742D622C042B5A298D29972726285F25D2256924CE2387258B26E023A024EF25BF2641274A29962AAA29602899255325C52613271B288A29082BFF28872898251E258F258324C22834291F2A202CF62AE32C6D37DF2D33287B28C826D1258C2551243825D226B6265128C227CA28D029A62A2727E42506266326CC285529CD2A2D2B482C592D8029CF2517231124E72490237E24802335257224E12477259627AA28B5287729A228BF2A9B28342601252F241A26EF2673274F290D276327F92493223926BF275029C12A722B622B4C2CDD2DAF36C52FBF2A542963280827C526472451261A2782273A29F7288329262768266927FC25F2251526D2269D270E2AFE29812A4F287E259224FB23C521C424BD220922D722B524F024B625AE276829592AD029222A022B2E2AD8299B25CA23D424192585267F26A9260F268127D1257D256C262F292D2B9E2B4B28FB28982A852CE635CE2F6F2CF729AF29532889261B2774279A293A299C2A4F29532914281D2757243725B2245B25FB25892510288427112673246E24892269227922B123BC2372236A24AE2489268F287F295B2B542DCD2AEB2AF729EB297A28A82667236C226123AB2639288F285A268E2728266E26D228422ABC2B7F2B052A2C298C27202A5A345F307E2DFF2D422ABF2AF32AF52900285F28EB29682CCA2B9E29242927265C27A1256E25FA23A62598234C26A824DC2436232324DB21DA218623B324A724D124E82303240E28DF261329152AC12B2229A929C628EE25D0249626672246229724B92773299129002A5029F727CE274F29202BB028102C832756275F2AB92BD334DA32932CCB2DAB2C712D0C2F1E2C722A9C2A612A782C492CE8299B286B28CF26AD294D299A2665236B252125FD227D245D24C4226D2402241E25622522278B26CD260A2786268E2722276827D228D326CA2643273826A025C72504251F2380258327262B0C2B702AF12ABF2748273B2C412B94292E2BC2298D29D52C362BDF364C31E32D8C2B7E2CA22D372C2A2D962B6F2BCF2AF3281D288226C6269C28A82AB92ADE295A27A725DC2352250F255C23CD22EB24C12484268A286D28FA27D2282229A528FC2637251826C626B624A925D626A9257527932676271724D02336257B283C28CD296C2C9D2A9627FF26952AD42B372D132B302B1B2B642DF32DC036D62E012CB62A162C032A862B2E2D1B2CD32AB726B2281B250F270A2616288F276829D227E6269D2467238F23FE22422516243924ED269727762A102BCF283929C12AEE2A9D27E624BF261D256B23F722BC246F2667278F279A261325E62471240228AD28BB297529862776266B26572AEE29782A502B282C902C0C2CE92CD834722CCE2961280A28492A2A2A40290C2BDF274426A325FB23A7263126392862270E27D2264525162639243224C9263C26AB241E25D026162AAE2BCB2A252AC52AA52A022A7A299326A323A424CF24092312248F28EB252226822766268C259F25472539276E29E32782284C2645274829EF287328C728372AEB2B552DFB2BDA33292E5E29FF28CC292F2A1A2A81289028C92566243B257026C924FC2535269E26DA264126DC24352704278A2585287926ED266128202AA529A92A742ABB28EF26A028BD2764251024582434252A269B270329B7298328DC254B24C623F12428233D2487270D27672682256D242F2806271226F6268D29FE295D2A492B942A03316930402A262AAA29442B292CB029FD277F26DB24452573243526B826B2267B2772268B275F27342A222B072AC929122C612A432A4A2AB42A702BA029BE287626F0287C28B0255D261D26A3251928F227B92A4B2CB42709278925AD23BB25DC24C22498254D24BC25C1243C276626B4265727DF27F727232A512CA6299F288E30CC2E792A7A293429252A052B6F28AE244B265125ED260E28E026AB26C9277D24D6259329472A8F2A342B30294929732AE62B602B6D2B8229612ACB2A492A8E2AE22AB42A342A61265926FF27CD28A627632997283526F023E52695265825CE2550246D2357242C241226C1258D27F9292E297029072904291F284927CA271C30B72EEE29952AF42A8A29142980267426F327BB285D28092B9328F7269327812564271128532A882BF62A78292C288C28A3293D2A8D2A1829DA2A532AF729B128A72A832A5A2BA627352724275227F22511274F25BF248F230827CC257A256C25EE2306238D23FA23DD2668273C2AB82A49295728E12510264625A6251027DD31B830332A652AD02BA32AB8282E25BF26202A4F2BB32A402C58291A282E268B263126AD28722A4C2A7F2A27287B274F287F27F5268A26D22703288F27F324CD255529D2298C2BC226C12501268424F1239A235A245022ED239123FF25AE231C234224ED21142424255326F327DC28262A272AA8276C25F724722623253528CA33292F372A442947291C294D27D227FD28E129A02A282CBE2A4129AA25422521273726AC26D829932A86271825FA23A625B32420253324CC24A8252D248B2435278127E6282B28EA241A255723B6229E227624BC23BD25EB244B257B236124EE23952318237A23B225CA27B629F12A642CB0282126DF25032522278827742A3736CB2E482A762767282027B026B229D429592A1C2A8C295C29FD26C2269126AF27E3285D2A722921288A249B27E9247A24CC229824212397230925ED24AD2304257526DC253B2610239D222B245223DB22F723802603284B272D27812682260527E126B4243625A127862AE42AC22B2C2B79296F270E2655240427CE28852B9337D62F382A2D29E7286D287F28192A5429532A7F29862A5928F226C0277126562ADF2BB32A5C293A29B726D72494267D26AD23392353228123C2246623A32578252826B825062670234D234E24C3232A24EA25B027A928AA27762AAA2A1229A72912284B27E12574269C2B2C2BAD2C282A1727F5263227FA252F28B129992C9135F82E4F291728F6263A2A262BD3291A2A3C2BE62A872ABB270A26DE2529288329662AD329EE286029962755270B26E5251E235F252926B825DE2799264627D725602587255D2571254A24EC249926AC26A027692B9A2AC72A782C222DD32C0A2ACE28F0257626F0251A290E2A3A2ADC297226A926FB28A127E528192B7E2D3835A52EF42945273327092A432C092CF92CB92C132CB72A3728FC241F254E25D4275E26AA27292787277F29D92BEB29BF2640261627ED285729D6287C29B726C2254A27F92560282727022629264228FC28752B2F2DFC2BE42DB22DC82BBA2C1A2BF02833260225D4262B28C328BB28E9290528A3271D29DB2BFD2A7F2ABF2BDC336F2F94289D260E276C292C2C962CB32BC32DF32B162B5827C2246626292733282328D926DC277F288B2A042CB52A2E294D287B2A7E2CB22A062A8727AD272D263027782845295A2871270329F3290D29D42BB82B722C4A2D392D352D3F2A9F2837257025EB26A4249B287E2AFA28152A3C28662A0D2CE429572A872AF7298633832DB128562605286B29C02B912CF22BF02AED2B42282326FA25BE27E8288B298829A82741277428F929712D592C352BC62AE22C592B2E288127C325A5250224C6250C29972A75293D29542C2329D029A32AAA2AB3289229E42C282C182A4D2866261A263A235B26EE28842BE12ABB2A9F2AF82CE22C102CF82B1D2A7B29DF32252E48281D288127B0293B2C0B2BD52C972B35295027D7258D27F928E5293A2D16285B284A28832821298329372B4B2AB2274D283F27E3260E261825C2265F26ED26A72794275828572964295328D62693266D27022610285229592B5A2B9028C125FD24FA243227EE2A772BE12B622CFA2B4A2C152CB12B742B212A512A0134AE2F9E2A7128C028332A412B402C7B2C9E29F428A92768272E271F2ABA2AEE2DA22A5A29792804296C296E29B528BC296A25252743265A254126B427D026E527C727D427F62781294F2A172AC4299827B7254726C4250D270928A1272229FF28B32636272D265128F8291F29422AF529EB291A2D222DA42A3E2C0B2AE02BB3337831212C7F28A82723294D2A3D2ABE2914295B27C1279629FB2A052A2E2B9A29D4278527BC284B2A822B982A54295E26F62506251624412532282528DF27A62959297B270726FD258927C52738286625AF26FF25BA25A824BB267D2726279B28C1272B278F27BA28272837275F26882766284029642C5C2CBD2C982BBF2B7E3490309D2B2A2ADE288429412B8D28D1261126D526F228702B0F2C2A2BFD2BA029072AB929EE2A202C272D1B2A8C2757258D22432309243024DE287929982BA729C9296C29EF298F2711267A2632288F267126A22649260024932A75296B2A4929F027CC28DB28BD276B27F125E92541261E265F282929082B172B232BB92A72324B2F672A8F27C628892AD92BCA2943268E2666284B2A7C2C762B5D2B882B5C2B0629042AC4295A2C3B2D8E297827BC24B123B523B924A024B528182ACD2B452B212BD02B0A2C5429E7260E253627AA25C825A327CF255228F629A52CCC2B552A9A28D72792263F26D225F925892627275527FB2866283828F7295A2ACD290E32853034281D28A929C82A612A6A271D2720260A2A182C7A2BDA29972ACF2BDE2A8F291527D1278C29F92A7A283527C32429255D239F24BB24E8285128B2287F29522B662CA229082925264D255A250227642A3F290B290C28FB2A022C462B622BB628CF261924DE24C62521250D284D296A2B4C2B7629842758299E2708286A32092F3C2A5D298229D129C72810260326E327B1285E2A2C2771283A28F427F7299A28252616250A288426ED25A9266A2580253125FC2568282F294229A72ADE2ABE29E82942289224B22448246B268A27BF29FD2AB52990275C2BBD2A032E692D272A0C28F323A323A026CC274229FD2A552B9F2BCB2D86297A28EE262E2875305030BD2AA12A582A722A7729A3266729322AC42B172BA428BF26EE26C92678297228A425072612265D267E265E268726352641287327232A6F2B6A2B8F2A7F29E5285D273227BC23FF213B267F293C292B2B3D2DC42A9F29812A362AC62B162C6B2CC8281926B826C527F128F929082CF12A322B772CB02BAC2A3B2C922B2A33692EC42AF8279A28D227CE2753270729DF2AC22CD32DA02AC329AE27D52805285B286027B427FD260227672665288228E32790293D28B928672819283B285E27E825CE26FB2508269F260C280029762AB32C602C25294E29A22A452B2A2CAF2B542CED27B8264B26D92662291D29BC28DC2A6C2C8B2C952B122DEC2C1C2CCA358E309F299027D826222834278828E129712D1F2D4D2D3D2D8F2C922B612AA02A4029522B5129E5291D293627B02AC429C229962A4E2A912994283A28AA26C126C3278328B327CD2746289A2A0E2DDB29882C732B402B722CB62C162A8B2A00290B2A1A283C2758252D283729E4285D287329B22BA22C192CA22B902BE42C9A35F72FAB29B825B7244A251A274529692BFD2C862CE52B652B4D2BC32B192A662ABC2A9A2ACC2A372A5A295C291C2BE22A562A132C4F2839275B2725285F27AB285F29E4282729AF2831292D295C2918290D299A29702BF8285829B629EF26CE270628532725281C24C225DB27692775282F27C8282F2AF6287C292D2AF22A7C35532F2129AB2478235525AB260B28D22A3C2CF829912BB32B462A7829462ACA285E27A12A9A2AC8284A29222A7C2B422B7A28F82801282026E0280A2809282D29E7299828D628E7269528342792266425A42782275027612649273325D42623270327DA271128AD27FB277D246126E8276A28A4272727EB27BF28C2273E2BD535F02F4228D925BE24D4269728F52A312C332AEB2AEE29E52BB829392AC929EF276C279228E725EA261226B2257A255026D3254225DE2421267E269D2887283626562765260E25AF248127CE26AE26B8278627A029492607247424BF24BC281229372A0A2ACF286D285A29A0278928952ADC2BC12A982911288C277A277029E3333D2F6529542901274027A827CA2AB42DFC2BC52B3B2DE12C102BB629C127D5269B26FE262E25CF254925AB242C2575263624F724E823C724D726A025BB261F261525FA2368254A2661272A270628F22A4B29532B70273E235A254C26D0277928C1293E2C792E572B7A2B4E2A442BF62B532C202CF72A7629052AD729702B9A3472307A2A6728ED2713277F28922B312D502D242C302BB72BEF295C282C26D72518258A24B625E624372501246A25FA2408256D2446250925222687256B251A263A243B25FD2508232E272D2753297A2AAC29AF29C926A12534263D289E2AA42A5E2B3B2DCE2D942CDD2979284628472AD92A312CDE2B4A29192894274928D5303131962A2D28FC25C12667278B2B7D2B052CD82B512AED28C22571240C2670257524EB2598253127D22569260D28F8269425CC26DF26B628EE264424F724F4258E26FA25B8261A2584276127D129632A5129692970265E255C274C26F428CA298C2C372C6F2CC529022A6D26D5254A29F02952298F29CA289226D527EC29E8313C31B82CE229552876271A26192A5629482B0A2AF3250F26F92683256F25CE269A2684288B28B229D12ADA29A829D629C1281329AD2AEB2A11282D261F25D2269028D5296D2A49277A287928CB27A6263C2929290F279525D22502269A28F728E52A5B2B902A6A2BC228B624A92434255326452814296327DA273928FD2971346430972CB029A926D22528254626BC27EC265827C2271E27382765268227FF28C2286A27102A7A29EE2BE62A4B2B5B284F2546280C26B5279527DE26AD248E27D229BD2C782BD526F2265D254C28F8241326C1270C27A025BE27212901292129BD270C29482AA9277C28DE256425F524FD263C259F28FD29462BA12C6A2BC1340731FA2CAD29A428E826B82577265229D42A182AA12B122CA0293629442A052B2929A9280C2842291E294228952680258F26AA28AE27CB260C2793264A261C28F728862A2B2A2F2709262928BA282C276327BB283D280F2A672AF0285E2A502AF32B56280E276C263A268F244725FD2419237427FA2818294D2AE22A5D2B9032D730082DBB2A6F2B792A932A3D29DC2BB32C482B5D2B9D2C012C0B2BFE2A7B2B6F2944290C298B2B092A3A2897282B277F28C8285D28D7263F25662654272C29DB284729F028172859287F294F2B842B372AFC2A082B892B252B9B2A932A4E2A1A2C522A6B28C4284F27882562243424C22591278D282D28FA27C5276A28973031330A2BEC29972B362CBA29742ACC29FA2A922E862C8E2CA02AA728F62805283B27302A9929582C4C2BAF29CE27CF275128EA28DD273E240926D52623287E2A8A2AE22763254F26D526EE287329BE28BB28792AF22A152AAA2BC8293B2AF12A132BCE29312AEF287429C5277C25C625D2244A27F32749275A290829A628FD320930A62B4729D82A2329E129B329DA2A502CDE2C812E5B2CA12A4B2A2A28C727C527422A1E2C312C0A2A432AEC290F2891275A295E277126792972283F2A44293D2B4A29D527AE28C4264627C8270C268C269D2798287A29202BD12A5E2A482B0F2C072CC42BC22BF02B6B2AD4281F274D255428F528092AD42BF92B042DFE34792E5B28F22738268627E128EA28662B3A2BAA2CB22CAE2C602A3E28B4278F280228E42ACA2BEF2BE92A1E2955272726F528BF273827E5273428F328BB284E284429ED291B2940275126E428B126082478257728A628CE2A592B6F2BD62C772CBC2A462B962C9C2CD9296829E4260B27C526AC27F629D92B212A232D5A2EE1341E2D482843262B288129FA2AAE2AA12DC62C9A2CCC2A142BD829CC26FE26B2270D28CA28EC29292AC226E5258324BE252D24B226C3262A270A28A427F6255728F327EF2561267B258D250527D726E42376263C2884263A260128EE271529E128972AC52A292A18293B2790268B258C2515279A28E92AB02B262C542BC92AB634542E6C284427A72956299D2B9C2BEF2A9E2B252C352BBD290E29F6255B266B26C8272929B529FC27F4267324E425D424AC24B4261F26B8282228942795250425F526372777245F2433250126D0230023F0259B24F425032519276C280327DE262A29EE29942BA92853273126C0251427C226CB28F7297D2AA42C532C982B3C35352FDE2A602A41298C2A1B29822A1E2977276D27C72755271E26FC28CB2878284C281F29872906297E2742277B266226F72696272A287B2ABD2A2D284427CC26EA2734275025FE23BD24C325AD24E3232626AF26DB2556250426312673268D243328CF295D2940287E2798276224DE25E224AB276D298729E92AE22AEB2C1336D62E392B952B9B2C9C2CEE2B432A9E27B826722743265128F729D42A2629552898278F2A0C2BF429DF28A4278B2BF228D425BE266629FC2A5B2C922B7C2A6A2BB52987271B266824182580253A2690258128F827F927D2282D28E92612284228F128642A902BC6274C284C275527F327AC253627C7287C29C029E22AD92C5234AB306E2C742C6E2D412D912C042C3429352A7029D2273129B72A7F2CBD2A67287C27D9272B2B9D2BC22C572ADA28B02698270E298229622DC92CFA2BCA2B992CF02A6D29AB27B524AD27B928AF285E295C2B102C092AF7288C28B0292B2A622C6F2BDA2ABD2ADB2ABA2A3D2A6E292E295C27622585269128B329312A0E2B9E340A30442CF12B842D9C2C402C832C9E2CF62AAA28DB27A3289A290B2C7E2A4626D725FD26882C752C712A2E29E927D12786262827322AEA2B212A502A6D2A242ACC295F28162536252627442BA12AC02A7F2B9E2A002910280329172BB52D162C542A8C294B2C752B932DC92BA32B87286B25E525FB2633294729382BC52A5534D22E1E2C242B37298A2A812BB62B052C8F2BAB2A23291F2A002A5729F1284D273C2502285B2B4F2C362B412C9D295C2A38291A286A285B2AE22A552AFF283F285528F82592253D26DF26A4284A2A282A452B452A8A28FA2680283A28B629FF294E2ADB2BB82B7B2B7D2D092FCA2B53297B2695272227A627332B572A782BB133782F3E2A9828C1279826BA260128E4267F276C278626C22684278327412713266C244C250F2AEB2B302CA42CA62A87281627CB285D2AA32A632BD4289427B025DB259724DE24A52584278129832AF328D828062A5728E8258C27F5254526972660295B2A922B392A772CCD2CEC2B8A2A8D27EA270B286A28FA29312B3F2BB732C62F232A4D28D3245026AF2449241426DF24C4254A2563252725032460237E23EE23D5257528162AC529E52ADE2C77298A26F1260F297B29A22A7528F126A3277B2570247524E724FC27B728BF281728A7280A29D2255A2413248C2485255E25DD27942877298C296D2A3D2B292DA92B1D29B727C8266F250B284A2A8B29A832302F5028262777240D2444242B24EE24C125C825312406247823B0246F246C230724ED25B6258B2748279C283829C226C726E526AD27AE287229492B8A29292852268024CD24F5260E288D283728792821291F2A702769246025F724FC249B27DD28C42A372B3029A529962AAF2BE82B422BB728D826D8266727D329542B1C34242E7228C126C024B224C52359246A24D8268225572549254C24A723E323E7244D24EB248F24DD261A269026B1285E27C026C927DE2557263D295129DC28B026AB26DD25D2243D260B27622839263828DD2A6729AD28E125F526C5260A27012AE62A3A2B362BF928E529BB2B732AFC2B0C2CB8277827F1252328582BA62D6C34142CA9270C24C1257125A52307253D2644277C26E326EB24AE243723AA227A247C24A6254427DC27B1269B2643272729D927AB252525C2253A2862296C2987280728EB27CE278A27B1278A282F2857276D2BC12C602A2928222869272F28A62BC52DF32B5D2BBE29E52A712A842B352CB32A6328E826AC265829472BC62D7335BB2C28279726CC2439270A26B927CC28DC272628E92737278725C323AA244524A625D726F12B2C2A3A295926EC27B02922291D2611262D2682262A267C268F27F6277A27F427292A442AD528512A2B2A8B2DEF2A8A2AB029BF29622AF22AEC2B982B7B2B6D2CA32AC62C902B422C972AC12A2C2A762B112B6F2B942B8B2E46369A2D612702262D299F299D290E28102BAA2A522BCD2AC22AD226492451268826142653292D29AD2BB0282824D8279C29592A2F2836264026B926ED25E3243C264D259A269D28A6282C289A2932299128172AA92970296C2A4A2A8429D329472C352B6F2B9829A729D82A6E2A652B222CC2279527D4298E296D2A142BD72D0836D52D97270A295A29192C242B9C2A522CF22B592A1C2A3C282F27DB24F92559276226EB28F028C02914286725242673260027932927298F28E226D725FF2384232D25F22744263527B028EA25E1287527502A502A5A29A727BF2667278528DB29622AA928052AB6296D2C422A432B5A288A278D26912A7C2AA32BA02BF82BFC35702C5E285027B32999296C2BCD298D28AE29322AAD29402665244F259B24A224AE26C227582879275F256A254626EA268128972AAE2A8B292929F225F8249024D52386244824F1230C255925BA251E27692A082CFA297827CC257F27CA28262AAD2AFB2776279229EE2C1A2CB02A35282D26AE265729A52A9C2BFC2B6A2D2537DA2DF82752276C27A5284A28F32744299428B8252526A924A424CB22492412251B244B27F02610279D25A526B725AD29032B572BC929632A992AE129AA29D52806273F26262405247F237D260028ED29082A342BB228F3259B265F26E828492A6C2A5829C22A8D2C7B2EDB2B182A3928D626F026C429702CA22DC32D9E2C6136E02C7927A025CF26BA27B7275A2701260E272824A4239823562385245426F22734277A264E255D25C324E424DC26CB26ED278A287D27A026B927BF28E228CE2825287B24FF223D21B7254E25B928DC29892AD32A7D262824E924FE27C5284C2BE82B582AB52AD52BA42B112A5A2AC428D8261D28C629FA2B3C2D7A2C7C2D2C36892D8F27AF26CE245B252F2798261B266E25FF23D12331252A24E824B228E529D629A7288E2788247F244323C52479274928AC28F628D125D825B926F525F1266B267E242825662488265227C528CD28682917289D258F26852797260529652B842D262D132AA82BDE2C9A2AF427C626382633286B2A952BFE2C4F2C512CEF335D2E6326352565254126C727DE26A724AF24D823A4221F24C7244525D7274B29892A9E2AA529C126F8242B249224C52657268A27FF251E277A253325C325AA245925AA246626CF272429002A7629432A902A0D28B126F2275425CB25AA273E29592D1B2DA82CA72BBA2B7F2A41284D2845271029432C902DAB2CE52C592AE933A12BD9264925AC24CB257B27872464241224082492248F236926E02553288128702A8B2B172B7E28FB26E7242726FF28DA250E28DA276728EC255C252F25B32350242A267A268A26D9284C2AC929A127B2284A264426902585259F235B25202A292B522C972BD62ABF2B5E2AA5282428F3281528CA29F127FA28CA29192A9D33532C1628DC231A265526CE26FB25D1233625CB228A234E25BA26232623268A287D27E529AF2BB62B90286026FB260429DD289D2833280F2986295227D423722339241B27CF2593250A27A0289228EC250D264C272F267D25C925D62208244C25192AF628702917291429DE26FE282028442A522785261328C927F0289B295432B42CD628A3256225FA257D26F8244B249F254B25D3250126482778247025E5254D2799291929282CAA29E8270A28492737289E27A1288227A22AE827B62790254B263326E2259D2476274B27FE264126AC254126BA27A82508266E22EC23B6240C286429452B862A9A2B6428EB29432AE828D3259F25242616298B2A642B4535EE2E6D2986263D261E2729272324F1246226FE264528612736268D27EA277D276A273E289927DE29D32763264B2749283C27DD277A267426E227A628192640273D27A6249024A625F924ED27C127A524FF270429BA271B2411251724A325A224EF26EE28492B482A922B712B472AA628542842250926FB24AB27B027242A79341C2D87276326AB250D250F25C425012583278927182785279427022638287F266226D325242675258024D5255F265A263D254B2608252D24C12506282A27E125A8267C260527D125A026F926632622256125CB268D265124EB23A623132506251D2684295F2B9E29252AC4299F281C2911279F255226832521288329712B89358F2B7525232517252224352501232225832707272C279D257225FF24432517264A25C224FE254325A3229E22D2236824BB2344255523DF24A22439234D262425662519271729822678270427B9241C258D256B26DD242A2558254B2439244524172687275E2865278F283928AB280C2851250E25B326CE2557285528AE2918334D2C0126CD22DB24D024F6232F246C251F2792247A24F225F323D6249C24022542267B25F7245A2588236B23C024EE24F8224B2596248423092476258226CC264E279B274B2737282A2814273426832533269825F22449249E24F824592434262426B125C325C9261E287F29492A052BC1269A254326B02664283529AB2BC0341C2B2D2636259C226723A623FC223023B6242A252424C72404230024DD233326AE24732570267B24A224122345247023D623FB255424BE25B325FA240126CE25E0268525F726BF26F225D02402250C24B72434244523F4258225EB231F2450250B276325042681279028BE27012864269925F825DB24C427DC29492B732BBA36F12CE0267123AA2274227622FD22B2228323BA238F22DE22152268228224FE2196239124D324462569252B24D0236122E0239A251327CC251F275C25D6260C271D26F8247C25D122D423C523A8228222BE24D0259E25C725C1243E24232490252C267F2618261E26DF27F725EE251227BF231624D12520263828472CF62C8D37412BBA25A022222245223C23AE215E2418218B22EE225823F42258246124F3221F2370256924F525CF236B23E32308248123DF25B7267B260E283E269E26D325CC25B2240824E42204247D242D245224B124E326C0275A277B25D5255C26A326B42702277C26A4246E264423F4235A23A822902497257E26F529E12AB32CFE35C62A6623B621B223F4215922EC218722EE22ED214A24C22388222024012442248E25B823D7252E272D252D238224682511231C25BA25CE2590259B23DC245423F4247C25C3269324EB243A25362611251626C5280227A82742292029792A9D2AAA281C27E8265C2517253A24F3214C23AF2380224C2431251B268D28DD292333622B0B262A225F22F523D221BC229C22A5236C2430237723A1245523B9223725E3253B264D26B327E6240A23BE24C1253B248A24B226B227AE24FA24EC23F7225E26EE2634266B243B275E25E825A8246127102705261B273429CF27A52B11296C2B712B0D2AA7266525AC236723C02462238522D3246B26C928BE29432C8B36E72C742520223B22DF237F21EF22D3211623D0228A2342229C2280217722FB22D123CB245A241D26CA248723B72371259B256524E324AF22AB24B02206243C23AD231824E7245F241822BE2571244423B9244B25592301253B253C25EB248A260F279627C82925279D262825D9231823932322245B2649287229252B3E2C9F368F2B8B25F72365215F214B21AE220722C02379229322D222D721C423D92388210B24792457252E269625E82310244C236A236D2483222F22442527240023F02104236324322257214B20B32245215023CA24762484211122E5232223212488220926D227B028FA298228E625B424E1255F23E223EC257225D929362BC92CAA33652BA2259623A822CE217822BD2366232423F821EC2287239122182210233224F4230E237E23A624AF24792309235123C12363223C21AE2248213E23B2212B22FA21E721AD22D3200420B42110226922A5237322D321AB212B22E72208221E252E25B0241527362950299125CC24AB24B923D822FD24282521273728B928D530012B5E26ED21342194203920E322AB211822C0205F225B2030213B21C421C721B122FC21DD223923CD23E420292212259F239022A121B0209B21BD20BD2223237921DE205D22161F0F205C2168215822032394238C231B21BE22C121A8216B21BA24F223222392237425D524FF22A223CE21FB22BE2484239C23802507270430962B6F258A238D214C22F4214F213B215C2240210222BF209C2199206021C8204C20CA2180210E22A0202C200E218D221322C820AE1FD620FE201021A3210A22F221DF21A2200520CB21FC2148222E22C9219E22C920E021332246213320A8216122DA21B622B622A7234E2179212D22D0232F2154228521C921BD219A2528304B2B102434224A22C021A620CC20B7225B2090212B21D520C720CA1F73208D2170219220D522FB2217222A206122C6213F21D421BB21142140211E20FE1F2422E8218922E51F4E20841F45228021B021E3211E2291209C20072231200E213121632196217B219D21AA214C225C239D20172128226922E7221D2333244E25522E9A2BD1244421FA214422F6203322CF21C1212A238F222020F2208B209421D6210B2296227222C921D4225C20D622BE1FA3211A22791F50211120D1209C204C221922172141217721F71F492286221922F123FA22801F0222D12035217321BA2287211D1F30229D21EE1F8621DB208A21B9216722FC22F2209723F1236D264B2F302B4C250422E7202F22E421E02062237E21F320F220CE20401F741F3321E022F420B721C723BD206522A921D621D320D22190223C20B720CA1F9520E71F7221EB20A51EE720F81FB51F0B2203229C20A0228B212021A51F33222E203A23D1209A206720AB20E61F06224E1F1221332230233321DD2167225E2306228A24FF2F072C2D255D21D0221D2218224D215B23B722B9219F21FC21C820981F6A219921FA22B022B82299208C223921E721DB209E2058227E20F61E7020AD2286203B207A1F771E62206B1FF71E8C2148214F20A022B9224720B920FC1F3A1F911F4320802130202C20381F2B212C217921BB226522C42262214721E0229325772682321B2CEB243B23752009239523F321D0224823A522C023012235219F202A2290203D210D233B225C209C21592074211021E420A5228C2183201E212D1FDA1FEC1FD61EF51E421EB61F9B20CE1FBA2075223B221E212C216E1E211D2F1F961F25217420F4205520661FF520A6201B21B0222E211524BA220221CD213B25E8268330 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 F227FD21CD211F2083200420111F211FCD1F3C1FBD1E401EE31D511DE91EA81DA11CBA1E711E841C791EEB1D9A1FD51DC21E161E061FF81E8E1E2F1EA91F491E231DFF1D151D5D1BC61B891D0C1DA31D2B1DB11E751D351DED1D391D561C9E1DF01E9F1EB61E761CFB1D491D711C181F1B1DCE1F301FDF1E9A1DDA206222822D492BB72353205222DE212C2087203121FD20101FFF1F261F591E391FB21EAB1EA31D0A1E481EB51D381E1D1FFC1FC320801E1D20A81EA41FE51EAA1F1E20231E521EB01F8A1EB61E321D841F931D891D6D1F071FF81D891D341E1520901F641E721EC51E3C1F0B1E641F451F6B1E911E601E2F20C720192001215121A323392DDF2A5624E522DA2162203020A42095217E1F3E22DA21C6211020561F9D1FF61FA61F24204A1F7E1E4F1E6420A81F4F1FC020B920BC1F971FCE1F8B1C841E02208E1F7F209B1FFA1F7E1E231F0F1EEF1D8B1E7E1F0F1ED31E661FDF1C0B1F2B1F6F1F9A1F231FA11D5D1F731F971F3A1EAD1E1E1F9B21B81FAC20FC20B8247B2EE12BA02702248C2185210D2137220B21502008202920B21F6C20BD1F1E21751EC21FA71FA71F7821E81E451FA21E2A20EC1FCC200F208820211F5D1ED91C9C1E0F201520BF20391E0F1E491F1D1E561DA91ED91F811FF61F6B1F171F06201A20F5208B1FAC1F181FDC1EEF1DF51D921E4C1FE71FBD2002225920C221E123F12D0B2C81259621D820A4202321A1202521D9204E2049205D205A1FBF1E5020E21F951EE01F481F1A1F341F421F8C21F51D591E8F21041FD41BBD1E9D1E201E531ED81F8D20BB1FAA1D671EAE1E8A1D4C1F2A1E1F20931EBF1E3B1F12207A1E841E0020FF1F9F20931EB51FAE1E661F121F4D1F401F3F20DE1EF31FF9219B229D2CF0292F25112227234B202D2232203E20A021B2201521AE21511FA71FBD1F25202320B81F381FDE200A1FD11E352099205C1EF01FE61ED71EB71E1B1F931E9A1FBC1F07203B1F861DE31FBA1DD61E6F1E4B1F491F891FA01F091F471FD11E591F582082201B1FC21F9F1FDC1F421FB91FF11ED01FDA21CD207120FB222A24152D392A9C22CB2110218F207320C7215720FF1F4D215820A41F0520101FAB208E20FA20B61F1A204A1FF220C0203C1F5F1F861DBE1DF01E261F751F1D1F8020B51FF31E901FF91E661EF31DF11D421EAA1D281FF220901E741E5C1F741F2F1E261FF81F501ECC1FF61E191F171FD31E021F3F20931E3920061FC8207E21F221982D092BCC24F521A722FC20311FCF1FD12089208A21701F062029213522062019204D217220D1202F21D620871F1620E5216F1FF31E6C1FD51EB21F4820D51FBD1E531FBD1FCF1F8B1EBB1E6F209B20C81DC320B01F9A1EF81D9E1E8D1D741F301FB61F601F741F7A1F4420DD1FDD1EBE1FF01FA41FB11F2F1FAC2138223924F62DA329BF24C5226621AE21F61FE61E0621D3211821AF20E51F9A1F811F4D20AD1ED11E77209520D420BD20461F091E4620AF1E08205C1EBF1DD21D651FE51E7E1E7C1F1020A41F3A1F5C1ED41D491D441ECF1F741E861FC41DE9208C1FFF1E061F631FA31E992060209A21A01F551E871F7B20341F9D1F501F242005224F226D2E7C2B9F225A206720A7204D1F99205420E3211E2065218220EC1E15201420A41F3120461F4820E71FE41F2220001E571FE51D4A20F41F1E1E2720091EE21DBC1EE51E3320AF1E171F971D2B1FE21E9A1D001FC41F121FAE1E681EB41F6D1ECC1E4722781F511E4B202E203F20BC20E21F5320D020FB1F3920B21F4822E0223530142A2B26ED22832105224720F320BA2033215C21C0226321BD20101F4A207420A820022079209E204D1EEC1FB61E7F20051EA01D1D1E6F1E411F7B1EC91D851DB71F2B1FFB1E491FDB1D881D4D1FC11DD61EF61D6A1EE71E1A20921FA21F9E208820491F221F2C200721661F281E4A200F207D1FC71FB61E10213022E7221F30272BAF240122AA23F0209D1F4E201320FC21D321F1209F20941FE41FD31FC3202620062003207722C41F1821651E091FCA1EAC1E631F341FF71D971DD91E301ED81DFF1E561EC11E561EFC1D321FFE1EE41FAF1E7E1F2B201C203E1FE91E47205A2071207A218C1FC421EA20DC1F4821A4200920CA1FC41F2B208320BC24092FAA2B0926E2213021D0201C204420321F1C219620B71F5721AF1F522153205F21C920F31FC71EBB20831F2B1F481E1921FF1FC11F071F371ECD1E8C1F821E391F0D1E341FDC1F181EE41C601EF5202E1F5D1EE01FCE1EEE1EF920C020E31E0921611F931FFC1DDA1EC51F9B1FA71FCA208A1F4D1F9B213620FD20A8213A24BA2CE02A93254B226D22ED223520992046213B22B9213A200620B81FBF1F1521451FA920C620EE1F1520A21F4E1F981F1020B02084208D1E781EBB20871EEB1DBF1C661FAE1F561F541E071F2A1F9A20071F33215521C21F311F091F1C202F20082152214A1EC41E751E9D206A1EB41D2A1F7F207C215C21A920B821052226247C2F4A2A7624F6228621F422FC2028224A209122AB1F6521F5218F1FB01F8C1F5B200D1FEC2128220820301F961E5C1F9F20D220221F4E1E961F711F0C1E611E4C1E1B208D1FA61F331FD41E9B1EDF1ED81FCE1F90200521C81E591F3D20BF1E391F891F83204D20441FF9200B202B1F24202821F41F8F21661F46200222F122362D6E2B9A25BE21FD206121F5217121E22130206F21D3218C20BE1EA02041219E21072070217C200920A621F821631FDB1F691E7C1FD91F361FFD1E481FC61E441E2E1FBD1E391F8E1E7B1DE920691FB41F7021121E8C1EAA1E941FC51EF91E6A1F59208E1E80207F1F4A21FD214D1FF1202F2004218921FB210D21BE21F623772DBE299525A6233C23A820FB20FE203C219120C72074228721B720E4208820FB20F32022208B2032206D21D21F8A203B21F71FC02031203A1ED11F24207E1F991FB01FF5200621AC1F171E491DA71EE31FE01FB91FFA1ECB1F01221420411F6E207F20721F8820611F1320062017205C1EDD20F7205E2103222C2269220925F32E692B4E259123D52077218E227B217D2163210422662181211A21EE20811F43202B201E210A2250201D20F12090207A20481F2921BB20132055200E1F4F200720A721A720661F0C1FA420F21F3C1F971EEF1F90214820A21EEB21A41F421FF11ECA213D1F65209C1E2F21B91F9D228F218C22B221BA207F21642275223524C430F929F226EC215E225B2228222E237C215B213421622211206F20CA20DF2187203A213423D1204C23C5211A206E212522621F2121552088202520821F2321AA206D2148210E21A81EF4204120FB202B1EA620EC1FC11F541FDF1E9D1EE31EB61F43209F216C22411F4A214920C71F641FE02082207220A7207223B1221A255B2F432C7C247A2175211A214221C7205B21C71FE21FF8203821F120501FDF21D821AA21D11E54211622D91FB91F6C1FE51FE920F71FE51D9E1D0022831FFC20401FBF20A8216C204820A91F701F541E7F1F9A1FA81F6B1E6A1E6020C81E381FB1202C225621912002210822361FE81E82218E207120D0205420B421632324247F2E322BEF24FE221A22A8215321E11F8420D02081218122D720A11FC41F582019216220F12207210F203F206C21BB202E20CA20861FD61F291F781FD1208920462244225E224C21F020551FC51E2121401E1B207620E81FC81F701EBF20CC1F74201421951F3D2085202122FE20A920D823C82050210B23F21F4722ED228523812ED62A8524D7236A21C7203E213C214521DE21E421AE1F9F210321E4216120F620C4219F1F8F229A200721E1206521B0205E1F0C20F01D9F1E5120881FE12125212022F622E7215821E4201F20541FC21F2821DE20FA1EA81FFB1F5D20741F172070204121142030214B2200217F21372023205322E3209222CE2281222C24022E9F2A4724F721612254225122C42128216D22B1213122E7219D2136205322F8204D21B32013210D1F551FE31F34201E20511FA01FAE1E651F2520501F4421CC218120FB21F2213A213F2033238A21971F25222B21C520481F722059209B20A221D8210E224C237D211223A9239022FD217F21D520B7212B220422EC225823272F462B812437238D226D226920DF21AB222221062030213022D51F15213223112155212722BF206121B120B920FE2162221F21C21FBB1EB32001219B1F6C215D21EB21CC222B212D1F192244224822EF218C2260219F228221BA213521D520C7223E207A21A72146216E22FE2070227C23C423CA2196228B22E123CE227225CD2FC82BD024B721F2219922B7211E21F620E622252121231222B520C5200120AF20A520CB203B21AF236B20DD1FA5214121A1208B20B2200E20E71F7A20382059211A21522210221B22B8211F21C9222A212021662148222B225C22B820A2206A21DF22C620AB2046219A203D21BB21C0243F24FC22612399233F2551250E24AE2E532B1E255622B82337222F22A422FB213522CC20A321F821EC2096216722F421C2226E20AF215621B821B92252206121E820B921D521CC208222A9217F22D3217F225F22EB225C2200219D226B22CD20C122D621CE203A20D722C620B220B922CD2132229B22AE201B235622E1232326B9255523DF22CE22F6234923D325492F632CAE256922A5210823A522632267221E226021B72265227020BB217B21B821A2221F23622000223821BD2035204A22442157217C22E520F4211722FB22FE2033228A229D23FC21DF238222B922C322392121223D21B1200221DA221422B4242E23E422D02306238323E922C024D225C424BC239E2389234122A92389243D2F3D2C102752228C239322C022DE22B023AF2200227F23BE218624BB21632257226D218B22B92119224C2159217E2123222022C02176203C2182212D220E22C3223E239E23C4235522F823BF228223A921DF214D218F2032213F210223C12242245F279D258B244825A924512450251725BB24EA221D2462231424A1235A26B030B82C45261625B6241D23F7211B232D23FD23F6227221032335222E247F22722386232722E022EA21F5213422B021B921B4211423402112212222A5227D212B23C923BB249825BF23F82394238221B221A222BC211A22AE21D32327220D252C2849285628E825DB25FF242225D42597279125A4252025EC231F24612650269630952DAE26F82178226C227F243023D22227241A22112472229C226A216E2236235923B7223723762467211C22522113243222FA22E8222622C222402265222E239C2383243C25EB24172407243B22D2228D235F233E2432214B2309242826A2287A2A572A0A298C26D02527260826BC26EE258F255E26DF24B9254D27E82696312C2C592541230123DE23A0225C227223802288243F2193220821FB210521D61F67213722662386220021B520A423FD2378231D24DC2456223C2349233A237C2330244A25EF244424592397214F22A4227823E5253422902205249625DE250828C027F828E6260E249A27C928D52AF02A0F2970265C26702628297329A9282D31382CF7278323D7249D24EC218B216121CA239B247125F023622128227224B524852227239323F023E220D7211D229122292439264425D4230A243722D2242A25B0288C27A726F6227A22CB23C72306233C25F126A9232124842448251027962606271D2641240326D827B428202A602B602A862A6028712880288A2A0B2AC331042D0A26C82333237723D522A423B9228122D123D623E1227B2341236A231E249224F0221225F0239A2248234B23C923602510273D26BB255D244224D623F626E728DB29F8277724CA21D024B524AD26E828FE2880267A248A24D924C6254E244125592410240226D02AF42B3D2B8F2A0F2BC729F22A9829AE2A2D2AA92825312A2DA1278224B5245123F623FE219B22D123B923AD223023422303245924C3243E243B262D25EE246925EC23DC268826D0261E27AC26DA222A24EA25C0253828632BD52BA9288124DB2481230626E127CA2AAB2A9225F2235324D923EA2369231F239A238D258A28D42A932A012AA9290B2CEE2BBA29B329862A55291F2701313F2DA92664233324162547229023DB216924B023FE23A32393246523D924E0242F2642275727F526DD289927BD276C29E4272A26E3268A233D23C125F027B52A192C9A2DFA28F924D024A7257E27F827322A9629E6251324CB2266238424C32176230A2388235026A9293C2C2A2BB82B132B9E2B692B002990278927E4251430E32A6525B7240F231E242B23F1222322CC22C9232025B8259B24BD23CF232925EB27BF27F32655282B26982640285D279924CF24E3252D2351243D275B28FD2A662B172B982AD02491226427282A77297229B72AED273F236A23EC23192377233F22DA2252251929682CD02B07299329362AF5296128962506259C2501258C30E32C3926C8249124212408229B218E23842425263527C52575246922E62345253A2781280A279F27F2250C25B8240C261F2425235526BD24E0256329572A992C872B912B40280E232B22A026DF28652A052C632ACB272F24C12322214722D121D82423225026FA29202BA92AB529632AAF2876271327C8241B251C24DD24732F732D7C278424EF236B2404246E25982681273F2773271225EA2269256723C923E3252B25F524D024E024D0217423F924FA231D2357241A251E2782293B2B0B2DDA2B222A4927CF220423842472282A29A02B8B2930292925E122CD2200223521D4227B241026AF27B92AE4285728492713263F2329255723EE22A6237025F0300B2F302886253625E3241225772602289C2BD12814286027AA258524BC241D243126E324E6239224CC23EC241E277B257F27A1250924D5267F27322A942C3E2C412CF62A1A28BB22C8220325BC269729D72BA32917293B264924F2210F2285238A24CF25EE27BD28D128F7275D26B425BC23DB221A24FC20DC23F3245A27B530652FA4287F2654253C24C7256328EA29712A7429462944280C2596228E229122F8222824C2237024C7264B261528402A6129AE27A325FB269A28B229292C032B6A2B2829E9251C245924B625622607278D28E3287F2710247D24C2211521E921B5230D2663287528E127A324ED2330247B247423B02448239724FF25AE2873331730C22BD8280928BC27BD28EE2A8C2BFC2BA3292C27D0249324EC2431249D239A251B25A3232D28BE27A4299B2B742B012B1829AD25E326372B3C2AA12BF62BB42AEC275525862468252727A3254026D12776278326F423782264217122A3236B23F3255E2720272827B125FC247C25DF24462402248623C0248226722B3E352232522BB927CE27CF251D287E29F62A1D2A722881270C274B24CE22CD2399232025FE2632292B2B752C242C342DB72DDD2BAF27322569256A28742A782AD62A61283B260A272D24B925C126E62604264A2637271D2716265125B622E2219722D825F8258625082673271626B826AA273E275A260A270F258927FA291B2C743346338F2CEA2908278729A9261629B4292229412819286627FF247A23E1246C253D27ED280E2C482C522CE52B742BED2C682AD8266E2425265C27EC27B428F82753267F247A269B25FB254425902690279A29CC29AB2A2127C12526246723A322F0241A27E027242857297829C829E82A152AD329C528A828A9292C28B82AB7337C31162B20288226BA261C28F2264728E9289F29112AD4289525E324572383251E27202B1E2C3F2B8728FC28052BE42BF8271C284D25E02224261E25E624D3267A2590244F24BC22C5237225E3284F29462BD72B0C2BB72990286A25FA23A4246324C8254A28E828CB291F2A6E2A9B2BEE2AE12802288A262E260227E4289A320431562A79271E26CB278C289026BA26B12A9E2A562A2629372547234C269B277B28B02AC6297E29032AF329762BBD2B8A28BD243223D3230D242B24F524D62356236324EC238722A7259228E7296D2C272C752E0A2C172C27286D268A240C246F259F27092A6E2B352C6F29082A942BDA281027F4269A260827E22545265030C62E14286B2522269A2736276427FC28552A312C652A9A281A261526EE26AF279628E92850284F298A272128372AF92AD229E5251923BF2282232F216324E523AA249F24A324DA248726FE271E2BA02BD42BBF2C6C2A0D2A4B2936255425D124C2240D2676280228812B402B432AB22ACC2779259A265425862537274726DD2F532DC6287F2687262E2935294E293729DC2AA92A542AFB26FA234A2500274B287B281B2930253726E22640277329BA2ABC275324C322D32346244324A8267527FC2671240A2568269727A129022D8F2ABD2AA029E62936285F245625C6248A23CE2138249E235925B7274027B926DB27D3247D2260244C23BD230C247E2559302D2E5D286F28F6290B2A302B3829772A8D2CCA2C1E2A162807259325A226362818296E27732648278927E728B72C492B04278F24E3234B243725F1277F28992821283226EB26D426BB28C02AE02AC52AC02AD52AB027662527251D240724602476234624E4234D23DF24F7241626EE24F8220F2374236E23CC235E24F125F230492E332AB729F62A662B842BE02A142A882B512BAC2AAD260324C823F2251F25F1279E2410262726F3269E2A8D2B302CA7284924F421552365260F26F12895294D294227FB27002627273227532864273C273D2890249023EF23AA23A622362495238721DB224822072403242123DE234823E321B7212D225B247025DD27BF301A2E0F2BFF2A922C212DBD2B9029B62B312DE52A3128C8257A23F3238825F4276226EB266E27DF28A029D629BD2959270A268A255F24EC24C924B2250628A3281229A827A126462655257D256F252626BB24C9257D24EC215023B02414248D237D228E2545247825372562242623D9225323202410245023A825F62598282433622FE22B912C962BA22C752C472EE52CAC2B9F28A326E22454241924C6261B27F429BC2DA42A4B2B73279C2711262C26F42155219023DA22D223B42586260526BA2486252F25FD246924B5229B226323E1246D23F8233E246125C92735267B27C926F6277A260326E4251B247F23D32331238023AD2565264F299B27402B80334731882E422D0D2CEC2A382CCE2B932AD82AB0289B26FA23FE23E625C927082A222BF42B2D2BFB2C112887253B25E124172173239E225F236A25642323255D25AE26AD28A626FC257524E823A1223722A523592539255725E926B528D528582869276A27772719256727A22462235B2332245926A5278027E0282C2BC22C9D358F31552D9E2D2E2A212A6429C728B926C427032868260C263827FF26F829822B7C2B552C9C29F02A3D298A258F246C2246233C211924C423992515240126CB2628283E2B8F2BBB29B928DF241B24AD235124EB25DD25FC271A2BF72A6829D3288C26B226CF2548259123EA22A5240C2512256627712BF52AB92B512B8C2CF137EC33D62C492BD228DE278326C9257F27FE2527255C2722275326E3260F28502ADC281329C328D027EC234B2448243524B323AC249D249D254B250E26C027CE281C2C652D072CA42A2A2894257D237523CC2686285728E129A7295E291926AF25A627D8251E24FE23402537232A25AB2722278D273C2BBB29BF2A892A162B3834C832622E102B7F2BE42A3C299727C226FE243827C8292A2C71277927AC25E6253E25F124A8259625FB269C24C526A0268F25B4264F2A11286B28002965280A29C12BC22C482C3B2CC6281325B1240E25FA28BD2BAD2A85292B289327102610274929F627FC25FA24BF254425A324E7250B261027E1295928F827FB276027A32F8933572EB62DF42B5B29F02A7428D52705298E28712AA82B222A0626EB24502329260A264D26D628F1276B299529802B4F29282960281E2B3B2BF72A9D2A9529A32B692ED52BF82B9528D02547246E26E629A12BFF284A27EE25F0265E27F728B1293D297D288024412873279E24E8254E259D2509291D27C6257427112882306E30BE2BAD2AD42A11296B28B12612283226CE2542298F2601276A2559266B25B227D027AE27DB289F2BE129142DB62B242C292A44295F29FD299F29DC297429B629652C902B392A8F27B7241928A128712AD72CF729EF2734270B277E28442A0B2A2A28532744279B272E27C6264325AC2220221B273D26DF27DD2642284231682FFE27942774275128902531273825F22549272F277225CD261D274B28E7263828E828C7282C2A2B2B342C962BBB2C9D2BFD29752A762AB9292A28F1268A26FB2744290C29122701252D24BB27A328502CF82C4A2C11283C2810279128C82AFE2A8F2A2F2B57285B29DD2676253E24F12354278B291C2BE42C712A532B2534842DA4271D27E726F025A4253D25AC257E2632276728E127B0294F299B2ADF2870272B275528272AD72B0E2C6C2D192DA42B2A2AB32A9228F928F926EB261E2592241C2632278B240A256C2667277B287C2A5F2B0E2A2229DB264F26E227FA27BA282A2ADA2BE2291E2AE726E0256C261425EF29412BB02B412DB02B872DF237832E0829B8291D287026C925A5243725EA266A27EC28E3274229EB2A602B952789269126C7260629FF29EE2BE52BE52C542E4A2AA1267D23AE2439250224D424CC23C325B524B724DC2537289C298D2A2D2BB829EC2BFA28C026B025B524D52673272C28752A2D2834284F25EF22E2266928132A7D2B022CC82BDD2CF12D01377130CD2BE02AC529312892266E246A2675276428142AB629082AD127DD26DA274E26E22573266C279928742B802BF72BCE291727F22411242322C424D7223B22FF22CE24A124F7253928EA291D2B952AB02A8D2B6D2A482A142607240425A8257D2795272327EC2604281926E3255027F229022CB82BEA284829442BC82CD635FE30D12D2F2B792AC62812276A27D3270F2A3E2ABF2BEA29062AAC287627A02477251925DA25F6263C27352A0A2A2A28B42517250B238D22C7220624ED23092475249E24C6262929522A992BD02D272B622B052BE92A4D299E276223EA224324A0274329092AF1272E288826A6269729FD2ADB2BE62B372A8E2944289D2AAF344031372E422FF52A2B2BB42B972A0329C029B12B432D5D2C492AD12954272F28DD2673261D25162773257328CB267E2678247125D222E922192528260926EB25BE24552539299628572AC42BC52C452A302B102AD8273A26DF2778238923C5252129BD2AED2A1A2B1C2A21291229BF2AFD2BE129A92D5128DB27502B8F2C9835F932EB2CE22DE12CB42DAD2F4D2CD12A2A2BB02AFF2CCA2C542AA528B7288627E42AC52ADF2720246A2634263724F1254E257F235C2524251B26C1267928D0276F2749271C2761286728E228E529E1271D27D12709279126EF26B225EC239A268E28C42B962BE12A812B44281528E42C882B362A752B002A162A692DB62B0837F931C92ED12B052D142EB72C842DDA2B1C2C742B7429D828532732272829F82BB42B1A2B9028B126B524A926AD267024FD23D525C8258627E029BB2A1B2A582AF72AFF299128CE265D27D427CB2528267C2782269F2861282F295C25EC248826BC29B729B02AC82C4B2B1E289827262B9D2CC72D802BE92B922BD82D7F2E2437632F2D2C862BB72C9B2AEF2B862DAC2C452B25271B29AE257927C726EC28E528DC2A7C298E28B8253824AB2436249D266E2567253728FB28C02BEC2BD729BD2AF92B182C862844262F283D26212467238F2510277F287828A6271626D325C42579298F2A4C2B272A51284A273527F02A3E2A132BB92BD32C0F2D3B2C6B2DC8350A2DF929DE282528A62A962A8E29FE2B83288926DB257A2428270C27EC280F289627A72711268A26262573259B274427AC25AF25AB277D2A0C2CF82A192A062BA82BDA2A212A4C278624DD258125CF23B024E3285126B5267D285B27AF260F27C2266228322A54282F29DF26DA2776292A29A12868294D2B122CCC2D952C47349E2E9A29C229A42ABE2AC92A7829DE290327C524E6255827B92572261A277127B027C626B12550280D28C6261E2A5428E7270629F82A0B2ACD2AE12A36295A2887292829FC26F12421251B26212763289229852A6B292627D4248624C6256324C1252D29BD2856271D260625FE28BB27B6264727182A7F2A142BA82B512B3931C730952A822A1E2A982B952C4C2A33286D26FA243B25D224F526FE26BA26CA27D826EF27F2273B2B3C2CA52A972AB52CCF2A102A612AA72A552BDC29172904273629D728BE26EA268A263F26C0289D28702B8A2C2F28B4278F26ED24E926DE25B9254826C62442263025C327D1267127CF275428DF28892A702C562A5C29AE31C82FD12AD829EC29732BBF2B6E29C2259F26CD254D27AE28EC2765277028D5243826802AF72A672BDE2B98293F2A912B3F2C592BD82B182A0F2B572BDA2A662B402B632BEE2AD1264B27E728F6290929AB2A9129802738259C2893280E2721274B253124F7249D249A26B22681280C2BC529AF2A292A0A2A5A296B285928FF304E2F7B2A292B9B2B592AA729BD27DA2695286B29B9298A2CA929B6282728F5250F28C3282C2B552C692B242A1029D629FD2A022BF02AD529062CFD2A4F2A4A297D2B4D2BC22B572809286A288528FE26AB271026C1254C25DD285D275C27D826CC248B2325249824B22775285A2B5C2BF329AB29C2271327E5254F26F327E032D131272B342B7F2C8B2B6F299D26CA27FF2A532C942B282DCE2A522949278D2742278129EF2BF82A7C2B392944290B2AC529A628BE27EE282729E7280326C226512AFE2ADC2CEF2739270D27D625F024C624AD25B523D025842598270B259E245D25F62218253A2640274F29682A8A2B6A2B0129DA26EC2531278926BE29A235CF2F872AED29362AFA2970281F286D29032B502BA22C8D2B352AC026F0258D27E2268127582A4B2BFC27EF2522255926F524BD25F7245D2571268C241E2518287228482A252A8626EF25F5232B232C23652517252327AA26852674245225DE249924AA235324912695284A2AE82B1C2DE3291F289726C425CF273129F72BFE36BB2F432B7528432902283E276D2ABF2A182BC72A822A6C2A2D28D1273827B1289229922B6E2AA529652685287E257B259E236C25142407248925E1256D243F26B427F726122714245123DF247F244924C725A028982A4E2A48297428CE272528B4279A2557267328672BB02B542CDA2BD12AA728E526362576284E2A492D28381C316D2B5E2A4F2A6D2984293D2BF929362B772A4F2B5F291A28AA287B27642BF32C882B372A6D2AF527FD2559272F277524372445235E24F0259424DA26B42698270427EF2649242F246B25E824DD2526286E2A502B222AB62CE62B8B2A722B72294C29A527E927ED2C322CC02D702B002828286728452784295A2CFA2D9C36962F2D2A94288C27B32AA72BC4298F2AF12B682BC12BB02881268826C4283A2A0D2B582A5E29D62AA9281B28E426A626AC230A26D4265D268828CC274428D126452636262D2673263B25DF25BF27F927D4285D2C7F2BC12B252DCC2DD22D2E2B092A9A271A279E260C2A3F2B2B2B122B1E278727C2293029692AD32C712EF935782FAF2A7D2730276D2AAD2C4F2C1E2D042DC92CC42BEA2890256725C9258F28D926082892274628122A582C3B2A2F27CA26CA278729712AB429862A9C276A26CE2756262F2982283A274127AE288129A02C8C2D332C012E9F2DEC2B672DC72B0D2A55279F257827E128E4294E2A6C2BE328BF28112AEA2C872B2B2BAA2C7034FE2F22297327B827CC29842CC52C2D2C522E942CCD2BD4274B25C426F227C928B82893278D2806295A2B9B2C0A2BB229E2282A2B0D2DFB2A8D2A7828C128EA26E42748295D2AD4282128022ACD2A2529132C542CCE2CE32D852D932DE12A7129B52644265F275B259D29BC2B9B29952A5D28DD2ABC2C572A8A2A012B652ACD33D72D1B2937274128F2292C2CB32C552C622BFB2B902824268826EF273F297A2A492A9828BF271029CA2AA02DA42C752B082B6D2D1E2CA6280F2847264426CA24E026AE29A52B74298D29792CD229C42AEF2AF32A70291A2B9D2D072D3B2B54299227C3260C2449276A29A62C532BF32AE12A3C2D562DB32CA22CD12A0C2A6133242EDD28A128BD276C2A932C422B442D2F2C4629A727412616288729C02A0D2EB128D72804291B29DA290C2AA02B922A7628F6282C289B27CF26BB25AA276827EF276828012865289329DA29EE28D92719270128D926B428A52A2A2DDC2C3E2AF5274D26D125BD27B12BE12B0B2C742C232CA12C502C3A2CD52B992A882A8134412F902ADA28EB28F629422B992C922C9C29AE286D276027C126052AB02AF82DE22A7C29D8285629B829802995285B298B258527A5267425A1264B28942741286F283A28F8275929702A8B2A2B2AB1270B26B82637266D27BF288B286E2A552B1029B928FF26B7286C2A4F290F2AF729CE29902C132DB82A2C2C362AD62B9B337931B92C47298128A3297A2B732A7F2A6F29ED272328222A962B892A8B2B402A8328A728FE29A82B252C272BFB29FF26EC265226D7242526F9281F298529002B3E2A50289826C6266328D9280C2A03283628E026DE26A025B627AE28D328292BF02A002A0A2ABE2ACB299828FD260A285129602A482DE42C6B2D1E2C532CD334C430FC2B892A2329EB29DE2B1729592736265A274C29E12B322CAF2B412C3C2AD42AA52ADF2B542C662DA92A1428EC25E122CC23A2249024F329F82A7D2C3A2ACF2A592A082B5128052771278C29AD28802731282227F3245B2B6C2AEB2B412B012ACC2BC12A5B296829102755265B267726EF288429AF2B892BC62B542BF632A32FC02AA227B4286A2AAF2B042A8F26DC266E286D2A502C702B712B8E2BDE2B9A29612A302AE72CC82D1F2A6028D7242A24F6231525082531291D2B7B2C6D2BA42B2B2C4C2CE1299527AD25CA273126B0266B28C22605294D2A022D9F2C4F2BF829F629C1284F27CF2637269C2697275A27F72838290129082B072B682AF432F430C22879281E2A332BE82AE0276F278926742A842C832B7C2A042B182C892B382A092880289E2A302CAA295D29A226F7255024BE259725B9299B29092A082BE32BBA2C692AB7296127132604264D27EF2AA0290A2A8C28C62B972C802BCB2B9729BF284325872574267A253C28A7296D2C642B7129F0270D2AC128A0283C336F2FAC2AC7293B2A962AAB29EE26B12635288729892BC3271C29DB281329A62A1829B126FA255A29B6281F286C280927DA269F2646278F29652A4A2A532B6A2B8B2ABD2A1529792525259A244D274128792A452B362AEB27DA2B742B802E232E162B15294A25CF231E279728E229992BB12B392C812E212A35296E281A2964319630E72A142BDD2AD72AC529D52663298C2AB32B5E2B9A287F2657272227A029DB28F3253F26BB2675279F27AD272628C127BE299B29ED2BC32B982BD82AF7296F29D4284227EF232322502669298929712B722D092B4E29482A552ABB2B6D2CF42C3F29BA26F926FC278329982A3B2CF92AEC2A562CAE2B282BD72C2E2C6833DF2E442BF928E22948291E290D28AE298E2B102DB32DE22A452A4D286D291D29F6280A287128D827A0272F27BF29242B1B2AA12B8C29862A95292E292E291D289626FF2630264826CE2669284529FC2A242DAF2C8729F529632B9A2B872C0F2C3E2DC228A02706276F27092AB12971294B2B632CAD2CB02B862D342D992C54362331672A6E288C278B284F27BB28162AD42D3F2DA52D6B2DC92CD62B242B442B9929FB2BE3295A2AD329B4280C2CE72A8F2A352BE92A492A342926299327352774285B29CC284828C928CE2A432D022ADC2CBC2B9F2B6F2C182D7D2A5C2BCB29B82B7129E72882262929692A7C295129082AC92B002D792C152C3A2C5B2D12369830202A69260525C4259E27B629612CF42CAA2C152CBD2BC72B2C2C5D2AFE2A2E2BDF2A2F2BBA2A4E2AFD29262C752B0E2B792CAC28B9270028A428D727FC28032A8729A729BE29812AEE290A2A262AFB29862A242C3929B4290B2AD7272D280A2929299F298025C3268F28E927D428D2279329232B53294D2AFE2A2D2B0636E32FAD29962599239E25F62694283C2B7A2C5A2AB82BD82B982ADE29E22A66295428562B222BA329A32A142B0E2CC72B6629752A87296F27D5297E29F929C62A382A9229FE29652823291328E726B4252E2823289527DD26F72785255227B927952712299F29CF28012956252927B1289E29C628FE27832811298728C62B9236153095280D262D25EE264629342CC92C742A452B352A512C262A872A2F2A6B28F127352923277B27BC26AA262C26E0267B261F26C92516277E27E5293A2AC527BF27F726E1257625482852279F27A9287528982A1C279A242D2583255229792AE02AAF2ADD29AF29BC2A90281E296D2BAC2C792BC02AEE28AF289728162AD734582F86299C29582742276628922BF42DFC2BEA2B452DB62C862B9A29B22765272E27B6265A25DF257B2505258725AE260D24F0241624662595279A269A27D526552552249125912604286A271A285A2B242ACE2C62281724D425BF261E28CC28442AF92B4A2E842BC52B8F2AC02B722C812C882CB62B7A2AEB2ACA2A1B2C1235BF30F82A0429A3286E2716293F2C512D4E2D6D2CD92AC32B672AE228D226F12554259D24D325F72493251D24A025E72430257E2481259925FD2612261A269A26E424A9256426C023B02781278229922A8F2AFF2A9228CC261427C028AE2BAB2A8D2B3B2DB12DE42CAF2A56294E29E82B842B9F2C712C0A2A40295628A5283831B131342B2429102733272C286F2C0C2CA52C5D2CD02A75290F2723258626CD251B257D26E32593277226B8264A28502722263A275C27AA29EC285C252F26E1268827D3268827022616280528502ABE2A602AA72A312869269E284D27BB29012BE12C8E2CF52C9B2A592B9227D726672A162B2D2A862AA9297E273D28782A67324C31252D912AE028F8276E266B2AD029F12B5C2A752645263B27D625A225FD261927DC283E29532A052B202AFB29252A10297929FB2A722BA528FF26C225A727A4294F2BE32AC82758298529E628CC27502AA42AF9278E269B268D265529DB29F12BF32B362B7E2CA2298C26A22517266227E628912994287F28BB28662ABC34A030A22CEA29E026F9251E258826A12751275727C02724277227DD26F82750292E2909284E2AC829282C032B212B7228BA25992861267927D227D126EC243628652A692DD62B0A2700273E253E284325942651284A270F260D286B293B292C291A28D6299F2B0229E7297027E42536253A27C025FA28B62A782BA42C4F2BF334C631872D5F2A99291928A1262D27262ACD2BB52A062C182D622A572A172C202CD929072A9D29DB2A562A5B29BB27F9253E276829CD285827BD27432729272129912ABF2BFE2A23283B272529E2296C286028C929F029DE2B422BE329D42BF12A9A2C02298128C1274327CE2553261D268024DA289E2A602A7A2BC12B592C46333031C62D692B072C472B4F2B032A142D5E2D162CCD2BF72CCA2CCA2B9A2B682C8E2A212A3A2AE22CF92ACF283B2957285329392AB6295C2835263F272428302A422AE62A092A0E29F4284E2AEC2BF72BC12A492BAC2B0B2CAB2B0B2BEB2AF22ABD2CC72A0D29FF299D28FC26AF259A253B271A29432AF629C929AD295A2AC231CA33BD2B872A0E2CD92C742A572BC02A872BFB2EDC2CE82C1C2B5029692AA129F328A62B162AD72CB82B182ACC28E7280829352A4029D125C626CE27FE28B12BF62AD528C72616276427A129FB2AF229532AEF2BC62BC72A572CA12ADF2A8F2BE42BB42A0D2BBA296A2B7729A42741278D261B29012AE5282D2AFF298C2AAC349330092C9229972BAB29942A052A232BAB2C0C2DA02E9C2CBF2AD12AA828A628A828142B432C7D2CA12AEE2A512A73287D28EF295E289426D329F028B82AC529B22B692959280829BF271A286D28A5263927C12877297D2A8B2B092BCC2A802BBF2C312CF22B8F2C922CF32BA42A3329FD268F29BE2AF92A132C8B2CAE2D7B35A32EB9281B28CF26C4274A29C129D42B592BB02CFE2CBF2CAE2A6528A627BC28AB28A92B072C212C602BA0290828AA267E296228C6274C28B5288D294329E2281F2A632A8F29142858270E2A602843259826DC296C2A3F2CFF2B262C802D4C2D142BFF2B242D092DF32ADC2ACF28AD282E280A29B82A2E2C8C2A5A2D7B2E1B35DE2D11294727C428DA297A2B4D2B022E692D732D502B922B892A5527A6276128C4287229162B992A4B278726EA2402267B2476279A278927E1287028CC26F828EC28A626492768267B2678281428FD2445273729382875275A29E629EF2A4C2ACC2BA42BED2AFE290C2986285E270F27B828F729B42CD72BAE2C902B8B2B7C35D52E4B292A287A2A9429642C9F2B492B4D2CD32CD02B982AC429AB26F326AC26772898294B2A9628622758253B262D252C254827E026F3287828F327CC257725B2274927392572251E264027E224AD23ED26782526272F26F127D9292829F5279C29132B892CDE2984296A28F62643283C28612AD52B0C2B212DF52C122C983525304B2C742B6B2AD42B172ADA2BD629A4288C2855285D289B27232A1C2A162A592ACD2A7D2A3C2A99281B28A6279D27FC27A12861290D2CA82B5329C62855284F290B29CE2647258D266327F825CE24FA262728252789266027A6274B27C5256B29662BA72A572A912AAF2A6827F627D326C029D12B6A2B6A2C522CFE2DED368B2F1A2CA82C442D212D452CB92AF327F226A227DA26F128C82A782B352A8629F628B92B382B3A2A88291629CE2C0C2AF6264F277B2A642BA02CD32BBA2A372CBC2A6228EB26A9255726AC26E8261C26E12813295A29F0298829F427D0286F294B2AEF2BE92C1829CC299229092A8E2A9327B128672A272B5C2B4C2C9A2DD4348C31AF2D9F2D462E032E172D882C8329E52AE229C228572A792B402DAB2B5729212949298B2C1B2C352D3F2BF629C3285828E429EE2A092E292DAE2C4E2C772DA42B8F2AD428E0253C294F2A522A302B562CF72CDB2A5E2A312A1C2BE82A442D112D782C832CFD2BC62B712B102B1C2BC128EA262828582A142CDD2BC62C8C35AB306E2DAA2C2E2EE22C562CDD2CDE2C742B1F291229322A382B092DEF2AD32660267A270F2DC92CF32A85290429D0288C27C927952A282C3D2A962A902AF12A662A19290D26ED251128CE2B182B362B062C472BA229A0296E2A032C5C2EEC2C342C4D2B712D722CFB2D282C662C052A402722277228382A762A9B2C092C1935A92FD32C8F2B8229342B0D2C352C962C882CD12BAB2AC22B4D2B8B2A492A7828DB25A828082CB02C3E2BE72C0B2A9A2A84290A2953290F2BE82A762A962965294629E826D425852654276F290A2B7F2AD52BDD2ADF28DD275B297929362B242B4F2BCB2C402C1E2C7C2D2A2F1A2C502AA62758282A28B328142CFB2AA62C4434A430EE2BC929D0284C275527E72801287728152913289C28B929EC294E29132708255E26252BDC2CBA2C112D362BEA287C270629C62A132BD22B4F2959285326462614256D2553260428D529352B3629092A3C2B2829A7265A2800272227A627332A302B5D2C702A302D132D642C6D2BDA2839298629E729462B4C2C1F2C47337A31182C262A29277027F02597252E27F5256227BB26D827792726262125E82417254627FA298B2C132B052CD52D202AAA274E28712AC82AAD2BA929D628D728EA268E255525F425B828FC296A2AA829922A3F2BB027CF2521258625D826F5268329602A422BD52AF12B482C022EEF2CCF2AFA299629812774299E2CEF2AAB33E62F99292B29D7259F24AC24CE24AE25C3261E277F250C25EA241A26902551240E256C2626265228FE2723290E2A5D27532792275B280F29342A8A2B212AFD28FB26CC247E256527A5286D29D7286129C229FE2ADC27F624C5258D25B7253D288529862B612B8229EE29142BF32B192C422CEF290A28942720286D2A212C7E34F62EF329E428FF25C7258324F9256526B2285D270C27E1264A26DC25F42512265D25D1257525C027F02674278229C72878276528F6265B27462A692AC829B12768278C26C625F6268827CB28FD2602298F2B542AE5294C27BA278D270128142BA72B3E2CF52BA229A42AE52BAF2A762CDB2CD3288428DE264729972C692E4C35F92C092916260827E72625251427782845290A2929299E273627F62591249E25AF25F4264E28BB287A2784271228142A2E29C0260A26BD264629082BC02A9229602975296E290929D928AA29A829F828A52CC72D4C2B1D299529FB288729B02C382E692C2F2C662A7B2B0E2B202C952CBD2B60299128BE27662A6F2C4F2E16365D2DC128192886264428632717294B2A092A252A632AED292F287A25BA2538258626FA27EB2CCE2A87298926FF27E8296B2908271B264026CB26E1260327EC276828A7274D28F629532AE928C12A472AD62D582BE92A5C2A7F2A8B2A3E2BE32BC52B892B7E2C132BCF2C9C2B7A2CB72A312B9A2AB52B7F2BD62B012C9C2E73361F2F6F294529D32BAA2B312B4629682C862B902C472C2A2C4B28AF253027582745277C2AA92AA52C6E2934256828792A472B2529BD26CE2637277B268425A526B1250B273529F728E3287C2AE2294629342BB929792AAF2B222B2C2A272A9E2CCE2BD22B5D2A292AB42B4A2BDB2BCB2C52287228092B752A8D2BC42B932E4536DA2F8D29DC2B6A2B3F2D442C372B9A2C902C592B472B75292329182680261C284427112AEC2A692B2629BF26F6267627D727D229CC29FF283527F2258524E42360256B28F226BA27E92853264A2970283F2AC62AFE294C284D27CE27FB287E2AB82A5F296F2A542ADF2CF92AD12B45299B28AD27802B332B1F2C302C952C1D36152FDC2AE329E52B8C2A6C2C852A8C29CE2B9F2BEB2AA927AE253626E3253E261E28F6285D2AAA2929271727862759289229D92BB12A152A8D29B42694254A2569240825B7248524EA2508263B268927522AB42C972A33288A2633287F29BA2B572BDC284028F129CA2DF62CFF2B4629D427AF27632A902B702CCE2C152EA3379D30002AEE298729C92A7F2A112A742B802ADB2762275B254C2566230125E025062533281028F227F126CD27F926A52AF22BAE2B162A602AD52A542A662A88298528992669246C24D123FC266828362AAA2AEA2B3E29FA2607273227E1297F2BDF2AFF29862B032D672E2B2C152B33292028FE27AD2AAB2CE32D332EC32CB0362330A22914288F288C29662AF2299A28AB2857257224762425245A2562270E297828552785265326C325B2253F280A282C2977299B28AC265E287829F329FE299E29E025B823E121D525AF259129CA2A2A2B232B1C27DC24AC25EE28B429AE2C032C402B912B8B2CF82BC12A7E2BA82943287028652A2E2C532DB62CF62D8636C430E52955290B276D273929D02812283A27D724B024D025ED242226C029AC2BF42A8D296629422671250224B72578285E290E2A122A00276E269227C726DB27DF262225E925E424C726F327FC281B29152A9E296527DA27432833274C295E2CF32DFA2D082B312C3C2D7B2BC928B327DE2608294C2BEC2B502DD22C012D513409315828B726D3264528172A0C2A86279A25BF244B23A9245F257226E328892A872B252BF82ADF27DC25B62413259927E927BF28122705286B2619267F265425D92563253A2769289F298A2ACA29D72A442B142937289A2910276D2696289029F82D872D202D232C332C082BF228D128EF278329DC2CA32D3D2D922DE12A26345A2EDD28A1273826EF27A22A3B2860262525D0247B25B0240127DF26F42871298B2B662C1E2CAD298028CB25D526612A1A289829FE290D2BF627A226EF253F243D25E7261227002782296D2BFB293F289B29F42702283D271027C3243626162BC42BD62C082C3C2B9D2CFE2A48296C290D2A6129362BCC28DD29162BBE2A0F34462FBC2AA726C6272328EF297729D425B52616241C25D226E82760272C275329F728DB2A302CDE2C882960288727162ADF29C0296A29642AF82AF528242560244125B4275B261826AB27AB29F8294B27DB260F28CD2732271E279A23F6243626E62AAB296A2AB729292A3328A0294329732B59286B27EA28AE28272AF92A39338030932C9C29E028842869290C283526052799279128E2289729F6266427B527D328DA2A662A5C2DE42A5529EC29D92800290428252937288B2B4E29A529AC2696270B27BD2659255628A128EF28C1276D26A427FF289D2775273823A7244F25F3285D2A312C1F2BCC2BAF28DF2A7B2BC1295A273F2647270F2AF42B512CB8351233B52D7D2A4F2AD12AC62A08278D266128EF296A2CFB2A66299B2A6B2B912AE129392A1D29AD2AAE28B32750286A292328F3279426A5268B284B29B827F82744289A25E3241F26DD255629F229E3251D29DB2A202A6E264326C1245626762577271A29522B522AC22B9E2BD92AAB29282AB726FD26E325EB280629122BB334B231152D872C642B4C2A8C296C294028562BD52C4B2C192C192BF0296A2C2C2B472A8E289227902664254727EA27D027C2269027EC25262502275B2985290D282228B227DF27F0261C28A72971299A27BC278C295F29C32680253825A726A3268B27E02A0B2CC02A062B922AF429BB2B20296E27FA27A827DB2A5D2CE22C27363630EC2AA72BE12A23295A29C226C328F02C8E2C4A2C612A3F291E288B28372AA5298C283B28B426B123EE23A125BF2639266E27DB24752699256C244A2771267C26C927A1293B284429F029AE279727EC272C2992270828C3275F26BB26A8264328FA285D2A6A29632A1F2A002B2E2B5928E32612296A28C32AEA2A8D2BB9331C30B32A5A280C2971285227F627272A722D5B2A4D29062A5F273F2724273B28F829CD29322991271B25C7248C261927A12672289F273A257225DA264727A327D52716282A286429652A212A472931281829A428E2276327EC26F1260527C229EC29D0283F288229AB2A6B2C842C472E89299528C228CC29062B602B522D9C35CD2DAF295029BD258B25222612266D27912859292D28C727A825A82691260C29642808298B2A5528E1268F2426264325A4264229F627EF27B8275F26232773266827FB256127A5274B279B2665266C258B26FC258325582841278525AE269828772A35293C29DE2A202C5E2BB52B2C2A072965282227142A3B2C2D2C352CFC36A42E592931263324222424241425A525A926AB2624257E254825E8256227A724B3264728FB285E297428DE2538255E240926162896297F283929812761282728B3265625EB256D23C824642472234D238825C32638275E27E1255925DB251928F928DC29152ADE29BA2BC829BE295D2A602639262328E328BF2A702EA12D92373C2DCC27AB24A7236123A624ED230027E22394258A2628277527D32883285E26712668299529D82A88276325962521268725F6270A292329662A59280B284A27822628255D248123CC2430250F254D2546250A28BB28E2270B265A261F27B2273329CA296429C627B9281A251C26D724282429269C273D29952C4E2C662D0E36F22D562653242625B62399241B2557265427D726BB2A702BC529832A142A2629B52952299C2BEF2CFE2983264C27A62844263F28D8282A298128F1256426762598269727BD285626AD2651275A2832273028562AEA28B8282B2A842A642B8E2B8E2936298928F02677267B25B823BB2464256224942628288528342AD52B0234BF2E65298F25EB237C25A523C825BA2656281D2A1C2B3B2B712B0029E6260129EE295B2BAB2B322DEC29E72675278628182816287A2AEC2BB1284A275C259624D028A829C429F027D1295F28A4284727E429AA2A97287928F629F0284A2CD5299F2C232C132B8F274D265F244324F7259024D7239D268B28692A412B1C2DDA36B2307529D625462420262224412665262F28B1285E2AD629B4295227A8262427A228802A0F2B422CD82AC0286F270E299629BA29AE2A8128E8285726C5266025712609273C285F27DD24482822271F275C295F2A3C271E27FD26CA26C726BD280B299B29B02B63283028BF26A225D9243825F725D428A32AE72B9D2C6A2D5037E12E27292C27972331237523D1242025972795263E275F28892885297029F126102A9D2B1C2CDD2CD62BE3292A2935271227AD28D9271A289D2ABF28CB25F423EE247F269E2493237F221625DE246E28592A362BE7263525E92532257E263825F328AA2A6B2B492C642AE628BB273F284C25ED255628C627182C062D6E2E2E35CD2D212896252B245C2313242B25612594258824CA25B027F0276028A82833298A29F1288B2888299B2A792995280B27F3260026A325D52748264F272D243A24BF23832382247A220022DC246726E727232A8329682865259224E624B124902842299B28212A4E2C152CBA28C52773274426F924822784279229E82A312BEA32B42C5628DC2308232022B921F8233523CA238C225A24C2222C255E26F926CE26A527BF2604271B27F627CA243F26B428F126E42513250A25DC25DA238B257A25BC2345234F245621FA227B2522278429042B542BDB2AAB26F425CE2327244025382905280D261826B0277D27E125BF2672248B25DD26B725842534278328E1301E2D10278A258423712496238922B12271238C22C323B922A9248A24ED2570255224E625E925CA2656258F24102562266125A423B3228D24D52485240625B525DE2513256E2382221E2566277529CC2A8A2A3D2BC528AD27D225F623D922F02403261825E224FF248425A7236E24F9254D285C25C625B22368230C23B626DB30312C6625DF235C242A24F3225222CD23AC21B42288228522F422AF22D6237C25C7246124C9271129BE283D267527F425D324C0249424C7230024AC234824CB261F263026B5220B2360230B288F283C29EF29A82AEA2875274D26BA223823A023C92315246F2336238923CA24A7265625F0264127E325FE24A824F225212701307C2CE925AB221F24B12456239D2327233523732407240422DF225223BF2493250F26022750284B29552BA52847297325BE25F224BB21D623C022A424CB25EF27472614249E23F5239B2313286B29F728312B3A2BAF278D28DF253A246523BD246F231F21302402231122112421247026C227D527C8269423FF25A926AF297432362C892652232123B024BD245023FA24262375227C22A4224C21552245259527BD26C027302B372A1D2C5E2AA6290627C0256C25C0220D23C82226253225B526322502222D2398225F23322782286D263728312754277925F826FB23BC2510232023A622E722E8215B243C22FA24A927BE290028F9252E26C6272A27DD290E35F72C72268F2267244D24AC248A230A251E24B822C32287236422CB2169252227DB286729082B202A812CED294829D325E723B6248D223F218523D22618259F2487238F2119236E22B72268263227E825FA26CA267824A524BE23A322A02229235B241B2306232B225A24D724B32606294E29DE282726CC258F284C2C342DBC37CB2C1C26B0244B223B25A625E82319248D24262403254423E922BA221F2593247D261E299D297F29D42AD0281C287025AF239B249F2316238C24042357239123BF22B02295215A23FF245D25CB26D228C327D0242A249B216F206722CB225725D9249E2551257E246226B92679283B2AD828CC2909289E265429492D2B2ECA35 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 4F282D223122112002210A201C1FC41FCF1F541FCE1E2A1E3B1E8D1D3A1FDF1DCE1CE51E6F1EA11C7C1EC51DC91F521ED71E221E501F3A1F781E8E1E3F20AA1E4B1D0C1E251DAA1B221CC51D461DAA1D431DC61E8B1D8B1D1D1E2B1DE61CF71D3D1FAF1EA21E831C2A1E931DA01CF11E571DE61F4A1F001F541ECB208522B22D4D2B892337205122B8211E20BD2018214621E91E59207D1F841E301FD11E851EB31D5E1E2A1E381E4A1E6B1FBB1F0621661E0A20AF1EA61FE01E361F0520651E7E1E821F701E341F7C1DB11FA41DD31DA21FDC1ED11D9A1D501E3920541F571E971EAA1E371F3D1E861F781FD41E021F9D1E2120F620592017210321C123612D362B8124EC22062290206B209220AA21C11F7D22AE21AE21D31F601F931FE71FCB1F70205D1F3A1E4F1E4A20AF1F2B1F7420BB20AA1F8C1FD31FBE1CDF1E1420C31F7020951FDC1F931E1A1F431E0E1EAA1E541F111E901E341F061DF41E441F561F671FD81E981D601F8D1FAD1F971E8C1E1A1F1122BF1FB5202121A624AA2E9E2B6427EA23FF209F21F920E92196203E201A20D61F771F6B20791FD120591EA81F8D1FA41F7121DD1E471F631E112002200D21F21F73201F1FDA1DCD1CBC1E1620AC1F1021651E231E371F111E601D7E1E771F581FCA1F061FEC1EC91F0320E2208D1FA01F031F1E1F211ED41D831E2C1F751F8320CE214420CA21CD23ED2D882CC725D321D520F520AF210F211E2140219E20AF208420A71F3B1F94200020041F5920791F6C1FAD1FC41FC621221EA51E04227D1F491C571F081FAD1E691E4D20E8203120F91DB91EFA1E0A1EBB1F9D1EC120D41E2B1F961F3220F31EDF1E49201E20AC20E71E1220C11E5E1F801F9B1F9F1F6320491F522096224E23B72C5B2A802543220823632025225B208920E521C3205F21A9212E1FF41F21209120B020DA1F891F3521AF1F261F5820B020B91E2720311FF51ED21E411F991EBB1FD41F2D20891F871D0820F71D221FAB1E201FAC1FDB1FFE1FE41ED71F281F7D1F9420A720691FDE1F991FFF1F681FEC1F0D1FDC1FC221D720B3204E234124F62CA42A57231522A421ED20C6201522F620A020B7210721CB1F3620AD1F10211721812125208020D81F7D215221AC1F1D205D1E1E1EBE1FC91FBF1F2F1FB42063206A1FFF1F751FC71E321E551E961E221EA91F29211B1F041FA81FEC1FCB1E581F9020B91E2620451F981FA01F451F671FCD202A1F8B20871F4521F8219322A12D9C2AAF240622B32215212E1FE41F8E208320F020F61E27204F210622E81FC61FF2206920E7205921ED20331F2920CA21EA1EB81E6A1FC01EBA1F3E205B1FB71E151F9B1FD61F951E861E3D2067208B1DE320971F741EB91D821E531D741F011F561F271F4E1F8E1F3B20711FDD1EF41FA91F5C1F721FF51E9321E021EB23462E57297B24CA2265217E210920E31ED320B22101215820DF1F9F1F571FAD20B31EFE1EA220D1209420AF20151FBE1D3E209C1E1C20361E891DA01D8D1FE51EAB1E671FD81F531F2A1F4E1EED1D791D281EBD1F951E841FEC1DE5206C1FF01E3C1F981F911E7C207B205621511F201EA31FA220241FC11F481F0C202C225222542E0D2C0623BB20B9200421B91FE8206F20132272207A21D820111F8120A4202420D320B41FB8204120262081205C1E8C1F8B1EB4206A20891E9220891E621EF81E1C1F9C206F1FB81FD61D6E1F201FE61D851F23206E1F281FC01EB81FB11E761FB222AF1FE41E9220A420672004215B20602006215F208620CE1F762275230530622A9626A92282210D228F200921E72035216B21AC227821F9204B1F5D20BA209920412080208E20331EED1FAD1E8E20F81DFA1D2E1E4C1E461F9A1EE81DA71DEF1F1D1F331FAF1FDE1DBD1D401FA81DEC1E021E8C1EBB1E1D20BE1FD01FCA206820611F571F5B201A21531F371E3520FA1F781FC01FA11ECE203A223223E52F832BB024C6217A23D8209A1F842053200322C7215821D020B11FC81F751F6920C91F0020CD1F7922B91F42217B1EDF1EF01E121F8B1FF11E1B1E931DEE1E331ECC1D561F0A1E841E851EF71D261FE71EEA1F9C1EB01FF61F26207E1FEF1E7B2061209D209221691FBF21B520DB1F4821C5200020D21F2620EC1F6120B024D02E412C4D266922CD21C1205720BE20681F3321C1200E208221DE1F6B21B020CF21D4203220F21E59218C1FC91F6C1E85210E20C81F971F7A1EDF1EE31F181F851F7A1E6C1F1220BF1E421DBE1E2821971FA31E4F20CD1E361F2F21D220311F0121AC1FDC1F631EE71ED01FE51FE61FDD20C11FEB1FD42148200621F3217F249D2C1F2B422593226422BF223620C320B9211622BF2144204E208E1F891F7621551FC620CF200F203720CF1F2A1F8C1F5C20C520B720EB1E771E8A208B1E211E1C1D651F8F1F5D1F541EE91E1F1FAA200D1F7221B421C21F8F1F1F1F4A205B20D6202421601E3E1FCD1E9A20841ED31D381F632081216821AB20A1212D22FE23312F6B2AB72423238921EB222C2119225F201B237320BD211422AA1F0520C51FE4205F1FDF21B322EA1FDF1ECA1ED31FC420FE20771F871E811F931FA61E821EAF1E3E20BA1FCA1F721F0F1FC51EFE1E5020B31F0D210721191F961FFB1FBD1E1E1F531F7A206620B31FDB20F21F681F4A2039212320E221521F7720582272233D2DDA2BD5252422C9204C212222B421CE21FA1F8F211522C220D61ED520622114221020822199202220F321FC21411FF51F731EE21F3A204E1F121F5E1F9E1E9F1E151F831E5F1FBF1EE01D3E21A21FDE1F8C216E1E8C1E8D1E7F1FDB1E201F541F7820C41E9D20901F4D210022251F2021522030217921E9215D21002224246A2DF129CF25D0236D2326214C217621B3218A201421A9229E21D7200921FA20382118218620D2205420C6211520C220A820192011215620601ECA1F3220671F9B1FB91FEC20FC208B1F551EB41D851EAA1FBF1F5D1F0F1FA31F0E220F20191FAF207D208F1F9B20601F3A20F41F0020491E5D21262168215222832289222F251D2FAC2B31255923C420E5219F229A215C21B6210F22AB219221482152219C1F6C203D20082126224620282014217120AA201F1F2E21E6202A204620011FC220F61F7F21A020C31F031FAC207520651F731EEB1FAF2137205D1EF321A31F0D1F221FC4210F1F8820E31E2821B71F7C22CB21C222A621042169219A2293227C24D630E929F2262D22AE228B224F220823082246210C218622F71FA020C020ED215720F1200523D4203C231222EC1F90216322401FDA207020AF20F21F401FBC208A203521F320B320761EFC203220CB20541EB620A81FA71FA51FF51E511E881EE81F60209E217E22231F3F2158200920781FFD20CE205D2082204923CD222425842FCB2CB82418220C22772104222321FE217220612059212B22A021A91F5522952214226A1FC02134223620F81FB31F5A20152177203C1E0E1E3D220F207321281F1421D421AD20B8202A203620E01EB61F54201220021FD71EBA203D1F15200F21772262216621B4219922981F8B1F3822FA20AB2055210F2141221C24A124482FA42B6125A0238D22092212225620012151219221F8226921212036209820B321842057234E21782087200022D820AA20452100200A203F1FEF1FE820DE2069224F22B122AE215521931F591F8B21A21EAB20B82047202E20D71EC220EC1FAD2095211420B2200721E022A621B42198248621B5217B239020332304245C24292FD92A6824D9236D21E42066214D2119211C22DF21751F8E210D21F121A1201C21F621D11F12227320412128213421CA20751FED1F3A1EB81E5720A31FCB211C216E220623CD214621D8203E208A1F37203C21DA20C81E721FDC1F8220251F0C20CE20C92193209E21DD228D210522112180204E222B214A23C12382233225AF2EE22AD924CC219E22BE22802220226C219422C3216B224622BF2152203B22E4204721C0203D210D1F581FC61F5A204F20A81F731FC31E9D1FFE1FE81E3A21E321D320FE21E021AC219F20A523A021F81F41224921EB20AA1F92208020D1204C223C222522F1237022AB23982420235C223D2247219F22AF2365234524C4243230542B96247B236322AC227F20062258225D217F2025210122A51F702145233C2157211A228D207421CE20D120C52120223321D01FC81E8920D920D41F5A21B321E021F1226321611F1F226D22C2228922F522F4211D238B21D32115210321D422A120D2213B2212226923A921BF22A123F323CE22E223FB23512534246826DB30A42B8424D121E72182225121D220B820DF22E720B8228821B92062209D1F572060209620262185232D20A91F5C210E211D202D202820D71F751F24200320602120215022D121C0219C21562134236821422155211922092260228F206D20FE20E022F6209E207B214E217721D9217A249024F523BA24E624D826B52649251D2F1E2BB22440228823E32106229E221C22152297203D217C219A209821E321C221C7222D20C22148216021862254204521822034216A2105201322CA21D1224722C52241229D221A2285209C22CC221E21E5226322CD20CE1FA7229E208220A6229B214A228B22CB2058236922E9235F260C2761257425A2240126D124AC2666300A2CD1255D22B5210F230D238D226A2234227621A6228222ED20FD21C3212022032334237D204C226E21A4204C201A22E320E2205022EB202422B622E723EA214223B122A523BA211724E4227F23D5232E22D02275218120DA209922B52161243423352364246A24BB240923D024F626AC27D12719273C264C2411254025B62FFD2B072703227B2319230F232623D223F8222022C423EB21AF241822A3229322A421A922E0212522782180215E21D821C221FC20242066210622D22239238123B623E62380236E2248245F239B24F322D022D0210E212021DF2096220922B9236527382605267F27A82690257625D7266528A726B226482592258224DF26DF30E42C0C263C25C624C22362223923BE2375249123A3214A239E223A24A922E823DF235F221423DB21FA211D22ED215D213C21C0228D21B5212723F523D122152482249C246425A42332256F25F7220A23BD2315223A22812170238C21FC23EE2637284529BD28B2299D289526E92504284A27CA2780267A2451243B268326B530B62D29276622CF22C4224125FC23FF23DA24AB22C92439232723DF218F22BB23D823EA22302394247B215B222A218A237521C522D62387234924AA23D423722406248724DE25F125FA25EE2568241E244D24B0230A25FA21CD23C52349259427342A272C9C2B3E2AE82808278025DA25F925DE2664276A255725FF26B427BE32DB2CCC25D5236123CB24D223C423FB2498238525FD2124235D2122222B213E20702112223723BD22102182202F23F622E422FD23EB258D2456253625A32409240424CC25DC264326C225AB23B22335235623FD25E622C3234C242D25C024102750285F2B9D2AC026EF276A27EF28C428F927462777273B263F28D628A9299E335E2C2628EE23C225F42505236523A222C4244325DA25F2239A219C22D324B324552202234923DF232B21BE217F213D21062353263E278226C42602242425A2246E28592868293F26BB24552536241F227E2439277C2536266626D325C8267D26A4289E284C261326EF25852659285F29F729B42B162950288A27E92A2F2C2534EC2C65268224C624F12475245225D12317230E24F02345232B2462238523EF2300248E220325B923052314238E226E225124AA2792287628C4260C256623DF256E289C2B4E2B8C283F249A25DD23AE248A27022AEA295728D2260E26A92665252327D02565244924C227FA280F2A6B2A4F2BDD2A012B1B29FD29822B142BCF33C52DA828E7256B260C250D262C232C23FD235523E422BC23D0234F24A4242324A1239C25BD241525A72596235925F22442264428D828662595256C2582248B261F2B6B2D952B5028D3269B239C23F0242B2A702CCB289927B226FC24CB2482245A242D24A42489257527F927B328B7287F2BF52BE429372A6B2B282B842921336F2D3627442486255A26A623532440221624FF2221242A248725F523B9244024F7245526C526B326C928D2269D25E327AB2781276B288324952381248125F128C22A762E5D2B2F287F263C25FE244825012AF92B92290A2871244C2437258822CC23A9225C2283236926BE29B02AA72BE82A3D2CAB2C062BD729F6292928A230E32B8C2603269C24952549248D235A220F232E244C26B627422655256F24FC243E274627B726D728932602262F272E27C2250D26B52656239D234E25CA26FB299E2B682C2B2DAD275524962669274B2793296F2D472BE1267625422531245524DA2268224E24FF268229022BB2294D2B662C142D052C1829E12711271B267531AC2D1B274C26F8254625132315227D2331248D2601290D287427E224EF2424252B260128922771283326952433246C26C524DB237F260E24682420271228362BDD2B022DC62A552655234F2519267428032C9B2C402A152790252322042336228F24792163249827B1286E2ACC2B8F2C052C1E2B632AAC275126F8244F25932F822E2D290427D425E625F62431251C265927D0284D2AC5280D27502984264F24DF251A25AE257E257E259B2156232E254E247223A924DF2321255C27DB291B2D782CFF2BDA29E4258A230C235B261E28C92BCF2ACA2BD927E6244324EE228621B7225A232F2461262A2A6E2AA12BAF2AC8294A262227B924CC231C249825B1304C30E7299A2847272226CF2432256126602BCF2AFF2AC92AF9290F297B278B24D925B724872321242123FF23EE259F2429275F263524AC2547250A28702B1A2C782CFB2B472AFF24AE222423EE246C28DC2A2D2A562AED280E279523A02240237A23BA23C825D5275229102A4A2959287325BA235124F720BC2340248D26B02F3831692B1F2AB128722506255F26B628D52ADB2B6C2C3E2B7328C8257B246923F622032444239A23D5253425DA263C290329F22819272C26E426B528072B0A2BC22BAA2AA128B7241424DA24922528273329F9299729FF27802780231622AF211223B6249E27EC28F629F827F02586252925C323DA241A231B248C25F427A132CE31F02D7B2B632B32290F288028F72AF92D322C5D29E3273A276027E9256A247925BE24B5225F27D626C428242AA12A522B562BD32759264B2934292B2B6C2CF52BA329C927F7249824BB267C267727B128872861287B26D12401234A2370246823562557275128DF280727AF257725AD241A24F22352234D24F325B22A3E35EC322E2D732AE32AAB264E263528612A722B032AAF29BC285D261625D424AC23FC238B257C27E728E62A512BB92BB82C412CC6292B2756247F268728CE28352A1429A0274527502363248326FA26CC25C925F626862706272626602386228C2209252B257F256E26BA27B725E6254326BE259C25B4268F248526BF29BA2B19330C34402EF72C43290E2A0225CE27A929A2294329F328F828692744254D2536241A2595269C29152BC72B132B522AF22B7E2B0229D4252525DB241C26B727A7270D263824942549247824332455250226D82741284F29B0260026B524F9239D22BA231D26ED265027BE282328AE27632852288F283328D427B8274527652A013396325B2D1C2B26297627512783268D28EF28102AE22A8C2AAB281E27B423F923C82453295F2B732B1329D728BD29172BAB29AD2B7E27C222DD24C42362245A2630255B249A23C4218022B5232E2797279029702B9D2AA529BE290C27F0246C25D8231D259F27A528702974292A29192A602B092A5D29D526CA252A27F828E5318832DA2CBB29412702278A270D26A6266C2A8E2A1D2B062BE4271725A7251D252626EB29D929F329962A59299429AE2A382AB227592491231523E522EA2308236A229A23562369218E236A268627C32A5A2BA22DED2BFF2BB2284B273B252324BC243626DA28062A402CEF281C290B2B752A1829B3279F257C26AD25F625A42F6431972A3B270826E7261027A927ED281B2AAE2C6F2BD12AE228BB26BD25732546273D29CA292B2A362783277829D92AD82B34281C24E422FC22FF1F592350236924D9247024C323B0243E26372AD02A442B0E2DD12AEE2A3A2A9925CD25252523242D2590279027572B0F2B4D2AE52B352AB6274527D2249825F0261926842FFC2F552A6C27952542289329DA2AD929092BE42A252C8229F426AE25B8258526D927572A46277F26A72643262A29D92B692A66272124F8230C247923A925702770271B25772591256226CE28C22B3C2AF52AD42A812BA629F625C825FD24B123F7215A24A2237625062887277627FD296928CD2427259F230E247824AA25B030DB2E7728A026B5275628152B6B2ACA2A0F2CA82CF72A642A61276F25E824DA2517286D271427592769265C277E2B322C252963266A24B123FF239E26E1274B28C6285B2733272F26CB27FD29C32A972A162BD12B7C2921275425AB23DE232E246B23B22403241F23D324F82449260C26F723BE23B8230523D623802435261331532E8C2815260328F429162C472B9229D32A402B7D2CAC28F52469232E2496233027F224A7267C26BD259229502B172D0A2A0726E221AA22ED24CC24E8272529012A6528ED288A264027582747281828CF288329C726CC2421246B2381221E24872379219F2235225B24A924BB23CF24A5236A22D0216622AA24B9254428F430CC2C03297A27B829AC2CBD2B8F29392B262D832BCC2918283B2496237C24A826EC2581273F28A129202A482AD02ABA28AD27FC25E6230324B823E424A12767299C2A9F293228DD26C82533266A26F3261B26102740251B2219239D24B32385237522922528242326AF254525E723382344236A242324D3237826FD2651294B34A72D0D296729D529E02B872CB12D9D2CF82B89299228DB25A72450230C250226F7292B2E942B2B2CC328B028EC26B62638226321F6226A221323B5259E2661265025C225A72583252225E92305244424B42598239E2329241B255327172653270027E927592698262B2718259423E9230723F822BB25D926702AEC28D02BD533412F542C2A2C342C182B162CBF2B472BCA2B88293028CF243024BA2547273229AC2A642C1F2C172E6929A2278926A325C7215423F922CA23F0251B247825C025CB26FC286C272A276F265426C424212315247F256C257225F326E0285A295E2993288B2823280F268B280126F02393235924862637288B281F2AB72C162DFC356C2F8A2B592E4F2B912A38297428AB265D2833289826F225F3269E267529ED2A432BA82CE329772BCB29A426EF24B62211236F216F2488243526C12456265C26D227E82AD62BC62A922AA3278C25E12318247B258625F527D52AAF2A7D29D128E126EF26D4259325E5234C23B924D124D2242827BF2B352B122C5A2B632CF4372732022C792C8F2AAA2919283B26B1272926A824FC26E12696269527E3289D2ABE28C3286328FD273A24C0249424A424BD23F6246C25FD26AF26D7266B28C128A22B402D932CA72B8729F3277824A423502610283D28812AE229B0298226B3255C277D25512494246A2528230325F22743278E27CC2AF529212BE32A412B593400312B2E712CDA2C572C472A86284E2758258526D628742B8028482987275B267225F4247925BB252F27AF24FE26F3264526D427BD2A1729002AF32A142A142AF92BF32CC52C1B2D442A2827FF24B4245E283A2B3F2B522AF6283328F325BF26FE2881270B264C2524269E254F25562628268227332AA22830287928D32712309D32182E202ECD2CF929472BC7288928B5281D2772292D2CB72B2427A72529248B26252642260B2931287D299929C72B8B2AB42A6A29782B8D2B5A2CC72B142A882B732E422C0A2DE02941277B2492269129FB2B7329A0281A274527912769289A2973292E295425A6287328DE252C27B7252326A7296928CB260D28E8286531982F772BA52A402BEF288328BC278A28DC25CD24E828D726E0273E269E269F253127792766273B28682A2C292D2C5D2C3E2D3B2BAE2909292B2A092BD32AE829232A1E2D142CC12A53284925FE273928522AE72C9B2AB928D8273E2721289429AC2918285D273427CC27FF27A327CC255023F2222E28A327DE28F927D3282E322C2FA9279327AA27D128E72635288C25B725F0263927B0259526DE2657287C27DE27F12721277428D228372A352B982C4E2CE42A8C2A132AEC2947299B286727D9272C29F3283A2701250F24A227B4281D2C0D2D102C70281F28B2263628102A5A2A9F29432A132864294B27992573247B24E527D42A332C002ECE2A4A2B18348C2D0428C3270D287F27582737261A2688266327BF28402895298F28892A3B2A86287F26DE263A28A529402B452DD42C122C102BEE2BE52898290328C227ED25F7243B262B277124A4250A27F4276529E52B032C5E2A7D2963277F26B627902709283729F92A97292F2A2927EE258B26E4258E2A7E2C362C902D262CAC2D1D38832E76295B2BDA2ABA296028B225F3255F271E28732A0E2A5F2ABA2A3D2C79291628A2262526CA278128442AC22BAE2D2D2FB32BE72740244725CE25F324A4253124C325EC2463257B262D29472BF82B922C532A6E2CED2959283E261F2515276627D727602A46287D28DA255B236A279129242C662C7A2C262C092D332E05378F2FBD2B502CAA2B342AEF282D25A5261B28A229132C422B6C2A2F28EE272E29A4276B260426B4265F28632B312C172DA02ADD27BB2584244F224C25FF227122FA22E924152511263F28732AD82B522BA72B1D2CBA2A032B0D27F0246B25D025412779278727D52624288E26172659270C2A432C8A2C50293A2A9E2BFA2C3D36402F5D2DDE2BCA2BB8297F28DE2700286B2AF62A9E2CBF2A3C2B6F29D02848255F26D325FC25EC266127442B8E2BF3297627B8252F23C722D5223D24262421249224D124DA26E128DC29F02BDC2D472BC02BF12A1E2B202AE4287E2476238C241128A529CF2AFB276C28B526E7266F292B2B442C942CF22AFF29BB28112BC434EE2F7B2D8E2F842B8A2B662BBE2ACE28D6297E2BAF2C592CA72A3F2A8427D227E0266527E5253027C12501290D28CA2715259225A12275227424D925922581255124C3248928DF275B2ABC2BB22CFA29EF2A0F2A3928BA269628CB23B623EB25AD29982BEE2A252B392A0A296F28192ABA2B9D29A02DB42893289B2BC82C4F3503326E2C2E2EDF2C292EB02FC12CAB2BD12BEA2A8D2C592C922A23296B28EC26F42A492C4729AD25E826C026812514270826C8235C2515252D26C9261F282D275327D52789270F29EB29302AD72A042862276428E127E227CA27E026E3247D274129922C7F2B282B5E2B3F28AB27CB2CCD2BB32A402C792A6D2A392E692C01378230952D6D2B032D1A2E0E2C0A2D3C2C912CF22B4C2939286D26C0263B28C02A7C2BE62BCE29F22733250F2702278B257424D7255C252E27C1295D2A8C2968294E2AC629C9286827842890281326702689276526CA28D5287F2974263525DD262D2AF629242B8C2CDE2AC2271127B82A262CAF2D3D2B9F2B9F2BE22D382EE836A82ECB2B232BB52C942AA92BFB2CB42C612CAF28552A04263E27822676286E288B2AFC29D5290F27D2247625DC2521282526A825A4273F28E02AA62B6829FB29512BF02B5F299927B5281027C724BC2345250F27B0282229822859265D26F825D929BF2AF62A2A2A6E2815271127D82A412AB92A5A2B762CE02C302C8C2DE5351A2DE72992283B28A22A2D2A2A29972CBF299328DB266E245E273B271029B728C628632878260E274326BF267529C629102725268127762A012C912AF429802A8B2B402BEC2A322858258A26C925C8239324F62897265327A7288A27E526AF27FA26C028522A7A28E028EB262328032AAC29DE281329CB2A1B2CCC2D162D4F34DA2FBA2A442AD12AF52A5F2B052AC72BF428B1267A26BB2760260428F9271628452886272A262229CA29E428F52B9B2946292A2A8F2B102ACD2A5F2B48294828052AFA295528FD25E325CE26BD276528AA29202BF429CD279A253125AC26382552266B29FD288527A3269425D9293129B7270A285A2AE72A2C2B032CC12B9131E2316D2BB02A442A8C2BFE2CCE2B4E2A7B28CF25E825D32505285D285D27CA27AB26B5271728AA2BE22CB02BE22AEA2CB12A492ADC29822A8D2BFE294B297F27CB29E429EC27742700273726C0282728CE2AB52C5D28B22789267525B527F52680269926A3240B263E2510288427CD273D28B4280729762AA22C872A2F29B4317630892B94292629A02AE22B502A2F275F272226E32783299529BF295B291225CA255A29FD293A2BD72B002A442AF82A282C632B5E2B8929D42A0E2B8F2A342B5A2BB12B5E2B69276C276629632AB228E22940293627E124F728022964286A28AD2536242125CE241E270C27F228452B362AE62A2C2A162A262933288528D430D62FB42AB42A5D2BA62A822A81286A27BA288B29192A272DB02A2E2ACD29B5269327CF275E2A552C672B552A8229772A1B2BD42ADA2A6C29E62BDF2A802A86295A2B432BDE2BA82852282628B528F626CF271326D7255B254E295A28D62795275B258F236F24B424F9272F292F2CFC2B312AA2296127782720264126F927DE32EF31F12AF42A7D2CD62B852A08275E273D2ADE2B562B252DC12ADB2935286E2795268F28082B362B9A2B4E29EA29A52A272A3129C927B828FD280D29642690260F2AE72ABA2CE12726272527C725C1248824CD251E2484261D2628286425CB247D250B23412599269D27B029082BA02BA42B1529DC2634266F278726D229DE352730A42A2B2ADE2A522B3129F7286D29AE2A632BCC2CFB2B662A84279926E2274C27E227C52A8E2B99280C27E6257627022666263D257725D4261A25B0254828AA28BC2A4F2AD6260F264D24AC234E230D26C6256828E627C3274325BE253025F2244C249424002746291F2B152CB02DD02ACA285F2708265D285829B32C4D372A30B12BF728402A0F297427042AB22A182B942AB42A7E2A5D28C32717276928D929852BF32A512A30272529F026412676235A2518242724BC254426F9248C262228AD274527E7236F23A62448241724CC25AF286B2BAC2A99298D2852286E28DF277C257526B628072C7D2BFE2BFD2B0A2B8928BB2633259128C52AB62DF7376E32B72C442BE02A912988297C2B022B632C682B302C412A3A298829D027702B772DE22BA32A072B3F2929287528DB271025CC2446245425A72691250828DC27C228F027AD271D25DD2428265C252A266C28ED2AD22B9C2AFB2C6E2C212B192CF329FB2963282128382D8D2C062EE02BAE286028C02845289D2AC02C3D2EBA360B31582B5B29CE27AC29682AC329092B712C512C442C6A29A727E6266F28DC29F62A852A7029C32A4E2980290C28FD269823AE266D27D626E12858282B298527562676262F26D6269A2531269D27E727D528C92C682B5D2B4A2DCA2DB82D812B2E2A6227E9269326CA29862B4A2B632B65279827092A9529EF2A2E2D712ECB3524307A2BF327E9267329A52B532C432D972DEC2C2D2C472926267E25ED256D2857274528CD270128522AE32C392BA827FC26D127EE29EF2AFD29BC2AEE27C426082886267429C628C5271F27CE288029B02C942D162CF22DD92D4F2C0C2DE32BF2295A279B255B27F828A029822AB82B30299F281E2A092DB12B732BE32C8E34BF301A2A1F284C274229542C0F2D382C572E0D2D202C7A28C42522278528BA294D2AFE28F5281629712BE82C992BFB290A29D72A1A2D4A2BE22A99288628252739286F29702A5129E228262ADE2A5E29382C132CBC2CC82DC52D732DCC2A7E29CD26622680276D25A329112CF5290C2BE328202B5D2C7A2A0D2B3E2BBA2A4A348F2E7529EC276528D5297B2C222DB32CBB2B662CD628BC26FC268428F929EA2B722B6529E2286D29552BD42DD32C9E2B962B6C2D392C2429E8280A27B226A0257D27B22A442C272A002AC62CB029DB2A392B7F2B9F295F2BD02D712D8F2BDA297F282B275D24AF27142A5F2D952B552B402B892D9D2DF82C242D7A2B892A8033122F0D2921297E28CA2A332D112CD22DB92C082A45287A263828E929402BAD2E9129782A472A0A2AAC2A752AD72B662A96285E2900296328FA263F2607290E297629A7291C297B29982A5C2AB229E228AD2775286927B9290E2CA02D8A2DE82A9828A22621267228FB2B182C742CBD2CC02CC42CE52C722C782C342B5B2BE734262FDC2A5C29FC29EE2A4A2B372CE22CDD294029D52772273D27192ACE2AFC2DF32AC1290A296E29D4291B2A0E29D829EF256B27A526C525C726A0284F286B29B12981294C292A2A202BE62A7C2A0D282B26B22637269F2729294229A12B982B42292629A7277729252B6829A32A0B2A392A1B2D5E2DDF2A352C3F2ACA2B04349B312C2D822ABA29AA2A932B5C2BCD2AE729A128B228862A562C452B542CD22A14293029282AE82B7F2C962B7A2AC927C3277E267625E826EC29BA2A2C2A192C542B4729A4271027AE28E129522BB428EA280828C427982668286C29772AB82CDA2BDA2AAA2A7E2B7F2A3F291128D028E129822BC42D452DBC2DB02CCA2C1835A630602C9F2AD4280F294F2B5629BD277B2636274329B92B512CAC2BAF2C6C2AEA2A902A802B672C682D1A2BA72863263E231424CC241925792A862B5E2C482AEF2A812A472B93284B272328D3291229C6284F29F527A5250A2CAF2AFD2BAD2BD02A732C862BDE29BB29D4277826A226A126F828012A042C942BA72B8A2B533310306B2B24288B28792A252C7D2A08271127A828902A9B2CD62B882B412C6C2C162A0A2B0A2AB12C2A2E4C2B58296426932436247225AD252F2A2B2CE92C3E2CC42BB82CC12C0F2AFB27D025422859260A27E9285F278129402B122DD82CBF2BD52AF32A442931283527C126EC26BF27E42745298A298629752B4C2BBF2A09334031E0289628ED29C72AB62A402875274926392A312CC22B292AF92A052C752B902A0C287228A92A9C2C6C2A0D2A442784267824AE250F26502A252A992A022BFD2BFD2CC92A032A0D27002617269B275C2B212A482A27298D2C6A2CB82B192CF0294229EB25BF257226AF25A528E329432C512B9E2915283F2A2E2940299C333730CE2A7A29112ADC2A0F2A8A27E62652283E29ED2B1C2853294B29AB29D92BB6292A283E26092AED29B229262AC8286F275F27F0272B2A592B0D2BE92B1C2C312B5C2BA2299E26B725DE241F27D128CB2AB32B9D2A2E28922C0A2CB12E522E9B2B39296F255C2468279328112AAF2BCD2B962CA32E1C2A59297D284F29223246311F2B782A432A172B272AFC2669295D2A1A2C1E2C5C29A827CA27CC27712ACD296B27DC267127C0281F29C228E22888281F2A012A3C2C102C012C2E2B802A022A95296B282E248922B426422AB829F12BE12D582BE629C72AAA2A052CBB2C632D8D29472745274A28B529062B462C1D2B4F2B922C262CB22B072DBE2CE433712FFF2A3028532929291329B0279C29232B802D5C2E172C412B2229E42A4A2ACA2A812987292A2924298328CA2AEA2BBD2A402C052AD42AD3298E29BD2958299D278B279D267B262227B228FD29852B512DC22C7D293C2ACB2B672C102D972CCD2D3A2987282B270928862AE929F129FF2BAF2CE82CF42BA52D802DB62C9436A031522A23280527FC275427BF28E129872D132D722DD02D642D892C852BFF2B872A8C2C6D2A142B372A6E29062D262B872A642B142B932A202957293228BB271E29DA291329AE28E7281D2B5D2DE429D52CC92B682BDD2C0B2D762A832B3A2A302CA2297229262725295F2AD32965299A2AEE2BE22CA32C3D2CE92B592D36367031CB2ABE26F824452526278729F12B282DFC2CDF2BAF2BFC2B462CDE2A472B762B4D2BA12B542BE32A602A4B2CB92BDE2A9F2C4B29B9288B285D2900298F29AB2A7F2A2E2A1B2A9F2AFE292C2A192A462A052B402C84299D2AA42A4F282F29D829B329792AE32516272029DC28CA29BF28EB297D2BD229F72A452B812B1D36E130A52A19263B24BF25FD26EE28DA2B3D2D172BCC2C482C6F2B982A562BCF29FE28DB2B8E2B0A2A692BB82B8B2C342C7929172B672AEF28372B002A842A222BF42A1E2AB02AE228EC2932292128B926D3282729C828E827B4287B263B28AC28C428102A942A112A4A2A5726ED277429262A242931299729832A8F29C52C173795301D29BD264425AC268F28C62BE72CDA2ABC2BC62AA12C582A4E2BE92AB0283428A12915279E27FE26D02655264427DA269D261D269C273328A32AF42A242839286A276C26DC25B428442800285A295A295A2B7027AF244B25B325E329F22A882BD22A3C2A862A242B1D29D2294C2CF42C802BBB2A7D291C29F928AB2A0535402FBA29FC29072799262F27842AAE2DD32BCF2B3A2D902CFA2AF42994285C270127D0260125AA254B252C25492575267D24752545246025D2273827DA27102781257E24CB259F2648287A274028802B492ADC2C282833245626F8265B28C628FF29BF2B592E402B422CD82AA32B522CB52C772C662B8D2A242B022B422CFB34F630AF2B862905292C274B288A2BA02DC72DA02C902BFF2B9E2A4929D8279C26D42563253D262A25FB25E6240F2656259725232551268326D5276027A72620276A256F26CB263A244A283528202AE92A042B772BFA289727A7278E29822CE62AFF2B582DF22D4A2D022BBE29812A652C752B022DE22CA82AA629F828A429AF319031CC2BAD29B727F4263327C12B442CE22C8E2CDC2A7F299727D32520277C26BF25E1265B26FE27DD268327D5289727C626EB2759285A2A712980268526762780289F27CC277A2696288528162B442BF82AF02A662826275A294028392A6F2B112D9E2C122DE92AEB2B2D286727D12AC32BC82AD62A4A2A1528BA280B2BCF323D31662D212B0329B027FC25F129DA29412CA62A36265C26932759267026FA271F288F290B2AC32A6F2B532A0A2A1B2ADA2868292A2B972B17292F27BE25EA27B329422B002BF42764297329AC288827412A6D2AEE27C8269826C5265B29312AEE2BEC2B702B992C5A2ACF269E2572267E271129F5296A2866288728442A8D34FC30692D102BAA277626E9243226BA27AC273F283228212898280B281529CB2A2F2ADD28D32AC0290A2C7A2B7D2B95289E25A4286326C62722284F27F42419289D2AA42DDE2B3B273F27CD2570287F2578262D285027FF253D286929642919295D28B829F02B7929DE2A26287D26AB25DA27C8255429FA2A7B2BE92CC42BC2346331DD2D242B4C2A6E28F925AB260C2AF62B892A0F2CD02CA52A742AC62B2A2C322A432AB529C82A062A21298B270926C7261B292F282727BE273F270527A628C029A12BBA2ABF27C9267128C6285F27262834296B29942B8C2A8129422B6E2A612CE6287D2815287D270B264A26F3250E24D028A42A4D2A302B672BFA2BE332D730952DC02B642C802BD12A0629532C6E2D312C9F2BD22CA72CCB2BA42BB52C4A2BFD2A742A352D2E2B3029062A922881292A2A3A2AD02822261127FB27212A612AE32AFC29DC28DE280C2AB62BE52BF92A502B9C2BE22BA82B092BF02AD22AD02CC52A7E297B2AF5282827BC25E5258B278429572A082A75295229C929A5311E33002BA729C52BE72C1F2A572BF22A8E2BBE2ED02CE72C192B2329212AD929EF29A42C802A002D422C452AF3282429C629C82AB1292F26CC26B427AF28622B102B76282926DA2672276329842A99293B2ADF2BB42BE52A4B2C172AE82A732BD22BC12A102BD129932B9329E6277927972659291E2AE228742A1C2A682AA334E72F392B7328EC29B229FA2A8C2AD62BD62C752DCE2E852C0B2BDB2ABD285A29BC292A2CBF2CA72CAE2A1E2BDB2ADA28EC28AE2AE028EA27192AA628C72AE329862B80290228F428B227D92796281C271D27B7286B29562A6B2B512B992AD92BE02C8A2C292C402CD32C1E2CBD2AA4296B27B329812A212B612C672CDC2D9E352C2EC727CA267C2566272929D129282C7B2BB32CD92CC52C0B2BE92872289029D129BD2C452C292C9C2BBF292928B726AF2935298E285728AB2830296D29E928CA29A12AC32916285A272A2A0328ED246E26C2291A2A442C022C3F2C8B2D352D922BD22BFF2C322DEF2AEC2A20293329F2285529CC2AEB2BAC2A582D2E2EF134472D3E282A26EC2732294A2A062A062DE92C242D302B1D2CF82A2228CC275628F528282A8A2BB62A8227A12642255726E3241D28EF272728F8288B28AA265A294C292C2753279726C2269928562808256627FD28252871277929D929132BB62A172CA22BF72A132A4D29DC28752761271529722A9C2CF82B7A2CCD2B5A2B3435A02E83284727BE29B028152B332A302A512B042C0B2C362BE32A86274127B9265E282B2AB02A1F2946288225DF2674258A2595274627BE29CF29DC28DD257725D2270D2835257E254D262F27B124BE23CA264B25E826B1253B28CE29D328C6271C2A412BBE2CD929C829C1288827C62812283C2AFF2B2E2B532DCD2C152C7635692F0E2BF32AB829272B9629292B30291D278D274A2865287927F929CF2998295B29252AE82AAC2AE92873282328AF27D427C0284B29532C012C7E29EC280A2876291829D32647259F263D27B8259D24E426CE27D9264826FE263B27F02609267629912BF92A6C2AAA2AF42ABE275B28E026EB29CF2B252B662CDB2BDE2DA736A32EB32AB22B982CAE2CB62C262BD427AF2673275626EA277329052BB4298F285627D02AD02BAF2A032AA329B02D3E2A332736272F2A6F2BDF2CE12BCA2A2B2CF22A8D28A326B0258C269C26E0262E26F9282E294029DE29B4296028F4287729C62A392C2F2D6F29762A462A7E2AE22ACD27C4285A2A582B6B2B4B2CA22D7C348C30792CB22CDB2D5B2DD22CFC2C432A6D2BD329CF2778283C29FF2B312B432876276B28F22B0E2C5D2D732B3E2AD528A828E929DA2AF82DF92C282C102C002D702B9E2A9628F9251B29412AC929BE2AE82BA32C8A2AFA29362A632B4A2B4D2E5D2E3B2D972CE92BB92B562B092B332BF42805276328272A082CEB2B772C8335AF2F292C392CE52D192C802BC52C1F2DBC2B4829B6287B282529F42B012B2127FD259127292D092DC72A1A2AF129B92948288728142B852C4A2AA02AA02A772A812A34291926E7250228112C2E2BEB2A9A2B752AE428B1280A2A2D2C232F902E462D862CB82D832C0A2E2F2C522C422A732731276A28612AC52AD02C112C0D35C32E2C2C652B6B294E2AA32A632B502CA62C262C922AEF2A182AFD298B2AAA2824269828F42B2B2D462BD32C4C2A472BDE2959297B29072B342BA22ADE29A429F8294C273926EF2663278129062B542AFA2A002A7828422713293D29E22B292CAA2C912DC22C1B2C7D2D5A2F732C902A2328E428B12852296D2C292BBE2C82349A2F3B2B4C2AA5291228CD2609285527F8279B28172855284C29E9298A29ED27ED24D125E72AE42C4E2D952DBA2B68290D286D29472B452B042CD529D028AC26A7263225552538264728E129442B5129DD29BD2AA9284D26C727FA26A1276D288D2B0A2CAC2C732A1A2D412DA72CC02B0429B729842A502A722B1F2C582C81337930A72B482B3428E327BB251D25EB269025E32653267827BC278B2658252525B424A9262629F42B722B5C2C072E592A8227A0279629852A652B31294C28972894262825D524752585285F29E2293029F6295A2A0127322555241B2594260C27CC290B2B4E2B102A752B3C2C2D2EAF2CA32A3C2A652968274F298A2C782AAA33082FF7287A295F275C25F4240C250B263D276227F0253B25DF249E263626CE24DE242A260C267D286728DE29D52ACA270427C2268E27C928412AAA2B272A05297327C52424253427EC2793286F28E7284729982AD527E2247A253425A2258228112A382CD82B6C29702AC82A242C132C282C092AA128C5275928852A342C8B34352E4A291C29432775260C25CC25E426DD290329FC27F6260C26D8259E26302731261D267B25A427E4268F279D29F1284627BA27F825E4264D2A4E2AFF29F3275E279326902586261527892831270329B82BA52A302A902792276527B827C32AA92BE62BBC2BD029B52AF52BBD2AA72CDB2C152927293F277829762C3E2E5935412C6428B12500270227112543265D28E1296A2A272A90277C263925A9242F26C1253F271D289E27BF26D4267C27AE299B28F7256E253D26D028802A092BA7299A291A29B8284A28E827CF289328DA27232CBA2DF32AF7281D29F9277328CB2B182E4B2CD32B672A892B1D2BDC2BD52C972B46298728AB276E2A832C422E0836E32C1128AE279C26402932283329142BA82AAF2B762B582AC828CF25412665253B26DB27932C7E2A2329B6255527112A002A67271B261E2671266126D7265728AC28D3274A28502AA92A3829032BF02A772EA12B122BFD29032A0A2AEC2A112CE12BCE2B172D0B2BFB2C092CB52C3C2B752BE92A522CD62B262C5D2CC62EC736922D1C273526092AEB2A112BFB28442B152BB02CD12CDF2CB0295027A027E6263A261B292C29332C52298724FB263729962A2529A326CC25622698255F242726E02415263128DF271528E229F029C629012CEB29DF297D2A3F2A9029B9298F2CD62B902B2B2A412AC42BD82AB02BE52C4C288628FC2A542A6F2BB22B562E5936F42D6F272D2865288D2B3F2B152A712B552BC02A762B532A652AD4275827E427D025D727DB28022B63298E263A264526232795294329F6275B26CC25EF231F23A024FF266A25AB2679282126EB292729572B4D2A0C29E72675268727FC28722AD82A8B29072B382A262D092BFC2BE3282D28C2275D2B662B262C4E2CA22C11362F2DCA288D2668286028C02A4C29B327FB28312AD82A3628FD250127A5269426A0276527B92884284C2660269B26442791280A2BCF29CF285228C225332551245B23EA23B2239F232625D02517265927122AEB2BAD294227E8251A288429102C952BC1281528492ADF2D002D192C6F29BC27FD27912AD22B4A2CE32C2F2E84376E2E82288826C725BE27A6283D282A297028DD25EC265D258625A023D1255127882595270D270527C925BF26CC258C29912A222B5E2919293529632961295E28AB26B325CE23B023E622D925CF27B629C329C72A4328AD253E26B6269329252BDD2AC5293D2BBB2C592E272CD02A1F29CF27A627142A8F2CB62D1B2EA92CD136362E3D28222500260E273A28EF27C8268F279124FB23DE23A5230E2537286E2A032A0228EC256D259E24AB24CA262027F428612951284E260127282872287028B427CF24772329217F24DD23DD27F8285C2AA82A5B265B249024B727F128EE2BBE2BE52A142B0B2CB12B712A3B2B6D290E2839285F2A182C332D7D2C972DFC35C32F7E298228B0240925E527A228FC27FB261B25852487251124BC244829702B702B3F2A3629A42571259623AC249E272B297B2A142B56276826CD260F2627272A2778259C26A72476258125EE26DB27EC299629A42722279927D32627292A2C522EEB2DEC2A1F2C6F2DC12B2F290F28D8266129052C142C642D382DF22C91345231F428A0267D25E325F327C9282B276C26F324592314240A24422478264C28AF290E2BDB2A2B280B267324E923A3258A26882872276628A0269F25E9253325A12579256B271E281328B527EA266328C029E12866275E28AD2509260C283E29372D6B2DD92C192C662C8D2BF5281D290C287829052D112E6F2D192E7A2B6B34362F362A54286E256F25852772263527372616254B25F22348266F25D626652684285A2A0E2C312A72297926FE253828F424BC276E28F9293428CE261D26D9233E24B9262627172789288E29132975266F2898260C270826342608246725D52A5A2C0E2D0B2C962BA32C712BA729012AB0296529D12AE428EA2A142C762B9534E82F582CD02761279A25DC26D427EA25EC26782332248326BE274C26D2254227C6250428B229E42B0B2AC4283427142845265D26E72619294A2A1E29482504247D24E6263726E225E526CF283D29E42635265B277F264726DE269323B5245E263F2B0F2AB92AD429512A6828CC29E628EA2AFC2755275E292F2AD22BC42B6C331630A12D052B3829A2275427D2268C26DA26462649277228C529EA25E8256026742727288826202ABC299A29DC29232709262C25E326B726052B1E29D029B826A126842690263725DE274828BE28AD273726CE267F283B27C0275823E524922573291A2BB22C6D2B1E2C0C291B2B012B3F299D265F265627782A7D2CC52C103680312F2D252BBA2A492A772AA627DD26AF273028442A262B542A262A6A2934295229C128A4263C287A26D12612282529D42690262F2542256F27D02895271F28E327682560253C2674254A29EB29AF26B628DA294A2A492776274C253B261D2583279729632C112B682CA92B022B002A532A1B27C9265D253A289028DD2AF134EC2E482A482A3B2A9C29A4292E2AF3273129612A202B0D2CDE2B15297F2975286A28AA274227C9258F2421268D27B5273A27E12792252F246325B927AC2787265227A726CD27C62674270F293D2952272727EC286629BE2757262E25C025E62489252E29B92A712ACD2A402A7529E52AD2283D27DD2635269828C7295B2C2436E82CA027D0270428E62747293027E327E22A492B4D2CA02A282AF7278A265A271827EF26C028D3273124B923D4241D26AD26DB284B2686262F25392310262525ED24B92668287B269B2832297F27DD27FD27C4297D29E8296B291627F6244624F025062797287B282B2A492A822A542BD328F72635285E278D29B1295E2BF833352D6A27E424D8266227732692260828BA2AC2294829AF29DE267626AE250A26DF26E6265F27F6270026B5246925B525E3241B28DF27E525F8244625842550259725862569253F271B2820280228AF27882842280D289C27ED277726942441262A26B7255C26F927D629F02BF22BC72D9229DE2885283729A529632A942CF734FD2B8427B3262624BB24F024772421258C276D2832278327A024372511254427CB258E265C28292774277A259E25E0235C24192730268E27C326A024C1241524F924412389245A254D252E259325142501268425FD2426286E272625C52480258F27DF259D265D28B4296F2A292B052A1029EA28AE27642AF12BE02BED2BAF36282E9428DD247D23A323A6230E246E24DC2530268924C2242124E22479267A231C252526A826A328F9296A28672548232F24A825D826A8254C272425512634278226DD24D224A5220D2404248E2354230625C725C225D92626262225D8245826D7261D2749267A26462990281D29412A272712266E280029D42AA42E982D2238E52C9427A924A0230223B623762283256E222724CE2462252225DA26AE26E4246F245A2678256F289627FC26A7258B24312364250F267D259427772668264B26D626C52501258E23A924A3256425FC24B1243726F825E725102593256726E726A027D2263426B024C9265524A525B12445249B25F5268A288F2B402C4B2DDD351E2DEC25C2247B250323232308230B24FF243A248527EC27F1263E2891276626F926272585277029A22972285C276F26802389252726B7261827B42505261124EA258C27BC287026F726C2278328D2266C2772280E258925662847283C2AAF2AF1281D28822744263526622561239D249D2430239825DA26E2275129542BDC33672DAB282925102539255222B123D8232025D2267C261A280F2A4C29BE2692270D278227CE27712965298F284C281F27E424C8246B27BA29D328E8273625F22231262127D6268F25B428D4261B282E261828D7275A2544256427B226492B5529212BF22A7B2A69282F27E6244924892515247A228B241726B4286229462C3C36562EC1271925B8249425B0229B23DF22762414251E26CC256C27D526CF26C825602509268225C92730282828202817286326AD24A72526257928BC2607266723FC220E23B1249524CA222826B3243224F7255B26B623B424DD24B4243A2557272227F626B4286227BA2826274225BD23B4232623A224C925F6266B28182AFD35A52C342743267D2312236D2225239522A324EB23BD239B24F7241828F42898258826C325A226F7279327CE268027342626254E25CA23552411298F289B25F822CF22C123CD214B216220F1229621B823892558267223AC23C924AB23A0243E235B2634275C2731295E290C297C274F271E247523CA237B22C126E627552A3033C02BB226B424CE234923A1230C24B223BB23DC2270238424FF23B224F926D9277726BC24F2243F2642267925562521256025D1239622B42416256327CE24D1236A221722CB22E320182091212122A3220625CC24C72434248C23B4236B2280253B25D523DC25192816299E2695267C26C72440230A2405230C25A526CA276330F52B4B271923D1221222BC21C623A72238236621EF2231212622CC2299244125D525FA23C824D424E4250D235E24D826902556242B239322C324FE249726E32527231022D622DA1FCC205B21AE216A23DE245A26412733249325722370223022FB242924B22217233A25C7257F24852594237D248525192451240E26C32713304C2C13264124BF229B2346239322BE222023C821B2224C217A228321AF22DD22E422ED233F23F9238F229422B8239D24C323782256219D2275232A247525B9252D25DD23ED21A820A7214422C3225823B3239825BC243A26782579233D2118229322EF21A722D622E323C921F7220A243526D723A124A22386231B23BA26FE30F02BE72414235B23332351228122F32390211A22F621282163216E207121682352238B22C0243525532418233A253B24652376233D23B1229022B522462335260626EE25CB2154210E20AE22D72191224523A9240124E324F925FF22BB226322EC2146221F22FB21352207235F244B223124E6259C257A259325D92603286C30C52B3425AC217722F62246226F232A23CF2297234E23E7204221F6209822F722F323C9243A24E023DF240023AC259A22A823B4237D206122E9201422AA22CE25E52592247523622218203C225E2273222125CE24D8212325A424E4234423E7231622AC1FC42298211E20952106216322BA239E2582269A2363265227682A6C33D02BBA25A022CA21DB222E236722D1241B23FF2158212A21F41F0C20132297231423312450266E23232592240C2552230D2419249C217321CC20E9216821AA23D2234222842378218A20602248225521D123D222DD221B223E25912358253222BD2131215D217D209422CF1FCE215E23DA241224DA249C25E6268726192A43356A2CCB25022224239B227223DA22AF24362486224822BC224221CD1F7622B92246246424D824F2226B2531242025AB239922D6238B21B41F39216D237621D521D6217E213E23FF2165202F22B521FB20B8231A24C62132223A22D22141220D22C32282212221FE1FC12191214A22FB23BF23AD24C42374232C269E2ADB2C3637812CB32543243221FC23CE243D23EC239C249C23C1249D22D721D720AB224C215B22AB24A223A222B62324238424D723232323248C22E82018225120FC205A2175204F2144219822D8226421C621A423BF23F922EC220420301F4221B821502374228222CE21EE207722C52145220124F622B0252C24CB22952441291D2CCC34 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 B027FC21BF21B01F6920CF1FD41E0F1F9F1F191F561EA41DB81D211D161FAE1D881CA21E411E151C1D1EB81D911FDF1D991EC51DFC1ECD1E401EBC1DAB1F491E231DBC1D101DFC1ABD1B751D111D5B1DEC1C7B1E461DE51CEA1D101D401C6B1DD61E541E311EDB1B9A1DFB1C381CB51EFF1C741FDC1E5F1E8B1D5620F221EC2C072B7023202003229021DA1F2A20B220FC20171F1120341F3F1EC11EA61E591E8A1DC21D4B1EC01D2A1E651FA11FB820481ECB1F621E241FB91E631FD31FDF1D171E021F551ED01E2C1D641F4C1D511DA91FFA1E641D5B1D2A1E0020051F2E1E2C1E8C1E271FE51D201F6F1F8B1EB81E531EF41FBF203820E820312187232F2D1B2B6B24DF22B021A8200A207C208721D71F6622D42153210F201F1FA91FA71F9B1F0720641F2D1E671E3E20911F731F7920B7209F1FB51FFE1F821CD31E4120C21FD620721FB51F561E6A1F0D1EF41D9F1E401FFE1DDD1E541FA31CFE1E1D1F6A1F7B1F021FB51D461F9D1FA71F761E961EED1EC121EE1FD120FA20B624892E9F2B4527B123FD207D212F211722E92025200220D61FD01F45206B1FDA20811EC41FBE1F601F3621E41E831F711E2620D31FEE20BA1F4220DA1E2A1ED21CA91E3920EA1FCD206A1E291E041F0A1E661D891EAE1F4A1FEA1F2F1F211FF31F5C200F21811FB41F2B1FC01E011EAD1D9C1E6D1FAE1F7620CD214420E321A723C92D6D2C0126C5210F21ED20B72122210D2145217520742079207D1F201FA120DB1FF81E0220A01F991FA31F581F9921FE1DB41EC921241F411C571FDB1E631E7C1E0520AC20C91FD61D111FD81ECF1DB21F9B1E8020CC1EDE1E9D1F2020BC1EDE1E01202520E420BC1EB61F071F9D1F6E1FAB1F721F4320161FC32085221E23A82C162A622526221423FC1FE5217620A520B521B8204721A821591FA41FF11F4C205520C51F5D1FD4206F1FF81E5B2096208F1EEF1F2F1F081FAB1EE61EB61EA01FA31F0F204E1F6C1DE21FE11DCE1E6A1E291F6A1FD21FCA1FEC1E531F1B1F471F8A20BA20041F841FB51F2D20D71FFD1FCE1EE11FC321D22074202D23DF233E2D732A18231822BB211921F8202D22052182209921CD2003203020B31F0D210721682118202D20BA1F6A214E21C51F21200B1E801E7D1FB81FD11F8B1FE4202E20851F0F20711FEE1E6C1E741E741E251E991F2621F91E261F9A1FD91FB21E231F9820BC1EF81F0F1FA91F441F1B1F9F1FE820181F9D207E1F422114223A229E2DEB2AF1246E22F2225521461F302015211021B721B31F72203F21632242201C205C21B8202021C9212221931F6D2011227A1F681FB01F211F1520E320D41F061FB11F26201620CC1EF31E6D20C3200B1E64210120A71E2E1E0C1FDB1DAE1F661F9C1F871FA81FB21F7020CD1F5D1F1F201320EA1FAF1F5C1F10222D223B24822E6029AD2407238F2194212A203F1F51212A223B21982001200C20C51FB820D51E461FBB201621F120C420581FF81D8620E11E5A205C1E9F1D101EEB1F571FFA1E9B1F6620CC1F5F1F8F1EE11DA41D2F1EDB1FDC1E961FE81D1F21D21F2B1F691FDE1FD81EC52091206521961F891EC71FBD20811FF41FC31F0B20482288228C2E832C8B2359211521592163204921FE209D22CF2010225F21C11FC2200D21A220E0203F20242170206020BA20DF1E6220D71E5821DE20E91E0821A91E771E981FB11FD920A31F2020661E9F1F961F781EC61F9620CC1F8F1F291FE31FFC1EA81F06233620201F3C213421042134215020D120BA21EE203F216720A222D4239830D22AEC263223B321F921E4205D215321AE219C213D23CE214221D21FC6202C214421A220DF203621C51E8B206B1F1F215A1E3D1EA11EA31E8A1F211F641EE71D6920C01FBB1F2220441E311EAF1F4E1E3C1F7C1EF51E181F87203F20EA1F0A21AD20881F6A1FC32071218C1F6A1E8420A020EC1F5720221F4121BF22462351302E2BB924B9215623D920911FD92028200522F7212921C320961FB71F0A201C2141208A2053209422E41F7721CD1ED01EEF1E0B1F951F711F021EA61DDE1E441E101E241F0D1E751E551E151E271F3B1FF61F911EA01FD31F2A206A1FD61E2D20552081209621831FA2210721CF1F4B21B82010208C1FF01FDE1FA620B824FF2E4E2C97266722C0210421D22008212720B821D2201A20F8215C20AE212B213C223C2178206D1F5F21C51F1620A71EAC210B204720A61FE31E651F16201B1F901F4E1EDE1F3120871E651D2A1F3A21871F9C1E4C201F1F821F2F21F020481F2B21911FDE1F5E1EDC1E18201A20BC1FC220E61FA91F1D2252202D211322CB24AC2CE82A1C253E225C22DB222820E520A3213B2293216C204320A91FEE1F6421871F1121DF2019204520FC1F711F6E1F4C20B3208220DE1EA11EB9207B1EFE1DD31C401F4F1F2B1F4B1EDC1ED11E8D20EE1E59217821901F4A1FEB1EF51F2D20EF201921111EDC1E701E8220101EA01D551F2B204D216C210821B12126222924692F922ADC247323B3210F236921B3228420F6223120CF213722E21F2A200A202321B11F1E22C52219202C1FB91E9C1FCE20D820701F4F1ECC1F7C1F421E9F1EB61E2B20C01FDE1F721FFB1EC61E2B1F0F20E31FF920CB203A1F4C1F2720C01ECE1E6B1F11204020791F1021F61F5F1F2120402156200922921FA9203F229123572D1F2C44265322C821142203231D227F22DD2015226E2230219D1FAC21E3219722BE2043221C21662010227022F41F4D20FA1E06205F20A81F6C1F7A1F2B1FA81EA91FF31E771FEA1E031E7E21C91FFD1FE021AC1EEF1E051FA81F411F6C1FF81FE720AA1EA920E61F90215D22991F9221C520AB211C229A22AA21AA2274241D2E202ADD25FC239B2393218E219321A221EC202421FC2209224A215C2106218F216221B520F9207E20D221E11F8B20402169200A212F205E1EEE1F7920F01FCA1FBC1FFC203E21B01F6B1E9D1DAF1EED1FF31FC81F581F262014226020781F6F2039205E1FA0204F1F282017204620781EA72151210122A422E222E522A925362FE82B9E25FD2334214F222423DF2127222F227222FE212522BA21EC215120C220F52067216A220E217F2032219320C220561F482102216A2066206B1FE4204E20E421DF20CC1FFE1EC6206820A61FF71E32201122B520FB1E3E2218205D1F3A1FA721201F7420B61E1521E71FD122402249236C22BD21692221235523F5241731242A52276C22E922E9229B224C23DA21B9211221FD226F200421F8204922AE206B21642336212F231C220D20692131225D1FE02028205220F21F5E1F0E2199201A21F720DC20771EDC206020C320521EBE20F01F2F20BA1F0D1F9C1EDA1E5A1FDB1F36210122221F26216320F91FEC1F7B215A211B214021FC2360239625EA2FAD2C1B2519223222D72138229621E0215B2065207D213122D621BE1FA622A12225228F1FF82166222C20F31FD51F0A2005215420371EA01D6022B91F5D21781FC620E02179205E20C21FE91FD51EBC1F502065206E1F281F0421561FC21FCB2000229D20A42055216622971FEB1F8F22D821CA214B22D121DF2284241225352FD92BE425EC2314235E223D22CE203221A6212B224623D3214F205A20A920C42191205E2384214620562020223421AA204C21BB1F3820BD1FF31F082135217C223022862222214F21A41F281FC2211F1F7E2176216021FE205A1F2A21E51F70200021741FDD1F7A20BD22B92125227F25A922CB22B924AD21FC235A24D3243A2F8C2B20259D243D22AD21F321F021FB21D72298227D206222E821BD220F2196216C22542005232021BF216721EE215E21F41F8E209D1E2B1F152187209422A921C82226234122CC219E2142219B2040218422242289203C21FA202D21D61F42208F20332129202821DA22D521D72213220122E123AD228724D1242B2485256C2F672BEF24702269232723FD228422A221D8221B22CA229722F2216F20F6227321A021E7206B21731FB91F4C209D207120EE1F0220181FBF1F8620861F4E21FE21A520FB21E221C221FA202C24DF2270218023CA224E221921D2218A2130210122C6219E2120239721692395246323EE22C422F521D8226B234023AF2389243D30852BC8243823AD228B22A720A9218D2233212F2030214322981F422137233B2157213622F1209B21D320FF20062278229421FE1FD81E9A200921DB1F3D2144218A21A7221321A51FE4227123C223A223F7239E220D24BA2214234D22CF2171238F2000217B214521D3229F21D122EC23F42327220623042329241E2338260D31092C96247121F2216F22D42105216C213F23CE21A92355221A210B214120E020B12041219A21F1230D218D204F221C222A21E020B22053208D1F0620B11F0521012139222F2240231D23CC228824C7227E2297226A237923A4249A22BF2278228D23B5209E206A216821C521F7214825D82492233424472403264C26FC25F9307D2B0E257B228023F1216622C0228222E22294218A22892270212322D7222E222F23D420772213228C22A8239A2182221A2234222222782020222C211A228721B222C2220524F023F8227C2433243422072456235222F3218125AE232623912423226E21CD2137203C2398227A244C26082773257325E12402263C259028C032772C04268C22A721EC220423F42227233A23AA221D2408247022752332232523BE230224B321A223C6224822EA21E7232122B721F0229F205E21A52180220921EB22AF23F6252B246B26C924F6249C24A22225247823FA236025D326F3247625A1225321302252228523D4223025092702285F281829EE28DA26DD26CE27A832572C4C2705226723CB222723BD23D524682499237C25F4237427ED243F25152502248124D3235324F92221232123B2231123C9216120DD20C8206121BF21C8224224CC25AB262F251D2792250126D523F123D3232824DC25622645279924912380242322BE217C23BC233F241126C127072ACA2A192C292BEF29F3272729B4330F2DD725962438242123202293233E248325E524C223BF25A025B9277526132721261824CB2476231A232623A0225222C721B8227220CB1F1821052233218F239B25BD274229F727FA271027D623CC234A252E25AB26F426C728A92553253225D0239A233D22E12358247B25BF264E2A842B5D2D7A2C212A9E28BE283928EA31912D992673217F21BA217424842301246725D623DC266225192677254A268E26F9253124EE237C25F021EE227021DA2313216E21FA212B21B52179214122DB23A8253E28312ABB2AF3281727B924A52490267E275C290A27AB2745261D25C52409259E250B26A325BB2540267826EA270B29632AC62BCE282A27A9270A28A233652C4825B6221A22ED230A2377233225E5242D2785248B264225BB2589245A22B022C022CD232823A2211821762325230B2253229423AC21DA22512392233724F9256829642BA12A80287B244224902457268B2AD7271927C2264226102443240C25AC28A228EA25312857285C29052A352901285E27FB25F42767287429DC33002C9B27182339249B241C2213236723AC263B28122A6729BA26342636270A26FE2230232523D12305210422CA2171217E228624702424244025612320254925EB29192BFC2BBB285E26D625EC24D8234227732A4F2976285427CD258D25C524972788298929EE29E828FD262D2771273627CE274C258E258A257B29F12BD734812C1B25CB226A224223AA23BE254C259725C027962802280D285726FA2411248E23E12145241F23DF221F233F227421CF229C25992614276A26FC258124D6263C29A32B902AE22724244425782429264629582C2E2B7B2986281126FB25D724AE28ED29C32A8E292B2A3228E9254C25CB25F02488252E246C260C29032BD434902CBE263823D523EA22CB248423D82482268326E0255E26BE259225D024B92351224B247A23C923D724E62284240923CC230326C127E625F62679279425D826062A652AD8277924CE24D32294249526FE2A292DE429092AEF28042647256526A028DF2A972B722A63283324E822A722AC249624AD22102439276829CF2AE435922CD5258B22B3230E250023A424CE2350268825AE255E2511263D2497249323082408250226C92692287726D024B425F3241B263E2976271826F225C3259A26EB2610289B249922D6239F244926F726B72AE02C7C2B242B08289426BE27BC267C2A712BE629CB27BC255D2557238223B52271238A24DA241B27772A062CA635882A6E24E32369222024E623E4238723AC249125C92638277A252B2482237E2323269D26E726BD2943285B274427602590237D259027E32482247B244223A924F92329247B255921F620042691283528EE29EC2DD32C78294D28292767262A29622A692B262B6F2A9428BC242D21B82123220A232924A324F226832AEA2BB1361F2C4F252124322454247C23B42309260C27DE28302A60280F2653230F2418250E27062ACD2A252CD62A9F296C27A0264F24E6230F27A6246223272491225824F123502548247E219C2115266728BF29162DD82CEB2B1E29B327B5235B253627C52BC229752B1C2B69285A25D423B1234123E723E625BE26CD297A2BD12B28355E2C9B2627245424B62581268A28272AB72BAE2BB72B44289F24A526E3247F253429DE2AC72B4E2B032B6427BD26DA25B92398220424A5238F2343233924E326F226AA27F8263C243C24DB25B529CC2AE62CA82B912CE828B52519253C2545260C29D52AA72AA729842AE626682575240B24D322A026BD27D8293E2CCB2C7A35022D7C2668246125472605271B2883291A2EB12A9B2ABF297827C5257226C0262B2B8C2B6A2A5F2A5C2876275227C4233224C4228F21272387222524ED26E3276C29072BF52A93262825EC268028622A2E2C622A492AEE27A925CB231225FB27E928CA289B28A7282C28CE26B9244724EB22DC22DB250125AD29442B832B7F32EC2D96272126362644268827FF28732A272C2C2CA62C432B0528F82428250D272F296D2BC429C228E0286926C425E1256723D022DE22F123022516262629AF29D62BDE2B032BBE283227C0279F28E429232CB62BAB29242652268324A225D426A827722723289D27B5270625E42339247C242524CC264827E8283029EA292E332A2EC22ABC286C29442AE42A782B592C7B2E902D602BE42974283427B0263227552AA22A11272529B927A327C22670247F23CC23DD22E424B3287C277C29772BAC2B0E2B732ADC278225B32693260529042BC52ABF2871254E24A7248A26C9270926F226FB2617279C276F263625D724E32331242625482679277427A02A4E33B42FE2290828A829B328B429922BF22C432D922C722C3E2B7527662479251526A3274D28D028A7283B2906293F288D26C92426236124AA25E7270729CE28BA290529372AF92A62259F23BA246526B4261E2714272127EC25BD259A24BD24E12461277327B926AE27F32878272A273D262025A32460270927092AA22BB22B5A326B302D2B672B0C2AC12C9028312B452D652C5B2C722BD529C626D523F82564261D285828BE290D2AD62A322A38288B2628251A25582602298529302972287D27F6272B286E299A260624E722E323CA241E2632252C2666235B243824EC24AE25CC277329092A762A872B122B692AC0297627E2262328D92AC92B192ABB2C7834A12E222A9829272A7A2A0D2B99294E2BDF2B222CD32A13287224CA241024E1253D26E528B629F729092809288C272926E1239328E1282227652811265525AA27EC27DA28F027B02306229F218723E32202246B24362480234D24FB233B25B4286028AE28DA29B82A2C2BBB2A8C294D29FC277C26CA273F27E1270F2A0D2D39352D2FF42A1F2A0A2A002BD92A0B280528992B1B2B4429B8261C2351238A269A271D275E2974297E2A332C6D2ACC287326E624BE253E274628BC269825C2259125BA26B4289027EA2237228C22102212249F2467272F26B1267C2318257C26C828E22AA42B632CB32B392C4328EA26EE268F25C025D826F52651297F2A542B6B34F12FB92B5C2A502A322A91289E278D282E29602ADD2777251F258C26272851287728B2297E2B5A2DC92A052A98289C25B1268126062716270B269E223B250126B5283429532866243C220F21B5234A24B7255B284A2758276027DE24D228AA2A892B6C2B902BE929CE2BF7280B26E32529250F25FB26B6258B27562A8D2A6F338431872E992CA22AE12AA029952812277E27B9255E2579231F24D626A629E42ADF2AD82C352A1A2C172B1B28E525E825FA24E2251E2643277A264125A8267228AD29F528BD274C25B822D3229525CB241B275828422A192AD4261628EB28AA297F29D12BCF29D229252AFF261D24F1254C248523C425A724AC256426A8274332B0324D2EDC2D572DB32A262A23275F267F26B725C6238824202562281A2A9F2B012C762BFA2BC72C7C2ADE2706272C25DA2327256F26E926D426B8275B27D227FC28C72741271024E92238245B24C825ED279C2A622A97291129FB263F278828E428DA2A322A4E28BB261F25252553245E238E24B0258925B8255726AC27FB313B33512F8E2DE32C922B342A4C27D123F9232F247225B7249E252F28AD2AAD299C2CB329C22BD32A192860273E257E264526B4258D252027B928BA26802764278127F225B7262523FA22A7223124CF24D4263D29EC27F12632271E262225BF261D271325B8251F24C824322455237825EB256F250025682597274828272A59324732BE2E1D2DCC2C642C5629DA2460247925662414243E2614273A293E2B972C612AE62AFF2A942B70293126D2240A24972651298B2A412BBF29E6280E2956285027DA25E1240524DC226E23DA236F25C7258E270C27AA24FC2537274526DC25DE233F26DE2380241E24D72472250027AB28222AEF29E127E3280229422AEE334D324B2D112CBC29E729CA280F28AC25D924A32370255E27E629062AAC2ACC288929852CA929372A3B26A6253B25F42669256527852AA22AD029FB2A412AD127DC24C824D92349233E237D22D3237925962729262127F027E828852A3E29F9285427E9265A24EE231A2607274028482AF42A582A932A60294F2BF9277E29A2317A31232D342B5429BC270B27ED252D24552527250F2775279328E32964297627C925ED25C5252528B4248B24FD2652286C2619293D2940292F2A3127FC26A02541251826AB233F236223F3243C258B2539278F287628712895297C2AEF294928D8269B256025A824B129842A932AAA2A722A282A9F2842261327E32771270A319C31CB2CCF2D4B2AE729C32791250E235325F426D127CD29A22CC72ABC2AA928C3266827122516270B278A266428D9279528CB2553273A26CD26722451255824D924BC26AC269026C3275A279928BD289E281829CF275A29BF2C872B252AD128B22573257E251A2821295B2AE42B9D2AF927A9261229F22719298C276F2744335B341A2DD92C7D2A532931268C246A2548248B243F28A229722AA22AF12AE42B8D28CB287E28A4273925AD275F29E829B2272626CE242925662417251026BA256D284729C929C529D628502994297E299A2ADE2996287A2A4C2BED2BF9284927C8265B245B253B297B2C5F2AEF2A2B2BD127BF25C3288028E8292729A72869323E32AE2D992AA52A91290C27B02495242F23342591289C2BEE28612A67293A29A528732746276426842806276629FC2889257125FF271E25F326B8270E274827AE29512B4B2BE62B092A9228EA28D028EE29AF2A13295229422ACB2B4D299827CB2692254D27362A4E2CDE2AA528EF27C32679273A2BB32A222A812955288730D6319B2BB32AE8289A25D2265C242F2523264C25C9275F29822A5D272127E725CF2880270826DC270D27B328BA276B288A260227A426A72845286929272A5A29792BC12E372C1C2DF52AC92906284428B829602AC0275D2769289A29E72853267B2582260D2AF429AF2DEC2B2929E529F9284329B62D732B5529D629832BE933962ECC28D826CD26BD24E52480240626BE23FD22602682241F267E251F27AB26B927122680240E2576270D25062865272129182A64298F27702662260B284129102BD52EC32D512DCD2B3929B02AAE298929822A1D283526052719270F262925D724A925A6281F2A0B2B082BAA2B71297D26A025992AA0295F2A4229EE2A07342A2E5226CB25DD250427CC249F265F24B8243E250825E3230F25E2258927482626263525CE2324256325AE2604278E282629152AF02A4E28EB24AA2321251527002B932DB22D742C092B4E288D281027752829282627B9239B2502247E247E256A26AF28302BFE29BA2B602A822ADB2883266E28082AF129282CBF2AC22BEB33392DB4277E27DD27ED2787287827BD268F26CB253626EA254928802747290A28092612255E25872649271D28F5292E2A9429CD29FD2A5A270926E823A225D326C628E52B2F2E4D2B792AA2292327F2248C25BC24F523F423482399235B256826BA28FB2A342D9E2BCA2CA42B752C892B5527DE286127242799297C2A4F2CBB36BF2D4129352BC82BF92B9B2B9329712803277625F5256025E8270A2AA42BCB286B271C275A26B927DC271F29FB28472AAA2C3F2A5C27F7231E24DC2455247127A428B72B082B042A05288B2672256524AE24A722D12445237723D823772499289B2AD12AF62CDB2AF62CAD2B4D298A2A732800263B250A2663272D2A762C9635B12FA62B0D2DE52D1B2DEE2C512A462A29287F26342752277B29EB29F92A1A2DEA2B1D2BB02AFF29022AF92B622B782CDF2A1B296C2774266E2452270B257A25FA27B82A592A5D28DC25E6243E24AB23F224A6257E24A825C82324245A279429202C652B402B302BE52C6E2BA52A4229C127F325F925F724B028822BAF2D6636EF2EED2C512CDA2CB92BFA2A102BB629B128E725EA267E26DE29D02B292D992BC22C402C2A2C902B5D291C2B332BBA2A6C293C283826B2262A27F727AF26E125AA269027D8286A284F253424FE25CE24AB26B72696278B27C52793250F260B28802B702C132C30298029342888281629612740265E27BD283A2B302BD02D88357F2E262CB82D792A472B582B082AF326CC25B325752620275028902B022CD22D122C552C222B7D2CCA28062AAA28E4274426A42717262B273529EB2999274E25FF23E7247F2857254625E7247226DD25ED289D29D9287A27F7293A27B826FD28F72ADB2A43286027D126FF26952885291E298E25F9292A28D829FA2DA92D4335D72FF8284929D128D029162CC8289C267E26162544271A28A128052A732C232ADE2CCA2CCA2B782A362CD42A44270C27B5269B25652855289428B8275F279225AC259326D326BD26492586250828F8277A2ADE2C6B2B662A102B442B5C297C2A9429252AF326792551276A261B28C32CB62A5E28DC286B28F528BF2C5C2BA336252E1A2982252F26D827AE26252790250E26F426F226CB276A272428F828A42A0F2AE92A052B4B2C392B612B4529A8250D25DD27A6274F28A228D9266525AC25A6264F2747270E264E2679274727092A912D3B2CB42CA62A732C702A632A0C2A462ABC26E8258F27A828D0270B28B22AAC2AE32A1D28EE27FF27ED2A372D7536E02CDB286026B62736268A2719285526EC25F424E02A6529F52B67292629CB277729A8297A2B082B8429A128B124AE26C2269B27A228A0262D27592631249B25DD27552954281F276E29B82893276928562AAB2BFC2AC029032A3D2A752AA9280729D9271827AE263D2889293729932A0528E326352781284629052A952CAA35552C83290928AC27C42ABD2AB0279C274F25A527E529812ABC2CEB2A0D2BCB29532A9B2B352BD12BA9289E25412682261026E12646265626C225F624792572273929342A492B9B2934284129A2294B28EB27A22A4E270927352AEA2A032A062936262C268527C426332B942AC72AF0290F281827F0276928AA28FC2AD22BD234E42E972B942B022C3A2C262C3E290E2944277B28642B062E422B842B652A3E2A692B642B302A8F2B1729622568271A268E272D291729B5244F24EA258626D1275C2BAE2BBA29DC2819297C2A1E2B562BEB2A622A102A9729192959283F29F926EE267C2807289828732953294C2BD728AF27BE287C2B3D2AF52896284D29CE309F302D2CA42B392A852BD22C7A2A992863286C298F2B002BD32B7E2B7A2ABC2A042A382BD229422ACF2830277227FD294D2982292728802544254825CE26AF271A2CDF2B05298928B6285C28522A7729EA2A5A2C322AC32B312AF7277829FA299929102A4C289A29DA2801293827F426F427B729492ADE2A982AB3272826A92FC12F502BC22928290D2B092C982983264629A72A0A2DEC2C592BBC2ACA2B9F287529462C622939279E26D6266F296C2B992BD72A432A142611259525FD26012AA92C9F2C7A2B40272528182A772A3C28CB29642AE0291C284829CD28B528822BF82ADD291A2A7928B9272D259525402805284E2A172A5029F2278F260427162F082FE329EE29C62AA22A7F2A81281928442A992CA12B872D64299028352A1F2A052C422ACB28CE2680266B28D129702B1E2B832AC6296A267A267425B626B627D32A442A462A6127B427122801284226092851277B27C92525282D271C29F32A052A0B28A3262825EA25BC240327C9279F285A29EF275727FF25DC25A42612311931BC293829812ACA2BE22A7B2730287B2BE82CF52BD82CBE299629222A1B2C072B852A2A29B92617283B282F2A952BAE2ACF29A6281C27BC269E275226C327BE2A8429932AAC265226E926E4252D2514258A2658247E258F2541299B28232815288624AE255A250024D52464267B298C2B432A0E29D627762876262628EF32982E33289B26E727BA293529BD2827297F2AC02BF82C8D2BC32ADC288829D22B3729582740282029F428112813279328E6276828B126282697278F27A628CB2A542A3B2ACA291827C426C8244E248D24692664253F27BA26FF27D3261728C526EA25B3243624C6241B259B26FC28562C552B232B2B2B0D2A632B362A932AD934A52E7D29E2268A29DC29522874290F2AAE2B382C702B7D2B8D2A162C8F2BF72AD8296F296829A32AA629382D8A2A122BEE284B291626B525B9271E293D2834282928EF27112A9928C22568262F269E26AC27F2281F2A4B2A3B2AE3287327DB27D727B126322727279B288928D02A8E2C572D202D202D3B2B9D2C372C3D2C1436D1306E2A542A182CFB2A8B28F5271628562B242CD22C802B132CCA2D8C2B672CA02AD2282E29072C302BEA2A5A2D0A2EC32A27289124B7245E2633255F27602715282D29322C702ADF28D82714270828BA292C2BB12A67296D2B8629E526DA274428952A052A6328192BD22ADA2DC02CF52B6E2ED62E0C2DF62C3C2C302C61340F30EE296A293329942AAB27C6240A27862A042CA22C7A2B182CA92C1A2D332B3829E328D5291A2D072B7A2BD02B942C43282827FA24D923EF261B26072706275E272829BF2A8C2B9229CC2837296A290D2AC32CE9297029EA29FE28B92849280B2A6C2A782B82293D2C702C0B2C202D072BF32CA42E0C2C692B1A2B662BF23206300B2BA027CD266F2774261D260B29542B9D2C8B2C472C6F2B912BCD291E2A79272E283729622AD12B172D952C402A262956264025CB254E271D2997272C28EA29F328512BF02AFC29B729A42A772A7E2C992CFA29AB2A5B2985271D2A592CBB2C522B232BF12C232D622C2F2BE12C7D2B1F2C822CD62DF22AF129972A6732A9307C292D27C4252D2633278D27B0275F2BB32C032EE62CC22B2A2C972ACD291A2955281D2AEC2AE32B162C422B402AE12713273D27E1264629D4293C2C3F2BE82A1A2AF429BA29CB29092B812AE5282B2B0A2B0E2A522943298A2AD82AFD2B762A952BD32D7F2B7B2D762CC42859295F287E2A292C382A452B332C202B6833B72E1029E825BA25C5265328F329F629AF29922CAE2B9A2CE42B122BEB2803285A280228C928E329762B072D492B8629F6270C287627D9268729332A572AF427752718296C2A442AA6291C2B70270929672A492AC426FA26292AD72BBA2B452BD32ABC2BFE292F2CB82B4C2B762810277626CC28D2292A2BF62C9E2C1A2C1734A82F4D28F92605260828D52AB32A062DC82CB62B672C252C1E2C092AD127842A4328B429232B1B2B4F2BCF29322A0D28D824BE267927A7295D2BDE296B2A1829B9285F29512A252B792A3C28E5265D27162887289226D728792B452E3F2EF92B6C2A552AF829612BF92C9A2A1D2AF3297928D4273C287B29822BE22CC62D8036F52E8228C124CA253827242888296D2B1A2B962C5F2C382B3E2872278526A72B122B332A61298F2941297F28C726C1271424ED279D29C02ACB2B5A2B752892281F29B42ACD2BBF2C442BD129AF281F26CD25E2263627EB291B2D582CDD2C2F2CB52A322B9729A52AA52BA7292B2B6D2957287D29712AB528D82AC92BC62EF8350830C929C525F7240E26BA272C280A2A342CD02C1F2C7D2BA02934270729082A4B292A29AC29B52A452B082A0129BB26EB27D529FB2A352C772D3D2B7B293F2BAC2A04291329322A1F2BC029A228FC243326E325EC270E297A2CB62CFB2A862C572CB12BC02ACB2A162ADF29E929122BC32A5F2A402C602CB52D1E2E402FC8370D30692A13280F2548259A27B2278329002B242C962BFE296C2870274A2A0D2BF42A1D2AE02A552B0B2C07298026712614262B294E2B7A2AE82C612B7B2CDE2998295528B3291B2A6F2A81292129EA258425D426C8274527EC2D9A2B782B222B862BA72DEC2B2E294528E1264A286F293F2AF02B362CD02C7F2C692D952E1436E230912B7527FB25512627271F29E629E12BA12CBC2AD72855273B28392AED2B81291A2AEF29842CA42C5228A02642263628C7298E2B4A29AD2A4E2B752C282BBC28EA27D828ED29492AD228B429C5260526F6273D276A2ACC2B362C5C2B472B562B502C4F2A2B287E26F026EC28062BA32B322CA62AF629502C002DDB2DC235F032E12AE6290F282D255F256D261A2AE02A512CA12A812807279429112C3B2B822ACE285B2AF12B0E2B3B279B26D926F329712A952A972702291C287B28AD281028CF276026B428DB281A296B2859297C2B7229C02A362AC72CB02B1D2AFF2A9B29162A64271626C3267D261E2A322CDA2CC82B9929F427342B7E2B642D51372531792CF428172668241F24B5248427A2290E2A2F2A7D26BD29312B202BA22C992A9A29E7285C2A81274B25DC26D727E9293B2BB32AB12A2929F92743299829BE287A287D275926A9275227D7283729FF29F22A602B9A293F2D9C2A7D2CCD2B94291B292D26DB245227B7288F2AC72C0F2C512BDE2C3229BF29FC2A002D6B341B32CC2B5229E8267326A4264C2565296A2AA02B912B762AA22AE32BDC2B8E2D422C5A291A29DE2766265226EF26F728292A622C5A2B872CD32B6A2B432B122B892B5F2B0A2BEE27A3257629CC2C592A6A2B542D7B2C202BBF2A5F297429E9298E2BE029BE2808291B2A132B372C722E902C6C2BC52B072B802B842D752DF234CF2E962A0E27F92644271928762642271E28792A342DCC2BD72BEB292E2CB42B332C772976282B262425F0241828062A782AB82BF928C829502A5D2A1D2B942ABB29632B1F2BE52A672A3D2B6E2B302B582C382C9029A32923294C29552A762A7B2C6329542A892AE62A4C2CF12A242B6D2CAB2B402B4D2A562C542C052B3C357930B2292D283628E12A0B2A9E28342655282D29FF2A6D2C6E2C1E2CC32B7B2CDB29252AAE26FF2515250C2408292B2964293C2AF629822ABB2AA32B3E290B280B292D2BA12BA82A2D2A0C2CCF2DED29502C312BDC2A2B2BD32AED28832A212ADA2B112AF42AAB2A712DD02CEA2A872A002BB72AB32A3A2A5B2AA22A3A2BA5337130ED2A2629F629D22BBF2BEB2995284F2805299129462A692BA72CBD2BD82B012A9C27B4253025D7248924D5273629572A472C55290C2A232CFF2BAC29C7280F29CC291C2A3B287D2724286029F029492AC32A902B4B280029982A462AE12BD72A6B29742A4828C22ACD2C5B2B112C8D2A7C2BA62AFE27AA28E528C5288233CD30E62B4329322A6C2C752B3328EF27F228C9279D29342AA029452A902C812A5C27DA27E2269825BF2524269328492B822A5C2C732CD92B742EF02B3E2BD52A072A5F299F28F6232A257125CF2508258727882784274427172950281E2B632BC1283827E8276329512C0B29182A542C1A2D0A2C4E2B562A7C291628902ADB357831852A372AD52A1F2D6F2CC22A7E29EF2739290C28F0277F252D2733296C28CF27682814271928D2258B24E025AF292D2B3F2B5C2BA92C102CF72CFF2A5D28AF283E27462421227F2460249E246B2549253F285A26C0250F27EC27B52AFE291A280426A5252E28452B282BA82CBC2D272E922D8B2C562A00295728E729C534B22F362AD32B5B2B782CE82A582A382AEA286A29422A4928E324DF248125B3273D287929392AD62A6E28F5256D27042B212BF92B592AE929542A19281628AB273326E524BB25B2258E26DE25D525EC26B3243629E3274426E228A82830277C2573258F27B82AD029132C562C6E2DF92CB52CA62C902B3C2A9D2A1A2B4E2D5536D62FEB298829922C262C022C532BC529E529A729892890276B250325BD2631290F2A3B2A6A2CD82A78298C264E273F28AE29EE29AC290228D527B526F8264228C326B22736280E257B288D2799288B274B2628287E28E429072B992AFD29C8269A26EF292A2C7A2C642B2F2B222B2B2C0C2B042CCE2B2229FB287A29AB2A0733DE2F02295528EA29E32B3D2BAB2CFB284C2811294028BB268724B3246A282F2A7A2ACD2BCB2AEC2BF0284A2734282E285427432884272C2931286B26C127AD283E290329292993274B2971295D2BF9297428CC2767279028262B1C29F428352731287E29042CB92AEA2C232A7B29AA2B072B1D2A0B2A69299427DE28F32A0932EE2F0C2C602B6F2CCE2CC82AB42C7E28AE28E62739242725C42669262727462A342B522CB02BB62BEC2ADB28A827CD2899282129D029392A9F29DF2A2D2A532AC32A942B092B2128D929C42A462A8528B8297729F327C927BA280F280A298227CB28EC29F12A702D482C362A0C2AE4292F2AF52AAA2A0D2911295529452A5E34AF30402D272C472B182C0A2A9E29E5277F257925922560269A271128CB28BE294B2A612A4B2D032B022CC92A2F2BEE29A9282D2B9F2879294F2BF12CF12AD02BCF2B8B2DD52B1827D4276927EC2A85270B275828E1272227AF295C2A7D28B0278127E92ACB2D3A2B3B2DB22B4F2C092C2B2D50298F2AC32B822CDB2D8F2CC93550319E2DD62A722B0B2B03290D2774277026AF243D269A2818286B296A2B632A2B289929A02ABD2AA9290E2A002A7429BA2A222D6E2BF92AE02C612D982CE72B312AD32AAA2A28284927D129892B072962288C283E28502AF2299927C2279327372BC82A162C2D2B7F2AAF29582BE92B4129442B122B9C2A492C362DF62DC0340831622D362ABB2AE42A2E2B72285A28DE260B25AB24A927D0299C2BEC2B862CF129B5291B29252AFF28E7280B2C0C2B1D2CEC2BE62B552CE52BFE2C382C7C2BEF28ED286929392AAA2A5D2B6D2C962C2A2AD728D7280C2A422AE4281F289D28D42B502CD82BF02C3F2B472A602AF72A712B8E2AE529FB29402B232CF12CE83305358D2CF8281429442BC82A752B182997263028F625B627D4287429922CE22BE72A1A2C80272227B62679278F28F829172AA72B8F2B7C29502BF72BAB2B7D2B8728F0254D26C328E729BD2BD62B082BA62A212AF8287428C52AD529712A662BB62BAA2A512B6E2A772C9C2ADF2A612C8D2A802AD728FC26522A922BCD2BA1350934BB2E92298629E7289D2B772B272B992908280B28B8276329BA2C4F2C0C2DFE2B312C83297527F2243A270929AB287E292B2C0C2B672AD02CC32AD42CB428E32744250526E9293E2912299B29A52841283A27392617275229AF2ADA2AC72B4B2CEE2A142A142BCC2BCB2A542B762C602A8F2A362898272D29C82AC42DE1355232012CA82936260C27D429D12A282B6928C9265026E4274B29D42AB52C612D6B2B5E2CD9292728F0261F27AC27A328742B132A7029D12887288229642A57290E28532657266F26DC268829FD275B256126912770253F276728CA29B12C532CA029592869281A2A4F295E284127452A9F2A3928B0265E267E25EE28DA2B01345631AD2C442991281129092AD12A0C2DA92AD528D225D127F029F0291A2BEA2ABA2A672A642ACA282126A32727287B2ABD291D2A4127B1255227C727A027022B852AF326B22637261827D72803299526752897295B271B25AF27AD28882A4A2BE52B042A04290F29A128C9275E27F128872A1D29702745265A27C9279528ED329231312CB729052AAB27922AB02B532BC52A672ADE29BA2AC92B9E285128C127F028982A7E2ADD284828EA27672BEC2B8E2B4F2B81272227642699268426BF279F2A6E2B2528FE266E28042AEA2898271D2B2A2A912A3728E129732D022DAA2C2E2EB22C722DFA2A362B84294329042C5C2B742AAB28F826F529B92B542BBD340431442DD82A96271B272F27442B592A4528C127B628512AC829F82A372AF1298229AE29132A71298928FE29E72BA12CD62C2C2C2A2AED298928C225AD26ED274C2B7F2C9D290B27A627752AEC2A8A2ACB2CAD2CA62A1729E7292E2C162D7B2B2A2E842D8D2B472BCC2B952A9C27302A1C2B0B2CC82AF7294C2C5D2CC02D6136512FD42ADD290A29BE27EB287C29C727DD261E289D28742B842CBD2BA52A382A75290D2C912AFF274D26D127682ED22C59295029D52A012A5E2A9229412899292C2B6A2B002A5B26CD25BF27312AB92A852C922A052A642AA3297229E72B792C532D4D2D972D042AB92AD6286E28672BE92B9A2D182D0B2C292C212DB42DF13417305E2AD3280B280228A628B929DC276D28AE284529232CBF2B232DCC2CF02BC12B332BC12BCE28BA28B328082A592A102A6E2ACB29F32C8E2B9A2A012A102BF22A592CC52AE3256D2686272D29662B602C772B1C29422858276F282B29682DFD2D6A2D452D792C702AB028EB27102B212DBB2C812C2B2C092CD62B2B2CBB35FA2FD1297D27A227EC2629273B283F28AE265F26B828422A5B2A732CB92C082BA82B692BDF2D652ADE27DA27BE299C2A13287F267D28E028C9261F27AE276F28022A702BF12831268B248C272C288C2A412C2F2B4A2A68295C28D928602C042DC82C4B2C482D6E2B8E2BAA283B2812291C2B1E2DDA2C862BD529F62B5E2BE234B92FAA2A6D27EA23452694272327F626FA26EF27FF28F82A192A8129712BCB2CC22B2B2D3E2D7A2AAC28E62AD52A272CC9290A275A2518267F25A525D2256B271E2AF42909291E26DA22F123DB262029492C552C882B272A7529E9278B2A852C622CBB2C0D2B1D2A672A3B2A7B2702289E29892DEA2B662A672C382B1B2D6C34C730762B6128642658253A257426B1245D25A1260328A029CF2AB12A982BF52BB32A7A2A032C742A142977294D2A6A2AE4287D27DC255E25DE268E25F825802503277B27EB2633254024C824F925CE251F28292BB42BDB29B42997276028272A322DCB2B4C2C43295F2ACF28C326D127FD28B02CBC2D6F2C3C2CD02C732DFA330832122DDF2B9828D92754252824752504245226EF27272A0D2BF2292D293F297E29CD2AA02B642A32278426132A412AF927FB257B2578251B28B62771273328CE266F2685264225FC257925D824432457263729942809281627B826AF270028042A5D2BDF2BE22AAF2AAA28FC28C329C62A752B552C962A122C412DC12BD034DA30C42BB32CFC291328A9252B24752357240D25F72523289F28012A7D29C6276927C4284E277627C7245D25DF264426BD27FD25B024BE25F627EE299429F928B027F025D625F825A8256F25FB243326C0266B281627B426C8285E287826BF26D4265729782BF72A402BA0299428C729142CE82AAE2A872BC32BD02CAF2CC83532309A2C0A2D3A2B9E2AAD270A253C23F52424247125DB27BF289D28A628FA281528ED2754267A275425DA24C32788279328492917276526EE28BE289328422735288027D924A623E123992587256C280B2B4E2938288F26032A452BCF28BB27CA25DD26FC288529C62B352B1E281C2A272DAB2A202CCB2A9E2CB62DE22D78352A2E122B032AB92BCC2AD327BB268625A32402247D256C25B026E5265627B529EB29402AA829392817266026D426EF282D298E29152A3E2A2F2B3A2BDD2AD02A342B4D2AD4275C24AF239F25BA267B27002C3B2DAC2963277729002A6F29A9295A29F6271228E8276D29A3287428502A622C612C6F2CC42BA62C7F2CE92D9335152FE02AB32B2529F0290C28EF282728FF244424A3241A256B2500263D29972A262B282A732C7C28ED276026BE274228CE276028602A552B782A2529B6281C2A312B9629EF261A26CC24DB233227A127022D6A2B8C29A4277427CB289329E329C9289928542A6D286D288C26F726A326252AEC2CD82E792D532C712B702DC0359630812BD32A162C042A962941288D290127E5257825D026BA2521274B2B132D7E2B262B02287D290429DC26B729BE29DA284C2854285229282A2B29F62788299C28C626CC25FB23F3231B266D250D26AA29BB2942295829BC286D27AB27F92AE02A692BA92A8829D3284E265426432810266928B22ADB29F82A722BAA2D03367331702C572D892A5E2B292AFC299F2A29283D244924B4241427F127942A402D682A0B2A37288828CE28D328A929E4271B2575270228C12872280D28A326A4260E27B227402412243B269724BB2729268F281228A127FC26772783272828432A722B4F2ADD2BC72A782CFC28C828252745277326A628D527282A512C122DC9364330542D4A2B0F2BDD27F6297A2AA6287727EE2593259A239B24D027B8287829CF2A5F29A528CA272F27B8294E2BA7291D283227CE260E28D4280226832600260D24B923A122DF22B2251C273C27262787287228172735262A27DC28E429FB2C5D2D6E293C281C29C02C462CEA2BDC2AB7290228FE26A4269E282F2B452E57374E31EE2B402A3B277B26C8275629C32A3E28182494249D2311241F2305265628702750298528D1270328CF2AA82A7F2C83293527F9243527A82837282E28DE26E024AB230522952362249428F0290D2BF028D928C32647251D26D625F8285E2B682B29294628C428652BEC2A5B2BE82B372BA428E426EE26CE28AC2AD32B1F36A12F882ADB27092654264127492835279127472497232A23EB222C239325AC285A292D29AE272B274A27F428CC2B712A51288C253124512407277F28BE27FF259F240021EE20392002252525BA28C729A22A512B7127E324A0248D26ED267B2A992BA8296A28AD271E27D526DC29E32B9D2B842A1929ED274928C1284A2B1C36422FAE29BF28F424C824E326402778276B27F82538259A255E237722002587266027922820294127B12720270E29E42AEB292A281F279224AD269128ED26EA25622360210D239C223E246D240A26542794298D2A7F29062A95294B2653260D29AD2BC62CE5296B2ADB2AE5285027F928F0293A2B4C2B2C2A472B052BF22B9234D32E4327FB254C25AE25DE27B128C4277C28BA2753251E2547243023A323FC23F924A8260F292F2891270B272F27362904290128DA24D525CE2569271228FC246123062280241026F02589254E25DB269C28EC28E629862C7629B227322686253F29C72A102CA92B962B202A83286229DC29BD2AE12B9A2BAF2BF52C402B4934D32B4F27EF25B624B025CF281D28F629122B332A4E290A26BB26C1258D267824BA24C725E12738285829DD273B28A12A7E28CA29342940284125D826EA27F524772340247A2582265D2720279F26F4255E28DE267D2840297B2A2E28A32633281B2779283829842A9D2CBB2BDE297F29EA297B29382A4C26B128BB2ABD2B6F34B62C2E28F0231B2647267F287A2A422B052E652AAF28CE274D2805289827B7274324FA24A026222A6E2A592ADD29002B2D2ABE2AF129072A7C299D2831267525A024EE26A2279528A628852810298B287A288F283E2765278429EE274E2858272F29E2255326A227172A112A672BB628DC2A5D295C29212AFB29FF2B3B2CA933B02C3E282C2537254C268B28F429582C902D2C2C012A452800299C260528F726CB26F426EE244329D929A82AA92B512902297628A929C2288D2B3B294A2AC2273127B1279A29C629D52BF929FC29BA2A202A1B293528F0255F27E92464272628042A7928A4271F279A29CB282B2B492B7F2A142AF72AE72A4B2CAC2CF42C1536A32ED527EC23C9240A276A2A702A732CE02C3F2B252A0328E0262E29092A44298128962738255F27BD269C280A2AAE2A1628A3284B28E927FC286D29BA27102828289126E127B929A628C029272AB727922A3A2B2F292F252A2632251B279626A028DC28BA282A2692278A27A0270E28342AA229DE2BD829D62AED297A2B8E34F82CCF26A0247724EF254529B82CD02B842C0B2AEC279D27A3284F28402AE128FD2743275826D124AC240F28A1296629C5269227BD2758272128D82891275D26F4274628242982280F290929D427D2262827612875281F2782265E259825BD241726892862299527C12640251F2525284528D028F729CB299D2BD12B6C2C29360D2C55256C247524EB251F2A622A222CB02C63297D282A27C928A329582A402AB328B0274D28A92663235924B0266727D4259F266F25F32759275F240D2646250E262928BF292427B627302747250D27AA27D728C0270329A229A9285125F0226124B3250D27C42605282226A526AB273027A227FE284F28FE290E2A222B2C337C2DC52656236825FF26FE286C2BE42C7C2C2028BC26E0289A28692B472CB82B372BF8298D29A128D42500256927AE28F726FE27EA268C258725C6257E2551254426BE2637266326662632264B271728C529082AD128D427DF28302A9327D62580241E2474245026BE27C1283428A12A48299229852880279B27B027BB290B333E2D27288D26AB23A125322818298429F72936290C279E276A27A82AAC2BDF2CA7294129122A9B28F827D625C9268826FC27412AAC28C227252670234D23DF221425F024E22567255F250B260428AC28082ABB29C227AF29082B5C2AB7296727922687247E25F2262228FD276028B3278728172A0E28AB275C271027D2276133E02FE02940260A24DA2471262F28A627B227DF26ED2425255B258B27412A5727E326B926D626A628D92913293527DF24C326B929002C3E29BE2877241A24EF240126F6261B284F251627F52716282028B329342B112AFB29192A7B2A3D2AEE29E1273B26B0258D267A2956295E2A152BA827C327ED28D527EF27072BCF2B7736022EAF281F25CD23A023DA255725F2276524DC25AA250C25C4244127F627BC257D242F26E024CE27CF276028E6278926CC242227282978298F2A0628BC255A243D253126A327B826D4271029FE285D28E0266828D927EC272428A529032B7A2A9C293827F525FB25CF291A29732AD428F825CC262227E427F02AC22BF62C9D354F2E0C275725E425FE23FE241025EE257926F525652848268F241626D5269D261527932469263028EB275F27F6282F29C2250A265926A8271729A52798267023E9234825232894261C27FE2745294828FF274229862632279D2ADB2BEB2C3D2C55291E27DA25EA256F28932A9D2A782BA2294E259E24512535262A28A4299A32C22EDC2968260D25EA25FB23A625B725A327112938289926AC266925B224172751276227E7261F281926CB25302813291B286E26F626F3271527FD2893270824792533257C24D0239C2726267B27E726F729462A96273527712A2F2AC72DFF296E2C112B1C290526462725288B2A742DC129F1254424B5239A25DF253528933222306029B42619251926BE230726FE25F527AC28C22958277425942319247624322577267D25A926492682263E28642A172B1929A6270224C8252326DE27822543245B230724202445222F2600252725C72746292227B42743284229EC2872290A296428F828A325E726ED2651285329292AF227BC255424F523AB241326BA31D92E57297028C724C3238F23D6255F2602291429F9295429F625E025B5250723B82537265027CB27862735271F296D29C229402A8E27C22409276926E52534250E268E269523292253211023E921AF23F8257227EB254126BC27AD27ED282A2732294829D32789273F265925E6259A29A22978285E2690221325AB257727C12FCE2DEC2815279C25D9239B246D268D273528CE27D529F02A2B272C2463244E2531252E2524263827CD277827802774280C2990273425DE256B247F26DB24FE257426D426A52603236A212A22092234227223D4236725E025D925EB268926782AD72AD7281928EB2792275A247924202668278A27DA2782252726F32600278D2FF12CE92848251D24BB224F2273257526B4274F268E289426FA2512246D2332236D24C7244C26E926082852258826992905296B2758258B24AD25A2252027392748263227C0284A24CB22D021AF21A0224C23602439261B25EE2673258E25BA263D2BC02AAA28B3262C271226A623B6240C24E7265C29C428722768270228D72FD82C6827F1250B247D24D6230A24F925F2273A26C4271427AC270525E123B62245229D248B25132783254625DD25E6267A263B2561243626242717275E27672654264A270D287C26DD25BC23FD22D0224F227F232323DC25BF27DE2642252A278229842A082B182A2D29362559233F23FB244823442631279E271D2608283631F62BD1257824BB240A24B922FB232C27922675274427C927A5288F26BF246E24D823A2236B273329222912274F28372747261227D92799271428CC279E261227F125BC27B726C52754256425BE22A022A8224F230A2377254529A628D728BB2860299E2A432B932A1229332740262B2218228523FF241327E928BF2AE72A7D31A52B722556223D235C236922D723492503279328F8274926D727E8273C2778256C241E2535269D2766290B28E9296627D727372889255728052792277E277527B6255F258A27BF28B926382793249522AC24DC2313219925192703295429CF2ADC298F28712BC62A1228A126A523E322412227235D243423CC260928262BE832C82B2326F2223C2242236D232923D026CE268826FF255826BB25B92685284528F1241625E327EB253E286028B6296C291B2A1F2AC8273B279D26A727842612277F25D723B527882889285129342760231D24D322E422A7222427BE26BB293A28A127B028C029F0299E2BEA26482581248224292345240F25DC258C2499272D33332CDD25E22154230D234523F422132651271F27D926D226BC258925CD2899289B27522646265C24D0265D2666288428C428B3298B275724A825F4273F26B725F3235F233C273D282228CD29992838250A254824C821E32224235F23EB233D24ED256C25832672269428A52730261B254C249825CD246624CC24692777284F34782CA125042448211D2483245223C42458272C281B297027E125D925322806275926CA277A261E25B425D124C826A827F128C42A3129422632263024DA249E2413235D232024A12719290728FD2739282E26C12356234B20E91F3B22E6225324BA233B24E42374239D25292532257F25DA23CF27DD2700268C25D5271829AD32 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 80287422CB22862028217020691FE31F3120B41F0F1FC71E6E1EE41DEC1F721E4C1D7A1F081F151DC21E621E6520951E691F871EA71F811FD71E871EA2202D1FB01D871E7B1DD31B561C541EA81D301E7D1D351F061EC41DAD1ED71D231D4C1E911F381F0A1FE31C781E121EF61C891FAA1D2520911F371F7A1E6121F422D82DC22B09246520C1227522A820D5205821A421941FB120D81FF11E991F721F541F441ED71EC51E991E9F1EE71F5F206121321FBD202A1F69203D1F27207120991EC01E0420F51E771FBF1DF91FF41DE91D27204E1F421E211EBB1E9C20EF1FDD1E731F751FF41F871ED61F2720341F801FFE1EA5203D21F4207421B3214724BA2D1D2BD024512345222521BE20102115222E20BF2239220C227C20C61F2B2026201820EE20D81F981EE51EA4201020D81FED2047212F2004204B20C61C221F8520FD1FC620DD1F2820A41E6E1F751E4B1EDF1EBB1F4A1E0F1FEF1F4F1D691FC01FD01FED1F611F431E0C200C200F20BD1EDF1E961F2D2238201B215521D4248D2EE02B16283124772141227921AD2258219520552076200920E820EE1F9521C41E1720FF1F0720D1214A1F901FC41E96208220172121202121561F6E1E531D491FAF209E201D21CC1E881E4A1F331EE71DA61EC81F971F2620A11FA21F1E20CA205D21FC1F69209E1FE71E751E481EE21ED31FF41FFB2039227720E921E2232A2E9D2CF225E2212E214421E421DE20A421BD21C820D820DF200420351F06214820F21E8520A71FC21FC81F971FE821701E341F1A22691F7D1C431F2E1FBF1EA81E5420EE203C20181EC61E0E1FFD1DD01FB71ED520DB1E331F921F22201F1FE41E9E20592030212B1F2D20EB1EAB1F5C1FEE1FA21F7E20881F8D202F22F822B52C832ABD2579227B2381209222C420B22032226021A621422203200920852099207720F51FA71F3A21661F511FBB202C21FB1E46208A1F551F441F5B1F151FD41F2620C220B91F0A1E4420351E741FF61E8B1F701F2420F01F501F0B20AF1FB11FC92021218F1F0520E61F5E20BD1F1D201E1F482002221C21C62031233624682DCF2A7F23862251225C21782140223E21E220462265214D20992030207B214B21AD215A206F20F31FAB215121D31F5120561E7B1ED91FE01F11208B1F4B219F20CF1F8220C31F261FDB1EB01ECF1E7F1E0B205C214C1F391FCE1F5520191FE41FF5202B1F5320901FCF1FD81F691F981F03217E1FC120861F5F214A225622CF2DAA2BB12547230224032257201821D621C7218A22B020392151224D231021EE201922DD21DA211922DC2147204F210E232D20B21F5920E81FEB204A21922013208A20FE200D21901FE21F7A219F21C81EEF21E520831FE91ECA1FA21E93205620CA2070208320912020215F2011209D20A8203F20B0201C207822B8221425FD2E252AAC25E7238C22B5220121971FDF2100231B222B21B120F02083202C217C1FEB1F2121592181213A21DC1F5D1E5621891FCE200B1F651EA11E47209F1F671F2B2027214C20E91F591FF11E741E011F7C20681F6220AB1ED5218C20E81F35206B20251F7A210121FA21EB1FCA1E3D207821212089203020C020CD221023BC2EAD2CE8231322C0210122D820A5217821E9221D21AF22F62174207B217A211121A521CF1F2121F12000210D212B1F7D20261F98211021361F0821251F141F1D20EE1FAD2124204C20F71E65204020EC1E3020DB2008209A1F7B1FA220531F38204E2369207D1F24211B21142168217E201E21B3214A215D21A820512336249330E92A0427C523B42235239F21A8219C2115221422CF2376225122822048217F217921C22016215121101FA120A81F2B21B01EA71E141F411F35206F1FB81E9A1ECE208620A920EC20271FD61E5C20A91ED51FBA1E531F681FE52067205C207C2131211B20D81FCE203B21AA1FC61E1821E8206420B120B11FED214E23E32355302D2CE0251723A2243122CC207B216A212923A9231A23A02262215621952126222621FD20D0205823D6206F22E31F61203920362092200620241FE11E4A20BB1F381FC320062074208F20971F9C2080202421901FB420F120BF205520BA1F7E21AB219921B322AB20C522D621C9209B22CB2155214021D72102226222DF250030052D6F2784237522DC213A219E21D620AA2264229D21B923C52122235B22222314221B21D11F1822F720EC20F31FE0226B2123218120A11FDF1F14213F201921DE1F822145228620571FD420BC22B020C81F3A21CC1F37202922F0211120EE21C220CC20FA1EE01FAC20D1205D20952144216421F1232A22FF2287232426CF2DB72B4B26392369239F23E3209B21762289239F23692247229B214E21D122C5202B22DC21E2204E21E220972034212C223E2226225E20F41F2C221620C81FF81E382186218B213320D020F9203B22562021226E22AF20782005204B214E210422C822601F5620CC1F6421901FBA1ED02015226C23872325231D244124B6257030682BCC256424F122FF233C229723CD218B248122012472249E21DD21B2217722EF201023BA2368218C20BC20FF211023FD22B02155209D21F6202620D52040211E231A22FE212F21CB204F2051205F210E2133223F2279201B21CC217520132123210A22F421E7206D229921FD200D226923BD222025C822CB2307257525B52EE42C6F27BF23CC223023CA23102378235E222C24E82454234C21BB227123E523ED210D23DE21CC21B1238F247122CB225421C322B8228A215021A321B0219D2133229521A421EE20D41F2E2381217D2131230D209020E020F4218D21AE21E021EE22CE20762267213023822463222F24E623F5240E263F2748262D26FB26402FC62BCB27F72598250023E522012357230F23EB230226AA24A12369231F233A23E722EA217A22DF21B8239822D723B4247C231C24CC2279200F220B23D722572322233A24BE230B22B420A31F68206421BB217F217C21F5224F253E232B223423DD2279218A2254215B2215236C24AB23A6266B26C8270C29A628B2271A28DF30D92DC52729267023B124E9245A23CE239D24F7253726F225BA243D24AF22F7223A22C822C9233D225B225F24B224EE24D6224E24C0236F22D92246226624C9232B25E4236D22A821B7230A2396216D20A5210224402317228825FF22C2216221DA23B42183223121AB23A6226E27A728072A7D297228D028B728E226AD26E331B42C4E2A862637267725CD240725CC23C72407267628C3253725DB2464258023A5233425F42268250C25152499269F271A24CE2442230A23B422E6228D256F259225C924BD244622A32490237E234620B422422236237A232823C8218321EF21CD22142430251322EC23E422FF2368252D2840284E27D2261528D22595262E304D2F3328EE25DC25DA245A240D2316244D23052586270F281A27CF234F26A325D0246321CE23C324A6239824BD251026912600258A215220BF2467239C2691258E26AC269425F925C824EB23BC21D221632224232E2373232F259F228C2264230D25322412246B24ED24C921512241267F262527EC262B253B25BA255C25522F962E49298A2876277D2590248E22F9221E24C2258228E3269725CD244D24F824B1233C26CB23D4236525CF274527D026D3263B246D23D2213522C82496260C298029B0296C28C8271A258323E8244A21672383241D255125C223D424C2223923FE23B522DA22AF2227246E2385238B277125A9251F27D5228B2452248824622F162EAE284829B32778257E247F237D23CC24DD25C824EA262426922656258B258725D6228D25B524C12678272F280F27A1241E243A213C210023872366270E286829422AD428C62766269424392295221A24EF243D2433252E25FC24E6221123DF226623AA217C227123042354240F24AF233D25242329247B231E23E224332F852EA3291A29A629C62844265224D92320269026A0271A278726802533287426FB252024382410234E24DE258A268125C02326237721A6216E22D622A42694281F270F285A279026E5249C26C723D821C2242F253D25A324102582248D230D248923582340247B22912473264D26122660257523562337239E22142336243730AF2F9D2A152B422AF8289B24A824412516250826E0273328212576262529E326C82571252E237A24772429257C26B126ED2410235821A1220A231F236C26BF27EC277928712662242926F2240624852364240324DA25C0240B255E235E22B8230C21BD2113222222802422246926BF27F82626247923F322D123E622EA25CD30CE30722B0F2A372A392ABA276624FA23F226D526732AA82994264E257D24CE246A24AD2356242727D324CD24CE26832698257C25AE246D239822DF23F22420270E275B28C028B52839272F249A243F22D622992385245824AB243822C021E121432302211B21BB220024D925BA2643297E28B425E4242524A425B625602568305D2FCE2AD929FE2AE1284A27C62598242E253825D527F127B6257125E524E923E4247D2268246E250127B5286926D4272C274327E9269D244C26392692272A272328F127852842270F24D023EF22D2203323C822CD214021F2237221282118235E2177212222BD21F825A0262E2829295328EC24CE23EC224024EA238327D331F42FB12A5029C5274E281827182548247424E0247A274127AC24E724B72324231524A02471235C271C28FF27B127E12911298D2744271E25E726C5276A28212695263626E826A7233C24BF21FE215D2299212723C3222322B0223B24DC226C2497211C21B6226D23C2254B2674273E271626EB24AA2447246B23BF253A2762322C30612B392727289A26E12541259E254525992533286126F5280126F6243E24EF228E24E125F728FB29C72A8D2A8C2A98291827DA23B824D3251C279826F025592502255824E4219922E620F7217A219C22E12220230F240E24242553242E243F25892201226A240C26BF26E426D32504260F25172665255126CB26A92A91354631532A5329332827260924542488246B26F126F2269A28C327F4289426DF2534252A24B22673285C2A6E2BF429D828C92605268F22D9219223E3245A2315241424FC23172443217B215221C61F0121A223E12338253E2571274C257926972677242123FE21AA24F7258F269E26D627B7266D28F927CB25AB250029742AFC3452327C2B6726E2259125F2269624CA2437279227AC2B4E2B552B4F298B28CE26A0251D25EF26F42AD429ED2A0E2944290625C02375223E2168220922DB21A8228522AC22D72272224C217021E5206422AE24D92505282726CA28C72849282027F8256025CF254B26B027BF28C127B6272C27E3276C289325C125E427DF28B533A931082BE728AB27622832262D259E262C277C2B202B482DB52B8F2BD8288824E0239224AD26902726276A2621284326D823F8224423AF20D32136229D22AC229B2267239223952244229B20782197225B24AC280F277928742A762B7B288626BF248027A1274B269A2A782C372D1C2CF329C027B7260025B8260D27902752317B31732D5129BD2A7D2AEB2660253C241A282B2B622E3B2D082B5C2B962BFF28A42442243E2566263D24E1249123F021CB21AE22B321FB201C22BC207223DF22282650258F25A622D82266238D2245215324772802288B29BD2AF4299D282325C0250D2792278B29952A552A8A2B582B8A29BE28002538246923F025A9261E303831B92A8E2986298C292A28D526EA246925DF27F228E428182ABE292B28B92522245D22AF24CE2390239523BD2247210C214322FD2102225422B3224622802498257527B7269D254223BB240B23802326266D29CB2A7A2ACF29F0274E26A5237F250F273A28C028F9290C2AB029B12838270225DC24F92215242C25C9256F30BF30732BA229572BDC29F428A32402242C25EE2516267927DC278A27A326C02480223824F4227E23B6243323DC2438239722B022B72256205F226A246124972559288F282027C22547267A236E23A2232128782AA0295F2AA329AC268A2423240B255E272529A7299B290E272C252E249825A6249022572359259D26E9265F320031262B8C29C72B1B2C63270C26792376251A25B7266227AA283926E725C9234C23A3230E24E42475272F26AF253F276225DF237F24B8215422D224C12657281228272944269C2484250725B8240D249827F329512A9A2A2528352688261A247327EE27CD27F226DD262127C5244424D122AA230F2510255526A328EC280B33AF2F042B0F2CD52A492B31283E2584237C2459259627BB28692788252A249D231B258F248B24A227C1261A275728FB271A268F25932568225823F9257827FC296E290528BB27F522FD21AA259A266A257927D82ADA2A272836272027C6262328E727AF28762A102BA5295E26222232227F23ED2443264726CB276D29BE290D352031BD2B5B2C1D2C7D2A732682233024862495266F28222703262523DE23C4236224AE25422638294129AF285927AB29A9283426782711240C242627C3271F2A042ADE29B1265B22F520FF2376253427E529BB29D427E0246F25AF232E269427302B8C28D129502AD5266323A422E22373242226B7281A29102B562A1F2AA333BB31132DDF2B882B9F2A2F284F26EA2511269526F027D82549245B272B25E12362257C2551270B29162B1A28BE28962A512AFF273F261A24D824E226D4288E2BC12AA32A9D282A24CF22B122C0254627072A7E2886275F249023072570264627BF297E2ADA28572601262F23E523A624CB25BB25E62A9E2BD62B9E2BB32B46354F321B2C2A2B302B9F294E27F1248724832707250126DE260C2786270728DE25D8261A260B27E029D72A652B102CF929552C2F293A253D25F8239F26A8293E2A8F2ACE2A132ADE2407238823C424EC27332AFD2745262E24A923EC2211253C286C29E028C426CE24702302235C230425D624D62569294729E12BFA2C072DDA334531E82A362A5B2911275425A4244F24D724FC24AD26662742275F276A274C262D258526AA27D629402DD32A102B342CBC2AA82835253D24242440256B28B8275529C729A32868257C240625DF25D627442A902AAE27C223FD238122B623852555270B274526D92468246522AB2269247B25CD259C286829F12BA82CAD2D7835F52F7E2BF928402910283A264D2541256027C826B62542267728CB2A282BA6287F27AF269D25692B852BDB2B262B4B2A232A24291B24042354256923BF254A276B284428A9278B252A24EC2524267528B92ACA2AFD27E523A32271224D2451261725C4251F25D7246425FF238E23F92338243825F1267F28F029472B7A2EC035A630C1296B2759283E251B257125E026E3275128B029BC2A002A732A652B53297F27572694276C29DB2B462B542BC32AFE29D326E723472273236C248F2488260F269B27932809243F241D27EA28C828D328BD28B12768260A26CE24D9249A24512699256D245125C02694248D24822416259826282A3E2A922CB12D982DEE3393301E2A5529302799284223D3251F28872891294A2AE02A212A332ADF2BEF290628972599267E268627A027E6264C270D266324C8229623CA23A3248226C7269C260626EC26D224E624EF250E28F8271B285126A12620244C258F26472763257F251D26EB25A626F0279126F4247B25B026C829B52C972DD82CC42A742DC734B42ED828C5266126D1251C268024C72661289B29672A412AA329112B2B29E827DF24D725D7245E24D82245245A25AF25D122EB252324CD219725C325D9264D29C6286B2724254E226022F5233B273E26442640251C2428248D26882714285A2856250E25D2260A28A728D126D324E12526284D2A1F2D092B3E2A5C2B152D29358B2F4629A8267E2500261726ED238E245B286E274C272028BC27A428592A8328D0241F25A823CC246126CC256C26E2257F2447231B236024D72482269C27BF26B925EB254B2427212B22C12391236A253224F9252624D125922510293F2961288D2705278D287429412B8626EF24DC268127BF29912CC72B622CF82B742C62344930AC29992651255225CA248325F6262B277127BE25AC26DD28C72AC32A8927B824FF240B26B428F5268927FC27B827E428DA262725EA24802598224525B3246C25CC243D243B229D2188211824BA235B23A4241223D6241428C4274F2A042B8229EB2844294F28562A6628BF250228A528B429432D562C702D2E2FC42D5535A230DA2BC527C1247D2518261527D52715287A254E252D245825DA2719285B2618254527B325B928832924289827C429992A522A61283627002635248B24712547256F2374231E2342223B2331265824D523B5226C2457258525CD29832BCD2AFE280D2AF3288F284328DF25DB25C229AD2982289D2AAD2B382DA92D7E2D0D3635324F2BF22871267C24DE260E27A6294E2BF029C926E1251125D82571250B259C255F253328D82A882AD728102AC22AA82AEA2A93292027C22436257B2491247F253F25332666245E2481251D268526C9257025F7234125252868297D2B1A2C482B592CEB2ADD283327FC25B027F8284C2853280629802AA62CF12C0A2DEB348032602C3D28E525A9255927FC286E29D72AEA2A062BC0272025252467246522EA24A123852724298028DC294C29D22B482C552A9D2644246B246B2212247325AA270128B329E926D6252B25BF265626B525BB25EF23E4258D29862AFF29002CAE2B6B29CC2949275F26EB251A275F2ADF2AC028ED261A28082BFA2B4A2CC23207314E2C7428B1266727D027EB27422AA92C722B1A2B552A2B27E724E523B6249322C9243C27362A372BD82920295B28452AEB2AB927D624A62250222524FA26FF29C72BAC2BCE29E226D925FE25AF26D124D5252925C624B728F52A9D2A892A9D291A2C2E290128A025CE257527C829832B172B86297B27FD282528812839322A31AF2B5E2957266F275829D12C142D2A2C852A2C2CBE2B512A9C26CB240A2349251929AF28542BE829652B552AE92A7427BE2584255E2313233A253C26CE261A28852A5A2B082A0828AE2496244D25BB26A42440257C27D629DE2C902A8D2BD22B152D8829E1267825C925F227C32AB02BAB2A442A34290F2A6126F32784308731DC2CE02907282A270C2A222C9B2B792CBB2B712CCD2A5C2990270B259A238B2378253E27F92BDA2ADC2A292B372A4026812623242724092672240726C6264229CF2C112BF4292C2725259F237023D624FD2589253526E0272129DB28F628CF29042A0E288E2348267125DB262E29F52A6D2BDD299E2752267B26F726973142311A2BD42AEF276229232B412B4029352B472C3C2C302C2E2B0727C0254C24422435279226A12A2C2C812AB129BE267925902259241D24392689253B275726F827C82B882C842AFB28F5244024562432256E265F25EE26EC29A929B328932809282E27FA24402492229523CA265E284728F628E12A0A28C62642258E26F733AE322129AA277B261129292AB729DB2A342936286D2A322AA427B4246D247C26E8241A289C297B2B82289128B8274526A62347236A22EE2384254E27A0280728552A5D2C4E2B53297726B02440232D2426276528A32798286E276C28482731284E29242647233D23DD241B237725B428A227BD26A928D3251A26DA25F2263F31E12F93291E269927B5294F2B112A4629B9266A277229D22A7D257B254F244A25BA25C52681293E2B942C23298D29572749237D236326F2232627A129882A042A2D2BA42BEB2AEA29AE26B523D32369244C28E32A472A0C29342774285C28F9299C2BC927BD249B24D2254125F3242C268025A025B92776254D2548261526B42FFA2FC7285827D6266A26EB290E29C528FA2899272629A2294628512467258F25492899273928972B282B352CA62A862A8826C22472230626D627DD2A9F2CBF2A2F2B652D402A2F2ACA26512411233F251228BD298C28072717261A27EF28ED29BF2AA8287027F324B028C4282927DB27F525B925AE285A2624257A278E293E33622DC927F425EF27C7272729DB281F2A0028C8265C2ACA274227D125C5276928272A9A28C12676278429F127CD2AA62A0F2A8B2776241A245E260B29732B172B792A912C312BA229D426332410270D27E9286A2B7E2914288C2755276B28A22948291027E326BD273329A52A452BBD2857253D249A289B279228C028002BB9347F2D44251925F626EA29B229192BDA2860289B29202A2A27D8257925FF271D285E290328A625252654258A26F126F32822281D25E924E124952507270B294C29642A602C852BC8289225A423A82617287E2B252CAD2BCB284529D427442875296E284F27FD27EB26012BAA2AF7299327D425D028B52B2F2C182D922A102C5F34DA2B9225E2240926E727C329722A1929B628BA28E32885265E260E24CF2625278E27BE268D26EC260026A925F826B0266D254C248A250024DD264928322B1F2BAB2A882C562DAD2859263526CE267E286E2B5E2C5A2B2F2BED29CD295A2A9F28A4261D26B127E127582BFD2A3E2A4329A726D22AEE2B862B4D2CEE29392B1B36312CB825132603261D282429F427482783277A26B5261E24F723BA247F26FB253527E327CD27EA2816284E27D325852608286E25512341225E25A52895290E2CCA2A1D2DE52B9229A026DE251A279C28042B5F2A002D0E2B052B422AA6284B278725202423276E27752BA92AB427F028F028C929722AA52A0D29F328A82A6E34D02CC72693252627A328592986272F274C2771267E26C324B62431235E258229AD2A052B002B0A2B2F2B0D2C8029332888256C24FC24D924C123F9277127CB27E3284A2B852A3D285A259E24C0249B25D22790295629342B392965288427FB2551258124102655286D2BB22B032B6E2AA22AC42AD22A89274427C028DB2A72353A2CD6272C25BB27AA28AC28AC28062858297E28A427AB24F724B925CD271C28302B7A2BDA2B5A2C692B382DA62AA827EE24D4251A25062531244A25DD266128382AE32A572A5028FC2301234125F023BC257C26DB271629B029DA268824AD238325FC262E294429CC2B772B032CE12CA12B1D2BFD2A60299F28D427022B2335F22C3228E828B727132AE52AD329592846290C2B432A9A27542585271828832BB92B172C212BF22C212A432C33297227E724862790268025182573250727A829742AF329FD2A4C25B723E922812489235B266227CC263827B02A7E2730250125F9256027C628F72A1E2C462C992C322D792CD228C72B4B2781274B2B812C0A35FE2E3527C527D428A82BB52D562AE929C62BD42BD82BBD295628B8281F2B4E2A072D392D072C0D2AEC2B9C2AD626F52595250725A5271726C424EC23132707296D2A942A59276A2463220723FB2464243C27C429482A4E2A592B5F2B4428CD2665258B275B283B2A002D432B8C2BF72E722BB028882853272328AB2B032A2835812E55297E27A829CF2CA62B362B5029F32AD42BAC297928E027C8293D2C102DDA2B192C992B1D2C412A8C2AE22732245C232626D5259525A6259624AB25D42730292328DC24A7225723172467239025FD28BB29702B462A4E2C702ACC293028DC260825D027B92BFE2C412BDE2A602C222BCC2A80278D278328BB2BE82B9334402D84290E29492CF02B232D5E2CA329BF288126B9290827D629DE2A262C572AEE2B202B852C4F2B5329B7271724BC253C251A26C1276A25B625E124F623C525ED265D26F0234123DF253024E6220E2323265129F42AE4298F293A2A712AA52741271126BA2783286329632ADE297A2C9D294728F3266828832A9D2BD92C0C35AF2B852948294D2B4E2E772CAD29042A1A268B258F25E924CC28FB294A2CD7295629292AF82A3C2C572990264C2650266226DD27A528AA282F27E02468245825A1250D265A278A265324FD244D24C3225324EA29E52854291D2B432B2E2B94296C255624CE263A26232AD929862B832C852A3328B126F227132A0E2ED02DBF354E2D94299C2B342D5F2C292B7929F92994266424852511275126FB2868299628BE28F828D8288E2B9F291026DA2760269B28782B352DEC293529D527F324B323C126A527BC27E127CA271C271A26FF25C527002A492BD62AAF2960299D2A1727CA249025612525263727F827F52CFE2B642AB02853284327FA28B42B572DA333BF2EE429562BC52AD92A702BE02AAC293E282925E324AA243527C72844282328BF262B282B28682ABA290828B127802A202AE12ADE2A642B162BDF27FA24B023F7272D29AB29542B142BD02819286A253928D92B442B982CF72AE128EF295E28C525372580234526F826ED2A5E2B9B2BEE296C281D26C527D92A672B8B2B0634F02DEA296C29F6283D294B2AB02AD428432896257826F9277128052AE32BC2271027E9298C28AD26EC26F42658295E2B052C522BD22B402A522A4F284F25C925C127CE29A12B8E29322BF22BDE29C42632282C29162AB828BD2AAD2A2E2ACC2AAA27A02435253925B728012A5D2BE62B7A2885270E279728CC29DF2BFD2C6734802D0529C72882280127A3282229C32905290827E425F0297B29232B642DED2A0B2C2C2AD328D0266826DF2794292E2B9A2B3E2B492BD5294D2AE12645245F230C26A9261C295228332952293529A526AD275127D7275426F628C228822A912BAB281D2564248C24382849298A2B5A2911277726E3269A29962A8C2B682C1936D0308029E727C1273A28102A9D298B2985298E2773265F2ADA2AFB2B012D082E8D2C972BBA29D126EF27E0285F2B6F2CAC2BE72B742BF82B502AC427D3223523A426B526ED29392818283428EC261E262E269528ED25872666259A29682AD72A132B1A266D250725A72558275E274827FF26B1260428442AFF2CB92A2A2D96372A3062294C271326B928252A122CBD292D287F26F328542A152B5629F52A5C2D4C2B3B295A290C29EE27C428CC28382A042A9F2B342B342BFB2A1427B8246B268226F927A1286527EE279D25BA2439255828A9287F2AA7286027A826A029FC2A362AF426FD234924882430257B25F926BF242A263C29812A6C2CEF2B182D80377430A52A7626F727CE28C42A352EA12B2A2AFE288429442B522AC52AE929802A5A2A972940282D288C27A32CAE2BDE2BF9298E2B6129AC29F7299B286524C924562661271C29AC275726C526D825DA259D27722A532C282A0829BA279329482BEC2A1E27AE242E248A253C24BD24D6248D25E226A7283028692AAE2A802BF4355031202B2C29F3288929122B072DB52BE12B9A2A582CD12B0E2C222C9A284029DF28E626DF26E928E2285D29742CCA2D082BBB29EB26D825542683238824BF24E026ED28F22A2329D927322731260A267227E2285529A927F32832284127EB28C6273E273824992272262F250827B225C524FF27092A192AE52A262A442A1333352F0E2973265726B229E92A2A2AAB2B6D2CED2A3E2BAD2AA52B192B5B2AC728E32636263D264328B9269B27E6272B294627C527C325A423812490222A23C4236F2502281429E9285826AD25FD2617264E26B729C72829283D294429D729192929282B259424F122E4252E277A27CF28B32641299F2CE72A102B172B3C2BD932052FA5295326C625C6270029702AB62CBD2CE72BE92A1B2BE72A9B2A5928E22795258826AB267D26F026AA273427E32564266026C6253024A02210233521582310276927602AF2283C262C256526FF26CB29052CB02ACA2B252B012A952CEE2CDA2B05280D253A2674271429652A652D642B1F2BF02BF82D712CAF2BFB2BB733BE2FD528F425E6240526AD276528B428432BF32A082C542ABE29DD292529C12796265726A227B026F425E325BB251B26EC25E02781273E245D23D021A123A7234726702848290328CC252C267D25BE243829AA2AF82AA22A922A192C132C8F2C382A63292C28882402288F2AA42AED2CF8293C2B3E2B80292B2A4A2B2B2B9234842E272986269C26292730289528D727CA27412AA6292129AD28A7273C26A0253E2650269927A227D1260E28FA27F22866299A2B45297825F324782372231222932455292B2C482ADF289828B924C8265829B02B0C291C282F2A7D2CB82C552CF62A732912250D265727202AD42A3A2BB9291A2B002B3D2AFA2A382AFB2ADD34BC2E56285D28EE27152AEC2B7629FD29D129442A3A2A0C293C28232735256927BA238227BC298F29B427E1250F29342A382968297D272127F726A12546261525FE2514288429052B4A2A8A286726ED250F27C129D828C1286B2AA72D0C2E7D2BF528F826E8250027182A3E2AE72AB62ACC29242A882A4B29B32871288E2AC1358D2EEC28F9267F299F2BC12AB229E4289927CA29A42BD72A54281A289D26A82943289B2720289B27AD257326A628312C7728B3289A274D278D28D129A2271D2743271828AD2810298D289F28AE28352690259B26A7267A28552AF12AE72B252A03271F275C265D288C297529482B4E292F28DA2A392C2B2862270F27CF2B36355530422A8E286B290C2B672A1F280427C3276429152C6F2D702C3E2A372BF42984270E279D2742279C268327222AC32A122CE72947282D295B2C1D2BE128B529922A8A28B825BC24A225D426AF288926782678253D2601269F29E62A6429BF282A272027E428AD2A512A422AFE2A022C662BBF2B8F2D4A2BDA29A729212D0B37CF2F982A4B2A3A2A4B2A8A2935260225C725BC27D8291A2CE52BF72A362CB62AE3292F2814276426E527C4268D27E628B127FB279A289628CA2C812B022BA128DD29152AFE295626C1246D25A6280728C026CE258424A523F92AFE2837284F26E6255029E62A802A1E2A6429B72ADB2B212B8D2C2F2CAE2BA928C627B12A0435672E7429EC26812876295328D926B624A526A3277828012A962A032BF42AC72AF32727277F257B2727290C28B727DA26ED264E2749293D29852BE12AD52AE029522A0E2BBC2A142809265925F328D927CB251625C0227C255F26DF27492654251D26FE28822A2A2B4F2AD829A22A0E2CA02A522B4A2A5328AE27892745293B34D82F3627E2264128B627E2266525EB27A727262AB32AA8297129D92AF42B602A902820257A26492894298C2823295C287D28A9260A281C27CB28F726FC263928292AEF2B192930290E29D2290C2A052AE529BF25EA244B241A277026B724F22529268829882AE82BC62B2129BF2A942BE32B222A9C2711254727CE263F29D4340E2E1929E6262E262126DC2583259E27482A0E2BD62B8B27FE292E2BD92A852B69284C261026A9291A2941288729142A772A99298528AC270D2616256727A128F22878290829CC27AF29A42AA32B9429A227FA25B525212596290A27DC277927FA26002A282BC32AFD2B792AD029972A252AD0284C29212620263927AC29843224303C2A8B2912283E275527F225912AF82BF22B122B34295A29F52A9B2A1E2BBD28002696272B29F229012A5E29772AEA2A142CEA281628532649265327142875289127F2277527B327532BB52CAD27292672276C27BE289429D227E7258425F2275A29832BA02DC52CE32ACC29462B3129B9267B26B62634289D2BD32CC533932E072B5A29922A342998284B27C929D52B6F2B612B4C29BF299E29E12B5229C62799264829272B972BE7296B2AD92A302BBC2C45289D267F251F268728BC28812663269C266F28522A072CF829C4279B264726AE259F28DA2A3D2ABB28C125FF27D927A22BC52CAA2BD62B022A4D29012A29289226E826F82A332D8D2C003617304B2AF529472BB52B6C28F5273329752C642BE4298A29A329282A7B2AB9297126D4270228462B752C2929822A4C288528252A09299C278326DF28CC28A628072829274C264E27EA28382BA12B7225EA25B625BD273A2BFA2C0A2A7E294B261627DB273D2BDA2BC32D952CE12A032B772ABF28592749289F2A982C022E6235E02FED2A7729362A232938281528C929632CAC2B3429912762278428F1277727ED257D256F277E296B2A46294D28D1267927D829CB26E6259D27A229292AD829D3281A2680259925FF265F27D42634255B24B525762997298C2B362CFD28F727D5265A27BB2AB7299A2BA62CE22BF22C6C2A662966282D27CE2AF12CB92CF7357330C52BCF298129DC28B126EA250429DE2BFF29282A71294C28012744280626B8238126652749280A2A772A2D2AFA281126A5272C277626EE2AC32A092BA72B4E2A0028F325532364266F26F524DB22C924CD25CD271D29812BD5297F2BA229B8264E266F280D2B922D4D2AD32BE12C882C852994273C28D02A142BEB2DC9365132C22BD12A7429E72842272A2779285528EB2998286E28AD2591266C27712511254E268C25B82830297729F127982680253425DE259C284F2AC92C4A2CA42A082B1028B8234722C4250A269D242724BD23DF2718274627E0275F27A62ABA2988277B24BD248A28AF2C7E2C292D142E762D2F2B01292927982881294D2BDF34C531F12B8B2C5D2A202910263526F4277128A629AB2B4729EA26B025C325B126E326C9263F26F3285C2A0B2B842AAF2940257E257625B927812A0E2AD42B442CE82A17289B259D249D252325E423F924FA227E28D92738272728F926DC261F2659246A243A278D26422B9C2D282EF12C392C362BE5280E277A29F82BCC2DA9352932542B1B2AFB2BDB2976272F268226AA28A929BF29BA29D027D9263D2868294A2915283E28FF27512A8A2A622A73274F259524682627278B28F628C1296E2BF929A3297127BE217C24DC22AE23F422142328264727D62871284E28C8293228022652254025FF258527C229802BD72B8E2A2F2B9E2925271028AF2ACC2CB033BE318E2A042AD02AB22ABB279527D0253328CF2ACE2AFF2879260127032B502C122B802B31297C29B8288429D02A06286B2410256D2638298128CA26D6277828D2289627392602236C235322F123FE2283233C26CC268727D628D326252AAB2A1B2ADB26FB244E2307270527DD28792BC52BC52ABE295A287926BB294F2D8B33A3300B2D022C942CA42B9327B627B625FF299E2B2228BC26DA270428DD297A2CD12B642CB62ABD2948294428332787269E248A251528532956281C28E42667275D28FA2802287E23C324D22332222E21032510278F27BF27F5264226002AA52B582BE5274B24BF253525D3249E260C28BC293C2B282A6026762516265628AE320030372D962C2D2BCE2A732766259B2664284B2AD32ACB287D273028DE2ADE2C632BE729C32B2A29B129C9270827F724692380269F25C628542A082B8928A1290F2BBF2C742AB824A223B1217B245421E4223F26B227542732280529722A322CBD2AB329CC2895242E2765261E289828BF2A1D283428CF26F0254D270A271132712EDE2BAA2A302B92298726B324C227272A0C2B802C492BB427C227562B1B2C3429B0297129CF29FF275925722465247E25C0272D28AA29332C3C2C202B622B562BFC2BAC2A7A267D23DA2380243623E023952571260229A627E12554298C2BF82DAC2998286726CB267226C828F229A328192A232A6C277F26CD2612293832FC2C4F2A8A29F029CB2864273B24B227F629512BC12ABA2AE928FE27A929EC2B252A232AEA29502B48289C2559272627B6284428AC28E229562AA82B572B012C3A2B542C972B262AF12624259425FC25D7244125F2263428ED26692593266728232CA82B62298329A7282128C2285A2A042C172C512B9C29512805277B28CB3173306A287926CF2742289525AC256125B927612CEB2BF52A2A288E25AB288429922A242D802A0C2B332810265126D3288629F6293029122733298429CF291A2CC72BAE2AB129172A0C288826072638254C25D8263C288D27BA27B62424256C27D829832A8C2A3F28F828C2273C28A72AC42A802B912ABE282B2958276C27ED32722E692928265E279A26E027F8255326DF27C129992CD829AA27D427F92612293D2A2E2D662C262B9927D2268B2894289C29282BE328B527F2297F2876299C28E82A192AE829C42AE8276726DE257F24AE24BA251227C12735278B247723C125E9280C2A332ABC293F29A7284B28102965277928C2275328BE28F627F6283832762DDF26B625C024BB27EB280E27E625A125EB276929BE299527F425E2268A287328462BEB2B6A2B9429F62719270328E92A9F290E29AF28FF282A29442838279C28D3288B28ED265C260E2934266F231C24D02666266528C7262F25042682260B263C27D4287929E627FD27CE26F027A0260F255F2504271D2608287929CB311E2D3527E3247627322A5D2B07280528C126C227A027E028A9274125512601272C274128272A072B35289527172770289B25C727C327012856295E295927AC28D72790255E2646259C25E027D52710248E25D6265B256B25F226E925D2252F25A6260D27D226D62678263328B9284A283D27062565253F25D12687265327A731592E7327B524B327D927B32B602A2028212779282C29B3291F295E254E267326D127DA28E529722A312BC229432B73299F276E273527522ABA2AE0295B271126302748274924F623672492264A2528242B26652436262526F829282CEF28A8269D2706281F2AA52816281B286E295A2B67282A263324A823B8274529FC298B33CD2FE4297227AC24D926A927FD2A18291226AC269628C8295C28C228C1280C2A672A90299729D02AE52A2E2CE42BF22AA22922283927852ACA2B97297428D226F5274F27E724452305242D267C26E22596262C260D257D26332AC92BF92A5127C927D327E126A42747285C28A526A6291C28D6268424EC23D9265529502C483573302A2A09289726DA269928512AB3288427E7272528512B872CDF2AE729A12A022AA32AD1281A27D527F728692E6C2B22278F24C3258B260529B629DC28A329092996273A267F238623EF2498272727FD271425C0244D2717298629832AC429D128B427A22785252E2738268527AA2AE929232944269C246A25F228362CD4332533322CD628C62645267E27822A3F2AEC2A8D295429372CE82BDA2C8A2BE12AEF29EB27932736264A284D282E282827D726062609243327F8261E279627C9297E2A002B08296A249725B1263928DA29EA29BD27932446254426A5273B27292A712AF028A927B1260326232645278C2ADB2BEB29D726F024B2251C27192AA8348432A82C7B286A27FA2598262929932B032AAA27E527E5294D2BD52CBE2BED280D28F2259F28E0266E26FF266D27332743256124B025C1254F24C025C826E0271F2A752BA1284F25952449287E28072AB829FD26C7245B25D5269D27B129CC2AA52AA8290E2AF82727284326FC275329AE2A642B09298F26FE244F281B2A6E355631B52CF428D42571260527BD284B2B792B9629B128642A1E2BFB29792A562AF12724272B28362801294D2C572AD32AD6282C26C6240F25AB251C27D9271F29D72BD72AC12978272524A325BA284B29412AD72761258726BF287127022970290E2B742C462AE928C8288E29812740284129232C35294D265D286A28CE2B4B359731D22B6F299928D926F425E827C628FF2917298127B828282A622A932A232AF0278E257028022AEB2B6D2D2C2C7C2AE4282B28412682240226B62600296F29E32AC12A0F2AD92765253E263828C627592733278526D9266F2ABE29D72866288E2A232B842BEA28D129762943279F27B627FF291F2A1A285F28122A562C86344F32C42C712BCF29882A9127EA25DD28AA2858295328A9290D2BF22952295D295E282E28FC29CD2C932B382C522EBF2B20298327EF25FA231125D525E827182B702BE72AC8295B27FC25F524A4250A266E269B26042585277F29112B5D2A372891282B29302A3C2AE92A7B2A3C2BD5292028DE27ED279F2587272D2A632A15341032D82B142C842A6E2992272326FD260C29B8294C286B289F28CF29F6297D28D2271D299229A72CE62B212C662C49298129DF272725A223FA239B2534277B29C82AF328642738267424A3237323A324712542267925FB266A2A0B2B4F299A2886286D2A3F2B522AA72B8A2B2A2B8F2A472A812852274E27E226AE287A2AF634A431572C4E2B102AD9297E27A12555258628F8272A283829042938273626082765260128B9285A2C832B5B2B342C88295C280629CD2661240A254423AF242826152934286524272374229523CD215223C5255C24862536265B2A3E2B5C29CE29B029BB2A3F2B292AFB2BCB2C6E2A2E2B912BAA28CE289A265527B929AE2C4035E52E832AA4275A28D327EA24D624E4240126AE261A2883270D289C25E9239824D82450262329452B832BEB2A8929B22927280B287B284B273B2624257224A3259A272A2791245A227A220D24F1222E214824EE251E25C8254829A728F02641283B2AAD2A762ACC28D2297E2A402B9E2B4A2B6E2939288F25A9263028AC2B8C35962F072A80291D27E4274825DC25D3250824B3259127A728AC287B27AB2695247524B124B42A432BE52BA32982296F2974284928072AB329FA260D23472252246C2693257F23AE231D238B22F124302340260D249A24C3260E29FD284827B8260F274028382A14292B2A232A692BB62A2F2C662B5B2ABC276C2643272E2CFE35D130942A3F29002B6429AA27DE233326272448250927712AED2A452A782AA8276A247725F6259A2B392C9D28C029162AD429052AA1298C290E28E124BF228E24E224AF25A6253623A022B72455248D23C9242123682441280C2ACD281C26ED27BF2779299B294728EE273527F628582C162A202AB829C225672588276F2C193612313B2B6F2C0F2B142C9429AF26D9257424A722DE243C27E42A3A2BFD2A8C2942257925CF258A29EF2A8129AE28DC25E124F6275828672832276B253C23E9237F266A2999279C250C26072461279125E625ED23D9238A25BD274F276826A9275F293429612A6128B128882673282F281D2A9F29872A81278B26802768292335D42F7E2C072C022D772AA72B5628AF24D5247024402539250827892970292028752738269026FF26E726DE273A27CF256625F326092798278C279124DE234A253A2612284228B126D726E32650272C273C2771266C2567261B28AF284028222A392CEB29ED285728AB2A662AEC2A9A2ABB2AD229632ADD284A270427672907359730942BFD2B9F2A302A2D295A28BA270B25E62249247824CF254024DF2589267325412739262A2686250A27942582275B26F826A6268628CB28D02677267E27E928C929B6296A293B277A288F29342A03274026CF2433261729D4285B29B829AB29C1280629C42A1B2D702BB92B2F2C892B5A29FC2897298F293D28E9264632642E6D2991289628EF271B2758266025E225C6224A2397244825CF252E2777285A2749260C258F24A924E224932616254F25EB262028CF272C28B026E025122784281A27D72731269B2886262E291629EC27D0268923832473278D2A4E29A5291E28A7251D26EC277D28A1288E2B0D2C232A2228AB266827A4284627C727F031FD2EF328C228EB26B326CC271B2708270226ED24C6254928202808285C2A242B242A10291D28E2242725DB231125D7264528D629892C4A29B1286C261D256E27B527BA26B6281D2883293F299329CE28FB27982533242E27402A882ADE2964290529802886252E27F8284128A6273B28EA26E025CA2529268928D728C029B832DD2E222762263C274228B529E029B4274E26C52490249F2787291C2A092B692B882A2A2A732AE927B72546240A2408279C27B6281D27F527F425AB248325D525E8269D25422773289529612A332A572A8B29ED2566245E27CA271A29E5286726D72717282A28B8272C28CF27F1262E280026F22441262827C128792B7D2A9133D52C27288F274D27E128DF2A7428F0274B2614256C268727C32B0C2C342D6E2B0F2BB92AA02BB929002880247225EA28C5261C29FD273E2752243A24DD24EB24C825B425EF246E259E271C298E292D29442A2F26AA24F4246A286B28472873294F287228B128B128832AD72AA0290D29A2277024AA25D923F327C52A1C2CC4342C2E452AB1260B29F129D12B1E2BF6277827592347240828702BBC2B3C2B432CFD287F29C92A082C29283825CA242327DC267F2782269126F8253024B2223124A7250C271A25C224562518278828BC278827DC26C024CF24C1288F282E29BB2720295026E9261E27B1294129042B8E28D428C524FD2414283329952B392C3A34622F192BF62884297D2B8C2CD32A14299927272506258027092BCB2858282E28B328FC29C729D32C2429FC254A2525245525A324182602257727BC230326EC25FB27E527DC27D9257627E22613282028BE263C25B024B223E327C527D1296228F627B0267727DB27A52A7A29CF2BF02A9128532509264428F92B8B2C5F2C173626318A2B23293E2AA72CAF2D3F2A64297B273625F5250127E628A52A772AFE287F28B529712AF62C60298D26192511260C25D625C1243D25ED26AF25D12377267D28C1263027F12771267129C62A8F28D6294928652488219825FE27ED2A7D286126422541266726AA29782B152B6C29D029F326C52740275F29FF2886290934FB2F202AF329B029422ACF2BD82C78294D28B925F524AA27432A672A112B36287627A128212BEF2BEC297829CB27AD25D8242E26132564251B27C6279725AD24632707289928C527DC28922AA12BA12A9B2927284125A122F12332264F294E28A425C425D825EE2577287429C129D42A8A28AD2724292B29962A932A0D2BAF35382EF927E12708280628702A182924284A27BA24DF24B72543289A28B427FE268026F227562B412CF628F726FA251C257823D22457231426E626C8248A25BE236424D7268B28FC2579280C2A8E299A2A3D2A5529F02491235324E6245E26682539257524AA241225B227CD27BF274E274E25DF25D828B5281A2B1A2AA12A4B33762FE4286C26D4283129D229F82AEA29702878237E235E26DE26242963283827DF278C289B292B2B6729A0285729372885246B2595244324A52545276826EC241F251026E5257E27FE28222A5F2BA02A432BB429782637231A2321246224682695256024782433268027B727D5261D28F524AE253F27B128DF29FB2A612C1F35CC2E772AE0294D27C32711290129382832265A25A02373253E250E288D27FB28B927D1284B2A1F2916294128232A392905286C271E24CB245B25FA243A256223A823B2220025C02601280429042A3329B92841271524C4248C239422AF23F124D426B9240F2669286F2968272326B224652549265725D2271629F929B62AE0357B312A2C06293027FE26A0272729812872269224BD224623BE23FD2560289B25BD279829A92ABD2A872ABB29552AE029262B872ACA288D249025EC245B272A271925612359247223332735296129FF27DD27A2271D26E4240523C8223E23DA255C265C26C6263F28F82A8F282B2702287E252E262027E3254427502BE32B6C36AC2F852B5E2811264726A1273A27B9291025A523F0220A2312231B2676273E271628D02AA62AC82BEE28D927A128C129ED29562BD9291A264B26C6251E282328B1261324DD223322E624C2276828A82766264A2870274B25DD2227236123E4243A267F25BD25ED267A2A7E27E226B625C225C72701284327A428D328922A5C34712F52290228E127AA251327052804297D279623B0249C23BC2265259E2762294C2B2A2A722C0E2D782AC32741281F299A2795297729C426E6244B24EB265F27142820269A25BE224C239A25782794263627752AAE283E26FF25FC23B524FB24C6237523E3247726D828C728AB26C927A528022716280C286127C627E728E3314F2F4C2B27286526802738266029222A4229FC26DA230B23A324AD24EB25082B262C822B5A2B092DAA29092742270A2831271B28D0295429DC24012573253026DF296D29F02546227E251724DA252E257928362ABE299728C326FD22CB25FD22CA256925302515254528B82864296E2ABD28C326AB2877295B2B512A552B3335D62F4B29E026A1254027BD2525297029FC282526782464229B22AC22D1259D287529B8298E28B9292A295927AD261028412814289228CE24B4249F221C253725902676265A26B824F12174255B240E243C269828282766282526EA236222D9237F23CC22732465231C288729B8299628B527762777290F2BFF2AE32AF32A4B35512DD0271F27F9233E240525CA27C52878297B26EF23EE2243221A250C270127392AA0292029922966292F279E26BF25A526582828273725F7255C247A23372393245A266824FB22A4218C230F22BB2376258F2666257426FD268324F62346215C2398237323632510273C2873274428AE25A726A9286727082AC12ACC2B3633702C09273725412490230F2532279328542844252224B2235322AE227125B6288F2965288626DE26E6268C25CC2426250A26BC253D25142629230224B722A6235C236C2377245822A2215423DA23E2234D2472234F24232563250B259E2297244A23F520A82278254228CF26A826D925AF240D2540283828192A122B852A9832152C6327182395221B22AD229F250426D12624241D24C5207821CF219C2371259C270527EF26AA25EC259122F123EB263626FF2575256C247024B722EF2413260C240523F723AB20D321ED222724EF25CD2500256325B32357265F24B72251216C23CF21F5206D223E27F628DF26122697238F258128FF28AF29512B8A2B6433992C5A26E42468230D24492422243F25C0266924572478213E226F21F32281231B244D26C6250F25F7223E2263233B256225F6247D2436262B251724FB244826A0264F255523AF212423B32369252727D42642262B237B24A725CF247922A922712277217E22152470272727ED26E9267927BB2404279227E3288628032BF734072CF6246723CB237823D5225823BE252824C32452231C22A82182208C216D232C249E2329265626FE249722D624A824EB242126032755262B256A23A423282715289C276E239622F420A123BF235526F52719270424A323B225152445247623232208222422DF23212686287A29672622262527A127DD279028E829F92A6232352CAA252B226D230024ED228D24CC2470257F261725C821D6218621C4226D230624F224CD24BF243125EE22632522239D259B2620245F260424A0237223E72621283827A625EC236721B923AF24F925742AF8299E2477251E256F263B264C2640237D206923AA2366249B2782276F2717275A282529C026FD277727D9295932882BDF25A222E62179237E237223D5255324282420231E222F20662033222924DB22DC23DD25BF22A62419249D24F723F7251C274A251725BC23AA23B2227625A22606256E25B72287211C2301248024CD28C027DC2516230826BB258229DD251D231B22FC21D32137254B24EA2712292E2904283B28BE274327922496267C316E2CAF25292290232123BC239423AD2575253524FD238323B2210620A4221A237524BE24F7249522AC248823B02412246B2468278A253623B42302259E221A232524ED23C6245F22D020B422FD22C6237128D328F624C7233723B223F9245624E123C82190210321E223F62428279B294929E52901295827B52687276427EC329C2C6425BC2324212824E4249F235A245E250325F3259C2303223121E022CE21E7227A2592244B23EC23C8223024F3233724EC266326682416249421AA213E2216224D2367223922F421F420B421CF249326A526C125B02171209E223E237824CD225E227C21E72025239523E325CA299729F22BB82A772873268727A627AE30 ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 D32817234C233221D021412156204120D020F81F561F291F3D1FB91E7C20151FC91DC31F7D1FA31D2A1FA91E5520DD1E371FAC1EC11FF61F631F4F1FFF20A81FDC1DDE1E481E401C131DF71EA61E131F801EF81F9D1E4E1E2D1F831ED21D321F42201C209D1F911D0F1F791E4B1D1220081E02212620C41FD41EF3213723262E6E2CC324922191233823B121C521332248223D209A21A320CF1F8D203720B01F1E1F2B1F131FED1E251F47209C20DE213F1F3221B31FC1200A20F92062218E1F8F1FB720C91F3F20FD1E56217D1F6D1F6A2196200B1FFA1E931FD621C620E21F39202D20DA20681F43208320C21FE61FAB1F6C21FA21A9217F227F22BC24092E3E2CD625A02498237522D7212D223D23D2207E23E922152352217220B7201B21B82041216F20201F0D1F352165205B207E21FF21D220112170213D1E7620E6215B21F2212121B02191208F212E20E81F4F20DF20721FAF204221C91ED220112195210F217520211FA1209920F420B21F32207B207023612161225D229A25A12FE92C3D293B26F9224F23DD22B12311221121DC2002219F205E21A920CC21761FA42091206020F321921FEA1F151FF22001212022AD21702207212420CB1E77203422CF21942240205B204521FE1F541F3D202D2110218F211D2106211C224222DC22472134211220D51F541F3F1FD91FDF207F2121225423A1211E23B3246F2EDB2DD727B8239722D0222C233E22492227224D212C2150211F20C71F6121E820841FEF20242029200A2028205122D31EFF1F7C232F21861E9B2148213120502012227F22DD211420E0208120BB1F33210320DF215E20CE20D321CA22692117216722B7216722FA1FE9200120C420762034214921C2219B208B211923B923432D362C632774244A254822AE23A12187218822B5210E22A5227120BA20DF203A215321D5203920F0215920E11F24210A2245203D22B921AA21C721CF215721F221DF215222AC212B20D121F11FB9204B2004218C2134228222BF21BD22EC2113221A23C322D6201721062161214221D9210021F221A423CD22CB21172457252E2EC62CEF25B124FF23F0226E225F23F421A821AF22242228217021D9207B225522CF227621E021F2200523D1226021F92174200E218F22CF22E122F1215E239922DD215722B921E8209520BE202620D11FF12103248D22C8224E23BD235122EC2281234F210B223B2130218421A821072289230A229C23CE210E23CE236024842F692D6827AE242A25E822C92034210D22B0217922BB202F219E22D3235C217A219522F921A222FE228722052137229424B7212722A9223A22CE22EC22D72120219C212B226E22FD20F820D8228122E31FBC234223B62276225723A9212A23C422EF227022B5219621782243224F22A1237F2371232F232D22B1241B241A269130552B0A27A1242023E7221E21C01FBA21B32202226321EC201D21E320CC21D11F8F20CD212F225A223B22F7203F20F0221122C823D221D1207020BF218720A920B42191220A22A421D1201320661F8D206D220622AB230022E724ED22292230228322F720A3228C22DE2383221322F72323258723CB23F9222823F6242125DB30992D9D246322F4212222F120D7217A21D9224521B1222E2294209E2105229B2138225021372205225C2237233B2264242823AA256F247F211F238C20692084212F22D623E822382340213A22F721B720B0221524DB234123DE226423EC21A5228A255822E720CF2289239524BF2573258F2564265D25A6246923CE251827C533642B8B2716248022F0228D21E521762112223C228F2388227B229120F7214C224122C7216522CF226D21FF23DA231B26A4231A235B2289217E21E020D52060216B2424247F24A424EF2118214A22192103235923EB23F523D724E0236B2379243F23E0217121A522872402241824D4263126E72431249E22A0248D260E2867343D2CB625CB2280240E22B320B2210A211D235823EB22CB226821E821F32143238B226E225922B225A82377267E247025D8242524B9230422BC20AD200C238A2322240826C324DC2479231122F4227A232226352679276027E32609250724B724BE2357233124E6226A26CC270A2886299428E1252024F323752473260E2BBC348D2C0C273A237722F921A621E921D9209A2276221422582487227124E823FF241724122385212E2423242225CE245A277A256C240B238821DC21AF231E24B626F5254E276227B12461228922CD244224002680293C29C528E7286E271E25D8251023A5227D21DF2249266B286529C72A57286D256B262E24D9258A28DA2BD932B32B652694231F24DC240B2264225E231E24242452231024E523D023FC25F2236C25912409239723102475241525D525D925F3248822A12143245623B624F624C7279F279A26A524B123CE225D2425241329412B822A1829DD269626F1259B252625B2211C231D244F284F273B278A283628992760258724122746296F2C5D366D2B32261925C12310254E23C82497223425F622AB252027D824A625E1250727C024D025BE251623D62250237924F525FF25F9233E2246234E23AF232E25EC253928122857277B254523F6214322572405267228AA285626D425F7252B24A1231A235224D3250927E629652A81298F2961293026C8253023B725A429FF2BA834702DE027A224AF23F7248525A724942430233325FD2648277D266E285A29672A65278E2615249123C425B326AB24B2256E24EE248A24E022D7222224BD246E25692785272327A924F521A9242E237B2444276524F72448252B26BD257F25CF24AE240A239A262D28C82A052C54282628212676259B2482252926DF28CA2B8D342F2B7827162644265824CC2499245424E323E92458285E29D829802AA52A442A7B28EE247A24202471269A253B2792284927C1269A2493211923B224C2255F27AF28522AE529E425D6219E20A5222F251C26AB259A244D2699299F28E226EC254E247523D62551268827FB26EE2505230C253D242524B7255F2741295F2CA734132D1C274426F123BC25C12660253F25232690274F291C2B7D2BF82BD3295E29DF266D25B925F2246C261729AD295D2A9B27CD26BC242523C1233124A727DE28962B9D2A0F281F2436248523D7232025FC2668285426E324A629312848254523ED24BB22A8249F231E2674245027B725DF257B24AB2322259227F528972ACF353E2C062ABB2601271B277527DE275026BE26AB28332C6E2BAE2BAB2B412CF028482780275C250729FC290A2A2D2CF32B6D274A260724EA23FC2369253429162BA82BFF2A852971245024AC2367250F25A828312797259D2466246123ED22212363230F25C926192451267525E424952407250B24D523C82470287128502A6C349A2F8929A02821280D27FA26DE250C27E72649290F2C442D712C032A942C852A252820247D272F293B29F629F429602989281D25C721202164261F26C7299729A12A322B9C286D254D23F4220A238B2525279F26F0238E22E323DC216F22CC2304266C260A27B1274229A42612261328FB258B2513260B26792750290D2A443458301A2C2C2CBA2AD7283D270A253E267C280D2B272E522C592AA429F5281728B825762963294E29BF29672B252AC72885276A241624B523272597277928242A472A382A992733255E2203228825DA2301262A26DC2453230D21A7224C22C3236B26BF264C288C289F2A3D2A5629232B9327A027422AC527F428CC2865285A32B830BB2CFB2D132B2D294228CE26772681289F296029202B8D295629D7265B26B0277227242CE82A0A2BD929122AB028A62523251923E124A727332779282527D127B927EA2565249E23C323F9237025982601264D2345234322A32234223A246627F629FD29582A452BAD2910297F262025FB276327B6287C27EC25DD266C303830732C832B792C0A2C7A2AB52863265A278B276E28A5277C269624DD264A267228EB291C2CA629A3284F276527F026FE24BA240D24DA269F28F0264527AC262325C325B424B6237223AE275E276C26AF2800289426BF23A723F922FD231D27EB29F02B1F2D272A432B0F2BD3276025AF246024712561254D244524DC240630C52FE52AD02BE02B662C19295A288F278A258A242A250F2620238C249B27DE27FA29BB2C1F2B902AD62882271628ED2705267424E92488285F29FE26C0262426FB253C26832379219225D127FE29142BDF2B8F2A4A2A00277C245E23CE234F284828F129332A11291F2811256624DD248824CC22622340230324EF2295251630482F9F296929EE2A332C372A9F27F0254027A925402721259A236124BE251F29C22A572B302BD52B9B27A8250327CF25C124FB24E826F8279A27F32636255526A025BF25D224E9248B266E28562B0C2B612B9C2BAA2A8E272E25BB22B6230A26892942284326D725F923AE2206224B244E23F921A3221D231325C425B5245C2F872EA52980290E2C702A7829EF27D0262727FD254A265925DB23BF259028E12A922D9D2ABE2A2C290328C527C8245A25A72440267E286F28D429B0287C28F627D9278A26E325A12571251929C32AD8293A2C042B44281F24C2244922CE220926B725602511254122BD232822AC2297238923DA214822CA228024E824C2279C312A30942B162A4529072A2F29D92763272F27AC26F3268E2566235E2567272729CA2AB92A7F27A5270326DF24032451258824BE25D7283C27EE276F27E92804280628AC269426E823DA267C26CF27002914289028D325E1220A226E235D224C25FA23AF223E23732270224521C7218A224F22AC224924FA245B25642776280033B030E32D392ADB2AB7298B29EB2834281C27A3258C260624B8268F24A826A427C426C32742267A2690250F256424942453259C266D264D27F92670273B28BC281E28CB2607252723F924AA24E9262B26D026812571234F2239216322E521AF22F5244A23BB227B23392378221A222D2247239023F62589265128D228E62B7A35DD31342D1A2DCA2B502A1229B92876275627A025C523CD24D82354263026F62759289F26DC26E525DE257C253624A123B6242228A727C226C2271E290429122A23298E2657253123612464257E2447254926F9233A239A2136235C2137233625C024F524D5230025DA233B2321230825EB24EA27C4288B27E327642A562B56342633112E022AC82960293A2C292A94287D276D24E225352482245D243226A5272E2843275C271829DE255A25762389256D241D27E7286A28E0285F29FE297E29F426D224C8247124472493253D255B254925D92337247C21B8230F24A6254E26D726572769273E266F255E2422233224BB254F28FA2A64294A28D1286E28EC32FD31242C8E2A3229812A802A9E2A682AA4270B2727239524B7233F250025EF235225C4250B27E626A6244623CD24BC242B25C327772A4729832A2A2B5C2A1828FF24942492247F241B253424B724B1235B23FF2439218322B5240027D52632277D2625294429ED25EC2621269E26A8265A27AE28992A4B2ABF2A6C290C286F306131D32D4129092AEA2A70299D2AF928CB28E1275327AB255524202692281F288C250826932654271A24F8232923D62278253A29802A9E2A482B52293B2A1E272D271425C625F423DD2440261925842254232D24E321AF2359264128BD29B628EE283B299E286E28D9265024F024B2267B286F2BD02AAD2A2C2982291029D1301D30D6290F28DB26A12898293B2CC32A46288F267825D8246D2621279127D126BC26E8244F27DC26B1257924E4238D230126B029F02AC92B222B462A1927E3259E2455254325A2245A236D269A25532593256C253624972487276229772B1F299C292E2A122AB6280D28F725C3258727F229B02AFD2B722ACB2A73292B280631DB2FC92A502888286B28512BCD2A4F2ADE28E6259B24F3255327402995296228B7254D2704268D26022754246E261626E8277529262AD6278D28E728D22554248125402517240023E024FD23CE25FA258827832615237B25B528D0291D2BCF2995299E2A172BF129A72703244C24B0260E2A402BFC29D02AE02A0D29F026D131C2301F2B43297C2ABC2C192B502C282926293A26B426DC27EE2A392BA72BDA29A3280427572616263428B2260927E0290B2A8A29D52906271B26A7264825B4240E247426312439235225EA268F2746267E274B26BD24F5269E28212B2D2DA229162B3B2A5929E8264A253A2528256227DF2786293D2C3C2BFE296E29B427B83145308B2C092DF62BC32D822C2B2B4D288026E1263829B12C0C2D6D2CED2B2D2B172B98289525B5261C2503264E29AC2A53293529B529A026C025B425C42363243F24BF25DB27C5243F25152A992BB128D6261528552796266D2A322D612CE42BEA29C4291F2AE328DD269D24F1226025772742294D2B5A2A20296328352808347F32C12D092EBC2DB62DB42A992826276E26F928DD2C092DC62C2D2BF62BFF2BCE2BA62A39278E263C254A2508264929BA28BA27D72908287A265826D2235E251D26B828D32804272D27A52A592B912A712A46283926C026B8292929B429B328022AF72673272D275D2423243C2555272C282829C82AC22970290D2834292E345A32B82D922C4A2CE32C102BFC29D128FF27A529612DD22BBB2A632D552BDB2A7B2C4B2913276125C925EE22A02591278B26C225BC265926F425AB24F723B526DD27D229922A22298529BC29FB2AF229D3295C263C2610258225E0261726062547254B25E523C2221025562454274529592AAB28EF29F8273E262727242ADA353C32972C712B182C882B3E2A6129B527A129FB28E42A302D3D2CCD2BF72B752B1A2DA92937265225A8249626E228EB26E727082661248F258E235C23ED24C72560288729792A062819285C293829E728EA27F223E423F0239624A2235C243A25D8241B2446230B2306243E269928682AC62A8B2943293B24B225F8267F299E32B6317E2BC82A192AD829422A6729882769261327482A612C652AD828A6284029E12822285A25A12400279A27F529572B3A289B25CB23C523812290229524C724A326D526AD26D926D128B7294429222796252E244923E022C5252024F823AE2453256B257D25A6244F26D32598271029FD294028F8268A24E424EF254C28D731D1316A2D752AB72B0B2CB12BEE29C9276027F326F4261928DF28CF296A2A8D29442A28283623612624267B29482C942BEB29E3273F239822A3241A227C244B262F26C924A924A8255B279429E227BD25C825EE245A256D254926BC250527032953286628A927E7269427C826A7264D279D266025F7230E23B9237B240F2948325332B02B1E29F82A87293A29002837272B263C26A528062AAC29E728C929872960282627E8254D2547275629BC2C9A2DA72B4127E8231422F622802481258A278E25232557267A2318254B271427C7246A241E265728862ABA2BAD28DA27E928452C052BB72838275D270625E2254D26F0254B25F225CE239A250728BF29A6327F320D2CBA2BD72A782DE4277028A627DA255E261A28512A672AF0294B2BA72992283B26E425FF240C266628232AD92CDE2A52272224F42300242D251E28F428AD27B7256F26A5249624EF232424DD236325B626772AF4296F2AC9285428BD28C62A342B2E286225832509258C25372787278128592810285127E226462B5E3478303D2B442BC02C282D292D222ABB290328AA278C29B22BC62A2A2B4C28DF26382513277526BE25D924A527B42A772CE1281E294326CD2273261B27E628852B0D2B102A1B28A2230123EF222F245E238625F1278D298F2A982AE4282828BE2A3B2A612822261824482441249625F928EF2A6F2BA32B5828ED256128292C8235E42FB42A032B492CFC2DC12D992A4D29D9298A270F2801294127E825F3266E256D24EA26AD2690270C291B29BC2A452B78280025D4232C25C626C8283C2A8D291329122A59290825B92364234622722422258D295F29EC2A53284028E127C7286D29132806263D2481259C23C92595297C2A7B2BAD2B3D29C728C3283C2A9E333A2F6D296C29AB2B2C2D982C1B2C132C6F2A7F297627B4268E268126D7255524EF241B28832AB72C9929AC29372B6E2AC729EB26C524FC258E28C72667297B28F3284C2AE82AE5273924AB2183239323312541282528A329872BFB273029572A9F28FB2535256923F826AB268D26C229182B852B032D5C2AB129E32A572AF632872E012B3C2AB42A202C732CC22CF82BF62AEA270F263B244F237A240225DC246D26DF2A852A6C2B632A2E29352A672B9E28F225C025FD28312ADF294D2AE729012A7729142ABE28E92446235824EC229824E6257829292B2D29E9292629DA276A259F2517236C248B2789267C26762A732B012BB62CE429822816273C28473291300A2C122C972B98297B2A0F2984299A2A60291B26E124C52394247424AF25D8277F28302A7C2B3B2A942AC42CF92A67276026DC278129592A702A2429D1272F286428802943277C2484236F220D23C224B4273728FD285629E127562676267A25B125A3251126F2273F2703281029D729A72BD52B53291E270E265D27A332ED32882F5F2DF12B0D2ABF29A828622787280128C92702259B23F023E7258A25432998270429ED281229F22B942B802BC628A22666268F285C29D2262126B42604280C2835293026AC24E922862334246F263D2945286128A7286D2624242E2572243323B4254927A92971299D28672A592C682B7B298827C82630273D2A253495327E2F362DF92B2F2B4E29E82608285C2A4B29F2263D258523A824B82626292A288E284829782B772C1C2B8E29822609265027F927E628C5265D24E5242126FC2739286527C82509245C241325AA261C28982A3A2AC927A127F3267024AD22BD211526CB26DA29052B1C2A7729012B152CEB2B4529B4255C26BC26EB29E0354B33CD2E9A2DCC2ABF2AE12AC32C512B4B2A9E2789263E25D125FB25E5278B27362A262E602B782D8E2ABB2ABC274E2618239E23BE26DA2604260B260426FF253D268C273626752592252725CC253B27362A132A622A9B2A9C2A7E2A80265925B324E627FF28A42A0F2CD52ABC2A2A2C3E2B3729CE2781254A28ED26502B51348933782FED2CCF2A162AFA2B8C2BB8298329FE270A271C257B262B29AC2A7B2AC529482B4A2BC92D7129332721269525E3228E26242720287A280825A326DB2735297F2A6527E3256F2672286527302644278A28DC2747289629352A2528DA24AE249727F429082AB52D592B4D2ABB2A392AE9288125F22302267429B32B2A35AE31252CDC2CF229F22A4D2A7028BF2554278727B92625270E2A262BC62CA62B8E2AE72B7829B32A90283824FD23F022E024E424C8284628CA2762256C270D288028F52876270E27A5282E28B5278B253D24CA240424ED26902ACE29EB2651248223BD25E727D729E7292E29852AF52A5D28D025922699245F275929222CD93793321A2AA6297529CC2A1929E0263E2782263F265E281328A628932A0E2C122DC3294B2A062AB628D823702375234B24222597274928CF277A258C259827152835290E2808268426D226A427AA25DA230B2589240A24D6268D26342790239A22892441245326AE29312CEB29D42BEA2D3B2ABE2669263E250F29212C302E5F36A130612B5A29262C992D4F2B47281927E9253728532AC22BA228D32AF1295629F5279126F1261A265E26132323240F248D2392262F2A5B2637259925ED257E25FE259325FC24A4261C2678254F252424F825A5270126B7251325922544235A232B25152567279529752B912A842A022C192AE927EF27C4268029472DFC2C9A34E9316B2C4C2D8C2DD32B942C1429A628E2297729BB2A442BEA2A20285B274E261929CE2871289429942701260624A725692525273626B926F024C4259526B524C124A2263625B727B92798272F2578252528742919287026A124CC24D6244B24FC2496255F28DA266C2A3C2A5229B22BFB299D274528C326E3278C2BEB2D5E359730E22CEF2CC62D9D2B732B472AFF2B1F290F287B2A6827CE27B52651285228CC2AC32AFE29EC29F129B824EE25D4255429D2293A287C25C9246825D4269E259B24B026F7264C29D62A542A9D2BC4298F2AAE2C8C2AFE279826D5253A26A726E9254E25BC26CC2734281F297D2B632A82267922AD25D42488277228922A63340F327E2BA32B232BD92B4A2AB42C952A022A442A3129E9256325EE25C628A029E52A782A9B29792AFF2760255A246927AC29D5298A296A2733262A26772609255C25CE26F0274D29C22A382A292C602A602C742C722B4C27F226A625882749294028A026BB2715264C2AE32A942A0D283924B62463258C259B284B27E028D0321631FC2B202B2B2A832A112C342C612BEB29A7286E27BE25A126B32586292F2B902A372AFB2AFB2A3728822578273429592A2B2ADA2A392864295429F0287A261B2503281D2BE72A242C8A2C712B422A312B642A89285026EF240E267B2898289727E226AD27FE27802BCB2BE62A7328752355256624AF24D5271A28882AD33687310B2CD42C8A2B732C572D1F2C4F2A062964264B267F24A8252A28132B4B2BBD2B0C2C892BD92A892758268F27A12B2E2F9C2C1129F0261429E22A2229B728EA27892B452CCD2C6E2C672CEF2B222BE62A0D28E9270425F724BF2539261B28FB263025792751271C2BE7293B26D3267325EF247624D325B427CF2A212E49370432842D032DD12C0C2DBE2D622BF72A6228B9254226CB257027892717298F2CAB2C802CFB2BD929D92736285429D52CBC2C212BF0291B298427422A8E274D262F29CE2CC52CF52B9F2BFF2A822A1E2ABA29522887243125D923BC24FA26AF265326E9246C25A026CE2842272E2644263A26CE258125FF233127132B9B2E1037E2300B2EAD2B1D2C792BC22BA32C292BF129AA263126E425EB28502A4D2B81292C2B062BC32A1B291126B6281B2AA02B342B142BD6279025D5240026C9259C261A2A2C2CDE2CC22B57295E29D42BA9298F28B925112573251128DA26CD262626CE26B8264E2794252826722561267A288F277326D926F626A62889292C2D653515318A2DB52DFF290D2C632D012DB92A0C297F277327D628FD29192CB929EC2A042ABA2ACE283928A52552296D2AD62BFE29F92AED26CF23E8238D24D2247826DE273F29F82B97277C27DB28522B3429922890268D246226872BE629E829D1297629B0275525F8253B2651270729D6295429C925CD2939274A29CE2D392ECB352932412BCD2AE629B82CD62FB02DCF2B1D2AC327C728C52A942CA22B622AA627A22A612CD429F526F228D32A122A2F2B782A0029F1283A256223C522F5243D26CF277728F8264C260A260828562A5128252788274C27F728B92B982CCC2A742B962801278424E224E9284229BB2A682EA72A2D2890282028B829902E872CF236CD31412D3F29122A312D7D2D262EBF2B5D2A63292728E129FE2A482A6E29032AE92A442C7A2ABC296F291C2CF62BD828E2270F2A03293226E3245924B625D3271829ED283426A524CC2611291328A8279128CB273B2AF52ADB2CA42ACD2A852AC429FE242A241628A72A5D2B382B6E2DCE2C0A2D7E29DB289629092D1C2EAE36FB31DA2D412B542C4F2B922D1D2EC02B632914261A2A2929322BAC281A2896275D2BB82BB32B47291A28AE285F275A294A290B2A932A7B266825B9250026E028D82AE92AD0275B268929F028AA260A252D27B8296F2B1C2BE12AAF2A132B7229632957260A2522265F282D2A152B7D2D262CD12B0D2A3A2909297A2A7C2C2F354D30E42D522B9C2A162D352CA5295D2A9826B6265C286528D929ED272228C8271329F52A34295D2996275A268028E228D0271628B7261B260025A125D727F129AD2BE52BF72B532AE627472741267A240B26D82AE6289829982CAE2C9F2BDA29F525F6239024FB23D0287728572A5F2C9D2B3D2A0629F3264527372A8D2B0334B531FA2D2D2DB92CA22BC82A52280A28B92510264729D22CB72955297A286428FD29A22A6F285729A628DB25FE28F427CA280F294228C12469252E281D297729412C5B2C742BB4297628CD26F726E728A92A562B192B582B1C2BD02A722BE527FC258F2642254425C3266727AF2BB32A2A29B428FD28F7264A27482A6F2BF3313832492DFB2C032B1B2BF32A2C28B225D425C22597278E287729B3291029E92A952A6D2BB329EF2A8C29F0272E28362BFB2905299D26C0258027B1288D29CE28B62A3E2B74299B29C2273C25F0279928212BE62CCF29932BD12A2C29072BEC29A9282B27AA25DA278927412A9929BE2830272127BE26D328742B8A2B932A6E32AD309F2C5F2B332AF02AC22ACF271524BE2551256D27722989295F29FA2A4F29D72A7C2DA52AD8289F278E265C29B42B522C0F2B502AC9270229722AA12A9A2A062ABC293A29DD2434259127A929DC29672CAF2BA42AC928832AC129A929992AE9285C2769286F29EA2A9E299229D5298527BB288729112BCD2B292C922B54325130172BBB2A7E2A0E2AEF2999272D26C6265727CE275A2B2C29B2289F2A832A972C202B6C2A932896263827EA28992B822C7A2CC82B3829F62AD02AE32A0C29FC287E26E5251E23BB24C1267D29372A062C262B1F2BD4284529B0261827982793261926A6274F299A2B5E2A112B5829F1271C296B29B62AB82A152B3D2B30345E326A2AD4281A29D629982A4C270926822732282B29EC2C662A96298129322B222BC42A91296226E6252C2680292A2C712C152C082BDD2AF62A482BD5283828512900277826BC22E72459279A279D27E8271D29E9261B27AB245626EA232A241F25DF234D27FC285929FE28022833286629152AC32A9D2BA92C872AE22BA735A0305729FD267F27BF29A82AF329E927AD26C927A42BB42C0B2BA327CF27302A382A81290329162705245424C0254B295B2AF92B092B762A0E2B7529192A132B0528F1253B25ED238326E325F624C524A2260F26FF26CC251525C7221E2392225623AF23CC24C22723290129E5272C295528BC29512C932BD42CE92A102C4B363F30D82AD327C329962A342A7E2BAB285B2718292B2BAC2C4A2AA129D7289E29C72BB22BA6280C263D23AA27D626A5282428F02A642AAB2A042B182A732789264B25DD239D25DE247F25CE267825F624A625BE27EB2860272326C9240E2483242A258424B82616298E2BC729CD28832730290D2B2E2D272BEB2B282A902BE536C531832C172CF12B8D2A4D29D7284926AB278E28F42BE72B2C2A052AAC270A2AB92B1C2A3F28272779250F266D29932A48285327B626B227C227CE24E32522253625F42463275D265126C326D8250826C827652942291A2733288F26582406256B241627BA27CD28D62CC82A442B5E286F260C2A5C2DDA2BD92ABA293B2B27352831252C3D2B90290E2AEA27CE24122616282729992BC82AFB2937298D2985299A2905291C2886284F277C29C12A622A092698261B27CF26F7277D25B2254E2577254F26C727A928892643265F28CB283B29392CD429C828F528AF2880287D263126F725AD287B29B12C592CAC2A8C290326CE27232B252A9729A02A3B2D5D3691300F2CD8283127D126D925B02577281C2A8C2B9E2BAE2A4F292F292929C62A7228E927F5268927C529A72CBC2BDC270C26C7257B2781280A283A281A260327DC28DB26E028F4270E2689251A28CE296E2CD52CE529D12A9F2A212A492CCC2BB62AE828C0286A2ACA2BC22AD529EF2AA5278C268E268C289C27FC28A32CCF358E31E12A0A296C26872593250126E2277F2C8B2C2A2CD8297129442BD92C002D312BDF28B128AA293F2B3D2BDB287926C5243E277E29CE29A62A3D290C2BE02AC32A27297327312576241E26E327C327612B7F2B842A8C2A5F2B262D902CDC2CF42A192C572C56280929F428AB27D12956276126B025A323B4255A298E2B3C352230232CB72A8C292D27D42504271729552B482DB829C8280729CB2A782C442CC12AFF272628FD29FF2AFB2AF927C125AD255B281029A228DA2A5E2AB72A192972288B287E270425A124BA274C263E29402BE12B08296E29752C372DF82C0E2C7A2C7F2DCB29FE29F527EB27D9279329EA280C287C26BD25B727B129262BC133AA30082C6D2D8B2AE22847272E26322AE92CD02B0E2A4E2873283829CD29B32CF42641278A288E2955293E263226D92537241B266B26E928152AF929822B3A2A0229E32605250725C3254C2612275727852868295D29312B7A2C422D912C662A152A5D2B732AD5295D2A512811290B2B2F2A4328D4255D2507279628BF29C1334230FF2C2E2C122C88290D27722630299B2A6A2C6A2B3D2A082886282E28512BF828402728275B28A627FA256725F628462636282C28D4275D29452B7329D929D3280B2704264227E42790287E29A328982760280B297C2A662B6B29B5295C291629302BC1295C2A122BC829B42BAE2AA028F227BF26552444268E269029B4321E31612DDF2BA22B8D29A2279C258B27ED29392C092D162D112CBA29972A262906274727F927742875283A2788271A28FB2A9A2B202A322AF92BD52A7929152A542841250B25792640287F28D12909294F2A0A2ABE29E427E32719278D262C29E2298B29A529CD2A652B792C7D2C0A2CFA29DC279D272627BA289228BE29CC33D430B92CFE2C692BE32948282B24B424E226F229682C3E2C5D2B292A392B5B293B299C29F329BF2827285825DF25F828C728402A8B2AF3282C2C782B5D2BD8273B261D266B288B28CD28FF27C229592A702BF92B69291C25EA282D26AE270D289927572977298E29AC2B202C2D2CD42AD527822798274D296729482944294231D930502C6429402A632A8228E2252F246B266629292BFE2A092A902ACA2A1C2A5528382AA32A1C2B3E290D260427FE28672A972A272ABA28982B832C342C7C2991278A28F42A952B862AF927CF29832A342BEC2B3B283327B52611287B28F3275827BC27A5278E29A62BD82B572B2829C326892786287E29522CA72B922A4F321033DA2AB329E828C72766264E24692585249B28832A6F2AF0295C2B9B2B8729FC287E29632C8E2B5C29A226AE28222AE32BBF28A1271226372A6F2AAE298D289B27E1294A2AF52BD62AD0293629CF2AF42DDD2A41292E264E2847295329AA299627D5260226EB28622B502A342AB827C526272761284F29522DD62B7B2B6734A731D02C3529DA273027E526D6245324B42461252B29FC27472BB62BFF29A52AA529812ACB2AA22B7627DF254B29B72AAA2A6B28AA26D527CD27D027BE288B27A426802850291C29D42991289E285D29E22A022BFE28A625B02A152BB22D982CC328D226BB255127BD2A872A0F289F25DE2442268F2BDA2A982B592B3C2C8332F832212DFE2AAD29F22A622BA4277E274025E025E6271729F62AF92B602A4B2B952ACE29A42A96286B26CA2665281B2A5F291C29112787283628B127062711266C268D274829C727A3261E29632A41284029902BB2297229B42ABF2AA62B152B542A60276A26DB28D7292029F3269526C324F5240B28AA29442B8F2D1A2DCB334B30272CB028CC298E2B512C9329CB27A3243825FB27F428492B172BF52B3E2A332ABE29132ABE27E7256D257728E7294229422986258C26C72529255E25C324E9232F26EA278C29AF2A612A6628B3269F27D8275826AD28B32AB42B592CD62A312AE02589261927DF27F427032566241126D126ED27FC27122AD52B4D2BC2343E313C2A8B28BA28212CD22B1F2A312711263E252726B228D72A7F2CE12B2C2BAD28312AE428F127F32506243E288C2745285B281E27B2264326E0268B24D6234025F32698281E2A452B362C572BAC251727E926FA271D2BE92CD32A7A2C902AA52A762778263C267F2941291526DB2456263028192AD12A292A432AD82B49347C30B32A9628E5289B2A6D2BD829FA278C263F26FA25B82683286F2B392BD72AB3296829E3295A287E25ED233A25AE268528712A32274B2660276928C7269C269B267F263C283A29642AE5295428C925FF2574274D2A7B29402B322C722A112C1E2B0529CF277D246B27D4286B26D6262F26FC285F2B0C2AE72AFC2AF42AC2345031FB2B85293E2A092CE82A0A281027F1266425EC2605278C27D528602BFD29EE279D2A132BE027DE259824F8252D28AD27F1296F299527222ADF29302AA42A532A2B2917295727012982273A259123DD268E2858294D29332A30288729AA2AF329ED28D926D4263B28E6248225DE259127552899296A2A852A1129FE2B3D36BB32242C1E2C252C482D0B2C572A3528B925DA26AD250A2701258B27C829FD29812A152C94294F29CC25B52364246827C828E8286F27CD277728742B2C2C822AC22B3F2A74276E25F22723268424F424E625CC2A6E29EA2717273C268329162AD5299E27A32425253F27C525FC25B026FE27ED28162ACC281C28D727D6291F355D31222CE92D5E2CF32BAA2957299A29522809280F2996271C253F25B826CD29B82BA52CB62AB1291C279625AC278A2B642AB9292027CA265729D229702BF42BDB2A38298F2846271B2765246223A1254B25FB2A062A652706281A27D0260427B427CC272C28B02490261126562694259A26AA2865292329E929F82A782D73360832592B4C2AD62B1F2A99294B2AD92A2C2B182A54297929AE262B25C125F2289D2ACE2B352C3729B0278C26FE291D2C0E2CB2296128C1260D29372A552BA32B97290C2A5F29FD24EF256923202449245A25F8281B2AE22A652A462A842BF529CC2A662BEE29C827CE250C26E62536269D257E28DE29E328F328D72AE82C8534BA31502ACF289A270C2877271C2B372BBF2B7F2BF82A0C2AF426EA2365269F27A8286C2AFF28732824263D27992B6B2D6E2B632A04286328E928BC283A2A0C2A2D290E27A226C5244425E8231626852527261529B829832A002C8929A52BC02BE72C942BFA2951261F28ED26A5260D287A27422754284B28D926A029562DD133C731F32D9D2B4A2A2F299727E92B302B122D2B2BF9277F28A028BD25C624C126DB272A29F427B8263F26D326BE296C2DE02B2B2BA629F1280828042A112A9F29C0294F297B273224A226B92600272F26FF284B2A9C2A4F2A392A2F2AB82CC42C3E2D352CC129032A0D291228092825278D27C929142ADA26D525FA25DD287933FB31AD2E562C182919280027C228512A6329DA281428DA285B286A25DD2401268D26C025BB2894261C2737262729552AC329142B1726B82582274B297B28452A822BDF2B6228DA22C9240725B829D1279A27372926290628EB280A2BA72B772C522B4F2C722C0929772A1D2A3E2A57285529CA2727284726112515268326BC311A329A2E212B9629EA275F2681270C2A8B2A62281C29C22A6E28E625E7254225952468272A29462A71273325BD25572777291E2BE427A6250D2771285A29892B4A2B662BBD280B2431240427F4282C28F128C2299329A32A2C291F27112A8E2BBB2DD02A8A2B2F2BFA29BE28BD28C0279825AB28D62704252525B125A5276D301E31D62D432A6929192810282027FB29312A2928F4263C2801285226E8247E25BB248427C929CA2CFA28B125B727B627452AC429C72767258A244F2638272629CD29A72A7129DD274726CA26DA27A9283929232A552A592A1E2979270427DB27FA29012A302A7E2CEC2AAF283E263026F526D2275A27DA2557255125B0264F2FDA33C52BE228AD279928A1271D2AF0299829C42BEF2851280C27AB245C25F2236F246E284928652A20297526A1258C275828AD28C526242355244925E3254E282C288B27B4263C27EA267D2798264E268028EE2AD02A6129FF29FB2638260A273C270F26DB26052773293F28D1250A268A25A22729286526A727CF25F025AA309F317D2D242A1E2ABC28602A6B2B5D2C192CFC2AD32BBB292B291D296426A525922464271B299F2A3B282B277D27BB2612282B2A652894256B27CC25572875269B28F5275C28EA2923283027D4263E25D52616299D296029C928A3266D252426D626C82529253426FB271F28F126C126FE248D27822871290C2A2A299A2950328830E22B2B2CB829232B8B2C862BDF2C782BBC2A262A242B262B252A0729A427C224A3263928612ACF2AFC271F26AC261A2BD02A352A79283F27D2281929C1272B27E2273029B8288A274929F426C823E9258629DE29F02A2D29D8277728FE270A259B249C258027702732284026B126CA25A2254C28F0298B29592B0A2CD132A02FB42C482C312E842ED52D982B462E6B2D342C5C29EA2A2F2C0C2BC12A82286825222518288C2A9729D6280F2687270428722BB52AAD296D2AE72A9E291E2AE22716257927A027F426F62774271B24C926E228FA275F26E627FF27E2285F28A928F226A62545270E296A2AE3289C26A1265926732840293D2A0B2ABC2A2634AC2F832AC12AB12D852C062EFC2BF32B482DA92CBC2B622BA82C702A962AC42745252825F7264129C52BEC28892823277528462B8D2AC42BCC2AC02A842811268926A6262125BD25CE25932673244223EC25232541271A266628DE2AF62AFA2A902B6E296B29A0281E2BA82BC529F52817269626CB262E263C286A29892A9C341530932CDF2B892A012C582A192C192BF62AAC2B6E2B652B292A452CAE2BF4291F278525B3268F29312B502B3F29FB28852AEC2B792B6D2CCE2AA7286A270F264827A0273A27EE25D5250A261D254524F025BC26CA260D2794283D2A7B2BF229802B052ADC264527AF2AFC2B67277C26B624B0263E278226F0278E286C2BB135AB303A2D1F2DE42C602CB72BB32AD629612BB72C3F2B512C3D2C762B6A2AA52916275E2704278627EB285229782C7C29D9278028C729FC282829582862264027F5268B27CA285B27B4262826A9256D24A0269D255327FD29302B572ACD2B7D2B0A2B202A63290826F528C928B82775273E258A271029282996289E294E2CDE3306333C2F2C2EFB2DD22C7F2B842B7A2A832DA92D742B5C2B6E2AA32BB32BEA29082977263927D126E029432AEA28DC267C28212AE829312B5F2914285A267627D6270D2A182BE228D329E128E3260A2678260027BE26B1287729E62A0C2B182D382CA32AF328FD273A281A28862684264E2643270029CB2984291B29442A19356832472F8B2DB32E712C9D2A302B452C6C2CBD2A6E2AE129B929A92B942BA92992291A287B293D28262759280E28362810283D29522BF82A17287C26D72579260529B02A532A552999287C2A5128DB265526662598251128D529AF2B8F2D812C2B2B42292C292227F228BF27CA2651257725A628BE2A562B02290A2AC62A1835DB30882E022D0F2B3F2CCB2B9F2B362D892D0D2C1D2AD42ABC2A7D2A592BC92B752A9F2AFA291628F626F62ACA29C62AA42A4D2AB5299E29F827DB2655260928F12A452BF32AA529FC26DA26A62709272F2700265125F4258C289628582A4F2A7E29A328DB25A82470268C2810261C253B25DC29E52AC4297B2BD029382DEE352B31BB2CBD2BD72BFA2A232BB12CCD2BAE2B6C2A9128D8270F299129432A112AA6287827C628B127732747295D290B28B82776291329A02671268424CE256027E329F32A442AE8270C26422711280B27E526E42637258624E726AC26CC2680260F272525CB2478222F2577259224AB240F25E328C72A432AE929FA2A562D23350A32CD2DA92C552A562CB92BED2B7D2DDF2A222A05289627DB279226D925B326CE269D27FE27A02768256E268629AA280727D22786271A251825642398244628E029D82A322935261B267D268927CA27F8277E27FC23A423E62337252C26BA24F8244D2456247D235624E0235225F8243C25E62762297827AC27A6293D2A7E340D319D2C272DEC2AC32A262B2E2C792C592CC32AE0271127AE26EB278227522639277327F225F8258024F4244D2680255A28C2285F270925162452240A24CC268F29BA29EB281127CA2594265A2714298F299529FF25E1230B257225BD2448257B2429254725732442252B245C230E2449269C27F5285929D1274E286D2951341D31212E3B2E7E2CA62C562B132C9B2B502D762A7029562A202AC4288128102A8029D8287C25B225D423732318267926F827992AE728DA25C725492326234224E928B829ED274F2694254C278A261829292CC629EE27CE241427F126FD264A2869264A2636279F265527962563221724A726F126112A8D285B288829832BF333942F412DA12B112DBB2C062B292CB52C172D802B922B322A992AE5284A284E2A002B792A2029FA263424FA23E223E125D52613280829E32842281E26B22481254C2841291328D72560258926D3266B26172BCD2C5C29F626672816284F28B32A682B75291F2AB229BC291D26362469243E260B284629022876289B296C2CC234B52F262C342CA529FC2BCB2ABE2C892D902B782B762B482B192A40295D2B152B7A2B5F2A382DB62835269B22452350247824442565270528D7268A248A22F323D4258A2595241E2557248C236A269B26892B752A2A29AC2755285D29CD2A062BFF298829F92BFE2A6A2B922705251123572656292D2C452A9829B2298E2C36356E30A22B832A502BE9295C2A57298A2C862A122B6B2B272D862AD729A12C792CB92A062B6528EF29C427D221F323B4244025E1243B2464256E26E4247922272321223123F823FD225E22712441257926F329222991281029112AD52985295F2CF22A2C2BE429622AB42A1B271125E4258424D627D12A1B29D028FA28862BF233C930082C162DBD29E12951290A2A672B0C2A892846292B2A7B2BEA29832A9F2BC7284928C4274329F2279624FD23282387237A260B26F0259B259725502316223B236125D42340242F2562239D28ED28852B762AC6288327B5286029542AE72B252C232AC22B902A342CED27792611243026EC27BF2B2B2A1D2A5F29EF28C332BD2E522CBB2A3A2A04272329A829252957290529C429D427F1269C278B2652266E288B282429EF2905276C2501253725D92615299C28E327A5273B25F224E3233C22F622DE2235233325C2266F279F280A2B982B1E2975283F29B82A172BE42C522D8F2AA8296B2A6A2C7A29D02775255426FF272B2A362908282E27C9281433062FAE2A0A2BBA283527E927D329DD2BEA291C27F027B4265C26D7231C25A226C126FD2ADB2B672BC228CB2684246B286529D52A3D2AE72AAD2A60298429622866251D24B6225F244E25ED284B29F6299828C62850279027B0294F29FC290E2B5E2B822A492B1B2CC02C892932272B26FA267928112A612A7729F9282928FF321A2E5A2A0B2AD02A632908292E2AEE29022A4527CC260E27F0257725D726CD28012A9F2BD82A5B2A532865257F264F266E28BA29992AFC29462AB0291B294B2827262522A0213A21B226BB2683286827A726A827F124C325FC27CA29722837293929D128DE28602A352AEE27A327DE2653274D29E42A652AC72916291C2B59355C2F552B1C2D812AEA28FE28042AF22A922A072A6F2A6B2B4E28DF2531286829BD2ABA2BC72BCB282D274024E1248627A029062B912CEB29C529F9282E27302844269622BA223F22A2240C260C27432688262D257B245627332A8F290C291A29C229DE29A027F7284C2A2F283D25C6242D258028BC2A862ADB2ACA2A292CE0340930782A992B292BE6299729DF29F029512BC92B062BDD2A8B29D8272B28A629052BD72BB62BE1283726A32460241F2715282529EF270929F82744275128EF27DF266923D62278232C25D825C125AC2758285425A124C327D2276629692AA628DD29142A1E2ABE29DE29BB28B525C225D4246027FC2AF72B142A8A2A022A4E34A42DF42A462CC72A6529BE282B266E28892A442C082D0B2BDF2BBE29962B362B362C2E2C5A2CC8284B26B02344255C299B274129132801286C256D2661287D27CD26032592229121AD230E256325B5257229D52604251625F5276828FD28B62BCE2AFE2A6D2A3A2AA82B192A3127F724DD244B2528291727FF26BA26872731322E2EF92BAD29632B15291A281B27F9264C2B3A2A202BF02BF02BDF2AB72A832CE62AFD2BCA2B342A1D260B24B8241D289428572872260B26D4261327D926BE276327FE267F237B220E2389247C257425D827D6283B264925072889271629D4281D2B2629072A3D2A592BC128B427EA23DC252C24DE26A329FC27DB262E276730A82DF62AA42907292B279526B725D126A629CA2A842BEC2A0E2B622739288128182AD42C022A332AB3252D238624FB245827EA2692265023EF260A264D2A2A2A002AB72717266523B5249C23A524F2250A2755274C26622454274626BC285D28262AF72A832CF42B1F2D202927284B25FC23BC235C266F285129082853271732932FA42A4C2872271A2712279E247026D128EB299A2BD22ABC28A82896299229512A2D2CB82A4B2A4A250823F2231926BA267028E925162417254D27522730294E29E925AA251F26FE235A257E253F23F927F528A026F222B825AB26CD296229802AFF2A312CAB2A0F2CB52AAA2756246925C7231026C0256D2713255B262B315A2E8629CE282A273A2537252C2681255F286C292A2A042B0F2AFA2733296B287F285729422A03285C242A243C24FE24622512289A26C9247525E527A0279626B626E22590270627C1262F26682474231D2423263226C6238523BB24EF26D327D428292B7D2B0B294128D02645258225D923C923FB246124EA26CE265E27FD32E42DC129312A0929AD2721273124EB25DC282F297F2A492A962ADB28D1276628A32725288C2A402971246A220323CB23FB235627F2256127E3260926A32826271B261D272B29EE27CB282628AD2451240C2423269226E126042682240A249B24FC27C829E22A5C282C271B2634269E25142346230025DB248127E0267A276131162FE02AD629E22B3B2B2729AD276E27D529DC28AA280E2B142A4A2AD028A7272C28A1288A295629E42591239C244A244B23A42675271927E4272F2A632BC12AC429A0283327662876297A292E28C325EF2568267527452789267B259B2354259B263A28D3288C282E2863285B287B298B255D2405253D26C727C5272929E332642D902AD82B012A3C2A7F294927F225FB277F29242AC52B772A5A2A64287728EF26BB283E2B4F29782713245B24A4222C232B26B026F628DD29D6281B296C282B28E6259726E12632270B28FF2738269D250F2554256329A229962633247B246F2673267A28F3284929FD282A2900283E26F625712333268727FA268226B032D62FD32BE8297B290B299E277C2632267327FD274C272729CC297029E728AB243426AB28302A3B2B71292726E2233522AD235626FC28AA28B62911282929A02AC729A52701279724EE263B28CD27EF25FF252A2650264C28E128F1279025CB25BD25FE254F262A279C29F229FC2A782BA326BD244125E4230E253228972743339F2E2B2B842ACF29C028A027B124F8261824B325BD26CB27B428182AA228FA2473255529252A592B6427552482230523AF220326A028C128E9298E281B298F29F1290E28FC25A524A52681282328A026A724A5256F25FB25B52665273727C825E72541255B255725EB281028B829A628F925C025F7247F245326C7253227D130592EED287E29822BD629DE28EA256D2513251D24DE26D42669261E28E5260C2677272727DD2A882CE828902447241E24C32139258C27F3289C287E264D27ED26F427982700282C251326D927CF2841261B25F9252223E4237D264D266E278A263524C2238724E624E6263528BB27D0286827AE23BC235923F822562460259D2E372E802AB6287429E12B4E29EB285826A425F625E1242025F326E3259B24C52652276728C7290D2C4D28E92309242624F0221B24ED27A82A6B2998283C26D724952761277725AE2356276B263B285325B225AC24BC227F23462564231D27FC23C02664260E267424C525AF252127372960279C23E1236D237024642412261F318A2FE5297D28FA275E2AA229C72AD7271826E6243125E623DE24D8239C24C72499257E2600270529C1277224562373242524FE230726BD25E4282C2764272925982452245D25C4246323B327A526EF24A3246224852264249524E6231B231A246C24BC241A275E258A26562522258F252A26C3249324E3238223A5230525FB303C2EB229012A5727B426A827BA298429F228602580244E24EB23C125C22592236B269B26CE276529C228B124BF235622D02284240E240B259329D82913288525782522269924E6239A2350266825C8254B2519254F234E25D4260B25CD2441222525192635279329D5284326C2245B2601259224092475212D24442468267A2F1B2DD2280B28BD26B625E4266129A52A6329B125C824FF2480233A23B5240A263B2680254E266928892863252E2395225723B9229A2227254325362834273E27FC25FF24EA254A246424BD2685266A25FE24C2232325B126C827F2264E24B3258A247F234B26F8295D2BE226AF24B124052532240225F422E623C024CD25512F512D752952268F256B245624A3273B2869281F25E5241422A02252227523E523DD258D25D9263628C2293E25E02370251124BB2376238123602583250F28D528D92689258F26C2237B253226EF2533260B252A25FF261E27412A80281B254C232025562412246E26D4293E295F25F124622498264427AB24B0230925C8260330762D3D2815274C25A0251025BC2472260628B32519257722F422B621CE223523552373259E25A22700275825A8239123B9220722E0215024E324DA24F72577260D27E726A9255A257F276327C726DE25C12337243023FB267D299228B024F723A323CD22DE2484277F29F1261F242C24182728260527652418231822172632317E2C952656254B25A0244D238723CD259224A525FB231D22A2219920592171230F243C243327CF28E928BA2579250923DB21B222E9234A240C25AD2433241126C3251427FE243826DF25F127FC253E25D8230A2308223A2422282A262725F523E1225223452464261828A32769268B2220241E27C3279D26E724EB24FE25EB2ED52C6B272624F724B9244323E5233F24222598265A252222E121D421C0220C24BA24502646272328C5299E260726E321F822592385216D2462247B267426842769263F25FD25F5262826D628F827A4257A26CB240A210D25FF25D5269525B9257F233621DC24E1253E26ED261C24E423F3246327692813250726F9240B27C02FE12CB927A724CB237224FE23362384254224CB235D23D4221021E9208322432493233825B028282771291B28AC25E92256233F2478229523D3236F261C27E1287427F823542510250E26E7281E28A7248A25D9239A23AA22C426602616286B245323DB22452383233327E2244325362500269A2593265B268D257B22C9242E30962D6627C523B3240F241924372361251B251124C323F92347228020B822DF227A241925ED2545259C288D2660250623692236246C22F4204723DF26912679279226BA24CA257124F324A2279D266D2462251425932271230A244B25C8251A24CB2328223A22032203252326DE258525A824DA25F0248D23AC236C253F26DA31602DF326682592221C252725792334242625582461250E249A226721B32297214322EC245824C723E925A124B624EF22DF21FE232423F52141235122582446258C240925C0236C2490253C253925E025192550236D2322215521CD24192557253A238022FA2187212F2434251E26422656234726F82484223A228D243426A62F ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 65289F229522A12011216920A51FF11F5D20DF1F431FB11E8D1E271EC71F311E1B1D631F2E1F2B1D741F251FD920721FEF1F101F38200720751F681F1E21A01F831EBE1E1D1E5E1CD01CA81EF41D691EEB1D7A1F141EC31DDC1E201EA41DDC1E5E2032202420AA1D4A1FD51EB11DB220D51EA0211C21AB20981F21223E23442EBF2BE623B8205A22522286203621CF218921CA1F11214620281FE01F661F191F8D1EB21EE61ED91E491F0A2199215D22E01FA721E01FE520D21F9820E520441F501F8520591F1E20681E68206B1E721E6120B71F791E771E141F3721A720D71F2D20742077212520612156213B20B52092200E221F23A3220723DF22D824F12D642BDD245B231E220221B2203721EB212E20FB2276226E227B20F01F532071201E20D6203A203E1FA91FE621472117211B22632243210421EF205A1D9F1F22218E206321612093202A1FFD1FF71EBC1E2A1FE41FAA1EA61F3A20E51D3420BB205421D0215321502097215921BC215E20E72045210024B9218B228F22A225782F3D2CF0278D24E6214622EA21FC22AC212A2140210C21AD205E213920CA213F1FC220B92099208E228520222180207022FB21D222A12109226D20401FF81D901F2E210321DA21791F551F3720141F621E991FD020842023218920A520EF217222B323E022E22222227E218620332038210A222922C822EA2318226D23F724F92EEF2C34267122C321AE212F220322F6213D22E321AF21D021A5204E20AF21C320841F30217920B7200A217321D7235720D820D023BF20591D2020B51F361F451FCE207E21CA20881E3A1FBE1FBC1E8520A11F7621A51F3720E920B02117212A21CE22E022BC2364212922FA206A2149218B218E210422B120C3219323D723EA2D522B272616232124BB213123CF21BD21F9220B22742201239020F520A1219821AF21E42085206A2231215121CE22EB2298208E2164200E209F1FF11F791FB520B92022217320F01E2721391F8020F21F5F20732040217421CD20E921A5214C2255237123FE2109228A212B224021AC21FB201D221D24C722F8218B24B625BA2E762B73247D233323C0226A2286238E22202202237C22CE21FF216B2186228022D8223A21E62149215D2361233022FC21E11FF71F922055209220F41F83210B214F200B21AE202020A41FBE1FE21F801F00219C229320FE20D5212323FD21CC22AB23BF21C9221E21962131214D21A0211F23AD21C42269211C23C3231B24BB2F442C60260C24ED2497237021ED21DD22B822502391219222552362240022E621D622E52182224723F4225B216722E023FA206820D5200E20FF205521AE2003209F204321492144201420DD2145225C1FEF227821C020F2204F22BA21592413241C24C7224A2201226D2258224F2281236723782350235E222C2429244C267730202BCB26E524AC233A2495222221F32208244E23862229224C22CD21BD22F42003211C2250226122A5223121A71FFB21FD1F5221BF1FC01E171FD120CB1F1220B42077214921C2201720B81F681F7120D021F1209822F3212B268A25F324BE246C242A22BF23DB223024E622B522E724E825A8249624BA230823C1240825E730DC2D5125A9237F23AD23AE228023BA22E8237C227924A723C821E022D822E72185223F21492286219121FF21D11F2821941FF0217021AA1F9B21B31F541F6420862060222621A32144200D22F8218320DD21F8224123DA23112519263425332567277223932162231C246B25F22615275327D227AB26C225A523AE25B8268933462CDF2803268224152532234A23062380230724DF25B32425242022B822A2224B226B21EB2107227D1F1D21EC1F8B21611F1D1F7C1FA31F59201920621F221FDE21BD214122A22240215921BD222E21C521062154220224D3268626A62558262225FA223B22442327257525E225D028B3286227BA263124E9248A254A26D3337E2D6B27D9249C26B823222295222C228E24F624E5248D24382396223F22C3229C21542106214F238B20D621701FC01F50205F20BE208520911F051F5F202C203C2022221422D122F922E322E2237523CF23D021D62261248825FD2418245125BF24E1232E24B82279269A27D627022A3129BE27FC25CD24702318232D270632522FB829C9264E258724CD23482326228324B424EF24022798244B25AA234524FC226A216D2032228120B520B41FDE22EC212322B2211821B521B022502119223121F92388251D2467234E250E28482565233424992220238C2508262A24452667240F24B621A0221525C72663277628E3275C27652801253224892450273B2F752EB2293627AD26E926A023E9231C244E2500266825AC25AB2496236924AF21B422232243214D21DA207820D4202A22C6224923F321C021D1239721EC20EE1F09238C24DE25DA250B2788270F291D275C27DA2580232923A5237325E425A126B426D6220B235F22EE24F0231E2481262B28B029E1286B25EE24F324B3262332FB2E9D29C2282C262127D02495253423BB25A623F325AD26F223A723D4222723B52001232023EC20F91FE51FF920DF226023122295218F23612330222C223222D924B125BF277B2827280A286B2860281F267E258224D2236A25E926B2255D26422669253024C522F224CB24DB25D427DC29F128E9285F24EF23C12412263C3065308E2BA1280B260D269F268F255B2544235D248225BB24D122D623C623DE234221B222902110218E222523022103224621E622B5236B238F23D5233A23EE22B424D6252128C0286228892B222ACF288B27A522D2221524BB26A1276A286128C427DA230224AE22BF24332767269529B9291A2AF8284A274D2468242F27E830272EFF2AE02905296F2678263A269825F223D12365258D24BA238723D02283222E2248219321F7204622E72012225D233823FD24E8244023C6245C259A24E8246A26E729492C5D2BFC29AD2834289E27E1251424B723CD251B2A422ACB29552A62283F24DA232622BE238825C1270727642A622AD629162899252E25E1271A32D82E65290A281E25A6262F289D273527BC25FC2468241B249D2351236021AF214C21D621B9220B21FF202A2242223E2355237A261A278F26DA254624B8259D259B28332AEC2A872A0B2C4F2B6929C5265125A326B9254125E1296329492870275628AC23AA237121C724C524D129972A342B982AA52899269225B1244E26E032CF2C532A4E26682604279427FA287027832512244A258322B222A0229123CF213C22A42416226024EA226921B423B3255D25F428FC28BD2828270C25FC251526A8279A29832B28299C2ACE2981292A25E8253F25B226552714271426652685265F26F2251326DC22A2258925E525C0253E27DC2620267824C725AA24322785315B2F7128532591259925772615262126C123E322A123BD23502378211B2414248323A2200A23442356215921CC215324D62751295628CD26042A2F27C5265224672638282728382828270E26FA2339247525EB26572775270B291F27FA26C0270B280B26FA2410264F288B2521251C27A625502501255123EE23AF258026E830C82F392A4829FA2799266E2643242D241924FE233F25D523CE22B5220C230E248A22AD2495229F21AF2168230223742453273E285329CF2801290429C9277B270B27AC276526B22626243C231A2517236026BB28C229702AFB273928B5261A274827942412252E26A5295B29F4271B29D4256B254A2671229624A025D6260D321B310F2C5D2C422918280827BD25BB242625B324F222A6251825CD252F245C247E24FB2160245A22602246227D23E6233624CE26BA250C27AA293329C6295F27D8263627D22540257524A02341236325B428292AAF296929A52830275125EE25CB25DA25A2244627EA2932299D28C1259F24642632241D251D25CA25F92820338031C72C8B2B402B652AF1285F266E2410259B244626EE265B26B124EC267F246D241823F422A6206020D920702139226B22142418243A26FA27C626BE27E126AF248125972543255D2302267725F4259A2A0F2C442BF328BB2754269C255626C425912581277A27EB2A5D2CD629E22741264F25852527250725EA262E291C354E31322C2E2CC72AC42909265225912517240824D72510279B24F225E6273D25E6240E25A3229922B9219F21FB22CE23EC23B3237D2386260827792526261D2548256A26FB24C7228C246E24EC255028DB2A4F2BD82B53294E283326312525264823E92372253F27112A33290429EF28FC2818276C26B72549268026452A0B354030722A0A29C2282E28062604240A2451261625D6270527EA25EB253A25C025892586241C2486250122D620C3222D2372233B255A26C426AF2582255A2430256E24DC25BA25F824F5230D23A925BD25E527AA28F9281A28C627452549242E2416253F235D245E278C27B227A2269B295E2AB1287F27C225EF26CB27442709324A2E84287326F627CD250E2504255524442589249F251726AE254727CC27B2275628172514255123AF22DB23A721C6239B24D426852889271B2880261D27DC2513263A25F925BC242C2258231624982335273F277C2544245026052413230E249F2259237E2503265E2931282C285A2A692B4428D325BE23CC246F24712772317A2E412821256024DE25AF256725B825FB25872589268C26B2251028792864283D29E7286924D524E12200224322E82498255F27032A2A2992288827EC27EB251D262425C9251C238824C322C5233125FC24DD26B625C124B824B4258523F824CC22F6228B25D6272E2950280229382A9E2AE5286626AB243123B3240F26F230512E6F295C25E52573252126002773287428C92774285C26F0296729902AC12A88297329B02627253523CE222A239B245C26A027D6276C286C270227EC26C727C227CE2620250323F92370222924FA2397258625EA246625B724B825CB232B239F24582385249A281F2A932ABE2AE22AB82A47288B26D5241E253A25452855328B2F98286127A82665268426D4287A29B22B982B57297829D228F02A942A8B2B722B47299628F624D723A02300239B23D6244E281E2832272027E226FC254D2803297328F7262923CD223B232322EC23FF256D25A025122546261824DF24F8249323A123ED231D28042A782B962B222DB22AD3299B278F242525B12713281832AB309E29102504259E25A029632A182B622DDF2BF82D512BB32AE129962A302B8D2B912A91294A29A324E8234E22FA24922312261528EF26F0258D253C26A8275228DD278C267724E22231237423F824EE26F225D6264D24752624260126E724A2240125B4266628792A312C4E2BE42A0B2925279E26E1245825D8271828CB327D2F9A28C525DA25AE284228DF28D92B8B2CA32E482BAD2B4B29E1294A29CF271F292E2AD72ACB27AC23B3218C2312230123532428267A245E25D02564262D27D32706283A26B423A22296219623CD24BE259D270324B1248A269C277E259C24812383269627C026E22A842CE22C282B2528D6245524FF2374265527C62722314A2F752AFD26AC28EA293928E5272E285B2C972EAE2EA52B55285D283A2BBE2CB32B162CE42A4C29B4237F225A2106212022A9248B254E258C261825AE27DB274D2B422A8E281323A022C824F6252625E226F0274F25FF25F92689275B27EB24BF250B27892727298E299D28E328BE282D27D12626242D24F723EB26E1277431942E9B271126AF26AC287B288828E3275928FB29062A84285C280C2814285129052BF129C02AFF26A3237222202161208521A624262638281A28F0272B277E29822A922A5627CC2397228E26372783288829592A61281D26F5257B255C257723F825832719283B28AB29D62878273F2638269F241325A6232425AE2654279931732EB128E62674286C2847296B260A263927C32650262F2723287C290A2A9329A8286429CC276D255224B421EC226A212322C124DA273427F929C02B4B2A842AF92B0E2A99267F23DD257326AC283629002CB92B9D27B926F325462494234F238224E526FD288A29EE28D125FC24A62421268E258F23FD2426288028B828E133062ED22748260629962AE827A927C925E4270426C426B527AC2AEC2A662B072A562908290F2765251C26AB2380227E234323F7243829AD29862AB32B962BAD2B112A222A002619240D275629E52A64295E2B372B5929E4286826202521257E2207255325AC251A269D265E2751267726E124EC24C326D4278B297B2C772B2735BD2C5528E429922A8B2BE12906299E27DD275327E82786290B2B1A2B2F2B0B2B172C232A212790269C230723E423262361228424B22875289129DB2A4F2AC02AC0289F26F5265123FD24A52A2E2C4F295129412C8B2B0F292E28B8269A24F6248324EC248B26B2277E27F3259823B42405257F2590268E27FB297D2CDA2B7936CB2E8B29A52BC82CE02BE5286227DC29E92AF02A612A8F2869287228A42A7C2CCA2C862C6429442821251B23EF21D923B422C123BE2887287F28C629CB288D293029F3281526B42277235B28E0280429542AB22A1D2A0D29222803244C241B249C2740256D27BA278B252E241E242525E524FE24E0264A27AB29032AC52A9634B72FB02A692A462BBB2B372AF92A7F2C372D6D2B4629DE2574256D2A402BE12B6F2DAC2B282A40282D26792155224623A72240239D26AA27D42724273A27B7292B2A0E29F82579224723CE249C27C226FB28AF2744297C279D254F251324EF2373266428CB276B26C726CC2312244B243424F622B0263826C7266627CE2875334430B92ABB2A042C252B1C2AC92A9D2BD92E492A1D28ED26A6275C297B2C712C2D2E5A2CA12AF629FD260825D12436225A246A244C25B2283F277526CC279D2857290029ED265C2268223424A6253C2739283926EB263D26C125CA23AC23C7256F27C9288C29B328A52629252C241B245E239E23BC26B624F126DE267628E4305B2F5F2AB02B6D2B592AAE2A9B2B472C2E2C492A6D29412812272D285A296E2A962A2A2C452B602AEB29182634248824FD22122485255727AE27AD264028E5278A28F326182574236523332576266B27D3287D2863276325B926E3233C23F723FB25C228962A5C2A7829B625E123FF23F8247925BD286C287B289C271228C931562E582B612B222D1D2CA72B4F2CAA2C572D2A2A83264A258227232BD02B3F2AAA2BF12BEB287A2BA1286F26FF24FD222E2389243B245D26EA28AF2551273229A12902285026A524D323AA254A26B2286B2ACF2A6729B926E324BA238C24F125D1253E286C2A5D2B7F2A5A27B72487245624FA252C28E3284C297928932ACA32AF2ED4286C27712A1928E727E428392AFC296E273C260827B127DA28CA2A652A4D2AE62A5A2BD62A0F2A31274C25122544244123E524B825232612264526AA297729F629D02A1F269C240C262928E428C428A2282628DB26B726D524DA247125ED27D727B027AB2855295526DA24C72428258827122B902A2E2CA32C182CE3314B2F3229AD287D27D4298C25D9264E27B025A324C0245B26EE27DF287D2AAF2A6F2A0F2A3B2B5B2A0F297126EF233424A8234C236324BA26D525FA24852645285829132ACE2BBE299C273E2513269626B9271626C8268823CC2466251027A52605277927DD2665270F280A26D92473258A26BA29982C1C2DCE2BD9299A2C0F34CF2EBB29E6288028C127D0279E255A265E25F5245125F4263F28AF2AD329482A37299E2A7E2AE9294727F4256F25A424E321B9258725792338262124FD2482286C29DE2AEC2AE2284B27AC255326E6245C25F324F723A9233825DE250028852905282A26F2266427F0267525A5245C262228F429502C3F2A79285E29862C693547304F2CA02B022B272BC12A7B27F4253827A8240C25A02660277228A62BA22B062A9C2BC329FD29F82AD228C726D924D72210220823CF2440259125D8265B261D26C4279A283B2712287C273725102598239C25EB23ED24322310263227E02734288F286429B42971297824D724BB278C287D29BF2A562A542A2C2AE72B43344430852C312CFD2CDF2C802B902ACC2A7B28172761257D269328662AA52B902A582A5D2B392BAC2BCF28D627E7269224972434232923D3240027662507281227BD26B82630279F26DA264125ED25BB23F222172425236424562696244727CC270528AA28AC291828AE283F2634258C287C29FF29422B5929C0294F2C102C8634902F262D5A2CC02B122D1D2DFD2C502B152AA826CF25052649279D2870297529A029162B5327112767260825E724AF245323FC228B230C273029FC29B82B152BE5287125AB255726352690262A27232390224122D1240F266A25D727832741276A265A294E2815279A269E24BD245229FF29F42712280F271E28BC288E2AC23427303A2B532BF12AB229302CD82A632BF229B9273525CA2690277C287827E9276628B62661263826C424BB2384252C240822802232248326E4287D2B602BE5297E28CC252B278A26EB26412756253523CF2278248B24A92533272C27C5276A28F028CC2A5D290526AF2409248B25D026A326DB26B126302692269627E6282233F931CB2C172A20290529A32A832B7A29E427F425C726F8258F262927F92791262D292B26A3269025FC2335252A2490253F248822462222251029E728CC29E228DB27CD26AF292A2870277D259F24E5223A233026B42542277A285428A1275F29612A1028CA261A2467247324822420277927332668258425232874299A2B13335431242D582A072A6D2A74290C28812852289E25E92446269B26EC279128222AFE28022917294F293D278824DD237D228F23482492246326472761273D28A02723281B281A2858272A2537248B23CF2374233027AD288827FC281B2975279A266725C4275924F0230323A1237B2460269E270228852678259428F528692A25349031962CEC2B312A7C2AB32A8A2CBD2AB7283E25EF2569278129E629922A6E298F2BA42E782B852B8326182655248F241721F2209E239424F125DE27B9276726DF254B278E262D25DA2388222D234B2422273C27EA29CC2B6B2BF32AA6271C273926F026D42342225623BB235825C9276C2754266E268C26622A8C28FC29E431D730B92DCD2C272CC12AD02BAA2B5929BD2839269A26BC26B228FB2AAA2B052A1429922942291D2BED2667255F26AB258E21EB2287222B243A27F924DB25EB25992792299D27B424EA22992309240B25D726D32876294629912835278325AF24F024B424D423E0207D248D23342400264E269F25AB24DB23C42557274927D830BE30FB2C5C2F9C2CA42CA02B462A442782272327A526F527022BA62BE82C942A7A28C428AE26BC284A2867273F28B3253224C7200323CC235A267725D826C82654286E2BC42A30282E26A024FD251B272F27E2278C269027DE28ED265725A6256A258B25D62324230022EA226125AD255624CA23E0252024722507255326B5327E330B2D282DCD2BA02B532A2429A529DB26922473265E26BB263D283F29AB2A1D271A27C3271128AF25D927492982285724E922BB210423D1231825A2278128F12B7B2CD52A1C29D5269F26CD256726FC271F27CC25642759263F27F4258526F827D7250424DD23F524AB236025FA2729256B2363250424D025D2253B260C309F32F02E622C672D9F2D732C2F2BA22A7D27DF26D42738295D264828D62698260725DF2468266B276F290E28CE294129CD24F823FC25022327252E27AB289329B82B222B1F2A202BD129AC2837273026D227E527F92547261C27A929DC287028252A3A29EC279326562621268826EF27BD2606268B281927952789275B260A2FAA32412E3B2E082DD02A5C2D632B822BDE2AA9282D29CF2ABC2A7527FE25CA235A25B5247B25F52874288128BD2780283D25A6242323ED2427254128C12AA42A5A2AA62B4C298C2B8A2AF5281825F124C62577253E235F2488266B29712A8529B329C429412A0F26D127F327A12799298028EE26772AFB29C628912881288130FF30A42DA82DB12D6A2B352CC22B9A2C5129D127112B0C29432AF028E0276825AF2568258326D6289E2A3A275F290C29C72878260F24F4225A24C526572A152B572A9B2BDB2A9B2B9A2A7F279D2798243F248925F723D524EF27C329B62AE9299B2939290529142708277B28982B382BA52738259A29DE293D2BBA284828A931E731AD2BFB2C6B2C092D5F2A4D2CB629A229292B6E2BAA2985296228F3279D25062643265127A22A8F2A85296028A5297629AF262025AE2391239C2400280D299F2AA72B702BA82A9C29C42626266123D924E624AD25E624F2283129D629B52A2A2A322A9629AC2573278E28A52AE72AAB281629B62A502BB82CBF28C428AF3252306C2C472D2C2D4D2C092C4D2AD229EA29662A592B8429D1291227E327AA268A26262763296A2C5C2BE029582A8C2AA32954276126952301251C25B128592AF62A3D2C212DA32A282BAD2A87270524752461244E25AD27482820295B2A312ADC290E2914287525F8274E29152C712C3D295F2A9E287227A62810276D294F36CA2F0B2C6A2ECA2DD62CB52BB7286927D827C6275C28AD26142748277E28D426D4278A297E2B212D2B2B1F2AA4280629212B0E28B7237E217D23EE2586271D2B162BEA2CF32B332CFC2B1D2CE5298D26F9248723AA275D28EB28A528A52753297429F726E426E324CF288229D728AE2A642A7B28C82546252B25D7266A29B9340230FF2BEA2CBF2CEE2B232A4026332609260C26A727EE26C927C4265A27D02AB42B212C952CC72C662BA72BEC28FD2743265524DF232723CC21EE25D12526276728042AD02AC52B3F2C642B2829AF254A248F257026A8298228D1263F28A128592930273825BF2575297F2A4B2A61292C2973287926DF22542479263629B933622EB12B8D2ABD2B152A2C281826B1253E277F260028D7264A29F42A122C312A3C2B042B802BF32B2F2A452B7B294E27CD24C42470222222352295245726D127DA28BE28342A552C2C2B052BA62BEF26FC24F5249B27AC29EF2A762726267A27232A0A2A2329CE26AD29822AB5292B2A1F29F22881287326E925142576281F32FD2EB52ABA2B32299F29AE283D2675245F26BE28812AA32A4A2A642CA12AB82B79297F29D528372A15287C2902290F29A726352699224D210C238C254827152973289027602AE828AF29982A722A70260726D725CE25A026C8292F262E255E27AB29B829AF27BA2786287A29522936293C2972273C2BF7254C257228BC298333E531322950280A279528F2291D2704267028112A7A2DCF2C1F2B742A4D2AC626F9272A293B2A8D29582B882A5129762B6B2AB1265A25F4225723B8246028F329462BC72A8E280F28BA2759284829312669252E277E271A27212759267724762619277928C925F7256528C426ED264F2AF128CF27A7282E26B8258929932997354F32652C6A2772265527D32565261E264229452C412C062CD629DC28F1277B2789265628492ADB2CDE2A532CD72B712A1229D128EC255724D724CE25D1273B2A132CD52A4A2867257D26C827C9257425B7261C26CC284C286C28DB2479246625D6276C254E25A827B6270126AA25CC280529F929A027FA25A8253C290D2CCF359231532D992A3D2A3B26DB25D626CB26B4281128E62C4C2A772B9A298E29FA268627E727A82ABB2AAB29772ADB29B32B8029EC277C268B239224BC2550260C29112B5B2BED2771256C27CA25E3234A227B23572578274528C12771268526DC25CC280F2857278326F025F8250D26EE295C291729F1274F2792276628152B41352E2F9B2C042BB52995295F26CB23E7268126AD28C3290729692BF12A052CF029682809285827C028DA276928152BB12B2B29C427D525F92424246424EF264F29682A282A2C2A4F2872259D25DC23E620C7201825A9236726FA28942807287A28F7277428E328BE26C42895269028682BE52B0F2B93296E282D28C22BF22C0D35172F942BE02B212B86280026D423D8266A270D29772BCD2C642A402B282B0D2B562AAF2806260528CD272227602A9629372A1E2BD72909251F2406265B2793275D29E7283327FA257D2637261625E9238A238E249C25CF26B7261726C02659252327A929F228532744263B25462AD52BF92B792C9D2C7C292529A92B3E2D7F33FF2F4B2BE82AAE2811287328B12600278229132B3A2CF62AB52B6D2B702B552C652A5F299B268B2850297F28E427D0296A2962290728AC258F2509263128D827BB294E28E5241E26DD26A3251E2640237B24F626DD2692290729AA25462656263927BC27F82596269524062751274F2A782C9D2C492BE92ACA2B422B762CA934E92FCE2B102ABB28AE290F2B752916273329262A232C572CFC2A1B2BFA2CA62A8F2AD72A7427F9260D291C28FA276D27E327AB2726275924032538265D28A32ABF2AB828BA26FC238B264B2881276724AA253A267427A627762A7B280426C927EF279527B3279E25942570246C26602A562B262D1F2C8B2B882A6F2BCE2C30340230432BEA2A5C2B3D2B202CD22A882A9D2A852A69292D2BF327EA270E2BAB2BA32CCA2996289028D329A52A842939289C261026512528232E2516250F2703287F296D2795268324E4262D28C028B426D526FA25EB275228A42A40280027E3271F2816289F2747258E256824D426DA279028592A6E2A232B542A7A2ACA2B423560314B2A2A297D2AF42B0D2DC22AA52ABC2ABF290D289D28EC254626A927542AD42A682AA8299D28522AB12A8E2A6A29EE269824B0231424B32333246B232F26C129E628982945268E26322805287226382520260925D127292740286F25B02530289C263E283B26382468245E251B273928FD276E282C29482A4D287229A934512F0329F926A927122AAF2B242DD32B5D2A8E294B2A0F2911274F245926E429D3296529802A062B65298A28E0268C27E625162675246D23E323A5224924D92868296C2AD029F5262427CA25AB254825DC26C825B32790272828C625ED253526BE26962699259825A425B7263428472A5C28E026A32776270929FB27D328AA33C72FF12A25270628E827A328BF2B0B2BA02A8B2ABE2AE82A6128F8278A27B729BB2BFD2BBD2A532B2529972BC9287428D4268C28EF25DB248E246924F2232E27F12864282228EC244F245D251225DB24FC25ED28152AA4299D292429C4282F29EA29F227692640265F285D28FC29D72A9D291B2842270C26C228BF28C5297135FA30102C592A792960299F29D02A6229D32ACE2A252DE02B3F2B2D2BA728BF2B8A2DC92B672B9E2CB12A7829CE2A4E2B8E2962294027BD25ED244122612559278129BB29982941265F24C424DF23342420279C29112AE027E6284A292929322B7F2A652A4E276725412A262A072C5C294326F426CA2764279929172BB82BCB340E30FB2B682AC928CA2AA82BEA29482A6E2BEE2B532D562B682B1E2A6B2A402B852CC62C222C372DE9294A293D285B295B28452A5C2AEF27B8267A24B5255027E128DF29732967281E255D244925C7240F26702A96293028E727CF284D2A5B2A642B4029D7274026A029D92AF828D7274124B725E32796269A28D32A272D1B35FF2FDC2C292A4C29402A082C562C562CC32BCF2B3C2C352B502902285B26DD283129B32B3D2C222BD42A282AED289727AD29C92A602BED29FF27EC260A25E926282A7A29902BBE29DD275B2515259824BD27E829BC29512AEB28C42636290F2B7C2B19290D272A281D296629D22716289925802503261228CB2742293B2C6C34BB31FE2B932AC9281028812AC62B652A9E2BD72AE42BD32943285427C7268127D128072A0F2D192CEB2A35298C27A727D728AB2B672C99290729AA27AE29F028C3285329712A9229F528BD272925D8229C26FC273529542AF529E1295D287328342715288C2847254A281629242790279725C727F1274B26CD261F293A2A8434DE30CD2C512A2729DE277B29AF2B2D2A63286F297528FC27BA27FE26C12599259526FB27082BC42C7B2BE92AEC2824299D2A1E2D8C2A79275328A3285D2981279526F227AB29F6296329DB294225D524CE2588279726D7282E2B2C2B1B2A0E297C2805284D24C72599267328792761276C269829712BD62AC32A042A752AFF337332282DB82C13296B29A22BD72ADC2B322AF528B0287129C52AE5290727F0278524EC28842C332DA02BA628F7289F29D629182B0D296728712886289B2A372ADE290429EF276728EC28D827CE25AD24CE247F26D0268729DF2BBE2CCE2B112AAE28DF2760269926BE28D127F8275428A3271529FA2A882B0E2BA02AE32B3536C8320D2EA32AB529F029E229932A862A9B28E528A929552B962A552BA428E3295628F828562B4A2CE0291D28E126122A86281A2AB229F727B82736289B269A28D729F32A092A2A293F28C0278727FF24DC231D2589254A285D2A7D29DA29B1290428ED27752644286829602793271226ED25002A082CD22889284927872B6F35A033E72E2E2B40299728D728612828291C2AEB29CC2A392D9B2DCE2B142C5B29D2271F29D62B202D1E2BC8289E270A277129432ADC2838287328C225E5246728BE2AF52A512955272B261826C326462403256C2432259B2505298C291629CA2A2F2A9328B327B129092B1E2AAD28BC27A528C329C02C862AB529DD28B22A2C362A33182F212D9229022833280427AD289929EB2A6E2B822CF72C6B2CE62CC4298F29152A6A2C2B2C452BA4277D2529263B252727FE27452614285E25AE26B526182A942B722C4329C62699256727C32598240D2521240223792AC729612B122B102A7D2A76291F29B92AED29CF288F273528392B222B9729A52744273429263330324C2E532A4D292928A02790281129FD2BDF2C9F2BDE2AA22A152BF32AE82988273C289728B42A972AD7268125BB254D271028BB28B5267C273A26A127D0287D2A5B2CE42C852A8A286A2622291F27C024A124E121AA2453264A290F2B432B5E2A872A152943296E293C28FB261C27E7276E2A4A2A7B27D92668274828CE315B33D22B852A01291626D825C126922A5F2B622DA42B59292D2828293F2A0D296F2729260628E4298129B1263027DB27662AC929A529DC265C276D254F267428212A5F2CEF29042A78285D28D9282F29F7287D2408249E223D2696276B28EA2AAA2AAD2A5A284728A328E2252F261D2676289929B128762605286B263728ED3228315E2C1A29F4257F2421259C26F829272C492B0F2B1326EE2753289D28442A12293727EC26292A3128A826992876297C2B922A9A2881271C26E1258528F729132AF429AE28412580267E262028AA27DC263D25EA23BE2178260C268B2AE32C572B9F2A2128C62681280A273025F9247D255127362B7E28B9260D26A92749309332082D552A8B275426F9265D27E42C2E2D1A2D8B2B8C29C428B0296D2AA42CBC2ACC276E2717282E28E728122A6A2BD22A872B4E288A279D267927A629AE2BE72B762A6D29A825D9231D28252A5327A82653276A258224E324852407278429A42C882AAF29A72AA72AAD284B26CF2639259825412822291329082A342ABC3289302A2D8C295629A8275B27E527A12A792CCA2C9E2DA62B7B2BE8293C2CCB2A8F2A2B28CA27FF2694273228442B722C732B302BC525ED24BB241F26CA29952B4D2A782A962866272028342981294E285427EB25FF22F423D4241525112782287B2B31296529C929E629B929C726B72431268726CB270728B029332A60290F342A33B52DBE2B0D2B762A7F28E028582A0B2E332DE02C942CE62B342BAD2AD62A80285029A3279927B6278827612C5E2BC82A922AD827A32530255227FA2745295D2B272C5B2A58298529602CBB2D6B283E283826E3256227DF271C25A326FD264D2A382A6B2B772ADA2CE92AE427AF258A260E28A529122ABB298A296B2BB334F4324A2E2C2B182AA228DB273E29D92BFC2D352DFA2A5D29E8289928B0278D271A28A427AA27D3264826B426DC29D82A862A322B1626BC247F25E12638279928322A8A2A512A73280E283329CF2ABE295B280C27D928E3260528C7272025F6261C282429912B4A29A82A192BF62729279B264029752B0D2A6F2A9F29CB29FA3454338A2E852AAA28C42768273528C42B792E182CDF2BD629B227A4268728D327E726AC2AD52A732811278927ED29BD2B59297F29F72759253328A827E128C72AA12B4C2B792A2F26EC26232706271A261B2819299F29C929182B5628FF27CB26A925522705290D2BB82C312838275127CB28F629F82B602C8D2B5728FA29A5354A33F42C8E2A5E28A627C2274229B02B612B802BD5287128FA2597278C293A294B2AA12C142A3B2A22273325DF250728D02771261D253A261A27162A522B5529F72A492A3F288025492715267A25742681277E2BE22988285F28D3273329F026242574246325B627302A8C284727ED277C296A2B902CA12B882A3128E22717336B32652DB22C012994274A255727022A782AB4290A2AAD28692775283D291E2B302C492DB42BCD2B54293327CE27602A4D285127E524AE2574282E28C529772AB028242730296A2A6D2AC7273425FA269C26EA2BDC29F926C8276F275F26CA23AD22DD23C527F42616294328B627CF26E1271C2AE02BAF2B942C5C2BAE2BC034E6327D2D382BD12A0528D425032707287629E028992788282D2845293C2BA52C9B2C7B2C842DB42BBF2AC228E929AE2A912A5A2847264E26C628E129C92AD72A2928AB277F290428B3298F27EB250F254E261F296728B227032785272E288C242D232F2418267E27C327C0271427CF26F125A228872A6D2AEA2A612AEF29FE31C9319D2B7A2A0A29E8271C25D2276727A229842BC62A002A1C280D28BD2B882CBD2BD42CCF2B4D2C9A29252AED2C5A2C8F2A752991275228DA280B29CA2A9E2AAD286526EC2794277D28D225DF257D245A253C276A26292665274C254327A2250125A123BE24942421299E28DF27C528CA267D260E28A92823271928C4286E2FB2302C2D872B8B2A21290626D9288028482CBF2C30294D29FA299D29722AC12C122C692D982CCF2B832A282ACC2BA82D7F2B842A6B292E292D29572BCF2A402A87289A2714284E2744297F279F243F2332271D28B0263126A9257625BE278C26C725152453236526FC2766289C28782756261927D627AD2678269B252D2610306330982CB32A502819278A257D26E328B8298F2A1C2B3B2A14291A28F3294B2CE12BD82A482D5F2A892A3C29362B782B4829082A33265126AF286D2A25291929C727DE27D126312445262724B226AC23F525AC28912711257426802725279D26C82361243625A9234328ED28E42912284227AB23F6252F2706277A276526C430E631F72DF32A7E2A7B281B267827562B182D362B772C652C3429DB289A2A7D2BE529B82B832B302B4A287326AF2722296E2A622B7128F2260129FB29772AA0294D2708269825EA241B2692275C287A27AC286A2ACD294A2A97286026BF281728C0286624432431243C2604284D2AB0293D25EF25E12564267628DF28C929F2310132C02E152C082C452AF429FF28FB2CA42DBA2BD72A9B2B122B862AB52A0D2B6D29592AC92AA02B5B284926A929FD2AB72C012B22299E27012665279B27CD27382583250C260927AD289F29792B432C6C2BC02B3E2BA02A76299028AB28CF28FD296E27422487252B26D5275529F2294A28492679266C273029D82A672BC4328E35142EDA2B8F2BF12A0628EE29432BAE2B1E2E302B032BFE297D29632B242AF628D72A7929AE29F5278B269B27962A782B132B2129702411256325AE25E526FE240523B82272256327B429982BE92A122BB92B4E2BF1298E2A5E2859293B2BB52ABD27FF24492328264B27C528902A6D2833279326B926AF2AA12B372BBB343D335A2F142CC02B262891281129C22B642D412C6D2C172AD729982B842B832C292BD42C912B7F2A2F286328ED29FF29D22A992BF7272D255A27EC2435277024E02413231223AD25B824CF261E292C29E228FE28F428CB29D6290B2974290F2CFD2C102AFA262D25B9251A275D297B2BAB28FB274026AD27812A7E2CCB2D5B3565305F2B572B4B289C277C287D28082B7A2BD52B4C2B222BA32AF52AC52C8B2DB92BDF2C002C252B792A422A682A682A822CF328D726FF25762629282D288B26FC24EF236624A42397235427D02644265F27512977284D2A302A452AA22C3C2D452BC82980289926BE249A2598267C2A8D2A7927B726F7272D28DB2BC32D4434A92F4D2B3B2A752BE52A4A2ACA293C2DE82C332D442B7E2BAB2BF92AF12CD82C6E2B022BDE2B0A2BC228FF29382A3E2B04297E297527C1264F29072B472ADE2ACD2750232625AC25CE2671285429D5272D29662AA728A52751298429C22A1D2BA62CF92A7C285426FC2477259D2662298A2B16291528B627FC29842A392A07347531E22B6C2A712B7A281B2AAC2AC62ACF2BA22CF52B6E2A612AE6281D2AE2295B29112AFE2AC42A612BDC29152C952AB0293E2A692725299B2AD22BC729D227E226EA2534254E27D228772A6E29EF27AB299E280C299D28D52A532C4F2A052AF22B152B562B5E281127E82545262B2AF42A8C29F9270627EB2AED2B812AD833BD32D92E4F2C3F281B27E425E529EE2A4A2A102BA72A4D295E26FA277B28F72872289D283F2A5C2CF72B972C322CDE2BEC2BA32AAC28E329EA2B8A2A1A2A0F28402777261A2605276729EA2B552B6229502ABC2A9629AC298D2AC62975290128572ABA2AE528232846283E2728247427C3271D29D22719279B2A482B352C0C352B327A2E162DC62A5128D726652859295C2C4F2D812B722BEC29FE27C6268D279E27CA2A312CE32B762B732BC62F232DD029AB28EE2702274E2ACB2BEA297F291127CC24002640269528A429142B7529072B202A9F2AAB2B312A4628A32830290F2AB92A032B3E28D927B42552259127BF2776290E290428EC28462AC22BC832E032EF2E6D2D032C8329862779287329F92D642EA12CC42CD6297029A528A728E529752A852C7F2BB72D622CB82B482B9E2BE52A6928D729D12A202B492A58296926A725E82595259229A02AF9291E2A6F2B6B2C642AFA296028C5268026AE29392A92295329D328B6278725C2245326BA27E5275A2754276F289D283429973261317B2DDB2B8A2C0B2A0B2841275829832B6F2BBE2B892A5B2860284828A327A429292A5B2DD82BDE2AB82ACB2A862BA72AD829862A1D2A5F28CB2860288D265B25BF24E32366257B27C42A67294C29BC2A762B672AA6296F28EA26DA28FB287C275B26B4278E269F276325222551246824F4266E276E27092759298029B73222303B2C5D2A3629E12A352AE42817290D2B822C292B792AEE273826F0279529B629A52B532C892BF22A8F2CB629732B6A2B8C2AEE295D2AD8296F297F28C226A22656248E24AE25F226A128DE29E029DB2B612C862B532A8D29B9260B289E285D284B28C726B225AE26B827DB2409249623CD26EF253326E4291F2A8F2B6933AF30642A8F289828BC29072A80298727EF284C2BB82A7729422851278729432B282AFF29F22BB62BA12B702BB3285E26F826C228E829B229302A6A28A2274E2580244723AC23832438271B2A9A2B8229702AD22C562C2C2B122B1128CD27AF28232A38290229DB26C4278726AA241A24E52236252A2630276929DA2B512C3433A331B82A092918286E2B622A57280128D527072BEB2B822B98295828B528882A962B652CE72C182DC42AB229962A8C27B52501273C28ED271F2947285B276B27242564234323C6230B277928D32828281D29822CF42A252BCC295029AE29DC28A929DC29A62AB529122A5A28822795259B23AA23B32450241D28312BBD2A8D338131BA290629802739293F2A99280D275628262A582BC02A5129B42A822B0B2BF72BEF2C522B712CD22AA82A9E29E626E8271128C12764275B28C229952997285A265D230623E424F22638283C27B927DE28AA2B402B7C2A6C2BE829B2284029A529692B312C3B2BE82B4E2A6F284A26EE2428239A231B252A263E28E52959347431292B9429B0288D2A6C2A422920275C28FC27092A342B0C29A728282A7E2C9A2B3A2B212AED2BF32AF32A8B2B7C29022A6E2BB628FF26A1282E283528A3263B261F243B2208248326BB281026B92667296729812AF0283A2ADA297729B52A6729322A762B442A422BC92A6527C1261026AC22A3248523A1255D27F2285032C52F7B2A06275028F329062AC5297B282F27E5268C285A27AC266026E027A12A802A272A022A752A1D2A842AA929AA2A652A262A7E298428C2289429D6291429C327F4245C23BB2394262029C5278224F127E829542985273328B926D7265728CF28B9274D284C270E2850268E2690266E251D2455245024E72581266028FB319530DF299C2814260E2A192B3E2CCF2A6F27922617279F269525DA253F295E2A7A2A87297E2C272A882A10288F28B4295F2AD929462A3C29742833281228B528FF27352467225E247726D326B3288D269829252941293D289B27C3263C26CF25192589252A28DB263A281A2700285426C9267F269F2786276E2854281F2B813437313D29E82612291D2AB82B7A2A1A2C5F285827D826B4276B252726172AAA2BE9297E2ABA28562B582A7726A5286F2AA42B362A14280727F32764289427E32751253A23F4224F227B239A26D0260F261A282D28D1282029F62777250724B025DB24FB251426A1269528F5273629C82A03267B25B32660269C29812B412EE73518318A29022A4129C82B1C2CF42B052CF5282E25AF25C92563279E27E929FB2BF428C228B328382B5F2B6E286E270427782796298728EC26042779270A26BC24F524A625ED21A1229824E823EF28EE27482976294229AF2756269025BF2436256F2567241427D026422A8029852AB927B62612258727B727B32A112D3B2D4136A42FF62AE128F029142A572D932B8C2996288C268F2639256E269629932A212A982AE029412A402B532AEF295729DA283D29CC2906286D27E427D6253F252624AB227122C721D7210B24AD26B32716286929032B9E2A40298A283128DC27A9283828A7251C253627D72A122B1F2A2828E12511256226B3271D2A2D2C852DDA362830F02912290B289129EF2A302B272BCA28132586252725D026BA269529BC2A20294D2A4E2AD72ADE2AA92B71294B2B772976284B26FF2752293B29022873252A2490233522B52289234228D2299C2A2928FB284529C829E52AB8297D2A372A092961272828EC298B2CBA2AD72941280726232455259127E12A592CBC2A0B354B2FC529D727D6277029C82A852A0329DA28B125CA24B424262538270E2AED2CD12BCA297F284E28E2280A2ACE2B32296227C925772529268C284329AD271426262584211821032025250F261B290A291D286F28B126E227582A9A2C1B2BAE2BE529262940299E2A082B372A152B0029E1254324C8240E27502A382B832C0835F72F0C2B8D2AA6272F279A29802A8B2AA329BE272D26EA26152586253F29102C272BDB29A329D0270F28C5277D29342B55297827BC270D26EC27DE28F326D1261925E0212922DF216B24F6252E275026B126C8259925BF28C92BB92BFF2BEB2B592B652B4929262B9B2CBB2BBC290E287324FC23D9248126172A452C962C4734D02F5229D629F828FE277A292F2B022A3D292E28C82554264525A4244F268F286029B929FE290328FA261C27C8277129C2276825CC23F6252426FE26AD278726FC248021E42198225F246225D6254F262426162481248A27A527D628B6294C285A29E329212A2C291B2A002B70292728032456236F2541271929852B4E2AEC33162D2F29032A142AE829C62A3629312AA429DD281129A8265A27C92578278D27B429862A7F2A1628DB26CD25A127932AA8263626C3243425EB237B250D278D255E24A22247214221B6239225B625E524A626F1236224A524B22635268C27DA29DF287F281928AE278429DF2AD7292628D0247F22BA237922C0266A29EF29A633122DBF290428EC2A4F2B4C2B242B66299D2A99270F27AF279227C6257325EC27D22668281228E5271825C924D525A628AD273226A0231B2379242824B9234624452311231F216121A223FC25A72607253325832510245F248B268E251B27D9264729202663261526E4274A273529FA2545264122C1229D254126C9286C29A331652CF828242716299A2ACC2A682988287828C8277327AC26CA266E2238236A24E326CD28AF2518274B24A123212570253B2729250E2463219F24E92298264E256A243722F1218F212A26C426B827202767250C246F249723BD261F258B273E27CE287F27C4274B27F128F9268728D52680247E22F92295248F27852806299833E92DF827B1252228842ADE2B4E28792711280728B7280B27C324FC24EA2436255427392921281128A024AE2381243527F6268E27712428221023F1245225712737262721D2209A229A2342287E2928279B284D27F7245222D3259A26BC28D827A128B2273A27A325D627372866277525CA252C232124AA222E253325CA272232432C832659256926A1277228F028292732280D2843274B273726E5238425212520279628AE29DC28D22509267926A526BD26D927C1254323FC2398264C27FD261C26F322B32235226924B12607286627B42644263725A623AA240726EA27B227D0276128C226D1249025BB2648270228D0242224EF239022A324382628290135EA2A0E257D2480258A2652289425A6262C285C279827CE252F2502242424752552260228C22AD32AEA26B9242725D725982568278E24212547242A23DF26BE2607256F23A42344217B24CB25ED24282625261826F123CE24872571259D2595255B27D92667251124C525A4267728D327B324A5231224452289245125CF280033A02C112668233E266F2769278427472784284E266F268A272A256D2599241325C326F9273829802A0529C92660273927A5254C27A0259B2397233625B8263E271E260024D321C122AE24D725E326F226542711266424732311240A251F243526C22699257E24A5240D265E283F29492BDD26C924EA2356233D24D425E7290D354B2B7626B4253F24CE266727232656255F26502716267C26D5233624C3233126DD24682688289E275E287626F0263125BA2518270F241D24BD236922B42309249824DA21FD2107229C220124A525F7258D262F259822F6239723AA223923F7232E26842483242E25E525D3259927E9261226352500223023B7238E24EC260F346D2D74275C248A24B2262027432740266326B526BC244624C222F2228624CF21CF230F258525FB26E127D826F825B224F825A126C725B722982353221B244F25CD24D422A8221B207E225B23B82343245A26C126FA240224B9229622E322DC235F248524FE23B723A2250225EC26F0287725EC2367237D214E228426092802352A2CA626FC239A24C3256B277E25AE27AE230E25C1242324D822D723D023582291229F24C2235D25FA232124DD241D25802495252325D6226624A5238A24892492242F23F921B720D52109237D2336247724C726FB25E5234C226422CC22F922F82364236B23C6221025D82288250D2510243F241B2342226E24A024EF278D32CC2B29242E235B256E247A25D6241C25F02485239A2518245C22682328231D234324752243245E252024E922692479253E23372453233F220E228F216F233122652329237723CB206221A622BD23C1223C249826F8230024DE243723BE237823F821482165223C237D24E22479236925412571220A224C21782170236E25882F622CD0262723D723822561237B24172494240825BF2369235824A722EB215E247524992424240425F122C6219F239E245F23EA2254234F231D2196226B224D212C242323C221DF1F8923FD219F23FF2130248D245923D723CA24FB218D244E21DA23B7233D230822CB239423722427266424AA21F6216E210323BC2341268C31352E98266423632369250923B82456234324DC233124CE22E022AE214A22882290227C2328227A23E52274220C2388247E2404235622561F7F21EE20D4222E2231226F21FE21B721212005247F2277219E2230238F2118240D24FA22B32165226322D0211B23E320D423D723CA23BB234A243B2322234122A822A623382580312C2C2A268724F52114227222D52375233C2571230F23AC22E6216B237323C520312361221F23E0232E233D22C3223D2286225B237220651F2822B821B821EB20B721ED22C220E41F2E1FD421422098215122872230207521CC239C22E522322083227D222E22FA228E22AE22F222E8248623DD225F22B01FDE22B2235D260B2FBA2B4426C323D2220D2256235924542482240B239E2341245F22FD21A02298234923C221022201237123272238229922662309221920F820B91F2222E620CF219821322123220520A61F48213F21C220F72131213D2193212D221623E021DB233222AC20D42156231A24C421CC229A23722331224B237A215A239324DE25252F892B9126F6217921B62009213A23A6227223F921F0225F200A210B21A521212110221121202236221523ED1F322122243C237F221521B51FBE2024204A22CA22DA202D2083215A1ED01F9D20762001214321C221B6229D20FA229B21392166206E222021C51F43205E22EB22EB211E237A21AF22AB231A2219221D242126592F0E2CC725B323BD21B9226322A5212F226123DB2183220E21EE217F20FE20D02009208721FA204B21AA1FA41FC3200D22D021B8207D1F6D20DD209B2070219A21C321DA203F20491FD22044213E21AD2066205221C21F89210A226E212020F62032216F202B21C921902267203921EB21BE232E21D921D620732168213B25D72F5A2B6D244E22842202228F20F3203023D820E0217E213C21F120771FEE1F5121D520FA1F0B221F223C21671FCB215C21F5207E21E821E320C320AF1F9E1FBA218521F1215A1F831FF41E2F2101204F207620A120AF1F4320F221D01F21212F21B020EF20CA20F7205821FA212D2363201E21EA21F6215F2292224E246A251B2EB42B1125912108224D221C21FA2102223B226123F322A120C12086203B21D7217C2113226621FE20E621831FD321411F9E21D921631F51219A1F3D20F51FF821FB2045207420C1200A1FA02150219B20D4224522F51E6D21BE2040215D2170222521EA1EF1212721A91F0C217720632159213722B722A5201C23FB220A26F32EAB2BA3257622912166227122A721DE2341228E2142211F21EF1FE11F6A215F22002165218C23D22002221D217B216620E921D622AE20DE200C20D220C31F4321A5206B1E7820511F121F39219321EB1F24225F211C21B71F2422C42080233221FE20F0208920B11FFA21EC1EB1203822C9222C21892123221C238A21EE23682F012CA6257621C122F5211C22B7219B233723CA21F3215C225C21961F9C219C21AE2218223422F11FCF21A2206C2161206A202522A2200F1FFA1FE9212E201720061FD41DEF1F111F641E5C201420821FBD213A22FB1F8420F81F8D1FD71F6C204F212720E21FBF1E9B203A20C5202922F8219522E1200C207921E323CF24AE30B32CCD258423E320DA230C24A222F022E5231A2377247022A3213221A322D52071215D23032243205D214020B1214B21F1201D23DF2183205621CF1FBD1FEA1FC91EC11EDA1D491F3820A01F4620F22149226F215D211B1F0F1EB41F0120C52128212821A0207A1FAF202D20D92077224B21F5239B224B209620AF238A25D92E ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 AF287B22C522FE20BF213B2130207C20F8200020991FF01E1F1F561E4B20591E711DC51F501F311D041FC81E6720CF1EA41FA61ED11FD41F441F191F0F21731F431ED81E331E5D1CFD1C8B1E2A1EBC1E091EA21F6C1E0B1E091FB61E591EFE1F55211D21E320B81E0620571FF51D1D20601EA520FD1FB91FA71EDC2119233A2EC82BF923E6202B2309235521EE21542252223720A2217020841F3F20CC1F831FBE1E081F0B1FB31EF71E4620AB20D721361FFB204D1F5C20BF1F3F20EC202B1F6F1F5120751F5A20931EBF20951EB41EE2202F200B1F881E331FDA21ED20BD2054217221E421692099213221F41FA41F881F3421DC214F214C2243229F24962DB92B982525244B232522B821792295233D21D4232923D6224221B120F420F120DE20D021A720861F9F1F5821AB20BA20BD2132221421EC2066210E1E24206B212321072244216A210220CA202D20871F4F20FC20881F3C20FD20D11E3A2125228D228E22A72113203F211D21F520861F761FFB1FB622FE20CE21A222AB258C2F862C5D28DB245E220F23E222E8237E220A2259218C21AD200922D12069221E205C21FB20C9206A2223206620AE1FAE219C217D2285210222CA201720AA1E53201422A02173229F1FC21F3521D31F5D1F5B202321072153210A21042151221623ED236622752235216B20A51FF21EB41F3120A920A221B92262213C23E824D82E2F2DB926C822652279226023B322C122F822F621EA21D121FC20832016227C217520DD210721B72090208720DB224E1F34206123EE20271E3221062178206D20FF216F22BA217C1F9720F720FD1FBF2177205422662084203A21352271217B21E7227A22E522452018213B206F201C2094205B20292177209D2180233D249B2D292B45265B23BC2457225724BF2295228823752292224D238E205E210D2254225C228C21A02036227D2043203721CF210220A02144212D216721D7212C213D222322FA216D21AF1F5C223F2088214F2192218F21DC21C621F520BE21F620E321BE22B322D2200D21EE207721ED200F2173207B210E2362221422B8247C25602E852B5024AC239223262331236B2454238D2265233E228921DD215A21CE2207235323B22109226521C1223E22FB20A521D21F8920EF219C22B3224122DE232523CE212E22D921712149219C21A321D920452294233B211A219921D921AF201721522259205B21E12000211521B520C2204222CC206322672172234924A224562FCB2BD825B023D0249923F7219F223F23FE223D23EC20A7218D22F923ED2106222423842216232F238722D120C2216F233021B7217E22D72109236C2394229A21C421522297220222C622F4231A24D020BC234C22AD20E51FA3205A1F1D219B201421BA20E4202821D5215321B420BC216A21AF21EE211922F32464251E279E30A02A3826D8243124A72451232F220D24A524602344229D21BD21F121D32232218D21122367231C230B237221E11F5F222821A2231D2263211D2253238322A12133222D238C23CC2394230323FC21442227234921FF211D20D5224021A420E9206B219620B3227722C9230822EF200F22152313223823C8231025ED2619273032182D672410233A23BB23C022E0233A2350243D22882390223C21A7221723AF224A2354226D23D2227E22F022772005223B215F240F246D228B248C22DA21E7210522ED23772331252C2432253A2401227B228B22952182200D20CB20E21F9B2034249321C12048236F2365235E238622D922E72322248A25FD258728EE287E34792B8B27C324AB2398242F23B6232F234F230B237424F3222223F52131239F23BE2324231F247224E621F3224E212923A3219D226623872327240123C92128211B239522D223CA2590243024D724F02146225920472038207121A420C32046228222D521F42157232E24E222B12179230323A322F523E9246128BC29982A7A36852C2B26DF23062689236F227C231223722429245B2331239722432382236C24D3232B249A24922752240F25D021B622FC2392259726DF25B523A7226C236422A22117239F221C24D0246C24BD247023212306214A2199215221DA208D201A2295225423C924EF22672538252D248F258D24582439253F27772832290A2D3E36802DC5272D24F223F223BD23142438237B24BC23AC22CC24B823C0255F2532264E25CA242F24D3269124CE23CF218825A5256D27CC272A264325A8252A24C524C3227323AB23BA224A22F0239125F922342120227A208F206D224622C420B022EF21C222BB21DC223524E72444250526AC24FF24AD2827295D2BA42C4C2E1034382C512768246D257826A024632509260D26302528238623DC23D324B42655249F25C825B225F725112550230723C9238A257627DA261D267127C924B82489235825212462236F227D233123D023FA216B235A234621942052206521D4218E222024C8215123B823D425C8231E23D824E2251228A9298D2BDC2CF72CBD2D1237972BA826E425542571271626BD27EA240A276F235A2457250424AA259E25B925B4237426B627A5251024F3229C22CB23E324C2247524AC252C25822487259526DC27D124B723B02288228D2177212222AA219F221E2268207820F820FC1F0D217D228D24632628269F27E9250B25B025D9261627E42AA52AC52B7D2C4C2CB834352E372935277126B0275728F626D8269024FB241B251C244E23B426DA27BC27C5246026B125B125BD263C26D6224A23A8228A2428254E2483247E251B2607274D274F2459230122042143241E2216229C234E202A207920E5208420F6202422F7246F2529291D29252A3C2A5126AD26EF253E288C2ADD2CD62BC02B8E2C0334122D602A082B432B4E28B52641263C26DC247C2491256D247D2497253C265126AC25A62440250A25D0256123FA238C247D24A9253425DD228A249F25D3258C26B925AF2562246C2224211C20FF20E121012281219D2070217D2365211D216F233D250527382A0E2A4D2AD328F926C1231E26D7267C283C2AA52A902A5D2BC2339C2F5B2AF12A5E2881277927F82594268B263226E62462245024F92419243725E324852595266424C5237224DA239E243424E926DC26EB25DF259A24DC25E124EC2522247922B421A5235A234B2201216B22EE234E22EE1F5F236021C420C32120263826612988286A2ABA28CE2994288F274626B8259D267727EE26AB270D33002EB42B38287328882787266027B6265A263925C1251023E623D92476263F25C225EB27B325A727AE254F23FD24312772265E298F280B28F12683255226C4247A24D223DC23DE21802419247E2491218A23F521E62122216B20731F01209721B62395265829672759290A29D9276825A125BB24482446247326CE25802768312D30F22851268826122615264126352797257224AA24F1247C25B924BE286428F92771250828B2279224C8231224FC2510291A2A19282F26B5290B2780265423C62397243E24BA2480248324D22244234E23A0222B218B20F8212020E7208E22C324C6249625EE26E8287126B9258B27ED244A24DC244C24122512260D26C830C22EAF28692710270C278727E126EC27C0276226D3265125CE25D327D128DB297C29BD2C192A0D28FA258A26BD258A26AC2850289E2835270627E6265B25D7252E25D625B2252D26D1241D2413261E2398242124182341222A2000220221D1210423EA2260248F25BA271E278E268728132537251D2734243D26C52590251731B62DA927FE270827AE275F29C92A342B3F2A0628E5239B26E527C32A1D2B622BEB2BF1296F2C0129F9275026A72699269125BD26C42476259226BF24CC2569247025DA267F26B5265B26C425DD246C2582268125C322CA22E2211B22DF20CE212A234A2583250627282843269D26F7242724CD25E624D5262826F4244126CE30942DD527BD260229332B0B2DCF2C772B7A2A9E2790269626C7276928692B842A422BF72AE72AF127A025872599252925042451244E23FF2350249F2235248624DC23852513264926F5251629C927BF252828FD2646254223B1222622EB21AB232E25CD26B1297029552A462A2B2857262325F323C9244125BC24C2241225D7305F2E822880289B29E02BB72AE12B1F2BCB274424C1246626A8257628862B0E2ABC2A932BA6291229A6262E260F27CA260E254323302205243424AE223C24AC247D252927EE242023EE266D2863293B2A7D2AD3282328DE24DD2397225A222F256B2430272729EF29902A9D27802717280E274524E5249C24C7256824E9268C31162F2C29D7270629032A2F2ADD280A273F27A024CC268926D626FC27D427D828A7287528B3271929F5253425CF2695255C24CE232023EF22AA229F230C24DD257A26E927E3264E2686262927472A812964293729CF277525A8240B22FD210C23FC26F426F2277329D3280927792627297028C2250D25BC248326C3268D257630752F0B2AB5282929E127B327C12765268F251124B325FB265F273D29702AD82AFE2A17279726EF25E426A6288826F0268A2532259424E32244251C26462864288329E42AC82AA82814264A28BC295528D829A829E52669237224AA215921F82347243927502901284A2877262B273629B6294E272F25AD23A7243C2471279E31A830C82A802829263027E3263F26782543255F255C2844297628C329F72AE32A9D2A4E29D5258727F627D628CB28C229E52744257A25A823AD255E27A6296B29942B132C2C2DB529C72A7929072A172A9228CD28432786244D2362236E2106249F233A25E5276027F6266D25BF261D2887287C2791262A25682316253D267631C92F662B2C279B276E26822650268126DA25A4268F2A072B5A2E372BAD2BB52BA3290429D927F628322A7A2B352BDC2AAF286A254423B3240426DB279B28262A882C5E2D8D2C1E2A952A2329CE293529AC297529BF2794255923E7222721D121EF242824CE246526FA259F255D26592770284F27A32772256E25362590285D3392303D2A662A432AE62827261C268C25B526E427EC28202CA32BA22C762A6C2B7E2AF028C229A82A802BB22B692A1A296826D7258B233F24B526BC27EA265229DE2BED2C162C5D2893277927532600283A2AEE29DE28A4251A254921E021D722C62287236223A525C42533262427BB29DD29E72AE3281C25DE2460278B2827336B32712C4F29E8295429302ADE2636250827FA26F32B1E2CC82B20297A28A928FC28A5284D2A332E4E2B4A2BF528642947252E24B22417258826F825BD252E27E82751281A28E2261C2685260F261B28972A612A582A2D257C24D4228422C422C92316258726472756281A29BB2839294429C628DC27B425F825B328F529E6350D32482CC12B8C2BE42BA4282B262B26C2254A296E287F2AFC28C8275B25882327256827BD2AFB2BFD295928B328EE262324EF235E25782445261F269325E724FE24F7251526162629261C250E26E726BA27252A18266D24C82353234521092284228626E5276827322B8C2C322DB82B2A29B826C925BC250E29D02A602C5A354331C52EEF2B5A2DEA2B1A27052576249827E928D72A9B2904272326C827B127A0261E28312AB02BF927AF26DE24152349234C25FD2536261C27D3241D26E62492272026EA262C259E264828A1279B25EC26CF277D24F823BD2314233E23D021D523B825D426102AC52B2E2B7C2B632AC5280028872502277828D72CE92DE1354A31E92B802BBA2AAB296B279D26D1253B261028B227632645266D25EF25B32643286427C8296C28EE255E253624892247233C261A28D628962775260925E126DB260D273A262726E92537294628B5272028DE27FE244023E72219226522D020E32233245D264B28822B5D2B0E2A47297C289F2609276B266629692C712C27352631E52C962B872B36286B273E257A26A028BB28A8274F2786261327D32761283728972916285026DB26AB256527062500253327D32934280528E227CD266A28D82911293326F424E6273E27812862283A2AF1290C25B523352389216E2108219B210D241C27E1288229EC270B270027D72872284125CA25F428732A4A2B8F353831722BA329ED293729CD25DC273D27A62AD52A0A2B822AD12AA228DD286C28FA28A928182799269729122A812994296E278927CF2ABE28C9264A279728912A622A1A2A0C262B24DA26B628722903294D2ABC29C826F3248622D022392377201C23E823422587260A27D12709276A28EA279627152799258B262D29992983330A30FC2A932A28281828FA27A9298F2AA92B062C2F2D772D3F2B8729FC289728782AA729E4270B2941283829F02A5C296527DE28052B6328A9276A28B5285E2A8829C427922706241F25372A302CBD29372AD42C152BF7269A25EC24A923D62374231C25AD285E2A9E2A8D2878256F2722281C287726CD242A26AA2885296D354D31732A2C294B2795273A289229E12B7A2B032CCB2CBB2AF828002665270729D82A9B2BD929632AEF283C271526C827FD2680281A2CFF296529872A312A7C2B1E297527602583230E25E428E928CB280C2B222CF62A40285D269422ED225A22B22512242D286D2A5629BD278127382906291F283827B0256A275B287D2A95347B30CD292827DD251328252A812D1C2D102CF52A1A2B5A282F25E528CE28FC29002D812B832A012AFD298625F024092632268D27932924292D2955292A2A8B2B45294127A4250D250327372747286927B72AE92A132C84287A25AC241523482217241526D326D02694283427DF296C2B552B0D2894286126AF2622295A2C7536A82F5F286B251126E927DF295F2C912BE72D272A452AB7290529D528052B322C5C2E822BB429C02A9529C32878275024FE264127C926A827C3251227B42826283427C0262D279C254527352820273828C629C029352A992847265323CA22E1230225F6259927012736265F27C529602CB32B982AAB2A1D26CB278929E92CD834DD2EBA27E22589258F265B29F62B6F2C3E2CF82B4B2C832B692904281729522A1B2BEE2AA4295F2A5D2CE7283E270B27FF249125A5256F25AE2474241D26B9244425FF24A426FD275D29082AB2286D279A288329C7299C271727922387228F22CF2329266D28752737271A265228C62ABF2CE02BA92CAE295529CF298A2BB6346C2E47291B264E27C328A42A862CD62C032E7E2B1929EB27B8276328A828AC286F2A0B29D8253B2A1C2A042A5528A2259B2532263E243424032618238423BC23C423C6231E2642281529DD29C4276F27B9288329B229A5272425FC22FD22CD23F222C4243E262426DC26B926C9275329BA29FA29692A51292328C926E929D532C2308628BC24C027B627EF2A5B2CDB2CDF2B3D2A132A9A29A0274526602703276E27B42645272D28A129A0298A29282A7D2A8928DB2692251126C42509248524AE226D2456288B27F5285B2AE22AA4293429232A0A2B6A2A4D29F324A92230223C242E24CE230A250027AE26B0270128F1274C28CD2AC9296B2A692A9329843025316C29F127AC26BB2B4129AC2BF52B542A962945293129D72700276F28CD270427E2259626F22580267F2681262D29F32ABC2AC0291D2A5529EC27FC261125B023A823622700288E2884284E294629132A2729212AAD273626F423CA227F216522AC23EC2391255F28BC286D280A285A268727FA285A2A222A17271C287530982FC82877263F2744297D2BEB29202B792BFD2BB42BFD2AE729032B39294F298727FD27E226F225FC234E25F4262429F128A92C822BD228EC2AD129F028CB27A425FA2522271B264326B326C8282A272C27FA26D4253425AE2546233822E82277217522602592279329782AB0292D29D727B42685286927EF263F274428DE30482F3F290C27D026DB28F82919282E28592CE72BAE2B282BE6283F270F2A162BF329812AFC278B273E296E28A92825291929D02730273429A92AE82A072A3C274C24CA2504277B251426B0261C26DB264D25B12689243225F422D32295219521ED22A2247C272029132CA529BA2994293128CE2785295529F6296E2833271C30D32ED728A026EA273929732880288129742BFB2C9F2A0E2A1129B8281929AA29242AE52A4F2A032C5B2AF82A532B0D2A8C2A6F288F26482745297227F427BC24F5239A247A26F1254A25C524CA26DF253725F7259123F6235724002168227222A222442427270D28112C612B28296829F628BD29822B78299A29272A42287130AB2F092CBE2AD72AEC2C8B2C082C4B2AEF2A222ACE2A8128E5267D27EE28F829202B052C18283429022B8D2A442BBE2B892962287C263328532927295328EA25A3246A23B8253D27AC26E3266229E7273127C7251C2625253A223F23A522D22127212225FB253C28972A8329C42712296C2844278E28B326922699268227B0313531122DCC2C892D8E2CB12DE02A2A2AB02A252B4D2A8F2A4F29512959298E2AD92B152985287F2833283728652A6D2AD928552854284328392874298E27312459235223392728285D289728F027A5270D287528E8256324DA235E224322DA22D9224825C526DD26D127E52641272827182655263B265B25912547269D270E327A32D22E452D462D8E2DA52D232C0B29AA28FA29312DAB2B362A112986297D28482A08279226DB25C02473270228D02A822B3E2A672854286129B5262A25A2238023B5249B293E2ABC2A3229C72734260127E9272025F624E025AC249C228E2337231922C3244625E7267626382674284A28862699247124AB26E227872AEE32A330F82DC42C4D2D3B2EDB2CD729192AB52B342BD22B8E2CC22976285727EA283D27A72659267F27AD26C52574276C28892A372CB12AB8295A2767241F24B623F024772652298C2BDD2AB42986274726FB24A426C725B424E7268027712442228C202424E0236E26D726A7266A27E928FD29242AF02733253A27A527CD29AD34D42FD82B032C6C2B812C872C042E702CE52B122B7A2CDD2BEE291A279F268A259D273A2A20289C285A258B27BE28FF2A3B291928D9280427C325AF25CB241C23CD224D2525276528362893253E24672471263725C225FF26B8288B2936252E24FE22E22440249524BD269927B028132A592AB12850287327892975278D2A9A32802FD22BB22B2D2CFD2B3C2DCE2C092C262D6F2CF92C492A5B28F626F2261327B52616280C29082CA928CC27A32AC42C0429F629D32814283C29DA259125E024FA252328BD2634260A259F24612349234725C426E6255D25DC26FF2641253F2320231624D3246324E2293F2AFD29B62942297429F8287127B62731295D2AF933A72FFF295B2B302A142C472CA42B4829AB2A882B9A2AE9291A2930275429FC29FA29C42BAA2A4F2DE32B9429B32A892AEE2AE427B728F9280B2A9B27452772266A27EA29312AB9273326CE23E623DC237E247C25F1232225192877269924AC23C52273237224B026DD277328BE290A2912270727C52988280C2869271D2928351733A92A19297327AE281929FA2888299D27D325AA27C726CC257227212AA12D522BF22C4D2DB82CE328C628092A532BE4297A295C285F2923290A28DC271228372BEB2B422A802870258C24AE222023EF25CA26DC253727C62669276B246223FC2346228F22F825FE295A298C296C2A4E28AC26B428422634274527C3274A31FC32942D2B29E628CA29E529CE281828AE257F264B28B929BF276B2A692B4B2C382CA42B482B442A992A3028BB2ADB2BAA296D2A422D9C29C8297329AC286729B32B832B432AF729E92710257624E623F426382AE529BC288628D8295628EA25BD257523122497265D291F2A6B29A329B328EC28022BC8286527C5263B26E42E6A346F2E362C2F297026F628DA27FF28112A2E29A629592BCE2BE229C62A9B292A2C1D2BBE29992A3228B3283129922C6F2BF12B862A102BBB28F52728299B29C72A5C2CAF282829B3275026FA23EB24A927012AB3288427CA27BD29C429502709254C24BC25EF2362292F2BC129B62B622AA12A4A2D232ABF2708274B27ED2F5C32652DF52A7D2956276228A6298A2D382BA629032C3329942A8F293B2AB5283B29A228D026B226C9270C25C1298D2BE92DD62C9D2ABC276425DD241727D027A02755290029BA280C2848268B287B27A2281C2BC029412836282928A22720262624642393242525322760296B2B312B4C29F528772CB62A2E2A1627FA265030F332C72A8D2934282E287228E42C3E2DDE2D1D2EB32CD329B6292229F029CF270F27332635257926EA259B26AE27BB2A632CF92A3E2A3A270824CA2234244125E7266F28EF280A29AE28D227BA294E29B92B442C752BD427D127D125662561256D249A24C62585237F27F027DF282F28A1283D2C392E5C2DFB2C0D285927E6307331F12AF3280A27C426CF29D52CDE2DD62DF72C3F2CCD296A2A8D28F3291529E3268225E12550276E270127D128D029BE2A192A842A2326D224952347254325A9254028A72AF9290E2B762B002A3D29E229D629A7286A270226F624732467232223FB2303259424D927E0274D2882289227452C882C922B712BB027EC276433FF31DF2BE32AA128C928502BA62CD72CCD2C3F2B8F2AE027D3276929942BB729F328CD27502778299D29FA286327B728642C8C2B5528EB231024102586258B28E227102A562ABC2A2D2ABD2AC729CB285828A4268F284827BA27F826D4248B245C2374222125D824E4288728DC256228A6283B2A422B5B2B9D29E42849292533C032A12C722A31298E29A02CDC2BB92CBB2BCE2AA32A5C298C29E228F2295C2C632ACF29FA29762BD52B582C74294929FE27B8278A27CC255523CC26082784288929C52AB4290A29062821279A26F9263A28A2284E27B4297929FB282328BF2586243A238A241427ED2A292B022AAB281028812861298827902722285F29CE331A31EE2CE528CA271E279529AC2C9F2CAC2CE6291C2A2829B32A7F2B8F2B9028D12868287529122CAF2B662D522A3C28AB250D26412446237B2311263028CF29FC2AD029C229F62811262D25CA275B270629B8283F29442A532C0D29BB26DB2481257F25F8261427792A422BA52A5B2A8728B2278E28C427FD260725C227B9313731032C1D2B81265E273D2A1E2CBF2A5D2A702A552BF22BD22BBF2C3B2AD32AB429632A002A072C632AD32C572AC829F2262126BB221122DE233126D627F82855281A28A02A2827D625AE259127B326072916294428D328B62B15282E26AF2597255525322552285E2A1E2C432C4C2B3B299525F229EE25CB24E726582745316B329F29422805268C28B62C002C392B0B2B162A942CF82C952CAC2BCA2ADF27A92A232DF12B6129522B172B9928BF29EC28FC248A249F22F222CA23B52679277E282A295B280928FE25F32513279125522635280528E028692A5F2A4A2739267824012520244E263D2AC829C129742CE228892678274025D923022660245C316B31162B68264826E528C3296C2C3D2B612C912C2C2B4F2B6B2A0A2A7C29472A732B4F2D4E2C332B0229FE29D42A0129EE268326022454236E244C25EC26B7284A2A442A982840267127E8279525B12584271226EA270528612A64290729D227B7264D238A240729662B8F29BE2742280F28D629C527CC25A1234F259D264631412F3F2A9F27F627F926F629702CA22BEE2B6A29992C4028D4287B2656274D27452BB92C722D4B2A6928C227F4260B297B27F1255726E6236625DE2632279329CF2B802B4E2882266B29C0289D2502245B257826D926A826CE27DB288E2918286227392530261728E329BF299D26202709265327E127F02687256D24CA269631882DF0296727DE26602A8E2BD229352CEA29AF2A682A5327832783258927D1272B2A322D8C2C692CC929D7281C2AFF28332721273A270027C3250126EB278029672A372A4D2A1629BA27152888267623332460281B2581255A28CE28BD286027F1239B23EC25B526492BE928D5269C269C268B274E283D27AA2509272928D1321D30712B722AFC2A0B2C152DD52B062DD42AC22AA82B952B9A27A9269426A1279E297E2BDC2A182D612B1C29DA2A6A28AD28292BCA2BD8271926DA26892658264B28B2279B26A426C5272628482732276428A3294F2988277A25D824572598227A227124D6249A26E6279126A628D926DA269B287B2ACC286C26B2267C28F3301632522C292B262A842C722E5C2DCA2C472CD22A092BDE29C8298C280C27A8273226E22785279D29502AB228252755291C29DC290B2A34293428702626265C24A026B52590249A264D2787267227ED25F1285E2B5729FE286F26E122C5238422D622B123F5225E261D272429FE27D827282895283728D928FE28FB263E2734312D31BD2C1D2BBB2AE82C5F2E1C2DEB2A522CF62A142CE52CEF2A9F29E1298126EB25F42703263B2561268A25B326352754287929F52A402974289A278827F6274F27C026472628249D26DD284728B7268D29572AF9280326552774255D23B124EC2381233A251426E2284728D728532A94285B28C227D02788278827502846318430352CA72C0B2D0A2C752C6D2B552BBA2BDF2BBA2B5C2E8F2AAA290E2B4429492ACE28C026F9254126E32608265C269C268E27BF286C2795283527B0272027D8289F2664260B25B0278728C82853286D2AF229BC28AB25132873268A26AE2616251124DC24F32518291229032AD1285D264326D4240B264626FF27442AE634A533C32D7E2DF62DCE2D612D632A5F2AB32B882BEE2BDE2D362B2F2BB82B3A2D252C242C902A892790280B28F327B5270127EA273C28EA28A728992834274828262B5729862949275429C02A0C2A6B2AA62A3E2BF12605270E27A42A3A297927F12637243E263D27FF27AA28712771271E274F250A2500269728FE28DE2C3137D231552DB22CEA2CD72D322DDE2C3A2B782A7F2AF52C372C852BF129A52BD42D042CC92AFA2A8C291D28C527EA25CF26DB26A329732AB929F1296428EC28D92BEE2A482AF4286727A92AD62A5E2A452ACD2B6F295C291828BD29162A132B92295F28B5252D25DE26CC275828A728D6291928362634268F255428DC29572D97376E31482E1C2C412E842D1E2C802DC32BA32B412B132BB02A4229BC2AD72B722CA92CB72CFF2A222A28289C2BF928F8270727692B4B2B1F2A382A5B2AFD2898290629F326FE26EF25DD27B12A902B632AE029E329A729AC28E9297C2B4E2C2D2CD62A7E28B2279827E5280C2871291A2B8D2B912944280E25F92784293C2CA8367C32452E772E8F2E7A2C632A9B2A302A9B2C032B2F2BAA28DF279B2959293B2CC82CD52B822B562C532A7B29FC2AAA2A9328B52844281728AB28E5265128102868273926B726FB24362657299A2A832ACB29C928BE262A268B2A762C3B2BC52B392ADF2B6C2A4E28B4295528942A732B842A692BF3293A277027E3280C2BFF343731092D992C432B9E2BB428FA254328F42A5D2A372986268226AE27042A0A2BDE2B522C552CC92DAC2A362AEF28702852250B289D28DC26D92783265927EC265A260726AC2486244B241027A72AEC2A7029ED29F5262C27742A682C552CEC294F2A442AE22B5429902998287728AE2AE729E12ABF2A8C26882593275D2A48345030EA2DF92BDE2AF2296A2839277E29C62A702958275526BB266C28D928992B232BDD2C642CAA2B3B2C3E2CD2291B271C27EB279A285D276F2556262A254B27E629AC27BF261524B3232E268B29AD2A712B752A5B287D2A2F2CD12AC22BEB2A0A2BB42AE82AF62BDA2AFA28AF27B02A3F2AEA29E3270527A72428253528DE31BF30B22C5E2CF12A84298729E3296829462BE6280E2824273D287A2B3A2D9D2DAB2D442D882DD52C9D2CAC2B70290E2811278229112AF326A6259A241428BA29C32BF32A422823242A24602711291A28FE2908296828B0298D2B212C702A8D29FD27CA289E2AF828502B622B662805291F275828152732235E23372541267A31F22E302CB52B802B292A8A2AC72B212BD329D72A3128F927592A282DE92CD42C9E2CD42BB62CEC2C772C432D9B2A1329A428182ABD28DE24EB25302618282D28D2290D2C002B2D277F25D02901296C2AAA2A6529CF25A4267529B02A692963284C27E1279D257C28612A742C862A3B29FF263327B126B4258A254925292673302E30302BAC2C942B8D2C602DB02BEF2D4E2DFD2BB92A6829572BEB2CB62BF82DD528F92A352D9A2DB42C812A612A93289225792620269027502819280E2ADD2A972BE42B322AF22757260227A628322993282B286D255726B9277F29092AC92742252F2597253D283D2C562C932C992BD628402727279626FE250F2554260731F230542B392A652C162D5B2CAA2CDF2D642DDD2DEF2B0F2A8E288E2A6B2B572E3E2B082B922B322C6C2BEB29FF27FC274523002639278B285E2A292BA5289328332A122BE8299B285D260427AB28AB270E279F26372684271529362877282427A32447253E256228EF2A1E2B132DC22A50289929622A72274E266F24052756303F32802C0E2A932B272D2E2D3A2CB32DE02E2A2E762C052B202BFF2A5B2D822C9A2ABE2A0E2CEE2C332CF729A6287B25F8251B2662277E2ACC2C012A6027E127652859272626C8241325C725B12713263A27262783282B28A82A1B2BA4282028A026E42522274D296E2ADE2ABD2A212B432A9E2AD32CB82A36290727EF27AA318C31662C7E2B8C2BD22C4E2DAE2B832CFD2CD92CBC2BB72AE92AB22BA32D2A2C4E2CAA2B772CE32BC02BD3271B25C624BB2273251A281B29672CCB29B328A9253A2760279728F425DD244125072816272F2782283A29A428D92D7C2A7229A4276F266B29B32AE929332AB7282A28C1272127A629E42A592A4527DD25F426EB2FFB30A62CCA294D2B062D212DB92C212BC62C972C882B2C2AD529572BA82CD32CCC2A912B552A072C952B7D273525ED23652436268029822A6D2CE02AF32A8629C329DC2A052BB928F225E1241228A526222737293529702B432B512AD727272647272C2AE82BB12B242AC82852276727332781299F295227E5262D26A42623309233E72BB12BB32B7F2B6F2B162A392B1A2AB42BB72AB6286D275429992B052C852BE029F32A172CB52B632834278725782639264429A4297C2C802A0E2A582A342BA62B5129FD28F1260926492646276A2A232AC62BA12A282C632919268126EA264D2A5B2B1E2C1C2CF628A0287E28282A672BC729012774279625592731329E319C2D622B892A5E2A8C2A5F29E028D7289127B127D9231327E6279928772BDB2B662BD72A682D592B0A2A092AB8275D2657272829BA2B112B2E2ABF2AB52A9529412A1F29572676261B251726F6253728332A072C372A9B2DC6287028BC27FE269E29752AB22A9B2CAC2AC2296B2AF42AAA2BD02D2F28B7258325E12731316E32372D752C932BE32B2F2CC22A8D2C082A9028D6260B2669262428E028792C0A2DAE2B6F2C872C9D2CFB2B342A46287A263329142A142DBF2B462A08296A2857282528E0278325E0246F270D282925E827282C1B2D3D2CC62B3B282F265326AD281129A92AA72C432CD72A5B2A6A2CD72B0E2BFD2A6A28E8262629672AA733562F242C062A7D2BAC2A262B762AAA2B232A1E2954294C288B29B729E52BC32A2C2BE42A1A2CDD2B822BBA29D929EC2788267B297B29412B2F2AE927EC266C263C255D2604269627B02803290A27B725B427A5291A293529B828D526CD26CB26C329BD29A82B662B4B2A182A9328A028A22A272A02290427B9282D2A9C2A3E352031162C662BD62B662C0E2AFF29A72A822C792AE829222B452CF12C132C622B6D285B297429B22BE12A9D277E28A12574250F28CB29B32B992AB829C226D5258727AE28A3287F29A42A4F2CDF2B2D26B227CF27D428B9295A29812505273E27D62A4D2BF92B322AD32B002BA0291F294C295328B927EB27BC29D02B992CB934CE31AC2D0D2C142CA82BD72AFD29912A322C802B142AF0293F2B932C922BE42AF2282D2777285B2A262AD927F7264025B224FC2772262C28EE284F2844268E27CE296F2A082B932A272BE12A7F2AC0280E276428C42A5828442746277226FE29652CC42BAB2B0D27AD28162B562BE42B0329FD27A4277A27B32ADE2B012B9D34EC32DA2E622C112C8A2CD02AD9281729162A4C29002A092A9D29432AB12C192A242777284F295D2A6D2BEC29552966272724632666278E27272A5D282E272D29AF2B922CC02CD7291F2B162AB029DE273029C12A332BAC2AB82A5B2787291D2C272C0A2C412A9429742B8C29DA2B0D2C7C2A8B2750264028892A9329FD2A93340634D52DDB2C442C8A2C532B612A9B2970274627E3256227C225D027D52933293A28A42873272A2A532AE428C4254E25F8247A252527B129552A9C2B6C2A5E28F52A6C2CD02A2A29112B8D2AD129EF290B2A762D252B4A2AE0294028122BDC2C222D4A2BFD283528C52AC42BC82C1B2C3E2AB7278A268126302706276E27D331FE32452DB42D502BEC2AB529102A892AF3271E262427402615254325AA2578279C27FF27E527F029082A8F289E272927B624D9260828062AF82BF629C929A129FB29612AA32B952B032C622A0429BB290A29F62C5A2B1C293829EB27AF27ED28FF29AB2B5D2CD028352AEF2BAD2CEC29BC27E1258325D425C3275728902942338B33B82CBD2A952BB52ACB2B422C382BDD29FB275426CE275E2686251A2663279B273D281E2AE029FD291228C1271C265426292796296E2A6C2B522A6429A7298B28F929792B4828972A81295A293127E826182A452A8B2A1B290F283B296E29972AD02BF92A8E296C285E2849293F296726B7261E277526EB2787289A285330E032962BFE29132ABE2B8D2BD82D8F2A3A2AF32AFC2A772A0C28C625F527C7274928A32A052BD02B23297828DE28D827A226B728D729462C182B86299F291F2948294028B128F827D429BF28D7274326AC26412939298328B028D025B427CD27972989292129F0251528BE262C28C12A222AD0281B29FC29AC293E2BEA2BBD317B31022D792B252C6C2DAE2B902DB429732BEB2BB629CE2AE42A26284C26BD277B28522B4E2C752C8B2B0D2A1E293329B528742ABD2B222C862A262B0C2A7E29C4298D29FF286C26A32928294A26DA239027B229552A13295227A5256527FB266C28A727A725CB264826B72567281F2A7D2B722C492C752A192BCE2A812A56336A31732DE32B002B022D682BB12ADD293929BE2A142CB22B142BDE28F127B927B1278328B42CE82B0B2D0B2BC12AEC2888271C2B1E29BD29DF2AC52BB829E02A2D2BAF2B9029EB25482765259E27DD234D25E928BA298A2812289D2719263B265225F726E6260C24252730273429B02A4B2D112A932B702BC32BD52CB12A09343032D42D272BFC2B8C2C8E2B4E2A4C2B602B9E2A2D2C922C392AC0298D29D1277225DD273E2A722C1E2B6B293C276D26A928E22B012B5D2A102B2D2BB62A042BB42A4E2B132ABA270327E527BE274226FF269D280028032921278B24F8250B2691289E257E259B243C257E25B227E0280527D929342AD22896299B2B5F2C6333CE30122D482A752BDA2BE62B3E29E12AD22BFD2AD129E22AC42A522A3B29BE270225F525A5272B2B312A5828012999275E29FF2A672B042BD929442AE229FF2A332AAB2B6C2BA52A9A29F328C928D0295729DB28EF27F126E2254D25262698265E297E27DF2473250B254D2524262227FB278D28D227A1263F27DD28682A3D320435772C642A182B0C2C8A296B295C280029E82DE02BB82BBD2A002A262BE4278025D3274C26C82803297F2892273A288428132A152BA428A629C72A232AB62B852B012ADC288129CA28DF28012956292E2A192B9F2913284C28D826C628752AA72BE9283E26FB235926492795287D2A9929052AF728E225C327C728012AD9344833872E252B152C8B29072AB2275A273F293A2B902DBB2B272BA12CC12A1C2AD927C728D0281829422701286E282E27EF27B129F32854275529D62702293F274A29DE27F5262828862603272828FA27CE284E2983283128E827CA27A028C82A3B2C092AEB26F1247926ED28CA2A562C692ACE2A7D28C226C82745297C2CDC346632BC2C852CA42A772B2D2B33280428EA276C2A242C722C0E2C102C132D852C8D295A2B772B892B1A2AED279C26C426342AAF29F9289A27BC26FF26B7260F26C526E7261027E72511267B294A298D28D3298D2C6C2A932AEE286328462BD12C5C2A6C28C026712698255128B529ED2CFB2B182AB928E027EC26032BCF2DAD34E3306A2CB02BCF2DDC2EAB2D6A2A6C2B402B2F2CDD2A462C782CA52B552D7B2C872AD629D52B502CD72873271D25C2262226DE29E3290429432995287026D627F226ED24492734279B27072A1B2C652ADE2CD32DD92A4A2858273E27DE29822BDA2BD12858254E243E257D28522A502CF42C222B3E2A6029922A0D2B042B6B340030702A4E2ABD2D9B2CF72E3E2DC72B952B682C9C2C2B2CDB2CE42A652CE72AF9298229E22A9C2BB62BFC274B2787255B266C29E3297C2B812A47298326D6249126DF27882736289528EE29C929AE29E42C492BE72B77287428E2299E2A142BEE2BE228D0261324E4259C27E629392D532BA52A932939296E2BD32B682A1C338630BB2B382B602AAA2C5C2C172F142DFB2A022B552BC72B802A152DD82C232CC12947294D2A0F2C712B0B2B252976278827D528D629542C0B2B07283D2658259F270929A029A4280428B429852ADF29072C402C992A6D29AE292A2A1F2B8829212B782819241A231C25252806286D2A8629082AC929BA29502B672A5D2A0533F330DC2BFE2A882B922CAF2D042E612C4D2CC42B392A3B2CB62C882CE92B1A2B96298F2BD92A5C2A9829B329272E9C29FB251826DE283A29EA29CF28E0252C27562726287E29E527DB268027B828BC273D2ABC29DF29C82AAF2AB429502BAE2A382A4B2810265D22712475268F29482D912AD32A9F2AEE2A4A2BC12B382BFD311C33B82DFE2BA72B602BA92B312D9C2B582D7A2B6729622AA62AA42C762CE32A602A0E2ADC2ABC284929C829522A2228D626BD270928582BCB2A7328CC263D287D28EA297D2A9D272C280528E527F4274B287C28EC265527ED27F52819298D2A152ACC2758257C24D9244526E328CB2B102C562AEC29BC2AB52B462B342BA133FC32172E172CBA2C9A2AFB29172B4A2B422A3128C5273728D828792B712C2E2AB62A072A262CEF28F42669288C295529192752265029562B292905282C275F28302A942BFC2932292E282E2AE7281A28722782268326682731283129202CB52B8B29C22616263624BA262E27EF29882A642A1C2B302BD02B982AF22C282CF7345E31402E872CF12AF72BD32B332BB22A422A332A0D2A4C2BC42AAF2A952C022DC52BF22B122BC7286C27632B992ACE2AC5281127C8279029702AC729B7286729832C5C2BCF2A7B29CF27412840292B288F284128E4272E280329A727EA29322B4C2AA0280825A423ED25082AA82A632A5729552B402A9829602C402B262D34357031232D702CD82C872C4F2CAD2C392A70299D29E2292B2B002CBD2BE62C5D2DAA2B152AD22AD52816285C2A9C2AEB2811272B274D27792759295A28E5270628602A8D2A5529C027632726297F2AB928C627A629C12AA829372A0228A927DF28282AD22792259522B4252028C129EF2A14294229082AA4299A29352A612BB433F432042E742D152CBB2D472CF22BD92C362A432A142A3A2B922B822A722A752BF72BBB2B702B6B2A8C271A28FE2BF62A12280026B32533256127FE255E263D29D52AB92A67287D25DA26D427482802279927E229AF29262A822880273928742887291628D42584231F25F126F42ABD2B1729BA27C0274626B827B728E42709329532D42C022DC12A5E2AB22A552BBD2BCB2B122BAF299B292A29982A6B2BB92AC72B8A2CE329832946274F28C62AAE29CD295B273124E423D224B3258A257727DA297A29042814261D2691262626EA26B427532A752A9A29AA292928EA26272931290229542730240E254B261D2810298B294C2795262F28B227C32715286032F631432D462D272B002B5A2AB42B5B2B602CA12A362B752B342921288229FA2BE22BAD2B0029EF28C727EF28212C862BD9295629B924542355251C2441240A256A287528E325F22465256427D624E12505293129FB293128032958285A274229B3288A275E26F3231E25112671258A2884292B27072916287F289B282229A731E82F4E2C7A2A442CAF2CE92A582C252C442B492A252C8F2A6429242700273D2A202B1F2B062A21298B28452AFC2B032D6A2A84272825D2242D2664266926912769299629B4274325A926C728F3265C249C28142BFC291F28A5283C274F27B028E728EA269F25AF23CC24212496260B29102A6C297F292429F0289827C828CB319730EE2A2A2B152A162D112C872DD32C9229E229712B972B3E2A1828D8286C29FB2A062A222CE3289029DB29FF2B852CE3292927DE25F924F524D72427269128E6294028A725CD26A827B027AB29EC27912ADC298329B6283B2882282528E5268D2543258F2631243D25E9249E277D28982A162BA82B332B702A4A29832B3734A531F32A292A5F2C6D2C9A2CB52AFA2C7229B729D32A9E2D262BA029002BDD2AF0294D2AB327AF29DA2921281C2BDD2B872AF3277C24E623EF242B2538261729C028C82788265125E825CD289228BB27AA2929289A279A281329DA281728AE2858267A261F254324B0244B242B270A2B072907293D29B9279B29582B582ED9359B32422C072D3E2BF62C7B2C062C092C092ADA27D828992AB02C922A9E29192A6C285528D327EE28B5289328B929A7283B2679275925E123AC23FB245F250727F4284C2A3C27B325E0266025FC29F529692BD3288526D7252F274B28A328C82840283526F3265D24C92559246F27872743291C28C92818279829C92CA12DF3362931692D2E2BEB2AF228342BD02A6629CB2979296D2AB1297329BE29572782251C27B7271029A3287B26F0270229C428EA27C5272425B9237623FB218C23482514260627BD255B24D82418250126BE27E0291C2A4F2759256A26B82801297D2A952A2627032474233D2521259E2638273E277B265E267825F3267929F52CE5364432762C312B61283627FA273929A72BDF2AEB28512A7D2A6B2A2127E82534251424F12710298F298528F22838286F2B582A73286A25932538255824C924B525BF267B27DA2684266424D6258726582875273328DB252E2576263A263128A1293E2A75274325E424A82554243A2559267926D1240125B0247D266728F72852340231562C872AFB2957286C27A4283C293A2B9E29372A3C2B952A73299928BA27EF25AE2586269128E528A428442A9429AF28DB26AF250E252F253B241D238B23F5244824E8245B2393257623512593257126A32701244E2319244C260C26592884282D264024B9231523F92201268D2697258224DD23C623182505260229EF333732592D7A2D202A742805280229712A5E2BA42AF02B972D5E2B7A29A1291F286A25A9244A26EC26EB2999298429392A83298228432848252125BE239F2198226F227C229C249A231B24302357230C23FB244A251A246525DD25302445250C27042876277723AD230225C4243525D1259624612450244123E124F5259E288D324432442C382C7C2BDF29C229232AA229522A752A572A272C482BFD281327282508248523FF24E42537282129A828AB281526692506247B25FB23A8225F22CA205521DF20DB22C723CF2329238622B92321258E244224A0251523462337244724ED262D26BE241C23C42331253126C527B32536258C2531259124E82651271D32562F2F2C7F2CE72A232A0A2A1C286E29022A162A992B102B502D402AF7289E2593244324C924342519285928EE28D029222597252B25CC251C23C8228122FF2024215E22B122A5228D23AE236423CC22EF25E52405251824C223782291237B27DB2640260C240D23A0249C25D926F027EF278D251A26C921B823942560272E32882EA32BD828E929A02944292C29B128CD29DB26EB26D9296C2C552A1E2893264523EE2308240026D82501273927B22723255024C723F923412487224F206820C32043236F2391233623FB2332240B23182463264125EC23A22490222B240D250E2895239F22EB216623B6226B26CA25BF288F25BC24D225C824E3254C279D30AC2D3A2A2B2845272A279227452793273C28752622266327132A93272926A7246924E324492245258B2423254926A9242C24EB22CA23C8219D24AC218D239021962285222224CA23B425432400243424BB23272402252C2390242822A12446253E273A257D24042302250E23D9254B260B26B924EF241625602677260E27C4316A2F8929FA267826C726BC275C26A2271328E8260E2734260A27D4285A283A2658251F25AD238C25E223E22331254426562496243A234C22B422E5224D21FD221723012151228224C9239B252A255922B825E0251E245521C7235B23DE25B224C225B8243624A422902410252725CB24DE26F4248D250E237224532376254830092E7B282327B02697250226F327B22760290028B42583263F27B7260D286A254E24E123D4236F236F238225582661251224E024AF234922CA22B5235D2292217A22C6211E231F234E246025B824492348232E24A023ED211622B72264245124EA232025DC23F92190220B238623C425C725BB254325F8223424BF24EF257231862D85273127852761261B270325E0260629972798260D25A52590251A26BB25E7234E23772489241C23F7234825CF246123AA2490223F24F8225B206B224221E1201B228D238E210224522458224923CA23AE2419238023A723BC22B82243229D23A5230423582176221E222F234E244824D024F3259023D424E223BA258C2F852E3E281426EF28A3286E2659252926AA27AA247024B925FC2368253925C3248F244E233723E923AD233724CA25DB2447221324FF22E721722116221022B521B6217321C9207C215E229E22ED221223A1243624F922DF21DE21712298212D23F3227C227E21E2211B22DD22FE22D825BA23382484244824602429244A26E42FD42CEA284629F927662726264E24D023BB24962595240A254B235C242A24FF2571232C231324D4220D2404239624CD228222042424227E2231220620FB1F641FD220A01F6320F220AD2021210122FC21692312231421CD228322562181217F2241246922AE22AD22F022F121A0228522A3237F248F2268246F24F02329247630842E9C29F827B22661260C2510248A232B242424B622EF225A22BD22682480216B22AA2243222C23232472232123E3218222D623AE234E218F223B20052171218621A1204321051FBE203C21C620C7200D23D623882209226A218B218B21EA2216234F239F2224229123F721E3220B255B22F12294238922EA22E325B1259131822C862766250B25EE24F424BB2239259421BF22F722922253228723B52332228121D0225D210E2357219B21312282226221FE22F8226F21FB228B21FC212A21822180203F205F1FD82078212321432168219A2394227E21C0205E21C9210622F8227522E22101213023D2206922BE21A221EC223F23AD22C7248B241826E52FD62B7924AC235525BF23C32398220E23C1226821CC23E7226F21B32216238A224A230821822285233122FC208522552384209B218121BA20F620C21FEA20D41F7B20C3203F227D1FEF1FCF208A213B20742176232221D02089227F2159226022B9204620D020232154223622D0207D22A822D1209C218521C3215E236B24A22D742C21277523C8235325A7226723C0225623F62389227B2272235E22B521C6231E248623AA22AD239F2146205D22E4225C213F2106229D2236207D21D1204F1F4C22BD21AE201B1F3F22B520D021EC1F30224F22E020D22070223C20AA23B32064236922BC216420EA218B210D228623152279206E21EA216423AF23EF2597308B2D812649232B23DF2472225823132208239B2292224521EF21AB2074219321DC212C22022107224221B92084212323CB225021CA205D1E6920A71FA8218B207920FA1F2221AA20CD1E6022EF20C61F842047213F1FE3201621AE20E51F37216B21AC203F21211F6A218F212C213021DE2148213922E2211D22152382244730932C8E260025432264223D22F32268220224D122FC214A226F2139235E236C20C22205222222E1221222E920DF215B218A21DB21B01FD31EAD2148219F20F31FF1200422E21F5B1F4E1E8020161F4C203E211321C81EBE1FB521CE208F211D1FEE2132225D21D3210D21D920DB20BA220D21FC204D21571F87226423B7259E2EDE2B0B26D62315236C223823CB2381233F232622B6226B239D2129212822E422EB21FA204B21D421D121F720B3203321E721F620611F2920061F372112209D207220592003210E1F5C1ED21FC01F6C1FB3207A1F931F631F09203A211820DC227A21BA1FC020EF213E22E11F78200B214F20C11FA72173209622EB23BF24022EDB2BE326A522D3212421D82008239622B4223A21D9224B20F9209C2035211A21BA21ED2083217B2140223A1F71206C23B022BB215C204F1F3220A21FB22145227520751F0221FD1D381F991F351F1D204D201921C821C61FEA218920D11FA11F05229620281F511F41218A21E51FD720341FC12057225B21E3214224A025622EB02C36267C245B221823D522F1210722D122A321A5221B21F821A12050217D20C31F26219B200621771F2E1F3020C621022114204D1FB9208A2067201C2182219321D5201720C91E78206F2060201720CC1FB1200E1FD1205521E6207E1FC820D820E51FB3201E21EA21AE1FE11F47202222AD1F25218620282145215525D92FA82BA8249222C12215224A216421E422C82098214821BC20D2206D1FF01F0621BF20AC1FB721CC21D720091F3A219C205E20F120172173204920681F151F0F21ED206C21EC1E031F191E1220201F1A1FB51F12202B1F7A1F2A215B1F1C203920282068203E20772091200421E821281F831F98200421A9216222B1231125BC2DD12B2F259E211D221F22E6200122E92122221823A02256206520082017213B214F218E21F320A3204C21DC1E50216E1EAA2028217B1EBF20511FF31F9C1F5521A320D91F40200A20231E1E200620261F20229421B61D8D20B41F48202820DC214720151E10216720B81E4320621F0A20BE1F9E208D21C01F7B228F228A25222EC32BF4256E2274212B222B228921CB234D228E210621F7207E1FAF1F6021792296204221462337206F21EF202B213C204B21352240203820891F82204E1FCA2041204A1ED71FDA1EA71E6A205820EE1E32213E202F20D81E5521D61FB8222F20482015204F20421F4C21851E46201C21BC217420DC205D215122AE207123142F8E2CE325D32128239422A822DB211F246A2330220E2273223321761F7E21BA219A224622E921AC1F0A22AF20C521A82040203E224B20D61E1F2029222220DE1F3E1FF31D2420F71E4F1E3520D11FF01E69212022BD1F1B20AA1F261F831FF61F0321BB1FD21FBA1E932006207020D5214421EA21AD201A2091211424A624EB304E2C90257C23A620A123DE235422EE22D1232A23F523852253218120F2216120EF20F3227921DD1F0E2109203E21F6202220002215210620FA20211F361F7D1F861E6E1EC61DDC1E731FF71E731F32215821A020DC20631EF81CF21E491FBB20F91F7020CB1F981EFA1F801F032096213E201C238921A41F10202E23E324C02E ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 042973239F239D21A9228121E7201321A921FE201A20341F461F141F4F20081F261E29200420F71DB61F301FE320861F3F20A11FE620E52065203820CF213520E41E661F6E1E0A1DC91D9E1FB91E471FCC1E3D20F61E851E4C1F891E271EA11FE820EE200021D41EC2203B200F1F20212C1FCD2175215D2130202E237B244B2FF52BBD2446218D232C23BC218022DB22E522A320C2215F208D1F3E20CC1FCE1FCF1E561F8E1F4F1FB11FD920EC202022961F98214A203F21C8206721C5217E1FAD1FB920AD1F7E20091F07212F1F2C1F56217E20D71EDF1E571F7221A720FA1F6C20F4208B21A22052223322F320EE20B020302259232E23D523AF23DD25D12E2D2CAC25A224C323C6224322B522C823E2213F24502307235B218720FC2023214B21F321322139205B20FA213021CF201922A9220122F3216A22C81E2921F72159211722252189212820422160200020DE2093211620BF200F21A01EE920A0214F226C223F222821D822DF2286225421432141227C25F9237C2468248227C630A22C94287E25202399235923A2245B236922E72193212A2168213A202B22EF1F842169214A214123AA200821BF1FAB219B21DD223722C7226221AB201B1FA620CD217B212C22142022204821F91FA41FFD20C9217D218C21C120D520F321E1220C244D234E23A52253225D21F120432166222923DC24A6269224A625CA26E52F102DAE260223CD22ED22D3231C2370239A2398221F22A3217A201720972169217020262298219F21672152214A23421F302087237D21891E8A21232173200F2083210D224E21701F7C2009213320DB213121DA22E520EE203921E521D120572183236E23BA247F228C2312224D221022D022F7232B268525F725AD26F925F62E742BAA267E23BC2452226F24E6221C232B24CA22E7222D23C5202B21452141226D2214229F218123B7210E21F12167222920DB212F21402140219F21CD209721A321BE21FE20841F05227720CE2194212C22B922E122BC2291210F22AD21D022EB2443259B2327240924D32304230B2396221D253F2983291528E0287928C02F062C9E24AA233C231C235523A024D423572352243A23172255226F21D122DE22BA2374223E238922B323772396217A21BB1F00208121C8212E22AC21622391224621F4219C2156213A217021BC21802126231D253023C922FA220323E521AE23ED258D24F42574247F240F24272315235B24ED237E277927BD28332885264D30AE2CB326DC238D242C23B821162381248D2400255A22F4220B24B2242F222322DE23B823232488247B23DC216822D623B820FE209D2177216F2253236422A721F121FE215222C321A52268249F24AB2129259A24EC23AC2212232E210C23112499264827E426F225BB25DD2422241F24D123A923D6248A251B2843270528CF30992B3E274F257C23E823BC228E2227258A266D259B24B62367238C222F231A21EB21CB23ED23F523B523D521DC1F07223E201E22B920A62039212C239E223722702209235B2201236A2320234622B7224E24EA232C2542236825FE224122CF23382680264A28AE266627A525812460257C258B23BC23EC23E624492628255630322EDF25F42328237323AF228A243A255A27AB25BE263626C8232B246B23F822C523F322E62331231423FB22A220942138205E239C232B22CF240A238E22E122882268236822B6238C2368258524D222AA23D724A12408241D23352383210023CB27352622258E26E52651278A2880276B26C22540245724A8238A25CE25DC316C2DBD29A727D924DA248023DB24BB250427A2273629CC288C279E24332438242724C82332241E24A121B9226521F522F2204221EF2257236A2485234E22E2215223312234229023942355243D250C23A623CA22F3231F249E24472378223D24F124CD24B224AF25E0265426A9262629CE279524AE232A22EE230F25512547313B2EA828212674270E24C7225D2433255228E828D6288928C7263F2583235D24992357241C247D265923E924E021762235233C24D42514255E2341220523332277216422E420A821C2228A2303250C2480240C234024CB240D246722CF216D23792425250326FC237126D626C426CB28D7267B241023D1229B22B0223B269530882F9F2A1A28972627259B244125B3252A28AF271B27E12859266B26B6246E253425E92408243C2682249224272353268D25D925472637255A24CB2451232024CE226A23DC224121B920152315265E24CE22832458235423832412246122B3247D249025FD230A240A255F2545251626BD242A23A424CA226F233E24C726862E2E2EFE299228D8279C2701256B267828B4299C295F277925252405234324992240251226A4252026BC255F25D125352689260726E7242B24B925DE227322D521FB234523612224216522FE22F824DF23EB25E92521244C23CA227423CD239B25CD27C02591265025AA261A24E522C7239B230C248D236C238624E624D9269F31082FF8296F2902283D28802653298F29702C472859273F260B23D622892233241F24F2276F29FA275D26F425FC26A027F326E1249523F3244424FD22A2234324BF251F245823902213236523CE24B425A4259B26AB264624FB2361240A23DE24BF27DC292E2BD729852A2828582592249B2446230B25442383243826C3262630A230162BE127FB256226A3279128462A302996283B27D22404228623352466252125F028D52855285129F52931276E26B3234D24632414240B249024B7242225D2259F230E235922B122B227F8262227142940264126C9250F257B23B5231F254F281F28522AD6299F2A202A84252C259B235A24462596261B26A8260128A330632E562AD4283928BD2646272D28C3285D27A926742750265D2509255D240E256C262C28FF29042A812A0B286E2731274F254B258F246D230E268E2723286C288F272F27752529244A247225CC27F828B629262A1429AD28612912268A2435263E272427EF28E42790275826A324C2213424B92422268F27CC27B8279A292B33A02EAF28082746255227B828AF274327E926A5269026472724278B26FE2356240725E127FA2AC7292529962859269D25572327252725D42567278B27B329262A3C2A2B27C223DF220B266E27F0275327EC285B2B772A0B280729C8251D240824D1264024AE252624D025DD23D7256F245D251325292564263E274E27A22857343D2C102AEA26BE2791286028BF28DB26A82614267A287D2718288D272E27B42428257C281628052B432A95271A27CA264223F124E324C0267027F327C429A4295E2874256824E9212325432620280D26332950293C291328042627240D2443244A24E524F62560226A24462350225C22042425245924A4245A277927042A6B34AC2EC327CB25D5266F27A327A2266B27EA25B4264628472A8F2A6727A82787266625FE227426D22756266625B024372400259E243823732345284A261828BC25AF25792569239F23F6233D2596250527432855289B26C7256426F523D024362584252124AF23CE23C024CB211A225A258224F9249425B1248C25C3274529B833692E5229D4282328C827A327D6257A264E277D281F2B9C2A06294E273F265626A3244A273E256D24FD249C2620259F24AE25AA248725CE240D2555261026E426FE250626632412259724C125B2289026D9285A2888267B259A23ED2517258D25C325892393230323A42458244825B029D227C5279D2995263C279427C9288C33632F632AB52A0F280B265D262C266A26EC27F8281C28C5299A29692969278C276228922539273C2495246C2490257625C824B6259B23BF2306251924B325E7247F251B26E625B726A7279C276B27D028E6292D291A2586243425A32686260E2761265B26DB23FA234C25772457279227F627462A592A212B742A2029EF2A3F342330E02A15294F281E27B526B426F326E528F1288329C329B428F126032A012A722ACE286426FE221622A022BF233C24F823CE24C323172466241D23D8242C256A23BC2461262328B9287D2B952AFA28042B96299E276325BF26AE278228C0298B290C28612782244926A228B028EA2845298A29E52AA12BB42A932AB32A2B354E30ED2A892A8C28A0265D248D26C9282528AD26C62667277F2502287A2B8F2A922ABC2924268B2425239B239425D82650260F2500249D25F72549244D25C7246B2465251F25E825662AC82BF42A752AB22A2029D02883278C28982892286A2A6627602649254C245E264F26202810299E298129312B252B192B0729472A7334E930282B0A2AE128D0276C260626A427592A4A28C0286427A826CB2751289E2954299B27E62516270A24502477275A2852282E28CE275B2795260F27B1257525FE23CD24C0253928022ACE2A5A2B4528FE261127B0276728862AE72915299528FF2862256723FA238E2450269B266A28AA2779273529C429AE2AF8295728BC31692F812A0E2A612B2D28A9262A27E12724288A265F27BB270827A028C029152AEB29252699254125B125D0275827C5299A2A262BAC2A3F29132B072A462986266F25D924882633270E273C297E2844258526882570256626872AEE296C28222892256924C8234F22DF25E1252E279727A12614256A258D255F2704275F298A33FA2E752904282F275228A427202708272B270827B2282729D2279A284C28D527C0275A27B2245427F82606270E28D52A162B732A262B4A29632A2F2A5E29B9255225F8244E26D12456272F26EA25B6250724D525B0257326262886290B28A327AB24EE22C3230724C125AD253426FF2517259024FA24AC257525FB279529A133BC2D0B29292543273D273D27F5266127F926AC265829D728252C6C29802832278925E6262C2715292A2932296429122AFF29BD28F0263228B228AC2805279A259725CA250826A02495253F24FE24BF238824F5247425FE26A0262E2710257F24A5254A23EC229725F1262427B22669259625CA240D26AC251427DB27602B3E35F92D4727D526522731274426A226AE269F27532773263229042A692BDF28CA276927D4267F29422AF22AB92AC42964291E282F287B267F269228F8273E2559252D26F4264228512665267B2579232E24F9254B26D9271D278C27872485250E2748261A25C423C326CF286129C52878281A27E028AB28832687266A29AC2A9E346A2F5A28A523FC242026D42868276B277128B226C629402A9E2BE5297629E1282228E9275329B52CE029782A1129C42A6A28ED27C127D326C3277626772599252F26A827F1285529C1287C281627E326B9270228D129D926B9269F25C02632283829A828A5279E277329F22A1A29C227472722297C2B88286F2607280D29C334AD2EF227CB25C4254F27572607273C2982286E298726BF29422A2B2AC727E724DA25022791286E280B271527FA29652A96299E29DF291827192732267125B9250D272629512A652A462A6528E327C5266C261B2915261626BF26DE26EF25AF27CC27E0288027D325312A7B2B532BAD29C028E828072A8A281928A127A12811337A2E672B41280E295F281425BB251C26F528DB287D2932290E280728CF29482A3D284E2898289E28B7253D27822784279F28062A592930273326822381256626652BBC2BC22B24287827A6283B2776248B257B271D264A27AE2706274227ED2599262226D42468272D291C292029D6287729572B142AD428872504284F2999337E307F2BF52A5B2A87299227DA277B27C526F927282737269127912773284329BC2AB629322B832968286A2820286C27E7275729A4286C273625BF240A24D227AF2A192D112BD928E22532287626CC258127B229472AA929C029C1281A287325A7259A24CC248B26972AA62AA8292829512A632BDD2B4228FC26BF2744294434F230372D552CE52C312A77290027E7271029E527CA2559252725C1265C288F29022AA92BCA298D29012A4F286A29F827D526252726273323E2238724F523E1262D2B7B2C1B2ADB270228D025FF25B6253729412B5329AC297F290B28B1275B26EF244624E32486260B28762625256925B0289629FE275B26FF266C27002912358B30162C952BFF2C6E2CBF289F29EA299F2C8B2A8428D0256826982529287428C5282129BD298429932B9929702802285C26DE25EA267123A52277237B245E279429792D8E2AA628F2289428E727FE257628BB292F2AC72954287C28A92A5228A027A6242623B923BB25D5261325AA2571256F26DF26A325BF2587288629A434EC2DA929AD2B8F2A272B6F29EF29122B552CD62B222A3728BB256C25D625FE26D028D627C926C2285327AE27A3281D272B2572269227E2230423C423AC239C266428EC29482C192848266C29EF29A12631264C29C5296F2789277628FC28252A6928C3259F25D4268327F225DA22EC238124802525252C244A256628722A9136472F7B294A2AB42AE029C2276527A92A762CBD2C722B4B270025B023A52522274928FF28AC27AD286727A4260F262F2884270228CC2ABC2760249524AD23662776284C2AC129AE26DB2402276A26DF252E271627BF262525CE25E7237726412783290E263627B128C327F126E725CF26B22653262D26B224CA26A2271A2A3D354330CE2AC929A829292A4129AB2ABF2C292D012C312AEE25F8229E26C426D627BA2A9B2A6E2AAE299929812563265928B2281329912A84285C25D723BD24782879296A2A1829C826F72519269C27F626C928FA262C2887252A24E424BD24192523267F26C6264428EE2AD3291B2AFD29362A5327EB27AB25C4259327802AE1353B31B52B762BFA2BC22A7329562A972B4D2E002A3D2827268325B0264929B82A582EE02C2D2B772B5A29A1284E29AF28092B8A2B92290629AB24B423D825182704292A2A5A2A79272C27FD277128A829982AB5287D286E276A268E2413259B267826F725132746288029B62AC42AC92B592B482A412A3125E6267A280B2BA233CE30FD2B172C372B822936299029BD2AC92A2629FE27DE26BF254626EB28BB2A1D2C1B2DD52B522BD82BFF2841292C2BBE2AE22A95298C279F246F23FB241825EC26F9267C27E42742293B2AC829EC288529E8298029762867294926D0259526D226C926BF273C2832295F286328922AC82C762B512BFD277627B128522BE5341B307D2C1E2B602C5E2B682AD929452A062B90281725DA24CE26DB29C52BC92BD42D0D2DE529222DA52A8B2AFC2A132A422A0D2A652791258C268C23C724252672262526AD266927EB2789294B283827EE270A28EB282829992825270128302A8529CE29422926290829AE2794273B29372AE82935281C25FE24A3266F2B2634A42F91294328782A872936297228182876275126A62654276927E627E829FB2ADF2B622CF52C552CF62BB62A822BCC2B842A5F27B325CB249525792630263F2825272128AA29BC26EC26A6289F28F426262688278D29AA2B9C2B4F28172704285F2BFA2A16293E2844288426F526BB272028E327AF2741245A25932792290932CD2FEC29C22A042B572EB028122984283126E825C7266328362875276329012A692B3D2C352DE62BBA2A182ACE29E12A162989265125E2269727FF272A29D029272A7429B62AA1287F27722768283A28DB28D427F6297A29AA29022892260F26BA270C29DB2759273928A627BB276F28F027C128ED271627D6251A257E298633462ED629682A6E2C432D302D1A2A9E293028DE2732297A2AB629D629642707288628742BD12BC42AB4277F27A02802299126CF286A273F2545295029A129F12BC62B702BD82901270D260B27FA29A129C729222967284D28F128F4263125EF2589248D24E025FB253A270128DC271D293729392864275A242323A2250E2AC134B72FFD2A892BAD2CE12D882DC9295D2888290E293B2A782BC2292528CB28A327A4269E2862278C2764287D2762284C28F126F32553258A26682758288329CD296429C92A4F2A1127EB267428D428A62A1C298F294D272428F7255B26AB242124D9244725C7265F278729EE271228F6289927C8266E26B3241C25C425E6287C331A30E22A4E2A832B5E2C582BAE2A252AEE292B2BD92A1A2B5E2B112B8229C226F12409264D263327E124BE2568275F2707284326CD24DB2466257523A22735286729602A942A0A2964271D27C6299829A927CF26AC24E5254F27B624752602260E252B2538271627942A2D2A89285E28F3260A260027BC2460250428B428A63292304E2C932A422A142C3D2CD12B1B2AAD2A4D2A4D2B9229C8280A29D5288226EC2506288C242E25D5247324F5267829D028C126DE24C62587258E24AE2690289B29AE28EA281629BF278E276F29C2272926B0240326DE26FF244D278D272F272A25F72639265C28952ABD296B286B29802805266D27D125F625A3264628383397315F2BAF29DF299A29C72BD029E629B82AE12B992A2C2A68289727B0268926B9275F27CF2748272A253F255F29F42A1529A627F02679264B26BC26AE2579259F26E6269928EE2665262C268A2560254425702645266D274D285F276C28BC295F298C29DF280F290B2AD329012ABD29F728F82898288927E427FF27452997332F32162C76287D27EF272729F928BC277A29CC2A5B2C3B29DF261F2666279626F0299128B829EF27E72478275A29512D0C2C1B297C26F726F228D026C6256A24D6244B25762888251F258F2391234823B424C127D7274F29102B712AB129042B012A47277827C5276A2AA62A74298F2A282BD4295D28BB274F2AC32BDB2C32347C30B52B2828C8277329E32882260C28452B642B0F2A0A29C92688272829682B0E2AAE2ABE2A752A92286E27D929B82A5D2BF22A402946291729652830283A26B3257525F6251F264D24AB2365239D241E25A32858298628142A022C452A9B2894259E275026FB28142A812AEC29F629AF2A142BC1296128962A572B0A2C44354330672A4D298A28D4292D2BAE2C7D2B412BA329112AB8282128A928232B922A012C2C2EDA2A922AEA265D28362A682C9428782629271B279728FE2AC72A9827642406251D2594250225E0235924E325BC28912871290F2A9F2A232C4D29F32805274727EF250F27F229332BFF2A572B7E292328BC27CD27932B8C29EC2BEA32C02F182B452A0A2B9D2B692DD02C9E2B392C522BFB2A7F28FB278F2AF42BFC2A242AEB2A6A2AE52B57273A27702A792C9628AC28EC26D827B42AAC295F2A7D2873262F27D725CA26FD26B227532747272E289029B128D626DF26F4266F26BC252F25B025D225EF25CA2B252C8B2BAC2AAF280A277725EA243127EA2811290033B82E8C296A2B412B622DAA2C272C462A722CD42C4B2B112A742A002A282C7E2B552A112C312ADC2B7729772701293229B129CD26AA277527CD296C295F2A9E27B1250A271C28CD28622A3F2ACF2AF829B4288D279525C1262A28DD2525241C24B623AE240025DD268228F729082C812A7D261324EA25652446266026D5275E340632A92922299629C82B422B982AEB2CFD2BAC2A4C2BEA28DC255D26F428292C9D2A2B2CA52C242C472794264428F229E12938295A27892705281529FD29FA27E82717271627D8283029702A95293C283428D026F625AA2837279F261323C522CA2418242F2482265D295A29FB2A672BEF260123EB2495237C2644276A284A32A7318E2CAD285D29FF2A192BC32A942CD42B302C7D2B782AD8245926A0265328AF28EA28D529092A4E2AB8265828F428A22893293F2C83283829C02AE02AF528C127FB266C27212A5F2A0E294D28AB26AC26A0270C276528B628F9289125CC249526BA2627273027BB279D27C327DE288826AE2477266A2542270429A0284A3151339B2DC92B602913272D298029472C3E2E972B102B66291528F224132614255C27D726942611294C279D2716275C291A296D2AD529352B6F2AC12B802CAF2924288828F6265D2AFA2AF029F2264025CA255826B62594276A28CE286127F42595264728C42A8427C3276C267925F72789264E25C9276F266227AB2A1A2C27334732A52DC12BA82AA32798273C29F32D862B7129982ACB268A271C277D288526E926A0251A250A26AB27FD248528EE28372B582B3F2A13292429E129122CDF2A74288428F727582A262CE729622A31271A26A1282B28662857290E29B627FC2646276C28D72AB42A9E28902607275C269F230C2214260726112A862B3F2CF1331D33E82BF92BDB29B3282A263E2A002B032BC22AE128ED25EF262E28E92936282A275026592511267925C826ED275F2A082B1E2A992AF9295E29C3288A29C128C9276E27A627F4289329242987290627BA287729852B9429932A4A28D0271E29A6291E2A3B2CDF29222B56281E27F5244E23E02499264B273E2B0B2BA22BFA333631872BD32AFE28C1253A26872718297A29952801288726F7270E2717299D280A28E42756280F28EA2629276D2A062C732B232A3B2BCA289C2A1C2A1F2B9C28AC256526A728C827BD29CF2AE7281227F527E3289429292A212909283729092A8C2A7B2A972A5829FA2A032AE229E02751234D258D24F424D7273B28C02A7D363430362A862A75288C26FC257525B426D927D226BE278D26572765289229C1285C29C82B992BDA2ACF278C2702290A2C5C2F9A2CFB284F260128DD299A295429932629276A261428FC28162A532A1329A4282A2750292E2880277027CA27FB2A162B7B284B2810263829EC281326542722252B2432241E25FA26DA29E72C7C366D2F812964285B27AC263326DE23C4254A262C276B29152ACC2A6C28D327AE2A492C312D372D4B2BC328BD284E294A2CAB2C2D2B5D2A9F28F625EA28F326882561259B263326E526FA270D28F827D127E1278627672543268D2462256128292AA72BAE2859268A25112894273527FF2506266F254325FC233028CD2B3E2E1037962D8329202737279026F725C725AF25522745273E2A382BB22C992BEB2A6529602B5A2CC52C222C6A288428E72722296329AC2A982888260E2557262427612762279E26D927D72852284D28D52953282E2805276E26F52517263E247925E027492BF32BDF2AC6274128452742275C281D283F284C28822723290F2AE72C3435DD2D4429542A5A28EE284729552707252526A728752BE22C342CF42C052AB62A462A012CCB2B2A2D52282828882597266626C4287E2623259B25B026E9278929CF28B627412AE5283A2A1F2B912BF328A8296A296127BF25732796236024A1269429EC2AE329F12944293A296129822A612BCA282C2CAF277227622A372BC4337D2F5F270128DC28B32A892C8C288026DD27AD27A42A8A2C872C922BB32A26271A2A2C2DFA2C3F2BFD2B99283224B9257126B025BD271A267025AE258F289A29E02A262AE2284B293A2A532B732C8A296A29252AA629FE27BB26D9256623EF2453254E27EA250F2620281926D1266F2BBB2A562A022C752985270C292227BD32AF2FA02AC0271F29F22ADF298D294128F129652BDB29E22ADB2A1A2B4A2A372A8B2A6F2C052D632DDF2A952A3428EB248425EC28F8283A2964292C283C28F029882B4C2A002999289C2A4D2C5E2A7E2A4F2BFB29782BAA29A029E7255524FF245B26D5235524E8264927562528254D281B298E2C5C2B2B2A3B28012976293733CD2F4A2C8C2ADD2B48297429D629652AC72B022A1F2DBF286B2AA2291E2AF228012B822BE12C7C2B5B294A28C8258627B2275C29D82B802A252B302AE427A928AF29242B1929EC28DF2BD62AEB28A92659270F29E72AAA2A48295C27F9263926DD28B0269D254225072612263224812637262D283A29C42925291B28092AFA33542FE62C722B8B2B352CA6297E27332AB42A742C932B5A28D828CF27CE29962ACC2BC52C7D2B1B2C322A8229E929CC286827C828F729842B0F2B412A3B293A299429A12A602C452B0B2A292B6329CD25F82464294B28F429982C772BC32A8F2A4229A6284F27F724FD2850278226E1260827C52757280C2887270B2A1C2C9235E0300E2D832C282C722A172917278729882A562B3F2BAD2AC326E9266E28842AA32CBE2C2C2BBF2CD02B252A432C3728BD26CD281F2BD429622A592B6729DA274529432A042B652AD12A1B2B292A79298628AC289B29A12AE9298629732AC5288D28622AB628812665268B2656298B27ED269D29AE2BFE28E1275B293C2C92337E32322D6B2C3F2AE1299B295D288F28972AEB2AE029F0265626AB26B527082AF92A9F2C762B622DCD2CA22B242B1F2B612766264B28AF29712BBA2AC629652717294C2A1D2AC02B592B53290A2A50288C29A12BA02824296428E325C028AE285029D22926285B284B2799294529B127FA27662A0C2B752AD92A462A2A2B6A34C931C62D362CC02A8D2A172A8129FB28C12B622BE32A81297D278727E429FB27DE281E2CD42A0D2A302A96299F2A6D2AEF283B27A2284229EB2B002C902AC12A412A462BD32B89287D283129DA283C271D2A3A2ACD277D24D7261B269B259D2802290F29102A3D2A3F2B872988298D2A2B28FD29892BE72A9A291F2A552B28338931412D2B2DF32CCD2AF4298D29592B542DCF2C6A2A542B15282329592C062B282C3D2A3A2ABB29D628E2289429312ABD28FD264C28AE28E62B452B702A9628B1299A29952A14287D27A026B526AE267729E228EF26AB2331261225A5262028812886286229592A6D2C782AD92AFB282D277928FE28E7295D2845284929843368346A2DD72C632D112CD92A87280E2A662D562C4D2A372B7429382BD32C8E2D142C4F2B602AE52724280828A82A292C422A9B287B277E29192B402B0C28D12630291329A02BB0286A274A27132620264B27562816240C249223F7274127BD27632A5029A12BDD2BBC2AAC2AFE284628222834285D29292A542A4327B028FC33BD314F2C342B042B9A2B80297829332A852AF7297D2A09292029F628F32AE12C4D2A0C295529A6285B26D026A827282AB7297D295D28EE274729C62735279928E626512815294328E7280B27B82513265C288F260F272425122674262E291F2ADD2A922A262A032BE62AB42A382A912AB227D327A1294D2922290427D627F2336131202D2A2AB52B002A4828C6297B2AFB2A3A2AC6281028D927962A6C2BCA2A342A5E2AC0298A2903277D2922294F2A67290A2BD9286228662985294D274F2735271926B4273127A5270629B728292866285529742959271F2766287C2A2F2DC22CCE2ADF2A1C2B9F2C412B1B2BF42989293F29402908278827DD262C28CC334E31942C282CB42BC129F8277528EB28272C172BF42A9A28D828102C762A782B462A02295C29AA2BE829A528F229B12B642AF7292C2855285529D127C2280D29C4294629542983278A27B8290F2ACF29342A842AE1297A274A286228D528D42B3D2B832BC829F328232DA12BEA2C1C2A43277928FE2845271D28A22875297B33932F832BEE2A9A293F2ABE27E3251929622C0A2CD62A77288D289F29542BC429A0282728BB29052D662A6B2AD229BA2A7828132A922A3A29B52A3529042AE22A4F2BAC2A33291728D326FB28962BD12AE729322C702AA32999293F29B92A342B9C2BB429CE29DD28C12BE22C8D2BE62AE22623278328822649280F2B0F2DFC34052F552CBD2A252A4E29D627F427B32A362C7B2B1C2AC8298729F729EF281829B026B52798286229C82A392C5B2B4E298D29642A7A2BC22ADA29DD292F28202A962D122BB82A2F270126FC27AB2AD32AD22B912C192B8F2C9F2A4A285F2AB82C2F2D882B142AD52A212C102CC72AED2A7D2781254F257A270E287E2A9D2DF434562FE52A0B2B002B1E2AB529A029DB29EC2C6C2B612B272A992A642C7D2C372BDB298B28DF29892A762B582B772AFA29EB29DF2B6E2C5B2A482A0F287B29F92A472C082C192A0827642505288E29D428B12A302BF32B3E2CC02AC4296E29432B632BD12C122DB5285D2A7B2B9D28352872242C25A2245923E726892AD62B9534252E4B2AFA29802B4F2B702B712BA72B752B852D762BA82B972C512DE12C342CBD2A0E29DF29FA2BF92B3D2D852B792B842B992D2E2C3C291B2AC9288A285C2727299C2B3A2C4C2967270329AF27F929982B902B3C29E429F32A9D29DC28B3290D2C732D302A822A9729472A2A29D4276A25DE253D25E32540297D2B332CAE34DA2E2B29F0299229C42B8D2CDC2A472DCE2D3A2DBF2C422CDF2CEA2CAF2BCB2D99285629282B552CC32BDA296E2BDA2ACB28D229012AC32945296A2738288A28DD29FC2ABF2AD229E7280827F22670284329062AF5275128462880282428682733287F29C429BA29352A8729D02A7D2AF127892502250F262328AE2AEF2CE935762F372AA528522A5F2CE12BF72BD32CC32C962EC52D962C7B2A9E2B5C2AFF2D762B342AC329302B032BE32AA02A302C8B272D297F293D289E2711272E25F727282AB72BFD2AB32AE529B729502A7A298C299429F227B9276E2756251B261426E12567285928252A032BBC298E2CDF2AA4281728FB2662247E27DF285E2DC835F0307F2BBC28EA29062C092C0F2B542BD62C732D9E2D0B2D3F2B0429C329CF29B828802880282029DA2AEE2A8A2B2F2AAF2A602A48295929D3285625B92320270429C0283A275926EA26C027552981287B29F12998294427AA26C7250624B72669278327A3286A2AEB2AE72A892B572C642B3F29D0286727F028FA2AF72D9D362031EF2BB12A572A052C682DCC2A622AA12A042C162CA52BB42900286228CB2761291D29EE28A1282E2A472985281629812726293E2AA628A629512625268C242027E626D127A325C325D8265229232892271F292F29C926642ACA26F926E0278B286A2A902AFF2849295529E62A0B2B1B290E299E272727B427EA2A7C2D25358230042C01299C29C12B262DF02C7F2ACB2A6A2B612BB42A9228D2262B27DD287129322B8729E32AF32BDA293D295F28A6289B2A142CC829AC2A0C29B6285A2809286928B2286F2724278727AF2AF328DB266F279B266F29782910291D2856292F2B582C222A6A2873279328A4298D2A8A280A28B32678250E28C92A552DA6353932492A632AAF2A3B2A892AF5292F2B1D29572AF42A012A3928AC274D28D228742AAE2A742BDF2B5A2C822AE42A8029B82A6D2AB02B8B29162B06291F285D2891297C2B07292429B628632A762B392B3D2B61271127A62624292828A426D828DE29CD2B98290A28AF2765268E29962A2D2A5F288225EB23A7272328062B4236A530FD2B132AE8296429B0299E28DE28A728DE271B2969263B2823286128852AC52AB82B3E2B912D242BB12A7B2BF7293E2AE12A7F2B312CFE2A5E2A092BBD2A702A7B2B1F2A0C2898289928632A342A30290A283C267D24DC28AD266228F4281329662AFD28BC2654275027AA288C2ACF294F28D928AE2426248A25B728FA319A31A12B982A3C2A2D2B2B2BEB28DA2A4B2AA12A372A3528C1262D28E828232C9B2B922AB52BC02B322C0F2CA72BEB2A6B29842BA22A0C2D8A2C672C422CAD2B6B2BA92A9A2A6F2829268E29CE2B8B28192832296827D725A9259524FE248B25DB27EF27F2273B281D27ED263C287F2B5A2A2B285B26E524A724D927A1292133A42EB32A2D28B629552A7B2AF52877299329782B742C6B2953282426FE28CF29052BAE29A82ADF2A012B642ACF2B992BEE29872A4128DE29362B792B822C1F2CCF293D2AA329542A952A1C2A72285027B1288828F325A825392582244C25C124B526B724C826D826D4253227DE260D28F0296B29F42678243E26D4272D291335AA30E8290E29FE29FF2B172A1729A927D529382B842B822A8028AC265D274B295E28D9298D28FC28D228EC26442AA7291C292E2831278C28532A642C8A2A462A312BA32B9F2AAD2A372ADB2AD12A89261529E0291C2AF7299528E92468263C25C52621251C266525C227DD27B227F727E7286C287A27112680264E283F2B57352131492B9B285F29342B4B2B2C2A5529462A862BA62A35291327D926ED26B9288E2961297129B928FA26BC253927DF27E4277928DB248426BA28CF29D228082801295529DC29B4288F280128E2276A276928AC2A2B2DF22802280D280727DD284B288A26C7269C239926E22824292A2AE12837286327322522274729252BB1357431112C9928B028212BCD2B0B2AAC2ABF2BCE2A222CCA2A64281927D029AB2AC9294F2C272B4729D428932710282329BE279A288928BE27F7291928802620278427A527E72766254B27CE268226F4254129352B6A2BAD2998297B278A2AE82BA92941285D26682664286F2697296E2B6B2B22298327F7262C281E280C2C8236B431F22A142A012B372D632DEF2C4C2C452A782B2F2A7B2AA6278028502B742BD82BB72CC129D52A6729F6279C2632287428A728B728682A202AD5291528FE24A726C4267025DD24D727BB273D27DC27AE289C2C402A00282427FC26762B572C4E2B21281D257C25C627E3273D2A052D572D7C2BE2299E2713271728F8291B354531D62ABE2BA12BC32C902B4C2CDF2C012B3D2BD62B312AFA27A6277429AE2B662C062D652B902BC22A552AB12A122CE1299A2AC629B82A9D2BCE282D282E27CB255F2529273C283529F728BF27AF281827062C682AA927A92713277B277327BC278C28AE291327A02785272C29692AA52B672B3B299E276328CF29412D77364C32302B0B29812A9B2B002C982CE42BD32B4A2BE129DA2924282327FF288A2B022CBD2B892C5E2B1F2BEA294F2BFC2A2B2B042A5C2A942A8F2BA02A122AEF292827E7266028DF25B92834278327662637262F285B2831285D27EA27F829BC285F28C7290A2B4629C7266A252A267D27922768292729CC26C2268A28702A9833DA32012BF128FB276E29AE2A272D542AFA2AE02B692B612A4627A825F628082A702ACB2BEE2A242CE9298929162B052BE129F5290129E42A172BD629BD2AE22979281E26A7278A273C2936285D281A271C2714289B26FA25752705263C29FC29522BC52A402BC128C7281525E024C52796274A275827CF265A25F627E32AD4327F32292EC82BEB2AB82AA529FB2C7C2AAF2C372C0B294729BC29F227B62684285029282B592BFA2B7C2B89294629432A002A4E2A362A3A2A0F2A6A2B6F2AB82992285127EC276B27E82AEB2A0929CE267C2A622BCA280A267E25AD25C429962BBA2CF82BCA2A172CB129B126EB25D526D427C5280128C925A1254D26FB2798328432EA2EC52CE12959293528BF28192A852AA92BA02B802A592A8A285C276628812890289D2BFD293C2BBA29F8294D28B126EE29C127DE27BB29B52BAC299F2A652AC52A32291F266D286C27EF298427AC28D42AC929D026952644276928712A1A2AE52BF12C462A1E2C89296F296C29302B502700272D261D261928E527D6329532062F432C592BA029D4279527B62A5F2C782BD22C9F2C8D29D128E9288F2847289E2AA32B4F2BEE28A027C326BF25A6277F2A252BE02AEE2BD62BF22A452BA12A2D2ACF28CB25362637284B283C27D928BD2A1A2A8C2A6F286025CA279828D62B442AAB2BA82B782B3C2AA72A6C2A37285A29F627852585250727F8298B33D131522EFE2A192B852A822A5B28122A212B9C2A3B2AB12A74292B287F276D28D1285F2B532C752D742A9B29042BB9285428DF28D52ACC2B452A442A002AD22ACA29992A46296E27CE266427C027152830288329CD2A752BB82AF6283A271627752A822BB22B902DC52C4A2B6F292329282A212B042A56279925F8250D288431F834BA2C9529C229EC2A6B297B2A2C2945289D2A1E2964284E2664248F269526A027EE2BE82AEA2B272B0A2B812AFF29B427B7272D2963281329A7289C27A4294E2A29290727FC26C826A027FD26FF2507276029DA2A0B2BC52C3E2A7229C828BE29B829642B1A2B6E2DF12A0A291A294728E429312A63271D274C256B261D32A532832E3C2AF42A072A3F2C082B372BB12AEA29A02A3F28E0251627CF250927F526322A832BFC2AC7299D2BA72CDB2983284228D927A028C32AFC27C5285D27522ADF2933293C296D27FD2739282D26F82531270B2894298A2B242BD4298D29552A392A2C2A742B6A2C932B702ABE29C0278A28CB27CD272C28232763289F314631DA2BAA2BD828052AEC2BD32A4C2B9E29292A2B2A432A98289F262427F227C9266829C129EB294B2A4C2A502AFF29092BAF27E626E22780287E281A28F3272F299E297B294A273B26082A5529E8262727F9289D270029D729682A3D2B852A8627BA266B28572A3D2A492AB6284929B728C1252C2653275126632860293C310F303F2C122B522C262D322D302BCB2C0C2C562C112B132C0A2B6028B8272B287328AB28B1297E2A0B2832280328BE292928B6275F268527E029872A0229382B3A2BC5283C286326BD264329002BC8284C2AFD2BC228D62543274527B227EC26D12741270627D127AA287D29D029252A512A942795266C264028F727192742316330A52A8D2AE92C232BE92DA32CC12B682C5E2DB12D3C2CF02BB328C5273A2703296D2AAA2BD42AB12A9D28F829372A742993284526F328512AF52A7729AB29B12BC12B6E28762602278929E328AC272B2B8B2A082BB9284529C32A7328932699284829362B7029D02A0E2B832BFE2C7C2A8428F2252D250029B4299E286031C0302C2CFB2AF628F829702A7C2E3F2D752B132CA72CE92BE429F42ABF299029BE29302BBD2BA32CD22AF22ABA2A3F2BE22A1429FD2675284C2AC42AE12AD32A642C242C242A94273F27D4293F2A2729D72A662CE52A0A2AAD2A652A7529132619287529EF29182A282B232C3C2A232C91299B28B72520250E28DE28CC29BD325031662CAC2BAC2B2B2B072CD32CED2B5E2C592DA52CE62C0C2C9C2A20297728DE28792CDB2CCC2BAE2A75297D2E6F2C1C2995264F26C625AC28B62A0E2B9B2C272B4E2AF629AB27D72652288E29D329A52C6E2B1B2B4A2BD02ACD29BC2A56295228F8282F2B5F290B2B552A1E2B0B2D842AAE294C27BF252827182A982B01326933D62D4A2CC52C9B2CE12B9C2CE32A362D492DFE2B492CA02A922A4C29B6274728CA29682C312B8A2B5929AA280829D6297E294D26F6268526DF278729BA2BEA29DC29DA2893250728AD281B29172ACA2B652C98296C2824277E287D28D429A429A929E2290A2AFD294D29A529982B602B65286C257B259D26D828312B1F346B32F92CCB2A242D052D932C6D2C402C0F2B312A142B5D2B4E2A9E2A172990256F262728B92C8D2B17292A2706277D280B29CE28AA280527EE23D6243E270B29262A8B29C5269225D526C02AFC290A2AA52A612A8F29E928172859295C2C0A2B5529C428DD2AD129802A3D29C52A542BB32AD5297B2787255625A9294A2C70352031602CD7298D28B42BC12DEF2C832C792B302BD62A382C872A9B28E3279627BF265529442C542B5429E5297A274A299F2A752ADA294C2856254F251C277A29482B9129DC2763269726A828272A3B2A192B5C2A9D297A29C92AD929792BEC2A51294F296829ED282029DC2AA829012B722A7A2BB227B124F227DD28D62C4A36EB31912BB4285D28E529F32B582D912B552B342BFA29DB29132AA02961290E2922289728192C912C862BB72A36296928EA28AB2A6D2B3329AE276325A5261D28F52999298E28C926C827B529C32B072A0A2AF82A6C2A102A422CDD2A892A8729AD29F4279E286F271F29AE2831287F29B429A62A3C291B27BE27D22ACA2DB6357A33ED2C8A2A9B28392B892C632CEB2DE42BDB2C792BB32A2A29D427B826E42730294C2CFC2DA92E8E2BB82A7C2C982BB32ADA2AE42A94291629F8252B26CB29D22A102AD1288027D1282529C229B229C22AAF2B7D294F2AD22A072B112B0A29F0278B2687278528FB295A29C7297F29E42800293328B725AC27DC2A172C693576328D2BEC2ACC277728712A232CED2BB02C492C4A2A9E28FD25BA26E026322778290E2C122BFE2B362A002A702A5229292BBB2AA929BD28D72730279E25A82751292A28662718287028322807289129492B572C432A18297E2ABC2AD628EE274A2684267327212730299E289626512637272626362657263F2664286C2AE034E7327B2D952B0E299529DF29352B992A3C2C2D2AD329D32820263D24A42543284E29102BF629B92A09290728C6297929422AB42B1629D627A4280C2680245324F527F627F72566266F27A628EB26FA285B2C5F2BB52A9928AF29B629BF288328C2262E26F2266E267A289C2836259B255026D0242C27BE2569265428602A0134C530412D94299D29D028B0269A289329B82A842918293B260E25A1238523A1263328282A462B742A7D28962772272929CD280728D827B427532813274725FD242227A42773266B2552260C283C274C263F2B422DA92A95287F28C326C32524283529C7274D27CE264628FB26CC252F251425DA24FD25B025BB26DB2603292F336230192CD12ABD26D826D325A928162BAE2A822A8E293827012543246C2639268427C628F42CA22A952929274B2848297728E5261527D826E625ED239422812304257124CE232E255325D6240F277926582BF22A8E2A9A29B4283C268C258E26CB2653271229A6282B2A7428C32621240C25DA254A27C426782723279A29553333317D2BF329872A26281627DC261A2C422CD42CE62A132A5726E825A029682AFD28AB299D29592C342AD526BF29CD2B9B2B572AFA277B26A6260A25C42233231722ED22B623D72237238125F924D2247C285A280B2AE22B882A0E27BA243E2738276428DC2712283A29E02711274327A6232F24E524B6237826A7282A2B1034E131E42B982CF929C0296A288A28E12B812CE02AC42AAB289427B1264829452C4B296429F228EB2A1A2A8B28B3288C283328862A6329AF277526D72514235E212822D524DF224E235B2408229325FD2493270628B9281829A128DA2610254526AE278926142866271F2A3928A1277D24DE248123ED247323FD259028BC29D133C530D92C042B9E2A73274E28E627E028B02B142CDB2B2B28F1251C27F4273F29132B482AF529392916277427DD282729C229FD2A972893267A267123EB22C421F520CC218D228F229A234423192352247F260728082821283828E327482667272428E825EB2405266E295029BE27682598248323E023C422E92367269C2992340231A92C972BAE287826A8251C27272A9A2B062AC52A5F284726EC23A925D027AB27C329522978281126EE26F0253129722956293C279A26D5257824F123F22225225E221522612391226F244524C624AB23BA252F252126052792258C254A26FC25C2240025E425A5276826E62555258324F822B622AF22EB2329252826AF312C2F722B742A522AA6286D261826BD26FA29082993282227A525FA2469268928772893278726D925E924AD245126E62464251926A7251825F5243C24002371223122D91F692031204024E9227324C623BE2318251C238D239C24002673240C2657252C24DC236324CC238C238F2665265824E0224022C121DE227C23B0269831902FD52ADA2BCD2918293A28A1267026EA272228E727FE274A25E423302625279B26E925F825BA234F240E23F4236D2588254126D9275425E82487245F22F822D921582094216021A02313244D245F23DF234523C722F42465268E2458242025052635263823FB23D2243424A323C4245523C822DE22BC210623D423A126C230D12F6629F029402A942A182A6C28A2255D2638271D2667261B25A9231024A024BC24ED243525962391233F233123EB242C2428254D246C26FE24602481242723D422D8202F222F235524AB2496242E2550252E23242328256923D723A4238C224D25412518256723B623C4237A232C25F922B422CC2364237422A824E1246130DE2C2029592A362A242A942A1F273126F3251C2610277A25A226D3246725BA24B925C0259425F823FB23A7226624F22669231125462582261E247624CC245A230C23A822FC216321FA2239246824FD231D266D233923D02299231F227222E0247B237A248423C722E523D02310238E23AA23B1215722321F5021B122B1240B30372DC529EE27192A052A7529F02815266B27C623FA2372252D26EF2442246B26092568268126D4262924BA23D923D8256D2402249D23CA24AB25882403231023D322C423B022F52148222F2358249223DE238B249923F4222D242922E1226D2294244D21E5219021CD225521782301229C24C321BD210C23F6215523DA24BD2E1E2DB72834268A271028A1277026E62557266624D723DC231625572184229923A425942712253A278D247323132454229022E821D4225521E424D02240255523F923B522CF22BF21DB23C322EB221C236B224D22DF22F121C2236F21452383227C237022D2226B22FE230521EC22BE229422D8212422AB22EB23DB23B224E42F702F972838251C2608288B289D25AF25C325FB241F25F6231823E723C223F8237C25BF268C25C826F22349239E236824CB22EE229C213B2163225F232522DC23722318213D21A822F421E623C323EF20E823CC231A221A20A022F422E2246E22FF22EF21C3229C218E233523CA2152218E2325220E232D2151226321A823A62EFC2D7D278225472552259A2693278E25A42620259F2340244A243422BF231323EC23562402250D2413235D245824EA2334224E23F1213A214222EF23CC22CF21A0229C210F22D121CB225F23B82270213A21E9219D2187202521EC212D236022A621AE22ED21EB20562113213A205A22042285229F22ED206D22D4227C243630362DE1261A25E5240125F6260B250226DA260D25C024722350238A22A3226123F82234236525DC240F221822D6221923BD212423FE20F32227227D2093229421FE208A21C5227E20C222CF22C2209F21D62179223421D5219522FF2176219520702157218021F81F2721C32034218221E8200F21BA22DC20B02291227024762EAC2D1627DA235825C525BF25E2257D26062790232A238E246A22FD228F227F228F233D237E230424B4226822A023E922CB209E222122D120AD20D4212F221422E121212113200C210F22BF2119220922AF22072225219420042188218820A821302162200E20A720DA201821FD209623FE2046217B215121E0216A221825082F5B2CB32776266B23A324FC24AF249A24CD25DD258424AD246A22DB228D228224B4226C239C241323892333227923CD21C72143234721F6211B2217201220CC1F1221501F6F20E6209B20BC209D21542140227C2105201F229921F620DD204321D222FD206C2117223322CE203821CC20942187222720A8211E22F3210823FF2F5F2E2728AB249023672383236A244E24F824F7242223F82298217621FA22F31FAA21B5225C223723CB23FE225C22EB20AB21FE225F23AB20222227202821C521D420F81FF3209A1ED120BD203D203320AE213C221721FD207A208D2054209821CA21ED218421EC20722299202F2107238920AC203A218E1F6F20C42344245A30EB2C4527122418230B2388238C228A253D2252235C2331231D22FD22B9222321D620B7224821E222FC203D21C2219121A9206A2260220F21B6227A21B921E920CA207F20CD1FBA1E3F20CF20212073208B20352255219720E91F2C208020F420B321F4201321CD1FE0216F1FD120E41FFC1F622145217E20632219220B24A72EAC2C2925AE23D824A92208237D227D23F3238222F724BF23412201239822262230236F21D122EB237A22E420EF21A32227204B21FD20A8200D212E203521831F5B20A820C021671FA81F2C202E21EB1FDE201B232C202B202E221821EB216D21C61F201F4B207920A7217521E41F12216821C51F7020FA1F1E20A621EB224D2C1F2D6D28382407248524C021DA22A522BA2387242A231423F823502216218223B4238323FA22192499211B2088213022BB203C209321ED2101205E219E207A1FB92195211A208D1E9721F21F6C21911FE421EC210D202620B321B01F1D23AB1F8C22D0212921C21F30219A20B1203C22DA201E1F3B203020B2211D222024762F602E65275B249123242529229222A1211223F02295233B226122D020A3216A21C621552216210822A321CC202A21A5224F22B5204720191E6E20B81FB8214B207B201020A62053207B1E2E229420871FAD20F220F51EBF2022219D20B31FC42096201D202321B21E0121EB20BD203A20882061203721EB202F21E9215023A82FDA2C2427ED252123D0222922AC22FD21CE2381226C22BA22AE213B2346236F20AD2222226322492356223321D22126213321C721951FF41EB2213C2100212220EE200922ED1F151F6A1E4020CD1EFB1F0721E0205B1E961F8921CC204E21F91E6B217421D82042218E205C203320E62135206A20B0209A1E0F22A9221E25D52DD82B72265224A2238E2221238323BD22EF22B1213F220A2392210821F821C82219229C200821FE217222F020C920FF20CE218620EF1EF61FF61E2921E01FD320592001200121121F281E6D1F711F9C1F7520201F421F561F29200D21E01F2422C320411F6B20AC211022ED1EBD1F84201E20591FCB20C71FE52104231C24852DCD2B38278A2282229621F320062329229B22DD209022FD1F0021D2205C214A2127224921C021CC216822931FC020FF23B8226E212420801F5B20DD1FE5216622A520D31F4821261E371F8C1F1D1FFC1F71202F219921741F902178200320721FE8218D201D1F7C1F32212621921FA820FB1E2120F421D120352151233A25182EE72BC02526246A22FD22772243219A212022E920EC2184206D210A20BD203520DA1FE1207B20D020381FBB1ED51F8021E120BF1F9C1E11206C205720DF202A214121C020831FB71E1F201720F41FFE1F941F5B20C21E2820EB205820FE1E11207C205F1F6B206D200421F51EFF1ECF1F2421BF1E6520A81F80207420EC23062F732BAB24CF22DC221822F12011219B225A203321C72066207720771FCD1FFE209520C01FC721ED21BE20041F5921C3204A20CC201C211C200A20B91F0D1F2D21DD20BF21FE1E0F1F171E5A200D1F761F9F1FE61F1E1F701F2D213E1F12203320FF1F3520182014200C20C8206221351E301FFC1F64203021B5211C237F248A2DB42B3425A6218E22B6226B213F222122B6212323C522432085204E200B215F21702123227B21F420EF213A1FFC21F21E41218621AF1EF2209F1F3620CB1F9521202176208C205820621E41208320CF1F2422AE212B1EE2202E206A20B22019228B206E1E7C215620F91E61205A1FBB1FEB1FC7208D21A61F5722C7224F25202E9B2BB2254422A4213A2270229021B223B6215221CF209D207A1F701F1F2128229720392140230020DC21AD2044210D20692153221B204520A71F3D203D1FCE200620D01DE41FFD1E8C1E9A203A20091F30215A208D20041F3F21A61FA82245202220DB1F4920ED1E1821FF1DF61F0C21A421C71F83200421402255200323AB2E3F2C8225A421D422A7228622E321842316237F21A021D621B820491F6D2155213C22F521EB21B11FEA21712036213E20E81F1C2214207A1EFD1FF121B81FDC1FE01EC91DAB1FD61EEA1DDC1F911FB21E00218B21891FFE1F2D1FBC1E331FA41F1921B61F6F1F401ED61FCA1FC91F31218D204A21DF1F801FC12064237C246F309E2C6A259123C3207823D5232322C5224923E722DD2317220E217620E2215D20F120BE22A221BF1F2421DF1F07216720F61F5522F120D61FDC20EB1EED1E6B1F2A1E8B1E801DC31E8B1FBC1E6A1F65215E215820B820D11DEF1C991EEE1E8120CC1F5420F71FD31EC31F551F911FF420A41FA7222221761F0520F3227424412E ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 D228EF2224238421F82154217F20052179218E20B41F551F2A1F9C1E8120051FF91D73202E20431EA31F551F2721601F0020851F76200F20841F501F6321BC1F431ECB1E491E561C0B1D571E1D1E771ED61D941F471E071ED11EEB1D7E1D941E7B1F661F8D1F321DA41E501E481DCF1FC11D66200920C31FC51EB4210C23412E642CD924D621B0238323D3217F22EE221623E52022220B21E31F67203920DE1F8A1FE21F0D20561F0620D92069217A22D11F9B21DC1FAC2027208D205121511FA51F6720CE1F4720AD1ECF20E71EC61EF7202B20161FD11E701F33215E203D1FAC1FAD1F2120091F5620A120751FDD1F521FF720DF2147210F223222EA24402E452CAA255E2478236822FD2182229C23DC212F247D2368238721D820F2201B211D211422F3200620E61FBA210E21CE2014222F22D020B7203421C41DDC1F2E21E420FC21F9202621C41F9320AE1F571F1520C220491FFB1F7D20221E252018209A207320BB1FC41E402043205B201D1F3D1F032071228D20BE211E22BB254D2F1F2D33297E260D233623F722612443234622D721FB217121E2211B213F22EE1F5D21812157213123C42042211920FF21C1219D22AD2128228420AE1F631EBD205822ED21B6222A20DB1FE820941F371F4A205121F620A921BE20612032215E212C22AA201921F21F9E1FF01EE81E791F7120AE206A210C23972116233A25DE2ECC2D8C27732361228A226223AE22F5224723672260225122172163209B2132214D20F02152214F212C2106218423C01F5620B623CD20AC1DA82077203620692045225A229721661F20208D20851F1F21652060221E20D220452166211620D71F3021F62083216C1F9620821F0A20F11F7B20F91FDF20E11F40213F231024AA2D532CFE26DE23A324F621EF2303225B229F23A1220223D1236721C021C421F721D2219A213D215923CF214D2194221123E32092227C21E1208D20E820C920E8210F226C226A21D91F06221C207321AC202F21AA216A218121C6207D21CB20D920EB21B9216E20BB207320C5207A207B20DE1FBD20BD2234229B2163247E25522E732C2325D0233D237D2247227B23AB225E22BC231F233922A522F221F022BC2246239F2161221C22AB2388232F228222D020E0203A220A229D215721D122B522E4217722C6215521F7200C210E217A20F9214223CE209A209321D6216A2009210622002085213C207D204E20C21FEE1F5B21E01F99217A20852273239723D42E292D2F27C624F72430230921EB21D8223223FD235E22022328244B25BA227822732358222823B32394232B2252230D256A224A228C220B22A122DF2229228321802256233E23FB212122B723DD23892091233122D6200620002120200E225621B021AB2192216221E421FC20922051210721A220DE2095205323A323BA25AF2F652CD227DD2568242B243C22E52045239E244B24D1230B234C231023D923EB2180218D22A6220423532363226321B2232B22FF234F224921C5206522A321F22177238424AF23002324226721C2205E217622D720BC21F41F2123C7215D21A221F721B820D02255225D23FA20CA1FEC201E22AB203921FA20A721CD23F023B12FE62E0F2641241F24892318227D22B622C724CB234B252E249222F723362465239223B221A1222F22B122C1231E22742378222C254225CB223E24B2214221E92204248625A223502383212423B22213210422AA224421AF2081206121B9204E21C224DE21AB20A22260226F228F22522177213022B721A4210921D6238B242931E22DEA294A2740250425E122FD221F232E241B2500273A258C2416234224D7245324F1229422B5225D2192236C238B253923522329240D246B24D1224A21662261265526BF25CA24D721922122235B218C228A214E2114216822D021D521342303231322B321B1227F23B32160203622E521DD20DD20D91F4E22B72384240B31912F55291A279B278E249422DE22912207253A267B26D9250824BF2304244C256224DB23CE2211254F22DC247723C6240F254125D4257C2589232F22052384225A2455278925BE24462313225723212367248C2235233E238822932178211823B82330233D248222E7243F24C422DF23AC22712100218921B721492241264F30ED2F3D2B3F28BE25AC2443231723392272244225B625B2274A25C02547259B268C250A243622BE2370222A232523D8275A27CD26CF2592242D2461249922D0233A241628D428D8253B230F2417263C245F2304259323A7237324D92322226324452349238F219822AE23EB238323DC231E226C218B23D221F3223824A2266E2E952E2C2A4728FF26BC267A236023A9232F255B26C626152725263E254F262E24482508252823842253226222DB2375263F28DD27792500249225CC22B92175204224CF261D28992613261E2523261E246626B2261625A5246B23F623C9236624062501222F23AF222325F522DE21E6221B237123F8223E2289233D248B26AE310C2F702AB2294C274F27D924E52570238526DE243228C92AC028AE279B260E272125B72646261B231E22FF21D323F026B528B9273125242615259123FB22B7225D2421255D279A27F9265B2500258E25812571262B276F2528258F2434225D228723E7246325EB24702649259B248B24D4249622B3234C217C22D1243D26F02F8230492C67293F27B726562789267D2677247126D528222A7A29A72AEA2AD62A75281028A925E623E02448250A24A1269926A8273027DE25DD254226162554234B23B22236243B2555255B280226BA2562270324F0246425A325A223B822C1227A24B223822619269427C4274C244E25CD23D5237623E723EE224A2420274030E52E6F2C812B732AA92708288B286028D5268026A729862B002CA62B022B0E2B9E2AC9297628A32574255E238D252928792895282F27362578275E28B92767266A24BC24162501252B259F2469251C2619269E2544251C26C427AF24C822DA236224AF2448278D2638272D2645257322AC24EE23D1235D24A1245325CF286C320A319A2CC42B4A288D28842A6E2BB12BBD2A73298E29A52B802CAF2C292AC92AC02A602B042B2C2768245624D72435270227B828C927EF26EF275727A528432792267324EC220F23CE25E826E02530255026C927CB26B6242427D923F321B1211C252A24FA26CD250C288325CE272826232681248323B623A4246E252B288134FA2EA72E672BC92A302A8F2A302D692CD62BFF296A2AA428BB298D2BC12CCC2A922B082D41297829C426082317255427F125EE27B0260927D626E826562808273226B224D8238121E024A8250127E4249F27E42682266625E02316227421EC214523D425DD283F26FB27582623255C240D257E246123A4227B25D925F928B2335C31252C662B9C2A2529A829552A562CBC2A5A2930287827FC27B527602B532C0E2BB32730281427FB23B6226D2204241D2678261824B023512802262427CE242925462548230623BD222124D023DA252627282780256C24EA241E22B5212323DE244025702620283D2966267F2598270026682594244523BD23FA258E2721328A306D2DA72D5B2C402AEF294C298E2A542B4A2AB629CB265525BE26352856290028D829DE276F2542245625BD23CE23B2256A255426C525DD25CD263A26F2269726E72682251A2532234D23F1265B254C27CD26F525EF24A222CD239E22FD22D023A123C02524278D295529C0282A2B2828E3268E275723DA242B253426E431FA2F3D2C892E0F2C922A152AE729A52AFD2BA32AD826FE26CD260C284527F7271428A62539280826FF25BC245C244424972494267025392628279E250427D6257527A928F727B52671252E25902598263327E825EB2286238D23952312236F2398237C2485242127CD29A129072AEC283527FB27C22549267725A7245E266231B02F5B2B8D2BD02C232CD02A0E2AFA297F2B4B2A9729F927AC269D2549288D26B426FA25A826B1242824A0235B23582353247A266D26C2264C267E241C2603275E26442892282F27E7241E275C26392504271525E2237F2273233B245325CA26EF2597243026BA258D29702C282BA02930283426D6255B256C24592445256F3192301D2BFE2A752A452A99279927E9286C285727FE26E226C4237425FC27AC25FD257227D326AB279226A02579253D259A258726692678270927722512276F274C287E29B6272024AD2503254025D3254C260725B6253E240025F62427262C2956265B2560247E248927FB272629652939286D25AF2528250B26AE2489261731A031E62A88283627BE27D726BD2556260D2827269B27E5255124702464247F25E1253827B628B62B1B29C0262726FD249224E126BF286D2828272327B12695284428C7285127FB2538244823E124B423982439253226D625AA268A2505279D28D92909262D23C2237324E6253E26912828279125DE2539260828E627072629307930502A2728C1276A267A2600270E262F268F24CC24BE24FA23A825E826742780297128602A382B692B512B64265C259724E3268E299129262BFB29A12AC029862A9429FC284B26DA22CC235B232E226725B4255425FB249C2719260027C329EE28F726B224AA219A2462242326432713271A254925A625AB278E2624281B31E82F9A2910273A2611289C281928C3279926DB24722581256124162762285729CE2BDB2BA029D12B9B2A0329D8267226BA243C25B728FC28AC2AC62ADB2A80284E28FF27AC28582506269523B623DA233A23AE259A25F7257326C327AA2676292628EE25E5247D2328242B24B325B726BB26AD264D27002864276428E5278431E72E6F2A842717298329EC2A442BD42BB5292727E626D124A328DC27C729932BDA2AE02B6C2A3D2A1729F828F827622640251024232427279C28DF285E2878277B278927AA26A524612587237D2477230624B623F423EE24F324C92565243D2539279F2441234724D324DC25242772274D280527F2282629722A7F291B2BB433CC2F582AAC2B622CD22B322B4C2C082C432C452AF1269226B2253A29592AE62C022DD92A132B3B2958289327EF26E2250C247424E8220B248C26D2274B266D27A9275B2758274924AD247724C32283241D26AE24A6240B24AD256A2399247A250625642463223824CD25D4271A293D2B862A8B2BF42ABA29692A042CDC2AE4339B31542C6929FC2A762BD02DD72BBD2A622B7A28FD28932654253625B327482ADA2B752ACA29142B87274E278925E62626232A23952369235925DE259326F126B626D626D826892546244B24FB23CB25EA274427BD2743242E255424E0244025EB25CB2534250F2565260F295B2AD02AB129302AEF2B5C2A882AF72BF22A4934AD30082C1A2B522B502D1A2C6E2B232B162973298225D725BA2347240C244F249F265C274D28A327A1264026C0270126F223C3231B25BE23C125B9264C278527502727288727A3258E24A522E9230A25D726D42917279926E526B826592520263726FA27AA26F42384278129BF2CB52BCF29A5282E29AE29FB2BA42BD22A4C33FB2FC52D122B9F2C072D032BD72A2829272A382A7E2AC92708243F2430268327F725372789273A2883260E2805277A24DF23AC255126A8264D28B6260E293729E72BBA2A642A66269A242B252825782481268128B426D5273528AD27DD27F626DB285C294027A8267026E7267829932A032A202BB7299D2AF129A82B002B3733022F022A1F2AF529C92A302B162CDE2AD729EF2A232A062895260D25A82471253726792531287227CF275428E726632481234B25A72620293F2A352A712892291C2BE62BB529D926B623DC25A8254D274329DD296528FA2662276A27B2274D269528EB28F0273D26DB27BE279F285C29E52A522A492BE7290C2B862A70297032282E702947288029D629BC2B062A422B922CE12B912A9B2987272526DB25B7252D258F2771274C284B2A28297829ED25E6235325AE27FB26B829B52BC829F829612C8A2BB52888258C256E237625D826E02A932B4527C7256026C9252D260626DD26E32723286827D3266E25F92622281D2B452B7E29292AE02B1E2BF4286C32502D68279F250A290E2CE32A792C772BC92D452C142C162A49292A26C7261D27CC275C282F29CD2AC82DD92BEE290A29FA256D253229EA28092AE52AE62A632B3B2B5D2C21282F24FA241625D3255126DD29A72B5B2924279624B425D8273E25B226DC25022572241625EA269F272C2A8D2AA72AEF2A902A302B032C93291F32D02B1927CC271329E72CFA2CCC2CA62BC32BA52B162C5D2B5D283C26B2266C28D02B6E2B8A2A702DE12BFA2BE82B6D290126672669293829772A772B432AFE2A112AAC29A5297B242B22D4257727A126E428D62CC82BD72799267D2784273E28412692253A26A226B2262126FC25B228452A922B102BC629032BAE2B522A4B347D2D5227CF27652A2F2D032C3D2B5D2C642B722C432D342AC627582497268D29622C4F2D642B022D362C702BF829AB2A5227F625702ABC2AD72A412B6329642A0129FE285E27922323223E24B6246B266F2A692C242B58281227A9249B267E261E28F2234225DE25B0244E254027F729962BFE2B562C3D2BB82B622A2E2A2933DE2D2C2806270D297A2C842D5E2E4F2E3E2DC62C592DF029D626EA27F6263328262BCF2A4D2A542A152B7128C42880292E27D7259428C829062B262A67297A2A5529FA2826281C2530245E23BF24CE245029442A2D2C07296F262926882697259C253C258C23C5228B243224E1273F2A652C822A232DE12A7E2A1A2AB82AB834212E6927F4254A28052A562BCF2B322CE02E8E2B492C082CB3296F2720279D27DC2A102AB7286F28C8272429FA2A0528EF27FB250926BD299A29FD281C292C2852280F29D429B926AE256125892448252E27F726A028F82793267A245C257826ED257A249D239B22A822DE235926B129A22A5D2A2F2BB0270F296229632BCC33FD2DDD2671258B259125F1262C281B29992A012BD32C152C78289924892472255E266628732747272E29DC281F2A1F2B06285C251B25BA263E2790260D27CE25ED260A27CF270228AF28E0279225E4247A25DC254D2532248E256D23942326245824682451248E230824A3227A245F27C629122A782AF128DB281E291A2B1335622E742993260027B226BF26C6270129A22BDA2ABA293E294928F826C02588251B29022AC4279B2A8729862A992B702AEC28C02699237B2453279724B125A426AC2636266C2774280329482ACC2738262C26402597240E23CF22CB22E124872617257D2564255425B22595240C25B226D6271828D1270C27BA270128C52B5335CF2F51287D247E26BF2406264827BF29ED2BC22AC42A192A85277724FC247D25CF272A2AA32C0E2C252C0B2B8C2B062C7F2A93262024EA221024D624F32450272227A7276E294F270D2887294729CE264E2509251A2592247A253224FB24EC252228F226E62418251326AD24E4243D2656271F28F629D6283329F12ADE2B3533163037292A27DC24FD27D5235D27FE29BD2A95290128F126EF24D8230B2533257627B8296C2CC62BAF2A762973283429BE282E26B1244B24AF23892411276B286B28802791285427FD26D825EA252D256B25DE237A245F22B723EF24832638266527BD276526302565259A244E2484255A260629912A6C2BAF29A627C429663309306A2A56281C2704273B282227FB28B329D6290B28562668257426AB24492589256B2A452C602B6428CD27F7273E284D26092A8C28BB237B25BF24CC268A2ADE2A2A2A8328BF24852489245126F0243325A8245023B5229424932543274029BB275D275928462719266F24B4234A258126A4273A2A0629692618272E2A71348E311B2DC62A61287D28AE29482805273529B927BE26DE262726E82629290728652675294C2A9D2B192C692A082AA029CD286728EA277C279C25102544276A28FA28B229A728FD24A325A126D42542277126A527A924DC249B239826EE2743288628F3285B2A4B2A022AEA243E24D22555256B260228452794271327F22819339632892D572BD8291229EF283F29172963288C28922774286B2AAF2C9C2C522AF7283829E42A052E932B892BDF2BEA2AF02BD42AE82AE82927287D237E26EB27F3294F2B922AEF28C427AB26FB28E7286A28E828F2252B258F26F725122AF22A632979281429AE28132B22297226172890272A27D628E627FD27E129512A52346832002F0E2C29298C285B277D27A526F026B62609293929AA29542CE82C112CEB2A5E2B4028032A912B9C2A5A2B812C642B412BCF2A742B8B29F226C1266F28232A292A142BF22AA029A029C62B9729D2296B287B27CB25B923EB27EC29782A39287228CC266328712AEB280627CB2934299427BB281028BA28BE28A82990347432AA2D962C5F2A4727B7265C24F824D026952822298A2B1F2B0A2C962BF32BDD2BDD2827284F294A2A472AD32C242CA72AC32AB92A352A1129E4275026B1253F282B29782BBD2AA32A322B322AE429EA29542A5E27C02429251826D228C62A3F2AE22A7A29FC28142A35297A285028F127EB287729262A062BB72AF12A293484322B2ED42B172AB8283F27DA25FC23EA25E627632BE22AA22987293D2A0C29982AEE2659276627F2274E2A282A452C662B3629732680262528AE256A2545257427E428212CB92A532B2D2A662A8229D029832A32270525D7257D26C927D62A312BA628C0280328552949294C27FD276C29DB29AA29CF29F92B412CC62CA133F0309B2DCA2BA12B782BA5295D26A426802858288F29072A0F285127D827C52865264525C52589289829E6297529F027F6287729462885279A2615262926FA2553282D2AFA2BC22BC02A462A9629A829C4285229BA27BA2303251B27AE2756286F27382AA028A428E7276E27F82501261D28E32AB92BEA29762BC529A32A07340632522D602C172B032C2E2C142DFD2ABC298B28FB29AF2A2E2A9528E928A4276728D2290F279E28A927AB2A632AD72AEB2732271D298528AC27DE28ED27B825F1250429672AE32AA22A14294D283C28072A8C28FF268926042643287C274329FB28E32965287426EE26E7253A253B26D02655284E2AF12A612C2A289529EF319733352F432D0C2CEC2B352D5D2CBA2AD62A5B2ABF2B122B042B6E2B842B222B9F295E28B826CE292529FF29902BD82A5528A82AE42A562BBA2CBE28BF2712265927AA2AF52ACB2AFA29422AEC286F285D29CF2AB228DA254725A8256326DC2610278627C526FF2347272A26582555259A255A279D275427F227C628842803323333F02D3D2EB92B642DC32C0C2B2428B328C429512B7C2CD22D092CE12CEF2B0C2BE32AB9277029BB2A282A1A2A7F287928EB272D2B662B1D2C2129992859268D262D2A392CAF2BFC2B7A2AB82A012A192A2D2AAD27A526F2262925242412252325CF2565256625802409252627D22636251425FB277C267927B726A1271234ED34292D402C602BF52C4A2C772A322A9427EE257D28AB29342AA62A1B2BE02C4F2AE62AFE29D72903284F29042AA429EC274828542886295029A228972715261A286D29A52A332B942AE82A5F2911296F2A702ADA272C270725AB241522662344262825EF241D264E27F0250D28942ACB281226FE27D426B0285928B428C331BE32442E812B742DE52E452E1B2CE429A0261626B427AD29E927BB298229102AAC29E52849289227642A1E2A6A2C802B5028B427192A4B270F27152747268525C4268E272728CC2975291028CA2700274C298C2A00292F27A1259625642376247327142758277627D1278727AC27732964296F28F02A0C2AA72AED2A12292830ED32362DEA2CC92CBA2C2F2F0B2D342CA62AF8275828B0292F2BF128D729EB29902CDA2A5629E72AF32A502DCD2CA12D142B722A7C289D2802289A284629BE274C270829F3267D28F3275B27642553267128DA29AA2867273427C127F326BD25C6261428C72AFE27BB29C6291529072B822AF129842D232C9D2AA32B972B7532CB30312CFB2A5C2C2B2CCB2D032D6B2DED28EE252E29C427BC29232A7F2B632A462CC02A6029D1281E2B99290B2D672C8E2DAB2BEC281C2794275F28032A8029F2276A280727B527E72704274829E7270128A32A412AF529B02A2C2A5B29852759263C277729B029E6280A29F32ACF2AE4276F25222A792A812B7929B6291432AD32102B402BDA2A092D0A2C6F2EAB2B152AB529D0296229272AC129052B9829892A9F291C28B9279A27C328D029BD2B0B2C572AE829CA289F27A3274D28E9264727AA270528BE272328C7279B29B028F429412BFF2B142A632CC22A052A0429EC262C287E2AA7285329E6275528E0272726C2279E29DE2ACC2C092987287031B4318D2C5C2CB72BA52B032D7C2DC52CF52AA829222B1D2BC92BB928152983289528D1279927832755279428182BC22BF72A8729EA296A289B297C29EF29F327D6255127C5294A29922A2D2BA029FA2782286829602A1B2B8F2AEC2AAC2A7B289B261E2790294A295B2A682804285A285E2535273A262026F827D02672282734DE31E32C952E2F2D6E2D122E922C1A2CB02A1A29262AA62AF82AE329DE2981288829E92A4329B828EC2616282D298F2B552D352A5527CB259F28072BE92A012BC4289B291D2A382B972BFE2BAB2A8B2879280028092BB62ACE2A6D2AFC28EC281A271F257D27912635296727EF2400282427CA252A24F923D824E6267B29503440324E2D7B2DF72DEA2DB12DB22AE82A75298B28C629B22BAE2B71283B273A2A7E2C482D522C3E2AE6273E286C281F2A52298D271027DA270E28762C892B962A2F2A1A2BA22A092BD92BB92B0B2A2C285A28292AD1291B2B6D29E2287C29602933298326F724042571271E2716286D285C28B7264A253A222A241327102A443564309E2D1E2C972C772BAE2A4C2A3B29E428EB268F289E29F72BE52AC329A027C2296C2B2E2C472BA3278127AB265626A625EE25E5248B266B289E2A022C212C9B2C872BE82BA52B172A2B2A812B4428F027CD28D429F92AFD2BCD291029FA28862AC229BA27B923A4255B269628B62AB1292F28E626A425C525CD24DE28E4333A30772D682EB82AA22A2B2A4F287D258E25352638272F282229682A2A289227F326ED27DB272729B52553266724DC24D023602535242B257C28102AC12A292BDC295A2A452DE029282AD929982A1C272028F2284229092A562DC3290E292D29012A2F29CD25A324132524272F291A2A2D294925AD292F26C0253A283128E031ED31792BB92C0C2B562BC92BDB2781259525FA24C9269627B127F327F1274824B1269C27CD270B268B27FA254B231B252325C32333269B263628C327D5281B28D228E129322B102CD92A992ADD2AA927CC27402AA22BBE2B0B2C5D2BAE28DD28BD27B727A92417248926382691271A2B94281E26672860284C28132AF12719338331C12C9029772A812A2E28042726254A25AF259424DE258F2521265B26D626D3254327F327C028C126202753260A247F234F250A25F126BE298129E227AC267B274A285028E328822A042B42284527E7282D29D52BD82A932BE3272C262426B6267F237B23AF2564269525ED259A28EF27322906283929B629112CA52BA4342931382D722ABC2A9227292707271C2569248F221D270825FD276D2674276C262128C4272D297C284F2601262D251A272E256124D625F32504297629FA260726EB269427AE269427892A2F2989261024C32551282F2940291C28A8261F269C243B267524B82321232124AB25162608292628B1284229A32A202B422BA12C2435852FB32C212A872871283426D423F52504234F2486253126A429F429B02B882A822AF62A6B2956292727A9267C296529AB2604259D24BA26E128F7284E28C2279A27FC272729FE272E261C274725F8223023CC277D25E52617299728AB27E026D8249324A524F6226126E8250D28022BDC2BCF2BC42B5C2BF02A752DC22DA0354330D72B752A8429B727EF25642404262E242A2409263D298B29802B7E2C7E2CBB2CAA2BF4283E29BE27B926112BC629482956281227C8243A27D929C329E8271D29452A12299C267A25BE25B2256725B4255C26E1261527B626CB2622286726282785286C262025E82484253C2B602CA02C5A2D5D2ED12B5F2BE62CDC2D8E33C930E02A12292C263C265F271D27EA261627FF24FF24392576288C2A3A2C402D222B402BBD28422925290529EA297F2C9F29ED278125C324CD261D282B29DD270C2A372B3F297528E425D62373259A24EA26AB288D26E52700273D265C29FD29832A332B0F283927C9256829902A162CAC2CEE2C0A2CA02CBE2D9B2C5E2C0A344C2FF929AF279825C9264028F72867280D2AD5274826C32615271A29BE2BCB289728F62988272C260428B328652AB02A442AC128612770244A25FE263C28092AE02AFE2A542A0E26242505268F263526E6294E2A5D296A2744297A29FA29972C072C822B252BF5280529AD28B12ACF2DFC2BEB2C002C782C732CDA2CF82CC833312E07299227F026CB267828B429CE2B1D2C3B2AE1267827BB25DF27682B3E2A122A1427C8253B26C9279E29692AE4296D28832629267C23F8242A24582514262D28CE260E27EC232B247724D925D426512A872A9B2A1329862A1F292B2A2A2C182CC52AF6294128D3286729482C212CE52A402B1F2A5B2BE32AF02A142B4D342131922952287C28F629142C962A272CB62D5F2B2028BF27B9269D291E2CF52C6D2AC8281327412598275C28512AF12AF3289126CA2482245524F82301226A23B426BE255827EC23E124CC25C6255A2629270A29E0262728DB27312A5629042A952CFF29D12AE028D7266228F8292C2C292C642B4C2BEC2B782CB929EA2A01353D2FE328F52640280C2B792C0C2DA82C562CE12A5C2AFF273F27E027A52A722D902A5A280D28FC271F26E5250426AF280428D92792257C24E924C82382244E264C257626D226C225FD273027BC2654269327182696274F27B62860278F284A29092B4D2B3D29D22781269B27EC294C2D1D2B9E2BC32C382CBE2C872AD52A0335892E5629BB26B529C52BE92B722EF62C222D272C4B2AE0282C265E29822BB62C0B2C992A302934291E279A29BE27EA27412746297E262D2540268B2775268F261E2675256B281728A528B62AB12A51295D286C280A29E8288729D529B82A4F2C642D002C282B24297F288B277929502B882CB62C5A2D702BC12C662B402B8A35CA2FC6295E299D2A902B4D2C282D0D2C982D8C2C192DA9295A284E29C529832DA82C3D2A85294A2B492A4F29412A062A7B27B12605254025E32696264729A429D929CD298E2B812A9B2AE12B292BDD2A1E2A952944290C29F02B142CAF2A7C2C442C042EE52BB228272A76293E2CDE2BD82AB92D8D2EC22C202DF82B952B5234552E3029C328EA280E2BE52A012AAC2B662D192D612D052A5A282127FA286A2A7D2BEE296729152BC629152A4229AE285D2469260626FC24EF268127B629052B8A2BB62B8A2B7B2B2A2AA42AFC2B862A1029BA291D283B297C2CE12CBA2CFE2A5F2B1B2B392C4529C729ED29012BF82C832A4E2C9A2E4B2C742C992C3D2CE133BD2E792B492A272B7C2BA72ADE2A972CB32C792C782CEF2A0F287226FE25072918289B2851271D279C286F2A152A322775261527CF2762269925E4276F27D0293C2D882BDA2C732A4C293929852ACD29242A8F298C287F2BBF2C3C2B0F2D902C422CC82B842BA12B452A3B2997290F2DB72B552BBE2B8C2DF82B7C2B362C84330631062C2B2C432CCE2B6C2BC72AF02AF92B282A072BDA296B28B5273228CE29172B7429A0284B27252822284F278F261026D728B6291E27CD25AB255F29912A352C692CA92B9C293F29522ABB2A1A28D52841284429F42BAC2CA52C452BC12B0D2BBC2CD12DF929C62ABF29D127942AE229D92B922BE129402B652C3E2BFF335B30BF2C5E2C0A2D3A2C9D2BDD2BB72B822ACF2A112876275227412764278829702B67297728AC27BD271929E627B126D8261D299E287A25E625252674281C286429E62BBC2CF02A9A2AFF2C0E2A132BA12ADB290928CF29AA2CCE2BBA2AEB2A3F2C512DEB294C2AE6285528CE268428E128392B172CBE2B862CBA2B3E2B8B33C931F32CC62DE12BFC2B152C242B752E182E132C342A39288827DA264F26AC2B9B292B2BB62ABA29E828E5266D27412662244F267C264A27A526B9256D29002BE42BBA2B4C2B2F2B372BCC2A212B032B862AD3291428A629E52BA72CA22B092A9B2A8F2BF12974296C29EF26E32655282129842A472BC82ACA2A902A512BFE3455329E2D752B1B2B6D2A452AD92BF92D4F2D782D4A2C5F2A6227FE257B25D92A802BAB2ABD29BC29FE282D286F2783287C24752788283F28F527AE27A7269029BB2BBB2CF72B812BC12A3C2B182C862A6B2929293C2742280E2A312A4A2A7A298428532A5829F0289B271A255427AE263327222A522BD1279D271D27852BE8343F33702EBF2A95293829502A062BDF2C852DA12CDF2BF12B742ACC265A262B279B2703297F294F2A792B6C2B372C4A2AFE2AB72A7D2AC82B5F2CAD28CA25FF28122B112B202A8829C229E929882B342A062BF628A0279C254F28F828512892296529FC288B289E281B27DB2625284F2A652BF32A312C292A722936298F2BA33624316F2C6B2A0D28CC2630288927CA289E295D2A732955290B28C3252A26B0248D268D278328CB28F32AD02ADE2AC72B7B29352A422AC129192D452A3A29AB264F287C290F2C0E2AEF2859283D2B262B1E2B4B2A9027AB239429EC274D286028402854294628D325B9267327AB29892BFD2A062C1E2B2D2A53283028B12A7A346F30422B9227CB2608279227B627F4255727A827332739267F2509257E24D9241E24E7265C26F928472B4A2A5E2BE62B1F2C4F2BF92A9D299C2C212CE22BD2298B29902A922B6A2A8829BA28332C0A2B962ABD2A0F274D27A5271629F628F1288829722A41283026BB267328952A242C402BF42B9B2AF0283329D729D12B01353B3272296D28D726102694269126B527E525E8275427DD25C0244425E7253925B325FC2502286E28AF28F827702A7C2B352D1A2BD02ACB28842B1A2B8A2A4F2AB52A392CD229422A5929302A4B2BFB2B182D4B29B228CD26242AB82A9A293A2AB929F02AE927CC26B027B4271D2BD82B352C352BF129F627CF29B4294C2C1337B22F9A2A9527BF25DF257C272028E4288E28822786282F245D26FF25B7258A27E326E5272128E3293727F7250328AA280A2AB92AEE296F2AA62A422A252B812A6A2AEB2B032B4D2862281E2864295929F9284328E1261226E82B5D2BD62D092DAB2AC32A542889250427B2273129FB2A1E2A552A4C2DDD282F27B327692A34344530F5292C289E26AC280A2B5D2B9E2ED32CF32B6B2B0229AA27BA272B28FF295129A728562A802A6929EF27F225A1265927C0298F287F295B2AAE2A052A23297129892BB02C8D2957272429252BFA27DB265F285427F827C6299E2AF32BFD2B722DD22BF72A4E2A172861266927582A9129EC28032A1A2ABA288129A82BBA34CE2CD12888253D27DA28FC2B6B2C832DF62C1A2DF92D462BF429BC28A52AF829D1293229D42A3F2B2C2AB827E72664264126412994270D28F02745283D299F284D27CD29F82A9F2B6D2A9529C5276426F826C326FD241D271629962A262CE72B9A2D602BC52CE22AFD276726DF24E92582289928E1282328E928C6282829FC34E52E6C282A261627F229222BB02CAE2C3F2E682D9A2D0C2DE62AF629D42AAB2B22297A2A942AB52BD52AF32789287F25782509281329442AB42A612B7529FA287E29952ADF2A402AF328C328D42873247E263626C327732A292CBF29612B662ADB2C1D2C332DF32AFD2A902863259E259D27EC28F029CD2980290829B629AE33472FD82A4E280528EE28142A712B402CDD2D3D2EFF2C362BA829CB289B28CD2AA82AC129292BC42B342B9B29BE29E92776262028AC26C728452A602BD229452A412B4B2AF129D3277226622618263625612521276F2A172AD62B2C2C002AD22A952BE02BEA2CC328EF285028D125C026C326E829D02B7D2AC02A8C2AEB29DC337C31872DB02AB32AC12B222B132AB82BAB2C122B8D2C312BCE288526EC28AE291529AC2B3E2CF92AEC2B402C8F2CD52B8E28F7285428A927EE2A4329AD28292A8F2BD82AC1297C25132687264E2645241F26CD26CC28672AE32C9D2A3A2C392B4F29C029802ADE2AB52AA525C2254027B128A828372A482CC52CB52AC92CE3351233FC2D502D4E2C5C2D802DA22D852CE0299629D9273A2838250B2666288929982B2E2D3D2ACC2AAE295329BA296A2B372B282A1F28A427562716298A28DC26F52806298126932317260527692704277F25D9274326852700293629EC2B832ABD286A26FD2585270129B2261127D928852AB32A992AD729B22AB22AA22BEB34D930672D652E5D2C722C9F2BF62CB22DA52A44284D274A263525A62512279729E92B212D482B232B7D292529F429662CC929512AF427C9254326D7245726A1262426A925442600264726B525C6253827F123DC2614257624F5261E27B7269B25442547263329832851295F28C42733288429ED2A1B2A80292B2B8C2C082EA836B730342BE42A932C1C2B262B282C702C692B8D2871253026E72583264D289D2AAE2BEC2BE62C632A78296E277D282728F4270B27002764251325852492258527CC259726D226B323DF268F2544265825E923D324CC248F265027CD27C828B4260B27A828DC292B2BD1292B2876276A283C286C2A1C2C632ABB2A7F2BD02C58343230D428A928DD290C2B9429A82B332A7A2A7229CE261726BE2554263929272ACB29AE2AA729262A2D270026E42792278125922551257926A624DD2290245F2654276A2621278B266128A92704296E2763258225D724FD26112AE828D729B729142BA02A992A3928B9299C272B27452ADF2AFC29F72AE02B742A442B932C4533932F8D2BC62A0C2C872C472A4F2C022AE82BE629492592252028982732273328B827F4280F28EA270427F2259B262E28BE26412650267C26A124F22481248A253B27BC288A290B28572B102C872A3528CB28A6270F267D275029EB29282CF12B932CF02B7C2A4E2BF12820265427E828182BB02B4A2B182AF32A0B2AF9295E33D92F582CEA2BDB2A9B2B372AEB2A972BAD2A302A8F28B9260F2826288428AD28E527F327A72AB228DA28FC26E42875295A289C29012664264227962728256327E628232B2C2BF9272A29B2288D2BAE28E52710285D268F26172A882CDF2B552CDE2A782C142D7529952A48285C288229412DFE293E2B472B2F2B5F2C0F2B8E340C2FFB2B602BAC2CE62AF928F827182BC82C9E2ADE2A852AF4272A281D2A0E2AD028612AD02B0B2C892988273127AD28122B172D082BF929FB2AE42AFC28A4280729832A182B7B284E27D52835295728A8273527EB25A3288A297129FA2AA12A002DED294F2A782984282A265427CD2805280F2BB62B422AA02A442B1B2D7F343A2E272BC22A0C2DAA2BA82A7427D029762B3C2B432A212B342A0B2AF12A502CD82A0B2CC72CE52E4E2C6629412B552B5A2D142DA22C252C412BE22B932A122A8828392AAB2BF22A85293E28D32737286C27A5266726CF275629802998284528B4293529AF27752845274526B725C7266929942B812BB42AF8299029002B41337431DA2889278829542B1B28E726F9252727902B402B152B78291A28052A332BB52A8A2D562B8B2D412C212AFA28B9290E2BC12B882BD0287F2A612B012AE4297D284426A52667282227F2266C263E268C276A284E27F026AB29332820277527A627A32616263E256227C225B924E7253F2644293A2A82284C293A288F277032EE2F5F2A5B276F284C272628242651269027A5280A2B2E2A4C29532A002A8B2BD52B532D2B2D572D352B6D2BFD2AF4289F28C72AD9299129132DCB2A212C7A28A428CC2655264728C525782530266C26D8274228B62755289929C729D427632712296E29F8281F29102AFC284D27C426B725F7283329E429CA2A4C2AB52AEF32592F83284227CF256D270A288326FE2645265027D22724280E28CB27DC28732AFF29F22BC82B862C8B2C2A2B9C298D28172A8A28F527E628B229952B6A2B3A2A4B2A112AE528C925E323452621256825FB270F2AC828FB291D2B672B302CE52ADF28DF289E2A402CD12A582AC1278027DE269A279029212B012A572C942CF8329D2F1A2AA328C82AF32C6A2CAE29A02BDF2AAE2AC22733271427DA259C27832717273227E028D429132964292328D4273B254E2799260028B42A2B2CF42A622D602C712A342BCE28D225ED25AE263B26AF2A262CAD281927B3294E2B6D2C1C2B2D2CF52A9A29E0293A2A2F2B442A50290329FD28DC2A732B6E2CAF2BE22A38342F31852A8929082D5B2CE52E482D182CD92C762DC92B4C295A28BF241626BB25E82554267F27A2280D2ACC28F328C02640258B26C825FF28F72AC92B9A2AAB2A9D2CE92C7B2A232A52292B2838259925462A372AF32ABA280F2B382E9A2C582C622D012C942CEE281429A7298A2B342C7E292129AC29FF29372D2D2DC02B3734EC30222C932AE929FB2B312B532E0F2D372B1B2C062C542A6C2765270E279F27B226B2266B28AE2A712B942BE829F5278826EE25A1259B28412A552A272BF32A1C2D0C2D8E2BF129F929C229D3279226232A362CF32A5A2A322B402B902B8D29BA2B9F2B9A294428BF27D528D2273B2A9F281228DE27B028612B9B2B492C8B349B2F0D2B642AE42A9A2B272C0A2DDB2BDA2B332C972BBE2CE32B9C294128B8278C27C429A42A352B1C2BDD2AA82E3A2A2526772410268026DC291E2CCA2B982DA52C472C9E2B92292C2957287727FF26B42ABE2BC82B982C812B02298E29452A622AB129002AB026BF260326EC274E2BEC29E32987287828F329EF2B742C00336430862B262A472AB62A542BA42CDE2B932D722CA62A1E2C612B562BAC2921287D276627E829F52A4B2D6C2C872BD229D92989290D283929EE29A72B582C992DE12C452D2B2CAF2820292C281F27B4273A2A012DBB2B5D2B6A2AC229B228042BE62B1E2B4B2A3B299C27FF253926F3296D2BC329D6281D282A29072A2D2C15351A2F0B2A3428C428E027B7284E2A762CE92BEF293929D928A928322A07295A25DC2415251D291B2954293F2A2D2B2D2BE229CC298B2A1029FE25C8275B29CC2A182C6E2C072A7E28742732291D27A726B728272A4F2BFA2AAA2A782A762BF12A3D2B352B412C762A1A2BED27E126FC265F28312AAA2AC1293328CA29E32B2A368A2D86298B271C25FB2674287729052B642C7E2C0B2AE328DF260C26CE263F266D24B825E726E9268D27642B922A5E2CC02BAF2ACD29E928B926F5266728022A422C1A2BD22A56299727C7274E28F526AB28DB29EE2AA62A922A9D28392914291629D72AF62A5C2A342CD42CAC2805277F277D2B5D2B9B29692B0E2A182D4F364C2FA5290A28982797272F274028EB2796290C2B16293427C8259325E9256825AD233D2322262F272428BB29272A59291C29EA2AFD2A7828FC26E125BD27FB28AD2A812ACA2985284728112AD92A302856277A292E2B4F2B252C7F29A3285027E2279727EF285328772BF32B3D2A8E28C426042AAD2CD22B552BB52B1A2DFA348E31C12ACF29C429BF2B78299128CB29B629EF2A7C294D2824260F248223A723A02358253C27D428E0270F29592C312B8129B129112A07289526F92452260B2A482B1C2AB428502600284A29392A5729FE289F29D128372A1E2BF32AE42A11292628B5264227F2272D2AE52AE12B862A1F28A1277B29E7285829FB2AAB2AAB343631A4299029A5283329042A5B2A272B472C332CA42A2F296A27CE269525CF233124E925F42582281528F629FE2B4F2A6D2B582A7F296428762635262C25EA2644295C289D26B125CD252B27A527F7289229472B422924299C2BAB2B282AEB2AFD29BA296329F228822ADC2A452AE32976298427C02653280F288B28D629AB34B331332B56290728A9283D29C12AA32BB22D222CF82BE62B162AFF2764260E26FA249725CE2546296C29492A602D2A2CE12BC92CFF298529832AD026B9249A24E2272028AD25A5247F247026F4258A28AF2BF62AE52A9629512CF92B252BD32B662A3D2A722A9529192C5C2CDC29BD2A6D2B3228532890265228092A122C17346030932BA9288A286B28EE269329852C202D4E2C222CE429572941270025AF25BA246F25FE26CF28D9282A2AA42BE82C732B812A482AD72AFC2B852A2228B826A9275228A5276F260726D826F726CE266B2BB12DD32B3A2A2A2BEA298929B62BEB2B4C2AF52948294B2BEA2A782BFA2BCD2BAA2A0D296C279228B729C82C23351E308B2AB42AB4285329C9278629E42CEE2B1F2C762B2F2A4628A12534264B254B252225DD2829276E282E27E0290E2C0A2B11290F29E929C1291B2895269D276B27DE25A725A627762748262A28AC27552CBC2B5E2BEF2ABA2A8B29AF285928FF274A28C9291A29422BE82A2A2C842A882CCB2CEC2CFA2964290E2A602DBB3517306229B428372BEF2ADA295428F62BE62B512CCD2B092CA8286D269B27352719266227B12571287E273025E328642B7F2CD62A822878273C28BE268C255C2770262226D125F52449251E28B127CA27F02A452B2A2CA02C6A2CD629FC2798296D2A7B2B3E2A6729832A302A112CD62DD62A2E2C1F2C0D289E27FC289A2D5436D32F3B29972A3E2A9A2C492B592A9C2B4D2B23294429F828B3297827D8267C273F265828D127782831278725202712273028BA2A432949289727B8264B2420249E266129DE26902573263125342A0C2A602C1D2CC82BCC2A9C2ADB290D293D29912AEB2ADA2CD12A752C672A132CB62B132DB02B052D8B293729B9294D2B2A361F2E162A32292E2B5C2A012D2D2B5D2A3F2BBD2A472AD12782266027FA255A25BA272829BD2A3429EC255625DE252B26FA274A2A42292F28C5275225202485239023DF250A279B262826102669274A297A2C7E2DAA2C232B922A5C2A6429822AD52B3B2A002A892A8D2CBA2B912CC32CA12CFD2BC42B9229D62842285E2A8035272F162928293B298B2A732B3D2CD72D602CAD294629B6263B261F240825FF25D8257F2ABB2B1C2B52282227D524E6272F28BF28C727AD288D299228182729259824AF25712617289F260D28F627D3297C2A982CEA2B6B2B2A2B9528DE27CD2808293D29852A092C9E2C9C2A1B2B222C8F2C772B3D2BB02A0F2A48292028B332812DAA27342607283029B32AFD2BF12BDF2CA629A9279B25AB2454251F276A29E7298429F729A52A10295F26E92601269B266827AB27B3271729E6282A275A25A824112349244F2459284926A22711273B28A72ADC29CC29F529402AFC270B29AE29BE292F2A2F2B662A4129AC2B9B2CDD2BEA2A992A0D2ACF29272894289B32BC2D7727E926082527266A29542BC22B6E2BB2291728FA265F245D2412280F2AC92AE4293C2AB528BC2757252D258927E028A829822A6628F62879298C278C26CF24FD231926A425F6262227FE2671254126FF265928372BC12C6529A1288928082AC02B152A932B832C592B9D2A992B912AA02AC02AEB296C2AB329F129EB32832E6726A224E324ED251828BC29DC299029A027C72411255E24172454268328EC28AB28CA28E6272D270726F4241F2778277328B4261F285B27D9277928E1262D26102577273428C02762277E2714287E278325D6261C2BCE2A7E2AC129B127F02840293A2A902A5F2B6F2BCC2A8F2C222BA62AC02BB72BAD2A5C2B9F298A331E2DA627E625AE243E254727AF26AA28C2274A26B2258B234B25C8241B27B62736295D297B2926299B29B327C326F1282826B428C428AE28D3256A264D2731265E26442772274E27DA27B327372757274829DA263E26B226B428BD270928A12A98296F294828FC27072BD42B452BC92B392CC02A5D2B68271A2835293E2A58344D2E6029D4248D250F25EC26FE27F3266D282824EB220D24EE243E24C6249327B626C8283A29712A7B2939290E28AF283627582752279C274A27B325B0239F240D264E28D227FF27DA27BF275727462613281E29A2273426B927F225AB2648279F2A0128B2260D269A28B428522B452A3D2DBD2AAD2ADC2AA228B9287829BC322A2E8729FE25712458248825E425992638270D258F23E2224C24E4206222E42381264629A727ED297D284327C72784268126B0241B269F249B276F24392605252E27512742285E27092955273D261E26ED25A826CB270127A528FD2467267C267C296C2AD72AE228072A0D293B2B6D2B172B242AC52A062A8C2AF1282E2807336830B029BD25A0249E24A225FE23DA2554263025AE24412391228823DB230A24E5255227A5264028A225302527268D2729264F267124CE234724DC2487237325AA263825FC25DE26C125B627D5264B232E269A266F2698258028D427C2287326CC278B295C2B4E29152ABA29DE29662A5E2C9C2ABE2BA7281D2843254B26B030882E8528E22599241623602318252524F425EB244E239D23D7233722CA230B23E32363240A25DF2405249C251426C025F72432266C2452234B24B225CC2480249925A22500274B26D3265927EA251A24412350244F2593258526DA26CA276E26F52544289C286827682774263E269929902A542B272BD428342805271427E2319A2C8F26A025BF2459235F24D8212B2319252124562409232B239322942222238E22D122DB24EE245B23E523BD2508261525ED26E924FC25C12407234B255D24CC24A926E828D9268E28E028B2262726E02459253E2595270928E226A325012453257B25BA256724F925F5244E25A426BB26D3275829B227C027BD258226A62F292D2427E123CE253625FB2366231F240025A7224D233525B523FA237A23EC22E1236F239923C224DF243226EF28222992270C29BE28A7262225D8253A267D26BC26DF26D126C728C629F629792A8429C82801278726252754283B28922568269A25B824EC2310245E240025B8240A2731256426C426F425F8258B2507278830C22B2B271D269F230724C92392225722CC23DA2478243426B324FA24F12342253B2355236F2496234625C525132928294829042B6629C128F226BF230024602442262625EA26FE26C227712885295229C028DE26B52416285E293E293A28082760284F26B7257325EC246923B6237F23B424C425602347250D257124ED241F313C2D6A27AC23DA22E7229C22C02269225D2307249F23FD244F240B24C72443211722A3221122542351244D25BC2627272729062BBE2B3728EE26792392231F25A7250526F0265C241326D0262927AD269A27CF2643258C25C626222898271B284F283B288F2612259A25512318241726B823E7234624C922F922CA25CF2592317C2B17262923802248223223762107243B215B23B424A3257725DA25182567229E212B2357210D23BA21B822E0248E26C7264E296B2A9D28D127E72462248723A0243F25AD2569242F25B42505265B26F2259C2623256F24AE2430267A2765279128B0280628CA254F260623A024A724FF2417268D2537248A25D62451264C30662BF123B22241245422CF222D22FF227123D32217260F260B25F5251525ED232924F2213223C323AA22C7210624FE2571241327842726277C26E223FE239E21F0221A242326A424EE243525A325892482254F273B2433240327FF261128F32774263D260027A426FF26072682247C268E27FB252426E8241B24A1249525A32E072C9E26ED222A237324F421F422DF22E423F32476243D259A26E42489230B259E2445247623FE23F121202131239124F423142403260B27F5249C258E233A21DD239D236D239B222826782453258623FB25B6250724A12429277926282AA527FA28D9276C268324BE253925A4253827832618254A2664267426FD252B276E31862D8626E222FF22AD24042262231E226E2389238D24C523BC246E23AF236823F022CE2251217922DD216A21762285246724A3239C2382213D2442238F24BA22702211222D233423D82191259623882241231E246A229224D3258E26D126182873272726982581229A243424FD231A24AE24E024622623268C25BF250B266831CF2B05268624B421C321F3218D226822D323DF221123A9238E230D254125082263233D223F22E5229022AD2152226122EF22A423D62159211424C2233223FE21CB22BA2302222021732086228220BA21DC220E238320012230257525DC26D9242B2795263125C1240D23A022AD222224D4224D23EB2338226425AC253D27722F6C2BC62581236F222D22D522A7239723BB23AA220823982479233323FE2350241523A1215A214F2280227121AB21A722F123E7225F21A3223321582301225E222622112262237C218220DD21152167208421A5201A2186213B23EA2489241E27C92508247E24BA24A12493215D22DF227D22A0215923B5221425CA256A26F32E602BAC263922D2213C21DD2033239D22D5228F211A23DB202B224122F322512289226521C521A5219D22C21F6C21CF248F248323D222B321D622DB215023F9231A2277211A2336203C217D2165207B214B213922BE221421CA23772390234E23A7252C2499222C22AF2390230422D9226E216A22CC23F9227223AC25DA267E2F212CB02506246022F422AE22EE2128220023F121CD22832175229A211D224721A520C821F720F920B81F9B1FDB2088228822E9211F21CC22A4224E22D6225D2265224222692197202F22FF219D214121A12057210720B321C822D02243221E239923FB2274236B23BF236521D1216622DE233F217A22852155222322222672306F2B662471226B220E223E212721E022B6209C218121132128210720D9200322582110201622BD21E720211FD92179215B216122E122432212223C219C209022E421922207208620951FC02145208820A2202021BF1F55202722E4203B22702245227F22402203229222D0229023CE203E211D229522D4226E23AE24CD25612E4C2BC8242221FA211122ED2011224622E621F5229B223E20BD20AB2033219A21A521E3214521C5207721D11E8721271F40211522AB1FEE217F202521D4207F227221A320DD20E9204C1F6C2164218720FA22F721841E4F21BF206421D621C2232F22AE1F0823E32141205E21DB2050213F211A2208239F20772398232126B72E7A2BD4254E22772144224D229E219B231422682149211421C11FF71FA921DD228621C32193232C20B621E82082217020C621DE223F219721DB207321B52015225421DF1E3321D51FB01FCC21A92149202F2241212521861F3322C0201024D221AD215E21AA219B20B122B11FA121C422612360213822EA226A23C1214824B02F6B2C84258421DF2295226D22E921AC2348230722BC216C221321C31FE0211022DE22A7222B2214202D22C220C421D420B420BF22E020691FDB201B232D21DB20C91F9E1E8620DA1F251F5121D62044207722AB22BB20FF204B20F11F74201C215422DC200321E21FB32137216621AB220E22D3228821D120EA215D244A255E31892CA325C523C220A2230C247C22E322AE2337233E2475227B2108216522DD2083215B23DB2132203D213B20C021FA20DE20B1221122DA20CB21FF1F5E208920881F4C1F651EAC1FAD202520D020B622D922EB21D7214B1FC11DF41FEF1FDF2131217B21012103206B21E4206421BC2284217824DA22C320DA20F223D2251C2F ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 A42936256425802333245C239422DD222223C321A920C21F7F1F241F6D2142209F1FCA21B221881F3F21F02026226320C6206D2025224D220E2231225524F1227E219F212720F11D3C1E41205E202921D3203322682031209B20BE1FBD1E4E1F59202520E01F081E38200320501FEA210420AF22B121DB207B1F53228B23BC2EA32C1026CA234A26042614246B2437253E25A52214239F213E2043219B21BB212E21BC21AE214421F9216B239C236C248E214823FE2180233723A624A225EF235224AA247323A2225C20A722F720A3216324A223AC214021842171236322B020B62081206021A120AA222D236622AA228B22F2235C247223CD233923BA251A2F072C3F26F125A3251725BC2439256F265D249E26E7243C241E221421F4215C221823F32340233E22442277245F2417248E242624E9225523052567220A25CD26C8266C2786255524D42162225021DB21642336249722DC22082383205A2237224722DF2172213E20DE22A6238F244723FF22A7231226D3235C2436242F27C0309E2CF72889266D2495258F251827C1252525B5243C24F222112377214423FE200A237823C7239E25AE237F24D3232F260425AB240623D9235323F423F92335267A289C285729FF2499225C22B6208F201C233425FA24D024DA23C623DA24D424F524BA22A122092241228A221E233324B42492241225332696240C26F8267030972ED027F02368232D244C253425BD256E26B025A9251C256723312246239722DD218B23F4235324D32402252828E52437259F26C722F71F332349248925A5267E289B297529E02598235D229E207C226822532646258E2597254D2687259A25D026EB243D24B62153233623D7241E25042584245E254124A9251B27BA264B2FC02CB327A124CE24042245245C2340243426B4252326CF2652245924A9231F23EF227422BC220C2564244525492776282E266B260424C42288223924C525072831288228C527E02414254521D121412160226A24A82684272126EB26F02606287628FB26D82314238D224923AE23E124B023EB24FD269E269A263A296A29CB300B2EE426702565245423F0227F24362497246026532693256D26C02590263925B424952259237C2360267C277C271429C2277D27A3271E263325C8243A28CF29BA299929B4281F270E2597237F227721FA22B025EC2518284B29202A2229DE29D02BC42853279223FD227822A422D123AF259E240027A526C929FB2AF32932339D2F9F2965278C263824892108227F233924B8257C242E265E27C2283C266225752592230D247A24CA2489243C27DB2ACE290E2A302A5C28D2263826CF25BE2604288E281F2834264926F726F225C7216C248A230F242C26C62879271D293829FF297D297927E724C82386221C22C323E1243B268327CE271A2B042CBC2CF2337C2E7F2A2D29AC2692253D238A2177230C253025F3256A26B027B02747284E257424DF246F2447246024F0232D24C428C128262BA52946282E26AD257224D824E126F027A2262926C7257E253324DB2357249622D5232D240A29EE28ED2736287129B4283829E426D025BD2253212C23D525A126EA2816298329492B472ABE334131FC2899277D262C269823E923532320255F249F272D295A29932A002A1528122716259E2506256B240C25A024F72763285E2B362BD528412966253623C423CB245E27102683269F251428742742253D25E2248123A0236024DD257725A9268C2B062A1A28AC277B25FA23C023FF22CA2421286D298C2A2229032A172A3B35CB2F592C782AB328AC27E3249424DD230F2429251929B72A882CDF2AFC2A9A29792808275F27EC2767252726F1248E28C2277D2722271127FF273A26BA236C2290241D253526D126512669274B29ED2700272C244C230123C2246524F624AD264827FC26CF2691269625AF220F2158236D248B25E0271F277128242808284933A130202B7E29202BF727F924E5247723CF24A125D42660290C2BD32BDE2A3F2A48287A272E28C72BA1297A2A06269925B82693272828ED271C276C26662617248322FB239A2358255A2667277A29BC295C298925A824E423F92318245624A4268D26B626E127D224E625F7238A222624F323B9240926A926D22543256828E3318731982CB629F6288B271126352532238A24B82312247A28EE28492CB32B902B5F2960286E27CB2AB32AD82966265C27AF25AE26A127DE27A828BC294C28C826C123012477247C236C237B26B4298E28BA2503264F239822B8249525742520285E26D4250C248C249C249D234D223A23C822F422CB268825EF254C264228DC2F5E2FA32AA22854288B28AB25B625CF253126BE252E24D124D6257B27012A0329652950296429902A2A2BFB2978286D261D268226F5266728112B7B29A928E2256326B324D223EB22592434258A2775262928722779244C23E022E424F1265F287128CF24F62585250727C523B62196220F23D9244A26E626F827A027E428D7337E2D1F2862275E26F327BE26552897266F29DF26F82696261E2456253426E027E826282A5A2C142BF82AD2291329FB277F26BE24D8243E286F29AE28E62880284E296B27AE2546257C254D25A22605286328B8281227C5232F2378242A24A025102679274128AB28812AE6281026D324A9246723D62658267D287429F5294933882DAC2879253E25BC265D28C828BD295129582AD329D226F42284246525FD26D1250629A529D32A7A2DAE2DDE293E28A2240C259025952584263A28D9289729462A79282B27A02673266A2ABB29282A5A2C97285E269224AE2392225223AF24E3261B264129D6294C2CEC2C9028B727CF24DC24DB253028DF288229FF2A9533022B7627712662279626C927C3283F2974294B29E5293E27AA240A24712372243D2553268D2898299F2C942A6C2A7A293827B926AC25B5237A25E1263228072A382B782BAE2A06295828A927AE28AB297D2AD22953279C25202686238B2263258D26F72615297428A4294F2ABC29E52529264025C6250828082A4D2B3A2C9534202C6E26B6254324C726E5289228BD284A28FD270427A32545249323E321782235238F258C287F28EB28BD29682860277A259227ED2738276326DE24A226AB275F2ADB29372874269128FD279727C3268C270C290C2704233825532297218622C226E925AB272D26BE28EB27F52A7D293D289A257824CF2542293E2B782BA135B62A3128E523AD25792725282C29F927B726BF25262758243D24A6231A2488228D23A4263626C629F429C827D728522961264628E228512A8929C2264326B925D926092790263123082694258D26DD230A26DC24A6243123CD21AF209F20D0211724ED26B228F625A328B1284928DE265526532431236723DE2765296D2CCC34932D1D264223DB24D525382713272B2748253C254D26B3260C26D223C0256B2584240922E72578277826E826B9274228D4284128F7263F270B2B6A277D263A234C244C25DA237F23232367232B2272233C247824EB22A3221324A8218F212C23DF249725AD26C028972B6F296329662B60286125E623DE22B724D1276329E933C92C13272025D2246725192734264D2675269326D428DB27A0264B264A2575255023E625C1248724A925B92886289E28FC28F9262D2712263A266126B9246C258324982421232223B021922141240322F72465251725132554239B249122742277234323F72532285B2BAD2B262B082EC6298627602647226824A325152793327B2DCB27572782244D241B2603275B275528492873266F29442A0C2B87282D276A268C23EF257B24F2256826C527C7279926B626FF230A2477257324C4259B2404254F25A9232B23F4224D237B2325253B277727F025ED266527AD261A243D234723D52407264829CB2C7B2BC72B882AD229B8296726C1254A2521251B287832722EDD28BE26F726FC252626FB26AC2784290A2ADD2A142B482B102AD62BC8285A27F72486247A221F23B82351240325EF242B25BF234F24B72490239C2534269224BE24D52342237F221126ED25C0256A29CE29EB292D29B22920294F27F3259524EE242A28F1287A2CB22DF22B322BEC2A98296F287926E324C0256A27E8332330C52AE02A0F2976270724E5255328BD28B228DA29732BB129E42BB62D292A4F29AD27E024E7245C2475244D250E26D5255325BA24EC260C27572539274B2770277E278A2494210A24DA24FF26C128AC2AA42A782C4F2BF42BE02A3B293029FB24B72470256B279A2AAA2A462B152C582C942A9A2A7B28FA265B25A32808348731C12BE42A0A2BE02979271325C72520295329292C8B2BE22A822BBA2AA32A9B29E3274326BE27E4249424F7250325942496253927F9274D271C279326412843285D294828C4257824DA23FD268127A4299B2B7B2C962C102D012B4C2ABB294C2A2426EE232225D126CD28D129EC2C512C4E2B5E2B2C2A0B2A7028142610314F31492C472BB02C982A8E292D2814269126A126D328762A062B7A2CA62CD22BDF2B3628B127EC261827222847257E25A024B225B427FC27232A9B29FA29BF29392B452B982BAC286D24B2243625E925C32A2C2C382B492AC22CD42A7E2A0E2C202A89280F262B233E261E27FB29E62CEC2C1A2AD6295128AC27B4253F27BB307C32592C7E2AD7292B2BE22A98293328342693256828302AE02A982C552CB02BD12B2F2BB828132AE329A828E426AC2662247C24B226D926E82836290F2A2D29212B822C6F2D3129D6288125AA24F725D726A12A812B002BEB2ADE2BFD2A1F2DA62AB828F426B224B1247D24B82668281728DE271328262774259625CB25F22FD7313F2DB22883294929442AD72A472AE5277925EF27A428902D5F2CFC2C862CD32A0A2BAB2AFA2B8F2B4C2B242934270025AB23E62290254E27B2283B299C2A3E2C842D2A2DB22A1E2A93263E25FB23B82576273029F32A462AFF2A362A632AE22B86286E25422549249C23A324DF24D325BC246F26AE25DD25F9242C27F5308D31EF2A422A522983288727B0288028A3288D26B7248C279928442C322C972DF42C822AA02B8D2B432CB02B9329C726DE23FB232C222223A1262D299F296E2BB62CA12D262E3B2B912A4528B5234D23772538262529E629FC2BEA282929842A9629C1273624562451230F235D237D2546247925A1258D2494243526EC25FC2FC330BE2AB12651266C26FB2807283727032869254C27CD25882610277729092C6D2C1A2B822BBD2D892AD42A2828E227A3230D230B2341232F266628092AB92B932B522CBB2C0B2C8A2A1F298A26F5240626D626592A7F29732B842A252AD429B8296B28E6251C24BF238023EB2212231023EE2340269625BD25BB264E26E430E12E0B29CD275528C729CB29642963293028FE29942719271B25D725E5250A26452806292A2B1D2B93297D2802294427E424F7239024E72215264F29882BEB2BF82B3B2CC72B112B002B4E2942281E261F2506285D26DD281E2B5D2C732A762A4029D52964273223462512259A25FB24D7230C24F625FD269429242A59290B32262DF129DD27182A502C7C29ED288A278229752B132DE12A0127B2257F27C2279526FF27B22844295D269F26DB25FE24FA2428261C259B23DC25B925FC29EA2A882D662BB22AD427B527C529B529F225E324862520242326F028A82A4B2C5B2AA62A4F295826AB257E24FD22E7223023F423502647260228E427FD2ABD2BDB33322D0527B625E52656294E2A522B282A7729012BCC2B4A2B622AAA278C250025A625F424BC27AE267F26C1267626CD2577260F28412785266F257925CD25E828452A8B2BB729A727B325C029202ABF284B27C92513240424122695277429D728812984298C284527D52720253523FE22F02495261D29D5285F2A182C3E2C2C35322E4B28172584263827C6296D29952A6B2B9B2A0D2A532B9E2A86291F27F324772374256925532612283A27E8288F2745279028C228192569259E2518250627052B022CB1294227BD288B28E729D129D129EC277622E1222624AB24F82541262D275328B529C22A3C299B243B220C22DE25ED271428BE29F32B772C222C6D36132FB0273524792540276226BD29082A602CCD2A5F2B862B602C54291428312597249D24EB24F225BA29B8291729502A7F2896274829D226572573252C25A827DC29B32DE52A96286E292E2B502B0329E9282227C22347232223262573272425EE2657261B269326FB262D26C423DF23F123E7262D2AEF2ADE2A3D2CC52BB235E62D0B28502663249F251E26EB276329042B6B2B4A2CE32C752BCD29F427EE259926EE24DA2338269B252127082985286826E9269D286626CF25B8256A2455269428C42A222DBB280928272CAD2C7D2860266527632580223024F0260D282729E327DF26BE27D528EB28E825D021442278233926332854284629632A7F2A9835EE2F5D290C286426AF2587245B252E29672B222D9B2D732B0C2B1129CC282128A9279D27A725AF269B252D263427B129E5285027252A0729E427B827AE242B268827DF2AC02BC3286A27DA29272AF02890281C27A22419238024AE246828B429A52C43283429EB2AFE28C526E824D12427242C250428E128972A862A592A4D332E30C42ADD286B2723278D264C27C228952A932C162D102AC928022BB329AB283A291A2856273F265F26B7231027362AF929FB28F429EE29D7296428C4257F26AB261129CA2A4C298428BC27282840264D27F9242026C323A8236C269F28D729202B642B092A9329312B8D28CB279B266B255223E3266527D228CE29132B4834FD30922B6F2AC52A2A2A68298728F526962A8429522B112CED2A7B2AEC2ABF29982B212AD2281A28A6255626F028C128A22B2A2B9F29432BE929A729FC285D26F925F027D52A37291828D2263425AE2532267624A42529251125A3248027FA2A762CCE2BD62A302AA02A972A4E2AE028B125E5232526FD245F29592B932C89336231B72C742C882BCB2A662B192B8E29F8275127AF29822BCD29A72820280C28F327C32944294528E5273725B326BB29FF29582A6F2AD82AD72A0F2AD629EC26C125DA2576274E28D8277F269624D92305258C26FB26012645279B244E257927DA297A2B362C162BF02B782A932ABD294D280425802628274F2A942C2B2D03353531C72E932C732D012DA62D782DF32B302B6F28C0250326C427D729EE2A9F2A052C182B0F28C729712725266126EC260329AA2A7A29D0298E2C6829AF2993281826EC249725F7251626B325FA228123D4258827D62899274C2683241525E7261E27A72845291A2AAA2B522BFD2AEF298C27EF246924C225A028142AFF2DFE342E33722D1E2BF42CDE2A652C262D312DD02BB729D328532742267E278A2A882BB62B4B2B6C2B642A462A35283427D52702294229BB29CA298F2A132A9A28B228B8260726BA265123A923C82403258A24E825E628D42AA02BAE2AF2267624FD23E72639276A26FB26EF289F28CC29F2292828D2253C2624251E280A2B372C93321833A12DFC2C542B0A2EB429252CE52C832B252B9D29A227E4249A258729D22AF72A812A612BF129B2291E29A4269A26A32682276A28CC2959291228BC27702707276725D6255F23D6225022C4231125B42751281A2B7129AC2822264E24C7222C245B268826BE269A274B283C29A62A962990289D269F267126AD25EE28DC31F230CA2C8D2CB82CDD2C682D032BFC2BBF2B472CB92BAC29B7268226B22636297D29962BD22BD32A6728862802293D28CB241F29CB29C62729290A2716264E28F7270227F724CF2180211622C22445254A289129212A282A222AC427CF241B257C23D124C52777287F2867280729F62AA62B0E2A03292425DF23F625EF28BD322C30132CD62B672CAD2C9C2C7029C728E12A292A442A9B29722693247927F428E629872C0C2B622B3B2C6B2B342B37294326A6240125DD26C6264826592677257D252E262725B3217A22C6233F24A727F3282C2CEA2AD22B2029EE284D2648249A242B267D28D129DC2BCD283629DB2A852A1F2A302948263A26E826D6285D32522ED729B829622B8F2BC929E92874280C286D288D2793275027BC268926D72694283D2B362CF42C702AFF2A6F2B3C29F427DF24C9237D24B025B1226225DB24C3250C26A7258D237722F22119257F268328242B062A4D2A3B2B1828222828264024E724AF277727392B502B092A822B922A1D2A402A1A2788268529A32AE433BD2D512A7F2A302B972C5C2BEA2902281A275D255E26C925F12560260826A4255E27F32A78286628F92726274928D2289626B624B3236425FD25E525432774282528A7265F27FB259B230D233625D424A626AE275E299C2971274629DC288B26542343255D258427282A912A002A902C362BB329FA2940274E260D2736298534C62E5829022A872C6B2CE32CDB29E1286C283927AF25B6279927F8275926A325662677262627CF274F260D269628F927C125D324A324ED2456267D283A295A29002A8C29AB2A88280B26D124F2226E23E1243C27192747271828382894289D272F261D27FA27F628AE2AD92AC22B842B742AE52A042A2228E626A0278A29C5340730262A09285829312C382D9E2BF7280328F72643285327A5272628C6275024D825032357255525A32410278227D72999293326C222AA23FE26D3267D28DE286F29DD29C02CC529F7275C240323B9210623E82533257A26A728FA280D28D9273B2688248A274A28E22A572B232A3B2BB92A3229E7268825F826B028D22B8E347730102BE5270028012B422C4E2ACC2A782BF32851271D284128CC29402A91292B2513246A25DE270428872749283B28D629DA292627A625CD2505276B290D2AC42A6C2BCA2BB12B5129FA26CF234623EE22CB256026DB25FC28152B5B2A7128F6249F272327EB296F2B1A2BEF2A7E2A6D2AEC29E927002553260127882AAD358C32A02CE7297B2793280B2BBB2E9F2D642C6D292129B628DD29AE2A522CD529FB287E2958270A295427E128A929A42B5C294828C927B624F3248928392AD4293428E0280D2A322B812A8627F324082493254925C1269128762A472D122B702B87296229CA278E28982AFA2A682B3E2C0B2B8B29C928FC258C2725259929F732C632E02E3F2C4629AE279D2A692D7C2D5B2EBA2C9E2B3D292929A32B3B2C822B0829652736264F29B727B2270C2A122CCB29EA2BD32974272227082649290F2A472A9B2B542AB92A002A102A8D27C424DE257327C327F22716290F2B9D2BB12AE529CA2869271B26D92A0F2BB02AED2A632B6F2B0F29BC254D258726D927AB32BF31662DA42EBC2AE229A9294E2BFC2BAD2E102F122D842BA72BEB2A2D2D2B2C362ACC29A7266B285228E3261428EE27A529B2284D2A3E28942616256D28B3294E2A102CF02B442B132CB42AF2297427C9251627C926E028762B4F2B772AC02A8F293228AB25BA263F277828882AD32A022A092ABF2B3B28BC26AA25CF27F7342533492CDF2C852BBC2AF828BD28042D662D612C2B2DF02ACE289D28662AF42DE02A572A8029172A8727EA2708286D28CA27BE280028E127C0255925F627302A9F2D142DC92BB52B0C2BF22B8F294327092703289028E92AC92A142BEE28F2280F2AFA265124EA255A29BB29012B0C2DA42AD629412CEF2992295F28DC284733AD30822CB42A002D122D5C2AE6283B2AA52ADF2B752C342C4127CB28C428762AB12A9D2875273628462BFF29962B782A0228A3289B2BB4276926BE25A526B728AB2B982CED2BBE2CAC2BAC2ADB29AB26B0266829A22A162BD92AB22B93296F2996295F269524FD2468275228F6278D2802284329872DD82BEF2AC32950285030CC316F2CA42C312C0E2AC92A70275228B82A882A172B332B712AFA274129BB296D2BF6284927F0293D2B772DD12BE42CCF2A9B2B952A4C2B6D28E72659279027692A5F2EE82B682D722C692BDE276A2530265F280C283F29D2297E2B4D2B4F2AAB285A26EB255F22E4257C2677259D270327F527722CA72BE329F629C429D931E72F2A2B912A402B7D2954280B2690277026842644296727C0288A288D2ADD2A532CBF297B27CC27442B3F2AF32CB72B322DC22C042CD32AB0295D284F27A2275C29632D772DDE2DFB2C762A8F2ADF26DC25CD2824295529F92A9C2BCC2BAF2B1E2A5D274125AF23CD230525F5265D265E249D231D29FD28F82932282728B230782FEA278A27CA275A286F259126ED2490256027462803284C29BC29932B322B642CCC2A1428F4275328162A2F2A732B732B652B742CC12BA32A5B289B260C264729A82C162DA52C912B16292A2912266027D428EE29EC286C2A6F2A1A2B152CD12A94290228EC22DD249E24B4269A266A257D272829FA291F2C01297C2849318A2C8D26AD258325122567253F252725492519269028BC29A82CDC2A8E2C902BC22BBD2A4229D12890281129BE2AC92A1F2AF229662C772AF02B182977287226CE269F2A3C2DDB2AF32AA92ADF27FF2427265827E1276F28A7273228D129B4292029C3278826862354255B255D28C729BA2701296328B42794295929472A2835E52CBA26EA265B26BD262027B725F3250E26AF254E283E29FA2BDF2CC32DE02B982C7A2C602A38296F28BA29312ADF2A732CF02A6C291729F62AA92BD02819288F277E2B0C2C1F2CCA2AC52A4229C426B0268726C92A502A0B2A102A4F29852A29291D268A26CC232126C0258D25D22AB92B932A0E2A722A882A652CC52D4E361D2D04272A260C277A27C6274C25D926D625712552274B28822A712A222BA32D4E2DB32CCF2A7B2850277F2A5B2B7E2B48299A274A2832290429B72BEE275025A226C62A6F2C112C6F2B602A742998272D26DC277328052BC529022A952B292B462AC52788250A253D270A260B277D29312C782C372C0B2AC12B6E2DF12EBF362E2DE32822266D27D6277F271328DD2792283026D7266E267629852B642C552AF82BD42B322B6529D9267D29AA2BE22B022ADC29E627A2277D283E294D288D265427BF29AC2DB52DE42B402BBE2C72292428EA264129FD2B9A2DEE2A842ABE2A8E2C162C6B2B3F288B28B326D126D929192C162D452EDC2D8D2DE32B772D2435692FD52A2F2B1A287D29BB2A382A132976292529D928DB2774283B2B342B272C4C2AC42A152A6C2A0B260727AF279B2AB02A122C80295E288028D02875273426F1245B27A02C0F2B962B8B2B4B2C98294029AD27E826C728F32C712A702A0B2BB92CCD2C9F2B632B902A6429A3288528602A522A5930E52BFD2B7A2D092C8E33AD326E2BE72A3329442B362ED02B732B962C1A2B212B012A622AD62BED2CC9299B2BD22BE12A962865283F26AA248828752A6D2ACC2B492AA129D4272F27B1255B253F278C280E2A512ACD2A652C99292429472883273729E82B4A2C332AC52A1E2A952C472B592B792C2C296B27EA291529082A4E2DEF2BA42A082CB0284633E032C52ED92A702A4B2C9A2CC12DAF2CF02D582EAA2B662AE429B52B382DF72D702CBA2C622C832CBF296A29E1277A258126FD29E129732A422BBD294E271C26222656264A2638278829CE2BBC2AB52B7C2C292968298729A12C4A2BD12A012AC92A2029732AE72D7F2DFE296F277727CC27EC2AD62A7C2AF4289029C42954339931522E992B382B7729842CBF2E822D7F2D212B4C2E9729FA2AA92AEF2C122CE42DBC2C8C2DA62B3A2AEF28FD2405264E25CD25E6271027D3282029142676257825C025C524F425342AAD2AE1299929A52AD92A7829FD28312A8F2B212BD328CB294329402AE12A1E2AC1281925E72586247F26B727DF27DD26E025B127ED315A2F7A2D152BDE29E12B302CEA2BA72E4F2CD02CD92C172A5A2BD82A112E262DF62C862D7C2C8B2DD02B592A112AD727CB247B2597262328E628862938291428602603261428C8288228722AD32A2E290A29702CF428C128D12B412DAA2C1C2B3328DA272929FE279E2A7A286D26E7251F253125FE25D9257D251D283F296933C12F052CD52BC52A9A291F2A032B9E2D6A2C882CDE2DE52D6B29D3292A2C4E2DB22DD72C842B072E5B2D852BDA2B1B2733262428CD296928D8280B2A4F2A0329E0286A27D3264528BC29562B5B2BA22B0F2C9D2C092C4C2A00297F29942B8729DC283C2A4729F92879291028D829552788242425D6264D25DB250428452AB5324530862B202BA928342881281C29702B8A2D9E2C902C7D2A382A9829062B702D082C122C2D2BB82D712E972CC32A0E2A3027E6270729BC293E2B162A4B2ABA28D729A12868263429792AE5299A2B5B2A402CFA2D7F2BC22B9A28CE252529F029142BDF2A48285A29DB299D2CA32AD82868266D25F424AE26FB29442AE12AA633162FD62B422B3B295B2852281C28CF28FC2CBF2C752DF02C5D2A5E29BD2A6C294A2B632D332B422B822CA92B672B4F291B289E286A2B7A2B7A2C562C042C4F2C8F2B482AAE299227C3293D2C3E2C062B532DD42CBD2BF1289C292328CB272F2B332C162B3B2BAA2AA62C4E2BC82B2E2C2C28B827C02658281D2A7C2C522D6334392FD82B5D2C102BBD28142885277729C42C7D2D6F2CC32D22290D28D528A328052B8F2A042B432C8E2C6D2CBB2A302993270028E92A942BD52D802C1A2CB22AB42BB6281A28D325D8287E2A112C8B2B872D5B2CF92B5929AB2AC928512A012DA62C112B0D2B4F2A4F2C162C692DEB2BBC29B1286B274129F72A6E2C1B2D57360632B52C582C002CC32A792AD328132A162D892C2E2B222CD42893278427BF29D32AAD2BFB2B462B2D2D092C6B2CB62A852839286C294E2C352DD72C352A802ACD2B9128B82869258527C02AAA2B232B692B9A2C6B29B9298C27F72855281B2ACF2D222B1F2C042B512A472B472B472CCE2BB129D4291B2BBF2C422BB72DC037892F892B5E2BFE2AAB2BDD2AB62B402C4E2C132B162B1E2924278E24D32529291D2AF62A8C2C812CD82AD72A4129BA284C278E28A428A129BC2B302AF52A702CAD29DD27EE256F2470276E282129EF28532A8B29E22AF828F7278E254E273829AE2B932B4C2A482AEA29472A432BFE2CE5291C29D529A42AF42BF32A472C3637DB2E552B592A942D7B2C4D2BAB2D412D782D252CCB2928280D25292645267528C82A132D592CF32B7129132D842AC22935271C2961284A2896291F2BE029DD2A93295126D62528244E25A0284A293529A8288629352AA2287B277A263427652AF62C0A2CF82BB22BD92BE229FB293B2AF3292B29D029EE29262C6C2B472CC7362A2F822A062C322E762D752C2E2C652BA72DCC2C732C70287426B8279D26AA2ABA2CDA2B4C2BB72B98298029C62BF02A2B2743265325D825F92628264D29CB2A1E2B11294527AD24BA256828A9289D28C428C927A3263A2551288B275C26AB29AE2BB02D0D2CBE2AFB2D3D2B2B2CF9297D2789286229242A6E2C822CDB2C2C35A62E2C29F829A62BC72EEC2CFB2AE42BF02D832DF72C6D293128E9278829582B942C202C552A792AAA2724286D28592825240E25D42409247926D525A428322A402B182AA92732263C266528912AE429B128D3280A261626FB28B929DC2936295A2B832BC62C352BFC2C562CBD2BDC2BB4289F28C229A9281C2AE52C282E8A353E2F682A5A28DE29162DF62C972C992DDA2DD42D402D1C2BB4284728C828872B802B9F2C602AA0276B26D227F3276E2695256B241625F62484241E268725D728F92B2B2AC029CC26842663285B2A052AF92A502A70289829132BFB29FD2A882A0B2C572C452CAF2C662CD22B902BE52DBD2B942ABB28FD2818292B2BAE2D30350931212AA028AF289C2AC42CAA2CDB2B0D2E6F2DF22D782B2A291F2A2D2C7C2DDE2DB82C092CD928C626FE26C826EC26CB252426CD26752575265A25F7271C28032ABE2ABC284925A725DA28D1298D28E42AFC2A532BDA2B0B2C2B2C0E2A07297C288C2B4A2E2D2BF12C9A2C5C2AC72C732A692BBE292A263E26A929C72B3635E930ED2BD328CB286E2AB62C932DA62C2A2C1F2E8D2CAF2B262A8A2A492B932CD92CED2BDB2B9F2A6D29502A4A2ADD2A0D2A5A2AC328D126D0289128912820276A28CF2A1E2BB9279B26A42A6A29442BEE2C402D9B2AC02B9C2D692D9C2BA32960297A2B212A802C9D2BB52CB22B402C4C2BD22B342AF228F3281129872AA034D731432C562BDA28902A962DEF2CBC2E7A2E972D892D812CAE2BED29FF286E2CC829242C0F2D282C782AB428482AD12BD029A0291E283E29F02ACC2A272CEF2A522BD12B2B2B4E29F727E4275829582B552C872D872BD52C8E2D922EA92D672A43288128CB29192C772DFE2BAD2C4D2D082C5A2B512AF429CE292329C2299A347031D22CDA296F29C1296F2B772DB32E9F2D7C2E092E212D122B5B2A2528FD2AE92A8A2BBF2BA32B842A58294E294C2C0E29E5290F29E928402BB42CE92A922B312C852C532C662B93297829442CC92B4F2CE82C602C502D022EF02CEC2CB72A90273B28A928122BDE2CC62A3B2D892B7B2A452C612BB328BC29D428422ACA323D313C2D3C2A2529AB280A2A312CF72D612EF52DBF2DE42D702DA72AFB29B7273526C527122A0A2CAD2B742A842AE829B92B1A2BD2287E29BE2C732B1A2A0A2C202CBE2A602A94290E2931296C2B3F2B4E2DBC2C812DF92B902D4D2DB82B732C032A4228E228B72B232CD92BDC2BE02CC62C2B2CAB2C102BE92B6B2BA02B35340E30932C702C432A2729592AFE2A6B2CD42CFB2CFD2CB72C652C8A2BFA2A6027AA262F27E328562A8D2C8F2A9C29F72928290E2A2F2A2528342B562B462C522A5F2BF82A2A2C7F2A8129A728772A422B572CB62C002CCD29C62E052BDE2BBB2BE329652A092A982A692CD42B2F2C722CDE2B5F2D4E2C032B0D2A062BA82B2133262F602B6729B52967299729D22A9A2AEA2BC32B782BC02B682BB32B132A55287C2516271227DD29802CAD2A782ACB29D82A212B772AE927182A142C992D1B2DEC2BBA2BE82B682B232AB8272629FB28F629252B1229E229402A3C2A8029EA29E429D0282A28EE28C92AF92B482C712CE02BA82D302C9029D029812A082B5133A9300729E529222A61288427FD272E2B3C2A8D2B2A2BCA2A252B892C382C2629DF270427D028B9291A2B9F293D2BC42AC42C902B332B0E28DE295F2AD22B402C3C2CD42B0F29692A212A4D293828AF28CA2BF729802ADF282B2BEB29F027462813276C27EF25FA27BB2AEC2AEE2CDB2CA02D982DFE2BB029AB2A3029BD2AD335F82E512ACC28F42631262826C3262C29DA2AB829822A8427C82A102C3D2B942BE1292E2A312ACD2CE129F428E829732AA32B5B2B1B2B292BB229092A6F2C402CC02A022ACA2834275D29F228B0287427A02715292A2A6429B32DEF2A902B462ABF288E277A25F525E029CB2B692C242DAB2C9D2C382F792A3C28C02673293E33F92FED29B828C9268F269326D625232AFA2AEC2A7A2AE229A32AFB2B062BFD2B8F2AE129F62B0C2CD52B2F2BA02954290129612AA1296F2BB22AE92A722BCF2A5F2A70289E273A266D269D29842ACC26DA266A29B02A7C2B582C852A5A29132882293A28A22641282E2A2A2CC32CBD2ED52CD22B2A2CB02AF0281929FE29AB33D62DC229EF26BA267F26BE26572557274A28DE29342C742BC82C7A2B8A2CC129DD29462AFB2CA32C642C3B2B992BF22931288F286826C62792274928982AB42A95277F26E025BA26CC27CA288B275D2610277B276A262C29CC2A332A9E29B02745288F25B8263E27B228E22B402C3B2CC62D182D2F2CE729432A7B29EC285434B22F2629972657263C2771258C253825C0275E28CD29BB2B072DBB2C792B402AD9274A2A232B4F2CC92B192AC42C06290E27542653264F2792273029AF2860282028AB27B62602262126C4276A281B247D2607262E27212AC82B9528B827FB244F26CA249C2596243628372A8D2B7E2BEA2BB32B132C3C2B0F2AE5283C291F33602F042A3A278F253D25542570253526A0270E28FC277C28132A4E2CBE2A9929AD28B727E429272B662A2E29102AB829A62819282F2434251C2762280A2829287A28FE279F27BA25DB24FC245B257325DA257A26FC284028072A842A9F26C225E62431242225ED21AF24D2274E28252A2829B229D12AD429F529F428AC27ED31CD2F032BB9275625A825B7246F247326212836273829E729B729C529F62A1C29A2269929682BBE2ACD2A6F2AB42A1E2B3B298C29A7270B2534287D279E28052A7A2A092A612A6526A22546248724C724BA27A227122886286E2AC028482885266A247C24B124DB24F5256723E425BD273228482729286C293F2A62277D27BD3144309B29B82826260F26FA25862656272C2690274A272D2A4D293C2A132B8528C327072A252A482C502A6E2947282C29B429CC29BE27B6260726D828882A322A892BC72A34297D27E527B025172663283329712C2829F1275328D827A629682877265325EB246A26C62747253726E127D228F32818295728BF27FC25FC254E30432E7E284F289225092577230325EA261C265A263928CE281729CE294129BE286628FA29ED2A3F2C082BEB29B32A952BE429D62ADE28BA2689260126A529262C162BEE29FD2A1D2BCD2ABC270726BA290C2AA92D4E2AF5272A299A288C26522439247B26012A8A28C228D126A926602665270329A6296429DF29432946290C326B2E7D27E324F1255B24E0233C25EF25D2263E26B9252C283629942A9B2AB52954287E287C2B062CA92BCB29692B432B7F2B612ACA2AC4289A276E278B29C62C3E2BBE2BB12B8E28392AB42709277E27DE28A72A3F2A162AED29FA29BA29EF253525B62798290D2AE9280427E02565267B26B329882B382AA92AB62A0A2A1C317D2DB1257D230323F523F72256253A24822539261826AB26BF260528902AFA287126FA270C29D82B102A102AE02BF82BBD2AFA2A7B2A652B3F29A5270D2ADE2B6B2C9B2A932A32292E2A0228982798265D28F5297A296B28FD28D72618287126C4268226EC275E27F12923281226AD276B27D1273429862A972A672CDB2C9F31B02C64276F243E245124EF226D254323DD256B258D22BD24892731276C278D273C264227DA275A297C2AE529632A7B2BD82A712BE22B4F2B1429F629432A992B1C2C552C812B5329E42BE42ABB279424C228102A3E294028B526262679286527C22710270428EC2A022BAE29F028AD2769279428F2287928752AE82B092C3834342C922766247F221A23DA213422E622512226230624E123122504256426A226E424C323EB26D02556280828B3291C297327B4291228D9277A28C129DD29C52BC12B4A2DDD2B5628F22997287729B8255A26EB285B285A26822787284C28FC2732261328042B2A2AD52CDA2BBD2B482AD72A46276D275528F42AC42D692C5C35902CC7272024F423F122B5218E21BD235224352362247F259F231E24B52535253E23F423B824F425F5242725A5253F26D327C12903295F288128DE289E296A2B562A782AFC291E2864282A2A792A982762273929D12831296C280C27A429E2291B2B19281329AA2A1A2BE929D22A062B4C28C0292C2995279129CA2C6C2EA7348C2B4A27BC23E5234423592341210324512428237122C22399237C23E523EF2450237423C323ED256D24C923E2265826ED272C28EA279D27F4258A2602278B28D8275C2818281E288C288F29B8293E2981271428CF28B6280D281728F6287629F72AC128A427EE29BD299A286D274D282D2AFA2BFB297728CA28232B982C9533642FDE258C22DE22AB23C521D222042289226E2557232823EF216D219423D822C222CD242F2255243B2400244724EA25C4256326112668231D259124572499268626F92468240726622678287A2838261326E827F2288F287F2904286429222BE32A17285027EF2663289626FA257B270928EA2A3D2A62272929D22AD62B1635362D50279A220C234E21B022F521AE22AE23A223B924C0221D22D02372235C242B234724B423DC23AB223424D625B2240F25F226682567243D26582380247A22A3258C24B0247A26C424EB2678286F264825C925AA26AF28F028F32753289C2A972B2F2922276127CA27F5261F276D27B8262A2AF629CF2845292C2BF32DB535EA2B2D25DA22452047214E2248210D2253217E228C220023742287220424F824462354247223DD23402404240624272424277F25E425CB258125B224E123A4225B236B244F25F423BB238F273027CF25B6250827E52522282B2888277A298F2B8C2999273326BD264F25F2256B25AB27212849282C29F5280427192B692E8135ED2BC5258A2293232024A8232A2257245F23BB23BA21C022F2222F224D24612466230E230C248F24E1225724BD230C258B233226D625A926AD285A27BA242A2670252724042642251C25F126BB2847279328BA28FF25472593275B27BF276428DA29BD285425C22480248625B4262C290D2CC02BC42B722AB92A962A2E2C4A36B12B20255D222124F2212324E8222F223423C3238F235722CE22832097227122B2222623E723A223552415232B25FB23952340256D24C327AC289A28F7253624712605281D276C26252687271027AF26D7287F263327CB25B8281B2BAA293828652969283027D923CC247C25F326CC2A512CC02C232BD429D82B812BD12ADB34512C03273124AD210722C520C923CF2261214722A7222C22E61F632285227C23FF220B23A3237924AE23572441248A24FB24CE244E24F726F42758273D27E025CE27C6290E2A8028C527A528FA288128242930289326FC263B29132B582BB527E92882279424A8231B25DB26AD2537297729332C4A2B632ACE2B5D2BA72B2934D72B4D262E2422239022502266223121DB2153231422D2226622B821B321F2217721B0239D23DE220622EF211B27F524CE218E2142231823D925EE26C82609283B270528B6294D28BB26642628289128ED298E2745269E28E129282A902BC62AC329A42811270E23ED2418263228BC2A7D29442AB92A722AF82A682B812BF731462D0B27E423502398220522D4227E21B42399230B22FD22C0219122BF22F121BB216321BE239222D8238C229C227C22CA221723042284241C24BC2442261A283127542852296D28C928B0278A275B29862A68295A267D267B27AC2827295B2CE62BAC2A3A2966271426CB26D128FF2A302AB52763265D27B4287328F9284632692CF725192302249522BE215622FA2260223A217821AA214821172316231421522102212D257323E821E321812226233422DC213E2359235C214722DC23A925A7265B2755260227CA2793291528A828A529AD28DE25AD25E2261628B22AD72B392BB229512A1E28FD27FF260429EB288127C626DA257725EF2468271328FA31A62AD02535223B202922792231225C22D12286229121F3212D21FC2014229C223021812291230E234A22F2231522A62328230422C6211022A3211622AD222D242F260025782566265326EA264C272E270829D8279625C4243D25A424562766289B284B287226A324EE252D28AB26FE25E024B22624242D22AE246D24E0273431782B0625D821AD21BD21962193223321BC21E821EB20D6203F2178213C223E22DF20A7203823312332235F230F226A216921B122B8227821862273212A222D22D1238C23EF233D24322620280C286F250E263827BA25D92304258A2353248B253C27C125CF25BE22E7245525FA241225EA233B254125D0237323DC2429271730602C7425A52211211E238D21A3207B220A210922FB20F9209920991F881FB8200A2145223423DA23A7217721E6231A223120A92016217520DE21D520512160232523B6225822E621F52469261B265F24C82401265E23032381228C22CF23882329251C255E25B2236A24802402268825EF2353245924612287238D252D2570302B2C8C245D23082125212421392185213D224922AD20FA1FA11F032107216B203421AC228B213723C7218A21832279209F21D3201C2045201C214222972114220323BD21C121EE2144238C247E246C246724B125A92388227B23C42242228D2320241D26CF26E2252226502514258225F1254C246224EC24BA24ED2564271A32142C0626CE23FA213622E0201221AE20BB227621992173213720851F7920CB216221FF21F6208122512135213A23EE21332150222720F51FF021A120892052208D222E22A520B7209121DF230922BC238D250024FA236D222724552389223824E523B825B727532742286127B1245526DF2657242926CC2416260228892A3734FC29C1240121FB21CD21991F0F20AB2043211F2189210920A21F8E1E4A1E65208A203621AA217421AB200A21E820E621C02016202920A620232202221F2152214C22372244216D202C215E23DD2214217E2471253D23CD218F2317227721BA239925A725F6275F28DA282F268025FF25F4258525B02545256326F9267F2AB534A62A17243822D11F95213A20B6214E22A720252178213C21EA1F181F9720932090208620E3234F216321951F2421A4218120B11FC0202A213921B01F0A1FA420D1217020EF1F8321AE212B21F023E922E82587231623B3220D2391222322AA220A231725AB282229E22A4E288C260725D0264427B4283B286A273727052B4D35F12ABE23FA20232235211E21A61FD32253210B22702260239E205B209C224122B12093211C2066232822E11EBC214D220D22C220D11F682030217520071F6720531F09205A20D31FC51F0522F7211322A924E62206237B243A2454224921672354235F25CD25B926F3274726F6256427B524FD25F8265725F7269127872BB8343F2BA323D522D920C1212F21D5203622C721002020210C2164220921E62178228D201621E620D12266228620F420C91F011F072167202720E11F3920F11EA21EDA1FC421991FF71FF920A61ED8222B22B3246823CC227522DB225622D421BC227D23DD226D25B8245327F2246E252F24E62588258A27AD25F72632283E29F7338929B2249321B421621F85217C20601F11217921352282203720A3217720FE1F642140210F22C0210420DF200E2136203D205F21D11FA91FF71F0A1E8B1EC81E211EEB1E071F781E731F8E1FF41F0921A823A7247023A2229822132382220A24EC23B4216C2100239A25E82475242624D5242D25DC2536257C253026CE28B033142B58243D226B201B205220EA202F221B21F51F8421F7200621131FC91F4420581F5A2217222D222E21E3213320AE22A3212D219E1F8E20CD2069208D205420E41FEC1FFC1ED61F101F6B21B321B222EB2102243223F3228A232B228C2253230A230022AD2296231B259D239B232B247B24E523B6242C253C268C265526C9310F2A2324B620D02059203C207620CE1F4D218F1F11208220AC1FE21F9C20D9214221D32045209420462077209421D01F6F1F801F401F321FFF1FCE1F021FFF1E081FFA1C891D561CB71F961E2621F62055210A23EE20E020E2212E23E021272358224E2137211122D5215D212124F3234A23B7228F23992371246C24E6268D31672BE52440235D20881FB9209220E42047212A2148217A228820B11FAF21CE21322109216B21F81FF420E51F7B209B21E92047212A22A11FED1FB01F111ECC1E451EF41CB21E711EE81FB31F5F20F91F1A214621242120231F24302233224C23B623BE23FD2087226E239A220D22EF22EB216B221623D5227D24F7241427CD30B42BA723BA21E8207820CE209C20EC1F9320B3209F1FAD203F20DC1F1A2049203D206D202321422082204B20FC1F0121FE1F0920971E6C20731F271F5D1FF81DCE1DBA1C5F1E8A1F57202C20881FD4209E216820802019236A2185218521DF2019230823BD228221EF213F22EB2132237621BE21A523E623922366255A25AB30C6293824A222DC206A204321031F5420C620DF20B92123200C22DB20C9219820F020F0206A218620E320F91F10213A232E1F69200F205920761EF11EE31F121EB31DE01D9D1D9A1D831F6B206B20A31FF22156208C2076206221CC1F0B20D822B3212122822107214322AC22DE216A221822A0206C22B81FF9218C232A254430B72AAB257E203722F72012213F21F11F60226E1FB31F3E2182224F21DB204E22F41FF4206221FC215F205420CA208B22C920F91F5D1F00205120B21FDD1DC21DD61D571F511E5A1EE21E3D201A21B51FA820E221F820C520F5219F1F95206D20AD22BB1F1820C51F2321C41F5322BD206523CB205B211123CD22E6232525E72E8B2AC425E0210E21D52020219420C520FC211D21ED20BF20D4216B1E881FEB1F3D21F821D11F8622502024200C21FF1FF91F671E8C1F741D7220A21ECB20461F961FC11EE81E351E7420611F5F2085201620F61FF92001200A22301FBB20772017221521C6216C21D4221A20E1211222C221DE20C821892268245A2449255B30562C7925692124217F213322F91F3621EA216F213C2212213220702171211F21CC215222E1208522FE1F7B1F9320D921EE1F76200C1F3B1E251FBF1FF81E6E201E20411DA51D171F521EC6203D219C1EC421AC218120F91D0121D8207E22B62082214421B22146206C221022F7209120C1226321C8221621C722C721B423B72ED32A97241122CE203820AF2025222321A422FA21EC20C221D22170200422AE2036214421B721DC20062052218B210A210E201F212620E31E9F1F30215B20241FC71F6E1E331FBE1EDC1FCE203C209E1FBC1F26202A202C1FF31F4A209821E1208F20C2213D21EF1F9F205520D11FFA217721E6216122DB20722266237F244A3087290F23B021302131209821591FAD20A3226D219821EC200C2187207A205721832097207122BA21851F971F13206020481FB520E41EC420D51F001E67204A1F641E511F9D20CB1D13207D20911EC61F1820AD20841F89206C21BD201E200E1F30207C208C20671F7920D01F4720F2207720A1203D22A520A32298221624152ED02A1524BB204822242267213B21BA21DB22422088206F22A320992127215C21132289212321FD211E21AB20F32144214E1FEF2062206E1F631F4B209D2088200B20991F951E441FE21FE81F64209A209421DF208F20AA1F47200B217F1FE920B320F71FA91F262090202521F7203F23DC203F2176210921ED2185225725692FE72941258C23DB20AE21BA219E201A206521FD210F21222235201621C9200223C6206E21B9221921BE215A20A4210D20CA1F6821651F55207120D71EA71E451E541FD61D071FEC1EE81EFC1EDD1F2920D5202A20AD1E46219920BC1F0220832033228C202F21A321902163209B2082205B213922F11F8B214C223E22F522D72FDB2BD8251A22E220FC20CE20AA20C62016214821A61F05206C1F9D1F4221951EFE1F8E208720432111220021BB203F1F33204D214421591F6420AF1E941F4120DE1FEE1E571F171DF01ECF1E6D1EC01E75202A21242005208C1FD71FD91F9C2015210E21C0205320F5215520DF20662209204D20EB20521F7720C2233E243830372AD624F721F420C520842121207D221F1F9C207A207E20EC1F56211C217E1F221F612107202F21A11FAD1F5B2039200B1FF820B820881F6121F91FA620D31F1B208C1F921E8C1DE61ED01F201F391F351F39218C20EF1F3A1FCF1F1C201E202D21AD2061208F1FCB21181FAB20AA1FB91F1B21EC204A203F224922A024982E5F2A17239A21052322217A21752029212E21F71FC72179213C2036211A2169211922032029219C225E219A1F0A21D621BD1E5120AB1F381F861FA91E0920851E941FEB1FE520601EB11E7A1F2B201E1F2A2021225D1F821F9521A32030211D21951F2B1F322043207E2147219D1FE52057219E1F352023204320CB214423B32CC52A77256D218721B2223E2025210021862122229B20BC20EC2194209A1F35224C2222228B217C223120E71EA2205221A21F261F0620DD20C01EE01F761F291E9B207C20331F871DD3201B1F3B20A31E1521D920151FAA1F3521F31E6E22321FB5214421D620401FAB20F61F902046227920C41ED91F0C206F211922E923712F772C4125BF21862159238720BE217720622108218021FE1FBC20861F45203C20B4201621D61F25217220FD1F3C2096216521DC1F511FF01C481F8A1E63203A1F4C1F1C1F2720941F911D6E21F21FAD1E8A1F2020101EFD1F0F208F1F221F5E202A20831FA020721EA72077202720C01F77206120FA20D7202E218A217623902F1F2B492589230021B920D120BE21102197224F21EF20E320EC1FCF213622581F932104216C21522235214220ED2055209820DD207E1EC81DEE205F202820081FF31F31215E1F601EE31D831F481E1B1F50203420E11DD71EEF200320AD20761E002100215720002102201A20E01F80210220FB1F7A20631ED921B2220B25EB2DD12AF824B722E521D92092215822F621F221B52049211E226020FE1F0321C5214F210E202E203D2175213620ED1F4D201C21D51F1E1E4E1F311E50201A1FD31F9A1F771F92204E1E8C1D0A1FD01EC11EAA1FCB1EDB1EDB1E8C1F9420A71FCD21A920251F202035218921FA1EB71F1120DF1F071FC420CD1FB1213F231B24882D712AB52539219620BB1FBA1FC52139211A21A81F5B21E21E7E1F8A1F0920E51F8920D61F6C20A0205A21431EAB1FA1229721C320051F4D1E5A1FCE1EBB204521581FE11EFF1F461D2E1EFA1E5B1E021F651F1820EA20BE1EE320C61F6E1F121F1F21B21F831E661E4A209420321FFE1F861ED11F3F218220D22029230725182EAE2B6E258823EA213B22AC2114212E21F7210821BD212320CF207E1F7A20C61FFD1E7820FA1F5F20D41E801E951FE620D120941F601EE41FE11FD21FA520C1201E2176208A1F8C1E1D202420F21F6A1F2F1F2820811E3120B5202C20001F38208420D41F65208B207321F81E0A1FD21F4021BA1E2C20F91FB920A720BE24742FE12AC5238121E0213E2129203920E521841F65204820EA1FAC1F5A1EED1E5120CF1FF41E28212B21E71F321EA7202620871F4D207520C91F771FD41EA51E6C200B20E720401E7F1E581DA41F641EAF1ECF1E651F6D1EF21E9F20BA1ED21F921F8B1FD91FED1FD61FCB1F34203521E11DA01EEA1F6320F12081213E237A248F2DE22A092472205B219B213420342103211C21E0219021791FBD1F2B1F2F2042205C20E52066200120AB20511E0821311E3920A620061EEE1FB51E5D1F211F05211B203E1F851F951FAB1DF01F991FDB1E7721D120611DEA1F311FCF1FD41F7521C01F8B1DBF20EF1F6E1EA81F931E241F221F422018211A1FFE214A220E25DD2DAE2AE5249421AF20872186218A200F231E218C202F202820711ECD1E5220D021F81F8A20A1226A1FBF203920C520541FA0209421821F6D1FD51EAC1FA61E23208C1F731D691F7C1E361E1320B41F881E9D20A61FCE1F961EFA20791F3322F11FB51F661FFE1FC01EA120DB1D8E1F742004216F1F2E20AE20872177202023972E0D2CC924A9201422CB21E52118213A235422F920F720872116208D1EF520BE20DF2160215F214D1F4221E91F9D20ED1F7B1FBE21C11FFC1D521F6F212F1F301F601E341D601F451EA81D911F191F6B1EA2202721271FA31FE71E571EF41E691F6E20451FF01EF11DC11F5A1FB31FEC204C20E220901F291FA7202E23112453300F2C2E25F0225F20FB224123CD21322217236D2266230022CE209620B121E91FAC206422F920681FAE20C11F262171202220DF212421A51F72207E1EFF1E241F131E161E111D7C1E361F741E2D1FF720032128206020D91D6E1C4D1EAB1E7C20B11F24208A1F4B1ED41F361FAE1FE4207B1F94224921261FA01FE322C224862E ++ USBDEVFS_REAPURBNDELAY 0 3 130 0 0 18432 18432 0 FB28092311230221A821FB20D51F3A20A020BD1F671FDF1EDC1E251E0220441E711D861F2D1F3D1D1B1F9D1E7620DB1EE31FD81E3C200D20B51F8C1FA6214D20081FB91FC41E1B1DAB1D7C1F591FEB1FB01F7E211A202420C120DA1F391F1D201221CC205620D71D7D1FED1ECB1D5920741E092123202E20F71EA6212523402ED42B6A242921EF22AA22ED208721E021AF21B81FDA201620DF1EB41F791F171F7E1EE11ED71E711EA91E5620CF20F021691F3E21E31F2E219D20B32127227E20B520B5219920FF202D1F6B21C51FF41F7322E62103214321E821C8237B222C2148217C21D32155206721612155206320BD1F5221F321B6215F228F22CA24142EBB2B1F25DB23BE2292210221A1218B22A7200A2371224C22AB20FA1F65205F20602016212520101F511F2D21F720AC20D121452237219D2135220D1F822157231F23FA2397228B227D205F216C20342079219922182296232F248D213A233A23212300234822F22010221622B6213A202820852085239021752204230026BA2FFF2BEB275324D521E3218E21BB227521F320922064202220AE20DF1F61211F1F302057201220F821EB1F5C20B51F8C217A2198226C217922722115212F20782235242424F2240B229A2100229420BD1F27215022FD225D24A524B32497254125D8254D2437245E236C226F217220EB203C21682143227E23EE216A2339251B2FB82C69265722A7218A215A226D21D121EA2147211D213C215A20C01F7521E620911F492191206E209920F42063230120DE204524BA21BE1E4E225D225D22FB22FD240626C9251B23F723BB232622FF2287217723142252230E258F26282692255426E5256426222414252C233D2359225022E9214922F9200E221924A0240E2E062B13268D22DB23D720D32264213021B322AC213A22E0229020BB204521A821CF214D21A9203922E620E5204E22382343218E22EE211022302214233E23BE24A02597264D26132592278225BA252D245A2382234D238923BD23FC250C27D727FA279427E8253126B2255825D523A5235022F8225D243C233822BC24E2257F2EEF2AF723CA2273228C21C921F522082285218E226C224621AA216D21EA22CE225023D8217E22BC213023D022B1215B22AD20302193222A23B5230A24D3250326B025E62620274D27CC27A827472782250D26D4264424A62318240D250F25B126F1270B262D270C2665259E24F6234823F8233B225223B121E7228723F823BB2E632B9425E522E9239D22C7208D217C224C222A2365210822462333242422582299238623F1231B243F23BA2169225024E621D821C422C0224F24912556256F258C26F326AC27DA26F827EA29352BA727B6294E29002785244F24612224240C2512269926C926F525BD2561244A23A6234E23F422852283215B234A237025852FEA2A34267F245D23DF2374223F2185235A24DE236423AF22F122E022D2231D221423BB2432250F25C2240923FC206E23B121112391217621782232258C258626EE279028D6278C2766276E276C276728492AFA29032BC227ED278F241B23AC2323251E2545277B266526F6231622F52212249722D9225422922221241F24DC2F4B2D9C240D2342238D23EA22CA236823EE246E2333258C24BD22E62346244B242325A22402268C2546251D259D2234236B21DC2371239C214E241C237624E026502889299B28832877270F291729F12709299C2A4B2A69283F250524E7218122D926EF24F3239025C3244524FE23102374237C2491238123D822EF24A025E431222C8E289B256B243525AD23A423A323FC236A244826E324A924A2226324F3246D252025DE25982643247425B6236E24582107210721EF20D921FF212A23B52430284C289328BD2977285D275828B625D02602263026BA2506251A23E721F02232230E23EF22CE238A247C229821FD230A248623D423332245245925B4256532942E7A282426D127BA247A23C623232315259E253D25CB24C1232D247624D3255C25B32554265F29C226D627362487235823B822DF22DD21CC20C420E022142458250B28AA27DE280429FD27BB2731266126B6241C259D24BA238B226F213F2288223F234C2442220625F324A724E5268B266426D3258225D2242C257929B633C030832B3E281B2605253E24052487226124AC238623C025652487264A26CE27FC267026D225AB284527822684249B26AA24302417237F219E217822D821FA23FE23F4260829D12821282529802A3A276E247A25662350235C245A2444220C2451228922EB20AB216A231A253126A02885281628A629632754265A27C42ACE32CE2FC82A90281027F126D723EC2332247D24CE23D9224A23A0234825FD27DC262728D52706276A27AA2644258C24C424E124382421222121FD22A1206320F91F4F2316256A26FD26CA28A428B82847258126E8251B2352228122C0236F24D92412255B217B213021ED230B2315241D279028AF29EB283D2638261F2763295434142FDF29D3285E265D272C253326B223BA25C0224524222532236925382778296328A829622A7C274725F023B6232424F6233922F720E6218E214820CF2040214324CD242726232726271C2645250125FE235E24F32376222C2395241524E224EB24D224C92341220724892365244326D627BF267027F32373246B2644276430EB2F602A92273E25E825DB2609261D2646246525C7254024AC22BD25FA27ED29C128B628222774252126F22557226A220D2101225B2288210A216B2142210A22B924B225FF266226B8249E26DB2365239024FB20672113220C24DC242326FE26D52737249224CB22D823D624D422522569255226E0250D26FC2484251D27CF2FE92D1E2A32296B285A268526CE2612271F266126F627F525F824EA24AE2508274C27CF25A4253F240B25E02238239123C0225923DB22F3203B22F522FA22352580279D2AD02B0B2971252522AE215F2262223B22FB21D8232C27B626E5266A2810286D250E2595229922702292229421E024052582256226482648267C28AE31092F6929E7289A25E82617280E2886283F29B7290D2936272025B1242823BD23DD238D244925E82256226023AE22EA229D21ED233A2446236D23052241243926542A3D2B31299326F225A1239E214D20B421EC2358230723B0274426E025E425FF2743248524FF21A723C5217E24E723352572244E24EB2434267D26ED2773332F2D802B7328AF28FD283B29D52ADE2A372B532AE8294726CF24F8236D24C1224A23782505239325162486222A24A2250323C52499249024D423D622EA24B326D629DA2A3429A224F524592320235920B1223522A223E22483253C256E25B42571259226452784238524CB22C0215221FF22D1224A231C24C427C227EF29F133532FA6280A28B229462AED2A3B2A172B1229A9276626D125AE240D225324CA239B23AC2067231324B822F32201233C2494252C2515233D2240261523A624122421277628DF25AA242923B62230216D22DD22B223AC232E25FF2700266A25A925A426D225B0259C258125B221E120BD23D32201232024DA24A327F429572A3933A72E5629C0299F2A2F2B622B3B29EF2760274526AE26252461220B22F721F222F421AB240F2379221523B82546256A253B26B924622569247D24D9242C24E5254426FF265925C52489229022412505237F255726C1267527ED250A276C24F323BE24D8230025ED24D625182419239226EB23A1249927DD25FE293B2B2D2ABB33172FB228BB28E4272E28C4289527412662261D25A3222B246B234A24DE222A23C523192295243923DA24E7253227E326C825F425D423AF241E2641245C25FC2321250D26EA24EF242E257A259925C126A1286428C226F2261D261725CD221C23E5239A257425D6269E274F2517254324BF2418288E275F2AFF2BE12A482BA433592FEE287826D5264A272927342673241B2524248D242824DF2336228A248F238323772233238321F92271257A27C427F926AA26E2243A25852530231624DC239D22C8235724C624C024C3282728E82612295A281827C32499245D23CD22F523FB244B26A1299529002BD52AA02729265C274028F329B82AFF29EF29C329CA33CE30E4297E28F625AA256A234924A524372385223D232324EC21D2233E26F123F7234424BB22AC231824A626242A732CAB2A5D280525D825372524235F23A0229B22C6231B2244212925F2264228482810281526A526D124662461233423E224B6235D261129732AF92B39289326C5267C28E3287C2A302A882AEE28152AE4332D32022B872765252125E923EE22292315256E23B5251A25C6235124702484241624AF233F24B42677240925E3286C2A792A5429512721256A23D722F5216B22DD218E229C22D922A0234E24642799263C26D2252626C92592268F2430248724D426DA26E228972ADA290328E424F2262B27CF27EE29ED2A352C042C672AED33FF30252B1328D7261F24B4239E238B23E2232623AF24A8256B25CD26B227E2266B272424A42517261B262E274F25182864289A283C274524C2246223BB23AB224E23B0222D23AC2260216D23B2241D24EB269C26BC2589254E283C261C25732606252727DA2807288929A6271A26B42663267A252427C0280E2BD62AB62CFB34A431122CDB2876254C2558248523D123D023DA23922646288E276B29CE291D29952895271426DA28D927D425AD24A22687259825F7251F2350230823F7235B227C23F4223E24DE2177231022632393242824B1269A27872816297C29A226E9261D25EB2554284E29752A7C281E274226D22466243426AB273A280E2AD12ACA331832E02DA228192869259724162496245B247424B927BD28C62DDE2B572BEE29F62726286328FA295C2949277D25B0242C24342376213122D9218622C022712349249F24C923FB213223E0211B232622D023EF24032724293A299528E42493245127762687273C2AC02B942A6929BF2634251B23A3245C2514277B27302A23342E333E2DF62B1E2AD426AF238724B2241E26FE25B425FB287329112C022A282AF129DE28F3295929F628AB275325D22358223423D520B4202D22EF22EC21F423E22451250525B822F8220023652141221E24462465264727DF287C255C25922643272228F427152ADD2A2D2B082A7729CE25D2245024B823AD2474279327A1310F331E2D9628BE265B258C26A624EB2461272C267228A82609275126F226C2276528B927CF2740294B26B9258C23FA24882166213A219420802193214A22462336231523E52367239522502338231F24922536259B262B24C5259C24FE2417262D280129802937299D29402A6128E9257023BE22A423A62229232F25C425D2304D31282B472976270227F924EE2411279827432A4227DB268F24CE2416247823282583253A260F2506232B2240244F239E213321F321B31F2B2104227E220C22CA218722D2225C22CD229A22DE24E72599262828A8233423CF236C241D23CC243D250E287C271E25072871281E28CC25B8223621BF21BF2133248124E924702F21305D2CAC28B028A3272924BA24A6253A2A562CFD2B8A28A8246F24552622262824632427242124E920A0215A2160209E201F2248219A20B6213E202F22C8217B2480230124AD2145230E2617272A269127F327E12322235F23CD22C8231023CB244E25FF232125FB241E24F4230B23E321092383214F22F721FE247525832FBA2E9528B7269F2501269C252E275727D128C22A612AFD2738266624D223CA239B2378214E23E7214D21AB21DF2001204520DC21D321F22148212E213A20E421D6229F24AC242E24FF23DE275D276927CC2721278C24B8225F220522962244210C2332231323D322E3240C24BE22EF2195225A22B32377228B23AB24332530301E2EDE28CA256426D525A327E92580272529F6286B27FF2571242224BF232E239821E722B2210B22E0226B214923A42140213822AB22D61F7F2153221A21C421A924B425C725712590270A2628269825662746262922362225222F21292107211321FD21F42289238A2338217C20EB207F2323244E237224E725BE258A255B31462DF9262C24F725D827C226272894262F2818269F253A247E24942238235922262279227A22BB225F253F240B24FE243323672207240D2103211022F1212B23EE233627B626DD263628F72754262B246125CD2495227822EA2097218D22E51FA521FF20C3200021F7214D2350228423A2237E25B82782271B2745271A26A430FE2B1527A526BE257827A127AA27C725EE246024C124EB24A023DB226D22AC2234248C23A0223825C1241D26E727B926112497245C257E22BA226D23AB22A723B8233825B0280E275C27252A7529D424A823942520249D21B222F7222F227C2250217221FA225C24F324B6231C223E248026F428862A7D2AB5296F286826E131192E5028BB274B27AA26A724FD232D242023A7237924B0223222CA203522B9221424142561246D262026512773277528562689259327D724C323BD24502366244824DE25D22576257326AC289C266C24E6241824DB222C21EF21CA1FD420C1204823FA1FB82296246924A224F72507288A29312BD42CCC2BE32AF5276F266030882FC02A19296927D22682256B2514258924B9235B2420220021EA24ED23F2237126F2257F2644274828CE25FF2793290E29CA277A27EF257625FA2422252027DE262027CF268025C82649260E26C423F224AF22CD23D4215421F4218E21EA20F421AD22B822872338272D27A229242CFF2CA02BF92DB42B2A2BCC299329D932BB2F242949278226E2249723EF22882231258E223323D523D9236324C325DF25662968290229C3284626322603282927362A70297C263426C2232024BD250326C8271E29F82859248723192415233F237A231721BA21CE2054213E2018215D22B722B6227623C524C026AE28D529EA2BBA2B8C2B9C2C8229F62B5A2B612B8F31682ED827A7250424652238224622622265229A227324BC24E323B5236B25E0266328B22A842AE828552749245325C9278A272327B125C3247A23BB227E242C24822679275D27DB24BD23F4220F22932132221222D220DD1F0C2229205C200521FC219023C5253F271D2939280228FB28D02A112B7D2CBB2B0D2DA72C922CA433072D98282E2599258A2412245C23452392246C23432277233E2588273928CA28F72B662CB9286B2936258224F224BF247825C2257A236923CA24CF211E23D12467262927922701265024C023F821052247239522DB21CA20D6206420ED217A237B226E246A26F028992B842AB32849276A2724284C29962A162CDA2BC62D59344F2D262685223C2401229822B12276230923732269234F2486249225CE27BC28202A892BC12AAF274F25C1231424902495248522F321EB20F82184226B22D5246725C927292A8626CF2480251C25FF2232227822E22200233B236721FD204A21F9233324D12484279D2AD1297B28012633255326A9294B2A792C192D102CD831302E5627AE2517245F269821E423EF23E6225722002305243624BB25E228E329952B7E2BC02AF9263324A4232D231D247C232122D321F322BE221023E4244D267F2705280B2A4A29A028DD2604267B243E24A622BE2340212422FA213F22DB212B237824F9243F271B2AD82AF728BD26CE244F267C28B52B542CE829B52BDE32E22D24280926BA25A22558251123C9238B23C623D923C423882379266C2666282F29222CFD29812661220F23A92328249421DC2487235821CF24AE2454266C2A542B322B552A0E284A272826E3268C24452463238D22B021D8224922C322BD244C239423242592265E28182815275226892592258C27F2272E281A29D52AFC331E2FBC29D02709264E26F925BE225822442516243B24D2236422F722022766284E29712B1A2848258225AB24A4243124EC22EB215322CA23892439261229F629B329652A362A2327E526C626CB249525012483259423F223C22126236323F4242C2645266826A726D027EF248B25DA255024D5248D2639270D2991291C2BE633C32FD929662789262A26682402247C24042598265025B1243324E3247326D3279429EB2AFF288327F72320241B253E243A253024D323A8248225FF23172819287728AE28E52855270C263E24CB25BF248924EF256A245A24C8242F225325AD276227BA26EE26C624F326B1257E24E925E924CF241D279D26AB28E62B9A2CDE341230372B022866252226452507256C248F25892581261D2401234824F925BC276C29532B0A266C256B24ED22E62346250625C3253226EB275628DF269C27AF279F26532529274A276926CA252827EF246D252025DF26D9252A23C8249F25AC264B264A280D26DA257326DC2440241C27722592248F2603261928212A392C5635BF2F4F2997272A2630246C253A232E243A26A9273626C6256724CD24A22458268E28F026E8259825F0232E2393254425D6245D261228E828D828F92876266E240E24522450273327AB27B5278E267326D026CA274B267F250D25F62399242B26552749299B2956275D26B125CB26DD262F268826AE266E260328C7296E2B8A34E82E4929752685254B25B3253C258C236D250B2788286D26A525D42404258C237C264B238C240C24F722E724FC245B274E27A126D925472739290426DD24C8230224042550296029512A2829ED28932763275B289E258125B8266F262525032654265426712811276B27DA26F72502284D2881264025B025CC28702A622C0A33E62C46288B253D262027EF2519236524792600261526722798260226A82412255322A9226A23522591255424CF2486249526942793274F28EB27B52615266425D425FD265D29772B5A2B302B742AB129CA279A272D261C241A270129DA267E24DD22FE26AF2642281C274C267E25892601270F27E2256D25CB28EB28022ACF33902DC327E426A6251827632744281F26D5259D249B2642286B298A27F2248A2285232126422443260524FF25B225B4260A245F248C26B72635285A2A4A2AF0276325C1265F283E2AC42BFB298C29C828BC28BF255925482629283A2ADE277B263525B32605263726FB27F6262226812652253C24EF249D25F82957283F2A9E32C32D3629AE27EA260E278628BF2708269F26CC251E279C27D028C427DF24D122DD21CE225F2319274E25A5251A27732746244326A525F7265E2AF829792B402A9629C3292828F927A7286729CA28C42690267C26EE24D4235D25732608260225B82412254F2592242E292928DB2527255D240E246A236423F0258F2865293834982D0D2896280627B028FD28D427B924F825C32610272B29022BE027A0254B237C226124C22228262727AF26D9270927FC262B243426B826C429302A2F2C9C2A2A2AF92A7C293828A0289A27E8276B265525D524E522C22315261E258D244425C724FA24FD23D0249C24DC240D260325D5225122A1247223882577266E29E236DD30C228B227BA26E527A3270D269826BB240524FC26C6289128F026EF248925DC228B24312508265224E7260829DC291F290D283426A0278428D529E92B212B732D7E2C0C2A042823266726AD2449244025D2244D23D92447244625C5234025EC2682240023352453266B248025AB2615243A22FA23C7229625BB27302A03359830B32B6E282F28462872276925DE24F722492437278C2A75286128B724CD23652357233925A0255C27F4257929362BCC29F729292C83289829362B8A2AA12A9D2CBB2C222BC82AA1274824CF23B4223724A6251C249C24F924AC269325822660281726CA244C2545263725C123AE24CC23F323F1254224B52551289E291B33A132822CF02A012890243E26BC2383247B256324D0269029D02AD226C824892201258525AD2667292928CF27EE26A0294B2A742B292A792B3E2A942A062B172A032CA72EFE2B4E2CD0281F2512221222AB23A1242E238324DD25C9270828C527AC27C12617272424342762264B24CF251F25DF248B27EB24BB249828CB2BE4344E312D2CB6295D288024F1231C231A25CF22452277266D25ED27D92518266A24212603274A2821292F2AAA25FC267626B5293C2BB32A8929F828DA2738296E2AA62B8C2E8D2D882CB429A325542530235E234625DD24842575289229262AFD283C271F267E262526A5262F2714280F278F241E23852690242526E326D62A36351332DA29EE286626AC2594225C24112379236E24AB244524842573259F262D2558263C27AF276729E1275226D1242D26F0260228042A352A6D289326C727D328642BB62D522DB62BBA28B624F62401232E25AE25E0268F26742A4D2AE3295629B32753289629942750297B29322AF428D0265A27D5277326F927A226122A39352530BF292B285925CF23C5239223F623F523F8239A2459245426DA246B27D9261626F02503274B2884272B2738280D27F825292682293629162AF228FB291B2A502A9C2CD72DF82AEA293028C2242A2397243525CD2667297B2AAB2A9C298B277B27C529D02B1B2AEF2B3D2BBE2B802BCB27CE2881266624CE25702520291336642F4F285B27D22508256F243E236D232B24352324244223A92487261D29B027DB26F42653269F2706278F281A29C729E12A6628212611260429302BD22A582C692BA62D9E2C672C952A7129942752257B25BB24C1290F2BA42B7A2AEB279327D0277D281E2BFF29F32BC4296927B529EF28D326FC243324432474263229CC33922E0328F42568250E258A243622972378233F2371243E243B255325F127F22ABA299228B5275027BA27552A1B2B272CDF299B270627EB278C289B2C5E2B332B352CE22DF82C502C162B06291D2748258D254F27EE274E2B962AB129E329ED2824297A29F729132A592BED280B27212613269925F324CF22A625BA273C292033A42C2F285D243824CD22FF210C231F238E241B23232406236125B227F02ADA29CC293228D2274728EB26D5297A2B0B2BDC295429B32683262928F22A7B2C542C6E2D812D442E612D442A0329BF298E273B27BF267A28DC2A3C2D6B2ABB2967292C2BF12BAC2C492AC52A7A285E26DA25CA242825A2260B271928222718298C31C12CE927E2269522B422D222AE226721D622A9233C244B240425D528FA29502C5B292228B326CE28EF2585289B28982AA92AB42B3C28E62548275529F62A702CA02B282C6A2E042AF929D429032BE628C129A728E6260228272DEB2A9C2A2C2BBF2BBB2B542BF92B332B8F29BF278525D7247923D029EA273628BE2ADA2A8132732EF825BE24D02261230625702215226923F622A424EC247125D927FA2A4229142AC829DB2831273129A8280D275D2A4C2CEB2AB32B84286C26D4254A285F29732B202CB62A252AA6289D28902A4129E129DE29FA271727F5294A2CB02A9D2B722A6C2B2B2AEA2A722B852700259227242589252429BE29152A392D912A1835A42DC327C922B922B123AD223C236822762306240023DF2383246B27322A5E2CCB2970290A29882A4A2A822B802ACF29D22A702DDC2B932A47290327E925C7272C2A0B2BBD296A287B284F296028CE285F2A09290428D2253828E8274929892A732BC0281029BE2B132B4E27572412261B278D2AE62AA12B942BFF2D2E2EA036412C9027D323B9243022292335243123D122D9204D25A9224426B926642AF82A462B0129CF29B22AB82AB12AD528602AEA2A572B8A2CDE29BE294D27F323BE25A228472A66297428052A44289925FE24E4267827EE25C024C624CD2560272427B9299C29E72969291028ED25E3239A264927B02A8B2C522D6E2D202D942E9036292A842654239F228824C5220B217723F82002229722C921232545267C2A842B7C2A132A31298E2A6B2ADA294A2A29290C27E327F4270A293C2878259824E5253828142A4B2C092AD426222604252123A3231427FD225B23C525172632268B26BB25BA26FD272A267028F525D3250E27EF28142BF02CEB2CD32C1E2F312F68365E2B1926AF242F245623D7227F212E23DE21CE21FA224B24E722DF2536285E29782ACE29B228F02AFB2AD228D929042665250427E327D8255626E9262525B3248328FB29C729D8278325F3245825E225452647269D25BA24A3234523A7242123DC24E427DC2660268D2614253328EE26BE27572A272DCC2BD72BEA2D6D2EED33122CEF25232491221323EB239B227822F42232225222862192230C255F26F82742276028D628BF2B012C0B2A6E28712898254D2593255026312860272A268A248C280D291127BF266B25F623C925C0244C27F128F6269527F2252A23BC243125C2264028D62655273E26E027822688264B27E8287A29AB2A772DFF2C102C6F33022BB0256B23B421DF2287237E22D3200723EF21ED22CB2309233324A826CC235A259E285A283629252A6D2830282F28F22729287528E9269E288C2855276C2828292929B728672460251F27E627FC26C7292C2A272A5928AE297D2804266F288529282A702A6E281128A4266A278C288F268B28D6288E2A1B2C582CE32B92329B2A522504242923B9214D22C6218722AD2316236F22B3242F227D235F2662253827C7261528CA28942860280C283729E929BE2A4D2BF5286629E4278727A9277929712862283B261A271228F129352BF92CF12BD22B962AEB2C862AF929CE2A6B2B3A2B972ADB288629C428002AB728E42675275A27462A4E2B7F2B3D2BFA33D02DC4256E235223DA22AA22C720FA21DC235323FC215A248B226E23B7240E27AC2663275C28152740288E27FE28452A8A2AFD2AC52A7D2A9428D12601255427F729DF28922A24283828D229972B172C3C2C0C2DCB29242BA92A5F2D112A7829AA2BB02ADE2B922A7929F629452A462A362981273228742A232DBC2A9B2B3135602C79256C221D2215236B22C222BD227B222122DE238C23AE2309225F24B62647251E252F278F27612641265C2680286928102AFB290D299027C2241126F0292D2A582A042AAF28D129142AB82A632B002DF62A632B372AA22BCB2AE82A34297429282A8B2AD32AE92A6A2B5F2C622D1D29C827282A192C472DB22B812C6D36CD2B2726542115231C22A921BF239C227D224C22D72274235E22E9232624FA245625D52527251726F52494299A28D928D626C52868279A2610262325D423CD2660289C278E281A262926DE28D6290D2A012A512ABA2A5529F929C32AB52AE929EF29EF28ED29AA2AA82C992BAB2C272BE5293D29DD2A242B032D292C592D8E37732C5226EB23E4238222B52117224A211D23A82263240B23CB2311257623CB25A7259C24B424722671261227262ACB2A9627C525A524252550256C22BA24AA267B29502A402AE5263A254427C727E327BA279027D026EB25D429AD2BDB296F2999276629EB29382A0B2E3D2CC52DA52A452730293D2C572C432D6A2DF02D60364D2B1F2548236D22F723F021B21FE2209922B922FB235D2251239923E02470247F249C24FD24D026E5251C288B28B728C2246426A926CA25F926D524A12564277F29FB2A21299926CE23B324582799269725C42737261327CB29F02BF42B7F2813272A27942AF22A262DE92CC42B152B92276D28082C1A2CFC2C1D2E002FA336A12ACC25B2219A217E22D721322161228D226822982268225522B02250222324DC22842447244424B826A729002BB128CF27EC2768292A29E3271B2782246227552B4C2A5E2A2426A3237A2390255526C32777289A27262A772BB72A122C792A7A29F828922A732D632DAD2C5F2BAB2C06290D2864297D2DEE2C272DB42E1836672BD4246522D3215B21A5216721E220E12266223D2330226E229C233A24E4240E2543241925C82463268D286429DE298229D12BA72C1F2A54290627B6276127012A3D2B2029A125B2231225E5259B2528299929092A0B2B822B2B2C0E2B392AD2275C296F2D342B682D862D822BB82C842868285E29F929E82BFC2D9A2D8F36112A2E25A822592281219221F82168211A211523C32175224523F3239D23A123CE2331232E24052593255628DF288D29EF2A4F2DF12BC428BD288F2721270725DF26052A942BB0282A268827B2255E29A92BBB2BE7283D29662CA02C212C9A2AD029D02B702ABF2CD92B272D6D2CA72CA229E429D92A5E2C2B2EC42DB52D1236312BAE24E3238C214322D1224521182344236E22A8227022B6237B2368225B2562219D23D224F624B0241C2424275428992769292529F1283629D127EC275B26ED26F728502A862AF2285326BC261829BE2AC32B9929192BB92CA12E1D2E0E2B8429F32AB22B772C4A2D3B2C962D922DA32A1B29F629DE2CC92DFB2D9B2E6137562B7325432267223B228121E42102237D2276230023D0228C21FB22E621E8252C24E723FC23E82342235D23D9243C290F27FD289828DD27272823280125AF25F2262A29072BAF2B532A1429C92848280929E4294E29382B742DE82C3C2D112B5529672B802B762CC52C0A2BEE2DF82B7029242A612B2E2B062E472DCF2FC336202CE1258B213421A2218621CA2002223723D62229237E231323B0211323FB22482239238023D523D323A323E725F7250E28A427A4263D270D280E25EA22DB240926C226BF27EC279F28E927DB27E3258627482749287628D12B0B2DC22ACE2A902AEE2A682BAC2B6D2A752A5F2B642CF62A5129BD2B0D2D922E792ED02FE4378A2BF9256F2388215821312283201221A32107227D22C22266220B2291237E229B23EC2327245A235924CF227923392508245425B0256424E526902478242523C32538275429C128EE288B285129C32610260127B8272827722EC72BBC2A5A295629712C7F2B2B294729D6289E2AE62B532A562AD32A9F2CBA2CE32DE02E3336EE2AC7256921D621282265223D227320C5213F2248222D22B621D5214022AF22CB218F23D322472475249C225423A0235724B924862502249A25D524DD257B262228A529912A8429F3296A29642AA426EA24D026D926782A672C772C2A2A1F29082A892C0A2B6B2910299329DC2B972CDA2AA42AF62AC52B972DF52D392E7C36652CB02355225C2280210F21A6202722CB20E4229922E92162216B22C22249227E22F0212223AB235C23EF215F236423FB2453235824EA228F25CF233E245B262429BB2B2329242939291E2A4329CF274C28ED25FD27A928262C622B7128B028212A962C812A4E2AB32A022A7B2C542CCB2B4A2A802AC82ADE2D692C1B2EA737E52AFA24D2219D209020C7205E2029219D212D2167220D1F072298213221FB2255225122D92163237221F620E322BA227B2323235E23F6242F2479232F25EF26A827AF28C827A8255127F326AA273D265D263F26492776279C2C0A2A3C2B532B9C2BAF2C112BC729732BD62B242CB32B7329D028F22C342B312BD32ACA2CE9341B2C5E25D422F620AA214822762044230C2201222322B3209D202021E220B7231E238F211F2294219921E221C4216F221322DC23AC227B24702412246F246425B926AF26B926F123AA224D26C227C2245325E8270C283829B92A8D28F9263528F12B4F2C8B2B012CD12BC82BEE2B452CE328DB265E29172B302B5B2C102DF234272A9B255621FF210322BE22AF21F9217C21F5211D23812148228E208122DC217222DC214D234E22802288213023F3224622CB232621AC2293223A22CF234124A023F32494246F24B62476259C245B24CA254B266A259D28FF2913290128D827782B9F2AE22B8A2A232ABB2B522A30291E2902282429162AC42C532C142CA136072CE524CC219F2129232422332267218A220C22AA22372343222D22DD216722B5202823C621FF2267229920C523FA200021F221E621782281226223BD21C2217F239F241B24BA23C223B0259126FE228C256C25B226A6291D2B37272927C1261F2A482AB92A0B29062B6E2BBF2940282527FB26EC285D2AD92B452CEF2D7D36D32B71253E2104215921C721CB21CD217822EA222022532142218F210421BC218321A02072219621432164200B21752086207A22BF1FF52028226A2212217D21C522942222239222322387231A242F24972496254B28CA26C0279D276B25DF2741297F2A4F2BC62750292E2B1329C3273F25A526FF277527E529CA2B3E2C8236252C292661219A203E21E32051207121C522172171225F22AB201D2056223821991FFE21CD21BD202B212E21BC21B6219C1FBA218F21E020B823B0215D21532216232F234F23A1209A22B1222F239D2245250A26D426C326FD2717252F2752289C28392A702BFF2B802C8027BC26E0260A27DC26502793285A29D328E82B7936682D9725F7229C217122E022BE227922802072214C20AF21B01F8A20C22107213E2128220D203D210520731F3A1F6C209420C120A6205F22D2213423CB221F21922353239021372046238B23BA23D6248724A2277525C9241F25EB241029C629462A9F29DC298E2BE92C3C2907282428BE29D02A9C2A072AD8291329D329F933192C81250125F321AA21C520D521B2224721B220F2216E210C20981FB11F2D21F5216622F220CC21F220822069216E224E20D3206720FE20FD21B2200422C6225E229F219422B122502313231623D32562230C2781249B22412472240B26FE261F275D280B2C3C2B932C042A07298B28012A832BD52AA42AC02CE92CCE2DB1355D2C1325E12162222521FB20AC21CD21A821EF20CF1F25215820212007203721E6200C212922102178215D208321DE20C920C71F5D20FC1FF4209C203721A722252102223422201F102212218B224C2218228923C12250236C238C2457271027122722289729C62A992912284D274029362A112CC62B132AAE2BEE2C4B2DD833032C38244D211921DA21FA202B233921DF215C22A7213021432001202C22DE21F92045221F218322B1202D216623342288202D202220E2214B2117207D21FF2177223021A8216920062245218C2218229D22BC23A622C222A42460232B275128B328D826B227CD2604293F2737284D2CA72DF12CCA2C392C122B492DDF2E3B34072BB925C02276227B22A1204623A620F0225422281F4020E821FB20C020BC210D210222A021D3214F21FA20C721B922E0208C20C1200F213C2011217920FD208A210C2214220E20F52292224921382096235E24BE228C22C8222A2305273728CB28CE2656252627B4260C26EC277C2A8C2CC02D962DAC2BDF2B8B2B232CB734942AC925C222B0205B21D61F3F20C22018207E20C0207120DD209D207F21E0219020A71F8B22512001220E2152221421411F67210E1EA71F2021F02122205321EE2161232A22921EC020AC1FAE22961FC120D222FF21DB20DA22AE24752540279426C7260227D223DA26AB269B285129F22BE7284F2A1A2C8F2BBA2C412B78341B2B37265E2203223E21FD1F0420E9214122F920EB2165224720AA20F2219221971FE9205021F2216820F41F0920F41F25219122CF2063200B227C229F212E226121CE217E21121F581F0821DC21D4204C2131220E217F225722D0215D2555276A2A16278C256F24A1240B25942708285F2504289028FE275F29B42AD02BCC328C2AE025F72164225E22D621E71F99227A22592173209F216421E1202B213922882015216B2186235B218320AC2298213722A92152217E216E20D82180212A220821DF2197215921C22004210C2277228A2131213C21CF2101224922AF2306269F29CA2789244D25AD240C25A6254026B826E62641264D261127A82773281E30582E21252321962195226D205121A020EC20C7238F21D720E51FF81E6721D1205020D3225220F6218C21DA20F120C3213421A4217021AC1E6620D6207920F8218E212B20571F4120DD1F0F2138218F2027217722C8210721EC2216229D23BF257D27EC257B24A1227F25622536267E272A26B526B125192456262E26AF26F130382CEF264621BC21A81F4D2183200E21E821CD21AA227B20F31FC3210121EF21B620E3214621EF20931FE3200C22C1201E2171225D20571F8B21581FA521511FF120DF1F681FB7208B1E4A1F6320F11F6620C4207A20F3200B22EB216022FB24C426D425E3238D2357259C26FF274E295D2777274D252A2519269A263328CE308A2B69242E22D71FD62059218620682199202921D8202721CF20CF201A22F822AE2029226C21B121A021D420CF20DF208C23F4205C20BE1F901F2720A020CD1F79207520B020EF1EEF1DDB209A1FC51E6A20A72204215922D62186227C241525BB23D8236024F02423241B260A27652ABC2A432890265D26A6240828482ADD31EE2A3725E02139234223E4223A21682349226E22632018214421842013221422132180205121F421CA1F8020D51F5A21EC1F4D21E81F6C1F4C20CF2007204122AE21841FA820781FDD1EA12058218F1F362285231121CC1F8E21A821AC22CC224124C223BC220B23C02347251D278D29392C402A282939271328A728BC29A733DC2BC4242C22A4238321D0237D22A221A9224123A42204217B212A1FC320AC20E520E5203D210F216321DE1F0622BA2028206121B71FFE2012210C210B20B61F7A210322EC1FA51FCB1F1D21691F171F3122F620F92133202422D4236C2243225724E023A6246E22DC2387243326A729582ADF291228B5250629352BB52B8734162C9F26B52315216E213B2014233022E120B9217B21EF20CF1EF7206821DF210921EE208421072208216721FC2090218B219321EF20172297211F20AA207F20DE2188221921C41FFC1F4E21C8202E206E2289221821CD20092275228822A4204D235B238B215321F4227824122372261B265D278826D425A028D829852C65359D2B1D26D623CA220422182202227C201D216822292199216721A5204320B020D11FD921CA21C0202020D21F95241322441F241F7B20E41F3F213E21762044227221F82007212B1F1D1F961F6420C61F72225E210A210522C221C220452290211E2270227622D71FDD21A3212B23A925BB24D9258B25A625A026E128F42AAE32132DBC26CD236C234A2256217722052174230D237B211522C620E421A121B2207F20082016220B2126222E21FE204620E62036210120082211219320AA2005223C21EA214221A51EAA206220FC1F21215B22CF22A920B1207620DC205F20E322A822672233220E22AA212721E7218D248C248F235C2311242725822635281832902B83252F226F23CD21192188219822A5213E208D20AA205220D321DE21B41FEC1FB51F7123C0214A20152044202D21FA1FFF1F5E212821AB1E9C1EFE1ED61FC5206521521F9D1ECC1E8F210E200D210C22BD217A20E820FB2050217B23B12226225A21C1228521302360219E223C2262224F23AC235723DE22F02500276E319B2AB1253E22F01FB2212E22F721102245226E222021622168203420AB211F2251208521BA22F3211B2182231D21AD2204220D21F520CF20E81F851F441FF81FD5217E202A208A1F171EDA1E7420EB20612257226C21E2207B215B2043227022DF217C224121C3205A2264242C2251222722A024CE22E72140243B24EC271431EF2AA324862191213F210921F621012163215C214A202B20A8207C207821A2211520C01F41221F223B224022ED202D202820932179210120B4200F1F551FF61E15208D1F851F9C1E911E2820D220591F5F207222FB21B120162220203C20BE202F22FD205A21511FE9212322AC21F3218E21C723D323292361230B25E926EC2F792C9D250A233F211623B7210A21A322B120FB211A21EE207020611F561F47209920AA21B0222F233B2120215C235A21C61F0B207F20C91F72206C1F711F1D217F20DF1F3D1FEC1D391F781F4E1F121F0D20EC212620682013203B201121F71F2421DC20202186209B21A121482317231B22D2225223F7218A2378256D253F30132C62242123202110218C2134215321102230228020961F111F19207720D11FC4203F2218215222B820EA209D21E11F87200920751F491FAB1FB920A01F22207F200F1F001F021FC61ECF1E811E7D1F36200F22B72011207321AD20C21FB4201620A121FD21D0209321782189211C22F42214228A224A2346234E24DD258830EA2BC8259D23B6211222BB20B120A0209A220C2160213821E51F3C1F2A207E21022198216020EC21C120B220A3225821C4207E214C1FBF1EC3206B1F1D1F5D1E6120DE1F971DCB1D1B1E971FEF1D6A1F002295205C21FF1F6122972129204A21F41FA620A521BD20EF2117226620B821EE220821822339228823F8248D26882FDF2933252A214022C921951F1C20E0207E211621A021F71F981F541E391E4C200120B520502130214A20AA208720C6215620411FAB1F0F201F214021EC1FC01FD7206020D21EFD1D201EAF1FE61EA91D43219C22E220D31FB5216020F41E08211B229820382175205E2122209A206A21E721B521F5218121B222FC223125182F4F2AFC234C22B41F9E2121204C210222832029210B217020741F9D1E7720DE1F3A200C20B623FB20DF20E31E3920DA20E81FDD1EC71F3B201520EE1E361E0E1F1220D01E001E5B1FD71E3F1E8E20561FD0223621B3204920A3208C2010201D20B51F9D207422D72054229B201A210B200722432364242523EA221E226F25522FCD2A53232B209721C6209620201FC722C52080219721A6226E20C61F2B22EA212020DD205B1FCE223E213B1E00218A2155211820241F431F1F204C1F251E561F1E1E1A1E961EB31D361D0D1F931EC61E6021DE1F4520BF21AD21CE1FB11E37218A209521F22097204421FF1F8F2069220120A621A3228E209221D9220426292F292B7623E222AB20CD21FB209420C3216121EE1FD420FA201822C520BD212122D31FFE20B9208522DD2138209620311F881E8120BB1F4D1F281F2F1F2F1E881D041FC7203E1E6D1EF91EA41C56206E1F1922D4201720A11F2420DA1F871F742007212C203522A620662222200B212E209A215021002311216B229F23CB24512FC629CE248C2193212F1FB121A020B61F2D210F21E9217C20322059218220D51F2F212B219C21792112209F2075202020EA1FC220671F241F5D1F961DEC1D171E8B1D6C1E491E691D3E1E6E1E5F1E771FBC21B822572133200520F6208D20E1217822E61F1C1F102028228421812103217321992105221E216221EA224C252C30012B55242F222620EC1F33209420F621FB20A41F5121B220D220C21E7C1FDA1F041F0622E921B42190207E21DA1F35222A218A206C1F5D2058207F1FB11F801F1E1F211F961EB91EE11D1F202720FE20252023221B2194200B21A11F9A2088214A212C20BD208B218022E920E52020219421DC20162179217522FD22A123712F812A5F249A213321E8208E20D92039201E22162090209E20E11F6520342156224421F220B120C520762063209F211320791FAD1F741FEF1EB91FD51F361F9B1EC91EB41C371D511CB91F3A1E6A204C20AA203422D41F8D1F5820CE2172200E227E2174201420D7206E20991F34224B229C211B210721D2201F223E22A2242330562BEA2484235220D61FAA20C220EE204721012112213D228E20AE1FC7212D22082197205321C81FE120981F2B205121A820CF20DD216A1F971F9E1FD61D841EB11D881C571EEC1D2A1FF71E891FAF1EFA1F6F20AE1F9C218F22C820A12091218522A322C21FA620F42100214820E1203020482013217220F921E5222D252E2FF42BB723CC21DD2076201721CC20D71FD220E0208A1F7A202D208B1F572044200F20F91FFA20E91F3620F21F8B1FAB20531FB71F801EF91F4B1F941E0A1F8E1D881D0C1CE81D3E1FDA1FEB1F1E1F0520DF20A61FA41F2D22282037204220701F2422DB218C218A20FE20EE208220C32111201320C321F7216C21602390236A2FD3294A24D922042170206E21421F5520CD20E220B72150203F2210211B22C6203F212D218F21D1201221B51F352133230D1F6520FB1F8220921E0A1F7D1FDC1D801DC51DE01DAA1D661F2F200F20681F8F21E01F3D20FA1FAE201E1FA71F5E223021A221C1200D20D1219021F4205421EE20BB1F2E211D1E8D200F2222245F2F882AF325C3200F220B21022155210B202422961FDF1F07210C223A2189203822AD1FA9203121122251200C2098205C224620A11F991EA01F0020581F731D6A1D6A1DA41EE71DC71D701E8C1F4B20631F5A2014215120C61FFB20BE1EC61F431FE121C81EEC1E5B1F5120191F3221BF1F6A22871FE41FD4211B2192221724032E6B2ACC258F212F21E5201A21A520F6200422F620C9201521EC21EC1EAB1FF41F33211822F91F78223820B41FF120C11FE31F841E2F1F831DE120951E8320051F5A1F9D1EC21EFE1D1C20471F012040207E1F6E1F6720A51F6A21CC1E28201B20562186204F21A72043228B1F3A214721E6201D20AF207F21BD2391235024CF2F642CF625BC2188219421A7222C209D212822FD212C22262157206F217621422106226222B420B2224720B21F922085213920C920D61E091E391FE21F7C1E3C2045207B1DB81D481F251EB2202A219B1E91217B212620F61DAA208D2047223620EB2056202F21EC1FD42189218F20282032228320F2212B20CC21D22049233D2EFF2A77242822F5201D20F32006221721A72208223721D421E5210B202922AB2044210B216321FB2040206521F9212C21F21F2121CF1FCA1E5A1FE9200620F31E9D1FAE1E4B1FC81EB01F7C204A20401F791F0320B41FCD1E861FF61F31216220EE1F7321F020B61F0C200920521FC721DF201D219A213E20EF21A32244240B30C9290623E4211A218A2097218A1F2121A9227621B9217720E220592053201721BF207B202622D821941F9C1F7A2079204E1FB320251F1521C21FD51D3A20E91E8F1E001F4B20DD1DB41F36203C1E871F801F6A206B1F5220DA206720BF1FBA1EEF1F13203C20ED1E1420631F1920A420A51F4220D721FF1F2722FA210424172ED72A1C2478207822E82167210A21DE210D2346203C203F228B20492100212D21C9211C217221F021B120CF20B3216421F11EAE208820721F951F65203020E51FF81F221F4F1E3D1FCB1FB21F4E2027206A2106212220591FE41F6F209A1FBD201620CF1F381FD31F5D20C0209E20DB224620AC201421C220AE213B220A25F52EB72907256423AF203E216C219320662072210922F820B3210A20D82054208A22A92043215A22D5206A2143207D21971F881F1521491F1920B71F3E1E561E071E041FA11D4D1E6A1E841EC51E901F871F5F20A01F4B1EA2204120741F571F14208B21F41F3E20F6206521B61F4920E61FD4209821731F0721A5218A2180224A2F092CE1250422F920E920B820F420B12055214521002018205E1FF51F55217E1EFD1FCD209C205A2102221821C520531F1E2028214D21481FAF208D1E741FEB1F831FCC1E4A1F431DA41EEE1E671E801E3D20D420E31FC91F8A1F881F361F99207F20412193202420B921F91FAC20792209206120DB20391F2F2099232224F62F8D2A0F25F42134213621E421352098220C1F66208F20A12013208B217021A41F6C1F282106204321AF1FFC1F62202C20491F02210321B41F3C2133209F20FD1F6220641FB61E8C1DFB1E9D1F5A1F891F971F20216720C81F3F1FA01F0920F31FED2039207C20411FB121041F6520AC1FC11F1B2106216C206D2220226A24CF2EA52A14238921052300214A218F2049211821D91F1722632147206721752100210322FD1F94218E221021B41F12218921C21E3020BC1F9B1FB61FD11E02208D1E8D1FD21FCA209E1EC91E951F3120F21E182005229F1F491F50219F207321EF205B1F151FDD1FE11F1F210521701FC820ED20371F1320AD1F122082213823CB2CEC2A34257421BA21D72264202D21AA207C210622A6209A20FB21C5208B1F41225D225A22B921A5222F20F71E68207021C51F321F4820E4200C1F1B203F1F071EE02094201D1F951D8720171F62209F1EB22000212A1F691FE420CD1EE721091F792126215C200A1F312002204820BD215020A61ECF1F22204C21C1210C244D2FC22C4325F72173216223D220E021792080218921FC217F207F209F1F8A206A20D3202821DC1FF42053200C20362006229521FF1F951FE31C6D1F8F1E9F20801FB31F2C1F1B208B1FA71D8521FF1F951EC91F2F20251E30201320D21F2E1F19206C20B41FA5203A1ED02099205720E41F5E2085201721E6202E21CD219723852FD42AF02450238120512040201621AB200422F72099207220BA1F7321AE21CD1E1A216F20EC20B521F720B21F9E20C21FEC1F5120361E441D70201A209E1F8F1EB91F0321991E031E301D321FC21DE41EDB1FE31F6A1D731E5E20E11F4D203B1EE320BB20FC1F9820A91F901F661F4721881F6E1FF61FF31D462133228A245F2DC32AFA24CA229D21D320B721712213220922AC2044211B225520DA1FEA20BA212721E61F1D20EB202C215420D91F2D20F220DE1F3B1E0A1FFD1D4520ED1EE21F761F4A1F2920721E9B1DF81E101F4A1E7A1FA71EA21ED41E441F5120561FA4216F20B51EE21F0F2179218F1E6A1FC61F581F1B1F4820A51FB72126234924432D912AD2250B219A20F11FD41F102204216D21F11F6421D21E931F5B1FF61F0320CD20C11FA820C4205C214E1E9F1F91226621BD20BB1F881E951FD51EAD204021971F0C1F4320231D721EEC1E881E2E1F761F3420DF20DC1ECD20B31F841FFB1E5E21E31F631EBD1E85206820E81ED11F551E9E1F442192200D211223F124072E2F2BB024F422F920A321332191206820862115202E21731F6220031F0920831FC21E0D20811F04204D1E191E0B1FA8201820081F2D1E671F4A1F821F3B20432091202B20C91EF71D861F541F581F051F991E991F271EAD1F7B20BF1F781E701FC31FEC1E551F3120A920581E491E231FDE20621E9D1F671F292006201E24382FDA2AC5239E21AF21342157203120C321B81F8A206020FF1FB31FAB1E041F70201820F41E2C21162129201C1E89205120CF1F54208E20B41F8C1FD11EB41E362037202221681E8E1EBC1DDE1F871EDB1EC81E6E1F521ECA1EAB20921E901FCF1FA81FE21FFB1FA61FDB1F46201721131E921EBF1F1520FE209B21F82263241B2D1C2B8824D42059219921F01F2221422121213022C321511FD51FD51F2C2084206D20E220A8202820CA206A1EFA206C1E1E20BF20D71D1B20AB1E3F1FD21ECF20F01F641FAC1FA41F921DEA1FE51F021FB721E920541D22206B1FBA1FB51F8521D41F8E1D91200A20211E681FD41E401F101FF41F4621331FE2211422BE24F62D102B2125E821FA20D921A221E820EC22E22096206F207220FF1ED71EB320C3211320CD20A8229D1F02211720D220A11FBD20E921B41FF01F381FDD1FDA1E4D20FA1F8B1D641F9B1EE81DD81F0F20841E1B21D81FD31F731EE920441F8322EE1FD81F8A1FCF1FB41EDF20C61DA11FCC2027219E1F29200421FC216320F622C02EE32BE724A62024229E217121E320BF225322D620E220262115207F1EB020832094215B210821FF1E182100207A20DC1F6C1F6C21AB1FC31D031F67212A1FDC1E4B1EFA1CF11E221E491D3A1FD11E5B1E81200721B01E711F861E3B1E871E041F5420121FCB1EA11D8A1FF51E971F9C201720E4206B1FE81E3A20E82217241230252C1125F522502020233E23CA214822192366225C23C521D320F21FA42106208A204F224021721FA320581FF12086201E20E321FC20CB1F78207C1EE81EE81EFE1DF41D0C1D501E251F4D1E0F1F1721FD2007207D20E11DC01CAA1E9E1EB120D51F33205D1F941EAF1F4B1F7D1FE820C91F7A223E21041F591FC5229524832E ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 4024 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2 2 0 2106 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 2 2 0 20B3 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 4023 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 01 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 01 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 01 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 01 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 01 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 03 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 4031 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 403F ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++ USBDEVFS_REAPURBNDELAY 0 3 131 0 0 1 1 0 55 ++ USBDEVFS_REAPURBNDELAY 0 3 131 -2 0 1 0 0 ++USBDEVFS_REAPURBNDELAY 0 3 1 0 0 2 2 0 000B +diff --git a/tests/elan/capture.png b/tests/elan/capture.png +new file mode 100644 +index 0000000000000000000000000000000000000000..6295abf9b8702f87a90f9fa4762c558c8eed707d +GIT binary patch +literal 47670 +zcmXtg2RzmL|G(|n$KK;`5|Yq~L*{YpErjeSB%37Jn`~LhCWKICvJ#SzBq7-(SqWMH +z*Zuw;e?9K?=yo5+XS`pp*K@s!HPBP1q2!<>ARwU8)W93T_pk8JI)VuP9r1j)1-_Bl +zYpdf4&i?yV&|aQKK)^?!iB~rEe=^-}Udwsi?{7zy8CU$ST-xnVPJ=Ezo&s+uQmY6K +zjW$;Xt|Pq0l~Nn8ZkTG<`}i#PWcS_|N;Pp9Kbw#KHWEK=R{i>bH=Z?2G(Yrt`(KWy +zE9Q5EYu4k)4<)H@zOsnK6&?oGR8|%V<&+7>)z5C4m|W4lW-`9v$B7^@tum>dINHrW +zJ9a<&>ptT);rZnD@YA(c9t4T?YkxzLj8AKSW@cuBPbPwArl%bw+4F~4smXN5p6HcF +z**%}QGlmK8vK3`H$_zft#PipgiDGmaaS^z}8MpmklMSv?53pR{JA%*h&kpljYgprZ +zoiMVwL)Ps9zF01U*d#8`Qx|O?GsmkfL$Ct9Z7%yD}V!thH|cHvw0v#P?(W=*}w( +zIiCFCm4$6APZBF7sfo!YF|ov?q>hunQ)6ReN_@6C%lh!~|Mu?mh({n(G|*`ST)ey! +zF0W34&UnwZd3hBAzi#gD1+-gK*G#OBI(>F)+CO?InC2{%+t=3@i9=-$W@wcb7Z>CC +z?aUunR<_n$h?~cLoby1C5aAH{!{wEgcc)rwrW(0vqrMAwo;omfM7^t9X=+~C#Xdd0u)p*y$guBmNEVIlx3RmbLnLXgZ65kutVI!8= +zHj~&h=pYGqovrhDaLKy1PdTb*uFF=OCy6dvMTqJBt%jhE;8zw_Ha6EqGOpKJ!&|qn +zI~c!ivmK~jJUZtwf~mHyB@gdPOH1>>zP1z-Na>&RFsn9w>=@ZIhbuIwHccCF;7>tB +z;^sWy-rc1*brjjCTWhMEzqv|j3#P>tWtGJi+Oj`(yqKvy)p)JKSRp?N&mZ5*&+*8w +zZAJraB+7EFBE3kcwFZ8Q65rNbPqdG0o>r-S9b4l(R!@%SI@38eYD(1a%}rk`Y3iE| +zlOEY{Aolir`BO$P7kQGdCZ_3?-+9I1ew87%zmJD9QYu%M4++QuIfb@*tPPSrv?>;L&+66nm>{Ldpl-R)2Hx^hHhOG +zWjVCZACA7JS!$G_)hkXdCSPN0nC^smzwnMQt88*}e>*X!Y_5sAhb^hE%XXx3W6A42 +zmP=JWy3qDSF%+1|hrO-f}?K5U*W%uyp^du;0C3oo7(a9T2v8Jhwa{c_M9=kEj +zeeJ4o5r)|GLC5^zdsr?e)!4p;$Br#EgZY!LU+P6sZ(Uw_ah=Z{vY)J3mrYC?Ub#E< +z+pjG{%duh7b`suSyY-4!iv}8MbpPmNW8&!@qLN(C#Ik)P}-kz^Etr~TT7?V{{NW}AR`@f#u9KLnAN1REu>xPbC +z+Njf?ll@sJyb0gyRpTC5%WBh7BTbWW>)K2Ww2u|s+th}iLOvCWD3ri7OGof_!=%5Q +zwJ1w;k6pXt0nx|EhrI) +z@L-FOE>8okr>7^GO`YP|HuKKDZomP~(BZ$sz&B>1Tk$Cx4h@q}o;=yAu$mZhkZiHk +zoABLf@WB4UCOVqO_u4~qQ7eWXAj(p=DeeBf#HhknJZr!qtm{Xh!mL}<`krjI&btLq +z9(Vo}AtuTJ2T3m4_133arSSR`K5gzZaxL#32DB@1(aLS%`6YOgnx^iGWLVTrpqrto +z`C8=5+J-BNK>lC7WG=ua*h6?)e?9$5ff$PxXYD1z1i3IRi02r_rT!cNvbuy +z&?A2Or(ALFX~X36BB4S9g!tk!_l3|O!Qn~a? +zaC8FNd6N1*8wIxd$etV@?#{TW3qo%a9ZZegah0MX3t#gIkjkY%X~Y0jvaYriyZQWUT9HuAI)jI=)p>ep-D`-tNms7EShZs4kvvJe5?6G4 +z)RO~(1`6+Y%)&YA^VBep@k#&Cc=yI*=J;MFRn79TpZd +zJESMb*yoASopP0eYHOOBi#W*s+UM4EquMkUk24t$>QKzno7#|?9bexQ9fXGuhu%`G +zcH&NDovrx6!S=$MkA*0UV+LbS={5ufKgR`-uC4(=QVR*h?!jGqMY#`kv5 +zy{N1VRVo;D!WWN@yEx{Ql{vT8+{sZpl*`sR4mw*~6E4$vrFX(ZO}6yN%PJF%=Aymn +zH!bmo%;v?6+d$S8T><*DRFwutbEr9%_&JVyZB`hLQZv-O#WLvc40r9{x;0&KLC)fs#H&7%5?eH{!h9O4+dlfWQ5HJRL`Q3X?cFHva7-6;p>n)RL4lOV(|0celTrxPiAIj&)iltZ_p1hyTqW5 +z4xD+)UJ?J{ecJXxRXleKu*< +z*BuibEDAgQun^Q7rSTRmx-$^TS{qA?)dtK%O;$X*>LUxNjVFmSO4+T(*#gV;ba-WK +z?d9xd+IRS|cz#qwOy9!PM&pbd9a;E*14DeTWcCMm@E!Eh3FI3-vWsR1dV2DigD|?F +zt@z8qbakC#!5L^g&C8?zC6)W=x%;zV006ZUyN7|&($WBN@`uw_swdXrIaiI>Pm0Q1 +zNPO=*v*CBNJe1qe&;X-&c2m9B5DLLTve3Y(&J2d7TT?DHhisivqb^B?*tc^Y&&FK> +zvm+iMDqf#My}i{SL0vrKMotvE=JQ@%1I;iUrz04C2d2|kvC;guQ3VMDL34%d*9)C< +z7O++0lq*o=xWW-vDPnRM(Q_Vb`z(*t9<)DQz&=tVHcNT`v2kP6$>;uk%@OCODRp)A +z^zow;D3Oi_`+(W<^73R7iE|!exilU^ThwIE4yml1bZs=MNa(vc&4UztHssg#aPQ}M +zJnJPPi)}^%B?o^dO^5c+3)woi#M!2&r=bU#Rxu+;{HG+H;7x0wKe;v4*4FkdNURD+ +z?gn+_>ywo@yt{3f?)n}=# +zbg46gN6>gTb8zV}@S}2AbofQa!TD`}Q5FEW`}_M2`(3s#%tV)W@9T~|9xSb_99&BE +zDVo}#B_rlq321++S3c=#iXdc4if?`M#=3T5&4QfH2jKm?=T#X0 +z^uQ_w+p&aq6^yOfS|=`0lM$;L!fl9T6g~N{dtLfeOdP}#K!czzs0cg*%L9OG#| +zy@%p#ukY^)<_-Y}^_NSeC$10sxYdZlg{FB#k2+zvXwyC<*gE*5)Dkn2qXz9rO9ADkWUQ9xixy++XYV|fbqvyquQW}O^y5;VUNrtP8@165K>2P>P&{>JataD$mg$kbKC-&yW6jo*p%&GRW}+X5 +zhgAxZYcoSb04@EG{%+XU0YjT~ef;S*6pK{u(b0p-Cit#_7B61&fr7{A=IRLEyLS)z +z4s<3?D^V8c2zVkrb3~nWZ7gx>Z~pw#K$Sly`DeSq3cKpZiUFRJ%D0GZtav|LxK+nN`+eCR#u#({C%@Y$*m!V0M$dePP+s(vmGo +znP6zitI$9QU@<>^JymKb(AI^81*qEyKF4&?%hdIEr(Wc}=z->m<${xLH0OlT>dw(C +z2N<)@H_q^ywEkCKfLe^1&SmQW^8j!Yi-*#Q +zVxx^#FHV`=)JHQUF0e(7uK7eDpEdkAfzi_<$S%?~<7EM!+dd-?GYNxM2|@fLQdgRTMvu@u`K1O?jIrzg(I=AHl@=x0Yi|gJ +z2Y=NmafndIBsBpqATz_m +z!&VdW3JS|N2&y8H(#Kdy2!QKHHPC*?+Hv#tMh?g{bKqf(0|8y{(E +zw&yKi%bdex()C+kqrz3<-xTT>p(xYEr_+Eq?gP$xq@O +z%|BL58#%LXvl>u`CQOt5&;6*`!X9XzgZn9vEgFdQ<8;a`BtW(+O?{N_m-&<}ag95?Qg +zf$#_pPU6aPAP)5?G(h4!N(p^{lJHZISH|lAmCf*RB$Q>0mAuO +zfsPhatX0bJYIJ>~mY%k#30}zR&@=BkRJy{GYt^QJX7R!PRK_8TCcquATx3L{rd5$P +znt<7m26uk(aXfkxc*wv{ex7Dd*%gj;YYm7{Q;ng9^ez!ScIoL%YKwiNPU+pe9Wln7 +z9c=NveA9K8<1(QA>k(n&&H173f5-eG1xSVh_lc!*>l!;Z4D`fyqhsvf*>(8p95f4&1hC +zopmqSlYfb2f+`nVUanCuN>#*8`|tmxf@H#XsLelaO#;E^@09haPxuNE4m5kj#$IZz +zISPCe)S=(1_P5cxcJ|FfPTFYTV9T_6poMmQ<-@@lyEpsrd=xYH+y%utgoY+zKArtA@7tPe(;luEh>ONW$Wl9CQar)ao~XbT=UdM&d{=78|YR>hfQXpAfpY;R|Hc8gIEHxkd4h$ +zBLL;DXwM#)Spa2(rXL%NKryw>{05n#xfw{pkGz_7jwooV +zpu;E)!zfBBCRUyJ=TtMSM9V;1UkmutcRU_E=c@)fLWWlQ2jqJ*f+r;EAdOdC08y-b +z45g>sYh(Z;Qq_=0F-VT%5r{7iHl5j^KU{`Eg!C^CR7eV(gI?_Sz_`lfz~&`j&4eBJ +zGiWnFmjJY^gPhD$!MPV|$CfUfT1of;AlMJ$m+d%ZWsbW|H-3|GfK&>ggRtCnYI%q} +zT-k!XMQ=php~eAgE9(^DIPkm@#zT+y&9KiZ`S+*kGR+Cqw+;j2dvPu#GT%U_T=P+C +zh`F~oXq<@Acg_J&Q-A^aq1PUoS-F;yBu#VwCMYF~9-!saKL?cK``;HStNIXOH%@{+ +zzW13POMIlG`Oqy!EX`+7#}tB3k5^ZPG6yM8AUCM_<^?Ra8lK63gLqEQTnL*wf{w1Ro@hEJShnLse +z>pxvR`Y&7W>oR9(W#YZfW__M+Zf+6Cty@BAntMp;PW&}-!w<_|G8%S&NC;RejI|KT +zte`4L77W(2wy;_w8PQ6>EGB&EOaGmmuK7?>?)K0r5_o^S)qpERQbvLtHJWY8jC$)J +zIcMXfaqhEGFaiaqVu4sm^WxyY!5PYgJP%R6)cG%s +zMF^>3jwC&ZGN{z%`0H&A@Ms>qhtiJNI5y+q#tncw>w8K*!n&OZffU43FUf4+qGK3M +zCl7y;ds??RFcg?q7LQu#m`S%tP)9w{bj71iEtWgy|LWRC{;D+=8KE{)?4r6#{O&)$ +zW_rzsKSkq}Md<@&lW{<2l^2-qR91fCi{7f6+5kB(sN<5{+bq6BS+c@Mc5HxDeT1=z +zV=k|d9(aEG){{u&v1VTUs=1*2W*nr1;RXI27Tm^bM!A1i5&N2%Td$6ZFk*Gg=+ +zFU!xvU|nT&`H;j+_m;>>>>Ji~N)OH8(dASMG760IC%vJOJ$617i!xe@M^tq0%F_q44x=ZCwP2Fg|bnp_Y`#&QhlqvMaydV- +zl7?i@OEtF{QN?hH=MOJv3nBb-NI+>AM9@>d8+Cd)<3`hyHM|0^+CT_AuLEYT@CB>} +zxlk2_pO8<`;ZmkvdAJWq<}=^Fr`kdh;0l$JY$}X*j!x1B7I$`bPEW1<+owF(j4ysB +zr@k24U1M4mb32kgx4)etA)uS@#^L2=G8?+f$jM#Nl*HjiC%TB??SSKE)Lk)Pg$o +zIkn&Rb_08wgwqv%7o<&=bv-BrRm=hkmJ^Tq77iwEHQayjKpS~}ukLQH0wHZN_;(B2 +zrd7ShjFf6QUkRBA13rHI2vmo=$bl8ZPqe2i$aq)-D!(|gwCe5@^jX`sLS_ +zz8l{gW|V_TS9EqwmjBosH7xfVu;de={Kv1eUZ^q^yQE-Q&RFLdE6^=6LoIw*kNQsE +zGUx9zGoz%g=B5hywWd{Xe*|yCwKk +z8>ljlM`{EM0}eaCf724WE99Sd2R)2;?@GmJ3=Fjr0g@PU!+YXvOt}70uaPdW)4pZ5GB^@&h8}J%`5E|ffeLg@q3xf# +zSs$t0dG&3fFR4xuMe+@A`+RKdngwC#tnS!iIb0`T+J*46^r +z{~nzHcq`y3iRv#6S#nwgz~O@th(=ul1?a1C`Pjgc7f9ehHtK;(Q(lUS=v@5duk@i; +z*6vRK75dV!jCpmtrw4y0YHhBCgGl?|BVYmh4q)gQ1}tRzI;CC>Yb+b}>ajX;s1xxB +zU?u*CO859LFwo-OBL|*#EG`Rw+pvu=ahGJf$8k?}IYP03NXeKyST!$Z(^4!G?@*r& +zgGx_=C4M`eEr5xdtm{dv0s4l}0laP()-p_&AhEX+8qP2bdKzEZynCD9fjk>kkaXk7 +z83mL)Z}uAsx7L9YpEtN9B6!$7SYoc&iK@Y>~X^R +z{=HKDI5D8ogwG<8TU;+`LY6?~GOEDudrIZX%gTcCr}j&)bU>U;NvluJVaR@>@L%|1N$u;1lxRJyV*cUr~H~sg2m$}A-Z{b{EXAbr^z`-gEGHbz1d`u8ArI3@8&x!;crG!|C%A+v6=sPCJyK%W +zl0p>ZA_!&pwpqCZYv7P%ajFhj2fk?s_S!YKqyL09e5*t9y3uEw0DSbWu;5bI|8w3>f?$cA!_e(B+A(N`!9Yz(6x#yMVK8i9Has0 +z+>-c6Q{m4a)5l+u?gYIE+1>TtI)oEpab#@bI4`Zp{`Wt}5+wifYZfGS*|Eei;##Gj +z0@`os$y=2JGRk9{$nd<4iwRWF@4F_L22RC?`Nq3P%gcfpS}FwtPga>WiAfw>f+CK#i`K}Pyu5B|xM;lFGt4Lg$ +zAS>bi1E#W8*6Le_GWJ^cL@5} +z(5+G<;S8UB;e>s=Jw6U{R|MBY2Su1Doj5eYL$ozsuw4$TEn<hG*y{esmRwaCv))>&+bXU+Zvr$4e<3LGw3Jj9yAVZQk%Wg*(NIM%LN|C^t=& +z?(`A@I@WBcnYdGi9OaE^0ULkR3Eelrkbq<_P!f>0{dGRhjZ$awYiR8`gCdgf#|5Rx +zk7Rxh9kY;scp;y@m^)N9>h!`9;p4qI!~o(zeUd0cELed4tlb!wScq12^^WEFgKjK1 +zxx5l;KxPqk@N#oYoFmtdYJe~T=w=#R +zl{qEJALV<*YiesDeW5k{@vAG-s^oZLwbzwTM2A}+wL_uF&EQF9pJ^M3K24xSff-47;U=SSvvlYpB +zzvKl7Epu@6vg%m~l1NcKmswbD2jQ{MYfor2^j!PTeKQfeydqA*-K8bR3S$P`v&w(R +zhu#$zJAWb7(zQy#EqT;;^L=2L!bDUO*;XtgB?%D_#Xt0rj!BKM6~|`l7@#CV$l^g^ +zHdq9kVcf;jiV%`nVRmfQrc`(J1k(z?#i$iSW@5(eLL9h#_c_7M%p82UH~wE1?ONN6 +z8-_zXO-Qj*h~T@U_7!8Iw2MscuO))jpYB$4{ey(aGiL4?X(L&c{|& +zzIV`5>Vy9`Q|p`qHsU6BHuI8=WCLNlNSd7{FX-3r>om}~V2K+#S@cO-#2BWEUqeGQ +zl(WFSM|k8zsc`IqJgHMEpwl)&5E26gGpo3cj7E6C!T+ZfE;%>pknnhzwX +ztRVk)cSc^}9f!>M+rcsl?;7aB +z;A1DKT{p!d_+E8pUhbr5C+%?qsb|ns`3U!2OxsrUlf7)vYUU4VhWl$_A(sjU6BwSh +z#l2C!g+DrZT7YJ*ADKS>5Yp7KacwXYF!|>e9AYF86|u0rD?U%z&EQO+d>I@OJ87I`tik3S^!^A%JT +zR2VdGix?v#uZyx=RZ#f8;kWs{y{);~mRh^isNz2(;%}x+5bA|^T-vy(rTCUMyLAjC +z?#hiSguc62T6lZg}H*D_CZ7N%VP^jr*IkefAP)@d%54hCWZ0c+$v0I4-7D +zN+b{+nE1$9JQ*p)dMhQAvM@-=?xXrqGffPYY3;=1*r0F$=B5Gd*=j(zmXl(#Rfp5# +zGpYOk2_VATwvB}Bx#^XRL_!SCckwSY%)>v7!H7J8l)?x)%C6reitGH81V~bReww?& +zH@jH(kK{w7A|T#Ku%&_&F1>)4Js^{%^lIUful>~QT!`ZipC9ym0xVEX1LA_g!F1uc +z8!Q+BL8`x+#S$uh-!}eEPG(Ohh1s%jy&QM33;aQ5`2t+V;gv&#motIdFoz1e*`-UD +zCNB*zE(pHtw++pw{KOa_(@6+wq +z1xt6?K}Bu1-b@NUUhr!xb#ju*eeMGJ1JmTi}z3 +z7C$2WTm(V0GAhhDj3NA=q^E~C8v;cz00}Ji)FL4bi>y)z#JxFO=KKM+{|66~iXvv* +z$h7cl;V}*B?6|~Rrid=FG=PYfVxa5_MA#Y$sQj*}srgZnuNX}GHvC&iD;uwlQL{z0 +z(~iB7bbl!_jNSWB9`Xjf28xpzH`a>`TUxaf;dRFCzK(Bc4E{h)wEt7%-M{bogy{mR +zCZ4tW6HVXu8VYH$#>*-iX{Jxrk8P&W?l(Ea)T?x#I0>K_uMP;xFc;WjtH3NdA)Fv@ +zOY+OP=p^p@RYG3Z-@xd?7)F>=nb9)>hp6{0yJGNXtIF_NgBkeV0A$gu9tlXF=$_Dd +zkT*vE4i`Y;PM8}}|Hu5Y{jvvEoGGsHxe^~lhL!2ENMB64LK@)b8AuV!QY8#9#}hW~ +zaA@u!h*Hlpfcy8k9{tMyS}akRT1926rC6P@@NiTq6D}m-(+vOXyX}Eb^kt`KQ&GR$ +zH6y0ANw812US6_A<(!Lp_Z}B5bp-U$$T_t^UyzaGO22yDQ_w@iGF!epH}tcD&fZ_a +zm%b~+(?4&%hxjGRsQaDSJ&D%v{jRZyDt8Yq6P&9GW3y2j0rK)_aiZ?blaJtkvc*+a +zf-S?%s}lwB63OflU#&0+E?S${{)NsQokR^fFcw`YL-fSi9A1yv*MZHNuu3wyd=lO& +z@IFGYvzkAnlz@MhkFg;6dV2+VK8F7nJoaWK^AEpYm-gTgwA6%<3Lf?XHI@9dNh(Eh}4N@tp58v3d_KJxxNp +zinC>v4Lra2J=c|*8JDhgP832qAuIHRT|tJPyTZoqz5?D>14-KL<&zJ1XPW>_8Jg1m% +zbQ!Gmd0@FoO)_jlSY<24$GM=I;rnOfkGZGDYSEfalxE{#TS%pb^?Cs8odL=UZtNtn_8Wu10Z5R)4NaD@(M3R!GDk6{v;tbdcPJexN!iPkC +zq@zG{lm8J)baI9GB*$K3o_9uK#0!~aA4uiimEz=Bkh9g|mCX{_Pz^P6Jl1_}>izTZa&NvxN+ +zx1=qKKpSTVG#?kl>OR#jg*Wj@ttenuRqCC$hbxlMg0+-UKaa +zGn;;GZcW+>eHXh8lFu`+m}?Z?7r5hm$Nmq&G^Ues5!*H}XVLkWZJ4}AY!BISyhDZM +z-?$F}OOpMVCM%9^ib%F4*6)cy*UT^NR;8fqD{zR!g=@LwLE1cq2xUjU*W4+1aumr| +zwpe#Qi-g9=AJ!U)UTyNt%7<9T}EA$e)2H~xyn%2v`t_v +z)A~KxJjhwU;LWbN<|Oe`_qY5WL^2`hNgc`lNDX}iw57xb=y2d?@dWEy^-2ii3~Vc# +zt!_io7h|6G3~0ot6BBLps1X7MGCas6i1>N}msc
zT%g9ne>G1J!x4EDHJmO_3~6EOTDs^S*z+j^b(_1-j*uwF +zbSO8?^Wj696O}Lk<_atgbDtuR9wPo%CwvvZzX-!WxqyBhBO0qvv3MAZ-4|KnRTNFOM3Ezi;ke8|u$?_P-~5$9@w# +zPsWoz%Nb6!6H-AaooYF+&h37dq%#}5v<_V!FQ0nH;DQGYdI&A{hZ=!mTYTS%dO0G; +z%2CheQ?V}FkO%?#Q{q)Zi|ok1#udOAW;Y?vb_%iUPBA?aCz(iHN`IrJm%8)1UL)|_5>&*yUp^jE)twyXzKH}T;`uIqval&Fyj +z3EqVB6a<>XWGobAJ=cROuQGL9R55N}tNVD?en#U(D$gHq@!dEDDxlrEc(j0okRT2J +z1@hOXRR&a$=$7MY$a{L5CNxwngHX13G{&Fu^Gd5*h4H_?Q||Nvsfx^$q(N85iHli; +zJ3Xh+E(bGRw#kD_$s%AdEq{T4x#G#1K2#?3(kMG7N>Z7^44D8Q_RCvh`NN=fgZ&z% +zLog}s6W3Q%2~pGt^4rI#UXsEPQui)fqyeKY@%_Y~cP)wY2u>HZ#;$8-hrL1(AfI~W +zz9eTngR?(EL+_VCKp0jTaABz>Gw_xN@+oa*21CR~J@q=DgZ88-hgsA;5W8iyS1SaT +zjpmbo^z^;B+uOJSsmxE$)rys=2u}(89yCmf6Xcc9^jbq)BMI+O>pw*i*2VX5M+pVd +zUNcTPtQh%0+T>Hr56_Bz3D94zp$olTr{27IBZ#t#&0lYAv8(|{!~cdTixdAqhPiU@ +z<Ajvpib|^#eRRBTLpOtrM84IU$fdr(EOAWQtjI)Z +zsENFne2Xv4(g)~Bh2)gWL +z&S1*1zW|2~Xx%C-tns7|CeT;-BW#@s8X*q?4IS31#JY|{Ud{PCuwGWqKhDZk+O047 +zG0Dmki~m|zupXe0ukMZ4davMX%P}=otuBSj5+p6}?)m4)dRaArgeqnK(@yuR(9C~0 +zLHVsuzT7M7N^b*Jrx(x;0(2Emkzt6zOquU4HK47&!MKo85|v?K*2l+F@pE_OX{G6& +z|M3B6XT`gI@2r26y7R4KD)X=?_+Sg%e>4M1!qJ}l+Gi#v&22nD;^HX2wRiM8n@Td&55uPg2)2Dnb{BY5P9CWV +z*t3|b{)x~QrzYN(>Sq^Zpp9N*dUpZdKmx-Zwdvsp(2`?z=x>Ohi{1g?T|aaPY3Yb$ +zJ;-IZj=`=;?L^uM857BBov=os5HLjs;~Mr#S93DLc*zSy)XyeeDN!JoNzVpCdV=i( +z`M3HRx6td{eRFDd`q&`qoLrTCg&MtWsmSonPJt1*&MO5k(&XLVTq^5&%8Ea~CvY6au*T(&d5uFsv*OabwFZ +z`?`Wq-W&MG$`oODO3YYz_des!A#ZQxSu#^%ry93Ojd=Dh{CC_3WH7pysfpjR318^k +z{LZPBcwGrkds+4qwLtC +zQnX3~6?kjl(QR{?_2H(IMI^u9Egw_HDO2cd5b?LqxUpN{RCVMEeW@Nq>K3}7s6Jz8 +zZuVBEl7w4o+3{0y-})64+DkdSy%39EJSV5#$`*Qa^#N?Jrq_T50jo=MIRNsUlKo`U_8F;>2S21Qa(FuMtBKeiA_LfiR^{vzX` +zDevzK-5ST-mE%e4=1&2|A`(X!nowB@V;k^T^Q04o??C~^DOF1_?M3j5NDUS-F|pOq +z@?~4woSJoz))wRubn}Fq-Iv0o3*D1<=udI41(DjGG$B!+-x1j(P_FJ5hiU`meN;;B +z8>jyEN+zIaLxz=5?(=CY&TUYo$}0AGIz1F&iFbYO=+szQiF}1eM;Zm{$21bqVpgl#MI+aWm1VUH_fMSV!~c%B1fLZ{aLsED}=qTAQkc +zvUPs%ANk0_9w?-pNf{kr>4=O9-afoL2qP3K^}>XBsu=uz&8Ofac{rhQ=vFu83g2nS +zXOB%?r(_OBF==AJw}{`#LB@(+WW;tH53NNqaI}#50gtZ5vMh}3AWN?tvMRN4G4HXGQNDO|K!gW%q9;)WyAyu*VcZrer(dl=1_J@-K)&7vI!HGf*pq87+LjIYRva +z!gKXYw(ZvU+GZ@p`pWn!d$;{{!Y>OjpSuRRRiWh3Y)X_+cjuvpYl+W?=XPI{2MJyN +ze-;3?=$yPfwLwdOB{h;1uBJ&>`^l~3=AU?eLQ4WKb_B^t+}Nki$_!Y9WTR$Mm64a9 +zag_oHeLRcjSLP@DrKGCA3?8En?`!55hphs3Ar8kE|4JrQr18&@LMch=VK`%7D^@$^ +zBqf$R2QpR@uzmNS|EmPqH}zn~UayYXzCv)OAPwDXKf2)uISe0FSUG8Lhi$SSVIjhu +zp9hy9=>+1|JIjTyF+On8hl5YOg_!=ebsSx7Wy<;z!dNdF&s^>!mm;X8lNd-J8Z>gF +zu+yKrzP-y +zefgT2IxmhCsI0W88V4xs-MX6nZ!Vhmt6t~%ZySD)cW=D=avoMA8?$`c048-#LJaV~ +zy>1+FXoh%onWY#Nib>V(CGk2RP!`VTK2{LkU*s{i`o+KZ;A&nZ5?t@84gTRd39{Fr +zPn7lQbBGA!u0g((C|R9TwZ- +ziugQ=*rr{jSXo&;!a=Y%V9mOUVrWT65}DhT8ntwEl&i7eJkC9vMDZjy*?wuaPAW+* +z3f*3ZH5HnO^;XEI{QYYhh{++Y8pl*my6$9*WNk&iSOopAvMKaJhL%JXt-opwJ%TL! +zc??HV->)0zBy49n6~^nI=Lh}Mtg(dzGNxtTa&2%~ff$+UytRhb+1P!||NfnZ&e-0q +zsqKO{7^SIgYxJ6fNa`QZb=Eq%FXW$-uN0!Z^R&MU@)?e6UM(bA$IH3y1wzjv0u^l9 +zty#bKJIt-k7_KUzgQg#<8x#i*uk3~%XP0S`cHWz7lv#%ADc}kq>#t!;(eMk!APZSL +zsH!itxls6#c(z=O`WDzUC80xp!{IOD25DkqqPXWjAvR1WlA%Z3pae23dga7(Xe#S0 +zc_SlL!&Ur3BNgg}s$0QUK#2cxAdUTN{mSb+ttg|f^LqY&oK8^p38RU>KgTC(sj0Pa +z#G<`09PCl3S7zN)%j%?Bp$R4I+a!kyJ7xx!U!u16>fe;nmhuveS4vI()W+sJ&tVu+89R3UCHu0b1YV$S-Pv5c)slK+2`<}RX~?~ +z{2KQO6$s2fJ4h-Q(teGK$#DMk_6`H=gNN-AFhWtKr7?P4HRXl1bxMRKM?LGe9MDXv +zeW-HkP&{WW>{OCjoW!5C;)DLc^Aep17{8wOQ`Fhpl8 +zT}8vzlIZ&%Wwj7s?}a?}OrCJOdhK1w`7adc-+yJ%^$(^fEEjF~J@D}%Ij`wDS9-sP +z$I0{UrJ|$xQ5oL5mzZ$Pyn7j`&PqQKs5h7cHGjR)y~k8HBg>p=$-=?^+1z&)g-@(A +zbFDK29|-=c08mC^@vz$)eg%?2Qn~G|twcA81EDoh-z+VIjfCgiuz;Z8{^Pbd+uJ0U +zoG1sXKYjJj{pC*EW=|3iY8vyY)F4 +z78}MBkYUuY&j!ld(a}+Se0)H=9#^?Mj}9dw$ECo!mRPJ_@b$zxh5IYU8!{fpuX_R& +z&S19zA~x_hWjrcb+dl%n+TrixgJ&gV5g_z-(Bi|QGZC@_;iV%PcrLA(m5p7)b{TB5 +zP8PF}LB2EzHF85cEwn3`z&tch(kT8zXSuIYVYBzTDl)ndW3CL-@UO*$n%AnA=OY0xI3!e*b9P5 +z&Wk>nmrc1sL`7Iq#ATqjD#z5SS_jI@Q +zscvkQ@@_~KYk^8TJ3AXR3A`#_#niAb#wGOVBq-G`8zL7gYi;96_UgQ3hu*1e=x8#4 +zBLqxmQ%mokV_yc{hv!jTD&q(2vXfY{-YkTc@`K~EZYl*wQ33lk;%D&p0(W4OWQM>c +z*n+5A^0*broj`z)VKhkd*JRsCSxC2!Fyl|L6G~mG<~iKas)CDvR#mNl%=`N<$3L3l +z#3}d*)T>Hz9H7L+Exz1bl7>Q6ov_=6`R(bcJbrpLaXv!(GBfh+@`cI`VcWO8Tty}( +zhbJc%2K1)C5dTOXp3O5q0)Dl?gRwuXsABc(Jojrdj1vpyrFmMfgj14ow|K`m)QSUx +ztd6M(tjb@B6fIuAjk9E|kf?n%wy_f%W7gc-IxeO6^Wfn3DLljih0uS0siB^GbGwx0 +z%)sYPicfjhxu0Pg=rikJ?9ES~`tNn@7yMA%$me{Gq2&uj*+&#fC?jNQqMv%Nyz@dD +z(2uD`3>flGz5?BNsrSH%I|mHBe}fQ8SDcH^n&Fp6GkCCZF1c54OR8#xZwb(AegH=aII>xa?!GJfX8Xk!jk0#SAkM!IWDM|r-juh*$b_(5S-4gb +zQ`nJznsOBRn53TTse}ecMTeB$HzzI$2IiMpS4d2WKP>pXC~=EEAW5LNE%_+mKSwT= +zgpzG=i0}Nb>|Plqv@H1S-8w5FEkk?dDusv^8YL|+Pb_Q0$saWfUqB|Ww0M$Px#mg8 +zI(hHS|IBS~JzS@X@hxDh@BCej+C*k+y^3$e4a!>s47#UX3l%E}a|C!Sr14%9aA +z<1tmH4d!EFClO!>Cc_XVzq40iXG1byd>>TyIHC5vl9etYC`n=YZc(Z2<0qSIIPRY7 +zgD&+D7yd?#GB@XYC+ho$R|?I-b8BCV^b|`;Q>m!a5;FJU@<;ljlCEb3&RmPH0g%B* +zqs-Y|Oi%`by&j3Xwb19IgTs`S5J9E761`^B9IHQnGPV${!?~*21WU~@6lw(TJrtE_ +zy)PO!I%sBbYg@k_^9A57*IbzUy5E_*Lmcyvnuq{21*U!z4}vQ6#s(eh>Mx^Q2JS>v +zzh5;x^NtEgK3)vh8++5zvTPnSxXhOr;XG$4<8dd7*w)kOGW8rE#rD$!s+W!Xy5tG& +zoOwNa^7<-JjK9~dqYV>Tt_1s^A=6Wex+egsfPc|C!M#_`T$V`qeb+xYi%7?+2aAYE +z1koGeQ0rbo|Go0^C2hFz;dJ3Qsek>Fu*m2bd@AbCI=vqBW(NQ|Cr|!yxZVxxLUtr{G*eWIgzx7t7DRN4EM4UC&EQy@`nhuBm +z*p@&?qXC1BdSpnc_o}ACQw|qyLu{EgqjG-GgVw|oIjkYm7xNwVpG^ +zB-0yn!M|D?pFtOKci}XEdQF4&(N1{1qeQ0SpGDZ1`$hKJ{@tPe+uZ$ +zJ_Bn|@Du#|Reo#gs|*OAf#L(49PpDvwU*{^dOH7Cz7VSEoe0H0HqDm*dBFhH5^#3> +z)n4NG+TVj~UV=a}c;o;3vv`be>lr|KK-hced)lXXW`OwTmLFP!5*(%*pe6;%6Avw@ +zgGawV8-?BJK(2D8?ix&w0r@ch_Y{;xJ9jVrhNA84?8je@Lz2`66oLH(W~6d=H4{)B +z{%%|g^tk!!MO9njcz7&Pg}Tw3wLts(%7~J{v3TV-Z@>JUTM&q{>))Wt`^1mtsK98; +z3m@lv6CqHS!s3PLprZyH>yFesgqI=<1qOAjbCYU5Pi-hEaI*v&!78`;h{|V;y*}pUiBfFENID?^WtsEKjWv;_u?x>vu5s!0?F*` +zOo28k;raW?AY#Jlj~WCfA@x-KS#%Oe!Y@oLWjs${ulkI!Z@I>XS=YjlKFl`9fbtKN +zEk!1PGOHGoW1~_G_~X+u`w@khSJ_ZWNADgiRL`V70p$+j6^6Gwtj;QgUt*A0KQK-SoD +z&87k_9LIkgpbqTTDEeBjbMwpTAHU!#p;KM`V}15vqmW3Y1e-Qc5xMFS<@|BjC5w-C +z(6+{jnWTZB+)Qt5eS6v2&7|Kg6ouRg{nqnIARD_EhCbBX}2{ErP}5hBqWYB~-|c!bbx9^Uwb`!=h2p}x +z?j>9IugNpZ3BK-jU()`SC*5(nJVAI-b*hC5+lyv4ufmtYQZMlIzxK1bBI2+-cY_n8 +zG0qlrbCw<)mo{(=IP#QcgIAV$hA;+n^x*ymkwn-;lPUuYQ$QE* +z(f|yif2uUGDAmG=&D~yc`62-jrwS+kG{+DvUFgyC(irJ_Ux16* +zVXD58-p?aHtX-C_ZyFP?5+KKM*`r5I5lUro-x8lXvDVN?CoL>}n7XXQs-eJ7eDVhS +z1h!f1BI})~i~*DPPV6v4NKbpB5oxU{FXWYU_vQr1JHBPZAbm`#EWxKdCA{_mF<(?* +z3i}W<*HeNSV}#P)>%TpZ{`ZJ@;326O24Eh#LVyeYGoVT7zyUWB{|~HM=Pr^nlsJ5BYGIE`jen0HNBW&@MUTcN1v{9Sj1a% +z4^liDa9w#xL?Q!qJ=q0e@A~-x01Vpvf2Ykcxk&uEOmPZYdSf2BWE6o*^wkRoVe1&E +z(mk5(tuBMnITO@V-DUaCr)!z}$ud-DOTLr|wCU1*CvG3&Z&80jX(=7m8y*cPy>nHQ +zHl;_tYK){nGO}G*|2~nzU3)(D-Ox~M=(@OG(@lEw1m1W~MZP|+%cRyYWsr!LiBqwG +zo-2r7OUhYg@!W38B>wl0DO4UW=qtxkzV7bB-AYTZ`cdKTuB?VontPV|B=4GD)?=q`*}*DkH`jk&OrA4-}six +z<{sR7F9X{VgPO>wM^8Oq`O7tBTxRc3X>njk@%=!-mr*_>?MuHsUtOAoEyMGi3)g5e +z=p<2i+e^21S%%JDzy8HoSG!01C^uX;h{##xw{vXvu>@~`;w4B?=U613E5@(tv +zDLVsB*#jf1A008FId%OzOm-x@y~>{174vnYkix8bEhvIr8gbGbCbW5)K65w>ke$y3 +zacD6sBccZNo*PwbJ>An60HJCAq<9_4Kf1+wxUos<3)hV>kXJ~vfiqNEU|-mP^&^RU +zo67HG#+P7ZJpKL4tK`O*^8n1r6bZ+`Q9h_JwF}{%F5WpMSL6^wM?e1Yucn^UAgj%odilQ)hYo2du1qtB|Mloa+zyJ@n +zpQmTAQ|EjOsxQk0$!=N#(uL%i*;!24q93%`9RYuSc*(*&N)@qubd>QemSp|t$jrp# +zmG*8$mzX^{6lXLpN_*hyj=2DC<}d%G8hvVSZ)r>LkwNKDaBacRdBpj`y5V5M1^tbH +zL-xSJAkB?#n+tG#U&o6rYk6eWT;+iz--Opuxn@y(^_@p{u~|kq$YE#JrT5(Y2$ezX +zG{Tapk<35x6Z&4|w8vl{W!|LGJva88)2q>{>O~1LaaZ%M56qHbpO7*A@k}iJy>IJ> +zb%GeMwI-(l0Z1Yfnl%_Q6aO^pfbTa9C%H4 +zeehm3;t&Sq6ve$!^CrpNRbgq +zLfH*)wBGcMWU25MRJ`ar5|akR&mYv7OQaf%Hc?fS?1O +z(?G-%)oXe`Vy3x_nt-=5|JX*<#(Jf{hOm9W_T@P5o1L!ZH{mH%`P@vIR|fCt%%kH3 +zOy*yVN9XQb8CzHRsEg*K)spJfmss_X!w@xw4td}`5KX7(W+KXpvC4=PC`pQa@&T=r +zA>l!8^n5I8oc|;V2Hx$*+3i8y6hGlA)3QS=h^9X=?Y<|v55y8sN_sR~!cgbCH)v-2 +z$Q9uXY12j8-c#CxU|f=+$h!X0dzP4Q~_AMS9+MRc*`Hq)^4DESY)t&y#ig-3yL6 +zW39V%b7F%K%o}raRy?%8t2p${y=+qtG(LK@f?{4?>p#>ECJ1~q{~!ypgDBaysh;QR +zqfm3j`SHhZChBK7Rtd +z7M$C*(yuHkVYc^j)9bV-kWqI*P_2M#nkMe9faeXPvRG+~PE3TD=9OEN7K9BFO-OT` +zv9@eJNrIf9aK!(A@}~*{7K?+Um6sy1BH%?Gy%Kb|F~+|>v!e}Xcuwi46VY>uy-N>$ +zrP*8?r}YJT-cWoDK?Q%2OVu{evu#By(niJ3`lPEHcu9&VG9 +zn+sG-yh^)6RV8)04(&^La)2}j)uyXrEaErsql8ct?qY>>@3~kVFm?+b^8B!|v-q=f +zd$KJ>rGYD*aNZBpD;AX!*SgMbnE?9Yn|Dhl4xXkh +z1`Guk888ly#*}7J${pT>Pf|yy^-@u`byNB6O4HP8hK79q1!})Dn +z)4z1@v${a^$M4?7sZwsc0Fi2GF*0cw+gR|`#H{Wg=Zi>$tA|p5e4-rRmdz3Q`63FT +zPoW)7F$-4Ar@DMi7wf0*B~hwSJs%^pA0ov2hX!S40|7pfl%)WM$eo%n_IAj+O|6Cq +zCUn8Dzk)=nUp3`R$QnDj2>C@D-;ashN{ljb#i7wve_s4Jf=|Ad;uE;Zwoepab!)w3 +zdUO>LR2#+Kw|QtWarh5)Xic0@C;+xBLwQhiu +z#VyV#&(sO_o}4PYNC1-E>FMd}DsQVXS0c_%CpewrAmfdaX|66`g9UtvFahR}6$&GYBR$)e*|t +znk-rkx9{qbAuvSW4h*?jmotG;OMc$*wq7v=t-0H$S9kzGxU3TJC#{Kc#FHM2qr%x# +zC_t>kG3W!N-jp!Jv#xGqvdVH)aCk_YPvi9X=7T{F@N=uq!k~?@8ql0T9C+uikS9r# +z=HZ-H`7t>ud-VBdmy0(icA3H03%=3qz$;EKStHwEa8+<0gR)!f!$Q +zFR5D3^fVI^MpKRc_yr_FVMc*7oS%#|&+cO>)(a1?YItq1dk20EsZ{n|t#kR38NGOk +zuoeSp{pWhy8iA=$pdt-R1B^2FDzDJh2a)OLW3UoIprGDS7S_w{57Zfl~OX|jjZT??} +zV_?YADW)ar(-&Cz_4|Bkbk2?h&Dzwn3#9gB|Ik?E9whu#<>kPg)x9w$Rc@wBm#MU@ +zi3tTNcvcBMCpo5TQC!v9Hf~BvD@E3DuY+aYeM+WhAd&v+3)vhu6959QEX^B +zdCE1tq2>O_F#ciJMkD9WN?U>8ayO+A>S>x|>54(K%a40%NKz +z;=ZU`CMMoXi{bY!_`6V1QQ@&Bb^!|Tr|s5{AClWo`j#V|SGFRQV7JpS{XHcl<_ic& +zIy>=oHU^}UY$FxfGeI#r>YMBf5Dv4*fedEX#A!<(l3_%G&Nl;T%BCWE61FMEF}tX< +zSy$f&dzs+cye;)eDQTL;ydaN2?Jr5Zqt>sb;qFEKtBuv6a9x67|9TOOr~c93rT?Dp +z0B+^%h+CRvbimw5fF7RyAKkg!1+uvxU@IPk2)K}`3-#-K>tpBy1vtx+*QFBY%F4k< +z?XCxWX5i8YQ3|rK$X%mClF)j?OWQb&cOTFh+MO^fVo*Ci*f4_sD8&lT9I5vQRkt+Y +zT3qJ~0&JS4=&zsOrvVU2^T(la8v3XHIc7X_y+$c@vD$sQHE#0icj%N_qA|9tq~c~8 +z+QD0wxQKWYSS+u+)%1(0dIaAHPuSMrO@pL4q#u@){8ouom5LMmNYGvg)F1;;D0dwRQiho +ztNr)fb-Glk1rk~6hrE=R2g7zqX8K2|uSeQxATaFZpVu6v$)-?QpBPp&=QOUGww=W( +z!mpy=Wa#H9Gf$_C!{PN0+#&i*el1Zl<>*>Khms +zfCYwr&(@vBX;{p`)l9VX=g-V{Z_jt#?On5}&%^rj|HAvn5j>!v!v)$NfNL+rM)HADnc#YIjY_}R3#i0_ZLBT7$|wl;;~@^pUW1t +zVYYV8zN#k)tt5nF$Z4h=DCfF2TNW+8;Jy +zt-#R?ifc%pomuG0eRdT~LR{NwRTX%&2;ll5RxUo4sk@BIgmmwBef-?rJKX?=1b>{w +znO8hy)&x|=>#m%Q`^de0Wh2gvJL;GXPJ%{v+{Z%m0UQ_?yI}qB8mM)D>RcJG~QB$7HmW|T@UU#El?kC9Bvik}k><@4V +zqQ_y+&vrShq^2`!4j7A{TbY1K+g&1_W!@?{^o>=_C@&YDT#Cvaa@6&mas4$k +zq^FRVenf+1XxQ^@4ZlAPgjbn@%!}E2zV{AF+`dY$mZh(lrBV;59O6CvvpK)i=u@`# +zl=w;Wca@BinwW)!zPfhyEke@E#*bh=T@e8K0p{{xB~(7Lr1PtHNh@&Am)c;MV`i0c +zb?j!6E65z*udsxi(mvq}DWeiBosO +zZ?N@?`v_mp@q0@{c%K|k({xoCfv4=E{bIx7Ly22Cb`4cT^pw0=jYjDFFOpU^IhTAp +zHcE|WG~1uq{>4+ge*=zmBnc3x30%lSLP7}Z`Laqz*#L7Yt)$w%NwwNRF=wpP`|W7re`KKFsug@@=u^S6`) +zO3DKC%6Kl4^8SLONTcQ$9X-L|WG;M;2WhjoKXnPEIZ28AZKKGbg>Z +zB8*3+<*ZOTWg;J)XGYcvGreYVIzRgnDqgY`i6wWKO#~%(Fg0s~Yzx2*Senx$D>70> +z8^V2mM9QE6nbLM*ub1%IJNOP%*RluAihbxkD0A?>+$hl{VkCPu?qV=9dH0nrA9v^i +zZODR~mqgMMeVRHiQ0o#>E!@}c>yzhicorI@f{7eUxkJTLVN8SOv%e$37*E;DHWFW6 +z4hl!oRA_=Xyrc~QI9S11#)WmUp{0O4$T-@IEnY=k16|bUJ7XjpH9f){EvMtf;0`d98z@k#Uqt62s)EF +z?P4x*#6wL2F4RJSdH-MR=b79|xXVk?EWc=Oc)aV2O}BT(T8o~*2;| +z;rZzvn;VIWC<#y1kAyUBTlySS5dgrcS7Mv8s$ybxu(O~5k!|fgJhSYyuK%JR-u8WD +zzh;nPCj54VM1qF%-`IzdRLHe%s%TNgZulU6iNVVJ`B@Kj0(G)Z7Z3D*W8Jz1$03|Usl+UMi1L?86prNFy0B1jm% +z`TFW#2<|EJ1S)3LxJ#w!X4T)5DjIcz1>n@cW=06#u``KQhx?jlqHq`rU>&j=$f$|bP^3xP9SIW#wQ$`;kbVqL!OkBZ;K0iYBPhhj>}mg%A)9@72Cqf#@Z +zX0$CAK`(3m?%5efX%1Swub&_A3--2HBb%$-ytAA%#99W3PM<7l?D_7Z-RT}0G8z+; +z(NC4SdDa%Bc=qADN5_jTZeCuWzI%^SN%neV{tj#2mTG7on=wzmlVfAEH`{BPQ +zoLuf*M^O%i{lyG)tu9>1A`7^|p$Ay0W<1X72Sw63cJ*e$5|a*Y%9XHFb|2x2xS)ua +z0)JL-UL9y~HPf8XC`_RKdSBGQ+EriT}mBMNR1KgCgta$E%+@!bw~|`p7v}ck)pe5m@&(h_C(mutbUb>=I!@r9zvM@R%$=ywk1ALcqKntV^ +zCUD|PJx?jdN&ARAR&F5MUXb^o%j-+N01?{)F8Gn)S5fR6YLCr4Q}jDQ{?0}5)9~h{ +z5xUi}_-JiJkSo)WAH4I2zRc{MKp*`V|4$b|PaCWoeG;ng`dllWg?tH!MS&Emu+#;;{Gvf* +z^So4hsPs|ZcZxeS(s8J;(xl~GA3(eH21OG6%^PxrnzXjSv5w;Xpn$dYC7Vax-1QfS +zidYgn;`WK#)vt^FI|&=7Mf7S=!OcQb4hnfdPF-jPZ&KBS%)Kavgd4I>j%1&1S6fTB +z2|n%5f+s^4!Q(=BK-f7A%&IbOU6ytCdP)*PIV+h7gy3AJB5-&#c?c#*ieJ+QI>nr8~bI6_Q +zTi7b7D}e`tUG&kmLjGn0!{vGRoiD-tLxO}-D!VJN0HF4m^# +zPgn+^*?j_i#af&}@45pUcC8~^koq+A#8BNd-@CIN8%&EI-2V_l!N3IiNz0?|`Is|o +z!cJv)+s-~KR$_S`4}=qbBk!fO<|z6AEQ6`LfU3Hl_D6~}76N-}fl^nvDN9K%iDjh` +zxUnL%V`jeO7I|%G!cF?qgIq*OD1SbSF>c*szxu7pp{|NhXh#unZ3`htWo!dTwmx!K +zCuA~pK~DxPY>>s#I|w+)8>UOA53KmbH%g1Ij1V&RrRkB~THEn$)y)f{>Ay!G`6u(? +z0tRrhG7h5p^x@5uOOlc~Lynz_ATc!LbJt=jeuc?f7;GKtG;Ht^Vm7!#VH +zqzpe1zHgZSVOM<3%^DeT3O!P5b29{_fw0HVr*+O)h`2ZWf)qcisN~=j+?Jp9h8&Z7 +zNAAzJh0#;eC4S*-1WZnCdppph!A>|h2Dx6Ip1_iPaP#(_sZgqK>m047rGs_Ob! +zec;*Gz;HAq@@R@=B-!~x)J2Bv*hLDAwY|HzfgWITAobwIIAkJNwFiKe)2Vw(5VBDq +zxr~PvIR2|1nVrbJ+txN2b`oO=zL_ULagOtGl^bGvqBi@6`x_H@M}A;j%H+`FrQ$uS`s6Lq>Miaq#*nT37)=Y0&mm6>a!kS>K_S +zsvu7ee{a-NST2yvXfv4%`_J5#r+;`nO;`cmcb90&_@4|HZRbR#)jGrc@vPys~ +z5AgsWWh$(`uqrToB*tN)uYa%{F@=mG^HB2a*FW*?;A`R<oJ?s>$}o7EmseHXTN(>cIPjml=WXK#jZ_qtv1bW1BdBxs}(t#gdd3cv{C3P)zJ2T +zqu-yPszQ>ykumMloM*uUV_y$102&iDJ9vH^`a(M=^&9aA+1=4b6IyB}+*J#@LOI6{ +zbx?5FlU@bBZFRxtDEo}*>UY<{wuZI&J`7!%jzc9a$tWjF +zeqLuO3Y&I&#*TLNXEw|vXVq@j@WdogjdIX%rWnD+4*WrnBqv@+bGCWV#)oXfj$zgY +z3!Z<-M1cVTMq*#ST%Ieb0=bOO!TRya4!zW~L9$K?1~tGL0`WME5Op11F*sh;pY^be +z6OcNz%sLW-Z|yD-0LmnT)zudhgd5jrF(Vqa?2dP&yz$J~PGZ75nse$a7M48M= +zd|i^BHF6(%OkW(Xtf;Dst6JE&c84-U`^?;mZ33Dee1WX7YaY!IdgkX>u_-$lj3Ric +zI1gsu{YdCBfDeV)T|@N^GRxBbwv#TA@noS1YE(IZkQfLSGf2Ur^99JCIy;4P*ynTI +zy2gbX2$bq#Yr(!tF~!kA5t#D{sUledWsu?_$f2`iX;~Wfe +zT^5y4xxoKhY5K?-uLw|#QW<8ocQs7FpRy0yOce!?dx6dpTvaX&mslws+uZD(#GDoc +z{H7FCsjfiu;UF2c)HgY=hl43)4sb&7czHmrDt1pH{D;}4k0YNpAJlSxy`n$S+1YtH +zgN7z#_mhW`pgu_mzNC>vpG(8X2RA1k&^y66v&IZtbqmt|%!FBExln2J2CwZxi4^ic +zJpjsOdkHc=(!{uvA15a#;P5&*$+COWb+EIe?<>Vc!$S?}Ca_+Gx>#>4!O1}E-_I!o +zgbi$*YTMM^gs;t(qVFVdPWtLNby0%JF~>T@)JC&iwmy-?u%5>f4#r~qcPxB +zgvLKG&cVTwZO2_aU&)a05zYFvcnpxs1=Z8PNj+@GD5{ac)Diwc8~+eyXoO8w2&y1+ +z!?q@}QX-$043fL*XjGziprZ;f22VT{^DVtGDO&?kL!3rT051vwkB0g)e3hRCR`9;K +zn=j0DIDE}fyF6e|JZxG@y%M$RQRd8gGZLj-%MyyxU8-E;D=`*=m?oJF>_aeLKKU1V +z31Lsq;Y0#KYZ32ffeDw3SS1eHOWNXFHn$k;(;!~#He^@5gCscs0!Xn!B*VcC2+C0J +zT=n3kC3CiEYHWPy=7t_}@F5_p)fXT_XkUX>8PwU1b;ppnk$w3-DoUM;#!bINP_6?e +zak;hKiyh8UTvzDHPmh-4Atw(msW|QiLOC$emIP;vsywmJEI|>_Ik*tY6>!?u^543~ +zi^{~hJ%IYe?621QU}NpBXg2R6@-hc}%0znw^VI*P8&;eqR%87>N>u{Phn3Qjy7(7U +zNpGyWU8~jd5k=y;pAs38yhKSMP!T|~!M=!@g0=zFcTnpCbDJx1(zOv3j#=njqXK=X +zK#Q!Nl4q1#3sm2SfW=}%a$2{4NCbXz4Z)oleBMDl`E+8J>lDqWQ1y#s+$GE&(t%W +z&RU{>>5J5Z)eF$~B4P*fi&*qIgzZ3t!fHLY0OWM(up@I|qwkr#Z}zbXUq)q_s{?16pR=0P&}=4P#gC49lyr +z?^o#NnAVA?c_cZ)v5@C*<@`Gmo0Bw^qkNaIxByfL>9H?uP}9Xm$$dAmA>xhqVmUcs +z&geJ_0u#j*{m^?062_mE5eJ;gh^8Bw2*+)KH3_d=z$NifbUTUfdCHXg=e{NCplD9fEh)o+3(V6KXnr&c%k; +zlapX>3+s5Kme8=JfENI8ct=OTsRce0r0u<5E#d+o7!ZU@E~*mN2i%-sNkCwn5aHdJ +zO8IBguv&;xEvgfFAX3t$3!X?y#_s@&%ss!#ddmjbULG<{W6hQyc6(pD@;qO#gqRv? +zNJ(tA4F4CljAf>2c{5_*hT`Plkl-qGv#*U2Q3%m!tDqM_r-h}cPRH$@{_o+c77a&r +zNv(vk@jic~+1dH9Xc~XTG+(U$Vx_6hSUpIwp`-EkCfTH;PtZCWQE^Z*5=WrPE| +zV~=we$mdC^K`52{epP?NE~Y0Lk0D9E6}t@w*^y6oX0e4sxYB`m_rhC9dsb#l0&{+0 +z2w;+73EVE0u2Z^E@e}a6z>Aow}PIj;o +zqx>&ro0v2hmfkZ^)r$ +zaO4pIr#Q*K769?Fw!eGAQAn&ArFza%-j7=*62hL1jPLqFVf60oFQ)6=Y{1t +zsAHtJE`a;a1`a$(5TVOUA+a3xik4tC!)3suX&pOAgO)ef6}xG=WxLkX?q50q=hmAm +z^kd?2y8&*V=wW@$46jeM7SJHS6WVPaaHFkCuF;U9g8NZ>yf)`ZlSm={E$P@#1 +zwAhf0jMLg4w!F{BfMZSvnK%%{1iy@|du{SY(8=EMABYBlu%Z*9eZ0xY0E%Chn)w<9kbSRL=~{fOLl?y82d(I9;NW;5>B65WX6NPbJAs8Q({Ej#}G9jwAhPHJcUQ +zR=(VN9fZ>pzrJwkR%AIKRi)V!j +zw%KUzs##x!Xe```2;=+9K2rNW_?G(}iwDG&s0I4Sh%a}_A)dH<&c +zK;3Bi`RmvI@tYW0WCQjCsOMtT=YX4BJm!oE1@p{rFp+3_gay56Y>e1ASG&IG7Wuvl +zB5mZCcaPqui;ZnaSp%RRB-kLRh(;wP!Z^tJ3-}hjbD>>xD*X?dMtJmZQ(Su$GAXa} +zhgudzAwQdUB4q_)Yj4+O=JYBRg;{h8G0l|cchHnU3N~#N*4oJAL13UF8&x-R7gt1T +zdrot;7gTpkfpct)4^vFv45+;AAZ(kc3J_d#ywk=njvqKcM&W{}B5Pq0CFe%j>+Srg +zc_J?-2iPRox)VX_A`B{p-lBs<#?Y@WP +ziq=SXX%?O0j}Qo@0Kfd#pn~8+flh1vxd1Qsd~vD>h}+oDL6_ft3iC&@9)K*JXja^V +z+Yu_JW9R{j&YL0X;MHdZ)m5o1ESPR8c85ucNL6f=+IFZZYY%%zVtL9rPYl`5%)bg?wg;ENtY}_4Pm@o>j*2~QqpXOj{ +zjq7p5aX+++l>ydev)5^ +zMja~ngoIVF5M!?zbCyvFsZ_O3Y?vnpX6NVahJ}XQ*B>O@8gVk>htmlXtKmI%X~-An +zI&brF)w>0ZRj(a&KWd!=H=)Tmq{R`C6iQdhn_jVJo#Tu?Pg!f94MX6rn^zzI-AiwW +zSJH`2;MQ>~>~|r4xeY+~vFe{_;TUB`7QS0{hfBxK@r|j|w^7ZCi973V0v@5L@^X*r +zrLnFDCGBm^&5&|77^I2sqXQwqy|x9LuWgtYCWTFdk?&Gc_gX>e04lt@J^3w#4`;GO +zn^DS2`bzO-S7%%y^CQ#=;i%)f%%gmDc-67xF*GwryWCGRy-G@7IuSUfVnqe|0U>}o +zCl`3emgn_ODZt>_D5O(gFLX&Za^+!@p8>?^L>*$?8*{bBoZF69!+ +zXT23-Uw)Iziv0YcbW(`JjNAMP(~2!|2GbohQkM%R7lzKKk}HCc+od6EViTe{p$(@F +zJR+==&*jo4dn*nh5ly3xbq3`MFcwI~^3;r~i(O9rg_)s=vrFxjAWADE{T +zxyq7>n#|#yo!Tpj8qUAgb2DuzNkT@QKDjm~UNvHB3pmZXDa#T66++KH{cdvT!V>=J +zZvOIh9~4j)AFRb;J@m#(EZbZ2WvJL<|9#-$6v+>ASj+CE`{0XHOl7uMHJutm?12R1 +zlLEF5OsovK8SOKsS}~SHTSB4;jq3@A%k~U=_hkwNfNdX6JO?5=vG48?+4}rlR74JG+TdiwcY9lCpLT3HJ +z1sig545ZgKTLKauOQ`Skqs_m$0QTCkL +zHdrVzF)3r&zzz+ol9W%7{HiYyqt2ZqpiL6@AnQ)brzC9xWE2M=a%Se{v`JM{$f66y +z?Fp8NR4ucz+4^ZLy%{;>|J{yU5$yY>-3K?rVv4d}nx+g$6-h-=c$!?8cmY|r+PraH +zAUCBl1!~51v@S+3n1+#@*n8DI*r+Bq@86$fLOkI|H|VeBJWSLi`c1U`f+wcnZQ)MD +z6R}6k)iADOvHxK#6gExdgl(VK5LEtYi|ZU;km1oz@Uj^P6&&hH2nyx{P4g|YaY{6u +zdfl*_fPNt4{>DXO&A1ZMb|Y3XTA4xCSMNq^txdxpF&rNS*)7=2Z%?%5OJn_$yB~bM +zmal-Xy+U5=5-)m@jf#_vZHG!3!B@Z$&(HY8CX8^MJ-&}WIcoST;ot5~5$N7z#;O+B +zNc}0&55H-(HNncQq(RgG8GYrE(OnFPx1AVz6}C(rHPj!T4jHy-HL +z7@nw^iDwUy4B*>8h$Q}#83lqAL?cE|c@H$TP{qZud_$a=H`({!Q?eH{sLr2ypscHVWi6kow${7`piKBZGGkEf^wJ&24{ETyL)@-0`*SdM%_jp}U3>_YXTOV}Ko}|_ +zB4R`o3QaUk0NPlBS^ws(TXpw1jO5T-CMH@IrFm`|_>2%`vUfcpM2YvmixCJLDbEL) +zY4!|$qLqo?@o8~?gd*|>DpD?8T(-GnC-k_k2r)8ZP=1XM=-CsShhRsM(gQCP*b>Ua +zeuYje19u4`$-8%ZkO?;INd0$@WI3MndOUo{ABv5Spy93uKgJOGFG$~%C{WUez$%b? +zj0_~Jy#whlt8rp41~*at;@qKU +zq}b_Yq1${-wf4qL81K2$eHLP%Mr2iiDu40(;$?!U@blEKet0y)yrjmA4N1a$9^#1g +z1rESLy$C|1ryT3UK5~%T@wfdecb5XsuMt1glNpRnk~^Eo1d33I9v-4ZG)t}HBtbWoISnT|A55G&X+iHi +z?gA?G?X{P) +z5x%EXL5NC(RkH9TOVrY9p1*XgK%4F~Vvu1-u7T;8pI;28IKAwoN5+XxA$hJx%j{Z{ +zO%XoE909|xMSmLu%NOGdA4WvQGl9G>NA`xt8B}2@+Nh2324KA%7fw`LUP^C2>0;}paVBnB3 +zy-~9WlB*8m6@EsPn+Tq6Z(D5Tz^a=aii1;68VY$$&@c+o7zb!3W_|-qP$1 +zTIm@88))Uxo1}PYzO+}sb^ZlAJk99y66flM0V$wk3ibl;So+jlNa+rgISGRX9vyp`rJczO~O%DPSK}m$Jld7#vT`dV`o+i9)(Fc +zuzQPDL1~d0PL^)muR%Rs0r8im$ASAxPRjx3ONKCy;%cMfiIl>BDzE8ah-$*V5S9?c +z2Pouy#esGexIrw(Ab*&-8=|)`e>yuKgbc}K3CEw!iw6O#;2?_}%qpyzzz9UL5Nelt +z0AVQcef#(S{=EMw7j-eiHV|<8@R>jy4a>U?uQcsq@ISzv()8M=Rw~K(LCH{&fa*F?n$9>uzGU`LwE~x!f$W%N +za=rJOtm6lT$oiP4Z~!ffnH||D!kb+XZ~XL_vXy>NIjZhYAs1Y|@BIe;}(B2yf4Rv|Q6m+t{ +ze1q9GERi+ySg*1rD8ASTH!Cy#^8J#h91hdu51dSn7P)h^exVDXmcx3RiNBA4Ees55 +z7ruMUys;E5o@I0ey)ElK9F(%d4HlL9CA`T%$=AP+mup?xM-wF5VksJeL_Gl&T+Gdr>6DQ#4ps%Hb3Ob+o!0*)oxz)n8%!vX +zcCfxo!&&`TW&x~}>d%@4XtMAE4g|blBmHaq#dY}l*r@25#2L`Bm$LODx($R<;gbbc +z;E+wZQke!NZjM?Jb#$sLVXZp$V_7X|u-9c<>1(sRynJg@Q~no{%jjJSOoi$B4|b5= +z9&zvf{rF2yNFq1&t0oM}AdP-w8>h^)3jXZw$TZ1Z3x`A04U@Cs^i|HkyPSbfex0^I +z-kmhp`>hd2{bFOW56ygw<~Xd3PbN4q@J8FtP7!U==cDM2g13oG@qJ2WZi6FImEgo8 +z3Cc6#>ypHKl(@#@wmBMHEfyIMzC0-4-k&{!nLrI*i*3Fh3GKq$rZ|`r!9^R_^Luk^ +zOE~vx2p`aRr7)*N4G^k2!0NT$)FUdu^B@PE$|5V%*;%1oCI=HiSG;z*EYv564`^eJ9`vDd>8*#+R;aFPCCd#T~TSN`thg@fgk)FH?)snw=E=A_D-e6v@z +z;|!)sfP+uY&+{YXIEH~wR7TW)`R)k3?UA`QMk+!0-=3K}N(a4og#yGDnqk$_QUCbI +z-?JZs9@YHCnJ}Qu*pv@E1DOgmtfnuDH)V-=y$*n|Th@^eJAsau*tZD-_WB(N434JS +zV?{zD6%;d?g#CEsVuwxCzkNSpS4`cr+^{;A(f_Zb^A3di|Ks@KaQ0bcTsRI#;>;xF +z>`i9KSIADX5|Zq_l}&a?W{Sv6c8D@cMrJ57qQvjjumAc-*ZF+j@7H)fAJ5DjR~gP3 +zsh516PN_2?fm^LsD;m++JF@^SAkMN`(3CDY6i-TfbU=UtHT<>zjAzRWpRxL>yCm^ +zFx2>0HCj;&l183M#xI-!|H?)Lk_m*~Hw5kXy}fB)^(tKWtq|=hfLM)p_*o5olNM@v +z&-j`Bn-;t9gp`v`jRaDA3DwMeM#Q9Xa*|EOq5}s1qGaXN7akc!%P#vAdWB*;j%^p3 +zC)PXus{BX3L!8)idpR(&0Ux8Yt+xnZ0MhL1dVS&tgo56%JdFvRQt&(Ab2T$@3Oaon +zE07P8?FOZ<1_Kqa{-INYMMZglO!j@q4BVT7!T-$6nM{UiAwwa5^R0I-4gH_ZW3)zd +z=g_2>w}LC29>}7eaL!;w_Q(`;$V=NOeeZtc_FT0(ol0Lr+5<#SauG|6s#2;HqcjC9e)BzesuDabdJAp4Uxq7p+v-Q(}FuZ(k +zKhCb*mQ{*3!Y1Dfv}`EZGP>Re5WeT~XpC+vQ%ZR=ky3h<>6z3& +z0%QWR%+TgZWU?rMH43N}_1G}t<8V4aXDdC46sFE(b-jg>CQji2!cLLYSaay6G|>$Rylor`a%{7uPmmT-LJsP_%J{;3~?w)TV(o_ +z3JZ&2sNF#U<9@Ka%VI!~n{|@%_xIO|PmJGw_t{PT%aRN@aACtKn$Ew*-9ags4ryPz +z`dS~Q=#=Hk81mO291dJ3>agqVoSkb?{23}8+>wbsE2M5!wg+fG$_Sf=A2qtFJ#ytOR^>Jn^xlzDa|%jS9up6&uLHl@|U<~dSomf +zN8Ue5b3jiiPK0OpySE%l9T5MOAM&}oZq{Y1-LalC^Avw1pzR?80l{3}8Uv7s6hr;# +zw5ukbfyixQ(w!W6UVXLC`^~0L_24Bvrcz +z_WnX^2jU}C@;~O*g77x4BHdzNa2%RJ(Q>aq*_xL+bf@Ebo3h%`PlaR=4@0k*WHIa< +z3R~7=lh5ej4BjPM8>#7|iArp<`A6d30>QLq!qgION=s@lDta?LkypRR-`dYEnA +zjmm?TSOc``AEh>zmnq_mOiZ$FV#L^%lBdJLrhqX>m~jI-V=pVdncc?dfOH6+SzH1b +zwgJrbe(3^$I^xy7zKn`jx1a5Gpd**Po8T4i8TMNzEfJ?de^V(^Ifhn65uD_(%gm{Q +zi&MnVfTeAASe9*w(mDFkDW*qZ+8!_`@$;k7fud|RIl0?RBn^0yQ1&JEj8<-49>jiW +zd%zIUS*Y26QDke9pxOuqpO7vD6N1tUMd6c7+#2nDa)#s)yYHa0iKO@8^x$C-Km*VfnwNvVK7 +zgYVLO!kUopz2?&lNUf7y+1l;Nq5hAS)mrMb3FM+EW`hh>Tp6Xpa3*~g-REBS%v2Dn +zvxIdEvQcZ%My+;eqHMV8B_i6ODg{KYE +z4{s)#Mx^%(cC57-mbWvLg+SP8KwzGliAkm{Oiu%v%0sa&@FAg@Ch~wkS@S*o%;q1h +zHyQ=Qf;RAjR2RG4I`7JJog5B7D6IkM-r7>Fo;@IYrT>bVhYO3Gqu;yCsOd)^pc~eA)E^dV#9$qAH*_2tXTTeP$|QXNM$Dh` +z^HWsrz5Wt=S`1Hye{>Xh0<98;o>D@~nX2yPOQ^EummDS7=dMq?$U|L7X(egr6h=oM +z$p;yc5)dRt%J}#Xol}+uZiH9DkF*(E{j?%xoTkqe!X*_Ho_O^%r>Pf$%RrW7C8P;> +z6rkRP9osr-yAfG%J1j3U-yo9Tqa}7fQ&ziV2aHKrt4m=3n$%={0q+1}Vka}+? +z#bH0qNF8qR?4!5btp*G02~3vLr6w;XphUs35A!{)#3xWk=q3AtfVTK%gfrNP`ZH>= +z%hLG!)zHv~M9?*vbQf6q)1IMiH(<;S2C^fua*QA;!YcB`6i} +zB%TR0EDgFX!`FX$kWtT3NS$=z(FW*!Cp146ckvVXAJV;7ydGz%F)dxI`vw$kg$7jy +zPyOV%Qs|5v{-K6R7t+qtZgT%1Ue{q&?3KgNt4&%zF4H>{e|rIXie0*g_OR-K*SA{x +zm}-U!bKeTn?20J8IggnWzj3V^hlf~>kK0lGK7wqtFtc-Mi20J3@bAY?5u`z;540tj +z?D$QCRnEijmT3H~k@MW=a9q;pr9;(o8hdb#4XK!tiI|C|FKU~!xasOMwS#!@9R1ii +z_PW83LCwhxUESP?Jz$0|CAY_rv3cWQvPh!fY_iPSZ`7{vw27Mf6kq*S>MInVJs(07 +zll=Bvy0+z3**CU)zEz|Y@CZiu%FL{tisDIeoln61Ja9Re&HgL2K8`;mx%KNZ=S=W1 +zo%AGflA2Gq{a-^eImp}O&ioXOD#etbV`p7?-iK>6iJHeNhwVghhkjF%7NR@{`^JO0 +zn$!g+H^OT!JP(W8v%50F{HdC+NHECE +zl;mCmVQeTUOs=#={U?m18nb4u#>ecoMlcRZ3a!M{v*&J~ +zzhVE*zsAhi*i1M7ai=F8Im12SXxG+QOpbfhH7;+yos(lImXR*=dO_t%CG#$%v#7D> +zY=3!&&rXH#WoPRus%b~1#qecpQwZkAsUjYNCeD}T-40Ax=_BD6w6d}Ss}f*CAO8kJ +z)e0#xi=6jULgIyEdOaN2bU-!n&aB8@OQoa{Q3sT3K4=rlx}Ua +zU~&UPeyTSXDJ%KhaTNlw9`cKVZ_xCqjc?q9m`WFn<4*F1SNt4m9(4xL+Mg@!ww3~z +zVvtsEPDBBUjkJBlNeWJu9%+^g3f*tsa;j-D3$)aHXU=;hI@8O{JXd^g-DfLm`XFbb +zh=NxrUM)7}O|Vq`AtoS~)B(=EThb?CXh39$AV66Zr=Oz-<5;+9YwECN +zOrJqGO1Cs(JulSnZ;T@8We|pJR0Cs8Ucz6@R~4=l$Qfc~x=p2G=B)r`3&3m2gh#1U +z!&?X66O`I4yVe9q5xy$?h(~QC@>1o6?Gt5J`RUtCN=aW(7xf&s=*vv!hLK5js~V<+ +z&*Yl2?GJMzGg4z6FTuSk!A@}WwFh4l3z?5pZ)T2Y9r2-5=sI*25;TMI9PtaM@r+lF +z=3qMkvguN1j2Eo5xc3hOpvk&$i==F+t{YTSKo`8nd-hdkaYvcEEJi0db7dilR!}~B +zD8$c0I_c@cv!Qx*bK2LQ0EO=FI7@4po0oO_O+Evbe)-1{wQcSw0y%VB2HkgLjhCOT +zsF0{G`ow?HZBUogILz?#n-lWnWKOmCRnH~>Kc_t+ln4XnQ_~Z>U2!y&KpLshd3&~6J|fNy~R^H1!rKWte7jWRwplS2 +zYIFq&bw(oyRi~{)8X=WICWdybKwILzLlcQVgcJc#xVYrKFiM(lEwd-PW_bbx%wpAq +zsfQJ%W+H+0|4GKOvXv1>1TTg(N)VD7iU|D1DG^=Sy{OVda<))~7MPsL%wGx3l4Xjn +z*}up}3xRw1=*HwZC$a-2zC?pch$ykgy^w%j@FtjMUsVAR*K{93R$!(0Ie@N<$I|R3 +z@ipk0K$;E%3m`cEj3ZUFOFGT7b}jULlLT67#FM5O!&Awak0U}{D|=k+{)*@`+Ac4r7oIq{rF2xt;}Ca(fqVcbP}H7Mn76h%KF4%Ff|pxj>6LVo)X +zpNP;8lJ%YJ>k#-v27BLj8z~O*We5_0DHaMc(*8_BUCdc&Mvded_ETb%05l)X>JBVy +zv!$K7nqJJo*QH?LdPHAL>Avy7g`a$Y#j5>05~EYx)buu)+kvg?by(bx=8%BgxCaEk +zsVCF(#d5@!k|bPoOs!gnamS8kz+^`#Td6o{Y5VM_Pp}-)F@i!J;RN_c9%{I?j(Wn- +zr((l(opG-8Dlyg~CkDPAPx^NAwcP`^4GS-T)a|C%C>0k_SDxY&Nsy(;skmt;X(v(^)#z?p&}iOdY%H-3#8iUtc^{8P1@X@B +zKn&R2B2d5s+o~&s8_pzi&_@QpUVQ-aLh#j%o=qPJ{*wA591ZY*U~Wfn>Ox4oGtU@`Ve>^N7OSvM12Ttw3Es0vjeMGum&ILwPezWTua%K_JWqSHcDkE{UNwOo(qg> +znbQ^%cj)N^#$yWSRMjA*^V@CQX4R;SZ8hFdSetVPxrp#ZWcaco`p2 +zV}pRdIpY8NZ5Y+3#!a7rVWU7oTq*ODQ4%)FzrpXdISrnf2IoIGTsoa#5Oir;I(MWl24)vKJ!QK+h)gz+}!GNekk3r@1ki*XYKKMZ(pdt9#&kZ1>jVRW$d>ys@ +zYCs0w?7om|V?SxG({s6Xk5eSwSafd2RqbnvDLhF{he9_QzyBM+;--?DssTHx{ +z#<@PY+<{yVYI2?Q+IWbq^l5$#i>Ot&nZuL{e46PNx>DQY7~|@%;Ndb*3z_?5rVNm( +z=izWrj5|DdaI&{P@leWL>d?koHHk0BpAhh*$?xBz-*UTHb>sc#lc56IHuOQnH_GE2 +zsg+`*0!D1-q_qZN)CJ%Vk&@f^5b$ptC@Zq6 +zg_kUN%Z)}u;R*BoCwBq@1~auc_rA|GgJ4ctVwiRw?Cw#wg~%6gDe~IfAUqRzz|0N~ +zIXR_&ge%}=zfPs3q=dQykIWh>1>6ic!DVIPs)YIqTxGnBAB{JE{HRC$glI$fN}%%t +zV&_l77MvB%(;a!o5B?4YA0gBs-*cgDrZD=IeNuW=lx3OIqUJ% +zYZp1LXn7vnG|xbID|C?%X<1~D#`x9wyZA&{SH)Epa$}$>6ppQdbq}P)(rJBmc${JR +zxRaEpECv+QVQ*}m8t=1E!JU){{*Ei{PFbbv{vfGS;RSLeQ*^smfqh36yojqf;8 +z^<9|4`asVDx7QrH1|nni7Hr{=Wh?0Iko%hEEl1}>eVYC<+ZTp^BHjjzxMNVM-b}!m +z95PxZ>XI=FMDc|os!JIQE*j|m#phCco|_eKC3hsnCxo +z6@XzM7iN7cx72x;uF+gVOKrGd{kKDX#~Ppm0Oke@5>OM2Isp^RW@_#!eFrd@=Q<#k +z2Ap+8qd~{L9lG0d+rC@vZ*GmcG}H|wEJIoljBV&`9lnF{&(;?FWWErt3I-L22;5nG +z3`h>(ggj*Pj30+^^`5WLPk}zVkiFwHpRR@zSYWb;m|}hRJx+uERY1{w0*nraf0Av# +zjs~U@Hq%!XirI*$f{gv^KLs^|p9=-itKj}36^gPt6?(OOPY07P-0IiyyCL@(+z_xQ +z4L`(Aa$d*?pt79+C_#yO(WqhhE`%?P$;sxv0{{Yo#dqRO=EOSa9_>oy9}mM~BU}u{ +z|D8Tr12(+#;XUo?{)qffwzZ#UXVVAl=U53xK%*XgIj~gta)}U3wfyVPz1MjFF>7fl +z&My5@vPXgk0tWnIzzG4rTMWGyv8cs#@Qf?63>`v_0)N^Emw6uYQOVRkdAQ0ir?O5m +z5Nv%v+FSs!y4ZCnIuLs#SCkoyOddIlEtCV`phHV8^3zq(bo1+NW+LcjAdP@^ +z82-okitS34QsHQ*9UtFyy_7*#potjfdk0m<7A$ivgR8>&itwX^#Ka4`Q)p$nXY2p| +z9k^5$aU65Gp=|DmHcElON|hP6mxKM_r0&{QkB#ryZ^cH0UAUX}Ok72P_tAJ+hNu5` +z^rD>vFB`5N8Kj9-;X#At_Mr#hx*)gfd-GQuSSQgUkerKS^82%YE(`Q_Q|o&m9gQl} +zngEj&cuDeSXs~Se=J&2n#XL1O +zYPW06n4;eVTxOsM1r<27+xOsp_jTQmFK)awXn%P_gEvn$yEmQIfXK|hN09&-Fv}6j +z?h=_n7ram*5nJ!v|wt=S&n*W{nshW=l=bn`S4q0vb=pv0&rA-3l>upXZCNi +zIcxMEh|HfpJzFLUtFmB{E2x`v@B)J$zOj)gHh}mIu~4XB+bnytjVg6y)L8)WgFW3V +zXRi&(Y%khrWG7z9*sZ+3xERJLzrnQ}Ml^U&n)&$Qaz8YN|Iou`g*Hbrt(zxb*YB=o +zohxmiv*&#-8rzf)u7osp%ZSHe*Z3b~gqD8VT(}+GBYpe}Gi2A{EvLJL!-j2xc(7ZaZtz^n_C{iJ5g?I +zOA91H^M&_LQW|{(eb8Ki-BcK$mV}2z?l_M84bBKGmE!Y7JCzucDl56%hye}F_P+WV +zxA`aHr3>$EJhqSj!b$W8$SEzN(5H_*@6p9EL6olhriT@5r2@qD9QDk)y)BbivGu1i +z=`(dk1gXcW61-q>Cq5CG28}#8w+}RbGekC>j>pBAGO1qD)`i`t3NnlKMMy1^2pg?L +z8PNdT(s1TOCRkI<6=;~>iyiOpzc3S_#saP`5Hdx%wyEVKK%>^`rD_10xc6TnB3v3_ +zA#6*2LolWn5UrX_K?<_K-lYhG-B!zmy|Z%DYDL@gU6Js~(+9$zP6FFC-g0|>ZQTN*-iUmN2TlZKSGrc&!yw9cilu;>YP2(^A3O%2Qz-@fi14xYU +ze;w%Vo?juXMn7_`xG`)SF|!KjH;4N97Pa>@KbF6Ji`g9B*iuwN(^62$BK{5ioumjs +zMUR85WAC0fN`fh$1`eLY>WQLAMBOpK_`s)05js+_rof^~Vhx8z6s2`yD4n<#_^;$| +zG|GX$7XDW=zcx3aA&0*hhOyE|?i|W@bwRojtV(0MYeH9IsIVZTaCr-)v-14EkPbYK +z6J~ByB{n6V;!OOOh@uMb1dYBY8jTK{c6&)S9o}ru_STwUmdVxLi(uQuB9}F~%Twq? +zJFE$rI!fbYdHKU8EaA_-5OS3YlF+2%92sxjPTFEFrq4XDB_wbwM;i>B`+TO#Su0f_ +zroxA@-0=MUkXE-Z1%@SB&K1Q->Ih^FR)!)3D^q{ar(U1A)HoF{rQ3darTMSe>=%%q +z&#{C+bJPIKYPHRk6-U~y1VM_AHv&QrR_EvEfBrN?K{*#~CVPg|fZ!ueOZKn@4sVE_ +zO6>zR_UbFhQhdL*+ui-o%4frSr?Kjq$SIhK?Jji3f=deAK0^*(K0f<^w%sj%m>pq5 +zq%XWyc+1v@t}iE((e1ttm+Plvc$&TC{(=^$e#-8JerPx6{Lcr6Klz{6Gy2pQA`5kv +zKP0ys-)A<{|I@Kx$Vlrk@~~YuY%K9rP!NcIV5nFn<^DvmN+?3MPIh`^m!PO3-uuLm +zMOChB`o(<^poJ^iP$dp{Kq7aC@M;4}ou1EG@C*Vv3+(mC9XnX}P%IHZ59sT`to>0!QagXozoawh$-~Z3nG^{m) +z{22Ko-I`zQn_*x(#wihmwO3OjY{L9xIt4BTaTMTLgKzMrs(O-8S!ih#2>J(0pNb>N +zx=E;oW@ddt%pE0TBdH&J08&Cib4TEtIuYM$>u9NBn0fYoQbFvufEp0;wnE1D>RN96 +zU4WChb&F}s+A3-!LzL_NS@T3XQNO;(MA&l$&hzaSKxYOq}>&J>x#{ +z8tIVErLvWLW5r90gMDe_MDisrv54!ux?b*w`Sabw2$PsXJdk>BG2U5mlByG-X(SCG +z-Qyu)+hC32e?0ul|B~r__$mt-f09`#Y%;c`=}-nUe1G;PxEPmjDcTioUOnO3>W+!r +zrfZPk>*}y}_xF#U^OxzjXap&~JILdQ%={V?gtvk|cLX^X +z?acz7`FbV&A=)S>-TDn#y|!7{XgvRBOgiH>@#5C!lo4SR*6cdNVPeu}mjJ3ZOt15Vcw9d;?9y#F2tJax#%FjrH-wk+{i(+8*e{BU9>c?3U?7~M?PlR8m8Kr_o +z7U8+rDmxpsA)O@o&iz>rOcz0COkP3ZwiL&ex=bQieCp8M3=LN@D3!w=XYr4Kn$5$t +z;}!YISu9dMFoZjt{uZU=xxPQ7b4qoZ22SQ5!MwVlVYdaQR>Sg~yuAJ$q^Iur%~zt| +zTapUPkIFFUr#n8uf7l)vTDYT4Ozed?-k9*7RUw)ECDaXmEMUOv%IK#0G5gYvBaJCz +z3Srt+nU`;&b@L{*V#QnF^{2%oG(vh&-`Vd~#$}dzIXZ=-PHnT4e<)a%REf_+k8C~x +zX=F>j`k$rNY^bM=ZpSrjlWhQh&9Ek^Mq@wz^ugQ~57Ed;p-*;v4Ppr8VJ?3oqCKW? +zaAgO|gvdxrG^5WN2L7Bm6I?4HUfOR=+GTFVRck)YkV6`)v%5l@FkrE;=8BJWky&nyZQiS$Ff!lV+@^ze1-*(AorQ|^X@1&z0I +z&`c3EERUWHO2DkAe#+fDO8aE`{uGp649Pq=JD_--+&6m +zS<17DV^Tu=wWmsFD@>nOtt-Wl1d#cwo!Z&m4g2j}Yc|p*`IhqA*8RtxN+us55*8F; +z-na|+;0`i&cD3^p85Jxagbs9zMiC;*YtZ_Z21Too>R=E_UlR0kNXU6vBM>-b6}(}z +z%(Kk%sa%WRF)P~X{nrZYitiSD_W1Agml*EJc1?i=SoMPw&Dmcr_uH!k>zLq8P_Tio +z3)c5FCvddLWW&XlI%bJy$r=){V#Kezqmo-!%z_K3ik%6%V46z#>YJ0Ao{;9ruKo(wT#$pn|za}de=!RgmuY}YZ-Dm08s;A6y=MYHuq+G +zlcmRrSY&;iMvWKwEBQ61uK~OZGG@$?=L*B@Rr9&6oq86&8Vld?^i+CGlN;IAo0bQw +z*EV5EK4Cp3_9u~B(OyhyTfMPi=x$pB|NI;I85+2QErfm2&su#jso7ag+_`=GHg@H` +z+K6R+WQeq@-K~K--2L1XGIItaVXiY5#XWXIUXUHp;ks7d$irg`23QHi_0+vGOHcm? +zb70KqokeCQRf82)Hjwb%QYn<9{9iQhzBRAYfO% +zdTgyF;LuYdlPJ3)@O3~;5RO{ )AB@fwj&Cp?CyU{sID(_&1pdWET@p%#ZA_md*=Ib_mbloxc +zCBgFfv#x9ui}?>G9MkM;i^$K)34GZ)W3LT^d(?%fBPxxg%Ag9HR(Ov`_{w>{Z2CkY +zVNh+2l(1q|y289O1HPUSMyn}UD*t{&VpBhbv?np5nCi-kYeL?qUD$@KUPs-Fq?NxaqanKezIB{2>7F^s;5$=WF7K9B1+S- + +literal 0 +HcmV?d00001 + +diff --git a/tests/elan/device b/tests/elan/device +new file mode 100644 +index 0000000..7374dc2 +--- /dev/null ++++ b/tests/elan/device +@@ -0,0 +1,284 @@ ++P: /devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4.4 ++N: bus/usb/001/094=1201000200000008F304260C40010102000109023E0001010080320904000005FF0000000921100100012215000705810240000107050102400001070582024000010705830240000107050302400001 ++E: DEVNAME=/dev/bus/usb/001/094 ++E: DEVTYPE=usb_device ++E: DRIVER=usb ++E: PRODUCT=4f3/c26/140 ++E: TYPE=0/0/0 ++E: BUSNUM=001 ++E: DEVNUM=094 ++E: MAJOR=189 ++E: MINOR=93 ++E: SUBSYSTEM=usb ++E: ID_VENDOR=ELAN ++E: ID_VENDOR_ENC=ELAN ++E: ID_VENDOR_ID=04f3 ++E: ID_MODEL=ELAN:Fingerprint ++E: ID_MODEL_ENC=ELAN:Fingerprint ++E: ID_MODEL_ID=0c26 ++E: ID_REVISION=0140 ++E: ID_SERIAL=ELAN_ELAN:Fingerprint ++E: ID_BUS=usb ++E: ID_USB_INTERFACES=:ff0000: ++E: ID_VENDOR_FROM_DATABASE=Elan Microelectronics Corp. ++E: ID_PATH=pci-0000:00:14.0-usb-0:4.4 ++E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_4_4 ++E: LIBFPRINT_DRIVER=ElanTech Fingerprint Sensor ++A: authorized=1 ++A: avoid_reset_quirk=0 ++A: bConfigurationValue=1 ++A: bDeviceClass=00 ++A: bDeviceProtocol=00 ++A: bDeviceSubClass=00 ++A: bMaxPacketSize0=8 ++A: bMaxPower=100mA ++A: bNumConfigurations=1 ++A: bNumInterfaces= 1 ++A: bcdDevice=0140 ++A: bmAttributes=80 ++A: busnum=1 ++A: configuration= ++H: descriptors=1201000200000008F304260C40010102000109023E0001010080320904000005FF0000000921100100012215000705810240000107050102400001070582024000010705830240000107050302400001 ++A: dev=189:93 ++A: devnum=94 ++A: devpath=4.4 ++L: driver=../../../../../../bus/usb/drivers/usb ++A: idProduct=0c26 ++A: idVendor=04f3 ++A: ltm_capable=no ++A: manufacturer=ELAN ++A: maxchild=0 ++L: port=../1-4:1.0/1-4-port4 ++A: power/active_duration=4747 ++A: power/autosuspend=2 ++A: power/autosuspend_delay_ms=2000 ++A: power/connected_duration=54012 ++A: power/control=auto ++A: power/level=auto ++A: power/persist=1 ++A: power/runtime_active_time=4721 ++A: power/runtime_status=active ++A: power/runtime_suspended_time=49114 ++A: product=ELAN:Fingerprint ++A: quirks=0x0 ++A: removable=removable ++A: rx_lanes=1 ++A: speed=12 ++A: tx_lanes=1 ++A: urbnum=13 ++A: version= 2.00 ++ ++P: /devices/pci0000:00/0000:00:14.0/usb1/1-4 ++N: bus/usb/001/083=1201100209000140EF17181084520102000109021900010100E0000904000001090000000705810301000C ++E: DEVNAME=/dev/bus/usb/001/083 ++E: DEVTYPE=usb_device ++E: DRIVER=usb ++E: PRODUCT=17ef/1018/5284 ++E: TYPE=9/0/1 ++E: BUSNUM=001 ++E: DEVNUM=083 ++E: MAJOR=189 ++E: MINOR=82 ++E: SUBSYSTEM=usb ++E: ID_VENDOR=VIA_Labs__Inc. ++E: ID_VENDOR_ENC=VIA\x20Labs\x2c\x20Inc.\x20\x20\x20\x20\x20\x20\x20\x20\x20 ++E: ID_VENDOR_ID=17ef ++E: ID_MODEL=USB2.0_Hub ++E: ID_MODEL_ENC=USB2.0\x20Hub\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20 ++E: ID_MODEL_ID=1018 ++E: ID_REVISION=5284 ++E: ID_SERIAL=VIA_Labs__Inc._USB2.0_Hub ++E: ID_BUS=usb ++E: ID_USB_INTERFACES=:090000: ++E: ID_VENDOR_FROM_DATABASE=Lenovo ++E: ID_PATH=pci-0000:00:14.0-usb-0:4 ++E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_4 ++E: ID_FOR_SEAT=usb-pci-0000_00_14_0-usb-0_4 ++E: TAGS=:seat: ++A: authorized=1 ++A: avoid_reset_quirk=0 ++A: bConfigurationValue=1 ++A: bDeviceClass=09 ++A: bDeviceProtocol=01 ++A: bDeviceSubClass=00 ++A: bMaxPacketSize0=64 ++A: bMaxPower=0mA ++A: bNumConfigurations=1 ++A: bNumInterfaces= 1 ++A: bcdDevice=5284 ++A: bmAttributes=e0 ++A: busnum=1 ++A: configuration= ++H: descriptors=1201100209000140EF17181084520102000109021900010100E0000904000001090000000705810301000C ++A: dev=189:82 ++A: devnum=83 ++A: devpath=4 ++L: driver=../../../../../bus/usb/drivers/usb ++A: idProduct=1018 ++A: idVendor=17ef ++A: ltm_capable=no ++A: manufacturer=VIA Labs, Inc. ++A: maxchild=4 ++L: port=../1-0:1.0/usb1-port4 ++A: power/active_duration=11223581 ++A: power/autosuspend=0 ++A: power/autosuspend_delay_ms=0 ++A: power/connected_duration=11223581 ++A: power/control=auto ++A: power/level=auto ++A: power/runtime_active_time=11223333 ++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: product=USB2.0 Hub ++A: quirks=0x0 ++A: removable=removable ++A: rx_lanes=1 ++A: speed=480 ++A: tx_lanes=1 ++A: urbnum=106 ++A: version= 2.10 ++ ++P: /devices/pci0000:00/0000:00:14.0/usb1 ++N: bus/usb/001/001=12010002090001406B1D020003050302010109021900010100E0000904000001090000000705810304000C ++E: DEVNAME=/dev/bus/usb/001/001 ++E: DEVTYPE=usb_device ++E: DRIVER=usb ++E: PRODUCT=1d6b/2/503 ++E: TYPE=9/0/1 ++E: BUSNUM=001 ++E: DEVNUM=001 ++E: MAJOR=189 ++E: MINOR=0 ++E: SUBSYSTEM=usb ++E: ID_VENDOR=Linux_5.3.8-300.fc31.x86_64_xhci-hcd ++E: ID_VENDOR_ENC=Linux\x205.3.8-300.fc31.x86_64\x20xhci-hcd ++E: ID_VENDOR_ID=1d6b ++E: ID_MODEL=xHCI_Host_Controller ++E: ID_MODEL_ENC=xHCI\x20Host\x20Controller ++E: ID_MODEL_ID=0002 ++E: ID_REVISION=0503 ++E: ID_SERIAL=Linux_5.3.8-300.fc31.x86_64_xhci-hcd_xHCI_Host_Controller_0000:00:14.0 ++E: ID_SERIAL_SHORT=0000:00:14.0 ++E: ID_BUS=usb ++E: ID_USB_INTERFACES=:090000: ++E: ID_VENDOR_FROM_DATABASE=Linux Foundation ++E: ID_MODEL_FROM_DATABASE=2.0 root hub ++E: ID_PATH=pci-0000:00:14.0 ++E: ID_PATH_TAG=pci-0000_00_14_0 ++E: ID_FOR_SEAT=usb-pci-0000_00_14_0 ++E: TAGS=:seat: ++A: authorized=1 ++A: authorized_default=1 ++A: avoid_reset_quirk=0 ++A: bConfigurationValue=1 ++A: bDeviceClass=09 ++A: bDeviceProtocol=01 ++A: bDeviceSubClass=00 ++A: bMaxPacketSize0=64 ++A: bMaxPower=0mA ++A: bNumConfigurations=1 ++A: bNumInterfaces= 1 ++A: bcdDevice=0503 ++A: bmAttributes=e0 ++A: busnum=1 ++A: configuration= ++H: descriptors=12010002090001406B1D020003050302010109021900010100E0000904000001090000000705810304000C ++A: dev=189:0 ++A: devnum=1 ++A: devpath=0 ++L: driver=../../../../bus/usb/drivers/usb ++A: idProduct=0002 ++A: idVendor=1d6b ++A: interface_authorized_default=1 ++A: ltm_capable=no ++A: manufacturer=Linux 5.3.8-300.fc31.x86_64 xhci-hcd ++A: maxchild=12 ++A: power/active_duration=2372569822 ++A: power/autosuspend=0 ++A: power/autosuspend_delay_ms=0 ++A: power/connected_duration=2405642105 ++A: power/control=auto ++A: power/level=auto ++A: power/runtime_active_time=2372599414 ++A: power/runtime_status=active ++A: power/runtime_suspended_time=33016992 ++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: product=xHCI Host Controller ++A: quirks=0x0 ++A: removable=unknown ++A: rx_lanes=1 ++A: serial=0000:00:14.0 ++A: speed=480 ++A: tx_lanes=1 ++A: urbnum=19225 ++A: version= 2.00 ++ ++P: /devices/pci0000:00/0000:00:14.0 ++E: DRIVER=xhci_hcd ++E: PCI_CLASS=C0330 ++E: PCI_ID=8086:9D2F ++E: PCI_SUBSYS_ID=17AA:2238 ++E: PCI_SLOT_NAME=0000:00:14.0 ++E: MODALIAS=pci:v00008086d00009D2Fsv000017AAsd00002238bc0Csc03i30 ++E: SUBSYSTEM=pci ++E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller ++E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller ++E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI ++E: ID_VENDOR_FROM_DATABASE=Intel Corporation ++E: ID_MODEL_FROM_DATABASE=Sunrise Point-LP USB 3.0 xHCI Controller ++A: ari_enabled=0 ++A: broken_parity_status=0 ++A: class=0x0c0330 ++H: config=86802F9D060490022130030C00008000040022E1000000000000000000000000000000000000000000000000AA1738220000000070000000000000000B010000 ++A: consistent_dma_mask_bits=64 ++A: d3cold_allowed=1 ++A: dbc=disabled ++A: device=0x9d2f ++A: dma_mask_bits=64 ++L: driver=../../../bus/pci/drivers/xhci_hcd ++A: driver_override=(null) ++A: enable=1 ++A: irq=125 ++A: local_cpulist=0-3 ++A: local_cpus=f ++A: modalias=pci:v00008086d00009D2Fsv000017AAsd00002238bc0Csc03i30 ++A: msi_bus=1 ++A: msi_irqs/125=msi ++A: numa_node=-1 ++A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 37 38 2112 38\nxHCI ring segments 116 120 4096 120\nbuffer-2048 3 6 2048 3\nbuffer-512 0 0 512 0\nbuffer-128 30 32 128 1\nbuffer-32 0 0 32 0 ++A: power/control=on ++A: power/runtime_active_time=2405617003 ++A: power/runtime_status=active ++A: power/runtime_suspended_time=0 ++A: power/wakeup=enabled ++A: power/wakeup_abort_count=0 ++A: power/wakeup_active=0 ++A: power/wakeup_active_count=0 ++A: power/wakeup_count=0 ++A: power/wakeup_expire_count=0 ++A: power/wakeup_last_time_ms=0 ++A: power/wakeup_max_time_ms=0 ++A: power/wakeup_total_time_ms=0 ++A: resource=0x00000000e1220000 0x00000000e122ffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000 ++A: revision=0x21 ++A: subsystem_device=0x2238 ++A: subsystem_vendor=0x17aa ++A: vendor=0x8086 ++ +diff --git a/tests/meson.build b/tests/meson.build +index 29ff6af..d46d1c8 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -29,6 +29,7 @@ if get_option('introspection') + endif + + drivers_tests = [ ++ 'elan', + 'vfs5011', + 'synaptics', + ] +-- +2.24.1 + diff --git a/SOURCES/0170-tests-Add-more-notes-about-umockdev-recording-creati.patch b/SOURCES/0170-tests-Add-more-notes-about-umockdev-recording-creati.patch new file mode 100644 index 0000000..818c1ef --- /dev/null +++ b/SOURCES/0170-tests-Add-more-notes-about-umockdev-recording-creati.patch @@ -0,0 +1,56 @@ +From 10086a20c80dc067607a5b73c10f0eae215846c7 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Tue, 7 Jan 2020 13:45:33 +0100 +Subject: [PATCH 170/181] tests: Add more notes about umockdev recording + creation + +umockdev recordings are usually not usable as is. Add some notes to the +README to summarise what kind of changes may be required. +--- + tests/README-umockdev | 31 ++++++++++++++++++++++++++++++- + 1 file changed, 30 insertions(+), 1 deletion(-) + +diff --git a/tests/README-umockdev b/tests/README-umockdev +index cabbace..eec3598 100644 +--- a/tests/README-umockdev ++++ b/tests/README-umockdev +@@ -21,4 +21,33 @@ To create a new umockdev test, you should: + 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 ++an image with the device. ++ ++ ++Note that umockdev-record groups URBs aggressively. In most cases, manual ++intervention is unfortunately required. In most cases, drivers do a chain ++of commands like e.g. A then B each with a different reply. Umockdev will ++create a file like: ++ ++A ++ reply 1 ++ reply 2 ++B ++ reply 1 ++ reply 2 ++ ++which then needs to be re-ordered to be: ++ ++A ++ reply 1 ++B ++ reply 1 ++A ++ reply 2 ++B ++ reply 2 ++ ++Other changes may be needed to get everything working. For example the elan ++driver relies on a timeout that is not reported correctly. In this case the ++driver works around it by interpreting the protocol error differently in ++the virtual environment. +\ No newline at end of file +-- +2.24.1 + diff --git a/SOURCES/0171-tests-Always-add-dummy-skipping-tests.patch b/SOURCES/0171-tests-Always-add-dummy-skipping-tests.patch new file mode 100644 index 0000000..c889d09 --- /dev/null +++ b/SOURCES/0171-tests-Always-add-dummy-skipping-tests.patch @@ -0,0 +1,90 @@ +From 3e3dcf39a5a1e1bf3419f1b31012ca16f28e361d Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Wed, 8 Jan 2020 18:40:41 +0100 +Subject: [PATCH 171/181] tests: Always add dummy skipping tests + +Just hiding tests that cannot be run does not seem like the best idea. +So add dummy tests that are skipped, to denote that we could test more +than we actually do (even if it is just for drivers that are not +enabled). +--- + tests/meson.build | 49 +++++++++++++++++++++++++++++++++++------------ + 1 file changed, 37 insertions(+), 12 deletions(-) + +diff --git a/tests/meson.build b/tests/meson.build +index d46d1c8..912b500 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -16,6 +16,12 @@ envs.set('FP_DRIVERS_WHITELIST', 'virtual_image') + + envs.set('NO_AT_BRIDGE', '1') + ++drivers_tests = [ ++ 'elan', ++ 'vfs5011', ++ 'synaptics', ++] ++ + if get_option('introspection') + envs.prepend('GI_TYPELIB_PATH', join_paths(meson.build_root(), 'libfprint')) + +@@ -26,25 +32,44 @@ if get_option('introspection') + env: envs, + depends: libfprint_typelib, + ) ++ else ++ test('virtual-image', ++ find_program('sh'), ++ args: ['-c', 'exit 77'] ++ ) + endif + +- drivers_tests = [ +- 'elan', +- 'vfs5011', +- 'synaptics', +- ] +- + foreach driver_test: drivers_tests + driver_envs = envs + driver_envs.set('FP_DRIVERS_WHITELIST', driver_test) + ++ if driver_test in drivers ++ test(driver_test, ++ find_program('umockdev-test.py'), ++ args: join_paths(meson.current_source_dir(), driver_test), ++ env: driver_envs, ++ suite: ['drivers'], ++ timeout: 10, ++ depends: libfprint_typelib, ++ ) ++ else ++ test(driver_test, ++ find_program('sh'), ++ args: ['-c', 'exit 77'] ++ ) ++ endif ++ endforeach ++else ++ warning('Skipping all driver tests as introspection bindings are missing') ++ test('virtual-image', ++ find_program('sh'), ++ args: ['-c', 'exit 77'] ++ ) ++ ++ foreach driver_test: drivers_tests + test(driver_test, +- find_program('umockdev-test.py'), +- args: join_paths(meson.current_source_dir(), driver_test), +- env: driver_envs, +- suite: ['drivers'], +- timeout: 10, +- depends: libfprint_typelib, ++ find_program('sh'), ++ args: ['-c', 'exit 77'] + ) + endforeach + endif +-- +2.24.1 + diff --git a/SOURCES/0172-device-Fix-potential-memory-leak-of-progress_cb-user.patch b/SOURCES/0172-device-Fix-potential-memory-leak-of-progress_cb-user.patch new file mode 100644 index 0000000..730bfef --- /dev/null +++ b/SOURCES/0172-device-Fix-potential-memory-leak-of-progress_cb-user.patch @@ -0,0 +1,28 @@ +From bd891b9c3ed6289d3499b084653942c595920f2c Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 23 Dec 2019 23:55:55 +0100 +Subject: [PATCH 172/181] device: Fix potential memory leak of progress_cb user + data + +The progress report user data free func was not assigned and therefore +never called. Add the missing assign, potentially fixing memory leaks +(mostly relevant for bindings). +--- + libfprint/fp-device.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c +index 116f9f8..634c2cc 100644 +--- a/libfprint/fp-device.c ++++ b/libfprint/fp-device.c +@@ -775,6 +775,7 @@ fp_device_enroll (FpDevice *device, + data->print = g_object_ref_sink (template_print); + data->enroll_progress_cb = progress_cb; + data->enroll_progress_data = progress_data; ++ data->enroll_progress_destroy = progress_destroy; + + // Attach the progress data as task data so that it is destroyed + g_task_set_task_data (priv->current_task, data, (GDestroyNotify) enroll_data_free); +-- +2.24.1 + diff --git a/SOURCES/0173-upekts-Remove-unused-argument-from-deinitsm_new.patch b/SOURCES/0173-upekts-Remove-unused-argument-from-deinitsm_new.patch new file mode 100644 index 0000000..61be0dd --- /dev/null +++ b/SOURCES/0173-upekts-Remove-unused-argument-from-deinitsm_new.patch @@ -0,0 +1,43 @@ +From 85d64aada6e339ca667fb6375b2137f091c26416 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Tue, 24 Dec 2019 00:03:14 +0100 +Subject: [PATCH 173/181] upekts: Remove unused argument from deinitsm_new + +--- + libfprint/drivers/upekts.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libfprint/drivers/upekts.c b/libfprint/drivers/upekts.c +index 16534d3..965b3b2 100644 +--- a/libfprint/drivers/upekts.c ++++ b/libfprint/drivers/upekts.c +@@ -832,7 +832,7 @@ initsm_done (FpiSsm *ssm, FpDevice *dev, GError *error) + } + + static FpiSsm * +-deinitsm_new (FpDevice *dev, void *user_data) ++deinitsm_new (FpDevice *dev) + { + return fpi_ssm_new (dev, deinitsm_state_handler, DEINITSM_NUM_STATES); + } +@@ -988,7 +988,7 @@ static void + do_enroll_stop (FpDevice *dev, FpPrint *print, GError *error) + { + EnrollStopData *data = g_new0 (EnrollStopData, 1); +- FpiSsm *ssm = deinitsm_new (dev, data); ++ FpiSsm *ssm = deinitsm_new (dev); + + data->print = g_object_ref (print); + data->error = error; +@@ -1251,7 +1251,7 @@ static void + do_verify_stop (FpDevice *dev, FpiMatchResult res, GError *error) + { + VerifyStopData *data = g_new0 (VerifyStopData, 1); +- FpiSsm *ssm = deinitsm_new (dev, data); ++ FpiSsm *ssm = deinitsm_new (dev); + + data->res = res; + data->error = error; +-- +2.24.1 + diff --git a/SOURCES/0174-device-Better-define-ownership-passing-for-results.patch b/SOURCES/0174-device-Better-define-ownership-passing-for-results.patch new file mode 100644 index 0000000..425ddb4 --- /dev/null +++ b/SOURCES/0174-device-Better-define-ownership-passing-for-results.patch @@ -0,0 +1,195 @@ +From e45ebf1af2a29f861a9aec367981492688692a72 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 13 Jan 2020 13:25:48 +0100 +Subject: [PATCH 174/181] device: Better define ownership passing for results + +Some things were odd with regard to the ownership of passed objects. Try +to make things sane overall, in particular with the possible floating +FpPrint reference. +--- + libfprint/fpi-device.c | 20 ++++++++++++++++---- + libfprint/fpi-image-device.c | 2 +- + tests/test-fpi-device.c | 24 ++++++++++++------------ + 3 files changed, 29 insertions(+), 17 deletions(-) + +diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c +index 51dbee1..8b2ef9d 100644 +--- a/libfprint/fpi-device.c ++++ b/libfprint/fpi-device.c +@@ -908,7 +908,7 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error) + * fpi_device_verify_complete: + * @device: The #FpDevice + * @result: The #FpiMatchResult of the operation +- * @print: The scanned #FpPrint ++ * @print: (transfer floating) The scanned #FpPrint + * @error: A #GError if result is %FPI_MATCH_ERROR + * + * Finish an ongoing verify operation. The returned print should be +@@ -929,6 +929,9 @@ fpi_device_verify_complete (FpDevice *device, + + clear_device_cancel_action (device); + ++ if (print) ++ g_object_ref_sink (print); ++ + g_object_set_data_full (G_OBJECT (priv->current_task), + "print", + print, +@@ -963,8 +966,8 @@ fpi_device_verify_complete (FpDevice *device, + /** + * 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 ++ * @match: (transfer none): The matching #FpPrint from the passed gallery, or %NULL if none matched ++ * @print: (transfer floating): The scanned #FpPrint, may be %NULL + * @error: The #GError or %NULL on success + * + * Finish an ongoing identify operation. The match that was identified is +@@ -986,6 +989,12 @@ fpi_device_identify_complete (FpDevice *device, + + clear_device_cancel_action (device); + ++ if (match) ++ g_object_ref (match); ++ ++ if (print) ++ g_object_ref_sink (print); ++ + g_object_set_data_full (G_OBJECT (priv->current_task), + "print", + print, +@@ -1134,7 +1143,7 @@ fpi_device_list_complete (FpDevice *device, + * fpi_device_enroll_progress: + * @device: The #FpDevice + * @completed_stages: The number of stages that are completed at this point +- * @print: (transfer full): The #FpPrint for the newly completed stage or %NULL on failure ++ * @print: (transfer floating): The #FpPrint for the newly completed stage or %NULL on failure + * @error: (transfer full): The #GError or %NULL on success + * + * Notify about the progress of the enroll operation. This is important for UI interaction. +@@ -1155,6 +1164,9 @@ fpi_device_enroll_progress (FpDevice *device, + + g_debug ("Device reported enroll progress, reported %i of %i have been completed", completed_stages, priv->nr_enroll_stages); + ++ if (print) ++ g_object_ref_sink (print); ++ + if (error && print) + { + g_warning ("Driver passed an error and also provided a print, returning error!"); +diff --git a/libfprint/fpi-image-device.c b/libfprint/fpi-image-device.c +index efdbb53..f962b8a 100644 +--- a/libfprint/fpi-image-device.c ++++ b/libfprint/fpi-image-device.c +@@ -226,7 +226,7 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g + + if (fpi_print_bz3_match (template, print, priv->bz3_threshold, &error) == FPI_MATCH_SUCCESS) + { +- result = g_object_ref (template); ++ result = template; + break; + } + } +diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c +index 3fa800c..3d1e81c 100644 +--- a/tests/test-fpi-device.c ++++ b/tests/test-fpi-device.c +@@ -548,10 +548,10 @@ test_driver_verify (void) + { + g_autoptr(GError) error = NULL; + g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); +- g_autoptr(FpPrint) enrolled_print = fp_print_new (device); ++ g_autoptr(FpPrint) enrolled_print = g_object_ref_sink (fp_print_new (device)); ++ g_autoptr(FpPrint) out_print = NULL; + FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); +- FpPrint *out_print = NULL; + gboolean match; + + fake_dev->ret_result = FPI_MATCH_SUCCESS; +@@ -570,10 +570,10 @@ test_driver_verify_fail (void) + { + g_autoptr(GError) error = NULL; + g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); +- g_autoptr(FpPrint) enrolled_print = fp_print_new (device); ++ g_autoptr(FpPrint) enrolled_print = g_object_ref_sink (fp_print_new (device)); ++ g_autoptr(FpPrint) out_print = NULL; + FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); +- FpPrint *out_print = NULL; + gboolean match; + + fake_dev->ret_result = FPI_MATCH_FAIL; +@@ -591,10 +591,10 @@ test_driver_verify_error (void) + { + g_autoptr(GError) error = NULL; + g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); +- g_autoptr(FpPrint) enrolled_print = fp_print_new (device); ++ g_autoptr(FpPrint) enrolled_print = g_object_ref_sink (fp_print_new (device)); ++ g_autoptr(FpPrint) out_print = NULL; + FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); +- FpPrint *out_print = NULL; + gboolean match; + + fake_dev->ret_result = FPI_MATCH_ERROR; +@@ -641,16 +641,16 @@ test_driver_identify (void) + { + g_autoptr(GError) error = NULL; + g_autoptr(FpPrint) print = NULL; ++ g_autoptr(FpPrint) matched_print = NULL; + g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); + g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); + FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); +- FpPrint *matched_print; + FpPrint *expected_matched; + unsigned int i; + + for (i = 0; i < 500; ++i) +- g_ptr_array_add (prints, fp_print_new (device)); ++ g_ptr_array_add (prints, g_object_ref_sink (fp_print_new (device))); + + expected_matched = g_ptr_array_index (prints, g_random_int_range (0, 499)); + fp_print_set_description (expected_matched, "fake-verified"); +@@ -673,15 +673,15 @@ test_driver_identify_fail (void) + { + g_autoptr(GError) error = NULL; + g_autoptr(FpPrint) print = NULL; ++ g_autoptr(FpPrint) matched_print = NULL; + g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); + g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); + FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); +- FpPrint *matched_print; + unsigned int i; + + for (i = 0; i < 500; ++i) +- g_ptr_array_add (prints, fp_print_new (device)); ++ g_ptr_array_add (prints, g_object_ref_sink (fp_print_new (device))); + + g_assert_true (fp_device_supports_identify (device)); + +@@ -700,16 +700,16 @@ test_driver_identify_error (void) + { + g_autoptr(GError) error = NULL; + g_autoptr(FpPrint) print = NULL; ++ g_autoptr(FpPrint) matched_print = NULL; + g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); + g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); + FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); +- FpPrint *matched_print; + FpPrint *expected_matched; + unsigned int i; + + for (i = 0; i < 500; ++i) +- g_ptr_array_add (prints, fp_print_new (device)); ++ g_ptr_array_add (prints, g_object_ref_sink (fp_print_new (device))); + + expected_matched = g_ptr_array_index (prints, g_random_int_range (0, 499)); + fp_print_set_description (expected_matched, "fake-verified"); +-- +2.24.1 + diff --git a/SOURCES/0175-image-device-Set-cancelling-when-errors-are-reported.patch b/SOURCES/0175-image-device-Set-cancelling-when-errors-are-reported.patch new file mode 100644 index 0000000..f84c668 --- /dev/null +++ b/SOURCES/0175-image-device-Set-cancelling-when-errors-are-reported.patch @@ -0,0 +1,38 @@ +From 9dcb941fc0d9d4f81aa588a46e1256fb1b4e9a44 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 13 Jan 2020 17:56:53 +0100 +Subject: [PATCH 175/181] image-device: Set cancelling when errors are reported + +Allow the AWAIT_FINGER_ON to deactivation state transition after errors +are reported. +--- + libfprint/fpi-image-device.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/libfprint/fpi-image-device.c b/libfprint/fpi-image-device.c +index f962b8a..888c931 100644 +--- a/libfprint/fpi-image-device.c ++++ b/libfprint/fpi-image-device.c +@@ -415,7 +415,9 @@ fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry) + /* 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)"); ++ priv->cancelling = TRUE; + fpi_image_device_deactivate (self); ++ priv->cancelling = FALSE; + fpi_device_action_error (FP_DEVICE (self), error); + } + } +@@ -463,7 +465,9 @@ fpi_image_device_session_error (FpImageDevice *self, GError *error) + if (error->domain == FP_DEVICE_RETRY) + g_warning ("Driver should report retries using fpi_image_device_retry_scan!"); + ++ priv->cancelling = TRUE; + fpi_image_device_deactivate (self); ++ priv->cancelling = FALSE; + fpi_device_action_error (FP_DEVICE (self), error); + } + +-- +2.24.1 + diff --git a/SOURCES/0176-tests-Add-error-reporting-tests-based-on-virtual-dri.patch b/SOURCES/0176-tests-Add-error-reporting-tests-based-on-virtual-dri.patch new file mode 100644 index 0000000..f98f968 --- /dev/null +++ b/SOURCES/0176-tests-Add-error-reporting-tests-based-on-virtual-dri.patch @@ -0,0 +1,122 @@ +From 2ce87cc7a8c662b12900acb9697d74bee0f143f4 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 13 Jan 2020 17:57:31 +0100 +Subject: [PATCH 176/181] tests: Add error reporting tests based on virtual + driver + +We were not testing the image device error reporting functions yet +inside libfprint (fprintd already had such tests). Add tests to make +sure we catch errors earlier. +--- + tests/virtual-image.py | 61 ++++++++++++++++++++++++++++++++++-------- + 1 file changed, 50 insertions(+), 11 deletions(-) + +diff --git a/tests/virtual-image.py b/tests/virtual-image.py +index 11ec8ae..a6bf6d2 100755 +--- a/tests/virtual-image.py ++++ b/tests/virtual-image.py +@@ -99,13 +99,13 @@ class VirtualImage(unittest.TestCase): + + def send_retry(self, retry_error=1, iterate=True): + # The default (1) is too-short +- self.sendall(struct.pack('ii', -1, retry_error)) ++ self.con.sendall(struct.pack('ii', -1, retry_error)) + while iterate and ctx.pending(): + ctx.iteration(False) + + def send_error(self, device_error=0, iterate=True): + # The default (0) is a generic error +- self.sendall(struct.pack('ii', -1, retry_error)) ++ self.con.sendall(struct.pack('ii', -2, device_error)) + while iterate and ctx.pending(): + ctx.iteration(False) + +@@ -212,9 +212,10 @@ class VirtualImage(unittest.TestCase): + done = False + + def verify_cb(dev, res): +- match, fp = dev.verify_finish(res) +- self._verify_match = match +- self._verify_fp = fp ++ try: ++ self._verify_match, self._verify_fp = dev.verify_finish(res) ++ except gi.repository.GLib.Error as e: ++ self._verify_error = e + + fp_whorl = self.enroll_print('whorl') + +@@ -234,20 +235,39 @@ class VirtualImage(unittest.TestCase): + ctx.iteration(True) + assert(not self._verify_match) + ++ # Test verify error cases ++ self._verify_fp = None ++ self._verify_error = None ++ self.dev.verify(fp_whorl, callback=verify_cb) ++ self.send_retry() ++ while self._verify_fp is None and self._verify_error is None: ++ ctx.iteration(True) ++ assert(self._verify_error is not None) ++ assert(self._verify_error.matches(FPrint.device_retry_quark(), FPrint.DeviceRetry.TOO_SHORT)) ++ ++ self._verify_fp = None ++ self._verify_error = None ++ self.dev.verify(fp_whorl, callback=verify_cb) ++ self.send_error() ++ while self._verify_fp is None and self._verify_error is None: ++ ctx.iteration(True) ++ assert(self._verify_error is not None) ++ print(self._verify_error) ++ assert(self._verify_error.matches(FPrint.device_error_quark(), FPrint.DeviceError.GENERAL)) ++ + 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) ++ try: ++ self._identify_match, self._identify_fp = self.dev.identify_finish(res) ++ except gi.repository.GLib.Error as e: ++ print(e) ++ self._identify_error = e + + self._identify_fp = None + self.dev.identify([fp_whorl, fp_tented_arch], None, identify_cb) +@@ -263,6 +283,25 @@ class VirtualImage(unittest.TestCase): + ctx.iteration(True) + assert(self._identify_match is fp_whorl) + ++ # Test error cases ++ self._identify_fp = None ++ self._identify_error = None ++ self.dev.identify([fp_whorl, fp_tented_arch], callback=identify_cb) ++ self.send_retry() ++ while self._identify_fp is None and self._identify_error is None: ++ ctx.iteration(True) ++ assert(self._identify_error is not None) ++ assert(self._identify_error.matches(FPrint.device_retry_quark(), FPrint.DeviceRetry.TOO_SHORT)) ++ ++ self._identify_fp = None ++ self._identify_error = None ++ self.dev.identify([fp_whorl, fp_tented_arch], callback=identify_cb) ++ self.send_error() ++ while self._identify_fp is None and self._identify_error is None: ++ ctx.iteration(True) ++ assert(self._identify_error is not None) ++ assert(self._identify_error.matches(FPrint.device_error_quark(), FPrint.DeviceError.GENERAL)) ++ + def test_verify_serialized(self): + done = False + +-- +2.24.1 + diff --git a/SOURCES/0177-image-device-Avoid-invalid-state-transition-on-cance.patch b/SOURCES/0177-image-device-Avoid-invalid-state-transition-on-cance.patch new file mode 100644 index 0000000..d0ff995 --- /dev/null +++ b/SOURCES/0177-image-device-Avoid-invalid-state-transition-on-cance.patch @@ -0,0 +1,66 @@ +From c16f8101e29dd93e846c90574b68677c8e9ab0b6 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Wed, 15 Jan 2020 14:48:06 +0100 +Subject: [PATCH 177/181] image-device: Avoid invalid state transition on + cancellation + +Fixes: #226 +--- + libfprint/drivers/elan.c | 2 -- + libfprint/fpi-image-device.c | 18 +++++++++++++++--- + 2 files changed, 15 insertions(+), 5 deletions(-) + +diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c +index 1c2a7a3..084e4bd 100644 +--- a/libfprint/drivers/elan.c ++++ b/libfprint/drivers/elan.c +@@ -585,8 +585,6 @@ capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) + + G_DEBUG_HERE (); + +- /* 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) && +diff --git a/libfprint/fpi-image-device.c b/libfprint/fpi-image-device.c +index 888c931..b5747f6 100644 +--- a/libfprint/fpi-image-device.c ++++ b/libfprint/fpi-image-device.c +@@ -428,7 +428,9 @@ fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry) + * @error: The #GError to report + * + * Report an error while interacting with the device. This effectively +- * aborts the current ongoing action. ++ * aborts the current ongoing action. Note that doing so will result in ++ * the deactivation handler to be called and this function must not be ++ * used to report an error during deactivation. + */ + void + fpi_image_device_session_error (FpImageDevice *self, GError *error) +@@ -455,10 +457,20 @@ fpi_image_device_session_error (FpImageDevice *self, GError *error) + return; + } + } ++ else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) && ++ fpi_device_action_is_cancelled (FP_DEVICE (self))) ++ { ++ /* Ignore cancellation errors here, as we will explicitly deactivate ++ * anyway (or, may already have done so at this point). ++ */ ++ g_debug ("Driver reported a cancellation error, this is expected but not required. Ignoring."); ++ g_clear_error (&error); ++ return; ++ } + else if (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE) + { +- g_warning ("Driver reported session error; translating to deactivation failure."); +- fpi_image_device_deactivate_complete (self, error); ++ g_warning ("Driver reported session error while deactivating already, ignoring. This indicates a driver bug."); ++ g_clear_error (&error); + return; + } + +-- +2.24.1 + diff --git a/SOURCES/0178-compat-Add-compatibility-defines-for-older-GLib.patch b/SOURCES/0178-compat-Add-compatibility-defines-for-older-GLib.patch new file mode 100644 index 0000000..a1b3efd --- /dev/null +++ b/SOURCES/0178-compat-Add-compatibility-defines-for-older-GLib.patch @@ -0,0 +1,114 @@ +From 96a9d5efa0309af8b61a7f728e85efd40b003f54 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Mon, 13 Jan 2020 15:16:04 +0100 +Subject: [PATCH 178/181] compat: Add compatibility defines for older GLib + +We are already using a number of defines and autoptrs from newer GLib +releases. Add the appropriate compatibility defines rather than removing +the corresponding code. + +Placing this into fpi-log.h is not ideal, but it seems to catch all +use-cases currently. + +Closes: #222 +--- + libfprint/drivers_api.h | 1 + + libfprint/fpi-compat.h | 31 +++++++++++++++++++++++ + libfprint/fpi-log.h | 3 +++ + libfprint/fprint-list-supported-devices.c | 2 ++ + libfprint/fprint-list-udev-rules.c | 2 ++ + 5 files changed, 39 insertions(+) + create mode 100644 libfprint/fpi-compat.h + +diff --git a/libfprint/drivers_api.h b/libfprint/drivers_api.h +index 7476ba7..aef8c9d 100644 +--- a/libfprint/drivers_api.h ++++ b/libfprint/drivers_api.h +@@ -21,6 +21,7 @@ + + #pragma once + ++#include "fpi-compat.h" + #include "fpi-assembling.h" + #include "fpi-device.h" + #include "fpi-image-device.h" +diff --git a/libfprint/fpi-compat.h b/libfprint/fpi-compat.h +new file mode 100644 +index 0000000..396fc77 +--- /dev/null ++++ b/libfprint/fpi-compat.h +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (C) 2020 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 ++ ++#if !GLIB_CHECK_VERSION (2, 57, 0) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (GTypeClass, g_type_class_unref); ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (GEnumClass, g_type_class_unref); ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (GParamSpec, g_param_spec_unref); ++#else ++#undef G_SOURCE_FUNC ++#endif ++ ++#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void)) (f)) +diff --git a/libfprint/fpi-log.h b/libfprint/fpi-log.h +index da61204..53546c2 100644 +--- a/libfprint/fpi-log.h ++++ b/libfprint/fpi-log.h +@@ -19,6 +19,9 @@ + + #pragma once + ++/* To avoid having to add it everywhere, at least for now. */ ++#include "fpi-compat.h" ++ + /** + * SECTION:fpi-log + * @title: Logging +diff --git a/libfprint/fprint-list-supported-devices.c b/libfprint/fprint-list-supported-devices.c +index cb2803f..1231ed0 100644 +--- a/libfprint/fprint-list-supported-devices.c ++++ b/libfprint/fprint-list-supported-devices.c +@@ -26,6 +26,8 @@ + #include "fpi-context.h" + #include "fpi-device.h" + ++#include "fpi-compat.h" ++ + GHashTable *printed = NULL; + + static GList * +diff --git a/libfprint/fprint-list-udev-rules.c b/libfprint/fprint-list-udev-rules.c +index ac50797..3bc64e8 100644 +--- a/libfprint/fprint-list-udev-rules.c ++++ b/libfprint/fprint-list-udev-rules.c +@@ -21,6 +21,8 @@ + + #include + ++#include "fpi-compat.h" ++ + #include "fpi-context.h" + #include "fpi-device.h" + +-- +2.24.1 + diff --git a/SOURCES/0179-tests-Return-skip-error-if-import-fails.patch b/SOURCES/0179-tests-Return-skip-error-if-import-fails.patch new file mode 100644 index 0000000..f195c37 --- /dev/null +++ b/SOURCES/0179-tests-Return-skip-error-if-import-fails.patch @@ -0,0 +1,57 @@ +From 871d07cc1e6533cf60950ebc75825e313c96e42b Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Wed, 15 Jan 2020 18:42:54 +0100 +Subject: [PATCH 179/181] tests: Return skip error if import fails + +Rather than backtracing, just print the exception and return a skip +error if the import fails. +--- + tests/virtual-image.py | 32 ++++++++++++++++++-------------- + 1 file changed, 18 insertions(+), 14 deletions(-) + +diff --git a/tests/virtual-image.py b/tests/virtual-image.py +index a6bf6d2..da77eee 100755 +--- a/tests/virtual-image.py ++++ b/tests/virtual-image.py +@@ -1,20 +1,24 @@ + #!/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 subprocess +-import shutil +-import glob +-import cairo +-import tempfile ++try: ++ 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 subprocess ++ import shutil ++ import glob ++ import cairo ++ import tempfile ++except Exception as e: ++ print("Missing dependencies: %s" % str(e)) ++ sys.exit(77) + + # Re-run the test with the passed wrapper if set + wrapper = os.getenv('LIBFPRINT_TEST_WRAPPER') +-- +2.24.1 + diff --git a/SOURCES/0180-synaptics-Really-check-if-a-print-is-device-database.patch b/SOURCES/0180-synaptics-Really-check-if-a-print-is-device-database.patch new file mode 100644 index 0000000..72980c9 --- /dev/null +++ b/SOURCES/0180-synaptics-Really-check-if-a-print-is-device-database.patch @@ -0,0 +1,27 @@ +From c828522f3f428f6a372c58e36c2c19204a1d18a6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 16 Jan 2020 19:09:20 +0100 +Subject: [PATCH 180/181] synaptics: Really check if a print is device database + +Fix a typo causing the not-in-database print error to be fired, actually +checking the response result. +--- + libfprint/drivers/synaptics/synaptics.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c +index 2aac75e..3f79e4b 100644 +--- a/libfprint/drivers/synaptics/synaptics.c ++++ b/libfprint/drivers/synaptics/synaptics.c +@@ -634,7 +634,7 @@ verify_msg_cb (FpiDeviceSynaptics *self, + self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_FAIL); + self->cmd_complete_error = NULL; + } +- else if (BMKT_FP_DATABASE_NO_RECORD_EXISTS) ++ else if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS) + { + fp_info ("Print is not in database"); + fpi_device_verify_complete (device, +-- +2.24.1 + diff --git a/SOURCES/0181-synaptics-Report-a-verify-complete-error-on-unexpect.patch b/SOURCES/0181-synaptics-Report-a-verify-complete-error-on-unexpect.patch new file mode 100644 index 0000000..b2fa60e --- /dev/null +++ b/SOURCES/0181-synaptics-Report-a-verify-complete-error-on-unexpect.patch @@ -0,0 +1,31 @@ +From 619666513c0250a96a5214fd8a00cc4d69c4d6cc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 16 Jan 2020 19:47:45 +0100 +Subject: [PATCH 181/181] synaptics: Report a verify complete error on + unexpected result + +--- + libfprint/drivers/synaptics/synaptics.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c +index 3f79e4b..227e406 100644 +--- a/libfprint/drivers/synaptics/synaptics.c ++++ b/libfprint/drivers/synaptics/synaptics.c +@@ -645,7 +645,12 @@ verify_msg_cb (FpiDeviceSynaptics *self, + else + { + fp_warn ("Verify has failed: %d", resp->result); +- fpi_device_verify_complete (device, FPI_MATCH_FAIL, NULL, NULL); ++ fpi_device_verify_complete (device, ++ FPI_MATCH_ERROR, ++ NULL, ++ fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, ++ "Unexpected result from device %d", ++ resp->result)); + } + break; + +-- +2.24.1 + diff --git a/SPECS/libfprint.spec b/SPECS/libfprint.spec index ebcb769..5c3a863 100644 --- a/SPECS/libfprint.spec +++ b/SPECS/libfprint.spec @@ -1,7 +1,7 @@ Name: libfprint Version: 1.90.0 -Release: 2%{?dist} +Release: 4%{?dist} Summary: Toolkit for fingerprint scanner @@ -26,11 +26,192 @@ BuildRequires: gtk-doc BuildRequires: systemd BuildRequires: gobject-introspection-devel # For internal CI tests -#BuildRequires: python3-cairo python3-gobject +BuildRequires: cairo-devel +BuildRequires: python3-cairo python3-gobject #BuildRequires: umockdev Patch0001: 0001-udev-rules-Remove-debug-spew-from-udev-rules.patch -Patch0002: 0002-Fix-missing-initialization.patch +Patch0002: 0002-elan-Fix-potential-leak-of-dark-frame.patch +Patch0003: 0003-elan-Fix-switch-in-change_state.patch +Patch0004: 0004-synaptics-Correctly-unref-pointer-array.patch +Patch0005: 0005-synaptics-Add-an-explicit-assert-on-the-response.patch +Patch0006: 0006-upeksonly-Add-default-clauses-to-switch-statements.patch +Patch0007: 0007-image-device-Remove-unused-fpi_device_get_current_ac.patch +Patch0008: 0008-print-Free-temporary-col-variable.patch +Patch0009: 0009-print-Ensure-xyt-struct-is-not-leaked-during-deseria.patch +Patch0010: 0010-verify-Ensure-we-set-set-the-autoptr-value-to-NULL-a.patch +Patch0011: 0011-fpi-ssm-fp-device-Add-missing-copyright.patch +Patch0012: 0012-meson-Use-multiline-array-for-default-dirvers-listin.patch +Patch0013: 0013-meson-Use-preferred-syntax-everywhere.patch +Patch0014: 0014-meson-Avoid-repeating-the-needed-glib-version-multip.patch +Patch0015: 0015-image-device-Use-g_clear_handle_id-for-timeouts.patch +Patch0016: 0016-fp-print-Use-g_date_copy.patch +Patch0017: 0017-fp-image-device-Clear-the-pending-activation-timeout.patch +Patch0018: 0018-fp-image-device-Reactivate-in-idle-on-deactivation-c.patch +Patch0019: 0019-fp-image-device-Add-private-fp-image-device-state-pr.patch +Patch0020: 0020-fp-image-device-Use-a-GObject-signal-to-notify-image.patch +Patch0021: 0021-fpi-ssm-Remove-any-reference-to-fpi_timeout_add.patch +Patch0022: 0022-fpi-log-Set-fp_error-as-equal-to-g_critical.patch +Patch0023: 0023-fp-device-Support-variadic-arguments-to-error-functi.patch +Patch0024: 0024-drivers-Use-clearer-messages-using-parameters.patch +Patch0025: 0025-synaptics-Use-GDate-getters-to-retrieve-the-DMY-valu.patch +Patch0026: 0026-synaptics-Initialize-user_id-autoptr-to-NULL.patch +Patch0027: 0027-examples-Handle-the-cases-where-the-print-date-is-no.patch +Patch0028: 0028-fpi-ssm-Take-ownership-of-the-SSM-when-completing-it.patch +Patch0029: 0029-fpi-usb-transfer-Take-ownership-of-the-transfer-when.patch +Patch0030: 0030-fpi-ssm-Add-a-usb-transfer-callback-with-data-as-wea.patch +Patch0031: 0031-drivers-Use-more-fpi_ssm_usb_transfer_cb-when-possib.patch +Patch0032: 0032-fpi-ssm-Make-clearer-that-data-is-unused-in-fpi_ssm_.patch +Patch0033: 0033-umockdev-test-Make-possible-to-use-a-wrapper-to-run-.patch +Patch0034: 0034-virtual-image-Re-run-the-test-using-the-defined-wrap.patch +Patch0035: 0035-tests-Add-gdb-setup-to-run-tests-using-gdb.patch +Patch0036: 0036-tests-Add-setup-mode-to-run-tests-using-valgrind.patch +Patch0037: 0037-fp-device-Unref-the-usb-device-on-finalize.patch +Patch0038: 0038-fp-context-Run-dispose-on-the-usb-context-to-deal-wi.patch +Patch0039: 0039-fp-print-Unref-the-prints-on-finalize.patch +Patch0040: 0040-fp-print-Assert-the-prints-aren-t-set-when-initializ.patch +Patch0041: 0041-fp-print-Unref-print-data-and-get-static-strings-whe.patch +Patch0042: 0042-virtual-image-Also-unref-the-object-when-closing-a-t.patch +Patch0043: 0043-fp-device-Use-an-autopointer-and-steal-the-print-whe.patch +Patch0044: 0044-fp-device-Unref-the-print-once-we-ve-notified-the-pr.patch +Patch0045: 0045-fp-device-Mark-user-data-in-FpEnrollProgress-as-tran.patch +Patch0046: 0046-fp-device-Use-g_clear_error-instead-of-check-free.patch +Patch0047: 0047-tests-Use-a-loop-for-generating-drivers-tests-and-us.patch +Patch0048: 0048-fp-print-Set-the-aligned_data-as-the-data-used-by-th.patch +Patch0049: 0049-tests-Fix-endianness-issue-in-test-suite.patch +Patch0050: 0050-assembling-Use-fixed-point-for-image-assembly.patch +Patch0051: 0051-Fix-indentation-issues-using-newer-uncrustify.patch +Patch0052: 0052-virtual-image-Fix-driver-reading-insufficient-data.patch +Patch0053: 0053-synaptics-Use-an-autoptr-to-handle-the-FpiUsbTransfe.patch +Patch0054: 0054-synaptics-Close-the-usb-device-if-reset-failed.patch +Patch0055: 0055-vfs301-Use-a-transfer-autopointer-to-cleanup-it-on-s.patch +Patch0056: 0056-fpi-ssm-Also-bug-on-negative-state-value.patch +Patch0057: 0057-fpi-device-Make-possible-to-set-a-DestroyNotify-for-.patch +Patch0058: 0058-fpi-ssm-Add-possibility-to-jump-to-a-state-or-next-o.patch +Patch0059: 0059-drivers-Use-fpi_ssm_next_state_delayed-instead-of-cu.patch +Patch0060: 0060-fpi-ssm-Clarify-the-ownership-of-error-in-fpi_ssm_ma.patch +Patch0061: 0061-drivers-Use-SSM-delayed-actions-when-possible.patch +Patch0062: 0062-fpi-ssm-Make-delayed-actions-cancellable.patch +Patch0063: 0063-fpi-ssm-Bug-on-handler-set-to-a-NULL-function.patch +Patch0064: 0064-fpi-ssm-Mark-a-fpi-ssm-completed-on-delay.patch +Patch0065: 0065-tests-Fix-image-writing-on-big-endian.patch +Patch0066: 0066-fpi-usb-Use-unsigned-length-for-USB-async-transfers.patch +Patch0067: 0067-drivers-examples-Don-t-use-Wno-pointer-sign-and-fix-.patch +Patch0068: 0068-fp-print-Clear-the-data-not-the-description-when-set.patch +Patch0069: 0069-meson-Use-add_project_arguments-for-common-cflags.patch +Patch0070: 0070-cpp-test-Fix-indentation.patch +Patch0071: 0071-meson-Build-nbis-separately-to-allow-changing-flags.patch +Patch0072: 0072-meson-Add-the-include-directories-to-deps.patch +Patch0073: 0073-nbis-Add-a-global-include-file-with-all-the-definiti.patch +Patch0074: 0074-cleanup-Don-t-make-nbis-depend-on-libfprint-built-so.patch +Patch0075: 0075-nbis-log-Don-t-use-old-style-function-declarations.patch +Patch0076: 0076-nbis-Make-the-extern-global-bozworth-y-variable-as-b.patch +Patch0077: 0077-storage-Include-storage-header-so-that-we-have-decla.patch +Patch0078: 0078-fp-device-Remove-unused-timeout-function-and-source-.patch +Patch0079: 0079-cleanup-Use-static-functions-for-non-declared-method.patch +Patch0080: 0080-gtk-demo-Use-G_DECLARE-to-avoid-missing-declarations.patch +Patch0081: 0081-vfs5011-Cast-gpointer-data-values-to-proper-type-to-.patch +Patch0082: 0082-vfs0050-Use-proper-casting-summing-pointers-first.patch +Patch0083: 0083-meson-Include-fpi-context.h-in-generated-fp-drivers..patch +Patch0084: 0084-meson-Move-generated-source-to-fpi-prefix-and-use-mo.patch +Patch0085: 0085-meson-Use-stricter-C-arguments-to-compile-libfprint.patch +Patch0086: 0086-elan-Fix-internal-state-machine-to-ensure-correct-de.patch +Patch0087: 0087-image-device-Prevent-deactivation-when-waiting-for-f.patch +Patch0088: 0088-uru4000-Fix-state-change-from-IRQ-handler.patch +Patch0089: 0089-uru4000-Fix-control-transfer-request-type.patch +Patch0090: 0090-fpi-ssm-Support-named-SSMs-and-use-a-fallback-macro.patch +Patch0091: 0091-fpi-ssm-Improve-debugging-of-SSM-using-driver-infos.patch +Patch0092: 0092-vfs0051-Use-named-SSMs-for-usb-async-exchanges.patch +Patch0093: 0093-image-device-Print-warning-for-incorrect-deactivatio.patch +Patch0094: 0094-virtual-image-Only-print-warnings-for-actual-errors.patch +Patch0095: 0095-virtual-image-Allow-fine-control-over-the-finger-sta.patch +Patch0096: 0096-tests-Update-helper-functions-for-new-virtual-image-.patch +Patch0097: 0097-tests-Test-finger-removal-after-minutiae-scan-comple.patch +Patch0098: 0098-print-Fix-match-error-propagation.patch +Patch0099: 0099-synaptics-Fix-problem-after-match-is-failed.patch +Patch0100: 0100-fp-device-Use-different-pointers-for-device-handlers.patch +Patch0101: 0101-docs-Don-t-ignore-the-deprecated-API_EXPORTED-defini.patch +Patch0102: 0102-tests-meson-Set-the-typelib-env-var-only-if-we-have-.patch +Patch0103: 0103-fp-device-Add-a-open-property-and-method-to-check-it.patch +Patch0104: 0104-libfprint-Introduce-libfprint_private-static-library.patch +Patch0105: 0105-fp-device-Move-fpi-code-into-its-own-unit-that-can-b.patch +Patch0106: 0106-fp-image-device-Move-fpi-code-into-its-own-unit-that.patch +Patch0107: 0107-fp-image-fp-print-Move-private-methods-to-own-code-u.patch +Patch0108: 0108-meson-Use-files-to-track-the-map-file-presence.patch +Patch0109: 0109-meson-Rely-on-libfprint-dependency-to-get-root_inclu.patch +Patch0110: 0110-fprint-Move-drivers-to-private-internal-library.patch +Patch0111: 0111-meson-Fix-syntax-in-the-auto-generated-fpi-drivers-f.patch +Patch0112: 0112-fpi-context-Make-fpi_get_driver_types-to-return-an-a.patch +Patch0113: 0113-fp-context-Use-an-env-to-define-a-whitelist-of-drive.patch +Patch0114: 0114-fp-context-tools-Use-auto-ptr-to-handle-GTypeClass-o.patch +Patch0115: 0115-tests-Add-basic-unit-tests-for-fp-context.patch +Patch0116: 0116-tests-Add-fp-device-basic-unit-tests.patch +Patch0117: 0117-fp-device-Call-identify-device-class-method-on-ident.patch +Patch0118: 0118-fpi-device-Clarify-ownership-of-parameters-for-progr.patch +Patch0119: 0119-test-device-fake-Add-fake-test-driver-to-verify-fpi-.patch +Patch0120: 0120-tests-meson-Support-unit-tests-non-depending-on-virt.patch +Patch0121: 0121-tests-Add-fpi-device-tests.patch +Patch0122: 0122-fpi-ssm-Use-same-argument-names-of-header-file.patch +Patch0123: 0123-fpi-ssm-Define-autoptr-cleanup-function.patch +Patch0124: 0124-fpi-ssm-Bug-on-wrong-state-passed-to-jump_to_state_d.patch +Patch0125: 0125-fpi-ssm-Add-debug-message-when-a-delayed-state-chang.patch +Patch0126: 0126-fpi-ssm-Make-clear-that-the-completed-callback-owns-.patch +Patch0127: 0127-fpi-ssm-Clear-delayed-actions-for-parent-and-child-o.patch +Patch0128: 0128-tests-Add-unit-tests-for-fpi-ssm.patch +Patch0129: 0129-meson-Split-single-line-dependencies-to-reduce-the-d.patch +Patch0130: 0130-driver_ids.h-Remove-the-legacy-ID-file.patch +Patch0131: 0131-synaptics-Use-local-variable-rather-than-re-fetching.patch +Patch0132: 0132-tests-Ensure-objects-are-free-ed-at-the-end-of-tests.patch +Patch0133: 0133-examples-Fix-double-device-closing-in-manage-prints.patch +Patch0134: 0134-elan-Do-not-leak-converted-frames.patch +Patch0135: 0135-meson-Add-missing-dependency-on-fp-enum.h-for-privat.patch +Patch0136: 0136-tests-Fix-stack-corruption-in-FpiSsm-test.patch +Patch0137: 0137-fpi-ssm-fpi-usb-transfer-Use-fwd-declarations-to-avo.patch +Patch0138: 0138-meson-Parse-all-private-headers.patch +Patch0139: 0139-meson-List-deps-in-multiple-lines-to-have-better-dif.patch +Patch0140: 0140-meson-No-need-to-redefine-default-pkgconfig-install-.patch +Patch0141: 0141-meson-Don-t-install-fpi-enums.patch +Patch0142: 0142-meson-Use-more-meson-s-project_name.patch +Patch0143: 0143-meson-Use-soversion-everywhere.patch +Patch0144: 0144-meson-Add-fp-image-device-to-public-headers.patch +Patch0145: 0145-cleanup-Remove-fp_internal.h-and-update-drivers_api..patch +Patch0146: 0146-cleanup-Use-pragma-once-everywhere.patch +Patch0147: 0147-cleanup-Use-FPI-prefix-for-all-the-internal-enum-typ.patch +Patch0148: 0148-tests-Add-a-reference-to-the-enrolled-print-before-r.patch +Patch0149: 0149-meson-Define-enum-dependency-and-ensure-we-generate-.patch +Patch0150: 0150-meson-Fix-syntax-for-fpi_enums-generation-call.patch +Patch0151: 0151-libfprint-Make-sure-we-install-fp-enums.h-in-the-rig.patch +Patch0152: 0152-meson-Bump-dependency-on-0.49.0.patch +Patch0153: 0153-Prefix-internal-properties-signals-with-fpi-and-anno.patch +Patch0154: 0154-fp-print-Add-aliases-for-First-and-Last-finger-in-ou.patch +Patch0155: 0155-examples-Iterate-through-fingers-via-first-last-refs.patch +Patch0156: 0156-fp-print-Add-FP_FINGER_IS_VALID.patch +Patch0157: 0157-fpi-assembling-Accept-error-of-zero.patch +Patch0158: 0158-fpi-assembling-Fix-offsets-to-be-relative-to-the-pre.patch +Patch0159: 0159-tests-Set-MESON_SOURCE_ROOT-to-source-root-not-build.patch +Patch0160: 0160-tests-Add-some-frame-assembly-unit-tests.patch +Patch0161: 0161-examples-Fix-possible-use-after-free-in-storage-code.patch +Patch0162: 0162-examples-Do-not-free-data-returned-by-g_variant_get_.patch +Patch0163: 0163-storage-Do-not-free-image-data-owned-by-FpPrint.patch +Patch0164: 0164-examples-Save-image-even-on-match-failure.patch +Patch0165: 0165-examples-Continue-verification-when-return-is-presse.patch +Patch0166: 0166-examples-Do-not-re-prompt-the-finger-when-repeating-.patch +Patch0167: 0167-image-device-Fix-reading-default-values-from-the-cla.patch +Patch0168: 0168-image-device-Fix-enroll-continuation-after-retry-err.patch +Patch0169: 0169-elan-Add-umockdev-based-test.patch +Patch0170: 0170-tests-Add-more-notes-about-umockdev-recording-creati.patch +Patch0171: 0171-tests-Always-add-dummy-skipping-tests.patch +Patch0172: 0172-device-Fix-potential-memory-leak-of-progress_cb-user.patch +Patch0173: 0173-upekts-Remove-unused-argument-from-deinitsm_new.patch +Patch0174: 0174-device-Better-define-ownership-passing-for-results.patch +Patch0175: 0175-image-device-Set-cancelling-when-errors-are-reported.patch +Patch0176: 0176-tests-Add-error-reporting-tests-based-on-virtual-dri.patch +Patch0177: 0177-image-device-Avoid-invalid-state-transition-on-cance.patch +Patch0178: 0178-compat-Add-compatibility-defines-for-older-GLib.patch +Patch0179: 0179-tests-Return-skip-error-if-import-fails.patch +Patch0180: 0180-synaptics-Really-check-if-a-print-is-device-database.patch +Patch0181: 0181-synaptics-Report-a-verify-complete-error-on-unexpect.patch +Patch0200: 0001-tests-Add-missing-NULL-terminator-to-g_object_new.patch %description libfprint offers support for consumer fingerprint reader devices. @@ -47,7 +228,7 @@ developing applications that use %{name}. %prep -%autosetup -p1 +%autosetup -S git %build # Include the virtual image driver for integration tests @@ -59,10 +240,8 @@ developing applications that use %{name}. %ldconfig_scriptlets -# Disabled as umockdev is not available %check -exit 0 -#%meson_test +%meson_test %files %license COPYING @@ -80,6 +259,13 @@ exit 0 %{_datadir}/gtk-doc/html/libfprint/ %changelog +* Mon Jan 20 2020 Benjamin Berg - 1.90.0-4 +- Add patch to fix unit-test failure + +* Wed Jan 15 2020 Benjamin Berg - 1.90.0-3 +- Pull in upstream fixes from the not-yet released 1.90.1 +- Related: rhbz1791256 + * Fri Nov 22 2019 Benjamin Berg - 1.90.0-2 - Add patch to remove debug spew from udev rules - Add patch to fix compilation error