From 3b0c2b24da5689990c4bc0fcd3afecdf063086c8 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Sun, 20 Nov 2016 04:24:57 -0800 Subject: Bring over support for retrying metadata cache entry loads, along with all the supporting metadata cache callback changes, etc. --- java/src/hdf/hdf5lib/H5.java | 36 +++ java/src/jni/h5pImp.c | 34 +++ java/src/jni/h5pImp.h | 19 ++ src/H5ACprivate.h | 4 +- src/H5B2cache.c | 192 +++++++++++--- src/H5Bcache.c | 54 ++-- src/H5C.c | 373 ++++++++++++++------------- src/H5Cepoch.c | 39 ++- src/H5Cprivate.h | 165 ++++++++---- src/H5EAcache.c | 294 ++++++++++++++++------ src/H5FAcache.c | 172 ++++++++++--- src/H5FScache.c | 129 +++++++--- src/H5Fint.c | 108 ++++++++ src/H5Fio.c | 43 ++++ src/H5Fpkg.h | 8 + src/H5Fprivate.h | 18 ++ src/H5Fpublic.h | 9 + src/H5Fquery.c | 23 ++ src/H5Fsuper_cache.c | 583 ++++++++++++++++++++++++++++--------------- src/H5Gcache.c | 34 +-- src/H5HFcache.c | 548 ++++++++++++++++++++++++++-------------- src/H5HFpkg.h | 8 + src/H5HGcache.c | 279 ++++++++++++--------- src/H5HL.c | 40 +-- src/H5HLcache.c | 282 ++++++++++++++------- src/H5HLdblk.c | 10 +- src/H5HLpkg.h | 16 -- src/H5HLprfx.c | 4 +- src/H5O.c | 86 +------ src/H5Ocache.c | 474 ++++++++++++++++++++--------------- src/H5Opkg.h | 6 +- src/H5Pfapl.c | 96 +++++++ src/H5Ppublic.h | 2 + src/H5SMcache.c | 133 +++++++--- src/H5private.h | 8 +- src/H5system.c | 81 ++++++ src/H5win32defs.h | 15 +- test/cache.c | 130 ++++++++++ test/cache_common.c | 248 ++++++++++++++---- test/cache_common.h | 3 + test/earray.c | 23 +- testpar/t_cache.c | 15 +- 42 files changed, 3323 insertions(+), 1521 deletions(-) diff --git a/java/src/hdf/hdf5lib/H5.java b/java/src/hdf/hdf5lib/H5.java index 789fea5..50faa6d 100644 --- a/java/src/hdf/hdf5lib/H5.java +++ b/java/src/hdf/hdf5lib/H5.java @@ -2854,6 +2854,7 @@ public class H5 implements java.io.Serializable { // /////// unimplemented //////// // ssize_t H5Fget_file_image(hid_t file_id, void * buf_ptr, size_t buf_len); + // herr_t H5Fget_metadata_read_retry_info(hid_t file_id, H5F_retry_info_t *info); // ssize_t H5Fget_free_sections(hid_t file_id, H5F_mem_t type, size_t nsects, H5F_sect_info_t *sect_info/*out*/); // /** @@ -5672,6 +5673,41 @@ public class H5 implements java.io.Serializable { public synchronized static native void H5Pset_elink_file_cache_size(long fapl_id, int efc_size) throws HDF5LibraryException; + /** + /** + * H5Pget_metadata_read_attempts retrieves the number of read attempts that is set in the file access property list plist_id. + * + * @param plist_id + * IN: File access property list identifier + * + * @return The number of read attempts. + * + * @exception HDF5LibraryException + * - Error from the HDF-5 Library. + * + **/ + public synchronized static native long H5Pget_metadata_read_attempts(long plist_id) throws HDF5LibraryException; + + /** + * H5Pset_metadata_read_attempts sets the number of reads that the library will try when reading checksummed + * metadata in an HDF5 file opened with SWMR access. When reading such metadata, the library will compare the + * checksum computed for the metadata just read with the checksum stored within the piece of checksum. When + * performing SWMR operations on a file, the checksum check might fail when the library reads data on a system + * that is not atomic. To remedy such situations, the library will repeatedly read the piece of metadata until + * the check passes or finally fails the read when the allowed number of attempts is reached. + * + * @param plist_id + * IN: File access property list identifier + * @param attempts + * IN: The number of read attempts which is a value greater than 0. + * + * @exception HDF5LibraryException + * - Error from the HDF-5 Library. + * + **/ + public synchronized static native void H5Pset_metadata_read_attempts(long plist_id, long attempts) + throws HDF5LibraryException; + // Dataset creation property list (DCPL) routines // /** diff --git a/java/src/jni/h5pImp.c b/java/src/jni/h5pImp.c index 7c71da1..01da210 100644 --- a/java/src/jni/h5pImp.c +++ b/java/src/jni/h5pImp.c @@ -5542,6 +5542,40 @@ Java_hdf_hdf5lib_H5_H5Piterate return (jint)status; } /* end Java_hdf_hdf5lib_H5_H5Piterate */ +/* + * Class: hdf_hdf5lib_H5 + * Method: H5Pget_metadata_read_attempts + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL +Java_hdf_hdf5lib_H5_H5Pget_1metadata_1read_1attempts + (JNIEnv *env, jclass clss, jlong plist_id) +{ + unsigned attempts; + if (H5Pget_metadata_read_attempts((hid_t)plist_id, &attempts) < 0) + h5libraryError(env); + + return (jlong) attempts; +} /* end Java_hdf_hdf5lib_H5_H5Pget_1metadata_1read_1attempts */ + +/* + * Class: hdf_hdf5lib_H5 + * Method: H5Pset_metadata_read_attempts + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL +Java_hdf_hdf5lib_H5_H5Pset_1metadata_1read_1attempts + (JNIEnv *env, jclass clss, jlong plist_id, jlong attempts) +{ + if (attempts <= 0) { + h5badArgument(env, "H5Pset_metadata_read_attempts: attempts <= 0"); + } /* end if */ + else { + if(H5Pset_metadata_read_attempts((hid_t)plist_id, (unsigned)attempts) < 0) + h5libraryError(env); + } /* end else */ +} /* end Java_hdf_hdf5lib_H5_H5Pset_1metadata_1read_1attempts */ + #ifdef __cplusplus } /* end extern "C" */ #endif /* __cplusplus */ diff --git a/java/src/jni/h5pImp.h b/java/src/jni/h5pImp.h index 2269624..d606b7a 100644 --- a/java/src/jni/h5pImp.h +++ b/java/src/jni/h5pImp.h @@ -1473,6 +1473,25 @@ JNIEXPORT jint JNICALL Java_hdf_hdf5lib_H5_H5Piterate (JNIEnv*, jclass, jlong, jintArray, jobject, jobject); +/* + * Class: hdf_hdf5lib_H5 + * Method: H5Pget_metadata_read_attempts + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL +Java_hdf_hdf5lib_H5_H5Pget_1metadata_1read_1attempts +(JNIEnv *, jclass, jlong); + + +/* + * Class: hdf_hdf5lib_H5 + * Method: H5Pset_metadata_read_attempts + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL +Java_hdf_hdf5lib_H5_H5Pset_1metadata_1read_1attempts +(JNIEnv *, jclass, jlong, jlong); + #ifdef __cplusplus } /* end extern "C" */ diff --git a/src/H5ACprivate.h b/src/H5ACprivate.h index 3a260d0..2251af4 100644 --- a/src/H5ACprivate.h +++ b/src/H5ACprivate.h @@ -175,7 +175,9 @@ typedef H5C_notify_action_t H5AC_notify_action_t; #define H5AC__CLASS_SKIP_READS H5C__CLASS_SKIP_READS #define H5AC__CLASS_SKIP_WRITES H5C__CLASS_SKIP_WRITES -typedef H5C_get_load_size_func_t H5AC_get_load_size_func_t; +typedef H5C_get_initial_load_size_func_t H5AC_get_initial_load_size_func_t; +typedef H5C_get_final_load_size_func_t H5AC_get_final_load_size_func_t; +typedef H5C_verify_chksum_func_t H5AC_verify_chksum_func_t; typedef H5C_deserialize_func_t H5AC_deserialize_func_t; typedef H5C_image_len_func_t H5AC_image_len_func_t; diff --git a/src/H5B2cache.c b/src/H5B2cache.c index 32db4b0..51ad32b 100644 --- a/src/H5B2cache.c +++ b/src/H5B2cache.c @@ -65,7 +65,8 @@ /********************/ /* Metadata cache callbacks */ -static herr_t H5B2__cache_hdr_get_load_size(const void *udata, size_t *image_len); +static herr_t H5B2__cache_hdr_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5B2__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata); static void *H5B2__cache_hdr_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5B2__cache_hdr_image_len(const void *thing, size_t *image_len); @@ -73,7 +74,8 @@ static herr_t H5B2__cache_hdr_serialize(const H5F_t *f, void *image, size_t len, void *thing); static herr_t H5B2__cache_hdr_free_icr(void *thing); -static herr_t H5B2__cache_int_get_load_size(const void *udata, size_t *image_len); +static herr_t H5B2__cache_int_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5B2__cache_int_verify_chksum(const void *image_ptr, size_t len, void *udata); static void *H5B2__cache_int_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5B2__cache_int_image_len(const void *thing, size_t *image_len); @@ -81,7 +83,8 @@ static herr_t H5B2__cache_int_serialize(const H5F_t *f, void *image, size_t len, void *thing); static herr_t H5B2__cache_int_free_icr(void *thing); -static herr_t H5B2__cache_leaf_get_load_size(const void *udata, size_t *image_len); +static herr_t H5B2__cache_leaf_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5B2__cache_leaf_verify_chksum(const void *image_ptr, size_t len, void *udata); static void *H5B2__cache_leaf_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5B2__cache_leaf_image_len(const void *thing, size_t *image_len); @@ -99,7 +102,9 @@ const H5AC_class_t H5AC_BT2_HDR[1] = {{ "v2 B-tree header", /* Metadata client name (for debugging) */ H5FD_MEM_BTREE, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5B2__cache_hdr_get_load_size, /* 'get_load_size' callback */ + H5B2__cache_hdr_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5B2__cache_hdr_verify_chksum, /* 'verify_chksum' callback */ H5B2__cache_hdr_deserialize, /* 'deserialize' callback */ H5B2__cache_hdr_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -115,7 +120,9 @@ const H5AC_class_t H5AC_BT2_INT[1] = {{ "v2 B-tree internal node", /* Metadata client name (for debugging) */ H5FD_MEM_BTREE, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5B2__cache_int_get_load_size, /* 'get_load_size' callback */ + H5B2__cache_int_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5B2__cache_int_verify_chksum, /* 'verify_chksum' callback */ H5B2__cache_int_deserialize, /* 'deserialize' callback */ H5B2__cache_int_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -131,7 +138,9 @@ const H5AC_class_t H5AC_BT2_LEAF[1] = {{ "v2 B-tree leaf node", /* Metadata client name (for debugging) */ H5FD_MEM_BTREE, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5B2__cache_leaf_get_load_size, /* 'get_load_size' callback */ + H5B2__cache_leaf_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5B2__cache_leaf_verify_chksum, /* 'verify_chksum' callback */ H5B2__cache_leaf_deserialize, /* 'deserialize' callback */ H5B2__cache_leaf_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -154,7 +163,7 @@ const H5AC_class_t H5AC_BT2_LEAF[1] = {{ /*------------------------------------------------------------------------- - * Function: H5B2__cache_hdr_get_load_size + * Function: H5B2__cache_hdr_get_initial_load_size * * Purpose: Compute the size of the data structure on disk. * @@ -167,21 +176,58 @@ const H5AC_class_t H5AC_BT2_LEAF[1] = {{ *------------------------------------------------------------------------- */ static herr_t -H5B2__cache_hdr_get_load_size(const void *_udata, size_t *image_len) +H5B2__cache_hdr_get_initial_load_size(void *_udata, size_t *image_len) { - const H5B2_hdr_cache_ud_t *udata = (const H5B2_hdr_cache_ud_t *)_udata; /* User data for callback */ + H5B2_hdr_cache_ud_t *udata = (H5B2_hdr_cache_ud_t *)_udata; /* User data for callback */ FUNC_ENTER_STATIC_NOERR /* Check arguments */ HDassert(udata); + HDassert(udata->f); HDassert(image_len); /* Set the image length size */ *image_len = H5B2_HEADER_SIZE_FILE(udata->f); FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5B2__cache_hdr_get_load_size() */ +} /* end H5B2__cache_hdr_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5B2__cache_hdr_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5B2__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5B2__cache_hdr_verify_chksum() */ /*------------------------------------------------------------------------- @@ -208,7 +254,6 @@ H5B2__cache_hdr_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, H5B2_subid_t id; /* ID of B-tree class, as found in file */ uint16_t depth; /* Depth of B-tree */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ H5B2_hdr_t *ret_value = NULL; /* Return value */ @@ -254,19 +299,14 @@ H5B2__cache_hdr_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, UINT16DECODE(image, hdr->root.node_nrec); H5F_DECODE_LENGTH(udata->f, image, hdr->root.all_nrec); + /* checksum verification already done in verify_chksum cb */ + /* Metadata checksum */ UINT32DECODE(image, stored_chksum); /* Sanity check */ HDassert((size_t)(image - (const uint8_t *)_image) == hdr->hdr_size); - /* Compute checksum on entire header */ - computed_chksum = H5_checksum_metadata(_image, (hdr->hdr_size - H5B2_SIZEOF_CHKSUM), 0); - - /* Verify checksum */ - if(stored_chksum != computed_chksum) - HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "incorrect metadata checksum for v2 B-tree header") - /* Initialize B-tree header info */ cparam.cls = H5B2_client_class_g[id]; if(H5B2__hdr_init(hdr, &cparam, udata->ctx_udata, depth) < 0) @@ -426,7 +466,7 @@ done: /*------------------------------------------------------------------------- - * Function: H5B2__cache_int_get_load_size + * Function: H5B2__cache_int_get_initial_load_size * * Purpose: Compute the size of the data structure on disk. * @@ -439,9 +479,9 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5B2__cache_int_get_load_size(const void *_udata, size_t *image_len) +H5B2__cache_int_get_initial_load_size(void *_udata, size_t *image_len) { - const H5B2_internal_cache_ud_t *udata = (const H5B2_internal_cache_ud_t *)_udata; /* User data for callback */ + H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* User data for callback */ FUNC_ENTER_STATIC_NOERR @@ -454,7 +494,49 @@ H5B2__cache_int_get_load_size(const void *_udata, size_t *image_len) *image_len = udata->hdr->node_size; FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5B2__cache_int_get_load_size() */ +} /* end H5B2__cache_int_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5B2__cache_int_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5B2__cache_int_verify_chksum(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* Pointer to user data */ + size_t chk_size; /* Exact size of the node with checksum at the end */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + HDassert(udata); + + /* Internal node prefix header + records + child pointer triplets: size with checksum at the end */ + chk_size = H5B2_INT_PREFIX_SIZE + (udata->nrec * udata->hdr->rrec_size) + ((size_t)(udata->nrec + 1) * H5B2_INT_POINTER_SIZE(udata->hdr, udata->depth)); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, chk_size, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5B2__cache_int_verify_chksum() */ /*------------------------------------------------------------------------- @@ -481,7 +563,6 @@ H5B2__cache_int_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, uint8_t *native; /* Pointer to native record info */ H5B2_node_ptr_t *int_node_ptr; /* Pointer to node pointer info */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ unsigned u; /* Local index variable */ H5B2_internal_t *ret_value = NULL; /* Return value */ @@ -555,8 +636,7 @@ H5B2__cache_int_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, int_node_ptr++; } /* end for */ - /* Compute checksum on internal node */ - computed_chksum = H5_checksum_metadata(_image, (size_t)(image - (const uint8_t *)_image), 0); + /* checksum verification already done in verify_chksum cb */ /* Metadata checksum */ UINT32DECODE(image, stored_chksum); @@ -564,10 +644,6 @@ H5B2__cache_int_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, /* Sanity check parsing */ HDassert((size_t)(image - (const uint8_t *)_image) <= len); - /* Verify checksum */ - if(stored_chksum != computed_chksum) - HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "incorrect metadata checksum for v2 internal node") - /* Set return value */ ret_value = internal; @@ -733,7 +809,7 @@ done: /*------------------------------------------------------------------------- - * Function: H5B2__cache_leaf_get_load_size + * Function: H5B2__cache_leaf_get_initial_load_size * * Purpose: Compute the size of the data structure on disk. * @@ -746,9 +822,9 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5B2__cache_leaf_get_load_size(const void *_udata, size_t *image_len) +H5B2__cache_leaf_get_initial_load_size(void *_udata, size_t *image_len) { - const H5B2_leaf_cache_ud_t *udata = (const H5B2_leaf_cache_ud_t *)_udata; /* User data for callback */ + H5B2_leaf_cache_ud_t *udata = (H5B2_leaf_cache_ud_t *)_udata; /* User data for callback */ FUNC_ENTER_STATIC_NOERR @@ -761,7 +837,49 @@ H5B2__cache_leaf_get_load_size(const void *_udata, size_t *image_len) *image_len = udata->hdr->node_size; FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5B2__cache_leaf_get_load_size() */ +} /* end H5B2__cache_leaf_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5B2__cache_leaf_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5B2__cache_leaf_verify_chksum(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5B2_internal_cache_ud_t *udata = (H5B2_internal_cache_ud_t *)_udata; /* Pointer to user data */ + size_t chk_size; /* Exact size of the node with checksum at the end */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + HDassert(udata); + + /* Leaf node prefix header + records: size with checksum at the end */ + chk_size = H5B2_LEAF_PREFIX_SIZE + (udata->nrec * udata->hdr->rrec_size); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, chk_size, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5B2__cache_leaf_verify_chksum() */ /*------------------------------------------------------------------------- @@ -787,7 +905,6 @@ H5B2__cache_leaf_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ uint8_t *native; /* Pointer to native keys */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ unsigned u; /* Local index variable */ H5B2_leaf_t *ret_value = NULL; /* Return value */ @@ -841,8 +958,7 @@ H5B2__cache_leaf_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, native += udata->hdr->cls->nrec_size; } /* end for */ - /* Compute checksum on leaf node */ - computed_chksum = H5_checksum_metadata(_image, (size_t)(image - (const uint8_t *)_image), 0); + /* checksum verification already done in verify_chksum cb */ /* Metadata checksum */ UINT32DECODE(image, stored_chksum); @@ -850,10 +966,6 @@ H5B2__cache_leaf_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, /* Sanity check parsing */ HDassert((size_t)(image - (const uint8_t *)_image) <= udata->hdr->node_size); - /* Verify checksum */ - if(stored_chksum != computed_chksum) - HGOTO_ERROR(H5E_BTREE, H5E_BADVALUE, NULL, "incorrect metadata checksum for v2 leaf node") - /* Sanity check */ HDassert((size_t)(image - (const uint8_t *)_image) <= len); diff --git a/src/H5Bcache.c b/src/H5Bcache.c index 44c5e62..b2be829 100644 --- a/src/H5Bcache.c +++ b/src/H5Bcache.c @@ -54,13 +54,13 @@ /********************/ /* Metadata cache callbacks */ -static herr_t H5B__get_load_size(const void *udata, size_t *image_len); -static void *H5B__deserialize(const void *image, size_t len, void *udata, +static herr_t H5B__cache_get_initial_load_size(void *udata, size_t *image_len); +static void *H5B__cache_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); -static herr_t H5B__image_len(const void *thing, size_t *image_len); -static herr_t H5B__serialize(const H5F_t *f, void *image, size_t len, +static herr_t H5B__cache_image_len(const void *thing, size_t *image_len); +static herr_t H5B__cache_serialize(const H5F_t *f, void *image, size_t len, void *thing); -static herr_t H5B__free_icr(void *thing); +static herr_t H5B__cache_free_icr(void *thing); /*********************/ @@ -73,13 +73,15 @@ const H5AC_class_t H5AC_BT[1] = {{ "v1 B-tree", /* Metadata client name (for debugging) */ H5FD_MEM_BTREE, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5B__get_load_size, /* 'get_load_size' callback */ - H5B__deserialize, /* 'deserialize' callback */ - H5B__image_len, /* 'image_len' callback */ + H5B__cache_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + NULL, /* 'verify_chksum' callback */ + H5B__cache_deserialize, /* 'deserialize' callback */ + H5B__cache_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ - H5B__serialize, /* 'serialize' callback */ + H5B__cache_serialize, /* 'serialize' callback */ NULL, /* 'notify' callback */ - H5B__free_icr, /* 'free_icr' callback */ + H5B__cache_free_icr, /* 'free_icr' callback */ NULL, /* 'fsf_size' callback */ }}; @@ -90,7 +92,7 @@ const H5AC_class_t H5AC_BT[1] = {{ /*------------------------------------------------------------------------- - * Function: H5B__get_load_size + * Function: H5B__cache_get_initial_load_size * * Purpose: Compute the size of the data structure on disk. * @@ -103,9 +105,9 @@ const H5AC_class_t H5AC_BT[1] = {{ *------------------------------------------------------------------------- */ static herr_t -H5B__get_load_size(const void *_udata, size_t *image_len) +H5B__cache_get_initial_load_size(void *_udata, size_t *image_len) { - const H5B_cache_ud_t *udata = (const H5B_cache_ud_t *)_udata; /* User data for callback */ + H5B_cache_ud_t *udata = (H5B_cache_ud_t *)_udata; /* User data for callback */ H5B_shared_t *shared; /* Pointer to shared B-tree info */ FUNC_ENTER_STATIC_NOERR @@ -122,11 +124,11 @@ H5B__get_load_size(const void *_udata, size_t *image_len) *image_len = shared->sizeof_rnode; FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5B__get_load_size() */ +} /* end H5B__cache_get_initial_load_size() */ /*------------------------------------------------------------------------- - * Function: H5B__deserialize + * Function: H5B__cache_deserialize * * Purpose: Deserialize the data structure from disk. * @@ -140,7 +142,7 @@ H5B__get_load_size(const void *_udata, size_t *image_len) *------------------------------------------------------------------------- */ static void * -H5B__deserialize(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata, +H5B__cache_deserialize(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata, hbool_t H5_ATTR_UNUSED *dirty) { H5B_t *bt = NULL; /* Pointer to the deserialized B-tree node */ @@ -229,11 +231,11 @@ done: HDONE_ERROR(H5E_BTREE, H5E_CANTFREE, NULL, "unable to destroy B-tree node") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5B__deserialize() */ +} /* end H5B__cache_deserialize() */ /*------------------------------------------------------------------------- - * Function: H5B__image_len + * Function: H5B__cache_image_len * * Purpose: Compute the size of the data structure on disk. * @@ -246,7 +248,7 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5B__image_len(const void *_thing, size_t *image_len) +H5B__cache_image_len(const void *_thing, size_t *image_len) { const H5B_t *bt = (const H5B_t *)_thing; /* Pointer to the B-tree node */ H5B_shared_t *shared; /* Pointer to shared B-tree info */ @@ -265,11 +267,11 @@ H5B__image_len(const void *_thing, size_t *image_len) *image_len = shared->sizeof_rnode; FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5B__image_len() */ +} /* end H5B__cache_image_len() */ /*------------------------------------------------------------------------- - * Function: H5B__serialize + * Function: H5B__cache_serialize * * Purpose: Serialize the data structure for writing to disk. * @@ -282,7 +284,7 @@ H5B__image_len(const void *_thing, size_t *image_len) *------------------------------------------------------------------------- */ static herr_t -H5B__serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, +H5B__cache_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, void *_thing) { H5B_t *bt = (H5B_t *)_thing; /* Pointer to the B-tree node */ @@ -351,11 +353,11 @@ H5B__serialize(const H5F_t *f, void *_image, size_t H5_ATTR_UNUSED len, done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5B__serialize() */ +} /* end H5B__cache_serialize() */ /*------------------------------------------------------------------------- - * Function: H5B__free_icr + * Function: H5B__cache_free_icr * * Purpose: Destroy/release an "in core representation" of a data structure * @@ -368,7 +370,7 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5B__free_icr(void *thing) +H5B__cache_free_icr(void *thing) { herr_t ret_value = SUCCEED; /* Return value */ @@ -383,5 +385,5 @@ H5B__free_icr(void *thing) done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5B__free_icr() */ +} /* end H5B__cache_free_icr() */ diff --git a/src/H5C.c b/src/H5C.c index a1477d4..147489b 100644 --- a/src/H5C.c +++ b/src/H5C.c @@ -167,6 +167,9 @@ static herr_t H5C__mark_flush_dep_dirty(H5C_cache_entry_t * entry); static herr_t H5C__mark_flush_dep_clean(H5C_cache_entry_t * entry); +static herr_t H5C__verify_len_eoa(H5F_t *f, const H5C_class_t * type, + haddr_t addr, size_t *len, hbool_t actual); + static herr_t H5C__generate_image(const H5F_t *f, H5C_t * cache_ptr, H5C_cache_entry_t *entry_ptr, hid_t dxpl_id); @@ -6136,6 +6139,70 @@ done: /*------------------------------------------------------------------------- * + * Function: H5C__verify_len_eoa + * + * Purpose: Verify that 'len' does not exceed eoa when 'actual' is + * false i.e. 'len" is the initial speculative length from + * get_load_size callback with null image pointer. + * If exceed, adjust 'len' accordingly. + * + * Verify that 'len' should not exceed eoa when 'actual' is + * true i.e. 'len' is the actual length from get_load_size + * callback with non-null image pointer. + * If exceed, return error. + * + * Return: FAIL if error is detected, SUCCEED otherwise. + * + * Programmer: Vailin Choi + * 9/6/15 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5C__verify_len_eoa(H5F_t *f, const H5C_class_t *type, haddr_t addr, + size_t *len, hbool_t actual) +{ + H5FD_mem_t cooked_type; /* Modified type, accounting for switching global heaps */ + haddr_t eoa; /* End-of-allocation in the file */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* if type == H5FD_MEM_GHEAP, H5F_block_read() forces + * type to H5FD_MEM_DRAW via its call to H5F__accum_read(). + * Thus we do the same for purposes of computing the EOA + * for sanity checks. + */ + cooked_type = (type->mem_type == H5FD_MEM_GHEAP) ? H5FD_MEM_DRAW : type->mem_type; + + /* Get the file's end-of-allocation value */ + eoa = H5F_get_eoa(f, cooked_type); + if(!H5F_addr_defined(eoa)) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "invalid EOA address for file") + + /* Check for bad address in general */ + if(H5F_addr_gt(addr, eoa)) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "address of object past end of allocation") + + /* Check if the amount of data to read will be past the EOA */ + if(H5F_addr_gt((addr + *len), eoa)) { + if(actual) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "actual len exceeds EOA.") + else + /* Trim down the length of the metadata */ + *len = (size_t)(eoa - addr); + } /* end if */ + + if(*len <= 0) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "len not positive after adjustment for EOA.") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5C__verify_len_eoa() */ + + +/*------------------------------------------------------------------------- + * * Function: H5C_load_entry * * Purpose: Attempt to load the entry at the specified disk address @@ -6163,7 +6230,7 @@ H5C_load_entry(H5F_t * f, void * udata) { hbool_t dirty = FALSE; /* Flag indicating whether thing was dirtied during deserialize */ - void * image = NULL; /* Buffer for disk image */ + uint8_t * image = NULL; /* Buffer for disk image */ void * thing = NULL; /* Pointer to thing loaded */ H5C_cache_entry_t *entry = NULL; /* Alias for thing loaded, as cache entry */ size_t len; /* Size of image in file */ @@ -6176,10 +6243,18 @@ H5C_load_entry(H5F_t * f, FUNC_ENTER_NOAPI_NOINIT + /* Sanity checks */ HDassert(f); HDassert(f->shared); HDassert(f->shared->cache); HDassert(type); + HDassert(H5F_addr_defined(addr)); + HDassert(type->get_initial_load_size); + if(type->flags & H5C__CLASS_SPECULATIVE_LOAD_FLAG) + HDassert(type->get_final_load_size); + else + HDassert(NULL == type->get_final_load_size); + HDassert(type->deserialize); /* Can't see how skip reads could be usefully combined with * the speculative read flag. Hence disallow. @@ -6187,59 +6262,19 @@ H5C_load_entry(H5F_t * f, HDassert(!((type->flags & H5C__CLASS_SKIP_READS) && (type->flags & H5C__CLASS_SPECULATIVE_LOAD_FLAG))); - HDassert(H5F_addr_defined(addr)); - HDassert(type->get_load_size); - HDassert(type->deserialize); - - /* Call the get_load_size callback, to retrieve the initial - * size of image - */ - if(type->get_load_size(udata, &len) < 0) + /* Call the get_initial_load_size callback, to retrieve the initial size of image */ + if(type->get_initial_load_size(udata, &len) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, NULL, "can't retrieve image size") - HDassert(len > 0); /* Check for possible speculative read off the end of the file */ - if(type->flags & H5C__CLASS_SPECULATIVE_LOAD_FLAG) { - - haddr_t eoa; /* End-of-allocation in the file */ - H5FD_mem_t cooked_type; - - /* if type == H5FD_MEM_GHEAP, H5F_block_read() forces - * type to H5FD_MEM_DRAW via its call to H5F__accum_read(). - * Thus we do the same for purposes of computing the eoa - * for sanity checks. - */ - cooked_type = (type->mem_type == H5FD_MEM_GHEAP) ? H5FD_MEM_DRAW : type->mem_type; - - /* Get the file's end-of-allocation value */ - eoa = H5F_get_eoa(f, cooked_type); - - HDassert(H5F_addr_defined(eoa)); - - /* Check for bad address in general */ - if ( H5F_addr_gt(addr, eoa) ) - HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "address of object past end of allocation") - - /* Check if the amount of data to read will be past the eoa */ - if( H5F_addr_gt((addr + len), eoa) ) { - - /* Trim down the length of the metadata */ - /* Note that for some cache clients, this will cause an - * assertion failure. JRM -- 8/29/14 - */ - len = (size_t)(eoa - addr); - } /* end if */ - - if ( len <= 0 ) - HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "len not positive after adjustment for EOA.") - - } /* end if */ + if(type->flags & H5C__CLASS_SPECULATIVE_LOAD_FLAG) + if(H5C__verify_len_eoa(f, type, addr, &len, FALSE) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "invalid len with respect to EOA") /* Allocate the buffer for reading the on-disk entry image */ - if(NULL == (image = H5MM_malloc(len + H5C_IMAGE_EXTRA_SPACE))) + if(NULL == (image = (uint8_t *)H5MM_malloc(len + H5C_IMAGE_EXTRA_SPACE))) HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "memory allocation failed for on disk image buffer.") - #if H5C_DO_MEMORY_SANITY_CHECKS HDmemcpy(image + len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); #endif /* H5C_DO_MEMORY_SANITY_CHECKS */ @@ -6255,150 +6290,144 @@ H5C_load_entry(H5F_t * f, /* Get the on-disk entry image */ if(0 == (type->flags & H5C__CLASS_SKIP_READS)) { + unsigned tries, max_tries; /* The # of read attempts */ + unsigned retries; /* The # of retries */ + htri_t chk_ret; /* return from verify_chksum callback */ + size_t actual_len = len; /* The actual length, after speculative reads have been resolved */ + uint64_t nanosec = 1; /* # of nanoseconds to sleep between retries */ + void *new_image; /* Pointer to image */ + hbool_t len_changed = TRUE; /* Whether to re-check speculative entries */ + + /* Get the # of read attempts */ + max_tries = tries = H5F_GET_READ_ATTEMPTS(f); + + /* + * This do/while loop performs the following till the metadata checksum + * is correct or the file's number of allowed read attempts are reached. + * --read the metadata + * --determine the actual size of the metadata + * --perform checksum verification + */ + do { + if(actual_len != len) { + if(NULL == (new_image = H5MM_realloc(image, len + H5C_IMAGE_EXTRA_SPACE))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "image null after H5MM_realloc()") + image = (uint8_t *)new_image; +#if H5C_DO_MEMORY_SANITY_CHECKS + HDmemcpy(image + len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); +#endif /* H5C_DO_MEMORY_SANITY_CHECKS */ + } /* end if */ + #ifdef H5_HAVE_PARALLEL - if(!coll_access || 0 == mpi_rank) { + if(!coll_access || 0 == mpi_rank) { #endif /* H5_HAVE_PARALLEL */ - - if(H5F_block_read(f, type->mem_type, addr, len, dxpl_id, image) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_READERROR, NULL, "Can't read image*") - + if(H5F_block_read(f, type->mem_type, addr, len, dxpl_id, image) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_READERROR, NULL, "Can't read image*") #ifdef H5_HAVE_PARALLEL - } /* end if */ - - /* if the collective metadata read optimization is turned on, - * bcast the metadata read from process 0 to all ranks in the file - * communicator - */ - if(coll_access) { - int buf_size; + } /* end if */ + /* if the collective metadata read optimization is turned on, + * bcast the metadata read from process 0 to all ranks in the file + * communicator + */ + if(coll_access) { + int buf_size; - H5_CHECKED_ASSIGN(buf_size, int, len, size_t); - if(MPI_SUCCESS != (mpi_code = MPI_Bcast(image, buf_size, MPI_BYTE, 0, comm))) - HMPI_GOTO_ERROR(NULL, "MPI_Bcast failed", mpi_code) - } /* end if */ + H5_CHECKED_ASSIGN(buf_size, int, len, size_t); + if(MPI_SUCCESS != (mpi_code = MPI_Bcast(image, buf_size, MPI_BYTE, 0, comm))) + HMPI_GOTO_ERROR(NULL, "MPI_Bcast failed", mpi_code) + } /* end if */ #endif /* H5_HAVE_PARALLEL */ - } /* end if */ - - /* Deserialize the on-disk image into the native memory form */ - if(NULL == (thing = type->deserialize(image, len, udata, &dirty))) - HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "Can't deserialize image") - - /* If the client's cache has an image_len callback, check it */ - if(type->image_len) { - size_t new_len; /* New size of on-disk image */ - - /* set magic and type field in *entry_ptr. While the image_len - * callback shouldn't touch the cache specific fields, it may check - * these fields to ensure that it it has received the expected - * value. - * - * Note that this initialization is repeated below on the off - * chance that we had to re-try the deserialization. - */ - entry = (H5C_cache_entry_t *)thing; - entry->magic = H5C__H5C_CACHE_ENTRY_T_MAGIC; - entry->type = type; - - /* Get the actual image size for the thing */ - if(type->image_len(thing, &new_len) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, NULL, "can't retrieve image length") - - if(new_len == 0) - HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "image length is 0") - - if(new_len != len) { - - if (type->flags & H5C__CLASS_SPECULATIVE_LOAD_FLAG) { - - void *new_image; /* Buffer for disk image */ - - /* Adjust the size of the image to match new_len */ - if(NULL == (new_image = H5MM_realloc(image, - new_len + H5C_IMAGE_EXTRA_SPACE))) - - HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "image null after H5MM_realloc()") - - image = new_image; + /* If the entry could be read speculatively and the length is still + * changing, check for updating the actual size + */ + if((type->flags & H5C__CLASS_SPECULATIVE_LOAD_FLAG) && len_changed) { + /* Retrieve the actual length */ + actual_len = len; + if(type->get_final_load_size(image, len, udata, &actual_len) < 0) + continue; /* Transfer control to while() and count towards retries */ + + /* Check for the length changing */ + if(actual_len != len) { + /* Verify that the length isn't past the EOA for the file */ + if(H5C__verify_len_eoa(f, type, addr, &actual_len, TRUE) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "actual_len exceeds EOA.") + + /* Expand buffer to new size */ + if(NULL == (new_image = H5MM_realloc(image, actual_len + H5C_IMAGE_EXTRA_SPACE))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "image null after H5MM_realloc()") + image = (uint8_t *)new_image; #if H5C_DO_MEMORY_SANITY_CHECKS - HDmemcpy(((uint8_t *)image) + new_len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); + HDmemcpy(image + actual_len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); #endif /* H5C_DO_MEMORY_SANITY_CHECKS */ - /* If the thing's image needs to be bigger for a speculatively - * loaded thing, free the thing and retry with new length - */ - if (new_len > len) { - - /* Release previous (possibly partially initialized) - * thing. Note that we must set entry->magic to - * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC and set one or - * two other fields before the call to free_icr - * so as to avoid sanity check failures. - */ - entry->magic = H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC; - - entry->addr = addr; - - if ( type->free_icr(thing) < 0 ) - - HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, NULL, "free_icr callback failed") - + if(actual_len > len) { #ifdef H5_HAVE_PARALLEL - if(!coll_access || 0 == mpi_rank) { + if(!coll_access || 0 == mpi_rank) { #endif /* H5_HAVE_PARALLEL */ - - /* Go get the on-disk image again */ - if(H5F_block_read(f, type->mem_type, addr, - new_len, dxpl_id, image) < 0) - HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "Can't read image") - + /* If the thing's image needs to be bigger for a speculatively + * loaded thing, go get the on-disk image again (the extra portion). + */ + if(H5F_block_read(f, type->mem_type, addr + len, actual_len - len, dxpl_id, image + len) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "can't read image") #ifdef H5_HAVE_PARALLEL - } - /* if the collective metadata read optimization is turned on, - bcast the metadata read from process 0 to all ranks in the file - communicator */ - if(coll_access) { - int buf_size; - - H5_CHECKED_ASSIGN(buf_size, int, new_len, size_t); - if(MPI_SUCCESS != (mpi_code = MPI_Bcast(image, buf_size, MPI_BYTE, 0, comm))) - HMPI_GOTO_ERROR(NULL, "MPI_Bcast failed", mpi_code) - } /* end if */ + } + /* If the collective metadata read optimization is turned on, + * Bcast the metadata read from process 0 to all ranks in the file + * communicator */ + if(coll_access) { + int buf_size; + + H5_CHECKED_ASSIGN(buf_size, int, actual_len - len, size_t); + if(MPI_SUCCESS != (mpi_code = MPI_Bcast(image + len, buf_size, MPI_BYTE, 0, comm))) + HMPI_GOTO_ERROR(NULL, "MPI_Bcast failed", mpi_code) + } /* end if */ #endif /* H5_HAVE_PARALLEL */ + } /* end if */ + } /* end if (actual_len != len) */ + else { + /* The length has stabilized */ + len_changed = FALSE; - /* Deserialize on-disk image into native memory form again */ - if(NULL == (thing = type->deserialize(image, new_len, udata, &dirty))) - HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "Can't deserialize image") + /* Set the final length */ + len = actual_len; + } /* else */ + } /* end if */ -#ifndef NDEBUG - { - size_t new_new_len; + /* If there's no way to verify the checksum for a piece of metadata + * (usually because there's no checksum in the file), leave now + */ + if(type->verify_chksum == NULL) + break; - /* Get the actual image size for the thing again. Note - * that since this is a new thing, we have to set - * the magic and type fields again so as to avoid - * failing sanity checks. - */ - entry = (H5C_cache_entry_t *)thing; - entry->magic = H5C__H5C_CACHE_ENTRY_T_MAGIC; - entry->type = type; + /* Verify the checksum for the metadata image */ + if((chk_ret = type->verify_chksum(image, actual_len, udata)) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, NULL, "failure from verify_chksum callback") + if(chk_ret == TRUE) + break; - type->image_len(thing, &new_new_len); - HDassert(new_new_len == new_len); - } /* end block */ -#endif /* NDEBUG */ - } /* end if (new_len > len) */ + /* Sleep for some time */ + H5_nanosleep(nanosec); + nanosec *= 2; /* Double the sleep time next time */ + } while(--tries); - /* Retain adjusted size */ - len = new_len; + /* Check for too many tries */ + if(tries == 0) + HGOTO_ERROR(H5E_CACHE, H5E_READERROR, NULL, "incorrect metadatda checksum after all read attempts") - } else { /* throw an error */ + /* Calculate and track the # of retries */ + retries = max_tries - tries; + if(retries) /* Does not track 0 retry */ + if(H5F_track_metadata_read_retries(f, (unsigned)type->mem_type, retries) < 0) + HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, NULL, "cannot track read tries = %u ", retries) - HGOTO_ERROR(H5E_CACHE, H5E_UNSUPPORTED, NULL, \ - "size of non-speculative object changed") - } - } /* end if (new_len != len) */ - } /* end if */ + /* Set the final length (in case it wasn't set earlier) */ + len = actual_len; + } /* end if !H5C__CLASS_SKIP_READS */ + + /* Deserialize the on-disk image into the native memory form */ + if(NULL == (thing = type->deserialize(image, len, udata, &dirty))) + HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "Can't deserialize image") entry = (H5C_cache_entry_t *)thing; @@ -6480,7 +6509,7 @@ done: if(thing && type->free_icr(thing) < 0) HDONE_ERROR(H5E_CACHE, H5E_CANTFLUSH, NULL, "free_icr callback failed") if(image) - image = H5MM_xfree(image); + image = (uint8_t *)H5MM_xfree(image); } /* end if */ FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Cepoch.c b/src/H5Cepoch.c index eacb247..3726aa1 100644 --- a/src/H5Cepoch.c +++ b/src/H5Cepoch.c @@ -63,8 +63,12 @@ * epochs so that they can be evicted from the cache. * ****************************************************************************/ -static herr_t H5C__epoch_marker_get_load_size(const void *udata_ptr, +static herr_t H5C__epoch_marker_get_initial_load_size(void *udata_ptr, size_t *image_len_ptr); +static herr_t H5C__epoch_marker_get_final_load_size(const void *image_ptr, + size_t image_len_ptr, void *udata_ptr, size_t *actual_len); +static htri_t H5C__epoch_marker_verify_chksum(const void *image_ptr, + size_t len, void *udata_ptr); static void * H5C__epoch_marker_deserialize(const void * image_ptr, size_t len, void * udata, hbool_t * dirty_ptr); static herr_t H5C__epoch_marker_image_len(const void * thing, @@ -101,7 +105,9 @@ const H5C_class_t H5C__epoch_marker_class = /* name = */ "epoch marker", /* mem_type = */ H5FD_MEM_DEFAULT, /* value doesn't matter */ /* flags = */ H5C__CLASS_NO_FLAGS_SET, - /* get_load_size = */ H5C__epoch_marker_get_load_size, + /* get_initial_load_size = */ H5C__epoch_marker_get_initial_load_size, + /* get_final_load_size = */ H5C__epoch_marker_get_final_load_size, + /* verify_chksum = */ H5C__epoch_marker_verify_chksum, /* deserialize = */ H5C__epoch_marker_deserialize, /* image_len = */ H5C__epoch_marker_image_len, /* pre_serialize = */ H5C__epoch_marker_pre_serialize, @@ -123,7 +129,7 @@ const H5C_class_t H5C__epoch_marker_class = static herr_t -H5C__epoch_marker_get_load_size(const void H5_ATTR_UNUSED *udata_ptr, +H5C__epoch_marker_get_initial_load_size(void H5_ATTR_UNUSED *udata_ptr, size_t H5_ATTR_UNUSED *image_len_ptr) { FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ @@ -131,7 +137,32 @@ H5C__epoch_marker_get_load_size(const void H5_ATTR_UNUSED *udata_ptr, HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); FUNC_LEAVE_NOAPI(FAIL) -} /* end H5C__epoch_marker_get_load_size() */ +} /* end H5C__epoch_marker_get_initial_load_size() */ + + +static herr_t +H5C__epoch_marker_get_final_load_size(const void H5_ATTR_UNUSED *image_ptr, + size_t H5_ATTR_UNUSED image_len, void H5_ATTR_UNUSED *udata_ptr, + size_t H5_ATTR_UNUSED *actual_len) +{ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ + + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); + + FUNC_LEAVE_NOAPI(FAIL) +} /* end H5C__epoch_marker_final_get_load_size() */ + + +static htri_t +H5C__epoch_marker_verify_chksum(const void H5_ATTR_UNUSED *image_ptr, size_t H5_ATTR_UNUSED len, + void H5_ATTR_UNUSED *udata_ptr) +{ + FUNC_ENTER_STATIC_NOERR /* Yes, even though this pushes an error on the stack */ + + HERROR(H5E_CACHE, H5E_SYSTEM, "called unreachable fcn."); + + FUNC_LEAVE_NOAPI(FALSE) +} /* end H5C__epoch_marker_verify_chksum() */ static void * diff --git a/src/H5Cprivate.h b/src/H5Cprivate.h index c4037b0..c03e2e7 100644 --- a/src/H5Cprivate.h +++ b/src/H5Cprivate.h @@ -323,50 +323,124 @@ typedef struct H5C_t H5C_t; * code. When it is set, writes of buffers prepared by the * serialize callback will be skipped. * - * GET_LOAD_SIZE: Pointer to the 'get load size' function. + * GET_INITIAL_LOAD_SIZE: Pointer to the 'get initial load size' function. * - * This function must be able to determine the size of the disk image of - * a metadata cache entry, given the 'udata' that will be passed to the - * 'deserialize' callback. + * This function determines the size based on the information in the + * parameter "udata" or an initial speculative guess. The size is + * returned in the parameter "image_len_ptr". * - * Note that if either the H5C__CLASS_SPECULATIVE_LOAD_FLAG is set, the disk image size - * returned by this callback is a first guess. - * In other cases, the value returned should be the correct - * size of the entry. + * For an entry with H5C__CLASS_NO_FLAGS_SET: + * This function returns in "image_len_ptr" the on disk size of the + * entry. + * + * For an entry with H5C__CLASS_SPECULATIVE_LOAD_FLAG: + * This function returns in "image_len_ptr" an initial guess of the + * entry's on disk size. This many bytes will be loaded from + * the file and then passed to 'get_final_load_size' callback + * for the actual (final) image length to be determined. * - * The typedef for the deserialize callback is as follows: + * The typedef for the get_initial_load_size callback is as follows: * - * typedef herr_t (*H5C_get_load_size_func_t)(void *udata_ptr, - * size_t *image_len_ptr); + * typedef herr_t (*H5C_get_initial_load_size_func_t)(void *udata_ptr, + * size_t *image_len_ptr); * - * The parameters of the deserialize callback are as follows: + * The parameters of the get_initial_load_size callback are as follows: * * udata_ptr: Pointer to user data provided in the protect call, which - * will also be passed through to the deserialize callback. + * will also be passed through to the 'get_final_load_size', + * 'verify_chksum', and 'deserialize' callbacks. * - * image_len_ptr: Pointer to the location in which the length in bytes - * of the in file image to be deserialized is to be returned. + * image_len_ptr: Pointer to the length in bytes of the in-file image to + * be deserialized is to be returned. * * This value is used by the cache to determine the size of * the disk image for the metadata, in order to read the disk * image from the file. - * + * * Processing in the get_load_size function should proceed as follows: * - * If successful, the function will place the length of the on disk - * image associated with supplied user data in *image_len_ptr, and - * then return SUCCEED. + * If successful, the function will place the length in the *image_len_ptr + * associated with supplied user data and then return SUCCEED. * * On failure, the function must return FAIL and push error information * onto the error stack with the error API routines, without modifying - * the value pointed to by the image_len_ptr. + * the value pointed to by image_len_ptr. + * + * + * GET_FINAL_LOAD_SIZE: Pointer to the 'get final load size' function. + * + * This function determines the final size of a speculatively loaded + * metadata cache entry based on the parameter "image" and the "udata" + * parameters. This callback _must_ be implemented for cache clients + * which set the H5C__CLASS_SPECULATIVE_LOAD_FLAG and must return the + * actual length of on-disk image after being called once. + * + * This function might deserialize the needed metadata information to + * determine the actual size. The size is returned in the parameter + * "actual_len_ptr". + * + * The typedef for the get_load_size callback is as follows: + * + * typedef herr_t (*H5C_get_final_load_size_func_t)(const void *image_ptr, + * size_t image_len, + * void *udata_ptr, + * size_t *actual_len_ptr); + * + * The parameters of the get_load_size callback are as follows: + * + * image_ptr: Pointer to a buffer containing the (possibly partial) + * metadata read in. + * + * image_len: The length in bytes of the (possibly partial) in-file image + * to be queried for an actual length. + * + * udata_ptr: Pointer to user data provided in the protect call, which + * will also be passed through to the 'verify_chksum' and + * 'deserialize' callbacks. + * + * actual_len_ptr: Pointer to the location containing the actual length + * of the metadata entry on disk. + * + * Processing in the get_final_load_size function should proceed as follows: + * + * If successful, the function will place the length in the *actual_len_ptr + * associated with supplied image and/or user data and then return SUCCEED. + * + * On failure, the function must return FAIL and push error information + * onto the error stack with the error API routines, without modifying + * the value pointed to by actual_len_ptr. + * + * + * VERIFY_CHKSUM: Pointer to the verify_chksum function. + * + * This function verifies the checksum computed for the metadata is + * the same as the checksum stored in the metadata. + * + * It computes the checksum based on the metadata stored in the + * parameter "image_ptr" and the actual length of the metadata in the + * parameter "len" which is obtained from the "get_load_size" callback. + * + * The typedef for the verify_chksum callback is as follows: + * + * typedef htri_t (*H5C_verify_chksum_func_t)(const void *image_ptr, + * size_t len, + * void *udata_ptr); + * + * The parameters of the verify_chksum callback are as follows: + * + * image_ptr: Pointer to a buffer containing the metadata read in. + * + * len: The actual length of the metadata. + * + * udata_ptr: Pointer to user data. * * * DESERIALIZE: Pointer to the deserialize function. * - * This function must be able to read a buffer containing the on disk - * image of a metadata cache entry, allocate and load the equivalent - * in core representation, and return a pointer to that representation. + * This function must be able to deserialize a buffer containing the + * on-disk image of a metadata cache entry, allocate and initialize the + * equivalent in core representation, and return a pointer to that + * representation. * * The typedef for the deserialize callback is as follows: * @@ -399,17 +473,17 @@ typedef struct H5C_t H5C_t; * Processing in the deserialize function should proceed as follows: * * If the image contains valid data, and is of the correct length, - * the deserialize function must allocate space for an in core - * representation of that data, load the contents of the image into - * the space allocated for the in core representation, and return + * the deserialize function must allocate space for an in-core + * representation of that data, deserialize the contents of the image + * into the space allocated for the in-core representation, and return * a pointer to the in core representation. Observe that an * instance of H5C_cache_entry_t must be the first item in this * representation. The cache will initialize it after the callback * returns. * - * Note that the structure of the in core representation is otherwise + * Note that the structure of the in-core representation is otherwise * up to the cache client. All that is required is that the pointer - * returned be sufficient for the clients purposes when it is returned + * returned be sufficient for the client's purposes when it is returned * on a protect call. * * If the deserialize function has to clean up file corruption @@ -421,30 +495,6 @@ typedef struct H5C_t H5C_t; * buffer length, malloc failure, etc.) the function must return NULL and * push error information on the error stack with the error API routines. * - * Exceptions to the above: - * - * If the H5C__CLASS_SPECULATIVE_LOAD_FLAG is set, the buffer supplied - * to the function need not be currect on the first invocation of the - * callback in any single attempt to load the entry. - * - * In this case, if the buffer is larger than necessary, the function - * should load the entry as described above and not flag an error due - * to the oversized buffer. The cache will correct its mis-apprehension - * of the entry size with a subsequent call to the image_len callback. - * - * If the buffer is too small, and this is the first deserialize call - * in the entry load operation, the function should not flag an error. - * Instead, it must compute the correct size of the entry, allocate an - * in core representation and initialize it to the extent that an - * immediate call to the image len callback will return the correct - * image size. - * - * In this case, when the deserialize callback returns, the cache will - * call the image length callback, realize that the supplied buffer was - * too small, discard the returned in core representation, allocate - * and load a new buffer of the correct size from file, and then call - * the deserialize callback again. - * * * IMAGE_LEN: Pointer to the image length callback. * @@ -473,6 +523,7 @@ typedef struct H5C_t H5C_t; * onto the error stack with the error API routines, and return without * modifying the values pointed to by the image_len_ptr parameter. * + * * PRE_SERIALIZE: Pointer to the pre-serialize callback. * * The pre-serialize callback is invoked by the metadata cache before @@ -818,8 +869,10 @@ typedef enum H5C_notify_action_t { } H5C_notify_action_t; /* Cache client callback function pointers */ -typedef herr_t (*H5C_get_load_size_func_t)(const void *udata_ptr, - size_t *image_len_ptr); +typedef herr_t (*H5C_get_initial_load_size_func_t)(void *udata_ptr, size_t *image_len_ptr); +typedef herr_t (*H5C_get_final_load_size_func_t)(const void *image_ptr, + size_t image_len, void *udata_ptr, size_t *actual_len_ptr); +typedef htri_t (*H5C_verify_chksum_func_t)(const void *image_ptr, size_t len, void *udata_ptr); typedef void *(*H5C_deserialize_func_t)(const void *image_ptr, size_t len, void *udata_ptr, hbool_t *dirty_ptr); typedef herr_t (*H5C_image_len_func_t)(const void *thing, size_t *image_len_ptr); @@ -838,7 +891,9 @@ typedef struct H5C_class_t { const char * name; H5FD_mem_t mem_type; unsigned flags; - H5C_get_load_size_func_t get_load_size; + H5C_get_initial_load_size_func_t get_initial_load_size; + H5C_get_final_load_size_func_t get_final_load_size; + H5C_verify_chksum_func_t verify_chksum; H5C_deserialize_func_t deserialize; H5C_image_len_func_t image_len; H5C_pre_serialize_func_t pre_serialize; diff --git a/src/H5EAcache.c b/src/H5EAcache.c index 4a53b5c..4210b07 100644 --- a/src/H5EAcache.c +++ b/src/H5EAcache.c @@ -73,7 +73,8 @@ /********************/ /* Metadata cache (H5AC) callbacks */ -static herr_t H5EA__cache_hdr_get_load_size(const void *udata, size_t *image_len); +static herr_t H5EA__cache_hdr_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5EA__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5EA__cache_hdr_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5EA__cache_hdr_image_len(const void *thing, size_t *image_len); @@ -81,7 +82,8 @@ static herr_t H5EA__cache_hdr_serialize(const H5F_t *f, void *image, size_t len, void *thing); static herr_t H5EA__cache_hdr_free_icr(void *thing); -static herr_t H5EA__cache_iblock_get_load_size(const void *udata, size_t *image_len); +static herr_t H5EA__cache_iblock_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5EA__cache_iblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5EA__cache_iblock_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5EA__cache_iblock_image_len(const void *thing, size_t *image_len); @@ -90,7 +92,8 @@ static herr_t H5EA__cache_iblock_serialize(const H5F_t *f, void *image, size_t l static herr_t H5EA__cache_iblock_notify(H5AC_notify_action_t action, void *thing); static herr_t H5EA__cache_iblock_free_icr(void *thing); -static herr_t H5EA__cache_sblock_get_load_size(const void *udata, size_t *image_len); +static herr_t H5EA__cache_sblock_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5EA__cache_sblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5EA__cache_sblock_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5EA__cache_sblock_image_len(const void *thing, size_t *image_len); @@ -99,7 +102,8 @@ static herr_t H5EA__cache_sblock_serialize(const H5F_t *f, void *image, size_t l static herr_t H5EA__cache_sblock_notify(H5AC_notify_action_t action, void *thing); static herr_t H5EA__cache_sblock_free_icr(void *thing); -static herr_t H5EA__cache_dblock_get_load_size(const void *udata, size_t *image_len); +static herr_t H5EA__cache_dblock_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5EA__cache_dblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5EA__cache_dblock_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5EA__cache_dblock_image_len(const void *thing, size_t *image_len); @@ -109,7 +113,8 @@ static herr_t H5EA__cache_dblock_notify(H5AC_notify_action_t action, void *thing static herr_t H5EA__cache_dblock_free_icr(void *thing); static herr_t H5EA__cache_dblock_fsf_size(const void *thing, size_t *fsf_size); -static herr_t H5EA__cache_dblk_page_get_load_size(const void *udata, size_t *image_len); +static herr_t H5EA__cache_dblk_page_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5EA__cache_dblk_page_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5EA__cache_dblk_page_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5EA__cache_dblk_page_image_len(const void *thing, @@ -130,7 +135,9 @@ const H5AC_class_t H5AC_EARRAY_HDR[1] = {{ "Extensible Array Header", /* Metadata client name (for debugging) */ H5FD_MEM_EARRAY_HDR, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5EA__cache_hdr_get_load_size, /* 'get_load_size' callback */ + H5EA__cache_hdr_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5EA__cache_hdr_verify_chksum, /* 'verify_chksum' callback */ H5EA__cache_hdr_deserialize, /* 'deserialize' callback */ H5EA__cache_hdr_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -146,7 +153,9 @@ const H5AC_class_t H5AC_EARRAY_IBLOCK[1] = {{ "Extensible Array Index Block", /* Metadata client name (for debugging) */ H5FD_MEM_EARRAY_IBLOCK, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5EA__cache_iblock_get_load_size, /* 'get_load_size' callback */ + H5EA__cache_iblock_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5EA__cache_iblock_verify_chksum, /* 'verify_chksum' callback */ H5EA__cache_iblock_deserialize, /* 'deserialize' callback */ H5EA__cache_iblock_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -162,7 +171,9 @@ const H5AC_class_t H5AC_EARRAY_SBLOCK[1] = {{ "Extensible Array Super Block", /* Metadata client name (for debugging) */ H5FD_MEM_EARRAY_SBLOCK, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5EA__cache_sblock_get_load_size, /* 'get_load_size' callback */ + H5EA__cache_sblock_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5EA__cache_sblock_verify_chksum, /* 'verify_chksum' callback */ H5EA__cache_sblock_deserialize, /* 'deserialize' callback */ H5EA__cache_sblock_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -178,7 +189,9 @@ const H5AC_class_t H5AC_EARRAY_DBLOCK[1] = {{ "Extensible Array Data Block", /* Metadata client name (for debugging) */ H5FD_MEM_EARRAY_DBLOCK, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5EA__cache_dblock_get_load_size, /* 'get_load_size' callback */ + H5EA__cache_dblock_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5EA__cache_dblock_verify_chksum, /* 'verify_chksum' callback */ H5EA__cache_dblock_deserialize, /* 'deserialize' callback */ H5EA__cache_dblock_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -194,7 +207,9 @@ const H5AC_class_t H5AC_EARRAY_DBLK_PAGE[1] = {{ "Extensible Array Data Block Page", /* Metadata client name (for debugging) */ H5FD_MEM_EARRAY_DBLK_PAGE, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5EA__cache_dblk_page_get_load_size, /* 'get_load_size' callback */ + H5EA__cache_dblk_page_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5EA__cache_dblk_page_verify_chksum, /* 'verify_chksum' callback */ H5EA__cache_dblk_page_deserialize, /* 'deserialize' callback */ H5EA__cache_dblk_page_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -217,7 +232,7 @@ const H5AC_class_t H5AC_EARRAY_DBLK_PAGE[1] = {{ /*------------------------------------------------------------------------- - * Function: H5EA__cache_hdr_get_load_size + * Function: H5EA__cache_hdr_get_initial_load_size * * Purpose: Compute the size of the data structure on disk. * @@ -231,21 +246,54 @@ const H5AC_class_t H5AC_EARRAY_DBLK_PAGE[1] = {{ */ BEGIN_FUNC(STATIC, NOERR, herr_t, SUCCEED, -, -H5EA__cache_hdr_get_load_size(const void *_udata, size_t *image_len)) +H5EA__cache_hdr_get_initial_load_size(void *_udata, size_t *image_len)) /* Local variables */ - const H5EA_hdr_cache_ud_t *udata = (const H5EA_hdr_cache_ud_t *)_udata; /* User data for callback */ + H5EA_hdr_cache_ud_t *udata = (H5EA_hdr_cache_ud_t *)_udata; /* User data for callback */ /* Check arguments */ HDassert(udata); HDassert(udata->f); - HDassert(H5F_addr_defined(udata->addr)); HDassert(image_len); /* Set the image length size */ *image_len = (size_t)H5EA_HEADER_SIZE_FILE(udata->f); -END_FUNC(STATIC) /* end H5EA__cache_hdr_get_load_size() */ +END_FUNC(STATIC) /* end H5EA__cache_hdr_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5EA__cache_hdr_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +htri_t, TRUE, -, +H5EA__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)) + + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + +END_FUNC(STATIC) /* end H5EA__cache_hdr_verify_chksum() */ /*------------------------------------------------------------------------- @@ -273,7 +321,6 @@ H5EA__cache_hdr_deserialize(const void *_image, size_t len, void *_udata, H5EA_hdr_cache_ud_t *udata = (H5EA_hdr_cache_ud_t *)_udata; const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ /* Check arguments */ HDassert(image); @@ -348,17 +395,11 @@ H5EA__cache_hdr_deserialize(const void *_image, size_t len, void *_udata, /* (allow for checksum not decoded yet) */ HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5EA_SIZEOF_CHKSUM)); - /* Compute checksum on entire header */ - /* (including the filter information, if present) */ - computed_chksum = H5_checksum_metadata(_image, (size_t)(image - (const uint8_t *)_image), 0); + /* checksum verification already done in verify_chksum cb */ /* Metadata checksum */ UINT32DECODE(image, stored_chksum); - /* Verify checksum */ - if(stored_chksum != computed_chksum) - H5E_THROW(H5E_BADVALUE, "incorrect metadata checksum for extensible array header") - /* Sanity check */ HDassert((size_t)(image - (const uint8_t *)_image) == len); @@ -510,7 +551,7 @@ END_FUNC(STATIC) /* end H5EA__cache_hdr_free_icr() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_iblock_get_load_size + * Function: H5EA__cache_iblock_get_initial_load_size * * Purpose: Compute the size of the data structure on disk. * @@ -524,11 +565,11 @@ END_FUNC(STATIC) /* end H5EA__cache_hdr_free_icr() */ */ BEGIN_FUNC(STATIC, NOERR, herr_t, SUCCEED, -, -H5EA__cache_iblock_get_load_size(const void *_udata, size_t *image_len)) +H5EA__cache_iblock_get_initial_load_size(void *_udata, size_t *image_len)) /* Local variables */ - const H5EA_hdr_t *hdr = (const H5EA_hdr_t *)_udata; /* User data for callback */ - H5EA_iblock_t iblock; /* Fake index block for computing size */ + H5EA_hdr_t *hdr = (H5EA_hdr_t *)_udata; /* User data for callback */ + H5EA_iblock_t iblock; /* Fake index block for computing size */ /* Check arguments */ HDassert(hdr); @@ -544,7 +585,41 @@ H5EA__cache_iblock_get_load_size(const void *_udata, size_t *image_len)) /* Set the image length size */ *image_len = (size_t)H5EA_IBLOCK_SIZE(&iblock); -END_FUNC(STATIC) /* end H5EA__cache_iblock_get_load_size() */ +END_FUNC(STATIC) /* end H5EA__cache_iblock_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5EA__cache_iblock_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +htri_t, TRUE, -, +H5EA__cache_iblock_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)) + + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + +END_FUNC(STATIC) /* end H5EA__cache_iblock_verify_chksum() */ /*------------------------------------------------------------------------- @@ -571,7 +646,6 @@ H5EA__cache_iblock_deserialize(const void *_image, size_t len, H5EA_hdr_t *hdr = (H5EA_hdr_t *)_udata; /* User data for callback */ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ haddr_t arr_addr; /* Address of array header in the file */ size_t u; /* Local index variable */ @@ -635,8 +709,7 @@ H5EA__cache_iblock_deserialize(const void *_image, size_t len, /* Save the index block's size */ iblock->size = len; - /* Compute checksum on index block */ - computed_chksum = H5_checksum_metadata((const uint8_t *)_image, (size_t)(image - (const uint8_t *)_image), 0); + /* checksum verification already done in verify_chksum cb */ /* Metadata checksum */ UINT32DECODE(image, stored_chksum); @@ -644,10 +717,6 @@ H5EA__cache_iblock_deserialize(const void *_image, size_t len, /* Sanity check */ HDassert((size_t)(image - (const uint8_t *)_image) == iblock->size); - /* Verify checksum */ - if(stored_chksum != computed_chksum) - H5E_THROW(H5E_BADVALUE, "incorrect metadata checksum for extensible array index block") - /* Set return value */ ret_value = iblock; @@ -863,7 +932,7 @@ END_FUNC(STATIC) /* end H5EA__cache_iblock_free_icr() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_sblock_get_load_size + * Function: H5EA__cache_sblock_get_initial_load_size * * Purpose: Compute the size of the data structure on disk. * @@ -877,11 +946,11 @@ END_FUNC(STATIC) /* end H5EA__cache_iblock_free_icr() */ */ BEGIN_FUNC(STATIC, NOERR, herr_t, SUCCEED, -, -H5EA__cache_sblock_get_load_size(const void *_udata, size_t *image_len)) +H5EA__cache_sblock_get_initial_load_size(void *_udata, size_t *image_len)) /* Local variables */ - const H5EA_sblock_cache_ud_t *udata = (const H5EA_sblock_cache_ud_t *)_udata; /* User data */ - H5EA_sblock_t sblock; /* Fake super block for computing size */ + H5EA_sblock_cache_ud_t *udata = (H5EA_sblock_cache_ud_t *)_udata; /* User data */ + H5EA_sblock_t sblock; /* Fake super block for computing size */ /* Check arguments */ HDassert(udata); @@ -917,7 +986,41 @@ H5EA__cache_sblock_get_load_size(const void *_udata, size_t *image_len)) /* Set the image length size */ *image_len = (size_t)H5EA_SBLOCK_SIZE(&sblock); -END_FUNC(STATIC) /* end H5EA__cache_sblock_get_load_size() */ +END_FUNC(STATIC) /* end H5EA__cache_sblock_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5EA__cache_sblock_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +htri_t, TRUE, -, +H5EA__cache_sblock_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)) + + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + +END_FUNC(STATIC) /* end H5EA__cache_sblock_verify_chksum() */ /*------------------------------------------------------------------------- @@ -944,7 +1047,6 @@ H5EA__cache_sblock_deserialize(const void *_image, size_t len, H5EA_sblock_cache_ud_t *udata = (H5EA_sblock_cache_ud_t *)_udata; /* User data */ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ haddr_t arr_addr; /* Address of array header in the file */ size_t u; /* Local index variable */ @@ -1005,8 +1107,7 @@ H5EA__cache_sblock_deserialize(const void *_image, size_t len, /* Save the super block's size */ sblock->size = len; - /* Compute checksum on super block */ - computed_chksum = H5_checksum_metadata(_image, (size_t)(image - (const uint8_t *)_image), 0); + /* checksum verification already done in verify_chksum cb */ /* Metadata checksum */ UINT32DECODE(image, stored_chksum); @@ -1014,10 +1115,6 @@ H5EA__cache_sblock_deserialize(const void *_image, size_t len, /* Sanity check */ HDassert((size_t)(image - (const uint8_t *)_image) == sblock->size); - /* Verify checksum */ - if(stored_chksum != computed_chksum) - H5E_THROW(H5E_BADVALUE, "incorrect metadata checksum for extensible array super block") - /* Set return value */ ret_value = sblock; @@ -1235,7 +1332,7 @@ END_FUNC(STATIC) /* end H5EA__cache_sblock_free_icr() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_dblock_get_load_size + * Function: H5EA__cache_dblock_get_initial_load_size * * Purpose: Compute the size of the data structure on disk. * @@ -1249,11 +1346,11 @@ END_FUNC(STATIC) /* end H5EA__cache_sblock_free_icr() */ */ BEGIN_FUNC(STATIC, NOERR, herr_t, SUCCEED, -, -H5EA__cache_dblock_get_load_size(const void *_udata, size_t *image_len)) +H5EA__cache_dblock_get_initial_load_size(void *_udata, size_t *image_len)) /* Local variables */ - const H5EA_dblock_cache_ud_t *udata = (const H5EA_dblock_cache_ud_t *)_udata; /* User data */ - H5EA_dblock_t dblock; /* Fake data block for computing size */ + H5EA_dblock_cache_ud_t *udata = (H5EA_dblock_cache_ud_t *)_udata; /* User data */ + H5EA_dblock_t dblock; /* Fake data block for computing size */ /* Check arguments */ HDassert(udata); @@ -1290,7 +1387,41 @@ H5EA__cache_dblock_get_load_size(const void *_udata, size_t *image_len)) else *image_len = H5EA_DBLOCK_PREFIX_SIZE(&dblock); -END_FUNC(STATIC) /* end H5EA__cache_dblock_get_load_size() */ +END_FUNC(STATIC) /* end H5EA__cache_dblock_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5EA__cache_dblock_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +htri_t, TRUE, -, +H5EA__cache_dblock_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)) + + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + +END_FUNC(STATIC) /* end H5EA__cache_sblock_verify_chksum() */ /*------------------------------------------------------------------------- @@ -1317,7 +1448,6 @@ H5EA__cache_dblock_deserialize(const void *_image, size_t len, H5EA_dblock_cache_ud_t *udata = (H5EA_dblock_cache_ud_t *)_udata; /* User data */ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ haddr_t arr_addr; /* Address of array header in the file */ /* Check arguments */ @@ -1377,8 +1507,7 @@ H5EA__cache_dblock_deserialize(const void *_image, size_t len, /* (Note: This is not the same as the image length, for paged data blocks) */ dblock->size = H5EA_DBLOCK_SIZE(dblock); - /* Compute checksum on data block */ - computed_chksum = H5_checksum_metadata(_image, (size_t)(image - (const uint8_t *)_image), 0); + /* checksum verification already done in verify_chksum cb */ /* Metadata checksum */ UINT32DECODE(image, stored_chksum); @@ -1386,10 +1515,6 @@ H5EA__cache_dblock_deserialize(const void *_image, size_t len, /* Sanity check */ HDassert((size_t)(image - (const uint8_t *)_image) == len); - /* Verify checksum */ - if(stored_chksum != computed_chksum) - H5E_THROW(H5E_BADVALUE, "incorrect metadata checksum for extensible array data block") - /* Set return value */ ret_value = dblock; @@ -1655,7 +1780,7 @@ END_FUNC(STATIC) /* end H5EA__cache_dblock_fsf_size() */ /*------------------------------------------------------------------------- - * Function: H5EA__cache_dblk_page_get_load_size + * Function: H5EA__cache_dblk_page_get_initial_load_size * * Purpose: Compute the size of the data structure on disk. * @@ -1669,10 +1794,10 @@ END_FUNC(STATIC) /* end H5EA__cache_dblock_fsf_size() */ */ BEGIN_FUNC(STATIC, NOERR, herr_t, SUCCEED, -, -H5EA__cache_dblk_page_get_load_size(const void *_udata, size_t *image_len)) +H5EA__cache_dblk_page_get_initial_load_size(void *_udata, size_t *image_len)) /* Local variables */ - const H5EA_dblk_page_cache_ud_t *udata = (const H5EA_dblk_page_cache_ud_t *)_udata; /* User data */ + H5EA_dblk_page_cache_ud_t *udata = (H5EA_dblk_page_cache_ud_t *)_udata; /* User data */ /* Check arguments */ HDassert(udata); @@ -1680,9 +1805,44 @@ H5EA__cache_dblk_page_get_load_size(const void *_udata, size_t *image_len)) HDassert(udata->parent); HDassert(image_len); + /* Set the image length size */ *image_len = (size_t)H5EA_DBLK_PAGE_SIZE(udata->hdr); -END_FUNC(STATIC) /* end H5EA__cache_dblk_page_get_load_size() */ +END_FUNC(STATIC) /* end H5EA__cache_dblk_page_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5EA__cache_dblk_page_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +htri_t, TRUE, -, +H5EA__cache_dblk_page_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)) + + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + +END_FUNC(STATIC) /* end H5EA__cache_dblk_page_verify_chksum() */ /*------------------------------------------------------------------------- @@ -1709,7 +1869,6 @@ H5EA__cache_dblk_page_deserialize(const void *_image, size_t len, H5EA_dblk_page_cache_ud_t *udata = (H5EA_dblk_page_cache_ud_t *)_udata; /* User data for loading data block page */ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ /* Sanity check */ HDassert(udata); @@ -1739,8 +1898,7 @@ H5EA__cache_dblk_page_deserialize(const void *_image, size_t len, /* Set the data block page's size */ dblk_page->size = len; - /* Compute checksum on data block page */ - computed_chksum = H5_checksum_metadata(_image, (size_t)(image - (const uint8_t *)_image), 0); + /* checksum verification already done in verify_chksum cb */ /* Metadata checksum */ UINT32DECODE(image, stored_chksum); @@ -1748,10 +1906,6 @@ H5EA__cache_dblk_page_deserialize(const void *_image, size_t len, /* Sanity check */ HDassert((size_t)(image - (const uint8_t *)_image) == dblk_page->size); - /* Verify checksum */ - if(stored_chksum != computed_chksum) - H5E_THROW(H5E_BADVALUE, "incorrect metadata checksum for extensible array data block page") - /* Set return value */ ret_value = dblk_page; diff --git a/src/H5FAcache.c b/src/H5FAcache.c index 9574c9f..82b87dd 100644 --- a/src/H5FAcache.c +++ b/src/H5FAcache.c @@ -71,7 +71,8 @@ /********************/ /* Metadata cache (H5AC) callbacks */ -static herr_t H5FA__cache_hdr_get_load_size(const void *udata, size_t *image_len); +static herr_t H5FA__cache_hdr_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5FA__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5FA__cache_hdr_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5FA__cache_hdr_image_len(const void *thing, size_t *image_len); @@ -79,7 +80,8 @@ static herr_t H5FA__cache_hdr_serialize(const H5F_t *f, void *image, size_t len, void *thing); static herr_t H5FA__cache_hdr_free_icr(void *thing); -static herr_t H5FA__cache_dblock_get_load_size(const void *udata, size_t *image_len); +static herr_t H5FA__cache_dblock_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5FA__cache_dblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5FA__cache_dblock_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5FA__cache_dblock_image_len(const void *thing, size_t *image_len); @@ -88,7 +90,8 @@ static herr_t H5FA__cache_dblock_serialize(const H5F_t *f, void *image, size_t l static herr_t H5FA__cache_dblock_free_icr(void *thing); static herr_t H5FA__cache_dblock_fsf_size(const void *thing, size_t *fsf_size); -static herr_t H5FA__cache_dblk_page_get_load_size(const void *udata, size_t *image_len); +static herr_t H5FA__cache_dblk_page_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5FA__cache_dblk_page_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5FA__cache_dblk_page_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5FA__cache_dblk_page_image_len(const void *thing, size_t *image_len); @@ -107,7 +110,9 @@ const H5AC_class_t H5AC_FARRAY_HDR[1] = {{ "Fixed-array Header", /* Metadata client name (for debugging) */ H5FD_MEM_FARRAY_HDR, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5FA__cache_hdr_get_load_size, /* 'get_load_size' callback */ + H5FA__cache_hdr_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5FA__cache_hdr_verify_chksum, /* 'verify_chksum' callback */ H5FA__cache_hdr_deserialize, /* 'deserialize' callback */ H5FA__cache_hdr_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -123,7 +128,9 @@ const H5AC_class_t H5AC_FARRAY_DBLOCK[1] = {{ "Fixed Array Data Block", /* Metadata client name (for debugging) */ H5FD_MEM_FARRAY_DBLOCK, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5FA__cache_dblock_get_load_size, /* 'get_load_size' callback */ + H5FA__cache_dblock_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5FA__cache_dblock_verify_chksum, /* 'verify_chksum' callback */ H5FA__cache_dblock_deserialize, /* 'deserialize' callback */ H5FA__cache_dblock_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -139,7 +146,9 @@ const H5AC_class_t H5AC_FARRAY_DBLK_PAGE[1] = {{ "Fixed Array Data Block Page", /* Metadata client name (for debugging) */ H5FD_MEM_FARRAY_DBLK_PAGE, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5FA__cache_dblk_page_get_load_size, /* 'get_load_size' callback */ + H5FA__cache_dblk_page_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5FA__cache_dblk_page_verify_chksum, /* 'verify_chksum' callback */ H5FA__cache_dblk_page_deserialize, /* 'deserialize' callback */ H5FA__cache_dblk_page_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -162,7 +171,7 @@ const H5AC_class_t H5AC_FARRAY_DBLK_PAGE[1] = {{ /*------------------------------------------------------------------------- - * Function: H5FA__cache_hdr_get_load_size + * Function: H5FA__cache_hdr_get_initial_load_size * * Purpose: Compute the size of the data structure on disk. * @@ -176,10 +185,10 @@ const H5AC_class_t H5AC_FARRAY_DBLK_PAGE[1] = {{ */ BEGIN_FUNC(STATIC, NOERR, herr_t, SUCCEED, -, -H5FA__cache_hdr_get_load_size(const void *_udata, size_t *image_len)) +H5FA__cache_hdr_get_initial_load_size(void *_udata, size_t *image_len)) /* Local variables */ - const H5FA_hdr_cache_ud_t *udata = (const H5FA_hdr_cache_ud_t *)_udata; /* User data for callback */ + H5FA_hdr_cache_ud_t *udata = (H5FA_hdr_cache_ud_t *)_udata; /* User data for callback */ /* Check arguments */ HDassert(udata); @@ -189,7 +198,41 @@ H5FA__cache_hdr_get_load_size(const void *_udata, size_t *image_len)) /* Set the image length size */ *image_len = (size_t)H5FA_HEADER_SIZE_FILE(udata->f); -END_FUNC(STATIC) /* end H5FA__cache_hdr_get_load_size() */ +END_FUNC(STATIC) /* end H5FA__cache_hdr_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5FA__cache_hdr_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +htri_t, TRUE, -, +H5FA__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)) + + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + +END_FUNC(STATIC) /* end H5FA__cache_hdr_verify_chksum() */ /*------------------------------------------------------------------------- @@ -217,7 +260,6 @@ H5FA__cache_hdr_deserialize(const void *_image, size_t len, H5FA_hdr_cache_ud_t *udata = (H5FA_hdr_cache_ud_t *)_udata; const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ /* Check arguments */ HDassert(udata); @@ -281,9 +323,7 @@ H5FA__cache_hdr_deserialize(const void *_image, size_t len, /* (allow for checksum not decoded yet) */ HDassert((size_t)(image - (const uint8_t *)_image) == (len - H5FA_SIZEOF_CHKSUM)); - /* Compute checksum on entire header */ - /* (including the filter information, if present) */ - computed_chksum = H5_checksum_metadata(_image, (size_t)(image - (const uint8_t *)_image), 0); + /* checksum verification already done in verify_chksum cb */ /* Metadata checksum */ UINT32DECODE(image, stored_chksum); @@ -291,10 +331,6 @@ H5FA__cache_hdr_deserialize(const void *_image, size_t len, /* Sanity check */ HDassert((size_t)(image - (const uint8_t *)_image) == len); - /* Verify checksum */ - if(stored_chksum != computed_chksum) - H5E_THROW(H5E_BADVALUE, "incorrect metadata checksum for fixed array header") - /* Finish initializing fixed array header */ if(H5FA__hdr_init(hdr, udata->ctx_udata) < 0) H5E_THROW(H5E_CANTINIT, "initialization failed for fixed array header") @@ -434,7 +470,7 @@ END_FUNC(STATIC) /* end H5FA__cache_hdr_free_icr() */ /*------------------------------------------------------------------------- - * Function: H5FA__cache_dblock_get_load_size + * Function: H5FA__cache_dblock_get_initial_load_size * * Purpose: Compute the size of the data structure on disk. * @@ -448,7 +484,7 @@ END_FUNC(STATIC) /* end H5FA__cache_hdr_free_icr() */ */ BEGIN_FUNC(STATIC, NOERR, herr_t, SUCCEED, -, -H5FA__cache_dblock_get_load_size(const void *_udata, size_t *image_len)) +H5FA__cache_dblock_get_initial_load_size(void *_udata, size_t *image_len)) /* Local variables */ H5FA_dblock_cache_ud_t *udata = (H5FA_dblock_cache_ud_t *)_udata; /* User data */ @@ -470,7 +506,6 @@ H5FA__cache_dblock_get_load_size(const void *_udata, size_t *image_len)) * dblock->npages * dblock->dblk_page_init_size */ - dblock.hdr = udata->hdr; dblk_page_nelmts = (size_t)1 << udata->hdr->cparam.max_dblk_page_nelmts_bits; if(udata->hdr->cparam.nelmts > dblk_page_nelmts) { @@ -484,7 +519,41 @@ H5FA__cache_dblock_get_load_size(const void *_udata, size_t *image_len)) else *image_len = (size_t)H5FA_DBLOCK_PREFIX_SIZE(&dblock); -END_FUNC(STATIC) /* end H5FA__cache_dblock_get_load_size() */ +END_FUNC(STATIC) /* end H5FA__cache_dblock_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5FA__cache_dblock_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +htri_t, TRUE, -, +H5FA__cache_dblock_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)) + + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + +END_FUNC(STATIC) /* end H5FA__cache_dblock_verify_chksum() */ /*------------------------------------------------------------------------- @@ -511,7 +580,6 @@ H5FA__cache_dblock_deserialize(const void *_image, size_t len, H5FA_dblock_cache_ud_t *udata = (H5FA_dblock_cache_ud_t *)_udata; /* User data for loading data block */ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ haddr_t arr_addr; /* Address of array header in the file */ /* Sanity check */ @@ -568,8 +636,7 @@ H5FA__cache_dblock_deserialize(const void *_image, size_t len, /* Set the data block's size */ dblock->size = H5FA_DBLOCK_SIZE(dblock); - /* Compute checksum on data block */ - computed_chksum = H5_checksum_metadata(_image, (size_t)(image - (const uint8_t *)_image), 0); + /* checksum verification already done in verify_chksum cb */ /* Metadata checksum */ UINT32DECODE(image, stored_chksum); @@ -577,10 +644,6 @@ H5FA__cache_dblock_deserialize(const void *_image, size_t len, /* Sanity check */ HDassert((size_t)(image - (const uint8_t *)_image) == len); - /* Verify checksum */ - if(stored_chksum != computed_chksum) - H5E_THROW(H5E_BADVALUE, "incorrect metadata checksum for fixed array data block") - /* Set return value */ ret_value = dblock; @@ -780,7 +843,7 @@ END_FUNC(STATIC) /* end H5FA__cache_dblock_fsf_size() */ /*------------------------------------------------------------------------- - * Function: H5FA__cache_dblk_page_get_load_size + * Function: H5FA__cache_dblk_page_get_initial_load_size * * Purpose: Compute the size of the data structure on disk. * @@ -794,10 +857,10 @@ END_FUNC(STATIC) /* end H5FA__cache_dblock_fsf_size() */ */ BEGIN_FUNC(STATIC, NOERR, herr_t, SUCCEED, -, -H5FA__cache_dblk_page_get_load_size(const void *_udata, size_t *image_len)) +H5FA__cache_dblk_page_get_initial_load_size(void *_udata, size_t *image_len)) /* Local variables */ - const H5FA_dblk_page_cache_ud_t *udata = (const H5FA_dblk_page_cache_ud_t *)_udata; /* User data */ + H5FA_dblk_page_cache_ud_t *udata = (H5FA_dblk_page_cache_ud_t *)_udata; /* User data */ /* Check arguments */ HDassert(udata); @@ -805,9 +868,44 @@ H5FA__cache_dblk_page_get_load_size(const void *_udata, size_t *image_len)) HDassert(udata->nelmts > 0); HDassert(image_len); + /* Set the image length size */ *image_len = (size_t)H5FA_DBLK_PAGE_SIZE(udata->hdr, udata->nelmts); -END_FUNC(STATIC) /* end H5FA__cache_dblk_page_get_load_size() */ +END_FUNC(STATIC) /* end H5FA__cache_dblk_page_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5FA__cache_dblk_page_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +BEGIN_FUNC(STATIC, NOERR, +htri_t, TRUE, -, +H5FA__cache_dblk_page_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)) + + /* Local variables */ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + +END_FUNC(STATIC) /* end H5FA__cache_dblk_page_verify_chksum() */ /*------------------------------------------------------------------------- @@ -834,7 +932,6 @@ H5FA__cache_dblk_page_deserialize(const void *_image, size_t len, H5FA_dblk_page_cache_ud_t *udata = (H5FA_dblk_page_cache_ud_t *)_udata; /* User data for loading data block page */ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ /* Sanity check */ HDassert(udata); @@ -864,8 +961,7 @@ H5FA__cache_dblk_page_deserialize(const void *_image, size_t len, /* Set the data block page's size */ dblk_page->size = len; - /* Compute checksum on data block */ - computed_chksum = H5_checksum_metadata(_image, (size_t)(image - (const uint8_t *)_image), 0); + /* checksum verification already done in verify_chksum cb */ /* Metadata checksum */ UINT32DECODE(image, stored_chksum); @@ -873,10 +969,6 @@ H5FA__cache_dblk_page_deserialize(const void *_image, size_t len, /* Sanity check */ HDassert((size_t)(image - (const uint8_t *)_image) == dblk_page->size); - /* Verify checksum */ - if(stored_chksum != computed_chksum) - H5E_THROW(H5E_BADVALUE, "incorrect metadata checksum for fixed array data block page") - /* Set return value */ ret_value = dblk_page; diff --git a/src/H5FScache.c b/src/H5FScache.c index b403a69..c1a9e0a 100644 --- a/src/H5FScache.c +++ b/src/H5FScache.c @@ -78,7 +78,8 @@ static herr_t H5FS__sinfo_serialize_sect_cb(void *_item, void H5_ATTR_UNUSED *ke static herr_t H5FS__sinfo_serialize_node_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata); /* Metadata cache callbacks */ -static herr_t H5FS__cache_hdr_get_load_size(const void *udata, size_t *image_len); +static herr_t H5FS__cache_hdr_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5FS__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5FS__cache_hdr_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5FS__cache_hdr_image_len(const void *thing, size_t *image_len); @@ -89,7 +90,8 @@ static herr_t H5FS__cache_hdr_serialize(const H5F_t *f, void *image, size_t len, void *thing); static herr_t H5FS__cache_hdr_free_icr(void *thing); -static herr_t H5FS__cache_sinfo_get_load_size(const void *udata, size_t *image_len); +static herr_t H5FS__cache_sinfo_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5FS__cache_sinfo_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5FS__cache_sinfo_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5FS__cache_sinfo_image_len(const void *thing, size_t *image_len); @@ -111,7 +113,9 @@ const H5AC_class_t H5AC_FSPACE_HDR[1] = {{ "Free Space Header", /* Metadata client name (for debugging) */ H5FD_MEM_FSPACE_HDR, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5FS__cache_hdr_get_load_size, /* 'get_load_size' callback */ + H5FS__cache_hdr_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5FS__cache_hdr_verify_chksum, /* 'verify_chksum' callback */ H5FS__cache_hdr_deserialize, /* 'deserialize' callback */ H5FS__cache_hdr_image_len, /* 'image_len' callback */ H5FS__cache_hdr_pre_serialize, /* 'pre_serialize' callback */ @@ -127,7 +131,9 @@ const H5AC_class_t H5AC_FSPACE_SINFO[1] = {{ "Free Space Section Info", /* Metadata client name (for debugging) */ H5FD_MEM_FSPACE_SINFO, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5FS__cache_sinfo_get_load_size, /* 'get_load_size' callback */ + H5FS__cache_sinfo_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5FS__cache_sinfo_verify_chksum, /* 'verify_chksum' callback */ H5FS__cache_sinfo_deserialize, /* 'deserialize' callback */ H5FS__cache_sinfo_image_len, /* 'image_len' callback */ H5FS__cache_sinfo_pre_serialize, /* 'pre_serialize' callback */ @@ -150,7 +156,7 @@ const H5AC_class_t H5AC_FSPACE_SINFO[1] = {{ /*------------------------------------------------------------------------- - * Function: H5FS__cache_hdr_get_load_size + * Function: H5FS__cache_hdr_get_initial_load_size * * Purpose: Compute the size of the data structure on disk. * @@ -163,9 +169,9 @@ const H5AC_class_t H5AC_FSPACE_SINFO[1] = {{ *------------------------------------------------------------------------- */ static herr_t -H5FS__cache_hdr_get_load_size(const void *_udata, size_t *image_len) +H5FS__cache_hdr_get_initial_load_size(void *_udata, size_t *image_len) { - const H5FS_hdr_cache_ud_t *udata = (const H5FS_hdr_cache_ud_t *)_udata; /* User-data for metadata cache callback */ + H5FS_hdr_cache_ud_t *udata = (H5FS_hdr_cache_ud_t *)_udata; /* User-data for metadata cache callback */ FUNC_ENTER_STATIC_NOERR @@ -178,7 +184,43 @@ H5FS__cache_hdr_get_load_size(const void *_udata, size_t *image_len) *image_len = (size_t)H5FS_HEADER_SIZE(udata->f); FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5FS__cache_hdr_get_load_size() */ +} /* end H5FS__cache_hdr_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5FS__cache_hdr_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +htri_t +H5FS__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FS__cache_hdr_verify_chksum() */ /*------------------------------------------------------------------------- @@ -206,7 +248,6 @@ H5FS__cache_hdr_deserialize(const void *_image, size_t len, void *_udata, H5FS_hdr_cache_ud_t *udata = (H5FS_hdr_cache_ud_t *)_udata; /* User data for callback */ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ unsigned nclasses; /* Number of section classes */ H5FS_t *ret_value = NULL; /* Return value */ @@ -279,8 +320,7 @@ H5FS__cache_hdr_deserialize(const void *_image, size_t len, void *_udata, /* Allocated size of serialized free space sections */ H5F_DECODE_LENGTH(udata->f, image, fspace->alloc_sect_size); - /* Compute checksum on indirect block */ - computed_chksum = H5_checksum_metadata(_image, (size_t)(image - (const uint8_t *)_image), 0); + /* checksum verification already done in verify_chksum cb */ /* Metadata checksum */ UINT32DECODE(image, stored_chksum); @@ -288,10 +328,6 @@ H5FS__cache_hdr_deserialize(const void *_image, size_t len, void *_udata, /* Sanity check */ HDassert((size_t)(image - (const uint8_t *)_image) <= len); - /* Verify checksum */ - if(stored_chksum != computed_chksum) - HGOTO_ERROR(H5E_FSPACE, H5E_BADVALUE, NULL, "incorrect metadata checksum for fractal heap indirect block") - /* Set return value */ ret_value = fspace; @@ -721,10 +757,6 @@ H5FS__cache_hdr_serialize(const H5F_t *f, void *_image, size_t len, FUNC_LEAVE_NOAPI(ret_value) } /* H5FS__cache_hdr_serialize() */ -/***************************************/ -/* no H5FS__cache_hdr_notify() function */ -/***************************************/ - /*------------------------------------------------------------------------- * Function: H5FS__cache_hdr_free_icr @@ -768,13 +800,9 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5FS__cache_hdr_free_icr() */ -/********************************************************/ -/* metadata cache callback definitions for section info */ -/********************************************************/ - /*------------------------------------------------------------------------- - * Function: H5FS__cache_sinfo_get_load_size() + * Function: H5FS__cache_sinfo_get_initial_load_size() * * Purpose: Compute the size of the on disk image of the free space * manager section info, and place this value in *image_len. @@ -788,10 +816,10 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5FS__cache_sinfo_get_load_size(const void *_udata, size_t *image_len) +H5FS__cache_sinfo_get_initial_load_size(void *_udata, size_t *image_len) { - const H5FS_t *fspace; /* free space manager */ - const H5FS_sinfo_cache_ud_t *udata = (const H5FS_sinfo_cache_ud_t *)_udata; /* User data for callback */ + const H5FS_t *fspace; /* free space manager */ + H5FS_sinfo_cache_ud_t *udata = (H5FS_sinfo_cache_ud_t *)_udata; /* User data for callback */ FUNC_ENTER_STATIC_NOERR @@ -802,10 +830,47 @@ H5FS__cache_sinfo_get_load_size(const void *_udata, size_t *image_len) HDassert(fspace->sect_size > 0); HDassert(image_len); + /* Set the image length size */ *image_len = (size_t)(fspace->sect_size); FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5FS__cache_sinfo_get_load_size() */ +} /* end H5FS__cache_sinfo_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5FS__cache_sinfo_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +htri_t +H5FS__cache_sinfo_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5FS__cache_sinfo_verify_chksum() */ /*------------------------------------------------------------------------- @@ -835,7 +900,6 @@ H5FS__cache_sinfo_deserialize(const void *_image, size_t len, void *_udata, size_t old_sect_size; /* Old section size */ const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ uint32_t stored_chksum; /* Stored metadata checksum */ - uint32_t computed_chksum; /* Computed metadata checksum */ void * ret_value = NULL; /* Return value */ FUNC_ENTER_STATIC @@ -942,16 +1006,11 @@ H5FS__cache_sinfo_deserialize(const void *_image, size_t len, void *_udata, HDassert(old_tot_space == fspace->tot_space); } /* end if */ - /* Compute checksum on indirect block */ - computed_chksum = H5_checksum_metadata((const uint8_t *)_image, (size_t)(image - (const uint8_t *)_image), 0); + /* checksum verification already done in verify_chksum cb */ /* Metadata checksum */ UINT32DECODE(image, stored_chksum); - /* Verify checksum */ - if(stored_chksum != computed_chksum) - HGOTO_ERROR(H5E_FSPACE, H5E_BADVALUE, NULL, "incorrect metadata checksum for fractal heap indirect block") - /* Sanity check */ HDassert((size_t)(image - (const uint8_t *)_image) == old_sect_size); diff --git a/src/H5Fint.c b/src/H5Fint.c index dab1900..dbaf3cc 100644 --- a/src/H5Fint.c +++ b/src/H5Fint.c @@ -686,6 +686,18 @@ H5F_new(H5F_file_t *shared, unsigned flags, hid_t fcpl_id, hid_t fapl_id, H5FD_t */ f->shared->use_tmp_space = !H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI); + /* Retrieve the # of read attempts here so that sohm in superblock will get the correct # of attempts */ + if(H5P_get(plist, H5F_ACS_METADATA_READ_ATTEMPTS_NAME, &f->shared->read_attempts) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, NULL, "can't get the # of read attempts") + + /* If no value for read attempts has been set, use the default */ + if(!f->shared->read_attempts) + f->shared->read_attempts = H5F_METADATA_READ_ATTEMPTS; + + /* Determine the # of bins for metdata read retries */ + if(H5F_set_retries(f) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "can't set retries and retries_nbins") + /* Get the metadata cache log location (if we're logging) */ { char *mdc_log_location = NULL; /* location of metadata cache log location */ @@ -780,6 +792,7 @@ H5F_dest(H5F_t *f, hid_t dxpl_id, hbool_t flush) HDassert(f->shared); if(1 == f->shared->nrefs) { + int actype; /* metadata cache type (enum value) */ H5F_io_info_t fio_info; /* I/O info for operation */ /* Flush at this point since the file will be closed. @@ -897,6 +910,11 @@ H5F_dest(H5F_t *f, hid_t dxpl_id, hbool_t flush) f->shared->mtab.child = (H5F_mount_t *)H5MM_xfree(f->shared->mtab.child); f->shared->mtab.nalloc = 0; + /* Clean up the metadata retries array */ + for(actype = 0; actype < (int)H5AC_NTYPES; actype++) + if(f->shared->retries[actype]) + f->shared->retries[actype] = (uint32_t *)H5MM_xfree(f->shared->retries[actype]); + /* Destroy shared file struct */ f->shared = (H5F_file_t *)H5FL_FREE(H5F_file_t, f->shared); @@ -2113,6 +2131,96 @@ done: /*------------------------------------------------------------------------- + * Function: H5F_track_metadata_read_retries + * + * Purpose: To track the # of a "retries" (log10) for a metadata item. + * This routine should be used only when: + * "retries" > 0 + * f->shared->read_attempts > 1 (does not have retry when 1) + * f->shared->retries_nbins > 0 (calculated based on f->shared->read_attempts) + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Vailin Choi; October 2013 + * + *------------------------------------------------------------------------- + */ +herr_t +H5F_track_metadata_read_retries(H5F_t *f, unsigned actype, unsigned retries) +{ + unsigned log_ind; /* Index to the array of retries based on log10 of retries */ + double tmp; /* Temporary value, to keep compiler quiet */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Sanity check */ + HDassert(f); + HDassert(f->shared->read_attempts > 1); + HDassert(f->shared->retries_nbins > 0); + HDassert(retries > 0); + HDassert(retries < f->shared->read_attempts); + HDassert(actype < H5AC_NTYPES); + + /* Allocate memory for retries */ + if(NULL == f->shared->retries[actype]) + if(NULL == (f->shared->retries[actype] = (uint32_t *)H5MM_calloc((size_t)f->shared->retries_nbins * sizeof(uint32_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Index to retries based on log10 */ + tmp = HDlog10((double)retries); + log_ind = (unsigned)tmp; + HDassert(log_ind < f->shared->retries_nbins); + + /* Increment the # of the "retries" */ + f->shared->retries[actype][log_ind]++; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5F_track_metadata_read_retries() */ + + +/*------------------------------------------------------------------------- + * Function: H5F_set_retries + * + * Purpose: To initialize data structures for read retries: + * --zero out "retries" + * --set up "retries_nbins" based on read_attempts + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Vailin Choi; November 2013 + * + *------------------------------------------------------------------------- + */ +herr_t +H5F_set_retries(H5F_t *f) +{ + double tmp; /* Temporary variable */ + + /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Sanity check */ + HDassert(f); + + /* Initialize the tracking for metadata read retries */ + HDmemset(f->shared->retries, 0, sizeof(f->shared->retries)); + + /* Initialize the # of bins for retries */ + f->shared->retries_nbins = 0; + if(f->shared->read_attempts > 1) { + tmp = HDlog10((double)(f->shared->read_attempts - 1)); + f->shared->retries_nbins = (unsigned)tmp + 1; + } + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5F_set_retries() */ + + +/*------------------------------------------------------------------------- * Function: H5F_object_flush_cb * * Purpose: To invoke the callback function for object flush that is set diff --git a/src/H5Fio.c b/src/H5Fio.c index 2ccd3f3..273ee74 100644 --- a/src/H5Fio.c +++ b/src/H5Fio.c @@ -282,3 +282,46 @@ done: FUNC_LEAVE_NOAPI(ret_value); } /* end H5F_evict_tagged_metadata */ + +/*------------------------------------------------------------------------- + * Function: H5F_get_checksums + * + * Purpose: Decode checksum stored in the buffer + * Calculate checksum for the data in the buffer + * + * Note: Assumes that the checksum is the last data in the buffer + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Vailin Choi + * Sept 2013 + * + *------------------------------------------------------------------------- + */ +herr_t +H5F_get_checksums(const uint8_t *buf, size_t buf_size, uint32_t *s_chksum/*out*/, uint32_t *c_chksum/*out*/) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check arguments */ + HDassert(buf); + HDassert(buf_size); + + /* Return the stored checksum */ + if(s_chksum) { + const uint8_t *chk_p; /* Pointer into raw data buffer */ + + /* Offset to the checksum in the buffer */ + chk_p = buf + buf_size - H5_SIZEOF_CHKSUM; + + /* Decode the checksum stored in the buffer */ + UINT32DECODE(chk_p, *s_chksum); + } /* end if */ + + /* Return the computed checksum for the buffer */ + if(c_chksum) + *c_chksum = H5_checksum_metadata(buf, buf_size - H5_SIZEOF_CHKSUM, 0); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5F_get_chksums() */ + diff --git a/src/H5Fpkg.h b/src/H5Fpkg.h index 8d7dcbd..e9c45f3 100644 --- a/src/H5Fpkg.h +++ b/src/H5Fpkg.h @@ -152,6 +152,9 @@ typedef struct H5F_superblock_cache_ud_t { unsigned btree_k[H5B_NUM_BTREE_ID]; /* B-tree key values for each type */ haddr_t stored_eof; /* End-of-file in file */ hbool_t drvrinfo_removed; /* Indicate if the driver info was removed */ + unsigned super_vers; /* Superblock version obtained in get_load_size callback. + * It will be used later in verify_chksum callback + */ } H5F_superblock_cache_ud_t; /* Structure for passing 'user data' to driver info block cache callbacks */ @@ -299,6 +302,11 @@ struct H5F_file_t { /* Metadata accumulator information */ H5F_meta_accum_t accum; /* Metadata accumulator info */ + /* Metadata retry info */ + unsigned read_attempts; /* The # of reads to try when reading metadata with checksum */ + unsigned retries_nbins; /* # of bins for each retries[] */ + uint32_t *retries[H5AC_NTYPES]; /* Track # of read retries for metdata items with checksum */ + /* Object flush info */ H5F_object_flush_t object_flush; /* Information for object flush callback */ }; diff --git a/src/H5Fprivate.h b/src/H5Fprivate.h index 35c7b5a..2aac18f 100644 --- a/src/H5Fprivate.h +++ b/src/H5Fprivate.h @@ -286,6 +286,7 @@ #define H5F_FILE_ID(F) ((F)->file_id) #define H5F_PARENT(F) ((F)->parent) #define H5F_NMOUNTS(F) ((F)->nmounts) +#define H5F_GET_READ_ATTEMPTS(F) ((F)->shared->read_attempts) #define H5F_DRIVER_ID(F) ((F)->shared->lf->driver_id) #define H5F_GET_FILENO(F,FILENUM) ((FILENUM) = (F)->shared->lf->fileno) #define H5F_HAS_FEATURE(F,FL) ((F)->shared->lf->feature_flags & (FL)) @@ -335,6 +336,7 @@ #define H5F_FILE_ID(F) (H5F_get_file_id(F)) #define H5F_PARENT(F) (H5F_get_parent(F)) #define H5F_NMOUNTS(F) (H5F_get_nmounts(F)) +#define H5F_GET_READ_ATTEMPTS(F) (H5F_get_read_attempts(F)) #define H5F_DRIVER_ID(F) (H5F_get_driver_id(F)) #define H5F_GET_FILENO(F,FILENUM) (H5F_get_fileno((F), &(FILENUM))) #define H5F_HAS_FEATURE(F,FL) (H5F_has_feature(F,FL)) @@ -467,6 +469,7 @@ #define H5F_ACS_MULTI_TYPE_NAME "multi_type" /* Data type in multi file driver */ #define H5F_ACS_LATEST_FORMAT_NAME "latest_format" /* 'Use latest format version' flag */ #define H5F_ACS_WANT_POSIX_FD_NAME "want_posix_fd" /* Internal: query the file descriptor from the core VFD, instead of the memory address */ +#define H5F_ACS_METADATA_READ_ATTEMPTS_NAME "metadata_read_attempts" /* # of metadata read attempts */ #define H5F_ACS_OBJECT_FLUSH_CB_NAME "object_flush_cb" /* Object flush callback */ #define H5F_ACS_EFC_SIZE_NAME "efc_size" /* Size of external file cache */ #define H5F_ACS_FILE_IMAGE_INFO_NAME "file_image_info" /* struct containing initial file image and callback info */ @@ -518,12 +521,19 @@ /* Default free space section threshold used by free-space managers */ #define H5F_FREE_SPACE_THRESHOLD_DEF 1 +/* Metadata read attempt values */ +#define H5F_METADATA_READ_ATTEMPTS 1 /* Default # of read attempts for non-SWMR access */ + /* Macros to define signatures of all objects in the file */ /* Size of signature information (on disk) */ /* (all on-disk signatures should be this length) */ #define H5_SIZEOF_MAGIC 4 +/* Size of checksum information (on disk) */ +/* (all on-disk checksums should be this length) */ +#define H5_SIZEOF_CHKSUM 4 + /* v1 B-tree node signature */ #define H5B_MAGIC "TREE" @@ -652,6 +662,7 @@ H5_DLL unsigned H5F_decr_nopen_objs(H5F_t *f); H5_DLL hid_t H5F_get_file_id(const H5F_t *f); H5_DLL H5F_t *H5F_get_parent(const H5F_t *f); H5_DLL unsigned H5F_get_nmounts(const H5F_t *f); +H5_DLL unsigned H5F_get_read_attempts(const H5F_t *f); H5_DLL hid_t H5F_get_access_plist(H5F_t *f, hbool_t app_ref); H5_DLL hid_t H5F_get_id(H5F_t *file, hbool_t app_ref); H5_DLL herr_t H5F_get_obj_count(const H5F_t *f, unsigned types, hbool_t app_ref, size_t *obj_id_count_ptr); @@ -716,6 +727,13 @@ H5_DLL herr_t H5F_block_write(const H5F_t *f, H5FD_mem_t type, haddr_t addr, H5_DLL herr_t H5F_flush_tagged_metadata(H5F_t * f, haddr_t tag, hid_t dxpl_id); H5_DLL herr_t H5F_evict_tagged_metadata(H5F_t * f, haddr_t tag, hid_t dxpl_id); +/* Functions that verify a piece of metadata with checksum */ +H5_DLL herr_t H5F_get_checksums(const uint8_t *buf, size_t chk_size, uint32_t *s_chksum, uint32_t *c_chksum); + +/* Routine to track the # of retries */ +H5_DLL herr_t H5F_track_metadata_read_retries(H5F_t *f, unsigned actype, unsigned retries); +H5_DLL herr_t H5F_set_retries(H5F_t *f); + /* Routine to invoke callback function upon object flush */ H5_DLL herr_t H5F_object_flush_cb(H5F_t *f, hid_t obj_id); diff --git a/src/H5Fpublic.h b/src/H5Fpublic.h index 6db5a69..018618e 100644 --- a/src/H5Fpublic.h +++ b/src/H5Fpublic.h @@ -175,6 +175,14 @@ typedef enum H5F_file_space_type_t { H5F_FILE_SPACE_NTYPES /* must be last */ } H5F_file_space_type_t; +/* Data structure to report the collection of read retries for metadata items with checksum */ +/* Used by public routine H5Fget_metadata_read_retry_info() */ +#define H5F_NUM_METADATA_READ_RETRY_TYPES 21 +typedef struct H5F_retry_info_t { + unsigned nbins; + uint32_t *retries[H5F_NUM_METADATA_READ_RETRY_TYPES]; +} H5F_retry_info_t; + /* Callback for H5Pset_object_flush_cb() in a file access property list */ typedef herr_t (*H5F_flush_cb_t)(hid_t object_id, void *udata); @@ -216,6 +224,7 @@ H5_DLL herr_t H5Fget_mdc_size(hid_t file_id, H5_DLL herr_t H5Freset_mdc_hit_rate_stats(hid_t file_id); H5_DLL ssize_t H5Fget_name(hid_t obj_id, char *name, size_t size); H5_DLL herr_t H5Fget_info2(hid_t obj_id, H5F_info2_t *finfo); +H5_DLL herr_t H5Fget_metadata_read_retry_info(hid_t file_id, H5F_retry_info_t *info); H5_DLL ssize_t H5Fget_free_sections(hid_t file_id, H5F_mem_t type, size_t nsects, H5F_sect_info_t *sect_info/*out*/); H5_DLL herr_t H5Fclear_elink_file_cache(hid_t file_id); diff --git a/src/H5Fquery.c b/src/H5Fquery.c index 487eb85..7fcd0f1 100644 --- a/src/H5Fquery.c +++ b/src/H5Fquery.c @@ -322,6 +322,29 @@ H5F_get_nmounts(const H5F_t *f) /*------------------------------------------------------------------------- + * Function: H5F_get_read_attempts + * + * Purpose: Retrieve the file's 'read_attempts' value + * + * Return: '# of read attempts' on success/abort on failure (shouldn't fail) + * + * Programmer: Vaili Choi; Sept 2013 + * + *------------------------------------------------------------------------- + */ +unsigned +H5F_get_read_attempts(const H5F_t *f) +{ + /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(f); + + FUNC_LEAVE_NOAPI(f->shared->read_attempts) +} /* end H5F_get_read_attempts() */ + + +/*------------------------------------------------------------------------- * Function: H5F_get_fcpl * * Purpose: Retrieve the value of a file's FCPL. diff --git a/src/H5Fsuper_cache.c b/src/H5Fsuper_cache.c index d863159..6cfd9c7 100644 --- a/src/H5Fsuper_cache.c +++ b/src/H5Fsuper_cache.c @@ -67,7 +67,10 @@ /********************/ /* Metadata cache (H5AC) callbacks */ -static herr_t H5F__cache_superblock_get_load_size(const void *udata, size_t *image_len); +static herr_t H5F__cache_superblock_get_initial_load_size(void *udata, size_t *image_len); +static herr_t H5F__cache_superblock_get_final_load_size(const void *image_ptr, + size_t image_len, void *udata, size_t *actual_len); +static htri_t H5F__cache_superblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5F__cache_superblock_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5F__cache_superblock_image_len(const void *thing, size_t *image_len); @@ -78,7 +81,9 @@ static herr_t H5F__cache_superblock_serialize(const H5F_t *f, void *image, size_ void *thing); static herr_t H5F__cache_superblock_free_icr(void *thing); -static herr_t H5F__cache_drvrinfo_get_load_size(const void *udata, size_t *image_len); +static herr_t H5F__cache_drvrinfo_get_initial_load_size(void *udata, size_t *image_len); +static herr_t H5F__cache_drvrinfo_get_final_load_size(const void *image_ptr, + size_t image_len, void *udata, size_t *actual_len); static void *H5F__cache_drvrinfo_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5F__cache_drvrinfo_image_len(const void *thing, size_t *image_len); @@ -97,7 +102,9 @@ const H5AC_class_t H5AC_SUPERBLOCK[1] = {{ "Superblock", /* Metadata client name (for debugging) */ H5FD_MEM_SUPER, /* File space memory type for client */ H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */ - H5F__cache_superblock_get_load_size,/* 'get_load_size' callback */ + H5F__cache_superblock_get_initial_load_size,/* 'get_initial_load_size' callback */ + H5F__cache_superblock_get_final_load_size, /* 'get_final_load_size' callback */ + H5F__cache_superblock_verify_chksum, /* 'verify_chksum' callback */ H5F__cache_superblock_deserialize, /* 'deserialize' callback */ H5F__cache_superblock_image_len, /* 'image_len' callback */ H5F__cache_superblock_pre_serialize,/* 'pre_serialize' callback */ @@ -113,7 +120,9 @@ const H5AC_class_t H5AC_DRVRINFO[1] = {{ "Driver info block", /* Metadata client name (for debugging) */ H5FD_MEM_SUPER, /* File space memory type for client */ H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */ - H5F__cache_drvrinfo_get_load_size, /* 'get_load_size' callback */ + H5F__cache_drvrinfo_get_initial_load_size, /* 'get_initial_load_size' callback */ + H5F__cache_drvrinfo_get_final_load_size, /* 'get_final_load_size' callback */ + NULL, /* 'verify_chksum' callback */ H5F__cache_drvrinfo_deserialize, /* 'deserialize' callback */ H5F__cache_drvrinfo_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -139,7 +148,7 @@ H5FL_EXTERN(H5F_super_t); /*------------------------------------------------------------------------- - * Function: H5F__cache_superblock_get_load_size + * Function: H5F__cache_superblock_get_initial_load_size * * Purpose: Compute the size of the data structure on disk. * @@ -152,7 +161,7 @@ H5FL_EXTERN(H5F_super_t); *------------------------------------------------------------------------- */ static herr_t -H5F__cache_superblock_get_load_size(const void H5_ATTR_UNUSED *udata, size_t *image_len) +H5F__cache_superblock_get_initial_load_size(void H5_ATTR_UNUSED *_udata, size_t *image_len) { FUNC_ENTER_STATIC_NOERR @@ -161,10 +170,138 @@ H5F__cache_superblock_get_load_size(const void H5_ATTR_UNUSED *udata, size_t *im /* Set the initial image length size */ *image_len = H5F_SUPERBLOCK_FIXED_SIZE + /* Fixed size of superblock */ - H5F_SUPERBLOCK_MINIMAL_VARLEN_SIZE; + H5F_SUPERBLOCK_MINIMAL_VARLEN_SIZE; FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5F__cache_superblock_get_load_size() */ +} /* end H5F__cache_superblock_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5F__cache_superblock_get_final_load_size + * + * Purpose: Compute the final size of the data structure on disk. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@lbl.gov + * November 17, 2016 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F__cache_superblock_get_final_load_size(const void *_image, size_t image_len, + void *_udata, size_t *actual_len) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5F_superblock_cache_ud_t *udata = (H5F_superblock_cache_ud_t *)_udata; /* User data */ + unsigned super_vers; /* Superblock version */ + uint8_t sizeof_addr; /* Size of offsets in the file (in bytes) */ + uint8_t sizeof_size; /* Size of lengths in the file (in bytes) */ + size_t variable_size; /* Variable size of superblock */ + htri_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Check arguments */ + HDassert(image); + HDassert(udata); + HDassert(udata->f); + HDassert(actual_len); + HDassert(*actual_len == image_len); + + /* Skip over file signature */ + image += H5F_SIGNATURE_LEN; + + /* Superblock version */ + super_vers = *image++; + if(super_vers > HDF5_SUPERBLOCK_VERSION_LATEST) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "bad superblock version number") + + /* Save the version to be used in verify_chksum callback */ + udata->super_vers = super_vers; + + /* Sanity check */ + HDassert(((size_t)(image - (const uint8_t *)_image)) == H5F_SUPERBLOCK_FIXED_SIZE); + HDassert(image_len >= H5F_SUPERBLOCK_FIXED_SIZE + 6); + + /* Determine the size of addresses & size of offsets, for computing the + * variable-sized portion of the superblock. + */ + if(super_vers < HDF5_SUPERBLOCK_VERSION_2) { + sizeof_addr = image[4]; + sizeof_size = image[5]; + } /* end if */ + else { + sizeof_addr = image[0]; + sizeof_size = image[1]; + } /* end else */ + if(sizeof_addr != 2 && sizeof_addr != 4 && + sizeof_addr != 8 && sizeof_addr != 16 && sizeof_addr != 32) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "bad byte number in an address") + if(sizeof_size != 2 && sizeof_size != 4 && + sizeof_size != 8 && sizeof_size != 16 && sizeof_size != 32) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "bad byte number for object size") + + /* Determine the size of the variable-length part of the superblock */ + variable_size = (size_t)H5F_SUPERBLOCK_VARLEN_SIZE(super_vers, sizeof_addr, sizeof_size); + HDassert(variable_size > 0); + + /* Sanity check */ + HDassert(image_len == (H5F_SUPERBLOCK_FIXED_SIZE + H5F_SUPERBLOCK_MINIMAL_VARLEN_SIZE)); + + /* Make certain we can read the variable-sized portion of the superblock */ + if(H5F__set_eoa(udata->f, H5FD_MEM_SUPER, (haddr_t)(H5F_SUPERBLOCK_FIXED_SIZE + variable_size)) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "set end of space allocation request failed") + + /* Set the final size for the cache image */ + *actual_len = H5F_SUPERBLOCK_FIXED_SIZE + variable_size; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5F__cache_superblock_get_final_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5F__cache_superblock_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5F__cache_superblock_verify_chksum(const void *_image, size_t len, void *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5F_superblock_cache_ud_t *udata = (H5F_superblock_cache_ud_t *)_udata; /* User data */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + HDassert(udata); + + /* No checksum for version 0 & 1 */ + if(udata->super_vers >= HDF5_SUPERBLOCK_VERSION_2) { + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5F__cache_superblock_verify_chksum() */ /*------------------------------------------------------------------------- @@ -244,176 +381,161 @@ H5F__cache_superblock_deserialize(const void *_image, size_t len, void *_udata, variable_size = (size_t)H5F_SUPERBLOCK_VARLEN_SIZE(super_vers, sizeof_addr, sizeof_size); HDassert(variable_size > 0); - /* Handle metadata cache retry for variable-sized portion of the superblock */ - if(len != (H5F_SUPERBLOCK_FIXED_SIZE + variable_size)) { - /* Sanity check */ - HDassert(len == (H5F_SUPERBLOCK_FIXED_SIZE + H5F_SUPERBLOCK_MINIMAL_VARLEN_SIZE)); + HDassert(len == (H5F_SUPERBLOCK_FIXED_SIZE + variable_size)); - /* Make certain we can read the variabled-sized portion of the superblock */ - if(H5F__set_eoa(udata->f, H5FD_MEM_SUPER, (haddr_t)(H5F_SUPERBLOCK_FIXED_SIZE + variable_size)) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, "set end of space allocation request failed") - } /* end if */ - else { - /* Check for older version of superblock format */ - if(super_vers < HDF5_SUPERBLOCK_VERSION_2) { - uint32_t status_flags; /* File status flags */ - unsigned sym_leaf_k; /* Symbol table leaf node's 'K' value */ - unsigned snode_btree_k; /* B-tree symbol table internal node 'K' value */ - unsigned chunk_btree_k; /* B-tree chunk internal node 'K' value */ - - /* Freespace version (hard-wired) */ - if(HDF5_FREESPACE_VERSION != *image++) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad free space version number") - - /* Root group version number (hard-wired) */ - if(HDF5_OBJECTDIR_VERSION != *image++) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad object directory version number") - - /* Skip over reserved byte */ - image++; - - /* Shared header version number (hard-wired) */ - if(HDF5_SHAREDHEADER_VERSION != *image++) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad shared-header format version number") - - /* Size of file addresses */ - sizeof_addr = *image++; - if(sizeof_addr != 2 && sizeof_addr != 4 && - sizeof_addr != 8 && sizeof_addr != 16 && sizeof_addr != 32) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad byte number in an address") - sblock->sizeof_addr = sizeof_addr; - udata->f->shared->sizeof_addr = sizeof_addr; /* Keep a local copy also */ - - /* Size of file sizes */ - sizeof_size = *image++; - if(sizeof_size != 2 && sizeof_size != 4 && - sizeof_size != 8 && sizeof_size != 16 && sizeof_size != 32) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad byte number for object size") - sblock->sizeof_size = sizeof_size; - udata->f->shared->sizeof_size = sizeof_size; /* Keep a local copy also */ - - /* Skip over reserved byte */ - image++; - - /* Various B-tree sizes */ - UINT16DECODE(image, sym_leaf_k); - if(sym_leaf_k == 0) - HGOTO_ERROR(H5E_FILE, H5E_BADRANGE, NULL, "bad symbol table leaf node 1/2 rank") - udata->sym_leaf_k = sym_leaf_k; /* Keep a local copy also */ - - /* Need 'get' call to set other array values */ - UINT16DECODE(image, snode_btree_k); - if(snode_btree_k == 0) - HGOTO_ERROR(H5E_FILE, H5E_BADRANGE, NULL, "bad 1/2 rank for btree internal nodes") - udata->btree_k[H5B_SNODE_ID] = snode_btree_k; - - /* - * Delay setting the value in the property list until we've checked - * for the indexed storage B-tree internal 'K' value later. - */ - - /* File status flags (not really used yet) */ - UINT32DECODE(image, status_flags); - HDassert(status_flags <= 255); - sblock->status_flags = (uint8_t)status_flags; - if(sblock->status_flags & ~H5F_SUPER_ALL_FLAGS) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad flag value for superblock") - - /* - * If the superblock version # is greater than 0, read in the indexed - * storage B-tree internal 'K' value - */ - if(super_vers > HDF5_SUPERBLOCK_VERSION_DEF) { - UINT16DECODE(image, chunk_btree_k); - - /* Reserved bytes are present only in version 1 */ - if(super_vers == HDF5_SUPERBLOCK_VERSION_1) - image += 2; /* reserved */ - } /* end if */ - else - chunk_btree_k = HDF5_BTREE_CHUNK_IK_DEF; - udata->btree_k[H5B_CHUNK_ID] = chunk_btree_k; - - /* Remainder of "variable-sized" portion of superblock */ - H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->base_addr/*out*/); - H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->ext_addr/*out*/); - H5F_addr_decode(udata->f, (const uint8_t **)&image, &udata->stored_eof/*out*/); - H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->driver_addr/*out*/); - - /* Allocate space for the root group symbol table entry */ - HDassert(!sblock->root_ent); - if(NULL == (sblock->root_ent = (H5G_entry_t *)H5MM_calloc(sizeof(H5G_entry_t)))) - HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "can't allocate space for root group symbol table entry") - - /* decode the root group symbol table entry */ - if(H5G_ent_decode(udata->f, (const uint8_t **)&image, sblock->root_ent) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, NULL, "can't decode root group symbol table entry") - - /* Set the root group address to the correct value */ - sblock->root_addr = sblock->root_ent->header; - - /* This step is for h5repart tool only. If user wants to change file driver - * from family to sec2 while using h5repart, set the driver address to - * undefined to let the library ignore the family driver information saved - * in the superblock. - */ - if(udata->ignore_drvrinfo && H5F_addr_defined(sblock->driver_addr)) { - /* Eliminate the driver info */ - sblock->driver_addr = HADDR_UNDEF; - udata->drvrinfo_removed = TRUE; - } /* end if */ + /* Check for older version of superblock format */ + if(super_vers < HDF5_SUPERBLOCK_VERSION_2) { + uint32_t status_flags; /* File status flags */ + unsigned sym_leaf_k; /* Symbol table leaf node's 'K' value */ + unsigned snode_btree_k; /* B-tree symbol table internal node 'K' value */ + unsigned chunk_btree_k; /* B-tree chunk internal node 'K' value */ + + /* Freespace version (hard-wired) */ + if(HDF5_FREESPACE_VERSION != *image++) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad free space version number") + + /* Root group version number (hard-wired) */ + if(HDF5_OBJECTDIR_VERSION != *image++) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad object directory version number") + + /* Skip over reserved byte */ + image++; + + /* Shared header version number (hard-wired) */ + if(HDF5_SHAREDHEADER_VERSION != *image++) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad shared-header format version number") + + /* Size of file addresses */ + sizeof_addr = *image++; + if(sizeof_addr != 2 && sizeof_addr != 4 && + sizeof_addr != 8 && sizeof_addr != 16 && sizeof_addr != 32) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad byte number in an address") + sblock->sizeof_addr = sizeof_addr; + udata->f->shared->sizeof_addr = sizeof_addr; /* Keep a local copy also */ + + /* Size of file sizes */ + sizeof_size = *image++; + if(sizeof_size != 2 && sizeof_size != 4 && + sizeof_size != 8 && sizeof_size != 16 && sizeof_size != 32) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad byte number for object size") + sblock->sizeof_size = sizeof_size; + udata->f->shared->sizeof_size = sizeof_size; /* Keep a local copy also */ + + /* Skip over reserved byte */ + image++; + + /* Various B-tree sizes */ + UINT16DECODE(image, sym_leaf_k); + if(sym_leaf_k == 0) + HGOTO_ERROR(H5E_FILE, H5E_BADRANGE, NULL, "bad symbol table leaf node 1/2 rank") + udata->sym_leaf_k = sym_leaf_k; /* Keep a local copy also */ + + /* Need 'get' call to set other array values */ + UINT16DECODE(image, snode_btree_k); + if(snode_btree_k == 0) + HGOTO_ERROR(H5E_FILE, H5E_BADRANGE, NULL, "bad 1/2 rank for btree internal nodes") + udata->btree_k[H5B_SNODE_ID] = snode_btree_k; + + /* + * Delay setting the value in the property list until we've checked + * for the indexed storage B-tree internal 'K' value later. + */ - /* NOTE: Driver info block is decoded separately, later */ + /* File status flags (not really used yet) */ + UINT32DECODE(image, status_flags); + HDassert(status_flags <= 255); + sblock->status_flags = (uint8_t)status_flags; + if(sblock->status_flags & ~H5F_SUPER_ALL_FLAGS) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad flag value for superblock") - } /* end if */ - else { - uint32_t computed_chksum; /* Computed checksum */ - uint32_t read_chksum; /* Checksum read from file */ - - /* Size of file addresses */ - sizeof_addr = *image++; - if(sizeof_addr != 2 && sizeof_addr != 4 && - sizeof_addr != 8 && sizeof_addr != 16 && sizeof_addr != 32) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad byte number in an address") - sblock->sizeof_addr = sizeof_addr; - udata->f->shared->sizeof_addr = sizeof_addr; /* Keep a local copy also */ - - /* Size of file sizes */ - sizeof_size = *image++; - if(sizeof_size != 2 && sizeof_size != 4 && - sizeof_size != 8 && sizeof_size != 16 && sizeof_size != 32) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad byte number for object size") - sblock->sizeof_size = sizeof_size; - udata->f->shared->sizeof_size = sizeof_size; /* Keep a local copy also */ - - /* File status flags (not really used yet) */ - sblock->status_flags = *image++; - if(sblock->status_flags & ~H5F_SUPER_ALL_FLAGS) - HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad flag value for superblock") - - /* Base, superblock extension, end of file & root group object header addresses */ - H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->base_addr/*out*/); - H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->ext_addr/*out*/); - H5F_addr_decode(udata->f, (const uint8_t **)&image, &udata->stored_eof/*out*/); - H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->root_addr/*out*/); - - /* Compute checksum for superblock */ - computed_chksum = H5_checksum_metadata(_image, (size_t)(image - (const uint8_t *)_image), 0); - - /* Decode checksum */ - UINT32DECODE(image, read_chksum); - - /* Verify correct checksum */ - if(read_chksum != computed_chksum) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, NULL, "bad checksum on driver information block") - - /* The Driver Information Block may not appear with the version - * 2 super block. Thus we set the driver_addr field of the in - * core representation of the super block HADDR_UNDEF to prevent - * any attempt to load the Driver Information Block. - */ - sblock->driver_addr = HADDR_UNDEF; - } /* end else */ + /* + * If the superblock version # is greater than 0, read in the indexed + * storage B-tree internal 'K' value + */ + if(super_vers > HDF5_SUPERBLOCK_VERSION_DEF) { + UINT16DECODE(image, chunk_btree_k); + + /* Reserved bytes are present only in version 1 */ + if(super_vers == HDF5_SUPERBLOCK_VERSION_1) + image += 2; /* reserved */ + } /* end if */ + else + chunk_btree_k = HDF5_BTREE_CHUNK_IK_DEF; + udata->btree_k[H5B_CHUNK_ID] = chunk_btree_k; + + /* Remainder of "variable-sized" portion of superblock */ + H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->base_addr/*out*/); + H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->ext_addr/*out*/); + H5F_addr_decode(udata->f, (const uint8_t **)&image, &udata->stored_eof/*out*/); + H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->driver_addr/*out*/); + + /* Allocate space for the root group symbol table entry */ + HDassert(!sblock->root_ent); + if(NULL == (sblock->root_ent = (H5G_entry_t *)H5MM_calloc(sizeof(H5G_entry_t)))) + HGOTO_ERROR(H5E_FILE, H5E_CANTALLOC, NULL, "can't allocate space for root group symbol table entry") + + /* decode the root group symbol table entry */ + if(H5G_ent_decode(udata->f, (const uint8_t **)&image, sblock->root_ent) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, NULL, "can't decode root group symbol table entry") + + /* Set the root group address to the correct value */ + sblock->root_addr = sblock->root_ent->header; + + /* This step is for h5repart tool only. If user wants to change file driver + * from family to sec2 while using h5repart, set the driver address to + * undefined to let the library ignore the family driver information saved + * in the superblock. + */ + if(udata->ignore_drvrinfo && H5F_addr_defined(sblock->driver_addr)) { + /* Eliminate the driver info */ + sblock->driver_addr = HADDR_UNDEF; + udata->drvrinfo_removed = TRUE; + } /* end if */ + + /* NOTE: Driver info block is decoded separately, later */ + + } /* end if */ + else { + uint32_t read_chksum; /* Checksum read from file */ + + /* Size of file addresses */ + sizeof_addr = *image++; + if(sizeof_addr != 2 && sizeof_addr != 4 && + sizeof_addr != 8 && sizeof_addr != 16 && sizeof_addr != 32) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad byte number in an address") + sblock->sizeof_addr = sizeof_addr; + udata->f->shared->sizeof_addr = sizeof_addr; /* Keep a local copy also */ + + /* Size of file sizes */ + sizeof_size = *image++; + if(sizeof_size != 2 && sizeof_size != 4 && + sizeof_size != 8 && sizeof_size != 16 && sizeof_size != 32) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad byte number for object size") + sblock->sizeof_size = sizeof_size; + udata->f->shared->sizeof_size = sizeof_size; /* Keep a local copy also */ + + /* File status flags (not really used yet) */ + sblock->status_flags = *image++; + if(sblock->status_flags & ~H5F_SUPER_ALL_FLAGS) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, NULL, "bad flag value for superblock") + + /* Base, superblock extension, end of file & root group object header addresses */ + H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->base_addr/*out*/); + H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->ext_addr/*out*/); + H5F_addr_decode(udata->f, (const uint8_t **)&image, &udata->stored_eof/*out*/); + H5F_addr_decode(udata->f, (const uint8_t **)&image, &sblock->root_addr/*out*/); + + /* checksum verification already done in verify_chksum cb */ + + /* Decode checksum */ + UINT32DECODE(image, read_chksum); + + /* The Driver Information Block may not appear with the version + * 2 super block. Thus we set the driver_addr field of the in + * core representation of the super block HADDR_UNDEF to prevent + * any attempt to load the Driver Information Block. + */ + sblock->driver_addr = HADDR_UNDEF; } /* end else */ /* Sanity check */ @@ -759,9 +881,9 @@ done: /*------------------------------------------------------------------------- - * Function: H5F__cache_drvrinfo_get_load_size + * Function: H5F__cache_drvrinfo_get_initial_load_size * - * Purpose: Compute the size of the data structure on disk. + * Purpose: Compute the intiial size of the data structure on disk. * * Return: Non-negative on success/Negative on failure * @@ -772,7 +894,7 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5F__cache_drvrinfo_get_load_size(const void H5_ATTR_UNUSED *udata, size_t *image_len) +H5F__cache_drvrinfo_get_initial_load_size(void H5_ATTR_UNUSED *_udata, size_t *image_len) { FUNC_ENTER_STATIC_NOERR @@ -783,7 +905,76 @@ H5F__cache_drvrinfo_get_load_size(const void H5_ATTR_UNUSED *udata, size_t *imag *image_len = H5F_DRVINFOBLOCK_HDR_SIZE; /* Fixed size portion of driver info block */ FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5F__cache_drvrinfo_get_load_size() */ +} /* end H5F__cache_drvrinfo_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5F__cache_drvrinfo_get_final_load_size + * + * Purpose: Compute the final size of the data structure on disk. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@lbl.gov + * November 17, 2016 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F__cache_drvrinfo_get_final_load_size(const void *_image, size_t image_len, + void *_udata, size_t *actual_len) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5F_drvrinfo_cache_ud_t *udata = (H5F_drvrinfo_cache_ud_t *)_udata; /* User data */ + unsigned drv_vers; /* Version of driver info block */ + size_t drvinfo_len; /* Length of encoded buffer */ + haddr_t eoa; /* Current EOA for the file */ + haddr_t min_eoa; /* Minimum EOA needed for reading the driver info */ + htri_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Check arguments */ + HDassert(image); + HDassert(udata); + HDassert(udata->f); + HDassert(actual_len); + HDassert(*actual_len == image_len); + + /* Version number */ + drv_vers = *image++; + if(drv_vers != HDF5_DRIVERINFO_VERSION_0) + HGOTO_ERROR(H5E_FILE, H5E_BADVALUE, FAIL, "bad driver information block version number") + + image += 3; /* reserved bytes */ + + /* Driver info size */ + UINT32DECODE(image, drvinfo_len); + + /* Sanity check */ + HDassert(image_len == H5F_DRVINFOBLOCK_HDR_SIZE); + + /* Extend the EOA if required so that we can read the complete driver info block */ + + /* Get current EOA... */ + if((eoa = H5FD_get_eoa(udata->f->shared->lf, H5FD_MEM_SUPER)) == HADDR_UNDEF) + HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "driver get_eoa request failed") + + /* ... if it is too small, extend it. */ + min_eoa = udata->driver_addr + H5F_DRVINFOBLOCK_HDR_SIZE + drvinfo_len; + + /* If it grew, set it */ + if(H5F_addr_gt(min_eoa, eoa)) + if(H5FD_set_eoa(udata->f->shared->lf, H5FD_MEM_SUPER, min_eoa) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, FAIL, "set end of space allocation request failed") + + /* Set the final size for the cache image */ + *actual_len = H5F_DRVINFOBLOCK_HDR_SIZE + drvinfo_len; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5F__cache_drvrinfo_get_final_load_size() */ /*------------------------------------------------------------------------- @@ -838,35 +1029,11 @@ H5F__cache_drvrinfo_deserialize(const void *_image, size_t len, void *_udata, drv_name[8] = '\0'; image += 8; /* advance past name/version */ - /* Handle metadata cache retry for variable-sized portion of the driver info block */ - if(len != (H5F_DRVINFOBLOCK_HDR_SIZE + drvinfo->len)) { - /* Sanity check */ - HDassert(len == H5F_DRVINFOBLOCK_HDR_SIZE); - - /* extend the eoa if required so that we can read the complete driver info block */ - { - haddr_t eoa; - haddr_t min_eoa; - - /* get current eoa... */ - if ((eoa = H5FD_get_eoa(udata->f->shared->lf, H5FD_MEM_SUPER)) == HADDR_UNDEF) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, NULL, "driver get_eoa request failed") - - /* ... if it is too small, extend it. */ - min_eoa = udata->driver_addr + H5F_DRVINFOBLOCK_HDR_SIZE + drvinfo->len; + HDassert(len == (H5F_DRVINFOBLOCK_HDR_SIZE + drvinfo->len)); - if ( H5F_addr_gt(min_eoa, eoa) ) - if(H5FD_set_eoa(udata->f->shared->lf, H5FD_MEM_SUPER, min_eoa) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTINIT, NULL, \ - "set end of space allocation request failed") - } - - } /* end if */ - else { - /* Validate and decode driver information */ - if(H5FD_sb_load(udata->f->shared->lf, drv_name, image) < 0) - HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, NULL, "unable to decode driver information") - } /* end if */ + /* Validate and decode driver information */ + if(H5FD_sb_load(udata->f->shared->lf, drv_name, image) < 0) + HGOTO_ERROR(H5E_FILE, H5E_CANTDECODE, NULL, "unable to decode driver information") /* Sanity check */ HDassert((size_t)(image - (const uint8_t *)_image) <= len); @@ -911,7 +1078,7 @@ H5F__cache_drvrinfo_image_len(const void *_thing, size_t *image_len) /* Set the image length size */ *image_len = (size_t)(H5F_DRVINFOBLOCK_HDR_SIZE + /* Fixed-size portion of driver info block */ - drvinfo->len); /* Variable-size portion of driver info block */ + drvinfo->len); /* Variable-size portion of driver info block */ FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5F__cache_drvrinfo_image_len() */ diff --git a/src/H5Gcache.c b/src/H5Gcache.c index c3e1c12..d153560 100644 --- a/src/H5Gcache.c +++ b/src/H5Gcache.c @@ -63,7 +63,7 @@ /********************/ /* Metadata cache (H5AC) callbacks */ -static herr_t H5G__cache_node_get_load_size(const void *udata, size_t *image_len); +static herr_t H5G__cache_node_get_initial_load_size(void *udata, size_t *image_len); static void *H5G__cache_node_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5G__cache_node_image_len(const void *thing, size_t *image_len); @@ -92,7 +92,9 @@ const H5AC_class_t H5AC_SNODE[1] = {{ "Symbol table node", /* Metadata client name (for debugging) */ H5FD_MEM_BTREE, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5G__cache_node_get_load_size, /* 'get_load_size' callback */ + H5G__cache_node_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + NULL, /* 'verify_chksum' callback */ H5G__cache_node_deserialize, /* 'deserialize' callback */ H5G__cache_node_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -111,17 +113,11 @@ H5FL_SEQ_EXTERN(H5G_entry_t); /*------------------------------------------------------------------------- - * Function: H5G__cache_node_get_load_size() + * Function: H5G__cache_node_get_initial_load_size() * - * Purpose: Determine the size of the on disk image of the node, and + * Purpose: Determine the size of the on-disk image of the node, and * return this value in *image_len. * - * Note that this computation requires access to the file pointer, - * which is not provided in the parameter list for this callback. - * Finesse this issue by passing in the file pointer twice to the - * H5AC_protect() call -- once as the file pointer proper, and - * again as the user data. - * * Return: Success: SUCCEED * Failure: FAIL * @@ -131,9 +127,9 @@ H5FL_SEQ_EXTERN(H5G_entry_t); *------------------------------------------------------------------------- */ static herr_t -H5G__cache_node_get_load_size(const void *_udata, size_t *image_len) +H5G__cache_node_get_initial_load_size(void *_udata, size_t *image_len) { - const H5F_t *f = (const H5F_t *)_udata; /* User data for callback */ + H5F_t *f = (H5F_t *)_udata; /* User data for callback */ FUNC_ENTER_STATIC_NOERR @@ -141,11 +137,11 @@ H5G__cache_node_get_load_size(const void *_udata, size_t *image_len) HDassert(f); HDassert(image_len); - /* report image length */ + /* Set the image length size */ *image_len = (size_t)(H5G_NODE_SIZE(f)); FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5G__cache_node_get_load_size() */ +} /* end H5G__cache_node_get_initial_load_size() */ /*------------------------------------------------------------------------- @@ -256,11 +252,6 @@ H5G__cache_node_image_len(const void *_thing, size_t *image_len) FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5G__cache_node_image_len() */ - -/*************************************/ -/* no H5G__cache_node_pre_serialize() */ -/*************************************/ - /*------------------------------------------------------------------------- * Function: H5G__cache_node_serialize @@ -320,11 +311,6 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5G__cache_node_serialize() */ - -/***************************************/ -/* no H5G__cache_node_notify() function */ -/***************************************/ - /*------------------------------------------------------------------------- * Function: H5G__cache_node_free_icr diff --git a/src/H5HFcache.c b/src/H5HFcache.c index 0e9485f..04f1459 100644 --- a/src/H5HFcache.c +++ b/src/H5HFcache.c @@ -73,7 +73,10 @@ static herr_t H5HF__dtable_encode(H5F_t *f, uint8_t **pp, const H5HF_dtable_t *d static herr_t H5HF__dtable_decode(H5F_t *f, const uint8_t **pp, H5HF_dtable_t *dtable); /* Metadata cache (H5AC) callbacks */ -static herr_t H5HF__cache_hdr_get_load_size(const void *udata, size_t *image_len); +static herr_t H5HF__cache_hdr_get_initial_load_size(void *udata, size_t *image_len); +static herr_t H5HF__cache_hdr_get_final_load_size(const void *image_ptr, + size_t image_len, void *udata, size_t *actual_len); +static htri_t H5HF__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5HF__cache_hdr_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5HF__cache_hdr_image_len(const void *thing, size_t *image_len); @@ -84,7 +87,8 @@ static herr_t H5HF__cache_hdr_serialize(const H5F_t *f, void *image, size_t len, void *thing); static herr_t H5HF__cache_hdr_free_icr(void *thing); -static herr_t H5HF__cache_iblock_get_load_size(const void *udata, size_t *image_len); +static herr_t H5HF__cache_iblock_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5HF__cache_iblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5HF__cache_iblock_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5HF__cache_iblock_image_len(const void *thing, size_t *image_len); @@ -96,7 +100,8 @@ static herr_t H5HF__cache_iblock_serialize(const H5F_t *f, void *image, static herr_t H5HF__cache_iblock_notify(H5C_notify_action_t action, void *thing); static herr_t H5HF__cache_iblock_free_icr(void *thing); -static herr_t H5HF__cache_dblock_get_load_size(const void *udata, size_t *image_len); +static herr_t H5HF__cache_dblock_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5HF__cache_dblock_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5HF__cache_dblock_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5HF__cache_dblock_image_len(const void *thing, size_t *image_len); @@ -131,7 +136,9 @@ const H5AC_class_t H5AC_FHEAP_HDR[1] = {{ "fractal heap header", /* Metadata client name (for debugging) */ H5FD_MEM_FHEAP_HDR, /* File space memory type for client */ H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */ - H5HF__cache_hdr_get_load_size, /* 'get_load_size' callback */ + H5HF__cache_hdr_get_initial_load_size, /* 'get_initial_load_size' callback */ + H5HF__cache_hdr_get_final_load_size, /* 'get_final_load_size' callback */ + H5HF__cache_hdr_verify_chksum, /* 'verify_chksum' callback */ H5HF__cache_hdr_deserialize, /* 'deserialize' callback */ H5HF__cache_hdr_image_len, /* 'image_len' callback */ H5HF__cache_hdr_pre_serialize, /* 'pre_serialize' callback */ @@ -147,7 +154,9 @@ const H5AC_class_t H5AC_FHEAP_IBLOCK[1] = {{ "fractal heap indirect block", /* Metadata client name (for debugging) */ H5FD_MEM_FHEAP_IBLOCK, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5HF__cache_iblock_get_load_size, /* 'get_load_size' callback */ + H5HF__cache_iblock_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5HF__cache_iblock_verify_chksum, /* 'verify_chksum' callback */ H5HF__cache_iblock_deserialize, /* 'deserialize' callback */ H5HF__cache_iblock_image_len, /* 'image_len' callback */ H5HF__cache_iblock_pre_serialize, /* 'pre_serialize' callback */ @@ -163,7 +172,9 @@ const H5AC_class_t H5AC_FHEAP_DBLOCK[1] = {{ "fractal heap direct block", /* Metadata client name (for debugging) */ H5FD_MEM_FHEAP_DBLOCK, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5HF__cache_dblock_get_load_size, /* 'get_load_size' callback */ + H5HF__cache_dblock_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5HF__cache_dblock_verify_chksum, /* 'verify_chksum' callback */ H5HF__cache_dblock_deserialize, /* 'deserialize' callback */ H5HF__cache_dblock_image_len, /* 'image_len' callback */ H5HF__cache_dblock_pre_serialize, /* 'pre_serialize' callback */ @@ -287,21 +298,13 @@ H5HF__dtable_encode(H5F_t *f, uint8_t **pp, const H5HF_dtable_t *dtable) FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5HF__dtable_encode() */ -/**************************************************/ -/* metadata cache callback definitions for header */ -/**************************************************/ - /*------------------------------------------------------------------------- - * Function: H5HF__cache_hdr_get_load_size() + * Function: H5HF__cache_hdr_get_initial_load_size() * * Purpose: Determine the size of the fractal heap header on disk, * and set *image_len to this value. * - * This code is based on the old H5HF_cache_hdr_load() routine - * that was used with the version 2 metadata cache. Note the - * use of a dummy header to compute the on disk size of the header. - * * Note also that the value returned by this function presumes that * there is no I/O filtering data in the header. If there is, the * size reported will be too small, and H5C_load_entry() @@ -316,10 +319,10 @@ H5HF__dtable_encode(H5F_t *f, uint8_t **pp, const H5HF_dtable_t *dtable) *------------------------------------------------------------------------- */ static herr_t -H5HF__cache_hdr_get_load_size(const void *_udata, size_t *image_len) +H5HF__cache_hdr_get_initial_load_size(void *_udata, size_t *image_len) { - const H5HF_hdr_cache_ud_t *udata = (const H5HF_hdr_cache_ud_t *)_udata; /* pointer to user data */ - H5HF_hdr_t dummy_hdr; /* dummy header -- to compute size */ + H5HF_hdr_cache_ud_t *udata = (H5HF_hdr_cache_ud_t *)_udata; /* Pointer to user data */ + H5HF_hdr_t dummy_hdr; /* Dummy header -- to compute size */ FUNC_ENTER_STATIC_NOERR @@ -336,40 +339,108 @@ H5HF__cache_hdr_get_load_size(const void *_udata, size_t *image_len) *image_len = (size_t)H5HF_HEADER_SIZE(&dummy_hdr); FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5HF__cache_hdr_get_load_size() */ +} /* end H5HF__cache_hdr_get_initial_load_size() */ /*------------------------------------------------------------------------- - * Function: H5HF__cache_hdr_deserialize + * Function: H5HF__cache_hdr_get_final_load_size() * - * Purpose: Given a buffer containing an on disk image of a fractal heap - * header block, allocate an instance of H5HF_hdr_t, load the contents - * of the buffer into into the new instance of H5HF_hdr_t, and then - * return a pointer to the new instance. + * Purpose: Determine the final size of the fractal heap header on disk, + * and set *actual_len to this value. * - * Since H5HF__cache_hdr_get_load_size() reports header on disk size - * base on the assumption that the header contains no I/O filtering - * data, it is possible that the provided image will be too small. + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Quincey Koziol + * November 18, 2016 * - * In this case, we DO NOT flag an error when this is discovered. - * Instead, we make note of the correct image size, and report - * success. + *------------------------------------------------------------------------- + */ +static herr_t +H5HF__cache_hdr_get_final_load_size(const void *_image, size_t image_len, + void *_udata, size_t *actual_len) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5HF_hdr_cache_ud_t *udata = (H5HF_hdr_cache_ud_t *)_udata; /* pointer to user data */ + unsigned filter_len; /* Size of I/O filter information (in bytes) */ + htri_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(image); + HDassert(udata); + HDassert(actual_len); + HDassert(*actual_len == image_len); + + /* Magic number */ + if(HDmemcmp(image, H5HF_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "wrong fractal heap header signature") + image += H5_SIZEOF_MAGIC; + + /* Version */ + if(*image++ != H5HF_HDR_VERSION) + HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "wrong fractal heap header version") + + /* General heap information */ + image += 2; /* Heap ID length */ + UINT16DECODE(image, filter_len); /* I/O filters' encoded length */ + + /* Check for I/O filter info on this heap */ + if(filter_len > 0) + /* Compute the extra heap header size */ + *actual_len += (size_t)(H5F_SIZEOF_SIZE(udata->f) /* Size of size for filtered root direct block */ + + (unsigned)4 /* Size of filter mask for filtered root direct block */ + + filter_len); /* Size of encoded I/O filter info */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF__cache_hdr_get_final_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_hdr_verify_chksum * - * Since H5HF__cache_hdr_image_len() callback is defined, - * H5C_load_entry() will call H5HF__cache_hdr_image_len() and - * obtain the correct image length. + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. * - * Since the H5AC__CLASS_SPECULATIVE_LOAD_FLAG is set, - * H5C_load_entry() will load an image of the correct size, and - * then call this function again to deserialize it. Before doing - * so, it will also call H5HF__cache_hdr_free_icr() to discard the - * result of the first deserialize call. + * Return: Success: TRUE/FALSE + * Failure: Negative * - * Note that the v2 B-tree and free space manager associated - * with the fractal heap (roots stored in the huge_bt2 and fspace - * fields respectively) are not loaded at this time. As best I can - * tell from reviewing the code, they are loaded or created when - * they are accessed. + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5HF__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF__cache_hdr_verify_chksum() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_hdr_deserialize + * + * Purpose: Given a buffer containing an on disk image of a fractal heap + * header block, allocate an instance of H5HF_hdr_t, load the contents + * of the buffer into into the new instance of H5HF_hdr_t, and then + * return a pointer to the new instance. * * Return: Success: Pointer to in core representation * Failure: NULL @@ -386,9 +457,7 @@ H5HF__cache_hdr_deserialize(const void *_image, size_t len, void *_udata, H5HF_hdr_t *hdr = NULL; /* Fractal heap info */ H5HF_hdr_cache_ud_t *udata = (H5HF_hdr_cache_ud_t *)_udata; /* User data for callback */ const uint8_t *image = (const uint8_t *)_image; /* Pointer into into supplied image */ - size_t size; /* Header size */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ uint8_t heap_flags; /* Status flags for heap */ void * ret_value = NULL; /* Return value */ @@ -404,28 +473,6 @@ H5HF__cache_hdr_deserialize(const void *_image, size_t len, void *_udata, if(NULL == (hdr = H5HF_hdr_alloc(udata->f))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - /* Compute the 'base' size of the fractal heap header on disk */ - size = (size_t)H5HF_HEADER_SIZE(hdr); - - /* the size we have just calculated presumes that there is no I/O - * filter information in the header. If there is no filter information, - * the deserialize operation should succeed. - * - * If there is filter information, the first attempt to deserialize - * the header will reveal this. In this case, we will be unable to - * deserialize the header as the supplied image will be too small. - * However, we will make note of the correct size and report success - * anyway. - * - * When H5C_load_entry() calls H5HF__cache_hdr_image_len(), we will report - * the correct size. Since the H5C__CLASS_SPECULATIVE_LOAD_FLAG is set, - * this will prompt H5C_load_entry() to load the correct size image, - * discard the result of the first attempt at deserialization, and - * call this routine a second time to deserialize the correct size - * buffer. - */ - HDassert(size <= len); - /* Magic number */ if(HDmemcmp(image, H5HF_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "wrong fractal heap header signature") @@ -469,32 +516,24 @@ H5HF__cache_hdr_deserialize(const void *_image, size_t len, void *_udata, if(H5HF__dtable_decode(hdr->f, &image, &(hdr->man_dtable)) < 0) HGOTO_ERROR(H5E_HEAP, H5E_CANTENCODE, NULL, "unable to encode managed obj. doubling table info") + /* Set the fractal heap header's 'base' size */ + hdr->heap_size = (size_t)H5HF_HEADER_SIZE(hdr); + /* Sanity check */ /* (allow for checksum not decoded yet) */ - HDassert((size_t)(image - (const uint8_t *)_image) == (size - H5HF_SIZEOF_CHKSUM)); + HDassert((size_t)(image - (const uint8_t *)_image) == (hdr->heap_size - H5HF_SIZEOF_CHKSUM)); /* Check for I/O filter information to decode */ if(hdr->filter_len > 0) { - size_t filter_info_size; /* Size of filter information */ H5O_pline_t *pline; /* Pipeline information from the header on disk */ - /* Compute the size of the extra filter information */ - filter_info_size = (size_t)(hdr->sizeof_size /* Size of size for filtered root direct block */ - + (unsigned)4 /* Size of filter mask for filtered root direct block */ - + hdr->filter_len); /* Size of encoded I/O filter info */ + /* Sanity check */ + HDassert(len > hdr->heap_size); /* A header with filter info is > than a standard header */ /* Compute the heap header's size */ - hdr->heap_size = size + filter_info_size; - - if(size == len) - /* we were supplied with too small a buffer -- goto done - * and let H5C_load_entry() retry with a larger buffer - */ - HGOTO_DONE((void *)hdr) - - else - if((size + filter_info_size) != len) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "bad image len") + hdr->heap_size += (size_t)(hdr->sizeof_size /* Size of size for filtered root direct block */ + + (unsigned)4 /* Size of filter mask for filtered root direct block */ + + hdr->filter_len); /* Size of encoded I/O filter info */ /* Decode the size of a filtered root direct block */ H5F_DECODE_LENGTH(udata->f, image, hdr->pline_root_direct_size); @@ -506,6 +545,7 @@ H5HF__cache_hdr_deserialize(const void *_image, size_t len, void *_udata, if(NULL == (pline = (H5O_pline_t *)H5O_msg_decode(hdr->f, udata->dxpl_id, NULL, H5O_PLINE_ID, image))) HGOTO_ERROR(H5E_HEAP, H5E_CANTDECODE, NULL, "can't decode I/O pipeline filters") + /* Advance past filter info to checksum */ image += hdr->filter_len; /* Copy the information into the header's I/O pipeline structure */ @@ -515,13 +555,6 @@ H5HF__cache_hdr_deserialize(const void *_image, size_t len, void *_udata, /* Release the space allocated for the I/O pipeline filters */ H5O_msg_free(H5O_PLINE_ID, pline); } /* end if */ - else - /* Set the heap header's size */ - hdr->heap_size = size; - - /* Compute checksum on entire header */ - /* (including the filter information, if present) */ - computed_chksum = H5_checksum_metadata(_image, (size_t)(image - (const uint8_t *)_image), 0); /* Metadata checksum */ UINT32DECODE(image, stored_chksum); @@ -529,10 +562,6 @@ H5HF__cache_hdr_deserialize(const void *_image, size_t len, void *_udata, /* Sanity check */ HDassert((size_t)(image - (const uint8_t *)_image) == hdr->heap_size); - /* Verify checksum */ - if(stored_chksum != computed_chksum) - HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "incorrect metadata checksum for fractal heap header") - /* Finish initialization of heap header */ if(H5HF_hdr_finish_init(hdr) < 0) HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, NULL, "can't finish initializing shared fractal heap header") @@ -556,7 +585,7 @@ done: * disk image. * * If the header contains filter information, this size will be - * larger than the value returned by H5HF__cache_hdr_get_load_size(). + * larger than the value returned by H5HF__cache_hdr_get_initial_load_size(). * * Return: Success: SUCCEED * Failure: FAIL @@ -770,10 +799,6 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5HF__cache_hdr_serialize() */ -/***************************************/ -/* no H5HF__cache_hdr_notify() function */ -/***************************************/ - /*------------------------------------------------------------------------- * Function: H5HF__cache_hdr_free_icr @@ -820,13 +845,9 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5HF__cache_hdr_free_icr() */ -/***********************************************************/ -/* metadata cache callback definitions for indirect blocks */ -/***********************************************************/ - /*------------------------------------------------------------------------- - * Function: H5HF__cache_iblock_get_load_size() + * Function: H5HF__cache_iblock_get_initial_load_size() * * Purpose: Compute the size of the on disk image of the indirect * block, and place this value in *image_len. @@ -840,24 +861,60 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5HF__cache_iblock_get_load_size(const void *_udata, size_t *image_len) +H5HF__cache_iblock_get_initial_load_size(void *_udata, size_t *image_len) { - const H5HF_iblock_cache_ud_t *udata = (const H5HF_iblock_cache_ud_t *)_udata; /* User data for callback */ + H5HF_iblock_cache_ud_t *udata = (H5HF_iblock_cache_ud_t *)_udata; /* User data for callback */ FUNC_ENTER_STATIC_NOERR /* Sanity checks */ HDassert(udata); + HDassert(udata->par_info); + HDassert(udata->par_info->hdr); HDassert(image_len); + /* Set the image length size */ *image_len = (size_t)H5HF_MAN_INDIRECT_SIZE(udata->par_info->hdr, *udata->nrows); FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5HF__cache_iblock_get_load_size() */ +} /* end H5HF__cache_iblock_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_iblock_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5HF__cache_iblock_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF__cache_iblock_verify_chksum() */ -/***********************************************************/ -/* metadata cache callback definitions for indirect blocks */ -/***********************************************************/ /*------------------------------------------------------------------------- @@ -890,7 +947,6 @@ H5HF__cache_iblock_deserialize(const void *_image, size_t len, void *_udata, const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ haddr_t heap_addr; /* Address of heap header in the file */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ unsigned u; /* Local index variable */ void * ret_value = NULL; /* Return value */ @@ -1017,8 +1073,7 @@ H5HF__cache_iblock_deserialize(const void *_image, size_t len, void *_udata, /* Sanity check */ HDassert(iblock->nchildren); /* indirect blocks w/no children should have been deleted */ - /* Compute checksum on indirect block */ - computed_chksum = H5_checksum_metadata((const uint8_t *)_image, (size_t)(image - (const uint8_t *)_image), 0); + /* checksum verification already done by verify_chksum cb */ /* Metadata checksum */ UINT32DECODE(image, stored_chksum); @@ -1026,10 +1081,6 @@ H5HF__cache_iblock_deserialize(const void *_image, size_t len, void *_udata, /* Sanity check */ HDassert((size_t)(image - (const uint8_t *)_image) == iblock->size); - /* Verify checksum */ - if(stored_chksum != computed_chksum) - HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "incorrect metadata checksum for fractal heap indirect block") - /* Check if we have any indirect block children */ if(iblock->nrows > hdr->man_dtable.max_direct_rows) { unsigned indir_rows;/* Number of indirect rows in this indirect block */ @@ -1481,7 +1532,7 @@ done: /*------------------------------------------------------------------------- - * Function: H5HF__cache_dblock_get_load_size() + * Function: H5HF__cache_dblock_get_initial_load_size() * * Purpose: Determine the size of the direct block on disk image, and * return it in *image_len. @@ -1495,44 +1546,158 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5HF__cache_dblock_get_load_size(const void *_udata, size_t *image_len) +H5HF__cache_dblock_get_initial_load_size(void *_udata, size_t *image_len) { const H5HF_dblock_cache_ud_t *udata = (const H5HF_dblock_cache_ud_t *)_udata; /* User data for callback */ - const H5HF_parent_t *par_info; /* Pointer to parent information */ - const H5HF_hdr_t *hdr; /* Shared fractal heap information */ - size_t size; + const H5HF_parent_t *par_info; /* Pointer to parent information */ + const H5HF_hdr_t *hdr; /* Shared fractal heap information */ FUNC_ENTER_STATIC_NOERR /* Sanity checks */ HDassert(udata); HDassert(image_len); + + /* Convenience variables */ par_info = (const H5HF_parent_t *)(&(udata->par_info)); HDassert(par_info); hdr = par_info->hdr; HDassert(hdr); - HDassert(hdr->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); - HDassert(hdr->cache_info.type == H5AC_FHEAP_HDR); /* Check for I/O filters on this heap */ if(hdr->filter_len > 0) { /* Check for root direct block */ if(par_info->iblock == NULL) - size = hdr->pline_root_direct_size; + /* filtered root direct block */ + *image_len = hdr->pline_root_direct_size; else - size = par_info->iblock->filt_ents[par_info->entry].size; + /* filtered direct block */ + *image_len = par_info->iblock->filt_ents[par_info->entry].size; + } /* end if */ + else + *image_len = udata->dblock_size; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5HF__cache_dblock_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5HF__cache_dblock_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5HF__cache_dblock_verify_chksum(const void *_image, size_t len, void *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5HF_dblock_cache_ud_t *udata = (H5HF_dblock_cache_ud_t *)_udata; /* User data for callback */ + void *read_buf = NULL; /* Pointer to buffer to read in */ + H5HF_hdr_t *hdr; /* Shared fractal heap information */ + H5HF_parent_t *par_info; /* Pointer to parent information */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + size_t chk_size; /* The size for validating checksum */ + uint8_t *chk_p; /* Pointer to the area for validating checksum */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(image); + HDassert(udata); + par_info = (H5HF_parent_t *)(&(udata->par_info)); + HDassert(par_info); + hdr = par_info->hdr; + HDassert(hdr); + + /* Reset callback context info */ + udata->decompressed = FALSE; + udata->dblk = NULL; + + /* Get out if data block is not checksummed */ + if(!(hdr->checksum_dblocks)) + HGOTO_DONE(TRUE); + + if(hdr->filter_len > 0) { + size_t nbytes; /* Number of bytes used in buffer, after applying reverse filters */ + unsigned filter_mask; /* Excluded filters for direct block */ + H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */ + + /* Allocate buffer to perform I/O filtering on and copy image into + * it. Must do this as H5Z_pipeline() may re-size the buffer + * provided to it. + */ + if(NULL == (read_buf = H5MM_malloc(len))) + HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, FAIL, "memory allocation failed for pipeline buffer") + + /* Set up parameters for filter pipeline */ + nbytes = len; + filter_mask = udata->filter_mask; + HDmemcpy(read_buf, image, len); + + /* Push direct block data through I/O filter pipeline */ + if(H5Z_pipeline(&(hdr->pline), H5Z_FLAG_REVERSE, &filter_mask, H5Z_ENABLE_EDC, filter_cb, &nbytes, &len, &read_buf) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFILTER, FAIL, "output pipeline failed") + + /* Update info about direct block */ + udata->decompressed = TRUE; + len = nbytes; } /* end if */ else - size = udata->dblock_size; + read_buf = (void *)image; /* Casting away const OK - QAK */ - *image_len = size; + /* Decode checksum */ + chk_size = (size_t)(H5HF_MAN_ABS_DIRECT_OVERHEAD(hdr) - H5HF_SIZEOF_CHKSUM); + chk_p = (uint8_t *)read_buf + chk_size; - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5HF__cache_dblock_get_load_size() */ + /* Metadata checksum */ + UINT32DECODE(chk_p, stored_chksum); + + chk_p -= H5HF_SIZEOF_CHKSUM; + + /* Reset checksum field, for computing the checksum */ + /* (Casting away const OK - QAK) */ + HDmemset(chk_p, 0, (size_t)H5HF_SIZEOF_CHKSUM); -/*********************************************************/ -/* metadata cache callback definitions for direct blocks */ -/*********************************************************/ + /* Compute checksum on entire direct block */ + computed_chksum = H5_checksum_metadata(read_buf, len, 0); + + /* Restore the checksum */ + UINT32ENCODE(chk_p, stored_chksum) + + /* Verify checksum */ + if(stored_chksum != computed_chksum) + HGOTO_DONE(FALSE); + + /* Save the decompressed data to be used later in deserialize callback */ + if(hdr->filter_len > 0) { + /* Sanity check */ + HDassert(udata->decompressed); + HDassert(len == udata->dblock_size); + + /* Allocate block buffer */ + if(NULL == (udata->dblk = H5FL_BLK_MALLOC(direct_block, (size_t)len))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + + /* Copy un-filtered data into block's buffer */ + HDmemcpy(udata->dblk, read_buf, len); + } /* end if */ + +done: + /* Release the read buffer */ + if(read_buf && read_buf != image) + H5MM_xfree(read_buf); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HF__cache_dblock_verify_chksum() */ /*------------------------------------------------------------------------- @@ -1563,14 +1728,15 @@ H5HF__cache_dblock_deserialize(const void *_image, size_t len, void *_udata, H5HF_dblock_cache_ud_t *udata = (H5HF_dblock_cache_ud_t *)_udata; /* User data for callback */ H5HF_parent_t *par_info; /* Pointer to parent information */ H5HF_direct_t *dblock = NULL; /* Direct block info */ - const uint8_t *image; /* Pointer into raw data buffer */ + const uint8_t *image = _image;/* Pointer into raw data buffer */ + void *read_buf = NULL; /* Pointer to buffer to decompress */ haddr_t heap_addr; /* Address of heap header in the file */ void * ret_value = NULL; /* Return value */ FUNC_ENTER_STATIC /* Sanity checks */ - HDassert(_image); + HDassert(image); HDassert(udata); par_info = (H5HF_parent_t *)(&(udata->par_info)); HDassert(par_info); @@ -1581,7 +1747,7 @@ H5HF__cache_dblock_deserialize(const void *_image, size_t len, void *_udata, HDassert(dirty); /* Allocate space for the fractal heap direct block */ - if(NULL == (dblock = H5FL_MALLOC(H5HF_direct_t))) + if(NULL == (dblock = H5FL_CALLOC(H5HF_direct_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") HDmemset(&dblock->cache_info, 0, sizeof(H5AC_info_t)); @@ -1595,61 +1761,62 @@ H5HF__cache_dblock_deserialize(const void *_image, size_t len, void *_udata, /* Set block's internal information */ dblock->size = udata->dblock_size; - dblock->file_size = 0; - - /* initialize fields used in serialization */ - dblock->write_buf = NULL; - dblock->write_size = 0; - - /* Allocate block buffer */ -/* XXX: Change to using free-list factories */ - if(NULL == (dblock->blk = H5FL_BLK_MALLOC(direct_block, (size_t)dblock->size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") /* Check for I/O filters on this heap */ if(hdr->filter_len > 0) { - H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */ - size_t nbytes; /* Number of bytes used in buffer, after applying reverse filters */ - void *read_buf; /* Pointer to buffer to read in */ - size_t read_size; /* Size of filtered direct block to read */ - unsigned filter_mask; /* Excluded filters for direct block */ + /* Direct block is already decompressed in verify_chksum callback */ + if(udata->decompressed) { + /* Sanity check */ + HDassert(udata->dblk); - /* Check for root direct block */ - if(par_info->iblock == NULL) - /* Set up parameters to read filtered direct block */ - read_size = hdr->pline_root_direct_size; - else - /* Set up parameters to read filtered direct block */ - read_size = par_info->iblock->filt_ents[par_info->entry].size; - HDassert(len == read_size); + /* Take ownership of the decompressed direct block */ + dblock->blk = udata->dblk; + udata->dblk = NULL; + } /* end if */ + else { + H5Z_cb_t filter_cb = {NULL, NULL}; /* Filter callback structure */ + size_t nbytes; /* Number of bytes used in buffer, after applying reverse filters */ + unsigned filter_mask; /* Excluded filters for direct block */ - /* Allocate buffer to perform I/O filtering on and copy image into - * it. Must do this as H5Z_pipeline() may re-sized the buffer - * provided to it. - */ - if(NULL == (read_buf = H5MM_malloc(read_size))) - HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, NULL, "memory allocation failed for pipeline buffer") - HDmemcpy(read_buf, _image, len); + /* Sanity check */ + HDassert(udata->dblk == NULL); - /* Push direct block data through I/O filter pipeline */ - nbytes = read_size; - filter_mask = udata->filter_mask; - if(H5Z_pipeline(&(hdr->pline), H5Z_FLAG_REVERSE, &filter_mask, H5Z_ENABLE_EDC, filter_cb, &nbytes, &read_size, &read_buf) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTFILTER, NULL, "output pipeline failed") + /* Allocate buffer to perform I/O filtering on and copy image into + * it. Must do this as H5Z_pipeline() may resize the buffer + * provided to it. + */ + if(NULL == (read_buf = H5MM_malloc(len))) + HGOTO_ERROR(H5E_HEAP, H5E_NOSPACE, NULL, "memory allocation failed for pipeline buffer") - /* Sanity check */ - HDassert(nbytes == dblock->size); + /* Copy compressed image into buffer */ + HDmemcpy(read_buf, image, len); - /* Copy un-filtered data into block's buffer */ - HDmemcpy(dblock->blk, read_buf, dblock->size); + /* Push direct block data through I/O filter pipeline */ + nbytes = len; + filter_mask = udata->filter_mask; + if(H5Z_pipeline(&(hdr->pline), H5Z_FLAG_REVERSE, &filter_mask, H5Z_ENABLE_EDC, filter_cb, &nbytes, &len, &read_buf) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTFILTER, NULL, "output pipeline failed") - /* Release the read buffer */ - H5MM_xfree(read_buf); + /* Sanity check */ + HDassert(nbytes == dblock->size); + + /* Copy un-filtered data into block's buffer */ + HDmemcpy(dblock->blk, read_buf, dblock->size); + } /* end if */ } /* end if */ else { - /* copy image to dblock->blk */ + /* Sanity checks */ + HDassert(udata->dblk == NULL); + HDassert(!udata->decompressed); + + /* Allocate block buffer */ +/* XXX: Change to using free-list factories */ + if(NULL == (dblock->blk = H5FL_BLK_MALLOC(direct_block, (size_t)dblock->size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + + /* Copy image to dblock->blk */ HDassert(dblock->size == len); - HDmemcpy(dblock->blk, _image, dblock->size); + HDmemcpy(dblock->blk, image, dblock->size); } /* end else */ /* Start decoding direct block */ @@ -1684,22 +1851,12 @@ H5HF__cache_dblock_deserialize(const void *_image, size_t len, void *_udata, /* Decode checksum on direct block, if requested */ if(hdr->checksum_dblocks) { - uint32_t stored_chksum; /* Metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ + uint32_t stored_chksum; /* Metadata checksum value */ + + /* checksum verification already done in verify_chksum cb */ /* Metadata checksum */ UINT32DECODE(image, stored_chksum); - - /* Reset checksum field, for computing the checksum */ - /* (Casting away const OK - QAK) */ - HDmemset((uint8_t *)image - H5HF_SIZEOF_CHKSUM, 0, (size_t)H5HF_SIZEOF_CHKSUM); - - /* Compute checksum on entire direct block */ - computed_chksum = H5_checksum_metadata(dblock->blk, dblock->size, 0); - - /* Verify checksum */ - if(stored_chksum != computed_chksum) - HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "incorrect metadata checksum for fractal heap direct block") } /* end if */ /* Sanity check */ @@ -1709,6 +1866,11 @@ H5HF__cache_dblock_deserialize(const void *_image, size_t len, void *_udata, ret_value = (void *)dblock; done: + /* Release the read buffer */ + if(read_buf) + H5MM_xfree(read_buf); + + /* Cleanup on error */ if(!ret_value && dblock) if(H5HF_man_dblock_dest(dblock) < 0) HDONE_ERROR(H5E_HEAP, H5E_CANTFREE, NULL, "unable to destroy fractal heap direct block") diff --git a/src/H5HFpkg.h b/src/H5HFpkg.h index 6253160..6abae65 100644 --- a/src/H5HFpkg.h +++ b/src/H5HFpkg.h @@ -544,6 +544,14 @@ typedef struct H5HF_dblock_cache_ud_t { * calls to it. */ unsigned filter_mask; /* Excluded filters for direct block */ + uint8_t *dblk; /* Pointer to the buffer containing the decompressed + * direct block data obtained in verify_chksum callback. + * It will be used later in deserialize callback. + */ + htri_t decompressed; /* Indicate that the direct block has been + * decompressed in verify_chksum callback. + * It will be used later in deserialize callback. + */ } H5HF_dblock_cache_ud_t; diff --git a/src/H5HGcache.c b/src/H5HGcache.c index b01f30e..6bc9860 100644 --- a/src/H5HGcache.c +++ b/src/H5HGcache.c @@ -62,7 +62,9 @@ /********************/ /* Metadata cache callbacks */ -static herr_t H5HG__cache_heap_get_load_size(const void *udata, size_t *image_len); +static herr_t H5HG__cache_heap_get_initial_load_size(void *udata, size_t *image_len); +static herr_t H5HG__cache_heap_get_final_load_size(const void *_image, + size_t image_len, void *udata, size_t *actual_len); static void *H5HG__cache_heap_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5HG__cache_heap_image_len(const void *thing, size_t *image_len); @@ -81,7 +83,9 @@ const H5AC_class_t H5AC_GHEAP[1] = {{ "global heap", /* Metadata client name (for debugging) */ H5FD_MEM_GHEAP, /* File space memory type for client */ H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */ - H5HG__cache_heap_get_load_size, /* 'get_load_size' callback */ + H5HG__cache_heap_get_initial_load_size, /* 'get_initial_load_size' callback */ + H5HG__cache_heap_get_final_load_size, /* 'get_final_load_size' callback */ + NULL, /* 'verify_chksum' callback */ H5HG__cache_heap_deserialize, /* 'deserialize' callback */ H5HG__cache_heap_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -104,13 +108,13 @@ const H5AC_class_t H5AC_GHEAP[1] = {{ /*------------------------------------------------------------------------- - * Function: H5HG__cache_heap_get_load_size() + * Function: H5HG__cache_heap_get_initial_load_size() * * Purpose: Return the initial speculative read size to the metadata * cache. This size will be used in the initial attempt to read * the global heap. If this read is too small, the cache will * try again with the correct value obtained from - * H5HG__cache_heap_image_len(). + * H5HG__cache_get_final_load_size(). * * Return: Success: SUCCEED * Failure: FAIL @@ -121,16 +125,74 @@ const H5AC_class_t H5AC_GHEAP[1] = {{ *------------------------------------------------------------------------- */ static herr_t -H5HG__cache_heap_get_load_size(const void H5_ATTR_UNUSED *_udata, size_t *image_len) +H5HG__cache_heap_get_initial_load_size(void H5_ATTR_UNUSED *_udata, size_t *image_len) { FUNC_ENTER_STATIC_NOERR + /* Sanity check */ HDassert(image_len); + /* Set the image length size */ *image_len = (size_t)H5HG_MINSIZE; FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5HG__cache_heap_get_load_size() */ +} /* end H5HG__cache_heap_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5HG__cache_heap_get_initial_load_size() + * + * Purpose: Return the final read size for a speculatively ready heap to + * the metadata cache. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Quincey Koziol + * November 18, 2016 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HG__cache_heap_get_final_load_size(const void *_image, size_t image_len, + void *_udata, size_t *actual_len) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5F_t *f = (H5F_t *)_udata; /* File pointer -- obtained from user data */ + size_t heap_size = 0; /* Total size of collection */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity check */ + HDassert(image); + HDassert(f); + HDassert(actual_len); + HDassert(*actual_len == image_len); + + /* Magic number */ + if(HDmemcmp(image, H5HG_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "bad global heap collection signature") + image += H5_SIZEOF_MAGIC; + + /* Version */ + if(H5HG_VERSION != *image++) + HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "wrong version number in global heap") + + /* Reserved */ + image += 3; + + /* Size */ + H5F_DECODE_LENGTH(f, image, heap_size); + HDassert(heap_size >= H5HG_MINSIZE); + HDassert(image_len == H5HG_MINSIZE); + + /* Set the final size for the cache image */ + *actual_len = heap_size; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HG__cache_heap_get_final_load_size() */ /*------------------------------------------------------------------------- @@ -140,10 +202,6 @@ H5HG__cache_heap_get_load_size(const void H5_ATTR_UNUSED *_udata, size_t *image_ * heap, deserialize it, load its contents into a newly allocated * instance of H5HG_heap_t, and return a pointer to the new instance. * - * Note that this heap client uses speculative reads. If the supplied - * buffer is too small, we simply make note of the correct size, and - * wait for the metadata cache to try again. - * * Return: Success: Pointer to in core representation * Failure: NULL * @@ -159,6 +217,8 @@ H5HG__cache_heap_deserialize(const void *_image, size_t len, void *_udata, H5F_t *f = (H5F_t *)_udata; /* File pointer -- obtained from user data */ H5HG_heap_t *heap = NULL; /* New global heap */ uint8_t *image; /* Pointer to image to decode */ + size_t max_idx = 0; /* Maximum heap object index seen */ + size_t nalloc; /* Number of objects allocated */ void *ret_value = NULL; /* Return value */ FUNC_ENTER_STATIC @@ -199,109 +259,98 @@ H5HG__cache_heap_deserialize(const void *_image, size_t len, void *_udata, HDassert((len == H5HG_MINSIZE) /* first try */ || ((len == heap->size) && (len > H5HG_MINSIZE))); /* second try */ - if(len == heap->size) { /* proceed with the deserialize */ - size_t max_idx = 0; - size_t nalloc; - - /* Decode each object */ - image = heap->chunk + H5HG_SIZEOF_HDR(f); - nalloc = H5HG_NOBJS(f, heap->size); - - /* Calloc the obj array because the file format spec makes no guarantee - * about the order of the objects, and unused slots must be set to zero. - */ - if(NULL == (heap->obj = H5FL_SEQ_CALLOC(H5HG_obj_t, nalloc))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - heap->nalloc = nalloc; - - while(image < (heap->chunk + heap->size)) { - if((image + H5HG_SIZEOF_OBJHDR(f)) > (heap->chunk + heap->size)) { - /* - * The last bit of space is too tiny for an object header, so - * we assume that it's free space. - */ - HDassert(NULL == heap->obj[0].begin); - heap->obj[0].size = (size_t)(((const uint8_t *)heap->chunk + heap->size) - image); - heap->obj[0].begin = image; - image += heap->obj[0].size; + /* Decode each object */ + image = heap->chunk + H5HG_SIZEOF_HDR(f); + nalloc = H5HG_NOBJS(f, heap->size); + + /* Calloc the obj array because the file format spec makes no guarantee + * about the order of the objects, and unused slots must be set to zero. + */ + if(NULL == (heap->obj = H5FL_SEQ_CALLOC(H5HG_obj_t, nalloc))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + heap->nalloc = nalloc; + + while(image < (heap->chunk + heap->size)) { + if((image + H5HG_SIZEOF_OBJHDR(f)) > (heap->chunk + heap->size)) { + /* + * The last bit of space is too tiny for an object header, so + * we assume that it's free space. + */ + HDassert(NULL == heap->obj[0].begin); + heap->obj[0].size = (size_t)(((const uint8_t *)heap->chunk + heap->size) - image); + heap->obj[0].begin = image; + image += heap->obj[0].size; + } /* end if */ + else { + size_t need; + unsigned idx; + uint8_t *begin = image; + + UINT16DECODE(image, idx); + + /* Check if we need more room to store heap objects */ + if(idx >= heap->nalloc) { + size_t new_alloc; /* New allocation number */ + H5HG_obj_t *new_obj; /* New array of object descriptions */ + + /* Determine the new number of objects to index */ + new_alloc = MAX(heap->nalloc * 2, (idx + 1)); + HDassert(idx < new_alloc); + + /* Reallocate array of objects */ + if(NULL == (new_obj = H5FL_SEQ_REALLOC(H5HG_obj_t, heap->obj, new_alloc))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + + /* Clear newly allocated space */ + HDmemset(&new_obj[heap->nalloc], 0, (new_alloc - heap->nalloc) * sizeof(heap->obj[0])); + + /* Update heap information */ + heap->nalloc = new_alloc; + heap->obj = new_obj; + HDassert(heap->nalloc > heap->nused); + } /* end if */ + + UINT16DECODE(image, heap->obj[idx].nrefs); + image += 4; /*reserved*/ + H5F_DECODE_LENGTH(f, image, heap->obj[idx].size); + heap->obj[idx].begin = begin; + + /* + * The total storage size includes the size of the object + * header and is zero padded so the next object header is + * properly aligned. The entire obj array was calloc'ed, + * so no need to zero the space here. The last bit of space + * is the free space object whose size is never padded and + * already includes the object header. + */ + if(idx > 0) { + need = H5HG_SIZEOF_OBJHDR(f) + H5HG_ALIGN(heap->obj[idx].size); + if(idx > max_idx) + max_idx = idx; } /* end if */ - else { - size_t need; - unsigned idx; - uint8_t *begin = image; - - UINT16DECODE(image, idx); - - /* Check if we need more room to store heap objects */ - if(idx >= heap->nalloc) { - size_t new_alloc; /* New allocation number */ - H5HG_obj_t *new_obj; /* New array of object descriptions */ - - /* Determine the new number of objects to index */ - new_alloc = MAX(heap->nalloc * 2, (idx + 1)); - HDassert(idx < new_alloc); - - /* Reallocate array of objects */ - if(NULL == (new_obj = H5FL_SEQ_REALLOC(H5HG_obj_t, heap->obj, new_alloc))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") - - /* Clear newly allocated space */ - HDmemset(&new_obj[heap->nalloc], 0, (new_alloc - heap->nalloc) * sizeof(heap->obj[0])); - - /* Update heap information */ - heap->nalloc = new_alloc; - heap->obj = new_obj; - HDassert(heap->nalloc > heap->nused); - } /* end if */ - - UINT16DECODE(image, heap->obj[idx].nrefs); - image += 4; /*reserved*/ - H5F_DECODE_LENGTH(f, image, heap->obj[idx].size); - heap->obj[idx].begin = begin; - - /* - * The total storage size includes the size of the object - * header and is zero padded so the next object header is - * properly aligned. The entire obj array was calloc'ed, - * so no need to zero the space here. The last bit of space - * is the free space object whose size is never padded and - * already includes the object header. - */ - if(idx > 0) { - need = H5HG_SIZEOF_OBJHDR(f) + H5HG_ALIGN(heap->obj[idx].size); - if(idx > max_idx) - max_idx = idx; - } /* end if */ - else - need = heap->obj[idx].size; - - image = begin + need; - } /* end else */ - } /* end while */ - - HDassert(image == heap->chunk + heap->size); - HDassert(H5HG_ISALIGNED(heap->obj[0].size)); - - /* Set the next index value to use */ - if(max_idx > 0) - heap->nused = max_idx + 1; - else - heap->nused = 1; - - HDassert(max_idx < heap->nused); - - /* Add the new heap to the CWFS list for the file */ - if(H5F_cwfs_add(f, heap) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "unable to add global heap collection to file's CWFS") - } /* end if ( len == heap->size ) */ + else + need = heap->obj[idx].size; + + image = begin + need; + } /* end else */ + } /* end while */ + + /* Sanity checks */ + HDassert(image == heap->chunk + heap->size); + HDassert(H5HG_ISALIGNED(heap->obj[0].size)); + + /* Set the next index value to use */ + if(max_idx > 0) + heap->nused = max_idx + 1; else - /* if len is less than heap size, then the initial speculative - * read was too small. In this case we return without reporting - * failure. H5C_load_entry() will call H5HG__cache_heap_image_len() - * to get the actual read size, and then repeat the read with the - * correct size, and call this function a second time. - */ - HDassert(len < heap->size); + heap->nused = 1; + + /* Sanity check */ + HDassert(max_idx < heap->nused); + + /* Add the new heap to the CWFS list for the file */ + if(H5F_cwfs_add(f, heap) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "unable to add global heap collection to file's CWFS") ret_value = heap; @@ -347,10 +396,6 @@ H5HG__cache_heap_image_len(const void *_thing, size_t *image_len) FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5HG__cache_heap_image_len() */ -/**************************************/ -/* no H5HG_cache_heap_pre_serialize() */ -/**************************************/ - /*------------------------------------------------------------------------- * Function: H5HG__cache_heap_serialize @@ -390,10 +435,6 @@ H5HG__cache_heap_serialize(const H5F_t *f, void *image, size_t len, FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5HG__cache_heap_serialize() */ -/****************************************/ -/* no H5HG_cache_heap_notify() function */ -/****************************************/ - /*------------------------------------------------------------------------- * Function: H5HG__cache_heap_free_icr diff --git a/src/H5HL.c b/src/H5HL.c index 7ad2e3c..9af1119 100644 --- a/src/H5HL.c +++ b/src/H5HL.c @@ -341,12 +341,10 @@ H5HL_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, unsigned flags)) HDassert((flags & (unsigned)(~H5AC__READ_ONLY_FLAG)) == 0); /* Construct the user data for protect callback */ - prfx_udata.made_attempt = FALSE; prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f); prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f); prfx_udata.prfx_addr = addr; prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f); - prfx_udata.loaded = FALSE; /* Protect the local heap prefix */ if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, flags))) @@ -359,25 +357,14 @@ H5HL_protect(H5F_t *f, hid_t dxpl_id, haddr_t addr, unsigned flags)) /* (for re-entrant situation) */ if(heap->prots == 0) { /* Check if heap has separate data block */ - if(heap->single_cache_obj) { + if(heap->single_cache_obj) /* Set the flag for pinning the prefix when unprotecting it */ prfx_cache_flags |= H5AC__PIN_ENTRY_FLAG; - } /* end if */ else { - H5HL_cache_dblk_ud_t dblk_udata; /* User data for protecting local heap data block */ - - /* Construct the user data for protect callback */ - dblk_udata.heap = heap; - dblk_udata.loaded = FALSE; - /* Protect the local heap data block */ - if(NULL == (dblk = (H5HL_dblk_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_DBLK, heap->dblk_addr, &dblk_udata, flags))) + if(NULL == (dblk = (H5HL_dblk_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_DBLK, heap->dblk_addr, heap, flags))) H5E_THROW(H5E_CANTPROTECT, "unable to load heap data block"); - /* Pin the prefix, if the data block was loaded from file */ - if(dblk_udata.loaded) - prfx_cache_flags |= H5AC__PIN_ENTRY_FLAG; - /* Set the flag for pinning the data block when unprotecting it */ dblk_cache_flags |= H5AC__PIN_ENTRY_FLAG; } /* end if */ @@ -931,12 +918,10 @@ H5HL_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr)) HDassert(H5F_addr_defined(addr)); /* Construct the user data for protect callback */ - prfx_udata.made_attempt = FALSE; prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f); prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f); prfx_udata.prfx_addr = addr; prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f); - prfx_udata.loaded = FALSE; /* Protect the local heap prefix */ if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC__NO_FLAGS_SET))) @@ -946,24 +931,11 @@ H5HL_delete(H5F_t *f, hid_t dxpl_id, haddr_t addr)) heap = prfx->heap; /* Check if heap has separate data block */ - if(!heap->single_cache_obj) { - H5HL_cache_dblk_ud_t dblk_udata; /* User data for protecting local heap data block */ - - /* Construct the user data for protect callback */ - dblk_udata.heap = heap; - dblk_udata.loaded = FALSE; - + if(!heap->single_cache_obj) /* Protect the local heap data block */ - if(NULL == (dblk = (H5HL_dblk_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_DBLK, heap->dblk_addr, &dblk_udata, H5AC__NO_FLAGS_SET))) + if(NULL == (dblk = (H5HL_dblk_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_DBLK, heap->dblk_addr, heap, H5AC__NO_FLAGS_SET))) H5E_THROW(H5E_CANTPROTECT, "unable to load heap data block"); - /* Pin the prefix, if the data block was loaded from file */ - if(dblk_udata.loaded) { - if(FAIL == H5AC_pin_protected_entry(prfx)) - H5E_THROW(H5E_CANTPIN, "unable to pin local heap prefix"); - } /* end if */ - } /* end if */ - /* Set the flags for releasing the prefix and data block */ cache_flags |= H5AC__DIRTIED_FLAG | H5AC__DELETED_FLAG | H5AC__FREE_FILE_SPACE_FLAG; @@ -1005,12 +977,10 @@ H5HL_get_size(H5F_t *f, hid_t dxpl_id, haddr_t addr, size_t *size)) HDassert(size); /* Construct the user data for protect callback */ - prfx_udata.made_attempt = FALSE; prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f); prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f); prfx_udata.prfx_addr = addr; prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f); - prfx_udata.loaded = FALSE; /* Protect the local heap prefix */ if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC__READ_ONLY_FLAG))) @@ -1056,12 +1026,10 @@ H5HL_heapsize(H5F_t *f, hid_t dxpl_id, haddr_t addr, hsize_t *heap_size)) HDassert(heap_size); /* Construct the user data for protect callback */ - prfx_udata.made_attempt = FALSE; prfx_udata.sizeof_size = H5F_SIZEOF_SIZE(f); prfx_udata.sizeof_addr = H5F_SIZEOF_ADDR(f); prfx_udata.prfx_addr = addr; prfx_udata.sizeof_prfx = H5HL_SIZEOF_HDR(f); - prfx_udata.loaded = FALSE; /* Protect the local heap prefix */ if(NULL == (prfx = (H5HL_prfx_t *)H5AC_protect(f, dxpl_id, H5AC_LHEAP_PRFX, addr, &prfx_udata, H5AC__READ_ONLY_FLAG))) diff --git a/src/H5HLcache.c b/src/H5HLcache.c index 5697121..c53292a 100644 --- a/src/H5HLcache.c +++ b/src/H5HLcache.c @@ -71,7 +71,9 @@ /* Metadata cache callbacks */ /* Local heap prefix */ -static herr_t H5HL__cache_prefix_get_load_size(const void *udata, size_t *image_len); +static herr_t H5HL__cache_prefix_get_initial_load_size(void *udata, size_t *image_len); +static herr_t H5HL__cache_prefix_get_final_load_size(const void *_image, + size_t image_len, void *udata, size_t *actual_len); static void *H5HL__cache_prefix_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5HL__cache_prefix_image_len(const void *thing, size_t *image_len); @@ -80,13 +82,13 @@ static herr_t H5HL__cache_prefix_serialize(const H5F_t *f, void *image, static herr_t H5HL__cache_prefix_free_icr(void *thing); /* Local heap data block */ -static herr_t H5HL__cache_datablock_get_load_size(const void *udata, - size_t *image_len); +static herr_t H5HL__cache_datablock_get_initial_load_size(void *udata, size_t *image_len); static void *H5HL__cache_datablock_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5HL__cache_datablock_image_len(const void *thing, size_t *image_len); static herr_t H5HL__cache_datablock_serialize(const H5F_t *f, void *image, size_t len, void *thing); +static herr_t H5HL__cache_datablock_notify(H5C_notify_action_t action, void *_thing); static herr_t H5HL__cache_datablock_free_icr(void *thing); /* Free list de/serialization */ @@ -103,7 +105,9 @@ const H5AC_class_t H5AC_LHEAP_PRFX[1] = {{ "local heap prefix", /* Metadata client name (for debugging) */ H5FD_MEM_LHEAP, /* File space memory type for client */ H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */ - H5HL__cache_prefix_get_load_size, /* 'get_load_size' callback */ + H5HL__cache_prefix_get_initial_load_size, /* 'get_initial_load_size' callback */ + H5HL__cache_prefix_get_final_load_size, /* 'get_final_load_size' callback */ + NULL, /* 'verify_chksum' callback */ H5HL__cache_prefix_deserialize, /* 'deserialize' callback */ H5HL__cache_prefix_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -118,12 +122,14 @@ const H5AC_class_t H5AC_LHEAP_DBLK[1] = {{ "local heap datablock", /* Metadata client name (for debugging) */ H5FD_MEM_LHEAP, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5HL__cache_datablock_get_load_size,/* 'get_load_size' callback */ + H5HL__cache_datablock_get_initial_load_size,/* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + NULL, /* 'verify_chksum' callback */ H5HL__cache_datablock_deserialize, /* 'deserialize' callback */ H5HL__cache_datablock_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ H5HL__cache_datablock_serialize, /* 'serialize' callback */ - NULL, /* 'notify' callback */ + H5HL__cache_datablock_notify, /* 'notify' callback */ H5HL__cache_datablock_free_icr, /* 'free_icr' callback */ NULL, /* 'fsf_size' callback */ }}; @@ -254,18 +260,11 @@ H5HL__fl_serialize(const H5HL_t *heap) /*------------------------------------------------------------------------- - * Function: H5HL__cache_prefix_get_load_size() + * Function: H5HL__cache_prefix_get_initial_load_size() * - * Purpose: Return the size of the buffer the metadata cache should + * Purpose: Return the initial size of the buffer the metadata cache should * load from file and pass to the deserialize routine. * - * The version 2 metadata cache callbacks included a test to - * ensure that the read did not pass the end of file, but this - * functionality has been moved to H5C_load_entry(). Thus - * all this function does is set *image_len equal to - * H5HL_SPEC_READ_SIZE, leaving it to the metadata cache to - * reduce the size of the read if appropriate. - * * Return: Success: SUCCEED * Failure: FAIL * @@ -275,16 +274,91 @@ H5HL__fl_serialize(const H5HL_t *heap) *------------------------------------------------------------------------- */ static herr_t -H5HL__cache_prefix_get_load_size(const void H5_ATTR_UNUSED *_udata, size_t *image_len) +H5HL__cache_prefix_get_initial_load_size(void H5_ATTR_UNUSED *_udata, size_t *image_len) { FUNC_ENTER_STATIC_NOERR + /* Sanity check */ HDassert(image_len); + /* Set the image length size */ *image_len = H5HL_SPEC_READ_SIZE; FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5HL__cache_prefix_get_load_size() */ +} /* end H5HL__cache_prefix_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5HL__cache_prefix_get_final_load_size() + * + * Purpose: Return the final size of the buffer the metadata cache should + * load from file and pass to the deserialize routine. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Quincey Koziol + * November 18, 2016 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HL__cache_prefix_get_final_load_size(const void *_image, size_t image_len, + void *_udata, size_t *actual_len) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5HL_cache_prfx_ud_t *udata = (H5HL_cache_prfx_ud_t *)_udata; /* User data for callback */ + H5HL_t heap; /* Local heap */ + htri_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(image); + HDassert(udata); + HDassert(actual_len); + HDassert(*actual_len == image_len); + + /* Check magic number */ + if(HDmemcmp(image, H5HL_MAGIC, (size_t)H5_SIZEOF_MAGIC)) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "bad local heap signature") + image += H5_SIZEOF_MAGIC; + + /* Version */ + if(H5HL_VERSION != *image++) + HGOTO_ERROR(H5E_HEAP, H5E_VERSION, FAIL, "wrong version number in local heap") + + /* Reserved */ + image += 3; + + /* Store the prefix's address & length */ + heap.prfx_addr = udata->prfx_addr; /* NEED */ + heap.prfx_size = udata->sizeof_prfx; /* NEED */ + + /* Heap data size */ + H5F_DECODE_LENGTH_LEN(image, heap.dblk_size, udata->sizeof_size); /* NEED */ + + /* Free list head */ + H5F_DECODE_LENGTH_LEN(image, heap.free_block, udata->sizeof_size); + if(heap.free_block != H5HL_FREE_NULL && heap.free_block >= heap.dblk_size) + HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, FAIL, "bad heap free list"); + + /* Heap data address */ + H5F_addr_decode_len(udata->sizeof_addr, &image, &(heap.dblk_addr)); /* NEED */ + + /* Set the final size for the cache image */ + *actual_len = heap.prfx_size; + + /* Check if heap block exists */ + if(heap.dblk_size) + /* Check if heap data block is contiguous with header */ + if(H5F_addr_eq((heap.prfx_addr + heap.prfx_size), heap.dblk_addr)) + /* Note that the heap should be a single object in the cache */ + *actual_len += heap.dblk_size; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HL__cache_prefix_get_final_load_size() */ /*------------------------------------------------------------------------- @@ -353,7 +427,6 @@ H5HL__cache_prefix_deserialize(const void *_image, size_t len, void *_udata, /* Free list head */ H5F_DECODE_LENGTH_LEN(image, heap->free_block, udata->sizeof_size); - if((heap->free_block != H5HL_FREE_NULL) && (heap->free_block >= heap->dblk_size)) HGOTO_ERROR(H5E_HEAP, H5E_BADVALUE, NULL, "bad heap free list") @@ -367,53 +440,29 @@ H5HL__cache_prefix_deserialize(const void *_image, size_t len, void *_udata, /* Note that the heap should be a single object in the cache */ heap->single_cache_obj = TRUE; - /* Check if the current buffer from the speculative read - * already has the heap data - */ - if(len >= (heap->prfx_size + heap->dblk_size)) { - /* Allocate space for the heap data image */ - if(NULL == (heap->dblk_image = H5FL_BLK_MALLOC(lheap_chunk, heap->dblk_size))) - HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "memory allocation failed") - - /* Set image to the start of the data block. This is necessary - * because there may be a gap between the used portion of the - * prefix and the data block due to alignment constraints. */ - image = ((const uint8_t *)_image) + heap->prfx_size; - - /* Copy the heap data from the speculative read buffer */ - HDmemcpy(heap->dblk_image, image, heap->dblk_size); - - /* Build free list */ - if(H5HL__fl_deserialize(heap) < 0) - HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't initialize free list") - } /* end if */ - else { - /* the supplied buffer is too small -- We have already made note - * of the correct size, so simply return success. H5C_load_entry() - * will notice the size discrepency, and re-try the load. - */ - - /* Make certain that this is the first try ... */ - HDassert(!udata->made_attempt); - - /* ... and mark the udata so that we know that we have used up - * our first try. - */ - udata->made_attempt = TRUE; - } /* end else */ + /* Allocate space for the heap data image */ + if(NULL == (heap->dblk_image = H5FL_BLK_MALLOC(lheap_chunk, heap->dblk_size))) + HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "memory allocation failed") + + /* Set image to the start of the data block. This is necessary + * because there may be a gap between the used portion of the + * prefix and the data block due to alignment constraints. */ + image = ((const uint8_t *)_image) + heap->prfx_size; + + /* Copy the heap data from the speculative read buffer */ + HDmemcpy(heap->dblk_image, image, heap->dblk_size); + + /* Build free list */ + if(H5HL__fl_deserialize(heap) < 0) + HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't initialize free list") } /* end if */ - else { + else /* Note that the heap should _NOT_ be a single * object in the cache */ heap->single_cache_obj = FALSE; - - } /* end else */ } /* end if */ - /* Set flag to indicate prefix from loaded from file */ - udata->loaded = TRUE; - /* Set return value */ ret_value = prfx; @@ -568,10 +617,6 @@ H5HL__cache_prefix_serialize(const H5F_t *f, void *_image, size_t len, FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5HL__cache_prefix_serialize() */ -/******************************************/ -/* no H5HL_cache_prefix_notify() function */ -/******************************************/ - /*------------------------------------------------------------------------- * Function: H5HL__cache_prefix_free_icr @@ -619,7 +664,7 @@ done: /*------------------------------------------------------------------------- - * Function: H5HL__cache_datablock_get_load_size() + * Function: H5HL__cache_datablock_get_initial_load_size() * * Purpose: Tell the metadata cache how large a buffer to read from * file when loading a datablock. In this case, we simply lookup @@ -634,22 +679,22 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5HL__cache_datablock_get_load_size(const void *_udata, size_t *image_len) +H5HL__cache_datablock_get_initial_load_size(void *_udata, size_t *image_len) { - const H5HL_cache_dblk_ud_t *udata = (const H5HL_cache_dblk_ud_t *)_udata; /* User data for callback */ + H5HL_t *heap = (H5HL_t *)_udata; /* User data for callback */ FUNC_ENTER_STATIC_NOERR /* Check arguments */ - HDassert(udata); - HDassert(udata->heap); - HDassert(udata->heap->dblk_size > 0); + HDassert(heap); + HDassert(heap->dblk_size > 0); HDassert(image_len); - *image_len = udata->heap->dblk_size; + /* Set the image length size */ + *image_len = heap->dblk_size; FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5HL__cache_datablock_get_load_size() */ +} /* end H5HL__cache_datablock_get_initial_load_size() */ /*------------------------------------------------------------------------- @@ -671,8 +716,8 @@ static void * H5HL__cache_datablock_deserialize(const void *image, size_t len, void *_udata, hbool_t H5_ATTR_UNUSED *dirty) { - H5HL_dblk_t *dblk = NULL; /* Local heap data block deserialized */ - H5HL_cache_dblk_ud_t *udata = (H5HL_cache_dblk_ud_t *)_udata; /* User data for callback */ + H5HL_dblk_t *dblk = NULL; /* Local heap data block deserialized */ + H5HL_t *heap = (H5HL_t *)_udata; /* User data for callback */ void *ret_value = NULL; /* Return value */ FUNC_ENTER_STATIC @@ -680,34 +725,30 @@ H5HL__cache_datablock_deserialize(const void *image, size_t len, void *_udata, /* Check arguments */ HDassert(image); HDassert(len > 0); - HDassert(udata); - HDassert(udata->heap); - HDassert(udata->heap->dblk_size == len); - HDassert(!udata->heap->single_cache_obj); - HDassert(NULL == udata->heap->dblk); + HDassert(heap); + HDassert(heap->dblk_size == len); + HDassert(!heap->single_cache_obj); + HDassert(NULL == heap->dblk); HDassert(dirty); /* Allocate space in memory for the heap data block */ - if(NULL == (dblk = H5HL__dblk_new(udata->heap))) + if(NULL == (dblk = H5HL__dblk_new(heap))) HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "memory allocation failed"); /* Check for heap still retaining image */ - if(NULL == udata->heap->dblk_image) { + if(NULL == heap->dblk_image) { /* Allocate space for the heap data image */ - if(NULL == (udata->heap->dblk_image = H5FL_BLK_MALLOC(lheap_chunk, udata->heap->dblk_size))) + if(NULL == (heap->dblk_image = H5FL_BLK_MALLOC(lheap_chunk, heap->dblk_size))) HGOTO_ERROR(H5E_HEAP, H5E_CANTALLOC, NULL, "can't allocate data block image buffer"); /* copy the datablock from the read buffer */ - HDmemcpy(udata->heap->dblk_image, image, len); + HDmemcpy(heap->dblk_image, image, len); /* Build free list */ - if(FAIL == H5HL__fl_deserialize(udata->heap)) + if(FAIL == H5HL__fl_deserialize(heap)) HGOTO_ERROR(H5E_HEAP, H5E_CANTINIT, NULL, "can't initialize free list"); } /* end if */ - /* Set flag to indicate data block from loaded from file */ - udata->loaded = TRUE; - /* Set return value */ ret_value = dblk; @@ -801,9 +842,73 @@ H5HL__cache_datablock_serialize(const H5F_t *f, void *image, size_t len, FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5HL__cache_datablock_serialize() */ -/*********************************************/ -/* no H5HL_cache_datablock_notify() function */ -/*********************************************/ + +/*------------------------------------------------------------------------- + * Function: H5HL__cache_datablock_notify + * + * Purpose: This function is used to create and destroy pinned + * relationships between datablocks and their prefix parent. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Quincey Koziol + * November 19, 2016 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5HL__cache_datablock_notify(H5C_notify_action_t action, void *_thing) +{ + H5HL_dblk_t *dblk = (H5HL_dblk_t *)_thing; /* Pointer to the local heap data block */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity check */ + HDassert(dblk); + + switch(action) { + case H5AC_NOTIFY_ACTION_AFTER_INSERT: + /* do nothing */ + break; + + case H5AC_NOTIFY_ACTION_AFTER_LOAD: + /* Sanity checks */ + HDassert(dblk->heap); + HDassert(dblk->heap->prfx); + + /* Pin the heap's prefix */ + if(FAIL == H5AC_pin_protected_entry(dblk->heap->prfx)) + HGOTO_ERROR(H5E_HEAP, H5E_CANTPIN, FAIL, "unable to pin local heap prefix") + break; + + case H5AC_NOTIFY_ACTION_AFTER_FLUSH: + case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED: + case H5AC_NOTIFY_ACTION_ENTRY_CLEANED: + case H5AC_NOTIFY_ACTION_CHILD_DIRTIED: + case H5AC_NOTIFY_ACTION_CHILD_CLEANED: + /* do nothing */ + break; + + case H5AC_NOTIFY_ACTION_BEFORE_EVICT: + /* Sanity checks */ + HDassert(dblk->heap); + HDassert(dblk->heap->prfx); + + /* Unpin the local heap prefix */ + if(FAIL == H5AC_unpin_entry(dblk->heap->prfx)) + HGOTO_ERROR(H5E_HEAP, H5E_CANTUNPIN, FAIL, "unable to unpin local heap prefix") + break; + + default: + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unknown action from metadata cache") + break; + } /* end switch */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5HL__cache_datablock_notify() */ /*------------------------------------------------------------------------- @@ -843,3 +948,4 @@ H5HL__cache_datablock_free_icr(void *_thing) done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5HL__cache_datablock_free_icr() */ + diff --git a/src/H5HLdblk.c b/src/H5HLdblk.c index 69e0334..f90562b 100644 --- a/src/H5HLdblk.c +++ b/src/H5HLdblk.c @@ -119,10 +119,9 @@ H5HL__dblk_new(H5HL_t *heap)) CATCH /* Ensure that the data block memory is deallocated on errors */ - if(!ret_value && dblk != NULL) { + if(!ret_value && dblk != NULL) /* H5FL_FREE always returns NULL so we can't check for errors */ dblk = H5FL_FREE(H5HL_dblk_t, dblk); - } END_FUNC(PKG) /* end H5HL__dblk_new() */ @@ -151,10 +150,6 @@ H5HL__dblk_dest(H5HL_dblk_t *dblk)) /* Unlink data block from heap */ dblk->heap->dblk = NULL; - /* Unpin the local heap prefix */ - if(FAIL == H5AC_unpin_entry(dblk->heap->prfx)) - H5E_THROW(H5E_CANTUNPIN, "can't unpin local heap prefix") - /* Decrement ref. count on heap data structure */ if(FAIL == H5HL__dec_rc(dblk->heap)) H5E_THROW(H5E_CANTDEC, "can't decrement heap ref. count") @@ -223,7 +218,6 @@ H5HL__dblk_realloc(H5F_t *f, hid_t dxpl_id, H5HL_t *heap, size_t new_heap_size)) /* Resize the heap prefix in the cache */ if(FAIL == H5AC_resize_entry(heap->prfx, (size_t)(heap->prfx_size + new_heap_size))) H5E_THROW(H5E_CANTRESIZE, "unable to resize heap in cache"); - } /* end if */ else { /* Sanity check */ @@ -233,7 +227,6 @@ H5HL__dblk_realloc(H5F_t *f, hid_t dxpl_id, H5HL_t *heap, size_t new_heap_size)) /* Resize the heap data block in the cache */ if(H5AC_resize_entry(heap->dblk, (size_t)new_heap_size) < 0) H5E_THROW(H5E_CANTRESIZE, "unable to resize heap (data block) in cache"); - } /* end else */ } /* end if */ else { @@ -280,3 +273,4 @@ CATCH } /* end if */ END_FUNC(PKG) /* end H5HL__dblk_realloc() */ + diff --git a/src/H5HLpkg.h b/src/H5HLpkg.h index fb8667b..7075b2a 100644 --- a/src/H5HLpkg.h +++ b/src/H5HLpkg.h @@ -131,28 +131,12 @@ struct H5HL_prfx_t { /* Callback information for loading local heap prefix from disk */ typedef struct H5HL_cache_prfx_ud_t { - /* Downwards */ - hbool_t made_attempt; /* Whether the deserialize routine */ - /* was already attempted */ size_t sizeof_size; /* Size of file sizes */ size_t sizeof_addr; /* Size of file addresses */ haddr_t prfx_addr; /* Address of prefix */ size_t sizeof_prfx; /* Size of heap prefix */ - - /* Upwards */ - hbool_t loaded; /* Whether prefix was loaded */ - /* from file */ } H5HL_cache_prfx_ud_t; -/* Callback information for loading local heap data block from disk */ -typedef struct H5HL_cache_dblk_ud_t { - /* Downwards */ - H5HL_t *heap; /* Local heap */ - - /* Upwards */ - hbool_t loaded; /* Whether data block was loaded from file */ -} H5HL_cache_dblk_ud_t; - /******************************/ /* Package Private Prototypes */ diff --git a/src/H5HLprfx.c b/src/H5HLprfx.c index 66c4dad..ed1c4db 100644 --- a/src/H5HLprfx.c +++ b/src/H5HLprfx.c @@ -118,10 +118,9 @@ H5HL__prfx_new(H5HL_t *heap)) CATCH /* Ensure that the prefix memory is deallocated on errors */ - if(!ret_value && prfx != NULL) { + if(!ret_value && prfx != NULL) /* H5FL_FREE always returns NULL so we can't check for errors */ prfx = H5FL_FREE(H5HL_prfx_t, prfx); - } END_FUNC(PKG) /* end H5HL__prfx_new() */ @@ -164,3 +163,4 @@ CATCH prfx = H5FL_FREE(H5HL_prfx_t, prfx); END_FUNC(PKG) /* end H5HL__prfx_dest() */ + diff --git a/src/H5O.c b/src/H5O.c index f12bfed..ff1e61a 100644 --- a/src/H5O.c +++ b/src/H5O.c @@ -1811,11 +1811,12 @@ H5O_protect(const H5O_loc_t *loc, hid_t dxpl_id, unsigned prot_flags) /* Construct the user data for protect callback */ udata.made_attempt = FALSE; udata.v1_pfx_nmesgs = 0; + udata.chunk0_size = 0; + udata.oh = NULL; udata.common.f = loc->file; udata.common.dxpl_id = dxpl_id; udata.common.file_intent = file_intent; udata.common.merged_null_msgs = 0; - udata.common.mesgs_modified = FALSE; HDmemset(&cont_msg_info, 0, sizeof(cont_msg_info)); udata.common.cont_msg_info = &cont_msg_info; udata.common.addr = loc->addr; @@ -1843,10 +1844,12 @@ H5O_protect(const H5O_loc_t *loc, hid_t dxpl_id, unsigned prot_flags) chk_udata.common.dxpl_id = dxpl_id; chk_udata.common.file_intent = file_intent; chk_udata.common.merged_null_msgs = udata.common.merged_null_msgs; - chk_udata.common.mesgs_modified = udata.common.mesgs_modified; chk_udata.common.cont_msg_info = &cont_msg_info; /* Read in continuation messages, until there are no more */ + /* (Note that loading chunks could increase the # of continuation + * messages if new ones are found - QAK, 19/11/2016) + */ curr_msg = 0; while(curr_msg < cont_msg_info.nmsgs) { H5O_chunk_proxy_t *chk_proxy; /* Proxy for chunk, to bring it into memory */ @@ -1879,16 +1882,12 @@ H5O_protect(const H5O_loc_t *loc, hid_t dxpl_id, unsigned prot_flags) /* Pass back out some of the chunk's user data */ udata.common.merged_null_msgs = chk_udata.common.merged_null_msgs; - udata.common.mesgs_modified = chk_udata.common.mesgs_modified; } /* end if */ /* Check for incorrect # of object header messages, if we've just loaded * this object header from the file */ if(udata.made_attempt) { - /* Check for incorrect # of messages in v1 object header */ - if(oh->version == H5O_VERSION_1 && - (oh->nmesgs + udata.common.merged_null_msgs) != udata.v1_pfx_nmesgs) { /* Don't enforce the error on an incorrect # of object header messages bug * unless strict format checking is enabled. This allows for older * files, created with a version of the library that had a bug in tracking @@ -1896,79 +1895,11 @@ H5O_protect(const H5O_loc_t *loc, hid_t dxpl_id, unsigned prot_flags) * erroring out here. -QAK */ #ifdef H5_STRICT_FORMAT_CHECKS + /* Check for incorrect # of messages in v1 object header */ + if(oh->version == H5O_VERSION_1 && + (oh->nmesgs + udata.common.merged_null_msgs) != udata.v1_pfx_nmesgs) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "corrupt object header - incorrect # of messages") -#else /* H5_STRICT_FORMAT_CHECKS */ - /* Mark object header prefix dirty later if we don't have write access */ - /* (object header will have been marked dirty during protect, if we - * have write access -QAK) - */ - if((prot_flags & H5AC__READ_ONLY_FLAG) != 0) - oh->prefix_modified = TRUE; -#ifndef NDEBUG - else { - unsigned oh_status = 0; /* Object header entry cache status */ - - /* Check the object header's status in the metadata cache */ - if(H5AC_get_entry_status(loc->file, loc->addr, &oh_status) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, NULL, "unable to check metadata cache status for object header") - - /* Make certain that object header is not dirty */ - HDassert(!(oh_status & H5AC_ES__IS_DIRTY)); - } /* end else */ -#endif /* NDEBUG */ #endif /* H5_STRICT_FORMAT_CHECKS */ - } /* end if */ - - /* Check for any messages that were modified while being read in */ - if(udata.common.mesgs_modified && (0 == (prot_flags & H5AC__READ_ONLY_FLAG))) - oh->mesgs_modified = TRUE; - - /* Reset the field that contained chunk 0's size during speculative load */ - oh->chunk0_size = 0; - } /* end if */ - - /* Take care of loose ends for modifications made while bringing in the - * object header & chunks. - */ - if(0 == (prot_flags & H5AC__READ_ONLY_FLAG)) { - /* Check for the object header prefix being modified somehow */ - /* (usually through updating the # of object header messages) */ - if(oh->prefix_modified) { - /* Mark the header as dirty now */ - if(H5AC_mark_entry_dirty(oh) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTMARKDIRTY, NULL, "unable to mark object header as dirty") - - /* Reset flag */ - oh->prefix_modified = FALSE; - } /* end if */ - - /* Check for deferred dirty messages */ - if(oh->mesgs_modified) { - unsigned u; /* Local index variable */ - - /* Loop through all messages, marking their chunks as dirty */ - /* (slightly inefficient, since we don't know exactly which messages - * were modified when the object header & chunks were brought in - * from the file, but this only can happen once per load -QAK) - */ - for(u = 0; u < oh->nmesgs; u++) { - /* Mark each chunk with a dirty message as dirty also */ - if(oh->mesg[u].dirty) { - H5O_chunk_proxy_t *chk_proxy; /* Chunk that message is in */ - - /* Protect chunk */ - if(NULL == (chk_proxy = H5O_chunk_protect(loc->file, dxpl_id, oh, oh->mesg[u].chunkno))) - HGOTO_ERROR(H5E_OHDR, H5E_CANTPROTECT, NULL, "unable to load object header chunk") - - /* Unprotect chunk, marking it dirty */ - if(H5O_chunk_unprotect(loc->file, dxpl_id, chk_proxy, TRUE) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTUNPROTECT, NULL, "unable to unprotect object header chunk") - } /* end if */ - } /* end for */ - - /* Reset flag */ - oh->mesgs_modified = FALSE; - } /* end if */ } /* end if */ #ifdef H5O_DEBUG @@ -3645,7 +3576,6 @@ herr_t H5O__free(H5O_t *oh) { unsigned u; /* Local index variable */ - herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE_NOERR diff --git a/src/H5Ocache.c b/src/H5Ocache.c index edabc52..88a4d85 100644 --- a/src/H5Ocache.c +++ b/src/H5Ocache.c @@ -68,7 +68,10 @@ /********************/ /* Metadata cache callbacks */ -static herr_t H5O__cache_get_load_size(const void *udata, size_t *image_len); +static herr_t H5O__cache_get_initial_load_size(void *udata, size_t *image_len); +static herr_t H5O__cache_get_final_load_size(const void *image_ptr, size_t image_len, + void *udata, size_t *actual_len); +static htri_t H5O__cache_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5O__cache_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5O__cache_image_len(const void *thing, size_t *image_len); @@ -77,7 +80,8 @@ static herr_t H5O__cache_serialize(const H5F_t *f, void *image, size_t len, static herr_t H5O__cache_notify(H5AC_notify_action_t action, void *_thing); static herr_t H5O__cache_free_icr(void *thing); -static herr_t H5O__cache_chk_get_load_size(const void *udata, size_t *image_len); +static herr_t H5O__cache_chk_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5O__cache_chk_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5O__cache_chk_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5O__cache_chk_image_len(const void *thing, size_t *image_len); @@ -94,7 +98,6 @@ static herr_t H5O__chunk_serialize(const H5F_t *f, H5O_t *oh, unsigned chunkno); /* Misc. routines */ static herr_t H5O__add_cont_msg(H5O_cont_msgs_t *cont_msg_info, const H5O_cont_t *cont); -static herr_t H5O_decode_prefix(H5F_t *f, H5O_t *oh, const uint8_t *buf, void *_udata); /*********************/ @@ -107,7 +110,9 @@ const H5AC_class_t H5AC_OHDR[1] = {{ "object header", /* Metadata client name (for debugging) */ H5FD_MEM_OHDR, /* File space memory type for client */ H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */ - H5O__cache_get_load_size, /* 'get_load_size' callback */ + H5O__cache_get_initial_load_size, /* 'get_initial_load_size' callback */ + H5O__cache_get_final_load_size, /* 'get_final_load_size' callback */ + H5O__cache_verify_chksum, /* 'verify_chksum' callback */ H5O__cache_deserialize, /* 'deserialize' callback */ H5O__cache_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -123,7 +128,9 @@ const H5AC_class_t H5AC_OHDR_CHK[1] = {{ "object header continuation chunk", /* Metadata client name (for debugging) */ H5FD_MEM_OHDR, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5O__cache_chk_get_load_size, /* 'get_load_size' callback */ + H5O__cache_chk_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5O__cache_chk_verify_chksum, /* 'verify_chksum' callback */ H5O__cache_chk_deserialize, /* 'deserialize' callback */ H5O__cache_chk_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -152,48 +159,88 @@ H5FL_SEQ_DEFINE(H5O_cont_t); /* Local Variables */ /*******************/ + /*------------------------------------------------------------------------- - * Function: H5O_decode_prefix + * Function: H5O__cache_get_initial_load_size() * - * Purpose: To decode the object header prefix. - * The coding is extracted fromt H5O__cache_deserialize() to this routine. + * Purpose: Tell the metadata cache how much data to read from file in + * the first speculative read for the object header. * - * Return: Non-negative on success/Negative on failure + * Return: Success: SUCCEED + * Failure: FAIL * - * Programmer: Vailin Choi - * Aug 2015 + * Programmer: John Mainzer + * 7/28/14 * *------------------------------------------------------------------------- */ static herr_t -H5O_decode_prefix(H5F_t *f, H5O_t *oh, const uint8_t *buf, void *_udata) +H5O__cache_get_initial_load_size(void H5_ATTR_UNUSED *_udata, size_t *image_len) { - H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata; /* User data for callback */ - const uint8_t *p = buf; /* Pointer into buffer to decode */ - herr_t ret_value = SUCCEED; /* Return value */ + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image_len); - FUNC_ENTER_NOAPI_NOINIT + /* Set the image length size */ + *image_len = H5O_SPEC_READ_SIZE; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5O__cache_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5O__cache_get_final_load_size() + * + * Purpose: Tell the metadata cache the final size of an object header. + * + * Return: Success: SUCCEED + * Failure: FAIL + * + * Programmer: Quincey Koziol + * November 18, 2016 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5O__cache_get_final_load_size(const void *_image, size_t image_len, + void *_udata, size_t *actual_len) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata; /* User data for callback */ + H5O_t *oh = NULL; /* Object header read in */ + htri_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC /* Check arguments */ - HDassert(f); - HDassert(oh); - HDassert(buf); + HDassert(image); HDassert(udata); + HDassert(actual_len); + HDassert(*actual_len == image_len); + + /* Allocate space for the new object header data structure */ + if(NULL == (oh = H5FL_CALLOC(H5O_t))) + HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed") + + /* File-specific, non-stored information */ + oh->sizeof_size = H5F_SIZEOF_SIZE(udata->common.f); + oh->sizeof_addr = H5F_SIZEOF_ADDR(udata->common.f); /* Check for presence of magic number */ /* (indicates version 2 or later) */ - if(!HDmemcmp(p, H5O_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) { + if(!HDmemcmp(image, H5O_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) { /* Magic number */ - p += H5_SIZEOF_MAGIC; + image += H5_SIZEOF_MAGIC; /* Version */ - oh->version = *p++; + oh->version = *image++; if(H5O_VERSION_2 != oh->version) HGOTO_ERROR(H5E_OHDR, H5E_VERSION, FAIL, "bad object header version number") /* Flags */ - oh->flags = *p++; + oh->flags = *image++; if(oh->flags & ~H5O_HDR_ALL_FLAGS) HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unknown object header status flag(s)") @@ -204,13 +251,13 @@ H5O_decode_prefix(H5F_t *f, H5O_t *oh, const uint8_t *buf, void *_udata) if(oh->flags & H5O_HDR_STORE_TIMES) { uint32_t tmp; /* Temporary value */ - UINT32DECODE(p, tmp); + UINT32DECODE(image, tmp); oh->atime = (time_t)tmp; - UINT32DECODE(p, tmp); + UINT32DECODE(image, tmp); oh->mtime = (time_t)tmp; - UINT32DECODE(p, tmp); + UINT32DECODE(image, tmp); oh->ctime = (time_t)tmp; - UINT32DECODE(p, tmp); + UINT32DECODE(image, tmp); oh->btime = (time_t)tmp; } /* end if */ else @@ -218,8 +265,8 @@ H5O_decode_prefix(H5F_t *f, H5O_t *oh, const uint8_t *buf, void *_udata) /* Attribute fields */ if(oh->flags & H5O_HDR_ATTR_STORE_PHASE_CHANGE) { - UINT16DECODE(p, oh->max_compact); - UINT16DECODE(p, oh->min_dense); + UINT16DECODE(image, oh->max_compact); + UINT16DECODE(image, oh->min_dense); if(oh->max_compact < oh->min_dense) HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad object header attribute phase change values") } /* end if */ @@ -231,30 +278,30 @@ H5O_decode_prefix(H5F_t *f, H5O_t *oh, const uint8_t *buf, void *_udata) /* First chunk size */ switch(oh->flags & H5O_HDR_CHUNK0_SIZE) { case 0: /* 1 byte size */ - oh->chunk0_size = *p++; + udata->chunk0_size = *image++; break; case 1: /* 2 byte size */ - UINT16DECODE(p, oh->chunk0_size); + UINT16DECODE(image, udata->chunk0_size); break; case 2: /* 4 byte size */ - UINT32DECODE(p, oh->chunk0_size); + UINT32DECODE(image, udata->chunk0_size); break; case 3: /* 8 byte size */ - UINT64DECODE(p, oh->chunk0_size); + UINT64DECODE(image, udata->chunk0_size); break; default: HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad size for chunk 0") } /* end switch */ - if(oh->chunk0_size > 0 && oh->chunk0_size < H5O_SIZEOF_MSGHDR_OH(oh)) + if(udata->chunk0_size > 0 && udata->chunk0_size < H5O_SIZEOF_MSGHDR_OH(oh)) HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad object header chunk size") } /* end if */ else { /* Version */ - oh->version = *p++; + oh->version = *image++; if(H5O_VERSION_1 != oh->version) HGOTO_ERROR(H5E_OHDR, H5E_VERSION, FAIL, "bad object header version number") @@ -262,13 +309,13 @@ H5O_decode_prefix(H5F_t *f, H5O_t *oh, const uint8_t *buf, void *_udata) oh->flags = H5O_CRT_OHDR_FLAGS_DEF; /* Reserved */ - p++; + image++; /* Number of messages */ - UINT16DECODE(p, udata->v1_pfx_nmesgs); + UINT16DECODE(image, udata->v1_pfx_nmesgs); /* Link count */ - UINT32DECODE(p, oh->nlink); + UINT32DECODE(image, oh->nlink); /* Reset unused time fields */ oh->atime = oh->mtime = oh->ctime = oh->btime = 0; @@ -278,51 +325,77 @@ H5O_decode_prefix(H5F_t *f, H5O_t *oh, const uint8_t *buf, void *_udata) oh->min_dense = 0; /* First chunk size */ - UINT32DECODE(p, oh->chunk0_size); - if((udata->v1_pfx_nmesgs > 0 && oh->chunk0_size < H5O_SIZEOF_MSGHDR_OH(oh)) || - (udata->v1_pfx_nmesgs == 0 && oh->chunk0_size > 0)) + UINT32DECODE(image, udata->chunk0_size); + if((udata->v1_pfx_nmesgs > 0 && udata->chunk0_size < H5O_SIZEOF_MSGHDR_OH(oh)) || + (udata->v1_pfx_nmesgs == 0 && udata->chunk0_size > 0)) HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad object header chunk size") /* Reserved, in version 1 (for 8-byte alignment padding) */ - p += 4; + image += 4; } /* end else */ /* Determine object header prefix length */ - HDassert((size_t)(p - buf) == (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh))); + HDassert((size_t)((const uint8_t *)image - (const uint8_t *)_image) == (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh))); + + /* Set the final size for the cache image */ + *actual_len = udata->chunk0_size + (size_t)H5O_SIZEOF_HDR(oh); + + /* Save the object header for later use in 'deserialize' callback */ + udata->oh = oh; + oh = NULL; done: + /* Release the [possibly partially initialized] object header on errors */ + if(ret_value < 0 && oh) + if(H5O__free(oh) < 0) + HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to destroy object header data") + FUNC_LEAVE_NOAPI(ret_value) -} /* H5O_decode_prefix() */ +} /* end H5O__cache_get_final_load_size() */ /*------------------------------------------------------------------------- - * Function: H5O__cache_get_load_size() + * Function: H5O__cache_verify_chksum * - * Purpose: Tell the metadata cache how much data to read from file in - * the first speculative read for the object header. Note that we do - * not have to be concerned about reading past the end of file, as the - * cache will clamp the read to avoid this if needed. + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. * - * Return: Success: SUCCEED - * Failure: FAIL + * Return: Success: TRUE/FALSE + * Failure: Negative * - * Programmer: John Mainzer - * 7/28/14 + * Programmer: Vailin Choi + * Aug 2015 * *------------------------------------------------------------------------- */ -static herr_t -H5O__cache_get_load_size(const void H5_ATTR_UNUSED *_udata, size_t *image_len) +static htri_t +H5O__cache_verify_chksum(const void *_image, size_t len, void *_udata) { + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata; /* User data for callback */ + htri_t ret_value = TRUE; /* Return value */ + FUNC_ENTER_STATIC_NOERR /* Check arguments */ - HDassert(image_len); + HDassert(image); + HDassert(udata); + HDassert(udata->oh); - *image_len = H5O_SPEC_READ_SIZE; + /* There is no checksum for version 1 */ + if(udata->oh->version != H5O_VERSION_1) { + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5O__cache_get_load_size() */ + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O__cache_verify_chksum() */ /*------------------------------------------------------------------------- @@ -349,10 +422,9 @@ static void * H5O__cache_deserialize(const void *_image, size_t len, void *_udata, hbool_t *dirty) { - H5O_t *oh = NULL; /* Object header read in */ + H5O_t *oh; /* Object header read in */ H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata; /* User data for callback */ const uint8_t *image = (const uint8_t *)_image; /* Pointer into buffer to decode */ - size_t buf_size; /* Size of prefix+chunk #0 buffer */ void * ret_value = NULL; /* Return value */ FUNC_ENTER_STATIC @@ -361,38 +433,17 @@ H5O__cache_deserialize(const void *_image, size_t len, void *_udata, HDassert(image); HDassert(len > 0); HDassert(udata); + HDassert(udata->oh); HDassert(udata->common.f); HDassert(udata->common.cont_msg_info); HDassert(dirty); - /* Allocate space for the object header data structure */ - if(NULL == (oh = H5FL_CALLOC(H5O_t))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") + /* Retrieve partially deserialized object header from user data */ + oh = udata->oh; - /* File-specific, non-stored information */ - oh->sizeof_size = H5F_SIZEOF_SIZE(udata->common.f); - oh->sizeof_addr = H5F_SIZEOF_ADDR(udata->common.f); - - /* Decode header prefix */ - if(H5O_decode_prefix(udata->common.f, oh, image, udata) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize object header prefix") - - /* Compute the size of the buffer used */ - buf_size = oh->chunk0_size + (size_t)H5O_SIZEOF_HDR(oh); - - - /* Check to see if the buffer provided is large enough to contain both - * the prefix and the first chunk. If it isn't, make note of the desired - * size, but otherwise do nothing. H5C_load_entry() will notice the - * discrepency, load the correct size buffer, and retry the deserialize. - */ - if(len >= buf_size) { - /* Parse the first chunk */ - if(H5O__chunk_deserialize(oh, udata->common.addr, oh->chunk0_size, (const uint8_t *)_image, &(udata->common), dirty) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize first object header chunk") - } /* end if */ - else - HDassert(!udata->made_attempt); + /* Parse the first chunk */ + if(H5O__chunk_deserialize(oh, udata->common.addr, udata->chunk0_size, (const uint8_t *)_image, &(udata->common), dirty) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize first object header chunk") /* Note that we've loaded the object header from the file */ udata->made_attempt = TRUE; @@ -439,10 +490,7 @@ H5O__cache_image_len(const void *_thing, size_t *image_len) HDassert(image_len); /* Report the object header's prefix+first chunk length */ - if(oh->chunk0_size) - *image_len = (size_t)H5O_SIZEOF_HDR(oh) + oh->chunk0_size; - else - *image_len = oh->chunk[0].size; + *image_len = oh->chunk[0].size; FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5O__cache_image_len() */ @@ -698,12 +746,11 @@ done: /*------------------------------------------------------------------------- - * Function: H5O__cache_chk_get_load_size() + * Function: H5O__cache_chk_get_initial_load_size() * * Purpose: Tell the metadata cache how large the on disk image of the * chunk proxy is, so it can load the image into a buffer for the - * deserialize call. In this case, we simply look up the size in - * the user data, and return it in *image_len, + * deserialize call. * * Return: Success: SUCCEED * Failure: FAIL @@ -714,9 +761,9 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5O__cache_chk_get_load_size(const void *_udata, size_t *image_len) +H5O__cache_chk_get_initial_load_size(void *_udata, size_t *image_len) { - const H5O_chk_cache_ud_t *udata = (const H5O_chk_cache_ud_t *)_udata; /* User data for callback */ + const H5O_chk_cache_ud_t *udata = (const H5O_chk_cache_ud_t *)_udata; /* User data for callback */ FUNC_ENTER_STATIC_NOERR @@ -725,10 +772,53 @@ H5O__cache_chk_get_load_size(const void *_udata, size_t *image_len) HDassert(udata->oh); HDassert(image_len); + /* Set the image length size */ *image_len = udata->size; FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5O__cache_chk_get_load_size() */ +} /* end H5O__cache_chk_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5B2__cache_chk_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi + * Aug 2015 + * + *------------------------------------------------------------------------- + */ +static htri_t +H5O__cache_chk_verify_chksum(const void *_image, size_t len, void *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5O_chk_cache_ud_t *udata = (H5O_chk_cache_ud_t *)_udata; /* User data for callback */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + + /* There is no checksum for version 1 */ + if(udata->oh->version != H5O_VERSION_1) { + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5O__cache_chk_verify_chksum() */ /*------------------------------------------------------------------------- @@ -1071,12 +1161,12 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image { const uint8_t *chunk_image; /* Pointer into buffer to decode */ uint8_t *eom_ptr; /* Pointer to end of messages for a chunk */ - size_t curmesg; /* Current message being decoded in object header */ unsigned merged_null_msgs = 0; /* Number of null messages merged together */ unsigned chunkno; /* Current chunk's index */ #ifndef NDEBUG unsigned nullcnt; /* Count of null messages (for sanity checking gaps in chunks) */ #endif /* NDEBUG */ + hbool_t mesgs_modified = FALSE; /* Whether any messages were modified when the object header was deserialized */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC @@ -1102,15 +1192,12 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image /* Init the chunk data info */ chunkno = (unsigned)oh->nchunks++; oh->chunk[chunkno].gap = 0; - if(chunkno == 0) { + oh->chunk[chunkno].addr = addr; + if(chunkno == 0) /* First chunk's 'image' includes room for the object header prefix */ - oh->chunk[0].addr = addr; oh->chunk[0].size = len + (size_t)H5O_SIZEOF_HDR(oh); - } /* end if */ - else { - oh->chunk[chunkno].addr = addr; + else oh->chunk[chunkno].size = len; - } /* end else */ if(NULL == (oh->chunk[chunkno].image = H5FL_BLK_MALLOC(chunk_image, oh->chunk[chunkno].size))) HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed") @@ -1132,16 +1219,12 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image chunk_image += H5_SIZEOF_MAGIC; } /* end if */ - /* Save # of messages already inspected */ - curmesg = oh->nmesgs; - /* Decode messages from this chunk */ eom_ptr = oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh)); #ifndef NDEBUG nullcnt = 0; #endif /* NDEBUG */ while(chunk_image < eom_ptr) { - size_t mesgno; /* Current message to operate on */ size_t mesg_size; /* Size of message read in */ unsigned id; /* ID (type) of current message */ uint8_t flags; /* Flags for current message */ @@ -1200,39 +1283,45 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image H5O_NULL_ID == id && oh->nmesgs > 0 && H5O_NULL_ID == oh->mesg[oh->nmesgs - 1].type->id && oh->mesg[oh->nmesgs - 1].chunkno == chunkno) { + size_t mesgno; /* Current message to operate on */ /* Combine adjacent null messages */ mesgno = oh->nmesgs - 1; oh->mesg[mesgno].raw_size += (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + mesg_size; oh->mesg[mesgno].dirty = TRUE; merged_null_msgs++; - udata->merged_null_msgs++; } /* end if */ else { + H5O_mesg_t *mesg; /* Pointer to new message */ + unsigned ioflags = 0; /* Flags for decode routine */ + /* Check if we need to extend message table to hold the new message */ if(oh->nmesgs >= oh->alloc_nmesgs) if(H5O_alloc_msgs(oh, (size_t)1) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "can't allocate more space for messages") - /* Get index for message */ - mesgno = oh->nmesgs++; + /* Get pointer to message to set up */ + mesg = &oh->mesg[oh->nmesgs]; + + /* Increment # of messages */ + oh->nmesgs++; /* Initialize information about message */ - oh->mesg[mesgno].dirty = FALSE; - oh->mesg[mesgno].flags = flags; - oh->mesg[mesgno].crt_idx = crt_idx; - oh->mesg[mesgno].native = NULL; - oh->mesg[mesgno].raw = (uint8_t *)chunk_image; /* Casting away const OK - QAK */ - oh->mesg[mesgno].raw_size = mesg_size; - oh->mesg[mesgno].chunkno = chunkno; + mesg->dirty = FALSE; + mesg->flags = flags; + mesg->crt_idx = crt_idx; + mesg->native = NULL; + mesg->raw = (uint8_t *)chunk_image; /* Casting away const OK - QAK */ + mesg->raw_size = mesg_size; + mesg->chunkno = chunkno; /* Point unknown messages at 'unknown' message class */ /* (Usually from future versions of the library) */ if(id >= H5O_UNKNOWN_ID || #ifdef H5O_ENABLE_BOGUS - id == H5O_BOGUS_VALID_ID || + id == H5O_BOGUS_VALID_ID || #endif - NULL == H5O_msg_class_g[id]) { + NULL == H5O_msg_class_g[id]) { H5O_unknown_t *unknown; /* Pointer to "unknown" message info */ @@ -1244,10 +1333,10 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image *unknown = id; /* Save 'native' form of unknown message */ - oh->mesg[mesgno].native = unknown; + mesg->native = unknown; /* Set message to "unknown" class */ - oh->mesg[mesgno].type = H5O_msg_class_g[H5O_UNKNOWN_ID]; + mesg->type = H5O_msg_class_g[H5O_UNKNOWN_ID]; /* Check for "fail if unknown" message flags */ if(((udata->file_intent & H5F_ACC_RDWR) && @@ -1270,17 +1359,66 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image * the metadata cache in some other "weird" way, like * using H5Ocopy() - QAK */ - oh->mesg[mesgno].flags |= H5O_MSG_FLAG_WAS_UNKNOWN; + mesg->flags |= H5O_MSG_FLAG_WAS_UNKNOWN; /* Mark the message and chunk as dirty */ - oh->mesg[mesgno].dirty = TRUE; - udata->mesgs_modified = TRUE; - *dirty = TRUE; + mesg->dirty = TRUE; + mesgs_modified = TRUE; } /* end if */ } /* end if */ else /* Set message class for "known" messages */ - oh->mesg[mesgno].type = H5O_msg_class_g[id]; + mesg->type = H5O_msg_class_g[id]; + + /* Do some inspection/interpretation of new messages from this chunk */ + /* (detect continuation messages, ref. count messages, etc.) */ + + /* Check if message is a continuation message */ + if(H5O_CONT_ID == id) { + H5O_cont_t *cont; + + /* Decode continuation message */ + cont = (H5O_cont_t *)(H5O_MSG_CONT->decode)(udata->f, udata->dxpl_id, NULL, 0, &ioflags, mesg->raw); + H5_CHECKED_ASSIGN(cont->chunkno, unsigned, udata->cont_msg_info->nmsgs + 1, size_t); /* the next continuation message/chunk */ + + /* Save 'native' form of continuation message */ + mesg->native = cont; + + /* Add to continuation messages left to interpret */ + if(H5O__add_cont_msg(udata->cont_msg_info, cont) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't add continuation message") + } /* end if */ + /* Check if message is a ref. count message */ + else if(H5O_REFCOUNT_ID == id) { + H5O_refcount_t *refcount; + + /* Decode ref. count message */ + HDassert(oh->version > H5O_VERSION_1); + refcount = (H5O_refcount_t *)(H5O_MSG_REFCOUNT->decode)(udata->f, udata->dxpl_id, NULL, 0, &ioflags, mesg->raw); + + /* Save 'native' form of ref. count message */ + mesg->native = refcount; + + /* Set object header values */ + oh->has_refcount_msg = TRUE; + oh->nlink = *refcount; + } /* end if */ + /* Check if message is a link message */ + else if(H5O_LINK_ID == id) { + /* Increment the count of link messages */ + oh->link_msgs_seen++; + } /* end if */ + /* Check if message is an attribute message */ + else if(H5O_ATTR_ID == id) { + /* Increment the count of attribute messages */ + oh->attr_msgs_seen++; + } /* end if */ + + /* Mark the message & chunk as dirty if the message was changed by decoding */ + if((ioflags & H5O_DECODEIO_DIRTY) && (udata->file_intent & H5F_ACC_RDWR)) { + mesg->dirty = TRUE; + mesgs_modified = TRUE; + } /* end if */ } /* end else */ /* Advance decode pointer past message */ @@ -1305,89 +1443,23 @@ H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image /* Check for correct checksum on chunks, in later versions of the format */ if(oh->version > H5O_VERSION_1) { uint32_t stored_chksum; /* Checksum from file */ - uint32_t computed_chksum; /* Checksum computed in memory */ + + /* checksum verification already done in verify_chksum cb */ /* Metadata checksum */ UINT32DECODE(chunk_image, stored_chksum); - - /* Compute checksum on chunk */ - computed_chksum = H5_checksum_metadata(oh->chunk[chunkno].image, (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM), 0); - - /* Verify checksum */ - if(stored_chksum != computed_chksum) - HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "incorrect metadata checksum for object header chunk") } /* end if */ /* Sanity check */ HDassert(chunk_image == oh->chunk[chunkno].image + oh->chunk[chunkno].size); - /* Do some inspection/interpretation of new messages from this chunk */ - /* (detect continuation messages, ref. count messages, etc.) */ - while(curmesg < oh->nmesgs) { - /* Check if next message to examine is a continuation message */ - if(H5O_CONT_ID == oh->mesg[curmesg].type->id) { - H5O_cont_t *cont; - unsigned ioflags = 0; /* Flags for decode routine */ - - /* Decode continuation message */ - cont = (H5O_cont_t *)(H5O_MSG_CONT->decode)(udata->f, udata->dxpl_id, NULL, 0, &ioflags, oh->mesg[curmesg].raw); - H5_CHECKED_ASSIGN(cont->chunkno, unsigned, udata->cont_msg_info->nmsgs + 1, size_t); /* the next continuation message/chunk */ - - /* Save 'native' form of continuation message */ - oh->mesg[curmesg].native = cont; - - /* Add to continuation messages left to interpret */ - if(H5O__add_cont_msg(udata->cont_msg_info, cont) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't add continuation message") - - /* Mark the message & chunk as dirty if the message was changed by decoding */ - if((ioflags & H5O_DECODEIO_DIRTY) && (udata->file_intent & H5F_ACC_RDWR)) { - oh->mesg[curmesg].dirty = TRUE; - udata->mesgs_modified = TRUE; - *dirty = TRUE; - } /* end if */ - } /* end if */ - /* Check if next message to examine is a ref. count message */ - else if(H5O_REFCOUNT_ID == oh->mesg[curmesg].type->id) { - H5O_refcount_t *refcount; - unsigned ioflags = 0; /* Flags for decode routine */ - - /* Decode ref. count message */ - HDassert(oh->version > H5O_VERSION_1); - refcount = (H5O_refcount_t *)(H5O_MSG_REFCOUNT->decode)(udata->f, udata->dxpl_id, NULL, 0, &ioflags, oh->mesg[curmesg].raw); - - /* Save 'native' form of ref. count message */ - oh->mesg[curmesg].native = refcount; - - /* Set object header values */ - oh->has_refcount_msg = TRUE; - oh->nlink = *refcount; - - /* Mark the message & chunk as dirty if the message was changed by decoding */ - if((ioflags & H5O_DECODEIO_DIRTY) && (udata->file_intent & H5F_ACC_RDWR)) { - oh->mesg[curmesg].dirty = TRUE; - udata->mesgs_modified = TRUE; - *dirty = TRUE; - } /* end if */ - } /* end if */ - /* Check if next message to examine is a link message */ - else if(H5O_LINK_ID == oh->mesg[curmesg].type->id) { - /* Increment the count of link messages */ - oh->link_msgs_seen++; - } /* end if */ - /* Check if next message to examine is an attribute message */ - else if(H5O_ATTR_ID == oh->mesg[curmesg].type->id) { - /* Increment the count of attribute messages */ - oh->attr_msgs_seen++; - } /* end if */ - - /* Advance to next message */ - curmesg++; - } /* end while */ + /* Mark the chunk dirty if we've modified messages */ + if(mesgs_modified) + *dirty = TRUE; /* Mark the chunk dirty if we've merged null messages */ - if(merged_null_msgs) { - udata->mesgs_modified = TRUE; + if(merged_null_msgs > 0) { + udata->merged_null_msgs += merged_null_msgs; *dirty = TRUE; } /* end if */ diff --git a/src/H5Opkg.h b/src/H5Opkg.h index 659bf6e..b80f736 100644 --- a/src/H5Opkg.h +++ b/src/H5Opkg.h @@ -292,9 +292,6 @@ struct H5O_t { /* Chunk management information (not stored) */ size_t rc; /* Reference count of [continuation] chunks using this structure */ - size_t chunk0_size; /* Size of serialized first chunk */ - hbool_t mesgs_modified; /* Whether any messages were modified when the object header was deserialized */ - hbool_t prefix_modified; /* Whether prefix was modified when the object header was deserialized */ /* Object information (stored) */ hbool_t has_refcount_msg; /* Whether the object has a ref. count message */ @@ -362,7 +359,6 @@ typedef struct H5O_common_cache_ud_t { hid_t dxpl_id; /* DXPL for operation */ unsigned file_intent; /* Read/write intent for file */ unsigned merged_null_msgs; /* Number of null messages merged together */ - hbool_t mesgs_modified; /* Whether any messages were modified when the object header was deserialized */ H5O_cont_msgs_t *cont_msg_info; /* Pointer to continuation messages to work on */ haddr_t addr; /* Address of the prefix or chunk */ } H5O_common_cache_ud_t; @@ -371,6 +367,8 @@ typedef struct H5O_common_cache_ud_t { typedef struct H5O_cache_ud_t { hbool_t made_attempt; /* Whether the deserialize routine was already attempted */ unsigned v1_pfx_nmesgs; /* Number of messages from v1 prefix header */ + size_t chunk0_size; /* Size of serialized first chunk */ + H5O_t *oh; /* Partially deserialized object header, for later use */ H5O_common_cache_ud_t common; /* Common object header cache callback info */ } H5O_cache_ud_t; diff --git a/src/H5Pfapl.c b/src/H5Pfapl.c index 15662cc..81cd260 100644 --- a/src/H5Pfapl.c +++ b/src/H5Pfapl.c @@ -178,6 +178,11 @@ #define H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_DEF 524288 #define H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_ENC H5P__encode_size_t #define H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_DEC H5P__decode_size_t +/* Definition for # of metadata read attempts */ +#define H5F_ACS_METADATA_READ_ATTEMPTS_SIZE sizeof(unsigned) +#define H5F_ACS_METADATA_READ_ATTEMPTS_DEF 0 +#define H5F_ACS_METADATA_READ_ATTEMPTS_ENC H5P__encode_unsigned +#define H5F_ACS_METADATA_READ_ATTEMPTS_DEC H5P__decode_unsigned /* Definition for object flush callback */ #define H5F_ACS_OBJECT_FLUSH_CB_SIZE sizeof(H5F_object_flush_t) #define H5F_ACS_OBJECT_FLUSH_CB_DEF {NULL, NULL} @@ -327,6 +332,7 @@ static const unsigned H5F_def_efc_size_g = H5F_ACS_EFC_SIZE_DEF; static const H5FD_file_image_info_t H5F_def_file_image_info_g = H5F_ACS_FILE_IMAGE_INFO_DEF; /* Default file image info and callbacks */ static const hbool_t H5F_def_core_write_tracking_flag_g = H5F_ACS_CORE_WRITE_TRACKING_FLAG_DEF; /* Default setting for core VFD write tracking */ static const size_t H5F_def_core_write_tracking_page_size_g = H5F_ACS_CORE_WRITE_TRACKING_PAGE_SIZE_DEF; /* Default core VFD write tracking page size */ +static const unsigned H5F_def_metadata_read_attempts_g = H5F_ACS_METADATA_READ_ATTEMPTS_DEF; /* Default setting for the # of metadata read attempts */ static const H5F_object_flush_t H5F_def_object_flush_cb_g = H5F_ACS_OBJECT_FLUSH_CB_DEF; /* Default setting for object flush callback */ static const hbool_t H5F_def_use_mdc_logging_g = H5F_ACS_USE_MDC_LOGGING_DEF; /* Default metadata cache logging flag */ static const char *H5F_def_mdc_log_location_g = H5F_ACS_MDC_LOG_LOCATION_DEF; /* Default mdc log location */ @@ -492,6 +498,12 @@ H5P__facc_reg_prop(H5P_genclass_t *pclass) NULL, NULL, NULL, NULL) < 0) HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") + /* Register the # of read attempts */ + if(H5P_register_real(pclass, H5F_ACS_METADATA_READ_ATTEMPTS_NAME, H5F_ACS_METADATA_READ_ATTEMPTS_SIZE, &H5F_def_metadata_read_attempts_g, + NULL, NULL, NULL, H5F_ACS_METADATA_READ_ATTEMPTS_ENC, H5F_ACS_METADATA_READ_ATTEMPTS_DEC, + NULL, NULL, NULL, NULL) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") + /* Register object flush callback */ /* (Note: this property should not have an encode/decode callback -QAK) */ if(H5P_register_real(pclass, H5F_ACS_OBJECT_FLUSH_CB_NAME, H5F_ACS_OBJECT_FLUSH_CB_SIZE, &H5F_def_object_flush_cb_g, @@ -3570,6 +3582,90 @@ done: /*------------------------------------------------------------------------- + * Function: H5Pset_metadata_read_attempts + * + * Purpose: Sets the # of read attempts in the file access property list + * when reading metadata with checksum. + * The # of read attempts set via this routine will only apply + * when opening a file with SWMR access. + * The # of read attempts set via this routine does not have + * any effect when opening a file with non-SWMR access; for this + * case, the # of read attempts will be always be 1. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Vailin Choi; Sept 2013 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Pset_metadata_read_attempts(hid_t plist_id, unsigned attempts) +{ + H5P_genplist_t *plist; /* Property list pointer */ + herr_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "iIu", plist_id, attempts); + + /* Cannot set the # of attempts to 0 */ + if(attempts == 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "number of metadatata read attempts must be greater than 0"); + + /* Get the plist structure */ + if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS))) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID") + + /* Set values */ + if(H5P_set(plist, H5F_ACS_METADATA_READ_ATTEMPTS_NAME, &attempts) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTSET, FAIL, "can't set # of metadata read attempts") + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Pset_metadata_read_attempts() */ + + +/*------------------------------------------------------------------------- + * Function: H5Pget_metadata_read_attempts + * + * Purpose: Returns the # of metadata read attempts set in the file access property list. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Vailin Choi; Sept 2013 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Pget_metadata_read_attempts(hid_t plist_id, unsigned *attempts/*out*/) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "ix", plist_id, attempts); + + /* Get values */ + if(attempts) { + H5P_genplist_t *plist; /* Property list pointer */ + + /* Get the plist structure */ + if(NULL == (plist = H5P_object_verify(plist_id, H5P_FILE_ACCESS))) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID") + + /* Get the # of read attempts set */ + if(H5P_get(plist, H5F_ACS_METADATA_READ_ATTEMPTS_NAME, attempts) < 0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, FAIL, "can't get the number of metadata read attempts") + + /* If not set, return the default value */ + if(*attempts == H5F_ACS_METADATA_READ_ATTEMPTS_DEF) /* 0 */ + *attempts = H5F_METADATA_READ_ATTEMPTS; + } /* end if */ + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Pget_metadata_read_attempts() */ + + +/*------------------------------------------------------------------------- * Function: H5Pset_obj_flush_cb * * Purpose: Sets the callback function to invoke and the user data when an diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h index 1f0d734..c736d7b 100644 --- a/src/H5Ppublic.h +++ b/src/H5Ppublic.h @@ -351,6 +351,8 @@ H5_DLL herr_t H5Pget_file_image_callbacks(hid_t fapl_id, H5FD_file_image_callbacks_t *callbacks_ptr); H5_DLL herr_t H5Pset_core_write_tracking(hid_t fapl_id, hbool_t is_enabled, size_t page_size); H5_DLL herr_t H5Pget_core_write_tracking(hid_t fapl_id, hbool_t *is_enabled, size_t *page_size); +H5_DLL herr_t H5Pset_metadata_read_attempts(hid_t plist_id, unsigned attempts); +H5_DLL herr_t H5Pget_metadata_read_attempts(hid_t plist_id, unsigned *attempts); H5_DLL herr_t H5Pset_object_flush_cb(hid_t plist_id, H5F_flush_cb_t func, void *udata); H5_DLL herr_t H5Pget_object_flush_cb(hid_t plist_id, H5F_flush_cb_t *func, void **udata); H5_DLL herr_t H5Pset_mdc_log_options(hid_t plist_id, hbool_t is_enabled, const char *location, hbool_t start_on_access); diff --git a/src/H5SMcache.c b/src/H5SMcache.c index 26db5d3..455dd1a 100644 --- a/src/H5SMcache.c +++ b/src/H5SMcache.c @@ -58,7 +58,8 @@ /********************/ /* Metadata cache (H5AC) callbacks */ -static herr_t H5SM__cache_table_get_load_size(const void *udata, size_t *image_len); +static herr_t H5SM__cache_table_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5SM__cache_table_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5SM__cache_table_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5SM__cache_table_image_len(const void *thing, size_t *image_len); @@ -66,7 +67,8 @@ static herr_t H5SM__cache_table_serialize(const H5F_t *f, void *image, size_t len, void *thing); static herr_t H5SM__cache_table_free_icr(void *thing); -static herr_t H5SM__cache_list_get_load_size(const void *udata, size_t *image_len); +static herr_t H5SM__cache_list_get_initial_load_size(void *udata, size_t *image_len); +static htri_t H5SM__cache_list_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *H5SM__cache_list_deserialize(const void *image, size_t len, void *udata, hbool_t *dirty); static herr_t H5SM__cache_list_image_len(const void *thing, size_t *image_len); @@ -85,7 +87,9 @@ const H5AC_class_t H5AC_SOHM_TABLE[1] = {{ "shared message table", /* Metadata client name (for debugging) */ H5FD_MEM_SOHM_TABLE, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5SM__cache_table_get_load_size, /* 'get_load_size' callback */ + H5SM__cache_table_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5SM__cache_table_verify_chksum, /* 'verify_chksum' callback */ H5SM__cache_table_deserialize, /* 'deserialize' callback */ H5SM__cache_table_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -100,7 +104,9 @@ const H5AC_class_t H5AC_SOHM_LIST[1] = {{ "shared message list", /* Metadata client name (for debugging) */ H5FD_MEM_SOHM_TABLE, /* File space memory type for client */ H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */ - H5SM__cache_list_get_load_size, /* 'get_load_size' callback */ + H5SM__cache_list_get_initial_load_size, /* 'get_initial_load_size' callback */ + NULL, /* 'get_final_load_size' callback */ + H5SM__cache_list_verify_chksum, /* 'verify_chksum' callback */ H5SM__cache_list_deserialize, /* 'deserialize' callback */ H5SM__cache_list_image_len, /* 'image_len' callback */ NULL, /* 'pre_serialize' callback */ @@ -123,11 +129,10 @@ const H5AC_class_t H5AC_SOHM_LIST[1] = {{ /*------------------------------------------------------------------------- - * Function: H5SM__cache_table_get_load_size() + * Function: H5SM__cache_table_get_initial_load_size() * * Purpose: Return the size of the master table of Shared Object Header - * Message indexes on disk. As this cache client doesn't use - * speculative reads, this value should be accurate. + * Message indexes on disk. * * Return: Success: SUCCEED * Failure: FAIL @@ -138,9 +143,9 @@ const H5AC_class_t H5AC_SOHM_LIST[1] = {{ *------------------------------------------------------------------------- */ static herr_t -H5SM__cache_table_get_load_size(const void *_udata, size_t *image_len) +H5SM__cache_table_get_initial_load_size(void *_udata, size_t *image_len) { - const H5SM_table_cache_ud_t *udata = (const H5SM_table_cache_ud_t *)_udata; /* User data for callback */ + const H5SM_table_cache_ud_t *udata = (const H5SM_table_cache_ud_t *)_udata; /* User data for callback */ FUNC_ENTER_STATIC_NOERR @@ -149,10 +154,47 @@ H5SM__cache_table_get_load_size(const void *_udata, size_t *image_len) HDassert(udata->f); HDassert(image_len); + /* Set the image length size */ *image_len = H5SM_TABLE_SIZE(udata->f); FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5SM__cache_table_get_load_size() */ +} /* end H5SM__cache_table_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5SM__cache_table_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +htri_t +H5SM__cache_table_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, len, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5SM__cache_table_verify_chksum() */ /*------------------------------------------------------------------------- @@ -180,7 +222,6 @@ H5SM__cache_table_deserialize(const void *_image, size_t len, void *_udata, H5SM_table_cache_ud_t *udata = (H5SM_table_cache_ud_t *)_udata; /* Pointer to user data */ const uint8_t *image = (const uint8_t *)_image; /* Pointer into input buffer */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ size_t u; /* Counter variable for index headers */ void *ret_value = NULL; /* Return value */ @@ -256,19 +297,14 @@ H5SM__cache_table_deserialize(const void *_image, size_t len, void *_udata, table->indexes[u].list_size = H5SM_LIST_SIZE(f, table->indexes[u].list_max); } /* end for */ + /* checksum verification already done in verify_chksum cb */ + /* Read in checksum */ UINT32DECODE(image, stored_chksum); /* Sanity check */ HDassert((size_t)(image - (const uint8_t *)_image) == table->table_size); - /* Compute checksum on entire header */ - computed_chksum = H5_checksum_metadata(_image, (table->table_size - H5SM_SIZEOF_CHECKSUM), 0); - - /* Verify checksum */ - if(stored_chksum != computed_chksum) - HGOTO_ERROR(H5E_SOHM, H5E_BADVALUE, NULL, "incorrect metadata checksum for shared message table") - /* Set return value */ ret_value = table; @@ -442,7 +478,7 @@ done: /*------------------------------------------------------------------------- - * Function: H5SM__cache_list_get_load_size() + * Function: H5SM__cache_list_get_initial_load_size() * * Purpose: Return the on disk size of list of SOHM messages. In this case, * we simply look up the size in the user data, and return that value @@ -457,9 +493,9 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5SM__cache_list_get_load_size(const void *_udata, size_t *image_len) +H5SM__cache_list_get_initial_load_size(void *_udata, size_t *image_len) { - const H5SM_list_cache_ud_t *udata = (const H5SM_list_cache_ud_t *)_udata; /* User data for callback */ + const H5SM_list_cache_ud_t *udata = (const H5SM_list_cache_ud_t *)_udata; /* User data for callback */ FUNC_ENTER_STATIC_NOERR @@ -469,10 +505,53 @@ H5SM__cache_list_get_load_size(const void *_udata, size_t *image_len) HDassert(udata->header->list_size > 0); HDassert(image_len); + /* Set the image length size */ *image_len = udata->header->list_size; FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5SM__cache_list_get_load_size() */ +} /* end H5SM__cache_list_get_initial_load_size() */ + + +/*------------------------------------------------------------------------- + * Function: H5SM__cache_list_verify_chksum + * + * Purpose: Verify the computed checksum of the data structure is the + * same as the stored chksum. + * + * Return: Success: TRUE/FALSE + * Failure: Negative + * + * Programmer: Vailin Choi; Aug 2015 + * + *------------------------------------------------------------------------- + */ +htri_t +H5SM__cache_list_verify_chksum(const void *_image, size_t H5_ATTR_UNUSED len, void *_udata) +{ + const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */ + H5SM_list_cache_ud_t *udata = (H5SM_list_cache_ud_t *)_udata; /* User data for callback */ + size_t chk_size; /* Exact size of the node with checksum at the end */ + uint32_t stored_chksum; /* Stored metadata checksum value */ + uint32_t computed_chksum; /* Computed metadata checksum value */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check arguments */ + HDassert(image); + HDassert(udata); + + /* Exact size with checksum at the end */ + chk_size = H5SM_LIST_SIZE(udata->f, udata->header->num_messages); + + /* Get stored and computed checksums */ + H5F_get_checksums(image, chk_size, &stored_chksum, &computed_chksum); + + if(stored_chksum != computed_chksum) + ret_value = FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5SM__cache_list_verify_chksum() */ /*------------------------------------------------------------------------- @@ -499,7 +578,6 @@ H5SM__cache_list_deserialize(const void *_image, size_t len, void *_udata, H5SM_bt2_ctx_t ctx; /* Message encoding context */ const uint8_t *image = (const uint8_t *)_image; /* Pointer into input buffer */ uint32_t stored_chksum; /* Stored metadata checksum value */ - uint32_t computed_chksum; /* Computed metadata checksum value */ size_t u; /* Counter variable for messages in list */ void *ret_value = NULL; /* Return value */ @@ -537,19 +615,14 @@ H5SM__cache_list_deserialize(const void *_image, size_t len, void *_udata, image += H5SM_SOHM_ENTRY_SIZE(udata->f); } /* end for */ + /* checksum verification already done in verify_chksum cb */ + /* Read in checksum */ UINT32DECODE(image, stored_chksum); /* Sanity check */ HDassert((size_t)(image - (const uint8_t *)_image) <= udata->header->list_size); - /* Compute checksum on entire header */ - computed_chksum = H5_checksum_metadata(_image, ((size_t)(image - (const uint8_t *)_image) - H5SM_SIZEOF_CHECKSUM), 0); - - /* Verify checksum */ - if(stored_chksum != computed_chksum) - HGOTO_ERROR(H5E_SOHM, H5E_BADVALUE, NULL, "incorrect metadata checksum for shared message list") - /* Initialize the rest of the array */ for(u = udata->header->num_messages; u < udata->header->list_max; u++) list->messages[u].location = H5SM_NO_LOC; diff --git a/src/H5private.h b/src/H5private.h index 4c40965..47f6d78 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -813,7 +813,8 @@ H5_DLL H5_ATTR_CONST int Nflock(int fd, int operation); /* NOTE: flock(2) is not present on all POSIX systems. * If it is not present, we try a flock() equivalent based on * fcntl(2), then fall back to a function that always fails if - * it is not present at all. + * it is not present at all (Windows uses a separate Wflock() + * function). */ #if defined(H5_HAVE_FLOCK) #define HDflock(F,L) flock(F,L) @@ -1114,6 +1115,9 @@ typedef off_t h5_stat_size_t; #ifndef HDmodf #define HDmodf(X,Y) modf(X,Y) #endif /* HDmodf */ +#ifndef HDnanosleep + #define HDnanosleep(N, O) nanosleep(N, O) +#endif /* HDnanosleep */ #ifndef HDopen #ifdef _O_BINARY #define HDopen(S,F,M) open(S,F|_O_BINARY,M) @@ -2597,6 +2601,8 @@ H5_DLL uint32_t H5_hash_string(const char *str); /* Time related routines */ H5_DLL time_t H5_make_time(struct tm *tm); +H5_DLL void H5_nanosleep(uint64_t nanosec); +H5_DLL double H5_get_time(void); /* Functions for building paths, etc. */ H5_DLL herr_t H5_build_extpath(const char *name, char **extpath /*out*/); diff --git a/src/H5system.c b/src/H5system.c index ab08d2c..5205d08 100644 --- a/src/H5system.c +++ b/src/H5system.c @@ -911,6 +911,27 @@ Wflock(int fd, int operation) { return 0; } /* end Wflock() */ + + /*-------------------------------------------------------------------------- + * Function: Wnanosleep + * + * Purpose: Sleep for a given # of nanoseconds (Windows version) + * + * Return: SUCCEED/FAIL + * + * Programmer: Dana Robinson + * Fall 2016 + *-------------------------------------------------------------------------- + */ +void +Wnanosleep(uint64_t nanosec) +{ + /* XXX: Currently just a placeholder */ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + FUNC_LEAVE_NOAPI_VOID +} /* end Wnanosleep() */ + #endif /* H5_HAVE_WIN32_API */ @@ -1108,3 +1129,63 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5_combine_path() */ + +/*-------------------------------------------------------------------------- + * Function: H5_nanosleep + * + * Purpose: Sleep for a given # of nanoseconds + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * October 01, 2016 + *-------------------------------------------------------------------------- + */ +void +H5_nanosleep(uint64_t nanosec) +{ + struct timespec sleeptime; /* Struct to hold time to sleep */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Set up time to sleep */ + sleeptime.tv_sec = 0; + sleeptime.tv_nsec = (long)nanosec; + + HDnanosleep(&sleeptime, NULL); + + FUNC_LEAVE_NOAPI_VOID +} /* end H5_nanosleep() */ + + +/*-------------------------------------------------------------------------- + * Function: H5_get_time + * + * Purpose: Get the current time, as the time of seconds after the UNIX epoch + * + * Return: SUCCEED/FAIL + * + * Programmer: Quincey Koziol + * October 05, 2016 + *-------------------------------------------------------------------------- + */ +double +H5_get_time(void) +{ +#ifdef H5_HAVE_GETTIMEOFDAY + struct timeval curr_time; +#endif /* H5_HAVE_GETTIMEOFDAY */ + double ret_value = (double)0.0f; + + FUNC_ENTER_NOAPI_NOINIT_NOERR + +#ifdef H5_HAVE_GETTIMEOFDAY + HDgettimeofday(&curr_time, NULL); + + ret_value = (double)curr_time.tv_sec + ((double)curr_time.tv_usec / (double)1000000.0f); +#endif /* H5_HAVE_GETTIMEOFDAY */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5_get_time() */ + + diff --git a/src/H5win32defs.h b/src/H5win32defs.h index a757832..662b97b 100644 --- a/src/H5win32defs.h +++ b/src/H5win32defs.h @@ -42,6 +42,7 @@ typedef __int64 h5_stat_size_t; #define HDlseek(F,O,W) _lseeki64(F,O,W) #define HDlstat(S,B) _lstati64(S,B) #define HDmkdir(S,M) _mkdir(S) +#define HDnanosleep(S) Wnanosleep(S) #define HDoff_t __int64 /* _O_BINARY must be set in Windows to avoid CR-LF <-> LF EOL * transformations when performing I/O. @@ -65,13 +66,23 @@ typedef __int64 h5_stat_size_t; */ #define HDmemset(X,C,Z) memset((void*)(X),C,Z) -#endif /* H5_HAVE_VISUAL_STUDIO */ - struct timezone { int tz_minuteswest; int tz_dsttime; }; +/* time.h before VS2015 does not include timespec */ +#if (_MSC_VER < 1900) +struct timespec +{ + time_t tv_sec; // Seconds - >= 0 + long tv_nsec; // Nanoseconds - [0, 999999999] +}; +#endif /* MSC_VER < 1900 */ + +#endif /* H5_HAVE_VISUAL_STUDIO */ + + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/test/cache.c b/test/cache.c index c89a1c7..3c2cf5c 100644 --- a/test/cache.c +++ b/test/cache.c @@ -17149,6 +17149,135 @@ check_protect_ro_rw_err(void) /*------------------------------------------------------------------------- + * Function: check_protect_retries() + * + * Purpose: To exercise checksum verification retries for an entry with + * a speculative load. + * + * Return: + * + * Programmer: + * + *------------------------------------------------------------------------- + */ +static unsigned +check_protect_retries(void) +{ + H5F_t * file_ptr = NULL; + H5C_t *cache_ptr = NULL; + test_entry_t *base_addr = NULL; + test_entry_t *entry_ptr = NULL; + H5C_cache_entry_t * cache_entry_ptr = NULL; + int32_t type; + int32_t idx; + + TESTING("protect an entry to verify retries"); + + pass = TRUE; + + /* Set up the cache */ + if(pass) { + + reset_entries(); + + file_ptr = setup_cache((size_t)(2 * 1024), + (size_t)(1 * 1024)); + + /* Set up read attempts for verifying checksum */ + file_ptr->shared->read_attempts = 10; + file_ptr->shared->retries_nbins = 1; + } + + /* Test only for this type which has a speculative load */ + type = VARIABLE_ENTRY_TYPE; + idx = 0; + + if(pass) { + + cache_ptr = file_ptr->shared->cache; + base_addr = entries[type]; + entry_ptr = &(base_addr[idx]); + + /* test case (1): + * --actual_len is smaller the initial length from get_load_size() + * --verify_chksum() returns TRUE after max_verify_ct is reached + * + */ + entry_ptr->actual_len = entry_ptr->size/2; + entry_ptr->max_verify_ct = 3; + entry_ptr->verify_ct = 0; + + cache_entry_ptr = (H5C_cache_entry_t *)H5C_protect(file_ptr, H5AC_ind_read_dxpl_id, + &(types[type]), entry_ptr->addr, &entry_ptr->addr, H5C__READ_ONLY_FLAG); + + if((cache_entry_ptr != (void *)entry_ptr) || + (!(entry_ptr->header.is_protected)) || + (!(entry_ptr->header.is_read_only)) || + (entry_ptr->header.ro_ref_count <= 0) || + (entry_ptr->header.type != &(types[type])) || + (entry_ptr->size != entry_ptr->header.size) || + (entry_ptr->addr != entry_ptr->header.addr) || + (entry_ptr->verify_ct != entry_ptr->max_verify_ct)) { + + pass = FALSE; + failure_mssg = "error from H5C_protect()."; + + } else { + + HDassert((entry_ptr->cache_ptr == NULL) || + (entry_ptr->cache_ptr == cache_ptr)); + + entry_ptr->cache_ptr = cache_ptr; + entry_ptr->file_ptr = file_ptr; + entry_ptr->is_protected = TRUE; + entry_ptr->is_read_only = TRUE; + entry_ptr->ro_ref_count++; + } + + HDassert(((entry_ptr->header).type)->id == type); + } + + if(pass) + unprotect_entry(file_ptr, VARIABLE_ENTRY_TYPE, idx, H5C__NO_FLAGS_SET); + + if(pass) { + entry_ptr = &(base_addr[++idx]); + + /* test case (2): + * --actual_len is greater the initial length from get_load_size() + * --verify_chksum() returns FALSE even after all tries is reached + * (file_ptr->shared->read_attempts is smaller then max_verify_ct) + */ + entry_ptr->actual_len = entry_ptr->size*2; + entry_ptr->max_verify_ct = 11; + entry_ptr->verify_ct = 0; + + cache_entry_ptr = (H5C_cache_entry_t *)H5C_protect(file_ptr, H5AC_ind_read_dxpl_id, + &(types[type]), entry_ptr->addr, &entry_ptr->addr, H5C__READ_ONLY_FLAG); + + /* H5C_protect() should fail after all retries fail */ + if(cache_entry_ptr != NULL) + pass = FALSE; + } + + + takedown_cache(file_ptr, FALSE, FALSE); + reset_entries(); + + if(pass) { PASSED(); } else { H5_FAILED(); } + + if(!pass) { + + HDfprintf(stdout, "%s: failure_msg = \"%s\".\n", + FUNC, failure_mssg); + } + + return (unsigned)!pass; + +} /* check_protect_retries() */ + + +/*------------------------------------------------------------------------- * Function: check_evictions_enabled_err() * * Purpose: Verify that H5C_get_evictions_enabled() and @@ -36190,6 +36319,7 @@ main(void) nerrs += check_resize_entry_errs(); nerrs += check_unprotect_ro_dirty_err(); nerrs += check_protect_ro_rw_err(); + nerrs += check_protect_retries(); nerrs += check_check_evictions_enabled_err(); nerrs += check_auto_cache_resize(FALSE); nerrs += check_auto_cache_resize(TRUE); diff --git a/test/cache_common.c b/test/cache_common.c index 4bea2a8..c0bee24 100644 --- a/test/cache_common.c +++ b/test/cache_common.c @@ -76,17 +76,22 @@ static test_entry_t *notify_entries = NULL, *orig_notify_entries = NULL; hbool_t orig_entry_arrays_init = FALSE; -static herr_t pico_get_load_size(const void *udata_ptr, size_t *image_len_ptr); -static herr_t nano_get_load_size(const void *udata_ptr, size_t *image_len_ptr); -static herr_t micro_get_load_size(const void *udata_ptr, size_t *image_len_ptr); -static herr_t tiny_get_load_size(const void *udata_ptr, size_t *image_len_ptr); -static herr_t small_get_load_size(const void *udata_ptr, size_t *image_len_ptr); -static herr_t medium_get_load_size(const void *udata_ptr, size_t *image_len_ptr); -static herr_t large_get_load_size(const void *udata_ptr, size_t *image_len_ptr); -static herr_t huge_get_load_size(const void *udata_ptr, size_t *image_len_ptr); -static herr_t monster_get_load_size(const void *udata_ptr, size_t *image_len_ptr); -static herr_t variable_get_load_size(const void *udata_ptr, size_t *image_len_ptr); -static herr_t notify_get_load_size(const void *udata_ptr, size_t *image_len_ptr); +static herr_t pico_get_initial_load_size(void *udata_ptr, size_t *image_len_ptr); +static herr_t nano_get_initial_load_size(void *udata_ptr, size_t *image_len_ptr); +static herr_t micro_get_initial_load_size(void *udata_ptr, size_t *image_len_ptr); +static herr_t tiny_get_initial_load_size(void *udata_ptr, size_t *image_len_ptr); +static herr_t small_get_initial_load_size(void *udata_ptr, size_t *image_len_ptr); +static herr_t medium_get_initial_load_size(void *udata_ptr, size_t *image_len_ptr); +static herr_t large_get_initial_load_size(void *udata_ptr, size_t *image_len_ptr); +static herr_t huge_get_initial_load_size(void *udata_ptr, size_t *image_len_ptr); +static herr_t monster_get_initial_load_size(void *udata_ptr, size_t *image_len_ptr); +static herr_t variable_get_initial_load_size(void *udata_ptr, size_t *image_len_ptr); +static herr_t notify_get_initial_load_size(void *udata_ptr, size_t *image_len_ptr); + +static herr_t variable_get_final_load_size(const void *image, size_t image_len, + void *udata, size_t *actual_len); + +static htri_t variable_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr); static void *pico_deserialize(const void *image_ptr, size_t len, void *udata_ptr, hbool_t *dirty_ptr); @@ -199,8 +204,10 @@ static void mark_flush_dep_dirty(test_entry_t * entry_ptr); static void mark_flush_dep_clean(test_entry_t * entry_ptr); /* Generic callback routines */ -static herr_t get_load_size(const void *udata_ptr, size_t *image_len_ptr, +static herr_t get_initial_load_size(void *udata_ptr, size_t *image_len_ptr, int32_t entry_type); +static herr_t get_final_load_size(const void *image, size_t image_len, + void *udata, size_t *actual_len, int32_t entry_type); static void *deserialize(const void *image_ptr, size_t len, void *udata_ptr, hbool_t *dirty_ptr, int32_t entry_type); static herr_t image_len(const void *thing, size_t *image_len_ptr, int32_t entry_type); @@ -306,7 +313,9 @@ const H5C_class_t types[NUMBER_OF_ENTRY_TYPES] = "pico_entry", H5FD_MEM_DEFAULT, H5C__CLASS_NO_FLAGS_SET, - pico_get_load_size, + pico_get_initial_load_size, + NULL, + NULL, pico_deserialize, pico_image_len, pico_pre_serialize, @@ -320,7 +329,9 @@ const H5C_class_t types[NUMBER_OF_ENTRY_TYPES] = "nano_entry", H5FD_MEM_DEFAULT, H5C__CLASS_NO_FLAGS_SET, - nano_get_load_size, + nano_get_initial_load_size, + NULL, + NULL, nano_deserialize, nano_image_len, nano_pre_serialize, @@ -334,7 +345,9 @@ const H5C_class_t types[NUMBER_OF_ENTRY_TYPES] = "micro_entry", H5FD_MEM_DEFAULT, H5C__CLASS_NO_FLAGS_SET, - micro_get_load_size, + micro_get_initial_load_size, + NULL, + NULL, micro_deserialize, micro_image_len, micro_pre_serialize, @@ -348,7 +361,9 @@ const H5C_class_t types[NUMBER_OF_ENTRY_TYPES] = "tiny_entry", H5FD_MEM_DEFAULT, H5C__CLASS_NO_FLAGS_SET, - tiny_get_load_size, + tiny_get_initial_load_size, + NULL, + NULL, tiny_deserialize, tiny_image_len, tiny_pre_serialize, @@ -362,7 +377,9 @@ const H5C_class_t types[NUMBER_OF_ENTRY_TYPES] = "small_entry", H5FD_MEM_DEFAULT, H5C__CLASS_NO_FLAGS_SET, - small_get_load_size, + small_get_initial_load_size, + NULL, + NULL, small_deserialize, small_image_len, small_pre_serialize, @@ -376,7 +393,9 @@ const H5C_class_t types[NUMBER_OF_ENTRY_TYPES] = "medium_entry", H5FD_MEM_DEFAULT, H5C__CLASS_NO_FLAGS_SET, - medium_get_load_size, + medium_get_initial_load_size, + NULL, + NULL, medium_deserialize, medium_image_len, medium_pre_serialize, @@ -390,7 +409,9 @@ const H5C_class_t types[NUMBER_OF_ENTRY_TYPES] = "large_entry", H5FD_MEM_DEFAULT, H5C__CLASS_NO_FLAGS_SET, - large_get_load_size, + large_get_initial_load_size, + NULL, + NULL, large_deserialize, large_image_len, large_pre_serialize, @@ -404,7 +425,9 @@ const H5C_class_t types[NUMBER_OF_ENTRY_TYPES] = "huge_entry", H5FD_MEM_DEFAULT, H5C__CLASS_NO_FLAGS_SET, - huge_get_load_size, + huge_get_initial_load_size, + NULL, + NULL, huge_deserialize, huge_image_len, huge_pre_serialize, @@ -418,7 +441,9 @@ const H5C_class_t types[NUMBER_OF_ENTRY_TYPES] = "monster_entry", H5FD_MEM_DEFAULT, H5C__CLASS_NO_FLAGS_SET, - monster_get_load_size, + monster_get_initial_load_size, + NULL, + NULL, monster_deserialize, monster_image_len, monster_pre_serialize, @@ -432,7 +457,9 @@ const H5C_class_t types[NUMBER_OF_ENTRY_TYPES] = "variable_entry", H5FD_MEM_DEFAULT, H5C__CLASS_SPECULATIVE_LOAD_FLAG, - variable_get_load_size, + variable_get_initial_load_size, + variable_get_final_load_size, + variable_verify_chksum, variable_deserialize, variable_image_len, variable_pre_serialize, @@ -446,7 +473,9 @@ const H5C_class_t types[NUMBER_OF_ENTRY_TYPES] = "notify_entry", H5FD_MEM_DEFAULT, H5C__CLASS_NO_FLAGS_SET, - notify_get_load_size, + notify_get_initial_load_size, + NULL, + NULL, notify_deserialize, notify_image_len, notify_pre_serialize, @@ -570,10 +599,10 @@ check_write_permitted(const H5F_t H5_ATTR_UNUSED *f, hbool_t *write_permitted_pt /*------------------------------------------------------------------------- - * Function: get_load_size & friends + * Function: get_initial_load_size & friends * * Purpose: Query the image size for loading an entry. The helper - * functions funnel into get_load_size proper. + * functions funnel into get_initial_load_size proper. * * Return: SUCCEED * @@ -583,7 +612,7 @@ check_write_permitted(const H5F_t H5_ATTR_UNUSED *f, hbool_t *write_permitted_pt *------------------------------------------------------------------------- */ static herr_t -get_load_size(const void *udata, size_t *image_length, int32_t entry_type) +get_initial_load_size(void *udata, size_t *image_length, int32_t entry_type) { test_entry_t *entry; test_entry_t *base_addr; @@ -609,72 +638,185 @@ get_load_size(const void *udata, size_t *image_length, int32_t entry_type) *image_length = entry->size; return(SUCCEED); -} /* get_load_size() */ +} /* get_initial_load_size() */ static herr_t -pico_get_load_size(const void *udata, size_t *image_length) +pico_get_initial_load_size(void *udata, size_t *image_length) { - return get_load_size(udata, image_length, PICO_ENTRY_TYPE); + return get_initial_load_size(udata, image_length, PICO_ENTRY_TYPE); } static herr_t -nano_get_load_size(const void *udata, size_t *image_length) +nano_get_initial_load_size(void *udata, size_t *image_length) { - return get_load_size(udata, image_length, NANO_ENTRY_TYPE); + return get_initial_load_size(udata, image_length, NANO_ENTRY_TYPE); } static herr_t -micro_get_load_size(const void *udata, size_t *image_length) +micro_get_initial_load_size(void *udata, size_t *image_length) { - return get_load_size(udata, image_length, MICRO_ENTRY_TYPE); + return get_initial_load_size(udata, image_length, MICRO_ENTRY_TYPE); } static herr_t -tiny_get_load_size(const void *udata, size_t *image_length) +tiny_get_initial_load_size(void *udata, size_t *image_length) { - return get_load_size(udata, image_length, TINY_ENTRY_TYPE); + return get_initial_load_size(udata, image_length, TINY_ENTRY_TYPE); } static herr_t -small_get_load_size(const void *udata, size_t *image_length) +small_get_initial_load_size(void *udata, size_t *image_length) { - return get_load_size(udata, image_length, SMALL_ENTRY_TYPE); + return get_initial_load_size(udata, image_length, SMALL_ENTRY_TYPE); } static herr_t -medium_get_load_size(const void *udata, size_t *image_length) +medium_get_initial_load_size(void *udata, size_t *image_length) { - return get_load_size(udata, image_length, MEDIUM_ENTRY_TYPE); + return get_initial_load_size(udata, image_length, MEDIUM_ENTRY_TYPE); } static herr_t -large_get_load_size(const void *udata, size_t *image_length) +large_get_initial_load_size(void *udata, size_t *image_length) { - return get_load_size(udata, image_length, LARGE_ENTRY_TYPE); + return get_initial_load_size(udata, image_length, LARGE_ENTRY_TYPE); } static herr_t -huge_get_load_size(const void *udata, size_t *image_length) +huge_get_initial_load_size(void *udata, size_t *image_length) { - return get_load_size(udata, image_length, HUGE_ENTRY_TYPE); + return get_initial_load_size(udata, image_length, HUGE_ENTRY_TYPE); } static herr_t -monster_get_load_size(const void *udata, size_t *image_length) +monster_get_initial_load_size(void *udata, size_t *image_length) { - return get_load_size(udata, image_length, MONSTER_ENTRY_TYPE); + return get_initial_load_size(udata, image_length, MONSTER_ENTRY_TYPE); } static herr_t -variable_get_load_size(const void *udata, size_t *image_length) +variable_get_initial_load_size(void *udata, size_t *image_length) { - return get_load_size(udata, image_length, VARIABLE_ENTRY_TYPE); + return get_initial_load_size(udata, image_length, VARIABLE_ENTRY_TYPE); } static herr_t -notify_get_load_size(const void *udata, size_t *image_length) +notify_get_initial_load_size(void *udata, size_t *image_length) { - return get_load_size(udata, image_length, NOTIFY_ENTRY_TYPE); + return get_initial_load_size(udata, image_length, NOTIFY_ENTRY_TYPE); +} + + +/*------------------------------------------------------------------------- + * Function: get_final_load_size & friends + * + * Purpose: Query the final image size for loading an entry. The helper + * functions funnel into get_final_load_size proper. + * + * Return: SUCCEED + * + * Programmer: Quincey Koziol + * 11/18/16 + * + *------------------------------------------------------------------------- + */ +static herr_t +get_final_load_size(const void *image, size_t image_len, void *udata, + size_t *actual_len, int32_t entry_type) +{ + test_entry_t *entry; + test_entry_t *base_addr; + haddr_t addr = *(const haddr_t *)udata; + int32_t type; + int32_t idx; + + addr_to_type_and_index(addr, &type, &idx); + + base_addr = entries[type]; + entry = &(base_addr[idx]); + + HDassert(entry->type >= 0); + HDassert(entry->type == type); + HDassert(entry->type == entry_type); + HDassert(entry->type < NUMBER_OF_ENTRY_TYPES); + HDassert(entry->index == idx); + HDassert(entry->index >= 0); + HDassert(entry->index <= max_indices[type]); + HDassert(entry == entry->self); + HDassert(entry->addr == addr); + HDassert(type == VARIABLE_ENTRY_TYPE); + + /* Simulate SPECULATIVE read with a specified actual_len */ + if(entry->actual_len) { + *actual_len = entry->actual_len; + entry->size = entry->actual_len; + } /* end if */ + else + *actual_len = entry->size; + + return(SUCCEED); +} /* get_final_load_size() */ + +static herr_t +variable_get_final_load_size(const void *image, size_t image_len, + void *udata, size_t *actual_len) +{ + return get_final_load_size(image, image_len, udata, actual_len, VARIABLE_ENTRY_TYPE); +} + + +/*------------------------------------------------------------------------- + * Function: verify_chksum & friends + * (only done for VARIABLE_ENTRY_TYPE which has a speculative read) + * + * Purpose: Simulate checksum verification: + * --check is ok only after 'max_verify_ct' is reached + * --otherwise check is not ok + * + * Return: TRUE: checksum is ok + * FALSE: checksum is not ok + * + * Programmer: + * + *------------------------------------------------------------------------- + */ + +static htri_t +verify_chksum(const void H5_ATTR_UNUSED *image, size_t H5_ATTR_UNUSED len, void *udata, int32_t entry_type) +{ + test_entry_t *entry; + test_entry_t *base_addr; + haddr_t addr = *(const haddr_t *)udata; + int32_t type; + int32_t idx; + + addr_to_type_and_index(addr, &type, &idx); + + base_addr = entries[type]; + entry = &(base_addr[idx]); + + HDassert(entry->type >= 0); + HDassert(entry->type == type); + HDassert(entry->type == entry_type); + HDassert(entry->type < NUMBER_OF_ENTRY_TYPES); + HDassert(type == VARIABLE_ENTRY_TYPE); + HDassert(entry->index == idx); + HDassert(entry->index >= 0); + HDassert(entry->index <= max_indices[type]); + HDassert(entry == entry->self); + HDassert(entry->addr == addr); + + if(++entry->verify_ct >= entry->max_verify_ct) + return(TRUE); + else + return(FALSE); + +} /* verify_chksum() */ + +static htri_t +variable_verify_chksum(const void *image, size_t len, void *udata) +{ + return verify_chksum(image, len, udata, VARIABLE_ENTRY_TYPE); } @@ -2340,6 +2482,10 @@ reset_entries(void) base_addr[j].notify_after_insert_count = 0; base_addr[j].notify_before_evict_count = 0; + base_addr[j].actual_len = 0; + base_addr[j].max_verify_ct = 0; + base_addr[j].verify_ct = 0; + addr += (haddr_t)entry_size; alt_addr += (haddr_t)entry_size; } /* end for */ @@ -3903,6 +4049,10 @@ protect_entry(H5F_t * file_ptr, int32_t type, int32_t idx) HDfprintf(stdout, "entry_ptr->addr = %d, entry_ptr->header.addr = %d\n", (int)(entry_ptr->addr), (int)(entry_ptr->header.addr)); + HDfprintf(stdout, + "entry_ptr->verify_ct = %d, entry_ptr->max_verify_ct = %d\n", + entry_ptr->verify_ct, entry_ptr->max_verify_ct); + H5Eprint2(H5E_DEFAULT, stdout); #endif pass = FALSE; failure_mssg = "error in H5C_protect()."; diff --git a/test/cache_common.h b/test/cache_common.h index 811c35e..3abcab5 100644 --- a/test/cache_common.h +++ b/test/cache_common.h @@ -360,6 +360,9 @@ typedef struct test_entry_t unsigned notify_after_insert_count; /* Count of times that entry was inserted in cache */ unsigned notify_before_evict_count; /* Count of times that entry was removed in cache */ + unsigned actual_len; /* Simulate the entry's actual size for a speculative load */ + unsigned max_verify_ct; /* Maximum # of times to verify an entry's checksum */ + unsigned verify_ct; /* Count the # of checksum verification for an entry */ } test_entry_t; /* The following are cut down test versions of the hash table manipulation diff --git a/test/earray.c b/test/earray.c index 17daefd..07acbb5 100644 --- a/test/earray.c +++ b/test/earray.c @@ -160,9 +160,7 @@ typedef struct earray_test_t { /* Local prototypes */ /* Metadata cache (H5AC) callbacks */ - -static herr_t earray_cache_test_get_load_size(const void *udata_ptr, - size_t *image_len_ptr); +static herr_t earray_cache_test_get_initial_load_size(void *udata, size_t *image_len); static void *earray_cache_test_deserialize(const void *image_ptr, size_t len, void *udata_ptr, hbool_t *dirty_ptr); static herr_t earray_cache_test_image_len(const void *thing, size_t *image_len_ptr); @@ -190,7 +188,9 @@ const H5AC_class_t H5AC_EARRAY_TEST[1] = {{ /* name */ "earray test", /* mem_type */ H5FD_MEM_DEFAULT, /* flags */ H5AC__CLASS_SKIP_READS | H5AC__CLASS_SKIP_WRITES, - /* get_load_size */ earray_cache_test_get_load_size, + /* get_initial_load_size */ earray_cache_test_get_initial_load_size, + /* get_final_load_size */ NULL, + /* verify_chksum */ NULL, /* deserialize */ earray_cache_test_deserialize, /* image_len */ earray_cache_test_image_len, /* pre_serialize */ NULL, @@ -619,13 +619,12 @@ error: /*------------------------------------------------------------------------- - * Function: earray_cache_test_get_load_size() + * Function: earray_cache_test_get_initial_load_size() * * Purpose: place holder function -- should never be called * - * * A generic discussion of metadata cache callbacks of this type - * may be found in H5Cprivate.h: + * may be found in H5Cprivate.h. * * Return: Success: SUCCEED * Failure: FAIL @@ -636,18 +635,18 @@ error: *------------------------------------------------------------------------- */ static herr_t -earray_cache_test_get_load_size(const void *udata_ptr, size_t *image_len_ptr) +earray_cache_test_get_initial_load_size( void *udata, size_t *image_len) { - HDassert(udata_ptr); - HDassert(image_len_ptr); + HDassert(udata); + HDassert(image_len); /* Should never be called */ HDassert(0 && "Can't be called!"); - *image_len_ptr = 0; + *image_len = 0; return(SUCCEED); -} /* end earray_cache_test_get_load_size() */ +} /* end earray_cache_test_get_initial_load_size() */ /*------------------------------------------------------------------------- diff --git a/testpar/t_cache.c b/testpar/t_cache.c index b855f5d..066dd77 100644 --- a/testpar/t_cache.c +++ b/testpar/t_cache.c @@ -390,7 +390,7 @@ static hbool_t serve_rw_count_reset_request(struct mssg_t * mssg_ptr); /* call back functions & related data structures */ -static herr_t datum_get_load_size(const void * udata_ptr, +static herr_t datum_get_initial_load_size(void *udata_ptr, size_t *image_len_ptr); static void * datum_deserialize(const void * image_ptr, @@ -436,7 +436,9 @@ const H5C_class_t types[NUMBER_OF_ENTRY_TYPES] = /* name */ "datum", /* mem_type */ H5FD_MEM_DEFAULT, /* flags */ H5AC__CLASS_SKIP_READS | H5AC__CLASS_SKIP_WRITES, - /* get_load_size */ datum_get_load_size, + /* get_initial_load_size */ datum_get_initial_load_size, + /* get_final_load_size */ NULL, + /* verify_chksum */ NULL, /* deserialize */ datum_deserialize, /* image_len */ datum_image_len, /* pre_serialize */ NULL, @@ -2318,7 +2320,7 @@ serve_rw_count_reset_request(struct mssg_t * mssg_ptr) /*------------------------------------------------------------------------- - * Function: datum_get_load_size + * Function: datum_get_initial_load_size * * Purpose: Query the image size for an entry before deserializing it * @@ -2330,8 +2332,7 @@ serve_rw_count_reset_request(struct mssg_t * mssg_ptr) *------------------------------------------------------------------------- */ static herr_t -datum_get_load_size(const void * udata_ptr, - size_t *image_len_ptr) +datum_get_initial_load_size(void *udata_ptr, size_t *image_len_ptr) { haddr_t addr = *(haddr_t *)udata_ptr; int idx; @@ -2355,7 +2356,7 @@ datum_get_load_size(const void * udata_ptr, if ( callbacks_verbose ) { HDfprintf(stdout, - "%d: get_load_size() idx = %d, addr = %ld, len = %d.\n", + "%d: get_initial_load_size() idx = %d, addr = %ld, len = %d.\n", world_mpi_rank, idx, (long)addr, (int)entry_ptr->local_len); fflush(stdout); } @@ -2364,7 +2365,7 @@ datum_get_load_size(const void * udata_ptr, *image_len_ptr = entry_ptr->local_len; return(SUCCEED); -} /* get_load_size() */ +} /* get_initial_load_size() */ /*------------------------------------------------------------------------- -- cgit v0.12 x;.1ݩv:պF i]r7ݕppHKa*!SbKhH!slPG| R%b&)Ux~$ȈV?MK7oAƑ< DŽL=",Vsrն![SPKy3`&TSPT@fK&`HФ&|#L*q$3E_v̨!D^![Qі)k:ecմbm)<9IK|f\$4|y?>+A1?'|8B}CnrI}:PW:$>ZMZTB xa9hK\ƿ q ܽ>@J*OZe" ζw3`{n !Di}K}2,,4"sT,]}'W/yCl u`S|F: 2Rֶu_J?/HpuD9%Ͽ h 솿Y@H)QN4,.8Vx/ 2xLB{_9ͱ3 ~ϡՔ:q~wߢ- "M9Buf5dVV(($kϴD$4o‰'ꇁϙN$o cT|9 NThK^LRhޠP td),Tb<CgE -c #EdM,-2F~sBup#N>Љ- 4Xv7K2)d}$r(ZBWߙ !V.Gm o%CW,ַ"!#[ kn¨A@+|>/?Kvֺ"G# jx<(-|wWA"[iWhf@Sº+ G $%8][R2/&5lLF{{,9*/wWgb} H-P98Ga7vyImmXvr8Da2Oia!|njue6r>̶ܭn\ BbC3X@7w}CA[mkm YQ@xcR1kV,EVb:#13 d`{9jE4)F$%,Yc^û[c}񶙐3 j1_ل]e@,-Qn6n‘cD5+f6ʲcNo :[ 9/'l/&.+cni.MNn7$ϩЫ%W'WYG0Ɵ^ۮON!2~:"Y# OK,Z8@'W1P}bnvARM6Js< q| bL!,gK_]`pkn."867cUUJrO^@xk ~6f6Mg豼>  *_u\%;*^L?S*%u[cvAb1B0g6T,>蝿+Cy#A~3 vO)U@uBz9b]OI ziPol>m]iqd%vV4rZTq>IEb-umcal™톐tC;yz7h_űIEu}4j%蜌u&]l5Ė3.ZKЍ@[0>3P3#:Gr@0C' GfDE*Ҏ橃5Hc_l~A∲L 95 xd O*S1g#6Zdkbo+Fs(Q btJ)5T ɑ!NƁ<%X#ث  LE ɿVQ,ps2zc2x# ~SB~d/h4Hs`hYkr,{˼o0ٮo\aq8OCwO& >~z̓.ӥł,O?>4[a*i0^+-2 vv5h6ʑ03dM8LY(8"*qBU_ 9dJ 3(kv?Mv[_ߤ5i Mg/u.+qdIy?yiT|b(oQ-1Skr$q%Y'Z\@5 {ADr/T3=GM(ɀ`>suL.^M3ch4bsY?c} d ­G+72_6GM4'6I~[5Lje>+y~禛ndn;Wfo^ج\, ZPa Z!}a# L&δGy=)P O!QM^bOĭ` \.> "hƤ.C|^Ux0L/L+G]{ i^GX[8{bTD2F ˙ʏ04)\SuyA;k\+ĹrAz–!nZVd<dliQ*rl^rG@diqvJ]^Orqse`EtZڸ'* IQ#.l۽OҐɨX@l} d(G|\y[ ,S Έ^7<&W t5vl-ahUAb-IH+S7BI#r76CsHܳ~D~~(gnl\Pݼ3{ ŽzyD1Kb0U΁1HewĪ}ǝ[Xp"0DRW_ daOTkzWr MR==E*=ԝMLyXl(big_Xf3|kAwh!I&~z% Tv\Xݮ [lC/5{*rߑY^di_s<~\kVplMܒ}Sy5xVrS!rJ;plUQMA\=ЭRgB&n4k!o)ZM6n* \uMeGBae *QT"*M|)e,4e@]A%E-sմxn0q-L\C+6+zfSxPPL.4ZiaZO *l }6bWd>j^eiVHѨ(_a 7INu ⮮-śRn]5"~6 /&M^5@@9Wd@M|pr#1QRj쇐C/8b=f,h-{Aa{/Txg bw/R /#6B_]帓A,|P|>J8SN ҬIk6q鼫=t  Ҟ"xJ1EKuL Odu,D 1G'bShn9q94>"kK=&k6QRJ 1ۡ[$1h-yUFxhYbY<.M*r;`_d6,jZ(բQrZP=`> Ek I~HGn \u(f}]h3\~ qM HV|ѕHa*5=UhxL]S5h֋3J[ZFu<.Lv) _nCe;SWdb7J;ώ0ߒ[-s|2n 7t܉p9U6tJ\"YB5fԒ8%c[jCeWwm _"aBq]- QY% P0 \=zBXbCghgbʆ{ioծ`c( $jBN#AQ 3hڰgڵcݴT=@ǹR”wxPiiBLJǍ{\4duj3ҷYQ-4>E&ݏxU +|dFO"/ZY/&Oe~~Qt0xꤾ å ĀKLZl7S+ t΍Q;BGTE.Jz?1d\VQy(c~u s"nB+C5/ٛUھtYb_m: C?jē`Gt`M0+ħ &IRqm)%I3T, ]%ÔkO՞/><(=E>(Aٍ\MFӕt(|kJ&MDS0{+AiY:SO`/KK'։=>ގ9_hѥSSYYJq^ Vxl̍/7on$!9aL{Y[ӹy "o\gz`R; ^ 2D}bԔʕM"*%7Щ{ i*SnمvM~Rp`|aW`9zR@w9 G̲ɄLO< .Q`mh,6LOUa,J Q!tBXVXL%C`$+V ['V/59$/;s 9KLqNϬ2^<-7W'3%džyubׁnf~JJ,~=%lO##UP0 k  m6G9\ua1Hfk迻}H=5AAVC^er]NM08cXl§XwrrI"yzI=~OW 2gvdR%pmTT%+E7ww)'ŋ>9 Ե\mԉY@diw 2inۥ: nDp ;_xN XaNx VU$<^q%3pݴjc\P72^:CnOx?; 3DHzf5#Hk{`:%naG2ed~YfeJ#4fEjxHd Ѳb)CI"0dh{I,?ךJTFD}۳hu<nԨ@,Dqe{q͘>HK!hVgҫX D:RB>:_7UZ{"Ϸo3U*%gjHUca UcjߑPX/ p<$3) "tN3yu*BW-"|F2Zo8wa~X4 8Ipti⭐ `Y֘uy4oMaJ.4tc|s} Y"u<!Wrgk+nuԬWegHk8&Ed#>¤dQcڸ3wnZ[85+}e#d3EYԨL a|˯͢mW̆ r{x+:qKBJ['b˾_KTƗ~*=jw.8FWQmF%>/ʴŘ|X;9 [?ty](}'$ x@>ՇM`'JxWɂՙp䄧O~AMBťgjvD\{9 AN1͙m}M'AHE}` @Hl'P$]J3|;b1hIup0Bb۲HP^!E/'),8z^%.#&q44Hq~f'"rՋ7MDt\ovXl'|Ƿ+>q!?4Eb)YTA* jTb0؎5 F :WsjQlV&)h}?;{!.8'uo#nT#eNU"6L^tD^Og>__+n}ԎѾ Ȟ{b Ohc[X*4ցywBjs?$yٻ=݀?+3"ͪ>) G;eAPfc>e.vp;QX].ʼYUu=n*ՠn^6geCySjwSYET'1N@AH,䉿c)ycg2|{ &W |΂oof12%L:K!>QyĊ_6l.!EbdD@;6 ,%}Nx?4*quk 损 `F!=Y:o-Ŕя :v9~/; =o7gM6㫡KOcWP|VH k$[>'${ WA+O![)E3g,_6&6m䘲WO\䬀i(E+G IjPX ^GL4?`Qjs엺?~>'|ay,v&&``bəxCad*`Lq| H ӼQ"6w)3O cʨ-jiw~;hiY[D3A_w\<< 5uJЈR-T]|6zz۾L_E!p`l|7jw"1-Ge69m޶}+GCv讟hs@ 2+d$B֒5O؏s|eBKB>TYܚgHmmp,W7DicR?h'wR:O[(0|{8()o;lzܾ|%eO^_I`$뻘,G(dS|@Zc#K1Lx8WU ݰ'Lxb2Eg!f#|H!7he,%7%hH14+/yCJ_JIFO٬!ϒP M,tdCen/-P )_)f?Nޝ 7C^Y:u(-c}]E˨R807MSd#xs1 >BiNQ y=#)B>clQϑ*]Ͽ`K(FɅaz$(K5o6#_F,ر>Suf:["ON2 _O~aQE)1oGq 0|jeM~4LCPQtjP'S+oG5TS2bogJ Lh߭:EƧ]Y HFk&˵KK"..C*XK*B4;}JcÖ9|$O!MvuP%$#]:NSkځ/2(L~YZ:.V1/A$ӬC}^&%l S =O|lU3<.ڹ?4(-@#j-e%ڀ(Nwʗl#pRVV,F =R!HW/W"iTϢ;ef/ӫfg72m}>p7-Rxt %;4"o;M6 x(X UͷU# ^tcFKߟM1Fbn9U=|_гH*]b5oWx)Ne]ƇMoqށ3GthU5в~~waVHP՜\-OIJ$d{#l3-L!3?lId~+BQ*yN+Fd bDl<`1` *)A6J͒*U3Bg|L]ُh'}"uȎe' ,D:h t!a;U2s%VҖTU%t'"ԣӀ3Aeo_x}TF(2g׌oEz-ם}$ ~e?Y?dxDᱨ]#@"XLN@q ;~=P!["LLBF;0a1O+ځN<(%&b %`lAIߜ~8QzR복Sqڕz`@K(ٗ\O:U,=Иr X).2ny$P3iQ} l>XvlXKhQ"D{~3ZNֻV+4n+VOJ{&\!1dC Ҋ C,b`GJYh%>vU+7s9 4cFm#6R 9 TuBftyTbe7,[AG*ZXI]ĚH++Ɗa*peU&-6%bX'KG?[(.XO}1.c>p~Bilo{5f ` j/|Q^Oí|ʣ=QfS~Qa}U;ی,,_H!l:}ν`- Tw.L75lTr1ʍ?+`>AbSz.(u.[gP1̆)BL6s#po%@K@`]WPV1a 㙲(Iq ؐRG)pf |w{j_a-m8Qjc9Q]Ŗjd"7ԍ#ӄh ]=Q*- SBBN+qHR^4L㻖Hp;nO_z_a/@)`"TY7uMXL]v/#N uPȥ& "˱?.AFl'];;  aG8v m1y^UA}\Z% e߯$Vl8Rn8:Jt Ⱦ"WoZ3VЭ jLo=ֿi*coY#@ѿPlںU( įS<|@зxɒaaP9CH:_ uoxĕn|r[@f¡BeٝLpzWԏ B}=V\]Cʢ8Z;TZgP>EP;;,_:徻}/cZD{E{XvDHchnJ 9”BfI=BH ; Q[^IֺiۡSV^e.d~ J~^(}2'[YKY8{ömMnaiھxtTdOrH~6^<\Oʫ'I15) xny_ `Ok3!m *Rz>_lb}uFUI !A,pFy2.,>gnBT&>g>e@>eYxR܋wkOEˁ,c z@8gqo[?Igv 5WmTF-7\ l[&bK%Eg:)BqN|g!&>?%# \=fRҙ.g!cZ3m ̊reLY$,JĿئSwA`pdKPHhˎ%'G wLRWA2oKH{픥']KT_5 y\lR"%<#tP$~VOX3>jtWN:wE/*_P`4 ^fm IR`m:כA43 %'(&[ Ў/ɜb(F}c(z*zCǐOLg̖{K/}; VJ^>'>d T{iG_sth0Abm\ 66f%{5x%\vb_`ٴ IZE! Eq)}`S/O6;67$7 1hb =Vzfd  >a9>ohy*YNkLk<<\Hx'!K׽{ i;o s&CSjv}Wm I#Bڻ:h.IgFC*L~u'm{ه73&:.WYcR!'o[ 4a 5QZ_0&NeV r;'<6K}V!q* bؼ tـ4R3н7vqh(2"2fRðOŮbkFiH<`oc +0 CAڂ!bkmpvLAl.J@ylB1|\}+E.dSGR:K"*-v*l1%2 \m.w %K>`H3%]ZT?ѡ]}0OoKmR9%-^Sl)3F]ʝ&];"]vw5Y/{'@CIo6-x)P{壶/1gq\ս-@>43 |:MhC=x@#xOh3\'VygЮ!Ed17ZgeW& 459r<99^V{lsE%j,=ݷO+@@=07=j7oJeǾ Ɏ38(wV gR~K*)5R6+oa$7'3=Ae2jwœ_gJѝ+M4Rf_}̏Z0YZ c[76P!ߢvI]dS uKQF k+z;w 3ﮓRP1"ns(YК<| S};Z8rdS0>$P,-iߐ-ATw)9pHQ's!bԩ[$)a38nBǢaծ ۍb l,uX26< \j#%tE6 _Uj [Yr0{yZ4b#{}$p*0A^6@Z{h1I7dbb7Bv 7/eWC#vC\iu=XkG:9vul_yFޜ1?ΥZʢk8YqUQeϯƇ\rS}(SoɸSSQE޴ViZ8u!ݥMeN}m{ZCV!lcLHʢWhLqA=puxe WŸVZd:] $q$ĥ'Ʉ| j;DrsnNJp@) ѦvN+4T^R, ^9ٛM/$(iy}g27Kts[N+8ݿ'@Wc?RY .1l>Z-=zBVmd_Q ަtmXgݕ\J0mE#JA>Uێ<\v| uP۠ \Z}UGeT~_V#vw ?% Y^a rPNj {x'M-B Ge1 L15S`Sb ;$שcYS ^&K)<^ .bE A>YpL?)#\HimR X34p:Ʊhvci3 &r- cDf_e ֈa)d @eMʔhC։5P!'P}?m#L7es*t6we7XOAhv1EG$'%|c*jO6awq [G~u;tmAxQ!e. U$2fJtŲIlez "wG~Ed€ vd|z e?Tx!aa^( x~{ 6r2?iFZR̟?bo[z~xTpp\1-]=րcTVE(b5l67.~ZdwؙرKoZO쓠7IϋBY;Ђq5x6f#mx΁cP4!qdR+&xW_T= =P@Q\o{aMz`:&~W;?ӇOz?= (ɓ[Ӈe?\ 8VcG"] ;|s\V5`I}b!$\wsL>נ*C&,c> 2K:0Pwt!fe%1ڌ@[>%k%DzVAc!û$|u 88zow刔ơX3hͫFpt S]KK'0&>akK ہF\MehҕNJAi;(я)rR/N{$n%'G7:f$d] Y悯US:F&ٔs_k~lܧ^ O,!"QْD̬ܳT Öȗ-I CA8+¦9m*JT+}#FB4:1*F<4G|-Gnm]n2/oyBt_| | 淕=`H@ܝ4b;G< ? ;W@Okz(-8~ {qMY d1rTZJ([6 f ʎCBGp!Zn$&st}:zFڌ1IqR{͂ [+Uџ|ڎ;-]^l=fx}a*KeSjT2گUVwB YX6^\)OI'݄ Zީw|n r@],&3dBwXKҀx0@'NUb-L7W$k~2 ["7DѲ]+Xm#&`g1hOf%gdeܮV7p{tX3 cU̒Ȇ:k=srN6i=1aIr!>0A?2HD["QQɩ %QU;v<׻ D kdo~cn  Dpi"c[N73FnPp) ΢Fƀ36[UpeԹZ7DzʆLyJ8-}dHHvМ?^a~6QFj@ 僠uЈOE*d޳Z'_V?uCs18^XR68ל(._3׏,{ݗ}BH<}.Yȇ-S dt3h肴Ɂ>~ejIW:_N|,FnLTHPT:ˣhFAx"{c$WMu$%oCaGCdpo7idj { xBbEBre;eDqj~gN;=<&VN9Lmkh|C= Tw ov..){$klK55%a]mKL"e hp-lxvH.L BLHe_ ~qbO`Hu<>F5m{ ddַYaoBfDT=̞ ҹi()Sdtb VUg۷ EN[60*{xrTp(YOK5()fDBBLJEVO_Us|fo?~ T^ӭDE3?w7=WLTNMkV9h 2* \Ɠo{U3"|0z{躴vV5CMPS÷vE;׫ch"BQa1 0n54Q)! * ZS-hˑwZvbb|~(XN̓ek:R: 7qk;ʑ1C ̤b"πl׌";G џwۚ Wھ6u) #BEML۵q}ЋQ`&T@Qr`|"A5vv@PYPZ*) 96rU%>A ?CTKc81UBoثs>1&'<^pZΡѠ8TVTģJ{MR >7l%mT}8ϵY/Sr+-2EH YNZj9OQHc_.e(NdB.ڔimtE"Գa&+(Ijo`4ۢn:ΛN.DO//' .{5ʲ)Wd}v\WwZ衇.p!_q1$\f/B+2w4@~.`9ę΃^R*"_ a="6q<~P:r349MAs4OJ ҦSna4ǷuмA+J4R0/%>aQ# ElGp3c`؆Տ]d8ދT2"DUc8$_`~T|;9%]`tKno[ȐF$VL13LJB5BҦiE"4 I-. d ιx&4Gk'ia3{e]8\q{;PY4Q $ R5`jڒ\2c p#; r ˞_OKO@-7V@ -F5Ht*3X~PO֯`ŎP(؃۟# 1'\ϘHo5^ҫ˒@ }jzq]cT3a۫jse? CntRRY74C⦼۽pB1] MQ/>UBNuo2Ҡav6Xgf9+' R?RZfsA=MBnGtz:w~,pR^Eƞ(3ߠ=nu;쥱QSIQTNu,6aAA(0d6K;^ȃ/I>Sw-]6UeF;+g#j9Ĵ{lT+tx>r:Z#dfDa* )wj;F(8U?H7*de2mѸdhb!`a@ձ#bpЬFQ>2'[a&?׷fzehNSDhxi-8X}醫hS can1I}=x&k[*E\J\3l'ۖM8H%Sw2483"cuB1xN+㴆4vosy5(Fca/r? '@U0 rDͷlRD Va=XYʢs⼹S6a=4BB'U@^z\"6Ob/#>TEC @7CG&,GEIE2dZU9쬷B4iF醄īC+Fj!`όF?GVk1$!׃$S씠_ + [Ҿ(< 䀓躝nl9Cq&5}iGዚ|1?~y뒙 ; O'HRJaT!+DZ3͗w QkwI\5~jx0imLoaEaB_6g5Tt1;bV;zy&WhusJz^K8\!,t\.C6TDwk |1Rr伇+ֱK6r(U&fYϟ^xx`-އHli:,fw x_NA?)v[^=sCD6H-)9}TDa-:$'eZ@@ڴ-<c^֮QI~.#T6H1^<l^`߫_谵)[3T{`kKiSŏO! =W=U(fqt" #QW5 U}"q\YF75a;kECch~W*Ftkd_a1 YVO@ltf@ڀi؃EZ!b˓ 7]%~;\2XƈelL}\iLpݹCf1s |E?5ԭ)Ȧέ|\t~5Q]#" E uo=ɩFkfj0֟6#/7Z)6@HP򀽒XcZq&z7"!XCB3%/ED!p݂;5YIa\ػeѾ;]JĔ{RT;}غF$fQ8]*[ n?FI|nYO"wqʽsvշJXK9',Prv3sJ+D $+Z{\9嬺㠗c<8Qs ij*5@Ȝz8}SuV2߹Om~>biimMw2،|1^#3N<4 ;JC<'t.39Zz%WJR[6{L3q-ՀawGE"V;\ki~]u۠Q^˒CǓ^:v- ~t<0]DhNS_,(lՖbD!fq%ʈEb(M> _9t샤a,؜X"iox} "X<^0FfXUO$y@m L]y+GóYc IsmUV278뽖UsM[[1A,αt[{R5H ͎/jOy X/f+xw &vcьѭU#Vt*QMnܕjC^jJV(0^Paߴ-'v[Κ#NtH 6yϼW2|wF{aV֊ $^Կ@z׎y({،ot v0Z:g1=ģݕ6,L]OqW4 pUF2K tZdXtAnPdu -Yrȡ:r6 ~LSr֫{pȪjT=nn;MN=.jFjR^%[{zd:7<@Jd8fܢ(e6. 2 uHmyf^H5:!t`^-`܉[Bs\ĖTW8\[[EqEpmW\nhG.fX!' PB+Z\p8;ùK-#S׎ՏucݬcO Kdvҏ2'@T,g @ oR0OdtJ]L!DhP(YZsvHbnnRe0ZD }}z"u&EvJyȸ"kZ4P'vVR +o)ߩ"GxW£0[3}bQӐ-D] cAb4>4d$Ð,Á B,<喝piǾ^|"%Kl h b)mB0ZwYjgwJJSuC^<9A5l?5 -=ǰOFktFטd#/ĉ'@ˑ^5 g7(X Wr2k'tJM'MlI]~cv:_/M ~#mI7k &I).4ʬ'17Ln?C@QP lg-*4NjXYK[qɃ 5ܹo۟Yx't@sb}*k{\#孷6|`m D=2]bz#X}40dKf_zdoT^bxφTY5#}{l>ۦ6UKcsģ=k^] NC< }|)fupp%*%®%u|!$ie L=VGH*XYÚwW_&QLoM: o_q4jjxwa fmgo K#t-Uao\?wH/FcMߩ^s=lA&   KcTN%~`䯘ƽVuKb9qݦGeCErK-vyI7??(879j吖VPԯnł "Bԭр2o~e4hsvH޴cWU$riJ+lTvLfssl1H$_mSQI ;вaX IWG>^BK xŹ5$[8)l& QuᓳP"_ElIRo y{>m 1H#4]={!ҽieW⇡1h%? Yt GZtxVpY*2+ r,H-QŽ=,:bDq/_*1 Y#fud"F.1 ;^Q} 7a åm rEj괔j^&s]Л(ޅ×*M[jPgˈ!fV"A[9ە_-@A" j.uJ %‹q.ٯ&('T`M.pcb[)!1&.Bf=ymt/PQGBw"iln:c A"s1mD!Td>~ poMs!:|'pם/6 ~0xtz6"_1!0Ų9}1BGoMis( Q m4!_Z`x `(I Te985 JŌ9l]NKhkE1C7E)e^yMi،O}؛*OϤ>nHc;50m G1>+u}YVRa[!R3\AzCpӷr|%75&9ʦʴR\{Az$3i DRM׀1sZ Sgh[W\v6P5OTEY;x>$ތХ,u0aL;Y]>8YO)*vMBc -<*8-fb4>b^4>*ey"GciD V%y-sF #NnQ'yu=30V/x.:vrw4pxvR|+HK^dZN>޹/,.bP'.bJf (GCGg^Ʉ]G w}*jюs\c@5TFk TٗUUdJF~IEC"zK:?Pޘ֋y5Nm&vڐg} rRu?v v[& PVæIp&VʳOwIykf'>пߍYy 5@6,HXv"#Bn$టpR.")B|*U2:Y+?tE }a먢ng5I^qJ٪abˀVq.WƳN}ûxBtZFĕ>i즘~s+=ei@Q]OK?w9'2!57N *s`Տb^GxIs‚k

B,'bM䈛BPU: >A-hcɸ}' .FԾcFYV0kL!us o`/ JTq1&.cz1bLCgtPgn&1Yv_GQeAAk"Z2(pV9TR=f{V깡ИWFv\CԸCic@|1@퍞૪%+jX-kR$vo4CoCܛd#ׂi=&q*Wz ȱ=}(rY)7H[BƌHExnhrV]侩 b=#ܮSÄ ]ː2o+M I"fdx EEA=̛h$&a0 , #$RȷW,.k$ӱfm)G⺱hgb䗂D<©&c? Sv _G2NRUV(* hf>RKz '|q(:Irqu ]Yn{X+L ۶^ ) (0hD^GBQ183n'n2.}jM@ %a#c^7M]<\gNwc`*s=dfĎRD.gK-.(n*M{&-F+EɎDYK@#@?믳I2' @(d㩳E%n4_uT߳,W r}h2A[ӈvpw@luRy)֝|ޅֳV4?,vP,sW\2@qG2Wm EE+u4e:ϤXDz3:#W7x|ɩS|A_#.A@e`#< |CtzwXq]r&Lێ"@gK*T{g:EjY_ ~F\8tؙ7ȥsӀق%w?=lM}) ,mhBB 0GpGx/N' JUl%|k.Lh*-Cʛ{VʹsA /ڝ؈:\+Gq8,oZ8mۘLKTZ^FONqlBS < X~5u2y.sX`.MP͗$+($i(?n{J1)_RWK)o^ ]V;W=.`$tFU'|Cb\Nna3H",(xS=Z/6"jMxQkC-O3,gx g(9/FJ|z2`ueTsAʎ!kS{Kr0 qoMt}rIry]zYeZyX Qfdkv CsqvLN$3㓠A@-FT*s&a#*ocj>>0"y,t?QXd5'3[1oOn4^~wD#8zo#__{gH2wY<3*e&|n(w1e'Oaưw9_3gɏo1epMɼLqMHOP10+ qu.E#t쀧>& 5- %CN-K2PHQq]2Nv02#rU/!}2x][|}.dWLF@kCڲ::yHd\]4wa+*Rwd:܀:5ǩ)WGN{F.7iEwh)b3ަIb\S_Ym+HHgYցtN@Em=ƭP]u\FKc{˅GD Xjo)$˕r`:pQPxEXV͇7TSUh3\D^e;φU`LiS[+ z;*^̬;R&MHdo1L{ƿH,ǟvgR(!Վ},dX\|@ #ݽzMGrOTQM"/Nk7yk*/~ZYX vjF7rmR6;(Y,GT7F֯(*qQnIV~+˶*HXU 3nOMk5`UފуWm off P><Ѓ zzWI LBlN[no7 YshO5wQ|~e-`ȲSXDy3lr1q?2mĎuoڟfbl[fz`m֝dlyXͮhךji1g0%Ro67+O/qCiF^1d{荒(k3AG?7)v:-ڲAL=Q]wjz\DeTFl9ߗq&/9{+ HeP]q%L䰕~<'U8f zE<ֱuo^7'ٟX&a V(hE{sEV}3څg d=e.ʤsL5'`a]QC3ÜM>T>αP:P#[T"(8=,Ml9TFtyK!@Jc2F0[K=?30e#) =) _2Dzw/Aΐ`]MKoWDp[ڇ/)Փd6Va0Lղ`8Ldec̎dEUxrj f!Pcm?.)EV G7#kީQ~ =̨j,5/q&vzhwξM~yWȎ,_|=[8E1FHAi^ L&'u{%9Nh}_<ήI#a+Ӌ 2R>i9KRFTfW S|g4}tlcx[[Oug(uVNmlp]:>o!\W `W$#S&VsB< zdhv)qEץkmI^Ծ{Ď0='k4im&c4" .$[43 "mۉ~.s"o@W ^=+?|{摮$ey Ƨg H:JĔZ1ܛ'.5̩9="q,ܘS Nﲙ'el ΐ)_"Rփ@M4(*~{! |$vMPW9qge!TxǼ(Gs&GC]b$ϸ(V%3anGq4f(kU0E+iP?ydi{H5 U<|ЭdIҘ<]t.K-#M Ly"VLwOh & L1 H]X*zC#V<#W:fMR~WIJPBv׶8Wzɝ^ am+1Jy Tf(htw]k[`J?&ާ㷝N6$[礪v>ج)o%@`E팺liHe-/ R/(1:+Z.7t Q{e5㣑ݣ$lb⼼4N7(yD-4`st+C~ -y8Ef.s72/Z5-5>chC_ΰizi+0(^S+^ `w$A+~V&_D*_gX 8jnjc{BC%mqk&pu3w\1ISwZ׊!o'JM%񍇪D %=7ͧ9ǫILAk*58Q!_.1t\)𮥤2nnx8 [zHI,4w*I~ ;24KJO< 67VGTz- [P _T*X:)6y59>hpZ &ܑR$WBhO`1ZpWBczЇ <±yk; ʬ Bf-ꑵAoz8L5)!G@TNvIJG0 Y,%)]Vζ|`4^Ukb!o7+؋UC;ԋ\РI/J^ڎ8LT@&7 m_${,TsDT2l݃HEEnheBŅ +/܋]$=|@1B#+/}DʓΧG@V*AޠP8LJk)]l~k8!SЉFeLbV0ɳJb8Ct;Zpn87GRDd8Qeԏ=9ivJgsqy< n%Xg b+#Z [քXu>PuA>S~=Ga5:E &[-v W>G"5*I"m)|{uT!>AC=9x, &ػśOLD)wiXjҸwS4sPsL3Aj`a=P:aõk g5fz)g 1 #}D,Ac ɱ1bCnIi\S!`/gZ߮Re6CW$BN}-"]ҍ`]4+i=z9`,l茬.Yʍ]>J(dY-@iz` s:5H"CסgXJn"] v51`_j_| :3 Bك2-Z e`8 ,BtEp DZiX@`\K%(8̀wari_֪ HA~qfm˦Vit-*bf%szhwvG$a;x^VB8*MVW?[cc#}i+][3α=F">KwJ<ڱαabF nkT Q"T@ 9|\6v4hѢRMy_Q? p93 Y-BZkyӵC%љ{`~reH3 aʮv)OYb }<z.onuq]:LqEʳѪNNbE:º]q1l$'i/Jk*74kʦo1cHA,ArK UYt@#?V# *SlE;⛂Y d/L Zj v[?¾I;Y;xb5#8RF.)ylya$QY{t(MIV(Bnט x/VL‡ N4{b𦟱|A!- | 8[+P޹."ƃE+L X/N7:7FmTd 5$ o4r_+Woa|ʞ>ަs6+W` ܻ%#zc4#ӧ 4*v;r ׳>pG){*4ULB o(c6l&~f>ĠrV XdkȒ[0W={a MiPJߔRo!'Q94"" >D3λKOsG_Xߍd!)׵3u,%sGf3Mms4*QUC#6h0Pj3AV[j'")]+c`. gȊ@.p!xIhTP/sKÞ*3O @XM 䢘誷Y hmts*K W+,#V N< lĩ_uWAy>9. 'Y|;㡜 g1BETP"u[T90vӞ"czx߷]kԡh&q,v+P\7^v8 !U"@Qx9mɴda6u1>nU͂6:گl߈Tjɴ7,s~ъ&A) DEnNt/ݸ^Si q`l6eA" ЍdlӒՐAl-4PPj8^KYdǻ6+MEV#psZ`7ڌsnŔ[N7eMsӐ쏰Nw)aœ Y;DؿkÓ,}FsQAѡ՟֬&vZhkZIئ%_&W3Ft1eVU]u p̕kgOՅp/lkV{d'(+g[e\zVqVRVH:M2B~V1ѥI>8-ē*}&> +dg29'ݡLv6NB<3\ 114x,'̫5*3ULbB||"լʬ\)^-Jr: #|\^4БIfEIz&=?P8ZOPAzs69D&B=缉tc,c+1ɭ%9og=Ӱ0"$;/X;3) ')EN]DC&WXKLW!*lvsL>QAў&2UwyONxeO}b.`k翹vY\"|0D{ϷM|O)#ęX"}_^}`;<q%U]#Iue&Gփr`[!vfi@ϳ;H1(O)LG1` +dnD.3ᆠmF8x4\mܬЫ+~i]peZ3!,rT(9 Gב '-'dQE-T::5;q/7D@湧45ae-}(ݬxo7~c }8wiQwIkȻ|CÌ`Űmz[%>gibhjBmwL0KybRC +s '~&k|է.+D㵝Ց͙tC5c>vPˣ赝Q^ ?$nw,?qZD<֭=kFeIxBHi!<%t7OߒyLbQGm&PKYꫯt@v\(nH8T8 ^)l<[# MK0IBwQc-ykʵw(CzX]Z.B'~8{+}StKKfGACiMzc ; =e1ʣG/Žg輳1M]=zt ™& 裌gimOxNs"G]Vޛs=d BA: 44kQ !ĜcHAkIaKteީ8kb97ro@.4Є=X{=G-tKC%$)M!.Yyخdot8?>v3JKf7VID '1h\#}$0LilZ <~##*(r #=I ֠v4ָ1- +g$_ E|3H }}e|y`|7\ɛV|a9]IҨVrE ݀œXu`? sy*p`@Lbwt[#aZ?cwf 3HI V9Sz weCI4zLMd"kED{LcdC議Ë-~K}aD(ޏKZ^iԉ2xzo5-GD#JlH!W"A}Z8[](̧;V8)nNlB)/>6d $Kg- +.OA˺v>ysGWlƷ2Tv@5Z6y"cf"78F.>f-m!7Ռb }E+(kYVyiSЈ曕8G8 Fx7H>DhY~ Jv5G`ժP$rPӫq6vHLEt[/mG̓E)DPaed)4\zB(z1U_Z_]]HD0>'OEߐlUoc:Ӓ:Nnqy&WYލd Dܻ66Y-z|m>=Z|.dչ! ]i?'&|y?q #,v!f&ty~q],2O jGvnv2Cr݁"Ce7 tm08>7R;rڨHukƬF}B 6st& vP[6kmIȑW㙖swECի̓bu.{8ssdE)mN+`Y] VՋeMQA2dt_=" %Jvm-{mi~W’F#XIBߔU&O! ڏ`۽-<C{ ߱'Y״X .>(QklW"g Rh,Ý ONvYwM;e+^sXZ;.cEtG['@IЩy-aP?)0elRo򤧁Ned3wb-x`.U$MOs1'c p:vu3~V r,Oy"tH _rXLT!{ۭ4e;2=g3vVjj&?0-z'Ǐ!W1Fڰ}†/OGno_,yPEafţhezKYH焃u5y?G?gc8>N~ED$f4-;s0Z@s8$D%vMűL̝ЅT6wog#~I|1;E*p,d Q OALrΰ:1n,.,f/Pdzv&-R?Ʊh,q[R57DhƆdrMW7{\V[pFPY3RXArqQ\J\+.Hâ,b&7eaeYVyH&|4tov -8Fϒח};I{~T*; Z?yFcz0<Ew*\YFԱW 0-BWX*%OGnxɾNhУNZE,xX|9X[=5).7 [R7RnIJî{4) HLA~(=xR]- W-?:"Hem:/5 I*rjׇh Y!R(M6NCBfmqm >!sfv'fC;ϬFZ6CN7}1elϓDyR:$ EP| d)]P}W@3PXxCgLz? }c}|TuJ7C،خފ}K:}M;̵B3CNQo샿RԧED0lu1|'{Х)Yk%3Cy@FL5u%su \)pK|Șji^ T0+6{>+8ztD\݂,qByO$Jȓ\Rš'TFe,gABxlQ08"ϗDheqD7ONCP)$nhεe&ymwnC5)Nu+i.M}U K~>4GRU& !Zrd \#hPOCܙ?d-vkS{aӒJaVsxG%[168Ӱ H]c5L*֋X l';)TP_ {HM `/+W@NAHm`&E\>r6lsO$Z83b8&uU1 *熗u#dl! (Ddku}9E{Kw3݇D.BĉMYt85ElMohwV Za{k$#C4"#o$<޴xv( q4-4l+џcz)^9@aE _em%05C#*HL?uw=v]XIS=^5KA`VtYZ䀛a/T\o:mo, r$[cgv>[(Y75I1E&=rWB;K OiǣւU~I^q@M&yf Zj7Ixߜ҅6NwSHHc}VY8KүU^My`Q RmN@pC :MWlQsB_m /na aZ w|hX±~ R{K17['Qeb k;5e/Rg_?lqK G^VHQR5%$Vj^y^+QWcO m-!~կRO[v*9!cñzzgBtx0o{2C 0pINܨ9<&(NM"+>'&Ym _|mr?BVzM=l18bYӛ#/GԀ&LvG0HQc=Bʞ=V(yE󡢖a؇-9c;t)<[zd!%zazNOTJNAAXPIbKp-a/G5XaqC:o27F ł3,x-*ץOW\C2.c鎒w`DD,FK t4uLeM`KA%({ƳoXhfFS܈[%tj̼VS *`9=B{Iz 0I=}}'Ghsx{/< JI=^׆7,j~8Sa Adޏ=Є w'Sr/MF#y@xy֙b۪bDgԋѵ/ml5}#yaoKnLW]`%?:p;nxyf v'^ %9U pW^S"D tMTfF+zdh787)aAK 8Y_:#ZSCm'6T]ܨ>#S+zxLV&Ude-*ǡCkSkS9#L'": 6@6!]`z>`H1x@Tb!U BZҤ42!CYIҸA=glj*kCP@!@ :(uwS f;|.&:s7@_7U&lr\į(gq߻SbG[o]?N3FJ!}/s3-flqU?6,N5ͫWCwT5&\{sbftJŕMժ2^8S*KYꝡr@"Шl3ݷeAj PJdJ/QjYd50O,e^YR1<{-*z! jJ1Ɗ e=Vhcdd=m_Ԃ' uؕ%]+7fLPEryK_@8< Efv^7յer68r^aܛ#$j7b["M?.iLR׏i#%u QL E;5&FI&qb[<4e'AL[g]{ڠ=އk* -+B"h;aM][ h6MƂbߨ7 Ŷ3/q>9w}1s>0Ep"rM⮉aa!KiF *n1A3@.;P@4pJ#nBSFM f>Ht k6n5mڿ"aty26 /"%1ËƸ#ԨDpf~I{"RֆL/k]Mc w/Շʓ R/x%#"W$+:hPJ~K`B[U Htn#6mn_RDt}ŕȅsEry1 ݡ6Ց/~rqSε Sx}OkZ qcOʸ\ N4ix'&;;.@um(5ecyR~4EO$ςtGyϹqZ o g~g63%Oy}NB:f!=.0pǭ*WS?Q!ߤMLBuC_)e$S14yۋ8>IԆ#;maИ! "jѻ5tl<İ.U ?QK0P&kз t[Z"#"yTx;Ul7_mYyHcЙ`bD~Hn$-iW'թ{,ɡIY 9$Դ^\[;گdJf, nr.U#c8Z 3]8%UJoijppBQ^Zb|̀8SI&_yAO%?ePI9کeGa5XoMHf׋5 qҊnvWy*``{㤗>!,Mu} ttk3o0m"{èǨt֑Ю$Vrvb7St"p&' PF¯:prʾcXOkM F%*Yko< t*DqAB>e wN7#Aϰ  >,GLsUeٿW:NM+Ge+^2RHͺ4y5#F@[,pf'qOWIu \<jm)]r}"M8˛&گp5mNKLOP r5pe&{Ik^^Y1z!`[} 5,{sN d]+JùhXѓQӺ32@RȻ+đ9kLZ&}ʓx$d|Rml 9 [E a T'4=C%KmV~%<pԭ*-ҫx0;L(J7qâ~XeF%39{t^ ;:ru*%y?:Ie.wvB[NK}1VQSVDKEXBPX걲0+%55"ߵ_W$QnIE,wI֢ v$]D$a|Nm~0ulZmPicdž.a(DXVKsq.wd{ F5-t/<7[8Uvly53IG2ǟ@WĻ~yz/\Uyat( =8[Ch+㆖OOjV 2xw('j((v]f3 $ܛ֒!u6ԝ"KUo0z1`}?cRO9Q#i,$YY` i=rTe C|.Da< #SA۞|D]i9WL {>KG##fha*v&BЬ'SPUlq&К$?;Z0kweO%E*f ל6ޒ| O{2-yU9b&=tla S m3:ޯ& rl&@3 7)AC$"gu+%{u&*W]1Ӕe>޼&^IЏ[=(r$AH;}H"^ʧfxvU׹ oNSlt:B? 7[clJ:rjaJ/m}ڪ8˥;wzr5 s!ǘIМم: m<$V!,Y|NҷR&FOqtРbCl/٨qjbBj̫K1k-X)7\O ߰{CyюL?MSu&MxUl׶o EBE I-\STek-E!}o%j{˧2gbI]=Z7ӕ# ۸iZtCjVԏqmӥ&N׸fk`!L1tqW!#ӏ쫷w&I `;lqR_mG*I+4AEBĴ& ō xkY-ES*3l%3\Hv[+~+bpTe/z Hj|:g;M\YZ 5CN!`k+yØ8gdLvg_$5IB>4uiJ4샙])FRĬ(YDDVCOtTO#[-bz?_AyP>قuY@G{+QuLڱ}#0$ #l9nvQʉxs?Kgv}ث-U垨~xCm]8rzp*99$:ۗ:ŘE6z?vճ;&1಼ͶGA-@ޢɜ3{m _^)rJO4DJlh#v@-jn_ST;WK i='ҁS)K^W1jNv( hn[9xmpD{\u"mqgq70JyēLA8OP|yE1av BD=’cFLzP' Bp%tx|k 3gh @390[n\UC~ļE(y DEy?) ӿZ?VmITQ?q \/s_:C 8땈w)>/dL֮ f̆Fs"I0_REs FNLt&;B!$k=NᠲeȔ"ʸ:哲%I]ȇ]ABS |D0VMbBEi|}@'h?w5Ǒ~RGJCܻ7$(iIBj(m(|ÅSVU,۩ ʴ>c~XLΦtk,o:&Rij52ͧ}m\ Gy?-@\솄!g7{T3{HlbwzA3_BZhçtxM )ˊTٞ 7VFDDj!Ҥ&ěd(0iG"%I6ra' -EIXR6Fm!4C{Ьe13nw5_aO:K0٥@)6*xDǯ28f,Ĩy DQ*54-Tm4r {D[q9OTMkαugm?v#?6XqE~!l&0]|(cK[.0c5DQk55[%WPLC`MM;79YhF^;B&SX Q^lSKqhNi^Z˘oI#.w wZU6KGUkQ w>V31b~ jRͿ ,8lqx~Ø̼k`M!ԺǜÈ1nĵ8W(V.;ѝKv#+7_4XJ :?}v2!8. H=e ut ݅ :Azۤ=Xl :c0OkBN̦`LXGP$%nqIc*zpbETVN۽P swL苁MņK~Y@·J=&GK|BQ *0FUT,+pj&KydA2]!f1$֩X_"t3# "m˷?=YoHYR0zEqθ*RҮuOz^ZVR[92~Jb"hĒK5& W*+UZSWo4҈fgԿBP3k4ejmRDTF`mtlC|ZWBmVL7o:gI!wJPC$Q$]u|ruugq&gE- G^ܚ\Blg#Fo]0u+-93:46ݸwmpf }*_&0A5GxOX:5RG .QpHSJˠ-c|HA[4@Bݐ$ KJdh;'re1,i)Jha(EFX H^5VYisnúP^ft|{K즆"6U&&6.:L>D[Ng'S=,JoA.l%#SKt 4g W䑥.ׅoŏ}4htM $Y^Oatx13pn/FuIpܓGL|bԺ##l>T@VBrV)92NjT' ى-ZN{Ϭ-dm[ݍ'%I V${I/XA\4aR{JHfu$'T Ņ?=wƩSlJNx"o#wQcR/ :=yJ`LJwC: 1?C(O-_=[._<#K5ȆuqnL23NfIoB"u'T_~ybʵ^n`:zNͻ!=h Vc8M)"A"@l"T#ebHW@0C*+%&^jU| xo@;yڞ$-.= iIr \Cq]I j]?7ѝmĨ)Vkw Ǒ@aUJ1hXZ1ٯΎXtĊsr4Z|#fݨo'{dqRPYzY#0oo]| (ݽM@0s-=+< 7}73cgc_ǒbGzQ0ỦpO|T0@ߴ{mzx4^8\\uJ:G)u|̆ƪ%CSB9.{yD̖ǝ\3p/%n7tY+cWwc!o'}XIoV/=;,{&{a@_=?tcjʝSwY`0 Kc -l:%b]y7O[PW9b[S+_LOg6c[Q]Ix_k[Vٹ9Abo:fU0\{s& 񀢼fj:@꩗T]CBV=lY"))r<}+$ eߘ'2/XKސ&م kɩ*uƥcB2@=Tԅ og:h'WZF̦0^x!>囅W_&AZ- +=NJ=+|qbO H^KǢI J\8Muyz:  ٿKpz3ׄ__mXL<Q$z|UfE㦋G h;zd>w> ,)tjW˄[G"a~]:X>T-ˌ1p]7bnSdyjInc2r&x{XJxuVԙi[9؆ [ kP^NT! ~»Q<0ݎ-&A[Z\H5M=x٢G Αl3sxƚ8P~vDseL7B}E49%YZC)+̷ U@;̹2 tMQ*LLH3Ԥir` 5i Fbo^t놷a]G+cCA(ߴ1!։Ɓ3s 1;k*sC|fG.ӹLmsҀ?A~65&qTxC5]Z61X*[s #($xy X1HAN}m@Ej E]*<߷=e-W $ӁRoúS*b ,tI?{P[V3QN*B´mSit}13aP/rr>i!$]`Jb OC<`KFdOYrKձbZ1C9\lFyyU5_".f跛EFˢN)NP$ҫp/YXiԶtد"FV~q [ ND=7g0Ut%r{Xf| U*1MTu 9~2NZ7s+o,i@Int2jDX|N9`LE0Ax|.YtVw;t+/l,- P"[/%^cw\"H0`i:)A#Ofz7y(EtH>I*̻f6 T_3zv;QUɁVʐ|"MGj[jVl02uպЈ 42 ns(U{(&QHF9fLvÑ&A<%o3蓺_]ϭ|q.1d+7ZZhI;k-ζLv1' Dyxf X$UcC'$` [c5;U/@ECm9SK~4w2~GK2,aa ):Tb9IL?-2LpR͞P@= <躛tV]|r d}`TU.ReӐ8e+2/oG˖API^g40*O9MNpmn'S~ h" >{H3]hFt^ PyJ?W- h* [ҵ0E 3O}@+r}m(R iz@*v:DDFNdkYu`2fL0` .8Z9ćY+8,=528TLYG:x݀^ $|=hLIA=Yٔ;|`QGi|v7fzfZA)dq `;D1dD!TE[$Ęd [43HS Cm_^J'7q:wEAh,1(Ɉď%O4(G򫀦0%I듄8ȵXHc|0[瀆wa\Pa  i*vi1>{^S\zϐhaGD]m. z+ a^%>6pUBvbW*IxO̚DGHKLB45Z,Iz^ ?{ أ1ബ; vж]ؠ;S V`(RBep|.E姳Í]ߟ/Օʬ@bL/fO?Ȝ{k`ɶ+= R}$(Q leB+Xh#PHFdR]gbJbѐ #A2Sp*XV!gKFpv0ֲoKv ŢK[^0Yn{kYˁC,fB岩7@ iMB{@=]/.|o4`i#O_~Eu&uٹ> bޅhh^[b:lC|\kْ|_;haǷy1϶h gJFU# 9#B%seҔ@7.NRFD'npߌLk$,.R.Ο%2O@]HK!w}쵻Ԑa":j=7rhI =qfR4%Q? "<2O5dUv}) V JToVg:x-l>n{0Bi~]4F;J-pG/̜ k2Un;`.5 [,U]Lf&ѝ&>B"3:N8B߆;v%رUxoWTZV+L?:/ l!a$(4-pi )&/]#0s ;|nr{_1UšT3(bUA8 (X\TXg41Gm3o֔Ermܻu.{~a˕IB6ʅ->\\hP1/ VXDcڂ LX}X1'Yij+*ӷ:3C~DZyU`tK/15RzἏ7&Mq<H?!j@$nme(3V'] 2U_ SzNĠk )CL^O͠:ܱ1Fo㲴GrYV;q2CrZ!_<) Hn#bɯVMOQetcy$`m|~V*4 Q;jBXLo$\yľc!Roljjz2 ^PzKޣGҠ(t*ep/bIFJiОNe!v9tٴ kfޞ1~@o ꇋňGkR;ciՐeL¶G@H^=0Ft+ݑGvf9>G3"z|-#$ꩉEi pц7W5X;FF!<[gDWsZ0[?|!^UYjP޹,*ez'_%e hǿ(n4Y>8[%,.ŽT勼]4c51r6|R ]Hp`G&l$=DS-|de&VRQ-R7kpj䅝1b?5,)RIj7[O$dxnT4eTc2Ϭ&ܵɶo5 {H`h[a׭vh"sGv(Sɚ PK"D[c~#u$*oFimQPLAQݫ@pU:ch{@7W]O/-~ :SH4ԮgOct3q-Œ4HFx! BVp0d`y#VF$XD.wo.%y1`s}E"eHUX/u嵟j􂪤O(Z½/:}*_xJY7  X{?M'*F1VpiɞL@)j '} |{4 e8H[^.GE *QQ^^K"U~y.tcDdwρʠC&4Gt8MG ]؃zIX9~:T8gSuu {vRD^3hAQefgQxx3>ϐZi3t.SpDth@RYd7@~1)8LjOkyH])e?іF1_FOQ 9CcȲDy'&D1<,eb2霦GOaΛ}ڨ@.:2P?& =ԲE>W|(q[ư[֙Rcf V]0d:(}lnhd{E; QxƤGj1CFwGPi$jع X(  eзzkQI(aQjIx]e[v=0Vv?>D0?[`EsHQh燜nL^ILB"!+%P:V{$/,W Lkz].|;zK+DڠK>:tB3:#~ ZmsF@oXuĭ<FYMU#F:/v6q4; V^90ŕ7p@m+CƤv?Q* @Xt4SnG53y*ZarsQz ȃt=@ wdPĽ\Yn5O[y%ϋΊ[ٟ #_-/1 ma}#痹]`TwoeTvG8`4 hy̑ȈP\mGgP{͗J Xa㡧:_b %bģ *;c6:.bC6wTG.5\d̠W> y >Pl~?6P&@}.#]nT&kSӍ9a3'O t~%vAKJ~3F5nN'/,Si$7TsXyzQ"{<# {μqg~͓iFEȡOe7Kang GV>%ah>%o"Aޢgrݤl t"^b6>8(*s6 /1_3f)9Sx/'Lz L;ǧCwoCcMR^\s~?xX =ܖ()Ұ!ۥ8 QFxX sg/x0 Oi/%Z h/ǁ/D%@ N>]ND Cu]3F꩞ ඏ3(ZFL_t9eBrU׬K6FBDpNMRvtPkvȬ(}+CaB^F)@]vCQKQfJx3{-GvU MmlzXMը-d>Bl秀}#Q.2> _S1mW];`ОіygIr`RERĉ%!af _$8!*o"ߺ^;\ FWSwB̷eyG Sɦ++Q-y9FGEr o;V݇zi9ӪbL$3Bc2>|kB^!1Y_TPzɈTɓb2HZ~,t$;hNLzGnG&ωR5\4reG&-lxpjVsPMMgec ZGq@g͑B8ffte+(D\[^Y=Zv'Ќ5r2LY ţXu"WMVI^̱È!nЕ4_Fox~ftHUie4*+;x 9AO[yD@(eƆ2+M8w 6P!{`xVVLjY\/4H J KlV"kYGNuB`~[r>Uw }QJbO7 n (t<ȟ#Yxr<b [V'sys3֣mP/7۾#.k:fO6lQf?mX@@9 Rbعt6m5r,%7/"c_/50c/YWbQV Nλ3z[kȸOLlkx*bIů6MVwk>FZ91~yFSX젓AB -X_*FlE &.U,)~WdN)ѣ_U8L<Me+Zb))E]q/vXh+t dn5(焍(9ܵBv8!`nE!ئ.Q@əU $\-C .ZQpW{Ad\NlIw(.u\DZ]|¶܆i?NK'C@@MPZ͋EATU2VK,&BPbTDr2Ks@}^) G`M(}A,@2? YYfiwfcH4L 1<޾ *îNՓt>ݧtlUڌY7>TI,k D!wJ%wѺ@&u* T 7 Pi/)<}\v>IF8+4!ԮMAه3ײϜֆC ipBG~+I1 ?Y fiH.zմ ( QZ6gPSi493j*fTS*YvwJӇpWȅLr5YUU-}7 Wrj[~}Q!邏GK*\h0Q 07-*"wlQsIIen|);[& fL:ayg#+D$"bSȂZf($zR,ԪS!!`~4Gh3,zmC 6ьBSn>fjpJ#ؓ=e 6`Bt"yJfŌ zES4_mAwB񹵇OcyD C8 12XG6˷P9L=`ҜqK>xӳ-j &ߧ+J{(;pC q3ŷ̀Je=8ϝ1fj+`3sǎ f%kկۮ[n@$ix'}r| VgK N](dzĢ(Kn:.Ru`u8둞SÇFHgꦏ li v|Zt:Tb{帿 dK&bu?AB<`'$Dv @o[~m^)꬗I/y Cz(,O!BgO|0ԛjc*71?VMk ^/<ڊv(A/,xƼqV=dȋ\^}W&4kIE=F*ԇHD`<4E\t|TLZUC#.1+3 g?Uy.x4+E!S_Rx#Jp?ă Vpo6Fָ-g&']njNxahh(̐89EVH/Z~>Oao!G"E$^z!M20g唈|8aVAc]fBqNAӀ3LO̽ x0zeq;VUv܄W`oL(ms$>uW*SU@nC"bxCr^A O VϪ퓾2=}= !2P(7*c^E\wP1 :뵲Y:xq9 s }NEV'%&/:=T==[,t0/ey툐.iSIXP=î7>lwQ[$`o`n#;/{|| Nʹz>f"OچA *h,]da,+$4>ߍKA.MǔTRt 2SCF@\bDu_e̶4 ν&wC.j~ ~{~[x_%2}C=_jq3Zܹ[G׺ö3 nu,Aèԥ~=|ecFrpO q(54<:k8R.Ҋq|1R hXI[I-@?H/L>gIBRQR $xG+h>K/[ap}'$ÀyQw>b;]i 5гBpA}ͩ-(Dĕ=ȏ}rB q ItgL 4d# 졨4 kԪTksSck̒Uh:Pj"kSgЫ׎ºᯠ*1Jb9;f];e|cg4̾XkDP K:FDp|xt3:;J gDn*-ʊquN` Kyzf '.:(\#X%3#1i WyӹDeBv}H]+ T-% n( ~:%az17,ZvR_b6v:N}.O, U?'˩¦/jFQb6N, ^s «`7_`x|MZs,{^=0qä1ʌSQYtfi\$hh` *2he4oIiP: ngqϞLDt ni{ds|8GL}Q"QCql(2 @ dKJ$?~G98\5dٙ}Q^,>fW~Êu-* Ɗh tQjwz3#lNxͱrn-)xsLn*RwgH.~"IJd2KL3{mӸ@axBfx՗@ '2y3Dܧrt 000.(0$2EF6ȑ+1.l^fI+Tk D\ȧvVoiJ:}f#[)Jl 0/Aw$6fH^5?j$)č D t d F{)r]k]m_vRG䆌VeNHPFWnKc]ǫSQ $m,{U# _; f(NZft#a#|AXT#^V}tpeH fFx1BK`(.ջ }?o4H`7­<㜳~b:I`@AϿZa~IŴ| 2OߴLYwgH`dH$aWɦϕ=}$O7CXzzZIAF7yLIӻT&J'9ݷEpl6Ϛ(&Cc>W:?Z CRu_=l'k7dV`V $$Yo;MU3īv_߂yRjc'#'ed0 JǕ6YB(Z:/ Wc`$-!-e.M8—-F-Ef=+ @D YPO,2ޞt\"%Y-%JtYBͳ R}a۾νhiB 4K~E)**9EZsG~aQA@ Z9_`LZ`oޢ 'I|$'5B1d.A=:cƐi,fy|gw(j t;ؠB-pd^9bq@8L#x \p䓲a,ML *B`8!^D[bC&&Q()s7c8t äW+#0F+ůe>׹ؚvz:\ޖ6"ϔn$tV6#&8E8$o,l )&]v9SjxTjXVWF3zh.gyA2p?W." $B\(,DڝH_Dћ[_*[N5{74TEhȌ2=hIS|k 5=A~B!`KB УTN\,JU#_'"vviǵSt#*c:tr ^bƟzTΒA s'2pX*ެ_FXVXjD;F_*(C LM΍XwAFW=.kFCirGsV(RCG,9` F=v=hT= [VS {NH!yFPO: {j&eEi&R=Db(]<12KDHOɕ0P;om4ɷ%{5$dx X,k3]'vB?,V^.*_lfcBfޡ)ya#'c^J[( Pg [T% ̳CE U\~l+Nl8(*cxu%ˬmȯM $>hTldg"-e@,MjE@ι&f-^_xa]Ta}fTިADA30_ocy@J>K+rW^6.k.5[8ϖSnN$+HIu> 6 5!.MV;gxG0e@l^*d8Sī![}z~gJ_C U*Tݽ* k>gѯΈ Kcn"sJד.HP E & 6C跏![͢]tc i)Co0颓ܐ"# z؃2忙2h-xLhF#nٟ4fa?æU")1iiaanԑQ0hR:D{}W3}EsVy= %=5)z$t-=sF%?RM/ )CHڸ WN)ֺ`ƽh_kRĎ'-ii|hHQneQ~"K9ct%9tߗD(y(^Onityo;7ٷ5+MIeu?z 3n78Foټ(I-Zz_mm2 “.nG!`3XTs=F+CJxdb_ְ24]pn~1x.j% S I7Rc1^Dx6=I:Ťgx 'X͉OK}tG^`6a}#[7beЊ!~&9Wb@iE FKkӈ΅{`lX~NغأwR!Rio0p)+/MmHm])6k9g -Y# ="\i.vjYVV0QA_v1x8C:wR/MnW0&0+]*%ɛR0/-A/ |P_)$NV27am|k\^߻uTGڪ`޻p5 KOoc˝J!,PJ7ZnxA…˚+N=IJh^\ :db9׎<Bf?@>INF l_az*ce"|R;;K1wIH7Fy0JZw:i!}X 6"E W:KYā'"d(q\mc o",|PΒ.Ԙgj眃nk/ݿyGs``RnHS;9aE˻Jk(!a07+{!ff j /Rֳq>B-^<"o-wєʳK*Bz/O==M_[ @zH/-xtkI3`DpPƸ9KsdɦĒj/KVYJՠܠ *Mw[|_Y$iqR˗& t鰇x=F*?r]?VL<Î ram?u 87"\;$2hPPg׀`P't5BOz-Z}]]8pp"v{8DfpVysl%S4@W*VWU VtIh&-uh\1ļr_Ntc^BXJ c{gO|q9߫c~F;4p N.mhYt5`9o`ߑ@%1w8:r\H/ȗi$r׾KP"I;^xVи>l8wX4ܒ[.Onژ `ĪM%*OSPۦNXu`şOZ[.z8}q Hcp jʱndLE‘8AF{[BZig@ɹ0.nN M T޸W*Rl{]HCtδB̧Y3uu{L*tA*!%O<=Z\kh` .S}m+K~:o!.9 #Gn8y[cpC)=[}h+O˺zV8gd{q=,KF46T?7$yߞʐ 0D:O<@S`,| Λ:Am>m&3מI%妷QxC!{ G=8sPTp3'C0?Md"?h a0穜PIs;i:.zη'_9}[.Mo?zd4-vkS0)7C:t"! }' JhX2ԅݟDObKq=\xxco(H@o s5';t ^GHNO'fQYg}Yv#82Sv z|$:PbˢN7'Z@|w8 ci?һ((ͯ ߚ(]DڅƤQ`6ӿ#xz\,P`yGNTR2[JǗM5Jw\@i7žニMZ]Rdd*[ıU!Ը"fM>¡ԠF uXX|BV୦1i%}Rւhy= c+W|S+{G/(fSqQx8"1"ܢ'g|X B+zR޹mj :N'}~EY\2L'O-{=ɂ..DĻ4Glrq#M]sXqWXY wS]\JsV9av!by<,c>H!x5'_9~3=,hSUfG>hӛc!BVE`҈WVa-w!,_hIY|gQnk⬓,&ٳL8C[2$%M0UL!UƎWu2H'V+6)LVgB㪶k=s B\3D*w0rpk(!,?x<`b{U驕l ZW?m~0%e½?V叛cJxF59 *w;WWRv K`i?cy ~jMO^X pPZ 6ƶ9zcP6 d٨̀4O  N~L#WnӇ9EǼ g#,qjXh[˟oQrS61 P{4 P0LK޳GB;P$tSJfMo6v+57؁i~hs4e: n@S&q<5 y蜅_MeM۲{cm0vbu%ye9B!-/ި̠'SFeJKY ƈdK,qG󒌿>i"Iɽt1[H}0JD}Ɣ_"% -6(iԎ綧ԓQūwiq \#)qX_2 ڤwoRn캻޼’$oތS焪`,WשttkjOMH\B.N֎ "oWB `yO" >̻"KY5_&5/l)@6f??}>`0d1襔ySPI,ȜAD5"v/SX"9FEES/utَY3; % V[֙5v:E4DV.X> AY7W3̻wNpF%tQ:cּKBH8 %KdQ38EȀWhdR;O%ƿ4tt}ijԦv(z`^+๟*b'6<8N]Bq @#(zqO[S2%T {u3qm~C;Z!K_6OF+v0j6AM\?yl*-eTcf^9 grmU}e%XP*b@cDpޔCa5CZ DZSxa*ltM} TM ?w:: Z1 ӏ'Q٩8 '} 1[k˱FcX.*,~| uLRtDR3"0 _Џ.Ne#й.^ʄ;c7B擱w.f l1|y V'|A[㤰\iك =DpRpXb 0J lt<{Mbe@ gBi`9q@ČFl]ͭ^bZ!qJڄo[ U./2 |"ءTԶ˴>*?m "ΊYE6_.WW޳$t~܊ ,;ָCtv!v5 | O)o&D'm6{k6T(Qȟx}l\TPb1t8=g0DzjbԛTPb/蟿o33È*DA|!24fzs |ʃe!*ڈ aJǜCӳd"ۘ#W&2\e+&g4k VZEo) c bJՒzvV8D[D `kn"Vc@{Gɋ.sø:UKC"p9o 2qha'rCzܻ=W[-/sM\ x?icxs &o01nv&zrS}LIǐ}Fc:qKWsؔ뢇7)q׌";q8}NƸln{2C 0B51W?ޑoˈe/]J/Dlrܱa"wB{P5&p+w;eG8ͳKF>y ߃qnu  ^DJ}H P\H;`h hNb-JUD8iU0EbTs9?rC B=b!cBϧR(tGU6{S\9RvIs1߿dy@X<9߁+>"TH|o-].h^|1hnV`NYcGtZp6$2JQpvE9 rTmBΆV5~;8V&I c EWAȠm4#O|QRhX"S} 1{ȗOwGF޿*:-\opd\xw%PgaCqHjʷkˆa`2ȕکY{\kE 7bBdA[E>A?ekD   IB%@K #1dO7 ѫ'V|`B'bD(˂Z[עµUD1]SM-[@/( x,k [ƥ3`;FQL>o=8>^?M 2jVgyF)-IdML6AgԠ;SiPZ֫^0i雀 C' 3'&zߓ2DIkMuыT }24XNpь{: 1ssc4mI'Snߢ^>o[%=8i?/b9]Ĭmm1~K% * i[/sVQt>'}^,1<kFO׺x iy{ Bap޻-4^uW%h1~GB[D+ $WRNm%~L{"+݈ x C9!%=yPdm}BXfr=Q  X2sUG\ |.~voy{4i2\׀8IFc!ǃBKD#@hi$FѤ.wp3!$&4y}|, P^$=3bUϛqY.w`$C6n{zșG$ibk{ - |,zSF'+:'U;8ƶVRë/qL/ZW,EIϜEP7ʀHrf9k5XZ@w<%fR6Pԛ[* |ANCkc4db޺*QM-˯뼻ЉXUB8#Oo@{vmDe= %_ĺ#ǎ_.TWLaaw fs0hEIP^h6]Quô^F&'%I99d1ثA"cZtں*b3IJn@Zc5IV. YÒzv= Vh{ds搭XA(ߩr9Z885ٲ)؜m|0_B3S0 2*Zە.>-4gnk)gNs:rGum l4,ΡXz7!W{VV*"J T5& ֛9ub酀R<&@!\R!E Gcp@L ձ+6Z|HQprblv( XPI]8ǫ&o1T LjL3lu6wJ2SC_ڳP|h=mY'Y`D(񨏈%7h4?f"C3*GAqxТ,}K+/wkEg&v[沙RͳMZ"١dE,4t=KȰ|SAvٙF?vٻ Z̮FC(by/ҖS,XƄ42hO/sjra|X$!,]3q1p,k$Sح]Qy ! H$jxxPݽˬhgAዙE!%" Æ}Dd,az8ds>C F9/6Iщ$&\yBPᗰvYڋyusÕ ISӱ5d8١eQԙ8{&y2K# DsPx%䞭ZyE8~ #;l.;ysMSs2TAߨ2̻my3k9ߠ\hiUPDaܔ,k`"wX)"dBd2D˺p){PN{{k~cgT,shc EϷNojwp$lڶL=o'.::Ch?U?n䤒>أ(;z*Jۈ;GHQ \f dxޝs(X~vm $jJ,I#.{G0^ J>Vj#3KL9QW4uqz:}Hdsׄs&t^u^%6Vt+ 5Q'CVq/ra)' WDGrۛH79} K$r"!|>qΨ1mQjO(k:VrCO1x #x% a*l YNf7Mti,V6֫孆}Kumkhh+7$Emm֝,*dM&R28sMa} 9=G6rkUw3& ·@"EAXVKv|Ջ8r\*RyX_4JLL4(,n.ui'lHF/BhL*^U,!-X@8ք?pcݪ95]t:NM3}nW:䜄|oП|d4֮>"8bu߶u5 /Eg^G% 6o\YJPpBs1iϔbrI伤(@JiF~d0=6, 2i`|ʎRo+E qS8 dI{XY; _ս,xkm韲~X{SvA)߅ p!?j`N^ dgaTQӳcV8S*E8_% ]$+ ]&Ug=@]!E-:Ⱦj jh A|Dl:S>5DӨ ;ZBAyjTZ-$>3j&٧MF5Hͨl0OOOA4!;Scp@eK@nk7|rכKCpQ/S \MQT\rytENgٯt\Oz֯Pxģ 6/MKXF>0V;v5)4z=6&~ d~yԮl%ûA>ǩf Ȑh"͝BǶB3Z|dAVv*מ+8L>"Ďߺ+B^Q,>Lᔔ}XF]̃58忛LΣ<ثMtWg)2f/*]i&om+ûdRQ>.c>k*Kqc |AͰ4o#"E0}`ׯ:! ৡS:K+ |J*7s|saYj*ă{kGsn϶Td3u:#>KPBNnQTC!ۼ)1sSTyN<"*!bY8 A( C<6qm^)Z -q;nTF>Lh{M/&hzd)ՒԥKpe \w_BtO;uobh-W1*b+i9K1 ىPWU˂$!]8LD&Ol.3+߅'9Y)=)Xjd,~rGIs&ǟ?C,ɣw{ 2εp!Yqf;(cO~n^$tC@mNqD_}p8-O *KNߓ!C։iJS\Ψ՗~v\:S@JD$3t4ߊ۞ط¯`M\ GLXD(gn@?oOiHz;TaJ.XrŋL1`tqbo`(хd 8?4!ѹf|O(^(93o(X?YajbK䛦"< 0cS%a5~&_9BOC O7Ki]7 lĬ؏|ڡmr(r8\:dMJ8hT_UϺ hѲ" k1h,g^;|VѽƇ~>4L \ק!d}~%e⼌g|i{~9z~CgEhA-V.ކ ٕ{|TL,ɲq4ң zȮeaHHNUʧH$?klz5wSDOs8r@[[KgHMnim~Y\%#puG ENՊLfQTG?1+U9e[[XrmoEjݯlt*y@$f nv}Jg:Z8tn),ύ')p)AtǍ !vNsmš[ԍk{%B@Bz)"Yrwp$̋?GWG[V/ճ Dii lqWbl#2MId3^˻%O1| v_F0Ü̧|oDwo c&V*Ni2dمGY4wJ2bҙ>a!%T蕾aBލ̝#퇺~.T̠m2zDA+ץݢ5c;j)v(BK )ا*hu T;p;IWR҂,@R=eڛHX/ op{`j# )@~2Y//hv@@lHtaaQ#7 F l.Q VXR5" r9A2,F&(&9ahNaAWWתw] Lי@SsP q}Xϡ CKJ<`1:d[ wg(!H[*V" J [u{(@Ȳ: pm9- 䆁w8s8ԍ`,\˕^Ъ)۟ ̀o  ,( k ^(AǮ*@㓿Eu#ne`uS;)Y?AInn[̫@\`V q| y[EK*vqYO/~:q;VPx^mM6KO,;eň@'"yP<$Tdݼ7qڤU4XAP[ۍ_l HsR&tǬd6{/ ZZOз۔mas@yE_ˍ NdcVe%[~>=o42܅[k`X’-@Svj3b(7dHb%( ݃I5"T$|΁*a]ӇB(6T`KvjA2π5 Um )>^  $m.ҙt}EA~i 7v"5=Ro3-V+>0Z/˜)ƿS%U80{E=s&)J: >ԉ^^1!f_hL_nKF3A-K&qx789sa \+(zh0.B$Xv/ݎX~U0|ݟi>phc*0$tWv#(|pvu\C;3Hs@ q(1h.9`RGpn"x\oSFv&o!S, b#z]lG&*QO;xEEu|́E㊝=v46EH"}$xEc e,]z=Ĉ0Lc4b{Vh0:o K`o ſ5)./%e;}h`'T'ڭT:62`D6;U̽ukV.fjĦ,<˟T`㽚p% 5$cH_8 (•nh~\B\ `@WojLQ\?M sQ;߹KB{kO{ [Kjr+&^9XA'] іwxEO}JugʩJ%-t9zJKTŚ'7; &_N jEJm>4*MXJɒ;?"fלOEVc!O*9ZΈzH-!(N-öBRkHRɺ(+^?r{}/Bw ̙-LW܀d}HSg%@Z{)FMx^/bIߦ)MPġi̵;. P:+xY4p4nODƤSծE*눦I2?Ȥ+.!z덀E19Zs݀&%fOjA.OW@lheKH/#+k1i.&*@#5+hB6-}E ;RTgI?@-Q6|wTW{8Ih' kS^$B%ᘎ&j(&tLP{6y Mte<ZK 䳶3Iqk@Ěm9!7/ t9MǛĉ}sMOZ 2[/GK["ϝtm&#^A[87ڻb})Zu[lCvf9o۟Q=S͔" k?0m/ki?}|erFb(]X)xvMP@;ad "آB[?ՃPY\Xv:>kχ,љ(r֪3oZP/.`@WNl{\XwY;/;DaK[Q2ǘC;UE_X?WN?ʹ )}z`5حLVGܞRm"6ǽ~XL&ʖ92l(fwH~O˨ZSz  4(qiAMt#&iY2P=*~,0>hTTDsMuSv4Ƽwґ v(C NP:7q+?^Z yy_^PduD"a}i"vSXdM@ٚiWrdՅfDf߶']Oi wPՊH (:QeUkaXtF.Q&E"m,YE)@K }u@‰Hc~%1,>nECyHH -DbO5KmWt o^%X.~w\KT!2i%c(nΧ^ iRP8um |]_&/zp%=[o U- 0$"z ,5Ws+ (Ö59&~d䇽/( ѡ;Ny Z(Z]u5~=7YJ6ǎW9Y{ -$00 Wb¡qskݧytjفHׇY4"z&cԺt‘ Q9n\tT$F5fA''C8UDX"KEo^y@Mw!TZ>i*#KӔ V(3*?utaˉ˽?]H8(13\-B #HOlWL=Bb[; d\ҶSU+T-G .C*kV[o,53)`ma Pu4$R;>pNkX+{(r{{gMBKS,VŝnacD:^F T6dw 96Èm%1@Yp8wTV4\u^lH> %<h98[[R+k4vjldCT;:*Xd5G?0/_};/þK8NW1@ gy4$RH6wnhL۹='iw&V0삏\,y/gsm?Ǹ!w&ˁ(úZ92<3rd\܀YFmVgaXRg4`&x9\@0 ' q,h [tFZc)?HN erHaD46tjj n|. z~ACJ н1s|d, Rsc^zjdx ~%wɶp3QyW4J?Ay֑"5qlG8<y=ӎdž3q2lbVj\.%R֔x]:X&qj'±wdD70.ҟ7vZy6fPz-M.h&u;'+)q-틂rS+Vڬ>"]hFV`g4*jdls?8Y53Ԓ+s~+xԚ(퇤$-R<|Cl[sる+GW/ į(@/-mMhrK0#7U!*Dz{T/!p.:iZ; M$bOc{6T7+} x\k3 6;v+:0IrNJ_%toBAb d75XUYt9GBnnUvar YZ!v -E,mq|gZ2"@IEKڰ4%egB *Tfq3jYu- 퇿:]OM ~TKU'RBZD`[OYV.S}VJao6"i~#YER,;SpR'r!7 JQK/}Y`|]my*ψSceu8}KcJEDzbG15/Ҏ ~S?Fij?#sep؆xqOb9^>YG5oO疡WBñ竌#A%ն+WZDw}M;\w6,:f Qk|X2>#9ѡ|#3ݶfnbO^"QfbTuLj{YE.=?ޮH{ǻ;vZ(9N3^ :!aσ^ ,AqV<,P;>(4ƸIBdeb}N}X{AKE!da,)IъѕFt{􀘷6ZmG5$GZ8 $m:M,KSB B6dMvRc'4y9ije%(v] Jtnhe8nT_i??9]`q_Z:]Tzn_Cwhby%'ǮJ"AgʓfW @֍/3W;Dz*Yաl}vEhTuǙk47i qM𐻧$"7. 7,hhJBtA^20 5e΂sf YWs+76Hg'OQO3)dŹ.9 iLhsD5XՃg.i&UZ Sw~drLyFP4o#@SkiFCU`kv X~꟨O!:+ϯhhEBTjjRCtTtk5p i\3d$WHBɆ:% [yKoJ((ƺ[|!ׯUτBˑReV,Ǻ֫IZiA`Oa6b!6HY!n%`uo ЈõqZӂXAF8u et$ hUͶy{-';Z%e6tM7N7Rm1mi<EW_P$RVĄKؚn;Hў3WazHKEmuOc҅7 ۤI]Hlڿ#AO5Sx.Έ$fqUahofi)uXR;kǫj>FߝPhuD=tq"\8t[s4p0KjҽBßvgՏgB=XWK1YfaL?=F>Ajs!̯s@}G +HP؞*sЈF ug`b2\>ڍN'].[-Y}kmA%HyX~C΋Kۀl Xo6l[{oZFa"~]ĀQ{ّD#C' zMCIڕ7te/%x3&JMb{FW|VG{Dd?LJԠs=, lxMZS `ࢎn*;ݢF3Eق})dzŢA/ْ6|7)(e ]f9~pĪ]o^Wwo  P,4R" X~Ԟ]{ܒyiAa# A!g\W: 2`\bF;Q6H}|Vlx!Uac.pH*`wcREă -Hu*Wc;m[ʯsQs_\dMV߿tIJYifQnj'ȐOr4CD9L7*D>gMs-q|&VC;Pq]z1!'Z9jgw?W(bYT%1!i.Yk(ӟU2"x$|Џun>+$B 3`{\Jc ȴ\*0CTݖʺ)@w;5KD%,/&oh!m^JQW=HZxzAiuyX asðuYQ#A~.y0RދTYiy$cm/%3e SV6t:y3~؁7f^ b.%&XդSX{Z h 'LW +k9-F!trȯYzi3q|mǓc{!*nHjbe/!'=^93t{B}m3ɿ j/d_jS܈%Uud]Nbv]ti|VN V;Z (XR :u]/c2!-fRͽTSk$?4%xl=Lٟ9 QwP +ҹJ##-Z^CUSvdpaGIzk\+ۏeruİG^;y'!GEcUv^k}rmQ B$щӗ J{3UÇMWn#@F"?_evj{eJ"(ӣrĈ`cա0(Юx$y[I)MEAHW-DVi2gZXRG{b{R-9/b,T:p<H'ZONFIGl%Тa`)QSF~7Ϯe*&2 2Je=6<ת_vѢ# fI|nT&Q*crc sWȅфPc.<((=xt/` Pn10BuB5jȇuWU`XS $n S0o{y,%|)gO,?h;b>d*6Xr ]o, ޑYh@ X%7CpثmZ$ S3oF{17*< t +9'im9ۛsYD-g=( u.Z:&VHǫP|HҭN7gK3uȪ-7<>6Xڳy*Kt gzxȒɑxt}x.,UvCsI5xt9݌PʓJD@erOƕ%g\b}b *> T`Hz#`-ږ1IZ'tAIG XeKˮn(yl,N"HT\wX\ l|ds 节&9 % :4&?f^0n1[lv"ţġ0 $ NP>,ȅphyzVjѣA {Մebb,oK@ y8L3ݨνr@|EOcv q>ޗ;&O5|efdV ^G\ zwtzݡ)tM>%kg;Qqj Jl PuG j/qxHLirCŇwzT]ͭqM}QANSm TYRkVAo"۰JgsJ슻/[ETуF9~8c6^IYJ&k:ҠÞEgM9ip$T ^^IՆ't>Pu:B>$pn{g(H綘GTs$Q9TX!B)80;RvLXfB뾒DƾfNmM/uռƫ(m vdGQ҈Hr%y 3MZ(ʅj`Wv31$6I UxCO+oc!|BQ0Fg>F;31%H0w*2Q"~O5CwL{].H`;"bB!oƍ_^xɻ˞Y4Q "Z,C|HLĿ 4ի\&TS1ް,i98F_龋6CrJ'}&;6-(coqoS;N-h?Ma؃AiOZ ťheҫAB0 |g#:dɈ-`lu(W9|Z)2N=^Lc7"3G aW$K7aUq!U83"B"gbGOJ>d8]M̺M4SӔm? I+LW2!jGI s #v T<@ YXbA^Ŀ~?AST;DžJ'QSs$G\ViƛM"%g|uLxoݜ$б/HpN캰߄IC G \{B< S%E߈IFG!*4DBt'Sfw'Rpc3Hvb!X.(V~ =A+{ 0< r4k/l^ @f03 Kj]X)&Hqط$ytg$ QRN ěכQP-kc6C]ʵٿ k+\ڻW=ö[]թ53}{P rafY{!6Y&nygPΣSq>zt7^2 4e!q?Hf+̻תk_4፯aZBJ9,c~OaCmb7fhXl0Mㄝk5U(%'sDpXvaE‡+ JqNf[(sB7L?Iy`@#OdN]2 ~-+懶f$Xue=Z8Ҋî Ğ J*\tr5`;ɖB T .!\ K\d5k7s=*}:K/w}P{\o!] II\D=o`G6]Rni )l=w@D1D"'gU|E͕׆pcrGHC9u콺'@h;2|L򖷋6C\8H+~eXƂL~:Rq錞&>5=Ŏ+柽vܟͷiUb2lrP?7nzNO(;Bb$ 2ZƲUBz ƜAŸ/N'tےtj q c,z:6F| 9f f2纸N}H]=0\^֘xcsqbLTͯz0uPa߼6 (D~uN}~sQ-"5(*_I JD~5aGaT6MHp7r|az@>gQE_;8X0ȾՌ|^ b4=QYciسz%g"%eD{x^dyI|GU=oџNPKms<[؜Ft* X jZF?فA:J"~د^[C!`8]uʾbdr[X'6@^d ;Qy&,a{^lYOd$0'"Ogm]Fng(cxm4eEv7[w>7P5 W*6T8nxg̐<~rxHp>7H.oLYQIgrI[&n!*AUi[|a D\`ֈFR.= >!Ǿ4,tYV"!i=TbNL%9nlWkяuOuH! U ('rġ^>V2BM0=M.l ?[v:ZІxy%He^b4-Io7NPҐGwD7ȉ0f5fsX!!c9‡qd{U*s˴\^ b/+/c OA%ql҆)0uJ5uxbՇp3EnA],el +) ]3Wf 1aeq_Z1av|X1/V? >.'($aTs-qOcID0'қtj '?#Vt9j}Pz.8#!zNZuMikA8]&g`pܒohB4n82S;_2kXE魎}Wl)aL^ ,"`,1w jv[R>~$r6xu!N8=WH7ƠAb6e}g ~m؞,1F\B '*x&dC۠y9$ad>``4hl _AUpdSd`Hm@Nx~ӀׅlGs+5^E2i$M_K$PtKY,[si\F'){g:ˆI^dN #Hۤ$7MbO 'vʧ>2j!tܪkj@{_< ' ؜ * it\Ox7NŨHϥ]"h/Z5Z[3q^wlSs8`т;9ew;,kab3++.nn1Է';l^MW@2|1,BV-xH6 5}IՒh4S@(u*תČs uU+źb Q/Rci '^,A0JZ.\?z=CKr^jc2"BnQ ˚XZޣn拖@$Z)^vLL‘m<;AOtCvS-4#\;A!7?R /:Oy]=O /ÃC 4Jr![۾z&nFin=z_ PNd2V(2&r [o[8m'(t}kfv]k]wCT({fpS|J~Ik+. I X$j2m59 !|rC M&hݥ9[\=BT7*Q6l bG2L|Q31̹)n2,҆T{~6*nމŻ:'|^ڻ-/NbҘ]3(B\GK0>Ojik%v)!|.f ]J8q?.mwHԱ;Dd[-2yV.[l9wOTIkb%7PKNUZ,=[Ԛ4y%#GU5drDF=R)^)o{M:8:#"h+Tc}:ۘ>i#_LWj?gȨ>xRm!aɓhAi$ѓ9'GsAZ7+X㱊y*KvTlFM $l>g{&lB8$,VUߦAL5T+1K1BC ]X*KEc:&䬫܃WI M.p ~5sק&jY1< gjٵ`p纀$*皯XMlx&y.'QgmHi)SaX(pESNxJJ. ` ɈSZLlc?Zfb!egd(+RE'W[ a| L'IM٪ORk`nIoa^Άh д1j1N B6pܓm DPƏ9edimp\:7ߝ"1TY# ׏ܽJe&^o}1*$O#lʎK2QFZj̭JGj=r9@ɿ }h"T#-'G#ds\o% jJy-]k d$%:+?4xN$M<2П]%d׷$Z_WM}wՅjjl4Bo2A R !Li\qk:k9R9r*tXabX.·4g*naف-8H&Av"쵙3I-Űh /)&vW4 ,BDygn3 '|Q'bsI,\ˌK }[j x % /шA5 @Ƹ)-$;]I~;(O N}Q \Q -[aI4A zgXi4R4^96 d!'?ǠQDΝ? )VTPz7KYf 6<>˜6\hA&o:<5EΛ΍ ohj7w=.ȗd :: |闗J0F/#IUĶt'.OY 퐵S=F!(Bq}Q-* )D%{Wy(47BgC^5 ^d?Y Y՞}2~3'9PM57n4.weL"8&OQ1]I/UJ^|x>tk*SGKin /q-7NĜ[ /FT vh0jsuQZO@Ah\?m.KN_ͱWW7fr˱2pF{R?7u0ܔ;VpaʝB7UUVY0^ea!AO\:O;"/Ēi#T2%9w ಼P0(tr/XU~OzH3Snp&A?.׊}OLx@R F*F*C҉ K1bHyTLgJ Ӝ/$yuðѢJ µc"RǴmbM-(t1[I#]C3n2EٙmRN[×2oD.^c,bxˮk?58ˮ1RRw% {xîIUhPCIKHpW*nzexn+L 2˗\6iƞc1۶70a65j\[\*4@/Л1D,ئN 55 HvoIbuMZУnG0- ;y'z%ՏM\e:FŪW'ے4\yy-hvƄTlW e2hXu-PJKw(zRYk/^H2`kF.n<Ir(PE*TZ&wcwRىxf@;9ct"] KَYHsCe ~F& tid{fKtT::f *k:sst ڧYt|Ȅ ܬ ֦\8NR 1B6+3߂/ ~߹d]ӓ:۟z|Cl@ϲ[U=){g=CB?rp#_`s_vnm sA&𵦧(#[>77vgSf`Jyh7^48xc*uUy1}kVDK,u['2o~nJWoX8D|Nf_;pD" G b#Y α4~+-S_h< EJ|FP2v!M/jJEK..x`o.HSGӾ&{P {IFgٍIx}S3)ꏼn^IAX (;Rݕ>@Tv_$;sn?J_x7KD ry@ E(>e\'Z*Z9(bm h0]cۦN]yڕ Rb x3E8BHyêM~}M|+"Gj.f`UL گψ0,eȭ\xH"FEՔd-tAOaĔ+ , 6B>'$E45 ↴u2{ugLwXm2z9D;sw۳ov4{% d| b/Pg}Ize'XиzjCpNrM:y~˭W#Wr5iچ/iR7gaZӶB#RԿ?U+q't!ߎmy*X˞jxLΡHRKe٥KKIUTVg92:nR^3#/1Ў"K[+PO]A,rXX0? 6X6&Wq`ܓQX ujUV><ۀRƓkD<(2 UU1\CoCQwiɆ9Ê!~Z%4jK9b%9Cӹ6M4֧ZSI~fB p ީ8<;Q$ߌkC,^y#ϖcQ7F]rA'>@u5k.N)]Ԯ;l b l0+DvIT 5'%*A+O'F (D{#JX0/}~6*ΎW`rd4VwTHU(EѯrtˮgRϓFBbPx ǯOQ&]Xe pV&۩ς$xv̵KK5Ǘ 38u*cGqԤ(Tw/@wsl#p/ny&J . ={N3.|)~0X)xi{Z'JhXv渳>I=>> h̰Xt4<',h+IVd`D7?Kc^`ƨ%&zE%52U|>_梃x 3XT;ϽH.yjxw DêZn"_Ȍa 6h]aݖʧ;P'uVR1dƕXc7&,;Ԁ)3kan?faZv=E)QfM2:]dƗؚNAYRF0{fn=H'l4EĒXi)V8rv3%%N =&tn/MZsrYiDnIx29WH u&W{-,tx`N 02wmAUrc?jt}ƹO ~G s6d?%g{T|ĵqy1C>*w&AyDZ ?HwNG.Zqxn& ,V>|,~oy4yڑx9cJs["*hzT©h3$0HC ߁a|zzJZ\@?<"/I蚝|7/T3h!յ-bM&=K]W+M "c͉/W8!i6M4.졓g?LchĮ@wfvI7_TIY+7)΁`Tt!h2Rti>,FLtt(ѮЅO"pb!0(,GP KL>r Ʈ>3Ag X ӏ\e9Wʔָ`mחM?oRd a>v8vNqsㄟJO"y IjBm ^vt=yC_[a<_v;I*ι ǤX{Q;b)K`P-AÑoX 1Au}}ךּ3eL: Eh 3p5 `0Qʰ!@Fg+Wo7?+L~Wi2kQKHa3[AC$";npYfbR&`DNQˣSRrI▷eg40A\ƙ×ʺ& ZXjy&,vJ0&t6nI^XK8 +'1{%vd ,4ށu0~XrljT(&k&ĭҪ E+62GU~eJi'ݭ͜6ԃxI5wqOCw…+h+'H#|﫻-C׊҃ga ǚਜZ^4:QK VkaDvVPmlaK77XN:dnS>ɫpg9l򳸹rB"ggnr;zRo,9HG 4G~8Xr[v@[V\(_|yxiH vd2l|U5ODzb!!!C&<:e_}@M&^9jS15BLP-X̽-CcggnU{nNx"#⨭޺PpKSf-q\^ t vD-!HJ_~ÎFT 0Y08e8y)̨w`o=Ikߜ9`Dqu!е`g>_߷uTT;-,W#%..(^31@ԣSԕ#ćC30X떹!ݒH$C ߎ]Aʾ*r"%B?,jk $5%ZB\Q6,=QK{Ica7xg!dz Yz;ubo_,C2dCwн1;6^r?j㢭 LOtRR#$/.Y?/< DKg_f/7r9SHOU~&PtVɧTs;," !˹5h6X(`Q{Rsi-_j(Lp&V͆: 1-p8v◞5lGE3 &n k+ d^]('53{'ښD jNJzj](IX`yoGϪl 2Ǎ~69p $DN$3.74)Ӳ}R7DG0sƿ *୨NnfXomNG;4IZshr.^)X!ѿlo#Υ9/a<N{N9WcrSO,@XG"4%x̂ x,mpZU S~1D5:~&zu~-dDP2(eEVV~v. sqvɥ~E/6Xr&n?T Vo; Ian4CDֱLG+:ӣ6fq El2,@5:麻uvy="蔺+Ia+1vԂur`^R75(:",DS?Lna kZ7[/- Yd._Hg-FǠަ&)΂'[ZgL(iЙd]lq+Cծ\5QUF@΀^~y3lw)[\^ zzK!O\Jw.y̐Z@h)Nb ,:kS\(,]:]_ַ"w≰St 2B 7BdA P#Lkĝ$+L4瑳1ܗ}ηZ|= 9%j~4VS юG>5 BJ"ҹh՝yO((kHnZFB'֦BS*.BŪÕ@D:FzJކp&Ci@ V 6碿&@׍p0 {ܝ<A4#C[TA4 ~=)+w*:aTLH,~Bٛx˫lGaeq{4 ޅ5COX%bZJٯW0s ÌojWD>CBO;f?9бoi~3*e& )>g԰mbB ^Jr!Qqޛ-(R^ ON8ϲO;VEhRy#WBԽ(&T+mkDݹ{pE_Q'_U $WޫK nmEӆN>fmN#8I֯>XCe&Ju@35_?M^:>~ \ɫ* ʵ\nF9JwRנ!QITQfO!X\J 댧u6m HTSo!j-a]0~R^t 7sH]aͯp,vL3 P)j"tLkjx'L`/ZGJ"V*gk"$֐ T&h ;MgDiv[Tii.3UXgD0}T<_m 垓pDŽ25)B5V\OR,/-X?M"^ Z3,w2M:|w,f^0r3M{~ˬhmQ+s9b9嬶Ka,f>]t14 XBBҚjyq~8.5ыRjz(,0ϻ̡NK)@ ?y}fCsDqD3&8S#Հ=bCWk"p/w,:'1u5 ͮn!Ij}l[dx/H ,9A.Dr130:7ΣNcKݡ^3{uk?mСTal"0,7{ЉZіN-&b /iz$p)y|W`]SRzBvna(>򊂣bTC3&0Nva,9]mF<$\oF`r ٥i({UhܣˤEu{/0j#s&44k RVFk%C3IW;V<ُ$oϥiܕj%xD Oul}l}:"kM[BlIbjT5v9cQ"޴f,""r67ko\mK޳+H f o \BhNk| |^A%Mq~g`%|;~h1RPFB[ Ŋ/`IbT~NrbNFQ gj5Shq<)_cG d/0ME2+4z‰G*\sykgfXhPfoPxjWF`+VvU\Yv\ &L7@7\  F moaNţ>KL tf>1A_j&p^lV7,lX%N5uMUCdӿZmf{kDUFR$aVq(A[S G]YF|tC'K3s4QŵAWQQeM peuLNwRf}8֐u^u{ BTnbnȷ֥Jo} 2иi[Qv(rMέsgWj|ۢc7^A5R- X1<-#$V#CIiLm-s3~:U|#ty*`uy]M/݀ZR(Z?buޜFi/9? )ؘ lB$ƥΧJv.O`f u}"Wzgsru@|жU l_K8''왻o*[Tǫf\fv ؖ 0^227.P 249u,p;["o+G/6|V6I@~9*RYGdzKt|@}p Sð;XV2)s>tykK,&钴X r$P[=PqNoRrjx/~M+~? n 140tX H џ<f0K8 '>kk }o?䴟Ֆ=#Hcekވ d_-xd__,ȌL >RWo@PE+ԾKpoF5Z"x냼 cUJOCuX"m gPb` WMyWF]Q/kF/Ət(7mK\RJb$I|pk߁r3DVOfCs4!_e7tg ?X'&BP,#8*E{.Nkl!3LLxx?0x5Urc* [D,58Rʼ;cGRbX6k#۬s I-]Hnq(5X4pRX9EZz+*w'T]4t2g3Y Z;cUotg.%H,iA.3뎝k=!yU,C~Ozӯoޒ0`=mSuQBP_Ѭ/d00V,ѵxe\k`L嵴 -ۓQ{c)lůdf5baDP/bWgnکDUp4,IPɑV=GEy+. OWW F6i"m(|VNpW gp&rEoRXc+a/0Kh;.?nZ m7_'YjVc1C =S|[a_]ü9-lZr0izLF_)9>јd2;];>u)Y.d`Eg ފcb$pG\")'-sԄ/Mf:Jk93^?+ L_C1q1̷i:fH7lUܩh`0c7NvêV]_rU|$Y?#ED|>mSʪHkpP4{nʒ/fg\x#Qæ^& }jҷC̬.u}Pq+=IZ|mOn E}ڳОހ|Tu :n}é]R;|"<}Cs+ tN/ (IϯC^!b]#g5g8 4O~:;Wp&-~BVRmU^AwN5m; [5\Be\w@H jۧ^ԸH=|D5IYJI|JPrE)Ftx|0'`O.F߳;87f( Pb960C>ѫX=IpӘ]1Qm / bWhQX +i[ɧ}nlW)xxv+7~2WHO2g»E-LԊ*O*p&>r*6AJ?GHW\jgzNaK|Y4U=+D\J=6*9G;R͉BOQF'PzS>al&l˜^+C{ .{Ia;ybશ[\qk f?-OP…3XY3}Srw0=dȘ-Li># G$-" Vě#q[,39!}"%vL i-`l fϺzF~#R[ bI™H4]*N5 ȁe@B+*~K_f&=ȇǀUS.. ~,G oeWF8%rx*3Dc@2&.73NuyxB^J>',F$Ub_q:'' o0zrFde*̹ZPnoU~P}{Q׀n4}8X}3{\MTrkgj ?]$'<|o քQo { dJh*x]w', U$fY],ZvJohGHcj[{eR ^݆m.71dS\%R>vqŞg8M-J_F?ǙԥB!Z\v8r,8yG~/Zl(%e9cg%^j%A^R e aev%ju{cE1tp`U4Unl"tm 5ưj\n^Dv蟸4keA S" Gw$(Eʳet_&JVp dGpx<@ʎ}y)rʠ b?]qÛY6xG>[?"Q-C[!-k@4}Ç$9Hz~sXC%ӄ*pl L.Y0AZzE3l Bȁá.M*n712Flrr2x9Q;{)i.Ob"IH{ 50=aX <*E8fZéEo$z7 w}pHu .{ei6ՀGL#/{U]D"VqY{j!wM SąA׎$22f=BvU2q{,,=kTdH33&u?(_.ARTS\.nI]4+WC.J|^{ iǸ|mjھI,akY@o@wTۛBѢBFP9Q/\OПxuD 3S6`@[EV=h`Kz\NԿ8,H/Q7d()e ʎPv#IEyF)kzEhC*"x`XB~lGukk?A4RL;>3q51Φ'B:P7fa)ٵ+T~fŁ 1%0&fFٞOzIwA*)loS/Rt`$IA1dn @A~$œY~Vz?3MX,!r⽞`a +b @βB<26H8g]-cV nčc\̝1-gpFF ٺ/Yv }Gȧ,~H^d VȚqZ- ͼq2% >ﻟw q/aL 1]eHhF@ Y=x<)\%*+RdA %kL d-C þgu*xۓ (o-X' suA=r;)%  yxӂ\{|XKAV!qH歫 f4Fh{C"nΝG6X%iZ@m,ފK8*Ak.ۍ=]xnG\xݯK F[ƳaQE {:.%gTm{ʂoPwa!w4Z;~шkM&ts0^x҆Z7tTQ4Z ʶ{oZ}䖎=JCo|thf(IK+‘ \FyΕfGdDN?ͭl#ⱉ(mb;f`nIQ4d ZtkM*9:/0QZ)/ QD+]Z&,)nË&:6wr;N*pW>b,-]X}p1>B.jE-HL9 u|BɮY5 vjsG.aZRxNӗy_6s@R^)(?jE q`wX/}adPCwLS TE<\Ѳ]x}9/ꔲƈD5 vX2p K۶l%Ǒ]0W@ꣀCwM-ܕkzw]{CMTiGs+ : !y<x2({p+v.7qY<֠ ZgZ?Ѵ`mP`t$`ac]w23gBf+{HQp>nFG\x^8ˆWHX# ']6g^nkP*FfKSȤFd wD97hm@6,9bGLk{tvlVJqx(8!ۣ`BԩԜ C\\כkD;'4YE7:?*SOg!U5xO:r %)"*U05:@tQ)Jo#rZC듃-Zc@Y1eJ :>0D k1_UZ+f6$yiMtv! 5FsDfUΏ)9 ,4͉Q &ZSRCcS:eԛQ)&D)h~3*MZǸ7Rs|$i[,.ۭikP4B=%F\kzk:#R<5$%,7u7Z= [8Ρj|i sc+O~PFG]ԡ cquR!Y(D'7@,иTs^;"/>)va j t?hG ׈E SڢP#.Z0 {wL^ڐ\pa%Iũ4XPґ %&A$\i`&vf:ɬYmehnf-Iw,KFnʞ'/7jaߤU[ aw濼l^d ~~ٻf7A7.5gD]cQ*UH%M&x/d{5d}>Oa`}gA!v{Ҟ$W6 X o|,.LG3&3xx%v="Ӛ}a.RS֡cT(;gjc`m0be U_l+Mp|ǖmGyA,XNB-X*7`#G WI Lwvg" 1#N;82JGR/x03&bqlCK9[ Jkwfi'<4ƣzh#MW@N\Q]r6%/hݐ@iPՋBd2 =uI 9Ho;G1a~8̸3*H>Y(W SR Iz۹J_v2T@E-7IأlBePп,%`iٵ.D/.UyNMZt8(b{k͑^`ka5Ƀ l#Ђ󉎤a$RGSl `]i8|jRyo@I nOᆬZf,`?(٣zߧf nX Ɣz#ذV]`C*,A g>BT' gύ ŬܶuLa')Z#/Bb2W@.O&5q`mfj_-|rYDԮk'5 `YqN1vV 4D(AのP5s:WK$†LsfK^o8qX uWGKD+%~Ωۅbf_+֞I ȉ Cil%$UکjKs [8Ww<`; | ?|lS7G7U/x֨ԮɞO9pBkKp,&ѓV_$zYXQG?o-e% +mGcF!IY g0|6kY4Hd&ߙtEQo+h˵eVr)"v9 Y}yݾ 1z6x /.eR,{/SlDQ"Ye ~u;㐀Q;;'mN-k9N?L1~pI%q2](([H6g{1D}gdeV`%!#VA# 6+{.kvom p$R q'|%&>%9I!7fM4z))tlCܓ>E}H.%>dlszZzYypFE=OnDe]lR6x+!BΪ,ߡr X/Uc8rLU/fADg"1\0,uT^ ʭ$*N7IJk\C9xǪ>*ɀx,a{CÚ7彎enU`Q e좆7-u 5H9SS)1f%eTTṄc1ӒrR\k ^Z@$ut7W"Dr#>Q#5CR^RA9߾Nӧ-j'e:+9|\2)PVqe'w4ޡnؿk$[¢Z8q#=;-e7rf1VK"sA&d9m#1 h~)mfbl{cn$WP>&*:|+ N퇓G2@-@g=Ew'4R -+}c>*%+{ LBlY-1m7MӪ<%( NV͂YI 0o @V)q3deμ s~é{9~vXG`J,ַ??Hڧ یP<0]tAڲ̴k7\b"q8gpI(`!6|T׋Yq?\0Cr)ވ1-=Isf.mvZjDKA_+!:[㳃rʻ9JuQ:-.vPЦJR0vIzdwj14k1NKWgdж]xA*"cYô5&.BDPوlvEg"VuU$t;UY)H\L5T _%w2eJŢ@R[p$3ޯIY E0wڢ[BF3ND sȸÏ "B;ivͣPc\, :c+Bw+7Š8}R Fɫ4Fb0qxv!6-D>9]߻C]Kc!~V1\Ø]h^cH14-~4xA,W#*QS4oE$=FgIHW|=&lƻ$1\D 7Ď|6'  P*ogF!GBqt@W;<P{۪89E<Ԉ.eb ,`e]VLhγff^1'2XsFt}s/3 `xY* A~pDzFBDK-E% M5MDpHƭxb%z/D8j:в] f )8!&giKcNw(e\=i.eb; 'A2(n vnۦ! kSLCubtkЫ 񺤲ݿ0,UʱzV^_h7 + U.NbQIEË껲[?-Qm@uhMs(˕V"" eR=H;]^sH 0^0le]c̉K,tppG/@+Yۅۄ:DGw[gǸJ>eyFx/·6`4so35 0^ 8'xC":p0:UC_ (hC=x; -Ku!QϪ\JpSAѽ7+hJCО"w*+,LӅeBrr/vUvoc7}n9rHurP~lRB"J|бu'ڔvλ)}7>qth[Pxaz~Gۄg{nb,:;@el[n[C=6182PO+[,v~sSOӷ.; QX.:Q'TjݙF {1i0]o KX L&$hI]le@t@ 8OtJvJcʪG bۻdD`:.v3(yK %&hy{R/w.dl@s9Aj#ᡆQhaD%C 2WfYzr?)o~յ[ L |[RI̒`lZ~F]]**ۙhW^z}:r1r<*{Zߓ^8OzL}dG?Ņɕ;1S᥸ xɩxֈ#a 6a[B.;yFYq =A6wN"AڳxYȻ cxj A%&u<\zcrS 3i(q[]$>0}<4ҕr;,4{? 4a~4c0cg΂^5Vq /_cB@u hP=,%vZsIBXb\ыLoq@B?mӖna<}֑ D)(JJ 7\!9rFS7s`zBo6Q PL`9 zOQI=`\k@m9F < ?W iqP ڲ6$JgL>XS|B&((c?i5{{'qįM"MHhԭOd(5 @Յ̙^He`ё #飍Pϒ0UeҮkvM Ÿ[ N' z=cs-I"o뗨2tunڋ]↻@DU;le5VNf4giµ*Z^f }VPr֘5q]ۇ#ʾ=yTGw]꾥 ! Głd(}J+ *Y7>٦Pm4w8Gp0Q87m.^L?:Gud|W& .Pj2>s.pg1)x(-p{^,")Jx\NF!"Cq&I-, 6a@| [PQyLA֑JZ Ysm(sqS8Y\pY3],*@C5K0 ([W~ڽQbDYx'}%` ` G(=:t;VzI«݋…ǿ?=N)>,ukg3 N2k$ 1Pk#>7WKᬔ=1JRӫ[J@nr p;SBZ羅EZ,TGΠaX{`_ Ztw 2y(q=o1׉[*CΕ?$1Gk9|8e2yĐPΔ/.F";DSv5{^3T=}M#q/ A%\}7Ñ/2u5|Z#W{a4^ i䱱H"3PO"u߸EESqK:R-j|">E8hڕRa+<['V7dn!'oKH ^.fib{!S54QY1Iߚow(Lr?cLٷU8_cqcArC /'%x!!(CO2m]AzIF4g$U9;$eFw`/K=rGQLrx #`nCʬV }f_,2 <׍9cPygr6&+1Q ZdžWB,({6kh% ̎<`lkoEl"L} 7IsȮVL͠f]e[^u$Ք'fq|ת\W-`='N&55IQX5WMfSNW bcwDfѪ],()m7zotb\ڞȊD6]"ٳw=`4q+ZM׶!O;"d}wv^NKv )ȸ-FF& L_4fJ9[z)Xs@fZMQ's^RzA|H|&h>BAOW/hd뎄5ZxrNtY_̿@iR"*ܟB)8[3J,y1 Ԯ1LNc u&0t vrj--ؠ(X[3LTu~1b۪ M$OΫ3u<&u>ybR=r+ ޮK|Hݺj s#w>"LyIVcUSKn*~tf, lrQr1DtK_^~BX.:Qc|ǗZb1 rxLȐW{ksψ:auáS3 P=b;'-$n7S˾hmr<si?3wϣ$ÿ1jQo(mN F)Y.Œ /;ȔF!-ddVPP\2y"ݿà!a=="zAMVw%H|J =s'BGۑ9[$>&pY_w&K\_#9i`ERяj$0E37 mlGn^Stw0Q^! n}/eAgi%褮9UR N}oz1t62@&F9r07(hCrUcJ5Qv#n[yEGWGF–搦r䷹@)2}0< 0bB`ptYZՈB /< C% ЏBDպ(Smٲ*LMoixx}&uAQ!(#ed@'&2pY@r$Tջ*Cko[*ǟ-H4؛X5A |Ҡj{ iđ,$/DN1+NV.T6%Nq6d oJs=}̎{PYw0)&`ZzÆKW:ܘLFG5UFƩY؏QW~Oki`Ej@OԘ!$ \v ^i?҂wĨ3_+I0ŋYJ i{&Sڐ-܋̒ƌ$顶GuR(|156a0@d @@A^+wQY{x>]a}5^hI*k0(ݭ, s lg~ 6v .9gƨ1?] ++f ;Fu`Î;_F0żƙwBpG %Q"fjfA O^Qx>}HW%Ne'#W" 2H vS_YPુ"3:ԄQP<$ =Nu$W;p}.]0!^D1UgÚx? AW{cҨޒ8f{6Mz#/˂a/FtEd+{1Bᾩ耀> eϾ~–~Ȋ܄aU?< nӹ1u٩m>h}ci!TlKޤik6wZnwPNk`ۚGZB=eL@TҾ#+Afroi?EQ(^r`AaAsͫq YwBب` c;[9h.HwlUihD`´4*SSyX\(]khո'6wwWfe3 L!¤ڊõ.WU}}8&V|"}7zv J+1*e[H^Cw>A}f.AgtǼX2nmܠCN\ޫοP!MY*хhc+d«wӸ41x'6)qH l%aXF粎Lpvz{Kfɛ.śUAa/|]wgbZ '0˄%l?i"iٶ1 [j=«!7 49C4Wy1M>eZ&+dncD>,1~fz(f57@* sopM,ENIR Ҥ E{,{7m9%n^ b1YSk+œbh(Nzk3t yHԬ/A[y[fat\ha#ivAn$v&Ug&AjlIF@ģč@io|Md eO;d^V-y97SD2&n7Q7Pz9FFt1O; jwY$(9BD"@bS *XO{I梘]%^gV׳ܱ#y3JhtKI"j2 m \dS 3U?ҌC)ꢚa9`0P9S/Cڑ0d]kcGoOw&blx‘ϋWp}υ:b:a5Ɠ4[KhZezDz95ѧ ]'CAs'-_yD63[SxJFN@*gxRa#La2YUkca?]Qw3,s =ۑ!5P崍"YZ` ߷g Yucl#eD޶uYas2>TqTDuoϡ߭4_.x"HI %(1 %;#CPCV@`3{S^E*\pkZ5I`puV74Җh{:<&(VI 13MZ sB<̛N}E>_ToC Wv!$-Zl\U0t˓h0GK)îC(7sEqƁOɽSCH)Qho̜[_.M-O}dFF2DB/W%u$`Q & AD&j#,oHywG_=aoFk. ~"e?9r:7j+rO^y*RK%k\Ȟm=_4z zm(^#7//mP)U)9uf2 Sz,2SV+|BBh(ϊ.{hlc7Pr*FƧUG =\.hiyud,XL-(5$!cL6TLDRH>8zJCN3qlޗaeDͪgR~W/j!oFpI s ZRxgSMݪ*ĀhY=QYAͪ@]xL fAdq.L%jT)k.MR#ˡULVa"7DO: Nm1- 6sTc<>Osʉ;1^EǮ\ K_ (Pkn78e1YonjblQrl8ډ~IwryFJ~F2gIPkeakgָم舤i{GNm0P x7iwGt1dz=DǴSU6['؊:9_(ܯ;~/tk+n(kGEQ(״4gˡ+X)q9@ɡ) R qIS8C6)jESYT Io6Fa]qmf6Ta'߱%I/Y{ hPwE-ÿ8@!ƛk I_jQE3LSMBltX]CG'IYB7 ,rD;sU۲QH8/Y$JSW l Waaxb(:=z8tP-J1I%Ћcrvln=zӃWz|lK0i"QR9gYVS@n Tχ&jˣHnuT 0g2.M޶=QmaSJ*:*U~SZu:wG7r^9t-wYYO{Gwmmz1QOcTQDJmebYT*|j j'z5&v/cRx5*G |Q)n 0eGV[dN]!K}! JoǗMLAQaȟ^枚'2G9|*7-ݓSZW'T"grgh:7h(,X?,Her`r_r;a> S?G,ՠʸWN]ҏ[2DDʵIP(՜i[T֒lP/vfjF6>*z/Ъ򓻒F=\]aZZ{4e!][~Q.Yݑ/,C@Q94#"3w"W45,ǵDV6 )J6C6#Էz˄R /YLWX|huVFrh" #bVk6ӥ+{YSoTW7tQ"hǶx4b>5gegC3f]Qz{kXwG&`*!ARs0o>.&b9`s;h$Z><6q3Ճe?J[8~?62 9*h[m -8QrF R1^YX qX:,ioHEW)s1ޜU\ՐjyhDhܔ>\<]1i$FS"7e~k326.<%_6*:%EE3ѠwW߭4}^=BcX #%24y Cַ7fWp}%ؓIq&gK5eC#B71ł:ug`Uؤ5,nP}?|?u}w z'kA@y{+>W NTO'`v;4zG;ft7Dќ\nj~W;d1U7k[ec*lG"3 k>0 h>BU<%9Ũƫ^BSKڝ2Rr췄I#p Dke.]} ̟iSt~KBC)RPfx_QC͂C3K/ڳ 7Tާ^k,`^:bh͋uu[\كz] 6Q 9!^!qCO은l|p(kBtIeUyŝ+#7kٕl.Unb%l[`yE|x%3}f38VˠrLwuIU}/ -u tnqsה(LY 3T%IZ=lE$NWtkL4p3֕G1@XcP7'BŊ7D@6빟(l۷o&9TS~f(n`xCiJ7iCvÐ SdRyU,HLqM㸔UHx]]9.Є[k\Fh9#  @1$it2t&Jiӻ$)읛q;BH'V7hz5(5[h[ 9 ryh#PS8&JJU&'~Wh;] ڮRB~ߠ| 1V̢  )%0<#4 GM0ɲjwN{<ʑOD&Kcjt` MX HNrJ?e~VY_i̩#Zb\,l&pjE7+&DC\+IkCR$/,G~af͌F2fڏ$.QWE;yFG6r![ ):yTNkT!}3p~ѻ[)R#qOZm k@0u#f*N+|@Ǫ] fXL.Z>*r:g__A86 ᓱl@;|[8o äE5g?0WR!yT=Z-`{1;5%ա^rheB3*~L_|n *P?P:j|6iX6bzې[JUu9O_.QbK*qwUՃ-zm=B;^%] |ujT4{ַIеpT4P`FpŸ۔]VhLYYM,N)Q}>Rj0_%kzt +?+SCܔ,2Ƃ.- |ahײ UVw593S9 vm"(oD"*,F3q E+/~$@ggjl[mmNCq@%gMɿ3ΊՖGϟdYak1g(Ud4+<Srik57|.hp&BZ+RSp7Y %+|)6g' ݉0br7x1& (NsluS0LS~0ᒇ\/ύۄh2.=1ɁB r'c 3Z# l;|Ik0ͼ02OIaR1jkB\C-qfK]3,_3x 9}7o!js*)Ə]0q=](+ Rk]Ὣ$JtK]b8S.$^uW ŀI7"0_]l 3I\61螡L~҃hBhrB'0B5,"-{.j|qO#[gmad6#z%2R{/%:eV;]աMȏp~w>]ՉxWPMl}`f ^=dHHb[i|xIXF)-G gB M_)\ιk%5ælrLV/@T%<JygVm3]JQC) aSWHy=ʷOۜY5#YEisEzt@a&'hӸ#\>{qo&bn%"k:X`үsk%C>M8JK?mUŹq hT x4>JSoUmBJ*;ݒKC:Hn < ;UЇj ^Ȑ~'/=3bSn`jYyx,X93P/#Wˠ71ʭX¼(~C/)ݡΉNAN9 \&Ja4N &NL݇P L [7N~O06rjZn6L=摗"[ /2Lۺ-jФ0Td}*TSpꯦF죧"abjd~RP2_'̰?8*Hz% |>EIPK "cn4SV0iT,E.{UJN1 >h)hUNF TDβSW,kC.M]ܗ$43Ė(")iX=\GzOB34 +!l7b(6d]wA7$c.\=v:Yg/`α˜0 ftgU(@完> {ً"Xe YPΆ,}<@ M 7n+9ŭR!I^nE nQi_4f ѽ儏^ J];7~癳dj?N<)X6U$rXrq*Ul2آ7KS2,JkMO٣DQn?dWj qN;C]|(he!}w\h%3N#` s o twV0L1(5EX)2\s؞3\e)F;^"-:9Pe@E[+NC=K!":$ڇImF/(L?hAD5 :iS,΁dD$Xna) X c=*g"rJz(lSa&'=[[' ~ayU\/-|{8[]op߾䚲{A-dx&h#%Zs"r?nw]>)Yϫɷӷ8Z;ga_8hGHinԢ` iCDSϽtOD#MO"7DwE\u !蠊 ʍ* Y\O0&'(%"IFϹ)\B$:^o@At}>gv' ac` ~+xwف W,[ acf5+]a*ëե>p~D̺Qa*`(PƢ".2v]z22-G{/X̆BF;%~$P3 w*]nLzc~˓Wz9}"aΗUoֲ"M-:2o4x Ĵ36Q\ -ڊ؎mPNOj9.KU D!sS` dO{}ܹ|.#~>/xX.]Gndt%[~JKҐDT+ǖdj OgNy2~/di5fcA %Y0Nc,~3taMb{hکRZ.دvD0%vz韩T飈`Iߓ՘e\ HG&G1W|b'w{ŵ=RQeä`]l \厨pg(ot?X"XR87VQuI*W|o/S􉽜Nt\= lK~h7z*N06#e ]ҧPʙD aLVPoyP;4U>>BwG #s?}[xs4D,K|<;NmU ѓXȊۡsKgmg{=W}z&Y{&*eŢ!!7xoԽ<G$Ik@'2m`)!e1ێU_>"JZQ$s>߉x[y7ǷHE:Ъҽ 5زxCKrZۜ\5O%jB OdvYpG4(pN⡋mA4χ1`nމØma\v9ge.eg:\'|meDu/b ZʓX[DO|>_D v˄Ly  Щ ܂T]Q>q=tZMl6CBQ9'YHi's{l ѱpx*\G؆OT޺~ZOeXO jE}|zCac @$ev !OWBlsvNyJ svGy OBHDhmEHLw]P}ǰx ϒ4=#Ek"^0}A\,Z۩,0c !6]p_N@:6aNY:g9``O\NK#X%dE)-RPyVhHGjW9Q/{9ː-ZBCUWq>ɬD8\ Ҏ+uC!X*fUV  t7nucB1"0=1d>]d6J,)aSFv2Z$4EMX><>ѸPquY [*[y&>W@d>]<3d/XΛՋK*`$;* 3V#!`arvAA/f21A=d&*{2* Ö)R q[_n3Ն@ω<jtw#G "v\ގP^uz$iz0ǙwZ>=88xLs VX8>UJQW+T/Zbwh8ƽc6pAќ%^#߄iZhl=̷P8c>DH]lvjC{تѐ7 'jCX^{y5 B(~S$~iFU^țё=k ۢfYPSpaٸlYӫXV)id͸v=֖i؜^êFF2QiN}<ȯ$6P9+NYDC/:LhI|/m|.GTp&kj@0q}*1laLYpd.gi %)<XifLL%RS1[V \Jɽ'yKv֓[2ݼ~#B ť5slԯtT 2iL̢$CzO2ETH)gmg UƗ^@ĺB\h+!3;A}hpx%µn˟*݈IWNabB@Pr%p.R0"cDNR,Ht.BeA.|:O(3ehjZA0"n(1f&!sd] 3RF\ϻDrma}ѶuyX8u )8Xc`6SlI3ds)vԴx4Җ7kPty{2Fk 0.tH8}*<(.,Mj-T3(E4;QLve$ b^6sPzJ. ]5$+m8{PdB~vL=2PL&A1 BQ}H:R]M y`i{,P%>g`Nྔ7^WaOLw98@f`VBk> '3 ̄6pRohJLn5t-%O0 mRn?_ɗeN#DpAjŕ B(l}sf$&L fWSyM{fXU-e)Aeq pʇ |^Ԥ3hPhvx=lRarE.m*^"".%gӕ"´X̕69k3k8O|7P;M#]6A#"߄5FNW}i"vݡ^M o7ba4H6͟_p)6J3Il+¸kmo!>vE|ϐ$,CU>fhx]+ 0n;W`-${B[y7 ΨSD@s[s[QH2bPBúH䚾yNCcetlDۤ/UuRtZ7sldb$nq."e^c RY+J (*@>(gl>'bix)u!SRdf^HAfm] 5s~Cs+Eu#B,1ڒ )JcQXBzRXȂD~vGncARYdšC7!EiC#e;nQ1 2)) ^À,KiTR^*a[[,T2U`a;k2#w5uwb&>U9mv cii{ vKEȁKBˡŸ5cqAY3|N%Z| q`|zeg޽]3 *B,zW`]1p'GsUP`[ 6.'fc@53IJTvYv%ؾQVBg֪(L(lSZoaU 3} " TEl ꞽC\MzϽtw/'{Ӄ tfXI@x*{ZkloN:ER+wLE8wp~|dUN ױ e U3N,0gḮ&"|.ܣd%ԡx{Šlف5վLr_s͍hJ*{pJgV!HaډfPl:_*n?jf6>d|#欗+]h_^њBQ,ju 鐊4JeDIiG,alsѠLMYx=WuW%#i2kK,!J5P:R(@oVDocbRb] o$Y?2y ?ɫwXi[>ceeMk ;p8X,F[)BA!-ADf*%N Z#k֍&T=؇Mð.1W/[XZPc>J2Ds)6u?ئ}Փɮe fmGã֐5@{07@rAnDV$%m1> /5H-~af1i5WU?CogR3֋MI%=ر$*hh JG˕en4(;ByqHaͣXt@==]&E+ࠆ 9GQU u1%:T%؊e` а `w4.?C?|smր ։HhݭMx-d7MKɭX*-ݷ`x/C6Jg`N/՘t-3&6m1#Y W 1t/V\fּ쨞$wʏIzݵuB6V!i:e={45ܯD "U\$|VEvs.7̞hɰVe~\  4c滟cBWx`jg T@KQJb8sm3VB@zoJaO-fS/(O\K#rZpXS݃> |c+?gimr^4 BM5zX.@u޴NH;<)gR1EOG[6?X\C;v<d򃹬&ߎmrm[?q58ï,r=hNIPPr-2 *+u,8T\F̈h["{}F:XBUqh1D:#Ah GhRq3Zypv|=0 ֹ@sыH0 )t\;BlX 95lN9 qś)CsC'|:>>I8W±QMqfnc#vQ]:25)C{ y<4j4T6Bknl9@^=?RXMb@>q{o!U~ I"E*v"rf'onbI #ftHj/Ym6VPP*gCl]rU_ZBt^ghmh~tC}}ƟZ(:xDTM s(3&&1kjҖ{6)3YFF FB\5L1siYZ`x(:' IJYeB~DPk'+Hч# bIw-m1iw ˌꜶFq0S2C =>,|guUS/s=pFbOQ8sdH6 8kLG)'bG!G~\.aamDAW.=Դa{ӭZt6;cf8hrb'- _KdDWvmiќ#o^jnwhCӎԕ-fx/FuάvjB\B0>JPrwڨ{ߋAer3 zlgAGs6Oe74?kHKb^[^^ast\UafSxKOD tx*A3V*+Fp\̈́5#~R`S+\il 2'3!-wY ~j]brgjba"rB]jS"ulmj`%]#CmܵKR[ sUc&zr%ZZOBcDUtB1G(w~+;HBoLlҿ`89jG>AWpUbg.Q#:ySg$ |g,%ROrR^YAOMf7OrW7$t\`E+<+?djV'L-d>ͽo[F6R0 mr: +)R]$*80kB"8k W]]BCL3*O!5MJ( 皏񩫓[*@!q;j˾ ǜ>s&.b*^ˬ{meŁpmL\wH=[qQ˯|9'tpm!\i{7ș`N>wjIDTGߦ^AR4Q7XT'ht܄~e&.G.X*) =sHVk@ttMs)nhJ?\J6Qb w]J;ҷStv0,#2ȁzʿDhE pYE i jp 7e>v pFz9pfASkt]J<a+QU`ݽ a%w1f!Ƥރ`mAmxz,l'S=]L{83w ,gaڈ>pǕ&f7Aq?./Ċrtf۔!ꁼW/_HE&pks@0ЍP2߄Z lڜWr)v+@H9 !`z+K L,3L#6ٹ\,,CKIJ(6M8B x?'?Obho쟷pҡUq`lh_yrOFNAo(;SDd",|Of'uvc5 ?"Di[+*_cmPva^HTWDf<jQBj2 b; qv"WhSF[xuN\Iz2'2dlRj쥥gI\Ɠ!␋B-I:u!kvSPi5ӾЩT.;Fp@cs#[gC4di+xG7bFoS1x|LI'IT0Tc69$d{/zIJ񚈬#Ԍ'j!3B! 3%O2$卵*_"0(]<?x`/KG:ckR%]g:+q`Zs kʤDH΅. qq*[e^e 0XuGv~jwWlAַ+%БF+$w C3꺇!AКR5V$,=3Dc/dﹸg$Q^y )w,Ep7]dhr5j$+[b8Hgyicˈ9o56К?yukR#@sVIgY- /(1[QZ΍3vOǙHgG!]zᗍ6n6YG_ o)h T\RG)†uMm,Z}:ÃxU\we SϷ&)Bu$cuCmM4"4Xpl;d.lRS*B% ڭhɗZB=oW1Q鬐FiBkւ$GΫU?̨AEnྞrJ%E@z:5m]nCVdՑ0?i14^^B&b(&g4NQ=@кB9&x 0<1Y~=g5Pm$tP*ez#TmLo};u~;n_-~[%F#:&L%O3܅}AV~\_OŲj&AQ!8IhYp"+锒X )WA DaHFg_'[tԽ,mP<)|X+Wf10MD"/O U^Gw$^ǬnjKKdcFh ~gs(ii3t^ 2ѥܪCU]o ΜIcNN[S”̩% p߱,$9cMdk?|A7 *̎?B-LtnbnE'%df!M–<]&.i?*Y}Soj`Fde=^ѐx?^{!CDŽOٜuHP1R*3m | XkE?}su^,% /9A(qFd3+²+Fw=N#iWcu0+k'&CethwCCF r ʑ,30vI5[uڔGYkExr! 9ލV41# Ngз[ʇ$y4Þ6{yDD넷(EvpD"f}FZt k .,CȴsޯQ ibx~U҂͓{-–-L4/8|gĊK㨸6P9~to0bm ž \_tRJ. ^v^_6@.R/hR ZEXa2Z@]y| 9W2wDO[e^uO`~XQJx n~hCNQ(CEveS9nOLWrNAZ!*RϒS9u\$H/L20`^?%h ubd&*g)٨%Vo7o{fjL-ho f§Ըq*.Rr* Rlm[Xh7 |x-GCg^͜2 B~¨α RI6#1KC%#Yt SD;ɴM!iqƾf`1NJq\(I,D3u$m^~[3P8ڊ FSFM,LVsek8Fx_\8/]-yMRf)Ajw@iq Ȯ^e"Tt1_U!_o-`#\z]N?/˂ 4Э׽-O}o)SQSMvh APNUS3g #u bR:_CY1&Vd"$f6 .w|ΑO7lwE 1Xs[Y1%iRiʁ.j.?|]'턚I'7O/,:W+r_rB8NDøAdX% 3.ER$ĩ4*ͥ%f 8Io$NF#^Jn@ &C%Q!==ae7>iA%x]^win<"_n:9Pr+U2-L)CTda k-H%uG3|jT|#V/>e'Eԥ1&w,.B\,4Y c P|^ߴ*Kj$IcRX-AKMzڲ֌3>Dݢ'1L܁2}x4&ޟayHvDGp1Ud!I*8}l99؃8ݸ##GHg&u%$M ,p, {;wxX-+$, ԁ]s] v>nL6'Lbl: /?,G پ:U"b >s0 W ڪ0}֭ŏI8E"$ jkzf^k#Up8-2R¨ 6Ӹd3QKkƪJ^qnOP5k7o!}"cd /X &?AFL[q>Fr#yTkVtEfRQ, ߃Ty9Y0N//EK5Nϣ&k\|8LOU F]bunoGX7M p{㪃EjO [sgn_r'ݰٷm ^gkzd_Ԛ4Mr3Qvr{6d.§}Hp+h@RѼ@}2]tj:HҪjdEH:À9N{.fd`/q0`\tT@|Ǣ’fқ;#RUr =$1_ ձ`=NwVx+5p/DM]vєxm)Q).=$s-Bc-Ofl罡+XJ`eLӄwȯq?:d \H6 cr}V]] D2ņC?G7K4|r3.`B-8:WH!}m7)3b88, [yYqX{)xBIHX 1UÌqcAj4&Y`̻lVmdOj fŧjtʁ qod?Vb%vCb_SAa43 i;ie)П%{ȖD [ZU P'q! O&fmwE5S* K`MV,'#teUCZDQ\oBxqzBD{ܝHb! g2nm89ͽsxU0g*T|}^VgqA6<ܫ 6i~hApو)79cG 8RRĽ:URܒ?ne~0ܐj' Ta1hS؄j1KpT7-ZAΦBlmcӱ4㱅z_7?yۘ/A$YƳ;25?:,<^fx@1V/f[ҒGubp{Ɨ = E燍$|l*Wfə Md=f~Yg=J.jms %g:5KVkÕpƙ]+:?k"=5ڲ=~6_OC }8xS 2m(3  #k 6˩T nLU{iۊЇנƤ%n|} dwJhD`= [$ *VD> "<>~ o푟F_A}\ÏD72-EUnʰ2.v*)o袌g}ٰƧa1YuwdqQS XuL{;*C5 YvZpWa<x9w{mPɵo+B]A=ƷH!6^vQ0+PZq1X"} k^Spo: je(ѥ̙ c:5'YX9hjqgq<^MOJ]9,x g77}*%<DN$jqq+PhMIiSBNB/&=bz 4I&*W».ven F {W]7Xvhe-vO[\CL1EQi "@pr di=UE\gba@1]ZԮwQ?} ]*BaXԹQW`[w`,,հ&TO)Y;3*fg)I*? i/X%Y!2,7ÿJyYA0h`1<_ҞTa51Q_VKV{Oډ$d+< tT4_=!-[QDs_)sy G9᯾`<{, !8ՙq@x\}wӜbNҏWj{EQ5Bw;dmKRz}ZaѢjJ;kGQZlKLI;ቑ' y,auG#\.*\-8 uZ \3ÈTzr&& f2)MD5MZ|7T9.͒+^i-@'/ޥ&ihlR8<ZϪ}U A~qeײPz{5WL(&6B , 8k}:lm*Of؍le`RpZBێ]֖H0I9]zTbA,lhLI~u_Y8t^a0zxY4Yծ B2밵 Mό 6+8|K|{_Ϧ_:`+T՞!m]D?Ν)-FFZO jm*&LJǠY&(ZhhP՛-%BKCmK;YF3xB C'75x5bn4ߘkٜ@أxzE< 'z~bSjq!!3(snԬ"]wvhCGH|@a>K@o&Rmhq 6" M3ۮopӼKxTdǚ@{,9ʜQ kaȂҙ8aG1= oRl'iFLJg‡GpfH097!.q,@'sih/ =g/aKDe Lm4AI8RZ > )PZ[2 {T:+Uɦ kx*!~Lͳ9ڸi88VUGe{ Zu!mLn9 Z_/:jO510m"'PTI ;L @> -_ :DK3;C }Z (C 9q@Ё*9t[[ 1%D@x%D4 t!4-)1+0uc4z_ʵƓ^ (q)N(v, J`Ij=Fj|R]ח5hĘ`ԭPФe]G 8Mq(޻Ԯk (=voŲ@Pi#jb%ZA;O&]A\Pg?l-#jdQUU Q~*r4{ /V.1Pp*J1sykQ)ʪCA6U 0;^0/ ԊW"(TD*ˑyUx5l( ]Ϊ!ED0إs12 7rE#D()׬9C_Ovwqu5UI&ɵ]W#PR(ǖAg']e$ 9ҋpD؂A`{~0 .BtzBq' 6=t8M1=Y!'ƦC*t1MlM*M@vw` K;e=T&$d{gvҥtr^t;LT,MǸ_ˬD\X&w'gAy7gHAXt>w\knkZ3EO5-svJ{TZNg.R 2O񀽏JI߳HdP C> FnrFN'9ق,~Ԩ&3Z0$Ij-aP{Պ@k],Lq^AMЛI=lR6gS:<$UWQpf8G/<٩U$ю1*1.TK_<E2fG Rm\r嵎<;NJBP$_LX+}ad97'"* 4 ԟ@zS{jMo ZNؿ ,#t穴DrM nP~=L UY7gF⫴B 4d_rZAC2`Ә4"*uwr`W M!!{a@fnI_61& tp͐Zsv*;)]@*DE88lX4Xe)'K@fXpbe\X z?^",5l(&9[XNI zP-QlPWl<aKD%:zOnsVa*.Z8_YTL JT9Dk!$@!FC $Z$D־V;JeYlrܥu9$.mXUln-YX/GERyp&Uyeu} 0'$1b?b ߓ-4ֈPbJ 5O3k  iygM3lo;Xfk/zt.ߙP@z :KIN)ơ~Xngl>i%mdB msDpЇȳD)Ew$vwr\+>gAZDAUCXCU9=ػ3ڜ)]C/IzOtƕ1nb\XuZC|`,iΥ¢6iIzxjꋜQbA+K*s]:sT(+=*n/| SkۂJms Giuq5+l fD}Ült[|d-#󦌙{ä-T7"`"Ay;:V%fcy=So֥53tb&cexRcGz:ĈDk[X GwJPjEx3~l _t+XsfƖ6m*7gABDŽ1U췄tIgHC/`!JS(JB>u>RSEoiy}_Xdg.ȼ+!x`My.J'.4H$c}MAqQP]pPxi:(JKo7}(BnA%\ezZԘ =WVl wR?%hzYgMg[vyx#hzg2Z: !;6L5 fISj p _-4*ٕ !'9w4.XsuCO[c+3\<ވ4cg>yZ#`vOAξ ғ~ܝr@1Zl?Ԍ 1 j<q$)WV,~i}0+h< KKK4 N3\ySB%Ay\ͱɒKԺo`T:F ;ݯ853%4WZ3p JrO\JDh̨J.JbعѨzqzY&6uShKN&_"Ƴ s$6g;L<"!-{Mq**:8[3,/#S1#7!,%ǣ`^FOe`dGD M#4Ų4凫Եle6yM^= }iVӠ(Ҁ.6U͏n)ig#? +30% CLu36)t9Y~U(t*T`7&b Q|Ȓ"0di$мlyӅ1,P;FQZDm~ "yUD@TR>LHv8a1I}^Vq(b?KI7`3x<Z}oU)Ɠ{wgw/HYquFc!r-&sD KRޯGfҕO#)HB*D9Ddg0)W<65|AK976g`:/ۙy0 Eӯ N`$kRd:㎆3\ QK]%9VJ1g(gcgqah7+UC6 aw,:'f l#=4TW7 1bP7 n/DƢreX9팖&؂;:XX$qr%#LpEr . Cɷ0v,ዪcVU.@ȋ#ՙ-7.eއ E1Sf9N.piI6l;)xBN0i$@fk8L> ֙u&^_ V*S؄0W VO`PQ\lchWo-[fxp'0 4VtٓH֣a7`N6]RY"Zlql /fSnhPD SP}35߼8rҔYGtQV]NFM-qglu?O.Փ5HͧS|4+G![8ܮ}Yud.tJV),ð"܅(#śtoI&% DkN1r% VoT8M{Zux1a貼eT1W-8\lJNLbRCa=(UJiJѰ1CI%ڇ&S霝6dc _q^ڽ)E@`^~f~8H8fK}ƃ&~@N)Sb&G]p # '@u_hNJt sG"a2I$Xv>Ab6ΦU W>Z OU7A0Q cU,]C]Q)>/ba+RۦJ٪#5C_y&=& 䣱+KohS8V%RR8RH'QW/6ԎOF>0ć'O*q*e_ħ/r$OaCV"fR kL B, q";6 ]e+LZ@8*_ukU j:XR`ȝ(3}fzdD~҉J;۠&!XRoCNIMI,xBvYMkEbәpp$DLĽb 'HS@oKl:#U)I 0xE WQ6+F=m!ҊEך&]1΁B^9KU^FV..(;1L-|_M(~rwh~w~8&H]%-{ۦcBC X.fX?OL49NtX5Pqbo͟$I-^~ DERx!M&2ı.%16Cnͤ7R9%~KwM8Q׀>I%7W1ۻTMB_0'u'12{} 3(Q"T,V94tD_)3ao)qP̧i]Kt.vs2'OM.u܋KY89L7 ir <T"5T@7y$*ݹ8Hw%ǽ1qb%*/pM 4B>_H1~@s;3Z"A7,-UV lPԮ5"f"(a\#?[axpBj V :xO Xm/߯+>Oz0}q(\^Gjn"|+U2/Mt13{c%EY,{C`Lp<9G:r vl]Hb8䇃|0g_\V);혁 & c^kL6|8~ͩ/H0a|ZoDŽ`k*+-$rm+ ds 3aζ"P^M &D>MܠDbJ1 Ve3Hڗ5`9F;{N) %b4j',HD pu"2T6p6%ą㌵%a&a)\5 (4!2a0sqqwSBC7_f:ujqM#'c@>?XBǒx<Ja(\7V+Iڹ(,*eÇYo^kc\]sD䫙y FFG=in)6Wpo Z=`X fD 6KKwCqn? ^d8-i*Z"˘UYc+7|K̍Y)!EXi#$H{*4姛Vm`I6oY6!6.+UGaθvbI/lPp)e\ qN8Ce@ K2|$c*2+k T*ĸơ&Y)H;WiǕM Ojz%2h#F"䮈 M:57=vD>Ġ;ySa =P=Ze(Xϝa(yW XHKH rGRM5H#jFŨHx-F fˆ`t#_[y $i%)n`'0B/Td ߋ4]\=kN$&q 8-:zuTD<l3tpd!_z5jOϞ6D*F,۸H5j(g/fyFB.FAriFmz9jǎHnKBlNgGIN\:uySqUwiwjN37:uzBi~9XVE3<ıT2NjлQ XS: k< X8T?!A9}Fx~ O2*Z#Wr<ᮔ5`?*ja#ƾ+g9 ᬪGɪl|YH0/ρhx u^_K 4(#Vܶژl,pgFn9غ+9Co5+edr2H RC ؆ԉjo] ңk'onʚeDK7.ɓo]n%AkI) Dy𪶈.87UPaVʊ tkQ WLmR{L3EB^>~JX" *4CU4fU9`Pa#C4ҬK3{X8bsL`b&r8~+ Oo1h1-3|Pf-20lc=YMqr7S7GiȞkjWZRK}b@PMft',3> wM#g(if4h}}[ܤ>Bk@O< v?x\ՍNJrȮhAtj,Wܵd_PK/WgC~qנ͎H"vΩLWps![v)yP綤 N\5F &bZaa&kOZ1d:TiQ+BpZ3'UcD;M+E][r`)bhgq1&ūsԻH-k' * EbX'o,tHh!M}? {ˀUt)v`Z)2Ůs mհ(Vx&h0]$YO++v˥j9v)B)C\iɰj7 rڄ!L`Zi d@ԈLWDF](+$k3窠`ԚOWoo `ӽ倏@6 UrMӒK}/^C}H︶wz2yi{}};w=v.7snWZc1{РYk׼ރ>A׏ Pcvi&)#1Yalm{v-0nv]kʁm{{w{#ݶ)+l6m.6[4v%}J汩=@f-:a[o=}:k]ـ-@PQv}M. ꅆO]=t:@dKbPR%ie bµ띃ergezbwv]{;qkzitn `;27Q U3sIe"5p\@>>nG*Wo^e׾=Uuf{{xjr{|a|O;.K݇޾vڷk/#ս}7^}}mb} mR,ope:H{zYkqےb"],q{۩>'Ѡ=Ox}} L޻|>>wown=@ :| =towx@h@Wmw|Opݞޫ׭ۭԣkl|m@iNwp Vz1t^aUm51m*tdYu׽ҪgsK[tݛ/ֹ٨JHYs٭U+;Rfٜlimfvjv*ڙCMcnuGvt6g EQE[5Ե]5lV[ܫcH)5Ъ'fŻneQnܼn`vﵫGv5WmE*5r4݊[ǯz.sv]M z޽-33 =kw{21a!.P7Klm:͚kku6g.4վͽsvtw"El}7v{= B M42a&&Lbhi=)0DmMHCeCM#G=M5~mM @A Mhɩ*bm4=@ML@!jbhdhS=H)&H6P$HA@hi&CTdzThDI䞠z0d @ш MLhOzi6ICThz$ bi=jl&SlFGjA;X6E4!Q@?DA3 Ĉ$,وD~$VUM8!$AU ((1+s;jEXKqLd0`-WUX+b `UE DX1Nxe(f¢"(3V$@%AA # ň#"AF *Q bBr9 *Hw@~G!\'q *0/C1P $TTb(P *0H #LUHB, k~/v2&1fįuܬ*Rf cNei`I#2%`yxK]Irj*Ma(ĝ]acs"^k%ӧd6oP@YTeNb22 j H8o,"DRL5MU"[+]T2·"@0Tڈ:hҭҢ#dD[SI13eadUM R&hcFE 3 *7hPYaUj9+(cr l+&eI8ʕxs 2䢙AԛZʱ&sV#5PuxiԂ$l̫H1pLnByMXX0̺W/'/Rg1;hHt.\t' n#SjNʃ(T?T,zj!l dd?e,E$X HB "F~d,c7gB@`"@P*  Ȅ@ T+"%1(ADXE@9 UWB#"2Q1DPDah44YZ  DACY-@# B`R( *1Q KE(f ;H$Y,TXPE!2 1eMX(i0 V+ @)UTR +" !pq , 8 Sj#?X!&h" D D]TeUTٳ JTIQ7m[?*mnG)2Е$ZUUժ (էbM?1c#Xƭ_޽ɀ?aÑ<]#UJ+`l-?v#Vrfdl1̦8a& +JdaD0A\p 0l˜aM$դȫcᅣm[53 \ MjLš5*JSNAuEPkm'i ]cLpAac_Jvjƃk^Ə[Oil6'|IId&=cI>?G _ed1E(r(QOQ! P!b 6Ml I$;eT=.?|<-^Hihu; ȩjg0+]dO!PyYO|d֖B2`֌h"Ea*T:&4&&pp8Zf,..&̺J͵54InJ!mfxu7lA@a!2xMk  eB(֌"mBȲDE`*?O ,ܾwAIF$w}Yƒl9:eV%%w}fZOh"-~&ႌOg[p( 9OrԒ:(+}&}hh{L8~,Tw,JArDCQ^3"~RN(%!2aJ }HG(_ġ(PBϭ\${6(#qXHI2sR_?%A/2YPqG[S:?uCG{>^ I²^6#SGlboY!D]f+2VDV 7ed9}$lO흪L E$<UQ1Dҵl]cd̩EXZẢ343ˆ@C YþbEQb'"*H,D=望4V"+**% Gw߆} n-'u4衹FSv^*T}s-!^o?aX|4*3aNkˬ>Wg%茇pw$?'ک턗]Ue{2&(-\,Ȓ bFR>CCpO$ڂubg_4uGrŗIwF(=AFf =Xs> l٤>ǯ afK6!#ѯC cjv? ǖ~>-mc=|$UI띭Cv U;a>Ssw G^fBg8hMA@/sUpv\hX0] }: $]Acy@DEAHɚ>gQ\\Y޿_ .Gii 8KIb9DlóS%^mPh7C'㦝qAdÍjY|~e sJN5 #yvq"hKD)=H2b g;'4܋* #II: 9T&%վ6I<;"gihxJgz5}J`Fs3vFFhykޫRAAb?Xa@C^ 5ih*L'x:OiSю%;5c/윃M F-8(~JPЧF7GHW{$ kf<B0\6 ^ݴW`$!Ix,LWscjnMsr*)+3-$'EFhcx}=|i!Tq;G4u5jQՂw)t+@Yׂ31Ǥ$5mV=Qio*UQ3Ts$wGO{(*=QP?hN&&4}#2ٺ<_s&8YUKJXt)N8'j{}@g#/;YclGU͓RTp:1 W8k^T\.;.M4aLFm\3i{\|(f(x'Ω_=]`AʁrV5OWw0_/C;**`GQ3[2(k[ ©w S_8ed? I_M{dG$@2`۝ɚU"k݀b(T mEmǃ~j4C9}Qo~(62I:@1F,%,R=QO/hq=>|0O {7e)h0Qq鶻w>O޼8e={b~ľyx{,}O>A%%!!'Lg]fΚv˻{χo&Xfݻ5|1X NLO@֝ !CÃ]"z9bFƥRu:YIo@U9Eև=&6(r0vyA彽h)Ŗt),$! DY5~m55aQ%~-IEFUVfb*39k.aݬǣaM *Hf̩iR;㧽 a={8:-ƴ%#~+TTDEDADA,>>79m>\] A̐c޿Jm3WaD:,{l&/{t7n~|`jU yl4#Ҥ@K611$mzi)-F۫61;z""WunqMQޕQ7:5цAch#%z8z4"XXԎEbG zU `aW<,\od{fٜPvh $Nӟѯ:]$)裇rWr ](q_Ϝq7$6vj#)E61P=/y)cU)u-_~ו/F>1᧻u߽{ܨ}2wBZ\EO6&?@N;R"Ib 슁ry3 PSBv_TN .2ؖ&=_>1g_Pt&&f#`Ax^Ȓˆ&dsЧN,ldFespu[RUTQu MviRu$D$(e#9.!!n]x AÍ l0c1^E5\λbvxRzGףEoŦDWd̜a,4 JqLP@OJ I#ZKRV4U.w>%*wflnH̪4} ϴf S x}}=޼傏q~O7iK~vUVI&O>wMZ=L8%hBWL~_oGP'X NUwDb'_=ݽ_ϡrl_~ĨpJ$X99" z29O. /*Jp)̿Sk5oLK4iGn J S-<9_҆ 4w~ΰ}Ů,:5p>>'}mi;8/Oaq~o[$VnvAO7ϑBE_gr怿Ց6ٟNUf˃{$E38$U/NDF8J$U=QE nf5;~Ϥ=mn)C OG2#}PQUVUCUIsdk뗻SyWd쇖,=LMJd;˶ 0tKо]<8\ȯ:㒨lwy.Kqu?t{:fI˦"2TQ}9ur<]zџ$Qɻ- 4H&_e&r=h][=?TD@B*j|2Ofν=+{Ғ?],9'6|O[Aj((X'JEȈv !k{Z˭SSN=Nsƚ_Q@Դ|mNbVU[~(!|.y!Os.9U5b(#9ڕ֖Mz[٬;jCfJv;` ޡ1QaAiFr =jOCreonG皍5bMljs>6¥m~쯬LJWrն\(k&gf篝!xqSl5kp\V-v9Ղ69ggoM}xojcܚr?&L/˞-"fɩ%]sBW6Nvuv#[YIΉdST{5`ưg:Z6lQQEDFqfpc-,QPUzQőD"hҬAHVԁ~d|Ȃ}""hPLj=Pݪ.waޫ:MmXG4P}݊=oޗ[?mVǡ/xq&.Byd­Q}jJw?GK r}$?<.[a#ŚA#Ul)>~jvVJo 3SQH=[xC|8?r: '@b!MiFzUG8=ߛtt0'omQ6wu˷(rWϭF1Gl\ya WuI&<[Ku`}2[ ˉBK2īx/h[6wy?:* Ш rL.s3SUGסN`FL`[b(0؇g4٦!O(ncrrnᏈx;!8w96i? $_PKP 7p<Wd7%ΊJ: lR[ԯ(E_ri}j/^%{%ڟ pĩ_&NOgw"ג.P۝stxH&%RvdfD>m>?_,; [CdES_Z5X —sB$S&c[L_ǐa`6]rWF7없Wi|G'31sqO10 r2I-@SR-:v N-Fj *: $L] bNhc, C9E 0&R&aJi+hBK+h 1D#c{<5|^^|v(q\?cb'kxkqiA?c" w}X9&>F9-WN{/OiM^ #k\ ȎgvJچi7OU4d}vO4 օr?koBD{O}.ly׭P"s߻8G8*1fT>C(&yՍWR;^JOzፎ J$RΒsZ;Aȷx*;d&5VºAeX7Iˇ>۸=ˀ&?oasP(<`_+޴ 9| 6'.6R(z5Zڅ\PvA-x}o,)EBGS|2x3iKA43eQGEX!*7M zNi)ڑvRIJ]TGpi+ T0,zRf p4 lQ#xׂ@"^0>@Qjߘf3dluYhy_a/NU[ٺOve U6:ʮ {)9(XL D`8.N"Y%'o -QGz8, m6 M.8Y; #VL0~E 0,js_MQDrAsAPU%5Ir'\E,71Bئ>cfї!B,(̢3Fؔ#ѕyC t 2LCo` \GeUUU >8.ˉܗ[31{.lEcZŏ &͌*T}kV2`4MXuzv]ɿ޺mճ:ֿ74,}7׏v*>e9hZYV?mHjRce=zqSg(ȦIk?N3\+~wAQZwK9(B0!7^!=`W6 001ߪ}v{,8WR+J&OedQx Ctq)Gw$י/Ol!+/kE{6J&^,䪝q/4 9_ﺛ(U߭zi|O# /?{Y`G5 ¥?(1m$<+T_+Ppx=K LlE&N:e M ɫ<6骣S}?u%=ɣG5ˉN/a$gK&.uKļ0rUVB9Aʓ8)]BWSP5zxfX ?'TpD )ҬG+{)nLh꒜Nrc nU&xb/Of#`;gfh;sȎ{7WWP#ՔYWy4sjV˸~=sA6CBSc/Cva(xk)v}MV`U9@:+4Έ6ΒˣҿX2GQ7Ym@|5MaCܬvvVLځkP*.e-f0pm-;bvF[pILYYOT̯ϳzɕ#\ RJl$ vKbfT (r"(FDD`R "+@H1Dc@>H!8q6k'(NQOV P΂IE$@(C?8ΝzVDBc2x>)zAH[M%eC'g=?W<"iӈ}(>O3GbN[_g/ײ-Ὗ/Vzla߾za~hEm>&?tviY;Ny?Wspf&_L򡤊(ʏR^&d,4oaX! .v`'O mx3jI_aLXB_JRuPrS!#/+:1Ts]@!Ea nY Y"R'곹=Jg0al s|Ems~M6*ZUЮ[5sU~Sx۠$l U"HFZ%*KPH@[S!dT A _R%6 5F934"#l6IȪRkD#`zONkWOR~+ 8\Af+6vlV~  ( R*Ӟu+]XCp.NU><m!x ' CCPOlm 2ȪP>~d|ݾ߮OC$o.kٵtÙ!SQ< =ri7Y"?ZLU|ȂCM S"ފmݕAWΔE*"PUP]u`@Q@P - {ĸ=kN[PBpBS+ Ƞfml=#(AcX1TfEX%>z^2ʦzzSB "%-dTytpxHEIlF64dQK"0@(0G !ᩚUɌ@#gs%I %d+PoXoI Ж$AT 1ILFUaPM<ЍKeT*[DAF5S Bc 0 !JBǓDaꅭBTƲ)HI`d,EƕY(DHLB\PCb‡p?l!t{FDQ{AX"uҜNTF'iUl(4zzZ TUeSA f1&-0HA3XAu>_K@$xY&ܨxX>U6=7 43M2]cFL0Jֹ436Y1DDGB^Eynz9#HGfp$@s1GxH6's>WE0RD悖@I"'7ԨUgZ:~+\}zu|) ;bqtQ @C.TũԷdDPZ0xp1V2 ER%E X0$P-B+#EeB+c'HdJC8{lij[vxD({) oo=(k67'4"a r',;6ZRlmReQHĂD)E7D-}T`θq 3OVAh2bQbal`(UETDϱe ` d1LQ}Y`R‹j ]y~Y;5mC7%747A#0fA-D61,`X 5oZiwt~U#dF€(n \ƪD؅1B{^-ʢ?J"~K&O{;UUW%A$'06SJFuIoZ&Gd"ʁÐPZ̈",PV,`>!Xn P-Dl?.t`*qś tM0V|;.',]3#S|3%DStaH(w~ĩYYFp~|!CQ<چs '1bI>۠H$I6}Ϲ>?1rv\_۽MK= 3/klx" )Qc!Z!*)TOdA A"ȳ~;r> wd[PZ(֖M0BIĔ0$ry0eiƬ -NN,aSsÓTx`aCpѱvd!a\+LVf`3 \elw݈s(D"D}ɀ?"1wV@5B}t!a`u 0ږQhXLP:LuJܠJh,73K` әOg0d cDd(`ht\=E1UӦxH?Ŷl[^.`)+( ?u ~b^Ƥ&vHukzN+ 50"HI\ww_ٯ?W[ƚ7OM3[ _4@.XSzW =ߨ_9v+}3E8ב_p0ẌI=Sk1YJaWY; hIպXaD0a=I@m$ KJ͆D^RWSOO}1<m捴:1C\=LlGHyួo)T>Y9%k,1 S> ɚ˨D "nnmUKI"0̥ssIq׏F0r[ 2OQK0C?|C|?)GJުy'x$`b9wM)] ZsBG e'?ldTRDO_yXe1˂zOR>Hт6Y'L4!Tj۱WqZ?=W|+ ۣR0AğapG#lj? Ag`ACvF" R3>ë " hIGQ(yP@D{^4gTɋ@bӽ+Y}M'_ {RhN rC >F:MYjJXp*IF<0Hs 3}J-xcx&dQUdo>@U("|<>S$Ƌ٧5>=qUr:A :omq:!}<>SO(G+J_aJ4 Тჸ۔Tվ0NDqP#(D P((I1HE} )a~&,{|QUT/RG;?}"_D1:z%JZdG1k?uخPSJߑE r83n¬RC)v"_Yt 7"kf&=sVx`i~Em >nzf03PUɏA]1(+̀ǀ%}O\~`bB ␆b"*"#JJJP@UD>Ьb0;XQ5 V"1(h(Sں 9kE|C}h0]Fݵ'0XȔz8D)'PP2Dž'ݙ$*-r/2)d G kشPp/@SW';tم@܊\zq홒 ZU) :V+G8Kx)M+*axHex:y JLȽތ1Jmܩէ>;`oq/+ytI'DUuF6[T>3qfXǔ%;ʻٌ9Q )$*UU`~+ ~/N4;?T!(mz9*hJ N쯱¨#=ێHT/C'  \"d?X,J̃7̞v0HnQ/@| @m"2 V0NզH~;Y+_<$w*yy@V(Y_LUZh_{@ۑ2G sP<[GQVuWiYĬΕ8hHtƊxՎeIg:}Nqs*W3o& &̉SZ%(B8ެA0 L@F}<1U:;H7%Թv˻>Y.P20xĉM%bM[k2h2CTj@RIf c20[rg$IdIem1Ahni'DṪTĔrMHjYJGFBNm:[.g-Tpq!Q6fq=a\JNd ^&DꊵdQBYQD.$b RZU8՚ec.lI~%33fM.rOnOwBW- bc&bo|oNIR_}.HW ]U߯#Qّjz-=bV}X(x~i9Lji|t_<'Th $<,TY1 $Xr? _N1[w |4rӁNoxtEwP;uU@6@&GdeP@rIKiIW7Iΰ~͌L/`[\8QǒxRWM;%`:VM;?DLzUM5-13J2ʈ:lYȑA&4@DDy[Ў}2"V " {SHlI`b'ӭ<(h:>mp>\$nl] <+ܿ$S%BEBO, O$on?Ԭq'TDKF8`Hf_50YF+2C0E[(hd zLDߎЛ2)/\ }@FBz"&$jSҪtT?A7;:͆DpVIDDb&4f@gHY]t@z8Y 6DzIJ)EU5Pv$}$SmrkXWqGRx$$Hdʈ:C .9E< )ڡb!D1KNv/̡sU.ҌhDe=ʛQMǞY]wc"B:Dݿ} H_]{ 9Ü#%AVҗL20alc! \˹, +瘀[a??QI#y{vO#ɩ9,tFn?$T\j$kYco޹+RVlإp1%; S&z̞ԉbtS1ehjLѨ'4k)8(ўn3*&3[8'RsASYiҩJ^L}3T<^Rihk4.utJ!&ӉYabM8+UMgbDέ}G O/4fY5D1K: +'3e#`{Lˇ0 7@FқHPQ kq2 bœ\m.maݔW+L+ vY@)ZX9UV,_![Pab2j1`uZ2l:'[3RpZb<:WGvQo(lncXuy )¤PU" T÷%{<mCR ofC%6pJ_j9˚~N&Duee/;o2S<&uKӤі\[OAfV3}vuIS8ﰁ!! _P~b8Jh0>q\_ r%U&O/s >O2ż:#RNm5UKKZB9BBDTZE43 w|IulڦYuiKlJ/Y21*To6FEއ7v{67UGj7%qK7:ʹ>}{8#|^T;dL&3r~՞ طsE>d{KHD XBAB((ȬR)"A@TaQ}}7dDr 5/aKQƍ:~\_ҾOpC߂8A*Hn8hw)ebNJ[qva;;wV(#84J|Ș 0n AHT37@".t>`WD =Bto,uG囯$QE'U)jMG[є7ba`R}ňn2(rj8"|AtpœOKqNJօl_1KꞺ]qx7mV/'GbpA>ATRBcO&Wg1C-892 7<92D\p-sRY4͚n@5nʶuTn ]@4+ͧ.1s✏qw=DWoDO8>iѝJjP/h:*κCDۼQH-O7-[`Yn- R> )7dN} a1QXr}8gO NVǦv)3qƯHAW27UJnާ雧2}싯O3\.rVϠe=wɰRNF+5 ]8"f/Q"4DC"ϴ}) .A|f?{$UQ풹n0n :_5Hz#x\ٝI1ɦIhdje]+霘1,J&xМMOt):*KV\ P*[QU6g*]I cHEƄ&"#ޯHι֕?=gا֥b@r*ªE~A.x1FF,NFC:pV(aACE-.TivC\l讙lfP*nZًyFW&-EqO ;kxn<PjPi0UV[$v#9:h$ H&,b[-8I8l LZDNӒNKI/iVvC":DEɲ,H4 sppM&.8JHJQDIœPc$3 AN(!!mp͒CO;Je9W>,c8K'!v=\}}g/?Yή:aD"-ƅYLM #"Z\+"\k3 w?1?\sv=U8-we%DxCO<{$Dp#߶u3ӷ )aa`s%k;7 DN .7Hܜ&6[N9'~a=\h!joA jLN:WHRLb&nsxhXqIAlfAtn;IƎ/+/RBzdMڔ&#2b>W>G\!?9 C@ [FznYfW:"noZB3#"LLC5cBOU|@v:[1j}*OZ6}UY;a~9*ޢ/a;V5G N,iя;.! Q)G7qɡc(HElI #pPzDz~$|1M~PQAUESTn79D PTC qݮMX1]{?%eU@iN!펍AӎlA6"C^Rd;GaILaszTGM5~5U~#rYK7DAc=_icµ=3Bܵ-2,'KRb(l>/{gL;lzȭ|) dsTX5<Hyh6aͩGeP!AIv|DAr"ŌPDALm'֎kRtI@0v {632i(l!]̏p,;ETUcJx7O,OJ^8|ɍ1]O ^})z=U>Aa[+3;A}=>CÙZrlQ3d\!˺04?F" y㿅hStFN;1^: +OtH$̉@{na0 ?I'~t2~P:8yb=5h΂9?6JPN@mtoJ6'~FEd蛈z, Ryw@!kG@+c~ @u@ ɷ)3iF nëFOGNW:/On=Jq _>oه/;aVoqWwgL+RX`4,oڇJO[a[-0ʍEjS8Ԯ|"|=fۍ71x|_y@FY{1O|bH@?sӓ *]i9j ؝&rP\N'˿OJ^l|NCT|\;ȯ7/ڙ{hO,uQw ×:.R9FURŖQp׏֮szl=^̢rq䠃EC Y(zx92Bd2Ck3{lK?Kg kV@Q`f:m>TD&tuK7(R.S|X3؝i;8K]"BJ^(vLoc&UEN9d؎@Q] yv/w-_HC1pǠs(aRͅ֐z`d(US9V}HrЅAȈ9-G&_%id[&bNk O{#&\i!'(y/1^#g|)swƋJZ@ 1VL دA=?y C,Mɥ,)u%bY=ZqF4σ<>/pblwߘ0t>1?v|YE_*!"6̊ R"rlp!E/6R)hEpQiTgɗ{ )}w>k'2e1 4Ւkd=$, vq$ C|1SPXNow]@["!ΘQ@qL#SB22) ,q6{5Hxul(l C5;68q[]̾뗎$*eEaV1Etv-PcG}Qc Ӄzo?|ZF4v}V 0E1h}Y0Ţ.݋cևܶTsᾫ>51Fd޾oCKL *Ο;=}81m6Bp$D3!<68^y<B*̕s˝P)y%<;\횞!r}Z9iN޷Nt`P2LIF+c<|opmF_T_Ǵ7\f;{ދ iy0Q_T?IgY")S/S&BF.uw26gw/nR+β yaဪi4(oCN.}"-o#U65ARx*nF8WUV4*AC<f )F1RDʠ|Ğh[^&qc 5Ea*qbPӧ'{QF:Fo5%Օ:O0b>ϋoG{}FcSz:2ߺ'%}[5I6i MaA%!{xs0˃}N-UUEihQkFΓJho A QD &NMT\Pǃ4UI?F!:sMDN;XE_τcd5]a4%;**r|4?"?E]U#]ww$Z@|߼fzv=niOW-צ'EֳU$@; $[hu1>W:g֙@_x[ڎ8\*y&KfDY ysyxx>KR 8#)i{ۈv9)զJkBiOWGЫЪ"Aͭ6wȚւ*gS@e9;-}f'|s4fHY)8G<%')K2$%)X`v"3*|L"(mЙxdfΕb;Rb2&[Hnh9g7! -:XCIpV#(MAb~y!PA_z?)q}FVp zG+s+\W\0cS'y'S⣢ȺINn2`%x(%8K >f ⵡ 3O9-XB祊l캻j%HLxoXxAš{b'WV98mdQz/D{P&aW8k[x|iVWZT፷KnLjĹ&*P*qcH̀ϙTdʯQFDǰv|C_s-DyzCNs<ȈtM%ܘ'#lJ,ScI]Ǵ9uSApʄ.@0t?$A13=PioOdɿ)E ս9O^9j ϥzz(M~1ֽ&|n1quC_!&d)_W/^澚.=(P$/lqSH%[6pQ; p2)K5kڸEi ʼn+"X@xLL^hn3*jiAqщӦL]OB4P,4Y$fZ;Gl]>aU8ނoPO4:=2(ߏ;(* ehM1yF_b]i@ՔAGaY0kLF3f dPp)bWE7(;C)^^;lT; 6\y cɺ\ĩѶSXr4*>5Z6(?\,ѥ{Rh)xf/: qiZdw_õLp2w㿭hd:13&|̙M-ZUm:ZYT_;46sc$TP3Wg3%SΔ--M~35 SƹL;Nu䱿wPm@ 2#u:G>D+REUKy6T9(tsOZзZoo7}<"EiA"#gU *~Q0Eb$X"={}WOtڵHxh؋mrDʷM-xLW*Zo*Pe)"gcd?:&1=ނ^|2L{}}<x*6 HeNH8uP,1k"kFH(Orh8/PU^7W'LtiSN^j& bĔ\ϋ–ad<ܚtE2~6.2~VPD~KbW>RN(׹yfں)v2w.6WecRrw/F;|{6wbG[bƃg ЬS =^wgv=]gtu0Rf ~NLDihp=hX3NS7|6lKNYG DLC2848pe_f+>|ܖ1EuV\Sѡa;$EUVB_#ISoX KXO>b%:GC|[Y&]ν^nlQbn՝vlM wb9M(6QյEDOf*D.n4ZPBt2<]>!pR:[#΁E4]LM9ϡqGG/'YU+T{ w0 A";٩Ƈ ^d;rR^SB fDz Մ4W8.JÔ|jwo[~tz#j^4ݰ,##s !>YsٶsĐ:09TP%*J擏_Ê:Dj| 0Fb4LӢ/]Ӳ<'Tx脼nLk+^UW<3eQC$^G`ScVyn'CȆ=` XAaUE r|7@߯-ᒗtL6֞No,beԽ.-x1TVmاΈjZtIsGfwQd)3twS -gwY.J$C)ꚫ&[.͖ϯZaڦO9݄D1y=;s9IeNGΐBBGi6gcDWDB݊~Sي(Ӌ0ӛ"\АkO}6@k9J{Us.;" ;}asH+r*V@mKb: tQ{| [1wVb0!Q12L/mVkuluphC.k>\`4 pv8 ֬GH'Q˧ʣ9f4zEEVnMy,O Vgᢍa"h{'O+r{'~hg޷m9~(}vWhN ɪT(2ֹ۸`\&BE̥Y99;E2犊`98^+p}͖5bGj/:r)* Ϭzg|49u {POn׷\Yl3Rl( Kye6 ',`tLBHqQ?>Hԫ #ix8E".a. )ccQ%^Ruu//̓fE0gmqiixN뛐]թjIkS\o B/~iznɇe3fEJV\=G.O,I?q2K\%`И*UMͮG9ɒY*ec0z\x'v%@Z"HacVRBYMPD$3xɴ=yS@_]om9dY9KlU/|*n: AHv#%h{זYJRuxt (!%)IJRR%)IJR|a=}}V|yy)EF"yf)f[u6YPL;dͧ6{,3t./u9]p>=sz'@TMc,3;da;RfrgA (8DUH|GL+ {麨̺3|GySCsGI|#hY]+Lrr4{`[=DعXk">P !~GW%|b!P1N .VbEZs:|b=R!̿ iC<95Xȱ9AUTWg# vGKH=jq= jLJ[xCAϚb4!C#rE?ZP#*^0|WdI;+d,޽esy3aCt;kQFdeZVF\-ƩUW8?wgrbMv?`x+5G1M'dϊTY66|Nm+e!C27)H Hѝ~ǘI8]w 2fi$'BkU`¾u CdS3s-eZVmz<H{d"+E\s{yf}}ljhJy4P2f;j@-O {ixթOx&~9>Rk⼪&>m@a&aN_AdA) F U-K2@0Q3oI7}ԣsFoYq1NJ ͢9*W ~I 5jsey”eto $ZM3v.Ku~'e~"h#8ohft(sQQΉψ`{g|nsH6}J,MӓJ6;%m p{ oRgbQ ]k*+j5S|5j O+&*>i>6li[Y ΌQz.{;"ZW r)DSLf *լrdsL0)JPL ݖHF=.#,ځxAA`,(A*Dd@Ad`1 B"""F0`" ,"ȬH"( ,HE F("$b  "9#ę ,}gzootgjg֠WhrמcVJIrqTCG^/GU@T@C݈Cl"AHObOUPDUCJCdIXd؊U[ٕUD]J;??m!lw~B+F5;Mڨ}]4``1|oٞ^~]p}OL[d=]x]t2"D4}u$v $ːD;FT 5`/́e6,'zf4Eg*, Lx7*ҡ)^ wdaI;ҝc|b\o\bOHsf<|pA먛8g5Ԛ]Wo5KeT#iZgΒW(IXDe5Ë>K=ߋeQhZeF]lf 6ٿI@]j78I|1yE97(a` ڈ$Mᑰ[#t(J$ X # d!Bi?*"R/t'[$MpKl}uPj!|; !'lpݝ$HvddEBu!9R떊B( HLQ[rD/>XHmZIDaTbX)!, X~0& !Hʠ$QSBr P% ҊEa *PT F*RRc#FERAPdApXs)6"4DSV$`*Io<(]0L*DbIǬ_xâ0V0DM[bU;K UGWX1 + P NZj) ?ʚywEt2\! ˆ+I9d؄ "RP3݃|sa *Bh߳]+³ML`izMLH `K*@u0S/ߐG8=,|;UU| Qǡv ['qRp7R)萡 ] ^,\.?70 x;em(7&XQ)O| nՁ^Y2 `_B"AY:ʆ&Dӟ]0ȠȢ,P HGꈶ,36`T>1__QEE>y@R?T'?'␐^>O.k2NW}4|nNXb͉UVuoSU5uȨOAͨAP+*uY]=o_ҟEM쬆)Nt4J<.&T%-a}vyHN/,9&ш3* ц)M@ȋ13EQbra*AU{>|NT޿KT"c l?`.RE?~''˧!#ɂ>&OctOT<# ~}=r˥+[U`OdeD|'oR[YDN*3]X49>*T<<7y>}MFOh gCU^p3A ?2TUE59jkٯq`y/K?{ԣ>s3M-U1 (qUI?UCE}ȑ$s4FDyiA\`b(sސiH"-0Y ܁ɗ5~) ?ԪP?\ 8$C+?Ǘ*l( Q;+$$,B0@dG RLC?KQrbYKs|Kl's+Y(HB`$+ V@ F`ĦX=m?7_Q~G~g8NoAUM_WyNϞA$H?^IQs`Z Ō!d2{/xzWw'K=:f(~O]}&k_҇>Xq9(}3I Xىi`S@х1[6$B {)=φܽVT{Ś.7T_FUQ[On40rVem{J'uV{kG<{_N|\ADCX [{xQ 6jPD bĐ+$:?d$- ;@ Lj4yNB}xa/PLvócerMSbmj+Nϳmg<5~򂨞@'ս|-Tʨ$HG {\N8|o#Z8R)!Cky9TiS ;'mg nTk>}hB͟2F7؝x 9/fd<=i&r%G₭%N$,Knţ:] #_,^f W6nEL.-4Fi=8""RWcbaBqq8a5K8#wK@1;2v$Se6;b &0QXs]!VueDĔ}LT[!kռve2cVV63Ӟl?>lāWвg!vAnXi@vf*{"z ue xfptK#L!8aV#P͈p(tT*][_zBU;P ^t&ٲ,kjI 9M}ŒUQ;RUY𩽊xjAZP9AL7a]ܷr$Bi!3Mqq3t9ju m,3$ @{NgLy)υ8rI+@#UuWI ,d ]bO٧Ũ`U_0B4z1_Ct6m[D2,~{'} <|=:s9{C3o&e'N$"\>pur=Lq<`&)>Xxo QՋ1AH2[6HC6g.m~vgFvP4W;Bw$'9Y$0R<>ʠfD6&ziN֦#>m;SaHy/^/B_g:lqzӶk] ,Щ"9;?p6|F81xGn!\举82"gmtվ^ 鬇}q"[/ њfVS@:DPJ-80L܀^ϩ&k+ﰏ_}@30dk޽$R}XKb@x"$^HyLmN2#[,֑'N\"D= a5d(1ӗ'ʨ+ a>:]q*D*OpT,$?ݳofu/WˢW_TO,p (|OKH,^3cU6xLWPb!еlѲ--P͛4[/dfS%{fNGDM}q6JPP**TUS[SCe]tQ +yRmH#{ncrozt|{> aano?o1fM-4k^m;q+|?RRN[)4?Sl ̘ p{Z|ƅJZa(ϻI+V=f_ +v}toWDs:. Ս?k.BRuW_! yS'gdpμ8WǡɾK8/7gSik52->E){"jvv(ߪ|ܫEjk+9DBt*>*-,\:*%65&F$HuIO/Ff"q0E|:⦧"QD($;'1OgS'bM #(H\ >^;=*(r.<ܨO&|/2{g>T)C.tzcgl&i).&EG*U? ww/Q GjwYD)3[]!mSh.fÉe_urɴ Y.v}iNw6uNnSձo?ɜ4ƾ6:"o>w*V ә)'{T^eFߡ4nvx1:s-43N1n66OM̯MU¸uC'#"FxX1qݶ"IWafc/:^/3,9L~5Co]q*5nSua}eZ*[bd$_v3A88>4..:~ouPٍ?Q{Wɍg]j.?W]1O' /=v Cm%ODO$J=Aʢq 籯jar|9S;uK2me>}C M95Ls/kG9RBѿ|8{9'Q]x{*'(R> YPzyUPr0(ƿ5KVsa{˝xZ5 S5JC"x)D|2" 2 L^F8`6+" aIŇڳˌ'wP[DA!Gy N6r yrz(>WΡW4z ɉVnu)\uXwdkgll)')oBgZ)!4!{/r)M ؏4ЯONBmtORd.Md)^[DUEQ22i|û)u+YuwPB=lY4|^dB|<˰=<ňCJJT_'Rm R@ӛK5cԪeP\31^ÊO6`r¤a+$ @UEFIoMi;Uh\QL-50T`({dU 'ݡ=efŝ\T\KvE JvrODc\+C;jU:tK7cEUnگ8*-&־8gOUl]Gaù+/?Vt\w{#[BOxЌB(kg,)DmKĵ)65x˫䢻ɧ |mTQFl\՚cd[]34f-凩5bņC|w's_{ExiϺٞYwx@3 됻!)㩋e͚OvS4 O$zcC65ޏgU:Q76h^ɟlQ#T]΢:2yO^YP߉g9 (|reNNFjVolч;!@zzi6D@,ЄN #0q[sSR :iX\;{8$n|R%&503ڏ~֋+esKC"Yܾ n^{PB8{Θ4oB'Y[9W̵&+ӧ-kfM!b* '?KQ9& hJ/u|tZKfLUB%㑡 S3AϹOs)!d(AXY 6SQh Q. y)B^Ld*h>jPKD3 ,QI?9l$dI+`Z0$,B'Tj"'cr%Ц`' @ı \"o$@+m$!2 FZ HTK6N.֑@g_D" (^DsՒ)t@[Go.'a`/JB!QiشwoÏ9xDoY[W?.Ķf.Mx]y"PT#*Fbp U4ƁHCPǪ5 ES5OZd#r)@~ƒ۝!.{#xx@I3- IY!H̀GVqv7b˄XEf5ٲwNo+x;F~1H;2.\A}R傻be&L23P 06I9/! b Q!% hV QTA ݢ!BhRE@0Hb6e'v@TU FDB"XB)ᆫo.La-LHCH`b`I?lUP`EMmCv;BY;; m[hѸ*0N[lWGu#H)? !@LdOiP}z&jds upwQaPhAFs[P @pl-1r 9!z_F6yd 8fqڂJܐRİ "Gy%|vG*>ʦQ$4F-F4S}%B=h:1ώ$?E:u*I}D5D܄ָ|t&,> tS}*7l`X.PB:5mѺvi}?l\ ?_;AdDc)$jTR,nV-ݔNzuf,h].^nEk82^4yE麓Rbv |Ӫ^v}:6,BՈswsCL# Fky}6UPKgTIkb}.rx&BUK'Ѧ悄2i@hԯ8܎`G]RDܗď VIQ'QQ|L: pՂ͟E/[l]ffh/!?Y2!_>4.Xrլ4̫fffsɗBɧDqiL⦃8O?Eb_tݬ!oir,>Sf3ŜHގG)c|RVԢg8Ge1g@|EJG.A:j:z$jRWY'Qe,$9|kngc{o\c2ο~l< ~C MP[WHz"<rX콓ylø` L3tDC|G-Iɐ#Y阿(9b!*2S~4/,BDGR9_Tw5YXwd{]=45^|*7%O5a;;MS7B L͸Hw{ߝ,gdypgPd§?2#UqW.^EE3kL1xto/<Fa9%QqA{8tnV>{o BbMkͮO?H5ԼZc璻%|4Y/߹ɽ'2f zdF6D<:. z )n4l@|#k8pͭ[WsoU$}e@>q'R_Ǯf+sLTQDMX.m+|hMri nhR]f^ksTqn,\⭧ji:)㻺˽ZM4.iso/<۾&Z9n Q.mng[;#/6fSY/l7vզ2]ELF!UP{SF4o!d,Z%JA]"HdJ7Ta--_v/qƅ0m Wv٬C,.Vdr;Եwk7l<8 ePAlc0VBɛՖȨsSVVJSG.rH+rFg4xy+e.A\O[ '{CUMN^nhm^v1x7<'Y VjIMyF=ƛbp loEaH FX%Y2|&"OP0G_ \t8Q"XV Ndwqyl䈃M@{,0z뾋E7!e$ß! hL8.92;uHvvC$dkhCnt>V%DR䭂 مEfa\w{Ǐas`fcF@AQU˘v;d%4V !IF x|&^;(@%>A~H(~Y!cY~H[YTğEaBR) tSaX"xޕ'!a08Kg#vQA~ b@> i/MQX*"m(*2)ϣ&qǎ:xMt8O'4k~gQWqܸbm'a7PV-dLk!) (CCm5"]\>wY$x= !:8"ͺ7@Vā4mo15n/W/Nh#}XtfnEJ"#CF%'Ro@`M H& @^95UUR,(|P331:QW}K_#b*y9hp`mA跬O I!+_cѿh IIUAڨ6} Trl;lsï!!''l4chKч@*%ŷB?fQV9U3 Xl3$]R$uo9jʯ?,spa3x$̂r.]XaĠ!*?""j-AGD-ů]v:5]~po\y W;`~dorδknb$밲ϛf~i-cLU|zpM4?"{Զ{7JugW4M*ԩ\̰zҀ{5Ⱦ|~q_{8Nok$據H Ew/kxdz߸rOM (spxzg~}X{[)AQD4M!ACfrMݬ k@V[MmHc\J pi4@S,N$DFxtCHf:X~Jk#oaY]QGe ię66i{>n:n;_LkB,9fP38=~,@ .373tsY=;p+MxWՅ-8):@z T<'\eC[S;Kn:T!pE&&jKgpR{Y^A|=6oAe}3}aSo R|_۾ljZڃL7#bx# VBbd£efVE gq)A'2?83cAvF"ýXdH}d2I k)V} pQDEPQQU x|ܝԇD3L-$Oead]@ eh"* )CZ,R=^P 6Nv %={y\S>BWѿEANTQcEuI$dM~ "xDgkd݊Cym]PojN.81Se\R659r_~fA:xc"N}<85آvˉxjh@GA);ԎI 0!F%3MA2Scy}GE; K4nU%B@_vetZɰIVvK<&|sVeUr2n{e4*c#$RissC3gꞽZx98j}a?M*%<5~M !Pt;)|=o7Ɣ`ok {D~?#f'O++(ͭiM%Sh& k (M)4Gd*%JΫ:Ltzu/$Gvm$SX/G>o{!i0}yc8O=~_)J,{m3lm OHFiYXJ{zh-6LE&isΓ2jۣlCZKwTe"3l4*wDWu:0b)"'[],'-iJUOzɵT`_[(=cS %##:&:Gb!# \A+xPIʪjQއ]d=>}sنZ:hvmRb '%CL ( `?TVLH2"E,""$ĔEyPvgnz{i>@^F}w˰Z&V>(4=bȱDN""|| t` H bãtWWuqÎEI aC@Y* 6LWSf;)RfKd8'&+/d=4+{L~ĿaɅ+P>o[)沢׏~wI- L[~><&08\' m`\4%PH^L`"$tA1Q}< o|?GϚk~CgY1ZfO&xj1xl3Uj˞ f_};PH K48qcLrl܆G4+0rGQBD;%+n<>jy%ի0:Fȅ ݎX/?r,5%eM09a!fd8@LA fd9 Ԧ}pq{! EB$A R1$DM}PM&ӗ^QT!h=W,rM7^<@wT F4g}Z`TA_GS?7r9d$_ i(@ c ?ӓ'7Fuc? l+ex\,HR@|@mAM8^UUCIU!ܠ_ho]UhiG o‚7 'H=YUVdG 4҅/铎1ԫ"JpdzR,5J4A3UܑJ&?su$k*) ;2NH"؁gmTצτs`NΕqA^2Ŏ}9VH&*UFǰDtD*oxHdk\u4̃&Ea,db:a kI}L׬}SRK%] h&8狣2vmcLd;l=UShY)ՈMI7Pod$0u7%;;X}K!(U±@SQ0.I(Ms śc3SQJ/f,:=f#pOaOpi9qxmLM9K G6/$|iΒa/{>!j߀h4&1I<$neW}/ᬹz=:-TWMtQ'*//+U_|C_'_\b+{?15^] $2" <=]Ot&߳EhAX;񟁡tb**(2?;QY%̯g{\G+?rf(׿^b!$=G:9LB> W_YGFk\aTkH@FStם"lLx 9 ^}YB8n&Ar'Ð0xfgd@}}8-{/оͨu";f;~iyN /L}@9UV(-۳BB%?;t N!]sC@v l}x:wI"""""""""""6@"""""BÔsLȖ,3S]nAͧs4 wg3ɾvh1TR,U<h\b0u*W\ϫ"@m~dD$:zp65uM= ZBb]MHBg9馲'L"9m&b7u\6E8Hq%Dyy&m\.FmEU$LhÒ/p9+sRqY34L% X(Vzӿ/ZDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDFY܎h{a~5ݭ1Qä.=A 9FX\tđwl2BYs5P G\Pa6O[ee_]2&!M/z71'3߳۰Q:9wPz7vkp& Q30m|!s@'>%7( "G>HAAr'l7}ca y9fJ ۭvܜ7X[IAES^qp-ALH_ʛn>sܚۭg2!fj.Z.tz O0-D+goTS"+T \!*"2^xEݝ2a9aagseyl 9; -)缭=c2[B=˩)ou[ʝro7A=C˳ɶN#VzmT-s"Z:4a+ L!&'A==07|#ƶv;(vN͌=WӟiN4"1٣;[Tb_NհՔDcbGyׯABGr !=T +@`r{ȸ9Y ͣO];$⠁8)tBzg I)Yl{N7 S9ZdXD݁dhM(kփ8V! ɠ(hN \EM0DQEn5tQOqEQTUEdNj:^P@s4ӊ(l/4)u~/ U͂@@`WH*Qp@LR-Aՠu L73 3082t<"># C> 2D)Qu{?SĴkꯒm;ʪ:]y˦;Q].A&Pw<4(Qa31ҘY^TM:3v1Sn cvB HI,hrt~EWGW\Lr! : `Cp%,z}7GS ƍ~홡h%Ff0!憴l2 Bf aI dP a6@""89d, O?j^A:m ?C:U S&ujE&NT*9ׄ(eUsu2nd'2ZNnx.Ui 1t.P#PB,k#>3@kE Gܹ(wJ$;4HLԹQP$ЖyWET 42_XEF~KHR{(jtT>b578$a>LҊ SzPq15tTTj&fuhEM4dd94bj:nPZh].结ZЙiUE1A'$d h7 (fUS5X#w3@_ylea,^oe mCt.&眸 ! `=7 wGZ'ۡӿD*gözY$W~lO~]=P6xxZqذ^#,ѯ+>0}CS>'m{iiG6/l*x 6લ,15I^ߟ1Gg?&)c~#zƟhS;"幟~Q(ao*UY᭤J{4/7x @QWd! ~luKtt޳5&*( 9tJ r5JNiτGZPĝ2 -P=SoZ1WqeQ|+f(gi"LR( Xem Ns^ sBE3ifMb/W XZP~e O[C&` !4hK5ag;E,83#C.Tnk?m)%\d@J! =tZ rބ~̊}auVCҙOoc::ɼtjH涫M%[:e.hgzyԈtвjV94rt˓ҡWXqm[̩%8 +&%΅fRfuRq0Aڮ`턷ffl0^E4MwCydK*/ >4qoFzw7JoZ5PjZ2)PR( br$D I;mJE75 / Vhw@@sd/_kҁm)kԌ3"31{[i^Eԁ«3m , kJ,QA%aۯtC}wH<_t2o!ic+^ڢ{*/ڀfFtz&ƍjiu 5=KWC=P%0. 6'iOeAºB߶j#|_(I*oD9NMtvp[H,ű7nT\byOOrm)jzw!%.g.o&*Rn]Iϖ٣wٳ^Z^TLZSy8ɹZ8U/,G7,n\6'YpڹQ3+l̮nYߜ# ׏xTRg4tژ>6JtEHe(+U:E0Z+fUq;4R蚞Z\@)-A議n*f&@_}{2D30H$DCdDF؅#"@2"_\4p' 6GI\dP摁cEHt+ZDdRB..:2EQ?71e.Q-lHY; .<1ⰵn pfbOX?!-J*4o}x,?:{J *ĸ׉fueӲ劌[3l5.us"C"~׮jaҮfedTUIgEUv!\]!RCʵb#(qRjcTeBƝ?mV5gHU'<^-'t5StҞH *Zz푌&3Z3ҸW#~'Fy!=; 0'sM/ݥhԐ$;{kA ̺y=d?~X pL8q)&.jIz9pA8*|I/FA(d۱d9В@kHaT }!w:1:;; ĠZ11sbS2kd}@G6$|WZ&X!,B9Cn2͚hTZx*" wmΑ숚PIUz JM$-tC A y|}L"I@CӜFH@Yrߖ<<3O9M~s&&f 1{Ug#(nJ`JO\\Czʖ ) )~'ET֨'DR0DV.'Ƿ}I"ULuiy:tcTyy3q؜]_oW|g̝%ܤ 5ULiO#VOyv#vR>P!M\ț@UCٜCX!m5/~yk1BZ=2R96JaP8r'n֛K`FZٗ}*z@ A=y. v{vK"_Dֱ˧UKKSNVgX ޲iVmr/0fFe~[8'&XK@A[>Myĩڂ0e84,cJwv_S 8~U CB09μ]d1 uOi٢U;S5 4La fV=@;OyOs2ymǧ;JRO pg! @#.c+Ŏ~$G;5i*ӄMU6KU pYQDD UULr."mۆeo|e cyV jMvHl!! 93 EA#=xIJNq x0`HUD_sqYzR)?@3r)e838H}~m0`6 G|C~ǯs[ę~x3Nei2e3W( Sy $@ +27C+|m7n* n? ffFХ۱\yK(Ay{=%{G樊ajK3k~ꕱ#9jl Sw9T$`H$_ѻ2^/Tt)}HL-b*Y׳dq(0WM+\$ZU.~+۱.L%+(O^=n:سo`*%:TC''eGC{jL!X-ь3,C}MR%~(82hfy3)"9us;" "x@zoznTAᎋ6]Kc|'~U3^ AAt}ޕPTEbvst@r9|NKab3LڣqItQkc4̗ef3/=Pa)]zϯ~|ek)B ߯lDh1i[ ly^δx?,kfyXF}ϲW*е[S49^n.~lu",_Zvz|7-3֓/sźx+,U{O:I}FDZ14_&tzHgun^Io59ֲ[!’A4 mtAՐ6!yUJ5q5288^?0Iq;wrP8A26ւ(h4cF/ѳkLn+f']/7szdžiĕgF,ޏ&h=m%i7̌p;%iqSzsȺ1NI,ZimK*}qM4l|ij=5CR3$=Z[]zBIVsYvT] ՐdZyK'5`moٽ iSNRRՆ,Z4WvSĸlsԯy6Z:6ZwIY_]̣Dz<c1c FsƾdFiмy%Yjd%R"d40VK(d{:V??D–>d{ Ҩ:vr![ uM87G p|XAD']j2,VeM'gʥ>tsh޺JcoI,^w`>yͼD ٣nukſ 險PPaTDcw {j4 -}5X'4jkN"S۠__gN!˯3QԾ=1 þH^0Y kW:|>a=]ӌ9xix A+VTckAGWzdZ"xh[\ *Sq3y侾 } 3_~7yME ERLLZT$o6Ɵls{?%p`zKbr&>ݽ ǝK._US_3S;LS7sȃτ}zspA0&BiHHɬu\@[$ p$14ApxW9Rc=|Vd%>oTMrXjjTيBF 9.%ِ )6ׯ;E'(f Tvd^d/'RamH|DGDDc]8#çk}LHa$ABH}>DP>f=)|[z43ͨ)T!fOOǐ`0Fc2xXwߩ7{_pMCWB %fB=}9$Bm9(Yw/r߿ 0\ZM|Wt3vZkN:YGDWב!S#ff T!2?MO hpMN=9T@ng\_8 @E<Lf;!yX YT0 ,G\ M3X Ǥ6R֟Pl&fxRKFǾ;!/S.s0>ښFF{p|ؚInj'}'Č93ݍH]̞_XC41?_xײī֯蛄f|x=w`[!_ްz[H|OՉ䈴f >OT,MtC b~^ZF=6Ϝx axƛ4rX'FBd)g!1Ur{m&#Rs"@z;0϶v۰Кc=9oZf^oQ/motׄKH~/?*|!ݔ%`ԦJNݠ^B 9Rvg XĖ=QDq$!CqqG'Auî/ܵu)Ꮇ3Bc@NzDtYyF;/!vQ^X=}tڭ @$clWBղ)OF1+#rx д T-K.t# jS8\)4(w9y&rbլDy{/Hr.sJ\taŬIiKVUqL""R~6'ۏ`x~uA+ߘsٝm*DwΥBnNV"ǾͮO; %3 ¥03]UrIJkLM3|-v}nP9DmHA]gI^F9aaDJǪ*4ij zvf-tHEMJt[R±Ȼ5dIݙ%M?o=&h4UDL᧵Az\:mfF,1v*7RDe!66մ*ҬܪgEC|gzs$<@@hkC/uqWYӜ<66agDd" 69ez@0{.jLW¿Q0Q;.9Hu{zbYWrKGW9W^7u| r7û-`SKBe|Øh/Yӟ5=(g/E̵k% sq &碧ErTw׫(j) =;w;|0<k挃Sr }0~e.CPmŸ$-atO @x몟3`u礛[m^TmNнm< ;#dCnQ "_hg ̎hH e*ژ[6f]|IP0dolIsuj^]S=rT+FJ;bJ{U5g v1JK5d'ޑMWP "l~&Qd#_C爰PDbF"`1*"QEAT}o)4{Ъ<X.h])SvDx^a3)$WNZM:&=!l]uU|t~Oܿp0nks_Wrg~#-^yA{,K'(M֖N'MBq,s9,ȹC(hIt~n6RaJc^/f\3/DYQ[(%d5W ׎}p'U{jR`H 3J>m{#)NDGE<3L,ES۞iv΍6穱A؎uVœ҈N748QD6cV+U>x 릝01YɻgG\$a}qoO>o>)H'ѮV-uuHUzUؿYJ`+?E 7EQ{=yWߚo/ x4՟}+?^T@akA #Oݿye&/Yu Z7E<iE~|1I3Ҫ%7"oӺ)< mDUҦzsz.<YzxmD]R(*|f9J6}cFn5ocS.E/9^g{nM\})!$Z9|z冀XELijj; Z;]C/li-Odz$0-?xO1%ώ;>8&z׭hRWgK\>kAm]=)yw]*xz~-HRfrZw ^fTjN^/SL#Ǘp> } x˘Oqy5 I=4oj5S2J;H ri+,rV.x /[7Զ!6so3vSIe}y|uբJvϸ+f*ߛ+sϞg;oR(Y<{doYDDST5~gΚyO>*P"կ|"W|>2eiNLC\Z# 6x^z':nѫ׏H: f.߫H%guƖ;~'O[g^uxyT:jOML4} n T)憬 [6Wd{,7;_qۅ M$NCUmI&a2B "mE^ޮ|}JwOMڞϵdلyN{UK xLs6C'aLRN]O-p,+\Z^: _J+\ݧ(oMq;[ZjV'bV^+wsQSSbVwbsܑ{t\vzftiR:" k* Ă36hy!ڛԮpZ1XdF3"s$8tr Ꞧ>c3&h1%%C4 ՑA;R;R˛arM@]8oo>[K,=%IVܪ:^n||Nȗn5q S?$WpYm%U5[P ?N4>9*CqOED&Rba4']0i^qO *X{3 RUٯ-/:qvAak%C .7Ӱ@ԉ+'$ }}GEl\/L3fuk[D lc}mN @>U:>VCnlQlt }Cѻ>VS|"" ya6%{~55ljZzxM8 G4~e\u0݂A=jw> @x}67CլG ojRx[I]a49RTOI/(AD%9N]UXW)G#"w;:ޭXwކy%dI<ҕDm.cu9)6zcltf;1u_31 tX&! I^8ެ4ztiwlwzo.5_QZZLkOZ疵s;c1#nڋkW.oyiv;~{ut[4NtYQ{2,{Ͱȁjz1^b"Irb\k;5 РPh@205Wi9~jpĞlM^'uR݀[\vNe|{sU^g}|A^iTiN'x<Ch'^e١]EJ2" .*.Ԫl}u1x<ҢťuwkM_f'NWRߙ^+tM/%&j7dlG\bA{Z͗jbp(tRT>5$nٞ220C[ZCqg,WGw<ѩe- Gm8 DxF^0QD>xc h7X0@ < &[4KȽkIyl /5Kfppu'ߧ@iȰכR& 2Q&dFv]˝d)u9SZGI?=ux1u,-2T &sd-p$Cag@9.+ޚjqr2" 7l'kSਫ FVbKVJK)O6Iu8})1hK/Nkss\xZBJz.=·[a#Ns=($je@;)JrVĒ;zV,-ʳРڪ=R:^ъ;RrXhyٔ>J~3:!2Eeڊml{8F*DD00pǁ&h4]5g|N_^*ƹhbS1I[Hr1@k(:3^UcJ9墜[ZNU|aRMѯĬlj}Vs<<68\zIkL0V%R,@[M:JL5Ҵ~^ j͍pvth@DbZi]i4mljўͦ(hgj1 yScnIX)韤mڵ 'aTE,IusK^ EdWN\K榝$݄ YX< zdD1IC~$3T'd"q"tO'CUyQ4g_cZ#^-IBfaܕ$]\7=W$HJ凎N;A/0GɃDh#4εe7 c╕AM1Fek[Ǔ٘vrݠ*V8w*UUbLxUw#zdM*m֑ŵ<5~*̻B.zޭ=~/B? ꊭ:L[{W7OYyo9'[|J=ߖG̎^FKtBg)g߯CO=Ykạy@I8_8,;Y/X׼[S}՗*&H]0ծ/vQӡX!R8&jxT91hӽ*m÷3ZSgt%V&o@V[*&nֆD6}?JUIa)w1`y=3j61^B" d,Lju&O@ٞ:f\O~~r){["}呂"VImgt 7c֭{[?C/oRyzLnkL-ן:l2kU;ѻa~fS-}J%l'\tZʠ>O,']yj8IEkI HޫJ+xيVOp^|Z^m=/9)a>RML=]δalK*U,L"+) VXJ=.G6h{ȁJ@K =r{^b;X2rQ)Qj.1f%嬬dkQ&P=;#쁢!oS)*g+=)>a\4N3wRܫS7ͷy^SU$6]mPi%|]V6 \II9Uԩ&IrFQʹv(vΒ(Q*]+a>T^Q(4ٕKJ=S\jBBNI,Z}A?)CͼT|YrN@"m9k3/e6& @G\$w=2< ̈Pc⬒v\RxkaQ%A|{#ndrsH3-M"zɥVńyK0,T89UWlPiW+rks$H3йg2 -)d/H-zH2;pyG/Y8Qܲ\!1p u=.}|THlcΒ:<ҶѦI$Pڲ|bǕn;5tm^sЄm"@dD0sF(!'f::GQ%`I^x{) r^bUW8Ţ/Ca3p$x&!i.dEH26ej92֛k^L;JWTuij4ڴKJnq:hk9KWO;M-7MOqTf/j(mKa_Q'9U{"s8DW)55(eawhw;fKZ=*0{\-ҖNbi䢆tp=J[WOt-Z\j,XENd;\o1 >eITTsY@:|ls3SlddI297[mV%o3(_N my7PV~Ǘ 0n rs]QnYx$U{r0CX҉`%&'pw2N$ӽ EC@ܒ)-7h@:!w1| >+¥ȮbUŨmIÖ!>CFg^zj%V()7_=Q>9w<?\boa8 XOF~ez +(ic Ed?wBbT|G?K~4"mzRP֥g׿mS 4Ȥ쌶NUsV b^h^o F/ۮ'q2"U([YRy9Wo\*Q½{":@pś8c:=xjrgT2*((^8]Eg|usۅ'R͓oPn|>܉g9UCۦk&#;;˲8P/qD3 rf*)xy4r>.˝? Iƨq@s^OVj3upq;tBAz+K',N=6PD1G1!7'2BdǀU|@XJ&[ΣL2Ed+fqXC7hşzb[,2|'lbv@S+',(V\UTۼ[%Rd1H}{j<)PdPsxRȡ5[Add$h OՖu RQ TO"}t_oP+.˳5p$bFq'Va#PSB|/b5*2"\PS@$ HefFVXiTICEKKb! %0viB*jhŀ (̠(D"̖)1% VT ѐ'L*od9& |)4aB 6NO p4Kb* 1'k 3@<\{%#PZ.mmKʪ$Q"MYP`E 6d "A@,(nR)X,DGr.`&p\AN9)$D@쒄 V1AG$堄02N5(x'VJ IHWR dC H(y?~#Jb})ۥAZai$?&^dz"ReF!~tvɯw&YMo.;zmu ~9cer(Bu$~>JS菥B7)W#xgb涜nG;wcuӇc c>_ˆeY/Eߘp2 3_ jf+g#%I\V-rK. ]g6J噝BCUv qvUC>Ž򗐽 u;:b\g@j1n>DDQOwAr|A! PDADFJXM0>_S_^D-pA~hB+=㔏4QOtK4g^:S}~^!փQ$zE8{ =3/𛟖mjxus$q?'\l؂t_t <,a͏m~L@DN.s;'a5z8ȹo\{ݝծYu|zYqKٚӗ,Ůxee:*x!8).FkOF/kQ|VK`*jPV6l%FR;e5=ffgir; 8' b@GNDQ 8E8`Btd14X *AЅ"#5F).59:*?EU[BXۆAu'`]{A~aDavt?VfOm6Xa\c3x DQG_a $@h EP("?jYRxfH8t߳h^Fa F}f~︞"]vn~ ң DU+@?>0g!;Km)JϒkeM5A jy/_PD_\*0&Ǒ !g 6*<"(5s ,"T^BdӋ9}Tv_otxg|Ȭr?N:Я~n~)Gsm4b*VRy"*;D(?H'֢ȿ,"D6{JUC"^(\b+S w-B￉5\QX:s۟W$$IP 0Š "Jd9E>k4AgKIs+1BWo9`] J '4*Vm/  R?wʊKQ%~*'{=jqQ<2K1"xXc鉉LOfzW Ta=1Tz}a C!@@?_lpp-yѼr%ܡڠ@řZz]osio.M!S&)x2H!KD`q Y3@;Dª.~Sze?xf 'QH@C۫TgYx6(\/d{ۨdy\)v0pSmCruLgUޏIoRˈngsmYVC薻!ٙYPx1@M))(_v60Kl;>v06DN>37;>b6B{/ !KjEDC7Cy;'1N:yK*/C?{*[&Uk Z zU gQqBTSpL0s8`}sv]WTg7J59iLp ?|,E3N~/vQ1?}*Px7O>%mw: Lk=. ÑOl5/ V2H/0? ؔ(롑Wj4m `cx71xwalDhF}D柴@yxsⅨ"tңYQJyiujU*(K@x);0!T7* :29 b `RXX*7 T&Tj=Gަ>xܤ!;~E:?T]H4%(+r4wA, 8N_%gm2K@6d3wC @`mG(ЄO:z)ǒͭT&FQ"vWrѨhX!@ t`]lḿ{5fZM48q$֨cPXˡۡMĤ] }$ OJ'/"8#ݜ~2]VGE>: =|SVփ08CCy>˩R+^i?|<<^ G9PnĒvwBBBw̏INcU_=vZǀ ~ZCj9MI5c˷y 2Uo9Npyq158{# SQb;_}-tl+Xr<Ǟl xE'Pe!f<; c "p$clI,P;s Dgøs5@o.$xẩEl(G = @Bƅm:LEI$qH7ܝ8 5`\ 71?U x8t07-nFBQ3 ;1蘍ޞTJ`ǯbp1uFʬsK[: p_C|_ IgT13=VQK}]T72DI2-f/)h0.Y&dڜ"`#2|;ࡩ\ĀkjP]LᑚF  "C܈yP'G Yz\ =Aį[w֏Dx ~! &qo~2n}$tN@$3 v*_GIdLvs4F0C+%7ESILFP9(@n)5 qX7xx(5Lbf.,z{" u 9ga$R AcozaEx& ;ΊgE) S|[Haz%iSSL9n5ݬ0 t :bP*I^¦I6=78,>M}d.ynK.J݀q`Q .vb r x\ni#4t؅<A nSFpWF`gtFC;U3ݭ#RTt-Q]@Dfs`h!d j ~'Bb?Q94 M0nHQ])LR09(Dn;pI׬'R=%/: iT4 @Noo.0+_è~?Ch8ܑ7Rx]{5O"NǼhH/ePeJ+(ٻ E(? oH8br8u@nc$O՞0!PqԞh*9*7PP^x!Qx8!! )5!"c[PFUb%~̞YlIJ٢%`aOzf1yJ%,90oX YL10|:d*VT!)i>ӀP .)ʝPM0TT͚OA|1s{{|}P6l`;NJH**j+3ݦᓄ$bT (&7(8!r6X̥ڒf^d:ܒTS are/q>gwJy ?'Ͼ,`#g:٣jI$QQO"I!\\X/=Ѧʾ9Re?p=xoO]< C)C(CbȪ%y_;N/u2|J-p4ʐ)&%pĜ2 1dL EKQB5b; \0GB3A>vV“+lB>?'EcvHQ,aC 6^hЛ\?`K<5` v*J'"$Q9 ZA3S PTZL>S|L >t 4IȒT8NUA>dk|&ՠ>F}etyᝀ&8 ȸlG|p{ӕ>AC @CJu#Pt"Gmy Po^ҜSőYAb5& oJ=y7_&R3FP/E 'FE̘@PC*t:/Ur HI2_\_mrq[Á<;-&npzjYsmoU,*kŘq<oV؋ ՠj(};qz,s ;$yڊWnHb#AhhD5hGyGըjN4|_wٍA!'J{eD!@{\BU2 5R=A^"Q`rUaTiTpæs1LЂ6 c1j1c1Hc1bF1c1c1Ƒ)1b٫nF7C`?z2;pⷽXm{iC ت@(A@?UX:D9}?֯S0u1,mcxЛLEtw yԁŰ̓nc].2=SOS0 SXo* b*ٻbtpiXx4mD׎ׅ=ERJD1]HMg3~}C+0X6'??6f+K =ngU9R?`0$T"OyIۻ؏"nP0C/\%͙PKj5)k?@p ÄPTXSַϫGQhnD?G O7I&!@YZuETB|c/\SS6>3<]3Ug jTb#(9e ~y_$Ua,(?IMYJJ(rqnX?zLIgvY]h!JN EMX,X+\џ_u;1U=PDAT("(2(ȁ%A@=9fY{%)J'I֦Q[th~ȈR `Mϒ{PXΠz6=EHyK"MJ>.{bռʎu ݄SbآA4ܫ̔94u 8A0r3--6dѬ݁4NM. Ue#,~Gf3,A#ب P !Av֫}Tg8tB1c0c 0`<8^e o6+vkE= "$@Dc 2@AY!ddD"H" a!hڼ}W\{@SH]U0m`iΞ+v+h}D7;.F6 [)LNd;-%J QCh>.qZt({D("MZZE#ڰ&gU)6@tP3UC؇~AG'M`4`<q2PN~xT~ߓxOI,ȉiFcsr+ >V4Bgshsx|w3?d`JPzA PbP'W+a^~8UXYQ HfR5V-Tdx;*R2vh'>O<@2'"R85]g/?~xt3͐d:UUWh6eswjl9 B x50IJ0?>砟Ż_鍒s(m3 F fMM РapcNNۣaDFn'SuEI Y,*6'.7JԳLY!$u: ^/~)iRe6)_{6WGN"T뱳aAh*PJT@9o%Mꉫz1GOIvX -ӡ7̲C`@#sDž@1P01DԄ*QsbQ]K{`qoC3LUBPs hѦ\4snB"2Lߖ:6{!IDns5[Ѝ#rw^)O2twhERx'Xovd;P3+vv~_s2v:jr H4(&fkFh"^KK "M#*Us4Hf@R'1TN_`],=H{vOhx`Kd 8Ί#(QMW]PԱD2h B(2E | :6(`KmXA$VE2Ⱥ8<:H&-C^n}Px_v Xڎ?i !ANR?HPu^|v(}/[oPRæ> (|k,{\E[ɺM$#TyΚ Ӧ_Y-$>Q(=ةab|/RH3YEXA"#$  m aͣP>/K0o R!`?p=nAݓD6=v"|5=[O`B|+?Nb=$Բ?Imc,BTE3֌RE "?*i PQ}.z w[vv'H> 0 PP\C\}TT,(!Y T~fɑr68ҁHmUP\dZba \E.s±4Ց|Tp,$0TAG lF @) dBEp!2ekRP!D g:sJ?!3uE (_RG.HD"Ŕ%ț5;ҼKۓsN!,ΗA(Vy3 MuAR@%ՁAMJ$U>(D(4"JaT p!rF5Ide@'@Išn=NS$ddxUXjiYLb/Ǣ)?+K5Pm)Y@ȘT) *nj1C%hinalb)Ae@NO?d`}\_V? < r!sӰj}&%u?"FdNi௾y!_'|V_Hcq$\ J>](SߊNۇE'~EЄXWyj43n]SagROhɖRKɆ iO(L <._-P iCy]ϗMHj ʀ3Ui$Hp2PVbD<'.}}o?Iy{!K*w}R1e|ig1oos4"g|b3| qC@k&"<ͨ|ʍ3ɝZg M6 VU̅7)z,e N®ߩMU$?e4ݼ > le7&XGSoíږbI!8kDLIh;Yab)p BKШOip(2μ'LR219|'dz+?I^=2 ]78cA G=;yhSvc*%J0HA$'">dB= =~FVkSrz&DPJSw;A9ਈx M!G+zrQHP Z]KZs(%٤j6~e̦pg)ltt[d Fp8ms VQ sxb%$fv!!Y"yF1vCLFk/F5]P+AzaJ6UW43yE͇g^af(& X$}M 0t*&gKc8謷 Uk7?%4;xNRE8*F  V LhTBA278d.2463yt͌3Em˾FCeANGK,`4:S0oTRz1Ns~PNq-'v ܉qEr!@gEa^' ;yB>yqa:;у*D8Яnӹ zl849Fx RL} c{m &Q D jxsgv86 {f'gm!@C!$>ɁR Nj ^̃MQ$f,N'oǠv#6( {U!ƍ(r`|a[&K6PNlL%IH\7p[T:;=~~]hB%>Yv;20$[(s҈/7T;"hP|-=>~H{5AAEX* +"~cėSk`5z_F5(m y|i-*sk?g7ʬ~AC49@Yi!,q#b^IAԚA /Fkm;u7MރShy|;A䂿mf~ߤ'bs[qB?V"!rX/'Pwo('C}&Q8esol u2!6kmsz311=Z(R?dHE"ɐ23ši1]")$4]P9*zwc<e:9py0b6xp B$c$1Z5pC[m\ˁyb#a8/p< (Nba>p]Ƣ ! 7ANb;@<3AS9=0Ytb*"?4IYL_dt 1(z>|=""D} :-2SNjY+xl*) J7%G=۬*DA)4)ǁN1z Gx> b.Q#HXš])/U%A Buwv.2J>ӕVofROW}mߍ'jOF(Uk* 0ns"0B@ !y{60ӱꔊPs! .~l.-LM]&Dh.je@Ó e.uPW4z@ff!CTPIq$| AGFv櫸,: owcO9 \8=hH7uidi+'phPކ7da }y k[,9Ιq ܨC[ ۡguE MZwef(:& 3v9yb|*/[UGH>h}‘7Ͷ4:,Ԁmwҟ(UI#c aB'zhV-!8 ] ~O4tk~챑F@SAAD q*}a%,DD9* ׳C [`0H0"XA 2D@ȑly1͜s(]iI(a8l= g(#b~0 Oԕt'BѠa PPO}_o z0!20Gg0D_n'=W|wnVJI΁>o} Y. [iNaϸDN+W4)wdKb~HX#C3l5,:jL mzC(*uQB!bbD#1XǏ|ý%d꩙HGݑ44?0 @h ''j. g &w>\}ڢ,hUX@T`ԸǐFA FG; / 66_Ɨ6aL*J!RQ$DsAB2|0W#-sz_F]Y &xdb1F"F#ZxŽ,;n޳D2.ڃ<ӡRtyîy\bA/_WnXJ-u]}'[v -A>h|?" xOx7is|?!;\G;v5'>_|C>F48c֚~V1͡X?}Ɲ 'v4Pxgg*9F ?rY='SY #rkިU7 e@_bkT> T~뱟?Ғ|tP$ ?I<;s Nw)*x([X쿼|99̬Õ ]fCϯ ui:+5Ik) ϥB$POax! 3sI19-h]X S%KUҮD_'SУmBVfɛ~g9N{l ?TV**{pLom4's欂S8.۞K$9U^;SWbǍ|j%=HXMM:*mNC敕z /m0?bO}O{9[L 3,La~ӘLk(iw 9 O|7y!] Hɯg˚=,s!(;B緐AzΟ _WmjC>kSv,{,S\s=P=30|x:N*"lܝ;s!B/jÝY=f-+of{`-,0b~cٳ/lj2=q TO_oo:fwk4&=d$QI2*uIGh Z@S+L8)9'04aA Ø&nlpR0M3SCS ^$0]:?Jx2m4]2~_(ԋp_] *vQ)}H ~9ޏ/'\S.`m2p`}P F=8#1zd@KL 0M@;iYe'~8*X=emX* %a5OE 1Y,qY?X\c(0ܨ? :?@!94C7Cnh(n4>Y'q{|n*vԠsΡ'4=d#:LFiV?A=fG~8Avhts/NTexM>LӊĢv#^+mWf799 w < ت 4sW/ C'"" !; 4v4NMAoN-R8"""˵8aY`/N:l<怬Y Sb'͒ $Caإ+xO40*{gek#g7h3@?ky=NswdZUK8&bAUT\LKn:?w)WK.ۂ $fi* ɗ3 3@4*'er:Q@1XªъN*rex<쩅}Ge=){ Pg*eٵv#"ߴ96<,|CFH@d  01 2! ˓ꠁ'pqϚkET5X~15)-h>,X{q.3V$HUfLE W25t+(ea *oC0nCEOwp;GLvࢨ! r[ u%PLi@G= KF3|Lv,QB9:|I}Pfp540ɚã*b %ڞo2xW'¹[`Z|[iS b/b НfsBILj}B֦8_u4EVJersLlB(Krd^`&2t63/Pohs4љ=H緐tp  %AJZ C7GiZRnzxO{~; Qk;C1}QWsN7ggIr-U$J-ѧ] M{gz^brB=Mޚ?n60w^5et۞Թ\-n |0:P]=RFꮘ`[8V"m{u:&f@aB* $CGSiMq/nw^΃My?Uwy,ǚ9C  :K<] AҴKM]LL<9ܪpyrf7b]3/Xqg`:s/L,-WU a Li@NPMgjvLՍh =3xzಱa Q6݊9XEH(Lvh?tKiv*y ݌QVގW9@!kʗġ jT+IUj) tA0km*BƁ yy{3%AL*+`:Ά@߂%T-`ėS]j zy;s`sFD9N=M̎S ra(-s0C!|KG }bN5:z'_v˕L  WJ}mx׾I \Ʃ|cc(z@ X"#]WbWt\i;5yTw7-Z[^@䃸JyNc2@}C$lA~ I tn9FEBT> rTrB8`PE h$DTTTdS93}ѡaE(@.~AEW*#TAc7?D{_ͿOZRL`!&N U}|@K0=U(@FePBV>(X@`|'&|eD:4`n;Js҉PPT9lY*/0ȋpO|jBҡ_d+Bi 숕ΘazHy[};r/MX dI'r%4Hp+hXh7܎] ԡݝc;{elޮu7E;ÑtB E7(@kRIbֵmMݰ3Ӵ%&,pXBjcLumG`B=*dVd@+Φc6h@9Ehqg3<=h-Nn']݈m xKQz}Л,@ S^O~Fo JJFЫ@s]$~q}GEIBԓƛn`pȧU6 -$FA[8 I$4T*"`9,3ϰN3x WdpG^Ϛ&ĴM5~-@Z\"A?dxkm\=Nʶ T ,EJ P"dJkj{}Cwox2'6,J'I+O njҩ @x)%r*oB+&*$鞁_BƁtP06t,ASQUfL %_'1$N%FtDR `\ZPDv/*D͞VbH$"4v,g`I!&[{?!޺.ݜ:=TT! n:R:@ʯȺ' w@| qʚ'Y kG5[n4'~[E2L N @^=gh$y>G j Z_խC;s3cF|s$!$ZJ$UHG32FʚpFJz']NnO^>h6>%Riכd h@Tae҂+*3C*}?VZɅ k+@!}“m>a9w1W &DNkZ ocrP$jDC@Wy6vs$I$b闙׆2#Q'7i"8 ,)P% utR g-ɋ9Ug]Y\\VT nZ V(ᴔELzGq(z3u\+ alFFgNxW+80ySI b-~&>-??|Yb tX 6i}ٚt9H{1 7[ A? Ȫ ]Xq`<>\6<"U3ȧ݀C،!.y:]89lpYM*%#} Κ`ݙg-I$+#ڍD[P6ьp]5Qf:q͞jHhqj9$ۼkA0\ÞbKYik 1BґMJB~Kt=8cɧ+wUAV!"EX+oQͰ_#+܍E^ud~u!DGng|$T0Z" ?9J#iDX@FЁ}Q , i0bEzO_R?_ѾߤR5U! ݻ7\O{Oy7jORe[*ӓW~Rqs ]}8HHe`4䶅0ϻv~'Nm1}5BhB#QV\SY|ԭMuT*1;[,qN'O*a^$c(z}N^/]XD "oZE]4KK^K;J}oZUV%tiRrjRuG`w'Wԫ ?zѼJYwri@H$O1{: ߤ{SbBq_F+6tGPs" A9}?)`*mKd?;ћl`hu@k XHwd]pDd(7cgX|/9Y' `mzY>,] o11>%] Rk,xN(C_& s3!"PdJei -Czv3OЃ .:$pz byÔ=`u?H b: 9d½B6Idlj$l6, K-{욚DqCiwz'TTC0xߒW'B+ $W0g9/siKQ8!3XFa ̯rO 펔veܭ[iL&P ԤUh۴mC'젪ʵfTUuJ;($ɠiCrJn!ס5  *** V`лL 9Q"@a"bHDL"M% 46$Y *AQa" 0ض]R]Buu'oX͢kZ=TٷUї|k>3QF#Eu.'#RxX7:bWH y2 bBnT嫼i9KZG2z75y9p@Om]ڝ^b 8W✑/s޺i]/;aGB6TMfWbgzgqd9VIںs56ʢ{mZwwwKE溣vЩ{nX7WNh|m]j%K*r|Xg K.YhNhif/3~#BkJ%:uu:-9TV:fd*.tjҔh/dljc[͝O Qn{J\k\7S-tWIG]zbw1<# K%\wnQ=qKR2D` }}'lY.W_&JtuҴ+f$\Ҳ1w zyݖc'_(Np H@ ~˰Xq<'VA.7/A_׶1,OG  o7sjN7]/5sUt21kᖔ||oxLYm`Nuޭ*"ɐ- t^ !-0y"_[]=cEa;q]VXuȅS H^u-|Tlt;rSCd~cbun&m$B`DS#55[jί{{!'gi-"Gvf멁2F$?j2 ˫^ME0mh҅iEs~;`nm[91P>ܭw# 'w5E!fH%hĿnWa!F|DԒ*WA@) 7Zs ?_IRyij#Zi3.}(FӢJE٭+/:i>Ģ@=}ULܓSD `eFFAR #@E[ 2 @@br%Ҿk\>䁂&`E`Aw<$D.}H'x1dnT9E:z/Fۊ"V)&-FU!0 FXgxgx/"eTNp<<_Yv9_'% > :"a+$9R1V& xV 80P sHR @-ҟxǪqU1Xqh&=/Kuah bRN8#}q MÓB aERDk 05#4[Kb d] G '|sAMZW;|Oȣ.J%&$Sh&5ߏ~6Åjb"(Fbÿ\>$T@X g"|$$^8!PoU"ZBr{7qm;nM)$_\ɥ6SEV*ZYP-kk%Q;r6+sH00a!e4DF͐-kI-!`EVۑ{uYVU; e0ݚvJv} Cd7wy$P,@HHh`K3 :m/F"Ym$w^!wK1;rm, @ ؃X E|FuX@5![pO8i=rw)ߞ~^HccC^Ex@ qʺ%uk/{HM%2ܼ[78)\VΪK.i26~'I[ kz  ;H7`,lSZ`ܵ涹h<"*`h~2@g*T ~b( 0;h[- pr֐ DW3H)DX͈-)\pg)KFҴHmލ<;iOS?M/wNM"RĵvvBO''<O?{Ǎtě_>iOkNY&|^jsI|իLeVW[4U%Rjq;YV];fpyI6'.?9VmCܰM*KF5)\hȦ65I k,V:5:FontԴDTezM{H@*΋w+5*eƱ11blVfYZ"5N+[&g:FHvzi|Y&$v?r'ƖlVYΆq4/hVնoDimg,7VQLk]ORkR_uMJ`ѥv֝ [V֟R][JKRԲOն#S64I:8lԚu:ϥRR,iyz2Di;Zj;PSnviZ5Vͯٱr5˜nbCJP!0P!߷qG !F:|©q^h Q`$X DH~ʸwc-(ՃIfן k dd yGxw:"kC, 8@]ҩ d}09BHL|ke;na>*ȏA4Pb!L^1A0}S3#1cB|QѠ]~%hTaGmm>x;"sd(65_Q}z$\"/%;gC,gBN'L4@TUk2"( mS'~^u8Dt(n{?R"ݿjSzŞ 'XgXQwgKalЄ.գ[w" C2xw$mwd]MSH 5js'Q=ݕu;{y?͘8Fzޯ9Nk(vGRɨ~ʈdv-ؕpUB(vCDLnSn}.(˥< Y6v2 -֦=9WztW7˰!CB:@;So"<+! :F" \:8dn* ϖBhyАA>cH?^|\w$a7;(K+.#v*֛ZsO6%, hٞH|Vo{ެ]hY#˘]2h)r1䩑,Dby*,Px{䞟iTCO=Uy|Ti?v$^ iJ;|㻔h1b:[K~;:)]SoVe|<;x_<6Bt&ޛ#0M_{ț ?EV#ކ"oOЦʅ dSͦ)vBhô)x;w> gg٬2bMТoi0fɭ€d&%H"@%tY1~Src9ik!X! Tvmơ!$RTnҮ" Rtc_}89r{ H?t\E>Do R§ð"2|{׀scLg4@zP,Qp_:0OՐ:} l1'qzF wٜؔaUNѴ3͚P`9/2+H{I{vN9;nOsi~7x6xC7ԇwд D!I (dq$a->%Q?6t.&n9s B;oPiq̈v`snL*j)ϟmP9!NY{opB%N]<*% 9 HAnvl!T -l U>n#!68uy'n?9d;Gߣ^_| ph(&Y  M{bBhCfQYaBREM@ kH* p@}υYw`נC ޒt ~\D#D)E1當9Ww73GXԨƗ!HuHwe0:yaȖ;w\p&CBa0)vmم%q+bS iQeD-om37 !P+ >d4-q]@횒H't֝›[*F5ÜZFd iͅ XTBԱL. Z鱚1 t &}uvhCZPґGW1jPN@*IY-ʢ]\PMd{aa"0ʂq!!l婮[h\C|M ĺMUZ!fdvO7T/?XBl=݄AexFVNK7k-pn>^wʚ@2(yK\]k[֡V h {AU0\@u/6A/@Z(h{|:'ǧ_@Ϝ*u ?$i}ESHVb9k3m鐂ɱ&6ʩC|,"*qDD"C OPN|_$E@rFbfG3eԱT̾R? G]Q76ƭ/Cw|Xez괫3[mvONwE𪊹↋V.eҨ[u Q󿑞-Ԧ1Qg}s43[x.Hߠhv:cjV猘d;K~_{Vi>1n-zU(@VigZt<=GH)>S%Zxi:W-|_v1$6LiMk8kz l^F+:=F2k)\rR犥SQ3vxeXc1X{Xkjiz;0+muJ< H4(bqVs 8)ѐe! FRHWdg) KVޛEpl{7sWnZk9di{ NYSØ:\2!g"\ZSFYtNZ; nk`C E04-tQ"QmUe$Hryv"*&k>>3ᯐÏ$iJTF&sl`d\ NU}7@-tjvfC}{ED1WQ͈s{@`یgA냶");vWw/lüίg0[GӖf4sEiS%**#,v2PbQ`) s"3BK j=Db/`u!{t~dP }zOn2R+IDiB1,dZ0A$Qd{z2hR0?J0x!B*1vE#jY љBBul]5\"yC3;}iw1MD<:aӹ!#% օ Zp!LC٠ܛ "DbZڇθ#Zać7FKK찟Om 'l?J­Ƒ)eˑMئE0{@AG__==N"zL9Ufg90*QOK=q6,kDtf  ""'e{$WbAβ͘^M  rIW"0F)`.PЛl΢'$IGQ @S?!"ph[KJH`w_|52<Yvcl]t j2HtN#"evLgڕS[ Ɉ@ P`sae[N ר!߼:90w^f[wm :+=lJ>w{`.\ [QAJLXpHbTAqvdIO9퀢iCfDIW/!:ߑ x (RW.مS*y@՘j)7uH H {P5rq~X#U 4V~>* X@0Ï.2#0 2"b(T^QS!:m:anҕq#O 0d;: &sxN=^]4:>c·phj*jk2s!"{T0'(G15DU{_"F5,= 2@Ѵ**tp;N|TM_u5z<ܑw<_eP>\ffdiLmf^  HJ 1  GmOVPsg;=/8ُP@=qT7C* s&:|N+i( f%)d\ϳD!>wC2!`D0A8A SY(}|/O'٫6>Cj6G 5ijMX~>T:E-Yd`tڿ2rg(ĉȀ%S&J蔺⿮K$t8|~xV>M|u.%Ȉ%ATGsz=ƘlZ ޅa3m7 6f^ڂ$ǂGvDB*ëGv=0gaځ)╻0\"!6p̡sXMرquƲ] Rؖն3t43&4{0JaL%Ʈ=ɬZ>ݦH< D+FGV*EZMn]8s>$NFoA}XQ$r4 ڕn:H(`2cS#lz9V&5_҅.P|FeWL26(r;6aZ۲@p Ƭ. PHl5bnoqn/G}L}r3PRiAZ!%Je$,L2c,C9HWyjuAb^5C8CB"ߤ$2f!oe#7+@ǚ"gQ5 GLQ}M~%Y4D.Z|LB &B"o *cC jbbWr T#Dǟۊ!L\R.9- F0'bR>r)0 +t#H1pS0VՂ1h+Xl 286{ܻ#ɷņy b_Rh#q<2y`>dCyZ>=j4d%<繟+ucgbA qi) qgJiUm a1+qAQU7ٮxkcOFJc2fHdxL0,TmP`7#]Sm.XS0f(İPQiwb*o3KYiB@2n EhF J(m\)3+dt5iFPl,ki *7톳(ed@ԫLC;7Bݔ Q e0*SpP^s(p剓,9=4KEʊ.AWH5RTP;|'da.;>-u휳Ox g-t(ɕ*y T "-jA5-𸈴gs"p@`` u@'f4 d;L0vPD=\}=0JGMnTknkRhY7b au"@H"APClw'2Q6ljf-h hLHFjE $ՎH؉$jKi"_Q{G8H)|M Mpۢ vzfvJ}6 ©YLQrBbv4H y)YHV q}ҜzrQXf/IuxD:W114i;2gUA"3>7NOD"W:Gժ NY7KhОc<ŕ40XC$ߘjAu apBS8@2!Fvs1bPCf.~Xh^ ڜpdbD 9)QsANQ+[ KeZ*J恴r86̻7Nq7=Û')sv(mCyپ,QUUe85J<0p)ۧ8뫨q"~ 'j\[=4 uDSXr ;ǐ2HTP,^G12!"!}K./hf\\,`6/DHLwCMYnr"7s9H@]B"m.)j= 4ƈ#Q Jɾ*$pb#(AJ)5Kxớ/'+N,+G&wbL^G-US|o0PȜ2"vC kpt ;lPH4  )"B$$DM$QN"v&" t: PZ_s_;`aN#~*i{ҕOJէ ߆\k~wr-֭xݧY]r1t鬺92خCCeAgweyN56Tm20/5Y[~+_g9/ϷwIںy45Z(Z]tső3! Ds"qc]P3ʁj&f'>Yn )iƅ™a-{Q̠~&tɰ\\0U"AL#X H[dY࠸mT^laEo|"xbhEb%= ,PmE[Fŧ$"jEC M(`n1osM&6{ëdfT١9j}C7* 62B${{Fi~V~Km6Fյ:c1C3SjXod_r!oaTEl&6bF;?%gm76| T# ^KW̱BH!i=5*dkPᲯ E j%@:L"| 5!!D jc!NjYHIÔrM?*.Ʊtp)S]xHL6@>S28ż `@Eيŝ<F , hyW/KЗy$v,'D!xwMt@ 1'A4{v`sE]sC?O7:e=s,\BkT&XmX2 LqvP2D L WTz{;:pUڢH,A}zpCCiwz3ӛA7fP>UT‚N{14>uN VBf槣9:i<\?jE723"mI/'Z"( Wx !$ 0 MD5"A|n?/ym/U$R'B#v*(,DYDPT8 dm͕ H$"^q{/|aѠq>;wo?D_*v{Rj/[܌+i$F"9!dC(rKE$R0p=z)A !3V_ : Tu©rD  I:Ge}#E %E?o[sʲ$%"Wm(^M\8hQnj;{TN"598QHC aĈ2G}{NwD]oH3OC(NaR#0"$<dz򅃨{`# hESe}pYPFmΙ2@̻M۽FCqϑ@j@5M0cQwn06Tf+J[3" $S?o?|R|, Oғ9o= C*"/OvĻc 55vHP0ɅgF1v 7_Sgs0 U!^I(?~B ŁD1)T HHeak%m>.Ǡ`!)zWC;p̴^ہAn@!-"vn8~Mg: fh1R]onm6 0w&X!jR6|' Vǐ&!9,!t ݮVۋ;7{@Ќኚ :~<=CAީ''a3Ӵåa-RCz; ΅."*E @VyW&_ ؈^K8t`2( @:5dewI9`p!n56:e2౶r40P "A\SQ jQSd7B?%YO9B ߟe,+E]R0FF^u$= @ VCh7WQԭ Gef2D B'9cfՁv?>z0v&!P`a V1YϧQ;UqYj #@AWTȵtRvB&O"0hjYCMzfBM5%7 &J$ 7.d4l]sց44)h MN C$σ5a lDB%~AcnB͵CBA!dESmwϒ/=U b>uu]Q. Hm}9Fi0(kw$6``_&b"QlRQGz\6Wɼe{ "\3gP:L6Qko@$>DB 2  0d` $dn(DHO4U))H0Xw1==gӖ)IDeG H$>ex5R)-$df)/l-xjSh ˑl70ғ|*&e9VqG"&QtnibѴyapBEbV$T3h *,nzS;tQ/~f7$1IS  A i$K.t`G E@h^@z.`Z ' sr "}G0+G%$:`N+IR!s0z@p8UkE@!W D:ِ/T NJ (Ŝ^$ 3)YMiSnςE"a7m4/\$Z'.m<PM$lL) u<_h]D|>3I FO C gp\H3[u J!i#tnoXle~4GD$* |4f@:$K,:" Dqϼv .?Q e04M Ȼ33Oz ֬2Q/4۞FJY$86,5CkI.HZDü[AL=T!HTSjkh#8\"!=NjndDa?WYd DseCQ %5,!t͑Dcc.ċaETE$5 X9ŜZ,aɄQBȚ4( v+22dX @"N yD JJiZ LBIH,VӢL4KPP2$b%dA{@:#<w1;Um`CQ \(;^ EV1Lcpf)^+mECePF2`oR(iݔ"b3H)j$EbZ Q5WPXSW ( > E% )C$d$Haܹzh$¾*6҈S^Hq2 O @}{IΈ֤Ȇ&+f+8OD5*Ygr$ T}8OߑDVNw?.rVebI&جA xCP 㠖 9x``X\6\:xw}hFhPDk@{l4L-LxG@J*$(IdPrZ]>/wxݟsp1^8*eHrr L`x6݁F2NY@9_SbUW&P]C8@D$P4&a9`RT!% A't. nfBW<é}Ͻna  R2" B,Og fqG Hb9weD6wRbXm8f Xy` Mru1ű)<,31 2<OWmUԂ}ij{_+fT@ϝCްܕ{m'ʴxkpW"nNWkXB(U1JhEkxjh'kY&n ./,xND\0-5!N|4t^M.񊬖Ә{[墤DDPg Akn{=(-L6k{!uDJ˃Pi]WAlo2i::9 IrړPس]U\b)+a*PMⓇͦ3Hgm+[wVR`9co60+9vgIe"Uq5b\K4~9b%V]f&T]YuYD\κD|:ef<įq"0_FC !2 "] qOqI S~ }S$H^!a윐vNu@::h9NfjŌRGfGl~ǻk*Tz౮r\O|w$53[VGKW^d \6vgiT_AB6?􎃹BT׉Bkϋhٗ<)A *jvKIQt?틌Ͱ<; E':zmXR Uo )G=_(޴ʓ5go_ "?}36j$i˓QG&[!>q/-cZ}E_E3ml>Z){ā! bDxmǸ ~Y|T=bL4"}g/y'? w&*<4ӸF ~/pUj46-S*,`Q^倆tH,DFDE {vc Q1OL{o9±t"JfƓwH^} .^2VӮ(X=3 hP[vD  =><</E$` &(~8o%}֠N-ͻ)s͙p j/B@4D袍 rU{* v*)c7B@"0^?!#$HE%{tMoFCC٭&C5VJZhl@[ޤߘ"`r.pȸJ!~@/*Ϣ0Rk6~Pb$XlY(HJC&:zZ?Y]wO\TqhJ'eOR0ɮC(F)$ `8$Rt`{OcaYjr0 y:}Hb|aoA# \9zzueM(oxYe>zT̼o#Z_6߁*H&R0T!!)H:}:T$Gqqt<L+}^'mIJe788MGѐ |!)1/ xkgle@5 BsIW͇:K=.*}6< *fHaP}k/I;·NO)?dZqUSh=NhӡH[Hhs|Ex7P۸+aA=rE$K9kFڊcWمi.Nx`1 XRT3:CCۜɅYk['6mAHebQ%gx"{rѷ5aٿb6MY\; ӲBx2I*e䂄D#jCI Ԛ@A@<CXd0I Ku\P8a ܎tjؐXȼj牑 "8Y7adӸ+V̯䕎)V=]`xGpbޮ^[C7$Y!)Loe!^Z8PS!@8Ct]y4V2;1R@"I`a1ӲKrț}},=r'Ӂ/?bOI hJOb )>,'N!ѽ #L@"r11ouT|QvTD1 wjG.7k8jn]|9%d}a݊pItu>dƞNc{ذ3`EdDTfu ΍H wqy4uNT\"0N(4sŠ2)4x@<*H/@rQ`;GcPhZTWm[K3_]4(\vf(Y τDMI"b>;c vheD7H #9ee !MLZp/hIe{g~.if c=Z[aYJ;N Dpxp>f!mM^_`E´|  vI$.#w:Nj݊ T焼3^; q ˓-(a3!78˳'lC6xpnD-ߖQvu%P0ɐ9.2 _+ aTAlY]VnqMԟ2@ eꝽ(MȘ K.փVCHI& 8֣{27&gP@QHx ^q3=" +"*HjL!'`d,dc!$&eAd$UaBZ ~4!Rbʆ+( NمpXao-fE, - )m+Di##QU2"]apBʕl& aƶV*j&Y56j( Y&mPR >YvЎdgKrdu҆@⋊x4*,ţ8+(0Fq=h`⮜?^@t}/ =oښ !} H<}-ݑ"h0f1@$@/Db[R`7g"8 >VYZ`Eh<'.0UQ&DG0Io=9т`}Pm+j ұɑPX*ȓv_vכAB F ċ+bVă),Pc "DP T$QID H5A"Â(~O5a ~/u"&X,fEEDVD!:u>$(I{p7zpC!2}'wŢ#r$~:C8Ps5)qzwPbXp8o3 ét6fxB̛Pw $H $"EAdӅDۛxy}zxtSR,}|f3}KBJ3(s:NqjAFWjԱX(A"!R$P9IDBi sZj2WV1Q#RaԺEŵE5U-+U6мyI`EUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUW{/JN8pF{ WAX^-Z~[~oӁD'z=M ϝ-mL^_,!rU|٥A/DG%T"GP9x uQ}!p7xqPLf!Av/30ɁݖHۂ}es$ɹVF2 jco :?7@3 xʼVK\uydNu$81%5i̝qJ@OW@(P$f:d` O5Pa H,dՊ DZ* P0P "%HA$#(E`c$$ #I   !`)@0k& Шt Lc1E$s04t !2ܯii"T:C(5sitzac:X'Q!@Tq 3Bo)00a#g#6'h:RAD›z)t܉vz], s# Td;ffiU\zpa^Td Yl!#kNڂ,@~$a7<%tҝ$)/Ñ˴O'thpA a@%t8nt= 'dDSR-DO2߻ndd7@DilWAEEdd#'5_*'BHF!#/dHoQ>KTkad͒ZU+#@pqށÕ7zkqz9lS!˴˧q9̐ S gU'$" "ZM#@9HchTn'BY-Om*ʨ0,BHuUSmzw7Y&bј!S;bsA`DZy#PPSE f83Q3,I`i1"5CI E,#P P%[DZ`7b0 6fc E@6s9UȌ~:xl7׽9W R w Sm״m/ڝ!{#YUD9@BGh!FS^̜SC|T>~wP;6Ud"..-~OD@}i!$@a50g] ] -tfn}(d@\-1 G9 0a@b!$d.[IY ͪ >(D >BGT/ż'CVkE l bI)w>K `tPɀJvI$E$pLx .@/"cPE4PDŕ KpRs~j/?wAytidbB"Aa$X)XQHY"0G2H0>{l8= " Ik*?DQ'dRC1~B? }h4!\;7 ]ֿg|A "$bAbADi<$E*H(XȠ/0 ,,a5@T:"HM&<c )`UiIT7y:; `7Yg;&ET*yPFh q9-Uۻ?^zDpe_9z=p`8dPHP?Fj٫ ̠+ZͪE6W%( 2ـn/ۘ`LdհUR ()IAa)+ 7ٷMlyܺ:m٭&8.$<\86Tێ "H"I@:Ea ^L7@}^'׈5TKౄpjzŨ갠c\DiU>h%}6\ 5N iz=œ 0CfD_~`*ySAE'\_e@w7d*URӯlNnnU}RC OJ x`R |t!pȽ[.(I1*95;uxSM^tKnd75_ .yd (kG65+gGA !ILj.Q$o"$R~y5k󖡪mr3^ 0%? BTf`m\q:(eVNK~HN򪩦Veu'K]p%U@PfpzOQ; U.@q̨JGyáQE M 3G9W!${0R-$C2tHw CqXRi3wsw<p$Xŝh5 $($H) "U,d$#4¢9RYKHI U# "DY1d") UF rO$)? 1򞒚=BO@ ΰs5Ymܺ6Q^mh`8zkzPE @s><]0O^<&$1$$C@-POkИ_ZH&Kd|@RC[ bEPd 22Z"@*,$1F9-c )rȞhImׇN3!(Nz);[L@$$>o)Ȼ9mp~v+>Pr"Tqh5PVqf,r4Q)U'= \iXH iꈗ~3 +ZB(,pbTLp5gE Q#UR ER%#4H|wbO^$?i$SE Csf9a:v܍BC"L?`]xtgP$!R$#qx~4?^lGF/H=pN!Lk(LM}*>tGg('FRu6;$#pߥvAn6{1Q"c~n5% 'Ӿ֦ǂR  e!SDr0)"K h4k~3wVUx'fl(XRMi2[S"ʢcADE%.QU.2 b#ɠ9<[aa8dAX T#aH#Ia`Y5CLC;# k DMK9؉σI88hx:M,@6@ s bD"EXA@!hZ*5`l .KBrY;z{S۳G`h<~zEA(r>4ȈڽVBHX$o;:moY%)}PAI$Cz~$#ͩnQ1LA({< QCO[SRD1'dM0 aXEMvR<&YꉨpN7*X9=an( B87t]4 f(1ӉT `-\C-,ʐDݷ5A5\[pmFf]CGZx}gO59Ï$ rA 0OHdi3")$ vzyQ"9toIk$#{^'}n3:P`x2HV,$Ds(-gBNj5ɽ@Hn^&MGϘv#:lCwAos~x!Xz vjtl/iAB8GxD(2aRX,  L}h?LTRIןmpS(qu 9ցR=WPH1^'y"l(8fl F)Q`U_rѬ(i(zCMښJ5ouѫ-B5,?6 R, T="YWfmҘ Nʁ L(^L% J/&AmMd+Ӎd麁cd(CB%ǎQ 1N3DL5dm( =yrr"A[`l"EbH& @2T卶̕В2+L5BH(t H%`\8BM$2)X `0i5  ր1pYbh![b$f =B8wT+PX,9u--vg7(?մSX|!^u1lUA|a%>ky@%1G /}Y #dpE0EXS*.Q1/}&̍ (.30 8`d 5輧ܣQ|ʈ8Dxskvb`̙xNnsvH1תr G2ާ{rx<߯| &#*c[l>ެ!C}(qTlZO(ށPnBT׃lE5-eid-vT^V ԩr^&z{ywVH[!! `C\D/R &y^Fl*x%ՅM i@{"-`9s?VY$ _v7L/JmMaj%8Sf!m@f9~v`X{ @@Y@!L`&b1w̿ŮZԪiDIk 2Į;]f ⇅8s kY~ThfAK,e(j0S5 K#ilo(R }ցErxq%qLݹbv&!ꪻ06a:ex2B#*OX 5* ۞@gK2:emVĚaPŇҮB04~ 0% OhoQ cT ӠTi?\i.#59p/{H΅++8'=PM&Y=po#QSfpH &A4#3A_]Ο ڳ t(AVi"&{C?]HA@bxG2_~grM$5 U%h:][@K @kMR<Uw 7u8,P34G#ͥ<{@d>"F,00.UCp>uCG)x*Әi^#OhEDEަ>s` oԫ rZ8$FE.NV;mb6T!I$C-ai)zdFYd6 '"O3$ Ղb%k~l Id).J  nLug xf@F[-S:%(e*h4d4bL#K X ꪪD C8rT2:s`|a$ծ?82Ϡ9lv(y飛7AO!fZzH )"})  ;G0BEQBQ/,ٸz2 uv&C~5+A_ wV|._}7Nj>*x=PGy o-$P*AaVE%2%ŋ (v&HIDr>vףA5HEQw@ hSBHäƳn%D~tq`'DvXv!~Hh!ufNQHC!#l UK;1 QLSsQ\Hsܾ B@ZeUW dCiHt6f8,,&+l2 P#}]AL ^Fx1{ P$gk;KP-gxs5NO.t!p#Vc&@6ʢ:s9A8.j ]Y$,%;`8h݂R  )I=H?{j-5 (tD@"2Nny;L;B@VF  wiйM@?h-Ez>Jf9FKXpT a(4Q"DF'}!AU/YYQO}H~H)CQO f6D"y[PwAN 1V@Hv܆>[|HOɊ05 bT/BL/3$MzOم  VGg?]L6Z"V_ %BQaeG^~ O%&$dJ%"%#@%: 6&J%OIEo\j)3WEd&q ȇp`*k(3/I>@+;^5niw3Wh0 PٮN+g3CwпgNέ54`!咢%^IV̏/czS|0fA HsC`@8qI:뤮ZE0c qO sHX4ت1ppLR_֥&JyQdN-D^=ztsOCty,~a+Nf&ZLIgt<=23 #Цjśo2C?׏O?C6?o7W'g_Oޯu1Tw,E #"HI db~sd"0!BAdX%7.2*@(Ĭ5CC @b@c# @FQ*"(P"?X 1d&Fu1BJhZZi&cUD`h@F,C`"aFJP -(-"iKiAw-`!V@K)0$**dzŠzl۰[r6nB @}H71;YYme@d "Yf'`i`$#8M5 609=iQ b ``@WXIH @EY" &J(3777vU6`%ژf$bEP$ *Đ $XBԘ V@ddP--E E,\XYBRlL2ʖlKFDJBX2 Rml_Ae "z`Bb$ 8Z٘fkA-("eP;#b%1dU0@<2Tb:^*p?*F6烒VB-Cv vH`bq^0ac(ʌ^RWG 1("%Y qH#МR:&)F0Y2 Ebă B"sLHU@=#CI9AXeW;( :2nebY)l j  Pnbf(Dd:f R+NslJͨsDc, gHL4^xΨN1F~I)lɭšh\Dȉ!U#5x9ɲL.i3LUy^ fd iPˆ9Hp!9S5 =ZP)tPh;]y߸uPEI5!I4`U/xSGNQ6eCE3&Д9]&B2%Յ``lߵ:./D+,s`*H "L4 1Kt >Dr0qF0۴0m%E\9nbbzegY1]X&yT!DJ =fzB3giv 4`pPxP<Ќ J|WztqA 0 TSA#k!(` @Nb K2*("$Nrt XQ !`aD0|5=@|0z6jeKqe6Eg_^c''•@RlYfFk l/(EȺ.頱K"`$:i tb8mԻd`?8) Bi̖bT~S]a<(LC '绵QP!0!;HBNCb,Q}{!KN!'NQL1hKhsdt}J:OH{tH)<#b2ȋ$ ˯r#A`,1P'(Mȇ;.`r3r90sSbA8A#EHao-EHDv@KT@EHP> Ae ] 4Sq".Q%* a"B+:)v"RE!J[ \$0$@A@0r"+! &Tߜm !8dUH3! (n |BSB50sii +  Bl[g[$܏IG+$n` P0q~w= C ֵozW9|[TS8Hd  *IDUPs℀|+T CF~% t$r F4b@DXv$ Xf 2g Ԕݦ a͐ԌUbR0,FAv=`>];0wx (D 0_D !r;9=~),V :ȹ;a0#2fԪ'_{ 1 (-3M݃j;D 4 D"5䠤A?M(ʄ rƄ&9q`uDMHF*K8 &h =כ> У]=GDJI xp6겚`;MݟXE B {}I{=w!@WހQL]Y_1x!su/C$jjkQ7!==zu&Y)vq16,ui LPhY1$K)BCEIAN M#)$(OؼHPXA=]jf(h'$.Jzy_? ,?GKYVt7~§1=/zʸI~6a'Z\ur|; о+=!ŋB²l1AeE2kUy)3O*{vڿj: T@Y vN{Lnn|捊z^1ӖczMfq{a6w VuTyAC=4殟ue O Lזfb|ƨq/ JkSӗ]V"妖hexٮf1n ԠAauBq  LPߟ4N?,xkٖGE " mN~o&G6๩E& qr87` Sp:.қ6a +`ʊ+i`R챕Iʔ !J&cAm9!hİ#GO<Bt!w|l˞Q!6N-dK\Rw:#q 8]6$8kCa8-wV B`THB% /o>syF Iv"!,5XA/u>2?1Оn W?WS#VU^Zaǘ A#7!z?GwA,:)D }u†~(d$˘zSLCéĤ}\00F~<Aщ9*2 XDNPZPץ;dG!Dā` "<6KB V E 9ge͏>m bapC@h|Os`ǫy EO`Ȝ"zC0%eY6%:KN&PJeAj04<! ɻyIU互3ڤt>*уѡ?"r@>#G4P!J r+pܥ)w 1e'5scMOv ;K0=~?qS#&h4'WE_6 \B 8)ry;~ .q Y&I />Ƃ2D!kF,f1 jˤ u C=ЦUCl }?vDږ lI0b Ni M " C ݆{*6^v|<"_pC2S KQs uET" Ĉ|m{PO>^<1Xʗs2]܉ıY~'Y|ȣ{lUW?EK)NzAӠD0rLS|'ɨƦƃCvDA^io9.XYwj@GNf69bD>t>jJ\@` $(_) hZE4f.pkt0.㼚:J.*9kB 8Gheb8AYN$ eȅ-nDŊ4<P^N4 mU%,XA1 X&XV/s'7I@޴NV2lz0,#$5di 7` s VD^)h%""#X9b(˱0S?YфO sݕ0:nI+,*ۃqtVۜwc}\ dLH I fqkPfb [Dvf}f  45 ܇p›/&&FS~wA  Ë11'b=;!|m/_̩.3HCP\[HU N6TQ#вHaE*ק*e=\< 9G:l#fVнp›{c7:hMڅDd5jE:(fBaB3P&ޅ (8JD 8x僺C"e/nVue w$$55S >m7"W0,Kyן04>'f]P#۪BfN,DʞD@ ѪXAt@#evc̀΃˵GSTػHB!,6rDKd<>3W@dTa0{2nScM"#Z!\3bJS8 v&$ V0?'y3 T<`UP*SC"Q"j#'A;e~2"kGЍ:yة H +"'*"M N[r`:3 ;;Ȝ)ۋd& vEY>@*A:KJ{I E5hH&R[ۗ)qƞLSWNUQddf0ĦVR(S(aeC*a+!(hd<I]e]!*(IuHɨYk7o R>cP->@6oJBVB$E-+ c#~ ?7Qb f{Ҡ==HDAY"=>$'@zw!&bTR ~Z$ N(`*! l&Ù{R*Th!fDl>.'G2mª0`ul狂OG5 *Gtbp.}m9zeKD(<"IU[%UF[dNMkOΑc1!t@4L=jSc# (Jx iEaRt@BC!58"4;]+a6ͧ-XFX<_AvuD]~]&A-וAEA`_ @؄'ADrd|HfBr9*ƻ[ ,H,Erۇ?!(Ca9jSU#JVUJh*}ټJHω?`AEt^tHS.a797GsAJH̔c  t CUeFEAfXG%(7/ Hܟs{IT",U" A Ay6 nnc&[9b&Pb@$j6+JXA.1vS#P\8NBh+ H$$H$T1(TedO{{" NQ?t?@`zN T'z 9N{UrJۼƏҜ| #_D|gܳy&8ɂϱ~209A9D=NB(x>:<ٿfH`F i' 4 +p`R A&EQMK6J  BJc V$A uHTT7 G:,JD?>/xiqjrg<3} @ÔpaDM7$7d .00SIL.3 HJ#9@'֧('NksW93A>r)آ]jϧ>6Y^{6cU go17ahnf" p=}T֐ >h Ɔ <L]H$Y2T;oZ Hsht(<< ~x+݆%]Da~;$z 7 I&)K(E+}E5+PjRwQy~x?U6HBbBe'!W UI [o9;ykV/]D!;T!:+cEeL6$"ZLWz!|Vz{Xpn!rk)SK -)0^ WᏤw[$d'1dT` va,X1F^Ukjex q6>A#'UAe},X4A"ȹw7}houDxH (Zcz+ӛc\a* @ -t3p P) .C4mצtGQI×OI$< ¤zyJUv]O}5.G^Rt^ 2uM0Ӫ(@R#294GP>c.tDU*OND^E;?vܺp?SUb](4'pNSݡk막A!TSYaT qI)D*>S-:r}l|8@ HɓxyTVVk,"@((hPY Qʹݐݓ݋6$7vI0P!tmѬ п UF(CBu3Ձ5m1ƨַq}R W@af(wpG ?8k[fz`xȷ ϧqG[NӫsoPYy6d Rp<fl] C=t T$xsF/Ó5&`l #Z~-QSOʈ8%hVE iO%OA:>SjYWs9SYzhNsx( Γ2 g]rҐnىAVeFAUJ~;.0S1>ij!n5@,!C_oi `T'k ʾ=\;@:O`I#>u7 C鴷-P*(U gXc+d\D~ߓ9_Yϝlq~1LDI՛B9iM&0 3:fc/8-b6HvSJXҪ1icO#SN7 @HlPi.t۶|!QILGAQTUbp4};?GDavT:H{ -'q0 =>ó )Q6ekkd &@ Txru_Mxٮ8` AuG7Fa/4QNE+E$#;PCc0?K,|r@!u~4) $P @>X\DSR `ph'(pU e! Q U,JRȵYCk@ԤP )I*B'v) DHg ,yz@}޺JBFәl#G‡iπ5% }`Ӗ_f`gjP}:DX%}Rixk *(Har~,k.Y Osu`;0`OgD6g1A{32~z .@8OW)'ۙ_G%Ǚ6\4e=8Y՘_CBE AWˆ3B$0< #=>i-Wp+@`Hc ю{9M@xK #+.51cJC;¼T}կó"9x+M"B%Lng~8{X't =NLп͸ UL W%S( gڦO0dtG7P;2b[{ $U}N 8.˂A88P9dzfTtMLA ~:ٚ*1 !n9ҵD3K"f@(s7Au3\CL6B r<] ݙdD4f?mË[r#8C]wYCfuM2HF#xMAJ1~$ڌA(0h+{wcR@Yb0;LZh0lwT pKCCSuBb]rm8r'pl(g{9Zzargz{уm5-嫘աl2̆Ep38y5y[ӍlJc;}Kއ!BP4`kvy ٽƊ"‘ -BJ֕DN%$+H(`]!k@*D(ۇ1C Јg%u1S~S.7T1 @ArCAARۘ ^Bƒję{snAomUUUUUU߮mM}u  2AA+Pu3ZEf"!N Y h&؀D(PhPdaeT(p`O=H1 wql7,Q8pҨ~uiZV s[c*c2:˪PΣ:X;sQ]5H/ZJD6j4/Xwڡ, 1pa &TH[dTn[r:遗n0!)O+*8&`0PbѲIҖ1XYɳ} )Q'u!5+$cpZC̠ՙJxPbC R1 ͠H5*86]AR2 %^w)fv̚fG] p 7 96H >TQQvn„T=jx¾i Hc_4[n/6 XԐ/6 "&CYnN׈n3֎[N`u5FZ7iN] dTy ˷:$U3ip0ȀwHY).{^t|'O 76;njh"bXlE$Tx[YL [5P>Ib`0 5J]SjzL K{p,6 sz=B!ʚ0cl)9(GH(ƍL GN>L-!wXP?z] qOG^SV {d4`H0I*C:fET|M;U`R%<(]CXD9`7os}hsj~UDWPxcxT].Jr;e:aߕ)@@*< 1*LDBĊI ]yNJhQ(ţ* IoX 1SIz52-j i4KЖَc1dEpRNIƥ1Cm\FB2i0a5)`79$r30YQZg 3a6+H0+pYqJo7wdtBF;w6^M~KX P:%(P!@9U,AGhn1E2dX 5)PBs!]"{! EwgldbXtӟL (I甞Db(UKvX0Q[nX6<̠-Fξ;&gފ"IEdEHBD Z(+ޘNCfCOID*9< c뺈'Sxx@_vFkN@ڀ"Gyy1C6Zd"@;lƩQCB׈6ɈH1"DdRm=8ą _pscbƏz(90KŸS8oI.-ˣ=2:hBZAQP&LaG+KFuuuHZe ioaqwr(vșL\C&p2MMd!^٤bhw!vbe/\qtnH5- sƑ3AJ(8`A@ځ0DP9ϊ;0Ncx=t 953RN6\ ڠ Nv?P `ȥXv{^QHw9bEŵYd Ѡu!}v-F 8S ?ZR?rI$PݝR)GDQM[>yvza2byE}".t!a1g'o-: &V 8l&y~C*/uR7݋{bCa]gК,n\?d ,` ?ױh ]fpU2g C=b#@Bx)Yќc aXm͹:${EA1A[D}~@YԈrC#H V{ɢCd!"TSR, )g#"X  z|g% $7 A`,PH@"AX@\rdA)@]}V;F1Ú.D'T ԰<(x0wϔMzNr_Of%8`]:1H00 DHV{WPb0 h#!(^95CYC.h@۷{x5q"@$"Kz?m+?tЌ!$1 ޤi `w(P@A;JSY+o!3ܱ^xf1N< C2? ?7?"i,k21 b+X6%Y2e ʵ-X1|o ⭑9rc^ .!Z t 9aŘ}@S\XiJi Ϗx#$!8_RYl?&iK7 )+&D-XJjH \$X W2D1h Y7-Ka X*0n8} ?"9D@PԼRg`"y3E)!((CǾt\{ ,XU$F1BLy ?v ]p@R2Ϛ TIi{:0"&P>&<@e쯵65<=U[=;mfݵu!5k~]Enl(TL"a(JH$hzc2Ctd1y11{l>XnB|ߧUC2 p!ׂD}o9bTs9& fP`Zvv̜s!>dJyPPH읩#`|N._ 'CRe!lrQgEj yh{KGD?ohOMny GP(λ>>S?62em9v򧧿egjIuEO?nVH^_}KxPfEXTS.S\=~q@_04 ^%`齋CDe-+ -%E,ث%A}P )d, ,m,tphbN$1\Q %Gd bʱxPѨ`{RQrٲOM`vT|P/mnTG./_q gpà.ӤGK>hP.躐8ietפWN;[B$fMx]x#" yUsƂKdI9 ;CΛ!x n1iO BcxQMt%>5 ʐ1+O9wU.`WJlgŷ+ٳ<,os }pNhI j1Sy5-=ؖ}FjUӠՀV2j37? ?pOSOg0w.""k x ;pPR(}LVF.lYۢjN !Gu龣 swr`9wQ„k!`N!GZE`,ȋytn6ӊxgw_ BH@v*DQ&Ac!/Qq2\3^Z6<ChWm`d AP(vl !t6 `>۠RS=.ʚ%–P7dYI \;:OV;O"[sѐ@' =]_ ͒ 2$.=k'iaA0*j?Ev@f jXsawh󟆌>v]M ȋCYBBB@EP 2+0[HE`iBpN:+y̆f~$JrD`/6/zqOKrQO xi{5mbuuHFE "H A`,憗pD7! z;9D@AFD8B7߼(B؂ȇęd;+, >82ʰL9-mWקђPɮ٭AfG'WeQHL "l!KTuK$23([Ȗ:e{-RT61KA&R#Y=Dڹ"1f!326HEt&,.f dO>9u񞾻~sN6KaLXPFłe%Lyxp2CcH#Rhm$SpE LmVBfaXYAkSz1USdwJM$Y=d\)^N2v4̱ED[_>T)}q[4qWІp6$U\ľ䞀4<×N .ыN)UTp /FfzGhbBRd*2Yv8D tn"}~(H ~ r in$؇L# ~\CV# 28 {>F4*vYGk, T*&$( e7Yc}Ǽr+cU{Lij;PtQvgW-L ϣ>g!t{VUt??X~Nzj; M/q  劦A~ԖdMfTpv Cs^t4 P}ST΀)Tʏn)E*HTIBHzu hyʂ'ډt͝Ko;}y}N_|z5QR.ݘzzl܉ Owo{Pyp>0EgA@Tx;TȢ4 WZ=U*tȢ[jw7x0wcܻ m.]vkf3KP=t}[+#7\ԫ`(jItR`+0ۓCy'|r99^tfF9A8 _:ﳷg|_|%{.{ʀ TQoaР'֥(%AgveO us] ] L;:{J@L<:ʉI{kܣui;タ;whTs|%/x: Gnw;ݦ4`o6BNZ@{|wvCESl7ovۻ6̹>}iOu^w}sקs{o}oZ{Y3_awםiMi7|V, (iR]YK˾w'O_O^fw5WJچ׶almERVX{yz7muٮM^o$ugKSmK<}\ܻJKbE: {e*Szqn-O}ۻ>}1vvo^ٹf qsC[8z<.ۛ 7Fgwsw+. Sq`V ;KC/>bF_m8o$MRyg<{7}F{]o!\jE};PDAM;6ik6Qݶvvub֠ۺmhvghqx6͵Zʆ[Y۸h[S=wLvjnUխ 8 U&ٽѬ]՚YQ3C;Ɩ{f;]^e}nV9ZpvNy><Gv`svҕY;G9Yˍ޼BPHwdJ 5KNU=(@&ѡISSɢmAd4 hhjz2 昍mFS?*xz4d H$B @&E6h'3DM6A6& 1 24'$&i0$&'OS&MOSG#jCLF@4h D@ 1&0 #@'hJoRSɊhFHAd&L ڛShi~D h 4h=G.,d]u_sy[+li)ei)dՉDRPAH'f~H|sxVLѦFa@%OX?Նkg8exLB4"q 9\*1)u7nX 1(i GYH !r!Y& $#h rT#Dª;tt@]`PفZr jX@VD$I$DDu"ARwPED eR!J"*DQFDZ$RI$d$a9Tbb)Qr1B@XJ~T[^U$Q(;pUcN6)QmnC !ai*M& cMQ-+|?L,Q6(;A_ ]帒J-jF6DmR 1`*2FhJ"&$3[q`BۇnA1.F"-NՆ\\Z﹥݄$@<CA(}ǥX\5G)#mQԭ/3$0qIAP1 {CآiV"GBi"B cQy~hdjn`>N\33h}VcpǷܮ= w9$90R ?Qчަ}4>=6noh:ךZ鲍nA_ÔS(o?UTTU3eǛþWQC~wwcB97}~mWT=Pxb,%p i}ϾGss6k<7XEOns_G"x> tHtKޕA6޽Qi]/kpX_dnKw ūs*ʥsG71{?/C~ւQWx{ʕUǿ)U`E]A{/" Zyce>/ 墣Ży$1?i6uqT $i=ߟUJg幛ejlλ@HQUE:&iqt(wyWnt ۆ>סuJ^j;-{AE+V[sUa] 1I,);TH6 59M>dUTY)Ŵq(zhS7y>]0M G cLJWRH[! J@^#}+  imu|U :;w5ppڮ}Α) @?}=t@WVIѢu;)KP. cC)UDG{C(Saݜk", tWu:Z:W_.??.)dI~9́ONE?0~$<Q PI۩ZtY[Jei傼PT;LVi^]"Q mŐ' ¢.l JG1EBM6(ڸUXmӟ,-5{<gL 6:oAwK~{ ϛyňG;ݏѵB;4;/x«|5b߃ g~4(YnԚi5te-l--jοCτ$p=?_=X5/P?\=91%BHu}B5ͅR_}Gޗt0tEJg`yn|e_D7{ΰ-X% !Mks(X1˩< >N;Ŏo&sH'RC43Iz]*X8CТWsmr F|e&.ؓ%GRhug:rлq~o"IQKU/rVa*=j<޷!ήzɌ}2'HTW(wt'N^ 鹠>Qx-i߆PmQcSNjYENE&ª ,{et$3~Io9f}N_HĘ޼[/ĚOS+?}dC/G GcĢvºizD>s̚7> AB_Eaee9700i/z;%JA̡̫EAֳGf"~U%(MkW0xKՔ$]02s9ŀz|"79oyA1OiWiG[P'4)mqDAI+sA()P(DAP}_Cص"_SBUO)g1ϔ -ÁB9~FW1ÃF=9?ݏk6AASۤQH)pU Q`н>j+xvnfk3Q޸O EIp W=ЫH)BQlk蜷mo_bo8`"^z@@pOYN7i◷7ֿkG 0œٿ<?s:+xm* f~tQ{Aυ~tXwM7VgOCmxՌL6W{k|Es~5&k˖;tqU5_RwZi6 :i:M4<[g#KD{ =!0/ݶ/HOnj9?lr3hk#Ai  .3O%0İb&DGaQ㰶n^mE)M--~qT8 pM x窓,,f |:*;›s;:̉yρ+qμvw{9sKmǯG1 ] Mx1{ {4: lu_+D/cj[",k>-}Ѻ.!.jK3e),)($dTPkcB]R^&q(%ĸ[}k=bƯYq;kWX QwpVf6UpƻpNjj6EOG&WA 9O礔QV϶.<ߊi֬.e۳Uxn᳊ն7oN+t^NVD3 Sx'79lFvxo?m D/ ֘?+%i`̈́/8 +_!5q_Ciʶl5mMJ&:JysKY2fL &t;vkj;,%ʝ;񔥜ʺthF2 Īx|6pv(\UcV2J%q/mn$K q\c:ګ_}jR4єc'"Ǘ}<,v">ۘq;ldnhַmcz6{;BBJӎ8n8+[x\o{rZ++\ Lidd3WF.[A?m$ՠe"UTjDoVM{޳9QߡT|ch˝{ޢ^/;]b238F׾A#-dO ȋ9:ܿBՉ#[D^1Yx" ]pX\+$d=zV4T3]5 7&8TyoF+Kͮq:%V'NX;쏅sneǖE;xTjϳ6nvjK,vod*R(˴w◚ 2 Y3ȴim-o_]nX'܏)͠ݥ7~+c=/111001....)22222/v In],Zi(5-py4+fu&W |~F¼ġ(K45y_]q~7g3n,A(lk:c^uy]Z7طn+>vz>OkjS% 2JcWVsO#SU֧-CVW[c}*JLb.jj!S 󟸻]I?&ʱDy9=? O}gyi'in_H:^ J59+VާvvL~%frr==yz-LFYn\5=Zd4eoKt6^ȅGP1%4/<7egGkF0|r#|NDzƣLO1xk}'`Q;JF[vYn*y8쾈'b8:gBnv/[z ~UКїV78f'cؾ1qMϫ/ICv ̢r(}f22^VN@,ܚƑP>բ_*v䌚cy^ WgMpk<"G& Г^AEo^?fX^lo$QBDIp"&Qw|QB>U^iaG<ُ_cxX|9~p|G W#:-p[Y  s5ٝuzgmjK˯tZwCm~y'8:ùE֨QQ[rx'#L _b(#+ʥT:@xQR88un1:@L3((( c]xOȇDOf= mdpBI_%=~̴<ThH-5Y%T!Ю[|.O:L{7K-!!X Fe! F*RHDTl&Q5EFA&4hڌb4Q1 [FJHبXjQ%RmdTkDD3DEE&-Ih0Ŷ% i$61AhEmb,QR[['UsOݶL|gW.V(MYT"jpcӗd m{?em}*e]tϩK-ω16g!ug.jrϖ8*g?>OL 'B>UEvKԴ8 dʩ:akqbB0>%r"0=p"Y: )$)Ks9K1F҈u8#>'>Kn9ѪG+Q4M~/gd7~sq~ ?_^уuҽSznzVН^~'?,քWljѣ X (2>Jbɂk:$<&}с(<]Jwjz*m"8ޤtWd,>o u@6ȿ׳/?w9<~Jz{^pT$aCmץi+Q/OfEm4|Az!0Yv ~X=1$ zI]E|/"u~t6^~3 Č$$d$!@g}&KK&et}';!\$2;>zu?s?6]c&?0qM$2cw }@,а4$:NEr0̠5΍Z*՚q'^6bl'@u8E*ڢQe[a;y ( Ϡ -3_5d/])ю_9?RԫoӅTG& uTZ] AʊH5MMڲI̵VU,DYe5dPo) !ʄpxLE@7pYrc ڵ)XY H/(Po??/W? cޓ"wY( rԨP2+Q${t5HeI#f#E KKRa b* =&@$L^>>t^0J/g\ ҏ,Iki%t2 e,M&/gGئ%%$kZ:4V*Le*>*Ʊ'S£Y^Y0V,*Q2:D9"BLĪm㍔d`E(҃^AVrP.+ONE~Cs w}Z[*%0Pן߼1* jNsϫKa"+-bktTmcI7qVqQrUeE>mh4YIV4 ۜ|j/X&e,zCvz$5|ĕa3g+xg㙊BDC?q5dT܌.%؇"0.xq#GA93*]I=T(Jd[Lzu;H?C:6Gq:nI}d@Tu0K A$NyaF7Ѵp 98:LCE&c= zj46BX0$kF+ X+hR5+Ωp꛹y:$Cx+{HL(U^C_Qvțn}O1dGȗȵu4 @z#BL)tT#n'O25asv,as j`T(5^מUP{\!UUUZD.uUj{eU~;z=Ec%L[rkF4Ɇ T=|Mӽ{xz뫑zIr%α}KXG`&1ס@0>=Kb#`d$v$;,0 JxF$ M}L\mRCBUݯ N6h4#D_-5j\QvjFF&" "k2J̨,W%`ҋn^yE LC$߿=S~|$ЪZm>=aIr؉`(f>H}g˖z0mAUk*[rqMr`t&Լj8]0/"@UIgv %רRZId?h!yJ ҤRTM uo߿fs9sfcӤC;<հ/]u0",ǀ P& $#DۜEd&ιJ|RP=!gw |[!K>d_|jL{6څ>a4G H0oa24C/-9Cj2p4:Q{Z(?KQ0Li P~h A-TPMmp>&O9bCDJٸ "U}r>PLhT7JOץi/l'BH$k &i["3eSv5!![P+J?o46,/*buV<&8Ǧ(D5BL zĈдUH#XQォ D7Χ5: ѿ/{M&!֨Z,jk5@jH辸=8Fzp:BSa "d޶ƊJ&d5DEY+$qdR$mH&*$BR0Q?f;)_a/*lhތuXy_~/}\ܾ^tt6O_s&{p f2d)O\jֺ́!㩶[s6) oXư?_:ii}g?I2ޝ$$}^j5!/wV,xBHk <~$9d$d%Hwve~oRi>Yr7oiӻW!8|0yxгOZԯH$ סHI !m{mx+-G[i]=&g6BHIyBHr65ߘd|$:|[~ /[V٣ʊ"rlc7lk$mȳ!F1Q1[TշW\\*^)]t59=W+W$2BLo\dG{3iLHZ?DIz/ˠpu]nz)"@Eۿ^v;}BHzI !$:mߪi18*]Q`n%Pѫ !$$mgC")]ex}2mmn5U7gi>,ċZd3L=W 6/a522ʈqw#.U|7FGO m-ZyqN%xK H =r~0\|iq4(nmIɘm<݇޵512f"fLyL;ް;kZfiZCfdehk֪[mMm5 HI !$1 ڭ[j `׵BHI !mᷔRI$m"I$0aJn`0d7 `6t:'r'㹾O+^WV^[Ws_r$}?'\\'9t9˜/{@sU@9j\]ҹ֛AHI 1m~miI=D`EOB br 1G?]v>a%Le[fVVW#A2W]jK;s1.@#Y` ZIc v-w5q]fm,Z4[5Qm[tXźY,Z4k.W!F[HjV̫2^L0?9V+W$^w|Mj&׀\7MtfYQYoi,$$$CqʕJ,UYəR*uV !$icQdo,.rܹr4pm)di+2bY3#-3 RC1eAM:B81H@j9!sI$I-r..".$ N\sq9ȸቒI$Insqqq!ޘcr:*$$:$ NCU0Ow,{nTӪZs)Fr\3$p؁ T*+Ugk<U$9fN*`$ވ͹e1>gNi31ǽ!^:5"s\Bpz9X~_đg*P ~G"47'H~Z5)" ] Ε,oFf!T|>ca Ht7P?I[|$/[A"Z-~5GPUUDU?7﫭^=7hŚ CS{lҡ1e:(' n>H?s4f&(l9~nc!8QBzG_6W0ѤN'=,A=5W>g-Qh xL̻s`Sq"x 8@$` ɍ$ s@.(y.l[̳#y; dcʞJ7Ow} k|<kYn"4oo A2 )OTh7w3G_(#!%!@ x06y"~?_B{?iM! =|}Gܳ0Y-3 QjmM~ y¸fpvvo7L$FgISv]?qK9/98x{.% ,| R8#;W Qi+Aɰo2\##ӛurMgRhme+cy%n`6ozn%o0MVId5* ]5߾ii'4W+;q~:9(ɜG*GLΎȻ7p?&s{K|F:$9Ͼ2}proNs@xXuvX Qb0ogL=;~ Ě?sNܔ{Cv {xPNȟB/ Y& T攽-̌7u<$FHIU[ r[^)Pgɓs-]׭}KnSԨ")`X<|,ʐ"r9~c_{S v77_3W-d2R⮵k}s[pKA Nͷ"H GyTPn&I73pCY['IŮ^@x?!qx@C*i9L;Qi?/?+̈sT <$|{\oQT۫Ҡ^(qnjsPp.:*7:&tO:Z/ Zl_R\wj8W ۗ㩳:TAPA =l@?ΛA0ã||(]; 2w_]2D U/3!Q__%CUAsN_>YhleS8%U.êyE9!MRp@NA7P>]45kOoQ5,]}TC­yyڳD[m]Vd t~p( UCɬOTmil~e;3pL]LXt YJ;#$mp=WOڟtFB*{xQ!< S!>k4{H^(8?]fQdHnE]qETֈN}~;}5߇qݖ G;TEDd )?l"% ~imKR]k՟mY+9Vmu!= mȉmiDDDDDDDb"#DDDDDDDDQDDDDDDDDDDDDDDDDb""[""""""""U""""""2DDDJkٵn+fխjD֤DDDemB ""&֩DDDDDJZV[UmM""""""#DDA"""2i*ԈDbc+hUI0Dedb11d2Ȓe%RKSҊm$HV #aHA9U--RXAe6"Jɶk0FƭY(jJ]LjSZIF***c4 M4JZ&1MVl`[#UTĒ(]jFX*B( !j\Im˒I$$I3M4ES)RB2d֒AIm.\k[R* 6AEQ)DMZT5QP,3(+.喔Wv^$cѭ>s}D*!U뢔ƽ+7,OQV4\jjUlZ k7W q耍Ym3nۊH!jCe(}'B/v{z 4lwh\wH5Rgd'IGK藤e1%j3hZW&ݘ&҈! B%X,Szv}pp?e>>\qQS綪()SҦ{OGW׉=zJD*rn&W(A_&#XuY.Pg߭TRϠ~RhpۯNΦzTTsfݧE=v]o6&]+C}c*MV)=6P~ "#w>Dz7w'- eGa|z7w bg0GSc >Bc"@So:Q/ZUy4,]udLёKfn֨|a'Oʪ:E0D^SImz7a:&t,{mõM<7B1 š%l"Zck1γ#˅eZSB6|r{r >;u/GNOaJSjbS/W!C_< 6J-Ex!q\+na1 *)ҿ覐lZt}Zc?t*wEG yڸsOUE _YXapMcJ2hՈd|ǔۇM)mcP`HhC&0-9| w~ q~ݖG{ -,^P/JuR#NJIW/"t9VV;5DV^A'y< 9hr $GtΈ궍ږnph2:|C%{@r(wBCirXpm!, re^5K;sʵ"h(Qp \-;\$g=)x5C64X;axSl+ޗYƂTM &FY! |oƧ&g}Ό2 OPzx)u$:/NҾ^WTGW\Y۸R=|N>-T6ZJ>8[oO(m}kmu L B` zll)ly6jxl>&@+V@XjGI K ^.CAhVڀ-hU0u`}C DdQ;ߏմD;/#`AÔKP@wxmJRH®ګJsü*kt}exs 3}*ѵ5ӉfL PQX9Đ!$f򲠹vLy=r-b4u"mADA$ڡCDATٰc-#wk6Jԉa*BV$|W}9r_iv&Ik{"Iբ)P (7:׶697rU֮O([Ps*!nKɬ|Bz(eIoQ]a MPD/u=ꈬ %檜7-dB%hiR)>2miV4`Ǯsf̈"qyt:ZvPhO "~e2 9ѝv+xmAo J '-߆n7l?=t- Ӯܮ|Mȗfݒ#T.Sf~B[O|Ԣ"VfDXze/tF/1fTR@De2\YjU({iwuq Cj*./ыx'ﶃ1 tՔhXzR8$y9!s#+*tc 5G!ɏ\ l]*!DRµ?5T4lHHFz6a yR DWCⵯܝj%c(N>gvYRJ@LAmah#羴#ܸC.#i@Uu3&˙BgAXaB>(Yӫf(IaP]Fˋ_'͞mo弛4pؾ#}[8;D5)<{uj8€DE㥴J6b""^ QG&o(UZ w2TH"ܢh+&_7NjZP>gKe.aBR"n@wQ}0{N 7c:g'AТ %iSW!o&T!Uº s2>Ӌ^G#z'w<;#D[ZHJx]giЮׁ}l3!{Sa ٻzk癏uCv@ +{Zaj/ʧ~ݧwӸ=7xXldt먡Iwt]0eͷו(Q TL))JvG$v&F:L6 5 *)aũo- ufxwѫ=|?s;y{63F(ȱJ'y9ݕ92+˔GAB! C$\YqW h/ LOkj|ya decuߕT\gXu>LjT9kɰ6c9J$UVUe;mfνsZ nTٗ/ߥLFoDUT_{"C`fw }y/D-.&^!}1h)HFEĦBhH!b<2wj6q]oxzE3FIQys+r٨X (dƗ%IB4*&Bxx3Mc AS9al=ks7[u9X˚R*Jq40I1*&"v^gnB=ޑ|䖫rbtwE2o* b+C _xfaUFBQG;c"EJ"}ObʑοwyW?lr’#[;[Cȩ̣Ը(bߎy l_z?3q>7IJB Wߒsc!'~yCOgZ'iQھ)۩ob4ìqM6p2N~딵j:ї`[PACn^9%ykf?j Ni 5]udhX{<ܓ]{ ԁ$_?dap"66*?*/PǣK:໸E߇¯N~Ww(@NUY5&)8$ph=윭z,6$;:ǔS7Ȣ>)`hF1?RIA,}ˏ5yQ`RZIN {'$>=o(0ؿD;4> Ä%f^Q*ƢD#JG,Jؤe[`,Usd*ACd, S25 idUuޚ݅8vxFF3zQCɛkZ?lqEPz]Nm% ]8G!9ݳ2s XǸB9Č l0I8i>?ZlLRg?5k(jD猄uuj n*X7|BH5Y@eq2 9 UjW; {0=1]-&?k*ʰ-\&mھ.IZ/DY݉b(V*[Ut7pRBLdWX w@ש斎 A; ~lʖ|{ ,K ҄n%! W -ԄԉTY=8)YGlnaR`_"HaDX$d$-^Dֹ۟(&!qFcW1lmRRrpJa,&KLWV7',<lSlkgzX69~8YX*bɧ.U{3^?UMۗ,o=03aqjF?Sn6XD&KFƽHi`U}7d-EȴzE\+U9t-"Q˥cA6FS :: «N2C SX~{`}L7,x0Wڧp37qzIԕ88`OR}%Ŗ6//C u.gaJ2 4P?hGqJ6S]XZG"gܦ%%m_A{)ܤ}] b)"ɬk٣0 *^J)jQ3^L45ơ@0`G~+JU0RU[ O%KYR !8,4ФpJ1IʈU qygݾ VӣQ:JEUDCL ܫ_iӍLY%JmLJyJ1[ ~9'GDՠB݅ne~V3oL?{ӧofNzQv+ y.~ᠣ0}֯ߚRCS8zUJHp.!UW{X0K^$QxcGEE&#=n̹߻IaBc/g8+Ca!,Հd[Lޫ!.|)|K|?9*ܸd# җ?LIyNhvD$M;H~J^Y2ɅMBhR<}< /i_#wK'Flp&1QPD(nM^sOm^5a|LD-DV!Yp/d"BJ;k qQ %tH8V2 @l׮Is&jqR pJ~بs9VHa5DG^Y (C w ]zr;~=:6t< #${H1HbȶME(c3}65  }dkǎEilc:G%^Gp! |;ﲪf$i_9̊$1N;"+փi:5S%V)OSt_Fa7dƽ{v C%A[]^z'X@n;}gv}wstáCjKS|V[={oMEn]z^~D}ʆ_ 2ޕ6996OL/)ɅSⲽڣu?/K|D5km|Ni$Uzvz'ۯ })1vaU*v'x2YH>TUQQBW ALp{ׯza5! =* X~gL'\|} C.ZXւ ($tX TY0pWJvZ&JDִ4Vo6.m}[πY邯lvstEbL隡 tab*eDP T$|W!$rBI.䄒_$$uyߠ ;~=O-joj9[l>1z+a zNy[f.'):!5ʠٿ'WN[C6GB Kqq}\r\rUa\t%@s7cɕpd1ьdfol35홅ّn̒$2^^wnAAAv/z'P|{No]333zcN2 <5qߏO>/+ ίF8g,s.~;1!#$Hv9! B]U*@5/899OϾaid2ul=\rӑcU"b)a3CP,Pz!}PIwQ y1a_Չj)vVFP`fAD88DPzjrr{Vk0|ZkwcJj>!g?O(OV$J5Ŗg+(3Gx>4>*[J~Yfh?fn x p# *V?}'7ժty6u49܏iWDu:Le0n9퍶J,á7F͚u8$N8n=i&nqȐTZQZXN7x9;+N팷+)(K[xOOHM& VV&{(4s4r`KrIkJ);c2f1F*Lo_skӪ6Mx=둙-'fkK|NzfkXͲYZ.9e vE}bηNdc)Ψrݝǒ.8;uNۂiAH_m4FfڭVVfl٤H"E!2 fĴ0Ɗ0,#-.$&(ǡ4pOBi*hܳmlllmHE!6#&@K{w7+FXhƑ0aQ%JklfDtM4UdҒeb\=Ǹ4igwW˖299UĪU+nnmCfΓF|8WZmq WZqNQ_}7M 7.m'Sr7=GkvJ<$tZ\hֿr/wn q VU*ëiygL=eZƓ1ĝ(`rIT$p,`wBw7IK:<W0nuQU$Νe~%szaWmi凡V1-:wu=dzi'-G.}N,:7ob.@?\ӗg=e͢êqnaW-kYy|~؝Ȩy>UNW;ZI4?&_kֈ#s?(?P ȳXxym !0V]բY4IJ+x"֤%H\c#FHnquoAnb[A&U'JиMQZ PҚMfV&k55WE@QD8J&ٝƳR!ڴ*ՙt 9UZuV"&fUAJ%hWva&C֌ʠ%=^R ҡL;j!bs?jS6A G!&KV/g޷/((=Z -OpCqA?\O ]e1Q>(?;R'B~*ۺ9.g_4RX5̴9aVgd~o܆S*DN iW43J)UQ*@"ՁrU 4HB1G=?aDGX`C}3e` D={;z,Yt7Wز]@P3CK(* 2!A?xduZoNi,@(.99Ǟ8;ĈB ! Us^wiğN$V\m&lWm- bz0b bPdTDjˋ-Q_gl<<2CB*D~'/^n|,u(l y@&dR>;i8ժO#h9`=@ԻU\ce }ゖ̆O+nԃ]2Xvݱ$];j^ ~Sk?;^7bб?EC1zkdW;aB^_..lE$P2atT+}7[Fܻm42uo<}@M#Dq6sbD9յo͆ײFiW/ߗ9J:ka{6aʝ!}A4`b1_*AďȺα{vΧ58*@y#BI2*2+5X{s^kٗ}CpG{@  !*ʑاyPd؈!l(im/P%}4o¬՝EБB!6/ujxVRn4s(;!k1g٪)~etGS]('~Q95j*Qx6Y}8V_k}deEmNUBCʒzL`A?V=bixzy0 Yx2"E$`YYAEDE}_Sw\<ݝihPcyD}k1ZY:[{7?ځat0'/6*>ES(Q@SpAA:7ŕuqhם(<poe~6j-.7۬:gu-"Bmo]wy0&c`ǩZ ؤI;i6QIq,.[8 N9~qb0/[BdbKHZ1ic6Oe˻a=X׻c{-3472UI'9 a P,ֽU=M:R-J(Hw%=M-_yU(+F?Dǣ#5SURbsҥ_ӫxh4T !HR$dVU-Vvu-vթS8(u §KBJk;]!c+fISsէyRyJdZsf:2D)pc8^VՍ’=S<$3O>ɡbmC B*E ޙ*A*vfVB:<ٿSG8f+ ,?]^&j'Ǿ}R?~@֗iR\ť}yJXPc)c\Y99=i9B]+#RMyU̧_Y:^C #n{*4Q}"-1\q drAF2^R(?źξ~aSC8I嚢O'K{0HBOzpԯ-5d=G:˾Pp=Y̭xbTn (3W+|R%}pU;G$bP M$"Ҡ4rR<"Y-AG4'^i|3\(ҋK_9xRjr['A{T-@Fu d~@v, "\ط?R.NsB%(_-M lv4\&[3nbuX'yiӲ<}=o3i;ު)Vg&.Ǝmi##dA2b |(qHEO˒I$I$I$I$I$ߓƢ[otmn#w}I.""$^W}|r os'Y8g|pGf:/ɻC86 x֡Bbr*PA@#QbxtG v[2&PG@=St +%$ sa}XEUU.Z]~5>Boi/~B!M4 G~<37zxҋ&U= j/֋c4|1tj1$͏ W t[ՠ¹ZhDR=OE' %Q|%oFA>a9s2fٜVDSH@81_]L5HZ*7a_pH.@z\1r?aIG^Vb*RqUdN9$?44ē)xڳI$OuhڹԓrI\ӒI<2wrI9YcΎ =.KK{+|35}2ltMg^!K Nď Jlw&;dijeÎyL̗jA7 C6];[GYp"}Z[MtQoyzlVC' Oi0iŤ+0wX8"*q/#[^OM2cM/{` %F(pm  :#k# Camb%߲vWdߞL etGƌ%EC}C=h{Љz `&r%2 oM^Fd&|9r{9񕍷"t@GO^;0#X'!rpd\t$O]-/~mzrh7Ra% JsґhTu_yUWJU'+z؇rI$mHg*(+ZGhiWYLcFmzWޒ M% L  jQ֕O9ۗ1 X)2R" \*51'vH33h:,԰`$$'vƽjMQ!EA NQ(Gͫҧ\G!8~PwnW`OO CJRؗ;ݷ)J@[ո`A.d*/P??Oߺ>2IM1{be9kq,EwtFw,?eT+N;[uBisZ|;ϵ^Fp;7AA Hさ@LJW;1|ft'b5Pؾ Z (= * D@&'4 Hd ~dfe95/ZOFd⚲n:V`n犊U P398cVnw J[QRMf; ֦zu+מsz4W) C+렠] AJar4yf,W"bC^xR!>f;? kޞ}=6Ѽ&ƵjֵߟϜ^~"""""=llll^z{`mOrLyKC#{YQDз)P|A*z.(I$H!mPp9uYx%;ŵАA)$I( v3g Jێmuvr(*\i|-) &myliZ(VC<zA;WA@Z$Oy$I$58&%oք¯iM2to LϕQPJQUWi!zQAT-0sӧ^Vj嘸x Iz<ĥ(@Uˬىir QQ+2 14$I$I&$I&U޷GI4{zRZ{|t-![ DDy"g6+:,r{)K򡻭=$A>Bh\b &bIĤ*']lNkjof $ҷd쭩8'2S|-rAwCtE9b&c;`2ё]`?Ɠj>"J㮯ۜ'jR3v鍪ʁ_wԩ|9Et;*$*!GaF=$+РO3gFpL-?/ .DPug~@?x4#Mh:wzww$(Ik:6I&⠻+DbysGM Oz\ q_zKxVemCDMSs]"uU*vټ=]9Š4qϵϹGrUѻNͽo᫙' K79TB@7yUs͋Cu}Dc|ڈUDe %: Gmުt73rflgkٝ8Ѧ/Hkesm<Ț`/q!'~Q(i4׈xF5JRMlJ!vyF6/TvFu IofCS*9+ܫz"_"DЈ\4uE÷3 B@@$R~uq.I*|9so棫=_Uv3H>i̼9&apޮRE$g uo9Ν{"}G#~;V5D>ԵqXoS#2vw9΋1q[b"!zzX8NNIߛ _uS2Ed+T4@=&ݩnwL}=Ug>]fp~7-[GVۓRvC")k޽j1~#~YL\cAl3D)Br+8tq7>J*Y_2x:%7c9skBb`}0E)RqZ,"Ѫu' GϢg\ ̂6)u$~1sMAv|汭#a3Ň9V11J{v|3@Ƈ]@HY*m((Ew  \w@sGX-o1vaDwGL 5U:w?ƚ_J&6QKYturZ;lUjduۻmfg?q3L<6=rZb|M3ȰK2y|?w*o-mMrDW9mPiOxgdl'~G Ma bx$je>Z("?Lh9)43GDn np w38f8'>W{%(W0 B?_VCkUl#Ы?/ϻ]pǤlIY@9CR V#G&<盷i1vR,ϣr>q|iKhBeCӻ,G2Ƴa#۴+z.u/A骧U-{$ f2oȷn AL=G+ T\S*=4pcWVEscrg6vݪ-k]*g2|oz+L 0=7ozj易k׼U^X ]cT,uE;P?$P9C P6޳5ϼ3XꫮIII:ujf۶ZmYe r\˓f,LX > nK8X=reu,G Jə̬R5(T*)<}GȲȾpJAd&*zE!]vT&kRNA,"]Tzc T; |?3{ aK5wJ dbGh=ŝ.5aWTӎR@V͋v~f--{p˙}-?zYyڵJT׬]~a.o\,tWy"u^7HHwKᏉWra04)[*p`hd?1Xޞduj$ԕ%dRٍnA>xPQ3Նƙ2{n4'<%{KRW|(*Vk> ЕJ$$4Z>0>[Х9Ͳ߆w;~jn{pͰ,h&_wf6иD,X .Dڔ Zd\-W~g lVYnw)C5!_Sܰ <{m}OFmm{uB0!8I6ѻqNTSVuh-O3PͮĮF˧-AXX)ۍחe%?:r.WWf;%vz/pagݮe6(D,AڋM\iec [JmJ=[`=]*wmR Ɛq9Ԏq/C]rpp[g//)WsSnF){zxN\ZȵJϝ[m|ۻkL;ۮǞAVt LFŊoUP_n Εb c+[YYX a -K;*H$@ [xԵZT KU`?g[:i</GL 5 qK+Y!%gs+bUKԔ'trwT?=>q-εJ[r;x,xcFQ+LBy͞㜴+W;dB0q> O84ټG޹s,|/;k $ q ^Xٝ,N ":;M#(K"qY)veBTJ]̶ַPQmcewMyUOaT Ug Lh< w>j>?aҷKED;]!"ٱA& V[Ø):KP1(Ң]tpznyF]gѻBuSJϵQW蓖aj7QAf_<](ΐCCp~OvRzf})Aq%UDJX@TޮgZ+gQd 1F/݌HWgvtgf}zz|qξ *]u*\\VܘTUUfݵ=­J&%A_g[iͲ:t }c­۪YvQ56m2TMUUlسλMʐQoN۲i5qd'+a=쑯^o[1.R"SQ}U b?2*!&2>ى&ꤵ K0-ߞ^ $./l"ޯ$wtŖ|(-kQd饭,gs6乿}2(_|J%Ʒ̭g`&Rxv6QM8 ZMOQOt/d 5^˅9VkF]-^v%/Ѡ~*ρC/`?Z"h -:*4L]˜i}ʪA *Ey +qsyO+KӞ;9fso@狢"ҽ->f#`Ħz ij5N[G9-;ƙE[{u,VI R-<%gAD *} ෫E;-.",+{{réptI++y25x͵ y)N42IcmU:MMՓueėN>-(su½K d@^G{C^wo^u~"2ɗ61ʰy1FPC)Jb‰zx1?)JSfJ$>ggC>Ri'gUy9ٷ?-N-VftU횵dk&Zo>W{ߛm]+{01kP}&q\|<oLD.ho7'ěWTS)Ds2k lGkpk"ַ wJ [KjSfEʸQ[:+]Xe~t8L"]z[-+ʆO%5Iw閉_D7o>|)N1^|p`]Bq5J;r9yUZY2&]ʍ o..Mb[T %:k2:e+XZ[Z@bAYTYmkBWK=UkV{^saT{%v}! K/K5 ܽ.VfݔRý )Q ujW[)[Ymj]p G3Uʸ畭fgRZSn "ժ59AqVhj1?xM\gTG?7#JG Bg"u_URkˣ^@B$tة*VԱHY·)seRNmWBli}RL[x1D!DhNS{mlIʏʆ vPg1"XVvuϑ˹QPruOaƺ$W]Vy#~g +`7O1ikzFd5Al`˫k֖ kFvbNAj;5W)/&eW^DIfT;VuA2 !e{yLE&6RCS<׺QKm8 z kMP3R풸1LL*UQx$E0:ྡྷrQ0K4OsRI% Fs:_qK92N4cptXFHSZ( .%]_x[MY #X,"g[n=wjO`HHRR /NrϨNF i6.׹X%>ޣ4Y1$3;TMiq!m"4T&~_b-Y3%*$@BnrX0m*:3k'K{;w^o d|LҿlT l8d3Τ,|S#&R80$Q̩oq%Әd5 )1Ӣ͕6+Iu߮f^y$i#J%x;viNJ^U%;dž|LN㎊+׾HҢ.*T !Vy:ģ"eyTP:,z=d2İb^f+^w۔h3Qik8:>T0 iN}cR̊vHPN(5PKJNzz~ב5XI.O(;MJYzE}%:$,TxDt$hF Iaq DC J rR"U!XgG]Rfy~ͷd0|tQ[u1U)1{v[RqwҺ5IH Z屷CH yN͸dsBʁg%N5%5Q ;.@o$rN$-7^uT1["IȦ3LRn-j-^/Sśn׬!-,޲n۫'L鏺Y] ؤp35r{/Pӣt=NQTXpzw::*t%IB !>BHQ2K@i৾XrUkBm]qo HX"C<4QgG(LNiuH^vd`TOgv R=ّ=NWWVجUEBѧHYuhhBd(uף'Χ]G0e RPRΞ9맧IWͩDž`={AwZsLRI~KGг@lEŘDdScEZHX7n%^oޔCj9 abS%@ Z,;*Ҭev(׀`#qWBߣG]g74誥:`i oe'Um;~ Z^1+=hh3ӔL $sATxrhIK|,qLSp9qB7TS0!{EDMTo{ ^tr7䜬M#ZOZ:<|7~<ǞFg+cQ; MhBdEYf@A'ѻGCpf'7σ<T:CWw3s3x*ĐUa *3{=ڡodʝ_d:)7tM5Z8}睸PD4399@j߃5b g|X,W_fE>?'ۣ[7V}w1l悄 ?N8N5B Bg\xƖm-M\kn5&.+;W70ATr2 ʉZtmV4:{ѝ9qL'g9yv=[ڲtbnDCw4!'i/ʹUKz]O@I-2̊ Kiu~oˎ쀇2:|{ʁ'FPob 1`BjV]gnTb\8E|'WuJy#ުQj_L+e`^@6\ir}TQtԂUO(*4n%`;0ieR~~l8F^'c|NS̿sE&5~JZZьX#qYQ%t(w /w9x@E101Y26v$&mmLSTD'%Dע)Ll߉ħzM[LIR C_9X$Y)Mfk6a;BAc &(1Y T\gʖA$):Մ%@eAyE"Ftx(vvY9c66&^87+|!85-\~/Ocmdl'I1@-n$lc7crB~h^ (߿  \xS ?l)Rղ*% 8{TX]RiE$cnm3꺊e*U__1 UDx8!ooi_9r]rF0R ƻP)H@\fO(G\C8+UsÝuj𻐄I/TQCRI0 _֧tXSq;'NgBy@5VA jYd9AEEDEQ02rt#(ɫIe4MmZF+QEHD RPEb!!aʩrW 2Q"ܾOVjҥ5fK$}I`(&!5,;>w`{, \k9[q>PQH}!Zz-@,pi6+z~׿siW/#o4;8MZ TQ. r. \s -J6y(~ڟ\Ի߷%y˖آtx!DST"R)PTAʁlH6b芇Aoal 0)H}|bMPUUJ*<"Hו2UmIE;0!& X/d:Xl W&ן zm^ۃd8@5`df8JmXcƀPWӨ7Qd" fMSy(CzjW%0%y @g݁,; , Hb+4e AN`UA!J e/+)XGwbUm=|"-(;@5xT٥3 4:AE$!F52cQS(dɱRm&2ImIRj,Z%L2dQ&Mezk`uY_$ }VA,,5(n@劄zU9X9 8fJ8dZ3ʷal!mZ5@rYUKsO|O.\MWݮ0!wWur[!kmK*<96;/-ZII=z,RȞ ϼ}vVVQF-4>|Dq84 B{aPsrs8o.m4u*$=ULOzQ0lʻ=z_|&|c[Z 1ġU c{ggeUc'sƘ& N";.6e] ,TX|Pw@G:bPAO```$`!ڒ|3l8e) J؈ăR#fʰur`CObE^`n`E@Hlءz*MD=[4r)˕>nJ̋dՑ)O?+AМpH2HZ)@==#chyp0UC W.s?0=~ϖn`Jh~ _Ӂ@h*3KJXoNuE/ weqfu3ղv@ +r8 Ag3%7RsJ% klv{ y` 5"6Z-WRҀ-F?5(@ {i qn9:U A4 ]h k4$p&qLpl`͏{٤'ii<4mL6(*r =+Cb в))*d 27RTb@8SzսR@937>DDJW IA@H1x#4iJ T @% rEL ؆.Y_Û;T @}?4V)*EFT$BXҲEګ! oD܅IL%e\0 $EA(vGH`OPq@Q-d),tB޶9n "ńBoTHD{{{ Vۇ;9}3ۙr˨]'7_NQi OZiۿG4"6c$D JN'eʌ3(1QVdVKf2da"L;~ "bF_f;Ǭ jh끏M LMTh, -~}^|f̎stT'^tPƓDa$0rbf("|~?xu}HϤ&_Q1MF"&9CQ7yDO㘢 UlVT(p?qm<]\1NqTdtc %E5v؁l a2 6֛jlFm^s?@fy@[~hEsfZ$|n*F* *=Š=$䃮кxl,c%<<33:dEZիQpW<̗\;gsFJR )b (12G '8ƕТDqu]q`NBA⤒!_DEK습OjsR۴#:jVS%Y^#ChEߙC;)r' Y8CK ~!QKHڑ&iٷ`b9>n)VFM%4̧Гf͑tr[lyF CNH.}4ThѠdA4ΜJvL#n˃0PPPPD1lbL8T2.{|6ߖقP _uMݩJm"r }"Q6TS(5*,7nٸ$#5t8%*H@e(qE(pR-*+ݮ4YPp ذ8N:"Ct&fϐmmӅcadAkt/aݡ  C2dBIGv!tI3x!Rh[o؟e%r>PXLLTH/z#^$mjs>;?u|fyv6y$oF k6QZ1P "a@&-|#(!֮wRyٓM+Qw~b 5=eV- 5L(; g7W@OΔ #XK٭l$Gq[lhTRLp 5UxD{L:K+3TS3EВJ #G&o*tfUUUI%Sn9;߽k֜ |+JuUIRU!U֊mJD./4C絭U C4KčhѣFh5k^=Sy=8 -)$$[7mz]8Tp aϗzD8JȳjLB8DZʂ)QiX;OL!is=θ(':P*IRLyܒֵmcpz?H>} gB$L/7)E og-s5\ǬfW-s[KC c9Jܢ*-2F)zZ8ce2س)LYIj1V `cD:MikCz8_e[C# ItPb:{xQN-cDm)aҞXf7hv]6+`!PbHHI}>T9f#@qM_gІ%

Q@rJBPdZ Ax~Q[O3O =,|%򞄄UF"b),RzoUyO f_ p-zF!h|-'KBc"آk)=Fh+}Ɩo4ކXkɩ*ߟ~H_ü~;kjw?ޮo \{B~ȻmKL ֵf-:irb稯is, @$1}H6z(/yzveQ)Hgnu9\Ǯ阠q`zz3|ᡞ;lqv2pɭ19gQepxbP4͈`ha/NKkh v:xߧDŽ`Dq<Ʌ8!1cm1{ lMs@cH"o{E뿓/{Y+ d2IVuŅV X3P)"Uigr,IRFIDOD=Lq”mm8ފr; JlaZ+m:z>X*Q \ \W,x;Ozzs4B}6LA1QChAV)T#t} *Lh(L\lD$IAp fٰ ˴ѽ}VRdu=|bjw|'sZyt%v9bԵn J֊pгb CQUbFyGbz28&FHEa߯P; @=hqX p@CZCK(Pg+L"c 4Ph-F+QA sNC[Pmq5"AA-?xEt=F4[Ґ,"2&4?=P<[t㝋Ha-$iT$pDHD!Ze`* '&, &C!/; Jy"-2Km$@I1UƘlFdh0S]X'e"Ɲ#Lk4D8L8k{K5o f0r>np]."]>: y꣎G 2M 1R-^_?5|?6v1YPm!9bi7 ;( V&j|cMOppKOH|,$*f ȉdLR ~35G(WN2HF̦p݂=uc# oPI,cmeM3eRX¨01[(S*-«F;C*#)p:4- <9c}io M6.t!E` -4MkQic UkZa9 ta@;ս6&8@ J]dl;܉*` 7{zۈ$ ~((H@ip-x`Bi%Wٻu% QkV+FR*ٕoz=U+ƗR;Vڧ:nK*e^.]eb>+'"@L  sj: ͠;65(%2Uh-/[ֻM3#4 1}sحcA6$cK3L O"[ĺ0tj sz @v;pJh1*5@^DK>Bʭk{ٝ$S;G\ܭAJ lZ"wf0QVDPEBû;Ax4 1mPkZZt{w {;,K_mri#E`k}%5<7I#$.-k&:]s8N&{pv3׻&~JNB4Lօ%$Qeja\4m"N`ncȘiiǜ0][kL `%K1,4`6(LŲH)39ɨ3R+: LY1q>TPI=09j>Pt|g C84Agz9ɑf\;VʘZӭ);5k^ d7Kq) Ɔ5 a \H}ihD~Vd˦ ?I?h+P|еw팈'D:=}o}ǀDۡ_Pe_MNRQ4a|5 = -ÀSCakTJҨv)hkemg%6U[X)=26M 8^,/S 3ъ:aC0OU$vnH'J'6&@^""&@'6J%6Nq(&С!EHz#j ((`o }\;}IIdaH!$'ɎyyoS kD3/8gV"RhQR/ ;1 ʃ``*U;3˞Ԛ29]*"p}1=ڃuq ZL3qmJ̷fjIU#"=p=G'Xl61(*O+<)>]AW[4;R !)=`Ό 7*g<Ç6넴 RV'o0ED0<&:)uo ?D\ SNCw @v"A ` Vͼ4F^L|F?q[o7l.Q q\Ylގ,>PP}Emss/ͭࡕp[d= PS ?@Du{*tPi *,0>8ac $ |*:sݩMB;qq ?Q_}=DG_y\s[Nb"#=}O_-y ;ȹ(|G%R<#d';@,hi@z=Xn9BFW(al̮aqs$"7N:9nu:8\bf-2P1Ϸtal*bSc齵l&Gvٗrʻ olNV#a94Dq ,]LrBlmt҃s# +2f4Ə޿J՗DX34V 53mO}gXٚD/Jcl*tۖ/Dfߎ"BLiDIj#cePCC (@Z̀=(itENLq!!K $TR/]mjxUm1mZJKK-i,VIE$!T,6kDRVi[eJ.V%Z@l),l,"i)-Vm&&+JF6*LZf€XPVUE46D,05EjTՂȍbI"F3FōIT TĥUJR""mX-iJl) L̳,̖fdmMJ#K*BR(FְJRֈlDEA-DQERHV[m[dHk%fI%F4dҚI,,)!JL`m֤%[XƈR[U&4YfmFlJIT*IImmd*ڭ,I$I%I$I$BQԴJEQEQJReMeI$I0YJImiel",imY+dZfffe)-+dLS(Jd֔&JK-6JjU)%d-Mj/+j+2%-JUJ`Bf)U)K,R,+)U+JʒKYdSfLdjKZYdI"̚RKl(4i-ԭ)VU%i$eԢ-+-e%ɒ%fV5deVVP)R[)JYKUdRAJɭFkjV$T$JR,H*P;>$l ,>RƧ =w07P4~N$϶U`-DFnF\ 6Kt*5 z#] u#eo;>=4,D`%i3dU?/Aq7Jg 4GT'Km/UP g M0bxzs^ "omz~Dp-EQ\(Cc% Dp!3^cxd[T, QEKd RsDj1e1" L)d&sض8}/cN}ɉ=r_C!_+lYl"6JV͆ѵbJj[+)lEU9 ձQdxO)<ߢs l!d큪)<~=29n)q?YJ_D5*a,9Gz:϶'LN 'g\TIs:Ge>h~4;!,x'~9{ѶxL:DXHH!͈߽C[*"d'ya9x[ l]x}!3빸5 ҆A#&dC̵,=c!TpPۖXaډ7rcIz8VW=PBw>̶J߾{G&bO`\`,0`Xn_vT$4*B&5)330Ji$9ZijCHz|DP=A`IjKHi>| rEU"EEi* !BeMʯ<$ԸD^ #;{ٯUZR)-kG}ѿV#V1>/3>r2:C-̶2H3w%nM˓)~r(V~3p W/lA =R8E[)I2RiRLL% Org'כlXclf?SQ_b7dwCC`)R?z! рHY"<OEfcaj#,%?yO趙U/W8'łbHMYDFFEERM#vXP -@,ۯfȪ5f$5Ra,Q LӆOſwٕY‹=Di~ܙ%H{lBJ@WJ=Y%G%d2Nu创K|?|5op(dU+P wdJujKP;[[~*HCB(N YBx(+l]D bKPc-+ ob,OzT" Dt4mb P1,uU'v2H9 L u }v}x0"hwrRӿ z 8^ Igj+F4Qf1mUIr|s$,$dU_q:irtOtyG݌١m6 GHjN{R[ H݈X@J@ʠVDyI"CdҊZ ikp `4fdᄔ8jFԗ*Bt;^H@q$3PuȘѥ@TnQ$)#.8BĔAM0=ZFP0a 4N 187LWK9aKJoȢ+`0 ' =߽=/>D$zi;&%aFxf5p͹[6jzh9Cjsf#-oϟIDտn2M<9@Lͺ.L@c5yq㌋" v\uv72\ًfQsuedz \c茟ABfSWQeaf[Y1E8t<1~%ӈDQ YAK[h^D&p ẻg#rKIʊP`i!LBjB:ef)p5mZ^^%${=bFZId~q ō %PR˱V}L^̴SJDXimtYQSb!t,EtdzU7d|9 P9Hт"óIh"EjLJ%Ɋ^pCo&@ߓZ_=4)oMl[l'G:#M9HDe;. OI]#y}1e~[-[*unvV4Yn6(т⾍mtqHE/]AE--9$娓5dx,MAT"mdjXUc|UJʂM'֬cßfm$orzhw5c)ռVko2FjjzXcb6qZm{qZe[TeBo…RMj^uD4Pޤ[b nQdo Œ& 6(7R$ʇ5DI1"M,yR#mpbNR*\`ȅH[ݭ-[UVC\bI`nߒܱ$2MXb({HRUQT~}Am|/@#O}OՊb2¨E*H3)|xR2VLQEE+4IIRRe+&Z[*nN)#T5>) |֫ A-^'V TKI0ayCW ! s۸/Nt\,R!Hwm;$)d*Ttdz-GeUY"E@!Ԋffvq(PH""K 4;l7ȒJɱ"(1&"2' QJ0c@ JQ&5s(f+a~1:_gK0*=/sgTwWA$ɥ!;DEA!bc廅Wmv2lHR$ށi;>>RV.<7bGnK"scdUH?-Y9XqbtSݨx;?"ĩr:05l:0$ ѥisYV ehA6>ZUUW&,9׿t50=э-p:Υ1'WVM#jjտe3ُ$C[(CАc }!()RRWU"Jɡ7(e:Cg QqfAkk-HERt64@*Q>cw|MACV< h+M@"H"k2?]T堩Ӣ,f:j$έ>Ar]q 8k,{U2$@\e Kb q)etT R7io})mDG?79âtD]9rR^7W'.pd4QQPJ`5^&:*"cOr4L#{ eHb+5qQs#E}#K7)_rMp J$=3CbaX ` aFs5ħ jҡGYF$gV^B(a#Sb("(Q66$,pXUj"au6 Y PFRdur̲h$F Pލʭ`U% &R,Y%mdAժ2]]`2x#$T*SO$Gd4đQ`6ƜYlq".$ cL2mhEE +^2]Sk I'J,#7F ley5,B4`%@D%FEM x+Ċ*YU  ֹ[E0ÈF!bE/AhށR؃VH)5+sj̗r![3@"A 䜟fSMҷ5ƀ"J4\!o2!6Q 8, ܌ u5*UIv#~Y S=jp|nJm*dO4P熂1J:3J6 hm P>D1{s'g/Gx2B1J).z>#T W;!j}VOAe V Tj",X}P.CZ=4P熂1J:3J;;gqqJTXY| 4=ݷ3x9oF)=@06a%"255fbEU,⺉u**9UsNJ0f30dK-}c- !0B}rfm(K)aqf|p G$zȝ ^P[ GC1 b \?ߊ7nG=Mk|  =.;BƄ%2Z 26$zn(E$CF֕V& 8~ЎݿBId2 ze!𳜕5MN(q4gu]tp"޶ŽqOÂց6%TiiY 8y \L[٭iE./ޱ41&n  DT´Oy='Km{vw[}>M+"[_L CbBMxl<bD") T/uMokMy23O*96T.3ծa eH+4ʶeX2jfM5 m&&ql6)DF˵΃PZGŁb\ 7|k^tM 59AIs3ۙުit"O#v0Q'R9;$h6fbHP0^LIf:̃>츎dA@WJR1Hb6K$')MOa/5TtFG0+d$'/R0 Òh[tjҮmS-TlT6BO[C>2Q[fUɏF9tl[}qrHTq[@-4=@!!B TvĊE[u-Ja۱t2BBE2XZ   6 E,H zHDubб,iX!$hʫFfOvfzwp9xH 9.(t xtK߹C_φ$sDMn&*68o#Bߣ̡ ,hP ::'aRIv)1NwA)=4,יZ6a_ce8-L(c( !?_,B'Ο_C8=Oti 'Bۋ҄bRAEQoH9}Y>:5f K*EmWXd ;8aJG az=ȟH}ꦩaF(+QDK>h EV2M2>#5Jc0`Ov.z}u+CWV~7t _۴{ϧSimmVK˚/t(NTg p]l5j$AkH$A:%  &"T(Q@rp E)MFc8OsاTD?׻fBzKLK^G R=ӽj)#!ZQfVUUH@_8~^H CYM˭*J;xSg5z{$"j8Ir~1)b*Ā.N%br Z Dnc^a YH7Y"F#RϯX Tбx;_cLZ\zIIabRݮM,HW:+[zw]_îxTIg/4LC3Zܮ<^f#ӌuVR m?L $J$BUΈ[/j78LmHmr=iM2\xo7$ۤqG֧Muy*2DoRM=84oߜ9wG=]t f H`b3`V$q~8a{(w# =xݼR?@z[pb xmn#1 Xߟ $[{$r~$rtBOAەΩ^-jcܯ^6sٻۧ#8gHH:9+[p q^N0َ53"js1+WlqIej22BI$hεM6t1IsW#ǭyDEp Fmأvms,xo wdɬז 1؄Gv׋,A""(Zʉf@e .˸<\Qy"#0I9k..빥]ՔtE *Ldǟ`[G8\{E$ Coۯ q]VIDQe&MNcX@2Z5}QcBr|3 R *vF&Hn>Xm!C&i0^"5^#)nD2!HQc|:#j*;Îdg4ٰ5^x9Z-D,!.r`+$!L6(4D;g:2X֓PicL) $%Y?(Nd$ksfxA1 쇆;<0G7Ոfe4#췃D1$R !8"TKLx{ؒH$'U!CWa93 dmOɷ|ÑO2PZy bC_>ZDjT8س`^q2g gEDoG({?cEHШШ[m-Or?K#9C/M6*UOvL3w^y#j3X)2Ǟ,&|L}o= Y.:pNOSOIpo Ɯ$ 09fMVxw莔ީ䚭IM[o]]2$UJ D$q+uUˆwW-BC$@LbegmKrrƀh_sq4IyR'dJ%p./40BhYlB1P`^BBK0S 'R!5(}*I'!i[pg $uH60BӯS ?Ak7FCCY6lǷ|mm{AmlA+:0vHMgshgc1  /TQMAs]ӮL x6Q!E/u{ Umb^QWs B*zU@"BEH!#A =P3a0_LZQax8}=ؖpĖeQcT꩜5dl[WZ@$aqt6>л£V|C60IǑTlȐI3qIaʭ]+aR_ %ZqiS\M%!w2('=0,À1.~ DmrA[A %~~o|XG"MZl`ؚCM YDcVI`$m|؊x; cͰi`:,\ y$=!'*,rY/3&67T@~86WA[0U]*['A^IcU25X Ai D4ɴz&y ']1[z׶tA{ZoO!޽dU Ew4(_K e^BȜ .* X%OdO!#>ˍpޘV1bfF1lG[I %"Wz "F!D|~:( ᝚cY(ˬ9Y9ם$$%SNHi˗'F9rKVm[%QI S(sj T43ME+)<*jo"""?7>\)#+Zf BH_=yrGRA WDs6N{yf%8! $qPTDoi؟4脮 <̓J8aw7~F*;M<ةKvpp K iMX|.`pˆP ی& t%Ԟu7"""?˜DDDDD]]t9gwnFIZаP|_uR0""-Ej%C?><ٮoi,]) ??~] `HI幄 ɭiB!Oz ~˞GdzmW$`TMdԕRH yּjT͹/!k <`$NE#&#0`A9##$"E,K(1$ h`%(3==I[wbMBXNY*PUdYB{'!X4.Z&El&wZJU̪U-MWvM82 `Gr6A0a6MQV,L@:ʹ;]LieFCPt0]/%lR5XMpmިUEŔXsnkuSKobmH7IdU;`r W,q-$IpGXY9E$sk>]&f[Kb:lvd7)E,Ij<:c3 ~+k5{o3IML66CP4hCi66HPijJ# 5z^}/]|hR-Tmn <}%Kÿ8f~բTUbľ?xQSƱlXjIz$,VE%#Fhf|/#3D=fh^5:iO{0~`dCV%n|7R XɒƒIAM#`z`;XLhI#qMSm'{yqm6@ 16P HX &fEz/!~\쿼/Y_˨I!>ķ7fx?O!$|Po7-xXtڝsg[ZQ&-L&f\/5b}!44P~?R_w В9,$D&)$nTI$ bLs$JR% Cѯyk2O\W4#IX M)K2!LO_smj2*ߣț*%OMY A0$TCr?%ۮAxN APC oyR$F's9VfGFie5 ol7F,aC dlKgR;YX Bbec\2q4\щW)nljsW-+l&.Rm a*PE`r4!@i`l,*6Ti6sET*K*3k(q˨bH@YLfs4FlV[jZ^˘2R[pǞJn!bpzlR 0Uf6PPa zh#$BGbTJ2uN-f[p6_aQ4&.Za#L2 BPZb3t¢FX H2ARbR(XiQ""smzV5"pF %SfKq0 Mdo2ΐƓ1 |0;p+&/@s*2Z?-o^>Y1D*3h{'ZZ).$ O'nv R9=1yIhL~OB xCk +o ۗܵ|>"iq=3[|# Oذ-lm[جg0p*ݶiN0~sR"1?5a 9(XsX^@#;;/|~&^IVt4lG >E֫B;g}Q$(tm75bL*2ЉV8CcДy&Ssipu[_ ڧQ|s@t+s6*f[ þMQUQUfة수KipjFvy8*/POH`|º4͛s!! L!z\EB -( >n"hw)߳e~ם{âь|;U7RW@399&\qqqZֵkZִַGo{F"Z^Dg9kZֵkZ>5bsflco9s9kZֵkZָscq'ۯ0 .GzRb)לO)Fv/5+C;H>?5Ѳ|=ߩ5QA]ޮ5 3UMշ|i)8$Mgh$0!M &Eh!HaQC31uhI5y vEfFhGӘX2BNP]ܩ!*Î&JE%$*z˗*YMŧ.1[ZѿZ6.FC$~y\ӚֵkZֵ&kZֵkZֵIkYs9sJXtjc @ђ: )&YxBK33_fԀ]_\rFpUjռxߧX++&ƴ*pXgb 5^ +^@ A r^{ڙlҌ6ЪhxZ09+ganIdѷ~S-V8J!`HPVAIEI U*S&i^X83Fҫn">AXqkHuG9t fb='pw3hʧsZtK< T;"XXۅ_ԏ1SQ`<][n3lcK4+aC63Fϧ/^8W1lmccclT4s>x # nVwmI7FqLEi 0}<գ  # j(ٚt۴fGl jLi cĠZ358k=xǤMs:iN{ 6)JZ2`t2$b7[$u^otI&w1wq=s&C߮pe2̹*NG{ra&Du;}.wY=wU؆x<]^=M*,m+<#* =?~=\H7tӏ@}{b&J3Y^5phqOαb1#<1~#Gi@߻$6.P^3ȇ{7l_FTY1䄛ˀ=BP"\0Bd@8I,/1jr}3~omةA @:98IV+UJފMN .voYƞ^?|ZֵkZ"qn fZu<<γpWϻ¡"zʷ'LvV*32FpkhkХ 7nkqS(ku뿷is\SV׏ks}o}x:M.4>&T#\ W<5^Y'2}]ݣ7+KJKr5whܸoۛbcwǛy ,V<Ldql$( K~>N7Si+1+g\9(׍W2WϬl5UW F2no>N[m:F1 p~NR{BPk Υ"~(Y|+ !]fIL A|{AfMKCp2 zOݯYd neآpdNYeZͦH$אj9&z'[hY@š/kZ&$ !LC;-߽W2>*\U@/ui8Cω!sHJ^W&>hz܉'E&1(9P_HlڧH5~60 $HDrDI( GhUtx#)(MƒҜFTҖyTwؠrKŽ]g:4-hןQ|CǷ );h g:YޞҔDDDD,FrI7SOcQk:y܍@ѭ 4mxh1ۮ&lZp1 l2{NMN2H23l' m*6hZkӓd{?75VG|,㋕:]e념i~y׏;,]‘}FۧKgTu9xח>Od,̄ԈI2KIL~ϊ~K}.{VX@L!! @UUU}FG)c[ݎzq鬛ÜxxrۉSdF0@;|vuC{C40AGbIIsV0]ܑcK/`x(TSI-b*QٿdM!i*˱ BCxH{97USԔ> ܱDQ4nIݭz =7r~~}o_KQDL#KF6_c/߁!m,m7¦ kۨ5u7e~W-^(3r~]?OKҭ$=}< 4خ.D&)4 ԁ\}7IHD jus s<>]s7KIfSSkfF Ĝ1 5V*Ev+2) +fS"$(窖T(=)Jbد xd^;ziv8RtdvKp ⧕`_dpr[2C:e҇3O85,p3֒I]voRvj9m ;1mW't7o(3!"둳[ЙG\^ZZV{C_Bx !idE/^@X}_;?Iƪˁ`WC `/MTRR8jPtQe$kk^~Fo՛^{܃`H+ǦmNwv:Nn6HF;Ԅ3pv-5n:aAIhc`U  Rək@.mnv2G$⼰#[fI"Ĉ*G)i31j{m|qljn7{R֦H6monkUvDDRO-HR nӚ(ꩃaz9}OA/m74 f GA5QDJo7ڇȨ TLwM4OQ0b|뿊ܧ]\{ Qt]A46-_ (eEо՗RVI.nQbɅB( yokl@hM卜L hKk>X<ŷskMF2ɤr&AQ uy||&wl.t"HxQ$$!$!2dJI$M46}rU$Vyi@H]"M.TH*Cyh0ROT^gIh&PI >EEĨ#U$/"xd *-LIDM&ÅԸǶPg;^uW/6qcy׻! ݋NȬCvE+BVw[1QS;)Idy?m-C꽾iOwJ…^ (z`+sӋp3凩5cdar( YHH3 2*}j~ybQuz?`{z}ng=Y>WtQZ]RqAYs !^5Sr2н".5*"OI0'!,}kNl Ds*(_|bSp^3KKs*}{)O03WBy"K=$CKX>*ؐ"ם\#sΝiz/[ɁtIn߂<Kyr{E5 ]i(ؓ7}aƳE=ޘÉ9 :|s3?T'&e#!#yNdV{k#~@2;I>^ĄQ/^_5)([e^]Vd Q\t7ӱѲ<Չm4,\Z姶#n:6$361a ŚpIQ%[clu4pQk3aAsdnbS;0j46v)+AmI7RĒ`aJT#4/ےeGrѫVB-Dz,E/`FDlއ\lLQ# M$r!>ٰc*mN1zQt5IMZ֛ *ʢpݳ-n|r7>Ÿf0d#- l}m \,`,_Q8rA7<omHD#t9wete$d8\IäY:#6q 9.>HNi$|R@{o:JFלG.jvjI0pv;Nwu9 [0i4ؾd%cTL^ tHEQHfHF&):om*ЫU9|:Ag.pwG9L$X!<=A.9I0rл9&☧q*UnNol>fSk²jk SPgųv''o<3߆UcP@j9=!Py^׹xK.jrCፓy䟾6פ=[SCQ{*TIiM6?ڈ5/6lum C롱K5k\RcrTePE%톿h) ]Z"T Mnۍ;iTʵLE.1y/xݬ_ᐦDEk=vީ]rf[qZ{y-U),\D8J@HF1+}s[[mƅ*/ck\ O^ز'?: 1?)t?z߶~ֶkյNT[նǍ[l VUm =j11{[ ̜lcctL }hy[5}e1ZH-zuHya_7DuI[p̢32#֐UVI gbc TGoΏpP9,K6gT` :*eX?MxkoPT^&roxByx;? $Eq",EX6-c W?r34c$ 0c/WHBr s8C˳~e[%"UZGs f2!@D!w0GoP+U2Aҕ7thڍ -lUmef7͑εI-u-H-$DLVY" 2NR8̛ɒZS A}A 4Ҵv+P&xX-3$l\*V9jhL+$9`]M! T|9pfլ? eJ0p3C@Gy[fKaf':S1CLD6-rm乆tNCƒpu 5yC= Ⱥf;Dx&GV<^! Typ #p0L!^~Dx+޺9He9K$*CS>{({U'Y?OY@.a~Y@e!f>EEHG$ HcŖȰIR l) 9y2-i\j{͑DH"Ĥ 80D)I[:=R!e-% 3f|M5-q)uP8J\ΜW;XZ \vf7峪8bZ13΂Y13~kSvކ31kO^~G!cSZ `o"Pm㳛w=09޾D{"`]E:Z6;Pr apBׄ7{3|cg1@ #4KPHbmOD[b9)tC0Rs]M哮~D u[윈V)JDDw-K_9b|kZ\njiҀM t sE4mx##G * {)Sӽ[Xl6|F"E?ni+.KKHL "#o:{{ե 8@^j ,d2I3&5I$ JRʔozxzJ/iBmmq~ ?'BUd=.ss7+md{xh%) .^grpI$ zH)?ZWo,kp0R_ڷE+2(,bM(ܱ۫ zp w2o;L6FlᎢhE[ot:i3m7rUPŷm5mb̌ڍ,-UMnwpJG E&SF>w|!'4^NCcR.x]7 C/.F02\ˆP؅M݊}ać871rkPA5|ڝٳ-KyY M;zp:`2 |DަEd)3l3 2 AGYwIH%?.I+sX$炜}=^ۊ6?A \rI^mQa!/=Ѵ>mCfdYŠY)]p̠ D&zy·u}٢$ }k7; (#rSnw1;iĖt~>{蹒GW^d@3@\K>[| y:D7""D" /aUQTz!YmE{hѧdO9 vA'Lk)-EJ Nka hTUl'hm3Ao MñCnL:ߒ¸}E]H"I2Bdz ͑&8XMZD2(2-FDUT%H b֖5dkd$ Kb%֣͘ wBm{c %0C'ኊihpAb,{Qۘ*a J?!$%'^P8'wK4 $ItV5V rX.΂xG߀:!6'c Ba]3BHЪtKЫ1Ts5bQ^7$8ũ`O \bk%(,Oci% ¢DL*m2VҖ0D)#cVE"ʲYfՒC6l6lŦVT͚1MZi+JUI-ImIVҩZJ[i2Y5[d'˴?T"@6Dl]^77urm9{G4cؓ! ; d$de,Y x# Ye0)"bCNdNDޜb̺ bj'&Gx&#}_ ƇZ,3p{!TK ȜϷ èg16]$,\R•i-(m}wVtiΒ.BEj8$)G/A4>;[$PQ(xXZdm~!0B!A:OVuDAxfG_mퟆ661EClc87ۧ|vO[17[!5#s_L` K5TiV4$,>oaaj5(q 2qb ZNB̢d(II:H>|Eg$ ͝iZiIuE]cFًޤa~ u(d}z\L*x "M7؁ZX(,h(z1]Щ&Y$AXz2&`nLAcc:(Ɋdݾݯ8vmfT-Ei;F,Ț*IZ RU,\ѳv DЕ84h LH`2dW<)b!Z7'F|<[#'Z{E'O2ae!1nQ2LOGZ 5oBm˗ m9U[_mL܎P Klln'ZIŀJUZ'yH b&RQD \YNiX畳NE8^ln[MTij;Myaqf1tN~xu۶۠uq1W}D._M4+>*V-wxB@Va)+6rY xXa NrlgRVB C(IL 1h2$X& !_ūWڟ'G "!ڕH!eWC{X*A#xܞh^)/F<߈6[9~q*@@Gx(*|}q+Eu"FZͮP̆H(i˝hffaKV+t\K+"`A]4MI2QI2Q-IR*ATLՖDD6 Ónͼp 2 #R ngDK ?rK4E/_G5H>i(AA$Bi};Ljj8#X""KK/U+EvrM A)s^M1ӯ>-D]r.דּK2J"[4El XlTY@-TaL?y~%̭XSwoS6;zTŸRIxҢtVjWP"|3C$}C%NF3b=C?;=ib0D 2.} AȖ39Ryy$AT$!@@$1.lY e"`{F<>dT4d7<w N@DSBh5("e|3T{^+_)ē.r9 CҊsF@W3e41m*JBV7R 6Yzc+jO)-S^f@N8b+Sfjc}ı%d8G/Q9D413FkH%՗bLNH +A53|ۑ+Zֵm՗+yzuUB!Ȯ'9҅ T(W %*xweU[FpLG x1gswjhhX9aUT-l -M?Qwo) w$`mnK^pŨk#,!ͳ5IŅ)feDXoXLawGÆc%cm9D|@;N2Q^uAݣZ%#5HVjW0^RF 1invۓE< vU%T:C&>:U'n9n^#icF˒YV3Y&ZYTm2#HBLXU}c|w<],}nRau\r|Ey//eK0/jE(*## GLR [œ΋VNB7Iq[I!$HA"5FԖ-AETQkPkQ[DEkR$I$I$IjAQtڴZlbMX`"bDF0[F4F5F mmQƠZmQIXF5-Z""*J+2#Vj#X-Z6*jڄՌb&5 EV""""5`"H6kTXb6l1ŴjZ* Vبk4b" BE1 @!-ZkhClccbM! }rkf^:th4 ;xPbQ. ANgvj DVh_aM=ML% J>dƆmf}9ؐx1Hފ0c/48=v1HYN.s HH5@˯^ѭ .G9A݈AqU7BU6!!w3I.m",(H62j$Vw0D:8jqe! 10ش&,^CA\l$%E5Ab$@AFM@HPr(r[\JVBlF/m{mGb&NM&wnpSѽ&nbHd4" "sZ$]rc(W -Pyuɟd &2n,A=3ZBG0:dа5h Sz=qqp4ؓLv! bǛn6*F (D>\m%%\ cIjH6G-WďRجޘuT4v7xݦBv96 .ďa4 f`FdJ$H?ۯ\"fM6=d֍mXAeLzk!yyֆ.UhsmkGZE8cGF vR6`0N-L잲(e\kCG]qpڭC+kZ:ֵیq!:.+@ qP봭24! @N׭瓪p9J[&0*4VҰtRF܏l`ݎrR&(i4$XbSf0饭6lRѣfdX))1iMJTc0٥JKRҸa9*1[1JnãI۹(؛k UaYVJA[uץׇG74sH444I+M a ZF&'cm-jAVIUb&[0E# @,eewٶ q L5ƛUsLRy\@غ(FrNM^gf@S1̄S Xjab[Knw*UTjVp:(7Ljpf᧣)} ޸%z&N2 @IBw"\^q@`wwq7p !~䐒 g=$NЍgu(9FlLa.ANtt.Ļ` C, oFB !cDOOCMyZ4YQPDdPwm(لH&Mvv$~^9㲵owI r1>Z^w|vym]=e3կR9kik[mg7:(7~ҐS]fvXxwVߖ~|98ӾTTG .7S:,B@9)D*%)F8;QR.y34#xp޳/#9klyvesx[٨x'p6f^D`yjF-88 ŵbD-qAd/S֜i`Cֹ.qaLLZѦws- b^-†?a~HbH6 sٹ\KѨRF!(ұ&2@ 1]b"3 QkBDQIR2?KN%($EB( `7$@DBS!jjC8GPNخT8yDb6m~~VXtS嫰#c _BMYi²+6ڙD،#I*R(!C^!|ɶs1j, us ˶!]L?Ǩ ړ!Kk`6itn1`srt{z=Z\]AWUq|G$DoapDq c az)ݳ/:~y,O4 R@ D`dVEPEϑk=,9NɼcO+=_ɫ߁!EE(@ ]Od6= "{PYG)I)`O NTGv㝞qf:qޑ! RH2`c.? ) #wh2{`=S%1P9% (CU^]O7M (銈6~96USdzszư/ O>di䟍>/f!ɚ)VaOX {{3b)`#E)MT(Eǡs# )UN'ږ@I ,jOi+ȇ}n<@A:DJ{Z.GZ6I`s-l)i'H>T (f (.8 $lV l€C LRnQWJ6sn #o*w%}Fsȴ\h☬H`,*Az"> g&$Qi t,Z'-T;VY o|x_"8ߗW;cY6S#qo6053G8"}dO [grBt oGv^xcRyE- 1*RcaE- 1*/[cY6YY30Ճi(V8a;1uF9#08[?yħ{Ur1FF4ٗnNxʩ˔9D4&U)'Q FI'YȺEczebTڷ6F̑E,Tͦ14CJK-[jYf܎ZL cMÐGR8DħPb-V4"/T_&VHo'9Ε5ͶYr0ס sq *a{7Xz[]Ǐg9䵝kvvF[#[a$d7' jœ.G[e4"YSag6-.e6깮.mmȰ1)cHm)TU[-dlm&Q f6LɉKԥ.$hU^KI2+T[&ld5uRod:PͲ$5[ګLŲ:CrQռL1Eh"஻w{!.C,.wtÑ"h)I_29C:% tC1P'AFTb-OuhDeERCXYꛒ|;|RvŽN;RN/*˙ uBXI2KMS3UqsIF0Ŭ"0$ȁ@k0k.32d2*BRFU84(tp*`Uf8I?Y Y5IC܁ulTWdwPΧاt-~C|pʴO_#!ΔA"HA$ EPI=⻼o4HNz`+^0lD>dD\ȁ8zOVp?1 Jjaw(/^Ifepύ_!@9Ǯ0O+]$@zQ :0(COw]|ݴ.u̦:F%LکT#?\ImXko"" FyptpDԖڄ%!:ߥbHZ_M-nrrǙ\Ј ƕ_H Jz.|~-\jh-76q!13۞Q%~;)$Vd1UD~ŷ6&cZٿkUT)D G "`4HGO$,% ̋H PuA\HssSA%`/X+Zmղ%,q;0y5D+*d< O^~*PA?<%qn1o( ~i)ZA\Nh%~[jWrH22I)EDP0L⊼i(ᔫjK"cK@;NTRJ$i,nJ:Xu~vGu|)wt[vYb`{@k<˨HIj!QS '[ queg0N֓'e։ZO혦HΓz/}ߴmG.T>R o;35Q n͜ow9VnMh`C?cOdn.--.b_&Q\qb3dql8E%]rst_fGzcm/#⭌mtƃa74wJ& 4vbH' #L`'u2nXm  : + 12H 'U?"> h i~8;pU[o - r!=D9t67aVgę c4FN+,*M!T٭,O&Ă- &))VbkE* 7h, hT+[eTwsjqĜy“zpI# $ZDM9l Srg\rkֺ)e̸a"PSHT ' pO9l:}h! 9}|b nXJJ%S,-$-kJ)5|&A1pfwYиN9.3$ Wc/j~*}RmwWz&y867x ;HdpTA]\ 2g9NޘkV3WxOH9gW8T`qy&E"(qJ9u]Rħ6<`L-$GKIE8ףg7[V̱ŋ "g7M~7U"GG{HZ-kN0:"߳{P"9:08í>@~&fTMFaf2QƈȶBc@X0cY qEHˆ R wH\2)Y4֔N B | $HaH~5CC_d*٣a!%6+_GG?̷߫n[yns;{*m1#T&LH@l ` )bY UU"բm'A M~xl!P8 h ȍZ`Y~. h>ܭ)9’"$#h{\J±bqlKYCm6mS.i[;KR0RlUbRX t>NGusU,+r|\/pRR7 0s"RJ,nzI:7DzFNޘmy|yִ&LH>c!fy(mS×G"n$ANìO؞мhG͆,1L0T$d5]q pS]ЏֵU[E71CT{=~hGa52bFQBK&+R"F11RL!A-@"ɞ2IGWPwBŠLՅDdGU=!C4RLZL\*'CkIZux=K^&K %ĿفQg-ۜ9+.4gCO!4PUCF՜ֵۭ-ф4tҬ?26`/瑲puI Z$?MC.KDeYd^E{Y-&Ջm+1 $`7$K6[IE.*FSă+%dwU/T`04ri,_DL 3_pifC@Pyl*AUrTi(2%*k_<%Q!1@JL*0ş9nxAPyGE,,8n7c|\"eVa.:;@^0~~kQ§ d/G`}kTGdJZ8.sk2Mïz?-kڙaC?FOƿYxҔB^A2.XZFG<(bQP2%+/iUq4  P8c RL*0 >^$L(Y#IK2\Ug.K{ADg11P> >xӋ# V "8fU0щ$TRAFJbb,eԐ+c擤~sϛz>u*EE*i~UEB3vY?~LZ֒LP(5IK<o+Flaϴ睱/Ie=ջE| ((=ٻicvfb}2*eEvyM85˂jDG0EQUZcXE0!"[=Hb]_@n J `rKea E]d̩E*sR1@ai $V%ϕs7 |z*$,)mVuni"$K\f>ğE10E%P2f\ ΀93tE" ! U?7 kog&x%'8fak14J8qHP(dT L`=.c9:zosDuM> -oigƹSl Ѓ<,HPd$;{C}٤O|y bQ*v궣h{X@#֤C̦ NDznK竞A$Z& I#UUfء+~PQRJ[KJZZZZҲ4$̑UDQZLZ F(4E4AF(4BZR2II)&$f"I$I$MNU-Xl)UUTIPf1m-IZ[JlPf:TV!@v^Jk.,3*"RJR9b#$HU*TMkF*Ϋsj J JP$ *T K6Mm6fɒ*U(JU iC>q詬-RhjZYXl)^O@A.)B @JSzفKC N(d읖M^{pIBB$I#,IMmI2R&w.RQl¢MUUq--MqͮVZMڍ٥ieJX-%IO랄H7 =ʪwlG"NK(HО Ƅ"L6l .493'CꊷRήȳzwXKBS mm*jaR]CN .z#lqNٻAM\k3 G'BB{:Sp1׼* GgBݕw@i2661ml"G;p(XUua:l &ɩK[+y UZh 4p6&w̷q2Y.s.[$liH)*=&S7_dwm$8Hd5WkfM ksvKlcuZ]? ՗lrōUeo췧Nn8Rﺖk׎@D3"q,usdya&0%NL Ġ!1x ,,mll XI[ qNȖ@UIc@*kL(SLj0n`Sf s^ 7) BԶH1lDEӮoӓYv^Ii*`B1 (,DpD`dHj]f~=Nh (`V*%ٯ5N&ª!?p$`H 'b/"6ϐ;^4MI^Oq[CYLv.REna߈N94Dz=Sdv41yY(65>@*N:e%PH< |cBjF|ZJE`l%Q>ZԱbt—bH8|N6V' tXkXY`kKS7)[6$)^UIUHZNe[,kdz.k Obtp`)/BM63Z[YٺZt[.^K5!.L1ag7lFE6#r9tv5hQZdf߯ioz}wYv!h۪Wh퓬a4bXǽ;Dm?HbQeeI);M$V CtGYy%f1'7ldq[!deQR,YiIeG# OX OeVBB7S^X5 <^aNwR]pGlv*ҨVHڕЂrA>(wFy}º(\VF-uA(B*Ĵh$(jedš kY $ $cʉPpDP+9+HWim2:C`>e&֭ª9طU5$+F1Axa_=e0ܩ"lBTR(lU$PvPߚIo"zԧOM%юܙ(5CYdC , 1X` C>?(WV,a'8/Ucco6%-P,a~T;6zZb #ߒrjBChU|P94a$XGuϘ9;rNRuAa QC&jU ]ɘIUUQ˪7Id)bbX24qҩ,seͷ.10(`%91\/, FbqWhɴTWW^h@ǟ$|hR*(y~ =;׊D<9_s#IAjf,ob`쵞|D9X{iY0$MTSC>9 ! ݆uS4m5Vo{;mdf0" nrNduW1aPZ : Pr YF桯+wW%LjR.#߲2=+6?έlbq ED2 C@I'X)!hED09N)҃Ȯb`k3։s`hxHvΎr9>[ @crgQ|NףA56v! :&顝 !36Aٷ, 9{!5}A-< ۮFbvZ[w0z. IZHvUƊYZQ,#st֓j$Œ$6IDISz?sDo_/Lۤ-I $TBZFMISe5[*Vq٤I+:ߗ[s`;s:y; TE#Q{^(+w\QEE Y1JQTJJ>qJnKKEIS]絛&!hdJEZ^[oKY-w-20I!d,\*;&)x2ݑzz*tO*smLG7݋ 0EYSTښ"ՋDm_住PnYGk.NlJlSRH}SҪ!7`i, $M6[>cv<]2 hO8u` PC}7|'s)CčwhE.&'W}'Γ|S6{>69[9DYK2۪j20, e$%,S 0dQ@-Ձ^'@'됕yb Y / M5[q|f蠸 8PȲڠ>uJ=n9(:Oj4 ތ<\.%-R!G?.|WY7'ZO?OA$v$KdqTniPQ0N@kIhM A&ڌ#+ ڷ9Z`CA  F%Z4?-?•Xm*aYkT!6E 2Mb2F@014k_1WneiEEq[hCV400 bm0c49Pcc1c8A!#H)6mcb%41 &M7s +9͏8j"i*niJ¹X oke[c& &JPTJDHI1)10INI[i'Q*HLHYDA$:r]MQE FJ)Z쬶U aoزRSthidՑR/C{f{aTĚD_ }p+0"[upV%nF1%WtSWl?OmC9!Gm#D,&[ :S3[ Aٿ}z!L -$ [ow y*Dd" !Mźs(J6DMR Z2Ƥ7*Kx5ܜT #l%&&Xe2 ,$QP$j TW bB"JT D 0EڬJVb(bUPIV̘JLUVL,&eJ*6T-M.f`7i0J\j 7%ES6˩j@EbBzY69O-mn[\*]NZĪvh[%}jCDL$RH$}X* k5 (6ս@ IV"\VV sXK<^'LF;:\A=Q5Tf{ibVn ״څ6|{oLm=ȕⲥk~=r<QêNr8bń^*=ryB!Xʈ:顈0 ֎KC QFHŒDYH@TRtw~pUo~? O%B, AV$!Z j0F`E ]3CĂWm"H w;s7w sXI$" 0a##mï*D=&Y28lbL7֤nN%K_GiK'eUIc}(M~znVdkFV"Z_0dHJ>i LuwbE1Y%X *_k )EvH '$H텉l vwXROEV2?Sv%vP587GSG;{~<Э_]qҶe*YK6N2]Ng LF٨EDv$R㤢"`Jcr(ҤBu{J =c9Uhߟw$RL I"LΊ$+3<Ц7>vEwIӍ\00(hޚ_N8F0GiGɑl!l;XݨG8zJXp]H|^u~ Aǡh*{`#lD8tM~xFɋHl9(ʟE1F0؝D$KSUpVH' cm7ѪݩB ?ۑ2ӨHnd$X I0,˛ഔ\sxrWQ/mH~?ۺe)KI)u lbYqb0ToKun]η=5;2-I$1N|+pU5Rx.H5 % ̀&VO?OHܞG|$pK|C·;CW$$oZM~VH  A@`<ɸ31"Lũ*TE"//H9u4J)0 ))wus5Pz ߁`j%"X #"afo$9!Jd\F3dJJXܶ3qR7di > 3 s~N)˲4&c~&Pbcs6OF FQYИmmhBD.USN#CH[QT?ҭS[=9 ȯjWˆ:Pj9<8(mOU|vd!^kQ/ ȩ>"v =|)'44-T~'nH N٩]R?Oύ8⎖Zg!)ƕ dOg nVZOfC#߾|mB+-WFg \HFAP!h< <Y<>*=9w1 ?IAo5"Y>PwXO`Ns9֜Ƨ$=a?c;UGEEX1V"}(^!Hv<6V@ɿIճ;e7u%kcn#m( X"T䊤 Rh6.&NL9Tm vy-0VȨ(R2l0X neEPC[B$Pbd"jҚ4Dv!ȇ~_˯B,aΨv61C",DQԫs%%/a˟+MF]+omyYG)MAK-S9+ZM#PTcxiMm4?vҸ6Xm~zj`6`2*'6$RAl.nRkfMTHA%mː85 y0lfc7QeU]+|] iFg*ʃ"I~)lIZTYu6KXAqؚN4d%P2$!ചQNiD)DHIRL),vB՚lb 0bf" Q42@jҺ,rSUG¼6=~7MDTAU1IhBX#(DR$fV-ѫ",M(ҳm++IjrEo'؛[wb4ĠPU#!vjdi&ehTgY#A$":ENNR6I%4i$hѤm]׈ZY,) U$**-j5h-H,7G?,{|"7`ifRJIExA&Ŗȫ p; y%Rb, (1a[q!b'qp|Y$C՚ЏW:4ڑVvHP9s8mT?R)bd 8$% ' 76(ʞ44@- V 2DfIFlF1* #(#Q .(\ DW`Dk3i Y$P&n=/o}Y>ou-77Ʌ0I{1%K]TSl2=((:%b1FPҎ ,14Fxw  x@H*;S6mvb_]EYs#TyyƦ|ž^v7PX{r>(.7r Ŏ!p:ċ<6-y@.w ?SH'iR5Owi.\~< =-H MIbI#b"7L$)@bICO81M~ N 0C_$-hҎ-X_yyjYSc fBBG w 9=I? *I4²,sL*. nArI p F$ަ^|-R-Ѷ J"L?9HP5,)B goUSg0JV-Xڥj"BV.aamnGU HF* 2jM)xV^ނ6EG~$da$6.y̐s_TdmSpNXHA" b)% CxK6nQOvd218-KBM]\Ѣ[ͬQ,4 5bs |z7n Ad Fa IhR'(FL\2[+!dԢ@[šv)VcB&``]_иV uL(MB`Ĭa_+WIeWexqq(k\J,%Rũr4ɮW Fd,ŚTDdn \'st/Y+d=V@!( )>(D3e^nwq1qtG$ôgj߃8K)5(J2(zC%QVkPs_c8*3ؐI2HQoIB09ˠu*Z1nBB׫}rMFQM/KIQ%+'TB q%\ ,ZZ:0|3ZJKz{`rϴ`GD e'ĐQ MG3\SBw,.H1\/d[]F*A(( ZNa6G7y) )EFX0VߜXY8ݤ|ƭ*W Q Gۄ ;z8\d >9 ˆT U2_y{8tF(``HY%G4>ym-z {aF 7֛C#oDen-1kVM|򡦸$fէyZ6i b9C<\ M1GF*^1\\\^uoך(*:ƧhT*~xK[pt 18i&lѳM=lhC0ͱh58Bh6#2JGT] 6H;3D"%5t`L1G~xK]8:L"I|-ٹ; ^f7Gry94iCBsbM&پzt1!zD@ GsQ9]ip95ns|On(q$1l+ ̪Ob!D¤ ˻KtCX $)yWl($ BϔJہlj:ZMZZװ|a; d$lg*_^AZP<2k wSMë^*<8W6aJ)ClkD'R4w#Úl.lwjq ~—k%bŒ뗎p`R*7v sDL"@|6 ƅD"]FCS{[f{=qrM4E+BcIE Fgiv;" KD=kSȑQ2 j3:Ƅ0ljcg4 5. G7loѱ҃6 sdzV4" =at*S2,n& ;5f4Cv6 ag{H(Nr|8zfuԖ*H'eDSĘ4VU8q Vy4pEi1!\,dZF6i=2:& ə(6N0)-rblShK|S=y*gg@Lq3AAw;q 5q6~^Ǐ.:la1{-Y 2"DhZwBo__Uo[s8IpdjKF3mYk6n- @,)aKBglk]!ȉ@Y`` 8 GWЦʟY>67|a(5%V%4W5RHY#ZTuzʝ,\$Ję=T%'Xjr h7nynq# 8ab?`M^6+gù==i0z =Mwr)c)s]yR oC%Kz4 f6uD10zm+`|C~IfLv\z7s.۟`{b`w:wᏚIITvaw@!@lPOýY] ynk!yyS(. ADU248 0y9.^.Vd656ĺ֙DGxF&g~vD_oMފr 4=hI1q㉃C3(yD]NHl듐|fHrI$1GI$FH1616 * uT-&4bf(CHbQ hPd0Ȍ-M`), ,E%QI !(I3"ѨS1&(ԭ$!BBld$3.I7.NnU$nn(Fp!B Л.srM2&sssssX @ J%% a%RRK8!HZ`*@A.o+mPiuz8c1G@cki?;@zhBDꄻb;T*tdi۾]?/(CmʍƓ9r$뱪M;\wi4|.՚7nv*UT7kC4s$FsRuȞBG` 覉O3 {Tsyx9}HEDIq4vϟr317(Q4 V5g8Xi* Z. HOj#@lBI$8611v;# G?"_+oZ @` !H $mRltQ!/Z1bc00':sr,'N݌cQ8\tN[ Ԋg/rRKaD!!@ $Ag;7 d$֣qVU(!QR*SPR`2m遌llitG$ (G$\g3غEr˙,.`& mP4U9Q@jr(0EI@EQ$59Q`QkЎf\!b:h6eD4j($o&ٜ 1v^{hpç-kMJfs*zX2& ;/RwX&X2â(sz֎7sMIzM'%; H&FWJ04,MV34 \h]HKWK\d-6MCBQ:$T)($CGVAӛ%edX*RHPum:$ 0314bT*RE T&ƍ'2a$rb'%**!EQRT(QhK Y)"qscîHjz^}śkDuvx0;%ƒ~$[aCW{(C"9ݦVw@#{HGg Lެ:zmo]W_$:t@F|W<q7^2 dƦ#ZS+)Z.%tV} `ihXDĘ4-9BQ 620yMVM[֦Tz"hM= ˗I5U{͘(ͯ*,X>f"M$isMU҇9,DA㰸צOIt9i MZS͔V6#|X h!(4<Ut[<iZDFxn 1W6GDbUFMffi# RU.i{#)~ϛZc444p4MtWW5T\ޔHW#,Uv6orGƦGI,2ɚHCY!%(8EN@C\L75O/Mb߫usû—tjD 8b́-nfjI$ܬۘ1I%nVrRѬ"Y,xPʽAY!?#UNor%TU=Ȇ\.`jySTT;  }8_Ņ^6#ovV񶙍@qzi@]~sēSF3o<\'I,9k74wS,ZdQ"ƃ/SW&^88N%e=E:-"NtWRr&95q7Qpnut(HjYK%򍶑)*XYB-" UTP094Hc"e~؎^pXʂ!HŚ'—v)b&{Nc8mIBΉ˰CMN#hztZԃxlG@iQց;RπbxpDI;:g^(嚌|pJWӏD}-*FU,ea7tJO`86rQׂ;$B=lėډ7$GQB"|jq1 {;F 3?"0ܛxD9oa!QUw ANқ _}XAV z [XQ Z26ϰ:KP 'aV-V F*! Z:xSx:`h 壦eTga8JL]+C}O5S]! 1E6*B!(D6"7ikha sA$VEP(b b`yl]No[QYa#*u`.|D )gV&* R)dAv7c$G 2ҬPTҘ`;Z$6'}.S#[\zݠ=뀆\c -3|ʚKxM` bX eetAE=!.@F LozݿpL.8&UKΡ "MP^4 Jh/# G+=$O$܉[Td2D f%R6$b)J/݈ .^-dmm/h=5-33>_{oZ33׸nKmՆL(cTk.o¾Q9GٲBZֵUZC3#*~5V;!jMQnI{t2u*}D Ka:gN?gŊtBK**),S"MTI_rG[=EuAہrDJ9Uz`"L=c\RD Ht!Pka0G^ɹ-R,%si3RD4E[ $k͆tOkP#tTFˁ|9,C=ׅd'd=H$ME~kej$]1E^d ;^@"5 m"M|WW <~wraS|hw5M>NvF R[3sp.ØݡD Da(U$zyCsC}tUY0P†"z +x#]}7E} c0$msAZ00003)B6b**16P16*y}8㬓!`@w#jHDCi*b,oAUXm"lE$JHp>Ẑjܧ< Qm9]:߲x `ܞN8VDZb-Eb#&1 z^IVjZB'V,VU"VLQR($JfJDPVz*erz a< w)F3@*Eei+nCNg\B"ip7YM?auhdl!C״ne۷p6v,TE)$$lXf84f%xBȧ|u RcO Gt\Es9H;B-XAԖf6WSn+G  -`Ф.05w4l&*ե996y˒Fo.^(& 4ȧ+ u 41! .%˄$"]8 ‹Q+?'hD:7,U髒24I铇0RtI~La^ ]xNJK[U%IIsS c)=ϫYeZ\WJT'#-bbՊj1.˱VMEW7w0?##TP׭Kʔ k%*Z)"&)Zm/ƐpIBR~gVM4MBPn܍A&0)HR6**6lM*P* $xX;"؎IO"QErpu< RILri&!$6,I&Vf34hI~<'YI "zxOl17@YQ$¬u0K "0,1T$ZcQh :nGEV$ H5dYBT Ŋ)AY^ٖ]k_{$j[T;:ho} ދHGkR(ĄP FDd0`yU .çR;jr@ƴ>:hl`2 9x+#o#L/чY]M~(h2H\[bs,a@i^momyۼy6k ̞ʫJ/s86w yf~Ob#p1ssvn#i6Hl٦0 3A/߭] uFP+M