From e5e5761da4860d8284ca757ee828ff8ef0df720a Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 25 Nov 2020 08:29:34 +0000 Subject: [PATCH 01/89] add raqm to thirdparty directory --- src/thirdparty/raqm/raqm-version.h | 44 + src/thirdparty/raqm/raqm.c | 2069 ++++++++++++++++++++++++++++ src/thirdparty/raqm/raqm.h | 185 +++ 3 files changed, 2298 insertions(+) create mode 100644 src/thirdparty/raqm/raqm-version.h create mode 100644 src/thirdparty/raqm/raqm.c create mode 100644 src/thirdparty/raqm/raqm.h diff --git a/src/thirdparty/raqm/raqm-version.h b/src/thirdparty/raqm/raqm-version.h new file mode 100644 index 000000000..4fd5c6842 --- /dev/null +++ b/src/thirdparty/raqm/raqm-version.h @@ -0,0 +1,44 @@ +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef _RAQM_H_IN_ +#error "Include instead." +#endif + +#ifndef _RAQM_VERSION_H_ +#define _RAQM_VERSION_H_ + +#define RAQM_VERSION_MAJOR 0 +#define RAQM_VERSION_MINOR 7 +#define RAQM_VERSION_MICRO 1 + +#define RAQM_VERSION_STRING "0.7.1" + +#define RAQM_VERSION_ATLEAST(major,minor,micro) \ + ((major)*10000+(minor)*100+(micro) <= \ + RAQM_VERSION_MAJOR*10000+RAQM_VERSION_MINOR*100+RAQM_VERSION_MICRO) + +#endif /* _RAQM_VERSION_H_ */ diff --git a/src/thirdparty/raqm/raqm.c b/src/thirdparty/raqm/raqm.c new file mode 100644 index 000000000..27e59b5fc --- /dev/null +++ b/src/thirdparty/raqm/raqm.c @@ -0,0 +1,2069 @@ +/* + * Copyright © 2015 Information Technology Authority (ITA) + * Copyright © 2016 Khaled Hosny + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#undef HAVE_CONFIG_H // Workaround for Fribidi 1.0.5 and earlier +#endif + +#include +#include + +#include +#include +#include + +#include "raqm.h" + +#if FRIBIDI_MAJOR_VERSION >= 1 +#define USE_FRIBIDI_EX_API +#endif + +/** + * SECTION:raqm + * @title: Raqm + * @short_description: A library for complex text layout + * @include: raqm.h + * + * Raqm is a light weight text layout library with strong emphasis on + * supporting languages and writing systems that require complex text layout. + * + * The main object in Raqm API is #raqm_t, it stores all the states of the + * input text, its properties, and the output of the layout process. + * + * To start, you create a #raqm_t object, add text and font(s) to it, run the + * layout process, and finally query about the output. For example: + * + * |[ + * #include "raqm.h" + * + * int + * main (int argc, char *argv[]) + * { + * const char *fontfile; + * const char *text; + * const char *direction; + * const char *language; + * int ret = 1; + * + * FT_Library library = NULL; + * FT_Face face = NULL; + * + * if (argc < 5) + * { + * printf ("Usage: %s FONT_FILE TEXT DIRECTION LANG\n", argv[0]); + * return 1; + * } + * + * fontfile = argv[1]; + * text = argv[2]; + * direction = argv[3]; + * language = argv[4]; + * + * if (FT_Init_FreeType (&library) == 0) + * { + * if (FT_New_Face (library, fontfile, 0, &face) == 0) + * { + * if (FT_Set_Char_Size (face, face->units_per_EM, 0, 0, 0) == 0) + * { + * raqm_t *rq = raqm_create (); + * if (rq != NULL) + * { + * raqm_direction_t dir = RAQM_DIRECTION_DEFAULT; + * + * if (strcmp (direction, "r") == 0) + * dir = RAQM_DIRECTION_RTL; + * else if (strcmp (direction, "l") == 0) + * dir = RAQM_DIRECTION_LTR; + * + * if (raqm_set_text_utf8 (rq, text, strlen (text)) && + * raqm_set_freetype_face (rq, face) && + * raqm_set_par_direction (rq, dir) && + * raqm_set_language (rq, language, 0, strlen (text)) && + * raqm_layout (rq)) + * { + * size_t count, i; + * raqm_glyph_t *glyphs = raqm_get_glyphs (rq, &count); + * + * ret = !(glyphs != NULL || count == 0); + * + * printf("glyph count: %zu\n", count); + * for (i = 0; i < count; i++) + * { + * printf ("gid#%d off: (%d, %d) adv: (%d, %d) idx: %d\n", + * glyphs[i].index, + * glyphs[i].x_offset, + * glyphs[i].y_offset, + * glyphs[i].x_advance, + * glyphs[i].y_advance, + * glyphs[i].cluster); + * } + * } + * + * raqm_destroy (rq); + * } + * } + * + * FT_Done_Face (face); + * } + * + * FT_Done_FreeType (library); + * } + * + * return ret; + * } + * ]| + * To compile this example: + * |[ + * cc -o test test.c `pkg-config --libs --cflags raqm` + * ]| + */ + +/* For enabling debug mode */ +/*#define RAQM_DEBUG 1*/ +#ifdef RAQM_DEBUG +#define RAQM_DBG(...) fprintf (stderr, __VA_ARGS__) +#else +#define RAQM_DBG(...) +#endif + +#ifdef RAQM_TESTING +# define RAQM_TEST(...) printf (__VA_ARGS__) +# define SCRIPT_TO_STRING(script) \ + char buff[5]; \ + hb_tag_to_string (hb_script_to_iso15924_tag (script), buff); \ + buff[4] = '\0'; +#else +# define RAQM_TEST(...) +#endif + +typedef enum { + RAQM_FLAG_NONE = 0, + RAQM_FLAG_UTF8 = 1 << 0 +} _raqm_flags_t; + +typedef struct { + FT_Face ftface; + hb_language_t lang; + hb_script_t script; +} _raqm_text_info; + +typedef struct _raqm_run raqm_run_t; + +struct _raqm { + int ref_count; + + uint32_t *text; + char *text_utf8; + size_t text_len; + + _raqm_text_info *text_info; + + raqm_direction_t base_dir; + raqm_direction_t resolved_dir; + + hb_feature_t *features; + size_t features_len; + + raqm_run_t *runs; + raqm_glyph_t *glyphs; + + _raqm_flags_t flags; + + int ft_loadflags; + int invisible_glyph; +}; + +struct _raqm_run { + int pos; + int len; + + hb_direction_t direction; + hb_script_t script; + hb_font_t *font; + hb_buffer_t *buffer; + + raqm_run_t *next; +}; + +static uint32_t +_raqm_u8_to_u32_index (raqm_t *rq, + uint32_t index); + +static bool +_raqm_init_text_info (raqm_t *rq) +{ + hb_language_t default_lang; + + if (rq->text_info) + return true; + + rq->text_info = malloc (sizeof (_raqm_text_info) * rq->text_len); + if (!rq->text_info) + return false; + + default_lang = hb_language_get_default (); + for (size_t i = 0; i < rq->text_len; i++) + { + rq->text_info[i].ftface = NULL; + rq->text_info[i].lang = default_lang; + rq->text_info[i].script = HB_SCRIPT_INVALID; + } + + return true; +} + +static void +_raqm_free_text_info (raqm_t *rq) +{ + if (!rq->text_info) + return; + + for (size_t i = 0; i < rq->text_len; i++) + { + if (rq->text_info[i].ftface) + FT_Done_Face (rq->text_info[i].ftface); + } + + free (rq->text_info); + rq->text_info = NULL; +} + +static bool +_raqm_compare_text_info (_raqm_text_info a, + _raqm_text_info b) +{ + if (a.ftface != b.ftface) + return false; + + if (a.lang != b.lang) + return false; + + if (a.script != b.script) + return false; + + return true; +} + +/** + * raqm_create: + * + * Creates a new #raqm_t with all its internal states initialized to their + * defaults. + * + * Return value: + * A newly allocated #raqm_t with a reference count of 1. The initial reference + * count should be released with raqm_destroy() when you are done using the + * #raqm_t. Returns %NULL in case of error. + * + * Since: 0.1 + */ +raqm_t * +raqm_create (void) +{ + raqm_t *rq; + + rq = malloc (sizeof (raqm_t)); + if (!rq) + return NULL; + + rq->ref_count = 1; + + rq->text = NULL; + rq->text_utf8 = NULL; + rq->text_len = 0; + + rq->text_info = NULL; + + rq->base_dir = RAQM_DIRECTION_DEFAULT; + rq->resolved_dir = RAQM_DIRECTION_DEFAULT; + + rq->features = NULL; + rq->features_len = 0; + + rq->runs = NULL; + rq->glyphs = NULL; + + rq->flags = RAQM_FLAG_NONE; + + rq->ft_loadflags = -1; + rq->invisible_glyph = 0; + + return rq; +} + +/** + * raqm_reference: + * @rq: a #raqm_t. + * + * Increases the reference count on @rq by one. This prevents @rq from being + * destroyed until a matching call to raqm_destroy() is made. + * + * Return value: + * The referenced #raqm_t. + * + * Since: 0.1 + */ +raqm_t * +raqm_reference (raqm_t *rq) +{ + if (rq) + rq->ref_count++; + + return rq; +} + +static void +_raqm_free_runs (raqm_t *rq) +{ + raqm_run_t *runs = rq->runs; + while (runs) + { + raqm_run_t *run = runs; + runs = runs->next; + + hb_buffer_destroy (run->buffer); + hb_font_destroy (run->font); + free (run); + } +} + +/** + * raqm_destroy: + * @rq: a #raqm_t. + * + * Decreases the reference count on @rq by one. If the result is zero, then @rq + * and all associated resources are freed. + * See cairo_reference(). + * + * Since: 0.1 + */ +void +raqm_destroy (raqm_t *rq) +{ + if (!rq || --rq->ref_count != 0) + return; + + free (rq->text); + free (rq->text_utf8); + _raqm_free_text_info (rq); + _raqm_free_runs (rq); + free (rq->glyphs); + free (rq); +} + +/** + * raqm_set_text: + * @rq: a #raqm_t. + * @text: a UTF-32 encoded text string. + * @len: the length of @text. + * + * Adds @text to @rq to be used for layout. It must be a valid UTF-32 text, any + * invalid character will be replaced with U+FFFD. The text should typically + * represent a full paragraph, since doing the layout of chunks of text + * separately can give improper output. + * + * Return value: + * %true if no errors happened, %false otherwise. + * + * Since: 0.1 + */ +bool +raqm_set_text (raqm_t *rq, + const uint32_t *text, + size_t len) +{ + if (!rq || !text) + return false; + + rq->text_len = len; + + /* Empty string, don’t fail but do nothing */ + if (!len) + return true; + + free (rq->text); + + rq->text = malloc (sizeof (uint32_t) * rq->text_len); + if (!rq->text) + return false; + + _raqm_free_text_info (rq); + if (!_raqm_init_text_info (rq)) + return false; + + memcpy (rq->text, text, sizeof (uint32_t) * rq->text_len); + + return true; +} + +/** + * raqm_set_text_utf8: + * @rq: a #raqm_t. + * @text: a UTF-8 encoded text string. + * @len: the length of @text in UTF-8 bytes. + * + * Same as raqm_set_text(), but for text encoded in UTF-8 encoding. + * + * Return value: + * %true if no errors happened, %false otherwise. + * + * Since: 0.1 + */ +bool +raqm_set_text_utf8 (raqm_t *rq, + const char *text, + size_t len) +{ + uint32_t *unicode; + size_t ulen; + bool ok; + + if (!rq || !text) + return false; + + /* Empty string, don’t fail but do nothing */ + if (!len) + { + rq->text_len = len; + return true; + } + + RAQM_TEST ("Text is: %s\n", text); + + rq->flags |= RAQM_FLAG_UTF8; + + rq->text_utf8 = malloc (sizeof (char) * len); + if (!rq->text_utf8) + return false; + + unicode = malloc (sizeof (uint32_t) * len); + if (!unicode) + return false; + + memcpy (rq->text_utf8, text, sizeof (char) * len); + + ulen = fribidi_charset_to_unicode (FRIBIDI_CHAR_SET_UTF8, + text, len, unicode); + + ok = raqm_set_text (rq, unicode, ulen); + + free (unicode); + return ok; +} + +/** + * raqm_set_par_direction: + * @rq: a #raqm_t. + * @dir: the direction of the paragraph. + * + * Sets the paragraph direction, also known as block direction in CSS. For + * horizontal text, this controls the overall direction in the Unicode + * Bidirectional Algorithm, so when the text is mainly right-to-left (with or + * without some left-to-right) text, then the base direction should be set to + * #RAQM_DIRECTION_RTL and vice versa. + * + * The default is #RAQM_DIRECTION_DEFAULT, which determines the paragraph + * direction based on the first character with strong bidi type (see [rule + * P2](http://unicode.org/reports/tr9/#P2) in Unicode Bidirectional Algorithm), + * which can be good enough for many cases but has problems when a mainly + * right-to-left paragraph starts with a left-to-right character and vice versa + * as the detected paragraph direction will be the wrong one, or when text does + * not contain any characters with string bidi types (e.g. only punctuation or + * numbers) as this will default to left-to-right paragraph direction. + * + * For vertical, top-to-bottom text, #RAQM_DIRECTION_TTB should be used. Raqm, + * however, provides limited vertical text support and does not handle rotated + * horizontal text in vertical text, instead everything is treated as vertical + * text. + * + * Return value: + * %true if no errors happened, %false otherwise. + * + * Since: 0.1 + */ +bool +raqm_set_par_direction (raqm_t *rq, + raqm_direction_t dir) +{ + if (!rq) + return false; + + rq->base_dir = dir; + + return true; +} + +/** + * raqm_set_language: + * @rq: a #raqm_t. + * @lang: a BCP47 language code. + * @start: index of first character that should use @face. + * @len: number of characters using @face. + * + * Sets a [BCP47 language + * code](https://www.w3.org/International/articles/language-tags/) to be used + * for @len-number of characters staring at @start. The @start and @len are + * input string array indices (i.e. counting bytes in UTF-8 and scaler values + * in UTF-32). + * + * This method can be used repeatedly to set different languages for different + * parts of the text. + * + * Return value: + * %true if no errors happened, %false otherwise. + * + * Stability: + * Unstable + * + * Since: 0.2 + */ +bool +raqm_set_language (raqm_t *rq, + const char *lang, + size_t start, + size_t len) +{ + hb_language_t language; + size_t end = start + len; + + if (!rq) + return false; + + if (!rq->text_len) + return true; + + if (rq->flags & RAQM_FLAG_UTF8) + { + start = _raqm_u8_to_u32_index (rq, start); + end = _raqm_u8_to_u32_index (rq, end); + } + + if (start >= rq->text_len || end > rq->text_len) + return false; + + if (!rq->text_info) + return false; + + language = hb_language_from_string (lang, -1); + for (size_t i = start; i < end; i++) + { + rq->text_info[i].lang = language; + } + + return true; +} + +/** + * raqm_add_font_feature: + * @rq: a #raqm_t. + * @feature: (transfer none): a font feature string. + * @len: length of @feature, -1 for %NULL-terminated. + * + * Adds a font feature to be used by the #raqm_t during text layout. This is + * usually used to turn on optional font features that are not enabled by + * default, for example `dlig` or `ss01`, but can be also used to turn off + * default font features. + * + * @feature is string representing a single font feature, in the syntax + * understood by hb_feature_from_string(). + * + * This function can be called repeatedly, new features will be appended to the + * end of the features list and can potentially override previous features. + * + * Return value: + * %true if parsing @feature succeeded, %false otherwise. + * + * Since: 0.1 + */ +bool +raqm_add_font_feature (raqm_t *rq, + const char *feature, + int len) +{ + hb_bool_t ok; + hb_feature_t fea; + + if (!rq) + return false; + + ok = hb_feature_from_string (feature, len, &fea); + if (ok) + { + rq->features_len++; + rq->features = realloc (rq->features, + sizeof (hb_feature_t) * (rq->features_len)); + if (!rq->features) + return false; + + rq->features[rq->features_len - 1] = fea; + } + + return ok; +} + +static hb_font_t * +_raqm_create_hb_font (raqm_t *rq, + FT_Face face) +{ + hb_font_t *font = hb_ft_font_create_referenced (face); + + if (rq->ft_loadflags >= 0) + hb_ft_font_set_load_flags (font, rq->ft_loadflags); + + return font; +} + +static bool +_raqm_set_freetype_face (raqm_t *rq, + FT_Face face, + size_t start, + size_t end) +{ + if (!rq) + return false; + + if (!rq->text_len) + return true; + + if (start >= rq->text_len || end > rq->text_len) + return false; + + if (!rq->text_info) + return false; + + for (size_t i = start; i < end; i++) + { + if (rq->text_info[i].ftface) + FT_Done_Face (rq->text_info[i].ftface); + rq->text_info[i].ftface = face; + FT_Reference_Face (face); + } + + return true; +} + +/** + * raqm_set_freetype_face: + * @rq: a #raqm_t. + * @face: an #FT_Face. + * + * Sets an #FT_Face to be used for all characters in @rq. + * + * See also raqm_set_freetype_face_range(). + * + * Return value: + * %true if no errors happened, %false otherwise. + * + * Since: 0.1 + */ +bool +raqm_set_freetype_face (raqm_t *rq, + FT_Face face) +{ + return _raqm_set_freetype_face (rq, face, 0, rq->text_len); +} + +/** + * raqm_set_freetype_face_range: + * @rq: a #raqm_t. + * @face: an #FT_Face. + * @start: index of first character that should use @face. + * @len: number of characters using @face. + * + * Sets an #FT_Face to be used for @len-number of characters staring at @start. + * The @start and @len are input string array indices (i.e. counting bytes in + * UTF-8 and scaler values in UTF-32). + * + * This method can be used repeatedly to set different faces for different + * parts of the text. It is the responsibility of the client to make sure that + * face ranges cover the whole text. + * + * See also raqm_set_freetype_face(). + * + * Return value: + * %true if no errors happened, %false otherwise. + * + * Since: 0.1 + */ +bool +raqm_set_freetype_face_range (raqm_t *rq, + FT_Face face, + size_t start, + size_t len) +{ + size_t end = start + len; + + if (!rq) + return false; + + if (!rq->text_len) + return true; + + if (rq->flags & RAQM_FLAG_UTF8) + { + start = _raqm_u8_to_u32_index (rq, start); + end = _raqm_u8_to_u32_index (rq, end); + } + + return _raqm_set_freetype_face (rq, face, start, end); +} + +/** + * raqm_set_freetype_load_flags: + * @rq: a #raqm_t. + * @flags: FreeType load flags. + * + * Sets the load flags passed to FreeType when loading glyphs, should be the + * same flags used by the client when rendering FreeType glyphs. + * + * This requires version of HarfBuzz that has hb_ft_font_set_load_flags(), for + * older version the flags will be ignored. + * + * Return value: + * %true if no errors happened, %false otherwise. + * + * Since: 0.3 + */ +bool +raqm_set_freetype_load_flags (raqm_t *rq, + int flags) +{ + if (!rq) + return false; + + rq->ft_loadflags = flags; + + return true; +} + +/** + * raqm_set_invisible_glyph: + * @rq: a #raqm_t. + * @gid: glyph id to use for invisible glyphs. + * + * Sets the glyph id to be used for invisible glyhphs. + * + * If @gid is negative, invisible glyphs will be suppressed from the output. + * This requires HarfBuzz 1.8.0 or later. If raqm is used with an earlier + * HarfBuzz version, the return value will be %false and the shaping behavior + * does not change. + * + * If @gid is zero, invisible glyphs will be rendered as space. + * This works on all versions of HarfBuzz. + * + * If @gid is a positive number, it will be used for invisible glyphs. + * This requires a version of HarfBuzz that has + * hb_buffer_set_invisible_glyph(). For older versions, the return value + * will be %false and the shaping behavior does not change. + * + * Return value: + * %true if no errors happened, %false otherwise. + * + * Since: 0.6 + */ +bool +raqm_set_invisible_glyph (raqm_t *rq, + int gid) +{ + if (!rq) + return false; + +#ifndef HAVE_HB_BUFFER_SET_INVISIBLE_GLYPH + if (gid > 0) + return false; +#endif + +#if !defined(HAVE_DECL_HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES) || \ + !HAVE_DECL_HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES + if (gid < 0) + return false; +#endif + + rq->invisible_glyph = gid; + return true; +} + +static bool +_raqm_itemize (raqm_t *rq); + +static bool +_raqm_shape (raqm_t *rq); + +/** + * raqm_layout: + * @rq: a #raqm_t. + * + * Run the text layout process on @rq. This is the main Raqm function where the + * Unicode Bidirectional Text algorithm will be applied to the text in @rq, + * text shaping, and any other part of the layout process. + * + * Return value: + * %true if the layout process was successful, %false otherwise. + * + * Since: 0.1 + */ +bool +raqm_layout (raqm_t *rq) +{ + if (!rq) + return false; + + if (!rq->text_len) + return true; + + if (!rq->text_info) + return false; + + for (size_t i = 0; i < rq->text_len; i++) + { + if (!rq->text_info[i].ftface) + return false; + } + + if (!_raqm_itemize (rq)) + return false; + + if (!_raqm_shape (rq)) + return false; + + return true; +} + +static uint32_t +_raqm_u32_to_u8_index (raqm_t *rq, + uint32_t index); + +/** + * raqm_get_glyphs: + * @rq: a #raqm_t. + * @length: (out): output array length. + * + * Gets the final result of Raqm layout process, an array of #raqm_glyph_t + * containing the glyph indices in the font, their positions and other possible + * information. + * + * Return value: (transfer none): + * An array of #raqm_glyph_t, or %NULL in case of error. This is owned by @rq + * and must not be freed. + * + * Since: 0.1 + */ +raqm_glyph_t * +raqm_get_glyphs (raqm_t *rq, + size_t *length) +{ + size_t count = 0; + + if (!rq || !rq->runs || !length) + { + if (length) + *length = 0; + return NULL; + } + + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + count += hb_buffer_get_length (run->buffer); + + *length = count; + + if (rq->glyphs) + free (rq->glyphs); + + rq->glyphs = malloc (sizeof (raqm_glyph_t) * count); + if (!rq->glyphs) + { + *length = 0; + return NULL; + } + + RAQM_TEST ("Glyph information:\n"); + + count = 0; + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + { + size_t len; + hb_glyph_info_t *info; + hb_glyph_position_t *position; + + len = hb_buffer_get_length (run->buffer); + info = hb_buffer_get_glyph_infos (run->buffer, NULL); + position = hb_buffer_get_glyph_positions (run->buffer, NULL); + + for (size_t i = 0; i < len; i++) + { + rq->glyphs[count + i].index = info[i].codepoint; + rq->glyphs[count + i].cluster = info[i].cluster; + rq->glyphs[count + i].x_advance = position[i].x_advance; + rq->glyphs[count + i].y_advance = position[i].y_advance; + rq->glyphs[count + i].x_offset = position[i].x_offset; + rq->glyphs[count + i].y_offset = position[i].y_offset; + rq->glyphs[count + i].ftface = rq->text_info[info[i].cluster].ftface; + + RAQM_TEST ("glyph [%d]\tx_offset: %d\ty_offset: %d\tx_advance: %d\tfont: %s\n", + rq->glyphs[count + i].index, rq->glyphs[count + i].x_offset, + rq->glyphs[count + i].y_offset, rq->glyphs[count + i].x_advance, + rq->glyphs[count + i].ftface->family_name); + } + + count += len; + } + + if (rq->flags & RAQM_FLAG_UTF8) + { +#ifdef RAQM_TESTING + RAQM_TEST ("\nUTF-32 clusters:"); + for (size_t i = 0; i < count; i++) + RAQM_TEST (" %02d", rq->glyphs[i].cluster); + RAQM_TEST ("\n"); +#endif + + for (size_t i = 0; i < count; i++) + rq->glyphs[i].cluster = _raqm_u32_to_u8_index (rq, + rq->glyphs[i].cluster); + +#ifdef RAQM_TESTING + RAQM_TEST ("UTF-8 clusters: "); + for (size_t i = 0; i < count; i++) + RAQM_TEST (" %02d", rq->glyphs[i].cluster); + RAQM_TEST ("\n"); +#endif + } + return rq->glyphs; +} + +static bool +_raqm_resolve_scripts (raqm_t *rq); + +static hb_direction_t +_raqm_hb_dir (raqm_t *rq, FriBidiLevel level) +{ + hb_direction_t dir = HB_DIRECTION_LTR; + + if (rq->base_dir == RAQM_DIRECTION_TTB) + dir = HB_DIRECTION_TTB; + else if (FRIBIDI_LEVEL_IS_RTL (level)) + dir = HB_DIRECTION_RTL; + + return dir; +} + +typedef struct { + size_t pos; + size_t len; + FriBidiLevel level; +} _raqm_bidi_run; + +static void +_raqm_reverse_run (_raqm_bidi_run *run, const size_t len) +{ + assert (run); + + for (size_t i = 0; i < len / 2; i++) + { + _raqm_bidi_run temp = run[i]; + run[i] = run[len - 1 - i]; + run[len - 1 - i] = temp; + } +} + +static _raqm_bidi_run * +_raqm_reorder_runs (const FriBidiCharType *types, + const size_t len, + const FriBidiParType base_dir, + /* input and output */ + FriBidiLevel *levels, + /* output */ + size_t *run_count) +{ + FriBidiLevel level; + FriBidiLevel last_level = -1; + FriBidiLevel max_level = 0; + size_t run_start = 0; + size_t run_index = 0; + _raqm_bidi_run *runs = NULL; + size_t count = 0; + + if (len == 0) + { + *run_count = 0; + return NULL; + } + + assert (types); + assert (levels); + + /* L1. Reset the embedding levels of some chars: + 4. any sequence of white space characters at the end of the line. */ + for (int i = len - 1; + i >= 0 && FRIBIDI_IS_EXPLICIT_OR_BN_OR_WS (types[i]); i--) + { + levels[i] = FRIBIDI_DIR_TO_LEVEL (base_dir); + } + + /* Find max_level of the line. We don't reuse the paragraph + * max_level, both for a cleaner API, and that the line max_level + * may be far less than paragraph max_level. */ + for (int i = len - 1; i >= 0; i--) + { + if (levels[i] > max_level) + max_level = levels[i]; + } + + for (size_t i = 0; i < len; i++) + { + if (levels[i] != last_level) + count++; + + last_level = levels[i]; + } + + runs = malloc (sizeof (_raqm_bidi_run) * count); + + while (run_start < len) + { + size_t run_end = run_start; + while (run_end < len && levels[run_start] == levels[run_end]) + { + run_end++; + } + + runs[run_index].pos = run_start; + runs[run_index].level = levels[run_start]; + runs[run_index].len = run_end - run_start; + run_start = run_end; + run_index++; + } + + /* L2. Reorder. */ + for (level = max_level; level > 0; level--) + { + for (int i = count - 1; i >= 0; i--) + { + if (runs[i].level >= level) + { + int end = i; + for (i--; (i >= 0 && runs[i].level >= level); i--) + ; + _raqm_reverse_run (runs + i + 1, end - i); + } + } + } + + *run_count = count; + return runs; +} + +static bool +_raqm_itemize (raqm_t *rq) +{ + FriBidiParType par_type = FRIBIDI_PAR_ON; + FriBidiCharType *types; +#ifdef USE_FRIBIDI_EX_API + FriBidiBracketType *btypes; +#endif + FriBidiLevel *levels; + _raqm_bidi_run *runs = NULL; + raqm_run_t *last; + int max_level; + size_t run_count; + bool ok = true; + +#ifdef RAQM_TESTING + switch (rq->base_dir) + { + case RAQM_DIRECTION_RTL: + RAQM_TEST ("Direction is: RTL\n\n"); + break; + case RAQM_DIRECTION_LTR: + RAQM_TEST ("Direction is: LTR\n\n"); + break; + case RAQM_DIRECTION_TTB: + RAQM_TEST ("Direction is: TTB\n\n"); + break; + case RAQM_DIRECTION_DEFAULT: + default: + RAQM_TEST ("Direction is: DEFAULT\n\n"); + break; + } +#endif + + types = calloc (rq->text_len, sizeof (FriBidiCharType)); +#ifdef USE_FRIBIDI_EX_API + btypes = calloc (rq->text_len, sizeof (FriBidiBracketType)); +#endif + levels = calloc (rq->text_len, sizeof (FriBidiLevel)); + if (!types || !levels +#ifdef USE_FRIBIDI_EX_API + || !btypes +#endif + ) + { + ok = false; + goto done; + } + + if (rq->base_dir == RAQM_DIRECTION_RTL) + par_type = FRIBIDI_PAR_RTL; + else if (rq->base_dir == RAQM_DIRECTION_LTR) + par_type = FRIBIDI_PAR_LTR; + + if (rq->base_dir == RAQM_DIRECTION_TTB) + { + /* Treat every thing as LTR in vertical text */ + max_level = 1; + memset (types, FRIBIDI_TYPE_LTR, rq->text_len); + memset (levels, 0, rq->text_len); + rq->resolved_dir = RAQM_DIRECTION_LTR; + } + else + { + fribidi_get_bidi_types (rq->text, rq->text_len, types); +#ifdef USE_FRIBIDI_EX_API + fribidi_get_bracket_types (rq->text, rq->text_len, types, btypes); + max_level = fribidi_get_par_embedding_levels_ex (types, btypes, + rq->text_len, &par_type, + levels); +#else + max_level = fribidi_get_par_embedding_levels (types, rq->text_len, + &par_type, levels); +#endif + + if (par_type == FRIBIDI_PAR_LTR) + rq->resolved_dir = RAQM_DIRECTION_LTR; + else + rq->resolved_dir = RAQM_DIRECTION_RTL; + } + + if (max_level == 0) + { + ok = false; + goto done; + } + + if (!_raqm_resolve_scripts (rq)) + { + ok = false; + goto done; + } + + /* Get the number of bidi runs */ + runs = _raqm_reorder_runs (types, rq->text_len, par_type, levels, &run_count); + if (!runs) + { + ok = false; + goto done; + } + +#ifdef RAQM_TESTING + RAQM_TEST ("Number of runs before script itemization: %zu\n\n", run_count); + + RAQM_TEST ("Fribidi Runs:\n"); + for (size_t i = 0; i < run_count; i++) + { + RAQM_TEST ("run[%zu]:\t start: %zu\tlength: %zu\tlevel: %d\n", + i, runs[i].pos, runs[i].len, runs[i].level); + } + RAQM_TEST ("\n"); +#endif + + last = NULL; + for (size_t i = 0; i < run_count; i++) + { + raqm_run_t *run = calloc (1, sizeof (raqm_run_t)); + if (!run) + { + ok = false; + goto done; + } + + if (!rq->runs) + rq->runs = run; + + if (last) + last->next = run; + + run->direction = _raqm_hb_dir (rq, runs[i].level); + + if (HB_DIRECTION_IS_BACKWARD (run->direction)) + { + run->pos = runs[i].pos + runs[i].len - 1; + run->script = rq->text_info[run->pos].script; + run->font = _raqm_create_hb_font (rq, rq->text_info[run->pos].ftface); + for (int j = runs[i].len - 1; j >= 0; j--) + { + _raqm_text_info info = rq->text_info[runs[i].pos + j]; + if (!_raqm_compare_text_info (rq->text_info[run->pos], info)) + { + raqm_run_t *newrun = calloc (1, sizeof (raqm_run_t)); + if (!newrun) + { + ok = false; + goto done; + } + newrun->pos = runs[i].pos + j; + newrun->len = 1; + newrun->direction = _raqm_hb_dir (rq, runs[i].level); + newrun->script = info.script; + newrun->font = _raqm_create_hb_font (rq, info.ftface); + run->next = newrun; + run = newrun; + } + else + { + run->len++; + run->pos = runs[i].pos + j; + } + } + } + else + { + run->pos = runs[i].pos; + run->script = rq->text_info[run->pos].script; + run->font = _raqm_create_hb_font (rq, rq->text_info[run->pos].ftface); + for (size_t j = 0; j < runs[i].len; j++) + { + _raqm_text_info info = rq->text_info[runs[i].pos + j]; + if (!_raqm_compare_text_info (rq->text_info[run->pos], info)) + { + raqm_run_t *newrun = calloc (1, sizeof (raqm_run_t)); + if (!newrun) + { + ok = false; + goto done; + } + newrun->pos = runs[i].pos + j; + newrun->len = 1; + newrun->direction = _raqm_hb_dir (rq, runs[i].level); + newrun->script = info.script; + newrun->font = _raqm_create_hb_font (rq, info.ftface); + run->next = newrun; + run = newrun; + } + else + run->len++; + } + } + + last = run; + last->next = NULL; + } + +#ifdef RAQM_TESTING + run_count = 0; + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + run_count++; + RAQM_TEST ("Number of runs after script itemization: %zu\n\n", run_count); + + run_count = 0; + RAQM_TEST ("Final Runs:\n"); + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + { + SCRIPT_TO_STRING (run->script); + RAQM_TEST ("run[%zu]:\t start: %d\tlength: %d\tdirection: %s\tscript: %s\tfont: %s\n", + run_count++, run->pos, run->len, + hb_direction_to_string (run->direction), buff, + rq->text_info[run->pos].ftface->family_name); + } + RAQM_TEST ("\n"); +#endif + +done: + free (runs); + free (types); +#ifdef USE_FRIBIDI_EX_API + free (btypes); +#endif + free (levels); + + return ok; +} + +/* Stack to handle script detection */ +typedef struct { + size_t capacity; + size_t size; + int *pair_index; + hb_script_t *script; +} _raqm_stack_t; + +/* Special paired characters for script detection */ +static size_t paired_len = 34; +static const FriBidiChar paired_chars[] = +{ + 0x0028, 0x0029, /* ascii paired punctuation */ + 0x003c, 0x003e, + 0x005b, 0x005d, + 0x007b, 0x007d, + 0x00ab, 0x00bb, /* guillemets */ + 0x2018, 0x2019, /* general punctuation */ + 0x201c, 0x201d, + 0x2039, 0x203a, + 0x3008, 0x3009, /* chinese paired punctuation */ + 0x300a, 0x300b, + 0x300c, 0x300d, + 0x300e, 0x300f, + 0x3010, 0x3011, + 0x3014, 0x3015, + 0x3016, 0x3017, + 0x3018, 0x3019, + 0x301a, 0x301b +}; + +static void +_raqm_stack_free (_raqm_stack_t *stack) +{ + free (stack->script); + free (stack->pair_index); + free (stack); +} + +/* Stack handling functions */ +static _raqm_stack_t * +_raqm_stack_new (size_t max) +{ + _raqm_stack_t *stack; + stack = calloc (1, sizeof (_raqm_stack_t)); + if (!stack) + return NULL; + + stack->script = malloc (sizeof (hb_script_t) * max); + if (!stack->script) + { + _raqm_stack_free (stack); + return NULL; + } + + stack->pair_index = malloc (sizeof (int) * max); + if (!stack->pair_index) + { + _raqm_stack_free (stack); + return NULL; + } + + stack->size = 0; + stack->capacity = max; + + return stack; +} + +static bool +_raqm_stack_pop (_raqm_stack_t *stack) +{ + if (!stack->size) + { + RAQM_DBG ("Stack is Empty\n"); + return false; + } + + stack->size--; + + return true; +} + +static hb_script_t +_raqm_stack_top (_raqm_stack_t *stack) +{ + if (!stack->size) + { + RAQM_DBG ("Stack is Empty\n"); + return HB_SCRIPT_INVALID; /* XXX: check this */ + } + + return stack->script[stack->size]; +} + +static bool +_raqm_stack_push (_raqm_stack_t *stack, + hb_script_t script, + int pair_index) +{ + if (stack->size == stack->capacity) + { + RAQM_DBG ("Stack is Full\n"); + return false; + } + + stack->size++; + stack->script[stack->size] = script; + stack->pair_index[stack->size] = pair_index; + + return true; +} + +static int +_get_pair_index (const FriBidiChar ch) +{ + int lower = 0; + int upper = paired_len - 1; + + while (lower <= upper) + { + int mid = (lower + upper) / 2; + if (ch < paired_chars[mid]) + upper = mid - 1; + else if (ch > paired_chars[mid]) + lower = mid + 1; + else + return mid; + } + + return -1; +} + +#define STACK_IS_EMPTY(script) ((script)->size <= 0) +#define IS_OPEN(pair_index) (((pair_index) & 1) == 0) + +/* Resolve the script for each character in the input string, if the character + * script is common or inherited it takes the script of the character before it + * except paired characters which we try to make them use the same script. We + * then split the BiDi runs, if necessary, on script boundaries. + */ +static bool +_raqm_resolve_scripts (raqm_t *rq) +{ + int last_script_index = -1; + int last_set_index = -1; + hb_script_t last_script = HB_SCRIPT_INVALID; + _raqm_stack_t *stack = NULL; + hb_unicode_funcs_t* unicode_funcs = hb_unicode_funcs_get_default (); + + for (size_t i = 0; i < rq->text_len; ++i) + rq->text_info[i].script = hb_unicode_script (unicode_funcs, rq->text[i]); + +#ifdef RAQM_TESTING + RAQM_TEST ("Before script detection:\n"); + for (size_t i = 0; i < rq->text_len; ++i) + { + SCRIPT_TO_STRING (rq->text_info[i].script); + RAQM_TEST ("script for ch[%zu]\t%s\n", i, buff); + } + RAQM_TEST ("\n"); +#endif + + stack = _raqm_stack_new (rq->text_len); + if (!stack) + return false; + + for (int i = 0; i < (int) rq->text_len; i++) + { + if (rq->text_info[i].script == HB_SCRIPT_COMMON && last_script_index != -1) + { + int pair_index = _get_pair_index (rq->text[i]); + if (pair_index >= 0) + { + if (IS_OPEN (pair_index)) + { + /* is a paired character */ + rq->text_info[i].script = last_script; + last_set_index = i; + _raqm_stack_push (stack, rq->text_info[i].script, pair_index); + } + else + { + /* is a close paired character */ + /* find matching opening (by getting the last even index for current + * odd index) */ + while (!STACK_IS_EMPTY (stack) && + stack->pair_index[stack->size] != (pair_index & ~1)) + { + _raqm_stack_pop (stack); + } + if (!STACK_IS_EMPTY (stack)) + { + rq->text_info[i].script = _raqm_stack_top (stack); + last_script = rq->text_info[i].script; + last_set_index = i; + } + else + { + rq->text_info[i].script = last_script; + last_set_index = i; + } + } + } + else + { + rq->text_info[i].script = last_script; + last_set_index = i; + } + } + else if (rq->text_info[i].script == HB_SCRIPT_INHERITED && + last_script_index != -1) + { + rq->text_info[i].script = last_script; + last_set_index = i; + } + else + { + for (int j = last_set_index + 1; j < i; ++j) + rq->text_info[j].script = rq->text_info[i].script; + last_script = rq->text_info[i].script; + last_script_index = i; + last_set_index = i; + } + } + + /* Loop backwards and change any remaining Common or Inherit characters to + * take the script if the next character. + * https://github.com/HOST-Oman/libraqm/issues/95 + */ + for (int i = rq->text_len - 2; i >= 0; --i) + { + if (rq->text_info[i].script == HB_SCRIPT_INHERITED || + rq->text_info[i].script == HB_SCRIPT_COMMON) + rq->text_info[i].script = rq->text_info[i + 1].script; + } + +#ifdef RAQM_TESTING + RAQM_TEST ("After script detection:\n"); + for (size_t i = 0; i < rq->text_len; ++i) + { + SCRIPT_TO_STRING (rq->text_info[i].script); + RAQM_TEST ("script for ch[%zu]\t%s\n", i, buff); + } + RAQM_TEST ("\n"); +#endif + + _raqm_stack_free (stack); + + return true; +} + +static bool +_raqm_shape (raqm_t *rq) +{ + hb_buffer_flags_t hb_buffer_flags = HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT; + +#if defined(HAVE_DECL_HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES) && \ + HAVE_DECL_HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES + if (rq->invisible_glyph < 0) + hb_buffer_flags |= HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES; +#endif + + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + { + run->buffer = hb_buffer_create (); + + hb_buffer_add_utf32 (run->buffer, rq->text, rq->text_len, + run->pos, run->len); + hb_buffer_set_script (run->buffer, run->script); + hb_buffer_set_language (run->buffer, rq->text_info[run->pos].lang); + hb_buffer_set_direction (run->buffer, run->direction); + hb_buffer_set_flags (run->buffer, hb_buffer_flags); + +#ifdef HAVE_HB_BUFFER_SET_INVISIBLE_GLYPH + if (rq->invisible_glyph > 0) + hb_buffer_set_invisible_glyph (run->buffer, rq->invisible_glyph); +#endif + + hb_shape_full (run->font, run->buffer, rq->features, rq->features_len, + NULL); + } + + return true; +} + +/* Convert index from UTF-32 to UTF-8 */ +static uint32_t +_raqm_u32_to_u8_index (raqm_t *rq, + uint32_t index) +{ + FriBidiStrIndex length; + char *output = malloc ((sizeof (char) * 4 * index) + 1); + + length = fribidi_unicode_to_charset (FRIBIDI_CHAR_SET_UTF8, + rq->text, + index, + output); + + free (output); + return length; +} + +/* Convert index from UTF-8 to UTF-32 */ +static uint32_t +_raqm_u8_to_u32_index (raqm_t *rq, + uint32_t index) +{ + FriBidiStrIndex length; + uint32_t *output = malloc (sizeof (uint32_t) * (index + 1)); + + length = fribidi_charset_to_unicode (FRIBIDI_CHAR_SET_UTF8, + rq->text_utf8, + index, + output); + + free (output); + return length; +} + +static bool +_raqm_allowed_grapheme_boundary (hb_codepoint_t l_char, + hb_codepoint_t r_char); + +static bool +_raqm_in_hangul_syllable (hb_codepoint_t ch); + +/** + * raqm_index_to_position: + * @rq: a #raqm_t. + * @index: (inout): character index. + * @x: (out): output x position. + * @y: (out): output y position. + * + * Calculates the cursor position after the character at @index. If the character + * is right-to-left, then the cursor will be at the left of it, whereas if the + * character is left-to-right, then the cursor will be at the right of it. + * + * Return value: + * %true if the process was successful, %false otherwise. + * + * Since: 0.2 + */ +bool +raqm_index_to_position (raqm_t *rq, + size_t *index, + int *x, + int *y) +{ + /* We don't currently support multiline, so y is always 0 */ + *y = 0; + *x = 0; + + if (rq == NULL) + return false; + + if (rq->flags & RAQM_FLAG_UTF8) + *index = _raqm_u8_to_u32_index (rq, *index); + + if (*index >= rq->text_len) + return false; + + RAQM_TEST ("\n"); + + while (*index < rq->text_len) + { + if (_raqm_allowed_grapheme_boundary (rq->text[*index], rq->text[*index + 1])) + break; + + ++*index; + } + + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + { + size_t len; + hb_glyph_info_t *info; + hb_glyph_position_t *position; + len = hb_buffer_get_length (run->buffer); + info = hb_buffer_get_glyph_infos (run->buffer, NULL); + position = hb_buffer_get_glyph_positions (run->buffer, NULL); + + for (size_t i = 0; i < len; i++) + { + uint32_t curr_cluster = info[i].cluster; + uint32_t next_cluster = curr_cluster; + *x += position[i].x_advance; + + if (run->direction == HB_DIRECTION_LTR) + { + for (size_t j = i + 1; j < len && next_cluster == curr_cluster; j++) + next_cluster = info[j].cluster; + } + else + { + for (int j = i - 1; i != 0 && j >= 0 && next_cluster == curr_cluster; + j--) + next_cluster = info[j].cluster; + } + + if (next_cluster == curr_cluster) + next_cluster = run->pos + run->len; + + if (*index < next_cluster && *index >= curr_cluster) + { + if (run->direction == HB_DIRECTION_RTL) + *x -= position[i].x_advance; + *index = curr_cluster; + goto found; + } + } + } + +found: + if (rq->flags & RAQM_FLAG_UTF8) + *index = _raqm_u32_to_u8_index (rq, *index); + RAQM_TEST ("The position is %d at index %zu\n",*x ,*index); + return true; +} + +/** + * raqm_position_to_index: + * @rq: a #raqm_t. + * @x: x position. + * @y: y position. + * @index: (out): output character index. + * + * Returns the @index of the character at @x and @y position within text. + * If the position is outside the text, the last character is chosen as + * @index. + * + * Return value: + * %true if the process was successful, %false in case of error. + * + * Since: 0.2 + */ +bool +raqm_position_to_index (raqm_t *rq, + int x, + int y, + size_t *index) +{ + int delta_x = 0, current_x = 0; + (void)y; + + if (rq == NULL) + return false; + + if (x < 0) /* Get leftmost index */ + { + if (rq->resolved_dir == RAQM_DIRECTION_RTL) + *index = rq->text_len; + else + *index = 0; + return true; + } + + RAQM_TEST ("\n"); + + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + { + size_t len; + hb_glyph_info_t *info; + hb_glyph_position_t *position; + len = hb_buffer_get_length (run->buffer); + info = hb_buffer_get_glyph_infos (run->buffer, NULL); + position = hb_buffer_get_glyph_positions (run->buffer, NULL); + + for (size_t i = 0; i < len; i++) + { + delta_x = position[i].x_advance; + if (x < (current_x + delta_x)) + { + bool before = false; + if (run->direction == HB_DIRECTION_LTR) + before = (x < current_x + (delta_x / 2)); + else + before = (x > current_x + (delta_x / 2)); + + if (before) + *index = info[i].cluster; + else + { + uint32_t curr_cluster = info[i].cluster; + uint32_t next_cluster = curr_cluster; + if (run->direction == HB_DIRECTION_LTR) + for (size_t j = i + 1; j < len && next_cluster == curr_cluster; j++) + next_cluster = info[j].cluster; + else + for (int j = i - 1; i != 0 && j >= 0 && next_cluster == curr_cluster; + j--) + next_cluster = info[j].cluster; + + if (next_cluster == curr_cluster) + next_cluster = run->pos + run->len; + + *index = next_cluster; + } + if (_raqm_allowed_grapheme_boundary (rq->text[*index],rq->text[*index + 1])) + { + RAQM_TEST ("The start-index is %zu at position %d \n", *index, x); + return true; + } + + while (*index < (unsigned)run->pos + run->len) + { + if (_raqm_allowed_grapheme_boundary (rq->text[*index], + rq->text[*index + 1])) + { + *index += 1; + break; + } + *index += 1; + } + RAQM_TEST ("The start-index is %zu at position %d \n", *index, x); + return true; + } + else + current_x += delta_x; + } + } + + /* Get rightmost index*/ + if (rq->resolved_dir == RAQM_DIRECTION_RTL) + *index = 0; + else + *index = rq->text_len; + + RAQM_TEST ("The start-index is %zu at position %d \n", *index, x); + + return true; +} + +typedef enum +{ + RAQM_GRAPHEM_CR, + RAQM_GRAPHEM_LF, + RAQM_GRAPHEM_CONTROL, + RAQM_GRAPHEM_EXTEND, + RAQM_GRAPHEM_REGIONAL_INDICATOR, + RAQM_GRAPHEM_PREPEND, + RAQM_GRAPHEM_SPACING_MARK, + RAQM_GRAPHEM_HANGUL_SYLLABLE, + RAQM_GRAPHEM_OTHER +} _raqm_grapheme_t; + +static _raqm_grapheme_t +_raqm_get_grapheme_break (hb_codepoint_t ch, + hb_unicode_general_category_t category); + +static bool +_raqm_allowed_grapheme_boundary (hb_codepoint_t l_char, + hb_codepoint_t r_char) +{ + hb_unicode_general_category_t l_category; + hb_unicode_general_category_t r_category; + _raqm_grapheme_t l_grapheme, r_grapheme; + hb_unicode_funcs_t* unicode_funcs = hb_unicode_funcs_get_default (); + + l_category = hb_unicode_general_category (unicode_funcs, l_char); + r_category = hb_unicode_general_category (unicode_funcs, r_char); + l_grapheme = _raqm_get_grapheme_break (l_char, l_category); + r_grapheme = _raqm_get_grapheme_break (r_char, r_category); + + if (l_grapheme == RAQM_GRAPHEM_CR && r_grapheme == RAQM_GRAPHEM_LF) + return false; /*Do not break between a CR and LF GB3*/ + if (l_grapheme == RAQM_GRAPHEM_CONTROL || l_grapheme == RAQM_GRAPHEM_CR || + l_grapheme == RAQM_GRAPHEM_LF || r_grapheme == RAQM_GRAPHEM_CONTROL || + r_grapheme == RAQM_GRAPHEM_CR || r_grapheme == RAQM_GRAPHEM_LF) + return true; /*Break before and after CONTROL GB4, GB5*/ + if (r_grapheme == RAQM_GRAPHEM_HANGUL_SYLLABLE) + return false; /*Do not break Hangul syllable sequences. GB6, GB7, GB8*/ + if (l_grapheme == RAQM_GRAPHEM_REGIONAL_INDICATOR && + r_grapheme == RAQM_GRAPHEM_REGIONAL_INDICATOR) + return false; /*Do not break between regional indicator symbols. GB8a*/ + if (r_grapheme == RAQM_GRAPHEM_EXTEND) + return false; /*Do not break before extending characters. GB9*/ + /*Do not break before SpacingMarks, or after Prepend characters.GB9a, GB9b*/ + if (l_grapheme == RAQM_GRAPHEM_PREPEND) + return false; + if (r_grapheme == RAQM_GRAPHEM_SPACING_MARK) + return false; + return true; /*Otherwise, break everywhere. GB1, GB2, GB10*/ +} + +static _raqm_grapheme_t +_raqm_get_grapheme_break (hb_codepoint_t ch, + hb_unicode_general_category_t category) +{ + _raqm_grapheme_t gb_type; + + gb_type = RAQM_GRAPHEM_OTHER; + switch ((int)category) + { + case HB_UNICODE_GENERAL_CATEGORY_FORMAT: + if (ch == 0x200C || ch == 0x200D) + gb_type = RAQM_GRAPHEM_EXTEND; + else + gb_type = RAQM_GRAPHEM_CONTROL; + break; + + case HB_UNICODE_GENERAL_CATEGORY_CONTROL: + if (ch == 0x000D) + gb_type = RAQM_GRAPHEM_CR; + else if (ch == 0x000A) + gb_type = RAQM_GRAPHEM_LF; + else + gb_type = RAQM_GRAPHEM_CONTROL; + break; + + case HB_UNICODE_GENERAL_CATEGORY_SURROGATE: + case HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR: + case HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR: + case HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED: + if ((ch >= 0xFFF0 && ch <= 0xFFF8) || + (ch >= 0xE0000 && ch <= 0xE0FFF)) + gb_type = RAQM_GRAPHEM_CONTROL; + break; + + case HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK: + case HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK: + case HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK: + if (ch != 0x102B && ch != 0x102C && ch != 0x1038 && + (ch < 0x1062 || ch > 0x1064) && (ch < 0x1067 || ch > 0x106D) && + ch != 0x1083 && (ch < 0x1087 || ch > 0x108C) && ch != 0x108F && + (ch < 0x109A || ch > 0x109C) && ch != 0x1A61 && ch != 0x1A63 && + ch != 0x1A64 && ch != 0xAA7B && ch != 0xAA70 && ch != 0x11720 && + ch != 0x11721) /**/ + gb_type = RAQM_GRAPHEM_SPACING_MARK; + + else if (ch == 0x09BE || ch == 0x09D7 || + ch == 0x0B3E || ch == 0x0B57 || ch == 0x0BBE || ch == 0x0BD7 || + ch == 0x0CC2 || ch == 0x0CD5 || ch == 0x0CD6 || + ch == 0x0D3E || ch == 0x0D57 || ch == 0x0DCF || ch == 0x0DDF || + ch == 0x1D165 || (ch >= 0x1D16E && ch <= 0x1D172)) + gb_type = RAQM_GRAPHEM_EXTEND; + break; + + case HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER: + if (ch == 0x0E33 || ch == 0x0EB3) + gb_type = RAQM_GRAPHEM_SPACING_MARK; + break; + + case HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL: + if (ch >= 0x1F1E6 && ch <= 0x1F1FF) + gb_type = RAQM_GRAPHEM_REGIONAL_INDICATOR; + break; + + default: + gb_type = RAQM_GRAPHEM_OTHER; + break; + } + + if (_raqm_in_hangul_syllable (ch)) + gb_type = RAQM_GRAPHEM_HANGUL_SYLLABLE; + + return gb_type; +} + +static bool +_raqm_in_hangul_syllable (hb_codepoint_t ch) +{ + (void)ch; + return false; +} + +/** + * raqm_version: + * @major: (out): Library major version component. + * @minor: (out): Library minor version component. + * @micro: (out): Library micro version component. + * + * Returns library version as three integer components. + * + * Since: 0.7 + **/ +void +raqm_version (unsigned int *major, + unsigned int *minor, + unsigned int *micro) +{ + *major = RAQM_VERSION_MAJOR; + *minor = RAQM_VERSION_MINOR; + *micro = RAQM_VERSION_MICRO; +} + +/** + * raqm_version_string: + * + * Returns library version as a string with three components. + * + * Return value: library version string. + * + * Since: 0.7 + **/ +const char * +raqm_version_string (void) +{ + return RAQM_VERSION_STRING; +} + +/** + * raqm_version_atleast: + * @major: Library major version component. + * @minor: Library minor version component. + * @micro: Library micro version component. + * + * Checks if library version is less than or equal the specified version. + * + * Return value: + * %true if library version is less than or equal the specfied version, %false + * otherwise. + * + * Since: 0.7 + **/ +bool +raqm_version_atleast (unsigned int major, + unsigned int minor, + unsigned int micro) +{ + return RAQM_VERSION_ATLEAST (major, minor, micro); +} + +/** + * RAQM_VERSION_ATLEAST: + * @major: Library major version component. + * @minor: Library minor version component. + * @micro: Library micro version component. + * + * Checks if library version is less than or equal the specified version. + * + * Return value: + * %true if library version is less than or equal the specfied version, %false + * otherwise. + * + * Since: 0.7 + **/ + +/** + * RAQM_VERSION_STRING: + * + * Library version as a string with three components. + * + * Since: 0.7 + **/ + +/** + * RAQM_VERSION_MAJOR: + * + * Library major version component. + * + * Since: 0.7 + **/ + +/** + * RAQM_VERSION_MINOR: + * + * Library minor version component. + * + * Since: 0.7 + **/ + +/** + * RAQM_VERSION_MICRO: + * + * Library micro version component. + * + * Since: 0.7 + **/ diff --git a/src/thirdparty/raqm/raqm.h b/src/thirdparty/raqm/raqm.h new file mode 100644 index 000000000..1a33fe8ba --- /dev/null +++ b/src/thirdparty/raqm/raqm.h @@ -0,0 +1,185 @@ +/* + * Copyright © 2015 Information Technology Authority (ITA) + * Copyright © 2016 Khaled Hosny + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#ifndef _RAQM_H_ +#define _RAQM_H_ +#define _RAQM_H_IN_ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include FT_FREETYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "raqm-version.h" + +/** + * raqm_t: + * + * This is the main object holding all state of the currently processed text as + * well as its output. + * + * Since: 0.1 + */ +typedef struct _raqm raqm_t; + +/** + * raqm_direction_t: + * @RAQM_DIRECTION_DEFAULT: Detect paragraph direction automatically. + * @RAQM_DIRECTION_RTL: Paragraph is mainly right-to-left text. + * @RAQM_DIRECTION_LTR: Paragraph is mainly left-to-right text. + * @RAQM_DIRECTION_TTB: Paragraph is mainly vertical top-to-bottom text. + * + * Base paragraph direction, see raqm_set_par_direction(). + * + * Since: 0.1 + */ +typedef enum +{ + RAQM_DIRECTION_DEFAULT, + RAQM_DIRECTION_RTL, + RAQM_DIRECTION_LTR, + RAQM_DIRECTION_TTB +} raqm_direction_t; + +/** + * raqm_glyph_t: + * @index: the index of the glyph in the font file. + * @x_advance: the glyph advance width in horizontal text. + * @y_advance: the glyph advance width in vertical text. + * @x_offset: the horizontal movement of the glyph from the current point. + * @y_offset: the vertical movement of the glyph from the current point. + * @cluster: the index of original character in input text. + * @ftface: the @FT_Face of the glyph. + * + * The structure that holds information about output glyphs, returned from + * raqm_get_glyphs(). + */ +typedef struct raqm_glyph_t { + unsigned int index; + int x_advance; + int y_advance; + int x_offset; + int y_offset; + uint32_t cluster; + FT_Face ftface; +} raqm_glyph_t; + +raqm_t * +raqm_create (void); + +raqm_t * +raqm_reference (raqm_t *rq); + +void +raqm_destroy (raqm_t *rq); + +bool +raqm_set_text (raqm_t *rq, + const uint32_t *text, + size_t len); + +bool +raqm_set_text_utf8 (raqm_t *rq, + const char *text, + size_t len); + +bool +raqm_set_par_direction (raqm_t *rq, + raqm_direction_t dir); + +bool +raqm_set_language (raqm_t *rq, + const char *lang, + size_t start, + size_t len); + +bool +raqm_add_font_feature (raqm_t *rq, + const char *feature, + int len); + +bool +raqm_set_freetype_face (raqm_t *rq, + FT_Face face); + +bool +raqm_set_freetype_face_range (raqm_t *rq, + FT_Face face, + size_t start, + size_t len); + +bool +raqm_set_freetype_load_flags (raqm_t *rq, + int flags); + +bool +raqm_set_invisible_glyph (raqm_t *rq, + int gid); + +bool +raqm_layout (raqm_t *rq); + +raqm_glyph_t * +raqm_get_glyphs (raqm_t *rq, + size_t *length); + +bool +raqm_index_to_position (raqm_t *rq, + size_t *index, + int *x, + int *y); + +bool +raqm_position_to_index (raqm_t *rq, + int x, + int y, + size_t *index); + +void +raqm_version (unsigned int *major, + unsigned int *minor, + unsigned int *micro); + +const char * +raqm_version_string (void); + +bool +raqm_version_atleast (unsigned int major, + unsigned int minor, + unsigned int micro); + + +#ifdef __cplusplus +} +#endif +#undef _RAQM_H_IN_ +#endif /* _RAQM_H_ */ From 8bc1ff35b4d87003e54d7f8cdcbc687ad3a62762 Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 25 Nov 2020 11:21:42 +0000 Subject: [PATCH 02/89] use FriBiDi shim in Raqm --- setup.py | 16 +- src/_imagingft.c | 225 ++++++-------------------- src/libImaging/raqm.h | 156 ------------------ src/thirdparty/fribidi-shim/fribidi.c | 68 ++++++++ src/thirdparty/fribidi-shim/fribidi.h | 104 ++++++++++++ src/thirdparty/raqm/raqm.c | 7 +- winbuild/build_prepare.py | 20 +-- winbuild/fribidi.cmake | 4 +- 8 files changed, 243 insertions(+), 357 deletions(-) delete mode 100644 src/libImaging/raqm.h create mode 100644 src/thirdparty/fribidi-shim/fribidi.c create mode 100644 src/thirdparty/fribidi-shim/fribidi.h diff --git a/setup.py b/setup.py index cbc2641c5..3e0ec5576 100755 --- a/setup.py +++ b/setup.py @@ -267,6 +267,7 @@ class pil_build_ext(build_ext): "jpeg", "tiff", "freetype", + "harfbuzz", "lcms", "webp", "webpmux", @@ -656,6 +657,12 @@ class pil_build_ext(build_ext): if subdir: _add_directory(self.compiler.include_dirs, subdir, 0) + if feature.want("harfbuzz"): + _dbg("Looking for harfbuzz") + if _find_include_file(self, "hb-version.h"): + if _find_library_file(self, "harfbuzz"): + feature.harfbuzz = "harfbuzz" + if feature.want("lcms"): _dbg("Looking for lcms") if _find_include_file(self, "lcms2.h"): @@ -850,7 +857,14 @@ for src_file in _LIB_IMAGING: files.append(os.path.join("src/libImaging", src_file + ".c")) ext_modules = [ Extension("PIL._imaging", files), - Extension("PIL._imagingft", ["src/_imagingft.c"]), + Extension( + "PIL._imagingft", + [ + "src/_imagingft.c", + "src/thirdparty/raqm/raqm.c", + "src/thirdparty/fribidi-shim/fribidi.c", + ], + ), Extension("PIL._imagingcms", ["src/_imagingcms.c"]), Extension("PIL._webp", ["src/_webp.c"]), Extension("PIL._imagingtk", ["src/_imagingtk.c", "src/Tk/tkImaging.c"]), diff --git a/src/_imagingft.c b/src/_imagingft.c index d73c6c2d5..4a4084e9f 100644 --- a/src/_imagingft.c +++ b/src/_imagingft.c @@ -35,10 +35,6 @@ #define KEEP_PY_UNICODE -#ifndef _WIN32 -#include -#endif - #if !defined(FT_LOAD_TARGET_MONO) #define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME #endif @@ -56,7 +52,8 @@ } \ ; -#include "libImaging/raqm.h" +#include "thirdparty/raqm/raqm.h" +#include "thirdparty/fribidi-shim/fribidi.h" #define LAYOUT_FALLBACK 0 #define LAYOUT_RAQM 1 @@ -86,42 +83,6 @@ typedef struct { static PyTypeObject Font_Type; -typedef const char *(*t_raqm_version_string)(void); -typedef bool (*t_raqm_version_atleast)( - unsigned int major, unsigned int minor, unsigned int micro); -typedef raqm_t *(*t_raqm_create)(void); -typedef int (*t_raqm_set_text)(raqm_t *rq, const uint32_t *text, size_t len); -typedef bool (*t_raqm_set_text_utf8)(raqm_t *rq, const char *text, size_t len); -typedef bool (*t_raqm_set_par_direction)(raqm_t *rq, raqm_direction_t dir); -typedef bool (*t_raqm_set_language)( - raqm_t *rq, const char *lang, size_t start, size_t len); -typedef bool (*t_raqm_add_font_feature)(raqm_t *rq, const char *feature, int len); -typedef bool (*t_raqm_set_freetype_face)(raqm_t *rq, FT_Face face); -typedef bool (*t_raqm_layout)(raqm_t *rq); -typedef raqm_glyph_t *(*t_raqm_get_glyphs)(raqm_t *rq, size_t *length); -typedef raqm_glyph_t_01 *(*t_raqm_get_glyphs_01)(raqm_t *rq, size_t *length); -typedef void (*t_raqm_destroy)(raqm_t *rq); - -typedef struct { - void *raqm; - int version; - t_raqm_version_string version_string; - t_raqm_version_atleast version_atleast; - t_raqm_create create; - t_raqm_set_text set_text; - t_raqm_set_text_utf8 set_text_utf8; - t_raqm_set_par_direction set_par_direction; - t_raqm_set_language set_language; - t_raqm_add_font_feature add_font_feature; - t_raqm_set_freetype_face set_freetype_face; - t_raqm_layout layout; - t_raqm_get_glyphs get_glyphs; - t_raqm_get_glyphs_01 get_glyphs_01; - t_raqm_destroy destroy; -} p_raqm_func; - -static p_raqm_func p_raqm; - /* round a 26.6 pixel coordinate to the nearest integer */ #define PIXEL(x) ((((x) + 32) & -64) >> 6) @@ -142,101 +103,7 @@ geterror(int code) { static int setraqm(void) { - /* set the static function pointers for dynamic raqm linking */ - p_raqm.raqm = NULL; - - /* Microsoft needs a totally different system */ -#ifndef _WIN32 - p_raqm.raqm = dlopen("libraqm.so.0", RTLD_LAZY); - if (!p_raqm.raqm) { - p_raqm.raqm = dlopen("libraqm.dylib", RTLD_LAZY); - } -#else - p_raqm.raqm = LoadLibrary("libraqm"); - /* MSYS */ - if (!p_raqm.raqm) { - p_raqm.raqm = LoadLibrary("libraqm-0"); - } -#endif - - if (!p_raqm.raqm) { - return 1; - } - -#ifndef _WIN32 - p_raqm.version_string = - (t_raqm_version_string)dlsym(p_raqm.raqm, "raqm_version_string"); - p_raqm.version_atleast = - (t_raqm_version_atleast)dlsym(p_raqm.raqm, "raqm_version_atleast"); - p_raqm.create = (t_raqm_create)dlsym(p_raqm.raqm, "raqm_create"); - p_raqm.set_text = (t_raqm_set_text)dlsym(p_raqm.raqm, "raqm_set_text"); - p_raqm.set_text_utf8 = - (t_raqm_set_text_utf8)dlsym(p_raqm.raqm, "raqm_set_text_utf8"); - p_raqm.set_par_direction = - (t_raqm_set_par_direction)dlsym(p_raqm.raqm, "raqm_set_par_direction"); - p_raqm.set_language = (t_raqm_set_language)dlsym(p_raqm.raqm, "raqm_set_language"); - p_raqm.add_font_feature = - (t_raqm_add_font_feature)dlsym(p_raqm.raqm, "raqm_add_font_feature"); - p_raqm.set_freetype_face = - (t_raqm_set_freetype_face)dlsym(p_raqm.raqm, "raqm_set_freetype_face"); - p_raqm.layout = (t_raqm_layout)dlsym(p_raqm.raqm, "raqm_layout"); - p_raqm.destroy = (t_raqm_destroy)dlsym(p_raqm.raqm, "raqm_destroy"); - if (dlsym(p_raqm.raqm, "raqm_index_to_position")) { - p_raqm.get_glyphs = (t_raqm_get_glyphs)dlsym(p_raqm.raqm, "raqm_get_glyphs"); - p_raqm.version = 2; - } else { - p_raqm.version = 1; - p_raqm.get_glyphs_01 = - (t_raqm_get_glyphs_01)dlsym(p_raqm.raqm, "raqm_get_glyphs"); - } - if (dlerror() || - !(p_raqm.create && p_raqm.set_text && p_raqm.set_text_utf8 && - p_raqm.set_par_direction && p_raqm.set_language && p_raqm.add_font_feature && - p_raqm.set_freetype_face && p_raqm.layout && - (p_raqm.get_glyphs || p_raqm.get_glyphs_01) && p_raqm.destroy)) { - dlclose(p_raqm.raqm); - p_raqm.raqm = NULL; - return 2; - } -#else - p_raqm.version_string = - (t_raqm_version_string)GetProcAddress(p_raqm.raqm, "raqm_version_string"); - p_raqm.version_atleast = - (t_raqm_version_atleast)GetProcAddress(p_raqm.raqm, "raqm_version_atleast"); - p_raqm.create = (t_raqm_create)GetProcAddress(p_raqm.raqm, "raqm_create"); - p_raqm.set_text = (t_raqm_set_text)GetProcAddress(p_raqm.raqm, "raqm_set_text"); - p_raqm.set_text_utf8 = - (t_raqm_set_text_utf8)GetProcAddress(p_raqm.raqm, "raqm_set_text_utf8"); - p_raqm.set_par_direction = - (t_raqm_set_par_direction)GetProcAddress(p_raqm.raqm, "raqm_set_par_direction"); - p_raqm.set_language = - (t_raqm_set_language)GetProcAddress(p_raqm.raqm, "raqm_set_language"); - p_raqm.add_font_feature = - (t_raqm_add_font_feature)GetProcAddress(p_raqm.raqm, "raqm_add_font_feature"); - p_raqm.set_freetype_face = - (t_raqm_set_freetype_face)GetProcAddress(p_raqm.raqm, "raqm_set_freetype_face"); - p_raqm.layout = (t_raqm_layout)GetProcAddress(p_raqm.raqm, "raqm_layout"); - p_raqm.destroy = (t_raqm_destroy)GetProcAddress(p_raqm.raqm, "raqm_destroy"); - if (GetProcAddress(p_raqm.raqm, "raqm_index_to_position")) { - p_raqm.get_glyphs = - (t_raqm_get_glyphs)GetProcAddress(p_raqm.raqm, "raqm_get_glyphs"); - p_raqm.version = 2; - } else { - p_raqm.version = 1; - p_raqm.get_glyphs_01 = - (t_raqm_get_glyphs_01)GetProcAddress(p_raqm.raqm, "raqm_get_glyphs"); - } - if (!(p_raqm.create && p_raqm.set_text && p_raqm.set_text_utf8 && - p_raqm.set_par_direction && p_raqm.set_language && p_raqm.add_font_feature && - p_raqm.set_freetype_face && p_raqm.layout && - (p_raqm.get_glyphs || p_raqm.get_glyphs_01) && p_raqm.destroy)) { - FreeLibrary(p_raqm.raqm); - p_raqm.raqm = NULL; - return 2; - } -#endif - - return 0; + return load_fribidi(); } static PyObject * @@ -359,10 +226,10 @@ text_layout_raqm( size_t i = 0, count = 0, start = 0; raqm_t *rq; raqm_glyph_t *glyphs = NULL; - raqm_glyph_t_01 *glyphs_01 = NULL; +// raqm_glyph_t_01 *glyphs_01 = NULL; raqm_direction_t direction; - rq = (*p_raqm.create)(); + rq = raqm_create(); if (rq == NULL) { PyErr_SetString(PyExc_ValueError, "raqm_create() failed."); goto failed; @@ -376,14 +243,14 @@ text_layout_raqm( and raqm fails with empty strings */ goto failed; } - int set_text = (*p_raqm.set_text)(rq, text, size); + int set_text = raqm_set_text(rq, text, size); PyMem_Free(text); if (!set_text) { PyErr_SetString(PyExc_ValueError, "raqm_set_text() failed"); goto failed; } if (lang) { - if (!(*p_raqm.set_language)(rq, lang, start, size)) { + if (!raqm_set_language(rq, lang, start, size)) { PyErr_SetString(PyExc_ValueError, "raqm_set_language() failed"); goto failed; } @@ -401,12 +268,12 @@ text_layout_raqm( direction = RAQM_DIRECTION_LTR; } else if (strcmp(dir, "ttb") == 0) { direction = RAQM_DIRECTION_TTB; - if (p_raqm.version_atleast == NULL || !(*p_raqm.version_atleast)(0, 7, 0)) { - PyErr_SetString( - PyExc_ValueError, - "libraqm 0.7 or greater required for 'ttb' direction"); - goto failed; - } +// if (p_raqm.version_atleast == NULL || !(*p_raqm.version_atleast)(0, 7, 0)) { +// PyErr_SetString( +// PyExc_ValueError, +// "libraqm 0.7 or greater required for 'ttb' direction"); +// goto failed; +// } } else { PyErr_SetString( PyExc_ValueError, "direction must be either 'rtl', 'ltr' or 'ttb'"); @@ -414,7 +281,7 @@ text_layout_raqm( } } - if (!(*p_raqm.set_par_direction)(rq, direction)) { + if (!raqm_set_par_direction(rq, direction)) { PyErr_SetString(PyExc_ValueError, "raqm_set_par_direction() failed"); goto failed; } @@ -446,38 +313,38 @@ text_layout_raqm( feature = PyBytes_AS_STRING(bytes); size = PyBytes_GET_SIZE(bytes); } - if (!(*p_raqm.add_font_feature)(rq, feature, size)) { + if (!raqm_add_font_feature(rq, feature, size)) { PyErr_SetString(PyExc_ValueError, "raqm_add_font_feature() failed"); goto failed; } } } - if (!(*p_raqm.set_freetype_face)(rq, self->face)) { + if (!raqm_set_freetype_face(rq, self->face)) { PyErr_SetString(PyExc_RuntimeError, "raqm_set_freetype_face() failed."); goto failed; } - if (!(*p_raqm.layout)(rq)) { + if (!raqm_layout(rq)) { PyErr_SetString(PyExc_RuntimeError, "raqm_layout() failed."); goto failed; } - if (p_raqm.version == 1) { - glyphs_01 = (*p_raqm.get_glyphs_01)(rq, &count); - if (glyphs_01 == NULL) { - PyErr_SetString(PyExc_ValueError, "raqm_get_glyphs() failed."); - count = 0; - goto failed; - } - } else { /* version == 2 */ - glyphs = (*p_raqm.get_glyphs)(rq, &count); +// if (p_raqm.version == 1) { +// glyphs_01 = raqm_get_glyphs_01(rq, &count); +// if (glyphs_01 == NULL) { +// PyErr_SetString(PyExc_ValueError, "raqm_get_glyphs() failed."); +// count = 0; +// goto failed; +// } +// } else { /* version == 2 */ + glyphs = raqm_get_glyphs(rq, &count); if (glyphs == NULL) { PyErr_SetString(PyExc_ValueError, "raqm_get_glyphs() failed."); count = 0; goto failed; } - } +// } (*glyph_info) = PyMem_New(GlyphInfo, count); if ((*glyph_info) == NULL) { @@ -486,16 +353,16 @@ text_layout_raqm( goto failed; } - if (p_raqm.version == 1) { - for (i = 0; i < count; i++) { - (*glyph_info)[i].index = glyphs_01[i].index; - (*glyph_info)[i].x_offset = glyphs_01[i].x_offset; - (*glyph_info)[i].x_advance = glyphs_01[i].x_advance; - (*glyph_info)[i].y_offset = glyphs_01[i].y_offset; - (*glyph_info)[i].y_advance = glyphs_01[i].y_advance; - (*glyph_info)[i].cluster = glyphs_01[i].cluster; - } - } else { +// if (p_raqm.version == 1) { +// for (i = 0; i < count; i++) { +// (*glyph_info)[i].index = glyphs_01[i].index; +// (*glyph_info)[i].x_offset = glyphs_01[i].x_offset; +// (*glyph_info)[i].x_advance = glyphs_01[i].x_advance; +// (*glyph_info)[i].y_offset = glyphs_01[i].y_offset; +// (*glyph_info)[i].y_advance = glyphs_01[i].y_advance; +// (*glyph_info)[i].cluster = glyphs_01[i].cluster; +// } +// } else { for (i = 0; i < count; i++) { (*glyph_info)[i].index = glyphs[i].index; (*glyph_info)[i].x_offset = glyphs[i].x_offset; @@ -504,10 +371,10 @@ text_layout_raqm( (*glyph_info)[i].y_advance = glyphs[i].y_advance; (*glyph_info)[i].cluster = glyphs[i].cluster; } - } +// } failed: - (*p_raqm.destroy)(rq); + raqm_destroy(rq); return count; } @@ -607,9 +474,9 @@ text_layout( int color) { size_t count; - if (p_raqm.raqm && self->layout_engine == LAYOUT_RAQM) { + if (p_fribidi && self->layout_engine == LAYOUT_RAQM) { count = text_layout_raqm( - string, self, dir, features, lang, glyph_info, mask, color); + string, self, dir, features, lang, glyph_info, mask, color); } else { count = text_layout_fallback( string, self, dir, features, lang, glyph_info, mask, color); @@ -1491,12 +1358,14 @@ setup_module(PyObject *m) { PyDict_SetItemString(d, "freetype2_version", v); setraqm(); - v = PyBool_FromLong(!!p_raqm.raqm); + v = PyBool_FromLong(!!p_fribidi); PyDict_SetItemString(d, "HAVE_RAQM", v); - if (p_raqm.version_string) { +// if (p_raqm.version_string) { PyDict_SetItemString( - d, "raqm_version", PyUnicode_FromString(p_raqm.version_string())); - } + d, "raqm_version", PyUnicode_FromString(raqm_version_string())); +// }; + + PyDict_SetItemString(d, "HAVE_FRIBIDI", v); return 0; } diff --git a/src/libImaging/raqm.h b/src/libImaging/raqm.h deleted file mode 100644 index 5f865853a..000000000 --- a/src/libImaging/raqm.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright © 2015 Information Technology Authority (ITA) - * Copyright © 2016 Khaled Hosny - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - */ - -#ifndef _RAQM_H_ -#define _RAQM_H_ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifndef bool -typedef int bool; -#endif -#ifndef uint32_t -typedef UINT32 uint32_t; -#endif -#include -#include FT_FREETYPE_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * raqm_t: - * - * This is the main object holding all state of the currently processed text as - * well as its output. - * - * Since: 0.1 - */ -typedef struct _raqm raqm_t; - -/** - * raqm_direction_t: - * @RAQM_DIRECTION_DEFAULT: Detect paragraph direction automatically. - * @RAQM_DIRECTION_RTL: Paragraph is mainly right-to-left text. - * @RAQM_DIRECTION_LTR: Paragraph is mainly left-to-right text. - * @RAQM_DIRECTION_TTB: Paragraph is mainly vertical top-to-bottom text. - * - * Base paragraph direction, see raqm_set_par_direction(). - * - * Since: 0.1 - */ -typedef enum { - RAQM_DIRECTION_DEFAULT, - RAQM_DIRECTION_RTL, - RAQM_DIRECTION_LTR, - RAQM_DIRECTION_TTB -} raqm_direction_t; - -/** - * raqm_glyph_t: - * @index: the index of the glyph in the font file. - * @x_advance: the glyph advance width in horizontal text. - * @y_advance: the glyph advance width in vertical text. - * @x_offset: the horizontal movement of the glyph from the current point. - * @y_offset: the vertical movement of the glyph from the current point. - * @cluster: the index of original character in input text. - * @ftface: the @FT_Face of the glyph. - * - * The structure that holds information about output glyphs, returned from - * raqm_get_glyphs(). - */ -typedef struct raqm_glyph_t { - unsigned int index; - int x_advance; - int y_advance; - int x_offset; - int y_offset; - uint32_t cluster; - FT_Face ftface; -} raqm_glyph_t; - -/** - * version 0.1 of the raqm_glyph_t structure - */ -typedef struct raqm_glyph_t_01 { - unsigned int index; - int x_advance; - int y_advance; - int x_offset; - int y_offset; - uint32_t cluster; -} raqm_glyph_t_01; - -raqm_t * -raqm_create(void); - -raqm_t * -raqm_reference(raqm_t *rq); - -void -raqm_destroy(raqm_t *rq); - -bool -raqm_set_text(raqm_t *rq, const uint32_t *text, size_t len); - -bool -raqm_set_text_utf8(raqm_t *rq, const char *text, size_t len); - -bool -raqm_set_par_direction(raqm_t *rq, raqm_direction_t dir); - -bool -raqm_set_language(raqm_t *rq, const char *lang, size_t start, size_t len); - -bool -raqm_add_font_feature(raqm_t *rq, const char *feature, int len); - -bool -raqm_set_freetype_face(raqm_t *rq, FT_Face face); - -bool -raqm_set_freetype_face_range(raqm_t *rq, FT_Face face, size_t start, size_t len); - -bool -raqm_set_freetype_load_flags(raqm_t *rq, int flags); - -bool -raqm_layout(raqm_t *rq); - -raqm_glyph_t * -raqm_get_glyphs(raqm_t *rq, size_t *length); - -bool -raqm_index_to_position(raqm_t *rq, size_t *index, int *x, int *y); - -bool -raqm_position_to_index(raqm_t *rq, int x, int y, size_t *index); - -#ifdef __cplusplus -} -#endif -#endif /* _RAQM_H_ */ diff --git a/src/thirdparty/fribidi-shim/fribidi.c b/src/thirdparty/fribidi-shim/fribidi.c new file mode 100644 index 000000000..64ff7e115 --- /dev/null +++ b/src/thirdparty/fribidi-shim/fribidi.c @@ -0,0 +1,68 @@ + +#ifndef _WIN32 +#include +#else +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#define FRIBIDI_SHIM_IMPLEMENTATION + +#include "fribidi.h" + +int load_fribidi(void) { + int error = 0; + + p_fribidi = NULL; + + /* Microsoft needs a totally different system */ +#ifndef _WIN32 + p_fribidi = dlopen("libfribidi.so.1", RTLD_LAZY); + if (!p_fribidi) { + p_fribidi = dlopen("libfribidi.dylib", RTLD_LAZY); + } +#else + p_fribidi = LoadLibrary("fribidi"); + /* MSYS2 */ + if (!p_fribidi) { + p_fribidi = LoadLibrary("libfribidi-1"); + } +#endif + + if (!p_fribidi) { + return 1; + } + +#ifndef _WIN32 +#define LOAD_FUNCTION(func) \ + func = (t_##func)dlsym(p_fribidi, #func); \ + error = error || (func == NULL); +#else +#define LOAD_FUNCTION(func) \ + func = (t_##func)GetProcAddress(p_fribidi, #func); \ + error = error || (func == NULL); +#endif + + LOAD_FUNCTION(fribidi_get_bidi_types); + LOAD_FUNCTION(fribidi_get_bracket_types); + LOAD_FUNCTION(fribidi_get_par_embedding_levels_ex); +// LOAD_FUNCTION(fribidi_get_par_embedding_levels); + LOAD_FUNCTION(fribidi_unicode_to_charset); + LOAD_FUNCTION(fribidi_charset_to_unicode); + +#ifndef _WIN32 + if (dlerror() || error) { + dlclose(p_fribidi); + p_fribidi = NULL; + return 2; + } +#else + if (error) { + FreeLibrary(p_fribidi); + p_fribidi = NULL; + return 2; + } +#endif + + return 0; +} diff --git a/src/thirdparty/fribidi-shim/fribidi.h b/src/thirdparty/fribidi-shim/fribidi.h new file mode 100644 index 000000000..c79bb170a --- /dev/null +++ b/src/thirdparty/fribidi-shim/fribidi.h @@ -0,0 +1,104 @@ + +/* fribidi-types.h */ + +# if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \ + defined (_sgi) || defined (__sun) || defined (sun) || \ + defined (__digital__) || defined (__HP_cc) +# include +# elif defined (_AIX) +# include +# else +# include +# endif + +typedef uint32_t FriBidiChar; +typedef int FriBidiStrIndex; + +typedef FriBidiChar FriBidiBracketType; + + + +/* fribidi-char-sets.h */ + +typedef enum +{ + _FRIBIDI_CHAR_SET_NOT_FOUND, + FRIBIDI_CHAR_SET_UTF8, + FRIBIDI_CHAR_SET_CAP_RTL, + FRIBIDI_CHAR_SET_ISO8859_6, + FRIBIDI_CHAR_SET_ISO8859_8, + FRIBIDI_CHAR_SET_CP1255, + FRIBIDI_CHAR_SET_CP1256, + _FRIBIDI_CHAR_SETS_NUM_PLUS_ONE +} +FriBidiCharSet; + + + +/* fribidi-bidi-types.h */ + +typedef signed char FriBidiLevel; + +#define FRIBIDI_TYPE_LTR_VAL 0x00000110L +#define FRIBIDI_TYPE_RTL_VAL 0x00000111L +#define FRIBIDI_TYPE_ON_VAL 0x00000040L + +typedef uint32_t FriBidiCharType; +#define FRIBIDI_TYPE_LTR FRIBIDI_TYPE_LTR_VAL + +typedef uint32_t FriBidiParType; +#define FRIBIDI_PAR_LTR FRIBIDI_TYPE_LTR_VAL +#define FRIBIDI_PAR_RTL FRIBIDI_TYPE_RTL_VAL +#define FRIBIDI_PAR_ON FRIBIDI_TYPE_ON_VAL + +#define FRIBIDI_LEVEL_IS_RTL(lev) ((lev) & 1) +#define FRIBIDI_DIR_TO_LEVEL(dir) ((FriBidiLevel) (FRIBIDI_IS_RTL(dir) ? 1 : 0)) +#define FRIBIDI_IS_RTL(p) ((p) & 0x00000001L) +#define FRIBIDI_IS_EXPLICIT_OR_BN_OR_WS(p) ((p) & 0x00901000L) + + + +/* functions */ + +#ifdef FRIBIDI_SHIM_IMPLEMENTATION +#define FRIBIDI_ENTRY +#else +#define FRIBIDI_ENTRY extern +#endif + +#define FRIBIDI_FUNC(ret, name, ...) \ + typedef ret (*t_##name) (__VA_ARGS__); \ + FRIBIDI_ENTRY t_##name name; + +FRIBIDI_FUNC(void, fribidi_get_bidi_types, + const FriBidiChar *, const FriBidiStrIndex, FriBidiCharType *); + +FRIBIDI_FUNC(void, fribidi_get_bracket_types, + const FriBidiChar *, const FriBidiStrIndex, const FriBidiCharType *, + FriBidiBracketType *); + +FRIBIDI_FUNC(FriBidiLevel, fribidi_get_par_embedding_levels_ex, + const FriBidiCharType *, const FriBidiBracketType *, const FriBidiStrIndex, + FriBidiParType *, FriBidiLevel *); + +//FRIBIDI_FUNC(FriBidiLevel, fribidi_get_par_embedding_levels, +// const FriBidiCharType *, const FriBidiStrIndex, FriBidiParType *, +// FriBidiLevel *); + +FRIBIDI_FUNC(FriBidiStrIndex, fribidi_unicode_to_charset, + FriBidiCharSet, const FriBidiChar *, FriBidiStrIndex, char *); + +FRIBIDI_FUNC(FriBidiStrIndex, fribidi_charset_to_unicode, + FriBidiCharSet, const char *, FriBidiStrIndex, FriBidiChar *); + +#undef FRIBIDI_FUNC + + + +/* shim */ + +FRIBIDI_ENTRY void *p_fribidi; + +FRIBIDI_ENTRY int load_fribidi(void); + +#undef FRIBIDI_ENTRY diff --git a/src/thirdparty/raqm/raqm.c b/src/thirdparty/raqm/raqm.c index 27e59b5fc..c796f645e 100644 --- a/src/thirdparty/raqm/raqm.c +++ b/src/thirdparty/raqm/raqm.c @@ -30,15 +30,16 @@ #include #include -#include +#include "../fribidi-shim/fribidi.h" + #include #include #include "raqm.h" -#if FRIBIDI_MAJOR_VERSION >= 1 +//#if FRIBIDI_MAJOR_VERSION >= 1 #define USE_FRIBIDI_EX_API -#endif +//#endif /** * SECTION:raqm diff --git a/winbuild/build_prepare.py b/winbuild/build_prepare.py index 2531d5504..fd63f4f1e 100644 --- a/winbuild/build_prepare.py +++ b/winbuild/build_prepare.py @@ -296,21 +296,7 @@ deps = { cmd_nmake(target="clean"), cmd_nmake(target="fribidi"), ], - "headers": [r"lib\*.h"], - "libs": [r"*.lib"], - }, - "libraqm": { - "url": "https://github.com/HOST-Oman/libraqm/archive/v0.7.1.zip", - "filename": "libraqm-0.7.1.zip", - "dir": "libraqm-0.7.1", - "build": [ - cmd_copy(r"{winbuild_dir}\raqm.cmake", r"CMakeLists.txt"), - cmd_cmake(), - cmd_nmake(target="clean"), - cmd_nmake(target="libraqm"), - ], - "headers": [r"src\*.h"], - "bins": [r"libraqm.dll"], + "bins": [r"*.dll"], }, } @@ -511,8 +497,8 @@ if __name__ == "__main__": verbose = True elif arg == "--no-imagequant": disabled += ["libimagequant"] - elif arg == "--no-raqm": - disabled += ["fribidi", "libraqm"] + elif arg == "--no-raqm" or arg == "--no-fribidi": + disabled += ["fribidi"] elif arg.startswith("--depends="): depends_dir = arg[10:] elif arg.startswith("--python="): diff --git a/winbuild/fribidi.cmake b/winbuild/fribidi.cmake index 47ab2c329..acb614bfa 100644 --- a/winbuild/fribidi.cmake +++ b/winbuild/fribidi.cmake @@ -93,10 +93,10 @@ fribidi_tab(brackets-type unidata/BidiBrackets.txt) file(GLOB FRIBIDI_SOURCES lib/*.c) file(GLOB FRIBIDI_HEADERS lib/*.h) -add_library(fribidi STATIC +add_library(fribidi SHARED ${FRIBIDI_SOURCES} ${FRIBIDI_HEADERS} ${FRIBIDI_SOURCES_GENERATED}) fribidi_definitions(fribidi) target_compile_definitions(fribidi - PUBLIC -DFRIBIDI_LIB_STATIC) + PUBLIC "-DFRIBIDI_ENTRY=__declspec(dllexport)") From 9e5fc136b90e86a4cfbd437455cbe60e4aeeba4c Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 25 Nov 2020 11:23:45 +0000 Subject: [PATCH 03/89] add Raqm license and readme --- src/thirdparty/raqm/AUTHORS | 9 ++++ src/thirdparty/raqm/COPYING | 22 +++++++++ src/thirdparty/raqm/NEWS | 89 +++++++++++++++++++++++++++++++++++++ src/thirdparty/raqm/README | 85 +++++++++++++++++++++++++++++++++++ 4 files changed, 205 insertions(+) create mode 100644 src/thirdparty/raqm/AUTHORS create mode 100644 src/thirdparty/raqm/COPYING create mode 100644 src/thirdparty/raqm/NEWS create mode 100644 src/thirdparty/raqm/README diff --git a/src/thirdparty/raqm/AUTHORS b/src/thirdparty/raqm/AUTHORS new file mode 100644 index 000000000..bd5c3ac6b --- /dev/null +++ b/src/thirdparty/raqm/AUTHORS @@ -0,0 +1,9 @@ +Abderraouf Adjal +Ali Yousuf +Anood Almuharbi +Asma Albahanta +Fahad Alsaidi +Ibtisam Almabsali +Khaled Hosny +Mazoon Almaamari +Shamsa Alqassabi diff --git a/src/thirdparty/raqm/COPYING b/src/thirdparty/raqm/COPYING new file mode 100644 index 000000000..196511ef6 --- /dev/null +++ b/src/thirdparty/raqm/COPYING @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright © 2015 Information Technology Authority (ITA) +Copyright © 2016 Khaled Hosny + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/thirdparty/raqm/NEWS b/src/thirdparty/raqm/NEWS new file mode 100644 index 000000000..29c9ae0e5 --- /dev/null +++ b/src/thirdparty/raqm/NEWS @@ -0,0 +1,89 @@ +Overview of changes leading to 0.7.1 +Sunday, November 22, 2020 +==================================== + +Require HarfBuzz >= 2.0.0 + +Build and documentation fixes. + +Overview of changes leading to 0.7.0 +Monday, May 27, 2019 +==================================== + +New API: + * raqm_version + * raqm_version_string + * raqm_version_atleast + * RAQM_VERSION_MAJOR + * RAQM_VERSION_MICRO + * RAQM_VERSION_MINOR + * RAQM_VERSION_STRING + * RAQM_VERSION_ATLEAST + +Overview of changes leading to 0.6.0 +Sunday, May 5, 2019 +==================================== + +Fix TTB direction regression from the previous release. + +Correctly detect script of Common and Inherite characters at start of text. + +Undef HAVE_CONFIG_H workaround, for older versions of Fribidi. + +Drop test suite dependency on GLib. + +Port test runner to Python instead of shell script. + +New API: +* raqm_set_invisible_glyph() + +Overview of changes leading to 0.5.0 +Saturday, February 24, 2018 +==================================== + +Use FriBiDi 1.x API when available. + +Overview of changes leading to 0.4.0 +Sunday, January 21, 2018 +==================================== + +Set begin-of-text and end-of-text HarfBuzz buffer flags. + +Dynamically allocate memory instead of using stack allocation for input text. + +Accept zero length text and do nothing instead of treating it as error. + +Overview of changes leading to 0.3.0 +Monday, August 21, 2017 +==================================== + +Fix stack corruption on MSVC. + +New API: +* raqm_set_freetype_load_flags + +Overview of changes leading to 0.2.0 +Wednesday, August 25, 2016 +==================================== + +Fix building with MSVC due to lacking C99 support. + +Make multiple fonts support actually work. Start and length now respect the +input encoding. + +New API: +* raqm_index_to_position +* raqm_position_to_index +* raqm_set_language + +Overview of changes leading to 0.1.1 +Sunday, May 1, 2016 +==================================== + +Fix make check on 32-bit systems. + +Overview of changes leading to 0.1.0 +Wednesday, January 20, 2016 +==================================== + +First release. diff --git a/src/thirdparty/raqm/README b/src/thirdparty/raqm/README new file mode 100644 index 000000000..7940bf3b6 --- /dev/null +++ b/src/thirdparty/raqm/README @@ -0,0 +1,85 @@ +Raqm +==== + +[![Linux & macOS build](https://travis-ci.org/HOST-Oman/libraqm.svg?branch=master)](https://travis-ci.org/HOST-Oman/libraqm) +[![Windows build](https://img.shields.io/appveyor/ci/HOSTOman/libraqm/master.svg)](https://ci.appveyor.com/project/HOSTOman/libraqm) + +Raqm is a small library that encapsulates the logic for complex text layout and +provides a convenient API. + +It currently provides bidirectional text support (using [FriBiDi][1]), shaping +(using [HarfBuzz][2]), and proper script itemization. As a result, +Raqm can support most writing systems covered by Unicode. + +The documentation can be accessed on the web at: +> http://host-oman.github.io/libraqm/ + +Raqm (Arabic: رَقْم) is writing, also number or digit and the Arabic word for +digital (رَقَمِيّ) shares the same root, so it is a play on “digital writing”. + +Building +-------- + +Raqm depends on the following libraries: +* [FreeType][3] +* [HarfBuzz][2] +* [FriBiDi][1] + +To build the documentation you will also need: +* [GTK-Doc][4] + +To install dependencies on Fedora: + + sudo dnf install freetype-devel harfbuzz-devel fribidi-devel gtk-doc + +To install dependencies on Ubuntu: + + sudo apt-get install libfreetype6-dev libharfbuzz-dev libfribidi-dev \ + gtk-doc-tools + +On Mac OS X you can use Homebrew: + + brew install freetype harfbuzz fribidi gtk-doc + export XML_CATALOG_FILES="/usr/local/etc/xml/catalog" # for the docs + +Once you have the source code and the dependencies, you can proceed to build. +To do that, run the customary sequence of commands in the source code +directory: + + $ ./configure + $ make + $ make install + +To build the documentation, pass `--enable-gtk-doc` to the `configure` script. + +To run the tests: + + $ make check + +Contributing +------------ + +Once you have made a change that you are happy with, contribute it back, we’ll +be happy to integrate it! Just fork the repository and make a pull request. + +Projects using Raqm +------------------- + +1. [ImageMagick](https://github.com/ImageMagick/ImageMagick) +2. [LibGD](https://github.com/libgd/libgd) +3. [FontView](https://github.com/googlei18n/fontview) +4. [Pillow](https://github.com/python-pillow) +5. [mplcairo](https://github.com/anntzer/mplcairo) + +The following projects have patches to support complex text layout using Raqm: + +2. SDL_ttf: https://bugzilla.libsdl.org/show_bug.cgi?id=3211 +3. Pygame: https://bitbucket.org/pygame/pygame/pull-requests/52 +4. Blender: https://developer.blender.org/D1809 + + + +[1]: http://fribidi.org +[2]: http://harfbuzz.org +[3]: https://www.freetype.org +[4]: https://www.gtk.org/gtk-doc From 5cd688fc82e875de25979af800642f905cb92cb3 Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 25 Nov 2020 14:01:16 +0000 Subject: [PATCH 04/89] add option to statically link fribidi, version info --- setup.py | 94 ++++++++++++++++++++++----- src/PIL/features.py | 7 ++ src/_imagingft.c | 74 ++++++++++++++++----- src/thirdparty/fribidi-shim/fribidi.c | 6 +- src/thirdparty/fribidi-shim/fribidi.h | 5 ++ src/thirdparty/raqm/raqm.c | 8 ++- 6 files changed, 157 insertions(+), 37 deletions(-) diff --git a/setup.py b/setup.py index 3e0ec5576..0afc6330c 100755 --- a/setup.py +++ b/setup.py @@ -267,7 +267,7 @@ class pil_build_ext(build_ext): "jpeg", "tiff", "freetype", - "harfbuzz", + "raqm", "lcms", "webp", "webpmux", @@ -277,6 +277,7 @@ class pil_build_ext(build_ext): ] required = {"jpeg", "zlib"} + system = set() def __init__(self): for f in self.features: @@ -288,6 +289,9 @@ class pil_build_ext(build_ext): def want(self, feat): return getattr(self, feat) is None + def want_system(self, feat): + return feat in self.system + def __iter__(self): yield from self.features @@ -297,6 +301,10 @@ class pil_build_ext(build_ext): build_ext.user_options + [(f"disable-{x}", None, f"Disable support for {x}") for x in feature] + [(f"enable-{x}", None, f"Enable support for {x}") for x in feature] + + [ + (f"system-{x}", None, f"Use system version of {x}") + for x in ("raqm", "fribidi") + ] + [ ("disable-platform-guessing", None, "Disable platform guessing on Linux"), ("debug", None, "Debug logging"), @@ -311,6 +319,8 @@ class pil_build_ext(build_ext): for x in self.feature: setattr(self, f"disable_{x}", None) setattr(self, f"enable_{x}", None) + for x in ("raqm", "fribidi"): + setattr(self, f"system_{x}", None) def finalize_options(self): build_ext.finalize_options(self) @@ -335,18 +345,40 @@ class pil_build_ext(build_ext): raise ValueError( f"Conflicting options: --enable-{x} and --disable-{x}" ) + if x == "freetype": + _dbg("--disable-freetype implies --disable-raqm") + if getattr(self, "enable_raqm"): + raise ValueError( + "Conflicting options: --enable-raqm and --disable-freetype" + ) + setattr(self, "disable_raqm", True) if getattr(self, f"enable_{x}"): _dbg("Requiring %s", x) self.feature.required.add(x) + if x == "raqm": + _dbg("--enable-raqm implies --enable-freetype") + self.feature.required.add("freetype") + for x in ("raqm", "fribidi"): + if getattr(self, f"system_{x}"): + if getattr(self, f"disable_raqm"): + raise ValueError( + f"Conflicting options: --system-{x} and --disable-raqm" + ) + if x == "fribidi" and getattr(self, f"system_raqm"): + raise ValueError( + f"Conflicting options: --system-{x} and --system-raqm" + ) + _dbg("Using system version of %s", x) + self.feature.system.add(x) - def _update_extension(self, name, libraries, define_macros=None, include_dirs=None): + def _update_extension(self, name, libraries, define_macros=None, sources=None): for extension in self.extensions: if extension.name == name: extension.libraries += libraries if define_macros is not None: extension.define_macros += define_macros - if include_dirs is not None: - extension.include_dirs += include_dirs + if sources is not None: + extension.sources += sources break def _remove_extension(self, name): @@ -657,11 +689,27 @@ class pil_build_ext(build_ext): if subdir: _add_directory(self.compiler.include_dirs, subdir, 0) - if feature.want("harfbuzz"): - _dbg("Looking for harfbuzz") - if _find_include_file(self, "hb-version.h"): - if _find_library_file(self, "harfbuzz"): - feature.harfbuzz = "harfbuzz" + if feature.want("raqm"): + if feature.want_system("raqm"): # want system Raqm + _dbg("Looking for Raqm") + if _find_include_file(self, "raqm.h"): + if _find_library_file(self, "raqm"): + feature.harfbuzz = "raqm" + elif _find_library_file(self, "libraqm"): + feature.harfbuzz = "libraqm" + else: # want to build Raqm + _dbg("Looking for HarfBuzz") + if _find_include_file(self, "hb.h"): + if _find_library_file(self, "harfbuzz"): + feature.harfbuzz = "harfbuzz" + if feature.harfbuzz: + if feature.want_system("fribidi"): # want system FriBiDi + _dbg("Looking for FriBiDi") + if _find_include_file(self, "fribidi.h"): + if _find_library_file(self, "fribidi"): + feature.harfbuzz = "fribidi" + else: # want to build FriBiDi shim + feature.raqm = True if feature.want("lcms"): _dbg("Looking for lcms") @@ -758,9 +806,25 @@ class pil_build_ext(build_ext): # additional libraries if feature.freetype: + srcs = [] libs = ["freetype"] defs = [] - self._update_extension("PIL._imagingft", libs, defs) + if feature.raqm: + if feature.want_system("raqm"): # using system Raqm + defs.append(("HAVE_RAQM", None)) + defs.append(("HAVE_RAQM_SYSTEM", None)) + libs.append(feature.raqm) + else: # building Raqm + defs.append(("HAVE_RAQM", None)) + srcs.append("src/thirdparty/raqm/raqm.c") + libs.append(feature.harfbuzz) + if feature.want_system("fribidi"): # using system FriBiDi + defs.append(("HAVE_FRIBIDI_SYSTEM", None)) + libs.append(feature.fribidi) + else: # building our FriBiDi shim + srcs.append("src/thirdparty/fribidi-shim/fribidi.c") + self._update_extension("PIL._imagingft", libs, defs, srcs) + else: self._remove_extension("PIL._imagingft") @@ -814,6 +878,7 @@ class pil_build_ext(build_ext): (feature.imagequant, "LIBIMAGEQUANT"), (feature.tiff, "LIBTIFF"), (feature.freetype, "FREETYPE2"), + (feature.raqm, "RAQM (Text shaping)"), # TODO!!! (feature.lcms, "LITTLECMS2"), (feature.webp, "WEBP"), (feature.webpmux, "WEBPMUX"), @@ -857,14 +922,7 @@ for src_file in _LIB_IMAGING: files.append(os.path.join("src/libImaging", src_file + ".c")) ext_modules = [ Extension("PIL._imaging", files), - Extension( - "PIL._imagingft", - [ - "src/_imagingft.c", - "src/thirdparty/raqm/raqm.c", - "src/thirdparty/fribidi-shim/fribidi.c", - ], - ), + Extension("PIL._imagingft", ["src/_imagingft.c"]), Extension("PIL._imagingcms", ["src/_imagingcms.c"]), Extension("PIL._webp", ["src/_webp.c"]), Extension("PIL._imagingtk", ["src/_imagingtk.c", "src/Tk/tkImaging.c"]), diff --git a/src/PIL/features.py b/src/PIL/features.py index da0ca557c..85459063b 100644 --- a/src/PIL/features.py +++ b/src/PIL/features.py @@ -118,6 +118,8 @@ features = { "webp_mux": ("PIL._webp", "HAVE_WEBPMUX", None), "transp_webp": ("PIL._webp", "HAVE_TRANSPARENCY", None), "raqm": ("PIL._imagingft", "HAVE_RAQM", "raqm_version"), + "fribidi": ("PIL._imagingft", "HAVE_FRIBIDI", "fribidi_version"), + "harfbuzz": ("PIL._imagingft", "HAVE_HARFBUZZ", "harfbuzz_version"), "libjpeg_turbo": ("PIL._imaging", "HAVE_LIBJPEGTURBO", "libjpeg_turbo_version"), "libimagequant": ("PIL._imaging", "HAVE_LIBIMAGEQUANT", "imagequant_version"), "xcb": ("PIL._imaging", "HAVE_XCB", None), @@ -274,6 +276,11 @@ def pilinfo(out=None, supported_formats=True): # this check is also in src/_imagingcms.c:setup_module() version_static = tuple(int(x) for x in v.split(".")) < (2, 7) t = "compiled for" if version_static else "loaded" + if name == "raqm": + for f in ("fribidi", "harfbuzz"): + v2 = version_feature(f) + if v2 is not None: + v += f", {f} {v2}" print("---", feature, "support ok,", t, v, file=out) else: print("---", feature, "support ok", file=out) diff --git a/src/_imagingft.c b/src/_imagingft.c index 4a4084e9f..fd5530642 100644 --- a/src/_imagingft.c +++ b/src/_imagingft.c @@ -52,8 +52,21 @@ } \ ; -#include "thirdparty/raqm/raqm.h" -#include "thirdparty/fribidi-shim/fribidi.h" +#ifdef HAVE_RAQM +# ifdef HAVE_RAQM_SYSTEM +# include +# else +# include "thirdparty/raqm/raqm.h" +# ifdef HAVE_FRIBIDI_SYSTEM +# include +# else +# include "thirdparty/fribidi-shim/fribidi.h" +# include +# endif +# endif +#endif + +static int have_raqm = 0; #define LAYOUT_FALLBACK 0 #define LAYOUT_RAQM 1 @@ -101,11 +114,6 @@ geterror(int code) { return NULL; } -static int -setraqm(void) { - return load_fribidi(); -} - static PyObject * getfont(PyObject *self_, PyObject *args, PyObject *kw) { /* create a font object from a file name and a size (in pixels) */ @@ -474,7 +482,7 @@ text_layout( int color) { size_t count; - if (p_fribidi && self->layout_engine == LAYOUT_RAQM) { + if (have_raqm && self->layout_engine == LAYOUT_RAQM) { count = text_layout_raqm( string, self, dir, features, lang, glyph_info, mask, color); } else { @@ -1357,15 +1365,51 @@ setup_module(PyObject *m) { v = PyUnicode_FromFormat("%d.%d.%d", major, minor, patch); PyDict_SetItemString(d, "freetype2_version", v); - setraqm(); - v = PyBool_FromLong(!!p_fribidi); - PyDict_SetItemString(d, "HAVE_RAQM", v); -// if (p_raqm.version_string) { - PyDict_SetItemString( - d, "raqm_version", PyUnicode_FromString(raqm_version_string())); -// }; +#ifdef HAVE_RAQM +#ifdef HAVE_FRIBIDI_SYSTEM + have_raqm = 1; +#else + load_fribidi(); + have_raqm = !!p_fribidi; +#endif +#else + have_raqm = 0; +#endif + /* if we have Raqm, we have all three (but possibly no version info) */ + v = PyBool_FromLong(have_raqm); + PyDict_SetItemString(d, "HAVE_RAQM", v); PyDict_SetItemString(d, "HAVE_FRIBIDI", v); + PyDict_SetItemString(d, "HAVE_HARFBUZZ", v); + if (have_raqm) { + const char *a, *b; +#ifdef RAQM_VERSION_MAJOR + v = PyUnicode_FromString(raqm_version_string()); +#else + v = Py_None; +#endif + PyDict_SetItemString(d, "raqm_version", v); + +#ifdef FRIBIDI_MAJOR_VERSION + a = strchr(fribidi_version_info, '1'); + b = strchr(fribidi_version_info, '\n'); + if (a && b) { + v = PyUnicode_FromStringAndSize(a, b - a); + } else { + v = Py_None; + } +#else + v = Py_None; +#endif + PyDict_SetItemString(d, "fribidi_version", v); + +#ifdef HB_VERSION_STRING + v = PyUnicode_FromString(hb_version_string()); +#else + v = Py_None; +#endif + PyDict_SetItemString(d, "harfbuzz_version", v); + } return 0; } diff --git a/src/thirdparty/fribidi-shim/fribidi.c b/src/thirdparty/fribidi-shim/fribidi.c index 64ff7e115..77a55b502 100644 --- a/src/thirdparty/fribidi-shim/fribidi.c +++ b/src/thirdparty/fribidi-shim/fribidi.c @@ -51,13 +51,15 @@ int load_fribidi(void) { LOAD_FUNCTION(fribidi_charset_to_unicode); #ifndef _WIN32 - if (dlerror() || error) { + fribidi_version_info = *(const char**)dlsym(p_fribidi, "fribidi_version_info"); + if (dlerror() || error || (fribidi_version_info == NULL)) { dlclose(p_fribidi); p_fribidi = NULL; return 2; } #else - if (error) { + fribidi_version_info = *(const char**)GetProcAddress(p_fribidi, "fribidi_version_info"); + if (error || (fribidi_version_info == NULL)) { FreeLibrary(p_fribidi); p_fribidi = NULL; return 2; diff --git a/src/thirdparty/fribidi-shim/fribidi.h b/src/thirdparty/fribidi-shim/fribidi.h index c79bb170a..b7c6064bc 100644 --- a/src/thirdparty/fribidi-shim/fribidi.h +++ b/src/thirdparty/fribidi-shim/fribidi.h @@ -1,4 +1,6 @@ +#define FRIBIDI_MAJOR_VERSION 1 + /* fribidi-types.h */ # if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \ @@ -93,6 +95,9 @@ FRIBIDI_FUNC(FriBidiStrIndex, fribidi_charset_to_unicode, #undef FRIBIDI_FUNC +/* constant, not a function */ +FRIBIDI_ENTRY const char *fribidi_version_info; + /* shim */ diff --git a/src/thirdparty/raqm/raqm.c b/src/thirdparty/raqm/raqm.c index c796f645e..5a0b2078e 100644 --- a/src/thirdparty/raqm/raqm.c +++ b/src/thirdparty/raqm/raqm.c @@ -30,16 +30,20 @@ #include #include +#ifdef HAVE_FRIBIDI_SYSTEM +#include +#else #include "../fribidi-shim/fribidi.h" +#endif #include #include #include "raqm.h" -//#if FRIBIDI_MAJOR_VERSION >= 1 +#if FRIBIDI_MAJOR_VERSION >= 1 #define USE_FRIBIDI_EX_API -//#endif +#endif /** * SECTION:raqm From d4403bec46a22d0b8cb8a8fde816519effbc4f2a Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 25 Nov 2020 14:02:21 +0000 Subject: [PATCH 05/89] GHA: fix windows build for dynamic fribidi --- .github/workflows/test-windows.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index db1675135..c5aa133cb 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -137,14 +137,11 @@ jobs: if: steps.build-cache.outputs.cache-hit != 'true' run: "& winbuild\\build\\build_dep_harfbuzz.cmd" + # Raqm dependencies - name: Build dependencies / FriBidi if: steps.build-cache.outputs.cache-hit != 'true' run: "& winbuild\\build\\build_dep_fribidi.cmd" - - name: Build dependencies / Raqm - if: steps.build-cache.outputs.cache-hit != 'true' - run: "& winbuild\\build\\build_dep_libraqm.cmd" - # trim ~150MB x 9 - name: Optimize build cache if: steps.build-cache.outputs.cache-hit != 'true' From 3386a9ce0272d92c1c1c20037c60022aa4e09ea4 Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 25 Nov 2020 15:18:43 +0000 Subject: [PATCH 06/89] replace tabs in thirdparty libs --- src/thirdparty/fribidi-shim/fribidi.h | 2 +- src/thirdparty/raqm/raqm-version.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/thirdparty/fribidi-shim/fribidi.h b/src/thirdparty/fribidi-shim/fribidi.h index b7c6064bc..aa446fbef 100644 --- a/src/thirdparty/fribidi-shim/fribidi.h +++ b/src/thirdparty/fribidi-shim/fribidi.h @@ -43,7 +43,7 @@ typedef signed char FriBidiLevel; #define FRIBIDI_TYPE_LTR_VAL 0x00000110L #define FRIBIDI_TYPE_RTL_VAL 0x00000111L -#define FRIBIDI_TYPE_ON_VAL 0x00000040L +#define FRIBIDI_TYPE_ON_VAL 0x00000040L typedef uint32_t FriBidiCharType; #define FRIBIDI_TYPE_LTR FRIBIDI_TYPE_LTR_VAL diff --git a/src/thirdparty/raqm/raqm-version.h b/src/thirdparty/raqm/raqm-version.h index 4fd5c6842..94b25ada7 100644 --- a/src/thirdparty/raqm/raqm-version.h +++ b/src/thirdparty/raqm/raqm-version.h @@ -38,7 +38,7 @@ #define RAQM_VERSION_STRING "0.7.1" #define RAQM_VERSION_ATLEAST(major,minor,micro) \ - ((major)*10000+(minor)*100+(micro) <= \ - RAQM_VERSION_MAJOR*10000+RAQM_VERSION_MINOR*100+RAQM_VERSION_MICRO) + ((major)*10000+(minor)*100+(micro) <= \ + RAQM_VERSION_MAJOR*10000+RAQM_VERSION_MINOR*100+RAQM_VERSION_MICRO) #endif /* _RAQM_VERSION_H_ */ From be0d0a3a4895aeef5504a78440cd08dbee16f99c Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 25 Nov 2020 16:27:12 +0000 Subject: [PATCH 07/89] fix finding raqm deps --- setup.py | 38 ++++++++++++++++++++++----- src/_imagingft.c | 12 ++++++--- src/thirdparty/fribidi-shim/fribidi.c | 2 +- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/setup.py b/setup.py index 0afc6330c..7275dc6ed 100755 --- a/setup.py +++ b/setup.py @@ -123,7 +123,7 @@ _LIB_IMAGING = ( "codec_fd", ) -DEBUG = False +DEBUG = True class DependencyException(Exception): @@ -228,6 +228,19 @@ def _find_library_file(self, library): return ret +def _find_include_dir(self, dirname, include): + for directory in self.compiler.include_dirs: + _dbg("Checking for include file %s in %s", (include, directory)) + if os.path.isfile(os.path.join(directory, include)): + _dbg("Found %s in %s", (include, directory)) + return True + subdir = os.path.join(directory, dirname) + _dbg("Checking for include file %s in %s", (include, subdir)) + if os.path.isfile(os.path.join(subdir, include)): + _dbg("Found %s in %s", (include, subdir)) + return subdir + + def _cmd_exists(cmd): return any( os.access(os.path.join(path, cmd), os.X_OK) @@ -689,25 +702,36 @@ class pil_build_ext(build_ext): if subdir: _add_directory(self.compiler.include_dirs, subdir, 0) - if feature.want("raqm"): + if feature.freetype and feature.want("raqm"): if feature.want_system("raqm"): # want system Raqm _dbg("Looking for Raqm") if _find_include_file(self, "raqm.h"): if _find_library_file(self, "raqm"): - feature.harfbuzz = "raqm" + feature.raqm = "raqm" elif _find_library_file(self, "libraqm"): - feature.harfbuzz = "libraqm" + feature.raqm = "libraqm" else: # want to build Raqm _dbg("Looking for HarfBuzz") - if _find_include_file(self, "hb.h"): + feature.harfbuzz = None + hb_dir = _find_include_dir(self, "harfbuzz", "hb.h") + if hb_dir: + if isinstance(hb_dir, str): + _add_directory(self.compiler.include_dirs, hb_dir, 0) if _find_library_file(self, "harfbuzz"): feature.harfbuzz = "harfbuzz" if feature.harfbuzz: if feature.want_system("fribidi"): # want system FriBiDi _dbg("Looking for FriBiDi") - if _find_include_file(self, "fribidi.h"): + feature.fribidi = None + fribidi_dir = _find_include_dir(self, "fribidi", "fribidi.h") + if fribidi_dir: + if isinstance(fribidi_dir, str): + _add_directory( + self.compiler.include_dirs, fribidi_dir, 0 + ) if _find_library_file(self, "fribidi"): - feature.harfbuzz = "fribidi" + feature.fribidi = "fribidi" + feature.raqm = True else: # want to build FriBiDi shim feature.raqm = True diff --git a/src/_imagingft.c b/src/_imagingft.c index fd5530642..b2cf76ce7 100644 --- a/src/_imagingft.c +++ b/src/_imagingft.c @@ -221,6 +221,8 @@ font_getchar(PyObject *string, int index, FT_ULong *char_out) { return 0; } +#ifdef HAVE_RAQM + static size_t text_layout_raqm( PyObject *string, @@ -386,6 +388,8 @@ failed: return count; } +#endif + static size_t text_layout_fallback( PyObject *string, @@ -481,11 +485,13 @@ text_layout( int mask, int color) { size_t count; - +#ifdef HAVE_RAQM if (have_raqm && self->layout_engine == LAYOUT_RAQM) { count = text_layout_raqm( string, self, dir, features, lang, glyph_info, mask, color); - } else { + } else +#endif + { count = text_layout_fallback( string, self, dir, features, lang, glyph_info, mask, color); } @@ -1366,7 +1372,7 @@ setup_module(PyObject *m) { PyDict_SetItemString(d, "freetype2_version", v); #ifdef HAVE_RAQM -#ifdef HAVE_FRIBIDI_SYSTEM +#if defined(HAVE_RAQM_SYSTEM) || defined(HAVE_FRIBIDI_SYSTEM) have_raqm = 1; #else load_fribidi(); diff --git a/src/thirdparty/fribidi-shim/fribidi.c b/src/thirdparty/fribidi-shim/fribidi.c index 77a55b502..c83159e29 100644 --- a/src/thirdparty/fribidi-shim/fribidi.c +++ b/src/thirdparty/fribidi-shim/fribidi.c @@ -25,7 +25,7 @@ int load_fribidi(void) { p_fribidi = LoadLibrary("fribidi"); /* MSYS2 */ if (!p_fribidi) { - p_fribidi = LoadLibrary("libfribidi-1"); + p_fribidi = LoadLibrary("libfribidi-0"); } #endif From 834c2e5e5dea378caf5603f58f0dcd476112cf6f Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 25 Nov 2020 16:29:43 +0000 Subject: [PATCH 08/89] lint --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 7275dc6ed..cb4ec2da8 100755 --- a/setup.py +++ b/setup.py @@ -373,11 +373,11 @@ class pil_build_ext(build_ext): self.feature.required.add("freetype") for x in ("raqm", "fribidi"): if getattr(self, f"system_{x}"): - if getattr(self, f"disable_raqm"): + if getattr(self, "disable_raqm"): raise ValueError( f"Conflicting options: --system-{x} and --disable-raqm" ) - if x == "fribidi" and getattr(self, f"system_raqm"): + if x == "fribidi" and getattr(self, "system_raqm"): raise ValueError( f"Conflicting options: --system-{x} and --system-raqm" ) From c3fce854f2e227e37036b96980ae00934db483a2 Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 25 Nov 2020 16:32:37 +0000 Subject: [PATCH 09/89] avoid NULL in fribidi shim --- src/thirdparty/fribidi-shim/fribidi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/thirdparty/fribidi-shim/fribidi.c b/src/thirdparty/fribidi-shim/fribidi.c index c83159e29..f23741ecd 100644 --- a/src/thirdparty/fribidi-shim/fribidi.c +++ b/src/thirdparty/fribidi-shim/fribidi.c @@ -13,7 +13,7 @@ int load_fribidi(void) { int error = 0; - p_fribidi = NULL; + p_fribidi = 0; /* Microsoft needs a totally different system */ #ifndef _WIN32 @@ -36,11 +36,11 @@ int load_fribidi(void) { #ifndef _WIN32 #define LOAD_FUNCTION(func) \ func = (t_##func)dlsym(p_fribidi, #func); \ - error = error || (func == NULL); + error = error || (func == 0); #else #define LOAD_FUNCTION(func) \ func = (t_##func)GetProcAddress(p_fribidi, #func); \ - error = error || (func == NULL); + error = error || (func == 0); #endif LOAD_FUNCTION(fribidi_get_bidi_types); @@ -52,16 +52,16 @@ int load_fribidi(void) { #ifndef _WIN32 fribidi_version_info = *(const char**)dlsym(p_fribidi, "fribidi_version_info"); - if (dlerror() || error || (fribidi_version_info == NULL)) { + if (dlerror() || error || (fribidi_version_info == 0)) { dlclose(p_fribidi); - p_fribidi = NULL; + p_fribidi = 0; return 2; } #else fribidi_version_info = *(const char**)GetProcAddress(p_fribidi, "fribidi_version_info"); - if (error || (fribidi_version_info == NULL)) { + if (error || (fribidi_version_info == 0)) { FreeLibrary(p_fribidi); - p_fribidi = NULL; + p_fribidi = 0; return 2; } #endif From f2b2d53ca82ea2ca882329d382d2812bf7818485 Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 25 Nov 2020 18:01:49 +0000 Subject: [PATCH 10/89] raqm: avoid declaring variables in for statement for C89 compatibility --- src/thirdparty/raqm/raqm.c | 127 +++++++++++++++++++++---------------- 1 file changed, 74 insertions(+), 53 deletions(-) diff --git a/src/thirdparty/raqm/raqm.c b/src/thirdparty/raqm/raqm.c index 5a0b2078e..96523ffb9 100644 --- a/src/thirdparty/raqm/raqm.c +++ b/src/thirdparty/raqm/raqm.c @@ -220,6 +220,7 @@ static bool _raqm_init_text_info (raqm_t *rq) { hb_language_t default_lang; + size_t i; if (rq->text_info) return true; @@ -229,7 +230,7 @@ _raqm_init_text_info (raqm_t *rq) return false; default_lang = hb_language_get_default (); - for (size_t i = 0; i < rq->text_len; i++) + for (i = 0; i < rq->text_len; i++) { rq->text_info[i].ftface = NULL; rq->text_info[i].lang = default_lang; @@ -242,10 +243,12 @@ _raqm_init_text_info (raqm_t *rq) static void _raqm_free_text_info (raqm_t *rq) { + size_t i; + if (!rq->text_info) return; - for (size_t i = 0; i < rq->text_len; i++) + for (i = 0; i < rq->text_len; i++) { if (rq->text_info[i].ftface) FT_Done_Face (rq->text_info[i].ftface); @@ -551,6 +554,7 @@ raqm_set_language (raqm_t *rq, size_t len) { hb_language_t language; + size_t i; size_t end = start + len; if (!rq) @@ -572,7 +576,7 @@ raqm_set_language (raqm_t *rq, return false; language = hb_language_from_string (lang, -1); - for (size_t i = start; i < end; i++) + for (i = start; i < end; i++) { rq->text_info[i].lang = language; } @@ -646,6 +650,8 @@ _raqm_set_freetype_face (raqm_t *rq, size_t start, size_t end) { + size_t i; + if (!rq) return false; @@ -658,7 +664,7 @@ _raqm_set_freetype_face (raqm_t *rq, if (!rq->text_info) return false; - for (size_t i = start; i < end; i++) + for (i = start; i < end; i++) { if (rq->text_info[i].ftface) FT_Done_Face (rq->text_info[i].ftface); @@ -832,6 +838,8 @@ _raqm_shape (raqm_t *rq); bool raqm_layout (raqm_t *rq) { + size_t i; + if (!rq) return false; @@ -841,7 +849,7 @@ raqm_layout (raqm_t *rq) if (!rq->text_info) return false; - for (size_t i = 0; i < rq->text_len; i++) + for (i = 0; i < rq->text_len; i++) { if (!rq->text_info[i].ftface) return false; @@ -879,6 +887,9 @@ raqm_glyph_t * raqm_get_glyphs (raqm_t *rq, size_t *length) { + size_t i; + raqm_run_t *run; + size_t count = 0; if (!rq || !rq->runs || !length) @@ -888,7 +899,7 @@ raqm_get_glyphs (raqm_t *rq, return NULL; } - for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + for (run = rq->runs; run != NULL; run = run->next) count += hb_buffer_get_length (run->buffer); *length = count; @@ -906,7 +917,7 @@ raqm_get_glyphs (raqm_t *rq, RAQM_TEST ("Glyph information:\n"); count = 0; - for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + for (run = rq->runs; run != NULL; run = run->next) { size_t len; hb_glyph_info_t *info; @@ -916,7 +927,7 @@ raqm_get_glyphs (raqm_t *rq, info = hb_buffer_get_glyph_infos (run->buffer, NULL); position = hb_buffer_get_glyph_positions (run->buffer, NULL); - for (size_t i = 0; i < len; i++) + for (i = 0; i < len; i++) { rq->glyphs[count + i].index = info[i].codepoint; rq->glyphs[count + i].cluster = info[i].cluster; @@ -939,18 +950,18 @@ raqm_get_glyphs (raqm_t *rq, { #ifdef RAQM_TESTING RAQM_TEST ("\nUTF-32 clusters:"); - for (size_t i = 0; i < count; i++) + for (i = 0; i < count; i++) RAQM_TEST (" %02d", rq->glyphs[i].cluster); RAQM_TEST ("\n"); #endif - for (size_t i = 0; i < count; i++) + for (i = 0; i < count; i++) rq->glyphs[i].cluster = _raqm_u32_to_u8_index (rq, rq->glyphs[i].cluster); #ifdef RAQM_TESTING RAQM_TEST ("UTF-8 clusters: "); - for (size_t i = 0; i < count; i++) + for (i = 0; i < count; i++) RAQM_TEST (" %02d", rq->glyphs[i].cluster); RAQM_TEST ("\n"); #endif @@ -983,9 +994,11 @@ typedef struct { static void _raqm_reverse_run (_raqm_bidi_run *run, const size_t len) { + size_t i; + assert (run); - for (size_t i = 0; i < len / 2; i++) + for (i = 0; i < len / 2; i++) { _raqm_bidi_run temp = run[i]; run[i] = run[len - 1 - i]; @@ -1002,6 +1015,7 @@ _raqm_reorder_runs (const FriBidiCharType *types, /* output */ size_t *run_count) { + size_t i; FriBidiLevel level; FriBidiLevel last_level = -1; FriBidiLevel max_level = 0; @@ -1021,8 +1035,7 @@ _raqm_reorder_runs (const FriBidiCharType *types, /* L1. Reset the embedding levels of some chars: 4. any sequence of white space characters at the end of the line. */ - for (int i = len - 1; - i >= 0 && FRIBIDI_IS_EXPLICIT_OR_BN_OR_WS (types[i]); i--) + for (i = len; i-- > 0 && FRIBIDI_IS_EXPLICIT_OR_BN_OR_WS (types[i]); ) { levels[i] = FRIBIDI_DIR_TO_LEVEL (base_dir); } @@ -1030,13 +1043,13 @@ _raqm_reorder_runs (const FriBidiCharType *types, /* Find max_level of the line. We don't reuse the paragraph * max_level, both for a cleaner API, and that the line max_level * may be far less than paragraph max_level. */ - for (int i = len - 1; i >= 0; i--) + for (i = len; i-- > 0; ) { if (levels[i] > max_level) max_level = levels[i]; } - for (size_t i = 0; i < len; i++) + for (i = 0; i < len; i++) { if (levels[i] != last_level) count++; @@ -1064,14 +1077,16 @@ _raqm_reorder_runs (const FriBidiCharType *types, /* L2. Reorder. */ for (level = max_level; level > 0; level--) { - for (int i = count - 1; i >= 0; i--) + for (i = count; i-- > 0; ) { if (runs[i].level >= level) { int end = i; - for (i--; (i >= 0 && runs[i].level >= level); i--) + for (; (i > 0 && runs[i - 1].level >= level); i--) ; - _raqm_reverse_run (runs + i + 1, end - i); + _raqm_reverse_run (runs + i, end - i + 1); + if (i-- == 0) + break; } } } @@ -1083,6 +1098,8 @@ _raqm_reorder_runs (const FriBidiCharType *types, static bool _raqm_itemize (raqm_t *rq) { + size_t i, j; + raqm_run_t *run; FriBidiParType par_type = FRIBIDI_PAR_ON; FriBidiCharType *types; #ifdef USE_FRIBIDI_EX_API @@ -1185,7 +1202,7 @@ _raqm_itemize (raqm_t *rq) RAQM_TEST ("Number of runs before script itemization: %zu\n\n", run_count); RAQM_TEST ("Fribidi Runs:\n"); - for (size_t i = 0; i < run_count; i++) + for (i = 0; i < run_count; i++) { RAQM_TEST ("run[%zu]:\t start: %zu\tlength: %zu\tlevel: %d\n", i, runs[i].pos, runs[i].len, runs[i].level); @@ -1194,7 +1211,7 @@ _raqm_itemize (raqm_t *rq) #endif last = NULL; - for (size_t i = 0; i < run_count; i++) + for (i = 0; i < run_count; i++) { raqm_run_t *run = calloc (1, sizeof (raqm_run_t)); if (!run) @@ -1216,7 +1233,7 @@ _raqm_itemize (raqm_t *rq) run->pos = runs[i].pos + runs[i].len - 1; run->script = rq->text_info[run->pos].script; run->font = _raqm_create_hb_font (rq, rq->text_info[run->pos].ftface); - for (int j = runs[i].len - 1; j >= 0; j--) + for (j = runs[i].len; j-- > 0; ) { _raqm_text_info info = rq->text_info[runs[i].pos + j]; if (!_raqm_compare_text_info (rq->text_info[run->pos], info)) @@ -1247,7 +1264,7 @@ _raqm_itemize (raqm_t *rq) run->pos = runs[i].pos; run->script = rq->text_info[run->pos].script; run->font = _raqm_create_hb_font (rq, rq->text_info[run->pos].ftface); - for (size_t j = 0; j < runs[i].len; j++) + for (j = 0; j < runs[i].len; j++) { _raqm_text_info info = rq->text_info[runs[i].pos + j]; if (!_raqm_compare_text_info (rq->text_info[run->pos], info)) @@ -1277,13 +1294,13 @@ _raqm_itemize (raqm_t *rq) #ifdef RAQM_TESTING run_count = 0; - for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + for (run = rq->runs; run != NULL; run = run->next) run_count++; RAQM_TEST ("Number of runs after script itemization: %zu\n\n", run_count); run_count = 0; RAQM_TEST ("Final Runs:\n"); - for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + for (run = rq->runs; run != NULL; run = run->next) { SCRIPT_TO_STRING (run->script); RAQM_TEST ("run[%zu]:\t start: %d\tlength: %d\tdirection: %s\tscript: %s\tfont: %s\n", @@ -1448,18 +1465,19 @@ _get_pair_index (const FriBidiChar ch) static bool _raqm_resolve_scripts (raqm_t *rq) { - int last_script_index = -1; - int last_set_index = -1; + size_t i, j; + size_t next_script_index = 0; + size_t next_set_index = 0; hb_script_t last_script = HB_SCRIPT_INVALID; _raqm_stack_t *stack = NULL; hb_unicode_funcs_t* unicode_funcs = hb_unicode_funcs_get_default (); - for (size_t i = 0; i < rq->text_len; ++i) + for (i = 0; i < rq->text_len; ++i) rq->text_info[i].script = hb_unicode_script (unicode_funcs, rq->text[i]); #ifdef RAQM_TESTING RAQM_TEST ("Before script detection:\n"); - for (size_t i = 0; i < rq->text_len; ++i) + for (i = 0; i < rq->text_len; ++i) { SCRIPT_TO_STRING (rq->text_info[i].script); RAQM_TEST ("script for ch[%zu]\t%s\n", i, buff); @@ -1471,9 +1489,9 @@ _raqm_resolve_scripts (raqm_t *rq) if (!stack) return false; - for (int i = 0; i < (int) rq->text_len; i++) + for (i = 0; i < rq->text_len; i++) { - if (rq->text_info[i].script == HB_SCRIPT_COMMON && last_script_index != -1) + if (rq->text_info[i].script == HB_SCRIPT_COMMON && next_script_index != 0) { int pair_index = _get_pair_index (rq->text[i]); if (pair_index >= 0) @@ -1482,7 +1500,7 @@ _raqm_resolve_scripts (raqm_t *rq) { /* is a paired character */ rq->text_info[i].script = last_script; - last_set_index = i; + next_set_index = i + 1; _raqm_stack_push (stack, rq->text_info[i].script, pair_index); } else @@ -1499,34 +1517,34 @@ _raqm_resolve_scripts (raqm_t *rq) { rq->text_info[i].script = _raqm_stack_top (stack); last_script = rq->text_info[i].script; - last_set_index = i; + next_set_index = i + 1; } else { rq->text_info[i].script = last_script; - last_set_index = i; + next_set_index = i + 1; } } } else { rq->text_info[i].script = last_script; - last_set_index = i; + next_set_index = i + 1; } } else if (rq->text_info[i].script == HB_SCRIPT_INHERITED && - last_script_index != -1) + next_script_index != 0) { rq->text_info[i].script = last_script; - last_set_index = i; + next_set_index = i + 1; } else { - for (int j = last_set_index + 1; j < i; ++j) + for (j = next_set_index; j < i; ++j) rq->text_info[j].script = rq->text_info[i].script; last_script = rq->text_info[i].script; - last_script_index = i; - last_set_index = i; + next_script_index = i + 1; + next_set_index = i + 1; } } @@ -1534,7 +1552,7 @@ _raqm_resolve_scripts (raqm_t *rq) * take the script if the next character. * https://github.com/HOST-Oman/libraqm/issues/95 */ - for (int i = rq->text_len - 2; i >= 0; --i) + for (i = rq->text_len - 1; i-- > 0; ) { if (rq->text_info[i].script == HB_SCRIPT_INHERITED || rq->text_info[i].script == HB_SCRIPT_COMMON) @@ -1543,7 +1561,7 @@ _raqm_resolve_scripts (raqm_t *rq) #ifdef RAQM_TESTING RAQM_TEST ("After script detection:\n"); - for (size_t i = 0; i < rq->text_len; ++i) + for (i = 0; i < rq->text_len; ++i) { SCRIPT_TO_STRING (rq->text_info[i].script); RAQM_TEST ("script for ch[%zu]\t%s\n", i, buff); @@ -1559,6 +1577,7 @@ _raqm_resolve_scripts (raqm_t *rq) static bool _raqm_shape (raqm_t *rq) { + raqm_run_t *run; hb_buffer_flags_t hb_buffer_flags = HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT; #if defined(HAVE_DECL_HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES) && \ @@ -1567,7 +1586,7 @@ _raqm_shape (raqm_t *rq) hb_buffer_flags |= HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES; #endif - for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + for (run = rq->runs; run != NULL; run = run->next) { run->buffer = hb_buffer_create (); @@ -1653,6 +1672,8 @@ raqm_index_to_position (raqm_t *rq, int *x, int *y) { + size_t i, j; + raqm_run_t *run; /* We don't currently support multiline, so y is always 0 */ *y = 0; *x = 0; @@ -1676,7 +1697,7 @@ raqm_index_to_position (raqm_t *rq, ++*index; } - for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + for (run = rq->runs; run != NULL; run = run->next) { size_t len; hb_glyph_info_t *info; @@ -1685,7 +1706,7 @@ raqm_index_to_position (raqm_t *rq, info = hb_buffer_get_glyph_infos (run->buffer, NULL); position = hb_buffer_get_glyph_positions (run->buffer, NULL); - for (size_t i = 0; i < len; i++) + for (i = 0; i < len; i++) { uint32_t curr_cluster = info[i].cluster; uint32_t next_cluster = curr_cluster; @@ -1693,13 +1714,12 @@ raqm_index_to_position (raqm_t *rq, if (run->direction == HB_DIRECTION_LTR) { - for (size_t j = i + 1; j < len && next_cluster == curr_cluster; j++) + for (j = i + 1; j < len && next_cluster == curr_cluster; j++) next_cluster = info[j].cluster; } else { - for (int j = i - 1; i != 0 && j >= 0 && next_cluster == curr_cluster; - j--) + for (j = i; i != 0 && j-- > 0 && next_cluster == curr_cluster; ) next_cluster = info[j].cluster; } @@ -1745,6 +1765,8 @@ raqm_position_to_index (raqm_t *rq, int y, size_t *index) { + size_t i, j; + raqm_run_t *run; int delta_x = 0, current_x = 0; (void)y; @@ -1762,7 +1784,7 @@ raqm_position_to_index (raqm_t *rq, RAQM_TEST ("\n"); - for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) + for (run = rq->runs; run != NULL; run = run->next) { size_t len; hb_glyph_info_t *info; @@ -1771,7 +1793,7 @@ raqm_position_to_index (raqm_t *rq, info = hb_buffer_get_glyph_infos (run->buffer, NULL); position = hb_buffer_get_glyph_positions (run->buffer, NULL); - for (size_t i = 0; i < len; i++) + for (i = 0; i < len; i++) { delta_x = position[i].x_advance; if (x < (current_x + delta_x)) @@ -1789,11 +1811,10 @@ raqm_position_to_index (raqm_t *rq, uint32_t curr_cluster = info[i].cluster; uint32_t next_cluster = curr_cluster; if (run->direction == HB_DIRECTION_LTR) - for (size_t j = i + 1; j < len && next_cluster == curr_cluster; j++) + for (j = i + 1; j < len && next_cluster == curr_cluster; j++) next_cluster = info[j].cluster; else - for (int j = i - 1; i != 0 && j >= 0 && next_cluster == curr_cluster; - j--) + for (j = i; i != 0 && j-- > 0 && next_cluster == curr_cluster; ) next_cluster = info[j].cluster; if (next_cluster == curr_cluster) From b4a57d6fc5c96749430dd244fa4ce4f7104ab311 Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 25 Nov 2020 18:05:50 +0000 Subject: [PATCH 11/89] support FriBiDi<1.0 --- src/thirdparty/fribidi-shim/fribidi.c | 46 ++++++++++++++++++++------- src/thirdparty/fribidi-shim/fribidi.h | 6 ++-- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/thirdparty/fribidi-shim/fribidi.c b/src/thirdparty/fribidi-shim/fribidi.c index f23741ecd..20364ea24 100644 --- a/src/thirdparty/fribidi-shim/fribidi.c +++ b/src/thirdparty/fribidi-shim/fribidi.c @@ -10,6 +10,20 @@ #include "fribidi.h" + +/* ..._ex adds bracket_types param, ignore and call legacy function */ +FriBidiLevel fribidi_get_par_embedding_levels_ex_compat( + const FriBidiCharType *bidi_types, + const FriBidiBracketType *bracket_types, + const FriBidiStrIndex len, + FriBidiParType *pbase_dir, + FriBidiLevel *embedding_levels) +{ + return fribidi_get_par_embedding_levels( + bidi_types, len, pbase_dir, embedding_levels); +} + + int load_fribidi(void) { int error = 0; @@ -17,11 +31,22 @@ int load_fribidi(void) { /* Microsoft needs a totally different system */ #ifndef _WIN32 - p_fribidi = dlopen("libfribidi.so.1", RTLD_LAZY); +#define LOAD_FUNCTION(func) \ + func = (t_##func)dlsym(p_fribidi, #func); \ + error = error || (func == 0); + + p_fribidi = dlopen("libfribidi.so", RTLD_LAZY); + if (!p_fribidi) { + p_fribidi = dlopen("libfribidi.so.0", RTLD_LAZY); + } if (!p_fribidi) { p_fribidi = dlopen("libfribidi.dylib", RTLD_LAZY); } #else +#define LOAD_FUNCTION(func) \ + func = (t_##func)GetProcAddress(p_fribidi, #func); \ + error = error || (func == 0); + p_fribidi = LoadLibrary("fribidi"); /* MSYS2 */ if (!p_fribidi) { @@ -33,20 +58,17 @@ int load_fribidi(void) { return 1; } -#ifndef _WIN32 -#define LOAD_FUNCTION(func) \ - func = (t_##func)dlsym(p_fribidi, #func); \ - error = error || (func == 0); -#else -#define LOAD_FUNCTION(func) \ - func = (t_##func)GetProcAddress(p_fribidi, #func); \ - error = error || (func == 0); -#endif + /* load ..._ex first to preserve error variable */ + LOAD_FUNCTION(fribidi_get_par_embedding_levels_ex); + if (error) { + /* using FriBiDi 0.x, emulate ..._ex function */ + fribidi_get_par_embedding_levels_ex = &fribidi_get_par_embedding_levels_ex_compat; + error = 0; + } LOAD_FUNCTION(fribidi_get_bidi_types); LOAD_FUNCTION(fribidi_get_bracket_types); - LOAD_FUNCTION(fribidi_get_par_embedding_levels_ex); -// LOAD_FUNCTION(fribidi_get_par_embedding_levels); + LOAD_FUNCTION(fribidi_get_par_embedding_levels); LOAD_FUNCTION(fribidi_unicode_to_charset); LOAD_FUNCTION(fribidi_charset_to_unicode); diff --git a/src/thirdparty/fribidi-shim/fribidi.h b/src/thirdparty/fribidi-shim/fribidi.h index aa446fbef..0f0cdac21 100644 --- a/src/thirdparty/fribidi-shim/fribidi.h +++ b/src/thirdparty/fribidi-shim/fribidi.h @@ -83,9 +83,9 @@ FRIBIDI_FUNC(FriBidiLevel, fribidi_get_par_embedding_levels_ex, const FriBidiCharType *, const FriBidiBracketType *, const FriBidiStrIndex, FriBidiParType *, FriBidiLevel *); -//FRIBIDI_FUNC(FriBidiLevel, fribidi_get_par_embedding_levels, -// const FriBidiCharType *, const FriBidiStrIndex, FriBidiParType *, -// FriBidiLevel *); +FRIBIDI_FUNC(FriBidiLevel, fribidi_get_par_embedding_levels, + const FriBidiCharType *, const FriBidiStrIndex, FriBidiParType *, + FriBidiLevel *); FRIBIDI_FUNC(FriBidiStrIndex, fribidi_unicode_to_charset, FriBidiCharSet, const FriBidiChar *, FriBidiStrIndex, char *); From 9c178435fba30f820a1dcd7845313609466c925a Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 25 Nov 2020 19:10:37 +0000 Subject: [PATCH 12/89] raqm: fix FriBiDi<1 support --- src/_imagingft.c | 4 ++-- src/thirdparty/fribidi-shim/fribidi.c | 23 +++++++++++++------ src/thirdparty/fribidi-shim/fribidi.h | 32 ++++++++++++++------------- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/_imagingft.c b/src/_imagingft.c index b2cf76ce7..0995abab3 100644 --- a/src/_imagingft.c +++ b/src/_imagingft.c @@ -1397,10 +1397,10 @@ setup_module(PyObject *m) { PyDict_SetItemString(d, "raqm_version", v); #ifdef FRIBIDI_MAJOR_VERSION - a = strchr(fribidi_version_info, '1'); + a = strchr(fribidi_version_info, ')'); b = strchr(fribidi_version_info, '\n'); if (a && b) { - v = PyUnicode_FromStringAndSize(a, b - a); + v = PyUnicode_FromStringAndSize(a + 2, b - a - 2); } else { v = Py_None; } diff --git a/src/thirdparty/fribidi-shim/fribidi.c b/src/thirdparty/fribidi-shim/fribidi.c index 20364ea24..55e2a6ab3 100644 --- a/src/thirdparty/fribidi-shim/fribidi.c +++ b/src/thirdparty/fribidi-shim/fribidi.c @@ -11,7 +11,7 @@ #include "fribidi.h" -/* ..._ex adds bracket_types param, ignore and call legacy function */ +/* FriBiDi>=1.0.0 adds bracket_types param, ignore and call legacy function */ FriBidiLevel fribidi_get_par_embedding_levels_ex_compat( const FriBidiCharType *bidi_types, const FriBidiBracketType *bracket_types, @@ -23,6 +23,14 @@ FriBidiLevel fribidi_get_par_embedding_levels_ex_compat( bidi_types, len, pbase_dir, embedding_levels); } +/* FriBiDi>=1.0.0 gets bracket types here, ignore */ +void fribidi_get_bracket_types_compat( + const FriBidiChar *str, + const FriBidiStrIndex len, + const FriBidiCharType *types, + FriBidiBracketType *btypes) +{ /* no-op*/ } + int load_fribidi(void) { int error = 0; @@ -58,19 +66,20 @@ int load_fribidi(void) { return 1; } - /* load ..._ex first to preserve error variable */ + /* load FriBiDi>=1.0.0 functions first, use error to detect version */ LOAD_FUNCTION(fribidi_get_par_embedding_levels_ex); + LOAD_FUNCTION(fribidi_get_bracket_types); if (error) { - /* using FriBiDi 0.x, emulate ..._ex function */ - fribidi_get_par_embedding_levels_ex = &fribidi_get_par_embedding_levels_ex_compat; + /* using FriBiDi<1.0.0, ignore new parameters */ error = 0; + fribidi_get_par_embedding_levels_ex = &fribidi_get_par_embedding_levels_ex_compat; + fribidi_get_bracket_types = &fribidi_get_bracket_types_compat; } - LOAD_FUNCTION(fribidi_get_bidi_types); - LOAD_FUNCTION(fribidi_get_bracket_types); - LOAD_FUNCTION(fribidi_get_par_embedding_levels); LOAD_FUNCTION(fribidi_unicode_to_charset); LOAD_FUNCTION(fribidi_charset_to_unicode); + LOAD_FUNCTION(fribidi_get_bidi_types); + LOAD_FUNCTION(fribidi_get_par_embedding_levels); #ifndef _WIN32 fribidi_version_info = *(const char**)dlsym(p_fribidi, "fribidi_version_info"); diff --git a/src/thirdparty/fribidi-shim/fribidi.h b/src/thirdparty/fribidi-shim/fribidi.h index 0f0cdac21..7712a5b22 100644 --- a/src/thirdparty/fribidi-shim/fribidi.h +++ b/src/thirdparty/fribidi-shim/fribidi.h @@ -72,27 +72,29 @@ typedef uint32_t FriBidiParType; typedef ret (*t_##name) (__VA_ARGS__); \ FRIBIDI_ENTRY t_##name name; -FRIBIDI_FUNC(void, fribidi_get_bidi_types, - const FriBidiChar *, const FriBidiStrIndex, FriBidiCharType *); - -FRIBIDI_FUNC(void, fribidi_get_bracket_types, - const FriBidiChar *, const FriBidiStrIndex, const FriBidiCharType *, - FriBidiBracketType *); - -FRIBIDI_FUNC(FriBidiLevel, fribidi_get_par_embedding_levels_ex, - const FriBidiCharType *, const FriBidiBracketType *, const FriBidiStrIndex, - FriBidiParType *, FriBidiLevel *); - -FRIBIDI_FUNC(FriBidiLevel, fribidi_get_par_embedding_levels, - const FriBidiCharType *, const FriBidiStrIndex, FriBidiParType *, - FriBidiLevel *); - FRIBIDI_FUNC(FriBidiStrIndex, fribidi_unicode_to_charset, FriBidiCharSet, const FriBidiChar *, FriBidiStrIndex, char *); FRIBIDI_FUNC(FriBidiStrIndex, fribidi_charset_to_unicode, FriBidiCharSet, const char *, FriBidiStrIndex, FriBidiChar *); +FRIBIDI_FUNC(void, fribidi_get_bidi_types, + const FriBidiChar *, const FriBidiStrIndex, FriBidiCharType *); + +FRIBIDI_FUNC(FriBidiLevel, fribidi_get_par_embedding_levels, + const FriBidiCharType *, const FriBidiStrIndex, FriBidiParType *, + FriBidiLevel *); + +/* FriBiDi>=1.0.0 */ +FRIBIDI_FUNC(FriBidiLevel, fribidi_get_par_embedding_levels_ex, + const FriBidiCharType *, const FriBidiBracketType *, const FriBidiStrIndex, + FriBidiParType *, FriBidiLevel *); + +/* FriBiDi>=1.0.0 */ +FRIBIDI_FUNC(void, fribidi_get_bracket_types, + const FriBidiChar *, const FriBidiStrIndex, const FriBidiCharType *, + FriBidiBracketType *); + #undef FRIBIDI_FUNC /* constant, not a function */ From db0dad909e53ac2f25e4badab4d2aad464c49a68 Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 25 Nov 2020 19:33:33 +0000 Subject: [PATCH 13/89] test --- setup.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/setup.py b/setup.py index cb4ec2da8..031cf5e4e 100755 --- a/setup.py +++ b/setup.py @@ -29,6 +29,8 @@ def get_version(): NAME = "Pillow" PILLOW_VERSION = get_version() FREETYPE_ROOT = None +HARFBUZZ_ROOT = None +FRIBIDI_ROOT = None IMAGEQUANT_ROOT = None JPEG2K_ROOT = None JPEG_ROOT = None @@ -417,6 +419,8 @@ class pil_build_ext(build_ext): TIFF_ROOT=("libtiff-5", "libtiff-4"), ZLIB_ROOT="zlib", FREETYPE_ROOT="freetype2", + HARFBUZZ_ROOT="harfbuzz", + FRIBIDI_ROOT="fribidi", LCMS_ROOT="lcms2", IMAGEQUANT_ROOT="libimagequant", ).items(): From 8c02e3803b995fe0e0d8db2ea4a59c394130d611 Mon Sep 17 00:00:00 2001 From: nulano Date: Sat, 2 Jan 2021 12:37:21 +0100 Subject: [PATCH 14/89] Revert "raqm: avoid declaring variables in for statement for C89 compatibility" This reverts commit b3cfe73854e74bc25a88f53b177713bfb63812e4. --- src/thirdparty/raqm/raqm.c | 127 ++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 74 deletions(-) diff --git a/src/thirdparty/raqm/raqm.c b/src/thirdparty/raqm/raqm.c index 96523ffb9..5a0b2078e 100644 --- a/src/thirdparty/raqm/raqm.c +++ b/src/thirdparty/raqm/raqm.c @@ -220,7 +220,6 @@ static bool _raqm_init_text_info (raqm_t *rq) { hb_language_t default_lang; - size_t i; if (rq->text_info) return true; @@ -230,7 +229,7 @@ _raqm_init_text_info (raqm_t *rq) return false; default_lang = hb_language_get_default (); - for (i = 0; i < rq->text_len; i++) + for (size_t i = 0; i < rq->text_len; i++) { rq->text_info[i].ftface = NULL; rq->text_info[i].lang = default_lang; @@ -243,12 +242,10 @@ _raqm_init_text_info (raqm_t *rq) static void _raqm_free_text_info (raqm_t *rq) { - size_t i; - if (!rq->text_info) return; - for (i = 0; i < rq->text_len; i++) + for (size_t i = 0; i < rq->text_len; i++) { if (rq->text_info[i].ftface) FT_Done_Face (rq->text_info[i].ftface); @@ -554,7 +551,6 @@ raqm_set_language (raqm_t *rq, size_t len) { hb_language_t language; - size_t i; size_t end = start + len; if (!rq) @@ -576,7 +572,7 @@ raqm_set_language (raqm_t *rq, return false; language = hb_language_from_string (lang, -1); - for (i = start; i < end; i++) + for (size_t i = start; i < end; i++) { rq->text_info[i].lang = language; } @@ -650,8 +646,6 @@ _raqm_set_freetype_face (raqm_t *rq, size_t start, size_t end) { - size_t i; - if (!rq) return false; @@ -664,7 +658,7 @@ _raqm_set_freetype_face (raqm_t *rq, if (!rq->text_info) return false; - for (i = start; i < end; i++) + for (size_t i = start; i < end; i++) { if (rq->text_info[i].ftface) FT_Done_Face (rq->text_info[i].ftface); @@ -838,8 +832,6 @@ _raqm_shape (raqm_t *rq); bool raqm_layout (raqm_t *rq) { - size_t i; - if (!rq) return false; @@ -849,7 +841,7 @@ raqm_layout (raqm_t *rq) if (!rq->text_info) return false; - for (i = 0; i < rq->text_len; i++) + for (size_t i = 0; i < rq->text_len; i++) { if (!rq->text_info[i].ftface) return false; @@ -887,9 +879,6 @@ raqm_glyph_t * raqm_get_glyphs (raqm_t *rq, size_t *length) { - size_t i; - raqm_run_t *run; - size_t count = 0; if (!rq || !rq->runs || !length) @@ -899,7 +888,7 @@ raqm_get_glyphs (raqm_t *rq, return NULL; } - for (run = rq->runs; run != NULL; run = run->next) + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) count += hb_buffer_get_length (run->buffer); *length = count; @@ -917,7 +906,7 @@ raqm_get_glyphs (raqm_t *rq, RAQM_TEST ("Glyph information:\n"); count = 0; - for (run = rq->runs; run != NULL; run = run->next) + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) { size_t len; hb_glyph_info_t *info; @@ -927,7 +916,7 @@ raqm_get_glyphs (raqm_t *rq, info = hb_buffer_get_glyph_infos (run->buffer, NULL); position = hb_buffer_get_glyph_positions (run->buffer, NULL); - for (i = 0; i < len; i++) + for (size_t i = 0; i < len; i++) { rq->glyphs[count + i].index = info[i].codepoint; rq->glyphs[count + i].cluster = info[i].cluster; @@ -950,18 +939,18 @@ raqm_get_glyphs (raqm_t *rq, { #ifdef RAQM_TESTING RAQM_TEST ("\nUTF-32 clusters:"); - for (i = 0; i < count; i++) + for (size_t i = 0; i < count; i++) RAQM_TEST (" %02d", rq->glyphs[i].cluster); RAQM_TEST ("\n"); #endif - for (i = 0; i < count; i++) + for (size_t i = 0; i < count; i++) rq->glyphs[i].cluster = _raqm_u32_to_u8_index (rq, rq->glyphs[i].cluster); #ifdef RAQM_TESTING RAQM_TEST ("UTF-8 clusters: "); - for (i = 0; i < count; i++) + for (size_t i = 0; i < count; i++) RAQM_TEST (" %02d", rq->glyphs[i].cluster); RAQM_TEST ("\n"); #endif @@ -994,11 +983,9 @@ typedef struct { static void _raqm_reverse_run (_raqm_bidi_run *run, const size_t len) { - size_t i; - assert (run); - for (i = 0; i < len / 2; i++) + for (size_t i = 0; i < len / 2; i++) { _raqm_bidi_run temp = run[i]; run[i] = run[len - 1 - i]; @@ -1015,7 +1002,6 @@ _raqm_reorder_runs (const FriBidiCharType *types, /* output */ size_t *run_count) { - size_t i; FriBidiLevel level; FriBidiLevel last_level = -1; FriBidiLevel max_level = 0; @@ -1035,7 +1021,8 @@ _raqm_reorder_runs (const FriBidiCharType *types, /* L1. Reset the embedding levels of some chars: 4. any sequence of white space characters at the end of the line. */ - for (i = len; i-- > 0 && FRIBIDI_IS_EXPLICIT_OR_BN_OR_WS (types[i]); ) + for (int i = len - 1; + i >= 0 && FRIBIDI_IS_EXPLICIT_OR_BN_OR_WS (types[i]); i--) { levels[i] = FRIBIDI_DIR_TO_LEVEL (base_dir); } @@ -1043,13 +1030,13 @@ _raqm_reorder_runs (const FriBidiCharType *types, /* Find max_level of the line. We don't reuse the paragraph * max_level, both for a cleaner API, and that the line max_level * may be far less than paragraph max_level. */ - for (i = len; i-- > 0; ) + for (int i = len - 1; i >= 0; i--) { if (levels[i] > max_level) max_level = levels[i]; } - for (i = 0; i < len; i++) + for (size_t i = 0; i < len; i++) { if (levels[i] != last_level) count++; @@ -1077,16 +1064,14 @@ _raqm_reorder_runs (const FriBidiCharType *types, /* L2. Reorder. */ for (level = max_level; level > 0; level--) { - for (i = count; i-- > 0; ) + for (int i = count - 1; i >= 0; i--) { if (runs[i].level >= level) { int end = i; - for (; (i > 0 && runs[i - 1].level >= level); i--) + for (i--; (i >= 0 && runs[i].level >= level); i--) ; - _raqm_reverse_run (runs + i, end - i + 1); - if (i-- == 0) - break; + _raqm_reverse_run (runs + i + 1, end - i); } } } @@ -1098,8 +1083,6 @@ _raqm_reorder_runs (const FriBidiCharType *types, static bool _raqm_itemize (raqm_t *rq) { - size_t i, j; - raqm_run_t *run; FriBidiParType par_type = FRIBIDI_PAR_ON; FriBidiCharType *types; #ifdef USE_FRIBIDI_EX_API @@ -1202,7 +1185,7 @@ _raqm_itemize (raqm_t *rq) RAQM_TEST ("Number of runs before script itemization: %zu\n\n", run_count); RAQM_TEST ("Fribidi Runs:\n"); - for (i = 0; i < run_count; i++) + for (size_t i = 0; i < run_count; i++) { RAQM_TEST ("run[%zu]:\t start: %zu\tlength: %zu\tlevel: %d\n", i, runs[i].pos, runs[i].len, runs[i].level); @@ -1211,7 +1194,7 @@ _raqm_itemize (raqm_t *rq) #endif last = NULL; - for (i = 0; i < run_count; i++) + for (size_t i = 0; i < run_count; i++) { raqm_run_t *run = calloc (1, sizeof (raqm_run_t)); if (!run) @@ -1233,7 +1216,7 @@ _raqm_itemize (raqm_t *rq) run->pos = runs[i].pos + runs[i].len - 1; run->script = rq->text_info[run->pos].script; run->font = _raqm_create_hb_font (rq, rq->text_info[run->pos].ftface); - for (j = runs[i].len; j-- > 0; ) + for (int j = runs[i].len - 1; j >= 0; j--) { _raqm_text_info info = rq->text_info[runs[i].pos + j]; if (!_raqm_compare_text_info (rq->text_info[run->pos], info)) @@ -1264,7 +1247,7 @@ _raqm_itemize (raqm_t *rq) run->pos = runs[i].pos; run->script = rq->text_info[run->pos].script; run->font = _raqm_create_hb_font (rq, rq->text_info[run->pos].ftface); - for (j = 0; j < runs[i].len; j++) + for (size_t j = 0; j < runs[i].len; j++) { _raqm_text_info info = rq->text_info[runs[i].pos + j]; if (!_raqm_compare_text_info (rq->text_info[run->pos], info)) @@ -1294,13 +1277,13 @@ _raqm_itemize (raqm_t *rq) #ifdef RAQM_TESTING run_count = 0; - for (run = rq->runs; run != NULL; run = run->next) + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) run_count++; RAQM_TEST ("Number of runs after script itemization: %zu\n\n", run_count); run_count = 0; RAQM_TEST ("Final Runs:\n"); - for (run = rq->runs; run != NULL; run = run->next) + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) { SCRIPT_TO_STRING (run->script); RAQM_TEST ("run[%zu]:\t start: %d\tlength: %d\tdirection: %s\tscript: %s\tfont: %s\n", @@ -1465,19 +1448,18 @@ _get_pair_index (const FriBidiChar ch) static bool _raqm_resolve_scripts (raqm_t *rq) { - size_t i, j; - size_t next_script_index = 0; - size_t next_set_index = 0; + int last_script_index = -1; + int last_set_index = -1; hb_script_t last_script = HB_SCRIPT_INVALID; _raqm_stack_t *stack = NULL; hb_unicode_funcs_t* unicode_funcs = hb_unicode_funcs_get_default (); - for (i = 0; i < rq->text_len; ++i) + for (size_t i = 0; i < rq->text_len; ++i) rq->text_info[i].script = hb_unicode_script (unicode_funcs, rq->text[i]); #ifdef RAQM_TESTING RAQM_TEST ("Before script detection:\n"); - for (i = 0; i < rq->text_len; ++i) + for (size_t i = 0; i < rq->text_len; ++i) { SCRIPT_TO_STRING (rq->text_info[i].script); RAQM_TEST ("script for ch[%zu]\t%s\n", i, buff); @@ -1489,9 +1471,9 @@ _raqm_resolve_scripts (raqm_t *rq) if (!stack) return false; - for (i = 0; i < rq->text_len; i++) + for (int i = 0; i < (int) rq->text_len; i++) { - if (rq->text_info[i].script == HB_SCRIPT_COMMON && next_script_index != 0) + if (rq->text_info[i].script == HB_SCRIPT_COMMON && last_script_index != -1) { int pair_index = _get_pair_index (rq->text[i]); if (pair_index >= 0) @@ -1500,7 +1482,7 @@ _raqm_resolve_scripts (raqm_t *rq) { /* is a paired character */ rq->text_info[i].script = last_script; - next_set_index = i + 1; + last_set_index = i; _raqm_stack_push (stack, rq->text_info[i].script, pair_index); } else @@ -1517,34 +1499,34 @@ _raqm_resolve_scripts (raqm_t *rq) { rq->text_info[i].script = _raqm_stack_top (stack); last_script = rq->text_info[i].script; - next_set_index = i + 1; + last_set_index = i; } else { rq->text_info[i].script = last_script; - next_set_index = i + 1; + last_set_index = i; } } } else { rq->text_info[i].script = last_script; - next_set_index = i + 1; + last_set_index = i; } } else if (rq->text_info[i].script == HB_SCRIPT_INHERITED && - next_script_index != 0) + last_script_index != -1) { rq->text_info[i].script = last_script; - next_set_index = i + 1; + last_set_index = i; } else { - for (j = next_set_index; j < i; ++j) + for (int j = last_set_index + 1; j < i; ++j) rq->text_info[j].script = rq->text_info[i].script; last_script = rq->text_info[i].script; - next_script_index = i + 1; - next_set_index = i + 1; + last_script_index = i; + last_set_index = i; } } @@ -1552,7 +1534,7 @@ _raqm_resolve_scripts (raqm_t *rq) * take the script if the next character. * https://github.com/HOST-Oman/libraqm/issues/95 */ - for (i = rq->text_len - 1; i-- > 0; ) + for (int i = rq->text_len - 2; i >= 0; --i) { if (rq->text_info[i].script == HB_SCRIPT_INHERITED || rq->text_info[i].script == HB_SCRIPT_COMMON) @@ -1561,7 +1543,7 @@ _raqm_resolve_scripts (raqm_t *rq) #ifdef RAQM_TESTING RAQM_TEST ("After script detection:\n"); - for (i = 0; i < rq->text_len; ++i) + for (size_t i = 0; i < rq->text_len; ++i) { SCRIPT_TO_STRING (rq->text_info[i].script); RAQM_TEST ("script for ch[%zu]\t%s\n", i, buff); @@ -1577,7 +1559,6 @@ _raqm_resolve_scripts (raqm_t *rq) static bool _raqm_shape (raqm_t *rq) { - raqm_run_t *run; hb_buffer_flags_t hb_buffer_flags = HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT; #if defined(HAVE_DECL_HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES) && \ @@ -1586,7 +1567,7 @@ _raqm_shape (raqm_t *rq) hb_buffer_flags |= HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES; #endif - for (run = rq->runs; run != NULL; run = run->next) + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) { run->buffer = hb_buffer_create (); @@ -1672,8 +1653,6 @@ raqm_index_to_position (raqm_t *rq, int *x, int *y) { - size_t i, j; - raqm_run_t *run; /* We don't currently support multiline, so y is always 0 */ *y = 0; *x = 0; @@ -1697,7 +1676,7 @@ raqm_index_to_position (raqm_t *rq, ++*index; } - for (run = rq->runs; run != NULL; run = run->next) + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) { size_t len; hb_glyph_info_t *info; @@ -1706,7 +1685,7 @@ raqm_index_to_position (raqm_t *rq, info = hb_buffer_get_glyph_infos (run->buffer, NULL); position = hb_buffer_get_glyph_positions (run->buffer, NULL); - for (i = 0; i < len; i++) + for (size_t i = 0; i < len; i++) { uint32_t curr_cluster = info[i].cluster; uint32_t next_cluster = curr_cluster; @@ -1714,12 +1693,13 @@ raqm_index_to_position (raqm_t *rq, if (run->direction == HB_DIRECTION_LTR) { - for (j = i + 1; j < len && next_cluster == curr_cluster; j++) + for (size_t j = i + 1; j < len && next_cluster == curr_cluster; j++) next_cluster = info[j].cluster; } else { - for (j = i; i != 0 && j-- > 0 && next_cluster == curr_cluster; ) + for (int j = i - 1; i != 0 && j >= 0 && next_cluster == curr_cluster; + j--) next_cluster = info[j].cluster; } @@ -1765,8 +1745,6 @@ raqm_position_to_index (raqm_t *rq, int y, size_t *index) { - size_t i, j; - raqm_run_t *run; int delta_x = 0, current_x = 0; (void)y; @@ -1784,7 +1762,7 @@ raqm_position_to_index (raqm_t *rq, RAQM_TEST ("\n"); - for (run = rq->runs; run != NULL; run = run->next) + for (raqm_run_t *run = rq->runs; run != NULL; run = run->next) { size_t len; hb_glyph_info_t *info; @@ -1793,7 +1771,7 @@ raqm_position_to_index (raqm_t *rq, info = hb_buffer_get_glyph_infos (run->buffer, NULL); position = hb_buffer_get_glyph_positions (run->buffer, NULL); - for (i = 0; i < len; i++) + for (size_t i = 0; i < len; i++) { delta_x = position[i].x_advance; if (x < (current_x + delta_x)) @@ -1811,10 +1789,11 @@ raqm_position_to_index (raqm_t *rq, uint32_t curr_cluster = info[i].cluster; uint32_t next_cluster = curr_cluster; if (run->direction == HB_DIRECTION_LTR) - for (j = i + 1; j < len && next_cluster == curr_cluster; j++) + for (size_t j = i + 1; j < len && next_cluster == curr_cluster; j++) next_cluster = info[j].cluster; else - for (j = i; i != 0 && j-- > 0 && next_cluster == curr_cluster; ) + for (int j = i - 1; i != 0 && j >= 0 && next_cluster == curr_cluster; + j--) next_cluster = info[j].cluster; if (next_cluster == curr_cluster) From 43bde01623d6db01435b8a821160ac48d9b722b0 Mon Sep 17 00:00:00 2001 From: nulano Date: Sat, 2 Jan 2021 12:47:08 +0100 Subject: [PATCH 15/89] disable Raqm/FriBiDi vendoring by default, except in Windows tests --- setup.py | 22 +++++++++++----------- winbuild/build_prepare.py | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/setup.py b/setup.py index 031cf5e4e..65fc7c47f 100755 --- a/setup.py +++ b/setup.py @@ -125,7 +125,7 @@ _LIB_IMAGING = ( "codec_fd", ) -DEBUG = True +DEBUG = False class DependencyException(Exception): @@ -292,7 +292,7 @@ class pil_build_ext(build_ext): ] required = {"jpeg", "zlib"} - system = set() + vendor = set() def __init__(self): for f in self.features: @@ -305,7 +305,7 @@ class pil_build_ext(build_ext): return getattr(self, feat) is None def want_system(self, feat): - return feat in self.system + return feat not in self.vendor def __iter__(self): yield from self.features @@ -317,7 +317,7 @@ class pil_build_ext(build_ext): + [(f"disable-{x}", None, f"Disable support for {x}") for x in feature] + [(f"enable-{x}", None, f"Enable support for {x}") for x in feature] + [ - (f"system-{x}", None, f"Use system version of {x}") + (f"_vendor-{x}", None, f"Use vendored version of {x}") for x in ("raqm", "fribidi") ] + [ @@ -335,7 +335,7 @@ class pil_build_ext(build_ext): setattr(self, f"disable_{x}", None) setattr(self, f"enable_{x}", None) for x in ("raqm", "fribidi"): - setattr(self, f"system_{x}", None) + setattr(self, f"_vendor_{x}", None) def finalize_options(self): build_ext.finalize_options(self) @@ -374,17 +374,17 @@ class pil_build_ext(build_ext): _dbg("--enable-raqm implies --enable-freetype") self.feature.required.add("freetype") for x in ("raqm", "fribidi"): - if getattr(self, f"system_{x}"): + if getattr(self, f"_vendor_{x}"): if getattr(self, "disable_raqm"): raise ValueError( - f"Conflicting options: --system-{x} and --disable-raqm" + f"Conflicting options: --_vendor-{x} and --disable-raqm" ) - if x == "fribidi" and getattr(self, "system_raqm"): + if x == "fribidi" and not getattr(self, "_vendor_raqm"): raise ValueError( - f"Conflicting options: --system-{x} and --system-raqm" + f"Conflicting options: --_vendor-{x} and not --_vendor-raqm" ) - _dbg("Using system version of %s", x) - self.feature.system.add(x) + _dbg("Using vendored version of %s", x) + self.feature.vendor.add(x) def _update_extension(self, name, libraries, define_macros=None, sources=None): for extension in self.extensions: diff --git a/winbuild/build_prepare.py b/winbuild/build_prepare.py index fd63f4f1e..100f07e90 100644 --- a/winbuild/build_prepare.py +++ b/winbuild/build_prepare.py @@ -472,7 +472,7 @@ def build_pillow(): cmd_set("DISTUTILS_USE_SDK", "1"), # use same compiler to build Pillow cmd_set("MSSdk", "1"), # for PyPy3.6 cmd_set("py_vcruntime_redist", "true"), # use /MD, not /MT - r'"{python_dir}\{python_exe}" setup.py build_ext %*', + r'"{python_dir}\{python_exe}" setup.py build_ext --_vendor-raqm --_vendor-fribidi %*', ] write_script("build_pillow.cmd", lines) From 0488a2761ac3ccc6cc65f910a8254b0e0677b0c9 Mon Sep 17 00:00:00 2001 From: nulano Date: Sat, 2 Jan 2021 12:51:45 +0100 Subject: [PATCH 16/89] can't use underscore prefix for distutils options --- setup.py | 12 ++++++------ winbuild/build_prepare.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/setup.py b/setup.py index 65fc7c47f..fbf869ffb 100755 --- a/setup.py +++ b/setup.py @@ -317,7 +317,7 @@ class pil_build_ext(build_ext): + [(f"disable-{x}", None, f"Disable support for {x}") for x in feature] + [(f"enable-{x}", None, f"Enable support for {x}") for x in feature] + [ - (f"_vendor-{x}", None, f"Use vendored version of {x}") + (f"vendor-{x}", None, f"Use vendored version of {x}") for x in ("raqm", "fribidi") ] + [ @@ -335,7 +335,7 @@ class pil_build_ext(build_ext): setattr(self, f"disable_{x}", None) setattr(self, f"enable_{x}", None) for x in ("raqm", "fribidi"): - setattr(self, f"_vendor_{x}", None) + setattr(self, f"vendor_{x}", None) def finalize_options(self): build_ext.finalize_options(self) @@ -374,14 +374,14 @@ class pil_build_ext(build_ext): _dbg("--enable-raqm implies --enable-freetype") self.feature.required.add("freetype") for x in ("raqm", "fribidi"): - if getattr(self, f"_vendor_{x}"): + if getattr(self, f"vendor_{x}"): if getattr(self, "disable_raqm"): raise ValueError( - f"Conflicting options: --_vendor-{x} and --disable-raqm" + f"Conflicting options: --vendor-{x} and --disable-raqm" ) - if x == "fribidi" and not getattr(self, "_vendor_raqm"): + if x == "fribidi" and not getattr(self, "vendor_raqm"): raise ValueError( - f"Conflicting options: --_vendor-{x} and not --_vendor-raqm" + f"Conflicting options: --vendor-{x} and not --vendor-raqm" ) _dbg("Using vendored version of %s", x) self.feature.vendor.add(x) diff --git a/winbuild/build_prepare.py b/winbuild/build_prepare.py index 100f07e90..dc372f36b 100644 --- a/winbuild/build_prepare.py +++ b/winbuild/build_prepare.py @@ -472,7 +472,7 @@ def build_pillow(): cmd_set("DISTUTILS_USE_SDK", "1"), # use same compiler to build Pillow cmd_set("MSSdk", "1"), # for PyPy3.6 cmd_set("py_vcruntime_redist", "true"), # use /MD, not /MT - r'"{python_dir}\{python_exe}" setup.py build_ext --_vendor-raqm --_vendor-fribidi %*', + r'"{python_dir}\{python_exe}" setup.py build_ext --vendor-raqm --vendor-fribidi %*', ] write_script("build_pillow.cmd", lines) From aae94110d76acedf7d4fb12bb45cc77df06027e2 Mon Sep 17 00:00:00 2001 From: nulano Date: Sat, 2 Jan 2021 13:08:38 +0100 Subject: [PATCH 17/89] lint --- winbuild/build_prepare.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winbuild/build_prepare.py b/winbuild/build_prepare.py index dc372f36b..3b1a15eac 100644 --- a/winbuild/build_prepare.py +++ b/winbuild/build_prepare.py @@ -472,7 +472,7 @@ def build_pillow(): cmd_set("DISTUTILS_USE_SDK", "1"), # use same compiler to build Pillow cmd_set("MSSdk", "1"), # for PyPy3.6 cmd_set("py_vcruntime_redist", "true"), # use /MD, not /MT - r'"{python_dir}\{python_exe}" setup.py build_ext --vendor-raqm --vendor-fribidi %*', + r'"{python_dir}\{python_exe}" setup.py build_ext --vendor-raqm --vendor-fribidi %*', # noqa: E501 ] write_script("build_pillow.cmd", lines) From 297789284b8680a1d15549dc2d192f3abc552160 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 22 Feb 2021 19:32:52 +1100 Subject: [PATCH 18/89] Fixed linear_gradient and radial_gradient 32-bit modes --- Tests/test_image.py | 4 ++-- src/libImaging/Fill.c | 28 ++++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/Tests/test_image.py b/Tests/test_image.py index 73cf7bf83..141a116f9 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -519,7 +519,7 @@ class TestImage: # Arrange target_file = "Tests/images/linear_gradient.png" - for mode in ["L", "P"]: + for mode in ["L", "P", "I", "F"]: # Act im = Image.linear_gradient(mode) @@ -545,7 +545,7 @@ class TestImage: # Arrange target_file = "Tests/images/radial_gradient.png" - for mode in ["L", "P"]: + for mode in ["L", "P", "I", "F"]: # Act im = Image.radial_gradient(mode) diff --git a/src/libImaging/Fill.c b/src/libImaging/Fill.c index e4e4b4344..f72060228 100644 --- a/src/libImaging/Fill.c +++ b/src/libImaging/Fill.c @@ -76,8 +76,21 @@ ImagingFillLinearGradient(const char *mode) { return NULL; } - for (y = 0; y < 256; y++) { - memset(im->image8[y], (unsigned char)y, 256); + if (im->image8) { + for (y = 0; y < 256; y++) { + memset(im->image8[y], (unsigned char)y, 256); + } + } else { + int x; + for (y = 0; y < 256; y++) { + for (x = 0; x < 256; x++) { + if (im->type == IMAGING_TYPE_FLOAT32) { + IMAGING_PIXEL_FLOAT32(im, x, y) = y; + } else { + IMAGING_PIXEL_INT32(im, x, y) = y; + } + } + } } return im; @@ -103,9 +116,16 @@ ImagingFillRadialGradient(const char *mode) { d = (int)sqrt( (double)((x - 128) * (x - 128) + (y - 128) * (y - 128)) * 2.0); if (d >= 255) { - im->image8[y][x] = 255; - } else { + d = 255; + } + if (im->image8) { im->image8[y][x] = d; + } else { + if (im->type == IMAGING_TYPE_FLOAT32) { + IMAGING_PIXEL_FLOAT32(im, x, y) = d; + } else { + IMAGING_PIXEL_INT32(im, x, y) = d; + } } } } From 70fb148fc45fe72302445450190907ee1d161539 Mon Sep 17 00:00:00 2001 From: nulano Date: Sat, 27 Feb 2021 15:14:00 +0100 Subject: [PATCH 19/89] fix merge --- winbuild/fribidi.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winbuild/fribidi.cmake b/winbuild/fribidi.cmake index acb614bfa..27b8d17a8 100644 --- a/winbuild/fribidi.cmake +++ b/winbuild/fribidi.cmake @@ -99,4 +99,4 @@ add_library(fribidi SHARED ${FRIBIDI_SOURCES_GENERATED}) fribidi_definitions(fribidi) target_compile_definitions(fribidi - PUBLIC "-DFRIBIDI_ENTRY=__declspec(dllexport)") + PUBLIC "-DFRIBIDI_BUILD") From e4cc42265dc4e00bccdf960f13fbbd6dfcb469dc Mon Sep 17 00:00:00 2001 From: nulano Date: Sat, 27 Feb 2021 16:52:46 +0100 Subject: [PATCH 20/89] add Raqm build configuration info to build summary --- setup.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/setup.py b/setup.py index cc902c152..6c4840c75 100755 --- a/setup.py +++ b/setup.py @@ -304,8 +304,8 @@ class pil_build_ext(build_ext): def want(self, feat): return getattr(self, feat) is None - def want_system(self, feat): - return feat not in self.vendor + def want_vendor(self, feat): + return feat in self.vendor def __iter__(self): yield from self.features @@ -710,14 +710,14 @@ class pil_build_ext(build_ext): _add_directory(self.compiler.include_dirs, subdir, 0) if feature.freetype and feature.want("raqm"): - if feature.want_system("raqm"): # want system Raqm + if not feature.want_vendor("raqm"): # want system Raqm _dbg("Looking for Raqm") if _find_include_file(self, "raqm.h"): if _find_library_file(self, "raqm"): feature.raqm = "raqm" elif _find_library_file(self, "libraqm"): feature.raqm = "libraqm" - else: # want to build Raqm + else: # want to build Raqm from src/thirdparty _dbg("Looking for HarfBuzz") feature.harfbuzz = None hb_dir = _find_include_dir(self, "harfbuzz", "hb.h") @@ -727,7 +727,7 @@ class pil_build_ext(build_ext): if _find_library_file(self, "harfbuzz"): feature.harfbuzz = "harfbuzz" if feature.harfbuzz: - if feature.want_system("fribidi"): # want system FriBiDi + if not feature.want_vendor("fribidi"): # want system FriBiDi _dbg("Looking for FriBiDi") feature.fribidi = None fribidi_dir = _find_include_dir(self, "fribidi", "fribidi.h") @@ -739,7 +739,7 @@ class pil_build_ext(build_ext): if _find_library_file(self, "fribidi"): feature.fribidi = "fribidi" feature.raqm = True - else: # want to build FriBiDi shim + else: # want to build FriBiDi shim from src/thirdparty feature.raqm = True if feature.want("lcms"): @@ -841,18 +841,18 @@ class pil_build_ext(build_ext): libs = ["freetype"] defs = [] if feature.raqm: - if feature.want_system("raqm"): # using system Raqm + if not feature.want_vendor("raqm"): # using system Raqm defs.append(("HAVE_RAQM", None)) defs.append(("HAVE_RAQM_SYSTEM", None)) libs.append(feature.raqm) - else: # building Raqm + else: # building Raqm from src/thirdparty defs.append(("HAVE_RAQM", None)) srcs.append("src/thirdparty/raqm/raqm.c") libs.append(feature.harfbuzz) - if feature.want_system("fribidi"): # using system FriBiDi + if not feature.want_vendor("fribidi"): # using system FriBiDi defs.append(("HAVE_FRIBIDI_SYSTEM", None)) libs.append(feature.fribidi) - else: # building our FriBiDi shim + else: # building FriBiDi shim from src/thirdparty srcs.append("src/thirdparty/fribidi-shim/fribidi.c") self._update_extension("PIL._imagingft", libs, defs, srcs) @@ -902,6 +902,12 @@ class pil_build_ext(build_ext): print(f" [{v.strip()}") print("-" * 68) + raqm_extra_info = "" + if feature.want_vendor("raqm"): + raqm_extra_info += "bundled" + if feature.want_vendor("fribidi"): + raqm_extra_info += ", FriBiDi shim" + options = [ (feature.jpeg, "JPEG"), (feature.jpeg2000, "OPENJPEG (JPEG2000)", feature.openjpeg_version), @@ -909,7 +915,7 @@ class pil_build_ext(build_ext): (feature.imagequant, "LIBIMAGEQUANT"), (feature.tiff, "LIBTIFF"), (feature.freetype, "FREETYPE2"), - (feature.raqm, "RAQM (Text shaping)"), # TODO!!! + (feature.raqm, "RAQM (Text shaping)", raqm_extra_info), (feature.lcms, "LITTLECMS2"), (feature.webp, "WEBP"), (feature.webpmux, "WEBPMUX"), @@ -919,10 +925,10 @@ class pil_build_ext(build_ext): all = 1 for option in options: if option[0]: - version = "" + extra_info = "" if len(option) >= 3 and option[2]: - version = f" ({option[2]})" - print(f"--- {option[1]} support available{version}") + extra_info = f" ({option[2]})" + print(f"--- {option[1]} support available{extra_info}") else: print(f"*** {option[1]} support not available") all = 0 From ca204ba04f9c68708a5acd9f7a40bbea199f39af Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 7 Mar 2021 14:21:27 +1100 Subject: [PATCH 21/89] Removed Image._MODEINFO --- src/PIL/Image.py | 25 ++----------------------- src/PIL/ImageMode.py | 30 ++++++++++++++++++++---------- 2 files changed, 22 insertions(+), 33 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 01fe7ed1b..deb39435e 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -213,28 +213,7 @@ DECODERS = {} ENCODERS = {} # -------------------------------------------------------------------- -# Modes supported by this version - -_MODEINFO = { - # NOTE: this table will be removed in future versions. use - # getmode* functions or ImageMode descriptors instead. - # official modes - "1": ("L", "L", ("1",)), - "L": ("L", "L", ("L",)), - "I": ("L", "I", ("I",)), - "F": ("L", "F", ("F",)), - "P": ("P", "L", ("P",)), - "RGB": ("RGB", "L", ("R", "G", "B")), - "RGBX": ("RGB", "L", ("R", "G", "B", "X")), - "RGBA": ("RGB", "L", ("R", "G", "B", "A")), - "CMYK": ("RGB", "L", ("C", "M", "Y", "K")), - "YCbCr": ("RGB", "L", ("Y", "Cb", "Cr")), - "LAB": ("RGB", "L", ("L", "A", "B")), - "HSV": ("RGB", "L", ("H", "S", "V")), - # Experimental modes include I;16, I;16L, I;16B, RGBa, BGR;15, and - # BGR;24. Use these modes only if you know exactly what you're - # doing... -} +# Modes if sys.byteorder == "little": _ENDIAN = "<" @@ -280,7 +259,7 @@ def _conv_type_shape(im): return (im.size[1], im.size[0], extra), typ -MODES = sorted(_MODEINFO) +MODES = ["1", "CMYK", "F", "HSV", "I", "L", "LAB", "P", "RGB", "RGBA", "RGBX", "YCbCr"] # raw modes that may be memory mapped. NOTE: if you change this, you # may have to modify the stride calculation in map.c too! diff --git a/src/PIL/ImageMode.py b/src/PIL/ImageMode.py index 988288329..0afcf9fe1 100644 --- a/src/PIL/ImageMode.py +++ b/src/PIL/ImageMode.py @@ -35,18 +35,28 @@ def getmode(mode): global _modes if not _modes: # initialize mode cache - - from . import Image - modes = {} - # core modes - for m, (basemode, basetype, bands) in Image._MODEINFO.items(): + for m, (basemode, basetype, bands) in { + # core modes + "1": ("L", "L", ("1",)), + "L": ("L", "L", ("L",)), + "I": ("L", "I", ("I",)), + "F": ("L", "F", ("F",)), + "P": ("P", "L", ("P",)), + "RGB": ("RGB", "L", ("R", "G", "B")), + "RGBX": ("RGB", "L", ("R", "G", "B", "X")), + "RGBA": ("RGB", "L", ("R", "G", "B", "A")), + "CMYK": ("RGB", "L", ("C", "M", "Y", "K")), + "YCbCr": ("RGB", "L", ("Y", "Cb", "Cr")), + "LAB": ("RGB", "L", ("L", "A", "B")), + "HSV": ("RGB", "L", ("H", "S", "V")), + # extra experimental modes + "RGBa": ("RGB", "L", ("R", "G", "B", "a")), + "LA": ("L", "L", ("L", "A")), + "La": ("L", "L", ("L", "a")), + "PA": ("RGB", "L", ("P", "A")), + }.items(): modes[m] = ModeDescriptor(m, bands, basemode, basetype) - # extra experimental modes - modes["RGBa"] = ModeDescriptor("RGBa", ("R", "G", "B", "a"), "RGB", "L") - modes["LA"] = ModeDescriptor("LA", ("L", "A"), "L", "L") - modes["La"] = ModeDescriptor("La", ("L", "a"), "L", "L") - modes["PA"] = ModeDescriptor("PA", ("P", "A"), "RGB", "L") # mapping modes for i16mode in ( "I;16", From 188d4f6b6abffe7ecb71f3e03d11079138661b60 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 12 Mar 2021 12:03:45 +1100 Subject: [PATCH 22/89] Only import numpy when necessary --- src/PIL/ImageFilter.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/PIL/ImageFilter.py b/src/PIL/ImageFilter.py index 9ca17d9ad..6800bc3a0 100644 --- a/src/PIL/ImageFilter.py +++ b/src/PIL/ImageFilter.py @@ -16,11 +16,6 @@ # import functools -try: - import numpy -except ImportError: # pragma: no cover - numpy = None - class Filter: pass @@ -369,6 +364,13 @@ class Color3DLUT(MultibandFilter): items = size[0] * size[1] * size[2] wrong_size = False + numpy = None + if hasattr(table, "shape"): + try: + import numpy + except ImportError: # pragma: no cover + pass + if numpy and isinstance(table, numpy.ndarray): if copy_table: table = table.copy() From 38692f222f0f5e8bfa5edd34e719f8ea9416721d Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sat, 13 Mar 2021 11:09:37 +0100 Subject: [PATCH 23/89] Delegate building of oss-fuzz versions to pillow --- Tests/oss-fuzz/build.sh | 46 ++++++++++++++++++++++++++++ Tests/oss-fuzz/build_dictionaries.sh | 33 ++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100755 Tests/oss-fuzz/build.sh create mode 100755 Tests/oss-fuzz/build_dictionaries.sh diff --git a/Tests/oss-fuzz/build.sh b/Tests/oss-fuzz/build.sh new file mode 100755 index 000000000..1d05bea79 --- /dev/null +++ b/Tests/oss-fuzz/build.sh @@ -0,0 +1,46 @@ +#!/bin/bash -eu +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ + +python3 setup.py build --build-base=/tmp/build install + +# Build fuzzers in $OUT. +for fuzzer in $(find $SRC -name 'fuzz_*.py'); do + fuzzer_basename=$(basename -s .py $fuzzer) + fuzzer_package=${fuzzer_basename}.pkg + pyinstaller \ + --add-binary /usr/local/lib/libjpeg.so.9:. \ + --add-binary /usr/local/lib/libfreetype.so.6:. \ + --add-binary /usr/local/lib/liblcms2.so.2:. \ + --add-binary /usr/local/lib/libopenjp2.so.7:. \ + --add-binary /usr/local/lib/libpng16.so.16:. \ + --add-binary /usr/local/lib/libtiff.so.5:. \ + --add-binary /usr/local/lib/libwebp.so.7:. \ + --add-binary /usr/local/lib/libwebpdemux.so.2:. \ + --add-binary /usr/local/lib/libwebpmux.so.3:. \ + --distpath $OUT --onefile --name $fuzzer_package $fuzzer + + # Create execution wrapper. + echo "#!/bin/sh +# LLVMFuzzerTestOneInput for fuzzer detection. +this_dir=\$(dirname \"\$0\") +LD_PRELOAD=\$this_dir/sanitizer_with_fuzzer.so \ +ASAN_OPTIONS=\$ASAN_OPTIONS:symbolize=1:external_symbolizer_path=\$this_dir/llvm-symbolizer:detect_leaks=0 \ +\$this_dir/$fuzzer_package \$@" > $OUT/$fuzzer_basename + chmod u+x $OUT/$fuzzer_basename +done + +find Tests/images Tests/icc Tests/fonts -print | zip -q $OUT/fuzz_pillow_seed_corpus.zip -@ diff --git a/Tests/oss-fuzz/build_dictionaries.sh b/Tests/oss-fuzz/build_dictionaries.sh new file mode 100755 index 000000000..9aae56ca8 --- /dev/null +++ b/Tests/oss-fuzz/build_dictionaries.sh @@ -0,0 +1,33 @@ +#!/bin/bash -eu +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ + +# Generate image dictionaries here for each of the fuzzers and put them in the +# $OUT directory, named for the fuzzer + +git clone --depth 1 https://github.com/google/fuzzing +cat fuzzing/dictionaries/bmp.dict \ + fuzzing/dictionaries/dds.dict \ + fuzzing/dictionaries/gif.dict \ + fuzzing/dictionaries/icns.dict \ + fuzzing/dictionaries/jpeg.dict \ + fuzzing/dictionaries/jpeg2000.dict \ + fuzzing/dictionaries/pbm.dict \ + fuzzing/dictionaries/png.dict \ + fuzzing/dictionaries/psd.dict \ + fuzzing/dictionaries/tiff.dict \ + fuzzing/dictionaries/webp.dict \ + > $OUT/fuzz_pillow.dict From e2577d1736617968110ef658b94150f114b17e41 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sat, 13 Mar 2021 11:35:50 +0100 Subject: [PATCH 24/89] font fuzzer --- Tests/oss-fuzz/build.sh | 3 ++- Tests/oss-fuzz/fuzz_font.py | 47 +++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100755 Tests/oss-fuzz/fuzz_font.py diff --git a/Tests/oss-fuzz/build.sh b/Tests/oss-fuzz/build.sh index 1d05bea79..fc54ee3ee 100755 --- a/Tests/oss-fuzz/build.sh +++ b/Tests/oss-fuzz/build.sh @@ -43,4 +43,5 @@ ASAN_OPTIONS=\$ASAN_OPTIONS:symbolize=1:external_symbolizer_path=\$this_dir/llvm chmod u+x $OUT/$fuzzer_basename done -find Tests/images Tests/icc Tests/fonts -print | zip -q $OUT/fuzz_pillow_seed_corpus.zip -@ +find Tests/images Tests/icc -print | zip -q $OUT/fuzz_pillow_seed_corpus.zip -@ +find Tests/fonts -print | zip -q $OUT/fuzz_font_seed_corpus.zip -@ diff --git a/Tests/oss-fuzz/fuzz_font.py b/Tests/oss-fuzz/fuzz_font.py new file mode 100755 index 000000000..43c23fe60 --- /dev/null +++ b/Tests/oss-fuzz/fuzz_font.py @@ -0,0 +1,47 @@ +#!/usr/bin/python3 + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import io +import sys +import warnings + +import atheris_no_libfuzzer as atheris + +from PIL import Image, ImageDraw, ImageFont + + +def TestOneInput(data): + try: + with ImageFont.load(io.BytesIO(data)) as font: + font.getsize_multiline("ABC\nAaaa") + font.getmask("test text") + with Image.new(mode="RGBA", size=(200, 200)) as im: + draw = ImageDraw.Draw(im) + draw.text((10,10), "Test Text", font) + except Exception: + # We're catching all exceptions because Pillow's exceptions are + # directly inheriting from Exception. + return + return + + +def main(): + atheris.Setup(sys.argv, TestOneInput, enable_python_coverage=True) + atheris.Fuzz() + + +if __name__ == "__main__": + main() From becd633d3f6c7fab7e6027d86ae3fbb6a09cfbd4 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sun, 14 Mar 2021 12:21:02 +0100 Subject: [PATCH 25/89] Refactor fuzzers, add fuzzer tests --- Tests/oss-fuzz/fuzz_font.py | 10 ++-------- Tests/oss-fuzz/fuzz_pillow.py | 15 ++++----------- Tests/oss-fuzz/fuzzers.py | 33 +++++++++++++++++++++++++++++++++ Tests/oss-fuzz/test_fuzzers.py | 31 +++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 19 deletions(-) create mode 100644 Tests/oss-fuzz/fuzzers.py create mode 100644 Tests/oss-fuzz/test_fuzzers.py diff --git a/Tests/oss-fuzz/fuzz_font.py b/Tests/oss-fuzz/fuzz_font.py index 43c23fe60..ec3a4b2de 100755 --- a/Tests/oss-fuzz/fuzz_font.py +++ b/Tests/oss-fuzz/fuzz_font.py @@ -20,17 +20,11 @@ import warnings import atheris_no_libfuzzer as atheris -from PIL import Image, ImageDraw, ImageFont - +import fuzzers def TestOneInput(data): try: - with ImageFont.load(io.BytesIO(data)) as font: - font.getsize_multiline("ABC\nAaaa") - font.getmask("test text") - with Image.new(mode="RGBA", size=(200, 200)) as im: - draw = ImageDraw.Draw(im) - draw.text((10,10), "Test Text", font) + fuzzers.fuzz_font(data) except Exception: # We're catching all exceptions because Pillow's exceptions are # directly inheriting from Exception. diff --git a/Tests/oss-fuzz/fuzz_pillow.py b/Tests/oss-fuzz/fuzz_pillow.py index 894068f63..695e9e5eb 100644 --- a/Tests/oss-fuzz/fuzz_pillow.py +++ b/Tests/oss-fuzz/fuzz_pillow.py @@ -18,28 +18,21 @@ import io import sys import warnings +import fuzzers + import atheris_no_libfuzzer as atheris -from PIL import Image, ImageFile, ImageFilter - - def TestOneInput(data): try: - with Image.open(io.BytesIO(data)) as im: - im.rotate(45) - im.filter(ImageFilter.DETAIL) - im.save(io.BytesIO(), "BMP") + fuzzers.fuzz_image(data) except Exception: # We're catching all exceptions because Pillow's exceptions are # directly inheriting from Exception. return return - def main(): - ImageFile.LOAD_TRUNCATED_IMAGES = True - warnings.filterwarnings("ignore") - warnings.simplefilter("error", Image.DecompressionBombWarning) + fuzzers.enable_decompressionbomb_error() atheris.Setup(sys.argv, TestOneInput, enable_python_coverage=True) atheris.Fuzz() diff --git a/Tests/oss-fuzz/fuzzers.py b/Tests/oss-fuzz/fuzzers.py new file mode 100644 index 000000000..f7c395e76 --- /dev/null +++ b/Tests/oss-fuzz/fuzzers.py @@ -0,0 +1,33 @@ +import warnings +import io + +from PIL import Image, ImageFont, ImageDraw, ImageFilter, ImageFile, PcfFontFile + +def enable_decompressionbomb_error(): + ImageFile.LOAD_TRUNCATED_IMAGES = True + warnings.filterwarnings("ignore") + warnings.simplefilter("error", Image.DecompressionBombWarning) + +def fuzz_image(data): + # This will fail on some images in the corpus, as we have many + # invalid images in the test suite. + with Image.open(io.BytesIO(data)) as im: + im.rotate(45) + im.filter(ImageFilter.DETAIL) + im.save(io.BytesIO(), "BMP") + +def fuzz_font(data): + # This should not fail on a valid font load for any of the fonts in the corpus + wrapper = io.BytesIO(data) + try: + font = ImageFont.truetype(wrapper) + except OSError: + # pcf/pilfonts/random garbage here here. They're different. + return + + font.getsize_multiline("ABC\nAaaa") + font.getmask("test text") + with Image.new(mode="RGBA", size=(200, 200)) as im: + draw = ImageDraw.Draw(im) + draw.multiline_textsize("ABC\nAaaa", font, stroke_width=2) + draw.text((10,10), "Test Text", font=font, fill="#000") diff --git a/Tests/oss-fuzz/test_fuzzers.py b/Tests/oss-fuzz/test_fuzzers.py new file mode 100644 index 000000000..56b1ee9a0 --- /dev/null +++ b/Tests/oss-fuzz/test_fuzzers.py @@ -0,0 +1,31 @@ +import pytest + +import fuzzers +import glob +import subprocess + +from PIL import Image + +@pytest.mark.parametrize("path", subprocess.check_output('find Tests/images -type f', shell=True).split(b'\n')) +def test_fuzz_images(path): + fuzzers.enable_decompressionbomb_error() + try: + with open(path, 'rb') as f: + fuzzers.fuzz_image(f.read()) + assert True + except (OSError, SyntaxError, MemoryError, ValueError, NotImplementedError): + # Known exceptions that are through from Pillow + assert True + except (Image.DecompressionBombError, Image.DecompressionBombWarning, + Image.UnidentifiedImageError): + # Known Image.* exceptions + assert True + + +@pytest.mark.parametrize("path", subprocess.check_output('find Tests/fonts -type f', shell=True).split(b'\n')) +def test_fuzz_fonts(path): + if not path or b'LICENSE.txt' in path or b'.pil' in path: + return + with open(path, 'rb') as f: + fuzzers.fuzz_font(f.read()) + assert True From 6d6ef4a539e2eb2a5103073495841de63cf4e852 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sun, 14 Mar 2021 12:21:25 +0100 Subject: [PATCH 26/89] Ignore the pyinstaller spec files --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 15add232b..5500ec037 100644 --- a/.gitignore +++ b/.gitignore @@ -88,3 +88,6 @@ Tests/images/jpeg2000 Tests/images/msp Tests/images/picins Tests/images/sunraster + +# pyinstaller +*.spec From c17ce801cfba4a850381ca6811e5b27b09bffe10 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sun, 14 Mar 2021 13:02:48 +0100 Subject: [PATCH 27/89] I see a python file and I want to paint it black --- Tests/oss-fuzz/fuzz_font.py | 2 +- Tests/oss-fuzz/fuzz_pillow.py | 3 ++- Tests/oss-fuzz/fuzzers.py | 9 ++++++--- Tests/oss-fuzz/test_fuzzers.py | 29 +++++++++++++++++++---------- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/Tests/oss-fuzz/fuzz_font.py b/Tests/oss-fuzz/fuzz_font.py index ec3a4b2de..3cea56fd7 100755 --- a/Tests/oss-fuzz/fuzz_font.py +++ b/Tests/oss-fuzz/fuzz_font.py @@ -19,9 +19,9 @@ import sys import warnings import atheris_no_libfuzzer as atheris - import fuzzers + def TestOneInput(data): try: fuzzers.fuzz_font(data) diff --git a/Tests/oss-fuzz/fuzz_pillow.py b/Tests/oss-fuzz/fuzz_pillow.py index 695e9e5eb..8112dd9a0 100644 --- a/Tests/oss-fuzz/fuzz_pillow.py +++ b/Tests/oss-fuzz/fuzz_pillow.py @@ -18,9 +18,9 @@ import io import sys import warnings +import atheris_no_libfuzzer as atheris import fuzzers -import atheris_no_libfuzzer as atheris def TestOneInput(data): try: @@ -31,6 +31,7 @@ def TestOneInput(data): return return + def main(): fuzzers.enable_decompressionbomb_error() atheris.Setup(sys.argv, TestOneInput, enable_python_coverage=True) diff --git a/Tests/oss-fuzz/fuzzers.py b/Tests/oss-fuzz/fuzzers.py index f7c395e76..c3fa1f0ce 100644 --- a/Tests/oss-fuzz/fuzzers.py +++ b/Tests/oss-fuzz/fuzzers.py @@ -1,13 +1,15 @@ -import warnings import io +import warnings + +from PIL import Image, ImageDraw, ImageFile, ImageFilter, ImageFont, PcfFontFile -from PIL import Image, ImageFont, ImageDraw, ImageFilter, ImageFile, PcfFontFile def enable_decompressionbomb_error(): ImageFile.LOAD_TRUNCATED_IMAGES = True warnings.filterwarnings("ignore") warnings.simplefilter("error", Image.DecompressionBombWarning) + def fuzz_image(data): # This will fail on some images in the corpus, as we have many # invalid images in the test suite. @@ -16,6 +18,7 @@ def fuzz_image(data): im.filter(ImageFilter.DETAIL) im.save(io.BytesIO(), "BMP") + def fuzz_font(data): # This should not fail on a valid font load for any of the fonts in the corpus wrapper = io.BytesIO(data) @@ -30,4 +33,4 @@ def fuzz_font(data): with Image.new(mode="RGBA", size=(200, 200)) as im: draw = ImageDraw.Draw(im) draw.multiline_textsize("ABC\nAaaa", font, stroke_width=2) - draw.text((10,10), "Test Text", font=font, fill="#000") + draw.text((10, 10), "Test Text", font=font, fill="#000") diff --git a/Tests/oss-fuzz/test_fuzzers.py b/Tests/oss-fuzz/test_fuzzers.py index 56b1ee9a0..aa13ff1b2 100644 --- a/Tests/oss-fuzz/test_fuzzers.py +++ b/Tests/oss-fuzz/test_fuzzers.py @@ -1,31 +1,40 @@ -import pytest - -import fuzzers import glob import subprocess +import fuzzers +import pytest + from PIL import Image -@pytest.mark.parametrize("path", subprocess.check_output('find Tests/images -type f', shell=True).split(b'\n')) + +@pytest.mark.parametrize( + "path", + subprocess.check_output("find Tests/images -type f", shell=True).split(b"\n"), +) def test_fuzz_images(path): fuzzers.enable_decompressionbomb_error() try: - with open(path, 'rb') as f: + with open(path, "rb") as f: fuzzers.fuzz_image(f.read()) assert True except (OSError, SyntaxError, MemoryError, ValueError, NotImplementedError): # Known exceptions that are through from Pillow assert True - except (Image.DecompressionBombError, Image.DecompressionBombWarning, - Image.UnidentifiedImageError): + except ( + Image.DecompressionBombError, + Image.DecompressionBombWarning, + Image.UnidentifiedImageError, + ): # Known Image.* exceptions assert True -@pytest.mark.parametrize("path", subprocess.check_output('find Tests/fonts -type f', shell=True).split(b'\n')) +@pytest.mark.parametrize( + "path", subprocess.check_output("find Tests/fonts -type f", shell=True).split(b"\n") +) def test_fuzz_fonts(path): - if not path or b'LICENSE.txt' in path or b'.pil' in path: + if not path or b"LICENSE.txt" in path or b".pil" in path: return - with open(path, 'rb') as f: + with open(path, "rb") as f: fuzzers.fuzz_font(f.read()) assert True From 8b06fec6ab62c2c588c7e8723fec4fc2ff218515 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sun, 14 Mar 2021 13:14:39 +0100 Subject: [PATCH 28/89] linty bits --- Tests/oss-fuzz/fuzz_font.py | 2 -- Tests/oss-fuzz/fuzz_pillow.py | 2 -- Tests/oss-fuzz/fuzzers.py | 2 +- Tests/oss-fuzz/test_fuzzers.py | 1 - 4 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Tests/oss-fuzz/fuzz_font.py b/Tests/oss-fuzz/fuzz_font.py index 3cea56fd7..9f21a1fa5 100755 --- a/Tests/oss-fuzz/fuzz_font.py +++ b/Tests/oss-fuzz/fuzz_font.py @@ -14,9 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import io import sys -import warnings import atheris_no_libfuzzer as atheris import fuzzers diff --git a/Tests/oss-fuzz/fuzz_pillow.py b/Tests/oss-fuzz/fuzz_pillow.py index 8112dd9a0..d816d535f 100644 --- a/Tests/oss-fuzz/fuzz_pillow.py +++ b/Tests/oss-fuzz/fuzz_pillow.py @@ -14,9 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import io import sys -import warnings import atheris_no_libfuzzer as atheris import fuzzers diff --git a/Tests/oss-fuzz/fuzzers.py b/Tests/oss-fuzz/fuzzers.py index c3fa1f0ce..156653f1d 100644 --- a/Tests/oss-fuzz/fuzzers.py +++ b/Tests/oss-fuzz/fuzzers.py @@ -1,7 +1,7 @@ import io import warnings -from PIL import Image, ImageDraw, ImageFile, ImageFilter, ImageFont, PcfFontFile +from PIL import Image, ImageDraw, ImageFile, ImageFilter, ImageFont def enable_decompressionbomb_error(): diff --git a/Tests/oss-fuzz/test_fuzzers.py b/Tests/oss-fuzz/test_fuzzers.py index aa13ff1b2..fc5b21840 100644 --- a/Tests/oss-fuzz/test_fuzzers.py +++ b/Tests/oss-fuzz/test_fuzzers.py @@ -1,4 +1,3 @@ -import glob import subprocess import fuzzers From 6189bca3bc238c11ec31de30091a60012d9acfa6 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sun, 14 Mar 2021 13:27:47 +0100 Subject: [PATCH 29/89] Skip fuzzer tests on windows --- Tests/oss-fuzz/test_fuzzers.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Tests/oss-fuzz/test_fuzzers.py b/Tests/oss-fuzz/test_fuzzers.py index fc5b21840..f7be87373 100644 --- a/Tests/oss-fuzz/test_fuzzers.py +++ b/Tests/oss-fuzz/test_fuzzers.py @@ -1,11 +1,15 @@ import subprocess +import sys import fuzzers import pytest from PIL import Image +def is_win32(): + sys.platform.startswith("win32") +@pytest.mark.skipif(is_win32(), reason="Fuzzer is linux only") @pytest.mark.parametrize( "path", subprocess.check_output("find Tests/images -type f", shell=True).split(b"\n"), @@ -27,7 +31,7 @@ def test_fuzz_images(path): # Known Image.* exceptions assert True - +@pytest.mark.skipif(is_win32(), reason="Fuzzer is linux only") @pytest.mark.parametrize( "path", subprocess.check_output("find Tests/fonts -type f", shell=True).split(b"\n") ) From 0ea13132a24cec8dbbf729630e480d26742879f0 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sun, 14 Mar 2021 13:32:44 +0100 Subject: [PATCH 30/89] Overflow error shows up in x86 --- Tests/oss-fuzz/test_fuzzers.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Tests/oss-fuzz/test_fuzzers.py b/Tests/oss-fuzz/test_fuzzers.py index f7be87373..d7c16f144 100644 --- a/Tests/oss-fuzz/test_fuzzers.py +++ b/Tests/oss-fuzz/test_fuzzers.py @@ -20,7 +20,12 @@ def test_fuzz_images(path): with open(path, "rb") as f: fuzzers.fuzz_image(f.read()) assert True - except (OSError, SyntaxError, MemoryError, ValueError, NotImplementedError): + except (OSError, + SyntaxError, + MemoryError, + ValueError, + NotImplementedError, + OverflowError): # Known exceptions that are through from Pillow assert True except ( From bb6b991d8d74ae4f09063dac9ed78d7df3ed3596 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sun, 14 Mar 2021 13:49:36 +0100 Subject: [PATCH 31/89] no colors anymore, they want them to turn black --- Tests/oss-fuzz/test_fuzzers.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Tests/oss-fuzz/test_fuzzers.py b/Tests/oss-fuzz/test_fuzzers.py index d7c16f144..410fff505 100644 --- a/Tests/oss-fuzz/test_fuzzers.py +++ b/Tests/oss-fuzz/test_fuzzers.py @@ -6,9 +6,11 @@ import pytest from PIL import Image + def is_win32(): sys.platform.startswith("win32") + @pytest.mark.skipif(is_win32(), reason="Fuzzer is linux only") @pytest.mark.parametrize( "path", @@ -20,12 +22,14 @@ def test_fuzz_images(path): with open(path, "rb") as f: fuzzers.fuzz_image(f.read()) assert True - except (OSError, - SyntaxError, - MemoryError, - ValueError, - NotImplementedError, - OverflowError): + except ( + OSError, + SyntaxError, + MemoryError, + ValueError, + NotImplementedError, + OverflowError, + ): # Known exceptions that are through from Pillow assert True except ( @@ -36,6 +40,7 @@ def test_fuzz_images(path): # Known Image.* exceptions assert True + @pytest.mark.skipif(is_win32(), reason="Fuzzer is linux only") @pytest.mark.parametrize( "path", subprocess.check_output("find Tests/fonts -type f", shell=True).split(b"\n") From 487dc16ce6ee4f71815329acb023d28ac6529d74 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sun, 14 Mar 2021 13:57:24 +0100 Subject: [PATCH 32/89] Can't skip windows properly because the depenedncy is in the decorator --- Tests/oss-fuzz/test_fuzzers.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Tests/oss-fuzz/test_fuzzers.py b/Tests/oss-fuzz/test_fuzzers.py index 410fff505..4ccdeca4a 100644 --- a/Tests/oss-fuzz/test_fuzzers.py +++ b/Tests/oss-fuzz/test_fuzzers.py @@ -7,11 +7,10 @@ import pytest from PIL import Image -def is_win32(): - sys.platform.startswith("win32") +if sys.platform.startswith("win32"): + pytest.skip("Fuzzer is linux only", true) -@pytest.mark.skipif(is_win32(), reason="Fuzzer is linux only") @pytest.mark.parametrize( "path", subprocess.check_output("find Tests/images -type f", shell=True).split(b"\n"), @@ -41,7 +40,6 @@ def test_fuzz_images(path): assert True -@pytest.mark.skipif(is_win32(), reason="Fuzzer is linux only") @pytest.mark.parametrize( "path", subprocess.check_output("find Tests/fonts -type f", shell=True).split(b"\n") ) From 961b2c0242df0b749c2524ce51e4272f2bd160d2 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sun, 14 Mar 2021 14:03:41 +0100 Subject: [PATCH 33/89] True --- Tests/oss-fuzz/test_fuzzers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/oss-fuzz/test_fuzzers.py b/Tests/oss-fuzz/test_fuzzers.py index 4ccdeca4a..97fe4a60f 100644 --- a/Tests/oss-fuzz/test_fuzzers.py +++ b/Tests/oss-fuzz/test_fuzzers.py @@ -8,7 +8,7 @@ from PIL import Image if sys.platform.startswith("win32"): - pytest.skip("Fuzzer is linux only", true) + pytest.skip("Fuzzer is linux only", True) @pytest.mark.parametrize( From 862e3b9d8e19fb7c222ecd590ac94c97f459ae6f Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sun, 14 Mar 2021 14:11:48 +0100 Subject: [PATCH 34/89] Apparently, it's a keyword-only parameter --- Tests/oss-fuzz/test_fuzzers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/oss-fuzz/test_fuzzers.py b/Tests/oss-fuzz/test_fuzzers.py index 97fe4a60f..b5e6a3d86 100644 --- a/Tests/oss-fuzz/test_fuzzers.py +++ b/Tests/oss-fuzz/test_fuzzers.py @@ -8,7 +8,7 @@ from PIL import Image if sys.platform.startswith("win32"): - pytest.skip("Fuzzer is linux only", True) + pytest.skip("Fuzzer is linux only", allow_module_level=True) @pytest.mark.parametrize( From 76e0422eb7810963a455443910a6ceeb9e39d631 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sun, 14 Mar 2021 14:13:37 +0100 Subject: [PATCH 35/89] Isort linted that there's an extra line, which black didn't worry about --- Tests/oss-fuzz/test_fuzzers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/oss-fuzz/test_fuzzers.py b/Tests/oss-fuzz/test_fuzzers.py index b5e6a3d86..c61cb7e55 100644 --- a/Tests/oss-fuzz/test_fuzzers.py +++ b/Tests/oss-fuzz/test_fuzzers.py @@ -6,7 +6,6 @@ import pytest from PIL import Image - if sys.platform.startswith("win32"): pytest.skip("Fuzzer is linux only", allow_module_level=True) From d45247eb6683d660cd151a4b3db555eb3f97d03b Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Mon, 15 Mar 2021 00:14:43 +0100 Subject: [PATCH 36/89] Add decompression bomb error to font fuzzer --- Tests/oss-fuzz/fuzz_font.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/oss-fuzz/fuzz_font.py b/Tests/oss-fuzz/fuzz_font.py index 9f21a1fa5..bdfda7a13 100755 --- a/Tests/oss-fuzz/fuzz_font.py +++ b/Tests/oss-fuzz/fuzz_font.py @@ -31,6 +31,7 @@ def TestOneInput(data): def main(): + fuzzers.enable_decompressionbomb_error() atheris.Setup(sys.argv, TestOneInput, enable_python_coverage=True) atheris.Fuzz() From 83dabda6b2df344ecc6352d2b4d1e20fee4120dc Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Mon, 15 Mar 2021 00:18:07 +0100 Subject: [PATCH 37/89] Clean up comments and filters --- Tests/oss-fuzz/fuzzers.py | 4 ++-- Tests/oss-fuzz/test_fuzzers.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/oss-fuzz/fuzzers.py b/Tests/oss-fuzz/fuzzers.py index 156653f1d..1e7a4e27d 100644 --- a/Tests/oss-fuzz/fuzzers.py +++ b/Tests/oss-fuzz/fuzzers.py @@ -20,12 +20,12 @@ def fuzz_image(data): def fuzz_font(data): - # This should not fail on a valid font load for any of the fonts in the corpus wrapper = io.BytesIO(data) try: font = ImageFont.truetype(wrapper) except OSError: - # pcf/pilfonts/random garbage here here. They're different. + # Catch pcf/pilfonts/random garbage here. They return + # different font objects. return font.getsize_multiline("ABC\nAaaa") diff --git a/Tests/oss-fuzz/test_fuzzers.py b/Tests/oss-fuzz/test_fuzzers.py index c61cb7e55..04d4fd16b 100644 --- a/Tests/oss-fuzz/test_fuzzers.py +++ b/Tests/oss-fuzz/test_fuzzers.py @@ -43,7 +43,7 @@ def test_fuzz_images(path): "path", subprocess.check_output("find Tests/fonts -type f", shell=True).split(b"\n") ) def test_fuzz_fonts(path): - if not path or b"LICENSE.txt" in path or b".pil" in path: + if not path: return with open(path, "rb") as f: fuzzers.fuzz_font(f.read()) From ad37e86c40e42a10300c763acba7bdf53dd7c28a Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Mon, 15 Mar 2021 00:21:18 +0100 Subject: [PATCH 38/89] DecompressionBombError is now an option --- Tests/oss-fuzz/test_fuzzers.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Tests/oss-fuzz/test_fuzzers.py b/Tests/oss-fuzz/test_fuzzers.py index 04d4fd16b..8de71eb4b 100644 --- a/Tests/oss-fuzz/test_fuzzers.py +++ b/Tests/oss-fuzz/test_fuzzers.py @@ -46,5 +46,9 @@ def test_fuzz_fonts(path): if not path: return with open(path, "rb") as f: - fuzzers.fuzz_font(f.read()) + try: + fuzzers.fuzz_font(f.read()) + except (Image.DecompressionBombError, + Image.DecompressionBombWarning): + pass assert True From d7cbc9a27e8907ed4dfae1127eb97bf6a365733c Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 16 Mar 2021 22:19:48 +1100 Subject: [PATCH 39/89] Corrected grammar --- src/libImaging/GifDecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libImaging/GifDecode.c b/src/libImaging/GifDecode.c index 88ae3896c..5817001ac 100644 --- a/src/libImaging/GifDecode.c +++ b/src/libImaging/GifDecode.c @@ -221,7 +221,7 @@ ImagingGifDecode(Imaging im, ImagingCodecState state, UINT8 *buffer, Py_ssize_t if (context->next < GIFTABLE) { /* We'll only add this symbol if we have room - for it (take advise, Netscape!) */ + for it (take the advice, Netscape!) */ context->data[context->next] = c; context->link[context->next] = context->lastcode; From 94df4ec1c95932ec498e8be307498a1cd9241cbe Mon Sep 17 00:00:00 2001 From: Andrew Murray <3112309+radarhere@users.noreply.github.com> Date: Wed, 17 Mar 2021 23:16:35 +1100 Subject: [PATCH 40/89] Lint fix --- Tests/oss-fuzz/test_fuzzers.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Tests/oss-fuzz/test_fuzzers.py b/Tests/oss-fuzz/test_fuzzers.py index 8de71eb4b..a243c0260 100644 --- a/Tests/oss-fuzz/test_fuzzers.py +++ b/Tests/oss-fuzz/test_fuzzers.py @@ -48,7 +48,6 @@ def test_fuzz_fonts(path): with open(path, "rb") as f: try: fuzzers.fuzz_font(f.read()) - except (Image.DecompressionBombError, - Image.DecompressionBombWarning): + except (Image.DecompressionBombError, Image.DecompressionBombWarning): pass assert True From c585e6ab6b4731d65570dbb1cbf396add919b3ae Mon Sep 17 00:00:00 2001 From: elejke Date: Sun, 21 Mar 2021 21:15:13 +0300 Subject: [PATCH 41/89] Add preserve_tone option to autocontrast --- Tests/test_imageops.py | 1 + src/PIL/ImageOps.py | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 33489bd13..b261fa9fe 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -29,6 +29,7 @@ def test_sanity(): ImageOps.autocontrast(hopper("L"), cutoff=(2, 10)) ImageOps.autocontrast(hopper("L"), ignore=[0, 255]) ImageOps.autocontrast(hopper("L"), mask=hopper("L")) + ImageOps.autocontrast(hopper("L"), preserve_tone=True) ImageOps.colorize(hopper("L"), (0, 0, 0), (255, 255, 255)) ImageOps.colorize(hopper("L"), "black", "white") diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index 14602a5c8..ac4a7c8f4 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -61,7 +61,7 @@ def _lut(image, lut): # actions -def autocontrast(image, cutoff=0, ignore=None, mask=None): +def autocontrast(image, cutoff=0, ignore=None, mask=None, preserve_tone=False): """ Maximize (normalize) image contrast. This function calculates a histogram of the input image (or mask region), removes ``cutoff`` percent of the @@ -77,9 +77,14 @@ def autocontrast(image, cutoff=0, ignore=None, mask=None): :param mask: Histogram used in contrast operation is computed using pixels within the mask. If no mask is given the entire image is used for histogram computation. + :param preserve_tone: Preserve image tone in Photoshop-like style autocontrast. :return: An image. """ - histogram = image.histogram(mask) + if preserve_tone: + histogram = image.convert("L").histogram(mask) + else: + histogram = image.histogram(mask) + lut = [] for layer in range(0, len(histogram), 256): h = histogram[layer : layer + 256] From 2d8658bd84327b601ddd9147fd84b32d8e7e09da Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 22 Mar 2021 18:58:50 +1100 Subject: [PATCH 42/89] Deprecated categories [ci skip] --- docs/deprecations.rst | 12 ++++++++++++ docs/reference/Image.rst | 7 ------- docs/releasenotes/8.2.0.rst | 10 ++++++++++ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/docs/deprecations.rst b/docs/deprecations.rst index fd2f5620e..ef88afa23 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -33,6 +33,18 @@ Tk/Tcl 8.4 Support for Tk/Tcl 8.4 is deprecated and will be removed in Pillow 10.0.0 (2023-01-02), when Tk/Tcl 8.5 will be the minimum supported. +Categories +~~~~~~~~~~ + +.. deprecated:: 8.2.0 + +``im.category`` is deprecated and will be removed in Pillow 10.0.0 (2023-01-02), +along with the related ``Image.NORMAL``, ``Image.SEQUENCE`` and +``Image.CONTAINER`` attributes. + +To determine if an image has multiple frames or not, +``getattr(im, "is_animated", False)`` can be used instead. + Image.show command parameter ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index c4e8f37a3..0e68366ad 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -502,10 +502,3 @@ Used to specify the quantization method to use for the :meth:`~Image.quantize` m Check support using :py:func:`PIL.features.check_feature` with ``feature="libimagequant"``. - -.. comment: These are not referenced anywhere? - Categories - ^^^^^^^^^^ - .. data:: NORMAL - .. data:: SEQUENCE - .. data:: CONTAINER diff --git a/docs/releasenotes/8.2.0.rst b/docs/releasenotes/8.2.0.rst index d82bf45c2..3ef05894d 100644 --- a/docs/releasenotes/8.2.0.rst +++ b/docs/releasenotes/8.2.0.rst @@ -10,6 +10,16 @@ Tk/Tcl 8.4 Support for Tk/Tcl 8.4 is deprecated and will be removed in Pillow 10.0.0 (2023-01-02), when Tk/Tcl 8.5 will be the minimum supported. +Categories +^^^^^^^^^^ + +``im.category`` is deprecated and will be removed in Pillow 10.0.0 (2023-01-02), +along with the related ``Image.NORMAL``, ``Image.SEQUENCE`` and +``Image.CONTAINER`` attributes. + +To determine if an image has multiple frames or not, +``getattr(im, "is_animated", False)`` can be used instead. + API Changes =========== From ab56edb49f30557eb684256a1e3064936b737ecf Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 22 Mar 2021 19:18:36 +1100 Subject: [PATCH 43/89] Documented default quantization method --- docs/reference/Image.rst | 6 +++--- src/PIL/Image.py | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index c4e8f37a3..bf173ace9 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -486,15 +486,15 @@ Used to specify the quantization method to use for the :meth:`~Image.quantize` m .. data:: MEDIANCUT - Median cut + Median cut. Default method, except for RGBA images. .. data:: MAXCOVERAGE - Maximum coverage + Maximum coverage. .. data:: FASTOCTREE - Fast octree + Fast octree. Default method for RGBA images. .. data:: LIBIMAGEQUANT diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 2e7abfb68..bec6f3f64 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -1059,6 +1059,11 @@ class Image: :data:`LIBIMAGEQUANT` (libimagequant; check support using :py:func:`PIL.features.check_feature` with ``feature="libimagequant"``). + + By default, :data:`MEDIANCUT` will be used. + + The exception to this is RGBA images. RGBA images use + :data:`FASTOCTREE` by default instead. :param kmeans: Integer :param palette: Quantize to the palette of given :py:class:`PIL.Image.Image`. From 0ff987917116d5b859959b1dc80092f7fdffac0f Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 22 Mar 2021 19:21:31 +1100 Subject: [PATCH 44/89] Document supported quantization methods for RGBA images --- docs/reference/Image.rst | 5 +++-- src/PIL/Image.py | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index bf173ace9..2f4c9af99 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -486,11 +486,12 @@ Used to specify the quantization method to use for the :meth:`~Image.quantize` m .. data:: MEDIANCUT - Median cut. Default method, except for RGBA images. + Median cut. Default method, except for RGBA images. This method does not support + RGBA images. .. data:: MAXCOVERAGE - Maximum coverage. + Maximum coverage. This method does not support RGBA images. .. data:: FASTOCTREE diff --git a/src/PIL/Image.py b/src/PIL/Image.py index bec6f3f64..0bfd1da80 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -1062,8 +1062,9 @@ class Image: By default, :data:`MEDIANCUT` will be used. - The exception to this is RGBA images. RGBA images use - :data:`FASTOCTREE` by default instead. + The exception to this is RGBA images. :data:`MEDIANCUT` and + :data:`MAXCOVERAGE` do not support RGBA images, so + :data:`FASTOCTREE` is used by default instead. :param kmeans: Integer :param palette: Quantize to the palette of given :py:class:`PIL.Image.Image`. From 4e0bc3bab61124e5c8d29743d77541de052c44d8 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 22 Mar 2021 19:44:56 +1100 Subject: [PATCH 45/89] Use quantization method attributes --- src/PIL/Image.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 2e7abfb68..5e9d9a89f 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -1074,11 +1074,11 @@ class Image: if method is None: # defaults: - method = 0 + method = MEDIANCUT if self.mode == "RGBA": - method = 2 + method = FASTOCTREE - if self.mode == "RGBA" and method not in (2, 3): + if self.mode == "RGBA" and method not in (FASTOCTREE, LIBIMAGEQUANT): # Caller specified an invalid mode. raise ValueError( "Fast Octree (method == 2) and libimagequant (method == 3) " From b4e5a6d202037f9f96cf46371ca96e2743d6f24a Mon Sep 17 00:00:00 2001 From: elejke Date: Mon, 22 Mar 2021 12:06:44 +0300 Subject: [PATCH 46/89] add more tests for autocontrast preserve tone option --- Tests/test_imageops.py | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index b261fa9fe..922899e51 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -363,3 +363,51 @@ def test_auto_contrast_mask_real_input(): threshold=2, msg="autocontrast without mask pixel incorrect", ) + + +def test_autocontrast_preserve_gradient(): + from PIL import _imaging as core + + gradient = Image.Image()._new(core.linear_gradient("L")) + + # test with a grayscale gradient that extends to 0,255. + # Should be a noop. + out = ImageOps.autocontrast(gradient, cutoff=0, preserve_tone=True) + + assert_image_equal(gradient, out) + + # cutoff the top and bottom + # autocontrast should make the first and list histogram entries equal + # and should be 10% of the image pixels (+-, because integers) + out = ImageOps.autocontrast(gradient, cutoff=10, preserve_tone=True) + hist = out.histogram() + assert hist[0] == hist[-1] + assert hist[-1] == 256 * round(256 * 0.10) + + # in rgb + img = gradient.convert("RGB") + out = ImageOps.autocontrast(img, cutoff=0, preserve_tone=True) + assert_image_equal(img, out) + + +def test_autocontrast_preserve_onecolor(): + def _test_one_color(color): + img = Image.new("RGB", (10, 10), color) + + # single color images shouldn't change + out = ImageOps.autocontrast(img, cutoff=0, preserve_tone=True) + # remove when production + assert_image_equal(img, out) # single color, no cutoff + + # even if there is a cutoff + out = ImageOps.autocontrast( + img, cutoff=0, preserve_tone=True + ) # single color 10 cutoff + assert_image_equal(img, out) + + # succeeding + _test_one_color((255, 255, 255)) + _test_one_color((127, 255, 0)) + # failing + _test_one_color((127, 127, 127)) + _test_one_color((0, 0, 0)) From 25403063ead189d2335968a2097b20c3e425bd1a Mon Sep 17 00:00:00 2001 From: German Novikov Date: Mon, 22 Mar 2021 15:27:13 +0300 Subject: [PATCH 47/89] Update Tests/test_imageops.py Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- Tests/test_imageops.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 922899e51..f2479da16 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -366,9 +366,7 @@ def test_auto_contrast_mask_real_input(): def test_autocontrast_preserve_gradient(): - from PIL import _imaging as core - - gradient = Image.Image()._new(core.linear_gradient("L")) + gradient = Image.linear_gradient("L")) # test with a grayscale gradient that extends to 0,255. # Should be a noop. From f73d238cd2d10d5b576d0d7472ef8b62f9a4e1c2 Mon Sep 17 00:00:00 2001 From: elejke Date: Mon, 22 Mar 2021 15:30:43 +0300 Subject: [PATCH 48/89] removed redundant comments in tests for tone preserving autocolor --- Tests/test_imageops.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index f2479da16..973d45c15 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -366,7 +366,7 @@ def test_auto_contrast_mask_real_input(): def test_autocontrast_preserve_gradient(): - gradient = Image.linear_gradient("L")) + gradient = Image.linear_gradient("L") # test with a grayscale gradient that extends to 0,255. # Should be a noop. @@ -394,7 +394,6 @@ def test_autocontrast_preserve_onecolor(): # single color images shouldn't change out = ImageOps.autocontrast(img, cutoff=0, preserve_tone=True) - # remove when production assert_image_equal(img, out) # single color, no cutoff # even if there is a cutoff @@ -403,9 +402,7 @@ def test_autocontrast_preserve_onecolor(): ) # single color 10 cutoff assert_image_equal(img, out) - # succeeding _test_one_color((255, 255, 255)) _test_one_color((127, 255, 0)) - # failing _test_one_color((127, 127, 127)) _test_one_color((0, 0, 0)) From 8913166c7ea748d6884813172208eac4cb057141 Mon Sep 17 00:00:00 2001 From: elejke Date: Tue, 23 Mar 2021 11:59:37 +0300 Subject: [PATCH 49/89] fix test function name for autocontrast --- Tests/test_imageops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 973d45c15..595a8e02b 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -337,7 +337,7 @@ def test_autocontrast_mask_toy_input(): assert ImageStat.Stat(result_nomask).median == [128] -def test_auto_contrast_mask_real_input(): +def test_autocontrast_mask_real_input(): # Test the autocontrast with a rectangular mask with Image.open("Tests/images/iptc.jpg") as img: From 4a0698838d08fb36bbbc8a90376e777e52c7d0ad Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 23 Mar 2021 20:08:18 +1100 Subject: [PATCH 50/89] Parametrized test --- Tests/test_imageops.py | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 595a8e02b..64736513e 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -388,21 +388,18 @@ def test_autocontrast_preserve_gradient(): assert_image_equal(img, out) -def test_autocontrast_preserve_onecolor(): - def _test_one_color(color): - img = Image.new("RGB", (10, 10), color) +@pytest.mark.parametrize( + "color", ((255, 255, 255), (127, 255, 0), (127, 127, 127), (0, 0, 0)) +) +def test_autocontrast_preserve_one_color(color): + img = Image.new("RGB", (10, 10), color) - # single color images shouldn't change - out = ImageOps.autocontrast(img, cutoff=0, preserve_tone=True) - assert_image_equal(img, out) # single color, no cutoff + # single color images shouldn't change + out = ImageOps.autocontrast(img, cutoff=0, preserve_tone=True) + assert_image_equal(img, out) # single color, no cutoff - # even if there is a cutoff - out = ImageOps.autocontrast( - img, cutoff=0, preserve_tone=True - ) # single color 10 cutoff - assert_image_equal(img, out) - - _test_one_color((255, 255, 255)) - _test_one_color((127, 255, 0)) - _test_one_color((127, 127, 127)) - _test_one_color((0, 0, 0)) + # even if there is a cutoff + out = ImageOps.autocontrast( + img, cutoff=0, preserve_tone=True + ) # single color 10 cutoff + assert_image_equal(img, out) From 694d70bdc3f6179178348c2c9a6da64944177442 Mon Sep 17 00:00:00 2001 From: elejke Date: Tue, 23 Mar 2021 13:09:51 +0300 Subject: [PATCH 51/89] fixed typos in test for autocolor tone preserving --- Tests/test_imageops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 64736513e..8d12f6869 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -400,6 +400,6 @@ def test_autocontrast_preserve_one_color(color): # even if there is a cutoff out = ImageOps.autocontrast( - img, cutoff=0, preserve_tone=True + img, cutoff=10, preserve_tone=True ) # single color 10 cutoff assert_image_equal(img, out) From 9b8f7c2a8ff1b7e7f33bf4f8c1badac9ea7cc0ac Mon Sep 17 00:00:00 2001 From: elejke Date: Tue, 23 Mar 2021 13:56:51 +0300 Subject: [PATCH 52/89] versionadded directive and releasenotes added --- docs/releasenotes/8.2.0.rst | 9 +++++++++ src/PIL/ImageOps.py | 3 +++ 2 files changed, 12 insertions(+) diff --git a/docs/releasenotes/8.2.0.rst b/docs/releasenotes/8.2.0.rst index d82bf45c2..7a6caec5b 100644 --- a/docs/releasenotes/8.2.0.rst +++ b/docs/releasenotes/8.2.0.rst @@ -73,6 +73,15 @@ be specified through a keyword argument:: im.save("out.tif", icc_profile=...) + +ImageOps.autocontrast: tone preserving option +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The default behaviour of the :py:meth:`~PIL.ImageOps.autocontrast` is to normalize separate +histograms for each color channel, it changes tone of the image. Added ``preserve_tone`` +argument which avoids changing the tone of the image using one luminance histogram for all +channels. + Security ======== diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index ac4a7c8f4..d0b255530 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -78,6 +78,9 @@ def autocontrast(image, cutoff=0, ignore=None, mask=None, preserve_tone=False): within the mask. If no mask is given the entire image is used for histogram computation. :param preserve_tone: Preserve image tone in Photoshop-like style autocontrast. + + .. versionadded:: 1.1.5 + :return: An image. """ if preserve_tone: From 2c973b4cca9e07de84e9fbe99e07411337cdebbc Mon Sep 17 00:00:00 2001 From: elejke Date: Tue, 23 Mar 2021 13:57:51 +0300 Subject: [PATCH 53/89] versionadded version fixed --- src/PIL/ImageOps.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index d0b255530..d69a304ca 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -79,7 +79,7 @@ def autocontrast(image, cutoff=0, ignore=None, mask=None, preserve_tone=False): for histogram computation. :param preserve_tone: Preserve image tone in Photoshop-like style autocontrast. - .. versionadded:: 1.1.5 + .. versionadded:: 8.2.0 :return: An image. """ From 9d3da37f35426704776aef421b7e620d4b667e6e Mon Sep 17 00:00:00 2001 From: German Novikov Date: Tue, 23 Mar 2021 15:04:12 +0300 Subject: [PATCH 54/89] Update docs/releasenotes/8.2.0.rst [ci skip] Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- docs/releasenotes/8.2.0.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/releasenotes/8.2.0.rst b/docs/releasenotes/8.2.0.rst index 7a6caec5b..3bdfadacd 100644 --- a/docs/releasenotes/8.2.0.rst +++ b/docs/releasenotes/8.2.0.rst @@ -74,13 +74,13 @@ be specified through a keyword argument:: im.save("out.tif", icc_profile=...) -ImageOps.autocontrast: tone preserving option -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ImageOps.autocontrast: preserve_tone +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The default behaviour of the :py:meth:`~PIL.ImageOps.autocontrast` is to normalize separate -histograms for each color channel, it changes tone of the image. Added ``preserve_tone`` -argument which avoids changing the tone of the image using one luminance histogram for all -channels. +The default behaviour of the :py:meth:`~PIL.ImageOps.autocontrast` is to normalize +separate histograms for each color channel, changing the tone of the image. The new +``preserve_tone`` argument keeps the tone unchanged by using one luminance histogram +for all channels. Security ======== From 49fa3656b180713dfa9b680e4b9a5885aba501bd Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 3 Mar 2021 13:58:13 +0100 Subject: [PATCH 55/89] do not premultiply alpha when resizing with Image.NEAREST resampling --- Tests/test_image_transform.py | 36 +++++++++++++++++++++++++++++++++++ src/PIL/Image.py | 6 +++--- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/Tests/test_image_transform.py b/Tests/test_image_transform.py index 3ee51178d..c22b874c6 100644 --- a/Tests/test_image_transform.py +++ b/Tests/test_image_transform.py @@ -143,6 +143,42 @@ class TestImageTransform: self._test_alpha_premult(op) + def _test_nearest(self, op, mode): + # create white image with half transparent, + # with the black half transparent. + # do op, + # the image should be white with half transparent + transparent, opaque = { + "RGBA": ((255, 255, 255, 0), (255, 255, 255, 255)), + "LA": ((255, 0), (255, 255)), + }[mode] + im = Image.new(mode, (10, 10), transparent) + im2 = Image.new(mode, (5, 10), opaque) + im.paste(im2, (0, 0)) + + im = op(im, (40, 10)) + + colors = im.getcolors() + assert colors == [ + (20 * 10, opaque), + (20 * 10, transparent), + ] + + @pytest.mark.parametrize("mode", ("RGBA", "LA")) + def test_nearest_resize(self, mode): + def op(im, sz): + return im.resize(sz, Image.NEAREST) + + self._test_nearest(op, mode) + + @pytest.mark.parametrize("mode", ("RGBA", "LA")) + def test_nearest_transform(self, mode): + def op(im, sz): + (w, h) = im.size + return im.transform(sz, Image.EXTENT, (0, 0, w, h), Image.NEAREST) + + self._test_nearest(op, mode) + def test_blank_fill(self): # attempting to hit # https://github.com/python-pillow/Pillow/issues/254 reported diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 2e7abfb68..6f7ed776f 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -1910,7 +1910,7 @@ class Image: if self.mode in ("1", "P"): resample = NEAREST - if self.mode in ["LA", "RGBA"]: + if self.mode in ["LA", "RGBA"] and resample != NEAREST: im = self.convert(self.mode[:-1] + "a") im = im.resize(size, resample, box) return im.convert(self.mode) @@ -2394,14 +2394,14 @@ class Image: :returns: An :py:class:`~PIL.Image.Image` object. """ - if self.mode == "LA": + if self.mode == "LA" and resample != NEAREST: return ( self.convert("La") .transform(size, method, data, resample, fill, fillcolor) .convert("LA") ) - if self.mode == "RGBA": + if self.mode == "RGBA" and resample != NEAREST: return ( self.convert("RGBa") .transform(size, method, data, resample, fill, fillcolor) From 5e61c1842fcee02562cbb46dd44e8bdd39e3903f Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 25 Mar 2021 00:04:41 +0100 Subject: [PATCH 56/89] fix support for old versions of Raqm --- src/_imagingft.c | 61 ++++++++++++++++-------------------------------- 1 file changed, 20 insertions(+), 41 deletions(-) diff --git a/src/_imagingft.c b/src/_imagingft.c index 0995abab3..330294479 100644 --- a/src/_imagingft.c +++ b/src/_imagingft.c @@ -236,7 +236,6 @@ text_layout_raqm( size_t i = 0, count = 0, start = 0; raqm_t *rq; raqm_glyph_t *glyphs = NULL; -// raqm_glyph_t_01 *glyphs_01 = NULL; raqm_direction_t direction; rq = raqm_create(); @@ -278,12 +277,12 @@ text_layout_raqm( direction = RAQM_DIRECTION_LTR; } else if (strcmp(dir, "ttb") == 0) { direction = RAQM_DIRECTION_TTB; -// if (p_raqm.version_atleast == NULL || !(*p_raqm.version_atleast)(0, 7, 0)) { -// PyErr_SetString( -// PyExc_ValueError, -// "libraqm 0.7 or greater required for 'ttb' direction"); -// goto failed; -// } +#if !defined(RAQM_VERSION_ATLEAST) || !RAQM_VERSION_ATLEAST(0, 7, 0) + PyErr_SetString( + PyExc_ValueError, + "libraqm 0.7 or greater required for 'ttb' direction"); + goto failed; +#endif } else { PyErr_SetString( PyExc_ValueError, "direction must be either 'rtl', 'ltr' or 'ttb'"); @@ -340,21 +339,12 @@ text_layout_raqm( goto failed; } -// if (p_raqm.version == 1) { -// glyphs_01 = raqm_get_glyphs_01(rq, &count); -// if (glyphs_01 == NULL) { -// PyErr_SetString(PyExc_ValueError, "raqm_get_glyphs() failed."); -// count = 0; -// goto failed; -// } -// } else { /* version == 2 */ - glyphs = raqm_get_glyphs(rq, &count); - if (glyphs == NULL) { - PyErr_SetString(PyExc_ValueError, "raqm_get_glyphs() failed."); - count = 0; - goto failed; - } -// } + glyphs = raqm_get_glyphs(rq, &count); + if (glyphs == NULL) { + PyErr_SetString(PyExc_ValueError, "raqm_get_glyphs() failed."); + count = 0; + goto failed; + } (*glyph_info) = PyMem_New(GlyphInfo, count); if ((*glyph_info) == NULL) { @@ -363,25 +353,14 @@ text_layout_raqm( goto failed; } -// if (p_raqm.version == 1) { -// for (i = 0; i < count; i++) { -// (*glyph_info)[i].index = glyphs_01[i].index; -// (*glyph_info)[i].x_offset = glyphs_01[i].x_offset; -// (*glyph_info)[i].x_advance = glyphs_01[i].x_advance; -// (*glyph_info)[i].y_offset = glyphs_01[i].y_offset; -// (*glyph_info)[i].y_advance = glyphs_01[i].y_advance; -// (*glyph_info)[i].cluster = glyphs_01[i].cluster; -// } -// } else { - for (i = 0; i < count; i++) { - (*glyph_info)[i].index = glyphs[i].index; - (*glyph_info)[i].x_offset = glyphs[i].x_offset; - (*glyph_info)[i].x_advance = glyphs[i].x_advance; - (*glyph_info)[i].y_offset = glyphs[i].y_offset; - (*glyph_info)[i].y_advance = glyphs[i].y_advance; - (*glyph_info)[i].cluster = glyphs[i].cluster; - } -// } + for (i = 0; i < count; i++) { + (*glyph_info)[i].index = glyphs[i].index; + (*glyph_info)[i].x_offset = glyphs[i].x_offset; + (*glyph_info)[i].x_advance = glyphs[i].x_advance; + (*glyph_info)[i].y_offset = glyphs[i].y_offset; + (*glyph_info)[i].y_advance = glyphs[i].y_advance; + (*glyph_info)[i].cluster = glyphs[i].cluster; + } failed: raqm_destroy(rq); From c718cc6c94cacfbfcd7e84cff9f012df1b84c718 Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 25 Mar 2021 00:25:38 +0100 Subject: [PATCH 57/89] avoid unused variable warnings --- src/_imagingft.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/_imagingft.c b/src/_imagingft.c index 330294479..73f0f6362 100644 --- a/src/_imagingft.c +++ b/src/_imagingft.c @@ -1367,7 +1367,6 @@ setup_module(PyObject *m) { PyDict_SetItemString(d, "HAVE_FRIBIDI", v); PyDict_SetItemString(d, "HAVE_HARFBUZZ", v); if (have_raqm) { - const char *a, *b; #ifdef RAQM_VERSION_MAJOR v = PyUnicode_FromString(raqm_version_string()); #else @@ -1376,12 +1375,14 @@ setup_module(PyObject *m) { PyDict_SetItemString(d, "raqm_version", v); #ifdef FRIBIDI_MAJOR_VERSION - a = strchr(fribidi_version_info, ')'); - b = strchr(fribidi_version_info, '\n'); - if (a && b) { - v = PyUnicode_FromStringAndSize(a + 2, b - a - 2); - } else { - v = Py_None; + { + const char *a = strchr(fribidi_version_info, ')'); + const char *b = strchr(fribidi_version_info, '\n'); + if (a && b && a + 2 < b) { + v = PyUnicode_FromStringAndSize(a + 2, b - (a + 2)); + } else { + v = Py_None; + } } #else v = Py_None; From 977e64fb6150b04fcbe2ae29eadd893df443f9c9 Mon Sep 17 00:00:00 2001 From: German Novikov Date: Thu, 25 Mar 2021 14:56:30 +0300 Subject: [PATCH 58/89] Update Tests/test_imageops.py Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- Tests/test_imageops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 8d12f6869..986c5f887 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -376,7 +376,7 @@ def test_autocontrast_preserve_gradient(): # cutoff the top and bottom # autocontrast should make the first and list histogram entries equal - # and should be 10% of the image pixels (+-, because integers) + # and, with rounding, should be 10% of the image pixels out = ImageOps.autocontrast(gradient, cutoff=10, preserve_tone=True) hist = out.histogram() assert hist[0] == hist[-1] From 9872d57e3baa0659482bee143e7029f358cd6746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ondrej=20Baranovi=C4=8D?= Date: Sat, 27 Mar 2021 02:06:36 +0100 Subject: [PATCH 59/89] corrected comment --- Tests/test_image_transform.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Tests/test_image_transform.py b/Tests/test_image_transform.py index c22b874c6..845900267 100644 --- a/Tests/test_image_transform.py +++ b/Tests/test_image_transform.py @@ -145,9 +145,8 @@ class TestImageTransform: def _test_nearest(self, op, mode): # create white image with half transparent, - # with the black half transparent. # do op, - # the image should be white with half transparent + # the image should remain white with half transparent transparent, opaque = { "RGBA": ((255, 255, 255, 0), (255, 255, 255, 255)), "LA": ((255, 0), (255, 255)), From a4a38b805b524f0fdb0d1feca83ca73d3ccfff0b Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 27 Mar 2021 14:47:11 +1100 Subject: [PATCH 60/89] Removed return value of build_distance_tables --- src/libImaging/Quant.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/libImaging/Quant.c b/src/libImaging/Quant.c index bee5e5599..f5a5d567c 100644 --- a/src/libImaging/Quant.c +++ b/src/libImaging/Quant.c @@ -789,7 +789,7 @@ resort_distance_tables( return 1; } -static int +static void build_distance_tables( uint32_t *avgDist, uint32_t **avgDistSortKey, Pixel *p, uint32_t nEntries) { uint32_t i, j; @@ -811,7 +811,6 @@ build_distance_tables( sizeof(uint32_t *), _sort_ulong_ptr_keys); } - return 1; } static int @@ -1373,9 +1372,7 @@ quantize( goto error_6; } - if (!build_distance_tables(avgDist, avgDistSortKey, p, nPaletteEntries)) { - goto error_7; - } + build_distance_tables(avgDist, avgDistSortKey, p, nPaletteEntries); if (!map_image_pixels_from_median_box( pixelData, nPixels, p, nPaletteEntries, h, avgDist, avgDistSortKey, qp)) { @@ -1580,9 +1577,7 @@ quantize2( goto error_3; } - if (!build_distance_tables(avgDist, avgDistSortKey, p, nQuantPixels)) { - goto error_4; - } + build_distance_tables(avgDist, avgDistSortKey, p, nQuantPixels); if (!map_image_pixels( pixelData, nPixels, p, nQuantPixels, avgDist, avgDistSortKey, qp)) { From 71cd97a5199bc54d492150fdd7f6ad216f381e70 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 28 Mar 2021 15:51:28 +1100 Subject: [PATCH 61/89] Added deprecation warnings --- Tests/test_image.py | 15 +++++++++++++++ src/PIL/Image.py | 35 ++++++++++++++++++++++++++++------- src/PIL/MicImagePlugin.py | 2 +- 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/Tests/test_image.py b/Tests/test_image.py index b326ca0f8..3fa071be1 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -1,6 +1,7 @@ import io import os import shutil +import sys import tempfile import pytest @@ -769,6 +770,20 @@ class TestImage: reloaded_exif.load(exif.tobytes()) assert reloaded_exif.get_ifd(0x8769) == exif.get_ifd(0x8769) + @pytest.mark.skipif( + sys.version_info < (3, 7), reason="Python 3.7 or greater required" + ) + def test_categories_deprecation(self): + with pytest.warns(DeprecationWarning): + assert hopper().category == 0 + + with pytest.warns(DeprecationWarning): + assert Image.NORMAL == 0 + with pytest.warns(DeprecationWarning): + assert Image.SEQUENCE == 1 + with pytest.warns(DeprecationWarning): + assert Image.CONTAINER == 2 + @pytest.mark.parametrize( "test_module", [PIL, Image], diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 2e7abfb68..6f0fd1383 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -59,6 +59,16 @@ if sys.version_info >= (3, 7): if name == "PILLOW_VERSION": _raise_version_warning() return __version__ + else: + categories = {"NORMAL": 0, "SEQUENCE": 1, "CONTAINER": 2} + if name in categories: + warnings.warn( + "Image categories are deprecated and will be removed in Pillow 10 " + "(2023-01-02). Use is_animated instead.", + DeprecationWarning, + stacklevel=2, + ) + return categories[name] raise AttributeError(f"module '{__name__}' has no attribute '{name}'") @@ -69,6 +79,11 @@ else: # Silence warning assert PILLOW_VERSION + # categories + NORMAL = 0 + SEQUENCE = 1 + CONTAINER = 2 + logger = logging.getLogger(__name__) @@ -187,11 +202,6 @@ MAXCOVERAGE = 1 FASTOCTREE = 2 LIBIMAGEQUANT = 3 -# categories -NORMAL = 0 -SEQUENCE = 1 -CONTAINER = 2 - if hasattr(core, "DEFAULT_STRATEGY"): DEFAULT_STRATEGY = core.DEFAULT_STRATEGY FILTERED = core.FILTERED @@ -535,11 +545,22 @@ class Image: self._size = (0, 0) self.palette = None self.info = {} - self.category = NORMAL + self._category = 0 self.readonly = 0 self.pyaccess = None self._exif = None + def __getattr__(self, name): + if name == "category": + warnings.warn( + "Image categories are deprecated and will be removed in Pillow 10 " + "(2023-01-02). Use is_animated instead.", + DeprecationWarning, + stacklevel=2, + ) + return self._category + raise AttributeError(name) + @property def width(self): return self.size[0] @@ -648,7 +669,7 @@ class Image: and self.mode == other.mode and self.size == other.size and self.info == other.info - and self.category == other.category + and self._category == other._category and self.readonly == other.readonly and self.getpalette() == other.getpalette() and self.tobytes() == other.tobytes() diff --git a/src/PIL/MicImagePlugin.py b/src/PIL/MicImagePlugin.py index 2aed26030..9248b1b65 100644 --- a/src/PIL/MicImagePlugin.py +++ b/src/PIL/MicImagePlugin.py @@ -68,7 +68,7 @@ class MicImageFile(TiffImagePlugin.TiffImageFile): self.is_animated = self._n_frames > 1 if len(self.images) > 1: - self.category = Image.CONTAINER + self._category = Image.CONTAINER self.seek(0) From fa6fed92cb8ca664a898e37f8df8188c363c4812 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 28 Mar 2021 16:10:34 +1100 Subject: [PATCH 62/89] Update CHANGES.rst [ci skip] --- CHANGES.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 21eeb214c..dba9d263a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,12 @@ Changelog (Pillow) 8.2.0 (unreleased) ------------------ +- Do not premultiply alpha when resizing with Image.NEAREST resampling #5304 + [nulano] + +- Dynamically link FriBiDi instead of Raqm #5062 + [nulano] + - Allow fewer PNG palette entries than the bit depth maximum when saving #5330 [radarhere] From bf8cebc96d8210d10394eb29728b1953def34f75 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sun, 28 Mar 2021 13:49:37 +0200 Subject: [PATCH 63/89] Add libxcb to fuzzers --- Tests/oss-fuzz/build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/oss-fuzz/build.sh b/Tests/oss-fuzz/build.sh index fc54ee3ee..513136fff 100755 --- a/Tests/oss-fuzz/build.sh +++ b/Tests/oss-fuzz/build.sh @@ -31,6 +31,7 @@ for fuzzer in $(find $SRC -name 'fuzz_*.py'); do --add-binary /usr/local/lib/libwebp.so.7:. \ --add-binary /usr/local/lib/libwebpdemux.so.2:. \ --add-binary /usr/local/lib/libwebpmux.so.3:. \ + --add-binary /usr/local/lib/libxcb.so.1:. \ --distpath $OUT --onefile --name $fuzzer_package $fuzzer # Create execution wrapper. From d18e55013dafa2da7a68dd5ab911bfdb3826d74c Mon Sep 17 00:00:00 2001 From: German Novikov Date: Sun, 28 Mar 2021 15:02:52 +0300 Subject: [PATCH 64/89] Update Tests/test_imageops.py Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- Tests/test_imageops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 986c5f887..888afad37 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -375,7 +375,7 @@ def test_autocontrast_preserve_gradient(): assert_image_equal(gradient, out) # cutoff the top and bottom - # autocontrast should make the first and list histogram entries equal + # autocontrast should make the first and last histogram entries equal # and, with rounding, should be 10% of the image pixels out = ImageOps.autocontrast(gradient, cutoff=10, preserve_tone=True) hist = out.histogram() From 0018685a8e475ce91ceb11a6df8e137f0b1f6a47 Mon Sep 17 00:00:00 2001 From: Konstantin Kopachev Date: Sat, 23 May 2020 09:24:41 -0700 Subject: [PATCH 65/89] Add Tests and support for Planar Tiff Images --- Tests/images/tiff_strip_planar_16bit_RGB.tiff | Bin 0 -> 31576 bytes .../images/tiff_strip_planar_16bit_RGBa.tiff | Bin 0 -> 37295 bytes Tests/images/tiff_strip_planar_lzw.tiff | Bin 0 -> 155014 bytes Tests/images/tiff_tiled_planar_16bit_RGB.tiff | Bin 0 -> 34501 bytes .../images/tiff_tiled_planar_16bit_RGBa.tiff | Bin 0 -> 41015 bytes Tests/images/tiff_tiled_planar_lzw.tiff | Bin 0 -> 159997 bytes Tests/test_file_libtiff.py | 46 +++++++ Tests/test_lib_pack.py | 54 ++++++++ src/libImaging/Unpack.c | 121 +++++++++++++++++- 9 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 Tests/images/tiff_strip_planar_16bit_RGB.tiff create mode 100644 Tests/images/tiff_strip_planar_16bit_RGBa.tiff create mode 100644 Tests/images/tiff_strip_planar_lzw.tiff create mode 100644 Tests/images/tiff_tiled_planar_16bit_RGB.tiff create mode 100644 Tests/images/tiff_tiled_planar_16bit_RGBa.tiff create mode 100644 Tests/images/tiff_tiled_planar_lzw.tiff diff --git a/Tests/images/tiff_strip_planar_16bit_RGB.tiff b/Tests/images/tiff_strip_planar_16bit_RGB.tiff new file mode 100644 index 0000000000000000000000000000000000000000..360b4c165333468fbbdc015916edf3fc265df7e9 GIT binary patch literal 31576 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 TOKzPa?>J~e2{$#_l;{5+2s|yj literal 0 HcmV?d00001 diff --git a/Tests/images/tiff_strip_planar_16bit_RGBa.tiff b/Tests/images/tiff_strip_planar_16bit_RGBa.tiff new file mode 100644 index 0000000000000000000000000000000000000000..b8c3dcf643853d875a274032c13377739be76638 GIT binary patch literal 37295 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 literal 0 HcmV?d00001 diff --git a/Tests/images/tiff_strip_planar_lzw.tiff b/Tests/images/tiff_strip_planar_lzw.tiff new file mode 100644 index 0000000000000000000000000000000000000000..8145703f4308af2329218d1ffbba2b7f8931d5e8 GIT binary patch literal 155014 zcmZsCXIN89)NVp21=1TuLI>#}T_tpo-a$%22azTspkhLALMS32Xab0U2mw(MQ4=}{ z2-px&6Pnl%Jcx=O&&~Pn`JU(gxI52e-o2*m*?ab$nYG?E4i4%7F#rG{2><{E0YE;& z@c)4S;Z!~r;A26)e4ZZ!|C0;zvB-Z|fREuoA%F@$PT}WA|0n;q4CX&9!^hbF@+|N% z0Vw=G*BazwssHdKA4~r~b*lb9^&I>U|Jy!KKK{3E*uNL%AOG-=`)9?(|2G!n-;Wqz z0m@GS0RY8t06+%`0F)vCfOQFe>-aZ1%#SPi@ep6GjRF9!^5Z3bz7>9%R(_d#{Im!B z^Jo|V;KG+>^Ya(-!y|qu<;%JMg)n})Jp=&A5eERu_-UH_^Dcfo%a{FIMw(xbDnFR; z0ANeBq|2Mq*7DFXqw^nn0lOCW&b1_YFZ00D#~AYd;G2w1EF z0uEjU0&=^70P%Z3K+OaYF!B-zNZ9}atiJ&PV}b&J6@&l)EH41C))N4{vJe0~aTVbA z%D+DublX*oN-9@u}UlFr%-`4lfIE-ibpD1GS=*y zJ(Lh7b_(u)8B}-^=nhJV7>9O>LCujC&zR=P2vdgZwdj};P@$cxr#f1FB=&yr?G8=M z5p>;jbgy3r`hb$-RiEoV`!9SL@vd&}@Vy?ldz8@Noa)hrD)KgEx?OWutx|^&&K_dA zKVdlveNED;aZ;)%bjk?QhD}AD@E=$;*deP|idiLIzUX}IY3xa$bL5?%E|75Q(St4H zns=7s1%BP<2I@ZKCZ+`*QURYHTTMfKJpS*SB`tN@l?3{#w4JuY`f*hD5%DgZX zCT%YzTuTxkjMF^`u4GM^K!@l{`jW%2DQ)<0&QJ3po!KTackLrD9X)Nq-7XKh9x**` zUvQr~DRbe7d0M~rqi!dU@!}^4Hp>Q554Nu2nH+Talxr2#6JCEytNfcg-pBj<^iEDGmxJ?nc0Z65q~h^X z-tHN;F)Ei=6Y)N08RsDHfN*$S!StW^7PMG&KYp!jad&>I_rldwC!bf}g-7sJBl4F= zo~+IXZJIw6`be6Uf>F|xLTHLHm~`6hGt z$o#j1Awf@5+TaMAPim9dhbp_R#BY7C2wuG3x#l0}hjHAF4yewpyK_I`($~cSwXcyE zE_wNno)}f}tyXnN`nub2?drg_5nai^0X49ib+@uzd5(hwi5^n6YylJe=ku>WIg;P@ z{yEGPA`0mgP~D&%_iSO#j>uSDu!E(=bIWlXQzLX}uOC=9QOjnb4{Ny*SWJuek+quC z&^EXY$_r2}3GGt_!$*xr9NU5y15Xc+Y$4`gKX`*;(Vdj$HjbWB4!soadVlX>;_rR- zy$*%MT}A6GO{Cy^S-52cPJXQ;#Ql9tTJD*EVoCyb1#kxoFV(ZPH`NNW=*Na`1(yJ` zbVYQ=@PdlrB?X^!M~z3ztWcpPqyn8$90w-|2m#NX61C|L!Pp!hFslCg`qh&u^dRGi z35E&CF*m8Sb9iJmgyUI{S0UtetP0$PtQ#p9Ny!}s##9EfNqMwkUEtpNaZ66pKes;;z%gp&@zl>FD ziUeiKL=?u;ZIL_P;Mrj~CHKh<{l?_3=iSF?L{k;sUwRI~UTe$LO|1>Uld;mKn z7Ft59(ib_tjjs-!vODrwM&Z6Oc6lqXII2oRQ?ngi15MzXo_Ej1QD9mAPb#j*WWQLs z7zFNcDm$tv=-Af~&} zYH@~ToYJ1trTb-Hg@V!Y(Hb67;_Z7fgKZ-?qfMj(l6b7>b9mM8PL~F6k3$&EOCBW6gW3#)m*|X{Imi7*cviA0^ z%!U>)rU*lw+LFX2GZA;8SC>VMva$j8p+Oqv0#q_Y`0Ps1@_=tH>pToeJt#&})z$MZ zdvH6_EOudgpAGj`0$RwQ3o0me@8{W$I1rlLrLorcb|imZ3I&Lp7Cd`^o^Dhy7Uh1x z330jmnikT^1lP^RsN1qbJIO`(c>pS^8DlD`IMruWJ$3kt#9w$vihP8N!)Kh-Pm|W#5cn z`aJ6f0RrzCC2~as0ID7YCyiVxSyBLIEDYU2?Xle83Rw<2yn~LhJNoUiOe!P`g z8Sq<`ZmLO<*xuMbR1hYiPc?M`>|%x~1xstLjrmY5b5X#oh>Q22TGf{0p%hx+4C2!t7l<|VrI^Zf?E^TM_1~x5t zuUaB3k?cIF2R6_`L{a6wMmUgw=iN;e5I6*&>3Nu!RGbVU&IuVn2=+ilr6c zfpr85ONuiuHCru3yah^Zl_K4i;>=2u7u0J#~MGhTFmv;l-;eIYYVz#Ci<00~-p1G?Su*1b^# z_6g0Pf`F>`d39VO9XI=1#_@#owiu3>iRM_t3;Hop#)xYJ_T3s0bBZ$ES`P3X6!|#} z@JXWE_%?YBx%$HwqK=@+!O2_%ZC^L9fSzNx-{ZpkQ9XI228vXsCymyUT#bcgQ3M^Ng84R_Weh4 z-2H~Q@@XNs7!INJkYbKt+PBIte_or|r%0D+65bzP;SeSUmHSigA<&*IA``yjt1bd3 z&*F&v_<~PZ5(CFe#Bu8JJO%;ClBL|nk(#C46R@OKg4TUWN*|8#6-1t|)d-LzGt_#* z(aF&$AQ5;|O~rXfL*sQ$%A7CWnI}aYNGPIGjygC5-6_$3`8eX zcdnN0Z+UK+S8fC}hme2Q_l&k%@Q~|~gDo|1?jIPX1K;`w$4n*A=vZ346s%c_(ka91 z#nI$Nx#1!f1_DG3{?U3Fuuh7o3gQk!-&aU5{(uDPwd3L?kc#iA01?C{1kMse>Lp~| zI2`)}O~QcyUFb(|4QM6T#Dx#&d(qp^!kL!p6*mlf`p>LsIW*VX5S5{T-I^zvSE#R% ztDA#Oig4~56r~ea@Y;mN!c)!=kS$V7hBUJi$Ci@-)Pty*Vr&E4$9ERY5(3Wy3b+kz zE0JLQ28{@yZoWZ@zL${WN(0#v0P-8;*0PARWAAl+is1*28hWbIq9}=k^r5$BVB^~0 zOvhUk7u3zT6H2qz=jqnmzxTZ_w2Ik| zN*#M6Np_TQ3%` z%;zouv_+ChNq9wNi!wglO znm|D3XLKuTb0kw;k|WYceGau0`2Xm2QUWf$gAsZ)N3K@1DaP(f|o)2lu=eD`1YX4+ue zc%#F|`$GS6cR-h)#zpY0U(llQ2)%11wo<~>hauX&*B>>0PVEou#C)_Vy6e^I(OMjm zWJDR+$1LW0kE^NLmp40jIaKBn$-%f5@yr;NbxLpiC6TtlL?pw0=Qtgxh6uw)swMiM z!Y2Y<#j;^bM$i>@zpG9J(E2@EnB?Jg!6UF%#X--(Rc$gt*RjRH#=+08`szeRNR2JA zfPw=TbB|6#J-q^|uQDV3F~SrNc9qb3!{T1+-fssVTX+0@SW=KPm2i1VrSw%zTq_=xRrFXUQ% znvUHHbyZ11fwgH~X2sn*R5tYY`LKndZ&io=Qls|{1z>Uu4$~F!64vG66lr?|U+=Vq zhr1)J;X((ePtb>TL6-C!yujhI?1isprA>@=lTzR5Z)e|Hbql$onl{GuW_N7x**q9^ zY1TD|SsGP4N>L6*UL^(w;YHdWBwhLOe)p8jyNRu|hBelV$7Nx$r^cmuzzz4<||M z`g6K2?NtwTUs~VptCAAA+Zp?8o!J_*DOI}GC#76o6nyYY(y5#;mp&e_b8T*;Tjl{1 zeKc`e<)I3$c<^6N*(zawF5(R1HXWP_zL; zh-vJF$>q_b33<#rCtrVW_>v)&#~V+TEf7$xQYi{;?bHNYj(4gTH8PsjK!>_+yx+@g zy{s&5XoW-BLlJI&r;ceNPZ7=etdb9|hlX;}(pl-B|EtMy; z@~ljbrIyCF zV}74yR{APYp>I%Q3*O*x!Lv}l=JzKF`_`xM3apnmzVMdjdUZ~R}|2Xrt;ky^DrqYkRJgc2w z!m06uq)kkm*Ils)D#MlyIqMmIZPbQ3eu54~# z-0l&5-%zs|h|4t{Yu$rTs#GB+Zn`3~Ws+IVA*Agysvm4`+kc!6FFPI;BwET(Q|)Ry#W`1VU>y8ngetFYM2WvfBAEJF!&M zaRuMGaMgAzX+Qnztvv*Mn9y4c|PA=gdznM=EOzzy#Y zH-u$}a%_v$HElMgDWu-`(z!j$Ke-zWsiweCzItWy!T8I*?BC~nO*f2&SPXg+v)8IO zuHXgMm!}kZ%QhKXTCQN1b3W>v<&t|Du~px8cKu=#_pHYqMf1@gjSyPOeqo(@Se9Eg zw#nc$*lj^c_y+o%<&U6+?vLT|BV|2z;!gP&-;a!Y-8kTrb29koboyB09K7+q_F{oe z>=#-M6kz#6T#(aWbVKtpjp z!3*ZvHnZmmg7cd}_a2_=*dz{Iyn+aJe^R(@t2QFo7ZH39ewqp09$L$jjES&QYWqb|KZcc>Gts4tcGf`O|V8wGM@>uJ#L%Sicmmh5k z6Aaa-{1_J_y=`@cqB}Ke24P|5OO{rKhVYLkqzB>2se%Bh3D2#O#-%m9Qr)L=*g>v4h_iP%Ch^y7*v`4QpyI9_&HMY7R}bX#4r%u0 zl~1l%r?0)%Qv8DZ_+&BLJu=Ak&NtQdCCB=Z_1ci@fR zXS8gLFA`49W=0<@8cWsrvylBGpqh6FTj?7T9qr-aSx@Xdm=i{`bDaHv)vSM>}8dJx(hvSXUHD zy_;kC$)}KFptpLd;=NN!CX}Kll|5U9&iWY5`GZriE%@4t&n{S|YnWQ4l}~X7e7_QB z^abqKSEUM!k}rEn*(9z(2d>>Mb@}}ISKsGn<_~MOrx&z`3ozMBj~YJ8jSHFV{hn<1^W`L#&kldZ%6X&H$KA;cT1F-jAfsa zj^*9)1;)Rg6jeF7d4D14*W0siZo2Bcmb#vLLR&=ETq^HxTdVo z{G{X8k0qWKJ%0d7)S>dgD6RH@$1V!6A*Bk6v(ah z`erAd_eT2j7<|)b&1D;rDDu7KjzqVvMBYPWk_nReK*o6z-TD)*@(p%mML_HwZ0j1T zz~uw4US?Z%DM|hqTzPX_{g}HpQuhF|J1s762nCcvx%-uEJKb_x-d24Nhv(($2FlF% zVmh}m+eu;~eaE`fk>zKllqaR;?n;%@aPIlI>%K5L6YqWz-O-6>zQS}T5a`)hcOxm= zF{$qNvb1}$+gno1Cn#MzbouZti%9_;c{r;HoiwvSNo)qb1h~HzgXSob<&*xB zXZA}~=qjkc!BI5ONxx9#e>yCl$hkj~o0rG|CZm7>Qp7o#ulwZTYqIm2`w$0|d-S4P z@}y&Mi1!V+(Es1^mmr{(lj1Esjn{sm?p0xUa39@1+`~jMSL1fPNub`{qgg@PHAd^6 zCQTW~jS`HaJX=v#B??jAOZ=7X=YpYkR+d`Fx#x(v$<)-Fu7)}}?YP93~58=VqxQ2Ae4BRT*v5q!e4YnEP+ldLP2W~ERzHZ0R7 zlxZsm8(Xy`ie;L~mf0yH;6fSZ`{?OIJ>t@(mI^6iN3;CpitOYOVylDxX8qR66%#pM z)16v8)XFzm3 z7`@wb?2^O#-s4g&yy1AMN!XhS1cWIYnU@nYm{2=PoJ}1q?>H_s2ItcnW96UD?i*bv z*4K{e*3%S5m&NiFOqX#vTPBVAvGN6>fE<|umt!gWL^% z1%rXj3WWl0RZ90gYpRtCmlGLkpsYUDe%C>Er$(^=w@(|~B(`+0JQpA6R~^w78-R%@ z4EC=cxtkG!Q`W7DBt(|C#}d{%^r3a@oSwL$_2pEigf5AQs-25rC*Yz?7VCX4d_Ehp zfPv;x7OG{EFZmvLT^#YE(lb-OQ0v!iqPT!gmb_EX(u}<5veX$l(HUyyikL(}p}JwH zSDRA7vhy<&@tc)TRf4n98r6!*Shvm=H-3g&7O$u-8kH%M47@QBoRlCes!GDYdTk;# zxF*u1A`-uz&WIUO9yO2iR-WrQen}UUX`E%}9OeJKIp#q;P9>C9yI$LQ{L(x8%*lpp zFN;oJiK+u-Dmct+T~Kof-9Jn$xOwow`jOJtqeRh0NXL7VO7F$L2DII3(+V#p)+-lg zd5)_;&f+ga4-1UnvML^2=+ru|&@E&Q59bB=@%;Q#gDwg)WBsZ}CgOvZTS(Or_(=cD zu~H(>yy7jl_VO-=TeWyzs1QkvwHF{eV0@jqLuIHIA;&LS6fM7bqxoQY z>wykZq*bQhf>j)sHdNb zkhiw)89QWTJNr;3Iuk_l(-h_oV+j&se4>G|N}l?kEoP&2j;|H|I5B71ct^=hNkW$O(D3Y?i?s#ftlsgt$d0fkY1w z(R%+>(+8$NYXDf^Nn4o9#tQt1kpwQ8i!xCvxrw(z!yq9LV1_m>a09bEcLWTN&KBMn z#D&R)m$U+Mo91tXH>D&XpE^#6ETjvBH9NSuE9!Il&Qr6tPU`N-SZ(CO@bJGF$4yK%1A@)34y5@s-4~BKyClSJMp{-m)l%HP=jwD`xx5h!E+=c}>5LNuSvd#+ zFV~`SvSt{JjcdY%g4eNjHrzf;C}$8%Nz@kp!NytP!X8K1kB>f0Q?*JtUdidpU)Vas zNI^Lin!*%pXJ25$nvcCasu}TVq_$^pE22ub%r4jO6Ec*290d2ZSM*xPulP&{ywXz? zc6%wsqlN^0JRT9((AQJ_=FQQe;rT2J=W4`s&oH^<4(8W{kt-rt`bDK?r?E{mPj%5y z;g#OyJ}(f>OTAU_JK9Qc8A7W!%4Y%;gjh^;<9I+fG2?fh;tqED&xzvl*!{U#!q}{x zkP`glHCyt0>D)GK!T;~WE05%1a!x13NorxXRAYE+V30(WZtm77e#nm;4DD4m$l0kJ z_Har%@7`h{+;p{>2WSPuhH=?|a42onve4+c z+K5F@sQgC2+jn1cROI?YEm!@Dx?MDI9+&Ee0A$w)ul$J#lPkkNee`UtiGUU;XV6oO zr`xV2YVqtzK!Qum>w_&L+(kk_iCZaWQ1hA@6_fSQ2khisEW9yBAe;+`;gJ=E#S%e# zFM?z4>$cqb@eE@o85$RKzI)epEcNS+lUgq_GM4enV()a;%`Hw}n29~&G;#2aic#WA zY|m+sKXt!waX&_V)(^}q(a)nlml`Tahs*o9gO~wX!mR_?Q~eSpM7n;SDyIQX_Xo{+ zX{55oz`bA*- zyuy?*cUIKW;MjTHIFr#UZQp{so@c!E(zczQ-3^{DDfx1I<}7;}n~jRf_;U7RwvHP} zAph;}5byVYyN(mi>bL!V+wfGDwi4H6v6Dlkr^hpIIymbtH^}8`3#bjds1zvPwy4Q? zh5vG|2zs}b!KX-rw4i_ZJtJvstS~RW(L*Q9WUGo2os^fUoxMO==#LS1xyvw8# zypW<*))^LUSn4B4iaDsn8I~FiE>ru#B4PxXPuEH62u|Y;rGr3u4~g3$ylC-${kHi?T}sHCbk2 z!N=@k#YG+*8=8QSTR>9}K#V@9+y@Ev9*iadr^q3Qih48*oTi0zUqzF=Fhnw%5{IRn zsb}Wlhy^&-5AOcuEzU&%tr}0O!#`G)3Jqsfim`-Dt#wtEW>r@wA@91(M5r6ST(6$xw>t<*O1Jg&q$BZcrZfY?@0URb3VVwvH%C%%@+qyzJb zIPRnvfGliaqo{w<$TQujs~%)K4T3RJH-a-PiqgqvjGM9yuchR!bo5(I)wI!r*^Nti zZy?lpD0^K}ZVyJmAczF`j3EN3ron&CJX;I(84M-*JTV0a%r>ZW`e$+nr*DnZRwNKx zlHKnsclWb+#tA*#Bw=yuXqCE9X z<|d(`)=%9;Xr%~hqA*e1K z{`n&JfOy%G-|4h&;&P6Z>W6S4Ez4o8a3v2uJ@|xlP>*Ed$~@qP)Iy&GdtQJm5$kYm z%Ha+;8PZcMtrNqs!0>WCD5_!>NuDQ76c22itCli4X@ytZJVkFc8<{a~sxeh+30zxr zaP5eDlohPF1+rSYXVI|ns+J7JB#37eOsc~J z{iI!?al3QJ4WAuHseeDPGfa9eply+n0rxnG}lBt|RQVa>?vu-3hI(0hX`v8{LeSAXMJHjjM+ixr-91S#Fcl>_(#p|=X zFHV<1GkwJqXX`+!6)vI~zZGJVK9(L)oKJ14Gg}`rF1clD12|3|hT6@-nX+(_v>r{_ zhoT$Fw0OgGK~u;S6_`FVr~X;TTgQWkU_Y|&oQi=)Caa-Xit1LHwyVs>UB6HQu-Wp& z?h_kFFN$jh#Vq4a_i5kvnV1)6B$II$q~b69mNC9iNSR0QGPe41i;V7PUVNW;=hJ&e zqj}DTc>XbUBV0gvugm^2lk*RgT%L+Qx(i`&Xf!a5qa;KzKmzqM_?=6%E9C^BX`zX{ zOcJjG4=m39@D)3`4LD&(S6c(p>IuaH)LaisX6GuinE-4IbBhs~P1z+~t01*_QM?3! zFC(iT5Xk3Fle|y&T|ExWBz#H6r5J|2l#L)ZoyJ2#xdjDR+xI@T*8-|*0rkP$#xsBpFnd9QBLe5C>(MljG;6y6u~@D%5g%Ouu-OpNS-5_6ueDI zm!xIkcy)O7T^z0CGPA*%9+!0Diy{GjI7f#-xlAw>XK?E975~VQs?J^eTL*TWkrqvG zazVc&wGk8vb(-x=4{3LF*DoN;OqfM5_zujqI;Lf1$nc_EZ#KTdI!){`Q|h5qc6FnB zIF(nipXB7I2nV4o2h}Pk8hm`%!vvLMt57bMQ=z6&ZLd`BkhAP>Q01bG0x4zj3Z5pL z6W#51lHCojxV1ekLJQ3Ht1K6aqzb?UIx$aOu9d)x-qxzt8 z^`q$C#q)%-YL`MHpS^UdK1wXN3%`jk`2|(0b!ByAOH4G<4n37?igmn*cKO#7lkjo( zeioZ^GBn7gKCDUl-MC4Q!^w|W;fs6^Q>RO7uBH=y_jdlTDQ3RBpghY#4`#OjYt-o> z;z}G8#|jm{I%o&FDOXMATHcKtKW-vZrfMDPtXx~ub^+vH|IE6@N8<(fWIr#1Lw2h< z@>~#3pK3K&yoEVNYMgFccmCbfxC*y+ zLy5HJ*gk;#GMuV`?1w~li@JA7)~)wi#@3CtwZ`_ub!ekUihmt?+^cCFf$wcqIHSNA zv?x&&w=c*c7C8Imy<%AE)TxLMMpvtdFEdyg#Z7Yarll)9Am-P<{Nh*u1sKa>Axo zvi)fwDOY-**kB^wBWX5e`hfG3I7K4~T@A|om<)tAGvN(s{^sHtksIWT629;6|Ey{N zc@*zn5)*VwY@tf&#j;z)f?SVS5%D%OFiFWF^bB3C$g-wI6Fj7|Y!0&~idmPhGBsSQ z*4!OGpiV&K+)-;Wp+Q(1P8#Fl2q!M!qHlUZ7`~;pGqz5-yd|omKZkZq zOT%jJ+@(iw_RDuRT1>i!*;hGqw-dW;gS4)%;w5a#S9PWj4a?{XS;2?9&6GoMKb7tM z_Wf-8;|39qk7!t}`D32c{_R;hvo|!YM#=wq;w4IL)rrsfw%NP3sd;spD!pGAp;R@kpUMYwzDV?N7GwlY9}Wc zjWv1roKReg+W7*!=le?Yno)RBI61I!>iWPB+C_8jr~xK*-fzaJ^a4R7{aO3E;5X|Uj6HtLrNqQL#}u~OIN?Gn>SWBt6NBWW7rA%{s3;yg3e z2>U`r&s_WG*N^%mvjKikpxpHl06lN(Jbl2oNF!8;RNyWlZ|zrr9L%zJpdD0F7*4Z> zo_H!ZEUT0YYeo-_`+}KOrujTRv7LAxkrnM&*ln#Q^y`!9U~X~|GgLE|)s4w|8VL66 z(-cm-fw5c&zD&x|El!);uiz93p%tvi9V@0ND2=vyOnFP*4U1I!X=y4Ba?dmF&u%Py zG6;0}z+6$lE5OL$?XzmHwu`+SFD#nH1a9Js`%#dEGzrnPX={KEsv;+1;%k@o)m0|n zkz&0MK0+kQ%|z;wMr;x2&Qy`!cfZfdMu&R%Li6 z4lT410M-rH5T@V3ln?uX#@4lLUY*Ly?bx*+EMVvDFUIA{ilD+_-qJ&e3gPoYDnE4? zB66IRXj4hCxy$;(7ONI~n$UgGbQpYqh?f{~Z})cj9Fe$+SpNOj+y^ra-Z)hPF?~rC zNYQFLY0{+B-teUEtm_8X4dgDTCXA;e=U(0rA66|DsxU@IT6hHj12u&iw{fKwsgj|> z@!~`c9L1d&3{J9ju9rzLnWHc+gHaLu+JwP-Bc~RU1099C)OZ zHd52;met`$Zu2=jLvGSh{*yHphF7jgEpczBMQm)aF_x{aw~rp=Gm#oM1uV{$iN_i! z)tmBtI(41YN1|EiP?lE_FHEK@PNiWi^$hsCj8LMCVDP3q?HaQr zy?#VcO@kz8g8E6UasiU9WCe>gAkObBo^tqe*|O6S*J4fi*#PJ?FNt9w0${@g|I~_r z3kx(m&uRu7Is8hrs#1XN0s`tbcZfH&6uhYm0Ncq3KPkdx>%@%<04&6aNZj!3MZ}<; zzc@))j&v7jVy8>zxF+E`_0kE83`V2Ma}r161Y>=Ut@KOS)-iZCXiA>eJ+2oDVBaa8zxq?W6t`46*V=Q?OinpoSm&S~7?tf2`jb)e9UvhB@U|^O0OqQF@ltx7D zXx}xQp0wK#PJT$xw&BU;;^&`V|CZ`J`DQ@h3h>X|3z%xcA1KFIC4@_e<|fiFBL>qv z?EfB6irLFWXSJBzCB|vxZp}&$@%^SQ3?uT=g$lpIEcMxD}OymLFG(&f(83E zN1i2PLbtBm`ID+WGT#3V{Du>WRoAf@tl4qsKDJBv+cOQDmG#ovN zt+=vy+L!aghN>zlMBE;x%6)8Tx>53$_}8EOxxEnA_o1bWNP!z}>HSfJ=FENW#+{~) z{MYC^ck_0RSRQOp&N@g}PT{vP9UiJ-CoU`o73M?O?_ z7QAnj-cWPw5`OcIne}ZQH?;nyb8F0AAI zpDAX`OAH(!1d9=2QG|6Igl3cR932ehy66^7Oea^2R3Z(_7t@j*9kfViRDk4K#Hm+7 z`{PFdjUYz*m|Z_aZWLniTte;-oQ8sRJ^h;o`kRS>ZOy`oQc#NGD#rks-JzoT2CKNB z($rtI{s%|P6)beyh?{voH2h86QB~wml1tr#!MxxP@*A#h>yN!&g5?^3#>hlVZ8tk1 zR>Hr`BA-N~4AV$w!i`x+L z6qNi4Mw0*6@v{pG`6BW+3ADn*tZ<~^?`DuB^Nu5I^z|9cyRTT`rS)08^*K@agamyJ zM*EVuzM1-gZylnX6VM#~pf3Nx&EOp{!z_I9Lq|Cx>npxn8#(uFU(!z`-=PpFD=i%D zLpwuQi*|_aFa{Oz5*vp<1^<$(Z)Y@vr~}}Y5-4?9k|N*1H!mdB!Dk0yOaP210wapS zSWhqU6z`D?Q8X`fXbNUzHNJUL6{eF!$?V+t1xwt)9V6i0{igGZffA?S32v(Pa7j|m z28oKj`UXo&ml8Kvnx02euFCT2QRTWKfKh>-0Z7s>4ZRWJT7jXSKPZO%s2SxH&UAO zHVeba{J=CvQVa+dRBh6g{iG|#Ckl;k7C~sj#^fyI&GRNV8%+LUn(ALQJ<(+BnI(NQ z55^m>A@Ut9Sy6cvJaQeV0^{J=yi8_*hVsA+4wgJ4!4ZJ-tmBE+NTNJ~C<~|H;7k=<2vXr$yift?6@`6YJA zgRcz5Vyzec0>zz8x^Z&O%*GKi_sI$;2QU zzjMOwX}bN*Hir|}Z1wXUIG16hnQ&kQN^apI1pu)agaNBj)CH8XlG)7%;j}8r?Evvk zDUb&S#BK%)=79jcV-^p2~yYmEXt zMe@!-0mE3%At=cr+;bp`;;!Z7_NydzL_$@Z+i6U02UC0aW=V(z8^TzGZA>Ds%_Dir zO8HZN|FsLhxdUT@U=&FxMY{h2?nuzI5gO<`c4nW zE5Pzjswn?08RPOT(Ky&8#(HfXv*WE!Gei=bd`JuwWomXeA~H1^LKB(g<{>%E$mdZ} z=Oy>EH6y>p&+@fe_C(b4@@Py#WOZ%K?S`1ol98CENFqa$@>BL!9@h~R&Z918?b5kXW*^a7J9 z_(UE8He(8}lt(ZX5fr{+Zi)(H4a6)v)6%dv1Fk3xZdB9_stX(OsC-OOkO*<1=?4T!sgmS*h{Y&WZr9nU2M3Iw!;a1o0TARf`8b!>9%Wcdr`eyTYapx0i+Z2~mf*19rz>fjMSe52QjBn&?pi%0R%!9YDX84?q zA~Im7DkFW)W&oMdMrG+~XVWj{rhmUyaQjMLTBHQ?p*pSx!#fc0ydPpQizFo!RxmKM zOGOJcm|KhO9^XKEYs6!D%Zv_3Kp*(oB1CRUk|vGRoWIAkKpKgxGF6~VML7TELH>fe zzST1ZDliYBQcwe;yJlTJWy~|!R8w!ot&Ijw1VBCm z!wg09@@*)Gkjw*l*hG}k$x|m2(hL&vt1ASar~B-tKx$4D_?(KyoGjol@W4GJ@1 zxJ9eN@_O-{UJNJVHU)&0cDQ4fEJ+)r@#H0_3kXgQoI494%Hl{GQ0fLkRhGXMgZ7Rf zL1jY#PjQ|5LF`U2xU?9trX9;4B!|Ej^H7UT$$0bC1@r@;cCxKrnDLv5(j)hQstA2} zNDMnrbnT&4pY!$k_#4#;OG0iUI9%jr(AN{*dEdjjK^st{HRY7P^0%t}gOmKd8gVV? zo5?bD3HM)_!UqoDF+cL;;DOsr2H*0G<+1UUP83aLy>gD!LE>}Hb zQrbfU>9+DsVmlem1`Y0Q&yFZHPDHZ&HGGccPOfDGR2(F)jnvZQW^SM8Kv`EbqJ|{Oh{Z5`3$7&*QFNtB(eTyf}Y1@J^35 z?#Q~J$-pMfb{tu_x*TI7@2tY#NuXEm*5amIDIPva(WnGN7N@ z<-7m+v6F+FjqENRzp3glnVbi~+80qai=UGlvBGni6g6AKU^n*aL>!}9QvJEl1tk*? zPgI1!hm-xy-KzJyuKyC49)?4#M`}m;mKQxcVwGEU__m>yb==OO$K@hFFZ^HECG6{Zlgn_RBXDtRm6={M5IMT+~|@JMC3LYB_JXwcHGbI&-Zzbzj;ZTjA6q&=b-bH{O#Hfnoi@OXX@Da(@%h73ejlC8$cL z-ELMFilua_<1F|W3}JOxoISEdJJV@_^pfCSc1MYPTttpYaxQ7PrfP!-#Da)$JQiw& zD7j`pF0H3hd>V)EoH|y~ly!xo1X9YRiCJ+s`&BGa&)ZiB$HbmcA>;b}S2tL}-XeFC zd^}1wOccq&z-q(_DK-Uw6`GUpIVKFM3XM|1vx4`}8F7%Z6<0ehp?O4eU0I}Z;V`gsa( z2v|Fo$ze&WsHle+OZYkwehrDw!rPbB1FVia58uasrOJIi$gUXvafw=){YL%d=d^=( z4(IeR>Vzn43PceLudwn%m(IDnmlft*ciFoZ6I5BBdJPv6+(5nUd=u1|xAsHExoqQy zwP(Va^VJ3QYvNV{brBNRHKRS@^03CuglhePa1`(M=;uF2oS%P@P&oeLkkQWHt`d2X z8>1og$ZS>@vi1@!p9UC0ji1uWIxw%aj1?A6uId!5rB9M(OA)IEq|6>=e1(Ae$<;#7 z9BT?|_@7F%cVDvGK^P5t6kN=bIMr*V=TS9L95=-whN*ta!(I*MDi25X5qk1zahk{) zvaJB%`o6#9@WlhQt-f~*6fSW=bf7cDl;I^ae97fJEbk!CqCj*FNX>Q0*Hnw{6v->} z7GiK%nuak_idc~T0AwgDL*mUf3WM``?t+!bI9|oO4tA-l0xZ?l)XYN8nban$Bv*cz zzph|l!AGdUK%L4zC}!t=r}di7py0YPHB*kOtu0nHt@SZYfj!q6dqsJed{;y;EkU1X zawaW8Gc%cFojZF$*2>Q|#|<1#`jPoU==lkViD4#@)$d z(_O`FQdn_A+O9O_lG+AwSJYi3{f@UrgP2AqdROYsK=#k%wA&p~p9K1|5oXp-tz~sg zzxW{+nWy#Nr|K65>U?}1!?x*+O?+&IDLd#9}R-n+=jq0nPn#Rc82Ov zaYO`Ku56*TxOqFRwhdkE3NyTp-&VD06WJoT2}Y=KlbfdPC!4eZ>&(uxqaeyF zX~z$j>sW{EmLjg6rOZqkxFk{sRJb6S!pug(DUO0vAC+seU8hw$*;$W@tx5akasv+5 z#}RNgNh3RY)yR~g5UMiV!(qJe0bsw}dduaDBD;4qvfH1LXI(Eir}0-;cYOBW>MTWz z?)Fs8*(qkS7b|ED(?l(r*1pZ8#6UuPUgYZ=pVMQeIV60D--nx@N6t^5@6ZpK`f}@Y z@$<-|uhiMC&%|4|A|R|+<|r&iK21_iU1P;{k<_dBBD5M+li=vdP|5?6v-}6}7W{)f z_?`C(k5;#6;I?vYE3Z+p)k81A$)9Non)1S{bo$BK+4I@(cC>?pYfjD7*lsW z#;1eC)Y2?rrdNFC@(Rw%%eYefzTOt(@q=$5_RPg|$D&j}p_3<`cW3VxNW9L66XlwRE>(d#a-_VNQFCGQ4>2-wE1FRvw7wI$F*k=l z8FZW&xU_+EjqS||+ZI8x9IK1xFNNMMM&H)=89eK%l%`zckH2ku0zu-sA@>y8Y zK2ZQwtWcMuw28|Q6{Py#vP`Ip!g<-g5Nc+p>U~3)YuIKbS;oKBUG*RSXjU4g_ohh`oSrv);z;A?nk2SBTW zHF@c)|IG5mlczrX8GZQ8|KppBZ%^-UJul|EICL&4>Omt z&8h?`S&}wx;!<5uEpJpUy%kY7Yd0cQ5Hr1$cFVMqyqbK$cbGmX&Z85Oo13f7n-o)3 zcl~e6^1h-`e7jSNv(7wJZ!UK)$a*Qe_ZH5-7T|G{5R2m{%pB z9mS{;BU=KaZGo--|9zR$S3n2Pz6I}W7?9Zq4lD;N*9=m|W>=;mls6FODipH|!+b~3 zJWtyfqtaG0wz;2Jk%bv1a!Ggu3yq)(E@XW|Ffezi1Yvggv6=l75HInh8u8kl(mlV) zouSd4{lMUTb35)J^A$C$KiZ)iO-37jIBTBj=TPH?%mpJ@`aDP7;cP*1Ol&2f6EzzG zYQrKm<&e=1DAuB+izMPeiMKHR2iF*9+yyf^i?C-9t_28v9m?E+QGUYq3z2z725T)y zwiYUN_iXaI2vC^~TzzD>f}n+NGSr0`6w`VQbl|>dQXwY|t;xzg3zSfgDE_#*D3au( zMsyF-Y(5RJGgp^at9iD_aDUq>WuI(Qk7x;DV}5q8^xICx4$>DOU?T|EGBj}?mdGKuK!_wo z#AGUpj6ZpYC6I5BsI-K-ThmJwm8N12Pg}{e$Y|qQZpWjA^Rzfuj0~e2#khej zeyaLu4qIfYMtORKVI)m`pc*@=riIQ+9J&EE0Dpi(cFmy7eHdpT1R!s0WgkWcA{m%u zqS%d9t>!WQA_pKcAMO;yG$NXaV53r-1ksFGaX^&>v0B_ASJeLSU#;tJv-_Oxw{8kd z2zU4ut5XUX?rQ6}x2-Z!Ia>3(R=u3>9u?1>G$UjAK~*48vUnUwSmB#5g~DB-02nIT zNo3`ckT!#tK6PZi%^2>0Vk}9P5*0GDeF%l@X9j?WfnaBP|1 zUfN`6L;i{`&moRE<>xYjz_w#s>P=qAsR?C9@CH_Ud3Ecu9vp-=V6prkONm(;4-}BtNim3 zIhNY7RU_Fin8Q-1822B_gSkfT&dP%=E$LncjS{z5WXiym#r8Zw+UJurnmkbqe#m@8 z6gz3T=SYQ#L4T2J^lt4k9}YHGH(Mpg?L~Joxv5hp0o*WlE@*B?l5HejQe?_B9i@QP>U|c&e{4$&hM+`Di=jsethGd38`Oswe=bwIj$jx?hS<5x$ zvGf>i7z#1H#87sY})CIMkAE_f1G4^LmrsY4WJN|#Fr;+u7X5ftqhXrLB% z#x$k!nCBOZl;`I{=DwmBucX8jlDqSce9MJ=kB1W8Kq-eXH2n`i3@PxvYHv2t)xn?t zs>R%_g&U>{*=*D`DJ{}Q#lkrUfIr+p&e;p7*i_Vj`y(P0Ua){5g5YAaaM3L|@a1W$ zpd$-{;Dh7Uz6MQi!=3Hz8==t*fta*?*!LsJ*s}DRAqZPg4B*2zunbvgS0(E3v62d3 zB1IU9@P`tr-m*mx6-oe!DDR_1-pY{GAt9`8vAP(X;am7prTB+X;SUEfacsHxiIQuf zVyN~bFAdYZ!ji8=R6M*~@gp3v@-l;*3Z-np$hp7QoA4qNLF50rKy+j$tBkBxnMzEf z@{wCfM=$2oB~QgWCP=~Mz7B=$#^hW_ZYh2t3S9+o!4f~gUar7eMqtdZu=SVT-?n9l z$lhcvBS#ZCCwNiN_l2p`+26%rD}P~(Tu{-D6xKAk%a!lBVU5d|-H8`)$Wa+lX9RMnWY1bb!}^~@hB*i$&3;G}O{o%kJgx?Yy> ztr0o`qyL7{eFbRQK>1Upj)^SxR&+D zVrl!f`-nf#?_NZ`13)~7>xVasd*Qw{8aB#Z*t~H3i1+enHQ_7FXRey-55wq5^E3Tw z0I!)^O%V~-VU6q^?1s;+JNABNNKA|Miixp@P>gff9?wuyy@6jySRiCGWoafjZ4VxZ;U1Rr94u-^6VY{czurfno?}zW+%Z)!V z;PW}@p9hSjbSdgt)IS@eeV0dnTtKqUO23;Ky_D3(&7COWm_B%ZZ1bGy5$7=-Wex#l zU5B&{90=37;n*lE@P#|irk1QwDk!#d&Go+5-LmjB^D>7zvI0r~7_JG;Ak~n^WPj}c zylO_rhIZPiLDS6{p*AFL;NK*|5$BM>AG==@nq|V@#jy?#JWY?x+K_N^Qbjg(#do~2 z4dL15uH;bEitW_ZV@I5GU9M}UZpNz5Fa5tkx)`rMPLM9+#G}_vCJjPIDh63lYgEzf z-eq$P*=ER930`1RkC?;PdCLkr-w_c!AAZe3#`7L}(z5BHuabvS=>&c!OcrYC{Y-KF z0+!F*bg^KJBve)nUnF z7E87h$8HNP1>00woga#;dY3E0`#+Dw06bStV4$#B>MRRBg%YwT3modD)qq8KQeigN z&yQHy*{{cp1U`2XjAUoOn@$Wqn*N-hlDTD=Ut2YG2%R_&wnT(-V4vdkBpIusK$63s zLg)8?kHK=50zFF8wv#C?|9K?lN>52!KNHTAvwc>2Pt7u~Hgi>9d$9LXTVbkJVT}Tm zD(_I7+NS4JQZMe{QW}J?@(^(qh(1vv_wtM%IxWn}S(Y@e%z2;P%(X2h1=ci8PRxEa zwwvb`K1NXAIy8ASqp@pDpAp;E%D1?^bqJIF0nWey@2F9WhG=<;-T||?*!wDT+2SG_ znkEj&7a#syT@i!wCaqMeLsHmcP9kY52;TnB(6990gu+1SX-kCCz^rWv|1}MV5>>3Z zQ>mq`gRiLN+y(!N5kNf0o8dyrLj}$ql`q!Q#9J$7t$gphd&u=E6&CPANU?En<#T<3 z9dqAkd#$`~`jt=Ojxh{6hs-E?@1pt(Q5RuHEF>YgjNhEQ{p(_RP_idGisO-ZxOb!F z!=sOq(_bEcys@`w_$qv}A{XgYG8Bwk zfP%?p`RA$t7eSVH!Z~Wgf_v|O$;@W?%pmW{SS($J zt^R-XRvu!N`?yjKxSij86KiLvkNuF@k%d*nU*j=G9-VT?2F9v*FqxvO>!pH2*^0K< z2dL)wA6Z2@@-jwy3PG7$4Zvo9`w5C^2+64IOt*|z(w0L=slmMtgNMk$oP;7j8wuJN zCVT#=GyD57i|E;7>qFN{T%(+9Uz#dx02!sO`L1@}jtV)f8hF;$jm)zJ!l=0eubd`* z0hX@Fv*-$xd7`Uq8%Kk<--jNU^1jQqQNn0f2jAUy%wik0=KFkruWJx=n4gZb4PRg1 zKUJTR)^iON08e?BYM8-qA&@GTqXrY}%KTCqH@-8&Eqh(CB1=u_-O!I)ZhKdpU+TD} z3bz{KbV%}_-r!0S^2}&w{ROdR@*=i}$UO(QY*ygL@Kzt1*6b-b6ee2KT7w$$a>_a| ziy>9{Iz#I$__g{jSPX9Y^4(5_7w$^)6rP3#io}?^O%Z1VK1Wz$k zS{BKiL(UBeCc?^0;zanCG}*&mU7jtA&VwtDh60u4lQo4UEXZ=esZbH_X1A#rf_+g> zy$J2L=L@u_x_Dx%$Uv)S_Hd|D8ekZ?mvuvch{@jl!mGqPbYh{7WIm}m#p$vXn zDka4=RXOya!E&H`@KHJaz|A-ebyseC;pygVRt2N!7B&grIKcI4=t+WA&4;4PTjwj)~ITEi{}fm;X0)= zEc4U7-o(AB)$0(}NSruxBmbjEIh49g;EUnHrrLi-CVK>Cc6Q3I=97WZ#@Se!nE3!c8 zmK=#*;EaDo>h>`I#q;5fLv-PR{IyBL3b8l{gQ=Ikd$mA8BkHk!ouN5lZ!VRHLeZRl zl(?>384^2F9W?zHoa2_5Lg!i}a2W+%Z_#IR*>u_8DOjH>mm`hzo6+3uvvQqJ58L+l z&~8cyGCaQoV>*v>@A^^?{8aXQjE4py?V10CVy797udF>!@uf^AI2$KEMqPuuJyytH zcyoR90V8_Mt#2+>^N!{AKispPV=}tFfpDMRe^=mz3V3GKV()SjpA)R5X(%dhy3#&m z2ST|BaimRUtut2u zT-^Vr?)Qtx>oVV#0A#(R9|tt2eXnBsOs1ag|7Tfu>e}LowM^LGZ?C)RZlZ2}y(_@b zx~uXTvp?h-R8*vAKP;gm*OTgX-X&1=&Fxln&6eNfkBm(9)YAc-w=?zx6pv(D*qi3* zwCJX%UvMMGK>pzML4WfljclT~sC~)tClqEsp3;Ps2YU>Zz7xvBT5sNrjMMb*2OFr} z`(RqJ1N-}OIi)fDXT%kUEGA$;cQo*q?7!PN|F#_aSA*-r$;K~#uZ|wBzfI|KSaNa= z$d`=5)W(9{MSi2yCwK*AHXc%FX4y?(q>;ID6 z`D%jJ4;;bF1a7J6a7LqfhlH=EgP%oS`DS(7l)C{AnivP5cWTRZngrntZpdCw7K2~> zD4j{X!UgNyeHy+OwNOGR{OyE3vNv7AwY7IgTR@}IcMl=(@ws4h^^yI1{QEV#1*`kn zO(-A@wUHKVj`5(TgvWotD`?BGz{S#9-@I33M(2#nMBLoMmogMv|l9l)qs$ z&75$Osa1Kj)%EbTXC`&iji=NhGglx_b&-U($ozCSbMV=^7TD^hDg!RxG}N)0uax+j zFZ2fAOifqe4Z)~Me)ZqK9D{eGy98op3>ua7K?5S@^_&=6H0`8y5CHTCd@a^-C< zyMPG?P_@a^XRq-K-z*HE5IhNX9+_V_nmX$X%1&l*VUzO}h|ouN+;GZo2mvFtpCFDo zDH7qivY)=&dLOs{SkSrWXKN=L5&CmxSay0wNTdDNhX{PTw$Qk)*iOs-fYwyob-lGf z;ZLC=YB%K>o-Y*|p;)g$hEEII=O1A9wbdodQ^4T{EqL-LSXNJjAnnnZ!K;xLzmRy} z@Kk6HUOO@YdOut{nhb@g`Zi}O(-KwfztVAIp&z`SQ0B2U#Y)&RoGK3*sUlF&UxL*5 zg9ww2-TjUH%&$H!>-v?A;>D}~-Yo%$%`%&cN{9KMc>?T2v?5do0d0pIep65N)dvQk=h`+yRPBvT0R^EFGg2>Y`xE~77HybOyNB z{w%rA?{dQU^FWDq-ACo-f4MCsxGA4xLuZJ-3jaw_{Fc|#lwpMw*ic_}ZPQUK zuc6yDLq;j@JiTeQy`*I7mZlFo$7^YTB+IfBPI3_bj2B7re>m|Rn2@g)NiC{s~iG2A|&&;Xun-p@$1~4?`D$< zH%c1UeAJ>>xxi_2L>?Shj^NIRFZf#S+_h5Dw+cJ3>Wu7iKJ>Jt$t_&!$^EFHb5_`~ z@)`;!ylRs(9AI0cik#fJyQvx=nB6G{fQQo>aB$#=cRg$}-9jEN*J20zOdm*ReF`WzH z!F4;x>ngZLU5{lG`a8!F`ib)GzxD@WDcKYgl|dEWfpGgHKz{Q#IWo_1J!dCH z_2lS`b&VU&zhh^zLLes071esTqHFyF@!a_CoXNPd5RlT^t@g!UXL(wU< z(lS^>L5<(2uGtq^oublj{5+vg@U(q*W;Afpq08&pMD*O@SldpN->InrtMU}tSwG6_ z;5EH-BCo()(qVdNaf(-#C^lAKF7}*K?CpfW!soQF&8RUSmU1DID06~Diy!ke8+f*} znt29Stc(CAZ*<;Zerg}@OQC$B)OVWlMUR!l1b4?drcON8JFUv~#?Ntf>;ceG;IRrc z3CMiazOp0qKs1b4%6s-k*tcdTXUbI+R@T+JX;bf}STerw%vOeDxG(0|RSa>3cKD*P z?*mrqh1NLuR-K&)|5d_~nRkQZD|=^+rGxphVwOH#GI6MX=XPhBYGQa3YR!{1wH{Y1 z4L#&36W%a4kjzJkZ%@6qZ<5Y0m959Dp4Ph&Dbm4M>W9YLA{5iTnrHuwcolWrxc)y) zq5tXQk2b#kx%x8!C{zN%n?H%;xVP1KGm7!E#mu%LntpsDYh*6&Nqgnm;W}S3?d;#vpw9Gq+ zpwhCltzPIP*7zfJr<3x4@}gUg)*K@ry^qbdjdn$4jRRyfxx*d;TMTbkns#D`(5 ziq^xx7R+_ApU3KJC+$q~*9Jh`oUtRZhk=YqCP}fV|B||fhdYC3Z}U0*diUuZ=}+bI_lHU^&-zG3TY{wk;Ux;HE8Ll%6}*T}WW6Y6Tq?*&H}<6S1_;^o#_uSswyZf47BBk-DFVqu*M!5qFW z4kE$Jb9eqF0&%V;Fh}#2C3y&~vtnjKIE2(2kX`SbcNlN&q^~v+Xf&Uarp$N{9}&B1 zy?1kU^;zkSOhX|dbDULCL#Vs6L{Gk4)@o%7&I>i#t(&)2xo2ANUq-1gz);4qWJ8SY z=^;{YYnN1tKhT)QF5bHr`E>C-Ke5m=3lQaFE6z=X)vmdkG(hYEV2a~qvPayV3SV0G zPnJ?X1Zg?1ld8LKXOoA+kmJ!FkG+-ej+>o=T>u|%r@8qIN;?4=~P|EAnO zPs$8f+pPVnqmaP^DQA)41N=Af(N9tZV2@8}E_NxUasU&Dj#k}fVrRe)ZgZb&o9C(v z15MkBhbj9%O}jMO{hJJ1QXNJ0MR*#U^KO1vz5iA=`lTdA1$J=_BJ0KBCM+mV-@5$c z)YJ;86j5J=tlpN0F9wIngitr{0}l4ZSR4PxT>RnK62JYa`^Nt9_tyRARIebSjjM2^ zi=Nz6`x`j+kif_M`95Vo5ytv6&yT)>O~qVJOfNOfX#L(}o71W*cg8`)gOG2L6A|&j z;eM&r!hUI7aKu)jE@+nHk0%F1h*i4jlxGq`0#x$;Mr(RKy3ggn8VU&dP{hXItrC<@ zI~U9AcWan%j*{6fPRf>E_e55QJW+GO9LfG;;bD$<5%=(q+#E>}I9r9NffI^b|8kVw z{PCdNWBg(}7$6u5TjeKYjH&ln^jwg8pIRXu+w2Opby0P^>||;_6y=Y43jUC`3mO@F z$rCqu9@`+<$9$>4Lk=s&cIuXkR`xs9XevQw<8NW{_!p8YW*FFFL zY>At|e$+gO=HQ*Dz6Ng>S-n?bSY&2F@{3H;>^#Ot|HU;<5=gA8E9Lv;2enJuFgSN6ZwUxNr915 zin+DC(Go_v>?#R_(t*9+PtA;}Zq#5qC!=I)z0HfQO_W>yw19V2-jQ%i4tSmNV9t-8Xj+ zowHMY3sRA&wP+gf@`X@$EwfrvnW&|^(gC}Q)$M4fApuG~71)*6UXJn3!3L{Z(oQzk zP;B{=1Tm??39zECJiTIXWatjS#5+4LGp<)vTP&jsEu*Wu4{c(+kb2gxJ}%C&%q11$ znNsqPH;d=La&*&SV8+e$^vqMoQXJGHd2KCPK$??5!0`GrZ{a9EgsNWO(HWF|tEwL4i<1B25Ch`T@!3Ani zKI`lPoy|keE#FhHxCg>JxC4dhEv=xVB?;WIaGV-327+K;WaRaY= z{!I0i#j`Bq>m4A)41xify(k|`xF+H8GY716#wtV4Wy0H8ImoZsFfG$XYQRk`=+fhg zQH|;;@dD+IsoHBD@*ZfEqGz_-8~N0pA_PvxM2+T-*{p5JW9*qcUHMr}add!lLk;Ld zUkvQ#qfa`L4KvQ5r5kgxP}K5;SN~k|wy=qb)X3}XJC_zO{b9DZus=EMit&(})`@J1%o=)`jxy?t$>> z7kjg(q343G)aX!Z8!wJjckGb+%31h@69Fv=y`t$Wjdw{)RVZ3y*!o!I(NFgzq)bld z$GkBe{lPT~TsxAN2EdLPT66xVUM!1!L&kGwNCAJ}s)#u_`E;04gQ7Xu@qhk~RkOS^ z({Vw_(Kv`ZWj{HDCSewmVhx}-C(Fypp1Zwq*tnqc<;3h~+t-a3jxT(6S9UyqrMoo# zC69w%_2-3E*-BC))z_Q7*6j4n#YoqnV@-50r~lmCuvPlMN&Eh=frOJ_*{=x-0&gTo z65fIo`py*{Bp)08E_`*pPhUT%Ce=}ZTc;x+z(glz)tIkGAWhBj?zRtL+?2I{SWKgx>F? zmx3fDpPb&i{Pyv;f4LM8|3=feV?4eev)=xdeDTYbw{sh2?^gf3P4t{+IBojxa0M?p zMPb_Ax2-a`c>W&4BJo&w0e&yE#!ELjeP@V53W&Yg&|H*BYEe>m%ieMsw>vR&odJt~ zSThvfm@qmpbjndDl51HIBO#qcK(WnGGfg#(T%yzmpw?5M30=_s8NTTAd_-5^e!RcN zMgHha)NB_2{sqLnYRG;OAH&lgheQRH!&$<<;Qbj;I$SU}-l^OtHT@W9&ur~$Jl9VH zo@Av45P4-!c?7_d28HZQM83OF>YRVd=2FC9!rc$%5c;gOb!9q?o?y|Gq3G(bgm$C9 z5hQyG!+lWfrjPPJMa@6e5<8G>YRCi4|2L!5riYp{71p#Aj?oZq@Hb^E6Buw#Rt4T@ z)yWnN$=pp$YcXqWLNIW$sUT{S#BB}vv|JnyDit0tpEwU z!(W{BDxC7_{GAPO_B7noG=K?(gWB%&i<{n968w zapaxCL<3}!JYs0UY|h6=$O*3Cn#bUGl-)%jj*ANTV_7n4RKeG>m#j{??(y9=XcGRW zW|S^elfE+2OBqY2OoL~CaJmIB33o{{<^#zj3Af^%<_k)Hs~MPiv*%5djji z0rEPWb8&FtO-tn0b;8%lp46=qatJzvYZ~0X!ok16*<9ysD3MCKlDXmcnA70Q$Wnz0 zi7i_CQ!9PSqRWI}AMqdIIR}ZYQkFJWOIuDW4u@hjYJJw!*4EXIGt}-d)&6X(HBZ!u zv(@R)5)R5o28(Idr6VjG1(R)v070|CPl&oj9FQMZi}6vEf|)0V=cez5cZr2ufLM*3 zCrqV3+v+6@fmIsS`2*8qkBe{XO1Qo?$}%((_*rUecyue0q1+px&?(Juz%ZO7`Aa?K zpPR|AO1ibmP9#A@vJE_o>8E`e zP?H*-{tzCLpCMFrk2wV1FG~BpaPH8-NLyaPE=AB3qp@+xTm?oi}X{8Mai0 zoz5M*&U>~odnmT5b`ADeaUU`!PM;`BAWAs~ayePxjsc$`R9s<)y(Pt9`T&^11S5^WltI#`4fSFRypB8g*&DE~IO+2Zb)+#KGfCQtI%T!+gI43# z*eT6&Kb_RhtCQibOOh(hu{pf&{>8;kr_n>#+XGpNVjCd`B{Es^W)|zRgLs7dQ_;Fb zv$+JbH6mJ#zlv91V&s+UjtD#kt{-?t{Btk3bdB)r0%#V|YRY5~N zs3fgEmOP56ZBJE~#bQOMGWb%2GJX-)yoqN3w{e~@Ipr3Y)HL`?+9W+==CX^s5m=-T zOyDGjhMk`?{IsjUhkwBYmO9~y`k6YR?g&e*4a3f(z8$yBw?fZ143S6rg}5Z7Kkocx zJn--O=+82xpc!`0|Agz+*i-E^Y-U%92Bz-}kRiQJRO#a$@$U2giWJf0WNl8U`Xtz{ zD5e>Nhx(M>FZ`e@B1?bbk~k#P?G8R04o15Ldj>gw0T_0Zh3Jp{xQ6}okwS+aq%P>g zgPshfWq-_4X40EYw!a9go7eM(|JPgL6-3+a#(3TDB6`jC3R)fqI8ypa^-9V)DE zF;d?i5_~7@_F|Ckbw~LQV&xP?ODxxNO(5~1Wvyt=@W5PPzrTiSt`$lkwC{v!c~08I zWkUZ+4YAx{S*7xZAe|c!KGgY!Fb#c)r$Nzite|t=`j$@i8()8~2MJ7w{>GjEm*Y_V z-{}|qmJ6vV&gli*&Y0j5{hpp~%yFm&a*7LDe4%&U@05mZa9=jM=`4@jCYAbV6j_>jK&t1{qoxP9KnbaCFhX!M{x+%T9LBj0&-ZjF4T1!16)Vn-*%X8r9U?tsF zBRcu#pbmUW=W2d3(O~Y@DzX1+J9uduQL(~f2pP^jG={Yygl(Q4*+7_+g@XVD7u})B zVB6x<7uN$B*)>O-vM=s6D1Y|pKdKzS#ni|R(3pMz;W1d!&f~FJHh{PjX4Tc} z@8NxJ%wAIMA1Lkp0k-UXFDj-P{TVq%3i)O1>;bkU47*zbY}|y05hhN;zyqyJyp3YK&>+DvOP1&dj%$tL4OLv@6fd z)UMY%*(EU5RF7(PtLNGoF}298s7_slK?evAB!9M#Pe$(HsiYf+UAhkQ?i+5-9+3{A zLl$lRqVCjYQkZlpuYieD$@+ngeQ{k9p2Kr7WNaUVvhg;>TDEW^Y;fhP@n%ZqN;jmq zH}anfG(-F0_BmnMoWpeR8z;!7=Bb218$+v~7m8l!XN^?Sa?S z5Et*cNjyvxl^c1UJa4~=uxEQ!d1v4H;%hgw@T=6f*PT~hXQ?ERt?m$gO;d)`BUi+! zXd8QYq!_UthPHrPd_Oed^dW5AkoTSl0YCzDh2Q6{c}V8YyLL%8FJA|(?vNnI-NbgstJyCYCBMsBe6O&R|(lgq*TjmzPYi~ z-vqwl+|6r`^g_r2myIaXojK%Sh5Bo!?v?&^$HW~!0cAy%alC4RL`&tQgtl89ulX$` zEqvy7wQiOU_@*d&2?B(rd0Jz|siFO%HQ!G{F+PWkJ82moli&hlskx5W8yU|WW|beR zejWW@d1)XDFR3Lp4$RCi!&w%YZ93pcE?C%s_Y@yDxjd^fQl3S>mR<&O6b>^YW0OtN zwMyS-OO2k0lWO7Z7!Y-C4^p)KeP@(=lo#E1BqAJSR&Lc_$;oW+QGQFMBnC@zC4Lh9 z+;f2;RkKL*fFU$}>x zQ9`9@l%DlsE2Mn7e0sqJk}-Io!jwX;`UZ1u=vBS76jH3K<$}G1GZxLR5FuZopRAk1W~=zDj|v)4N4l#0JKE z!B_(f&q^XP5Tg&mjKpTF;7vh<(Fu!6@f8p%=|(y4BuK}OvW$r)`KluFHLMns^`cJw zDua1+nq;WzXF!uQLNo+sZZbKRGslh_*)a_#)=Y;itS}w8yM8(Fa*nX6zl$Xv7nyrrQ=fF4DEuYw5khR&*E$3D&bV+EM8Z1(gyF=*$ z)kE!Hw3$W971hN4BQd+UdUa-dkM*oO-$k1GT_}QC5UmMfF2-@Qtavk8XC;h!&hXs#DR%a^ETFv~A=`}N^>?TA0aCK0 zazwuRx54aM!W(R#qu zcy#qCPza}LK6SRfCwXlr^dtHh@2ry3*$%n>U&$>(X+WViFh3=pA9IC|63p9N$!AXh zwJ9K&k)V}$G(|&({lAJi))GIjj)u}YH1fVM$yFyntHf6C%fX(;F7h59uFPQ~rbPw; z5ZpagSWY;E1y)0uTM*hyaO8@DQi2aIc>T_$p*!s5g@p7q?0GdJY5D0b0td~Y zyCgnMB?V`FK1w)n#fFzFlAkM9l&N(D(4|A|lxC)Pr79?&_D3ad(dun9_G_5){y{W# zj`1LXKor0yxCX1(yKcN$*uO8@0P|%&|8QQDYM8 zBoweBRDkZFT{q)pD$f9qarFo?tN9Zz^ARX~T=9HImqGLpenJ=@)1UX~I*6UlL)@2) z`z}d+#edgZS=;@63MQ(Kps^{dhp@3ov9iG##0W|P!f0?77#?v24&XxrxZ&`A=teGd zLJvByw5J(qH&Y(ZXWmAiP~@K?!|=Y`{XbL2@gE=INvlGUDVl++ZSG!z%%KUAFhqSm0XIIS|5 zzwG@-`fOecO$t1I5uV85g7;zZTeX2T(0J0-JMk5^mvSAOKhhF?g?+_pU!CRiSK-H6 zt!*}7THl%XBrDNP=r#P53!o3X^IWHGi+cGmXXh~qyooOIl;A(CYj)U2?(AOamHZ1t zf8eKEgeaJ93QTwO5i!v2$X3;hJsEulOqIoh1}o#Syk0b`?>xD-D?7C`GBmY8E_+km zY8Z06|FzAhV-YebnbW_V`&HH#TgktLxNqVek~XT&j$%uHmdH8yKp-hH@ZiNvtI%v#c5(|sb$3o#A z7p|~@Ygj=zSjBw)LN@(3{AeVllw@r`wO!1PS7#zVq zp`bwmAehIbFENNH^E`q}Z|WxPC}2TFWLo{Dj`s1x7ijb*?5kE!;;t8SC%CM559gy! z0?R+!AqVZ`lAbjdaHV9f?>mB98?HOSe|KmdcPWz)V&3MbT;ZqW@(ZnlF#aItf8^;t zz!itBZBE=bsy{K5mv}dV`s56|Uk1%|-QKJ|i+rC(C>~V4btuB6AI~M4z?orjbBgii z;)3Z!OyL+w83IZr49+Uz@rK~5M9vwvgT1tyU?M$j?N&7QCPq&ZJW}FP_bfz5;;B`f zZRMo)4RNrQ_rm@NMN=#{XiXrq@5E72q2bk+(LKi-=5ykU$KAVq6^m`~I9tUlI%2t2 z7MiWIKAPgWqdcGZcO$h$vPJ^rdtyGV^y$9=X2@|4yBzuC_Pf9T>jC+{8FqFwFxK0| zTnz!vVAO;fR5^+A5$T1Y?%d#?Nd!8K?;ds8=CrXi6f_^x%+|Ul{?w|LS~nY_b=@&I z#ie;9NK?#V^Mb&YD<|t*C+i2ED)yeNt1uF7GK}w9RzzjiUElg0ZX^!jlf@>?MiUhf z{B;0kr>6>>eIa z_QdeUc<+S6QfRsYWG-TO${jMbkKYgg z*#hTY`12U7N6Hf6=3=m8oWI6gHO#kYz#ELnCa&m1pvWMx16d#c>krR_PHW~?Rplsx z&%6#%1S4&_uwWYfwvty(z^XLgWb~;jek_wFp@y~blS;c>p8oARo&CzA%+i(|`Km(o zW8CX%71){Y^Ba3}gLoZTt3tf|)NGez{UHH%+5TCgoY#}Nowb~CP|Vc)f`EZBuQ#zXU0Vn5|Sj@8A*~v zsnx}{bA%+dDwW#Sdk(T{)vB%5wram;f1f{ox0{TUowqUwiW0JPz%MNd*<^c1S(yp`p z9R)6&C}0OzUWj*sm_s^7r`5xGXFY9xG3;Y(fAC#(kJZ77f!%g?I=j}i*Fl4SYH8!Y z{w0}TaMsdmyM1VBWx@Q)FiXkt=!A*7IZ=9ng=UooR?00E$xI9861=HbqBF&Ps~uVx zR??C@ml;P_v@Rgzs_C6;IkW6`-6}sU4!M8H4uqePY#TR35C&DhZsy=Bf{PcgxH7%X z2Dej9B`!YD@JV*Uyn_xSCj8XU-^9k zFz|IT3$4w)HrGm1W9#ieym~?wG@jWGbSxyGT+m8Wx^T9W&X-e{(Rt^^_1W8l+}f-j z=>zO+Y)I!A%Rat)Osv%3x?@v;^w|^gf}oY$COg{453Lmu(zr$K`Ad)W z3(57h_No>(G_i!>@nEZ^BATLY^|4lE@xmQ1GAwXDM8&VJxl_kIcBDF=+9Pr z9Z7Y1Z@0tv;wh{ck$j&WO+y=>pNibPv#k08^%YC;O?Rv?+!Rk~kD8b7TD}%)i^sQ* ziFH%)7XhY&wYguYGp8~;gO`;cR?@tPOgc0*^5az9{n=)^89SE~LeuZ_g z-*(r6t`jk5<^=8yC=m$@#?+GeKgREcAP<^3>A^^!u>a_eqrzDRj7F(JbkTbwlUM zs^(4qhA+=q@nS&jy_xBfuetpE)bmHx2Mhv?I1&pD1mg|G3M*VO8~EHsM*Qvb6}n@- z-XZ~uU%c?Q57efm%F~&Pb32ry?cVBIQr*qDxDD32 z-Y|9OaZ@N>olQ_-16ulAg%MEY5pPve3_60U24h|@H%&_?5adllG>aW@P_87D@HQ%OYu^Z_L836j~qu@|K76;_-m6VY}Nz+67fN zHT+mulznOSqRktwD!PIb44T~f5XB9OUlYY}jiP8Fs*?Vi^8H=!+t83`Z3@QYvcpR5 zS!?NZa|c;*lWyuIn)4`%PYffU0~svg{smYS6;ML#dOHgB{*#vR2b?oBN$$TeFvYk- zNYmJ$IccK_bZdVv!}Eov`wxB9L6(`uf%5zJlUAMY|4_0ao*~?C=wFzuOm8)O?B1}t z$v;F_>Uir$bbKuZ*Ich@BG2{3TbS^w%~m+|?Zk}hiVT7}fnd6L!SI{~SIiU+{L7o09EqH>97A zTW#(O^3!{%9zO5k|3aXVl7}A1JO?!8c>zjSU1&x+^l$LtQ-O=|G^t}b(t>m$BzQk441&fbd)bM>CBy$*!e-vzPl z1EO2<@JHeGsQ@>14Gs4m z6V^DeHwUD$HE+r4UMz^u#!WF5pXsXme6zb$UqMF-h>@lh?!E5r%yx_99N&bXkZfwG z$C|A=<@w<#+chqVJJ^}#!iNr2(~#E`cTpPmYUl)2)qlY%ol1WD2zP@r>n0^%LpGmx zFx8S3#wDtX42}M;d!HZ24-?J(3{xQ$H$>2s(*f?!pf^`*!3D%L!%Uxgkd83vxEZ!# zBsKX1&)_OeYYl+%i1X83Dc>wi4f69N2L-63${iND)KJFsYvOedo$2YCf%N+H7F~4u z=~&9G!?upP1cFC`lKd%hJzdl0plK#+8pz}@vf`A5x^DA?g6QfJJNGjM_twL_kEFgq zK2=IFjj)kmHt58G?7*D^bki`SK8_8G`M4W&$d}u0n|+2V#A$s;34Xbvg-sRd<&nii ztJQsPcWvIXxPOCE)w%j?ZiHoN@#gjZAEIB~8}asQag0ChdWq)qAtys!Pcod0G}V*3 z^&~~s8AV;9DTknlBf2S=iu(kGhGg1DFxS(x4qRg>2UKy?Ge=cp3@qOaN!fr08@A<| zD`{{9SLGsImP0e<5XR4~-CdQ8zq9tEF?PY}*u6%U_N4GGNq z!!5pG=#%imlEuV+zBWb1V|BkW`f*Ha9g*Y@~0 zVi)Doy$!qHlB0Aab1fOmy?0(CscJ~-65_|1IR-u9Ol*T8m0&2PAaXkPUGtfp(!f%` z#ZWseE!HmU%mJAk#FnM?;v!)y!7wi5Ni+2@AR*%&m!vAagS(yvblERN(te<2m*2_0 zqr^sX{xa+Is|gJ;bFnC{?pfNkxPs1Q`z1a@KlofRz0IvM$aiOQmdl9e30mUisgHO556wyb|Bsbr zhkM%HMLrE{xNGKMwO8rI+~zgT{AKnRUnNxg+Lqs$1-8CWyUrGb)Tft4RV;U8g;+g= zx%o<`qvX9Utl;{HYR;9hzuo3#VR(yPyZA-I0#9)XAusaXVdI@m9pR&*8DZqn1~Wv%Er&)GLNV zINbo*oj&%!DX7BQF+8GlEbXfg{Z>+~>!DG^J)G^=JN`|%U!#U?sWEx4%q0j>0Km}d>fq=N<8tZiElbh;jLA?uE$%`WuKs;v&WXRfsmty7i1jvMjP z&nnDie(-1c!_Hw9`Hm5*IC+Tc%JMG6IrvCEB=%rDHLBNFCOn8-UOw7ed#Sk2RJw#$ zzm~ZK%O$_}r6JRi?0jhF^5CSEiLVO7qz-_^WLyk zNB!S9Ejg42TR9!HxWkPo?}`|j$7Hll&cxXq7r2eQXdNXd)&_ z3D88gZC~f65(m=R^Zj;jZNGW8i?m%;>R2@E8QZa&i8(^!A`0DtT>}*t`4(BhdKTN> z3RlR{h53=%d>yT08acK};bhQxmZhnJXA!p~-*CVC*3>~JWLS7`XM`M?mRYLx5=$fs zAEd~nx7>iOxJq}e*VrEN?orWZ-}9@h>$4oBc2@a;@uC+2Zm%1^>uUR#6QA`jxzIc( zU(u5GK)9M<=-}y0$uwlZ+gf!)pi2uTBOOb>#ZAj|pH47=(J+ExX0XO&VBc}H3kB?K zPp^t%-IIKazXa*^ zaRjVnmgZ^(^vfoqdRm&NZsPi8tt8dIN&kl1#Cp2&F$r$>Cn3IjtzC_5T~sImv9h&N z>lskZe8Nh+jio7@X|c$gY>afs8!BenQkNIHZIA#HsVr^BVhmDm+hsOzJ3E4FQ5&E; z<{KAH>l=zNO`hAkmtjc-jSEvYj!0ZiG{kuOEV{g)p=NdTs`T?!2lmGld*PbhoKewx zGS4Dq9T8_1t+2{uKm)D?h9R-VK+e-np*I0lC@c+0v`(cT0XGDmK6)d(Qxi%8l#jnr zmGgWDw(Zo;1d|~byYAL1rmqEo_`AQ{aw?xWqVm5BDDCsAidc1F5%Y}lS$X=CEZ>A5 zh`4b{=g=OWZ+0*dbam_+sODM}uPQFfkpLPuYt?{^qQZD)L*F)8vYU*Ganc{ws3`pP z#p9~d{-feklD}$hbtm81>v#H9)SB}n{;hTTJL*-0J882lBVx(gs`xcF+XJ$9ybg>-n^jJ{*Qa2>)wpNyEqS35hRqn zFE=fd3b@+i6&QlWlt*93T!2@7)#g@B(0x@aNEhNHx#=Y|ZI)*a==0cWp!~(L^&D1b z+A;;`H9KFg<&3y`9sqE5d7ABXlM%J zj0+;@u$C1COh#Q7>REidcWK-C&} zFTVzQ&Pn~040oEM2!hDHKd)(JJXd?-araFpUDGK@?_#`Z(mpRD_2{Xg1+C_3u|<0l zYfKnKf~>$ilb)qZ3ZT|un1i|Dwq1$>M)%}mLfUhYrRo5?E-mOF^V6)n=^Bo2MC8Gh z4z_t&d#IEoFlL}$;x}Os)=dXlx8Aq6Qtf#Lrl<;8RPimZ^%P^hD?4b2Zhi78@|EK2NzFy0zI_bhOIA<1>!!}L`yCr>XRS`!bk zN0I_JK}tKz7=IF^H|~vS66FzF*>Kllg5tBp_wS{o>(V6$V4SU=8K#2$&NA0ZhV|2U z#;?VjGIJgr|0n&zo1gN!Eph7%h~CZmid11`w~qoPxf5ZoG`Gg#W9)PkNlWj^oyy*( zj;O^&TPuR!tHSSUvWcZ^J3}uMb@~6gcC6@T^E^dgJ+_}zPq357oRC01;?FXMV(oVf zvx$NmVWE7ArhuZV!#i9fs_xU8bC_6fvu2p4DJ83}k<9luc2gNfIaBeP3Ar;3c|>Ph z!JL-L6<36&;(z`y&E$E_q&2$!@w!Em@K#qy3?9R4{PFRHWOW5W5l?WoBB+Z=CJo`Y z!4i#*poneL>`M-x#M7Ov6&ncZQlk0AsVy70+6^4vi`bzXUGbdyI+~4!VpeUAHjHOf zaG_+D3fo#&(~$@!u9m3N;nhp64AFR1A5$B_R@@*dnrW&U;+qXr#b*w*lx==O!ZlH0 zD;Da^HVhNgnM8Cmsr4k8S${6#0=cckoyu-g$K$QC4pV5jO|1mgP4cOW1Va+W(IqCm zqtE+VV%W(jA~A4rCfB#$ny;|5p)Ad7+Pxko=)f!vWKpxO!jbHqR3>1{wR=G`y=ACg zvkZe&4AQ51Pc&!Z6$#cFA4^jl3HO|#=peRyrQrIh8icQy!H%BkhIX>5muec}7~L^? zCd=GKG&k_ym5)}Ig8a-YWPUswiZaJD`){6Cc70Le^Bn{dY){~v^K@GMqUZh zB;iXY@MV2uQ$M-0L}^MQVyDuoa^=Hjf+~T4&Hf7AezlH-Ay9WRZM8V8E0F_ua?nVw zF_}xDPGo{yCgRLdPf>A&K46#t*uXWqa#b_4?^>8urA*a}xO6tjzK8nC zmvw45U)@91j8k!a7-*3TIj{gRYhE=C-EMFAcfqBNo}75!Kev!IyB!CPP;Nh*8I4<@ z$s*&1NrgCqZAoXbD}gjanx92fv{MvMHsShd=PuqhO|k%Y9kP@Qh6;@dTqu%-8>4hstJQnzEvU(Hc?KZe{rgUtZ3G)(YN-kCr#tr|P zbyQ7@H};d<7J_fu+P9tr%m`s_rE31R4r17$4s4?>2X^YibP_0u2M2SI&<(IZ`$KgF zgw4m}D(DcA?$<=Vhx(o!jgdOoc?VmBq?7O;}Xc00(Y)e$vmF(w^N>&`G&AAWf+R`Hgh?%$2eSf{C@LO705UWqy6XAQ9c zY>e$E8-{srx)`nBFL-R8_wnV1Ek)aIvGIoO0r#l?nj45?8B_CK6LD1}b&56i9isqg z>PZYHCV4G1Ut<{Q4AV3wTyQ`!0}bT#yw}0PE2mU%VBa`uLn7X-fyf>rX?{A)x*!Xb;2R9qFY|MINKDT-Q8 z#5K04>u7#cYzPA%IIvL{Izs0dov~aA+b~8_V+<7GDcFk*Fj;q&GC_sLn9M52bj36Z z?kgAECjdN{*wC$bGWy_ZfGHEN$!bx@TWi)jnGy(^2CNp82ZpgBI^8tFI`xEsyAKL5 z<*kCEs3WPHcpCTXR1@QeN?*wChB8+;=pD7S^Jd7IefX@Kp@aID{;m_rL{-ZEJnV69 zC;z7tCgIgOqB-rky8J)fM&we;axYTTR~p8yeT4Z>*leQvFnxcn}u-Q;J zGk;g$>kLM7FhkK#eV0NRt>-|oLNN2S`3lw{M>gv&tSiivo{#47|)y z4D8be74!^th~WxdG4mg$8C7z)Z&?7zLn~&UOX6xiP!pm^O-zzW7rdqiZ&>3wfw`Glf@xXPQtxcVBOimap4hc%h_w-8BD{IjZwq`pa3rxJ1HUrhxMRh8cl zR1i!Cx}xV#h|I$MD}a{%fQZ?ONvh%@&35RLF_DL%V-atv0qd-7Wnd5EyhJXfVwuP2 znn{w%KzwMjHpdVZm8M&9*5-KYl#67=2p7r{0-1ayiVH;X;XsxVhp9|dkSzdG)8@ug zuosHfy#h)TNIay4bqvLa$^Je)sq$A3@2DP)Tj;ey*5R&A>}u#MQIUu@=izZl`%N`O zm7Z*;_i&unO?{&bBU%~(U@QeCbKIp|mG6hJE5Q70R z13zP{gz78RNaoJ>XKAMCiY~g;#6?}W+E_lEet>*>`HV-u;kVOqOGG|_tAi@GNJGdc zmvjXt5;O?}RT(3Eadtx=+3k?V!Q zxxaV)5;ao`Hh^A|5ep5qC%0VDo2HVL5pvmQ^-s3imf%O-kd)#Oj}u|tI@rH7V7~b0 z!Ug4LQ|e=!qF;}leaFt6f8r52!$L;g`;9Ft=}5?FYQ@TiBlr=fInh&E8f>X;97|qm zL+=^Yw$2o6TjunH{BqxUm&)a*@Bj9}t*bNIT^1fV`geQpR`(MRmHzL{Q{TCqd)#E7 zJn25R_~iZDnIP*9mJH#&a`wIv-q$s@>gSn;HFN(%x~{#^2z*yzCv!hE^J%TIW-xiz zzOaA3h%O1&ce^hJNTYQuKlHSzqz)-hm2ok2Rl_7M*>=! zWOJZXQve?DwfrnAu*Ky#l5|N;@`91b7c%PRgZxFjfUDul_%H87gs}X2KQAiD?d^0w zY^m&mO1oJ6<-B~axAuBuC{sp&CvV!4a&cGeNVXo-xh0l=6GNKqI%Ahq*l(3DVvG(< z`jlF&Yw|7~?Tq)NE!az4MfWYexTNf~Pi$P3waRs8$*IN(@2Ys|-Yw4wcKaP-E1QpQ zTSrqRI2?@k$^wa-@(#Q)yeWK)muj1O0^0bZ*zGdBx zkr78`4fXpn5=0iNBlc$#m$U8Wj0YyHfL(*iZfORVFf89$_?9Ic^oa@B{4OWslea zqDGRd&Sd+x#lr}3Hwn?WSWkBgZ70_CKS-X_U3vy9QZQAm`eDI%*RvC=l9HA``*GoKR%p$tlJxMk z_ZI!;|LWx2X1P^qtHdI0IYC{;&&9+y-Ng=)=>uOE(8I>~r7YcaY!NHjwI{8QZ(F*C z3hJa5Nx4ka#}+^ELZ~Z^A=7GX^3ob5d726~_}Uh)?g9f;r`Vk_D@YL8AwY4STbB^S zE?YCtKWT?QU=AQ@RgT@l^TN80NV2xlJ)lO*(W(83st;0Y=5>K3@P+&?bZ#Imx4+xG0)ok#?8vyDYR$}z^e>w>`L-{iOKxB zNzB@$^DIc~;?>1$D0=6_>ojblplOcQ>Pp^!wkCBi7SOon5P)muebOw)!mBoUhBj_p z_A0X0N!iVM!DZuC5RpKaZbdmOqj@>$fxizQPw$9hT`R()sqMRLk#J(>AQYBhCF zpzAP_+ftpahY;RKe{2zyhCiVE_69T=pO@Uz9{+37x&^f#?byvs9agQNRnN6zCNq!$ zUox7Y%)9iNyCq9ago8sVNc^09&4948V>MxF+SNKOho&`o=MU&qB?@mmOYe*~4`T_L z6Rdb{Fj3VkwZ>iG*=8?4_&QaY*Q%%2aaSBf_@MRn5T30jvQVq`C}4I=a;-Mdz+#s` z=CIhWbQc}G=!w_Y+UZQ;q@7&HfR4*N+m5wGMIEkzOo`O^k2?W9wD*Gd&p$4_oIKn= zl&m8zBHXr{WgSt@dSX^(!|`})L!XW1#Ex}!#Pfx4m|LLwBFAE18762+Z*^=TYRu9+ zyAHa}HGl|+{wa7smUSr#S?Il^5pbHle_A@DE-qrCO%D2->d%Z4*JJF-`FQ1k)Kb5d zg0_40sM^JrKAR6g7v~pbjY<6!2{b5WwpA_2k01VKv36-uvgx`=ld@~En}q_e3ck1K z+``NKzg`V9f8(gd+2%!Vsg< z_F9x@vzEEZ&hD+p-s-=6RWH8e_2=eUQJ~&cG(b4pTG3-~#muFn2_6L1X#$a5L=)<*kQ4o}Fm z*CcSC1T{&t=ZR302+R;_ON2lU4`wseAJ~6P^WbbjLNp&v6e+x z3gc7N4sgE>@>~u~%8ajN=ztvkYy*C>F%HULlMHMS8(SqvuM}(){`N@-ZQud10w98g zA?_d|8%-B#lXyrNcSoxfrBRGWsn$lSpQ5>RXubv)a?6pH)?ZTRfH$|ZXg*9F7A$XN zftW-x#lf#7jaqTF1tMcHA5IXV6+Ea;3>8Sw4l&pv0{r>fTDGZ%f@0I4HxHz9XV>wN z2qB>4Y0D*`8k0GAun%^!&H>%INIVb5w#(r>Fi!@J$6=fN6ELmKNM##6xiEc}29tNa*_dKwV%=)*;d zxeYa9pht@6MQE!~8_b2%`9@C`!sWsm4iv$MoVi9!B8(M7VeHUst~Q+Ql+D5DeOOvU z^OXfz{Rz5Dfnm9J$_99E1KgLjX3BSFNuh_b*3@TVHDb701Y#+O&fk!1z7_UqM+(6T ze%&X`ztRpyiCVAhS#f#sOM}%^FBvx;%Rs26()oWrbiX(N6_o7^)VP z@-ej(R5G+eK7xsrF|0frE^5Iu)`+!@GN_pktJqMA;6o@k_ZlW;E)I|6z*cNvRXF0! z!L%^Y8xuO&Aa?)|GK12YhOaCj%?9`)1V78+ixTaa+-Q~?dn7=+O#4Cxn#9^`Qm{h; zRy~C}rS0WHZIqzx8XwY#!m9)@rklT@x16UOzVc7|HQp$ltultKdgA`@g?q)%vX3|2 zO-Urva|UY5gS_jpnfyRM&FFjB@RQ_C95#zv5^s_GIOA4J`@-Y70RJ$8TwYH z?UW*e5@bluWJ=H;3ED13Oj5X0%Et~!D}`{c6#GK^Bu5&Bs{~GnMueryfD!>(%J_7A z>-|gXtiMmz-dXnKT=K0sacPhD0bfaPqM3?mredhfG)Pyxv{5wDjCi`yg@?xQfi*Cs z=k#Ro!4@gJ4?BHfV;E!D=_M2rxg(4Z1g!>q_;4f_o3!C{4oak3bJ+mh-t_rDnOLjZ z3w78S-voj8rBQ4d{6uQ}HNtp9%3P8MbV^_>&(kAzrAv|9MDRxviz|leg@Bq5Ys4L! z$VNE@IJ=kr1GbY3^1#|0&hCrum{d$~paojPB*lD_s(FHy8`3pnRP`_xP~K`R5Ta3R zFrGEnN2ooj_$`&Ide7EkN}_K9;LbAo@?h-5Xo}gG#KM+4ZS=pmX}W5Jri*9b#^^Y# zGMvf8L~hD}7c#g~8}a5r z2_odrX867YJsSe_OOg9h_?pZ(Bt=K0kU?gAZ-b26fS;x4$w2Lh4fxCpsS=@&_jrZA z#BNmV&4qQJ_s$5>4$-y6QkZn$n*TQM;Q8KR_sm^%$d-x9nVR=h(`$@~ToGu?MpJl@ z-E|;aw16r?j7N}iskToFRq`;a78;Qc5Lq~LuHh}se1m2{+q4M+xKIEjf7V^&ft!5i z*YN?p1b!(1rewy;8Q3yqd?vG;r^mZ2G;nCi$!hsox8rZ!HX-N#1@1aJx;susc<8jRoG zGFA(~}xUx^gn^@1Jjc`S}a(B*^7rLY`@u zqNt*oztYT8A7L*J;?2bPI8eJJ)_#xnz@Ecj7HM0AK+!E^DgB&+q^aHE;zYw7a7WlpV8C8BPRtgSC&?hqOh)g>q-JL9h9!0~$(l>jq7;nmu z3Awg~4kOMBGs{rSGQgqbwjp2XCYEX zT|Zt`d{{BS!j@$;hP!&{@%g19_)G;5!9ml9&`g1Gcd${;z+y5We~X6{}&cNPYa*=Rw1S>v44!npqDHMgbMo zkD!TmsarSj}b4=6aRkE7?Xgm7& zt~+C&vixT~=(Br&FZJp&<@$MBj$EDol5^wN`0b{Jdp;H7#)6+`^`%XP;0!*A@G`3Yt~c*aN%$Cl_KN zywJV>9`5}wg!i9Z*w;Q^bYpyvT|rpm!(PrS&Bc6A+b2c&w!2gAC%225qnEigz23fH z-JweFzf%u;J3ssVapyVw;n?P*cRz~PE3(`~eFwH)TM}63*T8GK^o#Z9KlWYUm~r6T z@s1a}umA5b|Ch}VzwBN7zYE8Tx`!rqU47AVZ2o!kW?`aZecFkhcU_q^1@BrCL=Jl! zwpEP-&OS#I%bK@bxE&%t$?8d}?(t`ldT-Bv;2d`U(n_Dz9Qqi*4`C+^4K88bI_n-Q zc=@WdSd5Q!Nj~1wW=IkT?rljCZH7EmJcmWGzSLYdoG-ino$vaJ(`D6B>{-vOLKw5k zyuvH3&Z;7~FAomyuMI+{_uFiFW=^j;U~-uAPk9k0s>Sl!mPe*K#61^W~F z%I(fF19)AH{oimbU%9TTNCbbP9B&Az+$wG;YfP*zINp>j2|OOPh423=@EiKA(wP-! z^7GQy9t&tISC=O^3Ky~R-i6rmyU>UYCkYQrvTJ{PHj{DUw%g6!HV2+fW=et_KV;W( zj$cWaZdv&xwdRZ#%j$Grt^T!hTwA=Uy7%2Vg184Rhq(c-s6?wLjG z09K0KH_W^*hZELxVQ-Xvj)stdbI1Ri8E*6CuZ)csMQ3)bWse1qtBzO!(x~$K2U+Ul zi7QLsm04HwHVW{fhP0aT2bbnn6ofq4b_`4922_lTG80b_NOjv!Bpy$8XWqY>y{h8$ z*$Rxycuz8`doKf>SrQcSn{-yn7OJ+>=WwSk-Lf&G1h|&liVIK->=^-OGSNW3pZMlvLWu^&{?Ny7$j_;h9e|uWu>Y>~GF+ z51-y~ocW3q@XrmmKg6@@THng8h_!6Uybi;{I`=U9g%651Q?Y!Lwc$tMCQxyx?S@BS z$6a3hbn>CH3O8%@3HC_GR@%-&*Ph;=guX-TiK^$$)+R)(tB;~uCTMP}{<87=u>Y`j zcu^4U7x5`&0zFua-ia1S$Ogs&`Oc7YG&0X zMHV8}$}O%x3;*cYSPX>!^E{$o;$9Q2FN^tvPr54}by!=(N_WX8p62M1d-gebV|}2yMc}swA?0+NIe?Dsai}& z3vS|d_HLvgh4WWVJrHloNG?a)7d9}fS-L!GiRuHUK;;NgThKq`%)+o!SNE(+u(LX_ zXF;c5cN4k8co(F#3F`DK zNe{%zu8AFFt-q&!XM$^iYoFwl$65-UJ@2_;STwpn=M3w)7v6kF?ZbiEIQy3z-oF{w&!OiZgp_QH?Mz;y{4>j*Y70G&TqWJ>ug`&<929n0q(XaaPVsL zgG`58rc(Z7oVv)Z#tW}#;MDDZP^=Af%)@PDpcMffS4!OjT3fH!-dIb88vj1)~iQ^Fa0D@O` zH(nN4bVN|l3YYGI9|fa|#NrW`?SUN+1$C}V3d;&z@i?qac{8})bTw27)Rej7mebuZ$iWyy1_gWH9(l-mxq)w$tgdWC+f^#>8IqjlCfzAlAQq8OH1YIX`i zQgqzoH5u;a;4Def?U%dke;~|6-7Sb)U0CMn6!0;FAAha2sPV}|ivE#!mQNDZO>G+> z&lA;+#ZrKno412U#1pt!zp5wZmw#~ymP>nRJ@rSrPgMa;#mafPtk!`vNr1Yef02(E^6p4}09)D{j^pPO+mKSo~r zVcUh{t)C@+nks&3)Oy;=(z)xI{crkHwjP60+^wgtOCO;T$N8r_B@q{*8u7`o#$0^0R^i z+XN4E^O?u(Q63f237`#_M~1I;I)`Y4V9kyJY*QY^J@i7TP0d3KF!e_UeOlS)D@Hb8 zlcB&EPKTl-#xx<+`yE=qGT*#z%#muFg;c2&u9clt`oJ$_zz}yw0jA{%NK7F*?F5a; zcZ5m6%2FWvGF*Wne#Kgy6!|nqJ0u5RNHN)Qtc+}I5o=9CG>{9#3&v--29HM5$N8|H zcyX=$nceoIiyYi^3^2YJ%HYA$U!WeQsxQ)jL}5yz=mFLz zIw%J|$RNGIUyn(>;y{NpaIXyQNi$A5!i^%RMgrFKgr$qnOm1d<2_{Jy@99h#VK9#bO|p-|+dbQ1>>pMuuH1%~zpu z=7V-Zsg30Ta)xF`oalb+^t{EJt;9ghAn?c)9kT&m$S+L_;9B{I90^p&*G7+l3G0wd zzBYz$Y!zbjHmnm7BC$jxOPNF3wbV_!#Qu^0`~|k|umuy%Zh=$zaIzS#5rJ*th?)b- zli*4T+RX(*h1m207wX@&=`^1z~@k7?ams|l*_z|dL170%t zv+P2!#Mp5JyvEnYNzZUob^$MhNT&F1gbbMepq(m*X5^6JCip}ORq;SBUHyWt z{))LB`DuM3k_B(8Mrh~mw>e_F$^p;04&^@re#GHj+za~B%*(*Fi;OvZh% z$vEjVzflNOh>?8~pie@II0jca0qy*WXb5>>15G+1pOzyxc~;nMP|U_k6)+>M;Xb=5 zkq;UUAvZ4F}NzaV#eVq`k5`tMg z)SZR<-2>4J(1u&kO>z7GtY8DL;R#2(ZUGo2v}B0TKDibfS=&X%DhWKflq5|9CS-L6 zQA&&mh!ggO$$%~?)GIS$hYe#AAV&ym_<)@V`7D1@XM;U)h=vJ7u#FqIhCwVmM^*RI zY1sOiCj~|%EBz&CiB>yl1w7#_yuktM$rwz~^Ht=UJ{FvHEa3aK+Ae`Ml#8s}4Mho{ zaFzzEp?%D{6DI~bJ|NGv;LiliTm~=ue{7xkH`I$C|BZc_-RzqgWXryVq#1j*Yzav- z_AS|x-0IHQvqg4E#+D=@NmAD^mLwsSTyH7~j&YPL@em$O> zHp3jnDvVn5Dhlw0z#SoQ zLy+{ZVCDo4^qs<8qa-pFI3aREg1qrdFtZD2fdvcoO*pv(#s-B}juYNcVvXQ=>*BPR z^4&G^oJQHQAwBfJ=ei_hxHt^RpKV*a2y#J{q0lrFWd;E-AAwgFvBF#icgCDGe-PA< z7oNk?m}rJK8gOSb0*JgRGHZgkrKkX!Af}~|HR%-IIE6Mv!KqPbtEr56(k%)uu?5Ge zA>n~UDZnq-FgjnZW(3OXpa`EJfxn1w9Y^m1v(y0Y15Ubt@N-+G>em!)(EXSF&2>H zP^rgJcjS3V2y$g$@x}QD~4Ej6MVa zBN)TSV`Pp1jHL!tQve_cYQhTbQLB7Zs&veFGSP?ZJYSfQSX-omq8P3m(vS2rBM!V5qU!-);NJ{i)I-^>77uHD-q<4qeWr3mjY<>cmUah zCzg4|3RG)y^KK*KW@9}a8eU&XJnZ&zF!dwgw;7!$N1`spt zlwq?WLQ9OWans)Dn&L$THJBLS9RvRNIK~K?J^>R!GV=n!D@FOYrma+o511rBO#!41 z-Uf+#(;0YljBz5X70=B;QRe_@N4Bq1cGnurl_UlBlYug`fG#2^4*g$<0gU2AVa;T> zK)x`LJ)04R@}gi~m?*Gq$#tzLhE->fwJfxubM%_~$?hv+suj%O4DRL00TTO4UumIV5kbl8QM zv;P)jnbJtb3!k)=RFXi~)0yMaK#IMlOSTV)vve@e?(&3!!L?s zQ_Rp@se_yt48y6HTT3L$6@Tef;Jh1N`pE%xVHf}nPfg7+q=2SLv>GDt4MwZN0WScY z?dVtM*qtIZ7eUKfRl@r`4xA29xePaaTPLPZJiZWxq4c0)JoxcUqR0=wYdOMw&5J) zn>?#>apXVN4&6iBMDqbIXxAf`t=T}=M zqYYlJ?fFq@_WQztx7tU=?h1A;{Y754Ge|Fg5@t+jj_1V`FjT8N`U(mlS{2l>ec{aN6G)Q5nF%ABu1={)u^(cxF^>tJ2)wZ@xz>|WNLeOg05 z&iB6xH@kM}`oiw_A7}3$bCyUxu2JN2)8l4_l0@!EgaHOT^!(%ej&Rc-X7?a=N#Vl7 ztLtT?ypHD)8i$AZvK8h_AvdN}^v3c%Q0%+9S; zLDa|LRBkjM!-S~M{&_oc^><%;%U)ElZcqUi*_Qi<8+Hg>uwtgK$S|2OwEJ-gH(dC> zIhrsOn;TZX*lrPeWto-5!j88WgkQ;IJy5tB`ugjIYu6{2!%OOU;--)V7Tg-9UB~3u}W*8$qp6#0*|v?v;13%Nq)r zLV+)WUx71`>t}cGyJYoVWN(&mqd+lhVK@J@f|ThKg4YG|@G z6fdcs&mvqu`!bj~{CX=MBetm#$+JVWMwB(|R{NBMY|aFftGaccs8Dgs3aMyvD-OYg z6qdg$34VObhkxX546j6Jk%wMMlqd_%FC2>y5kb`1HLT`x`3Va4?On&vHa-_(s)u+n z!S|ML)aG32+}t={{Z2UJhp1zJw}L4aBrC|wdv`hJrZ6w4Ll+rWEXbL9lcDCw_Lp%L zDiz!Dr0d~tI^6zI3m+o07+=+hcl9n?nyd*$HLx7qN+pV-SePN7 zN8z`Yb`!%%l7*Lp0C<`9r?pYbA?_|X@#fMU#6K0yB-^d*z_Nzdp%LVF69 z;&H+JfO=k{ft~Ie#cJ_XZu_*U_t$>sL!ns=$giF>`sfI+Eo;%ka$Ey!K*s zz%5Klg`WWHuWCweEE1J`DKLTcejBABuTLt9hS#ql-X_@jSiytx+Dm~s-5!kPL_ltP zn*LDC7{SWVpBtBLmO1fVA+RkZSC6SR$h?98MbX3>*P)yVp!RlJA(NAMAoDYUxDa%{ z8fY@g3|k-t7KC)WJ(Cz>kKwIQ{yCGyro%Oxl)ALQJX)ouZPDr2gi8J>xTxJVQf zG-4`A=aVIQ?1RYeO`=jS(BeFQP|AFqG|-X+7514*nLMjX)eOuj%rMQ&+NPv-p9FKy z>1Kv~O|@D)4HnkuNYntHx|l=R!cn_S+$?&&;FugJLR-TACQek~DJ`@pdd6PBr_v)X z&0J7x7PBlb!US7qXSZdD^x&1OkLNP-wIoI!6Rpw`VR{9+85?gYfwL*ble4L--rcwX zdQj%_Hc?E?QA&hQOcn8z6`km0S_w|)Ustx1eBn+J+fIIn7~A(WYY4YM4YY4oK5Hw| zg%^9g_XTfM*M{1Ln6L54=K87+>24BJt%Cr7vv+XgG0JkzUlx&JHE42|FyI*mn5WV+ zlKvI9YIFVDjn1_Ga{r#!`rBiFCmCu>@Vbve=lzc5#je{tzJFAE*^ifGY0JEe4dDCc zo=q|tPI`;0V_%{p=KF_}1o(){?YVW{wEiY%Sz4AsIz06lgRUlByK(+9Xw7`a`>TRj zaU8%G?d@XbNr6ET?Z}q~l5Ilt{6%v}%tXa}Rc?_6lsA?^^CO;qMnL`WOf%jd) zh=~g1XmJ;8HU`}Tx>81cnELYoK!Q0p6>-1=Ve-b%w;)-Ax*rk2{1ppNQ+Ek#6gu7 znKfJeIawEAj269&f=$X8JQm7mHq0=&yH6}EAy3$%E54C~>=*dUa&*;g3L53PKXo$O z%~h-m>WE6yXP`xuKsoSA@T;9uR_*0lDkIPFfkDxbx+v{T_&;O;`}D=h{n4>s>1XAM ziY=szx1H6dqf#}!E*6?=NuKQ`Srwmq&zm|h)by9)8lNerXBCmYk&8*$aY=8>f^k+H zWq3~N<87trjHKUWu{;l`aK+Ttq06T9ZI+gT|EOv5>iO4pHp823uSMg6CC|5&b>lOA7 z)X`kGguON^LzsC%FkmiKO;4(V^NI~G3e)b|W<4X+or}-ow&@L;+(Idd_+`@)^fN^k zNC#TtAybgIc53s4x-eKiS6fAVq=LXWd}Wc6)OP=$d-?&3VR^CF4Rk-h#7cC=o6-aa zhD~E;JG#BI+s_-?lBsZzxssS50hZF_2Ye<}(_QOTGRr?G)>V~(Z)hH{U)h~d!UgAm zqI5D`3z31k?y^%s(W+{r*!duP8H6R0x(#PBLqN?zto&GRD<0U>r5VGyl4u4K6EcG5 zwvw6%xPJaI?$|Z%BfN+?nV}_4)BSoX!X_{2o0ZEqT~|Za7=c$0yqN(H4yQw>M97Xa zhSoV*C|(SXb`A(a;uy(5U<%9fmg`HCW+zM0fzqB9S$csSvs;#-M&^!^Sj{9*AD&iE z;Ehlia|)c*Mpk8Mb}d@yg=R%zIk{G8rGvC83{Mdyq{;*Lc~EsBt)9&5C(v@SjPh)n zw>(4R5U7;EYP-w3faOJ?bHoXUlK$XU;e>24?i6791M++2PVHZhL zd|zG~a8%8H!kMEe5U~~VNh&gc8z={`gs_$=3;~5TPZXvB%0H0$!~txsp$7}t zqhvbZ%yJ;@_+Qg3kbu+akQ0nSX@Ek$!goPv$sJ|Q3MB?yIgKq7iT|jdy z0fdTYn~*`If4M3I$%3Ou6;gV_JA^GX)l?}^IYNKGVx6Husv-phc$&tDyfz|tQkFMQ zVa)jP`f(0HIMIKRX(#}6BB-tMv{D2eh+-wlQeXZz^dmA4_<$g+7y`>o0l4cT zL}7i!=qjG&j{eUm+Dc^E1704YHCr>i4J!;oF)*0179y{hNZWFx&Hv45RA5aH3Ij00 zQes__8mEsS>>xP>3^Bq8ptW(v1VLC{X@Eps>mj*r90g$`2bn5D}-jaEvFPh8Z2&JD1K3i8F&M5riUz>t0)lRU9J>PxN=5+rP3qi+ zkPZU@^a1$EiWpvuJg4^~XNJoV_SVkX;s|=^EA-G{cLJi4sKs}}ql&Y|- z83NZF3z{RIwpOZ_#Bu2u+JFts0>xlr;XR~7qQr)u05tWnrbf$e<`B z$4p)bN7Ve57tW%Ew!eUH6~U!OXjSTXpc{%u?Y+Zd5|@qa~Z=(dQEF1#%&O} zJWtkkV0aQxDFXbA1zemKVfhqPbC}oD*0e3CQstV&&o+hUvy46k1aq zuNq79C-9n#gx*-L3RoyB-{6nr>LOSK9BW&Fx0s4*&DoCqUB=>2e6XGiLsu= zyaMBymzz#21SF^jmMM7LH8UtvZd#1;ezNXIn_Y?ko&ysoPs0GwMMffl%SLlG3^yEZBd6(G2JZWbPEDy@_gT<*1vbLcZcmo}Q6(bcB_N z2W-V0KaA8Ag2Ouy)J8e{bpuE{(h2}#PU0oOnS2bd3vg&6gq}Dd22wK)WdLBPk*Hmb zuQ;)vR!dNPe$n$0fmi9vyHUmkB$Iv$U}JBn#EUldb6xQO2wszAGd9S)4k8yoz||Di zH~0dZfSo3m%_?vgiQUihSWuuP9#73ZD^e4-dJ)Ak^=K&2H~Fl1*CaxTN?;9<7>yY` zPaq;K527OHzfU2;u{RKn)@|NfTM~nAYzEWy8n9M&g}KGURD8Ukc&Lv zR_5x;b1hLUSF|t$Q^v=0Z`5#fVT=q%iBSSq0}j%~fZ707sKBbnf~ayl+4j_IJnd;S zw+X`#MF<__SswM}YB>FX9)P*u1>?D+3V?`3%O+$dkz{YXaHpsxt$1ENKG}=KE5?tm zk{kdB{Y!Lr3xT_#KT05l zfk>rUvRu1^jLEPRC4^dnyB;CmR&g?HIzkVZWl3`lUHC2`w&x&K`Q7u$jjze&lxLaG zw|l?-QK@kF^8478&j-!P`PZ!~rq|BwpS&b5_INcqxl&;QZR(ByXIRqU_R0j2U+VOl z7By=#GC0%v$V8YSQsm$LW!2&FrXTrh33U_Cq&zC7ekS%EAGZT!u(vU$^Db`SkbUG! zBUWz9pJ~i0OYm~MPuoZ!u;dk*^8J7cz;>o1PWv8!-aF1654pSh%YRxMGZ%g4SWEu5 z^M45#h!9|<#*k*;YwC9|^{=bXRuayxuU|iU>(yG~AIBfPJJY+KxO2{5HMH#MyF{~J z{(pJgeDmp>*@YAP?4&+^`w7JI;+QsSr^;=r#C_=Lg#q3SiF2rsAoW*Ztyj{7#qP7QkJfrMueeBeu7)EVHAg2)S;a1 z{21v}?s$3Xtj3|saTT<^g)55>+@^D53FI`DpO5v&o->Y1KW$gGg1HoO9gn?2+&z69 z_4)33vzIa3PDdsrVo!);ByyogCyty`MU}W+MY`MRy&=;^rt1rw9=it{sg1g~wAvv? zK03y~k#<8tktz@$QHE|_UHH*6x8(i2HpkAM|0f-FhU}ZJd6HmT)FpFbd}2|}3q8mQ z)+}prqD3t=VpmXs@?-Y9;Dd~=lI99sEi@#ka zaX-p;-auvV*}y&8XQ@Tg75k!()eq`BjN+}E?4Rt@Ftb@Eesr)GQ%!&CgF&D5@|f~t>CoZ3D0k3-g3qRurTe3X%b!Y4*>9r%N=Ci|@j@mn;`v4Vr+TN> zi^r~f`msG$?ch<*)o?5_e?_i)Px{yD`AlKd3!|qoY2=Jjn;UWdI2Br!?zN2poRv5; z7sS>X+<1g-eK99@CUI{%^G4`Ngz$#3VDs;~)5vfiP4g*3MZV)?n%$gLH%hjn)DMB` zzqocWwD`?bQ=vmd9AS@PV@VkhkgQFY{3`+1KA6>kNtr%owEP!hcBkheLeuZTnJDe_ zzuRzP(gC@gV*MfJQ+%Cn2)MmezfNQnucW9Cj?L9O@lygjJ~`KAEhY2ZOx7n`+Vf(P zxgy{7Vw!Hg1yP8XDKdU<`)8HA<>o>ADk#U>QD*0hfjB+0V!LI?KvhB(LvKZU_(whM zjwuzFj)8E;4k8hvkz0fqB)2Lv1retLV;`qi>DY z(nJwk_yRdcfEbNj*^&aid&#sl``#Azae#e33K8(<7T< zsoFSI0pm@(gM}{-O8o{YEc^h$c(aBQ_7|Y@%60>&CS`t70=&d{_5~=`vuR2iEy{LM z--J`e`jViS--08PY%QCa0lb*|5@hm$Z^qMSJxc!X-uQmBl1v(ApNY#gmh7HsAp|x>(_s)(S3E=XnUz2@^z|2u_C5XRex~z9hOXM6_Y0!;1Ke@5 zMWgoeSA@IMz|?o9g(S%%FJN8i&DZ;Oq4CIkIb|OidZ&stE$VUQt@3{)3X9{4Q{7U| zIcB=~ncA&xXW|*A%0I!ESyl60SXom_^U`A1!7+ zHr6p{xi(oT&NuY~^~ozLrjb~9K7S$!tMnua`nf+D#t@Ph`u@1&mP}2Z$@6&cXPdS0 zl`7G6r)$O!;8tv^an}qPL^qd^**roul!A*UxLyQ_ki-}+U{Mi|mEIG%38kM2#n2Rp z8CXBPrV5?H9khP+Ro!O%V6Wi?`UcNW)0!QEsK1sL)O!`Ugxq~~ME2+0O588yy0UIn zJNfOH-CU;q3R$Ts5k_0nvD!&QXszW*Zw#r#-1Nr=u$fZ1U(KcHGcuroEAeMPFY)OG z@}j!Bk|0CK-oW}59hVwU4A3U*r!u5Fgh@$qmUD~IvT^xWK$3i1b2nGr zvbzu_{I}!njKlt&2nf3P>0K#~|7l4Eq0B4JyPj$J9yqoPFS(2V?ReG^cg?KZcAAou}_ z!PID1^{lRc;aT2hM57qVSXvOO+3XuD>;ogZGE_F;akHEdv-er{!yLt3>BU_;Aijn| z0wD?R5VTKQjH)aK%oWjrg7j?&gF>V|BEi$8S$)6@Jef0&qE7=wH|-oS5ciY|0%K0S z?H5vUA``QpsK12;K!cqOG@7HM$!CZRa1(IA`(ED!tTlV^=`2CG1mY|Luam99DjY3D zo?C$9rr|)B#H9Wd%TOk_Tp%~i=Lbup`=;US->^29_6_%MLz?I?Wgz;4=gk7~M@g!t zD4i+Umn_{^B`bs@*#OAuA_{v4N2iF9i-Z}OdxqPux5jAPsi&OS4Sq|fFqIS z4FkbjnkNaXa?scZsu~m^l7eRdCY6xqsv#d#9+OofFnZvCMorf=MF>b*)orDraE-i@ zY?B>=VsGJr^i?)ef^IL#x`59Xe@op$GGF3^Z6x3~X?{+X1rxY@yiit-y`~IQL$koL z!yCVZaWJqk68!yHO&JTAhGoP=g}uFcD%qz&+LGmqrVhdTPibg)!6(-li!U2PR*2kNs+?+xngA(Q8UaX# zZKOaMa4@d`!}YckqM#t}8cqX|+d=}_%GJ!kQXau+XdRmpY{w5}AZ;unB8{Aai4@{$ z*opG;2Mkcy_g}F*7r4k8;g0h5bB&(=wziG&S$tbz!0GW03@w-6+B5X(A$gG8iJ1yb_UiL9j4?@s8k0)R9U zI%0&VcO0a#$}KW-jNihC4dF5`U^t0U+V1J#nwN+<8@>yi`pudBnQ@~Ej-t9Y$RRln zFj_8A?Gc_;EeWjVakB{%xq$BwMO{X6t5NL5ub_N1^*4@JXA7#t^Ez>Y-*WW#AmF^E zKEi-P?XG)6pyy;nm~}v2O@s@~ZR;6cIdb=yUYsqCTSLexauBxmOswU280W-qIvLBcYt9E39?LqDnkSzGU)Mwjs;oi7G~m#p5Xdonc)jZnt$GI zs>K3il9k`hYb4w(CdP^Mj1qFZG;>Ol@zPJ#7>Ste(Z)TMne~1?LQhwaEgXb`r?CIO zCmuBwy5#Al+3cwfe=2$NK;?MoWr&oghWJjRr-@h4m%V4>&NGc)IxN;fs;9#Z30jHG z-qq0-3b2(x#rpy6KDUm_-JSnh_2`60v*T#Pk)#JLUPmKeZ2d|b4!$#c((6HZ=S)QB ztd?ZFQRP^-AKt0ak(NKmy8Y^AL(hwlcJI9}M(0$}zAZo{Pg03{*6&O9l*4$FjQ>^g zu$n}A-P~_vznfk)Oh23M%&N{+D^X+-&YRwI2uo2)TfTbGc-+bJvrOqIs}0u@qL@`4 zWkGp15~%So*uKF-{Vue@_Lk=@?N`U|PHpw{2kKX1j0YfSzOjiza4*?~#G zo|W=uuS=FVzW)SRg4W}aZ^I}K#}CmGe9*x{_dSrnnXeY`Ky|Nyk_Jx5G0f8aSf$4j z{G2_dQ{j=SqsX&Se%L(=X~Fo$v$f%s8QHTyc*HbM?~#h;SO6{r!DeCyU&r{C+Hm}i z+*tzd#%B_y&Ig{Q>p330G%#uFOs{(gk#s{jqtam$=RQcImJr$}N^CeW%!-WWiAcio z>z){(e|jpG^p5i~j%*h@5=B&*Yz)FK-SOFg6J5Lr81*qMkGZF1GXiz$H&D z@c#T)x7PMU>zdXX#d|pTvjUXA1ZNTzKIb|9yuCI`OZ@Z>`t+)ldY}%Ye zlDJWxM34ZbB$e0idLG6P-6&_-hS0nYl-x1M2qS!9b)LMEv7T@$wBr54t6>D0``nd^ z$33Tr??C)G(sjM@1hSOrSX@;mZ78P~n9m6e;O69O~luRpHWqsKYqbcTUdiY3Uwd#%h1WYF0>vYj|n$zi` z<;_}Fv29^xKw0|za$8aMhRyRd2F@3o!Ds@;$ZAE{)U4yTPyYRlJd&XZ6zr6$$<|Kv z=z^`(M)km=8{JwtmLqMNIf}0u-hUVEYt_gO$f{P6Q8dX08om_<=e`R6dHVU6g7M~; zU&T!A#7`l8=T81kKU99abV#N&iZp!D&omP^j9X9!9P?p%b~ql|awRsG=IU?Fjm9m- zgkI!n==}rq(z-@N88Zi@gg|+&Yd+Fq##yFMCd$0YfF~{Y~d$rvi z91jId``UVsX-QOt=UI*#+s?cprne0c+AfBdXt*sk@E} zH1~&W3M?`w1}F>C3E7*iOT%s7<@@bzayc~yk}(2#MRR6exv_DE^hX7Q0N})H*9hhB zUPC^*;3yNRB_-V#vh^D=rU9wK;+=r+eg-WVGh4etVwWg4~+MFAA_(y^mX9ld$|3wd4XeN z{2PXvZqp;ihUrOPh^gK&`CPi{ph+ucKrIr=n$eWpc?1m8+Dr4`3VhuCd@I56OrD45 zP4>&yBU2AvJvny(Xp3n31_fqfmSWfGUnu<}K`(z0rPk6X_3u*MvS~KK5m9)e5{`B0 zWs+IOPJ?_vlnX)6MKgV5iK5gN3)y_M&-OnBo1P4**;2{S8c(&Uy${Rz(?1&0-`z!6 zWcook8){!D^CLkgZeEkpE=AC|b8^rpw@$Zo5()Ebp_i6x_S@0tqr})TM#9nk4c^-n zEB=}0SpESi>GMd@EmIz^%}8e*bbAN7z|6@vkCSAK_`nol;9PU5rX7qG*+sCkKdpl! z1D!c4mrc8s$eftQEU5i?i7{`!c|7g*jM{k^@B2aZn%!=(?UPcI1g(q`vDBo0NDB|3 zA4TCIZQVb_7M*^Y$60VDd`QWcs>JV&u+cM(jVm@aU>TIdNFMAOgccfX`=ZR0+@^8Mr==2xc1qB3xG zQ2}XWV%_$ILX;xgbt$S{GGk&ICt4f{+x&gd!1&tiY^v+~&Hg>9f=X<~5G?P!-+?cU z9V1G?v(YtUA8jbM&p_gl&|mLc?>+h?ZJB!}UugaDOwGE$55~E~_;PuuDq-dr+=5pY zreG!4^%@BM3f&lkUlXW=1>BKrw`vRHd$h%4eo?aU9VH3-K|)UlG&*9bN88r=jgQEQ zES3On`-mgGeGc(JY3erP)M*nwxh`*6!_0H*Hyt*+iR-Vo$rMu5ZC0M~CjKacwST;}C1o=5^WQ6<3(xoM zYfXYbMEo6tINK-L^ikSEb#VI`d20BY6mIJWbL~L(FOw5TR=@AJ-#lM#lz5Ip6r;0p z^lbO=ld=(_R2%6{4Yl+F9)7qK@y-8J!R{;5k$#l_CsvD&mGRET0g`35cKZA|*B4k$ zS;NjhP;H2K=$)$@#{#ooq?Gl5aME6)s;&F)G|jQr$5u)gOWB_Ndg@LoNKwO)A*g12jsN7eVzQ5(Z1>eqn4^5M1 z$ZpDOJ8ZihikpXUeS_Xh zh0^z;3y)(E0co68K*myFEPii~6+=kCV-I2{+ajQo#Mo|<@U4Q36wb9BmqUTZUP8AQ zAqz{>Sj{+E7iH}jc=9HA^9;QG4zYcc$a<;}y9-Da6z(Go_Zmh~^#3D8kStp}=My!j zDP6N;M|wsNC=}QSxtl7dpIi8&_qhB0pu5xW%bh|zRIOh|t;COqdfflJ^8CRXSHJOB zH{%@b>NRUoJ;BCT4`);<#(H;uY2-zj9skm^l=$#On|GAg{yn8nLpyyVU&sY_y*ZUa zT8#}_WM#ZQv;TP6gQfosvc`CutNd?}_0+5XqzKs?Hu5)~G<^yBaJuJ8p62oyK#B-U z@co|@F|lvY>xZ`Y=)QYPWE(C&KF0Lb!ZmtnJ2kTYjHhP#|pN%lOlGk{L#ou6CDi&rH`x;U0 z5VwW6f06a~wVmaIUK_d;1?`#~mR|yyxuR@97OutVAbYpsm^+H2ij7w^&yZCnYtK}> zIUPX{7DgS%4k2=b@k52I+LJ1JhHix6!oY~VIgqx-f4W4Qx-{kTUEB8NShn3%G1C|0 zs2I=pwF!-#e`ILnK*PE|%JpyX*X2Ir_+Mr zf0klfXw4uVM5fitIx~Xao4XV(zCj(Xo%S(zMePBrJEEj7tHZ5r3g;3CQn8Cyrc1P( zJzk)lj~sbX;!}6{D*C*g*UJ*68V!5JzQ(<>C5zY9A6PyJ`FK>jH)XHgmx;CoSOQ_EnIx5T(z*X zZhiGhz(l=pbUo?LUWfd>Vejs(H{DmyacOE6%HArdSH1W(+GS2|UeK$RGcM@YJ=V3J z`x%^SGG+v+W4<+oiH+HR`hYB3)W0wSvD+_1?C6Y-qkD=Iab-RNW53>&PnC>R$WuUQn%9kr^i3Q<*)EYL#m~81~-3R(|P*&XXEQM7G8zb z9s5h+($enlYj(WN3;*8!vhDEtNf4^P+)Y;Uap=wE=-Yk^H+{lS@73(AJl$U`D#No^ zmB6~9EX)5(1J6mc^~C#Xyp`h>MrDYM;R%s0ew?v`(ln@|xN8m~XUzVhp2i-3wL*j? zLzuNmQnv1pMBdzXuK5b*71X`5)Vd`t^L6D-Zc_*O_W6y!x?47?DQoxafVK?qg_=VTdNmtO^{^v=RBfev0okoI67@R6ZE?G$#-&4|}Mb(8z8 zv`@8Fts$k@>Q;-JlwH>m$r=lcRa+dGCookJ=aqXv1Dp^|`jYg=6$WZSIkXj>bnkhL zm0B>ku*gWI<~hkKKj7)>3?qKu3@NqSTkhgR(`E5TSM`4|K7BvxS}*`wTy#L6C6gR zFL19&=hoYc*j-dR1?P{HD>gejJPg)Iw~?-kcAy{53|X})_Pk#fm>Ue;96r1X3=tiH z)_^&;bZv`Y;uRN@W!ul0O0e%&4mi|+dByvrAl5gJfSp_bFO;Osu@=wY)h`{+dw;MA zGdW~BDIs!GB&FO%hHEZtQSpj%-*Sx4q`vD*j7D4jQCGvV0WAELSS!(&Vcd)%3iFA~ zD|k3$c*a6%5==`o*P{pMI=Vgo{mQ!X!a)b9n~bj$ce+R_Il`;LgAmjJ2j*s0HC>)_ zXH0Ia%>Q4T>G|j(`$b|I*lX}X9%h&+AOf#cvYht#p}tYVLh?Uvj-As?W6$70?7%mX z52J5A?IwS_u;uUC^sj&)>+^)J(UaD88zLMFK6GB`3cdMGzI>f5PrvV~7+1>cp{y@A zO`oEYj}yZMLqXH#|CyHg(is_|y1%m~NqbmrMaaF&hoyxWMe#%eGQia_fT5`}V}83) z>n^*F;DDrjkXwrSdio^co(JieFiu6n zl`V%i{%0ZbbV(-s!4scT+QD-V%eJ;2%I24f*quImUeND%I%M)i)gpUzs-su7Kt$aj z`{k)Ohk8s=>XC+>qe=4K5m3$=U799J<>S&2ipthh)r>vXBgL6oX?AJ|in4X7(uowN z6HSKYbS(Os{Pu_&?WyJ8R^8YkuZak;-9!^x`Z~$%nQ!FrlefM!nso=PdC0mQzCCEt zgeLs-kc|zzY->MF>{$qjj4h{%v6;{x`ywKp16#g!3$ejXoo~B8ibp9vtG<4m>&@)I z=DWKbTK#0&bGiy+Fuq~>K4JddJtod;Oc@-RpDnd1O|zzF9!%D;8PKp$5pN|81Q$Zwfy5mKYnLUy4yU)OC2N-RpQuHl_PUnjL6wTkgGL~HHrqU$9xf5V+ z%PH`*Paacq*R9u3H)*VK?=N=a!ap~c8=1ZsXgih5n%(zvxZ<<_sqwSb$DR!RqqltS z?^;5Wru$Xj;zN{Uze98VX;F&vh zSmcul9_a0<>xcfw!F5D0nQcAO69+x|rjwv~D#_L37H8A=Hp5-eG--W{G?r$QA@I&IY{f9ox7OaZAv8q{JjxY|1@U|Do+Bxj9YhxRu z4-Fd!N38XwPC@A79ZUffIs@sOfnHDO7ux`244}fUKlNv(P#MwK_guq8Ud#A7NB?4r zpOu74v^o>TaY9|fHQXkgWd0J7lo4^2fpF3xn=n|xJ18LJ0Nq)%8UpAViBScFKJl#L z`x~EOu^r0*kQJuMf~sMlY!p3bvtwAHZw|oB=*qn3Ob}|0&Y!&MlK) zVL1@#VkX0c**KpZWHy+Na;J%kfo6u_FCd&$B4QKD7=%8vB{=5iu->V604fEW;Py)G zW(^#ajdlYgsD08RM>KM{YLVA85kD0A`Ju|CvHTQAdaGPrIT-He$nF@wF`rMZJPoS} z-hzf%l{?mt9$T1#P=TlSj}r5p(%?%Nbqg2`f&(M3k-Bgpc>SV7|8ScBM<9i%Ew7d> z-#Gh+2GgBSaSQFRatz2?q$+YHREJwEc{fEkQ$*z8-m%O0xcu$NYJz^5`cx%_aT(8w z!^M0tcJGuGDJ6n@rKu_MMZw01c1<^;W=fB2NE}fQgN?&ZO+f?O6G@rb{+St>9ObMAjDB{EVpGmxEfWUK z2zOW{>J{v;vi#wfamg=+^uL}BeIA5o^)K_TsozW>?Xw^m=Tk5_?w-fOFW-p3a8Jb7 z_=4vgizZC1D#sC)`EsJ(9`&~a!`cQ*P1(JDIm*!V7fGHs9R^>WTwI5pL{4(S8GE+q zfx9vV)l-fZCu|mxY4C=G&6rQGV^5mUg+@4?m&xcZ`Lahqzl9j>wE>q-s7cco-U;m} zym03Ih1Sscqo(ToBVk{2DcGMVVI|?-M|P47``*V3N9V~dp{FlDHnT1@u}b+%&~qv!Vc&2pOYXe01!~`1S&}?^2J$B~0zXyxlG{hp zcKwX~mu=FJv%^!z0n>sI=dl&j}bqzw-i`#o%Cxts!`&&N59>>$^9bc$>99^ zWJAAvY_5tGzJB`DzAC7y5_e_ewAs~0yZFby#8WND;VVG_S_%j4>XGWomyhU{Iy9&s zvTkea`&qc&61o+;BQo6 znzfs@T#@c*N6u$ao^B?X6jKG~@MNwm|G*6E!>x@Vx8<5Y!HAmA40&2Gxo2#6;;v8Nde(LQn4jTiHrzGO-ezi`M#j;tYiKT{-%+Vt;*1I<2-o zT1zgauSF|IE7E03$!(`wGpBZ?PtQKpd)g=;X|ir{X<*9F9HvxMX%0*M*W3Z5H+#$U`7P=?_ci{V&?QUzkcTGOr>`9S z`0Gyr4)V)}5rton>W3Grotg@Xy~SbLg8sdDZHXgtA^UUzPU!RWeYScdZWc%`vrg#PHU~w^8Qtdmb~KW6MrPGPB7_l!{}^UQw!JX78ku&f$=~LP%wYkXb6#=e*vZ@B4fCet&)b z0gvb9e!t&t*Xs-eDXA?=gfY-Hv*o$KD#0(qx=|UDQ>$zk6PhW_-`gn$T7K)h%e|@< z&_6II&0lmX!btK`(EBUNsN0=2C97!Y2S;NPaxwt!Ib~1r%mR8(uL38snQ~S6h!f6i z#wQbXL;^ovg6x2t6wgDfP4?CrVdLhslMk2=0I<94E3gtE|6O)~%@jv!c0G5}%b5>m zA0#TVyH(GoqXG415|&}&jfB}~Kx}4kX!I+D!&?Eb{A@VhD-aSrs$O1B42gf;o4I); zQogp#!+7Q;k)ylnP*fy9@8)8`KZ(P{{3Tgev8f-PV`bQG!f?yXNTq58O>X0^Te&}| z;I|3sEs8Ytk=9^|-3%E+M2MCFb(5z8k(r4S_x&OauoSqGcS?3ZAK17fyx*oKXQddW zThG0cTf&F-xz!M5#7Yl-^4W@{TTTsTJD5|GOth}OXi3(_1iNwQD!K;e&hdv}~ZIecdB4n$&IhouH ziKiYuan-6q@|)(2`BE+WWG&^8UkL0>Q3Vk+X12^c!?~GUbs=u&oxi{30)>$JHD|Z6 z_3@1%3H(Dj6NM_(H`c>$W!yaComr9(ZNEOF)Z)GTGT8p7Au7md9=OP%tHYG|ii>MZ zH#3eTEp@%;`N`0dOI?>5k2N2tHL2Sa>oEk}!P)~biX1LApVfogL;6D-Y@SHcRwsfk7AIC%(?nOQ#%0IV zPEkkU6~VBJDV~rzBkvTkaV+<;*dY2sr$eb?8klLH%#WA%fe@N;nz1u%j4nSM-B;-y zLyqn~h)OnNhpP*R@^(B9$)S$AYC99A-?!6caSYZU*#3&a@`2}5`HjH9WkECm8PMku zW0_%gQ%%vr^qo^+Fo-Va>G5f{N7Rll7@V5Z$XxucpeybHiZ@U{hdp1mrs(AjyFfQe z1!22cj#(xqyBFu{Q~Jt-v*Wgxdv5H6*#Oc-;9;4b_Gr+#>z-w7ZDB z$M4`Dh}WIAMPw8Gco|4`0El(2?B??wm#o&vE2Hzj<$!~mOKI@iKKb#?7xOsNvovV^ z{$3z0fSJ0$d^`R&La*%Qjy(eX3fnb!~uB46q6R)k>e7b52C zCbpOBp-#%JYg(oGpn%k7@2suc%9gB?I2DbQBY0<5@Nd_k-9K+%&@N4%ZhgMJhffRw z3C17*?05IHpSB49LChE5h)#z@=W#n+)^aYV+ay>-KJZ zy@)^vGFyfD+M)n%z#jtMU8p;>+OzOeWJms7Pf1@}H>}Xu6*>$wE%OJmT4?+xy3hL}vz1znPQ(%wO~XuhXt6EzuOdFRl4z6U5|(bx_^CIT zG*Cb{20_dw>1BlFqQ?h{yy) z$Ew-L;6rwCCdY8bb@3q?c;j9Grc#;QUvef`G_+X=AdNjKo0##*j|*m9LCA0q`Cp5 zwUUx*W({eKrY~<3@FSX1IAP!Z=mB0S(BruD6a{r-d2QjUc~_M~JAq1w`?hG6HU(w( zZ20O=m3$qrtuvwhyneg2ff8CZ&zFm`&P4A^%Nq(JenFSZc-`rEv#r(T?fHn3NZk(5 zQ8hZYXPDe8;h}-{&;ZlXh+%WBSYo309b?kmYPH2*-Pt)sC>HUVrw(;sl++gHz`-e_ zv&?B$-b^KQXkN29Mm=N*@DG&rpr(HlXb@T0^DxUF;E+3uMuLLFTom-=1(j*V#2^DD z2{C1De1rwBvK;=%MDduweq>EJHnTpyXshIDPypr9Tlqm>&y6_bliK4$9C9P;e{f9w zh}{Wq@ESJqG$sx0p;TvU#W4m^IH^4-X#+x9m`l2g5Vu&hoSw67?>@N+^(UymO<<=m zI2}6BSauurppC)SFPWaQPhZ~h?n%os6)U^B5iuk-eS*25Q zQ5Ns=Y+b1k1tRnHX+=GEiYw2SE5#dp@tdp48T+z|YpFN;$!}LxJ~wwVmp#vwS*%B- zgvZ4-{YY6MdU@fv8qW?bfn@~ydNw<)$opN}lkx!m-O_7W8cJ>jk*f$Rn#RMNU|lkr z8g|vdZ3Qs|L3}ERrL7@0_NDkC1CHm`??h%QuacK4=yq_VL-xqBHZUD5g55IzhYr3D zgMY!$YB&MbsmhZ6h=f%(j~r!s`HN))Fx6?F&~e47xlE%(C_Q}3i|)J!*XW3}XB}~0?sTL8%sPh5>A9238#U!8G2f)08T1N(%{gQyCijQLn)@qDIcT=R zXenIv$(&@Vv>@+>5b{>=4|%;KlQ2FJ;3bJLj4<4tK9pPT?hU594or8Re+i?|s@0K# z4j^~F6}>rlcb}UJjE;Q?CNCPV<(wnUc4z9~e4QW}39Chskl_QriZXVlqWMf4F(l9|%~=mn zuQ4H%YMgrl6JxkfKJ4q+lHWU0R4`w!(H?;vtb{NkX{wRuw<%YHi_XPGeatvr&O}!6 z(YmT}wwe6r;+Ca__3E;!Kk?8^vwE4`%b7IrJr8|(7KK)ursO#M;-hIHk+n!bNWQOz znzhy?F=IndU!$dA1Y;7`*a<2Ym;|(gLNyZ0lUB(qtBpF?^f_|irkH$}zcPnxQRi__ z>=D${GO?Aacp`93F}i|+O^4hD8Mje@>m+&M$QAL^nT-4End&tUI+p~O?>|IV@ae_y zh_+?%t;a3P3%fUzl$P-=opR8p^U;>AH1Gfg#!jQ2st?ghr9uK-P#SHz38PoP-6$2^>1IM+oe|vWF&%<6FMs)PmB5+AQ`XZ zg4$Cepd8Fi6;=ui&sv?_IikO$+#iV2@VQ@HzGgvr%yRnvj=<9g3%8$s-=`rrh2mO; zlGh&&o|Nzl-_cVQHW}kCg~E_Ff~5p@(vEJNjcKWA$?{_%iLnw2x2W!4!F4;8Ekc5H z?eM5SIwFlNC}tH+Obq=eWrp%&aDxumLs9ln-NVGwNUUhAW9;eYdd@M&LKvaPzr2ZG z(*LP6AthvBqpFUtfy-&f^n@MvueYl3m#+rYLG1QEV0IIFaD1pJLXkHACQUph+W z`DD#n-rzj>v_f|Ke}fm!yGi9L6W?xhIs_ZEVU;_m%h%?>A5smsgEs#QUgT7)O>HhE zwr)keW|q-&pHu=U_d%2dMh&+d=hl^RB^E}G)WVQRP2-=mc4_BgkSaV%u{>w(@164& z6Diz)!<2hQ<<>LPLDw-khGn$2>xBZYON3bt<>?Gn%8HRaY`}E^G^YP5AnLD9mKUA; zby;dDrt3e9*GLa69YcM{e6TQ}$l_k>z>f{JH`fnb6B#RDv3|kT$3Y8T2>M80;=Y%W z@=}(qm##}zr5r|9cpJ~(r3fz9S5(gEEuw927_;}*XmNpK%`DF~pmt_2X)`A?K5AAO zf;OJse9@b7sPhW_6M)yeb^xu-q55YYa$-tR)g0G`SBz=_CNLTTiulr~yDeb)G?1^LH$_mFj;Xict_iW=u~SIRieIzsey)`~?9a^O|PBatP~ ztebuKDz+rAdL4iCbK(_q?0xj5c<=TT!7mnfA3w{8>LJbzkSLyhp0EM=1+<514hEm{ zUa}&A?j-QTK4L!)`kd2Wb$Hby@H3RLzU(~AAM*9)(spk3VJ*S-ZR~4H2~?{ads?-D zb^yFro5LaCd5X0x`FGl6{LHzG@qXW1S+m8B{?T4f@5?v}Zuq?nfzL;$xo{>Wt7Ttj zsws;+d34R?{mB>l^||Yly)NbV4%(d3*fxu(is@m9MUBBNuG}nWFZtKk!QQ#!y$`P- zt@-NZ@sGB!@$c`aWal||pVbfu+eVV7Ht9wbQ~yT8+t_Tz9yIV$R(dB2McheHiva$fa?fk=F=vFT>r)62=FPI#HL96h>!aeBnh$ahZGo&{=1cIqAVVUW6erJ^=*+Bg+(!z-}eeg5J z!-7t9nKy=@LGa7heG!z5&Jkza3N}qBdeA^Vy%t||gB??(E~H*6 zF%}YJLc;^m)<&^ZfxkLRuo@jBIuw_4f)rDX$>ZF#iw=NR?G~5sJU0~t#Z$FqMsgaG z(=K;bT!(n)@j?JxUFe!q?CXlEFu(4+;;~r=PQ}E;_@ClYOznf zz`i!OUm|VFYfb&5O=0<{?aWts{aKl$H4% z%LunWBo2D1V#HlBz><2L`-JrzVwlBaASTl~N{dA%r`6tK$kAEm>P}yAn|<(@W57AD zz(0@L?d_x!`wP>12J5Sr6Bmf=K@HDkvkS>(G!&<{~wmost>4NV3edTe~RuZMA0GVV!533(ui z6~UUkI{$MCfFSm#r_cJU;DYE2(@od+|D^DMkQPfsST%&cx2i)Vo*ex4(q+8oSAO+F z*q0fnCVT&nE_EkKEwfJl1utA{uj?MnE_}O`Nb2Ohe!$`g9GgYIEXuZ73V;l{NR7x}8G2=-A=uhVQU0LOtn;ws7GD_C73@nHK z-V7LV#Ua5f-A+p;xe9(FunT)xM8oCX)JisDUA`=r6!J;9_cWPf<+5d3$Z~WKixJ;S z*R^Cc?(%L%Sps-$#cujVhc83m1Q1-FWDrG!k3bl3!$8a zmd~sl#K#7R(zj=7U6YV*tSW-(i<_kCZ(|8jsbbTHZwe15N&{Mb z#hv_8xK>7%6ZDfjqQ(U)7KNYLbo%dHKGRFj9H$r@m4167w-NLC(IV6Sp)mUC+S%V9 zO&ua{94lDz>*Sl)mYZW7In zPVPo@$(Ee=0n7M+#qk|5-|2Vw?`2Zdk4F2>m8~StBBjC5q03jy-pY4q)A7w+>N((;W$Q)wI#%9V!dd4D}tI~ro(j9`7M?fkUOc+#g_^6|& zxj)9m*|BqV<;3S@7E#GBbpkKLb~!mHqMYuMoWM=jy$a2;NX@cDdd5?$vZP7zg-Il| zOq%clgi53P+u1M4uJ5pbsfX&$FpPV_^s*S;kA>Z16s|SELV@3id9Y=n-TlkLq4Y3o z&>q3#{m4s4f-iDw1zgWyj8A|pO^K$2Kp7O#DE%)Px|kjt({T+F%8H%tShtG7)p&w~ zUX)XRhf^Vt!>skY?}EmT0e$(|J5huz<4gAq6xAcrD+9(p#NRap_z)ih-j^2Z7vW#J z#uzsblh;Kv$n)-7K=g8$v+Zf1Z0;6{P-!a%<&Ut!J3w5FNZh>O@*AN^GFyNR!pr|r z53iA1KMneAMxNHtT~Q~0LSOp;H+>+Q5*Dzt{~TqG8GXdla2R7uCrPuHA*C&QsM2M` zZ5bGQ;v0U0l}Xf+dD`EU^2RNOn;8S2*i-d*YIFkV)&=QDA#wDA**M|S7FQq`GlGYa8QAKI;pAC&+EG5p^rD!i^>vVrpY-{B}!XL&~Szv-!nd#^d zvuSlCRCk0S%-enGpD5*6_**VquN|V7r>NHsqYr`Wg}}HlFphSJt&F1EG-o&lqGyig zQc_kjP|VX*QIb&($0{F5DchPThWn`GX)C|GsH`vnx4os-Ce26LR^&pfg=gT7a#VDC zo+bFdS$cCWkUCcJ2H{hWP9uw^Z$PCIjI%^4$LvO_qyVo*N^c5#1Lv(8FBy7XX<)5( zd55W}v}rPpB)xyx>YY z0`#Vw?ycM{gKWx3ecgWmdNFwHKlqU$Trm#dE+!Or4IhEv41Eqq%;0mn;K~|s<@0!j zHuyf?p!tF@Ob@pF2Vk3s%ReV#<#59^*Uv-Tm@xva*m>X?gZ8sAK{=d}7IH^B4|Y3o zfs2)mmn+Ge(dJ&JKD_M9;0q%zbb7!aWg+<pcY1!3W7^ZpP&OLKYZ|A%;DXT8F;#fv66w$g^PZ#?Y;)rIOe= z3N9z}olhS#3I7Hhv|&5q?k6zwlLM?~Jgx2gY)StJCww+4GS=6B+sq&VDk8kcX0~>E zcHij)curjR%{X`*0X#1DJXh^Q?2URvjQr4C96z~bZ-H}ob6zO2DM0o^fO`w!JC%32 z#n!$q$R;{4_=DJF7w=)BIB)%4&h)vl4<4#D5*ABf{FPy9#0cFGBt8-{#O44YLKfjt%h2M(Ph{s*gf)K_#n0V!Y1x6U2>bxEvnGMK}8 zWuXV|^3Z-F#<}V}-fT-4AqqpNUK(=&SVS*Q%>Iqt?0YdvGy9RwZhHh<#lQO5x`H`k(HxBFpPh?{h*d7Kc-3Z=m=`Ko6WuHtX4L=0D|M z9~U77cb#&w$mhRI9&@OiDf!DZ0?ASq^#~5cR1{}+-|QPRw*Cw0@suL!Sx9o5{qRyd zo~=9ujt+tHSJdvrE`rtWbeUH1zfU=*x4}=}xu@E*`@U$8-{*Ew;O_k~ktpZH)8O6M z);U11qhZMyY0SyQ28U0efo0#VJ@MT-&y!GtolTD(9*C;Qb&1_Y)NdaVF9*1N|4iB= zRnA2@D9_tfb>d{wR}|v-G@JphoA_7*p%*VLD0Zcs)O>3&Cr;6w_=05=}F^ZWtK zNO=@PgeZ5;(QjqV>}KyUiv32z+1h%Qk&iE=t zUCf4I@w9TBC!%4JR?5ak7aR2$<;UsoT?tKU`W(cgT|24~?0lX-jU`*`0^>w{*|!(3VATj>J)eaqhVJoXutehY;S4FMl` zN1p|KDBOL0ZGkw^In+vPp~$}~N8L=US-lWB+3DMAtV#83K0KdAkl@DW5UlwPa{z)4 z+UW8=ZVl7Jo)JwbK7K*PC@t-r1SD8T@M%W8Q)$Ma#OV-iK6e|Jz+a!3ozzMho>0%^ z4@!1mL!^#!W%X{Q2?%(r6J7cK+cRtmLK90jAIN5uZwXoyRBkeCcFMB#oOZ{jtJ#%3 zG3vEi+^8yKkg&``FEi+8uc`bohfx6*FT7i7MK!Y`tiC2?W|CH(O4V%NsaTb)zXg6} zO3hauJfRlt4jKn5Zlj?>ArGLS>&!|Z(!F*0d2hd>s{*1%+T+K<>;{v^kK``AI}x_L zICJs{{3i_T2nmxf^^~7l*ASdr!a*N>Fh71?LC;Lc@p9xa%cgQ(KL3+I_vwu&Tm#h? zHtz&pgW*%GVHJ>_P}xA3X3pV;xy_)LIEAbxlpD3XFnLKPjlA>92be@7e0gq}vM{Sl z55zlqrVJ0M3bnSr?RljLL(vtchj^jUfSLlE|0yDK_sV-}R{Z=>_>L@S`s)?+YH{b| zF!2x@^37->uck!u1G5C!E%w}OopQwYb6LgBiA|lwkBGckm8F(S%k8_v{4oNK0*jjF zMB`SvA$>faN5u#*{ebHU?(@Twd?JIbX{xLC7g`b7IxGZM-U~^a50r{~_DO#*KZA4X zF?3+c2FO8cNx0p!^#I>TO|nRc#>OU4sYNXPyf^Q0tP!ue?Y2~-?6GAQrefEz6{o!V zD7#jq%|KmJ_D48GfR>s%-c7o+sh&zGf84fLX6KY4<)vZlX@nKQ)ds=`ilU**$LEuK zwC0SD$6?4nEj4;D6o(50D<5&+db=uM`mkIZtX!I(y>!VF9}D4%%aV#H%Og2;dT|bg zV4iyn;3bA2$4f2hoKbm|c?v=!!2D^AEYF?9oV3J<4)lO%1dqgoiiB?~OYUZd^nOhA zSA=egf#|%o^N0b8XBntRXUG5zfS^-gM)3XcxJ_%(i%BB=v=YU5`g>3zGB44!N!zU*f;GU=a_`I@ z-XAIEx04d+yK415b=1Cl9N|`K`G(SvQ;|-m&nS4uWP83gNw?>Tv3ViemI4?y^w_|p z7KXN)NprG9W4FMx|2$k?Y-TS+mdM&;gG3CT$l`_Lsr-;yARjj~`jXiscNcz>;9ke)myjmbdxx+8sa@wjOT452B$wu7 zcQRJ*Z4Hh>0S8zntubWF-+d}GIeI~3Z@3WuxhT*f!IXj#86 zof2OOJZS$O`8Msvr!o-(T?=3-uQK84Etc$^qg~=)Ii~&t>U}1Xs_j~OI%%n`G*MWv zmL|2ut;%e#r1BZlDamPAeD%JE0MN8!_-4y_*@(yWgI_z9pH|!xX2c2fRQVL;ak)4O zCpR5ECXarA-95C>IZtK|Uwfs-Fc67d;SSHq+|47*(@Ig`U!AtN0( zTVq~MBeAR4P0FO_1MOU52&Tm_56*_<*9?Ze-7BJfQOdTLm@mN=J6)V^V{jhO7X#Y2 zE-$CZW9bH-ROZ@rLgyOmWyS7{hrwSmK2DxED0nCx4_t$@+XO)a)n>3sP9aZq)Dr)uY^evJapExRqD(7xjP zD%EbePtZ4s5*P(odr5BQoCn!Gu4WO(Q&4luhAs7{IBe+md#f#2>zdX#W(%dyn&0le zzYg#F2_g0{{S%$n5u^MyzmRh0wB$_ZygG~JOzX-1zq3=KRQTYrL56iT8k5G$@n<3s zWm-%+R`oN)^aiTN0qU6)VN?%0&*>WtJ?>R|N~s}8Z{_<8^&wJFO+rQb+I_~_Qx~Q& zebP%Xi(6xFmt{pqvL|V$3b&hJ?D0B&W{i5X9)n2 ze-Cy(ogp@<*CgTl1+3X6f92%UuI)TQQB!)8(8j;eZy#?C7OD(Y$CrYpf*;t>of%m1 z4@g!>r+iZO54rkf;x?-w9x?T^9y~OF%Jtu}zzC{hoU4=&vNo9R!5Itwd^ zj#+OmWW5#+c1jB!Ix^YQMk%sme0V0q!P))W!BtWE4wJpUqEZCf_5&>&i)$pJ%JOAu zwD3g!5(y!bFF;dP=}5_2Fcy#9dXoKwVWGj;!||A$329RUW|Jv5Q~9ex9KAyRne)}v zds;u=B5Ym=gLFjLuDqKzu;OiB7)Te*3A5O^t7Vl2(Q-(vQ|CK!!k4Wjp-PTd**2|^_v$?7LRRl%W32)cNGJ))n>eh&~u&9FE zyW*e}X!S1)Ix2x`HEB4#+2eqvT1}-sxU%)2)XV>>S)hY|uy)y;vHa!^OE+HsrPNB7 z=b^sI8VM;2Tb8cs^rNZP-pGiL+3$b1&v1}BbQ@wzFge^2X8PsYdcrAjB3E50w{=Ng z3GjDiKxGPn>7SeOvcj(DBn;-dC2|uIyx8S%)@)rjh$50Geo69x*r6L<3?pgkP{P>N zxYfP1K5}^nMhVmZ(X69+FDZisxNIUFN06MkI>x$$5T@r-YrBg(X4S2(HC^X7^m*)v z&D~-n+$Zf9*OV-drF0lOb@Upd-bSKy7h`~4n&lleJufxOo)WMgF%~e&)Q}gDcP4nn z^T;7?)WQCp%`(>~#75PrK_Hl}i2j()wUk#N)*Z(UF|KRA@B6FxAQIgVR2y)z^REcR zc)Q*6MR~PoLa3%?*#SNnb&RT5*5ke8H_HASNCPGT(9OKVl9gu`0w6dJ|^20`1I?cEtI7DbmvfN3~i zSzKAZ68V!<<-$x>2wu`k(s%4(O&=rig-X*ciwaWZ0H0xCb1t>q0L59dsv=10L6FJ* zh;FtV2C&^{5+q(pwoAVuiC<%C}B`0<=Xe#lmZ-pF(gYnLbK6Df>|G-_bsFqoBIpK{#+5O?f)`P(AD{}lMu|M=x7c;!?I*kFzj`#nDw0&^cA($ z%O3Ea6AhKM0y~xp|Ngs>%4ODh&QMvf#SOS4cG1o?Huh=-p&DBKyIZy{drhN>ZDO-~_1;0+ zm~7ulZ+kmikCjM7&f2Xm@5BnPMC3rObOxG+)-Ave<_12ZVV#V>>zJk>{^~$i%OnRd zCi1hYkm`sYRmGi`m_Lv~xbX)SknYg?r~b}fU%)kMpUPgK6}wi!;k{`!wY9aRPi))i zzZ48=%cEBN8gXP9Cddo9%pp$BcK=;%rwasr{%>7A$mP;Z=Twz@6)%6VXt4EU5|@OR)Zs^0 zddj8JipbUYwwv`^y|n?g@*3s9KC_QG<@IvXp}1!zHp;P`=(k=OXU4_HKL_KMiew@2 zOWx6ex7~|^g_BqKGqI^FMTLB6|JCJ_5mex>gi>^`YF4K7S$Bas@8$PC=RN(6aT%)d z#1gU82RR%Uw(;4eX-`f=? z7LgEX;<^##;4G9RI@-1ix0v>DH|qcRd=H*U!#X`|+#L>T@A5uT43JZi9PI@4)ow_p?KOodb4;K*X^C z&K@T?qkiaZ!)ev}OPn3&1}S>R2qhlUh}}C%lf=48M7xnQeNF_oRYOn}FQSVVG4ClI zWGqd&;mxaGeJRr2O~1F$h@#=_LZkw)&V z?#SZ|wlJB;AOJ8TZJIh?H(ezHjFwd`tuEA=<___2Rt~*~a#YW|VwuLUEQ(bqp|Lvo zG6h@>h9~)JLb_(GwZb#MvBHh)>zEe;Z?K7ZNi#*(2|s#x`Nmr>WRISl8ntsOM^U03 z5_f_&Xg+vk+Zbsv|55XcRT2>OH_Fm+SL2KMk0-Y6iU|T|FrUSJ7z(VL{L>i0IGF}r z?iS~Yofi0P!&0zZ+{d|cgTUzdJxzfyCuaNjB5D^wKwife=vTb5tAJFpO$uJ~B21x~SK=y+fQZqVKIYpSD)OJ+@m5?7e&|D|$k6`+qa{Bp5+F zv37=*x#tMF6u@K$E=#Lsc6#REPfCQTG}upcSgQM2;l<56 zXT@xm6TB&YCnauQE7_~n*L49{VEM;yk~7%fq?DrCw6maIFe(dGL|RpKZVRdK+dV2f zwox0bkuz4^t2r`%DC2=MA~&fJ2QC?ogQgs%B;N&+2-P$il-uM}+?v&Ntu5*L@@1LC z{eFR7e7!#F!K{G%cR1A{{rbH?lhpk&L{DcOw|frV+XSX*cIgy#L8({x>UYZEU`g>j zKaUF#A#2gB{n?W8qRt^nDex$k>yZJH2@&O_QCK3yYv&i!%+_JUYb;A4*NHd{TzqPA zCY>1H0+gxnYra=q zi&CZ$*+2h?u{=2Fmu!}Z{g6a3Wgi+u2hH-d#+#e3%k zP<7l7O$U84A;UYW?T$Zko8Mioj8no9jvK|^WloSZa_|-#>;c5SKDPk-R**q;U~!!i zLj~9Sl)1JGb-#Uu|1!*%H(Ld9=%|Eev_yOAh8;cCGq)rSxVLu zJ}aWkxM+TU?P-p{pI^Vq996p#x~ASg%Z9TrODW$&6hC;cTFN2KY$#sL$0KIb%{R>- z=^o%zs88LK4)1!iH#ol}rSnbnwMsk3h7ObOk(!ZP>Arq)QIP$#(p$dNgDavD@>#;G zbBJd^v;vW}Iety67Z~{1XH1?JE0{Z%d-(V|afs05oC>yoJ0|nslakSNb#yk=m?Jmo z3wOKFn1$tjQ-o-&5Je{fO-V0d&BV7;n!uuuXbyK;GaSA>CFMVM9pC{wL*sg8;`RC>_`EU5_PL~HQ zSFPl>ah1^&ylR^2v)}Y(P1*3WQn@&q0HAe?3n~GU6>f&u9>Rd2!O}}ZCXB{XJ6W3a zQ-8$zi?@yO(!AK68{7Wxm)ZkZ5~O``?=$W^s2}>3?F$;=7A`g9b|-M_)o+Lu3dB7F zHfI30CWPb*SVM|gn;)_6mxAOgLG(eOkOt6x3+q#AzuP{l0*KXJD5IMN?*zU=`-jEr zpwQw|`v`B3!sW^ywge3b;1Xlf1K;#9fBk{h&A(A*f8Q8mswxp#X1|#N8GdElk-k<9 zG6#S%ciP=*f77*tnj^VOO*ogEfTsD;rGfARZLR}7ZUx%FZ^GSjfjdW&``{u^s3SKc z47!i_?zVu|zk)Sdgw)?uj-5^;Eury}&@yqIT1Bx0bF1HKkS~WtJ{Vj8+)qE&2wSLX#&bP)t@H#`#wH8rw709g? zWEIk`&QC6@!Mt`qlKOEIrCr`otLHGb0mWPaC3{ zcJF`=V~6+7K-H&np{QRuW$$C_#4Kxnk*eC2L_o0>Ah&WMy0R>Vir==(|;L5R1WR2a!$4Z zGq(O%nXpM&)OhOMt=}JjXy72%21xxA9bwX_C$|S^D=bxja$`YCgJN_QtVa!sVGpkK>z)+atz!OJPeYG;B@176;dA{w8mrSpV{HGg1qmx5)k2&;|dGsQ{g2w{? zqfQ4mkPp!t7iCr~FbY?}3>FyAQ-_u)6twm3N}(jdP}4TQ+pubIU*8{#7L+o4vs9_Y zB?+>8syG!jVp$_5-3^K*fpkl?bSpr%AB~Rs6v$#X+F{KiUg+fuo3&HSV)vk5n4t*(Ga^ATUer8cz@c~h^VPzu)Sk~Ng%^4=*qJa7 zM( zEKGB*&FI1->P$~e&PTM;ara(SrkI^vyx7hev$|r27Ev;*hoTf6CT}XO>X#-9K>}LT z%5}ir-r)4cJ+53Cx)`Re|VA;rYo*N*}Zk<>EXjRvHtV?!I+? zo;JDMhVG$_VvuvVnqnKDQ@Dt0+$Ub1HD3Bore|hXcD8wETwEj27Yly6CR4SE8jW;& zNc5V6k&tfULwt|T(hyEOK24)GYG`F_ccb<}_8(!oCN0Hq&-@fN<=bLPgWA){#`&?V zvG=V{5Ud3vtk3vCD(A!^;zVbCjBOQ^5ETKGC0_d|-iu#ddA_+`{O23N;X0do(P)6( z`>%pN^QEU?$TuJND%0C2JE)atsG-05O6!mBl0Tk?7_rGXHam^j;@E7$MahpY=S^z0 zDQJ_PIDdCzB|p53AhE_4v3BgS77RMYl31S&JBRlf9Szcg*~T>a#PSmFeQsX&*H>oa z>XOC)BA(oJ zKEMC}5Zm1IVgVcMymWMO`wsie98IYs-r){i!IsDzithN+a?0jjl;&d#A6zMUg*F?H zdY6a3a^;^F%t*>p&mQrTFB-v49fWzg+~*xOs7bwfeMq`snCr0AuHvF(q#tHG`uq#4 zsv9+hoS|AprVY`lkG{EJ9$sj4@WXPxroAE(6I)E2R@y7hWTuwxS8`u_eksaLNbZx{ ztOAAZwh-|e*HXbpOrR&Lq)kfeevB5iN4`Y9uNl92nwZ&Jy*~|ItzMzYeY1CP=+TFP z>1asoG%aC^dwZ^m;n$T_HvI)J8Ma0T+AYeXvtAZdR^2F(W~M>o(lV4ikxnyx_)?U$ zjcw>hml9hSmenKvQ`771#o5DQHm^GMT2xdS_Dvs^&Y2uya|Ey)?h;_1NLR-6!k6f~ zd$_VG|DY4?>9S+Z`4@OK+0iRNZD^40raF}SOgRm;n!PfQGR~e;#f0vY^V3-avZdK_ zrHiCY^e38SKqpf%+rx?z6;J2otr)9^aSE2ml6s@^z7OQxd6)2$54U>X53@vF(FLg8 z^3NA-Flojw2x>xaA=YU1`sy_`LxmW()G}b~qAJ8wo_0cYsJtRq#WO_9tJgF)OM}kD zTO>>a^s{Sy?C)Gs89PGv)Gjat*2&LHCd(hzwFxa9h0kslBAF>6B|s5_Et)bW8R)9p z_$!^K=4*3sw}$n|^)E)>oBv%iLY5b;x1IWi?Ak(JxqZrVOG&&a0%1h-%cY}!dE6K6 z`Gn89RP&)iMrBvyIL|Vt?cDVYINJssZVatOYzj=HOjA4RpXLlZ&0wqgS60# ztaSVQ^h?Uz!n)mY`lq29Kiqb*rP^;)xz}mNLo3rcvx(mRpjX-Z!uawY+udrMJjU%X zJ|F`9Tv-b>tI}@_K zRW+|lz^7{!k)s9AB#zwz23|CxQ)rsr>^Z?yjvh>DC{k)xH*9dI3$*Md%j5&hgAQB* z=~-3gALia1JCYBRYZfhtEgJQB(C^*nR}6T+6Jt-c^Wm_G_2KbRpo_rAB~J z5v2$Z2#x2VQD6xJdh&)E#ql~`fK^AO%|ML637@d2UrOYGm86)VCdSY<=>vSpb_1KdPi3l<8UDC4p( zE4yB{!d~nKbHSfEo3Fr9Y2o)uqRk7>mAnkEmR!`ZC#R-U%v@C8!%0B+f7P`wE~CUOD?{XWey zB;>+Kj%81RKTtF@L<*5-w`GUhXJp636d(;rIqxC`MT`T3-OC1&UJVJvYcztF3$~vR zA{u8t5JAZ%2UwH8zd%ybQZ*jdN*f_x1nN{-^{~n!5#-NI7R7|oO6hN22*#iGOIcAQVZ~_Euxg4O1tb z&#V83s<#h^D*waB&pe-bG#HPGV+;m^AxTo584{8v zNs{dGkR(ZxB(-P8U_7KDS+#19hf0zp+p2BtnMoz7mDK9-bLdHJS(R;V+qS>6-|uz( zuHWyv=Kne8ea?BmU$6VVU-z9LGTTqGf`cEt9zNcuQ7*Ot)sUmMtU5~>0JESz3ymrg zgeM%Rc&3o@_Pd6nMGtH)4W?D0+j`a?eG$Fjnhb#$K5lxn?@ zWuV&?O{Hxwi%Pq6FmmT^=^>5J2^U~@P{1>sr z-~ZJ@vGQphWWB?*&t-?tdPaAPrSV(s>#i+sE2i7m-rE(P#$9;m=#QWOiT473wR|Sg zW|Iac{#QxcZ1Kv@QjJl%goXdFhDyY-4Uiq}uXZ6-=+81hF3*VUK=sNuev5&j+3@ez zLVt!zFMSip@6*lM^ibUPOrCzi&@$?NXK(oR$Uly@ye>H6*YLWjAWk_X)AVmk>2|A# zjHf^Pm6<&dHT)+~86O4JVfsO+9K2Zvb_5!by(}V^fglVxhJl9Ch#>l@Dmoyi@mqh- ziWk5#dom^BKg+Uvto;Mt%i2Fb75w8l$RAfuEPt>%HSZPQe?lC}yVm5)oN>AC#wL0K zmw(}04=BAhkRI}e1GRGav9jc&V=a#tNkGHGv;QJO z=tR^rBJcqm$$&%YRVw5DwolL>OvjVL#@5-$ZkG51D?4A_S@>x4fFv^ceO1jJ=+-qR z=^FRm#U-#iR2k@;>)KY=>(nKCu9X!{rAGnX>422h@sWnjwZqK=FSIxtNgo3uUKZreD@xdG^TzlaX{dkV=Hm z>p{n~!~t;$;rmHg%FEq;H8 z2BR!Ahe?FeaCd6E{{vLX0G3OHku=Pgf{Lg}&?jhyMwuKMd+4GYvPCquTduIsYS&_^ z?}pi?zkw^88Q}hBtG7J(a;w^HA3RNtKC@bnzU=Pakel+7`M;L~n0QpC(dlkXMM{Bz zw9NFj!R02qtX9;3RdcLNboaOFz}xxvk*prxNX1Yj9f>v)(GPT&Xplb@5K|#<2J){D z9PxWfz~KY#N`~7UF3k>pu=MoMk(0b9=+$JdSAc6vtILc_=uB)& zW%WyDwzg@35+#gn?!_0^2`tyLGuH9Ueux0+(Yx8p%R{Q3YF$KHEXqKmf{hZ zJ|wK!>Ke7fH@9GCbdlYamr~;rvv;!OnA+qTEY?XAD@MYd^xW?D`Q%3OHZCedqT3kg zrZs-wuQ$+#+6P&AXqc_JyA3%qBa2S8$FOc6^b|L5kfZkKoa!T2;alIIBrEJ+UE zki7L-y$jso>e_cQ`utjMT6)ow-?pSSUHixmnPhLTZ2v_+^GgW`RD!;)R`R(ikcL4% zYhq6PNE8*brTSD}Fq@>1_l{Xo2q_hv7XrDPTKtq?(U)N%zIfI)6C79Gz4z$ePP-I$ zLD{2uC!g__wj5m@BEkA3x9VS=XbUKNJsmC$Kl8=2v!_jYlz3@-{%Y#Lq+{eSyOnju zQN4WT_o~yix0joZvj{B+B+%}((hzqV5lAE7H^lFE!i$0l0Ni2&>Z-!rskn?{Fj+~t zu+6b&_8)eNRaXx|8sUK(zR`t;?|Mh?lv#~aQJc!E!9KP98+@!QkI!+`8B^ufNkcQa zlD7El- zEyjXGw_{B?@zS#K{F;b#NqpoM4);?t`6UxOW$K_SxlS-%a zCoeY6XdqTneU1$se$#ROhBx_H7ePaTLapzpjH5x)EtvqiiNibk!qB<-@XO5Sfl>O9 zKeu$vxp^Ur_f*L&;uSgh-uj-u{Dz4t{c`*eccpbt^%Bib9=oqJwYD4%Wv6KWSJsq{ zxs;33YscBiIeC)SVR228rz8M^3!9lJ*rff<jw=#d`7>%_sL^0zJ7 zBVi_V#ZoIDns>I`v6$;boRx270Zu6vhUv_UDf5uovkvCvLM=pJv|(MaH(6@7RROe5d|1H znX5Z~vZ}QPDs6ytcExI`%9Lh+B89X@VZ>(|OejrgK!1QhgVcwDc2kyABG+8@Zoq-| zh;7|*?5?$Q_iv92o@l^@r+yU6Lc;tk=7Mqeibuk%Zu`1MQxK2hD{rPW`0B)~Bksk? zv7+T?4ZBWI><(OsFdt>#VpBXFC9&3~(Te3DV}3kMp8uC(RYeYV(8m{D!~*KAXhc4* z3-$U2*1OW7ST~fgWrjdDcIszArRaMfsvUowJPK4uM>V>nBRq*CmnrNC?$;%9pC#-! zZSpOYUKOs1W)JGzQaF>Gono21-dr+KtF7VIK@f2@1}6<^^oWD)#yAB z8vR?X@?}#3lQ+OH`)4eGSz&EK#ezUewjaIx=@IJlk(|=jetV~ojHv8I^G^3X_K7?s zR3#P459h+at^|^}x2C%V27>hG><7 zO$XR79aquesyqu#E0_d`wLm7e-qC>3a3NHXFD-%iu9W4@uP1Rby8h|gHc2B22{pY z4+SvLgA580GOZya&*Z8C*+SM zR4eCGAFNzA(8_#o8?4RQ*3z^vtN%@tq#~$>x3HoTY4M&x=1?iOCbRhOh>M9EyOr=kTcA z*Bg3x6vUr{&TuGr0tc9y9Un1anTjTu|4cf>BMY}*@jz6`Kdh8&Bf6^Gv&OH#Dap&0EgX{=j=k3S;aeDD)TGFIs^L&rd zGmZ+4^GDnUE|k%ek8O%*o%@SL{SQYE3@|C6GXwe$$n(j>H*jh1GCL?(G-!8a+wHk` zmYje!QlGtb@*n(Pu3y;;%-b+@@nNg6>_+49NUzi1##|Lu<0lIk0?Rl5N3JYQad|FRPCiS1d*`Qlt$@S$zY$rV(-yzG;_~?K zGxiw=?JPC5?n@49EZu6pI(W-+MXQOs*{qnPTFr%vN9059^x+f%d;CaJr2N_Ju-yM; zDO&?cYJKGMwJr{{ZXuh}=|w$ec+o71G^1VwL2|of z;JUwxgmHXrX0i$8(E?Ud>B|H4cR;5VOFwx&nf3dZ*ZW>PUUvLqCaHAmcd8iO;+;KD zWmlj}Tm`j%^v)=Ly?57fjw?+!UzxqC!zHV!WVh^A;66>@@qg)qLeS)B8&=5Jkegan zkOTScsmi5MpV4{GJTWmH&S#==WY@|BqCN0XCYJS`T2u+Y5p>pndB(HNs+>0YGz?5! zZ2Tgq%>1LG=as(wwMX6mfQfnZ$lrJ^^JrTs&6*NguJh2nRpM2Yro?$s;-xgry=DzK z1xxvbS(?I0ZFyjF%Yw~%)|J$@)B0{KhxXcF1TUsFWN3Kf)1}_G*=C5k*{?({C`o1AB^wVnZmJ7n@?B+|X zYOoN?WdS)XB$07;oZe1d&6Nx0Mb)xT9UqPH&A?e`%Hm>kcH0NpX zVg-^9>SI9U>)AjC2IMkPH3LRLxRwT_u@7ujiky|`-t?He%hL)nM30wGk45=C+w`(& z25ntBuDWrYn$?WfG}q0)E@9I(Y*@28%^JBzb=#s@ove2&YX7dO$=$Er9V=kHZ)Kgc zXCd2GaibVS$k)nlnvbg)LiV%;EFdKHRU(zxI1AOWV1#k1(161X2%#g3Qi$-?kTng{ z3eCP(&dFm<%e;rL1e0g}w(q>UX12=Vdzba3pL<(GgY-1&`c%*62~R#(8GyoYW2J%9 z5;$_vKsz7g^mEWs)+%)S(rJ{5XEN9u7WQ@Qy(Xn22n$Z6Pd71Cl`P}e5oMpU@1!v* z3hA{aYr;;fK_VE$UZJm05Zz;KQ5M&DKW^G5cv)RQ*$7)d#dgxwZ2wNRx_b~Wb|G}q zaCm-;aiGNL%o(xBGj~^-w-b(!zqbZ~Sm`?#jupbxj^)1QWd%w!^9-I+VQFC@njY3wl%-O80rE6`#;Yf*TzczWBBzKM-myt3q z{fsId_p_?E1z-^pi%?dd85<~3ItW>p-%U;LahhFKa=CiqO;*4xekpBRXJ5RVNola5 zv$ZhJ%dBF_Q^)?1y!o?4pqA2uC&Ml^GN;=kg}Lq)+!88`_oObc1${(m@C?YhP9{%d7t@9!sDS!VAF&u<1(kY^hI?3!?=nzF;$lnDOG$fI8<78IP+UcgpeE?$wJec&Kod9^rHezw_z#aS|=_Q*V*aHrR6T* zSWk#0s3x);bWLH}S#xvhLxjbOqEtwi)R}0@N`mcaC=LmtXd8Wi#U{;TsuGz1%q!Q<4@a4QTX3U=SG*(7#yob}`ptMWZ%8bb?d77w$L-nF zx2Tv3;Ha2I29hcgilT;sOtlamZO>}#N9}tI@3Ur~pp2JF0(0Wh{wPuFQpZcnwl8um zr|PPRvZR^f9bj^LjyaPurE@G3t59cM(nK6jOG%I9Ymz$a?N}T+V#8EO=oB@qRtoH% zk-f8?Dc=|JO$u~9)G)Fqn9XMVZTD3fbxBwho3}%;-?-LgdGvD`Qdg{dO9jPcRA{dm zm6(A!8lvB69e_)%ITS42-$aAy+=UCE!I-x?L3AAPh%$aw6Ij)J+@?f*c(0vqY^F+D zMn&4(%bJF8N$JURbiVuuq!&I`P!s zs-xaKaZjs6r^bu=N|S}VE`dgQ#Y0f|q?>J+i3BU&Skf@0R-HbJj*LK5%>E1@x1kv^ zL6zD}Ob;lvQ8=^8Dc}O@2UR;tHiWzHh&Z-3|9^n+V8qFp&@}op=_+}fr8QQ0iW-4@ zt&llVRWJ*{ZAeB*01Qd!u!_40*P0yBMkkET*wT<(;gKttF!n(F?j`Hb{B#db_-aDQ z%IbHa5y@*6crZCrGn?jWE1=x>WMNZ|KX;Z34KoW^n=l6r7HdjPpF0;Bg}(c6z+OG0 zU_&?)g?P{4nbWk(7|9`7ic8{_DK1CiMi!j(Smf=Sk@>Z;S#;yd-)+T_y05z~grq!| z|9jA^74U_0rNR#ZAolo4H>)8UCz0v$8Me9vV^f@dVLX=|qe6kKu=@_60&pnG&K0EG z4q*~E-AqxfDYbtYI0owIs`A~2{s7jHwfVg4+&`-dvlAOd4)pm?_}~m#xuwr0YkH0% zOj7ML=cSbDsJT)l$HxT1_!^-?YbU0aKQ4l z^A0G_w`=Y24&Tz{Y$mv0Wk*F}`a#^52B&g^U|;$Z0HWh9<`g1=L*aZ+18PkvXaJ{q z{9@58QQeAr-9k-JCQCO{T?-_0 z)p4>AXlj|6X5D03yJ=fnHUZO-yJqrZC{fyR{Dl2y|Q0gsWEoMOUcP6C8@1Y@D|*qI2y`D0k991tTbsNGHig zSYWx!iREV3ScIgX(}a*^Os5Tfq}M`&1~H-0`m1-E?rSJZIvr&aT2r!+^7JW)y*cGT zX^lR*PyuHF? zYGQEHj-w9mPjDV^gG;vf+tn$gVl7g_?eGj=Lj-Usg$eKB9%m|{GN0dG7q`@$v$A!jw!gU+!pgnC3e|cLnXDUn3e5=%?{{E`8$G$D+ zd`GT~z2&_2OKA54y3I$Hku?V{qT+F8luii){v(t=`ONf`%Ac!H+0ltsQ%!DaJO1DT z!v;CDu&HeIcL15e66C1u!cCfs=Q2)ZT5Y6Nlr_r(qtul94ba{);L98;tYXWuV@;F= zldU)8wp3vl%YZIq(n&U59t|Gsx1wRHwHwb$o##ya!k$@BkmSiJ@yq+u7kXxy5M9dx zMlES*g(ktW1e}|7OtUoAoCd{$>HwEsXF2~BA*MbEa9~7pc7Bg1ub}3y1pVyn{Dlcz z3gpEgYERLI^ddwU#8gA}rgvhwW!A1bXwNvsrkrIs$Y@1-Y$vn*7yvH+am~o223cG# z7;>aG{k*Vj{S)VTb<>825BE4O{P1gJ&J`L~$fx9$uoSTSVh+LELcnZz$ZiZl-&5hp z9Y0JPX`C4*idqkixB4)i3vIMOyGUV(Vfoovz5gkevrHAtUN+)Fm)D!Be+xtr9Y=G# zn+3GmP^%@(S9l~}@i&W(^@%*lkIWGC`@1gCnmUwhqRzG$$HL-vB(^&z!~}JhrM@T6^KqrnTGs87R9ue z2B(`VFIa{HBbM=amQW*)zKGvVr{An)TLfxbVP=EqR77#iX5=q4Z zze8k9B$0+99Z){wSqww0jmIOY19_JF3tt;Bj!DVPe!cSd{fv$V8sbZ%Zv`T1sF=$} z%%661hK4HXSSa1(Xdn?m!~G7Cj0EII2lrAp6xPEocMvfh%jWR7tJ+a)|J!p^1BmR3@<& zlsut7Z;!{59|Qi68%NB}LS~)Ombcx^&U%`?^C6YJ=G*3*pZ)*Kdf!EbddhpSxbG%f z?#SzCD9l`b>+1ERhk!7;U|<2b_vVIlDgo7Zei?Btrvv#Ms3C$#i)Vgh7nOGa~_>2ORtlKx%W zcu!->e{;sF*dhHo#xT_viJDw~iSf%(x?V~{7ckKvvZQ95)Hi{xbSU(JyzU3g_a+gc z0|Kr>F*ku!2C8Bv3%^#1*&83RuMMqlLO`(#^Xm8j**X#~o=^*ixX8(V#2{(d+ZqZi zdgYT##jGiaFI6c02SVN<>1$0VXi(_U;|4C4<%LAPR*yV>=g9E+7cyfiRf&HAkxP+S z38rdAWp1hsU~tU%vdY$u{)dE&hQM_9d|GhM0yKgC6qiKIupb#e@o!-1R1Su?Je?G5sgN$uyvO zj%;f=eWGPtwU<19X`342;6-$|F9fsjq&9>4v_m(i;UiwM71Ds?nQTPICR*4}1K6;R z1s{E+EMz5POd<~i(&*b>vpPOfh}E;ohHt=m3@DJgN=b>%I^KDZqH1E8yrxghP{HFg zIJEL5{v3(82B)!d&Hgf|nv%o@ife!icXdqGkB*&%(y7q=M!0FSP1M+T!QCH~qR+m6 z0Kau(j8d1KO$~Hh6{;$>RB7I}WS90KCQ-% z7vnGs$XJgZCP}GlEbZ%e<{zb23r!7uhak9 z$Av^R6_NOp+7`e$1+u5~(aBuE!q_Rba^UcIC+lrK%V+YZsu4Px{)&i~JndmNDm5oP zatsYKYy7OX{1&h&dB?m(wI`BtH^!Z73-wX-jzEEjNZmxgt~E82e&R?9DWhoH$*#ON z?cI6kcAIDNQP$bEegbiV;z4c#1D%&hajC<@JbFQ3$2j0mVzj?i+ zK5vHNtEIp~3Le5N>ji%s`T$jdNY=Z~_bj6jG-cuv{nL%pq6v4?Bui7Zt<7oL_RtR7 z?6uGaukI_d;*;y3dCStlNQbG^9vVW6iOzq9(EmeQ?90pT+>-0m!QC`8lDXjvW6m?C zM!6`Z_YZX8md$lcK*z4lW1}boS{qXKU_tF+aLE%XE_ykX)93yz>+n`%}(Vq#%*C_$#X%E7*?P~0+ITWMO4KT*R6x(qUBugf&c z+jaSW*|e;R&2u0^ABR;$Z>XU~=orA_O_2S`trwSW-0t+=pNiX(6(^%AgEc{n(yP9L z{TWC^I1$^9RQ_wegSiRwaw=h4UZN2)%7@RCod9rub#i`j@-Gp+$gVoL=>_X!HIzOW z_J}T-+V3uSg~#n)axV{QFb{=HDQ2dQBAW{630m~^{cj;p>s31!ZJ^npSJxgdvb&82 zQTv_%Z%0~TITZ^ifU@ZPRw@xdZ!K*67)C=>^fZ8qN3wXAwgH*o6px7|(mY|BvZaky z$xO>VQ`GBPzA@#6o&uTJdC4hV`x^lpggndOu(fx6OQnpmW&iUcqTO?pOw~~PUtSCw z=3y+h6VRAnlbPB^HhWGSsK0*f_v#bYLp$cJ*thFs*NkXYV*qJcMZc_pX2K*kT$YhS z31~+=_(eto+OLNl%*y+ck%?SiD+|swdX75aaG0xEc&bl-PqK%wd}+waP9kHDjUco+ ztpAZFRAPDs>dcnei@;$8is!>FCQUR-qXL-N8{$}Vz4`2zFvHW9*Vp(P)RW+BUA}~B zD#z32Kowp}@g`Az*osoSiOu7Vb&+|bHMYcQ1y$>dyoQ2~&|BWmB9q+UCMmmiY?o`W!h* z{f)mZ4OYp#guW}8=C;FEt51mo0n_UN*HF`k!L!16?FHA)ncj%MMoWSt`C4E?%=y6) z_T$fkM*RgEV#wFD2p+R`auQDH)Lj@d}$IndXTA5oz(W0ZkXPDE*{cfMP<$qvDu7 z%N@?PWiuQ{^Q;-C^cfCdV-GB18DfG3m^3$zLD8#lXcf(Mg1^q@{ly!-kC~@UbbsewR zP5RcQztSypl{VtouOCkYF5Z)}^OMj|6VPa_G}XdA!jl>lo3mvADRA?oVOIuR{-&VI z_b|pt3w!$EyDy{ZW7eyKE-R2kz6RIZGNt6o@#*S-L<{XyxzZLCTbBscow6XLZU>v}oyHYN<)B{T&VY}LsCpH9EXak;$i8*|>BXIye?7Tm zRd_oo=NfJ6?WGzZ2#oDyQQ!@(>Y5D_bkn|t>4ipQ#d3v2T-G&Rc7wRFX6Q7c98De?E4GS5YWZq? z25-zQZ5!HAn(~S$8JL>2uVkw3-_8!&nMPriJqP6vKL!S|(+x`fW8m>$#M4|B@lx zCKz19f!~;GAf06r1T)7#XL^~v*{pzN-cAj{qtTxcY17Y5Bb!oge`~$3@o)zNKKX1` zw!6XrIz;qYa}Ef@7{F*S#~_2~o$VsZRQQ(05K@wx&ZPucyJ2A<`e!|C0Ow@3AI?$_ z#h6gtUV$y2FP=De)ihb>ThwVM)~agFFI&+0T>>mmlybtE!hME#s|BIG&$v47&Hr$&{|S0 zG?^e@v*a>J32{$^3wX1J0#k{4E)f-yEY={oR+ohd-(eH8;2C>?5>&F20-TCHBduuC zOumgMs04d5yC^%0YiN)&k$bkmKmyOP-Mgf-%f=N}R3|NYW08FTyo)WjfO2!eMv)U8 zxyioY^f~QH_1FGqNy;pn2aq@sCES6AcRSF8$=vuEIin(#qxtAA2#436p-5a9?q+6+ z_91sb!lJ}o+GB~E(!SL@(XlF1WBMAtVaTsof8I=u`!EcAzk|A|9maeWKWW6bRR7WX zGQP*eK+G#18np@rlKGC9UkNs1GdYvQqwKF^bnd#U)WHmec!_qZMPyW+xPM5$PRDK<-e6Y*SJzb;Int41CnK$TRyp?Digdc15ExF2r>V^kj8T%?fVaBQOk- z!0F8F%k?`2irP7)z_9IQIl@=8`xZ|%S!t$LalRd^(F$t{sI4n&9K&3vJ-@x}e_)Xa z?1Abt@7&oZ4p@5m-{YU@deEK(6?danML-zGAeFFyp>s3{HC^##itV_alb1LsGL9y2 z9dkX3vm5yDbRJY9#)M{;BmALt#qVmX^-N)xB^3?)`cA)-7O9LS`$V*mjZ6xWXC}~J z0P%v4zJG6^n!w|H^cJ7!z5@*MVI%kV9!~1#3#Y?wAO*}{CO%)+gNDHS`x*u_2jeJk zC>S?$S!PA(*(5k~rjpv6M}?roVt>X9f`(?XCOX&S*-V5i-80xo+aF|$igs}@Ee~qv zLYKH`>-6Y;q@oBaWCg`3kN6xAsv^@!i7JQ z`O-q@H5srZ#6Fv-0RePX01R>o<8}Nh7d_7b+WruCvrE$1a3>GyCV?h4+{>vFunb=J zE1nIiV%Pj$uv3rtV%1F5X3*n_-htFHnl7^7O|#$PtIDP@&tH)Y+P>pu^1c5d1S0o-q8$hz%7>@**lPr>RJ#POysbD~-O~^G=(D}d< z6Ld;|JUV?VQ2;&QlS%SZe%$Qir-`8fw1I=vv5})3efxeWjy37a9#e=Yrrwg6P)WRe z*xG8dg*X_RlQLWUbheXM!?K&bOrS8C97iCr8YlvU8zEpX6UqLF>}6~SVPo1hei|1a z;=;8#*=Z*sJqWb*Bgffu62^hT8b~vMSAnS`Ad;Sgrm{9&{VM$)7y2ZGJ_>;^Ccq^g zI%d7Te$WTsfKs6&wLjS9B4L6g|}3W2a5VA`R@&NoJdXiDjn^ zOmgwsJ|f)%I%Gv0{gKc-!Sk=8Iu2aBTsi~xJ96G6DFQjp0ALH1%G9sBDK%x;`@bX2 z|CFEmW09fv2PluBN$5ByNn{ym{q$tClAW!*iZ-!;cm`g>A&eaO@Cqc2Ri4c@c5Am( zEyuIi@Ugj9(%2--3$2@1eq#ADB=Gn!2oq+GQ~@w95Pcm3-J9Ot&;5nUgKv8JTi=Dc zuYI`4_qarkatGdxK1wuj@GId^7aPr>Q<7;nzl~FyEX(cr^8jV->Tl$~l&wwr!nkA4 z7=N*Vh+s&Fc~}g~v=GGVUhWHELvcSqSP@naKK;yqb_M;yyY#+l1kGY}_G-*C|M(IaQPxY-GeCVD9;_38cznIoSX89f^pyxnU>?nIS z?K9|VWI&nVmN$A@ABkrU5r_5MXz-Z3hZ~(;)ypPzIamUtY3^nup7HdW9rVx}dTWi~ zTrz9`Bl!5>kMIcJTglG~62PPU>KFakBLVz~M_l4!?e}hUaWlVJbH;e|gKc%=`fYV9 zH>|Pu`9|!!)8zr4myE?Tc~P$~S2AB9C&dvgEzJBu$%fOJD@^9DG~=|B*^+t?&kOO{ ztDa-O5I{i)`xmIIAI#VSB`|~gTzcHOYM}`lqUpPV9$r%T9<}L)x%>7^9$dWh#m)UknRucr5Elt& zB*8f@--|#b?O(i(gS2x`j-;VStZ|$JX#;!gm>c~WFv5zGtRz{3la-t;k!-YMzqkXe zw`Ji4)$q@|(bod(5%;5m4jSo)`vu4Y9(+3so-hI43((gl$UPoRke(qXnOZJV&pp>H z+mg*aoqL*S{tS79tSH%^_U$``xc>LYAKOBs#c269>A; zf%YaKe$>mkg;!tPIY%n1bWGwfM_SvEywq$-8W(*V(4EGAb0`q~*&dn@08jX) zg02e%t1j{Z!UTH3rJ^8y_dDWI`@I=1db$v6Tuhvpo1~-}hD|Tp_Ex+t`*qxRZRXES zd38t#6_Ia_>S<*C`_0uY+3-a!`~&+Lm2ClP3m#x+YZ!QVmofy73uN|BFo3V@q%#+8 zK`gjFhcF88_a?xf0X=)NR$=`6c0WS*K0u>_c^BGND9JEF0rFY^7=od1YNHZ6fFHMh zgLB^Ia6|3cC*Oz)2-C6I9V?ga`E#t}rFxN(iVB!d6}nn4djYGjdDzCT3Wg4Fju{7I zdcN{GxKuL!SH5nEq`ItcJV|yuTp|h!5g&?a4YA>bBv-52<9)3w%V^_kp%$gnQIn0q zW&hB%^S_OJ{$b^%$t*vceazrp#Ov+z?f5S~tn3`xKF{`Manm7T$y&czH?Q6?ExfqS zqwYot^?qD=faJhH@v*Qy!_{FU|FHJbi;z@>!~Uxp zbV#4>YFEQ@;_*?27gNhTT_#OvFZb9AuNP`=}NSy4;3Z_4e>Tx2KMm~ygjc!N*jLqszAdA=Z(4JaOX+ zm8-kdBVDuEl>TU|(#EDm5a+3?-@8IQ)#Jkx&-8j!P+QM?^^1W{u`Va&s7<#cp>tsy zJ=>jiV|c0^gEEmr;#m2pO{p>cjdK6xnfLPr%{>Eheljr-WJ1%AdRIQ}Ap-WDfv@`R zqrvBW_)c;CF6Gppo_JR%r#d|=>jc)Gm14Zx9Te+2e0a$=TUMAIVq?;g3$i7#8+dnD z*FN`h-jc;gBGB1A$)^D?&TqQDiyY%QmileopMs)GWPiBwMCUqVRsOa znr%4CZraIlGZ;IKz7-mMizhp|2lwGMzDqRmepcoZk(&Ki9yC3hxA?&G${szigVt;x zwF98^e*MRhV8?^g-^W$il~AxeTUOaRJoFNf?Da{%Iu5tt0nNKMO8)1{w*(033!Fx{xCH(H{CkD z#wOTjl6y<#N=J=Wn&uL4O!|Z&JWf*0U-`Fm%c`LcQ)T)h5uBe3j@e5>YMN4;JC)$l z(6^C8q}o1&RNFgoOJ{O-gwB7U)JF3R>hH*Q$5|_{w6Hb1#&wL57XQE#jds%(lTLdW z)NaE?qd@eHy>oV#h{#vDHU?N~I_ndaor^(*Oj;akW=)&eFEj!RnRkIqB^JY1+}v5x z^2z4%f}HZPJ+tl6Th^MPboN-GyjWgks*#7WlcdfJd4uIX6yX^%Wgh+RD=5T4S~Ipp z*B>-T|N5A15`B{~KXXIU%IY0gqb=)aHoM(+`Vllp?6h#Dh(@+(NqVnhq|N+)a4;ui z{a2>wfSF=+2}iy5Y!Falu32EqGMK(Ef+IN!om-*8#Zil5Pc^Uk+$Ld|4*qC2LWU?9 zvcNOQ)jgNRAGzvGZzhAdX7%YkZv`gR3Q-d!^(NaObC)gATOt%IxY2I57Rq(PiI+kn z6ryXaH(x7r4iVJE*|4Hs&n6{IqP;ftQ-G`Uj@dCptD{zxCD33hF9YOB4$v&q)W?Jl z%y<>w&$rNk^H^`5xy(YZIB9kOEMUap6eMRF;^wi{u(Vh>XhqGSkWLQn2Gyuj2$XM9 zG3~)QC3F&qoNCJf3wdboD)xcVD}|5_y~>s5Sfl`YLU3$c;&ih>M|i z^Nca8n#va)xA3lGDMT#D>vLfcXB;(CY3vh1yX8~0CRCxg4XB+JGLXB^h_2=+e0l5T z&&2e=>BO;Y=^)U4m*!E+GvI+td~|;uZI-{ta>G5OMrgGA!n%5VqIk&ou3oo}la%U4 z7nU??MPJn;X z8euWkVY%7R#Y9^rj9sWuV;#XB3OG8h6$zE*5p<;6t3=;suFQ{RLqoP&YOKh~dZ$nc zEG#94FFVgHKcq&;Q6R$ha%UcItj}*wcdpI4&L|Eg(n~v}H#JI?*MO;#`Ih^<6RlTs z$3kWoA-Z5AR7wlhFJyJjI56c)W6q~A#|}7!m3-0pjH>$6Pc3h(e1o$Uex8i`U$3pW zbLD8dpSK%uQDl_*fOp@>!ceUl83yKMi1VQ1U1sWRcV?s1!z}x#`RP$H1D7~WdkSv7s5KLU0HJxfMrtj)fi_=$Mq@WQ>^vItO+-XK;qq(q=jhj%9t zic(_K=5jv5F(}>?|A!S%ZTFyz1TgW(v+Kdld`h9Dcx~P@%1|&!kyICD7cFdQGH?v5 zay(bH<{6P-;lm&EORIIJt09GG*3;nlz|fRe=B>pkU-l35vJH_vKQlM_Ns5aLEmiP} zd`jM>>g>yVjB)FpD#9FMHzy?x%xtYerbMTqCcdI4f~^h`w*cqKYS@L<2wG905aHI& ze3Mh70sa@WdX$wnxa#geCh^F2PuK36HTCkaskT|lq2=Ji9nZ9~0Bl@SyT@!=RtzL> zH6mePlgYx5{|{U59?$gS$MJ5=?wetlxear_--R^y`(2`o=6=aNm88CNzu!heXmbl8 zBuT2xJxNHCRCB42TP5kH^ZA|IKj%Ci{$>x4&$jpb^?tpcFQ4b|UG;cNp&Ofoogh@d zk^ze8c7ta$vFO%x@inHcPa26SW47vzSkzGytl$WhK0PgUAFmPys&3;jph105iXnHK zpA~C`m-Y+Gn#Xc>ln0d_Pe@GD-eEwqn2BsOqaU3-t;||g<&4FG=m>H)ibO{Oh2hi# zG^K+BlKWNu(tD`?gnk~ND3HKJLA$P6TsHICuzVyymPXdB6>t;eAXR?B8^ zPGM3Ke<$dl0ONqL$pfo17MlDI&aDr3?uDC2#xocQX|F^^NUx)|Xf{gOC`OGk2aqIYTWQ1NSs=udcvQO=psbN8gBUQ8J88Vr z7l~ui5v~B>&mKRZF38&jWi_KIok&s{jCCH$h)2-+(Qa}WP)``G2F|L{Btc@ zntLC^n7IW?g!`Qb@D3OqgDBT0iuP79ne%u74q1u*2CSp)|#5ZFLi zCCzlXRvHJxn8Si5E-7!J`qz=Q;i%*aH0`BmTY&^B8I@n5x&g=pg$PbpBwMFA)Q~TU zAVMn>n*O4$^<6#or+V-S^>1JeZ61xY2#q@!jc_{zdg+OG?diGmjr{6 z)-fEKC19mu^xsxKiDGmCssx6y5d2KZ2f!@eDZFAnfgnA?QfDxZz`$vMawp}oO5mI_ zG(7WP%`b5&vIpE!%3lzl5hyh+d3b;fWyR;R8WEfu#)@;toOg`4gOHph^x3VuEly}u zBZlr+#2TIN4WkNBsGw6;_+$l5+qs|L8 zjXi7A8@7(3&hk<=RH>`Hq&+mF8A76ASi_mqS};)1g`2}etY#{wFrL~@AW_79wQYU1 zh?JX$-CvpTIop|&Ui?XdZCYFl$gZrCx#-q6TAy!C-VKISh51j9x)vcq7pQxkxsWkF|xJPW*vQ z4;gnrGBRU>b}G%uA}ou<@Sqq_k1}O) z=Z+&G%=1VEtVWx{zi*D>cNu?B*|tX1ojfa*}v4y}&I%mE7It{BG?hI7%nJuYx1 zZmJuM<;4B!{PvSSh*m}3=zSSRTQ8}Nc&{me>3)e!Is1vS8S3!6?JfSM-`1-~n+=M5 zl->+R7LnG8CY8V$iMxOulNwZ^lz_5;D-Ve&4-;N85)l|DD8~!Qn2zK!M4Qc^Nh>(u zAwLSiat7U9*OftlfVDxLnhukd@}f3dQA?pz51w5D4<{T&d(I8r6sL5;sSFtBxXw^6 zd@KGRr{0&+k0h0haA*inBT=|1;Z;Wz*`y?Ct|ZhRAJ>>}O-&b!I>x=z!CT|fIgg~Z zpXZ$9rpR#t;kGr2o#c;>U(jga-9#I2vxx}+)Idrs3XewDr=m5*`hXTh?j@|*sta{T zxrp#&D;J|?9GgLeQ#^q)287|j1B51b4X~8SR$3noG*Q?xKG76e#3+Pi1<6~SFP(V= zUrP{~{gklxISOJ@;?G;+?P!9*Z@oU|In4DBREGjhpc(maO2tJ=Di2_IqIg{bIHctj znAfRJvw#-Uhu}CtK#4g&meADCM03A{L$l~wHkf|OeqfqcI#XGC#nlzS0t_Ps#-FKQnT(h@>h4)BGiD&U|4T;S+G6|SPW zgXXp1@ZJ+z*KAUyy>%ET8m>JZqBAX;POFvXv?pIQNVk@`>dmDecGafN^{(B-xSTNB z^wa}9M5tO+toy$e01VP_3`kQ23Z&*{{{hp<@>;5i6W1JXj*B>2_Ak10pVlxP3+#V# z;-r_HkSfpSMTgP2LseLLnew_pA2t4w6~5PEbQ4v=(_xV;T3di_6-K`J^~}d}x?-4g zfvkb#b9#ilLL=9ZY%QVOCw0Z;0rVqySjvF3cfhnRMp_|SG<|XZ9tg8c?Ul}0QmDM0 zU6a|Ri2!=e$Ox{+r9kyuu!T#z!&$ToI#*%T#lk_EG-FwGMh+yrk@W~9x{+fxH8eFI z_g}8LeW6;eUtz3Fj#_(sH6;LqZa_D zU;&hl#nDLRyjseF9=5h|(y$;UepVmN?KN+RHTRm-!PF{rDk_?B^%&bOug;1dG1Z79 zBWm{Nb&)lMaM^6`#sz~$8G|}`q_RPaYPNJ4OBzsSlF5iA+K&J2G%*twVoi%%zpx() z9@-&z|Fz)Ad6bfq_9nN*bE})bZGF9SSseX*bA?%*Old;3YMa@Zv}#TmwNDwzwKJye zgyqc19reQn@ux1@go|fLvCNvdIjaU@x!kl_?YvsTyTb)CoE?3Pxk8sd*1vEnG!K3& zOkqZb@X;X0Je2D&rvJoBc5W@MSHpeju8WST+0IwZ`OU&MHIx~vSxSmM8B5MuMr1zn z4EWh};@BW5<;IZU_oSdX3b(}*D=LKg#5+N*ax~98eqS5I4X>6xQcD_D$!?wOR70-s z-$9|x3x65r_Pd0OK-ruGOfqA~f;Y_!=ZQ`6rGyi62RL)J)LO5VDl8y_Dd)=6z?w0B z>!Pwq>D38cYU@t`tWewDqY|3}uTW(6)4JqgOB!@3#8ODNVvb+XuyWSwWVL#(+1Ls> zOPZa|Cti=BI2XTudwFs2xWtX+&V;CfA$MBgl{t~nlZ=~;$deE z(MY>9=z`sk#DL2*ZqO1>nH5^2Oo8Q<6^kDz3_$wgm5L$Kcr%I_T&gTP&83APKDTk< zIVgV$~7LI~D0uPq%nP8@LYP4@LtN~1Ij0l|F?yGO4{ zqgRM4+Eebc;}M={z%W8Efl=qgQZ?qKQ|7!-&nu-N?YVsH9SW1RBc_yjh_AoLOE|XD zxeu12EPKYRG)mgrP1{80#`K5E~qPq#)a06~y zon#8tgoo8m;39cJlXr%t%%5hT^sUs+AiW3QoLWLBW$LE=I*$Jo?SV=vQif)G2$&U~ z$p^h}oUf_JoGOpr9hB_3Z5#9%;wq+KQ(aam zs!q3-6aP=OJ-5$<_nX7Pn>@@e&;04*CmcgJEgO++3(Y}NLj$IY(!w@SR{*^=;3fp1 znT0(sru~G#jWQ4rLpX(G1p~G7ae-8@>3neO(a%Q<(|444*5^guGESqI9`b3*J;K}s z8|23pg;Yu*@m7dGg0UfyQkaO@K6eRW8lnZE#PM?-Re<~IUP~Pr6W~&Lh$1VfrbSn5 z^fz`xWLlgMY(u#Zr=;Rz9~H~=+NU`xwxFkQ3aOlCz@!o2>zn!#I=L;*P4XWyJ-T2) zYr*n+Q6RK93>VH5fOtrA1Ct$?F(JWCjX+DCJCXr<4(e1s;oBteufJ=?~ex0 z{~(yF&MeS|l;=)#89UwtN@*8|Qg?~m3brs`8vs*e^fIFLp&Ctjv;9-K34w1+b- z)F3V{xrv^o!I z>-;O|0**_80?ir6b4Mo&avR-2u;DU;q%I=Y7k$(WLzU-5ykO`74^pJF4EYcuXE9nK zAY*S4QsSPb6RR@yU}cOFJ%}gvkuz--)S(Y9#$%%Wq*b~UAQ}zl5F}3os|@QwQ$vDX zWM>^$H8SEZM-I67Af;?%p~C#)=6o2Gln#*d>g7+y=QBY2a>wua@v2iPFesF zpX!2SMwj!nGjLo6W=p1!l200J{k7D6gzw3_X|4{i5tnQHOH>C8ss7=;M}NGGwmU>{ zOa;HL(Hl~SY}#ap;>LbP#`%g#m#B-78;^sEK=<=Qn zdcB;OdAp;zluPHK-ChCHLMtSgXJIh?B*t`U8_Hn_D}ow?_}!;a%tHA_DnM>6vw*WP zgFK{1grDsWfq{)W#Z!l8Aw8x1{U<}dAF%v?D;aK7m8e0lCq!I0!T7;!HEKH&bMfq8 zdG>Bc8)V1D<2OeL!f5AD#Q=%Qe_wNVAwV7K&B<4^T`f4O^T#fWrG4WO13M z!o^U5&?wwAo0mY=Q+C+JJYN}rq5~QYYY)vzcpFJSUb6vjIe<0M5#h#2S_W9-N~}Wj zIoddq17xk{P=K?B3Z!8Y;r$;Qo@iCky6LobHQ7BRr3VQr6PR@3XDaeYF_7}<$K>X0Nl z3RvbTrij3G2<0RM2t|=RdCZzmkG?Zw^`dHQ(6o10D&Q;0^}w7*kSe6p_E9!%c3dPB zDX3_p<~vuSIi;t@6wAx%Mo@AAM804Dn3Drs3yi}nspojJ`IL$T&DX&_)e=B2(Hh-^TH zNo2)1kXW%0P$_U5=VoXlL4MHK03HUghJ{E|v$1viXi$$_a_<>BXIiPmKm7hF(Kz4+^kBaiMh?H2{GP!+3(9 zv_XQMC7JS)Kz@!V(IN$@S)?rOCLqNxE{*f6i=k)%TM%pT0hbwuGvmYoEH--ye7GB+ zRCqG^=JoxbUf-wxaxBc2lK?p#xs@ahyr6&v~oQ(xMs#L%Pi5e(D;-ChkcVkV3 z=UDB)A$p$T0jG9XKHordIPbS>(9}lh!uo#&ByY6HKzz7Ns)Zk`k9?2$Dd2k`KqpwO#PF;HA)r^Kk`A6wAE7yur`=KDVanq` zJA^B4_ft5EGK~aH37)ThSPTo9a}N&Hqu#;CK|>1#mm}NpuGFQ^8k|L#k98iMg?@z5?esPC51ydjr_h8 z46Dhau1>mX;T(wp1(>tcSjEhfs9G264br+FYfOAa8PH;j=_6X&M#g z@*sH~sgQ{x0jp+W3gGzyP2zmHaHe>`s`F%B3`Plqerorl`9P=+Jm^SMMi39jlZTOy z^ULO?zL4mkBR_c}(v+alpd|NL4*QsB2VuoF6PLGD}V8B!}n){giraa|1F~L#q#k&Z+OPpgv>{E)A3? z!C@fmSSU{Qd6)-+a^)-N7cNN*Lj(L53^>gVN-0AF7D7@f56N1_sS(aK2?vshX=)R$ zQ0cIQ7avJ&H@(!PWx0e5%Mjy%FKx~Mzl0QTOPV+VmJ^TyVeSN|vKk87!t@xeL`Dmi zsld0|DDX;wUy8&Ju0#YT9!sZPo#r*MD)H96dHCC6(2Achr?0`R0tI5gXz_66m1$QW zz2TEdlu{nrEHC31pQ!|fMT0TYp&=%Ql+s9!98Ahdz!%3$=|cckO$KdO1&ahRZY;G` zH8vxkda8ct!BDb`S8q8DCI(K^k&$!Amtu3&8Z@WJxz%PYqb^@Q@7+^leZW&$3xgbKnVfp<4405;l%aM(bEu~Zpt@U^#aN&}j)58o`a zHTOa=szClNS>eCnpL<v59KDw{@N{#rgJUpo?XD?gwB&5AkMd*xd!b9q9PsN$AG_9*N+}|=6_;QlSqQJ9&YuyT_So zU3TQTaLA>@j9klmZ!#~Oc*sdLeawlr03XN;=Z&ny^qhQz{ZZAo7;C<`b@N#3tBvys z71&P~9==aD#4Ehmsr0y>Xd-d&IJk9ldp}X)@sXP^*LVM1`S0}Of#?5ktG)960V}vf zkcVxZD-L6iq{<@t3(Mc525?W=n1RA|{Mn-ARV}BgPl&DvQMo~nGZn)f&0!VkBf07Wgj(j{mL51m41ZStTe^3Aatwp*fcXu;VFHi zO3r~l;Hs>xwph6WA-0Kj`r6PJpm`zib=)ao?WQQB(xHy9;|))f0=y;>Yd*(Z(n61W zn$I{2Vk(z8PEJ*P#;*9GnDEnt;h4GzvAW^73li2}5yjFTbc?654qxNym7WTQrYPBW zF4QVGXhTLcM_*c8S2$XH@{Rt4cHO42(2I?~M{XiE;m2G)M+gVcqu0hXc&smz!{6|^ zb_iL{3UiSSQIGqoN2i~p9ebu#735o1jCoC-dHE#o=&?J# zm#D&lPhwK835@TT%b)!Vx-l6iJ?|+Pc&avM8SXkQED)nBZ+9Xlz*ofG^^v34LdovM zv*kxsWB&8}#`8Ae<<;<}V^7@{nCfM()(WIQ{qQK(ex}tyqaORPvS=tQFt~Tzc?Rqs zFxjQ2bX3r5;%+Mqrr;DmxHn8Wv*MZ?Dt7XsizDK=1lt=dy?*QZ`L>Kk3|1xmX_tykR}VvJ8w%+PcM=={)Ros=#qs^Myh;$~)eO=fbADEWwGR4my%mhxoDTPfo6 zzEAcPgfJA+o6KM0J_gk0j9A=Caq9{*k3R;Z6Rm`j18fjd27ra5nm?IhkL;jrylxyI za2YsY_*(8wwdh;9O9>CmW#Afer!!HZ;TUGOzSYiqF>YG))YK#W^i8Qc^8~t^otZv# zVd6xLi2Y!O$tpryB{xOPD?LU|?SrBP{zY{)ZtAIFL#3!yQFa8ngF@yB856B#oM*<& z8$wr~3URqOB7rNKtF829Lvg5N4fM!sK@ zteuR`HPw;l;q;%&3a4hWHLO4CBF$?1^X6wAb~1NkHDSFph{0exo+6e*4mWR zm^U3mQD-hc?!lK9=k-pR4wt>kxThrk%yVKjGGUFdtl$o1M=GXi)IIQO0eM}2hC)T3 zx!@X|sR!1=eseBZ^!+I4-f2tx@t%{KU3yT?Q(;`ypc%7HXXx+KERELKM+7UaG+d$( zSBdMVTb%}XHhtZ8)g5?aHjJ&43F2>}A|qxrjA4b}C1o5OvZdl~U)?_^)c7{q{PH1M zVOcwonB)2e+^z$IzLw`EMdl^h=wv{#qTi>&$LFW)_^gP8n)mLxNpY&_0pbJ?b>9t3 zlQ(Z@Bf?3IUfB-c?lf&pO8mB`AYw|cz;I{4B<<4JNq*7c)pha2@pJhT;YQZc-y{Z9 ztg~HXD-A*Ae0NTtj|Ly;Xdne`)EFTA!iD&#M6IHSbFtD`kZIJZ-LdC(24pmJ{no!GT+)>d(>=x zqd~}r`=4b#H1QU7ygJhg6FI3RiqY)W9=2f%e-n(xzMD1j_E#-6CmqffFMq4J%Gvt+ z$rl4wF@Tk=iLr_Y3W0@j$>w>o8nRgK(B`kL`P(o)VsgiRNgsn3!@FAA4z5bk+aWkoRYyJ2HBuEgPE)z}!Q{fr132;6x$xw*AC&Y{vNCK6?{r;(x-A!V>RDu87(EF}5YKfc_QPQiu6+0`{ z8J_gD1yL7Z-AiC!A+%+uH#k@=Rza*;aU&D9)B}9M4IagD(a3F{v9ClaCDFw>G1Et) z93c=3Bm!<3H+>AF@{8gniM6*9M5D(n$3(dxUg7LQg6T!9>T5!3pjASP

SKOPMGZ@E;T$W)e8px_uw*7=5siB5(I*RHs&%NCPdZ^?lB*ACnfN< zmpU&732|QIgLl%^3e6}S5Qt`G3i?-cO7IIcGu1;hsZ9c0i&m$KGP~=8tjet{PAoDU zeKSQGj}oTxv!bmw2lGXwLU745%U>8dQjdvY_@&ekylJVpRA2wp1JT6_(dS}cUCx7< zH3aq}5um)=G+Pwh*AMO!m#V-mk_6KmgiOP+?e+MlURV%~A42BmD#Y`{05ed=;yodD zNzX*PXlvw&)+@v?v4F62kwP62h2v=rZr3K%=0+)sMO9?FU9xW*Bx&QW;sQUjTa4XP z!|nr9As}$2=;HK8-`A3iQ6jsB;9DdE?iB%7ixvvig2zRH`g&gn`L89s3f_{^l)Fh( zI5gji!&G8$1~M<|#!!ii{X}M$Xa}}75{B*^f3Pw>%l#u9A1qWSxscMD7#&Baa@$$Ch9vV%FGsFKfsM?h$TJ3 zQ+EWG5`?5ect^eQzST1u2qmVJ$r@M?Datc$Bm{1+8Pmjl!HVV-<|6r-ne+zfqxiJL zs!y)O1tcckToq;ly^P0Ie60Y~!2frT&`m7}O7&El3h5GAmq+FGy^Xw=!XSy^IG-#* z{7#;qE$>U5>3p4c50xCg5~J*7I|S?zcPMwf$A`}xu6YrrOKc4b)V$@~=oYGKSnqk& z{!I6YSfOv1AH9p{CO*?E3DTIZ(^xLJVrdUk{bl%y#cjm_V?F$cm zwl~tvMZ$}`)$!}6gXATFJ>rUsUSZz)#Gk+;4lh$IQ~k?>vfBMKDKlVw#9QQ0G^W}dn+dT6%$1?N9?&cA`>^FqYhN8wZ z#E) z3>J}N#_95Z2=(&3I^fE0&9{<7wxy>wDcJ*k?iTj$FIDaAj^a0s?fF-p=r{_T%hGY+ zA7ske(k-%N9A66Fmpw^`Tu!y|DpgJK^@dy&4}4wfO>zdm38#NiXc&0Dd>$)iBo!N;Fv!Nj1M-HSW{rg|R2ep%CmB2&#d zk+g)#R24+OL29IEI=e3TdTNiS1l*61Dh2m*DFrO`nGH(WOFiu>IVZOMsG^LqKY@xo z>@T30eFre0`x8dB(Egxa)z$vtuPR@-wsq7{m$uQWsLQ2X@R13HH>DH=a4-Pam$_sR7Ir;ox-m+S zCuZsm(C7Ye`;R2=(3d|q)SrFZlXRW|owshu?Av>^_$cIh(8adM%1=q_xB{-MHhmaq z%{is;T!H3mFsyJ53WkX0Y4+$1GZsYqy?pY2uuSkMr9ku}tm$kZ?DZWzvFLn$GcQL( zhQ_v}bG6XnSFcd7_n$({Cm%kBg>Q~b_K6LTfeOH@&;boo(UiuEyuNCDgN&~Nq&;#$ z(gw=ymbM`-_Z!N^5edirv2AdKToB(+LFNqs| zmD@j4n1@t|2FC-?x-MZ1587~eG@roTZ(lGqq$KO`I#Our2{I=ArHAAk7p!dD$Cy zEEtPPDjDTrbrI6PR0FALHa|B${#i!P5$k8XHRgK_9`jZ1|5u;;P1`ZIBML7?Yww0< zqP<5oiwr(i;Wf^prw#_KGwZl$3NR2&3&!fv!1`>3pS<>YcPo z-+1ePX<#8V4}5TVr185%%4ou=H=Tz^UKU7pYh30{+BuTGlZQ`nNtg-lHQAi}*LMLD zp7~%yb4$FxPGLB6i=zsuv^$~~?tbBIam<0TZahvQ{tjfmOv-TiElMCb zzutISo-w(`8mPO>%RF-JY-G%Y`Da2w@Pyu%#(z3n@3}HNijq=&jM(PFlCloTha!tP zlIE5EIi|NnZovPDCbw8;Yi1vcGFl#+F}@O*`~13Ph0%+>c<+z73x=^15ibu7hKISf z$&XCjmNa~R{EWA5%$;rsYi{vPW?#__&9-E=46oU01nwtn^_%E2+B3(Lu9u;Vcd6Cz z&SH`k(?JUodML-!d_OC{mEL+*^PfjhOmL;P_#W}s2;~g;+x6&X8z4Wbjy)Q0pSB7kkMCZJ}|B1?bz#Th`HL)k2 zR5oM(GJ(<7#8PLXv3#S3u=pRf>XnyyBMyyxuipLeH{5%xBe?HgbdK1vm-D;GQ4^lR z*-i11M8v_!8+HAdEsd6#{Ft>z9o+_>v@cYD`>i@@UE!sBS!kty>RY1qd+pillX0=t zJ|@t+dqStKjs8@ZdSi6t>etH*Z{91ThyTKuyQe14ehYqj!{W5@^ZPQi3+p`^z5HHc zj|BR^JM%5wzY+VxXZzg+b<6Do7;CrcegCiR(*^0mPj;@%3dOL0Y+uQExPQcXoi}Fl z`@zWT{VT7Qk9H(|HE~(lyP^3tal7{C!R@sl|AO}}GylE4BKzcbSKMj;#gxCp!b^V& zuIC3v&HUS@{B7p}MZ|J@}Gkrgx`;>aw;p#hw>SiPKD;<3b zGM1m+mu0y4;SFVl@~qR_q|fZ%;?meZZ!GaVyWX?)Sc~VGqrD%_KRn&;6@E0qvh-PS zm#NThZ=gZ*R=kPC52O0oO`y;?>ez!1|7VX>gidjy{_b0yh};v=N0#>fqcNURF801F0SXZRv0UQ%H8N`3E%3$_q$-n#yC?q6>N@?I<1@TK|^E%_j>1nZu>ryp_c-utt(-Mx7|6l{D39l z3G^{VzO%01y!2l9+4sxuuWkPQk3+zGPw<(O<4JjMv8H89AB>T+qX!g`tnQ!Ffq%5t ztlV=lEE;eo_yLwHOI&~{+zhv3i?hD3MUJ(9>0(*ne@{y^ao#TKqLuqq9*gEZywjue z9?t^B5dMA6hs-wT)6kJyM`At$eIgd@kgRL>F2gU~oL~HOdqWgE)Uk10?b)48QKy$3 z*DLnk+}#qDDYKzp-2TtEOE^Dz5#g}VC^jU21{J|`RlS&&REPbE#<`tGT&H>E=KLgBXc*i!7f)$ z+tda3=jmjF?J8y`ZwOeYMM?UH(_9dbbXL0@j9$J|uSU%zv{r^=0l95h;g$GvJ;83x z7B%AjcQNVv>kn;?Von(S;_ElI%Ivn}vpA9aKN?OmIV9YIy<**lcNCpck{NUX0)1rj zOev(K1tE=3+SmdCCjF)#H;Y|^FJ;~7P7-1;1VYi=(u{tO|76_7XeKweg- zK`ez8|D^ns?1%zGYFG838eBakSOkjLdFj z!Lj3J{9_x|%1IE?ASsVa|3uT!3)Q+Ah1o>m2({hxCB${l(N-3b^tG@)fcRLjf>tGR4By#H27 zN5UZoTxgs@qY=Ae9qfBiwu%;4`J;xiZp9F#MZ9wP`0`vURu?)NQrhyv5=@Vms!HpgQWeUHTHSi*ttQEVj51Iu0{6Y4o|IgkVOC z#()-WHXNhrrFMf;Y-yR(sRMjUYsZI}d;;D{BUMZ1>Z_y-vraVE+;v5p!H>qtq}t?V zhJBav^azlJWR^t3^cuMCi+3c>c0?aN#gx36*Hy<|qVvO3!+UvSCZI9K6qEqt7Qb@BP7 z(kH{pA=&iPFLn9*y`K&>kUykWx$w6M&9})!@KlMs4fSKrWXCutR-COpyyhEq-M_o^ z)cEfsSyb;+@vi5i#s5A2K6&ngYmElaKKrS6lqwpWtQAgLW$M3DJnh><1~PECL#4kt z#!$_SD=`z^&kci5ZdOT4cjsnF`M^i7ho?4H;O);vsb~)zbvwgp@Qm0;AU(-7V&2_O zZm%8*NqiV=)#5|GeQH2>8R2TDq#wH3D1lFybegpXVt(PXLZ&PpIc98 z#V#)zkN7ob(*aSnH~f0ywvW_M zx780w3K_SgREzkQd-?5?A@|pNOnB?CG`~wG?skA>6!)6`qR-vXSBoO$^17wPg6;?{{xty$ z9i0C8kP^grU&p5)^V%lo?MuYQ!zAp7mchXWKjH-Si;y(rNIw)je@Z7Tak&%Ndi=$#-DnHnZ2%aXgN&nh$ zf7M@so#%E79Cq16TjvB{wj6tqJ}J|DUx{wTBwu3V`;*YPn>*hXawC~!+#=C4zZ$pI z$ro+$u66jB(pM@2{smc_K>}oIgF$JJx2Zk`8IIp+8{lDA6@QV zJ*lu|<`oyI1eb!zzb*nOsriG*lj71QVy1&)8vSBmmgr(%J9|>p`8&#)BLzQTl!KyH@$~62g zwDr&3_OQL3Gf-qujwv#$J%a1D=h?yJ8_U_24F)=^#JGU=qvn0qPyTo+U-9Hl&>#MD zgsHXDuOPg530X(_3%&`C-a1ehJ9w5W7PgnR_*W#RRFv5)7CrMXCjD;`OKhL>zOAO4m39LOnRyvIQu(UkIdJ`0 z=JHc4uk%0ot_HN{PNs#)s)?m?^ra-i+i|6L!C(2e!~V0d5x|f#)7@~3a9$=DB8A5_ z4jyyy!sRM_S5L?q9X}L`w@FRUZo=!4qmQlZ=nr}v@wGT=s>N@OJW}V8oboFPcA&HU zR5;c_VmeJ$D_NAiNMKKifDa_>*&@C@;)`t};KxMQ1|nNu{%i8zuNmOj9EI_%Ze@)C zx9$_QjbYrU@n7&|ThkkvXr=hB)ZYAaDKP zuH2z`zB{=Ui}?MTjE7DL{u1#viNl1llt&2xdpd@!} za|6}m#UouAI)9Qk(hjDXRDW3Wp%#WNX5-TbUNixB6PXo++%9o}FGt+J*+jjzd-0Eg z>GaHM>+F5XY&kN zSGcix5U7QKD0anW+}9rgyC}yV8lYRsgHqFu;BP`Jw;%bMyZLjwxeq$5uQ$gi;w{)3 zf^kW1-?fh%)f<-@5DE1@wa5|wZXvU`BTdG#p z&~QCj2LUUBMV4T|q5{Vv*-}o((+KSIO$993+oURRE)25 zg1sQV_%`4hQ%l#F zS-+@r&2d0_O{YeYm}ON{q)=ieC6-faH@O;jTvs~VMrPSoq}f&($B^|^Y?claD|eV; zh6eNoYC0FxGea%ko@68E-7ZGrZOd&}sStJKyF5-zz`=@AMMANvAW6RALwGuDu?idkB$S zzn*3LHR8z8CQE+!ik~hn+frsKq_yoUKpYsGG8#5Wy z>F)AtsSmXZOXr?1Ju#3-(<=SyE|q1^ll>&9>v$(&!T-wk#Xg_+_cP8uT=>@>u8sRe zDOBQgx9*tEKhf3*7kf(1UnJQmhs`TEHU>-q(VQs5x*JWr{V=Y$P@Ag}xJ<#{to)3I|tlolxvv0WP@^Ardzf7YF==j7S+r>i!Hi;gO zQ7&4kRC;L+nKE#yA%8J;!IPI#GY8sYwCv>4TgHDns|S}^Qwzt(G5KUuwHu6)R0nes{ScI?=lR(bY9X!Y&C^`Y~n ztqoCC-&`l7Zr@)1^KZgh>gAc^BjA5$Z+rw(LKm(@w1yn{k@WV+r2Z`hv%-~Fi0x^o zazjV@N|usS@e13}rFcln%(ba~O2cuaNs44XRHx+1UzAmQjvyNviklxA^yRNCS_z8< zma^2kHadEVu%+u(AN~DS*b?NX^(ddTP0`w4k5BwA6)LmFfhYT^p}bk&g6H+mSN^;H z>G0i1^$o;+zmwsUUFyQ|O9vsRgl!o%rz*a`x#)AOelwvcwDP1yQ9zTHvp~R}gplo1x6`d!*Zpiv8NTT8Z9 zEU<=z65bT1s;Q6$`89D33)c}`(cugIYO)P4B_*_=!E~Dv8#M-9V7JbOP8YCqU|!Y1 z*I8bzHIv?`b1#)jEPHBi@8f(lET27nD1)q-uIhSAH@)lYbq!Xyx|Mh?cnBr_$261I z!%W66Oy+vwb(t3YE5sK{dKsx29|^xnj8Ta3#%185zB_8UpO+paq~S&<%QJnkQG(pk z=f*;Nq`#XumcLOwG!AM;xJs0~{BlbNg@0X?o*Z-3&V+BgF1t|gd_lRL8os^kjtcw# z;OZ^BnttH_U&cm{1u<$2#zuEa%f^6_(j_9JOIid(B}R9Oh`?wNkWxWW>5?uH5lIOF zDHY?Rci-Rl-gED{f5CS4K4<6sdOe@7$77he*k9L?dNT!ST@c>tRx<5B;;V(9zC%@- zCF%Z&5Vcr`tVXORWKOE zjDika-kVw?{DrQ$8gvhjTuweqG|q_^zplR*%Or$o0Tm~BrPsqLiuS?N#a31f5~?H0 zHvAJMeMN+MD+D@9R`2-Lt$s_}vF*l7Lv>T!oAhz!j;y%iFV6XahM}74RP#klc|zXt zzZt_n?+PSE;5%XDlwLjQ>YfVrIB#>9m3pFJwP{^}!DTZG+&E}PNpa2S?vowCx)DbiR_YQVmfW#P-7dB&8- z+ov-5k+NoBsQF!Xpae_4VR(zvfj=+Dgpnb+o6Gg+Ndj)z{_)4?+z>|-rw@-r80-(5 zPIJ3te2gCDy^4t7+`qe0U4MOtm?qli(!kV;<4Ax}*iAT$Q>d~+&<8Cm#$7!|5{*DP zUEYI{c^yU)qoA8YNsMpwN|%Ct+NkC{5p=rJR@G>B{{v3YikxOv5FN?ZORJSNv)BNt zAx}K&a-%I=V`&YONmyFzd?$4D@xbXRU5v|+{pja0g9EYE*Sk0 zmE4`E772T6I0-RYBITFb?IGQ|c=Wzu-?zpZ1j%cQAXS@NH&$*_79YC2Wcq}3YmlV0 zhKhJ&cUKx&mRCXl#k*`oXXS)W;}>q0g~Tyl9(O1+-uNg5>#~W~>$5i|Xz^kQ`y?NS z89+{7!p(Xui8|e!8*I5&-tKnV68EnuyYr~ubNCan5gaCCKx5VUi;Hl>rU{bQPn>zW z!#~RR`1ud|^%a|u)Zr796)gE7o2$CqzI? z*X;YQv^}W9Ol;U25ql?GS;q|FXH6<`%96s$WY6QjdG4(r^Kmaj{Zw4Kwyx^>xK1>U zE@t;sP<1@606^ul@*}=Va>SYQjftPbs{EDjO3p&_vEdZ6WF&=IVm%QPfwKhJsS^2Q(}eCDWh-TCyDpp3)oVTsbA1EAu^r%eYW@d ztY1^8h9NU-UxYPlsy)*N22*snt8ULa{*F+yNN&IYJyo}zgfZdpSj}J13dB?$lJuQ_ z@4_5iUON_jBglh3$Qw6(l`eK)fmDS$y3NoWwv!zly-}sBe;|%lwFp$-BjMHKUuaaw z2{lh2rW7VWF{$>Zfw}yG(wtZK(o-R`UpCx@b>mbr@E!~b7{+PUY3)bA^yiYk#>~YA z3WD6(y!48VC6_mnWXM4W6yDD8!(s*31Adjk-yEqpzdbhx$O zPsabiVMFWXQF6|3QY<}u90_wlG9S_dG@EBuQ2=N5nFV@4EK>fBfc!TBi&uP4x>109 z0o?9&bn|AbM@v7(u z8wnx4=~*HwQ?vtywR*PE{0Zp=Q$fA=o|r(tUZnR&bbxFPg2oMQWQrO^8+dbq)L`IGMZYYD~xbnV&5UH`6caTc-8->L;-gPU}zrUqq}Y0{4O$-X+lbO#se?g1(Vn zcdniJglrpBw;Ysi`@lcDsqu9}CipLR?x7rMjT@lKTiL@)QRN1#%bl^vozb(4{c^zx z-SI%}d2rnETYfH0M#oCT^jQnyh<)n^4gR}-)LzTmwI*cZY1%sLpA!YuEtKfiXbu?0R8mX1RdN+PiXL8Ve;_vT3= zOHhZmy69LeGx)&EH0I~Am=rvoR+>YX+taISnVrAX3G!@M$-VkN)Dd#R)f z&XZwO*iE9`b@lTM1M3{au=|<@6KOOx^Nwb$N9B?c3E9sCvSw;*s6Dqzk_8id**csNHp==o8dm2w_|96TTHhi= zK1!ZFp=X;RD&2Hdcw~-R#bTBRMkZ!dnwNZbWZWL}7Wsnq&_U5}aY8ab{ z+Nt6unQ@RZ`FrpFN4m@3o5?{k0 z{?)JhLDOLSC20KX>+P}#tM#3-Y40#c(a;YD6k@NRkM*o0sK``wZZEkwQo7jyz15nc zbT2G1Z+d%fVwO!q^gbHqoiCNaqFH2C+e+4BP9auI)u-@o<7ZP3tKhr8nYDyB<`;8D z<{w?-NHGv<3g?LvhfZ{AG&elG>R#Oa#P5qNpeI`r685Ne4mm6!DxXd5@u7WyistMp zo@Jtq%G5ig1N8_2*tx1c8`ek6BzJ49+%R|RM8)*!K)bhb?m#3P9*!k(=wdCHEvqj-|+$=I#0$6%obu!*sK;;+$72;qO`OyIR-j zFK4^65jQKR@_Od$jNCq#Nl4TS5xWC5I!?q8cPO%&;pD#Ri7}4P`itMcsWvb7_^dGaPsF>+pQNtSNZVkAbv6J7+8EW1Ku;oEd)Zu%&$>hmyN#G1$WKOA_?E&sC;Qd1 zpUazD<^Qle3;%fG{PDKHrO~tJM@8aGw;pwhw|OH(5qpuOi^!I+-e_6Y{?=j2&jFl! zB)4IOnj}C$6WrRs`HNC4!4U}*D{&gS07kYJ| zNpg$aDkb{BQ}swPdY|pdq;Ea1{?Hr`qNQ9n#W5(}EPNPo_utne zjj}h-`97!2z2c=KJw93g5ZE1XS0HQq=ijm?pN-tB9tRkf=Q)Uokk`uDvuRS9@|KOP zLTuo)jJRao@}Q6986v{00&FBm*fmEyTo0g@m)B!Hm7=8Oq14FH%G<%*>mX=A^31;# z_F#F_TnhVBt=~H25pe{`|HR!g71zjC`sK!*jF}UH@~=xnVrzkc4H#8wLS5wOE?MF5 zINK6DO73}}LThf+HV`&9#;l{g!T5-u5NGBPWnjBwBh;?Angb#ziDU_W%eM=&nL=Nc z3@WdA8jKdmJ@t2DNG9MFqH`SMpNjf$BCG8~H1x!(Ib4%{$%Tu`718E-7CHgxfGl<) zr6OmxRMRI*$5_Ue0&)0!tWd06I;dM%%ftFqJ-^stAmoyrtJFvJ*~zAvO}xj}%>B+? zv!@xxcENAmn+z_@akJJjdW zaI^OxHFn4+iks2S=|0;UUKV9#imP{d*~<0E*@c8!+}7o@Km=j>0egkFDTf8>bS>uw zCL;lb3k{nhz~T&&XmoNzRI?pp*F?7wHYiuv+^Vhv{Lm>@>NK;ES#2|t&c;`G*AvUw zd#+wTUc-1Ab+Q9H%ylK3n+5--rlbGW+sM>dzyD_G_0g=9&byg2elat}xYPYyfn2Fq zH}ME~2{!&wD0eH>`2C)w*Um?goWa+f?8tk@NhL=d>)0z<7;`bE0QPLh0CUM1qGmYl zE4I_b{Z%!;9MMLd*wzmgASx*)Rw&Gdx7y=i(6TJtalBX|#-51N%W3`imP!U46LWw? zroY;qWDmbX*76eJh%8ICy(>7?%>@r@k|>Cx{hK=KT(!42(682N^S;tSTaSZcYJ#W$I^dum8wCXqT}~>0Cjgv1b-p?g`BiW4m0k09=MNume>L6czCU(x z{pyU|RK9}t75P637D|K%*Tl5kW04lYtRS+IyMe19{zHYaz8OxkU%e{Ozjz`fbtmhT z9yj6u6>>MZodt*JjS_?QW@s1n5xZGzt?tRNn=Xcr<&tv7cS|vqFK7Ys=iyXPHRZl{;omv{F04vp7#AmAx%>`Nlz|y;)IXFOd z?-+G+*g7WsYX;tzh*NOt^_^vQA@f*ETJ@(7rz|Xmd%*+tF+kl$vy>M+9R}S0KJ@=T z*|qq#)04uG)oX8mnypyz*%gI4TQ+U{G_2uSmxbNekg)`G8O)^L59;`Ays9SWRaNr2 zn%3Mvq!?@J6Qs{MTS_1Wo0znfS2wvWUV+RF_jTc?nh|}Ch7`Z{ZTde+%_?Kw#978} z^6iXAZ#p%GBh7U^(*LLHmkv2HFz7Bdv^oE9$!@jz>=9Xx5xP z@w*JY&V6q-qHT6n45lxBy#BW?YxTe}W&ipUj^dB`moh{7dA_UC!i9UL|Gi3y(!?-b zvQ{z(bCdxf#6Do_H4@8=#&nG|E$gd{)!O;j0cswjTwHVVLL$t~ExoYs``qkkDq%DE zM{FAkx4}oU0jyigQJx{b(xA`*oVW?vN)YGzKVXZx+?DK~=3GEs+D~{@2UEGVugp_~ z{ayDcta~x^bKFAwDqKi=fpJW=FGAW#U(%?K4JXeiR4P8&<_M_~mH{UmwGH|pk6q&i z$895Br=OUHsSBP0(eG#m%y|V9x6o&xAQ5VC{1u(ZiF*#pRuR|){{)<|9P_Z!{t+IF z@B=%2A@og*$Ph)yFuW2hE+!gQTCW0 zJk5(Zev1GCxa7nU@j$@z6zxnrm)sOMsGsv#0El4%#%}V$%VpO)1W4aF%|Ait{U>`x zr2RX5GZY>UhGVKqLEw)oJTxW{2g?O zFl2CrLs-&Yd&49S8=`f@{ZQ)suW(T;fCCcLq7om#OGDm5f9Er8;zHZd#s-4d1A%fA zV00jYv`I_-+Bqo*`2abXJVM@!Hb@o$<42rYaVuB|TV!zy{oxC7lnbu8Xj$MTb79Qa zWQTPk8G}4i+PdgVV=YFAV!Xd;{(J(ZdmX$MW(XTM5{caR)bNcq9dp!lUlMoQDh$Xs zdhF`ir`p@F+*_IGM7#9d%RhL0<=w7IB?$thQQ*hP2%#l~X65*B8z?{<;>ZwzE9F^# zE6)y-oYUA$KiVa`~{d?oopEJq`Ppo0-yY)xLy7qX#c~v+z)HNH| zkv*LoYdx_n{=JR7!i1okKCr7B)3@+pnXanvI8B3?BOqX2Wdp>s7Pp1|sbVFqIL9X+ zDlUI^qHHC8IaE^V>_l;WUA|qAXT6O(^mJ=ZULNjoIn(x{-F}PGA&@VuV&$Xa;a>}t z3dfXt$1NVFL5NJf$T%ac(74x*iKt(L6H#VddM!>&XaExS(a%M_LX$X}2zwlav243J zC1mFPk8LMEbTa}5EQXcuX<7c$YF`yt|1FmjE<0;X+ndBQYk-;Y;yif-XuEEta1AK$ z!HwHgoC!zHaq)y)7j3(RkelQViIAJt5_A0zkN$1gmIaZRhI#hg_Y05ohHLhPgdLO- z^rE%rT9MVRV{|UIp3bVY%g;vd`U|N(0r#jAC9ng1StR6DoLs&#=<0&Y;E-Kr@2{RsYjoS&!)rGE9@7Nyq_tK+4pJC zj|Qp^oA@(_41wQhE-W_Xb%m!E7cDg3S$Fh7}q0{T^epDz589tq~FDLmfGPH4zb7FBO( zy*_Ri04z4JK`z*uXyYS1dpUY3ys^10m4RIbpy=KvJ7Qt&p3L(?oG}4kUQ?&Ui)Kz~B#PK@5L96IR1^6P2^FT; zDS^)G-=7-?eEi>R`+uv}0cQ8V{963?Y_-J>^M313bjBXO=EeXxH5Y@1v86 zfsJe#DJqNVS5`-ErRpJ5^+!91-qAPM*@`G9yXv6t$ti?@Tf9Gg0YJsX`I@U+44e## z2`<(O&KE z*Z$ta^))=qSNe~!yn?xv5hp}YZ%L^1uCN2bw|uSja|vYL`5ba2l7JoXRVCzjmq3bo zq$*GeweF6tga)HndYx=6Tfk-L<_Uni)gsl8_Dy37M_KKWrtK$4K&wQ%hRDwsx3#9C z3xuiXZjVIA*wU-T$8sAV^1y)O_Lud1iajeRz%O^pC|i;OKuM4|w;ntwY>Al5DlVYb z7c}NHFWMMoOL?=U>6ERO;UxMsJ=nc?BESkPp{2OVI%(6VScEv@SbcD*}h+4%4( zP6(8P&B+&DNoo_;D1 zewh5}Z51z~+!VS8(#{4>|GLcjjdslNQzdw3%+#HJlNX z9%e$ihA+<@1Iqn{Hz_j6dk4m{!ZO(yRP(9rXz!63m;^SGi+6Cy#G=dG#Dl2wI4|{h z{rDcVX+poK0%5iE^FKkaX)T7K26b|St{-HGLC?O4bED5H;B6^yp0!g@{4bC@3rw#Z zDC3d7n?shA(qlXkc{_lgaNG(}$&E$E6G#%KWb1~!U__Z|supHnjQmvb=+63=e!*r3 z9t?xjOH)@6x^6@(sr($ZhBRlZ&i2+Lw*Sw$TdX^5laUPr*~-17fK|;j_%ZFqNDU2w zUvSmTs(7Jh9>E`zR1CtzjJAC}10K`pX;yXDSX&jsOgXfl3Vs*hoRzc6lhR>y`KLJX zQ%R(0NoxSJCqn43U~3Bpj)_mG?cj~vyhmSjjr5tijQ7C<0C;#S)mJ?8C}G58zBpG^ z2=i9LlT1-(tB=t$boiq~#&vQ$TMKe(FHAZi$I9B4s&9Sejadv&05 znxVb0@SWo!trh!(@Yctvho@};=_H%dnLoo<)WLCv8Xws37EEY>kWqHqgt90yX&M+J zR5VTYOpw7MZTK+RJcE$ljaG(+mNZw%P-yI5*Eb=$3k=aX6Jk#>9(lX;4OsS(6*nLokVBP!lqJ z8L`z;IRT-UY)w)eH}1E@g0+*T&wPs?o`>baWiHWaz{bTQSY7OIrj#&>&=uQS3#od$5PxEbv?(bau#`%6sjaR7T7 zo#xm>A?(OXg|BXvccWlIP4Q7|EpBw&aOqSTN*CJI$&yz#j(EQ{^TY%XZk5Q;cchi%zI-0j}|74*5 z-3c`Q%R0V}kvK3}Xw{*AE%4jG`-XJg1GfYPr^7yKNlLb6{%V!{poZj;R6JH@s0Mgm(STypPK5{VeH=w(Z~R_T?qX?Mx%tGqro{5A5hqGg{jfcBFfwE3>Pb z?MfBX9Sl^ifw(try{zrh!j34Fe8p(s5Z!2apZVNWp9!(>#zUXLiyGJr#5E=7XK1(u z0+xK+zBA9t&b!}6{wD9d*yrYA5buv>|JyOjJ;g_OzYMeJ_TiTBfX^>^Kb@N9jh?>h zA9s4_lkrz~;&fu*_@~|L2&IDOuA}Lg&kjJ|+z{^v74IFr?e$boK&2`6Irx@DF1}nN z&kX!Kck)W@_{;BuSAKoA@DCPfPANn&BDB`5owOM4nDF;Md%6&ufY9eA zT2~c*4k)1;IA>bF6F+Fp>gc8x8;GdrCB{@Xw1icFE@HtsRIRQwF~a5h;~J6Np@RjQ zKicFLJF%!_&l;<=g9o2KLnW5@NtZwrm0u8*yd(9m;K^Sbi!_iwV-tmMv$~i48-B~V z{LT(~-^fMZ5_0l&K6O_Ug9(!FFHzRDEOlQljW@yeE3tuu%mN8TKm`mQ>$oAKn^r7B zW)!T7KxZXeG_)jFxyuXP2iKlLC(LsjgS0cT^VO;rPsrXQ>C z^Aj4buYzCw?lD0Aj?2!#8Xv>bSKrEWA7|7&pA3*a{`-9VJhehhh@}(@M2V&rstpzj zi`c$6F5e?8y=2Ai^febT`U?TQ;Ub9=P)EIrI(@gywICU2+J(NyK}D7K8@fZ4 z(g)i}d1>39-o@H6M^G6_Xpj+aRz;eOlcCG*WHRjN0F}=ipq%nI7#Nf#tAHh}VdBi? zcbyXYoJ=c-%F@gdeNv9Q?&2HW`&%|F<$p!=rX>>8^}$h>MURW=4;Jfr?Shu^jWC}MDD$->W5dwNW;zL^Tuk*nr~x*S0Kh>)J6iYD8eK2pP9 zj$aE>^@gWV^Tphrd0NUMds`=an=EwFQtMPTRzVB1+bl%fWPxNR^qZ7bntwcsS=j=c z1|%>JEDG<_yhv1$z;mP1+?{ro?WR1%HjmI0nBXSIGyl7;U%bQ8Hi7;756btUvGkDH z20NW&h~T+g&u6G*K2-1k67x>d@}=ZVt<;=(bH6>IYALwxNI38c$CiYyc^&);L1&+x zacW7pqEUD^J8r;!4w$ItZih%6S){L8Xw94-PK3%#NBG%VH4yAVwJ*daAX8CLngfW= zX9&$PWbFt_v&+iX!9M$fHzpFpZl&cj4I6HA3|uxPpQ`jlCFnIPPHo%=2Hhsm>U`Gk zr_Fa7aHPInUm0t7w4<3LeMO!5soDhL!DFJn0%Wm)04+aCX>ZBxr;;kS?v|fJI%FU& zdrCBuw3H?Gc?-#&@CYRby^d>o=Olem-<>Zliv0?uUs%}VHDs`mOXh9nOtcakSWGOl z_Kp^g)#a7PxVVR)MNaf^HR?foQBEa`qW43^kOsSCGL%Cq!e!s}Y>?nW73Azfbf^H> z<*}?7@Vu$!Y$tENomT!CtF8Rnx&B1s0Rnff$B)JB*mQZeP8C6?0a9_%)_4Cdv#>@|2rMMwqdTS z$;$)Aqt|oA9A(%A@D(}PMUAPN)RAerE=AkZHjX-a5v_Ts*2)KhSLz4~0NUis0y|#I zY8QX*XqVLw=S@Iwm}&<+W_UsR5)`GyFP0Qlzx6#-pNqf9DxH&0=+My5Tn5T*~?dC_`80d^dWFStPav*QSD8$`-pmCVn@_YF@_=y)hE?BD1 z?4aL31}nABjKfw*AX8wcv%dHH_HykX!7$5~^TvDAf3>sZ&N4Mc7cVX}t~945*Io-w zKID8XUw5pT*+Fp8$doVI<9(62F{Jtu6ES>+!v>%$_+Ys3f9IJ5)aT$I{}aDSr)_di zDran}7OG`!@jxUDs3|2vKUYnh&$W_lq=Ro)nB%~WlhvJnRx dzofv!f>z~0AOIx z7-(yygEg(B+M;qf7B4>51Z&J<;j7SSd@J;vyRrY3qCqAmI_#2qWee5Mpc}EQvgSq7 zd!BEP+X_2+*nIf%D}$NPoxq1j|GhazLg{*sOW=?CPLNkP-;|$rAr0CHQ80b1$sPm` zQwhN*wr9A{x$4+j8R^t$_W3`A8SzceEY8~a3Bp0 z3Q_$5FS)H+1j|6hmy3ifn3-+?iiI%QJ&iNk#VbWF+*4*ICOBOK0r$cX;S2HXeBZ2iJklq3Hq`ZdAhrAD^{0>?x6Q}KUg93AK zoyv(d@0fw?a~!iKR;)2WeWVYODA=(Vs!Q{F)j?Ul?utGv9{DGE!`i+Dd7sTTrtPD6 zo$w9NdtUuSW5m@eVUd|x-pc4J6TL=a!OLpR>?Nu5cnL}L(w7n4x^%a7kLz;fM|jbP z%q-%|50ZTK>9be)ifFD!xt4}7M@oxe--h#V9+^RX{!jc?YBhNaxOPWNbl_(xQ2ox8 z_Zyc)JHEr_enoLdRAD~V1K}c%{^S9Pe@Fdk(iFZiA)p|j>$NNlqqJ%c7LeQW#{)wU4K zTfn%^AvhqF*J$bFN?=mC2i+cTF;$nfYl>0DO{IO zx+H&Gk5c0F=l6$1KUPY^JNhmmjRa>N&hX_h!<;3}6PmNUq9is~C)1P@L2W*a7pH6b zwX_qO$sz73wvFC4&68(J17GL$yMP!DLrSd@dE)K6e8gwqW_9<_$OP|a^7JD?a^)ac zM>Jp4I(}IhLOI^UFe)tcS7cfa#_1u%zGrfDtv~>EhYW&qzP^k;R=7sx`r1+|8q>ee zdRL`ienpbblZVfCH7v7ropP>Of>M{&_x_*wEv5n-B_*FKjjlc)%H&!0GV=kn>fpZT z&AqsGpOL~ZZly4(70_dN%xA6iLY+{QhnQ!-KM$MlU{lQ z_wHE--vN))5aa&w|? znFj(Z7o$F16=k^9N;N|+-@fiE*w57t#zQ~c{&eSH=+>JH=Oy3x^~VQyhWmfiTOKg> z@yi-MkQaFyJ*SgA=}iELD8(_+E*<^M$#`oL9=t`#-_<-yP3x9;cXFq){Ak(7`_{wr z?|)6@*3C)-*dq_0Fqs}tPf4x*+mD!7TRtxz1NV&Yp7?n_Vc! z6AK!CIe5kh%ToE?*mu=E&K{^+_>$`$s5dF)*M|!sI!BQBHr5e*fuWxETbICUTv&dx&<{K{qAm|6R|5Y=(M<2^%(KdY>P%KybHerj zYY37D5BeoUqU5%x5PvX*SH7AzxSqGQiT9+HxAzgBd>3EqD_&Q6`(|tm&0kO2@a{@? z*e=2w<{kqy``XW860iNI60bTqE`h0uC;pN&bFcPw)W?Y_wPSQ-acD+px`h3?Md%xHjhm?xMb`E5l*>dY_oc zt{Og#%T0AXdu_cEQU5#_BjIH5f!K;g2-Uto^)Z~s3M(R%}% zg4aSn!p?q^^-+{n_$hl*ERUD-rp2-Cn278j6zZDC05vIZhhhU6Z;EG%?)W;-=ISSi zkQ>{wlZrYR(pL=GawNh!MtSQ*=KK7`a&iJ`TgUb%(sTqS<5%I^!p|}ry(Y%5W&TVUoTjLX2Ff(LbH>stV7_np?{}R zRL=f+dG~qw2vzEEo@L}h+Th|qani{m?_@#pfoO3J!nYPz_$x*a%zk{*6T zsJl{+J#7Fx1dINz;60`yPV&5bIlxTaCWWotr(Kr>|)*+ z(13(0jqLL0lq zRdB!++s9x%YWwsjLD}p2(_cR)MeK!3O$Is^E#?==FdPtH7#A*V(kWWq1F7hS#C2EK z$#eQ?OZg8K=gmj5)`O+aF6Z2>Q;8?* z>zEOio@rXj78PO2)f7kM3DazxQuZOJOpz4|U8y7JjCZ~|4HE8fcH;6y82(YUu_vB~Fncu~)FMV@heU7q9tlHC0RdLUEWo2!a;=|k$* zqNhoKm2^Yuw^sx0o_A$Oue^3~nELZS4bTDVxoDgY;7!6%3=I!BXAZnQ_?b#C z3b@RaGrBHlP7p$a6Y&*cyGjyFG^W z+&8ItoX7HqgpB<_`-&TP&fKHpH%C9wo9%O#26u3xYNmM5dXHJ)IG%YN*YZV?p-&1c z%3QYn6Q&1ewE*kEu>?y(c9lFm9#fY>i_5Bez_^%=nLZP!mT@`PfSMlf?y6&YcGV$n zZ2^}uD~r}tG8%}>D&jzs2Bi!)wknF){#dyZxRQ5C0lbO%dFt)U>9N*h1)1mDD4JOL6AJqYQo^$LW{Oy#v1Nxi5IK7QkD7;)d8o-_=*R zIi>TqhK=uq@+_`Pub)WK4z4t(ofXVWGglB-SWt;718zvlHthDN+gksTb(d_E4aznv zvDe#vdjdLd9GqFF!Q9ngi%PrifqdCm*tyPTQ=CwCmZ4;mBg+XRZtuji-s#C6fwPC>C2kqvVM}R3u-KBut5!$A9OvB_g#;li8A0^KD6-A z<1*b!J}7_Fo#Asnq`xsP2ry~`KV#jQxtp$NG;dKVZ8_hX{a1UDwdHFjX2FZW76v~) z6MzCsZPg%^&$mjJ`tRCaGU8bc;G68idwIoFa0-r@zx6o zK>v!XhLkhI;d=O=ZL*v5@I=c!6{$F3`0<|{-JZx0FS+6*g`n}W>|j=@S0(i2i#Ke-ZZ)JI8ihma7QTZctG2C&pcJYmC6j zuhV2qgj|NYC$Hv(W+HX-E?B=Vsh1qDB6V^4>RHFigFh^-nZdLYfIFHm=0;|-kT8?M zgvOVk{pZW`sB679Lxx+LxoI~xnAfq~vD8jXOeYsDdWj{=qEKPTWt<;22r4(fqqUV2 zm$w@|dS&MIO6@+(V#v@C-Sypd`VOG%oIY0W+(&YoDmJQ{USXKU3IaD1U?$nxN&SgW z91Q!6aGfeuv+2BxVqxmFHtw^;2?ZB*R}Ep}V~&*4tM9yBz@$5h8cHj-Y0tVPj`L+@ z45B%glkKxe(Nu+13{y-eH!y|@^3mDR(7)lpQ&}#c64hPdt@+#KTY|oPh?t%eyTBzO zkhZa+vq1cD9Q5m}t5wz&;{vVf_Y}4zE+6l=jb2dA@{Ri)3O&|i9G;pvz5a=+Qw%;c z&c1#F&54&t=C&J$b?7ju1oO5oQ5q)}oQpJ_ToH^4VF$%HL1J5|k?eFh5IFDk!Jw2Tely^U2zZE&}}*x1p&$*-0f|A={es{*y5*kMU}w~i!K#{%jL&Hx@_@lab1lW1%rZ%0iSYT ziBLu^(eFNco7ocR`9+B$(3T+Q@P5aXuJPN_+T?Tg(d$wOUk$qHk$L=uBa2?N6kYan z@4lB#WSqNXf=(tJFD4Bv50(DFH0MV%9RtKH`FJ`ZVL|CieG?y;Keux^WrW7}Q_kNr z^l773xNpO7r_W~A){q(RFI{p!C>gYMzOtyi#`*<&&}cpqUasoX;!`DGfcfHaCC{o| zF<67HuNm<%<|<2JPT;aJfitetJ{#>hnLv{cJG8wDbg`|AEmu=lgt+lW9r$FnkQJZN z_by$9y86q%ZT+r4`u?h{r~k)C?cWn;maks%c}M|-8nU3E1$~{#G^ZD%+);+qV0o{vJ?WfzJ5-slcR`p2jTADzFO4mVzCsE66x@jZQ=a~MLmQf674eRTnC zBAQ^{$%XH7IzCm0H>CUo#t<=)?Y0 z#jjm`80#;Q5Y&iJxKqZAQ=-}fIymq!17@5#)tl(VsMEtktK&i?#E8)AOz{DATy#zW zO`nEZ4j4-)pbwLd@sVChay2jSA4Y2u4QcN5_kPY?oHasyYOqj8zxcv0xQcB4slR(h z->c(2Yn8P!VzSz#EP6w=Oe&ky;lxun@z&5%A&iTOqJpD?Ohe-YH5qAosGyt*`ip5! zTB=&_7EDU8XXyv;KNG*q>9lp2K;ntM-@t$E*9>$oB2In>Wadiu{hp+Wgr<+EZhQb3 z0#gSIzfH97$Pu6?&xbeP)8dGEu^i7(e}cApBY?DB}_4;RPP+)8kvszaWO`8f~vGV5?^5^wB=&Jme0T#6(9)& zBpvhNI{46S{5@Ipv=_h4-Q~@_k3SQpQkVZ!=(s29Uvf2p?5v5z?6N*NhFl>Sc}5pi z6z|cMXvDRJ=|^aea1^^zJ#s^41_9*M)Q1T}qa!LEej8s7DglDc>oFC~RF7ki6CI5@ z&`gyoUj_!80wwBzSMGDir~-RrU~8%ZR2X{fGd|J^6C5lX42NUj@Bl}s$$`6hApP2} zROvB;J}1LkF;SPb8GrYe2ks7p&e*C>P0xt*%@IulN6Cs0%+*WbC$8j#fz0vZ(YN2f zjMuOTHXf9>FvS!z35L_T7y(^SKo}7yC_+0a1uU1NU6aJH27+Sbc`fRBDV_XlxfZm4 zN)Lqj1{4B-LV5LCa0O4f*w+;^yqFDbXqu^?E-tn-A+rGZ(eoT-OQA434fhyetp zfSJcfvgt=M8`*2xz}a0OfQ6UzQV#use=XlU)`+9x6dVhluwXOvK;d_)@+^IShYIS7 z?DDPsqn{aoiF-D?Mf_iUz4uoW=^H*gnVIwu0t5)v0HK8zdZ-Se7ZDH<5p^gcDq=)b z*0m%dKtM!9L>AEvRitP{M65dmL{xMUk;S^9h=>i8-DO?Z{pRzQ^ZxdplRqHm%rnp2 zSGlk205)5~{cuVp(vG+sFAJP;O^HUocQNC}O4{z=l>HahjMndfczh zPU5xRV9M`0AMIY1nSFedoiWWSPW;{IHQGRMOP8JDmw0QYN$DN^;e}hhG{(Jy50jzx zLo(o%YqD*_NRo6xx8XP7US65#G7xcC&|EJKennlemc~|4M9q{-C-g7uFq0o7e0+6U zvj!ag^OIfDWsCy?JW%A$;Y~9{-pkBx7%k?R0#$8OEB#h7$+(02tf($KwS&xV^+#6q zDC0a863xKslNP6KMuCjL#!cr+7HR9q+HyO~il~AX|E>F07WAJD9$kMiJ$ci>pYPA) z1LuN(3;c611!;XR?^wz1BFppe@fn}k9I*JYfr#6>vj#f@!@er?>(%HzUg$?p=}+!KRpAZ$>GBuXsXhP7hc&Pn>(^DY za~qOUYcEcZ{{Cgpo(t(Ki@Q}HqJP;{`0gzf6#0>IVL#Okp^OHRv#lVE3p&++AMO8U zZZTjxf|&nlWEqF7ty!64tgDVinxWi3&WL(5rXWKgmi29D}}H;VoIT5K7J#0#7;6u&60AbU+abW<`1*F$}aP@A3kwg zq*T7qmp7It1Oy>lVTTOd<8wYPE)Zj;m2H1I=1mM@nZdS>t^1OE`N4X;*80f3ga~c9 zEl+;glMt5sqTZkX$7e6}z1O>zP<1jVW$6$yJ{cd4r2i`VKy%p*=JuMyO8kPpsO2wp86(z6#*UiR)!cWrB#+rxa@P?)%BFNik1;vs}1=+PVbE_WZNgb3?JGb^_=nt&Om#rHdvTiPOJM zmsuk(zW2%3%AbjXYnvtAceXL3+Qm_Ca+C2ds5x|%>f#Q^TldPjAgPFc9?W*mb zMh^%L;q4<^T@CKfSQw~tn_Se@@H)6$EW`Ohlx63_{+@LXdJ(rfpXPS0cQ_HTDXuQD zJ)V0a!ctI&G{)Oik~xBKCc2C)mGq+WC@cMoc(B)whuAQwg@HJ&##;z(dIHxYEDblX;-X`sv zL5;EJj^Axeb*7;lYJswD<@!M@L(+4J|NQG=*K`ULAWr-D^}v6%+rCh7SkZO*{a!|- z{oUS}ENw}hj4@Y8?~{KVtq+t>d(}Ba#_=ukg)hpjoLM7o8c^ax=k7kAtvt^_8_el& z1L=k%wak30@};{Cvxp!K8XBc)liHy~F8meJ=Km7#0eIH5?zez*;MQSD)0w^GILf zG~Z$>vEMByEpgbD)8O-iPO0E?j+1o*>6%kW>g>gp)aaP=_3`JQDdx`IleNF2fb#lx zB_O}jiZn5tYXGBz97;Zw???p!8LI~rRlK4&q6M`?@tFPSexvSlJ$o;FkxqE6)O%;) zvu^A&&5J!Hp%?cZVa?^62c95#(jnm}Un7?Fj2|4xzE^p~!Z70Z(sO8+D=m<^$N9?S zw`}{vsY62fVNhA|n$qdrP)HG=_11UIt7|P~O18`dp2$q>6yKLwQ6t+DjY&`0HKP>q zCm9Ei6QNAXQS9x<|JC1}-$TyWbEM&|Vf2Z{+H2XT&(0Z^HJzKQIp5Lt&hTMpDVf4(N~5rhtVG?ICvm9+f0sH)%dc>Oh{f!YUHt1M_)_IHjAu++8lr#H-= zi&)jRc5JJnnIlv3OW1^7UbHSGS2)u1JrE8JL_{u^97Qryf&@WL37g*K%!=Z)T@NhDlR-cFX?q@7QGvK>Fp*K$0gd+b=ZB}vb6)*p zfe*;1x=l*#C*yQl-<%WlwA#^I?4_w3q(Ji|d2@{Fvb!`o!?4mO$I2{F!myyBp<& zs!1bAjClmqdJq(2MuFjOv^s?=A>&)Na^aUyaWPi88~K~HZH}5Ew9^%K9s9lbB_$y7 zy>z(tpWmxJiO4tee0JErkwF7L)DOim%<&0qUGQTy2~bY26NxA|EanDXtZ&kvIF!#w zR|fR>UqKfS1;9atbxQLhNL&-si+Q$OX}mcagVAz!$GF5vsXS;IuJ$OC_$$HbLm$Z_UfW?sqmO`;>CWkdXseTxNa>wj(m3YT3BAm zlA|Q*DLWt1hvN zG>|=Xc{jEj@h$Y#23mySC;V7e*7k^~W3`NXQ5z&*k7qHf2)r9BS#f?;qKyMS zU%v7M61iU-WqoV7`I~NO0x8AKTFT4R5D&6JwpZpEh2w*5Dh9Z-oS>&N#EJ6sf0Fw> z7BhSa(2%xP1aY!{&a;6|G2ZPkg{T zhf*9x>SWwJ)*L2Vb_6$ecP;a%KbYbb7uF~zJ;QAN z(}w5I?ht%iMb*7wtt)6+_oO_W-0NlrA&E13u~`oDEYgsQr=CU0P4rsIddxb)1l3Qh z`$#4|GDsiTG|Ous#Z?3Qd8cpII$!A@fW`bYr74IXPuu0zvDIDP2_2B`e?*; z%?VlxxN1I~yko=gMvvh?K7@~b)b9g>sZIPdygOsL8_kz@Osp`Is+#`+6Jt_a@7mxQ zM;at~YSyQmlsGt)xSpiD91R2S{I7K^hMECHnuS^(X_cC;xI5`;(;>fmBF6I5*{8zW z)PKHIyNsI8^QrLbzizD=?awf{rj7r1VW{qAx7G>08z&356^=>A zx>aM_kF=3AxEoAsb=|VhJbooSdR+5(;>iHP)fWf0IE9a;)~`;Sc;53S%UU{=p$#H| z_}9go(?(S5krOT;JBu`rs)yc8is-8vtqr@?nD}2bF<4&s+Ja(sVMF5N{#A}e0pCsB zmudn1ch^|Qyk1__l5Nju_i4Fo6n`viJ3T0~?3_Kfq_Uf3*|zBX>$!O>&^GjWDbJw* z#dbZq&K!P?G~rEH331XjZpQoIf$B(xD{j2=e zw(0xRj$P>?7G&0CbAI7q=FFBw&-^`>76;M3+)z&94g@RSB=8EWvgtqQO)yWbZ&X7s zpTI7kX*pR{Pti=Kpw;AZbpd@Ti5+&QHKytAX((hvMsej4g$A8s>fahZ- zMYFfEZcR~V_U>G!P5)@o@39ez)5v%gYm3+`Qjsa4~t>e9u)>eif}IVDS*b*{u#@zF4xE%?6w5AD=r@z1dqN z;=z&HV0ORA+CLKYU}#-75^JBO+Vi&WHo5rJx{vuF<5?W=f|JVs=R>7c2xuuEwk$bs z&B>u*H>jKpYgHE|6nK-_Vsn<}_31B4iOtTmTNHeDkE(_&uRLGzkSwhysytM|M_9+o zK!@lj#iiE;;~?q*VnHw)fvvwTXIpBr-5f&QB-+_p+Br4v9IQLV_%Ei;cs+V+bt}>z z%bv67kk2$(X;@A65kCK{+*h2_LS?s5Qx()X)BP4_dXN_Co3T21jgNU1mC?Pk^I@8_ zo?MVkRz4kjM}cIYJ_H@Qydc_P!8a3f5_= zO}ScTC!I@nIgg0G4s{ju2NTW1X!jbQowM4A-uqb~JR?_Hv+q&mw<@CqR4|KrzQzV0 zk;*As%|Y;6_oMIS^E4dq>43wOj>GQ_44D2JK5xMpU zqf|Pq)?jb81|+vB#nfL2Z|HvSQbN)eqhmsdBi`He#FvWPekps6`BdqB^zsUaARgRmfQAi*BB z!fgW}I(DsC3}PNSy6T?sWpM$gj6U!6(>@Sp=MsZW7HPD4wtu9(X)dY{qbln|)jWmj zo;T8YRl~Hd!=8wgkkJ-zw6-L_WdJhE_}vLbKcnm0i8 z4@*^C2=jmef0*qCxvh?Q<7yys@pn`XhSxSDY)Fhi6QkN+-BJ`>=kd3NcYHqW0Qor<@^=9SI#PcfLG*_V&WY<9??3S?5$EmeQCY6-GtM$npx} zZ(B>04cqiS`^tp`RZ13Cx+rQr5LB43X%n@)yX4;NVLdkrP)=f360wbe(S4lNt>WM^ zaN)fAU_e*|BoE(&c|dx};?-w`UwYt(AVB#FWV?aqH9$E>kByk5xapWVYWLPt^h0>M z6DC)p&#E00H>13ToFo3NZPPaGEC<;m`U&`{e z&?*v4Jd>4sn=*>FD1q@zM+1^n+{GetfR$aaiO3A5P{QJqXEk z87f=_@u8yx}mh88!9cu8is%V&g z`pBjt*rI|Asg^QrGzc)%t5C(eacG3V_<0o?x?gC^6*i+q6nK3jB z7)Z2E-wue5t1MKsk$AZI{n-LWr7Pu>3U3eSzh7;?&!U=dk$goryi#MI1~kDyG+U8*W12l%s7Fjh$L%RN zmB>8>P{mM)xWbr-JUz=FlGhjsM%mf1Oa05j)8BV+2jXs$zi%8haPlE9daVf?(6GpS zp%%4co{x>0vs_*{;>;gXCEKFV1xU2SCg&ez*wFWidXi0L^)21@CG}{#ZL#_Gj&^dr zd!+?QU65#An8J%=;&G1i+65Cxsv*9vJW7W0prcrkJKkB{pINp_#PSe&<5o5VP0yU)wvg8aT_s{UtjydD>C`qm}BL%@khFo3b~N7&K6!B~&p>d*WyI&JfE5Mzz3-)ZAeNE4N!Ph4?f;=Af zl=-r+w3 zxRxCGiT0L5$~l|Vg z@9*53N6W1Vz&E>_U@Eh@L_qGD90@`$TkN5D{t7F?CHQ2Uy0yw@)~YbqAx z7d#sdCv%Qg0NIp|ooi3Y6Wc8s?~zule+C1`jd9l-OW*8TI{oV+MKo55Pqw>-Llg0U z-0%Xx*NrZIv>_>X1P1sTM(&F!^`9AjzV6@kYra6$-OJOX*40;XlW(uhx?j`eUFB?c z!zn*x0jTo*H!tJ0$@QEE`>=c8VQXOvF7>kWqj^0wJH{~<)#`%6m81!lB@EPP;ld1I zdHOSn%|zC(&+`+tdcW$i-XH9xUV(l)_KQf`1(o%#1domqW>=jDu{=Fbn|8v5VRoEI zM!cUkgqG5-@$*goe!Au_msa1Gm!d==gx%oNiNG7%A|8Fc9&NJGM`%MhNnYVeZ2DOo zHwFQT`Y_tF3|5@!CSP1eV$T{x2ThW+?!&=fG?#&*HMydH{)OJocJWbfJS9;ZhuA{^ zs^g?Km4R$$|5bARs>n=c=rJb2?z`3RSVkYqhl$etj(1jO3_T;IZT@`8Xn6woWAmes z-&Qr;+xl?f>&eYBZN0d9)uVY$P@QBg`t#p5Q4fb82G}>t%XB~+H+<|jE%T{(c;%xU z*gH?#F|eC-3N^CB0vdRH{R=4l0EiCX`o1wIaQzzzcm&ZQRC9E!1}FA}FwzQ&*` zn24VECK0YH(|Y?>_^*s9!4iLXTW&5??Z28nPuu2g79nRdi6WG>PBg6f0SzKdEA+LF z{pht33-bs9l(Pvq z%_W?|@uS8;+}pyH*|WI*gv5eZ7g&j$?9#HR_uEd<4O!hDvoVmDFv15t5+ zI4>sg3P{3YlHv&IPTswso(*!}zS|#dp=oGvQT3iHoEyiT%LVI4rw}WUKI!1-mhf>9 z&yI(Ih%@~!@a&{4wm&pDiU;EVkn}*opCPMnxXB?Hje_66KVvjt8W3ZwV3eu8LcrUy zuT!Jwks;jF`H$1Hr}GDdbr=^iFn_B{K+uBAQ!53?0K2|GxY;PZh zj~Ro3-_;lB@{fhM@EkkL#U4TMNDQ36#8D*?&}6)`6fcj4Gv32fx9lP1PRoOMQ3eq~ zm&>{Sayl+`?#$8iAVLA;jHQRBU2lihJS>b1iVr^fz7KQ6snw*3>G59CJbG8hsaI#G zmubG~^M@25Y|K_}%aT|cx(Pqs4 z29bgj!Jp*p=AZ;f3k9bp_ZAz%6Vta!Z_HPe@^X&ZS{T{xphI^L9&(_l)C0~#H&5P+ zM=L!xr%mHt=ixT*TaNJYs_5i`7mppU{V7j{RRRw=KdOHG;0JY8W$Vv!W7Pr;6h*+K znn=tZhb;qVm^j3I?~!Ej!#^Qs0&dWFCz}b}{+sggA?{Nd_)rDDH8wTN({G!7s^jFU z<0g3g%6UufZ$Y`f*+1%WdQQGAgb+huvPUTAI1njd;rHmm@sRB6o?$c4j3JL0D zWwDVq9tD!GpxwC#Wu5UuykR5`>ihFd;4M5Fk4FT@L?i$n#h;z`7rgcjXMGZ>u{zmO zMUhAT4$8HHTS}ubgBX?7#-T@`+~ybXizI8smD%Gl$06+K61g$SnWRyb}A&GRed5gYp$v2>#MOF1N>{EqQVC z8$tRvM-lf7<68GetG`PYuj%-)<$4=b+Q(u%CK?HV3Itr~K>Z0YIM0@DBRrg)xa!P1 zK-Z|b5UfZy(6y>?=Nj89>s0$+Go??@CRAEStO{EjU+le#B5*c4xL1mLV-~S)j{T@D ztUgX*^0OA#BM^JB+*%V^p=w%6;zX&i5yZ zLN}%{I=94qv$IA$+IXS#yDE>(@rvIN!}k7X{=rLwifcIdo9vu=9&j~#14Glve&k&- zZ%E~L_bi`YoiaIolAD_+;=R;4PX+>Rky!MWg#u5?GXtr>kVVLmER&HJM~ zdHyR5WwyQx`TAn3%fz=^{*jmJT8C9mn}GH@yc8HQz0wH61GI-obb>0$AdN zw{iP17{>_uT3q(+{$*aK#gQ*HpXdt6%VzHbu=|s*KC4j=r%sa2tm~*`URhzfmM?mBdy3FD1s$8k&4IBAr(jh7_*r!hU$esOd&f+XAukYRVq=K4UsLNBsopHmEL4mjv zimny@s#4jZcUH7dW`Cywby96Aa2IRUEQIHCQmU;rTJxtY>H5L3livgjmeR9QD) zop$P1dj8cDpCExm8 z=ZD+|0LCn^FTYz_E9vU5@p;K1*NRJ~OFXlPIH_$`^B#u+jKlrFJ8S|GHFnfwv{`?gk zW)GU4kl4oXikc4_r<253g)te21(ryldlx0zCbv`8;sb^+n@|I_{4B#SYA*kJ zO)O#eur7M3a=%`x18#zN@kN;%NnG3!Pk+$M3Zg*BJePpO@?6CEh$4tC!7zjYeW=ib z0fbNcB9aIFgDfw(FKiR56#hlx2_WKW7+Nz;0okuHiv34Q09vOH_)g`EMmpEU;@7ST zK9%}m*^d_%k2oE;wBYdfp^I*_Tn*eDW?zDn#~4zsqo@@Ll=JnI#aNFA(LpA3_gtgu z@uqdVuD|JFKl@{zCa5|xNESbKz3aF(uVTDCnbP<9gj{v)(9!ifgwDp$mU5@P4p+?M z>D(hnwr!gVFZW1(gkL?Ku;I!;#{tyvfnCSO!%^R8mNIM^A{J%pl|2J^3<4MBv+;JS z9^RXQ9+uv@Za~HpM_=eqyPA*07~=tMc3QHB{P6m?P>rdV5E!BG{~501M&6kQ+S9~e z&_NULg?0F?47kkqXJ{*N_v;_#u3i4rzOClLzvCk^ofnM!E%AGZxFh9O`Cn8KO-`Ur zQo45YHRFyQaAwJQGH^GBOWnB!uv+x}bI%y)@h;PY^xMT*hdmEdpu=_fw@w4cr&2h_ z_eik$h;m7`z?TB9`0}D^{XWVwA~1V%gWXWVh1k(DZUQ4}-?PFBZ)Ua@6uF53ISV}X zBg4+ohS&l=oIK3e&*Ai+6917-3Se27MU#jU9oa}PVxA*!*8!0TqP8U0LnWI!)BiC! zoM8xVH3=#iWxiXVQ?`fx=%5dOw)pWnZUi8t0+mWwl&7)xo!D6fXbUtRwU)w_Cvbl* z?po*EQ#7+k0;UF^mi+KHXm!q3&$9%-YG;yF(EE1W?So>m+42Z z$$T6Ihj30J#mT2*Z0gp=O-4`mQ*b!Z`j{kI?8O1E&^?z;nsW^IzTs)u16BISXY;@DdZZU+x!ZLsL=?Uhi_&u`k!e1 zlT2$Q<9aekajm;DS5=>?<@u8W__o%fYQ20QlPtEe!>ev+-3Ox7*$Xq*@N$_B#0VnwhFRmW?zNJbL{deh_ulu+tDMI&=XUa5MZxDjR_2@3;g=;h32viI z1v}!=%TG{Ite1rWWHu<&ONa9=v?1mMEXCeV&VW{0bgfzm5cVDwdph=Xk$P7@#50X) z9eX24z&IPi3SGeYtu(R9pCD2hN`ZK40LvLK7wJZ-q1*Wz$uLl=D-jB4Ni4O8a`&rW zCFulU3A^E0qI|WA`opKBfA3oD+kVV#;C$Rghw!G=9(MKTPlTB*<6QdbSXelUd+?U+9NH5rENtqv>+fokD8ZVYtRv^~BSec0+sRRc`agb!o@s!O?$3}8`=ZgG$-;czLB=+PCmtRB-_1eqRqyn&kL?)% z!oulmtstzluu15F2WA`wflS5}&)7a*P!b!9_0b%{Zn=cC8_gan+In6u?P;cF>Na?y zy#ALppAKAVfxCXLYpbh>94O)p{n<1SjV%eWtK! zG%PB`=KJGw66BW;`_9VJyOZ{cBoS|O_Z(>K_$t2C){`Ci!{7|tFNxQ;%VDz%5P_{v z3=h5723#u_%WfSXv%Y9m%&FCh;gSPdcm(#aalR@BkH)pjx*YAf(Uj?R5w{YHQvlis z=K}LHEqDD6E4?!1?vyU-CS%5fFs6L}(!*EIb$pkjRn9AG?%HLgq?Od1@7@($C|70| zyzYkbQ~ewAz@a&$Y^j*d+l=sGRq7*E)Lx1J3NFmFHnil_SPuAxV~%@Of?v@rB9KmS z(0fppk*+ZV&E3M=rawd@uCe0?aQSsmcx5vBbF&1(Y<4^C(+yY+&bu&_UyVfjjgCY@ zQ`#SdpFb!fZf1d{fIG>&XWam2vmn9@@jx*3^D~CHt%Wo8%8svQ#Di82-yv|{Ua%)3 zs5J2yzxF`^5%s_|y|AihaL`o3uSFXQwv zb@Ho2IPLoi+22y>dCk*BDBCJy21<1?6A235!e(a&I_%EWsd(`1t<$aiY%44|Fcqit zj{$7fpyqhhL86**`SetackAuDEu^xRx(`cl(Rj1=4Y?)Sh#bKKEA<*l5El2yJZSad zUe?4~ixFgrV-0miS_bM`(qB4>Z&`#7ML61O)Z|mt#gy(Ai@F9UrW0) zx$toXF|7t7mhdyPYhK^LT?)F{uvIPelF*84DB6bz&VL@8kMeXtP`o_i&s9ll-t()b zt3Z|iAJNx1t+(LRupMdDtixbz-21_yqfYr2hWGWnMS@kg2OZ8m^EB@qq;I`sF>hwe z#nq3eD3j7aS1lXNi{M{ad@wsg0kMM|3fVG?BoJZL%x4j?gLt(%QCJwh0-mejmf*Ya z?_(BLNbBSg1PybTCU)40^&!cJ@8)IsPynR<-d9hLmi|lcW`(xm7OQo;BJmXr)t!#l2 z?U;6{C{zm*w70YIqG%45P_IgW<^J%mx{+}t_(N;qmfhBJ8%x|y{^xfFE}sG+&A`BA zfhB0P-1{Ba9-2BnSHC;j{(P~(6uh@TD;0$XDl;vrQ>j@=Mf3K3@oO&SL6Z1i@{=%g zKG>>+w>q}HPBA$yRqJozyS`B0Z^heYb+9w8q3O4$!FAEs?OT7>&ppMiycpH_)}nLy z3c=T<&#Tq>)0P#(Tug7ee`{^u94B}%Z7|(#DkkO4f-&)|b7sj<`aK*x_j0O=z14ea zo68#Wku`wFVNA_)#lue=q0G~I$F?fdWN+t4|EZGyP{rd_nFMOaKff;1-#QFA9EfB` z@eBPSvkZk<(qDCJz*z%y4@orZiTt&NbMdV=r{~;h{cu9+f9Pgf(3u6*>P#T1^2xQs zqJ%0SabOLI59=xpS>{)`JbBeqlG7%Wj_#M3i{4>nKqh5LuWd!X$u@E=n=K;b2Ox?} zLox~K!^x{N?U!j1f&vzJr5+qTf^wo<5pQim8xYqCd)#jAvC2(fJ?qT`4cRGR=8+%fFX6zNzxiBH2RwK5P$B56ZWMIPg846(WH46f4f|x6CzDS`28{`#37vhXH^4UTbp}TXO|3GrFy_4kdSz!u4 zE}0M0FYIlJua^Szj%U@6KhzmYAtmd$;|#qi!>auu6e*xEEy`C^`xe~lh1+$YPdQgz zAmDBF_o}hGSvyK~F5iTIy+Sqfd$C3*h-P`$hN}$$Js!IF30cBrshET?qSy*=&8K!T zT!L#fyxCrWDI6&hd9$_#h{)X4rkG4Knb=kqWkv`PhNx9t8y-cXdK^;RljFL`kf=o5 zE1mKu)&;J)wFyTd4Za5zUdizL5!SetOZrLYhpp?X{+y--5}!p^1R}rT?+qBK2#sp# z-sadjGR^8dKreN_d-hkWC7<-O0RUIC4qJ-Tg=5B}nBnS@ARTEPDU1#d4!f_#y`N4o z5LcJxJhl7ev*&>r73mRi>|vpKVVxpEODbNsx(L4dYFHy*^lqHdkGyOx>(8xF(k16k zhdrG65;?Aw|F6vD@8w8u)%U7Rb=&KochB!n*>W8+YPkpo@cZm z%tv01g&E`Ja$1{i{rjj{)5!ZAns_E@bF~*a1wn|O!;U0MWTgWlrAsc&Ro$MoG@0yA zyngJ)r&TRYG?~d+-!Jq9)4;XPD-C9pGs?!F-kyQknJh0}G7T4I9fcM@Ju{}N6gzi9 zBANIU+bWXEW<|=QDhw2S5b4ph2JC6LnfQ}rwiOXw)RSP@WHi$l=Geb8y)EC%RK9}& z1+6=02!0ySw;SaVfO2D4R9DAU-R?1Gl}NP_9_6pFGdTv&$)06cO#{7A=Q!d0)hqZoe1j zF^jj@2H#13dtI|-hpO(fX2?;M<^H|Jk^yi=D8-@XYwt>qL*=$NjE32S z07Vc%UiX8<=2}qfIpF}%Cqd z9-{6HYGzK#vkJQ28{qB#s~fP2(VU68p_n)HCozO6XffJBGqDbpbn;>fgOvBjMe^lG0Rkd*_wz%rVxF}L+y^&uL||vmON|Z zkRJ1w*?h$FnbC7*P1V&WraPm4iroR-Q%5Kyu{#I9p}H#B9*S9r&29E?RNJwGXSd># zrd9u4b03JQ-gb6!q*1h;LP!;i-$*nY_+08<+RfQogNCFP`7 zMJ@2*^h2S}{th@KirOpU;Z>Dgt~r9vNVZ9=Fy(ZOD2A9^y=+(Mek!1{h^*eqzttM_ zX9qKyAZjrJS;;3$p37|TfZC>;Xm>Vd@Uh+Myuy_ZQ@?Rvj0L@>$#Xs4R}Yu}S37SW zi`A@d6bi@@n04Bb%N}7e!^KCZG{77ct^8iXNs)9V#1$$w#<0MV=_D}h1ql=-Q+owV zFz3VgPt!M!mpHdTuM=syq6CtRYsZ%Jo(CkTt2np)2-B`5iW?qo4$#xr{f)75_L0B4 zpp*D>L(ZG^HO$d7t4FqGXh(@?oA)@sEvFy-_o-z6Fj*XC`$XenCu^AR<@b`3K(Y5K@!dw5 z&f_FvBe@n;BO=k*Lt-!8bQgB;87|-L$n6cKkDdkW*s@+AwY&8fZ%IUVzJ86=n`gUY zQ)=;pztD#%% zluoRsKZ@Z5ufD5md)Js!)7~A~7?^jGU9IP&2x}VIw8CYYMlNY9F1eVn_^NZ=0rrD0 zkE1NMXJak8l04u2O&f;uBdvCP#G8lww2lnJbeRcKhzqD(kHbq(d z==?#EE-Q=^)qvwU<5fdO5CheGooMbVUC0Ho*e*(VLKId5N*a>ic(Cp9Wf@03)4C7T z)`fFsqckKt*IQWkwCY-*4*RV0-}*T%Ia_uAc415I+P>~9XBD;&hX*GsY-hVHnrZhP zhlA5Rg5`QpmLrJy+S7TinI-8Cs1FiGP-TZ9Nw5;b$xVY0$L+*hH;||~N!}480V=+> zBXuM}CD?cNJFIfN5xk_N)qKFyFPY^?12#BLex`~~lje_+c_+xi%Ku_&1)#u1ZvP-P z4^*~ae$C97p$$faSWRZ$yq6$3?+>DS3sS|7CKrC2+ootYoYKPuGyVGZJcuO`>g)Fq zgCMp)xFQ+aJnSy_#s~E~H1EkzOK{k+wXAvOP+#|xPsSzOo?WO5D?}O%&wTHvT%A9| z`xN!I-oy5G$;OOfSd}#WCgXyjCVXH>(8o_9Fvj}hIC6W5L_5BC6b|Oa%b17jlg-{& z!g5Cfdmla*U-#MfofYD-kJZE>EtRKkp-_!>MQgZ7*wp_pC-GU|fBUZSg5#Q;EO@Y~F4m;pN z=HxkGzsP=UCYe*{50lT}@7%&mB?Kg$V2Q%_D)!sn+C<{}-~JOauZ3dhSu=Yq5##Z~ zp!K)sWW_npU$Y=p0-pHQ2#YgKk+8ILjltzM1y^4wgW=azpqzO)28BBAHLDy2si{MoXY3wiw@U5((h7$$?;(^xWLFSWoAs&R zZRGI|7Ts{;5T4u(qe=LkGcKx_?ZnKxfr4-e1w^%5MK%|?i*Upm53rKBWs|GOW&1=6 zK46yh7-RL`cfMro)G0Q3%z5=88R~0<(fGg>~~C*x=--1&Lr*Dn;*JOHhTdi(2jK6D;04 zvcul5rvVX4_&x4FnY=is@4RNC2~O72hld z;%+_I1Lnk~aIz!m=D=d9pKYpp^S(}m18)l>$aCR_cKnxp<&7TT>$zqWNf;V~P~(_p zLAVT91u5<|@Grf7wnOgW-(YVx680^Ew|1Bd_O|(qZVD0K4;d)ivcl&3$C{Cu=JSN^ zfn6haUKLSJ^#|IF<7MA3+J}UKF=iJ0 z-Ra#s?eva;Fj&Uj_qNGpX72eUyx}8Q6`rWz$lyU;OD8w5@p1I)bo+(#uFB3+lOr4E zqN`gbq5H1hMM1?XOWxyKtj9XeQW~>8W!)3y;^BJz56eyFPpf%0c1JHk>%6a30`9PH zE1UzewZbKaI5}fHg8-sNYWee~oC#VzS~=|qpUd`{HQpt+%0*U$k#7Y?aLoyO;F)B* zHxaplVJL19*O2t?i);_!ArZ(Ts#1$3agj|H@Kl+b4b$MbrgK0cOYP%nq!W8-Mxq0; z&aUJ))yE5)>naL#vcFE(Tfr8h%fVo6L&?3#8=li~O66Ky1K*-PTKW1JR*r%pK|6#t z4k3He88+)xepcppEn4{2m1=Wtd=Ctr%ojP{-!;9a)8VC60l`o72g70S-~c+n7>`K>_9C+{xSTYxqC3+{-b4LZud+-F7VU zf#{cw7ivR1|0l<$XkKUzwEU0u*XHF5|Ifa2`p!n_jLmHBZBI<&+p3e6>NeOM^WMyE zhB1TOkJAFO?2Rj>lHvI-l%ok1^!ADrd@BR>ZuS4^=v@4v%-cVHpT|st!C*|M+Zc>- z2u}wiX@*Hd3e)72bQ`KkmeF>wYI6@mC>pY{YBdod)i|^(tGW|K+kvuer)PI)lsr92 zwXOE~{py+D?_c=7Uf=6=eXh^-{#;{*QBue;g&@waD7|9QDDBMHDg1Dx>km(*N^fyS zpsP*c^;5&fX#WLvj8&3y3!H0Dvp_Eglb0durEa(^Uy3K{O ziv61%8^`*t_`Y_ExN=-GbBS@GZOtm{erCb}z%R|HyWN@bI@EsP;H=nQ3n~X~3aFpA zG6i&@{~QR<5uh3&1COq z1>{tbEqu1ri-rALkTF-QmvP6sPXV$+Frac{A}Le`rzj;SkO5BzEPYsj_wcPWQ(P4*Se*@S{0L3oXUsL&cYpnHqC=A zefAxE)V8GL!JnHXHk}m$@JRdNk4q}rQ{oklsJuC-`l>OsmwEcDwt9r5WNui2{$2k^ z0<}$ri$F>>t;T2 zR8FWf5yU*R{Y8%vCaQxhARwNNkgbO0UTuFrqnHV|in)v^akQHia;@S1$s6AfOA;ZY zPIUHhQ{Z z$+E^Y6e81^+@bd{sj>tKb{RRuHGA1@SFe}80EPw;pvGS08$t&q&4|9n0opPsGw*%7 zigO(D<9c>{r)Rr(u$hv#yyy})6e$;+xi?1RPu4l#`Z&>)LoT;om# zO(#c@!yI_a2rc^cM1!UzhX$r9QGN44FrV>d{*!%20m*M?^n59qL+6{nbvKKbK$Xy8 zt>09e&L2~zwW;s*`!c8IhfWsS)GMSrM-shPO%6CUC^E}qo~&5?3Uxk>Z%J_z2d^pj zV7U@F1d!}b(%Gh(Pgx#o>Y_P~tc8uWEYiRQ$#|A`<9;pJwLg!Fw=QU%$N0(rH>KxrMWc)>3`b_eUsk0ZVr9%)Nglv4W)>~RL?)9)cG2!xuOOvs}O;X9O8NVYU;#)7UkK94NwKX$R4ZtLZ9C6vBqPAb^ zdn=<;gO*Ul|N5Ubhn|9Bmm}Vp+bRI|IZ#+wu+1ivkUtuCVxC5a6G9 zm;0_Zk+3{3{Egjd({syETSFn&2WIDJvWnZCiu$`x504+7O$BDX1$?S*o_r}bl+x#( zacyz!%b(;!!(7<7$eGm7Jw(3xsf>uUncr86TBmR!y_S(LZ>lf;ot2^CKp$4E8Puup?*BoG?biWLiV)hpI2frZX!SzEkb}MTH{`b40^EPMw_(N2SZ7 zRQVf{nHrG@(Z{@7#tM5hq;ZHVy~gst{CeD-NU7&C8>1D3Vt4yza2C>ZQH%ful)gT-~RFKv5Wq9ZVEQ+e%!1G^;^%l zA!2=@GryH{ehj|3`V0TU<=X%+`wBy1c5+AGtkrzzr@bEAjF>(=J}wxp&$M~rUZ}!E z@9)Y=X52c&Ws4g3`lw?|dZK%I_L21_$X3LEdb8$tyWf7K$dM>ey#Ec+aeSqC>}C7S zUlT$9;M;MtET@FK?%f9-rf8RCtzU6Hea?H~N(#8@w{;V{^@rvyOyZB@K;5t3P>MK> z-EQ>dJu6*9d3bKPH|$~AGi5GJnt8`F0|=Xw@mh<#mT-tFTCAbuan?Kcsh%M&TAtX} ztv)x#J%|^YnA2AbOG%J-g{NNzHFU%d?b4zao+!hNxK5b4Ij|PFW>TLr=jL9K8wW$i z-f-6a9$KdFzh_wZdaCAhD>xIdc}XpNQ6j2tW`(HIe&R-3(k?@ z(vAS!2Wc97YK?`3wTg-uW`MNkMdk^}w63okUDbiEUKgOZJy(=jlePcPTNHSv9}X)& z{#+|7W5MoSL3+X04F{Uq0-uN8N5y^sbnLgSS4i}j1q_J zm2}3j_!pTGAsz?L@MZ(T3Y*)rSIdeby|ZPjD<$ zdqTAqcdAE==p*2)q(Mm+a38;+k~<;;sqnt`w44itU#7LQ^^@&q_jUgkP3aO zn5RfxtT1FP+!Bu6F>G{gMS>BviGdGXGIQKwIpMw!;CMxYXww7P9M@Yy8rd#P9 zcM)kV3KZ?lT#Se#yr!&{$ryOx%tv2X0FZ1zing8H)BuIEDX~7r?(Ty$omw}8(jj3D}3#sbxFV8 zx-NrMV%Xa#2v;_mfK@y(6!3w(0E0Geja>ad&|vC#BJ2F^%oZU)p0?Z&xv;$m;mJ z{lgR8R|`pMaj*{EAqK;gN7e4@7Z6^R~Vi0rdb#Iha)+ zMt&1wOvZNkmx+CfN}_viZiS6}0CxbP750tg-l~U?sjd6MsM;m*s(4-y5rT;K(8ZZ3 z$?GZ}gh_?4@pJs-9?VD}fPfprkgpGxPXs7C|5|zY^FP8?(snl5wtL&b-kh!Hy(ZMM zA{)0OJ4N}5*M0Huh?q9O*tNYG5VJs7{Z6l@6XmpuEj-nZIr83ZE@i9le->`U literal 0 HcmV?d00001 diff --git a/Tests/images/tiff_tiled_planar_16bit_RGB.tiff b/Tests/images/tiff_tiled_planar_16bit_RGB.tiff new file mode 100644 index 0000000000000000000000000000000000000000..0376e90a7be5f9da5b5882aa5e54af41de695128 GIT binary patch literal 34501 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

9Rv+tv1F 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 C$e*_W literal 0 HcmV?d00001 diff --git a/Tests/images/tiff_tiled_planar_lzw.tiff b/Tests/images/tiff_tiled_planar_lzw.tiff new file mode 100644 index 0000000000000000000000000000000000000000..57cd6094a285b3ca74102c8041053b999711fea5 GIT binary patch literal 159997 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

T!*}83zCT$aQQ#mk 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 literal 0 HcmV?d00001 diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index d6f4900cd..43e6daeaf 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -856,6 +856,52 @@ class TestFileLibTiff(LibTiffTestCase): with Image.open(infile) as im: assert_image_similar_tofile(im, "Tests/images/flower.jpg", 0.5) + @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") + def test_strip_planar_rgb(self): + # gdal_translate -co TILED=no -co INTERLEAVE=BAND -co COMPRESS=LZW \ + # tiff_strip_raw.tif tiff_strip_planar_lzw.tiff + infile = "Tests/images/tiff_strip_planar_lzw.tiff" + with Image.open(infile) as im: + assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") + + @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") + def test_tiled_planar_rgb(self): + # gdal_translate -co TILED=yes -co INTERLEAVE=BAND -co COMPRESS=LZW \ + # tiff_tiled_raw.tif tiff_tiled_planar_lzw.tiff + infile = "Tests/images/tiff_tiled_planar_lzw.tiff" + with Image.open(infile) as im: + assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") + + @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") + def test_tiled_planar_16bit_RGB(self): + # gdal_translate -co TILED=yes -co INTERLEAVE=BAND -co COMPRESS=LZW \ + # tiff_16bit_RGB.tiff tiff_tiled_planar_16bit_RGB.tiff + with Image.open("Tests/images/tiff_tiled_planar_16bit_RGB.tiff") as im: + assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png") + + @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") + def test_strip_planar_16bit_RGB(self): + # gdal_translate -co TILED=no -co INTERLEAVE=BAND -co COMPRESS=LZW \ + # tiff_16bit_RGB.tiff tiff_strip_planar_16bit_RGB.tiff + with Image.open("Tests/images/tiff_strip_planar_16bit_RGB.tiff") as im: + assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png") + + @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") + def test_tiled_planar_16bit_RGBa(self): + # gdal_translate -co TILED=yes \ + # -co INTERLEAVE=BAND -co COMPRESS=LZW -co ALPHA=PREMULTIPLIED \ + # tiff_16bit_RGBa.tiff tiff_tiled_planar_16bit_RGBa.tiff + with Image.open("Tests/images/tiff_tiled_planar_16bit_RGBa.tiff") as im: + assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png") + + @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") + def test_strip_planar_16bit_RGBa(self): + # gdal_translate -co TILED=no \ + # -co INTERLEAVE=BAND -co COMPRESS=LZW -co ALPHA=PREMULTIPLIED \ + # tiff_16bit_RGBa.tiff tiff_strip_planar_16bit_RGBa.tiff + with Image.open("Tests/images/tiff_strip_planar_16bit_RGBa.tiff") as im: + assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png") + @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_old_style_jpeg(self): infile = "Tests/images/old-style-jpeg-compression.tif" diff --git a/Tests/test_lib_pack.py b/Tests/test_lib_pack.py index 8a1460346..af7eae935 100644 --- a/Tests/test_lib_pack.py +++ b/Tests/test_lib_pack.py @@ -320,6 +320,23 @@ class TestLibUnpack: self.assert_unpack("RGB", "G", 1, (0, 1, 0), (0, 2, 0), (0, 3, 0)) self.assert_unpack("RGB", "B", 1, (0, 0, 1), (0, 0, 2), (0, 0, 3)) + self.assert_unpack("RGB", "R;16B", 2, (1, 0, 0), (3, 0, 0), (5, 0, 0)) + self.assert_unpack("RGB", "G;16B", 2, (0, 1, 0), (0, 3, 0), (0, 5, 0)) + self.assert_unpack("RGB", "B;16B", 2, (0, 0, 1), (0, 0, 3), (0, 0, 5)) + + self.assert_unpack("RGB", "R;16L", 2, (2, 0, 0), (4, 0, 0), (6, 0, 0)) + self.assert_unpack("RGB", "G;16L", 2, (0, 2, 0), (0, 4, 0), (0, 6, 0)) + self.assert_unpack("RGB", "B;16L", 2, (0, 0, 2), (0, 0, 4), (0, 0, 6)) + + if sys.byteorder == "little": + self.assert_unpack("RGB", "R;16N", 2, (2, 0, 0), (4, 0, 0), (6, 0, 0)) + self.assert_unpack("RGB", "G;16N", 2, (0, 2, 0), (0, 4, 0), (0, 6, 0)) + self.assert_unpack("RGB", "B;16N", 2, (0, 0, 2), (0, 0, 4), (0, 0, 6)) + else: + self.assert_unpack("RGB", "R;16N", 2, (1, 0, 0), (3, 0, 0), (5, 0, 0)) + self.assert_unpack("RGB", "G;16N", 2, (0, 1, 0), (0, 3, 0), (0, 5, 0)) + self.assert_unpack("RGB", "B;16N", 2, (0, 0, 1), (0, 0, 3), (0, 0, 5)) + def test_RGBA(self): self.assert_unpack("RGBA", "LA", 2, (1, 1, 1, 2), (3, 3, 3, 4), (5, 5, 5, 6)) self.assert_unpack( @@ -450,6 +467,43 @@ class TestLibUnpack: self.assert_unpack("RGBA", "B", 1, (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0)) self.assert_unpack("RGBA", "A", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)) + self.assert_unpack("RGBA", "R;16B", 2, (1, 0, 0, 0), (3, 0, 0, 0), (5, 0, 0, 0)) + self.assert_unpack("RGBA", "G;16B", 2, (0, 1, 0, 0), (0, 3, 0, 0), (0, 5, 0, 0)) + self.assert_unpack("RGBA", "B;16B", 2, (0, 0, 1, 0), (0, 0, 3, 0), (0, 0, 5, 0)) + self.assert_unpack("RGBA", "A;16B", 2, (0, 0, 0, 1), (0, 0, 0, 3), (0, 0, 0, 5)) + + self.assert_unpack("RGBA", "R;16L", 2, (2, 0, 0, 0), (4, 0, 0, 0), (6, 0, 0, 0)) + self.assert_unpack("RGBA", "G;16L", 2, (0, 2, 0, 0), (0, 4, 0, 0), (0, 6, 0, 0)) + self.assert_unpack("RGBA", "B;16L", 2, (0, 0, 2, 0), (0, 0, 4, 0), (0, 0, 6, 0)) + self.assert_unpack("RGBA", "A;16L", 2, (0, 0, 0, 2), (0, 0, 0, 4), (0, 0, 0, 6)) + + if sys.byteorder == "little": + self.assert_unpack( + "RGBA", "R;16N", 2, (2, 0, 0, 0), (4, 0, 0, 0), (6, 0, 0, 0) + ) + self.assert_unpack( + "RGBA", "G;16N", 2, (0, 2, 0, 0), (0, 4, 0, 0), (0, 6, 0, 0) + ) + self.assert_unpack( + "RGBA", "B;16N", 2, (0, 0, 2, 0), (0, 0, 4, 0), (0, 0, 6, 0) + ) + self.assert_unpack( + "RGBA", "A;16N", 2, (0, 0, 0, 2), (0, 0, 0, 4), (0, 0, 0, 6) + ) + else: + self.assert_unpack( + "RGBA", "R;16N", 2, (1, 0, 0, 0), (3, 0, 0, 0), (5, 0, 0, 0) + ) + self.assert_unpack( + "RGBA", "G;16N", 2, (0, 1, 0, 0), (0, 3, 0, 0), (0, 5, 0, 0) + ) + self.assert_unpack( + "RGBA", "B;16N", 2, (0, 0, 1, 0), (0, 0, 3, 0), (0, 0, 5, 0) + ) + self.assert_unpack( + "RGBA", "A;16N", 2, (0, 0, 0, 1), (0, 0, 0, 3), (0, 0, 0, 5) + ) + def test_RGBa(self): self.assert_unpack( "RGBa", "RGBa", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12) diff --git a/src/libImaging/Unpack.c b/src/libImaging/Unpack.c index b4ba283b2..5dac95c1d 100644 --- a/src/libImaging/Unpack.c +++ b/src/libImaging/Unpack.c @@ -1363,6 +1363,94 @@ band3I(UINT8 *out, const UINT8 *in, int pixels) { } } +static void +band016B(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 0 only, big endian */ + for (i = 0; i < pixels; i++) { + out[0] = in[0]; + out += 4; in += 2; + } +} + +static void +band116B(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 1 only, big endian */ + for (i = 0; i < pixels; i++) { + out[1] = in[0]; + out += 4; in += 2; + } +} + +static void +band216B(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 2 only, big endian */ + for (i = 0; i < pixels; i++) { + out[2] = in[0]; + out += 4; in += 2; + } +} + +static void +band316B(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 3 only, big endian */ + for (i = 0; i < pixels; i++) { + out[3] = in[0]; + out += 4; in += 2; + } +} + +static void +band016L(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 0 only, little endian */ + for (i = 0; i < pixels; i++) { + out[0] = in[1]; + out += 4; in += 2; + } +} + +static void +band116L(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 1 only, little endian */ + for (i = 0; i < pixels; i++) { + out[1] = in[1]; + out += 4; in += 2; + } +} + +static void +band216L(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 2 only, little endian */ + for (i = 0; i < pixels; i++) { + out[2] = in[1]; + out += 4; in += 2; + } +} + +static void +band316L(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 3 only, little endian */ + for (i = 0; i < pixels; i++) { + out[3] = in[1]; + out += 4; in += 2; + } +} + static struct { const char *mode; const char *rawmode; @@ -1448,6 +1536,12 @@ static struct { {"RGB", "R", 8, band0}, {"RGB", "G", 8, band1}, {"RGB", "B", 8, band2}, + {"RGB", "R;16L", 16, band016L}, + {"RGB", "G;16L", 16, band116L}, + {"RGB", "B;16L", 16, band216L}, + {"RGB", "R;16B", 16, band016B}, + {"RGB", "G;16B", 16, band116B}, + {"RGB", "B;16B", 16, band216B}, /* true colour w. alpha */ {"RGBA", "LA", 16, unpackRGBALA}, @@ -1476,17 +1570,42 @@ static struct { {"RGBA", "G", 8, band1}, {"RGBA", "B", 8, band2}, {"RGBA", "A", 8, band3}, + {"RGBA", "R;16L", 16, band016L}, + {"RGBA", "G;16L", 16, band116L}, + {"RGBA", "B;16L", 16, band216L}, + {"RGBA", "A;16L", 16, band316L}, + {"RGBA", "R;16B", 16, band016B}, + {"RGBA", "G;16B", 16, band116B}, + {"RGBA", "B;16B", 16, band216B}, + {"RGBA", "A;16B", 16, band316B}, #ifdef WORDS_BIGENDIAN {"RGB", "RGB;16N", 48, unpackRGB16B}, {"RGBA", "RGBa;16N", 64, unpackRGBa16B}, {"RGBA", "RGBA;16N", 64, unpackRGBA16B}, {"RGBX", "RGBX;16N", 64, unpackRGBA16B}, + {"RGB", "R;16N", 16, band016B}, + {"RGB", "G;16N", 16, band116B}, + {"RGB", "B;16N", 16, band216B}, + + {"RGBA", "R;16N", 16, band016B}, + {"RGBA", "G;16N", 16, band116B}, + {"RGBA", "B;16N", 16, band216B}, + {"RGBA", "A;16N", 16, band316B}, #else {"RGB", "RGB;16N", 48, unpackRGB16L}, {"RGBA", "RGBa;16N", 64, unpackRGBa16L}, {"RGBA", "RGBA;16N", 64, unpackRGBA16L}, - {"RGBX", "RGBX;16N", 64, unpackRGBA16B}, + {"RGBX", "RGBX;16N", 64, unpackRGBA16L}, + {"RGB", "R;16N", 16, band016L}, + {"RGB", "G;16N", 16, band116L}, + {"RGB", "B;16N", 16, band216L}, + + + {"RGBA", "R;16N", 16, band016L}, + {"RGBA", "G;16N", 16, band116L}, + {"RGBA", "B;16N", 16, band216L}, + {"RGBA", "A;16N", 16, band316L}, #endif /* true colour w. alpha premultiplied */ From 64500434c21d2a038698dcc6c7b38cb04fce01e1 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Thu, 31 Dec 2020 13:01:35 +0100 Subject: [PATCH 66/89] Implementation for PlanarConfiguration=2 Tiffs, manually merged from f566c8a --- src/libImaging/TiffDecode.c | 222 ++++++++++++++++++++++-------------- 1 file changed, 139 insertions(+), 83 deletions(-) diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index 746994da3..f464ee23d 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -321,8 +321,8 @@ decodeycbcr_err: } int -_decodeStrip(Imaging im, ImagingCodecState state, TIFF *tiff) { - INT32 strip_row; +_decodeStrip(Imaging im, ImagingCodecState state, TIFF *tiff, UINT8 planes, ImagingShuffler *unpackers) { + INT32 strip_row = 0; UINT8 *new_data; UINT32 rows_per_strip, row_byte_size; int ret; @@ -334,7 +334,7 @@ _decodeStrip(Imaging im, ImagingCodecState state, TIFF *tiff) { TRACE(("RowsPerStrip: %u \n", rows_per_strip)); // We could use TIFFStripSize, but for YCbCr data it returns subsampled data size - row_byte_size = (state->xsize * state->bits + 7) / 8; + row_byte_size = (state->xsize * state->bits / planes + 7) / 8; /* overflow check for realloc */ if (INT_MAX / row_byte_size < rows_per_strip) { @@ -367,35 +367,35 @@ _decodeStrip(Imaging im, ImagingCodecState state, TIFF *tiff) { state->buffer = new_data; for (; state->y < state->ysize; state->y += rows_per_strip) { - if (TIFFReadEncodedStrip( - tiff, - TIFFComputeStrip(tiff, state->y, 0), - (tdata_t)state->buffer, - -1) == -1) { - TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, state->y, 0))); - state->errcode = IMAGING_CODEC_BROKEN; - return -1; - } + UINT8 plane; + for (plane = 0; plane < planes; plane++) { + ImagingShuffler shuffler = unpackers[plane]; + if (TIFFReadEncodedStrip(tiff, TIFFComputeStrip(tiff, state->y, plane), (tdata_t)state->buffer, -1) == -1) { + TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, state->y, 0))); + state->errcode = IMAGING_CODEC_BROKEN; + return -1; + } - TRACE(("Decoded strip for row %d \n", state->y)); + TRACE(("Decoded strip for row %d \n", state->y)); - // iterate over each row in the strip and stuff data into image - for (strip_row = 0; - strip_row < min((INT32)rows_per_strip, state->ysize - state->y); - strip_row++) { - TRACE(("Writing data into line %d ; \n", state->y + strip_row)); + // iterate over each row in the strip and stuff data into image + for (strip_row = 0; + strip_row < min((INT32) rows_per_strip, state->ysize - state->y); + strip_row++) { + TRACE(("Writing data into line %d ; \n", state->y + strip_row)); - // UINT8 * bbb = state->buffer + strip_row * (state->bytes / - // rows_per_strip); TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], - // ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); + // UINT8 * bbb = state->buffer + strip_row * (state->bytes / rows_per_strip); + // TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); - state->shuffle( - (UINT8 *)im->image[state->y + state->yoff + strip_row] + + shuffler( + (UINT8*) im->image[state->y + state->yoff + strip_row] + state->xoff * im->pixelsize, - state->buffer + strip_row * row_byte_size, - state->xsize); + state->buffer + strip_row * row_byte_size, + state->xsize); + } } } + return 0; } @@ -408,6 +408,9 @@ ImagingLibTiffDecode( TIFF *tiff; uint16 photometric = 0; // init to not PHOTOMETRIC_YCBCR int isYCbCr = 0; + UINT8 planarconfig = 0; + UINT8 planes = 1; + ImagingShuffler unpackers[4]; /* buffer is the encoded file, bytes is the length of the encoded file */ /* it all ends up in state->buffer, which is a uint8* from Imaging.h */ @@ -502,8 +505,38 @@ ImagingLibTiffDecode( } } + TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric); isYCbCr = photometric == PHOTOMETRIC_YCBCR; + TIFFGetFieldDefaulted(tiff, TIFFTAG_PLANARCONFIG, &planarconfig); + + // YCbCr data is read as RGB by libtiff and we don't need to worry about planar storage in that case + // if number of bands is 1, there is no difference with contig case + if (planarconfig == PLANARCONFIG_SEPARATE && + im->bands > 1 && + photometric != PHOTOMETRIC_YCBCR) { + + uint16 bits_per_sample = 8; + + TIFFGetFieldDefaulted(tiff, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); + if (bits_per_sample != 8 && bits_per_sample != 16) { + TRACE(("Invalid value for bits per sample: %d\n", bits_per_sample)); + state->errcode = IMAGING_CODEC_BROKEN; + goto decode_err; + } + + planes = im->bands; + + // We'll pick appropriate set of unpackers depending on planar_configuration + // It does not matter if data is RGB(A), CMYK or LUV really, + // we just copy it plane by plane + unpackers[0] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "R;16N" : "R", NULL); + unpackers[1] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "G;16N" : "G", NULL); + unpackers[2] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "B;16N" : "B", NULL); + unpackers[3] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "A;16N" : "A", NULL); + } else { + unpackers[0] = state->shuffle; + } if (TIFFIsTiled(tiff)) { INT32 x, y, tile_y; @@ -528,9 +561,8 @@ ImagingLibTiffDecode( goto decode_err; } } else { - // We could use TIFFTileSize, but for YCbCr data it returns subsampled data - // size - row_byte_size = (tile_width * state->bits + 7) / 8; + // We could use TIFFTileSize, but for YCbCr data it returns subsampled data size + row_byte_size = (tile_width * state->bits / planes + 7) / 8; } /* overflow check for realloc */ @@ -542,8 +574,7 @@ ImagingLibTiffDecode( state->bytes = row_byte_size * tile_length; if (TIFFTileSize(tiff) > state->bytes) { - // If the strip size as expected by LibTiff isn't what we're expecting, - // abort. + // If the tile size as expected by LibTiff isn't what we're expecting, abort. state->errcode = IMAGING_CODEC_MEMORY; goto decode_err; } @@ -561,75 +592,100 @@ ImagingLibTiffDecode( TRACE(("TIFFTileSize: %d\n", state->bytes)); for (y = state->yoff; y < state->ysize; y += tile_length) { - for (x = state->xoff; x < state->xsize; x += tile_width) { - /* Sanity Check. Apparently in some cases, the TiffReadRGBA* functions - have a different view of the size of the tiff than we're getting from - other functions. So, we need to check here. - */ - if (!TIFFCheckTile(tiff, x, y, 0, 0)) { - TRACE(("Check Tile Error, Tile at %dx%d\n", x, y)); - state->errcode = IMAGING_CODEC_BROKEN; - goto decode_err; - } - if (isYCbCr) { - /* To avoid dealing with YCbCr subsampling, let libtiff handle it */ - if (!TIFFReadRGBATile(tiff, x, y, (UINT32 *)state->buffer)) { - TRACE(("Decode Error, Tile at %dx%d\n", x, y)); + UINT8 plane; + for (plane = 0; plane < planes; plane++) { + ImagingShuffler shuffler = unpackers[plane]; + for (x = state->xoff; x < state->xsize; x += tile_width) { + /* Sanity Check. Apparently in some cases, the TiffReadRGBA* functions + have a different view of the size of the tiff than we're getting from + other functions. So, we need to check here. + */ + if (!TIFFCheckTile(tiff, x, y, 0, plane)) { + TRACE(("Check Tile Error, Tile at %dx%d\n", x, y)); state->errcode = IMAGING_CODEC_BROKEN; goto decode_err; } - } else { - if (TIFFReadTile(tiff, (tdata_t)state->buffer, x, y, 0, 0) == -1) { - TRACE(("Decode Error, Tile at %dx%d\n", x, y)); - state->errcode = IMAGING_CODEC_BROKEN; - goto decode_err; - } - } - - TRACE(("Read tile at %dx%d; \n\n", x, y)); - - current_tile_width = min((INT32)tile_width, state->xsize - x); - current_tile_length = min((INT32)tile_length, state->ysize - y); - // iterate over each line in the tile and stuff data into image - for (tile_y = 0; tile_y < current_tile_length; tile_y++) { - TRACE( - ("Writing tile data at %dx%d using tile_width: %d; \n", - tile_y + y, - x, - current_tile_width)); - - // UINT8 * bbb = state->buffer + tile_y * row_byte_size; - // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], - // ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); - /* - * For some reason the TIFFReadRGBATile() function - * chooses the lower left corner as the origin. - * Vertically mirror by shuffling the scanlines - * backwards - */ - if (isYCbCr) { - current_line = tile_length - tile_y - 1; + /* To avoid dealing with YCbCr subsampling, let libtiff handle it */ + if (!TIFFReadRGBATile(tiff, x, y, (UINT32 *)state->buffer)) { + TRACE(("Decode Error, Tile at %dx%d\n", x, y)); + state->errcode = IMAGING_CODEC_BROKEN; + goto decode_err; + } } else { - current_line = tile_y; + if (TIFFReadTile(tiff, (tdata_t)state->buffer, x, y, 0, plane) == -1) { + TRACE(("Decode Error, Tile at %dx%d\n", x, y)); + state->errcode = IMAGING_CODEC_BROKEN; + goto decode_err; + } } - state->shuffle( - (UINT8 *)im->image[tile_y + y] + x * im->pixelsize, - state->buffer + current_line * row_byte_size, - current_tile_width); + TRACE(("Read tile at %dx%d; \n\n", x, y)); + + current_tile_width = min((INT32) tile_width, state->xsize - x); + current_tile_length = min((INT32) tile_length, state->ysize - y); + // iterate over each line in the tile and stuff data into image + for (tile_y = 0; tile_y < current_tile_length; tile_y++) { + TRACE(("Writing tile data at %dx%d using tile_width: %d; \n", tile_y + y, x, current_tile_width)); + + // UINT8 * bbb = state->buffer + tile_y * row_byte_size; + // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); + /* + * For some reason the TIFFReadRGBATile() function + * chooses the lower left corner as the origin. + * Vertically mirror by shuffling the scanlines + * backwards + */ + + if (isYCbCr) { + current_line = tile_length - tile_y - 1; + } else { + current_line = tile_y; + } + + shuffler((UINT8*) im->image[tile_y + y] + x * im->pixelsize, + state->buffer + current_line * row_byte_size, + current_tile_width + ); + } } } } } else { if (!isYCbCr) { - _decodeStrip(im, state, tiff); - } else { + _decodeStrip(im, state, tiff, planes, unpackers); + } + else { _decodeStripYCbCr(im, state, tiff); } } -decode_err: + if (!state->errcode) { + // Check if raw mode was RGBa and it was stored on separate planes + // so we have to convert it to RGBA + if (planes > 3 && strcmp(im->mode, "RGBA") == 0) { + uint16 extrasamples; + uint16* sampleinfo; + ImagingShuffler shuffle; + INT32 y; + + TIFFGetFieldDefaulted(tiff, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo); + + if (extrasamples >= 1 && + (sampleinfo[0] == EXTRASAMPLE_UNSPECIFIED || sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA) + ) { + shuffle = ImagingFindUnpacker("RGBA", "RGBa", NULL); + + for (y = state->yoff; y < state->ysize; y++) { + UINT8* ptr = (UINT8*) im->image[y + state->yoff] + + state->xoff * im->pixelsize; + shuffle(ptr, ptr, state->xsize); + } + } + } + } + + decode_err: TIFFClose(tiff); TRACE(("Done Decoding, Returning \n")); // Returning -1 here to force ImageFile.load to break, rather than From 77a1a9aba3cc5a2d4c081cc81cd5c300ad3f9328 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Thu, 31 Dec 2020 14:35:26 +0100 Subject: [PATCH 67/89] initialize the unpackers --- src/libImaging/TiffDecode.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index f464ee23d..02c1c9f75 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -412,6 +412,8 @@ ImagingLibTiffDecode( UINT8 planes = 1; ImagingShuffler unpackers[4]; + memset(unpackers, 0, sizeof(ImagingShuffler *) * 4); + /* buffer is the encoded file, bytes is the length of the encoded file */ /* it all ends up in state->buffer, which is a uint8* from Imaging.h */ From a921c01102b046df07809e1f3e3a2fc24d078198 Mon Sep 17 00:00:00 2001 From: nulano Date: Sat, 9 Jan 2021 22:00:22 +0100 Subject: [PATCH 68/89] correct TIFFTAG_PLANARCONFIG size --- src/libImaging/TiffDecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index 02c1c9f75..b3a51f5b6 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -408,7 +408,7 @@ ImagingLibTiffDecode( TIFF *tiff; uint16 photometric = 0; // init to not PHOTOMETRIC_YCBCR int isYCbCr = 0; - UINT8 planarconfig = 0; + uint16 planarconfig = 0; UINT8 planes = 1; ImagingShuffler unpackers[4]; From 671837840a49613637f24555326747ba3a8ed991 Mon Sep 17 00:00:00 2001 From: nulano Date: Sat, 9 Jan 2021 22:41:13 +0100 Subject: [PATCH 69/89] the previous commit also fixes these big-endian failures --- Tests/test_file_libtiff.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index 43e6daeaf..c9f7d67c3 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -856,7 +856,6 @@ class TestFileLibTiff(LibTiffTestCase): with Image.open(infile) as im: assert_image_similar_tofile(im, "Tests/images/flower.jpg", 0.5) - @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_strip_planar_rgb(self): # gdal_translate -co TILED=no -co INTERLEAVE=BAND -co COMPRESS=LZW \ # tiff_strip_raw.tif tiff_strip_planar_lzw.tiff @@ -864,7 +863,6 @@ class TestFileLibTiff(LibTiffTestCase): with Image.open(infile) as im: assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") - @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_tiled_planar_rgb(self): # gdal_translate -co TILED=yes -co INTERLEAVE=BAND -co COMPRESS=LZW \ # tiff_tiled_raw.tif tiff_tiled_planar_lzw.tiff @@ -872,21 +870,18 @@ class TestFileLibTiff(LibTiffTestCase): with Image.open(infile) as im: assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") - @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_tiled_planar_16bit_RGB(self): # gdal_translate -co TILED=yes -co INTERLEAVE=BAND -co COMPRESS=LZW \ # tiff_16bit_RGB.tiff tiff_tiled_planar_16bit_RGB.tiff with Image.open("Tests/images/tiff_tiled_planar_16bit_RGB.tiff") as im: assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png") - @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_strip_planar_16bit_RGB(self): # gdal_translate -co TILED=no -co INTERLEAVE=BAND -co COMPRESS=LZW \ # tiff_16bit_RGB.tiff tiff_strip_planar_16bit_RGB.tiff with Image.open("Tests/images/tiff_strip_planar_16bit_RGB.tiff") as im: assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png") - @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_tiled_planar_16bit_RGBa(self): # gdal_translate -co TILED=yes \ # -co INTERLEAVE=BAND -co COMPRESS=LZW -co ALPHA=PREMULTIPLIED \ @@ -894,7 +889,6 @@ class TestFileLibTiff(LibTiffTestCase): with Image.open("Tests/images/tiff_tiled_planar_16bit_RGBa.tiff") as im: assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png") - @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_strip_planar_16bit_RGBa(self): # gdal_translate -co TILED=no \ # -co INTERLEAVE=BAND -co COMPRESS=LZW -co ALPHA=PREMULTIPLIED \ From daf7b6546e1bb9753062018cc7b0d987e2d66bf8 Mon Sep 17 00:00:00 2001 From: nulano Date: Sat, 9 Jan 2021 22:45:38 +0100 Subject: [PATCH 70/89] remove double pointer --- src/libImaging/TiffDecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index b3a51f5b6..9b5916ac0 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -412,7 +412,7 @@ ImagingLibTiffDecode( UINT8 planes = 1; ImagingShuffler unpackers[4]; - memset(unpackers, 0, sizeof(ImagingShuffler *) * 4); + memset(unpackers, 0, sizeof(ImagingShuffler) * 4); /* buffer is the encoded file, bytes is the length of the encoded file */ /* it all ends up in state->buffer, which is a uint8* from Imaging.h */ From fda638befecca25f9eb75ce39600dfc8e88c2608 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sun, 10 Jan 2021 19:29:56 +0100 Subject: [PATCH 71/89] Planes should be int, not uint --- src/libImaging/TiffDecode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index 9b5916ac0..07e9ab2c7 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -321,7 +321,7 @@ decodeycbcr_err: } int -_decodeStrip(Imaging im, ImagingCodecState state, TIFF *tiff, UINT8 planes, ImagingShuffler *unpackers) { +_decodeStrip(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, ImagingShuffler *unpackers) { INT32 strip_row = 0; UINT8 *new_data; UINT32 rows_per_strip, row_byte_size; @@ -409,7 +409,7 @@ ImagingLibTiffDecode( uint16 photometric = 0; // init to not PHOTOMETRIC_YCBCR int isYCbCr = 0; uint16 planarconfig = 0; - UINT8 planes = 1; + int planes = 1; ImagingShuffler unpackers[4]; memset(unpackers, 0, sizeof(ImagingShuffler) * 4); From c9ea87ecfd1f486e0ffdf278d7d000bbd78d7053 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Sun, 10 Jan 2021 19:31:56 +0100 Subject: [PATCH 72/89] Use flag instead of recalculating --- src/libImaging/TiffDecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index 07e9ab2c7..bae9b7a15 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -516,7 +516,7 @@ ImagingLibTiffDecode( // if number of bands is 1, there is no difference with contig case if (planarconfig == PLANARCONFIG_SEPARATE && im->bands > 1 && - photometric != PHOTOMETRIC_YCBCR) { + isYCbCr) { uint16 bits_per_sample = 8; From b1d3f0d5c21a935112794d06a5b70a2cb6c30e29 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Mon, 11 Jan 2021 20:57:08 +0100 Subject: [PATCH 73/89] not --- src/libImaging/TiffDecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index bae9b7a15..7629aec95 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -516,7 +516,7 @@ ImagingLibTiffDecode( // if number of bands is 1, there is no difference with contig case if (planarconfig == PLANARCONFIG_SEPARATE && im->bands > 1 && - isYCbCr) { + !isYCbCr) { uint16 bits_per_sample = 8; From f2020eeab454814d57adfcbf4c6e932ded1f3a35 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Mon, 11 Jan 2021 22:28:23 +0100 Subject: [PATCH 74/89] UINT8 -> int for plane --- src/libImaging/TiffDecode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index 7629aec95..232278985 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -367,7 +367,7 @@ _decodeStrip(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, Imagin state->buffer = new_data; for (; state->y < state->ysize; state->y += rows_per_strip) { - UINT8 plane; + int plane; for (plane = 0; plane < planes; plane++) { ImagingShuffler shuffler = unpackers[plane]; if (TIFFReadEncodedStrip(tiff, TIFFComputeStrip(tiff, state->y, plane), (tdata_t)state->buffer, -1) == -1) { @@ -594,7 +594,7 @@ ImagingLibTiffDecode( TRACE(("TIFFTileSize: %d\n", state->bytes)); for (y = state->yoff; y < state->ysize; y += tile_length) { - UINT8 plane; + int plane; for (plane = 0; plane < planes; plane++) { ImagingShuffler shuffler = unpackers[plane]; for (x = state->xoff; x < state->xsize; x += tile_width) { From 169bb4842f10303c6d2c37adc25dc9983cb5e506 Mon Sep 17 00:00:00 2001 From: Konstantin Kopachev Date: Sat, 9 Jan 2021 15:05:36 -0800 Subject: [PATCH 75/89] only use TIFFReadRGBA* in case of o_jpeg compression --- Tests/test_file_libtiff.py | 4 ---- src/PIL/TiffImagePlugin.py | 9 +++++++++ src/libImaging/TiffDecode.c | 11 ++++++++++- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index c9f7d67c3..3f2e5dbc1 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -824,14 +824,12 @@ class TestFileLibTiff(LibTiffTestCase): assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5) @pytest.mark.valgrind_known_error(reason="Known Failing") - @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_strip_ycbcr_jpeg_2x2_sampling(self): infile = "Tests/images/tiff_strip_ycbcr_jpeg_2x2_sampling.tif" with Image.open(infile) as im: assert_image_similar_tofile(im, "Tests/images/flower.jpg", 0.5) @pytest.mark.valgrind_known_error(reason="Known Failing") - @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_strip_ycbcr_jpeg_1x1_sampling(self): infile = "Tests/images/tiff_strip_ycbcr_jpeg_1x1_sampling.tif" with Image.open(infile) as im: @@ -843,14 +841,12 @@ class TestFileLibTiff(LibTiffTestCase): assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5) @pytest.mark.valgrind_known_error(reason="Known Failing") - @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_tiled_ycbcr_jpeg_1x1_sampling(self): infile = "Tests/images/tiff_tiled_ycbcr_jpeg_1x1_sampling.tif" with Image.open(infile) as im: assert_image_equal_tofile(im, "Tests/images/flower2.jpg") @pytest.mark.valgrind_known_error(reason="Known Failing") - @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_tiled_ycbcr_jpeg_2x2_sampling(self): infile = "Tests/images/tiff_tiled_ycbcr_jpeg_2x2_sampling.tif" with Image.open(infile) as im: diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 19bcf4419..24821d130 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -1324,6 +1324,15 @@ class TiffImageFile(ImageFile.ImageFile): if ";16L" in rawmode: rawmode = rawmode.replace(";16L", ";16N") + # YCbCr images with new jpeg compression with pixels in one plane + # unpacked straight into RGB values + if ( + photo == 6 + and self._compression == "jpeg" + and self._planar_configuration == 1 + ): + rawmode = "RGB" + # Offset in the tile tuple is 0, we go from 0,0 to # w,h, and we only do this once -- eds a = (rawmode, self._compression, False, self.tag_v2.offset) diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index 232278985..e20f57596 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -407,6 +407,7 @@ ImagingLibTiffDecode( char *mode = "r"; TIFF *tiff; uint16 photometric = 0; // init to not PHOTOMETRIC_YCBCR + uint16 compression; int isYCbCr = 0; uint16 planarconfig = 0; int planes = 1; @@ -509,9 +510,17 @@ ImagingLibTiffDecode( TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric); - isYCbCr = photometric == PHOTOMETRIC_YCBCR; + TIFFGetField(tiff, TIFFTAG_COMPRESSION, &compression); TIFFGetFieldDefaulted(tiff, TIFFTAG_PLANARCONFIG, &planarconfig); + isYCbCr = photometric == PHOTOMETRIC_YCBCR; + + if (isYCbCr && compression == COMPRESSION_JPEG && planarconfig == PLANARCONFIG_CONTIG) { + // If using new JPEG compression, let libjpeg do RGB convertion + TIFFSetField(tiff, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); + isYCbCr = 0; + } + // YCbCr data is read as RGB by libtiff and we don't need to worry about planar storage in that case // if number of bands is 1, there is no difference with contig case if (planarconfig == PLANARCONFIG_SEPARATE && From 4c2dfadf26b1d5a6a86e7dd66968f5222a1d24e3 Mon Sep 17 00:00:00 2001 From: Konstantin Kopachev Date: Mon, 11 Jan 2021 22:06:49 -0800 Subject: [PATCH 76/89] Swap pixel values on Big Endian --- Tests/test_file_libtiff.py | 2 -- src/libImaging/TiffDecode.c | 8 ++++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index 3f2e5dbc1..22b641b5f 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -17,7 +17,6 @@ from .helper import ( assert_image_similar, assert_image_similar_tofile, hopper, - is_big_endian, skip_unless_feature, ) @@ -892,7 +891,6 @@ class TestFileLibTiff(LibTiffTestCase): with Image.open("Tests/images/tiff_strip_planar_16bit_RGBa.tiff") as im: assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png") - @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_old_style_jpeg(self): infile = "Tests/images/old-style-jpeg-compression.tif" with Image.open(infile) as im: diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index e20f57596..b1a30f449 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -292,6 +292,10 @@ _decodeStripYCbCr(Imaging im, ImagingCodecState state, TIFF *tiff) { goto decodeycbcr_err; } +#if WORDS_BIGENDIAN + TIFFSwabArrayOfLong((UINT32 *)state->buffer, img.width * rows_to_read); +#endif + TRACE(("Decoded strip for row %d \n", state->y)); // iterate over each row in the strip and stuff data into image @@ -623,6 +627,10 @@ ImagingLibTiffDecode( state->errcode = IMAGING_CODEC_BROKEN; goto decode_err; } + +#if WORDS_BIGENDIAN + TIFFSwabArrayOfLong((UINT32 *)state->buffer, tile_width * tile_length); +#endif } else { if (TIFFReadTile(tiff, (tdata_t)state->buffer, x, y, 0, plane) == -1) { TRACE(("Decode Error, Tile at %dx%d\n", x, y)); From 4dd288c66c3e07cfffcc0f21e0bc7a9a2f4f2758 Mon Sep 17 00:00:00 2001 From: Konstantin Kopachev Date: Mon, 11 Jan 2021 23:28:58 -0800 Subject: [PATCH 77/89] unify reading of YCbCr Tiffs --- src/libImaging/TiffDecode.c | 291 +++++++++++++++++------------------- 1 file changed, 136 insertions(+), 155 deletions(-) diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index b1a30f449..bbc190d27 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -213,24 +213,34 @@ ImagingLibTiffInit(ImagingCodecState state, int fp, uint32 offset) { } int -_decodeStripYCbCr(Imaging im, ImagingCodecState state, TIFF *tiff) { +_decodeYCbCr(Imaging im, ImagingCodecState state, TIFF *tiff) { // To avoid dealing with YCbCr subsampling, let libtiff handle it // Use a TIFFRGBAImage wrapping the tiff image, and let libtiff handle // all of the conversion. Metadata read from the TIFFRGBAImage could // be different from the metadata that the base tiff returns. - INT32 strip_row; + INT32 current_row; UINT8 *new_data; - UINT32 rows_per_strip, row_byte_size, rows_to_read; + UINT32 rows_per_block, row_byte_size, rows_to_read; int ret; TIFFRGBAImage img; char emsg[1024] = ""; - ret = TIFFGetFieldDefaulted(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip); - if (ret != 1) { - rows_per_strip = state->ysize; + // Since using TIFFRGBAImage* functions, we can read whole tiff into rastrr in one call + // Let's select smaller block size. Multiplying image width by (tile length OR rows per strip) + // gives us manageable block size in pixels + if (TIFFIsTiled(tiff)) { + ret = TIFFGetFieldDefaulted(tiff, TIFFTAG_TILELENGTH, &rows_per_block); } - TRACE(("RowsPerStrip: %u \n", rows_per_strip)); + else { + ret = TIFFGetFieldDefaulted(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_block); + } + + if (ret != 1) { + rows_per_block = state->ysize; + } + + TRACE(("RowsPerBlock: %u \n", rows_per_block)); if (!(TIFFRGBAImageOK(tiff, emsg) && TIFFRGBAImageBegin(&img, tiff, 0, emsg))) { TRACE(("Decode error, msg: %s", emsg)); @@ -263,14 +273,14 @@ _decodeStripYCbCr(Imaging im, ImagingCodecState state, TIFF *tiff) { row_byte_size = img.width * 4; /* overflow check for realloc */ - if (INT_MAX / row_byte_size < rows_per_strip) { + if (INT_MAX / row_byte_size < rows_per_block) { state->errcode = IMAGING_CODEC_MEMORY; goto decodeycbcr_err; } - state->bytes = rows_per_strip * row_byte_size; + state->bytes = rows_per_block * row_byte_size; - TRACE(("StripSize: %d \n", state->bytes)); + TRACE(("BlockSize: %d \n", state->bytes)); /* realloc to fit whole strip */ /* malloc check above */ @@ -282,9 +292,9 @@ _decodeStripYCbCr(Imaging im, ImagingCodecState state, TIFF *tiff) { state->buffer = new_data; - for (; state->y < state->ysize; state->y += rows_per_strip) { + for (; state->y < state->ysize; state->y += rows_per_block) { img.row_offset = state->y; - rows_to_read = min(rows_per_strip, img.height - state->y); + rows_to_read = min(rows_per_block, img.height - state->y); if (!TIFFRGBAImageGet(&img, (UINT32 *)state->buffer, img.width, rows_to_read)) { TRACE(("Decode Error, y: %d\n", state->y)); @@ -299,19 +309,19 @@ _decodeStripYCbCr(Imaging im, ImagingCodecState state, TIFF *tiff) { TRACE(("Decoded strip for row %d \n", state->y)); // iterate over each row in the strip and stuff data into image - for (strip_row = 0; - strip_row < min((INT32)rows_per_strip, state->ysize - state->y); - strip_row++) { - TRACE(("Writing data into line %d ; \n", state->y + strip_row)); + for (current_row = 0; + current_row < min((INT32)rows_per_block, state->ysize - state->y); + current_row++) { + TRACE(("Writing data into line %d ; \n", state->y + current_row)); - // UINT8 * bbb = state->buffer + strip_row * (state->bytes / - // rows_per_strip); TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], + // UINT8 * bbb = state->buffer + current_row * (state->bytes / + // rows_per_block); TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], // ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); state->shuffle( - (UINT8 *)im->image[state->y + state->yoff + strip_row] + + (UINT8 *)im->image[state->y + state->yoff + current_row] + state->xoff * im->pixelsize, - state->buffer + strip_row * row_byte_size, + state->buffer + current_row * row_byte_size, state->xsize); } } @@ -525,180 +535,151 @@ ImagingLibTiffDecode( isYCbCr = 0; } - // YCbCr data is read as RGB by libtiff and we don't need to worry about planar storage in that case - // if number of bands is 1, there is no difference with contig case - if (planarconfig == PLANARCONFIG_SEPARATE && - im->bands > 1 && - !isYCbCr) { - - uint16 bits_per_sample = 8; - - TIFFGetFieldDefaulted(tiff, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); - if (bits_per_sample != 8 && bits_per_sample != 16) { - TRACE(("Invalid value for bits per sample: %d\n", bits_per_sample)); - state->errcode = IMAGING_CODEC_BROKEN; - goto decode_err; - } - - planes = im->bands; - - // We'll pick appropriate set of unpackers depending on planar_configuration - // It does not matter if data is RGB(A), CMYK or LUV really, - // we just copy it plane by plane - unpackers[0] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "R;16N" : "R", NULL); - unpackers[1] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "G;16N" : "G", NULL); - unpackers[2] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "B;16N" : "B", NULL); - unpackers[3] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "A;16N" : "A", NULL); - } else { - unpackers[0] = state->shuffle; + if (isYCbCr) { + _decodeYCbCr(im, state, tiff); } + else { + // YCbCr data is read as RGB by libtiff and we don't need to worry about planar storage in that case + // if number of bands is 1, there is no difference with contig case + if (planarconfig == PLANARCONFIG_SEPARATE && + im->bands > 1 && + !isYCbCr) { - if (TIFFIsTiled(tiff)) { - INT32 x, y, tile_y; - UINT32 tile_width, tile_length, current_tile_length, current_line, - current_tile_width, row_byte_size; - UINT8 *new_data; + uint16 bits_per_sample = 8; - TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tile_width); - TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tile_length); - - /* overflow check for row_byte_size calculation */ - if ((UINT32)INT_MAX / state->bits < tile_width) { - state->errcode = IMAGING_CODEC_MEMORY; - goto decode_err; - } - - if (isYCbCr) { - row_byte_size = tile_width * 4; - /* sanity check, we use this value in shuffle below */ - if (im->pixelsize != 4) { + TIFFGetFieldDefaulted(tiff, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); + if (bits_per_sample != 8 && bits_per_sample != 16) { + TRACE(("Invalid value for bits per sample: %d\n", bits_per_sample)); state->errcode = IMAGING_CODEC_BROKEN; goto decode_err; } + + planes = im->bands; + + // We'll pick appropriate set of unpackers depending on planar_configuration + // It does not matter if data is RGB(A), CMYK or LUV really, + // we just copy it plane by plane + unpackers[0] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "R;16N" : "R", NULL); + unpackers[1] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "G;16N" : "G", NULL); + unpackers[2] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "B;16N" : "B", NULL); + unpackers[3] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "A;16N" : "A", NULL); } else { - // We could use TIFFTileSize, but for YCbCr data it returns subsampled data size + unpackers[0] = state->shuffle; + } + + if (TIFFIsTiled(tiff)) { + INT32 x, y, tile_y; + UINT32 tile_width, tile_length, current_tile_length, current_line, + current_tile_width, row_byte_size; + UINT8 *new_data; + + TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tile_width); + TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tile_length); + + /* overflow check for row_byte_size calculation */ + if ((UINT32)INT_MAX / state->bits < tile_width) { + state->errcode = IMAGING_CODEC_MEMORY; + goto decode_err; + } + + // We could use TIFFTileSize, but for YCbCr data it returns subsampled data + // size row_byte_size = (tile_width * state->bits / planes + 7) / 8; - } - /* overflow check for realloc */ - if (INT_MAX / row_byte_size < tile_length) { - state->errcode = IMAGING_CODEC_MEMORY; - goto decode_err; - } + /* overflow check for realloc */ + if (INT_MAX / row_byte_size < tile_length) { + state->errcode = IMAGING_CODEC_MEMORY; + goto decode_err; + } - state->bytes = row_byte_size * tile_length; + state->bytes = row_byte_size * tile_length; - if (TIFFTileSize(tiff) > state->bytes) { - // If the tile size as expected by LibTiff isn't what we're expecting, abort. - state->errcode = IMAGING_CODEC_MEMORY; - goto decode_err; - } + if (TIFFTileSize(tiff) > state->bytes) { + // If the tile size as expected by LibTiff isn't what we're expecting, + // abort. + state->errcode = IMAGING_CODEC_MEMORY; + goto decode_err; + } - /* realloc to fit whole tile */ - /* malloc check above */ - new_data = realloc(state->buffer, state->bytes); - if (!new_data) { - state->errcode = IMAGING_CODEC_MEMORY; - goto decode_err; - } + /* realloc to fit whole tile */ + /* malloc check above */ + new_data = realloc(state->buffer, state->bytes); + if (!new_data) { + state->errcode = IMAGING_CODEC_MEMORY; + goto decode_err; + } - state->buffer = new_data; + state->buffer = new_data; - TRACE(("TIFFTileSize: %d\n", state->bytes)); + TRACE(("TIFFTileSize: %d\n", state->bytes)); - for (y = state->yoff; y < state->ysize; y += tile_length) { - int plane; - for (plane = 0; plane < planes; plane++) { - ImagingShuffler shuffler = unpackers[plane]; - for (x = state->xoff; x < state->xsize; x += tile_width) { - /* Sanity Check. Apparently in some cases, the TiffReadRGBA* functions - have a different view of the size of the tiff than we're getting from - other functions. So, we need to check here. - */ - if (!TIFFCheckTile(tiff, x, y, 0, plane)) { - TRACE(("Check Tile Error, Tile at %dx%d\n", x, y)); - state->errcode = IMAGING_CODEC_BROKEN; - goto decode_err; - } - if (isYCbCr) { - /* To avoid dealing with YCbCr subsampling, let libtiff handle it */ - if (!TIFFReadRGBATile(tiff, x, y, (UINT32 *)state->buffer)) { - TRACE(("Decode Error, Tile at %dx%d\n", x, y)); + for (y = state->yoff; y < state->ysize; y += tile_length) { + int plane; + for (plane = 0; plane < planes; plane++) { + ImagingShuffler shuffler = unpackers[plane]; + for (x = state->xoff; x < state->xsize; x += tile_width) { + /* Sanity Check. Apparently in some cases, the TiffReadRGBA* functions + have a different view of the size of the tiff than we're getting from + other functions. So, we need to check here. + */ + if (!TIFFCheckTile(tiff, x, y, 0, plane)) { + TRACE(("Check Tile Error, Tile at %dx%d\n", x, y)); state->errcode = IMAGING_CODEC_BROKEN; goto decode_err; } - -#if WORDS_BIGENDIAN - TIFFSwabArrayOfLong((UINT32 *)state->buffer, tile_width * tile_length); -#endif - } else { if (TIFFReadTile(tiff, (tdata_t)state->buffer, x, y, 0, plane) == -1) { TRACE(("Decode Error, Tile at %dx%d\n", x, y)); state->errcode = IMAGING_CODEC_BROKEN; goto decode_err; } - } - TRACE(("Read tile at %dx%d; \n\n", x, y)); + TRACE(("Read tile at %dx%d; \n\n", x, y)); - current_tile_width = min((INT32) tile_width, state->xsize - x); - current_tile_length = min((INT32) tile_length, state->ysize - y); - // iterate over each line in the tile and stuff data into image - for (tile_y = 0; tile_y < current_tile_length; tile_y++) { - TRACE(("Writing tile data at %dx%d using tile_width: %d; \n", tile_y + y, x, current_tile_width)); + current_tile_width = min((INT32) tile_width, state->xsize - x); + current_tile_length = min((INT32) tile_length, state->ysize - y); + // iterate over each line in the tile and stuff data into image + for (tile_y = 0; tile_y < current_tile_length; tile_y++) { + TRACE(("Writing tile data at %dx%d using tile_width: %d; \n", tile_y + y, x, current_tile_width)); - // UINT8 * bbb = state->buffer + tile_y * row_byte_size; - // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); - /* - * For some reason the TIFFReadRGBATile() function - * chooses the lower left corner as the origin. - * Vertically mirror by shuffling the scanlines - * backwards - */ + // UINT8 * bbb = state->buffer + tile_y * row_byte_size; + // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); - if (isYCbCr) { - current_line = tile_length - tile_y - 1; - } else { current_line = tile_y; - } - shuffler((UINT8*) im->image[tile_y + y] + x * im->pixelsize, - state->buffer + current_line * row_byte_size, - current_tile_width - ); + shuffler((UINT8*) im->image[tile_y + y] + x * im->pixelsize, + state->buffer + current_line * row_byte_size, + current_tile_width + ); + } } } } } - } else { - if (!isYCbCr) { + else { _decodeStrip(im, state, tiff, planes, unpackers); } - else { - _decodeStripYCbCr(im, state, tiff); - } - } - if (!state->errcode) { - // Check if raw mode was RGBa and it was stored on separate planes - // so we have to convert it to RGBA - if (planes > 3 && strcmp(im->mode, "RGBA") == 0) { - uint16 extrasamples; - uint16* sampleinfo; - ImagingShuffler shuffle; - INT32 y; + if (!state->errcode) { + // Check if raw mode was RGBa and it was stored on separate planes + // so we have to convert it to RGBA + if (planes > 3 && strcmp(im->mode, "RGBA") == 0) { + uint16 extrasamples; + uint16* sampleinfo; + ImagingShuffler shuffle; + INT32 y; - TIFFGetFieldDefaulted(tiff, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo); + TIFFGetFieldDefaulted(tiff, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo); - if (extrasamples >= 1 && - (sampleinfo[0] == EXTRASAMPLE_UNSPECIFIED || sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA) - ) { - shuffle = ImagingFindUnpacker("RGBA", "RGBa", NULL); + if (extrasamples >= 1 && + (sampleinfo[0] == EXTRASAMPLE_UNSPECIFIED || sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA) + ) { + shuffle = ImagingFindUnpacker("RGBA", "RGBa", NULL); - for (y = state->yoff; y < state->ysize; y++) { - UINT8* ptr = (UINT8*) im->image[y + state->yoff] + - state->xoff * im->pixelsize; - shuffle(ptr, ptr, state->xsize); + for (y = state->yoff; y < state->ysize; y++) { + UINT8* ptr = (UINT8*) im->image[y + state->yoff] + + state->xoff * im->pixelsize; + shuffle(ptr, ptr, state->xsize); + } } } } From e43804620174e057774483230ffe0290d54d3d00 Mon Sep 17 00:00:00 2001 From: Konstantin Kopachev Date: Wed, 13 Jan 2021 18:33:49 -0800 Subject: [PATCH 78/89] Refactor into smaller functions --- src/libImaging/TiffDecode.c | 269 +++++++++++++++++++----------------- 1 file changed, 142 insertions(+), 127 deletions(-) diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index bbc190d27..913b0742c 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -213,8 +213,37 @@ ImagingLibTiffInit(ImagingCodecState state, int fp, uint32 offset) { } int -_decodeYCbCr(Imaging im, ImagingCodecState state, TIFF *tiff) { - // To avoid dealing with YCbCr subsampling, let libtiff handle it +_pickUnpackers(Imaging im, ImagingCodecState state, TIFF *tiff, uint16 planarconfig, ImagingShuffler *unpackers) { + // if number of bands is 1, there is no difference with contig case + if (planarconfig == PLANARCONFIG_SEPARATE && im->bands > 1) { + uint16 bits_per_sample = 8; + + TIFFGetFieldDefaulted(tiff, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); + if (bits_per_sample != 8 && bits_per_sample != 16) { + TRACE(("Invalid value for bits per sample: %d\n", bits_per_sample)); + state->errcode = IMAGING_CODEC_BROKEN; + return -1; + } + + // We'll pick appropriate set of unpackers depending on planar_configuration + // It does not matter if data is RGB(A), CMYK or LUV really, + // we just copy it plane by plane + unpackers[0] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "R;16N" : "R", NULL); + unpackers[1] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "G;16N" : "G", NULL); + unpackers[2] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "B;16N" : "B", NULL); + unpackers[3] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "A;16N" : "A", NULL); + + return im->bands; + } else { + unpackers[0] = state->shuffle; + + return 1; + } +} + +int +_decodeAsRGBA(Imaging im, ImagingCodecState state, TIFF *tiff) { + // To avoid dealing with YCbCr subsampling and other complications, let libtiff handle it // Use a TIFFRGBAImage wrapping the tiff image, and let libtiff handle // all of the conversion. Metadata read from the TIFFRGBAImage could // be different from the metadata that the base tiff returns. @@ -260,13 +289,13 @@ _decodeYCbCr(Imaging im, ImagingCodecState state, TIFF *tiff) { state->ysize, img.height)); state->errcode = IMAGING_CODEC_BROKEN; - goto decodeycbcr_err; + goto decodergba_err; } /* overflow check for row byte size */ if (INT_MAX / 4 < img.width) { state->errcode = IMAGING_CODEC_MEMORY; - goto decodeycbcr_err; + goto decodergba_err; } // TiffRGBAImages are 32bits/pixel. @@ -275,7 +304,7 @@ _decodeYCbCr(Imaging im, ImagingCodecState state, TIFF *tiff) { /* overflow check for realloc */ if (INT_MAX / row_byte_size < rows_per_block) { state->errcode = IMAGING_CODEC_MEMORY; - goto decodeycbcr_err; + goto decodergba_err; } state->bytes = rows_per_block * row_byte_size; @@ -287,7 +316,7 @@ _decodeYCbCr(Imaging im, ImagingCodecState state, TIFF *tiff) { new_data = realloc(state->buffer, state->bytes); if (!new_data) { state->errcode = IMAGING_CODEC_MEMORY; - goto decodeycbcr_err; + goto decodergba_err; } state->buffer = new_data; @@ -299,7 +328,7 @@ _decodeYCbCr(Imaging im, ImagingCodecState state, TIFF *tiff) { if (!TIFFRGBAImageGet(&img, (UINT32 *)state->buffer, img.width, rows_to_read)) { TRACE(("Decode Error, y: %d\n", state->y)); state->errcode = IMAGING_CODEC_BROKEN; - goto decodeycbcr_err; + goto decodergba_err; } #if WORDS_BIGENDIAN @@ -326,7 +355,7 @@ _decodeYCbCr(Imaging im, ImagingCodecState state, TIFF *tiff) { } } -decodeycbcr_err: +decodergba_err: TIFFRGBAImageEnd(&img); if (state->errcode != 0) { return -1; @@ -334,6 +363,98 @@ decodeycbcr_err: return 0; } +int +_decodeTile(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, ImagingShuffler *unpackers) { + INT32 x, y, tile_y; + UINT32 tile_width, tile_length, current_tile_length, current_line, + current_tile_width, row_byte_size; + UINT8 *new_data; + + TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tile_width); + TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tile_length); + + /* overflow check for row_byte_size calculation */ + if ((UINT32)INT_MAX / state->bits < tile_width) { + state->errcode = IMAGING_CODEC_MEMORY; + return -1; + } + + // We could use TIFFTileSize, but for YCbCr data it returns subsampled data + // size + row_byte_size = (tile_width * state->bits / planes + 7) / 8; + + /* overflow check for realloc */ + if (INT_MAX / row_byte_size < tile_length) { + state->errcode = IMAGING_CODEC_MEMORY; + return -1; + } + + state->bytes = row_byte_size * tile_length; + + if (TIFFTileSize(tiff) > state->bytes) { + // If the tile size as expected by LibTiff isn't what we're expecting, + // abort. + state->errcode = IMAGING_CODEC_MEMORY; + return -1; + } + + /* realloc to fit whole tile */ + /* malloc check above */ + new_data = realloc(state->buffer, state->bytes); + if (!new_data) { + state->errcode = IMAGING_CODEC_MEMORY; + return -1; + } + + state->buffer = new_data; + + TRACE(("TIFFTileSize: %d\n", state->bytes)); + + for (y = state->yoff; y < state->ysize; y += tile_length) { + int plane; + for (plane = 0; plane < planes; plane++) { + ImagingShuffler shuffler = unpackers[plane]; + for (x = state->xoff; x < state->xsize; x += tile_width) { + /* Sanity Check. Apparently in some cases, the TiffReadRGBA* functions + have a different view of the size of the tiff than we're getting from + other functions. So, we need to check here. + */ + if (!TIFFCheckTile(tiff, x, y, 0, plane)) { + TRACE(("Check Tile Error, Tile at %dx%d\n", x, y)); + state->errcode = IMAGING_CODEC_BROKEN; + return -1; + } + if (TIFFReadTile(tiff, (tdata_t)state->buffer, x, y, 0, plane) == -1) { + TRACE(("Decode Error, Tile at %dx%d\n", x, y)); + state->errcode = IMAGING_CODEC_BROKEN; + return -1; + } + + TRACE(("Read tile at %dx%d; \n\n", x, y)); + + current_tile_width = min((INT32) tile_width, state->xsize - x); + current_tile_length = min((INT32) tile_length, state->ysize - y); + // iterate over each line in the tile and stuff data into image + for (tile_y = 0; tile_y < current_tile_length; tile_y++) { + TRACE(("Writing tile data at %dx%d using tile_width: %d; \n", tile_y + y, x, current_tile_width)); + + // UINT8 * bbb = state->buffer + tile_y * row_byte_size; + // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); + + current_line = tile_y; + + shuffler((UINT8*) im->image[tile_y + y] + x * im->pixelsize, + state->buffer + current_line * row_byte_size, + current_tile_width + ); + } + } + } + } + + return 0; +} + int _decodeStrip(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, ImagingShuffler *unpackers) { INT32 strip_row = 0; @@ -422,7 +543,7 @@ ImagingLibTiffDecode( TIFF *tiff; uint16 photometric = 0; // init to not PHOTOMETRIC_YCBCR uint16 compression; - int isYCbCr = 0; + int readAsRGBA = 0; uint16 planarconfig = 0; int planes = 1; ImagingShuffler unpackers[4]; @@ -527,133 +648,27 @@ ImagingLibTiffDecode( TIFFGetField(tiff, TIFFTAG_COMPRESSION, &compression); TIFFGetFieldDefaulted(tiff, TIFFTAG_PLANARCONFIG, &planarconfig); - isYCbCr = photometric == PHOTOMETRIC_YCBCR; + // Dealing with YCbCr images is complicated in case if subsampling + // Let LibTiff read them as RGBA + readAsRGBA = photometric == PHOTOMETRIC_YCBCR; - if (isYCbCr && compression == COMPRESSION_JPEG && planarconfig == PLANARCONFIG_CONTIG) { - // If using new JPEG compression, let libjpeg do RGB convertion + if (readAsRGBA && compression == COMPRESSION_JPEG && planarconfig == PLANARCONFIG_CONTIG) { + // If using new JPEG compression, let libjpeg do RGB convertion for performance reasons TIFFSetField(tiff, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); - isYCbCr = 0; + readAsRGBA = 0; } - if (isYCbCr) { - _decodeYCbCr(im, state, tiff); + if (readAsRGBA) { + _decodeAsRGBA(im, state, tiff); } else { - // YCbCr data is read as RGB by libtiff and we don't need to worry about planar storage in that case - // if number of bands is 1, there is no difference with contig case - if (planarconfig == PLANARCONFIG_SEPARATE && - im->bands > 1 && - !isYCbCr) { - - uint16 bits_per_sample = 8; - - TIFFGetFieldDefaulted(tiff, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); - if (bits_per_sample != 8 && bits_per_sample != 16) { - TRACE(("Invalid value for bits per sample: %d\n", bits_per_sample)); - state->errcode = IMAGING_CODEC_BROKEN; - goto decode_err; - } - - planes = im->bands; - - // We'll pick appropriate set of unpackers depending on planar_configuration - // It does not matter if data is RGB(A), CMYK or LUV really, - // we just copy it plane by plane - unpackers[0] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "R;16N" : "R", NULL); - unpackers[1] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "G;16N" : "G", NULL); - unpackers[2] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "B;16N" : "B", NULL); - unpackers[3] = ImagingFindUnpacker("RGBA", bits_per_sample == 16 ? "A;16N" : "A", NULL); - } else { - unpackers[0] = state->shuffle; + planes = _pickUnpackers(im, state, tiff, planarconfig, unpackers); + if (planes <= 0) { + goto decode_err; } if (TIFFIsTiled(tiff)) { - INT32 x, y, tile_y; - UINT32 tile_width, tile_length, current_tile_length, current_line, - current_tile_width, row_byte_size; - UINT8 *new_data; - - TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tile_width); - TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tile_length); - - /* overflow check for row_byte_size calculation */ - if ((UINT32)INT_MAX / state->bits < tile_width) { - state->errcode = IMAGING_CODEC_MEMORY; - goto decode_err; - } - - // We could use TIFFTileSize, but for YCbCr data it returns subsampled data - // size - row_byte_size = (tile_width * state->bits / planes + 7) / 8; - - /* overflow check for realloc */ - if (INT_MAX / row_byte_size < tile_length) { - state->errcode = IMAGING_CODEC_MEMORY; - goto decode_err; - } - - state->bytes = row_byte_size * tile_length; - - if (TIFFTileSize(tiff) > state->bytes) { - // If the tile size as expected by LibTiff isn't what we're expecting, - // abort. - state->errcode = IMAGING_CODEC_MEMORY; - goto decode_err; - } - - /* realloc to fit whole tile */ - /* malloc check above */ - new_data = realloc(state->buffer, state->bytes); - if (!new_data) { - state->errcode = IMAGING_CODEC_MEMORY; - goto decode_err; - } - - state->buffer = new_data; - - TRACE(("TIFFTileSize: %d\n", state->bytes)); - - for (y = state->yoff; y < state->ysize; y += tile_length) { - int plane; - for (plane = 0; plane < planes; plane++) { - ImagingShuffler shuffler = unpackers[plane]; - for (x = state->xoff; x < state->xsize; x += tile_width) { - /* Sanity Check. Apparently in some cases, the TiffReadRGBA* functions - have a different view of the size of the tiff than we're getting from - other functions. So, we need to check here. - */ - if (!TIFFCheckTile(tiff, x, y, 0, plane)) { - TRACE(("Check Tile Error, Tile at %dx%d\n", x, y)); - state->errcode = IMAGING_CODEC_BROKEN; - goto decode_err; - } - if (TIFFReadTile(tiff, (tdata_t)state->buffer, x, y, 0, plane) == -1) { - TRACE(("Decode Error, Tile at %dx%d\n", x, y)); - state->errcode = IMAGING_CODEC_BROKEN; - goto decode_err; - } - - TRACE(("Read tile at %dx%d; \n\n", x, y)); - - current_tile_width = min((INT32) tile_width, state->xsize - x); - current_tile_length = min((INT32) tile_length, state->ysize - y); - // iterate over each line in the tile and stuff data into image - for (tile_y = 0; tile_y < current_tile_length; tile_y++) { - TRACE(("Writing tile data at %dx%d using tile_width: %d; \n", tile_y + y, x, current_tile_width)); - - // UINT8 * bbb = state->buffer + tile_y * row_byte_size; - // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); - - current_line = tile_y; - - shuffler((UINT8*) im->image[tile_y + y] + x * im->pixelsize, - state->buffer + current_line * row_byte_size, - current_tile_width - ); - } - } - } - } + _decodeTile(im, state, tiff, planes, unpackers); } else { _decodeStrip(im, state, tiff, planes, unpackers); From 1c295bf43c3aab8c6044ee8c323bf39f3b4f5eee Mon Sep 17 00:00:00 2001 From: Konstantin Kopachev Date: Mon, 25 Jan 2021 20:29:04 -0800 Subject: [PATCH 79/89] Check for dimensions and sizes to fit into int --- src/libImaging/TiffDecode.c | 82 +++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index 913b0742c..cd44417aa 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -365,38 +365,34 @@ decodergba_err: int _decodeTile(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, ImagingShuffler *unpackers) { - INT32 x, y, tile_y; - UINT32 tile_width, tile_length, current_tile_length, current_line, - current_tile_width, row_byte_size; + INT32 x, y, tile_y, current_tile_length, current_tile_width; + UINT32 tile_width, tile_length; + tsize_t tile_bytes_size, row_byte_size; UINT8 *new_data; - TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tile_width); - TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tile_length); + tile_bytes_size = TIFFTileSize(tiff); - /* overflow check for row_byte_size calculation */ - if ((UINT32)INT_MAX / state->bits < tile_width) { - state->errcode = IMAGING_CODEC_MEMORY; + if (tile_bytes_size == 0) { + TRACE(("Decode Error, Can not calculate TileSize\n")); + state->errcode = IMAGING_CODEC_BROKEN; return -1; } - // We could use TIFFTileSize, but for YCbCr data it returns subsampled data - // size - row_byte_size = (tile_width * state->bits / planes + 7) / 8; + row_byte_size = TIFFTileRowSize(tiff); + + if (row_byte_size == 0 || row_byte_size > tile_bytes_size) { + TRACE(("Decode Error, Can not calculate TileRowSize\n")); + state->errcode = IMAGING_CODEC_BROKEN; + return -1; + } /* overflow check for realloc */ - if (INT_MAX / row_byte_size < tile_length) { + if (tile_bytes_size > INT_MAX - 1) { state->errcode = IMAGING_CODEC_MEMORY; return -1; } - state->bytes = row_byte_size * tile_length; - - if (TIFFTileSize(tiff) > state->bytes) { - // If the tile size as expected by LibTiff isn't what we're expecting, - // abort. - state->errcode = IMAGING_CODEC_MEMORY; - return -1; - } + state->bytes = tile_bytes_size; /* realloc to fit whole tile */ /* malloc check above */ @@ -405,9 +401,17 @@ _decodeTile(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, Imaging state->errcode = IMAGING_CODEC_MEMORY; return -1; } - state->buffer = new_data; + TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tile_width); + TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tile_length); + + if (tile_width > INT_MAX || tile_length > INT_MAX) { + // state->x and state->y are ints + state->errcode = IMAGING_CODEC_MEMORY; + return -1; + } + TRACE(("TIFFTileSize: %d\n", state->bytes)); for (y = state->yoff; y < state->ysize; y += tile_length) { @@ -441,10 +445,8 @@ _decodeTile(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, Imaging // UINT8 * bbb = state->buffer + tile_y * row_byte_size; // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); - current_line = tile_y; - shuffler((UINT8*) im->image[tile_y + y] + x * im->pixelsize, - state->buffer + current_line * row_byte_size, + state->buffer + tile_y * row_byte_size, current_tile_width ); } @@ -459,38 +461,40 @@ int _decodeStrip(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, ImagingShuffler *unpackers) { INT32 strip_row = 0; UINT8 *new_data; - UINT32 rows_per_strip, row_byte_size; + UINT32 rows_per_strip; int ret; + tsize_t strip_size, row_byte_size; ret = TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip); - if (ret != 1) { + if (ret != 1 || rows_per_strip==(UINT32)(-1)) { rows_per_strip = state->ysize; } - TRACE(("RowsPerStrip: %u \n", rows_per_strip)); - // We could use TIFFStripSize, but for YCbCr data it returns subsampled data size - row_byte_size = (state->xsize * state->bits / planes + 7) / 8; - - /* overflow check for realloc */ - if (INT_MAX / row_byte_size < rows_per_strip) { + if (rows_per_strip > INT_MAX) { state->errcode = IMAGING_CODEC_MEMORY; return -1; } - state->bytes = rows_per_strip * row_byte_size; + TRACE(("RowsPerStrip: %u\n", rows_per_strip)); + + strip_size = TIFFStripSize(tiff); + if (strip_size > INT_MAX - 1) { + state->errcode = IMAGING_CODEC_MEMORY; + return -1; + } + state->bytes = strip_size; TRACE(("StripSize: %d \n", state->bytes)); - if (TIFFStripSize(tiff) > state->bytes) { - // If the strip size as expected by LibTiff isn't what we're expecting, abort. - // man: TIFFStripSize returns the equivalent size for a strip of data as it - // would be returned in a - // call to TIFFReadEncodedStrip ... + row_byte_size = TIFFScanlineSize(tiff); - state->errcode = IMAGING_CODEC_MEMORY; + if (row_byte_size == 0 || row_byte_size > strip_size) { + state->errcode = IMAGING_CODEC_BROKEN; return -1; } + TRACE(("RowsByteSize: %u \n", row_byte_size)); + /* realloc to fit whole strip */ /* malloc check above */ new_data = realloc(state->buffer, state->bytes); From ab24c98491fe9ce345d1f2194bfc25ce2ffd267c Mon Sep 17 00:00:00 2001 From: Konstantin Kopachev Date: Mon, 25 Jan 2021 21:45:57 -0800 Subject: [PATCH 80/89] Add sanity check for memory overruns --- src/libImaging/TiffDecode.c | 39 ++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index cd44417aa..d6bc66907 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -392,17 +392,6 @@ _decodeTile(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, Imaging return -1; } - state->bytes = tile_bytes_size; - - /* realloc to fit whole tile */ - /* malloc check above */ - new_data = realloc(state->buffer, state->bytes); - if (!new_data) { - state->errcode = IMAGING_CODEC_MEMORY; - return -1; - } - state->buffer = new_data; - TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tile_width); TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tile_length); @@ -412,8 +401,27 @@ _decodeTile(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, Imaging return -1; } + if (tile_bytes_size > ((tile_length * state->bits / planes + 7) / 8) * tile_width) { + // If the tile size as expected by LibTiff isn't what we're expecting, abort. + // man: TIFFTileSize returns the equivalent size for a tile of data as it would be returned in a + // call to TIFFReadTile ... + state->errcode = IMAGING_CODEC_BROKEN; + return -1; + } + + state->bytes = tile_bytes_size; + TRACE(("TIFFTileSize: %d\n", state->bytes)); + /* realloc to fit whole tile */ + /* malloc check above */ + new_data = realloc(state->buffer, state->bytes); + if (!new_data) { + state->errcode = IMAGING_CODEC_MEMORY; + return -1; + } + state->buffer = new_data; + for (y = state->yoff; y < state->ysize; y += tile_length) { int plane; for (plane = 0; plane < planes; plane++) { @@ -482,6 +490,15 @@ _decodeStrip(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, Imagin state->errcode = IMAGING_CODEC_MEMORY; return -1; } + + if (strip_size > ((state->xsize * state->bits / planes + 7) / 8) * rows_per_strip) { + // If the strip size as expected by LibTiff isn't what we're expecting, abort. + // man: TIFFStripSize returns the equivalent size for a strip of data as it would be returned in a + // call to TIFFReadEncodedStrip ... + state->errcode = IMAGING_CODEC_BROKEN; + return -1; + } + state->bytes = strip_size; TRACE(("StripSize: %d \n", state->bytes)); From 52ecf1b142a9d9307411f41823fae7c3f9f920c7 Mon Sep 17 00:00:00 2001 From: Konstantin Kopachev Date: Mon, 8 Mar 2021 20:20:29 -0800 Subject: [PATCH 81/89] Stop guessing strip size and pass expected size --- src/libImaging/TiffDecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index d6bc66907..021c2898c 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -526,7 +526,7 @@ _decodeStrip(Imaging im, ImagingCodecState state, TIFF *tiff, int planes, Imagin int plane; for (plane = 0; plane < planes; plane++) { ImagingShuffler shuffler = unpackers[plane]; - if (TIFFReadEncodedStrip(tiff, TIFFComputeStrip(tiff, state->y, plane), (tdata_t)state->buffer, -1) == -1) { + if (TIFFReadEncodedStrip(tiff, TIFFComputeStrip(tiff, state->y, plane), (tdata_t)state->buffer, strip_size) == -1) { TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, state->y, 0))); state->errcode = IMAGING_CODEC_BROKEN; return -1; From 6eae8fd59213a6a403dd69f673ce596e5b9d7fa1 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 29 Mar 2021 08:11:41 +1100 Subject: [PATCH 82/89] Update CHANGES.rst [ci skip] --- CHANGES.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index dba9d263a..a2d40305f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,15 @@ Changelog (Pillow) 8.2.0 (unreleased) ------------------ +- Fixed linear_gradient and radial_gradient I and F modes #5274 + [radarhere] + +- Add support for reading TIFFs with PlanarConfiguration=2 #5364 + [kkopachev, wiredfool, nulano] + +- Deprecated categories #5351 + [radarhere] + - Do not premultiply alpha when resizing with Image.NEAREST resampling #5304 [nulano] From 9ea20c095efd3a17be121f96b18066843f6804b5 Mon Sep 17 00:00:00 2001 From: German Novikov Date: Mon, 29 Mar 2021 14:12:29 +0300 Subject: [PATCH 83/89] Update docs/releasenotes/8.2.0.rst Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- docs/releasenotes/8.2.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/releasenotes/8.2.0.rst b/docs/releasenotes/8.2.0.rst index 3bdfadacd..99e2ef97d 100644 --- a/docs/releasenotes/8.2.0.rst +++ b/docs/releasenotes/8.2.0.rst @@ -77,7 +77,7 @@ be specified through a keyword argument:: ImageOps.autocontrast: preserve_tone ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The default behaviour of the :py:meth:`~PIL.ImageOps.autocontrast` is to normalize +The default behaviour of :py:meth:`~PIL.ImageOps.autocontrast` is to normalize separate histograms for each color channel, changing the tone of the image. The new ``preserve_tone`` argument keeps the tone unchanged by using one luminance histogram for all channels. From 7844c6e48354bb9c7e4e029a394376ce21a76eff Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 29 Mar 2021 23:26:34 +1100 Subject: [PATCH 84/89] Test that preserve_tone changes RGB images but not L images --- Tests/test_imageops.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 888afad37..93be34bf8 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -365,6 +365,15 @@ def test_autocontrast_mask_real_input(): ) +def test_autocontrast_preserve_tone(): + def autocontrast(mode, preserve_tone): + im = hopper(mode) + return ImageOps.autocontrast(im, preserve_tone=preserve_tone).histogram() + + assert autocontrast("RGB", True) != autocontrast("RGB", False) + assert autocontrast("L", True) == autocontrast("L", False) + + def test_autocontrast_preserve_gradient(): gradient = Image.linear_gradient("L") From 4f61637e7fccc9786f90e97e2d55daa44aa2fca2 Mon Sep 17 00:00:00 2001 From: nulano Date: Mon, 29 Mar 2021 17:45:12 +0200 Subject: [PATCH 85/89] document libraqm/fribidi linking, support fribidi-0.dll on Windows --- docs/installation.rst | 31 ++++++++++++++++++--------- docs/releasenotes/8.2.0.rst | 18 ++++++++++++++++ src/thirdparty/fribidi-shim/fribidi.c | 3 +++ winbuild/build.rst | 2 +- 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index f79469c7f..1e7b0d6b2 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -57,8 +57,9 @@ Windows Installation We provide Pillow binaries for Windows compiled for the matrix of supported Pythons in both 32 and 64-bit versions in the wheel format. -These binaries have all of the optional libraries included except -for raqm, libimagequant, and libxcb:: +These binaries include support for all optional libraries except +libimagequant and libxcb. Raqm support requires +fribidi to be installed separately:: python3 -m pip install --upgrade pip python3 -m pip install --upgrade Pillow @@ -71,8 +72,8 @@ macOS Installation We provide binaries for macOS for each of the supported Python versions in the wheel format. These include support for all optional -libraries except libimagequant and libxcb. Raqm support requires -libraqm, fribidi, and harfbuzz to be installed separately:: +libraries except libimagequant. Raqm support requires +fribidi to be installed separately:: python3 -m pip install --upgrade pip python3 -m pip install --upgrade Pillow @@ -83,7 +84,7 @@ Linux Installation We provide binaries for Linux for each of the supported Python versions in the manylinux wheel format. These include support for all optional libraries except libimagequant. Raqm support requires -libraqm, fribidi, and harfbuzz to be installed separately:: +fribidi to be installed separately:: python3 -m pip install --upgrade pip python3 -m pip install --upgrade Pillow @@ -191,11 +192,15 @@ Many of Pillow's features require external libraries: * libraqm depends on the following libraries: FreeType, HarfBuzz, FriBiDi, make sure that you install them before installing libraqm if not available as package in your system. - * setting text direction or font features is not supported without - libraqm. - * libraqm is dynamically loaded in Pillow 5.0.0 and above, so support - is available if all the libraries are installed. - * Windows support: Raqm is not included in prebuilt wheels + * Setting text direction or font features is not supported without libraqm. + * Pillow wheels since version 8.2.0 include a modified version of libraqm that + loads libfribidi at runtime if it is installed. + On Windows this requires compiling FriBiDi and installing ``fribidi.dll`` + into a directory listed in the `Dynamic-Link Library Search Order (Microsoft Docs) + `_ + (``fribidi-0.dll`` or ``libfribidi-0.dll`` are also detected). + See `Build Options`_ to see how to build this version. + * Previous versions of Pillow (5.0.0 to 8.1.2) linked libraqm dynamically at runtime. * **libxcb** provides X11 screengrab support. @@ -244,6 +249,12 @@ Build Options an exception if the libraries are not found. Webpmux (WebP metadata) relies on WebP support. Tcl and Tk also must be used together. +* Build flags: ``--vendor-raqm --vendor-fribidi`` + These flags are used to compile a modified version of libraqm and + a shim that dynamically loads libfribidi at runtime. These are + used to compile the standard Pillow wheels. Compiling libraqm requires + a C99-compliant compiler. + * Build flag: ``--disable-platform-guessing``. Skips all of the platform dependent guessing of include and library directories for automated build systems that configure the proper paths in the diff --git a/docs/releasenotes/8.2.0.rst b/docs/releasenotes/8.2.0.rst index 3ef05894d..c76547c8e 100644 --- a/docs/releasenotes/8.2.0.rst +++ b/docs/releasenotes/8.2.0.rst @@ -91,6 +91,24 @@ TODO Other Changes ============= +Libraqm and FriBiDi linking +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The way the libraqm dependency for complex text scripts is linked has been changed: + +Source builds will now link against the system version of libraqm at build time +rather than at runtime by default. + +Binary wheels now include a statically linked modified version of libraqm that +links against FriBiDi at runtime instead. This change is intended to address +issues with the previous implementation on some platforms. These are created +by building Pillow with the new build flags ``--vendor-raqm --vendor-fribidi``. + +Windows users will now need to install ``fribidi.dll`` (or ``fribidi-0.dll``) only, +``libraqm.dll`` is no longer used. + +See :doc:`installation documentation<../installation>` for more information. + PyQt6 ^^^^^ diff --git a/src/thirdparty/fribidi-shim/fribidi.c b/src/thirdparty/fribidi-shim/fribidi.c index 55e2a6ab3..abbab07b0 100644 --- a/src/thirdparty/fribidi-shim/fribidi.c +++ b/src/thirdparty/fribidi-shim/fribidi.c @@ -56,6 +56,9 @@ int load_fribidi(void) { error = error || (func == 0); p_fribidi = LoadLibrary("fribidi"); + if (!p_fribidi) { + p_fribidi = LoadLibrary("fribidi-0"); + } /* MSYS2 */ if (!p_fribidi) { p_fribidi = LoadLibrary("libfribidi-0"); diff --git a/winbuild/build.rst b/winbuild/build.rst index cd4a45e87..7493c30e5 100644 --- a/winbuild/build.rst +++ b/winbuild/build.rst @@ -87,7 +87,7 @@ and install Pillow in develop mode (instead of ``python3 -m pip install --editab Testing Pillow -------------- -Some binary dependencies (e.g. ``libraqm.dll``) will be stored in the +Some binary dependencies (e.g. ``fribidi.dll``) will be stored in the ``winbuild\build\bin`` directory; this directory should be added to ``PATH`` before running tests. From 00cc32e3f92c990bd41df84e551813718368c9aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ondrej=20Baranovi=C4=8D?= Date: Mon, 29 Mar 2021 19:45:27 +0200 Subject: [PATCH 86/89] FriBiDi capitalization consistency Co-authored-by: Hugo van Kemenade --- docs/installation.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index 1e7b0d6b2..cc9c51039 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -59,7 +59,7 @@ We provide Pillow binaries for Windows compiled for the matrix of supported Pythons in both 32 and 64-bit versions in the wheel format. These binaries include support for all optional libraries except libimagequant and libxcb. Raqm support requires -fribidi to be installed separately:: +FriBiDi to be installed separately:: python3 -m pip install --upgrade pip python3 -m pip install --upgrade Pillow @@ -73,7 +73,7 @@ macOS Installation We provide binaries for macOS for each of the supported Python versions in the wheel format. These include support for all optional libraries except libimagequant. Raqm support requires -fribidi to be installed separately:: +FriBiDi to be installed separately:: python3 -m pip install --upgrade pip python3 -m pip install --upgrade Pillow @@ -84,7 +84,7 @@ Linux Installation We provide binaries for Linux for each of the supported Python versions in the manylinux wheel format. These include support for all optional libraries except libimagequant. Raqm support requires -fribidi to be installed separately:: +FriBiDi to be installed separately:: python3 -m pip install --upgrade pip python3 -m pip install --upgrade Pillow From 9e5ecd682567f9e0cb4dba7a415d12f7055a4054 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 30 Mar 2021 08:00:58 +1100 Subject: [PATCH 87/89] Update CHANGES.rst [ci skip] --- CHANGES.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index a2d40305f..3a16c0e50 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,9 @@ Changelog (Pillow) 8.2.0 (unreleased) ------------------ +- Add preserve_tone option to autocontrast #5350 + [elejke, radarhere] + - Fixed linear_gradient and radial_gradient I and F modes #5274 [radarhere] From d8b4a928068e038d7fb07a901a882864b5694de0 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 31 Mar 2021 16:03:13 +1100 Subject: [PATCH 88/89] Updated Ghostscript to 9.54.0 --- .appveyor.yml | 4 ++-- .github/workflows/test-windows.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 4e2ca1071..b843b16ee 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -24,8 +24,8 @@ install: - mv c:\pillow-depends-master c:\pillow-depends - xcopy /S /Y c:\pillow-depends\test_images\* c:\pillow\tests\images - 7z x ..\pillow-depends\nasm-2.14.02-win64.zip -oc:\ -- ..\pillow-depends\gs9533w32.exe /S -- path c:\nasm-2.14.02;C:\Program Files (x86)\gs\gs9.53.3\bin;%PATH% +- ..\pillow-depends\gs9540w32.exe /S +- path c:\nasm-2.14.02;C:\Program Files (x86)\gs\gs9.54.0\bin;%PATH% - cd c:\pillow\winbuild\ - ps: | c:\python37\python.exe c:\pillow\winbuild\build_prepare.py -v --depends=C:\pillow-depends\ diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index e3b2201a7..beb89ebeb 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -71,8 +71,8 @@ jobs: 7z x winbuild\depends\nasm-2.14.02-win64.zip "-o$env:RUNNER_WORKSPACE\" echo "$env:RUNNER_WORKSPACE\nasm-2.14.02" >> $env:GITHUB_PATH - winbuild\depends\gs9533w32.exe /S - echo "C:\Program Files (x86)\gs\gs9.53.3\bin" >> $env:GITHUB_PATH + winbuild\depends\gs9540w32.exe /S + echo "C:\Program Files (x86)\gs\gs9.54.0\bin" >> $env:GITHUB_PATH xcopy /S /Y winbuild\depends\test_images\* Tests\images\ From 7e940dea5e12326bafe68023f5f6cb6f0a695827 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 31 Mar 2021 19:22:31 +1100 Subject: [PATCH 89/89] Added release notes [ci skip] --- docs/releasenotes/8.2.0.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/releasenotes/8.2.0.rst b/docs/releasenotes/8.2.0.rst index cf90c1ae8..759ede9aa 100644 --- a/docs/releasenotes/8.2.0.rst +++ b/docs/releasenotes/8.2.0.rst @@ -45,6 +45,14 @@ This is now consistent with other IFDs, and must be accessed through These changes only affect :py:meth:`~PIL.Image.Image.getexif`, introduced in Pillow 6.0. The older ``_getexif()`` methods are unaffected. +Image._MODEINFO +^^^^^^^^^^^^^^^ + +This internal dictionary has been deprecated by a comment since PIL, and is now +removed. Instead, ``Image.getmodebase()``, ``Image.getmodetype()``, +``Image.getmodebandnames()``, ``Image.getmodebands()`` or ``ImageMode.getmode()`` +can be used. + API Additions =============